256 lines · 10.1 KB
import { structuredPatch } from "diff";
import { env, waitUntil } from "cloudflare:workers";
import type { GitStore } from "./store";
import type { DiffResult, FileChange } from "~/lib/types";

const MAX_CONTENT_FILES = 300;
const MAX_TREE_READS = 2000;
const MAX_CHANGED_FILES = 5000;
const MAX_EDIT_LENGTH = 20_000;
const DIFF_TIMEOUT_MS = 1500;
const MAX_BLOB_BYTES = 512 * 1024;
const BINARY_SNIFF_BYTES = 8000;
const BLOB_CONCURRENCY = 8;
const CONTEXT_LINES = 3;
const MAX_CACHED_PATCH_BYTES = 4 * 1024 * 1024;
const DIFF_CACHE_TTL_SECONDS = 60 * 60 * 24 * 7;
const DIFF_CACHE_VERSION = "v1";
const decoder = new TextDecoder();

type Entry = { name: string; mode: string; hash: string; type: ArtifactsTreeEntryType };

function joinPath(parent: string, name: string): string {
  return parent ? `${parent}/${name}` : name;
}

async function entriesOf(store: GitStore, sha: string | null): Promise<Map<string, Entry>> {
  if (!sha) return new Map();
  const entries = (await store.tree(sha)) ?? [];
  return new Map(entries.map((entry) => [entry.name, entry]));
}

type Budget = { treeReads: number };

function exhausted(budget: Budget, out: FileChange[]): boolean {
  return budget.treeReads >= MAX_TREE_READS || out.length >= MAX_CHANGED_FILES;
}

async function collectAll(
  store: GitStore,
  entry: Entry,