poe-code 14.0.5 → 14.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/index.js +1604 -255
  2. package/dist/index.js.map +4 -4
  3. package/dist/metafile.json +1 -1
  4. package/package.json +1 -1
  5. package/packages/safe-js/dist/chunks/{chunk-B7H4ZL65.js → chunk-BWVASPJX.js} +2099 -783
  6. package/packages/safe-js/dist/chunks/chunk-BWVASPJX.js.map +7 -0
  7. package/packages/safe-js/dist/chunks/{chunk-7B7BKWVF.js → chunk-ETKM3KPA.js} +2 -2
  8. package/packages/safe-js/dist/cli.js +2 -2
  9. package/packages/safe-js/dist/core.d.ts +3 -0
  10. package/packages/safe-js/dist/core.js +5 -1
  11. package/packages/safe-js/dist/extensions.d.ts +44 -0
  12. package/packages/safe-js/dist/extensions.js +83 -0
  13. package/packages/safe-js/dist/index.d.ts +4 -1
  14. package/packages/safe-js/dist/index.js +6 -2
  15. package/packages/safe-js/dist/index.js.map +2 -2
  16. package/packages/safe-js/dist/interp/async.d.ts +1 -0
  17. package/packages/safe-js/dist/interp/date.d.ts +19 -0
  18. package/packages/safe-js/dist/interp/date.js +129 -0
  19. package/packages/safe-js/dist/interp/globals/console-json.js +5 -1
  20. package/packages/safe-js/dist/interp/globals/date.d.ts +10 -0
  21. package/packages/safe-js/dist/interp/globals/date.js +95 -0
  22. package/packages/safe-js/dist/interp/globals/object-array.d.ts +2 -1
  23. package/packages/safe-js/dist/interp/globals/object-array.js +15 -1
  24. package/packages/safe-js/dist/interp/globals.d.ts +34 -0
  25. package/packages/safe-js/dist/interp/globals.js +24 -0
  26. package/packages/safe-js/dist/interp/host-bridge.d.ts +18 -1
  27. package/packages/safe-js/dist/interp/host-bridge.js +39 -5
  28. package/packages/safe-js/dist/interp/host-call.js +4 -0
  29. package/packages/safe-js/dist/interp/host-capabilities.d.ts +50 -0
  30. package/packages/safe-js/dist/interp/host-capabilities.js +151 -0
  31. package/packages/safe-js/dist/interp/interpreter.d.ts +4 -0
  32. package/packages/safe-js/dist/interp/interpreter.js +41 -6
  33. package/packages/safe-js/dist/interp/object-model.js +7 -0
  34. package/packages/safe-js/dist/interp/string-coercion.js +3 -0
  35. package/packages/safe-js/dist/interp/values.d.ts +2 -1
  36. package/packages/safe-js/dist/interp/values.js +36 -0
  37. package/packages/safe-js/dist/lint/rules/known-globals.d.ts +1 -1
  38. package/packages/safe-js/dist/lint/rules/known-globals.js +1 -0
  39. package/packages/safe-js/dist/modules/registry.d.ts +3 -1
  40. package/packages/safe-js/dist/modules/registry.js +2 -1
  41. package/packages/safe-js/dist/parse/parser.js +4 -2
  42. package/packages/safe-js/dist/realm.d.ts +46 -0
  43. package/packages/safe-js/dist/realm.js +779 -0
  44. package/packages/safe-js/dist/run.d.ts +7 -1
  45. package/packages/safe-js/dist/run.js +6 -35
  46. package/packages/safe-js/dist/snapshot/dump-format.js +8 -3
  47. package/packages/safe-js/dist/snapshot/replay-data.d.ts +4 -1
  48. package/packages/safe-js/dist/snapshot/replay-data.js +11 -0
  49. package/packages/safe-js/dist/snapshot/restore.js +6 -0
  50. package/packages/safe-js/dist/snapshot/serialize.d.ts +5 -2
  51. package/packages/safe-js/dist/snapshot/serialize.js +8 -2
  52. package/packages/safe-js/dist/snapshot/validation.js +18 -1
  53. package/packages/safe-js/dist/chunks/chunk-B7H4ZL65.js.map +0 -7
  54. /package/packages/safe-js/dist/chunks/{chunk-7B7BKWVF.js.map → chunk-ETKM3KPA.js.map} +0 -0
@@ -4263,8 +4263,9 @@ var Parser = class {
4263
4263
  }
4264
4264
  break;
4265
4265
  }
4266
- this.expectPunctuator("(");
4267
- const args = this.parseArguments();
4266
+ const optional = this.consumePunctuator("?.");
4267
+ if (optional !== void 0) throw new DisallowedSyntaxError("new optional chain", optional.start);
4268
+ const args = this.consumePunctuator("(") === void 0 ? [] : this.parseArguments();
4268
4269
  const end = this.previousToken();
