@uns-kit/core 3.0.45 → 3.0.46

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.
package/MIGRATIONS.md CHANGED
@@ -9,6 +9,18 @@ Agents must inspect the application's existing ownership and shutdown flow
9
9
  before editing it. The examples below describe the intended behavior, not a
10
10
  mechanical search-and-replace operation.
11
11
 
12
+ ## 3.0.46 - Verified retained-store copy and recovery
13
+
14
+ When crossing `<3.0.46` to `>=3.0.46`, existing rename and unbound consumers
15
+ remain compatible. An explicit
16
+ `transfer: "copy-verified"` adds stopped-source review and bounded asynchronous
17
+ opaque copying between local mounts. Use the same operation/checksum after
18
+ interruption; return current work and retain the original copy. Full Runtime
19
+ recovery requires the matching verified offline retained root before RTT owners
20
+ can be activated. See `docs/retained-store-adoption.md`, bundled as the core
21
+ retained-store guide. No application-specific Controller logic, queue conversion,
22
+ new default handover protocol or automatic disk persistence is introduced.
23
+
12
24
  ## 3.0.45 - Opt-in retained-store storage protocol
13
25
 
14
26
  When crossing `<3.0.45` to `>=3.0.45`, ordinary applications keep their current
@@ -0,0 +1,3 @@
1
+ export type RetainedCopyFingerprint = { digest: string; bytes: number; entries: number };
2
+ export function inspectRetainedCopy(root: string, kind: "file" | "directory", limits: unknown): RetainedCopyFingerprint;
3
+ export function applyRetainedCopy(plan: unknown, direction: "adopt" | "return", limits: unknown, afterMove?: (id: string) => void, onFile?: (file: string) => void): void;
@@ -0,0 +1,133 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { createHash } from "node:crypto";
4
+ import { safePath, owned, sha, sync, entry, relative, checkLimit } from "./retained-store-storage.mjs";
5
+
6
+ function inventory(root, kind, limits) {
7
+ checkLimit(limits);
8
+ const entries = [];
9
+ let bytes = 0;
10
+ function visit(file, rel, depth) {
11
+ if (depth > limits.maximumDepth || (rel && !relative(rel)) || entries.length >= limits.maximumEntries) throw Error("Retained copy path/count limit");
12
+ const stat = entry(file);
13
+ if (!stat) throw Error("Retained copy source is missing");
14
+ if (stat.isDirectory()) {
15
+ owned(file, true);
16
+ entries.push({ path: rel, type: "directory" });
17
+ for (const name of fs.readdirSync(file).sort()) visit(path.join(file, name), rel ? rel + "/" + name : name, depth + 1);
18
+ } else {
19
+ const value = owned(file);
20
+ bytes += value.size;
21
+ if (bytes > limits.maximumBytes || value.size > limits.maximumFileBytes) throw Error("Retained copy byte limit");
22
+ entries.push({ path: rel, type: "file", size: value.size, sha256: sha(file) });
23
+ }
24
+ }
25
+ safePath(root);
26
+ if ((kind === "directory") !== !!entry(root)?.isDirectory()) throw Error("Retained copy resource kind differs");
27
+ visit(root, "", 0);
28
+ return { entries, fingerprint: { digest: createHash("sha256").update(JSON.stringify(entries)).digest("hex"), bytes, entries: entries.length } };
29
+ }
30
+ export function inspectRetainedCopy(root, kind, limits) { return inventory(root, kind, limits).fingerprint; }
31
+ function same(a, b) { return a?.digest === b?.digest && a?.bytes === b?.bytes && a?.entries === b?.entries; }
32
+ function assertFingerprint(file, move, limits) {
33
+ const stat = entry(file);
34
+ if (!stat || stat.dev !== move.device || stat.ino !== move.inode || !same(inspectRetainedCopy(file, move.kind, limits), move.content)) throw Error("Retained copy source changed after review");
35
+ }
36
+ function privateStage(stage) {
37
+ if (!entry(stage)) { fs.mkdirSync(stage, { mode: 0o700 }); sync(path.dirname(stage)); }
38
+ if (owned(stage, true).mode & 0o077) throw Error("Retained copy staging must be private");
39
+ }
40
+ function checkStage(stage, entries) {
41
+ const allowed = new Set(["payload", ...entries.map(e => e.path ? "payload/" + e.path : "payload")]);
42
+ function visit(dir, prefix) {
43
+ for (const name of fs.readdirSync(dir)) {
44
+ const rel = prefix ? prefix + "/" + name : name, file = path.join(dir, name);
45
+ if (!allowed.has(rel)) throw Error("Unexpected retained copy staging entry");
46
+ const stat = entry(file);
47
+ owned(file, !!stat?.isDirectory());
48
+ if (stat.isDirectory()) visit(file, rel);
49
+ }
50
+ }
51
+ visit(stage, "");
52
+ }
53
+ function copyFile(source, destination, expected) {
54
+ if (entry(destination)) owned(destination);
55
+ const input = fs.openSync(source, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
56
+ let output;
57
+ try {
58
+ output = fs.openSync(destination, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_TRUNC | fs.constants.O_NOFOLLOW, 0o600);
59
+ const h = createHash("sha256"), buffer = Buffer.alloc(65536);
60
+ let count = 0, size;
61
+ while ((size = fs.readSync(input, buffer, 0, buffer.length, null))) {
62
+ count += size;
63
+ if (count > expected.size) throw Error("Retained copy source grew");
64
+ h.update(buffer.subarray(0, size));
65
+ let offset = 0;
66
+ while (offset < size) offset += fs.writeSync(output, buffer, offset, size - offset);
67
+ }
68
+ fs.fchmodSync(output, 0o600); fs.fsyncSync(output);
69
+ if (count !== expected.size || h.digest("hex") !== expected.sha256) throw Error("Retained copy source changed while reading");
70
+ } finally { fs.closeSync(input); if(output!==undefined)fs.closeSync(output); }
71
+ }
72
+ function copyClosed(source, destination, stage, move, limits, onFile) {
73
+ assertFingerprint(source, move, limits);
74
+ const snapshot = inventory(source, move.kind, limits);
75
+ if (entry(destination)) {
76
+ if (!same(inspectRetainedCopy(destination, move.kind, limits), move.content)) throw Error("Published retained copy differs; preserve for review");
77
+ if (entry(stage)) { checkStage(stage, snapshot.entries); fs.rmSync(stage, { recursive: true }); sync(path.dirname(stage)); }
78
+ return;
79
+ }
80
+ privateStage(stage); checkStage(stage, snapshot.entries);
81
+ const payload = path.join(stage, "payload");
82
+ for (const item of snapshot.entries) {
83
+ const from = item.path ? path.join(source, item.path) : source, to = item.path ? path.join(payload, item.path) : payload;
84
+ if (item.type === "directory") {
85
+ if (!entry(to)) fs.mkdirSync(to, { mode: 0o700 });
86
+ if (owned(to, true).mode & 0o077) throw Error("Retained stage directory must be private");
87
+ } else {
88
+ if (entry(to) && owned(to).size === item.size && sha(to) === item.sha256) continue;
89
+ copyFile(from, to, item); onFile?.(item.path);
90
+ }
91
+ }
92
+ assertFingerprint(source, move, limits);
93
+ if (!same(inspectRetainedCopy(payload, move.kind, limits), move.content)) throw Error("Retained staged copy differs");
94
+ for (const item of [...snapshot.entries].reverse()) if (item.type === "directory") sync(item.path ? path.join(payload, item.path) : payload);
95
+ fs.renameSync(payload, destination); sync(stage); sync(path.dirname(destination));
96
+ fs.rmdirSync(stage); sync(path.dirname(stage));
97
+ }
98
+ export function applyRetainedCopy(plan, direction, limits, afterMove, onFile) {
99
+ checkLimit(limits); safePath(plan.source); safePath(plan.directory);
100
+ for (const move of plan.moves) {
101
+ const legacy = path.join(plan.source, move.relative), stable = path.join(plan.directory, move.id);
102
+ const stage = direction === "adopt" ? path.join(plan.directory, ".retained-copy-" + move.id) : path.join(plan.source, ".retained-return-" + plan.storeId + "-" + move.id);
103
+ if (direction === "adopt") copyClosed(legacy, stable, stage, move, limits, onFile);
104
+ else {
105
+ assertFingerprint(stable, move, limits);
106
+ const original = plan.originalMoves?.find(m => m.id === move.id), saved = path.join(plan.source, ".retained-original-" + plan.storeId + "-" + move.id);
107
+ if (entry(legacy) && !same(inspectRetainedCopy(legacy, move.kind, limits), move.content)) {
108
+ if (!original || entry(saved)) throw Error("Return would overwrite unreviewed legacy work");
109
+ assertFingerprint(legacy, original, limits);
110
+ fs.renameSync(legacy, saved); sync(path.dirname(legacy));
111
+ }
112
+ if (entry(saved)) {
113
+ if (!original) throw Error("Unreviewed original retained copy");
114
+ assertFingerprint(saved, original, limits);
115
+ }
116
+ copyClosed(stable, legacy, stage, move, limits, onFile);
117
+ }
118
+ afterMove?.(move.id);
119
+ }
120
+ if (direction === "return") {
121
+ for (const original of plan.originalMoves ?? []) {
122
+ const stage = path.join(plan.directory, ".retained-copy-" + original.id);
123
+ if (!entry(stage)) continue;
124
+ const legacy = path.join(plan.source, original.relative);
125
+ if (!plan.moves.some(m => m.id === original.id)) assertFingerprint(legacy, original, limits);
126
+ const reference = plan.moves.some(m => m.id === original.id) ? path.join(plan.directory, original.id) : legacy;
127
+ const snapshot = inventory(reference, original.kind, limits);
128
+ checkStage(stage, snapshot.entries);
129
+ // Only incomplete scratch is discarded; all original bytes remain proven.
130
+ fs.rmSync(stage, { recursive: true }); sync(plan.directory);
131
+ }
132
+ }
133
+ }
@@ -1,7 +1,8 @@
1
1
  # Retained stores: opt-in same-host adoption
2
2
 
3
- Prepared in UNS Kit 3.0.45; npm publication and coordinated Controller/Runtime
4
- releases are separate steps. Existing applications do not change behavior.
3
+ Retained-store adoption starts in UNS Kit 3.0.45. The 3.0.46 extension adds
4
+ explicit copying between local mounts and verification of recovered stores.
5
+ Managed activation requires coordinated Controller and Runtime releases. Existing applications do not change behavior.
5
6
  This is a filesystem capability, separate from the small JSON
6
7
  handover-state contract and MQTT output persistence. It does not change the
7
8
  default handover protocol, enable disk queues, or transfer data between hosts.
@@ -120,3 +121,44 @@ cannot be used as a complete queue restore. Restore retains store/owner/generati
120
121
  identity at the same logical root on another offline volume, and leaves an applying
121
122
  fence until complete. Known private partial staging files may be re-created only
122
123
  from the verified snapshot; differing published work is never overwritten.
124
+
125
+ ## Cross-mount transfer and recovery verification in 3.0.46
126
+
127
+ Same-filesystem rename remains the default.
128
+ For initial relocation to a separately mounted Runtime volume, the host may
129
+ explicitly select `transfer: "copy-verified"`. Stop the source cleanly **before**
130
+ reviewing this transport. Review pins content hashes, aggregate byte/file counts,
131
+ resource identities, both installed artifacts, configuration and supervisor epoch.
132
+ There is no automatic `EXDEV` fallback or caller-selected filesystem path.
133
+
134
+ The host uses `prepareRetainedStoreMoveAsync`, `applyRetainedStoreMoveAsync` and
135
+ `prepareRetainedStoreReturnAsync`. Bounded worker jobs perform opaque hashing and
136
+ copying while the host event loop can serve health and recovery reads. Persist the
137
+ complete plan before mutation and hold the existing maintenance/lifecycle fences
138
+ through the durable outcome. Jobs have a 128MiB old-generation heap and a 300s
139
+ bound; uncertainty always requires reconciliation of the same operation.
140
+
141
+ Copy stages and fsyncs each declared resource on its receiving mount, verifies
142
+ its exact contents and atomically publishes it. Source files remain unchanged and
143
+ fenced; allow space for both copies. Known incomplete scratch can be resumed from
144
+ the unchanged reviewed source. Unknown entries, links, changed source bytes and
145
+ differing published files are preserved and refused. The existing limits remain
146
+ 32 stores, 100,000 entries, 64GiB aggregate files and 32GiB per file.
147
+
148
+ Return copies the **current** stopped store back. If current work differs from
149
+ the original, the original is first preserved as
150
+ `.retained-original-<store UUID>-<resource ID>` beside its legacy path. The retired
151
+ stable copy remains inert and is included by full backup; it cannot acquire a
152
+ runtime lease. No cleanup, resource merge, conversion or cross-host transfer is
153
+ implied. Runtime disk capacity and the application's destination acknowledgement
154
+ semantics remain independent operational requirements.
155
+
156
+ Offline restore now retains a verified local snapshot manifest. The data-only
157
+ `verify-restored` / `verify-root` actions rehash exact declared payloads under an
158
+ exclusive root lease before Runtime activation. A completed restore retry never
159
+ replaces newer application data. Full RTT stage/activation/completion binds the
160
+ verified root, signed backup digest and local manifest digest into its protected
161
+ receipts. Missing, excluded, unfinished or altered storage cannot enable bound
162
+ owners. After application work advances, do not activate an old snapshot: preserve
163
+ current storage and use a fresh reviewed owner transition. Historic operation
164
+ plans pin original physical files and are not rebased after a full restore.
@@ -0,0 +1 @@
1
+ export function retainedStoreJob(job: unknown, onProgress?: (id: string) => void): Promise<unknown>;
@@ -0,0 +1,28 @@
1
+ import { Worker, isMainThread, parentPort, workerData } from "node:worker_threads";
2
+ import { inspectRetainedCopy, applyRetainedCopy } from "./retained-store-copy.mjs";
3
+ if (!isMainThread) {
4
+ const job = workerData;
5
+ if (job.action === "inspect") parentPort.postMessage({ done: true, result: inspectRetainedCopy(job.path, job.kind, job.limits) });
6
+ else if (job.action === "apply") {
7
+ applyRetainedCopy(job.plan, job.direction, job.limits, id => parentPort.postMessage({ progress: id }));
8
+ parentPort.postMessage({ done: true });
9
+ } else throw Error("Unknown retained storage job");
10
+ }
11
+ export function retainedStoreJob(job, onProgress) {
12
+ if (!isMainThread) throw Error("Nested retained storage job");
13
+ return new Promise((resolve, reject) => {
14
+ const worker = new Worker(new URL(import.meta.url), { workerData: job, execArgv: [], env: { NODE_NO_WARNINGS: "1" }, resourceLimits: { maxOldGenerationSizeMb: 128 } });
15
+ let done = false;
16
+ const timer = setTimeout(() => finish(Error("Retained storage job timed out; reconcile the same operation")), 300000);
17
+ const finish = (error, result) => {
18
+ if (done) return; done = true; clearTimeout(timer);
19
+ void worker.terminate().finally(() => error ? reject(error) : resolve(result));
20
+ };
21
+ worker.on("message", message => {
22
+ if (message.progress) { try { onProgress?.(message.progress); } catch (error) { finish(error); } }
23
+ if (message.done) finish(undefined, message.result);
24
+ });
25
+ worker.once("error", error => finish(error));
26
+ worker.once("exit", () => { if (!done) finish(Error("Retained storage job exited without confirmation; reconcile the same operation")); });
27
+ });
28
+ }
@@ -15,3 +15,10 @@ export function restoreRetained(
15
15
  afterPublish?: (id: string) => void,
16
16
  ): { state: string; stores: number };
17
17
  export function available(root: string): void;
18
+ export function owned(path: string, directory?: boolean): import("node:fs").Stats;
19
+ export function sha(path: string): string;
20
+ export function sync(path: string): void;
21
+ export function relative(path: string): boolean;
22
+ export function checkLimit(limits: unknown): void;
23
+ export function verifyRestoredRetained(source:string,root:string,backupDigest:string,limits:unknown):{state:string;stores:number;backupDigest:string;manifestDigest:string;root:string};
24
+ export function verifyRetainedRecoveryRoot(root:string,backupDigest:string,manifestDigest:string,limits:unknown):{state:string;stores:number;backupDigest:string;manifestDigest:string;root:string};
@@ -4,6 +4,7 @@ import path from "node:path";
4
4
  import { DatabaseSync } from "node:sqlite";
5
5
 
6
6
  export const RESTORE_FILE = "retained-store-restore.json";
7
+ export const RESTORE_MANIFEST = "retained-store-restore-manifest.json";
7
8
  export const DECLARATION = "store-resources.json";
8
9
  export const OPERATION = "store-operation.json";
9
10
  const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
@@ -21,7 +22,7 @@ export function safePath(p) {
21
22
  if (!path.isAbsolute(p) || path.normalize(p) !== p) throw Error("Unsafe retained path");
22
23
  for (let a = p; a !== path.dirname(a); a = path.dirname(a)) if (entry(a)?.isSymbolicLink()) throw Error("Linked retained path");
23
24
  }
24
- function owned(p, directory = false) {
25
+ export function owned(p, directory = false) {
25
26
  safePath(p);
26
27
  const s = entry(p);
27
28
  if (!s || s.uid !== process.getuid?.() || s.isSymbolicLink() || (directory ? !s.isDirectory() : !s.isFile() || s.nlink !== 1))
@@ -38,7 +39,7 @@ export function readJSON(p, limit = 131072) {
38
39
  if (s.size > limit) throw Error("Retained metadata limit");
39
40
  return JSON.parse(fs.readFileSync(p, "utf8"));
40
41
  }
41
- function sync(p) {
42
+ export function sync(p) {
42
43
  const fd = fs.openSync(p, "r");
43
44
  try {
44
45
  fs.fsyncSync(fd);
@@ -147,7 +148,7 @@ export function runtimeLease(binding) {
147
148
  throw e;
148
149
  }
149
150
  }
150
- function sha(file) {
151
+ export function sha(file) {
151
152
  const fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
152
153
  const h = createHash("sha256"),
153
154
  buffer = Buffer.alloc(65536);
@@ -159,7 +160,7 @@ function sha(file) {
159
160
  fs.closeSync(fd);
160
161
  }
161
162
  }
162
- function relative(p) {
163
+ export function relative(p) {
163
164
  return (
164
165
  typeof p === "string" &&
165
166
  p.length <= 4096 &&
@@ -212,7 +213,7 @@ function declaration(value, format) {
212
213
  }
213
214
  return value;
214
215
  }
215
- function checkLimit(limits) {
216
+ export function checkLimit(limits) {
216
217
  if (
217
218
  limits.schemaVersion !== 1 ||
218
219
  limits.maximumStores !== 32 ||
@@ -258,7 +259,7 @@ export function captureRetained(root, destination, mode, limits) {
258
259
  }
259
260
  const names = fs.readdirSync(root).sort();
260
261
  for (const id of names) {
261
- if (["retained-root-lease.sqlite", RESTORE_FILE].includes(id)) continue;
262
+ if (["retained-root-lease.sqlite", RESTORE_FILE,RESTORE_MANIFEST].includes(id)) continue;
262
263
  if (!uuid.test(id) || manifest.stores.length >= limits.maximumStores) throw Error("Unexpected retained root entry");
263
264
  const dir = path.join(root, id);
264
265
  privateRoot(dir);
@@ -267,30 +268,25 @@ export function captureRetained(root, destination, mode, limits) {
267
268
  if (entry(path.join(dir, OPERATION))) throw Error("Retained operation is incomplete");
268
269
  const b = binding(readJSON(path.join(dir, "store.json")), root, id);
269
270
  const d = declaration(readJSON(path.join(dir, DECLARATION)), b.format);
270
- if (entry(path.join(dir, "store-returned.json"))) {
271
- if (fs.readdirSync(dir).some((n) => !["store.json", DECLARATION, "store-lease.sqlite", "store-returned.json"].includes(n)))
272
- throw Error("Undeclared returned-store entry");
271
+ const retired = !!entry(path.join(dir, "store-returned.json"));
272
+ if (retired) {
273
273
  const r = readJSON(path.join(dir, "store-returned.json"));
274
- if (r.operationId !== b.operationId || r.generation !== b.generation || d.resources.some((x) => entry(path.join(dir, x.id))))
274
+ if (r.operationId !== b.operationId || r.generation !== b.generation)
275
275
  throw Error("Uncertain returned store");
276
- fs.mkdirSync(path.join(destination, id), { mode: 0o700 });
277
- manifest.entries.push({ path: id, type: "directory" });
278
- for (const name of ["store.json", DECLARATION, "store-returned.json"]) copy(path.join(dir, name), id + "/" + name);
279
- manifest.stores.push({ binding: b, storeId: id, generation: b.generation, owner: b.owner, format: b.format, resources: [], retired: true });
280
- continue;
281
276
  }
282
- const allowed = new Set(["store.json", DECLARATION, "store-lease.sqlite", ...d.resources.map((x) => x.id)]);
277
+ const allowed = new Set(["store.json", DECLARATION, "store-lease.sqlite", ...(retired?["store-returned.json"]:[]), ...d.resources.map((x) => x.id)]);
283
278
  if (fs.readdirSync(dir).some((n) => !allowed.has(n))) throw Error("Undeclared retained entry");
284
279
  fs.mkdirSync(path.join(destination, id), { mode: 0o700 });
285
280
  manifest.entries.push({ path: id, type: "directory" });
286
281
  copy(path.join(dir, "store.json"), id + "/store.json");
287
282
  copy(path.join(dir, DECLARATION), id + "/" + DECLARATION);
283
+ if(retired)copy(path.join(dir,"store-returned.json"),id+"/store-returned.json");
288
284
  const resources = [];
289
285
  for (const r of d.resources) {
290
286
  const p = path.join(dir, r.id),
291
287
  s = entry(p);
292
288
  if (!s) {
293
- if (r.required) throw Error("Required retained resource missing");
289
+ if (r.required && !retired) throw Error("Required retained resource missing");
294
290
  continue;
295
291
  }
296
292
  if ((r.kind === "directory") !== s.isDirectory()) throw Error("Retained resource kind mismatch");
@@ -298,7 +294,7 @@ export function captureRetained(root, destination, mode, limits) {
298
294
  resources.push({ id: r.id, backup: r.backup ?? "payload", included });
299
295
  if (included) copy(p, id + "/" + r.id);
300
296
  }
301
- manifest.stores.push({ binding: b, storeId: id, generation: b.generation, owner: b.owner, format: b.format, resources });
297
+ manifest.stores.push({ binding: b, storeId: id, generation: b.generation, owner: b.owner, format: b.format, resources, ...(retired?{retired:true}:{}) });
302
298
  }
303
299
  const raw = JSON.stringify(manifest);
304
300
  if (Buffer.byteLength(raw) > limits.maximumManifestBytes) throw Error("Retained manifest limit");
@@ -363,7 +359,7 @@ function verifySnapshot(source, limits) {
363
359
  if (stores.size !== m.stores.length || m.entries.some((e) => !stores.has(e.path.split("/")[0]))) throw Error("Undeclared snapshot store");
364
360
  for (const st of m.stores) {
365
361
  const b = binding(readJSON(path.join(source, st.storeId, "store.json")), m.sourceRoot, st.storeId);
366
- declaration(readJSON(path.join(source, st.storeId, DECLARATION)), b.format);
362
+ const declared=declaration(readJSON(path.join(source, st.storeId, DECLARATION)), b.format);
367
363
  if (st.retired) {
368
364
  const r = readJSON(path.join(source, st.storeId, "store-returned.json"));
369
365
  if (
@@ -371,7 +367,7 @@ function verifySnapshot(source, limits) {
371
367
  r.generation !== b.generation ||
372
368
  m.entries.some(
373
369
  (e) =>
374
- e.path.startsWith(st.storeId + "/") && !["store.json", DECLARATION, "store-returned.json"].includes(e.path.slice(st.storeId.length + 1)),
370
+ e.path.startsWith(st.storeId + "/") && !["store.json", DECLARATION, "store-returned.json",...declared.resources.map(r=>r.id)].includes(e.path.slice(st.storeId.length + 1).split("/")[0]),
375
371
  )
376
372
  )
377
373
  throw Error("Invalid retired-store receipt");
@@ -397,6 +393,7 @@ export function restoreRetained(source, root, backupDigest, limits, afterPublish
397
393
  if (new Set(ids).size !== ids.length || ids.some((id) => !uuid.test(id))) throw Error("Invalid snapshot store identities");
398
394
  if (marker?.state === "complete") {
399
395
  for (const id of ids) binding(readJSON(path.join(root, id, "store.json")), root, id);
396
+ persistRecoveryManifest(source,root,manifestDigest);
400
397
  return { state: "complete", stores: ids.length };
401
398
  }
402
399
  if (!marker) {
@@ -404,10 +401,11 @@ export function restoreRetained(source, root, backupDigest, limits, afterPublish
404
401
  marker = { protocol: 1, state: "applying", backupDigest, manifestDigest };
405
402
  atomicJSON(markerFile, marker);
406
403
  }
404
+ persistRecoveryManifest(source,root,manifestDigest);
407
405
  const stage = path.join(root, "retained-restore-stage");
408
406
  if (!entry(stage)) fs.mkdirSync(stage, { mode: 0o700 });
409
407
  privateRoot(stage);
410
- const allowed = new Set(["retained-root-lease.sqlite", RESTORE_FILE, "retained-restore-stage", ...ids]);
408
+ const allowed = new Set(["retained-root-lease.sqlite", RESTORE_FILE,RESTORE_MANIFEST, "retained-restore-stage", ...ids]);
411
409
  if (fs.readdirSync(root).some((n) => !allowed.has(n))) throw Error("Unexpected restore target entry");
412
410
  for (const e of m.entries) {
413
411
  const id = e.path.split("/")[0],
@@ -486,8 +484,55 @@ export function retainedStorageMain() {
486
484
  ? captureRetained(root, out, modeOrDigest, limits)
487
485
  : action === "restore"
488
486
  ? restoreRetained(root, out, modeOrDigest, limits)
487
+ : action === "verify-restored"
488
+ ? verifyRestoredRetained(root,out,modeOrDigest,limits)
489
+ : action === "verify-root"
490
+ ? verifyRetainedRecoveryRoot(root,modeOrDigest,out,limits)
489
491
  : (() => {
490
492
  throw Error("Unknown retained operation");
491
493
  })();
492
494
  process.stdout.write(JSON.stringify(result));
493
495
  }
496
+
497
+ /** Offline proof tied to one verified backup, used before an RTT tree can activate. */
498
+ export function verifyRestoredRetained(source,root,backupDigest,limits){
499
+ checkLimit(limits);
500
+ const m=verifySnapshot(source,limits);
501
+ if(m.mode!=="include"||m.sourceRoot!==root||!hash.test(backupDigest))throw Error("Retained recovery scope differs");
502
+ return verifyRetainedRecoveryRoot(root,backupDigest,sha(path.join(source,"manifest.json")),limits);
503
+ }
504
+ function persistRecoveryManifest(source,root,digest){
505
+ const target=path.join(root,RESTORE_MANIFEST);
506
+ const temporary=target+".part";
507
+ if(entry(temporary)){owned(temporary);fs.unlinkSync(temporary);sync(root);}
508
+ if(entry(target)){if(sha(target)!==digest)throw Error("Retained recovery manifest differs");return;}
509
+ try{fs.copyFileSync(path.join(source,"manifest.json"),temporary,fs.constants.COPYFILE_EXCL);fs.chmodSync(temporary,0o600);sync(temporary);if(sha(temporary)!==digest)throw Error("Retained recovery manifest changed");fs.renameSync(temporary,target);sync(root);}finally{if(entry(temporary))fs.unlinkSync(temporary);}
510
+ }
511
+ export function verifyRetainedRecoveryRoot(root,backupDigest,digest,limits){
512
+ checkLimit(limits);
513
+ if(!hash.test(backupDigest)||!hash.test(digest))throw Error("Invalid retained recovery proof");
514
+ const release=rootLease(root,true,true);
515
+ try{
516
+ const marker=readJSON(path.join(root,RESTORE_FILE));
517
+ if(marker.state!=="complete"||marker.backupDigest!==backupDigest||marker.manifestDigest!==digest)throw Error("Matching completed retained recovery is required");
518
+ const file=path.join(root,RESTORE_MANIFEST);
519
+ if(sha(file)!==digest)throw Error("Retained recovery manifest differs");
520
+ const m=readJSON(file,limits.maximumManifestBytes);
521
+ if(m.schemaVersion!==1||m.kind!=="uns-retained-store-snapshot"||m.mode!=="include"||m.sourceRoot!==root||!Array.isArray(m.stores)||m.stores.length>limits.maximumStores||!Array.isArray(m.entries)||m.entries.length>limits.maximumEntries)throw Error("Invalid retained recovery manifest");
522
+ const ids=m.stores.map(s=>s.storeId);
523
+ if(new Set(ids).size!==ids.length||ids.some(id=>!uuid.test(id)))throw Error("Invalid recovered stores");
524
+ if(fs.readdirSync(root).some(n=>!["retained-root-lease.sqlite",RESTORE_FILE,RESTORE_MANIFEST,...ids].includes(n)))throw Error("Unexpected retained recovery root entry");
525
+ const seen=new Set();let total=0;
526
+ for(const e of m.entries){
527
+ if(!relative(e.path)||!ids.includes(e.path.split('/')[0])||seen.has(e.path)||!["file","directory"].includes(e.type))throw Error("Invalid retained recovery path");seen.add(e.path);
528
+ const p=path.join(root,e.path),s=owned(p,e.type==="directory");
529
+ if(e.type==="file"){total+=s.size;if(total>limits.maximumBytes||s.size>limits.maximumFileBytes||s.size!==e.size||sha(p)!==e.sha256)throw Error("Restored retained payload changed before activation");}
530
+ }
531
+ for(const id of ids){
532
+ const prefix=id+"/",dir=path.join(root,id),allowed=new Set(m.entries.filter(e=>e.path.startsWith(prefix)).map(e=>e.path.slice(prefix.length)));
533
+ if(entry(path.join(dir,"store-lease.sqlite"))){owned(path.join(dir,"store-lease.sqlite"));allowed.add("store-lease.sqlite");}
534
+ exactTree(dir,allowed);
535
+ }
536
+ return{state:"verified",stores:ids.length,backupDigest,manifestDigest:digest,root};
537
+ }finally{release();}
538
+ }
@@ -1,5 +1,6 @@
1
1
  import * as fs from "node:fs";
2
2
  import { z } from "zod";
3
+ import { type RetainedCopyFingerprint } from "./retained-store-copy.mjs";
3
4
  export declare const RETAINED_STORE_MANIFEST = "retained-store.manifest.json";
4
5
  export declare const RETAINED_STORE_BINDING = "retained-store-binding.json";
5
6
  export declare const RETAINED_STORE_GUARD = "retained-store-guard.json";
@@ -45,6 +46,7 @@ export type ResourceMove = {
45
46
  kind: "file" | "directory";
46
47
  device: number;
47
48
  inode: number;
49
+ content?: RetainedCopyFingerprint;
48
50
  };
49
51
  export type StoreMovePlan = {
50
52
  storeId: string;
@@ -54,6 +56,8 @@ export type StoreMovePlan = {
54
56
  directory: string;
55
57
  slots: RetainedStoreManifest["resources"];
56
58
  moves: ResourceMove[];
59
+ transfer?: "copy-verified";
60
+ originalMoves?: ResourceMove[];
57
61
  };
58
62
  export declare function retainedStoreDigest(value: unknown): string;
59
63
  export declare function retainedStoreEntry(file: string): fs.Stats | undefined;
@@ -62,10 +66,10 @@ export declare function readRetainedStoreJson(file: string): unknown;
62
66
  export declare function syncRetainedDirectory(directory: string): void;
63
67
  export declare function writeRetainedStoreJson(file: string, value: unknown): void;
64
68
  export declare function readRetainedStoreManifest(packageDirectory: string): RetainedStoreManifest;
65
- export declare function prepareRetainedStoreMove(source: string, root: string, storeId: string, manifest: RetainedStoreManifest): StoreMovePlan;
69
+ export declare function prepareRetainedStoreMove(source: string, root: string, storeId: string, manifest: RetainedStoreManifest, transfer?: "copy-verified", deferContent?: boolean): StoreMovePlan;
66
70
  /** Caller durably records the complete plan and holds its resource reservation first.
67
71
  * Each rename is atomic; the multi-resource operation is deliberately resumable. */
68
- export declare function applyRetainedStoreMove(plan: StoreMovePlan, direction: "adopt" | "return", afterMove?: (id: string) => void): void;
72
+ export declare function applyRetainedStoreMove(plan: StoreMovePlan, direction: "adopt" | "return", afterMove?: (id: string) => void, onFile?: (file: string) => void, validateOnly?: boolean): void;
69
73
  export declare function writeRetainedStoreBinding(instanceDirectory: string, binding: StoreBinding): void;
70
74
  export declare function loadRetainedStoreBinding(instanceDirectory: string, operationId?: string): StoreBinding | undefined;
71
75
  /** No application payload/schema inspection is performed by this helper. */
@@ -80,6 +84,7 @@ export declare const retainedStoreSelectionSchema: z.ZodObject<{
80
84
  sourceInstanceId: z.ZodString;
81
85
  targetVersion: z.ZodString;
82
86
  targetInstanceId: z.ZodString;
87
+ transfer: z.ZodOptional<z.ZodLiteral<"copy-verified">>;
83
88
  }, z.core.$strict>;
84
89
  export declare const retainedStoreRequestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
85
90
  action: z.ZodLiteral<"review">;
@@ -90,6 +95,7 @@ export declare const retainedStoreRequestSchema: z.ZodDiscriminatedUnion<[z.ZodO
90
95
  sourceInstanceId: z.ZodString;
91
96
  targetVersion: z.ZodString;
92
97
  targetInstanceId: z.ZodString;
98
+ transfer: z.ZodOptional<z.ZodLiteral<"copy-verified">>;
93
99
  }, z.core.$strict>;
94
100
  }, z.core.$strict>, z.ZodObject<{
95
101
  action: z.ZodLiteral<"get">;
@@ -104,12 +110,15 @@ export declare const retainedStoreRequestSchema: z.ZodDiscriminatedUnion<[z.ZodO
104
110
  }, z.core.$strict>], "action">;
105
111
  export type RetainedStoreRequest = z.infer<typeof retainedStoreRequestSchema>;
106
112
  /** Capture mutable control files from the current stopped owner before persisting return intent. */
107
- export declare function prepareRetainedStoreReturn(plan: StoreMovePlan): StoreMovePlan;
113
+ export declare function prepareRetainedStoreReturn(plan: StoreMovePlan, deferContent?: boolean): StoreMovePlan;
108
114
  export declare function retainedStoreRoot(defaultBase: string, configured?: string): string;
109
115
  export declare function openRetainedStoreLease(binding: StoreBinding): {
110
116
  close: () => void;
111
117
  };
112
118
  export declare function openRetainedStoreMaintenance(directory: string): () => void;
119
+ export declare function prepareRetainedStoreMoveAsync(source: string, root: string, id: string, manifest: RetainedStoreManifest, transfer?: "copy-verified"): Promise<StoreMovePlan>;
120
+ export declare function prepareRetainedStoreReturnAsync(plan: StoreMovePlan): Promise<StoreMovePlan>;
121
+ export declare function applyRetainedStoreMoveAsync(plan: StoreMovePlan, direction: "adopt" | "return", afterMove?: (id: string) => void): Promise<void>;
113
122
  export declare const retainedStoreBackupSchema: z.ZodObject<{
114
123
  schemaVersion: z.ZodLiteral<1>;
115
124
  state: z.ZodEnum<{
@@ -1 +1 @@
1
- {"version":3,"file":"retained-store.d.ts","sourceRoot":"","sources":["../../src/runtime/retained-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"retained-store.d.ts","sourceRoot":"","sources":["../../src/runtime/retained-store.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,9 @@ import * as fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { z } from "zod";
5
5
  import { available, maintenanceLease, runtimeLease } from "./retained-store-storage.mjs";
6
+ import { inspectRetainedCopy, applyRetainedCopy } from "./retained-store-copy.mjs";
7
+ import { retainedStoreJob } from "./retained-store-job.mjs";
8
+ const copyLimits = () => JSON.parse(fs.readFileSync(new URL("./retained-store-storage-contract.json", import.meta.url), "utf8"));
6
9
  const segment = z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/);
7
10
  const relative = z
8
11
  .string()
@@ -137,7 +140,7 @@ export function writeRetainedStoreJson(file, value) {
137
140
  export function readRetainedStoreManifest(packageDirectory) {
138
141
  return retainedStoreManifestSchema.parse(readRetainedStoreJson(path.join(packageDirectory, RETAINED_STORE_MANIFEST)));
139
142
  }
140
- export function prepareRetainedStoreMove(source, root, storeId, manifest) {
143
+ export function prepareRetainedStoreMove(source, root, storeId, manifest, transfer, deferContent = false) {
141
144
  z.uuid().parse(storeId);
142
145
  retainedStoreManifestSchema.parse(manifest);
143
146
  assertRetainedStorePath(source);
@@ -151,8 +154,10 @@ export function prepareRetainedStoreMove(source, root, storeId, manifest) {
151
154
  const rootStat = existingRoot ?? fs.statSync(path.dirname(root)), sourceStat = fs.statSync(source);
152
155
  if (root === source || root.startsWith(source + path.sep) || source.startsWith(root + path.sep))
153
156
  throw Error("Nested retained store roots");
154
- if (rootStat.dev !== sourceStat.dev)
155
- throw Error("Retained store requires same filesystem; copy is not permitted");
157
+ if (transfer !== undefined && transfer !== "copy-verified")
158
+ throw Error("Unsupported retained transfer");
159
+ if (!transfer && rootStat.dev !== sourceStat.dev)
160
+ throw Error("Retained store requires same filesystem; review an explicit verified copy");
156
161
  const moves = [];
157
162
  for (const resource of manifest.resources) {
158
163
  const file = path.join(source, resource.path);
@@ -164,13 +169,16 @@ export function prepareRetainedStoreMove(source, root, storeId, manifest) {
164
169
  continue;
165
170
  }
166
171
  if (s.uid !== process.getuid?.() ||
167
- s.dev !== rootStat.dev ||
172
+ (!transfer && s.dev !== rootStat.dev) ||
168
173
  s.isSymbolicLink() ||
169
174
  (resource.kind === "file" ? !s.isFile() || s.nlink !== 1 : !s.isDirectory()))
170
175
  throw Error("Unsafe retained resource");
171
- moves.push({ id: resource.id, relative: resource.path, kind: resource.kind, device: s.dev, inode: s.ino });
176
+ moves.push({ id: resource.id, relative: resource.path, kind: resource.kind, device: s.dev, inode: s.ino,
177
+ ...(transfer && !deferContent ? { content: inspectRetainedCopy(file, resource.kind, copyLimits()) } : {}) });
172
178
  }
173
- return { storeId, generation: randomUUID(), format: manifest.format, source, directory, slots: manifest.resources, moves };
179
+ if (transfer && (moves.reduce((n, m) => n + (m.content?.bytes ?? 0), 0) > copyLimits().maximumBytes || moves.reduce((n, m) => n + (m.content?.entries ?? 0), 0) > copyLimits().maximumEntries))
180
+ throw Error("Retained copy aggregate limit");
181
+ return { storeId, generation: randomUUID(), format: manifest.format, source, directory, slots: manifest.resources, moves, ...(transfer ? { transfer } : {}) };
174
182
  }
175
183
  function matches(file, move) {
176
184
  assertRetainedStorePath(file);
@@ -184,7 +192,8 @@ function matches(file, move) {
184
192
  }
185
193
  /** Caller durably records the complete plan and holds its resource reservation first.
186
194
  * Each rename is atomic; the multi-resource operation is deliberately resumable. */
187
- export function applyRetainedStoreMove(plan, direction, afterMove) {
195
+ export function applyRetainedStoreMove(plan, direction, afterMove, onFile, validateOnly = false) {
196
+ const resourceMove = z.object({ id: segment, relative, kind: z.enum(["file", "directory"]), device: z.number().int().nonnegative(), inode: z.number().int().nonnegative(), content: z.object({ digest: z.string().regex(/^[a-f0-9]{64}$/), bytes: z.number().int().nonnegative().max(copyLimits().maximumBytes), entries: z.number().int().positive().max(copyLimits().maximumEntries) }).strict().optional() }).strict();
188
197
  z.object({
189
198
  storeId: z.uuid(),
190
199
  generation: z.uuid(),
@@ -202,17 +211,9 @@ export function applyRetainedStoreMove(plan, direction, afterMove) {
202
211
  })
203
212
  .strict())
204
213
  .max(16),
205
- moves: z
206
- .array(z
207
- .object({
208
- id: segment,
209
- relative,
210
- kind: z.enum(["file", "directory"]),
211
- device: z.number().int().nonnegative(),
212
- inode: z.number().int().nonnegative(),
213
- })
214
- .strict())
215
- .max(16),
214
+ moves: z.array(resourceMove).max(16),
215
+ transfer: z.literal("copy-verified").optional(),
216
+ originalMoves: z.array(resourceMove).max(16).optional(),
216
217
  })
217
218
  .strict()
218
219
  .parse(plan);
@@ -234,6 +235,20 @@ export function applyRetainedStoreMove(plan, direction, afterMove) {
234
235
  const directoryStat = fs.lstatSync(plan.directory);
235
236
  if (!directoryStat.isDirectory() || directoryStat.uid !== process.getuid?.() || directoryStat.mode & 0o077)
236
237
  throw Error("Unsafe retained store directory");
238
+ if (plan.transfer) {
239
+ if (plan.moves.some(m => !m.content) || plan.originalMoves?.some(m => !m.content))
240
+ throw Error("Verified copy requires reviewed content fingerprints");
241
+ for (const entries of [plan.moves, plan.originalMoves ?? []])
242
+ if (entries.reduce((n, m) => n + (m.content?.bytes ?? 0), 0) > copyLimits().maximumBytes || entries.reduce((n, m) => n + (m.content?.entries ?? 0), 0) > copyLimits().maximumEntries)
243
+ throw Error("Retained copy aggregate limit");
244
+ if ((plan.originalMoves ?? []).some(m => !manifest.resources.some(r => r.id === m.id && r.path === m.relative && r.kind === m.kind)))
245
+ throw Error("Original copy differs from declared resources");
246
+ if (!validateOnly)
247
+ applyRetainedCopy(plan, direction, copyLimits(), afterMove, onFile);
248
+ return;
249
+ }
250
+ if (plan.originalMoves)
251
+ throw Error("Original copy receipt requires verified transfer");
237
252
  for (const move of plan.moves) {
238
253
  const legacy = path.join(plan.source, move.relative), stable = path.join(plan.directory, move.id);
239
254
  const [from, to] = direction === "adopt" ? [legacy, stable] : [stable, legacy];
@@ -314,6 +329,7 @@ export const retainedStoreSelectionSchema = z
314
329
  sourceInstanceId: segment,
315
330
  targetVersion: segment,
316
331
  targetInstanceId: segment,
332
+ transfer: z.literal("copy-verified").optional(),
317
333
  })
318
334
  .strict()
319
335
  .refine((x) => x.sourceVersion !== x.targetVersion || x.sourceInstanceId !== x.targetInstanceId, "Source and target must differ");
@@ -323,8 +339,25 @@ export const retainedStoreRequestSchema = z.discriminatedUnion("action", [
323
339
  z.object({ action: z.enum(["adopt", "return"]), id: z.uuid(), reviewedChecksum: z.string().regex(/^[a-f0-9]{64}$/) }).strict(),
324
340
  ]);
325
341
  /** Capture mutable control files from the current stopped owner before persisting return intent. */
326
- export function prepareRetainedStoreReturn(plan) {
342
+ export function prepareRetainedStoreReturn(plan, deferContent = false) {
327
343
  const moves = [];
344
+ if (plan.transfer) {
345
+ for (const slot of plan.slots) {
346
+ const stable = path.join(plan.directory, slot.id), legacy = path.join(plan.source, slot.path), a = retainedStoreEntry(stable), b = retainedStoreEntry(legacy);
347
+ if (a) {
348
+ assertRetainedStorePath(stable);
349
+ moves.push({ id: slot.id, relative: slot.path, kind: slot.kind, device: a.dev, inode: a.ino, ...(!deferContent ? { content: inspectRetainedCopy(stable, slot.kind, copyLimits()) } : {}) });
350
+ }
351
+ else if (b) {
352
+ const original = plan.moves.find(m => m.id === slot.id);
353
+ if (!original || !matches(legacy, original) || (!deferContent && retainedStoreDigest(inspectRetainedCopy(legacy, slot.kind, copyLimits())) !== retainedStoreDigest(original.content)))
354
+ throw Error("Original retained copy changed");
355
+ }
356
+ else if (slot.required)
357
+ throw Error("Current retained resource missing");
358
+ }
359
+ return { ...plan, moves, originalMoves: plan.moves };
360
+ }
328
361
  for (const slot of plan.slots) {
329
362
  const stable = path.join(plan.directory, slot.id), legacy = path.join(plan.source, slot.path);
330
363
  assertRetainedStorePath(stable);
@@ -359,6 +392,28 @@ export function openRetainedStoreLease(binding) {
359
392
  export function openRetainedStoreMaintenance(directory) {
360
393
  return maintenanceLease(directory);
361
394
  }
395
+ export async function prepareRetainedStoreMoveAsync(source, root, id, manifest, transfer) {
396
+ const plan = prepareRetainedStoreMove(source, root, id, manifest, transfer, !!transfer);
397
+ if (transfer)
398
+ for (const move of plan.moves)
399
+ move.content = await retainedStoreJob({ action: "inspect", path: path.join(source, move.relative), kind: move.kind, limits: copyLimits() });
400
+ return plan;
401
+ }
402
+ export async function prepareRetainedStoreReturnAsync(plan) {
403
+ const back = prepareRetainedStoreReturn(plan, !!plan.transfer);
404
+ if (plan.transfer)
405
+ for (const move of back.moves)
406
+ move.content = await retainedStoreJob({ action: "inspect", path: path.join(plan.directory, move.id), kind: move.kind, limits: copyLimits() });
407
+ return back;
408
+ }
409
+ export async function applyRetainedStoreMoveAsync(plan, direction, afterMove) {
410
+ if (!plan.transfer) {
411
+ applyRetainedStoreMove(plan, direction, afterMove);
412
+ return;
413
+ }
414
+ applyRetainedStoreMove(plan, direction, undefined, undefined, true);
415
+ await retainedStoreJob({ action: "apply", plan, direction, limits: copyLimits() }, afterMove);
416
+ }
362
417
  export const retainedStoreBackupSchema = z
363
418
  .object({
364
419
  schemaVersion: z.literal(1),
@@ -1 +1 @@
1
- {"version":3,"file":"retained-store.js","sourceRoot":"","sources":["../../src/runtime/retained-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\n\nimport { available, maintenanceLease, runtimeLease } from \"./retained-store-storage.mjs\";\n\nconst segment = z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/);\nconst relative = z\n .string()\n .min(1)\n .max(256)\n .refine((value) => !path.isAbsolute(value) && !value.includes(\"\\\\\") && value.split(\"/\").every((p) => /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(p)));\nexport const RETAINED_STORE_MANIFEST = \"retained-store.manifest.json\";\nexport const RETAINED_STORE_BINDING = \"retained-store-binding.json\";\nexport const RETAINED_STORE_GUARD = \"retained-store-guard.json\";\nexport const retainedStoreManifestSchema = z\n .object({\n protocol: z.literal(1),\n storageProtocol: z.literal(1).optional(),\n format: segment,\n resources: z\n .array(\n z\n .object({\n id: segment,\n path: relative,\n kind: z.enum([\"file\", \"directory\"]),\n required: z.boolean(),\n backup: z.enum([\"payload\", \"metadata\"]).optional(),\n })\n .strict(),\n )\n .min(1)\n .max(16),\n legacyVersions: z.array(segment).max(32).default([]),\n })\n .strict()\n .superRefine((m, ctx) => {\n if (new Set(m.resources.map((r) => r.id)).size !== m.resources.length) ctx.addIssue({ code: \"custom\", message: \"Duplicate resource ID\" });\n for (const r of m.resources) {\n if ([\"store.json\", \"store-resources.json\", \"store-operation.json\", \"store-lease.sqlite\", \"store-returned.json\"].includes(r.id))\n ctx.addIssue({ code: \"custom\", message: \"Reserved store metadata resource\" });\n if ([\"config.json\", \"controller-state.json\", RETAINED_STORE_BINDING, RETAINED_STORE_GUARD].includes(r.path))\n ctx.addIssue({ code: \"custom\", message: \"Reserved instance resource\" });\n if (m.resources.some((o) => o !== r && (o.path === r.path || o.path.startsWith(r.path + \"/\"))))\n ctx.addIssue({ code: \"custom\", message: \"Overlapping resources\" });\n }\n });\nexport type RetainedStoreManifest = z.infer<typeof retainedStoreManifestSchema>;\nexport type StoreOwner = { rttNode: string; version: string; instanceId: string };\nexport type StoreBinding = {\n protocol: 1;\n storeId: string;\n generation: string;\n operationId: string;\n directory: string;\n format: string;\n configurationDigest: string;\n owner: StoreOwner;\n maintenance: true;\n};\nexport type ResourceMove = { id: string; relative: string; kind: \"file\" | \"directory\"; device: number; inode: number };\nexport type StoreMovePlan = {\n storeId: string;\n generation: string;\n format: string;\n source: string;\n directory: string;\n slots: RetainedStoreManifest[\"resources\"];\n moves: ResourceMove[];\n};\nconst ownerSchema = z.object({ rttNode: segment, version: segment, instanceId: segment }).strict();\nconst bindingSchema = z\n .object({\n protocol: z.literal(1),\n storeId: z.uuid(),\n generation: z.uuid(),\n operationId: z.uuid(),\n directory: z.string().max(4096),\n format: segment,\n configurationDigest: z.string().regex(/^[a-f0-9]{64}$/),\n owner: ownerSchema,\n maintenance: z.literal(true),\n })\n .strict();\nexport function retainedStoreDigest(value: unknown): string {\n const stable = (v: any): any =>\n Array.isArray(v)\n ? v.map(stable)\n : v && typeof v === \"object\"\n ? Object.fromEntries(\n Object.keys(v)\n .sort()\n .map((k) => [k, stable(v[k])]),\n )\n : v;\n return createHash(\"sha256\")\n .update(JSON.stringify(stable(value)))\n .digest(\"hex\");\n}\nexport function retainedStoreEntry(file: string): fs.Stats | undefined {\n try {\n return fs.lstatSync(file);\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return;\n throw e;\n }\n}\nexport function assertRetainedStorePath(file: string): void {\n if (!path.isAbsolute(file) || path.normalize(file) !== file) throw Error(\"Unnormalized retained store path\");\n for (let p = file; p !== path.dirname(p); p = path.dirname(p)) {\n const s = retainedStoreEntry(p);\n if (s?.isSymbolicLink()) throw Error(\"Linked retained store path\");\n }\n}\nexport function readRetainedStoreJson(file: string): unknown {\n assertRetainedStorePath(file);\n const fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);\n try {\n const s = fs.fstatSync(fd);\n if (!s.isFile() || s.nlink !== 1 || s.size > 128 * 1024 || s.uid !== process.getuid?.()) throw Error(\"Unsafe retained store metadata\");\n return JSON.parse(fs.readFileSync(fd, \"utf8\"));\n } finally {\n fs.closeSync(fd);\n }\n}\nexport function syncRetainedDirectory(directory: string): void {\n const fd = fs.openSync(directory, \"r\");\n try {\n fs.fsyncSync(fd);\n } finally {\n fs.closeSync(fd);\n }\n}\nexport function writeRetainedStoreJson(file: string, value: unknown): void {\n assertRetainedStorePath(file);\n const temporary = file + \".\" + randomUUID() + \".tmp\";\n const text = JSON.stringify(value);\n if (Buffer.byteLength(text) > 128 * 1024) throw Error(\"Retained store metadata too large\");\n try {\n const fd = fs.openSync(temporary, \"wx\", 0o600);\n try {\n fs.writeFileSync(fd, text);\n fs.fsyncSync(fd);\n } finally {\n fs.closeSync(fd);\n }\n fs.renameSync(temporary, file);\n syncRetainedDirectory(path.dirname(file));\n } finally {\n if (retainedStoreEntry(temporary)) fs.unlinkSync(temporary);\n }\n}\nexport function readRetainedStoreManifest(packageDirectory: string): RetainedStoreManifest {\n return retainedStoreManifestSchema.parse(readRetainedStoreJson(path.join(packageDirectory, RETAINED_STORE_MANIFEST)));\n}\nexport function prepareRetainedStoreMove(source: string, root: string, storeId: string, manifest: RetainedStoreManifest): StoreMovePlan {\n z.uuid().parse(storeId);\n retainedStoreManifestSchema.parse(manifest);\n assertRetainedStorePath(source);\n assertRetainedStorePath(root);\n const directory = path.join(root, storeId);\n if (retainedStoreEntry(directory)) throw Error(\"Retained store destination exists\");\n const existingRoot = retainedStoreEntry(root);\n if (existingRoot && (!existingRoot.isDirectory() || existingRoot.uid !== process.getuid?.() || existingRoot.mode & 0o077))\n throw Error(\"Retained root must be private and owned\");\n const rootStat = existingRoot ?? fs.statSync(path.dirname(root)),\n sourceStat = fs.statSync(source);\n if (root === source || root.startsWith(source + path.sep) || source.startsWith(root + path.sep)) throw Error(\"Nested retained store roots\");\n if (rootStat.dev !== sourceStat.dev) throw Error(\"Retained store requires same filesystem; copy is not permitted\");\n const moves: ResourceMove[] = [];\n for (const resource of manifest.resources) {\n const file = path.join(source, resource.path);\n assertRetainedStorePath(file);\n const s = retainedStoreEntry(file);\n if (!s) {\n if (resource.required) throw Error(\"Required retained resource missing\");\n continue;\n }\n if (\n s.uid !== process.getuid?.() ||\n s.dev !== rootStat.dev ||\n s.isSymbolicLink() ||\n (resource.kind === \"file\" ? !s.isFile() || s.nlink !== 1 : !s.isDirectory())\n )\n throw Error(\"Unsafe retained resource\");\n moves.push({ id: resource.id, relative: resource.path, kind: resource.kind, device: s.dev, inode: s.ino });\n }\n return { storeId, generation: randomUUID(), format: manifest.format, source, directory, slots: manifest.resources, moves };\n}\nfunction matches(file: string, move: ResourceMove): boolean {\n assertRetainedStorePath(file);\n const s = retainedStoreEntry(file);\n return (\n !!s &&\n !s.isSymbolicLink() &&\n s.dev === move.device &&\n s.ino === move.inode &&\n s.uid === process.getuid?.() &&\n (move.kind === \"file\" ? s.isFile() && s.nlink === 1 : s.isDirectory())\n );\n}\n/** Caller durably records the complete plan and holds its resource reservation first.\n * Each rename is atomic; the multi-resource operation is deliberately resumable. */\nexport function applyRetainedStoreMove(plan: StoreMovePlan, direction: \"adopt\" | \"return\", afterMove?: (id: string) => void): void {\n z.object({\n storeId: z.uuid(),\n generation: z.uuid(),\n format: segment,\n source: z.string().max(4096),\n directory: z.string().max(4096),\n slots: z\n .array(\n z\n .object({\n id: segment,\n path: relative,\n kind: z.enum([\"file\", \"directory\"]),\n required: z.boolean(),\n backup: z.enum([\"payload\", \"metadata\"]).optional(),\n })\n .strict(),\n )\n .max(16),\n moves: z\n .array(\n z\n .object({\n id: segment,\n relative,\n kind: z.enum([\"file\", \"directory\"]),\n device: z.number().int().nonnegative(),\n inode: z.number().int().nonnegative(),\n })\n .strict(),\n )\n .max(16),\n })\n .strict()\n .parse(plan);\n z.enum([\"adopt\", \"return\"]).parse(direction);\n const manifest = retainedStoreManifestSchema.parse({ protocol: 1, format: plan.format, resources: plan.slots });\n if (plan.moves.some((move) => !manifest.resources.some((slot) => slot.id === move.id && slot.path === move.relative && slot.kind === move.kind)))\n throw Error(\"Retained move differs from declared resources\");\n if (\n new Set(plan.moves.map((m) => m.id)).size !== plan.moves.length ||\n plan.moves.some((m) => plan.moves.some((o) => o !== m && (m.relative === o.relative || o.relative.startsWith(m.relative + \"/\"))))\n )\n throw Error(\"Overlapping retained moves\");\n if (plan.directory === plan.source || plan.directory.startsWith(plan.source + path.sep) || plan.source.startsWith(plan.directory + path.sep))\n throw Error(\"Nested retained move\");\n assertRetainedStorePath(plan.source);\n assertRetainedStorePath(plan.directory);\n if (!retainedStoreEntry(plan.directory)) {\n fs.mkdirSync(plan.directory, { mode: 0o700 });\n syncRetainedDirectory(path.dirname(plan.directory));\n }\n const directoryStat = fs.lstatSync(plan.directory);\n if (!directoryStat.isDirectory() || directoryStat.uid !== process.getuid?.() || directoryStat.mode & 0o077)\n throw Error(\"Unsafe retained store directory\");\n for (const move of plan.moves) {\n const legacy = path.join(plan.source, move.relative),\n stable = path.join(plan.directory, move.id);\n const [from, to] = direction === \"adopt\" ? [legacy, stable] : [stable, legacy];\n if (!retainedStoreEntry(from) && matches(to, move)) continue;\n if (!matches(from, move) || retainedStoreEntry(to)) throw Error(\"Retained resource changed or destination is occupied\");\n fs.renameSync(from, to);\n syncRetainedDirectory(path.dirname(from));\n syncRetainedDirectory(path.dirname(to));\n if (!matches(to, move)) throw Error(\"Retained resource identity changed\");\n afterMove?.(move.id);\n }\n}\nexport function writeRetainedStoreBinding(instanceDirectory: string, binding: StoreBinding): void {\n bindingSchema.parse(binding);\n writeRetainedStoreJson(path.join(instanceDirectory, RETAINED_STORE_BINDING), binding);\n}\nexport function loadRetainedStoreBinding(instanceDirectory: string, operationId?: string): StoreBinding | undefined {\n const file = path.join(instanceDirectory, RETAINED_STORE_BINDING);\n if (!retainedStoreEntry(file)) return;\n const s = fs.statSync(file);\n if (s.mode & 0o077) throw Error(\"Retained store binding must be private\");\n const binding = bindingSchema.parse(readRetainedStoreJson(file));\n assertRetainedStorePath(binding.directory);\n const runtimeRoot = process.env[\"UNS_RETAINED_STORE_ROOT\"]?.trim();\n if (runtimeRoot && path.dirname(binding.directory) !== runtimeRoot) throw Error(\"Retained binding does not match the configured Runtime root\");\n const directoryStat = retainedStoreEntry(binding.directory);\n if (!directoryStat?.isDirectory() || directoryStat.uid !== process.getuid?.() || directoryStat.mode & 0o077)\n throw Error(\"Unsafe retained store directory\");\n available(path.dirname(binding.directory));\n if (\n retainedStoreEntry(path.join(binding.directory, \"store-operation.json\")) &&\n (readRetainedStoreJson(path.join(binding.directory, \"store-operation.json\")) as any).operationId !== operationId\n )\n throw Error(\"Retained store operation is incomplete\");\n const meta = bindingSchema.parse(readRetainedStoreJson(path.join(binding.directory, \"store.json\")));\n if (retainedStoreDigest(meta) !== retainedStoreDigest(binding)) throw Error(\"Retained store owner or generation changed\");\n return binding;\n}\n/** No application payload/schema inspection is performed by this helper. */\nexport function resolveRetainedStoreResources(\n instanceDirectory: string,\n manifest: RetainedStoreManifest,\n expected?: Partial<StoreOwner>,\n): { binding?: StoreBinding; resources: Record<string, string> } {\n retainedStoreManifestSchema.parse(manifest);\n if (retainedStoreEntry(path.join(instanceDirectory, RETAINED_STORE_GUARD))) throw Error(\"Retained store operation has fenced this instance\");\n const binding = loadRetainedStoreBinding(instanceDirectory);\n if (\n binding &&\n expected &&\n Object.entries(expected).some(([k, v]) =>\n k === \"version\" ? binding.owner.version.replace(/^v/, \"\") !== String(v).replace(/^v/, \"\") : (binding.owner as any)[k] !== v,\n )\n )\n throw Error(\"Retained binding does not name this runtime\");\n if (binding && binding.format !== manifest.format) throw Error(\"Unsupported retained store format\");\n if (binding) {\n if (manifest.storageProtocol !== 1) throw Error(\"Bound retained stores require the shared storage protocol\");\n const declaration = retainedStoreManifestSchema.parse(readRetainedStoreJson(path.join(binding.directory, \"store-resources.json\")));\n if (\n declaration.storageProtocol !== 1 ||\n declaration.format !== manifest.format ||\n retainedStoreDigest(declaration.resources) !== retainedStoreDigest(manifest.resources)\n )\n throw Error(\"Retained store resource declaration changed\");\n for (const resource of manifest.resources)\n if (resource.required && !retainedStoreEntry(path.join(binding.directory, resource.id))) throw Error(\"Required retained resource missing\");\n }\n return {\n binding,\n resources: Object.fromEntries(\n manifest.resources.map((r) => [r.id, binding ? path.join(binding.directory, r.id) : path.join(instanceDirectory, r.path)]),\n ),\n };\n}\n\nexport const retainedStoreSelectionSchema = z\n .object({\n requestId: z.uuid(),\n rttNode: segment,\n sourceVersion: segment,\n sourceInstanceId: segment,\n targetVersion: segment,\n targetInstanceId: segment,\n })\n .strict()\n .refine((x) => x.sourceVersion !== x.targetVersion || x.sourceInstanceId !== x.targetInstanceId, \"Source and target must differ\");\nexport const retainedStoreRequestSchema = z.discriminatedUnion(\"action\", [\n z.object({ action: z.literal(\"review\"), selection: retainedStoreSelectionSchema }).strict(),\n z.object({ action: z.literal(\"get\"), id: z.uuid() }).strict(),\n z.object({ action: z.enum([\"adopt\", \"return\"]), id: z.uuid(), reviewedChecksum: z.string().regex(/^[a-f0-9]{64}$/) }).strict(),\n]);\nexport type RetainedStoreRequest = z.infer<typeof retainedStoreRequestSchema>;\n\n/** Capture mutable control files from the current stopped owner before persisting return intent. */\nexport function prepareRetainedStoreReturn(plan: StoreMovePlan): StoreMovePlan {\n const moves: ResourceMove[] = [];\n for (const slot of plan.slots) {\n const stable = path.join(plan.directory, slot.id),\n legacy = path.join(plan.source, slot.path);\n assertRetainedStorePath(stable);\n assertRetainedStorePath(legacy);\n const a = retainedStoreEntry(stable),\n b = retainedStoreEntry(legacy);\n if (a && b) throw Error(\"Return destination is occupied\");\n if (a) {\n if (a.uid !== process.getuid?.() || a.isSymbolicLink() || (slot.kind === \"file\" ? !a.isFile() || a.nlink !== 1 : !a.isDirectory()))\n throw Error(\"Unsafe current retained resource\");\n moves.push({ id: slot.id, relative: slot.path, kind: slot.kind, device: a.dev, inode: a.ino });\n } else if (b) {\n const original = plan.moves.find((m) => m.id === slot.id);\n if (!original || !matches(legacy, original)) throw Error(\"Return source identity changed\");\n moves.push(original);\n } else if (slot.required) throw Error(\"Current retained resource missing\");\n }\n return { ...plan, moves };\n}\n\nexport function retainedStoreRoot(defaultBase: string, configured?: string): string {\n const root = configured?.trim() || path.join(defaultBase, \"retained-stores\");\n assertRetainedStorePath(root);\n return root;\n}\nexport function openRetainedStoreLease(binding: StoreBinding): { close: () => void } {\n return runtimeLease(binding);\n}\nexport function openRetainedStoreMaintenance(directory: string): () => void {\n return maintenanceLease(directory);\n}\nexport const retainedStoreBackupSchema = z\n .object({\n schemaVersion: z.literal(1),\n state: z.enum([\"included\", \"excluded\", \"empty\"]),\n rootSha256: z.string().regex(/^[a-f0-9]{64}$/),\n stores: z.number().int().min(0).max(32),\n files: z.number().int().min(0).max(100000),\n bytes: z.number().int().positive().max(68753031168),\n sha256: z.string().regex(/^[a-f0-9]{64}$/),\n })\n .strict();\n"]}
1
+ {"version":3,"file":"retained-store.js","sourceRoot":"","sources":["../../src/runtime/retained-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\n\nimport { available, maintenanceLease, runtimeLease } from \"./retained-store-storage.mjs\";\nimport { inspectRetainedCopy, applyRetainedCopy, type RetainedCopyFingerprint } from \"./retained-store-copy.mjs\";\nimport { retainedStoreJob } from \"./retained-store-job.mjs\";\nconst copyLimits = () => JSON.parse(fs.readFileSync(new URL(\"./retained-store-storage-contract.json\", import.meta.url), \"utf8\"));\n\nconst segment = z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/);\nconst relative = z\n .string()\n .min(1)\n .max(256)\n .refine((value) => !path.isAbsolute(value) && !value.includes(\"\\\\\") && value.split(\"/\").every((p) => /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(p)));\nexport const RETAINED_STORE_MANIFEST = \"retained-store.manifest.json\";\nexport const RETAINED_STORE_BINDING = \"retained-store-binding.json\";\nexport const RETAINED_STORE_GUARD = \"retained-store-guard.json\";\nexport const retainedStoreManifestSchema = z\n .object({\n protocol: z.literal(1),\n storageProtocol: z.literal(1).optional(),\n format: segment,\n resources: z\n .array(\n z\n .object({\n id: segment,\n path: relative,\n kind: z.enum([\"file\", \"directory\"]),\n required: z.boolean(),\n backup: z.enum([\"payload\", \"metadata\"]).optional(),\n })\n .strict(),\n )\n .min(1)\n .max(16),\n legacyVersions: z.array(segment).max(32).default([]),\n })\n .strict()\n .superRefine((m, ctx) => {\n if (new Set(m.resources.map((r) => r.id)).size !== m.resources.length) ctx.addIssue({ code: \"custom\", message: \"Duplicate resource ID\" });\n for (const r of m.resources) {\n if ([\"store.json\", \"store-resources.json\", \"store-operation.json\", \"store-lease.sqlite\", \"store-returned.json\"].includes(r.id))\n ctx.addIssue({ code: \"custom\", message: \"Reserved store metadata resource\" });\n if ([\"config.json\", \"controller-state.json\", RETAINED_STORE_BINDING, RETAINED_STORE_GUARD].includes(r.path))\n ctx.addIssue({ code: \"custom\", message: \"Reserved instance resource\" });\n if (m.resources.some((o) => o !== r && (o.path === r.path || o.path.startsWith(r.path + \"/\"))))\n ctx.addIssue({ code: \"custom\", message: \"Overlapping resources\" });\n }\n });\nexport type RetainedStoreManifest = z.infer<typeof retainedStoreManifestSchema>;\nexport type StoreOwner = { rttNode: string; version: string; instanceId: string };\nexport type StoreBinding = {\n protocol: 1;\n storeId: string;\n generation: string;\n operationId: string;\n directory: string;\n format: string;\n configurationDigest: string;\n owner: StoreOwner;\n maintenance: true;\n};\nexport type ResourceMove = { id: string; relative: string; kind: \"file\" | \"directory\"; device: number; inode: number; content?: RetainedCopyFingerprint };\nexport type StoreMovePlan = {\n storeId: string;\n generation: string;\n format: string;\n source: string;\n directory: string;\n slots: RetainedStoreManifest[\"resources\"];\n moves: ResourceMove[];\n transfer?: \"copy-verified\";\n originalMoves?: ResourceMove[];\n};\nconst ownerSchema = z.object({ rttNode: segment, version: segment, instanceId: segment }).strict();\nconst bindingSchema = z\n .object({\n protocol: z.literal(1),\n storeId: z.uuid(),\n generation: z.uuid(),\n operationId: z.uuid(),\n directory: z.string().max(4096),\n format: segment,\n configurationDigest: z.string().regex(/^[a-f0-9]{64}$/),\n owner: ownerSchema,\n maintenance: z.literal(true),\n })\n .strict();\nexport function retainedStoreDigest(value: unknown): string {\n const stable = (v: any): any =>\n Array.isArray(v)\n ? v.map(stable)\n : v && typeof v === \"object\"\n ? Object.fromEntries(\n Object.keys(v)\n .sort()\n .map((k) => [k, stable(v[k])]),\n )\n : v;\n return createHash(\"sha256\")\n .update(JSON.stringify(stable(value)))\n .digest(\"hex\");\n}\nexport function retainedStoreEntry(file: string): fs.Stats | undefined {\n try {\n return fs.lstatSync(file);\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return;\n throw e;\n }\n}\nexport function assertRetainedStorePath(file: string): void {\n if (!path.isAbsolute(file) || path.normalize(file) !== file) throw Error(\"Unnormalized retained store path\");\n for (let p = file; p !== path.dirname(p); p = path.dirname(p)) {\n const s = retainedStoreEntry(p);\n if (s?.isSymbolicLink()) throw Error(\"Linked retained store path\");\n }\n}\nexport function readRetainedStoreJson(file: string): unknown {\n assertRetainedStorePath(file);\n const fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);\n try {\n const s = fs.fstatSync(fd);\n if (!s.isFile() || s.nlink !== 1 || s.size > 128 * 1024 || s.uid !== process.getuid?.()) throw Error(\"Unsafe retained store metadata\");\n return JSON.parse(fs.readFileSync(fd, \"utf8\"));\n } finally {\n fs.closeSync(fd);\n }\n}\nexport function syncRetainedDirectory(directory: string): void {\n const fd = fs.openSync(directory, \"r\");\n try {\n fs.fsyncSync(fd);\n } finally {\n fs.closeSync(fd);\n }\n}\nexport function writeRetainedStoreJson(file: string, value: unknown): void {\n assertRetainedStorePath(file);\n const temporary = file + \".\" + randomUUID() + \".tmp\";\n const text = JSON.stringify(value);\n if (Buffer.byteLength(text) > 128 * 1024) throw Error(\"Retained store metadata too large\");\n try {\n const fd = fs.openSync(temporary, \"wx\", 0o600);\n try {\n fs.writeFileSync(fd, text);\n fs.fsyncSync(fd);\n } finally {\n fs.closeSync(fd);\n }\n fs.renameSync(temporary, file);\n syncRetainedDirectory(path.dirname(file));\n } finally {\n if (retainedStoreEntry(temporary)) fs.unlinkSync(temporary);\n }\n}\nexport function readRetainedStoreManifest(packageDirectory: string): RetainedStoreManifest {\n return retainedStoreManifestSchema.parse(readRetainedStoreJson(path.join(packageDirectory, RETAINED_STORE_MANIFEST)));\n}\nexport function prepareRetainedStoreMove(source: string, root: string, storeId: string, manifest: RetainedStoreManifest, transfer?: \"copy-verified\", deferContent=false): StoreMovePlan {\n z.uuid().parse(storeId);\n retainedStoreManifestSchema.parse(manifest);\n assertRetainedStorePath(source);\n assertRetainedStorePath(root);\n const directory = path.join(root, storeId);\n if (retainedStoreEntry(directory)) throw Error(\"Retained store destination exists\");\n const existingRoot = retainedStoreEntry(root);\n if (existingRoot && (!existingRoot.isDirectory() || existingRoot.uid !== process.getuid?.() || existingRoot.mode & 0o077))\n throw Error(\"Retained root must be private and owned\");\n const rootStat = existingRoot ?? fs.statSync(path.dirname(root)),\n sourceStat = fs.statSync(source);\n if (root === source || root.startsWith(source + path.sep) || source.startsWith(root + path.sep)) throw Error(\"Nested retained store roots\");\n if (transfer !== undefined && transfer !== \"copy-verified\") throw Error(\"Unsupported retained transfer\");\n if (!transfer && rootStat.dev !== sourceStat.dev) throw Error(\"Retained store requires same filesystem; review an explicit verified copy\");\n const moves: ResourceMove[] = [];\n for (const resource of manifest.resources) {\n const file = path.join(source, resource.path);\n assertRetainedStorePath(file);\n const s = retainedStoreEntry(file);\n if (!s) {\n if (resource.required) throw Error(\"Required retained resource missing\");\n continue;\n }\n if (\n s.uid !== process.getuid?.() ||\n (!transfer && s.dev !== rootStat.dev) ||\n s.isSymbolicLink() ||\n (resource.kind === \"file\" ? !s.isFile() || s.nlink !== 1 : !s.isDirectory())\n )\n throw Error(\"Unsafe retained resource\");\n moves.push({ id: resource.id, relative: resource.path, kind: resource.kind, device: s.dev, inode: s.ino,\n ...(transfer&&!deferContent ? {content:inspectRetainedCopy(file,resource.kind,copyLimits())} : {}) });\n }\n if(transfer && (moves.reduce((n,m)=>n+(m.content?.bytes??0),0)>copyLimits().maximumBytes || moves.reduce((n,m)=>n+(m.content?.entries??0),0)>copyLimits().maximumEntries))throw Error(\"Retained copy aggregate limit\");\n return { storeId, generation: randomUUID(), format: manifest.format, source, directory, slots: manifest.resources, moves, ...(transfer?{transfer}:{}) };\n}\nfunction matches(file: string, move: ResourceMove): boolean {\n assertRetainedStorePath(file);\n const s = retainedStoreEntry(file);\n return (\n !!s &&\n !s.isSymbolicLink() &&\n s.dev === move.device &&\n s.ino === move.inode &&\n s.uid === process.getuid?.() &&\n (move.kind === \"file\" ? s.isFile() && s.nlink === 1 : s.isDirectory())\n );\n}\n/** Caller durably records the complete plan and holds its resource reservation first.\n * Each rename is atomic; the multi-resource operation is deliberately resumable. */\nexport function applyRetainedStoreMove(plan: StoreMovePlan, direction: \"adopt\" | \"return\", afterMove?: (id: string) => void, onFile?: (file:string)=>void, validateOnly=false): void {\n const resourceMove = z.object({id:segment,relative,kind:z.enum([\"file\",\"directory\"]),device:z.number().int().nonnegative(),inode:z.number().int().nonnegative(),content:z.object({digest:z.string().regex(/^[a-f0-9]{64}$/),bytes:z.number().int().nonnegative().max(copyLimits().maximumBytes),entries:z.number().int().positive().max(copyLimits().maximumEntries)}).strict().optional()}).strict();\n z.object({\n storeId: z.uuid(),\n generation: z.uuid(),\n format: segment,\n source: z.string().max(4096),\n directory: z.string().max(4096),\n slots: z\n .array(\n z\n .object({\n id: segment,\n path: relative,\n kind: z.enum([\"file\", \"directory\"]),\n required: z.boolean(),\n backup: z.enum([\"payload\", \"metadata\"]).optional(),\n })\n .strict(),\n )\n .max(16),\n moves:z.array(resourceMove).max(16),\n transfer:z.literal(\"copy-verified\").optional(),\n originalMoves:z.array(resourceMove).max(16).optional(),\n })\n .strict()\n .parse(plan);\n z.enum([\"adopt\", \"return\"]).parse(direction);\n const manifest = retainedStoreManifestSchema.parse({ protocol: 1, format: plan.format, resources: plan.slots });\n if (plan.moves.some((move) => !manifest.resources.some((slot) => slot.id === move.id && slot.path === move.relative && slot.kind === move.kind)))\n throw Error(\"Retained move differs from declared resources\");\n if (\n new Set(plan.moves.map((m) => m.id)).size !== plan.moves.length ||\n plan.moves.some((m) => plan.moves.some((o) => o !== m && (m.relative === o.relative || o.relative.startsWith(m.relative + \"/\"))))\n )\n throw Error(\"Overlapping retained moves\");\n if (plan.directory === plan.source || plan.directory.startsWith(plan.source + path.sep) || plan.source.startsWith(plan.directory + path.sep))\n throw Error(\"Nested retained move\");\n assertRetainedStorePath(plan.source);\n assertRetainedStorePath(plan.directory);\n if (!retainedStoreEntry(plan.directory)) {\n fs.mkdirSync(plan.directory, { mode: 0o700 });\n syncRetainedDirectory(path.dirname(plan.directory));\n }\n const directoryStat = fs.lstatSync(plan.directory);\n if (!directoryStat.isDirectory() || directoryStat.uid !== process.getuid?.() || directoryStat.mode & 0o077)\n throw Error(\"Unsafe retained store directory\");\n if(plan.transfer){\n if(plan.moves.some(m=>!m.content) || plan.originalMoves?.some(m=>!m.content))throw Error(\"Verified copy requires reviewed content fingerprints\");\n for(const entries of [plan.moves,plan.originalMoves??[]])if(entries.reduce((n,m)=>n+(m.content?.bytes??0),0)>copyLimits().maximumBytes||entries.reduce((n,m)=>n+(m.content?.entries??0),0)>copyLimits().maximumEntries)throw Error(\"Retained copy aggregate limit\");\n if((plan.originalMoves??[]).some(m=>!manifest.resources.some(r=>r.id===m.id&&r.path===m.relative&&r.kind===m.kind)))throw Error(\"Original copy differs from declared resources\");\n if(!validateOnly)applyRetainedCopy(plan,direction,copyLimits(),afterMove,onFile); return;\n }\n if(plan.originalMoves)throw Error(\"Original copy receipt requires verified transfer\");\n for (const move of plan.moves) {\n const legacy = path.join(plan.source, move.relative),\n stable = path.join(plan.directory, move.id);\n const [from, to] = direction === \"adopt\" ? [legacy, stable] : [stable, legacy];\n if (!retainedStoreEntry(from) && matches(to, move)) continue;\n if (!matches(from, move) || retainedStoreEntry(to)) throw Error(\"Retained resource changed or destination is occupied\");\n fs.renameSync(from, to);\n syncRetainedDirectory(path.dirname(from));\n syncRetainedDirectory(path.dirname(to));\n if (!matches(to, move)) throw Error(\"Retained resource identity changed\");\n afterMove?.(move.id);\n }\n}\nexport function writeRetainedStoreBinding(instanceDirectory: string, binding: StoreBinding): void {\n bindingSchema.parse(binding);\n writeRetainedStoreJson(path.join(instanceDirectory, RETAINED_STORE_BINDING), binding);\n}\nexport function loadRetainedStoreBinding(instanceDirectory: string, operationId?: string): StoreBinding | undefined {\n const file = path.join(instanceDirectory, RETAINED_STORE_BINDING);\n if (!retainedStoreEntry(file)) return;\n const s = fs.statSync(file);\n if (s.mode & 0o077) throw Error(\"Retained store binding must be private\");\n const binding = bindingSchema.parse(readRetainedStoreJson(file));\n assertRetainedStorePath(binding.directory);\n const runtimeRoot = process.env[\"UNS_RETAINED_STORE_ROOT\"]?.trim();\n if (runtimeRoot && path.dirname(binding.directory) !== runtimeRoot) throw Error(\"Retained binding does not match the configured Runtime root\");\n const directoryStat = retainedStoreEntry(binding.directory);\n if (!directoryStat?.isDirectory() || directoryStat.uid !== process.getuid?.() || directoryStat.mode & 0o077)\n throw Error(\"Unsafe retained store directory\");\n available(path.dirname(binding.directory));\n if (\n retainedStoreEntry(path.join(binding.directory, \"store-operation.json\")) &&\n (readRetainedStoreJson(path.join(binding.directory, \"store-operation.json\")) as any).operationId !== operationId\n )\n throw Error(\"Retained store operation is incomplete\");\n const meta = bindingSchema.parse(readRetainedStoreJson(path.join(binding.directory, \"store.json\")));\n if (retainedStoreDigest(meta) !== retainedStoreDigest(binding)) throw Error(\"Retained store owner or generation changed\");\n return binding;\n}\n/** No application payload/schema inspection is performed by this helper. */\nexport function resolveRetainedStoreResources(\n instanceDirectory: string,\n manifest: RetainedStoreManifest,\n expected?: Partial<StoreOwner>,\n): { binding?: StoreBinding; resources: Record<string, string> } {\n retainedStoreManifestSchema.parse(manifest);\n if (retainedStoreEntry(path.join(instanceDirectory, RETAINED_STORE_GUARD))) throw Error(\"Retained store operation has fenced this instance\");\n const binding = loadRetainedStoreBinding(instanceDirectory);\n if (\n binding &&\n expected &&\n Object.entries(expected).some(([k, v]) =>\n k === \"version\" ? binding.owner.version.replace(/^v/, \"\") !== String(v).replace(/^v/, \"\") : (binding.owner as any)[k] !== v,\n )\n )\n throw Error(\"Retained binding does not name this runtime\");\n if (binding && binding.format !== manifest.format) throw Error(\"Unsupported retained store format\");\n if (binding) {\n if (manifest.storageProtocol !== 1) throw Error(\"Bound retained stores require the shared storage protocol\");\n const declaration = retainedStoreManifestSchema.parse(readRetainedStoreJson(path.join(binding.directory, \"store-resources.json\")));\n if (\n declaration.storageProtocol !== 1 ||\n declaration.format !== manifest.format ||\n retainedStoreDigest(declaration.resources) !== retainedStoreDigest(manifest.resources)\n )\n throw Error(\"Retained store resource declaration changed\");\n for (const resource of manifest.resources)\n if (resource.required && !retainedStoreEntry(path.join(binding.directory, resource.id))) throw Error(\"Required retained resource missing\");\n }\n return {\n binding,\n resources: Object.fromEntries(\n manifest.resources.map((r) => [r.id, binding ? path.join(binding.directory, r.id) : path.join(instanceDirectory, r.path)]),\n ),\n };\n}\n\nexport const retainedStoreSelectionSchema = z\n .object({\n requestId: z.uuid(),\n rttNode: segment,\n sourceVersion: segment,\n sourceInstanceId: segment,\n targetVersion: segment,\n targetInstanceId: segment,\n transfer:z.literal(\"copy-verified\").optional(),\n })\n .strict()\n .refine((x) => x.sourceVersion !== x.targetVersion || x.sourceInstanceId !== x.targetInstanceId, \"Source and target must differ\");\nexport const retainedStoreRequestSchema = z.discriminatedUnion(\"action\", [\n z.object({ action: z.literal(\"review\"), selection: retainedStoreSelectionSchema }).strict(),\n z.object({ action: z.literal(\"get\"), id: z.uuid() }).strict(),\n z.object({ action: z.enum([\"adopt\", \"return\"]), id: z.uuid(), reviewedChecksum: z.string().regex(/^[a-f0-9]{64}$/) }).strict(),\n]);\nexport type RetainedStoreRequest = z.infer<typeof retainedStoreRequestSchema>;\n\n/** Capture mutable control files from the current stopped owner before persisting return intent. */\nexport function prepareRetainedStoreReturn(plan: StoreMovePlan,deferContent=false): StoreMovePlan {\n const moves: ResourceMove[] = [];\n if(plan.transfer){\n for(const slot of plan.slots){\n const stable=path.join(plan.directory,slot.id),legacy=path.join(plan.source,slot.path),a=retainedStoreEntry(stable),b=retainedStoreEntry(legacy);\n if(a){assertRetainedStorePath(stable);moves.push({id:slot.id,relative:slot.path,kind:slot.kind,device:a.dev,inode:a.ino,...(!deferContent?{content:inspectRetainedCopy(stable,slot.kind,copyLimits())}:{})});}\n else if(b){const original=plan.moves.find(m=>m.id===slot.id);if(!original||!matches(legacy,original)||(!deferContent&&retainedStoreDigest(inspectRetainedCopy(legacy,slot.kind,copyLimits()))!==retainedStoreDigest(original.content)))throw Error(\"Original retained copy changed\");}\n else if(slot.required)throw Error(\"Current retained resource missing\");\n }\n return{...plan,moves,originalMoves:plan.moves};\n }\n for (const slot of plan.slots) {\n const stable = path.join(plan.directory, slot.id),\n legacy = path.join(plan.source, slot.path);\n assertRetainedStorePath(stable);\n assertRetainedStorePath(legacy);\n const a = retainedStoreEntry(stable),\n b = retainedStoreEntry(legacy);\n if (a && b) throw Error(\"Return destination is occupied\");\n if (a) {\n if (a.uid !== process.getuid?.() || a.isSymbolicLink() || (slot.kind === \"file\" ? !a.isFile() || a.nlink !== 1 : !a.isDirectory()))\n throw Error(\"Unsafe current retained resource\");\n moves.push({ id: slot.id, relative: slot.path, kind: slot.kind, device: a.dev, inode: a.ino });\n } else if (b) {\n const original = plan.moves.find((m) => m.id === slot.id);\n if (!original || !matches(legacy, original)) throw Error(\"Return source identity changed\");\n moves.push(original);\n } else if (slot.required) throw Error(\"Current retained resource missing\");\n }\n return { ...plan, moves };\n}\n\nexport function retainedStoreRoot(defaultBase: string, configured?: string): string {\n const root = configured?.trim() || path.join(defaultBase, \"retained-stores\");\n assertRetainedStorePath(root);\n return root;\n}\nexport function openRetainedStoreLease(binding: StoreBinding): { close: () => void } {\n return runtimeLease(binding);\n}\nexport function openRetainedStoreMaintenance(directory: string): () => void {\n return maintenanceLease(directory);\n}\nexport async function prepareRetainedStoreMoveAsync(source:string,root:string,id:string,manifest:RetainedStoreManifest,transfer?:\"copy-verified\"):Promise<StoreMovePlan>{\n const plan=prepareRetainedStoreMove(source,root,id,manifest,transfer,!!transfer);\n if(transfer)for(const move of plan.moves)move.content=await retainedStoreJob({action:\"inspect\",path:path.join(source,move.relative),kind:move.kind,limits:copyLimits()}) as RetainedCopyFingerprint;\n return plan;\n}\nexport async function prepareRetainedStoreReturnAsync(plan:StoreMovePlan):Promise<StoreMovePlan>{\n const back=prepareRetainedStoreReturn(plan,!!plan.transfer);\n if(plan.transfer)for(const move of back.moves)move.content=await retainedStoreJob({action:\"inspect\",path:path.join(plan.directory,move.id),kind:move.kind,limits:copyLimits()}) as RetainedCopyFingerprint;\n return back;\n}\nexport async function applyRetainedStoreMoveAsync(plan:StoreMovePlan,direction:\"adopt\"|\"return\",afterMove?:(id:string)=>void):Promise<void>{\n if(!plan.transfer){applyRetainedStoreMove(plan,direction,afterMove);return;}\n applyRetainedStoreMove(plan,direction,undefined,undefined,true);\n await retainedStoreJob({action:\"apply\",plan,direction,limits:copyLimits()},afterMove);\n}\nexport const retainedStoreBackupSchema = z\n .object({\n schemaVersion: z.literal(1),\n state: z.enum([\"included\", \"excluded\", \"empty\"]),\n rootSha256: z.string().regex(/^[a-f0-9]{64}$/),\n stores: z.number().int().min(0).max(32),\n files: z.number().int().min(0).max(100000),\n bytes: z.number().int().positive().max(68753031168),\n sha256: z.string().regex(/^[a-f0-9]{64}$/),\n })\n .strict();\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uns-kit/core",
3
- "version": "3.0.45",
3
+ "version": "3.0.46",
4
4
  "description": "Core utilities and runtime building blocks for UNS-based realtime transformers.",
5
5
  "type": "module",
6
6
  "license": "MIT",