mustardscript 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -22
- package/SECURITY.md +1 -1
- package/dist/index.js +2 -0
- package/dist/lib/executor.js +16 -1
- package/dist/lib/policy.js +301 -22
- package/dist/lib/progress.js +499 -113
- package/dist/lib/runtime.js +109 -40
- package/dist/lib/structured.js +327 -11
- package/dist/native-loader.js +11 -12
- package/index.d.ts +54 -6
- package/mustard.d.ts +23 -1
- package/package.json +34 -25
- package/Cargo.lock +0 -1579
- package/Cargo.toml +0 -40
- package/crates/mustard/Cargo.toml +0 -31
- package/crates/mustard/src/cancellation.rs +0 -28
- package/crates/mustard/src/diagnostic.rs +0 -145
- package/crates/mustard/src/ir.rs +0 -435
- package/crates/mustard/src/lib.rs +0 -21
- package/crates/mustard/src/limits.rs +0 -22
- package/crates/mustard/src/parser/expressions.rs +0 -723
- package/crates/mustard/src/parser/mod.rs +0 -115
- package/crates/mustard/src/parser/operators.rs +0 -105
- package/crates/mustard/src/parser/patterns.rs +0 -123
- package/crates/mustard/src/parser/scope.rs +0 -107
- package/crates/mustard/src/parser/statements.rs +0 -298
- package/crates/mustard/src/parser/tests/acceptance.rs +0 -339
- package/crates/mustard/src/parser/tests/mod.rs +0 -2
- package/crates/mustard/src/parser/tests/rejections.rs +0 -107
- package/crates/mustard/src/runtime/accounting.rs +0 -613
- package/crates/mustard/src/runtime/api.rs +0 -192
- package/crates/mustard/src/runtime/async_runtime/mod.rs +0 -5
- package/crates/mustard/src/runtime/async_runtime/promises.rs +0 -246
- package/crates/mustard/src/runtime/async_runtime/reactions.rs +0 -400
- package/crates/mustard/src/runtime/async_runtime/scheduler.rs +0 -224
- package/crates/mustard/src/runtime/builtins/arrays.rs +0 -1205
- package/crates/mustard/src/runtime/builtins/collections.rs +0 -573
- package/crates/mustard/src/runtime/builtins/install.rs +0 -501
- package/crates/mustard/src/runtime/builtins/intl.rs +0 -553
- package/crates/mustard/src/runtime/builtins/mod.rs +0 -25
- package/crates/mustard/src/runtime/builtins/objects.rs +0 -405
- package/crates/mustard/src/runtime/builtins/primitives.rs +0 -859
- package/crates/mustard/src/runtime/builtins/promises.rs +0 -335
- package/crates/mustard/src/runtime/builtins/regexp.rs +0 -356
- package/crates/mustard/src/runtime/builtins/strings.rs +0 -803
- package/crates/mustard/src/runtime/builtins/support.rs +0 -561
- package/crates/mustard/src/runtime/bytecode.rs +0 -123
- package/crates/mustard/src/runtime/compiler/assignments.rs +0 -690
- package/crates/mustard/src/runtime/compiler/bindings.rs +0 -92
- package/crates/mustard/src/runtime/compiler/context.rs +0 -46
- package/crates/mustard/src/runtime/compiler/control.rs +0 -342
- package/crates/mustard/src/runtime/compiler/expressions.rs +0 -372
- package/crates/mustard/src/runtime/compiler/mod.rs +0 -173
- package/crates/mustard/src/runtime/compiler/statements.rs +0 -459
- package/crates/mustard/src/runtime/conversions/boundary.rs +0 -293
- package/crates/mustard/src/runtime/conversions/coercions.rs +0 -217
- package/crates/mustard/src/runtime/conversions/errors.rs +0 -118
- package/crates/mustard/src/runtime/conversions/mod.rs +0 -14
- package/crates/mustard/src/runtime/conversions/operators.rs +0 -334
- package/crates/mustard/src/runtime/env.rs +0 -355
- package/crates/mustard/src/runtime/exceptions.rs +0 -377
- package/crates/mustard/src/runtime/gc.rs +0 -595
- package/crates/mustard/src/runtime/mod.rs +0 -318
- package/crates/mustard/src/runtime/properties.rs +0 -1762
- package/crates/mustard/src/runtime/serialization.rs +0 -127
- package/crates/mustard/src/runtime/shared.rs +0 -108
- package/crates/mustard/src/runtime/snapshot_validation_tests.rs +0 -93
- package/crates/mustard/src/runtime/state.rs +0 -652
- package/crates/mustard/src/runtime/tests/async_host.rs +0 -104
- package/crates/mustard/src/runtime/tests/collections.rs +0 -50
- package/crates/mustard/src/runtime/tests/diagnostics.rs +0 -36
- package/crates/mustard/src/runtime/tests/exceptions.rs +0 -122
- package/crates/mustard/src/runtime/tests/execution.rs +0 -553
- package/crates/mustard/src/runtime/tests/gc.rs +0 -533
- package/crates/mustard/src/runtime/tests/mod.rs +0 -56
- package/crates/mustard/src/runtime/tests/serialization.rs +0 -170
- package/crates/mustard/src/runtime/validation/bytecode.rs +0 -484
- package/crates/mustard/src/runtime/validation/mod.rs +0 -14
- package/crates/mustard/src/runtime/validation/policy.rs +0 -94
- package/crates/mustard/src/runtime/validation/snapshot.rs +0 -406
- package/crates/mustard/src/runtime/validation/walk.rs +0 -206
- package/crates/mustard/src/runtime/vm.rs +0 -1016
- package/crates/mustard/src/span.rs +0 -22
- package/crates/mustard/src/structured.rs +0 -107
- package/crates/mustard-bridge/Cargo.toml +0 -17
- package/crates/mustard-bridge/src/codec.rs +0 -46
- package/crates/mustard-bridge/src/dto.rs +0 -99
- package/crates/mustard-bridge/src/lib.rs +0 -12
- package/crates/mustard-bridge/src/operations.rs +0 -142
- package/crates/mustard-node/Cargo.toml +0 -24
- package/crates/mustard-node/build.rs +0 -3
- package/crates/mustard-node/src/lib.rs +0 -236
- package/crates/mustard-sidecar/Cargo.toml +0 -21
- package/crates/mustard-sidecar/src/lib.rs +0 -134
- package/crates/mustard-sidecar/src/main.rs +0 -36
- package/dist/install.js +0 -117
package/dist/lib/progress.js
CHANGED
|
@@ -8,19 +8,23 @@ const { performance } = require('node:perf_hooks');
|
|
|
8
8
|
const { MustardError, callNative } = require('./errors.js');
|
|
9
9
|
const { getAbortSignal, withCancellationSignal } = require('./cancellation.js');
|
|
10
10
|
const {
|
|
11
|
+
assertSuspendedManifest,
|
|
11
12
|
cloneSnapshotPolicy,
|
|
12
13
|
cloneSnapshotKey,
|
|
14
|
+
createSuspendedManifest,
|
|
13
15
|
encodeSnapshotPolicy,
|
|
16
|
+
programIdentity,
|
|
14
17
|
resolveProgressLoadContext,
|
|
15
18
|
snapshotIdentity,
|
|
16
19
|
snapshotKeyDigest,
|
|
17
20
|
snapshotToken,
|
|
21
|
+
suspendedManifestToken,
|
|
18
22
|
} = require('./policy.js');
|
|
19
23
|
const {
|
|
20
24
|
decodeStructured,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
encodeResumePayloadCancelBuffer,
|
|
26
|
+
encodeResumePayloadErrorBuffer,
|
|
27
|
+
encodeResumePayloadValueBuffer,
|
|
24
28
|
} = require('./structured.js');
|
|
25
29
|
|
|
26
30
|
const SHARED_PROGRESS_REGISTRY_ROOT = path.join(
|
|
@@ -74,44 +78,63 @@ function singleUseRuntimeError() {
|
|
|
74
78
|
}
|
|
75
79
|
|
|
76
80
|
function releaseClaimedSnapshot(native, snapshotIdentityValue) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
} finally {
|
|
80
|
-
releaseSharedProgressSnapshot(snapshotIdentityValue);
|
|
81
|
-
}
|
|
81
|
+
void native;
|
|
82
|
+
releaseSharedProgressSnapshot(snapshotIdentityValue);
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
function claimSnapshotForLoad(native, snapshotIdentityValue) {
|
|
86
|
+
void native;
|
|
85
87
|
if (!claimSharedProgressSnapshot(snapshotIdentityValue)) {
|
|
86
88
|
throw singleUseRuntimeError();
|
|
87
89
|
}
|
|
88
|
-
try {
|
|
89
|
-
if (!callNative(native.claimProgressSnapshot, snapshotIdentityValue)) {
|
|
90
|
-
releaseSharedProgressSnapshot(snapshotIdentityValue);
|
|
91
|
-
throw singleUseRuntimeError();
|
|
92
|
-
}
|
|
93
|
-
} catch (error) {
|
|
94
|
-
if (!(error instanceof MustardError)) {
|
|
95
|
-
releaseSharedProgressSnapshot(snapshotIdentityValue);
|
|
96
|
-
}
|
|
97
|
-
throw error;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
90
|
return () => {
|
|
101
91
|
releaseClaimedSnapshot(native, snapshotIdentityValue);
|
|
102
92
|
};
|
|
103
93
|
}
|
|
104
94
|
|
|
105
95
|
function assertSnapshotNotUsed(native, snapshotIdentityValue) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
callNative(native.isProgressSnapshotUsed, snapshotIdentityValue)
|
|
109
|
-
) {
|
|
96
|
+
void native;
|
|
97
|
+
if (isSharedProgressSnapshotUsed(snapshotIdentityValue)) {
|
|
110
98
|
throw singleUseRuntimeError();
|
|
111
99
|
}
|
|
112
100
|
}
|
|
113
101
|
|
|
102
|
+
function isBinaryLike(value) {
|
|
103
|
+
return Buffer.isBuffer(value) || value instanceof Uint8Array;
|
|
104
|
+
}
|
|
105
|
+
|
|
114
106
|
function createProgressApi(native) {
|
|
107
|
+
const programHandleRegistry =
|
|
108
|
+
typeof FinalizationRegistry === 'function'
|
|
109
|
+
? new FinalizationRegistry((programHandle) => {
|
|
110
|
+
try {
|
|
111
|
+
callNative(native.releaseProgram, programHandle);
|
|
112
|
+
} catch {
|
|
113
|
+
// Best-effort cleanup only; process shutdown can race native teardown.
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
: null;
|
|
117
|
+
const snapshotHandleRegistry =
|
|
118
|
+
typeof FinalizationRegistry === 'function'
|
|
119
|
+
? new FinalizationRegistry((snapshotHandle) => {
|
|
120
|
+
try {
|
|
121
|
+
callNative(native.releaseSnapshotHandle, snapshotHandle);
|
|
122
|
+
} catch {
|
|
123
|
+
// Best-effort cleanup only; process shutdown can race native teardown.
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
: null;
|
|
127
|
+
|
|
128
|
+
function assertAuthorizedSuspendedCapability(policy, capability) {
|
|
129
|
+
if (policy.capabilities.includes(capability)) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
throw new MustardError(
|
|
133
|
+
'Serialization',
|
|
134
|
+
`snapshot policy rejected unauthorized capability \`${capability}\``,
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
115
138
|
class Progress {
|
|
116
139
|
constructor(
|
|
117
140
|
snapshot,
|
|
@@ -121,25 +144,173 @@ function createProgressApi(native) {
|
|
|
121
144
|
snapshotKey,
|
|
122
145
|
token = undefined,
|
|
123
146
|
claimState = 'unclaimed',
|
|
147
|
+
suspendedManifest = undefined,
|
|
148
|
+
suspendedManifestTokenValue = undefined,
|
|
149
|
+
programHandle = null,
|
|
150
|
+
program = undefined,
|
|
151
|
+
programId = undefined,
|
|
152
|
+
snapshotHandle = null,
|
|
153
|
+
snapshotId = undefined,
|
|
154
|
+
snapshotKeyBase64 = undefined,
|
|
155
|
+
snapshotKeyDigestValue = undefined,
|
|
124
156
|
) {
|
|
125
|
-
this
|
|
126
|
-
this
|
|
127
|
-
this
|
|
128
|
-
this
|
|
157
|
+
this.#capability = capability;
|
|
158
|
+
this.#args = structuredClone(args);
|
|
159
|
+
this.capability = this.#capability;
|
|
160
|
+
this.args = structuredClone(this.#args);
|
|
161
|
+
this.#snapshot =
|
|
162
|
+
snapshot === undefined || snapshot === null ? null : Buffer.from(snapshot);
|
|
163
|
+
this.#snapshotIdentity =
|
|
164
|
+
typeof snapshotId === 'string' && snapshotId.length > 0
|
|
165
|
+
? snapshotId
|
|
166
|
+
: this.#snapshot !== null
|
|
167
|
+
? snapshotIdentity(this.#snapshot)
|
|
168
|
+
: null;
|
|
129
169
|
this.#snapshotKey = cloneSnapshotKey(snapshotKey);
|
|
130
|
-
this.#
|
|
131
|
-
|
|
170
|
+
this.#snapshotKeyBase64 =
|
|
171
|
+
typeof snapshotKeyBase64 === 'string' && snapshotKeyBase64.length > 0
|
|
172
|
+
? snapshotKeyBase64
|
|
173
|
+
: this.#snapshotKey.toString('base64');
|
|
174
|
+
this.#snapshotKeyDigest =
|
|
175
|
+
typeof snapshotKeyDigestValue === 'string' && snapshotKeyDigestValue.length > 0
|
|
176
|
+
? snapshotKeyDigestValue
|
|
177
|
+
: snapshotKeyDigest(this.#snapshotKey);
|
|
178
|
+
this.#snapshotToken =
|
|
179
|
+
typeof token === 'string' && token.length > 0
|
|
180
|
+
? token
|
|
181
|
+
: this.#snapshot !== null
|
|
182
|
+
? snapshotToken(this.#snapshot, this.#snapshotKey, this.#snapshotIdentity)
|
|
183
|
+
: null;
|
|
184
|
+
this.#suspendedManifest =
|
|
185
|
+
suspendedManifest ?? createSuspendedManifest(this.#capability, this.#args);
|
|
186
|
+
this.#suspendedManifestToken =
|
|
187
|
+
typeof suspendedManifestTokenValue === 'string' && suspendedManifestTokenValue.length > 0
|
|
188
|
+
? suspendedManifestTokenValue
|
|
189
|
+
: this.#snapshotIdentity === null
|
|
190
|
+
? null
|
|
191
|
+
: suspendedManifestToken(
|
|
192
|
+
this.#snapshotIdentity,
|
|
193
|
+
this.#suspendedManifest,
|
|
194
|
+
this.#snapshotKey,
|
|
195
|
+
);
|
|
132
196
|
this.#policy = cloneSnapshotPolicy(policy);
|
|
197
|
+
this.#snapshotPolicyJson =
|
|
198
|
+
this.#snapshotIdentity === null || this.#snapshotToken === null
|
|
199
|
+
? null
|
|
200
|
+
: encodeSnapshotPolicy(this.#policy, {
|
|
201
|
+
snapshotId: this.#snapshotIdentity,
|
|
202
|
+
snapshotKeyBase64: this.#snapshotKeyBase64,
|
|
203
|
+
snapshotKeyDigest: this.#snapshotKeyDigest,
|
|
204
|
+
snapshotToken: this.#snapshotToken,
|
|
205
|
+
});
|
|
133
206
|
this.#claimState = claimState;
|
|
207
|
+
this.#program = program === undefined || program === null ? null : Buffer.from(program);
|
|
208
|
+
this.#programIdentity =
|
|
209
|
+
typeof programId === 'string' && programId.length > 0
|
|
210
|
+
? programId
|
|
211
|
+
: this.#program !== null
|
|
212
|
+
? programIdentity(this.#program)
|
|
213
|
+
: null;
|
|
214
|
+
this.#programHandle = null;
|
|
215
|
+
this.#programHandleToken = null;
|
|
216
|
+
if (typeof programHandle === 'string' && programHandle.length > 0) {
|
|
217
|
+
this.#programHandle = programHandle;
|
|
218
|
+
this.#programHandleToken = {};
|
|
219
|
+
programHandleRegistry?.register(this, programHandle, this.#programHandleToken);
|
|
220
|
+
}
|
|
221
|
+
this.#snapshotHandle = null;
|
|
222
|
+
this.#snapshotHandleToken = null;
|
|
223
|
+
if (typeof snapshotHandle === 'string' && snapshotHandle.length > 0) {
|
|
224
|
+
this.#snapshotHandle = snapshotHandle;
|
|
225
|
+
this.#snapshotHandleToken = {};
|
|
226
|
+
snapshotHandleRegistry?.register(this, snapshotHandle, this.#snapshotHandleToken);
|
|
227
|
+
}
|
|
134
228
|
}
|
|
135
229
|
|
|
230
|
+
#capability;
|
|
231
|
+
#args;
|
|
136
232
|
#snapshot;
|
|
137
233
|
#snapshotIdentity;
|
|
138
234
|
#snapshotKey;
|
|
235
|
+
#snapshotKeyBase64;
|
|
139
236
|
#snapshotKeyDigest;
|
|
140
237
|
#snapshotToken;
|
|
238
|
+
#suspendedManifest;
|
|
239
|
+
#suspendedManifestToken;
|
|
141
240
|
#policy;
|
|
241
|
+
#snapshotPolicyJson;
|
|
142
242
|
#claimState;
|
|
243
|
+
#program;
|
|
244
|
+
#programIdentity;
|
|
245
|
+
#programHandle;
|
|
246
|
+
#programHandleToken;
|
|
247
|
+
#snapshotHandle;
|
|
248
|
+
#snapshotHandleToken;
|
|
249
|
+
|
|
250
|
+
#clearSnapshotHandle() {
|
|
251
|
+
if (this.#snapshotHandleToken !== null) {
|
|
252
|
+
snapshotHandleRegistry?.unregister(this.#snapshotHandleToken);
|
|
253
|
+
}
|
|
254
|
+
this.#snapshotHandle = null;
|
|
255
|
+
this.#snapshotHandleToken = null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
#releaseSnapshotHandle() {
|
|
259
|
+
if (this.#snapshotHandle === null) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
const snapshotHandle = this.#snapshotHandle;
|
|
263
|
+
this.#clearSnapshotHandle();
|
|
264
|
+
try {
|
|
265
|
+
callNative(native.releaseSnapshotHandle, snapshotHandle);
|
|
266
|
+
} catch {
|
|
267
|
+
// Best-effort cleanup only.
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
#ensureSnapshotBytes() {
|
|
272
|
+
if (this.#snapshot !== null) {
|
|
273
|
+
return Buffer.from(this.#snapshot);
|
|
274
|
+
}
|
|
275
|
+
if (this.#snapshotHandle === null) {
|
|
276
|
+
throw singleUseRuntimeError();
|
|
277
|
+
}
|
|
278
|
+
this.#snapshot = Buffer.from(callNative(native.dumpSnapshotHandle, this.#snapshotHandle));
|
|
279
|
+
this.#snapshotIdentity ??= snapshotIdentity(this.#snapshot);
|
|
280
|
+
this.#snapshotToken ??= snapshotToken(
|
|
281
|
+
this.#snapshot,
|
|
282
|
+
this.#snapshotKey,
|
|
283
|
+
this.#snapshotIdentity,
|
|
284
|
+
);
|
|
285
|
+
this.#suspendedManifestToken ??= suspendedManifestToken(
|
|
286
|
+
this.#snapshotIdentity,
|
|
287
|
+
this.#suspendedManifest,
|
|
288
|
+
this.#snapshotKey,
|
|
289
|
+
);
|
|
290
|
+
this.#snapshotPolicyJson ??= encodeSnapshotPolicy(this.#policy, {
|
|
291
|
+
snapshotId: this.#snapshotIdentity,
|
|
292
|
+
snapshotKeyBase64: this.#snapshotKeyBase64,
|
|
293
|
+
snapshotKeyDigest: this.#snapshotKeyDigest,
|
|
294
|
+
snapshotToken: this.#snapshotToken,
|
|
295
|
+
});
|
|
296
|
+
return Buffer.from(this.#snapshot);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
#ensureSnapshotPolicyJson() {
|
|
300
|
+
if (this.#snapshotPolicyJson !== null) {
|
|
301
|
+
return this.#snapshotPolicyJson;
|
|
302
|
+
}
|
|
303
|
+
const snapshot = this.#ensureSnapshotBytes();
|
|
304
|
+
this.#snapshotIdentity ??= snapshotIdentity(snapshot);
|
|
305
|
+
this.#snapshotToken ??= snapshotToken(snapshot, this.#snapshotKey, this.#snapshotIdentity);
|
|
306
|
+
this.#snapshotPolicyJson = encodeSnapshotPolicy(this.#policy, {
|
|
307
|
+
snapshotId: this.#snapshotIdentity,
|
|
308
|
+
snapshotKeyBase64: this.#snapshotKeyBase64,
|
|
309
|
+
snapshotKeyDigest: this.#snapshotKeyDigest,
|
|
310
|
+
snapshotToken: this.#snapshotToken,
|
|
311
|
+
});
|
|
312
|
+
return this.#snapshotPolicyJson;
|
|
313
|
+
}
|
|
143
314
|
|
|
144
315
|
#consumeSnapshot() {
|
|
145
316
|
if (this.#claimState === 'consumed') {
|
|
@@ -152,34 +323,127 @@ function createProgressApi(native) {
|
|
|
152
323
|
if (!claimSharedProgressSnapshot(this.#snapshotIdentity)) {
|
|
153
324
|
throw singleUseRuntimeError();
|
|
154
325
|
}
|
|
155
|
-
try {
|
|
156
|
-
if (!callNative(native.claimProgressSnapshot, this.#snapshotIdentity)) {
|
|
157
|
-
releaseSharedProgressSnapshot(this.#snapshotIdentity);
|
|
158
|
-
throw singleUseRuntimeError();
|
|
159
|
-
}
|
|
160
|
-
} catch (error) {
|
|
161
|
-
if (!(error instanceof MustardError)) {
|
|
162
|
-
releaseSharedProgressSnapshot(this.#snapshotIdentity);
|
|
163
|
-
}
|
|
164
|
-
throw error;
|
|
165
|
-
}
|
|
166
326
|
this.#claimState = 'consumed';
|
|
167
327
|
return Buffer.from(this.#snapshot);
|
|
168
328
|
}
|
|
169
329
|
|
|
330
|
+
#consumeSnapshotHandle() {
|
|
331
|
+
if (this.#claimState === 'consumed') {
|
|
332
|
+
throw singleUseRuntimeError();
|
|
333
|
+
}
|
|
334
|
+
if (
|
|
335
|
+
this.#claimState === 'unclaimed' &&
|
|
336
|
+
this.#snapshotIdentity !== null &&
|
|
337
|
+
!claimSharedProgressSnapshot(this.#snapshotIdentity)
|
|
338
|
+
) {
|
|
339
|
+
throw singleUseRuntimeError();
|
|
340
|
+
}
|
|
341
|
+
if (this.#snapshotHandle === null) {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
const snapshotHandle = this.#snapshotHandle;
|
|
345
|
+
this.#clearSnapshotHandle();
|
|
346
|
+
this.#claimState = 'consumed';
|
|
347
|
+
return snapshotHandle;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
#ensureProgramHandle() {
|
|
351
|
+
if (this.#programHandle !== null) {
|
|
352
|
+
return this.#programHandle;
|
|
353
|
+
}
|
|
354
|
+
if (this.#program === null) {
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
const programHandle = callNative(native.loadProgram, Buffer.from(this.#program));
|
|
358
|
+
this.#programHandle = programHandle;
|
|
359
|
+
this.#programHandleToken = {};
|
|
360
|
+
programHandleRegistry?.register(this, programHandle, this.#programHandleToken);
|
|
361
|
+
return programHandle;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
#ensureProgramBytes() {
|
|
365
|
+
if (this.#program !== null) {
|
|
366
|
+
return Buffer.from(this.#program);
|
|
367
|
+
}
|
|
368
|
+
if (this.#programHandle === null) {
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
this.#program = Buffer.from(callNative(native.dumpProgram, this.#programHandle));
|
|
372
|
+
this.#programIdentity ??= programIdentity(this.#program);
|
|
373
|
+
return Buffer.from(this.#program);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
#resumeWithPayload(payload, signal) {
|
|
377
|
+
const programHandle = this.#ensureProgramHandle();
|
|
378
|
+
const snapshotHandle = this.#consumeSnapshotHandle();
|
|
379
|
+
if (snapshotHandle !== null) {
|
|
380
|
+
try {
|
|
381
|
+
const nativeArgs = [snapshotHandle, payload];
|
|
382
|
+
const step = parseStep(
|
|
383
|
+
signal === undefined
|
|
384
|
+
? callNative(native.resumeSnapshotHandleBuffer, ...nativeArgs)
|
|
385
|
+
: withCancellationSignal(
|
|
386
|
+
native,
|
|
387
|
+
native.resumeSnapshotHandleBuffer,
|
|
388
|
+
nativeArgs,
|
|
389
|
+
signal,
|
|
390
|
+
),
|
|
391
|
+
);
|
|
392
|
+
return materializeStep(step, this.#policy, this.#snapshotKey, programHandle, this.#program);
|
|
393
|
+
} finally {
|
|
394
|
+
try {
|
|
395
|
+
callNative(native.releaseSnapshotHandle, snapshotHandle);
|
|
396
|
+
} catch {
|
|
397
|
+
// Best-effort cleanup only.
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const snapshot = this.#consumeSnapshot();
|
|
403
|
+
const policyJson = this.#ensureSnapshotPolicyJson();
|
|
404
|
+
const nativeResume =
|
|
405
|
+
programHandle === null ? native.resumeProgram : native.resumeDetachedProgram;
|
|
406
|
+
const nativeArgs =
|
|
407
|
+
programHandle === null
|
|
408
|
+
? [snapshot, payload, policyJson]
|
|
409
|
+
: [programHandle, snapshot, payload, policyJson];
|
|
410
|
+
const step = parseStep(
|
|
411
|
+
signal === undefined
|
|
412
|
+
? callNative(nativeResume, ...nativeArgs)
|
|
413
|
+
: withCancellationSignal(native, nativeResume, nativeArgs, signal),
|
|
414
|
+
);
|
|
415
|
+
return materializeStep(step, this.#policy, this.#snapshotKey, programHandle, this.#program);
|
|
416
|
+
}
|
|
417
|
+
|
|
170
418
|
get snapshot() {
|
|
171
|
-
return
|
|
419
|
+
return this.#ensureSnapshotBytes();
|
|
172
420
|
}
|
|
173
421
|
|
|
174
422
|
dump() {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
423
|
+
const snapshot = this.#ensureSnapshotBytes();
|
|
424
|
+
this.#snapshotIdentity ??= snapshotIdentity(snapshot);
|
|
425
|
+
this.#snapshotToken ??= snapshotToken(snapshot, this.#snapshotKey, this.#snapshotIdentity);
|
|
426
|
+
this.#suspendedManifestToken ??= suspendedManifestToken(
|
|
427
|
+
this.#snapshotIdentity,
|
|
428
|
+
this.#suspendedManifest,
|
|
429
|
+
this.#snapshotKey,
|
|
430
|
+
);
|
|
431
|
+
const dumped = {
|
|
432
|
+
capability: this.#capability,
|
|
433
|
+
args: structuredClone(this.#args),
|
|
434
|
+
snapshot,
|
|
179
435
|
snapshot_id: this.#snapshotIdentity,
|
|
180
436
|
snapshot_key_digest: this.#snapshotKeyDigest,
|
|
181
437
|
token: this.#snapshotToken,
|
|
438
|
+
suspended_manifest: this.#suspendedManifest,
|
|
439
|
+
suspended_manifest_token: this.#suspendedManifestToken,
|
|
182
440
|
};
|
|
441
|
+
const program = this.#ensureProgramBytes();
|
|
442
|
+
if (program !== null) {
|
|
443
|
+
dumped.program = program;
|
|
444
|
+
dumped.program_id = this.#programIdentity ?? programIdentity(program);
|
|
445
|
+
}
|
|
446
|
+
return dumped;
|
|
183
447
|
}
|
|
184
448
|
|
|
185
449
|
resume(value, options = undefined) {
|
|
@@ -187,21 +451,7 @@ function createProgressApi(native) {
|
|
|
187
451
|
if (signal?.aborted) {
|
|
188
452
|
return this.cancel();
|
|
189
453
|
}
|
|
190
|
-
|
|
191
|
-
const policyJson = encodeSnapshotPolicy(this.#policy, {
|
|
192
|
-
snapshotId: this.#snapshotIdentity,
|
|
193
|
-
snapshotKey: this.#snapshotKey,
|
|
194
|
-
snapshotToken: this.#snapshotToken,
|
|
195
|
-
});
|
|
196
|
-
const step = parseStep(
|
|
197
|
-
withCancellationSignal(
|
|
198
|
-
native,
|
|
199
|
-
native.resumeProgram,
|
|
200
|
-
[this.#consumeSnapshot(), payload, policyJson],
|
|
201
|
-
signal,
|
|
202
|
-
),
|
|
203
|
-
);
|
|
204
|
-
return materializeStep(step, this.#policy, this.#snapshotKey);
|
|
454
|
+
return this.#resumeWithPayload(encodeResumePayloadValueBuffer(value), signal);
|
|
205
455
|
}
|
|
206
456
|
|
|
207
457
|
resumeError(error, options = undefined) {
|
|
@@ -209,38 +459,11 @@ function createProgressApi(native) {
|
|
|
209
459
|
if (signal?.aborted) {
|
|
210
460
|
return this.cancel();
|
|
211
461
|
}
|
|
212
|
-
|
|
213
|
-
const policyJson = encodeSnapshotPolicy(this.#policy, {
|
|
214
|
-
snapshotId: this.#snapshotIdentity,
|
|
215
|
-
snapshotKey: this.#snapshotKey,
|
|
216
|
-
snapshotToken: this.#snapshotToken,
|
|
217
|
-
});
|
|
218
|
-
const step = parseStep(
|
|
219
|
-
withCancellationSignal(
|
|
220
|
-
native,
|
|
221
|
-
native.resumeProgram,
|
|
222
|
-
[this.#consumeSnapshot(), payload, policyJson],
|
|
223
|
-
signal,
|
|
224
|
-
),
|
|
225
|
-
);
|
|
226
|
-
return materializeStep(step, this.#policy, this.#snapshotKey);
|
|
462
|
+
return this.#resumeWithPayload(encodeResumePayloadErrorBuffer(error), signal);
|
|
227
463
|
}
|
|
228
464
|
|
|
229
465
|
cancel() {
|
|
230
|
-
|
|
231
|
-
snapshotId: this.#snapshotIdentity,
|
|
232
|
-
snapshotKey: this.#snapshotKey,
|
|
233
|
-
snapshotToken: this.#snapshotToken,
|
|
234
|
-
});
|
|
235
|
-
const step = parseStep(
|
|
236
|
-
callNative(
|
|
237
|
-
native.resumeProgram,
|
|
238
|
-
this.#consumeSnapshot(),
|
|
239
|
-
encodeResumePayloadCancel(),
|
|
240
|
-
policyJson,
|
|
241
|
-
),
|
|
242
|
-
);
|
|
243
|
-
return materializeStep(step, this.#policy, this.#snapshotKey);
|
|
466
|
+
return this.#resumeWithPayload(encodeResumePayloadCancelBuffer(), undefined);
|
|
244
467
|
}
|
|
245
468
|
|
|
246
469
|
static load(state, options = undefined) {
|
|
@@ -282,30 +505,168 @@ function createProgressApi(native) {
|
|
|
282
505
|
'Progress.load() rejected a tampered or unauthenticated snapshot',
|
|
283
506
|
);
|
|
284
507
|
}
|
|
508
|
+
|
|
509
|
+
let dumpedProgram;
|
|
510
|
+
let dumpedProgramId;
|
|
511
|
+
if (state.program !== undefined) {
|
|
512
|
+
if (!isBinaryLike(state.program)) {
|
|
513
|
+
throw new TypeError('Progress.load() requires dumped program bytes as Buffer or Uint8Array');
|
|
514
|
+
}
|
|
515
|
+
if (typeof state.program_id !== 'string' || state.program_id.length === 0) {
|
|
516
|
+
throw new TypeError(
|
|
517
|
+
'Progress.load() requires dumped program_id metadata when program bytes are present',
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
dumpedProgram = Buffer.from(state.program);
|
|
521
|
+
dumpedProgramId = programIdentity(dumpedProgram);
|
|
522
|
+
if (dumpedProgramId !== state.program_id) {
|
|
523
|
+
throw new MustardError(
|
|
524
|
+
'Serialization',
|
|
525
|
+
'Progress.load() rejected a tampered or mismatched detached program',
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
285
530
|
assertSnapshotNotUsed(native, snapshotIdentityValue);
|
|
286
|
-
const context = resolveProgressLoadContext(
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
531
|
+
const context = resolveProgressLoadContext(
|
|
532
|
+
state,
|
|
533
|
+
snapshot,
|
|
534
|
+
options,
|
|
535
|
+
snapshotIdentityValue,
|
|
536
|
+
);
|
|
537
|
+
const suspendedManifest = assertSuspendedManifest(
|
|
538
|
+
state,
|
|
539
|
+
context.snapshotKey,
|
|
540
|
+
snapshotIdentityValue,
|
|
541
|
+
);
|
|
542
|
+
const nativeContextHandle =
|
|
543
|
+
typeof context.nativeContextHandle === 'string' && context.nativeContextHandle.length > 0
|
|
544
|
+
? context.nativeContextHandle
|
|
545
|
+
: null;
|
|
546
|
+
const policyJson =
|
|
547
|
+
nativeContextHandle === null
|
|
548
|
+
? encodeSnapshotPolicy(context.policy, {
|
|
294
549
|
snapshotId: state.snapshot_id,
|
|
295
550
|
snapshotKey: context.snapshotKey,
|
|
551
|
+
snapshotKeyBase64: context.snapshotKeyBase64,
|
|
552
|
+
snapshotKeyDigest: context.snapshotKeyDigest,
|
|
296
553
|
snapshotToken: state.token,
|
|
297
|
-
})
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
554
|
+
})
|
|
555
|
+
: null;
|
|
556
|
+
const releaseClaim = claimSnapshotForLoad(native, snapshotIdentityValue);
|
|
557
|
+
try {
|
|
558
|
+
let loadedProgramHandle = null;
|
|
559
|
+
let snapshotHandle = null;
|
|
560
|
+
const loadSnapshotHandle = () => {
|
|
561
|
+
if (dumpedProgram === undefined) {
|
|
562
|
+
return nativeContextHandle === null
|
|
563
|
+
? callNative(native.loadSnapshotHandle, snapshot, policyJson)
|
|
564
|
+
: callNative(
|
|
565
|
+
native.loadSnapshotHandleWithExecutionContext,
|
|
566
|
+
nativeContextHandle,
|
|
567
|
+
snapshot,
|
|
568
|
+
state.snapshot_id,
|
|
569
|
+
context.snapshotKeyBase64,
|
|
570
|
+
context.snapshotKeyDigest,
|
|
571
|
+
state.token,
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
loadedProgramHandle = callNative(native.loadProgram, Buffer.from(dumpedProgram));
|
|
575
|
+
return nativeContextHandle === null
|
|
576
|
+
? callNative(
|
|
577
|
+
native.loadDetachedSnapshotHandle,
|
|
578
|
+
loadedProgramHandle,
|
|
579
|
+
snapshot,
|
|
580
|
+
policyJson,
|
|
581
|
+
)
|
|
582
|
+
: callNative(
|
|
583
|
+
native.loadDetachedSnapshotHandleWithExecutionContext,
|
|
584
|
+
loadedProgramHandle,
|
|
585
|
+
nativeContextHandle,
|
|
586
|
+
snapshot,
|
|
587
|
+
state.snapshot_id,
|
|
588
|
+
context.snapshotKeyBase64,
|
|
589
|
+
context.snapshotKeyDigest,
|
|
590
|
+
state.token,
|
|
591
|
+
);
|
|
592
|
+
};
|
|
593
|
+
if (suspendedManifest !== null) {
|
|
594
|
+
assertAuthorizedSuspendedCapability(
|
|
595
|
+
context.policy,
|
|
596
|
+
suspendedManifest.capability,
|
|
597
|
+
);
|
|
598
|
+
try {
|
|
599
|
+
snapshotHandle = loadSnapshotHandle();
|
|
600
|
+
} catch (error) {
|
|
601
|
+
if (loadedProgramHandle !== null) {
|
|
602
|
+
try {
|
|
603
|
+
callNative(native.releaseProgram, loadedProgramHandle);
|
|
604
|
+
} catch {
|
|
605
|
+
// Best-effort cleanup only.
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
throw error;
|
|
609
|
+
}
|
|
610
|
+
return new Progress(
|
|
611
|
+
snapshot,
|
|
612
|
+
suspendedManifest.capability,
|
|
613
|
+
suspendedManifest.args,
|
|
614
|
+
context.policy,
|
|
615
|
+
context.snapshotKey,
|
|
616
|
+
state.token,
|
|
617
|
+
'claimed',
|
|
618
|
+
state.suspended_manifest,
|
|
619
|
+
state.suspended_manifest_token,
|
|
620
|
+
loadedProgramHandle,
|
|
621
|
+
dumpedProgram,
|
|
622
|
+
dumpedProgramId,
|
|
623
|
+
snapshotHandle,
|
|
624
|
+
state.snapshot_id,
|
|
625
|
+
context.snapshotKeyBase64,
|
|
626
|
+
context.snapshotKeyDigest,
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
try {
|
|
631
|
+
snapshotHandle = loadSnapshotHandle();
|
|
632
|
+
const inspection = parseSnapshotInspection(
|
|
633
|
+
callNative(native.inspectSnapshotHandle, snapshotHandle),
|
|
634
|
+
);
|
|
635
|
+
return new Progress(
|
|
636
|
+
snapshot,
|
|
637
|
+
inspection.capability,
|
|
638
|
+
inspection.args,
|
|
639
|
+
context.policy,
|
|
640
|
+
context.snapshotKey,
|
|
641
|
+
state.token,
|
|
642
|
+
'claimed',
|
|
643
|
+
undefined,
|
|
644
|
+
undefined,
|
|
645
|
+
loadedProgramHandle,
|
|
646
|
+
dumpedProgram,
|
|
647
|
+
dumpedProgramId,
|
|
648
|
+
snapshotHandle,
|
|
649
|
+
state.snapshot_id,
|
|
650
|
+
context.snapshotKeyBase64,
|
|
651
|
+
context.snapshotKeyDigest,
|
|
652
|
+
);
|
|
653
|
+
} catch (error) {
|
|
654
|
+
if (snapshotHandle !== null) {
|
|
655
|
+
try {
|
|
656
|
+
callNative(native.releaseSnapshotHandle, snapshotHandle);
|
|
657
|
+
} catch {
|
|
658
|
+
// Best-effort cleanup only.
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
if (loadedProgramHandle !== null) {
|
|
662
|
+
try {
|
|
663
|
+
callNative(native.releaseProgram, loadedProgramHandle);
|
|
664
|
+
} catch {
|
|
665
|
+
// Best-effort cleanup only.
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
throw error;
|
|
669
|
+
}
|
|
309
670
|
} catch (error) {
|
|
310
671
|
releaseClaim();
|
|
311
672
|
throw error;
|
|
@@ -325,7 +686,14 @@ function createProgressApi(native) {
|
|
|
325
686
|
type: 'suspended',
|
|
326
687
|
capability: step.capability,
|
|
327
688
|
args: step.args.map(decodeStructured),
|
|
328
|
-
snapshot:
|
|
689
|
+
snapshot:
|
|
690
|
+
typeof step.snapshot_base64 === 'string'
|
|
691
|
+
? Buffer.from(step.snapshot_base64, 'base64')
|
|
692
|
+
: null,
|
|
693
|
+
snapshotHandle:
|
|
694
|
+
typeof step.snapshot_handle === 'string' && step.snapshot_handle.length > 0
|
|
695
|
+
? step.snapshot_handle
|
|
696
|
+
: null,
|
|
329
697
|
};
|
|
330
698
|
}
|
|
331
699
|
|
|
@@ -337,11 +705,29 @@ function createProgressApi(native) {
|
|
|
337
705
|
};
|
|
338
706
|
}
|
|
339
707
|
|
|
340
|
-
function materializeStep(step, policy, snapshotKey) {
|
|
708
|
+
function materializeStep(step, policy, snapshotKey, programHandle = null, program = undefined) {
|
|
341
709
|
if (step.type === 'completed') {
|
|
342
710
|
return step.value;
|
|
343
711
|
}
|
|
344
|
-
|
|
712
|
+
let ownedProgramHandle = null;
|
|
713
|
+
if (typeof programHandle === 'string' && programHandle.length > 0) {
|
|
714
|
+
ownedProgramHandle = callNative(native.retainProgram, programHandle);
|
|
715
|
+
}
|
|
716
|
+
return new Progress(
|
|
717
|
+
step.snapshot,
|
|
718
|
+
step.capability,
|
|
719
|
+
step.args,
|
|
720
|
+
policy,
|
|
721
|
+
snapshotKey,
|
|
722
|
+
undefined,
|
|
723
|
+
'unclaimed',
|
|
724
|
+
undefined,
|
|
725
|
+
undefined,
|
|
726
|
+
ownedProgramHandle,
|
|
727
|
+
program,
|
|
728
|
+
undefined,
|
|
729
|
+
step.snapshotHandle,
|
|
730
|
+
);
|
|
345
731
|
}
|
|
346
732
|
|
|
347
733
|
return {
|