sandboxedjs 0.1.26 → 0.1.28

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/dist/index.cjs CHANGED
@@ -6823,7 +6823,7 @@ var NetworkStack = class {
6823
6823
  }
6824
6824
  return [...out.values()].sort((a, b) => a.port - b.port);
6825
6825
  }
6826
- /** Ports Nodepod's proxy has registered for this instance. */
6826
+ /** Ports the pod's proxy has registered for this instance. */
6827
6827
  knownPodPorts() {
6828
6828
  try {
6829
6829
  return this.pod.proxy.activePorts(this.pod.instanceId) ?? [];
@@ -7349,15 +7349,15 @@ var Parser = class {
7349
7349
  if (this.isWord("-p")) this.next();
7350
7350
  }
7351
7351
  }
7352
- const commands11 = [this.parseCommand()];
7352
+ const commands12 = [this.parseCommand()];
7353
7353
  const stderrToo = [];
7354
7354
  while (this.isOp("|") || this.isOp("|&")) {
7355
7355
  stderrToo.push(this.next().value === "|&");
7356
7356
  this.skipNewlines();
7357
- commands11.push(this.parseCommand());
7357
+ commands12.push(this.parseCommand());
7358
7358
  }
7359
- if (commands11.length === 1 && !negated && !timed) return commands11[0];
7360
- return { type: "pipeline", commands: commands11, negated, stderrToo, timed };
7359
+ if (commands12.length === 1 && !negated && !timed) return commands12[0];
7360
+ return { type: "pipeline", commands: commands12, negated, stderrToo, timed };
7361
7361
  }
7362
7362
  // ── commands ─────────────────────────────────────────────────────────────
7363
7363
  parseCommand() {
@@ -16980,6 +16980,145 @@ var helpCmd = defineCommand({
16980
16980
  });
16981
16981
  var commands10 = [man, whatis, apropos, less, helpCmd];
16982
16982
 
16983
+ // src/bin/clipboard.ts
16984
+ init_path();
16985
+ var CLIPBOARD_DIR = "/run/clipboard";
16986
+ function selectionPath(selection) {
16987
+ return join(CLIPBOARD_DIR, selection);
16988
+ }
16989
+ function readSelection(ctx, selection) {
16990
+ try {
16991
+ return ctx.vfs.readFile(selectionPath(selection), ctx.cred);
16992
+ } catch {
16993
+ return new Uint8Array();
16994
+ }
16995
+ }
16996
+ function writeSelection(ctx, selection, bytes2) {
16997
+ try {
16998
+ ctx.vfs.mkdir(CLIPBOARD_DIR, { recursive: true, mode: 511 });
16999
+ } catch {
17000
+ }
17001
+ ctx.vfs.writeFile(selectionPath(selection), bytes2, { privileged: true, mode: 438 });
17002
+ }
17003
+ var xsel = defineCommand({
17004
+ name: "xsel",
17005
+ summary: "access an X selection",
17006
+ usage: "xsel [--clipboard|--primary|--secondary] [--input|--output|--clear]",
17007
+ async run(ctx) {
17008
+ let selection = "primary";
17009
+ let mode = "output";
17010
+ for (const arg of ctx.args) {
17011
+ switch (arg) {
17012
+ case "-b":
17013
+ case "--clipboard":
17014
+ selection = "clipboard";
17015
+ break;
17016
+ case "-p":
17017
+ case "--primary":
17018
+ selection = "primary";
17019
+ break;
17020
+ case "-s":
17021
+ case "--secondary":
17022
+ selection = "secondary";
17023
+ break;
17024
+ case "-i":
17025
+ case "--input":
17026
+ case "-a":
17027
+ case "--append":
17028
+ mode = "input";
17029
+ break;
17030
+ case "-o":
17031
+ case "--output":
17032
+ mode = "output";
17033
+ break;
17034
+ case "-c":
17035
+ case "--clear":
17036
+ mode = "clear";
17037
+ break;
17038
+ }
17039
+ }
17040
+ if (mode === "clear") {
17041
+ writeSelection(ctx, selection, new Uint8Array());
17042
+ return 0;
17043
+ }
17044
+ if (mode === "input") {
17045
+ writeSelection(ctx, selection, await ctx.stdin.readAll());
17046
+ return 0;
17047
+ }
17048
+ ctx.write(readSelection(ctx, selection));
17049
+ return 0;
17050
+ }
17051
+ });
17052
+ var xclip = defineCommand({
17053
+ name: "xclip",
17054
+ summary: "access an X selection",
17055
+ usage: "xclip [-selection clipboard|primary|secondary] [-i|-o]",
17056
+ async run(ctx) {
17057
+ let selection = "primary";
17058
+ let mode = "input";
17059
+ const args = ctx.args;
17060
+ for (let index = 0; index < args.length; index++) {
17061
+ const arg = args[index];
17062
+ if (arg === "-selection" || arg === "-sel" || arg === "--selection") {
17063
+ const value = args[++index];
17064
+ if (value === "clipboard" || value === "primary" || value === "secondary") selection = value;
17065
+ continue;
17066
+ }
17067
+ if (arg === "-i" || arg === "-in") mode = "input";
17068
+ else if (arg === "-o" || arg === "-out") mode = "output";
17069
+ }
17070
+ if (mode === "input") {
17071
+ writeSelection(ctx, selection, await ctx.stdin.readAll());
17072
+ return 0;
17073
+ }
17074
+ ctx.write(readSelection(ctx, selection));
17075
+ return 0;
17076
+ }
17077
+ });
17078
+ var pbcopy = defineCommand({
17079
+ name: "pbcopy",
17080
+ summary: "copy standard input to the clipboard",
17081
+ usage: "pbcopy",
17082
+ async run(ctx) {
17083
+ writeSelection(ctx, "clipboard", await ctx.stdin.readAll());
17084
+ return 0;
17085
+ }
17086
+ });
17087
+ var pbpaste = defineCommand({
17088
+ name: "pbpaste",
17089
+ summary: "write the clipboard to standard output",
17090
+ usage: "pbpaste",
17091
+ run(ctx) {
17092
+ ctx.write(readSelection(ctx, "clipboard"));
17093
+ return 0;
17094
+ }
17095
+ });
17096
+ var wlCopy = defineCommand({
17097
+ name: "wl-copy",
17098
+ summary: "copy standard input to the Wayland clipboard",
17099
+ usage: "wl-copy [--primary] [text...]",
17100
+ async run(ctx) {
17101
+ const selection = ctx.args.includes("--primary") || ctx.args.includes("-p") ? "primary" : "clipboard";
17102
+ const operands = ctx.args.filter((arg) => !arg.startsWith("-"));
17103
+ const bytes2 = operands.length ? new TextEncoder().encode(operands.join(" ")) : await ctx.stdin.readAll();
17104
+ writeSelection(ctx, selection, bytes2);
17105
+ return 0;
17106
+ }
17107
+ });
17108
+ var wlPaste = defineCommand({
17109
+ name: "wl-paste",
17110
+ summary: "write the Wayland clipboard to standard output",
17111
+ usage: "wl-paste [--primary] [-n]",
17112
+ run(ctx) {
17113
+ const selection = ctx.args.includes("--primary") || ctx.args.includes("-p") ? "primary" : "clipboard";
17114
+ const bytes2 = readSelection(ctx, selection);
17115
+ ctx.write(bytes2);
17116
+ if (!ctx.args.includes("-n") && !ctx.args.includes("--no-newline")) ctx.write("\n");
17117
+ return 0;
17118
+ }
17119
+ });
17120
+ var commands11 = [xsel, xclip, pbcopy, pbpaste, wlCopy, wlPaste];
17121
+
16983
17122
  // src/runtime/node.ts
16984
17123
  init_path();
16985
17124
  var NODE_VERSION = "v22.12.0";
@@ -18180,7 +18319,33 @@ function ffmpegCommands() {
18180
18319
  return [ffmpeg, ffprobe];
18181
18320
  }
18182
18321
  var platformBuffer = globalThis.Buffer;
18183
- var Buffer2 = platformBuffer ?? index_js.Buffer;
18322
+ var Buffer2 = platformBuffer ?? addBase64UrlSupport(index_js.Buffer);
18323
+ function addBase64UrlSupport(BufferClass) {
18324
+ const target = BufferClass;
18325
+ if (target.__sandboxedBase64Url) return BufferClass;
18326
+ Object.defineProperty(target, "__sandboxedBase64Url", { value: true });
18327
+ const from = target.from.bind(target);
18328
+ target.from = (value, encodingOrOffset, length) => from(value, normalizeEncoding(encodingOrOffset), length);
18329
+ const byteLength = target.byteLength.bind(target);
18330
+ target.byteLength = (value, encoding) => byteLength(value, normalizeEncoding(encoding));
18331
+ const isEncoding = target.isEncoding?.bind(target);
18332
+ if (isEncoding) target.isEncoding = (encoding) => encoding.toLowerCase() === "base64url" || isEncoding(encoding);
18333
+ const toString = target.prototype.toString;
18334
+ target.prototype.toString = function(encoding, start2, end) {
18335
+ if (encoding?.toLowerCase() !== "base64url") return toString.call(this, encoding, start2, end);
18336
+ return toString.call(this, "base64", start2, end).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
18337
+ };
18338
+ const write = target.prototype.write;
18339
+ target.prototype.write = function(...args) {
18340
+ const index = typeof args[1] === "string" ? 1 : typeof args[2] === "string" ? 2 : 3;
18341
+ if (typeof args[index] === "string") args[index] = normalizeEncoding(args[index]);
18342
+ return write.apply(this, args);
18343
+ };
18344
+ return BufferClass;
18345
+ }
18346
+ function normalizeEncoding(value) {
18347
+ return typeof value === "string" && value.toLowerCase() === "base64url" ? "base64" : value;
18348
+ }
18184
18349
 
18185
18350
  // src/pkg/clean-installer.ts
18186
18351
  init_path();
@@ -18222,6 +18387,9 @@ var CleanPackageInstaller = class _CleanPackageInstaller {
18222
18387
  const version = resolveVersion(metadata, range);
18223
18388
  const manifest = metadata.versions[version];
18224
18389
  if (!manifest) throw new Error(`No matching version found for ${name}@${range}`);
18390
+ if (!supportsPlatform(manifest)) {
18391
+ throw new Error(`${name}@${version} is not compatible with linux/x64/glibc`);
18392
+ }
18225
18393
  const identity = `${name}@${version}`;
18226
18394
  const target = join(modulesRoot, name);
18227
18395
  const installed2 = this.tryReadJson(join(target, "package.json"));
@@ -18316,6 +18484,15 @@ var CleanPackageInstaller = class _CleanPackageInstaller {
18316
18484
  }
18317
18485
  }
18318
18486
  };
