@ai-ecoverse/slicc-kernel 1.103.4 → 1.106.3

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.
Files changed (38) hide show
  1. package/README.md +57 -16
  2. package/dist/driver-worker.js +36 -1
  3. package/dist/driver-worker.js.map +2 -2
  4. package/dist/index.js +89 -5
  5. package/dist/index.js.map +2 -2
  6. package/dist/kernel-worker.js +798 -295
  7. package/dist/kernel-worker.js.map +4 -4
  8. package/dist/meta.js.map +2 -2
  9. package/dist/node-driver-worker.js +36 -1
  10. package/dist/node-driver-worker.js.map +2 -2
  11. package/dist/node-process-worker.js +489 -234
  12. package/dist/node-process-worker.js.map +4 -4
  13. package/dist/node.js +846 -315
  14. package/dist/node.js.map +4 -4
  15. package/dist/process-worker.js +426 -171
  16. package/dist/process-worker.js.map +4 -4
  17. package/dist/types/commands.d.ts +6 -1
  18. package/dist/types/fs/command-stat.d.ts +3 -0
  19. package/dist/types/fs/commands.d.ts +7 -1
  20. package/dist/types/fs/engines.d.ts +5 -0
  21. package/dist/types/fs/types.d.ts +1 -0
  22. package/dist/types/kernel/host.d.ts +1 -0
  23. package/dist/types/kernel/net/http-syscalls.d.ts +10 -0
  24. package/dist/types/kernel/net/http1.d.ts +1 -0
  25. package/dist/types/kernel/net/remote-transport.d.ts +18 -0
  26. package/dist/types/kernel/net/transport.d.ts +2 -0
  27. package/dist/types/kernel/process.d.ts +8 -0
  28. package/dist/types/launcher.d.ts +4 -0
  29. package/dist/types/process/js/js-kernel.d.ts +2 -1
  30. package/dist/types/process/process-signals.d.ts +3 -0
  31. package/dist/types/process/wasi/wasi-cred.d.ts +11 -0
  32. package/dist/types/process/wasi/wasi-files.d.ts +1 -0
  33. package/dist/types/process/wasi/wasi-host.d.ts +9 -0
  34. package/dist/types/process/wasi/wasi-sigmask.d.ts +7 -1
  35. package/dist/types/process/wasi/wasix-epoll.d.ts +3 -0
  36. package/dist/types/refused-command.d.ts +4 -0
  37. package/dist/types/transport.d.ts +1 -0
  38. package/package.json +12 -12
@@ -2491,7 +2491,7 @@ var KERNEL_VERSION, OS_RELEASE;
2491
2491
  var init_version = __esm({
2492
2492
  "src/version.ts"() {
2493
2493
  "use strict";
2494
- KERNEL_VERSION = true ? "1.103.4" : "0.0.0-dev";
2494
+ KERNEL_VERSION = true ? "1.106.3" : "0.0.0-dev";
2495
2495
  OS_RELEASE = "6.0.0-slicc";
2496
2496
  }
2497
2497
  });
@@ -4207,7 +4207,7 @@ function orphanContents(stream) {
4207
4207
  if (live.ranged) return live.ranged.read(0, live.ranged.size());
4208
4208
  return live.data?.slice(0, live.len ?? live.data.length) ?? new Uint8Array(0);
4209
4209
  }
4210
- function vfsPromoter(Fs, sys, streams, livePath) {
4210
+ function vfsPromoter(Fs, sys, streams2, livePath) {
4211
4211
  const promoted = /* @__PURE__ */ new Map();
4212
4212
  return (stream) => {
4213
4213
  if (stream.sliccKernelFd !== void 0 || !isVfsFile(Fs, stream)) return;
@@ -4227,11 +4227,11 @@ function vfsPromoter(Fs, sys, streams, livePath) {
4227
4227
  );
4228
4228
  promoted.set(stream.shared, kfd);
4229
4229
  }
4230
- streams.attachFile(stream, kfd);
4230
+ streams2.attachFile(stream, kfd);
4231
4231
  };
4232
4232
  }
