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.cjs
CHANGED
|
@@ -4795,7 +4795,15 @@ var Pipe = class _Pipe {
|
|
|
4795
4795
|
* whole line on every keystroke — so the terminal must stop echoing, or
|
|
4796
4796
|
* every character appears twice.
|
|
4797
4797
|
*/
|
|
4798
|
-
|
|
4798
|
+
raw = false;
|
|
4799
|
+
onRawMode;
|
|
4800
|
+
get rawMode() {
|
|
4801
|
+
return this.raw;
|
|
4802
|
+
}
|
|
4803
|
+
set rawMode(enabled) {
|
|
4804
|
+
this.raw = enabled;
|
|
4805
|
+
this.onRawMode?.(enabled);
|
|
4806
|
+
}
|
|
4799
4807
|
columns;
|
|
4800
4808
|
rows;
|
|
4801
4809
|
get closed() {
|
|
@@ -5923,13 +5931,19 @@ var Kernel = class {
|
|
|
5923
5931
|
stderr: opts.stderr ?? new NullOutput()
|
|
5924
5932
|
}
|
|
5925
5933
|
});
|
|
5934
|
+
const cancelWithParent = () => {
|
|
5935
|
+
if (parent?.termSignal) proc.deliver(parent.termSignal);
|
|
5936
|
+
};
|
|
5937
|
+
parent?.signal.addEventListener("abort", cancelWithParent, { once: true });
|
|
5938
|
+
if (parent?.signal.aborted) cancelWithParent();
|
|
5939
|
+
void proc.wait().then(() => parent?.signal.removeEventListener("abort", cancelWithParent));
|
|
5926
5940
|
let timer;
|
|
5927
5941
|
if (opts.timeoutMs !== void 0) {
|
|
5928
5942
|
timer = setTimeout(() => {
|
|
5929
5943
|
proc.deliver("SIGKILL");
|
|
5930
5944
|
}, opts.timeoutMs);
|
|
5931
5945
|
}
|
|
5932
|
-
void this.dispatch(proc).then((code) => {
|
|
5946
|
+
void (proc.signal.aborted ? Promise.resolve(proc.exitCode ?? 137) : this.dispatch(proc)).then((code) => {
|
|
5933
5947
|
proc.exit(code);
|
|
5934
5948
|
}).catch((e) => {
|
|
5935
5949
|
try {
|
|
@@ -7921,6 +7935,22 @@ var Shell = class _Shell {
|
|
|
7921
7935
|
}
|
|
7922
7936
|
return this.lastStatus;
|
|
7923
7937
|
}
|
|
7938
|
+
/** Signal the current terminal pipeline without terminating the interactive shell. */
|
|
7939
|
+
interruptForeground(signal, stdin) {
|
|
7940
|
+
const processes = this.kernel.procs.list().filter((process2) => process2.running);
|
|
7941
|
+
const selected = new Set(processes.filter((process2) => process2.ppid === this.proc.pid && process2.stdin === stdin).map((process2) => process2.pid));
|
|
7942
|
+
for (let changed = true; changed; ) {
|
|
7943
|
+
changed = false;
|
|
7944
|
+
const outputs = processes.filter((process2) => selected.has(process2.pid)).flatMap((process2) => [process2.stdout, process2.stderr]);
|
|
7945
|
+
for (const process2 of processes) {
|
|
7946
|
+
if (!selected.has(process2.pid) && (selected.has(process2.ppid) || outputs.some((output) => output === process2.stdin))) {
|
|
7947
|
+
selected.add(process2.pid);
|
|
7948
|
+
changed = true;
|
|
7949
|
+
}
|
|
7950
|
+
}
|
|
7951
|
+
}
|
|
7952
|
+
for (const process2 of processes) if (selected.has(process2.pid)) process2.deliver(signal);
|
|
7953
|
+
}
|
|
7924
7954
|
get isExiting() {
|
|
7925
7955
|
return this.exiting;
|
|
7926
7956
|
}
|
|
@@ -8570,6 +8600,7 @@ sys ${fmt2(Math.floor(ms * 0.2))}
|
|
|
8570
8600
|
for (const assignment of assignments) {
|
|
8571
8601
|
env2[assignment.name] = await expandWordToString(assignment.value, this.expandContext());
|
|
8572
8602
|
}
|
|
8603
|
+
if (this.proc.signal.aborted) return this.proc.exitCode ?? 137;
|
|
8573
8604
|
const proc = this.kernel.spawn(words, {
|
|
8574
8605
|
cwd: this.cwd,
|
|
8575
8606
|
env: env2,
|
|
@@ -19716,6 +19747,7 @@ var KernelChildProcess = class {
|
|
|
19716
19747
|
this.stdin.isTTY = true;
|
|
19717
19748
|
this.stdin.interactive = true;
|
|
19718
19749
|
}
|
|
19750
|
+
this.stdin.onRawMode = (enabled) => this.emit("rawmode", enabled);
|
|
19719
19751
|
this.kernel = kernel;
|
|
19720
19752
|
this.cred = cred;
|
|
19721
19753
|
this.pid = pid;
|
|
@@ -19832,7 +19864,7 @@ function installNodeChildProcessBridge(pod, kernel, cred) {
|
|
|
19832
19864
|
const originalSpawn = manager.spawn;
|
|
19833
19865
|
manager.spawn = (config) => {
|
|
19834
19866
|
const resolved = kernel.resolveExecutable(config.command, config.cwd ?? "/", config.env ?? {}, cred);
|
|
19835
|
-
if (resolved?.kind === "builtin"
|
|
19867
|
+
if (resolved?.kind === "builtin") {
|
|
19836
19868
|
return new KernelChildProcess(kernel, cred, config, nextBridgePid++);
|
|
19837
19869
|
}
|
|
19838
19870
|
return originalSpawn.call(manager, config);
|
|
@@ -19843,6 +19875,68 @@ function installNodeChildProcessBridge(pod, kernel, cred) {
|
|
|
19843
19875
|
};
|
|
19844
19876
|
}
|
|
19845
19877
|
|
|
19878
|
+
// src/runtime/host-module-tracker.ts
|
|
19879
|
+
var HostModuleTracker = class {
|
|
19880
|
+
active = 0;
|
|
19881
|
+
disposed = false;
|
|
19882
|
+
dispose() {
|
|
19883
|
+
this.disposed = true;
|
|
19884
|
+
}
|
|
19885
|
+
wrapped = /* @__PURE__ */ new WeakMap();
|
|
19886
|
+
originals = /* @__PURE__ */ new WeakMap();
|
|
19887
|
+
pending = () => this.active;
|
|
19888
|
+
unwrap = (value) => value && (typeof value === "object" || typeof value === "function") ? this.originals.get(value) ?? value : value;
|
|
19889
|
+
wrap(value) {
|
|
19890
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return value;
|
|
19891
|
+
const object = value;
|
|
19892
|
+
if (Array.isArray(value) || ArrayBuffer.isView(value) || value instanceof ArrayBuffer) return value;
|
|
19893
|
+
if (this.wrapped.has(object)) return this.wrapped.get(object);
|
|
19894
|
+
const tracker = this;
|
|
19895
|
+
const proxy = new Proxy(object, {
|
|
19896
|
+
// CommonJS native loaders re-export by assigning exports back onto the
|
|
19897
|
+
// binding object. Never store a process-owned proxy in a shared module.
|
|
19898
|
+
set(target, key, member) {
|
|
19899
|
+
return Reflect.set(target, key, tracker.unwrap(member), target);
|
|
19900
|
+
},
|
|
19901
|
+
defineProperty(target, key, descriptor) {
|
|
19902
|
+
return Reflect.defineProperty(target, key, "value" in descriptor ? { ...descriptor, value: tracker.unwrap(descriptor.value) } : descriptor);
|
|
19903
|
+
},
|
|
19904
|
+
get(target, key) {
|
|
19905
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
|
|
19906
|
+
const member = Reflect.get(target, key, target);
|
|
19907
|
+
if (descriptor && !descriptor.configurable && "value" in descriptor && !descriptor.writable) return member;
|
|
19908
|
+
return typeof member === "function" ? tracker.wrap(member) : member;
|
|
19909
|
+
},
|
|
19910
|
+
apply(target, receiver, args) {
|
|
19911
|
+
const result = Reflect.apply(target, tracker.unwrap(receiver), args.map(tracker.unwrap));
|
|
19912
|
+
if (result && typeof result.then === "function") {
|
|
19913
|
+
tracker.active++;
|
|
19914
|
+
return Promise.resolve(result).then(
|
|
19915
|
+
(value2) => {
|
|
19916
|
+
tracker.active--;
|
|
19917
|
+
return tracker.disposed ? new Promise(() => {
|
|
19918
|
+
}) : tracker.wrap(value2);
|
|
19919
|
+
},
|
|
19920
|
+
(error) => {
|
|
19921
|
+
tracker.active--;
|
|
19922
|
+
if (tracker.disposed) return new Promise(() => {
|
|
19923
|
+
});
|
|
19924
|
+
throw error;
|
|
19925
|
+
}
|
|
19926
|
+
);
|
|
19927
|
+
}
|
|
19928
|
+
return tracker.wrap(result);
|
|
19929
|
+
},
|
|
19930
|
+
construct(target, args, newTarget) {
|
|
19931
|
+
return tracker.wrap(Reflect.construct(target, args.map(tracker.unwrap), tracker.unwrap(newTarget)));
|
|
19932
|
+
}
|
|
19933
|
+
});
|
|
19934
|
+
this.wrapped.set(object, proxy);
|
|
19935
|
+
this.originals.set(proxy, object);
|
|
19936
|
+
return proxy;
|
|
19937
|
+
}
|
|
19938
|
+
};
|
|
19939
|
+
|
|
19846
19940
|
// src/runtime/commonjs-engine.ts
|
|
19847
19941
|
init_path();
|
|
19848
19942
|
var HELPERS = {
|
|
@@ -21580,6 +21674,7 @@ var VirtualHttpServer = class extends EventEmitter4__default.default {
|
|
|
21580
21674
|
owner;
|
|
21581
21675
|
listening = false;
|
|
21582
21676
|
portValue = null;
|
|
21677
|
+
referenced = true;
|
|
21583
21678
|
listen(...args) {
|
|
21584
21679
|
const callback = typeof args.at(-1) === "function" ? args.pop() : void 0;
|
|
21585
21680
|
const first = args[0];
|
|
@@ -21608,11 +21703,16 @@ var VirtualHttpServer = class extends EventEmitter4__default.default {
|
|
|
21608
21703
|
return this.portValue === null ? null : { address: "0.0.0.0", family: "IPv4", port: this.portValue };
|
|
21609
21704
|
}
|
|
21610
21705
|
ref() {
|
|
21706
|
+
this.referenced = true;
|
|
21611
21707
|
return this;
|
|
21612
21708
|
}
|
|
21613
21709
|
unref() {
|
|
21710
|
+
this.referenced = false;
|
|
21614
21711
|
return this;
|
|
21615
21712
|
}
|
|
21713
|
+
hasRef() {
|
|
21714
|
+
return this.referenced;
|
|
21715
|
+
}
|
|
21616
21716
|
setTimeout(_milliseconds, callback) {
|
|
21617
21717
|
if (callback) this.on("timeout", callback);
|
|
21618
21718
|
return this;
|
|
@@ -21622,13 +21722,16 @@ var VirtualHttpRouter = class {
|
|
|
21622
21722
|
servers = /* @__PURE__ */ new Map();
|
|
21623
21723
|
/** Notified when a server begins listening, for `onServerReady`. */
|
|
21624
21724
|
onListen;
|
|
21725
|
+
onClose;
|
|
21625
21726
|
register(port, server, owner) {
|
|
21626
21727
|
if (this.servers.has(port)) throw Object.assign(new Error(`listen EADDRINUSE: address already in use 0.0.0.0:${port}`), { code: "EADDRINUSE", port });
|
|
21627
21728
|
this.servers.set(port, { server, owner });
|
|
21628
21729
|
this.onListen?.(port);
|
|
21629
21730
|
}
|
|
21630
21731
|
unregister(port, server) {
|
|
21631
|
-
if (this.servers.get(port)?.server
|
|
21732
|
+
if (this.servers.get(port)?.server !== server) return;
|
|
21733
|
+
this.servers.delete(port);
|
|
21734
|
+
this.onClose?.(port);
|
|
21632
21735
|
}
|
|
21633
21736
|
/** Whether anything in this container is listening on `port`. */
|
|
21634
21737
|
activePortsIncludes(port) {
|
|
@@ -21637,6 +21740,9 @@ var VirtualHttpRouter = class {
|
|
|
21637
21740
|
activePorts(owner) {
|
|
21638
21741
|
return [...this.servers].filter(([, item]) => owner === void 0 || item.owner === owner).map(([port]) => port).sort((a, b) => a - b);
|
|
21639
21742
|
}
|
|
21743
|
+
referencedPorts(owner) {
|
|
21744
|
+
return [...this.servers].filter(([, item]) => item.owner === owner && item.server.hasRef()).map(([port]) => port);
|
|
21745
|
+
}
|
|
21640
21746
|
closeOwner(owner) {
|
|
21641
21747
|
for (const { server, owner: value } of [...this.servers.values()]) if (value === owner) server.close();
|
|
21642
21748
|
}
|
|
@@ -22048,6 +22154,108 @@ function hashFor(algorithm) {
|
|
|
22048
22154
|
function toBytes2(data, encoding) {
|
|
22049
22155
|
return typeof data === "string" ? Buffer2.from(data, encoding) : data;
|
|
22050
22156
|
}
|
|
22157
|
+
|
|
22158
|
+
// src/runtime/sync-channel.ts
|
|
22159
|
+
var STATE = 0;
|
|
22160
|
+
var LENGTH = 1;
|
|
22161
|
+
var MORE = 2;
|
|
22162
|
+
var CONTROL_WORDS = 4;
|
|
22163
|
+
var STATE_REQUEST = 1;
|
|
22164
|
+
var STATE_RESPONSE = 2;
|
|
22165
|
+
var STATE_CONTINUE = 3;
|
|
22166
|
+
var STATE_CLOSED = 4;
|
|
22167
|
+
function createSyncChannelBuffers(capacityBytes = 1 << 20) {
|
|
22168
|
+
return {
|
|
22169
|
+
control: new SharedArrayBuffer(CONTROL_WORDS * Int32Array.BYTES_PER_ELEMENT),
|
|
22170
|
+
data: new SharedArrayBuffer(capacityBytes)
|
|
22171
|
+
};
|
|
22172
|
+
}
|
|
22173
|
+
function syncChannelUnavailableReason() {
|
|
22174
|
+
if (typeof globalThis.crossOriginIsolated === "boolean" && !globalThis.crossOriginIsolated) {
|
|
22175
|
+
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.";
|
|
22176
|
+
}
|
|
22177
|
+
if (typeof SharedArrayBuffer !== "function") return "SharedArrayBuffer is unavailable in this host.";
|
|
22178
|
+
if (typeof Atomics !== "object" || typeof Atomics.wait !== "function") return "Atomics.wait is unavailable in this host.";
|
|
22179
|
+
return null;
|
|
22180
|
+
}
|
|
22181
|
+
function syncChannelSupported() {
|
|
22182
|
+
return syncChannelUnavailableReason() === null;
|
|
22183
|
+
}
|
|
22184
|
+
var SyncChannelServer = class {
|
|
22185
|
+
constructor(buffers, handle) {
|
|
22186
|
+
this.handle = handle;
|
|
22187
|
+
this.control = new Int32Array(buffers.control);
|
|
22188
|
+
this.data = new Uint8Array(buffers.data);
|
|
22189
|
+
this.capacity = this.data.length;
|
|
22190
|
+
}
|
|
22191
|
+
handle;
|
|
22192
|
+
control;
|
|
22193
|
+
data;
|
|
22194
|
+
capacity;
|
|
22195
|
+
/** Request chunks gathered so far, and the response still to be sent. */
|
|
22196
|
+
incoming = [];
|
|
22197
|
+
outgoing = null;
|
|
22198
|
+
sent = 0;
|
|
22199
|
+
closed = false;
|
|
22200
|
+
/** Call from the wake message the client sends after each chunk. */
|
|
22201
|
+
async pump() {
|
|
22202
|
+
if (this.closed) return;
|
|
22203
|
+
const state = Atomics.load(this.control, STATE);
|
|
22204
|
+
if (state === STATE_REQUEST) {
|
|
22205
|
+
const size = Atomics.load(this.control, LENGTH);
|
|
22206
|
+
this.incoming.push(this.data.slice(0, size));
|
|
22207
|
+
if (Atomics.load(this.control, MORE) === 1) {
|
|
22208
|
+
this.publish(STATE_CONTINUE);
|
|
22209
|
+
return;
|
|
22210
|
+
}
|
|
22211
|
+
const request = concat3(this.incoming);
|
|
22212
|
+
this.incoming = [];
|
|
22213
|
+
let response;
|
|
22214
|
+
try {
|
|
22215
|
+
response = await this.handle(request);
|
|
22216
|
+
} catch {
|
|
22217
|
+
response = new Uint8Array();
|
|
22218
|
+
}
|
|
22219
|
+
if (this.closed) return;
|
|
22220
|
+
this.outgoing = response;
|
|
22221
|
+
this.sent = 0;
|
|
22222
|
+
this.sendChunk();
|
|
22223
|
+
return;
|
|
22224
|
+
}
|
|
22225
|
+
if (state === STATE_CONTINUE) this.sendChunk();
|
|
22226
|
+
}
|
|
22227
|
+
/** Release a blocked client, e.g. when the container is torn down. */
|
|
22228
|
+
close() {
|
|
22229
|
+
if (this.closed) return;
|
|
22230
|
+
this.closed = true;
|
|
22231
|
+
Atomics.store(this.control, STATE, STATE_CLOSED);
|
|
22232
|
+
Atomics.notify(this.control, STATE);
|
|
22233
|
+
}
|
|
22234
|
+
sendChunk() {
|
|
22235
|
+
const payload = this.outgoing ?? new Uint8Array();
|
|
22236
|
+
const size = Math.min(this.capacity, payload.length - this.sent);
|
|
22237
|
+
this.data.set(payload.subarray(this.sent, this.sent + size), 0);
|
|
22238
|
+
this.sent += size;
|
|
22239
|
+
Atomics.store(this.control, LENGTH, size);
|
|
22240
|
+
Atomics.store(this.control, MORE, this.sent < payload.length ? 1 : 0);
|
|
22241
|
+
this.publish(STATE_RESPONSE);
|
|
22242
|
+
}
|
|
22243
|
+
publish(state) {
|
|
22244
|
+
Atomics.store(this.control, STATE, state);
|
|
22245
|
+
Atomics.notify(this.control, STATE);
|
|
22246
|
+
}
|
|
22247
|
+
};
|
|
22248
|
+
function concat3(parts) {
|
|
22249
|
+
if (parts.length === 1) return parts[0];
|
|
22250
|
+
const total = parts.reduce((sum, part) => sum + part.length, 0);
|
|
22251
|
+
const joined = new Uint8Array(total);
|
|
22252
|
+
let at = 0;
|
|
22253
|
+
for (const part of parts) {
|
|
22254
|
+
joined.set(part, at);
|
|
22255
|
+
at += part.length;
|
|
22256
|
+
}
|
|
22257
|
+
return joined;
|
|
22258
|
+
}
|
|
22051
22259
|
var ChildProcess = class extends EventEmitter4__default.default {
|
|
22052
22260
|
stdout = new streamModule4__default.default.PassThrough();
|
|
22053
22261
|
stderr = new streamModule4__default.default.PassThrough();
|
|
@@ -22252,7 +22460,7 @@ function unavailable(name) {
|
|
|
22252
22460
|
const list = Array.isArray(args[1]) ? args[1].map(String) : [];
|
|
22253
22461
|
const command = file3 ? [file3, ...list].join(" ") : void 0;
|
|
22254
22462
|
const error = new Error(
|
|
22255
|
-
`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.
|
|
22463
|
+
`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.")
|
|
22256
22464
|
);
|
|
22257
22465
|
error.code = "ERR_FEATURE_UNAVAILABLE_ON_PLATFORM";
|
|
22258
22466
|
throw error;
|
|
@@ -22540,6 +22748,11 @@ function createReadlineModule(defaultInput, defaultOutput = () => void 0) {
|
|
|
22540
22748
|
edit(sequence, key) {
|
|
22541
22749
|
if (this.closed) return;
|
|
22542
22750
|
const name = key.name;
|
|
22751
|
+
if (key.ctrl && name === "c") {
|
|
22752
|
+
if (this.listenerCount("SIGINT") > 0) this.emit("SIGINT");
|
|
22753
|
+
else this.close();
|
|
22754
|
+
return;
|
|
22755
|
+
}
|
|
22543
22756
|
if (name === "return" || name === "enter") {
|
|
22544
22757
|
const value = this.line;
|
|
22545
22758
|
this.line = "";
|
|
@@ -22635,7 +22848,7 @@ function createReadlineModule(defaultInput, defaultOutput = () => void 0) {
|
|
|
22635
22848
|
};
|
|
22636
22849
|
const createInterface = (options, output) => {
|
|
22637
22850
|
if (options && typeof options === "object" && !options.on) {
|
|
22638
|
-
const resolvedOutput2 = options.output
|
|
22851
|
+
const resolvedOutput2 = options.output;
|
|
22639
22852
|
const instance = new Interface(
|
|
22640
22853
|
options.input ?? defaultInput(),
|
|
22641
22854
|
resolvedOutput2,
|
|
@@ -22644,7 +22857,7 @@ function createReadlineModule(defaultInput, defaultOutput = () => void 0) {
|
|
|
22644
22857
|
if (typeof options.prompt === "string") instance.setPrompt(options.prompt);
|
|
22645
22858
|
return instance;
|
|
22646
22859
|
}
|
|
22647
|
-
const resolvedOutput = output
|
|
22860
|
+
const resolvedOutput = output;
|
|
22648
22861
|
return new Interface(options ?? defaultInput(), resolvedOutput, isTerminal(void 0, resolvedOutput));
|
|
22649
22862
|
};
|
|
22650
22863
|
const noop = () => {
|
|
@@ -22913,7 +23126,7 @@ function createCoreModules(options) {
|
|
|
22913
23126
|
"stream/promises": createStreamPromises(),
|
|
22914
23127
|
string_decoder: stringDecoderModule__default.default,
|
|
22915
23128
|
timers: { ...timersModule__default.default, ...timers.api },
|
|
22916
|
-
"timers/promises": createTimerPromises(),
|
|
23129
|
+
"timers/promises": createTimerPromises(timers.api),
|
|
22917
23130
|
tty: { isatty: () => false, ReadStream: streamModule4__default.default.Readable, WriteStream: streamModule4__default.default.Writable },
|
|
22918
23131
|
url: url_module_default,
|
|
22919
23132
|
util: util_module_default,
|
|
@@ -23658,10 +23871,10 @@ function createTrackedTimers() {
|
|
|
23658
23871
|
cancelAll
|
|
23659
23872
|
};
|
|
23660
23873
|
}
|
|
23661
|
-
function createTimerPromises() {
|
|
23874
|
+
function createTimerPromises(timers) {
|
|
23662
23875
|
return {
|
|
23663
|
-
setTimeout: (delay, value) => new Promise((resolve2) => setTimeout(resolve2, delay, value)),
|
|
23664
|
-
setImmediate: (value) => new Promise((resolve2) =>
|
|
23876
|
+
setTimeout: (delay, value) => new Promise((resolve2) => timers.setTimeout(resolve2, delay, value)),
|
|
23877
|
+
setImmediate: (value) => new Promise((resolve2) => timers.setImmediate(resolve2, value))
|
|
23665
23878
|
};
|
|
23666
23879
|
}
|
|
23667
23880
|
function createAsyncHooksModule() {
|
|
@@ -24369,11 +24582,8 @@ function ensureProcessGlobal() {
|
|
|
24369
24582
|
// src/runtime/host-rolldown.ts
|
|
24370
24583
|
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'] }";
|
|
24371
24584
|
async function loadHostRolldownBinding() {
|
|
24372
|
-
|
|
24373
|
-
|
|
24374
|
-
"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."
|
|
24375
|
-
);
|
|
24376
|
-
}
|
|
24585
|
+
const reason = syncChannelUnavailableReason();
|
|
24586
|
+
if (reason) throw new Error(`SandboxedJs threaded WASM unavailable: ${reason}`);
|
|
24377
24587
|
try {
|
|
24378
24588
|
const loaded = await import('@rolldown/binding-wasm32-wasi');
|
|
24379
24589
|
return "__fs" in loaded ? { ...loaded } : loaded.default ?? loaded;
|
|
@@ -24381,9 +24591,9 @@ async function loadHostRolldownBinding() {
|
|
|
24381
24591
|
if (typeof process !== "undefined" && process.env?.SANDBOXEDJS_DEBUG) {
|
|
24382
24592
|
console.error("[sandboxedjs] Rolldown WASI binding unavailable:", error);
|
|
24383
24593
|
}
|
|
24384
|
-
const
|
|
24594
|
+
const reason2 = error instanceof Error ? error.message : String(error);
|
|
24385
24595
|
throw new Error(
|
|
24386
|
-
`The optional Rolldown WASI binding could not be loaded: ${
|
|
24596
|
+
`The optional Rolldown WASI binding could not be loaded: ${reason2}` + (typeof window === "undefined" ? "" : `
|
|
24387
24597
|
|
|
24388
24598
|
${BUNDLER_HINT}`),
|
|
24389
24599
|
{ cause: error }
|
|
@@ -24494,6 +24704,8 @@ var LocalProcess = class extends EventEmitter4__default.default {
|
|
|
24494
24704
|
}
|
|
24495
24705
|
/** End the process now, for an asynchronous `process.exit`. */
|
|
24496
24706
|
exitNow(code) {
|
|
24707
|
+
this.killed = true;
|
|
24708
|
+
this.cleanup?.();
|
|
24497
24709
|
this.finish(code);
|
|
24498
24710
|
this.resolveKilled();
|
|
24499
24711
|
}
|
|
@@ -24677,6 +24889,7 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24677
24889
|
)
|
|
24678
24890
|
};
|
|
24679
24891
|
disposed = false;
|
|
24892
|
+
running = /* @__PURE__ */ new Set();
|
|
24680
24893
|
workdir;
|
|
24681
24894
|
env;
|
|
24682
24895
|
aliases;
|
|
@@ -24718,8 +24931,9 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24718
24931
|
const cwd = typeof options.cwd === "string" ? options.cwd : this.workdir;
|
|
24719
24932
|
const env2 = { ...this.env, ...isRecord(options.env) ? options.env : {} };
|
|
24720
24933
|
const owner = `${this.instanceId}:${Math.random().toString(36).slice(2)}`;
|
|
24721
|
-
|
|
24934
|
+
const process2 = new LocalProcess(async (proc) => {
|
|
24722
24935
|
await this.prepareRolldown(cwd, env2);
|
|
24936
|
+
if (proc.isKilled()) return 137;
|
|
24723
24937
|
const untrack = trackProcess(proc);
|
|
24724
24938
|
let requestedExit = 0;
|
|
24725
24939
|
let engine;
|
|
@@ -24747,7 +24961,9 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24747
24961
|
onRawMode: (enabled) => proc.emit("rawmode", enabled)
|
|
24748
24962
|
});
|
|
24749
24963
|
proc.acceptInput((data) => core.writeStdin(data), () => core.endStdin());
|
|
24964
|
+
const hostWork = new HostModuleTracker();
|
|
24750
24965
|
proc.onKill(() => {
|
|
24966
|
+
hostWork.dispose();
|
|
24751
24967
|
core.cancelTimers();
|
|
24752
24968
|
this.router.closeOwner(owner);
|
|
24753
24969
|
});
|
|
@@ -24756,21 +24972,22 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24756
24972
|
builtins: core.builtins,
|
|
24757
24973
|
globals: core.globals,
|
|
24758
24974
|
aliases: this.aliases,
|
|
24759
|
-
overrides: this.modules
|
|
24975
|
+
overrides: Object.fromEntries(Object.entries(this.modules).map(([key, value]) => [key, hostWork.wrap(value)]))
|
|
24760
24976
|
});
|
|
24761
24977
|
try {
|
|
24762
|
-
await engine.run(script);
|
|
24763
|
-
await this.settle(owner, core.pendingHandles, core.
|
|
24764
|
-
if (this.router.activePorts(owner).length) {
|
|
24765
|
-
await proc.waitForKill();
|
|
24766
|
-
return 137;
|
|
24767
|
-
}
|
|
24978
|
+
await Promise.race([engine.run(script), proc.waitForKill()]);
|
|
24979
|
+
await this.settle(owner, core.pendingHandles, core.readingStdin, () => core.pendingRequests() + hostWork.pending(), () => proc.isKilled());
|
|
24768
24980
|
return requestedExit;
|
|
24769
24981
|
} finally {
|
|
24982
|
+
hostWork.dispose();
|
|
24983
|
+
core.cancelTimers();
|
|
24770
24984
|
untrack();
|
|
24771
24985
|
this.router.closeOwner(owner);
|
|
24772
24986
|
}
|
|
24773
24987
|
});
|
|
24988
|
+
this.running.add(process2);
|
|
24989
|
+
void process2.completion.then(() => this.running.delete(process2));
|
|
24990
|
+
return process2;
|
|
24774
24991
|
}
|
|
24775
24992
|
/**
|
|
24776
24993
|
* Rolldown's JavaScript API synchronously requires its compiled binding.
|
|
@@ -24806,19 +25023,13 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24806
25023
|
* A plain script that has genuinely finished falls straight through both,
|
|
24807
25024
|
* costing a handful of empty turns.
|
|
24808
25025
|
*/
|
|
24809
|
-
async settle(owner, pendingHandles,
|
|
24810
|
-
|
|
24811
|
-
|
|
24812
|
-
|
|
24813
|
-
|
|
24814
|
-
|
|
24815
|
-
|
|
24816
|
-
while (!this.router.activePorts(owner).length && !killed() && Date.now() < deadline) {
|
|
24817
|
-
await new Promise((resolve2) => setTimeout(resolve2, 5));
|
|
24818
|
-
}
|
|
24819
|
-
}
|
|
24820
|
-
while (!this.router.activePorts(owner).length && !killed() && (pendingHandles() > 0 || pendingRequests() > 0 || readingStdin())) {
|
|
24821
|
-
await new Promise((resolve2) => setTimeout(resolve2, 5));
|
|
25026
|
+
async settle(owner, pendingHandles, readingStdin, pendingRequests, killed) {
|
|
25027
|
+
let idleTurns = 0;
|
|
25028
|
+
while (!killed()) {
|
|
25029
|
+
const busy = this.router.referencedPorts(owner).length > 0 || pendingHandles() > 0 || pendingRequests() > 0 || readingStdin();
|
|
25030
|
+
idleTurns = busy ? 0 : idleTurns + 1;
|
|
25031
|
+
if (idleTurns >= DRAIN_TURNS) return;
|
|
25032
|
+
await new Promise((resolve2) => setTimeout(resolve2, busy ? 5 : 0));
|
|
24822
25033
|
}
|
|
24823
25034
|
}
|
|
24824
25035
|
async request(_port, _init = {}) {
|
|
@@ -24835,6 +25046,8 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
24835
25046
|
}
|
|
24836
25047
|
teardown() {
|
|
24837
25048
|
this.disposed = true;
|
|
25049
|
+
for (const process2 of this.running) process2.kill();
|
|
25050
|
+
this.running.clear();
|
|
24838
25051
|
this.router.closeAll();
|
|
24839
25052
|
this.esbuild?.stop();
|
|
24840
25053
|
}
|
|
@@ -24904,103 +25117,6 @@ function attachRolldownMirror(binding, volume, root) {
|
|
|
24904
25117
|
volume.attach(fs, root);
|
|
24905
25118
|
}
|
|
24906
25119
|
|
|
24907
|
-
// src/runtime/sync-channel.ts
|
|
24908
|
-
var STATE = 0;
|
|
24909
|
-
var LENGTH = 1;
|
|
24910
|
-
var MORE = 2;
|
|
24911
|
-
var CONTROL_WORDS = 4;
|
|
24912
|
-
var STATE_REQUEST = 1;
|
|
24913
|
-
var STATE_RESPONSE = 2;
|
|
24914
|
-
var STATE_CONTINUE = 3;
|
|
24915
|
-
var STATE_CLOSED = 4;
|
|
24916
|
-
function createSyncChannelBuffers(capacityBytes = 1 << 20) {
|
|
24917
|
-
return {
|
|
24918
|
-
control: new SharedArrayBuffer(CONTROL_WORDS * Int32Array.BYTES_PER_ELEMENT),
|
|
24919
|
-
data: new SharedArrayBuffer(capacityBytes)
|
|
24920
|
-
};
|
|
24921
|
-
}
|
|
24922
|
-
function syncChannelSupported() {
|
|
24923
|
-
if (typeof SharedArrayBuffer !== "function") return false;
|
|
24924
|
-
if (typeof Atomics !== "object" || typeof Atomics.wait !== "function") return false;
|
|
24925
|
-
if (typeof window !== "undefined" && globalThis.crossOriginIsolated !== true) return false;
|
|
24926
|
-
return true;
|
|
24927
|
-
}
|
|
24928
|
-
var SyncChannelServer = class {
|
|
24929
|
-
constructor(buffers, handle) {
|
|
24930
|
-
this.handle = handle;
|
|
24931
|
-
this.control = new Int32Array(buffers.control);
|
|
24932
|
-
this.data = new Uint8Array(buffers.data);
|
|
24933
|
-
this.capacity = this.data.length;
|
|
24934
|
-
}
|
|
24935
|
-
handle;
|
|
24936
|
-
control;
|
|
24937
|
-
data;
|
|
24938
|
-
capacity;
|
|
24939
|
-
/** Request chunks gathered so far, and the response still to be sent. */
|
|
24940
|
-
incoming = [];
|
|
24941
|
-
outgoing = null;
|
|
24942
|
-
sent = 0;
|
|
24943
|
-
closed = false;
|
|
24944
|
-
/** Call from the wake message the client sends after each chunk. */
|
|
24945
|
-
async pump() {
|
|
24946
|
-
if (this.closed) return;
|
|
24947
|
-
const state = Atomics.load(this.control, STATE);
|
|
24948
|
-
if (state === STATE_REQUEST) {
|
|
24949
|
-
const size = Atomics.load(this.control, LENGTH);
|
|
24950
|
-
this.incoming.push(this.data.slice(0, size));
|
|
24951
|
-
if (Atomics.load(this.control, MORE) === 1) {
|
|
24952
|
-
this.publish(STATE_CONTINUE);
|
|
24953
|
-
return;
|
|
24954
|
-
}
|
|
24955
|
-
const request = concat3(this.incoming);
|
|
24956
|
-
this.incoming = [];
|
|
24957
|
-
let response;
|
|
24958
|
-
try {
|
|
24959
|
-
response = await this.handle(request);
|
|
24960
|
-
} catch {
|
|
24961
|
-
response = new Uint8Array();
|
|
24962
|
-
}
|
|
24963
|
-
if (this.closed) return;
|
|
24964
|
-
this.outgoing = response;
|
|
24965
|
-
this.sent = 0;
|
|
24966
|
-
this.sendChunk();
|
|
24967
|
-
return;
|
|
24968
|
-
}
|
|
24969
|
-
if (state === STATE_CONTINUE) this.sendChunk();
|
|
24970
|
-
}
|
|
24971
|
-
/** Release a blocked client, e.g. when the container is torn down. */
|
|
24972
|
-
close() {
|
|
24973
|
-
if (this.closed) return;
|
|
24974
|
-
this.closed = true;
|
|
24975
|
-
Atomics.store(this.control, STATE, STATE_CLOSED);
|
|
24976
|
-
Atomics.notify(this.control, STATE);
|
|
24977
|
-
}
|
|
24978
|
-
sendChunk() {
|
|
24979
|
-
const payload = this.outgoing ?? new Uint8Array();
|
|
24980
|
-
const size = Math.min(this.capacity, payload.length - this.sent);
|
|
24981
|
-
this.data.set(payload.subarray(this.sent, this.sent + size), 0);
|
|
24982
|
-
this.sent += size;
|
|
24983
|
-
Atomics.store(this.control, LENGTH, size);
|
|
24984
|
-
Atomics.store(this.control, MORE, this.sent < payload.length ? 1 : 0);
|
|
24985
|
-
this.publish(STATE_RESPONSE);
|
|
24986
|
-
}
|
|
24987
|
-
publish(state) {
|
|
24988
|
-
Atomics.store(this.control, STATE, state);
|
|
24989
|
-
Atomics.notify(this.control, STATE);
|
|
24990
|
-
}
|
|
24991
|
-
};
|
|
24992
|
-
function concat3(parts) {
|
|
24993
|
-
if (parts.length === 1) return parts[0];
|
|
24994
|
-
const total = parts.reduce((sum, part) => sum + part.length, 0);
|
|
24995
|
-
const joined = new Uint8Array(total);
|
|
24996
|
-
let at = 0;
|
|
24997
|
-
for (const part of parts) {
|
|
24998
|
-
joined.set(part, at);
|
|
24999
|
-
at += part.length;
|
|
25000
|
-
}
|
|
25001
|
-
return joined;
|
|
25002
|
-
}
|
|
25003
|
-
|
|
25004
25120
|
// src/runtime/remote-volume.ts
|
|
25005
25121
|
var encoder7 = new TextEncoder();
|
|
25006
25122
|
var decoder7 = new TextDecoder();
|
|
@@ -25095,24 +25211,32 @@ function defaultWorkerUrl() {
|
|
|
25095
25211
|
return new URL("./worker-entry.js", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
25096
25212
|
}
|
|
25097
25213
|
function hasDomWorker() {
|
|
25098
|
-
return typeof Worker === "function"
|
|
25214
|
+
return typeof Worker === "function";
|
|
25099
25215
|
}
|
|
25100
25216
|
async function startRuntimeWorker(options = {}) {
|
|
25101
25217
|
const url = options.url ?? defaultWorkerUrl();
|
|
25102
25218
|
const worker = hasDomWorker() ? await startDomWorker(url) : await startNodeWorker(url, options.workerData ?? {});
|
|
25103
|
-
|
|
25104
|
-
|
|
25105
|
-
|
|
25106
|
-
|
|
25219
|
+
try {
|
|
25220
|
+
await new Promise((resolve2, reject) => {
|
|
25221
|
+
const timer = setTimeout(() => reject(new Error("the runtime worker did not start in time")), options.timeoutMs ?? 1e4);
|
|
25222
|
+
worker.onMessage((message) => {
|
|
25223
|
+
if (message?.type === "sandboxedjs:ready") {
|
|
25224
|
+
clearTimeout(timer);
|
|
25225
|
+
resolve2();
|
|
25226
|
+
}
|
|
25227
|
+
});
|
|
25228
|
+
worker.onError((error) => {
|
|
25107
25229
|
clearTimeout(timer);
|
|
25108
|
-
|
|
25109
|
-
}
|
|
25110
|
-
});
|
|
25111
|
-
worker.onError((error) => {
|
|
25112
|
-
clearTimeout(timer);
|
|
25113
|
-
reject(error instanceof Error ? error : new Error(String(error)));
|
|
25230
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
25231
|
+
});
|
|
25114
25232
|
});
|
|
25115
|
-
})
|
|
25233
|
+
} catch (error) {
|
|
25234
|
+
try {
|
|
25235
|
+
await worker.terminate();
|
|
25236
|
+
} catch {
|
|
25237
|
+
}
|
|
25238
|
+
throw error;
|
|
25239
|
+
}
|
|
25116
25240
|
return worker;
|
|
25117
25241
|
}
|
|
25118
25242
|
async function startDomWorker(url) {
|
|
@@ -25173,6 +25297,8 @@ var WorkerProcess = class extends EventEmitter4__default.default {
|
|
|
25173
25297
|
started = false;
|
|
25174
25298
|
pendingInput = [];
|
|
25175
25299
|
inputEnded = false;
|
|
25300
|
+
inheritedInput;
|
|
25301
|
+
ownRawMode = false;
|
|
25176
25302
|
on(event, listener) {
|
|
25177
25303
|
return super.on(event, listener);
|
|
25178
25304
|
}
|
|
@@ -25198,13 +25324,38 @@ var WorkerProcess = class extends EventEmitter4__default.default {
|
|
|
25198
25324
|
* program is still loading, and dropping them loses the answer to a prompt.
|
|
25199
25325
|
*/
|
|
25200
25326
|
write(data) {
|
|
25327
|
+
if (this.inheritedInput) {
|
|
25328
|
+
this.inheritedInput.sendStdin(data);
|
|
25329
|
+
return;
|
|
25330
|
+
}
|
|
25201
25331
|
if (this.started) this.worker.postMessage({ type: "stdin", data });
|
|
25202
25332
|
else this.pendingInput.push(data);
|
|
25203
25333
|
}
|
|
25204
25334
|
endInput() {
|
|
25205
25335
|
this.inputEnded = true;
|
|
25336
|
+
if (this.inheritedInput) {
|
|
25337
|
+
this.inheritedInput.endStdin?.();
|
|
25338
|
+
return;
|
|
25339
|
+
}
|
|
25206
25340
|
if (this.started) this.worker.postMessage({ type: "stdin-end" });
|
|
25207
25341
|
}
|
|
25342
|
+
rawMode(enabled) {
|
|
25343
|
+
this.ownRawMode = enabled;
|
|
25344
|
+
if (!this.inheritedInput) this.emit("rawmode", enabled);
|
|
25345
|
+
}
|
|
25346
|
+
/** The parent is blocked in Atomics.wait, so inherited input must bypass it. */
|
|
25347
|
+
inheritInput(child) {
|
|
25348
|
+
this.inheritedInput = child;
|
|
25349
|
+
this.emit("rawmode", false);
|
|
25350
|
+
child.on("rawmode", (enabled) => {
|
|
25351
|
+
if (this.inheritedInput === child) this.emit("rawmode", Boolean(enabled));
|
|
25352
|
+
});
|
|
25353
|
+
return () => {
|
|
25354
|
+
if (this.inheritedInput !== child) return;
|
|
25355
|
+
this.inheritedInput = void 0;
|
|
25356
|
+
this.emit("rawmode", this.ownRawMode);
|
|
25357
|
+
};
|
|
25358
|
+
}
|
|
25208
25359
|
kill(_signal = "SIGTERM") {
|
|
25209
25360
|
this.worker.postMessage({ type: "kill" });
|
|
25210
25361
|
this.finish(137);
|
|
@@ -25225,25 +25376,30 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25225
25376
|
super(options);
|
|
25226
25377
|
this.workerUrl = options.workerUrl;
|
|
25227
25378
|
}
|
|
25228
|
-
/**
|
|
25229
|
-
|
|
25230
|
-
|
|
25231
|
-
|
|
25232
|
-
|
|
25233
|
-
|
|
25234
|
-
|
|
25235
|
-
* and keeps working.
|
|
25236
|
-
*/
|
|
25237
|
-
static async tryBoot(options = {}) {
|
|
25238
|
-
if (!syncChannelSupported()) return null;
|
|
25239
|
-
if (options.modules && Object.keys(options.modules).length > 0) return null;
|
|
25379
|
+
/** Boot without silently dropping synchronous child-process support. */
|
|
25380
|
+
static async boot(options = {}) {
|
|
25381
|
+
const reason = syncChannelUnavailableReason();
|
|
25382
|
+
if (reason) throw new Error(`SandboxedJs worker runtime unavailable: ${reason}`);
|
|
25383
|
+
if (options.modules && Object.keys(options.modules).length > 0) {
|
|
25384
|
+
throw new Error("SandboxedJs worker runtime cannot clone host-supplied modules. Use isolation: 'realm' explicitly.");
|
|
25385
|
+
}
|
|
25240
25386
|
const pod = new _WorkerRuntimePod(options);
|
|
25241
25387
|
try {
|
|
25242
25388
|
const probe = await startRuntimeWorker({ ...options.workerUrl ? { url: options.workerUrl } : {}, timeoutMs: 1e4 });
|
|
25243
25389
|
await probe.terminate();
|
|
25244
25390
|
return pod;
|
|
25245
|
-
} catch {
|
|
25391
|
+
} catch (cause) {
|
|
25246
25392
|
pod.teardown();
|
|
25393
|
+
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
25394
|
+
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 });
|
|
25395
|
+
}
|
|
25396
|
+
}
|
|
25397
|
+
/** Compatibility mode, with an observable explanation for every fallback. */
|
|
25398
|
+
static async tryBoot(options = {}, onFallback = (error) => console.warn(`[sandboxedjs] Falling back to the realm runtime; synchronous child processes are unavailable. ${error.message}`)) {
|
|
25399
|
+
try {
|
|
25400
|
+
return await _WorkerRuntimePod.boot(options);
|
|
25401
|
+
} catch (error) {
|
|
25402
|
+
onFallback(error instanceof Error ? error : new Error(String(error)));
|
|
25247
25403
|
return null;
|
|
25248
25404
|
}
|
|
25249
25405
|
}
|
|
@@ -25266,11 +25422,14 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25266
25422
|
const streams = { target: null };
|
|
25267
25423
|
const server = new SyncChannelServer(buffers, serveSyncSyscalls({
|
|
25268
25424
|
volume: this.volume,
|
|
25269
|
-
spawnChild: (request) => this.runChildToCompletion(request, streams.target)
|
|
25425
|
+
spawnChild: (request) => this.runChildToCompletion(request, streams.target, ownedChildren)
|
|
25270
25426
|
}));
|
|
25271
25427
|
const entry = { worker, server };
|
|
25272
25428
|
this.live.add(entry);
|
|
25429
|
+
const ownedChildren = /* @__PURE__ */ new Set();
|
|
25273
25430
|
const process2 = new WorkerProcess(worker, () => {
|
|
25431
|
+
for (const child of ownedChildren) child.kill("SIGTERM");
|
|
25432
|
+
ownedChildren.clear();
|
|
25274
25433
|
this.live.delete(entry);
|
|
25275
25434
|
server.close();
|
|
25276
25435
|
this.closeProxies(owner);
|
|
@@ -25291,7 +25450,7 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25291
25450
|
process2.error(String(message.text));
|
|
25292
25451
|
return;
|
|
25293
25452
|
case "rawmode":
|
|
25294
|
-
process2.
|
|
25453
|
+
process2.rawMode(Boolean(message.enabled));
|
|
25295
25454
|
return;
|
|
25296
25455
|
case "exit":
|
|
25297
25456
|
process2.finish(Number(message.code));
|
|
@@ -25299,11 +25458,20 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25299
25458
|
case "listen":
|
|
25300
25459
|
this.proxyPort(Number(message.port), owner, worker);
|
|
25301
25460
|
return;
|
|
25461
|
+
case "close-port": {
|
|
25462
|
+
const port = Number(message.port);
|
|
25463
|
+
const proxy = this.proxies.get(port);
|
|
25464
|
+
if (proxy?.owner === owner) {
|
|
25465
|
+
proxy.close();
|
|
25466
|
+
this.proxies.delete(port);
|
|
25467
|
+
}
|
|
25468
|
+
return;
|
|
25469
|
+
}
|
|
25302
25470
|
case "http-response":
|
|
25303
25471
|
this.settleProxied(Number(message.id), message.response);
|
|
25304
25472
|
return;
|
|
25305
25473
|
case "child-start":
|
|
25306
|
-
this.startChild(worker, children, message);
|
|
25474
|
+
this.startChild(worker, children, message, ownedChildren);
|
|
25307
25475
|
return;
|
|
25308
25476
|
case "child-stdin":
|
|
25309
25477
|
children.get(message.id)?.sendStdin?.(String(message.data));
|
|
@@ -25334,16 +25502,21 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25334
25502
|
return process2;
|
|
25335
25503
|
}
|
|
25336
25504
|
/** Start an asynchronous child on the host's behalf and relay its events. */
|
|
25337
|
-
startChild(worker, children, message) {
|
|
25505
|
+
startChild(worker, children, message, owned) {
|
|
25338
25506
|
const handle = this.processManager.spawn(message.config);
|
|
25339
25507
|
children.set(message.id, handle);
|
|
25508
|
+
owned.add(handle);
|
|
25509
|
+
handle.on("exit", () => {
|
|
25510
|
+
owned.delete(handle);
|
|
25511
|
+
children.delete(message.id);
|
|
25512
|
+
});
|
|
25340
25513
|
for (const event of ["stdout", "stderr", "exit"]) {
|
|
25341
25514
|
handle.on(event, (value) => worker.postMessage({ type: "child-event", id: message.id, event, value }));
|
|
25342
25515
|
}
|
|
25343
25516
|
handle.exec();
|
|
25344
25517
|
}
|
|
25345
25518
|
/** Run a child to completion and collect it, for the guest's `spawnSync`. */
|
|
25346
|
-
runChildToCompletion(request, streamTo) {
|
|
25519
|
+
runChildToCompletion(request, streamTo, owned) {
|
|
25347
25520
|
return new Promise((resolve2) => {
|
|
25348
25521
|
let handle;
|
|
25349
25522
|
try {
|
|
@@ -25359,9 +25532,13 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
25359
25532
|
resolve2({ status: null, stdout: "", stderr: "", signal: null, error: { ...failure.code ? { code: failure.code } : {}, message: failure.message } });
|
|
25360
25533
|
return;
|
|
25361
25534
|
}
|
|
25535
|
+
owned.add(handle);
|
|
25536
|
+
handle.on("exit", () => owned.delete(handle));
|
|
25362
25537
|
let stdout = "";
|
|
25363
25538
|
let stderr = "";
|
|
25364
25539
|
const live = request.inheritStdio ? streamTo : null;
|
|
25540
|
+
const restoreInput = live?.inheritInput(handle);
|
|
25541
|
+
if (restoreInput) handle.on("exit", restoreInput);
|
|
25365
25542
|
handle.on("stdout", (text2) => {
|
|
25366
25543
|
stdout += text2;
|
|
25367
25544
|
live?.output(text2);
|
|
@@ -25515,7 +25692,7 @@ var Container = class _Container {
|
|
|
25515
25692
|
...opts.onServerReady ? { onServerReady: opts.onServerReady } : {}
|
|
25516
25693
|
};
|
|
25517
25694
|
const workerOptions = { ...podOptions, ...opts.workerUrl ? { workerUrl: opts.workerUrl } : {} };
|
|
25518
|
-
const pod = opts.pod ?? (opts.isolation === "realm" ? null : await WorkerRuntimePod.tryBoot(workerOptions)) ?? await LocalRuntimePod.boot(podOptions);
|
|
25695
|
+
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);
|
|
25519
25696
|
const kernel = new Kernel({
|
|
25520
25697
|
pod,
|
|
25521
25698
|
hostname: opts.hostname ?? "sandbox",
|
|
@@ -26023,7 +26200,7 @@ var Terminal = class {
|
|
|
26023
26200
|
if (this.running) {
|
|
26024
26201
|
const raw = this.currentStdin?.rawMode === true;
|
|
26025
26202
|
if (ch === CTRL_C && !raw) {
|
|
26026
|
-
this.session.
|
|
26203
|
+
if (this.currentStdin) this.session.shell.interruptForeground("SIGINT", this.currentStdin);
|
|
26027
26204
|
this.write("^C\r\n");
|
|
26028
26205
|
return;
|
|
26029
26206
|
}
|
|
@@ -26413,7 +26590,7 @@ function serveContainerOn(port, box) {
|
|
|
26413
26590
|
}
|
|
26414
26591
|
async function createPreview(box, options = {}) {
|
|
26415
26592
|
if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) return null;
|
|
26416
|
-
const scriptUrl = options.scriptUrl ?? new URL("./service-worker.js", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
26593
|
+
const scriptUrl = options.scriptUrl ?? new URL("./service-worker.js?no-inline", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
26417
26594
|
let registration;
|
|
26418
26595
|
try {
|
|
26419
26596
|
registration = await navigator.serviceWorker.register(scriptUrl, {
|