1/**
2 * The repo head snapshot (DESIGN.md §21, "Continuity learnings"): a tiny
3 * JSON object in the BlobStore describing a repository's current serving
4 * state. The Repo DO rewrites it after every commit that changes what an
5 * anonymous reader could see (push, ref write, meta change, bundle cut),
6 * and the Worker uses it to answer public read traffic — the `info/refs`
7 * advertisement and bundle-covered full clones — without waking the DO.
8 *
9 * Consistency: the snapshot is written AFTER the SQLite commit and
10 * before the response, so read-your-writes holds for the writer. A crash
11 * between commit and write leaves a stale snapshot until the next
12 * mutation (the post-push bundle alarm rewrites it seconds later). The
13 * DO remains authoritative: authenticated traffic never reads this.
14 */
15import type { BundleInfo } from "../Jobs/Bundle.ts";
16
17/** One advertised ref (peeled target present for annotated tags). */
18export interface HeadRef {
19 readonly name: string;
20 readonly oid: string;
21 readonly peeled?: string | undefined;
22}
23
24export interface HeadSnapshot {
25 readonly v: 1;
26 readonly repoId: string;
27 readonly owner: string;
28 readonly name: string;
29 /** Anonymous read access (the GitHub public-repo model). */
30 readonly public: boolean;
31 readonly readOnly: boolean;
32 readonly defaultBranch: string;
33 readonly refs: ReadonlyArray<HeadRef>;
34 /** The current clone bundle, when one covers these refs. */
35 readonly bundle?: BundleInfo | undefined;
36}
37
38export const encodeHeadSnapshot = (snapshot: HeadSnapshot): string =>
39 JSON.stringify(snapshot);
40
41/** `undefined` on malformed/foreign content — callers fall to the DO. */
42export const decodeHeadSnapshot = (raw: string): HeadSnapshot | undefined => {
43 try {
44 const parsed = JSON.parse(raw) as HeadSnapshot;
45 return parsed.v === 1 && Array.isArray(parsed.refs) ? parsed : undefined;
46 } catch {
47 return undefined;
48 }
49};