4233
- function describeForFork(Fs, sys, streams, livePath) {
4234
- const promote = vfsPromoter(Fs, sys, streams, livePath);
4233
+ function describeForFork(Fs, sys, streams2, livePath) {
4234
+ const promote = vfsPromoter(Fs, sys, streams2, livePath);
4235
4235
  const out = [];
4236
4236
  for (const stream of Fs.streams) {
4237
4237
  if (!stream) continue;
@@ -4255,7 +4255,7 @@ function kernelEntry(stream, kernel) {
4255
4255
  const access = kind === "tty" ? O_RDWR : (stream.flags ?? O_RDWR) & O_ACCMODE4;
4256
4256
  return { fd: stream.fd, kernel, kind, flags: access, ...cloexec };
4257
4257
  }
4258
- function describeInherited(Fs, sys, streams, livePath, actions = []) {
4258
+ function describeInherited(Fs, sys, streams2, livePath, actions = []) {
4259
4259
  const table = /* @__PURE__ */ new Map();
4260
4260
  for (const stream of Fs.streams) {
4261
4261
  if (stream) table.set(stream.fd, { stream, cloexec: closesOnExec(stream) });
@@ -4270,7 +4270,7 @@ function describeInherited(Fs, sys, streams, livePath, actions = []) {
4270
4270
  for (const [fd, { stream, cloexec }] of table) {
4271
4271
  if (fd > 2 && !cloexec) slots3.set(fd, stream);
4272
4272
  }
4273
- const promote = vfsPromoter(Fs, sys, streams, livePath);
4273
+ const promote = vfsPromoter(Fs, sys, streams2, livePath);
4274
4274
  const out = [];
4275
4275
  for (const [fd, stream] of slots3) {
4276
4276
  promote(stream);
@@ -4299,50 +4299,50 @@ function place(Fs, stream, fd) {
4299
4299
  Fs.closeStream(stream.fd);
4300
4300
  return moved;
4301
4301
  }
4302
- function placeholder(Fs, streams, entry) {
4302
+ function placeholder(Fs, streams2, entry) {
4303
4303
  const access = entry.flags ?? O_RDWR;
4304
- if (entry.kind === "socket") return streams.socketStream(access);
4304
+ if (entry.kind === "socket") return streams2.socketStream(access);
4305
4305
  if (entry.kind === "tty") return Fs.open("/dev/tty", O_RDWR);
4306
4306
  if (entry.kind === "stream" || entry.kind === "clipboard" || entry.kind === "sealed")
4307
4307
  return Fs.open("/dev/null", access);
4308
4308
  Fs.mkdirTree(PLACEHOLDER_DIR);
4309
4309
  return Fs.open(`${PLACEHOLDER_DIR}/${entry.fd}`, access | O_CREAT3);
4310
4310
  }
4311
- function asFifo(stream, streams, identity) {
4312
- const inos = streamInos.get(streams) ?? /* @__PURE__ */ new Map();
4313
- streamInos.set(streams, inos);
4311
+ function asFifo(stream, streams2, identity) {
4312
+ const inos = streamInos.get(streams2) ?? /* @__PURE__ */ new Map();
4313
+ streamInos.set(streams2, inos);
4314
4314
  const fixed = inos.get(identity) ?? nextStreamIno++;
4315
4315
  inos.set(identity, fixed);
4316
4316
  const node = stream.node;
4317
- streams.describe(stream, `pipe:[${fixed}]`, () => ({
4317
+ streams2.describe(stream, `pipe:[${fixed}]`, () => ({
4318
4318
  ...node.node_ops?.getattr?.(node),
4319
4319
  mode: FIFO_MODE,
4320
4320
  ino: fixed,
4321
4321
  size: 0
4322
4322
  }));
4323
4323
  }
4324
- function placeKernelStream(Fs, streams, entry) {
4325
- const stream = place(Fs, placeholder(Fs, streams, entry), entry.fd);
4324
+ function placeKernelStream(Fs, streams2, entry) {
4325
+ const stream = place(Fs, placeholder(Fs, streams2, entry), entry.fd);
4326
4326
  if (entry.kind === "file") {
4327
- streams.attachFile(stream, entry.kernel);
4328
- streams.sizeFromKernel(stream, entry.kernel);
4329
- } else if (entry.kind === "socket") streams.attachSocket(stream, entry.kernel);
4330
- else streams.attach(stream, entry.kernel, entry.kind === "tty");
4331
- if (entry.kind === "clipboard") streams.reportClose(entry.kernel);
4332
- if (entry.kind === "sealed" || entry.kind === "clipboard") streams.nameDevice(stream, entry.kind);
4333
- if (entry.kind === "tty") streams.nameTerminal(stream);
4327
+ streams2.attachFile(stream, entry.kernel);
4328
+ streams2.sizeFromKernel(stream, entry.kernel);
4329
+ } else if (entry.kind === "socket") streams2.attachSocket(stream, entry.kernel);
4330
+ else streams2.attach(stream, entry.kernel, entry.kind === "tty");
4331
+ if (entry.kind === "clipboard") streams2.reportClose(entry.kernel);
4332
+ if (entry.kind === "sealed" || entry.kind === "clipboard") streams2.nameDevice(stream, entry.kind);
4333
+ if (entry.kind === "tty") streams2.nameTerminal(stream);
4334
4334
  if (entry.kind === "stream") {
4335
- asFifo(stream, streams, entry.desc !== void 0 ? `d${entry.desc}` : `k${entry.kernel}`);
4335
+ asFifo(stream, streams2, entry.desc !== void 0 ? `d${entry.desc}` : `k${entry.kernel}`);
4336
4336
  }
4337
4337
  setCloseOnExec(stream, entry.cloexec === true);
4338
4338
  return stream;
4339
4339
  }
4340
- function restoreForkedStreams(Fs, streams, table) {
4340
+ function restoreForkedStreams(Fs, streams2, table) {
4341
4341
  for (const stream of Fs.streams) if (stream) Fs.closeStream(stream.fd);
4342
4342
  for (const entry of table) {
4343
4343
  try {
4344
4344
  if ("kernel" in entry) {
4345
- placeKernelStream(Fs, streams, entry);
4345
+ placeKernelStream(Fs, streams2, entry);
4346
4346
  } else {
4347
4347
  const placed = place(
4348
4348
  Fs,
@@ -4410,14 +4410,14 @@ function forkRestarted(deps, state, snapshotAt) {
4410
4410
  let memory = state.memory;
4411
4411
  let seen = snapshotAt;
4412
4412
  return restarted(() => {
4413
- const streams = deps.describeFork();
4413
+ const streams2 = deps.describeFork();
4414
4414
  const now = deps.deliveries?.();
4415
4415
  if (now !== seen) {
4416
4416
  seen = now;
4417
4417
  const live = deps.memory?.();
4418
4418
  if (live) memory = new Uint8Array(live.buffer).slice();
4419
4419
  }
4420
- const forked = { ...state, memory, streams, cwd: deps.Fs.cwd() };
4420
+ const forked = { ...state, memory, streams: streams2, cwd: deps.Fs.cwd() };
4421
4421
  return deps.transport.call(
4422
4422
  { op: "proc-fork", state: forked, restart: true },
4423
4423
  Infinity,
@@ -4729,6 +4729,8 @@ var init_process_signals = __esm({
4729
4729
  unwinding = false;
4730
4730
  quieted = 0;
4731
4731
  delivered = 0;
4732
+ raised = 0;
4733
+ entering = 0;
4732
4734
  raw;
4733
4735
  header;
4734
4736
  hooks;
@@ -4791,9 +4793,18 @@ var init_process_signals = __esm({
4791
4793
  const header = this.header;
4792
4794
  const pending = Atomics.load(header, SAB_I_SIGNALS) & ~Atomics.load(header, SAB_I_BLOCKED) | Atomics.load(header, SAB_I_TIMERS) | Atomics.load(header, SAB_I_KILLED);
4793
4795
  if (pending === 0) return false;
4794
- this.deliver();
4796
+ if (this.entering === 0) this.raised = this.quieted > 0 ? -1 : 0;
4797
+ this.entering++;
4798
+ try {
4799
+ this.deliver();
4800
+ } finally {
4801
+ this.entering--;
4802
+ }
4795
4803
  return true;
4796
4804
  }
4805
+ raisedOnEntry() {
4806
+ return this.raised;
4807
+ }
4797
4808
  deliver() {
4798
4809
  if (this.quieted > 0) return;
4799
4810
  const killed = Atomics.load(this.header, SAB_I_KILLED);
@@ -4806,6 +4817,7 @@ var init_process_signals = __esm({
4806
4817
  const pending = blocked === 0 ? Atomics.exchange(this.header, SAB_I_SIGNALS, 0) : Atomics.and(this.header, SAB_I_SIGNALS, blocked) & ~blocked;
4807
4818
  if (this.depth <= 1) this.lastDelivered = pending | (timers & 1 ? sigbit(SIG.ALRM) : 0);
4808
4819
  if (pending !== 0 || timers !== 0) this.delivered++;
4820
+ this.raised |= pending | (timers & 1 ? sigbit(SIG.ALRM) : 0) | (timers & ~1 ? -1 : 0);
4809
4821
  for (let which = 0; which < 3; which++) {
4810
4822
  if (timers & 1 << which) this.hooks.timer?.(which);
4811
4823
  }
@@ -4828,7 +4840,7 @@ function resolved(Fs, addr) {
4828
4840
  return { family: "unix", path: normalizePath(path) };
4829
4841
  }
4830
4842
  function createSocketKernel(deps) {
4831
- const { transport, Fs, sys, streams } = deps;
4843
+ const { transport, Fs, sys, streams: streams2 } = deps;
4832
4844
  const call2 = (req) => {
4833
4845
  const r = transport.call(req, Number.POSITIVE_INFINITY, req.op);
4834
4846
  if (!r.ok) throw new SyscallError(r.errno);
@@ -4864,12 +4876,12 @@ function createSocketKernel(deps) {
4864
4876
  const install = (k, nonblock, cloexec = false) => {
4865
4877
  let stream;
4866
4878
  try {
4867
- stream = streams.socketStream(O_RDWR2 | (nonblock ? O_NONBLOCK : 0));
4879
+ stream = streams2.socketStream(O_RDWR2 | (nonblock ? O_NONBLOCK : 0));
4868
4880
  } catch (e) {
4869
4881
  sys.close(k);
4870
4882
  throw e;
4871
4883
  }
4872
- streams.attachSocket(stream, k);
4884
+ streams2.attachSocket(stream, k);
4873
4885
  setCloseOnExec(stream, cloexec);
4874
4886
  return stream.fd;
4875
4887
  };
@@ -5562,9 +5574,9 @@ function kernelSys(transport) {
5562
5574
  }
5563
5575
  };
5564
5576
  }
5565
- function wireKernelFd(Fs, streams, entry) {
5577
+ function wireKernelFd(Fs, streams2, entry) {
5566
5578
  if (entry.device && openDevice(Fs, entry.fd, entry.device)) return;
5567
- placeKernelStream(Fs, streams, {
5579
+ placeKernelStream(Fs, streams2, {
5568
5580
  ...entry,
5569
5581
  kind: entry.device ? "stream" : entry.kind,
5570
5582
  kernel: entry.fd
@@ -5589,7 +5601,7 @@ function openAt(Fs, fd, path, flags) {
5589
5601
  }
5590
5602
  return true;
5591
5603
  }
5592
- function wireKernelStdio(Fs, streams, sys) {
5604
+ function wireKernelStdio(Fs, streams2, sys) {
5593
5605
  for (const fd of [0, 1, 2]) {
5594
5606
  const stream = Fs.getStream(fd);
5595
5607
  if (!stream) continue;
@@ -5600,11 +5612,11 @@ function wireKernelStdio(Fs, streams, sys) {
5600
5612
  const flags = sys?.access ? stream.flags & ~O_ACCMODE5 | accessMode(sys.access(fd)) : stream.flags;
5601
5613
  Fs.closeStream(fd);
5602
5614
  const kernel = { fd, kernel: fd, kind, flags };
5603
- placeKernelStream(Fs, streams, kernel).flags = flags;
5615
+ placeKernelStream(Fs, streams2, kernel).flags = flags;
5604
5616
  continue;
5605
5617
  }
5606
- streams.attach(stream, fd);
5607
- streams.nameTerminal(stream);
5618
+ streams2.attach(stream, fd);
5619
+ streams2.nameTerminal(stream);
5608
5620
  }
5609
5621
  }
5610
5622
  function glueBody(glue) {
@@ -5703,6 +5715,11 @@ function credSyncTransport(gated, early, cred) {
5703
5715
  }
5704
5716
  };
5705
5717
  }
5718
+ function sigpipeSpared(transport) {
5719
+ const req = { op: "proc-kill-self", sig: SIG.PIPE, probe: true };
5720
+ const r = transport.call(req, Number.POSITIVE_INFINITY, "proc-kill-self");
5721
+ return r.ok && !(r.kind === "json" && r.json === "terminate");
5722
+ }
5706
5723
  async function runWasmProcess(init, port2, deps = {}) {
5707
5724
  const signals = new SignalGate(
5708
5725
  createSyncSabTransport(init.sab, port2, {
@@ -5810,10 +5827,10 @@ async function runWasmProcess(init, port2, deps = {}) {
5810
5827
  });
5811
5828
  early = () => signals.quiet(() => vfs.flushDirty());
5812
5829
  closeDropsLocks(running.FS, sys);
5813
- const sigpipe = () => running.sliccSigpipe?.() === 1;
5830
+ const sigpipe = () => running.sliccSigpipe?.() === 1 || sigpipeSpared(gated);
5814
5831
  const restartable = () => signals.restartable();
5815
5832
  const owners = init.owners ? { owners: true } : {};
5816
- const streams = new KernelStreams(running.FS, sys, {
5833
+ const streams2 = new KernelStreams(running.FS, sys, {
5817
5834
  sigpipe,
5818
5835
  restartable,
5819
5836
  ...owners,
@@ -5821,21 +5838,21 @@ async function runWasmProcess(init, port2, deps = {}) {
5821
5838
  });
5822
5839
  trackCloseOnExec(running.FS);
5823
5840
  quietQuit(running.FS, (on) => {
5824
- streams.quitting = on;
5841
+ streams2.quitting = on;
5825
5842
  });
5826
- atExit = () => streams.exiting();
5843
+ atExit = () => streams2.exiting();
5827
5844
  useMounts(running.FS, init.env, true);
5828
5845
  useZeroDevices(running.FS);
5829
5846
  useProcfs(running.FS, sys, init.pid);
5830
- if (init.fork) restoreForkedStreams(running.FS, streams, init.fork.streams ?? []);
5847
+ if (init.fork) restoreForkedStreams(running.FS, streams2, init.fork.streams ?? []);
5831
5848
  else {
5832
- wireKernelStdio(running.FS, streams, sys);
5833
- for (const entry of init.fds ?? []) wireKernelFd(running.FS, streams, entry);
5849
+ wireKernelStdio(running.FS, streams2, sys);
5850
+ for (const entry of init.fds ?? []) wireKernelFd(running.FS, streams2, entry);
5834
5851
  }
5835
5852
  const pipefs = ownValue(running, "PIPEFS");
5836
- if (pipefs) streams.usePipes(pipefs);
5837
- streams.useControllingTerminal();
5838
- streams.useKernelFdMetadata();
5853
+ if (pipefs) streams2.usePipes(pipefs);
5854
+ streams2.useControllingTerminal();
5855
+ streams2.useKernelFdMetadata();
5839
5856
  useDevFd(running.FS);
5840
5857
  useDevRemoval(running.FS);
5841
5858
  useFileMmap(running.FS, {
@@ -5855,9 +5872,9 @@ async function runWasmProcess(init, port2, deps = {}) {
5855
5872
  restartable,
5856
5873
  memory: () => memory,
5857
5874
  deliveries: () => signals.deliveries(),
5858
- describeFork: () => describeForFork(running.FS, sys, streams, livePath),
5859
- inherit: (actions) => describeInherited(running.FS, sys, streams, livePath, actions),
5860
- stdioPromoter: () => vfsPromoter(running.FS, sys, streams, livePath),
5875
+ describeFork: () => describeForFork(running.FS, sys, streams2, livePath),
5876
+ inherit: (actions) => describeInherited(running.FS, sys, streams2, livePath, actions),
5877
+ stdioPromoter: () => vfsPromoter(running.FS, sys, streams2, livePath),
5861
5878
  ...callerOwner(running.FS, init)
5862
5879
  });
5863
5880
  running.sliccKernel.http = createHttpKernel(transport);
@@ -5866,15 +5883,15 @@ async function runWasmProcess(init, port2, deps = {}) {
5866
5883
  transport,
5867
5884
  Fs: running.FS,
5868
5885
  sys,
5869
- streams,
5886
+ streams: streams2,
5870
5887
  sigpipe,
5871
5888
  restartable
5872
5889
  });
5873
- return runWithFlush(running, init, streams, vfs);
5890
+ return runWithFlush(running, init, streams2, vfs);
5874
5891
  }
5875
- function runWithFlush(running, init, streams, vfs) {
5892
+ function runWithFlush(running, init, streams2, vfs) {
5876
5893
  try {
5877
- return streams.exitStatus(runMain(running, init));
5894
+ return streams2.exitStatus(runMain(running, init));
5878
5895
  } finally {
5879
5896
  try {
5880
5897
  vfs.flush();
@@ -6419,7 +6436,7 @@ function pinnedIo2(bridge, handle, rewriting) {
6419
6436
  } : {}
6420
6437
  };
6421
6438
  }
6422
- var WasiError, FileBuffer, LocalFile, MAX_LINKS, MISS_TTL_MS, FS_GEN, RING2, RING_SIZE2, SLOT2, SHARED_IDS_BYTES, StatCache;
6439
+ var WasiError, FileBuffer, LocalFile, MAX_LINKS, MISS_TTL_MS, FS_GEN, CRED_GEN, RING2, RING_SIZE2, SLOT2, SHARED_IDS_BYTES, StatCache;
6423
6440
  var init_wasi_files = __esm({
6424
6441
  "src/process/wasi/wasi-files.ts"() {
6425
6442
  "use strict";
@@ -6641,6 +6658,7 @@ var init_wasi_files = __esm({
6641
6658
  MAX_LINKS = 40;
6642
6659
  MISS_TTL_MS = 20;
6643
6660
  FS_GEN = 4;
6661
+ CRED_GEN = 5;
6644
6662
  RING2 = 8;
6645
6663
  RING_SIZE2 = 64;
6646
6664
  SLOT2 = 3;
@@ -6861,6 +6879,48 @@ var init_slicc_sem = __esm({
6861
6879
  }
6862
6880
  });
6863
6881
 
6882
+ // src/process/wasi/wasi-cred.ts
6883
+ var CredCache;
6884
+ var init_wasi_cred = __esm({
6885
+ "src/process/wasi/wasi-cred.ts"() {
6886
+ "use strict";
6887
+ init_wasi_files();
6888
+ CredCache = class {
6889
+ cred;
6890
+ stamp = 0;
6891
+ fetch;
6892
+ shared;
6893
+ constructor(fetch, shared) {
6894
+ this.fetch = fetch;
6895
+ this.shared = shared;
6896
+ }
6897
+ gen() {
6898
+ return this.shared ? Atomics.load(this.shared, CRED_GEN) : 0;
6899
+ }
6900
+ get() {
6901
+ const gen = this.gen();
6902
+ if (this.cred === void 0 || this.stamp !== gen) {
6903
+ this.cred = this.fetch();
6904
+ this.stamp = gen;
6905
+ }
6906
+ return this.cred;
6907
+ }
6908
+ change(apply2) {
6909
+ const seen = this.gen();
6910
+ const cred = apply2();
6911
+ if (!this.shared) {
6912
+ this.cred = cred;
6913
+ return cred;
6914
+ }
6915
+ const was = Atomics.add(this.shared, CRED_GEN, 1);
6916
+ this.cred = was === seen ? cred : void 0;
6917
+ this.stamp = was + 1;
6918
+ return cred;
6919
+ }
6920
+ };
6921
+ }
6922
+ });
6923
+
6864
6924
  // src/kernel/pipe.ts
6865
6925
  var PIPE_CAPACITY;
6866
6926
  var init_pipe = __esm({
@@ -7949,6 +8009,92 @@ var init_wasi_termios = __esm({
7949
8009
  }
7950
8010
  });
7951
8011
 
8012
+ // src/process/wasi/wasix-epoll.ts
8013
+ function timeoutMs(ns) {
8014
+ const value2 = BigInt.asUintN(64, ns);
8015
+ if (value2 === FOREVER) return -1;
8016
+ const ms = (value2 + NS_PER_MS2 - 1n) / NS_PER_MS2;
8017
+ return ms > BigInt(MAX_TIMEOUT_MS) ? -1 : Number(ms);
8018
+ }
8019
+ function wasixEpollImports(host) {
8020
+ const { mem, fds, o } = host;
8021
+ const call2 = (req) => o.kernel.call(req);
8022
+ const kernelFd = (fd, refusal2) => {
8023
+ const e = fds.find(fd);
8024
+ if (!e) throw new WasiError("EBADF");
8025
+ if (e.type !== "kernel") throw new WasiError(refusal2);
8026
+ };
8027
+ const writeEvents2 = (ptr, events) => {
8028
+ const view = mem.view();
8029
+ events.forEach((ev, i) => {
8030
+ const at = ptr + i * EVENT_SIZE;
8031
+ mem.bytes(at, EVENT_SIZE).fill(0);
8032
+ view.setUint32(at, ev.events, true);
8033
+ mem.bytes(at + DATA_OFFSET, DATA_SIZE).set(ev.data);
8034
+ });
8035
+ };
8036
+ return {
8037
+ epoll_create: (out) => {
8038
+ const fd = call2({ op: "epoll-create" });
8039
+ fds.adopt(fd, "stream", false);
8040
+ mem.view().setUint32(out, fd, true);
8041
+ },
8042
+ epoll_ctl: (epfd, op, fd, event) => {
8043
+ const how = (host.strictEpoll ? WASIX_OPS : DUAL_OPS)[op];
8044
+ if (!how) throw new WasiError("EINVAL");
8045
+ kernelFd(epfd, "EINVAL");
8046
+ kernelFd(fd, "EPERM");
8047
+ if (how !== "del" && event === 0) throw new WasiError("EINVAL");
8048
+ const events = event === 0 ? 0 : mem.view().getUint32(event, true);
8049
+ const data = event === 0 ? [] : [...mem.bytes(event + DATA_OFFSET, DATA_SIZE)];
8050
+ call2({ op: "epoll-ctl", epfd, how, fd, events, data });
8051
+ },
8052
+ epoll_wait: (epfd, ptr, maxevents, timeout, out) => {
8053
+ mem.view().setUint32(out, 0, true);
8054
+ if ((maxevents | 0) <= 0) throw new WasiError("EINVAL");
8055
+ kernelFd(epfd, "EINVAL");
8056
+ const max = Math.min(maxevents | 0, MAX_EVENTS);
8057
+ const ms = host.entered ? 0 : timeoutMs(timeout);
8058
+ const events = call2({ op: "epoll-wait", epfd, max, timeoutMs: ms });
8059
+ if (host.entered && events.length === 0 && timeoutMs(timeout) !== 0) return E.INTR;
8060
+ writeEvents2(ptr, events);
8061
+ mem.view().setUint32(out, events.length, true);
8062
+ return E.SUCCESS;
8063
+ },
8064
+ fd_event: (initial, flags, out) => {
8065
+ const value2 = BigInt.asUintN(64, initial);
8066
+ if (value2 > EVENTFD_MAX) throw new WasiError("EINVAL");
8067
+ const fd = call2({
8068
+ op: "eventfd-open",
8069
+ initial: value2.toString(),
8070
+ semaphore: (flags & EVENTFD_SEMAPHORE) !== 0
8071
+ });
8072
+ fds.adopt(fd, "stream", (flags & EVENTFD_NONBLOCK) !== 0);
8073
+ mem.view().setUint32(out, fd, true);
8074
+ }
8075
+ };
8076
+ }
8077
+ var EVENT_SIZE, DATA_OFFSET, DATA_SIZE, MAX_EVENTS, FOREVER, MAX_TIMEOUT_MS, NS_PER_MS2, EVENTFD_SEMAPHORE, EVENTFD_NONBLOCK, EVENTFD_MAX, WASIX_OPS, DUAL_OPS;
8078
+ var init_wasix_epoll = __esm({
8079
+ "src/process/wasi/wasix-epoll.ts"() {
8080
+ "use strict";
8081
+ init_wasi_abi();
8082
+ init_wasi_files();
8083
+ EVENT_SIZE = 32;
8084
+ DATA_OFFSET = 8;
8085
+ DATA_SIZE = 24;
8086
+ MAX_EVENTS = 4096;
8087
+ FOREVER = 0xffffffffffffffffn;
8088
+ MAX_TIMEOUT_MS = 2147483647;
8089
+ NS_PER_MS2 = 1000000n;
8090
+ EVENTFD_SEMAPHORE = 1;
8091
+ EVENTFD_NONBLOCK = 4;
8092
+ EVENTFD_MAX = 0xfffffffffffffffen;
8093
+ WASIX_OPS = ["add", "mod", "del"];
8094
+ DUAL_OPS = ["add", "set", "del", "mod"];
8095
+ }
8096
+ });
8097
+
7952
8098
  // src/kernel/net/datagram-wire.ts
7953
8099
  function decodeReceived(raw) {
7954
8100
  const view = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
@@ -8335,7 +8481,7 @@ function filestatOf(path, s) {
8335
8481
  size: BigInt(s.size),
8336
8482
  ino: s.ino !== void 0 ? BigInt(s.ino) : pathInode(path),
8337
8483
  ...s.nlink !== void 0 ? { nlink: BigInt(s.nlink) } : {},
8338
- mtimeNs: BigInt(Math.round(s.mtimeMs ?? 0)) * NS_PER_MS2
8484
+ mtimeNs: BigInt(Math.round(s.mtimeMs ?? 0)) * NS_PER_MS3
8339
8485
  };
8340
8486
  }
8341
8487
  function kernelFiletype(kind) {
@@ -8385,7 +8531,7 @@ function wrap(table) {
8385
8531
  }
8386
8532
  return out;
8387
8533
  }
8388
- var WasiExit, IDS, NS_PER_MS2, AT_SYMLINK_NOFOLLOW2, AT_EACCESS2, ROOT_IDS, GONE, S_IFIFO, DEFAULT_UMASK, MONOTONIC_BASE, MAX_READ, SIGPIPE_EXIT, SIG_IGN, SEALED_MODE, WasiHost;
8534
+ var WasiExit, IDS, NS_PER_MS3, AT_SYMLINK_NOFOLLOW2, AT_EACCESS2, ROOT_IDS, GONE, S_IFIFO, DEFAULT_UMASK, MONOTONIC_BASE, MAX_READ, SIGPIPE_EXIT, SIG_IGN, SEALED_MODE, WasiHost;
8389
8535
  var init_wasi_host = __esm({
8390
8536
  "src/process/wasi/wasi-host.ts"() {
8391
8537
  "use strict";
@@ -8393,14 +8539,17 @@ var init_wasi_host = __esm({
8393
8539
  init_physical_path();
8394
8540
  init_cpu_clock();
8395
8541
  init_cred();
8542
+ init_signals();
8396
8543
  init_slicc_lock();
8397
8544
  init_slicc_sem();
8398
8545
  init_wasi_abi();
8546
+ init_wasi_cred();
8399
8547
  init_wasi_fds();
8400
8548
  init_wasi_files();
8401
8549
  init_wasi_memory();
8402
8550
  init_wasi_poll();
8403
8551
  init_wasi_termios();
8552
+ init_wasix_epoll();
8404
8553
  init_wasix_sockets();
8405
8554
  WasiExit = class extends Error {
8406
8555
  code;
@@ -8410,26 +8559,30 @@ var init_wasi_host = __esm({
8410
8559
  }
8411
8560
  };
8412
8561
  IDS = ["ruid", "euid", "suid", "rgid", "egid", "sgid"];
8413
- NS_PER_MS2 = 1000000n;
8562
+ NS_PER_MS3 = 1000000n;
8414
8563
  AT_SYMLINK_NOFOLLOW2 = 1;
8415
8564
  AT_EACCESS2 = 2;
8416
8565
  ROOT_IDS = Object.freeze({ uid: 0, gid: 0 });
8417
8566
  GONE = /* @__PURE__ */ new Set(["ENOENT", "ENOTDIR"]);
8418
8567
  S_IFIFO = 4096;
8419
8568
  DEFAULT_UMASK = 18;
8420
- MONOTONIC_BASE = BigInt(Math.round(performance.timeOrigin)) * NS_PER_MS2;
8569
+ MONOTONIC_BASE = BigInt(Math.round(performance.timeOrigin)) * NS_PER_MS3;
8421
8570
  MAX_READ = 1024 * 1024;
8422
- SIGPIPE_EXIT = 141;
8571
+ SIGPIPE_EXIT = 128 + SIG.PIPE;
8423
8572
  SIG_IGN = 1;
8424
8573
  SEALED_MODE = 8630;
8425
8574
  WasiHost = class {
8426
8575
  mem = new WasiMemory();
8427
8576
  fds;
8577
+ creds;
8428
8578
  started = performance.now();
8429
8579
  cache;
8430
8580
  startCwd;
8431
8581
  interruptWakes = false;
8582
+ strictEpoll = false;
8432
8583
  entered = false;
8584
+ enteredSignals = 0;
8585
+ raisedOnEntry;
8433
8586
  onRaise;
8434
8587
  muted;
8435
8588
  signals;
@@ -8460,6 +8613,10 @@ var init_wasi_host = __esm({
8460
8613
  this.o = { ...o, kernel: { sys, call: call2 } };
8461
8614
  this.startCwd = o.cwd;
8462
8615
  this.fds = new WasiFds(this.o.kernel, o.fs);
8616
+ this.creds = new CredCache(
8617
+ () => this.o.kernel.call({ op: "proc-cred" }),
8618
+ o.credGen ?? o.shared
8619
+ );
8463
8620
  if (o.shared) this.fds.share(o.shared, true);
8464
8621
  else if (o.forked) this.fds.restore(o.forked.fds, o.forked.cloexec);
8465
8622
  else this.fds.setup(o.cwd, o.inherited ?? [], o.preopenRoot === true);
@@ -8499,7 +8656,7 @@ var init_wasi_host = __esm({
8499
8656
  own.call(this.o.fs, path, idOf3(uid), idOf3(gid), follow2, handle);
8500
8657
  };
8501
8658
  const caller = () => {
8502
- const cred = this.o.kernel.call({ op: "proc-cred" });
8659
+ const cred = this.creds.get();
8503
8660
  return [cred.euid, cred.egid];
8504
8661
  };
8505
8662
  const owner = (st, out) => {
@@ -8604,7 +8761,7 @@ var init_wasi_host = __esm({
8604
8761
  }),
8605
8762
  umount2: (tp, tl, flags) => void this.o.kernel.call({ op: "umount", target: path(tp, tl), flags }),
8606
8763
  cred_get: (out) => {
8607
- const cred = this.o.kernel.call({ op: "proc-cred" });
8764
+ const cred = this.creds.get();
8608
8765
  const view = mem.view();
8609
8766
  view.getUint32(out + 20, true);
8610
8767
  IDS.forEach((key, i) => void view.setUint32(out + i * 4, cred[key], true));
@@ -8614,7 +8771,7 @@ var init_wasi_host = __esm({
8614
8771
  IDS.forEach((key, i) => {
8615
8772
  if (ids[i] !== -1) change[key] = ids[i] >>> 0;
8616
8773
  });
8617
- void this.o.kernel.call({ op: "proc-setcred", change });
8774
+ void this.creds.change(() => this.o.kernel.call({ op: "proc-setcred", change }));
8618
8775
  },
8619
8776
  ...semImports(this),
8620
8777
  ...lockImports({
@@ -8638,7 +8795,7 @@ var init_wasi_host = __esm({
8638
8795
  }
8639
8796
  }),
8640
8797
  groups_get: (buf, cap, count) => {
8641
- const { groups } = this.o.kernel.call({ op: "proc-cred" });
8798
+ const { groups } = this.creds.get();
8642
8799
  if (cap !== 0 && cap < groups.length) throw new WasiError("EINVAL");
8643
8800
  const shown = cap === 0 ? [] : groups;
8644
8801
  const view = mem.view();
@@ -8651,7 +8808,9 @@ var init_wasi_host = __esm({
8651
8808
  if (n < 0 || n > MAX_GROUPS) throw new WasiError("EINVAL");
8652
8809
  const view = mem.view();
8653
8810
  const groups = Array.from({ length: n }, (_, i) => view.getUint32(buf + i * 4, true));
8654
- void this.o.kernel.call({ op: "proc-setcred", change: { groups } });
8811
+ void this.creds.change(
8812
+ () => this.o.kernel.call({ op: "proc-setcred", change: { groups } })
8813
+ );
8655
8814
  },
8656
8815
  sigaction_set: (sig, disposition, flags) => {
8657
8816
  if (!this.signals) return E.NOSYS;
@@ -8666,6 +8825,24 @@ var init_wasi_host = __esm({
8666
8825
  view.setUint32(old + 4, oldHi, true);
8667
8826
  }) : E.NOSYS,
8668
8827
  sigmask_poll: (lo, hi, inPtr, outPtr, n, nevents) => this.sigmask ? this.maskedPoll(this.sigmask, [lo, hi], [inPtr, outPtr, n, nevents]) : E.NOSYS,
8828
+ sigmask_epoll_wait: (lo, hi, epfd, events, max, timeout, nevents) => this.sigmask ? this.maskedEpoll(
8829
+ this.sigmask,
8830
+ [lo, hi],
8831
+ nevents,
8832
+ (epoll) => epoll(epfd, events, max, timeout, nevents)
8833
+ ) : E.NOSYS,
8834
+ sigwait: (lo, _hi, timeout, out) => {
8835
+ const mask = this.sigmask;
8836
+ if (!mask) return E.NOSYS;
8837
+ mem.view().setUint32(out, 0, true);
8838
+ return mask.sigwait(
8839
+ lo,
8840
+ timeout,
8841
+ (set) => void this.o.kernel.call({ op: "sig-waiting", tid: mask.tid, set }),
8842
+ (sig) => void mem.view().setUint32(out, sig, true),
8843
+ this.entered
8844
+ );
8845
+ },
8669
8846
  sigpending_get: (out) => {
8670
8847
  if (!this.sigmask) return E.NOSYS;
8671
8848
  mem.view().setBigUint64(out, BigInt(this.sigmask.pending()), true);
@@ -8698,6 +8875,7 @@ var init_wasi_host = __esm({
8698
8875
  try {
8699
8876
  this.mem.view().setUint32(nevents, 0, true);
8700
8877
  if (mask.deliverUnblocked()) return E.INTR;
8878
+ this.settleEntry(mask);
8701
8879
  if (n > 0) return this.poll(inPtr, outPtr, n, nevents);
8702
8880
  return this.entered ? E.INTR : this.suspend();
8703
8881
  } finally {
@@ -8705,6 +8883,23 @@ var init_wasi_host = __esm({
8705
8883
  mask.restore(old);
8706
8884
  }
8707
8885
  }
8886
+ epollWait;
8887
+ settleEntry(mask) {
8888
+ if (this.entered && (this.enteredSignals & ~mask.blockedBits()) === 0) this.entered = false;
8889
+ }
8890
+ maskedEpoll(mask, set, nevents, wait2) {
8891
+ const old = mask.swap(set[0], set[1]);
8892
+ try {
8893
+ this.mem.view().setUint32(nevents, 0, true);
8894
+ if (mask.deliverUnblocked()) return E.INTR;
8895
+ this.settleEntry(mask);
8896
+ this.epollWait ??= wasixEpollImports(this).epoll_wait;
8897
+ return wait2(this.epollWait) ?? E.SUCCESS;
8898
+ } finally {
8899
+ mask.deliverUnblocked();
8900
+ mask.restore(old);
8901
+ }
8902
+ }
8708
8903
  suspend() {
8709
8904
  for (; ; ) {
8710
8905
  try {
@@ -8727,7 +8922,7 @@ var init_wasi_host = __esm({
8727
8922
  return this.cache;
8728
8923
  }
8729
8924
  now(id) {
8730
- if (id === CLOCK.REALTIME) return BigInt(Date.now()) * NS_PER_MS2;
8925
+ if (id === CLOCK.REALTIME) return BigInt(Date.now()) * NS_PER_MS3;
8731
8926
  if (id === CLOCK.MONOTONIC) {
8732
8927
  return MONOTONIC_BASE + BigInt(Math.round(performance.now() * 1e6));
8733
8928
  }
@@ -9061,7 +9256,7 @@ var init_wasi_host = __esm({
9061
9256
  return this.fds.kind(fd, e) === "file" ? this.changed(fd, e, n) : n;
9062
9257
  } catch (err) {
9063
9258
  const broken = err.code === "EPIPE";
9064
- if (broken && this.fds.kind(fd, e) !== "socket") throw new WasiExit(SIGPIPE_EXIT);
9259
+ if (broken && this.fds.kind(fd, e) !== "socket") this.brokenPipe();
9065
9260
  throw err;
9066
9261
  }
9067
9262
  }
@@ -9073,6 +9268,18 @@ var init_wasi_host = __esm({
9073
9268
  }
9074
9269
  return this.file(fd, "write").write(data);
9075
9270
  }
9271
+ brokenPipe() {
9272
+ let action;
9273
+ try {
9274
+ action = this.o.kernel.call({ op: "proc-kill-self", sig: SIG.PIPE, probe: true });
9275
+ } catch {
9276
+ action = "terminate";
9277
+ }
9278
+ if (action !== "terminate") return;
9279
+ const mask = this.sigmask;
9280
+ if (!mask?.blocks(SIG.PIPE)) throw new WasiExit(SIGPIPE_EXIT);
9281
+ this.o.kernel.call({ op: "thread-kill", tid: mask.tid, sig: SIG.PIPE });
9282
+ }
9076
9283
  read(fd, max) {
9077
9284
  const e = this.fds.get(fd);
9078
9285
  if (e.type === "kernel") {
@@ -9256,7 +9463,7 @@ var init_wasi_host = __esm({
9256
9463
  current ??= statOf(path);
9257
9464
  return current[field2] ?? current.mtimeMs ?? now;
9258
9465
  };
9259
- const pick = (set, setNow, value2, field2) => flags & setNow ? now : flags & set ? Number(value2 / NS_PER_MS2) : kept(field2);
9466
+ const pick = (set, setNow, value2, field2) => flags & setNow ? now : flags & set ? Number(value2 / NS_PER_MS3) : kept(field2);
9260
9467
  (follow2 ? this.o.fs.utimes : this.o.fs.lutimes).call(
9261
9468
  this.o.fs,
9262
9469
  path,
@@ -10257,7 +10464,7 @@ var init_wasi_procfs = __esm({
10257
10464
  });
10258
10465
 
10259
10466
  // src/process/wasi/wasi-sigmask.ts
10260
- var UNBLOCKABLE, LIBC_UNBLOCKABLE, SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK, kernelBits, libcBits, apply, WasiSigmask;
10467
+ var UNBLOCKABLE, LIBC_UNBLOCKABLE, FOREVER2, NS_PER_MS4, POLL_MS, SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK, kernelBits, libcBits, apply, WasiSigmask;
10261
10468
  var init_wasi_sigmask = __esm({
10262
10469
  "src/process/wasi/wasi-sigmask.ts"() {
10263
10470
  "use strict";
@@ -10266,6 +10473,9 @@ var init_wasi_sigmask = __esm({
10266
10473
  init_wasi_abi();
10267
10474
  UNBLOCKABLE = sigbit(SIG.KILL) | sigbit(SIG.STOP);
10268
10475
  LIBC_UNBLOCKABLE = 1 << SIG.KILL - 1 | 1 << SIG.STOP - 1;
10476
+ FOREVER2 = 0xffffffffffffffffn;
10477
+ NS_PER_MS4 = 1000000n;
10478
+ POLL_MS = 50;
10269
10479
  SIG_BLOCK = 0;
10270
10480
  SIG_UNBLOCK = 1;
10271
10481
  SIG_SETMASK = 2;
@@ -10282,10 +10492,12 @@ var init_wasi_sigmask = __esm({
10282
10492
  header;
10283
10493
  deliver;
10284
10494
  process;
10285
- constructor(header, deliver, process) {
10495
+ tid;
10496
+ constructor(header, deliver, process, tid = 1) {
10286
10497
  this.header = header;
10287
10498
  this.deliver = deliver;
10288
10499
  this.process = process;
10500
+ this.tid = tid;
10289
10501
  this.lo = libcBits(Atomics.load(header, SAB_I_BLOCKED));
10290
10502
  this.hi = Atomics.load(header, SAB_I_BLOCKED_HI);
10291
10503
  }
@@ -10319,6 +10531,12 @@ var init_wasi_sigmask = __esm({
10319
10531
  this.set(SIG_SETMASK, lo, hi, () => {
10320
10532
  });
10321
10533
  }
10534
+ blockedBits() {
10535
+ return Atomics.load(this.header, SAB_I_BLOCKED);
10536
+ }
10537
+ blocks(sig) {
10538
+ return (Atomics.load(this.header, SAB_I_BLOCKED) & sigbit(sig)) !== 0;
10539
+ }
10322
10540
  inherited() {
10323
10541
  return [kernelBits(this.lo), this.hi];
10324
10542
  }
@@ -10326,6 +10544,47 @@ var init_wasi_sigmask = __esm({
10326
10544
  Atomics.and(this.header, SAB_I_SIGNALS, ~sigbit(sig));
10327
10545
  if (this.process) Atomics.and(this.process, SAB_I_SIGNALS, ~sigbit(sig));
10328
10546
  }
10547
+ sigwait(setLo, timeoutNs, publish, took, entered = false) {
10548
+ const set = kernelBits(setLo | 0);
10549
+ const value2 = BigInt.asUintN(64, timeoutNs);
10550
+ const deadline = value2 === FOREVER2 ? Number.POSITIVE_INFINITY : performance.now() + Number((value2 + NS_PER_MS4 - 1n) / NS_PER_MS4);
10551
+ publish(set);
10552
+ try {
10553
+ for (; ; ) {
10554
+ const seen = Atomics.load(this.header, SAB_I_SIGNALS);
10555
+ const sig = this.take(set);
10556
+ if (sig !== 0) {
10557
+ took(sig);
10558
+ return E.SUCCESS;
10559
+ }
10560
+ if (entered || this.deliverUnblocked() || this.interrupted()) return E.INTR;
10561
+ const left = deadline - performance.now();
10562
+ if (left <= 0) return E.AGAIN;
10563
+ Atomics.wait(this.header, SAB_I_SIGNALS, seen, Math.min(left, POLL_MS));
10564
+ }
10565
+ } finally {
10566
+ publish(0);
10567
+ }
10568
+ }
10569
+ take(set) {
10570
+ for (const header of this.process ? [this.header, this.process] : [this.header]) {
10571
+ const ready = Atomics.load(header, SAB_I_SIGNALS) & set;
10572
+ if (ready === 0) continue;
10573
+ const bit = ready & -ready;
10574
+ if ((Atomics.and(header, SAB_I_SIGNALS, ~bit) & bit) !== 0) return 31 - Math.clz32(bit);
10575
+ }
10576
+ return 0;
10577
+ }
10578
+ interrupted() {
10579
+ const killed = this.process ?? this.header;
10580
+ if (Atomics.load(killed, SAB_I_KILLED) !== 0) {
10581
+ this.deliver();
10582
+ return true;
10583
+ }
10584
+ if (Atomics.load(killed, SAB_I_STOP) !== 1) return false;
10585
+ while (Atomics.load(killed, SAB_I_STOP) === 1) Atomics.wait(killed, SAB_I_STOP, 1);
10586
+ return true;
10587
+ }
10329
10588
  pending() {
10330
10589
  const own = Atomics.load(this.header, SAB_I_SIGNALS);
10331
10590
  return libcBits(own | (this.process ? Atomics.load(this.process, SAB_I_SIGNALS) : 0));
@@ -10684,91 +10943,6 @@ var init_wasix_fork = __esm({
10684
10943
  }
10685
10944
  });
10686
10945
 
10687
- // src/process/wasi/wasix-epoll.ts
10688
- function timeoutMs(ns) {
10689
- const value2 = BigInt.asUintN(64, ns);
10690
- if (value2 === FOREVER) return -1;
10691
- const ms = (value2 + NS_PER_MS3 - 1n) / NS_PER_MS3;
10692
- return ms > BigInt(MAX_TIMEOUT_MS) ? -1 : Number(ms);
10693
- }
10694
- function wasixEpollImports(host) {
10695
- const { mem, fds, o } = host;
10696
- const call2 = (req) => o.kernel.call(req);
10697
- const kernelFd = (fd, refusal2) => {
10698
- const e = fds.find(fd);
10699
- if (!e) throw new WasiError("EBADF");
10700
- if (e.type !== "kernel") throw new WasiError(refusal2);
10701
- };
10702
- const writeEvents2 = (ptr, events) => {
10703
- const view = mem.view();
10704
- events.forEach((ev, i) => {
10705
- const at = ptr + i * EVENT_SIZE;
10706
- mem.bytes(at, EVENT_SIZE).fill(0);
10707
- view.setUint32(at, ev.events, true);
10708
- mem.bytes(at + DATA_OFFSET, DATA_SIZE).set(ev.data);
10709
- });
10710
- };
10711
- return {
10712
- epoll_create: (out) => {
10713
- const fd = call2({ op: "epoll-create" });
10714
- fds.adopt(fd, "stream", false);
10715
- mem.view().setUint32(out, fd, true);
10716
- },
10717
- epoll_ctl: (epfd, op, fd, event) => {
10718
- const how = OPS[op];
10719
- if (!how) throw new WasiError("EINVAL");
10720
- kernelFd(epfd, "EINVAL");
10721
- kernelFd(fd, "EPERM");
10722
- if (how !== "del" && event === 0) throw new WasiError("EINVAL");
10723
- const events = event === 0 ? 0 : mem.view().getUint32(event, true);
10724
- const data = event === 0 ? [] : [...mem.bytes(event + DATA_OFFSET, DATA_SIZE)];
10725
- call2({ op: "epoll-ctl", epfd, how, fd, events, data });
10726
- },
10727
- epoll_wait: (epfd, ptr, maxevents, timeout, out) => {
10728
- mem.view().setUint32(out, 0, true);
10729
- if ((maxevents | 0) <= 0) throw new WasiError("EINVAL");
10730
- kernelFd(epfd, "EINVAL");
10731
- const max = Math.min(maxevents | 0, MAX_EVENTS);
10732
- const ms = host.entered ? 0 : timeoutMs(timeout);
10733
- const events = call2({ op: "epoll-wait", epfd, max, timeoutMs: ms });
10734
- if (host.entered && events.length === 0 && timeoutMs(timeout) !== 0) return E.INTR;
10735
- writeEvents2(ptr, events);
10736
- mem.view().setUint32(out, events.length, true);
10737
- return E.SUCCESS;
10738
- },
10739
- fd_event: (initial, flags, out) => {
10740
- const value2 = BigInt.asUintN(64, initial);
10741
- if (value2 > EVENTFD_MAX) throw new WasiError("EINVAL");
10742
- const fd = call2({
10743
- op: "eventfd-open",
10744
- initial: value2.toString(),
10745
- semaphore: (flags & EVENTFD_SEMAPHORE) !== 0
10746
- });
10747
- fds.adopt(fd, "stream", (flags & EVENTFD_NONBLOCK) !== 0);
10748
- mem.view().setUint32(out, fd, true);
10749
- }
10750
- };
10751
- }
10752
- var EVENT_SIZE, DATA_OFFSET, DATA_SIZE, MAX_EVENTS, FOREVER, MAX_TIMEOUT_MS, NS_PER_MS3, EVENTFD_SEMAPHORE, EVENTFD_NONBLOCK, EVENTFD_MAX, OPS;
10753
- var init_wasix_epoll = __esm({
10754
- "src/process/wasi/wasix-epoll.ts"() {
10755
- "use strict";
10756
- init_wasi_abi();
10757
- init_wasi_files();
10758
- EVENT_SIZE = 32;
10759
- DATA_OFFSET = 8;
10760
- DATA_SIZE = 24;
10761
- MAX_EVENTS = 4096;
10762
- FOREVER = 0xffffffffffffffffn;
10763
- MAX_TIMEOUT_MS = 2147483647;
10764
- NS_PER_MS3 = 1000000n;
10765
- EVENTFD_SEMAPHORE = 1;
10766
- EVENTFD_NONBLOCK = 4;
10767
- EVENTFD_MAX = 0xfffffffffffffffen;
10768
- OPS = ["add", "set", "del", "mod"];
10769
- }
10770
- });
10771
-
10772
10946
  // src/process/wasi/wasix-ffi.ts
10773
10947
  function read(view, at, type) {
10774
10948
  if (type === "i32") return view.getInt32(at, true);
@@ -11675,7 +11849,7 @@ function posixSignal(sig) {
11675
11849
  function nsToMs(ns) {
11676
11850
  return Math.ceil(Number(ns) / 1e6);
11677
11851
  }
11678
- var FDFLAGSEXT_CLOEXEC, SPAWN_OP_SIZE, SPAWN_OPS, RIGHTS_FD_WRITE, ICANON, ECHO, FUTEX_SLICE_MS, EINTR_LIBC, MAIN_HANDLE, WasixHost;
11852
+ var FDFLAGSEXT_CLOEXEC, SPAWN_OP_SIZE, SPAWN_OPS, RIGHTS_FD_WRITE, ICANON, ECHO, FUTEX_SLICE_MS, EINTR_LIBC, STRICT_EPOLL_LIBC, MAIN_HANDLE, WasixHost;
11679
11853
  var init_wasix_host = __esm({
11680
11854
  "src/process/wasi/wasix-host.ts"() {
11681
11855
  "use strict";
@@ -11699,6 +11873,7 @@ var init_wasix_host = __esm({
11699
11873
  ECHO = 8;
11700
11874
  FUTEX_SLICE_MS = 50;
11701
11875
  EINTR_LIBC = 22;
11876
+ STRICT_EPOLL_LIBC = 29;
11702
11877
  MAIN_HANDLE = 2147483647;
11703
11878
  WasixHost = class _WasixHost {
11704
11879
  process;
@@ -11717,6 +11892,7 @@ var init_wasix_host = __esm({
11717
11892
  driver,
11718
11893
  () => (this.threads?.tid ?? MAIN_TID) !== MAIN_TID
11719
11894
  );
11895
+ if (module) host.strictEpoll = (libcVersion(module) ?? 0) >= STRICT_EPOLL_LIBC;
11720
11896
  if (module && !WebAssembly.Module.imports(module).some((i) => i.name === "fd_fdflags_set")) {
11721
11897
  host.fds.implicitCloexec = true;
11722
11898
  host.interruptWakes = (libcVersion(module) ?? 0) < EINTR_LIBC;
@@ -12177,6 +12353,7 @@ __export(wasi_runtime_exports, {
12177
12353
  });
12178
12354
  function wireSignals(host, gate) {
12179
12355
  host.interrupted = () => gate.interrupt();
12356
+ host.raisedOnEntry = () => gate.raisedOnEntry();
12180
12357
  host.quietly = (fn) => gate.quiet(fn);
12181
12358
  }
12182
12359
  function catchUpFirst(host, sync) {
@@ -12202,6 +12379,7 @@ function delivering(ns, table, host, driver, before) {
12202
12379
  if (driver.idle) {
12203
12380
  before?.();
12204
12381
  host.entered = host.interrupted?.() === true;
12382
+ host.enteredSignals = host.entered ? host.raisedOnEntry?.() ?? -1 : 0;
12205
12383
  }
12206
12384
  return fn(...args);
12207
12385
  };
@@ -12216,7 +12394,7 @@ function sigmaskOf(module, sab, gate, threads, process) {
12216
12394
  }
12217
12395
  if (threads) threads.blocked = () => loadBlocked(header);
12218
12396
  const shared = process && new Int32Array(process, 0, SAB_HEADER_I32);
12219
- return new WasiSigmask(header, () => gate.deliver(), shared);
12397
+ return new WasiSigmask(header, () => gate.deliver(), shared, threads?.tid ?? MAIN_TID);
12220
12398
  }
12221
12399
  function enosys(module, name2, foreign) {
12222
12400
  const type = foreign?.[module]?.[name2];
@@ -12570,7 +12748,8 @@ async function runWasiProcess(init, port2) {
12570
12748
  ),
12571
12749
  procTree(call2, id.pid)
12572
12750
  ),
12573
- ...descriptors(init, fork, threads)
12751
+ ...descriptors(init, fork, threads),
12752
+ ...threads ? { credGen: threads.ids } : {}
12574
12753
  });
12575
12754
  host.sigmask = sigmaskOf(module, init.sab, gate, threads);
12576
12755
  if (threads) {
@@ -12950,7 +13129,11 @@ function modeOf(mode) {
12950
13129
  function callError(result, op) {
12951
13130
  const { errno: errno2, message: message2 } = result;
12952
13131
  const detailed = typeof message2 === "string" && message2 !== errno2 && DETAILED.has(op);
12953
- return new JsCallError(errno2, detailed ? `${op}: ${message2}` : op);
13132
+ return new JsCallError(
13133
+ errno2,
13134
+ detailed ? `${op}: ${message2}` : op,
13135
+ detailed ? message2 : void 0
13136
+ );
12954
13137
  }
12955
13138
  function untilAborted(work, signal) {
12956
13139
  if (!signal) return work;
@@ -12977,10 +13160,12 @@ var init_js_kernel = __esm({
12977
13160
  init_async_sab();
12978
13161
  JsCallError = class extends Error {
12979
13162
  code;
12980
- constructor(code2, what) {
13163
+ detail;
13164
+ constructor(code2, what, detail) {
12981
13165
  super(`${what}: ${code2}`);
12982
13166
  this.name = "JsCallError";
12983
13167
  this.code = code2;
13168
+ this.detail = detail;
12984
13169
  }
12985
13170
  };
12986
13171
  DETAILED = /* @__PURE__ */ new Set([
@@ -13895,6 +14080,29 @@ var init_js_exit = __esm({
13895
14080
  });
13896
14081
 
13897
14082
  // src/process/js/js-fetch.ts
14083
+ function cut(err) {
14084
+ if (!(err instanceof JsCallError) || err.code !== "EIO") return err;
14085
+ return Object.assign(new Error("other side closed"), {
14086
+ name: "SocketError",
14087
+ code: "UND_ERR_SOCKET"
14088
+ });
14089
+ }
14090
+ function givenNames(given) {
14091
+ if (given === void 0 || given instanceof Headers) return [];
14092
+ const pairs = Array.isArray(given) ? given : Object.entries(given);
14093
+ return pairs.map((pair) => String(pair[0]).toLowerCase());
14094
+ }
14095
+ function inOrder(headers, given) {
14096
+ const all = new Map(headers);
14097
+ const out = [];
14098
+ for (const name2 of [...givenNames(given), ...all.keys()]) {
14099
+ const value2 = all.get(name2);
14100
+ if (value2 === void 0) continue;
14101
+ all.delete(name2);
14102
+ out.push([name2, value2]);
14103
+ }
14104
+ return out;
14105
+ }
13898
14106
  function withoutFragment(url) {
13899
14107
  url.hash = "";
13900
14108
  return url.href;
@@ -13921,9 +14129,7 @@ function checkUrl(url) {
13921
14129
  if (protocol !== "http:" && protocol !== "https:") {
13922
14130
  throw failed3(new JsCallError("EPROTONOSUPPORT", protocol));
13923
14131
  }
13924
- if (badPort(parsed) && !local2(url)) {
13925
- throw failed3(Object.assign(new Error("bad port"), { code: "EACCES" }));
13926
- }
14132
+ if (badPort(parsed)) throw failed3(new Error("bad port"));
13927
14133
  }
13928
14134
  function rewrite(hop, status2, location) {
13929
14135
  const next2 = new URL(location, hop.url);
@@ -13935,6 +14141,9 @@ function rewrite(hop, status2, location) {
13935
14141
  );
13936
14142
  }
13937
14143
  const toGet = (status2 === 301 || status2 === 302) && hop.method === "POST" || status2 === 303 && hop.method !== "GET" && hop.method !== "HEAD";
14144
+ if (hop.stream && !toGet) {
14145
+ throw failed3(new JsCallError("EIO", `a ${status2} redirect would send a streamed body again`));
14146
+ }
13938
14147
  const crossOrigin = next2.origin !== new URL(hop.url).origin;
13939
14148
  const headers = hop.headers.filter(
13940
14149
  ([name2]) => !(toGet && BODY_HEADERS.has(name2.toLowerCase())) && !(crossOrigin && CREDENTIALS.has(name2.toLowerCase()))
@@ -14101,6 +14310,44 @@ async function bodyOf(request, cap, signal) {
14101
14310
  }
14102
14311
  return out;
14103
14312
  }
14313
+ function streams(known, request, init, url) {
14314
+ if (known.streamingBodies !== true || !(init?.body instanceof ReadableStream)) return false;
14315
+ return request.method !== "GET" && request.method !== "HEAD" && !local2(url);
14316
+ }
14317
+ async function pump(kernel, handle, stream, signal) {
14318
+ const reader = stream.getReader();
14319
+ const stop = () => void reader.cancel(signal.reason).catch(() => void 0);
14320
+ signal.addEventListener("abort", stop, { once: true });
14321
+ try {
14322
+ await pumpFrom(kernel, handle, reader, signal);
14323
+ } finally {
14324
+ signal.removeEventListener("abort", stop);
14325
+ }
14326
+ }
14327
+ async function pumpFrom(kernel, handle, reader, signal) {
14328
+ for (; ; ) {
14329
+ let bytes;
14330
+ try {
14331
+ const next2 = await reader.read();
14332
+ if (next2.done) break;
14333
+ bytes = bytesOf(next2.value);
14334
+ } catch (err) {
14335
+ await reader.cancel(err).catch(() => void 0);
14336
+ await kernel.raw({ op: "net-close", handle });
14337
+ return;
14338
+ }
14339
+ if (bytes.length === 0) continue;
14340
+ const taken = await kernel.blocking({ op: "net-write", handle, bytes }, signal).then(
14341
+ () => true,
14342
+ () => false
14343
+ );
14344
+ if (!taken) {
14345
+ await reader.cancel().catch(() => void 0);
14346
+ return;
14347
+ }
14348
+ }
14349
+ await kernel.raw({ op: "net-end", handle });
14350
+ }
14104
14351
  function fetchOp(kernel) {
14105
14352
  const traits = /* @__PURE__ */ new Map();
14106
14353
  const traitsOf = (url) => {
@@ -14120,8 +14367,9 @@ function fetchOp(kernel) {
14120
14367
  url: hop.url,
14121
14368
  method: hop.method,
14122
14369
  headers: hop.headers,
14123
- ...hop.body ? { body: hop.body } : {}
14370
+ ...hop.stream ? { stream: true } : hop.body ? { body: hop.body } : {}
14124
14371
  });
14372
+ if (hop.stream) void pump(kernel, handle, hop.stream, signal);
14125
14373
  try {
14126
14374
  const r = await kernel.blocking({ op: "net-head", handle }, signal);
14127
14375
  signal.throwIfAborted();
@@ -14153,7 +14401,7 @@ function fetchOp(kernel) {
14153
14401
  } catch (err) {
14154
14402
  settle();
14155
14403
  await close(handle);
14156
- throw signal.aborted ? signal.reason : new TypeError("terminated", { cause: err });
14404
+ throw signal.aborted ? signal.reason : new TypeError("terminated", { cause: cut(err) });
14157
14405
  }
14158
14406
  const bytes = r.ok && r.kind === "bytes" ? r.bytes : new Uint8Array(0);
14159
14407
  if (bytes.length > 0) {
@@ -14215,15 +14463,17 @@ function fetchOp(kernel) {
14215
14463
  throw failed3(new JsCallError("ENOTSUP", `redirect: ${request.redirect}`));
14216
14464
  }
14217
14465
  const url = withoutFragment(new URL(request.url));
14218
- const bytes = await bodyOf(request, known.maxRequestBody, signal);
14466
+ const streamed = streams(known, request, init, url);
14467
+ const bytes = streamed ? void 0 : await bodyOf(request, known.maxRequestBody, signal);
14219
14468
  if (bytes === OVER) {
14220
14469
  return withMeta(plain(413, `request body over ${known.maxRequestBody} bytes`), url, false);
14221
14470
  }
14222
14471
  let hop = {
14223
14472
  url,
14224
14473
  method: request.method,
14225
- headers: [...request.headers],
14226
- body: bytes
14474
+ headers: inOrder(request.headers, init?.headers),
14475
+ body: bytes,
14476
+ ...streamed && request.body ? { stream: request.body } : {}
14227
14477
  };
14228
14478
  for (let hops = 0; ; hops++) {
14229
14479
  const head = await send(hop, signal);
@@ -14234,8 +14484,7 @@ function fetchOp(kernel) {
14234
14484
  return respond(head, hop.method, redirected, known.encodedBodies, signal);
14235
14485
  }
14236
14486
  await close(head.handle);
14237
- if (request.redirect === "error")
14238
- throw failed3(new JsCallError("EREDIRECT", "unexpected redirect"));
14487
+ if (request.redirect === "error") throw failed3(new Error("unexpected redirect"));
14239
14488
  if (hops >= MAX_REDIRECTS) throw failed3(new JsCallError("ELOOP", hop.url));
14240
14489
  [hop, known] = await redirect(hop, head.status, location, known);
14241
14490
  }
@@ -15130,6 +15379,12 @@ var init_js_tty = __esm({
15130
15379
  function failed4(err) {
15131
15380
  return new TypeError("websocket failed", { cause: err });
15132
15381
  }
15382
+ function openError(err) {
15383
+ if (!(err instanceof JsCallError) || err.detail === void 0) return err;
15384
+ const prefix = `${err.code}: `;
15385
+ const message2 = err.detail.startsWith(prefix) ? err.detail.slice(prefix.length) : err.detail;
15386
+ return Object.assign(new Error(message2), { code: err.code });
15387
+ }
15133
15388
  function socketUrl(input) {
15134
15389
  const url = new URL(input);
15135
15390
  if (url.protocol === "http:") url.protocol = "ws:";
@@ -15171,7 +15426,7 @@ function websocketOp(kernel) {
15171
15426
  protocol = (r.ok && r.kind === "json" ? r.json : {}).protocol;
15172
15427
  } catch (err) {
15173
15428
  await free();
15174
- throw signal.aborted ? signal.reason : failed4(err);
15429
+ throw signal.aborted ? signal.reason : failed4(openError(err));
15175
15430
  }
15176
15431
  let settle;
15177
15432
  let lose;