@poe-platform/safe-js 0.1.133 → 0.1.135

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.
@@ -6448,8 +6448,50 @@ function nativeIterator(collection, method) {
6448
6448
  return collection.kind === "map" ? collection.entries[method]() : collection.values[method]();
6449
6449
  }
6450
6450
 
6451
- // packages/safe-js/src/interp/host-capabilities.ts
6451
+ // packages/safe-js/src/interp/boxed.ts
6452
6452
  import { types as types3 } from "node:util";
6453
+ var boxes = /* @__PURE__ */ new WeakSet();
6454
+ var numberValue = Number.prototype.valueOf;
6455
+ var stringValue = String.prototype.valueOf;
6456
+ var booleanValue = Boolean.prototype.valueOf;
6457
+ function nativeBoxedValue(value) {
6458
+ if (types3.isNumberObject(value)) return Reflect.apply(numberValue, value, []);
6459
+ if (types3.isStringObject(value)) return Reflect.apply(stringValue, value, []);
6460
+ if (types3.isBooleanObject(value)) return Reflect.apply(booleanValue, value, []);
6461
+ return void 0;
6462
+ }
6463
+ function createSandboxBox(value) {
6464
+ if (typeof value !== "number" && typeof value !== "string" && typeof value !== "boolean")
6465
+ throw new TypeError("Invalid boxed primitive payload.");
6466
+ const box = Object(value);
6467
+ Object.setPrototypeOf(box, null);
6468
+ boxes.add(box);
6469
+ return box;
6470
+ }
6471
+ function isSandboxBox(value) {
6472
+ return typeof value === "object" && value !== null && boxes.has(value);
6473
+ }
6474
+ function boxedValue(value) {
6475
+ if (!boxes.has(value)) throw new TypeError("Expected a sandbox boxed primitive.");
6476
+ return nativeBoxedValue(value);
6477
+ }
6478
+ function primitiveReceiver(value, kind) {
6479
+ const primitive = isSandboxBox(value) ? boxedValue(value) : value;
6480
+ if (typeof primitive !== kind) throw new TypeError(`${kind} method requires a ${kind} receiver.`);
6481
+ return primitive;
6482
+ }
6483
+ function boxedDataProperties(value) {
6484
+ const primitive = nativeBoxedValue(value);
6485
+ return Object.entries(Object.getOwnPropertyDescriptors(value)).filter(([key]) => {
6486
+ if (typeof primitive !== "string") return true;
6487
+ if (key === "length") return false;
6488
+ const index = Number(key);
6489
+ return !(Number.isInteger(index) && index >= 0 && index < primitive.length && String(index) === key);
6490
+ });
6491
+ }
6492
+
6493
+ // packages/safe-js/src/interp/host-capabilities.ts
6494
+ import { types as types4 } from "node:util";
6453
6495
  var MAX_INDEXED_LENGTH = 65536;
6454
6496
  var MAX_NAMED_KEYS = 65536;
6455
6497
  var MAX_NAMED_KEY_CODE_UNITS = 1048576;
