@run402/sdk 4.39.0 → 4.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/namespaces/gitvault.crypto.d.ts +10 -0
  2. package/dist/namespaces/gitvault.crypto.d.ts.map +1 -1
  3. package/dist/namespaces/gitvault.crypto.js +10 -0
  4. package/dist/namespaces/gitvault.crypto.js.map +1 -1
  5. package/dist/namespaces/gitvault.d.ts +141 -4
  6. package/dist/namespaces/gitvault.d.ts.map +1 -1
  7. package/dist/namespaces/gitvault.js +226 -3
  8. package/dist/namespaces/gitvault.js.map +1 -1
  9. package/dist/node/gitvault-keystore.d.ts +11 -1
  10. package/dist/node/gitvault-keystore.d.ts.map +1 -1
  11. package/dist/node/gitvault-keystore.js.map +1 -1
  12. package/dist/node/gitvault-mirror-backend.d.ts +88 -0
  13. package/dist/node/gitvault-mirror-backend.d.ts.map +1 -0
  14. package/dist/node/gitvault-mirror-backend.js +374 -0
  15. package/dist/node/gitvault-mirror-backend.js.map +1 -0
  16. package/dist/node/gitvault-mirror-config.d.ts +53 -0
  17. package/dist/node/gitvault-mirror-config.d.ts.map +1 -0
  18. package/dist/node/gitvault-mirror-config.js +112 -0
  19. package/dist/node/gitvault-mirror-config.js.map +1 -0
  20. package/dist/node/gitvault-mirror.d.ts +120 -0
  21. package/dist/node/gitvault-mirror.d.ts.map +1 -0
  22. package/dist/node/gitvault-mirror.js +464 -0
  23. package/dist/node/gitvault-mirror.js.map +1 -0
  24. package/dist/node/gitvault-publication.d.ts +131 -0
  25. package/dist/node/gitvault-publication.d.ts.map +1 -1
  26. package/dist/node/gitvault-publication.js +145 -1
  27. package/dist/node/gitvault-publication.js.map +1 -1
  28. package/dist/node/gitvault-recover.d.ts +136 -0
  29. package/dist/node/gitvault-recover.d.ts.map +1 -0
  30. package/dist/node/gitvault-recover.js +412 -0
  31. package/dist/node/gitvault-recover.js.map +1 -0
  32. package/dist/node/gitvault-snapshot.d.ts +8 -0
  33. package/dist/node/gitvault-snapshot.d.ts.map +1 -1
  34. package/dist/node/gitvault-snapshot.js +11 -0
  35. package/dist/node/gitvault-snapshot.js.map +1 -1
  36. package/package.json +1 -1
