@weiliang0121/capix-checkpoint 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +19 -2
- package/dist/contract.d.ts +257 -0
- package/dist/contract.js +1 -0
- package/dist/encoding.d.ts +9 -0
- package/dist/encoding.js +2 -0
- package/dist/evidence.d.ts +3 -0
- package/dist/evidence.js +2 -0
- package/dist/incremental.d.ts +58 -0
- package/dist/incremental.js +2 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +2 -0
- package/dist/receipt.d.ts +5 -0
- package/dist/receipt.js +2 -0
- package/dist/relation-cache.d.ts +16 -0
- package/dist/relation-cache.js +2 -0
- package/dist/selections.d.ts +43 -0
- package/dist/selections.js +2 -0
- package/dist/storage-record.d.ts +5 -0
- package/dist/storage-record.js +2 -0
- package/dist/storage.d.ts +8 -0
- package/dist/storage.js +2 -0
- package/dist/store.d.ts +8 -0
- package/dist/store.js +2 -0
- package/dist/value.d.ts +11 -0
- package/dist/value.js +2 -0
- package/package.json +45 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 wei.liang (https://github.com/weiliang0121)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @weiliang0121/capix-checkpoint
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Stable checkpoint facts, incremental storage, and recovery validation for CAPiX.
|
|
4
|
+
|
|
5
|
+
ES modules and TypeScript declarations. Requires Node.js 22.23.2 or newer.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @weiliang0121/capix-checkpoint
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Public entry points
|
|
12
|
+
|
|
13
|
+
- `@weiliang0121/capix-checkpoint`
|
|
14
|
+
- `@weiliang0121/capix-checkpoint/storage`
|
|
15
|
+
|
|
16
|
+
This package is part of CAPiX. The npm distribution contains compiled JavaScript, type declarations, and this package's MIT license. Reference services and client applications are not included in this package or the initial npm release.
|
|
17
|
+
|
|
18
|
+
## License
|
|
19
|
+
|
|
20
|
+
MIT. Copyright (c) 2026 wei.liang. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import type { InvocationIdentity, InvocationFailureFact, CheckpointValue, CheckpointContract } from '@weiliang0121/capix-contracts';
|
|
2
|
+
export interface CheckpointReference {
|
|
3
|
+
readonly contextId: string;
|
|
4
|
+
readonly parentContextId: string;
|
|
5
|
+
readonly parentRound: number;
|
|
6
|
+
readonly order: number;
|
|
7
|
+
readonly target: {
|
|
8
|
+
readonly position: number;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export type CheckpointReferences = Readonly<Record<string, CheckpointReference | readonly CheckpointReference[]>>;
|
|
12
|
+
export interface CheckpointContinuation {
|
|
13
|
+
readonly fromRound: 1;
|
|
14
|
+
readonly stage: 'accept' | 'handling';
|
|
15
|
+
readonly reason: string;
|
|
16
|
+
readonly origin?: {
|
|
17
|
+
readonly kind: 'self';
|
|
18
|
+
readonly phase: 'execute' | 'accept';
|
|
19
|
+
} | {
|
|
20
|
+
readonly kind: 'child-return' | 'child-reception';
|
|
21
|
+
readonly child: CheckpointReference;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export interface CheckpointReceptionContract {
|
|
25
|
+
readonly position: number;
|
|
26
|
+
}
|
|
27
|
+
export type CheckpointChildReception = {
|
|
28
|
+
readonly kind: 'pending';
|
|
29
|
+
} | {
|
|
30
|
+
readonly kind: 'receiving';
|
|
31
|
+
readonly contract?: CheckpointReceptionContract;
|
|
32
|
+
} | {
|
|
33
|
+
readonly kind: 'accepted';
|
|
34
|
+
readonly contract?: CheckpointReceptionContract;
|
|
35
|
+
readonly output?: CheckpointValue;
|
|
36
|
+
} | {
|
|
37
|
+
readonly kind: 'failed';
|
|
38
|
+
readonly contract?: CheckpointReceptionContract;
|
|
39
|
+
readonly error: CheckpointValue;
|
|
40
|
+
readonly failure: InvocationFailureFact & {
|
|
41
|
+
readonly kind: 'exception';
|
|
42
|
+
readonly contract: string;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
export interface CheckpointHandledReception {
|
|
46
|
+
readonly kind: 'handled';
|
|
47
|
+
readonly contract?: CheckpointReceptionContract;
|
|
48
|
+
readonly output?: CheckpointValue;
|
|
49
|
+
}
|
|
50
|
+
export interface CheckpointChild {
|
|
51
|
+
readonly identity: InvocationIdentity;
|
|
52
|
+
readonly target: {
|
|
53
|
+
readonly position: number;
|
|
54
|
+
};
|
|
55
|
+
readonly contract?: CheckpointContract;
|
|
56
|
+
readonly round: number;
|
|
57
|
+
readonly order: number;
|
|
58
|
+
readonly key?: string;
|
|
59
|
+
readonly input: CheckpointValue;
|
|
60
|
+
readonly state: {
|
|
61
|
+
readonly kind: 'waiting';
|
|
62
|
+
} | {
|
|
63
|
+
readonly kind: 'returned';
|
|
64
|
+
readonly output: CheckpointValue;
|
|
65
|
+
readonly progress: {
|
|
66
|
+
readonly round: number;
|
|
67
|
+
readonly currentInput: CheckpointValue;
|
|
68
|
+
readonly phase: 'execute' | 'receive' | 'handling';
|
|
69
|
+
};
|
|
70
|
+
readonly reception: CheckpointChildReception;
|
|
71
|
+
} | {
|
|
72
|
+
readonly kind: 'failed';
|
|
73
|
+
readonly error: CheckpointValue;
|
|
74
|
+
readonly failure: InvocationFailureFact;
|
|
75
|
+
readonly progress: {
|
|
76
|
+
readonly round: number;
|
|
77
|
+
readonly currentInput: CheckpointValue;
|
|
78
|
+
readonly phase: 'execute' | 'receive' | 'handling';
|
|
79
|
+
};
|
|
80
|
+
readonly reception?: CheckpointHandledReception;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export interface InvocationCheckpointFrame {
|
|
84
|
+
readonly owner: InvocationIdentity;
|
|
85
|
+
readonly round: number;
|
|
86
|
+
readonly phase: 'execute';
|
|
87
|
+
readonly input: CheckpointValue;
|
|
88
|
+
readonly currentInput: CheckpointValue;
|
|
89
|
+
readonly nextChildOrder: number;
|
|
90
|
+
readonly children: readonly CheckpointChild[];
|
|
91
|
+
readonly continuation?: CheckpointContinuation;
|
|
92
|
+
}
|
|
93
|
+
export interface CheckpointImage {
|
|
94
|
+
readonly id: string;
|
|
95
|
+
readonly formatVersion: 6;
|
|
96
|
+
readonly contract: CheckpointContract;
|
|
97
|
+
readonly point: string;
|
|
98
|
+
readonly frame: InvocationCheckpointFrame;
|
|
99
|
+
readonly state: CheckpointValue;
|
|
100
|
+
readonly references: CheckpointReferences;
|
|
101
|
+
}
|
|
102
|
+
export type CheckpointDelivery = {
|
|
103
|
+
readonly status: 'succeeded';
|
|
104
|
+
readonly output: CheckpointValue;
|
|
105
|
+
readonly progress: {
|
|
106
|
+
readonly round: number;
|
|
107
|
+
readonly currentInput: CheckpointValue;
|
|
108
|
+
readonly phase: 'execute' | 'receive' | 'handling';
|
|
109
|
+
};
|
|
110
|
+
} | {
|
|
111
|
+
readonly status: 'failed' | 'cancelled';
|
|
112
|
+
};
|
|
113
|
+
export interface CheckpointHead {
|
|
114
|
+
readonly revision: number;
|
|
115
|
+
readonly image: CheckpointImage;
|
|
116
|
+
readonly delivery?: CheckpointDelivery;
|
|
117
|
+
readonly publication?: CheckpointPublication;
|
|
118
|
+
}
|
|
119
|
+
export interface CheckpointSaveReceipt {
|
|
120
|
+
readonly kind: 'saved';
|
|
121
|
+
readonly contextId: string;
|
|
122
|
+
readonly checkpointId: string;
|
|
123
|
+
readonly revision: number;
|
|
124
|
+
readonly digest: string;
|
|
125
|
+
}
|
|
126
|
+
export interface CheckpointFinishReceipt {
|
|
127
|
+
readonly kind: 'finished';
|
|
128
|
+
readonly contextId: string;
|
|
129
|
+
readonly checkpointId: string;
|
|
130
|
+
readonly revision: number;
|
|
131
|
+
readonly status: CheckpointDelivery['status'];
|
|
132
|
+
readonly digest: string;
|
|
133
|
+
}
|
|
134
|
+
export interface CheckpointStore {
|
|
135
|
+
read(contextId: string): CheckpointHead | undefined;
|
|
136
|
+
save(image: CheckpointImage | CheckpointCommit, expectedRevision: number): CheckpointSaveReceipt;
|
|
137
|
+
finish(contextId: string, expectedRevision: number, delivery: CheckpointDelivery): CheckpointFinishReceipt;
|
|
138
|
+
}
|
|
139
|
+
export interface CheckpointValueReference {
|
|
140
|
+
readonly id: string;
|
|
141
|
+
readonly digest: string;
|
|
142
|
+
}
|
|
143
|
+
export interface CheckpointValueBlock extends CheckpointValueReference {
|
|
144
|
+
readonly value: CheckpointValue;
|
|
145
|
+
}
|
|
146
|
+
type ReferencedProgress = {
|
|
147
|
+
readonly round: number;
|
|
148
|
+
readonly currentInput: CheckpointValueReference;
|
|
149
|
+
readonly phase: 'execute' | 'receive' | 'handling';
|
|
150
|
+
};
|
|
151
|
+
type ReferencedReception = {
|
|
152
|
+
readonly kind: 'pending';
|
|
153
|
+
} | {
|
|
154
|
+
readonly kind: 'receiving';
|
|
155
|
+
readonly contract?: CheckpointReceptionContract;
|
|
156
|
+
} | {
|
|
157
|
+
readonly kind: 'accepted';
|
|
158
|
+
readonly contract?: CheckpointReceptionContract;
|
|
159
|
+
readonly output?: CheckpointValueReference;
|
|
160
|
+
} | {
|
|
161
|
+
readonly kind: 'failed';
|
|
162
|
+
readonly contract?: CheckpointReceptionContract;
|
|
163
|
+
readonly error: CheckpointValueReference;
|
|
164
|
+
readonly failure: InvocationFailureFact & {
|
|
165
|
+
readonly kind: 'exception';
|
|
166
|
+
readonly contract: string;
|
|
167
|
+
};
|
|
168
|
+
};
|
|
169
|
+
export interface CheckpointChildRecord extends Omit<CheckpointChild, 'input' | 'state'> {
|
|
170
|
+
readonly input: CheckpointValueReference;
|
|
171
|
+
readonly state: {
|
|
172
|
+
readonly kind: 'waiting';
|
|
173
|
+
} | {
|
|
174
|
+
readonly kind: 'returned';
|
|
175
|
+
readonly output: CheckpointValueReference;
|
|
176
|
+
readonly progress: ReferencedProgress;
|
|
177
|
+
readonly reception: ReferencedReception;
|
|
178
|
+
} | {
|
|
179
|
+
readonly kind: 'failed';
|
|
180
|
+
readonly error: CheckpointValueReference;
|
|
181
|
+
readonly failure: InvocationFailureFact;
|
|
182
|
+
readonly progress: ReferencedProgress;
|
|
183
|
+
readonly reception?: {
|
|
184
|
+
readonly kind: 'handled';
|
|
185
|
+
readonly contract?: CheckpointReceptionContract;
|
|
186
|
+
readonly output?: CheckpointValueReference;
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
export interface CheckpointCommit {
|
|
191
|
+
readonly kind: 'commit';
|
|
192
|
+
readonly formatVersion: 6;
|
|
193
|
+
readonly id: string;
|
|
194
|
+
readonly contract: CheckpointContract;
|
|
195
|
+
readonly point: string;
|
|
196
|
+
readonly frame: Omit<InvocationCheckpointFrame, 'input' | 'currentInput' | 'children'> & {
|
|
197
|
+
readonly input: CheckpointValueReference;
|
|
198
|
+
readonly currentInput: CheckpointValueReference;
|
|
199
|
+
};
|
|
200
|
+
readonly state: CheckpointValueReference;
|
|
201
|
+
readonly references: CheckpointValueReference | CheckpointSelectionSlots;
|
|
202
|
+
readonly selectionChanges?: readonly CheckpointSelectionChange[];
|
|
203
|
+
readonly values: readonly CheckpointValueBlock[];
|
|
204
|
+
readonly children: readonly CheckpointChildRecord[];
|
|
205
|
+
}
|
|
206
|
+
export interface CheckpointSelectionReference {
|
|
207
|
+
readonly id: string;
|
|
208
|
+
readonly revision: number;
|
|
209
|
+
readonly target: {
|
|
210
|
+
readonly position: number;
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
export interface CheckpointSelectionSlots {
|
|
214
|
+
readonly kind: 'slots';
|
|
215
|
+
readonly slots: Readonly<Record<string, {
|
|
216
|
+
readonly kind: 'one';
|
|
217
|
+
readonly reference: CheckpointReference;
|
|
218
|
+
} | {
|
|
219
|
+
readonly kind: 'many';
|
|
220
|
+
readonly selection: CheckpointSelectionReference;
|
|
221
|
+
}>>;
|
|
222
|
+
}
|
|
223
|
+
export interface CheckpointSelectionChange {
|
|
224
|
+
readonly id: string;
|
|
225
|
+
readonly target: {
|
|
226
|
+
readonly position: number;
|
|
227
|
+
};
|
|
228
|
+
readonly expectedRevision: number;
|
|
229
|
+
readonly reset?: true;
|
|
230
|
+
readonly append?: readonly {
|
|
231
|
+
readonly id: string;
|
|
232
|
+
readonly reference: CheckpointReference;
|
|
233
|
+
}[];
|
|
234
|
+
readonly remove?: readonly {
|
|
235
|
+
readonly id: string;
|
|
236
|
+
readonly order: number;
|
|
237
|
+
readonly reference: CheckpointReference;
|
|
238
|
+
}[];
|
|
239
|
+
}
|
|
240
|
+
export interface CheckpointSelectionSnapshot extends CheckpointSelectionReference {
|
|
241
|
+
readonly owner: string;
|
|
242
|
+
readonly nextOrder: number;
|
|
243
|
+
readonly count: number;
|
|
244
|
+
readonly bytes: number;
|
|
245
|
+
readonly nodes: number;
|
|
246
|
+
readonly sum: string;
|
|
247
|
+
readonly digest: string;
|
|
248
|
+
readonly occurrences: readonly {
|
|
249
|
+
readonly id: string;
|
|
250
|
+
readonly order: number;
|
|
251
|
+
readonly reference: CheckpointReference;
|
|
252
|
+
}[];
|
|
253
|
+
}
|
|
254
|
+
export interface CheckpointPublication extends CheckpointCommit {
|
|
255
|
+
readonly selectedSelections?: readonly CheckpointSelectionSnapshot[];
|
|
256
|
+
}
|
|
257
|
+
export {};
|
package/dist/contract.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface CheckpointValueMetrics {
|
|
2
|
+
readonly bytes: number;
|
|
3
|
+
readonly nodes: number;
|
|
4
|
+
readonly depth: number;
|
|
5
|
+
}
|
|
6
|
+
export declare const checkpointEncodingOverhead: number;
|
|
7
|
+
export declare function encodeCheckpointData(value: unknown): string;
|
|
8
|
+
export declare function decodeCheckpointData(body: string): unknown;
|
|
9
|
+
export declare function checkpointMetrics(value: unknown, reference?: (value: object) => CheckpointValueMetrics | undefined): CheckpointValueMetrics;
|
package/dist/encoding.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});const format="capix.checkpoint.value@1",checkpointEncodingOverhead=Buffer.byteLength(JSON.stringify({format,value:null}))-4;function encodeCheckpointData(value){return JSON.stringify({format,value:encode(value)})}__name(encodeCheckpointData,"encodeCheckpointData");function decodeCheckpointData(body){const value=JSON.parse(body);if(!value||typeof value!="object"||Array.isArray(value)||value.format!==format||!Object.hasOwn(value,"value")||Object.keys(value).length!==2)throw new Error("Invalid checkpoint value encoding");return decode(value.value)}__name(decodeCheckpointData,"decodeCheckpointData");function checkpointMetrics(value,reference){if(value!==null&&typeof value=="object"){const linked=reference?.(value);if(linked)return linked;let bytes=2,nodes=1,depth=0;const values=Array.isArray(value)?value.map(entry=>[void 0,entry]):Object.entries(value);for(let i=0;i<values.length;i++){const[key,entry]=values[i],measured=checkpointMetrics(entry,reference);bytes+=measured.bytes+(i?1:0)+(key===void 0?0:Buffer.byteLength(JSON.stringify(key))+1),nodes+=measured.nodes,depth=Math.max(depth,measured.depth+1)}return{bytes,nodes,depth}}return{bytes:Buffer.byteLength(JSON.stringify(encode(value))),nodes:1,depth:0}}__name(checkpointMetrics,"checkpointMetrics");function encode(value){return typeof value=="number"&&Object.is(value,-0)?"~0":typeof value=="string"?value.startsWith("~")?`~${value}`:value:Array.isArray(value)?value.map(encode):value!==null&&typeof value=="object"?Object.fromEntries(Object.entries(value).map(([key,entry])=>[key,encode(entry)])):value}__name(encode,"encode");function decode(value){if(typeof value=="string"){if(value==="~0")return-0;if(value.startsWith("~~"))return value.slice(1);if(value.startsWith("~"))throw new Error("Invalid checkpoint string escape");return value}return Array.isArray(value)?value.map(decode):value!==null&&typeof value=="object"?Object.fromEntries(Object.entries(value).map(([key,entry])=>[key,decode(entry)])):value}__name(decode,"decode");export{checkpointEncodingOverhead,checkpointMetrics,decodeCheckpointData,encodeCheckpointData};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { CheckpointPublication, CheckpointHead } from './contract.js';
|
|
2
|
+
export declare function checkpointHeadCommit(head: CheckpointHead): CheckpointPublication | undefined;
|
|
3
|
+
export declare function rememberCheckpointHead(head: CheckpointHead, commit: CheckpointPublication): void;
|
package/dist/evidence.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});const publications=new WeakMap;function checkpointHeadCommit(head){return publications.get(head)}__name(checkpointHeadCommit,"checkpointHeadCommit");function rememberCheckpointHead(head,commit){publications.set(head,commit)}__name(rememberCheckpointHead,"rememberCheckpointHead");export{checkpointHeadCommit,rememberCheckpointHead};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { CheckpointCommit, CheckpointValueBlock, CheckpointChildRecord, CheckpointHead, CheckpointImage, CheckpointSaveReceipt, CheckpointDelivery, CheckpointPublication } from './contract.js';
|
|
2
|
+
import { type CheckpointValueMetrics } from './encoding.js';
|
|
3
|
+
import { type CheckpointStoredSelection, type CheckpointStoredOccurrence, type CheckpointSelectionReader, type CheckpointSelectionPlan } from './selections.js';
|
|
4
|
+
export interface CheckpointStoredValue {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly digest: string;
|
|
7
|
+
readonly metrics: CheckpointValueMetrics;
|
|
8
|
+
readonly uses: number;
|
|
9
|
+
readonly referenceChecked: boolean;
|
|
10
|
+
readonly diagnosticChecked: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface CheckpointStoredChild {
|
|
13
|
+
readonly child: CheckpointChildRecord;
|
|
14
|
+
readonly metrics: CheckpointValueMetrics;
|
|
15
|
+
}
|
|
16
|
+
export interface CheckpointStoredHead {
|
|
17
|
+
readonly commit: Omit<CheckpointCommit, 'values' | 'children' | 'selectionChanges'>;
|
|
18
|
+
readonly revision: number;
|
|
19
|
+
readonly digest: string;
|
|
20
|
+
readonly childCount: number;
|
|
21
|
+
readonly childBytes: number;
|
|
22
|
+
readonly childNodes: number;
|
|
23
|
+
readonly childDepths: readonly number[];
|
|
24
|
+
readonly delivery?: CheckpointDelivery;
|
|
25
|
+
}
|
|
26
|
+
export interface CheckpointCommitReader extends CheckpointSelectionReader {
|
|
27
|
+
readonly head: CheckpointStoredHead | undefined;
|
|
28
|
+
value(id: string): CheckpointStoredValue | undefined;
|
|
29
|
+
body(id: string): string | undefined;
|
|
30
|
+
child(contextId: string): CheckpointStoredChild | undefined;
|
|
31
|
+
order(order: number): string | undefined;
|
|
32
|
+
imageUsed(id: string): boolean;
|
|
33
|
+
}
|
|
34
|
+
export interface CheckpointCommitPlan {
|
|
35
|
+
readonly head: CheckpointStoredHead;
|
|
36
|
+
readonly values: readonly {
|
|
37
|
+
readonly stored: CheckpointStoredValue;
|
|
38
|
+
readonly body?: string;
|
|
39
|
+
}[];
|
|
40
|
+
readonly children: readonly CheckpointStoredChild[];
|
|
41
|
+
readonly receipt: CheckpointSaveReceipt;
|
|
42
|
+
readonly selections: readonly CheckpointSelectionPlan[];
|
|
43
|
+
}
|
|
44
|
+
export declare function createCheckpointValueBlock(id: string, value: unknown): CheckpointValueBlock;
|
|
45
|
+
export declare function cloneCheckpointCommit(value: CheckpointCommit): CheckpointCommit;
|
|
46
|
+
export declare function checkpointCommitDigest(commit: CheckpointCommit): string;
|
|
47
|
+
export declare function checkpointCommitReceipt(commit: CheckpointCommit, revision: number): CheckpointSaveReceipt;
|
|
48
|
+
export declare function checkpointImageCommit(image: CheckpointImage, previous?: CheckpointCommit): CheckpointCommit;
|
|
49
|
+
export declare function checkCheckpointPublication(image: CheckpointImage, value: unknown): CheckpointPublication;
|
|
50
|
+
export declare function checkCheckpointCommitReceipt(receipt: unknown, commit: CheckpointCommit, expectedRevision: number): CheckpointSaveReceipt;
|
|
51
|
+
export declare function prepareCheckpointCommit(request: CheckpointCommit, expectedRevision: number, reader: CheckpointCommitReader): CheckpointCommitPlan;
|
|
52
|
+
export declare function materializeCheckpointHead(head: CheckpointStoredHead, children: readonly CheckpointStoredChild[], values: readonly {
|
|
53
|
+
readonly stored: CheckpointStoredValue;
|
|
54
|
+
readonly body: string;
|
|
55
|
+
}[], selections?: readonly {
|
|
56
|
+
readonly head: CheckpointStoredSelection;
|
|
57
|
+
readonly occurrences: readonly CheckpointStoredOccurrence[];
|
|
58
|
+
}[]): CheckpointHead;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{createHash}from"node:crypto";import{isEqual}from"es-toolkit";import{RuntimeError}from"@weiliang0121/capix-contracts";import{cloneCheckpointValue,cloneCheckpointImage,cloneCheckpointDelivery,CHECKPOINT_MAX_BYTES}from"./value.js";import{checkpointMetrics,checkpointEncodingOverhead,encodeCheckpointData,decodeCheckpointData}from"./encoding.js";import{rememberCheckpointHead}from"./evidence.js";import{isCheckpointSelectionSlots,checkpointSelectionReferences,prepareCheckpointSelections,materializeCheckpointSelections,checkpointSnapshotReferences}from"./selections.js";const hash=__name(value=>createHash("sha256").update(value).digest("hex"),"hash"),blockEvidence=new WeakMap;function createCheckpointValueBlock(id,value){requireId(id);const fixed=cloneCheckpointValue(value),body=encodeCheckpointData(fixed),metrics=checkpointMetrics(fixed);requireMetrics(metrics);const block=Object.freeze({id,digest:hash(body),value:fixed});return blockEvidence.set(block,{body,metrics}),block}__name(createCheckpointValueBlock,"createCheckpointValueBlock");function cloneCheckpointCommit(value){const properties=dataProperties(value);if(properties.kind?.value!=="commit"||properties.formatVersion?.value!==6||!Array.isArray(properties.values?.value)||!Array.isArray(properties.children?.value))throw new Error("Invalid incremental checkpoint commit");const values=dataArray(properties.values.value).map(entry=>{const block=entry;if(blockEvidence.has(block))return block;const fields=dataProperties(block);if(Object.keys(fields).sort().join()!=="digest,id,value")throw new Error("Invalid checkpoint value block fields");const fixed2=createCheckpointValueBlock(fields.id.value,fields.value.value);if(fixed2.digest!==fields.digest.value)throw new Error("Checkpoint block digest differs from its value");return fixed2}),rawChildren=dataArray(properties.children.value);if(rawChildren.length>4096)throw new Error("Checkpoint child limit exceeded");const children=Object.freeze(rawChildren.map(child=>cloneCheckpointValue(child))),metadata=Object.fromEntries(Object.entries(properties).filter(([key])=>key!=="values"&&key!=="children"&&key!=="selectionChanges").map(([key,property])=>[key,property.value])),fixed=cloneCheckpointValue(metadata);if(Object.keys(fixed).sort().join()!=="contract,formatVersion,frame,id,kind,point,references,state")throw new Error("Invalid checkpoint commit fields");for(const reference of headReferences(fixed))checkReference(reference);isCheckpointSelectionSlots(fixed.references)&&checkpointSelectionReferences(fixed.references);const selectionChanges=properties.selectionChanges?Object.freeze(dataArray(properties.selectionChanges.value).map(cloneSelectionChange)):void 0;if(selectionChanges&&(selectionChanges.reduce((total,change)=>total+(change.append?.length??0)+(change.remove?.length??0)+1,0)>1e5||Buffer.byteLength(encodeCheckpointData(selectionChanges))>CHECKPOINT_MAX_BYTES))throw new Error("Checkpoint selection delta exceeds its limits");const skeleton=logicalImage(fixed,[],()=>null);return cloneCheckpointImage({...skeleton,references:{}}),Object.freeze({...fixed,values:Object.freeze(values),children,...selectionChanges?{selectionChanges}:{}})}__name(cloneCheckpointCommit,"cloneCheckpointCommit");function checkpointCommitDigest(commit){const{values,...metadata}=cloneCheckpointCommit(commit);return hash(encodeCheckpointData(canonicalMetadata({...metadata,values:values.map(({id,digest})=>({id,digest}))})))}__name(checkpointCommitDigest,"checkpointCommitDigest");function canonicalMetadata(value){return Array.isArray(value)?value.map(canonicalMetadata):value!==null&&typeof value=="object"?Object.fromEntries(Object.keys(value).sort().map(key=>[key,canonicalMetadata(value[key])])):value}__name(canonicalMetadata,"canonicalMetadata");function checkpointCommitReceipt(commit,revision){return Object.freeze({kind:"saved",contextId:commit.frame.owner.contextId,checkpointId:commit.id,revision,digest:checkpointCommitDigest(commit)})}__name(checkpointCommitReceipt,"checkpointCommitReceipt");function checkpointImageCommit(image,previous){const fixed=cloneCheckpointImage(image);if(fixed.formatVersion!==6)throw new Error("Only v6 images can import incremental facts");const values=new Map,existing=new Map,priorChildren=new Map(previous?.children.map(child=>[child.identity.contextId,child]));if(previous){for(const reference of[...headReferences(previous),...previous.children.flatMap(childReferences)])existing.set(reference.digest,reference);const ids=new Set(fixed.frame.children.map(child=>child.identity.contextId));if(previous.children.some(child=>!ids.has(child.identity.contextId)))throw new Error("Full checkpoint import cannot remove established child facts")}const publish=__name((value,expected)=>{const digest=hash(encodeCheckpointData(value));if(expected?.digest===digest)return expected;const prior=existing.get(digest);if(prior)return prior;const id=`value:${digest}`;let block=values.get(id);return block||(block=createCheckpointValueBlock(id,value),values.set(id,block)),Object.freeze({id,digest})},"publish"),children=fixed.frame.children.map(child=>{const state=child.state,prior=priorChildren.get(child.identity.contextId);if(state.kind==="waiting")return{...child,input:publish(child.input,prior?.input),state};const priorState=prior?.state.kind==="waiting"?void 0:prior?.state,priorReception=priorState?.reception,progress={...state.progress,currentInput:publish(state.progress.currentInput,priorState?.progress.currentInput)},reception=state.reception&&("output"in state.reception?{...state.reception,output:publish(state.reception.output,priorReception&&"output"in priorReception?priorReception.output:void 0)}:state.reception.kind==="failed"?{...state.reception,error:publish(state.reception.error,priorReception?.kind==="failed"?priorReception.error:void 0)}:state.reception);return{...child,input:publish(child.input,prior?.input),state:state.kind==="returned"?{...state,output:publish(state.output,priorState?.kind==="returned"?priorState.output:void 0),progress,reception}:{...state,error:publish(state.error,priorState?.kind==="failed"?priorState.error:void 0),progress,...reception?{reception}:{}}}}),{children:_children,...frame}=fixed.frame,commit={kind:"commit",formatVersion:6,id:fixed.id,contract:fixed.contract,point:fixed.point,frame:{...frame,input:publish(frame.input,previous?.frame.input),currentInput:publish(frame.currentInput,previous?.frame.currentInput)},state:publish(fixed.state,previous?.state),references:publish(fixed.references,previous&&!isCheckpointSelectionSlots(previous.references)?previous.references:void 0),values:[...values.values()],children};return cloneCheckpointCommit(commit)}__name(checkpointImageCommit,"checkpointImageCommit");function checkCheckpointPublication(image,value){if(image.formatVersion!==6)throw new Error("Legacy checkpoint heads cannot contain v6 publication references");const fields=dataProperties(value),selectedSelections=fields.selectedSelections?Object.freeze(dataArray(fields.selectedSelections.value).map(cloneSelectionSnapshot)):void 0,publication=cloneCheckpointCommit(Object.fromEntries(Object.entries(fields).filter(([key])=>key!=="selectedSelections").map(([key,field])=>[key,field.value])));if(publication.values.length!==0||publication.selectionChanges!==void 0)throw new Error("Checkpoint publication cannot contain pending changes or duplicate value bodies");let comparison=publication;if(isCheckpointSelectionSlots(publication.references)){const references=checkpointSnapshotReferences(publication.references,image.frame.owner.contextId,selectedSelections??[]);if(!isEqual(references,image.references))throw new Error("Checkpoint selection publication differs from logical references");const ids=new Set([...headReferences(publication),...publication.children.flatMap(childReferences)].map(item=>item.id));let id="publication:references";for(;ids.has(id);)id+=":";comparison={...publication,references:{id,digest:hash(encodeCheckpointData(image.references))}}}else if(selectedSelections!==void 0)throw new Error("Unexpected checkpoint selection publication");const reconstructed=checkpointImageCommit(image,comparison);if(reconstructed.values.length!==0||!isEqual(reconstructed,comparison))throw new Error("Checkpoint publication differs from the complete logical image");const identities=new Map;for(const reference of[...headReferences(publication),...publication.children.flatMap(childReferences)]){const prior=identities.get(reference.id);if(prior&&prior!==reference.digest)throw new Error("Checkpoint publication reuses an identity with different content");identities.set(reference.id,reference.digest)}return Object.freeze({...publication,...selectedSelections?{selectedSelections}:{}})}__name(checkCheckpointPublication,"checkCheckpointPublication");function checkCheckpointCommitReceipt(receipt,commit,expectedRevision){const expected=checkpointCommitReceipt(commit,nextRevision(expectedRevision));if(!receipt||typeof receipt!="object")throw new Error("Invalid checkpoint commit receipt");const descriptors=Object.getOwnPropertyDescriptors(receipt);if(Reflect.ownKeys(descriptors).length!==Object.keys(expected).length||Object.entries(expected).some(([key,value])=>!descriptors[key]||!("value"in descriptors[key])||!descriptors[key].enumerable||descriptors[key].value!==value))throw new Error("Checkpoint receipt differs from incremental commit");return expected}__name(checkCheckpointCommitReceipt,"checkCheckpointCommitReceipt");function prepareCheckpointCommit(request,expectedRevision,reader){const commit=cloneCheckpointCommit(request),revision=nextRevision(expectedRevision),previous=reader.head;if((previous?.revision??0)!==expectedRevision||previous?.delivery)throw new RuntimeError("CHECKPOINT_CONFLICT","Checkpoint head revision or terminal state differs");if(reader.imageUsed(commit.id))throw new RuntimeError("CHECKPOINT_CONFLICT","Checkpoint identity has already been saved");if(previous&&(!isEqual(previous.commit.frame.owner,commit.frame.owner)||!isEqual(previous.commit.contract,commit.contract)||!sameReference(previous.commit.frame.input,commit.frame.input)))throw new RuntimeError("CHECKPOINT_CONFLICT","Checkpoint owner, contract and original input cannot change");if(previous&&(previous.commit.frame.round!==commit.frame.round||!isEqual(previous.commit.frame.continuation,commit.frame.continuation)))throw new RuntimeError("CHECKPOINT_CONFLICT","Incremental checkpoint scope cannot change round or continuation");const values=new Map,bodies=new Map,supplied=new Set;for(const block of commit.values){if(supplied.has(block.id))throw new Error("Duplicate checkpoint value block");supplied.add(block.id);const proof=blockEvidence.get(block),old=reader.value(block.id);if(old&&(old.digest!==block.digest||old.uses>0&&reader.body(block.id)!==proof.body))throw new Error("Checkpoint value identity has different content");values.set(block.id,{id:block.id,digest:block.digest,metrics:proof.metrics,uses:old?.uses??0,referenceChecked:old?.referenceChecked??!1,diagnosticChecked:old?.diagnosticChecked??!1}),bodies.set(block.id,proof.body)}const valueInfo=__name(reference=>{checkReference(reference);let info=values.get(reference.id);if(!info){if(info=reader.value(reference.id),!info||info.uses===0)throw new Error("Checkpoint references a missing or retired value body");values.set(reference.id,info)}if(info.digest!==reference.digest)throw new Error("Checkpoint value reference digest differs");if(!Number.isSafeInteger(info.uses)||info.uses<0||typeof info.referenceChecked!="boolean"||typeof info.diagnosticChecked!="boolean")throw new Error("Invalid checkpoint value metadata");return requireMetrics(info.metrics),info},"valueInfo"),deltas=new Map,account=__name((reference,direction)=>{valueInfo(reference),deltas.set(reference.id,(deltas.get(reference.id)??0)+direction)},"account");if(previous)for(const reference of headReferences(previous.commit))account(reference,-1);for(const reference of headReferences(commit))account(reference,1);let childCount=previous?.childCount??0,childBytes=previous?.childBytes??0,childNodes=previous?.childNodes??0;const childDepths=[...previous?.childDepths??Array.from({length:65},()=>0)],children=[],changed=new Map,orders=new Map;for(const child of commit.children){if(changed.has(child.identity.contextId))throw new Error("Duplicate changed checkpoint relation");const old=reader.child(child.identity.contextId);if(validateChildMetadata(commit,child),old){checkChildAdvance(old.child,child),childBytes-=old.metrics.bytes,childNodes-=old.metrics.nodes,childDepths[old.metrics.depth]=childDepths[old.metrics.depth]-1;for(const reference of childReferences(old.child))account(reference,-1)}else{if(previous&&child.order<previous.commit.frame.nextChildOrder)throw new Error("New checkpoint relation precedes the established order");childCount++}const existing=orders.get(child.order)??reader.order(child.order);if(existing!==void 0&&existing!==child.identity.contextId)throw new Error("Duplicate checkpoint child order");orders.set(child.order,child.identity.contextId),changed.set(child.identity.contextId,child);for(const reference of childReferences(child))account(reference,1);for(const reference of diagnosticReferences(child)){const info=valueInfo(reference);if(!info.diagnosticChecked){const body=bodies.get(info.id)??reader.body(info.id);if(body===void 0)throw new Error("Checkpoint diagnostic body is missing");const diagnostic=decodeCheckpointData(body);if(!diagnostic||typeof diagnostic!="object"||Array.isArray(diagnostic)||!("code"in diagnostic)||typeof diagnostic.code!="string"||!diagnostic.code.length||!("message"in diagnostic)||typeof diagnostic.message!="string")throw new Error("Invalid checkpoint diagnostic");values.set(info.id,{...info,diagnosticChecked:!0})}}const metrics=referencedMetrics(child,childReferences(child),valueInfo);requireMetrics(metrics),childBytes+=metrics.bytes,childNodes+=metrics.nodes,childDepths[metrics.depth]=childDepths[metrics.depth]+1,children.push({child,metrics})}if(childCount>4096||childCount<0||childDepths.length!==65||childDepths.some(n=>!Number.isSafeInteger(n)||n<0))throw new Error("Checkpoint child aggregate exceeds its limits");if(previous&&commit.frame.nextChildOrder<previous.commit.frame.nextChildOrder)throw new Error("Checkpoint next child order cannot regress");const selections=prepareCheckpointSelections(commit,reader,id=>changed.get(id)??reader.child(id)?.child);if(!isCheckpointSelectionSlots(commit.references)){const refsInfo=valueInfo(commit.references);if(!refsInfo.referenceChecked){const body=bodies.get(refsInfo.id)??reader.body(refsInfo.id);if(body===void 0)throw new Error("Checkpoint reference value body is missing");const references=decodeCheckpointData(body);authenticateReferences(references,id=>changed.get(id)??reader.child(id)?.child),values.set(refsInfo.id,{...refsInfo,referenceChecked:!0})}}const depth=childDepths.findLastIndex(count=>count>0),aggregate={bytes:2+childBytes+Math.max(0,childCount-1),nodes:1+childNodes,depth:depth<0?0:depth+1},linkedChildren=[],linkedReferences={},skeleton=logicalImage(commit,linkedChildren,reference=>reference,selections?linkedReferences:void 0),markers=new Map(headReferences(commit).map(ref=>[ref,valueInfo(ref).metrics]));markers.set(linkedChildren,aggregate),selections&&markers.set(linkedReferences,selections.metrics),requireMetrics(checkpointMetrics(skeleton,item=>markers.get(item)));const updates=[];for(const[id,info]of values){const uses=info.uses+(deltas.get(id)??0);if(!Number.isSafeInteger(uses)||uses<0)throw new Error("Invalid checkpoint value reference count");if(supplied.has(id)&&uses===0)throw new Error("Unused new checkpoint value");const body=bodies.get(id),prior=reader.value(id);((deltas.get(id)??0)!==0||body!==void 0||info.referenceChecked!==prior?.referenceChecked||info.diagnosticChecked!==prior?.diagnosticChecked)&&updates.push({stored:{...info,uses},...body!==void 0?{body}:{}})}const{values:_values,children:_children,selectionChanges:_selectionChanges,...header}=commit,receipt=checkpointCommitReceipt(commit,revision);return{head:Object.freeze({commit:header,revision,digest:receipt.digest,childCount,childBytes,childNodes,childDepths:Object.freeze(childDepths)}),values:updates,children,receipt,selections:selections?.plans??[]}}__name(prepareCheckpointCommit,"prepareCheckpointCommit");function materializeCheckpointHead(head,children,values,selections=[]){if(cloneCheckpointCommit({...head.commit,values:[],children:[]}),typeof head.digest!="string"||!/^[a-f0-9]{64}$/.test(head.digest))throw new Error("Invalid persisted checkpoint receipt digest");const loaded=new Map,counts=new Map;for(const{stored,body}of values){if(loaded.has(stored.id)||stored.uses<1||hash(body)!==stored.digest)throw new Error("Invalid persisted checkpoint value");const value=cloneCheckpointValue(decodeCheckpointData(body));if(!isEqual(checkpointMetrics(value),stored.metrics))throw new Error("Persisted checkpoint value metrics differ");loaded.set(stored.id,{stored,value})}const resolve=__name(reference=>{checkReference(reference);const value=loaded.get(reference.id);if(!value||value.stored.digest!==reference.digest)throw new Error("Missing persisted checkpoint value");return counts.set(reference.id,(counts.get(reference.id)??0)+1),value.value},"resolve"),ordered=[...children].sort((a,b)=>a.child.order-b.child.order);let childBytes=0,childNodes=0;const childDepths=Array.from({length:65},()=>0);for(const entry of ordered){const metrics=referencedMetrics(entry.child,childReferences(entry.child),ref=>{const found=loaded.get(ref.id)?.stored;if(!found||found.digest!==ref.digest)throw new Error("Missing child checkpoint value");return found});if(!isEqual(metrics,entry.metrics))throw new Error("Persisted relation metrics differ");requireMetrics(metrics),childBytes+=metrics.bytes,childNodes+=metrics.nodes,childDepths[metrics.depth]=childDepths[metrics.depth]+1}if(head.childCount!==ordered.length||childBytes!==head.childBytes||childNodes!==head.childNodes||!isEqual(childDepths,head.childDepths))throw new Error("Persisted checkpoint aggregates differ");const selected=isCheckpointSelectionSlots(head.commit.references)?materializeCheckpointSelections(head.commit.references,head.commit.frame.owner.contextId,selections):void 0;if(!selected&&selections.length)throw new Error("Unexpected checkpoint selections");const image=cloneCheckpointImage(logicalImage(head.commit,ordered.map(({child})=>mapChild(child,resolve)),resolve,selected?.references));for(const[id,item]of loaded)if(counts.get(id)!==item.stored.uses)throw new Error("Persisted value references differ");if(image.formatVersion!==6||!Number.isSafeInteger(head.revision)||head.revision<1)throw new Error("Invalid incremental checkpoint head");requireMetrics(checkpointMetrics(image));const publication=Object.freeze({...head.commit,values:Object.freeze([]),children:Object.freeze(ordered.map(({child})=>child)),...selected?{selectedSelections:selected.snapshots}:{}}),output=Object.freeze({revision:head.revision,image,...head.delivery?{delivery:cloneCheckpointDelivery(head.delivery)}:{},publication});return rememberCheckpointHead(output,publication),output}__name(materializeCheckpointHead,"materializeCheckpointHead");function logicalImage(commit,children,resolve,references){return{id:commit.id,formatVersion:6,contract:commit.contract,point:commit.point,frame:{...commit.frame,input:resolve(commit.frame.input),currentInput:resolve(commit.frame.currentInput),children},state:resolve(commit.state),references:references??(isCheckpointSelectionSlots(commit.references)?{}:resolve(commit.references))}}__name(logicalImage,"logicalImage");function validateChildMetadata(commit,child){for(const reference of childReferences(child))checkReference(reference);const placeholders=new Set(diagnosticReferences(child)),skeleton=logicalImage(commit,[mapChild(child,reference=>placeholders.has(reference)?{code:"CHECKPOINT_DIAGNOSTIC",message:""}:null)],()=>null);cloneCheckpointImage({...skeleton,references:{}})}__name(validateChildMetadata,"validateChildMetadata");function checkChildAdvance(previous,child){const{state:a,...basisA}=previous,{state:b,...basisB}=child;if(!isEqual(basisA,basisB))throw new Error("Checkpoint child identity and input cannot change");if(a.kind!=="waiting"){if(a.kind!==b.kind)throw new Error("Checkpoint child outcome cannot change");if(a.kind==="returned"&&b.kind==="returned"){if(!sameReference(a.output,b.output)||!isEqual(a.progress,b.progress))throw new Error("Checkpoint returned fact cannot change");if(a.reception.kind==="accepted"||a.reception.kind==="failed"){if(!isEqual(a.reception,b.reception))throw new Error("Checkpoint completed reception cannot change")}else if(a.reception.kind==="receiving"&&(b.reception.kind==="pending"||!isEqual(a.reception.contract,b.reception.contract)))throw new Error("Checkpoint reception cannot regress or replace its contract")}else if(a.kind==="failed"&&b.kind==="failed"&&!isEqual(a,b))throw new Error("Checkpoint handled failure cannot change")}}__name(checkChildAdvance,"checkChildAdvance");function mapChild(child,resolve){const state=child.state;if(state.kind==="waiting")return{...child,input:resolve(child.input),state};const progress={...state.progress,currentInput:resolve(state.progress.currentInput)},reception=state.reception&&("output"in state.reception?{...state.reception,output:resolve(state.reception.output)}:state.reception.kind==="failed"?{...state.reception,error:resolve(state.reception.error)}:state.reception);return{...child,input:resolve(child.input),state:state.kind==="returned"?{...state,output:resolve(state.output),progress,reception}:{...state,error:resolve(state.error),progress,...reception?{reception}:{}}}}__name(mapChild,"mapChild");function headReferences(commit){return[commit.frame.input,commit.frame.currentInput,commit.state,...isCheckpointSelectionSlots(commit.references)?[]:[commit.references]]}__name(headReferences,"headReferences");function childReferences(child){const refs=[child.input];if(child.state.kind!=="waiting"){refs.push(child.state.progress.currentInput,child.state.kind==="returned"?child.state.output:child.state.error);const reception=child.state.reception;reception&&"output"in reception&&refs.push(reception.output),reception?.kind==="failed"&&refs.push(reception.error)}return refs}__name(childReferences,"childReferences");function diagnosticReferences(child){const state=child.state;return state.kind==="failed"?[state.error]:state.kind==="returned"&&state.reception.kind==="failed"?[state.reception.error]:[]}__name(diagnosticReferences,"diagnosticReferences");function referencedMetrics(value,refs,lookup){const markers=new Map(refs.map(reference=>[reference,lookup(reference).metrics]));return checkpointMetrics(value,item=>markers.get(item))}__name(referencedMetrics,"referencedMetrics");function authenticateReferences(references,child){if(!references||typeof references!="object"||Array.isArray(references))throw new Error("Invalid checkpoint references");for(const selected of Object.values(references))for(const ref of Array.isArray(selected)?selected:[selected]){const relation=child(ref.contextId);if(!relation||Object.keys(ref).sort().join()!=="contextId,order,parentContextId,parentRound,target"||ref.parentContextId!==relation.identity.parentContextId||ref.parentRound!==relation.round||ref.order!==relation.order||!isEqual(ref.target,relation.target))throw new Error("Checkpoint reference differs from its relation")}}__name(authenticateReferences,"authenticateReferences");function sameReference(a,b){return a.id===b.id&&a.digest===b.digest}__name(sameReference,"sameReference");function cloneSelectionChange(value){const fields=dataProperties(value),header=cloneCheckpointValue(Object.fromEntries(Object.entries(fields).filter(([key])=>key!=="append"&&key!=="remove").map(([key,field])=>[key,field.value]))),append=fields.append?Object.freeze(dataArray(fields.append.value).map(item=>cloneCheckpointValue(item))):void 0,remove=fields.remove?Object.freeze(dataArray(fields.remove.value).map(item=>cloneCheckpointValue(item))):void 0;return Object.freeze({...header,...append?{append}:{},...remove?{remove}:{}})}__name(cloneSelectionChange,"cloneSelectionChange");function cloneSelectionSnapshot(value){const fields=dataProperties(value),header=cloneCheckpointValue(Object.fromEntries(Object.entries(fields).filter(([key])=>key!=="occurrences").map(([key,field])=>[key,field.value]))),occurrences=Object.freeze(dataArray(fields.occurrences?.value).map(item=>cloneCheckpointValue(item)));return Object.freeze({...header,occurrences})}__name(cloneSelectionSnapshot,"cloneSelectionSnapshot");function dataProperties(value){if(!value||typeof value!="object"||Object.getPrototypeOf(value)!==Object.prototype&&Object.getPrototypeOf(value)!==null)throw new Error("Checkpoint metadata requires an ordinary data record");const properties=Object.getOwnPropertyDescriptors(value);for(const key of Reflect.ownKeys(properties)){const property=typeof key=="string"?properties[key]:void 0;if(!property||!("value"in property)||!property.enumerable)throw new Error("Checkpoint metadata cannot contain accessors or hidden properties")}return properties}__name(dataProperties,"dataProperties");function dataArray(value){if(!Array.isArray(value))throw new Error("Checkpoint metadata requires an array");const descriptors=Object.getOwnPropertyDescriptors(value),length=descriptors.length?.value;if(!Number.isSafeInteger(length)||length<0||Reflect.ownKeys(descriptors).length!==length+1)throw new Error("Checkpoint metadata requires a dense data array");return Array.from({length},(_,index)=>{const property=descriptors[String(index)];if(!property||!("value"in property)||!property.enumerable)throw new Error("Checkpoint metadata array cannot contain accessors");return property.value})}__name(dataArray,"dataArray");function checkReference(value){if(!value||typeof value!="object"||Object.keys(value).sort().join()!=="digest,id")throw new Error("Invalid checkpoint value reference");if(requireId(value.id),!/^[a-f0-9]{64}$/.test(value.digest))throw new Error("Invalid checkpoint value digest")}__name(checkReference,"checkReference");function requireId(value){if(typeof value!="string"||!value.length)throw new Error("Checkpoint value identity is required")}__name(requireId,"requireId");function requireMetrics(value){if(!Number.isSafeInteger(value.bytes)||!Number.isSafeInteger(value.nodes)||!Number.isSafeInteger(value.depth)||value.bytes<1||value.nodes<1||value.depth<0||value.bytes+checkpointEncodingOverhead>CHECKPOINT_MAX_BYTES||value.nodes>1e5||value.depth>64)throw new Error("Checkpoint logical image exceeds its limits")}__name(requireMetrics,"requireMetrics");function nextRevision(value){if(!Number.isSafeInteger(value)||value<0||value>=Number.MAX_SAFE_INTEGER)throw new Error("Invalid checkpoint expected revision");return value+1}__name(nextRevision,"nextRevision");export{checkCheckpointCommitReceipt,checkCheckpointPublication,checkpointCommitDigest,checkpointCommitReceipt,checkpointImageCommit,cloneCheckpointCommit,createCheckpointValueBlock,materializeCheckpointHead,prepareCheckpointCommit};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type { CheckpointValue, CheckpointCodec, CheckpointContract } from '@weiliang0121/capix-contracts';
|
|
2
|
+
export type { CheckpointReference, CheckpointReferences, CheckpointContinuation, CheckpointReceptionContract, CheckpointChildReception, CheckpointHandledReception, CheckpointChild, InvocationCheckpointFrame, CheckpointImage, CheckpointDelivery, CheckpointHead, CheckpointSaveReceipt, CheckpointFinishReceipt, CheckpointStore } from './contract.js';
|
|
3
|
+
export { CHECKPOINT_MAX_BYTES, cloneCheckpointValue, cloneCheckpointImage, cloneCheckpointDelivery, cloneCheckpointHead, checkpointReference, checkpointReferenceChild } from './value.js';
|
|
4
|
+
export { MemoryCheckpointStore } from './store.js';
|
|
5
|
+
export { checkpointSaveReceipt, checkpointFinishReceipt, checkCheckpointSaveReceipt, checkCheckpointFinishReceipt } from './receipt.js';
|
|
6
|
+
export type { CheckpointCommit, CheckpointPublication, CheckpointSelectionReference, CheckpointSelectionSlots, CheckpointSelectionChange, CheckpointSelectionSnapshot, CheckpointValueReference, CheckpointValueBlock, CheckpointChildRecord } from './contract.js';
|
|
7
|
+
export { createCheckpointValueBlock, cloneCheckpointCommit, checkpointCommitDigest, checkpointCommitReceipt, checkCheckpointCommitReceipt } from './incremental.js';
|
|
8
|
+
export { checkpointHeadCommit } from './evidence.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
import{CHECKPOINT_MAX_BYTES,cloneCheckpointValue,cloneCheckpointImage,cloneCheckpointDelivery,cloneCheckpointHead,checkpointReference,checkpointReferenceChild}from"./value.js";import{MemoryCheckpointStore}from"./store.js";import{checkpointSaveReceipt,checkpointFinishReceipt,checkCheckpointSaveReceipt,checkCheckpointFinishReceipt}from"./receipt.js";import{createCheckpointValueBlock,cloneCheckpointCommit,checkpointCommitDigest,checkpointCommitReceipt,checkCheckpointCommitReceipt}from"./incremental.js";import{checkpointHeadCommit}from"./evidence.js";export{CHECKPOINT_MAX_BYTES,MemoryCheckpointStore,checkCheckpointCommitReceipt,checkCheckpointFinishReceipt,checkCheckpointSaveReceipt,checkpointCommitDigest,checkpointCommitReceipt,checkpointFinishReceipt,checkpointHeadCommit,checkpointReference,checkpointReferenceChild,checkpointSaveReceipt,cloneCheckpointCommit,cloneCheckpointDelivery,cloneCheckpointHead,cloneCheckpointImage,cloneCheckpointValue,createCheckpointValueBlock};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CheckpointImage, CheckpointDelivery, CheckpointSaveReceipt, CheckpointFinishReceipt } from './contract.js';
|
|
2
|
+
export declare function checkpointSaveReceipt(image: CheckpointImage, revision: number): CheckpointSaveReceipt;
|
|
3
|
+
export declare function checkpointFinishReceipt(contextId: string, checkpointId: string, delivery: CheckpointDelivery, revision: number): CheckpointFinishReceipt;
|
|
4
|
+
export declare function checkCheckpointSaveReceipt(value: unknown, image: CheckpointImage, expectedRevision: number): CheckpointSaveReceipt;
|
|
5
|
+
export declare function checkCheckpointFinishReceipt(value: unknown, contextId: string, checkpointId: string, delivery: CheckpointDelivery, expectedRevision: number): CheckpointFinishReceipt;
|
package/dist/receipt.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{cloneCheckpointImage,cloneCheckpointDelivery,checkpointImageDigest,checkpointDeliveryDigest}from"./value.js";function checkpointSaveReceipt(image,revision){requireRevision(revision);const fixed=cloneCheckpointImage(image);return Object.freeze({kind:"saved",contextId:fixed.frame.owner.contextId,checkpointId:fixed.id,revision,digest:checkpointImageDigest(fixed)})}__name(checkpointSaveReceipt,"checkpointSaveReceipt");function checkpointFinishReceipt(contextId,checkpointId,delivery,revision){if(requireRevision(revision),typeof contextId!="string"||!contextId.length||typeof checkpointId!="string"||!checkpointId.length)throw new Error("Checkpoint receipt requires context and image identity");const fixed=cloneCheckpointDelivery(delivery);return Object.freeze({kind:"finished",contextId,checkpointId,revision,status:fixed.status,digest:checkpointDeliveryDigest(fixed)})}__name(checkpointFinishReceipt,"checkpointFinishReceipt");function checkCheckpointSaveReceipt(value,image,expectedRevision){const expected=checkpointSaveReceipt(image,nextRevision(expectedRevision));return checkReceipt(value,expected),expected}__name(checkCheckpointSaveReceipt,"checkCheckpointSaveReceipt");function checkCheckpointFinishReceipt(value,contextId,checkpointId,delivery,expectedRevision){const expected=checkpointFinishReceipt(contextId,checkpointId,delivery,nextRevision(expectedRevision));return checkReceipt(value,expected),expected}__name(checkCheckpointFinishReceipt,"checkCheckpointFinishReceipt");function checkReceipt(value,expected){if(!value||typeof value!="object"||Object.getPrototypeOf(value)!==Object.prototype&&Object.getPrototypeOf(value)!==null)throw new Error("Invalid checkpoint commit receipt");const properties=Object.getOwnPropertyDescriptors(value);if(Reflect.ownKeys(properties).length!==Object.keys(expected).length)throw new Error("Invalid checkpoint commit receipt fields");for(const[key,entry]of Object.entries(expected)){const property=properties[key];if(!property||!("value"in property)||!property.enumerable||property.value!==entry)throw new Error(`Checkpoint commit receipt differs from request: ${key}`)}}__name(checkReceipt,"checkReceipt");function requireRevision(revision){if(!Number.isSafeInteger(revision)||revision<1)throw new Error("Invalid checkpoint receipt revision")}__name(requireRevision,"requireRevision");function nextRevision(expected){if(!Number.isSafeInteger(expected)||expected<0||expected>=Number.MAX_SAFE_INTEGER)throw new Error("Invalid checkpoint expected revision");return expected+1}__name(nextRevision,"nextRevision");export{checkCheckpointFinishReceipt,checkCheckpointSaveReceipt,checkpointFinishReceipt,checkpointSaveReceipt};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CheckpointStoredChild } from './incremental.js';
|
|
2
|
+
export interface CheckpointRelationRow {
|
|
3
|
+
readonly child_id: unknown;
|
|
4
|
+
readonly ordinal: unknown;
|
|
5
|
+
readonly body: unknown;
|
|
6
|
+
}
|
|
7
|
+
export declare class CheckpointRelationCache {
|
|
8
|
+
#private;
|
|
9
|
+
constructor(limits?: {
|
|
10
|
+
readonly maxEntries?: number;
|
|
11
|
+
readonly maxBytes?: number;
|
|
12
|
+
});
|
|
13
|
+
decode(owner: string, id: string, row: CheckpointRelationRow | undefined): CheckpointStoredChild | undefined;
|
|
14
|
+
forget(owner: string): void;
|
|
15
|
+
clear(): void;
|
|
16
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{decodeCheckpointRecord}from"./storage-record.js";class CheckpointRelationCache{static{__name(this,"CheckpointRelationCache")}#owners=new Map;#recent=new Map;#maxEntries;#maxBytes;#bytes=0;constructor(limits={}){if(this.#maxEntries=limits.maxEntries??4096,this.#maxBytes=limits.maxBytes??16*1024*1024,!Number.isSafeInteger(this.#maxEntries)||this.#maxEntries<0||!Number.isSafeInteger(this.#maxBytes)||this.#maxBytes<0)throw new TypeError("Invalid checkpoint relation cache limits")}decode(owner,id,row){const previous=this.#owners.get(owner)?.get(id);if(!row){previous&&this.#remove(previous);return}if(row.child_id===id&&previous&&row.ordinal===previous.ordinal&&row.body===previous.body)return this.#recent.delete(previous),this.#recent.set(previous,!0),previous.value;if(previous&&this.#remove(previous),row.child_id!==id||typeof row.body!="string")throw new Error("Invalid checkpoint relation row");const value=decodeCheckpointRecord("child",row.body);if(value.child.identity.contextId!==row.child_id||value.child.order!==row.ordinal)throw new Error("Checkpoint relation row identity differs");const bytes=64+2*(owner.length+id.length+row.body.length);if(!this.#maxEntries||bytes>this.#maxBytes)return value;for(;this.#recent.size>=this.#maxEntries||this.#bytes+bytes>this.#maxBytes;)this.#remove(this.#recent.keys().next().value);const entry={owner,id,ordinal:row.ordinal,body:row.body,value,bytes};let entries=this.#owners.get(owner);return entries||this.#owners.set(owner,entries=new Map),entries.set(id,entry),this.#recent.set(entry,!0),this.#bytes+=bytes,value}forget(owner){const entries=this.#owners.get(owner);if(entries)for(const entry of entries.values())this.#remove(entry)}clear(){this.#owners.clear(),this.#recent.clear(),this.#bytes=0}#remove(entry){const entries=this.#owners.get(entry.owner);entries.delete(entry.id),entries.size||this.#owners.delete(entry.owner),this.#recent.delete(entry),this.#bytes-=entry.bytes}}export{CheckpointRelationCache};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { CheckpointCommit, CheckpointReference, CheckpointReferences, CheckpointSelectionReference, CheckpointSelectionSlots, CheckpointSelectionSnapshot, CheckpointChildRecord } from './contract.js';
|
|
2
|
+
import { type CheckpointValueMetrics } from './encoding.js';
|
|
3
|
+
export interface CheckpointStoredSelection extends CheckpointSelectionReference {
|
|
4
|
+
readonly owner: string;
|
|
5
|
+
readonly nextOrder: number;
|
|
6
|
+
readonly count: number;
|
|
7
|
+
readonly bytes: number;
|
|
8
|
+
readonly nodes: number;
|
|
9
|
+
readonly sum: string;
|
|
10
|
+
readonly digest: string;
|
|
11
|
+
}
|
|
12
|
+
export interface CheckpointStoredOccurrence {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
readonly order: number;
|
|
15
|
+
readonly reference?: CheckpointReference;
|
|
16
|
+
}
|
|
17
|
+
export interface CheckpointSelectionReader {
|
|
18
|
+
selection(id: string): CheckpointStoredSelection | undefined;
|
|
19
|
+
occurrence(selection: string, id: string): CheckpointStoredOccurrence | undefined;
|
|
20
|
+
}
|
|
21
|
+
export interface CheckpointSelectionPlan {
|
|
22
|
+
readonly head: CheckpointStoredSelection;
|
|
23
|
+
readonly reset: boolean;
|
|
24
|
+
readonly remove: readonly string[];
|
|
25
|
+
readonly append: readonly CheckpointStoredOccurrence[];
|
|
26
|
+
}
|
|
27
|
+
export declare function isCheckpointSelectionSlots(value: CheckpointCommit['references']): value is CheckpointSelectionSlots;
|
|
28
|
+
export declare function checkpointSelectionReferences(value: CheckpointSelectionSlots): readonly CheckpointSelectionReference[];
|
|
29
|
+
export declare function checkCheckpointStoredSelection(value: CheckpointStoredSelection, owner: string, id: string): void;
|
|
30
|
+
export declare function prepareCheckpointSelections(commit: CheckpointCommit, reader: CheckpointSelectionReader, child: (id: string) => CheckpointChildRecord | undefined): {
|
|
31
|
+
readonly plans: readonly CheckpointSelectionPlan[];
|
|
32
|
+
readonly metrics: CheckpointValueMetrics;
|
|
33
|
+
} | undefined;
|
|
34
|
+
export declare function materializeCheckpointSelections(slots: CheckpointSelectionSlots, owner: string, selections: readonly {
|
|
35
|
+
readonly head: CheckpointStoredSelection;
|
|
36
|
+
readonly occurrences: readonly CheckpointStoredOccurrence[];
|
|
37
|
+
}[]): {
|
|
38
|
+
readonly references: CheckpointReferences;
|
|
39
|
+
readonly snapshots: readonly CheckpointSelectionSnapshot[];
|
|
40
|
+
};
|
|
41
|
+
export declare function checkCheckpointSelectionSnapshot(snapshot: CheckpointSelectionSnapshot, owner: string): void;
|
|
42
|
+
export declare function checkpointSnapshotReferences(slots: CheckpointSelectionSlots, owner: string, snapshots: readonly CheckpointSelectionSnapshot[]): CheckpointReferences;
|
|
43
|
+
export declare function authenticateCheckpointReference(ref: CheckpointReference, child: (id: string) => CheckpointChildRecord | undefined): void;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target2,value)=>__defProp(target2,"name",{value,configurable:!0});import{createHash}from"node:crypto";import{isEqual}from"es-toolkit";import{checkpointMetrics,encodeCheckpointData}from"./encoding.js";const zero="0".repeat(64),mask=(1n<<256n)-1n,hash=__name(value=>createHash("sha256").update(encodeCheckpointData(canonical(value))).digest("hex"),"hash");function canonical(value){return Array.isArray(value)?value.map(canonical):value!==null&&typeof value=="object"?Object.fromEntries(Object.keys(value).sort().map(key=>[key,canonical(value[key])])):value}__name(canonical,"canonical");const digest=__name(({digest:_digest,...value})=>hash(value),"digest"),add=__name((sum,term,direction)=>(BigInt(`0x${sum}`)+BigInt(direction)*BigInt(`0x${term}`)&mask).toString(16).padStart(64,"0"),"add");function isCheckpointSelectionSlots(value){return"kind"in value&&value.kind==="slots"}__name(isCheckpointSelectionSlots,"isCheckpointSelectionSlots");function checkpointSelectionReferences(value){if(exact(value,["kind","slots"]),!value.slots||typeof value.slots!="object"||Array.isArray(value.slots))throw new Error("Invalid checkpoint selection slots");const result=new Map;for(const slot of Object.values(value.slots))if(slot.kind==="one")exact(slot,["kind","reference"]),validateReference(slot.reference);else if(slot.kind==="many"){exact(slot,["kind","selection"]);const reference=slot.selection;exact(reference,["id","revision","target"]),identity(reference.id),integer(reference.revision,1),target(reference.target);const previous=result.get(reference.id);if(previous&&!isEqual(previous,reference))throw new Error("One selection cannot name different revisions or positions");result.set(reference.id,reference)}else throw new Error("Invalid checkpoint selection slot");return[...result.values()]}__name(checkpointSelectionReferences,"checkpointSelectionReferences");function occurrenceDigest(selection,occurrence){return hash({owner:selection.owner,selection:selection.id,target:selection.target,occurrence})}__name(occurrenceDigest,"occurrenceDigest");function checkCheckpointStoredSelection(value,owner,id){if(exact(value,["owner","id","target","revision","nextOrder","count","bytes","nodes","sum","digest"]),value.owner!==owner||value.id!==id)throw new Error("Checkpoint selection owner or identity differs");identity(id),target(value.target),integer(value.revision,1);for(const item of[value.nextOrder,value.count,value.bytes,value.nodes])integer(item,0);if(value.count>value.nextOrder||!/^[a-f0-9]{64}$/.test(value.sum)||value.digest!==digest(value))throw new Error("Checkpoint selection aggregate differs")}__name(checkCheckpointStoredSelection,"checkCheckpointStoredSelection");function prepareCheckpointSelections(commit,reader,child){if(!isCheckpointSelectionSlots(commit.references)){if(commit.selectionChanges?.length)throw new Error("Selection changes require explicit selection slots");return}const owner=commit.frame.owner.contextId,selected=checkpointSelectionReferences(commit.references),changes=new Map;for(const change of commit.selectionChanges??[]){if(exact(change,["id","target","expectedRevision"],["reset","append","remove"]),identity(change.id),target(change.target),integer(change.expectedRevision,0),change.reset!==void 0&&change.reset!==!0)throw new Error("Invalid checkpoint selection reset");if(changes.has(change.id))throw new Error("Duplicate checkpoint selection change");if(change.reset&&change.remove?.length)throw new Error("A selection reset cannot also remove individual occurrences");changes.set(change.id,change)}const installed=new Map,plans=[];for(const selection of selected){const previous=reader.selection(selection.id);if(previous&&(checkCheckpointStoredSelection(previous,owner,selection.id),!isEqual(previous.target,selection.target)))throw new Error("Checkpoint selection position cannot change");const change=changes.get(selection.id);if(!change){if(!previous||previous.revision!==selection.revision)throw new Error("Checkpoint selection revision is unavailable");installed.set(selection.id,previous);continue}if(change.expectedRevision!==(previous?.revision??0)||selection.revision!==change.expectedRevision+1||!isEqual(change.target,selection.target))throw new Error("Checkpoint selection revision or position conflicts");integer(selection.revision,1);let count=change.reset?0:previous?.count??0,bytes=change.reset?0:previous?.bytes??0,nodes=change.reset?0:previous?.nodes??0,sum=change.reset?zero:previous?.sum??zero,nextOrder=previous?.nextOrder??0;const basis={owner,id:selection.id,target:selection.target},removed=new Set;for(const removal of change.remove??[]){exact(removal,["id","order","reference"]);const id=removal.id;if(identity(id),integer(removal.order,0),validateReference(removal.reference),removed.has(id))throw new Error("Duplicate removed checkpoint occurrence");const occurrence=reader.occurrence(selection.id,id);if(!occurrence?.reference)throw new Error("Checkpoint occurrence is missing or already removed");if(validateOccurrence(occurrence),occurrence.id!==id||occurrence.order!==removal.order||occurrence.order>=nextOrder||!isEqual(occurrence.reference,removal.reference))throw new Error("Checkpoint occurrence identity, order or value differs");const metrics=checkpointMetrics(occurrence.reference);count--,bytes-=metrics.bytes,nodes-=metrics.nodes,sum=add(sum,occurrenceDigest(basis,occurrence),-1),removed.add(id)}const appended=new Map;for(const item of change.append??[]){if(exact(item,["id","reference"]),identity(item.id),validateReference(item.reference),appended.has(item.id)||reader.occurrence(selection.id,item.id))throw new Error("Checkpoint occurrence identity is already reserved");if(authenticateCheckpointReference(item.reference,child),item.reference.parentContextId!==owner||item.reference.parentRound!==commit.frame.round||!isEqual(item.reference.target,selection.target))throw new Error("Checkpoint selection reference belongs to a different scope or position");integer(nextOrder+1,1);const occurrence=Object.freeze({id:item.id,order:nextOrder++,reference:item.reference}),metrics=checkpointMetrics(item.reference);count++,bytes+=metrics.bytes,nodes+=metrics.nodes,sum=add(sum,occurrenceDigest(basis,occurrence),1),appended.set(item.id,occurrence)}if(count<0||bytes<0||nodes<0||count===0&&(bytes!==0||nodes!==0||sum!==zero))throw new Error("Checkpoint selection accounting differs");const candidate={...basis,revision:selection.revision,nextOrder,count,bytes,nodes,sum,digest:""},head=Object.freeze({...candidate,digest:digest(candidate)});checkCheckpointStoredSelection(head,owner,selection.id),installed.set(selection.id,head),plans.push({head,reset:!!change.reset,remove:[...removed],append:[...appended.values()]}),changes.delete(selection.id)}if(changes.size)throw new Error("Unselected checkpoint selection changes cannot be committed");const skeleton=Object.create(null),markers=new Map;for(const[name,slot]of Object.entries(commit.references.slots))if(slot.kind==="one")authenticateCheckpointReference(slot.reference,child),skeleton[name]=slot.reference;else{const selection=installed.get(slot.selection.id),array=[];skeleton[name]=array,markers.set(array,{bytes:2+selection.bytes+Math.max(0,selection.count-1),nodes:1+selection.nodes,depth:selection.count?3:0})}return{plans,metrics:checkpointMetrics(skeleton,value=>markers.get(value))}}__name(prepareCheckpointSelections,"prepareCheckpointSelections");function materializeCheckpointSelections(slots,owner,selections){const byId=new Map(selections.map(item=>[item.head.id,item]));if(byId.size!==selections.length)throw new Error("Duplicate persisted selection");const snapshots=[],contents=new Map;for(const selected of checkpointSelectionReferences(slots)){const item=byId.get(selected.id);if(!item)throw new Error("Missing persisted checkpoint selection");if(checkCheckpointStoredSelection(item.head,owner,selected.id),item.head.revision!==selected.revision||!isEqual(item.head.target,selected.target))throw new Error("Persisted checkpoint selection revision differs");const all=[...item.occurrences].sort((a,b)=>a.order-b.order);if(all.length!==item.head.nextOrder||new Set(all.map(value=>value.id)).size!==all.length)throw new Error("Persisted checkpoint occurrence identities differ");const live=[];all.forEach((value,index)=>{if(validateOccurrence(value),value.order!==index)throw new Error("Persisted checkpoint occurrence order is incomplete");value.reference&&live.push(value)});const snapshot=Object.freeze({...item.head,occurrences:Object.freeze(live)});checkCheckpointSelectionSnapshot(snapshot,owner),snapshots.push(snapshot),contents.set(selected.id,Object.freeze(live.map(({reference})=>reference))),byId.delete(selected.id)}if(byId.size)throw new Error("Unexpected unselected checkpoint material");return{references:projectReferences(slots,contents),snapshots:Object.freeze(snapshots)}}__name(materializeCheckpointSelections,"materializeCheckpointSelections");function checkCheckpointSelectionSnapshot(snapshot,owner){const{occurrences,...head}=snapshot;if(checkCheckpointStoredSelection(head,owner,snapshot.id),!Array.isArray(occurrences)||occurrences.length!==snapshot.count)throw new Error("Checkpoint selection snapshot count differs");let bytes=0,nodes=0,sum=zero,order=-1;const ids=new Set;for(const occurrence of occurrences){if(validateOccurrence(occurrence),!occurrence.reference||occurrence.order<=order||occurrence.order>=snapshot.nextOrder||ids.has(occurrence.id)||occurrence.reference.parentContextId!==owner||!isEqual(occurrence.reference.target,snapshot.target))throw new Error("Checkpoint selection snapshot occurrence differs");order=occurrence.order,ids.add(occurrence.id);const metrics=checkpointMetrics(occurrence.reference);bytes+=metrics.bytes,nodes+=metrics.nodes,sum=add(sum,occurrenceDigest(snapshot,occurrence),1)}if(bytes!==snapshot.bytes||nodes!==snapshot.nodes||sum!==snapshot.sum)throw new Error("Checkpoint selection snapshot aggregate differs")}__name(checkCheckpointSelectionSnapshot,"checkCheckpointSelectionSnapshot");function checkpointSnapshotReferences(slots,owner,snapshots){const selected=checkpointSelectionReferences(slots),values=new Map;if(selected.length!==snapshots.length)throw new Error("Checkpoint selection publication differs");for(const item of snapshots){checkCheckpointSelectionSnapshot(item,owner);const reference=selected.find(entry=>entry.id===item.id);if(!reference||reference.revision!==item.revision||!isEqual(reference.target,item.target)||values.has(item.id))throw new Error("Checkpoint selection publication identity differs");values.set(item.id,item.occurrences.map(({reference:reference2})=>reference2))}return projectReferences(slots,values)}__name(checkpointSnapshotReferences,"checkpointSnapshotReferences");function projectReferences(slots,contents){return Object.freeze(Object.fromEntries(Object.entries(slots.slots).map(([name,slot])=>[name,slot.kind==="one"?slot.reference:contents.get(slot.selection.id)])))}__name(projectReferences,"projectReferences");function validateOccurrence(value){exact(value,["id","order"],["reference"]),identity(value.id),integer(value.order,0),value.reference&&validateReference(value.reference)}__name(validateOccurrence,"validateOccurrence");function authenticateCheckpointReference(ref,child){validateReference(ref);const relation=child(ref.contextId);if(!relation||ref.parentContextId!==relation.identity.parentContextId||ref.parentRound!==relation.round||ref.order!==relation.order||!isEqual(ref.target,relation.target))throw new Error("Checkpoint reference differs from its relation")}__name(authenticateCheckpointReference,"authenticateCheckpointReference");function validateReference(value){exact(value,["contextId","parentContextId","parentRound","order","target"]),identity(value.contextId),identity(value.parentContextId),integer(value.parentRound,1),integer(value.order,0),target(value.target)}__name(validateReference,"validateReference");function target(value){exact(value,["position"]),integer(value.position,0)}__name(target,"target");function identity(value){if(typeof value!="string"||!value.length)throw new Error("Invalid checkpoint selection identity")}__name(identity,"identity");function integer(value,minimum){if(!Number.isSafeInteger(value)||value<minimum)throw new Error("Invalid checkpoint selection number")}__name(integer,"integer");function exact(value,required,optional=[]){if(!value||typeof value!="object"||Array.isArray(value)||required.some(key=>!Object.hasOwn(value,key))||Object.keys(value).some(key=>!required.includes(key)&&!optional.includes(key)))throw new Error("Invalid checkpoint selection fields")}__name(exact,"exact");export{authenticateCheckpointReference,checkCheckpointSelectionSnapshot,checkCheckpointStoredSelection,checkpointSelectionReferences,checkpointSnapshotReferences,isCheckpointSelectionSlots,materializeCheckpointSelections,prepareCheckpointSelections};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
type RecordKind = 'head' | 'child' | 'value' | 'selection' | 'occurrence';
|
|
2
|
+
export declare function encodeCheckpointRecord(kind: RecordKind, value: unknown): string;
|
|
3
|
+
export declare function isCheckpointRecord(body: string): boolean;
|
|
4
|
+
export declare function decodeCheckpointRecord<T>(kind: RecordKind, body: string): T;
|
|
5
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{createHash}from"node:crypto";import{encodeCheckpointData,decodeCheckpointData}from"./encoding.js";import{cloneCheckpointValue,CHECKPOINT_MAX_BYTES}from"./value.js";const format="capix.checkpoint.record@1";function encodeCheckpointRecord(kind,value){const body=encodeCheckpointData(value);return JSON.stringify({format,kind,body,digest:digest(body)})}__name(encodeCheckpointRecord,"encodeCheckpointRecord");function isCheckpointRecord(body){if(Buffer.byteLength(body)>CHECKPOINT_MAX_BYTES)throw new Error("Checkpoint metadata exceeds byte limit");return body.startsWith(`{"format":"${format}",`)}__name(isCheckpointRecord,"isCheckpointRecord");function decodeCheckpointRecord(kind,body){if(Buffer.byteLength(body)>CHECKPOINT_MAX_BYTES)throw new Error("Checkpoint metadata exceeds byte limit");const record=JSON.parse(body);if(!record||Object.keys(record).sort().join()!=="body,digest,format,kind"||record.format!==format||record.kind!==kind||typeof record.body!="string"||record.digest!==digest(record.body))throw new Error("Checkpoint metadata checksum or kind differs");return cloneCheckpointValue(decodeCheckpointData(record.body))}__name(decodeCheckpointRecord,"decodeCheckpointRecord");function digest(value){return createHash("sha256").update(value).digest("hex")}__name(digest,"digest");export{decodeCheckpointRecord,encodeCheckpointRecord,isCheckpointRecord};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { prepareCheckpointCommit, materializeCheckpointHead, checkpointImageCommit } from './incremental.js';
|
|
2
|
+
export type { CheckpointStoredValue, CheckpointStoredChild, CheckpointStoredHead, CheckpointCommitReader, CheckpointCommitPlan } from './incremental.js';
|
|
3
|
+
export { encodeCheckpointData, decodeCheckpointData } from './encoding.js';
|
|
4
|
+
export { encodeCheckpointRecord, decodeCheckpointRecord, isCheckpointRecord } from './storage-record.js';
|
|
5
|
+
export { CheckpointRelationCache } from './relation-cache.js';
|
|
6
|
+
export type { CheckpointRelationRow } from './relation-cache.js';
|
|
7
|
+
export { isCheckpointSelectionSlots, checkpointSelectionReferences } from './selections.js';
|
|
8
|
+
export type { CheckpointStoredSelection, CheckpointStoredOccurrence, CheckpointSelectionPlan } from './selections.js';
|
package/dist/storage.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
import{prepareCheckpointCommit,materializeCheckpointHead,checkpointImageCommit}from"./incremental.js";import{encodeCheckpointData,decodeCheckpointData}from"./encoding.js";import{encodeCheckpointRecord,decodeCheckpointRecord,isCheckpointRecord}from"./storage-record.js";import{CheckpointRelationCache}from"./relation-cache.js";import{isCheckpointSelectionSlots,checkpointSelectionReferences}from"./selections.js";export{CheckpointRelationCache,checkpointImageCommit,checkpointSelectionReferences,decodeCheckpointData,decodeCheckpointRecord,encodeCheckpointData,encodeCheckpointRecord,isCheckpointRecord,isCheckpointSelectionSlots,materializeCheckpointHead,prepareCheckpointCommit};
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CheckpointStore, CheckpointImage, CheckpointHead, CheckpointDelivery, CheckpointSaveReceipt, CheckpointFinishReceipt, CheckpointCommit } from './contract.js';
|
|
2
|
+
export declare class MemoryCheckpointStore implements CheckpointStore {
|
|
3
|
+
#private;
|
|
4
|
+
read(contextId: string): CheckpointHead | undefined;
|
|
5
|
+
save(image: CheckpointImage | CheckpointCommit, expectedRevision: number): CheckpointSaveReceipt;
|
|
6
|
+
finish(contextId: string, expectedRevision: number, delivery: CheckpointDelivery): CheckpointFinishReceipt;
|
|
7
|
+
private saveChanges;
|
|
8
|
+
}
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{RuntimeError}from"@weiliang0121/capix-contracts";import{cloneCheckpointImage,cloneCheckpointDelivery}from"./value.js";import{checkpointSaveReceipt,checkpointFinishReceipt}from"./receipt.js";import{prepareCheckpointCommit,materializeCheckpointHead,checkpointImageCommit}from"./incremental.js";import{checkpointHeadCommit}from"./evidence.js";import{isCheckpointSelectionSlots,checkpointSelectionReferences}from"./selections.js";class MemoryCheckpointStore{static{__name(this,"MemoryCheckpointStore")}#usedImageIds=new Set;#incremental=new Map;read(contextId){requireContext(contextId);const current=this.#incremental.get(contextId);if(current)return materializeCheckpointHead(current.head,[...current.children.values()],[...current.values.values()].filter(entry=>entry.stored.uses>0).map(entry=>({stored:entry.stored,body:entry.body})),isCheckpointSelectionSlots(current.head.commit.references)?checkpointSelectionReferences(current.head.commit.references).map(({id})=>{const source=current.selections.get(id);if(!source)throw new Error("Missing checkpoint selection");return{head:source.head,occurrences:[...source.reserved].map(([id2,order])=>source.active.get(id2)??{id:id2,order})}}):[])}save(image,expectedRevision){if("kind"in image&&image.kind==="commit")return this.saveChanges(image,expectedRevision);const fixed=cloneCheckpointImage(image),current=this.read(fixed.frame.owner.contextId);return this.saveChanges(checkpointImageCommit(fixed,current&&checkpointHeadCommit(current)),expectedRevision),checkpointSaveReceipt(fixed,expectedRevision+1)}finish(contextId,expectedRevision,delivery){requireContext(contextId),requireRevision(expectedRevision);const fixed=cloneCheckpointDelivery(delivery),incremental=this.#incremental.get(contextId);if(incremental){if(incremental.head.revision!==expectedRevision||incremental.head.delivery)throw conflict("Checkpoint head revision or terminal state differs");return incremental.head=Object.freeze({...incremental.head,revision:expectedRevision+1,delivery:fixed}),checkpointFinishReceipt(contextId,incremental.head.commit.id,fixed,expectedRevision+1)}throw conflict("Cannot finish a checkpoint scope without a saved image")}saveChanges(commit,expectedRevision){const contextId=commit.frame.owner.contextId,current=this.#incremental.get(contextId),plan=prepareCheckpointCommit(commit,expectedRevision,{head:current?.head,value:__name(id=>current?.values.get(id)?.stored,"value"),body:__name(id=>current?.values.get(id)?.body,"body"),child:__name(id=>current?.children.get(id),"child"),order:__name(order=>current?.orders.get(order),"order"),imageUsed:__name(id=>this.#usedImageIds.has(id),"imageUsed"),selection:__name(id=>current?.selections.get(id)?.head,"selection"),occurrence:__name((selection,id)=>{const source=current?.selections.get(selection),order=source?.reserved.get(id);return source?.active.get(id)??(order===void 0?void 0:{id,order})},"occurrence")}),next=current??{head:plan.head,children:new Map,orders:new Map,values:new Map,selections:new Map};for(const entry of plan.values){const body=entry.stored.uses===0?void 0:entry.body??next.values.get(entry.stored.id)?.body;next.values.set(entry.stored.id,{stored:entry.stored,...body!==void 0?{body}:{}})}for(const entry of plan.children)next.children.set(entry.child.identity.contextId,entry),next.orders.set(entry.child.order,entry.child.identity.contextId);for(const change of plan.selections){const source=next.selections.get(change.head.id)??{head:change.head,active:new Map,reserved:new Map};change.reset&&source.active.clear();for(const id of change.remove)source.active.delete(id);for(const item of change.append)source.active.set(item.id,item),source.reserved.set(item.id,item.order);source.head=change.head,next.selections.set(change.head.id,source)}return next.head=plan.head,this.#usedImageIds.add(commit.id),this.#incremental.set(contextId,next),plan.receipt}}function requireRevision(revision){if(!Number.isSafeInteger(revision)||revision<0||revision>=Number.MAX_SAFE_INTEGER)throw new TypeError("Checkpoint expected revision must be a nonnegative safe integer with room to advance")}__name(requireRevision,"requireRevision");function requireContext(contextId){if(typeof contextId!="string"||contextId.length===0)throw new TypeError("Checkpoint context identity is required")}__name(requireContext,"requireContext");function conflict(message){return new RuntimeError("CHECKPOINT_CONFLICT",message)}__name(conflict,"conflict");export{MemoryCheckpointStore};
|
package/dist/value.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CheckpointImage, CheckpointDelivery, CheckpointHead, CheckpointChild, CheckpointReference } from './contract.js';
|
|
2
|
+
import type { CheckpointValue } from '@weiliang0121/capix-contracts';
|
|
3
|
+
export declare const CHECKPOINT_MAX_BYTES: number;
|
|
4
|
+
export declare function cloneCheckpointValue(value: unknown): CheckpointValue;
|
|
5
|
+
export declare function checkpointReferenceChild(value: unknown, children: readonly CheckpointChild[]): CheckpointChild;
|
|
6
|
+
export declare function checkpointReference(child: CheckpointChild): CheckpointReference;
|
|
7
|
+
export declare function cloneCheckpointImage(value: unknown): CheckpointImage;
|
|
8
|
+
export declare function cloneCheckpointDelivery(value: unknown): CheckpointDelivery;
|
|
9
|
+
export declare function checkpointImageDigest(image: CheckpointImage): string;
|
|
10
|
+
export declare function checkpointDeliveryDigest(delivery: CheckpointDelivery): string;
|
|
11
|
+
export declare function cloneCheckpointHead(value: CheckpointHead): CheckpointHead;
|
package/dist/value.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! MIT License | Copyright (c) 2026 wei.liang | See LICENSE */
|
|
2
|
+
var __defProp=Object.defineProperty;var __name=(target,value)=>__defProp(target,"name",{value,configurable:!0});import{RuntimeError}from"@weiliang0121/capix-contracts";import{createHash}from"node:crypto";import{encodeCheckpointData}from"./encoding.js";import{checkpointHeadCommit,rememberCheckpointHead}from"./evidence.js";import{checkCheckpointPublication}from"./incremental.js";const CHECKPOINT_MAX_BYTES=8*1024*1024,fail=__name(message=>{throw new Error(`Invalid checkpoint: ${message}`)},"fail"),images=new WeakMap,deliveries=new WeakMap,fixedValues=new WeakMap;function cloneCheckpointValue(value){return copyCheckpointValue(value).value}__name(cloneCheckpointValue,"cloneCheckpointValue");function copyCheckpointValue(value){const ancestors=new Set;let count=0,bytes=0,deepest=0;const visit=__name((item,depth)=>{const fixed=item&&typeof item=="object"?fixedValues.get(item):void 0;if(fixed)return count+=fixed.nodes,bytes+=fixed.bytes,deepest=Math.max(deepest,depth+fixed.depth),count>1e5||deepest>64?fail("structure limit exceeded"):bytes>CHECKPOINT_MAX_BYTES?fail("byte limit exceeded"):item;if(++count>1e5||depth>64)return fail("structure limit exceeded");if(deepest=Math.max(deepest,depth),typeof item=="string"?bytes+=Buffer.byteLength(item,"utf8"):bytes+=8,bytes>CHECKPOINT_MAX_BYTES)return fail("byte limit exceeded");if(item===null||typeof item=="boolean"||typeof item=="string"||typeof item=="number"&&Number.isFinite(item))return item;if(!item||typeof item!="object")return fail("only finite JSON data is supported");const array=Array.isArray(item);if(!array&&Object.getPrototypeOf(item)!==Object.prototype&&Object.getPrototypeOf(item)!==null)return fail("live objects are not supported");if(ancestors.has(item))return fail("cyclic value");ancestors.add(item);try{const descriptors=Object.getOwnPropertyDescriptors(item);if(Reflect.ownKeys(descriptors).some(key=>typeof key!="string"))return fail("symbol property");const output={},values=[],keys=Object.keys(descriptors).filter(key=>!array||key!=="length");if(array&&keys.length!==item.length)return fail("sparse or extended array");for(const key of keys){const property=descriptors[key];if(!("value"in property)||!property.enumerable)return fail("accessor or hidden property");bytes+=Buffer.byteLength(key,"utf8");const child=visit(property.value,depth+1);if(array){if(key!==String(values.length))return fail("non-index array property");values.push(child)}else Object.defineProperty(output,key,{value:child,enumerable:!0,writable:!1,configurable:!1})}return Object.freeze(array?values:output)}finally{ancestors.delete(item)}},"visit"),result=visit(value,0),json=JSON.stringify(result);return Buffer.byteLength(json,"utf8")>CHECKPOINT_MAX_BYTES&&fail("encoded byte limit exceeded"),result&&typeof result=="object"&&!fixedValues.has(result)&&fixedValues.set(result,{nodes:count,bytes,depth:deepest}),{value:result,json}}__name(copyCheckpointValue,"copyCheckpointValue");const object=__name(value=>value!==null&&typeof value=="object"&&!Array.isArray(value),"object"),text=__name(value=>typeof value=="string"&&value.trim().length>0&&value.length<=1024,"text"),integer=__name((value,minimum=0)=>Number.isSafeInteger(value)&&value>=minimum,"integer"),contract=__name(value=>object(value)&&text(value.key)&&integer(value.version,1),"contract"),identity=__name(value=>object(value)&&text(value.contextId)&&["scene","group","node"].includes(value.kind)&&!Object.hasOwn(value,"level")&&(value.parentContextId===void 0||text(value.parentContextId)),"identity"),progress=__name(value=>object(value)&&integer(value.round,1)&&value.round<=2&&["execute","receive","handling"].includes(value.phase)&&Object.hasOwn(value,"currentInput"),"progress");function checkpointReferenceChild(value,children){const reference=value;if(!object(reference)||Object.keys(reference).some(key=>!["contextId","parentContextId","parentRound","order","target"].includes(key))||!text(reference.contextId)||!text(reference.parentContextId)||!integer(reference.parentRound,1)||!integer(reference.order)||!object(reference.target)||Object.keys(reference.target).length!==1||!integer(reference.target.position))return fail("invalid child reference");const child=children.find(entry=>entry.identity.contextId===reference.contextId);return!child||reference.parentContextId!==child.identity.parentContextId||reference.parentRound!==child.round||reference.order!==child.order||reference.target.position!==child.target.position?fail("child reference differs from its parent-owned relationship"):child}__name(checkpointReferenceChild,"checkpointReferenceChild");function checkpointReference(child){return child.identity.parentContextId?Object.freeze({contextId:child.identity.contextId,parentContextId:child.identity.parentContextId,parentRound:child.round,order:child.order,target:Object.freeze({position:child.target.position})}):fail("child reference requires parent identity")}__name(checkpointReference,"checkpointReference");function cloneCheckpointImage(value){if(value&&typeof value=="object"&&images.has(value))return value;const image=copyCheckpointValue(value).value;if(object(image)&&Number.isSafeInteger(image.formatVersion)&&image.formatVersion!==6)throw new RuntimeError("CHECKPOINT_FORMAT_UNSUPPORTED","Only checkpoint formatVersion 6 is supported; older checkpoint data is not migrated.",{formatVersion:image.formatVersion});(!object(image)||!text(image.id)||image.formatVersion!==6||!contract(image.contract)||!text(image.point)||!Object.hasOwn(image,"state")||!object(image.references))&&fail("invalid image; only checkpoint formatVersion 6 is supported");const frame=image.frame;(!object(frame)||!identity(frame.owner)||!integer(frame.round,1)||frame.round>2||frame.phase!=="execute"||!Object.hasOwn(frame,"input")||!Object.hasOwn(frame,"currentInput")||!integer(frame.nextChildOrder)||!Array.isArray(frame.children)||frame.children.length>4096)&&fail("invalid frame");const ids=new Set;let previousOrder=-1;for(const child of frame.children){(!object(child)||!identity(child.identity)||child.identity.parentContextId!==frame.owner.contextId||child.identity.contextId===frame.owner.contextId||ids.has(child.identity.contextId)||!integer(child.round,1)||child.round>frame.round||!integer(child.order)||child.order>=frame.nextChildOrder||child.order<=previousOrder||!Object.hasOwn(child,"input")||!object(child.target)||Object.keys(child.target).length!==1||!integer(child.target.position)||child.key!==void 0&&!text(child.key)||child.contract!==void 0&&!contract(child.contract))&&fail("invalid child identity, declaration position or order"),(frame.owner.kind==="node"?[]:["group","node"]).includes(child.identity.kind)||fail("invalid child structure kind");const state=child.state;if(object(state)||fail("invalid child state"),state.kind==="waiting")child.contract||fail("waiting child needs a resumable contract");else if(state.kind==="returned"){(!Object.hasOwn(state,"output")||!progress(state.progress)||!object(state.reception)||!["pending","receiving","accepted","failed"].includes(state.reception.kind))&&fail("invalid child reception");const receptionContract=state.reception.contract;if(receptionContract!==void 0&&(state.reception.kind==="pending"||!object(receptionContract)||Object.keys(receptionContract).length!==1||!integer(receptionContract.position))&&fail("invalid reception contract position"),state.reception.kind==="accepted"&&receptionContract!==void 0&&!Object.hasOwn(state.reception,"output")&&fail("contracted reception requires encoded output"),state.reception.kind==="failed"){const reception=state.reception,continuation2=frame.continuation;(child.round!==1||frame.round!==2||!object(reception.error)||!text(reception.error.code)||typeof reception.error.message!="string"||!object(reception.failure)||reception.failure.kind!=="exception"||reception.failure.contextId!==frame.owner.contextId||!text(reception.failure.contract)||!["execute","receive"].includes(reception.failure.phase)||continuation2?.stage!=="handling"||continuation2.origin?.kind!=="child-reception")&&fail("invalid handled child reception history"),checkpointReferenceChild(continuation2.origin.child,frame.children)!==child&&fail("reception failure is not the accepted continuation origin")}}else if(state.kind==="failed")if(state.reception!==void 0){const reception=state.reception;(!progress(state.progress)||!object(state.error)||!text(state.error.code)||typeof state.error.message!="string"||!object(state.failure)||!["error","exception"].includes(state.failure.kind)||!text(state.failure.contextId)||!["execute","receive","handling"].includes(state.failure.phase)||(state.failure.kind==="exception"?!text(state.failure.contract):state.failure.contract!==void 0)||Object.hasOwn(state,"output"))&&fail("invalid handled child failure"),(!object(reception)||reception.kind!=="handled"||Object.keys(reception).some(key=>!["kind","contract","output"].includes(key)))&&fail("invalid handled failure reception");const receptionContract=reception.contract;receptionContract!==void 0&&(!object(receptionContract)||Object.keys(receptionContract).length!==1||!integer(receptionContract.position)||!Object.hasOwn(reception,"output"))&&fail("invalid handled reception contract")}else(child.round>=frame.round||!progress(state.progress)||!object(state.error)||!text(state.error.code)||typeof state.error.message!="string"||!object(state.failure)||state.failure.kind!=="exception"||state.failure.contextId!==child.identity.contextId||!text(state.failure.contract)||!["execute","receive","handling"].includes(state.failure.phase))&&fail("invalid historical child failure");else fail("unsupported child state");ids.add(child.identity.contextId),previousOrder=child.order}const continuation=frame.continuation;if(frame.round===1&&continuation!==void 0&&fail("first round cannot have continuation"),frame.round===2&&continuation===void 0&&fail("second round requires accepted continuation"),continuation!==void 0){(!object(continuation)||Object.keys(continuation).some(key=>!["fromRound","stage","reason","origin"].includes(key))||continuation.fromRound!==1||!["accept","handling"].includes(continuation.stage)||!text(continuation.reason))&&fail("invalid continuation"),continuation.stage==="accept"&&continuation.origin!==void 0&&fail("acceptance continuation cannot have exception origin"),continuation.stage==="handling"&&!object(continuation.origin)&&fail("handled continuation needs exception origin");const origin=continuation.origin;if(origin?.kind==="self")(Object.keys(origin).some(key=>!["kind","phase"].includes(key))||!["execute","accept"].includes(origin.phase))&&fail("invalid self continuation origin");else if(origin!==void 0){(!object(origin)||Object.keys(origin).some(key=>!["kind","child"].includes(key))||!["child-return","child-reception"].includes(origin.kind))&&fail("invalid child continuation origin");const child=checkpointReferenceChild(origin.child,frame.children);child.round!==1&&fail("continuation origin must belong to preceding parent round"),origin.kind==="child-return"&&child.state.kind!=="failed"&&fail("child-return continuation needs failed child"),origin.kind==="child-reception"&&(child.state.kind!=="returned"||child.state.reception.kind!=="failed")&&fail("child-reception continuation needs failed reception")}}for(const value2 of Object.values(image.references))Array.isArray(value2)?value2.forEach(reference=>checkpointReferenceChild(reference,frame.children)):checkpointReferenceChild(value2,frame.children);const encoded=encodeCheckpointData(image);return Buffer.byteLength(encoded)>CHECKPOINT_MAX_BYTES&&fail("encoded image exceeds byte limit"),images.set(image,createHash("sha256").update(encoded).digest("hex")),image}__name(cloneCheckpointImage,"cloneCheckpointImage");function cloneCheckpointDelivery(value){if(value&&typeof value=="object"&&deliveries.has(value))return value;const delivery=copyCheckpointValue(value).value;(!object(delivery)||!["succeeded","failed","cancelled"].includes(delivery.status)||delivery.status==="succeeded"&&(!Object.hasOwn(delivery,"output")||!progress(delivery.progress)))&&fail("invalid delivery");const encoded=encodeCheckpointData(delivery);return Buffer.byteLength(encoded)>CHECKPOINT_MAX_BYTES&&fail("encoded delivery exceeds byte limit"),deliveries.set(delivery,createHash("sha256").update(encoded).digest("hex")),delivery}__name(cloneCheckpointDelivery,"cloneCheckpointDelivery");function checkpointImageDigest(image){return images.get(cloneCheckpointImage(image))}__name(checkpointImageDigest,"checkpointImageDigest");function checkpointDeliveryDigest(delivery){return deliveries.get(cloneCheckpointDelivery(delivery))}__name(checkpointDeliveryDigest,"checkpointDeliveryDigest");function cloneCheckpointHead(value){(!object(value)||Object.getPrototypeOf(value)!==Object.prototype&&Object.getPrototypeOf(value)!==null)&&fail("invalid head");const properties=Object.getOwnPropertyDescriptors(value);for(const key of Reflect.ownKeys(properties)){if(typeof key!="string"||!["revision","image","delivery","publication"].includes(key))return fail("invalid head property");const property=properties[key];(!("value"in property)||!property.enumerable)&&fail("accessor or hidden head property")}const revision=properties.revision?.value;if(typeof revision!="number"||!integer(revision,1)||!properties.image)return fail("invalid head revision or image");const image=cloneCheckpointImage(properties.image.value),publication=checkpointHeadCommit(value)??(properties.publication?checkCheckpointPublication(image,properties.publication.value):void 0),head=Object.freeze({revision,image,...properties.delivery?{delivery:cloneCheckpointDelivery(properties.delivery.value)}:{},...publication?{publication}:{}});return publication&&rememberCheckpointHead(head,publication),head}__name(cloneCheckpointHead,"cloneCheckpointHead");export{CHECKPOINT_MAX_BYTES,checkpointDeliveryDigest,checkpointImageDigest,checkpointReference,checkpointReferenceChild,cloneCheckpointDelivery,cloneCheckpointHead,cloneCheckpointImage,cloneCheckpointValue};
|
package/package.json
CHANGED
|
@@ -1,6 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weiliang0121/capix-checkpoint",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./storage": {
|
|
12
|
+
"types": "./dist/storage.d.ts",
|
|
13
|
+
"import": "./dist/storage.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"es-toolkit": "1.52.0",
|
|
18
|
+
"@weiliang0121/capix-contracts": "0.2.0"
|
|
19
|
+
},
|
|
20
|
+
"description": "Stable checkpoint facts, incremental storage, and recovery validation for CAPiX.",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"author": "wei.liang (https://github.com/weiliang0121)",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/weiliang0121/capix.git",
|
|
26
|
+
"directory": "packages/checkpoint"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=22.23.2"
|
|
30
|
+
},
|
|
31
|
+
"main": "./dist/index.js",
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"files": [
|
|
34
|
+
"dist/**/*.js",
|
|
35
|
+
"dist/**/*.d.ts",
|
|
36
|
+
"LICENSE",
|
|
37
|
+
"README.md"
|
|
38
|
+
],
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public",
|
|
41
|
+
"registry": "https://registry.npmjs.org"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsc -p tsconfig.json",
|
|
45
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
46
|
+
"test": "node ../../scripts/test/run.mjs --package ."
|
|
47
|
+
}
|
|
6
48
|
}
|