const REPO_PATH = /^\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(?:\.git)?\/?$/; export type GithubRepoRef = { owner: string; repo: string; /** Lowercase `owner/repo`, used to detect duplicate submissions. */ repoKey: string; /** Canonical URL stored in the database. */ canonicalUrl: string; }; /** Returns undefined unless the value is a plain https://github.com/owner/repo URL. */ export function parseGithubRepoUrl(value: string): GithubRepoRef | undefined { try { const url = new URL(value); if ( url.protocol !== "https:" || url.hostname !== "github.com" || url.username || url.password || url.search || url.hash ) { return undefined; } const match = REPO_PATH.exec(url.pathname); if (!match) return undefined; const [, owner, repo] = match; if (repo === "." || repo === ".." || owner === "." || owner === "..") return undefined; return { owner, repo, repoKey: `${owner}/${repo}`.toLowerCase(), canonicalUrl: `https://github.com/${owner}/${repo}`, }; } catch { return undefined; } } export type RepoVerification = | { status: "ok" } | { status: "not_found" } | { status: "unavailable" }; /** * Confirms that a public repository exists. `unavailable` means GitHub could not * answer (rate limit, timeout, 5xx), so the caller should not reject the submission. */ export async function verifyRepo( ref: Pick, fetchImpl: typeof fetch = fetch, ): Promise { const headers: Record = { Accept: "application/vnd.github+json", "User-Agent": "chainkit-directory", "X-GitHub-Api-Version": "2022-11-28", }; if (process.env.GITHUB_TOKEN) headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`; try { const response = await fetchImpl( `https://api.github.com/repos/${encodeURIComponent(ref.owner)}/${encodeURIComponent(ref.repo)}`, { headers, signal: AbortSignal.timeout(5000), cache: "no-store" }, ); // Private repos return 404 to unauthenticated callers, which is what we want. if (response.status === 404 || response.status === 451) return { status: "not_found" }; if (!response.ok) return { status: "unavailable" }; const data = (await response.json()) as { private?: boolean; disabled?: boolean }; if (data.private || data.disabled) return { status: "not_found" }; return { status: "ok" }; } catch { return { status: "unavailable" }; } }