@poe-platform/safe-js 0.1.26 → 0.1.28

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.
package/README.md CHANGED
@@ -212,7 +212,7 @@ The manifest requires `version: 1` and a nonempty `name`. Optional `capabilities
212
212
  | `signal` | Realm cancellation signal; aborted on close or failure. |
213
213
  | `onCleanup(fn)` | Register a sync/async disposer. Cleanup runs in reverse order, awaits every disposer, and reports failures without skipping the rest. |
214
214
  | `chargeWork(units = 1)` | Charge a nonnegative integer against the shared execution budget. Fatal exhaustion cannot be swallowed to continue execution. |
215
- | `createHostObject({ properties?, methods? })` | Create a realm-owned capability. Properties declare synchronous `get`/`set` functions; methods are host functions. Undeclared members expose no native prototype. |
215
+ | `createHostObject({ properties?, methods?, indexed? })` | Create a realm-owned capability. Properties declare synchronous `get`/`set` functions; methods are host functions. Optional `indexed` exposes a bounded live collection. Undeclared members expose no native prototype. |
216
216
  | `invokeCallback(callback, { thisValue?, args? })` | Invoke a captured guest function with the realm's state, cancellation and budgets. Same operation as on the realm. |
217
217
  | `releaseCallback(callback)` | Revoke the callback and release its retained guest state. |
218
218
  | `retainGuestArguments(operation, from)` | During setup, opt an operation into opaque argument references starting at the zero-based index `from`. Requires declared and granted `guest:retain`. Earlier arguments keep normal conversion; live host methods preserve the declaration. |
@@ -224,7 +224,21 @@ For a timer-shaped `schedule(callback, delay, ...args)`, register `context.retai
224
224
 
225
225
  Release each reference when the host no longer needs it; returning it does not release it. Retained graphs count against data budgets and `limits.guestReferences`. Synchronous native failure releases references captured for that call; asynchronous operations must release theirs in host cleanup. Close revokes all remaining references. Handles cannot be inspected, used in another realm, or serialized into replay/error data. Unmarked operations still copy values.
226
226
 
227
- Live objects do not support native prototypes, property-descriptor manipulation or portable serialization. Realm state is not a checkpoint: snapshot/replay and live-capability error-data conversion are rejected. Extensions are trusted native code; grants are a registration contract, not OS isolation. Native work still needs host timeouts and external process supervision for hard limits. No DOM, timers or browser engine are bundled.
227
+ For a live collection, keep the elements in your adapter and expose virtual indices instead of declaring one getter per element:
228
+
229
+ ```js
230
+ const collection = context.createHostObject({ indexed: {
231
+ length: () => elements.length,
232
+ get: index => elements[index],
233
+ maxLength: 4096
234
+ } });
235
+ ```
236
+
237
+ `length()` and `get(index)` must be synchronous. `maxLength` is required: an integer from 1 to 65,536. Every reported length must be a nonnegative integer within that cap and the execution array-length budget. Return existing `HostObject` handles for elements that need live identity; ordinary results use the normal copy boundary.
238
+
239
+ Saved collections observe current host contents. Index reads, `Object.keys`/`values`/`entries`, `Object.hasOwn`, `in`, `for...in`, `for...of`, array/object spread and `Array.from` use the live view. Enumerable keys include current indices and fixed members, but not `length`. `Array.from` preserves element identity and interleaves mapping with reads. Noncanonical and out-of-range indices never call `get`; fixed members cannot reuse `length` or canonical index names. Enumeration and traversal consume execution budgets, without eagerly allocating virtual properties.
240
+
241
+ Indexed members and their `length` are read-only. Live objects reject deletion, freezing, native prototype access, property-descriptor manipulation and portable serialization. Realm state is not a checkpoint: snapshot/replay and live-capability error-data conversion are rejected. Extensions are trusted native code; grants are a registration contract, not OS isolation. Native work still needs host timeouts and external process supervision for hard limits. No DOM, timers or browser engine are bundled.
228
242
 
