poe-code 14.0.79 → 14.0.80

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 (32) hide show
  1. package/dist/index.js +252 -100
  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-B3AL4KJ3.js → chunk-34G5WW2O.js} +2 -2
  6. package/packages/safe-js/dist/chunks/{chunk-BGSPSHLP.js → chunk-M4L3EZHL.js} +220 -93
  7. package/packages/safe-js/dist/chunks/chunk-M4L3EZHL.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/graph-depth.js +2 -1
  11. package/packages/safe-js/dist/index.js +2 -2
  12. package/packages/safe-js/dist/interp/generator-properties.d.ts +3 -0
  13. package/packages/safe-js/dist/interp/generator-properties.js +9 -0
  14. package/packages/safe-js/dist/interp/globals/function.d.ts +2 -0
  15. package/packages/safe-js/dist/interp/globals/function.js +24 -0
  16. package/packages/safe-js/dist/interp/globals/object-array.js +9 -6
  17. package/packages/safe-js/dist/interp/globals/object.js +2 -1
  18. package/packages/safe-js/dist/interp/globals.js +2 -0
  19. package/packages/safe-js/dist/interp/interpreter.js +13 -7
  20. package/packages/safe-js/dist/interp/iteration.js +37 -4
  21. package/packages/safe-js/dist/interp/methods/function.d.ts +4 -1
  22. package/packages/safe-js/dist/interp/methods/function.js +2 -2
  23. package/packages/safe-js/dist/interp/object-model.d.ts +1 -0
  24. package/packages/safe-js/dist/interp/object-model.js +67 -17
  25. package/packages/safe-js/dist/interp/string-coercion.js +3 -2
  26. package/packages/safe-js/dist/interp/values.js +21 -3
  27. package/packages/safe-js/dist/snapshot/guest-heap-validation.js +3 -1
  28. package/packages/safe-js/dist/snapshot/guest-heap.d.ts +1 -0
  29. package/packages/safe-js/dist/snapshot/guest-heap.js +4 -0
  30. package/packages/safe-js/dist/snapshot/restore.js +8 -0
  31. package/packages/safe-js/dist/chunks/chunk-BGSPSHLP.js.map +0 -7
  32. /package/packages/safe-js/dist/chunks/{chunk-B3AL4KJ3.js.map → chunk-34G5WW2O.js.map} +0 -0
@@ -22,7 +22,7 @@ import {
22
22
  resolveFsConfig,
23
23
  splitFrontmatter,
24
24
  withBrokenPipeGuard
25
- } from "./chunks/chunk-B3AL4KJ3.js";
25
+ } from "./chunks/chunk-34G5WW2O.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-BGSPSHLP.js";
37
+ } from "./chunks/chunk-M4L3EZHL.js";
38
38
  import "./chunks/chunk-M2DLCGEF.js";
39
39
  import "./chunks/chunk-Q7USUEL7.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-BGSPSHLP.js";
8
+ } from "./chunks/chunk-M4L3EZHL.js";
9
9
  import "./chunks/chunk-4YIDX44G.js";
