@poe-platform/safe-js 0.1.21 → 0.1.23

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.
@@ -5922,6 +5922,87 @@ function matchingOpeningPunctuator(value) {
5922
5922
  return "{";
5923
5923
  }
5924
5924
 
5925
+ // packages/safe-js/src/extensions.ts
5926
+ import { types } from "node:util";
5927
+ var definitions = /* @__PURE__ */ new WeakMap();
5928
+ function readDataRecord(value, label) {
5929
+ if (typeof value !== "object" || value === null || types.isProxy(value)) {
5930
+ throw new TypeError(`${label} must be a plain data record.`);
5931
+ }
5932
+ const prototype = Object.getPrototypeOf(value);
5933
+ if (prototype !== null && prototype !== Object.prototype) {
5934
+ throw new TypeError(`${label} must be a plain data record.`);
5935
+ }
5936
+ const keys = Reflect.ownKeys(value);
5937
+ if (keys.length > 4096) throw new RangeError(`${label} has too many fields.`);
5938
+ const result = /* @__PURE__ */ Object.create(null);
5939
+ for (const key of keys) {
5940
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
5941
+ if (typeof key !== "string" || !("value" in descriptor)) {
5942
+ throw new TypeError(`${label} requires string-keyed data properties, not accessors.`);
5943
+ }
5944
+ result[key] = descriptor.value;
5945
+ }
5946
+ return result;
5947
+ }
5948
+ function readStringList(value, label) {
5949
+ if (!Array.isArray(value) || types.isProxy(value) || value.length > 4096) {
5950
+ throw new TypeError(`${label} must be a bounded string array.`);
5951
+ }
5952
+ const result = [];
5953
+ for (let index = 0; index < value.length; index++) {
5954
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
5955
+ if (descriptor === void 0 || !("value" in descriptor) || typeof descriptor.value !== "string" || descriptor.value.length === 0) {
5956
+ throw new TypeError(`${label} requires nonempty string data properties.`);
5957
+ }
5958
+ if (result.includes(descriptor.value))
5959
+ throw new TypeError(`${label} contains a duplicate name.`);
5960
+ result.push(descriptor.value);
5961
+ }
5962
+ if (Reflect.ownKeys(value).length !== result.length + 1)
5963
+ throw new TypeError(`${label} has unexpected fields.`);
5964
+ return Object.freeze(result);
5965
+ }
5966
+ function defineExtension(definition) {
5967
+ const input = readDataRecord(definition, "Extension definition");
5968
+ if (Object.keys(input).some((key) => key !== "manifest" && key !== "setup"))
5969
+ throw new TypeError("Unknown extension definition field.");
5970
+ if (typeof input.setup !== "function") throw new TypeError("Extension setup must be a function.");
5971
+ if (types.isAsyncFunction(input.setup))
5972
+ throw new TypeError("Extension setup must be synchronous.");
5973
+ const manifest = readDataRecord(input.manifest, "Extension manifest");
5974
+ if (Object.keys(manifest).some(
5975
+ (key) => !["version", "name", "capabilities", "globals", "modules"].includes(key)
5976
+ ))
5977
+ throw new TypeError("Unknown extension manifest field.");
5978
+ if (manifest.version !== 1) throw new TypeError("Unsupported extension manifest version.");
5979
+ if (typeof manifest.name !== "string" || manifest.name.length === 0 || manifest.name.length > 256)
5980
+ throw new TypeError("Extension name must be a nonempty bounded string.");
5981
+ const modules = /* @__PURE__ */ Object.create(null);
5982
+ for (const [name, exports] of Object.entries(
5983
+ readDataRecord(manifest.modules ?? {}, "Extension modules")
5984
+ )) {
5985
+ if (name.length === 0) throw new TypeError("Module names must be nonempty.");
5986
+ modules[name] = readStringList(exports, `Module '${name}' exports`);
5987
+ }
5988
+ const extension = Object.freeze({
5989
+ manifest: Object.freeze({
5990
+ version: 1,
5991
+ name: manifest.name,
5992
+ capabilities: readStringList(manifest.capabilities ?? [], "Extension capabilities"),
5993
+ globals: readStringList(manifest.globals ?? [], "Extension globals"),
5994
+ modules: Object.freeze(modules)
5995
+ })
5996
+ });
5997
+ definitions.set(extension, input.setup);
5998
+ return extension;
5999
+ }
6000
+ function getExtensionSetup(extension) {
6001
+ const setup = definitions.get(extension);
6002
+ if (setup === void 0) throw new TypeError("Extensions must be created by defineExtension.");
6003
+ return setup;
6004
+ }
6005
+
5925
6006
  // packages/safe-js/src/observability/otel.ts
