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.js CHANGED
@@ -6806,7 +6806,7 @@ var NetworkStack = class {
6806
6806
  }
6807
6807
  return [...out.values()].sort((a, b) => a.port - b.port);
6808
6808
  }
6809
- /** Ports Nodepod's proxy has registered for this instance. */
6809
+ /** Ports the pod's proxy has registered for this instance. */
6810
6810
  knownPodPorts() {
6811
6811
  try {
6812
6812
  return this.pod.proxy.activePorts(this.pod.instanceId) ?? [];
@@ -7332,15 +7332,15 @@ var Parser = class {
7332
7332
  if (this.isWord("-p")) this.next();
7333
7333
  }
7334
7334
  }
7335
- const commands11 = [this.parseCommand()];
7335
+ const commands12 = [this.parseCommand()];
7336
7336
  const stderrToo = [];
7337
7337
  while (this.isOp("|") || this.isOp("|&")) {
7338
7338
  stderrToo.push(this.next().value === "|&");
7339
7339
  this.skipNewlines();
7340
- commands11.push(this.parseCommand());
7340
+ commands12.push(this.parseCommand());
7341
7341
  }
7342
- if (commands11.length === 1 && !negated && !timed) return commands11[0];
7343
- return { type: "pipeline", commands: commands11, negated, stderrToo, timed };
7342
+ if (commands12.length === 1 && !negated && !timed) return commands12[0];
7343
+ return { type: "pipeline", commands: commands12, negated, stderrToo, timed };
7344
7344
  }
7345
7345
  // ── commands ─────────────────────────────────────────────────────────────
7346
7346
  parseCommand() {
@@ -16963,6 +16963,145 @@ var helpCmd = defineCommand({
16963
16963
  });
16964
16964
  var commands10 = [man, whatis, apropos, less, helpCmd];
16965
16965
 
16966
+ // src/bin/clipboard.ts
16967
+ init_path();
16968
+ var CLIPBOARD_DIR = "/run/clipboard";
16969
+ function selectionPath(selection) {
16970
+ return join(CLIPBOARD_DIR, selection);
16971
+ }
16972
+ function readSelection(ctx, selection) {
16973
+ try {
16974
+ return ctx.vfs.readFile(selectionPath(selection), ctx.cred);
16975
+ } catch {
16976
+ return new Uint8Array();
16977
+ }
16978
+ }
16979
+ function writeSelection(ctx, selection, bytes2) {
16980
+ try {
16981
+ ctx.vfs.mkdir(CLIPBOARD_DIR, { recursive: true, mode: 511 });
16982
+ } catch {
16983
+ }
16984
+ ctx.vfs.writeFile(selectionPath(selection), bytes2, { privileged: true, mode: 438 });
16985
+ }
16986
+ var xsel = defineCommand({
16987
+ name: "xsel",
16988
+ summary: "access an X selection",
16989
+ usage: "xsel [--clipboard|--primary|--secondary] [--input|--output|--clear]",
16990
+ async run(ctx) {
16991
+ let selection = "primary";
16992
+ let mode = "output";
16993
+ for (const arg of ctx.args) {
16994
+ switch (arg) {
16995
+ case "-b":
16996
+ case "--clipboard":
16997
+ selection = "clipboard";
16998
+ break;
16999
+ case "-p":
17000
+ case "--primary":
17001
+ selection = "primary";
17002
+ break;
17003
+ case "-s":
17004
+ case "--secondary":
17005
+ selection = "secondary";
17006
+ break;
17007
+ case "-i":
17008
+ case "--input":
17009
+ case "-a":
17010
+ case "--append":
17011
+ mode = "input";
17012
+ break;
17013
+ case "-o":
17014
+ case "--output":
17015
+ mode = "output";
17016
+ break;
17017
+ case "-c":
17018
+ case "--clear":
17019
+ mode = "clear";
17020
+ break;
17021
+ }
17022
+ }
17023
+ if (mode === "clear") {
17024
+ writeSelection(ctx, selection, new Uint8Array());
17025
+ return 0;
17026
+ }
17027
+ if (mode === "input") {
17028
+ writeSelection(ctx, selection, await ctx.stdin.readAll());
17029
+ return 0;
17030
+ }
17031
+ ctx.write(readSelection(ctx, selection));
17032
+ return 0;
17033
+ }
17034
+ });
17035
+ var xclip = defineCommand({
17036
+ name: "xclip",
17037
+ summary: "access an X selection",
17038
+ usage: "xclip [-selection clipboard|primary|secondary] [-i|-o]",
17039
+ async run(ctx) {
17040
+ let selection = "primary";
17041
+ let mode = "input";
17042
+ const args = ctx.args;
17043
+ for (let index = 0; index < args.length; index++) {
17044
+ const arg = args[index];
17045
+ if (arg === "-selection" || arg === "-sel" || arg === "--selection") {
17046
+ const value = args[++index];
17047
+ if (value === "clipboard" || value === "primary" || value === "secondary") selection = value;
17048
+ continue;
17049
+ }
17050
+ if (arg === "-i" || arg === "-in") mode = "input";
17051
+ else if (arg === "-o" || arg === "-out") mode = "output";
17052
+ }
17053
+ if (mode === "input") {
17054
+ writeSelection(ctx, selection, await ctx.stdin.readAll());
17055
+ return 0;
17056
+ }
17057
+ ctx.write(readSelection(ctx, selection));
17058
+ return 0;
17059
+ }
17060
+ });
17061
+ var pbcopy = defineCommand({
17062
+ name: "pbcopy",
17063
+ summary: "copy standard input to the clipboard",
17064
+ usage: "pbcopy",
17065
+ async run(ctx) {
17066
+ writeSelection(ctx, "clipboard", await ctx.stdin.readAll());
17067
+ return 0;
17068
+ }
17069
+ });
17070
+ var pbpaste = defineCommand({
17071
+ name: "pbpaste",
17072
+ summary: "write the clipboard to standard output",
17073
+ usage: "pbpaste",
17074
+ run(ctx) {
17075
+ ctx.write(readSelection(ctx, "clipboard"));
17076
+ return 0;
17077
+ }
17078
+ });
17079
+ var wlCopy = defineCommand({
17080
+ name: "wl-copy",
17081
+ summary: "copy standard input to the Wayland clipboard",
17082
+ usage: "wl-copy [--primary] [text...]",
17083
+ async run(ctx) {
17084
+ const selection = ctx.args.includes("--primary") || ctx.args.includes("-p") ? "primary" : "clipboard";
17085
+ const operands = ctx.args.filter((arg) => !arg.startsWith("-"));
17086
+ const bytes2 = operands.length ? new TextEncoder().encode(operands.join(" ")) : await ctx.stdin.readAll();
17087
+ writeSelection(ctx, selection, bytes2);
17088
+ return 0;
17089
+ }
17090
+ });
17091
+ var wlPaste = defineCommand({
17092
+ name: "wl-paste",
17093
+ summary: "write the Wayland clipboard to standard output",
17094
+ usage: "wl-paste [--primary] [-n]",
17095
+ run(ctx) {
17096
+ const selection = ctx.args.includes("--primary") || ctx.args.includes("-p") ? "primary" : "clipboard";
17097
+ const bytes2 = readSelection(ctx, selection);
17098
+ ctx.write(bytes2);
17099
+ if (!ctx.args.includes("-n") && !ctx.args.includes("--no-newline")) ctx.write("\n");
17100
+ return 0;
17101
+ }
17102
+ });
17103
+ var commands11 = [xsel, xclip, pbcopy, pbpaste, wlCopy, wlPaste];
17104
+
16966
17105
  // src/runtime/node.ts
16967
17106
  init_path();
16968
17107
  var NODE_VERSION = "v22.12.0";
@@ -18163,7 +18302,33 @@ function ffmpegCommands() {
18163
18302
  return [ffmpeg, ffprobe];
18164
18303
  }
18165
18304
  var platformBuffer = globalThis.Buffer;
18166
- var Buffer2 = platformBuffer ?? Buffer$1;
18305
+ var Buffer2 = platformBuffer ?? addBase64UrlSupport(Buffer$1);
18306
+ function addBase64UrlSupport(BufferClass) {
18307
+ const target = BufferClass;
18308
+ if (target.__sandboxedBase64Url) return BufferClass;
18309
+ Object.defineProperty(target, "__sandboxedBase64Url", { value: true });
18310
+ const from = target.from.bind(target);
18311
+ target.from = (value, encodingOrOffset, length) => from(value, normalizeEncoding(encodingOrOffset), length);
18312
+ const byteLength = target.byteLength.bind(target);
18313
+ target.byteLength = (value, encoding) => byteLength(value, normalizeEncoding(encoding));
18314
+ const isEncoding = target.isEncoding?.bind(target);
18315
+ if (isEncoding) target.isEncoding = (encoding) => encoding.toLowerCase() === "base64url" || isEncoding(encoding);
18316
+ const toString = target.prototype.toString;
18317
+ target.prototype.toString = function(encoding, start2, end) {
18318
+ if (encoding?.toLowerCase() !== "base64url") return toString.call(this, encoding, start2, end);
18319
+ return toString.call(this, "base64", start2, end).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
18320
+ };
18321
+ const write = target.prototype.write;
18322
+ target.prototype.write = function(...args) {
18323
+ const index = typeof args[1] === "string" ? 1 : typeof args[2] === "string" ? 2 : 3;
18324
+ if (typeof args[index] === "string") args[index] = normalizeEncoding(args[index]);
18325
+ return write.apply(this, args);
18326
+ };
18327
+ return BufferClass;
18328
+ }
18329
+ function normalizeEncoding(value) {
18330
+ return typeof value === "string" && value.toLowerCase() === "base64url" ? "base64" : value;
18331
+ }
18167
18332
 
18168
18333
  // src/pkg/clean-installer.ts
18169
18334
  init_path();
@@ -18205,6 +18370,9 @@ var CleanPackageInstaller = class _CleanPackageInstaller {
18205
18370
  const version = resolveVersion(metadata, range);
18206
18371
  const manifest = metadata.versions[version];
18207
18372
  if (!manifest) throw new Error(`No matching version found for ${name}@${range}`);
18373
+ if (!supportsPlatform(manifest)) {
18374
+ throw new Error(`${name}@${version} is not compatible with linux/x64/glibc`);
18375
+ }
18208
18376
  const identity = `${name}@${version}`;
18209
18377
  const target = join(modulesRoot, name);
18210
18378
  const installed2 = this.tryReadJson(join(target, "package.json"));
@@ -18299,6 +18467,15 @@ var CleanPackageInstaller = class _CleanPackageInstaller {
18299
18467
  }
18300
18468
  }
18301
18469
  };
