import { advertisement, artifactsSource, assertPublicHttpsUrl, relayPack } from "./relay";
import { pushToArtifacts } from "./writer";
import { assertResolvesPublic } from "../net/resolve-guard";
import type { RepoRow } from "~/lib/types";
const MAX_SYNC_REFS = 1000;
const MAX_SYNC_BYTES = 1024 * 1024 * 1024;
const ZERO_SHA = "0".repeat(40);
export type RefSyncResult = { created: number; rejected: string[]; skipped: number };
/**
* 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> {
assertPublicHttpsUrl(sourceUrl);
await assertResolvesPublic(sourceUrl);
const [source, target] = await Promise.all([
advertisement({ url: sourceUrl, authorization: null }),
artifactsSource(repo).then((self) => advertisement(self)),
]);
const existingNames = new Set(target.map((ref) => ref.name));
const allMissing = source.filter((ref) => !existingNames.has(ref.name));
const missing = allMissing.slice(0, MAX_SYNC_REFS);
const result: RefSyncResult = { created: 0, rejected: [], skipped: allMissing.length - missing.length };
if (missing.length === 0) return result;
const present = new Set(target.map((ref) => ref.sha));
const wants = [...new Set(missing.map((ref) => ref.sha))].filter((sha) => !present.has(sha));
if (wants.length === 0) {
await pushToArtifacts(
repo,
missing.map((ref) => ({ ref: ref.name, oldSha: ZERO_SHA, newSha: ref.sha })),
[],
);
return { ...result, created: missing.length };
}
const report = await relayPack({