sandboxedjs 0.1.33 → 0.1.35

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
@@ -791,10 +791,10 @@ function globToRegexSource(pattern, opts = {}) {
791
791
  continue;
792
792
  }
793
793
  if (c === "[") {
794
- const compiled2 = compileBracket(pattern, i);
795
- if (compiled2) {
796
- out += guardDot() + compiled2.source;
797
- i = compiled2.next;
794
+ const compiled3 = compileBracket(pattern, i);
795
+ if (compiled3) {
796
+ out += guardDot() + compiled3.source;
797
+ i = compiled3.next;
798
798
  atSegmentStart = false;
799
799
  continue;
800
800
  }
@@ -5707,8 +5707,101 @@ function strerrorOf(e) {
5707
5707
  var EXIT_NOT_EXECUTABLE = 126;
5708
5708
  var EXIT_NOT_FOUND = 127;
5709
5709
 
5710
+ // src/wasi/constants.ts
5711
+ var WASI_ESUCCESS = 0;
5712
+ var WASI_EACCES = 2;
5713
+ var WASI_EAGAIN = 6;
5714
+ var WASI_EBADF = 8;
5715
+ var WASI_EBUSY = 10;
5716
+ var WASI_EEXIST = 20;
5717
+ var WASI_EFAULT = 21;
5718
+ var WASI_EFBIG = 22;
5719
+ var WASI_EINVAL = 28;
5720
+ var WASI_EIO = 29;
5721
+ var WASI_EISDIR = 31;
5722
+ var WASI_ELOOP = 32;
5723
+ var WASI_EMFILE = 34;
5724
+ var WASI_ENAMETOOLONG = 37;
5725
+ var WASI_ENOENT = 44;
5726
+ var WASI_ENOMEM = 48;
5727
+ var WASI_ENOSPC = 51;
5728
+ var WASI_ENOSYS = 52;
5729
+ var WASI_ENOTDIR = 54;
5730
+ var WASI_ENOTEMPTY = 55;
5731
+ var WASI_ENOTSUP = 58;
5732
+ var WASI_ENOTTY = 59;
5733
+ var WASI_EPERM = 63;
5734
+ var WASI_EPIPE = 64;
5735
+ var WASI_EROFS = 69;
5736
+ var WASI_ESPIPE = 70;
5737
+ var WASI_EXDEV = 75;
5738
+ var WASI_ENOTCAPABLE = 76;
5739
+ var WASI_ERRNO_BY_CODE = {
5740
+ EPERM: WASI_EPERM,
5741
+ ENOENT: WASI_ENOENT,
5742
+ EIO: WASI_EIO,
5743
+ EBADF: WASI_EBADF,
5744
+ EAGAIN: WASI_EAGAIN,
5745
+ ENOMEM: WASI_ENOMEM,
5746
+ EACCES: WASI_EACCES,
5747
+ EFAULT: WASI_EFAULT,
5748
+ EBUSY: WASI_EBUSY,
5749
+ EEXIST: WASI_EEXIST,
5750
+ EXDEV: WASI_EXDEV,
5751
+ ENOTDIR: WASI_ENOTDIR,
5752
+ EISDIR: WASI_EISDIR,
5753
+ EINVAL: WASI_EINVAL,
5754
+ EMFILE: WASI_EMFILE,
5755
+ ENOTTY: WASI_ENOTTY,
5756
+ EFBIG: WASI_EFBIG,
5757
+ ENOSPC: WASI_ENOSPC,
5758
+ ESPIPE: WASI_ESPIPE,
5759
+ EROFS: WASI_EROFS,
5760
+ EPIPE: WASI_EPIPE,
5761
+ ENAMETOOLONG: WASI_ENAMETOOLONG,
5762
+ ENOSYS: WASI_ENOSYS,
5763
+ ENOTEMPTY: WASI_ENOTEMPTY,
5764
+ ELOOP: WASI_ELOOP,
5765
+ ENOTSUP: WASI_ENOTSUP
5766
+ };
5767
+ var FILETYPE_UNKNOWN = 0;
5768
+ var FILETYPE_CHARACTER_DEVICE = 2;
5769
+ var FILETYPE_DIRECTORY = 3;
5770
+ var FILETYPE_REGULAR_FILE = 4;
5771
+ var FILETYPE_SYMBOLIC_LINK = 7;
5772
+ var O_CREAT = 1 << 0;
5773
+ var O_DIRECTORY = 1 << 1;
5774
+ var O_EXCL = 1 << 2;
5775
+ var O_TRUNC = 1 << 3;
5776
+ var FD_APPEND = 1 << 0;
5777
+ var LOOKUP_SYMLINK_FOLLOW = 1 << 0;
5778
+ var FST_ATIM = 1 << 0;
5779
+ var FST_ATIM_NOW = 1 << 1;
5780
+ var FST_MTIM = 1 << 2;
5781
+ var FST_MTIM_NOW = 1 << 3;
5782
+ var WHENCE_SET = 0;
5783
+ var WHENCE_CUR = 1;
5784
+ var WHENCE_END = 2;
5785
+ var EVENTTYPE_CLOCK = 0;
5786
+ var EVENTTYPE_FD_READ = 1;
5787
+ var EVENTTYPE_FD_WRITE = 2;
5788
+ var SUBSCRIPTION_CLOCK_ABSTIME = 1 << 0;
5789
+ var RIGHT_FD_READ = 1n << 1n;
5790
+ var RIGHT_FD_SEEK = 1n << 2n;
5791
+ var RIGHT_FD_WRITE = 1n << 6n;
5792
+ var RIGHTS_ALL = (1n << 30n) - 1n;
5793
+ var SIZEOF_FILESTAT = 64;
5794
+ var SIZEOF_FDSTAT = 24;
5795
+ var SIZEOF_DIRENT = 24;
5796
+ var SIZEOF_SUBSCRIPTION = 48;
5797
+ var SIZEOF_EVENT = 32;
5798
+ function isWasmBinary(bytes2) {
5799
+ return bytes2.length >= 4 && bytes2[0] === 0 && bytes2[1] === 97 && bytes2[2] === 115 && bytes2[3] === 109;
5800
+ }
5801
+
5710
5802
  // src/kernel/kernel.ts
5711
5803
  var BUILTIN_INTERPRETER = "/proc/self/exe";
5804
+ var WASI_INTERPRETER = "/usr/bin/wasi";
5712
5805
  var Kernel = class {
5713
5806
  vfs;
5714
5807
  procs = new ProcessTable();
@@ -5843,12 +5936,17 @@ var Kernel = class {
5843
5936
  if (command) return { kind: "builtin", path: candidate, command };
5844
5937
  }
5845
5938
  let head2 = "";
5939
+ let magic;
5846
5940
  try {
5847
5941
  if (this.vfs.permitted(st, R_OK, cred)) {
5848
- head2 = new TextDecoder().decode(this.vfs.readFile(real, cred).subarray(0, 256));
5942
+ magic = this.vfs.readFile(real, cred).subarray(0, 256);
5943
+ head2 = new TextDecoder().decode(magic);
5849
5944
  }
5850
5945
  } catch {
5851
5946
  }
5947
+ if (magic && isWasmBinary(magic)) {
5948
+ return { kind: "script", path: real, interpreter: [WASI_INTERPRETER] };
5949
+ }
5852
5950
  if (head2.startsWith("#!")) {
5853
5951
  const lineEnd = head2.indexOf("\n");
5854
5952
  const line = (lineEnd >= 0 ? head2.slice(2, lineEnd) : head2.slice(2)).trim();
@@ -5862,6 +5960,7 @@ var Kernel = class {
5862
5960
  const ext = extname(real);
5863
5961
  if (ext === ".js" || ext === ".mjs" || ext === ".cjs") return { kind: "script", path: real, interpreter: ["/usr/bin/node"] };
5864
5962
  if (ext === ".py") return { kind: "script", path: real, interpreter: ["/usr/bin/python3"] };
5963
+ if (ext === ".wasm") return { kind: "script", path: real, interpreter: [WASI_INTERPRETER] };
5865
5964
  return { kind: "script", path: real, interpreter: ["/bin/sh"] };
5866
5965
  }
5867
5966
  return null;
@@ -15740,9 +15839,9 @@ function makeSum(name, algorithm, path) {
15740
15839
  if (args.has("check")) return checkSums(ctx, algorithm, args.positional, args.has("quiet") || args.has("status"));
15741
15840
  const { sources, ok: ok2 } = await readInputs(ctx, args.positional, { stdinName: "-" });
15742
15841
  for (const source of sources) {
15743
- const digest = await digestHex(algorithm, source.bytes);
15744
- if (args.has("tag")) ctx.line(`${algorithm.toUpperCase()} (${source.name}) = ${digest}`);
15745
- else ctx.line(`${digest} ${source.name}`);
15842
+ const digest2 = await digestHex(algorithm, source.bytes);
15843
+ if (args.has("tag")) ctx.line(`${algorithm.toUpperCase()} (${source.name}) = ${digest2}`);
15844
+ else ctx.line(`${digest2} ${source.name}`);
15746
15845
  }
15747
15846
  return ok2 ? 0 : 1;
15748
15847
  }
@@ -18185,6 +18284,55 @@ def _install_processes():
18185
18284
 
18186
18285
  _install_processes()
18187
18286
  `;
18287
+ var ASYNCIO_PY = `
18288
+ import asyncio
18289
+ from pyodide.ffi import can_run_sync, run_sync
18290
+
18291
+ _orig_run = asyncio.run
18292
+
18293
+
18294
+ def _run(main, *, debug=None, loop_factory=None):
18295
+ if not asyncio.iscoroutine(main) and not asyncio.isfuture(main):
18296
+ raise ValueError("a coroutine was expected, got {!r}".format(main))
18297
+ if not can_run_sync():
18298
+ # No stack switching: the original at least raises a comprehensible
18299
+ # error rather than this shim inventing a new one.
18300
+ return _orig_run(main, debug=debug, loop_factory=loop_factory)
18301
+ return run_sync(main)
18302
+
18303
+
18304
+ def _run_until_complete(self, future):
18305
+ if not can_run_sync():
18306
+ raise RuntimeError(
18307
+ "cannot wait for a coroutine on this host: WebAssembly stack "
18308
+ "switching (JSPI) is unavailable."
18309
+ )
18310
+ return run_sync(future)
18311
+
18312
+
18313
+ async def _create_server(self, *args, **kwargs):
18314
+ # Pyodide's loop raises a bare NotImplementedError from deep inside
18315
+ # asyncio, which tells a reader nothing about why their server will not
18316
+ # start. Naming the limit is the least this can do until the container can
18317
+ # route connections to Python.
18318
+ raise NotImplementedError(
18319
+ "this container cannot yet accept network connections from Python: "
18320
+ "asyncio's create_server is not implemented on Pyodide's event loop, "
18321
+ "so an ASGI/WSGI server such as uvicorn will install and import but "
18322
+ "not bind a port. Outbound requests do work."
18323
+ )
18324
+
18325
+
18326
+ def _install_asyncio():
18327
+ asyncio.run = _run
18328
+ asyncio.runners.run = _run
18329
+ loop_type = type(asyncio.get_event_loop())
18330
+ loop_type.run_until_complete = _run_until_complete
18331
+ loop_type.create_server = _create_server
18332
+
18333
+
18334
+ _install_asyncio()
18335
+ `;
18188
18336
  var NETWORK_PY = `
18189
18337
  import builtins, email.message, io, sys, urllib.error, urllib.request, urllib.response
18190
18338
  import _sbx_host as _host
@@ -18469,16 +18617,17 @@ function installSyscallBridge(py) {
18469
18617
  py.runPython(BRIDGE_PY);
18470
18618
  py.runPython(PROCESS_PY);
18471
18619
  py.runPython(NETWORK_PY);
18620
+ py.runPython(ASYNCIO_PY);
18472
18621
  }
18473
18622
  function bindProgram(py, binding) {
18474
18623
  py.__sbxSlot.current = binding;
18475
18624
  const { ctx, stdin } = binding;
18476
- const decoder8 = new TextDecoder();
18625
+ const decoder9 = new TextDecoder();
18477
18626
  py.setStdout({
18478
- write: (buffer) => (ctx.write(decoder8.decode(buffer)), buffer.length)
18627
+ write: (buffer) => (ctx.write(decoder9.decode(buffer)), buffer.length)
18479
18628
  });
18480
18629
  py.setStderr({
18481
- write: (buffer) => (ctx.stderr.write(decoder8.decode(buffer)), buffer.length)
18630
+ write: (buffer) => (ctx.stderr.write(decoder9.decode(buffer)), buffer.length)
18482
18631
  });
18483
18632
  py.setStdin({
18484
18633
  read: (buffer) => {
@@ -18742,6 +18891,67 @@ async function runCPythonRepl(ctx) {
18742
18891
  }
18743
18892
  return 0;
18744
18893
  }
18894
+ var PIP_PY = `
18895
+ import json, re
18896
+
18897
+ import micropip
18898
+
18899
+ _MISSING = re.compile(r"Can't find a pure Python 3 wheel for '([^']+)'")
18900
+ _EXTRAS = re.compile(r"^\\s*([A-Za-z0-9._-]+)\\s*\\[([^\\]]+)\\](.*)$")
18901
+
18902
+
18903
+ def _name_of(spec):
18904
+ return re.split(r"[\\[<>=!~;\\s]", spec.strip(), 1)[0]
18905
+
18906
+
18907
+ def _installed_version(name):
18908
+ try:
18909
+ found = micropip.list()[name.replace("_", "-").lower()]
18910
+ return getattr(found, "version", None)
18911
+ except Exception:
18912
+ return None
18913
+
18914
+
18915
+ async def _install_one(spec):
18916
+ """Install one requirement, retrying without extras if they are impossible."""
18917
+ attempt = spec
18918
+ dropped = None
18919
+ while True:
18920
+ try:
18921
+ await micropip.install(attempt)
18922
+ except ValueError as error:
18923
+ message = str(error)
18924
+ missing = _MISSING.findall(message)
18925
+ extras = _EXTRAS.match(attempt)
18926
+ if missing and extras and dropped is None:
18927
+ dropped = [e.strip() for e in extras.group(2).split(",")]
18928
+ attempt = extras.group(1) + extras.group(3)
18929
+ continue
18930
+ return {
18931
+ "spec": spec, "ok": False, "missing": missing,
18932
+ "reason": message.strip().split("\\n")[0],
18933
+ }
18934
+ except Exception as error:
18935
+ return {"spec": spec, "ok": False, "missing": [], "reason": str(error).strip().split("\\n")[0]}
18936
+
18937
+ name = _name_of(attempt)
18938
+ return {
18939
+ "spec": spec, "ok": True, "name": name,
18940
+ "version": _installed_version(name), "dropped": dropped,
18941
+ }
18942
+
18943
+
18944
+ async def __sbx_pip(specs_json):
18945
+ results = []
18946
+ for spec in json.loads(specs_json):
18947
+ try:
18948
+ results.append(await _install_one(spec))
18949
+ except Exception as error:
18950
+ results.append({"spec": spec, "ok": False, "missing": [], "reason": str(error)})
18951
+ return json.dumps(results)
18952
+
18953
+ __sbx_pip
18954
+ `;
18745
18955
  var micropip = defineCommand({
18746
18956
  name: "micropip",
18747
18957
  path: "/usr/bin/micropip",
@@ -18779,8 +18989,7 @@ var micropip = defineCommand({
18779
18989
  ctx.stderr.write("pip: no packages specified\n");
18780
18990
  return 1;
18781
18991
  }
18782
- const index = "https://pypi.org";
18783
- if (!ctx.kernel.net.outboundAllowed(index)) {
18992
+ if (!ctx.kernel.net.outboundAllowed("https://pypi.org")) {
18784
18993
  ctx.stderr.write(
18785
18994
  "pip: outbound network access is disabled for this container (enable with network: { allowOutbound: true })\n"
18786
18995
  );
@@ -18793,22 +19002,42 @@ var micropip = defineCommand({
18793
19002
  ctx.stderr.write("pip: Pyodide is unavailable in this host\n");
18794
19003
  return 127;
18795
19004
  }
19005
+ let outcomes;
18796
19006
  try {
18797
19007
  await py.loadPackage("micropip");
18798
- const micropipModule = py.pyimport("micropip");
18799
- for (const name of packages) {
18800
- ctx.line(`Collecting ${name}`);
18801
- await micropipModule.install(name);
18802
- ctx.line(`Successfully installed ${name}`);
18803
- }
18804
- return 0;
19008
+ for (const name of packages) ctx.line(`Collecting ${name}`);
19009
+ const install2 = py.runPython(PIP_PY);
19010
+ outcomes = JSON.parse(String(await install2(JSON.stringify(packages))));
18805
19011
  } catch (error) {
18806
19012
  ctx.stderr.write(
18807
- `Package installation failed: ${error instanceof Error ? error.message : String(error)}
19013
+ `pip: installation failed: ${error instanceof Error ? error.message : String(error)}
18808
19014
  `
18809
19015
  );
18810
19016
  return 1;
18811
19017
  }
19018
+ const installed2 = [];
19019
+ for (const outcome of outcomes) {
19020
+ if (outcome.ok) {
19021
+ installed2.push(
19022
+ outcome.version ? `${outcome.name}-${outcome.version}` : String(outcome.name)
19023
+ );
19024
+ if (outcome.dropped?.length) {
19025
+ ctx.stderr.write(
19026
+ ` WARNING: ${outcome.name}: the ${outcome.dropped.map((extra) => `'${extra}'`).join(", ")} extra needs native code with no WebAssembly build; installed ${outcome.name} without it
19027
+ `
19028
+ );
19029
+ }
19030
+ continue;
19031
+ }
19032
+ const missing = outcome.missing ?? [];
19033
+ ctx.stderr.write(
19034
+ missing.length > 0 ? `ERROR: could not install ${outcome.spec}: no WebAssembly build exists for ${missing.map((name) => name.split(/[<>=!~;\s]/)[0]).join(", ")}
19035
+ ` : `ERROR: could not install ${outcome.spec}: ${outcome.reason ?? "unknown error"}
19036
+ `
19037
+ );
19038
+ }
19039
+ if (installed2.length > 0) ctx.line(`Successfully installed ${installed2.join(" ")}`);
19040
+ return outcomes.every((outcome) => outcome.ok) ? 0 : 1;
18812
19041
  }
18813
19042
  });
18814
19043
 
@@ -19012,6 +19241,1001 @@ var ffprobe = defineCommand({
19012
19241
  function ffmpegCommands() {
19013
19242
  return [ffmpeg, ffprobe];
19014
19243
  }
19244
+
19245
+ // src/wasi/host.ts
19246
+ init_path();
19247
+ init_errno();
19248
+ init_mode();
19249
+ var WasiExit = class extends Error {
19250
+ constructor(code) {
19251
+ super(`wasi exit ${code}`);
19252
+ this.code = code;
19253
+ this.name = "WasiExit";
19254
+ }
19255
+ code;
19256
+ };
19257
+ var encoder6 = new TextEncoder();
19258
+ var decoder7 = new TextDecoder();
19259
+ var FIRST_PREOPEN = 3;
19260
+ var WasiHost = class {
19261
+ memory;
19262
+ fds = /* @__PURE__ */ new Map();
19263
+ nextFd = FIRST_PREOPEN;
19264
+ opts;
19265
+ startTime;
19266
+ /** Set once `proc_exit` has run, so the runner reports the guest's code. */
19267
+ exitCode = null;
19268
+ constructor(options) {
19269
+ this.opts = {
19270
+ now: Date.now,
19271
+ hrtime: defaultHrtime,
19272
+ random: defaultRandom,
19273
+ sleep: defaultSleep,
19274
+ aborted: () => false,
19275
+ ...options
19276
+ };
19277
+ this.startTime = this.opts.hrtime();
19278
+ this.fds.set(0, { kind: "stdin" });
19279
+ this.fds.set(1, { kind: "stdout", stream: options.stdout });
19280
+ this.fds.set(2, { kind: "stderr", stream: options.stderr });
19281
+ const preopens = options.preopens ?? { "/": "/" };
19282
+ for (const [name, path] of Object.entries(preopens)) {
19283
+ const abs = resolve("/", path);
19284
+ this.fds.set(this.nextFd++, {
19285
+ kind: "dir",
19286
+ path: abs,
19287
+ root: abs,
19288
+ preopen: name,
19289
+ rights: RIGHTS_ALL
19290
+ });
19291
+ }
19292
+ }
19293
+ /** Attach the instance's memory. Called before `_start`. */
19294
+ bind(instance) {
19295
+ const exported = instance.exports.memory;
19296
+ if (!(exported instanceof WebAssembly.Memory)) {
19297
+ throw new Error("wasi: the module does not export a linear memory");
19298
+ }
19299
+ this.memory = exported;
19300
+ }
19301
+ /** Flush every buffered write. Called by the runner when the guest ends. */
19302
+ flushAll() {
19303
+ for (const fd of this.fds.values()) if (fd.kind === "file") this.writeBack(fd);
19304
+ }
19305
+ /**
19306
+ * `wasi_snapshot_preview1`.
19307
+ *
19308
+ * Every entry returns an errno rather than throwing: a JavaScript exception
19309
+ * crossing back into WebAssembly traps the instance, which turns a missing
19310
+ * file into an unrecoverable crash instead of the `ENOENT` the guest is
19311
+ * written to handle. `guard` is what enforces that.
19312
+ */
19313
+ get wasiImport() {
19314
+ const g = (fn) => ((...args) => this.guard(() => fn.apply(this, args)));
19315
+ return {
19316
+ args_get: g(this.args_get),
19317
+ args_sizes_get: g(this.args_sizes_get),
19318
+ environ_get: g(this.environ_get),
19319
+ environ_sizes_get: g(this.environ_sizes_get),
19320
+ clock_res_get: g(this.clock_res_get),
19321
+ clock_time_get: g(this.clock_time_get),
19322
+ fd_advise: g(() => WASI_ESUCCESS),
19323
+ fd_allocate: g(this.fd_allocate),
19324
+ fd_close: g(this.fd_close),
19325
+ fd_datasync: g(this.fd_sync),
19326
+ fd_fdstat_get: g(this.fd_fdstat_get),
19327
+ fd_fdstat_set_flags: g(this.fd_fdstat_set_flags),
19328
+ fd_fdstat_set_rights: g(() => WASI_ESUCCESS),
19329
+ fd_filestat_get: g(this.fd_filestat_get),
19330
+ fd_filestat_set_size: g(this.fd_filestat_set_size),
19331
+ fd_filestat_set_times: g(this.fd_filestat_set_times),
19332
+ fd_pread: g(this.fd_pread),
19333
+ fd_prestat_get: g(this.fd_prestat_get),
19334
+ fd_prestat_dir_name: g(this.fd_prestat_dir_name),
19335
+ fd_pwrite: g(this.fd_pwrite),
19336
+ fd_read: g(this.fd_read),
19337
+ fd_readdir: g(this.fd_readdir),
19338
+ fd_renumber: g(this.fd_renumber),
19339
+ fd_seek: g(this.fd_seek),
19340
+ fd_sync: g(this.fd_sync),
19341
+ fd_tell: g(this.fd_tell),
19342
+ fd_write: g(this.fd_write),
19343
+ path_create_directory: g(this.path_create_directory),
19344
+ path_filestat_get: g(this.path_filestat_get),
19345
+ path_filestat_set_times: g(this.path_filestat_set_times),
19346
+ path_link: g(this.path_link),
19347
+ path_open: g(this.path_open),
19348
+ path_readlink: g(this.path_readlink),
19349
+ path_remove_directory: g(this.path_remove_directory),
19350
+ path_rename: g(this.path_rename),
19351
+ path_symlink: g(this.path_symlink),
19352
+ path_unlink_file: g(this.path_unlink_file),
19353
+ poll_oneoff: g(this.poll_oneoff),
19354
+ proc_exit: ((code) => {
19355
+ this.exitCode = code;
19356
+ throw new WasiExit(code);
19357
+ }),
19358
+ proc_raise: g(() => WASI_ENOSYS),
19359
+ random_get: g(this.random_get),
19360
+ sched_yield: g(() => WASI_ESUCCESS),
19361
+ /* Sockets are the one part of WASI this container cannot honour: its
19362
+ * network is an HTTP router, not a packet path. Saying so with ENOTSUP
19363
+ * lets a guest fall back, where a trap would just kill it. */
19364
+ sock_accept: g(() => WASI_ENOTSUP),
19365
+ sock_recv: g(() => WASI_ENOTSUP),
19366
+ sock_send: g(() => WASI_ENOTSUP),
19367
+ sock_shutdown: g(() => WASI_ENOTSUP)
19368
+ };
19369
+ }
19370
+ /**
19371
+ * `wasi_unstable`, the preview0 name older toolchains still emit.
19372
+ *
19373
+ * Identical but for `fd_seek`, whose `whence` values were reordered before
19374
+ * preview1 was frozen. Aliasing the table without this correction is a
19375
+ * popular bug: every seek in an old binary lands somewhere plausible and
19376
+ * wrong.
19377
+ */
19378
+ get wasiUnstableImport() {
19379
+ const preview0Whence = [WHENCE_CUR, WHENCE_END, WHENCE_SET];
19380
+ return {
19381
+ ...this.wasiImport,
19382
+ fd_seek: ((fd, offset, whence, out) => this.guard(
19383
+ () => this.fd_seek(fd, offset, preview0Whence[whence] ?? WHENCE_SET, out)
19384
+ ))
19385
+ };
19386
+ }
19387
+ // ── memory access ────────────────────────────────────────────────────────
19388
+ //
19389
+ // Views are built per call rather than cached: `memory.grow` detaches every
19390
+ // existing view, so a cached one turns into a silent zero-length buffer the
19391
+ // first time the guest's allocator asks for another page.
19392
+ get view() {
19393
+ if (!this.memory) throw new Error("wasi: memory is not bound");
19394
+ return new DataView(this.memory.buffer);
19395
+ }
19396
+ get bytes() {
19397
+ if (!this.memory) throw new Error("wasi: memory is not bound");
19398
+ return new Uint8Array(this.memory.buffer);
19399
+ }
19400
+ readString(ptr, len) {
19401
+ return decoder7.decode(this.bytes.subarray(ptr, ptr + len));
19402
+ }
19403
+ /** The scatter/gather list `fd_read` and `fd_write` are given. */
19404
+ iovecs(ptr, count) {
19405
+ const view = this.view;
19406
+ const out = [];
19407
+ for (let i = 0; i < count; i++) {
19408
+ const base2 = ptr + i * 8;
19409
+ out.push({ offset: view.getUint32(base2, true), length: view.getUint32(base2 + 4, true) });
19410
+ }
19411
+ return out;
19412
+ }
19413
+ /**
19414
+ * Turn anything thrown inside a syscall into an errno.
19415
+ *
19416
+ * `WasiExit` is re-thrown on purpose: it is the guest unwinding its own
19417
+ * stack, not a failure to be reported through a return value.
19418
+ */
19419
+ guard(fn) {
19420
+ try {
19421
+ return fn();
19422
+ } catch (error) {
19423
+ if (error instanceof WasiExit) throw error;
19424
+ return errnoOf(error);
19425
+ }
19426
+ }
19427
+ // ── descriptors ──────────────────────────────────────────────────────────
19428
+ get(fd) {
19429
+ const found = this.fds.get(fd);
19430
+ if (!found) throw new WasiError(WASI_EBADF);
19431
+ return found;
19432
+ }
19433
+ dir(fd) {
19434
+ const found = this.get(fd);
19435
+ if (found.kind !== "dir") throw new WasiError(WASI_ENOTDIR);
19436
+ return found;
19437
+ }
19438
+ file(fd) {
19439
+ const found = this.get(fd);
19440
+ if (found.kind !== "file") throw new WasiError(WASI_EBADF);
19441
+ return found;
19442
+ }
19443
+ /**
19444
+ * Resolve a guest path against a directory descriptor.
19445
+ *
19446
+ * The confinement check is the one place preopens are enforced: a path that
19447
+ * climbs out of the directory the descriptor was derived from is
19448
+ * `ENOTCAPABLE`, which is exactly the error a capability-oriented guest
19449
+ * expects and knows how to report.
19450
+ */
19451
+ resolveAt(dirfd, path) {
19452
+ const dir3 = this.dir(dirfd);
19453
+ if (path === "") throw new WasiError(WASI_ENOENT);
19454
+ const abs = isAbsolute(path) ? resolve("/", path) : resolve(dir3.path, path);
19455
+ const root = dir3.root;
19456
+ if (root !== "/" && abs !== root && !abs.startsWith(root.endsWith("/") ? root : `${root}/`)) {
19457
+ throw new WasiError(WASI_ENOTCAPABLE);
19458
+ }
19459
+ return { abs, root };
19460
+ }
19461
+ allocate(descriptor) {
19462
+ const fd = this.nextFd++;
19463
+ this.fds.set(fd, descriptor);
19464
+ return fd;
19465
+ }
19466
+ /**
19467
+ * Push a buffered file back to the VFS.
19468
+ *
19469
+ * Called before every path-based call as well as on close, so a guest that
19470
+ * writes a file and then stats or reopens it by name sees what it wrote —
19471
+ * the alternative is a stale read that looks like data loss.
19472
+ */
19473
+ writeBack(fd) {
19474
+ if (!fd.dirty) return;
19475
+ this.opts.vfs.writeFile(fd.path, fd.data.subarray(0, fd.size), { cred: this.opts.cred });
19476
+ fd.dirty = false;
19477
+ }
19478
+ syncPaths() {
19479
+ for (const fd of this.fds.values()) if (fd.kind === "file" && fd.dirty) this.writeBack(fd);
19480
+ }
19481
+ // ── args and environment ─────────────────────────────────────────────────
19482
+ args_get(argvPtr, bufPtr) {
19483
+ return this.writeStringVector(this.opts.argv, argvPtr, bufPtr);
19484
+ }
19485
+ args_sizes_get(countPtr, sizePtr) {
19486
+ return this.writeVectorSizes(this.opts.argv, countPtr, sizePtr);
19487
+ }
19488
+ get envStrings() {
19489
+ return Object.entries(this.opts.env).map(([key, value]) => `${key}=${value}`);
19490
+ }
19491
+ environ_get(envPtr, bufPtr) {
19492
+ return this.writeStringVector(this.envStrings, envPtr, bufPtr);
19493
+ }
19494
+ environ_sizes_get(countPtr, sizePtr) {
19495
+ return this.writeVectorSizes(this.envStrings, countPtr, sizePtr);
19496
+ }
19497
+ writeStringVector(values, pointersPtr, bufPtr) {
19498
+ const view = this.view;
19499
+ const memory = this.bytes;
19500
+ let cursor = bufPtr;
19501
+ values.forEach((value, index) => {
19502
+ view.setUint32(pointersPtr + index * 4, cursor, true);
19503
+ const encoded = encoder6.encode(`${value}\0`);
19504
+ memory.set(encoded, cursor);
19505
+ cursor += encoded.length;
19506
+ });
19507
+ return WASI_ESUCCESS;
19508
+ }
19509
+ writeVectorSizes(values, countPtr, sizePtr) {
19510
+ const view = this.view;
19511
+ view.setUint32(countPtr, values.length, true);
19512
+ view.setUint32(
19513
+ sizePtr,
19514
+ values.reduce((total, value) => total + encoder6.encode(value).length + 1, 0),
19515
+ true
19516
+ );
19517
+ return WASI_ESUCCESS;
19518
+ }
19519
+ // ── clocks and randomness ────────────────────────────────────────────────
19520
+ clock_res_get(_id, out) {
19521
+ this.view.setBigUint64(out, 1000000n, true);
19522
+ return WASI_ESUCCESS;
19523
+ }
19524
+ clock_time_get(id, _precision, out) {
19525
+ this.view.setBigUint64(out, this.clockNow(id), true);
19526
+ return WASI_ESUCCESS;
19527
+ }
19528
+ clockNow(id) {
19529
+ if (id === 0) return BigInt(Math.round(this.opts.now())) * 1000000n;
19530
+ return this.opts.hrtime() - this.startTime;
19531
+ }
19532
+ random_get(ptr, len) {
19533
+ const into = new Uint8Array(len);
19534
+ this.opts.random(into);
19535
+ this.bytes.set(into, ptr);
19536
+ return WASI_ESUCCESS;
19537
+ }
19538
+ // ── reading and writing ──────────────────────────────────────────────────
19539
+ fd_read(fd, iovsPtr, iovsLen, out) {
19540
+ const descriptor = this.get(fd);
19541
+ const iovs = this.iovecs(iovsPtr, iovsLen);
19542
+ let total = 0;
19543
+ if (descriptor.kind === "stdin") {
19544
+ for (const iov of iovs) {
19545
+ if (iov.length === 0) continue;
19546
+ const chunk = this.opts.stdin.read(iov.length);
19547
+ if (chunk.length === 0) break;
19548
+ this.bytes.set(chunk, iov.offset);
19549
+ total += chunk.length;
19550
+ if (chunk.length < iov.length) break;
19551
+ }
19552
+ this.view.setUint32(out, total, true);
19553
+ return WASI_ESUCCESS;
19554
+ }
19555
+ if (descriptor.kind !== "file") throw new WasiError(WASI_EBADF);
19556
+ if ((descriptor.rights & RIGHT_FD_READ) === 0n) throw new WasiError(WASI_EACCES);
19557
+ for (const iov of iovs) {
19558
+ const end = Math.min(descriptor.pos + iov.length, descriptor.size);
19559
+ const chunk = descriptor.data.subarray(descriptor.pos, Math.max(end, descriptor.pos));
19560
+ if (chunk.length === 0) break;
19561
+ this.bytes.set(chunk, iov.offset);
19562
+ descriptor.pos += chunk.length;
19563
+ total += chunk.length;
19564
+ if (chunk.length < iov.length) break;
19565
+ }
19566
+ this.view.setUint32(out, total, true);
19567
+ return WASI_ESUCCESS;
19568
+ }
19569
+ fd_pread(fd, iovsPtr, iovsLen, offset, out) {
19570
+ const descriptor = this.get(fd);
19571
+ if (descriptor.kind !== "file") throw new WasiError(WASI_ESPIPE);
19572
+ const saved = descriptor.pos;
19573
+ descriptor.pos = Number(offset);
19574
+ try {
19575
+ return this.fd_read(fd, iovsPtr, iovsLen, out);
19576
+ } finally {
19577
+ descriptor.pos = saved;
19578
+ }
19579
+ }
19580
+ fd_write(fd, iovsPtr, iovsLen, out) {
19581
+ const descriptor = this.get(fd);
19582
+ const iovs = this.iovecs(iovsPtr, iovsLen);
19583
+ let total = 0;
19584
+ if (descriptor.kind === "stdout" || descriptor.kind === "stderr") {
19585
+ for (const iov of iovs) {
19586
+ const chunk = this.bytes.slice(iov.offset, iov.offset + iov.length);
19587
+ try {
19588
+ descriptor.stream.write(chunk);
19589
+ } catch (error) {
19590
+ if (isSysError(error) && error.code === "EPIPE") throw new WasiError(WASI_EPIPE);
19591
+ throw error;
19592
+ }
19593
+ total += chunk.length;
19594
+ }
19595
+ this.view.setUint32(out, total, true);
19596
+ return WASI_ESUCCESS;
19597
+ }
19598
+ if (descriptor.kind !== "file") throw new WasiError(WASI_EBADF);
19599
+ if ((descriptor.rights & RIGHT_FD_WRITE) === 0n) throw new WasiError(WASI_EACCES);
19600
+ if (descriptor.append) descriptor.pos = descriptor.size;
19601
+ for (const iov of iovs) {
19602
+ const chunk = this.bytes.subarray(iov.offset, iov.offset + iov.length);
19603
+ reserve(descriptor, descriptor.pos + chunk.length);
19604
+ descriptor.data.set(chunk, descriptor.pos);
19605
+ descriptor.pos += chunk.length;
19606
+ descriptor.size = Math.max(descriptor.size, descriptor.pos);
19607
+ total += chunk.length;
19608
+ }
19609
+ descriptor.dirty = true;
19610
+ this.view.setUint32(out, total, true);
19611
+ return WASI_ESUCCESS;
19612
+ }
19613
+ fd_pwrite(fd, iovsPtr, iovsLen, offset, out) {
19614
+ const descriptor = this.get(fd);
19615
+ if (descriptor.kind !== "file") throw new WasiError(WASI_ESPIPE);
19616
+ const saved = descriptor.pos;
19617
+ const appended = descriptor.append;
19618
+ descriptor.pos = Number(offset);
19619
+ descriptor.append = false;
19620
+ try {
19621
+ return this.fd_write(fd, iovsPtr, iovsLen, out);
19622
+ } finally {
19623
+ descriptor.pos = saved;
19624
+ descriptor.append = appended;
19625
+ }
19626
+ }
19627
+ fd_seek(fd, offset, whence, out) {
19628
+ const descriptor = this.get(fd);
19629
+ if (descriptor.kind !== "file") throw new WasiError(WASI_ESPIPE);
19630
+ if ((descriptor.rights & RIGHT_FD_SEEK) === 0n) throw new WasiError(WASI_EACCES);
19631
+ const base2 = whence === WHENCE_SET ? 0 : whence === WHENCE_CUR ? descriptor.pos : descriptor.size;
19632
+ const next = base2 + Number(offset);
19633
+ if (next < 0) throw new WasiError(WASI_EINVAL);
19634
+ descriptor.pos = next;
19635
+ this.view.setBigUint64(out, BigInt(next), true);
19636
+ return WASI_ESUCCESS;
19637
+ }
19638
+ fd_tell(fd, out) {
19639
+ this.view.setBigUint64(out, BigInt(this.file(fd).pos), true);
19640
+ return WASI_ESUCCESS;
19641
+ }
19642
+ fd_close(fd) {
19643
+ const descriptor = this.get(fd);
19644
+ if (descriptor.kind === "file") this.writeBack(descriptor);
19645
+ this.fds.delete(fd);
19646
+ return WASI_ESUCCESS;
19647
+ }
19648
+ fd_sync(fd) {
19649
+ const descriptor = this.get(fd);
19650
+ if (descriptor.kind === "file") this.writeBack(descriptor);
19651
+ return WASI_ESUCCESS;
19652
+ }
19653
+ fd_renumber(from, to) {
19654
+ const descriptor = this.get(from);
19655
+ const replaced = this.fds.get(to);
19656
+ if (replaced?.kind === "file") this.writeBack(replaced);
19657
+ this.fds.set(to, descriptor);
19658
+ this.fds.delete(from);
19659
+ return WASI_ESUCCESS;
19660
+ }
19661
+ fd_allocate(fd, offset, len) {
19662
+ const descriptor = this.file(fd);
19663
+ const size = Number(offset + len);
19664
+ if (descriptor.size < size) {
19665
+ reserve(descriptor, size);
19666
+ descriptor.data.fill(0, descriptor.size, size);
19667
+ descriptor.size = size;
19668
+ descriptor.dirty = true;
19669
+ }
19670
+ return WASI_ESUCCESS;
19671
+ }
19672
+ fd_filestat_set_size(fd, size) {
19673
+ const descriptor = this.file(fd);
19674
+ const length = Number(size);
19675
+ reserve(descriptor, length);
19676
+ if (length > descriptor.size) descriptor.data.fill(0, descriptor.size, length);
19677
+ descriptor.size = length;
19678
+ if (descriptor.pos > length) descriptor.pos = length;
19679
+ descriptor.dirty = true;
19680
+ return WASI_ESUCCESS;
19681
+ }
19682
+ // ── metadata ─────────────────────────────────────────────────────────────
19683
+ fd_fdstat_get(fd, out) {
19684
+ const descriptor = this.get(fd);
19685
+ const view = this.view;
19686
+ const [filetype, flags, rights] = (() => {
19687
+ switch (descriptor.kind) {
19688
+ case "dir":
19689
+ return [FILETYPE_DIRECTORY, 0, descriptor.rights];
19690
+ case "file":
19691
+ return [FILETYPE_REGULAR_FILE, descriptor.flags, descriptor.rights];
19692
+ default:
19693
+ return [FILETYPE_CHARACTER_DEVICE, 0, RIGHTS_ALL];
19694
+ }
19695
+ })();
19696
+ zero(this.bytes, out, SIZEOF_FDSTAT);
19697
+ view.setUint8(out, filetype);
19698
+ view.setUint16(out + 2, flags, true);
19699
+ view.setBigUint64(out + 8, rights, true);
19700
+ view.setBigUint64(out + 16, rights, true);
19701
+ return WASI_ESUCCESS;
19702
+ }
19703
+ fd_fdstat_set_flags(fd, flags) {
19704
+ const descriptor = this.file(fd);
19705
+ descriptor.flags = flags;
19706
+ descriptor.append = (flags & FD_APPEND) !== 0;
19707
+ return WASI_ESUCCESS;
19708
+ }
19709
+ fd_filestat_get(fd, out) {
19710
+ const descriptor = this.get(fd);
19711
+ if (descriptor.kind === "file" || descriptor.kind === "dir") {
19712
+ this.syncPaths();
19713
+ this.writeFilestat(out, this.opts.vfs.stat(descriptor.path, { cred: this.opts.cred }));
19714
+ return WASI_ESUCCESS;
19715
+ }
19716
+ zero(this.bytes, out, SIZEOF_FILESTAT);
19717
+ this.view.setUint8(out + 16, FILETYPE_CHARACTER_DEVICE);
19718
+ return WASI_ESUCCESS;
19719
+ }
19720
+ fd_filestat_set_times(fd, atim, mtim, flags) {
19721
+ const descriptor = this.get(fd);
19722
+ if (descriptor.kind !== "file" && descriptor.kind !== "dir") return WASI_ESUCCESS;
19723
+ return this.setTimes(descriptor.path, atim, mtim, flags);
19724
+ }
19725
+ path_filestat_get(dirfd, lookupFlags, pathPtr, pathLen, out) {
19726
+ this.syncPaths();
19727
+ const { abs } = this.resolveAt(dirfd, this.readString(pathPtr, pathLen));
19728
+ const follow = (lookupFlags & LOOKUP_SYMLINK_FOLLOW) !== 0;
19729
+ this.writeFilestat(
19730
+ out,
19731
+ follow ? this.opts.vfs.stat(abs, { cred: this.opts.cred }) : this.opts.vfs.lstat(abs)
19732
+ );
19733
+ return WASI_ESUCCESS;
19734
+ }
19735
+ path_filestat_set_times(dirfd, _lookupFlags, pathPtr, pathLen, atim, mtim, flags) {
19736
+ const { abs } = this.resolveAt(dirfd, this.readString(pathPtr, pathLen));
19737
+ return this.setTimes(abs, atim, mtim, flags);
19738
+ }
19739
+ setTimes(path, atim, mtim, flags) {
19740
+ const current = this.opts.vfs.stat(path, { cred: this.opts.cred });
19741
+ const now = this.opts.now();
19742
+ const atime = flags & FST_ATIM_NOW ? now : flags & FST_ATIM ? Number(atim / 1000000n) : current.atimeMs;
19743
+ const mtime = flags & FST_MTIM_NOW ? now : flags & FST_MTIM ? Number(mtim / 1000000n) : current.mtimeMs;
19744
+ this.opts.vfs.utimes(path, atime, mtime, this.opts.cred);
19745
+ return WASI_ESUCCESS;
19746
+ }
19747
+ writeFilestat(out, stat2) {
19748
+ const view = this.view;
19749
+ zero(this.bytes, out, SIZEOF_FILESTAT);
19750
+ view.setBigUint64(out, BigInt(stat2.dev), true);
19751
+ view.setBigUint64(out + 8, BigInt(stat2.ino), true);
19752
+ view.setUint8(out + 16, filetypeOf(stat2.mode));
19753
+ view.setBigUint64(out + 24, BigInt(stat2.nlink), true);
19754
+ view.setBigUint64(out + 32, BigInt(stat2.size), true);
19755
+ view.setBigUint64(out + 40, msToNs(stat2.atimeMs), true);
19756
+ view.setBigUint64(out + 48, msToNs(stat2.mtimeMs), true);
19757
+ view.setBigUint64(out + 56, msToNs(stat2.ctimeMs), true);
19758
+ }
19759
+ // ── preopens ─────────────────────────────────────────────────────────────
19760
+ fd_prestat_get(fd, out) {
19761
+ const descriptor = this.fds.get(fd);
19762
+ if (!descriptor || descriptor.kind !== "dir" || descriptor.preopen === void 0) {
19763
+ throw new WasiError(WASI_EBADF);
19764
+ }
19765
+ const view = this.view;
19766
+ view.setUint8(
19767
+ out,
19768
+ 0
19769
+ /* preopentype: dir */
19770
+ );
19771
+ view.setUint32(out + 4, encoder6.encode(descriptor.preopen).length, true);
19772
+ return WASI_ESUCCESS;
19773
+ }
19774
+ fd_prestat_dir_name(fd, ptr, len) {
19775
+ const descriptor = this.fds.get(fd);
19776
+ if (!descriptor || descriptor.kind !== "dir" || descriptor.preopen === void 0) {
19777
+ throw new WasiError(WASI_EBADF);
19778
+ }
19779
+ const name = encoder6.encode(descriptor.preopen);
19780
+ if (name.length > len) throw new WasiError(WASI_EINVAL);
19781
+ this.bytes.set(name, ptr);
19782
+ return WASI_ESUCCESS;
19783
+ }
19784
+ // ── paths ────────────────────────────────────────────────────────────────
19785
+ path_open(dirfd, _lookupFlags, pathPtr, pathLen, oflags, rightsBase, _rightsInheriting, fdflags, out) {
19786
+ this.syncPaths();
19787
+ const { abs, root } = this.resolveAt(dirfd, this.readString(pathPtr, pathLen));
19788
+ const vfs = this.opts.vfs;
19789
+ const cred = this.opts.cred;
19790
+ const exists = vfs.lexists(abs);
19791
+ if (oflags & O_EXCL && oflags & O_CREAT && exists) throw new WasiError(WASI_EEXIST);
19792
+ if (exists && vfs.stat(abs, { cred }).isDirectory()) {
19793
+ if (rightsBase & RIGHT_FD_WRITE) throw new WasiError(WASI_EISDIR);
19794
+ this.view.setUint32(out, this.allocate({ kind: "dir", path: abs, root, rights: RIGHTS_ALL }), true);
19795
+ return WASI_ESUCCESS;
19796
+ }
19797
+ if (oflags & O_DIRECTORY) throw new WasiError(exists ? WASI_ENOTDIR : WASI_ENOENT);
19798
+ if (!exists) {
19799
+ if (!(oflags & O_CREAT)) throw new WasiError(WASI_ENOENT);
19800
+ vfs.writeFile(abs, new Uint8Array(0), { cred, mode: 420 });
19801
+ }
19802
+ const truncate = (oflags & O_TRUNC) !== 0;
19803
+ const data = truncate ? new Uint8Array(0) : vfs.readFile(abs, cred);
19804
+ if (truncate) vfs.writeFile(abs, data, { cred });
19805
+ const size = data.length;
19806
+ const rights = rightsBase === 0n ? RIGHTS_ALL : rightsBase;
19807
+ const append = (fdflags & FD_APPEND) !== 0;
19808
+ this.view.setUint32(
19809
+ out,
19810
+ this.allocate({
19811
+ kind: "file",
19812
+ path: abs,
19813
+ root,
19814
+ data,
19815
+ size,
19816
+ pos: append ? size : 0,
19817
+ dirty: false,
19818
+ append,
19819
+ rights,
19820
+ flags: fdflags
19821
+ }),
19822
+ true
19823
+ );
19824
+ return WASI_ESUCCESS;
19825
+ }
19826
+ fd_readdir(fd, buf, bufLen, cookie, out) {
19827
+ this.syncPaths();
19828
+ const descriptor = this.dir(fd);
19829
+ const vfs = this.opts.vfs;
19830
+ const cred = this.opts.cred;
19831
+ const entries = [
19832
+ { name: ".", type: FILETYPE_DIRECTORY },
19833
+ { name: "..", type: FILETYPE_DIRECTORY },
19834
+ ...vfs.readdirWithTypes(descriptor.path, cred).map((entry) => ({
19835
+ name: entry.name,
19836
+ type: entry.kind === "directory" ? FILETYPE_DIRECTORY : entry.kind === "symlink" ? FILETYPE_SYMBOLIC_LINK : entry.kind === "file" ? FILETYPE_REGULAR_FILE : FILETYPE_UNKNOWN
19837
+ }))
19838
+ ];
19839
+ const view = this.view;
19840
+ const memory = this.bytes;
19841
+ let written = 0;
19842
+ for (let index = Number(cookie); index < entries.length; index++) {
19843
+ const entry = entries[index];
19844
+ const name = encoder6.encode(entry.name);
19845
+ if (written + SIZEOF_DIRENT > bufLen) break;
19846
+ const at = buf + written;
19847
+ view.setBigUint64(at, BigInt(index + 1), true);
19848
+ view.setBigUint64(at + 8, BigInt(inodeOf(descriptor.path, entry.name)), true);
19849
+ view.setUint32(at + 16, name.length, true);
19850
+ view.setUint8(at + 20, entry.type);
19851
+ written += SIZEOF_DIRENT;
19852
+ const room = Math.min(name.length, bufLen - written);
19853
+ memory.set(name.subarray(0, room), buf + written);
19854
+ written += room;
19855
+ if (room < name.length) break;
19856
+ }
19857
+ view.setUint32(out, written, true);
19858
+ return WASI_ESUCCESS;
19859
+ }
19860
+ path_create_directory(dirfd, pathPtr, pathLen) {
19861
+ const { abs } = this.resolveAt(dirfd, this.readString(pathPtr, pathLen));
19862
+ this.opts.vfs.mkdir(abs, { cred: this.opts.cred, mode: 493 });
19863
+ return WASI_ESUCCESS;
19864
+ }
19865
+ path_remove_directory(dirfd, pathPtr, pathLen) {
19866
+ const { abs } = this.resolveAt(dirfd, this.readString(pathPtr, pathLen));
19867
+ this.opts.vfs.rmdir(abs, this.opts.cred);
19868
+ return WASI_ESUCCESS;
19869
+ }
19870
+ path_unlink_file(dirfd, pathPtr, pathLen) {
19871
+ this.syncPaths();
19872
+ const { abs } = this.resolveAt(dirfd, this.readString(pathPtr, pathLen));
19873
+ this.opts.vfs.unlink(abs, this.opts.cred);
19874
+ return WASI_ESUCCESS;
19875
+ }
19876
+ path_rename(oldDirfd, oldPtr, oldLen, newDirfd, newPtr, newLen) {
19877
+ this.syncPaths();
19878
+ const from = this.resolveAt(oldDirfd, this.readString(oldPtr, oldLen));
19879
+ const to = this.resolveAt(newDirfd, this.readString(newPtr, newLen));
19880
+ this.opts.vfs.rename(from.abs, to.abs, this.opts.cred);
19881
+ return WASI_ESUCCESS;
19882
+ }
19883
+ path_symlink(targetPtr, targetLen, dirfd, pathPtr, pathLen) {
19884
+ const { abs } = this.resolveAt(dirfd, this.readString(pathPtr, pathLen));
19885
+ this.opts.vfs.symlink(this.readString(targetPtr, targetLen), abs, this.opts.cred);
19886
+ return WASI_ESUCCESS;
19887
+ }
19888
+ path_link(oldDirfd, _lookupFlags, oldPtr, oldLen, newDirfd, newPtr, newLen) {
19889
+ this.syncPaths();
19890
+ const from = this.resolveAt(oldDirfd, this.readString(oldPtr, oldLen));
19891
+ const to = this.resolveAt(newDirfd, this.readString(newPtr, newLen));
19892
+ this.opts.vfs.link(from.abs, to.abs, this.opts.cred);
19893
+ return WASI_ESUCCESS;
19894
+ }
19895
+ path_readlink(dirfd, pathPtr, pathLen, buf, bufLen, out) {
19896
+ const { abs } = this.resolveAt(dirfd, this.readString(pathPtr, pathLen));
19897
+ const target = encoder6.encode(this.opts.vfs.readlink(abs, this.opts.cred));
19898
+ const room = Math.min(target.length, bufLen);
19899
+ this.bytes.set(target.subarray(0, room), buf);
19900
+ this.view.setUint32(out, room, true);
19901
+ return WASI_ESUCCESS;
19902
+ }
19903
+ // ── polling ──────────────────────────────────────────────────────────────
19904
+ /**
19905
+ * `poll_oneoff`, which is how a WASI guest sleeps and how it waits on I/O.
19906
+ *
19907
+ * Files and the standard streams are always ready here — nothing in this
19908
+ * container can leave a read pending, since stdin was drained before the
19909
+ * guest started. That leaves the clock, which is the case that matters:
19910
+ * `sleep()` compiles to a lone clock subscription, and it is honoured by
19911
+ * actually waiting, in slices, so that killing the process interrupts it.
19912
+ */
19913
+ poll_oneoff(inPtr, outPtr, count, nevents) {
19914
+ if (count === 0) {
19915
+ this.view.setUint32(nevents, 0, true);
19916
+ return WASI_ESUCCESS;
19917
+ }
19918
+ const subscriptions = [];
19919
+ for (let index = 0; index < count; index++) {
19920
+ const at = inPtr + index * SIZEOF_SUBSCRIPTION;
19921
+ const view2 = this.view;
19922
+ subscriptions.push({
19923
+ userdata: view2.getBigUint64(at, true),
19924
+ type: view2.getUint8(at + 8),
19925
+ fd: view2.getUint32(at + 16, true),
19926
+ clockId: view2.getUint32(at + 16, true),
19927
+ timeout: view2.getBigUint64(at + 24, true),
19928
+ flags: view2.getUint16(at + 40, true)
19929
+ });
19930
+ }
19931
+ const ready = subscriptions.filter((s) => s.type !== EVENTTYPE_CLOCK);
19932
+ if (ready.length === 0) {
19933
+ const delays = subscriptions.map((s) => {
19934
+ const nanoseconds = (s.flags & SUBSCRIPTION_CLOCK_ABSTIME) !== 0 ? s.timeout - this.clockNow(s.clockId) : s.timeout;
19935
+ return Number(nanoseconds < 0n ? 0n : nanoseconds) / 1e6;
19936
+ });
19937
+ this.sleepInterruptibly(Math.min(...delays));
19938
+ }
19939
+ const events = ready.length > 0 ? ready : subscriptions;
19940
+ const view = this.view;
19941
+ events.forEach((subscription, index) => {
19942
+ const at = outPtr + index * SIZEOF_EVENT;
19943
+ zero(this.bytes, at, SIZEOF_EVENT);
19944
+ view.setBigUint64(at, subscription.userdata, true);
19945
+ view.setUint16(at + 8, WASI_ESUCCESS, true);
19946
+ view.setUint8(at + 10, subscription.type);
19947
+ if (subscription.type === EVENTTYPE_FD_READ) {
19948
+ const available = subscription.fd === 0 ? this.opts.stdin.available : this.bytesLeft(subscription.fd);
19949
+ view.setBigUint64(at + 16, BigInt(available), true);
19950
+ } else if (subscription.type === EVENTTYPE_FD_WRITE) {
19951
+ view.setBigUint64(at + 16, BigInt(64 * 1024), true);
19952
+ }
19953
+ });
19954
+ view.setUint32(nevents, events.length, true);
19955
+ return WASI_ESUCCESS;
19956
+ }
19957
+ bytesLeft(fd) {
19958
+ const descriptor = this.fds.get(fd);
19959
+ return descriptor?.kind === "file" ? Math.max(0, descriptor.size - descriptor.pos) : 0;
19960
+ }
19961
+ /** Wait in slices so that a `SIGKILL` does not have to outlast the sleep. */
19962
+ sleepInterruptibly(milliseconds) {
19963
+ let remaining = milliseconds;
19964
+ while (remaining > 0) {
19965
+ if (this.opts.aborted()) return;
19966
+ const slice = Math.min(remaining, 50);
19967
+ this.opts.sleep(slice);
19968
+ remaining -= slice;
19969
+ }
19970
+ }
19971
+ };
19972
+ var WasiError = class extends Error {
19973
+ constructor(errno) {
19974
+ super(`wasi errno ${errno}`);
19975
+ this.errno = errno;
19976
+ this.name = "WasiError";
19977
+ }
19978
+ errno;
19979
+ };
19980
+ function errnoOf(error) {
19981
+ if (error instanceof WasiError) return error.errno;
19982
+ if (isSysError(error)) return WASI_ERRNO_BY_CODE[error.code] ?? WASI_EIO;
19983
+ if (error instanceof RangeError) return WASI_EFAULT;
19984
+ return WASI_EIO;
19985
+ }
19986
+ function filetypeOf(mode) {
19987
+ const kind = mode & 61440;
19988
+ if (kind === S_IFDIR) return FILETYPE_DIRECTORY;
19989
+ if (kind === S_IFREG) return FILETYPE_REGULAR_FILE;
19990
+ if (kind === S_IFLNK) return FILETYPE_SYMBOLIC_LINK;
19991
+ if (kind === S_IFCHR) return FILETYPE_CHARACTER_DEVICE;
19992
+ return FILETYPE_UNKNOWN;
19993
+ }
19994
+ function msToNs(milliseconds) {
19995
+ return BigInt(Math.round(milliseconds)) * 1000000n;
19996
+ }
19997
+ function zero(memory, at, length) {
19998
+ memory.fill(0, at, at + length);
19999
+ }
20000
+ function reserve(descriptor, length) {
20001
+ if (length <= descriptor.data.length) return;
20002
+ const grown = new Uint8Array(Math.max(length, descriptor.data.length * 2, 1024));
20003
+ grown.set(descriptor.data.subarray(0, descriptor.size));
20004
+ descriptor.data = grown;
20005
+ }
20006
+ function inodeOf(dir3, name) {
20007
+ let hash = 2166136261;
20008
+ const path = `${dir3}/${name}`;
20009
+ for (let index = 0; index < path.length; index++) {
20010
+ hash ^= path.charCodeAt(index);
20011
+ hash = Math.imul(hash, 16777619);
20012
+ }
20013
+ return hash >>> 0;
20014
+ }
20015
+ function defaultHrtime() {
20016
+ return BigInt(Math.round(performance.now() * 1e6));
20017
+ }
20018
+ function defaultRandom(into) {
20019
+ crypto.getRandomValues(into);
20020
+ }
20021
+ function defaultSleep(milliseconds) {
20022
+ try {
20023
+ const buffer = new Int32Array(new SharedArrayBuffer(4));
20024
+ Atomics.wait(buffer, 0, 0, milliseconds);
20025
+ } catch {
20026
+ }
20027
+ }
20028
+
20029
+ // src/wasi/run.ts
20030
+ var compiled2 = /* @__PURE__ */ new Map();
20031
+ var MAX_CACHED_MODULES = 32;
20032
+ async function runWasi(ctx, bytes2, options = {}) {
20033
+ if (!isWasmBinary(bytes2)) {
20034
+ ctx.warn("cannot execute binary file: not a WebAssembly module");
20035
+ return EXIT_NOT_EXECUTABLE;
20036
+ }
20037
+ const argv = options.argv ?? ctx.argv;
20038
+ const host2 = new WasiHost({
20039
+ argv,
20040
+ /* `PWD` is set truthfully, but do not mistake it for a working directory:
20041
+ * wasi-libc keeps its own cwd, fixed at `/`, and ignores this. A guest's
20042
+ * relative path therefore resolves from the root — the same thing it does
20043
+ * under wasmtime, and why programs run here are given absolute paths. */
20044
+ env: { ...ctx.env, PWD: ctx.cwd },
20045
+ vfs: ctx.vfs,
20046
+ cred: ctx.cred,
20047
+ cwd: ctx.cwd,
20048
+ stdin: await primeStdin(ctx),
20049
+ stdout: ctx.stdout,
20050
+ stderr: ctx.stderr,
20051
+ ...options.preopens ? { preopens: options.preopens } : {},
20052
+ now: ctx.kernel.now,
20053
+ aborted: () => ctx.signal.aborted
20054
+ });
20055
+ let instance;
20056
+ try {
20057
+ const module = await compile(bytes2);
20058
+ instance = await WebAssembly.instantiate(module, {
20059
+ ...options.imports,
20060
+ wasi_snapshot_preview1: host2.wasiImport,
20061
+ wasi_unstable: host2.wasiUnstableImport
20062
+ });
20063
+ } catch (error) {
20064
+ ctx.warn(describeStartupFailure(error));
20065
+ return EXIT_NOT_EXECUTABLE;
20066
+ }
20067
+ try {
20068
+ host2.bind(instance);
20069
+ } catch (error) {
20070
+ ctx.warn(error instanceof Error ? error.message : String(error));
20071
+ return EXIT_NOT_EXECUTABLE;
20072
+ }
20073
+ const start2 = instance.exports._start ?? instance.exports._initialize;
20074
+ if (typeof start2 !== "function") {
20075
+ ctx.warn("not a WASI command: the module exports neither _start nor _initialize");
20076
+ return EXIT_NOT_EXECUTABLE;
20077
+ }
20078
+ try {
20079
+ start2();
20080
+ return host2.exitCode ?? 0;
20081
+ } catch (error) {
20082
+ if (error instanceof WasiExit) return error.code;
20083
+ ctx.warn(error instanceof Error ? error.message : String(error));
20084
+ return 134;
20085
+ } finally {
20086
+ try {
20087
+ host2.flushAll();
20088
+ } catch (error) {
20089
+ ctx.warn(`failed to flush open files: ${error instanceof Error ? error.message : String(error)}`);
20090
+ }
20091
+ }
20092
+ }
20093
+ async function compile(bytes2) {
20094
+ const key = await digest(bytes2);
20095
+ const hit = compiled2.get(key);
20096
+ if (hit) {
20097
+ compiled2.delete(key);
20098
+ compiled2.set(key, hit);
20099
+ return hit;
20100
+ }
20101
+ const module = await WebAssembly.compile(sliceForWasm(bytes2));
20102
+ compiled2.set(key, module);
20103
+ if (compiled2.size > MAX_CACHED_MODULES) {
20104
+ const oldest = compiled2.keys().next().value;
20105
+ if (oldest !== void 0) compiled2.delete(oldest);
20106
+ }
20107
+ return module;
20108
+ }
20109
+ async function digest(bytes2) {
20110
+ const hash = await crypto.subtle.digest("SHA-256", sliceForWasm(bytes2));
20111
+ return Array.from(new Uint8Array(hash, 0, 16), (byte) => byte.toString(16).padStart(2, "0")).join("");
20112
+ }
20113
+ function sliceForWasm(bytes2) {
20114
+ return bytes2.buffer.slice(bytes2.byteOffset, bytes2.byteOffset + bytes2.byteLength);
20115
+ }
20116
+ async function primeStdin(ctx) {
20117
+ let pending = new Uint8Array(0);
20118
+ if (!ctx.stdin.isTTY) {
20119
+ try {
20120
+ pending = await ctx.stdin.readAll();
20121
+ } catch {
20122
+ pending = new Uint8Array(0);
20123
+ }
20124
+ }
20125
+ return {
20126
+ read(size) {
20127
+ const chunk = pending.slice(0, Math.min(size, pending.length));
20128
+ pending = pending.subarray(chunk.length);
20129
+ return chunk;
20130
+ },
20131
+ get available() {
20132
+ return pending.length;
20133
+ },
20134
+ isTTY: ctx.stdin.isTTY
20135
+ };
20136
+ }
20137
+ function describeStartupFailure(error) {
20138
+ const message = error instanceof Error ? error.message : String(error);
20139
+ if (error instanceof WebAssembly.LinkError) {
20140
+ return `${message} \u2014 the module needs imports this container does not provide. Build it for wasm32-wasi (a plain wasm32-unknown-unknown or emscripten build will not run here).`;
20141
+ }
20142
+ return message;
20143
+ }
20144
+
20145
+ // src/wasi/command.ts
20146
+ var wasi = defineCommand({
20147
+ name: "wasi",
20148
+ path: "/usr/bin/wasi",
20149
+ summary: "run a WebAssembly (wasm32-wasi) binary",
20150
+ usage: "wasi [--dir PATH] [--mapdir GUEST=PATH] [--env K=V] MODULE.wasm [args...]",
20151
+ manual: `Runs a WebAssembly module built for wasm32-wasi as a container
20152
+ process: it sees the container's filesystem, environment and standard streams,
20153
+ and can be piped and redirected like any other command.
20154
+
20155
+ By default the module is given the whole filesystem, which is what an ordinary
20156
+ program compiled by clang, Rust, Zig or TinyGo expects. Passing --dir or
20157
+ --mapdir replaces that default with exactly what is listed, confining the
20158
+ module to those directories.
20159
+
20160
+ A WASI program has no working directory: wasi-libc fixes its own at / and
20161
+ resolves relative paths from there, exactly as it does under wasmtime. Pass
20162
+ absolute paths, or preopen a directory with --mapdir to give the program a
20163
+ name for it.
20164
+
20165
+ Executable .wasm files are dispatched here automatically, so ./tool.wasm runs
20166
+ without naming this command.
20167
+
20168
+ Sockets are not available: this container's network is an HTTP router rather
20169
+ than a packet path, and socket calls report ENOTSUP.`,
20170
+ async run(ctx) {
20171
+ const preopens = {};
20172
+ const env2 = {};
20173
+ let module;
20174
+ let rest = [];
20175
+ const args = ctx.args;
20176
+ for (let index = 0; index < args.length; index++) {
20177
+ const arg = args[index];
20178
+ if (arg === "--help" || arg === "-h") {
20179
+ ctx.line(wasi.usage);
20180
+ return 0;
20181
+ }
20182
+ if (arg === "--") {
20183
+ module = args[index + 1];
20184
+ rest = args.slice(index + 2);
20185
+ break;
20186
+ }
20187
+ if (arg === "--dir") {
20188
+ const dir3 = args[++index];
20189
+ if (dir3 === void 0) return ctx.reportError(new UsageError("--dir needs a path"));
20190
+ preopens[ctx.path(dir3)] = ctx.path(dir3);
20191
+ continue;
20192
+ }
20193
+ if (arg === "--mapdir") {
20194
+ const pair = args[++index];
20195
+ const split2 = pair?.indexOf("=") ?? -1;
20196
+ if (pair === void 0 || split2 < 0) {
20197
+ return ctx.reportError(new UsageError("--mapdir needs GUEST=PATH"));
20198
+ }
20199
+ preopens[pair.slice(0, split2)] = ctx.path(pair.slice(split2 + 1));
20200
+ continue;
20201
+ }
20202
+ if (arg === "--env") {
20203
+ const pair = args[++index];
20204
+ const split2 = pair?.indexOf("=") ?? -1;
20205
+ if (pair === void 0 || split2 < 0) {
20206
+ return ctx.reportError(new UsageError("--env needs KEY=VALUE"));
20207
+ }
20208
+ env2[pair.slice(0, split2)] = pair.slice(split2 + 1);
20209
+ continue;
20210
+ }
20211
+ module = arg;
20212
+ rest = args.slice(index + 1);
20213
+ break;
20214
+ }
20215
+ if (module === void 0) return ctx.reportError(new UsageError("a module is required"));
20216
+ const abs = ctx.path(module);
20217
+ let bytes2;
20218
+ try {
20219
+ bytes2 = ctx.vfs.readFile(abs, ctx.cred);
20220
+ } catch (error) {
20221
+ ctx.reportError(error, abs);
20222
+ return EXIT_NOT_FOUND;
20223
+ }
20224
+ if (!isWasmBinary(bytes2)) {
20225
+ return ctx.fail(`${abs}: not a WebAssembly module`, 126);
20226
+ }
20227
+ Object.assign(ctx.env, env2);
20228
+ return await runWasi(ctx, bytes2, {
20229
+ /* argv[0] is the path as the user wrote it, not the resolved one: a
20230
+ * program printing its own usage should echo what was typed. */
20231
+ argv: [module, ...rest],
20232
+ ...Object.keys(preopens).length > 0 ? { preopens } : {}
20233
+ });
20234
+ }
20235
+ });
20236
+ function wasiCommands() {
20237
+ return [wasi];
20238
+ }
19015
20239
  var platformBuffer = globalThis.Buffer;
19016
20240
  var Buffer2 = platformBuffer ?? addBase64UrlSupport(index_js.Buffer);
19017
20241
  function addBase64UrlSupport(BufferClass) {
@@ -19202,8 +20426,8 @@ function verifyIntegrity(data, integrity, shasum, identity) {
19202
20426
  const dash = choice.indexOf("-");
19203
20427
  const algorithm = choice.slice(0, dash);
19204
20428
  const expected = choice.slice(dash + 1).replace(/\?.*$/, "");
19205
- const digest = algorithm === "sha512" ? sha512.sha512(data) : algorithm === "sha256" ? sha256.sha256(data) : null;
19206
- if (digest && Buffer2.from(digest).toString("base64") === expected) return;
20429
+ const digest2 = algorithm === "sha512" ? sha512.sha512(data) : algorithm === "sha256" ? sha256.sha256(data) : null;
20430
+ if (digest2 && Buffer2.from(digest2).toString("base64") === expected) return;
19207
20431
  }
19208
20432
  throw new Error(`Integrity check failed for ${identity}`);
19209
20433
  }
@@ -20173,6 +21397,7 @@ function allCommands() {
20173
21397
  ...nodeCommands(),
20174
21398
  ...pythonCommands(),
20175
21399
  ...ffmpegCommands(),
21400
+ ...wasiCommands(),
20176
21401
  ...packageCommands()
20177
21402
  ];
20178
21403
  }
@@ -20332,15 +21557,15 @@ var Session = class {
20332
21557
  async run(command, opts = {}) {
20333
21558
  if (this.closed) throw new Error("session is closed");
20334
21559
  const combined = [];
20335
- const decoder8 = new TextDecoder();
21560
+ const decoder9 = new TextDecoder();
20336
21561
  const stdout = new BufferSink((chunk) => {
20337
- const text2 = decoder8.decode(chunk, { stream: true });
21562
+ const text2 = decoder9.decode(chunk, { stream: true });
20338
21563
  combined.push(text2);
20339
21564
  opts.onStdout?.(text2);
20340
21565
  this.hooks.onStdout?.(text2);
20341
21566
  });
20342
21567
  const stderr = new BufferSink((chunk) => {
20343
- const text2 = decoder8.decode(chunk, { stream: true });
21568
+ const text2 = decoder9.decode(chunk, { stream: true });
20344
21569
  combined.push(text2);
20345
21570
  opts.onStderr?.(text2);
20346
21571
  this.hooks.onStderr?.(text2);
@@ -22794,8 +24019,8 @@ function createCryptoModule() {
22794
24019
  queueMicrotask(() => done?.(null, target));
22795
24020
  },
22796
24021
  hash(algorithm, data, encoding = "hex") {
22797
- const digest = Buffer2.from(hashFor(algorithm)(toBytes2(data)));
22798
- return encoding === "buffer" ? digest : digest.toString(encoding);
24022
+ const digest2 = Buffer2.from(hashFor(algorithm)(toBytes2(data)));
24023
+ return encoding === "buffer" ? digest2 : digest2.toString(encoding);
22799
24024
  },
22800
24025
  timingSafeEqual(a, b) {
22801
24026
  if (a.length !== b.length) throw new RangeError("Input buffers must have the same byte length");
@@ -24730,7 +25955,7 @@ var MemoryStat = class {
24730
25955
  return this.inode.kind === "symlink";
24731
25956
  }
24732
25957
  };
24733
- var encoder6 = new TextEncoder();
25958
+ var encoder7 = new TextEncoder();
24734
25959
  var MemoryVolume = class {
24735
25960
  entries = /* @__PURE__ */ new Map();
24736
25961
  nextIno = 2;
@@ -24748,7 +25973,7 @@ var MemoryVolume = class {
24748
25973
  writeFileSync(path, data) {
24749
25974
  const key = this.key(path);
24750
25975
  this.requireParent(key, "open");
24751
- const bytes2 = typeof data === "string" ? encoder6.encode(data) : data.slice();
25976
+ const bytes2 = typeof data === "string" ? encoder7.encode(data) : data.slice();
24752
25977
  const current = this.entries.get(key);
24753
25978
  if (current?.kind === "directory") throw new VolumeError("EISDIR", "open", key);
24754
25979
  if (current?.kind === "symlink") throw new VolumeError("EINVAL", "open", key);
@@ -24761,7 +25986,7 @@ var MemoryVolume = class {
24761
25986
  }
24762
25987
  appendFileSync(path, data) {
24763
25988
  const key = this.key(path);
24764
- const bytes2 = typeof data === "string" ? encoder6.encode(data) : data;
25989
+ const bytes2 = typeof data === "string" ? encoder7.encode(data) : data;
24765
25990
  const current = this.entries.get(key);
24766
25991
  if (!current) return this.writeFileSync(key, bytes2);
24767
25992
  if (current.kind !== "file") throw new VolumeError(current.kind === "directory" ? "EISDIR" : "EINVAL", "open", key);
@@ -24899,7 +26124,7 @@ var MemoryVolume = class {
24899
26124
  if (node2.kind === "directory") directoryCount++;
24900
26125
  else {
24901
26126
  fileCount++;
24902
- totalBytes += node2.kind === "file" ? node2.data.length : encoder6.encode(node2.target).length;
26127
+ totalBytes += node2.kind === "file" ? node2.data.length : encoder7.encode(node2.target).length;
24903
26128
  }
24904
26129
  }
24905
26130
  return { totalBytes, fileCount, directoryCount, dirCount: directoryCount };
@@ -25781,10 +27006,10 @@ function attachRolldownMirror(binding, volume, root) {
25781
27006
  }
25782
27007
 
25783
27008
  // src/runtime/remote-volume.ts
25784
- var encoder7 = new TextEncoder();
25785
- var decoder7 = new TextDecoder();
27009
+ var encoder8 = new TextEncoder();
27010
+ var decoder8 = new TextDecoder();
25786
27011
  function encodeFrame(header, body) {
25787
- const json = encoder7.encode(JSON.stringify(header));
27012
+ const json = encoder8.encode(JSON.stringify(header));
25788
27013
  const frame = new Uint8Array(4 + json.length + (body?.length ?? 0));
25789
27014
  new DataView(frame.buffer).setUint32(0, json.length, true);
25790
27015
  frame.set(json, 4);
@@ -25794,7 +27019,7 @@ function encodeFrame(header, body) {
25794
27019
  function decodeFrame(frame) {
25795
27020
  const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
25796
27021
  const headerLength = view.getUint32(0, true);
25797
- const header = JSON.parse(decoder7.decode(frame.subarray(4, 4 + headerLength)));
27022
+ const header = JSON.parse(decoder8.decode(frame.subarray(4, 4 + headerLength)));
25798
27023
  return { header, body: frame.subarray(4 + headerLength) };
25799
27024
  }
25800
27025
  function flattenStat(stat2) {
@@ -26597,15 +27822,15 @@ var Container = class _Container {
26597
27822
  }
26598
27823
  makeStdio(opts) {
26599
27824
  const combined = [];
26600
- const decoder8 = new TextDecoder();
27825
+ const decoder9 = new TextDecoder();
26601
27826
  const stdout = new BufferSink((chunk) => {
26602
- const text2 = decoder8.decode(chunk, { stream: true });
27827
+ const text2 = decoder9.decode(chunk, { stream: true });
26603
27828
  combined.push(text2);
26604
27829
  opts.onStdout?.(text2);
26605
27830
  this.hooks.onStdout?.(text2);
26606
27831
  });
26607
27832
  const stderr = new BufferSink((chunk) => {
26608
- const text2 = decoder8.decode(chunk, { stream: true });
27833
+ const text2 = decoder9.decode(chunk, { stream: true });
26609
27834
  combined.push(text2);
26610
27835
  opts.onStderr?.(text2);
26611
27836
  this.hooks.onStderr?.(text2);
@@ -27350,6 +28575,9 @@ exports.VirtualHttpServer = VirtualHttpServer;
27350
28575
  exports.VirtualIncomingMessage = VirtualIncomingMessage;
27351
28576
  exports.VirtualServerResponse = VirtualServerResponse;
27352
28577
  exports.WASM_ALIASES = WASM_ALIASES;
28578
+ exports.WasiError = WasiError;
28579
+ exports.WasiExit = WasiExit;
28580
+ exports.WasiHost = WasiHost;
27353
28581
  exports.WorkerRuntimePod = WorkerRuntimePod;
27354
28582
  exports.allCommands = allCommands;
27355
28583
  exports.applyChmod = applyChmod;
@@ -27383,6 +28611,7 @@ exports.isBuiltinName = isBuiltinName;
27383
28611
  exports.isCPythonAvailable = isCPythonAvailable;
27384
28612
  exports.isPythonAvailable = isPythonAvailable;
27385
28613
  exports.isSysError = isSysError;
28614
+ exports.isWasmBinary = isWasmBinary;
27386
28615
  exports.looksLikeEsm = looksLikeEsm;
27387
28616
  exports.makeCred = makeCred;
27388
28617
  exports.normalizeSignal = normalizeSignal;
@@ -27392,11 +28621,13 @@ exports.parseUmask = parseUmask;
27392
28621
  exports.posixPath = path_exports;
27393
28622
  exports.renderInto = renderInto;
27394
28623
  exports.resetPidCounter = resetPidCounter;
28624
+ exports.runWasi = runWasi;
27395
28625
  exports.shellQuote = shellQuote;
27396
28626
  exports.startRuntimeWorker = startRuntimeWorker;
27397
28627
  exports.strerror = strerror;
27398
28628
  exports.syncChannelSupported = syncChannelSupported;
27399
28629
  exports.transformEsm = transformEsm;
27400
28630
  exports.unameInfo = unameInfo;
28631
+ exports.wasiCommand = wasi;
27401
28632
  //# sourceMappingURL=index.cjs.map
27402
28633
  //# sourceMappingURL=index.cjs.map