124 lines · 4.4 KB
import { recordArtifactsCall } from "./artifacts-health";
import { basicAuthHeader, repoTokenSecret } from "./artifacts";
import { concatBytes, FLUSH_PKT, packetText, parsePacket, pktLine } from "./pktline";
import { parsePack } from "./pack";
import type { RepoRow } from "~/lib/types";

const DELIM_PKT = new TextEncoder().encode("0001");
const SIDEBAND_DATA = 1;
const SIDEBAND_ERROR = 3;
const MAX_FETCH_BYTES = 4 * 1024 * 1024;
const MAX_COMMIT_BYTES = 256 * 1024;
const FETCH_TIMEOUT_MS = 15_000;
export const MAX_COMMITS_PER_FETCH = 50;

type FetchRepo = Pick<RepoRow, "artifacts_name" | "artifacts_remote">;

/** Builds a protocol v2 fetch asking only for the wanted commits, without trees or blobs where supported. */
export function commitFetchRequest(shas: string[], filter: boolean): Uint8Array<ArrayBuffer> {
  return concatBytes([
    pktLine("command=fetch\n"),
    pktLine("agent=git/gitfor\n"),
    DELIM_PKT,
    ...shas.map((sha) => pktLine(`want ${sha}\n`)),
    pktLine("deepen 1\n"),
    ...(filter ? [pktLine("filter tree:0\n")] : []),
    pktLine("no-progress\n"),
    pktLine("done\n"),
    FLUSH_PKT,
  ]);
}

/** Pulls packfile bytes out of a v2 fetch response, tolerating a truncated tail. */
export function packFromFetchResponse(body: Uint8Array): Uint8Array<ArrayBuffer> {
  const chunks: Uint8Array[] = [];
  let inPack = false;
  let offset = 0;
  while (offset < body.byteLength) {
    let parsed: ReturnType<typeof parsePacket>;
    try {
      parsed = parsePacket(body, offset);