18487
+ function supportsPlatform(manifest) {
18488
+ return !manifest.main?.endsWith(".node") && platformListAllows(manifest.os, "linux") && platformListAllows(manifest.cpu, "x64") && platformListAllows(manifest.libc, "glibc");
18489
+ }
18490
+ function platformListAllows(values, current) {
18491
+ if (!values?.length) return true;
18492
+ if (values.includes(`!${current}`)) return false;
18493
+ const positive = values.filter((value) => !value.startsWith("!"));
18494
+ return positive.length === 0 || positive.includes(current) || positive.includes("any");
18495
+ }
18319
18496
  function resolveVersion(metadata, range) {
18320
18497
  const tag2 = metadata["dist-tags"]?.[range];
18321
18498
  if (tag2) return tag2;
@@ -19298,6 +19475,7 @@ function allCommands() {
19298
19475
  ...commands8,
19299
19476
  ...commands9,
19300
19477
  ...commands10,
19478
+ ...commands11,
19301
19479
  ...nodeCommands(),
19302
19480
  ...pythonCommands(),
19303
19481
  ...ffmpegCommands(),
@@ -19594,6 +19772,13 @@ var KernelChildProcess = class {
19594
19772
  } catch {
19595
19773
  }
19596
19774
  }
19775
+ /** Signal EOF, so a child reading stdin to the end can finish. */
19776
+ endStdin() {
19777
+ try {
19778
+ this.stdin.end();
19779
+ } catch {
19780
+ }
19781
+ }
19597
19782
  kill(signal = "SIGTERM") {
19598
19783
  if (this.process) {
19599
19784
  this.process.deliver(signal);
@@ -20505,6 +20690,55 @@ function splitSpecifier(specifier) {
20505
20690
  return { name: parts.slice(0, size).join("/"), subpath: parts.slice(size).join("/") };
20506
20691
  }
20507
20692
 
20693
+ // src/runtime/readable-from.ts
20694
+ function createReadableFrom(Readable) {
20695
+ return function from(source, options = {}) {
20696
+ if (source && typeof source.pipe === "function") return source;
20697
+ const iterator = source && typeof source[Symbol.asyncIterator] === "function" ? source[Symbol.asyncIterator]() : source && typeof source[Symbol.iterator] === "function" ? source[Symbol.iterator]() : (function* () {
20698
+ yield source;
20699
+ })();
20700
+ let reading = false;
20701
+ const stream = new Readable({
20702
+ ...options,
20703
+ objectMode: options.objectMode ?? false,
20704
+ read() {
20705
+ if (reading) return;
20706
+ reading = true;
20707
+ void (async () => {
20708
+ try {
20709
+ for (; ; ) {
20710
+ const next = await iterator.next();
20711
+ if (next.done) {
20712
+ stream.push(null);
20713
+ return;
20714
+ }
20715
+ const value = next.value;
20716
+ if (!stream.push(value === void 0 ? null : value)) return;
20717
+ }
20718
+ } catch (error) {
20719
+ stream.destroy(error);
20720
+ } finally {
20721
+ reading = false;
20722
+ }
20723
+ })();
20724
+ },
20725
+ destroy(error, callback) {
20726
+ void (async () => {
20727
+ try {
20728
+ await iterator.return?.();
20729
+ } catch {
20730
+ }
20731
+ callback(error);
20732
+ })();
20733
+ }
20734
+ });
20735
+ return stream;
20736
+ };
20737
+ }
20738
+ function installReadableFrom(streamModule5) {
20739
+ streamModule5.Readable.from = createReadableFrom(streamModule5.Readable);
20740
+ }
20741
+
20508
20742
  // src/runtime/util-module.ts
20509
20743
  var customInspect = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
20510
20744
  var promisifyCustom = /* @__PURE__ */ Symbol.for("nodejs.util.promisify.custom");
@@ -21392,6 +21626,10 @@ var VirtualHttpRouter = class {
21392
21626
  unregister(port, server) {
21393
21627
  if (this.servers.get(port)?.server === server) this.servers.delete(port);
21394
21628
  }
21629
+ /** Whether anything in this container is listening on `port`. */
21630
+ activePortsIncludes(port) {
21631
+ return this.servers.has(port);
21632
+ }
21395
21633
  activePorts(owner) {
21396
21634
  return [...this.servers].filter(([, item]) => owner === void 0 || item.owner === owner).map(([port]) => port).sort((a, b) => a - b);
21397
21635
  }
@@ -21415,13 +21653,269 @@ var VirtualHttpRouter = class {
21415
21653
  }
21416
21654
  }
21417
21655
  };
21418
- function createHttpModule(router, owner) {
21656
+ var VirtualClientResponse = class extends streamModule4__default.default.Readable {
21657
+ constructor(statusCode, statusMessage, headers, body) {
21658
+ super();
21659
+ this.statusCode = statusCode;
21660
+ this.statusMessage = statusMessage;
21661
+ this.headers = headers;
21662
+ this.rawHeaders = Object.entries(headers).flatMap(([key, value]) => [key, value]);
21663
+ if (body.length) this.push(Buffer2.from(body));
21664
+ this.push(null);
21665
+ this.complete = true;
21666
+ }
21667
+ statusCode;
21668
+ statusMessage;
21669
+ headers;
21670
+ httpVersion = "1.1";
21671
+ httpVersionMajor = 1;
21672
+ httpVersionMinor = 1;
21673
+ socket = socketStub();
21674
+ connection = this.socket;
21675
+ rawHeaders;
21676
+ complete = false;
21677
+ _read() {
21678
+ }
21679
+ setTimeout(_milliseconds, callback) {
21680
+ if (callback) this.once("timeout", callback);
21681
+ return this;
21682
+ }
21683
+ };
21684
+ function resolveTarget(input, overrides, defaultProtocol) {
21685
+ const options = {};
21686
+ if (typeof input === "string" || input instanceof URL) {
21687
+ const url = new URL(String(input));
21688
+ options.protocol = url.protocol;
21689
+ options.hostname = url.hostname;
21690
+ if (url.port) options.port = Number(url.port);
21691
+ options.path = `${url.pathname}${url.search}`;
21692
+ if (url.username || url.password) options.auth = `${url.username}:${url.password}`;
21693
+ } else if (input && typeof input === "object") {
21694
+ Object.assign(options, input);
21695
+ }
21696
+ if (overrides) Object.assign(options, overrides);
21697
+ const protocol = String(options.protocol ?? defaultProtocol).replace(/:?$/, ":");
21698
+ const headers = {};
21699
+ for (const [name, value] of Object.entries(options.headers ?? {})) {
21700
+ if (value === void 0 || value === null) continue;
21701
+ headers[String(name)] = Array.isArray(value) ? value.join(", ") : String(value);
21702
+ }
21703
+ if (options.auth && headers.authorization === void 0) {
21704
+ headers.authorization = `Basic ${Buffer2.from(String(options.auth)).toString("base64")}`;
21705
+ }
21706
+ const rawHost = String(options.hostname ?? options.host ?? "localhost");
21707
+ const hostMatch = /^(\[[^\]]*\]|[^:]*)(?::(\d+))?$/.exec(rawHost);
21708
+ const hostname = (hostMatch?.[1] ?? rawHost).replace(/^\[|\]$/g, "");
21709
+ const explicitPort = options.port ?? hostMatch?.[2];
21710
+ const port = explicitPort === void 0 || explicitPort === null || explicitPort === "" || Number.isNaN(Number(explicitPort)) ? protocol === "https:" ? 443 : 80 : Number(explicitPort);
21711
+ return {
21712
+ protocol,
21713
+ hostname,
21714
+ port,
21715
+ path: String(options.path ?? "/"),
21716
+ method: String(options.method ?? "GET").toUpperCase(),
21717
+ headers
21718
+ };
21719
+ }
21720
+ function isLoopback(hostname) {
21721
+ return hostname === "localhost" || hostname === "0.0.0.0" || hostname === "::1" || hostname === "::" || hostname.startsWith("127.") || hostname.endsWith(".localhost");
21722
+ }
21723
+ var VirtualClientRequest = class extends streamModule4__default.default.Writable {
21724
+ constructor(target, router, fetchImpl, trackRequest) {
21725
+ super();
21726
+ this.target = target;
21727
+ this.router = router;
21728
+ this.fetchImpl = fetchImpl;
21729
+ this.trackRequest = trackRequest;
21730
+ for (const [name, value] of Object.entries(target.headers)) this.setHeader(name, value);
21731
+ }
21732
+ target;
21733
+ router;
21734
+ fetchImpl;
21735
+ trackRequest;
21736
+ socket = socketStub();
21737
+ connection = this.socket;
21738
+ chunks = [];
21739
+ headerMap = /* @__PURE__ */ new Map();
21740
+ dispatched = false;
21741
+ destroyedByUser = false;
21742
+ timer;
21743
+ aborted = false;
21744
+ finished = false;
21745
+ reusedSocket = false;
21746
+ get method() {
21747
+ return this.target.method;
21748
+ }
21749
+ get path() {
21750
+ return this.target.path;
21751
+ }
21752
+ get host() {
21753
+ return this.target.hostname;
21754
+ }
21755
+ get protocol() {
21756
+ return this.target.protocol;
21757
+ }
21758
+ setHeader(name, value) {
21759
+ validateHeaderName(name);
21760
+ validateHeaderValue(name, value);
21761
+ this.headerMap.set(name.toLowerCase(), { name, value: Array.isArray(value) ? [...value].map(String).join(", ") : String(value) });
21762
+ return this;
21763
+ }
21764
+ getHeader(name) {
21765
+ return this.headerMap.get(name.toLowerCase())?.value;
21766
+ }
21767
+ getHeaders() {
21768
+ return Object.fromEntries([...this.headerMap].map(([key, entry]) => [key, entry.value]));
21769
+ }
21770
+ getHeaderNames() {
21771
+ return [...this.headerMap.keys()];
21772
+ }
21773
+ hasHeader(name) {
21774
+ return this.headerMap.has(name.toLowerCase());
21775
+ }
21776
+ removeHeader(name) {
21777
+ this.headerMap.delete(name.toLowerCase());
21778
+ }
21779
+ flushHeaders() {
21780
+ }
21781
+ setNoDelay() {
21782
+ }
21783
+ setSocketKeepAlive() {
21784
+ }
21785
+ ref() {
21786
+ return this;
21787
+ }
21788
+ unref() {
21789
+ return this;
21790
+ }
21791
+ setTimeout(milliseconds, callback) {
21792
+ if (callback) this.once("timeout", callback);
21793
+ clearTimeout(this.timer);
21794
+ this.timer = setTimeout(() => this.emit("timeout"), milliseconds);
21795
+ return this;
21796
+ }
21797
+ abort() {
21798
+ this.destroyRequest();
21799
+ }
21800
+ destroy(error) {
21801
+ this.destroyRequest(error);
21802
+ return this;
21803
+ }
21804
+ destroyRequest(error) {
21805
+ if (this.destroyedByUser) return;
21806
+ this.destroyedByUser = true;
21807
+ this.aborted = true;
21808
+ clearTimeout(this.timer);
21809
+ this.emit("abort");
21810
+ if (error) this.emit("error", error);
21811
+ this.emit("close");
21812
+ }
21813
+ _write(chunk, encoding, callback) {
21814
+ this.chunks.push(Buffer2.isBuffer(chunk) ? chunk : Buffer2.from(chunk, encoding));
21815
+ callback();
21816
+ }
21817
+ _final(callback) {
21818
+ this.finished = true;
21819
+ callback();
21820
+ void this.dispatch();
21821
+ }
21822
+ async dispatch() {
21823
+ if (this.dispatched || this.destroyedByUser) return;
21824
+ this.dispatched = true;
21825
+ const body = Buffer2.concat(this.chunks);
21826
+ const release = this.trackRequest?.();
21827
+ let released = false;
21828
+ const untrack = () => {
21829
+ if (released || !release) return;
21830
+ released = true;
21831
+ release();
21832
+ };
21833
+ let settled = false;
21834
+ try {
21835
+ const response = this.router.activePortsIncludes(this.target.port) && isLoopback(this.target.hostname) ? await this.viaRouter(body) : await this.viaFetch(body);
21836
+ if (this.destroyedByUser) return;
21837
+ clearTimeout(this.timer);
21838
+ settled = true;
21839
+ response.once("end", untrack);
21840
+ response.once("close", untrack);
21841
+ response.once("error", untrack);
21842
+ this.emit("response", response);
21843
+ queueMicrotask(() => {
21844
+ if (this.listenerCount("response") === 0) response.resume();
21845
+ });
21846
+ } catch (error) {
21847
+ clearTimeout(this.timer);
21848
+ if (this.destroyedByUser) return;
21849
+ const failure = error instanceof Error ? error : new Error(String(error));
21850
+ if (!("code" in failure)) Object.assign(failure, { code: "ECONNREFUSED" });
21851
+ this.emit("error", failure);
21852
+ } finally {
21853
+ if (!settled) untrack();
21854
+ }
21855
+ }
21856
+ async viaRouter(body) {
21857
+ const result = await this.router.request(this.target.port, {
21858
+ method: this.target.method,
21859
+ path: this.target.path,
21860
+ headers: this.getHeaders(),
21861
+ body: body.length ? new Uint8Array(body) : null
21862
+ });
21863
+ const body_ = result.body;
21864
+ const bytes2 = typeof body_ === "string" ? new TextEncoder().encode(body_) : body_ instanceof ArrayBuffer ? new Uint8Array(body_) : body_ ?? new Uint8Array();
21865
+ const status = result.statusCode ?? 200;
21866
+ return new VirtualClientResponse(status, result.statusMessage ?? STATUS_CODES[status] ?? "", lowercaseHeaders(result.headers), bytes2);
21867
+ }
21868
+ async viaFetch(body) {
21869
+ const fetchImpl = this.fetchImpl ?? globalThis.fetch;
21870
+ if (typeof fetchImpl !== "function") {
21871
+ throw Object.assign(new Error(`getaddrinfo ENOTFOUND ${this.target.hostname}`), { code: "ENOTFOUND" });
21872
+ }
21873
+ const portSuffix = this.target.protocol === "https:" && this.target.port === 443 || this.target.protocol === "http:" && this.target.port === 80 ? "" : `:${this.target.port}`;
21874
+ const url = `${this.target.protocol}//${this.target.hostname}${portSuffix}${this.target.path}`;
21875
+ const bodyless = this.target.method === "GET" || this.target.method === "HEAD";
21876
+ const headers = this.getHeaders();
21877
+ delete headers.host;
21878
+ delete headers.connection;
21879
+ delete headers["content-length"];
21880
+ const response = await fetchImpl(url, {
21881
+ method: this.target.method,
21882
+ headers,
21883
+ ...bodyless || body.length === 0 ? {} : { body: new Uint8Array(body) },
21884
+ redirect: "follow"
21885
+ });
21886
+ const received = {};
21887
+ response.headers.forEach((value, key) => {
21888
+ received[key.toLowerCase()] = value;
21889
+ });
21890
+ const bytes2 = new Uint8Array(await response.arrayBuffer());
21891
+ return new VirtualClientResponse(response.status, response.statusText, received, bytes2);
21892
+ }
21893
+ };
21894
+ function lowercaseHeaders(headers) {
21895
+ return Object.fromEntries(Object.entries(headers ?? {}).map(([key, value]) => [key.toLowerCase(), String(value)]));
21896
+ }
21897
+ function createHttpModule(router, owner, options = {}, defaultProtocol = "http:") {
21419
21898
  const createServer = (listener) => new VirtualHttpServer(router, owner, listener);
21420
- const module = {
21899
+ const request = (input, second, third) => {
21900
+ const overrides = second && typeof second === "object" && !(second instanceof Function) ? second : void 0;
21901
+ const callback = [second, third].find((value) => typeof value === "function");
21902
+ const req = new VirtualClientRequest(resolveTarget(input, overrides, defaultProtocol), router, options.fetch, options.trackRequest);
21903
+ if (callback) req.on("response", callback);
21904
+ return req;
21905
+ };
21906
+ const get = (input, second, third) => {
21907
+ const req = request(input, second, third);
21908
+ req.end();
21909
+ return req;
21910
+ };
21911
+ return {
21421
21912
  createServer,
21913
+ request,
21914
+ get,
21422
21915
  Server: VirtualHttpServer,
21423
21916
  ServerResponse: VirtualServerResponse,
21424
21917
  IncomingMessage: VirtualIncomingMessage,
21918
+ ClientRequest: VirtualClientRequest,
21425
21919
  METHODS,
21426
21920
  STATUS_CODES,
21427
21921
  maxHeaderSize: 16 * 1024,
@@ -21431,10 +21925,6 @@ function createHttpModule(router, owner) {
21431
21925
  Agent: class Agent {
21432
21926
  }
21433
21927
  };
21434
- return { ...module, request: unsupportedClient, get: unsupportedClient };
21435
- }
21436
- function unsupportedClient() {
21437
- throw Object.assign(new Error("http client requests are not implemented yet"), { code: "ERR_NOT_IMPLEMENTED" });
21438
21928
  }
21439
21929
  function validateHeaderName(name) {
21440
21930
  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" });
@@ -21574,6 +22064,13 @@ var ChildProcess = class extends EventEmitter4__default.default {
21574
22064
  } catch {
21575
22065
  }
21576
22066
  done();
22067
+ },
22068
+ final: (done) => {
22069
+ try {
22070
+ handle.endStdin?.();
22071
+ } catch {
22072
+ }
22073
+ done();
21577
22074
  }
21578
22075
  });
21579
22076
  this.stdio = [this.stdin, this.stdout, this.stderr];
@@ -21812,7 +22309,7 @@ function emitKeypressEvents(stream) {
21812
22309
  }
21813
22310
  });
