@nodetool-ai/sandbox-runtime 0.0.0-stage → 0.8.9-bootstrap.0
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 +24 -2
- package/dist/.nodetool-build-stamp +1 -0
- package/dist/host-access-gate.d.ts +24 -0
- package/dist/host-access-gate.d.ts.map +1 -0
- package/dist/host-access-gate.js +31 -0
- package/dist/host-access-gate.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +318 -0
- package/dist/index.js.map +1 -0
- package/dist/js-sandbox-worker/engine.d.ts +4 -0
- package/dist/js-sandbox-worker/engine.d.ts.map +1 -0
- package/dist/js-sandbox-worker/engine.js +82 -0
- package/dist/js-sandbox-worker/engine.js.map +1 -0
- package/dist/js-sandbox-worker/host.d.ts +136 -0
- package/dist/js-sandbox-worker/host.d.ts.map +1 -0
- package/dist/js-sandbox-worker/host.js +482 -0
- package/dist/js-sandbox-worker/host.js.map +1 -0
- package/dist/js-sandbox-worker/interpreter.d.ts +276 -0
- package/dist/js-sandbox-worker/interpreter.d.ts.map +1 -0
- package/dist/js-sandbox-worker/interpreter.js +1318 -0
- package/dist/js-sandbox-worker/interpreter.js.map +1 -0
- package/dist/js-sandbox-worker/protocol.d.ts +168 -0
- package/dist/js-sandbox-worker/protocol.d.ts.map +1 -0
- package/dist/js-sandbox-worker/protocol.js +217 -0
- package/dist/js-sandbox-worker/protocol.js.map +1 -0
- package/dist/js-sandbox-worker/worker-entry.d.ts +26 -0
- package/dist/js-sandbox-worker/worker-entry.d.ts.map +1 -0
- package/dist/js-sandbox-worker/worker-entry.js +308 -0
- package/dist/js-sandbox-worker/worker-entry.js.map +1 -0
- package/dist/limits.d.ts +77 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/limits.js +56 -0
- package/dist/limits.js.map +1 -0
- package/dist/sandbox-bootstrap-modules.d.ts +54 -0
- package/dist/sandbox-bootstrap-modules.d.ts.map +1 -0
- package/dist/sandbox-bootstrap-modules.js +104 -0
- package/dist/sandbox-bootstrap-modules.js.map +1 -0
- package/dist/sandbox-bytes.d.ts +43 -0
- package/dist/sandbox-bytes.d.ts.map +1 -0
- package/dist/sandbox-bytes.js +61 -0
- package/dist/sandbox-bytes.js.map +1 -0
- package/dist/sandbox-canvas-api.d.ts +30 -0
- package/dist/sandbox-canvas-api.d.ts.map +1 -0
- package/dist/sandbox-canvas-api.js +81 -0
- package/dist/sandbox-canvas-api.js.map +1 -0
- package/dist/sandbox-constants.d.ts +5 -0
- package/dist/sandbox-constants.d.ts.map +1 -0
- package/dist/sandbox-constants.js +13 -0
- package/dist/sandbox-constants.js.map +1 -0
- package/dist/sandbox-json-transport.d.ts +107 -0
- package/dist/sandbox-json-transport.d.ts.map +1 -0
- package/dist/sandbox-json-transport.js +324 -0
- package/dist/sandbox-json-transport.js.map +1 -0
- package/dist/timeline-capture.d.ts +21 -0
- package/dist/timeline-capture.d.ts.map +1 -0
- package/dist/timeline-capture.js +564 -0
- package/dist/timeline-capture.js.map +1 -0
- package/dist/utils/type-guards.d.ts +26 -0
- package/dist/utils/type-guards.d.ts.map +1 -0
- package/dist/utils/type-guards.js +44 -0
- package/dist/utils/type-guards.js.map +1 -0
- package/package.json +138 -4
- package/vendor/README.md +17 -0
- package/vendor/quickjs/LICENSE +21 -0
- package/vendor/quickjs/PROVENANCE.json +8 -0
- package/vendor/quickjs/adapter/fetch.d.ts +56 -0
- package/vendor/quickjs/adapter/fetch.js +140 -0
- package/vendor/quickjs/createTimeInterval.d.ts +9 -0
- package/vendor/quickjs/createTimeInterval.js +22 -0
- package/vendor/quickjs/createVirtualFileSystem.d.ts +13 -0
- package/vendor/quickjs/createVirtualFileSystem.js +191 -0
- package/vendor/quickjs/index.d.ts +77 -0
- package/vendor/quickjs/index.js +77 -0
- package/vendor/quickjs/loadAsyncQuickJs.d.ts +12 -0
- package/vendor/quickjs/loadAsyncQuickJs.js +66 -0
- package/vendor/quickjs/loadQuickJs.d.ts +12 -0
- package/vendor/quickjs/loadQuickJs.js +73 -0
- package/vendor/quickjs/modules/assert.d.ts +2 -0
- package/vendor/quickjs/modules/assert.js +47 -0
- package/vendor/quickjs/modules/buffer.d.ts +2 -0
- package/vendor/quickjs/modules/buffer.js +106 -0
- package/vendor/quickjs/modules/build/test-lib.js +2 -0
- package/vendor/quickjs/modules/events.d.ts +2 -0
- package/vendor/quickjs/modules/events.js +4 -0
- package/vendor/quickjs/modules/fs.d.ts +2 -0
- package/vendor/quickjs/modules/fs.js +76 -0
- package/vendor/quickjs/modules/fs_promises.d.ts +2 -0
- package/vendor/quickjs/modules/fs_promises.js +328 -0
- package/vendor/quickjs/modules/module.d.ts +2 -0
- package/vendor/quickjs/modules/module.js +33 -0
- package/vendor/quickjs/modules/nodeCompatibility/headers.d.ts +2 -0
- package/vendor/quickjs/modules/nodeCompatibility/headers.js +58 -0
- package/vendor/quickjs/modules/nodeCompatibility/request.d.ts +2 -0
- package/vendor/quickjs/modules/nodeCompatibility/request.js +5 -0
- package/vendor/quickjs/modules/nodeCompatibility/response.d.ts +2 -0
- package/vendor/quickjs/modules/nodeCompatibility/response.js +5 -0
- package/vendor/quickjs/modules/path.d.ts +2 -0
- package/vendor/quickjs/modules/path.js +504 -0
- package/vendor/quickjs/modules/process.d.ts +2 -0
- package/vendor/quickjs/modules/process.js +309 -0
- package/vendor/quickjs/modules/punycode.d.ts +2 -0
- package/vendor/quickjs/modules/punycode.js +443 -0
- package/vendor/quickjs/modules/querystring.d.ts +2 -0
- package/vendor/quickjs/modules/querystring.js +15 -0
- package/vendor/quickjs/modules/string_decoder.d.ts +2 -0
- package/vendor/quickjs/modules/string_decoder.js +223 -0
- package/vendor/quickjs/modules/timers.d.ts +2 -0
- package/vendor/quickjs/modules/timers.js +10 -0
- package/vendor/quickjs/modules/timers_promises.d.ts +2 -0
- package/vendor/quickjs/modules/timers_promises.js +40 -0
- package/vendor/quickjs/modules/url.d.ts +2 -0
- package/vendor/quickjs/modules/url.js +104 -0
- package/vendor/quickjs/modules/util.d.ts +2 -0
- package/vendor/quickjs/modules/util.js +233 -0
- package/vendor/quickjs/package.json +3 -0
- package/vendor/quickjs/sandbox/asyncVersion/createAsyncEvalCodeFunction.d.ts +4 -0
- package/vendor/quickjs/sandbox/asyncVersion/createAsyncEvalCodeFunction.js +76 -0
- package/vendor/quickjs/sandbox/asyncVersion/createAsyncValidateCodeFunction.d.ts +3 -0
- package/vendor/quickjs/sandbox/asyncVersion/createAsyncValidateCodeFunction.js +22 -0
- package/vendor/quickjs/sandbox/asyncVersion/executeAsyncSandboxFunction.d.ts +12 -0
- package/vendor/quickjs/sandbox/asyncVersion/executeAsyncSandboxFunction.js +9 -0
- package/vendor/quickjs/sandbox/asyncVersion/getAsyncModuleLoader.d.ts +4 -0
- package/vendor/quickjs/sandbox/asyncVersion/getAsyncModuleLoader.js +30 -0
- package/vendor/quickjs/sandbox/asyncVersion/modulePathNormalizerAsync.d.ts +2 -0
- package/vendor/quickjs/sandbox/asyncVersion/modulePathNormalizerAsync.js +12 -0
- package/vendor/quickjs/sandbox/asyncVersion/prepareAsyncNodeCompatibility.d.ts +3 -0
- package/vendor/quickjs/sandbox/asyncVersion/prepareAsyncNodeCompatibility.js +11 -0
- package/vendor/quickjs/sandbox/asyncVersion/prepareAsyncSandbox.d.ts +4 -0
- package/vendor/quickjs/sandbox/asyncVersion/prepareAsyncSandbox.js +10 -0
- package/vendor/quickjs/sandbox/expose/expose.d.ts +3 -0
- package/vendor/quickjs/sandbox/expose/expose.js +155 -0
- package/vendor/quickjs/sandbox/expose/isES2015Class.d.ts +1 -0
- package/vendor/quickjs/sandbox/expose/isES2015Class.js +4 -0
- package/vendor/quickjs/sandbox/expose/isObject.d.ts +1 -0
- package/vendor/quickjs/sandbox/expose/isObject.js +4 -0
- package/vendor/quickjs/sandbox/expose/pendingHostPromises.d.ts +6 -0
- package/vendor/quickjs/sandbox/expose/pendingHostPromises.js +40 -0
- package/vendor/quickjs/sandbox/getMaxIntervalAmount.d.ts +8 -0
- package/vendor/quickjs/sandbox/getMaxIntervalAmount.js +12 -0
- package/vendor/quickjs/sandbox/getMaxTimeoutAmount.d.ts +8 -0
- package/vendor/quickjs/sandbox/getMaxTimeoutAmount.js +12 -0
- package/vendor/quickjs/sandbox/handleEvalError.d.ts +2 -0
- package/vendor/quickjs/sandbox/handleEvalError.js +21 -0
- package/vendor/quickjs/sandbox/handleToNative/handleToNative.d.ts +9 -0
- package/vendor/quickjs/sandbox/handleToNative/handleToNative.js +153 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/index.d.ts +10 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/index.js +36 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeArrayBuffer.d.ts +2 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeArrayBuffer.js +4 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeBuffer.d.ts +2 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeBuffer.js +16 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeDate.d.ts +2 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeDate.js +16 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeError.d.ts +2 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeError.js +18 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeHeaders.d.ts +2 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeHeaders.js +17 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeMap.d.ts +2 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeMap.js +18 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeSet.d.ts +2 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeSet.js +16 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeURLSearchParams.d.ts +2 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeURLSearchParams.js +17 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeUrl.d.ts +2 -0
- package/vendor/quickjs/sandbox/handleToNative/serializer/serializeUrl.js +17 -0
- package/vendor/quickjs/sandbox/helper.d.ts +2 -0
- package/vendor/quickjs/sandbox/helper.js +14 -0
- package/vendor/quickjs/sandbox/provide/provideConsole.d.ts +6 -0
- package/vendor/quickjs/sandbox/provide/provideConsole.js +53 -0
- package/vendor/quickjs/sandbox/provide/provideEnv.d.ts +3 -0
- package/vendor/quickjs/sandbox/provide/provideEnv.js +10 -0
- package/vendor/quickjs/sandbox/provide/provideFs.d.ts +4 -0
- package/vendor/quickjs/sandbox/provide/provideFs.js +159 -0
- package/vendor/quickjs/sandbox/provide/provideHttp.d.ts +9 -0
- package/vendor/quickjs/sandbox/provide/provideHttp.js +42 -0
- package/vendor/quickjs/sandbox/provide/provideTimingFunctions.d.ts +7 -0
- package/vendor/quickjs/sandbox/provide/provideTimingFunctions.js +119 -0
- package/vendor/quickjs/sandbox/setupFileSystem.d.ts +3 -0
- package/vendor/quickjs/sandbox/setupFileSystem.js +13 -0
- package/vendor/quickjs/sandbox/syncVersion/createEvalCodeFunction.d.ts +4 -0
- package/vendor/quickjs/sandbox/syncVersion/createEvalCodeFunction.js +76 -0
- package/vendor/quickjs/sandbox/syncVersion/createValidateCodeFunction.d.ts +3 -0
- package/vendor/quickjs/sandbox/syncVersion/createValidateCodeFunction.js +22 -0
- package/vendor/quickjs/sandbox/syncVersion/executeSandboxFunction.d.ts +12 -0
- package/vendor/quickjs/sandbox/syncVersion/executeSandboxFunction.js +9 -0
- package/vendor/quickjs/sandbox/syncVersion/getModuleLoader.d.ts +4 -0
- package/vendor/quickjs/sandbox/syncVersion/getModuleLoader.js +30 -0
- package/vendor/quickjs/sandbox/syncVersion/modulePathNormalizer.d.ts +2 -0
- package/vendor/quickjs/sandbox/syncVersion/modulePathNormalizer.js +12 -0
- package/vendor/quickjs/sandbox/syncVersion/prepareNodeCompatibility.d.ts +3 -0
- package/vendor/quickjs/sandbox/syncVersion/prepareNodeCompatibility.js +11 -0
- package/vendor/quickjs/sandbox/syncVersion/prepareSandbox.d.ts +4 -0
- package/vendor/quickjs/sandbox/syncVersion/prepareSandbox.js +10 -0
- package/vendor/quickjs/types/CodeFunctionInput.d.ts +12 -0
- package/vendor/quickjs/types/CodeFunctionInput.js +1 -0
- package/vendor/quickjs/types/ErrorResponse.d.ts +9 -0
- package/vendor/quickjs/types/ErrorResponse.js +1 -0
- package/vendor/quickjs/types/LoadQuickJsOptions.d.ts +3 -0
- package/vendor/quickjs/types/LoadQuickJsOptions.js +1 -0
- package/vendor/quickjs/types/OkResponse.d.ts +4 -0
- package/vendor/quickjs/types/OkResponse.js +1 -0
- package/vendor/quickjs/types/OkResponseCheck.d.ts +3 -0
- package/vendor/quickjs/types/OkResponseCheck.js +1 -0
- package/vendor/quickjs/types/Prettify.d.ts +3 -0
- package/vendor/quickjs/types/Prettify.js +1 -0
- package/vendor/quickjs/types/RuntimeOptions.d.ts +87 -0
- package/vendor/quickjs/types/RuntimeOptions.js +1 -0
- package/vendor/quickjs/types/SandboxEvalCode.d.ts +5 -0
- package/vendor/quickjs/types/SandboxEvalCode.js +1 -0
- package/vendor/quickjs/types/SandboxFunction.d.ts +16 -0
- package/vendor/quickjs/types/SandboxFunction.js +1 -0
- package/vendor/quickjs/types/SandboxOptions.d.ts +152 -0
- package/vendor/quickjs/types/SandboxOptions.js +1 -0
- package/vendor/quickjs/types/SandboxValidateCode.d.ts +9 -0
- package/vendor/quickjs/types/SandboxValidateCode.js +1 -0
- package/vendor/quickjs/types/Serializer.d.ts +2 -0
- package/vendor/quickjs/types/Serializer.js +1 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker main for the off-thread QuickJS sandbox.
|
|
3
|
+
*
|
|
4
|
+
* One engine per worker, one run at a time. Everything the guest reaches that
|
|
5
|
+
* lives on the main thread — every bridge, every dispatcher, every
|
|
6
|
+
* function-valued caller global — is rebuilt here as a proxy that posts an RPC
|
|
7
|
+
* and awaits the reply, which is indistinguishable from an ordinary async host
|
|
8
|
+
* function to the library's `expose()`.
|
|
9
|
+
*
|
|
10
|
+
* Three things are deliberately *not* proxied, because the guest reads them
|
|
11
|
+
* synchronously and a round trip has no synchronous answer: `crypto.randomUUID`
|
|
12
|
+
* and `crypto.getRandomValues`, which are reimplemented over the worker's own
|
|
13
|
+
* WebCrypto, and `stream.open`, which is served from a mirror seeded at run
|
|
14
|
+
* start and push-updated when a handle closes.
|
|
15
|
+
*
|
|
16
|
+
* This module is never statically imported by `js-sandbox.ts` — it is loaded
|
|
17
|
+
* only as a worker entry.
|
|
18
|
+
*/
|
|
19
|
+
import { createLogger, importNodeBuiltin } from "@nodetool-ai/config";
|
|
20
|
+
import { loadSandboxEngine } from "./engine.js";
|
|
21
|
+
import { toGuestBytes } from "../sandbox-bytes.js";
|
|
22
|
+
import { MAX_RANDOM_BYTES } from "../sandbox-constants.js";
|
|
23
|
+
import { registerTypedArraySerializers, runInterpreter, SANDBOX_STREAM_OPEN_BINDING } from "./interpreter.js";
|
|
24
|
+
import { interpreterResultMessage, isHostToWorkerMessage, SANDBOX_DISPATCHER_BINDINGS } from "./protocol.js";
|
|
25
|
+
import * as quickJsVariantModule from "@jitl/quickjs-ng-wasmfile-release-sync";
|
|
26
|
+
import { isFiniteNumber, isObjectLike } from "../utils/type-guards.js";
|
|
27
|
+
/**
|
|
28
|
+
* The variant package is CJS with a `default` export, so `ns.default` is the
|
|
29
|
+
* variant at runtime.
|
|
30
|
+
*/
|
|
31
|
+
// SAFETY: TypeScript's CJS interop synthesizes `default` as the whole module
|
|
32
|
+
// object, contradicting the package's own `.d.ts`, which declares it as the
|
|
33
|
+
// `QuickJSSyncVariant` this reads.
|
|
34
|
+
const quickJsVariant = quickJsVariantModule.default;
|
|
35
|
+
const log = createLogger("nodetool.agents.sandbox-worker");
|
|
36
|
+
const SLOW_SANDBOX_RUN_MS = 1_000;
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Engine
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
let enginePromise = null;
|
|
41
|
+
/**
|
|
42
|
+
* One engine per worker.
|
|
43
|
+
*
|
|
44
|
+
* `registerTypedArraySerializers` mutates the library's module-global
|
|
45
|
+
* serializer table, and a worker holds its own module instance, so it registers
|
|
46
|
+
* its own before the first run.
|
|
47
|
+
*/
|
|
48
|
+
function getEngine() {
|
|
49
|
+
registerTypedArraySerializers();
|
|
50
|
+
if (!enginePromise)
|
|
51
|
+
enginePromise = loadSandboxEngine(quickJsVariant);
|
|
52
|
+
return enginePromise;
|
|
53
|
+
}
|
|
54
|
+
class RunSession {
|
|
55
|
+
port;
|
|
56
|
+
run;
|
|
57
|
+
pending = new Map();
|
|
58
|
+
nextRpcId = 0;
|
|
59
|
+
suspended = 0;
|
|
60
|
+
streamOpen;
|
|
61
|
+
constructor(port, run) {
|
|
62
|
+
this.port = port;
|
|
63
|
+
this.run = run;
|
|
64
|
+
this.streamOpen = new Map(Object.entries(run.streamOpenSeed ?? {}));
|
|
65
|
+
}
|
|
66
|
+
suspendedMs = () => this.suspended;
|
|
67
|
+
setSuspendedMs(value) {
|
|
68
|
+
this.suspended = value;
|
|
69
|
+
}
|
|
70
|
+
closeStream(handle) {
|
|
71
|
+
this.streamOpen.set(handle, false);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Answer `stream.open(handle)` from the mirror.
|
|
75
|
+
*
|
|
76
|
+
* `null` means the run carries no input stream at all — the prelude turns
|
|
77
|
+
* that into the no-input-stream throw, matching the in-process binding. A
|
|
78
|
+
* stale `true` is harmless: streams are close-only, so the worst case is
|
|
79
|
+
* one extra take that comes back done.
|
|
80
|
+
*/
|
|
81
|
+
isStreamOpen = (handle) => this.run.streamOpenSeed === null
|
|
82
|
+
? null
|
|
83
|
+
: this.streamOpen.get(String(handle)) === true;
|
|
84
|
+
settleRpc(id, ok, value, error) {
|
|
85
|
+
const pending = this.pending.get(id);
|
|
86
|
+
if (pending === undefined)
|
|
87
|
+
return;
|
|
88
|
+
this.pending.delete(id);
|
|
89
|
+
if (ok)
|
|
90
|
+
pending.resolve(value);
|
|
91
|
+
else
|
|
92
|
+
pending.reject(error ?? new Error("the sandbox bridge call failed"));
|
|
93
|
+
}
|
|
94
|
+
call(path, args) {
|
|
95
|
+
const id = this.nextRpcId++;
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
this.pending.set(id, { resolve, reject });
|
|
98
|
+
this.port.postMessage({ type: "rpc", id, path, args });
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
log(line) {
|
|
102
|
+
this.port.postMessage({ type: "log", line });
|
|
103
|
+
}
|
|
104
|
+
progress(percent, message) {
|
|
105
|
+
this.port.postMessage(message === undefined
|
|
106
|
+
? { type: "progress", percent }
|
|
107
|
+
: { type: "progress", percent, message });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
// Bridge reconstruction
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
/** Random bytes, tagged the way the host bridge tags them. */
|
|
114
|
+
function getRandomValues(requested) {
|
|
115
|
+
const size = isFiniteNumber(requested)
|
|
116
|
+
? Math.min(Math.max(Math.floor(requested), 0), MAX_RANDOM_BYTES)
|
|
117
|
+
: 0;
|
|
118
|
+
const bytes = new Uint8Array(size);
|
|
119
|
+
if (size > 0)
|
|
120
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
121
|
+
return toGuestBytes(bytes);
|
|
122
|
+
}
|
|
123
|
+
/** One RPC proxy, indistinguishable from an async host function to `expose()`. */
|
|
124
|
+
function proxyFor(session, path) {
|
|
125
|
+
return (...args) => session.call(path, args);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Rebuild the record `buildSandbox` would have produced, from names alone.
|
|
129
|
+
*
|
|
130
|
+
* Every entry is an RPC proxy, a value that travelled by clone, or one of the
|
|
131
|
+
* three synchronous locals this worker owns. Those three are handed over
|
|
132
|
+
* unwrapped and the interpreter passes them through unwrapped: a round trip has
|
|
133
|
+
* no synchronous answer, and `stream.open` in particular is a function that
|
|
134
|
+
* must never be wrapped.
|
|
135
|
+
*/
|
|
136
|
+
function buildSandboxRecord(shape, session) {
|
|
137
|
+
const sandbox = {};
|
|
138
|
+
for (const name of shape.flat)
|
|
139
|
+
sandbox[name] = proxyFor(session, [name]);
|
|
140
|
+
for (const [name, value] of Object.entries(shape.values))
|
|
141
|
+
sandbox[name] = value;
|
|
142
|
+
for (const [name, members] of Object.entries(shape.objects)) {
|
|
143
|
+
const table = {};
|
|
144
|
+
for (const member of members)
|
|
145
|
+
table[member] = proxyFor(session, [name, member]);
|
|
146
|
+
sandbox[name] = table;
|
|
147
|
+
}
|
|
148
|
+
// `crypto.digest`/`hmac` stay proxied; the other two are worker-local.
|
|
149
|
+
const crypto = (sandbox.crypto ?? {});
|
|
150
|
+
crypto.randomUUID = () => globalThis.crypto.randomUUID();
|
|
151
|
+
crypto.getRandomValues = getRandomValues;
|
|
152
|
+
sandbox.crypto = crypto;
|
|
153
|
+
sandbox[SANDBOX_STREAM_OPEN_BINDING] = session.isStreamOpen;
|
|
154
|
+
return sandbox;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Caller globals, kept apart from the sandbox record.
|
|
158
|
+
*
|
|
159
|
+
* The interpreter applies them last so a global can shadow a non-reserved
|
|
160
|
+
* name, and it is the only place where "function → wrap, value → pass through"
|
|
161
|
+
* is the right rule. Merging them into the sandbox record would lose that.
|
|
162
|
+
*/
|
|
163
|
+
function buildGlobalsRecord(shape, session) {
|
|
164
|
+
const globals = {};
|
|
165
|
+
for (const [name, global] of Object.entries(shape.globals)) {
|
|
166
|
+
globals[name] =
|
|
167
|
+
global.kind === "fn" ? proxyFor(session, [name]) : global.value;
|
|
168
|
+
}
|
|
169
|
+
return globals;
|
|
170
|
+
}
|
|
171
|
+
/** Object-typed globals, whose contents are read back out of the guest. */
|
|
172
|
+
function syncTargetNames(shape) {
|
|
173
|
+
return Object.entries(shape.globals)
|
|
174
|
+
.filter(([, global]) => global.kind === "value" &&
|
|
175
|
+
isObjectLike(global.value))
|
|
176
|
+
.map(([name]) => name);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* A dispatcher proxy, present only when the run declared that kind.
|
|
180
|
+
*
|
|
181
|
+
* Presence is what decides the guest binding and the init prelude's
|
|
182
|
+
* conditional text, so the three travel as named optionals rather than as keys
|
|
183
|
+
* in an untyped record.
|
|
184
|
+
*/
|
|
185
|
+
function dispatcherCall(shape, session, kind) {
|
|
186
|
+
if (!shape.dispatchers.includes(kind))
|
|
187
|
+
return undefined;
|
|
188
|
+
const binding = SANDBOX_DISPATCHER_BINDINGS[kind];
|
|
189
|
+
const proxy = proxyFor(session, [binding]);
|
|
190
|
+
return (moduleKey, exportName, args) => proxy(moduleKey, exportName, args);
|
|
191
|
+
}
|
|
192
|
+
// ---------------------------------------------------------------------------
|
|
193
|
+
// Worker main
|
|
194
|
+
// ---------------------------------------------------------------------------
|
|
195
|
+
/**
|
|
196
|
+
* An optional param, omitted rather than passed as `undefined`.
|
|
197
|
+
*
|
|
198
|
+
* The interpreter reads presence, not value: a `wasmCall` key that is there and
|
|
199
|
+
* undefined would still be a declared dispatcher.
|
|
200
|
+
*/
|
|
201
|
+
function spreadIfSet(key, value) {
|
|
202
|
+
return value === undefined ? {} : { [key]: value };
|
|
203
|
+
}
|
|
204
|
+
async function executeRun(port, run, session) {
|
|
205
|
+
const startedAt = performance.now();
|
|
206
|
+
const engineStartedAt = performance.now();
|
|
207
|
+
const { runSandboxed } = await getEngine();
|
|
208
|
+
const engineMs = performance.now() - engineStartedAt;
|
|
209
|
+
const shape = run.bridgeShape;
|
|
210
|
+
let interpreterTiming;
|
|
211
|
+
let outcome;
|
|
212
|
+
let failed = false;
|
|
213
|
+
try {
|
|
214
|
+
outcome = await runInterpreter({
|
|
215
|
+
runSandboxed,
|
|
216
|
+
code: run.code,
|
|
217
|
+
sandbox: buildSandboxRecord(shape, session),
|
|
218
|
+
globals: buildGlobalsRecord(shape, session),
|
|
219
|
+
syncTargetNames: syncTargetNames(shape),
|
|
220
|
+
...spreadIfSet("wasmCall", dispatcherCall(shape, session, "wasm")),
|
|
221
|
+
...spreadIfSet("hostCall", dispatcherCall(shape, session, "host")),
|
|
222
|
+
...spreadIfSet("capabilityCall", dispatcherCall(shape, session, "capability")),
|
|
223
|
+
...spreadIfSet("modules", run.modules),
|
|
224
|
+
...spreadIfSet("capabilityFacades", run.capabilityFacades),
|
|
225
|
+
timeoutMs: run.timeoutMs,
|
|
226
|
+
limits: run.limits,
|
|
227
|
+
suspendAllowanceMs: run.suspendAllowanceMs,
|
|
228
|
+
hasClock: run.hasClock,
|
|
229
|
+
// No isAborted: cancellation from the host is `worker.terminate()`, so the
|
|
230
|
+
// interrupt handler in here enforces only the deadline.
|
|
231
|
+
suspendedMs: session.suspendedMs,
|
|
232
|
+
onTiming: (timing) => {
|
|
233
|
+
interpreterTiming = timing;
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
failed = true;
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
finally {
|
|
242
|
+
const totalMs = performance.now() - startedAt;
|
|
243
|
+
if (totalMs >= SLOW_SANDBOX_RUN_MS) {
|
|
244
|
+
log.warn("Slow sandbox worker run", {
|
|
245
|
+
runId: run.runId,
|
|
246
|
+
engineMs,
|
|
247
|
+
interpreter: interpreterTiming,
|
|
248
|
+
failed,
|
|
249
|
+
totalMs
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
port.postMessage(interpreterResultMessage(run.runId, outcome));
|
|
254
|
+
}
|
|
255
|
+
export async function startWorker(port) {
|
|
256
|
+
let session;
|
|
257
|
+
port.on("message", (raw) => {
|
|
258
|
+
if (!isHostToWorkerMessage(raw))
|
|
259
|
+
return;
|
|
260
|
+
switch (raw.type) {
|
|
261
|
+
case "run": {
|
|
262
|
+
const active = new RunSession(port, raw);
|
|
263
|
+
session = active;
|
|
264
|
+
void executeRun(port, raw, active).catch((error) => {
|
|
265
|
+
const failed = {
|
|
266
|
+
type: "result",
|
|
267
|
+
runId: raw.runId,
|
|
268
|
+
evalOk: false,
|
|
269
|
+
failure: "worker",
|
|
270
|
+
errorName: error instanceof Error ? error.name : "Error",
|
|
271
|
+
errorMessage: error instanceof Error ? error.message : String(error)
|
|
272
|
+
};
|
|
273
|
+
if (error instanceof Error && error.stack !== undefined) {
|
|
274
|
+
failed.errorStack = error.stack;
|
|
275
|
+
}
|
|
276
|
+
port.postMessage(failed);
|
|
277
|
+
});
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
case "suspend-update":
|
|
281
|
+
session?.setSuspendedMs(raw.suspendedMs);
|
|
282
|
+
return;
|
|
283
|
+
case "stream-closed":
|
|
284
|
+
session?.closeStream(raw.handle);
|
|
285
|
+
return;
|
|
286
|
+
case "rpc-reply":
|
|
287
|
+
if (raw.ok)
|
|
288
|
+
session?.settleRpc(raw.id, true, raw.value);
|
|
289
|
+
else {
|
|
290
|
+
const error = new Error(raw.message);
|
|
291
|
+
error.name = raw.name;
|
|
292
|
+
session?.settleRpc(raw.id, false, undefined, error);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Boot only under `worker_threads`.
|
|
299
|
+
*
|
|
300
|
+
* Importing this module on the main thread — a stray import, a bundler that
|
|
301
|
+
* pulled it into a graph — must do nothing rather than install a message
|
|
302
|
+
* handler on a port that is not a worker's.
|
|
303
|
+
*/
|
|
304
|
+
const threads = await importNodeBuiltin("node:worker_threads");
|
|
305
|
+
if (threads?.parentPort != null) {
|
|
306
|
+
await startWorker(threads.parentPort);
|
|
307
|
+
}
|
|
308
|
+
//# sourceMappingURL=worker-entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-entry.js","sourceRoot":"","sources":["../../src/js-sandbox-worker/worker-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAEtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EACL,6BAA6B,EAC7B,cAAc,EACd,2BAA2B,EAI5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,2BAA2B,EAK5B,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,oBAAoB,MAAM,wCAAwC,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvE;;;GAGG;AACH,6EAA6E;AAC7E,4EAA4E;AAC5E,mCAAmC;AACnC,MAAM,cAAc,GAClB,oBAGD,CAAC,OAAO,CAAC;AAEV,MAAM,GAAG,GAAG,YAAY,CAAC,gCAAgC,CAAC,CAAC;AAC3D,MAAM,mBAAmB,GAAG,KAAK,CAAC;AAElC,8EAA8E;AAC9E,SAAS;AACT,8EAA8E;AAE9E,IAAI,aAAa,GAAgD,IAAI,CAAC;AAEtE;;;;;;GAMG;AACH,SAAS,SAAS;IAChB,6BAA6B,EAAE,CAAC;IAChC,IAAI,CAAC,aAAa;QAAE,aAAa,GAAG,iBAAiB,CAAC,cAAc,CAAC,CAAC;IACtE,OAAO,aAAa,CAAC;AACvB,CAAC;AAgBD,MAAM,UAAU;IAOK,IAAI;IACJ,GAAG;IAPL,OAAO,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC9C,SAAS,GAAG,CAAC,CAAC;IACd,SAAS,GAAG,CAAC,CAAC;IACL,UAAU,CAAuB;IAElD,YACmB,IAAU,EACV,GAAe;oBADf,IAAI;mBACJ,GAAG;QAEpB,IAAI,CAAC,UAAU,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,WAAW,GAAG,GAAW,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC;IAE3C,cAAc,CAAC,KAAa;QAC1B,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAED,WAAW,CAAC,MAAc;QACxB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACrC,CAAC;IAED;;;;;;;OAOG;IACH,YAAY,GAAG,CAAC,MAAe,EAAkB,EAAE,CACjD,IAAI,CAAC,GAAG,CAAC,cAAc,KAAK,IAAI;QAC9B,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,CAAC;IAEnD,SAAS,CAAC,EAAU,EAAE,EAAW,EAAE,KAAc,EAAE,KAAa;QAC9D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO;QAClC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACxB,IAAI,EAAE;YAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;;YAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC,CAAC;IAC5E,CAAC;IAED,IAAI,CAAC,IAAuB,EAAE,IAAwB;QACpD,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC9C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YAC1C,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,GAAG,CAAC,IAAY;QACd,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,QAAQ,CAAC,OAAe,EAAE,OAAgB;QACxC,IAAI,CAAC,IAAI,CAAC,WAAW,CACnB,OAAO,KAAK,SAAS;YACnB,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE;YAC/B,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,CAC3C,CAAC;IACJ,CAAC;CACF;AAED,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E,8DAA8D;AAC9D,SAAS,eAAe,CAAC,SAAkB;IACzC,MAAM,IAAI,GACR,cAAc,CAAC,SAAS,CAAC;QACvB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,gBAAgB,CAAC;QAChE,CAAC,CAAC,CAAC,CAAC;IACR,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,IAAI,GAAG,CAAC;QAAE,UAAU,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IACvD,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;AAC7B,CAAC;AAED,kFAAkF;AAClF,SAAS,QAAQ,CACf,OAAmB,EACnB,IAAuB;IAEvB,OAAO,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,kBAAkB,CACzB,KAAkB,EAClB,OAAmB;IAEnB,MAAM,OAAO,GAA4B,EAAE,CAAC;IAC5C,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI;QAAE,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IACzE,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;QACtD,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACxB,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5D,MAAM,KAAK,GAA4B,EAAE,CAAC;QAC1C,KAAK,MAAM,MAAM,IAAI,OAAO;YAC1B,KAAK,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACxB,CAAC;IAED,uEAAuE;IACvE,MAAM,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAA4B,CAAC;IACjE,MAAM,CAAC,UAAU,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;IACzD,MAAM,CAAC,eAAe,GAAG,eAAe,CAAC;IACzC,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC;IACxB,OAAO,CAAC,2BAA2B,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC;IAE5D,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,kBAAkB,CACzB,KAAkB,EAClB,OAAmB;IAEnB,MAAM,OAAO,GAA4B,EAAE,CAAC;IAC5C,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3D,OAAO,CAAC,IAAI,CAAC;YACX,MAAM,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;IACpE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,2EAA2E;AAC3E,SAAS,eAAe,CAAC,KAAkB;IACzC,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;SACjC,MAAM,CACL,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,EAAE,CACb,MAAM,CAAC,IAAI,KAAK,OAAO;QACvB,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAC7B;SACA,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;GAMG;AACH,SAAS,cAAc,CACrB,KAAkB,EAClB,OAAmB,EACnB,IAA2B;IAE3B,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACxD,MAAM,OAAO,GAAG,2BAA2B,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3C,OAAO,CAAC,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;AAC7E,CAAC;AAED,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E;;;;;GAKG;AACH,SAAS,WAAW,CAClB,GAAM,EACN,KAAoB;IAEpB,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAmB,CAAC;AACvE,CAAC;AAaD,KAAK,UAAU,UAAU,CACvB,IAAU,EACV,GAAe,EACf,OAAmB;IAEnB,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IACpC,MAAM,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAC1C,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;IAC3C,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,eAAe,CAAC;IACrD,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,CAAC;IAC9B,IAAI,iBAAgD,CAAC;IAErD,IAAI,OAA2B,CAAC;IAChC,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,cAAc,CAAC;YAC7B,YAAY;YACZ,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,OAAO,EAAE,kBAAkB,CAAC,KAAK,EAAE,OAAO,CAAC;YAC3C,OAAO,EAAE,kBAAkB,CAAC,KAAK,EAAE,OAAO,CAAC;YAC3C,eAAe,EAAE,eAAe,CAAC,KAAK,CAAC;YACvC,GAAG,WAAW,CAAC,UAAU,EAAE,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;YAClE,GAAG,WAAW,CAAC,UAAU,EAAE,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;YAClE,GAAG,WAAW,CACZ,gBAAgB,EAChB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,YAAY,CAAC,CAC7C;YACD,GAAG,WAAW,CAAC,SAAS,EAAE,GAAG,CAAC,OAAO,CAAC;YACtC,GAAG,WAAW,CAAC,mBAAmB,EAAE,GAAG,CAAC,iBAAiB,CAAC;YAC1D,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,kBAAkB,EAAE,GAAG,CAAC,kBAAkB;YAC1C,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,2EAA2E;YAC3E,wDAAwD;YACxD,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;gBACnB,iBAAiB,GAAG,MAAM,CAAC;YAC7B,CAAC;SACF,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,IAAI,CAAC;QACd,MAAM,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAC9C,IAAI,OAAO,IAAI,mBAAmB,EAAE,CAAC;YACnC,GAAG,CAAC,IAAI,CAAC,yBAAyB,EAAE;gBAClC,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,QAAQ;gBACR,WAAW,EAAE,iBAAiB;gBAC9B,MAAM;gBACN,OAAO;aACR,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,IAAI,CAAC,WAAW,CAAC,wBAAwB,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAU;IAC1C,IAAI,OAA+B,CAAC;IAEpC,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAY,EAAE,EAAE;QAClC,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC;YAAE,OAAO;QACxC,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACjB,KAAK,KAAK,EAAE,CAAC;gBACX,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBACzC,OAAO,GAAG,MAAM,CAAC;gBACjB,KAAK,UAAU,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;oBAC1D,MAAM,MAAM,GAAsB;wBAChC,IAAI,EAAE,QAAQ;wBACd,KAAK,EAAE,GAAG,CAAC,KAAK;wBAChB,MAAM,EAAE,KAAK;wBACb,OAAO,EAAE,QAAQ;wBACjB,SAAS,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO;wBACxD,YAAY,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;qBACrE,CAAC;oBACF,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;wBACxD,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC;oBAClC,CAAC;oBACD,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;gBAC3B,CAAC,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YACD,KAAK,gBAAgB;gBACnB,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;gBACzC,OAAO;YACT,KAAK,eAAe;gBAClB,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBACjC,OAAO;YACT,KAAK,WAAW;gBACd,IAAI,GAAG,CAAC,EAAE;oBAAE,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;qBACnD,CAAC;oBACJ,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;oBACrC,KAAK,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;oBACtB,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;gBACtD,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,GAAG,MAAM,iBAAiB,CACrC,qBAAqB,CACtB,CAAC;AACF,IAAI,OAAO,EAAE,UAAU,IAAI,IAAI,EAAE,CAAC;IAChC,MAAM,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AACxC,CAAC"}
|
package/dist/limits.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export declare const DEFAULT_TIMEOUT_MS = 30000;
|
|
2
|
+
export declare const MAX_OUTPUT_SIZE = 100000;
|
|
3
|
+
export declare const MAX_LOOP_ITERATIONS = 10000;
|
|
4
|
+
export declare const MAX_FETCH_CALLS = 20;
|
|
5
|
+
export declare const MAX_RESPONSE_BODY_SIZE = 1000000;
|
|
6
|
+
/** Guest heap cap. QuickJS aborts if the guest tries to allocate beyond this. */
|
|
7
|
+
export declare const GUEST_MEMORY_LIMIT: number;
|
|
8
|
+
/** Guest stack cap — protects against deeply recursive code. */
|
|
9
|
+
export declare const GUEST_STACK_LIMIT: number;
|
|
10
|
+
/** Per-request wall-clock cap for the fetch bridge. */
|
|
11
|
+
export declare const FETCH_TIMEOUT_MS = 15000;
|
|
12
|
+
/** Redirect hops the fetch bridge follows before giving up. */
|
|
13
|
+
export declare const MAX_FETCH_REDIRECTS = 5;
|
|
14
|
+
/** Locale used by the `format` bridge when the caller names none. */
|
|
15
|
+
export declare const DEFAULT_FORMAT_LOCALE = "en-US";
|
|
16
|
+
export interface SandboxLimits {
|
|
17
|
+
maxFetchCalls?: number;
|
|
18
|
+
maxResponseBodyBytes?: number;
|
|
19
|
+
maxOutputSize?: number;
|
|
20
|
+
memoryLimitBytes?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Total bytes of media one run may hold host-side for its handles. The
|
|
23
|
+
* aggregate the per-call image/media ceilings never bounded.
|
|
24
|
+
*/
|
|
25
|
+
runMediaBytes?: number;
|
|
26
|
+
stackLimitBytes?: number;
|
|
27
|
+
fetchTimeoutMs?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Permit fetches to loopback, link-local and private address ranges.
|
|
30
|
+
*
|
|
31
|
+
* Off by default: guest code is untrusted, so the SSRF guard is the norm and
|
|
32
|
+
* this is the exception. It exists because the trusted `lib.http` nodes have
|
|
33
|
+
* always been able to reach a local service, and a Code node replacing one
|
|
34
|
+
* must be able to do the same — a workflow pointing at `http://localhost:8000`
|
|
35
|
+
* would otherwise silently stop working.
|
|
36
|
+
*
|
|
37
|
+
* Host-set only: it is read from {@link RunSandboxOptions.limits} and never
|
|
38
|
+
* exposed to the guest, so sandboxed code cannot turn it on for itself.
|
|
39
|
+
*/
|
|
40
|
+
allowPrivateNetwork?: boolean;
|
|
41
|
+
/** `User-Agent` for bridge fetches. Guest-set headers still win. */
|
|
42
|
+
userAgent?: string;
|
|
43
|
+
/**
|
|
44
|
+
* `"workspace"` (default) confines every `workspace.*` call to the workspace
|
|
45
|
+
* root, symlinks included. `"host"` lifts that to the whole filesystem the
|
|
46
|
+
* process can reach, with `~` expanded.
|
|
47
|
+
*
|
|
48
|
+
* Off by default for the same reason as {@link allowPrivateNetwork}, and the
|
|
49
|
+
* stakes are higher — host mode can read credential files. It exists because
|
|
50
|
+
* roughly half the `lib.os` nodes already operate on arbitrary host paths
|
|
51
|
+
* (`expandUser` + raw `node:fs`), so a Code node replacing one needs the same
|
|
52
|
+
* reach. Host-set only, and the graph migration sets it only on nodes
|
|
53
|
+
* rewritten from such a node — a hand-written or model-authored Code node
|
|
54
|
+
* stays confined.
|
|
55
|
+
*/
|
|
56
|
+
filesystemAccess?: "workspace" | "host";
|
|
57
|
+
/**
|
|
58
|
+
* The secret names this run may read, or `null`/absent for every secret the
|
|
59
|
+
* store holds.
|
|
60
|
+
*
|
|
61
|
+
* A script that talks to an external service needs one credential, and
|
|
62
|
+
* nothing about `getSecret` used to say so: a node written to send a Slack
|
|
63
|
+
* message could read the AWS keys. Declaring the scope makes the credential
|
|
64
|
+
* a node reaches part of the node, visible in the graph and refused at the
|
|
65
|
+
* bridge rather than trusted to the code.
|
|
66
|
+
*
|
|
67
|
+
* Host-set only, like {@link allowPrivateNetwork}. A run reads its own scope
|
|
68
|
+
* through `nodetool.secrets.list()` but cannot widen it, and an empty array
|
|
69
|
+
* means no secret at all — a stricter thing than an absent scope, not a
|
|
70
|
+
* looser one.
|
|
71
|
+
*/
|
|
72
|
+
secretScope?: readonly string[] | null;
|
|
73
|
+
}
|
|
74
|
+
export type ResolvedSandboxLimits = Required<SandboxLimits>;
|
|
75
|
+
/** Apply defaults and ceilings to a caller-supplied {@link SandboxLimits}. */
|
|
76
|
+
export declare function resolveSandboxLimits(limits?: SandboxLimits): ResolvedSandboxLimits;
|
|
77
|
+
//# sourceMappingURL=limits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,kBAAkB,QAAS,CAAC;AACzC,eAAO,MAAM,eAAe,SAAU,CAAC;AACvC,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAC1C,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,sBAAsB,UAAY,CAAC;AAChD,iFAAiF;AACjF,eAAO,MAAM,kBAAkB,QAAmB,CAAC;AACnD,gEAAgE;AAChE,eAAO,MAAM,iBAAiB,QAAa,CAAC;AAC5C,uDAAuD;AACvD,eAAO,MAAM,gBAAgB,QAAS,CAAC;AACvC,+DAA+D;AAC/D,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,qEAAqE;AACrE,eAAO,MAAM,qBAAqB,UAAU,CAAC;AAE7C,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;;;;;;OAWG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;;;OAYG;IACH,gBAAgB,CAAC,EAAE,WAAW,GAAG,MAAM,CAAC;IACxC;;;;;;;;;;;;;;OAcG;IACH,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;CACxC;AAED,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC;AA0B5D,8EAA8E;AAC9E,wBAAgB,oBAAoB,CAClC,MAAM,CAAC,EAAE,aAAa,GACrB,qBAAqB,CAmDvB"}
|
package/dist/limits.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { isHostAccessEnabled } from "./host-access-gate.js";
|
|
2
|
+
const MAX_RUN_MEDIA_BYTES = 256 * 1024 * 1024;
|
|
3
|
+
export const DEFAULT_TIMEOUT_MS = 30_000;
|
|
4
|
+
export const MAX_OUTPUT_SIZE = 100_000;
|
|
5
|
+
export const MAX_LOOP_ITERATIONS = 10_000;
|
|
6
|
+
export const MAX_FETCH_CALLS = 20;
|
|
7
|
+
export const MAX_RESPONSE_BODY_SIZE = 1_000_000;
|
|
8
|
+
/** Guest heap cap. QuickJS aborts if the guest tries to allocate beyond this. */
|
|
9
|
+
export const GUEST_MEMORY_LIMIT = 64 * 1024 * 1024;
|
|
10
|
+
/** Guest stack cap — protects against deeply recursive code. */
|
|
11
|
+
export const GUEST_STACK_LIMIT = 512 * 1024;
|
|
12
|
+
/** Per-request wall-clock cap for the fetch bridge. */
|
|
13
|
+
export const FETCH_TIMEOUT_MS = 15_000;
|
|
14
|
+
/** Redirect hops the fetch bridge follows before giving up. */
|
|
15
|
+
export const MAX_FETCH_REDIRECTS = 5;
|
|
16
|
+
/** Locale used by the `format` bridge when the caller names none. */
|
|
17
|
+
export const DEFAULT_FORMAT_LOCALE = "en-US";
|
|
18
|
+
/**
|
|
19
|
+
* Normalize a declared secret scope: a list of non-empty names, or `null` for
|
|
20
|
+
* an unscoped run. An empty declared list stays empty — it denies everything.
|
|
21
|
+
*/
|
|
22
|
+
function resolveSecretScope(scope) {
|
|
23
|
+
if (!Array.isArray(scope))
|
|
24
|
+
return null;
|
|
25
|
+
return scope
|
|
26
|
+
.filter((name) => typeof name === "string" && name !== "")
|
|
27
|
+
.map((name) => name.trim())
|
|
28
|
+
.filter((name) => name !== "");
|
|
29
|
+
}
|
|
30
|
+
function clampLimit(value, fallback, min, max) {
|
|
31
|
+
if (value == null || !Number.isFinite(value))
|
|
32
|
+
return fallback;
|
|
33
|
+
return Math.min(Math.max(Math.floor(value), min), max);
|
|
34
|
+
}
|
|
35
|
+
/** Apply defaults and ceilings to a caller-supplied {@link SandboxLimits}. */
|
|
36
|
+
export function resolveSandboxLimits(limits) {
|
|
37
|
+
return {
|
|
38
|
+
maxFetchCalls: clampLimit(limits?.maxFetchCalls, MAX_FETCH_CALLS, 0, 100),
|
|
39
|
+
maxResponseBodyBytes: clampLimit(limits?.maxResponseBodyBytes, MAX_RESPONSE_BODY_SIZE, 1024, 50 * 1024 * 1024),
|
|
40
|
+
maxOutputSize: clampLimit(limits?.maxOutputSize, MAX_OUTPUT_SIZE, 1024, 10 * 1024 * 1024),
|
|
41
|
+
memoryLimitBytes: clampLimit(limits?.memoryLimitBytes, GUEST_MEMORY_LIMIT, 1024 * 1024, 512 * 1024 * 1024),
|
|
42
|
+
runMediaBytes: clampLimit(limits?.runMediaBytes, MAX_RUN_MEDIA_BYTES, 1024 * 1024, 2 * 1024 * 1024 * 1024),
|
|
43
|
+
stackLimitBytes: clampLimit(limits?.stackLimitBytes, GUEST_STACK_LIMIT, 16 * 1024, 8 * 1024 * 1024),
|
|
44
|
+
fetchTimeoutMs: clampLimit(limits?.fetchTimeoutMs, FETCH_TIMEOUT_MS, 100, 120_000),
|
|
45
|
+
// Not clamped — these are capability switches, not magnitudes. Both
|
|
46
|
+
// resolve to the restrictive value unless the host explicitly opts out,
|
|
47
|
+
// and the cloud profile never lets them out (see isHostAccessEnabled).
|
|
48
|
+
allowPrivateNetwork: limits?.allowPrivateNetwork === true && isHostAccessEnabled(),
|
|
49
|
+
userAgent: limits?.userAgent ?? "",
|
|
50
|
+
filesystemAccess: limits?.filesystemAccess === "host" && isHostAccessEnabled()
|
|
51
|
+
? "host"
|
|
52
|
+
: "workspace",
|
|
53
|
+
secretScope: resolveSecretScope(limits?.secretScope)
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limits.js","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the guest's Node-compat bootstrap loads, in place of the wrapper's own
|
|
3
|
+
* polyfills.
|
|
4
|
+
*
|
|
5
|
+
* Before our sandboxed function is called, `@sebastianwessel/quickjs` evaluates
|
|
6
|
+
* a fixed preamble in the fresh context:
|
|
7
|
+
*
|
|
8
|
+
* ```js
|
|
9
|
+
* import 'node:buffer'; import 'node:util'; import 'node:url';
|
|
10
|
+
* import '@node_compatibility/headers'; import '@node_compatibility/request';
|
|
11
|
+
* import '@node_compatibility/response';
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Twelve kilobytes of JavaScript, compiled and evaluated into a new runtime on
|
|
15
|
+
* **every run** — 4.3 ms of a 12 ms empty run, against 0.34 ms for a bare
|
|
16
|
+
* QuickJS context. And most of it is thrown away immediately: the init prelude
|
|
17
|
+
* deletes `Buffer`, `Headers`, `Request` and `Response` before user code exists,
|
|
18
|
+
* because guest code has no business with host-shaped Node globals.
|
|
19
|
+
*
|
|
20
|
+
* Those imports resolve through the run's own module loader
|
|
21
|
+
* (`createGuestModuleHost`), which is ours, so the bootstrap can be served
|
|
22
|
+
* something cheaper instead of being fought. Four of the six become empty
|
|
23
|
+
* modules. `node:util` becomes the two classes the guest actually keeps, in
|
|
24
|
+
* place of promisify/callbackify/inherits/deprecate/types it never sees.
|
|
25
|
+
* `node:url` is served by the wrapper unchanged, because `URL` and
|
|
26
|
+
* `URLSearchParams` are guest capabilities and a hand-rolled URL parser is not
|
|
27
|
+
* a saving worth making.
|
|
28
|
+
*
|
|
29
|
+
* Measured on this repo's engine: wrapper setup 5.96 ms → 3.28 ms per run.
|
|
30
|
+
*
|
|
31
|
+
* The failure modes are deliberately lopsided. A wrapper release that renames
|
|
32
|
+
* or moves these modules makes the map miss, the real polyfill loads, and the
|
|
33
|
+
* only loss is the saving — pinned by "the compat bootstrap loads our stubs" in
|
|
34
|
+
* `tests/js-sandbox-modules.test.ts`, which fails loudly rather than silently
|
|
35
|
+
* costing 2.7 ms. A release that imports something our `node:util` does not
|
|
36
|
+
* export fails every sandbox run in the suite, which is as loud as it gets.
|
|
37
|
+
*
|
|
38
|
+
* Browser-safe: nothing here imports a Node builtin.
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* Module id → the source served during the wrapper's bootstrap phase. The ids
|
|
42
|
+
* are what its own normalizer produces for the specifiers above; anything not
|
|
43
|
+
* listed loads from the wrapper as before.
|
|
44
|
+
*/
|
|
45
|
+
export declare const BOOTSTRAP_MODULE_SOURCES: ReadonlyMap<string, string>;
|
|
46
|
+
/** Use one module-id shape across the wrapper's POSIX and Windows normalizers. */
|
|
47
|
+
export declare function normalizeBootstrapModuleId(moduleId: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* The globals the bootstrap no longer installs, in the order a reader would
|
|
50
|
+
* check them. Exported so a test can assert they are gone at the source rather
|
|
51
|
+
* than after the prelude's `delete`, which would hide a missed stub.
|
|
52
|
+
*/
|
|
53
|
+
export declare const BOOTSTRAP_DROPPED_GLOBALS: readonly ["Buffer", "Headers", "Request", "Response"];
|
|
54
|
+
//# sourceMappingURL=sandbox-bootstrap-modules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox-bootstrap-modules.d.ts","sourceRoot":"","sources":["../src/sandbox-bootstrap-modules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAuCH;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAQ/D,CAAC;AAEH,kFAAkF;AAClF,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,YACpC,QAAQ,EACR,SAAS,EACT,SAAS,EACT,UAAU,CACF,CAAC"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the guest's Node-compat bootstrap loads, in place of the wrapper's own
|
|
3
|
+
* polyfills.
|
|
4
|
+
*
|
|
5
|
+
* Before our sandboxed function is called, `@sebastianwessel/quickjs` evaluates
|
|
6
|
+
* a fixed preamble in the fresh context:
|
|
7
|
+
*
|
|
8
|
+
* ```js
|
|
9
|
+
* import 'node:buffer'; import 'node:util'; import 'node:url';
|
|
10
|
+
* import '@node_compatibility/headers'; import '@node_compatibility/request';
|
|
11
|
+
* import '@node_compatibility/response';
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Twelve kilobytes of JavaScript, compiled and evaluated into a new runtime on
|
|
15
|
+
* **every run** — 4.3 ms of a 12 ms empty run, against 0.34 ms for a bare
|
|
16
|
+
* QuickJS context. And most of it is thrown away immediately: the init prelude
|
|
17
|
+
* deletes `Buffer`, `Headers`, `Request` and `Response` before user code exists,
|
|
18
|
+
* because guest code has no business with host-shaped Node globals.
|
|
19
|
+
*
|
|
20
|
+
* Those imports resolve through the run's own module loader
|
|
21
|
+
* (`createGuestModuleHost`), which is ours, so the bootstrap can be served
|
|
22
|
+
* something cheaper instead of being fought. Four of the six become empty
|
|
23
|
+
* modules. `node:util` becomes the two classes the guest actually keeps, in
|
|
24
|
+
* place of promisify/callbackify/inherits/deprecate/types it never sees.
|
|
25
|
+
* `node:url` is served by the wrapper unchanged, because `URL` and
|
|
26
|
+
* `URLSearchParams` are guest capabilities and a hand-rolled URL parser is not
|
|
27
|
+
* a saving worth making.
|
|
28
|
+
*
|
|
29
|
+
* Measured on this repo's engine: wrapper setup 5.96 ms → 3.28 ms per run.
|
|
30
|
+
*
|
|
31
|
+
* The failure modes are deliberately lopsided. A wrapper release that renames
|
|
32
|
+
* or moves these modules makes the map miss, the real polyfill loads, and the
|
|
33
|
+
* only loss is the saving — pinned by "the compat bootstrap loads our stubs" in
|
|
34
|
+
* `tests/js-sandbox-modules.test.ts`, which fails loudly rather than silently
|
|
35
|
+
* costing 2.7 ms. A release that imports something our `node:util` does not
|
|
36
|
+
* export fails every sandbox run in the suite, which is as loud as it gets.
|
|
37
|
+
*
|
|
38
|
+
* Browser-safe: nothing here imports a Node builtin.
|
|
39
|
+
*/
|
|
40
|
+
/** A module whose only job is to exist, for an `import` that wants no export. */
|
|
41
|
+
const EMPTY_MODULE = "export default {};";
|
|
42
|
+
/**
|
|
43
|
+
* `TextEncoder`/`TextDecoder`, which the wrapper's `node:util` installs as
|
|
44
|
+
* globals and which the guest surface documents.
|
|
45
|
+
*
|
|
46
|
+
* The `encodeURIComponent`/`unescape` pair is UTF-8 the way the wrapper's own
|
|
47
|
+
* polyfill does it, so the bytes a guest sees are the bytes it saw before. Both
|
|
48
|
+
* classes are also exported by name: the wrapper's `node:buffer` imports them
|
|
49
|
+
* that way, and although that module is empty here, a future one may not be.
|
|
50
|
+
*/
|
|
51
|
+
const UTIL_MODULE = `
|
|
52
|
+
class TextEncoder {
|
|
53
|
+
encode(input = "") {
|
|
54
|
+
const utf8 = unescape(encodeURIComponent(input));
|
|
55
|
+
const out = new Uint8Array(utf8.length);
|
|
56
|
+
for (let i = 0; i < utf8.length; i++) out[i] = utf8.charCodeAt(i);
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
class TextDecoder {
|
|
61
|
+
constructor(encoding = "utf-8") {
|
|
62
|
+
if (encoding !== "utf-8") throw new Error("Only utf-8 encoding is supported");
|
|
63
|
+
}
|
|
64
|
+
decode(input = new Uint8Array()) {
|
|
65
|
+
let text = "";
|
|
66
|
+
for (let i = 0; i < input.length; i++) text += String.fromCharCode(input[i]);
|
|
67
|
+
return decodeURIComponent(escape(text));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
globalThis.TextEncoder = TextEncoder;
|
|
71
|
+
globalThis.TextDecoder = TextDecoder;
|
|
72
|
+
export { TextEncoder, TextDecoder };
|
|
73
|
+
export default { TextEncoder, TextDecoder };
|
|
74
|
+
`;
|
|
75
|
+
/**
|
|
76
|
+
* Module id → the source served during the wrapper's bootstrap phase. The ids
|
|
77
|
+
* are what its own normalizer produces for the specifiers above; anything not
|
|
78
|
+
* listed loads from the wrapper as before.
|
|
79
|
+
*/
|
|
80
|
+
export const BOOTSTRAP_MODULE_SOURCES = new Map([
|
|
81
|
+
// Deleted by the init prelude the moment the bootstrap finishes.
|
|
82
|
+
["/node_modules/buffer", EMPTY_MODULE],
|
|
83
|
+
["/node_modules/@node_compatibility/headers", EMPTY_MODULE],
|
|
84
|
+
["/node_modules/@node_compatibility/request", EMPTY_MODULE],
|
|
85
|
+
["/node_modules/@node_compatibility/response", EMPTY_MODULE],
|
|
86
|
+
// Kept, minus everything the guest cannot reach.
|
|
87
|
+
["/node_modules/util", UTIL_MODULE]
|
|
88
|
+
]);
|
|
89
|
+
/** Use one module-id shape across the wrapper's POSIX and Windows normalizers. */
|
|
90
|
+
export function normalizeBootstrapModuleId(moduleId) {
|
|
91
|
+
return moduleId.replaceAll("\\", "/");
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The globals the bootstrap no longer installs, in the order a reader would
|
|
95
|
+
* check them. Exported so a test can assert they are gone at the source rather
|
|
96
|
+
* than after the prelude's `delete`, which would hide a missed stub.
|
|
97
|
+
*/
|
|
98
|
+
export const BOOTSTRAP_DROPPED_GLOBALS = [
|
|
99
|
+
"Buffer",
|
|
100
|
+
"Headers",
|
|
101
|
+
"Request",
|
|
102
|
+
"Response"
|
|
103
|
+
];
|
|
104
|
+
//# sourceMappingURL=sandbox-bootstrap-modules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox-bootstrap-modules.js","sourceRoot":"","sources":["../src/sandbox-bootstrap-modules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,iFAAiF;AACjF,MAAM,YAAY,GAAG,oBAAoB,CAAC;AAE1C;;;;;;;;GAQG;AACH,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAuBnB,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAgC,IAAI,GAAG,CAAC;IAC3E,iEAAiE;IACjE,CAAC,sBAAsB,EAAE,YAAY,CAAC;IACtC,CAAC,2CAA2C,EAAE,YAAY,CAAC;IAC3D,CAAC,2CAA2C,EAAE,YAAY,CAAC;IAC3D,CAAC,4CAA4C,EAAE,YAAY,CAAC;IAC5D,iDAAiD;IACjD,CAAC,oBAAoB,EAAE,WAAW,CAAC;CACpC,CAAC,CAAC;AAEH,kFAAkF;AAClF,MAAM,UAAU,0BAA0B,CAAC,QAAgB;IACzD,OAAO,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACxC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,QAAQ;IACR,SAAS;IACT,SAAS;IACT,UAAU;CACF,CAAC"}
|