import { bufferUpTo, packOffset } from "../security/push-protection";
import { isAncestor } from "./history";
import { parsePack } from "./pack";
import { withStore, ZERO_SHA } from "./store";
import type { RepoRow } from "~/lib/types";
const MAX_BUFFERED_BYTES = 32 * 1024 * 1024;
const MAX_INFLATED_BYTES = 64 * 1024 * 1024;
const MAX_WALK = 5000;
const MAX_STORE_CHECKS = 64;
const PARENT_LINE = /^parent ([0-9a-f]{40})$/gm;
const decoder = new TextDecoder();
export type RefUpdate = { oldSha: string; newSha: string; ref: string };
function commitParents(content: Uint8Array): string[] {
const header = decoder.decode(content.subarray(0, Math.min(content.byteLength, 64 * 1024))).split("\n\n")[0];
return [...header.matchAll(PARENT_LINE)].map((match) => match[1]);
}
async function readPackParents(bytes: Uint8Array<ArrayBuffer>, gzip: boolean): Promise<Map<string, string[]> | null> {
let decoded = bytes;
if (gzip) {
const inflated = await bufferUpTo(
new Blob([bytes]).stream().pipeThrough(new DecompressionStream("gzip")),
MAX_INFLATED_BYTES,
);
if (!inflated.complete) return null;
decoded = inflated.bytes;
}
const offset = packOffset(decoded);
if (offset === null) return new Map();
const parsed = await parsePack(decoded.subarray(offset), {
maxObjects: 100_000,
maxObjectBytes: 16 * 1024 * 1024,
maxTotalBytes: MAX_INFLATED_BYTES,
});
if (parsed.truncated) return null;
return new Map(
parsed.objects