export interface GiteaConfig { baseUrl: string; user: string; token: string; } export interface GiteaRepo { clone_url: string; ssh_url: string; html_url: string; } export class GiteaRepoExistsError extends Error { constructor() { super('gitea-repo-exists'); } } export async function createGiteaRepo( cfg: GiteaConfig, name: string, options: { private: boolean } ): Promise { const res = await fetch(`${cfg.baseUrl}/api/v1/user/repos`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `token ${cfg.token}`, }, body: JSON.stringify({ name, private: options.private, auto_init: false, }), }); if (res.status === 409) throw new GiteaRepoExistsError(); if (!res.ok) { const text = await res.text().catch(() => ''); throw new Error(`gitea-api-${res.status}: ${text.slice(0, 200)}`); } const body = (await res.json()) as { ssh_url?: string; clone_url?: string; html_url?: string }; if (!body.ssh_url || !body.html_url || !body.clone_url) { throw new Error(`gitea-api-unexpected-shape: ${JSON.stringify(body).slice(0, 200)}`); } return { ssh_url: body.ssh_url, clone_url: body.clone_url, html_url: body.html_url, }; }