@@ -0,0 +1,464 @@
1
+ /**
2
+ * gitvault-mirror-and-recover — the mirror writer + reconcile/sync engine +
3
+ * capture-time dual-push hook (design D1/D6/D7, tasks 2.2–2.4).
4
+ *
5
+ * ADMISSION-ORDER WRITE DISCIPLINE (D1's whole point). The gateway's objects
6
+ * listing (`GET /gitvault/v1/vaults/:vault_id/objects`) is a flat, unordered
7
+ * set of `{key, object_kind, sha256, size_bytes}` — it does not group objects
8
+ * by generation. The correct, SUFFICIENT ordering rule does not need that
9
+ * grouping: write EVERY plain object first (any order among themselves — a
10
+ * WAL pack, a checkpoint pack, a prune intent never depend on one another),
11
+ * THEN write every `admissions/<gen>` and `head/<gen>` pair, interleaved and
12
+ * strictly ascending by generation, admission always immediately before its
13
+ * head. Any interruption therefore lands the mirror in one of exactly two
14
+ * shapes:
15
+ * - mid-objects: no admission/head has been written yet, so nothing in the
16
+ * mirror references anything absent — a completely inert, valid state
17
+ * (recovery just sees the mirror's newest COMPLETE prior generation, if
18
+ * any was mirrored on an earlier pass).
19
+ * - mid-admissions/heads at generation K: every object is present (phase
20
+ * one finished), every generation < K is fully written (admission +
21
+ * head), and K itself has AT MOST its admission record without its head
22
+ * — which recovery reads exactly as "the mirror's newest generation is
23
+ * K-1", a completely ordinary and valid earlier state (protocol §5A step
24
+ * 4: a record existing without its head PUT is a normal in-flight shape,
25
+ * never corruption).
26
+ * This is exactly the "torn mirror ≡ some earlier valid generation" property
27
+ * design D1 requires, and it needs no per-generation object grouping to prove.
28
+ *
29
+ * Read path: `GET …/objects` (paginated) for the listing, then the SAME
30
+ * presigned-read machinery the SDK's publication module uses for live pushes
31
+ * (`POST …/object-reads` for object-kind reads, `GET …/heads/:gen` /
32
+ * `GET …/admissions/:gen` for the two generation-addressed raw-byte routes) —
33
+ * reimplemented here as a THIN, self-contained reader (not exported from
34
+ * `gitvault-publication.ts`, which keeps those helpers module-private) so
35
+ * this file has no dependency on the live-push module and works from nothing
36
+ * but a `Client` + `repo_id`.
37
+ *
38
+ * MIRROR LAYOUT (task 5.3 fix — do not lose this again). The gateway's real
39
+ * bucket key for every stored artifact is FULLY QUALIFIED under the vault's
40
+ * own prefix (`storage-keys.ts` `vaultPrefix`): `source/<repo_id>/<rest>`,
41
+ * confirmed live 2026-08-26 (`gitvault-mirror-drill.mjs` against
42
+ * `api.run402.com`). The gateway's own `GET …/objects` listing (task 1.2)
43
+ * echoes that FULL key back on every entry — it never returns a
44
+ * repo-relative key. This module's own working representation, and the
45
+ * mirror BACKEND's key space (`gitvault-mirror-backend.ts`
46
+ * `openGitvaultMirrorBackend`, whose `root`/`prefix` already bake in
47
+ * `source/<repo_id>`), are both REPO-RELATIVE (`head/<gen>`,
48
+ * `wal/<id>.pack.enc`, `key-envelopes/<epoch>/<fp>.env`, …) — the same shape
49
+ * `gitvault-recover.ts` and `gitvault-publication.ts`'s `gitvaultPaths`
50
+ * already use. The mapping is therefore, in ONE place:
51
+ *
52
+ * bucket key = `source/<repo_id>/` + mirror key (repo-relative)
53
+ *
54
+ * `listGitvaultObjectsAll` is the ONLY function that ever sees a full,
55
+ * `source/<repo_id>/`-prefixed key (the raw wire shape, typed
56
+ * `RawVaultObjectEntry` below) — it strips the prefix via
57
+ * `stripSourcePrefix` before anything else in this module (or in
58
+ * `gitvault-recover.ts`, which never talks to the live gateway at all) sees
59
+ * the entry. Every `GitvaultObjectEntry` handed to `generationRouteForKey`,
60
+ * `objectReadRequestForEntry`, `planMirrorWrite`, `reconcileOne`, and the
61
+ * `GitvaultMirrorBackend` itself is repo-relative from that point on. An
62
+ * entry whose key names a DIFFERENT repo id than the one being synced is a
63
+ * listing-isolation violation and is refused loudly (never silently
64
+ * stripped-and-kept or silently dropped) — see `stripSourcePrefix`.
65
+ *
66
+ * Two chain kinds are part of this SAME listing (the pre-fix gateway omitted
67
+ * them entirely, which was task 5.3 finding (a); the listing now includes
68
+ * them end to end), both fetched via the exact-bytes generation routes
69
+ * (`.../heads/:generation`, `.../admissions/:generation`), never through
70
+ * `object-reads`:
71
+ * - `head/<generation>` — `object_kind: "head"` for every ordinary
72
+ * generation, but the GENESIS entry at generation `0000000000000000`
73
+ * carries `object_kind: "vault_genesis"` (the ledger's own
74
+ * `admitted_object_kind`) instead. Both route through the SAME
75
+ * `.../heads/:generation` fetch — the kind distinguishes the CONTENT,
76
+ * not the route.
77
+ * - `admissions/<generation>` — `object_kind: "admission_record"` at
78
+ * EVERY generation, including genesis (genesis has an admission record
79
+ * too).
80
+ * `size_bytes` is an EXACT decimal string for every kind, including these
81
+ * two (the ledger enforces the admitted byte count via CHECK constraints and
82
+ * the gateway serves it as `octet_length`) — never `null`. `reconcileOne`
83
+ * still diffs by size first (cheap) and hash-verifies on every actual copy
84
+ * (belt-and-suspenders, unconditional — never skipped just because a size
85
+ * happened to match).
86
+ */
87
+ import { createHash } from "node:crypto";
88
+ import { LocalError, isRun402Error } from "../errors.js";
89
+ import { GITVAULT_GENESIS_GENERATION, GITVAULT_MIRROR_KEYSTORE_STILL_REQUIRED_STATEMENT, GITVAULT_MIRROR_VALIDITY_NOT_FRESHNESS_STATEMENT, } from "../namespaces/gitvault.crypto.js";
90
+ import { GitvaultKeystore } from "./gitvault-keystore.js";
91
+ import { formatMirrorDestination, readMirrorConfig } from "./gitvault-mirror-config.js";
92
+ import { openGitvaultMirrorBackend, resolveMirrorCredentials } from "./gitvault-mirror-backend.js";
93
+ function fail(code, message, context, details, nextActions) {
94
+ throw new LocalError(message, context, { code, details, ...(nextActions ? { next_actions: nextActions } : {}) });
95
+ }
96
+ function sha256Hex(bytes) {
97
+ return createHash("sha256").update(bytes).digest("hex");
98
+ }
99
+ /** protocol §3 (`storage-keys.ts` `GITVAULT_SOURCE_PREFIX`) — duplicated here because the SDK carries no dependency on the gateway package. */
100
+ const GITVAULT_SOURCE_PREFIX = "source";
101
+ /**
102
+ * Turn one WIRE key (`source/<repo_id>/<rest>`) into the REPO-RELATIVE key
103
+ * every other function in this module expects. A key naming a DIFFERENT repo
104
+ * id than the one being synced is a listing-isolation violation — refused
105
+ * loudly rather than silently stripped-and-kept (it could only mean a
106
+ * gateway bug or a cross-tenant data leak, and a partial sync that quietly
107
+ * dropped it would misreport as a clean success). A key with no `source/`
108
+ * prefix at all is a listing-shape violation of the same severity.
109
+ */
110
+ function stripSourcePrefix(repoId, key) {
111
+ const expected = `${GITVAULT_SOURCE_PREFIX}/${repoId}/`;
112
+ if (key.startsWith(expected))
113
+ return key.slice(expected.length);
114
+ const foreign = /^source\/([^/]+)\//.exec(key);
115
+ if (foreign) {
116
+ fail("GITVAULT_MIRROR_FOREIGN_REPO_KEY", `the objects listing for ${repoId} returned a key addressed to a different vault (${foreign[1]}): ${key}`, "listing gitvault vault objects", { key, repo_id: repoId, foreign_repo_id: foreign[1] });
117
+ }
118
+ fail("GITVAULT_MIRROR_LISTING_INCONSISTENT", `listed key is not in the expected source/<repo_id>/… layout: ${key}`, "listing gitvault vault objects", { key, repo_id: repoId });
119
+ }
120
+ /** Page through `GET /gitvault/v1/vaults/:vault_id/objects`, collecting every entry, stripped to repo-relative keys. Store-and-echo cursor per D3a — never parsed here either. */
121
+ export async function listGitvaultObjectsAll(client, repoId) {
122
+ const base = `/gitvault/v1/vaults/${encodeURIComponent(repoId)}/objects`;
123
+ const out = [];
124
+ let cursor;
125
+ for (;;) {
126
+ const qs = cursor ? `?cursor=${encodeURIComponent(cursor)}` : "";
127
+ const page = await client.request(`${base}${qs}`, { context: "listing gitvault vault objects" });
128
+ for (const raw of page.objects) {
129
+ out.push({ key: stripSourcePrefix(repoId, raw.key), object_kind: raw.object_kind, sha256: raw.sha256, size_bytes: raw.size_bytes });
130
+ }
131
+ if (!page.has_more)
132
+ break;
133
+ if (!page.next_cursor)
134
+ fail("GITVAULT_MIRROR_LISTING_INCONSISTENT", "the objects listing reported has_more with no next_cursor", "listing gitvault vault objects");
135
+ cursor = page.next_cursor;
136
+ }
137
+ return out;
138
+ }
139
+ /** Read one object's bytes by key, using the same wire identity every stored kind already carries (§3 layout). `null` when the gateway reports the object absent. */
140
+ export async function readGitvaultObjectBytes(client, repoId, entry) {
141
+ const base = `/gitvault/v1/vaults/${encodeURIComponent(repoId)}`;
142
+ const generationRoute = generationRouteForKey(entry.key);
143
+ if (generationRoute) {
144
+ // Defense in depth: the key SHAPE alone is enough to route the read, but
145
+ // cross-checking the listing's own declared object_kind catches a
146
+ // mislabeled entry (gateway bug) loudly instead of silently reading the
147
+ // wrong thing under the right generation. `admissions/<gen>` is always
148
+ // `admission_record`; `head/<gen>` is `vault_genesis` ONLY at generation
149
+ // zero and `head` at every later generation — the kind names the
150
+ // CONTENT, both fetch through the same route.
151
+ const expectedKind = generationRoute.route === "admissions" ? "admission_record" : generationRoute.generation === GITVAULT_GENESIS_GENERATION ? "vault_genesis" : "head";
152
+ if (entry.object_kind !== expectedKind) {
153
+ fail("GITVAULT_MIRROR_KEY_UNRECOGNIZED", `listed object_kind '${entry.object_kind}' does not match its generation-addressed key ${entry.key} (expected '${expectedKind}')`, "reading gitvault mirror source object", { key: entry.key, object_kind: entry.object_kind, expected_object_kind: expectedKind });
154
+ }
155
+ const path = `${base}/${generationRoute.route}/${encodeURIComponent(generationRoute.generation)}`;
156
+ const auth = (await client.credentials.getAuth(path, { method: `gitvault.read_${generationRoute.route}` })) ?? {};
157
+ const r = await client.fetch(`${client.apiBase}${path}`, { method: "GET", headers: { ...auth, accept: "application/json" } });
158
+ if (r.status === 404)
159
+ return null;
160
+ if (!r.ok)
161
+ fail("GITVAULT_MIRROR_READ_FAILED", `${entry.key} read failed (HTTP ${r.status})`, "reading gitvault mirror source object", { key: entry.key, status: r.status });
162
+ return new Uint8Array(await r.arrayBuffer());
163
+ }
164
+ const read = objectReadRequestForEntry(entry);
165
+ let presigned;
166
+ try {
167
+ presigned = await client.request(`${base}/object-reads`, { method: "POST", body: { objects: [read] }, context: "resolving gitvault mirror source object" });
168
+ }
169
+ catch (e) {
170
+ if (isRun402Error(e) && (e.status === 404 || e.code === "RESOURCE_NOT_FOUND"))
171
+ return null;
172
+ throw e;
173
+ }
174
+ const target = presigned.reads[0];
175
+ if (!target)
176
+ return null;
177
+ const r = await client.fetch(target.url, { method: "GET" });
178
+ if (r.status === 404)
179
+ return null;
180
+ if (!r.ok)
181
+ fail("GITVAULT_MIRROR_READ_FAILED", `${entry.key} GET failed (HTTP ${r.status})`, "reading gitvault mirror source object", { key: entry.key, status: r.status });
182
+ return new Uint8Array(await r.arrayBuffer());
183
+ }
184
+ /** Exported for the key-shape conformance test (`gitvault-mirror-recover.test.ts`) — never called for its own sake outside this module. */
185
+ export function generationRouteForKey(key) {
186
+ const head = /^head\/([0-9a-f]{16})$/.exec(key);
187
+ if (head)
188
+ return { route: "heads", generation: head[1] };
189
+ const adm = /^admissions\/([0-9a-f]{16})$/.exec(key);
190
+ if (adm)
191
+ return { route: "admissions", generation: adm[1] };
192
+ return null;
193
+ }
194
+ /**
195
+ * Repo-relative key shapes for every id-addressed, non-generation-addressed
196
+ * kind (`storage-keys.ts` `objectKeyFor` + `upload-sessions.ts`
197
+ * `UPLOADABLE_KINDS`, mirrored here since the SDK has no dependency on the
198
+ * gateway package). ANCHORED (`^…$`) on purpose — the bug this table
199
+ * replaces (task 5.3 finding (b)) was an UNANCHORED fallback regex that
200
+ * greedily matched the REPO ID itself (`src_<32hex>` satisfies the same
201
+ * `[a-z0-9_]+_[0-9a-f]{32}` shape as a real object id) out of a
202
+ * `source/<repo_id>/…` key, sending the wrong object_id to the gateway.
203
+ * Keyed by the listing's own declared `object_kind` (trusted metadata from
204
+ * the gateway) — the pattern then both extracts the id AND validates that
205
+ * the key's shape actually matches its declared kind.
206
+ */
207
+ const NON_GENERATION_KEY_SPECS = [
208
+ { kind: "wal_pack", pattern: /^wal\/(wal_[0-9a-f]{32})\.pack\.enc$/ },
209
+ { kind: "ref_state", pattern: /^refs\/(refs_[0-9a-f]{32})\.enc$/ },
210
+ { kind: "retention_roots", pattern: /^retention\/(rr_[0-9a-f]{32})\.enc$/ },
211
+ { kind: "checkpoint_manifest", pattern: /^checkpoints\/(chk_[0-9a-f]{32})\.manifest\.enc$/ },
212
+ { kind: "checkpoint_pack", pattern: /^checkpoints\/(ckp_[0-9a-f]{32})\.pack\.enc$/ },
213
+ { kind: "checkpoint_claim_set", pattern: /^checkpoints\/(ccs_[0-9a-f]{32})\.claims\.json$/ },
214
+ { kind: "maintenance_stage_claim_set", pattern: /^maintenance\/(msc_[0-9a-f]{32})\.stage\.json$/ },
215
+ { kind: "maintenance_stage_page", pattern: /^maintenance\/(msp_[0-9a-f]{32})\.page\.json$/ },
216
+ { kind: "maintenance_completion_cut", pattern: /^maintenance\/cuts\/(adm_[0-9a-f]{32})\.json$/ },
217
+ { kind: "retention_cutoff", pattern: /^retention\/(rc_[0-9a-f]{32})\.ticket\.json$/ },
218
+ { kind: "prune_intent", pattern: /^prune\/(pi_[0-9a-f]{32})\.intent\.json$/ },
219
+ // prune_completion is filed under the INTENT's own object_id (storage-keys.ts
220
+ // `pruneCompletionKey`) — its key literally carries a `pi_…` id, not `pc_…`.
221
+ { kind: "prune_completion", pattern: /^prune\/(pi_[0-9a-f]{32})\.completion\.json$/ },
222
+ { kind: "verifier_receipt", pattern: /^verifier-receipts\/(vr_[0-9a-f]{32})\.json$/ },
223
+ { kind: "maintenance_cycle_issuance", pattern: /^maintenance\/issued\/(mc_[0-9a-f]{32})\.json$/ },
224
+ { kind: "maintenance_cycle_terminal", pattern: /^maintenance\/terminals\/(mc_[0-9a-f]{32})\.terminal\.json$/ },
225
+ ];
226
+ /**
227
+ * `key_envelope` is path-addressed by `(epoch, recipient_fingerprint)`, not a
228
+ * plain object_id — every other kind uses its object_id, read straight from
229
+ * the key's own filename via an ANCHORED, kind-specific pattern (never a
230
+ * loose, unanchored fallback — see {@link NON_GENERATION_KEY_SPECS}).
231
+ * Exported for the key-shape conformance test.
232
+ */
233
+ export function objectReadRequestForEntry(entry) {
234
+ if (entry.object_kind === "key_envelope") {
235
+ // `key-envelopes/<epoch>/<recipient_fingerprint>.env` — the GATEWAY's
236
+ // real §3 wire key (`packages/gateway/src/services/gitvault/
237
+ // upload-sessions.ts` `UPLOADABLE_KINDS.key_envelope.key()`, mirrored by
238
+ // `storage-keys.ts` `objectKeyFor`). This is what the live objects
239
+ // listing actually returns, and is DIFFERENT from the SDK's own
240
+ // `gitvault-creation-journal.ts` envelope `path` string
241
+ // (`envelopes/<epoch>/<fp>`, no `key-` prefix, no `.env` suffix) — that
242
+ // string is CLIENT-LOCAL addressing for the upload manifest only ("never
243
+ // rides the wire", per its own doc comment); the gateway derives its own
244
+ // key independently and never echoes the client's `path` back. Do not
245
+ // re-derive this from that SDK constant.
246
+ const m = /^key-envelopes\/([0-9a-f]{16})\/(ek_[0-9a-f]{32})\.env$/.exec(entry.key);
247
+ if (!m)
248
+ fail("GITVAULT_MIRROR_KEY_UNRECOGNIZED", `key_envelope key does not match the expected layout: ${entry.key}`, "building gitvault mirror read request", { key: entry.key });
249
+ return { object_kind: "key_envelope", epoch: m[1], recipient_fingerprint: m[2] };
250
+ }
251
+ const spec = NON_GENERATION_KEY_SPECS.find((s) => s.kind === entry.object_kind);
252
+ if (!spec) {
253
+ fail("GITVAULT_MIRROR_KEY_UNRECOGNIZED", `unrecognized object_kind '${entry.object_kind}' for mirror read (key ${entry.key})`, "building gitvault mirror read request", { key: entry.key, object_kind: entry.object_kind });
254
+ }
255
+ const m = spec.pattern.exec(entry.key);
256
+ if (!m)
257
+ fail("GITVAULT_MIRROR_KEY_UNRECOGNIZED", `${entry.object_kind} key does not match the expected §3 layout: ${entry.key}`, "building gitvault mirror read request", { key: entry.key, object_kind: entry.object_kind });
258
+ return { object_kind: entry.object_kind, object_id: m[1] };
259
+ }
260
+ /**
261
+ * Task 5.3 follow-up (found via the live drill 2026-08-26, gateway diagnosis
262
+ * confirmed correct — NOT a bug): the recipient-only read gate on
263
+ * `key_envelope` means a mirror can only ever hold envelopes wrapped for
264
+ * THIS machine's own identity. A multi-recipient vault (gitvault-human-
265
+ * envelopes) makes a foreign-recipient envelope the NORM, not an anomaly —
266
+ * it must never be synced as a failure. This extracts the `ek_` fingerprint
267
+ * straight from the key_envelope's own key (no network round-trip needed to
268
+ * classify it), reusing the exact pattern `objectReadRequestForEntry` uses;
269
+ * `null` for a key that doesn't match the expected layout at all (a real,
270
+ * separate problem — that case falls through to the normal read-and-fail
271
+ * path so `GITVAULT_MIRROR_KEY_UNRECOGNIZED` still surfaces).
272
+ */
273
+ function keyEnvelopeRecipientFingerprintFromKey(key) {
274
+ const m = /^key-envelopes\/[0-9a-f]{16}\/(ek_[0-9a-f]{32})\.env$/.exec(key);
275
+ return m ? m[1] : null;
276
+ }
277
+ /** The local keystore's own `ek_` fingerprint, or `null` when no identity exists on this machine (keyless / never-`gitvault init`-ed). */
278
+ function localEncryptionFingerprint(keystore) {
279
+ return keystore.readIdentity()?.encryption_fingerprint ?? null;
280
+ }
281
+ /** Sort a flat listing into the admission-order write plan (module doc above). */
282
+ export function planMirrorWrite(entries) {
283
+ const objects = [];
284
+ const byGeneration = new Map();
285
+ for (const e of entries) {
286
+ const route = generationRouteForKey(e.key);
287
+ if (!route) {
288
+ objects.push(e);
289
+ continue;
290
+ }
291
+ const slot = byGeneration.get(route.generation) ?? {};
292
+ if (route.route === "admissions")
293
+ slot.admission = e;
294
+ else
295
+ slot.head = e;
296
+ byGeneration.set(route.generation, slot);
297
+ }
298
+ const generations = [...byGeneration.keys()].sort();
299
+ const admissionsAndHeads = [];
300
+ for (const gen of generations) {
301
+ const slot = byGeneration.get(gen);
302
+ if (slot.admission)
303
+ admissionsAndHeads.push(slot.admission);
304
+ if (slot.head)
305
+ admissionsAndHeads.push(slot.head);
306
+ }
307
+ return { objects, admissionsAndHeads };
308
+ }
309
+ /**
310
+ * Copy one entry (presigned GET → hash-verify → mirror create-only PUT) if
311
+ * the mirror does not already hold it at the same size. Idempotent: a
312
+ * matching size is treated as already-present WITHOUT a hash check (D7 —
313
+ * "hash-verified on copy" means on copy, not on every skip, and applies
314
+ * uniformly to every kind now that `size_bytes` is exact for all of them —
315
+ * see the module doc); a size mismatch re-copies and hash-verifies. Every
316
+ * failure is tagged with its `object_kind` so a sync summary's `errors[]` is
317
+ * self-explaining without cross-referencing the listing (task 5.3's "no
318
+ * per-entry reason surfaced" gap).
319
+ *
320
+ * `ownFingerprint` (task 5.3 follow-up): a `key_envelope` entry addressed to
321
+ * a DIFFERENT recipient is classified `skipped_foreign_recipient` BEFORE any
322
+ * network read is attempted (the fingerprint is parsed straight out of the
323
+ * entry's own key) — never a failure, and never even reaches the gateway,
324
+ * which would correctly 403 it under the recipient-only read gate.
325
+ */
326
+ async function reconcileOne(client, repoId, backend, entry, ownFingerprint) {
327
+ const kindTag = `[${entry.object_kind}]`;
328
+ if (entry.object_kind === "key_envelope") {
329
+ const fp = keyEnvelopeRecipientFingerprintFromKey(entry.key);
330
+ if (fp !== null && fp !== ownFingerprint) {
331
+ return { key: entry.key, outcome: "skipped_foreign_recipient" };
332
+ }
333
+ }
334
+ try {
335
+ const existing = await backend.head(entry.key);
336
+ if (existing && existing.size_bytes === entry.size_bytes) {
337
+ return { key: entry.key, outcome: "already_present" };
338
+ }
339
+ const bytes = await readGitvaultObjectBytes(client, repoId, entry);
340
+ if (!bytes)
341
+ return { key: entry.key, outcome: "failed", error: `${kindTag} the source no longer serves this object (listed but unreadable)` };
342
+ const hash = sha256Hex(bytes);
343
+ if (hash !== entry.sha256) {
344
+ return { key: entry.key, outcome: "failed", error: `${kindTag} hash mismatch on copy: expected ${entry.sha256}, got ${hash}` };
345
+ }
346
+ const put = await backend.putCreateOnly(entry.key, bytes);
347
+ if (!put.created) {
348
+ // A concurrent writer (another sync, or the dual-push hook) won the
349
+ // create-only race — benign; the mirror now holds SOME valid bytes at
350
+ // this key, and re-checking their size closes the loop honestly.
351
+ const after = await backend.head(entry.key);
352
+ if (after && after.size_bytes === entry.size_bytes)
353
+ return { key: entry.key, outcome: "already_present" };
354
+ return { key: entry.key, outcome: "failed", error: `${kindTag} mirror key already exists with a different size — refusing to overwrite (content-addressed keys should never collide; investigate)` };
355
+ }
356
+ return { key: entry.key, outcome: "copied", size_bytes: entry.size_bytes };
357
+ }
358
+ catch (e) {
359
+ const message = e instanceof Error ? e.message : String(e);
360
+ return { key: entry.key, outcome: "failed", error: message.startsWith(kindTag) ? message : `${kindTag} ${message}` };
361
+ }
362
+ }
363
+ /**
364
+ * `run402 gitvault mirror sync` (task 2.3): list the vault's stored objects,
365
+ * diff against the mirror by key+size, fetch and hash-verify what's missing,
366
+ * write it in admission order. Resumable and idempotent — running it twice in
367
+ * a row with nothing new copies nothing the second time.
368
+ */
369
+ export async function mirrorSync(client, repoId, options = {}) {
370
+ const keystore = options.keystore ?? GitvaultKeystore.open();
371
+ const backend = options.backend ?? openBackendFromConfig(keystore, repoId);
372
+ const config = readMirrorConfig(keystore, repoId);
373
+ const destination = options.backend ? backend.describe() : formatMirrorDestination(config.destination);
374
+ const ownFingerprint = localEncryptionFingerprint(keystore);
375
+ const entries = await listGitvaultObjectsAll(client, repoId);
376
+ const plan = planMirrorWrite(entries);
377
+ const ordered = [...plan.objects, ...plan.admissionsAndHeads];
378
+ let copied = 0;
379
+ let already = 0;
380
+ let skippedForeign = 0;
381
+ let failed = 0;
382
+ let bytesCopied = 0n;
383
+ const errors = [];
384
+ const skippedForeignKeys = [];
385
+ for (const entry of ordered) {
386
+ const result = await reconcileOne(client, repoId, backend, entry, ownFingerprint);
387
+ if (result.outcome === "copied") {
388
+ copied += 1;
389
+ bytesCopied += BigInt(entry.size_bytes);
390
+ }
391
+ else if (result.outcome === "already_present") {
392
+ already += 1;
393
+ }
394
+ else if (result.outcome === "skipped_foreign_recipient") {
395
+ skippedForeign += 1;
396
+ skippedForeignKeys.push(result.key);
397
+ }
398
+ else {
399
+ failed += 1;
400
+ errors.push({ key: result.key, error: result.error ?? "unknown failure" });
401
+ }
402
+ }
403
+ return {
404
+ repo_id: repoId,
405
+ destination,
406
+ objects_listed: entries.length,
407
+ objects_copied: copied,
408
+ objects_already_present: already,
409
+ objects_skipped_foreign_recipient: skippedForeign,
410
+ skipped_foreign_recipient_keys: skippedForeignKeys,
411
+ objects_failed: failed,
412
+ bytes_copied: bytesCopied.toString(),
413
+ errors,
414
+ validity_not_freshness: GITVAULT_MIRROR_VALIDITY_NOT_FRESHNESS_STATEMENT,
415
+ keystore_still_required: GITVAULT_MIRROR_KEYSTORE_STILL_REQUIRED_STATEMENT,
416
+ };
417
+ }
418
+ function openBackendFromConfig(keystore, repoId) {
419
+ const config = readMirrorConfig(keystore, repoId);
420
+ if (!config)
421
+ fail("GITVAULT_MIRROR_NOT_CONFIGURED", `no mirror is configured for ${repoId}`, "opening gitvault mirror", { repo_id: repoId }, [{ action: "run402 gitvault mirror set <destination>" }]);
422
+ if (config.destination.kind === "s3" && config.credential) {
423
+ // Fail fast on a missing/misconfigured credential BEFORE any network call,
424
+ // so a sync's error names the credential problem instead of a confusing
425
+ // downstream 403.
426
+ resolveMirrorCredentials(config.credential);
427
+ }
428
+ return openGitvaultMirrorBackend(config.destination, repoId, config.credential);
429
+ }
430
+ /**
431
+ * Fires after an ordinary vault push/deploy produces a new generation. NEVER
432
+ * throws and NEVER alters the caller's deploy/push outcome (design D6) — a
433
+ * mirror is strictly extra durability, and its failure is reported BESIDE the
434
+ * vault result as a distinct line, not folded into it. Fires only when a
435
+ * mirror is configured for this vault; a vault with no mirror gets
436
+ * `skipped_no_mirror` (not an error) so callers can log it uniformly without
437
+ * branching on whether mirroring was ever opted into.
438
+ *
439
+ * Implemented as a full (but INCREMENTAL, idempotent) sync rather than a
440
+ * push-scoped upload: the objects listing + diff-by-size machinery already
441
+ * makes an all-caught-up sync cheap (one listing page, zero copies), and this
442
+ * keeps the admission-order write discipline in exactly one place instead of
443
+ * a second, push-scoped code path that could drift from it.
444
+ */
445
+ export async function mirrorPushForGeneration(client, repoId, options = {}) {
446
+ let keystore;
447
+ try {
448
+ keystore = options.keystore ?? GitvaultKeystore.open();
449
+ if (!options.backend && !readMirrorConfig(keystore, repoId)) {
450
+ return { attempted: false, outcome: "skipped_no_mirror" };
451
+ }
452
+ }
453
+ catch (e) {
454
+ return { attempted: false, outcome: "skipped_no_mirror", error: e instanceof Error ? e.message : String(e) };
455
+ }
456
+ try {
457
+ const summary = await mirrorSync(client, repoId, { ...options, keystore });
458
+ return { attempted: true, outcome: summary.objects_failed > 0 ? "failed" : "pushed", summary };
459
+ }
460
+ catch (e) {
461
+ return { attempted: true, outcome: "failed", error: e instanceof Error ? e.message : String(e) };
462
+ }
463
+ }
464
+ //# sourceMappingURL=gitvault-mirror.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitvault-mirror.js","sourceRoot":"","sources":["../../src/node/gitvault-mirror.ts"],"names":[],"mappings":"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"}