18470
+ function supportsPlatform(manifest) {
18471
+ return !manifest.main?.endsWith(".node") && platformListAllows(manifest.os, "linux") && platformListAllows(manifest.cpu, "x64") && platformListAllows(manifest.libc, "glibc");
18472
+ }
18473
+ function platformListAllows(values, current) {
18474
+ if (!values?.length) return true;
18475
+ if (values.includes(`!${current}`)) return false;
18476
+ const positive = values.filter((value) => !value.startsWith("!"));
18477
+ return positive.length === 0 || positive.includes(current) || positive.includes("any");
18478
+ }
18302
18479
  function resolveVersion(metadata, range) {
18303
18480
  const tag2 = metadata["dist-tags"]?.[range];
18304
18481
  if (tag2) return tag2;
@@ -19281,6 +19458,7 @@ function allCommands() {
19281
19458
  ...commands8,
19282
19459
  ...commands9,
19283
19460
  ...commands10,
19461
+ ...commands11,
19284
19462
  ...nodeCommands(),
19285
19463
  ...pythonCommands(),
19286
19464
  ...ffmpegCommands(),
@@ -19577,6 +19755,13 @@ var KernelChildProcess = class {
19577
19755
  } catch {
19578
19756
  }
19579
19757
  }
19758
+ /** Signal EOF, so a child reading stdin to the end can finish. */
19759
+ endStdin() {
19760
+ try {
19761
+ this.stdin.end();
19762
+ } catch {
19763
+ }
19764
+ }
19580
19765
  kill(signal = "SIGTERM") {
19581
19766
  if (this.process) {
19582
19767
  this.process.deliver(signal);
@@ -20488,6 +20673,55 @@ function splitSpecifier(specifier) {
20488
20673
  return { name: parts.slice(0, size).join("/"), subpath: parts.slice(size).join("/") };
20489
20674
  }
20490
20675
 
20676
+ // src/runtime/readable-from.ts
20677
+ function createReadableFrom(Readable) {
20678
+ return function from(source, options = {}) {
20679
+ if (source && typeof source.pipe === "function") return source;
20680
+ const iterator = source && typeof source[Symbol.asyncIterator] === "function" ? source[Symbol.asyncIterator]() : source && typeof source[Symbol.iterator] === "function" ? source[Symbol.iterator]() : (function* () {
20681
+ yield source;
20682
+ })();
20683
+ let reading = false;
20684
+ const stream = new Readable({
20685
+ ...options,
20686
+ objectMode: options.objectMode ?? false,
20687
+ read() {
20688
+ if (reading) return;
20689
+ reading = true;
20690
+ void (async () => {
20691
+ try {
20692
+ for (; ; ) {
20693
+ const next = await iterator.next();
20694
+ if (next.done) {
20695
+ stream.push(null);
20696
+ return;
20697
+ }
20698
+ const value = next.value;
20699
+ if (!stream.push(value === void 0 ? null : value)) return;
20700
+ }
20701
+ } catch (error) {
20702
+ stream.destroy(error);
20703
+ } finally {
20704
+ reading = false;
20705
+ }
20706
+ })();
20707
+ },
20708
+ destroy(error, callback) {
20709
+ void (async () => {
20710
+ try {
20711
+ await iterator.return?.();
20712
+ } catch {
20713
+ }
20714
+ callback(error);
20715
+ })();
20716
+ }
20717
+ });
20718
+ return stream;
20719
+ };
20720
+ }
20721
+ function installReadableFrom(streamModule5) {
20722
+ streamModule5.Readable.from = createReadableFrom(streamModule5.Readable);
20723
+ }
20724
+
20491
20725
  // src/runtime/util-module.ts
20492
20726
  var customInspect = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
20493
20727
  var promisifyCustom = /* @__PURE__ */ Symbol.for("nodejs.util.promisify.custom");
@@ -21375,6 +21609,10 @@ var VirtualHttpRouter = class {
21375
21609
  unregister(port, server) {
21376
21610
  if (this.servers.get(port)?.server === server) this.servers.delete(port);
21377
21611
  }
21612
+ /** Whether anything in this container is listening on `port`. */
21613
+ activePortsIncludes(port) {
21614
+ return this.servers.has(port);
21615
+ }
21378
21616
  activePorts(owner) {
21379
21617
  return [...this.servers].filter(([, item]) => owner === void 0 || item.owner === owner).map(([port]) => port).sort((a, b) => a - b);
21380
21618
  }
@@ -21398,13 +21636,269 @@ var VirtualHttpRouter = class {
21398
21636
  }
21399
21637
  }
21400
21638
  };
21401
- function createHttpModule(router, owner) {
21639
+ var VirtualClientResponse = class extends streamModule4.Readable {
21640
+ constructor(statusCode, statusMessage, headers, body) {
21641
+ super();
21642
+ this.statusCode = statusCode;
21643
+ this.statusMessage = statusMessage;
21644
+ this.headers = headers;
21645
+ this.rawHeaders = Object.entries(headers).flatMap(([key, value]) => [key, value]);
21646
+ if (body.length) this.push(Buffer2.from(body));
21647
+ this.push(null);
21648
+ this.complete = true;
21649
+ }
21650
+ statusCode;
21651
+ statusMessage;
21652
+ headers;
21653
+ httpVersion = "1.1";
21654
+ httpVersionMajor = 1;
21655
+ httpVersionMinor = 1;
21656
+ socket = socketStub();
21657
+ connection = this.socket;
21658
+ rawHeaders;
21659
+ complete = false;
21660
+ _read() {
21661
+ }
21662
+ setTimeout(_milliseconds, callback) {
21663
+ if (callback) this.once("timeout", callback);
21664
+ return this;
21665
+ }
21666
+ };
21667
+ function resolveTarget(input, overrides, defaultProtocol) {
21668
+ const options = {};
21669
+ if (typeof input === "string" || input instanceof URL) {
21670
+ const url = new URL(String(input));
21671
+ options.protocol = url.protocol;
21672
+ options.hostname = url.hostname;
21673
+ if (url.port) options.port = Number(url.port);
21674
+ options.path = `${url.pathname}${url.search}`;
21675
+ if (url.username || url.password) options.auth = `${url.username}:${url.password}`;
21676
+ } else if (input && typeof input === "object") {
21677
+ Object.assign(options, input);
21678
+ }
21679
+ if (overrides) Object.assign(options, overrides);
21680
+ const protocol = String(options.protocol ?? defaultProtocol).replace(/:?$/, ":");
21681
+ const headers = {};
21682
+ for (const [name, value] of Object.entries(options.headers ?? {})) {
21683
+ if (value === void 0 || value === null) continue;
21684
+ headers[String(name)] = Array.isArray(value) ? value.join(", ") : String(value);
21685
+ }
21686
+ if (options.auth && headers.authorization === void 0) {
21687
+ headers.authorization = `Basic ${Buffer2.from(String(options.auth)).toString("base64")}`;
21688
+ }
21689
+ const rawHost = String(options.hostname ?? options.host ?? "localhost");
21690
+ const hostMatch = /^(\[[^\]]*\]|[^:]*)(?::(\d+))?$/.exec(rawHost);
21691
+ const hostname = (hostMatch?.[1] ?? rawHost).replace(/^\[|\]$/g, "");
21692
+ const explicitPort = options.port ?? hostMatch?.[2];
21693
+ const port = explicitPort === void 0 || explicitPort === null || explicitPort === "" || Number.isNaN(Number(explicitPort)) ? protocol === "https:" ? 443 : 80 : Number(explicitPort);
21694
+ return {
21695
+ protocol,
21696
+ hostname,
21697
+ port,
21698
+ path: String(options.path ?? "/"),
21699
+ method: String(options.method ?? "GET").toUpperCase(),
21700
+ headers
21701
+ };
21702
+ }
21703
+ function isLoopback(hostname) {
21704
+ return hostname === "localhost" || hostname === "0.0.0.0" || hostname === "::1" || hostname === "::" || hostname.startsWith("127.") || hostname.endsWith(".localhost");
21705
+ }
21706
+ var VirtualClientRequest = class extends streamModule4.Writable {
21707
+ constructor(target, router, fetchImpl, trackRequest) {
21708
+ super();
21709
+ this.target = target;
21710
+ this.router = router;
21711
+ this.fetchImpl = fetchImpl;
21712
+ this.trackRequest = trackRequest;
21713
+ for (const [name, value] of Object.entries(target.headers)) this.setHeader(name, value);
21714
+ }
21715
+ target;
21716
+ router;
21717
+ fetchImpl;
21718
+ trackRequest;
21719
+ socket = socketStub();
21720
+ connection = this.socket;
21721
+ chunks = [];
21722
+ headerMap = /* @__PURE__ */ new Map();
21723
+ dispatched = false;
21724
+ destroyedByUser = false;
21725
+ timer;
21726
+ aborted = false;
21727
+ finished = false;
21728
+ reusedSocket = false;
21729
+ get method() {
21730
+ return this.target.method;
21731
+ }
21732
+ get path() {
21733
+ return this.target.path;
21734
+ }
21735
+ get host() {
21736
+ return this.target.hostname;
21737
+ }
21738
+ get protocol() {
21739
+ return this.target.protocol;
21740
+ }
21741
+ setHeader(name, value) {
21742
+ validateHeaderName(name);
21743
+ validateHeaderValue(name, value);
21744
+ this.headerMap.set(name.toLowerCase(), { name, value: Array.isArray(value) ? [...value].map(String).join(", ") : String(value) });
21745
+ return this;
21746
+ }
21747
+ getHeader(name) {
21748
+ return this.headerMap.get(name.toLowerCase())?.value;
21749
+ }
21750
+ getHeaders() {
21751
+ return Object.fromEntries([...this.headerMap].map(([key, entry]) => [key, entry.value]));
21752
+ }
21753
+ getHeaderNames() {
21754
+ return [...this.headerMap.keys()];
21755
+ }
21756
+ hasHeader(name) {
21757
+ return this.headerMap.has(name.toLowerCase());
21758
+ }
21759
+ removeHeader(name) {
21760
+ this.headerMap.delete(name.toLowerCase());
21761
+ }
21762
+ flushHeaders() {
21763
+ }
21764
+ setNoDelay() {
21765
+ }
21766
+ setSocketKeepAlive() {
21767
+ }
21768
+ ref() {
21769
+ return this;
21770
+ }
21771
+ unref() {
21772
+ return this;
21773
+ }
21774
+ setTimeout(milliseconds, callback) {
21775
+ if (callback) this.once("timeout", callback);
21776
+ clearTimeout(this.timer);
21777
+ this.timer = setTimeout(() => this.emit("timeout"), milliseconds);
21778
+ return this;
21779
+ }
21780
+ abort() {
21781
+ this.destroyRequest();
21782
+ }
21783
+ destroy(error) {
21784
+ this.destroyRequest(error);
21785
+ return this;
21786
+ }
21787
+ destroyRequest(error) {
21788
+ if (this.destroyedByUser) return;
21789
+ this.destroyedByUser = true;
21790
+ this.aborted = true;
21791
+ clearTimeout(this.timer);
21792
+ this.emit("abort");
21793
+ if (error) this.emit("error", error);
21794
+ this.emit("close");
21795
+ }
21796
+ _write(chunk, encoding, callback) {
21797
+ this.chunks.push(Buffer2.isBuffer(chunk) ? chunk : Buffer2.from(chunk, encoding));
21798
+ callback();
21799
+ }
21800
+ _final(callback) {
21801
+ this.finished = true;
21802
+ callback();
21803
+ void this.dispatch();
21804
+ }
21805
+ async dispatch() {
21806
+ if (this.dispatched || this.destroyedByUser) return;
21807
+ this.dispatched = true;
21808
+ const body = Buffer2.concat(this.chunks);
21809
+ const release = this.trackRequest?.();
21810
+ let released = false;
21811
+ const untrack = () => {
21812
+ if (released || !release) return;
21813
+ released = true;
21814
+ release();
21815
+ };
21816
+ let settled = false;
21817
+ try {
21818
+ const response = this.router.activePortsIncludes(this.target.port) && isLoopback(this.target.hostname) ? await this.viaRouter(body) : await this.viaFetch(body);
21819
+ if (this.destroyedByUser) return;
21820
+ clearTimeout(this.timer);
21821
+ settled = true;
21822
+ response.once("end", untrack);
21823
+ response.once("close", untrack);
21824
+ response.once("error", untrack);
21825
+ this.emit("response", response);
21826
+ queueMicrotask(() => {
21827
+ if (this.listenerCount("response") === 0) response.resume();
21828
+ });
21829
+ } catch (error) {
21830
+ clearTimeout(this.timer);
21831
+ if (this.destroyedByUser) return;
21832
+ const failure = error instanceof Error ? error : new Error(String(error));
21833
+ if (!("code" in failure)) Object.assign(failure, { code: "ECONNREFUSED" });
21834
+ this.emit("error", failure);
21835
+ } finally {
21836
+ if (!settled) untrack();
21837
+ }
21838
+ }
21839
+ async viaRouter(body) {
21840
+ const result = await this.router.request(this.target.port, {
21841
+ method: this.target.method,
21842
+ path: this.target.path,
21843
+ headers: this.getHeaders(),
21844
+ body: body.length ? new Uint8Array(body) : null
21845
+ });
21846
+ const body_ = result.body;
21847
+ const bytes2 = typeof body_ === "string" ? new TextEncoder().encode(body_) : body_ instanceof ArrayBuffer ? new Uint8Array(body_) : body_ ?? new Uint8Array();
21848
+ const status = result.statusCode ?? 200;
21849
+ return new VirtualClientResponse(status, result.statusMessage ?? STATUS_CODES[status] ?? "", lowercaseHeaders(result.headers), bytes2);
21850
+ }
21851
+ async viaFetch(body) {
21852
+ const fetchImpl = this.fetchImpl ?? globalThis.fetch;
21853
+ if (typeof fetchImpl !== "function") {
21854
+ throw Object.assign(new Error(`getaddrinfo ENOTFOUND ${this.target.hostname}`), { code: "ENOTFOUND" });
21855
+ }
21856
+ const portSuffix = this.target.protocol === "https:" && this.target.port === 443 || this.target.protocol === "http:" && this.target.port === 80 ? "" : `:${this.target.port}`;
21857
+ const url = `${this.target.protocol}//${this.target.hostname}${portSuffix}${this.target.path}`;
21858
+ const bodyless = this.target.method === "GET" || this.target.method === "HEAD";
21859
+ const headers = this.getHeaders();
21860
+ delete headers.host;
21861
+ delete headers.connection;
21862
+ delete headers["content-length"];
21863
+ const response = await fetchImpl(url, {
21864
+ method: this.target.method,
21865
+ headers,
21866
+ ...bodyless || body.length === 0 ? {} : { body: new Uint8Array(body) },
21867
+ redirect: "follow"
21868
+ });
21869
+ const received = {};
21870
+ response.headers.forEach((value, key) => {
21871
+ received[key.toLowerCase()] = value;
21872
+ });
21873
+ const bytes2 = new Uint8Array(await response.arrayBuffer());
21874
+ return new VirtualClientResponse(response.status, response.statusText, received, bytes2);
21875
+ }
21876
+ };
21877
+ function lowercaseHeaders(headers) {
21878
+ return Object.fromEntries(Object.entries(headers ?? {}).map(([key, value]) => [key.toLowerCase(), String(value)]));
21879
+ }
21880
+ function createHttpModule(router, owner, options = {}, defaultProtocol = "http:") {
21402
21881
  const createServer = (listener) => new VirtualHttpServer(router, owner, listener);
21403
- const module = {
21882
+ const request = (input, second, third) => {
21883
+ const overrides = second && typeof second === "object" && !(second instanceof Function) ? second : void 0;
21884
+ const callback = [second, third].find((value) => typeof value === "function");
21885
+ const req = new VirtualClientRequest(resolveTarget(input, overrides, defaultProtocol), router, options.fetch, options.trackRequest);
21886
+ if (callback) req.on("response", callback);
21887
+ return req;
21888
+ };
21889
+ const get = (input, second, third) => {
21890
+ const req = request(input, second, third);
21891
+ req.end();
21892
+ return req;
21893
+ };
21894
+ return {
21404
21895
  createServer,
21896
+ request,
21897
+ get,
21405
21898
  Server: VirtualHttpServer,
21406
21899
  ServerResponse: VirtualServerResponse,
21407
21900
  IncomingMessage: VirtualIncomingMessage,
21901
+ ClientRequest: VirtualClientRequest,
21408
21902
  METHODS,
21409
21903
  STATUS_CODES,
21410
21904
  maxHeaderSize: 16 * 1024,
@@ -21414,10 +21908,6 @@ function createHttpModule(router, owner) {
21414
21908
  Agent: class Agent {
21415
21909
  }
21416
21910
  };
21417
- return { ...module, request: unsupportedClient, get: unsupportedClient };
21418
- }
21419
- function unsupportedClient() {
21420
- throw Object.assign(new Error("http client requests are not implemented yet"), { code: "ERR_NOT_IMPLEMENTED" });
21421
21911
  }
21422
21912
  function validateHeaderName(name) {
21423
21913
  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" });
@@ -21557,6 +22047,13 @@ var ChildProcess = class extends EventEmitter4 {
21557
22047
  } catch {
21558
22048
  }
21559
22049
  done();
22050
+ },
22051
+ final: (done) => {
22052
+ try {
22053
+ handle.endStdin?.();
22054
+ } catch {
22055
+ }
22056
+ done();
21560
22057
  }
21561
22058
  });
21562
22059
  this.stdio = [this.stdin, this.stdout, this.stderr];
@@ -21795,7 +22292,7 @@ function emitKeypressEvents(stream) {
21795
22292
  }
21796
22293
  });
