sandboxedjs 0.1.29 → 0.1.31
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/LICENSE +1 -7
- package/README.md +137 -92
- package/bin/sandboxedjs-serve.mjs +24 -0
- package/dist/browser-host.cjs +112 -0
- package/dist/browser-host.cjs.map +1 -0
- package/dist/browser-host.d.cts +25 -0
- package/dist/browser-host.d.ts +25 -0
- package/dist/browser-host.js +109 -0
- package/dist/browser-host.js.map +1 -0
- package/dist/index.cjs +464 -178
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +139 -16
- package/dist/index.d.ts +139 -16
- package/dist/index.js +462 -179
- package/dist/index.js.map +1 -1
- package/dist/service-worker.js +112 -0
- package/dist/service-worker.js.map +1 -0
- package/dist/worker-entry.js +140 -116
- package/dist/worker-entry.js.map +1 -1
- package/package.json +9 -3
package/dist/index.js
CHANGED
|
@@ -4778,7 +4778,15 @@ var Pipe = class _Pipe {
|
|
|
4778
4778
|
* whole line on every keystroke — so the terminal must stop echoing, or
|
|
4779
4779
|
* every character appears twice.
|
|
4780
4780
|
*/
|
|
4781
|
-
|
|
4781
|
+
raw = false;
|
|
4782
|
+
onRawMode;
|
|
4783
|
+
get rawMode() {
|
|
4784
|
+
return this.raw;
|
|
4785
|
+
}
|
|
4786
|
+
set rawMode(enabled) {
|
|
4787
|
+
this.raw = enabled;
|
|
4788
|
+
this.onRawMode?.(enabled);
|
|
4789
|
+
}
|
|
4782
4790
|
columns;
|
|
4783
4791
|
rows;
|
|
4784
4792
|
get closed() {
|
|
@@ -5906,13 +5914,19 @@ var Kernel = class {
|
|
|
5906
5914
|
stderr: opts.stderr ?? new NullOutput()
|
|
5907
5915
|
}
|
|
5908
5916
|
});
|
|
5917
|
+
const cancelWithParent = () => {
|
|
5918
|
+
if (parent?.termSignal) proc.deliver(parent.termSignal);
|
|
5919
|
+
};
|
|
5920
|
+
parent?.signal.addEventListener("abort", cancelWithParent, { once: true });
|
|
5921
|
+
if (parent?.signal.aborted) cancelWithParent();
|
|
5922
|
+
void proc.wait().then(() => parent?.signal.removeEventListener("abort", cancelWithParent));
|
|
5909
5923
|
let timer;
|
|
5910
5924
|
if (opts.timeoutMs !== void 0) {
|
|
5911
5925
|
timer = setTimeout(() => {
|
|
5912
5926
|
proc.deliver("SIGKILL");
|
|
5913
5927
|
}, opts.timeoutMs);
|
|
5914
5928
|
}
|
|
5915
|
-
void this.dispatch(proc).then((code) => {
|
|
5929
|
+
void (proc.signal.aborted ? Promise.resolve(proc.exitCode ?? 137) : this.dispatch(proc)).then((code) => {
|
|
5916
5930
|
proc.exit(code);
|
|
5917
5931
|
}).catch((e) => {
|
|
5918
5932
|
try {
|
|
@@ -7904,6 +7918,22 @@ var Shell = class _Shell {
|
|
|
7904
7918
|
}
|
|
7905
7919
|
return this.lastStatus;
|
|
7906
7920
|
}
|
|
7921
|
+
/** Signal the current terminal pipeline without terminating the interactive shell. */
|
|
7922
|
+
interruptForeground(signal, stdin) {
|
|
7923
|
+
const processes = this.kernel.procs.list().filter((process2) => process2.running);
|
|
7924
|
+
const selected = new Set(processes.filter((process2) => process2.ppid === this.proc.pid && process2.stdin === stdin).map((process2) => process2.pid));
|
|
7925
|
+
for (let changed = true; changed; ) {
|
|
7926
|
+
changed = false;
|
|
7927
|
+
const outputs = processes.filter((process2) => selected.has(process2.pid)).flatMap((process2) => [process2.stdout, process2.stderr]);
|
|
7928
|
+
for (const process2 of processes) {
|
|
7929
|
+
if (!selected.has(process2.pid) && (selected.has(process2.ppid) || outputs.some((output) => output === process2.stdin))) {
|
|
7930
|
+
selected.add(process2.pid);
|
|
7931
|
+
changed = true;
|
|
7932
|
+
}
|
|
7933
|
+
}
|
|
7934
|
+
}
|
|
7935
|
+
for (const process2 of processes) if (selected.has(process2.pid)) process2.deliver(signal);
|
|
7936
|
+
}
|
|
7907
7937
|
get isExiting() {
|
|
7908
7938
|
return this.exiting;
|
|
7909
7939
|
}
|
|
@@ -8553,6 +8583,7 @@ sys ${fmt2(Math.floor(ms * 0.2))}
|
|
|
8553
8583
|
for (const assignment of assignments) {
|
|
8554
8584
|
env2[assignment.name] = await expandWordToString(assignment.value, this.expandContext());
|
|
8555
8585
|
}
|
|
8586
|
+
if (this.proc.signal.aborted) return this.proc.exitCode ?? 137;
|
|
8556
8587
|
const proc = this.kernel.spawn(words, {
|
|
8557
8588
|
cwd: this.cwd,
|
|
8558
8589
|
env: env2,
|
|
@@ -19695,6 +19726,11 @@ var KernelChildProcess = class {
|
|
|
19695
19726
|
started = false;
|
|
19696
19727
|
cancelled = false;
|
|
19697
19728
|
constructor(kernel, cred, config, pid) {
|
|
19729
|
+
if (config.inheritStdio) {
|
|
19730
|
+
this.stdin.isTTY = true;
|
|
19731
|
+
this.stdin.interactive = true;
|
|
19732
|
+
}
|
|
19733
|
+
this.stdin.onRawMode = (enabled) => this.emit("rawmode", enabled);
|
|
19698
19734
|
this.kernel = kernel;
|
|
19699
19735
|
this.cred = cred;
|
|
19700
19736
|
this.pid = pid;
|
|
@@ -19811,7 +19847,7 @@ function installNodeChildProcessBridge(pod, kernel, cred) {
|
|
|
19811
19847
|
const originalSpawn = manager.spawn;
|
|
19812
19848
|
manager.spawn = (config) => {
|
|
19813
19849
|
const resolved = kernel.resolveExecutable(config.command, config.cwd ?? "/", config.env ?? {}, cred);
|
|
19814
|
-
if (resolved?.kind === "builtin"
|
|
19850
|
+
if (resolved?.kind === "builtin") {
|
|
19815
19851
|
return new KernelChildProcess(kernel, cred, config, nextBridgePid++);
|
|
19816
19852
|
}
|
|
19817
19853
|
return originalSpawn.call(manager, config);
|
|
@@ -19822,6 +19858,68 @@ function installNodeChildProcessBridge(pod, kernel, cred) {
|
|
|
19822
19858
|
};
|
|
19823
19859
|
}
|
|
19824
19860
|
|
|
19861
|
+
// src/runtime/host-module-tracker.ts
|
|
19862
|
+
var HostModuleTracker = class {
|
|
19863
|
+
active = 0;
|
|
19864
|
+
disposed = false;
|
|
19865
|
+
dispose() {
|
|
19866
|
+
this.disposed = true;
|
|
19867
|
+
}
|
|
19868
|
+
wrapped = /* @__PURE__ */ new WeakMap();
|
|
19869
|
+
originals = /* @__PURE__ */ new WeakMap();
|
|
19870
|
+
pending = () => this.active;
|
|
19871
|
+
unwrap = (value) => value && (typeof value === "object" || typeof value === "function") ? this.originals.get(value) ?? value : value;
|
|
19872
|
+
wrap(value) {
|
|
19873
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return value;
|
|
19874
|
+
const object = value;
|
|
19875
|
+
if (Array.isArray(value) || ArrayBuffer.isView(value) || value instanceof ArrayBuffer) return value;
|
|
19876
|
+
if (this.wrapped.has(object)) return this.wrapped.get(object);
|
|
19877
|
+
const tracker = this;
|
|
19878
|
+
const proxy = new Proxy(object, {
|
|
19879
|
+
// CommonJS native loaders re-export by assigning exports back onto the
|
|
19880
|
+
// binding object. Never store a process-owned proxy in a shared module.
|
|
19881
|
+
set(target, key, member) {
|
|
19882
|
+
return Reflect.set(target, key, tracker.unwrap(member), target);
|
|
19883
|
+
},
|
|
19884
|
+
defineProperty(target, key, descriptor) {
|
|
19885
|
+
return Reflect.defineProperty(target, key, "value" in descriptor ? { ...descriptor, value: tracker.unwrap(descriptor.value) } : descriptor);
|
|
19886
|
+
},
|
|
19887
|
+
get(target, key) {
|
|
19888
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
|
|
19889
|
+
const member = Reflect.get(target, key, target);
|
|
19890
|
+
if (descriptor && !descriptor.configurable && "value" in descriptor && !descriptor.writable) return member;
|
|
19891
|
+
return typeof member === "function" ? tracker.wrap(member) : member;
|
|
19892
|
+
},
|
|
19893
|
+
apply(target, receiver, args) {
|
|
19894
|
+
const result = Reflect.apply(target, tracker.unwrap(receiver), args.map(tracker.unwrap));
|
|
19895
|
+
if (result && typeof result.then === "function") {
|
|
19896
|
+
tracker.active++;
|
|
19897
|
+
return Promise.resolve(result).then(
|
|
19898
|
+
(value2) => {
|
|
19899
|
+
tracker.active--;
|
|
19900
|
+
return tracker.disposed ? new Promise(() => {
|
|
19901
|
+
}) : tracker.wrap(value2);
|
|
19902
|
+
},
|
|
19903
|
+
(error) => {
|
|
19904
|
+
tracker.active--;
|
|
19905
|
+
if (tracker.disposed) return new Promise(() => {
|
|
19906
|
+
});
|
|
19907
|
+
throw error;
|
|
19908
|
+
}
|
|
19909
|
+
);
|
|
19910
|
+
}
|
|
19911
|
+
return tracker.wrap(result);
|
|
19912
|
+
},
|
|
19913
|
+
construct(target, args, newTarget) {
|
|
19914
|
+
return tracker.wrap(Reflect.construct(target, args.map(tracker.unwrap), tracker.unwrap(newTarget)));
|
|
19915
|
+
}
|
|
19916
|
+
});
|
|
19917
|
+
this.wrapped.set(object, proxy);
|
|
19918
|
+
this.originals.set(proxy, object);
|
|
19919
|
+
return proxy;
|
|
19920
|
+
}
|
|
19921
|
+
};
|
|
19922
|
+
|
|
19825
19923
|
// src/runtime/commonjs-engine.ts
|
|
19826
19924
|
init_path();
|
|
19827
19925
|
var HELPERS = {
|
|
@@ -21559,6 +21657,7 @@ var VirtualHttpServer = class extends EventEmitter4 {
|
|
|
21559
21657
|
owner;
|
|
21560
21658
|
listening = false;
|
|
21561
21659
|
portValue = null;
|
|
21660
|
+
referenced = true;
|
|
21562
21661
|
listen(...args) {
|
|
21563
21662
|
const callback = typeof args.at(-1) === "function" ? args.pop() : void 0;
|
|
21564
21663
|
const first = args[0];
|
|
@@ -21587,11 +21686,16 @@ var VirtualHttpServer = class extends EventEmitter4 {
|
|
|
21587
21686
|
return this.portValue === null ? null : { address: "0.0.0.0", family: "IPv4", port: this.portValue };
|
|
21588
21687
|
}
|
|
21589
21688
|
ref() {
|
|
21689
|
+
this.referenced = true;
|
|
21590
21690
|
return this;
|
|
21591
21691
|
}
|
|
21592
21692
|
unref() {
|
|
21693
|
+
this.referenced = false;
|
|
21593
21694
|
return this;
|
|
21594
21695
|
}
|
|
21696
|
+
hasRef() {
|
|
21697
|
+
return this.referenced;
|
|
21698
|
+
}
|
|
21595
21699
|
setTimeout(_milliseconds, callback) {
|
|
21596
21700
|
if (callback) this.on("timeout", callback);
|
|
21597
21701
|
return this;
|
|
@@ -21601,13 +21705,16 @@ var VirtualHttpRouter = class {
|
|
|
21601
21705
|
servers = /* @__PURE__ */ new Map();
|
|
21602
21706
|
/** Notified when a server begins listening, for `onServerReady`. */
|
|
21603
21707
|
onListen;
|
|
21708
|
+
onClose;
|
|
21604
21709
|
register(port, server, owner) {
|
|
21605
21710
|
if (this.servers.has(port)) throw Object.assign(new Error(`listen EADDRINUSE: address already in use 0.0.0.0:${port}`), { code: "EADDRINUSE", port });
|
|
21606
21711
|
this.servers.set(port, { server, owner });
|
|
21607
21712
|
this.onListen?.(port);
|
|
21608
21713
|
}
|
|
21609
21714
|
unregister(port, server) {
|
|
21610
|
-
if (this.servers.get(port)?.server
|
|
21715
|
+
if (this.servers.get(port)?.server !== server) return;
|
|
21716
|
+
this.servers.delete(port);
|
|
21717
|
+
this.onClose?.(port);
|
|
21611
21718
|
}
|
|
21612
21719
|
/** Whether anything in this container is listening on `port`. */
|
|
21613
21720
|
activePortsIncludes(port) {
|
|
@@ -21616,6 +21723,9 @@ var VirtualHttpRouter = class {
|
|
|
21616
21723
|
activePorts(owner) {
|
|
21617
21724
|
return [...this.servers].filter(([, item]) => owner === void 0 || item.owner === owner).map(([port]) => port).sort((a, b) => a - b);
|
|
21618
21725
|
}
|
|
21726
|
+
referencedPorts(owner) {
|
|
21727
|
+
return [...this.servers].filter(([, item]) => item.owner === owner && item.server.hasRef()).map(([port]) => port);
|
|
21728
|
+
}
|
|
21619
21729
|
closeOwner(owner) {
|
|
21620
21730
|
for (const { server, owner: value } of [...this.servers.values()]) if (value === owner) server.close();
|
|
21621
21731
|
}
|
|
@@ -22027,6 +22137,108 @@ function hashFor(algorithm) {
|
|
|
22027
22137
|
function toBytes2(data, encoding) {
|
|
22028
22138
|
return typeof data === "string" ? Buffer2.from(data, encoding) : data;
|
|
22029
22139
|
}
|
|
22140
|
+
|
|
22141
|
+
// src/runtime/sync-channel.ts
|
|
22142
|
+
var STATE = 0;
|
|
22143
|
+
var LENGTH = 1;
|
|
22144
|
+
var MORE = 2;
|
|
22145
|
+
var CONTROL_WORDS = 4;
|
|
22146
|
+
var STATE_REQUEST = 1;
|
|
22147
|
+
var STATE_RESPONSE = 2;
|
|
22148
|
+
var STATE_CONTINUE = 3;
|
|
22149
|
+
var STATE_CLOSED = 4;
|
|
22150
|
+
function createSyncChannelBuffers(capacityBytes = 1 << 20) {
|
|
22151
|
+
return {
|
|
22152
|
+
control: new SharedArrayBuffer(CONTROL_WORDS * Int32Array.BYTES_PER_ELEMENT),
|
|
22153
|
+
data: new SharedArrayBuffer(capacityBytes)
|
|
22154
|
+
};
|
|
22155
|
+
}
|
|
22156
|
+
function syncChannelUnavailableReason() {
|
|
22157
|
+
if (typeof globalThis.crossOriginIsolated === "boolean" && !globalThis.crossOriginIsolated) {
|
|
22158
|
+
return "The browser host is not cross-origin isolated. Serve the host app over HTTPS or localhost with Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp. For a built app use sandboxedjs-serve <directory>. Embedded browsers or iframe policies may also prevent isolation.";
|
|
22159
|
+
}
|
|
22160
|
+
if (typeof SharedArrayBuffer !== "function") return "SharedArrayBuffer is unavailable in this host.";
|
|
22161
|
+
if (typeof Atomics !== "object" || typeof Atomics.wait !== "function") return "Atomics.wait is unavailable in this host.";
|
|
22162
|
+
return null;
|
|
22163
|
+
}
|
|
22164
|
+
function syncChannelSupported() {
|
|
22165
|
+
return syncChannelUnavailableReason() === null;
|
|
22166
|
+
}
|
|
22167
|
+
var SyncChannelServer = class {
|
|
22168
|
+
constructor(buffers, handle) {
|
|
22169
|
+
this.handle = handle;
|
|
22170
|
+
this.control = new Int32Array(buffers.control);
|
|
22171
|
+
this.data = new Uint8Array(buffers.data);
|
|
22172
|
+
this.capacity = this.data.length;
|
|
22173
|
+
}
|
|
22174
|
+
handle;
|
|
22175
|
+
control;
|
|
22176
|
+
data;
|
|
22177
|
+
capacity;
|
|
22178
|
+
/** Request chunks gathered so far, and the response still to be sent. */
|
|
22179
|
+
incoming = [];
|
|
22180
|
+
outgoing = null;
|
|
22181
|
+
sent = 0;
|
|
22182
|
+
closed = false;
|
|
22183
|
+
/** Call from the wake message the client sends after each chunk. */
|
|
22184
|
+
async pump() {
|
|
22185
|
+
if (this.closed) return;
|
|
22186
|
+
const state = Atomics.load(this.control, STATE);
|
|
22187
|
+
if (state === STATE_REQUEST) {
|
|
22188
|
+
const size = Atomics.load(this.control, LENGTH);
|
|
22189
|
+
this.incoming.push(this.data.slice(0, size));
|
|
22190
|
+
if (Atomics.load(this.control, MORE) === 1) {
|
|
22191
|
+
this.publish(STATE_CONTINUE);
|
|
22192
|
+
return;
|
|
22193
|
+
}
|
|
22194
|
+
const request = concat3(this.incoming);
|
|
22195
|
+
this.incoming = [];
|
|
22196
|
+
let response;
|
|
22197
|
+
try {
|
|
22198
|
+
response = await this.handle(request);
|
|
22199
|
+
} catch {
|
|
22200
|
+
response = new Uint8Array();
|
|
22201
|
+
}
|
|
22202
|
+
if (this.closed) return;
|
|
22203
|
+
this.outgoing = response;
|
|
22204
|
+
this.sent = 0;
|
|
22205
|
+
this.sendChunk();
|
|
22206
|
+
return;
|
|
22207
|
+
}
|
|
22208
|
+
if (state === STATE_CONTINUE) this.sendChunk();
|
|
22209
|
+
}
|
|
22210
|
+
/** Release a blocked client, e.g. when the container is torn down. */
|
|
22211
|
+
close() {
|
|
22212
|
+
if (this.closed) return;
|
|
22213
|
+
this.closed = true;
|
|
22214
|
+
Atomics.store(this.control, STATE, STATE_CLOSED);
|
|
22215
|
+
Atomics.notify(this.control, STATE);
|
|
22216
|
+
}
|
|
22217
|
+
sendChunk() {
|
|
22218
|
+
const payload = this.outgoing ?? new Uint8Array();
|
|
22219
|
+
const size = Math.min(this.capacity, payload.length - this.sent);
|
|
22220
|
+
this.data.set(payload.subarray(this.sent, this.sent + size), 0);
|
|
22221
|
+
this.sent += size;
|
|
22222
|
+
Atomics.store(this.control, LENGTH, size);
|
|
22223
|
+
Atomics.store(this.control, MORE, this.sent < payload.length ? 1 : 0);
|
|
22224
|
+
this.publish(STATE_RESPONSE);
|
|
22225
|
+
}
|
|
22226
|
+
publish(state) {
|
|
22227
|
+
Atomics.store(this.control, STATE, state);
|
|
22228
|
+
Atomics.notify(this.control, STATE);
|
|
22229
|
+
}
|
|
22230
|
+
};
|
|
22231
|
+
function concat3(parts) {
|
|
22232
|
+
if (parts.length === 1) return parts[0];
|
|
22233
|
+
const total = parts.reduce((sum, part) => sum + part.length, 0);
|
|
22234
|
+
const joined = new Uint8Array(total);
|
|
22235
|
+
let at = 0;
|
|
22236
|
+
for (const part of parts) {
|
|
22237
|
+
joined.set(part, at);
|
|
22238
|
+
at += part.length;
|
|
22239
|
+
}
|
|
22240
|
+
return joined;
|
|
22241
|
+
}
|
|
22030
22242
|
var ChildProcess = class extends EventEmitter4 {
|
|
22031
22243
|
stdout = new streamModule4.PassThrough();
|
|
22032
22244
|
stderr = new streamModule4.PassThrough();
|
|
@@ -22099,7 +22311,8 @@ var ChildProcess = class extends EventEmitter4 {
|
|
|
22099
22311
|
queueMicrotask(() => this.emit("close", code, null));
|
|
22100
22312
|
}
|
|
22101
22313
|
};
|
|
22102
|
-
function createChildProcessModule(spawnChild, defaultCwd, syncSpawn) {
|
|
22314
|
+
function createChildProcessModule(spawnChild, defaultCwd, syncSpawn, defaultEnv = () => ({})) {
|
|
22315
|
+
const environmentFor = (options) => options.env ? { ...options.env } : defaultEnv();
|
|
22103
22316
|
const throughShell = (command, options) => {
|
|
22104
22317
|
const shell = typeof options.shell === "string" ? options.shell : "/bin/sh";
|
|
22105
22318
|
return { file: shell, args: ["-c", command] };
|
|
@@ -22110,7 +22323,7 @@ function createChildProcessModule(spawnChild, defaultCwd, syncSpawn) {
|
|
|
22110
22323
|
command: resolved.file,
|
|
22111
22324
|
args: resolved.args,
|
|
22112
22325
|
cwd: options.cwd ?? defaultCwd(),
|
|
22113
|
-
|
|
22326
|
+
env: environmentFor(options)
|
|
22114
22327
|
});
|
|
22115
22328
|
return new ChildProcess(handle, resolved.file, resolved.args);
|
|
22116
22329
|
};
|
|
@@ -22156,11 +22369,11 @@ ${err.join("")}`),
|
|
|
22156
22369
|
exec,
|
|
22157
22370
|
execFile,
|
|
22158
22371
|
fork: (modulePath, args = [], options = {}) => spawn("node", [modulePath, ...args], options),
|
|
22159
|
-
...buildSyncFamily(syncSpawn, throughShell, defaultCwd),
|
|
22372
|
+
...buildSyncFamily(syncSpawn, throughShell, defaultCwd, environmentFor),
|
|
22160
22373
|
ChildProcess
|
|
22161
22374
|
};
|
|
22162
22375
|
}
|
|
22163
|
-
function buildSyncFamily(syncSpawn, throughShell, defaultCwd) {
|
|
22376
|
+
function buildSyncFamily(syncSpawn, throughShell, defaultCwd, environmentFor) {
|
|
22164
22377
|
if (!syncSpawn) {
|
|
22165
22378
|
return {
|
|
22166
22379
|
execSync: unavailable("execSync"),
|
|
@@ -22171,12 +22384,14 @@ function buildSyncFamily(syncSpawn, throughShell, defaultCwd) {
|
|
|
22171
22384
|
const run = (file3, args, options) => {
|
|
22172
22385
|
const resolved = options.shell ? throughShell([file3, ...args].join(" "), options) : { file: file3, args };
|
|
22173
22386
|
const input = options.input === void 0 ? void 0 : typeof options.input === "string" ? options.input : new TextDecoder().decode(options.input);
|
|
22387
|
+
const inherit = options.stdio === "inherit" || Array.isArray(options.stdio) && options.stdio[0] === "inherit";
|
|
22174
22388
|
return syncSpawn({
|
|
22175
22389
|
command: resolved.file,
|
|
22176
22390
|
args: resolved.args,
|
|
22177
22391
|
cwd: options.cwd ?? defaultCwd(),
|
|
22178
|
-
|
|
22179
|
-
...input === void 0 ? {} : { input }
|
|
22392
|
+
env: environmentFor(options),
|
|
22393
|
+
...input === void 0 ? {} : { input },
|
|
22394
|
+
...inherit ? { inheritStdio: true } : {}
|
|
22180
22395
|
});
|
|
22181
22396
|
};
|
|
22182
22397
|
const asOutput = (text2, options) => options.encoding === "buffer" || options.encoding === void 0 ? Buffer2.from(text2) : text2;
|
|
@@ -22228,7 +22443,7 @@ function unavailable(name) {
|
|
|
22228
22443
|
const list = Array.isArray(args[1]) ? args[1].map(String) : [];
|
|
22229
22444
|
const command = file3 ? [file3, ...list].join(" ") : void 0;
|
|
22230
22445
|
const error = new Error(
|
|
22231
|
-
`child_process.${name} is not supported in the sandboxed runtime` + (command ? ` (tried to run: ${command})` : "") + `: the caller, the child and the event loop share one thread, so blocking the caller would also stop the child.
|
|
22446
|
+
`child_process.${name} is not supported in the sandboxed runtime` + (command ? ` (tried to run: ${command})` : "") + `: the caller, the child and the event loop share one thread, so blocking the caller would also stop the child. Enable the SandboxedJs worker runtime with createContainer({ isolation: "worker" }) and fix any boot prerequisite it reports. ` + (syncChannelUnavailableReason() ?? "This process is using the realm runtime, which cannot provide synchronous child processes.")
|
|
22232
22447
|
);
|
|
22233
22448
|
error.code = "ERR_FEATURE_UNAVAILABLE_ON_PLATFORM";
|
|
22234
22449
|
throw error;
|
|
@@ -22516,6 +22731,11 @@ function createReadlineModule(defaultInput, defaultOutput = () => void 0) {
|
|
|
22516
22731
|
edit(sequence, key) {
|
|
22517
22732
|
if (this.closed) return;
|
|
22518
22733
|
const name = key.name;
|
|
22734
|
+
if (key.ctrl && name === "c") {
|
|
22735
|
+
if (this.listenerCount("SIGINT") > 0) this.emit("SIGINT");
|
|
22736
|
+
else this.close();
|
|
22737
|
+
return;
|
|
22738
|
+
}
|
|
22519
22739
|
if (name === "return" || name === "enter") {
|
|
22520
22740
|
const value = this.line;
|
|
22521
22741
|
this.line = "";
|
|
@@ -22611,7 +22831,7 @@ function createReadlineModule(defaultInput, defaultOutput = () => void 0) {
|
|
|
22611
22831
|
};
|
|
22612
22832
|
const createInterface = (options, output) => {
|
|
22613
22833
|
if (options && typeof options === "object" && !options.on) {
|
|
22614
|
-
const resolvedOutput2 = options.output
|
|
22834
|
+
const resolvedOutput2 = options.output;
|
|
22615
22835
|
const instance = new Interface(
|
|
22616
22836
|
options.input ?? defaultInput(),
|
|
22617
22837
|
resolvedOutput2,
|
|
@@ -22620,7 +22840,7 @@ function createReadlineModule(defaultInput, defaultOutput = () => void 0) {
|
|
|
22620
22840
|
if (typeof options.prompt === "string") instance.setPrompt(options.prompt);
|
|
22621
22841
|
return instance;
|
|
22622
22842
|
}
|
|
22623
|
-
const resolvedOutput = output
|
|
22843
|
+
const resolvedOutput = output;
|
|
22624
22844
|
return new Interface(options ?? defaultInput(), resolvedOutput, isTerminal(void 0, resolvedOutput));
|
|
22625
22845
|
};
|
|
22626
22846
|
const noop = () => {
|
|
@@ -22856,7 +23076,7 @@ function createCoreModules(options) {
|
|
|
22856
23076
|
};
|
|
22857
23077
|
const http = options.http ? createHttpModule(options.http.router, options.http.owner, httpOptions, "http:") : createUnsupportedModule("http");
|
|
22858
23078
|
const https = options.http ? createHttpModule(options.http.router, options.http.owner, httpOptions, "https:") : createUnsupportedModule("https");
|
|
22859
|
-
const childProcess = options.spawnChild ? createChildProcessModule(options.spawnChild, () => cwd, options.syncSpawn) : createUnsupportedModule("child_process");
|
|
23079
|
+
const childProcess = options.spawnChild ? createChildProcessModule(options.spawnChild, () => cwd, options.syncSpawn, () => ({ ...processObject.env })) : createUnsupportedModule("child_process");
|
|
22860
23080
|
const readline = createReadlineModule(() => processObject.stdin, () => processObject.stdout);
|
|
22861
23081
|
const dns = createDnsModule();
|
|
22862
23082
|
const builtins = {
|
|
@@ -22889,7 +23109,7 @@ function createCoreModules(options) {
|
|
|
22889
23109
|
"stream/promises": createStreamPromises(),
|
|
22890
23110
|
string_decoder: stringDecoderModule,
|
|
22891
23111
|
timers: { ...timersModule, ...timers.api },
|
|
22892
|
-
"timers/promises": createTimerPromises(),
|
|
23112
|
+
"timers/promises": createTimerPromises(timers.api),
|
|
22893
23113
|
tty: { isatty: () => false, ReadStream: streamModule4.Readable, WriteStream: streamModule4.Writable },
|
|
22894
23114
|
url: url_module_default,
|
|
22895
23115
|
util: util_module_default,
|
|
@@ -23634,10 +23854,10 @@ function createTrackedTimers() {
|
|
|
23634
23854
|
cancelAll
|
|
23635
23855
|
};
|
|
23636
23856
|
}
|
|
23637
|
-
function createTimerPromises() {
|
|
23857
|
+
function createTimerPromises(timers) {
|
|
23638
23858
|
return {
|
|
23639
|
-
setTimeout: (delay, value) => new Promise((resolve2) => setTimeout(resolve2, delay, value)),
|
|
23640
|
-
setImmediate: (value) => new Promise((resolve2) =>
|
|
23859
|
+
setTimeout: (delay, value) => new Promise((resolve2) => timers.setTimeout(resolve2, delay, value)),
|
|
23860
|
+
setImmediate: (value) => new Promise((resolve2) => timers.setImmediate(resolve2, value))
|
|
23641
23861
|
};
|
|
23642
23862
|
}
|
|
23643
23863
|
function createAsyncHooksModule() {
|
|
@@ -24101,8 +24321,10 @@ var MirroringVolume = class {
|
|
|
24101
24321
|
* container pays nothing for this.
|
|
24102
24322
|
*/
|
|
24103
24323
|
attach(mirror, root) {
|
|
24324
|
+
const cleanRoot = clean(root);
|
|
24325
|
+
if (this.mirror === mirror && this.root === cleanRoot) return;
|
|
24104
24326
|
this.mirror = mirror;
|
|
24105
|
-
this.root =
|
|
24327
|
+
this.root = cleanRoot;
|
|
24106
24328
|
this.seed();
|
|
24107
24329
|
}
|
|
24108
24330
|
detach() {
|
|
@@ -24343,11 +24565,8 @@ function ensureProcessGlobal() {
|
|
|
24343
24565
|
// src/runtime/host-rolldown.ts
|
|
24344
24566
|
var BUNDLER_HINT = "If this is a bundler pre-bundling the worker away, exclude the binding from dependency optimisation \u2014 in Vite:\n\n optimizeDeps: { exclude: ['@rolldown/binding-wasm32-wasi'] }";
|
|
24345
24567
|
async function loadHostRolldownBinding() {
|
|
24346
|
-
|
|
24347
|
-
|
|
24348
|
-
"Vite 8/Rolldown requires cross-origin isolation. Serve the app with Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp headers."
|
|
24349
|
-
);
|
|
24350
|
-
}
|
|
24568
|
+
const reason = syncChannelUnavailableReason();
|
|
24569
|
+
if (reason) throw new Error(`SandboxedJs threaded WASM unavailable: ${reason}`);
|
|
24351
24570
|
try {
|
|
24352
24571
|
const loaded = await import('@rolldown/binding-wasm32-wasi');
|
|
24353
24572
|
return "__fs" in loaded ? { ...loaded } : loaded.default ?? loaded;
|
|
@@ -24355,9 +24574,9 @@ async function loadHostRolldownBinding() {
|
|
|
24355
24574
|
if (typeof process !== "undefined" && process.env?.SANDBOXEDJS_DEBUG) {
|
|
24356
24575
|
console.error("[sandboxedjs] Rolldown WASI binding unavailable:", error);
|
|
24357
24576
|
}
|
|
24358
|
-
const
|
|
24577
|
+
const reason2 = error instanceof Error ? error.message : String(error);
|
|
24359
24578
|
throw new Error(
|
|
24360
|
-
`The optional Rolldown WASI binding could not be loaded: ${
|
|
24579
|
+
`The optional Rolldown WASI binding could not be loaded: ${reason2}` + (typeof window === "undefined" ? "" : `
|
|
24361
24580
|
|
|
24362
24581
|
${BUNDLER_HINT}`),
|
|
24363
24582
|
{ cause: error }
|
|
@@ -24468,6 +24687,8 @@ var LocalProcess = class extends EventEmitter4 {
|
|
|
24468
24687
|
}
|
|
24469
24688
|
/** End the process now, for an asynchronous `process.exit`. */
|
|
24470
24689
|
exitNow(code) {
|
|
24690
|
+
this.killed = true;
|
|
24691
|
+
this.cleanup?.();
|
|
24471
24692
|
this.finish(code);
|
|
24472
24693
|
this.resolveKilled();
|
|
24473
24694
|
}
|
|
@@ -24651,6 +24872,7 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24651
24872
|
)
|
|
24652
24873
|
};
|
|
24653
24874
|
disposed = false;
|
|
24875
|
+
running = /* @__PURE__ */ new Set();
|
|
24654
24876
|
workdir;
|
|
24655
24877
|
env;
|
|
24656
24878
|
aliases;
|
|
@@ -24692,8 +24914,9 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24692
24914
|
const cwd = typeof options.cwd === "string" ? options.cwd : this.workdir;
|
|
24693
24915
|
const env2 = { ...this.env, ...isRecord(options.env) ? options.env : {} };
|
|
24694
24916
|
const owner = `${this.instanceId}:${Math.random().toString(36).slice(2)}`;
|
|
24695
|
-
|
|
24917
|
+
const process2 = new LocalProcess(async (proc) => {
|
|
24696
24918
|
await this.prepareRolldown(cwd, env2);
|
|
24919
|
+
if (proc.isKilled()) return 137;
|
|
24697
24920
|
const untrack = trackProcess(proc);
|
|
24698
24921
|
let requestedExit = 0;
|
|
24699
24922
|
let engine;
|
|
@@ -24721,7 +24944,9 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24721
24944
|
onRawMode: (enabled) => proc.emit("rawmode", enabled)
|
|
24722
24945
|
});
|
|
24723
24946
|
proc.acceptInput((data) => core.writeStdin(data), () => core.endStdin());
|
|
24947
|
+
const hostWork = new HostModuleTracker();
|
|
24724
24948
|
proc.onKill(() => {
|
|
24949
|
+
hostWork.dispose();
|
|
24725
24950
|
core.cancelTimers();
|
|
24726
24951
|
this.router.closeOwner(owner);
|
|
24727
24952
|
});
|
|
@@ -24730,21 +24955,22 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24730
24955
|
builtins: core.builtins,
|
|
24731
24956
|
globals: core.globals,
|
|
24732
24957
|
aliases: this.aliases,
|
|
24733
|
-
overrides: this.modules
|
|
24958
|
+
overrides: Object.fromEntries(Object.entries(this.modules).map(([key, value]) => [key, hostWork.wrap(value)]))
|
|
24734
24959
|
});
|
|
24735
24960
|
try {
|
|
24736
|
-
await engine.run(script);
|
|
24737
|
-
await this.settle(owner, core.pendingHandles, core.
|
|
24738
|
-
if (this.router.activePorts(owner).length) {
|
|
24739
|
-
await proc.waitForKill();
|
|
24740
|
-
return 137;
|
|
24741
|
-
}
|
|
24961
|
+
await Promise.race([engine.run(script), proc.waitForKill()]);
|
|
24962
|
+
await this.settle(owner, core.pendingHandles, core.readingStdin, () => core.pendingRequests() + hostWork.pending(), () => proc.isKilled());
|
|
24742
24963
|
return requestedExit;
|
|
24743
24964
|
} finally {
|
|
24965
|
+
hostWork.dispose();
|
|
24966
|
+
core.cancelTimers();
|
|
24744
24967
|
untrack();
|
|
24745
24968
|
this.router.closeOwner(owner);
|
|
24746
24969
|
}
|
|
24747
24970
|
});
|
|
24971
|
+
this.running.add(process2);
|
|
24972
|
+
void process2.completion.then(() => this.running.delete(process2));
|
|
24973
|
+
return process2;
|
|
24748
24974
|
}
|
|
24749
24975
|
/**
|
|
24750
24976
|
* Rolldown's JavaScript API synchronously requires its compiled binding.
|
|
@@ -24780,19 +25006,13 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24780
25006
|
* A plain script that has genuinely finished falls straight through both,
|
|
24781
25007
|
* costing a handful of empty turns.
|
|
24782
25008
|
*/
|
|
24783
|
-
async settle(owner, pendingHandles,
|
|
24784
|
-
|
|
24785
|
-
|
|
24786
|
-
|
|
24787
|
-
|
|
24788
|
-
|
|
24789
|
-
|
|
24790
|
-
while (!this.router.activePorts(owner).length && !killed() && Date.now() < deadline) {
|
|
24791
|
-
await new Promise((resolve2) => setTimeout(resolve2, 5));
|
|
24792
|
-
}
|
|
24793
|
-
}
|
|
24794
|
-
while (!this.router.activePorts(owner).length && !killed() && (pendingHandles() > 0 || pendingRequests() > 0 || readingStdin())) {
|
|
24795
|
-
await new Promise((resolve2) => setTimeout(resolve2, 5));
|
|
25009
|
+
async settle(owner, pendingHandles, readingStdin, pendingRequests, killed) {
|
|
25010
|
+
let idleTurns = 0;
|
|
25011
|
+
while (!killed()) {
|
|
25012
|
+
const busy = this.router.referencedPorts(owner).length > 0 || pendingHandles() > 0 || pendingRequests() > 0 || readingStdin();
|
|
25013
|
+
idleTurns = busy ? 0 : idleTurns + 1;
|
|
25014
|
+
if (idleTurns >= DRAIN_TURNS) return;
|
|
25015
|
+
await new Promise((resolve2) => setTimeout(resolve2, busy ? 5 : 0));
|
|
24796
25016
|
}
|
|
24797
25017
|
}
|
|
24798
25018
|
async request(_port, _init = {}) {
|
|
@@ -24809,6 +25029,8 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24809
25029
|
}
|
|
24810
25030
|
teardown() {
|
|
24811
25031
|
this.disposed = true;
|
|
25032
|
+
for (const process2 of this.running) process2.kill();
|
|
25033
|
+
this.running.clear();
|
|
24812
25034
|
this.router.closeAll();
|
|
24813
25035
|
this.esbuild?.stop();
|
|
24814
25036
|
}
|
|
@@ -24878,103 +25100,6 @@ function attachRolldownMirror(binding, volume, root) {
|
|
|
24878
25100
|
volume.attach(fs, root);
|
|
24879
25101
|
}
|
|
24880
25102
|
|
|
24881
|
-
// src/runtime/sync-channel.ts
|
|
24882
|
-
var STATE = 0;
|
|
24883
|
-
var LENGTH = 1;
|
|
24884
|
-
var MORE = 2;
|
|
24885
|
-
var CONTROL_WORDS = 4;
|
|
24886
|
-
var STATE_REQUEST = 1;
|
|
24887
|
-
var STATE_RESPONSE = 2;
|
|
24888
|
-
var STATE_CONTINUE = 3;
|
|
24889
|
-
var STATE_CLOSED = 4;
|
|
24890
|
-
function createSyncChannelBuffers(capacityBytes = 1 << 20) {
|
|
24891
|
-
return {
|
|
24892
|
-
control: new SharedArrayBuffer(CONTROL_WORDS * Int32Array.BYTES_PER_ELEMENT),
|
|
24893
|
-
data: new SharedArrayBuffer(capacityBytes)
|
|
24894
|
-
};
|
|
24895
|
-
}
|
|
24896
|
-
function syncChannelSupported() {
|
|
24897
|
-
if (typeof SharedArrayBuffer !== "function") return false;
|
|
24898
|
-
if (typeof Atomics !== "object" || typeof Atomics.wait !== "function") return false;
|
|
24899
|
-
if (typeof window !== "undefined" && globalThis.crossOriginIsolated !== true) return false;
|
|
24900
|
-
return true;
|
|
24901
|
-
}
|
|
24902
|
-
var SyncChannelServer = class {
|
|
24903
|
-
constructor(buffers, handle) {
|
|
24904
|
-
this.handle = handle;
|
|
24905
|
-
this.control = new Int32Array(buffers.control);
|
|
24906
|
-
this.data = new Uint8Array(buffers.data);
|
|
24907
|
-
this.capacity = this.data.length;
|
|
24908
|
-
}
|
|
24909
|
-
handle;
|
|
24910
|
-
control;
|
|
24911
|
-
data;
|
|
24912
|
-
capacity;
|
|
24913
|
-
/** Request chunks gathered so far, and the response still to be sent. */
|
|
24914
|
-
incoming = [];
|
|
24915
|
-
outgoing = null;
|
|
24916
|
-
sent = 0;
|
|
24917
|
-
closed = false;
|
|
24918
|
-
/** Call from the wake message the client sends after each chunk. */
|
|
24919
|
-
async pump() {
|
|
24920
|
-
if (this.closed) return;
|
|
24921
|
-
const state = Atomics.load(this.control, STATE);
|
|
24922
|
-
if (state === STATE_REQUEST) {
|
|
24923
|
-
const size = Atomics.load(this.control, LENGTH);
|
|
24924
|
-
this.incoming.push(this.data.slice(0, size));
|
|
24925
|
-
if (Atomics.load(this.control, MORE) === 1) {
|
|
24926
|
-
this.publish(STATE_CONTINUE);
|
|
24927
|
-
return;
|
|
24928
|
-
}
|
|
24929
|
-
const request = concat3(this.incoming);
|
|
24930
|
-
this.incoming = [];
|
|
24931
|
-
let response;
|
|
24932
|
-
try {
|
|
24933
|
-
response = await this.handle(request);
|
|
24934
|
-
} catch {
|
|
24935
|
-
response = new Uint8Array();
|
|
24936
|
-
}
|
|
24937
|
-
if (this.closed) return;
|
|
24938
|
-
this.outgoing = response;
|
|
24939
|
-
this.sent = 0;
|
|
24940
|
-
this.sendChunk();
|
|
24941
|
-
return;
|
|
24942
|
-
}
|
|
24943
|
-
if (state === STATE_CONTINUE) this.sendChunk();
|
|
24944
|
-
}
|
|
24945
|
-
/** Release a blocked client, e.g. when the container is torn down. */
|
|
24946
|
-
close() {
|
|
24947
|
-
if (this.closed) return;
|
|
24948
|
-
this.closed = true;
|
|
24949
|
-
Atomics.store(this.control, STATE, STATE_CLOSED);
|
|
24950
|
-
Atomics.notify(this.control, STATE);
|
|
24951
|
-
}
|
|
24952
|
-
sendChunk() {
|
|
24953
|
-
const payload = this.outgoing ?? new Uint8Array();
|
|
24954
|
-
const size = Math.min(this.capacity, payload.length - this.sent);
|
|
24955
|
-
this.data.set(payload.subarray(this.sent, this.sent + size), 0);
|
|
24956
|
-
this.sent += size;
|
|
24957
|
-
Atomics.store(this.control, LENGTH, size);
|
|
24958
|
-
Atomics.store(this.control, MORE, this.sent < payload.length ? 1 : 0);
|
|
24959
|
-
this.publish(STATE_RESPONSE);
|
|
24960
|
-
}
|
|
24961
|
-
publish(state) {
|
|
24962
|
-
Atomics.store(this.control, STATE, state);
|
|
24963
|
-
Atomics.notify(this.control, STATE);
|
|
24964
|
-
}
|
|
24965
|
-
};
|
|
24966
|
-
function concat3(parts) {
|
|
24967
|
-
if (parts.length === 1) return parts[0];
|
|
24968
|
-
const total = parts.reduce((sum, part) => sum + part.length, 0);
|
|
24969
|
-
const joined = new Uint8Array(total);
|
|
24970
|
-
let at = 0;
|
|
24971
|
-
for (const part of parts) {
|
|
24972
|
-
joined.set(part, at);
|
|
24973
|
-
at += part.length;
|
|
24974
|
-
}
|
|
24975
|
-
return joined;
|
|
24976
|
-
}
|
|
24977
|
-
|
|
24978
25103
|
// src/runtime/remote-volume.ts
|
|
24979
25104
|
var encoder7 = new TextEncoder();
|
|
24980
25105
|
var decoder7 = new TextDecoder();
|
|
@@ -25069,24 +25194,32 @@ function defaultWorkerUrl() {
|
|
|
25069
25194
|
return new URL("./worker-entry.js", import.meta.url);
|
|
25070
25195
|
}
|
|
25071
25196
|
function hasDomWorker() {
|
|
25072
|
-
return typeof Worker === "function"
|
|
25197
|
+
return typeof Worker === "function";
|
|
25073
25198
|
}
|
|
25074
25199
|
async function startRuntimeWorker(options = {}) {
|
|
25075
25200
|
const url = options.url ?? defaultWorkerUrl();
|
|
25076
25201
|
const worker = hasDomWorker() ? await startDomWorker(url) : await startNodeWorker(url, options.workerData ?? {});
|
|
25077
|
-
|
|
25078
|
-
|
|
25079
|
-
|
|
25080
|
-
|
|
25202
|
+
try {
|
|
25203
|
+
await new Promise((resolve2, reject) => {
|
|
25204
|
+
const timer = setTimeout(() => reject(new Error("the runtime worker did not start in time")), options.timeoutMs ?? 1e4);
|
|
25205
|
+
worker.onMessage((message) => {
|
|
25206
|
+
if (message?.type === "sandboxedjs:ready") {
|
|
25207
|
+
clearTimeout(timer);
|
|
25208
|
+
resolve2();
|
|
25209
|
+
}
|
|
25210
|
+
});
|
|
25211
|
+
worker.onError((error) => {
|
|
25081
25212
|
clearTimeout(timer);
|
|
25082
|
-
|
|
25083
|
-
}
|
|
25084
|
-
});
|
|
25085
|
-
worker.onError((error) => {
|
|
25086
|
-
clearTimeout(timer);
|
|
25087
|
-
reject(error instanceof Error ? error : new Error(String(error)));
|
|
25213
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
25214
|
+
});
|
|
25088
25215
|
});
|
|
25089
|
-
})
|
|
25216
|
+
} catch (error) {
|
|
25217
|
+
try {
|
|
25218
|
+
await worker.terminate();
|
|
25219
|
+
} catch {
|
|
25220
|
+
}
|
|
25221
|
+
throw error;
|
|
25222
|
+
}
|
|
25090
25223
|
return worker;
|
|
25091
25224
|
}
|
|
25092
25225
|
async function startDomWorker(url) {
|
|
@@ -25147,6 +25280,8 @@ var WorkerProcess = class extends EventEmitter4 {
|
|
|
25147
25280
|
started = false;
|
|
25148
25281
|
pendingInput = [];
|
|
25149
25282
|
inputEnded = false;
|
|
25283
|
+
inheritedInput;
|
|
25284
|
+
ownRawMode = false;
|
|
25150
25285
|
on(event, listener) {
|
|
25151
25286
|
return super.on(event, listener);
|
|
25152
25287
|
}
|
|
@@ -25172,13 +25307,38 @@ var WorkerProcess = class extends EventEmitter4 {
|
|
|
25172
25307
|
* program is still loading, and dropping them loses the answer to a prompt.
|
|
25173
25308
|
*/
|
|
25174
25309
|
write(data) {
|
|
25310
|
+
if (this.inheritedInput) {
|
|
25311
|
+
this.inheritedInput.sendStdin(data);
|
|
25312
|
+
return;
|
|
25313
|
+
}
|
|
25175
25314
|
if (this.started) this.worker.postMessage({ type: "stdin", data });
|
|
25176
25315
|
else this.pendingInput.push(data);
|
|
25177
25316
|
}
|
|
25178
25317
|
endInput() {
|
|
25179
25318
|
this.inputEnded = true;
|
|
25319
|
+
if (this.inheritedInput) {
|
|
25320
|
+
this.inheritedInput.endStdin?.();
|
|
25321
|
+
return;
|
|
25322
|
+
}
|
|
25180
25323
|
if (this.started) this.worker.postMessage({ type: "stdin-end" });
|
|
25181
25324
|
}
|
|
25325
|
+
rawMode(enabled) {
|
|
25326
|
+
this.ownRawMode = enabled;
|
|
25327
|
+
if (!this.inheritedInput) this.emit("rawmode", enabled);
|
|
25328
|
+
}
|
|
25329
|
+
/** The parent is blocked in Atomics.wait, so inherited input must bypass it. */
|
|
25330
|
+
inheritInput(child) {
|
|
25331
|
+
this.inheritedInput = child;
|
|
25332
|
+
this.emit("rawmode", false);
|
|
25333
|
+
child.on("rawmode", (enabled) => {
|
|
25334
|
+
if (this.inheritedInput === child) this.emit("rawmode", Boolean(enabled));
|
|
25335
|
+
});
|
|
25336
|
+
return () => {
|
|
25337
|
+
if (this.inheritedInput !== child) return;
|
|
25338
|
+
this.inheritedInput = void 0;
|
|
25339
|
+
this.emit("rawmode", this.ownRawMode);
|
|
25340
|
+
};
|
|
25341
|
+
}
|
|
25182
25342
|
kill(_signal = "SIGTERM") {
|
|
25183
25343
|
this.worker.postMessage({ type: "kill" });
|
|
25184
25344
|
this.finish(137);
|
|
@@ -25199,25 +25359,30 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25199
25359
|
super(options);
|
|
25200
25360
|
this.workerUrl = options.workerUrl;
|
|
25201
25361
|
}
|
|
25202
|
-
/**
|
|
25203
|
-
|
|
25204
|
-
|
|
25205
|
-
|
|
25206
|
-
|
|
25207
|
-
|
|
25208
|
-
|
|
25209
|
-
* and keeps working.
|
|
25210
|
-
*/
|
|
25211
|
-
static async tryBoot(options = {}) {
|
|
25212
|
-
if (!syncChannelSupported()) return null;
|
|
25213
|
-
if (options.modules && Object.keys(options.modules).length > 0) return null;
|
|
25362
|
+
/** Boot without silently dropping synchronous child-process support. */
|
|
25363
|
+
static async boot(options = {}) {
|
|
25364
|
+
const reason = syncChannelUnavailableReason();
|
|
25365
|
+
if (reason) throw new Error(`SandboxedJs worker runtime unavailable: ${reason}`);
|
|
25366
|
+
if (options.modules && Object.keys(options.modules).length > 0) {
|
|
25367
|
+
throw new Error("SandboxedJs worker runtime cannot clone host-supplied modules. Use isolation: 'realm' explicitly.");
|
|
25368
|
+
}
|
|
25214
25369
|
const pod = new _WorkerRuntimePod(options);
|
|
25215
25370
|
try {
|
|
25216
25371
|
const probe = await startRuntimeWorker({ ...options.workerUrl ? { url: options.workerUrl } : {}, timeoutMs: 1e4 });
|
|
25217
25372
|
await probe.terminate();
|
|
25218
25373
|
return pod;
|
|
25219
|
-
} catch {
|
|
25374
|
+
} catch (cause) {
|
|
25220
25375
|
pod.teardown();
|
|
25376
|
+
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
25377
|
+
throw new Error(`SandboxedJs guest worker failed to start: ${detail}. Check that worker-entry.js is served as JavaScript; set workerUrl if your bundler moved it.`, { cause });
|
|
25378
|
+
}
|
|
25379
|
+
}
|
|
25380
|
+
/** Compatibility mode, with an observable explanation for every fallback. */
|
|
25381
|
+
static async tryBoot(options = {}, onFallback = (error) => console.warn(`[sandboxedjs] Falling back to the realm runtime; synchronous child processes are unavailable. ${error.message}`)) {
|
|
25382
|
+
try {
|
|
25383
|
+
return await _WorkerRuntimePod.boot(options);
|
|
25384
|
+
} catch (error) {
|
|
25385
|
+
onFallback(error instanceof Error ? error : new Error(String(error)));
|
|
25221
25386
|
return null;
|
|
25222
25387
|
}
|
|
25223
25388
|
}
|
|
@@ -25237,18 +25402,23 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25237
25402
|
...this.workerUrl ? { url: this.workerUrl } : {},
|
|
25238
25403
|
timeoutMs: 15e3
|
|
25239
25404
|
});
|
|
25405
|
+
const streams = { target: null };
|
|
25240
25406
|
const server = new SyncChannelServer(buffers, serveSyncSyscalls({
|
|
25241
25407
|
volume: this.volume,
|
|
25242
|
-
spawnChild: (request) => this.runChildToCompletion(request)
|
|
25408
|
+
spawnChild: (request) => this.runChildToCompletion(request, streams.target, ownedChildren)
|
|
25243
25409
|
}));
|
|
25244
25410
|
const entry = { worker, server };
|
|
25245
25411
|
this.live.add(entry);
|
|
25412
|
+
const ownedChildren = /* @__PURE__ */ new Set();
|
|
25246
25413
|
const process2 = new WorkerProcess(worker, () => {
|
|
25414
|
+
for (const child of ownedChildren) child.kill("SIGTERM");
|
|
25415
|
+
ownedChildren.clear();
|
|
25247
25416
|
this.live.delete(entry);
|
|
25248
25417
|
server.close();
|
|
25249
25418
|
this.closeProxies(owner);
|
|
25250
25419
|
void worker.terminate();
|
|
25251
25420
|
});
|
|
25421
|
+
streams.target = process2;
|
|
25252
25422
|
const children = /* @__PURE__ */ new Map();
|
|
25253
25423
|
worker.onMessage((raw) => {
|
|
25254
25424
|
const message = raw;
|
|
@@ -25263,7 +25433,7 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25263
25433
|
process2.error(String(message.text));
|
|
25264
25434
|
return;
|
|
25265
25435
|
case "rawmode":
|
|
25266
|
-
process2.
|
|
25436
|
+
process2.rawMode(Boolean(message.enabled));
|
|
25267
25437
|
return;
|
|
25268
25438
|
case "exit":
|
|
25269
25439
|
process2.finish(Number(message.code));
|
|
@@ -25271,11 +25441,20 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25271
25441
|
case "listen":
|
|
25272
25442
|
this.proxyPort(Number(message.port), owner, worker);
|
|
25273
25443
|
return;
|
|
25444
|
+
case "close-port": {
|
|
25445
|
+
const port = Number(message.port);
|
|
25446
|
+
const proxy = this.proxies.get(port);
|
|
25447
|
+
if (proxy?.owner === owner) {
|
|
25448
|
+
proxy.close();
|
|
25449
|
+
this.proxies.delete(port);
|
|
25450
|
+
}
|
|
25451
|
+
return;
|
|
25452
|
+
}
|
|
25274
25453
|
case "http-response":
|
|
25275
25454
|
this.settleProxied(Number(message.id), message.response);
|
|
25276
25455
|
return;
|
|
25277
25456
|
case "child-start":
|
|
25278
|
-
this.startChild(worker, children, message);
|
|
25457
|
+
this.startChild(worker, children, message, ownedChildren);
|
|
25279
25458
|
return;
|
|
25280
25459
|
case "child-stdin":
|
|
25281
25460
|
children.get(message.id)?.sendStdin?.(String(message.data));
|
|
@@ -25306,16 +25485,21 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25306
25485
|
return process2;
|
|
25307
25486
|
}
|
|
25308
25487
|
/** Start an asynchronous child on the host's behalf and relay its events. */
|
|
25309
|
-
startChild(worker, children, message) {
|
|
25488
|
+
startChild(worker, children, message, owned) {
|
|
25310
25489
|
const handle = this.processManager.spawn(message.config);
|
|
25311
25490
|
children.set(message.id, handle);
|
|
25491
|
+
owned.add(handle);
|
|
25492
|
+
handle.on("exit", () => {
|
|
25493
|
+
owned.delete(handle);
|
|
25494
|
+
children.delete(message.id);
|
|
25495
|
+
});
|
|
25312
25496
|
for (const event of ["stdout", "stderr", "exit"]) {
|
|
25313
25497
|
handle.on(event, (value) => worker.postMessage({ type: "child-event", id: message.id, event, value }));
|
|
25314
25498
|
}
|
|
25315
25499
|
handle.exec();
|
|
25316
25500
|
}
|
|
25317
25501
|
/** Run a child to completion and collect it, for the guest's `spawnSync`. */
|
|
25318
|
-
runChildToCompletion(request) {
|
|
25502
|
+
runChildToCompletion(request, streamTo, owned) {
|
|
25319
25503
|
return new Promise((resolve2) => {
|
|
25320
25504
|
let handle;
|
|
25321
25505
|
try {
|
|
@@ -25323,27 +25507,35 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25323
25507
|
command: request.command,
|
|
25324
25508
|
args: request.args,
|
|
25325
25509
|
cwd: request.cwd,
|
|
25326
|
-
...request.env ? { env: request.env } : {}
|
|
25510
|
+
...request.env ? { env: request.env } : {},
|
|
25511
|
+
...request.inheritStdio ? { inheritStdio: true } : {}
|
|
25327
25512
|
});
|
|
25328
25513
|
} catch (error) {
|
|
25329
25514
|
const failure = error;
|
|
25330
25515
|
resolve2({ status: null, stdout: "", stderr: "", signal: null, error: { ...failure.code ? { code: failure.code } : {}, message: failure.message } });
|
|
25331
25516
|
return;
|
|
25332
25517
|
}
|
|
25518
|
+
owned.add(handle);
|
|
25519
|
+
handle.on("exit", () => owned.delete(handle));
|
|
25333
25520
|
let stdout = "";
|
|
25334
25521
|
let stderr = "";
|
|
25522
|
+
const live = request.inheritStdio ? streamTo : null;
|
|
25523
|
+
const restoreInput = live?.inheritInput(handle);
|
|
25524
|
+
if (restoreInput) handle.on("exit", restoreInput);
|
|
25335
25525
|
handle.on("stdout", (text2) => {
|
|
25336
25526
|
stdout += text2;
|
|
25527
|
+
live?.output(text2);
|
|
25337
25528
|
});
|
|
25338
25529
|
handle.on("stderr", (text2) => {
|
|
25339
25530
|
stderr += text2;
|
|
25531
|
+
live?.error(text2);
|
|
25340
25532
|
});
|
|
25341
25533
|
handle.on("exit", (code) => resolve2({ status: code, stdout, stderr, signal: null }));
|
|
25342
25534
|
handle.exec();
|
|
25343
25535
|
if (request.input !== void 0) {
|
|
25344
25536
|
handle.sendStdin?.(request.input);
|
|
25345
25537
|
}
|
|
25346
|
-
handle.endStdin?.();
|
|
25538
|
+
if (!request.inheritStdio) handle.endStdin?.();
|
|
25347
25539
|
});
|
|
25348
25540
|
}
|
|
25349
25541
|
// ── HTTP servers living on another thread ─────────────────────────────────
|
|
@@ -25483,7 +25675,7 @@ var Container = class _Container {
|
|
|
25483
25675
|
...opts.onServerReady ? { onServerReady: opts.onServerReady } : {}
|
|
25484
25676
|
};
|
|
25485
25677
|
const workerOptions = { ...podOptions, ...opts.workerUrl ? { workerUrl: opts.workerUrl } : {} };
|
|
25486
|
-
const pod = opts.pod ?? (opts.isolation === "realm" ? null : await WorkerRuntimePod.tryBoot(workerOptions)) ?? await LocalRuntimePod.boot(podOptions);
|
|
25678
|
+
const pod = opts.pod ?? (opts.isolation === "realm" ? null : opts.isolation === "worker" ? await WorkerRuntimePod.boot(workerOptions) : await WorkerRuntimePod.tryBoot(workerOptions, opts.onRuntimeFallback)) ?? await LocalRuntimePod.boot(podOptions);
|
|
25487
25679
|
const kernel = new Kernel({
|
|
25488
25680
|
pod,
|
|
25489
25681
|
hostname: opts.hostname ?? "sandbox",
|
|
@@ -25991,7 +26183,7 @@ var Terminal = class {
|
|
|
25991
26183
|
if (this.running) {
|
|
25992
26184
|
const raw = this.currentStdin?.rawMode === true;
|
|
25993
26185
|
if (ch === CTRL_C && !raw) {
|
|
25994
|
-
this.session.
|
|
26186
|
+
if (this.currentStdin) this.session.shell.interruptForeground("SIGINT", this.currentStdin);
|
|
25995
26187
|
this.write("^C\r\n");
|
|
25996
26188
|
return;
|
|
25997
26189
|
}
|
|
@@ -26344,8 +26536,99 @@ init_variables();
|
|
|
26344
26536
|
init_arith();
|
|
26345
26537
|
init_expand();
|
|
26346
26538
|
init_builtins();
|
|
26539
|
+
|
|
26540
|
+
// src/preview/register.ts
|
|
26541
|
+
function serveContainerOn(port, box) {
|
|
26542
|
+
port.onmessage = async (event) => {
|
|
26543
|
+
const request = event.data;
|
|
26544
|
+
try {
|
|
26545
|
+
const response = await box.request(request.port, {
|
|
26546
|
+
method: request.method,
|
|
26547
|
+
path: request.path,
|
|
26548
|
+
headers: request.headers,
|
|
26549
|
+
...request.body ? { body: new Uint8Array(request.body) } : {}
|
|
26550
|
+
});
|
|
26551
|
+
const bytes2 = response.bytes.slice();
|
|
26552
|
+
port.postMessage(
|
|
26553
|
+
{
|
|
26554
|
+
id: request.id,
|
|
26555
|
+
response: {
|
|
26556
|
+
status: response.status,
|
|
26557
|
+
statusText: response.statusText,
|
|
26558
|
+
headers: response.headers,
|
|
26559
|
+
body: bytes2.buffer
|
|
26560
|
+
}
|
|
26561
|
+
},
|
|
26562
|
+
[bytes2.buffer]
|
|
26563
|
+
);
|
|
26564
|
+
} catch (error) {
|
|
26565
|
+
const message = new TextEncoder().encode(error instanceof Error ? error.message : String(error));
|
|
26566
|
+
port.postMessage({
|
|
26567
|
+
id: request.id,
|
|
26568
|
+
response: { status: 502, statusText: "Bad Gateway", headers: {}, body: message.buffer }
|
|
26569
|
+
});
|
|
26570
|
+
}
|
|
26571
|
+
};
|
|
26572
|
+
port.start?.();
|
|
26573
|
+
}
|
|
26574
|
+
async function createPreview(box, options = {}) {
|
|
26575
|
+
if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) return null;
|
|
26576
|
+
const scriptUrl = options.scriptUrl ?? new URL("./service-worker.js?no-inline", import.meta.url);
|
|
26577
|
+
let registration;
|
|
26578
|
+
try {
|
|
26579
|
+
registration = await navigator.serviceWorker.register(scriptUrl, {
|
|
26580
|
+
type: "module",
|
|
26581
|
+
...options.scope ? { scope: options.scope } : {}
|
|
26582
|
+
});
|
|
26583
|
+
} catch {
|
|
26584
|
+
return null;
|
|
26585
|
+
}
|
|
26586
|
+
const worker = registration.active ?? registration.waiting ?? registration.installing;
|
|
26587
|
+
if (!worker) return null;
|
|
26588
|
+
if (worker.state !== "activated") {
|
|
26589
|
+
const activated = await new Promise((resolve2) => {
|
|
26590
|
+
const check = () => {
|
|
26591
|
+
if (worker.state === "activated") {
|
|
26592
|
+
worker.removeEventListener("statechange", check);
|
|
26593
|
+
resolve2(true);
|
|
26594
|
+
} else if (worker.state === "redundant") {
|
|
26595
|
+
worker.removeEventListener("statechange", check);
|
|
26596
|
+
resolve2(false);
|
|
26597
|
+
}
|
|
26598
|
+
};
|
|
26599
|
+
worker.addEventListener("statechange", check);
|
|
26600
|
+
setTimeout(() => resolve2(worker.state === "activated"), 1e4);
|
|
26601
|
+
check();
|
|
26602
|
+
});
|
|
26603
|
+
if (!activated) return null;
|
|
26604
|
+
}
|
|
26605
|
+
const channel = new MessageChannel();
|
|
26606
|
+
serveContainerOn(channel.port1, box);
|
|
26607
|
+
worker.postMessage({ type: "sandboxedjs:connect" }, [channel.port2]);
|
|
26608
|
+
const base2 = registration.scope.replace(/\/$/, "");
|
|
26609
|
+
return {
|
|
26610
|
+
urlFor: (port) => `${base2}/__sbx__/${port}/`,
|
|
26611
|
+
dispose: async () => {
|
|
26612
|
+
channel.port1.close();
|
|
26613
|
+
await registration.unregister();
|
|
26614
|
+
}
|
|
26615
|
+
};
|
|
26616
|
+
}
|
|
26617
|
+
async function renderInto(box, element, options = { port: 80 }) {
|
|
26618
|
+
const response = await box.request(options.port, { path: options.path ?? "/" });
|
|
26619
|
+
const frame = document.createElement("iframe");
|
|
26620
|
+
frame.setAttribute("sandbox", "allow-scripts");
|
|
26621
|
+
frame.style.width = "100%";
|
|
26622
|
+
frame.style.height = "100%";
|
|
26623
|
+
frame.style.border = "0";
|
|
26624
|
+
frame.srcdoc = response.body;
|
|
26625
|
+
element.replaceChildren(frame);
|
|
26626
|
+
return frame;
|
|
26627
|
+
}
|
|
26628
|
+
|
|
26629
|
+
// src/index.ts
|
|
26347
26630
|
var src_default = createContainer;
|
|
26348
26631
|
|
|
26349
|
-
export { ArithError, BufferSink, CallbackSink, CleanPackageInstaller, CommandRegistry, CommonJsEngine, Container, ContainerFs, ERRNO, FileInput, FileOutput, IncompleteInputError, KERNEL_NAME, KERNEL_RELEASE, Kernel, LocalRuntimePod, MemoryVolume, NODE_VERSION, NPM_VERSION, NetworkStack, NullInput, NullOutput, OS_RELEASE, PYTHON_VERSION, Pipe, Process, ProcessTable, ROOT_CRED, SIGNALS, SIGNAL_NAMES, Session, Shell, ShellExit, Lexer as ShellLexer, ShellSyntaxError, Stats, SysError, TeeOutput, Terminal, UserDatabase, Variables, Vfs, VirtualHttpRouter, VirtualHttpServer, VirtualIncomingMessage, VirtualServerResponse, WASM_ALIASES, allCommands, applyChmod, braceExpand, buildRootfs, builtinNames, captureStdio, configureCPython, configurePython, createChildProcessModule, createContainer, createContext, createCoreModules, src_default as default, defineCommand, evalArith, exitCodeForSignal, expandPrompt, expandWord, expandWords, extractNpmTarball, fnmatch, formatMode, getBuiltin, glob, globToRegex, hasMagic, installUserland, isBuiltinName, isCPythonAvailable, isPythonAvailable, isSysError, looksLikeEsm, makeCred, normalizeSignal, octalMode, parse as parseShell, parseUmask, path_exports as posixPath, resetPidCounter, shellQuote, startRuntimeWorker, strerror, syncChannelSupported, transformEsm, unameInfo };
|
|
26632
|
+
export { ArithError, BufferSink, CallbackSink, CleanPackageInstaller, CommandRegistry, CommonJsEngine, Container, ContainerFs, ERRNO, FileInput, FileOutput, IncompleteInputError, KERNEL_NAME, KERNEL_RELEASE, Kernel, LocalRuntimePod, MemoryVolume, NODE_VERSION, NPM_VERSION, NetworkStack, NullInput, NullOutput, OS_RELEASE, PYTHON_VERSION, Pipe, Process, ProcessTable, ROOT_CRED, SIGNALS, SIGNAL_NAMES, Session, Shell, ShellExit, Lexer as ShellLexer, ShellSyntaxError, Stats, SysError, TeeOutput, Terminal, UserDatabase, Variables, Vfs, VirtualHttpRouter, VirtualHttpServer, VirtualIncomingMessage, VirtualServerResponse, WASM_ALIASES, WorkerRuntimePod, allCommands, applyChmod, braceExpand, buildRootfs, builtinNames, captureStdio, configureCPython, configurePython, createChildProcessModule, createContainer, createContext, createCoreModules, createPreview, src_default as default, defineCommand, evalArith, exitCodeForSignal, expandPrompt, expandWord, expandWords, extractNpmTarball, fnmatch, formatMode, getBuiltin, glob, globToRegex, hasMagic, installUserland, isBuiltinName, isCPythonAvailable, isPythonAvailable, isSysError, looksLikeEsm, makeCred, normalizeSignal, octalMode, parse as parseShell, parseUmask, path_exports as posixPath, renderInto, resetPidCounter, shellQuote, startRuntimeWorker, strerror, syncChannelSupported, transformEsm, unameInfo };
|
|
26350
26633
|
//# sourceMappingURL=index.js.map
|
|
26351
26634
|
//# sourceMappingURL=index.js.map
|