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