@poe-platform/safe-js 0.1.734 → 0.1.736

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 (56) hide show
  1. package/README.md +11 -11
  2. package/dist/safe-js/chunks/{chunk-X3CKAZQ4.js → chunk-33AKDRQ4.js} +3 -3
  3. package/dist/safe-js/chunks/{chunk-K4T4EBED.js → chunk-356QH3RB.js} +7 -3
  4. package/dist/safe-js/chunks/chunk-356QH3RB.js.map +7 -0
  5. package/dist/safe-js/chunks/{chunk-RULU2F5J.js → chunk-762WTEEI.js} +2 -2
  6. package/dist/safe-js/chunks/{chunk-E4XLBT7R.js → chunk-7AHNAUR5.js} +2 -2
  7. package/dist/safe-js/chunks/{chunk-W4SWUHCQ.js → chunk-FUUG7UIZ.js} +4 -4
  8. package/dist/safe-js/chunks/{chunk-PSVV3IG2.js → chunk-IKRAX7Z5.js} +3 -3
  9. package/dist/safe-js/chunks/{chunk-GNEORAQI.js → chunk-LELXBLG2.js} +22 -12
  10. package/dist/safe-js/chunks/chunk-LELXBLG2.js.map +7 -0
  11. package/dist/safe-js/chunks/{chunk-MDIWQFYU.js → chunk-SBFOCNNW.js} +196 -142
  12. package/dist/safe-js/chunks/{chunk-MDIWQFYU.js.map → chunk-SBFOCNNW.js.map} +3 -3
  13. package/dist/safe-js/chunks/{chunk-KETIFEA7.js → chunk-TAC75RFB.js} +2 -2
  14. package/dist/safe-js/chunks/{chunk-P64CQIUA.js → chunk-UVJ27MVC.js} +3 -3
  15. package/dist/safe-js/chunks/{chunk-QKO4FATZ.js → chunk-VQGYRKM4.js} +36 -10
  16. package/dist/safe-js/chunks/{chunk-QKO4FATZ.js.map → chunk-VQGYRKM4.js.map} +2 -2
  17. package/dist/safe-js/chunks/{chunk-O4IDRXW7.js → chunk-WDEOWDLS.js} +4 -4
  18. package/dist/safe-js/chunks/{chunk-WS2FJBH6.js → chunk-ZNAW4ZDX.js} +2 -2
  19. package/dist/safe-js/chunks/{cli-runtime-ZSOTNIVC.js → cli-runtime-FMSBDP7G.js} +11 -11
  20. package/dist/safe-js/chunks/{dump-RGRC3CG3.js → dump-2IM3WE2J.js} +4 -4
  21. package/dist/safe-js/chunks/harness-ZLV6ZBEU.js +11 -0
  22. package/dist/safe-js/chunks/{mcp-2Z4XWHKW.js → mcp-42AFDWT3.js} +4 -4
  23. package/dist/safe-js/chunks/{migration-file-KRXQYI3Q.js → migration-file-AYLLA72K.js} +5 -5
  24. package/dist/safe-js/chunks/restore-SGQO4E4M.js +14 -0
  25. package/dist/safe-js/chunks/{run-ZSFX66RN.js → run-Q5Z4TRQO.js} +7 -7
  26. package/dist/safe-js/chunks/{runtime-modules-A3U2DKFL.js → runtime-modules-3P6FZJ55.js} +4 -4
  27. package/dist/safe-js/cli.js +2 -2
  28. package/dist/safe-js/core.js +7 -7
  29. package/dist/safe-js/index.js +13 -13
  30. package/dist/safe-js/interp/host-bridge.d.ts +3 -1
  31. package/dist/safe-js/interp/host-capabilities.d.ts +5 -5
  32. package/dist/safe-js/modules/fs.d.ts +4 -1
  33. package/dist/safe-js/modules/fs.js +3 -3
  34. package/dist/safe-js/snapshot/validation.d.ts +1 -1
  35. package/package.json +2 -2
  36. package/dist/safe-js/chunks/chunk-GNEORAQI.js.map +0 -7
  37. package/dist/safe-js/chunks/chunk-K4T4EBED.js.map +0 -7
  38. package/dist/safe-js/chunks/harness-UMOMFXDT.js +0 -11
  39. package/dist/safe-js/chunks/restore-GEO7VN2R.js +0 -14
  40. /package/dist/safe-js/chunks/{chunk-X3CKAZQ4.js.map → chunk-33AKDRQ4.js.map} +0 -0
  41. /package/dist/safe-js/chunks/{chunk-RULU2F5J.js.map → chunk-762WTEEI.js.map} +0 -0
  42. /package/dist/safe-js/chunks/{chunk-E4XLBT7R.js.map → chunk-7AHNAUR5.js.map} +0 -0
  43. /package/dist/safe-js/chunks/{chunk-W4SWUHCQ.js.map → chunk-FUUG7UIZ.js.map} +0 -0
  44. /package/dist/safe-js/chunks/{chunk-PSVV3IG2.js.map → chunk-IKRAX7Z5.js.map} +0 -0
  45. /package/dist/safe-js/chunks/{chunk-KETIFEA7.js.map → chunk-TAC75RFB.js.map} +0 -0
  46. /package/dist/safe-js/chunks/{chunk-P64CQIUA.js.map → chunk-UVJ27MVC.js.map} +0 -0
  47. /package/dist/safe-js/chunks/{chunk-O4IDRXW7.js.map → chunk-WDEOWDLS.js.map} +0 -0
  48. /package/dist/safe-js/chunks/{chunk-WS2FJBH6.js.map → chunk-ZNAW4ZDX.js.map} +0 -0
  49. /package/dist/safe-js/chunks/{cli-runtime-ZSOTNIVC.js.map → cli-runtime-FMSBDP7G.js.map} +0 -0
  50. /package/dist/safe-js/chunks/{dump-RGRC3CG3.js.map → dump-2IM3WE2J.js.map} +0 -0
  51. /package/dist/safe-js/chunks/{harness-UMOMFXDT.js.map → harness-ZLV6ZBEU.js.map} +0 -0
  52. /package/dist/safe-js/chunks/{mcp-2Z4XWHKW.js.map → mcp-42AFDWT3.js.map} +0 -0
  53. /package/dist/safe-js/chunks/{migration-file-KRXQYI3Q.js.map → migration-file-AYLLA72K.js.map} +0 -0
  54. /package/dist/safe-js/chunks/{restore-GEO7VN2R.js.map → restore-SGQO4E4M.js.map} +0 -0
  55. /package/dist/safe-js/chunks/{run-ZSFX66RN.js.map → run-Q5Z4TRQO.js.map} +0 -0
  56. /package/dist/safe-js/chunks/{runtime-modules-A3U2DKFL.js.map → runtime-modules-3P6FZJ55.js.map} +0 -0