5926
6007
  var noopOtelSink = {
5927
6008
  startSpan: () => noopOtelSpan,
@@ -6126,6 +6207,144 @@ function copyFloat32Storage(value, state) {
6126
6207
  return new Float32Array(buffer, storage.byteOffset, storage.length);
6127
6208
  }
6128
6209
 
6210
+ // packages/safe-js/src/interp/host-capabilities.ts
6211
+ var hostObjects = /* @__PURE__ */ new WeakMap();
6212
+ var guestObjects = /* @__PURE__ */ new WeakMap();
6213
+ var guestCallbacks = /* @__PURE__ */ new WeakMap();
6214
+ var guestReferences = /* @__PURE__ */ new WeakMap();
6215
+ function createGuestReference(root, owner, assertActive) {
6216
+ const reference = Object.freeze(/* @__PURE__ */ Object.create(null));
6217
+ guestReferences.set(reference, { root, owner, assertActive });
6218
+ return reference;
6219
+ }
6220
+ function readGuestReference(reference, owner) {
6221
+ const state = typeof reference === "object" && reference !== null ? guestReferences.get(reference) : void 0;
6222
+ if (state === void 0 || state.owner !== owner)
6223
+ throw new TypeError("Foreign or invalid guest reference.");
6224
+ state.assertActive();
6225
+ if (state.root === void 0) throw new TypeError("Guest reference is revoked.");
6226
+ return state.root[0];
6227
+ }
6228
+ function revokeGuestReference(reference, owner) {
6229
+ const state = guestReferences.get(reference);
6230
+ if (state === void 0 || state.owner !== owner) throw new TypeError("Foreign guest reference.");
6231
+ state.root = void 0;
6232
+ }
6233
+ function createLiveHostObject(definition, controller) {
6234
+ const input = readDataRecord(definition, "Host object definition");
6235
+ if (Object.keys(input).some((key) => key !== "properties" && key !== "methods"))
6236
+ throw new TypeError("Unknown host object definition field.");
6237
+ const properties = /* @__PURE__ */ new Map();
6238
+ for (const [name, inputProperty] of Object.entries(
6239
+ readDataRecord(input.properties ?? {}, "Host properties")
6240
+ )) {
6241
+ const property = readDataRecord(inputProperty, `Host property '${name}'`);
6242
+ if (Object.keys(property).some((key) => key !== "get" && key !== "set"))
6243
+ throw new TypeError("Unknown host property field.");
6244
+ if (property.get !== void 0 && typeof property.get !== "function" || property.set !== void 0 && typeof property.set !== "function")
6245
+ throw new TypeError("Host property operations must be functions.");
6246
+ properties.set(name, property);
6247
+ }
6248
+ const operations = readDataRecord(input.methods ?? {}, "Host methods");
6249
+ for (const [name, operation] of Object.entries(operations)) {
6250
+ if (typeof operation !== "function") throw new TypeError("Host methods must be functions.");
6251
+ if (properties.has(name)) throw new TypeError(`Conflicting host member '${name}'.`);
6252
+ }
6253
+ for (const name of [...properties.keys(), ...Object.keys(operations)]) {
6254
+ if (["constructor", "prototype", "__proto__"].includes(name))
6255
+ throw new TypeError(`Reserved host member '${name}'.`);
6256
+ }
6257
+ controller.assertActive();
6258
+ controller.chargeWork(properties.size + Object.keys(operations).length + 1);
6259
+ const host = Object.freeze(/* @__PURE__ */ Object.create(null));
6260
+ const guest = Object.freeze(/* @__PURE__ */ Object.create(null));
6261
+ const methods = new Map(
6262
+ Object.entries(operations).map(([name, operation]) => [
6263
+ name,
6264
+ controller.method(operation)
6265
+ ])
6266
+ );
6267
+ const state = { host, guest, controller, properties, methods };
6268
+ hostObjects.set(host, state);
6269
+ guestObjects.set(guest, state);
6270
+ return host;
6271
+ }
6272
+ function isGuestHostObject(value) {
6273
+ return typeof value === "object" && value !== null && guestObjects.has(value);
6274
+ }
6275
+ function isLiveCapability(value) {
6276
+ return (typeof value === "object" && value !== null || typeof value === "function") && (hostObjects.has(value) || guestObjects.has(value) || guestCallbacks.has(value) || guestReferences.has(value));
6277
+ }
6278
+ function importHostCapability(value, owner) {
6279
+ if (guestReferences.has(value)) return readGuestReference(value, owner);
6280
+ const object = hostObjects.get(value);
6281
+ if (object !== void 0) {
6282
+ if (object.controller.owner !== owner) throw new TypeError("Foreign realm host capability.");
6283
+ object.controller.assertActive();
6284
+ return object.guest;
6285
+ }
6286
+ const callback = guestCallbacks.get(value);
6287
+ if (callback !== void 0) {
6288
+ if (callback.owner !== owner) throw new TypeError("Foreign realm guest callback.");
6289
+ callback.assertActive();
6290
+ if (callback.closure === void 0) throw new TypeError("Guest callback is revoked.");
6291
+ return callback.closure;
6292
+ }
6293
+ throw new TypeError("Unsupported live capability conversion.");
6294
+ }
6295
+ function exportHostCapability(value, owner) {
6296
+ const state = guestObjects.get(value);
6297
+ if (state === void 0 || state.controller.owner !== owner)
6298
+ throw new TypeError("Foreign realm host capability.");
6299
+ state.controller.assertActive();
6300
+ return state.host;
6301
+ }
6302
+ function registerGuestCallback(callback, state) {
6303
+ guestCallbacks.set(callback, state);
6304
+ }
6305
+ function readGuestCallback(callback, owner) {
6306
+ const state = typeof callback === "function" ? guestCallbacks.get(callback) : void 0;
6307
+ if (state === void 0 || state.owner !== owner)
6308
+ throw new TypeError("Foreign or invalid guest callback.");
6309
+ state.assertActive();
6310
+ if (state.closure === void 0) throw new TypeError("Guest callback is revoked.");
6311
+ return state.closure;
6312
+ }
6313
+ function revokeGuestCallback(callback, owner) {
6314
+ const state = guestCallbacks.get(callback);
6315
+ if (state === void 0 || state.owner !== owner) throw new TypeError("Foreign guest callback.");
6316
+ state.closure = void 0;
6317
+ }
6318
+ function revokeHostObject(value, owner) {
6319
+ const state = hostObjects.get(value);
6320
+ if (state === void 0 || state.controller.owner !== owner)
6321
+ throw new TypeError("Foreign host object.");
6322
+ state.properties.clear();
6323
+ state.methods.clear();
6324
+ }
6325
+ function getHostObjectMember(value, key) {
6326
+ const state = guestObjects.get(value);
6327
+ state.controller.assertActive();
6328
+ state.controller.chargeWork();
6329
+ const property = state.properties.get(key);
6330
+ if (property !== void 0)
6331
+ return property.get === void 0 ? void 0 : state.controller.read(property.get);
6332
+ return state.methods.get(key);
6333
+ }
6334
+ function setHostObjectMember(value, key, entry) {
6335
+ const state = guestObjects.get(value);
6336
+ state.controller.assertActive();
6337
+ state.controller.chargeWork();
6338
+ const property = state.properties.get(key);
6339
+ if (property?.set === void 0) throw new TypeError(`Host property '${key}' is not writable.`);
6340
+ state.controller.write(property.set, entry);
6341
+ }
6342
+ function getHostObjectKeys(value) {
6343
+ const state = guestObjects.get(value);
6344
+ state.controller.assertActive();
6345
+ return [...state.properties.keys(), ...state.methods.keys()];
6346
+ }
6347
+
6129
6348
  // packages/safe-js/src/interp/values.ts
6130
6349
  import { types as nodeTypes } from "node:util";
6131
6350
 
@@ -6246,7 +6465,7 @@ async function flushPromiseJobs() {
6246
6465
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
6247
6466
 
6248
6467
  // packages/safe-js/src/snapshot/validation.ts
6249
- import { types } from "node:util";
6468
+ import { types as types2 } from "node:util";
6250
6469
 
6251
6470
  // packages/safe-js/src/interp/arguments.ts
6252
6471
  var sandboxArgumentsBrand = /* @__PURE__ */ Symbol("SandboxArguments");
@@ -6443,6 +6662,7 @@ function setSandboxPrototype(value, prototype, budget) {
6443
6662
  else prototypes.set(value, prototype);
6444
6663
  }
6445
6664
  function isPrototypeRecord(value) {
6665
+ if (isGuestHostObject(value)) return false;
6446
6666
  if (isSandboxClosure(value) || isSandboxGenerator(value) || isSandboxMap(value) || isSandboxPromise(value) || isSandboxRegex(value) || isSandboxSet(value))
6447
6667
  return false;
6448
6668
  const prototype = Object.getPrototypeOf(value);
@@ -6455,6 +6675,7 @@ function hasManagedDescriptors(value) {
6455
6675
  return descriptorObjects.has(value);
6456
6676
  }
6457
6677
  function hasGuestObjectState(value) {
6678
+ if (isLiveCapability(value)) return true;
6458
6679
  if (functionProperties.has(value) || prototypes.has(value)) return true;
6459
6680
  return descriptorObjects.has(value) && Object.values(Object.getOwnPropertyDescriptors(value)).some(
6460
6681
  (descriptor) => !descriptor.enumerable || !descriptor.configurable || !descriptor.writable
@@ -7088,7 +7309,7 @@ function validateGenericValue(value, path, depth, state) {
7088
7309
  if (typeof value === "object" && value !== null && hasGuestObjectState(value)) {
7089
7310
  fail("invalidState", path, "guest function properties, prototype links and custom descriptors cannot be restored");
7090
7311
  }
7091
- if (state.dataPropertiesOnly && types.isProxy(value)) {
7312
+ if (state.dataPropertiesOnly && types2.isProxy(value)) {
7092
7313
  fail("invalidType", path, "proxy objects are not snapshot data");
7093
7314
  }
7094
7315
  if (depth > state.limits.maxDepth)
@@ -9178,6 +9399,7 @@ function createSandboxClosure(input) {
9178
9399
  return Object.freeze(closure);
9179
9400
  }
9180
9401
  function ownEnumerableSandboxEntries(value) {
9402
+ if (isGuestHostObject(value)) return getHostObjectKeys(value).map((key) => [key, getHostObjectMember(value, key)]);
9181
9403
  if (value === null || value === void 0) throw new TypeError("Cannot convert undefined or null to object.");
9182
9404
  if (isGuestClosure(value)) return Object.entries(value.properties ?? {});
9183
9405
  if (isSandboxClosure(value) || isSandboxGenerator(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxPromise(value) || isSandboxRegex(value)) return [];
@@ -9330,6 +9552,10 @@ function measureSandboxData(values, options = {}) {
9330
9552
  assertSandboxDataDepth(depth);
9331
9553
  seen.add(value);
9332
9554
  usage += 1;
9555
+ if (isGuestHostObject(value)) {
9556
+ for (const key of getHostObjectKeys(value)) usage += key.length + 1;
9557
+ return;
9558
+ }
9333
9559
  const prototype = getSandboxPrototype(value);
9334
9560
  if (prototype !== null) visit(prototype, depth + 1);
9335
9561
  if (isFloat32Array(value)) {
@@ -9472,6 +9698,7 @@ function copyToSandbox(value, state, path = "<root>", cloneSandboxCollections =
9472
9698
  if (isSandboxPrimitive(value)) {
9473
9699
  return value;
9474
9700
  }
9701
+ if (isLiveCapability(value)) throw new TypeError("Live capabilities require their owning realm bridge.");
9475
9702
  if (isSandboxClosure(value) || isSandboxGenerator(value) || isSandboxRegex(value) || isSandboxPromise(value)) {
9476
9703
  return value;
9477
9704
  }
@@ -9635,6 +9862,10 @@ function copyFromSandbox(value, state, path = "<root>", options, depth = 0) {
9635
9862
  if (isSandboxPrimitive(value)) {
9636
9863
  return value;
9637
9864
  }
9865
+ if (isGuestHostObject(value)) {
9866
+ if (options.unwrapHostObject === void 0) throw new TypeError("Live capabilities require their owning realm bridge.");
9867
+ return options.unwrapHostObject(value);
9868
+ }
9638
9869
  if (nodeTypes.isProxy(value)) throw new TypeError("Unsupported proxy sandbox value.");
9639
9870
  if (!isSandboxClosure(value) && hasGuestObjectState(value)) {
9640
9871
  throw new TypeError("Guest prototype links and custom descriptors cannot be copied as data.");
@@ -22240,128 +22471,6 @@ function hasOnlyRegexLiteralDiagnostics(diagnostics) {
22240
22471
  );
22241
22472
  }
22242
22473
 
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
22474
  // packages/safe-js/src/interp/generator.ts
22366
22475
  function createGeneratorChannel(body) {
22367
22476
  let state = "unstarted";
@@ -25003,9 +25112,10 @@ async function interpret(node, options = {}) {
25003
25112
  peakDataSize: { enumerable: false, value: 0, writable: true }
25004
25113
  });
25005
25114
  const activeLoopIterations = /* @__PURE__ */ new Map();
25006
- const jobs = new SandboxJobQueue();
25115
+ const jobs = options.jobs ?? new SandboxJobQueue();
25007
25116
  hoistVarDeclarations(node, scope);
25008
25117
  const context = {
25118
+ assertActive: options.assertActive,
25009
25119
  compilation,
25010
25120
  budget,
25011
25121
  callStack: [],
@@ -25028,9 +25138,9 @@ async function interpret(node, options = {}) {
25028
25138
  };
25029
25139
  const evaluation = await withCancellationSignal(
25030
25140
  options.signal,
25031
- () => jobs.run(() => evaluateNode(node, context))
25141
+ () => options.nested ? runAsyncPrefix(() => evaluateNode(node, context)) : jobs.run(() => evaluateNode(node, context))
25032
25142
  );
25033
- await jobs.drain();
25143
+ if (!options.nested) await jobs.drain();
25034
25144
  const snapshot = scope.snapshot();
25035
25145
  reconcileDataBudget(
25036
25146
  budget,
@@ -25085,6 +25195,7 @@ async function interpret(node, options = {}) {
25085
25195
  }
25086
25196
  }
25087
25197
  async function evaluateNode(node, context) {
25198
+ context.assertActive?.();
25088
25199
  const replayWait = promiseReplayContext.getStore()?.beforeNode(node.nodeId);
25089
25200
  if (replayWait !== void 0) await suspendJob(replayWait);
25090
25201
  assertPromiseExecutionAllowed();
@@ -26056,6 +26167,7 @@ function forInObject(value) {
26056
26167
  return void 0;
26057
26168
  }
26058
26169
  function forInKeys(object, budget) {
26170
+ if (isGuestHostObject(object)) return getHostObjectKeys(object);
26059
26171
  const keys = [];
26060
26172
  const seen = /* @__PURE__ */ new Set();
26061
26173
  let depth = 0;
@@ -26073,6 +26185,7 @@ function forInKeys(object, budget) {
26073
26185
  return keys;
26074
26186
  }
26075
26187
  function hasForInProperty(object, key, budget) {
26188
+ if (isGuestHostObject(object)) return getHostObjectKeys(object).includes(key);
26076
26189
  let depth = 0;
26077
26190
  for (let current = object; current !== null; current = getSandboxPrototype(current)) {
26078
26191
  if (depth > 0) budget.visitNode();
@@ -26564,6 +26677,7 @@ async function evaluateMemberExpression(node, context) {
26564
26677
  };
26565
26678
  }
26566
26679
  function getPropertyValue(target, property, context) {
26680
+ if (isGuestHostObject(target)) return getHostObjectMember(target, String(property));
26567
26681
  if (typeof target === "string") return getStringMember(target, property, context.budget);
26568
26682
  if (typeof target === "number") return getNumberMember(target, property, context.budget);
26569
26683
  if (typeof target === "boolean") return void 0;
@@ -27270,6 +27384,7 @@ function isPlainSandboxObject(value) {
27270
27384
  return typeof value === "object" && value !== null && !Array.isArray(value) && !isSandboxClosure(value) && !isSandboxMap(value) && !isSandboxSet(value) && !isSandboxPromise(value) && !isSandboxRegex(value);
27271
27385
  }
27272
27386
  function getMemberValue(target, property, context) {
27387
+ if (isGuestHostObject(target)) return getHostObjectMember(target, String(property));
27273
27388
  let current = target;
27274
27389
  let depth = 0;
27275
27390
  while (typeof current === "object" && current !== null) {
@@ -27294,6 +27409,10 @@ function getArrayMemberValue(target, property, context) {
27294
27409
  return getArrayMember(target, property, createArrayMethodOptions(context));
27295
27410
  }
27296
27411
  function setSandboxProperty(target, property, value, budget) {
27412
+ if (isGuestHostObject(target)) {
27413
+ setHostObjectMember(target, String(property), value);
27414
+ return;
27415
+ }
27297
27416
  const prototypeOwner = target;
27298
27417
  if (isGuestClosure(target)) target = materializeFunctionProperties(target);
27299
27418
  if (isFloat32Array(target)) {
@@ -27338,6 +27457,7 @@ function setSandboxProperty(target, property, value, budget) {
27338
27457
  }
27339
27458
  }
27340
27459
  function deleteSandboxProperty(target, property) {
27460
+ if (isGuestHostObject(target)) throw new TypeError("Live host properties cannot be deleted.");
27341
27461
  if (isGuestClosure(target)) target = materializeFunctionProperties(target);
27342
27462
  if (Array.isArray(target)) {
27343
27463
  assertCollectionMutable(target);
@@ -27903,7 +28023,7 @@ function wrapCallerInjectedBindings(bindings, options) {
27903
28023
  const copied = Object.fromEntries(
27904
28024
  Object.entries(bindings).map(([name, value]) => [
27905
28025
  name,
27906
- typeof value === "function" ? wrapCallerInjectedFunction(name, value, { ...options, capabilityPath: [name] }, state) : copyHostValueToSandbox(
28026
+ typeof value === "function" && !isLiveCapability(value) ? wrapCallerInjectedFunction(name, value, { ...options, capabilityPath: [name] }, state) : copyHostValueToSandbox(
27907
28027
  value,
27908
28028
  [],
27909
28029
  { ...options, operation: name, capabilityPath: [name] },
@@ -27924,9 +28044,10 @@ function wrapCallerInjectedFunction(name, value, options, state) {
27924
28044
  const bindingName = name === "default" && value.name.length > 0 ? value.name : name;
27925
28045
  const callable = value;
27926
28046
  return createSandboxClosure({
27927
- ...isAsyncFunction(callable) ? { async: true } : {},
28047
+ ...isAsyncFunction(callable) && !options.realm?.awaitResult(callable) ? { async: true } : {},
27928
28048
  cancellationSignal: options.signal,
27929
28049
  call: (args, context) => {
28050
+ options.realm?.assertActive();
27930
28051
  const operationLease = options.budget.acquireCompileOwner(false, options.compileOwner);
27931
28052
  const compilation = new CompileScope(operationLease.owner);
27932
28053
  try {
@@ -27942,9 +28063,10 @@ function wrapCallerInjectedFunction(name, value, options, state) {
27942
28063
  seen: /* @__PURE__ */ new WeakMap(),
27943
28064
  restored: []
27944
28065
  };
27945
- const hostArgs = deepCopyFromSandbox([...args], {
28066
+ const copyArguments = (values) => deepCopyFromSandbox([...values], {
27946
28067
  compilation,
27947
- wrapClosure: (closure) => wrapSandboxClosureForHost(
28068
+ unwrapHostObject: options.realm === void 0 ? void 0 : (object) => exportHostCapability(object, options.realm.owner),
28069
+ wrapClosure: (closure) => options.realm?.wrapCallback(closure) ?? wrapSandboxClosureForHost(
27948
28070
  closure,
27949
28071
  stackFrames,
27950
28072
  options.budget,
@@ -27952,11 +28074,26 @@ function wrapCallerInjectedFunction(name, value, options, state) {
27952
28074
  callbacks
27953
28075
  )
27954
28076
  });
28077
+ const captured = options.realm?.captureArguments(callable, args, copyArguments);
28078
+ const hostArgs = captured?.args ?? copyArguments(args);
27955
28079
  const hostCalls = options.hostCalls;
27956
28080
  const operation = options.operation ?? bindingName;
27957
28081
  const moduleId = options.moduleId ?? "<bindings>";
27958
28082
  const policy = readHostOperationPolicy(value) ?? readRegisteredPendingHostCallPolicy(moduleId, operation) ?? "re-issue";
27959
28083
  if (hostCalls === void 0) {
28084
+ if (options.realm !== void 0) {
28085
+ let result;
28086
+ try {
28087
+ result = options.realm.invoke(callable, () => Reflect.apply(callable, void 0, hostArgs));
28088
+ } catch (error) {
28089
+ captured.rollback();
28090
+ throw error;
28091
+ }
28092
+ if (options.realm.awaitResult(callable)) {
28093
+ return Promise.resolve(result).then((value2) => copyHostResultToSandbox(value2, stackFrames, options));
28094
+ }
28095
+ return copyHostResultToSandbox(result, stackFrames, options);
28096
+ }
27960
28097
  return copyHostResultToSandbox(
27961
28098
  invokeHostCallback(() => Reflect.apply(callable, void 0, hostArgs), options),
27962
28099
  stackFrames,
@@ -28494,6 +28631,10 @@ function wrapHostPromiseWithSignal(promise, signal) {
28494
28631
  }
28495
28632
  function copyHostValueToSandbox(value, stackFrames, options, state, path) {
28496
28633
  const { budget } = options;
28634
+ if (isLiveCapability(value)) {
28635
+ if (options.realm === void 0 || options.errorData || options.hostCalls !== void 0) throw new TypeError("Live capabilities are not portable replay or error data.");
28636
+ return importHostCapability(value, options.realm.owner);
28637
+ }
28497
28638
  if (value === null || value === void 0 || typeof value === "number" || typeof value === "boolean") {
28498
28639
  return value;
28499
28640
  }
@@ -28812,673 +28953,418 @@ function describeValue2(value) {
28812
28953
  return typeof value;
28813
28954
  }
28814
28955
 
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;
28956
+ // packages/safe-js/src/random.ts
28957
+ import { randomInt } from "node:crypto";
28958
+
28959
+ // packages/safe-js/src/interp/globals/math.ts
28960
+ var mathMethods = {
28961
+ abs: Math.abs,
28962
+ acos: Math.acos,
28963
+ acosh: Math.acosh,
28964
+ asin: Math.asin,
28965
+ asinh: Math.asinh,
28966
+ atan: Math.atan,
28967
+ atan2: Math.atan2,
28968
+ atanh: Math.atanh,
28969
+ ceil: Math.ceil,
28970
+ cbrt: Math.cbrt,
28971
+ clz32: Math.clz32,
28972
+ cos: Math.cos,
28973
+ cosh: Math.cosh,
28974
+ exp: Math.exp,
28975
+ expm1: Math.expm1,
28976
+ floor: Math.floor,
28977
+ f16round,
28978
+ fround: Math.fround,
28979
+ hypot: Math.hypot,
28980
+ imul: Math.imul,
28981
+ log: Math.log,
28982
+ log1p: Math.log1p,
28983
+ log10: Math.log10,
28984
+ log2: Math.log2,
28985
+ max: Math.max,
28986
+ min: Math.min,
28987
+ pow: Math.pow,
28988
+ round: Math.round,
28989
+ sign: Math.sign,
28990
+ sin: Math.sin,
28991
+ sinh: Math.sinh,
28992
+ sqrt: Math.sqrt,
28993
+ tan: Math.tan,
28994
+ tanh: Math.tanh,
28995
+ trunc: Math.trunc
28996
+ };
28997
+ function f16round(value) {
28998
+ const number = +value;
28999
+ if (!Number.isFinite(number) || number === 0) {
29000
+ return number;
29001
+ }
29002
+ const magnitude = Math.abs(number);
29003
+ if (magnitude >= 65520) {
29004
+ return number < 0 ? -Infinity : Infinity;
29005
+ }
29006
+ let quantum = 2 ** -24;
29007
+ let boundary = 2 ** -13;
29008
+ for (let exponent = -13; exponent <= 15 && magnitude >= boundary; exponent += 1) {
29009
+ quantum *= 2;
29010
+ boundary *= 2;
29011
+ }
29012
+ const scaled = magnitude / quantum;
29013
+ const lower = Math.floor(scaled);
29014
+ const remainder = scaled - lower;
29015
+ const rounded = (remainder > 0.5 || remainder === 0.5 && lower % 2 !== 0 ? lower + 1 : lower) * quantum;
29016
+ return number < 0 ? -rounded : rounded;
28825
29017
  }
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());
29018
+ function createMathGlobals(options = {}) {
29019
+ const random = options.random ?? Math.random;
29020
+ const mathObject = {
29021
+ E: Math.E,
29022
+ LN2: Math.LN2,
29023
+ LN10: Math.LN10,
29024
+ LOG2E: Math.LOG2E,
29025
+ LOG10E: Math.LOG10E,
29026
+ PI: Math.PI,
29027
+ SQRT1_2: Math.SQRT1_2,
29028
+ SQRT2: Math.SQRT2,
29029
+ random: createSandboxClosure({ sandbox: true, call: () => random(), name: "random" })
29030
+ };
29031
+ for (const [name, method] of Object.entries(mathMethods)) {
29032
+ mathObject[name] = createSandboxClosure({
29033
+ sandbox: true,
29034
+ call: (args) => Reflect.apply(method, Math, args),
29035
+ name
29036
+ });
29037
+ }
29038
+ return {
29039
+ Infinity: Infinity,
29040
+ Math: mathObject,
29041
+ NaN: Number.NaN
29042
+ };
29043
+ }
29044
+ function createSeededRandom(seed) {
29045
+ let state = normalizeSeed(seed);
29046
+ return {
29047
+ next: () => {
29048
+ state = Math.imul(state, 1664525) + 1013904223 >>> 0;
29049
+ return state / 4294967296;
28861
29050
  },
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);
29051
+ snapshot: () => state,
29052
+ restore: (nextState) => {
29053
+ state = normalizeSeed(nextState);
29054
+ }
29055
+ };
29056
+ }
29057
+ function normalizeSeed(seed) {
29058
+ if (!Number.isFinite(seed)) {
29059
+ throw new TypeError("Seeded random requires a finite numeric seed.");
29060
+ }
29061
+ return Math.trunc(seed) >>> 0;
29062
+ }
29063
+
29064
+ // packages/safe-js/src/random.ts
29065
+ function createReplayableRandom(options = {}) {
29066
+ const snapshot = options.snapshot;
29067
+ const saved = snapshot?.random;
29068
+ let initialState = options.seed;
29069
+ if (saved !== void 0) {
29070
+ const hasLoopState = typeof snapshot?.loopIterations === "object" && snapshot.loopIterations !== null && Object.keys(snapshot.loopIterations).length > 0;
29071
+ const replaysFromStart = snapshot?.replay !== void 0 || Array.isArray(snapshot?.pendingAwaits) && snapshot.pendingAwaits.length > 0 && !hasLoopState;
29072
+ initialState = replaysFromStart ? saved.initialState ?? saved.seed : saved.resumeState ?? saved.state;
29073
+ }
29074
+ const generator = createSeededRandom(initialState ?? randomInt(4294967296));
29075
+ return { seed: saved?.seed ?? generator.snapshot(), ...generator };
29076
+ }
29077
+
29078
+ // packages/safe-js/src/realm.ts
29079
+ import { AsyncLocalStorage as AsyncLocalStorage6 } from "node:async_hooks";
29080
+ import { types as types3 } from "node:util";
29081
+
29082
+ // packages/safe-js/src/interp/globals/console-json.ts
29083
+ function createConsoleJsonGlobals(options) {
29084
+ const sink = options.sink ?? console;
29085
+ return {
29086
+ JSON: {
29087
+ parse: createSandboxClosure({
29088
+ sandbox: true,
29089
+ call: async ([text]) => parseJson(text, options.budget),
29090
+ name: "parse"
29091
+ }),
29092
+ stringify: createSandboxClosure({
29093
+ sandbox: true,
29094
+ call: async ([value, replacer, indent]) => stringifyJson(value, replacer, indent, options.budget),
29095
+ name: "stringify"
29096
+ })
28875
29097
  },
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) {
29098
+ console: options.hostCalls === void 0 ? {
29099
+ error: createSandboxClosure({
29100
+ sandbox: true,
29101
+ call: async (args, context) => {
29102
+ const operation = options.budget.acquireCompileOwner(
29103
+ false,
29104
+ options.compileOwner ?? context?.compilation?.owner
29105
+ );
29106
+ const compilation = new CompileScope(operation.owner);
28880
29107
  try {
28881
- return Promise.resolve(serializeRunSnapshot(finalSnapshot));
28882
- } catch (error) {
28883
- return Promise.reject(error);
29108
+ sink.error(...args.map((value) => deepCopyFromSandbox(value, { compilation })));
29109
+ return void 0;
29110
+ } finally {
29111
+ compilation.dispose();
29112
+ operation.release();
28884
29113
  }
29114
+ },
29115
+ name: "error"
29116
+ }),
29117
+ log: createSandboxClosure({
29118
+ sandbox: true,
29119
+ call: async (args, context) => {
29120
+ const operation = options.budget.acquireCompileOwner(
29121
+ false,
29122
+ options.compileOwner ?? context?.compilation?.owner
29123
+ );
29124
+ const compilation = new CompileScope(operation.owner);
29125
+ try {
29126
+ sink.log(...args.map((value) => deepCopyFromSandbox(value, { compilation })));
29127
+ return void 0;
29128
+ } finally {
29129
+ compilation.dispose();
29130
+ operation.release();
29131
+ }
29132
+ },
29133
+ name: "log"
29134
+ })
29135
+ } : wrapCallerInjectedBindings(
29136
+ {
29137
+ error: (...args) => {
29138
+ sink.error(...args);
29139
+ return void 0;
29140
+ },
29141
+ log: (...args) => {
29142
+ sink.log(...args);
29143
+ return void 0;
28885
29144
  }
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;
29145
+ },
29146
+ {
29147
+ budget: options.budget,
29148
+ compileOwner: options.compileOwner,
29149
+ hostCalls: options.hostCalls,
29150
+ moduleId: "<console>"
28904
29151
  }
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
- }
29152
+ )
28918
29153
  };
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;
28938
- }
28939
29154
  }
28940
- function isDataBudgetError(error) {
28941
- return typeof error === "object" && error !== null && "code" in error && error.code === "budgetExceeded" && "budget" in error && error.budget === "dataSize";
29155
+ function parseJson(input, budget) {
29156
+ const text = budget.allocateString(toJsonParseText(input));
29157
+ return copyJsonToSandbox(JSON.parse(text), budget);
28942
29158
  }
28943
- function dump(result, options = {}) {
28944
- const controller = readDumpController(result);
28945
- if (controller !== void 0) {
28946
- return controller.requestSnapshot(options);
29159
+ async function stringifyJson(value, replacer, indent, budget) {
29160
+ if (replacer !== void 0 && replacer !== null && !isSandboxClosure(replacer)) {
29161
+ throw new TypeError(
29162
+ "JSON.stringify(value, replacer, indent) only supports function, null, or undefined replacers."
29163
+ );
28947
29164
  }
28948
- if (hasSnapshot(result)) {
28949
- try {
28950
- return Promise.resolve(serializeRunSnapshot(result.snapshot));
28951
- } catch (error) {
28952
- return Promise.reject(error);
28953
- }
29165
+ if (indent !== void 0 && typeof indent !== "number" && typeof indent !== "string") {
29166
+ throw new TypeError(
29167
+ "JSON.stringify(value, replacer, indent) requires indent to be a string, number, or undefined."
29168
+ );
28954
29169
  }
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);
29170
+ const holder = {};
29171
+ defineDataProperty(holder, "", value);
29172
+ const output = await stringifyProperty("", holder, {
29173
+ budget,
29174
+ gap: normalizeStringifyGap(indent),
29175
+ replacer: isSandboxClosure(replacer) ? replacer : void 0,
29176
+ stack: []
28960
29177
  });
28961
- }
28962
- function dumpCurrent(result) {
28963
- const controller = readDumpController(result);
28964
- if (controller !== void 0) {
28965
- return controller.requestCurrentSnapshot();
29178
+ if (output === void 0) {
29179
+ return void 0;
28966
29180
  }
28967
- return dump(result);
28968
- }
28969
- function serializeRunSnapshot(snapshot) {
28970
- return serializeSafeJSSnapshot(snapshot);
29181
+ return budget.allocateString(output);
28971
29182
  }
28972
- function hasSnapshot(value) {
28973
- return typeof value === "object" && value !== null && Object.prototype.hasOwnProperty.call(value, "snapshot");
28974
- }
28975
- function readDumpController(value) {
28976
- if (typeof value !== "object" || value === null) {
28977
- return void 0;
29183
+ function toJsonParseText(input) {
29184
+ if (Array.isArray(input)) {
29185
+ return input.map((entry) => entry === null || entry === void 0 ? "" : toJsonParseText(entry)).join(",");
28978
29186
  }
28979
- return value[RUN_DUMP_CONTROLLER];
28980
- }
28981
-
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;
29187
+ if (typeof input === "object" && input !== null) {
29188
+ return "[object Object]";
28986
29189
  }
28987
- const code = error.code;
28988
- return typeof code === "string" ? code : void 0;
29190
+ return String(input);
28989
29191
  }
28990
- function hasOwnErrorCode(error, code) {
28991
- return getOwnErrorCode(error) === code;
29192
+ async function stringifyProperty(key, holder, state, indent = "") {
29193
+ let value = getOwnDataValue(holder, key);
29194
+ if (isStringifyContainer(value)) {
29195
+ const toJSON = getOwnDataValue(value, "toJSON");
29196
+ if (isSandboxClosure(toJSON)) {
29197
+ value = await callStringifyClosure(toJSON, [key], value, state);
29198
+ }
29199
+ }
29200
+ if (state.replacer !== void 0) {
29201
+ value = await callStringifyClosure(state.replacer, [key, toSandboxValue(value)], holder, state);
29202
+ }
29203
+ return stringifyValue(value, state, indent);
28992
29204
  }
28993
-
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;
29205
+ async function stringifyValue(value, state, indent) {
29206
+ if (value === null) {
29207
+ return "null";
29007
29208
  }
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
- }
29209
+ if (typeof value === "string") {
29210
+ return quoteJsonString(value);
29023
29211
  }
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
- );
29212
+ if (typeof value === "number") {
29213
+ return Number.isFinite(value) ? String(value) : "null";
29032
29214
  }
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
- });
29215
+ if (typeof value === "boolean") {
29216
+ return value ? "true" : "false";
29043
29217
  }
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
- }
29218
+ if (typeof value === "bigint") {
29219
+ throw new TypeError("Do not know how to serialize a BigInt.");
29220
+ }
29221
+ if (isSandboxPromise(value)) return "{}";
29222
+ if (value === void 0 || isSandboxClosure(value)) {
29223
+ return void 0;
29224
+ }
29225
+ if (Array.isArray(value)) {
29226
+ return stringifyArray(value, state, indent);
29227
+ }
29228
+ if (isStringifyObject(value)) {
29229
+ return stringifyObject(value, state, indent);
29079
29230
  }
29231
+ return void 0;
29080
29232
  }
29081
- async function assertParentDirectoryExists(snapshotPath, parentPath) {
29233
+ async function stringifyArray(value, state, indent) {
29234
+ enterStringifyObject(value, state);
29082
29235
  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
- );
29236
+ const nextIndent = indent + state.gap;
29237
+ const entries = [];
29238
+ for (let index = 0; index < value.length; index += 1) {
29239
+ entries.push(await stringifyProperty(String(index), value, state, nextIndent) ?? "null");
29088
29240
  }
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
- );
29241
+ if (entries.length === 0) {
29242
+ return "[]";
29097
29243
  }
29098
- throw error;
29244
+ if (state.gap === "") {
29245
+ return `[${entries.join(",")}]`;
29246
+ }
29247
+ return `[
29248
+ ${nextIndent}${entries.join(`,
29249
+ ${nextIndent}`)}
29250
+ ${indent}]`;
29251
+ } finally {
29252
+ leaveStringifyObject(value, state);
29099
29253
  }
29100
29254
  }
29101
- async function writeSnapshotOnce(temporaryPath, snapshotPath, contents) {
29102
- let temporaryCreated = false;
29103
- let renamed = false;
29255
+ async function stringifyObject(value, state, indent) {
29256
+ enterStringifyObject(value, state);
29104
29257
  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);
29258
+ const nextIndent = indent + state.gap;
29259
+ const entries = [];
29260
+ for (const key of Object.keys(value)) {
29261
+ const serialized = await stringifyProperty(key, value, state, nextIndent);
29262
+ if (serialized !== void 0) {
29263
+ entries.push(`${quoteJsonString(key)}:${state.gap === "" ? "" : " "}${serialized}`);
29111
29264
  }
29112
- throw error;
29113
29265
  }
29114
- await rename(temporaryPath, snapshotPath);
29115
- renamed = true;
29116
- } finally {
29117
- if (temporaryCreated && !renamed) {
29118
- await removeTemporarySnapshot(temporaryPath).catch(() => void 0);
29266
+ if (entries.length === 0) {
29267
+ return "{}";
29268
+ }
29269
+ if (state.gap === "") {
29270
+ return `{${entries.join(",")}}`;
29119
29271
  }
29272
+ return `{
29273
+ ${nextIndent}${entries.join(`,
29274
+ ${nextIndent}`)}
29275
+ ${indent}}`;
29276
+ } finally {
29277
+ leaveStringifyObject(value, state);
29120
29278
  }
29121
29279
  }
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
- }
29280
+ async function callStringifyClosure(closure, args, thisValue, state) {
29281
+ const result = await closure.call(args, { stack: [], thisValue });
29282
+ if (isSandboxPromise(result) && result.synchronousPrefix !== void 0) {
29283
+ await result.synchronousPrefix;
29133
29284
  }
29285
+ return allocateProducedSandboxValue(result, state.budget);
29134
29286
  }
29135
- async function removeTemporarySnapshot(temporaryPath) {
29136
- try {
29137
- await unlink(temporaryPath);
29138
- } catch (error) {
29139
- if (!hasErrorCode(error, "ENOENT")) {
29140
- throw error;
29141
- }
29287
+ function enterStringifyObject(value, state) {
29288
+ if (state.stack.includes(value)) {
29289
+ throw new TypeError("Converting circular structure to JSON.");
29142
29290
  }
29291
+ state.stack.push(value);
29143
29292
  }
29144
- async function delay(ms) {
29145
- if (ms === 0) {
29293
+ function leaveStringifyObject(value, state) {
29294
+ if (state.stack.at(-1) === value) {
29295
+ state.stack.pop();
29146
29296
  return;
29147
29297
  }
29148
- await new Promise((resolve) => setTimeout(resolve, ms));
29298
+ const index = state.stack.lastIndexOf(value);
29299
+ if (index >= 0) {
29300
+ state.stack.splice(index, 1);
29301
+ }
29149
29302
  }
29150
- function hasErrorCode(error, code) {
29151
- return hasOwnErrorCode(error, code);
29303
+ function normalizeStringifyGap(indent) {
29304
+ if (typeof indent === "number") {
29305
+ return " ".repeat(Math.min(10, Math.max(0, Math.trunc(indent))));
29306
+ }
29307
+ if (typeof indent === "string") {
29308
+ return indent.slice(0, 10);
29309
+ }
29310
+ return "";
29152
29311
  }
29153
- function isLockedFileError(error) {
29154
- const code = getOwnErrorCode(error);
29155
- return code !== void 0 && LOCKED_FILE_ERROR_CODES.has(code);
29312
+ function quoteJsonString(value) {
29313
+ return JSON.stringify(value);
29156
29314
  }
29157
-
29158
- // packages/safe-js/src/run.ts
29159
- 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
- }
29195
-
29196
- // packages/safe-js/src/interp/globals/console-json.ts
29197
- function createConsoleJsonGlobals(options) {
29198
- const sink = options.sink ?? console;
29199
- return {
29200
- JSON: {
29201
- parse: createSandboxClosure({
29202
- sandbox: true,
29203
- call: async ([text]) => parseJson(text, options.budget),
29204
- name: "parse"
29205
- }),
29206
- stringify: createSandboxClosure({
29207
- sandbox: true,
29208
- call: async ([value, replacer, indent]) => stringifyJson(value, replacer, indent, options.budget),
29209
- name: "stringify"
29210
- })
29211
- },
29212
- console: options.hostCalls === void 0 ? {
29213
- error: createSandboxClosure({
29214
- sandbox: true,
29215
- call: async (args, context) => {
29216
- const operation = options.budget.acquireCompileOwner(
29217
- false,
29218
- options.compileOwner ?? context?.compilation?.owner
29219
- );
29220
- const compilation = new CompileScope(operation.owner);
29221
- try {
29222
- sink.error(...args.map((value) => deepCopyFromSandbox(value, { compilation })));
29223
- return void 0;
29224
- } finally {
29225
- compilation.dispose();
29226
- operation.release();
29227
- }
29228
- },
29229
- name: "error"
29230
- }),
29231
- log: createSandboxClosure({
29232
- sandbox: true,
29233
- call: async (args, context) => {
29234
- const operation = options.budget.acquireCompileOwner(
29235
- false,
29236
- options.compileOwner ?? context?.compilation?.owner
29237
- );
29238
- const compilation = new CompileScope(operation.owner);
29239
- try {
29240
- sink.log(...args.map((value) => deepCopyFromSandbox(value, { compilation })));
29241
- return void 0;
29242
- } finally {
29243
- compilation.dispose();
29244
- operation.release();
29245
- }
29246
- },
29247
- name: "log"
29248
- })
29249
- } : wrapCallerInjectedBindings(
29250
- {
29251
- error: (...args) => {
29252
- sink.error(...args);
29253
- return void 0;
29254
- },
29255
- log: (...args) => {
29256
- sink.log(...args);
29257
- return void 0;
29258
- }
29259
- },
29260
- {
29261
- budget: options.budget,
29262
- compileOwner: options.compileOwner,
29263
- hostCalls: options.hostCalls,
29264
- moduleId: "<console>"
29265
- }
29266
- )
29267
- };
29268
- }
29269
- function parseJson(input, budget) {
29270
- const text = budget.allocateString(toJsonParseText(input));
29271
- return copyJsonToSandbox(JSON.parse(text), budget);
29315
+ function isStringifyContainer(value) {
29316
+ return typeof value === "object" && value !== null && !isSandboxClosure(value) && !isSandboxPromise(value);
29272
29317
  }
29273
- async function stringifyJson(value, replacer, indent, budget) {
29274
- if (replacer !== void 0 && replacer !== null && !isSandboxClosure(replacer)) {
29275
- throw new TypeError(
29276
- "JSON.stringify(value, replacer, indent) only supports function, null, or undefined replacers."
29277
- );
29278
- }
29279
- if (indent !== void 0 && typeof indent !== "number" && typeof indent !== "string") {
29280
- throw new TypeError(
29281
- "JSON.stringify(value, replacer, indent) requires indent to be a string, number, or undefined."
29282
- );
29283
- }
29284
- const holder = {};
29285
- defineDataProperty(holder, "", value);
29286
- const output = await stringifyProperty("", holder, {
29287
- budget,
29288
- gap: normalizeStringifyGap(indent),
29289
- replacer: isSandboxClosure(replacer) ? replacer : void 0,
29290
- stack: []
29291
- });
29292
- if (output === void 0) {
29293
- return void 0;
29294
- }
29295
- return budget.allocateString(output);
29318
+ function isStringifyObject(value) {
29319
+ return isStringifyContainer(value) && !Array.isArray(value);
29296
29320
  }
29297
- function toJsonParseText(input) {
29298
- if (Array.isArray(input)) {
29299
- return input.map((entry) => entry === null || entry === void 0 ? "" : toJsonParseText(entry)).join(",");
29321
+ function toSandboxValue(value) {
29322
+ if (value === null || value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || isSandboxClosure(value) || isSandboxPromise(value) || Array.isArray(value) || isStringifyContainer(value)) {
29323
+ return value;
29300
29324
  }
29301
- if (typeof input === "object" && input !== null) {
29302
- return "[object Object]";
29325
+ if (typeof value === "bigint") {
29326
+ throw new TypeError("Do not know how to serialize a BigInt.");
29303
29327
  }
29304
- return String(input);
29328
+ throw new TypeError(
29329
+ `JSON.stringify(value) produced an unsupported value of type ${typeof value}.`
29330
+ );
29305
29331
  }
29306
- async function stringifyProperty(key, holder, state, indent = "") {
29307
- let value = getOwnDataValue(holder, key);
29308
- if (isStringifyContainer(value)) {
29309
- const toJSON = getOwnDataValue(value, "toJSON");
29310
- if (isSandboxClosure(toJSON)) {
29311
- value = await callStringifyClosure(toJSON, [key], value, state);
29312
- }
29332
+ function getOwnDataValue(target, key) {
29333
+ const descriptor = Object.getOwnPropertyDescriptor(target, key);
29334
+ if (descriptor === void 0) {
29335
+ return void 0;
29313
29336
  }
29314
- if (state.replacer !== void 0) {
29315
- value = await callStringifyClosure(state.replacer, [key, toSandboxValue(value)], holder, state);
29337
+ if ("get" in descriptor || "set" in descriptor) {
29338
+ throw new TypeError(`JSON.stringify(value) cannot serialize accessor property ${key}.`);
29316
29339
  }
29317
- return stringifyValue(value, state, indent);
29340
+ return descriptor.value;
29318
29341
  }
29319
- async function stringifyValue(value, state, indent) {
29320
- if (value === null) {
29321
- return "null";
29342
+ function copyJsonToSandbox(value, budget) {
29343
+ if (value === null || value === void 0 || typeof value === "boolean" || typeof value === "number") {
29344
+ return value;
29322
29345
  }
29323
29346
  if (typeof value === "string") {
29324
- return quoteJsonString(value);
29325
- }
29326
- if (typeof value === "number") {
29327
- return Number.isFinite(value) ? String(value) : "null";
29328
- }
29329
- if (typeof value === "boolean") {
29330
- return value ? "true" : "false";
29331
- }
29332
- if (typeof value === "bigint") {
29333
- throw new TypeError("Do not know how to serialize a BigInt.");
29334
- }
29335
- if (isSandboxPromise(value)) return "{}";
29336
- if (value === void 0 || isSandboxClosure(value)) {
29337
- return void 0;
29347
+ return budget.allocateString(value);
29338
29348
  }
29339
29349
  if (Array.isArray(value)) {
29340
- return stringifyArray(value, state, indent);
29341
- }
29342
- if (isStringifyObject(value)) {
29343
- return stringifyObject(value, state, indent);
29350
+ budget.allocateArrayLength(value.length);
29351
+ return value.map((entry) => copyJsonToSandbox(entry, budget));
29344
29352
  }
29345
- return void 0;
29346
- }
29347
- async function stringifyArray(value, state, indent) {
29348
- enterStringifyObject(value, state);
29349
- try {
29350
- const nextIndent = indent + state.gap;
29351
- const entries = [];
29352
- for (let index = 0; index < value.length; index += 1) {
29353
- entries.push(await stringifyProperty(String(index), value, state, nextIndent) ?? "null");
29354
- }
29355
- if (entries.length === 0) {
29356
- return "[]";
29357
- }
29358
- if (state.gap === "") {
29359
- return `[${entries.join(",")}]`;
29353
+ if (isPlainObject4(value)) {
29354
+ const copy = /* @__PURE__ */ Object.create(null);
29355
+ for (const [key, entry] of Object.entries(value)) {
29356
+ defineDataProperty(copy, key, copyJsonToSandbox(entry, budget));
29360
29357
  }
29361
- return `[
29362
- ${nextIndent}${entries.join(`,
29363
- ${nextIndent}`)}
29364
- ${indent}]`;
29365
- } finally {
29366
- leaveStringifyObject(value, state);
29358
+ return copy;
29367
29359
  }
29360
+ throw new TypeError("JSON.parse(text) produced an unsupported value.");
29368
29361
  }
29369
- async function stringifyObject(value, state, indent) {
29370
- enterStringifyObject(value, state);
29371
- try {
29372
- const nextIndent = indent + state.gap;
29373
- const entries = [];
29374
- for (const key of Object.keys(value)) {
29375
- const serialized = await stringifyProperty(key, value, state, nextIndent);
29376
- if (serialized !== void 0) {
29377
- entries.push(`${quoteJsonString(key)}:${state.gap === "" ? "" : " "}${serialized}`);
29378
- }
29379
- }
29380
- if (entries.length === 0) {
29381
- return "{}";
29382
- }
29383
- if (state.gap === "") {
29384
- return `{${entries.join(",")}}`;
29385
- }
29386
- return `{
29387
- ${nextIndent}${entries.join(`,
29388
- ${nextIndent}`)}
29389
- ${indent}}`;
29390
- } finally {
29391
- leaveStringifyObject(value, state);
29362
+ function isPlainObject4(value) {
29363
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
29364
+ return false;
29392
29365
  }
29393
- }
29394
- async function callStringifyClosure(closure, args, thisValue, state) {
29395
- const result = await closure.call(args, { stack: [], thisValue });
29396
- if (isSandboxPromise(result) && result.synchronousPrefix !== void 0) {
29397
- await result.synchronousPrefix;
29398
- }
29399
- return allocateProducedSandboxValue(result, state.budget);
29400
- }
29401
- function enterStringifyObject(value, state) {
29402
- if (state.stack.includes(value)) {
29403
- throw new TypeError("Converting circular structure to JSON.");
29404
- }
29405
- state.stack.push(value);
29406
- }
29407
- function leaveStringifyObject(value, state) {
29408
- if (state.stack.at(-1) === value) {
29409
- state.stack.pop();
29410
- return;
29411
- }
29412
- const index = state.stack.lastIndexOf(value);
29413
- if (index >= 0) {
29414
- state.stack.splice(index, 1);
29415
- }
29416
- }
29417
- function normalizeStringifyGap(indent) {
29418
- if (typeof indent === "number") {
29419
- return " ".repeat(Math.min(10, Math.max(0, Math.trunc(indent))));
29420
- }
29421
- if (typeof indent === "string") {
29422
- return indent.slice(0, 10);
29423
- }
29424
- return "";
29425
- }
29426
- function quoteJsonString(value) {
29427
- return JSON.stringify(value);
29428
- }
29429
- function isStringifyContainer(value) {
29430
- return typeof value === "object" && value !== null && !isSandboxClosure(value) && !isSandboxPromise(value);
29431
- }
29432
- function isStringifyObject(value) {
29433
- return isStringifyContainer(value) && !Array.isArray(value);
29434
- }
29435
- function toSandboxValue(value) {
29436
- if (value === null || value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || isSandboxClosure(value) || isSandboxPromise(value) || Array.isArray(value) || isStringifyContainer(value)) {
29437
- return value;
29438
- }
29439
- if (typeof value === "bigint") {
29440
- throw new TypeError("Do not know how to serialize a BigInt.");
29441
- }
29442
- throw new TypeError(
29443
- `JSON.stringify(value) produced an unsupported value of type ${typeof value}.`
29444
- );
29445
- }
29446
- function getOwnDataValue(target, key) {
29447
- const descriptor = Object.getOwnPropertyDescriptor(target, key);
29448
- if (descriptor === void 0) {
29449
- return void 0;
29450
- }
29451
- if ("get" in descriptor || "set" in descriptor) {
29452
- throw new TypeError(`JSON.stringify(value) cannot serialize accessor property ${key}.`);
29453
- }
29454
- return descriptor.value;
29455
- }
29456
- function copyJsonToSandbox(value, budget) {
29457
- if (value === null || value === void 0 || typeof value === "boolean" || typeof value === "number") {
29458
- return value;
29459
- }
29460
- if (typeof value === "string") {
29461
- return budget.allocateString(value);
29462
- }
29463
- if (Array.isArray(value)) {
29464
- budget.allocateArrayLength(value.length);
29465
- return value.map((entry) => copyJsonToSandbox(entry, budget));
29466
- }
29467
- if (isPlainObject4(value)) {
29468
- const copy = /* @__PURE__ */ Object.create(null);
29469
- for (const [key, entry] of Object.entries(value)) {
29470
- defineDataProperty(copy, key, copyJsonToSandbox(entry, budget));
29471
- }
29472
- return copy;
29473
- }
29474
- throw new TypeError("JSON.parse(text) produced an unsupported value.");
29475
- }
29476
- function isPlainObject4(value) {
29477
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
29478
- return false;
29479
- }
29480
- const prototype = Object.getPrototypeOf(value);
29481
- return prototype === Object.prototype || prototype === null;
29366
+ const prototype = Object.getPrototypeOf(value);
29367
+ return prototype === Object.prototype || prototype === null;
29482
29368
  }
29483
29369
  function defineDataProperty(target, key, value) {
29484
29370
  Object.defineProperty(target, key, {
@@ -29886,295 +29772,1458 @@ function createObjectArrayGlobals(options) {
29886
29772
  NEGATIVE_INFINITY: Number.NEGATIVE_INFINITY,
29887
29773
  POSITIVE_INFINITY: Number.POSITIVE_INFINITY
29888
29774
  }
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.");
29775
+ }),
29776
+ Boolean: createSandboxClosure({
29777
+ sandbox: true,
29778
+ call: ([value]) => Boolean(value),
29779
+ name: "Boolean"
29780
+ })
29781
+ };
29782
+ }
29783
+ async function objectFromSandboxEntries(iterator, budget) {
29784
+ const object = /* @__PURE__ */ Object.create(null);
29785
+ try {
29786
+ while (true) {
29787
+ const result = await iterator.next();
29788
+ if (typeof result !== "object" && typeof result !== "function" || result === null) {
29789
+ throw new TypeError("Iterator result must be an object.");
29790
+ }
29791
+ if (result.done) break;
29792
+ const entry = result.value;
29793
+ if (typeof entry !== "object" && typeof entry !== "function" || entry === null) {
29794
+ throw new TypeError("Object.fromEntries requires entry objects.");
29795
+ }
29796
+ const key = entry[0];
29797
+ const value = entry[1];
29798
+ Object.defineProperty(object, key, {
29799
+ configurable: true,
29800
+ enumerable: true,
29801
+ value,
29802
+ writable: true
29803
+ });
29804
+ }
29805
+ } catch (error) {
29806
+ try {
29807
+ await iterator.return?.();
29808
+ } catch {
29809
+ throw error;
29810
+ }
29811
+ throw error;
29812
+ }
29813
+ return allocateProducedSandboxValue(object, budget);
29814
+ }
29815
+ function assignSandboxValues(target, sources, budget) {
29816
+ if (target === null || target === void 0) {
29817
+ throw new TypeError("Object.assign(target, ...sources) requires a non-null target.");
29818
+ }
29819
+ if (!isGuestClosure(target) && !isAssignableSandboxTarget(target)) {
29820
+ throw new TypeError("Object.assign(target, ...sources) requires an object or array target.");
29821
+ }
29822
+ for (const source of sources) {
29823
+ if (source === null || source === void 0) {
29824
+ continue;
29825
+ }
29826
+ for (const [key, value] of ownEnumerableSandboxEntries(source)) {
29827
+ setSandboxProperty(target, key, value, budget);
29828
+ }
29829
+ }
29830
+ return target;
29831
+ }
29832
+ function objectProperties(value, mutable = false) {
29833
+ if (isGuestHostObject(value)) throw new TypeError("Live host object descriptors are not supported.");
29834
+ if (isGuestClosure(value)) return materializeFunctionProperties(value);
29835
+ if (isSandboxClosure(value)) {
29836
+ if (mutable) throw new TypeError("Host function properties are read only.");
29837
+ return value.properties ?? /* @__PURE__ */ Object.create(null);
29838
+ }
29839
+ if (!isAssignableSandboxTarget(value)) throw new TypeError("Expected a sandbox object or function.");
29840
+ return value;
29841
+ }
29842
+ function dataDescriptor(input) {
29843
+ const source = objectProperties(input);
29844
+ const descriptor = {};
29845
+ for (const field of ["get", "set", "value", "writable", "enumerable", "configurable"]) {
29846
+ const entry = Object.getOwnPropertyDescriptor(source, field);
29847
+ if (entry === void 0) continue;
29848
+ if (!("value" in entry) || field === "get" || field === "set") {
29849
+ throw new TypeError("Only data property descriptors are supported.");
29850
+ }
29851
+ if (field === "value") descriptor.value = entry.value;
29852
+ else descriptor[field] = Boolean(entry.value);
29853
+ }
29854
+ return descriptor;
29855
+ }
29856
+ function defineDataProperty2(target, key, descriptor, budget) {
29857
+ budget.visitNode();
29858
+ if (isFloat32Array(target)) throw new TypeError("Typed array property descriptors are not supported.");
29859
+ const properties = objectProperties(target, true);
29860
+ if (Array.isArray(properties)) {
29861
+ if (key === "length" && "value" in descriptor) budget.allocateArrayLength(Number(descriptor.value));
29862
+ else {
29863
+ const index = Number(key);
29864
+ if (Number.isInteger(index) && index >= 0 && index < 4294967295 && String(index) === key) {
29865
+ budget.allocateArrayLength(index + 1);
29866
+ }
29867
+ }
29868
+ }
29869
+ Object.defineProperty(properties, key, descriptor);
29870
+ markDescriptorObject(properties);
29871
+ }
29872
+ function isAssignableSandboxTarget(value) {
29873
+ return typeof value === "object" && value !== null && !isSandboxClosure(value) && !isSandboxGenerator(value) && !isSandboxMap(value) && !isSandboxSet(value) && !isSandboxPromise(value) && !isSandboxRegex(value);
29874
+ }
29875
+ async function arrayFromSandboxValues(args, budget) {
29876
+ const [items, mapFn, thisValue] = args;
29877
+ const iterator = getSandboxIterator(items);
29878
+ const values = iterator === void 0 ? Reflect.apply(Array.from, Array, [items]) : await collectIteratorValues(iterator);
29879
+ if (mapFn === void 0 || !isSandboxClosure(mapFn)) {
29880
+ if (mapFn !== void 0) {
29881
+ throw new TypeError("Array.from mapping callback must be a function.");
29882
+ }
29883
+ return budgetSandboxValue2(values, budget);
29884
+ }
29885
+ const mappedValues = [];
29886
+ for (const [index, value] of values.entries()) {
29887
+ const result = await mapFn.call([value, index], { stack: [], thisValue });
29888
+ if (isSandboxPromise(result) && result.synchronousPrefix !== void 0) {
29889
+ await result.synchronousPrefix;
29890
+ }
29891
+ mappedValues.push(result);
29892
+ }
29893
+ return budgetSandboxValue2(mappedValues, budget);
29894
+ }
29895
+ function createArrayFromConstructorArgs(args, budget) {
29896
+ if (args.length !== 1) {
29897
+ return budgetSandboxValue2(Reflect.apply(Array, Array, [...args]), budget);
29898
+ }
29899
+ const [lengthOrValue] = args;
29900
+ if (typeof lengthOrValue !== "number") {
29901
+ return budgetSandboxValue2([lengthOrValue], budget);
29902
+ }
29903
+ if (!Number.isInteger(lengthOrValue) || lengthOrValue < 0 || lengthOrValue > 4294967295) {
29904
+ throw new RangeError("Invalid array length.");
29905
+ }
29906
+ budget.allocateArrayLength(lengthOrValue);
29907
+ return new Array(lengthOrValue);
29908
+ }
29909
+ async function collectIteratorValues(iterator) {
29910
+ const values = [];
29911
+ while (true) {
29912
+ const result = await iterator.next();
29913
+ if (result.done) return values;
29914
+ values.push(result.value);
29915
+ }
29916
+ }
29917
+ function getOwnEnumerableKeys(value) {
29918
+ if (isGuestHostObject(value)) return getHostObjectKeys(value);
29919
+ return ownEnumerableSandboxEntries(value).map(([key]) => key);
29920
+ }
29921
+ function getOwnEnumerableValues(value) {
29922
+ return ownEnumerableSandboxEntries(value).map(([, entryValue]) => entryValue);
29923
+ }
29924
+ function budgetSandboxValue2(value, budget) {
29925
+ const sandboxValue = deepCopyToSandbox(value);
29926
+ return allocateProducedSandboxValue(sandboxValue, budget);
29927
+ }
29928
+ function stringRaw(args, budget) {
29929
+ const [template, ...substitutions] = args;
29930
+ const raw = getTemplateRawParts(template);
29931
+ let result = "";
29932
+ for (let index = 0; index < raw.length; index += 1) {
29933
+ result += String(raw[index]);
29934
+ if (index < raw.length - 1 && index < substitutions.length) {
29935
+ result += String(substitutions[index]);
29936
+ }
29937
+ }
29938
+ return budget.allocateString(result);
29939
+ }
29940
+ function getTemplateRawParts(template) {
29941
+ const raw = typeof template === "object" && template !== null ? template.raw : void 0;
29942
+ if (typeof template !== "object" || template === null || isSandboxClosure(template) || isSandboxPromise(template) || !Array.isArray(raw)) {
29943
+ throw new TypeError("String.raw requires a raw strings array.");
29944
+ }
29945
+ return raw;
29946
+ }
29947
+
29948
+ // packages/safe-js/src/interp/globals.ts
29949
+ function createBuiltinBindings(options) {
29950
+ return {
29951
+ ...createConsoleJsonGlobals(options),
29952
+ ...createCollectionGlobals(options),
29953
+ Float32Array: createFloat32ArrayGlobal(options.budget),
29954
+ ...createErrorGlobals(options),
29955
+ ...createMathGlobals({ random: options.random }),
29956
+ ...createObjectArrayGlobals(options),
29957
+ ...createMiscGlobals(options),
29958
+ ...createPromiseGlobals(options),
29959
+ ...createRegexGlobals(options.compileOwner)
29960
+ };
29961
+ }
29962
+
29963
+ // packages/safe-js/src/interp/resources.ts
29964
+ import { AsyncLocalStorage as AsyncLocalStorage5 } from "node:async_hooks";
29965
+ var runResources = new AsyncLocalStorage5();
29966
+ async function withRunResources(signal, execute) {
29967
+ const controller = new AbortController();
29968
+ const cancel = () => controller.abort(signal?.reason);
29969
+ const cleanups = /* @__PURE__ */ new Set();
29970
+ const resources = {
29971
+ signal: controller.signal,
29972
+ add(close) {
29973
+ cleanups.add(close);
29974
+ }
29975
+ };
29976
+ signal?.addEventListener("abort", cancel, { once: true });
29977
+ if (signal?.aborted) cancel();
29978
+ let result;
29979
+ let failure;
29980
+ let errors = [];
29981
+ try {
29982
+ result = await runResources.run(resources, execute);
29983
+ } catch (error) {
29984
+ failure = { reason: error };
29985
+ } finally {
29986
+ signal?.removeEventListener("abort", cancel);
29987
+ controller.abort(new Error("SafeJS run finished."));
29988
+ const outcomes = await Promise.allSettled(
29989
+ [...cleanups].map((close) => Promise.resolve().then(close))
29990
+ );
29991
+ errors = outcomes.flatMap((outcome) => outcome.status === "rejected" ? [outcome.reason] : []);
29992
+ }
29993
+ if (failure !== void 0) throw failure.reason;
29994
+ if (errors.length > 0) throw new AggregateError(errors, "SafeJS resource cleanup failed.");
29995
+ return result;
29996
+ }
29997
+
29998
+ // packages/safe-js/src/modules/registry.ts
29999
+ function createUnknownModuleMessage2(moduleName, moduleNames) {
30000
+ if (moduleNames.length === 0) {
30001
+ return `Unknown module '${moduleName}'. No modules are registered.`;
30002
+ }
30003
+ return `Unknown module '${moduleName}'. Available modules: ${moduleNames.join(", ")}.`;
30004
+ }
30005
+ function createUnknownExportMessage2(moduleName, exportName, availableExports) {
30006
+ if (availableExports.length === 0) {
30007
+ return `Module '${moduleName}' does not export '${exportName}'. The module exports nothing.`;
30008
+ }
30009
+ return `Module '${moduleName}' does not export '${exportName}'. Available exports: ${availableExports.join(", ")}.`;
30010
+ }
30011
+ function resolveModuleImports(module, modules, options) {
30012
+ const registry = normalizeModuleRegistry(modules);
30013
+ const bindings = createBindingRecord();
30014
+ const wrappedModules = options.wrappedModules ?? /* @__PURE__ */ new Map();
30015
+ for (const statement of module.body) {
30016
+ if (statement.type !== "ImportDeclaration") {
30017
+ continue;
30018
+ }
30019
+ bindImportDeclaration(statement, registry, wrappedModules, bindings, options);
30020
+ }
30021
+ return bindings;
30022
+ }
30023
+ function bindImportDeclaration(declaration, registry, wrappedModules, bindings, options) {
30024
+ const moduleName = declaration.source.value;
30025
+ const moduleExports = registry.get(moduleName);
30026
+ if (moduleExports === void 0) {
30027
+ if (options.allowMissing) return;
30028
+ throw createModuleImportError(
30029
+ createUnknownModuleMessage2(moduleName, [...registry.keys()]),
30030
+ declaration.source.span
30031
+ );
30032
+ }
30033
+ const wrappedExports = wrappedModules.get(moduleName) ?? createBindingRecord(
30034
+ wrapCancelableBindings(
30035
+ wrapCallerInjectedBindings(Object.fromEntries(moduleExports), {
30036
+ realm: options.realm,
30037
+ budget: options.budget,
30038
+ compileOwner: options.compileOwner,
30039
+ hostCalls: options.hostCalls,
30040
+ moduleId: moduleName,
30041
+ signal: options.signal
30042
+ }),
30043
+ options.signal
30044
+ )
30045
+ );
30046
+ wrappedModules.set(moduleName, wrappedExports);
30047
+ for (const specifier of declaration.specifiers) {
30048
+ const localName = specifier.local.name;
30049
+ if (Object.hasOwn(bindings, localName)) {
30050
+ throw createModuleImportError(
30051
+ `Cannot redeclare imported binding '${localName}'.`,
30052
+ specifier.local.span
30053
+ );
30054
+ }
30055
+ if (options.allowMissing && specifier.type !== "ImportNamespaceSpecifier") {
30056
+ const exportName = specifier.type === "ImportDefaultSpecifier" ? "default" : specifier.imported.name;
30057
+ if (!Object.hasOwn(wrappedExports, exportName)) continue;
30058
+ }
30059
+ bindings[localName] = resolveImportSpecifier(moduleName, specifier, wrappedExports);
30060
+ }
30061
+ }
30062
+ function resolveImportSpecifier(moduleName, specifier, wrappedExports) {
30063
+ if (specifier.type === "ImportNamespaceSpecifier") {
30064
+ return wrappedExports;
30065
+ }
30066
+ const exportName = specifier.type === "ImportDefaultSpecifier" ? "default" : specifier.imported.name;
30067
+ const exportedValue = wrappedExports[exportName];
30068
+ if (exportedValue !== void 0 || Object.hasOwn(wrappedExports, exportName)) {
30069
+ return exportedValue;
30070
+ }
30071
+ throw createModuleImportError(
30072
+ createUnknownExportMessage2(moduleName, exportName, Object.keys(wrappedExports).sort()),
30073
+ specifier.span
30074
+ );
30075
+ }
30076
+ function createModuleImportError(message, span) {
30077
+ const error = new Error(message);
30078
+ attachErrorSpan(error, span);
30079
+ return error;
30080
+ }
30081
+ function normalizeModuleRegistry(modules) {
30082
+ if (modules === void 0) {
30083
+ return /* @__PURE__ */ new Map();
30084
+ }
30085
+ const entries = modules instanceof Map ? [...modules.entries()] : Object.entries(modules);
30086
+ const registry = new Map(
30087
+ entries.map(
30088
+ ([moduleName, moduleExports]) => [moduleName, normalizeModuleExports(moduleExports)]
30089
+ ).sort(([left], [right]) => left.localeCompare(right))
30090
+ );
30091
+ registerModuleHostOperationPolicies(registry);
30092
+ return registry;
30093
+ }
30094
+ function registerModuleHostOperationPolicies(registry) {
30095
+ for (const [moduleId, moduleExports] of registry) {
30096
+ for (const [operation, value] of moduleExports) {
30097
+ if (typeof value !== "function") {
30098
+ continue;
30099
+ }
30100
+ const policy = readHostOperationPolicy(value);
30101
+ if (policy !== void 0) {
30102
+ registerPendingHostCallPolicy({ moduleId, operation, policy });
30103
+ }
30104
+ }
30105
+ }
30106
+ }
30107
+ function normalizeModuleExports(moduleExports) {
30108
+ const entries = moduleExports instanceof Map ? [...moduleExports.entries()] : Object.entries(moduleExports);
30109
+ return new Map(
30110
+ entries.filter(([exportName]) => exportName.length > 0).sort(([left], [right]) => left.localeCompare(right))
30111
+ );
30112
+ }
30113
+ function createBindingRecord(entries) {
30114
+ return Object.assign(/* @__PURE__ */ Object.create(null), entries);
30115
+ }
30116
+
30117
+ // packages/safe-js/src/realm.ts
30118
+ var RealmState = class {
30119
+ constructor(options) {
30120
+ this.options = options;
30121
+ const limitInput = readDataRecord(options.limits ?? {}, "Realm limits");
30122
+ this.limits = {
30123
+ extensions: 32,
30124
+ hostObjects: 1024,
30125
+ callbacks: 1024,
30126
+ guestReferences: 1024,
30127
+ cleanups: 1024,
30128
+ nestedEvaluations: 16
30129
+ };
30130
+ for (const [name, value] of Object.entries(limitInput)) {
30131
+ if (!Object.hasOwn(this.limits, name) || !Number.isSafeInteger(value) || Number(value) < 1)
30132
+ throw new TypeError("Realm limits must be positive safe integers with supported names.");
30133
+ this.limits[name] = Number(value);
30134
+ }
30135
+ if (options.extensions !== void 0 && (!Array.isArray(options.extensions) || types3.isProxy(options.extensions)))
30136
+ throw new TypeError("Extensions must be a registration array.");
30137
+ const registrations = options.extensions ?? [];
30138
+ const extensions = [];
30139
+ if (registrations.length > this.limits.extensions)
30140
+ throw new RangeError("Realm extension limit exceeded.");
30141
+ for (let index = 0; index < registrations.length; index++) {
30142
+ const descriptor = Object.getOwnPropertyDescriptor(registrations, String(index));
30143
+ if (descriptor === void 0 || !("value" in descriptor))
30144
+ throw new TypeError("Extension registrations require data properties, not accessors.");
30145
+ extensions.push(descriptor.value);
30146
+ }
30147
+ if (Reflect.ownKeys(registrations).length !== extensions.length + 1)
30148
+ throw new TypeError("Extension registrations have unsupported fields.");
30149
+ this.extensions = Object.freeze(extensions);
30150
+ if (this.extensions.length > this.limits.extensions)
30151
+ throw new RangeError("Realm extension limit exceeded.");
30152
+ this.globals = readDataRecord(options.bindings ?? {}, "Realm bindings");
30153
+ this.modules = readModules(options.modules);
30154
+ const grants = new Set(readStringList(options.grants ?? [], "Realm grants"));
30155
+ for (const extension of this.extensions) getExtensionSetup(extension);
30156
+ this.budget = options.budget ?? new Budget({ maxCallDepth: 1e3 });
30157
+ this.lease = this.budget.acquireCompileOwner(true);
30158
+ this.compilation = new CompileScope(this.lease.owner);
30159
+ this.bridge = {
30160
+ owner: this,
30161
+ assertActive: this.assertOpen,
30162
+ wrapCallback: this.wrapCallback,
30163
+ captureArguments: this.captureArguments,
30164
+ invoke: this.invokeHost,
30165
+ awaitResult: (operation) => this.nestedOperations.has(operation)
30166
+ };
30167
+ try {
30168
+ this.builtinBindings = createBuiltinBindings({
30169
+ budget: this.budget,
30170
+ compileOwner: this.lease.owner,
30171
+ sink: options.sink,
30172
+ random: createReplayableRandom({ seed: options.randomSeed }).next
30173
+ });
30174
+ const names = /* @__PURE__ */ new Set();
30175
+ const globals = /* @__PURE__ */ new Set([...Object.keys(this.builtinBindings), ...Object.keys(this.globals)]);
30176
+ const modules = new Map(
30177
+ Object.entries(this.modules).map(([name, exports]) => [name, new Set(Object.keys(exports))])
30178
+ );
30179
+ for (const extension of this.extensions) {
30180
+ const manifest = extension.manifest;
30181
+ if (names.has(manifest.name))
30182
+ throw new TypeError(`Duplicate extension '${manifest.name}'.`);
30183
+ names.add(manifest.name);
30184
+ for (const capability of manifest.capabilities ?? []) {
30185
+ if (!grants.has(capability))
30186
+ throw new TypeError(`Missing grant '${capability}' for extension '${manifest.name}'.`);
30187
+ }
30188
+ for (const name of manifest.globals ?? []) {
30189
+ if (globals.has(name)) throw new TypeError(`Conflicting global '${name}'.`);
30190
+ globals.add(name);
30191
+ }
30192
+ for (const [name, exports] of Object.entries(manifest.modules ?? {})) {
30193
+ const occupied = modules.get(name) ?? /* @__PURE__ */ new Set();
30194
+ for (const key of exports) {
30195
+ if (occupied.has(key)) throw new TypeError(`Conflicting export '${name}.${key}'.`);
30196
+ occupied.add(key);
30197
+ }
30198
+ modules.set(name, occupied);
30199
+ }
30200
+ }
30201
+ options.signal?.addEventListener("abort", this.abort, { once: true });
30202
+ if (options.signal?.aborted) this.abort();
30203
+ this.budget.setRetainedValues(this, this.retainedRoots);
30204
+ this.tracker.onFatalRejection((error) => this.poison(error));
30205
+ } catch (error) {
30206
+ this.compilation.dispose();
30207
+ this.lease.release();
30208
+ throw error;
30209
+ }
30210
+ }
30211
+ options;
30212
+ budget;
30213
+ lease;
30214
+ compilation;
30215
+ controller = new AbortController();
30216
+ phase = new AsyncLocalStorage6();
30217
+ queue = new SandboxJobQueue();
30218
+ tracker = createSandboxPromiseRejectionTracker();
30219
+ bridge;
30220
+ limits;
30221
+ extensions;
30222
+ cleanups = [];
30223
+ callbacks = /* @__PURE__ */ new Map();
30224
+ pendingCallbacks = /* @__PURE__ */ new Set();
30225
+ callbackCache = /* @__PURE__ */ new WeakMap();
30226
+ hostObjects = /* @__PURE__ */ new Set();
30227
+ guestReferences = /* @__PURE__ */ new Map();
30228
+ retainedOperations = /* @__PURE__ */ new WeakMap();
30229
+ nestedOperations = /* @__PURE__ */ new WeakMap();
30230
+ convertedModules = /* @__PURE__ */ new Map();
30231
+ nativeConversions = { seen: /* @__PURE__ */ new WeakMap() };
30232
+ modules;
30233
+ globals;
30234
+ builtinBindings;
30235
+ scope;
30236
+ active;
30237
+ disposal;
30238
+ closed = false;
30239
+ initialized = false;
30240
+ nestedDepth = 0;
30241
+ failure;
30242
+ bridgeOptions = () => ({
30243
+ budget: this.budget,
30244
+ compileOwner: this.lease.owner,
30245
+ signal: this.controller.signal,
30246
+ realm: this.bridge
30247
+ });
30248
+ retainedRoots = () => [
30249
+ ...this.callbacks.values(),
30250
+ ...Array.from(this.pendingCallbacks, (pending) => pending.closure),
30251
+ ...this.guestReferences.values()
30252
+ ];
30253
+ captureArguments = (operation, args, copy) => {
30254
+ const from = this.retainedOperations.get(operation)?.from ?? args.length;
30255
+ const values = copy(args.slice(0, from));
30256
+ const captured = [];
30257
+ const rollback = () => {
30258
+ for (const reference of captured) {
30259
+ revokeGuestReference(reference, this);
30260
+ this.guestReferences.delete(reference);
30261
+ }
30262
+ };
30263
+ try {
30264
+ for (const value of args.slice(from)) {
30265
+ this.checkCollection(
30266
+ this.guestReferences.size + 1,
30267
+ this.limits.guestReferences,
30268
+ "guest reference"
30269
+ );
30270
+ const root = [value];
30271
+ const reference = createGuestReference(root, this, this.assertOpen);
30272
+ this.guestReferences.set(reference, root);
30273
+ captured.push(reference);
30274
+ values.push(reference);
30275
+ }
30276
+ if (captured.length > 0)
30277
+ this.budget.reconcileDataUsage(
30278
+ measureSandboxData([...this.scope?.retainedValues() ?? [], ...this.retainedRoots()])
30279
+ );
30280
+ return { args: values, rollback };
30281
+ } catch (error) {
30282
+ rollback();
30283
+ if (error instanceof SandboxError) this.poison(error);
30284
+ throw error;
30285
+ }
30286
+ };
30287
+ releaseGuestReference = (reference) => {
30288
+ readGuestReference(reference, this);
30289
+ revokeGuestReference(reference, this);
30290
+ this.guestReferences.delete(reference);
30291
+ if (this.active === void 0)
30292
+ reconcileCompiledValues(
30293
+ this.budget,
30294
+ [...this.scope?.retainedValues() ?? [], ...this.retainedRoots()],
30295
+ this.compilation
30296
+ );
30297
+ };
30298
+ assertOpen = () => {
30299
+ if (this.failure !== void 0) throw this.failure.reason;
30300
+ if (this.closed) throw new Error("SafeJS realm is closed; capabilities are revoked.");
30301
+ this.controller.signal.throwIfAborted();
30302
+ };
30303
+ abort = () => {
30304
+ this.poison(this.options.signal?.reason ?? new SandboxError("aborted"));
30305
+ void this.close().catch(() => void 0);
30306
+ };
30307
+ poison(reason) {
30308
+ this.failure ??= { reason };
30309
+ this.controller.abort(reason);
30310
+ if (this.active === void 0)
30311
+ queueMicrotask(() => {
30312
+ void this.dispose().catch(() => void 0);
30313
+ });
30314
+ }
30315
+ chargeWork = (units = 1) => {
30316
+ this.assertOpen();
30317
+ if (!Number.isSafeInteger(units) || units < 0)
30318
+ throw new TypeError("Work charges must be non-negative safe integers.");
30319
+ try {
30320
+ for (let index = 0; index < units; index++) this.budget.visitNode();
30321
+ } catch (error) {
30322
+ this.poison(error);
30323
+ throw error;
30324
+ }
30325
+ };
30326
+ onCleanup = (cleanup) => {
30327
+ this.assertOpen();
30328
+ if (typeof cleanup !== "function") throw new TypeError("Cleanup must be a function.");
30329
+ this.checkCollection(this.cleanups.length + 1, this.limits.cleanups, "cleanup");
30330
+ this.cleanups.push(cleanup);
30331
+ };
30332
+ checkCollection(count, limit, name) {
30333
+ this.assertOpen();
30334
+ try {
30335
+ this.budget.allocateCollectionEntries(count);
30336
+ } catch (error) {
30337
+ this.poison(error);
30338
+ throw error;
30339
+ }
30340
+ if (count > limit) throw new RangeError(`Realm ${name} limit exceeded.`);
30341
+ }
30342
+ invokeHost = (operation, call) => {
30343
+ this.assertOpen();
30344
+ const phase = {
30345
+ active: true,
30346
+ extension: this.nestedOperations.get(operation),
30347
+ evaluating: false,
30348
+ pending: /* @__PURE__ */ new Set()
30349
+ };
30350
+ return this.phase.run(phase, () => {
30351
+ try {
30352
+ const result = call();
30353
+ if (types3.isPromise(result) || phase.pending.size > 0 || phase.failure !== void 0) {
30354
+ return Promise.resolve(result).then(
30355
+ async (value) => {
30356
+ await Promise.allSettled(phase.pending);
30357
+ if (phase.failure !== void 0) throw phase.failure.reason;
30358
+ this.assertOpen();
30359
+ return value;
30360
+ },
30361
+ async (error) => {
30362
+ if (error instanceof SandboxError || phase.pending.size > 0) this.poison(error);
30363
+ await Promise.allSettled(phase.pending);
30364
+ throw error;
30365
+ }
30366
+ ).finally(() => {
30367
+ phase.active = false;
30368
+ });
30369
+ }
30370
+ this.assertOpen();
30371
+ phase.active = false;
30372
+ return result;
30373
+ } catch (error) {
30374
+ phase.active = false;
30375
+ if (error instanceof SandboxError) this.poison(error);
30376
+ if (phase.pending.size > 0) {
30377
+ this.poison(error);
30378
+ return Promise.allSettled(phase.pending).then(() => {
30379
+ throw error;
30380
+ });
30381
+ }
30382
+ throw error;
30383
+ }
30384
+ });
30385
+ };
30386
+ importValue(value) {
30387
+ return copyHostValueToSandbox(
30388
+ value,
30389
+ [],
30390
+ this.bridgeOptions(),
30391
+ { seen: /* @__PURE__ */ new WeakMap() },
30392
+ "<realm>"
30393
+ );
30394
+ }
30395
+ exportValue(value) {
30396
+ return deepCopyFromSandbox(value, {
30397
+ compilation: this.compilation,
30398
+ wrapClosure: this.wrapCallback,
30399
+ unwrapHostObject: (object) => exportHostCapability(object, this)
30400
+ });
30401
+ }
30402
+ createHostObject = (definition) => {
30403
+ this.checkCollection(this.hostObjects.size + 1, this.limits.hostObjects, "host object");
30404
+ const object = createLiveHostObject(definition, {
30405
+ owner: this,
30406
+ assertActive: this.assertOpen,
30407
+ chargeWork: this.chargeWork,
30408
+ read: (operation) => {
30409
+ const value = this.invokeHost(operation, operation);
30410
+ if (types3.isPromise(value)) {
30411
+ void Promise.resolve(value).catch(() => void 0);
30412
+ throw new TypeError("Live property getters must be synchronous.");
30413
+ }
30414
+ return this.importValue(value);
30415
+ },
30416
+ write: (operation, value) => {
30417
+ const result = this.invokeHost(operation, () => operation(this.exportValue(value)));
30418
+ if (types3.isPromise(result)) {
30419
+ void Promise.resolve(result).catch(() => void 0);
30420
+ throw new TypeError("Live property setters must be synchronous.");
30421
+ }
30422
+ },
30423
+ method: (operation) => {
30424
+ const value = copyHostValueToSandbox(
30425
+ operation,
30426
+ [],
30427
+ this.bridgeOptions(),
30428
+ this.nativeConversions,
30429
+ "<host-method>"
30430
+ );
30431
+ if (!isSandboxClosure(value)) throw new TypeError("Invalid host method.");
30432
+ return value;
30433
+ }
30434
+ });
30435
+ this.hostObjects.add(object);
30436
+ try {
30437
+ this.budget.chargeDataUsage(1);
30438
+ } catch (error) {
30439
+ this.poison(error);
30440
+ throw error;
30441
+ }
30442
+ return object;
30443
+ };
30444
+ wrapCallback = (closure) => {
30445
+ this.assertOpen();
30446
+ const existing = this.callbackCache.get(closure);
30447
+ if (existing !== void 0 && this.callbacks.has(existing)) return existing;
30448
+ this.checkCollection(this.callbacks.size + 1, this.limits.callbacks, "callback");
30449
+ const invokeCallback = this.invokeCallback;
30450
+ const callback = function(...args) {
30451
+ return invokeCallback(callback, { args, thisValue: this });
30452
+ };
30453
+ this.callbacks.set(callback, closure);
30454
+ this.callbackCache.set(closure, callback);
30455
+ registerGuestCallback(callback, {
30456
+ owner: this,
30457
+ closure,
30458
+ assertActive: () => {
30459
+ this.assertOpen();
30460
+ if (!this.callbacks.has(callback)) throw new TypeError("Guest callback is revoked.");
30461
+ }
30462
+ });
30463
+ try {
30464
+ this.budget.reconcileDataUsage(
30465
+ measureSandboxData([...this.scope?.retainedValues() ?? [], ...this.retainedRoots()])
30466
+ );
30467
+ } catch (error) {
30468
+ this.poison(error);
30469
+ throw error;
30470
+ }
30471
+ return callback;
30472
+ };
30473
+ releaseCallback = (callback) => {
30474
+ readGuestCallback(callback, this);
30475
+ revokeGuestCallback(callback, this);
30476
+ this.callbacks.delete(callback);
30477
+ if (this.active === void 0)
30478
+ reconcileCompiledValues(
30479
+ this.budget,
30480
+ [...this.scope?.retainedValues() ?? [], ...this.retainedRoots()],
30481
+ this.compilation
30482
+ );
30483
+ };
30484
+ invokeCallback = async (callback, options = {}) => {
30485
+ if (this.closed || this.failure !== void 0) await this.dispose();
30486
+ this.assertOpen();
30487
+ const closure = readGuestCallback(callback, this);
30488
+ this.checkCollection(this.pendingCallbacks.size + 1, this.limits.callbacks, "pending callback");
30489
+ const record2 = { closure };
30490
+ this.pendingCallbacks.add(record2);
30491
+ const invoke = async () => {
30492
+ this.assertOpen();
30493
+ readGuestCallback(callback, this);
30494
+ const leave = enterRunningState(closure);
30495
+ const leaveCall = this.budget.enterCall();
30496
+ try {
30497
+ const values = this.importValue([
30498
+ options.thisValue,
30499
+ [...options.args ?? []]
30500
+ ]);
30501
+ const value = await closure.call(values[1], {
30502
+ thisValue: values[0],
30503
+ compilation: this.compilation,
30504
+ stack: []
30505
+ });
30506
+ const settled = await suspendJob(
30507
+ awaitSandboxValue(value, this.controller.signal, this.budget)
30508
+ );
30509
+ return this.exportValue(settled);
30510
+ } finally {
30511
+ leaveCall();
30512
+ leave();
30513
+ }
30514
+ };
30515
+ try {
30516
+ if (this.active !== void 0) {
30517
+ record2.promise = withSandboxPromiseRejectionTracker(
30518
+ this.tracker,
30519
+ () => runResources.run(
30520
+ { signal: this.controller.signal, add: this.onCleanup },
30521
+ () => withCancellationSignal(
30522
+ this.controller.signal,
30523
+ () => this.phase.getStore()?.active ? runAsyncPrefix(invoke) : this.queue.run(invoke)
30524
+ )
30525
+ )
30526
+ );
30527
+ } else {
30528
+ record2.promise = this.perform(() => this.queue.run(invoke));
30529
+ }
30530
+ return await record2.promise;
30531
+ } catch (error) {
30532
+ if (error instanceof SandboxError) this.poison(error);
30533
+ throw error;
30534
+ } finally {
30535
+ this.pendingCallbacks.delete(record2);
30536
+ if (!this.closed && this.active === void 0)
30537
+ reconcileCompiledValues(
30538
+ this.budget,
30539
+ [...this.scope?.retainedValues() ?? [], ...this.retainedRoots()],
30540
+ this.compilation
30541
+ );
30542
+ }
30543
+ };
30544
+ initialize() {
30545
+ if (this.initialized) return;
30546
+ this.assertOpen();
30547
+ this.initialized = true;
30548
+ for (const extension of this.extensions) {
30549
+ const context = Object.freeze({
30550
+ signal: this.controller.signal,
30551
+ onCleanup: this.onCleanup,
30552
+ chargeWork: this.chargeWork,
30553
+ createHostObject: this.createHostObject,
30554
+ invokeCallback: this.invokeCallback,
30555
+ releaseCallback: this.releaseCallback,
30556
+ releaseGuestReference: this.releaseGuestReference,
30557
+ retainGuestArguments: (operation, from) => {
30558
+ this.assertOpen();
30559
+ if (!extension.manifest.capabilities?.includes("guest:retain"))
30560
+ throw new TypeError("Retaining arguments requires the guest:retain grant.");
30561
+ if (typeof operation !== "function")
30562
+ throw new TypeError("Retained operation must be a function.");
30563
+ if (!Number.isSafeInteger(from) || from < 0)
30564
+ throw new TypeError("Argument index must be a non-negative safe integer.");
30565
+ if (this.scope !== void 0)
30566
+ throw new TypeError("Retained operations must be registered during setup.");
30567
+ const previous = this.retainedOperations.get(operation);
30568
+ if (previous !== void 0 && (previous.extension !== extension || previous.from !== from))
30569
+ throw new TypeError("Conflicting retained operation declaration.");
30570
+ this.retainedOperations.set(operation, { extension, from });
30571
+ return operation;
30572
+ },
30573
+ nestedOperation: (operation) => {
30574
+ this.assertOpen();
30575
+ if (!extension.manifest.capabilities?.includes("source:nested"))
30576
+ throw new TypeError("Nested source requires the source:nested grant.");
30577
+ if (typeof operation !== "function")
30578
+ throw new TypeError("Nested operation must be a function.");
30579
+ if (this.scope !== void 0)
30580
+ throw new TypeError("Nested operations must be registered during setup.");
30581
+ const owner = this.nestedOperations.get(operation);
30582
+ if (owner !== void 0 && owner !== extension)
30583
+ throw new TypeError("Nested operation already belongs to another extension.");
30584
+ this.nestedOperations.set(operation, extension);
30585
+ return operation;
30586
+ },
30587
+ evaluateNested: (source) => {
30588
+ const phase = this.phase.getStore();
30589
+ if (!extension.manifest.capabilities?.includes("source:nested") || !phase?.active || phase.extension !== extension || phase.evaluating) {
30590
+ const error = new SandboxError("reentry");
30591
+ this.poison(error);
30592
+ const rejected = Promise.reject(error);
30593
+ void rejected.catch(() => void 0);
30594
+ return rejected;
30595
+ }
30596
+ const pending = this.evaluateNested(source, extension);
30597
+ phase.pending.add(pending);
30598
+ void pending.then(
30599
+ () => {
30600
+ phase.pending.delete(pending);
30601
+ },
30602
+ (reason) => {
30603
+ phase.pending.delete(pending);
30604
+ phase.failure ??= { reason };
30605
+ }
30606
+ );
30607
+ return pending;
30608
+ }
30609
+ });
30610
+ const output = getExtensionSetup(extension)(context);
30611
+ if (types3.isPromise(output)) {
30612
+ void Promise.resolve(output).catch(() => void 0);
30613
+ throw new TypeError("Extension setup must be synchronous.");
30614
+ }
30615
+ const exports = readDataRecord(output, "Extension exports");
30616
+ if (Object.keys(exports).some((key) => key !== "globals" && key !== "modules"))
30617
+ throw new TypeError("Unknown extension export field.");
30618
+ const globals = readDataRecord(
30619
+ exports.globals ?? {},
30620
+ "Extension globals"
30621
+ );
30622
+ const modules = readModules(exports.modules);
30623
+ assertNames(Object.keys(globals), extension.manifest.globals ?? [], "global");
30624
+ assertNames(Object.keys(modules), Object.keys(extension.manifest.modules ?? {}), "module");
30625
+ for (const [name, values] of Object.entries(modules)) {
30626
+ assertNames(Object.keys(values), extension.manifest.modules?.[name] ?? [], "module export");
30627
+ this.modules[name] ??= /* @__PURE__ */ Object.create(null);
30628
+ Object.assign(this.modules[name], values);
30629
+ }
30630
+ Object.assign(this.globals, globals);
30631
+ }
30632
+ const bindings = wrapCallerInjectedBindings(this.globals, this.bridgeOptions());
30633
+ this.scope = new Scope(this.builtinBindings, void 0, void 0, { chargeData: false }).child(
30634
+ bindings,
30635
+ { functionBoundary: true }
30636
+ );
30637
+ }
30638
+ async evaluateRaw(source, filename = "<realm>", nested = false) {
30639
+ this.assertOpen();
30640
+ if (typeof source !== "string") throw new TypeError("Realm source must be a string.");
30641
+ const module = parseExecutableModule(source, filename, this.lease.owner);
30642
+ this.initialize();
30643
+ const imports = resolveModuleImports(module, this.modules, {
30644
+ ...this.bridgeOptions(),
30645
+ wrappedModules: this.convertedModules
30646
+ });
30647
+ for (const [name, value] of Object.entries(imports)) {
30648
+ const binding = this.scope.lookup(name);
30649
+ if (!binding.found) this.scope.declare(name, "const", value);
30650
+ else if (binding.value !== value) throw new TypeError(`Conflicting import '${name}'.`);
30651
+ }
30652
+ const result = await interpret(
30653
+ {
30654
+ type: "BlockStatement",
30655
+ body: module.body.filter((statement) => statement.type !== "ImportDeclaration"),
30656
+ span: module.span
30657
+ },
30658
+ {
30659
+ scope: this.scope,
30660
+ useScopeDirectly: true,
30661
+ budget: this.budget,
30662
+ compilation: this.compilation,
30663
+ signal: this.controller.signal,
30664
+ surfaceUnhandledThrows: true,
30665
+ jobs: this.queue,
30666
+ nested,
30667
+ assertActive: this.assertOpen
30668
+ }
30669
+ );
30670
+ this.assertOpen();
30671
+ return result;
30672
+ }
30673
+ evaluateNested = async (source, extension) => {
30674
+ this.assertOpen();
30675
+ const phase = this.phase.getStore();
30676
+ if (!phase?.active || phase.extension !== extension || phase.evaluating || this.active === void 0)
30677
+ throw new SandboxError("reentry");
30678
+ const leave = this.budget.enterCall();
30679
+ phase.evaluating = true;
30680
+ try {
30681
+ if (++this.nestedDepth > this.limits.nestedEvaluations) {
30682
+ const error = new SandboxError({
30683
+ budget: "callDepth",
30684
+ current: this.nestedDepth,
30685
+ limit: this.limits.nestedEvaluations
30686
+ });
30687
+ this.poison(error);
30688
+ throw error;
30689
+ }
30690
+ const result = await this.evaluateRaw(source, "<nested>", true);
30691
+ if (!result.ok) throw new Error(result.error.message);
30692
+ } finally {
30693
+ this.nestedDepth--;
30694
+ phase.evaluating = false;
30695
+ leave();
30696
+ }
30697
+ };
30698
+ evaluate = async (source, options = {}) => this.perform(async () => {
30699
+ const result = await this.evaluateRaw(source, options.filename);
30700
+ if (!result.ok) {
30701
+ await this.dispose();
30702
+ return { ok: false, error: result.error, stats: result.stats };
30703
+ }
30704
+ return { ok: true, returnValue: this.exportValue(result.returnValue), stats: result.stats };
30705
+ });
30706
+ async perform(task) {
30707
+ if (this.closed || this.failure !== void 0) await this.dispose();
30708
+ this.assertOpen();
30709
+ if (this.active !== void 0) throw new SandboxError("reentry");
30710
+ const pending = Promise.resolve().then(
30711
+ () => withSandboxPromiseRejectionTracker(
30712
+ this.tracker,
30713
+ () => runResources.run(
30714
+ { signal: this.controller.signal, add: this.onCleanup },
30715
+ () => withCancellationSignal(this.controller.signal, task)
30716
+ )
30717
+ )
30718
+ );
30719
+ this.active = pending;
30720
+ try {
30721
+ const result = await pending;
30722
+ await this.queue.drain();
30723
+ const unhandled = await this.tracker.findUnhandledRejection();
30724
+ if (unhandled !== void 0) {
30725
+ const error = new Error(
30726
+ `Unhandled guest promise rejection: ${describeThrownValue(unhandled.reason)}`
30727
+ );
30728
+ error.name = "UnhandledRejectionError";
30729
+ throw error;
30730
+ }
30731
+ if (this.failure !== void 0) throw this.failure.reason;
30732
+ if (!this.closed)
30733
+ reconcileCompiledValues(
30734
+ this.budget,
30735
+ [...this.scope?.retainedValues() ?? [], ...this.retainedRoots()],
30736
+ this.compilation
30737
+ );
30738
+ return result;
30739
+ } catch (error) {
30740
+ this.poison(error);
30741
+ try {
30742
+ await this.dispose();
30743
+ } catch (cleanup) {
30744
+ throw new AggregateError([error, cleanup], "Realm execution and cleanup failed.");
30745
+ }
30746
+ throw error;
30747
+ } finally {
30748
+ this.active = void 0;
30749
+ }
30750
+ }
30751
+ close = () => {
30752
+ this.closed = true;
30753
+ this.controller.abort(new Error("SafeJS realm is closed."));
30754
+ if (this.phase.getStore()?.active) return this.dispose();
30755
+ return Promise.allSettled([
30756
+ this.active,
30757
+ ...Array.from(this.pendingCallbacks, (pending) => pending.promise)
30758
+ ]).then(() => this.dispose());
30759
+ };
30760
+ dispose() {
30761
+ if (this.disposal !== void 0) return this.disposal;
30762
+ this.closed = true;
30763
+ this.controller.abort(new Error("SafeJS realm is closed."));
30764
+ this.options.signal?.removeEventListener("abort", this.abort);
30765
+ for (const callback of this.callbacks.keys()) revokeGuestCallback(callback, this);
30766
+ this.callbacks.clear();
30767
+ for (const object of this.hostObjects) revokeHostObject(object, this);
30768
+ this.hostObjects.clear();
30769
+ for (const reference of this.guestReferences.keys()) revokeGuestReference(reference, this);
30770
+ this.guestReferences.clear();
30771
+ this.budget.setRetainedValues(this, void 0);
30772
+ this.disposal = (async () => {
30773
+ const errors = [];
30774
+ for (const cleanup of this.cleanups.splice(0).reverse()) {
30775
+ try {
30776
+ await cleanup();
30777
+ } catch (error) {
30778
+ errors.push(error);
30779
+ }
30780
+ }
30781
+ this.scope = void 0;
30782
+ this.convertedModules.clear();
30783
+ for (const key of Object.keys(this.globals)) delete this.globals[key];
30784
+ for (const key of Object.keys(this.modules)) delete this.modules[key];
30785
+ for (const key of Object.keys(this.builtinBindings))
30786
+ Reflect.deleteProperty(this.builtinBindings, key);
30787
+ this.nativeConversions.seen = /* @__PURE__ */ new WeakMap();
30788
+ reconcileCompiledValues(this.budget, [], this.compilation);
30789
+ this.compilation.dispose();
30790
+ this.lease.release();
30791
+ if (errors.length > 0) throw new AggregateError(errors, "Realm cleanup failed.");
30792
+ })();
30793
+ return this.disposal;
30794
+ }
30795
+ };
30796
+ function readModules(input) {
30797
+ const entries = (value, label) => {
30798
+ if (types3.isMap(value) && !types3.isProxy(value)) {
30799
+ const result = [...Map.prototype.entries.call(value)];
30800
+ if (result.length > 4096 || result.some(([key]) => typeof key !== "string" || key.length === 0))
30801
+ throw new TypeError(`${label} requires bounded string keys.`);
30802
+ return result;
30803
+ }
30804
+ return Object.entries(readDataRecord(value, label));
30805
+ };
30806
+ const modules = /* @__PURE__ */ Object.create(null);
30807
+ for (const [name, exports] of entries(input ?? {}, "Module registry")) {
30808
+ const exported = /* @__PURE__ */ Object.create(null);
30809
+ for (const [key, value] of entries(exports, "Module exports"))
30810
+ exported[key] = value;
30811
+ modules[name] = exported;
30812
+ }
30813
+ return modules;
30814
+ }
30815
+ function assertNames(actual, expected, label) {
30816
+ if (actual.length !== expected.length || actual.some((name) => !expected.includes(name)))
30817
+ throw new TypeError(`Extension ${label} names do not match its manifest.`);
30818
+ }
30819
+ function createRealm(options = {}) {
30820
+ const state = new RealmState(readRealmOptions(options));
30821
+ return Object.freeze({
30822
+ extensions: Object.freeze(state.extensions.map((extension) => extension.manifest)),
30823
+ evaluate: state.evaluate,
30824
+ invokeCallback: state.invokeCallback,
30825
+ releaseCallback: state.releaseCallback,
30826
+ releaseGuestReference: state.releaseGuestReference,
30827
+ close: state.close
30828
+ });
30829
+ }
30830
+ async function runWithExtensions(source, options) {
30831
+ if (options.snapshot !== void 0 || options.snapshotBackend !== void 0 || options.snapshotPath !== void 0 || options.entryPointArgs !== void 0)
30832
+ throw new TypeError(
30833
+ "Live extension runs do not support snapshots or entryPointArgs; use a persistent realm."
30834
+ );
30835
+ const state = new RealmState(readRealmOptions(options, true));
30836
+ try {
30837
+ const result = await state.perform(() => state.evaluateRaw(source, options.filename));
30838
+ if (result.ok) encodeReplayData(result.returnValue);
30839
+ return {
30840
+ ...result,
30841
+ snapshot: {
30842
+ version: 1,
30843
+ sourceHash: hashSource(source),
30844
+ bindings: {},
30845
+ replayError: "Live realm state cannot be serialized or replayed."
30846
+ }
30847
+ };
30848
+ } catch (error) {
30849
+ if (state.disposal === void 0) {
30850
+ try {
30851
+ await state.close();
30852
+ } catch (cleanupError) {
30853
+ throw new AggregateError([error, cleanupError], "Realm execution and cleanup failed.");
30854
+ }
30855
+ }
30856
+ throw error;
30857
+ } finally {
30858
+ if (state.disposal === void 0) await state.close();
30859
+ }
30860
+ }
30861
+ function readRealmOptions(value, oneShot = false) {
30862
+ const options = readDataRecord(value, "Realm options");
30863
+ const supported = /* @__PURE__ */ new Set([
30864
+ "bindings",
30865
+ "modules",
30866
+ "extensions",
30867
+ "grants",
30868
+ "budget",
30869
+ "signal",
30870
+ "sink",
30871
+ "randomSeed",
30872
+ "limits"
30873
+ ]);
30874
+ for (const [key, entry] of Object.entries(options)) {
30875
+ if (supported.has(key) || oneShot && (key === "filename" || entry === void 0)) continue;
30876
+ throw new TypeError(`Unsupported ${oneShot ? "extension-run" : "realm"} option '${key}'.`);
30877
+ }
30878
+ return options;
30879
+ }
30880
+
30881
+ // packages/safe-js/src/snapshot/dump.ts
30882
+ var RUN_DUMP_CONTROLLER = /* @__PURE__ */ Symbol("SafeJS.run-dump-controller");
30883
+ function attachDumpController(result, controller) {
30884
+ Object.defineProperty(result, RUN_DUMP_CONTROLLER, {
30885
+ configurable: false,
30886
+ enumerable: false,
30887
+ value: controller,
30888
+ writable: false
30889
+ });
30890
+ return result;
30891
+ }
30892
+ function createDumpController(lifecycle) {
30893
+ let finished = false;
30894
+ let failed;
30895
+ let finalSnapshot;
30896
+ let latestSnapshot;
30897
+ let latestSnapshotFactory;
30898
+ let pendingRequest;
30899
+ return {
30900
+ fail(error) {
30901
+ finished = true;
30902
+ failed = {
30903
+ error
30904
+ };
30905
+ if (pendingRequest === void 0) {
30906
+ return;
30907
+ }
30908
+ pendingRequest.reject(error);
30909
+ pendingRequest = void 0;
30910
+ },
30911
+ finalize(snapshot) {
30912
+ finished = true;
30913
+ finalSnapshot = snapshot;
30914
+ latestSnapshot = snapshot;
30915
+ latestSnapshotFactory = void 0;
30916
+ if (pendingRequest !== void 0) {
30917
+ settlePendingSnapshot(snapshot);
30918
+ }
30919
+ },
30920
+ onYield(createSnapshot) {
30921
+ latestSnapshot = void 0;
30922
+ latestSnapshotFactory = createSnapshot;
30923
+ if (pendingRequest === void 0) {
30924
+ return;
30925
+ }
30926
+ settlePendingSnapshot(createSnapshot());
30927
+ },
30928
+ requestCurrentSnapshot(options = {}) {
30929
+ assertDumpAllowed(options);
30930
+ if (failed !== void 0) {
30931
+ return Promise.reject(failed.error);
29904
30932
  }
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.");
30933
+ if (latestSnapshot !== void 0 || latestSnapshotFactory !== void 0) {
30934
+ try {
30935
+ return Promise.resolve(serializeRunSnapshot(latestSnapshot ?? latestSnapshotFactory()));
30936
+ } catch (error) {
30937
+ return Promise.reject(error);
30938
+ }
29909
30939
  }
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
30940
+ return this.requestSnapshot(options);
30941
+ },
30942
+ requestSnapshot(options = {}) {
30943
+ assertDumpAllowed(options);
30944
+ if (failed !== void 0) {
30945
+ if ((options.onFailure === "checkpoint" || options.onFailure === void 0 && isDataBudgetError(failed.error)) && finalSnapshot !== void 0) {
30946
+ try {
30947
+ return Promise.resolve(serializeRunSnapshot(finalSnapshot));
30948
+ } catch (error) {
30949
+ return Promise.reject(error);
30950
+ }
30951
+ }
30952
+ return Promise.reject(failed.error);
30953
+ }
30954
+ if (finished) {
30955
+ if (finalSnapshot === void 0) {
30956
+ throw new Error("Run completed without producing a snapshot.");
30957
+ }
30958
+ try {
30959
+ const serializedSnapshot = serializeRunSnapshot(finalSnapshot);
30960
+ return Promise.resolve(serializedSnapshot);
30961
+ } catch (error) {
30962
+ return Promise.reject(error);
30963
+ }
30964
+ }
30965
+ if (options.mode === "replay" && (latestSnapshot !== void 0 || latestSnapshotFactory !== void 0)) {
30966
+ return this.requestCurrentSnapshot(options);
30967
+ }
30968
+ if (pendingRequest !== void 0) {
30969
+ return pendingRequest.promise;
30970
+ }
30971
+ let resolveSnapshot = () => void 0;
30972
+ let rejectSnapshot = () => void 0;
30973
+ const promise = new Promise((resolve, reject) => {
30974
+ resolveSnapshot = resolve;
30975
+ rejectSnapshot = reject;
29917
30976
  });
30977
+ pendingRequest = {
30978
+ promise,
30979
+ reject: rejectSnapshot,
30980
+ resolve: resolveSnapshot
30981
+ };
30982
+ return promise;
29918
30983
  }
29919
- } catch (error) {
29920
- try {
29921
- await iterator.return?.();
29922
- } catch {
29923
- throw error;
30984
+ };
30985
+ function assertDumpAllowed(options) {
30986
+ if ((lifecycle?.hostCallbackDepth ?? 0) > 0 && (options.mode !== "replay" || lifecycle?.hostCallbackContext.getStore() === true)) {
30987
+ throw new SandboxError("reentry");
29924
30988
  }
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
30989
  }
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;
30990
+ function settlePendingSnapshot(snapshot) {
30991
+ try {
30992
+ settlePendingRequest(serializeRunSnapshot(snapshot));
30993
+ } catch (error) {
30994
+ pendingRequest?.reject(error);
30995
+ pendingRequest = void 0;
29939
30996
  }
29940
- for (const [key, value] of ownEnumerableSandboxEntries(source)) {
29941
- setSandboxProperty(target, key, value, budget);
30997
+ }
30998
+ function settlePendingRequest(snapshot) {
30999
+ if (pendingRequest === void 0) {
31000
+ return;
29942
31001
  }
31002
+ pendingRequest.resolve(snapshot);
31003
+ pendingRequest = void 0;
29943
31004
  }
29944
- return target;
29945
31005
  }
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;
31006
+ function isDataBudgetError(error) {
31007
+ return typeof error === "object" && error !== null && "code" in error && error.code === "budgetExceeded" && "budget" in error && error.budget === "dataSize";
29954
31008
  }
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.");
31009
+ function dump(result, options = {}) {
31010
+ const controller = readDumpController(result);
31011
+ if (controller !== void 0) {
31012
+ return controller.requestSnapshot(options);
31013
+ }
31014
+ if (hasSnapshot(result)) {
31015
+ try {
31016
+ return Promise.resolve(serializeRunSnapshot(result.snapshot));
31017
+ } catch (error) {
31018
+ return Promise.reject(error);
29963
31019
  }
29964
- if (field === "value") descriptor.value = entry.value;
29965
- else descriptor[field] = Boolean(entry.value);
29966
31020
  }
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
- }
31021
+ return Promise.resolve(result).then((resolved) => {
31022
+ if (!hasSnapshot(resolved)) {
31023
+ throw new Error("Run completed without producing a snapshot.");
29980
31024
  }
31025
+ return serializeRunSnapshot(resolved.snapshot);
31026
+ });
31027
+ }
31028
+ function dumpCurrent(result) {
31029
+ const controller = readDumpController(result);
31030
+ if (controller !== void 0) {
31031
+ return controller.requestCurrentSnapshot();
29981
31032
  }
29982
- Object.defineProperty(properties, key, descriptor);
29983
- markDescriptorObject(properties);
31033
+ return dump(result);
29984
31034
  }
29985
- function isAssignableSandboxTarget(value) {
29986
- return typeof value === "object" && value !== null && !isSandboxClosure(value) && !isSandboxGenerator(value) && !isSandboxMap(value) && !isSandboxSet(value) && !isSandboxPromise(value) && !isSandboxRegex(value);
31035
+ function serializeRunSnapshot(snapshot) {
31036
+ return serializeSafeJSSnapshot(snapshot);
29987
31037
  }
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);
31038
+ function hasSnapshot(value) {
31039
+ return typeof value === "object" && value !== null && Object.prototype.hasOwnProperty.call(value, "snapshot");
30007
31040
  }
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.");
31041
+ function readDumpController(value) {
31042
+ if (typeof value !== "object" || value === null) {
31043
+ return void 0;
30018
31044
  }
30019
- budget.allocateArrayLength(lengthOrValue);
30020
- return new Array(lengthOrValue);
31045
+ return value[RUN_DUMP_CONTROLLER];
30021
31046
  }
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);
31047
+
31048
+ // packages/safe-js/src/error-codes.ts
31049
+ function getOwnErrorCode(error) {
31050
+ if (typeof error !== "object" || error === null || !Object.prototype.hasOwnProperty.call(error, "code")) {
31051
+ return void 0;
30028
31052
  }
31053
+ const code = error.code;
31054
+ return typeof code === "string" ? code : void 0;
30029
31055
  }
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);
31056
+ function hasOwnErrorCode(error, code) {
31057
+ return getOwnErrorCode(error) === code;
30039
31058
  }
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
- }
31059
+
31060
+ // packages/safe-js/src/snapshot/backend.ts
31061
+ import { randomUUID as randomUUID2 } from "node:crypto";
31062
+ import { readFile, rename, stat, unlink, writeFile } from "node:fs/promises";
31063
+ import { dirname } from "node:path";
31064
+ var DEFAULT_WRITE_MAX_ATTEMPTS = 3;
31065
+ var DEFAULT_WRITE_RETRY_DELAY_MS = 100;
31066
+ var LOCKED_FILE_ERROR_CODES = /* @__PURE__ */ new Set(["EACCES", "EBUSY", "EPERM"]);
31067
+ var pendingOperations = /* @__PURE__ */ new Map();
31068
+ var FileSnapshotBackend = class {
31069
+ constructor(path, options = {}) {
31070
+ this.path = path;
31071
+ this.#writeMaxAttempts = options.writeMaxAttempts ?? DEFAULT_WRITE_MAX_ATTEMPTS;
31072
+ this.#writeRetryDelayMs = options.writeRetryDelayMs ?? DEFAULT_WRITE_RETRY_DELAY_MS;
30049
31073
  }
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.");
31074
+ path;
31075
+ #writeMaxAttempts;
31076
+ #writeRetryDelayMs;
31077
+ async read() {
31078
+ try {
31079
+ return JSON.parse(await readFile(this.path, "utf8"));
31080
+ } catch (error) {
31081
+ if (hasErrorCode(error, "ENOENT")) {
31082
+ return void 0;
31083
+ }
31084
+ if (error instanceof SyntaxError) {
31085
+ throw new Error(`Failed to parse snapshot at ${this.path}: ${error.message}`);
31086
+ }
31087
+ throw error;
31088
+ }
30056
31089
  }
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.`;
31090
+ async write(snapshot) {
31091
+ await enqueueOperation(
31092
+ this.path,
31093
+ () => writeSnapshotAtomically(this.path, snapshot, {
31094
+ maxAttempts: this.#writeMaxAttempts,
31095
+ retryDelayMs: this.#writeRetryDelayMs
31096
+ })
31097
+ );
30064
31098
  }
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.`;
31099
+ async remove() {
31100
+ await enqueueOperation(this.path, async () => {
31101
+ try {
31102
+ await unlink(this.path);
31103
+ } catch (error) {
31104
+ if (!hasErrorCode(error, "ENOENT")) {
31105
+ throw error;
31106
+ }
31107
+ }
31108
+ });
30070
31109
  }
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;
31110
+ };
31111
+ async function writeSnapshotAtomically(snapshotPath, snapshot, options) {
31112
+ const parentPath = dirname(snapshotPath);
31113
+ const contents = serializeSafeJSSnapshot(snapshot);
31114
+ await assertParentDirectoryExists(snapshotPath, parentPath);
31115
+ for (let attempt = 1; attempt <= options.maxAttempts; attempt += 1) {
31116
+ try {
31117
+ const temporaryPath = `${snapshotPath}.${randomUUID2()}.tmp`;
31118
+ await writeSnapshotOnce(temporaryPath, snapshotPath, contents);
31119
+ return;
31120
+ } catch (error) {
31121
+ if (hasErrorCode(error, "EEXIST")) {
31122
+ if (attempt === options.maxAttempts) {
31123
+ throw new Error(
31124
+ `Failed to write snapshot at ${snapshotPath} after ${options.maxAttempts} attempts: temporary path already exists`,
31125
+ {
31126
+ cause: error
31127
+ }
31128
+ );
31129
+ }
31130
+ continue;
31131
+ }
31132
+ if (!isLockedFileError(error)) {
31133
+ throw error;
31134
+ }
31135
+ if (attempt === options.maxAttempts) {
31136
+ throw new Error(
31137
+ `Failed to write snapshot at ${snapshotPath} after ${options.maxAttempts} attempts: file is locked (${getOwnErrorCode(error)})`,
31138
+ {
31139
+ cause: error
31140
+ }
31141
+ );
31142
+ }
31143
+ await delay(options.retryDelayMs);
30080
31144
  }
30081
- bindImportDeclaration(statement, registry, wrappedModules, bindings, options);
30082
31145
  }
30083
- return bindings;
30084
31146
  }
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
31147
+ async function assertParentDirectoryExists(snapshotPath, parentPath) {
31148
+ try {
31149
+ const parent = await stat(parentPath);
31150
+ if (!parent.isDirectory()) {
31151
+ throw new Error(
31152
+ `Cannot write snapshot at ${snapshotPath}: parent path ${parentPath} is not a directory`
30114
31153
  );
30115
31154
  }
30116
- if (options.allowMissing && specifier.type !== "ImportNamespaceSpecifier") {
30117
- const exportName = specifier.type === "ImportDefaultSpecifier" ? "default" : specifier.imported.name;
30118
- if (!Object.hasOwn(wrappedExports, exportName)) continue;
31155
+ } catch (error) {
31156
+ if (hasErrorCode(error, "ENOENT")) {
31157
+ throw new Error(
31158
+ `Cannot write snapshot at ${snapshotPath}: parent directory ${parentPath} does not exist`,
31159
+ {
31160
+ cause: error
31161
+ }
31162
+ );
30119
31163
  }
30120
- bindings[localName] = resolveImportSpecifier(moduleName, specifier, wrappedExports);
31164
+ throw error;
30121
31165
  }
30122
31166
  }
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;
31167
+ async function writeSnapshotOnce(temporaryPath, snapshotPath, contents) {
31168
+ let temporaryCreated = false;
31169
+ let renamed = false;
31170
+ try {
31171
+ try {
31172
+ await writeFile(temporaryPath, contents, { encoding: "utf8", flag: "wx" });
31173
+ temporaryCreated = true;
31174
+ } catch (error) {
31175
+ if (!hasErrorCode(error, "EEXIST")) {
31176
+ await removeTemporarySnapshot(temporaryPath).catch(() => void 0);
31177
+ }
31178
+ throw error;
31179
+ }
31180
+ await rename(temporaryPath, snapshotPath);
31181
+ renamed = true;
31182
+ } finally {
31183
+ if (temporaryCreated && !renamed) {
31184
+ await removeTemporarySnapshot(temporaryPath).catch(() => void 0);
31185
+ }
30131
31186
  }
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
31187
  }
30142
- function normalizeModuleRegistry(modules) {
30143
- if (modules === void 0) {
30144
- return /* @__PURE__ */ new Map();
31188
+ async function enqueueOperation(path, operation) {
31189
+ const previous = pendingOperations.get(path) ?? Promise.resolve();
31190
+ const pending = previous.catch(() => void 0).then(operation);
31191
+ const queued = pending.catch(() => void 0);
31192
+ pendingOperations.set(path, queued);
31193
+ try {
31194
+ await pending;
31195
+ } finally {
31196
+ if (pendingOperations.get(path) === queued) {
31197
+ pendingOperations.delete(path);
31198
+ }
30145
31199
  }
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
31200
  }
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
- }
31201
+ async function removeTemporarySnapshot(temporaryPath) {
31202
+ try {
31203
+ await unlink(temporaryPath);
31204
+ } catch (error) {
31205
+ if (!hasErrorCode(error, "ENOENT")) {
31206
+ throw error;
30165
31207
  }
30166
31208
  }
30167
31209
  }
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
- );
31210
+ async function delay(ms) {
31211
+ if (ms === 0) {
31212
+ return;
31213
+ }
31214
+ await new Promise((resolve) => setTimeout(resolve, ms));
30173
31215
  }
30174
- function createBindingRecord(entries) {
30175
- return Object.assign(/* @__PURE__ */ Object.create(null), entries);
31216
+ function hasErrorCode(error, code) {
31217
+ return hasOwnErrorCode(error, code);
31218
+ }
31219
+ function isLockedFileError(error) {
31220
+ const code = getOwnErrorCode(error);
31221
+ return code !== void 0 && LOCKED_FILE_ERROR_CODES.has(code);
30176
31222
  }
30177
31223
 
31224
+ // packages/safe-js/src/run.ts
31225
+ import { AsyncLocalStorage as AsyncLocalStorage7 } from "node:async_hooks";
31226
+
30178
31227
  // packages/safe-js/src/snapshot/scheduler.ts
30179
31228
  var DEFAULT_SNAPSHOT_INTERVAL_MS = 3e4;
30180
31229
  function createSnapshotScheduler(options) {
@@ -30397,9 +31446,10 @@ var UnhandledRejectionError = class extends Error {
30397
31446
  };
30398
31447
  var DEFAULT_MAX_CALL_DEPTH = 1e3;
30399
31448
  function run(source, options = {}) {
31449
+ if (options.extensions !== void 0) return runWithExtensions(source, options);
30400
31450
  const lifecycle = {
30401
31451
  hostCallbackDepth: 0,
30402
- hostCallbackContext: new AsyncLocalStorage6()
31452
+ hostCallbackContext: new AsyncLocalStorage7()
30403
31453
  };
30404
31454
  const dumpController = createDumpController(lifecycle);
30405
31455
  const promiseTracker = createSandboxPromiseRejectionTracker();
@@ -30465,32 +31515,7 @@ function run(source, options = {}) {
30465
31515
  lifecycle
30466
31516
  })
30467
31517
  );
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
- };
31518
+ const builtinBindings = createBuiltinBindings({ compileOwner: operation.owner, budget, hostCalls, sink: options.sink, random: random?.generator.next });
30494
31519
  const importMeta = convertInitialInput(
30495
31520
  () => deepCopyToSandbox(options.importMeta ?? {})
30496
31521
  );
@@ -30952,6 +31977,7 @@ export {
30952
31977
  parse,
30953
31978
  parseModule,
30954
31979
  hashSource,
31980
+ defineExtension,
30955
31981
  noopOtelSink,
30956
31982
  bindOtelSpan,
30957
31983
  activateOtelSpan,
@@ -30980,10 +32006,11 @@ export {
30980
32006
  validateSnapshotMigration,
30981
32007
  restore,
30982
32008
  lint,
30983
- runResources,
32009
+ declareHostOperation,
30984
32010
  createSeededRandom,
32011
+ runResources,
30985
32012
  createReplayableRandom,
30986
- declareHostOperation,
32013
+ createRealm,
30987
32014
  dump,
30988
32015
  dumpCurrent,
30989
32016
  getOwnErrorCode,
@@ -30991,4 +32018,4 @@ export {
30991
32018
  FileSnapshotBackend,
30992
32019
  run
30993
32020
  };
30994
- //# sourceMappingURL=chunk-B7H4ZL65.js.map
32021
+ //# sourceMappingURL=chunk-MXUOEOBE.js.map