4269
4270
  return {
4270
4271
  node: {
@@ -5922,6 +5923,87 @@ function matchingOpeningPunctuator(value) {
5922
5923
  return "{";
5923
5924
  }
5924
5925
 
5926
+ // packages/safe-js/src/extensions.ts
5927
+ import { types } from "node:util";
5928
+ var definitions = /* @__PURE__ */ new WeakMap();
5929
+ function readDataRecord(value, label) {
5930
+ if (typeof value !== "object" || value === null || types.isProxy(value)) {
5931
+ throw new TypeError(`${label} must be a plain data record.`);
5932
+ }
5933
+ const prototype = Object.getPrototypeOf(value);
5934
+ if (prototype !== null && prototype !== Object.prototype) {
5935
+ throw new TypeError(`${label} must be a plain data record.`);
5936
+ }
5937
+ const keys = Reflect.ownKeys(value);
5938
+ if (keys.length > 4096) throw new RangeError(`${label} has too many fields.`);
5939
+ const result = /* @__PURE__ */ Object.create(null);
5940
+ for (const key of keys) {
5941
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
5942
+ if (typeof key !== "string" || !("value" in descriptor)) {
5943
+ throw new TypeError(`${label} requires string-keyed data properties, not accessors.`);
5944
+ }
5945
+ result[key] = descriptor.value;
5946
+ }
5947
+ return result;
5948
+ }
5949
+ function readStringList(value, label) {
5950
+ if (!Array.isArray(value) || types.isProxy(value) || value.length > 4096) {
5951
+ throw new TypeError(`${label} must be a bounded string array.`);
5952
+ }
5953
+ const result = [];
5954
+ for (let index = 0; index < value.length; index++) {
5955
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
5956
+ if (descriptor === void 0 || !("value" in descriptor) || typeof descriptor.value !== "string" || descriptor.value.length === 0) {
5957
+ throw new TypeError(`${label} requires nonempty string data properties.`);
5958
+ }
5959
+ if (result.includes(descriptor.value))
5960
+ throw new TypeError(`${label} contains a duplicate name.`);
5961
+ result.push(descriptor.value);
5962
+ }
5963
+ if (Reflect.ownKeys(value).length !== result.length + 1)
5964
+ throw new TypeError(`${label} has unexpected fields.`);
5965
+ return Object.freeze(result);
5966
+ }
5967
+ function defineExtension(definition) {
5968
+ const input = readDataRecord(definition, "Extension definition");
5969
+ if (Object.keys(input).some((key) => key !== "manifest" && key !== "setup"))
5970
+ throw new TypeError("Unknown extension definition field.");
5971
+ if (typeof input.setup !== "function") throw new TypeError("Extension setup must be a function.");
5972
+ if (types.isAsyncFunction(input.setup))
5973
+ throw new TypeError("Extension setup must be synchronous.");
5974
+ const manifest = readDataRecord(input.manifest, "Extension manifest");
5975
+ if (Object.keys(manifest).some(
5976
+ (key) => !["version", "name", "capabilities", "globals", "modules"].includes(key)
5977
+ ))
5978
+ throw new TypeError("Unknown extension manifest field.");
5979
+ if (manifest.version !== 1) throw new TypeError("Unsupported extension manifest version.");
5980
+ if (typeof manifest.name !== "string" || manifest.name.length === 0 || manifest.name.length > 256)
5981
+ throw new TypeError("Extension name must be a nonempty bounded string.");
5982
+ const modules = /* @__PURE__ */ Object.create(null);
5983
+ for (const [name, exports] of Object.entries(
5984
+ readDataRecord(manifest.modules ?? {}, "Extension modules")
5985
+ )) {
5986
+ if (name.length === 0) throw new TypeError("Module names must be nonempty.");
5987
+ modules[name] = readStringList(exports, `Module '${name}' exports`);
5988
+ }
5989
+ const extension = Object.freeze({
5990
+ manifest: Object.freeze({
5991
+ version: 1,
5992
+ name: manifest.name,
5993
+ capabilities: readStringList(manifest.capabilities ?? [], "Extension capabilities"),
5994
+ globals: readStringList(manifest.globals ?? [], "Extension globals"),
5995
+ modules: Object.freeze(modules)
5996
+ })
5997
+ });
5998
+ definitions.set(extension, input.setup);
5999
+ return extension;
6000
+ }
6001
+ function getExtensionSetup(extension) {
6002
+ const setup = definitions.get(extension);
6003
+ if (setup === void 0) throw new TypeError("Extensions must be created by defineExtension.");
6004
+ return setup;
6005
+ }
6006
+
5925
6007
  // packages/safe-js/src/observability/otel.ts
5926
6008
  var noopOtelSink = {
5927
6009
  startSpan: () => noopOtelSpan,
@@ -6126,6 +6208,266 @@ function copyFloat32Storage(value, state) {
6126
6208
  return new Float32Array(buffer, storage.byteOffset, storage.length);
6127
6209
  }
6128
6210
 
6211
+ // packages/safe-js/src/interp/date.ts
6212
+ import { types as types2 } from "node:util";
6213
+ var NativeDate = Date;
6214
+ var readTime = NativeDate.prototype.getTime;
6215
+ var writeTime = NativeDate.prototype.setTime;
6216
+ var dates = /* @__PURE__ */ new WeakSet();
6217
+ function isSandboxDate(value) {
6218
+ return typeof value === "object" && value !== null && dates.has(value);
6219
+ }
6220
+ function createSandboxDate(time) {
6221
+ const value = new NativeDate(time);
6222
+ dates.add(value);
6223
+ return Object.freeze(value);
6224
+ }
6225
+ function dateTime(value) {
6226
+ return Reflect.apply(readTime, value, []);
6227
+ }
6228
+ function copyNativeDate(value) {
6229
+ if (!types2.isDate(value)) return void 0;
6230
+ if (Object.getPrototypeOf(value) !== NativeDate.prototype || Reflect.ownKeys(value).length > 0)
6231
+ throw new TypeError("Date subclasses and own properties are not supported.");
6232
+ return createSandboxDate(dateTime(value));
6233
+ }
6234
+ function exportDate(value) {
6235
+ return new NativeDate(dateTime(value));
6236
+ }
6237
+ function dateNumber(value) {
6238
+ if (isSandboxDate(value)) return dateTime(value);
6239
+ if (typeof value === "object" && value !== null || typeof value === "function" || typeof value === "symbol" || typeof value === "bigint")
6240
+ throw new TypeError("Date arguments require primitive values; custom coercion is unsupported.");
6241
+ return Number(value);
6242
+ }
6243
+ function parseDate(value, budget) {
6244
+ if (typeof value === "object" && value !== null || typeof value === "function")
6245
+ throw new TypeError("Date parsing requires a primitive value.");
6246
+ const text = String(value);
6247
+ if (text.length > 4096) throw new RangeError("Date input exceeds the 4096 character limit.");
6248
+ budget.allocateString(text);
6249
+ for (let index = 0; index < text.length; index++) budget.visitNode();
6250
+ return NativeDate.parse(text);
6251
+ }
6252
+ function dateFromParts(args, utc) {
6253
+ const parts = args.slice(0, 7).map(dateNumber);
6254
+ return utc ? Reflect.apply(NativeDate.UTC, NativeDate, parts) : dateTime(Reflect.construct(NativeDate, parts));
6255
+ }
6256
+ var methodNames = [
6257
+ "getTime",
6258
+ "valueOf",
6259
+ "getDate",
6260
+ "getDay",
6261
+ "getFullYear",
6262
+ "getHours",
6263
+ "getMilliseconds",
6264
+ "getMinutes",
6265
+ "getMonth",
6266
+ "getSeconds",
6267
+ "getTimezoneOffset",
6268
+ "getUTCDate",
6269
+ "getUTCDay",
6270
+ "getUTCFullYear",
6271
+ "getUTCHours",
6272
+ "getUTCMilliseconds",
6273
+ "getUTCMinutes",
6274
+ "getUTCMonth",
6275
+ "getUTCSeconds",
6276
+ "setTime",
6277
+ "setDate",
6278
+ "setFullYear",
6279
+ "setHours",
6280
+ "setMilliseconds",
6281
+ "setMinutes",
6282
+ "setMonth",
6283
+ "setSeconds",
6284
+ "setUTCDate",
6285
+ "setUTCFullYear",
6286
+ "setUTCHours",
6287
+ "setUTCMilliseconds",
6288
+ "setUTCMinutes",
6289
+ "setUTCMonth",
6290
+ "setUTCSeconds",
6291
+ "toDateString",
6292
+ "toISOString",
6293
+ "toString",
6294
+ "toTimeString",
6295
+ "toUTCString",
6296
+ "toJSON"
6297
+ ];
6298
+ var dateMethods = new Map(
6299
+ methodNames.map((name) => {
6300
+ const native = NativeDate.prototype[name];
6301
+ return [
6302
+ name,
6303
+ {
6304
+ length: native.length,
6305
+ invoke: (date, args) => {
6306
+ if (name === "toJSON")
6307
+ return Number.isNaN(dateTime(date)) ? null : Reflect.apply(NativeDate.prototype.toISOString, date, []);
6308
+ return Reflect.apply(
6309
+ native,
6310
+ date,
6311
+ name.startsWith("set") ? args.slice(0, native.length).map(dateNumber) : []
6312
+ );
6313
+ }
6314
+ }
6315
+ ];
6316
+ })
6317
+ );
6318
+ function dateString(value) {
6319
+ return dateMethods.get("toString").invoke(value, []);
6320
+ }
6321
+ function restoreDateTime(value) {
6322
+ if (value !== null && (typeof value !== "number" || !Number.isInteger(value) || Math.abs(value) > 864e13 || Object.is(value, -0)))
6323
+ throw new TypeError("Invalid serialized Date epoch.");
6324
+ const date = createSandboxDate(0);
6325
+ Reflect.apply(writeTime, date, [value === null ? NaN : value]);
6326
+ return date;
6327
+ }
6328
+ function serializedDateTime(value) {
6329
+ const time = dateTime(value);
6330
+ return Number.isNaN(time) ? null : time;
6331
+ }
6332
+
6333
+ // packages/safe-js/src/interp/host-capabilities.ts
6334
+ var hostObjects = /* @__PURE__ */ new WeakMap();
6335
+ var guestObjects = /* @__PURE__ */ new WeakMap();
6336
+ var guestCallbacks = /* @__PURE__ */ new WeakMap();
6337
+ var guestReferences = /* @__PURE__ */ new WeakMap();
6338
+ function createGuestReference(root, owner, assertActive) {
6339
+ const reference = Object.freeze(/* @__PURE__ */ Object.create(null));
6340
+ guestReferences.set(reference, { root, owner, assertActive });
6341
+ return reference;
6342
+ }
6343
+ function readGuestReference(reference, owner) {
6344
+ const state = typeof reference === "object" && reference !== null ? guestReferences.get(reference) : void 0;
6345
+ if (state === void 0 || state.owner !== owner)
6346
+ throw new TypeError("Foreign or invalid guest reference.");
6347
+ state.assertActive();
6348
+ if (state.root === void 0) throw new TypeError("Guest reference is revoked.");
6349
+ return state.root[0];
6350
+ }
6351
+ function revokeGuestReference(reference, owner) {
6352
+ const state = guestReferences.get(reference);
6353
+ if (state === void 0 || state.owner !== owner) throw new TypeError("Foreign guest reference.");
6354
+ state.root = void 0;
6355
+ }
6356
+ function createLiveHostObject(definition, controller) {
6357
+ const input = readDataRecord(definition, "Host object definition");
6358
+ if (Object.keys(input).some((key) => key !== "properties" && key !== "methods"))
6359
+ throw new TypeError("Unknown host object definition field.");
6360
+ const properties = /* @__PURE__ */ new Map();
6361
+ for (const [name, inputProperty] of Object.entries(
6362
+ readDataRecord(input.properties ?? {}, "Host properties")
6363
+ )) {
6364
+ const property = readDataRecord(inputProperty, `Host property '${name}'`);
6365
+ if (Object.keys(property).some((key) => key !== "get" && key !== "set"))
6366
+ throw new TypeError("Unknown host property field.");
6367
+ if (property.get !== void 0 && typeof property.get !== "function" || property.set !== void 0 && typeof property.set !== "function")
6368
+ throw new TypeError("Host property operations must be functions.");
6369
+ properties.set(name, property);
6370
+ }
6371
+ const operations = readDataRecord(input.methods ?? {}, "Host methods");
6372
+ for (const [name, operation] of Object.entries(operations)) {
6373
+ if (typeof operation !== "function") throw new TypeError("Host methods must be functions.");
6374
+ if (properties.has(name)) throw new TypeError(`Conflicting host member '${name}'.`);
6375
+ }
6376
+ for (const name of [...properties.keys(), ...Object.keys(operations)]) {
6377
+ if (["constructor", "prototype", "__proto__"].includes(name))
6378
+ throw new TypeError(`Reserved host member '${name}'.`);
6379
+ }
6380
+ controller.assertActive();
6381
+ controller.chargeWork(properties.size + Object.keys(operations).length + 1);
6382
+ const host = Object.freeze(/* @__PURE__ */ Object.create(null));
6383
+ const guest = Object.freeze(/* @__PURE__ */ Object.create(null));
6384
+ const methods = new Map(
6385
+ Object.entries(operations).map(([name, operation]) => [
6386
+ name,
6387
+ controller.method(operation)
6388
+ ])
6389
+ );
6390
+ const state = { host, guest, controller, properties, methods };
6391
+ hostObjects.set(host, state);
6392
+ guestObjects.set(guest, state);
6393
+ return host;
6394
+ }
6395
+ function isGuestHostObject(value) {
6396
+ return typeof value === "object" && value !== null && guestObjects.has(value);
6397
+ }
6398
+ function isLiveCapability(value) {
6399
+ return (typeof value === "object" && value !== null || typeof value === "function") && (hostObjects.has(value) || guestObjects.has(value) || guestCallbacks.has(value) || guestReferences.has(value));
6400
+ }
6401
+ function importHostCapability(value, owner) {
6402
+ if (guestReferences.has(value)) return readGuestReference(value, owner);
6403
+ const object = hostObjects.get(value);
6404
+ if (object !== void 0) {
6405
+ if (object.controller.owner !== owner) throw new TypeError("Foreign realm host capability.");
6406
+ object.controller.assertActive();
6407
+ return object.guest;
6408
+ }
6409
+ const callback = guestCallbacks.get(value);
6410
+ if (callback !== void 0) {
6411
+ if (callback.owner !== owner) throw new TypeError("Foreign realm guest callback.");
6412
+ callback.assertActive();
6413
+ if (callback.closure === void 0) throw new TypeError("Guest callback is revoked.");
6414
+ return callback.closure;
6415
+ }
6416
+ throw new TypeError("Unsupported live capability conversion.");
6417
+ }
6418
+ function exportHostCapability(value, owner) {
6419
+ const state = guestObjects.get(value);
6420
+ if (state === void 0 || state.controller.owner !== owner)
6421
+ throw new TypeError("Foreign realm host capability.");
6422
+ state.controller.assertActive();
6423
+ return state.host;
6424
+ }
6425
+ function registerGuestCallback(callback, state) {
6426
+ guestCallbacks.set(callback, state);
6427
+ }
6428
+ function readGuestCallback(callback, owner) {
6429
+ const state = typeof callback === "function" ? guestCallbacks.get(callback) : void 0;
6430
+ if (state === void 0 || state.owner !== owner)
6431
+ throw new TypeError("Foreign or invalid guest callback.");
6432
+ state.assertActive();
6433
+ if (state.closure === void 0) throw new TypeError("Guest callback is revoked.");
6434
+ return state.closure;
6435
+ }
6436
+ function revokeGuestCallback(callback, owner) {
6437
+ const state = guestCallbacks.get(callback);
6438
+ if (state === void 0 || state.owner !== owner) throw new TypeError("Foreign guest callback.");
6439
+ state.closure = void 0;
6440
+ }
6441
+ function revokeHostObject(value, owner) {
6442
+ const state = hostObjects.get(value);
6443
+ if (state === void 0 || state.controller.owner !== owner)
6444
+ throw new TypeError("Foreign host object.");
6445
+ state.properties.clear();
6446
+ state.methods.clear();
6447
+ }
6448
+ function getHostObjectMember(value, key) {
6449
+ const state = guestObjects.get(value);
6450
+ state.controller.assertActive();
6451
+ state.controller.chargeWork();
6452
+ const property = state.properties.get(key);
6453
+ if (property !== void 0)
6454
+ return property.get === void 0 ? void 0 : state.controller.read(property.get);
6455
+ return state.methods.get(key);
6456
+ }
6457
+ function setHostObjectMember(value, key, entry) {
6458
+ const state = guestObjects.get(value);
6459
+ state.controller.assertActive();
6460
+ state.controller.chargeWork();
6461
+ const property = state.properties.get(key);
6462
+ if (property?.set === void 0) throw new TypeError(`Host property '${key}' is not writable.`);
6463
+ state.controller.write(property.set, entry);
6464
+ }
6465
+ function getHostObjectKeys(value) {
6466
+ const state = guestObjects.get(value);
6467
+ state.controller.assertActive();
6468
+ return [...state.properties.keys(), ...state.methods.keys()];
6469
+ }
6470
+
6129
6471
  // packages/safe-js/src/interp/values.ts
6130
6472
  import { types as nodeTypes } from "node:util";
6131
6473
 
@@ -6246,7 +6588,7 @@ async function flushPromiseJobs() {
6246
6588
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
6247
6589
 
6248
6590
  // packages/safe-js/src/snapshot/validation.ts
6249
- import { types } from "node:util";
6591
+ import { types as types3 } from "node:util";
6250
6592
 
6251
6593
  // packages/safe-js/src/interp/arguments.ts
6252
6594
  var sandboxArgumentsBrand = /* @__PURE__ */ Symbol("SandboxArguments");
@@ -6443,6 +6785,7 @@ function setSandboxPrototype(value, prototype, budget) {
6443
6785
  else prototypes.set(value, prototype);
6444
6786
  }
6445
6787
  function isPrototypeRecord(value) {
6788
+ if (isGuestHostObject(value)) return false;
6446
6789
  if (isSandboxClosure(value) || isSandboxGenerator(value) || isSandboxMap(value) || isSandboxPromise(value) || isSandboxRegex(value) || isSandboxSet(value))
6447
6790
  return false;
6448
6791
  const prototype = Object.getPrototypeOf(value);
@@ -6455,6 +6798,7 @@ function hasManagedDescriptors(value) {
6455
6798
  return descriptorObjects.has(value);
6456
6799
  }
6457
6800
  function hasGuestObjectState(value) {
6801
+ if (isLiveCapability(value)) return true;
6458
6802
  if (functionProperties.has(value) || prototypes.has(value)) return true;
6459
6803
  return descriptorObjects.has(value) && Object.values(Object.getOwnPropertyDescriptors(value)).some(
6460
6804
  (descriptor) => !descriptor.enumerable || !descriptor.configurable || !descriptor.writable
@@ -6620,7 +6964,7 @@ function serializeDumpValue(value, path, state) {
6620
6964
  if (hasGuestObjectState(value)) {
6621
6965
  throw new TypeError("Guest function properties and prototype links cannot be serialized.");
6622
6966
  }
6623
- if (isFloat32Array(value)) return serializeHeapReference(value, path, state);
6967
+ if (isSandboxDate(value) || isFloat32Array(value)) return serializeHeapReference(value, path, state);
6624
6968
  if (Array.isArray(value)) {
6625
6969
  const reference2 = serializeHeapReference(value, path, state);
6626
6970
  if (reference2 !== void 0) {
@@ -6644,7 +6988,9 @@ function serializeHeapReference(value, path, state) {
6644
6988
  }
6645
6989
  if (!state.serializedHeapIds.has(id)) {
6646
6990
  state.serializedHeapIds.add(id);
6647
- if (isFloat32Array(value)) {
6991
+ if (isSandboxDate(value)) {
6992
+ state.heap[String(id)] = { kind: "date", time: serializedDateTime(value) };
6993
+ } else if (isFloat32Array(value)) {
6648
6994
  const storage = encodeFloat32Storage(value, id, state.float32Buffers, (id2) => ({
6649
6995
  kind: "ref",
6650
6996
  id: id2
@@ -6701,7 +7047,7 @@ function indexHeapContainers(snapshot) {
6701
7047
  const heapIds = /* @__PURE__ */ new WeakMap();
6702
7048
  let nextId = 1;
6703
7049
  for (const [value, stat2] of stats.entries()) {
6704
- if (stat2.count > 1 || stat2.cyclic || isFloat32Array(value) || Array.isArray(value) && requiresArrayEntries(value) || isSandboxArguments(value) || sandboxErrorTypes.has(value)) {
7050
+ if (stat2.count > 1 || stat2.cyclic || isSandboxDate(value) || isFloat32Array(value) || Array.isArray(value) && requiresArrayEntries(value) || isSandboxArguments(value) || sandboxErrorTypes.has(value)) {
6705
7051
  heapIds.set(value, nextId);
6706
7052
  nextId += 1;
6707
7053
  }
@@ -6712,7 +7058,7 @@ function collectContainerStats(value, stats, ancestors) {
6712
7058
  if (value === null || typeof value !== "object") {
6713
7059
  return;
6714
7060
  }
6715
- if (!Array.isArray(value) && !isPlainObject(value) && !isFloat32Array(value)) {
7061
+ if (!Array.isArray(value) && !isPlainObject(value) && !isFloat32Array(value) && !isSandboxDate(value)) {
6716
7062
  return;
6717
7063
  }
6718
7064
  let stat2 = stats.get(value);
@@ -6848,6 +7194,10 @@ function validateDumpHeap(root, state) {
6848
7194
  addUnique(heapIds, id, path);
6849
7195
  const entry = requireRecord(value, path);
6850
7196
  validateErrorType(entry, path);
7197
+ if (entry.kind === "date") {
7198
+ validateDateRecord(entry, path);
7199
+ continue;
7200
+ }
6851
7201
  if (entry.kind === "float32array") {
6852
7202
  validateFloat32Storage(entry);
6853
7203
  requireRecord(entry.entries, `${path}.entries`);
@@ -7005,6 +7355,14 @@ function validateGeneratorShape(record2, path, state) {
7005
7355
  }
7006
7356
  });
7007
7357
  }
7358
+ function validateDateRecord(record2, path) {
7359
+ if (Object.keys(record2).length !== 2) fail("invalidValue", path, "invalid Date fields");
7360
+ try {
7361
+ restoreDateTime(record2.time);
7362
+ } catch {
7363
+ fail("invalidValue", `${path}.time`, "invalid Date epoch");
7364
+ }
7365
+ }
7008
7366
  function validateArrayHeap(record2, path, state) {
7009
7367
  if (Object.hasOwn(record2, "items")) {
7010
7368
  requireArray(record2.items, `${path}.items`, state);
@@ -7088,7 +7446,7 @@ function validateGenericValue(value, path, depth, state) {
7088
7446
  if (typeof value === "object" && value !== null && hasGuestObjectState(value)) {
7089
7447
  fail("invalidState", path, "guest function properties, prototype links and custom descriptors cannot be restored");
7090
7448
  }
7091
- if (state.dataPropertiesOnly && types.isProxy(value)) {
7449
+ if (state.dataPropertiesOnly && types3.isProxy(value)) {
7092
7450
  fail("invalidType", path, "proxy objects are not snapshot data");
7093
7451
  }
7094
7452
  if (depth > state.limits.maxDepth)
@@ -9178,6 +9536,7 @@ function createSandboxClosure(input) {
9178
9536
  return Object.freeze(closure);
9179
9537
  }
9180
9538
  function ownEnumerableSandboxEntries(value) {
9539
+ if (isGuestHostObject(value)) return getHostObjectKeys(value).map((key) => [key, getHostObjectMember(value, key)]);
9181
9540
  if (value === null || value === void 0) throw new TypeError("Cannot convert undefined or null to object.");
9182
9541
  if (isGuestClosure(value)) return Object.entries(value.properties ?? {});
9183
9542
  if (isSandboxClosure(value) || isSandboxGenerator(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxPromise(value) || isSandboxRegex(value)) return [];
@@ -9330,6 +9689,14 @@ function measureSandboxData(values, options = {}) {
9330
9689
  assertSandboxDataDepth(depth);
9331
9690
  seen.add(value);
9332
9691
  usage += 1;
9692
+ if (isSandboxDate(value)) {
9693
+ usage += 8;
9694
+ return;
9695
+ }
9696
+ if (isGuestHostObject(value)) {
9697
+ for (const key of getHostObjectKeys(value)) usage += key.length + 1;
9698
+ return;
9699
+ }
9333
9700
  const prototype = getSandboxPrototype(value);
9334
9701
  if (prototype !== null) visit(prototype, depth + 1);
9335
9702
  if (isFloat32Array(value)) {
@@ -9472,6 +9839,7 @@ function copyToSandbox(value, state, path = "<root>", cloneSandboxCollections =
9472
9839
  if (isSandboxPrimitive(value)) {
9473
9840
  return value;
9474
9841
  }
9842
+ if (isLiveCapability(value)) throw new TypeError("Live capabilities require their owning realm bridge.");
9475
9843
  if (isSandboxClosure(value) || isSandboxGenerator(value) || isSandboxRegex(value) || isSandboxPromise(value)) {
9476
9844
  return value;
9477
9845
  }
@@ -9519,6 +9887,13 @@ function copyToSandbox(value, state, path = "<root>", cloneSandboxCollections =
9519
9887
  }
9520
9888
  return sandboxPromise;
9521
9889
  }
9890
+ if (nodeTypes.isDate(value)) {
9891
+ const existing = state.seen.get(value);
9892
+ if (existing !== void 0) return existing;
9893
+ const copy = copyNativeDate(value);
9894
+ state.seen.set(value, copy);
9895
+ return copy;
9896
+ }
9522
9897
  if (isFloat32Array(value)) {
9523
9898
  const existing = state.seen.get(value);
9524
9899
  if (existing !== void 0) return existing;
@@ -9635,6 +10010,10 @@ function copyFromSandbox(value, state, path = "<root>", options, depth = 0) {
9635
10010
  if (isSandboxPrimitive(value)) {
9636
10011
  return value;
9637
10012
  }
10013
+ if (isGuestHostObject(value)) {
10014
+ if (options.unwrapHostObject === void 0) throw new TypeError("Live capabilities require their owning realm bridge.");
10015
+ return options.unwrapHostObject(value);
10016
+ }
9638
10017
  if (nodeTypes.isProxy(value)) throw new TypeError("Unsupported proxy sandbox value.");
9639
10018
  if (!isSandboxClosure(value) && hasGuestObjectState(value)) {
9640
10019
  throw new TypeError("Guest prototype links and custom descriptors cannot be copied as data.");
@@ -9674,6 +10053,13 @@ function copyFromSandbox(value, state, path = "<root>", options, depth = 0) {
9674
10053
  if (!Object.isExtensible(value)) Object.preventExtensions(copy);
9675
10054
  return copy;
9676
10055
  }
10056
+ if (isSandboxDate(value)) {
10057
+ const existing = state.seen.get(value);
10058
+ if (existing !== void 0) return existing;
10059
+ const copy = exportDate(value);
10060
+ state.seen.set(value, copy);
10061
+ return copy;
10062
+ }
9677
10063
  if (isSandboxClosure(value)) {
9678
10064
  if (options.wrapClosure === void 0) {
9679
10065
  throw new TypeError(
@@ -9988,6 +10374,8 @@ function encodeReplayData(value, options = {}) {
9988
10374
  id: capabilityId,
9989
10375
  properties: child(entry.properties, "properties")
9990
10376
  };
10377
+ } else if (isSandboxDate(entry)) {
10378
+ nodes[id] = { kind: "date", time: serializedDateTime(entry) };
9991
10379
  } else if (isFloat32Array(entry)) {
9992
10380
  const storage = encodeFloat32Storage(entry, id, float32Buffers, (id2) => ({
9993
10381
  tag: "ref",
@@ -10138,6 +10526,12 @@ function decodeReplayData(input, options = {}, parent) {
10138
10526
  options.onCapabilityRestored?.(capability, copy);
10139
10527
  return copy;
10140
10528
  }
10529
+ if (kind === "date") {
10530
+ if (Object.keys(node).length !== 2) throw new TypeError("Invalid serialized Date fields.");
10531
+ const result3 = restoreDateTime(own(node, "time"));
10532
+ restored.set(id, result3);
10533
+ return result3;
10534
+ }
10141
10535
  if (kind === "float32array") {
10142
10536
  if (typeof node.extensible !== "boolean")
10143
10537
  throw new TypeError("Invalid Float32Array extensibility.");
@@ -10828,6 +11222,8 @@ function normalize(value, seen) {
10828
11222
  if (seen.has(value)) throw new TypeError("Host call arguments cannot contain cycles.");
10829
11223
  seen.add(value);
10830
11224
  try {
11225
+ const date = copyNativeDate(value);
11226
+ if (date !== void 0) return Object.assign(/* @__PURE__ */ Object.create(null), { $type: "date", time: serializedDateTime(date) });
10831
11227
  if (isFloat32Array(value)) {
10832
11228
  const storage = float32Storage(value);
10833
11229
  const properties = /* @__PURE__ */ Object.create(null);
@@ -11783,6 +12179,7 @@ var KNOWN_RUNTIME_GLOBALS = [
11783
12179
  "AggregateError",
11784
12180
  "Array",
11785
12181
  "Boolean",
12182
+ "Date",
11786
12183
  "Error",
11787
12184
  "Infinity",
11788
12185
  "isFinite",
@@ -16947,9 +17344,9 @@ var ASFloatingPromiseScanner = class {
16947
17344
  isPromiseFactoryCall(node) {
16948
17345
  return this.isPromiseStaticMethodCall(node, PROMISE_FACTORIES);
16949
17346
  }
16950
- isPromiseStaticMethodCall(node, methodNames) {
17347
+ isPromiseStaticMethodCall(node, methodNames2) {
16951
17348
  const member = node.callee.type === "MemberExpression" ? node.callee : void 0;
16952
- return member !== void 0 && !member.computed && member.object.type === "Identifier" && member.object.name === "Promise" && member.property.type === "Identifier" && methodNames.has(member.property.name);
17349
+ return member !== void 0 && !member.computed && member.object.type === "Identifier" && member.object.name === "Promise" && member.property.type === "Identifier" && methodNames2.has(member.property.name);
16953
17350
  }
16954
17351
  isPromiseChainCall(node) {
16955
17352
  const member = node.callee.type === "MemberExpression" ? node.callee : void 0;
@@ -22240,128 +22637,6 @@ function hasOnlyRegexLiteralDiagnostics(diagnostics) {
22240
22637
  );
22241
22638
  }
22242
22639
 
22243
- // packages/safe-js/src/random.ts
22244
- import { randomInt } from "node:crypto";
22245
-
22246
- // packages/safe-js/src/interp/globals/math.ts
22247
- var mathMethods = {
22248
- abs: Math.abs,
22249
- acos: Math.acos,
22250
- acosh: Math.acosh,
22251
- asin: Math.asin,
22252
- asinh: Math.asinh,
22253
- atan: Math.atan,
22254
- atan2: Math.atan2,
22255
- atanh: Math.atanh,
22256
- ceil: Math.ceil,
22257
- cbrt: Math.cbrt,
22258
- clz32: Math.clz32,
22259
- cos: Math.cos,
22260
- cosh: Math.cosh,
22261
- exp: Math.exp,
22262
- expm1: Math.expm1,
22263
- floor: Math.floor,
22264
- f16round,
22265
- fround: Math.fround,
22266
- hypot: Math.hypot,
22267
- imul: Math.imul,
22268
- log: Math.log,
22269
- log1p: Math.log1p,
22270
- log10: Math.log10,
22271
- log2: Math.log2,
22272
- max: Math.max,
22273
- min: Math.min,
22274
- pow: Math.pow,
22275
- round: Math.round,
22276
- sign: Math.sign,
22277
- sin: Math.sin,
22278
- sinh: Math.sinh,
22279
- sqrt: Math.sqrt,
22280
- tan: Math.tan,
22281
- tanh: Math.tanh,
22282
- trunc: Math.trunc
22283
- };
22284
- function f16round(value) {
22285
- const number = +value;
22286
- if (!Number.isFinite(number) || number === 0) {
22287
- return number;
22288
- }
22289
- const magnitude = Math.abs(number);
22290
- if (magnitude >= 65520) {
22291
- return number < 0 ? -Infinity : Infinity;
22292
- }
22293
- let quantum = 2 ** -24;
22294
- let boundary = 2 ** -13;
22295
- for (let exponent = -13; exponent <= 15 && magnitude >= boundary; exponent += 1) {
22296
- quantum *= 2;
22297
- boundary *= 2;
22298
- }
22299
- const scaled = magnitude / quantum;
22300
- const lower = Math.floor(scaled);
22301
- const remainder = scaled - lower;
22302
- const rounded = (remainder > 0.5 || remainder === 0.5 && lower % 2 !== 0 ? lower + 1 : lower) * quantum;
22303
- return number < 0 ? -rounded : rounded;
22304
- }
22305
- function createMathGlobals(options = {}) {
22306
- const random = options.random ?? Math.random;
22307
- const mathObject = {
22308
- E: Math.E,
22309
- LN2: Math.LN2,
22310
- LN10: Math.LN10,
22311
- LOG2E: Math.LOG2E,
22312
- LOG10E: Math.LOG10E,
22313
- PI: Math.PI,
22314
- SQRT1_2: Math.SQRT1_2,
22315
- SQRT2: Math.SQRT2,
22316
- random: createSandboxClosure({ sandbox: true, call: () => random(), name: "random" })
22317
- };
22318
- for (const [name, method] of Object.entries(mathMethods)) {
22319
- mathObject[name] = createSandboxClosure({
22320
- sandbox: true,
22321
- call: (args) => Reflect.apply(method, Math, args),
22322
- name
22323
- });
22324
- }
22325
- return {
22326
- Infinity: Infinity,
22327
- Math: mathObject,
22328
- NaN: Number.NaN
22329
- };
22330
- }
22331
- function createSeededRandom(seed) {
22332
- let state = normalizeSeed(seed);
22333
- return {
22334
- next: () => {
22335
- state = Math.imul(state, 1664525) + 1013904223 >>> 0;
22336
- return state / 4294967296;
22337
- },
22338
- snapshot: () => state,
22339
- restore: (nextState) => {
22340
- state = normalizeSeed(nextState);
22341
- }
22342
- };
22343
- }
22344
- function normalizeSeed(seed) {
22345
- if (!Number.isFinite(seed)) {
22346
- throw new TypeError("Seeded random requires a finite numeric seed.");
22347
- }
22348
- return Math.trunc(seed) >>> 0;
22349
- }
22350
-
22351
- // packages/safe-js/src/random.ts
22352
- function createReplayableRandom(options = {}) {
22353
- const snapshot = options.snapshot;
22354
- const saved = snapshot?.random;
22355
- let initialState = options.seed;
22356
- if (saved !== void 0) {
22357
- const hasLoopState = typeof snapshot?.loopIterations === "object" && snapshot.loopIterations !== null && Object.keys(snapshot.loopIterations).length > 0;
22358
- const replaysFromStart = snapshot?.replay !== void 0 || Array.isArray(snapshot?.pendingAwaits) && snapshot.pendingAwaits.length > 0 && !hasLoopState;
22359
- initialState = replaysFromStart ? saved.initialState ?? saved.seed : saved.resumeState ?? saved.state;
22360
- }
22361
- const generator = createSeededRandom(initialState ?? randomInt(4294967296));
22362
- return { seed: saved?.seed ?? generator.snapshot(), ...generator };
22363
- }
22364
-
22365
22640
  // packages/safe-js/src/interp/generator.ts
22366
22641
  function createGeneratorChannel(body) {
22367
22642
  let state = "unstarted";
@@ -24709,6 +24984,101 @@ function relativeIndex(value, length, fallback) {
24709
24984
  return integer < 0 ? Math.max(length + integer, 0) : Math.min(integer, length);
24710
24985
  }
24711
24986
 
24987
+ // packages/safe-js/src/interp/globals/date.ts
24988
+ var intrinsics = /* @__PURE__ */ new WeakMap();
24989
+ var constructors2 = /* @__PURE__ */ new WeakSet();
24990
+ function createDateGlobal(options) {
24991
+ const validateClockTime = (value) => {
24992
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || Math.abs(value) > 864e13)
24993
+ throw new TypeError("Date clock must return a finite integer epoch within the Date range.");
24994
+ return value;
24995
+ };
24996
+ const readNow = declareHostOperation(
24997
+ () => {
24998
+ options.budget.visitNode();
24999
+ const value = options.clock?.now === void 0 ? Date.now() : options.clock.now();
25000
+ return validateClockTime(value);
25001
+ },
25002
+ "re-issue",
25003
+ {
25004
+ onReplay: (_args, outcome) => {
25005
+ if (outcome.status === "fulfilled") {
25006
+ const time = validateClockTime(outcome.value);
25007
+ options.clock?.restore?.({ next: time + 1 });
25008
+ }
25009
+ }
25010
+ }
25011
+ );
25012
+ const now = wrapCallerInjectedBindings({ now: readNow }, { ...options, moduleId: "<Date>" }).now;
25013
+ const prototype = createSandboxDate(NaN);
25014
+ const constructor = createSandboxClosure({
25015
+ sandbox: true,
25016
+ name: "Date",
25017
+ length: 7,
25018
+ call: async (_args, context) => options.budget.allocateString(
25019
+ dateString(createSandboxDate(Number(await now.call([], context))))
25020
+ ),
25021
+ construct: async (args, context) => {
25022
+ let time;
25023
+ if (args.length === 0) time = Number(await now.call([], context));
25024
+ else if (args.length > 1) time = dateFromParts(args, false);
25025
+ else if (isSandboxDate(args[0])) time = dateTime(args[0]);
25026
+ else if (typeof args[0] === "string") time = parseDate(args[0], options.budget);
25027
+ else time = dateNumber(args[0]);
25028
+ options.budget.chargeDataUsage(9);
25029
+ return createSandboxDate(time);
25030
+ },
25031
+ properties: {
25032
+ now,
25033
+ prototype,
25034
+ parse: createSandboxClosure({
25035
+ sandbox: true,
25036
+ name: "parse",
25037
+ length: 1,
25038
+ call: ([value]) => parseDate(value, options.budget)
25039
+ }),
25040
+ UTC: createSandboxClosure({
25041
+ sandbox: true,
25042
+ name: "UTC",
25043
+ length: 7,
25044
+ call: (args) => dateFromParts(args, true)
25045
+ })
25046
+ }
25047
+ });
25048
+ const methods = /* @__PURE__ */ new Map();
25049
+ for (const [name, method] of dateMethods)
25050
+ methods.set(
25051
+ name,
25052
+ createSandboxClosure({
25053
+ sandbox: true,
25054
+ name,
25055
+ length: method.length,
25056
+ call: (args, context) => {
25057
+ const receiver = context?.thisValue;
25058
+ if (!isSandboxDate(receiver))
25059
+ throw new TypeError(`Date#${name} requires a Date receiver.`);
25060
+ options.budget.visitNode();
25061
+ const value = method.invoke(receiver, args);
25062
+ return typeof value === "string" ? options.budget.allocateString(value) : value;
25063
+ }
25064
+ })
25065
+ );
25066
+ constructors2.add(constructor);
25067
+ intrinsics.set(options.compileOwner ?? options.budget, { constructor, prototype, methods });
25068
+ return constructor;
25069
+ }
25070
+ function isDateConstructor(value) {
25071
+ return typeof value === "object" && value !== null && constructors2.has(value);
25072
+ }
25073
+ function getDateMember(property, budget, owner) {
25074
+ const state = intrinsics.get(owner ?? budget);
25075
+ return property === "constructor" ? state?.constructor : state?.methods.get(String(property));
25076
+ }
25077
+ function getDatePrototype(value, budget, owner) {
25078
+ const prototype = intrinsics.get(owner ?? budget)?.prototype;
25079
+ return prototype === value ? null : prototype ?? null;
25080
+ }
25081
+
24712
25082
  // packages/safe-js/src/interp/scope.ts
24713
25083
  var uninitialized = /* @__PURE__ */ Symbol("uninitialized");
24714
25084
  var Scope = class _Scope {
@@ -25003,9 +25373,10 @@ async function interpret(node, options = {}) {
25003
25373
  peakDataSize: { enumerable: false, value: 0, writable: true }
25004
25374
  });
25005
25375
  const activeLoopIterations = /* @__PURE__ */ new Map();
25006
- const jobs = new SandboxJobQueue();
25376
+ const jobs = options.jobs ?? new SandboxJobQueue();
25007
25377
  hoistVarDeclarations(node, scope);
25008
25378
  const context = {
25379
+ assertActive: options.assertActive,
25009
25380
  compilation,
25010
25381
  budget,
25011
25382
  callStack: [],
@@ -25028,9 +25399,9 @@ async function interpret(node, options = {}) {
25028
25399
  };
25029
25400
  const evaluation = await withCancellationSignal(
25030
25401
  options.signal,
25031
- () => jobs.run(() => evaluateNode(node, context))
25402
+ () => options.nested ? runAsyncPrefix(() => evaluateNode(node, context)) : jobs.run(() => evaluateNode(node, context))
25032
25403
  );
25033
- await jobs.drain();
25404
+ if (!options.nested) await jobs.drain();
25034
25405
  const snapshot = scope.snapshot();
25035
25406
  reconcileDataBudget(
25036
25407
  budget,
@@ -25085,6 +25456,7 @@ async function interpret(node, options = {}) {
25085
25456
  }
25086
25457
  }
25087
25458
  async function evaluateNode(node, context) {
25459
+ context.assertActive?.();
25088
25460
  const replayWait = promiseReplayContext.getStore()?.beforeNode(node.nodeId);
25089
25461
  if (replayWait !== void 0) await suspendJob(replayWait);
25090
25462
  assertPromiseExecutionAllowed();
@@ -26056,6 +26428,7 @@ function forInObject(value) {
26056
26428
  return void 0;
26057
26429
  }
26058
26430
  function forInKeys(object, budget) {
26431
+ if (isGuestHostObject(object)) return getHostObjectKeys(object);
26059
26432
  const keys = [];
26060
26433
  const seen = /* @__PURE__ */ new Set();
26061
26434
  let depth = 0;
@@ -26073,6 +26446,7 @@ function forInKeys(object, budget) {
26073
26446
  return keys;
26074
26447
  }
26075
26448
  function hasForInProperty(object, key, budget) {
26449
+ if (isGuestHostObject(object)) return getHostObjectKeys(object).includes(key);
26076
26450
  let depth = 0;
26077
26451
  for (let current = object; current !== null; current = getSandboxPrototype(current)) {
26078
26452
  if (depth > 0) budget.visitNode();
@@ -26564,10 +26938,12 @@ async function evaluateMemberExpression(node, context) {
26564
26938
  };
26565
26939
  }
26566
26940
  function getPropertyValue(target, property, context) {
26941
+ if (isGuestHostObject(target)) return getHostObjectMember(target, String(property));
26567
26942
  if (typeof target === "string") return getStringMember(target, property, context.budget);
26568
26943
  if (typeof target === "number") return getNumberMember(target, property, context.budget);
26569
26944
  if (typeof target === "boolean") return void 0;
26570
26945
  if (isFloat32Array(target)) return getFloat32Member(target, property, context.budget);
26946
+ if (isSandboxDate(target)) return getDateMember(property, context.budget, context.compilation?.owner);
26571
26947
  if (isSandboxMap(target)) return getMapMember(target, property, createMapMethodOptions(context));
26572
26948
  if (isSandboxSet(target)) return getSetMember(target, property, createSetMethodOptions(context));
26573
26949
  if (isSandboxGenerator(target)) return getGeneratorMember(target, property, context.budget);
@@ -26804,6 +27180,9 @@ async function evaluateMemberCallExpression(node, context) {
26804
27180
  context
26805
27181
  );
26806
27182
  }
27183
+ if (isSandboxDate(member.object)) {
27184
+ return evaluateResolvedCallExpression(node, getDateMember(member.property, context.budget, context.compilation?.owner), context, member.object);
27185
+ }
26807
27186
  if (isFloat32Array(member.object)) {
26808
27187
  return evaluateResolvedCallExpression(
26809
27188
  node,
@@ -27056,6 +27435,7 @@ function applyBinaryOperator(node, left, right, context) {
27056
27435
  return true;
27057
27436
  }
27058
27437
  if (isFloat32ArrayConstructor(right)) return isFloat32Array(left);
27438
+ if (isDateConstructor(right)) return isSandboxDate(left) && getDatePrototype(left, context.budget, context.compilation?.owner) !== null;
27059
27439
  if (isSandboxSetConstructor(right) && isSandboxSet(left)) {
27060
27440
  return true;
27061
27441
  }
@@ -27119,8 +27499,8 @@ function applyAdditionOperator(left, right, context) {
27119
27499
  return toNumber(leftPrimitive) + toNumber(rightPrimitive);
27120
27500
  }
27121
27501
  function compareRelational(left, right, operator) {
27122
- const leftPrimitive = toPrimitive(left);
27123
- const rightPrimitive = toPrimitive(right);
27502
+ const leftPrimitive = isSandboxDate(left) ? dateTime(left) : toPrimitive(left);
27503
+ const rightPrimitive = isSandboxDate(right) ? dateTime(right) : toPrimitive(right);
27124
27504
  if (typeof leftPrimitive === "string" && typeof rightPrimitive === "string") {
27125
27505
  switch (operator) {
27126
27506
  case "<":
@@ -27203,6 +27583,7 @@ function toPrimitive(value) {
27203
27583
  return toString(value);
27204
27584
  }
27205
27585
  async function toNumericPrimitive(value, context) {
27586
+ if (isSandboxDate(value)) return dateTime(value);
27206
27587
  if (isPrimitiveCoercionType(getCoercionType(value))) {
27207
27588
  return value;
27208
27589
  }
@@ -27232,6 +27613,7 @@ async function toNumericPrimitive(value, context) {
27232
27613
  return toString(value);
27233
27614
  }
27234
27615
  function toNumber(value) {
27616
+ if (isSandboxDate(value)) return dateTime(value);
27235
27617
  if (typeof value === "number") {
27236
27618
  return value;
27237
27619
  }
@@ -27250,6 +27632,7 @@ function toNumber(value) {
27250
27632
  return toNumber(toPrimitive(value));
27251
27633
  }
27252
27634
  function toString(value) {
27635
+ if (isSandboxDate(value)) return dateString(value);
27253
27636
  if (Array.isArray(value)) {
27254
27637
  return value.map((entry) => entry === null || entry === void 0 ? "" : toString(entry)).join(",");
27255
27638
  }
@@ -27270,6 +27653,7 @@ function isPlainSandboxObject(value) {
27270
27653
  return typeof value === "object" && value !== null && !Array.isArray(value) && !isSandboxClosure(value) && !isSandboxMap(value) && !isSandboxSet(value) && !isSandboxPromise(value) && !isSandboxRegex(value);
27271
27654
  }
27272
27655
  function getMemberValue(target, property, context) {
27656
+ if (isGuestHostObject(target)) return getHostObjectMember(target, String(property));
27273
27657
  let current = target;
27274
27658
  let depth = 0;
27275
27659
  while (typeof current === "object" && current !== null) {
@@ -27294,6 +27678,11 @@ function getArrayMemberValue(target, property, context) {
27294
27678
  return getArrayMember(target, property, createArrayMethodOptions(context));
27295
27679
  }
27296
27680
  function setSandboxProperty(target, property, value, budget) {
27681
+ if (isSandboxDate(target)) throw new TypeError("Date own properties are not supported.");
27682
+ if (isGuestHostObject(target)) {
27683
+ setHostObjectMember(target, String(property), value);
27684
+ return;
27685
+ }
27297
27686
  const prototypeOwner = target;
27298
27687
  if (isGuestClosure(target)) target = materializeFunctionProperties(target);
27299
27688
  if (isFloat32Array(target)) {
@@ -27338,6 +27727,7 @@ function setSandboxProperty(target, property, value, budget) {
27338
27727
  }
27339
27728
  }
27340
27729
  function deleteSandboxProperty(target, property) {
27730
+ if (isGuestHostObject(target)) throw new TypeError("Live host properties cannot be deleted.");
27341
27731
  if (isGuestClosure(target)) target = materializeFunctionProperties(target);
27342
27732
  if (Array.isArray(target)) {
27343
27733
  assertCollectionMutable(target);
@@ -27903,7 +28293,7 @@ function wrapCallerInjectedBindings(bindings, options) {
27903
28293
  const copied = Object.fromEntries(
27904
28294
  Object.entries(bindings).map(([name, value]) => [
27905
28295
  name,
27906
- typeof value === "function" ? wrapCallerInjectedFunction(name, value, { ...options, capabilityPath: [name] }, state) : copyHostValueToSandbox(
28296
+ typeof value === "function" && !isLiveCapability(value) ? wrapCallerInjectedFunction(name, value, { ...options, capabilityPath: [name] }, state) : copyHostValueToSandbox(
27907
28297
  value,
27908
28298
  [],
27909
28299
  { ...options, operation: name, capabilityPath: [name] },
@@ -27924,9 +28314,10 @@ function wrapCallerInjectedFunction(name, value, options, state) {
27924
28314
  const bindingName = name === "default" && value.name.length > 0 ? value.name : name;
27925
28315
  const callable = value;
27926
28316
  return createSandboxClosure({
27927
- ...isAsyncFunction(callable) ? { async: true } : {},
28317
+ ...isAsyncFunction(callable) && !options.realm?.awaitResult(callable) ? { async: true } : {},
27928
28318
  cancellationSignal: options.signal,
27929
28319
  call: (args, context) => {
28320
+ options.realm?.assertActive();
27930
28321
  const operationLease = options.budget.acquireCompileOwner(false, options.compileOwner);
27931
28322
  const compilation = new CompileScope(operationLease.owner);
27932
28323
  try {
@@ -27942,9 +28333,10 @@ function wrapCallerInjectedFunction(name, value, options, state) {
27942
28333
  seen: /* @__PURE__ */ new WeakMap(),
27943
28334
  restored: []
27944
28335
  };
27945
- const hostArgs = deepCopyFromSandbox([...args], {
28336
+ const copyArguments = (values) => deepCopyFromSandbox([...values], {
27946
28337
  compilation,
27947
- wrapClosure: (closure) => wrapSandboxClosureForHost(
28338
+ unwrapHostObject: options.realm === void 0 ? void 0 : (object) => exportHostCapability(object, options.realm.owner),
28339
+ wrapClosure: (closure) => options.realm?.wrapCallback(closure) ?? wrapSandboxClosureForHost(
27948
28340
  closure,
27949
28341
  stackFrames,
27950
28342
  options.budget,
@@ -27952,11 +28344,26 @@ function wrapCallerInjectedFunction(name, value, options, state) {
27952
28344
  callbacks
27953
28345
  )
27954
28346
  });
28347
+ const captured = options.realm?.captureArguments(callable, args, copyArguments);
28348
+ const hostArgs = captured?.args ?? copyArguments(args);
27955
28349
  const hostCalls = options.hostCalls;
27956
28350
  const operation = options.operation ?? bindingName;
27957
28351
  const moduleId = options.moduleId ?? "<bindings>";
27958
28352
  const policy = readHostOperationPolicy(value) ?? readRegisteredPendingHostCallPolicy(moduleId, operation) ?? "re-issue";
27959
28353
  if (hostCalls === void 0) {
28354
+ if (options.realm !== void 0) {
28355
+ let result;
28356
+ try {
28357
+ result = options.realm.invoke(callable, () => Reflect.apply(callable, void 0, hostArgs));
28358
+ } catch (error) {
28359
+ captured.rollback();
28360
+ throw error;
28361
+ }
28362
+ if (options.realm.awaitResult(callable)) {
28363
+ return Promise.resolve(result).then((value2) => copyHostResultToSandbox(value2, stackFrames, options));
28364
+ }
28365
+ return copyHostResultToSandbox(result, stackFrames, options);
28366
+ }
27960
28367
  return copyHostResultToSandbox(
27961
28368
  invokeHostCallback(() => Reflect.apply(callable, void 0, hostArgs), options),
27962
28369
  stackFrames,
@@ -28494,6 +28901,10 @@ function wrapHostPromiseWithSignal(promise, signal) {
28494
28901
  }
28495
28902
  function copyHostValueToSandbox(value, stackFrames, options, state, path) {
28496
28903
  const { budget } = options;
28904
+ if (isLiveCapability(value)) {
28905
+ if (options.realm === void 0 || options.errorData || options.hostCalls !== void 0) throw new TypeError("Live capabilities are not portable replay or error data.");
28906
+ return importHostCapability(value, options.realm.owner);
28907
+ }
28497
28908
  if (value === null || value === void 0 || typeof value === "number" || typeof value === "boolean") {
28498
28909
  return value;
28499
28910
  }
@@ -28535,6 +28946,14 @@ function copyHostValueToSandbox(value, stackFrames, options, state, path) {
28535
28946
  state
28536
28947
  );
28537
28948
  }
28949
+ const date = copyNativeDate(value);
28950
+ if (date !== void 0) {
28951
+ const existing = state.seen.get(value);
28952
+ if (existing !== void 0) return existing;
28953
+ budget.chargeDataUsage(9);
28954
+ state.seen.set(value, date);
28955
+ return date;
28956
+ }
28538
28957
  if (isFloat32Array(value)) {
28539
28958
  const existing = state.seen.get(value);
28540
28959
  if (existing !== void 0) return existing;
@@ -28812,386 +29231,131 @@ function describeValue2(value) {
28812
29231
  return typeof value;
28813
29232
  }
28814
29233
 
28815
- // packages/safe-js/src/snapshot/dump.ts
28816
- var RUN_DUMP_CONTROLLER = /* @__PURE__ */ Symbol("SafeJS.run-dump-controller");
28817
- function attachDumpController(result, controller) {
28818
- Object.defineProperty(result, RUN_DUMP_CONTROLLER, {
28819
- configurable: false,
28820
- enumerable: false,
28821
- value: controller,
28822
- writable: false
28823
- });
28824
- return result;
28825
- }
28826
- function createDumpController(lifecycle) {
28827
- let finished = false;
28828
- let failed;
28829
- let finalSnapshot;
28830
- let latestSnapshot;
28831
- let latestSnapshotFactory;
28832
- let pendingRequest;
28833
- return {
28834
- fail(error) {
28835
- finished = true;
28836
- failed = {
28837
- error
28838
- };
28839
- if (pendingRequest === void 0) {
28840
- return;
28841
- }
28842
- pendingRequest.reject(error);
28843
- pendingRequest = void 0;
28844
- },
28845
- finalize(snapshot) {
28846
- finished = true;
28847
- finalSnapshot = snapshot;
28848
- latestSnapshot = snapshot;
28849
- latestSnapshotFactory = void 0;
28850
- if (pendingRequest !== void 0) {
28851
- settlePendingSnapshot(snapshot);
28852
- }
28853
- },
28854
- onYield(createSnapshot) {
28855
- latestSnapshot = void 0;
28856
- latestSnapshotFactory = createSnapshot;
28857
- if (pendingRequest === void 0) {
28858
- return;
28859
- }
28860
- settlePendingSnapshot(createSnapshot());
28861
- },
28862
- requestCurrentSnapshot(options = {}) {
28863
- assertDumpAllowed(options);
28864
- if (failed !== void 0) {
28865
- return Promise.reject(failed.error);
28866
- }
28867
- if (latestSnapshot !== void 0 || latestSnapshotFactory !== void 0) {
28868
- try {
28869
- return Promise.resolve(serializeRunSnapshot(latestSnapshot ?? latestSnapshotFactory()));
28870
- } catch (error) {
28871
- return Promise.reject(error);
28872
- }
28873
- }
28874
- return this.requestSnapshot(options);
28875
- },
28876
- requestSnapshot(options = {}) {
28877
- assertDumpAllowed(options);
28878
- if (failed !== void 0) {
28879
- if ((options.onFailure === "checkpoint" || options.onFailure === void 0 && isDataBudgetError(failed.error)) && finalSnapshot !== void 0) {
28880
- try {
28881
- return Promise.resolve(serializeRunSnapshot(finalSnapshot));
28882
- } catch (error) {
28883
- return Promise.reject(error);
28884
- }
28885
- }
28886
- return Promise.reject(failed.error);
28887
- }
28888
- if (finished) {
28889
- if (finalSnapshot === void 0) {
28890
- throw new Error("Run completed without producing a snapshot.");
28891
- }
28892
- try {
28893
- const serializedSnapshot = serializeRunSnapshot(finalSnapshot);
28894
- return Promise.resolve(serializedSnapshot);
28895
- } catch (error) {
28896
- return Promise.reject(error);
28897
- }
28898
- }
28899
- if (options.mode === "replay" && (latestSnapshot !== void 0 || latestSnapshotFactory !== void 0)) {
28900
- return this.requestCurrentSnapshot(options);
28901
- }
28902
- if (pendingRequest !== void 0) {
28903
- return pendingRequest.promise;
28904
- }
28905
- let resolveSnapshot = () => void 0;
28906
- let rejectSnapshot = () => void 0;
28907
- const promise = new Promise((resolve, reject) => {
28908
- resolveSnapshot = resolve;
28909
- rejectSnapshot = reject;
28910
- });
28911
- pendingRequest = {
28912
- promise,
28913
- reject: rejectSnapshot,
28914
- resolve: resolveSnapshot
28915
- };
28916
- return promise;
28917
- }
28918
- };
28919
- function assertDumpAllowed(options) {
28920
- if ((lifecycle?.hostCallbackDepth ?? 0) > 0 && (options.mode !== "replay" || lifecycle?.hostCallbackContext.getStore() === true)) {
28921
- throw new SandboxError("reentry");
28922
- }
28923
- }
28924
- function settlePendingSnapshot(snapshot) {
28925
- try {
28926
- settlePendingRequest(serializeRunSnapshot(snapshot));
28927
- } catch (error) {
28928
- pendingRequest?.reject(error);
28929
- pendingRequest = void 0;
28930
- }
28931
- }
28932
- function settlePendingRequest(snapshot) {
28933
- if (pendingRequest === void 0) {
28934
- return;
28935
- }
28936
- pendingRequest.resolve(snapshot);
28937
- pendingRequest = void 0;
29234
+ // packages/safe-js/src/random.ts
29235
+ import { randomInt } from "node:crypto";
29236
+
29237
+ // packages/safe-js/src/interp/globals/math.ts
29238
+ var mathMethods = {
29239
+ abs: Math.abs,
29240
+ acos: Math.acos,
29241
+ acosh: Math.acosh,
29242
+ asin: Math.asin,
29243
+ asinh: Math.asinh,
29244
+ atan: Math.atan,
29245
+ atan2: Math.atan2,
29246
+ atanh: Math.atanh,
29247
+ ceil: Math.ceil,
29248
+ cbrt: Math.cbrt,
29249
+ clz32: Math.clz32,
29250
+ cos: Math.cos,
29251
+ cosh: Math.cosh,
29252
+ exp: Math.exp,
29253
+ expm1: Math.expm1,
29254
+ floor: Math.floor,
29255
+ f16round,
29256
+ fround: Math.fround,
29257
+ hypot: Math.hypot,
29258
+ imul: Math.imul,
29259
+ log: Math.log,
29260
+ log1p: Math.log1p,
29261
+ log10: Math.log10,
29262
+ log2: Math.log2,
29263
+ max: Math.max,
29264
+ min: Math.min,
29265
+ pow: Math.pow,
29266
+ round: Math.round,
29267
+ sign: Math.sign,
29268
+ sin: Math.sin,
29269
+ sinh: Math.sinh,
29270
+ sqrt: Math.sqrt,
29271
+ tan: Math.tan,
29272
+ tanh: Math.tanh,
29273
+ trunc: Math.trunc
29274
+ };
29275
+ function f16round(value) {
29276
+ const number = +value;
29277
+ if (!Number.isFinite(number) || number === 0) {
29278
+ return number;
28938
29279
  }
28939
- }
28940
- function isDataBudgetError(error) {
28941
- return typeof error === "object" && error !== null && "code" in error && error.code === "budgetExceeded" && "budget" in error && error.budget === "dataSize";
28942
- }
28943
- function dump(result, options = {}) {
28944
- const controller = readDumpController(result);
28945
- if (controller !== void 0) {
28946
- return controller.requestSnapshot(options);
29280
+ const magnitude = Math.abs(number);
29281
+ if (magnitude >= 65520) {
29282
+ return number < 0 ? -Infinity : Infinity;
28947
29283
  }
28948
- if (hasSnapshot(result)) {
28949
- try {
28950
- return Promise.resolve(serializeRunSnapshot(result.snapshot));
28951
- } catch (error) {
28952
- return Promise.reject(error);
28953
- }
29284
+ let quantum = 2 ** -24;
29285
+ let boundary = 2 ** -13;
29286
+ for (let exponent = -13; exponent <= 15 && magnitude >= boundary; exponent += 1) {
29287
+ quantum *= 2;
29288
+ boundary *= 2;
28954
29289
  }
28955
- return Promise.resolve(result).then((resolved) => {
28956
- if (!hasSnapshot(resolved)) {
28957
- throw new Error("Run completed without producing a snapshot.");
28958
- }
28959
- return serializeRunSnapshot(resolved.snapshot);
28960
- });
29290
+ const scaled = magnitude / quantum;
29291
+ const lower = Math.floor(scaled);
29292
+ const remainder = scaled - lower;
29293
+ const rounded = (remainder > 0.5 || remainder === 0.5 && lower % 2 !== 0 ? lower + 1 : lower) * quantum;
29294
+ return number < 0 ? -rounded : rounded;
28961
29295
  }
28962
- function dumpCurrent(result) {
28963
- const controller = readDumpController(result);
28964
- if (controller !== void 0) {
28965
- return controller.requestCurrentSnapshot();
29296
+ function createMathGlobals(options = {}) {
29297
+ const random = options.random ?? Math.random;
29298
+ const mathObject = {
29299
+ E: Math.E,
29300
+ LN2: Math.LN2,
29301
+ LN10: Math.LN10,
29302
+ LOG2E: Math.LOG2E,
29303
+ LOG10E: Math.LOG10E,
29304
+ PI: Math.PI,
29305
+ SQRT1_2: Math.SQRT1_2,
29306
+ SQRT2: Math.SQRT2,
29307
+ random: createSandboxClosure({ sandbox: true, call: () => random(), name: "random" })
29308
+ };
29309
+ for (const [name, method] of Object.entries(mathMethods)) {
29310
+ mathObject[name] = createSandboxClosure({
29311
+ sandbox: true,
29312
+ call: (args) => Reflect.apply(method, Math, args),
29313
+ name
29314
+ });
28966
29315
  }
28967
- return dump(result);
28968
- }
28969
- function serializeRunSnapshot(snapshot) {
28970
- return serializeSafeJSSnapshot(snapshot);
29316
+ return {
29317
+ Infinity: Infinity,
29318
+ Math: mathObject,
29319
+ NaN: Number.NaN
29320
+ };
28971
29321
  }
28972
- function hasSnapshot(value) {
28973
- return typeof value === "object" && value !== null && Object.prototype.hasOwnProperty.call(value, "snapshot");
29322
+ function createSeededRandom(seed) {
29323
+ let state = normalizeSeed(seed);
29324
+ return {
29325
+ next: () => {
29326
+ state = Math.imul(state, 1664525) + 1013904223 >>> 0;
29327
+ return state / 4294967296;
29328
+ },
29329
+ snapshot: () => state,
29330
+ restore: (nextState) => {
29331
+ state = normalizeSeed(nextState);
29332
+ }
29333
+ };
28974
29334
  }
28975
- function readDumpController(value) {
28976
- if (typeof value !== "object" || value === null) {
28977
- return void 0;
29335
+ function normalizeSeed(seed) {
29336
+ if (!Number.isFinite(seed)) {
29337
+ throw new TypeError("Seeded random requires a finite numeric seed.");
28978
29338
  }
28979
- return value[RUN_DUMP_CONTROLLER];
29339
+ return Math.trunc(seed) >>> 0;
28980
29340
  }
28981
29341
 
28982
- // packages/safe-js/src/error-codes.ts
28983
- function getOwnErrorCode(error) {
28984
- if (typeof error !== "object" || error === null || !Object.prototype.hasOwnProperty.call(error, "code")) {
28985
- return void 0;
29342
+ // packages/safe-js/src/random.ts
29343
+ function createReplayableRandom(options = {}) {
29344
+ const snapshot = options.snapshot;
29345
+ const saved = snapshot?.random;
29346
+ let initialState = options.seed;
29347
+ if (saved !== void 0) {
29348
+ const hasLoopState = typeof snapshot?.loopIterations === "object" && snapshot.loopIterations !== null && Object.keys(snapshot.loopIterations).length > 0;
29349
+ const replaysFromStart = snapshot?.replay !== void 0 || Array.isArray(snapshot?.pendingAwaits) && snapshot.pendingAwaits.length > 0 && !hasLoopState;
29350
+ initialState = replaysFromStart ? saved.initialState ?? saved.seed : saved.resumeState ?? saved.state;
28986
29351
  }
28987
- const code = error.code;
28988
- return typeof code === "string" ? code : void 0;
28989
- }
28990
- function hasOwnErrorCode(error, code) {
28991
- return getOwnErrorCode(error) === code;
29352
+ const generator = createSeededRandom(initialState ?? randomInt(4294967296));
29353
+ return { seed: saved?.seed ?? generator.snapshot(), ...generator };
28992
29354
  }
28993
29355
 
28994
- // packages/safe-js/src/snapshot/backend.ts
28995
- import { randomUUID as randomUUID2 } from "node:crypto";
28996
- import { readFile, rename, stat, unlink, writeFile } from "node:fs/promises";
28997
- import { dirname } from "node:path";
28998
- var DEFAULT_WRITE_MAX_ATTEMPTS = 3;
28999
- var DEFAULT_WRITE_RETRY_DELAY_MS = 100;
29000
- var LOCKED_FILE_ERROR_CODES = /* @__PURE__ */ new Set(["EACCES", "EBUSY", "EPERM"]);
29001
- var pendingOperations = /* @__PURE__ */ new Map();
29002
- var FileSnapshotBackend = class {
29003
- constructor(path, options = {}) {
29004
- this.path = path;
29005
- this.#writeMaxAttempts = options.writeMaxAttempts ?? DEFAULT_WRITE_MAX_ATTEMPTS;
29006
- this.#writeRetryDelayMs = options.writeRetryDelayMs ?? DEFAULT_WRITE_RETRY_DELAY_MS;
29007
- }
29008
- path;
29009
- #writeMaxAttempts;
29010
- #writeRetryDelayMs;
29011
- async read() {
29012
- try {
29013
- return JSON.parse(await readFile(this.path, "utf8"));
29014
- } catch (error) {
29015
- if (hasErrorCode(error, "ENOENT")) {
29016
- return void 0;
29017
- }
29018
- if (error instanceof SyntaxError) {
29019
- throw new Error(`Failed to parse snapshot at ${this.path}: ${error.message}`);
29020
- }
29021
- throw error;
29022
- }
29023
- }
29024
- async write(snapshot) {
29025
- await enqueueOperation(
29026
- this.path,
29027
- () => writeSnapshotAtomically(this.path, snapshot, {
29028
- maxAttempts: this.#writeMaxAttempts,
29029
- retryDelayMs: this.#writeRetryDelayMs
29030
- })
29031
- );
29032
- }
29033
- async remove() {
29034
- await enqueueOperation(this.path, async () => {
29035
- try {
29036
- await unlink(this.path);
29037
- } catch (error) {
29038
- if (!hasErrorCode(error, "ENOENT")) {
29039
- throw error;
29040
- }
29041
- }
29042
- });
29043
- }
29044
- };
29045
- async function writeSnapshotAtomically(snapshotPath, snapshot, options) {
29046
- const parentPath = dirname(snapshotPath);
29047
- const contents = serializeSafeJSSnapshot(snapshot);
29048
- await assertParentDirectoryExists(snapshotPath, parentPath);
29049
- for (let attempt = 1; attempt <= options.maxAttempts; attempt += 1) {
29050
- try {
29051
- const temporaryPath = `${snapshotPath}.${randomUUID2()}.tmp`;
29052
- await writeSnapshotOnce(temporaryPath, snapshotPath, contents);
29053
- return;
29054
- } catch (error) {
29055
- if (hasErrorCode(error, "EEXIST")) {
29056
- if (attempt === options.maxAttempts) {
29057
- throw new Error(
29058
- `Failed to write snapshot at ${snapshotPath} after ${options.maxAttempts} attempts: temporary path already exists`,
29059
- {
29060
- cause: error
29061
- }
29062
- );
29063
- }
29064
- continue;
29065
- }
29066
- if (!isLockedFileError(error)) {
29067
- throw error;
29068
- }
29069
- if (attempt === options.maxAttempts) {
29070
- throw new Error(
29071
- `Failed to write snapshot at ${snapshotPath} after ${options.maxAttempts} attempts: file is locked (${getOwnErrorCode(error)})`,
29072
- {
29073
- cause: error
29074
- }
29075
- );
29076
- }
29077
- await delay(options.retryDelayMs);
29078
- }
29079
- }
29080
- }
29081
- async function assertParentDirectoryExists(snapshotPath, parentPath) {
29082
- try {
29083
- const parent = await stat(parentPath);
29084
- if (!parent.isDirectory()) {
29085
- throw new Error(
29086
- `Cannot write snapshot at ${snapshotPath}: parent path ${parentPath} is not a directory`
29087
- );
29088
- }
29089
- } catch (error) {
29090
- if (hasErrorCode(error, "ENOENT")) {
29091
- throw new Error(
29092
- `Cannot write snapshot at ${snapshotPath}: parent directory ${parentPath} does not exist`,
29093
- {
29094
- cause: error
29095
- }
29096
- );
29097
- }
29098
- throw error;
29099
- }
29100
- }
29101
- async function writeSnapshotOnce(temporaryPath, snapshotPath, contents) {
29102
- let temporaryCreated = false;
29103
- let renamed = false;
29104
- try {
29105
- try {
29106
- await writeFile(temporaryPath, contents, { encoding: "utf8", flag: "wx" });
29107
- temporaryCreated = true;
29108
- } catch (error) {
29109
- if (!hasErrorCode(error, "EEXIST")) {
29110
- await removeTemporarySnapshot(temporaryPath).catch(() => void 0);
29111
- }
29112
- throw error;
29113
- }
29114
- await rename(temporaryPath, snapshotPath);
29115
- renamed = true;
29116
- } finally {
29117
- if (temporaryCreated && !renamed) {
29118
- await removeTemporarySnapshot(temporaryPath).catch(() => void 0);
29119
- }
29120
- }
29121
- }
29122
- async function enqueueOperation(path, operation) {
29123
- const previous = pendingOperations.get(path) ?? Promise.resolve();
29124
- const pending = previous.catch(() => void 0).then(operation);
29125
- const queued = pending.catch(() => void 0);
29126
- pendingOperations.set(path, queued);
29127
- try {
29128
- await pending;
29129
- } finally {
29130
- if (pendingOperations.get(path) === queued) {
29131
- pendingOperations.delete(path);
29132
- }
29133
- }
29134
- }
29135
- async function removeTemporarySnapshot(temporaryPath) {
29136
- try {
29137
- await unlink(temporaryPath);
29138
- } catch (error) {
29139
- if (!hasErrorCode(error, "ENOENT")) {
29140
- throw error;
29141
- }
29142
- }
29143
- }
29144
- async function delay(ms) {
29145
- if (ms === 0) {
29146
- return;
29147
- }
29148
- await new Promise((resolve) => setTimeout(resolve, ms));
29149
- }
29150
- function hasErrorCode(error, code) {
29151
- return hasOwnErrorCode(error, code);
29152
- }
29153
- function isLockedFileError(error) {
29154
- const code = getOwnErrorCode(error);
29155
- return code !== void 0 && LOCKED_FILE_ERROR_CODES.has(code);
29156
- }
29157
-
29158
- // packages/safe-js/src/run.ts
29356
+ // packages/safe-js/src/realm.ts
29159
29357
  import { AsyncLocalStorage as AsyncLocalStorage6 } from "node:async_hooks";
29160
-
29161
- // packages/safe-js/src/interp/resources.ts
29162
- import { AsyncLocalStorage as AsyncLocalStorage5 } from "node:async_hooks";
29163
- var runResources = new AsyncLocalStorage5();
29164
- async function withRunResources(signal, execute) {
29165
- const controller = new AbortController();
29166
- const cancel = () => controller.abort(signal?.reason);
29167
- const cleanups = /* @__PURE__ */ new Set();
29168
- const resources = {
29169
- signal: controller.signal,
29170
- add(close) {
29171
- cleanups.add(close);
29172
- }
29173
- };
29174
- signal?.addEventListener("abort", cancel, { once: true });
29175
- if (signal?.aborted) cancel();
29176
- let result;
29177
- let failure;
29178
- let errors = [];
29179
- try {
29180
- result = await runResources.run(resources, execute);
29181
- } catch (error) {
29182
- failure = { reason: error };
29183
- } finally {
29184
- signal?.removeEventListener("abort", cancel);
29185
- controller.abort(new Error("SafeJS run finished."));
29186
- const outcomes = await Promise.allSettled(
29187
- [...cleanups].map((close) => Promise.resolve().then(close))
29188
- );
29189
- errors = outcomes.flatMap((outcome) => outcome.status === "rejected" ? [outcome.reason] : []);
29190
- }
29191
- if (failure !== void 0) throw failure.reason;
29192
- if (errors.length > 0) throw new AggregateError(errors, "SafeJS resource cleanup failed.");
29193
- return result;
29194
- }
29358
+ import { types as types4 } from "node:util";
29195
29359
 
29196
29360
  // packages/safe-js/src/interp/globals/console-json.ts
29197
29361
  function createConsoleJsonGlobals(options) {
@@ -29305,7 +29469,9 @@ function toJsonParseText(input) {
29305
29469
  }
29306
29470
  async function stringifyProperty(key, holder, state, indent = "") {
29307
29471
  let value = getOwnDataValue(holder, key);
29308
- if (isStringifyContainer(value)) {
29472
+ if (isSandboxDate(value)) {
29473
+ value = dateMethods.get("toJSON").invoke(value, []);
29474
+ } else if (isStringifyContainer(value)) {
29309
29475
  const toJSON = getOwnDataValue(value, "toJSON");
29310
29476
  if (isSandboxClosure(toJSON)) {
29311
29477
  value = await callStringifyClosure(toJSON, [key], value, state);
@@ -29617,6 +29783,7 @@ async function stringifyObject2(value, budget, context, joining) {
29617
29783
  }
29618
29784
  }
29619
29785
  async function defaultToString(value, budget, context, joining) {
29786
+ if (isSandboxDate(value)) return budget.allocateString(dateString(value));
29620
29787
  if (Array.isArray(value) || isFloat32Array(value)) {
29621
29788
  if (Object.hasOwn(value, "join")) {
29622
29789
  const join = ownDataValue(value, "join");
@@ -29720,6 +29887,7 @@ function createObjectArrayGlobals(options) {
29720
29887
  getPrototypeOf: createSandboxClosure({
29721
29888
  sandbox: true,
29722
29889
  call: ([value]) => {
29890
+ if (isSandboxDate(value)) return getDatePrototype(value, options.budget, options.compileOwner);
29723
29891
  objectProperties(value);
29724
29892
  return getSandboxPrototype(value);
29725
29893
  },
@@ -29844,7 +30012,7 @@ function createObjectArrayGlobals(options) {
29844
30012
  }),
29845
30013
  Number: createSandboxClosure({
29846
30014
  sandbox: true,
29847
- call: ([value]) => Number(value),
30015
+ call: ([value]) => isSandboxDate(value) ? dateTime(value) : Number(value),
29848
30016
  name: "Number",
29849
30017
  properties: {
29850
30018
  isFinite: createSandboxClosure({
@@ -29886,295 +30054,1465 @@ function createObjectArrayGlobals(options) {
29886
30054
  NEGATIVE_INFINITY: Number.NEGATIVE_INFINITY,
29887
30055
  POSITIVE_INFINITY: Number.POSITIVE_INFINITY
29888
30056
  }
29889
- }),
29890
- Boolean: createSandboxClosure({
29891
- sandbox: true,
29892
- call: ([value]) => Boolean(value),
29893
- name: "Boolean"
29894
- })
29895
- };
29896
- }
29897
- async function objectFromSandboxEntries(iterator, budget) {
29898
- const object = /* @__PURE__ */ Object.create(null);
29899
- try {
29900
- while (true) {
29901
- const result = await iterator.next();
29902
- if (typeof result !== "object" && typeof result !== "function" || result === null) {
29903
- throw new TypeError("Iterator result must be an object.");
30057
+ }),
30058
+ Boolean: createSandboxClosure({
30059
+ sandbox: true,
30060
+ call: ([value]) => Boolean(value),
30061
+ name: "Boolean"
30062
+ })
30063
+ };
30064
+ }
30065
+ async function objectFromSandboxEntries(iterator, budget) {
30066
+ const object = /* @__PURE__ */ Object.create(null);
30067
+ try {
30068
+ while (true) {
30069
+ const result = await iterator.next();
30070
+ if (typeof result !== "object" && typeof result !== "function" || result === null) {
30071
+ throw new TypeError("Iterator result must be an object.");
30072
+ }
30073
+ if (result.done) break;
30074
+ const entry = result.value;
30075
+ if (typeof entry !== "object" && typeof entry !== "function" || entry === null) {
30076
+ throw new TypeError("Object.fromEntries requires entry objects.");
30077
+ }
30078
+ const key = entry[0];
30079
+ const value = entry[1];
30080
+ Object.defineProperty(object, key, {
30081
+ configurable: true,
30082
+ enumerable: true,
30083
+ value,
30084
+ writable: true
30085
+ });
30086
+ }
30087
+ } catch (error) {
30088
+ try {
30089
+ await iterator.return?.();
30090
+ } catch {
30091
+ throw error;
30092
+ }
30093
+ throw error;
30094
+ }
30095
+ return allocateProducedSandboxValue(object, budget);
30096
+ }
30097
+ function assignSandboxValues(target, sources, budget) {
30098
+ if (target === null || target === void 0) {
30099
+ throw new TypeError("Object.assign(target, ...sources) requires a non-null target.");
30100
+ }
30101
+ if (!isGuestClosure(target) && !isAssignableSandboxTarget(target)) {
30102
+ throw new TypeError("Object.assign(target, ...sources) requires an object or array target.");
30103
+ }
30104
+ for (const source of sources) {
30105
+ if (source === null || source === void 0) {
30106
+ continue;
30107
+ }
30108
+ for (const [key, value] of ownEnumerableSandboxEntries(source)) {
30109
+ setSandboxProperty(target, key, value, budget);
30110
+ }
30111
+ }
30112
+ return target;
30113
+ }
30114
+ function objectProperties(value, mutable = false) {
30115
+ if (isSandboxDate(value)) {
30116
+ if (mutable) throw new TypeError("Date own properties and prototypes are not supported.");
30117
+ return value;
30118
+ }
30119
+ if (isGuestHostObject(value)) throw new TypeError("Live host object descriptors are not supported.");
30120
+ if (isGuestClosure(value)) return materializeFunctionProperties(value);
30121
+ if (isSandboxClosure(value)) {
30122
+ if (mutable) throw new TypeError("Host function properties are read only.");
30123
+ return value.properties ?? /* @__PURE__ */ Object.create(null);
30124
+ }
30125
+ if (!isAssignableSandboxTarget(value)) throw new TypeError("Expected a sandbox object or function.");
30126
+ return value;
30127
+ }
30128
+ function dataDescriptor(input) {
30129
+ const source = objectProperties(input);
30130
+ const descriptor = {};
30131
+ for (const field of ["get", "set", "value", "writable", "enumerable", "configurable"]) {
30132
+ const entry = Object.getOwnPropertyDescriptor(source, field);
30133
+ if (entry === void 0) continue;
30134
+ if (!("value" in entry) || field === "get" || field === "set") {
30135
+ throw new TypeError("Only data property descriptors are supported.");
30136
+ }
30137
+ if (field === "value") descriptor.value = entry.value;
30138
+ else descriptor[field] = Boolean(entry.value);
30139
+ }
30140
+ return descriptor;
30141
+ }
30142
+ function defineDataProperty2(target, key, descriptor, budget) {
30143
+ budget.visitNode();
30144
+ if (isFloat32Array(target)) throw new TypeError("Typed array property descriptors are not supported.");
30145
+ const properties = objectProperties(target, true);
30146
+ if (Array.isArray(properties)) {
30147
+ if (key === "length" && "value" in descriptor) budget.allocateArrayLength(Number(descriptor.value));
30148
+ else {
30149
+ const index = Number(key);
30150
+ if (Number.isInteger(index) && index >= 0 && index < 4294967295 && String(index) === key) {
30151
+ budget.allocateArrayLength(index + 1);
30152
+ }
30153
+ }
30154
+ }
30155
+ Object.defineProperty(properties, key, descriptor);
30156
+ markDescriptorObject(properties);
30157
+ }
30158
+ function isAssignableSandboxTarget(value) {
30159
+ return typeof value === "object" && value !== null && !isSandboxClosure(value) && !isSandboxGenerator(value) && !isSandboxMap(value) && !isSandboxSet(value) && !isSandboxPromise(value) && !isSandboxRegex(value);
30160
+ }
30161
+ async function arrayFromSandboxValues(args, budget) {
30162
+ const [items, mapFn, thisValue] = args;
30163
+ const iterator = getSandboxIterator(items);
30164
+ const values = iterator === void 0 ? Reflect.apply(Array.from, Array, [items]) : await collectIteratorValues(iterator);
30165
+ if (mapFn === void 0 || !isSandboxClosure(mapFn)) {
30166
+ if (mapFn !== void 0) {
30167
+ throw new TypeError("Array.from mapping callback must be a function.");
30168
+ }
30169
+ return budgetSandboxValue2(values, budget);
30170
+ }
30171
+ const mappedValues = [];
30172
+ for (const [index, value] of values.entries()) {
30173
+ const result = await mapFn.call([value, index], { stack: [], thisValue });
30174
+ if (isSandboxPromise(result) && result.synchronousPrefix !== void 0) {
30175
+ await result.synchronousPrefix;
30176
+ }
30177
+ mappedValues.push(result);
30178
+ }
30179
+ return budgetSandboxValue2(mappedValues, budget);
30180
+ }
30181
+ function createArrayFromConstructorArgs(args, budget) {
30182
+ if (args.length !== 1) {
30183
+ return budgetSandboxValue2(Reflect.apply(Array, Array, [...args]), budget);
30184
+ }
30185
+ const [lengthOrValue] = args;
30186
+ if (typeof lengthOrValue !== "number") {
30187
+ return budgetSandboxValue2([lengthOrValue], budget);
30188
+ }
30189
+ if (!Number.isInteger(lengthOrValue) || lengthOrValue < 0 || lengthOrValue > 4294967295) {
30190
+ throw new RangeError("Invalid array length.");
30191
+ }
30192
+ budget.allocateArrayLength(lengthOrValue);
30193
+ return new Array(lengthOrValue);
30194
+ }
30195
+ async function collectIteratorValues(iterator) {
30196
+ const values = [];
30197
+ while (true) {
30198
+ const result = await iterator.next();
30199
+ if (result.done) return values;
30200
+ values.push(result.value);
30201
+ }
30202
+ }
30203
+ function getOwnEnumerableKeys(value) {
30204
+ if (isGuestHostObject(value)) return getHostObjectKeys(value);
30205
+ return ownEnumerableSandboxEntries(value).map(([key]) => key);
30206
+ }
30207
+ function getOwnEnumerableValues(value) {
30208
+ return ownEnumerableSandboxEntries(value).map(([, entryValue]) => entryValue);
30209
+ }
30210
+ function budgetSandboxValue2(value, budget) {
30211
+ const sandboxValue = deepCopyToSandbox(value);
30212
+ return allocateProducedSandboxValue(sandboxValue, budget);
30213
+ }
30214
+ function stringRaw(args, budget) {
30215
+ const [template, ...substitutions] = args;
30216
+ const raw = getTemplateRawParts(template);
30217
+ let result = "";
30218
+ for (let index = 0; index < raw.length; index += 1) {
30219
+ result += String(raw[index]);
30220
+ if (index < raw.length - 1 && index < substitutions.length) {
30221
+ result += String(substitutions[index]);
30222
+ }
30223
+ }
30224
+ return budget.allocateString(result);
30225
+ }
30226
+ function getTemplateRawParts(template) {
30227
+ const raw = typeof template === "object" && template !== null ? template.raw : void 0;
30228
+ if (typeof template !== "object" || template === null || isSandboxClosure(template) || isSandboxPromise(template) || !Array.isArray(raw)) {
30229
+ throw new TypeError("String.raw requires a raw strings array.");
30230
+ }
30231
+ return raw;
30232
+ }
30233
+
30234
+ // packages/safe-js/src/interp/globals.ts
30235
+ function createBuiltinBindings(options) {
30236
+ return {
30237
+ ...createConsoleJsonGlobals(options),
30238
+ ...createCollectionGlobals(options),
30239
+ Float32Array: createFloat32ArrayGlobal(options.budget),
30240
+ Date: createDateGlobal(options),
30241
+ ...createErrorGlobals(options),
30242
+ ...createMathGlobals({ random: options.random }),
30243
+ ...createObjectArrayGlobals(options),
30244
+ ...createMiscGlobals(options),
30245
+ ...createPromiseGlobals(options),
30246
+ ...createRegexGlobals(options.compileOwner)
30247
+ };
30248
+ }
30249
+
30250
+ // packages/safe-js/src/interp/resources.ts
30251
+ import { AsyncLocalStorage as AsyncLocalStorage5 } from "node:async_hooks";
30252
+ var runResources = new AsyncLocalStorage5();
30253
+ async function withRunResources(signal, execute) {
30254
+ const controller = new AbortController();
30255
+ const cancel = () => controller.abort(signal?.reason);
30256
+ const cleanups = /* @__PURE__ */ new Set();
30257
+ const resources = {
30258
+ signal: controller.signal,
30259
+ add(close) {
30260
+ cleanups.add(close);
30261
+ }
30262
+ };
30263
+ signal?.addEventListener("abort", cancel, { once: true });
30264
+ if (signal?.aborted) cancel();
30265
+ let result;
30266
+ let failure;
30267
+ let errors = [];
30268
+ try {
30269
+ result = await runResources.run(resources, execute);
30270
+ } catch (error) {
30271
+ failure = { reason: error };
30272
+ } finally {
30273
+ signal?.removeEventListener("abort", cancel);
30274
+ controller.abort(new Error("SafeJS run finished."));
30275
+ const outcomes = await Promise.allSettled(
30276
+ [...cleanups].map((close) => Promise.resolve().then(close))
30277
+ );
30278
+ errors = outcomes.flatMap((outcome) => outcome.status === "rejected" ? [outcome.reason] : []);
30279
+ }
30280
+ if (failure !== void 0) throw failure.reason;
30281
+ if (errors.length > 0) throw new AggregateError(errors, "SafeJS resource cleanup failed.");
30282
+ return result;
30283
+ }
30284
+
30285
+ // packages/safe-js/src/modules/registry.ts
30286
+ function createUnknownModuleMessage2(moduleName, moduleNames) {
30287
+ if (moduleNames.length === 0) {
30288
+ return `Unknown module '${moduleName}'. No modules are registered.`;
30289
+ }
30290
+ return `Unknown module '${moduleName}'. Available modules: ${moduleNames.join(", ")}.`;
30291
+ }
30292
+ function createUnknownExportMessage2(moduleName, exportName, availableExports) {
30293
+ if (availableExports.length === 0) {
30294
+ return `Module '${moduleName}' does not export '${exportName}'. The module exports nothing.`;
30295
+ }
30296
+ return `Module '${moduleName}' does not export '${exportName}'. Available exports: ${availableExports.join(", ")}.`;
30297
+ }
30298
+ function resolveModuleImports(module, modules, options) {
30299
+ const registry = normalizeModuleRegistry(modules);
30300
+ const bindings = createBindingRecord();
30301
+ const wrappedModules = options.wrappedModules ?? /* @__PURE__ */ new Map();
30302
+ for (const statement of module.body) {
30303
+ if (statement.type !== "ImportDeclaration") {
30304
+ continue;
30305
+ }
30306
+ bindImportDeclaration(statement, registry, wrappedModules, bindings, options);
30307
+ }
30308
+ return bindings;
30309
+ }
30310
+ function bindImportDeclaration(declaration, registry, wrappedModules, bindings, options) {
30311
+ const moduleName = declaration.source.value;
30312
+ const moduleExports = registry.get(moduleName);
30313
+ if (moduleExports === void 0) {
30314
+ if (options.allowMissing) return;
30315
+ throw createModuleImportError(
30316
+ createUnknownModuleMessage2(moduleName, [...registry.keys()]),
30317
+ declaration.source.span
30318
+ );
30319
+ }
30320
+ const wrappedExports = wrappedModules.get(moduleName) ?? createBindingRecord(
30321
+ wrapCancelableBindings(
30322
+ wrapCallerInjectedBindings(Object.fromEntries(moduleExports), {
30323
+ realm: options.realm,
30324
+ budget: options.budget,
30325
+ compileOwner: options.compileOwner,
30326
+ hostCalls: options.hostCalls,
30327
+ moduleId: moduleName,
30328
+ signal: options.signal
30329
+ }),
30330
+ options.signal
30331
+ )
30332
+ );
30333
+ wrappedModules.set(moduleName, wrappedExports);
30334
+ for (const specifier of declaration.specifiers) {
30335
+ const localName = specifier.local.name;
30336
+ if (Object.hasOwn(bindings, localName)) {
30337
+ throw createModuleImportError(
30338
+ `Cannot redeclare imported binding '${localName}'.`,
30339
+ specifier.local.span
30340
+ );
30341
+ }
30342
+ if (options.allowMissing && specifier.type !== "ImportNamespaceSpecifier") {
30343
+ const exportName = specifier.type === "ImportDefaultSpecifier" ? "default" : specifier.imported.name;
30344
+ if (!Object.hasOwn(wrappedExports, exportName)) continue;
30345
+ }
30346
+ bindings[localName] = resolveImportSpecifier(moduleName, specifier, wrappedExports);
30347
+ }
30348
+ }
30349
+ function resolveImportSpecifier(moduleName, specifier, wrappedExports) {
30350
+ if (specifier.type === "ImportNamespaceSpecifier") {
30351
+ return wrappedExports;
30352
+ }
30353
+ const exportName = specifier.type === "ImportDefaultSpecifier" ? "default" : specifier.imported.name;
30354
+ const exportedValue = wrappedExports[exportName];
30355
+ if (exportedValue !== void 0 || Object.hasOwn(wrappedExports, exportName)) {
30356
+ return exportedValue;
30357
+ }
30358
+ throw createModuleImportError(
30359
+ createUnknownExportMessage2(moduleName, exportName, Object.keys(wrappedExports).sort()),
30360
+ specifier.span
30361
+ );
30362
+ }
30363
+ function createModuleImportError(message, span) {
30364
+ const error = new Error(message);
30365
+ attachErrorSpan(error, span);
30366
+ return error;
30367
+ }
30368
+ function normalizeModuleRegistry(modules) {
30369
+ if (modules === void 0) {
30370
+ return /* @__PURE__ */ new Map();
30371
+ }
30372
+ const entries = modules instanceof Map ? [...modules.entries()] : Object.entries(modules);
30373
+ const registry = new Map(
30374
+ entries.map(
30375
+ ([moduleName, moduleExports]) => [moduleName, normalizeModuleExports(moduleExports)]
30376
+ ).sort(([left], [right]) => left.localeCompare(right))
30377
+ );
30378
+ registerModuleHostOperationPolicies(registry);
30379
+ return registry;
30380
+ }
30381
+ function registerModuleHostOperationPolicies(registry) {
30382
+ for (const [moduleId, moduleExports] of registry) {
30383
+ for (const [operation, value] of moduleExports) {
30384
+ if (typeof value !== "function") {
30385
+ continue;
30386
+ }
30387
+ const policy = readHostOperationPolicy(value);
30388
+ if (policy !== void 0) {
30389
+ registerPendingHostCallPolicy({ moduleId, operation, policy });
30390
+ }
30391
+ }
30392
+ }
30393
+ }
30394
+ function normalizeModuleExports(moduleExports) {
30395
+ const entries = moduleExports instanceof Map ? [...moduleExports.entries()] : Object.entries(moduleExports);
30396
+ return new Map(
30397
+ entries.filter(([exportName]) => exportName.length > 0).sort(([left], [right]) => left.localeCompare(right))
30398
+ );
30399
+ }
30400
+ function createBindingRecord(entries) {
30401
+ return Object.assign(/* @__PURE__ */ Object.create(null), entries);
30402
+ }
30403
+
30404
+ // packages/safe-js/src/realm.ts
30405
+ var RealmState = class {
30406
+ constructor(options) {
30407
+ this.options = options;
30408
+ const limitInput = readDataRecord(options.limits ?? {}, "Realm limits");
30409
+ this.limits = {
30410
+ extensions: 32,
30411
+ hostObjects: 1024,
30412
+ callbacks: 1024,
30413
+ guestReferences: 1024,
30414
+ cleanups: 1024,
30415
+ nestedEvaluations: 16
30416
+ };
30417
+ for (const [name, value] of Object.entries(limitInput)) {
30418
+ if (!Object.hasOwn(this.limits, name) || !Number.isSafeInteger(value) || Number(value) < 1)
30419
+ throw new TypeError("Realm limits must be positive safe integers with supported names.");
30420
+ this.limits[name] = Number(value);
30421
+ }
30422
+ if (options.extensions !== void 0 && (!Array.isArray(options.extensions) || types4.isProxy(options.extensions)))
30423
+ throw new TypeError("Extensions must be a registration array.");
30424
+ const registrations = options.extensions ?? [];
30425
+ const extensions = [];
30426
+ if (registrations.length > this.limits.extensions)
30427
+ throw new RangeError("Realm extension limit exceeded.");
30428
+ for (let index = 0; index < registrations.length; index++) {
30429
+ const descriptor = Object.getOwnPropertyDescriptor(registrations, String(index));
30430
+ if (descriptor === void 0 || !("value" in descriptor))
30431
+ throw new TypeError("Extension registrations require data properties, not accessors.");
30432
+ extensions.push(descriptor.value);
30433
+ }
30434
+ if (Reflect.ownKeys(registrations).length !== extensions.length + 1)
30435
+ throw new TypeError("Extension registrations have unsupported fields.");
30436
+ this.extensions = Object.freeze(extensions);
30437
+ if (this.extensions.length > this.limits.extensions)
30438
+ throw new RangeError("Realm extension limit exceeded.");
30439
+ this.globals = readDataRecord(options.bindings ?? {}, "Realm bindings");
30440
+ this.modules = readModules(options.modules);
30441
+ const grants = new Set(readStringList(options.grants ?? [], "Realm grants"));
30442
+ for (const extension of this.extensions) getExtensionSetup(extension);
30443
+ this.budget = options.budget ?? new Budget({ maxCallDepth: 1e3 });
30444
+ this.lease = this.budget.acquireCompileOwner(true);
30445
+ this.compilation = new CompileScope(this.lease.owner);
30446
+ this.bridge = {
30447
+ owner: this,
30448
+ assertActive: this.assertOpen,
30449
+ wrapCallback: this.wrapCallback,
30450
+ captureArguments: this.captureArguments,
30451
+ invoke: this.invokeHost,
30452
+ awaitResult: (operation) => this.nestedOperations.has(operation)
30453
+ };
30454
+ try {
30455
+ this.builtinBindings = createBuiltinBindings({
30456
+ budget: this.budget,
30457
+ compileOwner: this.lease.owner,
30458
+ sink: options.sink,
30459
+ clock: options.clock,
30460
+ random: createReplayableRandom({ seed: options.randomSeed }).next
30461
+ });
30462
+ const names = /* @__PURE__ */ new Set();
30463
+ const globals = /* @__PURE__ */ new Set([...Object.keys(this.builtinBindings), ...Object.keys(this.globals)]);
30464
+ const modules = new Map(
30465
+ Object.entries(this.modules).map(([name, exports]) => [name, new Set(Object.keys(exports))])
30466
+ );
30467
+ for (const extension of this.extensions) {
30468
+ const manifest = extension.manifest;
30469
+ if (names.has(manifest.name))
30470
+ throw new TypeError(`Duplicate extension '${manifest.name}'.`);
30471
+ names.add(manifest.name);
30472
+ for (const capability of manifest.capabilities ?? []) {
30473
+ if (!grants.has(capability))
30474
+ throw new TypeError(`Missing grant '${capability}' for extension '${manifest.name}'.`);
30475
+ }
30476
+ for (const name of manifest.globals ?? []) {
30477
+ if (globals.has(name)) throw new TypeError(`Conflicting global '${name}'.`);
30478
+ globals.add(name);
30479
+ }
30480
+ for (const [name, exports] of Object.entries(manifest.modules ?? {})) {
30481
+ const occupied = modules.get(name) ?? /* @__PURE__ */ new Set();
30482
+ for (const key of exports) {
30483
+ if (occupied.has(key)) throw new TypeError(`Conflicting export '${name}.${key}'.`);
30484
+ occupied.add(key);
30485
+ }
30486
+ modules.set(name, occupied);
30487
+ }
30488
+ }
30489
+ options.signal?.addEventListener("abort", this.abort, { once: true });
30490
+ if (options.signal?.aborted) this.abort();
30491
+ this.budget.setRetainedValues(this, this.retainedRoots);
30492
+ this.tracker.onFatalRejection((error) => this.poison(error));
30493
+ } catch (error) {
30494
+ this.compilation.dispose();
30495
+ this.lease.release();
30496
+ throw error;
30497
+ }
30498
+ }
30499
+ options;
30500
+ budget;
30501
+ lease;
30502
+ compilation;
30503
+ controller = new AbortController();
30504
+ phase = new AsyncLocalStorage6();
30505
+ queue = new SandboxJobQueue();
30506
+ tracker = createSandboxPromiseRejectionTracker();
30507
+ bridge;
30508
+ limits;
30509
+ extensions;
30510
+ cleanups = [];
30511
+ callbacks = /* @__PURE__ */ new Map();
30512
+ pendingCallbacks = /* @__PURE__ */ new Set();
30513
+ callbackCache = /* @__PURE__ */ new WeakMap();
30514
+ hostObjects = /* @__PURE__ */ new Set();
30515
+ guestReferences = /* @__PURE__ */ new Map();
30516
+ retainedOperations = /* @__PURE__ */ new WeakMap();
30517
+ nestedOperations = /* @__PURE__ */ new WeakMap();
30518
+ convertedModules = /* @__PURE__ */ new Map();
30519
+ nativeConversions = { seen: /* @__PURE__ */ new WeakMap() };
30520
+ modules;
30521
+ globals;
30522
+ builtinBindings;
30523
+ scope;
30524
+ active;
30525
+ disposal;
30526
+ closed = false;
30527
+ initialized = false;
30528
+ nestedDepth = 0;
30529
+ failure;
30530
+ bridgeOptions = () => ({
30531
+ budget: this.budget,
30532
+ compileOwner: this.lease.owner,
30533
+ signal: this.controller.signal,
30534
+ realm: this.bridge
30535
+ });
30536
+ retainedRoots = () => [
30537
+ ...this.callbacks.values(),
30538
+ ...Array.from(this.pendingCallbacks, (pending) => pending.closure),
30539
+ ...this.guestReferences.values()
30540
+ ];
30541
+ captureArguments = (operation, args, copy) => {
30542
+ const from = this.retainedOperations.get(operation)?.from ?? args.length;
30543
+ const values = copy(args.slice(0, from));
30544
+ const captured = [];
30545
+ const rollback = () => {
30546
+ for (const reference of captured) {
30547
+ revokeGuestReference(reference, this);
30548
+ this.guestReferences.delete(reference);
30549
+ }
30550
+ };
30551
+ try {
30552
+ for (const value of args.slice(from)) {
30553
+ this.checkCollection(
30554
+ this.guestReferences.size + 1,
30555
+ this.limits.guestReferences,
30556
+ "guest reference"
30557
+ );
30558
+ const root = [value];
30559
+ const reference = createGuestReference(root, this, this.assertOpen);
30560
+ this.guestReferences.set(reference, root);
30561
+ captured.push(reference);
30562
+ values.push(reference);
30563
+ }
30564
+ if (captured.length > 0)
30565
+ this.budget.reconcileDataUsage(
30566
+ measureSandboxData([...this.scope?.retainedValues() ?? [], ...this.retainedRoots()])
30567
+ );
30568
+ return { args: values, rollback };
30569
+ } catch (error) {
30570
+ rollback();
30571
+ if (error instanceof SandboxError) this.poison(error);
30572
+ throw error;
30573
+ }
30574
+ };
30575
+ releaseGuestReference = (reference) => {
30576
+ readGuestReference(reference, this);
30577
+ revokeGuestReference(reference, this);
30578
+ this.guestReferences.delete(reference);
30579
+ if (this.active === void 0)
30580
+ reconcileCompiledValues(
30581
+ this.budget,
30582
+ [...this.scope?.retainedValues() ?? [], ...this.retainedRoots()],
30583
+ this.compilation
30584
+ );
30585
+ };
30586
+ assertOpen = () => {
30587
+ if (this.failure !== void 0) throw this.failure.reason;
30588
+ if (this.closed) throw new Error("SafeJS realm is closed; capabilities are revoked.");
30589
+ this.controller.signal.throwIfAborted();
30590
+ };
30591
+ abort = () => {
30592
+ this.poison(this.options.signal?.reason ?? new SandboxError("aborted"));
30593
+ void this.close().catch(() => void 0);
30594
+ };
30595
+ poison(reason) {
30596
+ this.failure ??= { reason };
30597
+ this.controller.abort(reason);
30598
+ if (this.active === void 0)
30599
+ queueMicrotask(() => {
30600
+ void this.dispose().catch(() => void 0);
30601
+ });
30602
+ }
30603
+ chargeWork = (units = 1) => {
30604
+ this.assertOpen();
30605
+ if (!Number.isSafeInteger(units) || units < 0)
30606
+ throw new TypeError("Work charges must be non-negative safe integers.");
30607
+ try {
30608
+ for (let index = 0; index < units; index++) this.budget.visitNode();
30609
+ } catch (error) {
30610
+ this.poison(error);
30611
+ throw error;
30612
+ }
30613
+ };
30614
+ onCleanup = (cleanup) => {
30615
+ this.assertOpen();
30616
+ if (typeof cleanup !== "function") throw new TypeError("Cleanup must be a function.");
30617
+ this.checkCollection(this.cleanups.length + 1, this.limits.cleanups, "cleanup");
30618
+ this.cleanups.push(cleanup);
30619
+ };
30620
+ checkCollection(count, limit, name) {
30621
+ this.assertOpen();
30622
+ try {
30623
+ this.budget.allocateCollectionEntries(count);
30624
+ } catch (error) {
30625
+ this.poison(error);
30626
+ throw error;
30627
+ }
30628
+ if (count > limit) throw new RangeError(`Realm ${name} limit exceeded.`);
30629
+ }
30630
+ invokeHost = (operation, call) => {
30631
+ this.assertOpen();
30632
+ const phase = {
30633
+ active: true,
30634
+ extension: this.nestedOperations.get(operation),
30635
+ evaluating: false,
30636
+ pending: /* @__PURE__ */ new Set()
30637
+ };
30638
+ return this.phase.run(phase, () => {
30639
+ try {
30640
+ const result = call();
30641
+ if (types4.isPromise(result) || phase.pending.size > 0 || phase.failure !== void 0) {
30642
+ return Promise.resolve(result).then(
30643
+ async (value) => {
30644
+ await Promise.allSettled(phase.pending);
30645
+ if (phase.failure !== void 0) throw phase.failure.reason;
30646
+ this.assertOpen();
30647
+ return value;
30648
+ },
30649
+ async (error) => {
30650
+ if (error instanceof SandboxError || phase.pending.size > 0) this.poison(error);
30651
+ await Promise.allSettled(phase.pending);
30652
+ throw error;
30653
+ }
30654
+ ).finally(() => {
30655
+ phase.active = false;
30656
+ });
30657
+ }
30658
+ this.assertOpen();
30659
+ phase.active = false;
30660
+ return result;
30661
+ } catch (error) {
30662
+ phase.active = false;
30663
+ if (error instanceof SandboxError) this.poison(error);
30664
+ if (phase.pending.size > 0) {
30665
+ this.poison(error);
30666
+ return Promise.allSettled(phase.pending).then(() => {
30667
+ throw error;
30668
+ });
30669
+ }
30670
+ throw error;
30671
+ }
30672
+ });
30673
+ };
30674
+ importValue(value) {
30675
+ return copyHostValueToSandbox(
30676
+ value,
30677
+ [],
30678
+ this.bridgeOptions(),
30679
+ { seen: /* @__PURE__ */ new WeakMap() },
30680
+ "<realm>"
30681
+ );
30682
+ }
30683
+ exportValue(value) {
30684
+ return deepCopyFromSandbox(value, {
30685
+ compilation: this.compilation,
30686
+ wrapClosure: this.wrapCallback,
30687
+ unwrapHostObject: (object) => exportHostCapability(object, this)
30688
+ });
30689
+ }
30690
+ createHostObject = (definition) => {
30691
+ this.checkCollection(this.hostObjects.size + 1, this.limits.hostObjects, "host object");
30692
+ const object = createLiveHostObject(definition, {
30693
+ owner: this,
30694
+ assertActive: this.assertOpen,
30695
+ chargeWork: this.chargeWork,
30696
+ read: (operation) => {
30697
+ const value = this.invokeHost(operation, operation);
30698
+ if (types4.isPromise(value)) {
30699
+ void Promise.resolve(value).catch(() => void 0);
30700
+ throw new TypeError("Live property getters must be synchronous.");
30701
+ }
30702
+ return this.importValue(value);
30703
+ },
30704
+ write: (operation, value) => {
30705
+ const result = this.invokeHost(operation, () => operation(this.exportValue(value)));
30706
+ if (types4.isPromise(result)) {
30707
+ void Promise.resolve(result).catch(() => void 0);
30708
+ throw new TypeError("Live property setters must be synchronous.");
30709
+ }
30710
+ },
30711
+ method: (operation) => {
30712
+ const value = copyHostValueToSandbox(
30713
+ operation,
30714
+ [],
30715
+ this.bridgeOptions(),
30716
+ this.nativeConversions,
30717
+ "<host-method>"
30718
+ );
30719
+ if (!isSandboxClosure(value)) throw new TypeError("Invalid host method.");
30720
+ return value;
30721
+ }
30722
+ });
30723
+ this.hostObjects.add(object);
30724
+ try {
30725
+ this.budget.chargeDataUsage(1);
30726
+ } catch (error) {
30727
+ this.poison(error);
30728
+ throw error;
30729
+ }
30730
+ return object;
30731
+ };
30732
+ wrapCallback = (closure) => {
30733
+ this.assertOpen();
30734
+ const existing = this.callbackCache.get(closure);
30735
+ if (existing !== void 0 && this.callbacks.has(existing)) return existing;
30736
+ this.checkCollection(this.callbacks.size + 1, this.limits.callbacks, "callback");
30737
+ const invokeCallback = this.invokeCallback;
30738
+ const callback = function(...args) {
30739
+ return invokeCallback(callback, { args, thisValue: this });
30740
+ };
30741
+ this.callbacks.set(callback, closure);
30742
+ this.callbackCache.set(closure, callback);
30743
+ registerGuestCallback(callback, {
30744
+ owner: this,
30745
+ closure,
30746
+ assertActive: () => {
30747
+ this.assertOpen();
30748
+ if (!this.callbacks.has(callback)) throw new TypeError("Guest callback is revoked.");
30749
+ }
30750
+ });
30751
+ try {
30752
+ this.budget.reconcileDataUsage(
30753
+ measureSandboxData([...this.scope?.retainedValues() ?? [], ...this.retainedRoots()])
30754
+ );
30755
+ } catch (error) {
30756
+ this.poison(error);
30757
+ throw error;
30758
+ }
30759
+ return callback;
30760
+ };
30761
+ releaseCallback = (callback) => {
30762
+ readGuestCallback(callback, this);
30763
+ revokeGuestCallback(callback, this);
30764
+ this.callbacks.delete(callback);
30765
+ if (this.active === void 0)
30766
+ reconcileCompiledValues(
30767
+ this.budget,
30768
+ [...this.scope?.retainedValues() ?? [], ...this.retainedRoots()],
30769
+ this.compilation
30770
+ );
30771
+ };
30772
+ invokeCallback = async (callback, options = {}) => {
30773
+ if (this.closed || this.failure !== void 0) await this.dispose();
30774
+ this.assertOpen();
30775
+ const closure = readGuestCallback(callback, this);
30776
+ this.checkCollection(this.pendingCallbacks.size + 1, this.limits.callbacks, "pending callback");
30777
+ const record2 = { closure };
30778
+ this.pendingCallbacks.add(record2);
30779
+ const invoke = async () => {
30780
+ this.assertOpen();
30781
+ readGuestCallback(callback, this);
30782
+ const leave = enterRunningState(closure);
30783
+ const leaveCall = this.budget.enterCall();
30784
+ try {
30785
+ const values = this.importValue([
30786
+ options.thisValue,
30787
+ [...options.args ?? []]
30788
+ ]);
30789
+ const value = await closure.call(values[1], {
30790
+ thisValue: values[0],
30791
+ compilation: this.compilation,
30792
+ stack: []
30793
+ });
30794
+ const settled = await suspendJob(
30795
+ awaitSandboxValue(value, this.controller.signal, this.budget)
30796
+ );
30797
+ return this.exportValue(settled);
30798
+ } finally {
30799
+ leaveCall();
30800
+ leave();
30801
+ }
30802
+ };
30803
+ try {
30804
+ if (this.active !== void 0) {
30805
+ record2.promise = withSandboxPromiseRejectionTracker(
30806
+ this.tracker,
30807
+ () => runResources.run(
30808
+ { signal: this.controller.signal, add: this.onCleanup },
30809
+ () => withCancellationSignal(
30810
+ this.controller.signal,
30811
+ () => this.phase.getStore()?.active ? runAsyncPrefix(invoke) : this.queue.run(invoke)
30812
+ )
30813
+ )
30814
+ );
30815
+ } else {
30816
+ record2.promise = this.perform(() => this.queue.run(invoke));
30817
+ }
30818
+ return await record2.promise;
30819
+ } catch (error) {
30820
+ if (error instanceof SandboxError) this.poison(error);
30821
+ throw error;
30822
+ } finally {
30823
+ this.pendingCallbacks.delete(record2);
30824
+ if (!this.closed && this.active === void 0)
30825
+ reconcileCompiledValues(
30826
+ this.budget,
30827
+ [...this.scope?.retainedValues() ?? [], ...this.retainedRoots()],
30828
+ this.compilation
30829
+ );
30830
+ }
30831
+ };
30832
+ initialize() {
30833
+ if (this.initialized) return;
30834
+ this.assertOpen();
30835
+ this.initialized = true;
30836
+ for (const extension of this.extensions) {
30837
+ const context = Object.freeze({
30838
+ signal: this.controller.signal,
30839
+ onCleanup: this.onCleanup,
30840
+ chargeWork: this.chargeWork,
30841
+ createHostObject: this.createHostObject,
30842
+ invokeCallback: this.invokeCallback,
30843
+ releaseCallback: this.releaseCallback,
30844
+ releaseGuestReference: this.releaseGuestReference,
30845
+ retainGuestArguments: (operation, from) => {
30846
+ this.assertOpen();
30847
+ if (!extension.manifest.capabilities?.includes("guest:retain"))
30848
+ throw new TypeError("Retaining arguments requires the guest:retain grant.");
30849
+ if (typeof operation !== "function")
30850
+ throw new TypeError("Retained operation must be a function.");
30851
+ if (!Number.isSafeInteger(from) || from < 0)
30852
+ throw new TypeError("Argument index must be a non-negative safe integer.");
30853
+ if (this.scope !== void 0)
30854
+ throw new TypeError("Retained operations must be registered during setup.");
30855
+ const previous = this.retainedOperations.get(operation);
30856
+ if (previous !== void 0 && (previous.extension !== extension || previous.from !== from))
30857
+ throw new TypeError("Conflicting retained operation declaration.");
30858
+ this.retainedOperations.set(operation, { extension, from });
30859
+ return operation;
30860
+ },
30861
+ nestedOperation: (operation) => {
30862
+ this.assertOpen();
30863
+ if (!extension.manifest.capabilities?.includes("source:nested"))
30864
+ throw new TypeError("Nested source requires the source:nested grant.");
30865
+ if (typeof operation !== "function")
30866
+ throw new TypeError("Nested operation must be a function.");
30867
+ if (this.scope !== void 0)
30868
+ throw new TypeError("Nested operations must be registered during setup.");
30869
+ const owner = this.nestedOperations.get(operation);
30870
+ if (owner !== void 0 && owner !== extension)
30871
+ throw new TypeError("Nested operation already belongs to another extension.");
30872
+ this.nestedOperations.set(operation, extension);
30873
+ return operation;
30874
+ },
30875
+ evaluateNested: (source) => {
30876
+ const phase = this.phase.getStore();
30877
+ if (!extension.manifest.capabilities?.includes("source:nested") || !phase?.active || phase.extension !== extension || phase.evaluating) {
30878
+ const error = new SandboxError("reentry");
30879
+ this.poison(error);
30880
+ const rejected = Promise.reject(error);
30881
+ void rejected.catch(() => void 0);
30882
+ return rejected;
30883
+ }
30884
+ const pending = this.evaluateNested(source, extension);
30885
+ phase.pending.add(pending);
30886
+ void pending.then(
30887
+ () => {
30888
+ phase.pending.delete(pending);
30889
+ },
30890
+ (reason) => {
30891
+ phase.pending.delete(pending);
30892
+ phase.failure ??= { reason };
30893
+ }
30894
+ );
30895
+ return pending;
30896
+ }
30897
+ });
30898
+ const output = getExtensionSetup(extension)(context);
30899
+ if (types4.isPromise(output)) {
30900
+ void Promise.resolve(output).catch(() => void 0);
30901
+ throw new TypeError("Extension setup must be synchronous.");
30902
+ }
30903
+ const exports = readDataRecord(output, "Extension exports");
30904
+ if (Object.keys(exports).some((key) => key !== "globals" && key !== "modules"))
30905
+ throw new TypeError("Unknown extension export field.");
30906
+ const globals = readDataRecord(
30907
+ exports.globals ?? {},
30908
+ "Extension globals"
30909
+ );
30910
+ const modules = readModules(exports.modules);
30911
+ assertNames(Object.keys(globals), extension.manifest.globals ?? [], "global");
30912
+ assertNames(Object.keys(modules), Object.keys(extension.manifest.modules ?? {}), "module");
30913
+ for (const [name, values] of Object.entries(modules)) {
30914
+ assertNames(Object.keys(values), extension.manifest.modules?.[name] ?? [], "module export");
30915
+ this.modules[name] ??= /* @__PURE__ */ Object.create(null);
30916
+ Object.assign(this.modules[name], values);
30917
+ }
30918
+ Object.assign(this.globals, globals);
30919
+ }
30920
+ const bindings = wrapCallerInjectedBindings(this.globals, this.bridgeOptions());
30921
+ this.scope = new Scope(this.builtinBindings, void 0, void 0, { chargeData: false }).child(
30922
+ bindings,
30923
+ { functionBoundary: true }
30924
+ );
30925
+ }
30926
+ async evaluateRaw(source, filename = "<realm>", nested = false) {
30927
+ this.assertOpen();
30928
+ if (typeof source !== "string") throw new TypeError("Realm source must be a string.");
30929
+ const module = parseExecutableModule(source, filename, this.lease.owner);
30930
+ this.initialize();
30931
+ const imports = resolveModuleImports(module, this.modules, {
30932
+ ...this.bridgeOptions(),
30933
+ wrappedModules: this.convertedModules
30934
+ });
30935
+ for (const [name, value] of Object.entries(imports)) {
30936
+ const binding = this.scope.lookup(name);
30937
+ if (!binding.found) this.scope.declare(name, "const", value);
30938
+ else if (binding.value !== value) throw new TypeError(`Conflicting import '${name}'.`);
30939
+ }
30940
+ const result = await interpret(
30941
+ {
30942
+ type: "BlockStatement",
30943
+ body: module.body.filter((statement) => statement.type !== "ImportDeclaration"),
30944
+ span: module.span
30945
+ },
30946
+ {
30947
+ scope: this.scope,
30948
+ useScopeDirectly: true,
30949
+ budget: this.budget,
30950
+ compilation: this.compilation,
30951
+ signal: this.controller.signal,
30952
+ surfaceUnhandledThrows: true,
30953
+ jobs: this.queue,
30954
+ nested,
30955
+ assertActive: this.assertOpen
30956
+ }
30957
+ );
30958
+ this.assertOpen();
30959
+ return result;
30960
+ }
30961
+ evaluateNested = async (source, extension) => {
30962
+ this.assertOpen();
30963
+ const phase = this.phase.getStore();
30964
+ if (!phase?.active || phase.extension !== extension || phase.evaluating || this.active === void 0)
30965
+ throw new SandboxError("reentry");
30966
+ const leave = this.budget.enterCall();
30967
+ phase.evaluating = true;
30968
+ try {
30969
+ if (++this.nestedDepth > this.limits.nestedEvaluations) {
30970
+ const error = new SandboxError({
30971
+ budget: "callDepth",
30972
+ current: this.nestedDepth,
30973
+ limit: this.limits.nestedEvaluations
30974
+ });
30975
+ this.poison(error);
30976
+ throw error;
30977
+ }
30978
+ const result = await this.evaluateRaw(source, "<nested>", true);
30979
+ if (!result.ok) throw new Error(result.error.message);
30980
+ } finally {
30981
+ this.nestedDepth--;
30982
+ phase.evaluating = false;
30983
+ leave();
30984
+ }
30985
+ };
30986
+ evaluate = async (source, options = {}) => this.perform(async () => {
30987
+ const result = await this.evaluateRaw(source, options.filename);
30988
+ if (!result.ok) {
30989
+ await this.dispose();
30990
+ return { ok: false, error: result.error, stats: result.stats };
30991
+ }
30992
+ return { ok: true, returnValue: this.exportValue(result.returnValue), stats: result.stats };
30993
+ });
30994
+ async perform(task) {
30995
+ if (this.closed || this.failure !== void 0) await this.dispose();
30996
+ this.assertOpen();
30997
+ if (this.active !== void 0) throw new SandboxError("reentry");
30998
+ const pending = Promise.resolve().then(
30999
+ () => withSandboxPromiseRejectionTracker(
31000
+ this.tracker,
31001
+ () => runResources.run(
31002
+ { signal: this.controller.signal, add: this.onCleanup },
31003
+ () => withCancellationSignal(this.controller.signal, task)
31004
+ )
31005
+ )
31006
+ );
31007
+ this.active = pending;
31008
+ try {
31009
+ const result = await pending;
31010
+ await this.queue.drain();
31011
+ const unhandled = await this.tracker.findUnhandledRejection();
31012
+ if (unhandled !== void 0) {
31013
+ const error = new Error(
31014
+ `Unhandled guest promise rejection: ${describeThrownValue(unhandled.reason)}`
31015
+ );
31016
+ error.name = "UnhandledRejectionError";
31017
+ throw error;
31018
+ }
31019
+ if (this.failure !== void 0) throw this.failure.reason;
31020
+ if (!this.closed)
31021
+ reconcileCompiledValues(
31022
+ this.budget,
31023
+ [...this.scope?.retainedValues() ?? [], ...this.retainedRoots()],
31024
+ this.compilation
31025
+ );
31026
+ return result;
31027
+ } catch (error) {
31028
+ this.poison(error);
31029
+ try {
31030
+ await this.dispose();
31031
+ } catch (cleanup) {
31032
+ throw new AggregateError([error, cleanup], "Realm execution and cleanup failed.");
31033
+ }
31034
+ throw error;
31035
+ } finally {
31036
+ this.active = void 0;
31037
+ }
31038
+ }
31039
+ close = () => {
31040
+ this.closed = true;
31041
+ this.controller.abort(new Error("SafeJS realm is closed."));
31042
+ if (this.phase.getStore()?.active) return this.dispose();
31043
+ return Promise.allSettled([
31044
+ this.active,
31045
+ ...Array.from(this.pendingCallbacks, (pending) => pending.promise)
31046
+ ]).then(() => this.dispose());
31047
+ };
31048
+ dispose() {
31049
+ if (this.disposal !== void 0) return this.disposal;
31050
+ this.closed = true;
31051
+ this.controller.abort(new Error("SafeJS realm is closed."));
31052
+ this.options.signal?.removeEventListener("abort", this.abort);
31053
+ for (const callback of this.callbacks.keys()) revokeGuestCallback(callback, this);
31054
+ this.callbacks.clear();
31055
+ for (const object of this.hostObjects) revokeHostObject(object, this);
31056
+ this.hostObjects.clear();
31057
+ for (const reference of this.guestReferences.keys()) revokeGuestReference(reference, this);
31058
+ this.guestReferences.clear();
31059
+ this.budget.setRetainedValues(this, void 0);
31060
+ this.disposal = (async () => {
31061
+ const errors = [];
31062
+ for (const cleanup of this.cleanups.splice(0).reverse()) {
31063
+ try {
31064
+ await cleanup();
31065
+ } catch (error) {
31066
+ errors.push(error);
31067
+ }
31068
+ }
31069
+ this.scope = void 0;
31070
+ this.convertedModules.clear();
31071
+ for (const key of Object.keys(this.globals)) delete this.globals[key];
31072
+ for (const key of Object.keys(this.modules)) delete this.modules[key];
31073
+ for (const key of Object.keys(this.builtinBindings))
31074
+ Reflect.deleteProperty(this.builtinBindings, key);
31075
+ this.nativeConversions.seen = /* @__PURE__ */ new WeakMap();
31076
+ reconcileCompiledValues(this.budget, [], this.compilation);
31077
+ this.compilation.dispose();
31078
+ this.lease.release();
31079
+ if (errors.length > 0) throw new AggregateError(errors, "Realm cleanup failed.");
31080
+ })();
31081
+ return this.disposal;
31082
+ }
31083
+ };
31084
+ function readModules(input) {
31085
+ const entries = (value, label) => {
31086
+ if (types4.isMap(value) && !types4.isProxy(value)) {
31087
+ const result = [...Map.prototype.entries.call(value)];
31088
+ if (result.length > 4096 || result.some(([key]) => typeof key !== "string" || key.length === 0))
31089
+ throw new TypeError(`${label} requires bounded string keys.`);
31090
+ return result;
31091
+ }
31092
+ return Object.entries(readDataRecord(value, label));
31093
+ };
31094
+ const modules = /* @__PURE__ */ Object.create(null);
31095
+ for (const [name, exports] of entries(input ?? {}, "Module registry")) {
31096
+ const exported = /* @__PURE__ */ Object.create(null);
31097
+ for (const [key, value] of entries(exports, "Module exports"))
31098
+ exported[key] = value;
31099
+ modules[name] = exported;
31100
+ }
31101
+ return modules;
31102
+ }
31103
+ function assertNames(actual, expected, label) {
31104
+ if (actual.length !== expected.length || actual.some((name) => !expected.includes(name)))
31105
+ throw new TypeError(`Extension ${label} names do not match its manifest.`);
31106
+ }
31107
+ function createRealm(options = {}) {
31108
+ const state = new RealmState(readRealmOptions(options));
31109
+ return Object.freeze({
31110
+ extensions: Object.freeze(state.extensions.map((extension) => extension.manifest)),
31111
+ evaluate: state.evaluate,
31112
+ invokeCallback: state.invokeCallback,
31113
+ releaseCallback: state.releaseCallback,
31114
+ releaseGuestReference: state.releaseGuestReference,
31115
+ close: state.close
31116
+ });
31117
+ }
31118
+ async function runWithExtensions(source, options) {
31119
+ if (options.snapshot !== void 0 || options.snapshotBackend !== void 0 || options.snapshotPath !== void 0 || options.entryPointArgs !== void 0)
31120
+ throw new TypeError(
31121
+ "Live extension runs do not support snapshots or entryPointArgs; use a persistent realm."
31122
+ );
31123
+ const state = new RealmState(readRealmOptions(options, true));
31124
+ try {
31125
+ const result = await state.perform(() => state.evaluateRaw(source, options.filename));
31126
+ if (result.ok) encodeReplayData(result.returnValue);
31127
+ return {
31128
+ ...result,
31129
+ snapshot: {
31130
+ version: 1,
31131
+ sourceHash: hashSource(source),
31132
+ bindings: {},
31133
+ replayError: "Live realm state cannot be serialized or replayed."
31134
+ }
31135
+ };
31136
+ } catch (error) {
31137
+ if (state.disposal === void 0) {
31138
+ try {
31139
+ await state.close();
31140
+ } catch (cleanupError) {
31141
+ throw new AggregateError([error, cleanupError], "Realm execution and cleanup failed.");
31142
+ }
31143
+ }
31144
+ throw error;
31145
+ } finally {
31146
+ if (state.disposal === void 0) await state.close();
31147
+ }
31148
+ }
31149
+ function readRealmOptions(value, oneShot = false) {
31150
+ const options = readDataRecord(value, "Realm options");
31151
+ const supported = /* @__PURE__ */ new Set([
31152
+ "bindings",
31153
+ "modules",
31154
+ "extensions",
31155
+ "grants",
31156
+ "budget",
31157
+ "signal",
31158
+ "sink",
31159
+ "randomSeed",
31160
+ "clock",
31161
+ "limits"
31162
+ ]);
31163
+ for (const [key, entry] of Object.entries(options)) {
31164
+ if (supported.has(key) || oneShot && (key === "filename" || entry === void 0)) continue;
31165
+ throw new TypeError(`Unsupported ${oneShot ? "extension-run" : "realm"} option '${key}'.`);
31166
+ }
31167
+ return options;
31168
+ }
31169
+
31170
+ // packages/safe-js/src/snapshot/dump.ts
31171
+ var RUN_DUMP_CONTROLLER = /* @__PURE__ */ Symbol("SafeJS.run-dump-controller");
31172
+ function attachDumpController(result, controller) {
31173
+ Object.defineProperty(result, RUN_DUMP_CONTROLLER, {
31174
+ configurable: false,
31175
+ enumerable: false,
31176
+ value: controller,
31177
+ writable: false
31178
+ });
31179
+ return result;
31180
+ }
31181
+ function createDumpController(lifecycle) {
31182
+ let finished = false;
31183
+ let failed;
31184
+ let finalSnapshot;
31185
+ let latestSnapshot;
31186
+ let latestSnapshotFactory;
31187
+ let pendingRequest;
31188
+ return {
31189
+ fail(error) {
31190
+ finished = true;
31191
+ failed = {
31192
+ error
31193
+ };
31194
+ if (pendingRequest === void 0) {
31195
+ return;
31196
+ }
31197
+ pendingRequest.reject(error);
31198
+ pendingRequest = void 0;
31199
+ },
31200
+ finalize(snapshot) {
31201
+ finished = true;
31202
+ finalSnapshot = snapshot;
31203
+ latestSnapshot = snapshot;
31204
+ latestSnapshotFactory = void 0;
31205
+ if (pendingRequest !== void 0) {
31206
+ settlePendingSnapshot(snapshot);
31207
+ }
31208
+ },
31209
+ onYield(createSnapshot) {
31210
+ latestSnapshot = void 0;
31211
+ latestSnapshotFactory = createSnapshot;
31212
+ if (pendingRequest === void 0) {
31213
+ return;
31214
+ }
31215
+ settlePendingSnapshot(createSnapshot());
31216
+ },
31217
+ requestCurrentSnapshot(options = {}) {
31218
+ assertDumpAllowed(options);
31219
+ if (failed !== void 0) {
31220
+ return Promise.reject(failed.error);
29904
31221
  }
29905
- if (result.done) break;
29906
- const entry = result.value;
29907
- if (typeof entry !== "object" && typeof entry !== "function" || entry === null) {
29908
- throw new TypeError("Object.fromEntries requires entry objects.");
31222
+ if (latestSnapshot !== void 0 || latestSnapshotFactory !== void 0) {
31223
+ try {
31224
+ return Promise.resolve(serializeRunSnapshot(latestSnapshot ?? latestSnapshotFactory()));
31225
+ } catch (error) {
31226
+ return Promise.reject(error);
31227
+ }
29909
31228
  }
29910
- const key = entry[0];
29911
- const value = entry[1];
29912
- Object.defineProperty(object, key, {
29913
- configurable: true,
29914
- enumerable: true,
29915
- value,
29916
- writable: true
31229
+ return this.requestSnapshot(options);
31230
+ },
31231
+ requestSnapshot(options = {}) {
31232
+ assertDumpAllowed(options);
31233
+ if (failed !== void 0) {
31234
+ if ((options.onFailure === "checkpoint" || options.onFailure === void 0 && isDataBudgetError(failed.error)) && finalSnapshot !== void 0) {
31235
+ try {
31236
+ return Promise.resolve(serializeRunSnapshot(finalSnapshot));
31237
+ } catch (error) {
31238
+ return Promise.reject(error);
31239
+ }
31240
+ }
31241
+ return Promise.reject(failed.error);
31242
+ }
31243
+ if (finished) {
31244
+ if (finalSnapshot === void 0) {
31245
+ throw new Error("Run completed without producing a snapshot.");
31246
+ }
31247
+ try {
31248
+ const serializedSnapshot = serializeRunSnapshot(finalSnapshot);
31249
+ return Promise.resolve(serializedSnapshot);
31250
+ } catch (error) {
31251
+ return Promise.reject(error);
31252
+ }
31253
+ }
31254
+ if (options.mode === "replay" && (latestSnapshot !== void 0 || latestSnapshotFactory !== void 0)) {
31255
+ return this.requestCurrentSnapshot(options);
31256
+ }
31257
+ if (pendingRequest !== void 0) {
31258
+ return pendingRequest.promise;
31259
+ }
31260
+ let resolveSnapshot = () => void 0;
31261
+ let rejectSnapshot = () => void 0;
31262
+ const promise = new Promise((resolve, reject) => {
31263
+ resolveSnapshot = resolve;
31264
+ rejectSnapshot = reject;
29917
31265
  });
31266
+ pendingRequest = {
31267
+ promise,
31268
+ reject: rejectSnapshot,
31269
+ resolve: resolveSnapshot
31270
+ };
31271
+ return promise;
29918
31272
  }
29919
- } catch (error) {
29920
- try {
29921
- await iterator.return?.();
29922
- } catch {
29923
- throw error;
31273
+ };
31274
+ function assertDumpAllowed(options) {
31275
+ if ((lifecycle?.hostCallbackDepth ?? 0) > 0 && (options.mode !== "replay" || lifecycle?.hostCallbackContext.getStore() === true)) {
31276
+ throw new SandboxError("reentry");
29924
31277
  }
29925
- throw error;
29926
- }
29927
- return allocateProducedSandboxValue(object, budget);
29928
- }
29929
- function assignSandboxValues(target, sources, budget) {
29930
- if (target === null || target === void 0) {
29931
- throw new TypeError("Object.assign(target, ...sources) requires a non-null target.");
29932
31278
  }
29933
- if (!isGuestClosure(target) && !isAssignableSandboxTarget(target)) {
29934
- throw new TypeError("Object.assign(target, ...sources) requires an object or array target.");
29935
- }
29936
- for (const source of sources) {
29937
- if (source === null || source === void 0) {
29938
- continue;
31279
+ function settlePendingSnapshot(snapshot) {
31280
+ try {
31281
+ settlePendingRequest(serializeRunSnapshot(snapshot));
31282
+ } catch (error) {
31283
+ pendingRequest?.reject(error);
31284
+ pendingRequest = void 0;
29939
31285
  }
29940
- for (const [key, value] of ownEnumerableSandboxEntries(source)) {
29941
- setSandboxProperty(target, key, value, budget);
31286
+ }
31287
+ function settlePendingRequest(snapshot) {
31288
+ if (pendingRequest === void 0) {
31289
+ return;
29942
31290
  }
31291
+ pendingRequest.resolve(snapshot);
31292
+ pendingRequest = void 0;
29943
31293
  }
29944
- return target;
29945
31294
  }
29946
- function objectProperties(value, mutable = false) {
29947
- if (isGuestClosure(value)) return materializeFunctionProperties(value);
29948
- if (isSandboxClosure(value)) {
29949
- if (mutable) throw new TypeError("Host function properties are read only.");
29950
- return value.properties ?? /* @__PURE__ */ Object.create(null);
29951
- }
29952
- if (!isAssignableSandboxTarget(value)) throw new TypeError("Expected a sandbox object or function.");
29953
- return value;
31295
+ function isDataBudgetError(error) {
31296
+ return typeof error === "object" && error !== null && "code" in error && error.code === "budgetExceeded" && "budget" in error && error.budget === "dataSize";
29954
31297
  }
29955
- function dataDescriptor(input) {
29956
- const source = objectProperties(input);
29957
- const descriptor = {};
29958
- for (const field of ["get", "set", "value", "writable", "enumerable", "configurable"]) {
29959
- const entry = Object.getOwnPropertyDescriptor(source, field);
29960
- if (entry === void 0) continue;
29961
- if (!("value" in entry) || field === "get" || field === "set") {
29962
- throw new TypeError("Only data property descriptors are supported.");
31298
+ function dump(result, options = {}) {
31299
+ const controller = readDumpController(result);
31300
+ if (controller !== void 0) {
31301
+ return controller.requestSnapshot(options);
31302
+ }
31303
+ if (hasSnapshot(result)) {
31304
+ try {
31305
+ return Promise.resolve(serializeRunSnapshot(result.snapshot));
31306
+ } catch (error) {
31307
+ return Promise.reject(error);
29963
31308
  }
29964
- if (field === "value") descriptor.value = entry.value;
29965
- else descriptor[field] = Boolean(entry.value);
29966
31309
  }
29967
- return descriptor;
29968
- }
29969
- function defineDataProperty2(target, key, descriptor, budget) {
29970
- budget.visitNode();
29971
- if (isFloat32Array(target)) throw new TypeError("Typed array property descriptors are not supported.");
29972
- const properties = objectProperties(target, true);
29973
- if (Array.isArray(properties)) {
29974
- if (key === "length" && "value" in descriptor) budget.allocateArrayLength(Number(descriptor.value));
29975
- else {
29976
- const index = Number(key);
29977
- if (Number.isInteger(index) && index >= 0 && index < 4294967295 && String(index) === key) {
29978
- budget.allocateArrayLength(index + 1);
29979
- }
31310
+ return Promise.resolve(result).then((resolved) => {
31311
+ if (!hasSnapshot(resolved)) {
31312
+ throw new Error("Run completed without producing a snapshot.");
29980
31313
  }
31314
+ return serializeRunSnapshot(resolved.snapshot);
31315
+ });
31316
+ }
31317
+ function dumpCurrent(result) {
31318
+ const controller = readDumpController(result);
31319
+ if (controller !== void 0) {
31320
+ return controller.requestCurrentSnapshot();
29981
31321
  }
29982
- Object.defineProperty(properties, key, descriptor);
29983
- markDescriptorObject(properties);
31322
+ return dump(result);
29984
31323
  }
29985
- function isAssignableSandboxTarget(value) {
29986
- return typeof value === "object" && value !== null && !isSandboxClosure(value) && !isSandboxGenerator(value) && !isSandboxMap(value) && !isSandboxSet(value) && !isSandboxPromise(value) && !isSandboxRegex(value);
31324
+ function serializeRunSnapshot(snapshot) {
31325
+ return serializeSafeJSSnapshot(snapshot);
29987
31326
  }
29988
- async function arrayFromSandboxValues(args, budget) {
29989
- const [items, mapFn, thisValue] = args;
29990
- const iterator = getSandboxIterator(items);
29991
- const values = iterator === void 0 ? Reflect.apply(Array.from, Array, [items]) : await collectIteratorValues(iterator);
29992
- if (mapFn === void 0 || !isSandboxClosure(mapFn)) {
29993
- if (mapFn !== void 0) {
29994
- throw new TypeError("Array.from mapping callback must be a function.");
29995
- }
29996
- return budgetSandboxValue2(values, budget);
29997
- }
29998
- const mappedValues = [];
29999
- for (const [index, value] of values.entries()) {
30000
- const result = await mapFn.call([value, index], { stack: [], thisValue });
30001
- if (isSandboxPromise(result) && result.synchronousPrefix !== void 0) {
30002
- await result.synchronousPrefix;
30003
- }
30004
- mappedValues.push(result);
30005
- }
30006
- return budgetSandboxValue2(mappedValues, budget);
31327
+ function hasSnapshot(value) {
31328
+ return typeof value === "object" && value !== null && Object.prototype.hasOwnProperty.call(value, "snapshot");
30007
31329
  }
30008
- function createArrayFromConstructorArgs(args, budget) {
30009
- if (args.length !== 1) {
30010
- return budgetSandboxValue2(Reflect.apply(Array, Array, [...args]), budget);
30011
- }
30012
- const [lengthOrValue] = args;
30013
- if (typeof lengthOrValue !== "number") {
30014
- return budgetSandboxValue2([lengthOrValue], budget);
30015
- }
30016
- if (!Number.isInteger(lengthOrValue) || lengthOrValue < 0 || lengthOrValue > 4294967295) {
30017
- throw new RangeError("Invalid array length.");
31330
+ function readDumpController(value) {
31331
+ if (typeof value !== "object" || value === null) {
31332
+ return void 0;
30018
31333
  }
30019
- budget.allocateArrayLength(lengthOrValue);
30020
- return new Array(lengthOrValue);
31334
+ return value[RUN_DUMP_CONTROLLER];
30021
31335
  }
30022
- async function collectIteratorValues(iterator) {
30023
- const values = [];
30024
- while (true) {
30025
- const result = await iterator.next();
30026
- if (result.done) return values;
30027
- values.push(result.value);
31336
+
31337
+ // packages/safe-js/src/error-codes.ts
31338
+ function getOwnErrorCode(error) {
31339
+ if (typeof error !== "object" || error === null || !Object.prototype.hasOwnProperty.call(error, "code")) {
31340
+ return void 0;
30028
31341
  }
31342
+ const code = error.code;
31343
+ return typeof code === "string" ? code : void 0;
30029
31344
  }
30030
- function getOwnEnumerableKeys(value) {
30031
- return ownEnumerableSandboxEntries(value).map(([key]) => key);
30032
- }
30033
- function getOwnEnumerableValues(value) {
30034
- return ownEnumerableSandboxEntries(value).map(([, entryValue]) => entryValue);
30035
- }
30036
- function budgetSandboxValue2(value, budget) {
30037
- const sandboxValue = deepCopyToSandbox(value);
30038
- return allocateProducedSandboxValue(sandboxValue, budget);
31345
+ function hasOwnErrorCode(error, code) {
31346
+ return getOwnErrorCode(error) === code;
30039
31347
  }
30040
- function stringRaw(args, budget) {
30041
- const [template, ...substitutions] = args;
30042
- const raw = getTemplateRawParts(template);
30043
- let result = "";
30044
- for (let index = 0; index < raw.length; index += 1) {
30045
- result += String(raw[index]);
30046
- if (index < raw.length - 1 && index < substitutions.length) {
30047
- result += String(substitutions[index]);
30048
- }
31348
+
31349
+ // packages/safe-js/src/snapshot/backend.ts
31350
+ import { randomUUID as randomUUID2 } from "node:crypto";
31351
+ import { readFile, rename, stat, unlink, writeFile } from "node:fs/promises";
31352
+ import { dirname } from "node:path";
31353
+ var DEFAULT_WRITE_MAX_ATTEMPTS = 3;
31354
+ var DEFAULT_WRITE_RETRY_DELAY_MS = 100;
31355
+ var LOCKED_FILE_ERROR_CODES = /* @__PURE__ */ new Set(["EACCES", "EBUSY", "EPERM"]);
31356
+ var pendingOperations = /* @__PURE__ */ new Map();
31357
+ var FileSnapshotBackend = class {
31358
+ constructor(path, options = {}) {
31359
+ this.path = path;
31360
+ this.#writeMaxAttempts = options.writeMaxAttempts ?? DEFAULT_WRITE_MAX_ATTEMPTS;
31361
+ this.#writeRetryDelayMs = options.writeRetryDelayMs ?? DEFAULT_WRITE_RETRY_DELAY_MS;
30049
31362
  }
30050
- return budget.allocateString(result);
30051
- }
30052
- function getTemplateRawParts(template) {
30053
- const raw = typeof template === "object" && template !== null ? template.raw : void 0;
30054
- if (typeof template !== "object" || template === null || isSandboxClosure(template) || isSandboxPromise(template) || !Array.isArray(raw)) {
30055
- throw new TypeError("String.raw requires a raw strings array.");
31363
+ path;
31364
+ #writeMaxAttempts;
31365
+ #writeRetryDelayMs;
31366
+ async read() {
31367
+ try {
31368
+ return JSON.parse(await readFile(this.path, "utf8"));
31369
+ } catch (error) {
31370
+ if (hasErrorCode(error, "ENOENT")) {
31371
+ return void 0;
31372
+ }
31373
+ if (error instanceof SyntaxError) {
31374
+ throw new Error(`Failed to parse snapshot at ${this.path}: ${error.message}`);
31375
+ }
31376
+ throw error;
31377
+ }
30056
31378
  }
30057
- return raw;
30058
- }
30059
-
30060
- // packages/safe-js/src/modules/registry.ts
30061
- function createUnknownModuleMessage2(moduleName, moduleNames) {
30062
- if (moduleNames.length === 0) {
30063
- return `Unknown module '${moduleName}'. No modules are registered.`;
31379
+ async write(snapshot) {
31380
+ await enqueueOperation(
31381
+ this.path,
31382
+ () => writeSnapshotAtomically(this.path, snapshot, {
31383
+ maxAttempts: this.#writeMaxAttempts,
31384
+ retryDelayMs: this.#writeRetryDelayMs
31385
+ })
31386
+ );
30064
31387
  }
30065
- return `Unknown module '${moduleName}'. Available modules: ${moduleNames.join(", ")}.`;
30066
- }
30067
- function createUnknownExportMessage2(moduleName, exportName, availableExports) {
30068
- if (availableExports.length === 0) {
30069
- return `Module '${moduleName}' does not export '${exportName}'. The module exports nothing.`;
31388
+ async remove() {
31389
+ await enqueueOperation(this.path, async () => {
31390
+ try {
31391
+ await unlink(this.path);
31392
+ } catch (error) {
31393
+ if (!hasErrorCode(error, "ENOENT")) {
31394
+ throw error;
31395
+ }
31396
+ }
31397
+ });
30070
31398
  }
30071
- return `Module '${moduleName}' does not export '${exportName}'. Available exports: ${availableExports.join(", ")}.`;
30072
- }
30073
- function resolveModuleImports(module, modules, options) {
30074
- const registry = normalizeModuleRegistry(modules);
30075
- const bindings = createBindingRecord();
30076
- const wrappedModules = /* @__PURE__ */ new Map();
30077
- for (const statement of module.body) {
30078
- if (statement.type !== "ImportDeclaration") {
30079
- continue;
31399
+ };
31400
+ async function writeSnapshotAtomically(snapshotPath, snapshot, options) {
31401
+ const parentPath = dirname(snapshotPath);
31402
+ const contents = serializeSafeJSSnapshot(snapshot);
31403
+ await assertParentDirectoryExists(snapshotPath, parentPath);
31404
+ for (let attempt = 1; attempt <= options.maxAttempts; attempt += 1) {
31405
+ try {
31406
+ const temporaryPath = `${snapshotPath}.${randomUUID2()}.tmp`;
31407
+ await writeSnapshotOnce(temporaryPath, snapshotPath, contents);
31408
+ return;
31409
+ } catch (error) {
31410
+ if (hasErrorCode(error, "EEXIST")) {
31411
+ if (attempt === options.maxAttempts) {
31412
+ throw new Error(
31413
+ `Failed to write snapshot at ${snapshotPath} after ${options.maxAttempts} attempts: temporary path already exists`,
31414
+ {
31415
+ cause: error
31416
+ }
31417
+ );
31418
+ }
31419
+ continue;
31420
+ }
31421
+ if (!isLockedFileError(error)) {
31422
+ throw error;
31423
+ }
31424
+ if (attempt === options.maxAttempts) {
31425
+ throw new Error(
31426
+ `Failed to write snapshot at ${snapshotPath} after ${options.maxAttempts} attempts: file is locked (${getOwnErrorCode(error)})`,
31427
+ {
31428
+ cause: error
31429
+ }
31430
+ );
31431
+ }
31432
+ await delay(options.retryDelayMs);
30080
31433
  }
30081
- bindImportDeclaration(statement, registry, wrappedModules, bindings, options);
30082
31434
  }
30083
- return bindings;
30084
31435
  }
30085
- function bindImportDeclaration(declaration, registry, wrappedModules, bindings, options) {
30086
- const moduleName = declaration.source.value;
30087
- const moduleExports = registry.get(moduleName);
30088
- if (moduleExports === void 0) {
30089
- if (options.allowMissing) return;
30090
- throw createModuleImportError(
30091
- createUnknownModuleMessage2(moduleName, [...registry.keys()]),
30092
- declaration.source.span
30093
- );
30094
- }
30095
- const wrappedExports = wrappedModules.get(moduleName) ?? createBindingRecord(
30096
- wrapCancelableBindings(
30097
- wrapCallerInjectedBindings(Object.fromEntries(moduleExports), {
30098
- budget: options.budget,
30099
- compileOwner: options.compileOwner,
30100
- hostCalls: options.hostCalls,
30101
- moduleId: moduleName,
30102
- signal: options.signal
30103
- }),
30104
- options.signal
30105
- )
30106
- );
30107
- wrappedModules.set(moduleName, wrappedExports);
30108
- for (const specifier of declaration.specifiers) {
30109
- const localName = specifier.local.name;
30110
- if (Object.hasOwn(bindings, localName)) {
30111
- throw createModuleImportError(
30112
- `Cannot redeclare imported binding '${localName}'.`,
30113
- specifier.local.span
31436
+ async function assertParentDirectoryExists(snapshotPath, parentPath) {
31437
+ try {
31438
+ const parent = await stat(parentPath);
31439
+ if (!parent.isDirectory()) {
31440
+ throw new Error(
31441
+ `Cannot write snapshot at ${snapshotPath}: parent path ${parentPath} is not a directory`
30114
31442
  );
30115
31443
  }
30116
- if (options.allowMissing && specifier.type !== "ImportNamespaceSpecifier") {
30117
- const exportName = specifier.type === "ImportDefaultSpecifier" ? "default" : specifier.imported.name;
30118
- if (!Object.hasOwn(wrappedExports, exportName)) continue;
31444
+ } catch (error) {
31445
+ if (hasErrorCode(error, "ENOENT")) {
31446
+ throw new Error(
31447
+ `Cannot write snapshot at ${snapshotPath}: parent directory ${parentPath} does not exist`,
31448
+ {
31449
+ cause: error
31450
+ }
31451
+ );
30119
31452
  }
30120
- bindings[localName] = resolveImportSpecifier(moduleName, specifier, wrappedExports);
31453
+ throw error;
30121
31454
  }
30122
31455
  }
30123
- function resolveImportSpecifier(moduleName, specifier, wrappedExports) {
30124
- if (specifier.type === "ImportNamespaceSpecifier") {
30125
- return wrappedExports;
30126
- }
30127
- const exportName = specifier.type === "ImportDefaultSpecifier" ? "default" : specifier.imported.name;
30128
- const exportedValue = wrappedExports[exportName];
30129
- if (exportedValue !== void 0 || Object.hasOwn(wrappedExports, exportName)) {
30130
- return exportedValue;
31456
+ async function writeSnapshotOnce(temporaryPath, snapshotPath, contents) {
31457
+ let temporaryCreated = false;
31458
+ let renamed = false;
31459
+ try {
31460
+ try {
31461
+ await writeFile(temporaryPath, contents, { encoding: "utf8", flag: "wx" });
31462
+ temporaryCreated = true;
31463
+ } catch (error) {
31464
+ if (!hasErrorCode(error, "EEXIST")) {
31465
+ await removeTemporarySnapshot(temporaryPath).catch(() => void 0);
31466
+ }
31467
+ throw error;
31468
+ }
31469
+ await rename(temporaryPath, snapshotPath);
31470
+ renamed = true;
31471
+ } finally {
31472
+ if (temporaryCreated && !renamed) {
31473
+ await removeTemporarySnapshot(temporaryPath).catch(() => void 0);
31474
+ }
30131
31475
  }
30132
- throw createModuleImportError(
30133
- createUnknownExportMessage2(moduleName, exportName, Object.keys(wrappedExports).sort()),
30134
- specifier.span
30135
- );
30136
- }
30137
- function createModuleImportError(message, span) {
30138
- const error = new Error(message);
30139
- attachErrorSpan(error, span);
30140
- return error;
30141
31476
  }
30142
- function normalizeModuleRegistry(modules) {
30143
- if (modules === void 0) {
30144
- return /* @__PURE__ */ new Map();
31477
+ async function enqueueOperation(path, operation) {
31478
+ const previous = pendingOperations.get(path) ?? Promise.resolve();
31479
+ const pending = previous.catch(() => void 0).then(operation);
31480
+ const queued = pending.catch(() => void 0);
31481
+ pendingOperations.set(path, queued);
31482
+ try {
31483
+ await pending;
31484
+ } finally {
31485
+ if (pendingOperations.get(path) === queued) {
31486
+ pendingOperations.delete(path);
31487
+ }
30145
31488
  }
30146
- const entries = modules instanceof Map ? [...modules.entries()] : Object.entries(modules);
30147
- const registry = new Map(
30148
- entries.map(
30149
- ([moduleName, moduleExports]) => [moduleName, normalizeModuleExports(moduleExports)]
30150
- ).sort(([left], [right]) => left.localeCompare(right))
30151
- );
30152
- registerModuleHostOperationPolicies(registry);
30153
- return registry;
30154
31489
  }
30155
- function registerModuleHostOperationPolicies(registry) {
30156
- for (const [moduleId, moduleExports] of registry) {
30157
- for (const [operation, value] of moduleExports) {
30158
- if (typeof value !== "function") {
30159
- continue;
30160
- }
30161
- const policy = readHostOperationPolicy(value);
30162
- if (policy !== void 0) {
30163
- registerPendingHostCallPolicy({ moduleId, operation, policy });
30164
- }
31490
+ async function removeTemporarySnapshot(temporaryPath) {
31491
+ try {
31492
+ await unlink(temporaryPath);
31493
+ } catch (error) {
31494
+ if (!hasErrorCode(error, "ENOENT")) {
31495
+ throw error;
30165
31496
  }
30166
31497
  }
30167
31498
  }
30168
- function normalizeModuleExports(moduleExports) {
30169
- const entries = moduleExports instanceof Map ? [...moduleExports.entries()] : Object.entries(moduleExports);
30170
- return new Map(
30171
- entries.filter(([exportName]) => exportName.length > 0).sort(([left], [right]) => left.localeCompare(right))
30172
- );
31499
+ async function delay(ms) {
31500
+ if (ms === 0) {
31501
+ return;
31502
+ }
31503
+ await new Promise((resolve) => setTimeout(resolve, ms));
30173
31504
  }
30174
- function createBindingRecord(entries) {
30175
- return Object.assign(/* @__PURE__ */ Object.create(null), entries);
31505
+ function hasErrorCode(error, code) {
31506
+ return hasOwnErrorCode(error, code);
31507
+ }
31508
+ function isLockedFileError(error) {
31509
+ const code = getOwnErrorCode(error);
31510
+ return code !== void 0 && LOCKED_FILE_ERROR_CODES.has(code);
30176
31511
  }
30177
31512
 
31513
+ // packages/safe-js/src/run.ts
31514
+ import { AsyncLocalStorage as AsyncLocalStorage7 } from "node:async_hooks";
31515
+
30178
31516
  // packages/safe-js/src/snapshot/scheduler.ts
30179
31517
  var DEFAULT_SNAPSHOT_INTERVAL_MS = 3e4;
30180
31518
  function createSnapshotScheduler(options) {
@@ -30397,9 +31735,10 @@ var UnhandledRejectionError = class extends Error {
30397
31735
  };
30398
31736
  var DEFAULT_MAX_CALL_DEPTH = 1e3;
30399
31737
  function run(source, options = {}) {
31738
+ if (options.extensions !== void 0) return runWithExtensions(source, options);
30400
31739
  const lifecycle = {
30401
31740
  hostCallbackDepth: 0,
30402
- hostCallbackContext: new AsyncLocalStorage6()
31741
+ hostCallbackContext: new AsyncLocalStorage7()
30403
31742
  };
30404
31743
  const dumpController = createDumpController(lifecycle);
30405
31744
  const promiseTracker = createSandboxPromiseRejectionTracker();
@@ -30465,32 +31804,7 @@ function run(source, options = {}) {
30465
31804
  lifecycle
30466
31805
  })
30467
31806
  );
30468
- const builtinBindings = {
30469
- ...createConsoleJsonGlobals({
30470
- compileOwner: operation.owner,
30471
- budget,
30472
- hostCalls,
30473
- sink: options.sink
30474
- }),
30475
- ...createCollectionGlobals({ budget }),
30476
- Float32Array: createFloat32ArrayGlobal(budget),
30477
- ...createErrorGlobals({
30478
- budget
30479
- }),
30480
- ...createMathGlobals({
30481
- random: random?.generator.next
30482
- }),
30483
- ...createObjectArrayGlobals({
30484
- budget
30485
- }),
30486
- ...createMiscGlobals({
30487
- budget
30488
- }),
30489
- ...createPromiseGlobals({
30490
- budget
30491
- }),
30492
- ...createRegexGlobals(operation.owner)
30493
- };
31807
+ const builtinBindings = createBuiltinBindings({ compileOwner: operation.owner, budget, hostCalls, sink: options.sink, random: random?.generator.next, clock: options.clock });
30494
31808
  const importMeta = convertInitialInput(
30495
31809
  () => deepCopyToSandbox(options.importMeta ?? {})
30496
31810
  );
@@ -30952,6 +32266,7 @@ export {
30952
32266
  parse,
30953
32267
  parseModule,
30954
32268
  hashSource,
32269
+ defineExtension,
30955
32270
  noopOtelSink,
30956
32271
  bindOtelSpan,
30957
32272
  activateOtelSpan,
@@ -30980,10 +32295,11 @@ export {
30980
32295
  validateSnapshotMigration,
30981
32296
  restore,
30982
32297
  lint,
30983
- runResources,
32298
+ declareHostOperation,
30984
32299
  createSeededRandom,
32300
+ runResources,
30985
32301
  createReplayableRandom,
30986
- declareHostOperation,
32302
+ createRealm,
30987
32303
  dump,
30988
32304
  dumpCurrent,
30989
32305
  getOwnErrorCode,
@@ -30991,4 +32307,4 @@ export {
30991
32307
  FileSnapshotBackend,
30992
32308
  run
30993
32309
  };
30994
- //# sourceMappingURL=chunk-B7H4ZL65.js.map
32310
+ //# sourceMappingURL=chunk-BWVASPJX.js.map