poe-code 14.0.80 → 14.0.82
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 +876 -404
- package/dist/index.js.map +4 -4
- package/dist/metafile.json +1 -1
- package/package.json +1 -1
- package/packages/safe-js/dist/chunks/{chunk-34G5WW2O.js → chunk-7LGBDF56.js} +2 -2
- package/packages/safe-js/dist/chunks/{chunk-M4L3EZHL.js → chunk-V6LQP64H.js} +733 -334
- package/packages/safe-js/dist/chunks/chunk-V6LQP64H.js.map +7 -0
- package/packages/safe-js/dist/cli.js +2 -2
- package/packages/safe-js/dist/core.js +1 -1
- package/packages/safe-js/dist/index.js +2 -2
- package/packages/safe-js/dist/interp/async.d.ts +1 -1
- package/packages/safe-js/dist/interp/async.js +65 -43
- package/packages/safe-js/dist/interp/bound-function-state.d.ts +7 -0
- package/packages/safe-js/dist/interp/bound-function-state.js +1 -0
- package/packages/safe-js/dist/interp/bound-function.d.ts +4 -0
- package/packages/safe-js/dist/interp/bound-function.js +18 -0
- package/packages/safe-js/dist/interp/error-prototypes.d.ts +3 -0
- package/packages/safe-js/dist/interp/error-prototypes.js +1 -0
- package/packages/safe-js/dist/interp/exceptions.d.ts +1 -0
- package/packages/safe-js/dist/interp/exceptions.js +39 -15
- package/packages/safe-js/dist/interp/generator-prototypes.d.ts +6 -0
- package/packages/safe-js/dist/interp/generator-prototypes.js +1 -0
- package/packages/safe-js/dist/interp/globals/error.d.ts +2 -0
- package/packages/safe-js/dist/interp/globals/error.js +104 -4
- package/packages/safe-js/dist/interp/globals/function.d.ts +1 -1
- package/packages/safe-js/dist/interp/globals/function.js +10 -2
- package/packages/safe-js/dist/interp/globals/generator.d.ts +2 -0
- package/packages/safe-js/dist/interp/globals/generator.js +51 -0
- package/packages/safe-js/dist/interp/globals/object-array.js +19 -1
- package/packages/safe-js/dist/interp/globals.d.ts +2 -0
- package/packages/safe-js/dist/interp/globals.js +7 -3
- package/packages/safe-js/dist/interp/host-bridge.js +4 -2
- package/packages/safe-js/dist/interp/instanceof.d.ts +4 -0
- package/packages/safe-js/dist/interp/instanceof.js +59 -0
- package/packages/safe-js/dist/interp/interpreter.js +3 -40
- package/packages/safe-js/dist/interp/iteration.js +44 -6
- package/packages/safe-js/dist/interp/methods/function.d.ts +1 -1
- package/packages/safe-js/dist/interp/methods/function.js +53 -40
- package/packages/safe-js/dist/interp/methods/generator.d.ts +4 -1
- package/packages/safe-js/dist/interp/methods/generator.js +12 -6
- package/packages/safe-js/dist/interp/object-model.js +13 -0
- package/packages/safe-js/dist/interp/values.js +47 -2
- package/packages/safe-js/dist/snapshot/guest-heap-validation.js +28 -3
- package/packages/safe-js/dist/snapshot/guest-heap.d.ts +10 -0
- package/packages/safe-js/dist/snapshot/guest-heap.js +13 -2
- package/packages/safe-js/dist/snapshot/restore.js +69 -8
- package/packages/safe-js/dist/snapshot/validation.js +1 -1
- package/packages/safe-js/dist/chunks/chunk-M4L3EZHL.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-34G5WW2O.js.map → chunk-7LGBDF56.js.map} +0 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Budget } from "../interp/budget.js";
|
|
2
|
+
import { sandboxErrorNames } from "../error/shape.js";
|
|
2
3
|
import { createRawJson } from "../interp/raw-json.js";
|
|
3
4
|
import { createBuiltinBindings } from "../interp/globals.js";
|
|
4
5
|
import { getIntrinsicIdentity, listIntrinsicIdentities, resolveIntrinsicIdentity } from "../interp/intrinsics.js";
|
|
5
6
|
import { releaseObjectPrototype } from "../interp/object-model.js";
|
|
6
7
|
import { isSandboxClosure } from "../interp/values.js";
|
|
8
|
+
import { assertSnapshotDataDepth } from "../graph-depth.js";
|
|
7
9
|
let intrinsicKinds;
|
|
8
10
|
function intrinsicCatalogue() {
|
|
9
11
|
if (intrinsicKinds !== undefined)
|
|
@@ -59,7 +61,7 @@ export function validateGuestHeapNode(raw, heap, maxArrayLength = 0xffffffff) {
|
|
|
59
61
|
createRawJson(node.text);
|
|
60
62
|
return true;
|
|
61
63
|
}
|
|
62
|
-
if (!["intrinsic", "guest-function", "guest-class", "guest-generator", "scope-frame", "guest-object", "guest-array", "array-iterator", "map", "set"].includes(String(node.kind)))
|
|
64
|
+
if (!["intrinsic", "bound-function", "guest-function", "guest-class", "guest-generator", "scope-frame", "guest-object", "guest-array", "array-iterator", "map", "set"].includes(String(node.kind)))
|
|
63
65
|
return false;
|
|
64
66
|
const reference = (value, kinds) => {
|
|
65
67
|
const ref = record(value);
|
|
@@ -74,7 +76,7 @@ export function validateGuestHeapNode(raw, heap, maxArrayLength = 0xffffffff) {
|
|
|
74
76
|
const callable = (value) => {
|
|
75
77
|
if (absent(value))
|
|
76
78
|
return;
|
|
77
|
-
const target = reference(value, ["intrinsic", "guest-function", "guest-class"]);
|
|
79
|
+
const target = reference(value, ["intrinsic", "bound-function", "guest-function", "guest-class"]);
|
|
78
80
|
if (target.kind === "intrinsic" && intrinsicCatalogue().get(String(target.id)) !== true)
|
|
79
81
|
throw new TypeError("Guest accessor reference is not callable.");
|
|
80
82
|
};
|
|
@@ -145,7 +147,9 @@ export function validateGuestHeapNode(raw, heap, maxArrayLength = 0xffffffff) {
|
|
|
145
147
|
state(node.state);
|
|
146
148
|
}
|
|
147
149
|
else if (node.kind === "guest-object" || node.kind === "guest-array") {
|
|
148
|
-
fields(node, ["kind", "state"], node.kind === "guest-array" ? ["templateNodeId", "templateOwner"] : []);
|
|
150
|
+
fields(node, ["kind", "state"], node.kind === "guest-array" ? ["templateNodeId", "templateOwner"] : ["errorType"]);
|
|
151
|
+
if (Object.hasOwn(node, "errorType") && !sandboxErrorNames.includes(node.errorType))
|
|
152
|
+
throw new TypeError("Invalid guest error type.");
|
|
149
153
|
if (Object.hasOwn(node, "templateOwner"))
|
|
150
154
|
reference(node.templateOwner, ["guest-array"]);
|
|
151
155
|
if (Object.hasOwn(node, "templateNodeId") && integer(node.templateNodeId) < 1)
|
|
@@ -199,6 +203,27 @@ export function validateGuestHeapNode(raw, heap, maxArrayLength = 0xffffffff) {
|
|
|
199
203
|
throw new TypeError("Invalid class prototype descriptor.");
|
|
200
204
|
reference(descriptor.value, ["object", "guest-object"]);
|
|
201
205
|
}
|
|
206
|
+
else if (node.kind === "bound-function") {
|
|
207
|
+
fields(node, ["kind", "target", "thisValue", "args", "length", "state"], ["name"]);
|
|
208
|
+
if (Object.hasOwn(node, "name") && typeof node.name !== "string")
|
|
209
|
+
throw new TypeError("Invalid bound function name.");
|
|
210
|
+
if (array(node.args).length > maxArrayLength)
|
|
211
|
+
throw new TypeError("Bound arguments exceed allocation limit.");
|
|
212
|
+
if (!absent(node.length) && !(typeof node.length === "number" && node.length >= 0) &&
|
|
213
|
+
!(record(node.length).kind === "number" && record(node.length).value === "Infinity"))
|
|
214
|
+
throw new TypeError("Invalid bound function length.");
|
|
215
|
+
const visited = new Set([raw]);
|
|
216
|
+
let current = node;
|
|
217
|
+
while (current.kind === "bound-function") {
|
|
218
|
+
assertSnapshotDataDepth(visited.size, "<bound-target>");
|
|
219
|
+
callable(current.target);
|
|
220
|
+
current = reference(current.target);
|
|
221
|
+
if (visited.has(current))
|
|
222
|
+
throw new TypeError("Cyclic bound function target.");
|
|
223
|
+
visited.add(current);
|
|
224
|
+
}
|
|
225
|
+
state(node.state);
|
|
226
|
+
}
|
|
202
227
|
else if (node.kind === "guest-function") {
|
|
203
228
|
fields(node, ["kind", "astNodeId", "scope", "state"], ["name", "environment"]);
|
|
204
229
|
if (integer(node.astNodeId) < 1)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type SandboxErrorName } from "../error/shape.js";
|
|
1
2
|
import { type ScopeFrame } from "../interp/scope.js";
|
|
2
3
|
import { type PropertyDescriptorData } from "./property-descriptors.js";
|
|
3
4
|
import type { CompletionResult } from "../interp/exceptions.js";
|
|
@@ -13,6 +14,14 @@ export type GuestObjectState<T> = {
|
|
|
13
14
|
prototype?: T;
|
|
14
15
|
};
|
|
15
16
|
export type GuestHeapNode<T> = {
|
|
17
|
+
kind: "bound-function";
|
|
18
|
+
target: T;
|
|
19
|
+
thisValue: T;
|
|
20
|
+
args: T[];
|
|
21
|
+
name?: string;
|
|
22
|
+
length: T;
|
|
23
|
+
state: GuestObjectState<T>;
|
|
24
|
+
} | {
|
|
16
25
|
kind: "array-iterator";
|
|
17
26
|
source: T;
|
|
18
27
|
index: number;
|
|
@@ -65,6 +74,7 @@ export type GuestHeapNode<T> = {
|
|
|
65
74
|
} | {
|
|
66
75
|
kind: "guest-object";
|
|
67
76
|
state: GuestObjectState<T>;
|
|
77
|
+
errorType?: SandboxErrorName;
|
|
68
78
|
} | {
|
|
69
79
|
kind: "guest-array";
|
|
70
80
|
state: GuestObjectState<T>;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { getClosureOrigin, getGeneratorOrigin } from "../interp/closure-origin.js";
|
|
2
|
+
import { boundFunctionStates } from "../interp/bound-function-state.js";
|
|
3
|
+
import { sandboxErrorTypes } from "../error/shape.js";
|
|
2
4
|
import { getGeneratorProperties } from "../interp/generator-properties.js";
|
|
3
5
|
import { getIntrinsicIdentity } from "../interp/intrinsics.js";
|
|
4
6
|
import { getSandboxPrototype, hasExplicitSandboxPrototype, hasGuestObjectState, isGuestClosure, materializeFunctionProperties } from "../interp/object-model.js";
|
|
@@ -27,6 +29,12 @@ export function captureGuestHeapNode(value, encode) {
|
|
|
27
29
|
const state = captureObjectState(value, encode);
|
|
28
30
|
return { kind: "intrinsic", id: intrinsic, ...(state === undefined ? {} : { state }) };
|
|
29
31
|
}
|
|
32
|
+
const bound = boundFunctionStates.get(value);
|
|
33
|
+
if (bound !== undefined && isSandboxClosure(value)) {
|
|
34
|
+
return { kind: "bound-function", target: encode(bound.target), thisValue: encode(bound.thisValue),
|
|
35
|
+
args: bound.args.map(encode), length: encode(value.length),
|
|
36
|
+
...(value.name === undefined ? {} : { name: value.name }), state: captureObjectState(value, encode) };
|
|
37
|
+
}
|
|
30
38
|
if (isSandboxMap(value))
|
|
31
39
|
return { kind: "map", entries: [...value.entries].map(([key, entry]) => [encode(key), encode(entry)]), ...serializeCollectionProperties(value, encode) };
|
|
32
40
|
if (isSandboxSet(value))
|
|
@@ -144,8 +152,11 @@ export function captureGuestHeapNode(value, encode) {
|
|
|
144
152
|
isSandboxRegExpIterator(value))
|
|
145
153
|
return undefined;
|
|
146
154
|
const prototype = Object.getPrototypeOf(value);
|
|
147
|
-
if ((prototype === null || prototype === Object.prototype) && hasGuestObjectState(value))
|
|
148
|
-
|
|
155
|
+
if ((prototype === null || prototype === Object.prototype) && hasGuestObjectState(value)) {
|
|
156
|
+
const errorType = sandboxErrorTypes.get(value);
|
|
157
|
+
return { kind: "guest-object", state: captureObjectState(value, encode),
|
|
158
|
+
...(errorType === undefined ? {} : { errorType }) };
|
|
159
|
+
}
|
|
149
160
|
return undefined;
|
|
150
161
|
}
|
|
151
162
|
if (origin.node.nodeId === undefined)
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Budget, SandboxError } from "../interp/budget.js";
|
|
2
|
+
import { createBoundFunction } from "../interp/bound-function.js";
|
|
3
|
+
import { invokeBuiltinClosure } from "../interp/builtin-call.js";
|
|
2
4
|
import { getGeneratorProperties } from "../interp/generator-properties.js";
|
|
3
5
|
import { restoreRegexProperties } from "./regexp-properties.js";
|
|
4
6
|
import { classOrigins, createClassConstructor } from "../interp/classes.js";
|
|
@@ -20,7 +22,7 @@ import { restoreDateTime } from "../interp/date.js";
|
|
|
20
22
|
import { createRawJson } from "../interp/raw-json.js";
|
|
21
23
|
import { createSandboxBox } from "../interp/boxed.js";
|
|
22
24
|
import { restoreBoxedProperties } from "./boxed.js";
|
|
23
|
-
import { sandboxErrorTypes } from "../error/shape.js";
|
|
25
|
+
import { sandboxErrorNames, sandboxErrorTypes } from "../error/shape.js";
|
|
24
26
|
import { SnapshotMismatchError } from "../restore.js";
|
|
25
27
|
import { evaluateNode, Scope, setSandboxProperty } from "../interp/interpreter.js";
|
|
26
28
|
import { getGuestFunctionProperties, getGuestFunctionProperty, getSandboxDataProperty, isGuestClosure, materializeFunctionProperties, registerGuestClosure, setSandboxPrototype } from "../interp/object-model.js";
|
|
@@ -376,6 +378,42 @@ function isSerializedRegexValue(value) {
|
|
|
376
378
|
typeof value.flags === "string" &&
|
|
377
379
|
typeof value.lastIndex === "number");
|
|
378
380
|
}
|
|
381
|
+
function initializeIntrinsicRealm(state) {
|
|
382
|
+
if (state.intrinsicsInitialized)
|
|
383
|
+
return;
|
|
384
|
+
const prototype = Object.values(state.heap).find(node => node.kind === "intrinsic" && node.id === '["%FunctionPrototype%"]');
|
|
385
|
+
// Older heaps could omit this property or contain a guest-defined hook.
|
|
386
|
+
// Do not preinstall a nonconfigurable property over their captured state.
|
|
387
|
+
const functionHasInstance = prototype?.kind !== "intrinsic" || prototype.state === undefined ||
|
|
388
|
+
prototype.state.properties.properties.some(([key, descriptor]) => {
|
|
389
|
+
if (key === null || typeof key !== "object" || !("kind" in key) || key.kind !== "ref")
|
|
390
|
+
return false;
|
|
391
|
+
const symbol = state.heap[String(key.id)];
|
|
392
|
+
if (symbol?.kind !== "symbol" || symbol.wellKnown !== "hasInstance" || descriptor.kind !== "data" ||
|
|
393
|
+
descriptor.writable || descriptor.enumerable || descriptor.configurable)
|
|
394
|
+
return false;
|
|
395
|
+
const value = descriptor.value;
|
|
396
|
+
if (value === null || typeof value !== "object" || !("kind" in value) || value.kind !== "ref")
|
|
397
|
+
return false;
|
|
398
|
+
const method = state.heap[String(value.id)];
|
|
399
|
+
return method?.kind === "intrinsic" && method.id === '["%FunctionPrototype%",{"symbol":"hasInstance"}]';
|
|
400
|
+
});
|
|
401
|
+
const errorConstructors = Object.values(state.heap).filter(node => node.kind === "intrinsic" && sandboxErrorNames.some(name => node.id === JSON.stringify([name])));
|
|
402
|
+
const errorPrototypes = errorConstructors.every(node => node.kind === "intrinsic" &&
|
|
403
|
+
node.state?.properties.properties.some(([key, descriptor]) => {
|
|
404
|
+
if (key !== "prototype" || descriptor.kind !== "data" || descriptor.writable ||
|
|
405
|
+
descriptor.enumerable || descriptor.configurable)
|
|
406
|
+
return false;
|
|
407
|
+
const value = descriptor.value;
|
|
408
|
+
if (value === null || typeof value !== "object" || !("kind" in value) || value.kind !== "ref")
|
|
409
|
+
return false;
|
|
410
|
+
const prototype = state.heap[String(value.id)];
|
|
411
|
+
return prototype?.kind === "intrinsic" &&
|
|
412
|
+
prototype.id === JSON.stringify([...JSON.parse(node.id), "prototype"]);
|
|
413
|
+
}));
|
|
414
|
+
createBuiltinBindings({ budget: state.budget, compileOwner: state.compilation.owner, functionHasInstance, errorPrototypes });
|
|
415
|
+
state.intrinsicsInitialized = true;
|
|
416
|
+
}
|
|
379
417
|
function restoreHeapValue(id, state) {
|
|
380
418
|
const existing = state.heapValueById.get(id);
|
|
381
419
|
if (existing !== undefined) {
|
|
@@ -531,13 +569,27 @@ function restoreHeapValue(id, state) {
|
|
|
531
569
|
});
|
|
532
570
|
return generator;
|
|
533
571
|
}
|
|
534
|
-
if (serialized.kind === "intrinsic" || serialized.kind === "guest-function" || serialized.kind === "guest-class" || serialized.kind === "guest-object" || serialized.kind === "guest-array" || serialized.kind === "array-iterator") {
|
|
572
|
+
if (serialized.kind === "intrinsic" || serialized.kind === "bound-function" || serialized.kind === "guest-function" || serialized.kind === "guest-class" || serialized.kind === "guest-object" || serialized.kind === "guest-array" || serialized.kind === "array-iterator") {
|
|
535
573
|
let value;
|
|
536
|
-
if (serialized.kind === "
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
574
|
+
if (serialized.kind === "bound-function") {
|
|
575
|
+
initializeIntrinsicRealm(state);
|
|
576
|
+
const target = deserializeValue(serialized.target, state);
|
|
577
|
+
if (!isSandboxClosure(target))
|
|
578
|
+
throw new TypeError("Invalid bound function target.");
|
|
579
|
+
const boundState = { target, thisValue: undefined, args: [] };
|
|
580
|
+
const length = deserializeValue(serialized.length, state);
|
|
581
|
+
if (length !== undefined && typeof length !== "number")
|
|
582
|
+
throw new TypeError("Invalid bound function length.");
|
|
583
|
+
value = createBoundFunction(boundState, serialized.name, length, (callee, args, stack, thisValue, construct, newTarget) => invokeBuiltinClosure(callee, args, state.budget, { stack, thisValue, newTarget }, thisValue, construct));
|
|
584
|
+
// Allocate every bound identity before decoding arguments and receivers:
|
|
585
|
+
// either may point back to this function, including through another bind.
|
|
586
|
+
state.initializeIterators.push(() => {
|
|
587
|
+
boundState.thisValue = deserializeValue(serialized.thisValue, state);
|
|
588
|
+
boundState.args = serialized.args.map(entry => deserializeValue(entry, state));
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
else if (serialized.kind === "intrinsic") {
|
|
592
|
+
initializeIntrinsicRealm(state);
|
|
541
593
|
value = resolveIntrinsicIdentity(state.budget, serialized.id);
|
|
542
594
|
}
|
|
543
595
|
else if (serialized.kind === "guest-class") {
|
|
@@ -578,12 +630,19 @@ function restoreHeapValue(id, state) {
|
|
|
578
630
|
homeObject: serialized.environment.homeObject === undefined ? undefined : deserializeValue(serialized.environment.homeObject, state),
|
|
579
631
|
newTarget: serialized.environment.newTarget === undefined ? undefined : deserializeValue(serialized.environment.newTarget, state)
|
|
580
632
|
};
|
|
633
|
+
// Current generator functions need their realm before creation, not only
|
|
634
|
+
// when a later prototype reference is decoded. Earlier heaps can lack the
|
|
635
|
+
// native nonconfigurable prototype property and retain that legacy shape.
|
|
636
|
+
const initializeGeneratorPrototype = node.type !== "ArrowFunctionExpression" && node.generator &&
|
|
637
|
+
serialized.state.properties.properties.some(([key, descriptor]) => key === "prototype" && descriptor.kind === "data" && !descriptor.configurable);
|
|
638
|
+
if (initializeGeneratorPrototype)
|
|
639
|
+
initializeIntrinsicRealm(state);
|
|
581
640
|
value = createInterpretedClosure(node, {
|
|
582
641
|
scope, budget: state.budget, compilation: state.compilation, rootNode: state.rootNode,
|
|
583
642
|
signal: state.signal, inferredName: serialized.name, functionEnvironment: environment,
|
|
584
643
|
callStack: [], activeLoopIterations: new Map(), restoredLoopIterations: new Map(),
|
|
585
644
|
stats: { currentDataSize: 0, nodeVisits: 0, peakDataSize: 0 }
|
|
586
|
-
}, evaluateNode, environment?.homeObject);
|
|
645
|
+
}, evaluateNode, environment?.homeObject, initializeGeneratorPrototype);
|
|
587
646
|
}
|
|
588
647
|
else
|
|
589
648
|
value = serialized.kind === "guest-array" ? [] : Object.create(null);
|
|
@@ -607,6 +666,8 @@ function restoreHeapValue(id, state) {
|
|
|
607
666
|
throw new TypeError(`Missing restored function properties for ${serialized.kind === "intrinsic" ? serialized.id : serialized.kind}.`);
|
|
608
667
|
if (objectState.prototype !== undefined)
|
|
609
668
|
setSandboxPrototype(value, deserializeValue(objectState.prototype, state), state.budget);
|
|
669
|
+
if (serialized.kind === "guest-object" && serialized.errorType !== undefined)
|
|
670
|
+
sandboxErrorTypes.set(value, serialized.errorType);
|
|
610
671
|
restorePropertyDescriptors(target, objectState.properties, entry => deserializeValue(entry, state));
|
|
611
672
|
if (serialized.kind === "guest-array" && serialized.templateNodeId !== undefined) {
|
|
612
673
|
const node = state.nodeById.get(serialized.templateNodeId);
|
|
@@ -706,7 +706,7 @@ function validateArrayHeap(record, path, state) {
|
|
|
706
706
|
function validateErrorType(record, path) {
|
|
707
707
|
if (!Object.hasOwn(record, "errorType"))
|
|
708
708
|
return;
|
|
709
|
-
if (record.kind !== "object" ||
|
|
709
|
+
if ((record.kind !== "object" && record.kind !== "guest-object") ||
|
|
710
710
|
!sandboxErrorNames.includes(record.errorType)) {
|
|
711
711
|
fail("invalidValue", `${path}.errorType`, "invalid error metadata");
|
|
712
712
|
}
|