import { basicAuthHeader, repoTokenSecret } from "./artifacts";
import { invalidateRefs } from "./refs";
import { pushToArtifacts } from "./writer";
import {
packStream,
parseReportStatus,
parseSyncableRefs,
receivePackBody,
uploadPackRequest,
} from "./ref-sync-protocol";
import type { AdvertisedRef } from "./ref-sync-protocol";
import { badRequest } from "../errors";
import type { RepoRow } from "~/lib/types";
const MAX_SYNC_REFS = 1000;
const MAX_HAVES = 256;
const ADVERTISEMENT_TIMEOUT_MS = 30_000;
const USER_AGENT = "git/gitfor";
export type RefSyncResult = { created: number; rejected: string[]; skipped: number };
async function advertisement(url: string, authorization: string | null): Promise<AdvertisedRef[]> {
const headers: Record<string, string> = { "user-agent": USER_AGENT };
if (authorization) headers.authorization = authorization;
const response = await fetch(`${url.replace(/\/$/, "")}/info/refs?service=git-upload-pack`, {
headers,
signal: AbortSignal.timeout(ADVERTISEMENT_TIMEOUT_MS),
});
if (!response.ok) throw badRequest(`Could not list refs at ${url} (HTTP ${response.status})`);
return parseSyncableRefs(new Uint8Array(await response.arrayBuffer()));
}
/**
* Artifacts imports only copy one branch. This copies every other branch and tag from the source by
* relaying a packfile straight from the source's upload-pack into Artifacts' receive-pack, so nothing
* is buffered in the Worker. Existing refs are never overwritten.
*/
export async function syncRefsFromSource(repo: RepoRow, sourceUrl: string): Promise<RefSyncResult> {
if (!sourceUrl.startsWith("https://")) throw badRequest("Only https:// sources can be synced");
const readSecret = await repoTokenSecret(repo, "read");