poe-code 14.0.40 → 14.0.42

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.
@@ -22,7 +22,7 @@ import {
22
22
  resolveFsConfig,
23
23
  splitFrontmatter,
24
24
  withBrokenPipeGuard
25
- } from "./chunks/chunk-LGJLTEI5.js";
25
+ } from "./chunks/chunk-IRDBTJYC.js";
26
26
  import {
27
27
  Budget,
28
28
  SandboxError,
@@ -34,7 +34,7 @@ import {
34
34
  replaceErrorStack,
35
35
  restore,
36
36
  run
37
- } from "./chunks/chunk-GO774BRE.js";
37
+ } from "./chunks/chunk-M4M56OCI.js";
38
38
  import "./chunks/chunk-UXMKEUH3.js";
39
39
  import "./chunks/chunk-5DYEOCT5.js";
40
40
  import "./chunks/chunk-4YIDX44G.js";
@@ -5,7 +5,7 @@ import {
5
5
  defineExtension,
6
6
  lint,
7
7
  run
8
- } from "./chunks/chunk-GO774BRE.js";
8
+ } from "./chunks/chunk-M4M56OCI.js";
9
9
  import "./chunks/chunk-4YIDX44G.js";
10
10
  export {
11
11
  Budget,
@@ -26,7 +26,7 @@ import {
26
26
  runWithSpawnUsageAccumulator,
27
27
  splitFrontmatter,
28
28
  supportsSpawnMode
29
- } from "./chunks/chunk-LGJLTEI5.js";
29
+ } from "./chunks/chunk-IRDBTJYC.js";
30
30
  import {
31
31
  Budget,
32
32
  FileSnapshotBackend,
@@ -50,7 +50,7 @@ import {
50
50
  registerPendingHostCallPolicy,
51
51
  restore,
52
52
  run
53
- } from "./chunks/chunk-GO774BRE.js";
53
+ } from "./chunks/chunk-M4M56OCI.js";
54
54
  import "./chunks/chunk-UXMKEUH3.js";
55
55
  import "./chunks/chunk-5DYEOCT5.js";
56
56
  import "./chunks/chunk-4YIDX44G.js";
@@ -52,6 +52,7 @@ export declare function emitResumeBreakpoint(context: AsyncEvaluationContext, br
52
52
  export declare function evaluateArrowFunctionExpression(node: ArrowFunctionExpression, context: AsyncEvaluationContext, evaluateNode: EvaluateAsyncNode): Promise<AsyncEvaluationResult>;
53
53
  export declare function evaluateFunctionExpression(node: FunctionExpression, context: AsyncEvaluationContext, evaluateNode: EvaluateAsyncNode): Promise<AsyncEvaluationResult>;
54
54
  export declare function createInterpretedClosure(node: ArrowFunctionExpression | FunctionDeclaration | FunctionExpression, context: AsyncEvaluationContext, evaluateNode: EvaluateAsyncNode): import("./values.js").SandboxClosure;
55
+ export declare function executeAsyncFunction(execute: (onSuspend: () => void) => Promise<SandboxValue>, budget: Budget, signal?: AbortSignal): import("./values.js").SandboxPromise;
55
56
  export declare function evaluateAwaitExpression(node: AwaitExpression, context: AsyncEvaluationContext, evaluateNode: EvaluateAsyncNode): Promise<AsyncEvaluationResult>;
56
57
  export declare function normalizeClosureResult(result: SandboxValue | Promise<SandboxValue> | PromiseLike<SandboxValue>, budget?: Budget): SandboxValue;
57
58
  export {};
@@ -81,36 +81,39 @@ export function createInterpretedClosure(node, context, evaluateNode) {
81
81
  };
82
82
  if (!node.async)
83
83
  return executeClosure(node, args, callContext?.thisValue, invocationContext, evaluateNode);
84
- let completePrefix;
85
- const synchronousPrefix = new Promise((resolve) => {
86
- completePrefix = resolve;
87
- });
88
- const promise = new Promise((resolve, reject) => {
89
- runAsyncPrefix(async () => {
90
- try {
91
- const value = await executeClosure(node, args, callContext?.thisValue, { ...invocationContext, onSuspend: completePrefix }, evaluateNode);
92
- resolve(isSandboxPromise(value) || getThenable(value) !== undefined
93
- ? awaitSandboxValue(createSandboxPromise(resolveSandboxValue(value, { budget: context.budget }), {
94
- trackReplay: false
95
- }), context.signal, context.budget)
96
- : allocateProducedSandboxValue(value, context.budget));
97
- }
98
- catch (error) {
99
- reject(error);
100
- }
101
- finally {
102
- completePrefix();
103
- }
104
- }).catch((error) => {
105
- reject(error);
106
- completePrefix();
107
- });
108
- });
109
- return createSandboxPromise(promise, { synchronousPrefix });
84
+ return executeAsyncFunction((onSuspend) => executeClosure(node, args, callContext?.thisValue, { ...invocationContext, onSuspend }, evaluateNode), context.budget, context.signal);
110
85
  }