21814
22311
  }
21815
- function createReadlineModule(defaultInput) {
22312
+ function createReadlineModule(defaultInput, defaultOutput = () => void 0) {
21816
22313
  class Interface extends EventEmitter4__default.default {
21817
22314
  constructor(input, output, terminal = false) {
21818
22315
  super();
@@ -21823,6 +22320,14 @@ function createReadlineModule(defaultInput) {
21823
22320
  if (terminal) {
21824
22321
  emitKeypressEvents(input);
21825
22322
  input?.on?.("keypress", this.onTerminalKeypress);
22323
+ if (typeof input?.setRawMode === "function") {
22324
+ try {
22325
+ input.setRawMode(true);
22326
+ this.ownsRawMode = true;
22327
+ } catch {
22328
+ }
22329
+ }
22330
+ input?.resume?.();
21826
22331
  } else {
21827
22332
  input?.on?.("data", (chunk) => this.receive(String(chunk)));
21828
22333
  }
@@ -21834,6 +22339,10 @@ function createReadlineModule(defaultInput) {
21834
22339
  buffer = "";
21835
22340
  pending = [];
21836
22341
  lines = [];
22342
+ /** Set while `question` is waiting, so the echoed line carries the query. */
22343
+ questionPrompt = null;
22344
+ /** Raw mode is only ours to restore if we were the one to enable it. */
22345
+ ownsRawMode = false;
21837
22346
  line = "";
21838
22347
  cursor = 0;
21839
22348
  terminal;
@@ -21841,20 +22350,31 @@ function createReadlineModule(defaultInput) {
21841
22350
  /** Split incoming data into lines, answering any waiting `question`. */
21842
22351
  receive(text2) {
21843
22352
  this.buffer += text2;
21844
- let newline = this.buffer.indexOf("\n");
21845
- while (newline >= 0) {
21846
- const line = this.buffer.slice(0, newline).replace(/\r$/, "");
21847
- this.buffer = this.buffer.slice(newline + 1);
21848
- const waiting = this.pending.shift();
21849
- if (waiting) waiting(line);
21850
- else {
21851
- this.lines.push(line);
21852
- this.emit("line", line);
21853
- }
21854
- newline = this.buffer.indexOf("\n");
22353
+ let match2 = /\r\n|\r|\n/.exec(this.buffer);
22354
+ while (match2) {
22355
+ const line = this.buffer.slice(0, match2.index);
22356
+ this.buffer = this.buffer.slice(match2.index + match2[0].length);
22357
+ this.deliver(line);
22358
+ match2 = /\r\n|\r|\n/.exec(this.buffer);
22359
+ }
22360
+ }
22361
+ /** Hand a completed line to whoever is waiting for it. */
22362
+ deliver(line) {
22363
+ const waiting = this.pending.shift();
22364
+ if (waiting) {
22365
+ this.questionPrompt = null;
22366
+ waiting(line);
22367
+ return;
21855
22368
  }
22369
+ this.lines.push(line);
22370
+ this.emit("line", line);
21856
22371
  }
21857
22372
  question(query, callback) {
22373
+ if (this.terminal) {
22374
+ this.questionPrompt = query;
22375
+ this.line = "";
22376
+ this.cursor = 0;
22377
+ }
21858
22378
  this.output?.write?.(query);
21859
22379
  if (callback) {
21860
22380
  this.pending.push(callback);
@@ -21869,6 +22389,9 @@ function createReadlineModule(defaultInput) {
21869
22389
  setPrompt(text2) {
21870
22390
  this.promptText = text2;
21871
22391
  }
22392
+ getPrompt() {
22393
+ return this.promptText;
22394
+ }
21872
22395
  pause() {
21873
22396
  this.input?.pause?.();
21874
22397
  return this;
@@ -21896,21 +22419,48 @@ function createReadlineModule(defaultInput) {
21896
22419
  if (text2) {
21897
22420
  this.line = this.line.slice(0, this.cursor) + text2 + this.line.slice(this.cursor);
21898
22421
  this.cursor += text2.length;
22422
+ this.refresh();
21899
22423
  }
21900
22424
  }
21901
22425
  getCursorPos() {
21902
- return { rows: 0, cols: this.cursor + this.promptText.length };
22426
+ return { rows: 0, cols: this.cursor + this.currentPrompt().length };
21903
22427
  }
21904
22428
  close() {
21905
22429
  if (this.closed) return;
21906
22430
  this.closed = true;
21907
22431
  if (this.terminal) {
21908
22432
  this.input?.off?.("keypress", this.onTerminalKeypress);
22433
+ if (this.ownsRawMode) {
22434
+ this.ownsRawMode = false;
22435
+ try {
22436
+ this.input?.setRawMode?.(false);
22437
+ } catch {
22438
+ }
22439
+ }
21909
22440
  this.input?.pause?.();
21910
22441
  }
21911
22442
  for (const waiting of this.pending.splice(0)) waiting("");
21912
22443
  this.emit("close");
21913
22444
  }
22445
+ /** The text shown to the left of the edited line. */
22446
+ currentPrompt() {
22447
+ return this.questionPrompt ?? this.promptText;
22448
+ }
22449
+ /**
22450
+ * Repaint the edited line.
22451
+ *
22452
+ * In raw mode nothing echoes on its own, so an Interface that does not do
22453
+ * this leaves the user typing blind. Libraries that draw their own frame
22454
+ * (clack, inquirer) simply overwrite this, exactly as they do on Node.
22455
+ */
22456
+ refresh() {
22457
+ if (!this.terminal) return;
22458
+ const prompt = this.currentPrompt();
22459
+ let text2 = `\r\x1B[0K${prompt}${this.line}`;
22460
+ const back = this.line.length - this.cursor;
22461
+ if (back > 0) text2 += `\x1B[${back}D`;
22462
+ this.output?.write?.(text2);
22463
+ }
21914
22464
  edit(sequence, key) {
21915
22465
  if (this.closed) return;
21916
22466
  const name = key.name;
@@ -21918,48 +22468,62 @@ function createReadlineModule(defaultInput) {
21918
22468
  const value = this.line;
21919
22469
  this.line = "";
21920
22470
  this.cursor = 0;
21921
- this.emit("line", value);
22471
+ this.output?.write?.("\r\n");
22472
+ this.deliver(value);
21922
22473
  return;
21923
22474
  }
21924
22475
  if (name === "left") {
21925
22476
  this.cursor = Math.max(0, this.cursor - 1);
22477
+ this.refresh();
21926
22478
  return;
21927
22479
  }
21928
22480
  if (name === "right") {
21929
22481
  this.cursor = Math.min(this.line.length, this.cursor + 1);
22482
+ this.refresh();
21930
22483
  return;
21931
22484
  }
21932
22485
  if (name === "home" || key.ctrl && name === "a") {
21933
22486
  this.cursor = 0;
22487
+ this.refresh();
21934
22488
  return;
21935
22489
  }
21936
22490
  if (name === "end" || key.ctrl && name === "e") {
21937
22491
  this.cursor = this.line.length;
22492
+ this.refresh();
21938
22493
  return;
21939
22494
  }
21940
22495
  if (name === "backspace" || key.ctrl && name === "h") {
21941
22496
  if (this.cursor > 0) {
21942
22497
  this.line = this.line.slice(0, this.cursor - 1) + this.line.slice(this.cursor);
21943
22498
  this.cursor--;
22499
+ this.refresh();
21944
22500
  }
21945
22501
  return;
21946
22502
  }
21947
22503
  if (name === "delete") {
21948
- if (this.cursor < this.line.length) this.line = this.line.slice(0, this.cursor) + this.line.slice(this.cursor + 1);
22504
+ if (this.cursor < this.line.length) {
22505
+ this.line = this.line.slice(0, this.cursor) + this.line.slice(this.cursor + 1);
22506
+ this.refresh();
22507
+ }
21949
22508
  return;
21950
22509
  }
21951
22510
  if (key.ctrl && name === "u") {
21952
22511
  this.line = this.line.slice(this.cursor);
21953
22512
  this.cursor = 0;
22513
+ this.refresh();
21954
22514
  return;
21955
22515
  }
21956
22516
  if (key.ctrl && name === "k") {
21957
22517
  this.line = this.line.slice(0, this.cursor);
22518
+ this.refresh();
21958
22519
  return;
21959
22520
  }
21960
22521
  if (key.ctrl || key.meta || sequence.length !== 1 || sequence < " ") return;
22522
+ const atEnd = this.cursor === this.line.length;
21961
22523
  this.line = this.line.slice(0, this.cursor) + sequence + this.line.slice(this.cursor);
21962
22524
  this.cursor += sequence.length;
22525
+ if (atEnd) this.output?.write?.(sequence);
22526
+ else this.refresh();
21963
22527
  }
21964
22528
  async *[Symbol.asyncIterator]() {
21965
22529
  while (!this.closed || this.lines.length) {
@@ -21989,13 +22553,23 @@ function createReadlineModule(defaultInput) {
21989
22553
  }
21990
22554
  }
21991
22555
  }
22556
+ const isTerminal = (options, output) => {
22557
+ if (typeof options?.terminal === "boolean") return options.terminal;
22558
+ return Boolean(output?.isTTY);
22559
+ };
21992
22560
  const createInterface = (options, output) => {
21993
22561
  if (options && typeof options === "object" && !options.on) {
21994
- const instance = new Interface(options.input ?? defaultInput(), options.output, options.terminal === true);
22562
+ const resolvedOutput2 = options.output ?? defaultOutput();
22563
+ const instance = new Interface(
22564
+ options.input ?? defaultInput(),
22565
+ resolvedOutput2,
22566
+ isTerminal(options, resolvedOutput2)
22567
+ );
21995
22568
  if (typeof options.prompt === "string") instance.setPrompt(options.prompt);
21996
22569
  return instance;
21997
22570
  }
21998
- return new Interface(options ?? defaultInput(), output, Boolean(output));
22571
+ const resolvedOutput = output ?? defaultOutput();
22572
+ return new Interface(options ?? defaultInput(), resolvedOutput, isTerminal(void 0, resolvedOutput));
21999
22573
  };
22000
22574
  const noop = () => {
22001
22575
  };
@@ -22012,6 +22586,7 @@ function createReadlineModule(defaultInput) {
22012
22586
  }
22013
22587
 
22014
22588
  // src/runtime/core-modules.ts
22589
+ installReadableFrom(streamModule4__default.default);
22015
22590
  var Dirent = class {
22016
22591
  /** Node 20+ exposes the containing directory, and `fs.glob` consumers read it. */
22017
22592
  constructor(name, stat2, parentPath = "") {
@@ -22217,9 +22792,20 @@ function createCoreModules(options) {
22217
22792
  throw new Error("createRequire is only available inside a loaded module");
22218
22793
  }
22219
22794
  };
22220
- const http = options.http ? createHttpModule(options.http.router, options.http.owner) : createUnsupportedModule("http");
22795
+ let inFlightRequests = 0;
22796
+ const httpOptions = {
22797
+ ...options.http?.fetch ? { fetch: options.http.fetch } : {},
22798
+ trackRequest: () => {
22799
+ inFlightRequests++;
22800
+ return () => {
22801
+ inFlightRequests--;
22802
+ };
22803
+ }
22804
+ };
22805
+ const http = options.http ? createHttpModule(options.http.router, options.http.owner, httpOptions, "http:") : createUnsupportedModule("http");
22806
+ const https = options.http ? createHttpModule(options.http.router, options.http.owner, httpOptions, "https:") : createUnsupportedModule("https");
22221
22807
  const childProcess = options.spawnChild ? createChildProcessModule(options.spawnChild, () => cwd) : createUnsupportedModule("child_process");
22222
- const readline = createReadlineModule(() => processObject.stdin);
22808
+ const readline = createReadlineModule(() => processObject.stdin, () => processObject.stdout);
22223
22809
  const dns = createDnsModule();
22224
22810
  const builtins = {
22225
22811
  assert: assert_module_default,
@@ -22237,7 +22823,7 @@ function createCoreModules(options) {
22237
22823
  "fs/promises": fs.promises,
22238
22824
  module: moduleBuiltin,
22239
22825
  http,
22240
- https: http,
22826
+ https,
22241
22827
  os,
22242
22828
  path,
22243
22829
  "path/posix": path,
@@ -22276,6 +22862,9 @@ function createCoreModules(options) {
22276
22862
  globals,
22277
22863
  process: processObject,
22278
22864
  pendingHandles: timers.pending,
22865
+ pendingUnrefed: timers.pendingUnrefed,
22866
+ /** Client requests sent but not yet read to completion. */
22867
+ pendingRequests: () => inFlightRequests,
22279
22868
  writeStdin: (data) => {
22280
22869
  if (options.interactiveStdin) stdin.write(data);
22281
22870
  },
@@ -22503,9 +23092,20 @@ function createFsModule(volume, cwd, stdinPath) {
22503
23092
  if (position == null) file3.position = start2 + chunk.length;
22504
23093
  return chunk.length;
22505
23094
  },
22506
- createReadStream: (path) => {
22507
- const data = Buffer2.from(volume.readFileSync(resolveLinks(volume, abs(path))));
22508
- return streamModule4__default.default.Readable.from([data]);
23095
+ createReadStream: (path, options) => {
23096
+ const target = abs(path);
23097
+ const settings = typeof options === "string" ? { encoding: options } : options ?? {};
23098
+ const whole = Buffer2.from(volume.readFileSync(resolveLinks(volume, target)));
23099
+ const start2 = settings.start ?? 0;
23100
+ const end = settings.end === void 0 ? whole.length : Math.min(settings.end + 1, whole.length);
23101
+ const slice = whole.subarray(start2, Math.max(start2, end));
23102
+ const stream = streamModule4__default.default.Readable.from([settings.encoding ? slice.toString(settings.encoding) : slice]);
23103
+ Object.assign(stream, { path: target, bytesRead: slice.length, close: () => stream.destroy() });
23104
+ queueMicrotask(() => {
23105
+ stream.emit("open", 0);
23106
+ stream.emit("ready");
23107
+ });
23108
+ return stream;
22509
23109
  },
22510
23110
  createWriteStream: (path, options) => {
22511
23111
  const target = abs(path);
@@ -22871,33 +23471,78 @@ var ERRNO_CONSTANTS = {
22871
23471
  };
22872
23472
  function createTrackedTimers() {
22873
23473
  const live = /* @__PURE__ */ new Set();
22874
- const track = (handle, repeating) => {
23474
+ const unrefed = /* @__PURE__ */ new Set();
23475
+ const states = /* @__PURE__ */ new WeakMap();
23476
+ const track = (native) => {
23477
+ const state = { native, active: true, referenced: true };
23478
+ const handle = {
23479
+ ref() {
23480
+ state.referenced = true;
23481
+ unrefed.delete(handle);
23482
+ if (state.active) live.add(handle);
23483
+ state.native?.ref?.();
23484
+ return handle;
23485
+ },
23486
+ unref() {
23487
+ state.referenced = false;
23488
+ live.delete(handle);
23489
+ if (state.active) unrefed.add(handle);
23490
+ state.native?.unref?.();
23491
+ return handle;
23492
+ },
23493
+ hasRef: () => state.referenced,
23494
+ refresh() {
23495
+ state.native?.refresh?.();
23496
+ return handle;
23497
+ },
23498
+ [Symbol.toPrimitive]: () => Number(state.native)
23499
+ };
23500
+ states.set(handle, state);
22875
23501
  live.add(handle);
22876
23502
  return handle;
22877
23503
  };
23504
+ const complete = (handle) => {
23505
+ const state = states.get(handle);
23506
+ if (state) state.active = false;
23507
+ live.delete(handle);
23508
+ unrefed.delete(handle);
23509
+ };
22878
23510
  const setTimeoutTracked = (fn, delay, ...args) => {
22879
- const handle = setTimeout(
23511
+ let handle;
23512
+ const native = setTimeout(
22880
23513
  (...inner) => {
22881
- live.delete(handle);
23514
+ complete(handle);
22882
23515
  fn(...inner);
22883
23516
  },
22884
23517
  delay,
22885
23518
  ...args
22886
23519
  );
22887
- live.add(handle);
23520
+ handle = track(native);
22888
23521
  return handle;
22889
23522
  };
22890
23523
  const setIntervalTracked = (fn, delay, ...args) => track(setInterval(fn, delay, ...args));
22891
23524
  const hostSetImmediate = globalThis.setImmediate;
22892
23525
  const setImmediateTracked = (fn, ...args) => {
22893
- const handle = hostSetImmediate ? hostSetImmediate((...inner) => {
22894
- live.delete(handle);
23526
+ if (!hostSetImmediate) return setTimeoutTracked(fn, 0, ...args);
23527
+ let handle;
23528
+ const native = hostSetImmediate((...inner) => {
23529
+ complete(handle);
22895
23530
  fn(...inner);
22896
- }, ...args) : setTimeoutTracked(fn, 0, ...args);
22897
- live.add(handle);
23531
+ }, ...args);
23532
+ handle = track(native);
22898
23533
  return handle;
22899
23534
  };
22900
23535
  const clear2 = (handle, native) => {
23536
+ if (typeof handle === "object" && handle !== null) {
23537
+ const state = states.get(handle);
23538
+ if (state) {
23539
+ state.active = false;
23540
+ live.delete(handle);
23541
+ unrefed.delete(handle);
23542
+ native(state.native);
23543
+ return;
23544
+ }
23545
+ }
22901
23546
  live.delete(handle);
22902
23547
  native(handle);
22903
23548
  };
@@ -22910,7 +23555,8 @@ function createTrackedTimers() {
22910
23555
  clearInterval: (handle) => clear2(handle, clearInterval),
22911
23556
  clearImmediate: (handle) => clear2(handle, globalThis.clearImmediate ?? clearTimeout)
22912
23557
  },
22913
- pending: () => live.size
23558
+ pending: () => live.size,
23559
+ pendingUnrefed: () => unrefed.size
22914
23560
  };
22915
23561
  }
22916
23562
  function createTimerPromises() {
@@ -23432,7 +24078,26 @@ function ensureProcessGlobal() {
23432
24078
  });
23433
24079
  }
23434
24080
 
24081
+ // src/runtime/host-rolldown.ts
24082
+ async function loadHostRolldownBinding() {
24083
+ if (typeof window !== "undefined" && globalThis.crossOriginIsolated !== true) {
24084
+ throw new Error(
24085
+ "Vite 8/Rolldown requires cross-origin isolation. Serve the app with Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp headers."
24086
+ );
24087
+ }
24088
+ try {
24089
+ const loaded = await import('@rolldown/binding-wasm32-wasi');
24090
+ return "__fs" in loaded ? { ...loaded } : loaded.default ?? loaded;
24091
+ } catch (error) {
24092
+ if (typeof process !== "undefined" && process.env?.SANDBOXEDJS_DEBUG) {
24093
+ console.error("[sandboxedjs] Rolldown WASI binding unavailable:", error);
24094
+ }
24095
+ throw new Error("The optional Rolldown WASI binding could not be loaded.", { cause: error });
24096
+ }
24097
+ }
24098
+
23435
24099
  // src/runtime/local-runtime-pod.ts
24100
+ init_path();
23436
24101
  var WASM_ALIASES = {
23437
24102
  esbuild: "esbuild-wasm",
23438
24103
  rollup: "@rollup/wasm-node"
@@ -23557,6 +24222,11 @@ var PodChildProcess = class {
23557
24222
  started = false;
23558
24223
  cancelled = false;
23559
24224
  child;
24225
+ /* The child is launched asynchronously, but a parent may write and close
24226
+ * its input synchronously right after spawning. Holding both until the
24227
+ * child exists is what keeps `echo hi | child` from losing the `hi`. */
24228
+ pendingInput = "";
24229
+ inputEnded = false;
23560
24230
  on(event, listener) {
23561
24231
  let set = this.listeners.get(event);
23562
24232
  if (!set) this.listeners.set(event, set = /* @__PURE__ */ new Set());
@@ -23579,6 +24249,11 @@ var PodChildProcess = class {
23579
24249
  (child) => {
23580
24250
  this.child = child;
23581
24251
  if (this.cancelled) child.kill();
24252
+ if (this.pendingInput !== "") {
24253
+ child.write(this.pendingInput);
24254
+ this.pendingInput = "";
24255
+ }
24256
+ if (this.inputEnded) child.endInput?.();
23582
24257
  child.on("output", (text2) => {
23583
24258
  this.stdout += text2;
23584
24259
  this.emit("stdout", text2);
@@ -23601,7 +24276,13 @@ var PodChildProcess = class {
23601
24276
  });
23602
24277
  }
23603
24278
  sendStdin(data) {
23604
- this.child?.write(data);
24279
+ if (this.child) this.child.write(data);
24280
+ else this.pendingInput += data;
24281
+ }
24282
+ /** Signal EOF, so a child reading stdin to the end can finish. */
24283
+ endStdin() {
24284
+ if (this.child) this.child.endInput?.();
24285
+ else this.inputEnded = true;
23605
24286
  }
23606
24287
  kill(signal = "SIGTERM") {
23607
24288
  if (this.child) this.child.kill(signal);
@@ -23683,6 +24364,9 @@ var LocalRuntimePod = class _LocalRuntimePod {
23683
24364
  aliases;
23684
24365
  modules;
23685
24366
  esbuild;
24367
+ rolldownBinding;
24368
+ /** Backs outbound `http`/`https` client requests from inside the sandbox. */
24369
+ fetch;
23686
24370
  constructor(options) {
23687
24371
  ensureProcessGlobal();
23688
24372
  this.workdir = options.workdir ?? "/";
@@ -23697,6 +24381,7 @@ var LocalRuntimePod = class _LocalRuntimePod {
23697
24381
  const notify = options.onServerReady;
23698
24382
  this.router.onListen = (port) => notify(port, `http://localhost:${port}`);
23699
24383
  }
24384
+ if (options.fetch) this.fetch = options.fetch;
23700
24385
  this.packages = new CleanPackageInstaller(this.volume, {
23701
24386
  cwd: this.workdir,
23702
24387
  ...options.registry ? { registry: options.registry } : {},
@@ -23716,6 +24401,7 @@ var LocalRuntimePod = class _LocalRuntimePod {
23716
24401
  const env2 = { ...this.env, ...isRecord(options.env) ? options.env : {} };
23717
24402
  const owner = `${this.instanceId}:${Math.random().toString(36).slice(2)}`;
23718
24403
  return new LocalProcess(async (proc) => {
24404
+ await this.prepareRolldown(cwd, env2);
23719
24405
  const untrack = trackProcess(proc);
23720
24406
  let requestedExit = 0;
23721
24407
  let engine;
@@ -23735,7 +24421,7 @@ var LocalRuntimePod = class _LocalRuntimePod {
23735
24421
  proc.exitNow(code);
23736
24422
  if (engine?.isEvaluating) throw new ProcessExit(code);
23737
24423
  },
23738
- http: { router: this.router, owner },
24424
+ http: { router: this.router, owner, ...this.fetch ? { fetch: this.fetch } : {} },
23739
24425
  spawnChild: (config) => this.processManager.spawn(config),
23740
24426
  ...typeof options.stdinPath === "string" ? { stdinPath: options.stdinPath } : {},
23741
24427
  ...options.interactiveStdin ? { interactiveStdin: true } : {},
@@ -23752,7 +24438,7 @@ var LocalRuntimePod = class _LocalRuntimePod {
23752
24438
  });
23753
24439
  try {
23754
24440
  await engine.run(script);
23755
- await this.settle(owner, core.pendingHandles, core.readingStdin);
24441
+ await this.settle(owner, core.pendingHandles, core.pendingUnrefed, core.readingStdin, core.pendingRequests);
23756
24442
  if (this.router.activePorts(owner).length) {
23757
24443
  await proc.waitForKill();
23758
24444
  return 137;
@@ -23764,6 +24450,25 @@ var LocalRuntimePod = class _LocalRuntimePod {
23764
24450
  }
23765
24451
  });
23766
24452
  }
24453
+ /**
24454
+ * Rolldown's JavaScript API synchronously requires its compiled binding.
24455
+ * When a project contains Rolldown, preload the official WASI build in the
24456
+ * host and expose it through the module override table before evaluation.
24457
+ * Keeping this demand-driven avoids adding WASM startup cost to ordinary
24458
+ * shells and Node programs.
24459
+ */
24460
+ async prepareRolldown(cwd, env2) {
24461
+ const specifier = "@rolldown/binding-wasm32-wasi";
24462
+ if (!this.modules[specifier] && packageInstalled(this.volume, cwd, "rolldown")) {
24463
+ this.rolldownBinding ??= loadHostRolldownBinding();
24464
+ const binding = await this.rolldownBinding;
24465
+ if (binding) this.modules[specifier] = binding;
24466
+ }
24467
+ if (this.modules[specifier]) {
24468
+ syncRolldownFileSystem(this.modules[specifier], this.volume, cwd);
24469
+ env2.NAPI_RS_FORCE_WASI ??= "true";
24470
+ }
24471
+ }
23767
24472
  /**
23768
24473
  * Wait until the process has either started serving or genuinely run out of
23769
24474
  * work.
@@ -23779,12 +24484,18 @@ var LocalRuntimePod = class _LocalRuntimePod {
23779
24484
  * A plain script that has genuinely finished falls straight through both,
23780
24485
  * costing a handful of empty turns.
23781
24486
  */
23782
- async settle(owner, pendingHandles, readingStdin) {
24487
+ async settle(owner, pendingHandles, pendingUnrefed, readingStdin, pendingRequests) {
23783
24488
  for (let turn = 0; turn < DRAIN_TURNS; turn++) {
23784
24489
  if (this.router.activePorts(owner).length) return;
23785
24490
  await new Promise((resolve2) => setTimeout(resolve2, 0));
23786
24491
  }
23787
- while (!this.router.activePorts(owner).length && (pendingHandles() > 0 || readingStdin())) {
24492
+ if (pendingHandles() === 0 && pendingRequests() === 0 && pendingUnrefed() > 0 && !readingStdin()) {
24493
+ const deadline = Date.now() + 1e3;
24494
+ while (!this.router.activePorts(owner).length && Date.now() < deadline) {
24495
+ await new Promise((resolve2) => setTimeout(resolve2, 5));
24496
+ }
24497
+ }
24498
+ while (!this.router.activePorts(owner).length && (pendingHandles() > 0 || pendingRequests() > 0 || readingStdin())) {
23788
24499
  await new Promise((resolve2) => setTimeout(resolve2, 5));
23789
24500
  }
23790
24501
  }
@@ -23836,6 +24547,60 @@ function formatError(error) {
23836
24547
  function isRecord(value) {
23837
24548
  return typeof value === "object" && value !== null && !Array.isArray(value);
23838
24549
  }
24550
+ function packageInstalled(volume, cwd, wanted) {
24551
+ for (let dir3 = clean(cwd); ; dir3 = dirname(dir3)) {
24552
+ if (packageTreeContains(volume, join(dir3, "node_modules"), wanted, /* @__PURE__ */ new Set())) return true;
24553
+ if (dir3 === "/") return false;
24554
+ }
24555
+ }
24556
+ function packageTreeContains(volume, modulesRoot, wanted, visited) {
24557
+ if (visited.has(modulesRoot) || !directory(volume, modulesRoot)) return false;
24558
+ visited.add(modulesRoot);
24559
+ if (directory(volume, join(modulesRoot, wanted))) return true;
24560
+ for (const entry of volume.readdirSync(modulesRoot)) {
24561
+ if (entry === ".bin") continue;
24562
+ const first = join(modulesRoot, entry);
24563
+ const packages = entry.startsWith("@") && directory(volume, first) ? volume.readdirSync(first).map((name) => join(first, name)) : [first];
24564
+ for (const root of packages) {
24565
+ if (directory(volume, root) && packageTreeContains(volume, join(root, "node_modules"), wanted, visited)) {
24566
+ return true;
24567
+ }
24568
+ }
24569
+ }
24570
+ return false;
24571
+ }
24572
+ function directory(volume, path) {
24573
+ try {
24574
+ return volume.lstatSync(path).isDirectory();
24575
+ } catch {
24576
+ return false;
24577
+ }
24578
+ }
24579
+ function syncRolldownFileSystem(binding, volume, root) {
24580
+ const fs = binding?.__fs;
24581
+ if (!fs?.mkdirSync || !fs?.writeFileSync) return;
24582
+ try {
24583
+ fs.rmSync?.(root, { recursive: true, force: true });
24584
+ } catch {
24585
+ }
24586
+ const copy = (path) => {
24587
+ const stat2 = volume.lstatSync(path);
24588
+ if (stat2.isDirectory()) {
24589
+ fs.mkdirSync(path, { recursive: true });
24590
+ for (const name of volume.readdirSync(path)) copy(join(path, name));
24591
+ } else if (stat2.isSymbolicLink()) {
24592
+ fs.mkdirSync(dirname(path), { recursive: true });
24593
+ try {
24594
+ fs.symlinkSync(volume.readlinkSync(path), path);
24595
+ } catch {
24596
+ }
24597
+ } else if (!path.endsWith(".node")) {
24598
+ fs.mkdirSync(dirname(path), { recursive: true });
24599
+ fs.writeFileSync(path, volume.readFileSync(path));
24600
+ }
24601
+ };
24602
+ copy(clean(root));
24603
+ }
23839
24604
 
23840
24605
  // src/container/container.ts
23841
24606
  var Container = class _Container {
@@ -24179,7 +24944,7 @@ var Container = class _Container {
24179
24944
  /**
24180
24945
  * Deliver a request whose body is bytes, without letting them become text.
24181
24946
  *
24182
- * Nodepod's public `request()` runs the body through `toString("utf8")` on
24947
+ * A RuntimePod's public `request()` may run the body through `toString("utf8")` on
24183
24948
  * its way in, so anything above `0x7f` is replaced: a five-byte payload
24184
24949
  * containing `0x89` and `0xff` arrives as nine. That silently destroys every
24185
24950
  * upload — an image or a video reaches the server the wrong size and no
@@ -24281,7 +25046,7 @@ var Container = class _Container {
24281
25046
  assertActive() {
24282
25047
  if (this.disposed) throw new Error("container has been disposed");
24283
25048
  }
24284
- /** Tear down every process and release the Nodepod instance. */
25049
+ /** Tear down every process and release the runtime pod. */
24285
25050
  dispose() {
24286
25051
  if (this.disposed) return;
24287
25052
  this.disposed = true;
@@ -24391,17 +25156,18 @@ var Terminal = class {
24391
25156
  // ── key handling ──────────────────────────────────────────────────────────
24392
25157
  key(ch) {
24393
25158
  if (this.running) {
24394
- if (ch === CTRL_C) {
25159
+ const raw = this.currentStdin?.rawMode === true;
25160
+ if (ch === CTRL_C && !raw) {
24395
25161
  this.session.proc.deliver("SIGINT");
24396
25162
  this.write("^C\r\n");
24397
25163
  return;
24398
25164
  }
24399
- if (ch === CTRL_D) {
25165
+ if (ch === CTRL_D && !raw) {
24400
25166
  this.currentStdin?.end();
24401
25167
  return;
24402
25168
  }
24403
- if (!this.currentStdin?.rawMode) this.write(ch === "\r" ? "\r\n" : ch);
24404
- this.currentStdin?.write(ch === "\r" ? "\n" : ch);
25169
+ if (!raw) this.write(ch === "\r" ? "\r\n" : ch);
25170
+ this.currentStdin?.write(!raw && ch === "\r" ? "\n" : ch);
24405
25171
  return;
24406
25172
  }
24407
25173
  if (this.escapeBuffer !== "") {