poe-code 4.0.69 → 4.0.70
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/dist/index.js +33 -6
- package/dist/index.js.map +2 -2
- package/dist/metafile.json +1 -1
- package/package.json +1 -1
- package/packages/safejs/dist/random.js +4 -3
- package/packages/safejs/dist/run.d.ts +2 -1
- package/packages/safejs/dist/run.js +18 -2
- package/packages/safejs/dist/snapshot/dump-format.js +7 -0
- package/packages/safejs/dist/snapshot/dump.js +6 -1
- package/packages/safejs/dist/snapshot/replay-data.d.ts +2 -0
- package/packages/safejs/dist/snapshot/replay-data.js +4 -2
- package/packages/safejs/dist/snapshot/validation.js +7 -0
package/package.json
CHANGED
|
@@ -8,9 +8,10 @@ export function createReplayableRandom(options = {}) {
|
|
|
8
8
|
const hasLoopState = typeof snapshot?.loopIterations === "object" &&
|
|
9
9
|
snapshot.loopIterations !== null &&
|
|
10
10
|
Object.keys(snapshot.loopIterations).length > 0;
|
|
11
|
-
const replaysFromStart =
|
|
12
|
-
snapshot
|
|
13
|
-
|
|
11
|
+
const replaysFromStart = snapshot?.replay !== undefined ||
|
|
12
|
+
(Array.isArray(snapshot?.pendingAwaits) &&
|
|
13
|
+
snapshot.pendingAwaits.length > 0 &&
|
|
14
|
+
!hasLoopState);
|
|
14
15
|
initialState = replaysFromStart
|
|
15
16
|
? (saved.initialState ?? saved.seed)
|
|
16
17
|
: (saved.resumeState ?? saved.state);
|
|
@@ -10,7 +10,7 @@ import { type InterpreterResult, type LoopIterationSnapshot } from "./interp/int
|
|
|
10
10
|
import { type ModuleRegistry } from "./modules/registry.js";
|
|
11
11
|
import { type OtelSink } from "./observability/otel.js";
|
|
12
12
|
import type { SnapshotBackend } from "./snapshot/backend.js";
|
|
13
|
-
import type
|
|
13
|
+
import { type ReplayData } from "./snapshot/replay-data.js";
|
|
14
14
|
export type RunOptions = {
|
|
15
15
|
bindings?: Record<string, CallerInjectedBinding>;
|
|
16
16
|
budget?: Budget;
|
|
@@ -39,6 +39,7 @@ export type RunSnapshot = SafeJSSnapshot & {
|
|
|
39
39
|
clock?: RunClockSnapshot;
|
|
40
40
|
hostCalls?: HostCallRecord[];
|
|
41
41
|
replay?: HostCallReplay;
|
|
42
|
+
replayError?: string;
|
|
42
43
|
promiseReplay?: PromiseReplaySnapshot;
|
|
43
44
|
initialInputs?: ReplayData;
|
|
44
45
|
loopIterations?: Record<string, LoopIterationSnapshot>;
|
|
@@ -27,6 +27,7 @@ import { DUMP_FORMAT_VERSION } from "./snapshot/dump-format.js";
|
|
|
27
27
|
import { createSnapshotScheduler } from "./snapshot/scheduler.js";
|
|
28
28
|
import { UnsnapshotableValueError } from "./snapshot/serialize.js";
|
|
29
29
|
import { prepareReplayInputs } from "./snapshot/replay-inputs.js";
|
|
30
|
+
import { MissingReplayCapabilityError } from "./snapshot/replay-data.js";
|
|
30
31
|
export class UnhandledRejectionError extends Error {
|
|
31
32
|
reason;
|
|
32
33
|
constructor(reason, span) {
|
|
@@ -248,17 +249,32 @@ export function run(source, options = {}) {
|
|
|
248
249
|
scope: executionScope,
|
|
249
250
|
snapshot: interpreterSnapshot
|
|
250
251
|
});
|
|
252
|
+
await throwIfReturnedPromiseRejected(result);
|
|
253
|
+
await throwIfUnhandledPromiseRejected(promiseTracker);
|
|
251
254
|
await activeSnapshotScheduler.finish();
|
|
255
|
+
let replay;
|
|
256
|
+
let replayError;
|
|
257
|
+
try {
|
|
258
|
+
replay = hostCalls.snapshotReplay();
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
if (!(error instanceof MissingReplayCapabilityError))
|
|
262
|
+
throw error;
|
|
263
|
+
replayError = error.message;
|
|
264
|
+
}
|
|
252
265
|
const snapshot = createRunSnapshot({
|
|
253
266
|
bindings: executionScope.snapshot().bindings,
|
|
254
267
|
clock: options.clock,
|
|
255
268
|
hostCalls: hostCalls.snapshot(),
|
|
269
|
+
replay,
|
|
270
|
+
initialInputs: initialInputs.snapshot,
|
|
271
|
+
promiseReplay: promiseReplay.snapshot(),
|
|
256
272
|
random,
|
|
257
273
|
sourceHash
|
|
258
274
|
});
|
|
275
|
+
if (replayError !== undefined)
|
|
276
|
+
snapshot.replayError = replayError;
|
|
259
277
|
dumpController.finalize(snapshot);
|
|
260
|
-
await throwIfReturnedPromiseRejected(result);
|
|
261
|
-
await throwIfUnhandledPromiseRejected(promiseTracker);
|
|
262
278
|
return {
|
|
263
279
|
...result,
|
|
264
280
|
snapshot
|
|
@@ -4,6 +4,13 @@ import { getSandboxArgumentEntries, isSandboxArguments } from "../interp/argumen
|
|
|
4
4
|
import { serializeArguments } from "./arguments.js";
|
|
5
5
|
const SKIP_VALUE = Symbol("SafeJS.skip-dump-value");
|
|
6
6
|
export function serializeSafeJSSnapshot(snapshot) {
|
|
7
|
+
const replayError = Object.getOwnPropertyDescriptor(snapshot, "replayError");
|
|
8
|
+
if (replayError !== undefined) {
|
|
9
|
+
const reason = "value" in replayError && typeof replayError.value === "string"
|
|
10
|
+
? replayError.value
|
|
11
|
+
: "missing resume capability";
|
|
12
|
+
throw new TypeError(`Snapshot is not replayable: ${reason}`);
|
|
13
|
+
}
|
|
7
14
|
for (const [key, value] of getEnumerableDataEntries(snapshot)) {
|
|
8
15
|
if (key !== "version" && key !== "sourceHash" && key !== "heap") {
|
|
9
16
|
assertSnapshotGraphDepth(value, key);
|
|
@@ -140,7 +140,12 @@ export function dump(result) {
|
|
|
140
140
|
return controller.requestSnapshot();
|
|
141
141
|
}
|
|
142
142
|
if (hasSnapshot(result)) {
|
|
143
|
-
|
|
143
|
+
try {
|
|
144
|
+
return Promise.resolve(serializeRunSnapshot(result.snapshot));
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
return Promise.reject(error);
|
|
148
|
+
}
|
|
144
149
|
}
|
|
145
150
|
return Promise.resolve(result).then((resolved) => {
|
|
146
151
|
if (!hasSnapshot(resolved)) {
|
|
@@ -49,6 +49,8 @@ export type ReplayData = {
|
|
|
49
49
|
root: Atom;
|
|
50
50
|
nodes: DataNode[];
|
|
51
51
|
};
|
|
52
|
+
export declare class MissingReplayCapabilityError extends TypeError {
|
|
53
|
+
}
|
|
52
54
|
export declare function encodeReplayData(value: SandboxValue, options?: {
|
|
53
55
|
identifyCapability?: (value: SandboxClosure, path: readonly string[]) => string | undefined;
|
|
54
56
|
captureCapabilityProperties?: boolean;
|
|
@@ -2,6 +2,8 @@ import { MAX_DATA_DEPTH } from "../graph-depth.js";
|
|
|
2
2
|
import { createSandboxArguments, createSandboxClosure, createSandboxMap, createSandboxRegex, createSandboxSet, isSandboxArguments, isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, isSandboxRegex, isSandboxSet } from "../interp/values.js";
|
|
3
3
|
import { serializeArguments } from "./arguments.js";
|
|
4
4
|
import { validateArgumentsProperties, validateSnapshotData } from "./validation.js";
|
|
5
|
+
export class MissingReplayCapabilityError extends TypeError {
|
|
6
|
+
}
|
|
5
7
|
export function encodeReplayData(value, options = {}) {
|
|
6
8
|
const nodes = [];
|
|
7
9
|
const seen = new WeakMap();
|
|
@@ -31,12 +33,12 @@ export function encodeReplayData(value, options = {}) {
|
|
|
31
33
|
if (isSandboxClosure(entry)) {
|
|
32
34
|
capabilityId = options.identifyCapability?.(entry, path);
|
|
33
35
|
if (typeof capabilityId !== "string" || capabilityId.length === 0)
|
|
34
|
-
throw new
|
|
36
|
+
throw new MissingReplayCapabilityError("A callable needs an explicit resume capability.");
|
|
35
37
|
if (!options.captureCapabilityProperties)
|
|
36
38
|
return { tag: "capability", id: capabilityId };
|
|
37
39
|
}
|
|
38
40
|
if (typeof entry !== "object" || isSandboxPromise(entry) || isSandboxGenerator(entry)) {
|
|
39
|
-
throw new
|
|
41
|
+
throw new MissingReplayCapabilityError("A host result containing a callable or live execution state needs an explicit resume capability.");
|
|
40
42
|
}
|
|
41
43
|
const existing = seen.get(entry);
|
|
42
44
|
if (existing !== undefined)
|
|
@@ -50,6 +50,13 @@ export function validateDumpEnvelope(snapshot) {
|
|
|
50
50
|
fail("unsupportedVersion", "$.version", `expected ${DUMP_FORMAT_VERSION}`);
|
|
51
51
|
}
|
|
52
52
|
requireNonEmptyString(root.sourceHash, "$.sourceHash", limits);
|
|
53
|
+
const replayError = Object.getOwnPropertyDescriptor(root, "replayError");
|
|
54
|
+
if (replayError !== undefined) {
|
|
55
|
+
if (!("value" in replayError))
|
|
56
|
+
fail("invalidType", "$.replayError", "must be a data property");
|
|
57
|
+
const reason = requireNonEmptyString(replayError.value, "$.replayError", limits);
|
|
58
|
+
fail("invalidState", "$.replayError", `snapshot is not replayable: ${reason}`);
|
|
59
|
+
}
|
|
53
60
|
const state = {
|
|
54
61
|
allowFunctions: true,
|
|
55
62
|
allowUndefined: true,
|