@poe-platform/safe-js 0.1.21 → 0.1.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -1
- package/dist/safe-js/chunks/{chunk-B7H4ZL65.js → chunk-2M6MNQBY.js} +1937 -1008
- package/dist/safe-js/chunks/chunk-2M6MNQBY.js.map +7 -0
- package/dist/safe-js/chunks/{chunk-GMDOPMVZ.js → chunk-BO5CZWZM.js} +2 -2
- package/dist/safe-js/cli.js +2 -2
- package/dist/safe-js/core.d.ts +3 -0
- package/dist/safe-js/core.js +5 -1
- package/dist/safe-js/extensions.d.ts +42 -0
- package/dist/safe-js/index.d.ts +4 -1
- package/dist/safe-js/index.js +6 -2
- package/dist/safe-js/index.js.map +2 -2
- package/dist/safe-js/interp/async.d.ts +1 -0
- package/dist/safe-js/interp/host-bridge.d.ts +14 -1
- package/dist/safe-js/interp/host-capabilities.d.ts +43 -0
- package/dist/safe-js/interp/interpreter.d.ts +4 -0
- package/dist/safe-js/interp/jobs.d.ts +20 -0
- package/dist/safe-js/interp/values.d.ts +1 -0
- package/dist/safe-js/modules/registry.d.ts +3 -1
- package/dist/safe-js/realm.d.ts +43 -0
- package/dist/safe-js/run.d.ts +5 -1
- package/package.json +2 -2
- package/dist/safe-js/chunks/chunk-B7H4ZL65.js.map +0 -7
- /package/dist/safe-js/chunks/{chunk-GMDOPMVZ.js.map → chunk-BO5CZWZM.js.map} +0 -0
|
@@ -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,124 @@ 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
|
+
function createLiveHostObject(definition, controller) {
|
|
6215
|
+
const input = readDataRecord(definition, "Host object definition");
|
|
6216
|
+
if (Object.keys(input).some((key) => key !== "properties" && key !== "methods"))
|
|
6217
|
+
throw new TypeError("Unknown host object definition field.");
|
|
6218
|
+
const properties = /* @__PURE__ */ new Map();
|
|
6219
|
+
for (const [name, inputProperty] of Object.entries(
|
|
6220
|
+
readDataRecord(input.properties ?? {}, "Host properties")
|
|
6221
|
+
)) {
|
|
6222
|
+
const property = readDataRecord(inputProperty, `Host property '${name}'`);
|
|
6223
|
+
if (Object.keys(property).some((key) => key !== "get" && key !== "set"))
|
|
6224
|
+
throw new TypeError("Unknown host property field.");
|
|
6225
|
+
if (property.get !== void 0 && typeof property.get !== "function" || property.set !== void 0 && typeof property.set !== "function")
|
|
6226
|
+
throw new TypeError("Host property operations must be functions.");
|
|
6227
|
+
properties.set(name, property);
|
|
6228
|
+
}
|
|
6229
|
+
const operations = readDataRecord(input.methods ?? {}, "Host methods");
|
|
6230
|
+
for (const [name, operation] of Object.entries(operations)) {
|
|
6231
|
+
if (typeof operation !== "function") throw new TypeError("Host methods must be functions.");
|
|
6232
|
+
if (properties.has(name)) throw new TypeError(`Conflicting host member '${name}'.`);
|
|
6233
|
+
}
|
|
6234
|
+
for (const name of [...properties.keys(), ...Object.keys(operations)]) {
|
|
6235
|
+
if (["constructor", "prototype", "__proto__"].includes(name))
|
|
6236
|
+
throw new TypeError(`Reserved host member '${name}'.`);
|
|
6237
|
+
}
|
|
6238
|
+
controller.assertActive();
|
|
6239
|
+
controller.chargeWork(properties.size + Object.keys(operations).length + 1);
|
|
6240
|
+
const host = Object.freeze(/* @__PURE__ */ Object.create(null));
|
|
6241
|
+
const guest = Object.freeze(/* @__PURE__ */ Object.create(null));
|
|
6242
|
+
const methods = new Map(
|
|
6243
|
+
Object.entries(operations).map(([name, operation]) => [
|
|
6244
|
+
name,
|
|
6245
|
+
controller.method(operation)
|
|
6246
|
+
])
|
|
6247
|
+
);
|
|
6248
|
+
const state = { host, guest, controller, properties, methods };
|
|
6249
|
+
hostObjects.set(host, state);
|
|
6250
|
+
guestObjects.set(guest, state);
|
|
6251
|
+
return host;
|
|
6252
|
+
}
|
|
6253
|
+
function isGuestHostObject(value) {
|
|
6254
|
+
return typeof value === "object" && value !== null && guestObjects.has(value);
|
|
6255
|
+
}
|
|
6256
|
+
function isLiveCapability(value) {
|
|
6257
|
+
return (typeof value === "object" && value !== null || typeof value === "function") && (hostObjects.has(value) || guestObjects.has(value) || guestCallbacks.has(value));
|
|
6258
|
+
}
|
|
6259
|
+
function importHostCapability(value, owner) {
|
|
6260
|
+
const object = hostObjects.get(value);
|
|
6261
|
+
if (object !== void 0) {
|
|
6262
|
+
if (object.controller.owner !== owner) throw new TypeError("Foreign realm host capability.");
|
|
6263
|
+
object.controller.assertActive();
|
|
6264
|
+
return object.guest;
|
|
6265
|
+
}
|
|
6266
|
+
const callback = guestCallbacks.get(value);
|
|
6267
|
+
if (callback !== void 0) {
|
|
6268
|
+
if (callback.owner !== owner) throw new TypeError("Foreign realm guest callback.");
|
|
6269
|
+
callback.assertActive();
|
|
6270
|
+
if (callback.closure === void 0) throw new TypeError("Guest callback is revoked.");
|
|
6271
|
+
return callback.closure;
|
|
6272
|
+
}
|
|
6273
|
+
throw new TypeError("Unsupported live capability conversion.");
|
|
6274
|
+
}
|
|
6275
|
+
function exportHostCapability(value, owner) {
|
|
6276
|
+
const state = guestObjects.get(value);
|
|
6277
|
+
if (state === void 0 || state.controller.owner !== owner)
|
|
6278
|
+
throw new TypeError("Foreign realm host capability.");
|
|
6279
|
+
state.controller.assertActive();
|
|
6280
|
+
return state.host;
|
|
6281
|
+
}
|
|
6282
|
+
function registerGuestCallback(callback, state) {
|
|
6283
|
+
guestCallbacks.set(callback, state);
|
|
6284
|
+
}
|
|
6285
|
+
function readGuestCallback(callback, owner) {
|
|
6286
|
+
const state = typeof callback === "function" ? guestCallbacks.get(callback) : void 0;
|
|
6287
|
+
if (state === void 0 || state.owner !== owner)
|
|
6288
|
+
throw new TypeError("Foreign or invalid guest callback.");
|
|
6289
|
+
state.assertActive();
|
|
6290
|
+
if (state.closure === void 0) throw new TypeError("Guest callback is revoked.");
|
|
6291
|
+
return state.closure;
|
|
6292
|
+
}
|
|
6293
|
+
function revokeGuestCallback(callback, owner) {
|
|
6294
|
+
const state = guestCallbacks.get(callback);
|
|
6295
|
+
if (state === void 0 || state.owner !== owner) throw new TypeError("Foreign guest callback.");
|
|
6296
|
+
state.closure = void 0;
|
|
6297
|
+
}
|
|
6298
|
+
function revokeHostObject(value, owner) {
|
|
6299
|
+
const state = hostObjects.get(value);
|
|
6300
|
+
if (state === void 0 || state.controller.owner !== owner)
|
|
6301
|
+
throw new TypeError("Foreign host object.");
|
|
6302
|
+
state.properties.clear();
|
|
6303
|
+
state.methods.clear();
|
|
6304
|
+
}
|
|
6305
|
+
function getHostObjectMember(value, key) {
|
|
6306
|
+
const state = guestObjects.get(value);
|
|
6307
|
+
state.controller.assertActive();
|
|
6308
|
+
state.controller.chargeWork();
|
|
6309
|
+
const property = state.properties.get(key);
|
|
6310
|
+
if (property !== void 0)
|
|
6311
|
+
return property.get === void 0 ? void 0 : state.controller.read(property.get);
|
|
6312
|
+
return state.methods.get(key);
|
|
6313
|
+
}
|
|
6314
|
+
function setHostObjectMember(value, key, entry) {
|
|
6315
|
+
const state = guestObjects.get(value);
|
|
6316
|
+
state.controller.assertActive();
|
|
6317
|
+
state.controller.chargeWork();
|
|
6318
|
+
const property = state.properties.get(key);
|
|
6319
|
+
if (property?.set === void 0) throw new TypeError(`Host property '${key}' is not writable.`);
|
|
6320
|
+
state.controller.write(property.set, entry);
|
|
6321
|
+
}
|
|
6322
|
+
function getHostObjectKeys(value) {
|
|
6323
|
+
const state = guestObjects.get(value);
|
|
6324
|
+
state.controller.assertActive();
|
|
6325
|
+
return [...state.properties.keys(), ...state.methods.keys()];
|
|
6326
|
+
}
|
|
6327
|
+
|
|
6129
6328
|
// packages/safe-js/src/interp/values.ts
|
|
6130
6329
|
import { types as nodeTypes } from "node:util";
|
|
6131
6330
|
|
|
@@ -6246,7 +6445,7 @@ async function flushPromiseJobs() {
|
|
|
6246
6445
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
6247
6446
|
|
|
6248
6447
|
// packages/safe-js/src/snapshot/validation.ts
|
|
6249
|
-
import { types } from "node:util";
|
|
6448
|
+
import { types as types2 } from "node:util";
|
|
6250
6449
|
|
|
6251
6450
|
// packages/safe-js/src/interp/arguments.ts
|
|
6252
6451
|
var sandboxArgumentsBrand = /* @__PURE__ */ Symbol("SandboxArguments");
|
|
@@ -6443,6 +6642,7 @@ function setSandboxPrototype(value, prototype, budget) {
|
|
|
6443
6642
|
else prototypes.set(value, prototype);
|
|
6444
6643
|
}
|
|
6445
6644
|
function isPrototypeRecord(value) {
|
|
6645
|
+
if (isGuestHostObject(value)) return false;
|
|
6446
6646
|
if (isSandboxClosure(value) || isSandboxGenerator(value) || isSandboxMap(value) || isSandboxPromise(value) || isSandboxRegex(value) || isSandboxSet(value))
|
|
6447
6647
|
return false;
|
|
6448
6648
|
const prototype = Object.getPrototypeOf(value);
|
|
@@ -6455,6 +6655,7 @@ function hasManagedDescriptors(value) {
|
|
|
6455
6655
|
return descriptorObjects.has(value);
|
|
6456
6656
|
}
|
|
6457
6657
|
function hasGuestObjectState(value) {
|
|
6658
|
+
if (isLiveCapability(value)) return true;
|
|
6458
6659
|
if (functionProperties.has(value) || prototypes.has(value)) return true;
|
|
6459
6660
|
return descriptorObjects.has(value) && Object.values(Object.getOwnPropertyDescriptors(value)).some(
|
|
6460
6661
|
(descriptor) => !descriptor.enumerable || !descriptor.configurable || !descriptor.writable
|
|
@@ -7088,7 +7289,7 @@ function validateGenericValue(value, path, depth, state) {
|
|
|
7088
7289
|
if (typeof value === "object" && value !== null && hasGuestObjectState(value)) {
|
|
7089
7290
|
fail("invalidState", path, "guest function properties, prototype links and custom descriptors cannot be restored");
|
|
7090
7291
|
}
|
|
7091
|
-
if (state.dataPropertiesOnly &&
|
|
7292
|
+
if (state.dataPropertiesOnly && types2.isProxy(value)) {
|
|
7092
7293
|
fail("invalidType", path, "proxy objects are not snapshot data");
|
|
7093
7294
|
}
|
|
7094
7295
|
if (depth > state.limits.maxDepth)
|
|
@@ -9178,6 +9379,7 @@ function createSandboxClosure(input) {
|
|
|
9178
9379
|
return Object.freeze(closure);
|
|
9179
9380
|
}
|
|
9180
9381
|
function ownEnumerableSandboxEntries(value) {
|
|
9382
|
+
if (isGuestHostObject(value)) return getHostObjectKeys(value).map((key) => [key, getHostObjectMember(value, key)]);
|
|
9181
9383
|
if (value === null || value === void 0) throw new TypeError("Cannot convert undefined or null to object.");
|
|
9182
9384
|
if (isGuestClosure(value)) return Object.entries(value.properties ?? {});
|
|
9183
9385
|
if (isSandboxClosure(value) || isSandboxGenerator(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxPromise(value) || isSandboxRegex(value)) return [];
|
|
@@ -9330,6 +9532,10 @@ function measureSandboxData(values, options = {}) {
|
|
|
9330
9532
|
assertSandboxDataDepth(depth);
|
|
9331
9533
|
seen.add(value);
|
|
9332
9534
|
usage += 1;
|
|
9535
|
+
if (isGuestHostObject(value)) {
|
|
9536
|
+
for (const key of getHostObjectKeys(value)) usage += key.length + 1;
|
|
9537
|
+
return;
|
|
9538
|
+
}
|
|
9333
9539
|
const prototype = getSandboxPrototype(value);
|
|
9334
9540
|
if (prototype !== null) visit(prototype, depth + 1);
|
|
9335
9541
|
if (isFloat32Array(value)) {
|
|
@@ -9472,6 +9678,7 @@ function copyToSandbox(value, state, path = "<root>", cloneSandboxCollections =
|
|
|
9472
9678
|
if (isSandboxPrimitive(value)) {
|
|
9473
9679
|
return value;
|
|
9474
9680
|
}
|
|
9681
|
+
if (isLiveCapability(value)) throw new TypeError("Live capabilities require their owning realm bridge.");
|
|
9475
9682
|
if (isSandboxClosure(value) || isSandboxGenerator(value) || isSandboxRegex(value) || isSandboxPromise(value)) {
|
|
9476
9683
|
return value;
|
|
9477
9684
|
}
|
|
@@ -9635,6 +9842,10 @@ function copyFromSandbox(value, state, path = "<root>", options, depth = 0) {
|
|
|
9635
9842
|
if (isSandboxPrimitive(value)) {
|
|
9636
9843
|
return value;
|
|
9637
9844
|
}
|
|
9845
|
+
if (isGuestHostObject(value)) {
|
|
9846
|
+
if (options.unwrapHostObject === void 0) throw new TypeError("Live capabilities require their owning realm bridge.");
|
|
9847
|
+
return options.unwrapHostObject(value);
|
|
9848
|
+
}
|
|
9638
9849
|
if (nodeTypes.isProxy(value)) throw new TypeError("Unsupported proxy sandbox value.");
|
|
9639
9850
|
if (!isSandboxClosure(value) && hasGuestObjectState(value)) {
|
|
9640
9851
|
throw new TypeError("Guest prototype links and custom descriptors cannot be copied as data.");
|
|
@@ -22240,128 +22451,6 @@ function hasOnlyRegexLiteralDiagnostics(diagnostics) {
|
|
|
22240
22451
|
);
|
|
22241
22452
|
}
|
|
22242
22453
|
|
|
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
22454
|
// packages/safe-js/src/interp/generator.ts
|
|
22366
22455
|
function createGeneratorChannel(body) {
|
|
22367
22456
|
let state = "unstarted";
|
|
@@ -25003,9 +25092,10 @@ async function interpret(node, options = {}) {
|
|
|
25003
25092
|
peakDataSize: { enumerable: false, value: 0, writable: true }
|
|
25004
25093
|
});
|
|
25005
25094
|
const activeLoopIterations = /* @__PURE__ */ new Map();
|
|
25006
|
-
const jobs = new SandboxJobQueue();
|
|
25095
|
+
const jobs = options.jobs ?? new SandboxJobQueue();
|
|
25007
25096
|
hoistVarDeclarations(node, scope);
|
|
25008
25097
|
const context = {
|
|
25098
|
+
assertActive: options.assertActive,
|
|
25009
25099
|
compilation,
|
|
25010
25100
|
budget,
|
|
25011
25101
|
callStack: [],
|
|
@@ -25028,9 +25118,9 @@ async function interpret(node, options = {}) {
|
|
|
25028
25118
|
};
|
|
25029
25119
|
const evaluation = await withCancellationSignal(
|
|
25030
25120
|
options.signal,
|
|
25031
|
-
() => jobs.run(() => evaluateNode(node, context))
|
|
25121
|
+
() => options.nested ? runAsyncPrefix(() => evaluateNode(node, context)) : jobs.run(() => evaluateNode(node, context))
|
|
25032
25122
|
);
|
|
25033
|
-
await jobs.drain();
|
|
25123
|
+
if (!options.nested) await jobs.drain();
|
|
25034
25124
|
const snapshot = scope.snapshot();
|
|
25035
25125
|
reconcileDataBudget(
|
|
25036
25126
|
budget,
|
|
@@ -25085,6 +25175,7 @@ async function interpret(node, options = {}) {
|
|
|
25085
25175
|
}
|
|
25086
25176
|
}
|
|
25087
25177
|
async function evaluateNode(node, context) {
|
|
25178
|
+
context.assertActive?.();
|
|
25088
25179
|
const replayWait = promiseReplayContext.getStore()?.beforeNode(node.nodeId);
|
|
25089
25180
|
if (replayWait !== void 0) await suspendJob(replayWait);
|
|
25090
25181
|
assertPromiseExecutionAllowed();
|
|
@@ -26056,6 +26147,7 @@ function forInObject(value) {
|
|
|
26056
26147
|
return void 0;
|
|
26057
26148
|
}
|
|
26058
26149
|
function forInKeys(object, budget) {
|
|
26150
|
+
if (isGuestHostObject(object)) return getHostObjectKeys(object);
|
|
26059
26151
|
const keys = [];
|
|
26060
26152
|
const seen = /* @__PURE__ */ new Set();
|
|
26061
26153
|
let depth = 0;
|
|
@@ -26073,6 +26165,7 @@ function forInKeys(object, budget) {
|
|
|
26073
26165
|
return keys;
|
|
26074
26166
|
}
|
|
26075
26167
|
function hasForInProperty(object, key, budget) {
|
|
26168
|
+
if (isGuestHostObject(object)) return getHostObjectKeys(object).includes(key);
|
|
26076
26169
|
let depth = 0;
|
|
26077
26170
|
for (let current = object; current !== null; current = getSandboxPrototype(current)) {
|
|
26078
26171
|
if (depth > 0) budget.visitNode();
|
|
@@ -26564,6 +26657,7 @@ async function evaluateMemberExpression(node, context) {
|
|
|
26564
26657
|
};
|
|
26565
26658
|
}
|
|
26566
26659
|
function getPropertyValue(target, property, context) {
|
|
26660
|
+
if (isGuestHostObject(target)) return getHostObjectMember(target, String(property));
|
|
26567
26661
|
if (typeof target === "string") return getStringMember(target, property, context.budget);
|
|
26568
26662
|
if (typeof target === "number") return getNumberMember(target, property, context.budget);
|
|
26569
26663
|
if (typeof target === "boolean") return void 0;
|
|
@@ -27270,6 +27364,7 @@ function isPlainSandboxObject(value) {
|
|
|
27270
27364
|
return typeof value === "object" && value !== null && !Array.isArray(value) && !isSandboxClosure(value) && !isSandboxMap(value) && !isSandboxSet(value) && !isSandboxPromise(value) && !isSandboxRegex(value);
|
|
27271
27365
|
}
|
|
27272
27366
|
function getMemberValue(target, property, context) {
|
|
27367
|
+
if (isGuestHostObject(target)) return getHostObjectMember(target, String(property));
|
|
27273
27368
|
let current = target;
|
|
27274
27369
|
let depth = 0;
|
|
27275
27370
|
while (typeof current === "object" && current !== null) {
|
|
@@ -27294,6 +27389,10 @@ function getArrayMemberValue(target, property, context) {
|
|
|
27294
27389
|
return getArrayMember(target, property, createArrayMethodOptions(context));
|
|
27295
27390
|
}
|
|
27296
27391
|
function setSandboxProperty(target, property, value, budget) {
|
|
27392
|
+
if (isGuestHostObject(target)) {
|
|
27393
|
+
setHostObjectMember(target, String(property), value);
|
|
27394
|
+
return;
|
|
27395
|
+
}
|
|
27297
27396
|
const prototypeOwner = target;
|
|
27298
27397
|
if (isGuestClosure(target)) target = materializeFunctionProperties(target);
|
|
27299
27398
|
if (isFloat32Array(target)) {
|
|
@@ -27338,6 +27437,7 @@ function setSandboxProperty(target, property, value, budget) {
|
|
|
27338
27437
|
}
|
|
27339
27438
|
}
|
|
27340
27439
|
function deleteSandboxProperty(target, property) {
|
|
27440
|
+
if (isGuestHostObject(target)) throw new TypeError("Live host properties cannot be deleted.");
|
|
27341
27441
|
if (isGuestClosure(target)) target = materializeFunctionProperties(target);
|
|
27342
27442
|
if (Array.isArray(target)) {
|
|
27343
27443
|
assertCollectionMutable(target);
|
|
@@ -27903,7 +28003,7 @@ function wrapCallerInjectedBindings(bindings, options) {
|
|
|
27903
28003
|
const copied = Object.fromEntries(
|
|
27904
28004
|
Object.entries(bindings).map(([name, value]) => [
|
|
27905
28005
|
name,
|
|
27906
|
-
typeof value === "function" ? wrapCallerInjectedFunction(name, value, { ...options, capabilityPath: [name] }, state) : copyHostValueToSandbox(
|
|
28006
|
+
typeof value === "function" && !isLiveCapability(value) ? wrapCallerInjectedFunction(name, value, { ...options, capabilityPath: [name] }, state) : copyHostValueToSandbox(
|
|
27907
28007
|
value,
|
|
27908
28008
|
[],
|
|
27909
28009
|
{ ...options, operation: name, capabilityPath: [name] },
|
|
@@ -27924,9 +28024,10 @@ function wrapCallerInjectedFunction(name, value, options, state) {
|
|
|
27924
28024
|
const bindingName = name === "default" && value.name.length > 0 ? value.name : name;
|
|
27925
28025
|
const callable = value;
|
|
27926
28026
|
return createSandboxClosure({
|
|
27927
|
-
...isAsyncFunction(callable) ? { async: true } : {},
|
|
28027
|
+
...isAsyncFunction(callable) && !options.realm?.awaitResult(callable) ? { async: true } : {},
|
|
27928
28028
|
cancellationSignal: options.signal,
|
|
27929
28029
|
call: (args, context) => {
|
|
28030
|
+
options.realm?.assertActive();
|
|
27930
28031
|
const operationLease = options.budget.acquireCompileOwner(false, options.compileOwner);
|
|
27931
28032
|
const compilation = new CompileScope(operationLease.owner);
|
|
27932
28033
|
try {
|
|
@@ -27944,7 +28045,8 @@ function wrapCallerInjectedFunction(name, value, options, state) {
|
|
|
27944
28045
|
};
|
|
27945
28046
|
const hostArgs = deepCopyFromSandbox([...args], {
|
|
27946
28047
|
compilation,
|
|
27947
|
-
|
|
28048
|
+
unwrapHostObject: options.realm === void 0 ? void 0 : (object) => exportHostCapability(object, options.realm.owner),
|
|
28049
|
+
wrapClosure: (closure) => options.realm?.wrapCallback(closure) ?? wrapSandboxClosureForHost(
|
|
27948
28050
|
closure,
|
|
27949
28051
|
stackFrames,
|
|
27950
28052
|
options.budget,
|
|
@@ -27957,6 +28059,13 @@ function wrapCallerInjectedFunction(name, value, options, state) {
|
|
|
27957
28059
|
const moduleId = options.moduleId ?? "<bindings>";
|
|
27958
28060
|
const policy = readHostOperationPolicy(value) ?? readRegisteredPendingHostCallPolicy(moduleId, operation) ?? "re-issue";
|
|
27959
28061
|
if (hostCalls === void 0) {
|
|
28062
|
+
if (options.realm !== void 0) {
|
|
28063
|
+
const result = options.realm.invoke(callable, () => Reflect.apply(callable, void 0, hostArgs));
|
|
28064
|
+
if (options.realm.awaitResult(callable)) {
|
|
28065
|
+
return Promise.resolve(result).then((value2) => copyHostResultToSandbox(value2, stackFrames, options));
|
|
28066
|
+
}
|
|
28067
|
+
return copyHostResultToSandbox(result, stackFrames, options);
|
|
28068
|
+
}
|
|
27960
28069
|
return copyHostResultToSandbox(
|
|
27961
28070
|
invokeHostCallback(() => Reflect.apply(callable, void 0, hostArgs), options),
|
|
27962
28071
|
stackFrames,
|
|
@@ -28494,6 +28603,10 @@ function wrapHostPromiseWithSignal(promise, signal) {
|
|
|
28494
28603
|
}
|
|
28495
28604
|
function copyHostValueToSandbox(value, stackFrames, options, state, path) {
|
|
28496
28605
|
const { budget } = options;
|
|
28606
|
+
if (isLiveCapability(value)) {
|
|
28607
|
+
if (options.realm === void 0 || options.errorData || options.hostCalls !== void 0) throw new TypeError("Live capabilities are not portable replay or error data.");
|
|
28608
|
+
return importHostCapability(value, options.realm.owner);
|
|
28609
|
+
}
|
|
28497
28610
|
if (value === null || value === void 0 || typeof value === "number" || typeof value === "boolean") {
|
|
28498
28611
|
return value;
|
|
28499
28612
|
}
|
|
@@ -28812,673 +28925,418 @@ function describeValue2(value) {
|
|
|
28812
28925
|
return typeof value;
|
|
28813
28926
|
}
|
|
28814
28927
|
|
|
28815
|
-
// packages/safe-js/src/
|
|
28816
|
-
|
|
28817
|
-
|
|
28818
|
-
|
|
28819
|
-
|
|
28820
|
-
|
|
28821
|
-
|
|
28822
|
-
|
|
28823
|
-
|
|
28824
|
-
|
|
28928
|
+
// packages/safe-js/src/random.ts
|
|
28929
|
+
import { randomInt } from "node:crypto";
|
|
28930
|
+
|
|
28931
|
+
// packages/safe-js/src/interp/globals/math.ts
|
|
28932
|
+
var mathMethods = {
|
|
28933
|
+
abs: Math.abs,
|
|
28934
|
+
acos: Math.acos,
|
|
28935
|
+
acosh: Math.acosh,
|
|
28936
|
+
asin: Math.asin,
|
|
28937
|
+
asinh: Math.asinh,
|
|
28938
|
+
atan: Math.atan,
|
|
28939
|
+
atan2: Math.atan2,
|
|
28940
|
+
atanh: Math.atanh,
|
|
28941
|
+
ceil: Math.ceil,
|
|
28942
|
+
cbrt: Math.cbrt,
|
|
28943
|
+
clz32: Math.clz32,
|
|
28944
|
+
cos: Math.cos,
|
|
28945
|
+
cosh: Math.cosh,
|
|
28946
|
+
exp: Math.exp,
|
|
28947
|
+
expm1: Math.expm1,
|
|
28948
|
+
floor: Math.floor,
|
|
28949
|
+
f16round,
|
|
28950
|
+
fround: Math.fround,
|
|
28951
|
+
hypot: Math.hypot,
|
|
28952
|
+
imul: Math.imul,
|
|
28953
|
+
log: Math.log,
|
|
28954
|
+
log1p: Math.log1p,
|
|
28955
|
+
log10: Math.log10,
|
|
28956
|
+
log2: Math.log2,
|
|
28957
|
+
max: Math.max,
|
|
28958
|
+
min: Math.min,
|
|
28959
|
+
pow: Math.pow,
|
|
28960
|
+
round: Math.round,
|
|
28961
|
+
sign: Math.sign,
|
|
28962
|
+
sin: Math.sin,
|
|
28963
|
+
sinh: Math.sinh,
|
|
28964
|
+
sqrt: Math.sqrt,
|
|
28965
|
+
tan: Math.tan,
|
|
28966
|
+
tanh: Math.tanh,
|
|
28967
|
+
trunc: Math.trunc
|
|
28968
|
+
};
|
|
28969
|
+
function f16round(value) {
|
|
28970
|
+
const number = +value;
|
|
28971
|
+
if (!Number.isFinite(number) || number === 0) {
|
|
28972
|
+
return number;
|
|
28973
|
+
}
|
|
28974
|
+
const magnitude = Math.abs(number);
|
|
28975
|
+
if (magnitude >= 65520) {
|
|
28976
|
+
return number < 0 ? -Infinity : Infinity;
|
|
28977
|
+
}
|
|
28978
|
+
let quantum = 2 ** -24;
|
|
28979
|
+
let boundary = 2 ** -13;
|
|
28980
|
+
for (let exponent = -13; exponent <= 15 && magnitude >= boundary; exponent += 1) {
|
|
28981
|
+
quantum *= 2;
|
|
28982
|
+
boundary *= 2;
|
|
28983
|
+
}
|
|
28984
|
+
const scaled = magnitude / quantum;
|
|
28985
|
+
const lower = Math.floor(scaled);
|
|
28986
|
+
const remainder = scaled - lower;
|
|
28987
|
+
const rounded = (remainder > 0.5 || remainder === 0.5 && lower % 2 !== 0 ? lower + 1 : lower) * quantum;
|
|
28988
|
+
return number < 0 ? -rounded : rounded;
|
|
28825
28989
|
}
|
|
28826
|
-
function
|
|
28827
|
-
|
|
28828
|
-
|
|
28829
|
-
|
|
28830
|
-
|
|
28831
|
-
|
|
28832
|
-
|
|
28990
|
+
function createMathGlobals(options = {}) {
|
|
28991
|
+
const random = options.random ?? Math.random;
|
|
28992
|
+
const mathObject = {
|
|
28993
|
+
E: Math.E,
|
|
28994
|
+
LN2: Math.LN2,
|
|
28995
|
+
LN10: Math.LN10,
|
|
28996
|
+
LOG2E: Math.LOG2E,
|
|
28997
|
+
LOG10E: Math.LOG10E,
|
|
28998
|
+
PI: Math.PI,
|
|
28999
|
+
SQRT1_2: Math.SQRT1_2,
|
|
29000
|
+
SQRT2: Math.SQRT2,
|
|
29001
|
+
random: createSandboxClosure({ sandbox: true, call: () => random(), name: "random" })
|
|
29002
|
+
};
|
|
29003
|
+
for (const [name, method] of Object.entries(mathMethods)) {
|
|
29004
|
+
mathObject[name] = createSandboxClosure({
|
|
29005
|
+
sandbox: true,
|
|
29006
|
+
call: (args) => Reflect.apply(method, Math, args),
|
|
29007
|
+
name
|
|
29008
|
+
});
|
|
29009
|
+
}
|
|
28833
29010
|
return {
|
|
28834
|
-
|
|
28835
|
-
|
|
28836
|
-
|
|
28837
|
-
|
|
28838
|
-
|
|
28839
|
-
|
|
28840
|
-
|
|
28841
|
-
|
|
28842
|
-
|
|
28843
|
-
|
|
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());
|
|
29011
|
+
Infinity: Infinity,
|
|
29012
|
+
Math: mathObject,
|
|
29013
|
+
NaN: Number.NaN
|
|
29014
|
+
};
|
|
29015
|
+
}
|
|
29016
|
+
function createSeededRandom(seed) {
|
|
29017
|
+
let state = normalizeSeed(seed);
|
|
29018
|
+
return {
|
|
29019
|
+
next: () => {
|
|
29020
|
+
state = Math.imul(state, 1664525) + 1013904223 >>> 0;
|
|
29021
|
+
return state / 4294967296;
|
|
28861
29022
|
},
|
|
28862
|
-
|
|
28863
|
-
|
|
28864
|
-
|
|
28865
|
-
|
|
28866
|
-
|
|
28867
|
-
|
|
28868
|
-
|
|
28869
|
-
|
|
28870
|
-
|
|
28871
|
-
|
|
28872
|
-
|
|
28873
|
-
|
|
28874
|
-
|
|
29023
|
+
snapshot: () => state,
|
|
29024
|
+
restore: (nextState) => {
|
|
29025
|
+
state = normalizeSeed(nextState);
|
|
29026
|
+
}
|
|
29027
|
+
};
|
|
29028
|
+
}
|
|
29029
|
+
function normalizeSeed(seed) {
|
|
29030
|
+
if (!Number.isFinite(seed)) {
|
|
29031
|
+
throw new TypeError("Seeded random requires a finite numeric seed.");
|
|
29032
|
+
}
|
|
29033
|
+
return Math.trunc(seed) >>> 0;
|
|
29034
|
+
}
|
|
29035
|
+
|
|
29036
|
+
// packages/safe-js/src/random.ts
|
|
29037
|
+
function createReplayableRandom(options = {}) {
|
|
29038
|
+
const snapshot = options.snapshot;
|
|
29039
|
+
const saved = snapshot?.random;
|
|
29040
|
+
let initialState = options.seed;
|
|
29041
|
+
if (saved !== void 0) {
|
|
29042
|
+
const hasLoopState = typeof snapshot?.loopIterations === "object" && snapshot.loopIterations !== null && Object.keys(snapshot.loopIterations).length > 0;
|
|
29043
|
+
const replaysFromStart = snapshot?.replay !== void 0 || Array.isArray(snapshot?.pendingAwaits) && snapshot.pendingAwaits.length > 0 && !hasLoopState;
|
|
29044
|
+
initialState = replaysFromStart ? saved.initialState ?? saved.seed : saved.resumeState ?? saved.state;
|
|
29045
|
+
}
|
|
29046
|
+
const generator = createSeededRandom(initialState ?? randomInt(4294967296));
|
|
29047
|
+
return { seed: saved?.seed ?? generator.snapshot(), ...generator };
|
|
29048
|
+
}
|
|
29049
|
+
|
|
29050
|
+
// packages/safe-js/src/realm.ts
|
|
29051
|
+
import { AsyncLocalStorage as AsyncLocalStorage6 } from "node:async_hooks";
|
|
29052
|
+
import { types as types3 } from "node:util";
|
|
29053
|
+
|
|
29054
|
+
// packages/safe-js/src/interp/globals/console-json.ts
|
|
29055
|
+
function createConsoleJsonGlobals(options) {
|
|
29056
|
+
const sink = options.sink ?? console;
|
|
29057
|
+
return {
|
|
29058
|
+
JSON: {
|
|
29059
|
+
parse: createSandboxClosure({
|
|
29060
|
+
sandbox: true,
|
|
29061
|
+
call: async ([text]) => parseJson(text, options.budget),
|
|
29062
|
+
name: "parse"
|
|
29063
|
+
}),
|
|
29064
|
+
stringify: createSandboxClosure({
|
|
29065
|
+
sandbox: true,
|
|
29066
|
+
call: async ([value, replacer, indent]) => stringifyJson(value, replacer, indent, options.budget),
|
|
29067
|
+
name: "stringify"
|
|
29068
|
+
})
|
|
28875
29069
|
},
|
|
28876
|
-
|
|
28877
|
-
|
|
28878
|
-
|
|
28879
|
-
|
|
29070
|
+
console: options.hostCalls === void 0 ? {
|
|
29071
|
+
error: createSandboxClosure({
|
|
29072
|
+
sandbox: true,
|
|
29073
|
+
call: async (args, context) => {
|
|
29074
|
+
const operation = options.budget.acquireCompileOwner(
|
|
29075
|
+
false,
|
|
29076
|
+
options.compileOwner ?? context?.compilation?.owner
|
|
29077
|
+
);
|
|
29078
|
+
const compilation = new CompileScope(operation.owner);
|
|
28880
29079
|
try {
|
|
28881
|
-
|
|
28882
|
-
|
|
28883
|
-
|
|
29080
|
+
sink.error(...args.map((value) => deepCopyFromSandbox(value, { compilation })));
|
|
29081
|
+
return void 0;
|
|
29082
|
+
} finally {
|
|
29083
|
+
compilation.dispose();
|
|
29084
|
+
operation.release();
|
|
28884
29085
|
}
|
|
29086
|
+
},
|
|
29087
|
+
name: "error"
|
|
29088
|
+
}),
|
|
29089
|
+
log: createSandboxClosure({
|
|
29090
|
+
sandbox: true,
|
|
29091
|
+
call: async (args, context) => {
|
|
29092
|
+
const operation = options.budget.acquireCompileOwner(
|
|
29093
|
+
false,
|
|
29094
|
+
options.compileOwner ?? context?.compilation?.owner
|
|
29095
|
+
);
|
|
29096
|
+
const compilation = new CompileScope(operation.owner);
|
|
29097
|
+
try {
|
|
29098
|
+
sink.log(...args.map((value) => deepCopyFromSandbox(value, { compilation })));
|
|
29099
|
+
return void 0;
|
|
29100
|
+
} finally {
|
|
29101
|
+
compilation.dispose();
|
|
29102
|
+
operation.release();
|
|
29103
|
+
}
|
|
29104
|
+
},
|
|
29105
|
+
name: "log"
|
|
29106
|
+
})
|
|
29107
|
+
} : wrapCallerInjectedBindings(
|
|
29108
|
+
{
|
|
29109
|
+
error: (...args) => {
|
|
29110
|
+
sink.error(...args);
|
|
29111
|
+
return void 0;
|
|
29112
|
+
},
|
|
29113
|
+
log: (...args) => {
|
|
29114
|
+
sink.log(...args);
|
|
29115
|
+
return void 0;
|
|
28885
29116
|
}
|
|
28886
|
-
|
|
28887
|
-
|
|
28888
|
-
|
|
28889
|
-
|
|
28890
|
-
|
|
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;
|
|
29117
|
+
},
|
|
29118
|
+
{
|
|
29119
|
+
budget: options.budget,
|
|
29120
|
+
compileOwner: options.compileOwner,
|
|
29121
|
+
hostCalls: options.hostCalls,
|
|
29122
|
+
moduleId: "<console>"
|
|
28904
29123
|
}
|
|
28905
|
-
|
|
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
|
-
}
|
|
29124
|
+
)
|
|
28918
29125
|
};
|
|
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
29126
|
}
|
|
28940
|
-
function
|
|
28941
|
-
|
|
29127
|
+
function parseJson(input, budget) {
|
|
29128
|
+
const text = budget.allocateString(toJsonParseText(input));
|
|
29129
|
+
return copyJsonToSandbox(JSON.parse(text), budget);
|
|
28942
29130
|
}
|
|
28943
|
-
function
|
|
28944
|
-
|
|
28945
|
-
|
|
28946
|
-
|
|
29131
|
+
async function stringifyJson(value, replacer, indent, budget) {
|
|
29132
|
+
if (replacer !== void 0 && replacer !== null && !isSandboxClosure(replacer)) {
|
|
29133
|
+
throw new TypeError(
|
|
29134
|
+
"JSON.stringify(value, replacer, indent) only supports function, null, or undefined replacers."
|
|
29135
|
+
);
|
|
28947
29136
|
}
|
|
28948
|
-
if (
|
|
28949
|
-
|
|
28950
|
-
|
|
28951
|
-
|
|
28952
|
-
return Promise.reject(error);
|
|
28953
|
-
}
|
|
29137
|
+
if (indent !== void 0 && typeof indent !== "number" && typeof indent !== "string") {
|
|
29138
|
+
throw new TypeError(
|
|
29139
|
+
"JSON.stringify(value, replacer, indent) requires indent to be a string, number, or undefined."
|
|
29140
|
+
);
|
|
28954
29141
|
}
|
|
28955
|
-
|
|
28956
|
-
|
|
28957
|
-
|
|
28958
|
-
|
|
28959
|
-
|
|
29142
|
+
const holder = {};
|
|
29143
|
+
defineDataProperty(holder, "", value);
|
|
29144
|
+
const output = await stringifyProperty("", holder, {
|
|
29145
|
+
budget,
|
|
29146
|
+
gap: normalizeStringifyGap(indent),
|
|
29147
|
+
replacer: isSandboxClosure(replacer) ? replacer : void 0,
|
|
29148
|
+
stack: []
|
|
28960
29149
|
});
|
|
29150
|
+
if (output === void 0) {
|
|
29151
|
+
return void 0;
|
|
29152
|
+
}
|
|
29153
|
+
return budget.allocateString(output);
|
|
28961
29154
|
}
|
|
28962
|
-
function
|
|
28963
|
-
|
|
28964
|
-
|
|
28965
|
-
return controller.requestCurrentSnapshot();
|
|
29155
|
+
function toJsonParseText(input) {
|
|
29156
|
+
if (Array.isArray(input)) {
|
|
29157
|
+
return input.map((entry) => entry === null || entry === void 0 ? "" : toJsonParseText(entry)).join(",");
|
|
28966
29158
|
}
|
|
28967
|
-
|
|
29159
|
+
if (typeof input === "object" && input !== null) {
|
|
29160
|
+
return "[object Object]";
|
|
29161
|
+
}
|
|
29162
|
+
return String(input);
|
|
28968
29163
|
}
|
|
28969
|
-
function
|
|
28970
|
-
|
|
28971
|
-
|
|
28972
|
-
|
|
28973
|
-
|
|
28974
|
-
|
|
28975
|
-
|
|
28976
|
-
if (typeof value !== "object" || value === null) {
|
|
28977
|
-
return void 0;
|
|
29164
|
+
async function stringifyProperty(key, holder, state, indent = "") {
|
|
29165
|
+
let value = getOwnDataValue(holder, key);
|
|
29166
|
+
if (isStringifyContainer(value)) {
|
|
29167
|
+
const toJSON = getOwnDataValue(value, "toJSON");
|
|
29168
|
+
if (isSandboxClosure(toJSON)) {
|
|
29169
|
+
value = await callStringifyClosure(toJSON, [key], value, state);
|
|
29170
|
+
}
|
|
28978
29171
|
}
|
|
28979
|
-
|
|
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;
|
|
29172
|
+
if (state.replacer !== void 0) {
|
|
29173
|
+
value = await callStringifyClosure(state.replacer, [key, toSandboxValue(value)], holder, state);
|
|
28986
29174
|
}
|
|
28987
|
-
|
|
28988
|
-
return typeof code === "string" ? code : void 0;
|
|
28989
|
-
}
|
|
28990
|
-
function hasOwnErrorCode(error, code) {
|
|
28991
|
-
return getOwnErrorCode(error) === code;
|
|
29175
|
+
return stringifyValue(value, state, indent);
|
|
28992
29176
|
}
|
|
28993
|
-
|
|
28994
|
-
|
|
28995
|
-
|
|
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;
|
|
29177
|
+
async function stringifyValue(value, state, indent) {
|
|
29178
|
+
if (value === null) {
|
|
29179
|
+
return "null";
|
|
29007
29180
|
}
|
|
29008
|
-
|
|
29009
|
-
|
|
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
|
-
}
|
|
29181
|
+
if (typeof value === "string") {
|
|
29182
|
+
return quoteJsonString(value);
|
|
29023
29183
|
}
|
|
29024
|
-
|
|
29025
|
-
|
|
29026
|
-
this.path,
|
|
29027
|
-
() => writeSnapshotAtomically(this.path, snapshot, {
|
|
29028
|
-
maxAttempts: this.#writeMaxAttempts,
|
|
29029
|
-
retryDelayMs: this.#writeRetryDelayMs
|
|
29030
|
-
})
|
|
29031
|
-
);
|
|
29184
|
+
if (typeof value === "number") {
|
|
29185
|
+
return Number.isFinite(value) ? String(value) : "null";
|
|
29032
29186
|
}
|
|
29033
|
-
|
|
29034
|
-
|
|
29035
|
-
try {
|
|
29036
|
-
await unlink(this.path);
|
|
29037
|
-
} catch (error) {
|
|
29038
|
-
if (!hasErrorCode(error, "ENOENT")) {
|
|
29039
|
-
throw error;
|
|
29040
|
-
}
|
|
29041
|
-
}
|
|
29042
|
-
});
|
|
29187
|
+
if (typeof value === "boolean") {
|
|
29188
|
+
return value ? "true" : "false";
|
|
29043
29189
|
}
|
|
29044
|
-
|
|
29045
|
-
|
|
29046
|
-
|
|
29047
|
-
|
|
29048
|
-
|
|
29049
|
-
|
|
29050
|
-
|
|
29051
|
-
|
|
29052
|
-
|
|
29053
|
-
|
|
29054
|
-
|
|
29055
|
-
|
|
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
|
-
}
|
|
29190
|
+
if (typeof value === "bigint") {
|
|
29191
|
+
throw new TypeError("Do not know how to serialize a BigInt.");
|
|
29192
|
+
}
|
|
29193
|
+
if (isSandboxPromise(value)) return "{}";
|
|
29194
|
+
if (value === void 0 || isSandboxClosure(value)) {
|
|
29195
|
+
return void 0;
|
|
29196
|
+
}
|
|
29197
|
+
if (Array.isArray(value)) {
|
|
29198
|
+
return stringifyArray(value, state, indent);
|
|
29199
|
+
}
|
|
29200
|
+
if (isStringifyObject(value)) {
|
|
29201
|
+
return stringifyObject(value, state, indent);
|
|
29079
29202
|
}
|
|
29203
|
+
return void 0;
|
|
29080
29204
|
}
|
|
29081
|
-
async function
|
|
29205
|
+
async function stringifyArray(value, state, indent) {
|
|
29206
|
+
enterStringifyObject(value, state);
|
|
29082
29207
|
try {
|
|
29083
|
-
const
|
|
29084
|
-
|
|
29085
|
-
|
|
29086
|
-
|
|
29087
|
-
);
|
|
29208
|
+
const nextIndent = indent + state.gap;
|
|
29209
|
+
const entries = [];
|
|
29210
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
29211
|
+
entries.push(await stringifyProperty(String(index), value, state, nextIndent) ?? "null");
|
|
29088
29212
|
}
|
|
29089
|
-
|
|
29090
|
-
|
|
29091
|
-
throw new Error(
|
|
29092
|
-
`Cannot write snapshot at ${snapshotPath}: parent directory ${parentPath} does not exist`,
|
|
29093
|
-
{
|
|
29094
|
-
cause: error
|
|
29095
|
-
}
|
|
29096
|
-
);
|
|
29213
|
+
if (entries.length === 0) {
|
|
29214
|
+
return "[]";
|
|
29097
29215
|
}
|
|
29098
|
-
|
|
29216
|
+
if (state.gap === "") {
|
|
29217
|
+
return `[${entries.join(",")}]`;
|
|
29218
|
+
}
|
|
29219
|
+
return `[
|
|
29220
|
+
${nextIndent}${entries.join(`,
|
|
29221
|
+
${nextIndent}`)}
|
|
29222
|
+
${indent}]`;
|
|
29223
|
+
} finally {
|
|
29224
|
+
leaveStringifyObject(value, state);
|
|
29099
29225
|
}
|
|
29100
29226
|
}
|
|
29101
|
-
async function
|
|
29102
|
-
|
|
29103
|
-
let renamed = false;
|
|
29227
|
+
async function stringifyObject(value, state, indent) {
|
|
29228
|
+
enterStringifyObject(value, state);
|
|
29104
29229
|
try {
|
|
29105
|
-
|
|
29106
|
-
|
|
29107
|
-
|
|
29108
|
-
|
|
29109
|
-
if (
|
|
29110
|
-
|
|
29230
|
+
const nextIndent = indent + state.gap;
|
|
29231
|
+
const entries = [];
|
|
29232
|
+
for (const key of Object.keys(value)) {
|
|
29233
|
+
const serialized = await stringifyProperty(key, value, state, nextIndent);
|
|
29234
|
+
if (serialized !== void 0) {
|
|
29235
|
+
entries.push(`${quoteJsonString(key)}:${state.gap === "" ? "" : " "}${serialized}`);
|
|
29111
29236
|
}
|
|
29112
|
-
throw error;
|
|
29113
29237
|
}
|
|
29114
|
-
|
|
29115
|
-
|
|
29116
|
-
|
|
29117
|
-
if (
|
|
29118
|
-
|
|
29238
|
+
if (entries.length === 0) {
|
|
29239
|
+
return "{}";
|
|
29240
|
+
}
|
|
29241
|
+
if (state.gap === "") {
|
|
29242
|
+
return `{${entries.join(",")}}`;
|
|
29119
29243
|
}
|
|
29244
|
+
return `{
|
|
29245
|
+
${nextIndent}${entries.join(`,
|
|
29246
|
+
${nextIndent}`)}
|
|
29247
|
+
${indent}}`;
|
|
29248
|
+
} finally {
|
|
29249
|
+
leaveStringifyObject(value, state);
|
|
29120
29250
|
}
|
|
29121
29251
|
}
|
|
29122
|
-
async function
|
|
29123
|
-
const
|
|
29124
|
-
|
|
29125
|
-
|
|
29126
|
-
pendingOperations.set(path, queued);
|
|
29127
|
-
try {
|
|
29128
|
-
await pending;
|
|
29129
|
-
} finally {
|
|
29130
|
-
if (pendingOperations.get(path) === queued) {
|
|
29131
|
-
pendingOperations.delete(path);
|
|
29132
|
-
}
|
|
29252
|
+
async function callStringifyClosure(closure, args, thisValue, state) {
|
|
29253
|
+
const result = await closure.call(args, { stack: [], thisValue });
|
|
29254
|
+
if (isSandboxPromise(result) && result.synchronousPrefix !== void 0) {
|
|
29255
|
+
await result.synchronousPrefix;
|
|
29133
29256
|
}
|
|
29257
|
+
return allocateProducedSandboxValue(result, state.budget);
|
|
29134
29258
|
}
|
|
29135
|
-
|
|
29136
|
-
|
|
29137
|
-
|
|
29138
|
-
} catch (error) {
|
|
29139
|
-
if (!hasErrorCode(error, "ENOENT")) {
|
|
29140
|
-
throw error;
|
|
29141
|
-
}
|
|
29259
|
+
function enterStringifyObject(value, state) {
|
|
29260
|
+
if (state.stack.includes(value)) {
|
|
29261
|
+
throw new TypeError("Converting circular structure to JSON.");
|
|
29142
29262
|
}
|
|
29263
|
+
state.stack.push(value);
|
|
29143
29264
|
}
|
|
29144
|
-
|
|
29145
|
-
if (
|
|
29265
|
+
function leaveStringifyObject(value, state) {
|
|
29266
|
+
if (state.stack.at(-1) === value) {
|
|
29267
|
+
state.stack.pop();
|
|
29146
29268
|
return;
|
|
29147
29269
|
}
|
|
29148
|
-
|
|
29270
|
+
const index = state.stack.lastIndexOf(value);
|
|
29271
|
+
if (index >= 0) {
|
|
29272
|
+
state.stack.splice(index, 1);
|
|
29273
|
+
}
|
|
29149
29274
|
}
|
|
29150
|
-
function
|
|
29151
|
-
|
|
29275
|
+
function normalizeStringifyGap(indent) {
|
|
29276
|
+
if (typeof indent === "number") {
|
|
29277
|
+
return " ".repeat(Math.min(10, Math.max(0, Math.trunc(indent))));
|
|
29278
|
+
}
|
|
29279
|
+
if (typeof indent === "string") {
|
|
29280
|
+
return indent.slice(0, 10);
|
|
29281
|
+
}
|
|
29282
|
+
return "";
|
|
29152
29283
|
}
|
|
29153
|
-
function
|
|
29154
|
-
|
|
29155
|
-
return code !== void 0 && LOCKED_FILE_ERROR_CODES.has(code);
|
|
29284
|
+
function quoteJsonString(value) {
|
|
29285
|
+
return JSON.stringify(value);
|
|
29156
29286
|
}
|
|
29157
|
-
|
|
29158
|
-
|
|
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);
|
|
29287
|
+
function isStringifyContainer(value) {
|
|
29288
|
+
return typeof value === "object" && value !== null && !isSandboxClosure(value) && !isSandboxPromise(value);
|
|
29272
29289
|
}
|
|
29273
|
-
|
|
29274
|
-
|
|
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);
|
|
29290
|
+
function isStringifyObject(value) {
|
|
29291
|
+
return isStringifyContainer(value) && !Array.isArray(value);
|
|
29296
29292
|
}
|
|
29297
|
-
function
|
|
29298
|
-
if (Array.isArray(
|
|
29299
|
-
return
|
|
29293
|
+
function toSandboxValue(value) {
|
|
29294
|
+
if (value === null || value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean" || isSandboxClosure(value) || isSandboxPromise(value) || Array.isArray(value) || isStringifyContainer(value)) {
|
|
29295
|
+
return value;
|
|
29300
29296
|
}
|
|
29301
|
-
if (typeof
|
|
29302
|
-
|
|
29297
|
+
if (typeof value === "bigint") {
|
|
29298
|
+
throw new TypeError("Do not know how to serialize a BigInt.");
|
|
29303
29299
|
}
|
|
29304
|
-
|
|
29300
|
+
throw new TypeError(
|
|
29301
|
+
`JSON.stringify(value) produced an unsupported value of type ${typeof value}.`
|
|
29302
|
+
);
|
|
29305
29303
|
}
|
|
29306
|
-
|
|
29307
|
-
|
|
29308
|
-
if (
|
|
29309
|
-
|
|
29310
|
-
if (isSandboxClosure(toJSON)) {
|
|
29311
|
-
value = await callStringifyClosure(toJSON, [key], value, state);
|
|
29312
|
-
}
|
|
29304
|
+
function getOwnDataValue(target, key) {
|
|
29305
|
+
const descriptor = Object.getOwnPropertyDescriptor(target, key);
|
|
29306
|
+
if (descriptor === void 0) {
|
|
29307
|
+
return void 0;
|
|
29313
29308
|
}
|
|
29314
|
-
if (
|
|
29315
|
-
|
|
29309
|
+
if ("get" in descriptor || "set" in descriptor) {
|
|
29310
|
+
throw new TypeError(`JSON.stringify(value) cannot serialize accessor property ${key}.`);
|
|
29316
29311
|
}
|
|
29317
|
-
return
|
|
29312
|
+
return descriptor.value;
|
|
29318
29313
|
}
|
|
29319
|
-
|
|
29320
|
-
if (value === null) {
|
|
29321
|
-
return
|
|
29314
|
+
function copyJsonToSandbox(value, budget) {
|
|
29315
|
+
if (value === null || value === void 0 || typeof value === "boolean" || typeof value === "number") {
|
|
29316
|
+
return value;
|
|
29322
29317
|
}
|
|
29323
29318
|
if (typeof value === "string") {
|
|
29324
|
-
return
|
|
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;
|
|
29319
|
+
return budget.allocateString(value);
|
|
29338
29320
|
}
|
|
29339
29321
|
if (Array.isArray(value)) {
|
|
29340
|
-
|
|
29341
|
-
|
|
29342
|
-
if (isStringifyObject(value)) {
|
|
29343
|
-
return stringifyObject(value, state, indent);
|
|
29322
|
+
budget.allocateArrayLength(value.length);
|
|
29323
|
+
return value.map((entry) => copyJsonToSandbox(entry, budget));
|
|
29344
29324
|
}
|
|
29345
|
-
|
|
29346
|
-
|
|
29347
|
-
|
|
29348
|
-
|
|
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(",")}]`;
|
|
29325
|
+
if (isPlainObject4(value)) {
|
|
29326
|
+
const copy = /* @__PURE__ */ Object.create(null);
|
|
29327
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
29328
|
+
defineDataProperty(copy, key, copyJsonToSandbox(entry, budget));
|
|
29360
29329
|
}
|
|
29361
|
-
return
|
|
29362
|
-
${nextIndent}${entries.join(`,
|
|
29363
|
-
${nextIndent}`)}
|
|
29364
|
-
${indent}]`;
|
|
29365
|
-
} finally {
|
|
29366
|
-
leaveStringifyObject(value, state);
|
|
29330
|
+
return copy;
|
|
29367
29331
|
}
|
|
29332
|
+
throw new TypeError("JSON.parse(text) produced an unsupported value.");
|
|
29368
29333
|
}
|
|
29369
|
-
|
|
29370
|
-
|
|
29371
|
-
|
|
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);
|
|
29334
|
+
function isPlainObject4(value) {
|
|
29335
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
29336
|
+
return false;
|
|
29392
29337
|
}
|
|
29393
|
-
|
|
29394
|
-
|
|
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;
|
|
29338
|
+
const prototype = Object.getPrototypeOf(value);
|
|
29339
|
+
return prototype === Object.prototype || prototype === null;
|
|
29482
29340
|
}
|
|
29483
29341
|
function defineDataProperty(target, key, value) {
|
|
29484
29342
|
Object.defineProperty(target, key, {
|
|
@@ -29886,295 +29744,1388 @@ function createObjectArrayGlobals(options) {
|
|
|
29886
29744
|
NEGATIVE_INFINITY: Number.NEGATIVE_INFINITY,
|
|
29887
29745
|
POSITIVE_INFINITY: Number.POSITIVE_INFINITY
|
|
29888
29746
|
}
|
|
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.");
|
|
29747
|
+
}),
|
|
29748
|
+
Boolean: createSandboxClosure({
|
|
29749
|
+
sandbox: true,
|
|
29750
|
+
call: ([value]) => Boolean(value),
|
|
29751
|
+
name: "Boolean"
|
|
29752
|
+
})
|
|
29753
|
+
};
|
|
29754
|
+
}
|
|
29755
|
+
async function objectFromSandboxEntries(iterator, budget) {
|
|
29756
|
+
const object = /* @__PURE__ */ Object.create(null);
|
|
29757
|
+
try {
|
|
29758
|
+
while (true) {
|
|
29759
|
+
const result = await iterator.next();
|
|
29760
|
+
if (typeof result !== "object" && typeof result !== "function" || result === null) {
|
|
29761
|
+
throw new TypeError("Iterator result must be an object.");
|
|
29762
|
+
}
|
|
29763
|
+
if (result.done) break;
|
|
29764
|
+
const entry = result.value;
|
|
29765
|
+
if (typeof entry !== "object" && typeof entry !== "function" || entry === null) {
|
|
29766
|
+
throw new TypeError("Object.fromEntries requires entry objects.");
|
|
29767
|
+
}
|
|
29768
|
+
const key = entry[0];
|
|
29769
|
+
const value = entry[1];
|
|
29770
|
+
Object.defineProperty(object, key, {
|
|
29771
|
+
configurable: true,
|
|
29772
|
+
enumerable: true,
|
|
29773
|
+
value,
|
|
29774
|
+
writable: true
|
|
29775
|
+
});
|
|
29776
|
+
}
|
|
29777
|
+
} catch (error) {
|
|
29778
|
+
try {
|
|
29779
|
+
await iterator.return?.();
|
|
29780
|
+
} catch {
|
|
29781
|
+
throw error;
|
|
29782
|
+
}
|
|
29783
|
+
throw error;
|
|
29784
|
+
}
|
|
29785
|
+
return allocateProducedSandboxValue(object, budget);
|
|
29786
|
+
}
|
|
29787
|
+
function assignSandboxValues(target, sources, budget) {
|
|
29788
|
+
if (target === null || target === void 0) {
|
|
29789
|
+
throw new TypeError("Object.assign(target, ...sources) requires a non-null target.");
|
|
29790
|
+
}
|
|
29791
|
+
if (!isGuestClosure(target) && !isAssignableSandboxTarget(target)) {
|
|
29792
|
+
throw new TypeError("Object.assign(target, ...sources) requires an object or array target.");
|
|
29793
|
+
}
|
|
29794
|
+
for (const source of sources) {
|
|
29795
|
+
if (source === null || source === void 0) {
|
|
29796
|
+
continue;
|
|
29797
|
+
}
|
|
29798
|
+
for (const [key, value] of ownEnumerableSandboxEntries(source)) {
|
|
29799
|
+
setSandboxProperty(target, key, value, budget);
|
|
29800
|
+
}
|
|
29801
|
+
}
|
|
29802
|
+
return target;
|
|
29803
|
+
}
|
|
29804
|
+
function objectProperties(value, mutable = false) {
|
|
29805
|
+
if (isGuestHostObject(value)) throw new TypeError("Live host object descriptors are not supported.");
|
|
29806
|
+
if (isGuestClosure(value)) return materializeFunctionProperties(value);
|
|
29807
|
+
if (isSandboxClosure(value)) {
|
|
29808
|
+
if (mutable) throw new TypeError("Host function properties are read only.");
|
|
29809
|
+
return value.properties ?? /* @__PURE__ */ Object.create(null);
|
|
29810
|
+
}
|
|
29811
|
+
if (!isAssignableSandboxTarget(value)) throw new TypeError("Expected a sandbox object or function.");
|
|
29812
|
+
return value;
|
|
29813
|
+
}
|
|
29814
|
+
function dataDescriptor(input) {
|
|
29815
|
+
const source = objectProperties(input);
|
|
29816
|
+
const descriptor = {};
|
|
29817
|
+
for (const field of ["get", "set", "value", "writable", "enumerable", "configurable"]) {
|
|
29818
|
+
const entry = Object.getOwnPropertyDescriptor(source, field);
|
|
29819
|
+
if (entry === void 0) continue;
|
|
29820
|
+
if (!("value" in entry) || field === "get" || field === "set") {
|
|
29821
|
+
throw new TypeError("Only data property descriptors are supported.");
|
|
29822
|
+
}
|
|
29823
|
+
if (field === "value") descriptor.value = entry.value;
|
|
29824
|
+
else descriptor[field] = Boolean(entry.value);
|
|
29825
|
+
}
|
|
29826
|
+
return descriptor;
|
|
29827
|
+
}
|
|
29828
|
+
function defineDataProperty2(target, key, descriptor, budget) {
|
|
29829
|
+
budget.visitNode();
|
|
29830
|
+
if (isFloat32Array(target)) throw new TypeError("Typed array property descriptors are not supported.");
|
|
29831
|
+
const properties = objectProperties(target, true);
|
|
29832
|
+
if (Array.isArray(properties)) {
|
|
29833
|
+
if (key === "length" && "value" in descriptor) budget.allocateArrayLength(Number(descriptor.value));
|
|
29834
|
+
else {
|
|
29835
|
+
const index = Number(key);
|
|
29836
|
+
if (Number.isInteger(index) && index >= 0 && index < 4294967295 && String(index) === key) {
|
|
29837
|
+
budget.allocateArrayLength(index + 1);
|
|
29838
|
+
}
|
|
29839
|
+
}
|
|
29840
|
+
}
|
|
29841
|
+
Object.defineProperty(properties, key, descriptor);
|
|
29842
|
+
markDescriptorObject(properties);
|
|
29843
|
+
}
|
|
29844
|
+
function isAssignableSandboxTarget(value) {
|
|
29845
|
+
return typeof value === "object" && value !== null && !isSandboxClosure(value) && !isSandboxGenerator(value) && !isSandboxMap(value) && !isSandboxSet(value) && !isSandboxPromise(value) && !isSandboxRegex(value);
|
|
29846
|
+
}
|
|
29847
|
+
async function arrayFromSandboxValues(args, budget) {
|
|
29848
|
+
const [items, mapFn, thisValue] = args;
|
|
29849
|
+
const iterator = getSandboxIterator(items);
|
|
29850
|
+
const values = iterator === void 0 ? Reflect.apply(Array.from, Array, [items]) : await collectIteratorValues(iterator);
|
|
29851
|
+
if (mapFn === void 0 || !isSandboxClosure(mapFn)) {
|
|
29852
|
+
if (mapFn !== void 0) {
|
|
29853
|
+
throw new TypeError("Array.from mapping callback must be a function.");
|
|
29854
|
+
}
|
|
29855
|
+
return budgetSandboxValue2(values, budget);
|
|
29856
|
+
}
|
|
29857
|
+
const mappedValues = [];
|
|
29858
|
+
for (const [index, value] of values.entries()) {
|
|
29859
|
+
const result = await mapFn.call([value, index], { stack: [], thisValue });
|
|
29860
|
+
if (isSandboxPromise(result) && result.synchronousPrefix !== void 0) {
|
|
29861
|
+
await result.synchronousPrefix;
|
|
29862
|
+
}
|
|
29863
|
+
mappedValues.push(result);
|
|
29864
|
+
}
|
|
29865
|
+
return budgetSandboxValue2(mappedValues, budget);
|
|
29866
|
+
}
|
|
29867
|
+
function createArrayFromConstructorArgs(args, budget) {
|
|
29868
|
+
if (args.length !== 1) {
|
|
29869
|
+
return budgetSandboxValue2(Reflect.apply(Array, Array, [...args]), budget);
|
|
29870
|
+
}
|
|
29871
|
+
const [lengthOrValue] = args;
|
|
29872
|
+
if (typeof lengthOrValue !== "number") {
|
|
29873
|
+
return budgetSandboxValue2([lengthOrValue], budget);
|
|
29874
|
+
}
|
|
29875
|
+
if (!Number.isInteger(lengthOrValue) || lengthOrValue < 0 || lengthOrValue > 4294967295) {
|
|
29876
|
+
throw new RangeError("Invalid array length.");
|
|
29877
|
+
}
|
|
29878
|
+
budget.allocateArrayLength(lengthOrValue);
|
|
29879
|
+
return new Array(lengthOrValue);
|
|
29880
|
+
}
|
|
29881
|
+
async function collectIteratorValues(iterator) {
|
|
29882
|
+
const values = [];
|
|
29883
|
+
while (true) {
|
|
29884
|
+
const result = await iterator.next();
|
|
29885
|
+
if (result.done) return values;
|
|
29886
|
+
values.push(result.value);
|
|
29887
|
+
}
|
|
29888
|
+
}
|
|
29889
|
+
function getOwnEnumerableKeys(value) {
|
|
29890
|
+
if (isGuestHostObject(value)) return getHostObjectKeys(value);
|
|
29891
|
+
return ownEnumerableSandboxEntries(value).map(([key]) => key);
|
|
29892
|
+
}
|
|
29893
|
+
function getOwnEnumerableValues(value) {
|
|
29894
|
+
return ownEnumerableSandboxEntries(value).map(([, entryValue]) => entryValue);
|
|
29895
|
+
}
|
|
29896
|
+
function budgetSandboxValue2(value, budget) {
|
|
29897
|
+
const sandboxValue = deepCopyToSandbox(value);
|
|
29898
|
+
return allocateProducedSandboxValue(sandboxValue, budget);
|
|
29899
|
+
}
|
|
29900
|
+
function stringRaw(args, budget) {
|
|
29901
|
+
const [template, ...substitutions] = args;
|
|
29902
|
+
const raw = getTemplateRawParts(template);
|
|
29903
|
+
let result = "";
|
|
29904
|
+
for (let index = 0; index < raw.length; index += 1) {
|
|
29905
|
+
result += String(raw[index]);
|
|
29906
|
+
if (index < raw.length - 1 && index < substitutions.length) {
|
|
29907
|
+
result += String(substitutions[index]);
|
|
29908
|
+
}
|
|
29909
|
+
}
|
|
29910
|
+
return budget.allocateString(result);
|
|
29911
|
+
}
|
|
29912
|
+
function getTemplateRawParts(template) {
|
|
29913
|
+
const raw = typeof template === "object" && template !== null ? template.raw : void 0;
|
|
29914
|
+
if (typeof template !== "object" || template === null || isSandboxClosure(template) || isSandboxPromise(template) || !Array.isArray(raw)) {
|
|
29915
|
+
throw new TypeError("String.raw requires a raw strings array.");
|
|
29916
|
+
}
|
|
29917
|
+
return raw;
|
|
29918
|
+
}
|
|
29919
|
+
|
|
29920
|
+
// packages/safe-js/src/interp/globals.ts
|
|
29921
|
+
function createBuiltinBindings(options) {
|
|
29922
|
+
return {
|
|
29923
|
+
...createConsoleJsonGlobals(options),
|
|
29924
|
+
...createCollectionGlobals(options),
|
|
29925
|
+
Float32Array: createFloat32ArrayGlobal(options.budget),
|
|
29926
|
+
...createErrorGlobals(options),
|
|
29927
|
+
...createMathGlobals({ random: options.random }),
|
|
29928
|
+
...createObjectArrayGlobals(options),
|
|
29929
|
+
...createMiscGlobals(options),
|
|
29930
|
+
...createPromiseGlobals(options),
|
|
29931
|
+
...createRegexGlobals(options.compileOwner)
|
|
29932
|
+
};
|
|
29933
|
+
}
|
|
29934
|
+
|
|
29935
|
+
// packages/safe-js/src/interp/resources.ts
|
|
29936
|
+
import { AsyncLocalStorage as AsyncLocalStorage5 } from "node:async_hooks";
|
|
29937
|
+
var runResources = new AsyncLocalStorage5();
|
|
29938
|
+
async function withRunResources(signal, execute) {
|
|
29939
|
+
const controller = new AbortController();
|
|
29940
|
+
const cancel = () => controller.abort(signal?.reason);
|
|
29941
|
+
const cleanups = /* @__PURE__ */ new Set();
|
|
29942
|
+
const resources = {
|
|
29943
|
+
signal: controller.signal,
|
|
29944
|
+
add(close) {
|
|
29945
|
+
cleanups.add(close);
|
|
29946
|
+
}
|
|
29947
|
+
};
|
|
29948
|
+
signal?.addEventListener("abort", cancel, { once: true });
|
|
29949
|
+
if (signal?.aborted) cancel();
|
|
29950
|
+
let result;
|
|
29951
|
+
let failure;
|
|
29952
|
+
let errors = [];
|
|
29953
|
+
try {
|
|
29954
|
+
result = await runResources.run(resources, execute);
|
|
29955
|
+
} catch (error) {
|
|
29956
|
+
failure = { reason: error };
|
|
29957
|
+
} finally {
|
|
29958
|
+
signal?.removeEventListener("abort", cancel);
|
|
29959
|
+
controller.abort(new Error("SafeJS run finished."));
|
|
29960
|
+
const outcomes = await Promise.allSettled(
|
|
29961
|
+
[...cleanups].map((close) => Promise.resolve().then(close))
|
|
29962
|
+
);
|
|
29963
|
+
errors = outcomes.flatMap((outcome) => outcome.status === "rejected" ? [outcome.reason] : []);
|
|
29964
|
+
}
|
|
29965
|
+
if (failure !== void 0) throw failure.reason;
|
|
29966
|
+
if (errors.length > 0) throw new AggregateError(errors, "SafeJS resource cleanup failed.");
|
|
29967
|
+
return result;
|
|
29968
|
+
}
|
|
29969
|
+
|
|
29970
|
+
// packages/safe-js/src/modules/registry.ts
|
|
29971
|
+
function createUnknownModuleMessage2(moduleName, moduleNames) {
|
|
29972
|
+
if (moduleNames.length === 0) {
|
|
29973
|
+
return `Unknown module '${moduleName}'. No modules are registered.`;
|
|
29974
|
+
}
|
|
29975
|
+
return `Unknown module '${moduleName}'. Available modules: ${moduleNames.join(", ")}.`;
|
|
29976
|
+
}
|
|
29977
|
+
function createUnknownExportMessage2(moduleName, exportName, availableExports) {
|
|
29978
|
+
if (availableExports.length === 0) {
|
|
29979
|
+
return `Module '${moduleName}' does not export '${exportName}'. The module exports nothing.`;
|
|
29980
|
+
}
|
|
29981
|
+
return `Module '${moduleName}' does not export '${exportName}'. Available exports: ${availableExports.join(", ")}.`;
|
|
29982
|
+
}
|
|
29983
|
+
function resolveModuleImports(module, modules, options) {
|
|
29984
|
+
const registry = normalizeModuleRegistry(modules);
|
|
29985
|
+
const bindings = createBindingRecord();
|
|
29986
|
+
const wrappedModules = options.wrappedModules ?? /* @__PURE__ */ new Map();
|
|
29987
|
+
for (const statement of module.body) {
|
|
29988
|
+
if (statement.type !== "ImportDeclaration") {
|
|
29989
|
+
continue;
|
|
29990
|
+
}
|
|
29991
|
+
bindImportDeclaration(statement, registry, wrappedModules, bindings, options);
|
|
29992
|
+
}
|
|
29993
|
+
return bindings;
|
|
29994
|
+
}
|
|
29995
|
+
function bindImportDeclaration(declaration, registry, wrappedModules, bindings, options) {
|
|
29996
|
+
const moduleName = declaration.source.value;
|
|
29997
|
+
const moduleExports = registry.get(moduleName);
|
|
29998
|
+
if (moduleExports === void 0) {
|
|
29999
|
+
if (options.allowMissing) return;
|
|
30000
|
+
throw createModuleImportError(
|
|
30001
|
+
createUnknownModuleMessage2(moduleName, [...registry.keys()]),
|
|
30002
|
+
declaration.source.span
|
|
30003
|
+
);
|
|
30004
|
+
}
|
|
30005
|
+
const wrappedExports = wrappedModules.get(moduleName) ?? createBindingRecord(
|
|
30006
|
+
wrapCancelableBindings(
|
|
30007
|
+
wrapCallerInjectedBindings(Object.fromEntries(moduleExports), {
|
|
30008
|
+
realm: options.realm,
|
|
30009
|
+
budget: options.budget,
|
|
30010
|
+
compileOwner: options.compileOwner,
|
|
30011
|
+
hostCalls: options.hostCalls,
|
|
30012
|
+
moduleId: moduleName,
|
|
30013
|
+
signal: options.signal
|
|
30014
|
+
}),
|
|
30015
|
+
options.signal
|
|
30016
|
+
)
|
|
30017
|
+
);
|
|
30018
|
+
wrappedModules.set(moduleName, wrappedExports);
|
|
30019
|
+
for (const specifier of declaration.specifiers) {
|
|
30020
|
+
const localName = specifier.local.name;
|
|
30021
|
+
if (Object.hasOwn(bindings, localName)) {
|
|
30022
|
+
throw createModuleImportError(
|
|
30023
|
+
`Cannot redeclare imported binding '${localName}'.`,
|
|
30024
|
+
specifier.local.span
|
|
30025
|
+
);
|
|
30026
|
+
}
|
|
30027
|
+
if (options.allowMissing && specifier.type !== "ImportNamespaceSpecifier") {
|
|
30028
|
+
const exportName = specifier.type === "ImportDefaultSpecifier" ? "default" : specifier.imported.name;
|
|
30029
|
+
if (!Object.hasOwn(wrappedExports, exportName)) continue;
|
|
30030
|
+
}
|
|
30031
|
+
bindings[localName] = resolveImportSpecifier(moduleName, specifier, wrappedExports);
|
|
30032
|
+
}
|
|
30033
|
+
}
|
|
30034
|
+
function resolveImportSpecifier(moduleName, specifier, wrappedExports) {
|
|
30035
|
+
if (specifier.type === "ImportNamespaceSpecifier") {
|
|
30036
|
+
return wrappedExports;
|
|
30037
|
+
}
|
|
30038
|
+
const exportName = specifier.type === "ImportDefaultSpecifier" ? "default" : specifier.imported.name;
|
|
30039
|
+
const exportedValue = wrappedExports[exportName];
|
|
30040
|
+
if (exportedValue !== void 0 || Object.hasOwn(wrappedExports, exportName)) {
|
|
30041
|
+
return exportedValue;
|
|
30042
|
+
}
|
|
30043
|
+
throw createModuleImportError(
|
|
30044
|
+
createUnknownExportMessage2(moduleName, exportName, Object.keys(wrappedExports).sort()),
|
|
30045
|
+
specifier.span
|
|
30046
|
+
);
|
|
30047
|
+
}
|
|
30048
|
+
function createModuleImportError(message, span) {
|
|
30049
|
+
const error = new Error(message);
|
|
30050
|
+
attachErrorSpan(error, span);
|
|
30051
|
+
return error;
|
|
30052
|
+
}
|
|
30053
|
+
function normalizeModuleRegistry(modules) {
|
|
30054
|
+
if (modules === void 0) {
|
|
30055
|
+
return /* @__PURE__ */ new Map();
|
|
30056
|
+
}
|
|
30057
|
+
const entries = modules instanceof Map ? [...modules.entries()] : Object.entries(modules);
|
|
30058
|
+
const registry = new Map(
|
|
30059
|
+
entries.map(
|
|
30060
|
+
([moduleName, moduleExports]) => [moduleName, normalizeModuleExports(moduleExports)]
|
|
30061
|
+
).sort(([left], [right]) => left.localeCompare(right))
|
|
30062
|
+
);
|
|
30063
|
+
registerModuleHostOperationPolicies(registry);
|
|
30064
|
+
return registry;
|
|
30065
|
+
}
|
|
30066
|
+
function registerModuleHostOperationPolicies(registry) {
|
|
30067
|
+
for (const [moduleId, moduleExports] of registry) {
|
|
30068
|
+
for (const [operation, value] of moduleExports) {
|
|
30069
|
+
if (typeof value !== "function") {
|
|
30070
|
+
continue;
|
|
30071
|
+
}
|
|
30072
|
+
const policy = readHostOperationPolicy(value);
|
|
30073
|
+
if (policy !== void 0) {
|
|
30074
|
+
registerPendingHostCallPolicy({ moduleId, operation, policy });
|
|
30075
|
+
}
|
|
30076
|
+
}
|
|
30077
|
+
}
|
|
30078
|
+
}
|
|
30079
|
+
function normalizeModuleExports(moduleExports) {
|
|
30080
|
+
const entries = moduleExports instanceof Map ? [...moduleExports.entries()] : Object.entries(moduleExports);
|
|
30081
|
+
return new Map(
|
|
30082
|
+
entries.filter(([exportName]) => exportName.length > 0).sort(([left], [right]) => left.localeCompare(right))
|
|
30083
|
+
);
|
|
30084
|
+
}
|
|
30085
|
+
function createBindingRecord(entries) {
|
|
30086
|
+
return Object.assign(/* @__PURE__ */ Object.create(null), entries);
|
|
30087
|
+
}
|
|
30088
|
+
|
|
30089
|
+
// packages/safe-js/src/realm.ts
|
|
30090
|
+
var RealmState = class {
|
|
30091
|
+
constructor(options) {
|
|
30092
|
+
this.options = options;
|
|
30093
|
+
const limitInput = readDataRecord(options.limits ?? {}, "Realm limits");
|
|
30094
|
+
this.limits = {
|
|
30095
|
+
extensions: 32,
|
|
30096
|
+
hostObjects: 1024,
|
|
30097
|
+
callbacks: 1024,
|
|
30098
|
+
cleanups: 1024,
|
|
30099
|
+
nestedEvaluations: 16
|
|
30100
|
+
};
|
|
30101
|
+
for (const [name, value] of Object.entries(limitInput)) {
|
|
30102
|
+
if (!Object.hasOwn(this.limits, name) || !Number.isSafeInteger(value) || Number(value) < 1)
|
|
30103
|
+
throw new TypeError("Realm limits must be positive safe integers with supported names.");
|
|
30104
|
+
this.limits[name] = Number(value);
|
|
30105
|
+
}
|
|
30106
|
+
if (options.extensions !== void 0 && (!Array.isArray(options.extensions) || types3.isProxy(options.extensions)))
|
|
30107
|
+
throw new TypeError("Extensions must be a registration array.");
|
|
30108
|
+
const registrations = options.extensions ?? [];
|
|
30109
|
+
const extensions = [];
|
|
30110
|
+
if (registrations.length > this.limits.extensions)
|
|
30111
|
+
throw new RangeError("Realm extension limit exceeded.");
|
|
30112
|
+
for (let index = 0; index < registrations.length; index++) {
|
|
30113
|
+
const descriptor = Object.getOwnPropertyDescriptor(registrations, String(index));
|
|
30114
|
+
if (descriptor === void 0 || !("value" in descriptor))
|
|
30115
|
+
throw new TypeError("Extension registrations require data properties, not accessors.");
|
|
30116
|
+
extensions.push(descriptor.value);
|
|
30117
|
+
}
|
|
30118
|
+
if (Reflect.ownKeys(registrations).length !== extensions.length + 1)
|
|
30119
|
+
throw new TypeError("Extension registrations have unsupported fields.");
|
|
30120
|
+
this.extensions = Object.freeze(extensions);
|
|
30121
|
+
if (this.extensions.length > this.limits.extensions)
|
|
30122
|
+
throw new RangeError("Realm extension limit exceeded.");
|
|
30123
|
+
this.globals = readDataRecord(options.bindings ?? {}, "Realm bindings");
|
|
30124
|
+
this.modules = readModules(options.modules);
|
|
30125
|
+
const grants = new Set(readStringList(options.grants ?? [], "Realm grants"));
|
|
30126
|
+
for (const extension of this.extensions) getExtensionSetup(extension);
|
|
30127
|
+
this.budget = options.budget ?? new Budget({ maxCallDepth: 1e3 });
|
|
30128
|
+
this.lease = this.budget.acquireCompileOwner(true);
|
|
30129
|
+
this.compilation = new CompileScope(this.lease.owner);
|
|
30130
|
+
this.bridge = {
|
|
30131
|
+
owner: this,
|
|
30132
|
+
assertActive: this.assertOpen,
|
|
30133
|
+
wrapCallback: this.wrapCallback,
|
|
30134
|
+
invoke: this.invokeHost,
|
|
30135
|
+
awaitResult: (operation) => this.nestedOperations.has(operation)
|
|
30136
|
+
};
|
|
30137
|
+
try {
|
|
30138
|
+
this.builtinBindings = createBuiltinBindings({
|
|
30139
|
+
budget: this.budget,
|
|
30140
|
+
compileOwner: this.lease.owner,
|
|
30141
|
+
sink: options.sink,
|
|
30142
|
+
random: createReplayableRandom({ seed: options.randomSeed }).next
|
|
30143
|
+
});
|
|
30144
|
+
const names = /* @__PURE__ */ new Set();
|
|
30145
|
+
const globals = /* @__PURE__ */ new Set([...Object.keys(this.builtinBindings), ...Object.keys(this.globals)]);
|
|
30146
|
+
const modules = new Map(
|
|
30147
|
+
Object.entries(this.modules).map(([name, exports]) => [name, new Set(Object.keys(exports))])
|
|
30148
|
+
);
|
|
30149
|
+
for (const extension of this.extensions) {
|
|
30150
|
+
const manifest = extension.manifest;
|
|
30151
|
+
if (names.has(manifest.name))
|
|
30152
|
+
throw new TypeError(`Duplicate extension '${manifest.name}'.`);
|
|
30153
|
+
names.add(manifest.name);
|
|
30154
|
+
for (const capability of manifest.capabilities ?? []) {
|
|
30155
|
+
if (!grants.has(capability))
|
|
30156
|
+
throw new TypeError(`Missing grant '${capability}' for extension '${manifest.name}'.`);
|
|
30157
|
+
}
|
|
30158
|
+
for (const name of manifest.globals ?? []) {
|
|
30159
|
+
if (globals.has(name)) throw new TypeError(`Conflicting global '${name}'.`);
|
|
30160
|
+
globals.add(name);
|
|
30161
|
+
}
|
|
30162
|
+
for (const [name, exports] of Object.entries(manifest.modules ?? {})) {
|
|
30163
|
+
const occupied = modules.get(name) ?? /* @__PURE__ */ new Set();
|
|
30164
|
+
for (const key of exports) {
|
|
30165
|
+
if (occupied.has(key)) throw new TypeError(`Conflicting export '${name}.${key}'.`);
|
|
30166
|
+
occupied.add(key);
|
|
30167
|
+
}
|
|
30168
|
+
modules.set(name, occupied);
|
|
30169
|
+
}
|
|
30170
|
+
}
|
|
30171
|
+
options.signal?.addEventListener("abort", this.abort, { once: true });
|
|
30172
|
+
if (options.signal?.aborted) this.abort();
|
|
30173
|
+
this.budget.setRetainedValues(this, this.retainedCallbacks);
|
|
30174
|
+
this.tracker.onFatalRejection((error) => this.poison(error));
|
|
30175
|
+
} catch (error) {
|
|
30176
|
+
this.compilation.dispose();
|
|
30177
|
+
this.lease.release();
|
|
30178
|
+
throw error;
|
|
30179
|
+
}
|
|
30180
|
+
}
|
|
30181
|
+
options;
|
|
30182
|
+
budget;
|
|
30183
|
+
lease;
|
|
30184
|
+
compilation;
|
|
30185
|
+
controller = new AbortController();
|
|
30186
|
+
phase = new AsyncLocalStorage6();
|
|
30187
|
+
queue = new SandboxJobQueue();
|
|
30188
|
+
tracker = createSandboxPromiseRejectionTracker();
|
|
30189
|
+
bridge;
|
|
30190
|
+
limits;
|
|
30191
|
+
extensions;
|
|
30192
|
+
cleanups = [];
|
|
30193
|
+
callbacks = /* @__PURE__ */ new Map();
|
|
30194
|
+
pendingCallbacks = /* @__PURE__ */ new Set();
|
|
30195
|
+
callbackCache = /* @__PURE__ */ new WeakMap();
|
|
30196
|
+
hostObjects = /* @__PURE__ */ new Set();
|
|
30197
|
+
nestedOperations = /* @__PURE__ */ new WeakMap();
|
|
30198
|
+
convertedModules = /* @__PURE__ */ new Map();
|
|
30199
|
+
nativeConversions = { seen: /* @__PURE__ */ new WeakMap() };
|
|
30200
|
+
modules;
|
|
30201
|
+
globals;
|
|
30202
|
+
builtinBindings;
|
|
30203
|
+
scope;
|
|
30204
|
+
active;
|
|
30205
|
+
disposal;
|
|
30206
|
+
closed = false;
|
|
30207
|
+
initialized = false;
|
|
30208
|
+
nestedDepth = 0;
|
|
30209
|
+
failure;
|
|
30210
|
+
bridgeOptions = () => ({
|
|
30211
|
+
budget: this.budget,
|
|
30212
|
+
compileOwner: this.lease.owner,
|
|
30213
|
+
signal: this.controller.signal,
|
|
30214
|
+
realm: this.bridge
|
|
30215
|
+
});
|
|
30216
|
+
retainedCallbacks = () => [
|
|
30217
|
+
...this.callbacks.values(),
|
|
30218
|
+
...Array.from(this.pendingCallbacks, (pending) => pending.closure)
|
|
30219
|
+
];
|
|
30220
|
+
assertOpen = () => {
|
|
30221
|
+
if (this.failure !== void 0) throw this.failure.reason;
|
|
30222
|
+
if (this.closed) throw new Error("SafeJS realm is closed; capabilities are revoked.");
|
|
30223
|
+
this.controller.signal.throwIfAborted();
|
|
30224
|
+
};
|
|
30225
|
+
abort = () => {
|
|
30226
|
+
this.poison(this.options.signal?.reason ?? new SandboxError("aborted"));
|
|
30227
|
+
void this.close().catch(() => void 0);
|
|
30228
|
+
};
|
|
30229
|
+
poison(reason) {
|
|
30230
|
+
this.failure ??= { reason };
|
|
30231
|
+
this.controller.abort(reason);
|
|
30232
|
+
if (this.active === void 0)
|
|
30233
|
+
queueMicrotask(() => {
|
|
30234
|
+
void this.dispose().catch(() => void 0);
|
|
30235
|
+
});
|
|
30236
|
+
}
|
|
30237
|
+
chargeWork = (units = 1) => {
|
|
30238
|
+
this.assertOpen();
|
|
30239
|
+
if (!Number.isSafeInteger(units) || units < 0)
|
|
30240
|
+
throw new TypeError("Work charges must be non-negative safe integers.");
|
|
30241
|
+
try {
|
|
30242
|
+
for (let index = 0; index < units; index++) this.budget.visitNode();
|
|
30243
|
+
} catch (error) {
|
|
30244
|
+
this.poison(error);
|
|
30245
|
+
throw error;
|
|
30246
|
+
}
|
|
30247
|
+
};
|
|
30248
|
+
onCleanup = (cleanup) => {
|
|
30249
|
+
this.assertOpen();
|
|
30250
|
+
if (typeof cleanup !== "function") throw new TypeError("Cleanup must be a function.");
|
|
30251
|
+
this.checkCollection(this.cleanups.length + 1, this.limits.cleanups, "cleanup");
|
|
30252
|
+
this.cleanups.push(cleanup);
|
|
30253
|
+
};
|
|
30254
|
+
checkCollection(count, limit, name) {
|
|
30255
|
+
this.assertOpen();
|
|
30256
|
+
try {
|
|
30257
|
+
this.budget.allocateCollectionEntries(count);
|
|
30258
|
+
} catch (error) {
|
|
30259
|
+
this.poison(error);
|
|
30260
|
+
throw error;
|
|
30261
|
+
}
|
|
30262
|
+
if (count > limit) throw new RangeError(`Realm ${name} limit exceeded.`);
|
|
30263
|
+
}
|
|
30264
|
+
invokeHost = (operation, call) => {
|
|
30265
|
+
this.assertOpen();
|
|
30266
|
+
const phase = {
|
|
30267
|
+
active: true,
|
|
30268
|
+
extension: this.nestedOperations.get(operation),
|
|
30269
|
+
evaluating: false,
|
|
30270
|
+
pending: /* @__PURE__ */ new Set()
|
|
30271
|
+
};
|
|
30272
|
+
return this.phase.run(phase, () => {
|
|
30273
|
+
try {
|
|
30274
|
+
const result = call();
|
|
30275
|
+
if (types3.isPromise(result) || phase.pending.size > 0 || phase.failure !== void 0) {
|
|
30276
|
+
return Promise.resolve(result).then(
|
|
30277
|
+
async (value) => {
|
|
30278
|
+
await Promise.allSettled(phase.pending);
|
|
30279
|
+
if (phase.failure !== void 0) throw phase.failure.reason;
|
|
30280
|
+
this.assertOpen();
|
|
30281
|
+
return value;
|
|
30282
|
+
},
|
|
30283
|
+
async (error) => {
|
|
30284
|
+
if (error instanceof SandboxError || phase.pending.size > 0) this.poison(error);
|
|
30285
|
+
await Promise.allSettled(phase.pending);
|
|
30286
|
+
throw error;
|
|
30287
|
+
}
|
|
30288
|
+
).finally(() => {
|
|
30289
|
+
phase.active = false;
|
|
30290
|
+
});
|
|
30291
|
+
}
|
|
30292
|
+
this.assertOpen();
|
|
30293
|
+
phase.active = false;
|
|
30294
|
+
return result;
|
|
30295
|
+
} catch (error) {
|
|
30296
|
+
phase.active = false;
|
|
30297
|
+
if (error instanceof SandboxError) this.poison(error);
|
|
30298
|
+
if (phase.pending.size > 0) {
|
|
30299
|
+
this.poison(error);
|
|
30300
|
+
return Promise.allSettled(phase.pending).then(() => {
|
|
30301
|
+
throw error;
|
|
30302
|
+
});
|
|
30303
|
+
}
|
|
30304
|
+
throw error;
|
|
30305
|
+
}
|
|
30306
|
+
});
|
|
30307
|
+
};
|
|
30308
|
+
importValue(value) {
|
|
30309
|
+
return copyHostValueToSandbox(
|
|
30310
|
+
value,
|
|
30311
|
+
[],
|
|
30312
|
+
this.bridgeOptions(),
|
|
30313
|
+
{ seen: /* @__PURE__ */ new WeakMap() },
|
|
30314
|
+
"<realm>"
|
|
30315
|
+
);
|
|
30316
|
+
}
|
|
30317
|
+
exportValue(value) {
|
|
30318
|
+
return deepCopyFromSandbox(value, {
|
|
30319
|
+
compilation: this.compilation,
|
|
30320
|
+
wrapClosure: this.wrapCallback,
|
|
30321
|
+
unwrapHostObject: (object) => exportHostCapability(object, this)
|
|
30322
|
+
});
|
|
30323
|
+
}
|
|
30324
|
+
createHostObject = (definition) => {
|
|
30325
|
+
this.checkCollection(this.hostObjects.size + 1, this.limits.hostObjects, "host object");
|
|
30326
|
+
const object = createLiveHostObject(definition, {
|
|
30327
|
+
owner: this,
|
|
30328
|
+
assertActive: this.assertOpen,
|
|
30329
|
+
chargeWork: this.chargeWork,
|
|
30330
|
+
read: (operation) => {
|
|
30331
|
+
const value = this.invokeHost(operation, operation);
|
|
30332
|
+
if (types3.isPromise(value)) {
|
|
30333
|
+
void Promise.resolve(value).catch(() => void 0);
|
|
30334
|
+
throw new TypeError("Live property getters must be synchronous.");
|
|
30335
|
+
}
|
|
30336
|
+
return this.importValue(value);
|
|
30337
|
+
},
|
|
30338
|
+
write: (operation, value) => {
|
|
30339
|
+
const result = this.invokeHost(operation, () => operation(this.exportValue(value)));
|
|
30340
|
+
if (types3.isPromise(result)) {
|
|
30341
|
+
void Promise.resolve(result).catch(() => void 0);
|
|
30342
|
+
throw new TypeError("Live property setters must be synchronous.");
|
|
30343
|
+
}
|
|
30344
|
+
},
|
|
30345
|
+
method: (operation) => {
|
|
30346
|
+
const value = copyHostValueToSandbox(
|
|
30347
|
+
operation,
|
|
30348
|
+
[],
|
|
30349
|
+
this.bridgeOptions(),
|
|
30350
|
+
this.nativeConversions,
|
|
30351
|
+
"<host-method>"
|
|
30352
|
+
);
|
|
30353
|
+
if (!isSandboxClosure(value)) throw new TypeError("Invalid host method.");
|
|
30354
|
+
return value;
|
|
30355
|
+
}
|
|
30356
|
+
});
|
|
30357
|
+
this.hostObjects.add(object);
|
|
30358
|
+
try {
|
|
30359
|
+
this.budget.chargeDataUsage(1);
|
|
30360
|
+
} catch (error) {
|
|
30361
|
+
this.poison(error);
|
|
30362
|
+
throw error;
|
|
30363
|
+
}
|
|
30364
|
+
return object;
|
|
30365
|
+
};
|
|
30366
|
+
wrapCallback = (closure) => {
|
|
30367
|
+
this.assertOpen();
|
|
30368
|
+
const existing = this.callbackCache.get(closure);
|
|
30369
|
+
if (existing !== void 0 && this.callbacks.has(existing)) return existing;
|
|
30370
|
+
this.checkCollection(this.callbacks.size + 1, this.limits.callbacks, "callback");
|
|
30371
|
+
const invokeCallback = this.invokeCallback;
|
|
30372
|
+
const callback = function(...args) {
|
|
30373
|
+
return invokeCallback(callback, { args, thisValue: this });
|
|
30374
|
+
};
|
|
30375
|
+
this.callbacks.set(callback, closure);
|
|
30376
|
+
this.callbackCache.set(closure, callback);
|
|
30377
|
+
registerGuestCallback(callback, {
|
|
30378
|
+
owner: this,
|
|
30379
|
+
closure,
|
|
30380
|
+
assertActive: () => {
|
|
30381
|
+
this.assertOpen();
|
|
30382
|
+
if (!this.callbacks.has(callback)) throw new TypeError("Guest callback is revoked.");
|
|
30383
|
+
}
|
|
30384
|
+
});
|
|
30385
|
+
try {
|
|
30386
|
+
this.budget.reconcileDataUsage(
|
|
30387
|
+
measureSandboxData([...this.scope?.retainedValues() ?? [], ...this.retainedCallbacks()])
|
|
30388
|
+
);
|
|
30389
|
+
} catch (error) {
|
|
30390
|
+
this.poison(error);
|
|
30391
|
+
throw error;
|
|
30392
|
+
}
|
|
30393
|
+
return callback;
|
|
30394
|
+
};
|
|
30395
|
+
releaseCallback = (callback) => {
|
|
30396
|
+
readGuestCallback(callback, this);
|
|
30397
|
+
revokeGuestCallback(callback, this);
|
|
30398
|
+
this.callbacks.delete(callback);
|
|
30399
|
+
if (this.active === void 0)
|
|
30400
|
+
reconcileCompiledValues(
|
|
30401
|
+
this.budget,
|
|
30402
|
+
[...this.scope?.retainedValues() ?? [], ...this.retainedCallbacks()],
|
|
30403
|
+
this.compilation
|
|
30404
|
+
);
|
|
30405
|
+
};
|
|
30406
|
+
invokeCallback = async (callback, options = {}) => {
|
|
30407
|
+
if (this.closed || this.failure !== void 0) await this.dispose();
|
|
30408
|
+
this.assertOpen();
|
|
30409
|
+
const closure = readGuestCallback(callback, this);
|
|
30410
|
+
this.checkCollection(this.pendingCallbacks.size + 1, this.limits.callbacks, "pending callback");
|
|
30411
|
+
const record2 = { closure };
|
|
30412
|
+
this.pendingCallbacks.add(record2);
|
|
30413
|
+
const invoke = async () => {
|
|
30414
|
+
this.assertOpen();
|
|
30415
|
+
readGuestCallback(callback, this);
|
|
30416
|
+
const leave = enterRunningState(closure);
|
|
30417
|
+
const leaveCall = this.budget.enterCall();
|
|
30418
|
+
try {
|
|
30419
|
+
const values = this.importValue([
|
|
30420
|
+
options.thisValue,
|
|
30421
|
+
[...options.args ?? []]
|
|
30422
|
+
]);
|
|
30423
|
+
const value = await closure.call(values[1], {
|
|
30424
|
+
thisValue: values[0],
|
|
30425
|
+
compilation: this.compilation,
|
|
30426
|
+
stack: []
|
|
30427
|
+
});
|
|
30428
|
+
const settled = await suspendJob(
|
|
30429
|
+
awaitSandboxValue(value, this.controller.signal, this.budget)
|
|
30430
|
+
);
|
|
30431
|
+
return this.exportValue(settled);
|
|
30432
|
+
} finally {
|
|
30433
|
+
leaveCall();
|
|
30434
|
+
leave();
|
|
30435
|
+
}
|
|
30436
|
+
};
|
|
30437
|
+
try {
|
|
30438
|
+
if (this.active !== void 0) {
|
|
30439
|
+
record2.promise = withSandboxPromiseRejectionTracker(
|
|
30440
|
+
this.tracker,
|
|
30441
|
+
() => runResources.run(
|
|
30442
|
+
{ signal: this.controller.signal, add: this.onCleanup },
|
|
30443
|
+
() => withCancellationSignal(
|
|
30444
|
+
this.controller.signal,
|
|
30445
|
+
() => this.phase.getStore()?.active ? runAsyncPrefix(invoke) : this.queue.run(invoke)
|
|
30446
|
+
)
|
|
30447
|
+
)
|
|
30448
|
+
);
|
|
30449
|
+
} else {
|
|
30450
|
+
record2.promise = this.perform(() => this.queue.run(invoke));
|
|
30451
|
+
}
|
|
30452
|
+
return await record2.promise;
|
|
30453
|
+
} catch (error) {
|
|
30454
|
+
if (error instanceof SandboxError) this.poison(error);
|
|
30455
|
+
throw error;
|
|
30456
|
+
} finally {
|
|
30457
|
+
this.pendingCallbacks.delete(record2);
|
|
30458
|
+
if (!this.closed && this.active === void 0)
|
|
30459
|
+
reconcileCompiledValues(
|
|
30460
|
+
this.budget,
|
|
30461
|
+
[...this.scope?.retainedValues() ?? [], ...this.retainedCallbacks()],
|
|
30462
|
+
this.compilation
|
|
30463
|
+
);
|
|
30464
|
+
}
|
|
30465
|
+
};
|
|
30466
|
+
initialize() {
|
|
30467
|
+
if (this.initialized) return;
|
|
30468
|
+
this.assertOpen();
|
|
30469
|
+
this.initialized = true;
|
|
30470
|
+
for (const extension of this.extensions) {
|
|
30471
|
+
const context = Object.freeze({
|
|
30472
|
+
signal: this.controller.signal,
|
|
30473
|
+
onCleanup: this.onCleanup,
|
|
30474
|
+
chargeWork: this.chargeWork,
|
|
30475
|
+
createHostObject: this.createHostObject,
|
|
30476
|
+
invokeCallback: this.invokeCallback,
|
|
30477
|
+
releaseCallback: this.releaseCallback,
|
|
30478
|
+
nestedOperation: (operation) => {
|
|
30479
|
+
this.assertOpen();
|
|
30480
|
+
if (!extension.manifest.capabilities?.includes("source:nested"))
|
|
30481
|
+
throw new TypeError("Nested source requires the source:nested grant.");
|
|
30482
|
+
if (typeof operation !== "function")
|
|
30483
|
+
throw new TypeError("Nested operation must be a function.");
|
|
30484
|
+
if (this.scope !== void 0)
|
|
30485
|
+
throw new TypeError("Nested operations must be registered during setup.");
|
|
30486
|
+
const owner = this.nestedOperations.get(operation);
|
|
30487
|
+
if (owner !== void 0 && owner !== extension)
|
|
30488
|
+
throw new TypeError("Nested operation already belongs to another extension.");
|
|
30489
|
+
this.nestedOperations.set(operation, extension);
|
|
30490
|
+
return operation;
|
|
30491
|
+
},
|
|
30492
|
+
evaluateNested: (source) => {
|
|
30493
|
+
const phase = this.phase.getStore();
|
|
30494
|
+
if (!extension.manifest.capabilities?.includes("source:nested") || !phase?.active || phase.extension !== extension || phase.evaluating) {
|
|
30495
|
+
const error = new SandboxError("reentry");
|
|
30496
|
+
this.poison(error);
|
|
30497
|
+
const rejected = Promise.reject(error);
|
|
30498
|
+
void rejected.catch(() => void 0);
|
|
30499
|
+
return rejected;
|
|
30500
|
+
}
|
|
30501
|
+
const pending = this.evaluateNested(source, extension);
|
|
30502
|
+
phase.pending.add(pending);
|
|
30503
|
+
void pending.then(
|
|
30504
|
+
() => {
|
|
30505
|
+
phase.pending.delete(pending);
|
|
30506
|
+
},
|
|
30507
|
+
(reason) => {
|
|
30508
|
+
phase.pending.delete(pending);
|
|
30509
|
+
phase.failure ??= { reason };
|
|
30510
|
+
}
|
|
30511
|
+
);
|
|
30512
|
+
return pending;
|
|
30513
|
+
}
|
|
30514
|
+
});
|
|
30515
|
+
const output = getExtensionSetup(extension)(context);
|
|
30516
|
+
if (types3.isPromise(output)) {
|
|
30517
|
+
void Promise.resolve(output).catch(() => void 0);
|
|
30518
|
+
throw new TypeError("Extension setup must be synchronous.");
|
|
30519
|
+
}
|
|
30520
|
+
const exports = readDataRecord(output, "Extension exports");
|
|
30521
|
+
if (Object.keys(exports).some((key) => key !== "globals" && key !== "modules"))
|
|
30522
|
+
throw new TypeError("Unknown extension export field.");
|
|
30523
|
+
const globals = readDataRecord(
|
|
30524
|
+
exports.globals ?? {},
|
|
30525
|
+
"Extension globals"
|
|
30526
|
+
);
|
|
30527
|
+
const modules = readModules(exports.modules);
|
|
30528
|
+
assertNames(Object.keys(globals), extension.manifest.globals ?? [], "global");
|
|
30529
|
+
assertNames(Object.keys(modules), Object.keys(extension.manifest.modules ?? {}), "module");
|
|
30530
|
+
for (const [name, values] of Object.entries(modules)) {
|
|
30531
|
+
assertNames(Object.keys(values), extension.manifest.modules?.[name] ?? [], "module export");
|
|
30532
|
+
this.modules[name] ??= /* @__PURE__ */ Object.create(null);
|
|
30533
|
+
Object.assign(this.modules[name], values);
|
|
30534
|
+
}
|
|
30535
|
+
Object.assign(this.globals, globals);
|
|
30536
|
+
}
|
|
30537
|
+
const bindings = wrapCallerInjectedBindings(this.globals, this.bridgeOptions());
|
|
30538
|
+
this.scope = new Scope(this.builtinBindings, void 0, void 0, { chargeData: false }).child(
|
|
30539
|
+
bindings,
|
|
30540
|
+
{ functionBoundary: true }
|
|
30541
|
+
);
|
|
30542
|
+
}
|
|
30543
|
+
async evaluateRaw(source, filename = "<realm>", nested = false) {
|
|
30544
|
+
this.assertOpen();
|
|
30545
|
+
if (typeof source !== "string") throw new TypeError("Realm source must be a string.");
|
|
30546
|
+
const module = parseExecutableModule(source, filename, this.lease.owner);
|
|
30547
|
+
this.initialize();
|
|
30548
|
+
const imports = resolveModuleImports(module, this.modules, {
|
|
30549
|
+
...this.bridgeOptions(),
|
|
30550
|
+
wrappedModules: this.convertedModules
|
|
30551
|
+
});
|
|
30552
|
+
for (const [name, value] of Object.entries(imports)) {
|
|
30553
|
+
const binding = this.scope.lookup(name);
|
|
30554
|
+
if (!binding.found) this.scope.declare(name, "const", value);
|
|
30555
|
+
else if (binding.value !== value) throw new TypeError(`Conflicting import '${name}'.`);
|
|
30556
|
+
}
|
|
30557
|
+
const result = await interpret(
|
|
30558
|
+
{
|
|
30559
|
+
type: "BlockStatement",
|
|
30560
|
+
body: module.body.filter((statement) => statement.type !== "ImportDeclaration"),
|
|
30561
|
+
span: module.span
|
|
30562
|
+
},
|
|
30563
|
+
{
|
|
30564
|
+
scope: this.scope,
|
|
30565
|
+
useScopeDirectly: true,
|
|
30566
|
+
budget: this.budget,
|
|
30567
|
+
compilation: this.compilation,
|
|
30568
|
+
signal: this.controller.signal,
|
|
30569
|
+
surfaceUnhandledThrows: true,
|
|
30570
|
+
jobs: this.queue,
|
|
30571
|
+
nested,
|
|
30572
|
+
assertActive: this.assertOpen
|
|
30573
|
+
}
|
|
30574
|
+
);
|
|
30575
|
+
this.assertOpen();
|
|
30576
|
+
return result;
|
|
30577
|
+
}
|
|
30578
|
+
evaluateNested = async (source, extension) => {
|
|
30579
|
+
this.assertOpen();
|
|
30580
|
+
const phase = this.phase.getStore();
|
|
30581
|
+
if (!phase?.active || phase.extension !== extension || phase.evaluating || this.active === void 0)
|
|
30582
|
+
throw new SandboxError("reentry");
|
|
30583
|
+
const leave = this.budget.enterCall();
|
|
30584
|
+
phase.evaluating = true;
|
|
30585
|
+
try {
|
|
30586
|
+
if (++this.nestedDepth > this.limits.nestedEvaluations) {
|
|
30587
|
+
const error = new SandboxError({
|
|
30588
|
+
budget: "callDepth",
|
|
30589
|
+
current: this.nestedDepth,
|
|
30590
|
+
limit: this.limits.nestedEvaluations
|
|
30591
|
+
});
|
|
30592
|
+
this.poison(error);
|
|
30593
|
+
throw error;
|
|
30594
|
+
}
|
|
30595
|
+
const result = await this.evaluateRaw(source, "<nested>", true);
|
|
30596
|
+
if (!result.ok) throw new Error(result.error.message);
|
|
30597
|
+
} finally {
|
|
30598
|
+
this.nestedDepth--;
|
|
30599
|
+
phase.evaluating = false;
|
|
30600
|
+
leave();
|
|
30601
|
+
}
|
|
30602
|
+
};
|
|
30603
|
+
evaluate = async (source, options = {}) => this.perform(async () => {
|
|
30604
|
+
const result = await this.evaluateRaw(source, options.filename);
|
|
30605
|
+
if (!result.ok) {
|
|
30606
|
+
await this.dispose();
|
|
30607
|
+
return { ok: false, error: result.error, stats: result.stats };
|
|
30608
|
+
}
|
|
30609
|
+
return { ok: true, returnValue: this.exportValue(result.returnValue), stats: result.stats };
|
|
30610
|
+
});
|
|
30611
|
+
async perform(task) {
|
|
30612
|
+
if (this.closed || this.failure !== void 0) await this.dispose();
|
|
30613
|
+
this.assertOpen();
|
|
30614
|
+
if (this.active !== void 0) throw new SandboxError("reentry");
|
|
30615
|
+
const pending = Promise.resolve().then(
|
|
30616
|
+
() => withSandboxPromiseRejectionTracker(
|
|
30617
|
+
this.tracker,
|
|
30618
|
+
() => runResources.run(
|
|
30619
|
+
{ signal: this.controller.signal, add: this.onCleanup },
|
|
30620
|
+
() => withCancellationSignal(this.controller.signal, task)
|
|
30621
|
+
)
|
|
30622
|
+
)
|
|
30623
|
+
);
|
|
30624
|
+
this.active = pending;
|
|
30625
|
+
try {
|
|
30626
|
+
const result = await pending;
|
|
30627
|
+
await this.queue.drain();
|
|
30628
|
+
const unhandled = await this.tracker.findUnhandledRejection();
|
|
30629
|
+
if (unhandled !== void 0) {
|
|
30630
|
+
const error = new Error(
|
|
30631
|
+
`Unhandled guest promise rejection: ${describeThrownValue(unhandled.reason)}`
|
|
30632
|
+
);
|
|
30633
|
+
error.name = "UnhandledRejectionError";
|
|
30634
|
+
throw error;
|
|
30635
|
+
}
|
|
30636
|
+
if (this.failure !== void 0) throw this.failure.reason;
|
|
30637
|
+
if (!this.closed)
|
|
30638
|
+
reconcileCompiledValues(
|
|
30639
|
+
this.budget,
|
|
30640
|
+
[...this.scope?.retainedValues() ?? [], ...this.retainedCallbacks()],
|
|
30641
|
+
this.compilation
|
|
30642
|
+
);
|
|
30643
|
+
return result;
|
|
30644
|
+
} catch (error) {
|
|
30645
|
+
this.poison(error);
|
|
30646
|
+
try {
|
|
30647
|
+
await this.dispose();
|
|
30648
|
+
} catch (cleanup) {
|
|
30649
|
+
throw new AggregateError([error, cleanup], "Realm execution and cleanup failed.");
|
|
30650
|
+
}
|
|
30651
|
+
throw error;
|
|
30652
|
+
} finally {
|
|
30653
|
+
this.active = void 0;
|
|
30654
|
+
}
|
|
30655
|
+
}
|
|
30656
|
+
close = () => {
|
|
30657
|
+
this.closed = true;
|
|
30658
|
+
this.controller.abort(new Error("SafeJS realm is closed."));
|
|
30659
|
+
if (this.phase.getStore()?.active) return this.dispose();
|
|
30660
|
+
return Promise.allSettled([
|
|
30661
|
+
this.active,
|
|
30662
|
+
...Array.from(this.pendingCallbacks, (pending) => pending.promise)
|
|
30663
|
+
]).then(() => this.dispose());
|
|
30664
|
+
};
|
|
30665
|
+
dispose() {
|
|
30666
|
+
if (this.disposal !== void 0) return this.disposal;
|
|
30667
|
+
this.closed = true;
|
|
30668
|
+
this.controller.abort(new Error("SafeJS realm is closed."));
|
|
30669
|
+
this.options.signal?.removeEventListener("abort", this.abort);
|
|
30670
|
+
for (const callback of this.callbacks.keys()) revokeGuestCallback(callback, this);
|
|
30671
|
+
this.callbacks.clear();
|
|
30672
|
+
for (const object of this.hostObjects) revokeHostObject(object, this);
|
|
30673
|
+
this.hostObjects.clear();
|
|
30674
|
+
this.budget.setRetainedValues(this, void 0);
|
|
30675
|
+
this.disposal = (async () => {
|
|
30676
|
+
const errors = [];
|
|
30677
|
+
for (const cleanup of this.cleanups.splice(0).reverse()) {
|
|
30678
|
+
try {
|
|
30679
|
+
await cleanup();
|
|
30680
|
+
} catch (error) {
|
|
30681
|
+
errors.push(error);
|
|
30682
|
+
}
|
|
30683
|
+
}
|
|
30684
|
+
this.scope = void 0;
|
|
30685
|
+
this.convertedModules.clear();
|
|
30686
|
+
for (const key of Object.keys(this.globals)) delete this.globals[key];
|
|
30687
|
+
for (const key of Object.keys(this.modules)) delete this.modules[key];
|
|
30688
|
+
for (const key of Object.keys(this.builtinBindings))
|
|
30689
|
+
Reflect.deleteProperty(this.builtinBindings, key);
|
|
30690
|
+
this.nativeConversions.seen = /* @__PURE__ */ new WeakMap();
|
|
30691
|
+
reconcileCompiledValues(this.budget, [], this.compilation);
|
|
30692
|
+
this.compilation.dispose();
|
|
30693
|
+
this.lease.release();
|
|
30694
|
+
if (errors.length > 0) throw new AggregateError(errors, "Realm cleanup failed.");
|
|
30695
|
+
})();
|
|
30696
|
+
return this.disposal;
|
|
30697
|
+
}
|
|
30698
|
+
};
|
|
30699
|
+
function readModules(input) {
|
|
30700
|
+
const entries = (value, label) => {
|
|
30701
|
+
if (types3.isMap(value) && !types3.isProxy(value)) {
|
|
30702
|
+
const result = [...Map.prototype.entries.call(value)];
|
|
30703
|
+
if (result.length > 4096 || result.some(([key]) => typeof key !== "string" || key.length === 0))
|
|
30704
|
+
throw new TypeError(`${label} requires bounded string keys.`);
|
|
30705
|
+
return result;
|
|
30706
|
+
}
|
|
30707
|
+
return Object.entries(readDataRecord(value, label));
|
|
30708
|
+
};
|
|
30709
|
+
const modules = /* @__PURE__ */ Object.create(null);
|
|
30710
|
+
for (const [name, exports] of entries(input ?? {}, "Module registry")) {
|
|
30711
|
+
const exported = /* @__PURE__ */ Object.create(null);
|
|
30712
|
+
for (const [key, value] of entries(exports, "Module exports"))
|
|
30713
|
+
exported[key] = value;
|
|
30714
|
+
modules[name] = exported;
|
|
30715
|
+
}
|
|
30716
|
+
return modules;
|
|
30717
|
+
}
|
|
30718
|
+
function assertNames(actual, expected, label) {
|
|
30719
|
+
if (actual.length !== expected.length || actual.some((name) => !expected.includes(name)))
|
|
30720
|
+
throw new TypeError(`Extension ${label} names do not match its manifest.`);
|
|
30721
|
+
}
|
|
30722
|
+
function createRealm(options = {}) {
|
|
30723
|
+
const state = new RealmState(readRealmOptions(options));
|
|
30724
|
+
return Object.freeze({
|
|
30725
|
+
extensions: Object.freeze(state.extensions.map((extension) => extension.manifest)),
|
|
30726
|
+
evaluate: state.evaluate,
|
|
30727
|
+
invokeCallback: state.invokeCallback,
|
|
30728
|
+
releaseCallback: state.releaseCallback,
|
|
30729
|
+
close: state.close
|
|
30730
|
+
});
|
|
30731
|
+
}
|
|
30732
|
+
async function runWithExtensions(source, options) {
|
|
30733
|
+
if (options.snapshot !== void 0 || options.snapshotBackend !== void 0 || options.snapshotPath !== void 0 || options.entryPointArgs !== void 0)
|
|
30734
|
+
throw new TypeError(
|
|
30735
|
+
"Live extension runs do not support snapshots or entryPointArgs; use a persistent realm."
|
|
30736
|
+
);
|
|
30737
|
+
const state = new RealmState(readRealmOptions(options, true));
|
|
30738
|
+
try {
|
|
30739
|
+
const result = await state.perform(() => state.evaluateRaw(source, options.filename));
|
|
30740
|
+
if (result.ok) encodeReplayData(result.returnValue);
|
|
30741
|
+
return {
|
|
30742
|
+
...result,
|
|
30743
|
+
snapshot: {
|
|
30744
|
+
version: 1,
|
|
30745
|
+
sourceHash: hashSource(source),
|
|
30746
|
+
bindings: {},
|
|
30747
|
+
replayError: "Live realm state cannot be serialized or replayed."
|
|
30748
|
+
}
|
|
30749
|
+
};
|
|
30750
|
+
} catch (error) {
|
|
30751
|
+
if (state.disposal === void 0) {
|
|
30752
|
+
try {
|
|
30753
|
+
await state.close();
|
|
30754
|
+
} catch (cleanupError) {
|
|
30755
|
+
throw new AggregateError([error, cleanupError], "Realm execution and cleanup failed.");
|
|
30756
|
+
}
|
|
30757
|
+
}
|
|
30758
|
+
throw error;
|
|
30759
|
+
} finally {
|
|
30760
|
+
if (state.disposal === void 0) await state.close();
|
|
30761
|
+
}
|
|
30762
|
+
}
|
|
30763
|
+
function readRealmOptions(value, oneShot = false) {
|
|
30764
|
+
const options = readDataRecord(value, "Realm options");
|
|
30765
|
+
const supported = /* @__PURE__ */ new Set([
|
|
30766
|
+
"bindings",
|
|
30767
|
+
"modules",
|
|
30768
|
+
"extensions",
|
|
30769
|
+
"grants",
|
|
30770
|
+
"budget",
|
|
30771
|
+
"signal",
|
|
30772
|
+
"sink",
|
|
30773
|
+
"randomSeed",
|
|
30774
|
+
"limits"
|
|
30775
|
+
]);
|
|
30776
|
+
for (const [key, entry] of Object.entries(options)) {
|
|
30777
|
+
if (supported.has(key) || oneShot && (key === "filename" || entry === void 0)) continue;
|
|
30778
|
+
throw new TypeError(`Unsupported ${oneShot ? "extension-run" : "realm"} option '${key}'.`);
|
|
30779
|
+
}
|
|
30780
|
+
return options;
|
|
30781
|
+
}
|
|
30782
|
+
|
|
30783
|
+
// packages/safe-js/src/snapshot/dump.ts
|
|
30784
|
+
var RUN_DUMP_CONTROLLER = /* @__PURE__ */ Symbol("SafeJS.run-dump-controller");
|
|
30785
|
+
function attachDumpController(result, controller) {
|
|
30786
|
+
Object.defineProperty(result, RUN_DUMP_CONTROLLER, {
|
|
30787
|
+
configurable: false,
|
|
30788
|
+
enumerable: false,
|
|
30789
|
+
value: controller,
|
|
30790
|
+
writable: false
|
|
30791
|
+
});
|
|
30792
|
+
return result;
|
|
30793
|
+
}
|
|
30794
|
+
function createDumpController(lifecycle) {
|
|
30795
|
+
let finished = false;
|
|
30796
|
+
let failed;
|
|
30797
|
+
let finalSnapshot;
|
|
30798
|
+
let latestSnapshot;
|
|
30799
|
+
let latestSnapshotFactory;
|
|
30800
|
+
let pendingRequest;
|
|
30801
|
+
return {
|
|
30802
|
+
fail(error) {
|
|
30803
|
+
finished = true;
|
|
30804
|
+
failed = {
|
|
30805
|
+
error
|
|
30806
|
+
};
|
|
30807
|
+
if (pendingRequest === void 0) {
|
|
30808
|
+
return;
|
|
30809
|
+
}
|
|
30810
|
+
pendingRequest.reject(error);
|
|
30811
|
+
pendingRequest = void 0;
|
|
30812
|
+
},
|
|
30813
|
+
finalize(snapshot) {
|
|
30814
|
+
finished = true;
|
|
30815
|
+
finalSnapshot = snapshot;
|
|
30816
|
+
latestSnapshot = snapshot;
|
|
30817
|
+
latestSnapshotFactory = void 0;
|
|
30818
|
+
if (pendingRequest !== void 0) {
|
|
30819
|
+
settlePendingSnapshot(snapshot);
|
|
30820
|
+
}
|
|
30821
|
+
},
|
|
30822
|
+
onYield(createSnapshot) {
|
|
30823
|
+
latestSnapshot = void 0;
|
|
30824
|
+
latestSnapshotFactory = createSnapshot;
|
|
30825
|
+
if (pendingRequest === void 0) {
|
|
30826
|
+
return;
|
|
30827
|
+
}
|
|
30828
|
+
settlePendingSnapshot(createSnapshot());
|
|
30829
|
+
},
|
|
30830
|
+
requestCurrentSnapshot(options = {}) {
|
|
30831
|
+
assertDumpAllowed(options);
|
|
30832
|
+
if (failed !== void 0) {
|
|
30833
|
+
return Promise.reject(failed.error);
|
|
29904
30834
|
}
|
|
29905
|
-
if (
|
|
29906
|
-
|
|
29907
|
-
|
|
29908
|
-
|
|
30835
|
+
if (latestSnapshot !== void 0 || latestSnapshotFactory !== void 0) {
|
|
30836
|
+
try {
|
|
30837
|
+
return Promise.resolve(serializeRunSnapshot(latestSnapshot ?? latestSnapshotFactory()));
|
|
30838
|
+
} catch (error) {
|
|
30839
|
+
return Promise.reject(error);
|
|
30840
|
+
}
|
|
29909
30841
|
}
|
|
29910
|
-
|
|
29911
|
-
|
|
29912
|
-
|
|
29913
|
-
|
|
29914
|
-
|
|
29915
|
-
|
|
29916
|
-
|
|
30842
|
+
return this.requestSnapshot(options);
|
|
30843
|
+
},
|
|
30844
|
+
requestSnapshot(options = {}) {
|
|
30845
|
+
assertDumpAllowed(options);
|
|
30846
|
+
if (failed !== void 0) {
|
|
30847
|
+
if ((options.onFailure === "checkpoint" || options.onFailure === void 0 && isDataBudgetError(failed.error)) && finalSnapshot !== void 0) {
|
|
30848
|
+
try {
|
|
30849
|
+
return Promise.resolve(serializeRunSnapshot(finalSnapshot));
|
|
30850
|
+
} catch (error) {
|
|
30851
|
+
return Promise.reject(error);
|
|
30852
|
+
}
|
|
30853
|
+
}
|
|
30854
|
+
return Promise.reject(failed.error);
|
|
30855
|
+
}
|
|
30856
|
+
if (finished) {
|
|
30857
|
+
if (finalSnapshot === void 0) {
|
|
30858
|
+
throw new Error("Run completed without producing a snapshot.");
|
|
30859
|
+
}
|
|
30860
|
+
try {
|
|
30861
|
+
const serializedSnapshot = serializeRunSnapshot(finalSnapshot);
|
|
30862
|
+
return Promise.resolve(serializedSnapshot);
|
|
30863
|
+
} catch (error) {
|
|
30864
|
+
return Promise.reject(error);
|
|
30865
|
+
}
|
|
30866
|
+
}
|
|
30867
|
+
if (options.mode === "replay" && (latestSnapshot !== void 0 || latestSnapshotFactory !== void 0)) {
|
|
30868
|
+
return this.requestCurrentSnapshot(options);
|
|
30869
|
+
}
|
|
30870
|
+
if (pendingRequest !== void 0) {
|
|
30871
|
+
return pendingRequest.promise;
|
|
30872
|
+
}
|
|
30873
|
+
let resolveSnapshot = () => void 0;
|
|
30874
|
+
let rejectSnapshot = () => void 0;
|
|
30875
|
+
const promise = new Promise((resolve, reject) => {
|
|
30876
|
+
resolveSnapshot = resolve;
|
|
30877
|
+
rejectSnapshot = reject;
|
|
29917
30878
|
});
|
|
30879
|
+
pendingRequest = {
|
|
30880
|
+
promise,
|
|
30881
|
+
reject: rejectSnapshot,
|
|
30882
|
+
resolve: resolveSnapshot
|
|
30883
|
+
};
|
|
30884
|
+
return promise;
|
|
29918
30885
|
}
|
|
29919
|
-
}
|
|
29920
|
-
|
|
29921
|
-
|
|
29922
|
-
|
|
29923
|
-
throw error;
|
|
30886
|
+
};
|
|
30887
|
+
function assertDumpAllowed(options) {
|
|
30888
|
+
if ((lifecycle?.hostCallbackDepth ?? 0) > 0 && (options.mode !== "replay" || lifecycle?.hostCallbackContext.getStore() === true)) {
|
|
30889
|
+
throw new SandboxError("reentry");
|
|
29924
30890
|
}
|
|
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
30891
|
}
|
|
29933
|
-
|
|
29934
|
-
|
|
29935
|
-
|
|
29936
|
-
|
|
29937
|
-
|
|
29938
|
-
|
|
30892
|
+
function settlePendingSnapshot(snapshot) {
|
|
30893
|
+
try {
|
|
30894
|
+
settlePendingRequest(serializeRunSnapshot(snapshot));
|
|
30895
|
+
} catch (error) {
|
|
30896
|
+
pendingRequest?.reject(error);
|
|
30897
|
+
pendingRequest = void 0;
|
|
29939
30898
|
}
|
|
29940
|
-
|
|
29941
|
-
|
|
30899
|
+
}
|
|
30900
|
+
function settlePendingRequest(snapshot) {
|
|
30901
|
+
if (pendingRequest === void 0) {
|
|
30902
|
+
return;
|
|
29942
30903
|
}
|
|
30904
|
+
pendingRequest.resolve(snapshot);
|
|
30905
|
+
pendingRequest = void 0;
|
|
29943
30906
|
}
|
|
29944
|
-
return target;
|
|
29945
30907
|
}
|
|
29946
|
-
function
|
|
29947
|
-
|
|
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;
|
|
30908
|
+
function isDataBudgetError(error) {
|
|
30909
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "budgetExceeded" && "budget" in error && error.budget === "dataSize";
|
|
29954
30910
|
}
|
|
29955
|
-
function
|
|
29956
|
-
const
|
|
29957
|
-
|
|
29958
|
-
|
|
29959
|
-
|
|
29960
|
-
|
|
29961
|
-
|
|
29962
|
-
|
|
30911
|
+
function dump(result, options = {}) {
|
|
30912
|
+
const controller = readDumpController(result);
|
|
30913
|
+
if (controller !== void 0) {
|
|
30914
|
+
return controller.requestSnapshot(options);
|
|
30915
|
+
}
|
|
30916
|
+
if (hasSnapshot(result)) {
|
|
30917
|
+
try {
|
|
30918
|
+
return Promise.resolve(serializeRunSnapshot(result.snapshot));
|
|
30919
|
+
} catch (error) {
|
|
30920
|
+
return Promise.reject(error);
|
|
29963
30921
|
}
|
|
29964
|
-
if (field === "value") descriptor.value = entry.value;
|
|
29965
|
-
else descriptor[field] = Boolean(entry.value);
|
|
29966
30922
|
}
|
|
29967
|
-
return
|
|
29968
|
-
|
|
29969
|
-
|
|
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
|
-
}
|
|
30923
|
+
return Promise.resolve(result).then((resolved) => {
|
|
30924
|
+
if (!hasSnapshot(resolved)) {
|
|
30925
|
+
throw new Error("Run completed without producing a snapshot.");
|
|
29980
30926
|
}
|
|
30927
|
+
return serializeRunSnapshot(resolved.snapshot);
|
|
30928
|
+
});
|
|
30929
|
+
}
|
|
30930
|
+
function dumpCurrent(result) {
|
|
30931
|
+
const controller = readDumpController(result);
|
|
30932
|
+
if (controller !== void 0) {
|
|
30933
|
+
return controller.requestCurrentSnapshot();
|
|
29981
30934
|
}
|
|
29982
|
-
|
|
29983
|
-
markDescriptorObject(properties);
|
|
30935
|
+
return dump(result);
|
|
29984
30936
|
}
|
|
29985
|
-
function
|
|
29986
|
-
return
|
|
30937
|
+
function serializeRunSnapshot(snapshot) {
|
|
30938
|
+
return serializeSafeJSSnapshot(snapshot);
|
|
29987
30939
|
}
|
|
29988
|
-
|
|
29989
|
-
|
|
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);
|
|
30940
|
+
function hasSnapshot(value) {
|
|
30941
|
+
return typeof value === "object" && value !== null && Object.prototype.hasOwnProperty.call(value, "snapshot");
|
|
30007
30942
|
}
|
|
30008
|
-
function
|
|
30009
|
-
if (
|
|
30010
|
-
return
|
|
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.");
|
|
30943
|
+
function readDumpController(value) {
|
|
30944
|
+
if (typeof value !== "object" || value === null) {
|
|
30945
|
+
return void 0;
|
|
30018
30946
|
}
|
|
30019
|
-
|
|
30020
|
-
return new Array(lengthOrValue);
|
|
30947
|
+
return value[RUN_DUMP_CONTROLLER];
|
|
30021
30948
|
}
|
|
30022
|
-
|
|
30023
|
-
|
|
30024
|
-
|
|
30025
|
-
|
|
30026
|
-
|
|
30027
|
-
values.push(result.value);
|
|
30949
|
+
|
|
30950
|
+
// packages/safe-js/src/error-codes.ts
|
|
30951
|
+
function getOwnErrorCode(error) {
|
|
30952
|
+
if (typeof error !== "object" || error === null || !Object.prototype.hasOwnProperty.call(error, "code")) {
|
|
30953
|
+
return void 0;
|
|
30028
30954
|
}
|
|
30955
|
+
const code = error.code;
|
|
30956
|
+
return typeof code === "string" ? code : void 0;
|
|
30029
30957
|
}
|
|
30030
|
-
function
|
|
30031
|
-
return
|
|
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);
|
|
30958
|
+
function hasOwnErrorCode(error, code) {
|
|
30959
|
+
return getOwnErrorCode(error) === code;
|
|
30039
30960
|
}
|
|
30040
|
-
|
|
30041
|
-
|
|
30042
|
-
|
|
30043
|
-
|
|
30044
|
-
|
|
30045
|
-
|
|
30046
|
-
|
|
30047
|
-
|
|
30048
|
-
|
|
30961
|
+
|
|
30962
|
+
// packages/safe-js/src/snapshot/backend.ts
|
|
30963
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
30964
|
+
import { readFile, rename, stat, unlink, writeFile } from "node:fs/promises";
|
|
30965
|
+
import { dirname } from "node:path";
|
|
30966
|
+
var DEFAULT_WRITE_MAX_ATTEMPTS = 3;
|
|
30967
|
+
var DEFAULT_WRITE_RETRY_DELAY_MS = 100;
|
|
30968
|
+
var LOCKED_FILE_ERROR_CODES = /* @__PURE__ */ new Set(["EACCES", "EBUSY", "EPERM"]);
|
|
30969
|
+
var pendingOperations = /* @__PURE__ */ new Map();
|
|
30970
|
+
var FileSnapshotBackend = class {
|
|
30971
|
+
constructor(path, options = {}) {
|
|
30972
|
+
this.path = path;
|
|
30973
|
+
this.#writeMaxAttempts = options.writeMaxAttempts ?? DEFAULT_WRITE_MAX_ATTEMPTS;
|
|
30974
|
+
this.#writeRetryDelayMs = options.writeRetryDelayMs ?? DEFAULT_WRITE_RETRY_DELAY_MS;
|
|
30049
30975
|
}
|
|
30050
|
-
|
|
30051
|
-
|
|
30052
|
-
|
|
30053
|
-
|
|
30054
|
-
|
|
30055
|
-
|
|
30976
|
+
path;
|
|
30977
|
+
#writeMaxAttempts;
|
|
30978
|
+
#writeRetryDelayMs;
|
|
30979
|
+
async read() {
|
|
30980
|
+
try {
|
|
30981
|
+
return JSON.parse(await readFile(this.path, "utf8"));
|
|
30982
|
+
} catch (error) {
|
|
30983
|
+
if (hasErrorCode(error, "ENOENT")) {
|
|
30984
|
+
return void 0;
|
|
30985
|
+
}
|
|
30986
|
+
if (error instanceof SyntaxError) {
|
|
30987
|
+
throw new Error(`Failed to parse snapshot at ${this.path}: ${error.message}`);
|
|
30988
|
+
}
|
|
30989
|
+
throw error;
|
|
30990
|
+
}
|
|
30056
30991
|
}
|
|
30057
|
-
|
|
30058
|
-
|
|
30059
|
-
|
|
30060
|
-
|
|
30061
|
-
|
|
30062
|
-
|
|
30063
|
-
|
|
30992
|
+
async write(snapshot) {
|
|
30993
|
+
await enqueueOperation(
|
|
30994
|
+
this.path,
|
|
30995
|
+
() => writeSnapshotAtomically(this.path, snapshot, {
|
|
30996
|
+
maxAttempts: this.#writeMaxAttempts,
|
|
30997
|
+
retryDelayMs: this.#writeRetryDelayMs
|
|
30998
|
+
})
|
|
30999
|
+
);
|
|
30064
31000
|
}
|
|
30065
|
-
|
|
30066
|
-
|
|
30067
|
-
|
|
30068
|
-
|
|
30069
|
-
|
|
31001
|
+
async remove() {
|
|
31002
|
+
await enqueueOperation(this.path, async () => {
|
|
31003
|
+
try {
|
|
31004
|
+
await unlink(this.path);
|
|
31005
|
+
} catch (error) {
|
|
31006
|
+
if (!hasErrorCode(error, "ENOENT")) {
|
|
31007
|
+
throw error;
|
|
31008
|
+
}
|
|
31009
|
+
}
|
|
31010
|
+
});
|
|
30070
31011
|
}
|
|
30071
|
-
|
|
30072
|
-
|
|
30073
|
-
|
|
30074
|
-
const
|
|
30075
|
-
|
|
30076
|
-
|
|
30077
|
-
|
|
30078
|
-
|
|
30079
|
-
|
|
31012
|
+
};
|
|
31013
|
+
async function writeSnapshotAtomically(snapshotPath, snapshot, options) {
|
|
31014
|
+
const parentPath = dirname(snapshotPath);
|
|
31015
|
+
const contents = serializeSafeJSSnapshot(snapshot);
|
|
31016
|
+
await assertParentDirectoryExists(snapshotPath, parentPath);
|
|
31017
|
+
for (let attempt = 1; attempt <= options.maxAttempts; attempt += 1) {
|
|
31018
|
+
try {
|
|
31019
|
+
const temporaryPath = `${snapshotPath}.${randomUUID2()}.tmp`;
|
|
31020
|
+
await writeSnapshotOnce(temporaryPath, snapshotPath, contents);
|
|
31021
|
+
return;
|
|
31022
|
+
} catch (error) {
|
|
31023
|
+
if (hasErrorCode(error, "EEXIST")) {
|
|
31024
|
+
if (attempt === options.maxAttempts) {
|
|
31025
|
+
throw new Error(
|
|
31026
|
+
`Failed to write snapshot at ${snapshotPath} after ${options.maxAttempts} attempts: temporary path already exists`,
|
|
31027
|
+
{
|
|
31028
|
+
cause: error
|
|
31029
|
+
}
|
|
31030
|
+
);
|
|
31031
|
+
}
|
|
31032
|
+
continue;
|
|
31033
|
+
}
|
|
31034
|
+
if (!isLockedFileError(error)) {
|
|
31035
|
+
throw error;
|
|
31036
|
+
}
|
|
31037
|
+
if (attempt === options.maxAttempts) {
|
|
31038
|
+
throw new Error(
|
|
31039
|
+
`Failed to write snapshot at ${snapshotPath} after ${options.maxAttempts} attempts: file is locked (${getOwnErrorCode(error)})`,
|
|
31040
|
+
{
|
|
31041
|
+
cause: error
|
|
31042
|
+
}
|
|
31043
|
+
);
|
|
31044
|
+
}
|
|
31045
|
+
await delay(options.retryDelayMs);
|
|
30080
31046
|
}
|
|
30081
|
-
bindImportDeclaration(statement, registry, wrappedModules, bindings, options);
|
|
30082
31047
|
}
|
|
30083
|
-
return bindings;
|
|
30084
31048
|
}
|
|
30085
|
-
function
|
|
30086
|
-
|
|
30087
|
-
|
|
30088
|
-
|
|
30089
|
-
|
|
30090
|
-
|
|
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
|
|
31049
|
+
async function assertParentDirectoryExists(snapshotPath, parentPath) {
|
|
31050
|
+
try {
|
|
31051
|
+
const parent = await stat(parentPath);
|
|
31052
|
+
if (!parent.isDirectory()) {
|
|
31053
|
+
throw new Error(
|
|
31054
|
+
`Cannot write snapshot at ${snapshotPath}: parent path ${parentPath} is not a directory`
|
|
30114
31055
|
);
|
|
30115
31056
|
}
|
|
30116
|
-
|
|
30117
|
-
|
|
30118
|
-
|
|
31057
|
+
} catch (error) {
|
|
31058
|
+
if (hasErrorCode(error, "ENOENT")) {
|
|
31059
|
+
throw new Error(
|
|
31060
|
+
`Cannot write snapshot at ${snapshotPath}: parent directory ${parentPath} does not exist`,
|
|
31061
|
+
{
|
|
31062
|
+
cause: error
|
|
31063
|
+
}
|
|
31064
|
+
);
|
|
30119
31065
|
}
|
|
30120
|
-
|
|
31066
|
+
throw error;
|
|
30121
31067
|
}
|
|
30122
31068
|
}
|
|
30123
|
-
function
|
|
30124
|
-
|
|
30125
|
-
|
|
30126
|
-
|
|
30127
|
-
|
|
30128
|
-
|
|
30129
|
-
|
|
30130
|
-
|
|
31069
|
+
async function writeSnapshotOnce(temporaryPath, snapshotPath, contents) {
|
|
31070
|
+
let temporaryCreated = false;
|
|
31071
|
+
let renamed = false;
|
|
31072
|
+
try {
|
|
31073
|
+
try {
|
|
31074
|
+
await writeFile(temporaryPath, contents, { encoding: "utf8", flag: "wx" });
|
|
31075
|
+
temporaryCreated = true;
|
|
31076
|
+
} catch (error) {
|
|
31077
|
+
if (!hasErrorCode(error, "EEXIST")) {
|
|
31078
|
+
await removeTemporarySnapshot(temporaryPath).catch(() => void 0);
|
|
31079
|
+
}
|
|
31080
|
+
throw error;
|
|
31081
|
+
}
|
|
31082
|
+
await rename(temporaryPath, snapshotPath);
|
|
31083
|
+
renamed = true;
|
|
31084
|
+
} finally {
|
|
31085
|
+
if (temporaryCreated && !renamed) {
|
|
31086
|
+
await removeTemporarySnapshot(temporaryPath).catch(() => void 0);
|
|
31087
|
+
}
|
|
30131
31088
|
}
|
|
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
31089
|
}
|
|
30142
|
-
function
|
|
30143
|
-
|
|
30144
|
-
|
|
31090
|
+
async function enqueueOperation(path, operation) {
|
|
31091
|
+
const previous = pendingOperations.get(path) ?? Promise.resolve();
|
|
31092
|
+
const pending = previous.catch(() => void 0).then(operation);
|
|
31093
|
+
const queued = pending.catch(() => void 0);
|
|
31094
|
+
pendingOperations.set(path, queued);
|
|
31095
|
+
try {
|
|
31096
|
+
await pending;
|
|
31097
|
+
} finally {
|
|
31098
|
+
if (pendingOperations.get(path) === queued) {
|
|
31099
|
+
pendingOperations.delete(path);
|
|
31100
|
+
}
|
|
30145
31101
|
}
|
|
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
31102
|
}
|
|
30155
|
-
function
|
|
30156
|
-
|
|
30157
|
-
|
|
30158
|
-
|
|
30159
|
-
|
|
30160
|
-
|
|
30161
|
-
const policy = readHostOperationPolicy(value);
|
|
30162
|
-
if (policy !== void 0) {
|
|
30163
|
-
registerPendingHostCallPolicy({ moduleId, operation, policy });
|
|
30164
|
-
}
|
|
31103
|
+
async function removeTemporarySnapshot(temporaryPath) {
|
|
31104
|
+
try {
|
|
31105
|
+
await unlink(temporaryPath);
|
|
31106
|
+
} catch (error) {
|
|
31107
|
+
if (!hasErrorCode(error, "ENOENT")) {
|
|
31108
|
+
throw error;
|
|
30165
31109
|
}
|
|
30166
31110
|
}
|
|
30167
31111
|
}
|
|
30168
|
-
function
|
|
30169
|
-
|
|
30170
|
-
|
|
30171
|
-
|
|
30172
|
-
);
|
|
31112
|
+
async function delay(ms) {
|
|
31113
|
+
if (ms === 0) {
|
|
31114
|
+
return;
|
|
31115
|
+
}
|
|
31116
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
30173
31117
|
}
|
|
30174
|
-
function
|
|
30175
|
-
return
|
|
31118
|
+
function hasErrorCode(error, code) {
|
|
31119
|
+
return hasOwnErrorCode(error, code);
|
|
31120
|
+
}
|
|
31121
|
+
function isLockedFileError(error) {
|
|
31122
|
+
const code = getOwnErrorCode(error);
|
|
31123
|
+
return code !== void 0 && LOCKED_FILE_ERROR_CODES.has(code);
|
|
30176
31124
|
}
|
|
30177
31125
|
|
|
31126
|
+
// packages/safe-js/src/run.ts
|
|
31127
|
+
import { AsyncLocalStorage as AsyncLocalStorage7 } from "node:async_hooks";
|
|
31128
|
+
|
|
30178
31129
|
// packages/safe-js/src/snapshot/scheduler.ts
|
|
30179
31130
|
var DEFAULT_SNAPSHOT_INTERVAL_MS = 3e4;
|
|
30180
31131
|
function createSnapshotScheduler(options) {
|
|
@@ -30397,9 +31348,10 @@ var UnhandledRejectionError = class extends Error {
|
|
|
30397
31348
|
};
|
|
30398
31349
|
var DEFAULT_MAX_CALL_DEPTH = 1e3;
|
|
30399
31350
|
function run(source, options = {}) {
|
|
31351
|
+
if (options.extensions !== void 0) return runWithExtensions(source, options);
|
|
30400
31352
|
const lifecycle = {
|
|
30401
31353
|
hostCallbackDepth: 0,
|
|
30402
|
-
hostCallbackContext: new
|
|
31354
|
+
hostCallbackContext: new AsyncLocalStorage7()
|
|
30403
31355
|
};
|
|
30404
31356
|
const dumpController = createDumpController(lifecycle);
|
|
30405
31357
|
const promiseTracker = createSandboxPromiseRejectionTracker();
|
|
@@ -30465,32 +31417,7 @@ function run(source, options = {}) {
|
|
|
30465
31417
|
lifecycle
|
|
30466
31418
|
})
|
|
30467
31419
|
);
|
|
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
|
-
};
|
|
31420
|
+
const builtinBindings = createBuiltinBindings({ compileOwner: operation.owner, budget, hostCalls, sink: options.sink, random: random?.generator.next });
|
|
30494
31421
|
const importMeta = convertInitialInput(
|
|
30495
31422
|
() => deepCopyToSandbox(options.importMeta ?? {})
|
|
30496
31423
|
);
|
|
@@ -30952,6 +31879,7 @@ export {
|
|
|
30952
31879
|
parse,
|
|
30953
31880
|
parseModule,
|
|
30954
31881
|
hashSource,
|
|
31882
|
+
defineExtension,
|
|
30955
31883
|
noopOtelSink,
|
|
30956
31884
|
bindOtelSpan,
|
|
30957
31885
|
activateOtelSpan,
|
|
@@ -30980,10 +31908,11 @@ export {
|
|
|
30980
31908
|
validateSnapshotMigration,
|
|
30981
31909
|
restore,
|
|
30982
31910
|
lint,
|
|
30983
|
-
|
|
31911
|
+
declareHostOperation,
|
|
30984
31912
|
createSeededRandom,
|
|
31913
|
+
runResources,
|
|
30985
31914
|
createReplayableRandom,
|
|
30986
|
-
|
|
31915
|
+
createRealm,
|
|
30987
31916
|
dump,
|
|
30988
31917
|
dumpCurrent,
|
|
30989
31918
|
getOwnErrorCode,
|
|
@@ -30991,4 +31920,4 @@ export {
|
|
|
30991
31920
|
FileSnapshotBackend,
|
|
30992
31921
|
run
|
|
30993
31922
|
};
|
|
30994
|
-
//# sourceMappingURL=chunk-
|
|
31923
|
+
//# sourceMappingURL=chunk-2M6MNQBY.js.map
|