@poe-platform/safe-js 0.1.25 → 0.1.27

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.
@@ -6331,6 +6331,7 @@ function serializedDateTime(value) {
6331
6331
  }
6332
6332
 
6333
6333
  // packages/safe-js/src/interp/host-capabilities.ts
6334
+ var MAX_INDEXED_LENGTH = 65536;
6334
6335
  var hostObjects = /* @__PURE__ */ new WeakMap();
6335
6336
  var guestObjects = /* @__PURE__ */ new WeakMap();
6336
6337
  var guestCallbacks = /* @__PURE__ */ new WeakMap();
@@ -6355,8 +6356,23 @@ function revokeGuestReference(reference, owner) {
6355
6356
  }
6356
6357
  function createLiveHostObject(definition, controller) {
6357
6358
  const input = readDataRecord(definition, "Host object definition");
6358
- if (Object.keys(input).some((key) => key !== "properties" && key !== "methods"))
6359
+ if (Object.keys(input).some((key) => key !== "properties" && key !== "methods" && key !== "indexed"))
6359
6360
  throw new TypeError("Unknown host object definition field.");
6361
+ let indexed;
6362
+ if (input.indexed !== void 0) {
6363
+ const data = readDataRecord(input.indexed, "Indexed host capability");
6364
+ if (Object.keys(data).some((key) => !["length", "get", "maxLength"].includes(key)))
6365
+ throw new TypeError("Unknown indexed host capability field.");
6366
+ if (typeof data.length !== "function" || typeof data.get !== "function")
6367
+ throw new TypeError("Indexed length and get must be synchronous functions.");
6368
+ if (typeof data.maxLength !== "number" || !Number.isInteger(data.maxLength) || data.maxLength < 1 || data.maxLength > MAX_INDEXED_LENGTH)
6369
+ throw new RangeError(`Indexed maxLength must be an integer from 1 to ${MAX_INDEXED_LENGTH}.`);
6370
+ indexed = {
6371
+ length: data.length,
6372
+ get: data.get,
6373
+ maxLength: data.maxLength
6374
+ };
6375
+ }
6360
6376
  const properties = /* @__PURE__ */ new Map();
6361
6377
  for (const [name, inputProperty] of Object.entries(
6362
6378
  readDataRecord(input.properties ?? {}, "Host properties")
@@ -6376,6 +6392,8 @@ function createLiveHostObject(definition, controller) {
6376
6392
  for (const name of [...properties.keys(), ...Object.keys(operations)]) {
6377
6393
  if (["constructor", "prototype", "__proto__"].includes(name))
6378
6394
  throw new TypeError(`Reserved host member '${name}'.`);
6395
+ if (indexed !== void 0 && (name === "length" || canonicalIndex(name) !== void 0))
6396
+ throw new TypeError(`Conflicting indexed host member '${name}'.`);
6379
6397
  }
6380
6398
  controller.assertActive();
6381
6399
  controller.chargeWork(properties.size + Object.keys(operations).length + 1);
@@ -6387,7 +6405,7 @@ function createLiveHostObject(definition, controller) {
6387
6405
  controller.method(operation)
6388
6406
  ])
6389
6407
  );
6390
- const state = { host, guest, controller, properties, methods };
6408
+ const state = { host, guest, controller, properties, methods, indexed };
6391
6409
  hostObjects.set(host, state);
6392
6410
  guestObjects.set(guest, state);
6393
6411
  return host;
@@ -6444,11 +6462,20 @@ function revokeHostObject(value, owner) {
6444
6462
  throw new TypeError("Foreign host object.");
6445
6463
  state.properties.clear();
6446
6464
  state.methods.clear();
6465
+ state.indexed = void 0;
6447
6466
  }
6448
6467
  function getHostObjectMember(value, key) {
6449
6468
  const state = guestObjects.get(value);
6450
6469
  state.controller.assertActive();
6451
6470
  state.controller.chargeWork();
6471
+ if (state.indexed !== void 0) {
6472
+ if (key === "length") return indexedLength(state);
6473
+ const index = canonicalIndex(key);
6474
+ if (index !== void 0) {
6475
+ if (index >= state.indexed.maxLength || index >= indexedLength(state)) return void 0;
6476
+ return state.controller.read(() => state.indexed.get(index));
6477
+ }
6478
+ }
6452
6479
  const property = state.properties.get(key);
6453
6480
  if (property !== void 0)
6454
6481
  return property.get === void 0 ? void 0 : state.controller.read(property.get);
@@ -6465,7 +6492,65 @@ function setHostObjectMember(value, key, entry) {
6465
6492
  function getHostObjectKeys(value) {
6466
6493
  const state = guestObjects.get(value);
6467
6494
  state.controller.assertActive();
6468
- return [...state.properties.keys(), ...state.methods.keys()];
6495
+ const length = state.indexed === void 0 ? 0 : indexedLength(state);
6496
+ const size = length + state.properties.size + state.methods.size;
6497
+ state.controller.checkLength(size);
6498
+ state.controller.chargeWork(size + 1);
6499
+ return [
6500
+ ...Array.from({ length }, (_entry, index) => String(index)),
6501
+ ...state.properties.keys(),
6502
+ ...state.methods.keys()
6503
+ ];
6504
+ }
6505
+ function hasHostObjectMember(value, key, enumerableOnly = false) {
6506
+ const state = guestObjects.get(value);
6507
+ state.controller.assertActive();
6508
+ state.controller.chargeWork();
6509
+ if (state.indexed !== void 0) {
6510
+ if (key === "length") return !enumerableOnly;
6511
+ const index = canonicalIndex(key);
6512
+ if (index !== void 0) return index < state.indexed.maxLength && index < indexedLength(state);
6513
+ }
6514
+ return state.properties.has(key) || state.methods.has(key);
6515
+ }
6516
+ function measureHostObjectData(value) {
6517
+ const state = guestObjects.get(value);
6518
+ let size = state.indexed === void 0 ? 0 : 16;
6519
+ for (const key of state.properties.keys()) size += key.length + 1;
6520
+ for (const key of state.methods.keys()) size += key.length + 1;
6521
+ return size;
6522
+ }
6523
+ function getHostObjectIterator(value) {
6524
+ const state = guestObjects.get(value);
6525
+ state.controller.assertActive();
6526
+ if (state.indexed === void 0) return void 0;
6527
+ let index = 0;
6528
+ let exhausted = false;
6529
+ return {
6530
+ next: () => {
6531
+ state.controller.assertActive();
6532
+ state.controller.chargeWork();
6533
+ if (exhausted) return { done: true, value: void 0 };
6534
+ if (index >= indexedLength(state)) {
6535
+ exhausted = true;
6536
+ return { done: true, value: void 0 };
6537
+ }
6538
+ const position = index++;
6539
+ return { done: false, value: state.controller.read(() => state.indexed.get(position)) };
6540
+ }
6541
+ };
6542
+ }
6543
+ function indexedLength(state) {
6544
+ state.controller.chargeWork();
6545
+ const length = state.controller.read(state.indexed.length);
6546
+ if (typeof length !== "number" || !Number.isInteger(length) || length < 0 || length > state.indexed.maxLength)
6547
+ throw new RangeError("Indexed length must be a non-negative integer within maxLength.");
6548
+ state.controller.checkLength(length);
6549
+ return length;
6550
+ }
6551
+ function canonicalIndex(key) {
6552
+ const index = Number(key);
6553
+ return Number.isInteger(index) && index >= 0 && index < 4294967295 && String(index) === key ? index : void 0;
6469
6554
  }
6470
6555
 
6471
6556
  // packages/safe-js/src/interp/values.ts
@@ -6718,6 +6803,8 @@ function graphEntries(value) {
6718
6803
  var guestClosures = /* @__PURE__ */ new WeakSet();
6719
6804
  var functionProperties = /* @__PURE__ */ new WeakMap();
6720
6805
  var prototypes = /* @__PURE__ */ new WeakMap();
6806
+ var intrinsicPrototypes = /* @__PURE__ */ new WeakMap();
6807
+ var intrinsicConstructors = /* @__PURE__ */ new WeakMap();
6721
6808
  var descriptorObjects = /* @__PURE__ */ new WeakSet();
6722
6809
  function registerGuestClosure(closure) {
6723
6810
  guestClosures.add(closure);
@@ -6762,27 +6849,49 @@ function getGuestFunctionProperty(closure, key) {
6762
6849
  }
6763
6850
  return properties === void 0 ? void 0 : Object.getOwnPropertyDescriptor(properties, key)?.value;
6764
6851
  }
6765
- function getSandboxPrototype(value) {
6766
- return prototypes.get(value) ?? null;
6852
+ function installObjectPrototype(budget, prototype, constructor) {
6853
+ prototypes.set(prototype, null);
6854
+ intrinsicPrototypes.set(budget, prototype);
6855
+ const records = [prototype, materializeFunctionProperties(constructor)].map((value) => ({
6856
+ value,
6857
+ descriptors: new Map(Object.entries(Object.getOwnPropertyDescriptors(value)))
6858
+ }));
6859
+ 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;
6860
+ intrinsicConstructors.set(constructor, () => records.every(({ value, descriptors }) => {
6861
+ const current = Object.getOwnPropertyDescriptors(value);
6862
+ return Object.keys(current).length === descriptors.size && Object.keys(current).every((key) => unchanged(descriptors.get(key), current[key]));
6863
+ }));
6864
+ budget.setRetainedValues(prototype, () => records.flatMap(({ value, descriptors }) => Object.entries(Object.getOwnPropertyDescriptors(value)).flatMap(([key, descriptor]) => unchanged(descriptors.get(key), descriptor) ? [] : [key, descriptor.value])));
6865
+ }
6866
+ function releaseObjectPrototype(budget) {
6867
+ const prototype = intrinsicPrototypes.get(budget);
6868
+ if (prototype !== void 0) budget.setRetainedValues(prototype, void 0);
6869
+ intrinsicPrototypes.delete(budget);
6870
+ }
6871
+ function getSandboxPrototype(value, budget) {
6872
+ if (prototypes.has(value)) return prototypes.get(value) ?? null;
6873
+ return budget !== void 0 && isPrototypeRecord(value) ? intrinsicPrototypes.get(budget) ?? null : null;
6767
6874
  }
6768
6875
  function setSandboxPrototype(value, prototype, budget) {
6876
+ if (budget !== void 0 && intrinsicPrototypes.get(budget) === value && prototype !== null) {
6877
+ throw new TypeError("Object.prototype has an immutable null prototype.");
6878
+ }
6769
6879
  if (!isPrototypeRecord(value) || prototype !== null && !isPrototypeRecord(prototype)) {
6770
6880
  throw new TypeError(
6771
6881
  "Prototype links require ordinary sandbox objects; callable and exotic prototype chains are not supported."
6772
6882
  );
6773
6883
  }
6774
- if (getSandboxPrototype(value) === prototype) return;
6884
+ if (prototypes.has(value) && getSandboxPrototype(value, budget) === prototype) return;
6775
6885
  if (!Object.isExtensible(isGuestClosure(value) ? materializeFunctionProperties(value) : value)) {
6776
6886
  throw new TypeError("Cannot change the prototype of a non-extensible object.");
6777
6887
  }
6778
6888
  let depth = 0;
6779
- for (let current = prototype; current !== null; current = getSandboxPrototype(current)) {
6889
+ for (let current = prototype; current !== null; current = getSandboxPrototype(current, budget)) {
6780
6890
  budget?.visitNode();
6781
6891
  assertSandboxDataDepth(depth++);
6782
6892
  if (current === value) throw new TypeError("Cyclic prototype value.");
6783
6893
  }
6784
- if (prototype === null) prototypes.delete(value);
6785
- else prototypes.set(value, prototype);
6894
+ prototypes.set(value, prototype);
6786
6895
  }
6787
6896
  function isPrototypeRecord(value) {
6788
6897
  if (isGuestHostObject(value)) return false;
@@ -6798,6 +6907,8 @@ function hasManagedDescriptors(value) {
6798
6907
  return descriptorObjects.has(value);
6799
6908
  }
6800
6909
  function hasGuestObjectState(value) {
6910
+ const intrinsicUnchanged = intrinsicConstructors.get(value);
6911
+ if (intrinsicUnchanged !== void 0) return !intrinsicUnchanged();
6801
6912
  if (isLiveCapability(value)) return true;
6802
6913
  if (functionProperties.has(value) || prototypes.has(value)) return true;
6803
6914
  return descriptorObjects.has(value) && Object.values(Object.getOwnPropertyDescriptors(value)).some(
@@ -8380,6 +8491,7 @@ function assertSnapshotInactive(snapshot) {
8380
8491
 
8381
8492
  // packages/safe-js/src/interp/iteration.ts
8382
8493
  function getSandboxIterator(value) {
8494
+ if (isGuestHostObject(value)) return getHostObjectIterator(value);
8383
8495
  if (isFloat32Array(value)) {
8384
8496
  return syncIterator(Float32Array.prototype.values.call(value));
8385
8497
  }
@@ -9504,6 +9616,7 @@ function createSandboxClosure(input) {
9504
9616
  if (input.sandbox === true) {
9505
9617
  Object.defineProperty(closure, "sandbox", { value: true });
9506
9618
  }
9619
+ if (input.generator === true) Object.defineProperty(closure, "generator", { value: true });
9507
9620
  if (input.length !== void 0) {
9508
9621
  Object.defineProperty(closure, "length", { value: input.length });
9509
9622
  }
@@ -9536,7 +9649,13 @@ function createSandboxClosure(input) {
9536
9649
  return Object.freeze(closure);
9537
9650
  }
9538
9651
  function ownEnumerableSandboxEntries(value) {
9539
- if (isGuestHostObject(value)) return getHostObjectKeys(value).map((key) => [key, getHostObjectMember(value, key)]);
9652
+ if (isGuestHostObject(value)) {
9653
+ const entries = [];
9654
+ for (const key of getHostObjectKeys(value)) {
9655
+ if (hasHostObjectMember(value, key, true)) entries.push([key, getHostObjectMember(value, key)]);
9656
+ }
9657
+ return entries;
9658
+ }
9540
9659
  if (value === null || value === void 0) throw new TypeError("Cannot convert undefined or null to object.");
9541
9660
  if (isGuestClosure(value)) return Object.entries(value.properties ?? {});
9542
9661
  if (isSandboxClosure(value) || isSandboxGenerator(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxPromise(value) || isSandboxRegex(value)) return [];
@@ -9694,7 +9813,7 @@ function measureSandboxData(values, options = {}) {
9694
9813
  return;
9695
9814
  }
9696
9815
  if (isGuestHostObject(value)) {
9697
- for (const key of getHostObjectKeys(value)) usage += key.length + 1;
9816
+ usage += measureHostObjectData(value);
9698
9817
  return;
9699
9818
  }
9700
9819
  const prototype = getSandboxPrototype(value);
@@ -9791,7 +9910,7 @@ function measureSandboxData(values, options = {}) {
9791
9910
  function reconcileCompiledValues(budget, values, compilation, parent, escaping = []) {
9792
9911
  while (parent?.closed) parent = parent.parent;
9793
9912
  const included = /* @__PURE__ */ new Set();
9794
- const usage = measureSandboxData(values, { compileTickets: included });
9913
+ const usage = measureSandboxData([...values, ...budget.retainedValues()], { compileTickets: included });
9795
9914
  const kept = /* @__PURE__ */ new Set();
9796
9915
  if (parent !== void 0) measureSandboxData(escaping, { compileTickets: kept });
9797
9916
  const transferred = /* @__PURE__ */ new Set();
@@ -22935,6 +23054,86 @@ function hoistVarDeclarations(node, scope) {
22935
23054
  }
22936
23055
  }
22937
23056
 
23057
+ // packages/safe-js/src/interp/string-coercion.ts
23058
+ function sandboxString(value, budget, context, joining = /* @__PURE__ */ new Set()) {
23059
+ if (value === null || typeof value !== "object") {
23060
+ if (typeof value === "function") throw new TypeError("Expected a sandbox value.");
23061
+ return budget.allocateString(String(value));
23062
+ }
23063
+ return stringifyObject(value, budget, context, joining);
23064
+ }
23065
+ async function stringifyObject(value, budget, context, joining) {
23066
+ const leaveCall = budget.enterCall();
23067
+ try {
23068
+ budget.visitNode();
23069
+ for (const name of ["toString", "valueOf"]) {
23070
+ const descriptor = Object.getOwnPropertyDescriptor(value, name);
23071
+ let result;
23072
+ if (descriptor === void 0) {
23073
+ if (name === "valueOf") continue;
23074
+ result = await defaultToString(value, budget, context, joining);
23075
+ } else {
23076
+ const hook = ownDataValue(value, name);
23077
+ if (!isSandboxClosure(hook)) continue;
23078
+ if (context?.invokeClosure === void 0) {
23079
+ throw new TypeError("String hooks require a sandbox call context.");
23080
+ }
23081
+ result = await context.invokeClosure(hook, [], value);
23082
+ }
23083
+ if (result === null || typeof result !== "object") {
23084
+ return sandboxString(result, budget, context, joining);
23085
+ }
23086
+ }
23087
+ throw new TypeError("Cannot convert object to primitive value");
23088
+ } finally {
23089
+ leaveCall();
23090
+ }
23091
+ }
23092
+ async function defaultToString(value, budget, context, joining) {
23093
+ if (isSandboxDate(value)) return budget.allocateString(dateString(value));
23094
+ if (Array.isArray(value) || isFloat32Array(value)) {
23095
+ if (Object.hasOwn(value, "join")) {
23096
+ const join = ownDataValue(value, "join");
23097
+ if (!isSandboxClosure(join))
23098
+ return isFloat32Array(value) ? "[object Float32Array]" : "[object Array]";
23099
+ if (context?.invokeClosure === void 0) {
23100
+ throw new TypeError("String hooks require a sandbox call context.");
23101
+ }
23102
+ return context.invokeClosure(join, [], value);
23103
+ }
23104
+ if (joining.has(value)) return "";
23105
+ joining.add(value);
23106
+ try {
23107
+ const length = isFloat32Array(value) ? float32Storage(value).length : value.length;
23108
+ let text = "";
23109
+ for (let index = 0; index < length; index++) {
23110
+ budget.visitNode();
23111
+ const element = ownDataValue(value, String(index));
23112
+ const part = element === null || element === void 0 ? "" : await sandboxString(element, budget, context, joining);
23113
+ text = budget.allocateString(text + (index === 0 ? "" : ",") + part);
23114
+ }
23115
+ return text;
23116
+ } finally {
23117
+ joining.delete(value);
23118
+ }
23119
+ }
23120
+ if (sandboxErrorTypes.has(value)) {
23121
+ const nameValue = ownDataValue(value, "name");
23122
+ const name = nameValue === void 0 ? "Error" : await sandboxString(nameValue, budget, context, joining);
23123
+ const messageValue = ownDataValue(value, "message");
23124
+ const message = messageValue === void 0 ? "" : await sandboxString(messageValue, budget, context, joining);
23125
+ return name === "" ? message : message === "" ? name : `${name}: ${message}`;
23126
+ }
23127
+ return isSandboxPromise(value) ? "[object Promise]" : "[object Object]";
23128
+ }
23129
+ function ownDataValue(value, name) {
23130
+ const descriptor = Object.getOwnPropertyDescriptor(value, name);
23131
+ if (descriptor !== void 0 && !Object.hasOwn(descriptor, "value")) {
23132
+ throw new TypeError("String conversion requires sandbox data properties.");
23133
+ }
23134
+ return descriptor?.value;
23135
+ }
23136
+
22938
23137
  // packages/safe-js/src/interp/methods/array.ts
22939
23138
  var activeArrayCallbacks = /* @__PURE__ */ new WeakMap();
22940
23139
  var arrayMethodNames = /* @__PURE__ */ new Set([
@@ -25628,6 +25827,9 @@ async function evaluateObjectExpression(node, context) {
25628
25827
  return value;
25629
25828
  }
25630
25829
  if (isObjectPrototypeSetterProperty(property, key.value)) {
25830
+ if (value.value === null || typeof value.value === "object") {
25831
+ setSandboxPrototype(object, value.value, context.budget);
25832
+ }
25631
25833
  continue;
25632
25834
  }
25633
25835
  defineSandboxProperty(object, String(key.value), value.value);
@@ -25749,7 +25951,11 @@ async function evaluateBinaryExpression(node, context) {
25749
25951
  if (right.kind !== "normal") {
25750
25952
  return right;
25751
25953
  }
25752
- const value = applyBinaryOperator(node, left.value, right.value, context);
25954
+ const value = node.operator === "in" && isGuestHostObject(right.value) ? hasHostObjectMember(right.value, await sandboxString(left.value, context.budget, {
25955
+ stack: context.callStack,
25956
+ thisValue: void 0,
25957
+ invokeClosure: (closure, args, thisValue) => invokeSandboxClosure(closure, args, context, context.callStack, void 0, thisValue)
25958
+ })) : applyBinaryOperator(node, left.value, right.value, context);
25753
25959
  return {
25754
25960
  kind: "normal",
25755
25961
  hasValue: true,
@@ -26432,7 +26638,7 @@ function forInKeys(object, budget) {
26432
26638
  const keys = [];
26433
26639
  const seen = /* @__PURE__ */ new Set();
26434
26640
  let depth = 0;
26435
- for (let current = object; current !== null; current = getSandboxPrototype(current)) {
26641
+ for (let current = object; current !== null; current = getSandboxPrototype(current, budget)) {
26436
26642
  if (depth > 0) budget.visitNode();
26437
26643
  assertSandboxDataDepth(depth++);
26438
26644
  const properties = isGuestClosure(current) ? materializeFunctionProperties(current) : isSandboxClosure(current) ? current.properties ?? {} : current;
@@ -26446,9 +26652,9 @@ function forInKeys(object, budget) {
26446
26652
  return keys;
26447
26653
  }
26448
26654
  function hasForInProperty(object, key, budget) {
26449
- if (isGuestHostObject(object)) return getHostObjectKeys(object).includes(key);
26655
+ if (isGuestHostObject(object)) return hasHostObjectMember(object, key, true);
26450
26656
  let depth = 0;
26451
- for (let current = object; current !== null; current = getSandboxPrototype(current)) {
26657
+ for (let current = object; current !== null; current = getSandboxPrototype(current, budget)) {
26452
26658
  if (depth > 0) budget.visitNode();
26453
26659
  assertSandboxDataDepth(depth++);
26454
26660
  const properties = isGuestClosure(current) ? materializeFunctionProperties(current) : isSandboxClosure(current) ? current.properties ?? {} : current;
@@ -27449,7 +27655,7 @@ function applyBinaryOperator(node, left, right, context) {
27449
27655
  throw new TypeError("Function has a non-object prototype in instanceof check.");
27450
27656
  }
27451
27657
  let depth = 0;
27452
- for (let current = getSandboxPrototype(left); current !== null; current = getSandboxPrototype(current)) {
27658
+ for (let current = getSandboxPrototype(left, context.budget); current !== null; current = getSandboxPrototype(current, context.budget)) {
27453
27659
  context.budget.visitNode();
27454
27660
  assertSandboxDataDepth(depth++);
27455
27661
  if (current === prototype) return true;
@@ -27663,7 +27869,7 @@ function getMemberValue(target, property, context) {
27663
27869
  return getPropertyValue(current, property, context);
27664
27870
  }
27665
27871
  if (Object.hasOwn(current, String(property))) return current[String(property)];
27666
- current = getSandboxPrototype(current);
27872
+ current = getSandboxPrototype(current, context.budget);
27667
27873
  if (current !== null) {
27668
27874
  context.budget.visitNode();
27669
27875
  assertSandboxDataDepth(++depth);
@@ -27713,7 +27919,7 @@ function setSandboxProperty(target, property, value, budget) {
27713
27919
  } else {
27714
27920
  if (typeof prototypeOwner === "object" && prototypeOwner !== null) {
27715
27921
  let depth = 0;
27716
- for (let prototype = getSandboxPrototype(prototypeOwner); prototype !== null; prototype = getSandboxPrototype(prototype)) {
27922
+ for (let prototype = getSandboxPrototype(prototypeOwner, budget); prototype !== null; prototype = getSandboxPrototype(prototype, budget)) {
27717
27923
  budget.visitNode();
27718
27924
  assertSandboxDataDepth(depth++);
27719
27925
  const properties = isSandboxClosure(prototype) ? prototype.properties : prototype;
@@ -27907,6 +28113,13 @@ async function evaluateObjectSpread(node, context) {
27907
28113
  value: []
27908
28114
  };
27909
28115
  }
28116
+ if (isGuestHostObject(value.value)) {
28117
+ const entries = [];
28118
+ for (const key of getHostObjectKeys(value.value)) {
28119
+ if (hasHostObjectMember(value.value, key, true)) entries.push([key, getHostObjectMember(value.value, key)]);
28120
+ }
28121
+ return { ok: true, value: entries };
28122
+ }
27910
28123
  if (isSandboxClosure(value.value) && !isGuestClosure(value.value) || isSandboxPromise(value.value)) {
27911
28124
  throw new TypeError(
27912
28125
  `Cannot spread ${describeObjectSpreadValue(value.value)} into object literal.`
@@ -28089,6 +28302,7 @@ function createInterpretedClosure(node, context, evaluateNode2) {
28089
28302
  function createGeneratorClosure(node, context, evaluateNode2) {
28090
28303
  return createSandboxClosure({
28091
28304
  guest: true,
28305
+ generator: true,
28092
28306
  sandbox: true,
28093
28307
  length: getFunctionLength(node.params),
28094
28308
  ...node.id === void 0 ? {} : { name: node.id.name },
@@ -29506,7 +29720,7 @@ async function stringifyValue(value, state, indent) {
29506
29720
  return stringifyArray(value, state, indent);
29507
29721
  }
29508
29722
  if (isStringifyObject(value)) {
29509
- return stringifyObject(value, state, indent);
29723
+ return stringifyObject2(value, state, indent);
29510
29724
  }
29511
29725
  return void 0;
29512
29726
  }
@@ -29532,7 +29746,7 @@ ${indent}]`;
29532
29746
  leaveStringifyObject(value, state);
29533
29747
  }
29534
29748
  }
29535
- async function stringifyObject(value, state, indent) {
29749
+ async function stringifyObject2(value, state, indent) {
29536
29750
  enterStringifyObject(value, state);
29537
29751
  try {
29538
29752
  const nextIndent = indent + state.gap;
@@ -29747,90 +29961,138 @@ function assertStructuredCloneable(value, seen) {
29747
29961
  }
29748
29962
  }
29749
29963
 
29750
- // packages/safe-js/src/interp/string-coercion.ts
29751
- function sandboxString(value, budget, context, joining = /* @__PURE__ */ new Set()) {
29752
- if (value === null || typeof value !== "object") {
29753
- if (typeof value === "function") throw new TypeError("Expected a sandbox value.");
29754
- return budget.allocateString(String(value));
29755
- }
29756
- return stringifyObject2(value, budget, context, joining);
29757
- }
29758
- async function stringifyObject2(value, budget, context, joining) {
29759
- const leaveCall = budget.enterCall();
29760
- try {
29761
- budget.visitNode();
29762
- for (const name of ["toString", "valueOf"]) {
29763
- const descriptor = Object.getOwnPropertyDescriptor(value, name);
29764
- let result;
29765
- if (descriptor === void 0) {
29766
- if (name === "valueOf") continue;
29767
- result = await defaultToString(value, budget, context, joining);
29768
- } else {
29769
- const hook = ownDataValue(value, name);
29770
- if (!isSandboxClosure(hook)) continue;
29771
- if (context?.invokeClosure === void 0) {
29772
- throw new TypeError("String hooks require a sandbox call context.");
29773
- }
29774
- result = await context.invokeClosure(hook, [], value);
29964
+ // packages/safe-js/src/interp/globals/object.ts
29965
+ function createObjectGlobal(methods, budget) {
29966
+ const construct = ([value]) => {
29967
+ if (value === null || value === void 0) {
29968
+ budget.chargeDataUsage(1);
29969
+ return /* @__PURE__ */ Object.create(null);
29970
+ }
29971
+ if (typeof value !== "object") throw new TypeError("Object primitive boxing is not supported.");
29972
+ return value;
29973
+ };
29974
+ const constructor = createSandboxClosure({
29975
+ guest: true,
29976
+ sandbox: true,
29977
+ name: "Object",
29978
+ length: 1,
29979
+ call: construct,
29980
+ construct
29981
+ });
29982
+ const properties = materializeFunctionProperties(constructor);
29983
+ const prototype = properties.prototype;
29984
+ Object.defineProperty(properties, "prototype", { writable: false });
29985
+ for (const [name, method] of Object.entries(methods)) {
29986
+ Object.defineProperty(properties, name, { value: method, writable: true, configurable: true });
29987
+ }
29988
+ const prototypeMethods = {
29989
+ toString: createSandboxClosure({
29990
+ sandbox: true,
29991
+ name: "toString",
29992
+ length: 0,
29993
+ call: (_args, context) => budget.allocateString(`[object ${typeTag(context?.thisValue)}]`)
29994
+ }),
29995
+ valueOf: createSandboxClosure({
29996
+ sandbox: true,
29997
+ name: "valueOf",
29998
+ length: 0,
29999
+ call: (_args, context) => {
30000
+ const value = requireReceiver(context?.thisValue);
30001
+ if (typeof value !== "object")
30002
+ throw new TypeError("Object primitive boxing is not supported.");
30003
+ return value;
29775
30004
  }
29776
- if (result === null || typeof result !== "object") {
29777
- return sandboxString(result, budget, context, joining);
30005
+ }),
30006
+ hasOwnProperty: createSandboxClosure({
30007
+ sandbox: true,
30008
+ name: "hasOwnProperty",
30009
+ length: 1,
30010
+ call: async ([key], context) => hasOwnSandboxProperty(
30011
+ requireReceiver(context?.thisValue),
30012
+ await sandboxString(key, budget, context),
30013
+ false
30014
+ )
30015
+ }),
30016
+ propertyIsEnumerable: createSandboxClosure({
30017
+ sandbox: true,
30018
+ name: "propertyIsEnumerable",
30019
+ length: 1,
30020
+ call: async ([key], context) => hasOwnSandboxProperty(
30021
+ requireReceiver(context?.thisValue),
30022
+ await sandboxString(key, budget, context),
30023
+ true
30024
+ )
30025
+ }),
30026
+ isPrototypeOf: createSandboxClosure({
30027
+ sandbox: true,
30028
+ name: "isPrototypeOf",
30029
+ length: 1,
30030
+ call: ([value], context) => {
30031
+ if (typeof value !== "object" || value === null) return false;
30032
+ const receiver = requireReceiver(context?.thisValue);
30033
+ let depth = 0;
30034
+ for (let current = getSandboxPrototype(value, budget); current !== null; current = getSandboxPrototype(current, budget)) {
30035
+ budget.visitNode();
30036
+ assertSandboxDataDepth(depth++);
30037
+ if (current === receiver) return true;
30038
+ }
30039
+ return false;
29778
30040
  }
29779
- }
29780
- throw new TypeError("Cannot convert object to primitive value");
29781
- } finally {
29782
- leaveCall();
30041
+ })
30042
+ };
30043
+ for (const [name, method] of Object.entries(prototypeMethods)) {
30044
+ Object.defineProperty(prototype, name, { value: method, writable: true, configurable: true });
29783
30045
  }
30046
+ markDescriptorObject(prototype);
30047
+ installObjectPrototype(budget, prototype, constructor);
30048
+ return constructor;
29784
30049
  }
29785
- async function defaultToString(value, budget, context, joining) {
29786
- if (isSandboxDate(value)) return budget.allocateString(dateString(value));
29787
- if (Array.isArray(value) || isFloat32Array(value)) {
29788
- if (Object.hasOwn(value, "join")) {
29789
- const join = ownDataValue(value, "join");
29790
- if (!isSandboxClosure(join))
29791
- return isFloat32Array(value) ? "[object Float32Array]" : "[object Array]";
29792
- if (context?.invokeClosure === void 0) {
29793
- throw new TypeError("String hooks require a sandbox call context.");
29794
- }
29795
- return context.invokeClosure(join, [], value);
29796
- }
29797
- if (joining.has(value)) return "";
29798
- joining.add(value);
29799
- try {
29800
- const length = isFloat32Array(value) ? float32Storage(value).length : value.length;
29801
- let text = "";
29802
- for (let index = 0; index < length; index++) {
29803
- budget.visitNode();
29804
- const element = ownDataValue(value, String(index));
29805
- const part = element === null || element === void 0 ? "" : await sandboxString(element, budget, context, joining);
29806
- text = budget.allocateString(text + (index === 0 ? "" : ",") + part);
29807
- }
29808
- return text;
29809
- } finally {
29810
- joining.delete(value);
29811
- }
29812
- }
29813
- if (sandboxErrorTypes.has(value)) {
29814
- const nameValue = ownDataValue(value, "name");
29815
- const name = nameValue === void 0 ? "Error" : await sandboxString(nameValue, budget, context, joining);
29816
- const messageValue = ownDataValue(value, "message");
29817
- const message = messageValue === void 0 ? "" : await sandboxString(messageValue, budget, context, joining);
29818
- return name === "" ? message : message === "" ? name : `${name}: ${message}`;
29819
- }
29820
- return isSandboxPromise(value) ? "[object Promise]" : "[object Object]";
30050
+ function requireReceiver(value) {
30051
+ if (value === null || value === void 0)
30052
+ throw new TypeError("Object method requires a non-null receiver.");
30053
+ return value;
29821
30054
  }
29822
- function ownDataValue(value, name) {
29823
- const descriptor = Object.getOwnPropertyDescriptor(value, name);
29824
- if (descriptor !== void 0 && !Object.hasOwn(descriptor, "value")) {
29825
- throw new TypeError("String conversion requires sandbox data properties.");
29826
- }
29827
- return descriptor?.value;
30055
+ function hasOwnSandboxProperty(value, key, enumerable) {
30056
+ requireReceiver(value);
30057
+ if (isGuestHostObject(value)) return hasHostObjectMember(value, key, enumerable);
30058
+ let properties;
30059
+ if (isGuestClosure(value)) properties = materializeFunctionProperties(value);
30060
+ else if (isSandboxClosure(value)) {
30061
+ if (key === "length" || key === "name") return !enumerable;
30062
+ properties = value.properties ?? /* @__PURE__ */ Object.create(null);
30063
+ } else if (isSandboxMap(value) || isSandboxSet(value) || isSandboxPromise(value) || isSandboxGenerator(value))
30064
+ return false;
30065
+ else if (isSandboxRegex(value)) return key === "lastIndex" && !enumerable;
30066
+ else properties = Object(value);
30067
+ const descriptor = Object.getOwnPropertyDescriptor(properties, key);
30068
+ return descriptor !== void 0 && (!enumerable || descriptor.enumerable === true);
30069
+ }
30070
+ function typeTag(value) {
30071
+ if (value === void 0) return "Undefined";
30072
+ if (value === null) return "Null";
30073
+ if (typeof value === "string") return "String";
30074
+ if (typeof value === "number") return "Number";
30075
+ if (typeof value === "boolean") return "Boolean";
30076
+ if (isSandboxClosure(value)) {
30077
+ while (value.boundTarget !== void 0) value = value.boundTarget;
30078
+ return value.generator ? "GeneratorFunction" : value.async ? "AsyncFunction" : "Function";
30079
+ }
30080
+ if (Array.isArray(value)) return "Array";
30081
+ if (isSandboxDate(value)) return "Date";
30082
+ if (isSandboxErrorConstructorInstance(value, "Error")) return "Error";
30083
+ if (isSandboxRegex(value)) return "RegExp";
30084
+ if (isSandboxMap(value)) return "Map";
30085
+ if (isSandboxSet(value)) return "Set";
30086
+ if (isSandboxPromise(value)) return "Promise";
30087
+ if (isSandboxGenerator(value)) return "Generator";
30088
+ if (isFloat32Array(value)) return "Float32Array";
30089
+ return "Object";
29828
30090
  }
29829
30091
 
29830
30092
  // packages/safe-js/src/interp/globals/object-array.ts
29831
30093
  function createObjectArrayGlobals(options) {
29832
30094
  return {
29833
- Object: {
30095
+ Object: createObjectGlobal({
29834
30096
  keys: createSandboxClosure({
29835
30097
  sandbox: true,
29836
30098
  call: ([value]) => budgetSandboxValue2(getOwnEnumerableKeys(value), options.budget),
@@ -29848,7 +30110,11 @@ function createObjectArrayGlobals(options) {
29848
30110
  }),
29849
30111
  hasOwn: createSandboxClosure({
29850
30112
  sandbox: true,
29851
- call: ([value, key]) => Reflect.apply(Object.hasOwn, Object, [isSandboxClosure(value) ? objectProperties(value) : value, key]),
30113
+ call: ([value, key], context) => {
30114
+ if (value === null || value === void 0) throw new TypeError("Cannot convert undefined or null to object.");
30115
+ const name = sandboxString(key, options.budget, context);
30116
+ return typeof name === "string" ? hasOwnSandboxProperty(value, name, false) : name.then((property) => hasOwnSandboxProperty(value, property, false));
30117
+ },
29852
30118
  name: "hasOwn"
29853
30119
  }),
29854
30120
  getOwnPropertyDescriptor: createSandboxClosure({
@@ -29889,7 +30155,7 @@ function createObjectArrayGlobals(options) {
29889
30155
  call: ([value]) => {
29890
30156
  if (isSandboxDate(value)) return getDatePrototype(value, options.budget, options.compileOwner);
29891
30157
  objectProperties(value);
29892
- return getSandboxPrototype(value);
30158
+ return getSandboxPrototype(value, options.budget);
29893
30159
  },
29894
30160
  name: "getPrototypeOf"
29895
30161
  }),
@@ -29947,6 +30213,7 @@ function createObjectArrayGlobals(options) {
29947
30213
  freeze: createSandboxClosure({
29948
30214
  sandbox: true,
29949
30215
  call: ([value]) => {
30216
+ if (isGuestHostObject(value)) throw new TypeError("Live host objects cannot be frozen.");
29950
30217
  if (typeof value === "object" && value !== null) {
29951
30218
  Object.freeze(isGuestClosure(value) ? materializeFunctionProperties(value) : value);
29952
30219
  }
@@ -29964,7 +30231,7 @@ function createObjectArrayGlobals(options) {
29964
30231
  call: ([target, ...sources]) => assignSandboxValues(target, sources, options.budget),
29965
30232
  name: "assign"
29966
30233
  })
29967
- },
30234
+ }, options.budget),
29968
30235
  Array: createSandboxClosure({
29969
30236
  sandbox: true,
29970
30237
  call: (args) => createArrayFromConstructorArgs(args, options.budget),
@@ -30161,6 +30428,21 @@ function isAssignableSandboxTarget(value) {
30161
30428
  async function arrayFromSandboxValues(args, budget) {
30162
30429
  const [items, mapFn, thisValue] = args;
30163
30430
  const iterator = getSandboxIterator(items);
30431
+ if (isGuestHostObject(items) && iterator !== void 0) {
30432
+ if (mapFn !== void 0 && !isSandboxClosure(mapFn))
30433
+ throw new TypeError("Array.from mapping callback must be a function.");
30434
+ const values2 = [];
30435
+ while (true) {
30436
+ const next = await iterator.next();
30437
+ if (next.done) break;
30438
+ budget.allocateArrayLength(values2.length + 1);
30439
+ const value = mapFn === void 0 ? next.value : await mapFn.call([next.value, values2.length], { stack: [], thisValue });
30440
+ if (isSandboxPromise(value) && value.synchronousPrefix !== void 0)
30441
+ await value.synchronousPrefix;
30442
+ values2.push(value);
30443
+ }
30444
+ return allocateProducedSandboxValue(values2, budget);
30445
+ }
30164
30446
  const values = iterator === void 0 ? Reflect.apply(Array.from, Array, [items]) : await collectIteratorValues(iterator);
30165
30447
  if (mapFn === void 0 || !isSandboxClosure(mapFn)) {
30166
30448
  if (mapFn !== void 0) {
@@ -30491,6 +30773,7 @@ var RealmState = class {
30491
30773
  this.budget.setRetainedValues(this, this.retainedRoots);
30492
30774
  this.tracker.onFatalRejection((error) => this.poison(error));
30493
30775
  } catch (error) {
30776
+ releaseObjectPrototype(this.budget);
30494
30777
  this.compilation.dispose();
30495
30778
  this.lease.release();
30496
30779
  throw error;
@@ -30693,6 +30976,7 @@ var RealmState = class {
30693
30976
  owner: this,
30694
30977
  assertActive: this.assertOpen,
30695
30978
  chargeWork: this.chargeWork,
30979
+ checkLength: (length) => this.budget.allocateArrayLength(length),
30696
30980
  read: (operation) => {
30697
30981
  const value = this.invokeHost(operation, operation);
30698
30982
  if (types4.isPromise(value)) {
@@ -31057,6 +31341,7 @@ var RealmState = class {
31057
31341
  for (const reference of this.guestReferences.keys()) revokeGuestReference(reference, this);
31058
31342
  this.guestReferences.clear();
31059
31343
  this.budget.setRetainedValues(this, void 0);
31344
+ releaseObjectPrototype(this.budget);
31060
31345
  this.disposal = (async () => {
31061
31346
  const errors = [];
31062
31347
  for (const cleanup of this.cleanups.splice(0).reverse()) {
@@ -32065,6 +32350,7 @@ function run(source, options = {}) {
32065
32350
  }
32066
32351
  });
32067
32352
  } finally {
32353
+ releaseObjectPrototype(budget);
32068
32354
  compilation.dispose();
32069
32355
  operation.release();
32070
32356
  }
@@ -32307,4 +32593,4 @@ export {
32307
32593
  FileSnapshotBackend,
32308
32594
  run
32309
32595
  };
32310
- //# sourceMappingURL=chunk-BWVASPJX.js.map
32596
+ //# sourceMappingURL=chunk-MCF7GT3X.js.map