import { guardedFetch, relayPack, trimUrl } from "../git/relay";
import type { RelaySource } from "../git/relay";
import { parseReportStatus, receivePackBody } from "../git/ref-sync-protocol";
import type { RefCommand } from "../git/ref-sync-protocol";
import { badRequest } from "../errors";
import { ZERO_SHA } from "./plan";
const MAX_PUSH_BYTES = 1024 * 1024 * 1024;
const PUSH_TIMEOUT_MS = 10 * 60_000;
export type RemoteReport = { accepted: Set<string>; rejected: Map<string, string> };
function emptyPack(): ReadableStream<Uint8Array> {
return new ReadableStream({ start: (controller) => controller.close() });
}
function splitReport(commands: RefCommand[], rejected: string[]): RemoteReport {
const refused = new Map<string, string>();
for (const entry of rejected) {
const space = entry.indexOf(" ");
const name = space === -1 ? entry : entry.slice(0, space);
refused.set(name, space === -1 ? "rejected by the remote" : entry.slice(space + 1));
}
return {
accepted: new Set(commands.map((command) => command.name).filter((name) => !refused.has(name))),
rejected: refused,
};
}
/** Deletions carry no packfile, so they go straight to receive-pack instead of through relayPack. */
async function sendDeletions(remote: RelaySource, commands: RefCommand[]): Promise<string[]> {
const headers: Record<string, string> = {
"content-type": "application/x-git-receive-pack-request",
accept: "application/x-git-receive-pack-result",
"user-agent": "git/gitfor",
};
if (remote.authorization) headers.authorization = remote.authorization;
const response = await guardedFetch(remote, `${trimUrl(remote.url)}/git-receive-pack`, {
method: "POST",
headers,