229
243
  For one-shot use, `run(source, { extensions, grants, ... })` accepts the same realm options plus `filename`, returns data only, and closes resources before settling. Run-only features such as snapshots, `entryPointArgs`, `importMeta`, custom random generators and telemetry are rejected in this mode rather than silently ignored.
230
244
 
@@ -27,7 +27,7 @@ import {
27
27
  validateMigrationSemantics,
28
28
  validateSnapshotData,
29
29
  validateSnapshotMigration
30
- } from "./chunk-2LVAGOJR.js";
30
+ } from "./chunk-MCF7GT3X.js";
31
31
 
32
32
  // packages/safe-js/src/migrate.ts
33
33
  import { createHash } from "node:crypto";
@@ -8245,4 +8245,4 @@ export {
8245
8245
  parseMcpConfig,
8246
8246
  makeMcpModule
8247
8247
  };
8248
- //# sourceMappingURL=chunk-I2SNTMRS.js.map
8248
+ //# sourceMappingURL=chunk-6V2VGVEH.js.map
@@ -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
@@ -8406,6 +8491,7 @@ function assertSnapshotInactive(snapshot) {
8406
8491
 
8407
8492
  // packages/safe-js/src/interp/iteration.ts
8408
8493
  function getSandboxIterator(value) {
8494
+ if (isGuestHostObject(value)) return getHostObjectIterator(value);
8409
8495
  if (isFloat32Array(value)) {
8410
8496
  return syncIterator(Float32Array.prototype.values.call(value));
8411
8497
  }
@@ -9563,7 +9649,13 @@ function createSandboxClosure(input) {
9563
9649
  return Object.freeze(closure);
9564
9650
  }
9565
9651
  function ownEnumerableSandboxEntries(value) {
9566
- 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
+ }
9567
9659
  if (value === null || value === void 0) throw new TypeError("Cannot convert undefined or null to object.");
9568
9660
  if (isGuestClosure(value)) return Object.entries(value.properties ?? {});
9569
9661
  if (isSandboxClosure(value) || isSandboxGenerator(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxPromise(value) || isSandboxRegex(value)) return [];
@@ -9721,7 +9813,7 @@ function measureSandboxData(values, options = {}) {
9721
9813
  return;
9722
9814
  }
9723
9815
  if (isGuestHostObject(value)) {
9724
- for (const key of getHostObjectKeys(value)) usage += key.length + 1;
9816
+ usage += measureHostObjectData(value);
9725
9817
  return;
9726
9818
  }
9727
9819
  const prototype = getSandboxPrototype(value);
@@ -22962,6 +23054,86 @@ function hoistVarDeclarations(node, scope) {
22962
23054
  }
22963
23055
  }
22964
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
+
22965
23137
  // packages/safe-js/src/interp/methods/array.ts
22966
23138
  var activeArrayCallbacks = /* @__PURE__ */ new WeakMap();
22967
23139
  var arrayMethodNames = /* @__PURE__ */ new Set([
@@ -25779,7 +25951,11 @@ async function evaluateBinaryExpression(node, context) {
25779
25951
  if (right.kind !== "normal") {
25780
25952
  return right;
25781
25953
  }
25782
- 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);
25783
25959
  return {
25784
25960
  kind: "normal",
25785
25961
  hasValue: true,
@@ -26476,7 +26652,7 @@ function forInKeys(object, budget) {
26476
26652
  return keys;
26477
26653
  }
26478
26654
  function hasForInProperty(object, key, budget) {
26479
- if (isGuestHostObject(object)) return getHostObjectKeys(object).includes(key);
26655
+ if (isGuestHostObject(object)) return hasHostObjectMember(object, key, true);
26480
26656
  let depth = 0;
26481
26657
  for (let current = object; current !== null; current = getSandboxPrototype(current, budget)) {
26482
26658
  if (depth > 0) budget.visitNode();
@@ -27937,6 +28113,13 @@ async function evaluateObjectSpread(node, context) {
27937
28113
  value: []
27938
28114
  };
27939
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
+ }
27940
28123
  if (isSandboxClosure(value.value) && !isGuestClosure(value.value) || isSandboxPromise(value.value)) {
27941
28124
  throw new TypeError(
27942
28125
  `Cannot spread ${describeObjectSpreadValue(value.value)} into object literal.`
@@ -29537,7 +29720,7 @@ async function stringifyValue(value, state, indent) {
29537
29720
  return stringifyArray(value, state, indent);
29538
29721
  }
29539
29722
  if (isStringifyObject(value)) {
29540
- return stringifyObject(value, state, indent);
29723
+ return stringifyObject2(value, state, indent);
29541
29724
  }
29542
29725
  return void 0;
29543
29726
  }
@@ -29563,7 +29746,7 @@ ${indent}]`;
29563
29746
  leaveStringifyObject(value, state);
29564
29747
  }
29565
29748
  }
29566
- async function stringifyObject(value, state, indent) {
29749
+ async function stringifyObject2(value, state, indent) {
29567
29750
  enterStringifyObject(value, state);
29568
29751
  try {
29569
29752
  const nextIndent = indent + state.gap;
@@ -29778,86 +29961,6 @@ function assertStructuredCloneable(value, seen) {
29778
29961
  }
29779
29962
  }
29780
29963
 
29781
- // packages/safe-js/src/interp/string-coercion.ts
29782
- function sandboxString(value, budget, context, joining = /* @__PURE__ */ new Set()) {
29783
- if (value === null || typeof value !== "object") {
29784
- if (typeof value === "function") throw new TypeError("Expected a sandbox value.");
29785
- return budget.allocateString(String(value));
29786
- }
29787
- return stringifyObject2(value, budget, context, joining);
29788
- }
29789
- async function stringifyObject2(value, budget, context, joining) {
29790
- const leaveCall = budget.enterCall();
29791
- try {
29792
- budget.visitNode();
29793
- for (const name of ["toString", "valueOf"]) {
29794
- const descriptor = Object.getOwnPropertyDescriptor(value, name);
29795
- let result;
29796
- if (descriptor === void 0) {
29797
- if (name === "valueOf") continue;
29798
- result = await defaultToString(value, budget, context, joining);
29799
- } else {
29800
- const hook = ownDataValue(value, name);
29801
- if (!isSandboxClosure(hook)) continue;
29802
- if (context?.invokeClosure === void 0) {
29803
- throw new TypeError("String hooks require a sandbox call context.");
29804
- }
29805
- result = await context.invokeClosure(hook, [], value);
29806
- }
29807
- if (result === null || typeof result !== "object") {
29808
- return sandboxString(result, budget, context, joining);
29809
- }
29810
- }
29811
- throw new TypeError("Cannot convert object to primitive value");
29812
- } finally {
29813
- leaveCall();
29814
- }
29815
- }
29816
- async function defaultToString(value, budget, context, joining) {
29817
- if (isSandboxDate(value)) return budget.allocateString(dateString(value));
29818
- if (Array.isArray(value) || isFloat32Array(value)) {
29819
- if (Object.hasOwn(value, "join")) {
29820
- const join = ownDataValue(value, "join");
29821
- if (!isSandboxClosure(join))
29822
- return isFloat32Array(value) ? "[object Float32Array]" : "[object Array]";
29823
- if (context?.invokeClosure === void 0) {
29824
- throw new TypeError("String hooks require a sandbox call context.");
29825
- }
29826
- return context.invokeClosure(join, [], value);
29827
- }
29828
- if (joining.has(value)) return "";
29829
- joining.add(value);
29830
- try {
29831
- const length = isFloat32Array(value) ? float32Storage(value).length : value.length;
29832
- let text = "";
29833
- for (let index = 0; index < length; index++) {
29834
- budget.visitNode();
29835
- const element = ownDataValue(value, String(index));
29836
- const part = element === null || element === void 0 ? "" : await sandboxString(element, budget, context, joining);
29837
- text = budget.allocateString(text + (index === 0 ? "" : ",") + part);
29838
- }
29839
- return text;
29840
- } finally {
29841
- joining.delete(value);
29842
- }
29843
- }
29844
- if (sandboxErrorTypes.has(value)) {
29845
- const nameValue = ownDataValue(value, "name");
29846
- const name = nameValue === void 0 ? "Error" : await sandboxString(nameValue, budget, context, joining);
29847
- const messageValue = ownDataValue(value, "message");
29848
- const message = messageValue === void 0 ? "" : await sandboxString(messageValue, budget, context, joining);
29849
- return name === "" ? message : message === "" ? name : `${name}: ${message}`;
29850
- }
29851
- return isSandboxPromise(value) ? "[object Promise]" : "[object Object]";
29852
- }
29853
- function ownDataValue(value, name) {
29854
- const descriptor = Object.getOwnPropertyDescriptor(value, name);
29855
- if (descriptor !== void 0 && !Object.hasOwn(descriptor, "value")) {
29856
- throw new TypeError("String conversion requires sandbox data properties.");
29857
- }
29858
- return descriptor?.value;
29859
- }
29860
-
29861
29964
  // packages/safe-js/src/interp/globals/object.ts
29862
29965
  function createObjectGlobal(methods, budget) {
29863
29966
  const construct = ([value]) => {
@@ -29951,7 +30054,7 @@ function requireReceiver(value) {
29951
30054
  }
29952
30055
  function hasOwnSandboxProperty(value, key, enumerable) {
29953
30056
  requireReceiver(value);
29954
- if (isGuestHostObject(value)) return getHostObjectKeys(value).includes(key);
30057
+ if (isGuestHostObject(value)) return hasHostObjectMember(value, key, enumerable);
29955
30058
  let properties;
29956
30059
  if (isGuestClosure(value)) properties = materializeFunctionProperties(value);
29957
30060
  else if (isSandboxClosure(value)) {
@@ -30110,6 +30213,7 @@ function createObjectArrayGlobals(options) {
30110
30213
  freeze: createSandboxClosure({
30111
30214
  sandbox: true,
30112
30215
  call: ([value]) => {
30216
+ if (isGuestHostObject(value)) throw new TypeError("Live host objects cannot be frozen.");
30113
30217
  if (typeof value === "object" && value !== null) {
30114
30218
  Object.freeze(isGuestClosure(value) ? materializeFunctionProperties(value) : value);
30115
30219
  }
@@ -30324,6 +30428,21 @@ function isAssignableSandboxTarget(value) {
30324
30428
  async function arrayFromSandboxValues(args, budget) {
30325
30429
  const [items, mapFn, thisValue] = args;
30326
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
+ }
30327
30446
  const values = iterator === void 0 ? Reflect.apply(Array.from, Array, [items]) : await collectIteratorValues(iterator);
30328
30447
  if (mapFn === void 0 || !isSandboxClosure(mapFn)) {
30329
30448
  if (mapFn !== void 0) {
@@ -30857,6 +30976,7 @@ var RealmState = class {
30857
30976
  owner: this,
30858
30977
  assertActive: this.assertOpen,
30859
30978
  chargeWork: this.chargeWork,
30979
+ checkLength: (length) => this.budget.allocateArrayLength(length),
30860
30980
  read: (operation) => {
30861
30981
  const value = this.invokeHost(operation, operation);
30862
30982
  if (types4.isPromise(value)) {
@@ -32473,4 +32593,4 @@ export {
32473
32593
  FileSnapshotBackend,
32474
32594
  run
32475
32595
  };
32476
- //# sourceMappingURL=chunk-2LVAGOJR.js.map
32596
+ //# sourceMappingURL=chunk-MCF7GT3X.js.map