@poe-platform/safe-js 0.1.721 → 0.1.722
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 +36 -6
- package/dist/config-mutations/types.d.ts +3 -1
- package/dist/safe-js/chunks/{chunk-B4M6QVUV.js → chunk-3QQYJ4RQ.js} +3 -2
- package/dist/safe-js/chunks/chunk-3QQYJ4RQ.js.map +7 -0
- package/dist/safe-js/chunks/{chunk-BHYBD6SY.js → chunk-55RIIUGG.js} +23 -7
- package/dist/safe-js/chunks/chunk-55RIIUGG.js.map +7 -0
- package/dist/safe-js/chunks/{chunk-A4L72WXV.js → chunk-7SBQ7WTV.js} +10 -11
- package/dist/safe-js/chunks/chunk-7SBQ7WTV.js.map +7 -0
- package/dist/safe-js/chunks/{chunk-DNA7BMBY.js → chunk-BNIEPGDU.js} +8520 -7312
- package/dist/safe-js/chunks/{chunk-DNA7BMBY.js.map → chunk-BNIEPGDU.js.map} +4 -4
- package/dist/safe-js/chunks/{chunk-HYD4K4HN.js → chunk-D3GC5QPZ.js} +63 -1
- package/dist/safe-js/chunks/chunk-D3GC5QPZ.js.map +7 -0
- package/dist/safe-js/chunks/{chunk-Q7B6JIMI.js → chunk-EH5A2EQI.js} +404 -117
- package/dist/safe-js/chunks/chunk-EH5A2EQI.js.map +7 -0
- package/dist/safe-js/chunks/{chunk-4CX3HYRY.js → chunk-FA5CQO6V.js} +2 -2
- package/dist/safe-js/chunks/{chunk-LPBTSTDG.js → chunk-GCOLKRMY.js} +4 -4
- package/dist/safe-js/chunks/{chunk-GMPZBMPA.js → chunk-K3ZRBAG5.js} +3 -3
- package/dist/safe-js/chunks/{chunk-JNLY7IMV.js → chunk-QL2ALAE6.js} +4 -4
- package/dist/safe-js/chunks/{chunk-ILYJBA2D.js → chunk-RYVHEOHM.js} +1109 -100
- package/dist/safe-js/chunks/chunk-RYVHEOHM.js.map +7 -0
- package/dist/safe-js/chunks/{chunk-BEXRQET4.js → chunk-S2GFVXSI.js} +3 -3
- package/dist/safe-js/chunks/{chunk-Y4LNCDCP.js → chunk-WF7HYDJ4.js} +4 -5
- package/dist/safe-js/chunks/{chunk-Y4LNCDCP.js.map → chunk-WF7HYDJ4.js.map} +2 -2
- package/dist/safe-js/chunks/{chunk-IS7YUCOF.js → chunk-XHSOM5CG.js} +2 -2
- package/dist/safe-js/chunks/{cli-runtime-YK2WE33M.js → cli-runtime-6QPGM3TX.js} +14 -14
- package/dist/safe-js/chunks/{dump-ATWBOZWV.js → dump-TU6SYRFD.js} +4 -4
- package/dist/safe-js/chunks/{fs-D72Y52I5.js → fs-HTZT32MQ.js} +4 -4
- package/dist/safe-js/chunks/harness-RYAMI444.js +10 -0
- package/dist/safe-js/chunks/mcp-DO2IRFGQ.js +11 -0
- package/dist/safe-js/chunks/migration-file-K7UH5ZG6.js +12 -0
- package/dist/safe-js/chunks/restore-7LRP4BM3.js +13 -0
- package/dist/safe-js/chunks/run-6SETM7SV.js +17 -0
- package/dist/safe-js/chunks/runtime-modules-MCQS2SHQ.js +10 -0
- package/dist/safe-js/cli.js +2 -2
- package/dist/safe-js/core.js +7 -7
- package/dist/safe-js/index.js +14 -14
- package/dist/safe-js/interp/async.d.ts +4 -1
- package/dist/safe-js/interp/budget.d.ts +12 -6
- package/dist/safe-js/interp/collection-iterator.d.ts +1 -1
- package/dist/safe-js/interp/host-bridge.d.ts +1 -0
- package/dist/safe-js/interp/host-capabilities.d.ts +13 -4
- package/dist/safe-js/interp/interpreter.d.ts +5 -1
- package/dist/safe-js/interp/intl-numberformat.d.ts +2 -2
- package/dist/safe-js/interp/jobs.d.ts +8 -0
- package/dist/safe-js/interp/scope.d.ts +9 -2
- package/dist/safe-js/interp/typed-array.d.ts +2 -2
- package/dist/safe-js/interp/values.d.ts +1 -0
- package/dist/safe-js/modules/registry.d.ts +4 -1
- package/dist/safe-js/modules/source-graph.d.ts +19 -1
- package/dist/safe-js/parse/compact-spans.d.ts +18 -0
- package/dist/safe-js/parse/dynamic-source.d.ts +3 -1
- package/dist/safe-js/parse/function-source.d.ts +1 -1
- package/dist/safe-js/parse/parser.d.ts +8 -3
- package/dist/safe-js/parse/tokenizer.d.ts +4 -0
- package/dist/safe-js/realm.d.ts +16 -3
- package/dist/safe-js/restore.d.ts +1 -0
- package/dist/safe-js/run.d.ts +10 -0
- package/package.json +2 -2
- package/dist/safe-js/chunks/chunk-A4L72WXV.js.map +0 -7
- package/dist/safe-js/chunks/chunk-B4M6QVUV.js.map +0 -7
- package/dist/safe-js/chunks/chunk-BHYBD6SY.js.map +0 -7
- package/dist/safe-js/chunks/chunk-HYD4K4HN.js.map +0 -7
- package/dist/safe-js/chunks/chunk-ILYJBA2D.js.map +0 -7
- package/dist/safe-js/chunks/chunk-Q7B6JIMI.js.map +0 -7
- package/dist/safe-js/chunks/harness-LUYCGWHZ.js +0 -10
- package/dist/safe-js/chunks/mcp-IWKZB2R2.js +0 -11
- package/dist/safe-js/chunks/migration-file-IXO5MLP4.js +0 -12
- package/dist/safe-js/chunks/restore-SI7HOC6C.js +0 -13
- package/dist/safe-js/chunks/run-SHI2PYR6.js +0 -17
- package/dist/safe-js/chunks/runtime-modules-OO72HTVF.js +0 -10
- /package/dist/safe-js/chunks/{chunk-4CX3HYRY.js.map → chunk-FA5CQO6V.js.map} +0 -0
- /package/dist/safe-js/chunks/{chunk-LPBTSTDG.js.map → chunk-GCOLKRMY.js.map} +0 -0
- /package/dist/safe-js/chunks/{chunk-GMPZBMPA.js.map → chunk-K3ZRBAG5.js.map} +0 -0
- /package/dist/safe-js/chunks/{chunk-JNLY7IMV.js.map → chunk-QL2ALAE6.js.map} +0 -0
- /package/dist/safe-js/chunks/{chunk-BEXRQET4.js.map → chunk-S2GFVXSI.js.map} +0 -0
- /package/dist/safe-js/chunks/{chunk-IS7YUCOF.js.map → chunk-XHSOM5CG.js.map} +0 -0
- /package/dist/safe-js/chunks/{cli-runtime-YK2WE33M.js.map → cli-runtime-6QPGM3TX.js.map} +0 -0
- /package/dist/safe-js/chunks/{dump-ATWBOZWV.js.map → dump-TU6SYRFD.js.map} +0 -0
- /package/dist/safe-js/chunks/{fs-D72Y52I5.js.map → fs-HTZT32MQ.js.map} +0 -0
- /package/dist/safe-js/chunks/{harness-LUYCGWHZ.js.map → harness-RYAMI444.js.map} +0 -0
- /package/dist/safe-js/chunks/{mcp-IWKZB2R2.js.map → mcp-DO2IRFGQ.js.map} +0 -0
- /package/dist/safe-js/chunks/{migration-file-IXO5MLP4.js.map → migration-file-K7UH5ZG6.js.map} +0 -0
- /package/dist/safe-js/chunks/{restore-SI7HOC6C.js.map → restore-7LRP4BM3.js.map} +0 -0
- /package/dist/safe-js/chunks/{run-SHI2PYR6.js.map → run-6SETM7SV.js.map} +0 -0
- /package/dist/safe-js/chunks/{runtime-modules-OO72HTVF.js.map → runtime-modules-MCQS2SHQ.js.map} +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
restore
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-7SBQ7WTV.js";
|
|
4
4
|
import {
|
|
5
5
|
attachDumpController,
|
|
6
6
|
createDumpController
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-S2GFVXSI.js";
|
|
8
8
|
import {
|
|
9
9
|
getOwnErrorCode,
|
|
10
10
|
hasOwnErrorCode
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
hashParsedAst,
|
|
14
14
|
hashSource
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-K3ZRBAG5.js";
|
|
16
16
|
import {
|
|
17
17
|
DUMP_FORMAT_VERSION,
|
|
18
18
|
EXECUTION_SEMANTICS,
|
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
createEvalSource,
|
|
37
37
|
createGuestReference,
|
|
38
38
|
createHostCallbackContext,
|
|
39
|
+
createImmutableEmptyModuleEnvironment,
|
|
39
40
|
createLiveHostObject,
|
|
40
41
|
createModuleEnvironment,
|
|
41
42
|
createModuleNamespace,
|
|
@@ -48,6 +49,7 @@ import {
|
|
|
48
49
|
decodeReplayData,
|
|
49
50
|
deepCopyFromSandbox,
|
|
50
51
|
deepCopyToSandbox,
|
|
52
|
+
denyGuestStringCompilation,
|
|
51
53
|
encodeReplayData,
|
|
52
54
|
enterRunningState,
|
|
53
55
|
enterSnapshotRun,
|
|
@@ -55,6 +57,7 @@ import {
|
|
|
55
57
|
getExtensionSetup,
|
|
56
58
|
getRealmGlobalObject,
|
|
57
59
|
guestProxyStates,
|
|
60
|
+
hostObjectGuestRoot,
|
|
58
61
|
inMemoryRunSnapshots,
|
|
59
62
|
interpret,
|
|
60
63
|
invokeBuiltinClosure,
|
|
@@ -97,7 +100,7 @@ import {
|
|
|
97
100
|
withSandboxPromiseRejectionTracker,
|
|
98
101
|
wrapCallerInjectedBindings,
|
|
99
102
|
wrapCancelableBindings
|
|
100
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-BNIEPGDU.js";
|
|
101
104
|
import {
|
|
102
105
|
Budget,
|
|
103
106
|
CompileScope,
|
|
@@ -112,20 +115,21 @@ import {
|
|
|
112
115
|
parseSourceModule,
|
|
113
116
|
replaceErrorStack,
|
|
114
117
|
safeAddEvent
|
|
115
|
-
} from "./chunk-
|
|
118
|
+
} from "./chunk-RYVHEOHM.js";
|
|
116
119
|
|
|
117
120
|
// packages/safe-js/src/realm.ts
|
|
118
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
121
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
119
122
|
import { types } from "node:util";
|
|
120
123
|
|
|
121
124
|
// packages/safe-js/src/modules/source-graph.ts
|
|
125
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
122
126
|
var ambiguous = /* @__PURE__ */ Symbol("ambiguous module export");
|
|
123
127
|
var sourceRecords = /* @__PURE__ */ new WeakSet();
|
|
124
128
|
var SourceModuleGraph = class {
|
|
125
129
|
constructor(options) {
|
|
126
130
|
this.options = options;
|
|
127
131
|
this.jobs = options.jobs ?? new SandboxJobQueue();
|
|
128
|
-
attachSourceLoader(options.modules, this.import.bind(this));
|
|
132
|
+
attachSourceLoader(options.modules, this.import.bind(this), { preserveImmutableNamespaces: true });
|
|
129
133
|
options.budget?.setRetainedValues(this, () => [...this.records.values()].flatMap((record) => [record.id, record.source, ...record.parsed.requests, ...record.scope.retainedDataRoots()]));
|
|
130
134
|
}
|
|
131
135
|
options;
|
|
@@ -133,60 +137,169 @@ var SourceModuleGraph = class {
|
|
|
133
137
|
records = /* @__PURE__ */ new Map();
|
|
134
138
|
requests = /* @__PURE__ */ new Map();
|
|
135
139
|
requestDataSize = 0;
|
|
140
|
+
lookupDataSize = 0;
|
|
136
141
|
pendingImports = /* @__PURE__ */ new Set();
|
|
142
|
+
fulfilledImports = 0;
|
|
143
|
+
rejectedImports = 0;
|
|
144
|
+
importGroup = new AsyncLocalStorage();
|
|
137
145
|
jobs;
|
|
138
146
|
evaluationStack = [];
|
|
139
147
|
evaluationIndex = 0;
|
|
140
148
|
close() {
|
|
141
149
|
this.options.budget?.setRetainedValues(this, void 0);
|
|
142
150
|
this.options.budget?.setRetainedDataUsage(this.requests, 0);
|
|
151
|
+
for (const record of this.records.values()) {
|
|
152
|
+
record.explicitExports.clear();
|
|
153
|
+
record.localImports.clear();
|
|
154
|
+
record.starExports.length = 0;
|
|
155
|
+
}
|
|
156
|
+
this.options.budget?.setRetainedDataUsage(this.records, 0);
|
|
157
|
+
this.lookupDataSize = 0;
|
|
143
158
|
this.requestDataSize = 0;
|
|
144
159
|
this.records.clear();
|
|
145
160
|
this.requests.clear();
|
|
146
161
|
}
|
|
162
|
+
sourceModuleStatus() {
|
|
163
|
+
return Object.freeze({
|
|
164
|
+
pendingImports: this.pendingImports.size,
|
|
165
|
+
preparedModules: this.records.size,
|
|
166
|
+
fulfilledImports: this.fulfilledImports,
|
|
167
|
+
rejectedImports: this.rejectedImports
|
|
168
|
+
});
|
|
169
|
+
}
|
|
147
170
|
import(specifier, referrer) {
|
|
171
|
+
const group = this.importGroup.getStore();
|
|
172
|
+
const cancelDeadline = this.startImportDeadline();
|
|
148
173
|
const pending = (async () => {
|
|
149
174
|
const entry = await this.load(specifier, referrer);
|
|
150
175
|
if (!isRecord(entry)) return entry;
|
|
151
176
|
await this.loadGraph(entry);
|
|
152
|
-
await this.link(entry);
|
|
177
|
+
if (this.options.serializePreparation) await this.jobs.run(() => this.link(entry));
|
|
178
|
+
else await this.link(entry);
|
|
153
179
|
await this.evaluate(entry);
|
|
154
180
|
await this.jobs.drain();
|
|
155
181
|
return this.namespace(entry);
|
|
156
182
|
})();
|
|
157
183
|
this.pendingImports.add(pending);
|
|
158
|
-
|
|
184
|
+
group?.add(pending);
|
|
185
|
+
const release = () => {
|
|
186
|
+
cancelDeadline();
|
|
187
|
+
this.pendingImports.delete(pending);
|
|
188
|
+
group?.delete(pending);
|
|
189
|
+
};
|
|
190
|
+
void pending.then(
|
|
191
|
+
() => {
|
|
192
|
+
this.fulfilledImports++;
|
|
193
|
+
release();
|
|
194
|
+
},
|
|
195
|
+
() => {
|
|
196
|
+
this.rejectedImports++;
|
|
197
|
+
release();
|
|
198
|
+
}
|
|
199
|
+
);
|
|
159
200
|
return pending;
|
|
160
201
|
}
|
|
161
|
-
|
|
202
|
+
startImportDeadline() {
|
|
203
|
+
const policy = this.options.importDeadline;
|
|
204
|
+
const signal = this.options.signal;
|
|
205
|
+
if (policy === void 0 || signal?.aborted) return () => {
|
|
206
|
+
};
|
|
207
|
+
const deadline = Date.now() + policy.timeoutMs;
|
|
208
|
+
let expired = false;
|
|
209
|
+
const expire = (reason) => {
|
|
210
|
+
if (expired) return;
|
|
211
|
+
expired = true;
|
|
212
|
+
cancel();
|
|
213
|
+
policy.abort(reason);
|
|
214
|
+
};
|
|
215
|
+
const releaseDeadline = this.options.budget?.acquireDeadline(deadline, expire);
|
|
216
|
+
const timer = setTimeout(() => {
|
|
217
|
+
expire(new SandboxError({
|
|
218
|
+
budget: "deadline",
|
|
219
|
+
current: Date.now(),
|
|
220
|
+
limit: deadline
|
|
221
|
+
}));
|
|
222
|
+
}, policy.timeoutMs);
|
|
223
|
+
const cancel = () => {
|
|
224
|
+
clearTimeout(timer);
|
|
225
|
+
releaseDeadline?.();
|
|
226
|
+
signal?.removeEventListener("abort", cancel);
|
|
227
|
+
};
|
|
228
|
+
signal?.addEventListener("abort", cancel, { once: true });
|
|
229
|
+
return cancel;
|
|
230
|
+
}
|
|
231
|
+
withoutImportGroup(task) {
|
|
232
|
+
return this.importGroup.exit(task);
|
|
233
|
+
}
|
|
234
|
+
withImportGroup(task) {
|
|
235
|
+
const group = /* @__PURE__ */ new Set();
|
|
236
|
+
return this.importGroup.run(group, async () => {
|
|
237
|
+
const result = await task();
|
|
238
|
+
await this.settle(group);
|
|
239
|
+
return result;
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
async settle(pendingImports = this.pendingImports) {
|
|
162
243
|
do {
|
|
163
|
-
await Promise.allSettled([...
|
|
244
|
+
await Promise.allSettled([...pendingImports]);
|
|
164
245
|
await this.jobs.drain();
|
|
165
|
-
} while (
|
|
246
|
+
} while (pendingImports.size > 0);
|
|
166
247
|
}
|
|
167
248
|
async evaluateSource(source, beforeEvaluation) {
|
|
168
|
-
const entry = this.register(source);
|
|
249
|
+
const entry = this.options.serializePreparation ? await this.jobs.run(() => this.register(source)) : this.register(source);
|
|
169
250
|
await this.loadGraph(entry);
|
|
170
|
-
await this.link(entry);
|
|
251
|
+
if (this.options.serializePreparation) await this.jobs.run(() => this.link(entry));
|
|
252
|
+
else await this.link(entry);
|
|
171
253
|
beforeEvaluation?.(entry.parsed.module);
|
|
172
254
|
await this.evaluate(entry);
|
|
173
255
|
await this.jobs.drain();
|
|
174
256
|
return this.namespace(entry);
|
|
175
257
|
}
|
|
176
258
|
register(source) {
|
|
259
|
+
this.options.assertActive?.();
|
|
260
|
+
this.options.signal?.throwIfAborted();
|
|
177
261
|
const known = this.records.get(source.id);
|
|
178
262
|
if (known !== void 0) {
|
|
179
263
|
if (known.source !== source.source) throw new TypeError(`Source identity '${source.id}' changed within the graph.`);
|
|
180
264
|
return known;
|
|
181
265
|
}
|
|
182
266
|
this.options.budget?.chargeDataUsage(source.source.length + source.id.length + 1);
|
|
183
|
-
const parsed = parseSourceModule(source.source, source.id, this.options.compilation?.owner ?? this.options.compileOwner);
|
|
267
|
+
const parsed = parseSourceModule(source.source, source.id, this.options.compilation?.owner ?? this.options.compileOwner, { sharedPositions: true, compactAst: true });
|
|
268
|
+
const explicitExports = /* @__PURE__ */ new Map();
|
|
269
|
+
const localImports = /* @__PURE__ */ new Map();
|
|
270
|
+
const starExports = [];
|
|
271
|
+
for (const entry of parsed.exports) {
|
|
272
|
+
this.options.budget?.visitNode();
|
|
273
|
+
if (entry.exported === void 0) {
|
|
274
|
+
const lookupDataSize = this.lookupDataSize + 1;
|
|
275
|
+
this.options.budget?.setRetainedDataUsage(this.records, lookupDataSize);
|
|
276
|
+
this.lookupDataSize = lookupDataSize;
|
|
277
|
+
starExports.push(entry);
|
|
278
|
+
} else if (!explicitExports.has(entry.exported)) {
|
|
279
|
+
const lookupDataSize = this.lookupDataSize + entry.exported.length + 2;
|
|
280
|
+
this.options.budget?.setRetainedDataUsage(this.records, lookupDataSize);
|
|
281
|
+
this.lookupDataSize = lookupDataSize;
|
|
282
|
+
explicitExports.set(entry.exported, entry);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
for (const entry of parsed.imports) {
|
|
286
|
+
this.options.budget?.visitNode();
|
|
287
|
+
if (!localImports.has(entry.local)) {
|
|
288
|
+
const lookupDataSize = this.lookupDataSize + entry.local.length + 2;
|
|
289
|
+
this.options.budget?.setRetainedDataUsage(this.records, lookupDataSize);
|
|
290
|
+
this.lookupDataSize = lookupDataSize;
|
|
291
|
+
localImports.set(entry.local, entry);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
184
294
|
const importMeta = /* @__PURE__ */ Object.create(null);
|
|
185
295
|
setSandboxPrototype(importMeta, null);
|
|
186
296
|
const record = {
|
|
187
297
|
id: source.id,
|
|
188
298
|
source: source.source,
|
|
189
299
|
parsed,
|
|
300
|
+
explicitExports,
|
|
301
|
+
localImports,
|
|
302
|
+
starExports,
|
|
190
303
|
scope: new Scope({ this: void 0 }, this.options.scope, importMeta, { functionBoundary: true }),
|
|
191
304
|
dependencies: /* @__PURE__ */ new Map()
|
|
192
305
|
};
|
|
@@ -212,7 +325,7 @@ var SourceModuleGraph = class {
|
|
|
212
325
|
if (source === void 0) throw new TypeError(`Source resolver denied '${specifier}' from '${referrer}'.`);
|
|
213
326
|
if (typeof source.id !== "string" || source.id.length === 0 || typeof source.source !== "string")
|
|
214
327
|
throw new TypeError("Source resolver must supply a nonempty identity and source text.");
|
|
215
|
-
return this.register(source);
|
|
328
|
+
return this.options.serializePreparation ? this.jobs.run(() => this.register(source)) : this.register(source);
|
|
216
329
|
})();
|
|
217
330
|
this.requests.set(key, request);
|
|
218
331
|
return request;
|
|
@@ -322,24 +435,17 @@ var SourceModuleGraph = class {
|
|
|
322
435
|
const leave = this.options.budget?.enterCall();
|
|
323
436
|
try {
|
|
324
437
|
visited.add(key);
|
|
325
|
-
const explicit = record.
|
|
326
|
-
this.options.budget?.visitNode();
|
|
327
|
-
return entry.exported === name;
|
|
328
|
-
});
|
|
438
|
+
const explicit = record.explicitExports.get(name);
|
|
329
439
|
if (explicit?.local !== void 0) {
|
|
330
|
-
const imported = record.
|
|
331
|
-
this.options.budget?.visitNode();
|
|
332
|
-
return entry.local === explicit.local;
|
|
333
|
-
});
|
|
440
|
+
const imported = record.localImports.get(explicit.local);
|
|
334
441
|
if (imported === void 0 || imported.namespace === true) return { record, name: explicit.local };
|
|
335
442
|
return this.resolveDependency(record, imported.request, imported.imported, visited);
|
|
336
443
|
}
|
|
337
444
|
if (explicit?.request !== void 0) return this.resolveDependency(record, explicit.request, explicit.imported, visited, explicit.namespace);
|
|
338
445
|
if (name === "default") return void 0;
|
|
339
446
|
let resolved;
|
|
340
|
-
for (const entry of record.
|
|
447
|
+
for (const entry of record.starExports) {
|
|
341
448
|
this.options.budget?.visitNode();
|
|
342
|
-
if (entry.exported !== void 0) continue;
|
|
343
449
|
const candidate = this.resolveDependency(record, entry.request, name, visited);
|
|
344
450
|
if (candidate === ambiguous) return ambiguous;
|
|
345
451
|
if (candidate === void 0) continue;
|
|
@@ -466,7 +572,7 @@ var SourceModuleGraph = class {
|
|
|
466
572
|
async execute(record, modulePhase, onSuspend) {
|
|
467
573
|
const result = await interpret(
|
|
468
574
|
{ type: "BlockStatement", body: record.parsed.module.body, span: record.parsed.module.span },
|
|
469
|
-
{ ...this.options, scope: record.scope, useScopeDirectly: true, jobs: this.jobs, nested: true, modulePhase, onSuspend }
|
|
575
|
+
{ ...this.options, scope: record.scope, useScopeDirectly: true, captureSnapshot: false, jobs: this.jobs, nested: true, modulePhase, onSuspend }
|
|
470
576
|
);
|
|
471
577
|
this.stats.nodeVisits += result.stats.nodeVisits;
|
|
472
578
|
if (!result.ok) throw new Error(result.error.message);
|
|
@@ -495,6 +601,10 @@ function createReplayableRandom(options = {}) {
|
|
|
495
601
|
}
|
|
496
602
|
|
|
497
603
|
// packages/safe-js/src/realm.ts
|
|
604
|
+
var retainedArrayPrototype = Array.prototype;
|
|
605
|
+
var nativeRetainedArrayPrototype = Object.setPrototypeOf;
|
|
606
|
+
var nativeRetainedArrayAppend = Function.prototype.call.bind(Array.prototype.push);
|
|
607
|
+
var freezeSourceReference = Object.freeze;
|
|
498
608
|
var RealmState = class {
|
|
499
609
|
constructor(options, queue = new SandboxJobQueue()) {
|
|
500
610
|
this.options = options;
|
|
@@ -622,7 +732,7 @@ var RealmState = class {
|
|
|
622
732
|
lease;
|
|
623
733
|
compilation;
|
|
624
734
|
controller = new AbortController();
|
|
625
|
-
phase = new
|
|
735
|
+
phase = new AsyncLocalStorage2();
|
|
626
736
|
queue;
|
|
627
737
|
tracker = createSandboxPromiseRejectionTracker();
|
|
628
738
|
bridge;
|
|
@@ -634,6 +744,8 @@ var RealmState = class {
|
|
|
634
744
|
resources;
|
|
635
745
|
callbacks = /* @__PURE__ */ new Map();
|
|
636
746
|
pendingCallbacks = /* @__PURE__ */ new Set();
|
|
747
|
+
pendingWork = /* @__PURE__ */ new Set();
|
|
748
|
+
releaseReconciliation;
|
|
637
749
|
callbackCache = /* @__PURE__ */ new WeakMap();
|
|
638
750
|
hostObjects = /* @__PURE__ */ new Set();
|
|
639
751
|
guestReferences = /* @__PURE__ */ new Map();
|
|
@@ -659,11 +771,17 @@ var RealmState = class {
|
|
|
659
771
|
signal: this.controller.signal,
|
|
660
772
|
realm: this.bridge
|
|
661
773
|
});
|
|
662
|
-
retainedRoots = () =>
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
774
|
+
retainedRoots = () => {
|
|
775
|
+
const roots = nativeRetainedArrayPrototype([], null);
|
|
776
|
+
for (const object of this.hostObjects) {
|
|
777
|
+
const root = hostObjectGuestRoot(object);
|
|
778
|
+
if (root !== void 0) nativeRetainedArrayAppend(roots, root);
|
|
779
|
+
}
|
|
780
|
+
for (const closure of this.callbacks.values()) nativeRetainedArrayAppend(roots, closure);
|
|
781
|
+
for (const pending of this.pendingCallbacks) nativeRetainedArrayAppend(roots, pending.closure);
|
|
782
|
+
for (const reference of this.guestReferences.values()) nativeRetainedArrayAppend(roots, reference);
|
|
783
|
+
return nativeRetainedArrayPrototype(roots, retainedArrayPrototype);
|
|
784
|
+
};
|
|
667
785
|
captureArguments = (operation, args, copy) => {
|
|
668
786
|
const from = this.retainedOperations.get(operation)?.from ?? args.length;
|
|
669
787
|
const values = copy(args.slice(0, from));
|
|
@@ -760,6 +878,34 @@ var RealmState = class {
|
|
|
760
878
|
void this.dispose().catch(() => void 0);
|
|
761
879
|
});
|
|
762
880
|
}
|
|
881
|
+
trackWork(pending) {
|
|
882
|
+
this.pendingWork.add(pending);
|
|
883
|
+
void pending.then(
|
|
884
|
+
() => {
|
|
885
|
+
this.pendingWork.delete(pending);
|
|
886
|
+
},
|
|
887
|
+
() => {
|
|
888
|
+
this.pendingWork.delete(pending);
|
|
889
|
+
}
|
|
890
|
+
);
|
|
891
|
+
return pending;
|
|
892
|
+
}
|
|
893
|
+
reconcileWhenIdle() {
|
|
894
|
+
if (this.closed || this.active !== void 0 || this.pendingCallbacks.size > 0) return;
|
|
895
|
+
this.releaseReconciliation?.();
|
|
896
|
+
this.releaseReconciliation = void 0;
|
|
897
|
+
try {
|
|
898
|
+
reconcileCompiledValues(
|
|
899
|
+
this.budget,
|
|
900
|
+
[...this.scope?.retainedDataRoots() ?? [], ...this.retainedRoots()],
|
|
901
|
+
this.compilation
|
|
902
|
+
);
|
|
903
|
+
} catch (error) {
|
|
904
|
+
this.poison(error);
|
|
905
|
+
void this.dispose().catch(() => void 0);
|
|
906
|
+
throw error;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
763
909
|
chargeWork = (units = 1) => {
|
|
764
910
|
this.assertOpen();
|
|
765
911
|
if (!Number.isSafeInteger(units) || units < 0)
|
|
@@ -858,6 +1004,7 @@ var RealmState = class {
|
|
|
858
1004
|
owner: this,
|
|
859
1005
|
assertActive: this.assertOpen,
|
|
860
1006
|
chargeWork: this.chargeWork,
|
|
1007
|
+
chargeGuestData: (units) => this.budget.chargeDataUsage(units),
|
|
861
1008
|
checkLength: (length) => this.budget.allocateArrayLength(length),
|
|
862
1009
|
checkString: (value) => {
|
|
863
1010
|
this.budget.allocateString(value);
|
|
@@ -960,12 +1107,19 @@ var RealmState = class {
|
|
|
960
1107
|
};
|
|
961
1108
|
invokeCallback = this.executeCallback.bind(this);
|
|
962
1109
|
async executeCallback(callback, options = {}, completeSynchronous) {
|
|
963
|
-
if (this.closed || this.failure !== void 0)
|
|
1110
|
+
if ((this.closed || this.failure !== void 0) && this.options.callbackScheduling !== "after-prefix")
|
|
1111
|
+
await this.dispose();
|
|
964
1112
|
this.assertOpen();
|
|
965
1113
|
const closure = readGuestCallback(callback, this);
|
|
966
1114
|
this.checkCollection(this.pendingCallbacks.size + 1, this.limits.callbacks, "pending callback");
|
|
967
|
-
const
|
|
1115
|
+
const scheduled = this.options.callbackScheduling === "after-prefix";
|
|
1116
|
+
const record = {
|
|
1117
|
+
closure,
|
|
1118
|
+
prefixComplete: false
|
|
1119
|
+
};
|
|
968
1120
|
this.pendingCallbacks.add(record);
|
|
1121
|
+
if (scheduled) this.releaseReconciliation ??= this.budget.deferReconciliation();
|
|
1122
|
+
const rejectionOwner = scheduled ? this.tracker.startOperation() : void 0;
|
|
969
1123
|
const invoke = async () => {
|
|
970
1124
|
this.assertOpen();
|
|
971
1125
|
readGuestCallback(callback, this);
|
|
@@ -996,6 +1150,7 @@ var RealmState = class {
|
|
|
996
1150
|
if (isSandboxPromise(value) && value.synchronousPrefix !== void 0)
|
|
997
1151
|
await value.synchronousPrefix;
|
|
998
1152
|
this.assertOpen();
|
|
1153
|
+
record.prefixComplete = true;
|
|
999
1154
|
completeSynchronous?.();
|
|
1000
1155
|
const settled = await suspendJob(settlement);
|
|
1001
1156
|
return this.exportValue(settled);
|
|
@@ -1005,25 +1160,37 @@ var RealmState = class {
|
|
|
1005
1160
|
}
|
|
1006
1161
|
};
|
|
1007
1162
|
try {
|
|
1008
|
-
const active = this.active !== void 0;
|
|
1009
|
-
const
|
|
1010
|
-
|
|
1011
|
-
() =>
|
|
1012
|
-
this.
|
|
1013
|
-
() =>
|
|
1014
|
-
this.
|
|
1015
|
-
() =>
|
|
1163
|
+
const active = this.active !== void 0 || scheduled && this.phase.getStore()?.active === true;
|
|
1164
|
+
const execute = () => this.tracker.withOperation(
|
|
1165
|
+
rejectionOwner,
|
|
1166
|
+
() => withSandboxPromiseRejectionTracker(
|
|
1167
|
+
this.tracker,
|
|
1168
|
+
() => runResources.run(
|
|
1169
|
+
this.resources,
|
|
1170
|
+
() => withCancellationSignal(
|
|
1171
|
+
this.controller.signal,
|
|
1172
|
+
() => active && this.phase.getStore()?.active ? runAsyncPrefix(invoke, completeSynchronous === void 0 && this.phase.getStore()?.extension !== void 0) : this.queue.run(invoke)
|
|
1173
|
+
)
|
|
1016
1174
|
)
|
|
1017
1175
|
)
|
|
1018
1176
|
);
|
|
1019
|
-
|
|
1020
|
-
|
|
1177
|
+
const pending = scheduled && this.sourceGraph !== void 0 ? this.sourceGraph.withoutImportGroup(execute) : execute();
|
|
1178
|
+
record.promise = scheduled ? this.trackWork(pending) : active ? pending : this.perform(() => pending);
|
|
1179
|
+
const result = await record.promise;
|
|
1180
|
+
if (scheduled) {
|
|
1181
|
+
await this.checkUnhandledRejection(rejectionOwner);
|
|
1182
|
+
this.assertOpen();
|
|
1183
|
+
}
|
|
1184
|
+
return result;
|
|
1021
1185
|
} catch (error) {
|
|
1022
|
-
if (error instanceof SandboxError) this.poison(error);
|
|
1186
|
+
if (scheduled || error instanceof SandboxError) this.poison(error);
|
|
1187
|
+
if (scheduled) void this.dispose().catch(() => void 0);
|
|
1023
1188
|
throw error;
|
|
1024
1189
|
} finally {
|
|
1190
|
+
this.tracker.finishOperation(rejectionOwner);
|
|
1025
1191
|
this.pendingCallbacks.delete(record);
|
|
1026
|
-
if (
|
|
1192
|
+
if (scheduled) this.reconcileWhenIdle();
|
|
1193
|
+
else if (!this.closed && this.active === void 0)
|
|
1027
1194
|
reconcileCompiledValues(
|
|
1028
1195
|
this.budget,
|
|
1029
1196
|
[...this.scope?.retainedDataRoots() ?? [], ...this.retainedRoots()],
|
|
@@ -1138,37 +1305,83 @@ var RealmState = class {
|
|
|
1138
1305
|
);
|
|
1139
1306
|
if (this.options.classicScripts)
|
|
1140
1307
|
this.scope.declare("this", "const", getRealmGlobalObject(this.budget));
|
|
1308
|
+
if (this.options.stringCompilation === "deny") denyGuestStringCompilation(this.scope);
|
|
1309
|
+
}
|
|
1310
|
+
sourceModuleStatus = () => {
|
|
1311
|
+
this.assertOpen();
|
|
1312
|
+
return this.sourceGraph?.sourceModuleStatus() ?? Object.freeze({
|
|
1313
|
+
pendingImports: 0,
|
|
1314
|
+
preparedModules: 0,
|
|
1315
|
+
fulfilledImports: 0,
|
|
1316
|
+
rejectedImports: 0
|
|
1317
|
+
});
|
|
1318
|
+
};
|
|
1319
|
+
ensureSourceGraph() {
|
|
1320
|
+
this.assertOpen();
|
|
1321
|
+
this.initialize();
|
|
1322
|
+
if (this.sourceGraph !== void 0) return this.sourceGraph;
|
|
1323
|
+
const moduleOptions = { ...this.bridgeOptions(), wrappedModules: this.convertedModules };
|
|
1324
|
+
const modules = Object.keys(this.modules).length === 0 && this.convertedModules.size === 0 ? createImmutableEmptyModuleEnvironment(moduleOptions) : createModuleEnvironment(this.modules, moduleOptions);
|
|
1325
|
+
return this.sourceGraph ??= new SourceModuleGraph({
|
|
1326
|
+
resolver: this.options.sourceResolver ?? (() => void 0),
|
|
1327
|
+
scope: this.scope,
|
|
1328
|
+
modules,
|
|
1329
|
+
budget: this.budget,
|
|
1330
|
+
compilation: this.compilation,
|
|
1331
|
+
signal: this.controller.signal,
|
|
1332
|
+
jobs: this.queue,
|
|
1333
|
+
assertActive: this.assertOpen,
|
|
1334
|
+
surfaceUnhandledThrows: true,
|
|
1335
|
+
serializePreparation: this.options.callbackScheduling === "after-prefix",
|
|
1336
|
+
...this.options.sourceImportTimeoutMs === void 0 ? {} : {
|
|
1337
|
+
importDeadline: {
|
|
1338
|
+
timeoutMs: this.options.sourceImportTimeoutMs,
|
|
1339
|
+
abort: (reason) => {
|
|
1340
|
+
this.poison(reason);
|
|
1341
|
+
void this.close().catch(() => void 0);
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
});
|
|
1141
1346
|
}
|
|
1142
|
-
async evaluateRaw(source, filename = "<realm>", nested = false, sourceType) {
|
|
1347
|
+
async evaluateRaw(source, filename = "<realm>", nested = false, sourceType, reportUnhandledThrows = false) {
|
|
1143
1348
|
this.assertOpen();
|
|
1144
1349
|
if (typeof source !== "string") throw new TypeError("Realm source must be a string.");
|
|
1145
1350
|
if (sourceType === "module") {
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
return { ok: true, returnValue: namespace, snapshot: { bindings: {} }, stats: { nodeVisits: this.sourceGraph.stats.nodeVisits - before, currentDataSize: this.budget.currentDataSize, peakDataSize: this.budget.peakDataSize } };
|
|
1351
|
+
const prepare = () => {
|
|
1352
|
+
this.ensureSourceGraph();
|
|
1353
|
+
};
|
|
1354
|
+
const scheduled = this.options.callbackScheduling === "after-prefix";
|
|
1355
|
+
if (scheduled) await this.queue.run(prepare);
|
|
1356
|
+
else prepare();
|
|
1357
|
+
const graph = this.sourceGraph;
|
|
1358
|
+
const before = graph.stats.nodeVisits;
|
|
1359
|
+
const evaluate = async () => {
|
|
1360
|
+
const namespace2 = await graph.evaluateSource({ id: filename, source }, (module) => {
|
|
1361
|
+
this.sourceModuleHash = hashParsedAst(module);
|
|
1362
|
+
});
|
|
1363
|
+
if (!scheduled) await graph.settle();
|
|
1364
|
+
return namespace2;
|
|
1365
|
+
};
|
|
1366
|
+
const namespace = scheduled ? await graph.withImportGroup(evaluate) : await evaluate();
|
|
1367
|
+
return { ok: true, returnValue: namespace, snapshot: { bindings: {} }, stats: { nodeVisits: graph.stats.nodeVisits - before, currentDataSize: this.budget.currentDataSize, peakDataSize: this.budget.peakDataSize } };
|
|
1164
1368
|
}
|
|
1165
|
-
const script = this.options.classicScripts ? createEvalSource(source, {}, this.lease.owner, filename) : void 0;
|
|
1166
|
-
const
|
|
1369
|
+
const script = this.options.classicScripts ? createEvalSource(source, {}, this.lease.owner, filename, { compactAst: true }) : void 0;
|
|
1370
|
+
const sourceReference = script && this.options.sourceResolver !== void 0 ? freezeSourceReference({ referrer: filename }) : void 0;
|
|
1371
|
+
const releaseSource = script ? retainValues(this.budget, () => [script.source, sourceReference]) : void 0;
|
|
1167
1372
|
try {
|
|
1168
1373
|
if (script) this.budget.chargeDataUsage(measureSandboxData([script.source]));
|
|
1374
|
+
if (sourceReference) this.budget.chargeDataUsage(measureSandboxData([sourceReference]));
|
|
1169
1375
|
const module = script?.node ?? parseExecutableModule(source, filename, this.lease.owner);
|
|
1170
1376
|
this.initialize();
|
|
1171
|
-
const
|
|
1377
|
+
const moduleOptions = { ...this.bridgeOptions(), wrappedModules: this.convertedModules };
|
|
1378
|
+
const moduleEnvironment = script && Object.keys(this.modules).length === 0 && this.convertedModules.size === 0 ? createImmutableEmptyModuleEnvironment(moduleOptions) : createModuleEnvironment(this.modules, moduleOptions);
|
|
1379
|
+
if (sourceReference)
|
|
1380
|
+
attachSourceLoader(
|
|
1381
|
+
moduleEnvironment,
|
|
1382
|
+
(specifier, referrer) => this.ensureSourceGraph().import(specifier, referrer),
|
|
1383
|
+
{ preserveImmutableNamespaces: true }
|
|
1384
|
+
);
|
|
1172
1385
|
const imports = script ? {} : resolveModuleImports(module, this.modules, {
|
|
1173
1386
|
environment: moduleEnvironment,
|
|
1174
1387
|
...this.bridgeOptions(),
|
|
@@ -1188,12 +1401,14 @@ var RealmState = class {
|
|
|
1188
1401
|
},
|
|
1189
1402
|
{
|
|
1190
1403
|
...script ? { script: { strict: script.strict } } : {},
|
|
1404
|
+
sourceReference,
|
|
1191
1405
|
scope: this.scope,
|
|
1192
1406
|
useScopeDirectly: true,
|
|
1193
1407
|
budget: this.budget,
|
|
1194
1408
|
compilation: this.compilation,
|
|
1195
1409
|
signal: this.controller.signal,
|
|
1196
1410
|
surfaceUnhandledThrows: true,
|
|
1411
|
+
reportUnhandledThrows: script !== void 0 && reportUnhandledThrows,
|
|
1197
1412
|
jobs: this.queue,
|
|
1198
1413
|
nested,
|
|
1199
1414
|
assertActive: this.assertOpen
|
|
@@ -1208,7 +1423,7 @@ var RealmState = class {
|
|
|
1208
1423
|
evaluateNested = async (source, extension) => {
|
|
1209
1424
|
this.assertOpen();
|
|
1210
1425
|
const phase = this.phase.getStore();
|
|
1211
|
-
if (!phase?.active || phase.extension !== extension || phase.evaluating || this.active === void 0)
|
|
1426
|
+
if (!phase?.active || phase.extension !== extension || phase.evaluating || this.active === void 0 && !(this.options.callbackScheduling === "after-prefix" && this.pendingCallbacks.size > 0))
|
|
1212
1427
|
throw new SandboxError("reentry");
|
|
1213
1428
|
const leave = this.budget.enterCall();
|
|
1214
1429
|
phase.evaluating = true;
|
|
@@ -1231,39 +1446,65 @@ var RealmState = class {
|
|
|
1231
1446
|
}
|
|
1232
1447
|
};
|
|
1233
1448
|
evaluate = async (source, options = {}) => this.perform(async () => {
|
|
1234
|
-
const
|
|
1449
|
+
const discard = Object.getOwnPropertyDescriptor(options, "discardResult");
|
|
1450
|
+
if (discard && (!("value" in discard) || discard.value !== void 0 && typeof discard.value !== "boolean"))
|
|
1451
|
+
throw new TypeError("Realm evaluation discardResult must be an own-data boolean.");
|
|
1452
|
+
const scheduled = this.options.callbackScheduling === "after-prefix";
|
|
1453
|
+
const reportUnhandledThrows = options.sourceType !== "module" && this.options.classicScriptErrors === "report";
|
|
1454
|
+
const result = scheduled && options.sourceType !== "module" ? await this.queue.run(() => this.evaluateRaw(source, options.filename, true, void 0, reportUnhandledThrows)) : await this.evaluateRaw(source, options.filename, false, options.sourceType, reportUnhandledThrows);
|
|
1235
1455
|
if (!result.ok) {
|
|
1236
|
-
|
|
1237
|
-
|
|
1456
|
+
const recoverable = reportUnhandledThrows && result.error.code === "UNCAUGHT_EXCEPTION";
|
|
1457
|
+
if (!scheduled && !recoverable) await this.dispose();
|
|
1458
|
+
return { ok: false, error: result.error, stats: result.stats, ...recoverable ? { recoverable: true } : {} };
|
|
1238
1459
|
}
|
|
1239
|
-
return { ok: true, returnValue: this.exportValue(result.returnValue), stats: result.stats };
|
|
1240
|
-
});
|
|
1241
|
-
async
|
|
1242
|
-
|
|
1460
|
+
return { ok: true, ...discard?.value === true ? {} : { returnValue: this.exportValue(result.returnValue) }, stats: result.stats };
|
|
1461
|
+
}, (result) => !result.ok && !result.recoverable);
|
|
1462
|
+
async checkUnhandledRejection(owner) {
|
|
1463
|
+
const unhandled = await this.tracker.findUnhandledRejection(owner);
|
|
1464
|
+
if (unhandled !== void 0) {
|
|
1465
|
+
const error = new Error(
|
|
1466
|
+
`Unhandled guest promise rejection: ${describeThrownValue(unhandled.reason)}`
|
|
1467
|
+
);
|
|
1468
|
+
error.name = "UnhandledRejectionError";
|
|
1469
|
+
throw error;
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
async perform(task, failed) {
|
|
1473
|
+
if ((this.closed || this.failure !== void 0) && this.options.callbackScheduling !== "after-prefix")
|
|
1474
|
+
await this.dispose();
|
|
1243
1475
|
this.assertOpen();
|
|
1244
1476
|
if (this.active !== void 0) throw new SandboxError("reentry");
|
|
1477
|
+
const scheduled = this.options.callbackScheduling === "after-prefix";
|
|
1478
|
+
if (scheduled && (this.phase.getStore()?.active || [...this.pendingCallbacks].some((record) => !record.prefixComplete)))
|
|
1479
|
+
throw new SandboxError("reentry");
|
|
1480
|
+
const rejectionOwner = scheduled ? this.tracker.startOperation() : void 0;
|
|
1245
1481
|
const pending = Promise.resolve().then(
|
|
1246
|
-
() =>
|
|
1247
|
-
|
|
1248
|
-
() =>
|
|
1249
|
-
this.
|
|
1250
|
-
() =>
|
|
1482
|
+
() => this.tracker.withOperation(
|
|
1483
|
+
rejectionOwner,
|
|
1484
|
+
() => withSandboxPromiseRejectionTracker(
|
|
1485
|
+
this.tracker,
|
|
1486
|
+
() => runResources.run(
|
|
1487
|
+
this.resources,
|
|
1488
|
+
() => withCancellationSignal(this.controller.signal, task)
|
|
1489
|
+
)
|
|
1251
1490
|
)
|
|
1252
1491
|
)
|
|
1253
1492
|
);
|
|
1254
1493
|
this.active = pending;
|
|
1494
|
+
if (scheduled) this.trackWork(pending);
|
|
1255
1495
|
try {
|
|
1256
1496
|
const result = await pending;
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
);
|
|
1263
|
-
error.name = "UnhandledRejectionError";
|
|
1264
|
-
throw error;
|
|
1497
|
+
if (scheduled && failed?.(result)) {
|
|
1498
|
+
this.closed = true;
|
|
1499
|
+
this.controller.abort(new Error("SafeJS source evaluation failed."));
|
|
1500
|
+
await this.dispose();
|
|
1501
|
+
return result;
|
|
1265
1502
|
}
|
|
1503
|
+
if (scheduled) this.assertOpen();
|
|
1504
|
+
await this.queue.drain();
|
|
1505
|
+
await this.checkUnhandledRejection(rejectionOwner);
|
|
1266
1506
|
if (this.failure !== void 0) throw this.failure.reason;
|
|
1507
|
+
if (scheduled) this.assertOpen();
|
|
1267
1508
|
if (!this.closed)
|
|
1268
1509
|
reconcileCompiledValues(
|
|
1269
1510
|
this.budget,
|
|
@@ -1281,12 +1522,22 @@ var RealmState = class {
|
|
|
1281
1522
|
}
|
|
1282
1523
|
throw reason;
|
|
1283
1524
|
} finally {
|
|
1284
|
-
this.
|
|
1525
|
+
this.tracker.finishOperation(rejectionOwner);
|
|
1526
|
+
if (this.active === pending) this.active = void 0;
|
|
1527
|
+
if (scheduled) this.reconcileWhenIdle();
|
|
1285
1528
|
}
|
|
1286
1529
|
}
|
|
1287
1530
|
close = () => {
|
|
1288
1531
|
this.closed = true;
|
|
1289
1532
|
this.controller.abort(new Error("SafeJS realm is closed."));
|
|
1533
|
+
if (this.options.callbackScheduling === "after-prefix") {
|
|
1534
|
+
const disposal = this.dispose();
|
|
1535
|
+
if (this.phase.getStore()?.active) {
|
|
1536
|
+
void disposal.catch(() => void 0);
|
|
1537
|
+
return Promise.reject(new SandboxError("reentry"));
|
|
1538
|
+
}
|
|
1539
|
+
return disposal;
|
|
1540
|
+
}
|
|
1290
1541
|
if (this.phase.getStore()?.active) return this.dispose();
|
|
1291
1542
|
return Promise.allSettled([
|
|
1292
1543
|
this.active,
|
|
@@ -1298,6 +1549,21 @@ var RealmState = class {
|
|
|
1298
1549
|
this.closed = true;
|
|
1299
1550
|
this.controller.abort(new Error("SafeJS realm is closed."));
|
|
1300
1551
|
this.options.signal?.removeEventListener("abort", this.abort);
|
|
1552
|
+
if (this.options.callbackScheduling === "after-prefix") {
|
|
1553
|
+
this.disposal = Promise.resolve().then(async () => {
|
|
1554
|
+
while (this.pendingWork.size > 0) await Promise.allSettled([...this.pendingWork]);
|
|
1555
|
+
await this.sourceGraph?.settle();
|
|
1556
|
+
await this.queue.settle();
|
|
1557
|
+
this.releaseReconciliation?.();
|
|
1558
|
+
this.releaseReconciliation = void 0;
|
|
1559
|
+
await this.releaseResources();
|
|
1560
|
+
}).finally(() => this.queue.finish());
|
|
1561
|
+
return this.disposal;
|
|
1562
|
+
}
|
|
1563
|
+
this.disposal = this.releaseResources().finally(() => this.queue.finish());
|
|
1564
|
+
return this.disposal;
|
|
1565
|
+
}
|
|
1566
|
+
async releaseResources() {
|
|
1301
1567
|
for (const callback of this.callbacks.keys()) revokeGuestCallback(callback, this);
|
|
1302
1568
|
this.callbacks.clear();
|
|
1303
1569
|
for (const object of this.hostObjects) revokeHostObject(object, this);
|
|
@@ -1309,28 +1575,25 @@ var RealmState = class {
|
|
|
1309
1575
|
this.budget.setRetainedValues(this, void 0);
|
|
1310
1576
|
this.sourceGraph?.close();
|
|
1311
1577
|
releaseObjectPrototype(this.budget);
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
errors.push(error);
|
|
1319
|
-
}
|
|
1578
|
+
const errors = [];
|
|
1579
|
+
for (const cleanup of this.cleanups.splice(0).reverse()) {
|
|
1580
|
+
try {
|
|
1581
|
+
await cleanup();
|
|
1582
|
+
} catch (error) {
|
|
1583
|
+
errors.push(error);
|
|
1320
1584
|
}
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
this.
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
return this.disposal;
|
|
1585
|
+
}
|
|
1586
|
+
this.scope = void 0;
|
|
1587
|
+
this.convertedModules.clear();
|
|
1588
|
+
for (const key of Object.keys(this.globals)) delete this.globals[key];
|
|
1589
|
+
for (const key of Object.keys(this.modules)) delete this.modules[key];
|
|
1590
|
+
for (const key of Object.keys(this.builtinBindings))
|
|
1591
|
+
Reflect.deleteProperty(this.builtinBindings, key);
|
|
1592
|
+
this.nativeConversions.seen = /* @__PURE__ */ new WeakMap();
|
|
1593
|
+
reconcileCompiledValues(this.budget, [], this.compilation);
|
|
1594
|
+
this.compilation.dispose();
|
|
1595
|
+
this.lease.release();
|
|
1596
|
+
if (errors.length > 0) throw new AggregateError(errors, "Realm cleanup failed.");
|
|
1334
1597
|
}
|
|
1335
1598
|
};
|
|
1336
1599
|
function readModules(input) {
|
|
@@ -1359,12 +1622,17 @@ function assertNames(actual, expected, label) {
|
|
|
1359
1622
|
function createRealm(options = {}) {
|
|
1360
1623
|
const state = new RealmState(readRealmOptions(options));
|
|
1361
1624
|
return Object.freeze(attachExecutionControl({
|
|
1625
|
+
stringCompilation: state.options.stringCompilation ?? "allow",
|
|
1626
|
+
classicScriptErrors: state.options.classicScriptErrors ?? "fatal",
|
|
1627
|
+
supportsDiscardResult: true,
|
|
1628
|
+
sourceImportTimeoutMs: state.options.sourceImportTimeoutMs,
|
|
1362
1629
|
extensions: Object.freeze(state.extensions.map((extension) => extension.manifest)),
|
|
1363
1630
|
evaluate: state.evaluate,
|
|
1364
1631
|
startCallback: state.startCallback,
|
|
1365
1632
|
invokeCallback: state.invokeCallback,
|
|
1366
1633
|
releaseCallback: state.releaseCallback,
|
|
1367
1634
|
releaseGuestReference: state.releaseGuestReference,
|
|
1635
|
+
sourceModuleStatus: state.sourceModuleStatus,
|
|
1368
1636
|
close: state.close
|
|
1369
1637
|
}, state.queue));
|
|
1370
1638
|
}
|
|
@@ -1374,6 +1642,7 @@ async function runWithExtensions(source, options, jobs) {
|
|
|
1374
1642
|
"Live extension runs do not support snapshots or entryPointArgs; use a persistent realm."
|
|
1375
1643
|
);
|
|
1376
1644
|
const state = new RealmState(readRealmOptions(options, true), jobs);
|
|
1645
|
+
if (options.sourceLocation !== void 0) state.resources.sourceLocation = options.sourceLocation;
|
|
1377
1646
|
try {
|
|
1378
1647
|
const result = await state.perform(() => state.evaluateRaw(source, options.filename, false, options.sourceType));
|
|
1379
1648
|
if (result.ok && options.sourceType !== "module") encodeReplayData(result.returnValue);
|
|
@@ -1415,11 +1684,25 @@ function readRealmOptions(value, oneShot = false) {
|
|
|
1415
1684
|
"clock",
|
|
1416
1685
|
"limits"
|
|
1417
1686
|
]);
|
|
1687
|
+
if (!oneShot) supported.add("stringCompilation");
|
|
1418
1688
|
if (!oneShot) supported.add("classicScripts");
|
|
1689
|
+
if (!oneShot) supported.add("classicScriptErrors");
|
|
1690
|
+
if (!oneShot) supported.add("callbackScheduling");
|
|
1691
|
+
if (!oneShot) supported.add("sourceImportTimeoutMs");
|
|
1419
1692
|
for (const [key, entry] of Object.entries(options)) {
|
|
1420
|
-
if (supported.has(key) || oneShot && (key === "filename" || key === "sourceType" || entry === void 0)) continue;
|
|
1693
|
+
if (supported.has(key) || oneShot && (key === "filename" || key === "sourceType" || key === "sourceLocation" || entry === void 0)) continue;
|
|
1421
1694
|
throw new TypeError(`Unsupported ${oneShot ? "extension-run" : "realm"} option '${key}'.`);
|
|
1422
1695
|
}
|
|
1696
|
+
if (options.callbackScheduling !== void 0 && options.callbackScheduling !== "after-prefix")
|
|
1697
|
+
throw new TypeError("Realm callbackScheduling must be 'after-prefix'.");
|
|
1698
|
+
if (options.sourceImportTimeoutMs !== void 0 && (!Number.isSafeInteger(options.sourceImportTimeoutMs) || Number(options.sourceImportTimeoutMs) < 1 || Number(options.sourceImportTimeoutMs) > 2147483647))
|
|
1699
|
+
throw new TypeError("Realm sourceImportTimeoutMs must be an integer between 1 and 2147483647.");
|
|
1700
|
+
if (options.stringCompilation !== void 0 && options.stringCompilation !== "allow" && options.stringCompilation !== "deny")
|
|
1701
|
+
throw new TypeError("Realm stringCompilation must be 'allow' or 'deny'.");
|
|
1702
|
+
if (options.classicScriptErrors !== void 0 && options.classicScriptErrors !== "fatal" && options.classicScriptErrors !== "report")
|
|
1703
|
+
throw new TypeError("Realm classicScriptErrors must be 'fatal' or 'report'.");
|
|
1704
|
+
if (options.classicScriptErrors === "report" && options.classicScripts !== true)
|
|
1705
|
+
throw new TypeError("Reporting classic Script errors requires classicScripts:true.");
|
|
1423
1706
|
return options;
|
|
1424
1707
|
}
|
|
1425
1708
|
|
|
@@ -1940,7 +2223,10 @@ function run(source, options = {}) {
|
|
|
1940
2223
|
const operation = budget.acquireCompileOwner(true);
|
|
1941
2224
|
const compilation = new CompileScope(operation.owner);
|
|
1942
2225
|
try {
|
|
1943
|
-
const restoredSnapshot = options.snapshot === void 0 ? void 0 : restore(options.snapshot, {
|
|
2226
|
+
const restoredSnapshot = options.snapshot === void 0 ? void 0 : restore(options.snapshot, {
|
|
2227
|
+
source,
|
|
2228
|
+
...options.importSpecifiers ? { importSpecifiers: options.importSpecifiers } : {}
|
|
2229
|
+
}, operation.owner);
|
|
1944
2230
|
const promiseReplay = new PromiseReplay(restoredSnapshot?.promiseReplay);
|
|
1945
2231
|
return await promiseReplayContext.run(promiseReplay, async () => {
|
|
1946
2232
|
const deactivateOtelSink = activateOtelSink(options.otelSink);
|
|
@@ -1964,15 +2250,16 @@ function run(source, options = {}) {
|
|
|
1964
2250
|
const functionSourceText = executionSemantics === "jobs-v8" || executionSemantics === EXECUTION_SEMANTICS;
|
|
1965
2251
|
runResources.getStore().functionSourceText = functionSourceText;
|
|
1966
2252
|
runResources.getStore().hostDataMetadata = executionSemantics === EXECUTION_SEMANTICS;
|
|
2253
|
+
if (options.sourceLocation !== void 0) runResources.getStore().sourceLocation = options.sourceLocation;
|
|
1967
2254
|
const convertInitialInput = (convert) => executionSemantics === "jobs-v6" ? convert() : promiseReplayContext.exit(convert);
|
|
1968
2255
|
if (restoredSnapshot !== void 0) {
|
|
1969
2256
|
leaveSnapshotRun = enterSnapshotRun(options.snapshot ?? restoredSnapshot);
|
|
1970
2257
|
}
|
|
1971
2258
|
promiseReplay.attachBudget(budget);
|
|
1972
2259
|
const filename = options.filename ?? "<input>";
|
|
1973
|
-
const module = parseExecutableModule(source, filename, operation.owner);
|
|
2260
|
+
const module = parseExecutableModule(source, filename, operation.owner, options.importSpecifiers);
|
|
1974
2261
|
promiseReplay.validateNodes(module);
|
|
1975
|
-
const sourceHash = findRegexLiteral(module) === void 0 ? hashSource(source, operation.owner, functionSourceText) : hashParsedAst(module, functionSourceText);
|
|
2262
|
+
const sourceHash = findRegexLiteral(module) === void 0 && options.importSpecifiers === void 0 ? hashSource(source, operation.owner, functionSourceText) : hashParsedAst(module, functionSourceText);
|
|
1976
2263
|
const hostCalls = new HostCallJournal(
|
|
1977
2264
|
sourceHash,
|
|
1978
2265
|
readHostCallSnapshot(restoredSnapshot),
|
|
@@ -2511,4 +2798,4 @@ export {
|
|
|
2511
2798
|
UnhandledRejectionError,
|
|
2512
2799
|
run
|
|
2513
2800
|
};
|
|
2514
|
-
//# sourceMappingURL=chunk-
|
|
2801
|
+
//# sourceMappingURL=chunk-EH5A2EQI.js.map
|