21797
22294
  }
21798
- function createReadlineModule(defaultInput) {
22295
+ function createReadlineModule(defaultInput, defaultOutput = () => void 0) {
21799
22296
  class Interface extends EventEmitter4 {
21800
22297
  constructor(input, output, terminal = false) {
21801
22298
  super();
@@ -21806,6 +22303,14 @@ function createReadlineModule(defaultInput) {
21806
22303
  if (terminal) {
21807
22304
  emitKeypressEvents(input);
21808
22305
  input?.on?.("keypress", this.onTerminalKeypress);
22306
+ if (typeof input?.setRawMode === "function") {
22307
+ try {
22308
+ input.setRawMode(true);
22309
+ this.ownsRawMode = true;
22310
+ } catch {
22311
+ }
22312
+ }
22313
+ input?.resume?.();
21809
22314
  } else {
21810
22315
  input?.on?.("data", (chunk) => this.receive(String(chunk)));
21811
22316
  }
@@ -21817,6 +22322,10 @@ function createReadlineModule(defaultInput) {
21817
22322
  buffer = "";
21818
22323
  pending = [];
21819
22324
  lines = [];
22325
+ /** Set while `question` is waiting, so the echoed line carries the query. */
22326
+ questionPrompt = null;
22327
+ /** Raw mode is only ours to restore if we were the one to enable it. */
22328
+ ownsRawMode = false;
21820
22329
  line = "";
21821
22330
  cursor = 0;
21822
22331
  terminal;
@@ -21824,20 +22333,31 @@ function createReadlineModule(defaultInput) {
21824
22333
  /** Split incoming data into lines, answering any waiting `question`. */
21825
22334
  receive(text2) {
21826
22335
  this.buffer += text2;
21827
- let newline = this.buffer.indexOf("\n");
21828
- while (newline >= 0) {
21829
- const line = this.buffer.slice(0, newline).replace(/\r$/, "");
21830
- this.buffer = this.buffer.slice(newline + 1);
21831
- const waiting = this.pending.shift();
21832
- if (waiting) waiting(line);
21833
- else {
21834
- this.lines.push(line);
21835
- this.emit("line", line);
21836
- }
21837
- newline = this.buffer.indexOf("\n");
22336
+ let match2 = /\r\n|\r|\n/.exec(this.buffer);
22337
+ while (match2) {
22338
+ const line = this.buffer.slice(0, match2.index);
22339
+ this.buffer = this.buffer.slice(match2.index + match2[0].length);
22340
+ this.deliver(line);
22341
+ match2 = /\r\n|\r|\n/.exec(this.buffer);
22342
+ }
22343
+ }
22344
+ /** Hand a completed line to whoever is waiting for it. */
22345
+ deliver(line) {
22346
+ const waiting = this.pending.shift();
22347
+ if (waiting) {
22348
+ this.questionPrompt = null;
22349
+ waiting(line);
22350
+ return;
21838
22351
  }
22352
+ this.lines.push(line);
22353
+ this.emit("line", line);
21839
22354
  }
21840
22355
  question(query, callback) {
22356
+ if (this.terminal) {
22357
+ this.questionPrompt = query;
22358
+ this.line = "";
22359
+ this.cursor = 0;
22360
+ }
21841
22361
  this.output?.write?.(query);
21842
22362
  if (callback) {
21843
22363
  this.pending.push(callback);
@@ -21852,6 +22372,9 @@ function createReadlineModule(defaultInput) {
21852
22372
  setPrompt(text2) {
21853
22373
  this.promptText = text2;
21854
22374
  }
22375
+ getPrompt() {
22376
+ return this.promptText;
22377
+ }
21855
22378
  pause() {
21856
22379
  this.input?.pause?.();
21857
22380
  return this;
@@ -21879,21 +22402,48 @@ function createReadlineModule(defaultInput) {
21879
22402
  if (text2) {
21880
22403
  this.line = this.line.slice(0, this.cursor) + text2 + this.line.slice(this.cursor);
21881
22404
  this.cursor += text2.length;
22405
+ this.refresh();
21882
22406
  }
21883
22407
  }
21884
22408
  getCursorPos() {
21885
- return { rows: 0, cols: this.cursor + this.promptText.length };
22409
+ return { rows: 0, cols: this.cursor + this.currentPrompt().length };
21886
22410
  }
21887
22411
  close() {
21888
22412
  if (this.closed) return;
21889
22413
  this.closed = true;
21890
22414
  if (this.terminal) {
21891
22415
  this.input?.off?.("keypress", this.onTerminalKeypress);
22416
+ if (this.ownsRawMode) {
22417
+ this.ownsRawMode = false;
22418
+ try {
22419
+ this.input?.setRawMode?.(false);
22420
+ } catch {
22421
+ }
22422
+ }
21892
22423
  this.input?.pause?.();
21893
22424
  }
21894
22425
  for (const waiting of this.pending.splice(0)) waiting("");
21895
22426
  this.emit("close");
21896
22427
  }
22428
+ /** The text shown to the left of the edited line. */
22429
+ currentPrompt() {
22430
+ return this.questionPrompt ?? this.promptText;
22431
+ }
22432
+ /**
22433
+ * Repaint the edited line.
22434
+ *
22435
+ * In raw mode nothing echoes on its own, so an Interface that does not do
22436
+ * this leaves the user typing blind. Libraries that draw their own frame
22437
+ * (clack, inquirer) simply overwrite this, exactly as they do on Node.
22438
+ */
22439
+ refresh() {
22440
+ if (!this.terminal) return;
22441
+ const prompt = this.currentPrompt();
22442
+ let text2 = `\r\x1B[0K${prompt}${this.line}`;
22443
+ const back = this.line.length - this.cursor;
22444
+ if (back > 0) text2 += `\x1B[${back}D`;
22445
+ this.output?.write?.(text2);
22446
+ }
21897
22447
  edit(sequence, key) {
21898
22448
  if (this.closed) return;
21899
22449
  const name = key.name;
@@ -21901,48 +22451,62 @@ function createReadlineModule(defaultInput) {
21901
22451
  const value = this.line;
21902
22452
  this.line = "";
21903
22453
  this.cursor = 0;
21904
- this.emit("line", value);
22454
+ this.output?.write?.("\r\n");
22455
+ this.deliver(value);
21905
22456
  return;
21906
22457
  }
21907
22458
  if (name === "left") {
21908
22459
  this.cursor = Math.max(0, this.cursor - 1);
22460
+ this.refresh();
21909
22461
  return;
21910
22462
  }
21911
22463
  if (name === "right") {
21912
22464
  this.cursor = Math.min(this.line.length, this.cursor + 1);
22465
+ this.refresh();
21913
22466
  return;
21914
22467
  }
21915
22468
  if (name === "home" || key.ctrl && name === "a") {
21916
22469
  this.cursor = 0;
22470
+ this.refresh();
21917
22471
  return;
21918
22472
  }
21919
22473
  if (name === "end" || key.ctrl && name === "e") {
21920
22474
  this.cursor = this.line.length;
22475
+ this.refresh();
21921
22476
  return;
21922
22477
  }
21923
22478
  if (name === "backspace" || key.ctrl && name === "h") {
21924
22479
  if (this.cursor > 0) {
21925
22480
  this.line = this.line.slice(0, this.cursor - 1) + this.line.slice(this.cursor);
21926
22481
  this.cursor--;
22482
+ this.refresh();
21927
22483
  }
21928
22484
  return;
21929
22485
  }
21930
22486
  if (name === "delete") {
21931
- if (this.cursor < this.line.length) this.line = this.line.slice(0, this.cursor) + this.line.slice(this.cursor + 1);
22487
+ if (this.cursor < this.line.length) {
22488
+ this.line = this.line.slice(0, this.cursor) + this.line.slice(this.cursor + 1);
22489
+ this.refresh();
22490
+ }
21932
22491
  return;
21933
22492
  }
21934
22493
  if (key.ctrl && name === "u") {
21935
22494
  this.line = this.line.slice(this.cursor);
21936
22495
  this.cursor = 0;
22496
+ this.refresh();
21937
22497
  return;
21938
22498
  }
21939
22499
  if (key.ctrl && name === "k") {
21940
22500
  this.line = this.line.slice(0, this.cursor);
22501
+ this.refresh();
21941
22502
  return;
21942
22503
  }
21943
22504
  if (key.ctrl || key.meta || sequence.length !== 1 || sequence < " ") return;
22505
+ const atEnd = this.cursor === this.line.length;
21944
22506
  this.line = this.line.slice(0, this.cursor) + sequence + this.line.slice(this.cursor);
21945
22507
  this.cursor += sequence.length;
22508
+ if (atEnd) this.output?.write?.(sequence);
22509
+ else this.refresh();
21946
22510
  }
21947
22511
  async *[Symbol.asyncIterator]() {
21948
22512
  while (!this.closed || this.lines.length) {
@@ -21972,13 +22536,23 @@ function createReadlineModule(defaultInput) {
21972
22536
  }
21973
22537
  }
21974
22538
  }
22539
+ const isTerminal = (options, output) => {
22540
+ if (typeof options?.terminal === "boolean") return options.terminal;
22541
+ return Boolean(output?.isTTY);
22542
+ };
21975
22543
  const createInterface = (options, output) => {
21976
22544
  if (options && typeof options === "object" && !options.on) {
21977
- const instance = new Interface(options.input ?? defaultInput(), options.output, options.terminal === true);
22545
+ const resolvedOutput2 = options.output ?? defaultOutput();
22546
+ const instance = new Interface(
22547
+ options.input ?? defaultInput(),
22548
+ resolvedOutput2,
22549
+ isTerminal(options, resolvedOutput2)
22550
+ );
21978
22551
  if (typeof options.prompt === "string") instance.setPrompt(options.prompt);
21979
22552
  return instance;
21980
22553
  }
21981
- return new Interface(options ?? defaultInput(), output, Boolean(output));
22554
+ const resolvedOutput = output ?? defaultOutput();
22555
+ return new Interface(options ?? defaultInput(), resolvedOutput, isTerminal(void 0, resolvedOutput));
21982
22556
  };
21983
22557
  const noop = () => {
21984
22558
  };
@@ -21995,6 +22569,7 @@ function createReadlineModule(defaultInput) {
21995
22569
  }
21996
22570
 
21997
22571
  // src/runtime/core-modules.ts
22572
+ installReadableFrom(streamModule4);
21998
22573
  var Dirent = class {
21999
22574
  /** Node 20+ exposes the containing directory, and `fs.glob` consumers read it. */
22000
22575
  constructor(name, stat2, parentPath = "") {
@@ -22200,9 +22775,20 @@ function createCoreModules(options) {
22200
22775
  throw new Error("createRequire is only available inside a loaded module");
22201
22776
  }
22202
22777
  };
22203
- const http = options.http ? createHttpModule(options.http.router, options.http.owner) : createUnsupportedModule("http");
22778
+ let inFlightRequests = 0;
22779
+ const httpOptions = {
22780
+ ...options.http?.fetch ? { fetch: options.http.fetch } : {},
22781
+ trackRequest: () => {
22782
+ inFlightRequests++;
22783
+ return () => {
22784
+ inFlightRequests--;
22785
+ };
22786
+ }
22787
+ };
22788
+ const http = options.http ? createHttpModule(options.http.router, options.http.owner, httpOptions, "http:") : createUnsupportedModule("http");
22789
+ const https = options.http ? createHttpModule(options.http.router, options.http.owner, httpOptions, "https:") : createUnsupportedModule("https");
22204
22790
  const childProcess = options.spawnChild ? createChildProcessModule(options.spawnChild, () => cwd) : createUnsupportedModule("child_process");
22205
- const readline = createReadlineModule(() => processObject.stdin);
22791
+ const readline = createReadlineModule(() => processObject.stdin, () => processObject.stdout);
22206
22792
  const dns = createDnsModule();
22207
22793
  const builtins = {
22208
22794
  assert: assert_module_default,
@@ -22220,7 +22806,7 @@ function createCoreModules(options) {
22220
22806
  "fs/promises": fs.promises,
22221
22807
  module: moduleBuiltin,
22222
22808
  http,
22223
- https: http,
22809
+ https,
22224
22810
  os,
22225
22811
  path,
22226
22812
  "path/posix": path,
@@ -22259,6 +22845,9 @@ function createCoreModules(options) {
22259
22845
  globals,
22260
22846
  process: processObject,
22261
22847
  pendingHandles: timers.pending,
22848
+ pendingUnrefed: timers.pendingUnrefed,
22849
+ /** Client requests sent but not yet read to completion. */
22850
+ pendingRequests: () => inFlightRequests,
22262
22851
  writeStdin: (data) => {
22263
22852
  if (options.interactiveStdin) stdin.write(data);
22264
22853
  },
@@ -22486,9 +23075,20 @@ function createFsModule(volume, cwd, stdinPath) {
22486
23075
  if (position == null) file3.position = start2 + chunk.length;
22487
23076
  return chunk.length;
22488
23077
  },
22489
- createReadStream: (path) => {
22490
- const data = Buffer2.from(volume.readFileSync(resolveLinks(volume, abs(path))));
22491
- return streamModule4.Readable.from([data]);
23078
+ createReadStream: (path, options) => {
23079
+ const target = abs(path);
23080
+ const settings = typeof options === "string" ? { encoding: options } : options ?? {};
23081
+ const whole = Buffer2.from(volume.readFileSync(resolveLinks(volume, target)));
23082
+ const start2 = settings.start ?? 0;
23083
+ const end = settings.end === void 0 ? whole.length : Math.min(settings.end + 1, whole.length);
23084
+ const slice = whole.subarray(start2, Math.max(start2, end));
23085
+ const stream = streamModule4.Readable.from([settings.encoding ? slice.toString(settings.encoding) : slice]);
23086
+ Object.assign(stream, { path: target, bytesRead: slice.length, close: () => stream.destroy() });
23087
+ queueMicrotask(() => {
23088
+ stream.emit("open", 0);
23089
+ stream.emit("ready");
23090
+ });
23091
+ return stream;
22492
23092
  },
22493
23093
  createWriteStream: (path, options) => {
22494
23094
  const target = abs(path);
@@ -22854,33 +23454,78 @@ var ERRNO_CONSTANTS = {
22854
23454
  };
22855
23455
  function createTrackedTimers() {
22856
23456
  const live = /* @__PURE__ */ new Set();
22857
- const track = (handle, repeating) => {
23457
+ const unrefed = /* @__PURE__ */ new Set();
23458
+ const states = /* @__PURE__ */ new WeakMap();
23459
+ const track = (native) => {
23460
+ const state = { native, active: true, referenced: true };
23461
+ const handle = {
23462
+ ref() {
23463
+ state.referenced = true;
23464
+ unrefed.delete(handle);
23465
+ if (state.active) live.add(handle);
23466
+ state.native?.ref?.();
23467
+ return handle;
23468
+ },
23469
+ unref() {
23470
+ state.referenced = false;
23471
+ live.delete(handle);
23472
+ if (state.active) unrefed.add(handle);
23473
+ state.native?.unref?.();
23474
+ return handle;
23475
+ },
23476
+ hasRef: () => state.referenced,
23477
+ refresh() {
23478
+ state.native?.refresh?.();
23479
+ return handle;
23480
+ },
23481
+ [Symbol.toPrimitive]: () => Number(state.native)
23482
+ };
23483
+ states.set(handle, state);
22858
23484
  live.add(handle);
22859
23485
  return handle;
22860
23486
  };
23487
+ const complete = (handle) => {
23488
+ const state = states.get(handle);
23489
+ if (state) state.active = false;
23490
+ live.delete(handle);
23491
+ unrefed.delete(handle);
23492
+ };
22861
23493
  const setTimeoutTracked = (fn, delay, ...args) => {
22862
- const handle = setTimeout(
23494
+ let handle;
23495
+ const native = setTimeout(
22863
23496
  (...inner) => {
22864
- live.delete(handle);
23497
+ complete(handle);
22865
23498
  fn(...inner);
22866
23499
  },
22867
23500
  delay,
22868
23501
  ...args
22869
23502
  );
22870
- live.add(handle);
23503
+ handle = track(native);
22871
23504
  return handle;
22872
23505
  };
22873
23506
  const setIntervalTracked = (fn, delay, ...args) => track(setInterval(fn, delay, ...args));
22874
23507
  const hostSetImmediate = globalThis.setImmediate;
22875
23508
  const setImmediateTracked = (fn, ...args) => {
22876
- const handle = hostSetImmediate ? hostSetImmediate((...inner) => {
22877
- live.delete(handle);
23509
+ if (!hostSetImmediate) return setTimeoutTracked(fn, 0, ...args);
23510
+ let handle;
23511
+ const native = hostSetImmediate((...inner) => {
23512
+ complete(handle);
22878
23513
  fn(...inner);
22879
- }, ...args) : setTimeoutTracked(fn, 0, ...args);
22880
- live.add(handle);
23514
+ }, ...args);
23515
+ handle = track(native);
22881
23516
  return handle;
22882
23517
  };
22883
23518
  const clear2 = (handle, native) => {
23519
+ if (typeof handle === "object" && handle !== null) {
23520
+ const state = states.get(handle);
23521
+ if (state) {
23522
+ state.active = false;
23523
+ live.delete(handle);
23524
+ unrefed.delete(handle);
23525
+ native(state.native);
23526
+ return;
23527
+ }
23528
+ }
22884
23529
  live.delete(handle);
22885
23530
  native(handle);
22886
23531
  };
@@ -22893,7 +23538,8 @@ function createTrackedTimers() {
22893
23538
  clearInterval: (handle) => clear2(handle, clearInterval),
22894
23539
  clearImmediate: (handle) => clear2(handle, globalThis.clearImmediate ?? clearTimeout)
22895
23540
  },
22896
- pending: () => live.size
23541
+ pending: () => live.size,
23542
+ pendingUnrefed: () => unrefed.size
22897
23543
  };
22898
23544
  }
22899
23545
  function createTimerPromises() {
@@ -23415,7 +24061,26 @@ function ensureProcessGlobal() {
23415
24061
  });
23416
24062
  }
23417
24063
 
24064
+ // src/runtime/host-rolldown.ts
24065
+ async function loadHostRolldownBinding() {
24066
+ if (typeof window !== "undefined" && globalThis.crossOriginIsolated !== true) {
24067
+ throw new Error(
24068
+ "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."
24069
+ );
24070
+ }
24071
+ try {
24072
+ const loaded = await import('@rolldown/binding-wasm32-wasi');
24073
+ return "__fs" in loaded ? { ...loaded } : loaded.default ?? loaded;
24074
+ } catch (error) {
24075
+ if (typeof process !== "undefined" && process.env?.SANDBOXEDJS_DEBUG) {
24076
+ console.error("[sandboxedjs] Rolldown WASI binding unavailable:", error);
24077
+ }
24078
+ throw new Error("The optional Rolldown WASI binding could not be loaded.", { cause: error });
24079
+ }
24080
+ }
24081
+
23418
24082
  // src/runtime/local-runtime-pod.ts
24083
+ init_path();
23419
24084
  var WASM_ALIASES = {
23420
24085
  esbuild: "esbuild-wasm",
23421
24086
  rollup: "@rollup/wasm-node"
@@ -23540,6 +24205,11 @@ var PodChildProcess = class {
23540
24205
  started = false;
23541
24206
  cancelled = false;
23542
24207
  child;
24208
+ /* The child is launched asynchronously, but a parent may write and close
24209
+ * its input synchronously right after spawning. Holding both until the
24210
+ * child exists is what keeps `echo hi | child` from losing the `hi`. */
24211
+ pendingInput = "";
24212
+ inputEnded = false;
23543
24213
  on(event, listener) {
23544
24214
  let set = this.listeners.get(event);
23545
24215
  if (!set) this.listeners.set(event, set = /* @__PURE__ */ new Set());
@@ -23562,6 +24232,11 @@ var PodChildProcess = class {
23562
24232
  (child) => {
23563
24233
  this.child = child;
23564
24234
  if (this.cancelled) child.kill();
24235
+ if (this.pendingInput !== "") {
24236
+ child.write(this.pendingInput);
24237
+ this.pendingInput = "";
24238
+ }
24239
+ if (this.inputEnded) child.endInput?.();
23565
24240
  child.on("output", (text2) => {
23566
24241
  this.stdout += text2;
23567
24242
  this.emit("stdout", text2);
@@ -23584,7 +24259,13 @@ var PodChildProcess = class {
23584
24259
  });
23585
24260
  }
23586
24261
  sendStdin(data) {
23587
- this.child?.write(data);
24262
+ if (this.child) this.child.write(data);
24263
+ else this.pendingInput += data;
24264
+ }
24265
+ /** Signal EOF, so a child reading stdin to the end can finish. */
24266
+ endStdin() {
24267
+ if (this.child) this.child.endInput?.();
24268
+ else this.inputEnded = true;
23588
24269
  }
23589
24270
  kill(signal = "SIGTERM") {
23590
24271
  if (this.child) this.child.kill(signal);
@@ -23666,6 +24347,9 @@ var LocalRuntimePod = class _LocalRuntimePod {
23666
24347
  aliases;
23667
24348
  modules;
23668
24349
  esbuild;
24350
+ rolldownBinding;
24351
+ /** Backs outbound `http`/`https` client requests from inside the sandbox. */
24352
+ fetch;
23669
24353
  constructor(options) {
23670
24354
  ensureProcessGlobal();
23671
24355
  this.workdir = options.workdir ?? "/";
@@ -23680,6 +24364,7 @@ var LocalRuntimePod = class _LocalRuntimePod {
23680
24364
  const notify = options.onServerReady;
23681
24365
  this.router.onListen = (port) => notify(port, `http://localhost:${port}`);
23682
24366
  }
24367
+ if (options.fetch) this.fetch = options.fetch;
23683
24368
  this.packages = new CleanPackageInstaller(this.volume, {
23684
24369
  cwd: this.workdir,
23685
24370
  ...options.registry ? { registry: options.registry } : {},
@@ -23699,6 +24384,7 @@ var LocalRuntimePod = class _LocalRuntimePod {
23699
24384
  const env2 = { ...this.env, ...isRecord(options.env) ? options.env : {} };
23700
24385
  const owner = `${this.instanceId}:${Math.random().toString(36).slice(2)}`;
23701
24386
  return new LocalProcess(async (proc) => {
24387
+ await this.prepareRolldown(cwd, env2);
23702
24388
  const untrack = trackProcess(proc);
23703
24389
  let requestedExit = 0;
23704
24390
  let engine;
@@ -23718,7 +24404,7 @@ var LocalRuntimePod = class _LocalRuntimePod {
23718
24404
  proc.exitNow(code);
23719
24405
  if (engine?.isEvaluating) throw new ProcessExit(code);
23720
24406
  },
23721
- http: { router: this.router, owner },
24407
+ http: { router: this.router, owner, ...this.fetch ? { fetch: this.fetch } : {} },
23722
24408
  spawnChild: (config) => this.processManager.spawn(config),
23723
24409
  ...typeof options.stdinPath === "string" ? { stdinPath: options.stdinPath } : {},
23724
24410
  ...options.interactiveStdin ? { interactiveStdin: true } : {},
@@ -23735,7 +24421,7 @@ var LocalRuntimePod = class _LocalRuntimePod {
23735
24421
  });
23736
24422
  try {
23737
24423
  await engine.run(script);
23738
- await this.settle(owner, core.pendingHandles, core.readingStdin);
24424
+ await this.settle(owner, core.pendingHandles, core.pendingUnrefed, core.readingStdin, core.pendingRequests);
23739
24425
  if (this.router.activePorts(owner).length) {
23740
24426
  await proc.waitForKill();
23741
24427
  return 137;
@@ -23747,6 +24433,25 @@ var LocalRuntimePod = class _LocalRuntimePod {
23747
24433
  }
23748
24434
  });
23749
24435
  }
24436
+ /**
24437
+ * Rolldown's JavaScript API synchronously requires its compiled binding.
24438
+ * When a project contains Rolldown, preload the official WASI build in the
24439
+ * host and expose it through the module override table before evaluation.
24440
+ * Keeping this demand-driven avoids adding WASM startup cost to ordinary
24441
+ * shells and Node programs.
24442
+ */
24443
+ async prepareRolldown(cwd, env2) {
24444
+ const specifier = "@rolldown/binding-wasm32-wasi";
24445
+ if (!this.modules[specifier] && packageInstalled(this.volume, cwd, "rolldown")) {
24446
+ this.rolldownBinding ??= loadHostRolldownBinding();
24447
+ const binding = await this.rolldownBinding;
24448
+ if (binding) this.modules[specifier] = binding;
24449
+ }
24450
+ if (this.modules[specifier]) {
24451
+ syncRolldownFileSystem(this.modules[specifier], this.volume, cwd);
24452
+ env2.NAPI_RS_FORCE_WASI ??= "true";
24453
+ }
24454
+ }
23750
24455
  /**
23751
24456
  * Wait until the process has either started serving or genuinely run out of
23752
24457
  * work.
@@ -23762,12 +24467,18 @@ var LocalRuntimePod = class _LocalRuntimePod {
23762
24467
  * A plain script that has genuinely finished falls straight through both,
23763
24468
  * costing a handful of empty turns.
23764
24469
  */
23765
- async settle(owner, pendingHandles, readingStdin) {
24470
+ async settle(owner, pendingHandles, pendingUnrefed, readingStdin, pendingRequests) {
23766
24471
  for (let turn = 0; turn < DRAIN_TURNS; turn++) {
23767
24472
  if (this.router.activePorts(owner).length) return;
23768
24473
  await new Promise((resolve2) => setTimeout(resolve2, 0));
23769
24474
  }
23770
- while (!this.router.activePorts(owner).length && (pendingHandles() > 0 || readingStdin())) {
24475
+ if (pendingHandles() === 0 && pendingRequests() === 0 && pendingUnrefed() > 0 && !readingStdin()) {
24476
+ const deadline = Date.now() + 1e3;
24477
+ while (!this.router.activePorts(owner).length && Date.now() < deadline) {
24478
+ await new Promise((resolve2) => setTimeout(resolve2, 5));
24479
+ }
24480
+ }
24481
+ while (!this.router.activePorts(owner).length && (pendingHandles() > 0 || pendingRequests() > 0 || readingStdin())) {
23771
24482
  await new Promise((resolve2) => setTimeout(resolve2, 5));
23772
24483
  }
23773
24484
  }
@@ -23819,6 +24530,60 @@ function formatError(error) {
23819
24530
  function isRecord(value) {
23820
24531
  return typeof value === "object" && value !== null && !Array.isArray(value);
23821
24532
  }
24533
+ function packageInstalled(volume, cwd, wanted) {
24534
+ for (let dir3 = clean(cwd); ; dir3 = dirname(dir3)) {
24535
+ if (packageTreeContains(volume, join(dir3, "node_modules"), wanted, /* @__PURE__ */ new Set())) return true;
24536
+ if (dir3 === "/") return false;
24537
+ }
24538
+ }
24539
+ function packageTreeContains(volume, modulesRoot, wanted, visited) {
24540
+ if (visited.has(modulesRoot) || !directory(volume, modulesRoot)) return false;
24541
+ visited.add(modulesRoot);
24542
+ if (directory(volume, join(modulesRoot, wanted))) return true;
24543
+ for (const entry of volume.readdirSync(modulesRoot)) {
24544
+ if (entry === ".bin") continue;
24545
+ const first = join(modulesRoot, entry);
24546
+ const packages = entry.startsWith("@") && directory(volume, first) ? volume.readdirSync(first).map((name) => join(first, name)) : [first];
24547
+ for (const root of packages) {
24548
+ if (directory(volume, root) && packageTreeContains(volume, join(root, "node_modules"), wanted, visited)) {
24549
+ return true;
24550
+ }
24551
+ }
24552
+ }
24553
+ return false;
24554
+ }
24555
+ function directory(volume, path) {
24556
+ try {
24557
+ return volume.lstatSync(path).isDirectory();
24558
+ } catch {
24559
+ return false;
24560
+ }
24561
+ }
24562
+ function syncRolldownFileSystem(binding, volume, root) {
24563
+ const fs = binding?.__fs;
24564
+ if (!fs?.mkdirSync || !fs?.writeFileSync) return;
24565
+ try {
24566
+ fs.rmSync?.(root, { recursive: true, force: true });
24567
+ } catch {
24568
+ }
24569
+ const copy = (path) => {
24570
+ const stat2 = volume.lstatSync(path);
24571
+ if (stat2.isDirectory()) {
24572
+ fs.mkdirSync(path, { recursive: true });
24573
+ for (const name of volume.readdirSync(path)) copy(join(path, name));
24574
+ } else if (stat2.isSymbolicLink()) {
24575
+ fs.mkdirSync(dirname(path), { recursive: true });
24576
+ try {
24577
+ fs.symlinkSync(volume.readlinkSync(path), path);
24578
+ } catch {
24579
+ }
24580
+ } else if (!path.endsWith(".node")) {
24581
+ fs.mkdirSync(dirname(path), { recursive: true });
24582
+ fs.writeFileSync(path, volume.readFileSync(path));
24583
+ }
24584
+ };
24585
+ copy(clean(root));
24586
+ }
23822
24587
 
23823
24588
  // src/container/container.ts
23824
24589
  var Container = class _Container {
@@ -24162,7 +24927,7 @@ var Container = class _Container {
24162
24927
  /**
24163
24928
  * Deliver a request whose body is bytes, without letting them become text.
24164
24929
  *
24165
- * Nodepod's public `request()` runs the body through `toString("utf8")` on
24930
+ * A RuntimePod's public `request()` may run the body through `toString("utf8")` on
24166
24931
  * its way in, so anything above `0x7f` is replaced: a five-byte payload
24167
24932
  * containing `0x89` and `0xff` arrives as nine. That silently destroys every
24168
24933
  * upload — an image or a video reaches the server the wrong size and no
@@ -24264,7 +25029,7 @@ var Container = class _Container {
24264
25029
  assertActive() {
24265
25030
  if (this.disposed) throw new Error("container has been disposed");
24266
25031
  }
24267
- /** Tear down every process and release the Nodepod instance. */
25032
+ /** Tear down every process and release the runtime pod. */
24268
25033
  dispose() {
24269
25034
  if (this.disposed) return;
24270
25035
  this.disposed = true;
@@ -24374,17 +25139,18 @@ var Terminal = class {
24374
25139
  // ── key handling ──────────────────────────────────────────────────────────
24375
25140
  key(ch) {
24376
25141
  if (this.running) {
24377
- if (ch === CTRL_C) {
25142
+ const raw = this.currentStdin?.rawMode === true;
25143
+ if (ch === CTRL_C && !raw) {
24378
25144
  this.session.proc.deliver("SIGINT");
24379
25145
  this.write("^C\r\n");
24380
25146
  return;
24381
25147
  }
24382
- if (ch === CTRL_D) {
25148
+ if (ch === CTRL_D && !raw) {
24383
25149
  this.currentStdin?.end();
24384
25150
  return;
24385
25151
  }
24386
- if (!this.currentStdin?.rawMode) this.write(ch === "\r" ? "\r\n" : ch);
24387
- this.currentStdin?.write(ch === "\r" ? "\n" : ch);
25152
+ if (!raw) this.write(ch === "\r" ? "\r\n" : ch);
25153
+ this.currentStdin?.write(!raw && ch === "\r" ? "\n" : ch);
24388
25154
  return;
24389
25155
  }
24390
25156
  if (this.escapeBuffer !== "") {