sandboxedjs 0.1.73 → 0.1.74
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 +25 -2
- package/dist/agent.d.cts +2 -2
- package/dist/agent.d.ts +2 -2
- package/dist/{container-B5X6stfx.d.ts → container-CsLNpeyi.d.ts} +18 -3
- package/dist/{container-BxEoVOmX.d.cts → container-DAWPIkGG.d.cts} +18 -3
- package/dist/{contracts-CVgctitO.d.cts → contracts-C2_dTgk3.d.cts} +30 -1
- package/dist/{contracts-CVgctitO.d.ts → contracts-C2_dTgk3.d.ts} +30 -1
- package/dist/index.cjs +2425 -1235
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +57 -5
- package/dist/index.d.ts +57 -5
- package/dist/index.js +2426 -1236
- package/dist/index.js.map +1 -1
- package/dist/{memory-volume-CWuWScIs.d.ts → memory-volume-CG56p660.d.ts} +1 -1
- package/dist/{memory-volume-DlMSAh-K.d.cts → memory-volume-DqEWFo7t.d.cts} +1 -1
- package/dist/python-abi.d.cts +3 -3
- package/dist/python-abi.d.ts +3 -3
- package/dist/rolldown-wasi-worker.js +5 -1
- package/dist/rolldown-wasi-worker.js.map +1 -1
- package/dist/worker-entry.js +861 -55
- package/dist/worker-entry.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { inflateRaw, ungzip, gzip as gzip$1, deflate as deflate$1, inflate as inflate$1, deflateRaw } from 'pako';
|
|
2
|
+
import { Parser as Parser$1, parse as parse$1 } from 'acorn';
|
|
3
|
+
import jsx from 'acorn-jsx';
|
|
2
4
|
import { sha256, sha224 } from '@noble/hashes/sha256';
|
|
3
5
|
import { Buffer as Buffer$1 } from 'buffer/index.js';
|
|
4
6
|
import { sha512, sha384 } from '@noble/hashes/sha512';
|
|
5
7
|
import { sha1 } from '@noble/hashes/sha1';
|
|
6
8
|
import { valid, maxSatisfying } from 'semver';
|
|
7
|
-
import { Parser as Parser$1, parse as parse$1 } from 'acorn';
|
|
8
9
|
import EventEmitter4 from 'events/events.js';
|
|
9
|
-
import jsx from 'acorn-jsx';
|
|
10
10
|
import { exports as exports$1, imports } from 'resolve.exports';
|
|
11
11
|
import pathModule from 'path-browserify';
|
|
12
12
|
import streamModule4 from 'stream-browserify';
|
|
@@ -3807,7 +3807,10 @@ function builtinKill({ shell, argv, io }) {
|
|
|
3807
3807
|
for (const target of args.slice(i)) {
|
|
3808
3808
|
if (target.startsWith("%")) {
|
|
3809
3809
|
const job = shell.jobs.find((j) => j.id === Number(target.slice(1)));
|
|
3810
|
-
if (job)
|
|
3810
|
+
if (job) {
|
|
3811
|
+
if (job.state !== "done") shell.kernel.procs.signal(job.pgid, signal);
|
|
3812
|
+
continue;
|
|
3813
|
+
}
|
|
3811
3814
|
io.stderr.write(`kill: ${target}: no such job
|
|
3812
3815
|
`);
|
|
3813
3816
|
status = 1;
|
|
@@ -5403,6 +5406,51 @@ var BufferSink = class {
|
|
|
5403
5406
|
this.total = 0;
|
|
5404
5407
|
}
|
|
5405
5408
|
};
|
|
5409
|
+
var DetachableOutput = class {
|
|
5410
|
+
constructor(inner, onDetached) {
|
|
5411
|
+
this.inner = inner;
|
|
5412
|
+
this.onDetached = onDetached;
|
|
5413
|
+
}
|
|
5414
|
+
inner;
|
|
5415
|
+
onDetached;
|
|
5416
|
+
attached = true;
|
|
5417
|
+
decoder = new TextDecoder();
|
|
5418
|
+
get closed() {
|
|
5419
|
+
return this.attached ? this.inner.closed : false;
|
|
5420
|
+
}
|
|
5421
|
+
get isTTY() {
|
|
5422
|
+
return this.inner.isTTY;
|
|
5423
|
+
}
|
|
5424
|
+
set isTTY(value) {
|
|
5425
|
+
this.inner.isTTY = value;
|
|
5426
|
+
}
|
|
5427
|
+
get columns() {
|
|
5428
|
+
return this.inner.columns;
|
|
5429
|
+
}
|
|
5430
|
+
set columns(value) {
|
|
5431
|
+
this.inner.columns = value;
|
|
5432
|
+
}
|
|
5433
|
+
get rows() {
|
|
5434
|
+
return this.inner.rows;
|
|
5435
|
+
}
|
|
5436
|
+
set rows(value) {
|
|
5437
|
+
this.inner.rows = value;
|
|
5438
|
+
}
|
|
5439
|
+
write(data) {
|
|
5440
|
+
if (this.attached) {
|
|
5441
|
+
this.inner.write(data);
|
|
5442
|
+
return;
|
|
5443
|
+
}
|
|
5444
|
+
if (!this.onDetached) return;
|
|
5445
|
+
this.onDetached(typeof data === "string" ? data : this.decoder.decode(data, { stream: true }));
|
|
5446
|
+
}
|
|
5447
|
+
end() {
|
|
5448
|
+
if (this.attached) this.inner.end();
|
|
5449
|
+
}
|
|
5450
|
+
detach() {
|
|
5451
|
+
this.attached = false;
|
|
5452
|
+
}
|
|
5453
|
+
};
|
|
5406
5454
|
var CallbackSink = class {
|
|
5407
5455
|
constructor(sink, opts = {}) {
|
|
5408
5456
|
this.sink = sink;
|
|
@@ -7265,6 +7313,77 @@ function createSysProvider(kernel) {
|
|
|
7265
7313
|
};
|
|
7266
7314
|
}
|
|
7267
7315
|
|
|
7316
|
+
// src/net/policy.ts
|
|
7317
|
+
function isLoopbackHostname(hostname) {
|
|
7318
|
+
const host2 = hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
7319
|
+
return host2 === "localhost" || host2 === "0.0.0.0" || host2 === "::1" || host2 === "::" || host2.startsWith("127.") || host2.endsWith(".localhost");
|
|
7320
|
+
}
|
|
7321
|
+
function outboundAllowed(policy, url) {
|
|
7322
|
+
if (!policy.allowOutbound) return false;
|
|
7323
|
+
let hostname;
|
|
7324
|
+
try {
|
|
7325
|
+
hostname = new URL(url).hostname;
|
|
7326
|
+
} catch {
|
|
7327
|
+
return false;
|
|
7328
|
+
}
|
|
7329
|
+
if (isLoopbackHostname(hostname)) return false;
|
|
7330
|
+
const hosts = policy.allowedHosts;
|
|
7331
|
+
if (!hosts) return true;
|
|
7332
|
+
return hosts.some((allowed) => hostname === allowed || hostname.endsWith(`.${allowed}`));
|
|
7333
|
+
}
|
|
7334
|
+
function outboundBlockedError(url) {
|
|
7335
|
+
let host2 = url;
|
|
7336
|
+
try {
|
|
7337
|
+
host2 = new URL(url).host;
|
|
7338
|
+
} catch {
|
|
7339
|
+
}
|
|
7340
|
+
return Object.assign(
|
|
7341
|
+
new Error(
|
|
7342
|
+
`connect ENETUNREACH ${host2}: outbound network access is disabled for this container (allowed by the host with network.allowOutbound and network.allowedHosts)`
|
|
7343
|
+
),
|
|
7344
|
+
{ code: "ENETUNREACH", errno: -101, syscall: "connect", hostname: host2 }
|
|
7345
|
+
);
|
|
7346
|
+
}
|
|
7347
|
+
function requestUrl(input) {
|
|
7348
|
+
if (typeof input === "string") return input;
|
|
7349
|
+
if (input instanceof URL) return input.href;
|
|
7350
|
+
return input.url;
|
|
7351
|
+
}
|
|
7352
|
+
function policedFetch(policy, fetchImpl) {
|
|
7353
|
+
return (async (input, init) => {
|
|
7354
|
+
const url = requestUrl(input);
|
|
7355
|
+
if (!outboundAllowed(policy, url)) {
|
|
7356
|
+
throw Object.assign(new TypeError("fetch failed"), { cause: outboundBlockedError(url) });
|
|
7357
|
+
}
|
|
7358
|
+
return fetchImpl(input, init);
|
|
7359
|
+
});
|
|
7360
|
+
}
|
|
7361
|
+
function policedWebSocket(Native, policy) {
|
|
7362
|
+
const Base = Native;
|
|
7363
|
+
return class PolicedWebSocket extends Base {
|
|
7364
|
+
constructor(url, protocols) {
|
|
7365
|
+
const href = url instanceof URL ? url.href : String(url);
|
|
7366
|
+
let parsed = null;
|
|
7367
|
+
try {
|
|
7368
|
+
parsed = new URL(href);
|
|
7369
|
+
} catch {
|
|
7370
|
+
}
|
|
7371
|
+
if (parsed && isLoopbackHostname(parsed.hostname)) {
|
|
7372
|
+
throw Object.assign(
|
|
7373
|
+
new Error(
|
|
7374
|
+
`WebSocket to ${parsed.host} is not available from a program inside the container; reach servers in the container over HTTP`
|
|
7375
|
+
),
|
|
7376
|
+
{ code: "ERR_UNSUPPORTED" }
|
|
7377
|
+
);
|
|
7378
|
+
}
|
|
7379
|
+
if (parsed && !outboundAllowed(policy, href.replace(/^ws(s?):/i, "http$1:"))) {
|
|
7380
|
+
throw outboundBlockedError(href);
|
|
7381
|
+
}
|
|
7382
|
+
super(url, protocols);
|
|
7383
|
+
}
|
|
7384
|
+
};
|
|
7385
|
+
}
|
|
7386
|
+
|
|
7268
7387
|
// src/net/stack.ts
|
|
7269
7388
|
var NetworkStack = class {
|
|
7270
7389
|
constructor(pod, vfs, options = {}) {
|
|
@@ -7403,16 +7522,12 @@ var NetworkStack = class {
|
|
|
7403
7522
|
return false;
|
|
7404
7523
|
}
|
|
7405
7524
|
// ── outbound policy ──────────────────────────────────────────────────────
|
|
7525
|
+
/** The policy every way out of the container applies, not only the shell's. */
|
|
7526
|
+
get policy() {
|
|
7527
|
+
return { allowOutbound: this.options.allowOutbound, allowedHosts: this.options.allowedHosts ?? null };
|
|
7528
|
+
}
|
|
7406
7529
|
outboundAllowed(url) {
|
|
7407
|
-
|
|
7408
|
-
const hosts = this.options.allowedHosts;
|
|
7409
|
-
if (hosts === null || hosts === void 0) return true;
|
|
7410
|
-
try {
|
|
7411
|
-
const { hostname } = new URL(url);
|
|
7412
|
-
return hosts.some((h) => hostname === h || hostname.endsWith("." + h));
|
|
7413
|
-
} catch {
|
|
7414
|
-
return false;
|
|
7415
|
-
}
|
|
7530
|
+
return outboundAllowed(this.policy, url);
|
|
7416
7531
|
}
|
|
7417
7532
|
// ── /proc plumbing ───────────────────────────────────────────────────────
|
|
7418
7533
|
procNetDev() {
|
|
@@ -8560,11 +8675,16 @@ var Shell = class _Shell {
|
|
|
8560
8675
|
}
|
|
8561
8676
|
return path;
|
|
8562
8677
|
}
|
|
8563
|
-
/**
|
|
8564
|
-
|
|
8678
|
+
/**
|
|
8679
|
+
* A copy that shares nothing mutable with this shell.
|
|
8680
|
+
*
|
|
8681
|
+
* Subshells and pipeline stages run as part of this shell's process. A
|
|
8682
|
+
* background job passes a process of its own, the way fork(2) gives one.
|
|
8683
|
+
*/
|
|
8684
|
+
fork(proc = this.proc) {
|
|
8565
8685
|
const sub = new _Shell({
|
|
8566
8686
|
kernel: this.kernel,
|
|
8567
|
-
proc
|
|
8687
|
+
proc,
|
|
8568
8688
|
cwd: this.cwd,
|
|
8569
8689
|
cred: this.cred,
|
|
8570
8690
|
env: {},
|
|
@@ -8719,29 +8839,42 @@ sys ${fmt2(Math.floor(ms * 0.2))}
|
|
|
8719
8839
|
`);
|
|
8720
8840
|
}
|
|
8721
8841
|
startBackgroundJob(node2, io) {
|
|
8722
|
-
const
|
|
8842
|
+
const jobProc = this.kernel.procs.create({
|
|
8843
|
+
argv: [this.scriptName],
|
|
8844
|
+
cwd: this.cwd,
|
|
8845
|
+
env: this.vars.environment(),
|
|
8846
|
+
cred: this.cred,
|
|
8847
|
+
ppid: this.proc.pid,
|
|
8848
|
+
kind: "shell",
|
|
8849
|
+
tty: this.proc.tty,
|
|
8850
|
+
stdio: { stdin: new NullInput(), stdout: io.stdout, stderr: io.stderr }
|
|
8851
|
+
});
|
|
8852
|
+
const sub = this.fork(jobProc);
|
|
8723
8853
|
const id = this.nextJobId++;
|
|
8724
8854
|
const command = describeNode(node2);
|
|
8725
8855
|
const job = {
|
|
8726
8856
|
id,
|
|
8727
|
-
pgid:
|
|
8857
|
+
pgid: jobProc.pid,
|
|
8728
8858
|
command,
|
|
8729
8859
|
state: "running",
|
|
8730
8860
|
exitCode: null,
|
|
8731
|
-
pids: [],
|
|
8861
|
+
pids: [jobProc.pid],
|
|
8732
8862
|
promise: Promise.resolve(0)
|
|
8733
8863
|
};
|
|
8734
8864
|
job.promise = (async () => {
|
|
8865
|
+
let code;
|
|
8735
8866
|
try {
|
|
8736
|
-
|
|
8737
|
-
job.exitCode = code;
|
|
8738
|
-
job.state = "done";
|
|
8739
|
-
return code;
|
|
8867
|
+
code = await sub.run(node2, { stdin: new NullInput(), stdout: io.stdout, stderr: io.stderr });
|
|
8740
8868
|
} catch (e) {
|
|
8741
|
-
|
|
8742
|
-
job.exitCode = e instanceof ShellExit ? e.code : 1;
|
|
8743
|
-
return job.exitCode;
|
|
8869
|
+
code = e instanceof ShellExit ? e.code : 1;
|
|
8744
8870
|
}
|
|
8871
|
+
jobProc.exit(code);
|
|
8872
|
+
job.exitCode = jobProc.exitCode ?? code;
|
|
8873
|
+
job.state = "done";
|
|
8874
|
+
queueMicrotask(() => {
|
|
8875
|
+
if (jobProc.children.size === 0) this.kernel.procs.remove(jobProc.pid);
|
|
8876
|
+
});
|
|
8877
|
+
return job.exitCode;
|
|
8745
8878
|
})();
|
|
8746
8879
|
this.jobs.push(job);
|
|
8747
8880
|
this.lastBackgroundPid = job.pgid;
|
|
@@ -17478,439 +17611,1112 @@ var commands11 = [xsel, xclip, pbcopy, pbpaste, wlCopy, wlPaste];
|
|
|
17478
17611
|
|
|
17479
17612
|
// src/node/node.ts
|
|
17480
17613
|
init_path();
|
|
17481
|
-
var
|
|
17482
|
-
|
|
17483
|
-
|
|
17484
|
-
|
|
17485
|
-
|
|
17486
|
-
|
|
17487
|
-
|
|
17488
|
-
|
|
17489
|
-
|
|
17490
|
-
|
|
17491
|
-
|
|
17492
|
-
|
|
17493
|
-
|
|
17494
|
-
|
|
17495
|
-
|
|
17496
|
-
|
|
17497
|
-
|
|
17498
|
-
|
|
17499
|
-
|
|
17500
|
-
|
|
17501
|
-
|
|
17502
|
-
|
|
17503
|
-
|
|
17504
|
-
|
|
17505
|
-
|
|
17506
|
-
try { widen(globalThis.Buffer); } catch (e) {}
|
|
17507
|
-
try { widen(require('buffer').Buffer); } catch (e) {}
|
|
17508
|
-
})();
|
|
17509
|
-
`;
|
|
17510
|
-
function buildPrelude(scriptPath, argv, stdinPath) {
|
|
17511
|
-
const argvLiteral = JSON.stringify(["/usr/bin/node", scriptPath, ...argv]);
|
|
17512
|
-
const pathLiteral = JSON.stringify(scriptPath);
|
|
17513
|
-
const stdinLiteral = JSON.stringify(stdinPath);
|
|
17514
|
-
return `${BUFFER_COMPAT_SHIM}
|
|
17515
|
-
process.argv = ${argvLiteral};
|
|
17516
|
-
try {
|
|
17517
|
-
__filename = ${pathLiteral};
|
|
17518
|
-
module.filename = ${pathLiteral};
|
|
17519
|
-
module.id = ${pathLiteral};
|
|
17520
|
-
if (require.main === module) require.main.filename = ${pathLiteral};
|
|
17521
|
-
} catch (e) {}
|
|
17522
|
-
${stdinPath === null ? "" : `(function () {
|
|
17523
|
-
const fs = require('fs');
|
|
17524
|
-
const { Readable } = require('stream');
|
|
17525
|
-
let data;
|
|
17526
|
-
try { data = fs.readFileSync(${stdinLiteral}); } catch (e) { data = Buffer.alloc(0); }
|
|
17527
|
-
const stream = Readable.from([data]);
|
|
17528
|
-
stream.isTTY = false;
|
|
17529
|
-
stream.fd = 0;
|
|
17530
|
-
stream.setRawMode = function () { return this; };
|
|
17531
|
-
try {
|
|
17532
|
-
Object.defineProperty(process, 'stdin', { value: stream, configurable: true, writable: true });
|
|
17533
|
-
} catch (e) { process.stdin = stream; }
|
|
17534
|
-
})();
|
|
17535
|
-
`}`;
|
|
17614
|
+
var HELPERS = {
|
|
17615
|
+
/** Import a specifier and return an ES-module-shaped namespace. */
|
|
17616
|
+
import: "__sbxImport",
|
|
17617
|
+
/** `import(...)`, returning a promise of a namespace. */
|
|
17618
|
+
dynamic: "__sbxDynamicImport",
|
|
17619
|
+
/** `export * from` — copy live bindings onto `exports`. */
|
|
17620
|
+
exportAll: "__sbxExportAll",
|
|
17621
|
+
/** `import.meta`. */
|
|
17622
|
+
meta: "__sbxMeta",
|
|
17623
|
+
/**
|
|
17624
|
+
* The exports object, under a name of the engine's choosing.
|
|
17625
|
+
*
|
|
17626
|
+
* An ES module is free to declare its own top-level `exports`, `require` or
|
|
17627
|
+
* `__dirname` — they are ordinary identifiers there, and real packages use
|
|
17628
|
+
* all three (`const require = createRequire(import.meta.url)` is close to
|
|
17629
|
+
* idiomatic). Naming the wrapper's binding something no source would write
|
|
17630
|
+
* removes that entire class of collision instead of patching it up after a
|
|
17631
|
+
* `SyntaxError`.
|
|
17632
|
+
*/
|
|
17633
|
+
exports: "__sbxExports"
|
|
17634
|
+
};
|
|
17635
|
+
var DEFAULT_LOCAL = "__sbxDefault";
|
|
17636
|
+
var MAYBE_ESM = /(^|[\s;}(])(?:import|export)(?:[\s({[*"']|$)|\bimport\s*\.\s*meta\b/;
|
|
17637
|
+
function looksLikeEsm(source) {
|
|
17638
|
+
return MAYBE_ESM.test(source);
|
|
17536
17639
|
}
|
|
17537
|
-
|
|
17538
|
-
|
|
17539
|
-
|
|
17540
|
-
const tty = ctx.stdin.isTTY;
|
|
17541
|
-
let exitCode = 0;
|
|
17640
|
+
function transformEsm(source, filename = "module.js") {
|
|
17641
|
+
if (!looksLikeEsm(source)) return null;
|
|
17642
|
+
let ast;
|
|
17542
17643
|
try {
|
|
17543
|
-
|
|
17544
|
-
|
|
17545
|
-
|
|
17546
|
-
argv: ["/usr/bin/node", invocation.argvPath ?? invocation.script, ...invocation.argv],
|
|
17547
|
-
...invocation.stdinPath ? { stdinPath: invocation.stdinPath } : {},
|
|
17548
|
-
/* An interactive caller's input was not captured to a file, so the
|
|
17549
|
-
* program's stdin has to stay open and be fed as it arrives — and be
|
|
17550
|
-
* reported as a terminal, since that is what decides whether a CLI
|
|
17551
|
-
* prompts or takes its defaults. */
|
|
17552
|
-
...live ? { interactiveStdin: true } : {},
|
|
17553
|
-
...tty ? { tty: true } : {}
|
|
17554
|
-
});
|
|
17555
|
-
proc.on("output", (chunk) => {
|
|
17556
|
-
try {
|
|
17557
|
-
ctx.write(chunk);
|
|
17558
|
-
} catch {
|
|
17559
|
-
}
|
|
17560
|
-
});
|
|
17561
|
-
proc.on("error", (chunk) => {
|
|
17562
|
-
try {
|
|
17563
|
-
ctx.stderr.write(chunk);
|
|
17564
|
-
} catch {
|
|
17565
|
-
}
|
|
17566
|
-
});
|
|
17567
|
-
proc.on("rawmode", (enabled) => {
|
|
17568
|
-
ctx.stdin.rawMode = enabled;
|
|
17569
|
-
});
|
|
17570
|
-
let forwarding = false;
|
|
17571
|
-
if (live) {
|
|
17572
|
-
forwarding = true;
|
|
17573
|
-
void (async () => {
|
|
17574
|
-
while (forwarding) {
|
|
17575
|
-
const chunk = await ctx.stdin.read();
|
|
17576
|
-
if (chunk === null) {
|
|
17577
|
-
proc.endInput?.();
|
|
17578
|
-
break;
|
|
17579
|
-
}
|
|
17580
|
-
try {
|
|
17581
|
-
proc.write(new TextDecoder().decode(chunk));
|
|
17582
|
-
} catch {
|
|
17583
|
-
break;
|
|
17584
|
-
}
|
|
17585
|
-
}
|
|
17586
|
-
})();
|
|
17587
|
-
}
|
|
17588
|
-
let onAbort;
|
|
17589
|
-
const aborted = new Promise((resolve3) => {
|
|
17590
|
-
onAbort = () => {
|
|
17591
|
-
try {
|
|
17592
|
-
proc.kill();
|
|
17593
|
-
} catch {
|
|
17594
|
-
}
|
|
17595
|
-
resolve3({ exitCode: 137 });
|
|
17596
|
-
};
|
|
17597
|
-
if (ctx.signal.aborted) onAbort();
|
|
17598
|
-
else ctx.signal.addEventListener("abort", onAbort, { once: true });
|
|
17599
|
-
});
|
|
17600
|
-
const result = await Promise.race([proc.completion, aborted]);
|
|
17601
|
-
forwarding = false;
|
|
17602
|
-
if (onAbort) ctx.signal.removeEventListener("abort", onAbort);
|
|
17603
|
-
exitCode = result.exitCode;
|
|
17604
|
-
} catch (e) {
|
|
17605
|
-
ctx.stderr.write(`node: ${e instanceof Error ? e.message : String(e)}
|
|
17606
|
-
`);
|
|
17607
|
-
exitCode = 1;
|
|
17608
|
-
} finally {
|
|
17609
|
-
for (const temp of invocation.temps) {
|
|
17610
|
-
try {
|
|
17611
|
-
ctx.vfs.unlink(temp);
|
|
17612
|
-
} catch {
|
|
17613
|
-
}
|
|
17614
|
-
}
|
|
17644
|
+
ast = parseModule(source, filename);
|
|
17645
|
+
} catch {
|
|
17646
|
+
return null;
|
|
17615
17647
|
}
|
|
17616
|
-
|
|
17617
|
-
|
|
17618
|
-
|
|
17619
|
-
|
|
17620
|
-
const
|
|
17621
|
-
|
|
17622
|
-
|
|
17623
|
-
|
|
17624
|
-
|
|
17625
|
-
|
|
17626
|
-
|
|
17627
|
-
|
|
17628
|
-
|
|
17629
|
-
|
|
17630
|
-
|
|
17631
|
-
|
|
17632
|
-
|
|
17633
|
-
|
|
17634
|
-
|
|
17635
|
-
|
|
17636
|
-
|
|
17637
|
-
|
|
17638
|
-
|
|
17639
|
-
|
|
17640
|
-
let printResult = false;
|
|
17641
|
-
let scriptArg;
|
|
17642
|
-
for (; i < argv.length; i++) {
|
|
17643
|
-
const arg = argv[i];
|
|
17644
|
-
if (arg === "-v" || arg === "--version") {
|
|
17645
|
-
ctx.line(NODE_VERSION);
|
|
17646
|
-
return 0;
|
|
17647
|
-
}
|
|
17648
|
-
if (arg === "-h" || arg === "--help") {
|
|
17649
|
-
printHelp(ctx);
|
|
17650
|
-
return 0;
|
|
17651
|
-
}
|
|
17652
|
-
if (arg === "-e" || arg === "--eval") {
|
|
17653
|
-
evalSource = argv[++i] ?? "";
|
|
17654
|
-
i++;
|
|
17655
|
-
break;
|
|
17656
|
-
}
|
|
17657
|
-
if (arg === "-p" || arg === "--print") {
|
|
17658
|
-
printResult = true;
|
|
17659
|
-
evalSource = argv[++i] ?? "";
|
|
17660
|
-
i++;
|
|
17661
|
-
break;
|
|
17662
|
-
}
|
|
17663
|
-
if (arg.startsWith("--eval=")) {
|
|
17664
|
-
evalSource = arg.slice("--eval=".length);
|
|
17665
|
-
i++;
|
|
17648
|
+
const body = ast.body;
|
|
17649
|
+
const hasModuleSyntax = body.some(
|
|
17650
|
+
(node2) => node2.type.startsWith("Import") || node2.type.startsWith("Export")
|
|
17651
|
+
);
|
|
17652
|
+
const usesImportMeta = !hasModuleSyntax && containsImportMeta(ast);
|
|
17653
|
+
const esm = hasModuleSyntax || usesImportMeta;
|
|
17654
|
+
if (!esm && !containsImportExpression(ast)) return null;
|
|
17655
|
+
const edits = [];
|
|
17656
|
+
const prelude = [];
|
|
17657
|
+
const importBindings = /* @__PURE__ */ new Map();
|
|
17658
|
+
const exportGetters = /* @__PURE__ */ new Map();
|
|
17659
|
+
let namespaceCount = 0;
|
|
17660
|
+
const namespaceFor = (specifier) => {
|
|
17661
|
+
const id = `__sbxNs${namespaceCount++}`;
|
|
17662
|
+
prelude.push(`var ${id} = ${HELPERS.import}(${JSON.stringify(specifier)});`);
|
|
17663
|
+
return id;
|
|
17664
|
+
};
|
|
17665
|
+
for (const node2 of body) {
|
|
17666
|
+
if (node2.type === "ImportDeclaration") collectImport(node2);
|
|
17667
|
+
}
|
|
17668
|
+
for (const node2 of body) {
|
|
17669
|
+
switch (node2.type) {
|
|
17670
|
+
case "ExportNamedDeclaration":
|
|
17671
|
+
collectNamedExport(node2);
|
|
17666
17672
|
break;
|
|
17667
|
-
|
|
17668
|
-
|
|
17669
|
-
printResult = true;
|
|
17670
|
-
evalSource = arg.slice("--print=".length);
|
|
17671
|
-
i++;
|
|
17673
|
+
case "ExportDefaultDeclaration":
|
|
17674
|
+
collectDefaultExport(node2);
|
|
17672
17675
|
break;
|
|
17673
|
-
|
|
17674
|
-
|
|
17675
|
-
i++;
|
|
17676
|
+
case "ExportAllDeclaration":
|
|
17677
|
+
collectExportAll(node2);
|
|
17676
17678
|
break;
|
|
17677
|
-
}
|
|
17678
|
-
if (arg.startsWith("-") && arg !== "-") {
|
|
17679
|
-
continue;
|
|
17680
|
-
}
|
|
17681
|
-
scriptArg = arg;
|
|
17682
|
-
i++;
|
|
17683
|
-
break;
|
|
17684
|
-
}
|
|
17685
|
-
const scriptArgs = argv.slice(i);
|
|
17686
|
-
if (evalSource !== void 0) {
|
|
17687
|
-
const body = printResult ? `const __sbxResult = (function(){ return (${evalSource}
|
|
17688
|
-
); })();
|
|
17689
|
-
console.log(typeof __sbxResult === 'string' ? __sbxResult : require('util').inspect(__sbxResult));` : evalSource;
|
|
17690
|
-
const path = tempPath("eval", ctx.proc.pid);
|
|
17691
|
-
const stdinPath2 = await captureStdin(ctx);
|
|
17692
|
-
if (stdinPath2) temps.push(stdinPath2);
|
|
17693
|
-
ctx.vfs.writeFile(path, buildBootstrapForEval(body, ["/usr/bin/node", ...scriptArgs], stdinPath2), {
|
|
17694
|
-
privileged: true,
|
|
17695
|
-
mode: 384
|
|
17696
|
-
});
|
|
17697
|
-
temps.push(path);
|
|
17698
|
-
return execute(ctx, { script: path, argv: scriptArgs, stdinPath: stdinPath2, temps });
|
|
17699
17679
|
}
|
|
17700
|
-
|
|
17701
|
-
|
|
17702
|
-
|
|
17703
|
-
|
|
17704
|
-
|
|
17680
|
+
}
|
|
17681
|
+
rewriteReferences();
|
|
17682
|
+
const header = esm ? [
|
|
17683
|
+
`Object.defineProperty(${HELPERS.exports}, "__esModule", { value: true });`,
|
|
17684
|
+
...prelude,
|
|
17685
|
+
...[...exportGetters].map(
|
|
17686
|
+
([name, expression]) => `Object.defineProperty(${HELPERS.exports}, ${JSON.stringify(name)}, { enumerable: true, configurable: true, get: function () { return ${expression}; } });`
|
|
17687
|
+
)
|
|
17688
|
+
].join("\n") : "";
|
|
17689
|
+
return {
|
|
17690
|
+
code: header ? `${header}
|
|
17691
|
+
${applyEdits(source, edits)}` : applyEdits(source, edits),
|
|
17692
|
+
esm,
|
|
17693
|
+
topLevelAwait: hasTopLevelAwait(ast)
|
|
17694
|
+
};
|
|
17695
|
+
function collectImport(node2) {
|
|
17696
|
+
const specifier = node2.source.value;
|
|
17697
|
+
const specifiers = node2.specifiers ?? [];
|
|
17698
|
+
const id = namespaceFor(specifier);
|
|
17699
|
+
for (const entry of specifiers) {
|
|
17700
|
+
const local = entry.local.name ?? "";
|
|
17701
|
+
if (entry.type === "ImportDefaultSpecifier") {
|
|
17702
|
+
importBindings.set(local, `${id}.default`);
|
|
17703
|
+
} else if (entry.type === "ImportNamespaceSpecifier") {
|
|
17704
|
+
importBindings.set(local, id);
|
|
17705
|
+
} else {
|
|
17706
|
+
const imported = entry.imported;
|
|
17707
|
+
const name = imported.type === "Identifier" ? imported.name : imported.value;
|
|
17708
|
+
importBindings.set(local, `${id}[${JSON.stringify(name)}]`);
|
|
17705
17709
|
}
|
|
17706
|
-
const source = new TextDecoder().decode(await ctx.stdin.readAll());
|
|
17707
|
-
if (source.trim() === "") return 0;
|
|
17708
|
-
const path = tempPath("stdin-script", ctx.proc.pid);
|
|
17709
|
-
ctx.vfs.writeFile(path, buildBootstrapForEval(source, ["/usr/bin/node", ...scriptArgs], null), {
|
|
17710
|
-
privileged: true,
|
|
17711
|
-
mode: 384
|
|
17712
|
-
});
|
|
17713
|
-
temps.push(path);
|
|
17714
|
-
return execute(ctx, { script: path, argv: scriptArgs, temps });
|
|
17715
17710
|
}
|
|
17716
|
-
|
|
17717
|
-
|
|
17718
|
-
|
|
17719
|
-
|
|
17720
|
-
|
|
17721
|
-
|
|
17722
|
-
|
|
17723
|
-
|
|
17724
|
-
`
|
|
17725
|
-
);
|
|
17726
|
-
return 1;
|
|
17711
|
+
drop(node2);
|
|
17712
|
+
}
|
|
17713
|
+
function collectNamedExport(node2) {
|
|
17714
|
+
const declaration = node2.declaration;
|
|
17715
|
+
if (declaration) {
|
|
17716
|
+
for (const name of declaredNames(declaration)) exportGetters.set(name, name);
|
|
17717
|
+
edits.push({ start: node2.start, end: declaration.start, text: "" });
|
|
17718
|
+
return;
|
|
17727
17719
|
}
|
|
17728
|
-
const
|
|
17729
|
-
|
|
17730
|
-
const
|
|
17731
|
-
|
|
17732
|
-
const
|
|
17733
|
-
|
|
17734
|
-
|
|
17735
|
-
mode: 384
|
|
17736
|
-
});
|
|
17737
|
-
temps.push(sibling);
|
|
17738
|
-
return await execute(ctx, { script: sibling, argvPath: script, argv: scriptArgs, stdinPath, temps });
|
|
17739
|
-
} catch {
|
|
17740
|
-
return await execute(ctx, { script, argv: scriptArgs, stdinPath, temps });
|
|
17720
|
+
const source_ = node2.source;
|
|
17721
|
+
const id = source_ ? namespaceFor(source_.value) : null;
|
|
17722
|
+
for (const entry of node2.specifiers ?? []) {
|
|
17723
|
+
const local = nameOf(entry.local);
|
|
17724
|
+
const exported = nameOf(entry.exported);
|
|
17725
|
+
const read = id ? `${id}[${JSON.stringify(local)}]` : importBindings.get(local) ?? local;
|
|
17726
|
+
exportGetters.set(exported, read);
|
|
17741
17727
|
}
|
|
17728
|
+
drop(node2);
|
|
17742
17729
|
}
|
|
17743
|
-
|
|
17744
|
-
|
|
17745
|
-
|
|
17746
|
-
|
|
17747
|
-
|
|
17748
|
-
|
|
17749
|
-
|
|
17750
|
-
|
|
17751
|
-
|
|
17752
|
-
` : "";
|
|
17753
|
-
return `${BUFFER_COMPAT_SHIM}process.argv = ${JSON.stringify(argv)};
|
|
17754
|
-
${prelude}${source}
|
|
17755
|
-
`;
|
|
17756
|
-
}
|
|
17757
|
-
function resolveScript(ctx, operand) {
|
|
17758
|
-
const base2 = ctx.path(operand);
|
|
17759
|
-
const candidates = [base2, `${base2}.js`, `${base2}.mjs`, `${base2}.cjs`, `${base2}.json`];
|
|
17760
|
-
for (const candidate of candidates) {
|
|
17761
|
-
try {
|
|
17762
|
-
const st = ctx.vfs.stat(candidate, { cred: ctx.cred });
|
|
17763
|
-
if (st.isFile()) return ctx.vfs.realpath(candidate, ctx.cred);
|
|
17764
|
-
if (st.isDirectory()) {
|
|
17765
|
-
const manifest = join(candidate, "package.json");
|
|
17766
|
-
if (ctx.vfs.lexists(manifest)) {
|
|
17767
|
-
try {
|
|
17768
|
-
const main = JSON.parse(ctx.vfs.readText(manifest, ctx.cred)).main;
|
|
17769
|
-
if (main) {
|
|
17770
|
-
const mainPath = resolve(candidate, main);
|
|
17771
|
-
if (ctx.vfs.lexists(mainPath)) return ctx.vfs.realpath(mainPath, ctx.cred);
|
|
17772
|
-
if (ctx.vfs.lexists(mainPath + ".js")) return ctx.vfs.realpath(mainPath + ".js", ctx.cred);
|
|
17773
|
-
}
|
|
17774
|
-
} catch {
|
|
17775
|
-
}
|
|
17776
|
-
}
|
|
17777
|
-
for (const index of ["index.js", "index.mjs", "index.cjs"]) {
|
|
17778
|
-
const path = join(candidate, index);
|
|
17779
|
-
if (ctx.vfs.lexists(path)) return ctx.vfs.realpath(path, ctx.cred);
|
|
17780
|
-
}
|
|
17730
|
+
function collectDefaultExport(node2) {
|
|
17731
|
+
const declaration = node2.declaration;
|
|
17732
|
+
const isDeclaration = declaration.type === "FunctionDeclaration" || declaration.type === "ClassDeclaration";
|
|
17733
|
+
if (isDeclaration) {
|
|
17734
|
+
const named = declaration.id;
|
|
17735
|
+
if (named) {
|
|
17736
|
+
exportGetters.set("default", named.name);
|
|
17737
|
+
edits.push({ start: node2.start, end: declaration.start, text: "" });
|
|
17738
|
+
return;
|
|
17781
17739
|
}
|
|
17782
|
-
|
|
17740
|
+
const keyword = declaration.type === "FunctionDeclaration" ? "function" : "class";
|
|
17741
|
+
const keywordEnd = source.indexOf(keyword, declaration.start) + keyword.length;
|
|
17742
|
+
exportGetters.set("default", DEFAULT_LOCAL);
|
|
17743
|
+
edits.push({ start: node2.start, end: declaration.start, text: "" });
|
|
17744
|
+
edits.push({ start: keywordEnd, end: keywordEnd, text: ` ${DEFAULT_LOCAL}` });
|
|
17745
|
+
return;
|
|
17783
17746
|
}
|
|
17747
|
+
exportGetters.set("default", DEFAULT_LOCAL);
|
|
17748
|
+
edits.push({ start: node2.start, end: declaration.start, text: `var ${DEFAULT_LOCAL} = ` });
|
|
17749
|
+
edits.push({ start: node2.end, end: node2.end, text: ";" });
|
|
17784
17750
|
}
|
|
17785
|
-
|
|
17786
|
-
|
|
17787
|
-
|
|
17788
|
-
|
|
17789
|
-
|
|
17790
|
-
|
|
17791
|
-
|
|
17792
|
-
|
|
17793
|
-
|
|
17794
|
-
|
|
17795
|
-
|
|
17796
|
-
}
|
|
17797
|
-
|
|
17798
|
-
|
|
17799
|
-
|
|
17800
|
-
|
|
17801
|
-
|
|
17802
|
-
|
|
17803
|
-
|
|
17804
|
-
|
|
17805
|
-
|
|
17806
|
-
|
|
17807
|
-
|
|
17808
|
-
|
|
17809
|
-
|
|
17810
|
-
|
|
17811
|
-
|
|
17812
|
-
|
|
17813
|
-
|
|
17814
|
-
|
|
17815
|
-
|
|
17816
|
-
|
|
17817
|
-
|
|
17818
|
-
|
|
17819
|
-
|
|
17820
|
-
|
|
17821
|
-
|
|
17822
|
-
|
|
17823
|
-
|
|
17824
|
-
|
|
17825
|
-
|
|
17826
|
-
|
|
17827
|
-
|
|
17751
|
+
function collectExportAll(node2) {
|
|
17752
|
+
const id = namespaceFor(node2.source.value);
|
|
17753
|
+
const exported = node2.exported;
|
|
17754
|
+
if (exported) exportGetters.set(nameOf(exported), id);
|
|
17755
|
+
else prelude.push(`${HELPERS.exportAll}(${HELPERS.exports}, ${id});`);
|
|
17756
|
+
drop(node2);
|
|
17757
|
+
}
|
|
17758
|
+
function drop(node2) {
|
|
17759
|
+
edits.push({ start: node2.start, end: node2.end, text: "" });
|
|
17760
|
+
}
|
|
17761
|
+
function rewriteReferences() {
|
|
17762
|
+
const programScope = { names: new Set(importBindings.keys()), parent: null };
|
|
17763
|
+
visit(ast, programScope, true);
|
|
17764
|
+
function visit(node2, scope, isProgram = false) {
|
|
17765
|
+
let childScope = scope;
|
|
17766
|
+
let skip = NOTHING;
|
|
17767
|
+
switch (node2.type) {
|
|
17768
|
+
case "ImportDeclaration":
|
|
17769
|
+
case "ExportAllDeclaration":
|
|
17770
|
+
return;
|
|
17771
|
+
case "ExportNamedDeclaration":
|
|
17772
|
+
if (!node2.declaration) return;
|
|
17773
|
+
break;
|
|
17774
|
+
case "FunctionDeclaration":
|
|
17775
|
+
case "FunctionExpression":
|
|
17776
|
+
case "ArrowFunctionExpression": {
|
|
17777
|
+
const names = /* @__PURE__ */ new Set();
|
|
17778
|
+
for (const param of node2.params ?? []) collectPattern(param, names);
|
|
17779
|
+
const id = node2.id;
|
|
17780
|
+
if (id && node2.type === "FunctionExpression") names.add(id.name);
|
|
17781
|
+
const fnBody = node2.body;
|
|
17782
|
+
if (fnBody?.type === "BlockStatement") {
|
|
17783
|
+
for (const name of hoistedNames(fnBody.body)) names.add(name);
|
|
17784
|
+
}
|
|
17785
|
+
childScope = { names, parent: scope };
|
|
17786
|
+
break;
|
|
17787
|
+
}
|
|
17788
|
+
case "CatchClause": {
|
|
17789
|
+
const names = /* @__PURE__ */ new Set();
|
|
17790
|
+
if (node2.param) collectPattern(node2.param, names);
|
|
17791
|
+
childScope = { names, parent: scope };
|
|
17792
|
+
break;
|
|
17793
|
+
}
|
|
17794
|
+
case "ClassExpression": {
|
|
17795
|
+
const id = node2.id;
|
|
17796
|
+
if (id) childScope = { names: /* @__PURE__ */ new Set([id.name]), parent: scope };
|
|
17797
|
+
break;
|
|
17798
|
+
}
|
|
17799
|
+
case "BlockStatement":
|
|
17800
|
+
case "StaticBlock":
|
|
17801
|
+
if (!isProgram) {
|
|
17802
|
+
childScope = { names: blockNames(node2.body), parent: scope };
|
|
17803
|
+
}
|
|
17804
|
+
break;
|
|
17805
|
+
case "ForStatement":
|
|
17806
|
+
case "ForInStatement":
|
|
17807
|
+
case "ForOfStatement": {
|
|
17808
|
+
const head2 = node2.init ?? node2.left;
|
|
17809
|
+
if (head2?.type === "VariableDeclaration" && head2.kind !== "var") {
|
|
17810
|
+
const names = /* @__PURE__ */ new Set();
|
|
17811
|
+
for (const declarator of head2.declarations) {
|
|
17812
|
+
collectPattern(declarator.id, names);
|
|
17813
|
+
}
|
|
17814
|
+
childScope = { names, parent: scope };
|
|
17815
|
+
}
|
|
17816
|
+
break;
|
|
17817
|
+
}
|
|
17818
|
+
case "MetaProperty":
|
|
17819
|
+
edits.push({ start: node2.start, end: node2.end, text: HELPERS.meta });
|
|
17820
|
+
return;
|
|
17821
|
+
case "ImportExpression": {
|
|
17822
|
+
const argument = node2.source;
|
|
17823
|
+
edits.push({ start: node2.start, end: argument.start, text: `${HELPERS.dynamic}(` });
|
|
17824
|
+
visit(argument, childScope);
|
|
17825
|
+
edits.push({ start: argument.end, end: node2.end, text: ")" });
|
|
17826
|
+
return;
|
|
17827
|
+
}
|
|
17828
|
+
case "Identifier": {
|
|
17829
|
+
const replacement = lookup(node2.name, scope);
|
|
17830
|
+
if (replacement) edits.push({ start: node2.start, end: node2.end, text: replacement });
|
|
17831
|
+
return;
|
|
17832
|
+
}
|
|
17833
|
+
case "MemberExpression":
|
|
17834
|
+
case "MethodDefinition":
|
|
17835
|
+
case "PropertyDefinition":
|
|
17836
|
+
skip = node2.computed ? NOTHING : PROPERTY;
|
|
17837
|
+
break;
|
|
17838
|
+
case "Property": {
|
|
17839
|
+
if (node2.computed) break;
|
|
17840
|
+
if (node2.shorthand) {
|
|
17841
|
+
const value = node2.value;
|
|
17842
|
+
if (value.type === "Identifier") {
|
|
17843
|
+
const replacement = lookup(value.name, scope);
|
|
17844
|
+
if (replacement) {
|
|
17845
|
+
edits.push({ start: value.start, end: value.end, text: `${value.name}: ${replacement}` });
|
|
17846
|
+
return;
|
|
17847
|
+
}
|
|
17848
|
+
}
|
|
17849
|
+
break;
|
|
17850
|
+
}
|
|
17851
|
+
skip = PROPERTY;
|
|
17852
|
+
break;
|
|
17853
|
+
}
|
|
17854
|
+
case "LabeledStatement":
|
|
17855
|
+
case "BreakStatement":
|
|
17856
|
+
case "ContinueStatement":
|
|
17857
|
+
skip = LABEL;
|
|
17858
|
+
break;
|
|
17859
|
+
}
|
|
17860
|
+
for (const [key, value] of Object.entries(node2)) {
|
|
17861
|
+
if (key === "type" || key === "start" || key === "end" || skip.includes(key)) continue;
|
|
17862
|
+
if (Array.isArray(value)) {
|
|
17863
|
+
for (const item of value) if (isNode2(item)) visit(item, childScope);
|
|
17864
|
+
} else if (isNode2(value)) {
|
|
17865
|
+
visit(value, childScope);
|
|
17866
|
+
}
|
|
17867
|
+
}
|
|
17828
17868
|
}
|
|
17829
|
-
|
|
17830
|
-
|
|
17831
|
-
|
|
17869
|
+
function lookup(name, scope) {
|
|
17870
|
+
for (let current = scope; current; current = current.parent) {
|
|
17871
|
+
if (current.names.has(name)) {
|
|
17872
|
+
return current.parent === null ? importBindings.get(name) ?? null : null;
|
|
17873
|
+
}
|
|
17874
|
+
}
|
|
17875
|
+
return null;
|
|
17832
17876
|
}
|
|
17833
17877
|
}
|
|
17834
|
-
return 0;
|
|
17835
17878
|
}
|
|
17836
|
-
|
|
17837
|
-
|
|
17838
|
-
|
|
17839
|
-
|
|
17840
|
-
|
|
17841
|
-
|
|
17842
|
-
|
|
17879
|
+
var JSX_EXTENSION = /\.[jt]sx$/;
|
|
17880
|
+
var JsxParser = Parser$1.extend(jsx());
|
|
17881
|
+
var PARSE_OPTIONS = {
|
|
17882
|
+
ecmaVersion: "latest",
|
|
17883
|
+
sourceType: "module",
|
|
17884
|
+
allowAwaitOutsideFunction: true,
|
|
17885
|
+
allowHashBang: true,
|
|
17886
|
+
allowReturnOutsideFunction: true
|
|
17887
|
+
};
|
|
17888
|
+
function parseModule(source, filename) {
|
|
17889
|
+
const parser = JSX_EXTENSION.test(filename) ? JsxParser.parse.bind(JsxParser) : parse$1;
|
|
17890
|
+
return parser(source, PARSE_OPTIONS);
|
|
17891
|
+
}
|
|
17892
|
+
function containsImportExpression(node2) {
|
|
17893
|
+
if (Array.isArray(node2)) return node2.some(containsImportExpression);
|
|
17894
|
+
if (!isNode2(node2)) return false;
|
|
17895
|
+
if (node2.type === "ImportExpression") return true;
|
|
17896
|
+
for (const [key, value] of Object.entries(node2)) {
|
|
17897
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
17898
|
+
if (containsImportExpression(value)) return true;
|
|
17843
17899
|
}
|
|
17900
|
+
return false;
|
|
17844
17901
|
}
|
|
17845
|
-
function
|
|
17846
|
-
|
|
17847
|
-
|
|
17848
|
-
|
|
17849
|
-
|
|
17850
|
-
|
|
17851
|
-
|
|
17852
|
-
|
|
17902
|
+
function containsImportMeta(node2) {
|
|
17903
|
+
if (Array.isArray(node2)) return node2.some(containsImportMeta);
|
|
17904
|
+
if (!isNode2(node2)) return false;
|
|
17905
|
+
if (node2.type === "MetaProperty") return true;
|
|
17906
|
+
for (const [key, value] of Object.entries(node2)) {
|
|
17907
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
17908
|
+
if (containsImportMeta(value)) return true;
|
|
17909
|
+
}
|
|
17910
|
+
return false;
|
|
17853
17911
|
}
|
|
17854
|
-
|
|
17855
|
-
|
|
17856
|
-
|
|
17857
|
-
|
|
17858
|
-
|
|
17859
|
-
|
|
17860
|
-
|
|
17861
|
-
|
|
17862
|
-
|
|
17912
|
+
function hasTopLevelAwait(node2) {
|
|
17913
|
+
if (Array.isArray(node2)) return node2.some(hasTopLevelAwait);
|
|
17914
|
+
if (!isNode2(node2)) return false;
|
|
17915
|
+
if (node2.type === "FunctionDeclaration" || node2.type === "FunctionExpression" || node2.type === "ArrowFunctionExpression") {
|
|
17916
|
+
return false;
|
|
17917
|
+
}
|
|
17918
|
+
if (node2.type === "AwaitExpression") return true;
|
|
17919
|
+
if (node2.type === "ForOfStatement" && node2.await === true) return true;
|
|
17920
|
+
for (const [key, value] of Object.entries(node2)) {
|
|
17921
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
17922
|
+
if (hasTopLevelAwait(value)) return true;
|
|
17923
|
+
}
|
|
17924
|
+
return false;
|
|
17925
|
+
}
|
|
17926
|
+
function declaredNames(declaration) {
|
|
17927
|
+
const names = /* @__PURE__ */ new Set();
|
|
17928
|
+
if (declaration.type === "VariableDeclaration") {
|
|
17929
|
+
for (const declarator of declaration.declarations) {
|
|
17930
|
+
collectPattern(declarator.id, names);
|
|
17863
17931
|
}
|
|
17864
|
-
|
|
17865
|
-
|
|
17866
|
-
|
|
17932
|
+
} else if (isNode2(declaration.id)) {
|
|
17933
|
+
names.add(declaration.id.name);
|
|
17934
|
+
}
|
|
17935
|
+
return [...names];
|
|
17936
|
+
}
|
|
17937
|
+
function nameOf(node2) {
|
|
17938
|
+
return node2.type === "Identifier" ? node2.name : node2.value;
|
|
17939
|
+
}
|
|
17940
|
+
function hoistedNames(body) {
|
|
17941
|
+
const names = blockNames(body);
|
|
17942
|
+
collectVars(body, names);
|
|
17943
|
+
return names;
|
|
17944
|
+
}
|
|
17945
|
+
function blockNames(body) {
|
|
17946
|
+
const names = /* @__PURE__ */ new Set();
|
|
17947
|
+
for (const node2 of body ?? []) {
|
|
17948
|
+
if (node2.type === "VariableDeclaration" && node2.kind !== "var") {
|
|
17949
|
+
for (const declarator of node2.declarations) {
|
|
17950
|
+
collectPattern(declarator.id, names);
|
|
17951
|
+
}
|
|
17952
|
+
} else if ((node2.type === "ClassDeclaration" || node2.type === "FunctionDeclaration") && isNode2(node2.id)) {
|
|
17953
|
+
names.add(node2.id.name);
|
|
17867
17954
|
}
|
|
17868
|
-
ctx.line(`nvm: only ${NODE_VERSION} is available in this container`);
|
|
17869
|
-
return 0;
|
|
17870
17955
|
}
|
|
17871
|
-
|
|
17872
|
-
function nodeCommands() {
|
|
17873
|
-
return [node, nodeVersionFile];
|
|
17956
|
+
return names;
|
|
17874
17957
|
}
|
|
17875
|
-
|
|
17876
|
-
|
|
17877
|
-
|
|
17878
|
-
|
|
17879
|
-
|
|
17880
|
-
|
|
17881
|
-
|
|
17882
|
-
|
|
17883
|
-
|
|
17884
|
-
|
|
17885
|
-
|
|
17886
|
-
|
|
17887
|
-
|
|
17888
|
-
|
|
17889
|
-
|
|
17890
|
-
|
|
17891
|
-
|
|
17892
|
-
|
|
17893
|
-
|
|
17894
|
-
|
|
17895
|
-
|
|
17896
|
-
|
|
17897
|
-
|
|
17898
|
-
|
|
17899
|
-
|
|
17900
|
-
|
|
17901
|
-
|
|
17902
|
-
|
|
17903
|
-
|
|
17904
|
-
|
|
17905
|
-
|
|
17906
|
-
|
|
17907
|
-
|
|
17908
|
-
|
|
17909
|
-
|
|
17910
|
-
|
|
17911
|
-
|
|
17912
|
-
|
|
17913
|
-
|
|
17958
|
+
function collectVars(nodes, names) {
|
|
17959
|
+
if (Array.isArray(nodes)) {
|
|
17960
|
+
for (const item of nodes) collectVars(item, names);
|
|
17961
|
+
return;
|
|
17962
|
+
}
|
|
17963
|
+
if (!isNode2(nodes)) return;
|
|
17964
|
+
const node2 = nodes;
|
|
17965
|
+
if (node2.type === "FunctionDeclaration" || node2.type === "FunctionExpression" || node2.type === "ArrowFunctionExpression") {
|
|
17966
|
+
if (isNode2(node2.id)) names.add(node2.id.name);
|
|
17967
|
+
return;
|
|
17968
|
+
}
|
|
17969
|
+
if (node2.type === "VariableDeclaration" && node2.kind === "var") {
|
|
17970
|
+
for (const declarator of node2.declarations) {
|
|
17971
|
+
collectPattern(declarator.id, names);
|
|
17972
|
+
}
|
|
17973
|
+
}
|
|
17974
|
+
for (const [key, value] of Object.entries(node2)) {
|
|
17975
|
+
if (key === "type" || key === "start" || key === "end") continue;
|
|
17976
|
+
collectVars(value, names);
|
|
17977
|
+
}
|
|
17978
|
+
}
|
|
17979
|
+
function collectPattern(node2, names) {
|
|
17980
|
+
if (!isNode2(node2)) return;
|
|
17981
|
+
switch (node2.type) {
|
|
17982
|
+
case "Identifier":
|
|
17983
|
+
names.add(node2.name);
|
|
17984
|
+
return;
|
|
17985
|
+
case "ObjectPattern":
|
|
17986
|
+
for (const property of node2.properties) {
|
|
17987
|
+
collectPattern(property.value ?? property.argument, names);
|
|
17988
|
+
}
|
|
17989
|
+
return;
|
|
17990
|
+
case "ArrayPattern":
|
|
17991
|
+
for (const element of node2.elements) collectPattern(element, names);
|
|
17992
|
+
return;
|
|
17993
|
+
case "AssignmentPattern":
|
|
17994
|
+
collectPattern(node2.left, names);
|
|
17995
|
+
return;
|
|
17996
|
+
case "RestElement":
|
|
17997
|
+
collectPattern(node2.argument, names);
|
|
17998
|
+
return;
|
|
17999
|
+
default:
|
|
18000
|
+
return;
|
|
18001
|
+
}
|
|
18002
|
+
}
|
|
18003
|
+
function applyEdits(source, edits) {
|
|
18004
|
+
const ordered = [...edits].sort((a, b) => b.start - a.start || b.end - a.end);
|
|
18005
|
+
let out = source;
|
|
18006
|
+
for (const edit of ordered) out = out.slice(0, edit.start) + edit.text + out.slice(edit.end);
|
|
18007
|
+
return out;
|
|
18008
|
+
}
|
|
18009
|
+
function isNode2(value) {
|
|
18010
|
+
return typeof value === "object" && value !== null && typeof value.type === "string";
|
|
18011
|
+
}
|
|
18012
|
+
var NOTHING = [];
|
|
18013
|
+
var PROPERTY = ["property", "key"];
|
|
18014
|
+
var LABEL = ["label"];
|
|
18015
|
+
|
|
18016
|
+
// src/node/node.ts
|
|
18017
|
+
var NODE_VERSION = "v22.12.0";
|
|
18018
|
+
new TextEncoder();
|
|
18019
|
+
var tempCounter = 0;
|
|
18020
|
+
function tempPath(kind, pid, ext = ".js") {
|
|
18021
|
+
return `/tmp/.sbx-${kind}-${pid}-${tempCounter++}${ext}`;
|
|
18022
|
+
}
|
|
18023
|
+
function withPrelude(source, prelude) {
|
|
18024
|
+
if (!source.startsWith("#!")) return prelude + source;
|
|
18025
|
+
const eol = source.indexOf("\n");
|
|
18026
|
+
if (eol < 0) return source + "\n" + prelude;
|
|
18027
|
+
return source.slice(0, eol + 1) + prelude + source.slice(eol + 1);
|
|
18028
|
+
}
|
|
18029
|
+
function siblingPath(script, pid) {
|
|
18030
|
+
const ext = extname(script) || ".js";
|
|
18031
|
+
return join(dirname(script), `.sbx-${pid}-${tempCounter++}-${basename(script, ext)}${ext}`);
|
|
18032
|
+
}
|
|
18033
|
+
var BUFFER_COMPAT_SHIM = `
|
|
18034
|
+
(function () {
|
|
18035
|
+
const seen = new Set();
|
|
18036
|
+
const widen = (B) => {
|
|
18037
|
+
if (!B || seen.has(B) || typeof B.isBuffer !== 'function') return;
|
|
18038
|
+
seen.add(B);
|
|
18039
|
+
const original = B.isBuffer.bind(B);
|
|
18040
|
+
B.isBuffer = (value) => original(value) || value instanceof Uint8Array;
|
|
18041
|
+
};
|
|
18042
|
+
try { widen(globalThis.Buffer); } catch (e) {}
|
|
18043
|
+
try { widen(require('buffer').Buffer); } catch (e) {}
|
|
18044
|
+
})();
|
|
18045
|
+
`;
|
|
18046
|
+
function buildPrelude(scriptPath, argv, stdinPath, preloads = []) {
|
|
18047
|
+
const argvLiteral = JSON.stringify(["/usr/bin/node", scriptPath, ...argv]);
|
|
18048
|
+
const pathLiteral = JSON.stringify(scriptPath);
|
|
18049
|
+
const stdinLiteral = JSON.stringify(stdinPath);
|
|
18050
|
+
return `${BUFFER_COMPAT_SHIM}
|
|
18051
|
+
process.argv = ${argvLiteral};
|
|
18052
|
+
try {
|
|
18053
|
+
__filename = ${pathLiteral};
|
|
18054
|
+
module.filename = ${pathLiteral};
|
|
18055
|
+
module.id = ${pathLiteral};
|
|
18056
|
+
if (require.main === module) require.main.filename = ${pathLiteral};
|
|
18057
|
+
} catch (e) {}
|
|
18058
|
+
${stdinPath === null ? "" : `(function () {
|
|
18059
|
+
const fs = require('fs');
|
|
18060
|
+
const { Readable } = require('stream');
|
|
18061
|
+
let data;
|
|
18062
|
+
try { data = fs.readFileSync(${stdinLiteral}); } catch (e) { data = Buffer.alloc(0); }
|
|
18063
|
+
const stream = Readable.from([data]);
|
|
18064
|
+
stream.isTTY = false;
|
|
18065
|
+
stream.fd = 0;
|
|
18066
|
+
stream.setRawMode = function () { return this; };
|
|
18067
|
+
try {
|
|
18068
|
+
Object.defineProperty(process, 'stdin', { value: stream, configurable: true, writable: true });
|
|
18069
|
+
} catch (e) { process.stdin = stream; }
|
|
18070
|
+
})();
|
|
18071
|
+
`}${preloadRequires(preloads)}`;
|
|
18072
|
+
}
|
|
18073
|
+
function preloadRequires(preloads) {
|
|
18074
|
+
return preloads.map((specifier) => `require(${JSON.stringify(specifier)});
|
|
18075
|
+
`).join("");
|
|
18076
|
+
}
|
|
18077
|
+
async function execute(ctx, invocation) {
|
|
18078
|
+
const { pod } = ctx.kernel;
|
|
18079
|
+
const live = ctx.stdin.interactive || ctx.stdin.isTTY;
|
|
18080
|
+
const tty = ctx.stdin.isTTY;
|
|
18081
|
+
let exitCode = 0;
|
|
18082
|
+
try {
|
|
18083
|
+
const proc = await pod.spawn("node", [invocation.script], {
|
|
18084
|
+
cwd: ctx.cwd,
|
|
18085
|
+
env: { ...invocation.env ?? ctx.env, PWD: ctx.cwd },
|
|
18086
|
+
argv: ["/usr/bin/node", invocation.argvPath ?? invocation.script, ...invocation.argv],
|
|
18087
|
+
...invocation.stdinPath ? { stdinPath: invocation.stdinPath } : {},
|
|
18088
|
+
/* An interactive caller's input was not captured to a file, so the
|
|
18089
|
+
* program's stdin has to stay open and be fed as it arrives — and be
|
|
18090
|
+
* reported as a terminal, since that is what decides whether a CLI
|
|
18091
|
+
* prompts or takes its defaults. */
|
|
18092
|
+
...live ? { interactiveStdin: true } : {},
|
|
18093
|
+
...tty ? { tty: true } : {}
|
|
18094
|
+
});
|
|
18095
|
+
proc.on("output", (chunk) => {
|
|
18096
|
+
try {
|
|
18097
|
+
ctx.write(chunk);
|
|
18098
|
+
} catch {
|
|
18099
|
+
}
|
|
18100
|
+
});
|
|
18101
|
+
proc.on("error", (chunk) => {
|
|
18102
|
+
try {
|
|
18103
|
+
ctx.stderr.write(chunk);
|
|
18104
|
+
} catch {
|
|
18105
|
+
}
|
|
18106
|
+
});
|
|
18107
|
+
proc.on("rawmode", (enabled) => {
|
|
18108
|
+
ctx.stdin.rawMode = enabled;
|
|
18109
|
+
});
|
|
18110
|
+
let forwarding = false;
|
|
18111
|
+
if (live) {
|
|
18112
|
+
forwarding = true;
|
|
18113
|
+
void (async () => {
|
|
18114
|
+
while (forwarding) {
|
|
18115
|
+
const chunk = await ctx.stdin.read();
|
|
18116
|
+
if (chunk === null) {
|
|
18117
|
+
proc.endInput?.();
|
|
18118
|
+
break;
|
|
18119
|
+
}
|
|
18120
|
+
try {
|
|
18121
|
+
proc.write(new TextDecoder().decode(chunk));
|
|
18122
|
+
} catch {
|
|
18123
|
+
break;
|
|
18124
|
+
}
|
|
18125
|
+
}
|
|
18126
|
+
})();
|
|
18127
|
+
}
|
|
18128
|
+
let onAbort;
|
|
18129
|
+
const aborted = new Promise((resolve3) => {
|
|
18130
|
+
onAbort = () => {
|
|
18131
|
+
try {
|
|
18132
|
+
proc.kill();
|
|
18133
|
+
} catch {
|
|
18134
|
+
}
|
|
18135
|
+
resolve3({ exitCode: 137 });
|
|
18136
|
+
};
|
|
18137
|
+
if (ctx.signal.aborted) onAbort();
|
|
18138
|
+
else ctx.signal.addEventListener("abort", onAbort, { once: true });
|
|
18139
|
+
});
|
|
18140
|
+
const result = await Promise.race([proc.completion, aborted]);
|
|
18141
|
+
forwarding = false;
|
|
18142
|
+
if (onAbort) ctx.signal.removeEventListener("abort", onAbort);
|
|
18143
|
+
exitCode = result.exitCode;
|
|
18144
|
+
} catch (e) {
|
|
18145
|
+
ctx.stderr.write(`node: ${e instanceof Error ? e.message : String(e)}
|
|
18146
|
+
`);
|
|
18147
|
+
exitCode = 1;
|
|
18148
|
+
} finally {
|
|
18149
|
+
for (const temp of invocation.temps) {
|
|
18150
|
+
try {
|
|
18151
|
+
ctx.vfs.unlink(temp);
|
|
18152
|
+
} catch {
|
|
18153
|
+
}
|
|
18154
|
+
}
|
|
18155
|
+
}
|
|
18156
|
+
return exitCode;
|
|
18157
|
+
}
|
|
18158
|
+
async function captureStdin(ctx) {
|
|
18159
|
+
if (ctx.stdin.isTTY || ctx.stdin.interactive) return null;
|
|
18160
|
+
const bytes2 = await ctx.stdin.readAll();
|
|
18161
|
+
if (bytes2.length === 0) return null;
|
|
18162
|
+
const path = tempPath("stdin", ctx.proc.pid, ".dat");
|
|
18163
|
+
ctx.vfs.writeFile(path, bytes2, { privileged: true, mode: 384 });
|
|
18164
|
+
return path;
|
|
18165
|
+
}
|
|
18166
|
+
var node = defineCommand({
|
|
18167
|
+
name: "node",
|
|
18168
|
+
path: "/usr/bin/node",
|
|
18169
|
+
aliases: ["nodejs"],
|
|
18170
|
+
summary: "run a JavaScript program with Node.js",
|
|
18171
|
+
usage: "node [options] [script.js] [arguments]",
|
|
18172
|
+
manual: `Runs JavaScript with a real Node.js API surface \u2014 fs, path, http,
|
|
18173
|
+
crypto, streams, worker_threads and npm packages \u2014 inside the container.
|
|
18174
|
+
The filesystem a script sees is the container's filesystem.`,
|
|
18175
|
+
async run(ctx) {
|
|
18176
|
+
const argv = ctx.args;
|
|
18177
|
+
const temps = [];
|
|
18178
|
+
let i = 0;
|
|
18179
|
+
let evalSource;
|
|
18180
|
+
let printResult = false;
|
|
18181
|
+
let scriptArg;
|
|
18182
|
+
const preloads = [];
|
|
18183
|
+
const envFiles = [];
|
|
18184
|
+
let testMode = false;
|
|
18185
|
+
let checkOnly = false;
|
|
18186
|
+
const testSettings = { namePatterns: [] };
|
|
18187
|
+
for (; i < argv.length; i++) {
|
|
18188
|
+
const arg = argv[i];
|
|
18189
|
+
if (arg === "-v" || arg === "--version") {
|
|
18190
|
+
ctx.line(NODE_VERSION);
|
|
18191
|
+
return 0;
|
|
18192
|
+
}
|
|
18193
|
+
if (arg === "-h" || arg === "--help") {
|
|
18194
|
+
printHelp(ctx);
|
|
18195
|
+
return 0;
|
|
18196
|
+
}
|
|
18197
|
+
if (arg === "-e" || arg === "--eval") {
|
|
18198
|
+
evalSource = argv[++i] ?? "";
|
|
18199
|
+
i++;
|
|
18200
|
+
break;
|
|
18201
|
+
}
|
|
18202
|
+
if (arg === "-p" || arg === "--print") {
|
|
18203
|
+
printResult = true;
|
|
18204
|
+
evalSource = argv[++i] ?? "";
|
|
18205
|
+
i++;
|
|
18206
|
+
break;
|
|
18207
|
+
}
|
|
18208
|
+
if (arg.startsWith("--eval=")) {
|
|
18209
|
+
evalSource = arg.slice("--eval=".length);
|
|
18210
|
+
i++;
|
|
18211
|
+
break;
|
|
18212
|
+
}
|
|
18213
|
+
if (arg.startsWith("--print=")) {
|
|
18214
|
+
printResult = true;
|
|
18215
|
+
evalSource = arg.slice("--print=".length);
|
|
18216
|
+
i++;
|
|
18217
|
+
break;
|
|
18218
|
+
}
|
|
18219
|
+
if (arg === "--") {
|
|
18220
|
+
i++;
|
|
18221
|
+
break;
|
|
18222
|
+
}
|
|
18223
|
+
const flag = arg.startsWith("--") ? arg.split("=", 1)[0] : arg;
|
|
18224
|
+
if (VALUE_FLAGS.has(flag)) {
|
|
18225
|
+
const value = arg.length > flag.length ? arg.slice(flag.length + 1) : argv[++i];
|
|
18226
|
+
if (value === void 0) {
|
|
18227
|
+
ctx.stderr.write(`node: ${flag} requires an argument
|
|
18228
|
+
`);
|
|
18229
|
+
return 9;
|
|
18230
|
+
}
|
|
18231
|
+
if (flag === "-r" || flag === "--require" || flag === "--import") preloads.push(value);
|
|
18232
|
+
else if (flag === "--env-file") envFiles.push({ path: value, optional: false });
|
|
18233
|
+
else if (flag === "--env-file-if-exists") envFiles.push({ path: value, optional: true });
|
|
18234
|
+
else if (flag === "--test-reporter") testSettings.reporter = value === "tap" ? "tap" : "spec";
|
|
18235
|
+
else if (flag === "--test-name-pattern") testSettings.namePatterns.push(value);
|
|
18236
|
+
else if (flag === "--loader" || flag === "--experimental-loader") {
|
|
18237
|
+
ctx.stderr.write(`node: ${flag} is not supported in this container; ${value} was not loaded
|
|
18238
|
+
`);
|
|
18239
|
+
}
|
|
18240
|
+
continue;
|
|
18241
|
+
}
|
|
18242
|
+
if (arg === "--test") {
|
|
18243
|
+
testMode = true;
|
|
18244
|
+
continue;
|
|
18245
|
+
}
|
|
18246
|
+
if (arg === "--test-only") {
|
|
18247
|
+
testSettings.only = true;
|
|
18248
|
+
continue;
|
|
18249
|
+
}
|
|
18250
|
+
if (arg === "-c" || arg === "--check") {
|
|
18251
|
+
checkOnly = true;
|
|
18252
|
+
continue;
|
|
18253
|
+
}
|
|
18254
|
+
if (flag === "--watch" || flag === "--watch-path" || flag === "--watch-preserve-output") {
|
|
18255
|
+
ctx.stderr.write(
|
|
18256
|
+
`node: ${flag} is not available in this container: file changes are not watched. Run the program again after changing it.
|
|
18257
|
+
`
|
|
18258
|
+
);
|
|
18259
|
+
return 9;
|
|
18260
|
+
}
|
|
18261
|
+
if (arg.startsWith("-") && arg !== "-") {
|
|
18262
|
+
continue;
|
|
18263
|
+
}
|
|
18264
|
+
scriptArg = arg;
|
|
18265
|
+
i++;
|
|
18266
|
+
break;
|
|
18267
|
+
}
|
|
18268
|
+
const scriptArgs = argv.slice(i);
|
|
18269
|
+
let env2;
|
|
18270
|
+
if (envFiles.length > 0) {
|
|
18271
|
+
const loaded = {};
|
|
18272
|
+
for (const file3 of envFiles) {
|
|
18273
|
+
let text2;
|
|
18274
|
+
try {
|
|
18275
|
+
text2 = ctx.vfs.readText(ctx.path(file3.path), ctx.cred);
|
|
18276
|
+
} catch {
|
|
18277
|
+
if (file3.optional) continue;
|
|
18278
|
+
ctx.stderr.write(`node: ${file3.path}: not found
|
|
18279
|
+
`);
|
|
18280
|
+
return 9;
|
|
18281
|
+
}
|
|
18282
|
+
Object.assign(loaded, parseEnvFile(text2));
|
|
18283
|
+
}
|
|
18284
|
+
env2 = { ...loaded, ...ctx.env };
|
|
18285
|
+
}
|
|
18286
|
+
const preloadSpecs = preloads.map((spec) => spec.startsWith(".") || spec.startsWith("/") ? ctx.path(spec) : spec);
|
|
18287
|
+
if (testMode) {
|
|
18288
|
+
return runTestFiles(ctx, scriptArg === void 0 ? scriptArgs : [scriptArg, ...scriptArgs], testSettings, preloads, env2 ?? ctx.env);
|
|
18289
|
+
}
|
|
18290
|
+
if (checkOnly && scriptArg !== void 0) {
|
|
18291
|
+
const script2 = resolveScript(ctx, scriptArg);
|
|
18292
|
+
if (!script2) {
|
|
18293
|
+
ctx.stderr.write(`node: cannot find module '${ctx.path(scriptArg)}'
|
|
18294
|
+
`);
|
|
18295
|
+
return 1;
|
|
18296
|
+
}
|
|
18297
|
+
return checkSyntax(ctx, script2);
|
|
18298
|
+
}
|
|
18299
|
+
if (evalSource !== void 0) {
|
|
18300
|
+
const body = printResult ? `const __sbxResult = (function(){ return (${evalSource}
|
|
18301
|
+
); })();
|
|
18302
|
+
console.log(typeof __sbxResult === 'string' ? __sbxResult : require('util').inspect(__sbxResult));` : evalSource;
|
|
18303
|
+
const path = tempPath("eval", ctx.proc.pid);
|
|
18304
|
+
const stdinPath2 = await captureStdin(ctx);
|
|
18305
|
+
if (stdinPath2) temps.push(stdinPath2);
|
|
18306
|
+
ctx.vfs.writeFile(path, buildBootstrapForEval(body, ["/usr/bin/node", ...scriptArgs], stdinPath2, preloadSpecs), {
|
|
18307
|
+
privileged: true,
|
|
18308
|
+
mode: 384
|
|
18309
|
+
});
|
|
18310
|
+
temps.push(path);
|
|
18311
|
+
return execute(ctx, { script: path, argv: scriptArgs, stdinPath: stdinPath2, temps, ...env2 ? { env: env2 } : {} });
|
|
18312
|
+
}
|
|
18313
|
+
if (scriptArg === void 0 || scriptArg === "-") {
|
|
18314
|
+
if (ctx.stdin.isTTY) {
|
|
18315
|
+
ctx.line(`Welcome to Node.js ${NODE_VERSION}.`);
|
|
18316
|
+
ctx.line('Type ".help" for more information.');
|
|
18317
|
+
return runRepl(ctx);
|
|
18318
|
+
}
|
|
18319
|
+
const source = new TextDecoder().decode(await ctx.stdin.readAll());
|
|
18320
|
+
if (source.trim() === "") return 0;
|
|
18321
|
+
const path = tempPath("stdin-script", ctx.proc.pid);
|
|
18322
|
+
ctx.vfs.writeFile(path, buildBootstrapForEval(source, ["/usr/bin/node", ...scriptArgs], null, preloadSpecs), {
|
|
18323
|
+
privileged: true,
|
|
18324
|
+
mode: 384
|
|
18325
|
+
});
|
|
18326
|
+
temps.push(path);
|
|
18327
|
+
return execute(ctx, { script: path, argv: scriptArgs, temps, ...env2 ? { env: env2 } : {} });
|
|
18328
|
+
}
|
|
18329
|
+
const script = resolveScript(ctx, scriptArg);
|
|
18330
|
+
if (!script) {
|
|
18331
|
+
ctx.stderr.write(
|
|
18332
|
+
`node:internal/modules/cjs/loader:1215
|
|
18333
|
+
throw err;
|
|
18334
|
+
^
|
|
18335
|
+
|
|
18336
|
+
Error: Cannot find module '${ctx.path(scriptArg)}'
|
|
18337
|
+
`
|
|
18338
|
+
);
|
|
18339
|
+
return 1;
|
|
18340
|
+
}
|
|
18341
|
+
const stdinPath = await captureStdin(ctx);
|
|
18342
|
+
if (stdinPath) temps.push(stdinPath);
|
|
18343
|
+
const sibling = siblingPath(script, ctx.proc.pid);
|
|
18344
|
+
try {
|
|
18345
|
+
const source = ctx.vfs.readText(script, ctx.cred);
|
|
18346
|
+
ctx.vfs.writeFile(sibling, withPrelude(source, buildPrelude(script, scriptArgs, stdinPath, preloadSpecs)), {
|
|
18347
|
+
privileged: true,
|
|
18348
|
+
mode: 384
|
|
18349
|
+
});
|
|
18350
|
+
temps.push(sibling);
|
|
18351
|
+
return await execute(ctx, {
|
|
18352
|
+
script: sibling,
|
|
18353
|
+
argvPath: script,
|
|
18354
|
+
argv: scriptArgs,
|
|
18355
|
+
stdinPath,
|
|
18356
|
+
temps,
|
|
18357
|
+
...env2 ? { env: env2 } : {}
|
|
18358
|
+
});
|
|
18359
|
+
} catch {
|
|
18360
|
+
return await execute(ctx, { script, argv: scriptArgs, stdinPath, temps, ...env2 ? { env: env2 } : {} });
|
|
18361
|
+
}
|
|
18362
|
+
}
|
|
18363
|
+
});
|
|
18364
|
+
function buildBootstrapForEval(source, argv, stdinPath, preloads = []) {
|
|
18365
|
+
const prelude = stdinPath ? `const fs = require('fs');
|
|
18366
|
+
const { Readable } = require('stream');
|
|
18367
|
+
let __sbxData; try { __sbxData = fs.readFileSync(${JSON.stringify(stdinPath)}); } catch (e) { __sbxData = Buffer.alloc(0); }
|
|
18368
|
+
const __sbxStdin = Readable.from([__sbxData]);
|
|
18369
|
+
__sbxStdin.isTTY = false;
|
|
18370
|
+
__sbxStdin.setRawMode = function () { return this; };
|
|
18371
|
+
try { Object.defineProperty(process, 'stdin', { value: __sbxStdin, configurable: true, writable: true }); } catch (e) { process.stdin = __sbxStdin; }
|
|
18372
|
+
` : "";
|
|
18373
|
+
return `${BUFFER_COMPAT_SHIM}process.argv = ${JSON.stringify(argv)};
|
|
18374
|
+
${prelude}${preloadRequires(preloads)}${source}
|
|
18375
|
+
`;
|
|
18376
|
+
}
|
|
18377
|
+
function resolveScript(ctx, operand) {
|
|
18378
|
+
const base2 = ctx.path(operand);
|
|
18379
|
+
const candidates = [base2, `${base2}.js`, `${base2}.mjs`, `${base2}.cjs`, `${base2}.json`];
|
|
18380
|
+
for (const candidate of candidates) {
|
|
18381
|
+
try {
|
|
18382
|
+
const st = ctx.vfs.stat(candidate, { cred: ctx.cred });
|
|
18383
|
+
if (st.isFile()) return ctx.vfs.realpath(candidate, ctx.cred);
|
|
18384
|
+
if (st.isDirectory()) {
|
|
18385
|
+
const manifest = join(candidate, "package.json");
|
|
18386
|
+
if (ctx.vfs.lexists(manifest)) {
|
|
18387
|
+
try {
|
|
18388
|
+
const main = JSON.parse(ctx.vfs.readText(manifest, ctx.cred)).main;
|
|
18389
|
+
if (main) {
|
|
18390
|
+
const mainPath = resolve(candidate, main);
|
|
18391
|
+
if (ctx.vfs.lexists(mainPath)) return ctx.vfs.realpath(mainPath, ctx.cred);
|
|
18392
|
+
if (ctx.vfs.lexists(mainPath + ".js")) return ctx.vfs.realpath(mainPath + ".js", ctx.cred);
|
|
18393
|
+
}
|
|
18394
|
+
} catch {
|
|
18395
|
+
}
|
|
18396
|
+
}
|
|
18397
|
+
for (const index of ["index.js", "index.mjs", "index.cjs"]) {
|
|
18398
|
+
const path = join(candidate, index);
|
|
18399
|
+
if (ctx.vfs.lexists(path)) return ctx.vfs.realpath(path, ctx.cred);
|
|
18400
|
+
}
|
|
18401
|
+
}
|
|
18402
|
+
} catch {
|
|
18403
|
+
}
|
|
18404
|
+
}
|
|
18405
|
+
return null;
|
|
18406
|
+
}
|
|
18407
|
+
async function runRepl(ctx) {
|
|
18408
|
+
const historyPath = join(ctx.env.HOME ?? "/root", ".node_repl_history");
|
|
18409
|
+
const statements = [];
|
|
18410
|
+
for (; ; ) {
|
|
18411
|
+
ctx.write("> ");
|
|
18412
|
+
const line = await ctx.stdin.readLine();
|
|
18413
|
+
if (line === null) {
|
|
18414
|
+
ctx.line("");
|
|
18415
|
+
break;
|
|
18416
|
+
}
|
|
18417
|
+
const trimmed = line.trim();
|
|
18418
|
+
if (trimmed === ".exit") break;
|
|
18419
|
+
if (trimmed === ".help") {
|
|
18420
|
+
ctx.line(".exit Exit the REPL");
|
|
18421
|
+
ctx.line(".help Print this help message");
|
|
18422
|
+
ctx.line(".clear Reset the session context");
|
|
18423
|
+
continue;
|
|
18424
|
+
}
|
|
18425
|
+
if (trimmed === ".clear") {
|
|
18426
|
+
statements.length = 0;
|
|
18427
|
+
continue;
|
|
18428
|
+
}
|
|
18429
|
+
if (trimmed === "") continue;
|
|
18430
|
+
const program = [...statements, `console.log(require('util').inspect((${trimmed})))`].join(";\n");
|
|
18431
|
+
const fallback = [...statements, trimmed].join(";\n");
|
|
18432
|
+
const path = tempPath("repl", ctx.proc.pid);
|
|
18433
|
+
ctx.vfs.writeFile(path, program, { privileged: true, mode: 384 });
|
|
18434
|
+
const result = await runQuiet(ctx, path);
|
|
18435
|
+
if (result.exitCode !== 0) {
|
|
18436
|
+
ctx.vfs.writeFile(path, fallback, { privileged: true, mode: 384 });
|
|
18437
|
+
const second = await runQuiet(ctx, path);
|
|
18438
|
+
ctx.write(second.stdout);
|
|
18439
|
+
if (second.exitCode === 0) statements.push(trimmed);
|
|
18440
|
+
else ctx.stderr.write(second.stderr);
|
|
18441
|
+
} else {
|
|
18442
|
+
ctx.write(result.stdout);
|
|
18443
|
+
statements.push(trimmed);
|
|
18444
|
+
}
|
|
18445
|
+
try {
|
|
18446
|
+
ctx.vfs.unlink(path);
|
|
18447
|
+
} catch {
|
|
18448
|
+
}
|
|
18449
|
+
try {
|
|
18450
|
+
ctx.vfs.appendFile(historyPath, trimmed + "\n", { cred: ctx.cred });
|
|
18451
|
+
} catch {
|
|
18452
|
+
}
|
|
18453
|
+
}
|
|
18454
|
+
return 0;
|
|
18455
|
+
}
|
|
18456
|
+
async function runQuiet(ctx, script) {
|
|
18457
|
+
try {
|
|
18458
|
+
const proc = await ctx.kernel.pod.spawn("node", [script], { cwd: ctx.cwd, env: ctx.env });
|
|
18459
|
+
return await proc.completion;
|
|
18460
|
+
} catch (e) {
|
|
18461
|
+
return { exitCode: 1, stdout: "", stderr: `${e instanceof Error ? e.message : String(e)}
|
|
18462
|
+
` };
|
|
18463
|
+
}
|
|
18464
|
+
}
|
|
18465
|
+
function printHelp(ctx) {
|
|
18466
|
+
ctx.line("Usage: node [options] [script.js] [arguments]");
|
|
18467
|
+
ctx.line(" node --test [files or globs]");
|
|
18468
|
+
ctx.line("");
|
|
18469
|
+
ctx.line("Options:");
|
|
18470
|
+
ctx.line(" -v, --version print Node.js version");
|
|
18471
|
+
ctx.line(" -e, --eval script evaluate script");
|
|
18472
|
+
ctx.line(" -p, --print evaluate script and print result");
|
|
18473
|
+
ctx.line(" -c, --check check syntax without running");
|
|
18474
|
+
ctx.line(" -r, --require module load a module before the program");
|
|
18475
|
+
ctx.line(" --import module load a module before the program");
|
|
18476
|
+
ctx.line(" --env-file file load environment variables from a file");
|
|
18477
|
+
ctx.line(" --test run test files with node:test");
|
|
18478
|
+
ctx.line(" --test-reporter spec|tap choose the test report format");
|
|
18479
|
+
ctx.line(" --test-name-pattern regex run only tests whose name matches");
|
|
18480
|
+
ctx.line(" -h, --help print this message");
|
|
18481
|
+
}
|
|
18482
|
+
var VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
18483
|
+
"-r",
|
|
18484
|
+
"--require",
|
|
18485
|
+
"--import",
|
|
18486
|
+
"--loader",
|
|
18487
|
+
"--experimental-loader",
|
|
18488
|
+
"--env-file",
|
|
18489
|
+
"--env-file-if-exists",
|
|
18490
|
+
"--input-type",
|
|
18491
|
+
"--title",
|
|
18492
|
+
"-C",
|
|
18493
|
+
"--conditions",
|
|
18494
|
+
"--test-reporter",
|
|
18495
|
+
"--test-reporter-destination",
|
|
18496
|
+
"--test-name-pattern",
|
|
18497
|
+
"--test-skip-pattern",
|
|
18498
|
+
"--test-concurrency",
|
|
18499
|
+
"--test-timeout",
|
|
18500
|
+
"--test-shard",
|
|
18501
|
+
"--disable-warning",
|
|
18502
|
+
"--redirect-warnings",
|
|
18503
|
+
"--stack-trace-limit",
|
|
18504
|
+
"--inspect-port",
|
|
18505
|
+
"--report-dir",
|
|
18506
|
+
"--report-filename"
|
|
18507
|
+
]);
|
|
18508
|
+
function parseEnvFile(text2) {
|
|
18509
|
+
const out = {};
|
|
18510
|
+
for (const raw of text2.split(/\r?\n/)) {
|
|
18511
|
+
const line = raw.trim();
|
|
18512
|
+
if (!line || line.startsWith("#")) continue;
|
|
18513
|
+
const match2 = /^(?:export\s+)?([A-Za-z_][A-Za-z0-9_.-]*)\s*=\s*(.*)$/.exec(line);
|
|
18514
|
+
if (!match2) continue;
|
|
18515
|
+
let value = match2[2];
|
|
18516
|
+
const quote3 = value[0];
|
|
18517
|
+
if ((quote3 === '"' || quote3 === "'" || quote3 === "`") && value.length >= 2 && value.endsWith(quote3)) {
|
|
18518
|
+
value = value.slice(1, -1);
|
|
18519
|
+
if (quote3 === '"') value = value.replace(/\\n/g, "\n");
|
|
18520
|
+
} else {
|
|
18521
|
+
const comment = value.indexOf(" #");
|
|
18522
|
+
if (comment >= 0) value = value.slice(0, comment);
|
|
18523
|
+
value = value.trim();
|
|
18524
|
+
}
|
|
18525
|
+
out[match2[1]] = value;
|
|
18526
|
+
}
|
|
18527
|
+
return out;
|
|
18528
|
+
}
|
|
18529
|
+
var AsyncFunction = Object.getPrototypeOf(async function() {
|
|
18530
|
+
}).constructor;
|
|
18531
|
+
function checkSyntax(ctx, script) {
|
|
18532
|
+
let source = ctx.vfs.readText(script, ctx.cred);
|
|
18533
|
+
if (source.startsWith("#!")) source = `//${source.slice(2)}`;
|
|
18534
|
+
try {
|
|
18535
|
+
const esm = script.endsWith(".mjs") || !script.endsWith(".cjs") && looksLikeEsm(source);
|
|
18536
|
+
const transformed = esm ? transformEsm(source, script) : null;
|
|
18537
|
+
new AsyncFunction("exports", "require", "module", "__filename", "__dirname", transformed?.code ?? source);
|
|
18538
|
+
return 0;
|
|
18539
|
+
} catch (error) {
|
|
18540
|
+
if (!(error instanceof SyntaxError)) throw error;
|
|
18541
|
+
ctx.stderr.write(`${script}
|
|
18542
|
+
|
|
18543
|
+
${error.name}: ${error.message}
|
|
18544
|
+
|
|
18545
|
+
Node.js ${NODE_VERSION}
|
|
18546
|
+
`);
|
|
18547
|
+
return 1;
|
|
18548
|
+
}
|
|
18549
|
+
}
|
|
18550
|
+
var TEST_FILE_NAME = /^(?:test|test-.+|.+[.\-_]test)\.(?:c|m)?js$/;
|
|
18551
|
+
var SCRIPT_FILE = /\.(?:c|m)?js$/;
|
|
18552
|
+
function globToRegExp(pattern) {
|
|
18553
|
+
let out = "";
|
|
18554
|
+
for (let index = 0; index < pattern.length; index += 1) {
|
|
18555
|
+
const ch = pattern[index];
|
|
18556
|
+
if (ch === "*") {
|
|
18557
|
+
if (pattern[index + 1] === "*") {
|
|
18558
|
+
index += 1;
|
|
18559
|
+
if (pattern[index + 1] === "/") index += 1;
|
|
18560
|
+
out += "(?:.*/)?";
|
|
18561
|
+
} else out += "[^/]*";
|
|
18562
|
+
} else if (ch === "?") out += "[^/]";
|
|
18563
|
+
else out += ch.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
18564
|
+
}
|
|
18565
|
+
return new RegExp(`^${out}$`);
|
|
18566
|
+
}
|
|
18567
|
+
function discoverTestFiles(ctx, patterns) {
|
|
18568
|
+
const files = /* @__PURE__ */ new Set();
|
|
18569
|
+
const missing = [];
|
|
18570
|
+
const walk = (dir3, visit, underTestDir = false) => {
|
|
18571
|
+
let names;
|
|
18572
|
+
try {
|
|
18573
|
+
names = ctx.vfs.readdir(dir3, ctx.cred);
|
|
18574
|
+
} catch {
|
|
18575
|
+
return;
|
|
18576
|
+
}
|
|
18577
|
+
for (const name of [...names].sort()) {
|
|
18578
|
+
if (name === "node_modules" || name.startsWith(".")) continue;
|
|
18579
|
+
const path = join(dir3, name);
|
|
18580
|
+
let isDirectory;
|
|
18581
|
+
try {
|
|
18582
|
+
isDirectory = ctx.vfs.stat(path, { cred: ctx.cred }).isDirectory();
|
|
18583
|
+
} catch {
|
|
18584
|
+
continue;
|
|
18585
|
+
}
|
|
18586
|
+
if (isDirectory) walk(path, visit, underTestDir || name === "test");
|
|
18587
|
+
else visit(path, name, underTestDir);
|
|
18588
|
+
}
|
|
18589
|
+
};
|
|
18590
|
+
const byName = (path, name, underTestDir) => {
|
|
18591
|
+
if (SCRIPT_FILE.test(name) && (underTestDir || TEST_FILE_NAME.test(name))) files.add(path);
|
|
18592
|
+
};
|
|
18593
|
+
if (patterns.length === 0) walk(ctx.cwd, byName);
|
|
18594
|
+
for (const pattern of patterns) {
|
|
18595
|
+
const target = ctx.path(pattern);
|
|
18596
|
+
let stat2 = null;
|
|
18597
|
+
try {
|
|
18598
|
+
stat2 = ctx.vfs.stat(target, { cred: ctx.cred });
|
|
18599
|
+
} catch {
|
|
18600
|
+
stat2 = null;
|
|
18601
|
+
}
|
|
18602
|
+
if (stat2?.isFile()) {
|
|
18603
|
+
files.add(target);
|
|
18604
|
+
continue;
|
|
18605
|
+
}
|
|
18606
|
+
if (stat2?.isDirectory()) {
|
|
18607
|
+
walk(target, byName, basename(target) === "test");
|
|
18608
|
+
continue;
|
|
18609
|
+
}
|
|
18610
|
+
if (/[*?]/.test(pattern)) {
|
|
18611
|
+
const matcher = globToRegExp(target);
|
|
18612
|
+
const before = files.size;
|
|
18613
|
+
walk(ctx.cwd, (path) => {
|
|
18614
|
+
if (matcher.test(path)) files.add(path);
|
|
18615
|
+
});
|
|
18616
|
+
if (files.size > before) continue;
|
|
18617
|
+
}
|
|
18618
|
+
missing.push(pattern);
|
|
18619
|
+
}
|
|
18620
|
+
return { files: [...files].sort(), missing };
|
|
18621
|
+
}
|
|
18622
|
+
async function runTestFiles(ctx, args, settings, preloads, env2) {
|
|
18623
|
+
const patterns = [];
|
|
18624
|
+
for (const arg of args) {
|
|
18625
|
+
if (arg.startsWith("--test-reporter=")) settings.reporter = arg.endsWith("=tap") ? "tap" : "spec";
|
|
18626
|
+
else if (arg.startsWith("--test-name-pattern=")) settings.namePatterns.push(arg.slice("--test-name-pattern=".length));
|
|
18627
|
+
else if (arg === "--test-only") settings.only = true;
|
|
18628
|
+
else if (!arg.startsWith("-")) patterns.push(arg);
|
|
18629
|
+
}
|
|
18630
|
+
const { files, missing } = discoverTestFiles(ctx, patterns);
|
|
18631
|
+
if (missing.length > 0) {
|
|
18632
|
+
for (const pattern of missing) ctx.stderr.write(`Could not find '${ctx.path(pattern)}'
|
|
18633
|
+
`);
|
|
18634
|
+
return 1;
|
|
18635
|
+
}
|
|
18636
|
+
if (files.length === 0) {
|
|
18637
|
+
ctx.stderr.write(
|
|
18638
|
+
"node --test: no test files found. Test files are named *.test.js, *-test.js, *_test.js, test-*.js or test.js (also .mjs and .cjs), or live in a test/ directory; node_modules is not searched.\n"
|
|
18639
|
+
);
|
|
18640
|
+
return 0;
|
|
18641
|
+
}
|
|
18642
|
+
const childEnv = { ...env2, SANDBOXEDJS_NODE_TEST: JSON.stringify(settings) };
|
|
18643
|
+
let failed = 0;
|
|
18644
|
+
for (const file3 of files) {
|
|
18645
|
+
const child = ctx.kernel.spawn(["node", ...preloads.flatMap((spec) => ["-r", spec]), file3], {
|
|
18646
|
+
cwd: ctx.cwd,
|
|
18647
|
+
env: childEnv,
|
|
18648
|
+
cred: ctx.cred,
|
|
18649
|
+
ppid: ctx.proc.pid,
|
|
18650
|
+
stdout: ctx.stdout,
|
|
18651
|
+
stderr: ctx.stderr
|
|
18652
|
+
});
|
|
18653
|
+
if (await child.wait() !== 0) failed += 1;
|
|
18654
|
+
}
|
|
18655
|
+
if (files.length > 1) {
|
|
18656
|
+
ctx.line(settings.reporter === "tap" ? `# files ${files.length} failed ${failed}` : `\u2139 files ${files.length}, failed ${failed}`);
|
|
18657
|
+
}
|
|
18658
|
+
return failed > 0 ? 1 : 0;
|
|
18659
|
+
}
|
|
18660
|
+
var nodeVersionFile = defineCommand({
|
|
18661
|
+
name: "nvm",
|
|
18662
|
+
path: "/usr/local/bin/nvm",
|
|
18663
|
+
summary: "node version manager (single-version stub)",
|
|
18664
|
+
run(ctx) {
|
|
18665
|
+
const sub = ctx.args[0];
|
|
18666
|
+
if (sub === "current" || sub === "version") {
|
|
18667
|
+
ctx.line(NODE_VERSION);
|
|
18668
|
+
return 0;
|
|
18669
|
+
}
|
|
18670
|
+
if (sub === "ls" || sub === "list") {
|
|
18671
|
+
ctx.line(`-> ${NODE_VERSION}`);
|
|
18672
|
+
return 0;
|
|
18673
|
+
}
|
|
18674
|
+
ctx.line(`nvm: only ${NODE_VERSION} is available in this container`);
|
|
18675
|
+
return 0;
|
|
18676
|
+
}
|
|
18677
|
+
});
|
|
18678
|
+
function nodeCommands() {
|
|
18679
|
+
return [node, nodeVersionFile];
|
|
18680
|
+
}
|
|
18681
|
+
|
|
18682
|
+
// src/python/python.ts
|
|
18683
|
+
init_path();
|
|
18684
|
+
|
|
18685
|
+
// src/python/host-abi.ts
|
|
18686
|
+
var SBX_HOST_ABI_VERSION = 1;
|
|
18687
|
+
var SBX_REQUEST_HEADER_BYTES = 16;
|
|
18688
|
+
var SBX_RESPONSE_HEADER_BYTES = 20;
|
|
18689
|
+
var Op = {
|
|
18690
|
+
handshake: 0,
|
|
18691
|
+
openat: 1,
|
|
18692
|
+
close: 2,
|
|
18693
|
+
read: 3,
|
|
18694
|
+
write: 4,
|
|
18695
|
+
pread: 5,
|
|
18696
|
+
pwrite: 6,
|
|
18697
|
+
lseek: 7,
|
|
18698
|
+
fstat: 8,
|
|
18699
|
+
statat: 9,
|
|
18700
|
+
ftruncate: 10,
|
|
18701
|
+
renameat: 11,
|
|
18702
|
+
unlinkat: 12,
|
|
18703
|
+
mkdirat: 13,
|
|
18704
|
+
readlinkat: 14,
|
|
18705
|
+
symlinkat: 15,
|
|
18706
|
+
getdents: 16,
|
|
18707
|
+
fsync: 17,
|
|
18708
|
+
dup: 256,
|
|
18709
|
+
dup2: 257,
|
|
18710
|
+
get_flags: 258,
|
|
18711
|
+
set_flags: 259,
|
|
18712
|
+
pipe: 512,
|
|
18713
|
+
poll: 768,
|
|
18714
|
+
clock_gettime: 1024,
|
|
18715
|
+
sleep: 1025,
|
|
18716
|
+
getpid: 1280,
|
|
18717
|
+
getcwd: 1281,
|
|
18718
|
+
chdir: 1282,
|
|
18719
|
+
environ: 1283,
|
|
17914
18720
|
getrandom: 1536,
|
|
17915
18721
|
socket: 1792,
|
|
17916
18722
|
bind: 1793,
|
|
@@ -18346,7 +19152,7 @@ var wheels_default = {
|
|
|
18346
19152
|
|
|
18347
19153
|
// package.json
|
|
18348
19154
|
var package_default = {
|
|
18349
|
-
version: "0.1.
|
|
19155
|
+
version: "0.1.74"};
|
|
18350
19156
|
|
|
18351
19157
|
// src/python/config.ts
|
|
18352
19158
|
function runtimeModuleUrl() {
|
|
@@ -22317,7 +23123,7 @@ var pyodideModule = null;
|
|
|
22317
23123
|
var indexUrl;
|
|
22318
23124
|
var moduleUrl;
|
|
22319
23125
|
var DEFAULT_BROWSER_INDEX_URL = "https://cdn.jsdelivr.net/pyodide/v0.28.3/full/";
|
|
22320
|
-
var
|
|
23126
|
+
var isNode3 = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
|
|
22321
23127
|
function configureCPython(options = {}) {
|
|
22322
23128
|
if (options.indexURL !== void 0) indexUrl = options.indexURL;
|
|
22323
23129
|
if (options.moduleURL !== void 0) {
|
|
@@ -22333,7 +23139,7 @@ function importPyodide() {
|
|
|
22333
23139
|
/* webpackIgnore: true */
|
|
22334
23140
|
moduleUrl
|
|
22335
23141
|
);
|
|
22336
|
-
} else if (
|
|
23142
|
+
} else if (isNode3) {
|
|
22337
23143
|
pyodideModule = nodeOnlyModule("pyodide");
|
|
22338
23144
|
} else {
|
|
22339
23145
|
pyodideModule = import(
|
|
@@ -22347,7 +23153,7 @@ function importPyodide() {
|
|
|
22347
23153
|
}
|
|
22348
23154
|
async function resolveIndexUrl() {
|
|
22349
23155
|
if (indexUrl) return indexUrl;
|
|
22350
|
-
if (!
|
|
23156
|
+
if (!isNode3) return DEFAULT_BROWSER_INDEX_URL;
|
|
22351
23157
|
try {
|
|
22352
23158
|
const { createRequire } = await nodeBuiltin("module");
|
|
22353
23159
|
const path = await nodeBuiltin("path");
|
|
@@ -24286,7 +25092,7 @@ function renameShadowedExports(source) {
|
|
|
24286
25092
|
(node2) => node2.type.startsWith("Import") || node2.type.startsWith("Export")
|
|
24287
25093
|
);
|
|
24288
25094
|
if (!isModule) return null;
|
|
24289
|
-
const programScope = { bindsExports:
|
|
25095
|
+
const programScope = { bindsExports: hoistedNames2(body).has(NAME), parent: null };
|
|
24290
25096
|
if (!programScope.bindsExports) return null;
|
|
24291
25097
|
const targets = [];
|
|
24292
25098
|
let bail = false;
|
|
@@ -24302,24 +25108,24 @@ function renameShadowedExports(source) {
|
|
|
24302
25108
|
function visit(node2, scope) {
|
|
24303
25109
|
if (bail) return;
|
|
24304
25110
|
let childScope = scope;
|
|
24305
|
-
let skip =
|
|
25111
|
+
let skip = NOTHING2;
|
|
24306
25112
|
switch (node2.type) {
|
|
24307
25113
|
case "FunctionDeclaration":
|
|
24308
25114
|
case "FunctionExpression":
|
|
24309
25115
|
case "ArrowFunctionExpression": {
|
|
24310
25116
|
const names = /* @__PURE__ */ new Set();
|
|
24311
|
-
for (const param of node2.params ?? [])
|
|
25117
|
+
for (const param of node2.params ?? []) collectPattern2(param, names);
|
|
24312
25118
|
if (isExports(node2.id) && node2.type === "FunctionExpression") names.add(NAME);
|
|
24313
25119
|
const fnBody = node2.body;
|
|
24314
25120
|
if (fnBody?.type === "BlockStatement") {
|
|
24315
|
-
for (const name of
|
|
25121
|
+
for (const name of hoistedNames2(fnBody.body)) names.add(name);
|
|
24316
25122
|
}
|
|
24317
25123
|
childScope = { bindsExports: names.has(NAME), parent: scope };
|
|
24318
25124
|
break;
|
|
24319
25125
|
}
|
|
24320
25126
|
case "CatchClause": {
|
|
24321
25127
|
const names = /* @__PURE__ */ new Set();
|
|
24322
|
-
if (node2.param)
|
|
25128
|
+
if (node2.param) collectPattern2(node2.param, names);
|
|
24323
25129
|
childScope = { bindsExports: names.has(NAME), parent: scope };
|
|
24324
25130
|
break;
|
|
24325
25131
|
}
|
|
@@ -24333,7 +25139,7 @@ function renameShadowedExports(source) {
|
|
|
24333
25139
|
case "StaticBlock":
|
|
24334
25140
|
if (node2 !== ast.body) {
|
|
24335
25141
|
childScope = {
|
|
24336
|
-
bindsExports:
|
|
25142
|
+
bindsExports: blockNames2(node2.body).has(NAME),
|
|
24337
25143
|
parent: scope
|
|
24338
25144
|
};
|
|
24339
25145
|
}
|
|
@@ -24345,7 +25151,7 @@ function renameShadowedExports(source) {
|
|
|
24345
25151
|
if (head2?.type === "VariableDeclaration" && head2.kind !== "var") {
|
|
24346
25152
|
const names = /* @__PURE__ */ new Set();
|
|
24347
25153
|
for (const declarator of head2.declarations) {
|
|
24348
|
-
|
|
25154
|
+
collectPattern2(declarator.id, names);
|
|
24349
25155
|
}
|
|
24350
25156
|
childScope = { bindsExports: names.has(NAME), parent: scope };
|
|
24351
25157
|
}
|
|
@@ -24369,7 +25175,7 @@ function renameShadowedExports(source) {
|
|
|
24369
25175
|
case "MemberExpression":
|
|
24370
25176
|
case "MethodDefinition":
|
|
24371
25177
|
case "PropertyDefinition":
|
|
24372
|
-
skip = node2.computed ?
|
|
25178
|
+
skip = node2.computed ? NOTHING2 : PROPERTY2;
|
|
24373
25179
|
break;
|
|
24374
25180
|
case "Property":
|
|
24375
25181
|
if (node2.computed) break;
|
|
@@ -24380,19 +25186,19 @@ function renameShadowedExports(source) {
|
|
|
24380
25186
|
}
|
|
24381
25187
|
return;
|
|
24382
25188
|
}
|
|
24383
|
-
skip =
|
|
25189
|
+
skip = PROPERTY2;
|
|
24384
25190
|
break;
|
|
24385
25191
|
case "LabeledStatement":
|
|
24386
25192
|
case "BreakStatement":
|
|
24387
25193
|
case "ContinueStatement":
|
|
24388
|
-
skip =
|
|
25194
|
+
skip = LABEL2;
|
|
24389
25195
|
break;
|
|
24390
25196
|
}
|
|
24391
25197
|
for (const [key, value] of Object.entries(node2)) {
|
|
24392
25198
|
if (key === "type" || key === "start" || key === "end" || skip.includes(key)) continue;
|
|
24393
25199
|
if (Array.isArray(value)) {
|
|
24394
|
-
for (const item of value) if (
|
|
24395
|
-
} else if (
|
|
25200
|
+
for (const item of value) if (isNode4(item)) visit(item, childScope);
|
|
25201
|
+
} else if (isNode4(value)) {
|
|
24396
25202
|
visit(value, childScope);
|
|
24397
25203
|
}
|
|
24398
25204
|
}
|
|
@@ -24404,73 +25210,73 @@ function resolvesToProgram(scope) {
|
|
|
24404
25210
|
}
|
|
24405
25211
|
return false;
|
|
24406
25212
|
}
|
|
24407
|
-
function
|
|
24408
|
-
const names =
|
|
24409
|
-
|
|
25213
|
+
function hoistedNames2(body) {
|
|
25214
|
+
const names = blockNames2(body);
|
|
25215
|
+
collectVars2(body, names);
|
|
24410
25216
|
return names;
|
|
24411
25217
|
}
|
|
24412
|
-
function
|
|
25218
|
+
function blockNames2(body) {
|
|
24413
25219
|
const names = /* @__PURE__ */ new Set();
|
|
24414
25220
|
for (const node2 of body ?? []) {
|
|
24415
25221
|
if (node2.type === "VariableDeclaration" && node2.kind !== "var") {
|
|
24416
25222
|
for (const declarator of node2.declarations) {
|
|
24417
|
-
|
|
25223
|
+
collectPattern2(declarator.id, names);
|
|
24418
25224
|
}
|
|
24419
|
-
} else if (node2.type === "ClassDeclaration" &&
|
|
25225
|
+
} else if (node2.type === "ClassDeclaration" && isNode4(node2.id)) {
|
|
24420
25226
|
names.add(node2.id.name);
|
|
24421
|
-
} else if (node2.type === "FunctionDeclaration" &&
|
|
25227
|
+
} else if (node2.type === "FunctionDeclaration" && isNode4(node2.id)) {
|
|
24422
25228
|
names.add(node2.id.name);
|
|
24423
25229
|
}
|
|
24424
25230
|
}
|
|
24425
25231
|
return names;
|
|
24426
25232
|
}
|
|
24427
|
-
function
|
|
25233
|
+
function collectVars2(nodes, names) {
|
|
24428
25234
|
if (Array.isArray(nodes)) {
|
|
24429
|
-
for (const item of nodes)
|
|
25235
|
+
for (const item of nodes) collectVars2(item, names);
|
|
24430
25236
|
return;
|
|
24431
25237
|
}
|
|
24432
|
-
if (!
|
|
25238
|
+
if (!isNode4(nodes)) return;
|
|
24433
25239
|
const node2 = nodes;
|
|
24434
25240
|
if (node2.type === "FunctionDeclaration" || node2.type === "FunctionExpression" || node2.type === "ArrowFunctionExpression") {
|
|
24435
|
-
if (
|
|
25241
|
+
if (isNode4(node2.id)) names.add(node2.id.name);
|
|
24436
25242
|
return;
|
|
24437
25243
|
}
|
|
24438
25244
|
if (node2.type === "VariableDeclaration" && node2.kind === "var") {
|
|
24439
25245
|
for (const declarator of node2.declarations) {
|
|
24440
|
-
|
|
25246
|
+
collectPattern2(declarator.id, names);
|
|
24441
25247
|
}
|
|
24442
25248
|
}
|
|
24443
25249
|
for (const [key, value] of Object.entries(node2)) {
|
|
24444
25250
|
if (key === "type" || key === "start" || key === "end") continue;
|
|
24445
|
-
|
|
25251
|
+
collectVars2(value, names);
|
|
24446
25252
|
}
|
|
24447
25253
|
}
|
|
24448
|
-
function
|
|
24449
|
-
if (!
|
|
25254
|
+
function collectPattern2(node2, names) {
|
|
25255
|
+
if (!isNode4(node2)) return;
|
|
24450
25256
|
switch (node2.type) {
|
|
24451
25257
|
case "Identifier":
|
|
24452
25258
|
names.add(node2.name);
|
|
24453
25259
|
return;
|
|
24454
25260
|
case "ObjectPattern":
|
|
24455
25261
|
for (const property of node2.properties) {
|
|
24456
|
-
|
|
25262
|
+
collectPattern2(property.value ?? property.argument, names);
|
|
24457
25263
|
}
|
|
24458
25264
|
return;
|
|
24459
25265
|
case "ArrayPattern":
|
|
24460
|
-
for (const element of node2.elements)
|
|
25266
|
+
for (const element of node2.elements) collectPattern2(element, names);
|
|
24461
25267
|
return;
|
|
24462
25268
|
case "AssignmentPattern":
|
|
24463
|
-
|
|
25269
|
+
collectPattern2(node2.left, names);
|
|
24464
25270
|
return;
|
|
24465
25271
|
case "RestElement":
|
|
24466
|
-
|
|
25272
|
+
collectPattern2(node2.argument, names);
|
|
24467
25273
|
return;
|
|
24468
25274
|
default:
|
|
24469
25275
|
return;
|
|
24470
25276
|
}
|
|
24471
25277
|
}
|
|
24472
25278
|
function isExports(value) {
|
|
24473
|
-
return
|
|
25279
|
+
return isNode4(value) && value.type === "Identifier" && value.name === NAME;
|
|
24474
25280
|
}
|
|
24475
25281
|
function freshName(source) {
|
|
24476
25282
|
let name = "__sandboxedjs_exports";
|
|
@@ -24478,12 +25284,12 @@ function freshName(source) {
|
|
|
24478
25284
|
while (source.includes(name)) name = `__sandboxedjs_exports${++suffix}`;
|
|
24479
25285
|
return name;
|
|
24480
25286
|
}
|
|
24481
|
-
function
|
|
25287
|
+
function isNode4(value) {
|
|
24482
25288
|
return typeof value === "object" && value !== null && typeof value.type === "string";
|
|
24483
25289
|
}
|
|
24484
|
-
var
|
|
24485
|
-
var
|
|
24486
|
-
var
|
|
25290
|
+
var NOTHING2 = [];
|
|
25291
|
+
var PROPERTY2 = ["property", "key"];
|
|
25292
|
+
var LABEL2 = ["label"];
|
|
24487
25293
|
|
|
24488
25294
|
// src/pkg/index.ts
|
|
24489
25295
|
init_path();
|
|
@@ -25229,752 +26035,356 @@ var ContainerFs = class {
|
|
|
25229
26035
|
this.vfs.symlink(target, clean(link));
|
|
25230
26036
|
}
|
|
25231
26037
|
async readlink(path) {
|
|
25232
|
-
return this.vfs.readlink(clean(path));
|
|
25233
|
-
}
|
|
25234
|
-
async realpath(path) {
|
|
25235
|
-
return this.vfs.realpath(clean(path));
|
|
25236
|
-
}
|
|
25237
|
-
async chmod(path, mode) {
|
|
25238
|
-
this.vfs.chmod(clean(path), mode);
|
|
25239
|
-
}
|
|
25240
|
-
async chown(path, uid, gid) {
|
|
25241
|
-
this.vfs.chown(clean(path), uid, gid, ROOT_CRED);
|
|
25242
|
-
}
|
|
25243
|
-
/** Every path beneath `root`, depth-first. */
|
|
25244
|
-
async walk(root = "/") {
|
|
25245
|
-
return [...this.vfs.walk(clean(root))];
|
|
25246
|
-
}
|
|
25247
|
-
/** Total bytes and file counts, as `df` reports them. */
|
|
25248
|
-
async usage(root = "/") {
|
|
25249
|
-
return this.vfs.usage(clean(root));
|
|
25250
|
-
}
|
|
25251
|
-
/** Read many files at once, keyed by path. */
|
|
25252
|
-
async readAll(paths) {
|
|
25253
|
-
const out = {};
|
|
25254
|
-
for (const path of paths) out[path] = this.vfs.readText(clean(path));
|
|
25255
|
-
return out;
|
|
25256
|
-
}
|
|
25257
|
-
/** Write a whole map of files, creating parents. */
|
|
25258
|
-
async writeAll(files, opts = {}) {
|
|
25259
|
-
for (const [key, value] of Object.entries(files)) {
|
|
25260
|
-
await this.writeFile(resolve(opts.cwd ?? "/", key), value);
|
|
25261
|
-
}
|
|
25262
|
-
}
|
|
25263
|
-
};
|
|
25264
|
-
|
|
25265
|
-
// src/container/session.ts
|
|
25266
|
-
var Session = class {
|
|
25267
|
-
constructor(kernel, init) {
|
|
25268
|
-
this.kernel = kernel;
|
|
25269
|
-
this.proc = kernel.procs.create({
|
|
25270
|
-
argv: ["-sh"],
|
|
25271
|
-
cwd: init.cwd,
|
|
25272
|
-
env: init.env,
|
|
25273
|
-
cred: init.cred,
|
|
25274
|
-
ppid: 1,
|
|
25275
|
-
kind: "shell",
|
|
25276
|
-
tty: "pts/0"
|
|
25277
|
-
});
|
|
25278
|
-
this.shell = new Shell({
|
|
25279
|
-
kernel,
|
|
25280
|
-
proc: this.proc,
|
|
25281
|
-
cwd: init.cwd,
|
|
25282
|
-
env: init.env,
|
|
25283
|
-
cred: init.cred,
|
|
25284
|
-
scriptName: "sh",
|
|
25285
|
-
options: { interactive: true }
|
|
25286
|
-
});
|
|
25287
|
-
this.hooks = init.hooks ?? {};
|
|
25288
|
-
}
|
|
25289
|
-
kernel;
|
|
25290
|
-
shell;
|
|
25291
|
-
proc;
|
|
25292
|
-
closed = false;
|
|
25293
|
-
hooks;
|
|
25294
|
-
get cwd() {
|
|
25295
|
-
return this.shell.cwd;
|
|
25296
|
-
}
|
|
25297
|
-
get env() {
|
|
25298
|
-
return this.shell.vars.environment();
|
|
25299
|
-
}
|
|
25300
|
-
get history() {
|
|
25301
|
-
return this.shell.history;
|
|
25302
|
-
}
|
|
25303
|
-
/** Run a command line, keeping every side effect for the next call. */
|
|
25304
|
-
async run(command, opts = {}) {
|
|
25305
|
-
if (this.closed) throw new Error("session is closed");
|
|
25306
|
-
const combined = [];
|
|
25307
|
-
const decoder9 = new TextDecoder();
|
|
25308
|
-
const stdout = new BufferSink((chunk) => {
|
|
25309
|
-
const text2 = decoder9.decode(chunk, { stream: true });
|
|
25310
|
-
combined.push(text2);
|
|
25311
|
-
opts.onStdout?.(text2);
|
|
25312
|
-
this.hooks.onStdout?.(text2);
|
|
25313
|
-
});
|
|
25314
|
-
const stderr = new BufferSink((chunk) => {
|
|
25315
|
-
const text2 = decoder9.decode(chunk, { stream: true });
|
|
25316
|
-
combined.push(text2);
|
|
25317
|
-
opts.onStderr?.(text2);
|
|
25318
|
-
this.hooks.onStderr?.(text2);
|
|
25319
|
-
});
|
|
25320
|
-
if (opts.tty) {
|
|
25321
|
-
stdout.isTTY = true;
|
|
25322
|
-
stderr.isTTY = true;
|
|
25323
|
-
stdout.columns = opts.columns ?? 80;
|
|
25324
|
-
stdout.rows = opts.rows ?? 24;
|
|
25325
|
-
}
|
|
25326
|
-
const stdin = opts.stdin === void 0 ? new NullInput() : typeof opts.stdin === "string" || opts.stdin instanceof Uint8Array ? Pipe.from(opts.stdin) : opts.stdin;
|
|
25327
|
-
this.shell.history.push(command);
|
|
25328
|
-
let timer;
|
|
25329
|
-
if (opts.timeoutMs !== void 0) {
|
|
25330
|
-
timer = setTimeout(() => this.proc.deliver("SIGKILL"), opts.timeoutMs);
|
|
25331
|
-
}
|
|
25332
|
-
let exitCode;
|
|
25333
|
-
try {
|
|
25334
|
-
exitCode = await this.shell.execute(command, { stdin, stdout, stderr });
|
|
25335
|
-
} finally {
|
|
25336
|
-
if (timer) clearTimeout(timer);
|
|
25337
|
-
}
|
|
25338
|
-
return { exitCode, stdout: stdout.text(), stderr: stderr.text(), output: combined.join("") };
|
|
25339
|
-
}
|
|
25340
|
-
/** Stream a long-running command; resolves when it exits. */
|
|
25341
|
-
async stream(command, handlers = {}) {
|
|
25342
|
-
const result = await this.run(command, handlers);
|
|
25343
|
-
return result.exitCode;
|
|
25344
|
-
}
|
|
25345
|
-
/** Feed the session an arbitrary output stream, for terminal integration. */
|
|
25346
|
-
async pipeTo(command, stdout, stderr, stdin) {
|
|
25347
|
-
return this.shell.execute(command, { stdin: stdin ?? new NullInput(), stdout, stderr });
|
|
25348
|
-
}
|
|
25349
|
-
/** True when the last command asked the shell to exit. */
|
|
25350
|
-
get isExiting() {
|
|
25351
|
-
return this.shell.isExiting;
|
|
25352
|
-
}
|
|
25353
|
-
close() {
|
|
25354
|
-
if (this.closed) return;
|
|
25355
|
-
this.closed = true;
|
|
25356
|
-
this.proc.exit(0);
|
|
25357
|
-
this.kernel.procs.remove(this.proc.pid);
|
|
25358
|
-
}
|
|
25359
|
-
};
|
|
25360
|
-
|
|
25361
|
-
// src/node/node-child-process-bridge.ts
|
|
25362
|
-
var KernelChildProcess = class {
|
|
25363
|
-
pid;
|
|
25364
|
-
command;
|
|
25365
|
-
args;
|
|
25366
|
-
parentPid;
|
|
25367
|
-
state = "running";
|
|
25368
|
-
exitCode;
|
|
25369
|
-
stdout = "";
|
|
25370
|
-
stderr = "";
|
|
25371
|
-
listeners = /* @__PURE__ */ new Map();
|
|
25372
|
-
kernel;
|
|
25373
|
-
cred;
|
|
25374
|
-
cwd;
|
|
25375
|
-
env;
|
|
25376
|
-
stdin = new Pipe();
|
|
25377
|
-
process;
|
|
25378
|
-
started = false;
|
|
25379
|
-
cancelled = false;
|
|
25380
|
-
constructor(kernel, cred, config2, pid) {
|
|
25381
|
-
this.stdin.interactive = true;
|
|
25382
|
-
if (config2.inheritStdio) this.stdin.isTTY = true;
|
|
25383
|
-
if (config2.stdinIgnored) this.stdin.end();
|
|
25384
|
-
this.stdin.onRawMode = (enabled) => this.emit("rawmode", enabled);
|
|
25385
|
-
this.kernel = kernel;
|
|
25386
|
-
this.cred = cred;
|
|
25387
|
-
this.pid = pid;
|
|
25388
|
-
this.command = config2.command;
|
|
25389
|
-
this.args = config2.args?.slice() ?? [];
|
|
25390
|
-
this.parentPid = config2.parentPid;
|
|
25391
|
-
this.cwd = config2.cwd ?? "/";
|
|
25392
|
-
this.env = { ...config2.env };
|
|
25393
|
-
}
|
|
25394
|
-
on(event, listener) {
|
|
25395
|
-
let listeners = this.listeners.get(event);
|
|
25396
|
-
if (!listeners) {
|
|
25397
|
-
listeners = /* @__PURE__ */ new Set();
|
|
25398
|
-
this.listeners.set(event, listeners);
|
|
25399
|
-
}
|
|
25400
|
-
listeners.add(listener);
|
|
25401
|
-
return this;
|
|
25402
|
-
}
|
|
25403
|
-
emit(event, ...args) {
|
|
25404
|
-
for (const listener of this.listeners.get(event) ?? []) listener(...args);
|
|
25405
|
-
}
|
|
25406
|
-
exec() {
|
|
25407
|
-
if (this.started) return;
|
|
25408
|
-
this.started = true;
|
|
25409
|
-
queueMicrotask(() => {
|
|
25410
|
-
if (this.cancelled) {
|
|
25411
|
-
this.finish(143);
|
|
25412
|
-
return;
|
|
25413
|
-
}
|
|
25414
|
-
const stdout = new ChildOutput(this, "stdout");
|
|
25415
|
-
const stderr = new ChildOutput(this, "stderr");
|
|
25416
|
-
try {
|
|
25417
|
-
this.process = this.kernel.spawn([this.command, ...this.args], {
|
|
25418
|
-
cwd: this.cwd,
|
|
25419
|
-
env: this.env,
|
|
25420
|
-
cred: this.cred,
|
|
25421
|
-
stdin: this.stdin,
|
|
25422
|
-
stdout,
|
|
25423
|
-
stderr,
|
|
25424
|
-
ppid: 1
|
|
25425
|
-
});
|
|
25426
|
-
void this.process.wait().then((code) => {
|
|
25427
|
-
stdout.end();
|
|
25428
|
-
stderr.end();
|
|
25429
|
-
this.finish(code);
|
|
25430
|
-
});
|
|
25431
|
-
} catch (error) {
|
|
25432
|
-
stderr.write(error instanceof Error ? error.message : String(error));
|
|
25433
|
-
stderr.end();
|
|
25434
|
-
stdout.end();
|
|
25435
|
-
this.finish(1);
|
|
25436
|
-
}
|
|
25437
|
-
});
|
|
25438
|
-
}
|
|
25439
|
-
sendStdin(data) {
|
|
25440
|
-
try {
|
|
25441
|
-
this.stdin.write(data);
|
|
25442
|
-
} catch {
|
|
25443
|
-
}
|
|
25444
|
-
}
|
|
25445
|
-
/** Signal EOF, so a child reading stdin to the end can finish. */
|
|
25446
|
-
endStdin() {
|
|
25447
|
-
try {
|
|
25448
|
-
this.stdin.end();
|
|
25449
|
-
} catch {
|
|
25450
|
-
}
|
|
25451
|
-
}
|
|
25452
|
-
kill(signal = "SIGTERM") {
|
|
25453
|
-
if (this.process) {
|
|
25454
|
-
this.process.deliver(signal);
|
|
25455
|
-
return;
|
|
25456
|
-
}
|
|
25457
|
-
this.cancelled = true;
|
|
26038
|
+
return this.vfs.readlink(clean(path));
|
|
25458
26039
|
}
|
|
25459
|
-
|
|
25460
|
-
|
|
25461
|
-
this.state = "exited";
|
|
25462
|
-
this.exitCode = code;
|
|
25463
|
-
this.emit("exit", code);
|
|
26040
|
+
async realpath(path) {
|
|
26041
|
+
return this.vfs.realpath(clean(path));
|
|
25464
26042
|
}
|
|
25465
|
-
|
|
25466
|
-
this
|
|
25467
|
-
this.emit(stream, text2);
|
|
26043
|
+
async chmod(path, mode) {
|
|
26044
|
+
this.vfs.chmod(clean(path), mode);
|
|
25468
26045
|
}
|
|
25469
|
-
|
|
25470
|
-
|
|
25471
|
-
constructor(child, stream) {
|
|
25472
|
-
this.child = child;
|
|
25473
|
-
this.stream = stream;
|
|
26046
|
+
async chown(path, uid, gid) {
|
|
26047
|
+
this.vfs.chown(clean(path), uid, gid, ROOT_CRED);
|
|
25474
26048
|
}
|
|
25475
|
-
|
|
25476
|
-
|
|
25477
|
-
|
|
25478
|
-
closedState = false;
|
|
25479
|
-
decoder = new TextDecoder();
|
|
25480
|
-
get closed() {
|
|
25481
|
-
return this.closedState;
|
|
26049
|
+
/** Every path beneath `root`, depth-first. */
|
|
26050
|
+
async walk(root = "/") {
|
|
26051
|
+
return [...this.vfs.walk(clean(root))];
|
|
25482
26052
|
}
|
|
25483
|
-
|
|
25484
|
-
|
|
25485
|
-
|
|
25486
|
-
if (text2) this.child.append(this.stream, text2);
|
|
26053
|
+
/** Total bytes and file counts, as `df` reports them. */
|
|
26054
|
+
async usage(root = "/") {
|
|
26055
|
+
return this.vfs.usage(clean(root));
|
|
25487
26056
|
}
|
|
25488
|
-
|
|
25489
|
-
|
|
25490
|
-
|
|
25491
|
-
const
|
|
25492
|
-
|
|
26057
|
+
/** Read many files at once, keyed by path. */
|
|
26058
|
+
async readAll(paths) {
|
|
26059
|
+
const out = {};
|
|
26060
|
+
for (const path of paths) out[path] = this.vfs.readText(clean(path));
|
|
26061
|
+
return out;
|
|
25493
26062
|
}
|
|
25494
|
-
|
|
25495
|
-
|
|
25496
|
-
|
|
25497
|
-
|
|
25498
|
-
const originalSpawn = manager.spawn;
|
|
25499
|
-
manager.spawn = (config2) => {
|
|
25500
|
-
const resolved = kernel.resolveExecutable(config2.command, config2.cwd ?? "/", config2.env ?? {}, cred);
|
|
25501
|
-
if (resolved?.kind === "builtin") {
|
|
25502
|
-
return new KernelChildProcess(kernel, cred, config2, nextBridgePid++);
|
|
26063
|
+
/** Write a whole map of files, creating parents. */
|
|
26064
|
+
async writeAll(files, opts = {}) {
|
|
26065
|
+
for (const [key, value] of Object.entries(files)) {
|
|
26066
|
+
await this.writeFile(resolve(opts.cwd ?? "/", key), value);
|
|
25503
26067
|
}
|
|
25504
|
-
return originalSpawn.call(manager, config2);
|
|
25505
|
-
};
|
|
25506
|
-
return () => {
|
|
25507
|
-
if (manager.spawn === originalSpawn) return;
|
|
25508
|
-
manager.spawn = originalSpawn;
|
|
25509
|
-
};
|
|
25510
|
-
}
|
|
25511
|
-
|
|
25512
|
-
// src/node/host-module-tracker.ts
|
|
25513
|
-
var HostModuleTracker = class {
|
|
25514
|
-
active = 0;
|
|
25515
|
-
disposed = false;
|
|
25516
|
-
dispose() {
|
|
25517
|
-
this.disposed = true;
|
|
25518
|
-
}
|
|
25519
|
-
wrapped = /* @__PURE__ */ new WeakMap();
|
|
25520
|
-
originals = /* @__PURE__ */ new WeakMap();
|
|
25521
|
-
pending = () => this.active;
|
|
25522
|
-
unwrap = (value) => value && (typeof value === "object" || typeof value === "function") ? this.originals.get(value) ?? value : value;
|
|
25523
|
-
wrap(value) {
|
|
25524
|
-
if (value === null || typeof value !== "object" && typeof value !== "function") return value;
|
|
25525
|
-
const object = value;
|
|
25526
|
-
if (Array.isArray(value) || ArrayBuffer.isView(value) || value instanceof ArrayBuffer) return value;
|
|
25527
|
-
if (this.wrapped.has(object)) return this.wrapped.get(object);
|
|
25528
|
-
const tracker = this;
|
|
25529
|
-
const proxy = new Proxy(object, {
|
|
25530
|
-
// CommonJS native loaders re-export by assigning exports back onto the
|
|
25531
|
-
// binding object. Never store a process-owned proxy in a shared module.
|
|
25532
|
-
set(target, key, member) {
|
|
25533
|
-
return Reflect.set(target, key, tracker.unwrap(member), target);
|
|
25534
|
-
},
|
|
25535
|
-
defineProperty(target, key, descriptor) {
|
|
25536
|
-
return Reflect.defineProperty(target, key, "value" in descriptor ? { ...descriptor, value: tracker.unwrap(descriptor.value) } : descriptor);
|
|
25537
|
-
},
|
|
25538
|
-
get(target, key) {
|
|
25539
|
-
const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
|
|
25540
|
-
const member = Reflect.get(target, key, target);
|
|
25541
|
-
if (descriptor && !descriptor.configurable && "value" in descriptor && !descriptor.writable) return member;
|
|
25542
|
-
return typeof member === "function" ? tracker.wrap(member) : member;
|
|
25543
|
-
},
|
|
25544
|
-
apply(target, receiver, args) {
|
|
25545
|
-
const result = Reflect.apply(target, tracker.unwrap(receiver), args.map(tracker.unwrap));
|
|
25546
|
-
if (result && typeof result.then === "function") {
|
|
25547
|
-
tracker.active++;
|
|
25548
|
-
return Promise.resolve(result).then(
|
|
25549
|
-
(value2) => {
|
|
25550
|
-
tracker.active--;
|
|
25551
|
-
return tracker.disposed ? new Promise(() => {
|
|
25552
|
-
}) : tracker.wrap(value2);
|
|
25553
|
-
},
|
|
25554
|
-
(error) => {
|
|
25555
|
-
tracker.active--;
|
|
25556
|
-
if (tracker.disposed) return new Promise(() => {
|
|
25557
|
-
});
|
|
25558
|
-
throw error;
|
|
25559
|
-
}
|
|
25560
|
-
);
|
|
25561
|
-
}
|
|
25562
|
-
return tracker.wrap(result);
|
|
25563
|
-
},
|
|
25564
|
-
construct(target, args, newTarget) {
|
|
25565
|
-
return tracker.wrap(Reflect.construct(target, args.map(tracker.unwrap), tracker.unwrap(newTarget)));
|
|
25566
|
-
}
|
|
25567
|
-
});
|
|
25568
|
-
this.wrapped.set(object, proxy);
|
|
25569
|
-
this.originals.set(proxy, object);
|
|
25570
|
-
return proxy;
|
|
25571
26068
|
}
|
|
25572
26069
|
};
|
|
25573
26070
|
|
|
25574
|
-
// src/
|
|
25575
|
-
|
|
25576
|
-
|
|
25577
|
-
|
|
25578
|
-
|
|
25579
|
-
|
|
25580
|
-
|
|
25581
|
-
|
|
25582
|
-
|
|
25583
|
-
|
|
25584
|
-
|
|
25585
|
-
|
|
25586
|
-
|
|
25587
|
-
|
|
25588
|
-
|
|
25589
|
-
|
|
25590
|
-
|
|
25591
|
-
|
|
25592
|
-
|
|
25593
|
-
|
|
25594
|
-
|
|
25595
|
-
|
|
25596
|
-
};
|
|
25597
|
-
var DEFAULT_LOCAL = "__sbxDefault";
|
|
25598
|
-
var MAYBE_ESM = /(^|[\s;}(])(?:import|export)(?:[\s({[*"']|$)|\bimport\s*\.\s*meta\b/;
|
|
25599
|
-
function looksLikeEsm(source) {
|
|
25600
|
-
return MAYBE_ESM.test(source);
|
|
25601
|
-
}
|
|
25602
|
-
function transformEsm(source, filename = "module.js") {
|
|
25603
|
-
if (!looksLikeEsm(source)) return null;
|
|
25604
|
-
let ast;
|
|
25605
|
-
try {
|
|
25606
|
-
ast = parseModule(source, filename);
|
|
25607
|
-
} catch {
|
|
25608
|
-
return null;
|
|
25609
|
-
}
|
|
25610
|
-
const body = ast.body;
|
|
25611
|
-
const hasModuleSyntax = body.some(
|
|
25612
|
-
(node2) => node2.type.startsWith("Import") || node2.type.startsWith("Export")
|
|
25613
|
-
);
|
|
25614
|
-
const usesImportMeta = !hasModuleSyntax && containsImportMeta(ast);
|
|
25615
|
-
const esm = hasModuleSyntax || usesImportMeta;
|
|
25616
|
-
if (!esm && !containsImportExpression(ast)) return null;
|
|
25617
|
-
const edits = [];
|
|
25618
|
-
const prelude = [];
|
|
25619
|
-
const importBindings = /* @__PURE__ */ new Map();
|
|
25620
|
-
const exportGetters = /* @__PURE__ */ new Map();
|
|
25621
|
-
let namespaceCount = 0;
|
|
25622
|
-
const namespaceFor = (specifier) => {
|
|
25623
|
-
const id = `__sbxNs${namespaceCount++}`;
|
|
25624
|
-
prelude.push(`var ${id} = ${HELPERS.import}(${JSON.stringify(specifier)});`);
|
|
25625
|
-
return id;
|
|
25626
|
-
};
|
|
25627
|
-
for (const node2 of body) {
|
|
25628
|
-
if (node2.type === "ImportDeclaration") collectImport(node2);
|
|
26071
|
+
// src/container/session.ts
|
|
26072
|
+
var Session = class {
|
|
26073
|
+
constructor(kernel, init) {
|
|
26074
|
+
this.kernel = kernel;
|
|
26075
|
+
this.proc = kernel.procs.create({
|
|
26076
|
+
argv: ["-sh"],
|
|
26077
|
+
cwd: init.cwd,
|
|
26078
|
+
env: init.env,
|
|
26079
|
+
cred: init.cred,
|
|
26080
|
+
ppid: 1,
|
|
26081
|
+
kind: "shell",
|
|
26082
|
+
tty: "pts/0"
|
|
26083
|
+
});
|
|
26084
|
+
this.shell = new Shell({
|
|
26085
|
+
kernel,
|
|
26086
|
+
proc: this.proc,
|
|
26087
|
+
cwd: init.cwd,
|
|
26088
|
+
env: init.env,
|
|
26089
|
+
cred: init.cred,
|
|
26090
|
+
scriptName: "sh",
|
|
26091
|
+
options: { interactive: true }
|
|
26092
|
+
});
|
|
26093
|
+
this.hooks = init.hooks ?? {};
|
|
25629
26094
|
}
|
|
25630
|
-
|
|
25631
|
-
|
|
25632
|
-
|
|
25633
|
-
|
|
25634
|
-
|
|
25635
|
-
|
|
25636
|
-
|
|
25637
|
-
break;
|
|
25638
|
-
case "ExportAllDeclaration":
|
|
25639
|
-
collectExportAll(node2);
|
|
25640
|
-
break;
|
|
25641
|
-
}
|
|
26095
|
+
kernel;
|
|
26096
|
+
shell;
|
|
26097
|
+
proc;
|
|
26098
|
+
closed = false;
|
|
26099
|
+
hooks;
|
|
26100
|
+
get cwd() {
|
|
26101
|
+
return this.shell.cwd;
|
|
25642
26102
|
}
|
|
25643
|
-
|
|
25644
|
-
|
|
25645
|
-
`Object.defineProperty(${HELPERS.exports}, "__esModule", { value: true });`,
|
|
25646
|
-
...prelude,
|
|
25647
|
-
...[...exportGetters].map(
|
|
25648
|
-
([name, expression]) => `Object.defineProperty(${HELPERS.exports}, ${JSON.stringify(name)}, { enumerable: true, configurable: true, get: function () { return ${expression}; } });`
|
|
25649
|
-
)
|
|
25650
|
-
].join("\n") : "";
|
|
25651
|
-
return {
|
|
25652
|
-
code: header ? `${header}
|
|
25653
|
-
${applyEdits(source, edits)}` : applyEdits(source, edits),
|
|
25654
|
-
esm,
|
|
25655
|
-
topLevelAwait: hasTopLevelAwait(ast)
|
|
25656
|
-
};
|
|
25657
|
-
function collectImport(node2) {
|
|
25658
|
-
const specifier = node2.source.value;
|
|
25659
|
-
const specifiers = node2.specifiers ?? [];
|
|
25660
|
-
const id = namespaceFor(specifier);
|
|
25661
|
-
for (const entry of specifiers) {
|
|
25662
|
-
const local = entry.local.name ?? "";
|
|
25663
|
-
if (entry.type === "ImportDefaultSpecifier") {
|
|
25664
|
-
importBindings.set(local, `${id}.default`);
|
|
25665
|
-
} else if (entry.type === "ImportNamespaceSpecifier") {
|
|
25666
|
-
importBindings.set(local, id);
|
|
25667
|
-
} else {
|
|
25668
|
-
const imported = entry.imported;
|
|
25669
|
-
const name = imported.type === "Identifier" ? imported.name : imported.value;
|
|
25670
|
-
importBindings.set(local, `${id}[${JSON.stringify(name)}]`);
|
|
25671
|
-
}
|
|
25672
|
-
}
|
|
25673
|
-
drop(node2);
|
|
26103
|
+
get env() {
|
|
26104
|
+
return this.shell.vars.environment();
|
|
25674
26105
|
}
|
|
25675
|
-
|
|
25676
|
-
|
|
25677
|
-
|
|
25678
|
-
|
|
25679
|
-
|
|
25680
|
-
|
|
26106
|
+
get history() {
|
|
26107
|
+
return this.shell.history;
|
|
26108
|
+
}
|
|
26109
|
+
/** Run a command line, keeping every side effect for the next call. */
|
|
26110
|
+
async run(command, opts = {}) {
|
|
26111
|
+
if (this.closed) throw new Error("session is closed");
|
|
26112
|
+
const combined = [];
|
|
26113
|
+
const decoder9 = new TextDecoder();
|
|
26114
|
+
const stdout = new BufferSink((chunk) => {
|
|
26115
|
+
const text2 = decoder9.decode(chunk, { stream: true });
|
|
26116
|
+
combined.push(text2);
|
|
26117
|
+
opts.onStdout?.(text2);
|
|
26118
|
+
this.hooks.onStdout?.(text2);
|
|
26119
|
+
});
|
|
26120
|
+
const stderr = new BufferSink((chunk) => {
|
|
26121
|
+
const text2 = decoder9.decode(chunk, { stream: true });
|
|
26122
|
+
combined.push(text2);
|
|
26123
|
+
opts.onStderr?.(text2);
|
|
26124
|
+
this.hooks.onStderr?.(text2);
|
|
26125
|
+
});
|
|
26126
|
+
const outGate = new DetachableOutput(stdout, (text2) => this.hooks.onStdout?.(text2));
|
|
26127
|
+
const errGate = new DetachableOutput(stderr, (text2) => this.hooks.onStderr?.(text2));
|
|
26128
|
+
if (opts.tty) {
|
|
26129
|
+
outGate.isTTY = true;
|
|
26130
|
+
errGate.isTTY = true;
|
|
26131
|
+
outGate.columns = opts.columns ?? 80;
|
|
26132
|
+
outGate.rows = opts.rows ?? 24;
|
|
25681
26133
|
}
|
|
25682
|
-
const
|
|
25683
|
-
|
|
25684
|
-
|
|
25685
|
-
|
|
25686
|
-
|
|
25687
|
-
const read = id ? `${id}[${JSON.stringify(local)}]` : importBindings.get(local) ?? local;
|
|
25688
|
-
exportGetters.set(exported, read);
|
|
26134
|
+
const stdin = opts.stdin === void 0 ? new NullInput() : typeof opts.stdin === "string" || opts.stdin instanceof Uint8Array ? Pipe.from(opts.stdin) : opts.stdin;
|
|
26135
|
+
this.shell.history.push(command);
|
|
26136
|
+
let timer;
|
|
26137
|
+
if (opts.timeoutMs !== void 0) {
|
|
26138
|
+
timer = setTimeout(() => this.proc.deliver("SIGKILL"), opts.timeoutMs);
|
|
25689
26139
|
}
|
|
25690
|
-
|
|
25691
|
-
|
|
25692
|
-
|
|
25693
|
-
|
|
25694
|
-
|
|
25695
|
-
|
|
25696
|
-
|
|
25697
|
-
if (named) {
|
|
25698
|
-
exportGetters.set("default", named.name);
|
|
25699
|
-
edits.push({ start: node2.start, end: declaration.start, text: "" });
|
|
25700
|
-
return;
|
|
25701
|
-
}
|
|
25702
|
-
const keyword = declaration.type === "FunctionDeclaration" ? "function" : "class";
|
|
25703
|
-
const keywordEnd = source.indexOf(keyword, declaration.start) + keyword.length;
|
|
25704
|
-
exportGetters.set("default", DEFAULT_LOCAL);
|
|
25705
|
-
edits.push({ start: node2.start, end: declaration.start, text: "" });
|
|
25706
|
-
edits.push({ start: keywordEnd, end: keywordEnd, text: ` ${DEFAULT_LOCAL}` });
|
|
25707
|
-
return;
|
|
26140
|
+
let exitCode;
|
|
26141
|
+
try {
|
|
26142
|
+
exitCode = await this.shell.execute(command, { stdin, stdout: outGate, stderr: errGate });
|
|
26143
|
+
} finally {
|
|
26144
|
+
if (timer) clearTimeout(timer);
|
|
26145
|
+
outGate.detach();
|
|
26146
|
+
errGate.detach();
|
|
25708
26147
|
}
|
|
25709
|
-
|
|
25710
|
-
edits.push({ start: node2.start, end: declaration.start, text: `var ${DEFAULT_LOCAL} = ` });
|
|
25711
|
-
edits.push({ start: node2.end, end: node2.end, text: ";" });
|
|
26148
|
+
return { exitCode, stdout: stdout.text(), stderr: stderr.text(), output: combined.join("") };
|
|
25712
26149
|
}
|
|
25713
|
-
|
|
25714
|
-
|
|
25715
|
-
const
|
|
25716
|
-
|
|
25717
|
-
else prelude.push(`${HELPERS.exportAll}(${HELPERS.exports}, ${id});`);
|
|
25718
|
-
drop(node2);
|
|
26150
|
+
/** Stream a long-running command; resolves when it exits. */
|
|
26151
|
+
async stream(command, handlers = {}) {
|
|
26152
|
+
const result = await this.run(command, handlers);
|
|
26153
|
+
return result.exitCode;
|
|
25719
26154
|
}
|
|
25720
|
-
|
|
25721
|
-
|
|
26155
|
+
/** Feed the session an arbitrary output stream, for terminal integration. */
|
|
26156
|
+
async pipeTo(command, stdout, stderr, stdin) {
|
|
26157
|
+
return this.shell.execute(command, { stdin: stdin ?? new NullInput(), stdout, stderr });
|
|
25722
26158
|
}
|
|
25723
|
-
|
|
25724
|
-
|
|
25725
|
-
|
|
25726
|
-
|
|
25727
|
-
|
|
25728
|
-
|
|
25729
|
-
|
|
25730
|
-
|
|
25731
|
-
|
|
25732
|
-
return;
|
|
25733
|
-
case "ExportNamedDeclaration":
|
|
25734
|
-
if (!node2.declaration) return;
|
|
25735
|
-
break;
|
|
25736
|
-
case "FunctionDeclaration":
|
|
25737
|
-
case "FunctionExpression":
|
|
25738
|
-
case "ArrowFunctionExpression": {
|
|
25739
|
-
const names = /* @__PURE__ */ new Set();
|
|
25740
|
-
for (const param of node2.params ?? []) collectPattern2(param, names);
|
|
25741
|
-
const id = node2.id;
|
|
25742
|
-
if (id && node2.type === "FunctionExpression") names.add(id.name);
|
|
25743
|
-
const fnBody = node2.body;
|
|
25744
|
-
if (fnBody?.type === "BlockStatement") {
|
|
25745
|
-
for (const name of hoistedNames2(fnBody.body)) names.add(name);
|
|
25746
|
-
}
|
|
25747
|
-
childScope = { names, parent: scope };
|
|
25748
|
-
break;
|
|
25749
|
-
}
|
|
25750
|
-
case "CatchClause": {
|
|
25751
|
-
const names = /* @__PURE__ */ new Set();
|
|
25752
|
-
if (node2.param) collectPattern2(node2.param, names);
|
|
25753
|
-
childScope = { names, parent: scope };
|
|
25754
|
-
break;
|
|
25755
|
-
}
|
|
25756
|
-
case "ClassExpression": {
|
|
25757
|
-
const id = node2.id;
|
|
25758
|
-
if (id) childScope = { names: /* @__PURE__ */ new Set([id.name]), parent: scope };
|
|
25759
|
-
break;
|
|
25760
|
-
}
|
|
25761
|
-
case "BlockStatement":
|
|
25762
|
-
case "StaticBlock":
|
|
25763
|
-
if (!isProgram) {
|
|
25764
|
-
childScope = { names: blockNames2(node2.body), parent: scope };
|
|
25765
|
-
}
|
|
25766
|
-
break;
|
|
25767
|
-
case "ForStatement":
|
|
25768
|
-
case "ForInStatement":
|
|
25769
|
-
case "ForOfStatement": {
|
|
25770
|
-
const head2 = node2.init ?? node2.left;
|
|
25771
|
-
if (head2?.type === "VariableDeclaration" && head2.kind !== "var") {
|
|
25772
|
-
const names = /* @__PURE__ */ new Set();
|
|
25773
|
-
for (const declarator of head2.declarations) {
|
|
25774
|
-
collectPattern2(declarator.id, names);
|
|
25775
|
-
}
|
|
25776
|
-
childScope = { names, parent: scope };
|
|
25777
|
-
}
|
|
25778
|
-
break;
|
|
25779
|
-
}
|
|
25780
|
-
case "MetaProperty":
|
|
25781
|
-
edits.push({ start: node2.start, end: node2.end, text: HELPERS.meta });
|
|
25782
|
-
return;
|
|
25783
|
-
case "ImportExpression": {
|
|
25784
|
-
const argument = node2.source;
|
|
25785
|
-
edits.push({ start: node2.start, end: argument.start, text: `${HELPERS.dynamic}(` });
|
|
25786
|
-
visit(argument, childScope);
|
|
25787
|
-
edits.push({ start: argument.end, end: node2.end, text: ")" });
|
|
25788
|
-
return;
|
|
25789
|
-
}
|
|
25790
|
-
case "Identifier": {
|
|
25791
|
-
const replacement = lookup(node2.name, scope);
|
|
25792
|
-
if (replacement) edits.push({ start: node2.start, end: node2.end, text: replacement });
|
|
25793
|
-
return;
|
|
25794
|
-
}
|
|
25795
|
-
case "MemberExpression":
|
|
25796
|
-
case "MethodDefinition":
|
|
25797
|
-
case "PropertyDefinition":
|
|
25798
|
-
skip = node2.computed ? NOTHING2 : PROPERTY2;
|
|
25799
|
-
break;
|
|
25800
|
-
case "Property": {
|
|
25801
|
-
if (node2.computed) break;
|
|
25802
|
-
if (node2.shorthand) {
|
|
25803
|
-
const value = node2.value;
|
|
25804
|
-
if (value.type === "Identifier") {
|
|
25805
|
-
const replacement = lookup(value.name, scope);
|
|
25806
|
-
if (replacement) {
|
|
25807
|
-
edits.push({ start: value.start, end: value.end, text: `${value.name}: ${replacement}` });
|
|
25808
|
-
return;
|
|
25809
|
-
}
|
|
25810
|
-
}
|
|
25811
|
-
break;
|
|
25812
|
-
}
|
|
25813
|
-
skip = PROPERTY2;
|
|
25814
|
-
break;
|
|
25815
|
-
}
|
|
25816
|
-
case "LabeledStatement":
|
|
25817
|
-
case "BreakStatement":
|
|
25818
|
-
case "ContinueStatement":
|
|
25819
|
-
skip = LABEL2;
|
|
25820
|
-
break;
|
|
25821
|
-
}
|
|
25822
|
-
for (const [key, value] of Object.entries(node2)) {
|
|
25823
|
-
if (key === "type" || key === "start" || key === "end" || skip.includes(key)) continue;
|
|
25824
|
-
if (Array.isArray(value)) {
|
|
25825
|
-
for (const item of value) if (isNode4(item)) visit(item, childScope);
|
|
25826
|
-
} else if (isNode4(value)) {
|
|
25827
|
-
visit(value, childScope);
|
|
25828
|
-
}
|
|
25829
|
-
}
|
|
25830
|
-
}
|
|
25831
|
-
function lookup(name, scope) {
|
|
25832
|
-
for (let current = scope; current; current = current.parent) {
|
|
25833
|
-
if (current.names.has(name)) {
|
|
25834
|
-
return current.parent === null ? importBindings.get(name) ?? null : null;
|
|
25835
|
-
}
|
|
25836
|
-
}
|
|
25837
|
-
return null;
|
|
25838
|
-
}
|
|
26159
|
+
/** True when the last command asked the shell to exit. */
|
|
26160
|
+
get isExiting() {
|
|
26161
|
+
return this.shell.isExiting;
|
|
26162
|
+
}
|
|
26163
|
+
close() {
|
|
26164
|
+
if (this.closed) return;
|
|
26165
|
+
this.closed = true;
|
|
26166
|
+
this.proc.exit(0);
|
|
26167
|
+
this.kernel.procs.remove(this.proc.pid);
|
|
25839
26168
|
}
|
|
25840
|
-
}
|
|
25841
|
-
var JSX_EXTENSION = /\.[jt]sx$/;
|
|
25842
|
-
var JsxParser = Parser$1.extend(jsx());
|
|
25843
|
-
var PARSE_OPTIONS = {
|
|
25844
|
-
ecmaVersion: "latest",
|
|
25845
|
-
sourceType: "module",
|
|
25846
|
-
allowAwaitOutsideFunction: true,
|
|
25847
|
-
allowHashBang: true,
|
|
25848
|
-
allowReturnOutsideFunction: true
|
|
25849
26169
|
};
|
|
25850
|
-
|
|
25851
|
-
|
|
25852
|
-
|
|
25853
|
-
|
|
25854
|
-
|
|
25855
|
-
|
|
25856
|
-
|
|
25857
|
-
|
|
25858
|
-
|
|
25859
|
-
|
|
25860
|
-
|
|
26170
|
+
|
|
26171
|
+
// src/node/node-child-process-bridge.ts
|
|
26172
|
+
var KernelChildProcess = class {
|
|
26173
|
+
pid;
|
|
26174
|
+
command;
|
|
26175
|
+
args;
|
|
26176
|
+
parentPid;
|
|
26177
|
+
state = "running";
|
|
26178
|
+
exitCode;
|
|
26179
|
+
stdout = "";
|
|
26180
|
+
stderr = "";
|
|
26181
|
+
listeners = /* @__PURE__ */ new Map();
|
|
26182
|
+
kernel;
|
|
26183
|
+
cred;
|
|
26184
|
+
cwd;
|
|
26185
|
+
env;
|
|
26186
|
+
stdin = new Pipe();
|
|
26187
|
+
process;
|
|
26188
|
+
started = false;
|
|
26189
|
+
cancelled = false;
|
|
26190
|
+
constructor(kernel, cred, config2, pid) {
|
|
26191
|
+
this.stdin.interactive = true;
|
|
26192
|
+
if (config2.inheritStdio) this.stdin.isTTY = true;
|
|
26193
|
+
if (config2.stdinIgnored) this.stdin.end();
|
|
26194
|
+
this.stdin.onRawMode = (enabled) => this.emit("rawmode", enabled);
|
|
26195
|
+
this.kernel = kernel;
|
|
26196
|
+
this.cred = cred;
|
|
26197
|
+
this.pid = pid;
|
|
26198
|
+
this.command = config2.command;
|
|
26199
|
+
this.args = config2.args?.slice() ?? [];
|
|
26200
|
+
this.parentPid = config2.parentPid;
|
|
26201
|
+
this.cwd = config2.cwd ?? "/";
|
|
26202
|
+
this.env = { ...config2.env };
|
|
26203
|
+
}
|
|
26204
|
+
on(event, listener) {
|
|
26205
|
+
let listeners = this.listeners.get(event);
|
|
26206
|
+
if (!listeners) {
|
|
26207
|
+
listeners = /* @__PURE__ */ new Set();
|
|
26208
|
+
this.listeners.set(event, listeners);
|
|
26209
|
+
}
|
|
26210
|
+
listeners.add(listener);
|
|
26211
|
+
return this;
|
|
25861
26212
|
}
|
|
25862
|
-
|
|
25863
|
-
|
|
25864
|
-
function containsImportMeta(node2) {
|
|
25865
|
-
if (Array.isArray(node2)) return node2.some(containsImportMeta);
|
|
25866
|
-
if (!isNode4(node2)) return false;
|
|
25867
|
-
if (node2.type === "MetaProperty") return true;
|
|
25868
|
-
for (const [key, value] of Object.entries(node2)) {
|
|
25869
|
-
if (key === "type" || key === "start" || key === "end") continue;
|
|
25870
|
-
if (containsImportMeta(value)) return true;
|
|
26213
|
+
emit(event, ...args) {
|
|
26214
|
+
for (const listener of this.listeners.get(event) ?? []) listener(...args);
|
|
25871
26215
|
}
|
|
25872
|
-
|
|
25873
|
-
|
|
25874
|
-
|
|
25875
|
-
|
|
25876
|
-
|
|
25877
|
-
|
|
25878
|
-
|
|
26216
|
+
exec() {
|
|
26217
|
+
if (this.started) return;
|
|
26218
|
+
this.started = true;
|
|
26219
|
+
queueMicrotask(() => {
|
|
26220
|
+
if (this.cancelled) {
|
|
26221
|
+
this.finish(143);
|
|
26222
|
+
return;
|
|
26223
|
+
}
|
|
26224
|
+
const stdout = new ChildOutput(this, "stdout");
|
|
26225
|
+
const stderr = new ChildOutput(this, "stderr");
|
|
26226
|
+
try {
|
|
26227
|
+
this.process = this.kernel.spawn([this.command, ...this.args], {
|
|
26228
|
+
cwd: this.cwd,
|
|
26229
|
+
env: this.env,
|
|
26230
|
+
cred: this.cred,
|
|
26231
|
+
stdin: this.stdin,
|
|
26232
|
+
stdout,
|
|
26233
|
+
stderr,
|
|
26234
|
+
ppid: 1
|
|
26235
|
+
});
|
|
26236
|
+
void this.process.wait().then((code) => {
|
|
26237
|
+
stdout.end();
|
|
26238
|
+
stderr.end();
|
|
26239
|
+
this.finish(code);
|
|
26240
|
+
});
|
|
26241
|
+
} catch (error) {
|
|
26242
|
+
stderr.write(error instanceof Error ? error.message : String(error));
|
|
26243
|
+
stderr.end();
|
|
26244
|
+
stdout.end();
|
|
26245
|
+
this.finish(1);
|
|
26246
|
+
}
|
|
26247
|
+
});
|
|
25879
26248
|
}
|
|
25880
|
-
|
|
25881
|
-
|
|
25882
|
-
|
|
25883
|
-
|
|
25884
|
-
|
|
26249
|
+
sendStdin(data) {
|
|
26250
|
+
try {
|
|
26251
|
+
this.stdin.write(data);
|
|
26252
|
+
} catch {
|
|
26253
|
+
}
|
|
25885
26254
|
}
|
|
25886
|
-
|
|
25887
|
-
|
|
25888
|
-
|
|
25889
|
-
|
|
25890
|
-
|
|
25891
|
-
for (const declarator of declaration.declarations) {
|
|
25892
|
-
collectPattern2(declarator.id, names);
|
|
26255
|
+
/** Signal EOF, so a child reading stdin to the end can finish. */
|
|
26256
|
+
endStdin() {
|
|
26257
|
+
try {
|
|
26258
|
+
this.stdin.end();
|
|
26259
|
+
} catch {
|
|
25893
26260
|
}
|
|
25894
|
-
} else if (isNode4(declaration.id)) {
|
|
25895
|
-
names.add(declaration.id.name);
|
|
25896
26261
|
}
|
|
25897
|
-
|
|
25898
|
-
|
|
25899
|
-
|
|
25900
|
-
|
|
25901
|
-
}
|
|
25902
|
-
function hoistedNames2(body) {
|
|
25903
|
-
const names = blockNames2(body);
|
|
25904
|
-
collectVars2(body, names);
|
|
25905
|
-
return names;
|
|
25906
|
-
}
|
|
25907
|
-
function blockNames2(body) {
|
|
25908
|
-
const names = /* @__PURE__ */ new Set();
|
|
25909
|
-
for (const node2 of body ?? []) {
|
|
25910
|
-
if (node2.type === "VariableDeclaration" && node2.kind !== "var") {
|
|
25911
|
-
for (const declarator of node2.declarations) {
|
|
25912
|
-
collectPattern2(declarator.id, names);
|
|
25913
|
-
}
|
|
25914
|
-
} else if ((node2.type === "ClassDeclaration" || node2.type === "FunctionDeclaration") && isNode4(node2.id)) {
|
|
25915
|
-
names.add(node2.id.name);
|
|
26262
|
+
kill(signal = "SIGTERM") {
|
|
26263
|
+
if (this.process) {
|
|
26264
|
+
this.process.deliver(signal);
|
|
26265
|
+
return;
|
|
25916
26266
|
}
|
|
26267
|
+
this.cancelled = true;
|
|
25917
26268
|
}
|
|
25918
|
-
|
|
25919
|
-
|
|
25920
|
-
|
|
25921
|
-
|
|
25922
|
-
|
|
25923
|
-
return;
|
|
26269
|
+
finish(code) {
|
|
26270
|
+
if (this.state === "exited") return;
|
|
26271
|
+
this.state = "exited";
|
|
26272
|
+
this.exitCode = code;
|
|
26273
|
+
this.emit("exit", code);
|
|
25924
26274
|
}
|
|
25925
|
-
|
|
25926
|
-
|
|
25927
|
-
|
|
25928
|
-
if (isNode4(node2.id)) names.add(node2.id.name);
|
|
25929
|
-
return;
|
|
26275
|
+
append(stream, text2) {
|
|
26276
|
+
this[stream] += text2;
|
|
26277
|
+
this.emit(stream, text2);
|
|
25930
26278
|
}
|
|
25931
|
-
|
|
25932
|
-
|
|
25933
|
-
|
|
25934
|
-
|
|
26279
|
+
};
|
|
26280
|
+
var ChildOutput = class {
|
|
26281
|
+
constructor(child, stream) {
|
|
26282
|
+
this.child = child;
|
|
26283
|
+
this.stream = stream;
|
|
25935
26284
|
}
|
|
25936
|
-
|
|
25937
|
-
|
|
25938
|
-
|
|
26285
|
+
child;
|
|
26286
|
+
stream;
|
|
26287
|
+
isTTY = false;
|
|
26288
|
+
closedState = false;
|
|
26289
|
+
decoder = new TextDecoder();
|
|
26290
|
+
get closed() {
|
|
26291
|
+
return this.closedState;
|
|
26292
|
+
}
|
|
26293
|
+
write(data) {
|
|
26294
|
+
if (this.closedState) return;
|
|
26295
|
+
const text2 = typeof data === "string" ? data : this.decoder.decode(data, { stream: true });
|
|
26296
|
+
if (text2) this.child.append(this.stream, text2);
|
|
26297
|
+
}
|
|
26298
|
+
end() {
|
|
26299
|
+
if (this.closedState) return;
|
|
26300
|
+
this.closedState = true;
|
|
26301
|
+
const tail2 = this.decoder.decode();
|
|
26302
|
+
if (tail2) this.child.append(this.stream, tail2);
|
|
25939
26303
|
}
|
|
26304
|
+
};
|
|
26305
|
+
var nextBridgePid = 1073741824;
|
|
26306
|
+
function installNodeChildProcessBridge(pod, kernel, cred) {
|
|
26307
|
+
const manager = pod.processManager;
|
|
26308
|
+
const originalSpawn = manager.spawn;
|
|
26309
|
+
manager.spawn = (config2) => {
|
|
26310
|
+
const resolved = kernel.resolveExecutable(config2.command, config2.cwd ?? "/", config2.env ?? {}, cred);
|
|
26311
|
+
if (resolved?.kind === "builtin") {
|
|
26312
|
+
return new KernelChildProcess(kernel, cred, config2, nextBridgePid++);
|
|
26313
|
+
}
|
|
26314
|
+
return originalSpawn.call(manager, config2);
|
|
26315
|
+
};
|
|
26316
|
+
return () => {
|
|
26317
|
+
if (manager.spawn === originalSpawn) return;
|
|
26318
|
+
manager.spawn = originalSpawn;
|
|
26319
|
+
};
|
|
25940
26320
|
}
|
|
25941
|
-
|
|
25942
|
-
|
|
25943
|
-
|
|
25944
|
-
|
|
25945
|
-
|
|
25946
|
-
|
|
25947
|
-
|
|
25948
|
-
|
|
25949
|
-
|
|
26321
|
+
|
|
26322
|
+
// src/node/host-module-tracker.ts
|
|
26323
|
+
var HostModuleTracker = class {
|
|
26324
|
+
active = 0;
|
|
26325
|
+
disposed = false;
|
|
26326
|
+
dispose() {
|
|
26327
|
+
this.disposed = true;
|
|
26328
|
+
}
|
|
26329
|
+
wrapped = /* @__PURE__ */ new WeakMap();
|
|
26330
|
+
originals = /* @__PURE__ */ new WeakMap();
|
|
26331
|
+
pending = () => this.active;
|
|
26332
|
+
unwrap = (value) => value && (typeof value === "object" || typeof value === "function") ? this.originals.get(value) ?? value : value;
|
|
26333
|
+
wrap(value) {
|
|
26334
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return value;
|
|
26335
|
+
const object = value;
|
|
26336
|
+
if (Array.isArray(value) || ArrayBuffer.isView(value) || value instanceof ArrayBuffer) return value;
|
|
26337
|
+
if (this.wrapped.has(object)) return this.wrapped.get(object);
|
|
26338
|
+
const tracker = this;
|
|
26339
|
+
const proxy = new Proxy(object, {
|
|
26340
|
+
// CommonJS native loaders re-export by assigning exports back onto the
|
|
26341
|
+
// binding object. Never store a process-owned proxy in a shared module.
|
|
26342
|
+
set(target, key, member) {
|
|
26343
|
+
return Reflect.set(target, key, tracker.unwrap(member), target);
|
|
26344
|
+
},
|
|
26345
|
+
defineProperty(target, key, descriptor) {
|
|
26346
|
+
return Reflect.defineProperty(target, key, "value" in descriptor ? { ...descriptor, value: tracker.unwrap(descriptor.value) } : descriptor);
|
|
26347
|
+
},
|
|
26348
|
+
get(target, key) {
|
|
26349
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
|
|
26350
|
+
const member = Reflect.get(target, key, target);
|
|
26351
|
+
if (descriptor && !descriptor.configurable && "value" in descriptor && !descriptor.writable) return member;
|
|
26352
|
+
return typeof member === "function" ? tracker.wrap(member) : member;
|
|
26353
|
+
},
|
|
26354
|
+
apply(target, receiver, args) {
|
|
26355
|
+
const result = Reflect.apply(target, tracker.unwrap(receiver), args.map(tracker.unwrap));
|
|
26356
|
+
if (result && typeof result.then === "function") {
|
|
26357
|
+
tracker.active++;
|
|
26358
|
+
return Promise.resolve(result).then(
|
|
26359
|
+
(value2) => {
|
|
26360
|
+
tracker.active--;
|
|
26361
|
+
return tracker.disposed ? new Promise(() => {
|
|
26362
|
+
}) : tracker.wrap(value2);
|
|
26363
|
+
},
|
|
26364
|
+
(error) => {
|
|
26365
|
+
tracker.active--;
|
|
26366
|
+
if (tracker.disposed) return new Promise(() => {
|
|
26367
|
+
});
|
|
26368
|
+
throw error;
|
|
26369
|
+
}
|
|
26370
|
+
);
|
|
26371
|
+
}
|
|
26372
|
+
return tracker.wrap(result);
|
|
26373
|
+
},
|
|
26374
|
+
construct(target, args, newTarget) {
|
|
26375
|
+
return tracker.wrap(Reflect.construct(target, args.map(tracker.unwrap), tracker.unwrap(newTarget)));
|
|
25950
26376
|
}
|
|
25951
|
-
|
|
25952
|
-
|
|
25953
|
-
|
|
25954
|
-
|
|
25955
|
-
case "AssignmentPattern":
|
|
25956
|
-
collectPattern2(node2.left, names);
|
|
25957
|
-
return;
|
|
25958
|
-
case "RestElement":
|
|
25959
|
-
collectPattern2(node2.argument, names);
|
|
25960
|
-
return;
|
|
25961
|
-
default:
|
|
25962
|
-
return;
|
|
26377
|
+
});
|
|
26378
|
+
this.wrapped.set(object, proxy);
|
|
26379
|
+
this.originals.set(proxy, object);
|
|
26380
|
+
return proxy;
|
|
25963
26381
|
}
|
|
25964
|
-
}
|
|
25965
|
-
|
|
25966
|
-
|
|
25967
|
-
|
|
25968
|
-
for (const edit of ordered) out = out.slice(0, edit.start) + edit.text + out.slice(edit.end);
|
|
25969
|
-
return out;
|
|
25970
|
-
}
|
|
25971
|
-
function isNode4(value) {
|
|
25972
|
-
return typeof value === "object" && value !== null && typeof value.type === "string";
|
|
25973
|
-
}
|
|
25974
|
-
var NOTHING2 = [];
|
|
25975
|
-
var PROPERTY2 = ["property", "key"];
|
|
25976
|
-
var LABEL2 = ["label"];
|
|
26382
|
+
};
|
|
26383
|
+
|
|
26384
|
+
// src/node/commonjs-engine.ts
|
|
26385
|
+
init_path();
|
|
25977
26386
|
var EXTENSIONS = [".js", ".mjs", ".cjs", ".json", ".node"];
|
|
26387
|
+
var PREFIX_ONLY_BUILTINS = /* @__PURE__ */ new Set(["test", "test/reporters", "sea", "sqlite"]);
|
|
25978
26388
|
var CONDITION_SETS = {
|
|
25979
26389
|
import: [["node", "import", "module", "default"], ["node", "require", "default"], ["default"]],
|
|
25980
26390
|
require: [["node", "require", "default"], ["node", "import", "module", "default"], ["default"]]
|
|
@@ -26314,7 +26724,8 @@ ${code}
|
|
|
26314
26724
|
}
|
|
26315
26725
|
builtin(specifier, importer) {
|
|
26316
26726
|
const name = specifier.replace(/^node:/, "");
|
|
26317
|
-
|
|
26727
|
+
const prefixOnly = PREFIX_ONLY_BUILTINS.has(name) && !specifier.startsWith("node:");
|
|
26728
|
+
if (prefixOnly || !Object.prototype.hasOwnProperty.call(this.builtins, name)) {
|
|
26318
26729
|
return Object.prototype.hasOwnProperty.call(this.overrides, specifier) ? { found: true, value: this.overrides[specifier] } : { found: false, value: void 0 };
|
|
26319
26730
|
}
|
|
26320
26731
|
if (name === "module" && importer) {
|
|
@@ -27584,21 +27995,23 @@ function resolveTarget(input, overrides, defaultProtocol) {
|
|
|
27584
27995
|
};
|
|
27585
27996
|
}
|
|
27586
27997
|
function isLoopback(hostname) {
|
|
27587
|
-
return
|
|
27998
|
+
return isLoopbackHostname(hostname);
|
|
27588
27999
|
}
|
|
27589
28000
|
var VirtualClientRequest = class extends streamModule4.Writable {
|
|
27590
|
-
constructor(target, router, fetchImpl, trackRequest) {
|
|
28001
|
+
constructor(target, router, fetchImpl, trackRequest, loopback = void 0) {
|
|
27591
28002
|
super();
|
|
27592
28003
|
this.target = target;
|
|
27593
28004
|
this.router = router;
|
|
27594
28005
|
this.fetchImpl = fetchImpl;
|
|
27595
28006
|
this.trackRequest = trackRequest;
|
|
28007
|
+
this.loopback = loopback;
|
|
27596
28008
|
for (const [name, value] of Object.entries(target.headers)) this.setHeader(name, value);
|
|
27597
28009
|
}
|
|
27598
28010
|
target;
|
|
27599
28011
|
router;
|
|
27600
28012
|
fetchImpl;
|
|
27601
28013
|
trackRequest;
|
|
28014
|
+
loopback;
|
|
27602
28015
|
socket = socketStub();
|
|
27603
28016
|
connection = this.socket;
|
|
27604
28017
|
chunks = [];
|
|
@@ -27712,7 +28125,9 @@ var VirtualClientRequest = class extends streamModule4.Writable {
|
|
|
27712
28125
|
} catch (error) {
|
|
27713
28126
|
clearTimeout(this.timer);
|
|
27714
28127
|
if (this.destroyedByUser) return;
|
|
27715
|
-
const
|
|
28128
|
+
const thrown = error instanceof Error ? error : new Error(String(error));
|
|
28129
|
+
const cause = thrown.cause;
|
|
28130
|
+
const failure2 = cause instanceof Error && "code" in cause ? cause : thrown;
|
|
27716
28131
|
if (!("code" in failure2)) Object.assign(failure2, { code: "ECONNREFUSED" });
|
|
27717
28132
|
this.emit("error", failure2);
|
|
27718
28133
|
} finally {
|
|
@@ -27720,18 +28135,21 @@ var VirtualClientRequest = class extends streamModule4.Writable {
|
|
|
27720
28135
|
}
|
|
27721
28136
|
}
|
|
27722
28137
|
async viaRouter(body) {
|
|
27723
|
-
|
|
28138
|
+
const init = {
|
|
28139
|
+
method: this.target.method,
|
|
28140
|
+
path: this.target.path,
|
|
28141
|
+
headers: this.getHeaders(),
|
|
28142
|
+
body: body.length ? new Uint8Array(body) : null
|
|
28143
|
+
};
|
|
28144
|
+
const local = this.router.activePortsIncludes(this.target.port);
|
|
28145
|
+
const remote = local || !this.loopback ? null : await this.loopback(this.target.port, init);
|
|
28146
|
+
if (!local && !remote) {
|
|
27724
28147
|
throw Object.assign(
|
|
27725
28148
|
new Error(`connect ECONNREFUSED ${this.target.hostname}:${this.target.port}`),
|
|
27726
28149
|
{ code: "ECONNREFUSED", errno: -61, syscall: "connect", address: this.target.hostname, port: this.target.port }
|
|
27727
28150
|
);
|
|
27728
28151
|
}
|
|
27729
|
-
const result = await this.router.request(this.target.port,
|
|
27730
|
-
method: this.target.method,
|
|
27731
|
-
path: this.target.path,
|
|
27732
|
-
headers: this.getHeaders(),
|
|
27733
|
-
body: body.length ? new Uint8Array(body) : null
|
|
27734
|
-
});
|
|
28152
|
+
const result = remote ?? await this.router.request(this.target.port, init);
|
|
27735
28153
|
const body_ = result.body;
|
|
27736
28154
|
const bytes2 = typeof body_ === "string" ? new TextEncoder().encode(body_) : body_ instanceof ArrayBuffer ? new Uint8Array(body_) : body_ ?? new Uint8Array();
|
|
27737
28155
|
const status = result.statusCode ?? 200;
|
|
@@ -27771,7 +28189,13 @@ function createHttpModule(router, owner, options = {}, defaultProtocol = "http:"
|
|
|
27771
28189
|
const request = (input, second, third) => {
|
|
27772
28190
|
const overrides = second && typeof second === "object" && !(second instanceof Function) ? second : void 0;
|
|
27773
28191
|
const callback = [second, third].find((value) => typeof value === "function");
|
|
27774
|
-
const req = new VirtualClientRequest(
|
|
28192
|
+
const req = new VirtualClientRequest(
|
|
28193
|
+
resolveTarget(input, overrides, defaultProtocol),
|
|
28194
|
+
router,
|
|
28195
|
+
options.fetch,
|
|
28196
|
+
options.trackRequest,
|
|
28197
|
+
options.loopback
|
|
28198
|
+
);
|
|
27775
28199
|
if (callback) req.on("response", callback);
|
|
27776
28200
|
return req;
|
|
27777
28201
|
};
|
|
@@ -27798,6 +28222,62 @@ function createHttpModule(router, owner, options = {}, defaultProtocol = "http:"
|
|
|
27798
28222
|
}
|
|
27799
28223
|
};
|
|
27800
28224
|
}
|
|
28225
|
+
function createVirtualFetch(router, options = {}) {
|
|
28226
|
+
return (async (input, init) => {
|
|
28227
|
+
const request = new Request(input, init);
|
|
28228
|
+
const url = new URL(request.url);
|
|
28229
|
+
const release = options.trackRequest?.();
|
|
28230
|
+
try {
|
|
28231
|
+
if (!isLoopback(url.hostname)) {
|
|
28232
|
+
if (!options.fetch) {
|
|
28233
|
+
throw Object.assign(new TypeError("fetch failed"), {
|
|
28234
|
+
cause: Object.assign(new Error(`getaddrinfo ENOTFOUND ${url.hostname}`), { code: "ENOTFOUND" })
|
|
28235
|
+
});
|
|
28236
|
+
}
|
|
28237
|
+
return await options.fetch(request);
|
|
28238
|
+
}
|
|
28239
|
+
const port = Number(url.port || (url.protocol === "https:" ? 443 : 80));
|
|
28240
|
+
const headers = {};
|
|
28241
|
+
request.headers.forEach((value, key) => {
|
|
28242
|
+
headers[key] = value;
|
|
28243
|
+
});
|
|
28244
|
+
const bodyless = request.method === "GET" || request.method === "HEAD";
|
|
28245
|
+
const loopbackRequest = {
|
|
28246
|
+
method: request.method,
|
|
28247
|
+
path: `${url.pathname}${url.search}`,
|
|
28248
|
+
headers,
|
|
28249
|
+
body: bodyless ? null : new Uint8Array(await request.arrayBuffer())
|
|
28250
|
+
};
|
|
28251
|
+
const result = router.activePortsIncludes(port) ? await router.request(port, loopbackRequest) : await options.loopback?.(port, loopbackRequest) ?? null;
|
|
28252
|
+
if (!result) {
|
|
28253
|
+
throw Object.assign(new TypeError("fetch failed"), {
|
|
28254
|
+
cause: Object.assign(new Error(`connect ECONNREFUSED ${url.hostname}:${port}`), {
|
|
28255
|
+
code: "ECONNREFUSED",
|
|
28256
|
+
errno: -61,
|
|
28257
|
+
syscall: "connect",
|
|
28258
|
+
address: url.hostname,
|
|
28259
|
+
port
|
|
28260
|
+
})
|
|
28261
|
+
});
|
|
28262
|
+
}
|
|
28263
|
+
const status = result.statusCode ?? 200;
|
|
28264
|
+
const responseHeaders = new Headers();
|
|
28265
|
+
for (const [name, value] of Object.entries(result.headers ?? {})) {
|
|
28266
|
+
for (const part of Array.isArray(value) ? value : [value]) responseHeaders.append(name, String(part));
|
|
28267
|
+
}
|
|
28268
|
+
const raw = result.body;
|
|
28269
|
+
const bytes2 = typeof raw === "string" ? new TextEncoder().encode(raw) : raw instanceof ArrayBuffer ? new Uint8Array(raw) : raw ?? new Uint8Array();
|
|
28270
|
+
const nullBody = status === 204 || status === 205 || status === 304 || request.method === "HEAD";
|
|
28271
|
+
return new Response(nullBody ? null : new Uint8Array(bytes2), {
|
|
28272
|
+
status,
|
|
28273
|
+
statusText: result.statusMessage ?? STATUS_CODES[status] ?? "",
|
|
28274
|
+
headers: responseHeaders
|
|
28275
|
+
});
|
|
28276
|
+
} finally {
|
|
28277
|
+
release?.();
|
|
28278
|
+
}
|
|
28279
|
+
});
|
|
28280
|
+
}
|
|
27801
28281
|
function validateHeaderName(name) {
|
|
27802
28282
|
if (!/^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/.test(name)) throw Object.assign(new TypeError(`Header name must be a valid HTTP token [${name}]`), { code: "ERR_INVALID_HTTP_TOKEN" });
|
|
27803
28283
|
}
|
|
@@ -27817,6 +28297,492 @@ function socketStub() {
|
|
|
27817
28297
|
}
|
|
27818
28298
|
var METHODS = ["ACL", "BIND", "CHECKOUT", "CONNECT", "COPY", "DELETE", "GET", "HEAD", "LINK", "LOCK", "M-SEARCH", "MERGE", "MKACTIVITY", "MKCALENDAR", "MKCOL", "MOVE", "NOTIFY", "OPTIONS", "PATCH", "POST", "PROPFIND", "PROPPATCH", "PURGE", "PUT", "REBIND", "REPORT", "SEARCH", "SOURCE", "SUBSCRIBE", "TRACE", "UNBIND", "UNLINK", "UNLOCK", "UNSUBSCRIBE"];
|
|
27819
28299
|
var STATUS_CODES = { 100: "Continue", 200: "OK", 201: "Created", 202: "Accepted", 204: "No Content", 206: "Partial Content", 301: "Moved Permanently", 302: "Found", 304: "Not Modified", 307: "Temporary Redirect", 308: "Permanent Redirect", 400: "Bad Request", 401: "Unauthorized", 403: "Forbidden", 404: "Not Found", 405: "Method Not Allowed", 409: "Conflict", 413: "Payload Too Large", 415: "Unsupported Media Type", 422: "Unprocessable Entity", 429: "Too Many Requests", 500: "Internal Server Error", 501: "Not Implemented", 502: "Bad Gateway", 503: "Service Unavailable" };
|
|
28300
|
+
|
|
28301
|
+
// src/node/test-module.ts
|
|
28302
|
+
function parseArguments(args) {
|
|
28303
|
+
let name = "<anonymous>";
|
|
28304
|
+
let options = {};
|
|
28305
|
+
let fn;
|
|
28306
|
+
for (const arg of args) {
|
|
28307
|
+
if (typeof arg === "string") name = arg;
|
|
28308
|
+
else if (typeof arg === "function") {
|
|
28309
|
+
fn = arg;
|
|
28310
|
+
if (name === "<anonymous>" && arg.name) name = arg.name;
|
|
28311
|
+
} else if (arg && typeof arg === "object") options = arg;
|
|
28312
|
+
}
|
|
28313
|
+
return { name, options, fn };
|
|
28314
|
+
}
|
|
28315
|
+
function errorText(error) {
|
|
28316
|
+
if (error instanceof Error) {
|
|
28317
|
+
const stack = error.stack ?? `${error.name}: ${error.message}`;
|
|
28318
|
+
return stack.includes(error.message) ? stack : `${error.name}: ${error.message}
|
|
28319
|
+
${stack}`;
|
|
28320
|
+
}
|
|
28321
|
+
return String(error);
|
|
28322
|
+
}
|
|
28323
|
+
function indent(text2, spaces) {
|
|
28324
|
+
const pad2 = " ".repeat(spaces);
|
|
28325
|
+
return text2.split("\n").map((line) => line ? pad2 + line : line).join("\n");
|
|
28326
|
+
}
|
|
28327
|
+
function duration(started) {
|
|
28328
|
+
return (performance.now() - started).toFixed(6).replace(/\.?0+$/, "");
|
|
28329
|
+
}
|
|
28330
|
+
function invoke(host2, fn, context, timeout) {
|
|
28331
|
+
const body = new Promise((resolve3, reject) => {
|
|
28332
|
+
if (fn.length >= 2) {
|
|
28333
|
+
let settled = false;
|
|
28334
|
+
const done = (error) => {
|
|
28335
|
+
if (settled) return;
|
|
28336
|
+
settled = true;
|
|
28337
|
+
if (error) reject(error);
|
|
28338
|
+
else resolve3();
|
|
28339
|
+
};
|
|
28340
|
+
try {
|
|
28341
|
+
const returned = fn(context, done);
|
|
28342
|
+
if (returned && typeof returned.then === "function") {
|
|
28343
|
+
reject(new Error("passed a callback but also returned a Promise"));
|
|
28344
|
+
}
|
|
28345
|
+
} catch (error) {
|
|
28346
|
+
done(error);
|
|
28347
|
+
}
|
|
28348
|
+
return;
|
|
28349
|
+
}
|
|
28350
|
+
try {
|
|
28351
|
+
Promise.resolve(fn(context)).then(() => resolve3(), reject);
|
|
28352
|
+
} catch (error) {
|
|
28353
|
+
reject(error);
|
|
28354
|
+
}
|
|
28355
|
+
});
|
|
28356
|
+
if (timeout === void 0 || !Number.isFinite(timeout)) return body;
|
|
28357
|
+
return new Promise((resolve3, reject) => {
|
|
28358
|
+
const timer = host2.setTimeout(() => reject(new Error(`test timed out after ${timeout}ms`)), timeout);
|
|
28359
|
+
body.then(
|
|
28360
|
+
() => {
|
|
28361
|
+
host2.clearTimeout(timer);
|
|
28362
|
+
resolve3();
|
|
28363
|
+
},
|
|
28364
|
+
(error) => {
|
|
28365
|
+
host2.clearTimeout(timer);
|
|
28366
|
+
reject(error);
|
|
28367
|
+
}
|
|
28368
|
+
);
|
|
28369
|
+
});
|
|
28370
|
+
}
|
|
28371
|
+
function createMockTracker() {
|
|
28372
|
+
const restorers = [];
|
|
28373
|
+
const fn = (original = () => void 0, implementation = original) => {
|
|
28374
|
+
let current = implementation;
|
|
28375
|
+
const once = /* @__PURE__ */ new Map();
|
|
28376
|
+
const calls = [];
|
|
28377
|
+
const mocked = function(...args) {
|
|
28378
|
+
const index = calls.length;
|
|
28379
|
+
const chosen = once.get(index) ?? current;
|
|
28380
|
+
once.delete(index);
|
|
28381
|
+
const call = { arguments: args, result: void 0, error: void 0, this: this };
|
|
28382
|
+
calls.push(call);
|
|
28383
|
+
try {
|
|
28384
|
+
call.result = chosen.apply(this, args);
|
|
28385
|
+
return call.result;
|
|
28386
|
+
} catch (error) {
|
|
28387
|
+
call.error = error;
|
|
28388
|
+
throw error;
|
|
28389
|
+
}
|
|
28390
|
+
};
|
|
28391
|
+
Object.defineProperty(mocked, "mock", {
|
|
28392
|
+
value: {
|
|
28393
|
+
calls,
|
|
28394
|
+
callCount: () => calls.length,
|
|
28395
|
+
resetCalls: () => {
|
|
28396
|
+
calls.length = 0;
|
|
28397
|
+
},
|
|
28398
|
+
mockImplementation: (next) => {
|
|
28399
|
+
current = next;
|
|
28400
|
+
},
|
|
28401
|
+
mockImplementationOnce: (next, onCall) => {
|
|
28402
|
+
once.set(onCall ?? calls.length, next);
|
|
28403
|
+
},
|
|
28404
|
+
restore: () => {
|
|
28405
|
+
current = original;
|
|
28406
|
+
}
|
|
28407
|
+
}
|
|
28408
|
+
});
|
|
28409
|
+
return mocked;
|
|
28410
|
+
};
|
|
28411
|
+
const method = (object, name, implementation) => {
|
|
28412
|
+
const original = object[name];
|
|
28413
|
+
if (typeof original !== "function") {
|
|
28414
|
+
throw new TypeError(`The property '${name}' is not a function and cannot be mocked`);
|
|
28415
|
+
}
|
|
28416
|
+
const mocked = fn(original, implementation ?? original);
|
|
28417
|
+
object[name] = mocked;
|
|
28418
|
+
const restore = () => {
|
|
28419
|
+
object[name] = original;
|
|
28420
|
+
};
|
|
28421
|
+
mocked.mock.restore = restore;
|
|
28422
|
+
restorers.push(restore);
|
|
28423
|
+
return mocked;
|
|
28424
|
+
};
|
|
28425
|
+
return {
|
|
28426
|
+
fn,
|
|
28427
|
+
method,
|
|
28428
|
+
reset: () => {
|
|
28429
|
+
for (const restore of restorers.splice(0)) restore();
|
|
28430
|
+
},
|
|
28431
|
+
restoreAll: () => {
|
|
28432
|
+
for (const restore of restorers.splice(0)) restore();
|
|
28433
|
+
}
|
|
28434
|
+
};
|
|
28435
|
+
}
|
|
28436
|
+
function createTestModule(host2) {
|
|
28437
|
+
const root = {
|
|
28438
|
+
kind: "suite",
|
|
28439
|
+
name: "",
|
|
28440
|
+
options: {},
|
|
28441
|
+
parent: null,
|
|
28442
|
+
children: [],
|
|
28443
|
+
hooks: { before: [], after: [], beforeEach: [], afterEach: [] }
|
|
28444
|
+
};
|
|
28445
|
+
let collecting = root;
|
|
28446
|
+
let scheduled = false;
|
|
28447
|
+
let running = null;
|
|
28448
|
+
const mock = createMockTracker();
|
|
28449
|
+
const counts = { tests: 0, suites: 0, pass: 0, fail: 0, cancelled: 0, skipped: 0, todo: 0 };
|
|
28450
|
+
const failures = [];
|
|
28451
|
+
let tapIndex = 0;
|
|
28452
|
+
let onlyWarned = false;
|
|
28453
|
+
const settings = () => host2.settings();
|
|
28454
|
+
const tap = () => settings().reporter === "tap";
|
|
28455
|
+
const schedule = () => {
|
|
28456
|
+
if (scheduled) return;
|
|
28457
|
+
scheduled = true;
|
|
28458
|
+
host2.setTimeout(() => {
|
|
28459
|
+
running = runAll();
|
|
28460
|
+
}, 0);
|
|
28461
|
+
};
|
|
28462
|
+
const fullName = (node2) => {
|
|
28463
|
+
const parts = [];
|
|
28464
|
+
let cursor = node2;
|
|
28465
|
+
while (cursor && cursor !== root) {
|
|
28466
|
+
parts.unshift(cursor.name);
|
|
28467
|
+
cursor = cursor.parent;
|
|
28468
|
+
}
|
|
28469
|
+
return parts.join(" ");
|
|
28470
|
+
};
|
|
28471
|
+
const matchesPattern2 = (name) => {
|
|
28472
|
+
const patterns = settings().namePatterns ?? [];
|
|
28473
|
+
if (patterns.length === 0) return true;
|
|
28474
|
+
return patterns.some((pattern) => {
|
|
28475
|
+
try {
|
|
28476
|
+
return new RegExp(pattern).test(name);
|
|
28477
|
+
} catch {
|
|
28478
|
+
return name.includes(pattern);
|
|
28479
|
+
}
|
|
28480
|
+
});
|
|
28481
|
+
};
|
|
28482
|
+
const hasOnly = (node2) => Boolean(node2.options.only) || node2.kind === "suite" && node2.children.some(hasOnly);
|
|
28483
|
+
const report = (depth, outcome, name, started, detail) => {
|
|
28484
|
+
if (tap()) {
|
|
28485
|
+
tapIndex += 1;
|
|
28486
|
+
const ok2 = outcome === "fail" ? "not ok" : "ok";
|
|
28487
|
+
const directive = outcome === "skip" ? " # SKIP" : outcome === "todo" ? " # TODO" : outcome === "cancelled" ? " # CANCELLED" : "";
|
|
28488
|
+
host2.write(`${ok2} ${tapIndex} - ${name}${directive}
|
|
28489
|
+
`);
|
|
28490
|
+
host2.write(` ---
|
|
28491
|
+
duration_ms: ${duration(started)}
|
|
28492
|
+
`);
|
|
28493
|
+
if (detail) host2.write(` error: |-
|
|
28494
|
+
${indent(detail, 4)}
|
|
28495
|
+
`);
|
|
28496
|
+
host2.write(" ...\n");
|
|
28497
|
+
return;
|
|
28498
|
+
}
|
|
28499
|
+
const pad2 = " ".repeat(depth);
|
|
28500
|
+
const mark = outcome === "pass" ? "\u2714" : outcome === "fail" ? "\u2716" : outcome === "cancelled" ? "\u2716" : "\uFE63";
|
|
28501
|
+
const suffix = outcome === "skip" ? " # SKIP" : outcome === "todo" ? " # TODO" : "";
|
|
28502
|
+
host2.write(`${pad2}${mark} ${name} (${duration(started)}ms)${suffix}
|
|
28503
|
+
`);
|
|
28504
|
+
if (detail) host2.write(`${indent(detail, depth * 2 + 2)}
|
|
28505
|
+
`);
|
|
28506
|
+
};
|
|
28507
|
+
const record = (outcome, name, error) => {
|
|
28508
|
+
counts.tests += 1;
|
|
28509
|
+
if (outcome === "pass") counts.pass += 1;
|
|
28510
|
+
else if (outcome === "fail") {
|
|
28511
|
+
counts.fail += 1;
|
|
28512
|
+
failures.push({ name, error });
|
|
28513
|
+
} else if (outcome === "cancelled") {
|
|
28514
|
+
counts.cancelled += 1;
|
|
28515
|
+
failures.push({ name, error });
|
|
28516
|
+
} else if (outcome === "skip") counts.skipped += 1;
|
|
28517
|
+
else counts.todo += 1;
|
|
28518
|
+
};
|
|
28519
|
+
const ancestors = (suite) => {
|
|
28520
|
+
const chain = [];
|
|
28521
|
+
for (let cursor = suite; cursor; cursor = cursor.parent) chain.unshift(cursor);
|
|
28522
|
+
return chain;
|
|
28523
|
+
};
|
|
28524
|
+
const runTest = async (name, display, options, fn, depth, suite, extraHooks, runOnly) => {
|
|
28525
|
+
const started = performance.now();
|
|
28526
|
+
if (!matchesPattern2(display)) return true;
|
|
28527
|
+
if (runOnly && !options.only) return true;
|
|
28528
|
+
if (options.skip) {
|
|
28529
|
+
record("skip", display);
|
|
28530
|
+
report(depth, "skip", name, started);
|
|
28531
|
+
return true;
|
|
28532
|
+
}
|
|
28533
|
+
if (!fn) {
|
|
28534
|
+
const outcome = options.todo ? "todo" : "skip";
|
|
28535
|
+
record(outcome, display);
|
|
28536
|
+
report(depth, outcome, name, started);
|
|
28537
|
+
return true;
|
|
28538
|
+
}
|
|
28539
|
+
const controller = new AbortController();
|
|
28540
|
+
const subtests = [];
|
|
28541
|
+
const ownHooks = { before: [], after: [], beforeEach: [], afterEach: [] };
|
|
28542
|
+
let skipped = false;
|
|
28543
|
+
let todo = options.todo ?? false;
|
|
28544
|
+
const context = {
|
|
28545
|
+
name,
|
|
28546
|
+
fullName: display,
|
|
28547
|
+
signal: controller.signal,
|
|
28548
|
+
mock,
|
|
28549
|
+
test: (...args) => {
|
|
28550
|
+
const sub = parseArguments(args);
|
|
28551
|
+
const promise = runTest(
|
|
28552
|
+
sub.name,
|
|
28553
|
+
`${display} ${sub.name}`,
|
|
28554
|
+
sub.options,
|
|
28555
|
+
sub.fn,
|
|
28556
|
+
depth + 1,
|
|
28557
|
+
suite,
|
|
28558
|
+
ownHooks,
|
|
28559
|
+
false
|
|
28560
|
+
);
|
|
28561
|
+
subtests.push(promise);
|
|
28562
|
+
return promise.then(() => void 0);
|
|
28563
|
+
},
|
|
28564
|
+
skip: (message) => {
|
|
28565
|
+
skipped = message ?? true;
|
|
28566
|
+
},
|
|
28567
|
+
todo: (message) => {
|
|
28568
|
+
todo = message ?? true;
|
|
28569
|
+
},
|
|
28570
|
+
diagnostic: (message) => {
|
|
28571
|
+
host2.write(tap() ? `# ${message}
|
|
28572
|
+
` : `${" ".repeat(depth + 1)}\u2139 ${message}
|
|
28573
|
+
`);
|
|
28574
|
+
},
|
|
28575
|
+
plan: () => {
|
|
28576
|
+
},
|
|
28577
|
+
before: (hook2) => ownHooks.before.push(hook2),
|
|
28578
|
+
after: (hook2) => ownHooks.after.push(hook2),
|
|
28579
|
+
beforeEach: (hook2) => ownHooks.beforeEach.push(hook2),
|
|
28580
|
+
afterEach: (hook2) => ownHooks.afterEach.push(hook2)
|
|
28581
|
+
};
|
|
28582
|
+
let error;
|
|
28583
|
+
try {
|
|
28584
|
+
const chain = ancestors(suite);
|
|
28585
|
+
for (const level of chain) for (const hook2 of level.hooks.beforeEach) await invoke(host2, hook2, context, void 0);
|
|
28586
|
+
for (const hook2 of extraHooks.beforeEach) await invoke(host2, hook2, context, void 0);
|
|
28587
|
+
await invoke(host2, fn, context, options.timeout);
|
|
28588
|
+
const results = await Promise.all(subtests);
|
|
28589
|
+
for (const hook2 of ownHooks.after) await invoke(host2, hook2, context, void 0);
|
|
28590
|
+
if (results.includes(false)) error = new Error(`${results.filter((ok2) => !ok2).length} subtest(s) failed`);
|
|
28591
|
+
for (const hook2 of extraHooks.afterEach) await invoke(host2, hook2, context, void 0);
|
|
28592
|
+
for (const level of [...chain].reverse()) for (const hook2 of level.hooks.afterEach) await invoke(host2, hook2, context, void 0);
|
|
28593
|
+
} catch (caught) {
|
|
28594
|
+
error = caught;
|
|
28595
|
+
} finally {
|
|
28596
|
+
controller.abort();
|
|
28597
|
+
}
|
|
28598
|
+
if (skipped) {
|
|
28599
|
+
record("skip", display);
|
|
28600
|
+
report(depth, "skip", name, started);
|
|
28601
|
+
return true;
|
|
28602
|
+
}
|
|
28603
|
+
if (error !== void 0) {
|
|
28604
|
+
if (todo) {
|
|
28605
|
+
record("todo", display);
|
|
28606
|
+
report(depth, "todo", name, started);
|
|
28607
|
+
return true;
|
|
28608
|
+
}
|
|
28609
|
+
record("fail", display, error);
|
|
28610
|
+
report(depth, "fail", name, started, errorText(error));
|
|
28611
|
+
return false;
|
|
28612
|
+
}
|
|
28613
|
+
record(todo ? "todo" : "pass", display);
|
|
28614
|
+
report(depth, todo ? "todo" : "pass", name, started);
|
|
28615
|
+
return true;
|
|
28616
|
+
};
|
|
28617
|
+
const runSuite = async (suite, depth, runOnly) => {
|
|
28618
|
+
const started = performance.now();
|
|
28619
|
+
const display = fullName(suite);
|
|
28620
|
+
const isRoot = suite === root;
|
|
28621
|
+
if (!isRoot) {
|
|
28622
|
+
counts.suites += 1;
|
|
28623
|
+
if (tap()) host2.write(`# Subtest: ${suite.name}
|
|
28624
|
+
`);
|
|
28625
|
+
else host2.write(`${" ".repeat(depth)}\u25B6 ${suite.name}
|
|
28626
|
+
`);
|
|
28627
|
+
if (suite.options.skip) {
|
|
28628
|
+
for (const child of suite.children) if (child.kind === "test") record("skip", fullName(child));
|
|
28629
|
+
report(depth, "skip", suite.name, started);
|
|
28630
|
+
return true;
|
|
28631
|
+
}
|
|
28632
|
+
}
|
|
28633
|
+
const context = { name: suite.name, signal: new AbortController().signal };
|
|
28634
|
+
let ok2 = true;
|
|
28635
|
+
try {
|
|
28636
|
+
for (const hook2 of suite.hooks.before) await invoke(host2, hook2, context, void 0);
|
|
28637
|
+
} catch (error) {
|
|
28638
|
+
for (const child of suite.children) {
|
|
28639
|
+
if (child.kind === "test") {
|
|
28640
|
+
record("cancelled", fullName(child), error);
|
|
28641
|
+
report(depth + (isRoot ? 0 : 1), "cancelled", child.name, started, errorText(error));
|
|
28642
|
+
}
|
|
28643
|
+
}
|
|
28644
|
+
if (!isRoot) report(depth, "fail", suite.name, started);
|
|
28645
|
+
return false;
|
|
28646
|
+
}
|
|
28647
|
+
const only = runOnly || settings().only === true && suite.children.some(hasOnly);
|
|
28648
|
+
for (const child of suite.children) {
|
|
28649
|
+
const childDepth = depth + (isRoot ? 0 : 1);
|
|
28650
|
+
if (child.kind === "suite") {
|
|
28651
|
+
if (only && !hasOnly(child) && !child.options.only) continue;
|
|
28652
|
+
ok2 = await runSuite(child, childDepth, only && !child.options.only) && ok2;
|
|
28653
|
+
} else {
|
|
28654
|
+
ok2 = await runTest(
|
|
28655
|
+
child.name,
|
|
28656
|
+
fullName(child),
|
|
28657
|
+
child.options,
|
|
28658
|
+
child.fn,
|
|
28659
|
+
childDepth,
|
|
28660
|
+
suite,
|
|
28661
|
+
{ before: [], after: [], beforeEach: [], afterEach: [] },
|
|
28662
|
+
only
|
|
28663
|
+
) && ok2;
|
|
28664
|
+
}
|
|
28665
|
+
}
|
|
28666
|
+
try {
|
|
28667
|
+
for (const hook2 of suite.hooks.after) await invoke(host2, hook2, context, void 0);
|
|
28668
|
+
} catch (error) {
|
|
28669
|
+
ok2 = false;
|
|
28670
|
+
failures.push({ name: `${display || "<root>"} (after hook)`, error });
|
|
28671
|
+
host2.write(`${indent(`\u2716 after hook failed
|
|
28672
|
+
${errorText(error)}`, depth * 2)}
|
|
28673
|
+
`);
|
|
28674
|
+
}
|
|
28675
|
+
if (!isRoot) {
|
|
28676
|
+
if (tap()) host2.write(`${ok2 ? "ok" : "not ok"} ${++tapIndex} - ${suite.name}
|
|
28677
|
+
`);
|
|
28678
|
+
else host2.write(`${" ".repeat(depth)}${ok2 ? "\u25B6" : "\u2716"} ${suite.name} (${duration(started)}ms)
|
|
28679
|
+
`);
|
|
28680
|
+
}
|
|
28681
|
+
return ok2;
|
|
28682
|
+
};
|
|
28683
|
+
const runAll = async () => {
|
|
28684
|
+
const release = host2.keepAlive();
|
|
28685
|
+
const started = performance.now();
|
|
28686
|
+
if (tap()) host2.write("TAP version 13\n");
|
|
28687
|
+
if (!settings().only && !onlyWarned && root.children.some(hasOnly)) {
|
|
28688
|
+
onlyWarned = true;
|
|
28689
|
+
host2.write("\u2139 'only' and 'runOnly' require the --test-only command-line option.\n");
|
|
28690
|
+
}
|
|
28691
|
+
let ok2 = true;
|
|
28692
|
+
try {
|
|
28693
|
+
ok2 = await runSuite(root, 0, false);
|
|
28694
|
+
} catch (error) {
|
|
28695
|
+
ok2 = false;
|
|
28696
|
+
failures.push({ name: "<test runner>", error });
|
|
28697
|
+
}
|
|
28698
|
+
mock.restoreAll();
|
|
28699
|
+
if (tap()) {
|
|
28700
|
+
host2.write(`1..${tapIndex}
|
|
28701
|
+
`);
|
|
28702
|
+
for (const [key, value] of Object.entries(counts)) host2.write(`# ${key} ${value}
|
|
28703
|
+
`);
|
|
28704
|
+
host2.write(`# duration_ms ${duration(started)}
|
|
28705
|
+
`);
|
|
28706
|
+
} else {
|
|
28707
|
+
for (const [key, value] of Object.entries(counts)) host2.write(`\u2139 ${key} ${value}
|
|
28708
|
+
`);
|
|
28709
|
+
host2.write(`\u2139 duration_ms ${duration(started)}
|
|
28710
|
+
`);
|
|
28711
|
+
if (failures.length > 0) {
|
|
28712
|
+
host2.write("\n\u2716 failing tests:\n\n");
|
|
28713
|
+
for (const failure2 of failures) host2.write(`test at ${failure2.name}
|
|
28714
|
+
${indent(errorText(failure2.error), 2)}
|
|
28715
|
+
|
|
28716
|
+
`);
|
|
28717
|
+
}
|
|
28718
|
+
}
|
|
28719
|
+
release();
|
|
28720
|
+
host2.exit(ok2 && counts.fail === 0 && counts.cancelled === 0 ? 0 : 1);
|
|
28721
|
+
};
|
|
28722
|
+
const declareTest = (extra) => (...args) => {
|
|
28723
|
+
const { name, options, fn } = parseArguments(args);
|
|
28724
|
+
if (running && collecting === root && scheduled) {
|
|
28725
|
+
host2.write(`\u2716 test "${name}" was declared after the run started and did not run
|
|
28726
|
+
`);
|
|
28727
|
+
return Promise.resolve();
|
|
28728
|
+
}
|
|
28729
|
+
collecting.children.push({ kind: "test", name, options: { ...options, ...extra }, parent: collecting, fn });
|
|
28730
|
+
schedule();
|
|
28731
|
+
return Promise.resolve();
|
|
28732
|
+
};
|
|
28733
|
+
const declareSuite = (extra) => (...args) => {
|
|
28734
|
+
const { name, options, fn } = parseArguments(args);
|
|
28735
|
+
const suite = {
|
|
28736
|
+
kind: "suite",
|
|
28737
|
+
name,
|
|
28738
|
+
options: { ...options, ...extra },
|
|
28739
|
+
parent: collecting,
|
|
28740
|
+
children: [],
|
|
28741
|
+
hooks: { before: [], after: [], beforeEach: [], afterEach: [] }
|
|
28742
|
+
};
|
|
28743
|
+
collecting.children.push(suite);
|
|
28744
|
+
schedule();
|
|
28745
|
+
const previous = collecting;
|
|
28746
|
+
collecting = suite;
|
|
28747
|
+
try {
|
|
28748
|
+
fn?.({ name, signal: new AbortController().signal });
|
|
28749
|
+
} finally {
|
|
28750
|
+
collecting = previous;
|
|
28751
|
+
}
|
|
28752
|
+
return Promise.resolve();
|
|
28753
|
+
};
|
|
28754
|
+
const withModifiers = (make) => {
|
|
28755
|
+
const base2 = make({});
|
|
28756
|
+
base2.skip = make({ skip: true });
|
|
28757
|
+
base2.todo = make({ todo: true });
|
|
28758
|
+
base2.only = make({ only: true });
|
|
28759
|
+
return base2;
|
|
28760
|
+
};
|
|
28761
|
+
const test = withModifiers(declareTest);
|
|
28762
|
+
const describe2 = withModifiers(declareSuite);
|
|
28763
|
+
const hook = (kind) => (fn) => {
|
|
28764
|
+
collecting.hooks[kind].push(fn);
|
|
28765
|
+
schedule();
|
|
28766
|
+
};
|
|
28767
|
+
Object.assign(test, {
|
|
28768
|
+
test,
|
|
28769
|
+
it: test,
|
|
28770
|
+
describe: describe2,
|
|
28771
|
+
suite: describe2,
|
|
28772
|
+
before: hook("before"),
|
|
28773
|
+
after: hook("after"),
|
|
28774
|
+
beforeEach: hook("beforeEach"),
|
|
28775
|
+
afterEach: hook("afterEach"),
|
|
28776
|
+
mock,
|
|
28777
|
+
run: () => {
|
|
28778
|
+
throw Object.assign(new Error("node:test run() is not available in this container; use `node --test`"), {
|
|
28779
|
+
code: "ERR_FEATURE_UNAVAILABLE_ON_PLATFORM"
|
|
28780
|
+
});
|
|
28781
|
+
}
|
|
28782
|
+
});
|
|
28783
|
+
Object.defineProperty(test, "default", { value: test, enumerable: false });
|
|
28784
|
+
return test;
|
|
28785
|
+
}
|
|
27820
28786
|
var hashes = { md5, sha1: sha1$1, "sha-1": sha1$1, sha224, "sha-224": sha224, sha256: sha256, "sha-256": sha256, sha384, "sha-384": sha384, sha512: sha512, "sha-512": sha512 };
|
|
27821
28787
|
function createCryptoModule() {
|
|
27822
28788
|
const cryptoObject = globalThis.crypto;
|
|
@@ -28773,7 +29739,7 @@ function createCoreModules(options) {
|
|
|
28773
29739
|
});
|
|
28774
29740
|
const stderrWrite = options.stderr ?? (() => {
|
|
28775
29741
|
});
|
|
28776
|
-
const timers = createTrackedTimers();
|
|
29742
|
+
const timers = createTrackedTimers((error) => reportUncaught(error));
|
|
28777
29743
|
const processObject = Object.assign(new EventEmitter4(), processShim, {
|
|
28778
29744
|
argv: options.argv?.slice() ?? ["/usr/bin/node"],
|
|
28779
29745
|
argv0: "node",
|
|
@@ -28803,16 +29769,65 @@ function createCoreModules(options) {
|
|
|
28803
29769
|
uptime: () => performance.now() / 1e3,
|
|
28804
29770
|
memoryUsage: () => ({ rss: 0, heapTotal: 0, heapUsed: 0, external: 0, arrayBuffers: 0 }),
|
|
28805
29771
|
cpuUsage: () => ({ user: 0, system: 0 }),
|
|
28806
|
-
|
|
28807
|
-
|
|
28808
|
-
|
|
28809
|
-
|
|
29772
|
+
/* A bare `process.exit()` ends with `process.exitCode`, as in Node. */
|
|
29773
|
+
exit: (code) => {
|
|
29774
|
+
const status = normalizeExitCode(code ?? processObject.exitCode);
|
|
29775
|
+
exitCode = status;
|
|
29776
|
+
processObject.exitCode = status;
|
|
29777
|
+
emitExit(status);
|
|
29778
|
+
options.onExit?.(status);
|
|
29779
|
+
},
|
|
29780
|
+
nextTick: (fn, ...args) => {
|
|
29781
|
+
queueMicrotask(() => {
|
|
29782
|
+
try {
|
|
29783
|
+
fn(...args);
|
|
29784
|
+
} catch (error) {
|
|
29785
|
+
reportUncaught(error);
|
|
29786
|
+
}
|
|
29787
|
+
});
|
|
28810
29788
|
},
|
|
28811
29789
|
kill: () => true
|
|
28812
29790
|
});
|
|
29791
|
+
for (const method of EVENT_EMITTER_METHODS) {
|
|
29792
|
+
const implementation = EventEmitter4.prototype[method];
|
|
29793
|
+
if (typeof implementation === "function") processObject[method] = implementation;
|
|
29794
|
+
}
|
|
28813
29795
|
const tty = options.tty === true;
|
|
28814
29796
|
processObject.stdout = makeOutputStream(stdoutWrite, 1, tty);
|
|
28815
29797
|
processObject.stderr = makeOutputStream(stderrWrite, 2, tty);
|
|
29798
|
+
let exiting = false;
|
|
29799
|
+
const emitExit = (status) => {
|
|
29800
|
+
if (exiting) return;
|
|
29801
|
+
exiting = true;
|
|
29802
|
+
try {
|
|
29803
|
+
processObject.emit("exit", status);
|
|
29804
|
+
} catch {
|
|
29805
|
+
}
|
|
29806
|
+
};
|
|
29807
|
+
const reportUncaught = (error, origin = "uncaughtException") => {
|
|
29808
|
+
if (!exiting && processObject.listenerCount(origin) > 0) {
|
|
29809
|
+
try {
|
|
29810
|
+
processObject.emit(origin, error, origin === "uncaughtException" ? origin : void 0);
|
|
29811
|
+
return;
|
|
29812
|
+
} catch (handlerError) {
|
|
29813
|
+
error = handlerError;
|
|
29814
|
+
}
|
|
29815
|
+
}
|
|
29816
|
+
stderrWrite(formatUncaught(error));
|
|
29817
|
+
try {
|
|
29818
|
+
processObject.exit(1);
|
|
29819
|
+
} catch {
|
|
29820
|
+
}
|
|
29821
|
+
};
|
|
29822
|
+
const defer = (fn) => {
|
|
29823
|
+
queueMicrotask(() => {
|
|
29824
|
+
try {
|
|
29825
|
+
fn();
|
|
29826
|
+
} catch (error) {
|
|
29827
|
+
reportUncaught(error);
|
|
29828
|
+
}
|
|
29829
|
+
});
|
|
29830
|
+
};
|
|
28816
29831
|
const stdin = options.interactiveStdin ? new streamModule4.PassThrough() : new streamModule4.Readable({ read() {
|
|
28817
29832
|
this.push(null);
|
|
28818
29833
|
} });
|
|
@@ -28832,7 +29847,7 @@ function createCoreModules(options) {
|
|
|
28832
29847
|
});
|
|
28833
29848
|
processObject.stdin = stdin;
|
|
28834
29849
|
Reflect.deleteProperty(processObject, "browser");
|
|
28835
|
-
const fs = createFsModule(volume, () => cwd, options.stdinPath);
|
|
29850
|
+
const fs = createFsModule(volume, () => cwd, options.stdinPath, defer);
|
|
28836
29851
|
const path = createPathModule(() => cwd);
|
|
28837
29852
|
const consoleObject = new Console(stdoutWrite, stderrWrite);
|
|
28838
29853
|
const os = createOsModule();
|
|
@@ -28845,20 +29860,24 @@ function createCoreModules(options) {
|
|
|
28845
29860
|
}
|
|
28846
29861
|
};
|
|
28847
29862
|
let inFlightRequests = 0;
|
|
29863
|
+
const trackRequest = () => {
|
|
29864
|
+
inFlightRequests++;
|
|
29865
|
+
return () => {
|
|
29866
|
+
inFlightRequests--;
|
|
29867
|
+
};
|
|
29868
|
+
};
|
|
29869
|
+
const ambientFetch = options.http?.fetch ?? (typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0);
|
|
29870
|
+
const outboundFetch = options.http?.policy && ambientFetch ? policedFetch(options.http.policy, ambientFetch) : ambientFetch;
|
|
28848
29871
|
const httpOptions = {
|
|
28849
|
-
...
|
|
28850
|
-
|
|
28851
|
-
|
|
28852
|
-
return () => {
|
|
28853
|
-
inFlightRequests--;
|
|
28854
|
-
};
|
|
28855
|
-
}
|
|
29872
|
+
...outboundFetch ? { fetch: outboundFetch } : {},
|
|
29873
|
+
...options.http?.loopback ? { loopback: options.http.loopback } : {},
|
|
29874
|
+
trackRequest
|
|
28856
29875
|
};
|
|
28857
29876
|
const http = options.http ? createHttpModule(options.http.router, options.http.owner, httpOptions, "http:") : createUnsupportedModule("http");
|
|
28858
29877
|
const https = options.http ? createHttpModule(options.http.router, options.http.owner, httpOptions, "https:") : createUnsupportedModule("https");
|
|
28859
29878
|
const childProcess = options.spawnChild ? createChildProcessModule(options.spawnChild, () => cwd, options.syncSpawn, () => ({ ...processObject.env })) : createUnsupportedModule("child_process");
|
|
28860
29879
|
const readline = createReadlineModule(() => processObject.stdin, () => processObject.stdout);
|
|
28861
|
-
const dns = createDnsModule();
|
|
29880
|
+
const dns = createDnsModule(defer);
|
|
28862
29881
|
const builtins = {
|
|
28863
29882
|
assert: assert_module_default,
|
|
28864
29883
|
"assert/strict": assert_module_default.strict ?? assert_module_default,
|
|
@@ -28894,7 +29913,27 @@ function createCoreModules(options) {
|
|
|
28894
29913
|
url: url_module_default,
|
|
28895
29914
|
util: util_module_default,
|
|
28896
29915
|
"util/types": util_module_default.types ?? {},
|
|
28897
|
-
zlib: zlib_module_default
|
|
29916
|
+
zlib: zlib_module_default,
|
|
29917
|
+
test: createTestModule({
|
|
29918
|
+
write: stdoutWrite,
|
|
29919
|
+
setTimeout: (fn, ms) => timers.api.setTimeout(fn, ms),
|
|
29920
|
+
clearTimeout: (handle) => timers.api.clearTimeout(handle),
|
|
29921
|
+
/* A pending interval is what keeps a process alive in this runtime; a test
|
|
29922
|
+
* awaiting nothing but promises would otherwise be judged finished. */
|
|
29923
|
+
keepAlive: () => {
|
|
29924
|
+
const handle = timers.api.setInterval(() => {
|
|
29925
|
+
}, 1 << 30);
|
|
29926
|
+
return () => timers.api.clearInterval(handle);
|
|
29927
|
+
},
|
|
29928
|
+
exit: (code) => {
|
|
29929
|
+
processObject.exitCode = code;
|
|
29930
|
+
try {
|
|
29931
|
+
processObject.exit(code);
|
|
29932
|
+
} catch {
|
|
29933
|
+
}
|
|
29934
|
+
},
|
|
29935
|
+
settings: () => parseTestSettings(env2.SANDBOXEDJS_NODE_TEST)
|
|
29936
|
+
})
|
|
28898
29937
|
};
|
|
28899
29938
|
for (const name of stubNames) builtins[name] = createUnsupportedModule(name);
|
|
28900
29939
|
builtins.net = createNetModule();
|
|
@@ -28902,8 +29941,26 @@ function createCoreModules(options) {
|
|
|
28902
29941
|
Buffer: Buffer2,
|
|
28903
29942
|
console: consoleObject,
|
|
28904
29943
|
process: processObject,
|
|
28905
|
-
...timers.api
|
|
29944
|
+
...timers.api,
|
|
29945
|
+
queueMicrotask: (fn) => queueMicrotask(() => {
|
|
29946
|
+
try {
|
|
29947
|
+
fn();
|
|
29948
|
+
} catch (error) {
|
|
29949
|
+
reportUncaught(error);
|
|
29950
|
+
}
|
|
29951
|
+
})
|
|
28906
29952
|
};
|
|
29953
|
+
if (options.http) {
|
|
29954
|
+
globals.fetch = createVirtualFetch(options.http.router, {
|
|
29955
|
+
...outboundFetch ? { fetch: outboundFetch } : {},
|
|
29956
|
+
...options.http.loopback ? { loopback: options.http.loopback } : {},
|
|
29957
|
+
trackRequest
|
|
29958
|
+
});
|
|
29959
|
+
const NativeWebSocket = globalThis.WebSocket;
|
|
29960
|
+
if (options.http.policy && NativeWebSocket) {
|
|
29961
|
+
globals.WebSocket = policedWebSocket(NativeWebSocket, options.http.policy);
|
|
29962
|
+
}
|
|
29963
|
+
}
|
|
28907
29964
|
const globalOverlay = new Proxy(globalThis, {
|
|
28908
29965
|
get: (target, key) => typeof key === "string" && key in globals ? globals[key] : key === "global" || key === "globalThis" ? globalOverlay : Reflect.get(target, key),
|
|
28909
29966
|
has: (target, key) => typeof key === "string" && key in globals || Reflect.has(target, key)
|
|
@@ -28919,6 +29976,10 @@ function createCoreModules(options) {
|
|
|
28919
29976
|
/** Client requests sent but not yet read to completion. */
|
|
28920
29977
|
pendingRequests: () => inFlightRequests,
|
|
28921
29978
|
cancelTimers: timers.cancelAll,
|
|
29979
|
+
reportUncaught: (error) => reportUncaught(error),
|
|
29980
|
+
reportUnhandledRejection: (reason) => reportUncaught(reason, "unhandledRejection"),
|
|
29981
|
+
exitStatus: () => normalizeExitCode(processObject.exitCode),
|
|
29982
|
+
emitExit,
|
|
28922
29983
|
writeStdin: (data) => {
|
|
28923
29984
|
if (options.interactiveStdin) stdin.write(data);
|
|
28924
29985
|
},
|
|
@@ -28980,7 +30041,7 @@ function createPathModule(cwd) {
|
|
|
28980
30041
|
path.default = path;
|
|
28981
30042
|
return path;
|
|
28982
30043
|
}
|
|
28983
|
-
function createFsModule(volume, cwd, stdinPath) {
|
|
30044
|
+
function createFsModule(volume, cwd, stdinPath, defer = queueMicrotask) {
|
|
28984
30045
|
const fds = /* @__PURE__ */ new Map();
|
|
28985
30046
|
let nextFd = 3;
|
|
28986
30047
|
if (stdinPath) fds.set(0, { path: stdinPath, position: 0, flags: "r" });
|
|
@@ -29020,12 +30081,15 @@ function createFsModule(volume, cwd, stdinPath) {
|
|
|
29020
30081
|
volume.rmdirSync(path);
|
|
29021
30082
|
};
|
|
29022
30083
|
const callback = (operation, cb) => {
|
|
29023
|
-
|
|
30084
|
+
defer(() => {
|
|
30085
|
+
let value;
|
|
29024
30086
|
try {
|
|
29025
|
-
|
|
30087
|
+
value = operation();
|
|
29026
30088
|
} catch (error) {
|
|
29027
30089
|
cb(error);
|
|
30090
|
+
return;
|
|
29028
30091
|
}
|
|
30092
|
+
cb(null, value);
|
|
29029
30093
|
});
|
|
29030
30094
|
};
|
|
29031
30095
|
const fs = {
|
|
@@ -29155,7 +30219,7 @@ function createFsModule(volume, cwd, stdinPath) {
|
|
|
29155
30219
|
const slice = whole.subarray(start2, Math.max(start2, end));
|
|
29156
30220
|
const stream = streamModule4.Readable.from([settings.encoding ? slice.toString(settings.encoding) : slice]);
|
|
29157
30221
|
Object.assign(stream, { path: target, bytesRead: slice.length, close: () => stream.destroy() });
|
|
29158
|
-
|
|
30222
|
+
defer(() => {
|
|
29159
30223
|
stream.emit("open", 0);
|
|
29160
30224
|
stream.emit("ready");
|
|
29161
30225
|
});
|
|
@@ -29223,7 +30287,7 @@ function createFsModule(volume, cwd, stdinPath) {
|
|
|
29223
30287
|
}
|
|
29224
30288
|
fs.realpath.native = fs.realpath;
|
|
29225
30289
|
fs.exists = (path, cb) => {
|
|
29226
|
-
|
|
30290
|
+
defer(() => cb(fs.existsSync(path)));
|
|
29227
30291
|
};
|
|
29228
30292
|
fs.promises = {
|
|
29229
30293
|
...Object.fromEntries(
|
|
@@ -29345,7 +30409,7 @@ var Console = class {
|
|
|
29345
30409
|
timeLog = (_label = "default") => {
|
|
29346
30410
|
};
|
|
29347
30411
|
};
|
|
29348
|
-
function createDnsModule() {
|
|
30412
|
+
function createDnsModule(defer = queueMicrotask) {
|
|
29349
30413
|
const LOOPBACK = {
|
|
29350
30414
|
localhost: { address: "127.0.0.1", family: 4 },
|
|
29351
30415
|
"127.0.0.1": { address: "127.0.0.1", family: 4 },
|
|
@@ -29365,7 +30429,7 @@ function createDnsModule() {
|
|
|
29365
30429
|
const lookup = (hostname, options, callback) => {
|
|
29366
30430
|
const done = typeof options === "function" ? options : callback;
|
|
29367
30431
|
const all = typeof options === "object" && options !== null && options.all;
|
|
29368
|
-
|
|
30432
|
+
defer(() => {
|
|
29369
30433
|
try {
|
|
29370
30434
|
const entry = lookupSync(hostname);
|
|
29371
30435
|
done?.(null, all ? [entry] : entry.address, entry.family);
|
|
@@ -29523,7 +30587,16 @@ var ERRNO_CONSTANTS = {
|
|
|
29523
30587
|
EWOULDBLOCK: 11,
|
|
29524
30588
|
EXDEV: 18
|
|
29525
30589
|
};
|
|
29526
|
-
function createTrackedTimers() {
|
|
30590
|
+
function createTrackedTimers(onError = (error) => {
|
|
30591
|
+
throw error;
|
|
30592
|
+
}) {
|
|
30593
|
+
const run2 = (fn, args) => {
|
|
30594
|
+
try {
|
|
30595
|
+
fn(...args);
|
|
30596
|
+
} catch (error) {
|
|
30597
|
+
onError(error);
|
|
30598
|
+
}
|
|
30599
|
+
};
|
|
29527
30600
|
const live = /* @__PURE__ */ new Set();
|
|
29528
30601
|
const unrefed = /* @__PURE__ */ new Set();
|
|
29529
30602
|
const states = /* @__PURE__ */ new WeakMap();
|
|
@@ -29566,7 +30639,7 @@ function createTrackedTimers() {
|
|
|
29566
30639
|
const native = setTimeout(
|
|
29567
30640
|
(...inner) => {
|
|
29568
30641
|
complete(handle);
|
|
29569
|
-
fn
|
|
30642
|
+
run2(fn, inner);
|
|
29570
30643
|
},
|
|
29571
30644
|
delay,
|
|
29572
30645
|
...args
|
|
@@ -29574,14 +30647,14 @@ function createTrackedTimers() {
|
|
|
29574
30647
|
handle = track(native);
|
|
29575
30648
|
return handle;
|
|
29576
30649
|
};
|
|
29577
|
-
const setIntervalTracked = (fn, delay, ...args) => track(setInterval(fn, delay, ...args));
|
|
30650
|
+
const setIntervalTracked = (fn, delay, ...args) => track(setInterval((...inner) => run2(fn, inner), delay, ...args));
|
|
29578
30651
|
const hostSetImmediate = globalThis.setImmediate;
|
|
29579
30652
|
const setImmediateTracked = (fn, ...args) => {
|
|
29580
30653
|
if (!hostSetImmediate) return setTimeoutTracked(fn, 0, ...args);
|
|
29581
30654
|
let handle;
|
|
29582
30655
|
const native = hostSetImmediate((...inner) => {
|
|
29583
30656
|
complete(handle);
|
|
29584
|
-
fn
|
|
30657
|
+
run2(fn, inner);
|
|
29585
30658
|
}, ...args);
|
|
29586
30659
|
handle = track(native);
|
|
29587
30660
|
return handle;
|
|
@@ -29764,6 +30837,43 @@ function createNetModule() {
|
|
|
29764
30837
|
isIP: (value) => isIPv4(value) ? 4 : isIPv6(value) ? 6 : 0
|
|
29765
30838
|
});
|
|
29766
30839
|
}
|
|
30840
|
+
function parseTestSettings(raw) {
|
|
30841
|
+
if (!raw) return {};
|
|
30842
|
+
try {
|
|
30843
|
+
const parsed = JSON.parse(raw);
|
|
30844
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
30845
|
+
} catch {
|
|
30846
|
+
return {};
|
|
30847
|
+
}
|
|
30848
|
+
}
|
|
30849
|
+
var EVENT_EMITTER_METHODS = [
|
|
30850
|
+
"on",
|
|
30851
|
+
"addListener",
|
|
30852
|
+
"once",
|
|
30853
|
+
"off",
|
|
30854
|
+
"removeListener",
|
|
30855
|
+
"removeAllListeners",
|
|
30856
|
+
"emit",
|
|
30857
|
+
"prependListener",
|
|
30858
|
+
"prependOnceListener",
|
|
30859
|
+
"listeners",
|
|
30860
|
+
"rawListeners",
|
|
30861
|
+
"listenerCount",
|
|
30862
|
+
"eventNames",
|
|
30863
|
+
"setMaxListeners",
|
|
30864
|
+
"getMaxListeners"
|
|
30865
|
+
];
|
|
30866
|
+
function normalizeExitCode(value) {
|
|
30867
|
+
const code = typeof value === "string" && value.trim() !== "" ? Number(value) : value;
|
|
30868
|
+
return typeof code === "number" && Number.isInteger(code) ? code & 255 : 0;
|
|
30869
|
+
}
|
|
30870
|
+
function formatUncaught(error) {
|
|
30871
|
+
const text2 = error instanceof Error ? error.stack ?? `${error.name}: ${error.message}` : `Uncaught ${typeof error === "string" ? JSON.stringify(error) : String(error)}`;
|
|
30872
|
+
return `${text2}
|
|
30873
|
+
|
|
30874
|
+
Node.js v22.12.0
|
|
30875
|
+
`;
|
|
30876
|
+
}
|
|
29767
30877
|
var stubNames = ["cluster", "dgram", "diagnostics_channel", "domain", "http2", "inspector", "net", "tls", "v8", "vm", "worker_threads"];
|
|
29768
30878
|
var builtinNames2 = [
|
|
29769
30879
|
"assert",
|
|
@@ -29801,6 +30911,7 @@ var builtinNames2 = [
|
|
|
29801
30911
|
"util",
|
|
29802
30912
|
"util/types",
|
|
29803
30913
|
"zlib",
|
|
30914
|
+
"test",
|
|
29804
30915
|
...stubNames
|
|
29805
30916
|
];
|
|
29806
30917
|
|
|
@@ -30622,16 +31733,20 @@ async function loadNodeRolldownMemfsBinding() {
|
|
|
30622
31733
|
return null;
|
|
30623
31734
|
}
|
|
30624
31735
|
const fromBinding = createRequire(join3(packageDir, "package.json"));
|
|
30625
|
-
let
|
|
31736
|
+
let runtimeModuleUrl2;
|
|
30626
31737
|
let fsModuleUrl;
|
|
30627
|
-
let createContext2;
|
|
30628
31738
|
try {
|
|
30629
|
-
|
|
31739
|
+
runtimeModuleUrl2 = resolveSubpath(node2, fromBinding, "@napi-rs/wasm-runtime", ".");
|
|
30630
31740
|
fsModuleUrl = resolveSubpath(node2, fromBinding, "@napi-rs/wasm-runtime", "./fs");
|
|
30631
|
-
({ createContext: createContext2 } = fromBinding("@emnapi/runtime"));
|
|
30632
31741
|
} catch {
|
|
30633
31742
|
return null;
|
|
30634
31743
|
}
|
|
31744
|
+
const runtime = await import(
|
|
31745
|
+
/* @vite-ignore */
|
|
31746
|
+
/* webpackIgnore: true */
|
|
31747
|
+
runtimeModuleUrl2
|
|
31748
|
+
);
|
|
31749
|
+
const createContext2 = runtime.createContext;
|
|
30635
31750
|
const { memfs } = await import(
|
|
30636
31751
|
/* @vite-ignore */
|
|
30637
31752
|
/* webpackIgnore: true */
|
|
@@ -30663,7 +31778,7 @@ async function loadNodeRolldownMemfsBinding() {
|
|
|
30663
31778
|
onCreateWorker() {
|
|
30664
31779
|
const worker = new Worker2(workerPath, {
|
|
30665
31780
|
env: process.env,
|
|
30666
|
-
workerData: { runtimeAnchor, fsModuleUrl },
|
|
31781
|
+
workerData: { runtimeAnchor, runtimeModuleUrl: runtimeModuleUrl2, fsModuleUrl },
|
|
30667
31782
|
/*
|
|
30668
31783
|
* Deliberately no `execArgv`.
|
|
30669
31784
|
*
|
|
@@ -31106,6 +32221,8 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
31106
32221
|
rolldownBinding;
|
|
31107
32222
|
/** Backs outbound `http`/`https` client requests from inside the sandbox. */
|
|
31108
32223
|
fetch;
|
|
32224
|
+
/** What guest programs may reach outside the container. */
|
|
32225
|
+
networkPolicy;
|
|
31109
32226
|
constructor(options) {
|
|
31110
32227
|
ensureProcessGlobal();
|
|
31111
32228
|
this.sockets = new VirtualTcpNetwork((port) => this.router.activePortsIncludes(port));
|
|
@@ -31123,6 +32240,7 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
31123
32240
|
this.router.onListen = (port) => notify(port, `http://localhost:${port}`);
|
|
31124
32241
|
}
|
|
31125
32242
|
if (options.fetch) this.fetch = options.fetch;
|
|
32243
|
+
if (options.network) this.networkPolicy = { ...options.network };
|
|
31126
32244
|
this.packages = new CleanPackageInstaller(this.volume, {
|
|
31127
32245
|
cwd: this.workdir,
|
|
31128
32246
|
...options.registry ? { registry: options.registry } : {},
|
|
@@ -31133,6 +32251,10 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
31133
32251
|
static async boot(options = {}) {
|
|
31134
32252
|
return new _LocalRuntimePod(options);
|
|
31135
32253
|
}
|
|
32254
|
+
/** Apply a container's outbound policy to programs started from now on. */
|
|
32255
|
+
setNetworkPolicy(policy) {
|
|
32256
|
+
this.networkPolicy = { ...policy };
|
|
32257
|
+
}
|
|
31136
32258
|
async spawn(command, args = [], options = {}) {
|
|
31137
32259
|
this.assertActive();
|
|
31138
32260
|
if (command !== "node" && command !== "nodejs") throw commandError(command);
|
|
@@ -31145,7 +32267,6 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
31145
32267
|
await this.prepareRolldown(cwd, env2);
|
|
31146
32268
|
if (proc.isKilled()) return 137;
|
|
31147
32269
|
const untrack = trackProcess(proc);
|
|
31148
|
-
let requestedExit = 0;
|
|
31149
32270
|
let engine;
|
|
31150
32271
|
const core = createCoreModules({
|
|
31151
32272
|
volume: this.volume,
|
|
@@ -31159,11 +32280,15 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
31159
32280
|
* thrown from a later callback it would escape into whichever library
|
|
31160
32281
|
* scheduled that callback and look like an unrelated crash. */
|
|
31161
32282
|
onExit: (code) => {
|
|
31162
|
-
requestedExit = code;
|
|
31163
32283
|
proc.exitNow(code);
|
|
31164
32284
|
if (engine?.isEvaluating) throw new ProcessExit(code);
|
|
31165
32285
|
},
|
|
31166
|
-
http: {
|
|
32286
|
+
http: {
|
|
32287
|
+
router: this.router,
|
|
32288
|
+
owner,
|
|
32289
|
+
...this.fetch ? { fetch: this.fetch } : {},
|
|
32290
|
+
...this.networkPolicy ? { policy: this.networkPolicy } : {}
|
|
32291
|
+
},
|
|
31167
32292
|
spawnChild: (config2) => this.processManager.spawn(config2),
|
|
31168
32293
|
...typeof options.stdinPath === "string" ? { stdinPath: options.stdinPath } : {},
|
|
31169
32294
|
...options.interactiveStdin ? { interactiveStdin: true } : {},
|
|
@@ -31187,7 +32312,9 @@ var LocalRuntimePod = class _LocalRuntimePod {
|
|
|
31187
32312
|
try {
|
|
31188
32313
|
await Promise.race([engine.run(script), proc.waitForKill()]);
|
|
31189
32314
|
await this.settle(owner, core.pendingHandles, core.readingStdin, () => core.pendingRequests() + hostWork.pending(), () => proc.isKilled());
|
|
31190
|
-
|
|
32315
|
+
const status = core.exitStatus();
|
|
32316
|
+
core.emitExit(status);
|
|
32317
|
+
return status;
|
|
31191
32318
|
} finally {
|
|
31192
32319
|
hostWork.dispose();
|
|
31193
32320
|
core.cancelTimers();
|
|
@@ -31690,6 +32817,9 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
31690
32817
|
case "http-response":
|
|
31691
32818
|
this.settleProxied(Number(message.id), message.response);
|
|
31692
32819
|
return;
|
|
32820
|
+
case "loopback-request":
|
|
32821
|
+
void this.answerLoopback(worker, message);
|
|
32822
|
+
return;
|
|
31693
32823
|
case "ws-data":
|
|
31694
32824
|
this.upgraded.get(Number(message.id))?.write(new Uint8Array(message.data));
|
|
31695
32825
|
return;
|
|
@@ -31725,7 +32855,8 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
31725
32855
|
aliases: this.aliases,
|
|
31726
32856
|
...typeof options.stdinPath === "string" ? { stdinPath: options.stdinPath } : {},
|
|
31727
32857
|
...options.interactiveStdin ? { interactiveStdin: true } : {},
|
|
31728
|
-
...options.tty ? { tty: true } : {}
|
|
32858
|
+
...options.tty ? { tty: true } : {},
|
|
32859
|
+
...this.networkPolicy ? { network: this.networkPolicy } : {}
|
|
31729
32860
|
});
|
|
31730
32861
|
process2.begin();
|
|
31731
32862
|
return process2;
|
|
@@ -31861,6 +32992,38 @@ var WorkerRuntimePod = class _WorkerRuntimePod extends LocalRuntimePod {
|
|
|
31861
32992
|
init: { method: request.method, path: request.url, headers: request.headers }
|
|
31862
32993
|
});
|
|
31863
32994
|
}
|
|
32995
|
+
/**
|
|
32996
|
+
* Answer a program that is calling a server in this container.
|
|
32997
|
+
*
|
|
32998
|
+
* A guest's router holds only the servers on its own thread, so a request to
|
|
32999
|
+
* a port some other process opened comes here, where every server in the
|
|
33000
|
+
* container is registered. `null` means nothing listens, which the guest
|
|
33001
|
+
* reports as a refused connection.
|
|
33002
|
+
*/
|
|
33003
|
+
async answerLoopback(worker, message) {
|
|
33004
|
+
const port = Number(message.port);
|
|
33005
|
+
let response = null;
|
|
33006
|
+
if (this.router.activePortsIncludes(port)) {
|
|
33007
|
+
try {
|
|
33008
|
+
const result = await this.router.request(port, message.request);
|
|
33009
|
+
const body = result.body;
|
|
33010
|
+
response = {
|
|
33011
|
+
statusCode: result.statusCode,
|
|
33012
|
+
statusMessage: result.statusMessage,
|
|
33013
|
+
headers: result.headers,
|
|
33014
|
+
body: typeof body === "string" ? new TextEncoder().encode(body) : body instanceof ArrayBuffer ? new Uint8Array(body) : body ?? new Uint8Array()
|
|
33015
|
+
};
|
|
33016
|
+
} catch (error) {
|
|
33017
|
+
response = {
|
|
33018
|
+
statusCode: 502,
|
|
33019
|
+
statusMessage: "Bad Gateway",
|
|
33020
|
+
headers: {},
|
|
33021
|
+
body: new TextEncoder().encode(error instanceof Error ? error.message : String(error))
|
|
33022
|
+
};
|
|
33023
|
+
}
|
|
33024
|
+
}
|
|
33025
|
+
worker.postMessage({ type: "loopback-response", id: message.id, response });
|
|
33026
|
+
}
|
|
31864
33027
|
settleProxied(id, response) {
|
|
31865
33028
|
const resolve3 = this.waiting.get(id);
|
|
31866
33029
|
if (!resolve3) return;
|
|
@@ -31951,13 +33114,19 @@ var Container = class _Container {
|
|
|
31951
33114
|
// ── boot ──────────────────────────────────────────────────────────────────
|
|
31952
33115
|
static async create(opts = {}) {
|
|
31953
33116
|
if (opts.python) configurePython(opts.python);
|
|
33117
|
+
const network = {
|
|
33118
|
+
allowOutbound: opts.network?.allowOutbound ?? false,
|
|
33119
|
+
allowedHosts: opts.network?.allowedHosts ?? null
|
|
33120
|
+
};
|
|
31954
33121
|
const podOptions = {
|
|
31955
33122
|
workdir: opts.cwd ?? "/",
|
|
31956
33123
|
env: opts.env ?? {},
|
|
33124
|
+
network,
|
|
31957
33125
|
...opts.onServerReady ? { onServerReady: opts.onServerReady } : {}
|
|
31958
33126
|
};
|
|
31959
33127
|
const workerOptions = { ...podOptions, ...opts.workerUrl ? { workerUrl: opts.workerUrl } : {} };
|
|
31960
33128
|
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);
|
|
33129
|
+
if (opts.pod) opts.pod.setNetworkPolicy?.(network);
|
|
31961
33130
|
const kernel = new Kernel({
|
|
31962
33131
|
pod,
|
|
31963
33132
|
hostname: opts.hostname ?? "sandbox",
|
|
@@ -32052,7 +33221,7 @@ var Container = class _Container {
|
|
|
32052
33221
|
async exec(command, opts = {}) {
|
|
32053
33222
|
this.assertActive();
|
|
32054
33223
|
const started = Date.now();
|
|
32055
|
-
const { io, stdout, stderr, combined } = this.makeStdio(opts);
|
|
33224
|
+
const { io, stdout, stderr, combined, detach } = this.makeStdio(opts);
|
|
32056
33225
|
const cred = opts.user ? this.kernel.users.credFor(opts.user) : this.defaults.cred;
|
|
32057
33226
|
const env2 = { ...this.defaults.env, ...opts.env };
|
|
32058
33227
|
const cwd = opts.cwd ? resolve(this.defaults.cwd, opts.cwd) : this.defaults.cwd;
|
|
@@ -32081,6 +33250,7 @@ var Container = class _Container {
|
|
|
32081
33250
|
]);
|
|
32082
33251
|
} finally {
|
|
32083
33252
|
if (timer) clearTimeout(timer);
|
|
33253
|
+
detach();
|
|
32084
33254
|
proc.exit(0);
|
|
32085
33255
|
this.kernel.procs.remove(proc.pid);
|
|
32086
33256
|
}
|
|
@@ -32097,7 +33267,7 @@ var Container = class _Container {
|
|
|
32097
33267
|
async run(argv, opts = {}) {
|
|
32098
33268
|
this.assertActive();
|
|
32099
33269
|
const started = Date.now();
|
|
32100
|
-
const { io, stdout, stderr, combined } = this.makeStdio(opts);
|
|
33270
|
+
const { io, stdout, stderr, combined, detach } = this.makeStdio(opts);
|
|
32101
33271
|
const cred = opts.user ? this.kernel.users.credFor(opts.user) : this.defaults.cred;
|
|
32102
33272
|
const cwd = opts.cwd ? resolve(this.defaults.cwd, opts.cwd) : this.defaults.cwd;
|
|
32103
33273
|
const result = await this.kernel.run(argv, {
|
|
@@ -32109,6 +33279,7 @@ var Container = class _Container {
|
|
|
32109
33279
|
stderr: io.stderr,
|
|
32110
33280
|
...opts.timeoutMs ?? this.defaults.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs ?? this.defaults.timeoutMs } : {}
|
|
32111
33281
|
});
|
|
33282
|
+
detach();
|
|
32112
33283
|
return {
|
|
32113
33284
|
exitCode: result.exitCode,
|
|
32114
33285
|
stdout: stdout.text(),
|
|
@@ -32199,6 +33370,14 @@ var Container = class _Container {
|
|
|
32199
33370
|
if (!this.defaultSession) this.defaultSession = this.session();
|
|
32200
33371
|
return this.defaultSession;
|
|
32201
33372
|
}
|
|
33373
|
+
/**
|
|
33374
|
+
* The streams one call collects into.
|
|
33375
|
+
*
|
|
33376
|
+
* They are detachable because a background job started by the command keeps
|
|
33377
|
+
* writing after the call has returned. Nothing reads the result any more by
|
|
33378
|
+
* then, so without `detach` a chatty server would grow the buffer for as long
|
|
33379
|
+
* as it ran; afterwards its output still reaches the container-wide taps.
|
|
33380
|
+
*/
|
|
32202
33381
|
makeStdio(opts) {
|
|
32203
33382
|
const combined = [];
|
|
32204
33383
|
const decoder9 = new TextDecoder();
|
|
@@ -32214,14 +33393,25 @@ var Container = class _Container {
|
|
|
32214
33393
|
opts.onStderr?.(text2);
|
|
32215
33394
|
this.hooks.onStderr?.(text2);
|
|
32216
33395
|
});
|
|
33396
|
+
const outGate = new DetachableOutput(stdout, (text2) => this.hooks.onStdout?.(text2));
|
|
33397
|
+
const errGate = new DetachableOutput(stderr, (text2) => this.hooks.onStderr?.(text2));
|
|
32217
33398
|
if (opts.tty) {
|
|
32218
|
-
|
|
32219
|
-
|
|
32220
|
-
|
|
32221
|
-
|
|
33399
|
+
outGate.isTTY = true;
|
|
33400
|
+
errGate.isTTY = true;
|
|
33401
|
+
outGate.columns = opts.columns ?? 80;
|
|
33402
|
+
outGate.rows = opts.rows ?? 24;
|
|
32222
33403
|
}
|
|
32223
33404
|
const stdin = opts.stdin === void 0 ? new NullInput() : Pipe.from(opts.stdin);
|
|
32224
|
-
return {
|
|
33405
|
+
return {
|
|
33406
|
+
io: { stdin, stdout: outGate, stderr: errGate },
|
|
33407
|
+
stdout,
|
|
33408
|
+
stderr,
|
|
33409
|
+
combined,
|
|
33410
|
+
detach: () => {
|
|
33411
|
+
outGate.detach();
|
|
33412
|
+
errGate.detach();
|
|
33413
|
+
}
|
|
33414
|
+
};
|
|
32225
33415
|
}
|
|
32226
33416
|
// ── networking ────────────────────────────────────────────────────────────
|
|
32227
33417
|
/** Send an HTTP request to a server running inside the container. */
|