@@ -6504,7 +6546,7 @@ function createLiveHostObject(definition, controller) {
6504
6546
  for (const name of ["keys", "get", "set", "delete"]) {
6505
6547
  const operation = data[name];
6506
6548
  if (operation === void 0 && (name === "set" || name === "delete")) continue;
6507
- if (typeof operation !== "function" || types3.isProxy(operation) || types3.isAsyncFunction(operation) || types3.isGeneratorFunction(operation))
6549
+ if (typeof operation !== "function" || types4.isProxy(operation) || types4.isAsyncFunction(operation) || types4.isGeneratorFunction(operation))
6508
6550
  throw new TypeError(`Named ${name} must be a synchronous non-generator function, not a proxy.`);
6509
6551
  }
6510
6552
  if (typeof data.maxKeys !== "number" || !Number.isInteger(data.maxKeys) || data.maxKeys < 1 || data.maxKeys > MAX_NAMED_KEYS)
@@ -6759,7 +6801,7 @@ function namedMutationKeys(state, key, create) {
6759
6801
  function namedKeys(state) {
6760
6802
  const named = state.named;
6761
6803
  return state.controller.read(named.keys, (value) => {
6762
- if (!Array.isArray(value) || types3.isProxy(value))
6804
+ if (!Array.isArray(value) || types4.isProxy(value))
6763
6805
  throw new TypeError("Named keys must be a dense own-data array of strings, not a proxy.");
6764
6806
  const length = Object.getOwnPropertyDescriptor(value, "length").value;
6765
6807
  if (length > named.maxKeys) throw new RangeError("Named keys exceed maxKeys.");
@@ -6912,7 +6954,7 @@ async function flushPromiseJobs() {
6912
6954
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
6913
6955
 
6914
6956
  // packages/safe-js/src/snapshot/validation.ts
6915
- import { types as types4 } from "node:util";
6957
+ import { types as types5 } from "node:util";
6916
6958
 
6917
6959
  // packages/safe-js/src/interp/arguments.ts
6918
6960
  var sandboxArgumentsBrand = /* @__PURE__ */ Symbol("SandboxArguments");
@@ -7017,6 +7059,7 @@ function walkGraphDepth(root, rootPath, assertDepth) {
7017
7059
  }
7018
7060
  }
7019
7061
  function graphEntries(value) {
7062
+ if (isSandboxBox(value)) return boxedDataProperties(value).map(([key, descriptor]) => [`.${key}`, descriptor.value]);
7020
7063
  if (isSandboxArguments(value)) {
7021
7064
  return getSandboxArgumentEntries(value).map(([key, entry]) => [`.${key}`, entry]);
7022
7065
  }
@@ -7046,7 +7089,10 @@ var guestClosures = /* @__PURE__ */ new WeakSet();
7046
7089
  var functionProperties = /* @__PURE__ */ new WeakMap();
7047
7090
  var prototypes = /* @__PURE__ */ new WeakMap();
7048
7091
  var intrinsicPrototypes = /* @__PURE__ */ new WeakMap();
7092
+ var boxedPrototypes = /* @__PURE__ */ new WeakMap();
7093
+ var intrinsicPrototypeRoots = /* @__PURE__ */ new WeakMap();
7049
7094
  var intrinsicConstructors = /* @__PURE__ */ new WeakMap();
7095
+ var initialBoxedMethods = /* @__PURE__ */ new WeakMap();
7050
7096
  var descriptorObjects = /* @__PURE__ */ new WeakSet();
7051
7097
  function registerGuestClosure(closure) {
7052
7098
  guestClosures.add(closure);
@@ -7094,11 +7140,34 @@ function getGuestFunctionProperty(closure, key) {
7094
7140
  function installObjectPrototype(budget, prototype, constructor) {
7095
7141
  prototypes.set(prototype, null);
7096
7142
  intrinsicPrototypes.set(budget, prototype);
7143
+ registerIntrinsicPrototype(budget, prototype, constructor);
7144
+ }
7145
+ function installBoxedPrototype(budget, prototype, constructor) {
7146
+ let state = boxedPrototypes.get(budget);
7147
+ if (state === void 0) boxedPrototypes.set(budget, state = /* @__PURE__ */ new Map());
7148
+ state.set(typeof boxedValue(prototype), prototype);
7149
+ initialBoxedMethods.set(prototype, new Map(Object.entries(Object.getOwnPropertyDescriptors(prototype)).map(([key, descriptor]) => [key, descriptor.value])));
7150
+ registerIntrinsicPrototype(budget, prototype, constructor);
7151
+ }
7152
+ function getBoxedPrototype(value, budget) {
7153
+ return boxedPrototypes.get(budget)?.get(typeof value);
7154
+ }
7155
+ function isDefaultBoxedMethod(value, key, budget) {
7156
+ const prototype = getBoxedPrototype(value, budget);
7157
+ return prototype !== void 0 && initialBoxedMethods.get(prototype)?.has(key) === true && Object.getOwnPropertyDescriptor(prototype, key)?.value === initialBoxedMethods.get(prototype)?.get(key);
7158
+ }
7159
+ function isIntrinsicConstructor(value) {
7160
+ return intrinsicConstructors.has(value);
7161
+ }
7162
+ function registerIntrinsicPrototype(budget, prototype, constructor) {
7163
+ let roots = intrinsicPrototypeRoots.get(budget);
7164
+ if (roots === void 0) intrinsicPrototypeRoots.set(budget, roots = /* @__PURE__ */ new Set());
7165
+ roots.add(prototype);
7097
7166
  const records = [prototype, materializeFunctionProperties(constructor)].map((value) => ({
7098
7167
  value,
7099
7168
  descriptors: new Map(Object.entries(Object.getOwnPropertyDescriptors(value)))
7100
7169
  }));
7101
- const unchanged = (before, after) => before !== void 0 && after !== void 0 && before.value === after.value && before.writable === after.writable && before.configurable === after.configurable && before.enumerable === after.enumerable;
7170
+ const unchanged = (before, after) => before !== void 0 && after !== void 0 && Object.is(before.value, after.value) && before.writable === after.writable && before.configurable === after.configurable && before.enumerable === after.enumerable;
7102
7171
  intrinsicConstructors.set(constructor, () => records.every(({ value, descriptors }) => {
7103
7172
  const current = Object.getOwnPropertyDescriptors(value);
7104
7173
  return Object.keys(current).length === descriptors.size && Object.keys(current).every((key) => unchanged(descriptors.get(key), current[key]));
@@ -7106,12 +7175,17 @@ function installObjectPrototype(budget, prototype, constructor) {
7106
7175
  budget.setRetainedValues(prototype, () => records.flatMap(({ value, descriptors }) => Object.entries(Object.getOwnPropertyDescriptors(value)).flatMap(([key, descriptor]) => unchanged(descriptors.get(key), descriptor) ? [] : [key, descriptor.value])));
7107
7176
  }
7108
7177
  function releaseObjectPrototype(budget) {
7109
- const prototype = intrinsicPrototypes.get(budget);
7110
- if (prototype !== void 0) budget.setRetainedValues(prototype, void 0);
7178
+ for (const prototype of intrinsicPrototypeRoots.get(budget) ?? []) budget.setRetainedValues(prototype, void 0);
7179
+ intrinsicPrototypeRoots.delete(budget);
7180
+ boxedPrototypes.delete(budget);
7111
7181
  intrinsicPrototypes.delete(budget);
7112
7182
  }
7113
7183
  function getSandboxPrototype(value, budget) {
7114
7184
  if (prototypes.has(value)) return prototypes.get(value) ?? null;
7185
+ if (budget !== void 0 && isSandboxBox(value)) {
7186
+ const prototype = getBoxedPrototype(boxedValue(value), budget);
7187
+ if (prototype !== void 0 && prototype !== value) return prototype;
7188
+ }
7115
7189
  return budget !== void 0 && isPrototypeRecord(value) ? intrinsicPrototypes.get(budget) ?? null : null;
7116
7190
  }
7117
7191
  function hasExplicitSandboxPrototype(value) {
@@ -7177,6 +7251,7 @@ function hasGuestObjectState(value) {
7177
7251
  if (intrinsicUnchanged !== void 0) return !intrinsicUnchanged();
7178
7252
  if (isLiveCapability(value)) return true;
7179
7253
  if (functionProperties.has(value) || prototypes.has(value)) return true;
7254
+ if (isSandboxBox(value)) return false;
7180
7255
  return descriptorObjects.has(value) && Object.values(Object.getOwnPropertyDescriptors(value)).some(
7181
7256
  (descriptor) => !descriptor.enumerable || !descriptor.configurable || !descriptor.writable
7182
7257
  );
@@ -7280,6 +7355,34 @@ function decodeFloat32Storage(value, resolve) {
7280
7355
  return new Float32Array(buffer, Number(value.byteOffset), Number(value.length));
7281
7356
  }
7282
7357
 
7358
+ // packages/safe-js/src/snapshot/boxed.ts
7359
+ function encodeBoxedData(value, encode) {
7360
+ const properties = /* @__PURE__ */ Object.create(null);
7361
+ for (const [key, descriptor] of boxedDataProperties(value)) {
7362
+ if (!("value" in descriptor)) throw new TypeError("Boxed data cannot contain accessors.");
7363
+ properties[key] = {
7364
+ value: encode(descriptor.value, key),
7365
+ configurable: descriptor.configurable === true,
7366
+ enumerable: descriptor.enumerable === true,
7367
+ writable: descriptor.writable === true
7368
+ };
7369
+ }
7370
+ return {
7371
+ kind: "boxed",
7372
+ value: encode(boxedValue(value), "<payload>"),
7373
+ properties,
7374
+ extensible: Object.isExtensible(value)
7375
+ };
7376
+ }
7377
+ function validateBoxedProperties(data) {
7378
+ if (!Object.hasOwn(data, "kind") || data.kind !== "boxed" || !Object.hasOwn(data, "value") || !Object.hasOwn(data, "extensible") || !Object.hasOwn(data, "properties") || Object.keys(data).length !== 4 || typeof data.extensible !== "boolean" || typeof data.properties !== "object" || data.properties === null || Array.isArray(data.properties))
7379
+ throw new TypeError("Invalid boxed primitive properties.");
7380
+ for (const descriptor of Object.values(data.properties)) {
7381
+ if (typeof descriptor !== "object" || descriptor === null || !Object.hasOwn(descriptor, "value") || !Object.hasOwn(descriptor, "writable") || !Object.hasOwn(descriptor, "enumerable") || !Object.hasOwn(descriptor, "configurable") || typeof descriptor.writable !== "boolean" || typeof descriptor.enumerable !== "boolean" || typeof descriptor.configurable !== "boolean" || Object.keys(descriptor).length !== 4)
7382
+ throw new TypeError("Invalid boxed primitive descriptor.");
7383
+ }
7384
+ }
7385
+
7283
7386
  // packages/safe-js/src/snapshot/dump-format.ts
7284
7387
  var DUMP_FORMAT_VERSION = 1;
7285
7388
  var EXECUTION_SEMANTICS = "jobs-v8";
@@ -7341,7 +7444,7 @@ function serializeDumpValue(value, path, state) {
7341
7444
  if (hasGuestObjectState(value)) {
7342
7445
  throw new TypeError("Guest function properties and prototype links cannot be serialized.");
7343
7446
  }
7344
- if (isSandboxDate(value) || isFloat32Array(value)) return serializeHeapReference(value, path, state);
7447
+ if (isSandboxBox(value) || isSandboxDate(value) || isFloat32Array(value)) return serializeHeapReference(value, path, state);
7345
7448
  if (Array.isArray(value)) {
7346
7449
  const reference2 = serializeHeapReference(value, path, state);
7347
7450
  if (reference2 !== void 0) {
@@ -7365,7 +7468,13 @@ function serializeHeapReference(value, path, state) {
7365
7468
  }
7366
7469
  if (!state.serializedHeapIds.has(id)) {
7367
7470
  state.serializedHeapIds.add(id);
7368
- if (isSandboxDate(value)) {
7471
+ if (isSandboxBox(value)) {
7472
+ state.heap[String(id)] = encodeBoxedData(value, (entry, key) => {
7473
+ if (Object.is(entry, -0)) return { kind: "number", value: "-0" };
7474
+ const serialized = serializeDumpValue(entry, `${path}.${key}`, state);
7475
+ return serialized === SKIP_VALUE ? { kind: "undefined" } : serialized;
7476
+ });
7477
+ } else if (isSandboxDate(value)) {
7369
7478
  state.heap[String(id)] = { kind: "date", time: serializedDateTime(value) };
7370
7479
  } else if (isFloat32Array(value)) {
7371
7480
  const storage = encodeFloat32Storage(value, id, state.float32Buffers, (id2) => ({
@@ -7424,7 +7533,7 @@ function indexHeapContainers(snapshot) {
7424
7533
  const heapIds = /* @__PURE__ */ new WeakMap();
7425
7534
  let nextId = 1;
7426
7535
  for (const [value, stat2] of stats.entries()) {
7427
- if (stat2.count > 1 || stat2.cyclic || isSandboxDate(value) || isFloat32Array(value) || Array.isArray(value) && requiresArrayEntries(value) || isSandboxArguments(value) || sandboxErrorTypes.has(value)) {
7536
+ if (stat2.count > 1 || stat2.cyclic || isSandboxBox(value) || isSandboxDate(value) || isFloat32Array(value) || Array.isArray(value) && requiresArrayEntries(value) || isSandboxArguments(value) || sandboxErrorTypes.has(value)) {
7428
7537
  heapIds.set(value, nextId);
7429
7538
  nextId += 1;
7430
7539
  }
@@ -7457,7 +7566,7 @@ function collectContainerStats(value, stats, ancestors) {
7457
7566
  }
7458
7567
  stat2.expanded = true;
7459
7568
  ancestors.add(value);
7460
- const entries = isSandboxArguments(value) ? getSandboxArgumentEntries(value).map(([, entry]) => entry) : getEnumerableDataValues(value);
7569
+ const entries = isSandboxBox(value) ? boxedDataProperties(value).map(([, descriptor]) => descriptor.value) : isSandboxArguments(value) ? getSandboxArgumentEntries(value).map(([, entry]) => entry) : getEnumerableDataValues(value);
7461
7570
  for (const entry of entries) {
7462
7571
  collectContainerStats(entry, stats, ancestors);
7463
7572
  }
@@ -7571,6 +7680,10 @@ function validateDumpHeap(root, state) {
7571
7680
  addUnique(heapIds, id, path);
7572
7681
  const entry = requireRecord(value, path);
7573
7682
  validateErrorType(entry, path);
7683
+ if (entry.kind === "boxed") {
7684
+ validateBoxedRecord(entry, path);
7685
+ continue;
7686
+ }
7574
7687
  if (entry.kind === "date") {
7575
7688
  validateDateRecord(entry, path);
7576
7689
  continue;
@@ -7738,6 +7851,18 @@ function validateGeneratorShape(record2, path, state) {
7738
7851
  }
7739
7852
  });
7740
7853
  }
7854
+ function validateBoxedRecord(record2, path) {
7855
+ try {
7856
+ validateBoxedProperties(record2);
7857
+ } catch {
7858
+ fail("invalidValue", path, "invalid boxed primitive properties");
7859
+ }
7860
+ const value = record2.value;
7861
+ if (typeof value === "number" || typeof value === "string" || typeof value === "boolean") return;
7862
+ const number = requireRecord(value, `${path}.value`);
7863
+ if (number.kind !== "number" || !["NaN", "Infinity", "-Infinity", "-0"].includes(String(number.value)))
7864
+ fail("invalidValue", `${path}.value`, "invalid boxed primitive payload");
7865
+ }
7741
7866
  function validateDateRecord(record2, path) {
7742
7867
  if (Object.keys(record2).length !== 2) fail("invalidValue", path, "invalid Date fields");
7743
7868
  try {
@@ -7829,7 +7954,7 @@ function validateGenericValue(value, path, depth, state) {
7829
7954
  if (typeof value === "object" && value !== null && hasGuestObjectState(value)) {
7830
7955
  fail("invalidState", path, "guest function properties, prototype links and custom descriptors cannot be restored");
7831
7956
  }
7832
- if (state.dataPropertiesOnly && types4.isProxy(value)) {
7957
+ if (state.dataPropertiesOnly && types5.isProxy(value)) {
7833
7958
  fail("invalidType", path, "proxy objects are not snapshot data");
7834
7959
  }
7835
7960
  if (depth > state.limits.maxDepth)
@@ -8754,7 +8879,7 @@ async function objectToPrimitive(value, budget, context, joining, hint) {
8754
8879
  if (hook === defaultStringHook) {
8755
8880
  result = await defaultToString(value, budget, context, joining);
8756
8881
  } else if (hook === defaultValueHook) {
8757
- result = isSandboxDate(value) ? dateTime(value) : value;
8882
+ result = isSandboxDate(value) ? dateTime(value) : isSandboxBox(value) ? boxedValue(value) : value;
8758
8883
  } else {
8759
8884
  if (!isSandboxClosure(hook)) continue;
8760
8885
  result = await invokeBuiltinClosure(hook, [], budget, context, value);
@@ -8794,6 +8919,7 @@ function conversionHook(value, name, budget) {
8794
8919
  return void 0;
8795
8920
  }
8796
8921
  async function defaultToString(value, budget, context, joining) {
8922
+ if (isSandboxBox(value)) return budget.allocateString(String(boxedValue(value)));
8797
8923
  if (isSandboxClosure(value)) return budget.allocateString(functionString(value));
8798
8924
  if (isSandboxMap(value)) return "[object Map]";
8799
8925
  if (isSandboxSet(value)) return "[object Set]";
@@ -9350,7 +9476,27 @@ function assertSnapshotInactive(snapshot) {
9350
9476
  }
9351
9477
 
9352
9478
  // packages/safe-js/src/interp/iteration.ts
9353
- function getSandboxIterator(value, budget) {
9479
+ function getSandboxIterator(value, budget, context) {
9480
+ if (isSandboxBox(value) && typeof boxedValue(value) === "string") {
9481
+ const primitive = boxedValue(value);
9482
+ let text;
9483
+ let iterator;
9484
+ let initialized;
9485
+ return {
9486
+ asynchronous: true,
9487
+ get retainedValue() {
9488
+ return text === primitive ? void 0 : text;
9489
+ },
9490
+ next: async () => {
9491
+ initialized ??= Promise.resolve(sandboxString(value, budget ?? new Budget(), context)).then((converted) => {
9492
+ text = converted;
9493
+ iterator = syncIterator(converted[Symbol.iterator]());
9494
+ });
9495
+ await initialized;
9496
+ return iterator.next();
9497
+ }
9498
+ };
9499
+ }
9354
9500
  if (isSandboxCollectionIterator(value)) return { next: () => nextCollectionIterator(value, budget), snapshotIndex: () => 0 };
9355
9501
  if (isGuestHostObject(value)) return getHostObjectIterator(value);
9356
9502
  if (isFloat32Array(value)) {
@@ -9917,67 +10063,72 @@ async function settleIterable(iterable, method, budget, constructor, context) {
9917
10063
  const promiseResolve = readPromiseReceiverProperty(constructor, "resolve", prototype);
9918
10064
  if (!isSandboxClosure(promiseResolve))
9919
10065
  throw new TypeError("Promise constructor requires a callable resolve.");
9920
- const iterator = getSandboxIterator(iterable, budget);
10066
+ const iterator = getSandboxIterator(iterable, budget, context);
9921
10067
  if (iterator === void 0) throw new TypeError("Promise helpers require an iterable.");
9922
- let index = 0;
9923
- while (true) {
9924
- budget.visitNode();
9925
- const next = iterator.generator ? await iterator.next() : iterator.next();
9926
- if (typeof next !== "object" || next === null)
9927
- throw new TypeError("Iterator result must be an object.");
9928
- if (next.done) break;
9929
- const value = next.value;
9930
- try {
9931
- budget.allocateArrayLength(index + 1);
9932
- const entryIndex = index++;
9933
- if (method !== "race") values.push(void 0);
9934
- const entry = await callPromiseClosure(
9935
- promiseResolve,
9936
- [value],
9937
- constructor,
9938
- budget,
9939
- context
9940
- );
9941
- let called = false;
9942
- const handlers = ["fulfilled", "rejected"].map((state) => {
9943
- if (method === "race" || method === "any" && state === "fulfilled")
9944
- return state === "fulfilled" ? capability.resolve : capability.reject;
9945
- if (method === "all" && state === "rejected") return capability.reject;
9946
- return createSandboxClosure({
9947
- sandbox: true,
9948
- retainedValues: () => [
9949
- capability.promise,
9950
- capability.resolve,
9951
- capability.reject,
9952
- values
9953
- ],
9954
- call: async ([settlement]) => {
9955
- if (called) return void 0;
9956
- called = true;
9957
- values[entryIndex] = method === "allSettled" ? state === "fulfilled" ? { status: state, value: settlement } : { status: state, reason: settlement } : settlement;
9958
- remaining--;
9959
- await complete();
9960
- return void 0;
9961
- }
9962
- });
9963
- });
9964
- remaining++;
9965
- const then = readPromiseReceiverProperty(entry, "then", prototype);
9966
- if (!isSandboxClosure(then))
9967
- throw new TypeError("Promise resolver result requires a callable then.");
9968
- await callPromiseClosure(then, handlers, entry, budget, context);
9969
- } catch (error) {
10068
+ const releaseIterator = retainValues(budget, () => [iterator.retainedValue]);
10069
+ try {
10070
+ let index = 0;
10071
+ while (true) {
10072
+ budget.visitNode();
10073
+ const next = iterator.generator || iterator.asynchronous ? await iterator.next() : iterator.next();
10074
+ if (typeof next !== "object" || next === null)
10075
+ throw new TypeError("Iterator result must be an object.");
10076
+ if (next.done) break;
10077
+ const value = next.value;
9970
10078
  try {
9971
- const closed = iterator.return?.();
9972
- if (iterator.generator) await closed;
9973
- } catch {
10079
+ budget.allocateArrayLength(index + 1);
10080
+ const entryIndex = index++;
10081
+ if (method !== "race") values.push(void 0);
10082
+ const entry = await callPromiseClosure(
10083
+ promiseResolve,
10084
+ [value],
10085
+ constructor,
10086
+ budget,
10087
+ context
10088
+ );
10089
+ let called = false;
10090
+ const handlers = ["fulfilled", "rejected"].map((state) => {
10091
+ if (method === "race" || method === "any" && state === "fulfilled")
10092
+ return state === "fulfilled" ? capability.resolve : capability.reject;
10093
+ if (method === "all" && state === "rejected") return capability.reject;
10094
+ return createSandboxClosure({
10095
+ sandbox: true,
10096
+ retainedValues: () => [
10097
+ capability.promise,
10098
+ capability.resolve,
10099
+ capability.reject,
10100
+ values
10101
+ ],
10102
+ call: async ([settlement]) => {
10103
+ if (called) return void 0;
10104
+ called = true;
10105
+ values[entryIndex] = method === "allSettled" ? state === "fulfilled" ? { status: state, value: settlement } : { status: state, reason: settlement } : settlement;
10106
+ remaining--;
10107
+ await complete();
10108
+ return void 0;
10109
+ }
10110
+ });
10111
+ });
10112
+ remaining++;
10113
+ const then = readPromiseReceiverProperty(entry, "then", prototype);
10114
+ if (!isSandboxClosure(then))
10115
+ throw new TypeError("Promise resolver result requires a callable then.");
10116
+ await callPromiseClosure(then, handlers, entry, budget, context);
10117
+ } catch (error) {
10118
+ try {
10119
+ const closed = iterator.return?.();
10120
+ if (iterator.generator || iterator.asynchronous) await closed;
10121
+ } catch {
10122
+ throw error;
10123
+ }
9974
10124
  throw error;
9975
10125
  }
9976
- throw error;
9977
10126
  }
10127
+ remaining--;
10128
+ await complete();
10129
+ } finally {
10130
+ releaseIterator();
9978
10131
  }
9979
- remaining--;
9980
- await complete();
9981
10132
  } catch (error) {
9982
10133
  if (error instanceof SandboxError && (error.code === "budgetExceeded" || error.code === "reentry")) {
9983
10134
  if (isSandboxPromise(capability.promise)) observeSandboxPromise(capability.promise);
@@ -10679,6 +10830,17 @@ function measureSandboxData(values, options = {}) {
10679
10830
  assertSandboxDataDepth(depth);
10680
10831
  seen.add(value);
10681
10832
  usage += 1;
10833
+ if (isSandboxBox(value)) {
10834
+ const primitive = boxedValue(value);
10835
+ usage += typeof primitive === "string" ? primitive.length : 8;
10836
+ const prototype2 = getSandboxPrototype(value);
10837
+ if (prototype2 !== null) visit(prototype2, depth + 1);
10838
+ for (const [key, descriptor] of boxedDataProperties(value)) {
10839
+ usage += key.length + 1;
10840
+ if ("value" in descriptor) visit(descriptor.value, depth + 1);
10841
+ }
10842
+ return;
10843
+ }
10682
10844
  if (isSandboxDate(value)) {
10683
10845
  usage += 8;
10684
10846
  return;
@@ -10740,7 +10902,15 @@ function measureSandboxData(values, options = {}) {
10740
10902
  }
10741
10903
  if (isSandboxClosure(value)) {
10742
10904
  if (options.ignoreClosures) return;
10743
- if (value.properties !== void 0) visit(value.properties, depth + 1);
10905
+ if (value.properties !== void 0) {
10906
+ if (isIntrinsicConstructor(value)) {
10907
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value.properties))) {
10908
+ if (key === "prototype" || key === "name" || key === "length") continue;
10909
+ usage += key.length + 1;
10910
+ if ("value" in descriptor) visit(descriptor.value, depth + 1);
10911
+ }
10912
+ } else visit(value.properties, depth + 1);
10913
+ }
10744
10914
  if (!options.ignoreClosureCaptures)
10745
10915
  for (const retained of value[sandboxRetainedValues]?.() ?? []) visit(retained, depth + 1);
10746
10916
  return;
@@ -10872,6 +11042,24 @@ function copyToSandbox(value, state, path = "<root>", cloneSandboxCollections =
10872
11042
  if (typeof value === "object" && value !== null && hasGuestObjectState(value)) {
10873
11043
  throw new TypeError("Guest prototype links and custom descriptors cannot be copied as data.");
10874
11044
  }
11045
+ const primitive = nativeBoxedValue(value);
11046
+ if (primitive !== void 0) {
11047
+ const original = value;
11048
+ const existing = state.seen.get(original);
11049
+ if (existing !== void 0) return existing;
11050
+ const copy = createSandboxBox(primitive);
11051
+ state.seen.set(original, copy);
11052
+ if (!state.structuredClone) {
11053
+ for (const [key, descriptor] of boxedDataProperties(original)) {
11054
+ if (!("value" in descriptor)) throw new TypeError("Boxed data cannot contain accessors.");
11055
+ Object.defineProperty(copy, key, {
11056
+ ...descriptor,
11057
+ value: copyToSandbox(descriptor.value, state, joinPath(path, key), cloneSandboxCollections, depth + 1)
11058
+ });
11059
+ }
11060
+ }
11061
+ return copy;
11062
+ }
10875
11063
  if (isSandboxMap(value)) {
10876
11064
  if (!cloneSandboxCollections) return value;
10877
11065
  const existing = state.seen.get(value);
@@ -11044,6 +11232,20 @@ function copyFromSandbox(value, state, path = "<root>", options, depth = 0) {
11044
11232
  if (!isSandboxClosure(value) && hasGuestObjectState(value)) {
11045
11233
  throw new TypeError("Guest prototype links and custom descriptors cannot be copied as data.");
11046
11234
  }
11235
+ if (isSandboxBox(value)) {
11236
+ const existing = state.seen.get(value);
11237
+ if (existing !== void 0) return existing;
11238
+ const copy = Object(boxedValue(value));
11239
+ state.seen.set(value, copy);
11240
+ for (const [key, descriptor] of boxedDataProperties(value)) {
11241
+ if (!("value" in descriptor)) throw new TypeError("Boxed data cannot contain accessors.");
11242
+ Object.defineProperty(copy, key, {
11243
+ ...descriptor,
11244
+ value: copyFromSandbox(descriptor.value, state, joinPath(path, key), options, depth + 1)
11245
+ });
11246
+ }
11247
+ return copy;
11248
+ }
11047
11249
  const regexBrand = Object.getOwnPropertyDescriptor(value, sandboxRegexBrand);
11048
11250
  if (regexBrand !== void 0) {
11049
11251
  if (!("value" in regexBrand) || regexBrand.value !== true) {
@@ -11214,6 +11416,17 @@ function allocateSandboxValue2(value, budget, seen) {
11214
11416
  budget.allocateString(value);
11215
11417
  return;
11216
11418
  }
11419
+ if (isSandboxBox(value)) {
11420
+ if (seen.has(value)) return;
11421
+ seen.add(value);
11422
+ const primitive = boxedValue(value);
11423
+ if (typeof primitive === "string") budget.allocateString(primitive);
11424
+ for (const [key, descriptor] of boxedDataProperties(value)) {
11425
+ budget.allocateString(key);
11426
+ if ("value" in descriptor) allocateSandboxValue2(descriptor.value, budget, seen);
11427
+ }
11428
+ return;
11429
+ }
11217
11430
  if (isFloat32Array(value)) {
11218
11431
  if (seen.has(value)) return;
11219
11432
  seen.add(value);
@@ -11403,6 +11616,13 @@ function encodeReplayData(value, options = {}) {
11403
11616
  id: capabilityId,
11404
11617
  properties: child(entry.properties, "properties")
11405
11618
  };
11619
+ } else if (nativeBoxedValue(entry) !== void 0) {
11620
+ const properties = /* @__PURE__ */ Object.create(null);
11621
+ nodes[id] = { kind: "boxed", value: child(nativeBoxedValue(entry), "<payload>"), properties, extensible: Object.isExtensible(entry) };
11622
+ for (const [key, descriptor] of boxedDataProperties(entry)) {
11623
+ if (!("value" in descriptor)) throw new TypeError(`Cannot record replay data accessor '${key}'.`);
11624
+ properties[key] = { value: child(descriptor.value, JSON.stringify(["property", key])), configurable: descriptor.configurable === true, enumerable: descriptor.enumerable === true, writable: descriptor.writable === true };
11625
+ }
11406
11626
  } else if (isSandboxDate(entry)) {
11407
11627
  nodes[id] = { kind: "date", time: serializedDateTime(entry) };
11408
11628
  } else if (isFloat32Array(entry)) {
@@ -11564,6 +11784,17 @@ function decodeReplayData(input, options = {}, parent) {
11564
11784
  options.onCapabilityRestored?.(capability, copy);
11565
11785
  return copy;
11566
11786
  }
11787
+ if (kind === "boxed") {
11788
+ validateBoxedProperties(node);
11789
+ const payload = own(node, "value");
11790
+ if (typeof payload !== "number" && typeof payload !== "string" && typeof payload !== "boolean" && (payload === null || typeof payload !== "object" || own(record(payload), "tag") !== "number"))
11791
+ throw new TypeError("Invalid boxed primitive payload.");
11792
+ const result3 = createSandboxBox(child(payload));
11793
+ restored.set(id, result3);
11794
+ defineProperties(result3, record(own(node, "properties")), child);
11795
+ if (!node.extensible) Object.preventExtensions(result3);
11796
+ return result3;
11797
+ }
11567
11798
  if (kind === "date") {
11568
11799
  if (Object.keys(node).length !== 2) throw new TypeError("Invalid serialized Date fields.");
11569
11800
  const result3 = restoreDateTime(own(node, "time"));
@@ -24086,7 +24317,10 @@ function isArrayMethodName(property) {
24086
24317
  }
24087
24318
  async function callArrayMethod(receiver, methodName, args, options, stack = []) {
24088
24319
  if (receiver === null || receiver === void 0) throw new TypeError("Array method requires a receiver.");
24089
- if (typeof receiver !== "object") throw new TypeError("Object primitive boxing is not supported.");
24320
+ if (typeof receiver !== "object") {
24321
+ receiver = createSandboxBox(receiver);
24322
+ options.budget.chargeDataUsage(measureSandboxData([receiver]));
24323
+ }
24090
24324
  const retainedReceiver = {};
24091
24325
  options.budget.setRetainedValues(retainedReceiver, () => [receiver]);
24092
24326
  try {
@@ -24865,273 +25099,58 @@ function callFunctionMethod(target, methodName, args, options, stack) {
24865
25099
  return options.callClosure(target, applyArgs, stack, thisValue);
24866
25100
  }
24867
25101
 
24868
- // packages/safe-js/src/interp/methods/collection-callback.ts
24869
- var activeCallbacks = /* @__PURE__ */ new WeakMap();
24870
- function enterKeyedCollectionCallback(target, keys, budget) {
24871
- let state = activeCallbacks.get(target);
24872
- if (state === void 0) {
24873
- state = { cursors: /* @__PURE__ */ new Set(), leaveRunning: enterRunningState(target) };
24874
- activeCallbacks.set(target, state);
24875
- }
24876
- const cursor = { budget, pending: /* @__PURE__ */ new Set() };
24877
- state.cursors.add(cursor);
24878
- const leave = () => {
24879
- if (!state.cursors.delete(cursor)) return;
24880
- cursor.pending.clear();
24881
- budget.setRetainedDataUsage(cursor, 0);
24882
- budget.setRetainedValues(cursor, void 0);
24883
- if (state.cursors.size === 0) {
24884
- activeCallbacks.delete(target);
24885
- state.leaveRunning();
24886
- }
24887
- };
24888
- try {
24889
- budget.setRetainedDataUsage(cursor, 1);
24890
- budget.setRetainedValues(cursor, () => cursor.pending);
24891
- for (const key of keys) updatePendingKeys(cursor, "add", key);
24892
- } catch (error) {
24893
- leave();
24894
- throw error;
24895
- }
24896
- return {
24897
- next: () => {
24898
- budget.visitNode();
24899
- for (const key of cursor.pending) {
24900
- cursor.pending.delete(key);
24901
- budget.setRetainedDataUsage(cursor, 1 + cursor.pending.size);
24902
- return { done: false, value: key };
24903
- }
24904
- return { done: true, value: void 0 };
24905
- },
24906
- leave
24907
- };
24908
- }
24909
- function updateKeyedCollectionCallbacks(target, mutation, key) {
24910
- const state = activeCallbacks.get(target);
24911
- if (state === void 0) return;
24912
- for (const cursor of state.cursors) updatePendingKeys(cursor, mutation, key);
24913
- }
24914
- function updatePendingKeys(cursor, mutation, key) {
24915
- const { budget, pending } = cursor;
24916
- budget.visitNode();
24917
- if (mutation === "add") {
24918
- const nextSize = pending.has(key) ? pending.size : pending.size + 1;
24919
- budget.allocateCollectionEntries(nextSize);
24920
- budget.setRetainedDataUsage(cursor, 1 + nextSize);
24921
- pending.add(key);
24922
- } else {
24923
- if (mutation === "delete") pending.delete(key);
24924
- else pending.clear();
24925
- budget.setRetainedDataUsage(cursor, 1 + pending.size);
24926
- }
24927
- }
24928
-
24929
- // packages/safe-js/src/interp/methods/map.ts
24930
- var mapMethodNames = /* @__PURE__ */ new Set([
24931
- "get",
24932
- "set",
24933
- "has",
24934
- "delete",
24935
- "clear",
24936
- "forEach",
24937
- "keys",
24938
- "values",
24939
- "entries"
25102
+ // packages/safe-js/src/interp/methods/string.ts
25103
+ var SPLIT_STRING_MESSAGE = "String#split only supports string separator values.";
25104
+ var stringMethodNames = /* @__PURE__ */ new Set([
25105
+ "at",
25106
+ "charAt",
25107
+ "charCodeAt",
25108
+ "codePointAt",
25109
+ "concat",
25110
+ "endsWith",
25111
+ "includes",
25112
+ "indexOf",
25113
+ "isWellFormed",
25114
+ "lastIndexOf",
25115
+ "localeCompare",
25116
+ "match",
25117
+ "matchAll",
25118
+ "normalize",
25119
+ "padEnd",
25120
+ "padStart",
25121
+ "repeat",
25122
+ "replace",
25123
+ "replaceAll",
25124
+ "slice",
25125
+ "search",
25126
+ "split",
25127
+ "startsWith",
25128
+ "substr",
25129
+ "substring",
25130
+ "toLowerCase",
25131
+ "toUpperCase",
25132
+ "toWellFormed",
25133
+ "trim",
25134
+ "trimEnd",
25135
+ "trimStart"
24940
25136
  ]);
24941
- function isMapMethodName(value) {
24942
- return typeof value === "string" && mapMethodNames.has(value);
24943
- }
24944
- function getMapMember(target, property, options) {
24945
- if (property === "size") {
24946
- return target.entries.size;
25137
+ function getStringMember(value, property, budget) {
25138
+ const index = getStringIndex(property);
25139
+ if (index !== void 0) {
25140
+ return value[index];
24947
25141
  }
24948
- if (!isMapMethodName(property)) {
25142
+ if (property === "length") {
25143
+ return value.length;
25144
+ }
25145
+ if (!isStringMethodName(property)) {
24949
25146
  return void 0;
24950
25147
  }
24951
25148
  return createSandboxClosure({
24952
25149
  sandbox: true,
24953
- call: (args, context) => {
24954
- const receiver = context?.thisValue;
24955
- if (!isSandboxMap(receiver)) throw new TypeError(`Map#${property} requires a Map receiver.`);
24956
- return callMapMethod(receiver, property, args, options, context?.stack ?? []);
24957
- },
24958
- name: property
24959
- });
24960
- }
24961
- async function callMapMethod(target, methodName, args, options, stack = []) {
24962
- switch (methodName) {
24963
- case "get":
24964
- return target.entries.get(args[0]);
24965
- case "set": {
24966
- assertCollectionMutable(target);
24967
- const exists = target.entries.has(args[0]);
24968
- const nextSize = exists ? target.entries.size : target.entries.size + 1;
24969
- options.budget.allocateCollectionEntries(nextSize);
24970
- if (!exists) updateKeyedCollectionCallbacks(target, "add", args[0]);
24971
- target.entries.set(args[0], args[1]);
24972
- return target;
24973
- }
24974
- case "has":
24975
- return target.entries.has(args[0]);
24976
- case "delete": {
24977
- assertCollectionMutable(target);
24978
- const deleted = target.entries.delete(args[0]);
24979
- if (deleted) updateKeyedCollectionCallbacks(target, "delete", args[0]);
24980
- return deleted;
24981
- }
24982
- case "clear":
24983
- assertCollectionMutable(target);
24984
- target.entries.clear();
24985
- updateKeyedCollectionCallbacks(target, "clear");
24986
- return void 0;
24987
- case "forEach": {
24988
- const callback = args[0];
24989
- if (!isSandboxClosure(callback)) {
24990
- throw new TypeError("Map.prototype.forEach requires a callback function.");
24991
- }
24992
- const cursor = enterKeyedCollectionCallback(target, target.entries.keys(), options.budget);
24993
- try {
24994
- for (let entry = cursor.next(); !entry.done; entry = cursor.next()) {
24995
- const key = entry.value;
24996
- const value = target.entries.get(key);
24997
- await options.callClosure(callback, [value, key, target], stack, args[1]);
24998
- }
24999
- } finally {
25000
- cursor.leave();
25001
- }
25002
- return void 0;
25003
- }
25004
- case "keys":
25005
- case "values":
25006
- case "entries":
25007
- return createSandboxCollectionIterator(target, methodName);
25008
- }
25009
- }
25010
-
25011
- // packages/safe-js/src/interp/methods/number.ts
25012
- var numberMethodNames = /* @__PURE__ */ new Set([
25013
- "toExponential",
25014
- "toFixed",
25015
- "toPrecision",
25016
- "toString"
25017
- ]);
25018
- function getNumberMember(property, budget) {
25019
- if (!isNumberMethodName(property)) {
25020
- return void 0;
25021
- }
25022
- return createSandboxClosure({
25023
- sandbox: true,
25024
- name: `Number#${property}`,
25025
- call: (args, context) => callNumberMethod(context?.thisValue, property, args, budget, context)
25026
- });
25027
- }
25028
- function isNumberMethodName(property) {
25029
- return typeof property === "string" && numberMethodNames.has(property);
25030
- }
25031
- function callNumberMethod(value, methodName, args, budget, context) {
25032
- if (typeof value !== "number") {
25033
- throw new TypeError(`Number#${methodName} requires a number receiver.`);
25034
- }
25035
- const argument = args[0];
25036
- if (argument !== null && typeof argument === "object") {
25037
- return formatObjectArgument(value, methodName, argument, budget, context);
25038
- }
25039
- return formatNumber(value, methodName, argument === void 0 ? void 0 : Number(argument), budget);
25040
- }
25041
- async function formatObjectArgument(value, methodName, argument, budget, context) {
25042
- const retainedArgument = {};
25043
- budget.setRetainedValues(retainedArgument, () => [argument]);
25044
- try {
25045
- const number = await sandboxNumber(argument, budget, context);
25046
- return formatNumber(value, methodName, number, budget);
25047
- } finally {
25048
- budget.setRetainedValues(retainedArgument, void 0);
25049
- }
25050
- }
25051
- function formatNumber(value, methodName, argument, budget) {
25052
- let result;
25053
- try {
25054
- result = value[methodName](argument);
25055
- } catch (error) {
25056
- if (!(error instanceof RangeError)) throw error;
25057
- const detail = methodName === "toString" ? "radix must be between 2 and 36." : methodName === "toPrecision" ? "precision must be between 1 and 100." : "digits must be between 0 and 100.";
25058
- throw new RangeError(`Number#${methodName} ${detail}`);
25059
- }
25060
- return budget.allocateString(result);
25061
- }
25062
-
25063
- // packages/safe-js/src/interp/methods/generator.ts
25064
- var generatorMethodNames = /* @__PURE__ */ new Set(["next", "return", "throw"]);
25065
- function getGeneratorMember(target, property, budget) {
25066
- if (typeof property !== "string" || !generatorMethodNames.has(property)) {
25067
- return void 0;
25068
- }
25069
- return createSandboxClosure({
25070
- sandbox: true,
25071
- name: property,
25072
- call: async ([value]) => {
25073
- const iterator = getSandboxIterator(target);
25074
- const result = await iterator[property](value);
25075
- return allocateProducedSandboxValue(
25076
- { value: result.value, done: result.done === true },
25077
- budget
25078
- );
25079
- }
25080
- });
25081
- }
25082
-
25083
- // packages/safe-js/src/interp/methods/string.ts
25084
- var SPLIT_STRING_MESSAGE = "String#split only supports string separator values.";
25085
- var stringMethodNames = /* @__PURE__ */ new Set([
25086
- "at",
25087
- "charAt",
25088
- "charCodeAt",
25089
- "codePointAt",
25090
- "concat",
25091
- "endsWith",
25092
- "includes",
25093
- "indexOf",
25094
- "isWellFormed",
25095
- "lastIndexOf",
25096
- "localeCompare",
25097
- "match",
25098
- "matchAll",
25099
- "normalize",
25100
- "padEnd",
25101
- "padStart",
25102
- "repeat",
25103
- "replace",
25104
- "replaceAll",
25105
- "slice",
25106
- "search",
25107
- "split",
25108
- "startsWith",
25109
- "substr",
25110
- "substring",
25111
- "toLowerCase",
25112
- "toUpperCase",
25113
- "toWellFormed",
25114
- "trim",
25115
- "trimEnd",
25116
- "trimStart"
25117
- ]);
25118
- function getStringMember(value, property, budget) {
25119
- const index = getStringIndex(property);
25120
- if (index !== void 0) {
25121
- return value[index];
25122
- }
25123
- if (property === "length") {
25124
- return value.length;
25125
- }
25126
- if (!isStringMethodName(property)) {
25127
- return void 0;
25128
- }
25129
- return createSandboxClosure({
25130
- sandbox: true,
25131
- name: `String#${property}`,
25132
- ...property === "localeCompare" ? { length: 1 } : {},
25133
- ...property === "isWellFormed" || property === "toWellFormed" ? { length: 0 } : {},
25134
- call: async (args, context) => {
25150
+ name: `String#${property}`,
25151
+ ...property === "localeCompare" ? { length: 1 } : {},
25152
+ ...property === "isWellFormed" || property === "toWellFormed" ? { length: 0 } : {},
25153
+ call: async (args, context) => {
25135
25154
  const receiver = context?.thisValue;
25136
25155
  if (receiver === null || receiver === void 0) {
25137
25156
  throw new TypeError(`String#${property} requires a non-null receiver.`);
@@ -25559,30 +25578,246 @@ function callMatchLikeMethod(value, methodName, args, compilation, lastIndex) {
25559
25578
  if (methodName === "match" && matches.length === 0) return null;
25560
25579
  return methodName === "match" ? matches.map((match) => match.text) : matches.map((match) => toMatchArray(match, value));
25561
25580
  }
25562
- function collectRegexMatches(regex, value, all, budget, lastIndex = 0) {
25563
- const matches = [];
25564
- do {
25565
- const match = executeRegex(regex, value, lastIndex);
25566
- if (match === null) break;
25567
- budget?.allocateArrayLength(matches.length + 1);
25568
- matches.push(match);
25569
- lastIndex = match.index + match.text.length;
25570
- if (all && match.text.length === 0) regex.lastIndex = ++lastIndex;
25571
- } while (all);
25572
- return matches;
25581
+ function collectRegexMatches(regex, value, all, budget, lastIndex = 0) {
25582
+ const matches = [];
25583
+ do {
25584
+ const match = executeRegex(regex, value, lastIndex);
25585
+ if (match === null) break;
25586
+ budget?.allocateArrayLength(matches.length + 1);
25587
+ matches.push(match);
25588
+ lastIndex = match.index + match.text.length;
25589
+ if (all && match.text.length === 0) regex.lastIndex = ++lastIndex;
25590
+ } while (all);
25591
+ return matches;
25592
+ }
25593
+ function splitString(value, separator, limit) {
25594
+ const split = String.prototype.split;
25595
+ return split.call(value, separator, limit);
25596
+ }
25597
+ function asNumber(value) {
25598
+ return Number(value);
25599
+ }
25600
+ function asNumberOrUndefined(value) {
25601
+ return value === void 0 ? void 0 : Number(value);
25602
+ }
25603
+ function asStringOrUndefined(value) {
25604
+ return value === void 0 ? void 0 : String(value);
25605
+ }
25606
+
25607
+ // packages/safe-js/src/interp/methods/collection-callback.ts
25608
+ var activeCallbacks = /* @__PURE__ */ new WeakMap();
25609
+ function enterKeyedCollectionCallback(target, keys, budget) {
25610
+ let state = activeCallbacks.get(target);
25611
+ if (state === void 0) {
25612
+ state = { cursors: /* @__PURE__ */ new Set(), leaveRunning: enterRunningState(target) };
25613
+ activeCallbacks.set(target, state);
25614
+ }
25615
+ const cursor = { budget, pending: /* @__PURE__ */ new Set() };
25616
+ state.cursors.add(cursor);
25617
+ const leave = () => {
25618
+ if (!state.cursors.delete(cursor)) return;
25619
+ cursor.pending.clear();
25620
+ budget.setRetainedDataUsage(cursor, 0);
25621
+ budget.setRetainedValues(cursor, void 0);
25622
+ if (state.cursors.size === 0) {
25623
+ activeCallbacks.delete(target);
25624
+ state.leaveRunning();
25625
+ }
25626
+ };
25627
+ try {
25628
+ budget.setRetainedDataUsage(cursor, 1);
25629
+ budget.setRetainedValues(cursor, () => cursor.pending);
25630
+ for (const key of keys) updatePendingKeys(cursor, "add", key);
25631
+ } catch (error) {
25632
+ leave();
25633
+ throw error;
25634
+ }
25635
+ return {
25636
+ next: () => {
25637
+ budget.visitNode();
25638
+ for (const key of cursor.pending) {
25639
+ cursor.pending.delete(key);
25640
+ budget.setRetainedDataUsage(cursor, 1 + cursor.pending.size);
25641
+ return { done: false, value: key };
25642
+ }
25643
+ return { done: true, value: void 0 };
25644
+ },
25645
+ leave
25646
+ };
25647
+ }
25648
+ function updateKeyedCollectionCallbacks(target, mutation, key) {
25649
+ const state = activeCallbacks.get(target);
25650
+ if (state === void 0) return;
25651
+ for (const cursor of state.cursors) updatePendingKeys(cursor, mutation, key);
25652
+ }
25653
+ function updatePendingKeys(cursor, mutation, key) {
25654
+ const { budget, pending } = cursor;
25655
+ budget.visitNode();
25656
+ if (mutation === "add") {
25657
+ const nextSize = pending.has(key) ? pending.size : pending.size + 1;
25658
+ budget.allocateCollectionEntries(nextSize);
25659
+ budget.setRetainedDataUsage(cursor, 1 + nextSize);
25660
+ pending.add(key);
25661
+ } else {
25662
+ if (mutation === "delete") pending.delete(key);
25663
+ else pending.clear();
25664
+ budget.setRetainedDataUsage(cursor, 1 + pending.size);
25665
+ }
25666
+ }
25667
+
25668
+ // packages/safe-js/src/interp/methods/map.ts
25669
+ var mapMethodNames = /* @__PURE__ */ new Set([
25670
+ "get",
25671
+ "set",
25672
+ "has",
25673
+ "delete",
25674
+ "clear",
25675
+ "forEach",
25676
+ "keys",
25677
+ "values",
25678
+ "entries"
25679
+ ]);
25680
+ function isMapMethodName(value) {
25681
+ return typeof value === "string" && mapMethodNames.has(value);
25682
+ }
25683
+ function getMapMember(target, property, options) {
25684
+ if (property === "size") {
25685
+ return target.entries.size;
25686
+ }
25687
+ if (!isMapMethodName(property)) {
25688
+ return void 0;
25689
+ }
25690
+ return createSandboxClosure({
25691
+ sandbox: true,
25692
+ call: (args, context) => {
25693
+ const receiver = context?.thisValue;
25694
+ if (!isSandboxMap(receiver)) throw new TypeError(`Map#${property} requires a Map receiver.`);
25695
+ return callMapMethod(receiver, property, args, options, context?.stack ?? []);
25696
+ },
25697
+ name: property
25698
+ });
25699
+ }
25700
+ async function callMapMethod(target, methodName, args, options, stack = []) {
25701
+ switch (methodName) {
25702
+ case "get":
25703
+ return target.entries.get(args[0]);
25704
+ case "set": {
25705
+ assertCollectionMutable(target);
25706
+ const exists = target.entries.has(args[0]);
25707
+ const nextSize = exists ? target.entries.size : target.entries.size + 1;
25708
+ options.budget.allocateCollectionEntries(nextSize);
25709
+ if (!exists) updateKeyedCollectionCallbacks(target, "add", args[0]);
25710
+ target.entries.set(args[0], args[1]);
25711
+ return target;
25712
+ }
25713
+ case "has":
25714
+ return target.entries.has(args[0]);
25715
+ case "delete": {
25716
+ assertCollectionMutable(target);
25717
+ const deleted = target.entries.delete(args[0]);
25718
+ if (deleted) updateKeyedCollectionCallbacks(target, "delete", args[0]);
25719
+ return deleted;
25720
+ }
25721
+ case "clear":
25722
+ assertCollectionMutable(target);
25723
+ target.entries.clear();
25724
+ updateKeyedCollectionCallbacks(target, "clear");
25725
+ return void 0;
25726
+ case "forEach": {
25727
+ const callback = args[0];
25728
+ if (!isSandboxClosure(callback)) {
25729
+ throw new TypeError("Map.prototype.forEach requires a callback function.");
25730
+ }
25731
+ const cursor = enterKeyedCollectionCallback(target, target.entries.keys(), options.budget);
25732
+ try {
25733
+ for (let entry = cursor.next(); !entry.done; entry = cursor.next()) {
25734
+ const key = entry.value;
25735
+ const value = target.entries.get(key);
25736
+ await options.callClosure(callback, [value, key, target], stack, args[1]);
25737
+ }
25738
+ } finally {
25739
+ cursor.leave();
25740
+ }
25741
+ return void 0;
25742
+ }
25743
+ case "keys":
25744
+ case "values":
25745
+ case "entries":
25746
+ return createSandboxCollectionIterator(target, methodName);
25747
+ }
25748
+ }
25749
+
25750
+ // packages/safe-js/src/interp/methods/number.ts
25751
+ var numberMethodNames = /* @__PURE__ */ new Set([
25752
+ "toExponential",
25753
+ "toFixed",
25754
+ "toPrecision",
25755
+ "toString"
25756
+ ]);
25757
+ function getNumberMember(property, budget) {
25758
+ if (!isNumberMethodName(property)) {
25759
+ return void 0;
25760
+ }
25761
+ return createSandboxClosure({
25762
+ sandbox: true,
25763
+ name: `Number#${property}`,
25764
+ call: (args, context) => callNumberMethod(context?.thisValue, property, args, budget, context)
25765
+ });
25766
+ }
25767
+ function isNumberMethodName(property) {
25768
+ return typeof property === "string" && numberMethodNames.has(property);
25573
25769
  }
25574
- function splitString(value, separator, limit) {
25575
- const split = String.prototype.split;
25576
- return split.call(value, separator, limit);
25770
+ function callNumberMethod(value, methodName, args, budget, context) {
25771
+ if (isSandboxBox(value)) value = boxedValue(value);
25772
+ if (typeof value !== "number") {
25773
+ throw new TypeError(`Number#${methodName} requires a number receiver.`);
25774
+ }
25775
+ const argument = args[0];
25776
+ if (argument !== null && typeof argument === "object") {
25777
+ return formatObjectArgument(value, methodName, argument, budget, context);
25778
+ }
25779
+ return formatNumber(value, methodName, argument === void 0 ? void 0 : Number(argument), budget);
25577
25780
  }
25578
- function asNumber(value) {
25579
- return Number(value);
25781
+ async function formatObjectArgument(value, methodName, argument, budget, context) {
25782
+ const retainedArgument = {};
25783
+ budget.setRetainedValues(retainedArgument, () => [argument]);
25784
+ try {
25785
+ const number = await sandboxNumber(argument, budget, context);
25786
+ return formatNumber(value, methodName, number, budget);
25787
+ } finally {
25788
+ budget.setRetainedValues(retainedArgument, void 0);
25789
+ }
25580
25790
  }
25581
- function asNumberOrUndefined(value) {
25582
- return value === void 0 ? void 0 : Number(value);
25791
+ function formatNumber(value, methodName, argument, budget) {
25792
+ let result;
25793
+ try {
25794
+ result = value[methodName](argument);
25795
+ } catch (error) {
25796
+ if (!(error instanceof RangeError)) throw error;
25797
+ const detail = methodName === "toString" ? "radix must be between 2 and 36." : methodName === "toPrecision" ? "precision must be between 1 and 100." : "digits must be between 0 and 100.";
25798
+ throw new RangeError(`Number#${methodName} ${detail}`);
25799
+ }
25800
+ return budget.allocateString(result);
25583
25801
  }
25584
- function asStringOrUndefined(value) {
25585
- return value === void 0 ? void 0 : String(value);
25802
+
25803
+ // packages/safe-js/src/interp/methods/generator.ts
25804
+ var generatorMethodNames = /* @__PURE__ */ new Set(["next", "return", "throw"]);
25805
+ function getGeneratorMember(target, property, budget) {
25806
+ if (typeof property !== "string" || !generatorMethodNames.has(property)) {
25807
+ return void 0;
25808
+ }
25809
+ return createSandboxClosure({
25810
+ sandbox: true,
25811
+ name: property,
25812
+ call: async ([value]) => {
25813
+ const iterator = getSandboxIterator(target);
25814
+ const result = await iterator[property](value);
25815
+ return allocateProducedSandboxValue(
25816
+ { value: result.value, done: result.done === true },
25817
+ budget
25818
+ );
25819
+ }
25820
+ });
25586
25821
  }
25587
25822
 
25588
25823
  // packages/safe-js/src/interp/methods/set.ts
@@ -25719,7 +25954,11 @@ function createObjectGlobal(methods, budget) {
25719
25954
  budget.chargeDataUsage(1);
25720
25955
  return /* @__PURE__ */ Object.create(null);
25721
25956
  }
25722
- if (typeof value !== "object") throw new TypeError("Object primitive boxing is not supported.");
25957
+ if (typeof value !== "object") {
25958
+ const box = createSandboxBox(value);
25959
+ budget.chargeDataUsage(measureSandboxData([box]));
25960
+ return box;
25961
+ }
25723
25962
  return value;
25724
25963
  };
25725
25964
  const constructor = createSandboxClosure({
@@ -25749,9 +25988,7 @@ function createObjectGlobal(methods, budget) {
25749
25988
  length: 0,
25750
25989
  call: (_args, context) => {
25751
25990
  const value = requireReceiver(context?.thisValue);
25752
- if (typeof value !== "object")
25753
- throw new TypeError("Object primitive boxing is not supported.");
25754
- return value;
25991
+ return construct([value]);
25755
25992
  }
25756
25993
  }),
25757
25994
  hasOwnProperty: createSandboxClosure({
@@ -25819,6 +26056,7 @@ function hasOwnSandboxProperty(value, key, enumerable) {
25819
26056
  return descriptor !== void 0 && (!enumerable || descriptor.enumerable === true);
25820
26057
  }
25821
26058
  function typeTag(value) {
26059
+ if (isSandboxBox(value)) value = boxedValue(value);
25822
26060
  if (value === void 0) return "Undefined";
25823
26061
  if (value === null) return "Null";
25824
26062
  if (typeof value === "string") return "String";
@@ -25923,12 +26161,12 @@ function isSandboxSetConstructor(value) {
25923
26161
  function populateCollection(source, collection, { name, budget, context, append, retainedValues }) {
25924
26162
  budget.allocateCollectionEntries(0);
25925
26163
  if (source === void 0 || source === null) return collection;
25926
- const iterator = getSandboxIterator(source, budget);
26164
+ const iterator = getSandboxIterator(source, budget, context);
25927
26165
  if (iterator === void 0) throw new TypeError(`${name} constructor requires an iterable.`);
25928
26166
  let entry;
25929
26167
  let failure;
25930
26168
  const retained = {};
25931
- budget.setRetainedValues(retained, () => [source, collection, entry, failure, ...retainedValues?.() ?? []]);
26169
+ budget.setRetainedValues(retained, () => [source, iterator.retainedValue, collection, entry, failure, ...retainedValues?.() ?? []]);
25932
26170
  const checkData = createDataCheckpoint(budget, context);
25933
26171
  const closeOnThrow = (error) => {
25934
26172
  failure = isCapturedException(error) ? error.reason : error;
@@ -25938,7 +26176,7 @@ function populateCollection(source, collection, { name, budget, context, append,
25938
26176
  };
25939
26177
  try {
25940
26178
  const closing = iterator.return?.();
25941
- if (iterator.generator) return Promise.resolve(closing).then(() => {
26179
+ if (iterator.generator || iterator.asynchronous) return Promise.resolve(closing).then(() => {
25942
26180
  throw error;
25943
26181
  }, rethrow);
25944
26182
  } catch (closeError) {
@@ -25960,7 +26198,7 @@ function populateCollection(source, collection, { name, budget, context, append,
25960
26198
  }
25961
26199
  return false;
25962
26200
  };
25963
- if (iterator.generator) {
26201
+ if (iterator.generator || iterator.asynchronous) {
25964
26202
  return (async () => {
25965
26203
  try {
25966
26204
  checkData(collection, 0, true);
@@ -26915,22 +27153,29 @@ async function evaluateBinaryExpression(node, context) {
26915
27153
  if (left.kind !== "normal") {
26916
27154
  return left;
26917
27155
  }
27156
+ let leftValue = left.value;
26918
27157
  let rightValue;
26919
- const release = retainValues(context.budget, () => [left.value, rightValue]);
27158
+ const release = retainValues(context.budget, () => [leftValue, rightValue]);
26920
27159
  try {
26921
27160
  const right = await evaluateNode(node.right, context);
26922
27161
  if (right.kind !== "normal") {
26923
27162
  return right;
26924
27163
  }
26925
27164
  rightValue = right.value;
26926
- let leftValue = left.value;
26927
27165
  if (node.operator === "in") {
26928
27166
  if (typeof right.value !== "object" || right.value === null) {
26929
27167
  throw new TypeError("Right-hand side of 'in' must be an object.");
26930
27168
  }
26931
27169
  leftValue = await toPropertyKey(leftValue, context.budget, createCoercionContext(context));
26932
27170
  }
26933
- const value = applyBinaryOperator(node, leftValue, right.value, context);
27171
+ if (!["in", "instanceof", "===", "!=="].includes(node.operator)) {
27172
+ const equality = node.operator === "==" || node.operator === "!=";
27173
+ if (isSandboxBox(leftValue) && (!equality || rightValue !== null && rightValue !== void 0 && typeof rightValue !== "object"))
27174
+ leftValue = await toNumericPrimitive(leftValue, context);
27175
+ if (isSandboxBox(rightValue) && (!equality || left.value !== null && left.value !== void 0 && typeof left.value !== "object"))
27176
+ rightValue = await toNumericPrimitive(rightValue, context);
27177
+ }
27178
+ const value = applyBinaryOperator(node, leftValue, rightValue, context);
26934
27179
  return {
26935
27180
  kind: "normal",
26936
27181
  hasValue: true,
@@ -27518,63 +27763,68 @@ async function evaluateForOfStatement(node, context) {
27518
27763
  };
27519
27764
  }
27520
27765
  async function evaluateForOfIterator(node, value, context, restoredEntry) {
27521
- const iterator = getSandboxIterator(value, context.budget);
27766
+ const iterator = getSandboxIterator(value, context.budget, createCoercionContext(context));
27522
27767
  if (iterator === void 0) {
27523
27768
  throw new TypeError(`${String(value)} is not a supported iterable`);
27524
27769
  }
27525
- const nodeId = node.nodeId ?? -1;
27526
- let index = consumeRestoredLoopIterationIndex(node, context);
27527
- for (let skipped = 0; skipped < index; skipped += 1) {
27528
- const skippedIteration = await iterator.next();
27529
- if (typeof skippedIteration !== "object" || skippedIteration === null) {
27530
- throw new TypeError("Iterator result must be an object.");
27531
- }
27532
- if (skippedIteration.done) {
27533
- return normalEmptyResult();
27534
- }
27535
- }
27536
- while (true) {
27537
- const iteration = restoredEntry ?? await iterator.next();
27538
- restoredEntry = void 0;
27539
- if (typeof iteration !== "object" || iteration === null) {
27540
- throw new TypeError("Iterator result must be an object.");
27541
- }
27542
- if (iteration.done) {
27543
- context.activeLoopIterations.delete(nodeId);
27544
- return normalEmptyResult();
27545
- }
27546
- context.activeLoopIterations.set(
27547
- nodeId,
27548
- iterator.snapshotIndex === void 0 ? index : {
27549
- get index() {
27550
- return iterator.snapshotIndex();
27551
- },
27552
- values: [value, iteration.value]
27770
+ const releaseIterator = retainValues(context.budget, () => [value, iterator.retainedValue]);
27771
+ try {
27772
+ const nodeId = node.nodeId ?? -1;
27773
+ let index = consumeRestoredLoopIterationIndex(node, context);
27774
+ for (let skipped = 0; skipped < index; skipped += 1) {
27775
+ const skippedIteration = await iterator.next();
27776
+ if (typeof skippedIteration !== "object" || skippedIteration === null) {
27777
+ throw new TypeError("Iterator result must be an object.");
27778
+ }
27779
+ if (skippedIteration.done) {
27780
+ return normalEmptyResult();
27553
27781
  }
27554
- );
27555
- const scope = context.scope.child();
27556
- const binding = await bindForOfLoopVariable(node.left, iteration.value, scope, context);
27557
- if (!binding.ok) {
27558
- return binding.result;
27559
- }
27560
- const iterationContext = createLoopIterationContext(context, scope);
27561
- emitLoopIterationBreakpoint(node, iterationContext);
27562
- const result = await evaluateNode(node.body, iterationContext);
27563
- if (isMatchingBreak(result, loopLabels(node))) {
27564
- context.activeLoopIterations.delete(nodeId);
27565
- await closeIterator(iterator);
27566
- return normalEmptyResult();
27567
27782
  }
27568
- if (isMatchingContinue(result, loopLabels(node))) {
27783
+ while (true) {
27784
+ const iteration = restoredEntry ?? await iterator.next();
27785
+ restoredEntry = void 0;
27786
+ if (typeof iteration !== "object" || iteration === null) {
27787
+ throw new TypeError("Iterator result must be an object.");
27788
+ }
27789
+ if (iteration.done) {
27790
+ context.activeLoopIterations.delete(nodeId);
27791
+ return normalEmptyResult();
27792
+ }
27793
+ context.activeLoopIterations.set(
27794
+ nodeId,
27795
+ iterator.snapshotIndex === void 0 ? index : {
27796
+ get index() {
27797
+ return iterator.snapshotIndex();
27798
+ },
27799
+ values: [value, iteration.value]
27800
+ }
27801
+ );
27802
+ const scope = context.scope.child();
27803
+ const binding = await bindForOfLoopVariable(node.left, iteration.value, scope, context);
27804
+ if (!binding.ok) {
27805
+ return binding.result;
27806
+ }
27807
+ const iterationContext = createLoopIterationContext(context, scope);
27808
+ emitLoopIterationBreakpoint(node, iterationContext);
27809
+ const result = await evaluateNode(node.body, iterationContext);
27810
+ if (isMatchingBreak(result, loopLabels(node))) {
27811
+ context.activeLoopIterations.delete(nodeId);
27812
+ await closeIterator(iterator);
27813
+ return normalEmptyResult();
27814
+ }
27815
+ if (isMatchingContinue(result, loopLabels(node))) {
27816
+ index += 1;
27817
+ continue;
27818
+ }
27819
+ if (result.kind !== "normal") {
27820
+ context.activeLoopIterations.delete(nodeId);
27821
+ await closeIterator(iterator);
27822
+ return result;
27823
+ }
27569
27824
  index += 1;
27570
- continue;
27571
- }
27572
- if (result.kind !== "normal") {
27573
- context.activeLoopIterations.delete(nodeId);
27574
- await closeIterator(iterator);
27575
- return result;
27576
27825
  }
27577
- index += 1;
27826
+ } finally {
27827
+ releaseIterator();
27578
27828
  }
27579
27829
  }
27580
27830
  async function evaluateForInStatement(node, context) {
@@ -27944,52 +28194,64 @@ async function evaluateYieldDelegate(node, context) {
27944
28194
  if (argument.kind !== "normal") {
27945
28195
  return argument;
27946
28196
  }
27947
- const iterator = getSandboxIterator(argument.value, context.budget);
28197
+ const iterator = getSandboxIterator(
28198
+ argument.value,
28199
+ context.budget,
28200
+ createCoercionContext(context)
28201
+ );
27948
28202
  if (iterator === void 0) {
27949
28203
  throw new TypeError(`${String(argument.value)} is not a supported iterable`);
27950
28204
  }
27951
- let completion = {
27952
- type: "normal",
27953
- value: void 0
27954
- };
27955
- const replay = context.generatorResume?.sent ?? [];
27956
- let replayIndex = 0;
27957
- while (true) {
27958
- const method = completion.type === "normal" ? "next" : completion.type;
27959
- const iteratorMethod = iterator[method];
27960
- if (iteratorMethod === void 0) {
27961
- if (completion.type === "throw") {
27962
- throw completion.value;
28205
+ const releaseIterator = retainValues(context.budget, () => [
28206
+ argument.value,
28207
+ iterator.retainedValue
28208
+ ]);
28209
+ try {
28210
+ let completion = {
28211
+ type: "normal",
28212
+ value: void 0
28213
+ };
28214
+ const replay = context.generatorResume?.sent ?? [];
28215
+ let replayIndex = 0;
28216
+ while (true) {
28217
+ const method = completion.type === "normal" ? "next" : completion.type;
28218
+ const iteratorMethod = iterator[method];
28219
+ if (iteratorMethod === void 0) {
28220
+ if (completion.type === "throw") {
28221
+ throw completion.value;
28222
+ }
28223
+ return generatorCompletionResult(completion);
27963
28224
  }
27964
- return generatorCompletionResult(completion);
27965
- }
27966
- const result = await iteratorMethod(completion.value);
27967
- if (result.done) {
27968
- if (completion.type === "return") {
27969
- return generatorCompletionResult({ type: "return", value: result.value });
28225
+ const result = await iteratorMethod(completion.value);
28226
+ if (result.done) {
28227
+ if (completion.type === "return") {
28228
+ return generatorCompletionResult({ type: "return", value: result.value });
28229
+ }
28230
+ return {
28231
+ kind: "normal",
28232
+ hasValue: true,
28233
+ value: result.value
28234
+ };
27970
28235
  }
27971
- return {
27972
- kind: "normal",
27973
- hasValue: true,
27974
- value: result.value
27975
- };
27976
- }
27977
- if (replayIndex < replay.length - 1) {
27978
- completion = replay[replayIndex + 1];
27979
- replayIndex += 1;
27980
- continue;
28236
+ if (replayIndex < replay.length - 1) {
28237
+ completion = replay[replayIndex + 1];
28238
+ replayIndex += 1;
28239
+ continue;
28240
+ }
28241
+ const completionPromise = context.generatorYield(
28242
+ allocateProducedSandboxValue(result.value, context.budget),
28243
+ node.nodeId
28244
+ );
28245
+ emitResumeBreakpoint(context, {
28246
+ kind: "generator-yield",
28247
+ nodeId: node.nodeId,
28248
+ span: node.span
28249
+ });
28250
+ completion = await completionPromise;
28251
+ context.generatorResume = void 0;
27981
28252
  }
27982
- const completionPromise = context.generatorYield(
27983
- allocateProducedSandboxValue(result.value, context.budget),
27984
- node.nodeId
27985
- );
27986
- emitResumeBreakpoint(context, {
27987
- kind: "generator-yield",
27988
- nodeId: node.nodeId,
27989
- span: node.span
27990
- });
27991
- completion = await completionPromise;
27992
- context.generatorResume = void 0;
28253
+ } finally {
28254
+ releaseIterator();
27993
28255
  }
27994
28256
  }
27995
28257
  function generatorCompletionResult(completion) {
@@ -28136,6 +28398,14 @@ async function evaluateMemberExpression(node, context) {
28136
28398
  }
28137
28399
  function getPropertyValue(target, property, context) {
28138
28400
  if (isGuestHostObject(target)) return getHostObjectMember(target, String(property));
28401
+ if (typeof target === "string" || typeof target === "number" || typeof target === "boolean") {
28402
+ const prototype = getBoxedPrototype(target, context.budget);
28403
+ if (prototype !== void 0) {
28404
+ if (typeof target === "string" && (property === "length" || getStringIndex(property) !== void 0))
28405
+ return getStringMember(target, property, context.budget);
28406
+ return getMemberValue(prototype, property, context);
28407
+ }
28408
+ }
28139
28409
  if (typeof target === "string") return getStringMember(target, property, context.budget);
28140
28410
  if (typeof target === "number") return getNumberMember(property, context.budget);
28141
28411
  if (typeof target === "boolean") return void 0;
@@ -28307,6 +28577,15 @@ async function evaluateMemberCallExpression(node, context) {
28307
28577
  ...reference,
28308
28578
  property: await toPropertyKey(reference.property, context.budget, createCoercionContext(context))
28309
28579
  };
28580
+ if ((typeof member.object === "string" || typeof member.object === "number" || typeof member.object === "boolean") && getBoxedPrototype(member.object, context.budget) !== void 0) {
28581
+ if (isDefaultBoxedMethod(member.object, member.property, context.budget)) {
28582
+ if (typeof member.object === "string" && isStringMethodName(member.property))
28583
+ return evaluateStringMethodCall(node, member.object, member.property, context);
28584
+ if (typeof member.object === "number" && isNumberMethodName(member.property))
28585
+ return evaluateNumberMethodCall(node, member.object, member.property, context);
28586
+ }
28587
+ return evaluateResolvedCallExpression(node, getPropertyValue(member.object, member.property, context), context, member.object);
28588
+ }
28310
28589
  if (typeof member.object === "string" && isStringMethodName(member.property)) {
28311
28590
  return evaluateStringMethodCall(node, member.object, member.property, context);
28312
28591
  }
@@ -28668,33 +28947,41 @@ function hasSandboxProperty(value, key, context) {
28668
28947
  return false;
28669
28948
  }
28670
28949
  async function applyCompoundAssignmentOperator(operator, left, right, context) {
28671
- left = await toNumericPrimitive(left, context);
28672
- right = await toNumericPrimitive(right, context);
28673
- switch (operator) {
28674
- case "+=":
28675
- return applyAdditionOperator(left, right, context);
28676
- case "-=":
28677
- return toNumber(left) - toNumber(right);
28678
- case "*=":
28679
- return toNumber(left) * toNumber(right);
28680
- case "/=":
28681
- return toNumber(left) / toNumber(right);
28682
- case "%=":
28683
- return toNumber(left) % toNumber(right);
28684
- case "**=":
28685
- return toNumber(left) ** toNumber(right);
28686
- case "&=":
28687
- return toNumber(left) & toNumber(right);
28688
- case "|=":
28689
- return toNumber(left) | toNumber(right);
28690
- case "^=":
28691
- return toNumber(left) ^ toNumber(right);
28692
- case "<<=":
28693
- return toNumber(left) << toNumber(right);
28694
- case ">>=":
28695
- return toNumber(left) >> toNumber(right);
28696
- case ">>>=":
28697
- return toNumber(left) >>> toNumber(right);
28950
+ const convertingObject = typeof left === "object" && left !== null;
28951
+ let convertedLeft;
28952
+ const release = retainValues(context.budget, () => [convertedLeft]);
28953
+ try {
28954
+ left = await toNumericPrimitive(left, context);
28955
+ if (convertingObject) convertedLeft = left;
28956
+ right = await toNumericPrimitive(right, context);
28957
+ switch (operator) {
28958
+ case "+=":
28959
+ return applyAdditionOperator(left, right, context);
28960
+ case "-=":
28961
+ return toNumber(left) - toNumber(right);
28962
+ case "*=":
28963
+ return toNumber(left) * toNumber(right);
28964
+ case "/=":
28965
+ return toNumber(left) / toNumber(right);
28966
+ case "%=":
28967
+ return toNumber(left) % toNumber(right);
28968
+ case "**=":
28969
+ return toNumber(left) ** toNumber(right);
28970
+ case "&=":
28971
+ return toNumber(left) & toNumber(right);
28972
+ case "|=":
28973
+ return toNumber(left) | toNumber(right);
28974
+ case "^=":
28975
+ return toNumber(left) ^ toNumber(right);
28976
+ case "<<=":
28977
+ return toNumber(left) << toNumber(right);
28978
+ case ">>=":
28979
+ return toNumber(left) >> toNumber(right);
28980
+ case ">>>=":
28981
+ return toNumber(left) >>> toNumber(right);
28982
+ }
28983
+ } finally {
28984
+ release();
28698
28985
  }
28699
28986
  }
28700
28987
  function applyAdditionOperator(left, right, context) {
@@ -29091,12 +29378,12 @@ async function evaluateSpreadElement(node, context) {
29091
29378
  result: value
29092
29379
  };
29093
29380
  }
29094
- const iterator = getSandboxIterator(value.value, context.budget);
29381
+ const iterator = getSandboxIterator(value.value, context.budget, createCoercionContext(context));
29095
29382
  if (iterator === void 0) {
29096
29383
  throw new TypeError("Spread arguments must evaluate to an iterable.");
29097
29384
  }
29098
29385
  const spreadValues = [];
29099
- const release = retainValues(context.budget, () => [value.value, ...spreadValues]);
29386
+ const release = retainValues(context.budget, () => [value.value, iterator.retainedValue, ...spreadValues]);
29100
29387
  try {
29101
29388
  while (true) {
29102
29389
  const next = await iterator.next();
@@ -30176,6 +30463,30 @@ function copyHostValueToSandbox(value, stackFrames, options, state, path) {
30176
30463
  state
30177
30464
  );
30178
30465
  }
30466
+ const primitive = nativeBoxedValue(value);
30467
+ if (primitive !== void 0) {
30468
+ if (typeof primitive === "string") budget.allocateString(primitive);
30469
+ const original = value;
30470
+ const existing = state.seen.get(original);
30471
+ if (existing !== void 0) return existing;
30472
+ const copy = createSandboxBox(primitive);
30473
+ state.seen.set(original, copy);
30474
+ budget.chargeDataUsage(measureSandboxData([copy]));
30475
+ for (const [key, descriptor] of boxedDataProperties(original)) {
30476
+ if (!("value" in descriptor)) throw new TypeError(`Unsupported sandbox value at ${joinPath2(path, key)}: accessor property`);
30477
+ Object.defineProperty(copy, budget.allocateString(key), {
30478
+ ...descriptor,
30479
+ value: copyHostValueToSandbox(
30480
+ descriptor.value,
30481
+ stackFrames,
30482
+ { ...options, capabilityPath: [...options.capabilityPath ?? [], key] },
30483
+ state,
30484
+ joinPath2(path, key)
30485
+ )
30486
+ });
30487
+ }
30488
+ return copy;
30489
+ }
30179
30490
  const date = copyNativeDate(value);
30180
30491
  if (date !== void 0) {
30181
30492
  const existing = state.seen.get(value);
@@ -30585,7 +30896,7 @@ function createReplayableRandom(options = {}) {
30585
30896
 
30586
30897
  // packages/safe-js/src/realm.ts
30587
30898
  import { AsyncLocalStorage as AsyncLocalStorage6 } from "node:async_hooks";
30588
- import { types as types5 } from "node:util";
30899
+ import { types as types6 } from "node:util";
30589
30900
 
30590
30901
  // packages/safe-js/src/interp/globals/console-json.ts
30591
30902
  function createConsoleJsonGlobals(options) {
@@ -30594,12 +30905,18 @@ function createConsoleJsonGlobals(options) {
30594
30905
  JSON: {
30595
30906
  parse: createSandboxClosure({
30596
30907
  sandbox: true,
30597
- call: async ([text]) => parseJson(text, options.budget),
30908
+ call: async ([text], context) => {
30909
+ const converted = sandboxString(text, options.budget, context);
30910
+ return copyJsonToSandbox(
30911
+ JSON.parse(converted instanceof Promise ? await converted : converted),
30912
+ options.budget
30913
+ );
30914
+ },
30598
30915
  name: "parse"
30599
30916
  }),
30600
30917
  stringify: createSandboxClosure({
30601
30918
  sandbox: true,
30602
- call: async ([value, replacer, indent]) => stringifyJson(value, replacer, indent, options.budget),
30919
+ call: async ([value, replacer, indent], context) => stringifyJson(value, replacer, indent, options.budget, context),
30603
30920
  name: "stringify"
30604
30921
  })
30605
30922
  },
@@ -30660,11 +30977,7 @@ function createConsoleJsonGlobals(options) {
30660
30977
  )
30661
30978
  };
30662
30979
  }
30663
- function parseJson(input, budget) {
30664
- const text = budget.allocateString(toJsonParseText(input));
30665
- return copyJsonToSandbox(JSON.parse(text), budget);
30666
- }
30667
- async function stringifyJson(value, replacer, indent, budget) {
30980
+ async function stringifyJson(value, replacer, indent, budget, context) {
30668
30981
  if (replacer !== void 0 && replacer !== null && !isSandboxClosure(replacer)) {
30669
30982
  throw new TypeError(
30670
30983
  "JSON.stringify(value, replacer, indent) only supports function, null, or undefined replacers."
@@ -30679,6 +30992,7 @@ async function stringifyJson(value, replacer, indent, budget) {
30679
30992
  defineDataProperty(holder, "", value);
30680
30993
  const output = await stringifyProperty("", holder, {
30681
30994
  budget,
30995
+ context,
30682
30996
  gap: normalizeStringifyGap(indent),
30683
30997
  replacer: isSandboxClosure(replacer) ? replacer : void 0,
30684
30998
  stack: []
@@ -30688,15 +31002,6 @@ async function stringifyJson(value, replacer, indent, budget) {
30688
31002
  }
30689
31003
  return budget.allocateString(output);
30690
31004
  }
30691
- function toJsonParseText(input) {
30692
- if (Array.isArray(input)) {
30693
- return input.map((entry) => entry === null || entry === void 0 ? "" : toJsonParseText(entry)).join(",");
30694
- }
30695
- if (typeof input === "object" && input !== null) {
30696
- return "[object Object]";
30697
- }
30698
- return String(input);
30699
- }
30700
31005
  async function stringifyProperty(key, holder, state, indent = "") {
30701
31006
  let value = getOwnDataValue(holder, key);
30702
31007
  if (isSandboxDate(value)) {
@@ -30713,6 +31018,10 @@ async function stringifyProperty(key, holder, state, indent = "") {
30713
31018
  return stringifyValue(value, state, indent);
30714
31019
  }
30715
31020
  async function stringifyValue(value, state, indent) {
31021
+ if (isSandboxBox(value)) {
31022
+ const primitive = boxedValue(value);
31023
+ value = typeof primitive === "number" ? await sandboxNumber(value, state.budget, state.context) : typeof primitive === "string" ? await sandboxString(value, state.budget, state.context) : primitive;
31024
+ }
30716
31025
  if (value === null) {
30717
31026
  return "null";
30718
31027
  }
@@ -30997,7 +31306,7 @@ function structuredCloneSandboxValue(value, budget, parent) {
30997
31306
  const operation = budget.acquireCompileOwner(false, parent?.owner);
30998
31307
  const compilation = parent?.owner === operation.owner ? parent : new CompileScope(operation.owner);
30999
31308
  try {
31000
- const clone = cloneSandboxValue(value, { compilation, resetRegexLastIndex: true });
31309
+ const clone = cloneSandboxValue(value, { compilation, resetRegexLastIndex: true, structuredClone: true });
31001
31310
  assertSandboxGraphDepth(clone);
31002
31311
  assertStructuredCloneable(clone, /* @__PURE__ */ new WeakSet());
31003
31312
  allocateProducedSandboxValue(clone, budget);
@@ -31034,6 +31343,72 @@ function assertStructuredCloneable(value, seen) {
31034
31343
  }
31035
31344
  }
31036
31345
 
31346
+ // packages/safe-js/src/interp/globals/primitives.ts
31347
+ function createPrimitiveConstructor(options, budget) {
31348
+ const initial = { Number: 0, String: "", Boolean: false }[options.name];
31349
+ const kind = typeof initial;
31350
+ const prototype = createSandboxBox(initial);
31351
+ const allocate = (value) => {
31352
+ const box = createSandboxBox(value);
31353
+ budget.chargeDataUsage(measureSandboxData([box]));
31354
+ return box;
31355
+ };
31356
+ const constructor = createSandboxClosure({
31357
+ guest: true,
31358
+ sandbox: true,
31359
+ name: options.name,
31360
+ length: 1,
31361
+ call: options.call,
31362
+ construct: (args, context) => {
31363
+ const value = options.call(args, context);
31364
+ return value instanceof Promise ? value.then(allocate) : allocate(value);
31365
+ }
31366
+ });
31367
+ const properties = materializeFunctionProperties(constructor);
31368
+ Object.defineProperty(properties, "prototype", { value: prototype, writable: false });
31369
+ Object.defineProperty(prototype, "constructor", {
31370
+ value: constructor,
31371
+ writable: true,
31372
+ configurable: true
31373
+ });
31374
+ for (const [name, value] of Object.entries(options.properties ?? {}))
31375
+ Object.defineProperty(properties, name, {
31376
+ value,
31377
+ writable: isSandboxClosure(value),
31378
+ configurable: isSandboxClosure(value)
31379
+ });
31380
+ const methods = /* @__PURE__ */ new Map([
31381
+ [
31382
+ "valueOf",
31383
+ createSandboxClosure({
31384
+ sandbox: true,
31385
+ name: "valueOf",
31386
+ length: 0,
31387
+ call: (_args, context) => primitiveReceiver(context?.thisValue, kind)
31388
+ })
31389
+ ]
31390
+ ]);
31391
+ if (kind === "number") {
31392
+ for (const name of numberMethodNames) methods.set(name, getNumberMember(name, budget));
31393
+ } else {
31394
+ methods.set(
31395
+ "toString",
31396
+ createSandboxClosure({
31397
+ sandbox: true,
31398
+ name: "toString",
31399
+ length: 0,
31400
+ call: (_args, context) => budget.allocateString(String(primitiveReceiver(context?.thisValue, kind)))
31401
+ })
31402
+ );
31403
+ if (kind === "string")
31404
+ for (const name of stringMethodNames) methods.set(name, getStringMember("", name, budget));
31405
+ }
31406
+ for (const [name, value] of methods)
31407
+ Object.defineProperty(prototype, name, { value, writable: true, configurable: true });
31408
+ installBoxedPrototype(budget, prototype, constructor);
31409
+ return constructor;
31410
+ }
31411
+
31037
31412
  // packages/safe-js/src/interp/globals/object-array.ts
31038
31413
  function createObjectArrayGlobals(options) {
31039
31414
  return {
@@ -31099,6 +31474,7 @@ function createObjectArrayGlobals(options) {
31099
31474
  sandbox: true,
31100
31475
  call: ([value]) => {
31101
31476
  if (isSandboxDate(value)) return getDatePrototype(value, options.budget, options.compileOwner);
31477
+ if (value !== null && value !== void 0 && typeof value !== "object") value = createSandboxBox(value);
31102
31478
  objectProperties(value);
31103
31479
  return getSandboxPrototype(value, options.budget);
31104
31480
  },
@@ -31138,11 +31514,11 @@ function createObjectArrayGlobals(options) {
31138
31514
  fromEntries: createSandboxClosure({
31139
31515
  sandbox: true,
31140
31516
  call: ([value], context) => {
31141
- const iterator = getSandboxIterator(value, options.budget);
31517
+ const iterator = getSandboxIterator(value, options.budget, context);
31142
31518
  if (iterator === void 0) {
31143
31519
  throw new TypeError("Object.fromEntries requires an iterable.");
31144
31520
  }
31145
- if (context === void 0 && !iterator.generator) {
31521
+ if (context === void 0 && !iterator.generator && !iterator.asynchronous) {
31146
31522
  return allocateProducedSandboxValue(
31147
31523
  Object.setPrototypeOf(
31148
31524
  Reflect.apply(Object.fromEntries, Object, [{ [Symbol.iterator]: () => iterator }]),
@@ -31200,8 +31576,7 @@ function createObjectArrayGlobals(options) {
31200
31576
  })
31201
31577
  }
31202
31578
  }),
31203
- String: createSandboxClosure({
31204
- sandbox: true,
31579
+ String: createPrimitiveConstructor({
31205
31580
  call: (args, context) => sandboxString(args.length === 0 ? "" : args[0], options.budget, context),
31206
31581
  name: "String",
31207
31582
  properties: {
@@ -31221,9 +31596,8 @@ function createObjectArrayGlobals(options) {
31221
31596
  name: "fromCodePoint"
31222
31597
  })
31223
31598
  }
31224
- }),
31225
- Number: createSandboxClosure({
31226
- sandbox: true,
31599
+ }, options.budget),
31600
+ Number: createPrimitiveConstructor({
31227
31601
  call: (args, context) => sandboxNumber(args.length === 0 ? 0 : args[0], options.budget, context),
31228
31602
  name: "Number",
31229
31603
  properties: {
@@ -31257,12 +31631,11 @@ function createObjectArrayGlobals(options) {
31257
31631
  NEGATIVE_INFINITY: Number.NEGATIVE_INFINITY,
31258
31632
  POSITIVE_INFINITY: Number.POSITIVE_INFINITY
31259
31633
  }
31260
- }),
31261
- Boolean: createSandboxClosure({
31262
- sandbox: true,
31634
+ }, options.budget),
31635
+ Boolean: createPrimitiveConstructor({
31263
31636
  call: ([value]) => Boolean(value),
31264
31637
  name: "Boolean"
31265
- })
31638
+ }, options.budget)
31266
31639
  };
31267
31640
  }
31268
31641
  async function objectFromSandboxEntries(items, iterator, budget, context) {
@@ -31272,7 +31645,7 @@ async function objectFromSandboxEntries(items, iterator, budget, context) {
31272
31645
  let value;
31273
31646
  let failure;
31274
31647
  const retained = {};
31275
- budget.setRetainedValues(retained, () => [items, object, entry, key, value, failure]);
31648
+ budget.setRetainedValues(retained, () => [items, iterator.retainedValue, object, entry, key, value, failure]);
31276
31649
  const checkData = createDataCheckpoint(budget, context);
31277
31650
  const closeOnThrow = async (error) => {
31278
31651
  failure = isCapturedException(error) ? error.reason : error;
@@ -31323,6 +31696,10 @@ function assignSandboxValues(target, sources, budget) {
31323
31696
  if (target === null || target === void 0) {
31324
31697
  throw new TypeError("Object.assign(target, ...sources) requires a non-null target.");
31325
31698
  }
31699
+ if (typeof target !== "object") {
31700
+ target = createSandboxBox(target);
31701
+ budget.chargeDataUsage(measureSandboxData([target]));
31702
+ }
31326
31703
  if (!isGuestClosure(target) && !isAssignableSandboxTarget(target)) {
31327
31704
  throw new TypeError("Object.assign(target, ...sources) requires an object or array target.");
31328
31705
  }
@@ -31392,13 +31769,13 @@ async function arrayFromSandboxValues(args, budget, context) {
31392
31769
  throw new TypeError("Array.from requires a non-null input.");
31393
31770
  }
31394
31771
  const read = (property) => context?.getProperty !== void 0 ? context.getProperty(items, property) : getSandboxDataProperty(items, property, budget);
31395
- const iterator = getSandboxIterator(items, budget);
31772
+ const iterator = getSandboxIterator(items, budget, context);
31396
31773
  const constructor = context?.thisValue;
31397
31774
  let result;
31398
31775
  let currentValue;
31399
31776
  let failure;
31400
31777
  const retained = {};
31401
- budget.setRetainedValues(retained, () => [items, mapFn, constructor, result, currentValue, failure]);
31778
+ budget.setRetainedValues(retained, () => [items, iterator?.retainedValue, mapFn, constructor, result, currentValue, failure]);
31402
31779
  const checkData = createDataCheckpoint(budget, context);
31403
31780
  const closeOnThrow = async (error) => {
31404
31781
  failure = isCapturedException(error) ? error.reason : error;
@@ -31657,7 +32034,7 @@ var RealmState = class {
31657
32034
  throw new TypeError("Realm limits must be positive safe integers with supported names.");
31658
32035
  this.limits[name] = Number(value);
31659
32036
  }
31660
- if (options.extensions !== void 0 && (!Array.isArray(options.extensions) || types5.isProxy(options.extensions)))
32037
+ if (options.extensions !== void 0 && (!Array.isArray(options.extensions) || types6.isProxy(options.extensions)))
31661
32038
  throw new TypeError("Extensions must be a registration array.");
31662
32039
  const registrations = options.extensions ?? [];
31663
32040
  const extensions = [];
@@ -31892,7 +32269,7 @@ var RealmState = class {
31892
32269
  return this.phase.run(phase, () => {
31893
32270
  try {
31894
32271
  const result = call();
31895
- if (types5.isPromise(result) || phase.pending.size > 0 || phase.failure !== void 0) {
32272
+ if (types6.isPromise(result) || phase.pending.size > 0 || phase.failure !== void 0) {
31896
32273
  return Promise.resolve(result).then(
31897
32274
  async (value) => {
31898
32275
  await Promise.allSettled(phase.pending);
@@ -31961,7 +32338,7 @@ var RealmState = class {
31961
32338
  },
31962
32339
  read: (operation, validate) => {
31963
32340
  const value = this.invokeHost(operation, operation);
31964
- if (types5.isPromise(value)) {
32341
+ if (types6.isPromise(value)) {
31965
32342
  void Promise.resolve(value).catch(() => void 0);
31966
32343
  throw new TypeError("Live property operations must be synchronous.");
31967
32344
  }
@@ -31969,7 +32346,7 @@ var RealmState = class {
31969
32346
  },
31970
32347
  write: (operation, value) => {
31971
32348
  const result = this.invokeHost(operation, () => operation(this.exportValue(value)));
31972
- if (types5.isPromise(result)) {
32349
+ if (types6.isPromise(result)) {
31973
32350
  void Promise.resolve(result).catch(() => void 0);
31974
32351
  throw new TypeError("Live property setters must be synchronous.");
31975
32352
  }
@@ -32178,7 +32555,7 @@ var RealmState = class {
32178
32555
  }
32179
32556
  });
32180
32557
  const output = getExtensionSetup(extension)(context);
32181
- if (types5.isPromise(output)) {
32558
+ if (types6.isPromise(output)) {
32182
32559
  void Promise.resolve(output).catch(() => void 0);
32183
32560
  throw new TypeError("Extension setup must be synchronous.");
32184
32561
  }
@@ -32370,7 +32747,7 @@ var RealmState = class {
32370
32747
  };
32371
32748
  function readModules(input) {
32372
32749
  const entries = (value, label) => {
32373
- if (types5.isMap(value) && !types5.isProxy(value)) {
32750
+ if (types6.isMap(value) && !types6.isProxy(value)) {
32374
32751
  const result = [...Map.prototype.entries.call(value)];
32375
32752
  if (result.length > 4096 || result.some(([key]) => typeof key !== "string" || key.length === 0))
32376
32753
  throw new TypeError(`${label} requires bounded string keys.`);
@@ -33615,4 +33992,4 @@ export {
33615
33992
  FileSnapshotBackend,
33616
33993
  run
33617
33994
  };
33618
- //# sourceMappingURL=chunk-VKGWGZBH.js.map
33995
+ //# sourceMappingURL=chunk-RU2BCN4G.js.map