111
86
  });
112
87
  return closure;
113
88
  }
89
+ export function executeAsyncFunction(execute, budget, signal) {
90
+ let completePrefix;
91
+ const synchronousPrefix = new Promise((resolve) => {
92
+ completePrefix = resolve;
93
+ });
94
+ const promise = new Promise((resolve, reject) => {
95
+ runAsyncPrefix(async () => {
96
+ try {
97
+ const value = await execute(completePrefix);
98
+ resolve(isSandboxPromise(value) || getThenable(value) !== undefined
99
+ ? awaitSandboxValue(createSandboxPromise(resolveSandboxValue(value, { budget }), {
100
+ trackReplay: false
101
+ }), signal, budget)
102
+ : allocateProducedSandboxValue(value, budget));
103
+ }
104
+ catch (error) {
105
+ reject(error);
106
+ }
107
+ finally {
108
+ completePrefix();
109
+ }
110
+ }).catch((error) => {
111
+ reject(error);
112
+ completePrefix();
113
+ });
114
+ });
115
+ return createSandboxPromise(promise, { synchronousPrefix });
116
+ }
114
117
  function createGeneratorClosure(node, context, evaluateNode) {
115
118
  return createSandboxClosure({
116
119
  guest: true,
@@ -29,6 +29,7 @@ type ExceptionContext = {
29
29
  budget: Budget;
30
30
  callStack: readonly string[];
31
31
  scope: Scope;
32
+ toPropertyKey?: (value: SandboxValue) => Promise<string>;
32
33
  };
33
34
  type EvaluateExceptionNode<TContext, TError> = (node: ParseResult, context: TContext) => Promise<EvaluationResult<TError>>;
34
35
  export declare function evaluateThrowStatement<TContext extends ExceptionContext, TError>(node: ThrowStatement, context: TContext, evaluateNode: EvaluateExceptionNode<TContext, TError>): Promise<EvaluationResult<TError>>;
@@ -3,6 +3,7 @@ import { SandboxError } from "./budget.js";
3
3
  import { HostCallResumabilityError } from "./host-call.js";
4
4
  import { withFatalPromiseCleanup } from "./promise-tracker.js";
5
5
  import { deepCopyToSandbox } from "./values.js";
6
+ import { toPropertyKey } from "./property-key.js";
6
7
  const capturedExceptionBrand = Symbol("CapturedException");
7
8
  export async function evaluateThrowStatement(node, context, evaluateNode) {
8
9
  const argument = await evaluateNode(node.argument, context);
@@ -389,12 +390,9 @@ async function resolvePatternPropertyKey(property, context, evaluateNode) {
389
390
  result: computedKey
390
391
  };
391
392
  }
392
- if (typeof computedKey.value !== "string" && typeof computedKey.value !== "number") {
393
- throw new TypeError("Computed catch binding keys must evaluate to a string or number.");
394
- }
395
393
  return {
396
394
  ok: true,
397
- value: computedKey.value
395
+ value: await (context.toPropertyKey?.(computedKey.value) ?? toPropertyKey(computedKey.value, context.budget, { stack: context.callStack, thisValue: undefined }))
398
396
  };
399
397
  }
400
398
  function getStaticPropertyKey(property) {
@@ -45,6 +45,7 @@ export type InterpreterResult = {
45
45
  };
46
46
  export type InterpretOptions = {
47
47
  assertActive?: () => void;
48
+ onSuspend?: () => void;
48
49
  jobs?: SandboxJobQueue;
49
50
  nested?: boolean;
50
51
  compilation?: CompileScope;
@@ -1,6 +1,6 @@
1
1
  import { promiseReplayContext } from "./promise-replay.js";
2
2
  import { deleteHostObjectMember, getHostObjectKeys, getHostObjectMember, hasHostObjectMember, isGuestHostObject, setHostObjectMember } from "./host-capabilities.js";
3
- import { sandboxString } from "./string-coercion.js";
3
+ import { toPropertyKey } from "./property-key.js";
4
4
  import { assertPromiseExecutionAllowed } from "./promise-tracker.js";
5
5
  import { SandboxJobQueue, runAsyncPrefix, suspendJob } from "./jobs.js";
6
6
  import { withCancellationSignal } from "./cancel.js";
@@ -111,6 +111,7 @@ export async function interpret(node, options = {}) {
111
111
  budget,
112
112
  callStack: [],
113
113
  onYield: options.onYield,
114
+ onSuspend: options.onSuspend,
114
115
  captureReplayState: options.captureReplayState,
115
116
  rootNode: node,
116
117
  scope,
@@ -443,7 +444,7 @@ async function evaluateBinaryExpression(node, context) {
443
444
  if (typeof right.value !== "object" || right.value === null) {
444
445
  throw new TypeError("Right-hand side of 'in' must be an object.");
445
446
  }
446
- leftValue = await toPropertyKey(leftValue, context);
447
+ leftValue = await toPropertyKey(leftValue, context.budget, createCoercionContext(context));
447
448
  }
448
449
  const value = applyBinaryOperator(node, leftValue, right.value, context);
449
450
  return {
@@ -534,7 +535,15 @@ async function evaluateMemberAssignmentExpression(node, context) {
534
535
  if (member.kind === "nullish") {
535
536
  throw new TypeError("Cannot assign properties of null or undefined.");
536
537
  }
537
- const current = node.operator === "=" ? undefined : getPropertyValue(member.object, member.property, context);
538
+ let property;
539
+ let current = undefined;
540
+ if (node.operator !== "=") {
541
+ if (member.object === null || member.object === undefined) {
542
+ throw new TypeError("Cannot assign properties of null or undefined.");
543
+ }
544
+ property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
545
+ current = getPropertyValue(member.object, property, context);
546
+ }
538
547
  if (node.operator === "&&=" && !isTruthy(current)) {
539
548
  return {
540
549
  kind: "normal",
@@ -566,7 +575,11 @@ async function evaluateMemberAssignmentExpression(node, context) {
566
575
  node.operator === "??="
567
576
  ? right.value
568
577
  : await applyCompoundAssignmentOperator(node.operator, current, right.value, context);
569
- setSandboxProperty(member.object, member.property, value, context.budget);
578
+ if (member.object === null || member.object === undefined) {
579
+ throw new TypeError("Cannot assign properties of null or undefined.");
580
+ }
581
+ property ??= await toPropertyKey(member.property, context.budget, createCoercionContext(context));
582
+ setSandboxProperty(member.object, property, value, context.budget);
570
583
  return {
571
584
  kind: "normal",
572
585
  hasValue: true,
@@ -1522,7 +1535,10 @@ async function evaluateThrowStatement(node, context) {
1522
1535
  return evaluateThrowStatementResult(node, context, evaluateNode);
1523
1536
  }
1524
1537
  async function evaluateTryStatement(node, context) {
1525
- return evaluateTryStatementResult(node, context, evaluateNode);
1538
+ return evaluateTryStatementResult(node, {
1539
+ ...context,
1540
+ toPropertyKey: (value) => toPropertyKey(value, context.budget, createCoercionContext(context))
1541
+ }, evaluateNode);
1526
1542
  }
1527
1543
  async function evaluateUnaryExpression(node, context) {
1528
1544
  if (node.operator === "delete") {
@@ -1565,8 +1581,8 @@ async function evaluateDeleteExpression(node, context) {
1565
1581
  if (member.kind === "completion") {
1566
1582
  return member.result;
1567
1583
  }
1568
- if (member.kind === "nullish") {
1569
- if (node.argument.optional) {
1584
+ if (member.kind === "nullish" || member.object === null || member.object === undefined) {
1585
+ if (member.kind === "nullish" && node.argument.optional) {
1570
1586
  return {
1571
1587
  kind: "normal",
1572
1588
  hasValue: true,
@@ -1578,7 +1594,8 @@ async function evaluateDeleteExpression(node, context) {
1578
1594
  if (!isIndexableSandboxValue(member.object)) {
1579
1595
  throw new TypeError("Unary operator 'delete' requires a sandbox object property.");
1580
1596
  }
1581
- const deleted = deleteSandboxProperty(member.object, member.property);
1597
+ const property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
1598
+ const deleted = deleteSandboxProperty(member.object, property);
1582
1599
  return {
1583
1600
  kind: "normal",
1584
1601
  hasValue: true,
@@ -1622,12 +1639,13 @@ async function evaluateMemberUpdateExpression(node, context) {
1622
1639
  if (member.kind === "completion") {
1623
1640
  return member.result;
1624
1641
  }
1625
- if (member.kind === "nullish") {
1642
+ if (member.kind === "nullish" || member.object === null || member.object === undefined) {
1626
1643
  throw new TypeError("Cannot update properties of null or undefined.");
1627
1644
  }
1628
- const current = toNumber(await toNumericPrimitive(getPropertyValue(member.object, member.property, context), context));
1645
+ const property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
1646
+ const current = toNumber(await toNumericPrimitive(getPropertyValue(member.object, property, context), context));
1629
1647
  const next = node.operator === "++" ? current + 1 : current - 1;
1630
- setSandboxProperty(member.object, member.property, next, context.budget);
1648
+ setSandboxProperty(member.object, property, next, context.budget);
1631
1649
  return {
1632
1650
  kind: "normal",
1633
1651
  hasValue: true,
@@ -1640,15 +1658,15 @@ async function evaluateMemberExpression(node, context) {
1640
1658
  return member;
1641
1659
  if (member.kind === "completion")
1642
1660
  return member.result;
1643
- if (member.kind === "nullish") {
1644
- if (node.optional)
1661
+ if (member.kind === "nullish" || member.object === null || member.object === undefined) {
1662
+ if (member.kind === "nullish" && node.optional)
1645
1663
  return { kind: "normal", hasValue: true, value: undefined };
1646
1664
  throw new TypeError("Cannot read properties of null or undefined.");
1647
1665
  }
1648
1666
  return {
1649
1667
  kind: "normal",
1650
1668
  hasValue: true,
1651
- value: getPropertyValue(member.object, member.property, context)
1669
+ value: getPropertyValue(member.object, await toPropertyKey(member.property, context.budget, createCoercionContext(context)), context)
1652
1670
  };
1653
1671
  }
1654
1672
  function getPropertyValue(target, property, context) {
@@ -1685,6 +1703,7 @@ export function createPatternContext(context, scope = context.scope, evaluate =
1685
1703
  const evaluationContext = { ...context, scope };
1686
1704
  return {
1687
1705
  evaluate: node => evaluate(node, evaluationContext),
1706
+ toPropertyKey: value => toPropertyKey(value, context.budget, createCoercionContext(evaluationContext)),
1688
1707
  getProperty: (value, key) => getPropertyValue(value, key, evaluationContext),
1689
1708
  setProperty: (target, key, value) => setSandboxProperty(target, key, value, context.budget)
1690
1709
  };
@@ -1772,24 +1791,10 @@ async function evaluateMemberAccess(node, context) {
1772
1791
  };
1773
1792
  }
1774
1793
  const property = node.computed
1775
- ? await evaluateMemberProperty(node.property, context)
1776
- : { ok: true, value: getStaticPropertyName(node.property) };
1777
- if (!property.ok) {
1778
- return property.result.kind === "error"
1779
- ? {
1780
- kind: "error",
1781
- error: property.result.error
1782
- }
1783
- : {
1784
- kind: "completion",
1785
- result: property.result
1786
- };
1787
- }
1788
- if (object.value === null || object.value === undefined) {
1789
- return {
1790
- kind: "nullish"
1791
- };
1792
- }
1794
+ ? await evaluateNode(node.property, context)
1795
+ : { kind: "normal", value: getStaticPropertyName(node.property) };
1796
+ if (property.kind !== "normal")
1797
+ return { kind: "completion", result: property };
1793
1798
  return {
1794
1799
  kind: "resolved",
1795
1800
  object: object.value,
@@ -1804,13 +1809,10 @@ async function evaluateMemberProperty(node, context) {
1804
1809
  result: property
1805
1810
  };
1806
1811
  }
1807
- if (typeof property.value === "string" || typeof property.value === "number") {
1808
- return {
1809
- ok: true,
1810
- value: property.value
1811
- };
1812
- }
1813
- throw new TypeError("Computed property access requires a string or number key.");
1812
+ return {
1813
+ ok: true,
1814
+ value: await toPropertyKey(property.value, context.budget, createCoercionContext(context))
1815
+ };
1814
1816
  }
1815
1817
  async function evaluateObjectPropertyKey(node, context) {
1816
1818
  if (!node.computed) {
@@ -1834,15 +1836,15 @@ async function evaluateMemberCallExpression(node, context) {
1834
1836
  if (node.callee.type !== "MemberExpression") {
1835
1837
  throw new TypeError("Expected member call expression.");
1836
1838
  }
1837
- const member = await evaluateMemberAccess(node.callee, context);
1838
- if (member.kind === "error") {
1839
- return member;
1839
+ const reference = await evaluateMemberAccess(node.callee, context);
1840
+ if (reference.kind === "error") {
1841
+ return reference;
1840
1842
  }
1841
- if (member.kind === "completion") {
1842
- return member.result;
1843
+ if (reference.kind === "completion") {
1844
+ return reference.result;
1843
1845
  }
1844
- if (member.kind === "nullish") {
1845
- if (node.optional || node.callee.optional) {
1846
+ if (reference.kind === "nullish" || reference.object === null || reference.object === undefined) {
1847
+ if (reference.kind === "nullish") {
1846
1848
  return {
1847
1849
  kind: "normal",
1848
1850
  hasValue: true,
@@ -1851,6 +1853,10 @@ async function evaluateMemberCallExpression(node, context) {
1851
1853
  }
1852
1854
  throw new TypeError("Cannot read properties of null or undefined.");
1853
1855
  }
1856
+ const member = {
1857
+ ...reference,
1858
+ property: await toPropertyKey(reference.property, context.budget, createCoercionContext(context))
1859
+ };
1854
1860
  if (typeof member.object === "string" && isStringMethodName(member.property)) {
1855
1861
  return evaluateStringMethodCall(node, member.object, member.property, context);
1856
1862
  }
@@ -2123,25 +2129,13 @@ function applyBinaryOperator(node, left, right, context) {
2123
2129
  return hasSandboxProperty(right, left, context);
2124
2130
  }
2125
2131
  }
2126
- async function toPropertyKey(value, context) {
2127
- if (isPlainSandboxObject(value) && !isSandboxDate(value) && !isFloat32Array(value) &&
2128
- !isSandboxGenerator(value) && !isGuestHostObject(value)) {
2129
- for (const name of ["toString", "valueOf"]) {
2130
- const method = getMemberValue(value, name, context);
2131
- if (!isSandboxClosure(method))
2132
- continue;
2133
- const primitive = await invokeSandboxClosure(method, [], context, context.callStack, undefined, value);
2134
- if (primitive === null || typeof primitive !== "object") {
2135
- return context.budget.allocateString(String(primitive));
2136
- }
2137
- }
2138
- throw new TypeError("Cannot convert object to primitive value.");
2139
- }
2140
- return sandboxString(value, context.budget, {
2132
+ function createCoercionContext(context) {
2133
+ return {
2141
2134
  stack: context.callStack,
2142
2135
  thisValue: undefined,
2136
+ compilation: context.compilation,
2143
2137
  invokeClosure: (closure, args, thisValue) => invokeSandboxClosure(closure, args, context, context.callStack, undefined, thisValue)
2144
- });
2138
+ };
2145
2139
  }
2146
2140
  function hasSandboxProperty(value, key, context) {
2147
2141
  let current = value;
@@ -11,6 +11,7 @@ export type PatternTarget = {
11
11
  };
12
12
  export type PatternContext = {
13
13
  evaluate(node: ParseResult): Promise<AsyncEvaluationResult>;
14
+ toPropertyKey(value: SandboxValue): Promise<string>;
14
15
  getProperty(value: SandboxValue, key: string | number): SandboxValue;
15
16
  setProperty(target: SandboxValue, key: string | number, value: SandboxValue): void;
16
17
  };
@@ -90,19 +90,19 @@ async function bindMemberExpression(pattern, value, scope, context) {
90
90
  if (object.kind !== "normal") {
91
91
  return { ok: false, result: object };
92
92
  }
93
+ const property = pattern.computed
94
+ ? await context.evaluate(pattern.property)
95
+ : { kind: "normal", value: getStaticPropertyName(pattern.property) };
96
+ if (property.kind !== "normal") {
97
+ return { ok: false, result: property };
98
+ }
93
99
  if (object.value === null || object.value === undefined) {
94
100
  throw new TypeError("Cannot assign properties of null or undefined.");
95
101
  }
96
102
  if (!isIndexableValue(object.value)) {
97
103
  throw new TypeError("Assignment expressions require a sandbox object property.");
98
104
  }
99
- const property = pattern.computed
100
- ? await evaluateProperty(pattern.property, context)
101
- : { ok: true, value: getStaticPropertyName(pattern.property) };
102
- if (!property.ok) {
103
- return property;
104
- }
105
- context.setProperty(object.value, property.value, value);
105
+ context.setProperty(object.value, await context.toPropertyKey(property.value), value);
106
106
  return { ok: true };
107
107
  }
108
108
  async function evaluatePatternKey(property, context) {
@@ -115,10 +115,7 @@ async function evaluateProperty(property, context) {
115
115
  if (result.kind !== "normal") {
116
116
  return { ok: false, result };
117
117
  }
118
- if (typeof result.value !== "string" && typeof result.value !== "number") {
119
- throw new TypeError("Computed property access requires a string or number key.");
120
- }
121
- return { ok: true, value: result.value };
118
+ return { ok: true, value: await context.toPropertyKey(result.value) };
122
119
  }
123
120
  function getStaticPropertyName(property) {
124
121
  if (property.type === "Identifier") {
@@ -0,0 +1,3 @@
1
+ import type { Budget } from "./budget.js";
2
+ import { type SandboxCallContext, type SandboxValue } from "./values.js";
3
+ export declare function toPropertyKey(value: SandboxValue, budget: Budget, context: SandboxCallContext): Promise<string>;
@@ -0,0 +1,53 @@
1
+ import { isSandboxDate } from "./date.js";
2
+ import { isFloat32Array } from "./float32.js";
3
+ import { isGuestHostObject } from "./host-capabilities.js";
4
+ import { getSandboxDataProperty } from "./object-model.js";
5
+ import { sandboxString } from "./string-coercion.js";
6
+ import { isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, isSandboxRegex, isSandboxSet } from "./values.js";
7
+ export async function toPropertyKey(value, budget, context) {
8
+ if (typeof value === "string")
9
+ return value;
10
+ const invocation = context.invokeClosure === undefined
11
+ ? {
12
+ ...context,
13
+ invokeClosure: async (closure, args, thisValue) => {
14
+ const leaveCall = budget.enterCall();
15
+ try {
16
+ const result = closure.call(args, { ...invocation, thisValue });
17
+ if (isSandboxPromise(result)) {
18
+ await result.synchronousPrefix;
19
+ return result;
20
+ }
21
+ return await result;
22
+ }
23
+ finally {
24
+ leaveCall();
25
+ }
26
+ }
27
+ }
28
+ : context;
29
+ if (typeof value === "object" &&
30
+ value !== null &&
31
+ !Array.isArray(value) &&
32
+ !isSandboxClosure(value) &&
33
+ !isSandboxMap(value) &&
34
+ !isSandboxSet(value) &&
35
+ !isSandboxPromise(value) &&
36
+ !isSandboxRegex(value) &&
37
+ !isSandboxDate(value) &&
38
+ !isFloat32Array(value) &&
39
+ !isSandboxGenerator(value) &&
40
+ !isGuestHostObject(value)) {
41
+ for (const name of ["toString", "valueOf"]) {
42
+ const method = getSandboxDataProperty(value, name, budget);
43
+ if (!isSandboxClosure(method))
44
+ continue;
45
+ const primitive = await invocation.invokeClosure(method, [], value);
46
+ if (primitive === null || typeof primitive !== "object") {
47
+ return budget.allocateString(String(primitive));
48
+ }
49
+ }
50
+ throw new TypeError("Cannot convert object to primitive value.");
51
+ }
52
+ return sandboxString(value, budget, invocation);
53
+ }
@@ -1,4 +1,6 @@
1
1
  import { Budget, SandboxError } from "../interp/budget.js";
2
+ import { executeAsyncFunction } from "../interp/async.js";
3
+ import { toPropertyKey } from "../interp/property-key.js";
2
4
  import { CompileScope } from "../interp/regex/compile-guard.js";
3
5
  import { decodeFloat32Storage } from "./float32array.js";
4
6
  import { restoreDateTime } from "../interp/date.js";
@@ -429,7 +431,8 @@ function restoreClosureValue(astNodeId, capturedScopeId, state) {
429
431
  throw new Error(`Snapshot references unknown closure AST node ${astNodeId}.`);
430
432
  }
431
433
  const baseClosure = createSandboxClosure({
432
- async: true,
434
+ async: node.async,
435
+ sandbox: true,
433
436
  length: getFunctionLength(node.params),
434
437
  ...(node.type === "ArrowFunctionExpression" || node.id === undefined ? {} : { name: node.id.name }),
435
438
  ...(node.type !== "ArrowFunctionExpression" &&
@@ -437,18 +440,23 @@ function restoreClosureValue(astNodeId, capturedScopeId, state) {
437
440
  !node.generator &&
438
441
  !node.async
439
442
  ? {
440
- construct: async (args) => {
443
+ construct: async (args, callContext) => {
441
444
  const thisValue = {};
442
445
  const prototype = getGuestFunctionProperty(restoredClosure, "prototype");
443
446
  if (typeof prototype === "object" && prototype !== null) {
444
447
  setSandboxPrototype(thisValue, prototype, state.budget);
445
448
  }
446
- const result = await executeRestoredClosure(node, capturedScopeId, restoredClosure, args, thisValue, state);
449
+ const result = await executeRestoredClosure(node, capturedScopeId, restoredClosure, args, thisValue, state, callContext);
447
450
  return typeof result === "object" && result !== null ? result : thisValue;
448
451
  }
449
452
  }
450
453
  : {}),
451
- call: (args, callContext) => createSandboxPromise(executeRestoredClosure(node, capturedScopeId, restoredClosure, args, callContext?.thisValue, state))
454
+ call: (args, callContext) => {
455
+ if (node.async) {
456
+ return executeAsyncFunction((onSuspend) => executeRestoredClosure(node, capturedScopeId, restoredClosure, args, callContext?.thisValue, state, callContext, onSuspend), state.budget);
457
+ }
458
+ return executeRestoredClosure(node, capturedScopeId, restoredClosure, args, callContext?.thisValue, state, callContext);
459
+ }
452
460
  });
453
461
  const restoredClosure = Object.defineProperties(Object.create(baseClosure), {
454
462
  astNodeId: {
@@ -468,9 +476,10 @@ function restoreClosureValue(astNodeId, capturedScopeId, state) {
468
476
  Object.defineProperty(restoredClosure, "properties", { get: () => getGuestFunctionProperties(restoredClosure) });
469
477
  return restoredClosure;
470
478
  }
471
- async function executeRestoredClosure(node, capturedScopeId, closure, args, thisValue, state) {
472
- const operation = state.budget.acquireCompileOwner(false, state.compilation.owner);
473
- const compilation = new CompileScope(operation.owner);
479
+ async function executeRestoredClosure(node, capturedScopeId, closure, args, thisValue, state, callContext, onSuspend) {
480
+ const parent = callContext?.compilation ?? state.compilation;
481
+ const operation = state.budget.acquireCompileOwner(false, parent.owner);
482
+ const compilation = new CompileScope(operation.owner, parent);
474
483
  state = { ...state, compilation };
475
484
  try {
476
485
  const capturedScope = state.scopeById.get(capturedScopeId) ?? restoreParentScope(capturedScopeId, state);
@@ -492,6 +501,7 @@ async function executeRestoredClosure(node, capturedScopeId, closure, args, this
492
501
  const rest = args.slice(index);
493
502
  state.budget.allocateArrayLength(rest.length);
494
503
  const binding = await bindPattern(param, rest, { kind: "let" }, scope, {
504
+ toPropertyKey: value => toPropertyKey(value, state.budget, { ...callContext, stack: callContext?.stack ?? [], thisValue, compilation }),
495
505
  getProperty: (value, key) => getSandboxDataProperty(value, key, state.budget),
496
506
  setProperty: (target, key, value) => setSandboxProperty(target, key, value, state.budget),
497
507
  evaluate: async (defaultNode) => {
@@ -499,6 +509,7 @@ async function executeRestoredClosure(node, capturedScopeId, closure, args, this
499
509
  budget: state.budget,
500
510
  compilation,
501
511
  scope,
512
+ nested: true,
502
513
  useScopeDirectly: true
503
514
  });
504
515
  return result.ok
@@ -521,6 +532,7 @@ async function executeRestoredClosure(node, capturedScopeId, closure, args, this
521
532
  break;
522
533
  }
523
534
  const binding = await bindPattern(param, args[index], { kind: "let" }, scope, {
535
+ toPropertyKey: value => toPropertyKey(value, state.budget, { ...callContext, stack: callContext?.stack ?? [], thisValue, compilation }),
524
536
  getProperty: (value, key) => getSandboxDataProperty(value, key, state.budget),
525
537
  setProperty: (target, key, value) => setSandboxProperty(target, key, value, state.budget),
526
538
  evaluate: async (defaultNode) => {
@@ -528,6 +540,7 @@ async function executeRestoredClosure(node, capturedScopeId, closure, args, this
528
540
  budget: state.budget,
529
541
  compilation,
530
542
  scope,
543
+ nested: true,
531
544
  useScopeDirectly: true
532
545
  });
533
546
  return result.ok
@@ -551,12 +564,14 @@ async function executeRestoredClosure(node, capturedScopeId, closure, args, this
551
564
  const result = await interpret(node.body, {
552
565
  budget: state.budget,
553
566
  compilation,
567
+ nested: true,
568
+ onSuspend,
554
569
  scope
555
570
  });
556
571
  if (!result.ok) {
557
572
  throw new Error(result.error.message);
558
573
  }
559
- reconcileCompiledValues(state.budget, [...scope.retainedValues(), ...state.budget.retainedValues(), result.returnValue], compilation);
574
+ reconcileCompiledValues(state.budget, [...scope.retainedValues(), ...state.budget.retainedValues(), result.returnValue], compilation, parent, [result.returnValue]);
560
575
  return result.returnValue;
561
576
  }
562
577
  finally {