@@ -40,7 +40,7 @@ import {
40
40
  sandboxErrorTypes,
41
41
  syntaxDiagnostics,
42
42
  templateRealms
43
- } from "./chunk-QKO4FATZ.js";
43
+ } from "./chunk-VQGYRKM4.js";
44
44
  import {
45
45
  AsyncLocalStorage,
46
46
  cloneSharedBufferWrapper,
@@ -514,7 +514,7 @@ function getGeneratorProperties(value) {
514
514
  }
515
515
 
516
516
  // packages/safe-js/src/graph-depth.ts
517
- var MAX_DATA_DEPTH = 1024;
517
+ var MAX_DATA_DEPTH = Infinity;
518
518
  var SnapshotBudgetError = class extends Error {
519
519
  code = "budgetExceeded";
520
520
  budget = "dataDepth";
@@ -530,19 +530,21 @@ var SnapshotBudgetError = class extends Error {
530
530
  replaceErrorStack(this);
531
531
  }
532
532
  };
533
- function assertSandboxDataDepth(depth) {
534
- if (depth > MAX_DATA_DEPTH) {
535
- throw new SandboxError({ budget: "dataDepth", current: depth, limit: MAX_DATA_DEPTH });
533
+ function assertSandboxDataDepth(depth, limit = MAX_DATA_DEPTH) {
534
+ if (depth > limit) {
535
+ throw new SandboxError({ budget: "dataDepth", current: depth, limit });
536
536
  }
537
537
  }
538
- function assertSnapshotDataDepth(depth, path) {
539
- if (depth > MAX_DATA_DEPTH) throw new SnapshotBudgetError(path, depth);
538
+ function assertSnapshotDataDepth(depth, path, limit = MAX_DATA_DEPTH) {
539
+ if (depth > limit) throw new SnapshotBudgetError(path, depth, limit);
540
540
  }
541
- function assertSnapshotGraphDepth(value, rootPath = "$") {
542
- walkGraphDepth(value, rootPath, (depth, path) => assertSnapshotDataDepth(depth, path));
541
+ function assertSnapshotGraphDepth(value, rootPath = "$", limit = MAX_DATA_DEPTH) {
542
+ if (limit === Infinity) return;
543
+ walkGraphDepth(value, rootPath, (depth, path) => assertSnapshotDataDepth(depth, path, limit));
543
544
  }
544
- function assertSandboxGraphDepth(value) {
545
- walkGraphDepth(value, "<root>", (depth) => assertSandboxDataDepth(depth));
545
+ function assertSandboxGraphDepth(value, limit = MAX_DATA_DEPTH) {
546
+ if (limit === Infinity) return;
547
+ walkGraphDepth(value, "<root>", (depth) => assertSandboxDataDepth(depth, limit));
546
548
  }
547
549
  function walkGraphDepth(root, rootPath, assertDepth) {
548
550
  const ancestors = /* @__PURE__ */ new WeakSet();
@@ -2567,9 +2569,6 @@ function serializedDateTime(value) {
2567
2569
  }
2568
2570
 
2569
2571
  // packages/safe-js/src/interp/host-capabilities.ts
2570
- var MAX_INDEXED_LENGTH = 65536;
2571
- var MAX_NAMED_KEYS = 65536;
2572
- var MAX_NAMED_KEY_CODE_UNITS = 1048576;
2573
2572
  var hostObjects = /* @__PURE__ */ new WeakMap();
2574
2573
  var guestObjects = /* @__PURE__ */ new WeakMap();
2575
2574
  var readHostObject = WeakMap.prototype.get.bind(hostObjects);
@@ -2617,6 +2616,12 @@ function revokeGuestReference(reference, owner) {
2617
2616
  if (state === void 0 || state.owner !== owner) throw new TypeError("Foreign guest reference.");
2618
2617
  state.root = void 0;
2619
2618
  }
2619
+ function hostObjectLimit(value, name) {
2620
+ if (value === void 0 || value === Infinity) return Infinity;
2621
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 1)
2622
+ throw new RangeError(`${name} must be a positive integer or Infinity.`);
2623
+ return value;
2624
+ }
2620
2625
  function createLiveHostObject(definition, controller) {
2621
2626
  const input = readDataRecord(definition, "Host object definition");
2622
2627
  if (Object.keys(input).some((key) => !["properties", "methods", "indexed", "named", "expandos"].includes(key)))
@@ -2626,17 +2631,15 @@ function createLiveHostObject(definition, controller) {
2626
2631
  const data = readDataRecord(input.expandos, "Guest expando definition");
2627
2632
  if (Object.keys(data).some((key) => !["maxKeys", "maxKeyCodeUnits", "assertActive"].includes(key)))
2628
2633
  throw new TypeError("Unknown guest expando field.");
2629
- for (const [key, maximum] of [["maxKeys", MAX_NAMED_KEYS], ["maxKeyCodeUnits", MAX_NAMED_KEY_CODE_UNITS]]) {
2630
- if (typeof data[key] !== "number" || !Number.isInteger(data[key]) || data[key] < 1 || data[key] > maximum)
2631
- throw new RangeError(`Guest expando ${key} must be an integer from 1 to ${maximum}.`);
2632
- }
2634
+ const maxKeys = hostObjectLimit(data.maxKeys, "Guest expando maxKeys");
2635
+ const maxKeyCodeUnits = hostObjectLimit(data.maxKeyCodeUnits, "Guest expando maxKeyCodeUnits");
2633
2636
  if (data.assertActive !== void 0 && (typeof data.assertActive !== "function" || types.isProxy(data.assertActive) || types.isAsyncFunction(data.assertActive) || types.isGeneratorFunction(data.assertActive)))
2634
2637
  throw new TypeError("Guest expando assertActive must be a synchronous function, not a proxy.");
2635
2638
  expandos = {
2636
2639
  // Owned writes invalidate descriptor projections; descendants stay live.
2637
2640
  values: createIntrinsicObject(),
2638
- maxKeys: data.maxKeys,
2639
- maxKeyCodeUnits: data.maxKeyCodeUnits,
2641
+ maxKeys,
2642
+ maxKeyCodeUnits,
2640
2643
  assertActive: data.assertActive
2641
2644
  };
2642
2645
  }
@@ -2647,12 +2650,11 @@ function createLiveHostObject(definition, controller) {
2647
2650
  throw new TypeError("Unknown indexed host capability field.");
2648
2651
  if (typeof data.length !== "function" || typeof data.get !== "function")
2649
2652
  throw new TypeError("Indexed length and get must be synchronous functions.");
2650
- if (typeof data.maxLength !== "number" || !Number.isInteger(data.maxLength) || data.maxLength < 1 || data.maxLength > MAX_INDEXED_LENGTH)
2651
- throw new RangeError(`Indexed maxLength must be an integer from 1 to ${MAX_INDEXED_LENGTH}.`);
2653
+ const maxLength = hostObjectLimit(data.maxLength, "Indexed maxLength");
2652
2654
  indexed = {
2653
2655
  length: data.length,
2654
2656
  get: data.get,
2655
- maxLength: data.maxLength
2657
+ maxLength
2656
2658
  };
2657
2659
  }
2658
2660
  let named;
@@ -2668,12 +2670,8 @@ function createLiveHostObject(definition, controller) {
2668
2670
  if (typeof operation !== "function" || types.isProxy(operation) || types.isAsyncFunction(operation) || types.isGeneratorFunction(operation))
2669
2671
  throw new TypeError(`Named ${name} must be a synchronous non-generator function, not a proxy.`);
2670
2672
  }
2671
- if (typeof data.maxKeys !== "number" || !Number.isInteger(data.maxKeys) || data.maxKeys < 1 || data.maxKeys > MAX_NAMED_KEYS)
2672
- throw new RangeError(`Named maxKeys must be an integer from 1 to ${MAX_NAMED_KEYS}.`);
2673
- if (typeof data.maxKeyCodeUnits !== "number" || !Number.isInteger(data.maxKeyCodeUnits) || data.maxKeyCodeUnits < 1 || data.maxKeyCodeUnits > MAX_NAMED_KEY_CODE_UNITS)
2674
- throw new RangeError(
2675
- `Named maxKeyCodeUnits must be an integer from 1 to ${MAX_NAMED_KEY_CODE_UNITS}.`
2676
- );
2673
+ const maxKeys = hostObjectLimit(data.maxKeys, "Named maxKeys");
2674
+ const maxKeyCodeUnits = hostObjectLimit(data.maxKeyCodeUnits, "Named maxKeyCodeUnits");
2677
2675
  if (data.enumerable !== void 0 && typeof data.enumerable !== "boolean")
2678
2676
  throw new TypeError("Named enumerable must be a boolean.");
2679
2677
  named = {
@@ -2681,8 +2679,8 @@ function createLiveHostObject(definition, controller) {
2681
2679
  get: data.get,
2682
2680
  set: data.set,
2683
2681
  delete: data.delete,
2684
- maxKeys: data.maxKeys,
2685
- maxKeyCodeUnits: data.maxKeyCodeUnits,
2682
+ maxKeys,
2683
+ maxKeyCodeUnits,
2686
2684
  enumerable: data.enumerable
2687
2685
  };
2688
2686
  }
@@ -19829,7 +19827,6 @@ async function numberFormatValue(value, budget, context) {
19829
19827
  }
19830
19828
  return Number(primitive);
19831
19829
  }
19832
- var MAX_FORMAT_ALLOCATION = 16 * 1024 * 1024;
19833
19830
  function formatNumberValue(receiver, method, values, budget) {
19834
19831
  const { native, options } = numberFormatState(receiver);
19835
19832
  const magnitudes = values.map((value) => typeof value === "bigint" ? value.toString(16).length * 2 : typeof value === "string" ? value.length : 309);
@@ -19844,8 +19841,6 @@ function formatNumberValue(receiver, method, values, budget) {
19844
19841
  }
19845
19842
  const bytes = parts * 256 + characters * 2 + magnitudes.reduce((sum, digits2) => sum + digits2 * 16, 0);
19846
19843
  if (method.endsWith("ToParts")) budget.allocateArrayLength(parts);
19847
- const totalBytes = budget.currentDataSize + bytes;
19848
- if (totalBytes > MAX_FORMAT_ALLOCATION) throw new SandboxError({ budget: "dataSize", current: totalBytes, limit: MAX_FORMAT_ALLOCATION });
19849
19844
  const reservation = {};
19850
19845
  budget.setRetainedDataUsage(reservation, bytes);
19851
19846
  try {
@@ -21924,6 +21919,10 @@ var hostErrorMetadata = {
21924
21919
  syscall: "string"
21925
21920
  };
21926
21921
  var awaitedHostOperations = /* @__PURE__ */ new WeakSet();
21922
+ var scheduledCallbackOperations = /* @__PURE__ */ new WeakSet();
21923
+ function schedulesHostCallbacks(operation) {
21924
+ return scheduledCallbackOperations.has(operation);
21925
+ }
21927
21926
  var budgetedHostOperations = /* @__PURE__ */ new WeakMap();
21928
21927
  function declareBudgetedHostOperation(operation, invoke) {
21929
21928
  budgetedHostOperations.set(operation, invoke);
@@ -21931,7 +21930,11 @@ function declareBudgetedHostOperation(operation, invoke) {
21931
21930
  var hostOperationPolicies = /* @__PURE__ */ new WeakMap();
21932
21931
  var hostOperationReplayHandlers = /* @__PURE__ */ new WeakMap();
21933
21932
  function declareHostOperation(operation, policy, options = {}) {
21933
+ if (options.callbackScheduling !== void 0 && options.callbackScheduling !== "after-prefix") throw new TypeError("Host callbackScheduling must be after-prefix.");
21934
+ if (options.callbackScheduling === "after-prefix" && options.awaitResult === true) throw new TypeError("Queued callbacks cannot be combined with awaitResult.");
21934
21935
  hostOperationPolicies.set(operation, policy);
21936
+ if (options.callbackScheduling === "after-prefix") scheduledCallbackOperations.add(operation);
21937
+ else scheduledCallbackOperations.delete(operation);
21935
21938
  if (options.awaitResult === true) awaitedHostOperations.add(operation);
21936
21939
  else awaitedHostOperations.delete(operation);
21937
21940
  if (options.onReplay !== void 0) hostOperationReplayHandlers.set(operation, options.onReplay);
@@ -21970,6 +21973,7 @@ function wrapCallerInjectedFunction(name, value, options, state) {
21970
21973
  const bindingName = typeof nativeName === "string" && nativeName.length > 0 ? nativeName : name;
21971
21974
  const callable = value;
21972
21975
  const awaitResult = awaitedHostOperations.has(value) || options.realm?.awaitResult(callable) === true;
21976
+ if (awaitResult && schedulesHostCallbacks(callable)) throw new TypeError("Queued callbacks cannot be combined with awaitResult or nestedOperation.");
21973
21977
  return createSandboxClosure({
21974
21978
  ...isAsyncFunction(callable) && !awaitResult ? { async: true } : {},
21975
21979
  cancellationSignal: options.signal,
@@ -21981,6 +21985,7 @@ function wrapCallerInjectedFunction(name, value, options, state) {
21981
21985
  if (options.signal?.aborted) throw readAbortReason2(options.signal);
21982
21986
  const stackFrames = context?.stack ?? [];
21983
21987
  const callbacks = {
21988
+ ...schedulesHostCallbacks(callable) ? { schedule: captureJobScheduler() } : {},
21984
21989
  journal: options.hostCalls,
21985
21990
  entries: /* @__PURE__ */ new Map(),
21986
21991
  hostFunctions: /* @__PURE__ */ new Map(),
@@ -22002,7 +22007,8 @@ function wrapCallerInjectedFunction(name, value, options, state) {
22002
22007
  stackFrames,
22003
22008
  options.budget,
22004
22009
  operationLease.owner,
22005
- callbacks
22010
+ callbacks,
22011
+ options.signal
22006
22012
  ))
22007
22013
  });
22008
22014
  const captured = options.realm?.captureArguments(callable, args, copyArguments);
@@ -22427,18 +22433,19 @@ function copyHostErrorMetadata(error, reason, budget, chargeBudget) {
22427
22433
  resumeChecks?.();
22428
22434
  }
22429
22435
  }
22430
- function wrapSandboxClosureForHost(closure, stackFrames, budget, compileOwner, callbacks) {
22436
+ function wrapSandboxClosureForHost(closure, stackFrames, budget, compileOwner, callbacks, signal) {
22431
22437
  const existing = callbacks?.seen.get(closure);
22432
22438
  if (existing !== void 0) return existing;
22433
22439
  const id = (callbacks?.entries.size ?? 0) + 1;
22434
- const invoke = async (sandboxArgs, token, receiver) => {
22440
+ const invokeNow = async (sandboxArgs, token, receiver) => {
22435
22441
  const operation = budget.acquireCompileOwner(false, compileOwner);
22436
22442
  const compilation = new CompileScope(operation.owner);
22437
22443
  let leaveRunning;
22438
22444
  let leaveCall;
22439
- const wrapClosure = (nestedClosure) => wrapSandboxClosureForHost(nestedClosure, stackFrames, budget, compileOwner, callbacks);
22445
+ const wrapClosure = (nestedClosure) => wrapSandboxClosureForHost(nestedClosure, stackFrames, budget, compileOwner, callbacks, signal);
22440
22446
  const onSharedBuffer = callbacks?.journal?.markSharedCallbackExport.bind(callbacks.journal);
22441
22447
  try {
22448
+ signal?.throwIfAborted();
22442
22449
  leaveRunning = enterRunningState(closure);
22443
22450
  leaveCall = budget.enterCall();
22444
22451
  let result;
@@ -22454,6 +22461,7 @@ function wrapSandboxClosureForHost(closure, stackFrames, budget, compileOwner, c
22454
22461
  invokeClosure: (target, values, receiver2, construct, newTarget) => invokeBuiltinClosure(target, values, budget, callerContext, receiver2, construct, newTarget)
22455
22462
  };
22456
22463
  result = guestProxyStates.has(closure) ? await callGuestProxy(closure, sandboxArgs, budget, bridge, receiver) : closure.call(sandboxArgs, { compilation, stack: stackFrames, thisValue: receiver });
22464
+ if (callbacks?.schedule !== void 0) result = await result;
22457
22465
  } catch (error) {
22458
22466
  if (isSandboxLikeValue(error)) {
22459
22467
  throw deepCopyFromSandbox(error, {
@@ -22464,11 +22472,17 @@ function wrapSandboxClosureForHost(closure, stackFrames, budget, compileOwner, c
22464
22472
  }
22465
22473
  throw error;
22466
22474
  }
22467
- return await deepCopyFromSandbox(normalizeClosureResult(result, budget), {
22475
+ const settlement = deepCopyFromSandbox(normalizeClosureResult(result, budget), {
22468
22476
  compilation,
22469
22477
  wrapClosure,
22470
22478
  onSharedBuffer
22471
22479
  });
22480
+ if (callbacks?.schedule !== void 0) {
22481
+ void settlement.catch(() => void 0);
22482
+ if (isSandboxPromise(result) && result.synchronousPrefix !== void 0) await result.synchronousPrefix;
22483
+ return await suspendJob(settlement);
22484
+ }
22485
+ return await settlement;
22472
22486
  } catch (error) {
22473
22487
  if (isFatalBridgeError(error)) promiseReplayContext.getStore()?.fail(error);
22474
22488
  throw error;
@@ -22480,6 +22494,7 @@ function wrapSandboxClosureForHost(closure, stackFrames, budget, compileOwner, c
22480
22494
  if (token !== void 0) promiseReplayContext.getStore()?.completeCallback(token);
22481
22495
  }
22482
22496
  };
22497
+ const invoke = callbacks?.schedule === void 0 ? invokeNow : (args, token, receiver) => callbacks.schedule(() => invokeNow(args, token, receiver));
22483
22498
  const wrapped = async function(...args) {
22484
22499
  const operation = budget.acquireCompileOwner(false, compileOwner);
22485
22500
  try {
@@ -31327,7 +31342,6 @@ function admitJson(text, budget) {
31327
31342
  }
31328
31343
  if (character === '"') quoted = true;
31329
31344
  else if (character === "[" || character === "{") {
31330
- if (frames.length >= 256) throw new SandboxError({ budget: "dataDepth", current: frames.length + 1, limit: 256 });
31331
31345
  const leave = budget.enterCall();
31332
31346
  frames.push({ array: character === "[", entries: 0, expectingValue: true, leave });
31333
31347
  } else if (character === "]" || character === "}") frames.pop()?.leave();
@@ -41288,7 +41302,7 @@ function intrinsicCatalogue() {
41288
41302
  const kinds = /* @__PURE__ */ new Map();
41289
41303
  for (const id of listIntrinsicIdentities(budget)) {
41290
41304
  const value = resolveIntrinsicIdentity(budget, id);
41291
- if (getIntrinsicIdentity(value) === id) kinds.set(id, isSandboxClosure(value));
41305
+ if (getIntrinsicIdentity(value) === id) kinds.set(id, { callable: isSandboxClosure(value), constructible: isSandboxClosure(value) && value.construct !== void 0 });
41292
41306
  }
41293
41307
  intrinsicKinds = kinds;
41294
41308
  return kinds;
@@ -41296,6 +41310,28 @@ function intrinsicCatalogue() {
41296
41310
  releaseObjectPrototype(budget);
41297
41311
  }
41298
41312
  }
41313
+ function targetFlags(node) {
41314
+ if (node.kind === "bound-function") return void 0;
41315
+ if (node.kind === "guest-proxy") return { callable: node.callable === true, constructible: node.constructible === true };
41316
+ if (node.kind === "intrinsic") return intrinsicCatalogue().get(String(node.id));
41317
+ if (node.kind === "guest-function" || node.kind === "module-function") return { callable: true };
41318
+ if (node.kind === "guest-class") return { callable: true, constructible: true };
41319
+ return { callable: [
41320
+ "guest-proxy-revoker",
41321
+ "async-generator-handler",
41322
+ "async-function-handler",
41323
+ "async-cleanup-handler",
41324
+ "thenable-resolver",
41325
+ "aggregate-handler",
41326
+ "adoption-resolver",
41327
+ "capability-executor",
41328
+ "promise-resolver"
41329
+ ].includes(String(node.kind)), constructible: false };
41330
+ }
41331
+ function validateProxyFlags(node, flags) {
41332
+ if (node.callable !== flags.callable || flags.constructible !== void 0 && node.constructible !== flags.constructible)
41333
+ throw new TypeError("Inconsistent Proxy callable flags.");
41334
+ }
41299
41335
  function record3(value) {
41300
41336
  if (value === null || typeof value !== "object" || Array.isArray(value)) throw new TypeError("Expected a guest heap record.");
41301
41337
  return value;
@@ -41316,7 +41352,7 @@ function absent(value) {
41316
41352
  const node = record3(value);
41317
41353
  return node.kind === "undefined" && Object.keys(node).length === 1;
41318
41354
  }
41319
- function validateGuestHeapNode(raw, heap, maxArrayLength = 4294967295) {
41355
+ function validateGuestHeapNode(raw, heap, maxArrayLength = Infinity) {
41320
41356
  if (record3(raw).kind === "guest-script") {
41321
41357
  const source = record3(raw);
41322
41358
  fields(source, ["kind", "body", "context"]);
@@ -41420,7 +41456,7 @@ function validateGuestHeapNode(raw, heap, maxArrayLength = 4294967295) {
41420
41456
  const target = reference(value, ["guest-proxy", "guest-proxy-revoker", "module-function", "async-generator-handler", "async-function-handler", "async-cleanup-handler", "thenable-resolver", "aggregate-handler", "capability-executor", "intrinsic", "bound-function", "promise-resolver", "guest-function", "guest-class"]);
41421
41457
  if (target.kind === "guest-proxy" && target.callable !== true)
41422
41458
  throw new TypeError("Guest accessor Proxy is not callable.");
41423
- if (target.kind === "intrinsic" && intrinsicCatalogue().get(String(target.id)) !== true)
41459
+ if (target.kind === "intrinsic" && intrinsicCatalogue().get(String(target.id))?.callable !== true)
41424
41460
  throw new TypeError("Guest accessor reference is not callable.");
41425
41461
  };
41426
41462
  if ((node.kind === "pending-promise" || node.kind === "guest-promise") && Object.hasOwn(node, "generatorOwner")) {
@@ -41511,17 +41547,9 @@ function validateGuestHeapNode(raw, heap, maxArrayLength = 4294967295) {
41511
41547
  if (node.target === null !== (node.handler === null)) throw new TypeError("Invalid revoked Proxy state.");
41512
41548
  if (node.target !== null) {
41513
41549
  reference(node.handler, objectKinds);
41514
- const seen = /* @__PURE__ */ new Set([node]);
41515
- let current = node;
41516
- while (current.kind === "guest-proxy" && current.target !== null) {
41517
- assertSnapshotDataDepth(seen.size, "Proxy target chain");
41518
- const target = reference(current.target, objectKinds);
41519
- if (seen.has(target)) throw new TypeError("Cyclic Proxy target chain.");
41520
- seen.add(target);
41521
- if (target.kind === "guest-proxy" && (target.callable !== current.callable || target.constructible !== current.constructible))
41522
- throw new TypeError("Inconsistent Proxy callable flags.");
41523
- current = target;
41524
- }
41550
+ const target = reference(node.target, objectKinds);
41551
+ const flags = targetFlags(target);
41552
+ if (flags !== void 0) validateProxyFlags(node, flags);
41525
41553
  }
41526
41554
  if (node.privateElements !== void 0) privateState(node.privateElements);
41527
41555
  } else if (node.kind === "guest-proxy-revoker") {
@@ -42298,15 +42326,8 @@ function validateGuestHeapNode(raw, heap, maxArrayLength = 4294967295) {
42298
42326
  if (array(node.args).length > maxArrayLength) throw new TypeError("Bound arguments exceed allocation limit.");
42299
42327
  if (!absent(node.length) && !(typeof node.length === "number" && node.length >= 0) && !(record3(node.length).kind === "number" && record3(node.length).value === "Infinity"))
42300
42328
  throw new TypeError("Invalid bound function length.");
42301
- const visited = /* @__PURE__ */ new Set([raw]);
42302
- let current = node;
42303
- while (current.kind === "bound-function") {
42304
- assertSnapshotDataDepth(visited.size, "<bound-target>");
42305
- callable(current.target);
42306
- current = reference(current.target);
42307
- if (visited.has(current)) throw new TypeError("Cyclic bound function target.");
42308
- visited.add(current);
42309
- }
42329
+ callable(node.target);
42330
+ reference(node.target);
42310
42331
  state(node.state);
42311
42332
  } else if (node.kind === "guest-function") {
42312
42333
  fields(node, ["kind", "astNodeId", "scope", "state"], ["name", "environment", "dynamicSource", "realm"]);
@@ -42661,20 +42682,47 @@ function validateGuestHeapGraphs(heap) {
42661
42682
  ["scope-frame", "parent", "Cyclic guest scope parent graph."],
42662
42683
  ["promise-reaction", "source", "Cyclic promise reaction source graph."]
42663
42684
  ]) {
42664
- const finished = /* @__PURE__ */ new Set();
42685
+ const finished2 = /* @__PURE__ */ new Set();
42665
42686
  for (const [id, raw] of Object.entries(heap)) {
42666
- if (record3(raw).kind !== kind || finished.has(id)) continue;
42687
+ if (record3(raw).kind !== kind || finished2.has(id)) continue;
42667
42688
  const path = /* @__PURE__ */ new Set();
42668
42689
  let current = id;
42669
- while (current !== void 0 && !finished.has(current)) {
42690
+ while (current !== void 0 && !finished2.has(current)) {
42670
42691
  if (path.has(current)) throw new TypeError(message);
42671
42692
  const node = record3(heap[current]);
42672
42693
  if (node.kind !== kind) break;
42673
42694
  path.add(current);
42674
42695
  const parent = node[edge];
42675
- current = absent(parent) ? void 0 : String(record3(parent).id);
42696
+ current = parent === null || absent(parent) ? void 0 : String(record3(parent).id);
42697
+ }
42698
+ for (const visited of path) finished2.add(visited);
42699
+ }
42700
+ }
42701
+ const finished = /* @__PURE__ */ new Map();
42702
+ for (const [id, raw] of Object.entries(heap)) {
42703
+ const root = record3(raw);
42704
+ if (root.kind !== "guest-proxy" && root.kind !== "bound-function" || finished.has(id)) continue;
42705
+ const path = /* @__PURE__ */ new Map();
42706
+ let current = id;
42707
+ let flags = finished.get(current);
42708
+ while (flags === void 0) {
42709
+ if (path.has(current)) throw new TypeError(root.kind === "guest-proxy" ? "Cyclic Proxy target chain." : "Cyclic bound function target.");
42710
+ const node = record3(heap[current]);
42711
+ if (node.kind !== "guest-proxy" && node.kind !== "bound-function" || node.target === null) {
42712
+ flags = targetFlags(node);
42713
+ if (flags === void 0) throw new TypeError("Invalid function target.");
42714
+ break;
42715
+ }
42716
+ path.set(current, node);
42717
+ current = String(record3(node.target).id);
42718
+ flags = finished.get(current);
42719
+ }
42720
+ for (const [visited, node] of [...path].reverse()) {
42721
+ if (node.kind === "guest-proxy") {
42722
+ validateProxyFlags(node, flags);
42723
+ flags = targetFlags(node);
42676
42724
  }
42677
- for (const visited of path) finished.add(visited);
42725
+ finished.set(visited, flags);
42678
42726
  }
42679
42727
  }
42680
42728
  }
@@ -42956,9 +43004,6 @@ function checkArray(properties, values, cooked) {
42956
43004
  }
42957
43005
 
42958
43006
  // packages/safe-js/src/snapshot/validation.ts
42959
- var DEFAULT_MAX_ENTRIES = 1e5;
42960
- var DEFAULT_MAX_STRING_LENGTH = 1e6;
42961
- var DEFAULT_MAX_DATA_SIZE = 16e6;
42962
43007
  var TAGGED_VALUE_KINDS = /* @__PURE__ */ new Set([
42963
43008
  "arguments",
42964
43009
  "array",
@@ -42989,23 +43034,21 @@ function validateSnapshotData(value) {
42989
43034
  validateGenericValue(value, "$", 0, {
42990
43035
  allowFunctions: false,
42991
43036
  allowUndefined: false,
42992
- entries: 0,
42993
43037
  dataSize: 0,
42994
- limits: defaultLimits(),
43038
+ limits: limitsFromBudget(),
42995
43039
  validateTaggedPayloads: false,
42996
43040
  dataPropertiesOnly: true,
42997
43041
  dataPrototypes: /* @__PURE__ */ new WeakSet()
42998
43042
  });
42999
43043
  }
43000
43044
  function validateDumpEnvelope(snapshot, options = {}) {
43001
- const limits = defaultLimits();
43045
+ const limits = limitsFromBudget();
43002
43046
  const root = requireRecord(snapshot, "$");
43003
43047
  const trusted = inMemoryRunSnapshots.has(root);
43004
43048
  const state = {
43005
43049
  allowHostFunctionState: trusted,
43006
43050
  allowFunctions: trusted,
43007
43051
  allowUndefined: true,
43008
- entries: 0,
43009
43052
  dataSize: 0,
43010
43053
  limits,
43011
43054
  validateTaggedPayloads: false,
@@ -43590,80 +43633,91 @@ function validateSnapshotProxy(value, path, dataPropertiesOnly = false) {
43590
43633
  }
43591
43634
  }
43592
43635
  function validateGenericValue(value, path, depth, state) {
43593
- validateSnapshotProxy(value, path, state.dataPropertiesOnly);
43594
- if (typeof value === "object" && value !== null && hasGuestObjectState(value) && !(state.allowHostFunctionState && (isSandboxModuleNamespace(value) || isSandboxClosure(value) && !isGuestClosure(value)))) {
43595
- fail("invalidState", path, "guest function properties, prototype links and custom descriptors cannot be restored");
43596
- }
43597
- if (depth > state.limits.maxDepth)
43598
- fail("budgetExceeded", path, `exceeds nesting limit ${state.limits.maxDepth}`);
43599
- state.entries += 1;
43600
- if (state.entries > state.limits.maxAggregateEntries)
43601
- fail(
43602
- "budgetExceeded",
43603
- path,
43604
- `exceeds aggregate entry limit ${state.limits.maxAggregateEntries}`
43605
- );
43606
- if (typeof value === "string") {
43607
- requireString(value, path, state.limits);
43608
- state.dataSize += value.length;
43609
- } else if (Array.isArray(value)) {
43610
- if (value.length > state.limits.maxEntries) fail("budgetExceeded", path, "array is too large");
43611
- if (state.dataPropertiesOnly) {
43612
- const entries = snapshotDataEntries(value, path, state.dataPrototypes).filter(([key]) => key !== "length");
43613
- if (entries.length !== value.length)
43614
- fail("invalidType", path, "snapshot arrays must be dense");
43615
- for (const [key, entry] of entries) {
43616
- const index = Number(key);
43617
- if (!Number.isInteger(index) || index < 0 || index >= value.length || String(index) !== key) {
43618
- fail("invalidType", path, "snapshot arrays cannot have named properties");
43636
+ const pending = [{ value, path, depth }];
43637
+ const ancestors = /* @__PURE__ */ new WeakSet();
43638
+ while (pending.length > 0) {
43639
+ const frame = pending.pop();
43640
+ if ("exit" in frame) {
43641
+ ancestors.delete(frame.exit);
43642
+ continue;
43643
+ }
43644
+ const { value: value2, path: path2, depth: depth2, key } = frame;
43645
+ if (key !== void 0) {
43646
+ requireString(key, path2, state.limits);
43647
+ state.dataSize += key.length;
43648
+ }
43649
+ validateSnapshotProxy(value2, path2, state.dataPropertiesOnly);
43650
+ if (typeof value2 === "object" && value2 !== null && hasGuestObjectState(value2) && !(state.allowHostFunctionState && (isSandboxModuleNamespace(value2) || isSandboxClosure(value2) && !isGuestClosure(value2)))) {
43651
+ fail("invalidState", path2, "guest function properties, prototype links and custom descriptors cannot be restored");
43652
+ }
43653
+ if (depth2 > state.limits.maxDepth)
43654
+ fail("budgetExceeded", path2, `exceeds nesting limit ${state.limits.maxDepth}`);
43655
+ if (typeof value2 === "object" && value2 !== null) {
43656
+ if (ancestors.has(value2)) {
43657
+ if (state.dataPropertiesOnly) fail("invalidCycle", path2, "snapshot data cannot contain cycles");
43658
+ continue;
43659
+ }
43660
+ ancestors.add(value2);
43661
+ pending.push({ exit: value2 });
43662
+ }
43663
+ if (typeof value2 === "string") {
43664
+ requireString(value2, path2, state.limits);
43665
+ state.dataSize += value2.length;
43666
+ } else if (Array.isArray(value2)) {
43667
+ if (value2.length > state.limits.maxEntries) fail("budgetExceeded", path2, "array is too large");
43668
+ if (state.dataPropertiesOnly) {
43669
+ const entries = snapshotDataEntries(value2, path2, state.dataPrototypes).filter(([key2]) => key2 !== "length");
43670
+ if (entries.length !== value2.length)
43671
+ fail("invalidType", path2, "snapshot arrays must be dense");
43672
+ for (const [key2, entry] of entries.reverse()) {
43673
+ const index = Number(key2);
43674
+ if (!Number.isInteger(index) || index < 0 || index >= value2.length || String(index) !== key2) {
43675
+ fail("invalidType", path2, "snapshot arrays cannot have named properties");
43676
+ }
43677
+ pending.push({ value: entry, path: `${path2}[${key2}]`, depth: depth2 + 1 });
43678
+ }
43679
+ } else {
43680
+ for (const [key2, entry] of ownSnapshotDataEntries(value2, path2, true).reverse()) {
43681
+ const index = Number(key2);
43682
+ if (Number.isInteger(index) && index >= 0 && index < value2.length && String(index) === key2)
43683
+ pending.push({ value: entry, path: `${path2}[${index}]`, depth: depth2 + 1 });
43619
43684
  }
43620
- validateGenericValue(entry, `${path}[${key}]`, depth + 1, state);
43621
43685
  }
43622
- } else {
43623
- for (const [key, entry] of ownSnapshotDataEntries(value, path, true)) {
43624
- const index = Number(key);
43625
- if (Number.isInteger(index) && index >= 0 && index < value.length && String(index) === key)
43626
- validateGenericValue(entry, `${path}[${index}]`, depth + 1, state);
43686
+ } else if (value2 !== null && typeof value2 === "object") {
43687
+ const record4 = value2;
43688
+ if (state.validateTaggedPayloads && isTaggedValueShape(record4)) {
43689
+ validateTaggedValue(record4, path2, state);
43627
43690
  }
43628
- }
43629
- } else if (value !== null && typeof value === "object") {
43630
- const record4 = value;
43631
- if (state.validateTaggedPayloads && isTaggedValueShape(record4)) {
43632
- validateTaggedValue(record4, path, state);
43633
- }
43634
- const entries = state.dataPropertiesOnly ? snapshotDataEntries(value, path, state.dataPrototypes) : ownSnapshotDataEntries(value, path, true);
43635
- if (state.dataPropertiesOnly) {
43636
- for (const [key, entry] of entries) {
43637
- if (typeof entry === "object" && entry !== null && getIntrinsicIdentity(entry) !== void 0 && hasGuestObjectState(entry))
43638
- fail("invalidState", `${path}${formatKey(key)}`, "mutated intrinsics require a serialized snapshot");
43691
+ const entries = state.dataPropertiesOnly ? snapshotDataEntries(value2, path2, state.dataPrototypes) : ownSnapshotDataEntries(value2, path2, true);
43692
+ if (state.dataPropertiesOnly) {
43693
+ for (const [key2, entry] of entries) {
43694
+ if (typeof entry === "object" && entry !== null && getIntrinsicIdentity(entry) !== void 0 && hasGuestObjectState(entry))
43695
+ fail("invalidState", `${path2}${formatKey(key2)}`, "mutated intrinsics require a serialized snapshot");
43696
+ }
43639
43697
  }
43698
+ for (const [key2, entry] of entries.reverse()) {
43699
+ const entryPath = `${path2}${formatKey(key2)}`;
43700
+ pending.push({ value: entry, path: entryPath, depth: depth2 + 1, key: key2 });
43701
+ }
43702
+ } else if (!["boolean", "number"].includes(typeof value2) && !(state.allowFunctions && typeof value2 === "function") && !(state.allowUndefined && value2 === void 0) && value2 !== null) {
43703
+ fail("invalidType", path2, "contains an unsupported value");
43640
43704
  }
43641
- for (const [key, entry] of entries) {
43642
- const entryPath = `${path}${formatKey(key)}`;
43643
- requireString(key, entryPath, state.limits);
43644
- state.dataSize += key.length;
43645
- validateGenericValue(entry, entryPath, depth + 1, state);
43646
- }
43647
- } else if (!["boolean", "number"].includes(typeof value) && !(state.allowFunctions && typeof value === "function") && !(state.allowUndefined && value === void 0) && value !== null) {
43648
- fail("invalidType", path, "contains an unsupported value");
43705
+ if (state.dataSize > state.limits.maxDataSize)
43706
+ fail("budgetExceeded", path2, `exceeds aggregate data limit ${state.limits.maxDataSize}`);
43649
43707
  }
43650
- if (state.dataSize > state.limits.maxDataSize)
43651
- fail("budgetExceeded", path, `exceeds aggregate data limit ${state.limits.maxDataSize}`);
43652
43708
  }
43653
- function validateRuntimeSnapshotDescriptors(snapshot) {
43709
+ function validateRuntimeSnapshotDescriptors(snapshot, budget) {
43654
43710
  const pending = [{ value: snapshot, path: "$", depth: 0 }];
43655
43711
  const seen = /* @__PURE__ */ new WeakSet();
43656
- let entries = 0;
43712
+ const limits = limitsFromBudget(budget);
43657
43713
  while (pending.length > 0) {
43658
43714
  const { value, path, depth } = pending.pop();
43659
43715
  validateSnapshotProxy(value, path);
43660
43716
  if (seen.has(value)) continue;
43661
43717
  seen.add(value);
43662
- if (depth > MAX_DATA_DEPTH)
43663
- fail("budgetExceeded", path, `exceeds nesting limit ${MAX_DATA_DEPTH}`);
43718
+ if (depth > limits.maxDepth)
43719
+ fail("budgetExceeded", path, `exceeds nesting limit ${limits.maxDepth}`);
43664
43720
  for (const [key, entry] of ownSnapshotDataEntries(value, path, true, true)) {
43665
- if (++entries > DEFAULT_MAX_ENTRIES)
43666
- fail("budgetExceeded", path, `exceeds aggregate entry limit ${DEFAULT_MAX_ENTRIES}`);
43667
43721
  if (entry !== null && typeof entry === "object")
43668
43722
  pending.push({ value: entry, path: `${path}${formatKey(key)}`, depth: depth + 1 });
43669
43723
  }
@@ -43706,14 +43760,13 @@ function ownSnapshotDataEntries(value, path, runtime = false, guestDescriptors =
43706
43760
  }
43707
43761
  return entries;
43708
43762
  }
43709
- function defaultLimits() {
43763
+ function limitsFromBudget(budget) {
43710
43764
  return {
43711
- maxAggregateEntries: DEFAULT_MAX_ENTRIES,
43712
- maxCallDepth: 1e4,
43713
- maxDepth: MAX_DATA_DEPTH,
43714
- maxEntries: DEFAULT_MAX_ENTRIES,
43715
- maxStringLength: DEFAULT_MAX_STRING_LENGTH,
43716
- maxDataSize: DEFAULT_MAX_DATA_SIZE
43765
+ maxCallDepth: budget?.limits.maxCallDepth ?? Infinity,
43766
+ maxDepth: budget?.limits.maxCallDepth ?? Infinity,
43767
+ maxEntries: budget?.limits.arrayLength ?? Infinity,
43768
+ maxStringLength: budget?.limits.stringLength ?? Infinity,
43769
+ maxDataSize: budget?.limits.dataSize ?? Infinity
43717
43770
  };
43718
43771
  }
43719
43772
  function requireArray(value, path, state) {
@@ -49202,6 +49255,7 @@ export {
49202
49255
  createReplayEncodingContext,
49203
49256
  encodeReplayData,
49204
49257
  decodeReplayData,
49258
+ schedulesHostCallbacks,
49205
49259
  declareBudgetedHostOperation,
49206
49260
  declareHostOperation,
49207
49261
  wrapCallerInjectedBindings,
@@ -49312,4 +49366,4 @@ authorization of the copyright holder.
49312
49366
  SPDX-License-Identifier: Unicode-3.0
49313
49367
 
49314
49368
  */
49315
- //# sourceMappingURL=chunk-MDIWQFYU.js.map
49369
+ //# sourceMappingURL=chunk-SBFOCNNW.js.map