@ifc-lite/flow 0.5.0 → 0.6.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.
package/README.md CHANGED
@@ -88,3 +88,9 @@ Node libraries over the ifc-lite SDK live in `@ifc-lite/flow-nodes`.
88
88
  ## License
89
89
 
90
90
  MPL-2.0
91
+
92
+ The Node-only `@ifc-lite/flow/checkpoint-file` entry exports `FileCheckpointStore`
93
+ and `sourceDigestOf`, shared by CLI and MCP review continuations. Disk updates
94
+ use an exclusive lock, revision CAS and atomic rename; locks are never reclaimed
95
+ by age. Browser consumers continue to use the portable checkpoint entry and
96
+ their native IndexedDB store.
@@ -0,0 +1,13 @@
1
+ import { type CheckpointStore, type FlowCheckpoint, type StoredCheckpoint } from './checkpoint.js';
2
+ export declare class FileCheckpointStore implements CheckpointStore {
3
+ readonly path: string;
4
+ constructor(path: string);
5
+ read(id: string): Promise<StoredCheckpoint | null>;
6
+ /** The checkpoint in the file, whatever its id. */
7
+ load(): Promise<StoredCheckpoint>;
8
+ write(checkpoint: FlowCheckpoint, expected: number | null): Promise<boolean>;
9
+ private acquire;
10
+ }
11
+ /** What a resume must start from: the model bytes and effective tracking state the paused run left behind. */
12
+ export declare function sourceDigestOf(bytes: Uint8Array | string, trackingFingerprint?: string): string;
13
+ //# sourceMappingURL=checkpoint-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkpoint-file.d.ts","sourceRoot":"","sources":["../src/checkpoint-file.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAmB,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEpH,qBAAa,mBAAoB,YAAW,eAAe;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM;IAE3B,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAcxD,mDAAmD;IAC7C,IAAI,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAQjC,KAAK,CAAC,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;YAqBpE,OAAO;CAStB;AAED,8GAA8G;AAC9G,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,EAAE,mBAAmB,CAAC,EAAE,MAAM,GAAG,MAAM,CAI/F"}
@@ -0,0 +1,92 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * Review checkpoints on disk shared by CLI and MCP Flow hosts (#6923).
6
+ *
7
+ * The file is the same portable record the viewer stores (`FlowCheckpoint`
8
+ * from `@ifc-lite/flow`) plus a revision. Writes are compare-and-swap under
9
+ * an exclusive lock file (`<file>.lock`, created with `wx`), so two
10
+ * processes resuming the same reviewed checkpoint cannot both claim it: the
11
+ * loser re-reads `applying` and is refused. Existing locks are never
12
+ * reclaimed by age: an old lock can still belong to a live writer.
13
+ */
14
+ import { createHash } from 'node:crypto';
15
+ import { open, readFile, rename, unlink, writeFile } from 'node:fs/promises';
16
+ import { parseCheckpoint } from './checkpoint.js';
17
+ export class FileCheckpointStore {
18
+ path;
19
+ constructor(path) {
20
+ this.path = path;
21
+ }
22
+ async read(id) {
23
+ let text;
24
+ try {
25
+ text = await readFile(this.path, 'utf-8');
26
+ }
27
+ catch (error) {
28
+ if (error.code === 'ENOENT')
29
+ return null;
30
+ throw error;
31
+ }
32
+ const value = JSON.parse(text);
33
+ const checkpoint = parseCheckpoint(value.checkpoint);
34
+ if (checkpoint.id !== id || typeof value.revision !== 'number')
35
+ return null;
36
+ return { checkpoint, revision: value.revision };
37
+ }
38
+ /** The checkpoint in the file, whatever its id. */
39
+ async load() {
40
+ const value = JSON.parse(await readFile(this.path, 'utf-8'));
41
+ const checkpoint = parseCheckpoint(value.checkpoint);
42
+ const stored = await this.read(checkpoint.id);
43
+ if (!stored)
44
+ throw new Error(`${this.path} is not a review checkpoint file`);
45
+ return stored;
46
+ }
47
+ async write(checkpoint, expected) {
48
+ const lock = `${this.path}.lock`;
49
+ if (!(await this.acquire(lock)))
50
+ return false;
51
+ try {
52
+ const current = await this.load().catch((error) => {
53
+ if (error.code === 'ENOENT')
54
+ return null;
55
+ throw error;
56
+ });
57
+ if (current && current.checkpoint.id !== checkpoint.id)
58
+ return false;
59
+ if ((current?.revision ?? null) !== expected)
60
+ return false;
61
+ const temp = `${this.path}.${process.pid}.tmp`;
62
+ await writeFile(temp, `${JSON.stringify({ revision: (current?.revision ?? 0) + 1, checkpoint }, null, 2)}\n`);
63
+ await rename(temp, this.path);
64
+ return true;
65
+ }
66
+ finally {
67
+ await unlink(lock).catch((error) => {
68
+ if (error.code !== 'ENOENT')
69
+ throw error;
70
+ });
71
+ }
72
+ }
73
+ async acquire(lock) {
74
+ try {
75
+ await (await open(lock, 'wx')).close();
76
+ return true;
77
+ }
78
+ catch (error) {
79
+ if (error.code !== 'EEXIST')
80
+ throw error;
81
+ return false;
82
+ }
83
+ }
84
+ }
85
+ /** What a resume must start from: the model bytes and effective tracking state the paused run left behind. */
86
+ export function sourceDigestOf(bytes, trackingFingerprint) {
87
+ const hash = createHash('sha256').update(bytes);
88
+ if (trackingFingerprint !== undefined)
89
+ hash.update(`\0tracking:${trackingFingerprint}`);
90
+ return `sha256:${hash.digest('hex')}`;
91
+ }
92
+ //# sourceMappingURL=checkpoint-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkpoint-file.js","sourceRoot":"","sources":["../src/checkpoint-file.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,97 @@
1
+ import type { FlowDocument } from './document.js';
2
+ import type { RunResult } from './scheduler.js';
3
+ import type { FlowData } from './values.js';
4
+ export declare const CHECKPOINT_VERSION = 1;
5
+ /**
6
+ * `prepared` awaits review; `reviewed` is approved and claimable once;
7
+ * `applying` is claimed by one owner under a lease; `completed` resumed
8
+ * cleanly; `partially-committed` resumed with failures or lost its owner
9
+ * mid-resume, so downstream effects may be partial and the checkpoint can
10
+ * never be applied again; `rejected` was declined.
11
+ */
12
+ export type CheckpointState = 'prepared' | 'reviewed' | 'rejected' | 'applying' | 'partially-committed' | 'completed';
13
+ export type PortableFlowData = {
14
+ readonly kind: 'item';
15
+ readonly value: unknown;
16
+ } | {
17
+ readonly kind: 'list';
18
+ readonly items: readonly unknown[];
19
+ } | {
20
+ readonly kind: 'group';
21
+ readonly branches: readonly (readonly [string, readonly unknown[]])[];
22
+ };
23
+ /** Node id → port → value. */
24
+ export type PortableOutputs = Readonly<Record<string, Readonly<Record<string, PortableFlowData>>>>;
25
+ export interface FlowCheckpoint {
26
+ readonly version: typeof CHECKPOINT_VERSION;
27
+ readonly id: string;
28
+ readonly graphId: string;
29
+ readonly graphName: string;
30
+ /** Graph structure, params, capabilities and Player inputs; layout excluded; names and labels bind default write targets. */
31
+ readonly graphDigest: string;
32
+ /** Host-supplied digest of what the run read (model content hashes, input files). */
33
+ readonly sourceDigest: string;
34
+ readonly reviewNodes: readonly string[];
35
+ /** Digest of the proposal and all restored outputs: an approval binds this complete snapshot. */
36
+ readonly proposalDigest: string;
37
+ readonly outputs: PortableOutputs;
38
+ /** Host budget state (e.g. an `@ifc-lite/ai` root budget) a resume continues from. */
39
+ readonly budget?: unknown;
40
+ readonly state: CheckpointState;
41
+ readonly createdAt: number;
42
+ readonly updatedAt: number;
43
+ readonly review?: {
44
+ readonly decision: 'approved' | 'rejected';
45
+ readonly proposalDigest: string;
46
+ readonly at: number;
47
+ };
48
+ readonly claim?: {
49
+ readonly owner: string;
50
+ readonly leaseUntil: number;
51
+ readonly at: number;
52
+ };
53
+ readonly outcome?: {
54
+ readonly ok: boolean;
55
+ readonly at: number;
56
+ readonly message?: string;
57
+ };
58
+ }
59
+ export declare class CheckpointNotPortableError extends Error {
60
+ readonly paths: readonly string[];
61
+ constructor(paths: readonly string[]);
62
+ }
63
+ interface ReviewRegistry {
64
+ get(type: string): {
65
+ readonly review?: 'required';
66
+ } | undefined;
67
+ }
68
+ /** What a resume must match: the graph minus layout, plus the Player inputs it runs with. */
69
+ export declare function graphDigest(doc: FlowDocument, inputs?: Readonly<Record<string, unknown>>, registry?: ReviewRegistry): string;
70
+ export declare function nonPortable(value: unknown, path: string, out: string[]): void;
71
+ /** Every saved port is a portable container, including outputs outside the reviewed proposal. */
72
+ export declare function validPortableOutputs(outputs: Readonly<Record<string, Readonly<Record<string, unknown>>>>): boolean;
73
+ export declare function fromPortable(data: PortableFlowData): FlowData;
74
+ export declare function proposalDigestOf(outputs: PortableOutputs, reviewNodes: readonly string[], budget?: unknown): string;
75
+ export interface CreateCheckpointInput {
76
+ readonly doc: FlowDocument;
77
+ readonly registry: ReviewRegistry;
78
+ /** A run that paused for review (`result.review` non-empty) without failures. */
79
+ readonly result: RunResult;
80
+ readonly sourceDigest: string;
81
+ readonly inputs?: Readonly<Record<string, unknown>>;
82
+ readonly budget?: unknown;
83
+ readonly now?: number;
84
+ }
85
+ export declare function createCheckpoint(input: CreateCheckpointInput): FlowCheckpoint;
86
+ /** Internal: bind checkpoint creation to the graph and Player inputs used at run entry. */
87
+ export declare function registerPausedRun(result: RunResult, graphDigestAtEntry: string): void;
88
+ /** Internal: only a successful CAS claim yields a process-local ownership receipt. */
89
+ export declare function registerOwnedClaim(checkpoint: FlowCheckpoint): void;
90
+ /** Scheduler-only boundary: raw, changed, expired or reused maps cannot bypass review. */
91
+ export declare function consumeReviewedResume(outputs: ReadonlyMap<string, ReadonlyMap<string, FlowData>>, doc: FlowDocument, inputs: Readonly<Record<string, unknown>>, registry: ReviewRegistry): Map<string, Map<string, FlowData>>;
92
+ /** The `RunOptions.resume` map, only for a reviewed checkpoint with a live claim. */
93
+ export declare function resumeOutputs(checkpoint: FlowCheckpoint, now?: number): Map<string, Map<string, FlowData>>;
94
+ /** The pending proposal's values, by review node and port, for a review UI or CLI summary. */
95
+ export declare function checkpointProposal(checkpoint: FlowCheckpoint): Map<string, Map<string, FlowData>>;
96
+ export {};
97
+ //# sourceMappingURL=checkpoint-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkpoint-record.d.ts","sourceRoot":"","sources":["../src/checkpoint-record.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,255 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * Review checkpoints (#6923): the durable, portable record of a run that
6
+ * paused at a node declaring `review: 'required'`.
7
+ *
8
+ * A checkpoint holds what a later resume needs and nothing host-specific:
9
+ * the outputs of every node that completed before the pause (plain JSON, so a
10
+ * viewer checkpoint can be resumed by a headless host and the other way
11
+ * round), the digest of the graph and Player inputs it ran with, a
12
+ * host-supplied digest of the sources it read, the digest of the proposal a
13
+ * reviewer must approve, and an opaque budget state so a resume keeps
14
+ * spending from the same root budget. A value that is not plain JSON (a
15
+ * viewer-only handle, a Map, a function) makes the run uncheckpointable,
16
+ * named by node and port, rather than silently dropped.
17
+ *
18
+ * State transitions live in `checkpoint-state.ts`.
19
+ */
20
+ import { digest } from './digest.js';
21
+ export const CHECKPOINT_VERSION = 1;
22
+ export class CheckpointNotPortableError extends Error {
23
+ paths;
24
+ constructor(paths) {
25
+ super(`the run cannot be checkpointed: ${paths.slice(0, 5).join(', ')} ${paths.length === 1 ? 'is' : 'are'} not plain JSON values`);
26
+ this.paths = paths;
27
+ this.name = 'CheckpointNotPortableError';
28
+ }
29
+ }
30
+ /** What a resume must match: the graph minus layout, plus the Player inputs it runs with. */
31
+ export function graphDigest(doc, inputs = {}, registry) {
32
+ return digest({
33
+ id: doc.id,
34
+ name: doc.name,
35
+ capabilities: doc.capabilities,
36
+ edges: doc.edges,
37
+ inputs: doc.inputs,
38
+ outputs: doc.outputs,
39
+ maxCross: doc.maxCross,
40
+ nodes: doc.nodes.map(({ id, type, label, params, lacing, tracking, trackingKey }) => ({ id, type, label, params, lacing, tracking, trackingKey })),
41
+ player: inputs,
42
+ reviewPolicy: registry ? doc.nodes.map(node => [node.id, registry.get(node.type)?.review ?? null]) : null,
43
+ });
44
+ }
45
+ export function nonPortable(value, path, out) {
46
+ const pending = [[value, path, 0]];
47
+ const active = new Set();
48
+ let work = 0;
49
+ while (pending.length > 0 && out.length < 20) {
50
+ const [v, p, depth, exiting] = pending.pop();
51
+ if (exiting) {
52
+ active.delete(v);
53
+ continue;
54
+ }
55
+ if (++work > 100_000 || depth > 256) {
56
+ out.push(`${p} (JSON traversal limit)`);
57
+ break;
58
+ }
59
+ if (v !== null && typeof v === 'object') {
60
+ if (active.has(v)) {
61
+ out.push(`${p} (cycle)`);
62
+ continue;
63
+ }
64
+ active.add(v);
65
+ pending.push([v, p, depth, true]);
66
+ }
67
+ if (v === null || typeof v === 'string' || typeof v === 'boolean')
68
+ continue;
69
+ if (typeof v === 'number') {
70
+ if (!Number.isFinite(v))
71
+ out.push(p);
72
+ continue;
73
+ }
74
+ if (Array.isArray(v)) {
75
+ v.forEach((child, i) => pending.push([child, `${p}[${i}]`, depth + 1]));
76
+ continue;
77
+ }
78
+ // Plain objects only, from any realm: a class instance, Map, Date or function is not data.
79
+ const proto = typeof v === 'object' ? Object.getPrototypeOf(v) : undefined;
80
+ const plain = Object.prototype.toString.call(v) === '[object Object]' && (proto === null || (typeof proto === 'object' && Object.getPrototypeOf(proto) === null));
81
+ if (!plain) {
82
+ out.push(p);
83
+ continue;
84
+ }
85
+ // An undefined property is absent in JSON, which is what it means here too.
86
+ for (const [key, child] of Object.entries(v))
87
+ if (child !== undefined)
88
+ pending.push([child, `${p}.${key}`, depth + 1]);
89
+ }
90
+ }
91
+ function toPortable(data, path, problems) {
92
+ if (data.kind === 'item') {
93
+ nonPortable(data.value, path, problems);
94
+ return { kind: 'item', value: data.value };
95
+ }
96
+ if (data.kind === 'list') {
97
+ nonPortable(data.items, path, problems);
98
+ return { kind: 'list', items: data.items };
99
+ }
100
+ const branches = [...data.branches.entries()];
101
+ nonPortable(branches, path, problems);
102
+ return { kind: 'group', branches };
103
+ }
104
+ /** Every saved port is a portable container, including outputs outside the reviewed proposal. */
105
+ export function validPortableOutputs(outputs) {
106
+ const problems = [];
107
+ for (const [node, ports] of Object.entries(outputs))
108
+ for (const [port, value] of Object.entries(ports)) {
109
+ if (!value || typeof value !== 'object' || Array.isArray(value))
110
+ return false;
111
+ const data = value;
112
+ if (data.kind === 'item') {
113
+ if (!Object.hasOwn(data, 'value'))
114
+ return false;
115
+ nonPortable(data.value, `${node}.${port}`, problems);
116
+ }
117
+ else if (data.kind === 'list') {
118
+ if (!Array.isArray(data.items))
119
+ return false;
120
+ nonPortable(data.items, `${node}.${port}`, problems);
121
+ }
122
+ else if (data.kind === 'group') {
123
+ if (!Array.isArray(data.branches) || !data.branches.every(branch => Array.isArray(branch) && branch.length === 2 && typeof branch[0] === 'string' && Array.isArray(branch[1])))
124
+ return false;
125
+ if (new Set(data.branches.map(branch => branch[0])).size !== data.branches.length)
126
+ return false;
127
+ nonPortable(data.branches, `${node}.${port}`, problems);
128
+ }
129
+ else
130
+ return false;
131
+ if (problems.length)
132
+ return false;
133
+ }
134
+ return true;
135
+ }
136
+ export function fromPortable(data) {
137
+ if (data.kind === 'item')
138
+ return { kind: 'item', value: data.value };
139
+ if (data.kind === 'list')
140
+ return { kind: 'list', items: data.items };
141
+ return { kind: 'group', branches: new Map(data.branches) };
142
+ }
143
+ function portableOutputs(outputs) {
144
+ const problems = [];
145
+ const out = Object.create(null);
146
+ for (const [nodeId, ports] of outputs) {
147
+ out[nodeId] = Object.create(null);
148
+ for (const [port, data] of ports)
149
+ out[nodeId][port] = toPortable(data, `${nodeId}.${port}`, problems);
150
+ }
151
+ if (problems.length > 0)
152
+ throw new CheckpointNotPortableError(problems);
153
+ return JSON.parse(JSON.stringify(out));
154
+ }
155
+ export function proposalDigestOf(outputs, reviewNodes, budget) {
156
+ return digest({ reviewNodes, outputs, ...(budget !== undefined ? { budget } : {}) });
157
+ }
158
+ export function createCheckpoint(input) {
159
+ const { doc, result } = input;
160
+ if (result.review.length === 0)
161
+ throw new Error('the run did not pause for review');
162
+ if (!result.ok)
163
+ throw new Error('a run with failed nodes cannot be resumed; fix the graph and run it again');
164
+ const problems = [];
165
+ if (input.budget !== undefined)
166
+ nonPortable(input.budget, 'budget', problems);
167
+ if (problems.length)
168
+ throw new CheckpointNotPortableError(problems);
169
+ const outputs = portableOutputs(result.outputs);
170
+ const graph = graphDigest(doc, input.inputs, input.registry);
171
+ if (pausedRunGraphs.get(result) !== graph) {
172
+ throw new Error('the checkpoint graph and Player inputs must match the actual paused run');
173
+ }
174
+ const proposal = proposalDigestOf(outputs, result.review, input.budget);
175
+ const now = input.now ?? Date.now();
176
+ if (!Number.isFinite(now))
177
+ throw new Error('the checkpoint timestamp must be finite');
178
+ return {
179
+ version: CHECKPOINT_VERSION,
180
+ id: globalThis.crypto.randomUUID(),
181
+ graphId: doc.id,
182
+ graphName: doc.name,
183
+ graphDigest: graph,
184
+ sourceDigest: input.sourceDigest,
185
+ reviewNodes: [...result.review],
186
+ proposalDigest: proposal,
187
+ outputs,
188
+ ...(input.budget !== undefined ? { budget: JSON.parse(JSON.stringify(input.budget)) } : {}),
189
+ state: 'prepared',
190
+ createdAt: now,
191
+ updatedAt: now,
192
+ };
193
+ }
194
+ /** Decode a detached snapshot for inspection or an owned resume. */
195
+ function restoreMap(checkpoint) {
196
+ if (!validPortableOutputs(checkpoint.outputs)
197
+ || proposalDigestOf(checkpoint.outputs, checkpoint.reviewNodes, checkpoint.budget) !== checkpoint.proposalDigest) {
198
+ throw new Error('the checkpoint outputs no longer match their reviewed snapshot');
199
+ }
200
+ const outputs = JSON.parse(JSON.stringify(checkpoint.outputs));
201
+ const out = new Map();
202
+ for (const [nodeId, ports] of Object.entries(outputs)) {
203
+ out.set(nodeId, new Map(Object.entries(ports).map(([port, data]) => [port, fromPortable(data)])));
204
+ }
205
+ return out;
206
+ }
207
+ const pausedRunGraphs = new WeakMap();
208
+ /** Internal: bind checkpoint creation to the graph and Player inputs used at run entry. */
209
+ export function registerPausedRun(result, graphDigestAtEntry) {
210
+ pausedRunGraphs.set(result, graphDigestAtEntry);
211
+ }
212
+ const authorizedResumes = new WeakMap();
213
+ const ownedClaims = new WeakMap();
214
+ /** Internal: only a successful CAS claim yields a process-local ownership receipt. */
215
+ export function registerOwnedClaim(checkpoint) {
216
+ ownedClaims.set(checkpoint, digest({ id: checkpoint.id, graph: checkpoint.graphDigest,
217
+ source: checkpoint.sourceDigest, proposal: checkpoint.proposalDigest, claim: checkpoint.claim }));
218
+ }
219
+ /** Scheduler-only boundary: raw, changed, expired or reused maps cannot bypass review. */
220
+ export function consumeReviewedResume(outputs, doc, inputs, registry) {
221
+ const authorization = authorizedResumes.get(outputs);
222
+ if (!authorization || authorization.expires <= Date.now()
223
+ || authorization.graph !== graphDigest(doc, inputs, registry)
224
+ || authorization.outputs !== digest(portableOutputs(outputs))) {
225
+ throw new Error('resume requires unchanged outputs from an actively claimed, approved checkpoint');
226
+ }
227
+ authorizedResumes.delete(outputs);
228
+ // Own a detached snapshot before any node can await or mutate caller-owned data.
229
+ const snapshot = JSON.parse(JSON.stringify(portableOutputs(outputs)));
230
+ return new Map(Object.entries(snapshot).map(([node, ports]) => [node, new Map(Object.entries(ports).map(([port, data]) => [port, fromPortable(data)]))]));
231
+ }
232
+ /** The `RunOptions.resume` map, only for a reviewed checkpoint with a live claim. */
233
+ export function resumeOutputs(checkpoint, now = Date.now()) {
234
+ if (checkpoint.state !== 'applying' || checkpoint.review?.decision !== 'approved'
235
+ || checkpoint.review.proposalDigest !== checkpoint.proposalDigest || !checkpoint.claim?.owner
236
+ || !Number.isFinite(now) || !Number.isFinite(checkpoint.claim.leaseUntil) || checkpoint.claim.leaseUntil <= Math.max(now, Date.now())) {
237
+ throw new Error('only an actively claimed, approved checkpoint can supply resume outputs');
238
+ }
239
+ const outputs = restoreMap(checkpoint);
240
+ const ownership = digest({ id: checkpoint.id, graph: checkpoint.graphDigest,
241
+ source: checkpoint.sourceDigest, proposal: checkpoint.proposalDigest, claim: checkpoint.claim });
242
+ if (ownedClaims.get(checkpoint) !== ownership) {
243
+ throw new Error('resume requires the original successful store claim; a persisted or already supplied claim cannot resume');
244
+ }
245
+ ownedClaims.delete(checkpoint);
246
+ authorizedResumes.set(outputs, { graph: checkpoint.graphDigest, outputs: digest(portableOutputs(outputs)),
247
+ expires: checkpoint.claim.leaseUntil });
248
+ return outputs;
249
+ }
250
+ /** The pending proposal's values, by review node and port, for a review UI or CLI summary. */
251
+ export function checkpointProposal(checkpoint) {
252
+ const all = restoreMap(checkpoint);
253
+ return new Map(checkpoint.reviewNodes.flatMap((id) => (all.has(id) ? [[id, all.get(id)]] : [])));
254
+ }
255
+ //# sourceMappingURL=checkpoint-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkpoint-record.js","sourceRoot":"","sources":["../src/checkpoint-record.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import { type FlowCheckpoint } from './checkpoint-record.js';
2
+ export type CheckpointErrorCode = 'invalid' | 'not-prepared' | 'not-reviewed' | 'digest-mismatch' | 'graph-changed' | 'sources-changed' | 'not-owner' | 'conflict';
3
+ export declare class CheckpointError extends Error {
4
+ readonly code: CheckpointErrorCode;
5
+ constructor(code: CheckpointErrorCode, message: string);
6
+ }
7
+ /**
8
+ * Validate an untrusted checkpoint (a file handed to a headless host, a
9
+ * stored row). The proposal digest is recomputed from the stored outputs, so
10
+ * a bundle whose values were edited after review no longer matches its
11
+ * approval and cannot be claimed.
12
+ */
13
+ export declare function parseCheckpoint(value: unknown): FlowCheckpoint;
14
+ /** Approve exactly the proposal the reviewer saw, named by its digest. */
15
+ export declare function approveCheckpoint(checkpoint: FlowCheckpoint, proposalDigest: string, now?: number): FlowCheckpoint;
16
+ export declare function rejectCheckpoint(checkpoint: FlowCheckpoint, now?: number): FlowCheckpoint;
17
+ export interface ClaimInput {
18
+ readonly owner: string;
19
+ /** The graph and Player inputs the resume will run with (`graphDigest`). */
20
+ readonly graphDigest: string;
21
+ /** What the resume will read, digested the same way as at checkpoint time. */
22
+ readonly sourceDigest: string;
23
+ readonly leaseMs: number;
24
+ readonly now?: number;
25
+ }
26
+ /** Take single ownership of a reviewed checkpoint for one resume. */
27
+ export declare function claimCheckpoint(checkpoint: FlowCheckpoint, input: ClaimInput): FlowCheckpoint;
28
+ /** Record how the owner's resume ended. A failed resume may have committed some effects. */
29
+ export declare function finishCheckpoint(checkpoint: FlowCheckpoint, owner: string, outcome: {
30
+ ok: boolean;
31
+ message?: string;
32
+ }, now?: number): FlowCheckpoint;
33
+ /** A claim whose lease ran out without a finish: its effects are unknown, so it can never be applied again. */
34
+ export declare function recoverCheckpoint(checkpoint: FlowCheckpoint, now?: number): FlowCheckpoint | null;
35
+ export interface StoredCheckpoint {
36
+ readonly checkpoint: FlowCheckpoint;
37
+ readonly revision: number;
38
+ }
39
+ /** Durable checkpoint storage with compare-and-swap writes. */
40
+ export interface CheckpointStore {
41
+ read(id: string): Promise<StoredCheckpoint | null>;
42
+ /** Write when the stored revision still equals `expected` (`null`: must not exist yet); false on conflict. */
43
+ write(checkpoint: FlowCheckpoint, expected: number | null): Promise<boolean>;
44
+ }
45
+ /** Apply one transition through the store's CAS, re-applying it to the fresh record on conflict. */
46
+ export declare function updateCheckpoint(store: CheckpointStore, id: string, change: (current: FlowCheckpoint) => FlowCheckpoint): Promise<FlowCheckpoint>;
47
+ /** An in-process store, for tests and single-process hosts. */
48
+ export declare class MemoryCheckpointStore implements CheckpointStore {
49
+ private readonly rows;
50
+ read(id: string): Promise<StoredCheckpoint | null>;
51
+ write(checkpoint: FlowCheckpoint, expected: number | null): Promise<boolean>;
52
+ }
53
+ //# sourceMappingURL=checkpoint-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkpoint-state.d.ts","sourceRoot":"","sources":["../src/checkpoint-state.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAqH,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAEhL,MAAM,MAAM,mBAAmB,GAC3B,SAAS,GACT,cAAc,GACd,cAAc,GACd,iBAAiB,GACjB,eAAe,GACf,iBAAiB,GACjB,WAAW,GACX,UAAU,CAAC;AAEf,qBAAa,eAAgB,SAAQ,KAAK;IAC5B,QAAQ,CAAC,IAAI,EAAE,mBAAmB;gBAAzB,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM;CAIhE;AAQD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAyB9D;AAUD,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,cAAc,CAOtH;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,cAAc,EAAE,GAAG,SAAa,GAAG,cAAc,CAI7F;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAID,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,UAAU,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,GAAG,cAAc,CAqB7F;AAED,4FAA4F;AAC5F,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,SAAa,GAAG,cAAc,CAUxJ;AAED,+GAA+G;AAC/G,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,cAAc,EAAE,GAAG,SAAa,GAAG,cAAc,GAAG,IAAI,CASrG;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,+DAA+D;AAC/D,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACnD,8GAA8G;IAC9G,KAAK,CAAC,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9E;AAID,oGAAoG;AACpG,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAgBvJ;AAED,+DAA+D;AAC/D,qBAAa,qBAAsB,YAAW,eAAe;IAC3D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAuC;IAEtD,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAKlD,KAAK,CAAC,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;CAMnF"}