33 lines · 1.3 KB
import { env } from "cloudflare:workers";
import { CAPS } from "../limits";
import { forgetReachability } from "./reachable";
import type { RepoRow } from "~/lib/types";

/** Every KV namespace that caches a repository's objects or derived data, keyed by its Artifacts name. */
const PREFIXES = ["commit:", "tree:", "blob:", "diff:v2:", "compare:v1:", "path-log:v1:", "last-commit:v2:"];

/**
 * Best-effort purge of a repository's cached objects after deletion or a visibility change (GIT-A13). Every
 * read path re-checks permission before touching these keys, so this is hygiene rather than access control;
 * the loop is bounded by `CAPS.cachePurgeKeys` and never throws into the caller.
 */
export async function purgeRepoCaches(repo: Pick<RepoRow, "id" | "artifacts_name">): Promise<void> {
  await forgetReachability(repo.id);
  let budget = CAPS.cachePurgeKeys;
  for (const prefix of PREFIXES) {
    let cursor: string | undefined;
    while (budget > 0) {
      const page = await env.KV.list({
        prefix: `${prefix}${repo.artifacts_name}:`,
        cursor,
        limit: Math.min(budget, 1000),
      });
      for (const key of page.keys) await env.KV.delete(key.name);
      budget -= page.keys.length;
      if (page.list_complete) break;
      cursor = page.cursor;
    }
    if (budget <= 0) break;
  }
}