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.
Files changed (49) hide show
  1. package/dist/index.js +876 -404
  2. package/dist/index.js.map +4 -4
  3. package/dist/metafile.json +1 -1
  4. package/package.json +1 -1
  5. package/packages/safe-js/dist/chunks/{chunk-34G5WW2O.js → chunk-7LGBDF56.js} +2 -2
  6. package/packages/safe-js/dist/chunks/{chunk-M4L3EZHL.js → chunk-V6LQP64H.js} +733 -334
  7. package/packages/safe-js/dist/chunks/chunk-V6LQP64H.js.map +7 -0
  8. package/packages/safe-js/dist/cli.js +2 -2
  9. package/packages/safe-js/dist/core.js +1 -1
  10. package/packages/safe-js/dist/index.js +2 -2
  11. package/packages/safe-js/dist/interp/async.d.ts +1 -1
  12. package/packages/safe-js/dist/interp/async.js +65 -43
  13. package/packages/safe-js/dist/interp/bound-function-state.d.ts +7 -0
  14. package/packages/safe-js/dist/interp/bound-function-state.js +1 -0
  15. package/packages/safe-js/dist/interp/bound-function.d.ts +4 -0
  16. package/packages/safe-js/dist/interp/bound-function.js +18 -0
  17. package/packages/safe-js/dist/interp/error-prototypes.d.ts +3 -0
  18. package/packages/safe-js/dist/interp/error-prototypes.js +1 -0
  19. package/packages/safe-js/dist/interp/exceptions.d.ts +1 -0
  20. package/packages/safe-js/dist/interp/exceptions.js +39 -15
  21. package/packages/safe-js/dist/interp/generator-prototypes.d.ts +6 -0
  22. package/packages/safe-js/dist/interp/generator-prototypes.js +1 -0
  23. package/packages/safe-js/dist/interp/globals/error.d.ts +2 -0
  24. package/packages/safe-js/dist/interp/globals/error.js +104 -4
  25. package/packages/safe-js/dist/interp/globals/function.d.ts +1 -1
  26. package/packages/safe-js/dist/interp/globals/function.js +10 -2
  27. package/packages/safe-js/dist/interp/globals/generator.d.ts +2 -0
  28. package/packages/safe-js/dist/interp/globals/generator.js +51 -0
  29. package/packages/safe-js/dist/interp/globals/object-array.js +19 -1
  30. package/packages/safe-js/dist/interp/globals.d.ts +2 -0
  31. package/packages/safe-js/dist/interp/globals.js +7 -3
  32. package/packages/safe-js/dist/interp/host-bridge.js +4 -2
  33. package/packages/safe-js/dist/interp/instanceof.d.ts +4 -0
  34. package/packages/safe-js/dist/interp/instanceof.js +59 -0
  35. package/packages/safe-js/dist/interp/interpreter.js +3 -40
  36. package/packages/safe-js/dist/interp/iteration.js +44 -6
  37. package/packages/safe-js/dist/interp/methods/function.d.ts +1 -1
  38. package/packages/safe-js/dist/interp/methods/function.js +53 -40
  39. package/packages/safe-js/dist/interp/methods/generator.d.ts +4 -1
  40. package/packages/safe-js/dist/interp/methods/generator.js +12 -6
  41. package/packages/safe-js/dist/interp/object-model.js +13 -0
  42. package/packages/safe-js/dist/interp/values.js +47 -2
  43. package/packages/safe-js/dist/snapshot/guest-heap-validation.js +28 -3
  44. package/packages/safe-js/dist/snapshot/guest-heap.d.ts +10 -0
  45. package/packages/safe-js/dist/snapshot/guest-heap.js +13 -2
  46. package/packages/safe-js/dist/snapshot/restore.js +69 -8
  47. package/packages/safe-js/dist/snapshot/validation.js +1 -1
  48. package/packages/safe-js/dist/chunks/chunk-M4L3EZHL.js.map +0 -7
  49. /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
- return { kind: "guest-object", state: captureObjectState(value, encode) };
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 === "intrinsic") {
537
- if (!state.intrinsicsInitialized) {
538
- createBuiltinBindings({ budget: state.budget, compileOwner: state.compilation.owner });
539
- state.intrinsicsInitialized = true;
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
  }