sandboxedjs 0.1.30 → 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/README.md +85 -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 +346 -169
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -26
- package/dist/index.d.ts +26 -26
- package/dist/index.js +346 -169
- package/dist/index.js.map +1 -1
- package/dist/worker-entry.js +130 -109
- 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,
|
|
@@ -19699,6 +19730,7 @@ var KernelChildProcess = class {
|
|
|
19699
19730
|
this.stdin.isTTY = true;
|
|
19700
19731
|
this.stdin.interactive = true;
|
|
19701
19732
|
}
|
|
19733
|
+
this.stdin.onRawMode = (enabled) => this.emit("rawmode", enabled);
|
|
19702
19734
|
this.kernel = kernel;
|
|
19703
19735
|
this.cred = cred;
|
|
19704
19736
|
this.pid = pid;
|
|
@@ -19815,7 +19847,7 @@ function installNodeChildProcessBridge(pod, kernel, cred) {
|
|
|
19815
19847
|
const originalSpawn = manager.spawn;
|
|
19816
19848
|
manager.spawn = (config) => {
|
|
19817
19849
|
const resolved = kernel.resolveExecutable(config.command, config.cwd ?? "/", config.env ?? {}, cred);
|
|
19818
|
-
if (resolved?.kind === "builtin"
|
|
19850
|
+
if (resolved?.kind === "builtin") {
|
|
19819
19851
|
return new KernelChildProcess(kernel, cred, config, nextBridgePid++);
|
|
19820
19852
|
}
|
|
19821
19853
|
return originalSpawn.call(manager, config);
|
|
@@ -19826,6 +19858,68 @@ function installNodeChildProcessBridge(pod, kernel, cred) {
|
|
|
19826
19858
|
};
|
|
19827
19859
|
}
|
|
19828
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
|
+
|
|
19829
19923
|
// src/runtime/commonjs-engine.ts
|
|
19830
19924
|
init_path();
|
|
19831
19925
|
var HELPERS = {
|
|
@@ -21563,6 +21657,7 @@ var VirtualHttpServer = class extends EventEmitter4 {
|
|
|
21563
21657
|
owner;
|
|
21564
21658
|
listening = false;
|
|
21565
21659
|
portValue = null;
|
|
21660
|
+
referenced = true;
|
|
21566
21661
|
listen(...args) {
|
|
21567
21662
|
const callback = typeof args.at(-1) === "function" ? args.pop() : void 0;
|
|
21568
21663
|
const first = args[0];
|
|
@@ -21591,11 +21686,16 @@ var VirtualHttpServer = class extends EventEmitter4 {
|
|
|
21591
21686
|
return this.portValue === null ? null : { address: "0.0.0.0", family: "IPv4", port: this.portValue };
|
|
21592
21687
|
}
|
|
21593
21688
|
ref() {
|
|
21689
|
+
this.referenced = true;
|
|
21594
21690
|
return this;
|
|
21595
21691
|
}
|
|
21596
21692
|
unref() {
|
|
21693
|
+
this.referenced = false;
|
|
21597
21694
|
return this;
|
|
21598
21695
|
}
|
|
21696
|
+
hasRef() {
|
|
21697
|
+
return this.referenced;
|
|
21698
|
+
}
|
|
21599
21699
|
setTimeout(_milliseconds, callback) {
|
|
21600
21700
|
if (callback) this.on("timeout", callback);
|
|
21601
21701
|
return this;
|
|
@@ -21605,13 +21705,16 @@ var VirtualHttpRouter = class {
|
|
|
21605
21705
|
servers = /* @__PURE__ */ new Map();
|
|
21606
21706
|
/** Notified when a server begins listening, for `onServerReady`. */
|
|
21607
21707
|
onListen;
|
|
21708
|
+
onClose;
|
|
21608
21709
|
register(port, server, owner) {
|
|
21609
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 });
|
|
21610
21711
|
this.servers.set(port, { server, owner });
|
|
21611
21712
|
this.onListen?.(port);
|
|
21612
21713
|
}
|
|
21613
21714
|
unregister(port, server) {
|
|
21614
|
-
if (this.servers.get(port)?.server
|
|
21715
|
+
if (this.servers.get(port)?.server !== server) return;
|
|
21716
|
+
this.servers.delete(port);
|
|
21717
|
+
this.onClose?.(port);
|
|
21615
21718
|
}
|
|
21616
21719
|
/** Whether anything in this container is listening on `port`. */
|
|
21617
21720
|
activePortsIncludes(port) {
|
|
@@ -21620,6 +21723,9 @@ var VirtualHttpRouter = class {
|
|
|
21620
21723
|
activePorts(owner) {
|
|
21621
21724
|
return [...this.servers].filter(([, item]) => owner === void 0 || item.owner === owner).map(([port]) => port).sort((a, b) => a - b);
|
|
21622
21725
|
}
|
|
21726
|
+
referencedPorts(owner) {
|
|
21727
|
+
return [...this.servers].filter(([, item]) => item.owner === owner && item.server.hasRef()).map(([port]) => port);
|
|
21728
|
+
}
|
|
21623
21729
|
closeOwner(owner) {
|
|
21624
21730
|
for (const { server, owner: value } of [...this.servers.values()]) if (value === owner) server.close();
|
|
21625
21731
|
}
|
|
@@ -22031,6 +22137,108 @@ function hashFor(algorithm) {
|
|
|
22031
22137
|
function toBytes2(data, encoding) {
|
|
22032
22138
|
return typeof data === "string" ? Buffer2.from(data, encoding) : data;
|
|
22033
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
|
+
}
|
|
22034
22242
|
var ChildProcess = class extends EventEmitter4 {
|
|
22035
22243
|
stdout = new streamModule4.PassThrough();
|
|
22036
22244
|
stderr = new streamModule4.PassThrough();
|
|
@@ -22235,7 +22443,7 @@ function unavailable(name) {
|
|
|
22235
22443
|
const list = Array.isArray(args[1]) ? args[1].map(String) : [];
|
|
22236
22444
|
const command = file3 ? [file3, ...list].join(" ") : void 0;
|
|
22237
22445
|
const error = new Error(
|
|
22238
|
-
`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.")
|
|
22239
22447
|
);
|
|
22240
22448
|
error.code = "ERR_FEATURE_UNAVAILABLE_ON_PLATFORM";
|
|
22241
22449
|
throw error;
|
|
@@ -22523,6 +22731,11 @@ function createReadlineModule(defaultInput, defaultOutput = () => void 0) {
|
|
|
22523
22731
|
edit(sequence, key) {
|
|
22524
22732
|
if (this.closed) return;
|
|
22525
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
|
+
}
|
|
22526
22739
|
if (name === "return" || name === "enter") {
|
|
22527
22740
|
const value = this.line;
|
|
22528
22741
|
this.line = "";
|
|
@@ -22618,7 +22831,7 @@ function createReadlineModule(defaultInput, defaultOutput = () => void 0) {
|
|
|
22618
22831
|
};
|
|
22619
22832
|
const createInterface = (options, output) => {
|
|
22620
22833
|
if (options && typeof options === "object" && !options.on) {
|
|
22621
|
-
const resolvedOutput2 = options.output
|
|
22834
|
+
const resolvedOutput2 = options.output;
|
|
22622
22835
|
const instance = new Interface(
|
|
22623
22836
|
options.input ?? defaultInput(),
|
|
22624
22837
|
resolvedOutput2,
|
|
@@ -22627,7 +22840,7 @@ function createReadlineModule(defaultInput, defaultOutput = () => void 0) {
|
|
|
22627
22840
|
if (typeof options.prompt === "string") instance.setPrompt(options.prompt);
|
|
22628
22841
|
return instance;
|
|
22629
22842
|
}
|
|
22630
|
-
const resolvedOutput = output
|
|
22843
|
+
const resolvedOutput = output;
|
|
22631
22844
|
return new Interface(options ?? defaultInput(), resolvedOutput, isTerminal(void 0, resolvedOutput));
|
|
22632
22845
|
};
|
|
22633
22846
|
const noop = () => {
|
|
@@ -22896,7 +23109,7 @@ function createCoreModules(options) {
|
|
|
22896
23109
|
"stream/promises": createStreamPromises(),
|
|
22897
23110
|
string_decoder: stringDecoderModule,
|
|
22898
23111
|
timers: { ...timersModule, ...timers.api },
|
|
22899
|
-
"timers/promises": createTimerPromises(),
|
|
23112
|
+
"timers/promises": createTimerPromises(timers.api),
|
|
22900
23113
|
tty: { isatty: () => false, ReadStream: streamModule4.Readable, WriteStream: streamModule4.Writable },
|
|
22901
23114
|
url: url_module_default,
|
|
22902
23115
|
util: util_module_default,
|
|
@@ -23641,10 +23854,10 @@ function createTrackedTimers() {
|
|
|
23641
23854
|
cancelAll
|
|
23642
23855
|
};
|
|
23643
23856
|
}
|
|
23644
|
-
function createTimerPromises() {
|
|
23857
|
+
function createTimerPromises(timers) {
|
|
23645
23858
|
return {
|
|
23646
|
-
setTimeout: (delay, value) => new Promise((resolve2) => setTimeout(resolve2, delay, value)),
|
|
23647
|
-
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))
|
|
23648
23861
|
};
|
|
23649
23862
|
}
|
|
23650
23863
|
function createAsyncHooksModule() {
|
|
@@ -24352,11 +24565,8 @@ function ensureProcessGlobal() {
|
|
|
24352
24565
|
// src/runtime/host-rolldown.ts
|
|
24353
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'] }";
|
|
24354
24567
|
async function loadHostRolldownBinding() {
|
|
24355
|
-
|
|
24356
|
-
|
|
24357
|
-
"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."
|
|
24358
|
-
);
|
|
24359
|
-
}
|
|
24568
|
+
const reason = syncChannelUnavailableReason();
|
|
24569
|
+
if (reason) throw new Error(`SandboxedJs threaded WASM unavailable: ${reason}`);
|
|
24360
24570
|
try {
|
|
24361
24571
|
const loaded = await import('@rolldown/binding-wasm32-wasi');
|
|
24362
24572
|
return "__fs" in loaded ? { ...loaded } : loaded.default ?? loaded;
|
|
@@ -24364,9 +24574,9 @@ async function loadHostRolldownBinding() {
|
|
|
24364
24574
|
if (typeof process !== "undefined" && process.env?.SANDBOXEDJS_DEBUG) {
|
|
24365
24575
|
console.error("[sandboxedjs] Rolldown WASI binding unavailable:", error);
|
|
24366
24576
|
}
|
|
24367
|
-
const
|
|
24577
|
+
const reason2 = error instanceof Error ? error.message : String(error);
|
|
24368
24578
|
throw new Error(
|
|
24369
|
-
`The optional Rolldown WASI binding could not be loaded: ${
|
|
24579
|
+
`The optional Rolldown WASI binding could not be loaded: ${reason2}` + (typeof window === "undefined" ? "" : `
|
|
24370
24580
|
|
|
24371
24581
|
${BUNDLER_HINT}`),
|
|
24372
24582
|
{ cause: error }
|
|
@@ -24477,6 +24687,8 @@ var LocalProcess = class extends EventEmitter4 {
|
|
|
24477
24687
|
}
|
|
24478
24688
|
/** End the process now, for an asynchronous `process.exit`. */
|
|
24479
24689
|
exitNow(code) {
|
|
24690
|
+
this.killed = true;
|
|
24691
|
+
this.cleanup?.();
|
|
24480
24692
|
this.finish(code);
|
|
24481
24693
|
this.resolveKilled();
|
|
24482
24694
|
}
|
|
@@ -24660,6 +24872,7 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24660
24872
|
)
|
|
24661
24873
|
};
|
|
24662
24874
|
disposed = false;
|
|
24875
|
+
running = /* @__PURE__ */ new Set();
|
|
24663
24876
|
workdir;
|
|
24664
24877
|
env;
|
|
24665
24878
|
aliases;
|
|
@@ -24701,8 +24914,9 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24701
24914
|
const cwd = typeof options.cwd === "string" ? options.cwd : this.workdir;
|
|
24702
24915
|
const env2 = { ...this.env, ...isRecord(options.env) ? options.env : {} };
|
|
24703
24916
|
const owner = `${this.instanceId}:${Math.random().toString(36).slice(2)}`;
|
|
24704
|
-
|
|
24917
|
+
const process2 = new LocalProcess(async (proc) => {
|
|
24705
24918
|
await this.prepareRolldown(cwd, env2);
|
|
24919
|
+
if (proc.isKilled()) return 137;
|
|
24706
24920
|
const untrack = trackProcess(proc);
|
|
24707
24921
|
let requestedExit = 0;
|
|
24708
24922
|
let engine;
|
|
@@ -24730,7 +24944,9 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24730
24944
|
onRawMode: (enabled) => proc.emit("rawmode", enabled)
|
|
24731
24945
|
});
|
|
24732
24946
|
proc.acceptInput((data) => core.writeStdin(data), () => core.endStdin());
|
|
24947
|
+
const hostWork = new HostModuleTracker();
|
|
24733
24948
|
proc.onKill(() => {
|
|
24949
|
+
hostWork.dispose();
|
|
24734
24950
|
core.cancelTimers();
|
|
24735
24951
|
this.router.closeOwner(owner);
|
|
24736
24952
|
});
|
|
@@ -24739,21 +24955,22 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24739
24955
|
builtins: core.builtins,
|
|
24740
24956
|
globals: core.globals,
|
|
24741
24957
|
aliases: this.aliases,
|
|
24742
|
-
overrides: this.modules
|
|
24958
|
+
overrides: Object.fromEntries(Object.entries(this.modules).map(([key, value]) => [key, hostWork.wrap(value)]))
|
|
24743
24959
|
});
|
|
24744
24960
|
try {
|
|
24745
|
-
await engine.run(script);
|
|
24746
|
-
await this.settle(owner, core.pendingHandles, core.
|
|
24747
|
-
if (this.router.activePorts(owner).length) {
|
|
24748
|
-
await proc.waitForKill();
|
|
24749
|
-
return 137;
|
|
24750
|
-
}
|
|
24961
|
+
await Promise.race([engine.run(script), proc.waitForKill()]);
|
|
24962
|
+
await this.settle(owner, core.pendingHandles, core.readingStdin, () => core.pendingRequests() + hostWork.pending(), () => proc.isKilled());
|
|
24751
24963
|
return requestedExit;
|
|
24752
24964
|
} finally {
|
|
24965
|
+
hostWork.dispose();
|
|
24966
|
+
core.cancelTimers();
|
|
24753
24967
|
untrack();
|
|
24754
24968
|
this.router.closeOwner(owner);
|
|
24755
24969
|
}
|
|
24756
24970
|
});
|
|
24971
|
+
this.running.add(process2);
|
|
24972
|
+
void process2.completion.then(() => this.running.delete(process2));
|
|
24973
|
+
return process2;
|
|
24757
24974
|
}
|
|
24758
24975
|
/**
|
|
24759
24976
|
* Rolldown's JavaScript API synchronously requires its compiled binding.
|
|
@@ -24789,19 +25006,13 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24789
25006
|
* A plain script that has genuinely finished falls straight through both,
|
|
24790
25007
|
* costing a handful of empty turns.
|
|
24791
25008
|
*/
|
|
24792
|
-
async settle(owner, pendingHandles,
|
|
24793
|
-
|
|
24794
|
-
|
|
24795
|
-
|
|
24796
|
-
|
|
24797
|
-
|
|
24798
|
-
|
|
24799
|
-
while (!this.router.activePorts(owner).length && !killed() && Date.now() < deadline) {
|
|
24800
|
-
await new Promise((resolve2) => setTimeout(resolve2, 5));
|
|
24801
|
-
}
|
|
24802
|
-
}
|
|
24803
|
-
while (!this.router.activePorts(owner).length && !killed() && (pendingHandles() > 0 || pendingRequests() > 0 || readingStdin())) {
|
|
24804
|
-
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));
|
|
24805
25016
|
}
|
|
24806
25017
|
}
|
|
24807
25018
|
async request(_port, _init = {}) {
|
|
@@ -24818,6 +25029,8 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24818
25029
|
}
|
|
24819
25030
|
teardown() {
|
|
24820
25031
|
this.disposed = true;
|
|
25032
|
+
for (const process2 of this.running) process2.kill();
|
|
25033
|
+
this.running.clear();
|
|
24821
25034
|
this.router.closeAll();
|
|
24822
25035
|
this.esbuild?.stop();
|
|
24823
25036
|
}
|
|
@@ -24887,103 +25100,6 @@ function attachRolldownMirror(binding, volume, root) {
|
|
|
24887
25100
|
volume.attach(fs, root);
|
|
24888
25101
|
}
|
|
24889
25102
|
|
|
24890
|
-
// src/runtime/sync-channel.ts
|
|
24891
|
-
var STATE = 0;
|
|
24892
|
-
var LENGTH = 1;
|
|
24893
|
-
var MORE = 2;
|
|
24894
|
-
var CONTROL_WORDS = 4;
|
|
24895
|
-
var STATE_REQUEST = 1;
|
|
24896
|
-
var STATE_RESPONSE = 2;
|
|
24897
|
-
var STATE_CONTINUE = 3;
|
|
24898
|
-
var STATE_CLOSED = 4;
|
|
24899
|
-
function createSyncChannelBuffers(capacityBytes = 1 << 20) {
|
|
24900
|
-
return {
|
|
24901
|
-
control: new SharedArrayBuffer(CONTROL_WORDS * Int32Array.BYTES_PER_ELEMENT),
|
|
24902
|
-
data: new SharedArrayBuffer(capacityBytes)
|
|
24903
|
-
};
|
|
24904
|
-
}
|
|
24905
|
-
function syncChannelSupported() {
|
|
24906
|
-
if (typeof SharedArrayBuffer !== "function") return false;
|
|
24907
|
-
if (typeof Atomics !== "object" || typeof Atomics.wait !== "function") return false;
|
|
24908
|
-
if (typeof window !== "undefined" && globalThis.crossOriginIsolated !== true) return false;
|
|
24909
|
-
return true;
|
|
24910
|
-
}
|
|
24911
|
-
var SyncChannelServer = class {
|
|
24912
|
-
constructor(buffers, handle) {
|
|
24913
|
-
this.handle = handle;
|
|
24914
|
-
this.control = new Int32Array(buffers.control);
|
|
24915
|
-
this.data = new Uint8Array(buffers.data);
|
|
24916
|
-
this.capacity = this.data.length;
|
|
24917
|
-
}
|
|
24918
|
-
handle;
|
|
24919
|
-
control;
|
|
24920
|
-
data;
|
|
24921
|
-
capacity;
|
|
24922
|
-
/** Request chunks gathered so far, and the response still to be sent. */
|
|
24923
|
-
incoming = [];
|
|
24924
|
-
outgoing = null;
|
|
24925
|
-
sent = 0;
|
|
24926
|
-
closed = false;
|
|
24927
|
-
/** Call from the wake message the client sends after each chunk. */
|
|
24928
|
-
async pump() {
|
|
24929
|
-
if (this.closed) return;
|
|
24930
|
-
const state = Atomics.load(this.control, STATE);
|
|
24931
|
-
if (state === STATE_REQUEST) {
|
|
24932
|
-
const size = Atomics.load(this.control, LENGTH);
|
|
24933
|
-
this.incoming.push(this.data.slice(0, size));
|
|
24934
|
-
if (Atomics.load(this.control, MORE) === 1) {
|
|
24935
|
-
this.publish(STATE_CONTINUE);
|
|
24936
|
-
return;
|
|
24937
|
-
}
|
|
24938
|
-
const request = concat3(this.incoming);
|
|
24939
|
-
this.incoming = [];
|
|
24940
|
-
let response;
|
|
24941
|
-
try {
|
|
24942
|
-
response = await this.handle(request);
|
|
24943
|
-
} catch {
|
|
24944
|
-
response = new Uint8Array();
|
|
24945
|
-
}
|
|
24946
|
-
if (this.closed) return;
|
|
24947
|
-
this.outgoing = response;
|
|
24948
|
-
this.sent = 0;
|
|
24949
|
-
this.sendChunk();
|
|
24950
|
-
return;
|
|
24951
|
-
}
|
|
24952
|
-
if (state === STATE_CONTINUE) this.sendChunk();
|
|
24953
|
-
}
|
|
24954
|
-
/** Release a blocked client, e.g. when the container is torn down. */
|
|
24955
|
-
close() {
|
|
24956
|
-
if (this.closed) return;
|
|
24957
|
-
this.closed = true;
|
|
24958
|
-
Atomics.store(this.control, STATE, STATE_CLOSED);
|
|
24959
|
-
Atomics.notify(this.control, STATE);
|
|
24960
|
-
}
|
|
24961
|
-
sendChunk() {
|
|
24962
|
-
const payload = this.outgoing ?? new Uint8Array();
|
|
24963
|
-
const size = Math.min(this.capacity, payload.length - this.sent);
|
|
24964
|
-
this.data.set(payload.subarray(this.sent, this.sent + size), 0);
|
|
24965
|
-
this.sent += size;
|
|
24966
|
-
Atomics.store(this.control, LENGTH, size);
|
|
24967
|
-
Atomics.store(this.control, MORE, this.sent < payload.length ? 1 : 0);
|
|
24968
|
-
this.publish(STATE_RESPONSE);
|
|
24969
|
-
}
|
|
24970
|
-
publish(state) {
|
|
24971
|
-
Atomics.store(this.control, STATE, state);
|
|
24972
|
-
Atomics.notify(this.control, STATE);
|
|
24973
|
-
}
|
|
24974
|
-
};
|
|
24975
|
-
function concat3(parts) {
|
|
24976
|
-
if (parts.length === 1) return parts[0];
|
|
24977
|
-
const total = parts.reduce((sum, part) => sum + part.length, 0);
|
|
24978
|
-
const joined = new Uint8Array(total);
|
|
24979
|
-
let at = 0;
|
|
24980
|
-
for (const part of parts) {
|
|
24981
|
-
joined.set(part, at);
|
|
24982
|
-
at += part.length;
|
|
24983
|
-
}
|
|
24984
|
-
return joined;
|
|
24985
|
-
}
|
|
24986
|
-
|
|
24987
25103
|
// src/runtime/remote-volume.ts
|
|
24988
25104
|
var encoder7 = new TextEncoder();
|
|
24989
25105
|
var decoder7 = new TextDecoder();
|
|
@@ -25078,24 +25194,32 @@ function defaultWorkerUrl() {
|
|
|
25078
25194
|
return new URL("./worker-entry.js", import.meta.url);
|
|
25079
25195
|
}
|
|
25080
25196
|
function hasDomWorker() {
|
|
25081
|
-
return typeof Worker === "function"
|
|
25197
|
+
return typeof Worker === "function";
|
|
25082
25198
|
}
|
|
25083
25199
|
async function startRuntimeWorker(options = {}) {
|
|
25084
25200
|
const url = options.url ?? defaultWorkerUrl();
|
|
25085
25201
|
const worker = hasDomWorker() ? await startDomWorker(url) : await startNodeWorker(url, options.workerData ?? {});
|
|
25086
|
-
|
|
25087
|
-
|
|
25088
|
-
|
|
25089
|
-
|
|
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) => {
|
|
25090
25212
|
clearTimeout(timer);
|
|
25091
|
-
|
|
25092
|
-
}
|
|
25093
|
-
});
|
|
25094
|
-
worker.onError((error) => {
|
|
25095
|
-
clearTimeout(timer);
|
|
25096
|
-
reject(error instanceof Error ? error : new Error(String(error)));
|
|
25213
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
25214
|
+
});
|
|
25097
25215
|
});
|
|
25098
|
-
})
|
|
25216
|
+
} catch (error) {
|
|
25217
|
+
try {
|
|
25218
|
+
await worker.terminate();
|
|
25219
|
+
} catch {
|
|
25220
|
+
}
|
|
25221
|
+
throw error;
|
|
25222
|
+
}
|
|
25099
25223
|
return worker;
|
|
25100
25224
|
}
|
|
25101
25225
|
async function startDomWorker(url) {
|
|
@@ -25156,6 +25280,8 @@ var WorkerProcess = class extends EventEmitter4 {
|
|
|
25156
25280
|
started = false;
|
|
25157
25281
|
pendingInput = [];
|
|
25158
25282
|
inputEnded = false;
|
|
25283
|
+
inheritedInput;
|
|
25284
|
+
ownRawMode = false;
|
|
25159
25285
|
on(event, listener) {
|
|
25160
25286
|
return super.on(event, listener);
|
|
25161
25287
|
}
|
|
@@ -25181,13 +25307,38 @@ var WorkerProcess = class extends EventEmitter4 {
|
|
|
25181
25307
|
* program is still loading, and dropping them loses the answer to a prompt.
|
|
25182
25308
|
*/
|
|
25183
25309
|
write(data) {
|
|
25310
|
+
if (this.inheritedInput) {
|
|
25311
|
+
this.inheritedInput.sendStdin(data);
|
|
25312
|
+
return;
|
|
25313
|
+
}
|
|
25184
25314
|
if (this.started) this.worker.postMessage({ type: "stdin", data });
|
|
25185
25315
|
else this.pendingInput.push(data);
|
|
25186
25316
|
}
|
|
25187
25317
|
endInput() {
|
|
25188
25318
|
this.inputEnded = true;
|
|
25319
|
+
if (this.inheritedInput) {
|
|
25320
|
+
this.inheritedInput.endStdin?.();
|
|
25321
|
+
return;
|
|
25322
|
+
}
|
|
25189
25323
|
if (this.started) this.worker.postMessage({ type: "stdin-end" });
|
|
25190
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
|
+
}
|
|
25191
25342
|
kill(_signal = "SIGTERM") {
|
|
25192
25343
|
this.worker.postMessage({ type: "kill" });
|
|
25193
25344
|
this.finish(137);
|
|
@@ -25208,25 +25359,30 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25208
25359
|
super(options);
|
|
25209
25360
|
this.workerUrl = options.workerUrl;
|
|
25210
25361
|
}
|
|
25211
|
-
/**
|
|
25212
|
-
|
|
25213
|
-
|
|
25214
|
-
|
|
25215
|
-
|
|
25216
|
-
|
|
25217
|
-
|
|
25218
|
-
* and keeps working.
|
|
25219
|
-
*/
|
|
25220
|
-
static async tryBoot(options = {}) {
|
|
25221
|
-
if (!syncChannelSupported()) return null;
|
|
25222
|
-
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
|
+
}
|
|
25223
25369
|
const pod = new _WorkerRuntimePod(options);
|
|
25224
25370
|
try {
|
|
25225
25371
|
const probe = await startRuntimeWorker({ ...options.workerUrl ? { url: options.workerUrl } : {}, timeoutMs: 1e4 });
|
|
25226
25372
|
await probe.terminate();
|
|
25227
25373
|
return pod;
|
|
25228
|
-
} catch {
|
|
25374
|
+
} catch (cause) {
|
|
25229
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)));
|
|
25230
25386
|
return null;
|
|
25231
25387
|
}
|
|
25232
25388
|
}
|
|
@@ -25249,11 +25405,14 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25249
25405
|
const streams = { target: null };
|
|
25250
25406
|
const server = new SyncChannelServer(buffers, serveSyncSyscalls({
|
|
25251
25407
|
volume: this.volume,
|
|
25252
|
-
spawnChild: (request) => this.runChildToCompletion(request, streams.target)
|
|
25408
|
+
spawnChild: (request) => this.runChildToCompletion(request, streams.target, ownedChildren)
|
|
25253
25409
|
}));
|
|
25254
25410
|
const entry = { worker, server };
|
|
25255
25411
|
this.live.add(entry);
|
|
25412
|
+
const ownedChildren = /* @__PURE__ */ new Set();
|
|
25256
25413
|
const process2 = new WorkerProcess(worker, () => {
|
|
25414
|
+
for (const child of ownedChildren) child.kill("SIGTERM");
|
|
25415
|
+
ownedChildren.clear();
|
|
25257
25416
|
this.live.delete(entry);
|
|
25258
25417
|
server.close();
|
|
25259
25418
|
this.closeProxies(owner);
|
|
@@ -25274,7 +25433,7 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25274
25433
|
process2.error(String(message.text));
|
|
25275
25434
|
return;
|
|
25276
25435
|
case "rawmode":
|
|
25277
|
-
process2.
|
|
25436
|
+
process2.rawMode(Boolean(message.enabled));
|
|
25278
25437
|
return;
|
|
25279
25438
|
case "exit":
|
|
25280
25439
|
process2.finish(Number(message.code));
|
|
@@ -25282,11 +25441,20 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25282
25441
|
case "listen":
|
|
25283
25442
|
this.proxyPort(Number(message.port), owner, worker);
|
|
25284
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
|
+
}
|
|
25285
25453
|
case "http-response":
|
|
25286
25454
|
this.settleProxied(Number(message.id), message.response);
|
|
25287
25455
|
return;
|
|
25288
25456
|
case "child-start":
|
|
25289
|
-
this.startChild(worker, children, message);
|
|
25457
|
+
this.startChild(worker, children, message, ownedChildren);
|
|
25290
25458
|
return;
|
|
25291
25459
|
case "child-stdin":
|
|
25292
25460
|
children.get(message.id)?.sendStdin?.(String(message.data));
|
|
@@ -25317,16 +25485,21 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25317
25485
|
return process2;
|
|
25318
25486
|
}
|
|
25319
25487
|
/** Start an asynchronous child on the host's behalf and relay its events. */
|
|
25320
|
-
startChild(worker, children, message) {
|
|
25488
|
+
startChild(worker, children, message, owned) {
|
|
25321
25489
|
const handle = this.processManager.spawn(message.config);
|
|
25322
25490
|
children.set(message.id, handle);
|
|
25491
|
+
owned.add(handle);
|
|
25492
|
+
handle.on("exit", () => {
|
|
25493
|
+
owned.delete(handle);
|
|
25494
|
+
children.delete(message.id);
|
|
25495
|
+
});
|
|
25323
25496
|
for (const event of ["stdout", "stderr", "exit"]) {
|
|
25324
25497
|
handle.on(event, (value) => worker.postMessage({ type: "child-event", id: message.id, event, value }));
|
|
25325
25498
|
}
|
|
25326
25499
|
handle.exec();
|
|
25327
25500
|
}
|
|
25328
25501
|
/** Run a child to completion and collect it, for the guest's `spawnSync`. */
|
|
25329
|
-
runChildToCompletion(request, streamTo) {
|
|
25502
|
+
runChildToCompletion(request, streamTo, owned) {
|
|
25330
25503
|
return new Promise((resolve2) => {
|
|
25331
25504
|
let handle;
|
|
25332
25505
|
try {
|
|
@@ -25342,9 +25515,13 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25342
25515
|
resolve2({ status: null, stdout: "", stderr: "", signal: null, error: { ...failure.code ? { code: failure.code } : {}, message: failure.message } });
|
|
25343
25516
|
return;
|
|
25344
25517
|
}
|
|
25518
|
+
owned.add(handle);
|
|
25519
|
+
handle.on("exit", () => owned.delete(handle));
|
|
25345
25520
|
let stdout = "";
|
|
25346
25521
|
let stderr = "";
|
|
25347
25522
|
const live = request.inheritStdio ? streamTo : null;
|
|
25523
|
+
const restoreInput = live?.inheritInput(handle);
|
|
25524
|
+
if (restoreInput) handle.on("exit", restoreInput);
|
|
25348
25525
|
handle.on("stdout", (text2) => {
|
|
25349
25526
|
stdout += text2;
|
|
25350
25527
|
live?.output(text2);
|
|
@@ -25498,7 +25675,7 @@ var Container = class _Container {
|
|
|
25498
25675
|
...opts.onServerReady ? { onServerReady: opts.onServerReady } : {}
|
|
25499
25676
|
};
|
|
25500
25677
|
const workerOptions = { ...podOptions, ...opts.workerUrl ? { workerUrl: opts.workerUrl } : {} };
|
|
25501
|
-
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);
|
|
25502
25679
|
const kernel = new Kernel({
|
|
25503
25680
|
pod,
|
|
25504
25681
|
hostname: opts.hostname ?? "sandbox",
|
|
@@ -26006,7 +26183,7 @@ var Terminal = class {
|
|
|
26006
26183
|
if (this.running) {
|
|
26007
26184
|
const raw = this.currentStdin?.rawMode === true;
|
|
26008
26185
|
if (ch === CTRL_C && !raw) {
|
|
26009
|
-
this.session.
|
|
26186
|
+
if (this.currentStdin) this.session.shell.interruptForeground("SIGINT", this.currentStdin);
|
|
26010
26187
|
this.write("^C\r\n");
|
|
26011
26188
|
return;
|
|
26012
26189
|
}
|
|
@@ -26396,7 +26573,7 @@ function serveContainerOn(port, box) {
|
|
|
26396
26573
|
}
|
|
26397
26574
|
async function createPreview(box, options = {}) {
|
|
26398
26575
|
if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) return null;
|
|
26399
|
-
const scriptUrl = options.scriptUrl ?? new URL("./service-worker.js", import.meta.url);
|
|
26576
|
+
const scriptUrl = options.scriptUrl ?? new URL("./service-worker.js?no-inline", import.meta.url);
|
|
26400
26577
|
let registration;
|
|
26401
26578
|
try {
|
|
26402
26579
|
registration = await navigator.serviceWorker.register(scriptUrl, {
|