10
10
  export {
11
11
  Budget,
@@ -7,6 +7,7 @@ import { regexpIteratorState, isSandboxRegExpIterator } from "./interp/regexp-it
7
7
  import { isSandboxMap, isSandboxSet } from "./interp/collection-brands.js";
8
8
  import { boxedDataProperties, isSandboxBox } from "./interp/boxed.js";
9
9
  import { regexGuestProperties } from "./interp/regexp-properties.js";
10
+ import { generatorGuestProperties } from "./interp/generator-properties.js";
10
11
  export const MAX_DATA_DEPTH = 1_024;
11
12
  export class SnapshotBudgetError extends Error {
12
13
  code = "budgetExceeded";
@@ -67,7 +68,7 @@ function walkGraphDepth(root, rootPath, assertDepth) {
67
68
  }
68
69
  }
69
70
  function graphEntries(value) {
70
- const properties = regexGuestProperties.get(value);
71
+ const properties = regexGuestProperties.get(value) ?? generatorGuestProperties.get(value);
71
72
  if (properties !== undefined)
72
73
  return Reflect.ownKeys(properties).flatMap(key => {
73
74
  const descriptor = Object.getOwnPropertyDescriptor(properties, key);
@@ -26,7 +26,7 @@ import {
26
26
  runWithSpawnUsageAccumulator,
27
27
  splitFrontmatter,
28
28
  supportsSpawnMode
29
- } from "./chunks/chunk-B3AL4KJ3.js";
29
+ } from "./chunks/chunk-34G5WW2O.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-BGSPSHLP.js";
53
+ } from "./chunks/chunk-M4L3EZHL.js";
54
54
  import "./chunks/chunk-M2DLCGEF.js";
55
55
  import "./chunks/chunk-Q7USUEL7.js";
56
56
  import "./chunks/chunk-4YIDX44G.js";
@@ -0,0 +1,3 @@
1
+ import type { SandboxGenerator, SandboxObject } from "./values.js";
2
+ export declare const generatorGuestProperties: WeakMap<object, SandboxObject>;
3
+ export declare function getGeneratorProperties(value: SandboxGenerator): SandboxObject;
@@ -0,0 +1,9 @@
1
+ export const generatorGuestProperties = new WeakMap();
2
+ export function getGeneratorProperties(value) {
3
+ let properties = generatorGuestProperties.get(value);
4
+ if (properties === undefined) {
5
+ properties = Object.create(null);
6
+ generatorGuestProperties.set(value, properties);
7
+ }
8
+ return properties;
9
+ }
@@ -0,0 +1,2 @@
1
+ import type { Budget } from "../budget.js";
2
+ export declare function createFunctionPrototype(budget: Budget): void;
@@ -0,0 +1,24 @@
1
+ import { invokeBuiltinClosure } from "../builtin-call.js";
2
+ import { callFunctionMethod } from "../methods/function.js";
3
+ import { getSandboxPrototype, installFunctionPrototype, materializeFunctionProperties, setSandboxPrototype } from "../object-model.js";
4
+ import { createSandboxClosure } from "../values.js";
5
+ export function createFunctionPrototype(budget) {
6
+ const prototype = createSandboxClosure({ guest: true, sandbox: true, name: "", length: 0, call: () => undefined });
7
+ const properties = materializeFunctionProperties(prototype);
8
+ // Invocation support does not grant the host's dynamic source constructor.
9
+ Object.defineProperty(properties, "constructor", { value: undefined, writable: true, configurable: true });
10
+ for (const [name, length] of [["call", 1], ["apply", 2], ["bind", 1], ["toString", 0]]) {
11
+ Object.defineProperty(properties, name, { writable: true, configurable: true,
12
+ value: createSandboxClosure({ guest: true, sandbox: true, name, length,
13
+ call: (args, context) => callFunctionMethod(context?.thisValue, name, args, {
14
+ budget,
15
+ callClosure: (target, values, stack, thisValue, construct, newTarget) => context?.invokeClosure !== undefined
16
+ ? context.invokeClosure(target, values, thisValue, construct, newTarget)
17
+ : invokeBuiltinClosure(target, values, budget, { ...context, stack, thisValue, newTarget }, thisValue, construct)
18
+ }, context?.stack ?? [], context)
19
+ })
20
+ });
21
+ }
22
+ setSandboxPrototype(prototype, getSandboxPrototype(Object.create(null), budget));
23
+ installFunctionPrototype(budget, prototype);
24
+ }
@@ -1,4 +1,5 @@
1
1
  import { isFatalSandboxError } from "../budget.js";
2
+ import { getGeneratorProperties } from "../generator-properties.js";
2
3
  import { accessorAdapter, accessorClosure, readPropertyDescriptor, retainedAccessorClosures } from "../accessors.js";
3
4
  import { invokeBuiltinClosure } from "../builtin-call.js";
4
5
  import { createDataCheckpoint } from "../data-checkpoint.js";
@@ -180,14 +181,14 @@ export function createObjectArrayGlobals(options) {
180
181
  call: ([value]) => {
181
182
  if (isGuestHostObject(value))
182
183
  throw new TypeError("Live host objects cannot be made non-extensible.");
183
- Object.preventExtensions(isSandboxPromise(value) ? getPromiseProperties(value) : isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : isSandboxMap(value) || isSandboxSet(value) ? getCollectionProperties(value) : value);
184
+ Object.preventExtensions(isSandboxGenerator(value) ? getGeneratorProperties(value) : isSandboxPromise(value) ? getPromiseProperties(value) : isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : isSandboxMap(value) || isSandboxSet(value) ? getCollectionProperties(value) : value);
184
185
  return value;
185
186
  },
186
187
  name: "preventExtensions"
187
188
  }),
188
189
  isExtensible: createSandboxClosure({
189
190
  sandbox: true,
190
- call: ([value]) => Object.isExtensible(isSandboxPromise(value) ? getPromiseProperties(value) : isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : isSandboxMap(value) || isSandboxSet(value) ? getCollectionProperties(value) : value),
191
+ call: ([value]) => Object.isExtensible(isSandboxGenerator(value) ? getGeneratorProperties(value) : isSandboxPromise(value) ? getPromiseProperties(value) : isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : isSandboxMap(value) || isSandboxSet(value) ? getCollectionProperties(value) : value),
191
192
  name: "isExtensible"
192
193
  }),
193
194
  seal: createSandboxClosure({
@@ -195,14 +196,14 @@ export function createObjectArrayGlobals(options) {
195
196
  call: ([value]) => {
196
197
  if (isGuestHostObject(value))
197
198
  throw new TypeError("Live host objects cannot be sealed.");
198
- Object.seal(isSandboxPromise(value) ? getPromiseProperties(value) : isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : isSandboxMap(value) || isSandboxSet(value) ? getCollectionProperties(value) : value);
199
+ Object.seal(isSandboxGenerator(value) ? getGeneratorProperties(value) : isSandboxPromise(value) ? getPromiseProperties(value) : isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : isSandboxMap(value) || isSandboxSet(value) ? getCollectionProperties(value) : value);
199
200
  return value;
200
201
  },
201
202
  name: "seal"
202
203
  }),
203
204
  isSealed: createSandboxClosure({
204
205
  sandbox: true,
205
- call: ([value]) => Object.isSealed(isSandboxPromise(value) ? getPromiseProperties(value) : isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : isSandboxMap(value) || isSandboxSet(value) ? getCollectionProperties(value) : value),
206
+ call: ([value]) => Object.isSealed(isSandboxGenerator(value) ? getGeneratorProperties(value) : isSandboxPromise(value) ? getPromiseProperties(value) : isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : isSandboxMap(value) || isSandboxSet(value) ? getCollectionProperties(value) : value),
206
207
  name: "isSealed"
207
208
  }),
208
209
  freeze: createSandboxClosure({
@@ -211,7 +212,7 @@ export function createObjectArrayGlobals(options) {
211
212
  if (isGuestHostObject(value))
212
213
  throw new TypeError("Live host objects cannot be frozen.");
213
214
  if (typeof value === "object" && value !== null) {
214
- Object.freeze(isSandboxPromise(value) ? getPromiseProperties(value) : isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : isSandboxMap(value) || isSandboxSet(value) ? getCollectionProperties(value) : value);
215
+ Object.freeze(isSandboxGenerator(value) ? getGeneratorProperties(value) : isSandboxPromise(value) ? getPromiseProperties(value) : isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : isSandboxMap(value) || isSandboxSet(value) ? getCollectionProperties(value) : value);
215
216
  }
216
217
  return value;
217
218
  },
@@ -219,7 +220,7 @@ export function createObjectArrayGlobals(options) {
219
220
  }),
220
221
  isFrozen: createSandboxClosure({
221
222
  sandbox: true,
222
- call: ([value]) => Object.isFrozen(isSandboxPromise(value) ? getPromiseProperties(value) : isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : isSandboxMap(value) || isSandboxSet(value) ? getCollectionProperties(value) : value),
223
+ call: ([value]) => Object.isFrozen(isSandboxGenerator(value) ? getGeneratorProperties(value) : isSandboxPromise(value) ? getPromiseProperties(value) : isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : isSandboxMap(value) || isSandboxSet(value) ? getCollectionProperties(value) : value),
223
224
  name: "isFrozen"
224
225
  }),
225
226
  assign: createSandboxClosure({
@@ -556,6 +557,8 @@ function reflectionProperties(value) {
556
557
  return objectProperties(value);
557
558
  }
558
559
  export function objectProperties(value, mutable = false) {
560
+ if (isSandboxGenerator(value))
561
+ return getGeneratorProperties(value);
559
562
  if (isSandboxPromise(value))
560
563
  return getPromiseProperties(value);
561
564
  if (isSandboxMap(value) || isSandboxSet(value))
@@ -1,4 +1,5 @@
1
1
  import { assertSandboxDataDepth } from "../../graph-depth.js";
2
+ import { getGeneratorProperties } from "../generator-properties.js";
2
3
  import { readPropertyDescriptor } from "../accessors.js";
3
4
  import { isSandboxArguments } from "../arguments.js";
4
5
  import { isSandboxDate } from "../date.js";
@@ -153,7 +154,7 @@ export function hasOwnSandboxProperty(value, key, enumerable) {
153
154
  else if (isSandboxPromise(value))
154
155
  properties = getPromiseProperties(value);
155
156
  else if (isSandboxGenerator(value))
156
- return false;
157
+ properties = getGeneratorProperties(value);
157
158
  else if (isSandboxRegex(value))
158
159
  properties = getRegexProperties(value);
159
160
  else
@@ -7,6 +7,7 @@ import { createRegexGlobals } from "./globals/regex.js";
7
7
  import { createMiscGlobals } from "./globals/misc.js";
8
8
  import { createUriGlobals } from "./globals/uri.js";
9
9
  import { createObjectArrayGlobals } from "./globals/object-array.js";
10
+ import { createFunctionPrototype } from "./globals/function.js";
10
11
  import { createPromiseGlobals } from "./promise.js";
11
12
  import { createDateGlobal } from "./globals/date.js";
12
13
  import { createSymbolGlobal } from "./globals/symbol.js";
@@ -28,6 +29,7 @@ export function createBuiltinBindings(options) {
28
29
  ...createPromiseGlobals(options),
29
30
  ...createRegexGlobals(options)
30
31
  };
32
+ createFunctionPrototype(options.budget);
31
33
  registerBuiltinIdentities(options.budget, bindings);
32
34
  return bindings;
33
35
  }
@@ -29,6 +29,7 @@ import { getPromiseMember } from "./promise.js";
29
29
  import { acquireSandboxIterator, closeIterator, readIteratorResult, restoreSandboxIterator } from "./iteration.js";
30
30
  import { assertCollectionMutable } from "./running-state.js";
31
31
  import { getGeneratorMember } from "./methods/generator.js";
32
+ import { getGeneratorProperties } from "./generator-properties.js";
32
33
  import { getRegexMember, setRegexMember } from "./methods/regex.js";
33
34
  import { bindPattern } from "./patterns.js";
34
35
  import { callStringMethod, getStringMember, isStringMethodName, validateStringMethodArguments } from "./methods/string.js";
@@ -1494,7 +1495,7 @@ function forInKeys(object, budget) {
1494
1495
  if (depth > 0)
1495
1496
  budget.visitNode();
1496
1497
  assertSandboxDataDepth(depth++);
1497
- const properties = isSandboxPromise(current) ? getPromiseProperties(current) : isGuestClosure(current) ? materializeFunctionProperties(current) : isSandboxClosure(current) ? current.properties ?? {} : isSandboxRegex(current) ? getRegexProperties(current) : isSandboxMap(current) || isSandboxSet(current) ? getCollectionProperties(current) : current;
1498
+ const properties = isSandboxGenerator(current) ? getGeneratorProperties(current) : isSandboxPromise(current) ? getPromiseProperties(current) : isGuestClosure(current) ? materializeFunctionProperties(current) : isSandboxClosure(current) ? current.properties ?? {} : isSandboxRegex(current) ? getRegexProperties(current) : isSandboxMap(current) || isSandboxSet(current) ? getCollectionProperties(current) : current;
1498
1499
  for (const key of Object.getOwnPropertyNames(properties)) {
1499
1500
  if (seen.has(key))
1500
1501
  continue;
@@ -1515,7 +1516,7 @@ function hasForInProperty(object, key, budget) {
1515
1516
  if (depth > 0)
1516
1517
  budget.visitNode();
1517
1518
  assertSandboxDataDepth(depth++);
1518
- const properties = isSandboxPromise(current) ? getPromiseProperties(current) : isGuestClosure(current) ? materializeFunctionProperties(current) : isSandboxClosure(current) ? current.properties ?? {} : isSandboxRegex(current) ? getRegexProperties(current) : isSandboxMap(current) || isSandboxSet(current) ? getCollectionProperties(current) : current;
1519
+ const properties = isSandboxGenerator(current) ? getGeneratorProperties(current) : isSandboxPromise(current) ? getPromiseProperties(current) : isGuestClosure(current) ? materializeFunctionProperties(current) : isSandboxClosure(current) ? current.properties ?? {} : isSandboxRegex(current) ? getRegexProperties(current) : isSandboxMap(current) || isSandboxSet(current) ? getCollectionProperties(current) : current;
1519
1520
  if (Object.hasOwn(properties, key))
1520
1521
  return true;
1521
1522
  }
@@ -2097,7 +2098,8 @@ function getPropertyValue(target, property, context, receiver = target) {
2097
2098
  if (isSandboxCollectionIterator(target))
2098
2099
  return getCollectionIteratorMember(target, property, context.budget);
2099
2100
  if (isSandboxGenerator(target))
2100
- return getGeneratorMember(target, property, context.budget);
2101
+ return hasExplicitSandboxPrototype(target)
2102
+ ? undefined : getGeneratorMember(target, property, context.budget);
2101
2103
  if (isSandboxClosure(target))
2102
2104
  return getClosureMemberValue(target, property, context);
2103
2105
  if (isSandboxPromise(target))
@@ -2384,7 +2386,7 @@ async function evaluateMemberCallExpression(node, context) {
2384
2386
  return evaluatePrimitiveMemberCall(node, "Set", member.property, getSetMember(member.object, member.property, createSetMethodOptions(context)), context);
2385
2387
  }
2386
2388
  if (isSandboxGenerator(member.object)) {
2387
- const memberValue = getGeneratorMember(member.object, member.property, context.budget);
2389
+ const memberValue = await getPropertyValue(member.object, member.property, context);
2388
2390
  if (memberValue === undefined) {
2389
2391
  throw new TypeError(`Generator#${String(member.property)} is not a supported method.`);
2390
2392
  }
@@ -2662,7 +2664,7 @@ function hasSandboxProperty(value, key, context) {
2662
2664
  return typeof key === "symbol" ? false : hasHostObjectMember(current, String(key));
2663
2665
  if (hasOwnSandboxProperty(current, key, false))
2664
2666
  return true;
2665
- if (!isSandboxDate(current) && !isSandboxRegex(current) && !isSandboxMap(current) && !isSandboxSet(current) && !((isGuestClosure(current) || Array.isArray(current)) && hasExplicitSandboxPrototype(current)) &&
2667
+ if (!isSandboxDate(current) && !isSandboxRegex(current) && !isSandboxMap(current) && !isSandboxSet(current) && !((isGuestClosure(current) || isSandboxGenerator(current) || Array.isArray(current)) && hasExplicitSandboxPrototype(current)) &&
2666
2668
  (Array.isArray(current) || !isPlainSandboxObject(current) ||
2667
2669
  isSandboxDate(current) || isFloat32Array(current) || isSandboxGenerator(current) || isSandboxCollectionIterator(current) || isSandboxRegExpIterator(current))) {
2668
2670
  return getPropertyValue(current, key, context) !== undefined;
@@ -2941,6 +2943,8 @@ export function setSandboxProperty(target, property, value, budget, checkInherit
2941
2943
  target = materializeFunctionProperties(target);
2942
2944
  if (isSandboxPromise(target))
2943
2945
  target = getPromiseProperties(target);
2946
+ if (isSandboxGenerator(target))
2947
+ target = getGeneratorProperties(target);
2944
2948
  if (isSandboxMap(target) || isSandboxSet(target))
2945
2949
  target = getCollectionProperties(target);
2946
2950
  if (isFloat32Array(target)) {
@@ -2977,7 +2981,7 @@ export function setSandboxProperty(target, property, value, budget, checkInherit
2977
2981
  for (let prototype = getSandboxPrototype(prototypeOwner, budget); prototype !== null; prototype = getSandboxPrototype(prototype, budget)) {
2978
2982
  budget.visitNode();
2979
2983
  assertSandboxDataDepth(depth++);
2980
- const properties = isSandboxClosure(prototype) ? prototype.properties : prototype;
2984
+ const properties = isSandboxGenerator(prototype) ? getGeneratorProperties(prototype) : isSandboxClosure(prototype) ? prototype.properties : prototype;
2981
2985
  const inherited = properties === undefined ? undefined : Object.getOwnPropertyDescriptor(properties, key);
2982
2986
  if (inherited === undefined)
2983
2987
  continue;
@@ -2997,7 +3001,7 @@ function setSuperProperty(base, receiver, key, value, context) {
2997
3001
  for (let current = base; current !== null; current = getSandboxPrototype(current, budget)) {
2998
3002
  budget.visitNode();
2999
3003
  assertSandboxDataDepth(depth++);
3000
- const properties = isSandboxClosure(current) ? current.properties : current;
3004
+ const properties = isSandboxGenerator(current) ? getGeneratorProperties(current) : isSandboxClosure(current) ? current.properties : current;
3001
3005
  const descriptor = properties === undefined ? undefined : Object.getOwnPropertyDescriptor(properties, key);
3002
3006
  if (descriptor === undefined)
3003
3007
  continue;
@@ -3020,6 +3024,8 @@ export function deleteSandboxProperty(target, property) {
3020
3024
  target = getRegexProperties(target);
3021
3025
  if (isSandboxPromise(target))
3022
3026
  target = getPromiseProperties(target);
3027
+ if (isSandboxGenerator(target))
3028
+ target = getGeneratorProperties(target);
3023
3029
  if (isSandboxMap(target) || isSandboxSet(target))
3024
3030
  target = getCollectionProperties(target);
3025
3031
  if (Array.isArray(target)) {
@@ -31,8 +31,9 @@ export async function restoreSandboxIterator(snapshot, budget, context, signal)
31
31
  return asyncFromSyncIterator(await restoreSandboxIterator(snapshot.inner, budget, context, signal), budget, signal, context);
32
32
  if (Array.isArray(snapshot.value))
33
33
  return arrayIterator(snapshot.value, context, budget, snapshot.index);
34
- const iterator = isSandboxGenerator(snapshot.value) && snapshot.value.async
35
- ? getSandboxAsyncIterator(snapshot.value, budget, context, signal)
34
+ const iterator = isSandboxGenerator(snapshot.value)
35
+ ? { ...generatorObjectIterator(snapshot.value, budget, context),
36
+ ...(snapshot.value.async ? { asyncProtocol: true } : {}) }
36
37
  : getSandboxIterator(snapshot.value, budget, context);
37
38
  if (iterator === undefined)
38
39
  throw new TypeError("Invalid builtin iterator snapshot.");
@@ -49,6 +50,12 @@ export async function acquireSandboxIterator(value, budget, context, asyncProtoc
49
50
  : getSandboxIterator(value, budget, context);
50
51
  if (getSandboxPropertyDescriptor(value, key, budget) === undefined &&
51
52
  !(isSandboxRegExpIterator(value) && !asyncProtocol && getSandboxPropertyDescriptor(value, "next", budget) !== undefined)) {
53
+ if (isSandboxGenerator(value)) {
54
+ if (hasExplicitSandboxPrototype(value))
55
+ return undefined;
56
+ if ((value.async === true) === asyncProtocol && getSandboxPropertyDescriptor(value, "next", budget) !== undefined)
57
+ return guestIterator(value, await context.getProperty(value, "next"), asyncProtocol, budget, context, signal);
58
+ }
52
59
  if (!asyncProtocol && Array.isArray(value) && getSandboxPrototype(value, budget) !== null)
53
60
  return undefined;
54
61
  if (!asyncProtocol)
@@ -130,7 +137,8 @@ export async function readIteratorResult(iterator, result, property) {
130
137
  }
131
138
  export function getSandboxAsyncIterator(value, budget, context, signal) {
132
139
  if (isSandboxGenerator(value) && value.async) {
133
- return { ...generatorIterator(value, budget, context), asyncProtocol: true };
140
+ return hasExplicitSandboxPrototype(value) ? undefined
141
+ : { ...generatorObjectIterator(value, budget, context), asyncProtocol: true };
134
142
  }
135
143
  if (value !== null &&
136
144
  (typeof value === "object" || typeof value === "function") &&
@@ -288,7 +296,7 @@ export function getSandboxIterator(value, budget, context) {
288
296
  return syncIterator(Float32Array.prototype.values.call(value));
289
297
  }
290
298
  if (isSandboxGenerator(value)) {
291
- return value.async ? undefined : generatorIterator(value);
299
+ return value.async || hasExplicitSandboxPrototype(value) ? undefined : generatorObjectIterator(value, budget, context);
292
300
  }
293
301
  if (typeof value === "string") {
294
302
  const iterator = value[Symbol.iterator]();
@@ -373,6 +381,31 @@ function collectionIterator(collection, value) {
373
381
  return adapter;
374
382
  }
375
383
  const asyncGeneratorRequests = new WeakMap();
384
+ function generatorObjectIterator(generator, budget, context) {
385
+ const iterator = generatorIterator(generator, budget, context);
386
+ if (context?.getProperty === undefined)
387
+ return iterator;
388
+ return {
389
+ ...iterator,
390
+ getOperation: async (method) => {
391
+ if (method === "next" || (!hasExplicitSandboxPrototype(generator) &&
392
+ getSandboxPropertyDescriptor(generator, method, budget) === undefined))
393
+ return iterator[method];
394
+ const operation = await context.getProperty(generator, method);
395
+ if (operation === undefined || operation === null)
396
+ return undefined;
397
+ if (!isSandboxClosure(operation))
398
+ throw new TypeError("Iterator operation must be callable.");
399
+ return async (...args) => {
400
+ const result = await invokeBuiltinClosure(operation, args, budget ?? new Budget(), context, generator);
401
+ return (generator.async ? await awaitSandboxValue(result, undefined, budget, context) : result);
402
+ };
403
+ },
404
+ readResultProperty: async (result, property) => ({
405
+ value: await context.getProperty(result, property)
406
+ })
407
+ };
408
+ }
376
409
  export function generatorIterator(generator, budget, context) {
377
410
  const invoke = async (method, value) => {
378
411
  const leaveRunning = enterRunningState(generator);
@@ -1,7 +1,10 @@
1
- import { type SandboxClosure, type SandboxValue } from "../values.js";
1
+ import { type SandboxCallContext, type SandboxClosure, type SandboxValue } from "../values.js";
2
2
  import type { Budget } from "../budget.js";
3
3
  export type FunctionMethodOptions = {
4
4
  budget?: Budget;
5
5
  callClosure: (closure: SandboxClosure, args: readonly SandboxValue[], stack: readonly string[], thisValue: SandboxValue, construct?: boolean, newTarget?: SandboxClosure) => Promise<SandboxValue> | SandboxValue;
6
6
  };
7
+ type FunctionMethodName = "apply" | "bind" | "call" | "toString";
7
8
  export declare function getFunctionMember(target: SandboxClosure, property: string | number, options: FunctionMethodOptions): SandboxValue | undefined;
9
+ export declare function callFunctionMethod(target: SandboxValue, methodName: FunctionMethodName, args: readonly SandboxValue[], options: FunctionMethodOptions, stack: readonly string[], context?: SandboxCallContext): Promise<SandboxValue> | SandboxValue;
10
+ export {};
@@ -22,7 +22,7 @@ export function getFunctionMember(target, property, options) {
22
22
  else if (Object.hasOwn(current, String(property))) {
23
23
  return current[String(property)];
24
24
  }
25
- if (isSandboxClosure(current) && !hasExplicitSandboxPrototype(current))
25
+ if (isSandboxClosure(current) && !hasExplicitSandboxPrototype(current) && getSandboxPrototype(current, options.budget) === null)
26
26
  break;
27
27
  current = getSandboxPrototype(current, options.budget);
28
28
  if (current !== null) {
@@ -47,7 +47,7 @@ export function getFunctionMember(target, property, options) {
47
47
  function isFunctionMethodName(property) {
48
48
  return typeof property === "string" && functionMethodNames.has(property);
49
49
  }
50
- function callFunctionMethod(target, methodName, args, options, stack, context) {
50
+ export function callFunctionMethod(target, methodName, args, options, stack, context) {
51
51
  if (!isSandboxClosure(target)) {
52
52
  throw new TypeError(`Function#${methodName} requires a callable receiver.`);
53
53
  }
@@ -7,6 +7,7 @@ export declare function getGuestFunctionProperties(closure: SandboxClosure): San
7
7
  export declare function materializeFunctionProperties(closure: SandboxClosure): SandboxObject;
8
8
  export declare function getGuestFunctionProperty(closure: SandboxClosure, key: PropertyKey): SandboxValue;
9
9
  export declare function installObjectPrototype(budget: Budget, prototype: SandboxObject, constructor: SandboxClosure): void;
10
+ export declare function installFunctionPrototype(budget: Budget, prototype: SandboxClosure): void;
10
11
  export declare function installBoxedPrototype(budget: Budget, prototype: SandboxObject, constructor: SandboxClosure, kind?: BoxedKind): void;
11
12
  export declare function getBoxedPrototype(value: BoxedPrimitive, budget: Budget): SandboxObject | undefined;
12
13
  export declare function installRegexPrototype(budget: Budget, prototype: SandboxObject, constructor: SandboxClosure): void;
@@ -1,4 +1,6 @@
1
1
  import { assertSandboxDataDepth } from "../graph-depth.js";
2
+ import { getGeneratorProperties } from "./generator-properties.js";
3
+ import { runResources } from "./resources.js";
2
4
  import { getIntrinsicIdentity, registerBuiltinIdentities, releaseIntrinsicIdentities } from "./intrinsics.js";
3
5
  import { releaseTemplateObjects } from "./template-objects.js";
4
6
  import { isSandboxDate } from "./date.js";
@@ -8,6 +10,7 @@ import { boxedValue, isSandboxBox } from "./boxed.js";
8
10
  import { isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, getPromiseProperties, isSandboxRegex, getRegexProperties, getCollectionProperties, isSandboxSet } from "./values.js";
9
11
  const guestClosures = new WeakSet();
10
12
  const functionProperties = new WeakMap();
13
+ const functionPropertyRevisions = new WeakMap();
11
14
  const prototypes = new WeakMap();
12
15
  const intrinsicPrototypes = new WeakMap();
13
16
  const boxedPrototypes = new WeakMap();
@@ -16,6 +19,7 @@ const collectionPrototypes = new WeakMap();
16
19
  const promisePrototypes = new WeakMap();
17
20
  const datePrototypes = new WeakMap();
18
21
  const arrayPrototypes = new WeakMap();
22
+ const functionPrototypes = new WeakMap();
19
23
  const initialArrayMethods = new WeakMap();
20
24
  const initialRegexDescriptors = new WeakMap();
21
25
  const intrinsicPrototypeRoots = new WeakMap();
@@ -53,9 +57,26 @@ export function materializeFunctionProperties(closure) {
53
57
  descriptorObjects.add(prototype);
54
58
  Object.defineProperty(properties, "prototype", { value: prototype, writable: true });
55
59
  }
56
- descriptorObjects.add(properties);
57
- functionProperties.set(closure, properties);
58
- return properties;
60
+ // Never expose the raw table: native callers must invalidate captures too.
61
+ const state = { revision: 0 };
62
+ const tracked = new Proxy(properties, {
63
+ defineProperty(target, key, descriptor) {
64
+ const changed = Reflect.defineProperty(target, key, descriptor);
65
+ if (changed)
66
+ state.revision++;
67
+ return changed;
68
+ },
69
+ deleteProperty(target, key) {
70
+ const changed = Reflect.deleteProperty(target, key);
71
+ if (changed)
72
+ state.revision++;
73
+ return changed;
74
+ }
75
+ });
76
+ functionPropertyRevisions.set(tracked, state);
77
+ descriptorObjects.add(tracked);
78
+ functionProperties.set(closure, tracked);
79
+ return tracked;
59
80
  }
60
81
  export function getGuestFunctionProperty(closure, key) {
61
82
  let properties = functionProperties.get(closure);
@@ -79,6 +100,12 @@ export function installObjectPrototype(budget, prototype, constructor) {
79
100
  intrinsicPrototypes.set(budget, prototype);
80
101
  registerIntrinsicPrototype(budget, prototype, constructor);
81
102
  }
103
+ export function installFunctionPrototype(budget, prototype) {
104
+ functionPrototypes.set(budget, prototype);
105
+ registerBuiltinIdentities(budget, { "%FunctionPrototype%": prototype });
106
+ registerIntrinsicFunction(budget, prototype);
107
+ registerIntrinsicObject(budget, materializeFunctionProperties(prototype));
108
+ }
82
109
  export function installBoxedPrototype(budget, prototype, constructor, kind = typeof boxedValue(prototype)) {
83
110
  let state = boxedPrototypes.get(budget);
84
111
  if (state === undefined)
@@ -181,6 +208,9 @@ function trackIntrinsicState(budget, root, owner, targets) {
181
208
  }))
182
209
  .map((record) => ({
183
210
  ...record,
211
+ revision: functionPropertyRevisions.get(record.value),
212
+ capturedRevision: -1,
213
+ captured: [],
184
214
  extensible: Object.isExtensible(record.value),
185
215
  descriptors: new Map(Reflect.ownKeys(record.value).map(key => [key, Object.getOwnPropertyDescriptor(record.value, key)]))
186
216
  }));
@@ -206,16 +236,24 @@ function trackIntrinsicState(budget, root, owner, targets) {
206
236
  budget.setRetainedValues(root, () => {
207
237
  // Capture every change before measurement invokes retained-value callbacks.
208
238
  const retained = [];
209
- for (const { target, value, descriptors, prototype: parent } of records) {
239
+ for (const record of records) {
240
+ const { target, value, descriptors, prototype: parent, revision } = record;
210
241
  const currentPrototype = getSandboxPrototype(target);
211
242
  if (currentPrototype !== parent)
212
243
  retained.push(currentPrototype);
213
- for (const key of Reflect.ownKeys(value)) {
214
- const descriptor = Object.getOwnPropertyDescriptor(value, key);
215
- if (unchanged(descriptors.get(key), descriptor))
216
- continue;
217
- retained.push(key, descriptor.value, ...retainedAccessorClosures(descriptor));
244
+ if (revision === undefined || revision.revision !== record.capturedRevision) {
245
+ const captured = [];
246
+ for (const key of Reflect.ownKeys(value)) {
247
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
248
+ if (unchanged(descriptors.get(key), descriptor))
249
+ continue;
250
+ captured.push(key, descriptor.value, ...retainedAccessorClosures(descriptor));
251
+ }
252
+ record.captured = captured;
253
+ record.capturedRevision = revision?.revision ?? -1;
218
254
  }
255
+ for (const item of record.captured)
256
+ retained.push(item);
219
257
  }
220
258
  return retained;
221
259
  });
@@ -232,12 +270,15 @@ export function releaseObjectPrototype(budget) {
232
270
  promisePrototypes.delete(budget);
233
271
  datePrototypes.delete(budget);
234
272
  arrayPrototypes.delete(budget);
273
+ functionPrototypes.delete(budget);
235
274
  initialRegexDescriptors.delete(budget);
236
275
  intrinsicPrototypes.delete(budget);
237
276
  }
238
277
  export function getSandboxPrototype(value, budget) {
239
278
  if (prototypes.has(value))
240
279
  return prototypes.get(value) ?? null;
280
+ if (budget !== undefined && isGuestClosure(value) && runResources.getStore()?.functionSourceText !== false)
281
+ return functionPrototypes.get(budget) ?? null;
241
282
  if (budget !== undefined && Array.isArray(value))
242
283
  return arrayPrototypes.get(budget) ?? null;
243
284
  if (budget !== undefined && isSandboxDate(value))
@@ -273,9 +314,14 @@ export function getSandboxPropertyDescriptor(value, key, budget) {
273
314
  let depth = 0;
274
315
  while (typeof current === "object" &&
275
316
  current !== null &&
276
- (Array.isArray(current) || isSandboxDate(current) || isSandboxPromise(current) || isSandboxRegex(current) || isSandboxMap(current) || isSandboxSet(current) || isPrototypeRecord(current))) {
277
- const properties = isSandboxPromise(current) ? getPromiseProperties(current) : isGuestClosure(current) ? getGuestFunctionProperties(current)
317
+ (Array.isArray(current) || isSandboxGenerator(current) || isSandboxDate(current) || isSandboxPromise(current) || isSandboxRegex(current) || isSandboxMap(current) || isSandboxSet(current) || isPrototypeRecord(current))) {
318
+ const properties = isSandboxGenerator(current) ? getGeneratorProperties(current) : isSandboxPromise(current) ? getPromiseProperties(current) : isGuestClosure(current)
319
+ ? key === "prototype" && current.construct !== undefined && current.boundTarget === undefined
320
+ ? materializeFunctionProperties(current) : getGuestFunctionProperties(current)
278
321
  : isSandboxRegex(current) ? getRegexProperties(current) : isSandboxMap(current) || isSandboxSet(current) ? getCollectionProperties(current) : current;
322
+ if (properties === undefined && isGuestClosure(current) && (key === "name" || key === "length"))
323
+ return { value: key === "name" ? current.name ?? "" : current.length ?? 0,
324
+ writable: false, enumerable: false, configurable: true };
279
325
  const descriptor = properties === undefined ? undefined : Object.getOwnPropertyDescriptor(properties, key);
280
326
  if (descriptor !== undefined)
281
327
  return descriptor;
@@ -297,6 +343,11 @@ export function getSandboxDataProperty(value, key, budget) {
297
343
  return Object.getOwnPropertyDescriptor(getRegexProperties(current), key)?.value;
298
344
  if (isSandboxPromise(current))
299
345
  return Object.getOwnPropertyDescriptor(getPromiseProperties(current), key)?.value;
346
+ if (isSandboxGenerator(current)) {
347
+ const descriptor = Object.getOwnPropertyDescriptor(getGeneratorProperties(current), key);
348
+ if (descriptor !== undefined)
349
+ return descriptor.value;
350
+ }
300
351
  if (isSandboxMap(current) || isSandboxSet(current))
301
352
  return Object.getOwnPropertyDescriptor(getCollectionProperties(current), key)?.value;
302
353
  if (isGuestClosure(current)) {
@@ -313,10 +364,9 @@ export function getSandboxDataProperty(value, key, budget) {
313
364
  if (isSandboxMap(current) ||
314
365
  isSandboxSet(current) ||
315
366
  isSandboxPromise(current) ||
316
- isSandboxRegex(current) ||
317
- isSandboxGenerator(current))
367
+ isSandboxRegex(current))
318
368
  return undefined;
319
- if (!isSandboxClosure(current) && Object.hasOwn(current, key))
369
+ if (!isSandboxClosure(current) && !isSandboxGenerator(current) && Object.hasOwn(current, key))
320
370
  return current[key];
321
371
  current = getSandboxPrototype(current, budget);
322
372
  if (current !== null) {
@@ -330,8 +380,8 @@ export function setSandboxPrototype(value, prototype, budget) {
330
380
  if (budget !== undefined && intrinsicPrototypes.get(budget) === value && prototype !== null) {
331
381
  throw new TypeError("Object.prototype has an immutable null prototype.");
332
382
  }
333
- if ((!Array.isArray(value) && !isSandboxDate(value) && !isSandboxPromise(value) && !isSandboxRegex(value) && !isSandboxMap(value) && !isSandboxSet(value) && !isPrototypeRecord(value)) ||
334
- (prototype !== null && !Array.isArray(prototype) && !isSandboxDate(prototype) && !isSandboxPromise(prototype) && !isSandboxRegex(prototype) && !isSandboxMap(prototype) && !isSandboxSet(prototype) && !isPrototypeRecord(prototype))) {
383
+ if ((!Array.isArray(value) && !isSandboxGenerator(value) && !isSandboxDate(value) && !isSandboxPromise(value) && !isSandboxRegex(value) && !isSandboxMap(value) && !isSandboxSet(value) && !isPrototypeRecord(value)) ||
384
+ (prototype !== null && !Array.isArray(prototype) && !isSandboxGenerator(prototype) && !isSandboxDate(prototype) && !isSandboxPromise(prototype) && !isSandboxRegex(prototype) && !isSandboxMap(prototype) && !isSandboxSet(prototype) && !isPrototypeRecord(prototype))) {
335
385
  throw new TypeError("Prototype links require supported sandbox objects.");
336
386
  }
337
387
  if (getSandboxPrototype(value, budget) === prototype) {
@@ -340,7 +390,7 @@ export function setSandboxPrototype(value, prototype, budget) {
340
390
  prototypes.set(value, null);
341
391
  return;
342
392
  }
343
- if (!Object.isExtensible(isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxPromise(value) ? getPromiseProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : isSandboxMap(value) || isSandboxSet(value) ? getCollectionProperties(value) : value)) {
393
+ if (!Object.isExtensible(isSandboxGenerator(value) ? getGeneratorProperties(value) : isGuestClosure(value) ? materializeFunctionProperties(value) : isSandboxPromise(value) ? getPromiseProperties(value) : isSandboxRegex(value) ? getRegexProperties(value) : isSandboxMap(value) || isSandboxSet(value) ? getCollectionProperties(value) : value)) {
344
394
  throw new TypeError("Cannot change the prototype of a non-extensible object.");
345
395
  }
346
396
  let depth = 0;
@@ -1,4 +1,5 @@
1
1
  import { sandboxErrorTypes } from "../error/shape.js";
2
+ import { getGeneratorProperties } from "./generator-properties.js";
2
3
  import { readPropertyDescriptor } from "./accessors.js";
3
4
  import { dateString, dateTime, isSandboxDate } from "./date.js";
4
5
  import { invokeBuiltinClosure } from "./builtin-call.js";
@@ -115,7 +116,7 @@ function conversionHook(value, name, budget, context) {
115
116
  ((Array.isArray(value) && getSandboxPrototype(value, budget) === null) ||
116
117
  isFloat32Array(value) ||
117
118
  sandboxErrorTypes.has(value) ||
118
- isSandboxClosure(value) ||
119
+ (isSandboxClosure(value) && getSandboxPrototype(value, budget) === null) ||
119
120
  isSandboxMap(value) ||
120
121
  isSandboxSet(value) ||
121
122
  isSandboxCollectionIterator(value) ||
@@ -127,7 +128,7 @@ function conversionHook(value, name, budget, context) {
127
128
  let current = value;
128
129
  let depth = 0;
129
130
  while (current !== null) {
130
- const properties = isSandboxPromise(current) ? getPromiseProperties(current) : isGuestClosure(current) ? getGuestFunctionProperties(current)
131
+ const properties = isSandboxGenerator(current) ? getGeneratorProperties(current) : isSandboxPromise(current) ? getPromiseProperties(current) : isGuestClosure(current) ? getGuestFunctionProperties(current)
131
132
  : isSandboxRegex(current) ? getRegexProperties(current)
132
133
  : isSandboxMap(current) || isSandboxSet(current) ? getCollectionProperties(current) : current;
133
134
  const descriptor = properties === undefined ? undefined : Object.getOwnPropertyDescriptor(properties, name);