@ai-ecoverse/slicc-kernel 1.114.0 → 1.116.0

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/node.js CHANGED
@@ -473,8 +473,8 @@ async function access(fs, cred, path, want, options = {}) {
473
473
  if (await present(fs, walked.path, false)) return { ...walked, denied: walked.path };
474
474
  return { ...walked, missing: true };
475
475
  }
476
- function refused(path, errno2 = "EACCES") {
477
- return fsError(errno2, path);
476
+ function refused(path, errno3 = "EACCES") {
477
+ return fsError(errno3, path);
478
478
  }
479
479
 
480
480
  // src/fs/dac.ts
@@ -534,9 +534,9 @@ var Created = class {
534
534
  function linked(g, options) {
535
535
  return g.links === void 0 ? options : { ...options, links: g.links };
536
536
  }
537
- function deny(g, op, path, errno2 = "EACCES") {
537
+ function deny(g, op, path, errno3 = "EACCES") {
538
538
  const tag = g.tag === void 0 ? {} : { tag: g.tag };
539
- g.dac.denied({ pid: g.pid, uid: g.cred.euid, op, path, errno: errno2, ...tag });
539
+ g.dac.denied({ pid: g.pid, uid: g.cred.euid, op, path, errno: errno3, ...tag });
540
540
  }
541
541
  var TTY_MODE = 400;
542
542
  function ttyOpenable(g, tty) {
@@ -1249,7 +1249,7 @@ var WASI_SIGNAL_TO_POSIX = Object.fromEntries(
1249
1249
 
1250
1250
  // src/process/wasi-errno.ts
1251
1251
  var WASI_ERRNO = {
1252
- ...Object.fromEntries(Object.entries(E).map(([name2, errno2]) => [`E${name2}`, errno2])),
1252
+ ...Object.fromEntries(Object.entries(E).map(([name2, errno3]) => [`E${name2}`, errno3])),
1253
1253
  EWOULDBLOCK: E.AGAIN,
1254
1254
  ENOTSUP: 138,
1255
1255
  EOPNOTSUPP: 138,
@@ -1489,7 +1489,7 @@ function dialError(e, timedOut, closed) {
1489
1489
  if (timedOut) return new KernelError("ETIMEDOUT");
1490
1490
  if (closed) return new KernelError("ECONNABORTED");
1491
1491
  const code = e?.code;
1492
- const known = DIAL_ERRORS.find((errno2) => errno2 === code);
1492
+ const known = DIAL_ERRORS.find((errno3) => errno3 === code);
1493
1493
  return new KernelError(known ?? "EHOSTUNREACH");
1494
1494
  }
1495
1495
  function isLoopback(host) {
@@ -1865,6 +1865,14 @@ var LoopbackNet = class {
1865
1865
  facades = /* @__PURE__ */ new Map();
1866
1866
  nextEphemeral = EPHEMERAL_FIRST;
1867
1867
  route;
1868
+ origins;
1869
+ useOrigins(serve) {
1870
+ this.origins = serve;
1871
+ }
1872
+ serveOrigin(conn, origin) {
1873
+ if (!this.origins) throw new KernelError("ENETUNREACH");
1874
+ void this.origins(conn, origin).catch(() => conn.close());
1875
+ }
1868
1876
  useUplink(route) {
1869
1877
  this.route = route;
1870
1878
  }
@@ -4102,6 +4110,7 @@ var S_IFDIR = 16384;
4102
4110
  var S_IFREG = 32768;
4103
4111
  var S_IFLNK = 40960;
4104
4112
  var S_IFSOCK = 49152;
4113
+ var S_IFIFO = 4096;
4105
4114
  var PERM_MASK = 4095;
4106
4115
  var S_ISGID3 = 1024;
4107
4116
  var READ_ATTEMPTS = 3;
@@ -4381,7 +4390,10 @@ var OpfsFs = class {
4381
4390
  }
4382
4391
  async stampNew(path, owner, directory) {
4383
4392
  const owned4 = await this.newFields(path, owner, directory);
4384
- const fields = owner?.socket && !directory ? { ...owned4, socket: true } : owned4;
4393
+ if (owner?.socket && owner.fifo) throw new Error("a new node is a socket or a FIFO, not both");
4394
+ const kind = directory ? void 0 : owner?.socket ? "socket" : owner?.fifo ? "fifo" : void 0;
4395
+ const unique = kind === "fifo" ? { ino: inodeOf(`${path}\0${crypto.randomUUID()}`) } : {};
4396
+ const fields = kind ? { ...owned4, ...unique, [kind]: true } : owned4;
4385
4397
  if (fields) await this.meta.update(path, (entry) => ({ ...entry, path, ...fields }));
4386
4398
  }
4387
4399
  guarded = [];
@@ -4623,7 +4635,7 @@ var OpfsFs = class {
4623
4635
  }
4624
4636
  mode(path, directory, meta) {
4625
4637
  const fallback = directory || EXECUTABLE.test(path) ? 493 : 420;
4626
- const type = directory ? S_IFDIR : meta?.socket ? S_IFSOCK : S_IFREG;
4638
+ const type = directory ? S_IFDIR : meta?.socket ? S_IFSOCK : meta?.fifo ? S_IFIFO : S_IFREG;
4627
4639
  return type | (meta?.mode ?? fallback);
4628
4640
  }
4629
4641
  id = crypto.randomUUID();
@@ -4724,11 +4736,13 @@ var OpfsFs = class {
4724
4736
  const kept = meta?.mtimeMs !== void 0 && meta.mtimeFor === modified ? meta.mtimeMs : modified;
4725
4737
  const mtime = touched ?? kept;
4726
4738
  const socket = !directory && meta?.socket === true;
4739
+ const fifo = !directory && meta?.fifo === true;
4727
4740
  return {
4728
- isFile: !directory && !socket,
4741
+ isFile: !directory && !socket && !fifo,
4729
4742
  isDirectory: directory,
4730
4743
  isSymbolicLink: false,
4731
4744
  ...socket ? { isSocket: true } : {},
4745
+ ...fifo ? { isFifo: true } : {},
4732
4746
  size: file?.size ?? 0,
4733
4747
  mode: this.mode(path, directory, meta),
4734
4748
  mtime: new Date(mtime),
@@ -5644,6 +5658,12 @@ var Incoming = class {
5644
5658
  this.buf = this.buf.subarray(n);
5645
5659
  return out;
5646
5660
  }
5661
+ async firstLine(max, signal) {
5662
+ while (this.buf.length < max && !this.buf.includes(10) && await this.fill(signal)) ;
5663
+ const end = this.buf.indexOf(10);
5664
+ const bytes = this.buf.subarray(0, end >= 0 ? end + 1 : Math.min(max, this.buf.length));
5665
+ return String.fromCharCode(...bytes);
5666
+ }
5647
5667
  async peek(signal) {
5648
5668
  if (this.buf.length === 0) await this.fill(signal);
5649
5669
  return this.buf[0];
@@ -6539,7 +6559,7 @@ function satisfies(version, range2) {
6539
6559
  }
6540
6560
 
6541
6561
  // src/version.ts
6542
- var KERNEL_VERSION = true ? "1.114.0" : "0.0.0-dev";
6562
+ var KERNEL_VERSION = true ? "1.116.0" : "0.0.0-dev";
6543
6563
  var OS_RELEASE = "6.0.0-slicc";
6544
6564
  function procVersion() {
6545
6565
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -7677,6 +7697,9 @@ var TLS_HANDSHAKE = 22;
7677
7697
  var TOKEN2 = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
7678
7698
  var NO_WEBSOCKET2 = "WebSocket not supported by this transport (fetchTransport needs { webSocket: true })";
7679
7699
  var REALM_PROXY_PORT = 3128;
7700
+ var REQUEST_LINE_MAX = 8192;
7701
+ var REQUEST_LINE = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+ \S+ HTTP\/1\.[01]\r?\n$/;
7702
+ var NOT_HTTP = "not HTTP/1.1: TLS through the transport carries only HTTP/1.1 and WebSocket";
7680
7703
  var DEFAULT_LIMITS = {
7681
7704
  maxConnections: 64,
7682
7705
  maxHead: 64 * 1024,
@@ -7965,6 +7988,26 @@ var RealmProxy = class {
7965
7988
  conn.close();
7966
7989
  }
7967
7990
  }
7991
+ async serveOrigin(conn, origin) {
7992
+ if (this.stop.signal.aborted) {
7993
+ conn.close();
7994
+ return;
7995
+ }
7996
+ this.connections.add(conn);
7997
+ const idle = { ms: this.limits.idleMs };
7998
+ const incoming = new Incoming(timedSource(conn, idle, this.stop.signal));
7999
+ try {
8000
+ const line = await incoming.firstLine(REQUEST_LINE_MAX).catch(() => "");
8001
+ if (line !== "" && !REQUEST_LINE.test(line)) {
8002
+ await this.refuse(conn, new HttpError(400, NOT_HTTP));
8003
+ return;
8004
+ }
8005
+ await this.requests({ sink: conn, incoming, origin, socket: conn, idle });
8006
+ } finally {
8007
+ this.connections.delete(conn);
8008
+ conn.close();
8009
+ }
8010
+ }
7968
8011
  async requests(ctx) {
7969
8012
  try {
7970
8013
  for (; ; ) {
@@ -9542,6 +9585,139 @@ var TicketBook = class {
9542
9585
  }
9543
9586
  };
9544
9587
 
9588
+ // src/kernel/fifo.ts
9589
+ function errno(e) {
9590
+ return e instanceof KernelError ? e : new KernelError(e.code ?? "EIO");
9591
+ }
9592
+ var FifoTable = class {
9593
+ fifos = /* @__PURE__ */ new Map();
9594
+ size() {
9595
+ return this.fifos.size;
9596
+ }
9597
+ async open(key, path, access2, nonblock, signal) {
9598
+ const fifo = this.entry(key);
9599
+ if (access2 === "write" && nonblock && fifo.readers === 0) {
9600
+ this.drop(key, fifo);
9601
+ throw new KernelError("ENXIO");
9602
+ }
9603
+ const reads = access2 !== "write";
9604
+ const writes = access2 !== "read";
9605
+ const seen = { readOpens: fifo.readOpens, writeOpens: fifo.writeOpens };
9606
+ if (reads) this.count(fifo, "readers", 1);
9607
+ if (writes) this.count(fifo, "writers", 1);
9608
+ this.notify(fifo);
9609
+ try {
9610
+ if (!nonblock && access2 === "read") {
9611
+ while (fifo.writers === 0 && fifo.writeOpens === seen.writeOpens) {
9612
+ await this.changed(fifo, signal);
9613
+ }
9614
+ }
9615
+ if (!nonblock && access2 === "write") {
9616
+ while (fifo.readers === 0 && fifo.readOpens === seen.readOpens) {
9617
+ await this.changed(fifo, signal);
9618
+ }
9619
+ }
9620
+ } catch (e) {
9621
+ this.release(key, fifo, reads, writes);
9622
+ throw errno(e);
9623
+ }
9624
+ return this.end(key, path, fifo, reads, writes);
9625
+ }
9626
+ entry(key) {
9627
+ let fifo = this.fifos.get(key);
9628
+ if (!fifo) {
9629
+ fifo = {
9630
+ pipe: new KernelPipe(),
9631
+ readers: 0,
9632
+ writers: 0,
9633
+ readOpens: 0,
9634
+ writeOpens: 0,
9635
+ waiters: []
9636
+ };
9637
+ this.fifos.set(key, fifo);
9638
+ }
9639
+ return fifo;
9640
+ }
9641
+ count(fifo, side, by) {
9642
+ fifo[side] += by;
9643
+ if (side === "readers") {
9644
+ if (by > 0) {
9645
+ fifo.readOpens += 1;
9646
+ fifo.pipe.openRead();
9647
+ } else fifo.pipe.closeRead();
9648
+ } else if (by > 0) {
9649
+ fifo.writeOpens += 1;
9650
+ fifo.pipe.openWrite();
9651
+ } else fifo.pipe.closeWrite();
9652
+ }
9653
+ notify(fifo) {
9654
+ const waiters = fifo.waiters;
9655
+ fifo.waiters = [];
9656
+ for (const wake of waiters) wake();
9657
+ }
9658
+ changed(fifo, signal) {
9659
+ if (signal.aborted) return Promise.reject(new KernelError("EINTR"));
9660
+ return new Promise((resolve2, reject) => {
9661
+ const onAbort = () => {
9662
+ fifo.waiters = fifo.waiters.filter((w) => w !== wake);
9663
+ reject(new KernelError("EINTR"));
9664
+ };
9665
+ const wake = () => {
9666
+ signal.removeEventListener("abort", onAbort);
9667
+ resolve2();
9668
+ };
9669
+ fifo.waiters.push(wake);
9670
+ signal.addEventListener("abort", onAbort, { once: true });
9671
+ });
9672
+ }
9673
+ release(key, fifo, reads, writes) {
9674
+ if (reads) this.count(fifo, "readers", -1);
9675
+ if (writes) this.count(fifo, "writers", -1);
9676
+ this.notify(fifo);
9677
+ this.drop(key, fifo);
9678
+ }
9679
+ drop(key, fifo) {
9680
+ const idle = fifo.readers === 0 && fifo.writers === 0 && fifo.waiters.length === 0;
9681
+ if (idle && this.fifos.get(key) === fifo) this.fifos.delete(key);
9682
+ }
9683
+ end(key, path, fifo, reads, writes) {
9684
+ const { pipe } = fifo;
9685
+ let open = true;
9686
+ return new OpenFile({
9687
+ fifo: path,
9688
+ ...reads ? {
9689
+ read: async (max, signal) => {
9690
+ try {
9691
+ return await pipe.read(max, signal);
9692
+ } catch (e) {
9693
+ throw errno(e);
9694
+ }
9695
+ }
9696
+ } : {},
9697
+ ...writes ? {
9698
+ write: async (bytes, signal) => {
9699
+ try {
9700
+ return await pipe.write(bytes, signal);
9701
+ } catch (e) {
9702
+ throw errno(e);
9703
+ }
9704
+ }
9705
+ } : {},
9706
+ close: () => {
9707
+ if (!open) return;
9708
+ open = false;
9709
+ this.release(key, fifo, reads, writes);
9710
+ },
9711
+ poll: () => ({
9712
+ readable: reads && pipe.readReady,
9713
+ writable: writes && pipe.writeReady,
9714
+ hangup: reads ? pipe.writersGone : pipe.readersGone
9715
+ }),
9716
+ changed: (signal) => pipe.changed(signal)
9717
+ });
9718
+ }
9719
+ };
9720
+
9545
9721
  // src/mount/protocol.ts
9546
9722
  var DRIVER_PROTOCOL = [1, 2];
9547
9723
  function driverVersionError(theirs) {
@@ -10402,6 +10578,7 @@ var MountFs = class _MountFs {
10402
10578
  }
10403
10579
  const { mount, rel: rel2 } = found;
10404
10580
  this.writable(mount, real);
10581
+ if (owner?.fifo) throw errnoError("EPERM", `${real}: this mount has no FIFOs`);
10405
10582
  const bytes = typeof content === "string" ? new TextEncoder().encode(content) : content;
10406
10583
  if (mount.maxFile > 0 && bytes.length > mount.maxFile) {
10407
10584
  throw errnoError(
@@ -11007,6 +11184,7 @@ var SYNC_FS_OPS = [
11007
11184
  "statfs",
11008
11185
  "hold",
11009
11186
  "create",
11187
+ "mkfifo",
11010
11188
  "kept",
11011
11189
  "pread",
11012
11190
  "pwrite",
@@ -11039,6 +11217,7 @@ function statJson(s) {
11039
11217
  isFile: s.isFile,
11040
11218
  isSymbolicLink: s.isSymbolicLink,
11041
11219
  ...s.isSocket ? { isSocket: true } : {},
11220
+ ...s.isFifo ? { isFifo: true } : {},
11042
11221
  size: s.size,
11043
11222
  mode: s.mode,
11044
11223
  mtimeMs: s.mtime.getTime(),
@@ -11188,6 +11367,12 @@ async function run(entry, path, req) {
11188
11367
  case "symlink":
11189
11368
  await fs.symlink(req.arg2 ?? "", path, ownerFor2(entry));
11190
11369
  return done;
11370
+ case "mkfifo": {
11371
+ const owner = ownerFor2(entry, req.mode ?? 438) ?? { uid: 0, gid: 0 };
11372
+ await createExclusive(fs, path, { ...owner, fifo: true });
11373
+ entry.fresh?.(path);
11374
+ return done;
11375
+ }
11191
11376
  case "create":
11192
11377
  await createExclusive(fs, path, ownerFor2(entry, req.mode ?? 438));
11193
11378
  if (req.opening) entry.created?.add(path);
@@ -11266,9 +11451,10 @@ async function guard(g, path, req, cwd) {
11266
11451
  return { path: await walkSafe(g, path, false) };
11267
11452
  }
11268
11453
  case "create":
11454
+ case "mkfifo":
11269
11455
  case "symlink":
11270
11456
  await inParent(g, op, path);
11271
- return { path: await walkSafe(g, path, op === "create") };
11457
+ return { path: await walkSafe(g, path, op !== "symlink") };
11272
11458
  case "unlink":
11273
11459
  case "rmdir": {
11274
11460
  await inParent(g, op, path, true);
@@ -11356,6 +11542,7 @@ async function accessOp(entry, path, req) {
11356
11542
  var CHANGING = /* @__PURE__ */ new Set([
11357
11543
  "mkdir",
11358
11544
  "create",
11545
+ "mkfifo",
11359
11546
  "symlink",
11360
11547
  "unlink",
11361
11548
  "rmdir",
@@ -11550,7 +11737,13 @@ async function guardAndResolve(entry, path, req) {
11550
11737
  };
11551
11738
  }
11552
11739
  var REMOVALS = /* @__PURE__ */ new Set(["unlink", "rmdir", "rm"]);
11553
- var CREATIONS = /* @__PURE__ */ new Set(["write", "mkdir", "symlink", "create"]);
11740
+ var CREATIONS = /* @__PURE__ */ new Set([
11741
+ "write",
11742
+ "mkdir",
11743
+ "symlink",
11744
+ "create",
11745
+ "mkfifo"
11746
+ ]);
11554
11747
  var NAMING = /* @__PURE__ */ new Set(["link", "rename"]);
11555
11748
  async function newDevName(entry, path, req) {
11556
11749
  const named = NAMING.has(req.op);
@@ -13297,16 +13490,16 @@ var TOKEN3 = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
13297
13490
  var SAFE_VALUE = /^[^\r\n\0]*$/;
13298
13491
  var CLOSE_WAIT_MS3 = 5e3;
13299
13492
  var MAX_UNREAD = 16 * 1024 * 1024;
13300
- function errno(code, message3) {
13493
+ function errno2(code, message3) {
13301
13494
  return Object.assign(new Error(`${code}: ${message3}`), { code });
13302
13495
  }
13303
13496
  function requestHead(method, url, headers, extra, first = []) {
13304
- if (!TOKEN3.test(method)) throw errno("EINVAL", `method ${method}`);
13497
+ if (!TOKEN3.test(method)) throw errno2("EINVAL", `method ${method}`);
13305
13498
  const lines2 = [`${method} ${url.pathname}${url.search} HTTP/1.1`, `host: ${url.host}`];
13306
13499
  for (const [name2, value2] of first) lines2.push(`${name2}: ${value2}`);
13307
13500
  for (const [name2, value2] of headers) {
13308
13501
  if (OWN_HEADERS.has(name2.toLowerCase())) continue;
13309
- if (!TOKEN3.test(name2) || !SAFE_VALUE.test(value2)) throw errno("EINVAL", `header ${name2}`);
13502
+ if (!TOKEN3.test(name2) || !SAFE_VALUE.test(value2)) throw errno2("EINVAL", `header ${name2}`);
13310
13503
  lines2.push(`${name2}: ${value2}`);
13311
13504
  }
13312
13505
  for (const [name2, value2] of extra) lines2.push(`${name2}: ${value2}`);
@@ -13317,7 +13510,7 @@ function requestHead(method, url, headers, extra, first = []) {
13317
13510
  function parseHead(bytes) {
13318
13511
  const [statusLine = "", ...lines2] = latin1(bytes).split(/\r?\n/);
13319
13512
  const match = /^HTTP\/1\.[01] (\d{3})(?: (.*))?$/.exec(statusLine);
13320
- if (!match) throw errno("EPROTO", `not an HTTP/1.x response: ${statusLine.slice(0, 80)}`);
13513
+ if (!match) throw errno2("EPROTO", `not an HTTP/1.x response: ${statusLine.slice(0, 80)}`);
13321
13514
  const headers = [];
13322
13515
  for (const line of lines2) {
13323
13516
  const colon = line.indexOf(":");
@@ -13332,9 +13525,9 @@ async function readHead(incoming, signal) {
13332
13525
  raw = await incoming.head(MAX_HEAD2, signal);
13333
13526
  } catch (err) {
13334
13527
  if (err instanceof KernelError) throw err;
13335
- throw errno("EPROTO", "the response head is malformed or too large");
13528
+ throw errno2("EPROTO", "the response head is malformed or too large");
13336
13529
  }
13337
- if (!raw) throw errno("ECONNRESET", "the connection closed before a response");
13530
+ if (!raw) throw errno2("ECONNRESET", "the connection closed before a response");
13338
13531
  const head = parseHead(raw);
13339
13532
  if (head.status < 100 || head.status >= 200 || head.status === 101) return head;
13340
13533
  }
@@ -13343,20 +13536,20 @@ async function* chunked(incoming, signal) {
13343
13536
  for (; ; ) {
13344
13537
  const line = await incoming.line(4096, signal);
13345
13538
  const size = /^([0-9A-Fa-f]{1,12})[ \t]*(;.*)?$/.exec(line);
13346
- if (!size) throw errno("EPROTO", "a malformed chunk size");
13539
+ if (!size) throw errno2("EPROTO", "a malformed chunk size");
13347
13540
  const n = Number.parseInt(size[1], 16);
13348
13541
  if (n === 0) {
13349
13542
  while (await incoming.line(MAX_HEAD2, signal) !== "") ;
13350
13543
  return;
13351
13544
  }
13352
13545
  yield await incoming.exactly(n, signal);
13353
- if (await incoming.line(2, signal) !== "") throw errno("EPROTO", "a malformed chunk");
13546
+ if (await incoming.line(2, signal) !== "") throw errno2("EPROTO", "a malformed chunk");
13354
13547
  }
13355
13548
  }
13356
13549
  async function* counted(incoming, length2, signal) {
13357
13550
  for (let left = length2; left > 0; ) {
13358
13551
  const data = await incoming.some(Math.min(left, 64 * 1024), signal);
13359
- if (data.length === 0) throw errno("EPROTO", "the body ended early");
13552
+ if (data.length === 0) throw errno2("EPROTO", "the body ended early");
13360
13553
  left -= data.length;
13361
13554
  yield data;
13362
13555
  }
@@ -13377,7 +13570,7 @@ function bodyOf(incoming, head, method, signal) {
13377
13570
  if (lengths.length === 0) return untilClose(incoming, signal);
13378
13571
  const length2 = lengths[0]?.trim() ?? "";
13379
13572
  if (!/^\d{1,15}$/.test(length2) || lengths.some((l) => l.trim() !== length2)) {
13380
- throw errno("EPROTO", `a malformed Content-Length: ${lengths.join(", ")}`);
13573
+ throw errno2("EPROTO", `a malformed Content-Length: ${lengths.join(", ")}`);
13381
13574
  }
13382
13575
  return counted(incoming, Number(length2), signal);
13383
13576
  }
@@ -13395,7 +13588,7 @@ var KernelLoopback = class {
13395
13588
  }
13396
13589
  async connect(url, port, signal) {
13397
13590
  if (url.protocol === "https:" || url.protocol === "wss:") {
13398
- throw errno("ENOTSUP", `TLS to the kernel's loopback is not supported: ${url.origin}`);
13591
+ throw errno2("ENOTSUP", `TLS to the kernel's loopback is not supported: ${url.origin}`);
13399
13592
  }
13400
13593
  signal.throwIfAborted();
13401
13594
  const socket = this.net.socket("inet");
@@ -13410,7 +13603,7 @@ var KernelLoopback = class {
13410
13603
  } catch (err) {
13411
13604
  socket.close();
13412
13605
  const refused2 = err instanceof KernelError && err.code === "ECONNREFUSED";
13413
- throw refused2 ? errno("ECONNREFUSED", `nothing listens on the kernel's port ${port}`) : err;
13606
+ throw refused2 ? errno2("ECONNREFUSED", `nothing listens on the kernel's port ${port}`) : err;
13414
13607
  }
13415
13608
  signal.addEventListener("abort", () => socket.close(), { once: true });
13416
13609
  return socket;
@@ -13456,7 +13649,7 @@ var KernelLoopback = class {
13456
13649
  const incoming = new Incoming(socket);
13457
13650
  const head = await readHead(incoming, req.signal);
13458
13651
  if (head.status !== 101) {
13459
- throw errno(
13652
+ throw errno2(
13460
13653
  "EPROTO",
13461
13654
  `the server answered the upgrade with ${head.status}${head.statusText ? ` ${head.statusText}` : ""}`
13462
13655
  );
@@ -13464,10 +13657,10 @@ var KernelLoopback = class {
13464
13657
  const upgraded = fieldTokens(head.headers, "upgrade").includes("websocket") && fieldTokens(head.headers, "connection").includes("upgrade");
13465
13658
  const accept2 = fieldValues(head.headers, "sec-websocket-accept")[0];
13466
13659
  if (!upgraded || accept2 !== await acceptFor(key)) {
13467
- throw errno("EPROTO", "the server did not accept the WebSocket key");
13660
+ throw errno2("EPROTO", "the server did not accept the WebSocket key");
13468
13661
  }
13469
13662
  if (fieldValues(head.headers, "sec-websocket-extensions").length > 0) {
13470
- throw errno("EPROTO", "the server offered an unsolicited extension");
13663
+ throw errno2("EPROTO", "the server offered an unsolicited extension");
13471
13664
  }
13472
13665
  const protocol = fieldValues(head.headers, "sec-websocket-protocol")[0] ?? "";
13473
13666
  return new LoopbackWebSocket(socket, incoming, protocol);
@@ -13485,7 +13678,7 @@ async function* closing(chunks2, socket) {
13485
13678
  yield* chunks2;
13486
13679
  } catch (err) {
13487
13680
  if (typeof err?.code === "string") throw err;
13488
- throw errno("EPROTO", err instanceof Error ? err.message : String(err));
13681
+ throw errno2("EPROTO", err instanceof Error ? err.message : String(err));
13489
13682
  } finally {
13490
13683
  socket.close();
13491
13684
  }
@@ -13614,7 +13807,7 @@ var LoopbackWebSocket = class {
13614
13807
  this.write(clientFrame(OP_CLOSE, payload));
13615
13808
  }
13616
13809
  send(data) {
13617
- if (this.sentClose) throw errno("EPIPE", "the websocket is closing");
13810
+ if (this.sentClose) throw errno2("EPIPE", "the websocket is closing");
13618
13811
  const text = typeof data === "string";
13619
13812
  const payload = text ? new TextEncoder().encode(data) : data;
13620
13813
  this.write(clientFrame(text ? OP_TEXT : OP_BINARY, payload));
@@ -14265,7 +14458,7 @@ async function writeCaFile(fs, ca, locks = globalThis.navigator?.locks) {
14265
14458
  function enableNetwork(net, options) {
14266
14459
  let proxy;
14267
14460
  const transport = options.transport ?? missingTransport();
14268
- net.activate({ family: "inet", host: "127.0.0.1", port: REALM_PROXY_PORT }, () => {
14461
+ const start2 = () => {
14269
14462
  const tls2 = new TlsTerminator({
14270
14463
  ca: options.ca,
14271
14464
  engine: options.engine,
@@ -14284,6 +14477,11 @@ function enableNetwork(net, options) {
14284
14477
  if (proxy === started) proxy = void 0;
14285
14478
  await tls2.close();
14286
14479
  });
14480
+ };
14481
+ net.activate({ family: "inet", host: "127.0.0.1", port: REALM_PROXY_PORT }, start2);
14482
+ net.useOrigins((conn, origin) => {
14483
+ if (!proxy) start2();
14484
+ return proxy.serveOrigin(conn, origin);
14287
14485
  });
14288
14486
  return () => proxy;
14289
14487
  }
@@ -14306,8 +14504,8 @@ function errnoOf(e) {
14306
14504
  const code = e?.code;
14307
14505
  return typeof code === "string" && ERRNO.test(code) ? code : "ECONNREFUSED";
14308
14506
  }
14309
- function fail(errno2, text) {
14310
- return { ok: false, errno: errno2, message: text };
14507
+ function fail(errno3, text) {
14508
+ return { ok: false, errno: errno3, message: text };
14311
14509
  }
14312
14510
  var WsHandles = class {
14313
14511
  transport;
@@ -14581,8 +14779,8 @@ var HttpHandles = class {
14581
14779
  const status = e.status;
14582
14780
  if (text === NO_TRANSPORT || typeof status !== "number" || status === 502) {
14583
14781
  const code = codeOf2(e);
14584
- const errno2 = text === NO_TRANSPORT ? "ENETUNREACH" : code !== "EIO" ? code : "ECONNREFUSED";
14585
- return { ok: false, errno: errno2, message: text };
14782
+ const errno3 = text === NO_TRANSPORT ? "ENETUNREACH" : code !== "EIO" ? code : "ECONNREFUSED";
14783
+ return { ok: false, errno: errno3, message: text };
14586
14784
  }
14587
14785
  entry.body = once(new TextEncoder().encode(text))[Symbol.asyncIterator]();
14588
14786
  return this.headOf(handle, req.url, {
@@ -15677,7 +15875,7 @@ var UNREACHABLE = ["EACCES", "ENETUNREACH", "EHOSTUNREACH"];
15677
15875
  function sendError(e) {
15678
15876
  if (e instanceof KernelError) return e;
15679
15877
  const code = e?.code;
15680
- return new KernelError(SEND_ERRORS.find((errno2) => errno2 === code) ?? "EHOSTUNREACH");
15878
+ return new KernelError(SEND_ERRORS.find((errno3) => errno3 === code) ?? "EHOSTUNREACH");
15681
15879
  }
15682
15880
  function sameAddr(a, b) {
15683
15881
  return a.port === b.port && canonicalHost(a.host) === canonicalHost(b.host);
@@ -15806,7 +16004,7 @@ var KernelDgram = class {
15806
16004
  }
15807
16005
  unreachable(error, from) {
15808
16006
  if (!this.peer || !sameAddr(this.peer, from)) return;
15809
- this.pending = UNREACHABLE.find((errno2) => errno2 === error) ?? "EHOSTUNREACH";
16007
+ this.pending = UNREACHABLE.find((errno3) => errno3 === error) ?? "EHOSTUNREACH";
15810
16008
  this.changes.wake();
15811
16009
  }
15812
16010
  deliver(datagram2) {
@@ -16089,7 +16287,8 @@ var SOCKET_OPS = [
16089
16287
  "sock-setopt",
16090
16288
  "sock-resolve",
16091
16289
  "sock-sendto",
16092
- "sock-recvfrom"
16290
+ "sock-recvfrom",
16291
+ "sock-tls"
16093
16292
  ];
16094
16293
  function socketAt(fds, fd) {
16095
16294
  const file = anySocketAt(fds, fd);
@@ -16161,6 +16360,8 @@ async function socketSyscall(req, proc) {
16161
16360
  if (addresses.length === 0) throw new KernelError("ENOENT");
16162
16361
  return ok3(addresses);
16163
16362
  }
16363
+ case "sock-tls":
16364
+ return ok3(tlsOverTransport(req, proc));
16164
16365
  default:
16165
16366
  return datagram(req, proc);
16166
16367
  }
@@ -16264,6 +16465,48 @@ async function accept(proc, fd, nonblock) {
16264
16465
  const socket = await listener.accept(waits ? proc.blocking() : void 0, nonblock);
16265
16466
  return { fd: proc.fds.install(new OpenFile(socket), 3), peer: socket.peer };
16266
16467
  }
16468
+ var NOT_HTTP_PORTS = /* @__PURE__ */ new Set([
16469
+ 465,
16470
+ 563,
16471
+ 585,
16472
+ 636,
16473
+ 853,
16474
+ 989,
16475
+ 990,
16476
+ 992,
16477
+ 993,
16478
+ 994,
16479
+ 995,
16480
+ 5061,
16481
+ 5671,
16482
+ 6697,
16483
+ 8883
16484
+ ]);
16485
+ var HOST_NAME = /^[A-Za-z0-9.-]+$|^\[?[0-9A-Fa-f:.]+\]?$/;
16486
+ function tlsOverTransport(req, proc) {
16487
+ if (req.ca) throw new KernelError("ENOTSUP");
16488
+ if (req.alpn && req.alpn.length > 0 && !req.alpn.includes("http/1.1")) {
16489
+ throw new KernelError("EPROTONOSUPPORT");
16490
+ }
16491
+ if (!Number.isInteger(req.port) || req.port < 1 || req.port > 65535)
16492
+ throw new KernelError("EINVAL");
16493
+ if (NOT_HTTP_PORTS.has(req.port)) throw new KernelError("EPROTONOSUPPORT");
16494
+ const servername = req.servername || req.host;
16495
+ if (!HOST_NAME.test(servername)) throw new KernelError("EINVAL");
16496
+ if (isLoopbackHost(servername) || isLoopbackHost(req.host)) throw new KernelError("ENOTSUP");
16497
+ const host = servername.includes(":") && !servername.startsWith("[") ? `[${servername}]` : servername;
16498
+ const origin = req.port === 443 ? `https://${host}` : `https://${host}:${req.port}`;
16499
+ const [mine, theirs] = KernelSocket.pair(proc.net, "inet", proc.cred?.());
16500
+ mine.peer = { family: "inet", host: req.host, port: req.port };
16501
+ try {
16502
+ proc.net.serveOrigin(theirs, origin);
16503
+ } catch (err) {
16504
+ mine.close();
16505
+ theirs.close();
16506
+ throw err;
16507
+ }
16508
+ return { fd: proc.fds.install(new OpenFile(mine), 3), alpnProtocol: "http/1.1", servername };
16509
+ }
16267
16510
 
16268
16511
  // src/kernel/vfs-file.ts
16269
16512
  var O_ACCMODE = 3;
@@ -17138,6 +17381,7 @@ function isWasmSyscall(req) {
17138
17381
  return typeof op === "string" && SYSCALL_OPS.has(op);
17139
17382
  }
17140
17383
  var MAX_READ = 1024 * 1024;
17384
+ var O_NONBLOCK = 2048;
17141
17385
  var WRITE_ACCESS = 3;
17142
17386
  var KEYBOARD = /* @__PURE__ */ new Set([SIG.INT, SIG.QUIT, SIG.TSTP]);
17143
17387
  var DEFAULT_UMASK2 = 18;
@@ -17635,7 +17879,7 @@ var WasmProcess = class {
17635
17879
  this.options.hasPending?.() ? AbortSignal.abort() : this.cancelSignal(cancelled)
17636
17880
  );
17637
17881
  }
17638
- async openVfs(req) {
17882
+ async openVfs(req, cancelled) {
17639
17883
  if (inProc(req.path)) return this.openProc(req, req.path);
17640
17884
  const device = req.orphan ? void 0 : deviceAt(req.path);
17641
17885
  if (device) return this.openDevice(req, device);
@@ -17646,6 +17890,10 @@ var WasmProcess = class {
17646
17890
  await refuseReadonly(this.options.fs, req.path, req.flags, req);
17647
17891
  if (this.writesAt(req)) await this.options.fs.mayChange?.(req.path, !req.exclusive);
17648
17892
  await this.mayOpen(req);
17893
+ if (req.fifo && !req.exclusive) {
17894
+ const opened2 = await this.openFifo(req, cancelled);
17895
+ if (opened2 !== void 0) return opened2;
17896
+ }
17649
17897
  const marked = await this.markedPath(req);
17650
17898
  await this.sourceOpen(marked === void 0 ? req : { ...req, path: marked });
17651
17899
  const fs = marked === void 0 ? this.options.fs : this.options.noLinks;
@@ -17687,6 +17935,19 @@ var WasmProcess = class {
17687
17935
  }
17688
17936
  return fd;
17689
17937
  }
17938
+ async openFifo(req, cancelled) {
17939
+ const fifos = this.options.fifos;
17940
+ const path = await this.nodes.targetKey(req.path);
17941
+ const st = await this.heldFs().stat(path);
17942
+ if (!st.isFifo) return void 0;
17943
+ if (!fifos) throw new KernelError("ENXIO");
17944
+ const access2 = openAccess(req.flags);
17945
+ const nonblock = (req.flags & O_NONBLOCK) !== 0;
17946
+ const blocks = !nonblock && access2 !== "both";
17947
+ const signal = blocks ? this.blockingSignal(cancelled) : cancelled;
17948
+ const end = await fifos.open(`${st.dev ?? 0}:${st.ino}`, path, access2, nonblock, signal);
17949
+ return this.fds.install(end, 3);
17950
+ }
17690
17951
  openDevice(req, device) {
17691
17952
  if (req.exclusive) throw Object.assign(new Error(req.path), { code: "EEXIST" });
17692
17953
  const access2 = req.flags & WRITE_ACCESS;
@@ -17886,7 +18147,7 @@ var WasmProcess = class {
17886
18147
  case "fd-poll":
17887
18148
  return { ok: true, kind: "json", json: pollFile(this.fds.get(req.fd).file) };
17888
18149
  case "fd-open-vfs":
17889
- return { ok: true, kind: "json", json: await this.openVfs(req) };
18150
+ return { ok: true, kind: "json", json: await this.openVfs(req, cancelled) };
17890
18151
  case "fd-info":
17891
18152
  return { ok: true, kind: "json", json: this.fdInfo(req.fd) };
17892
18153
  case "fd-list":
@@ -18546,7 +18807,8 @@ function inheritedFds(fds) {
18546
18807
  ...kind === "device" && meta && "device" in meta ? { device: meta } : {},
18547
18808
  ...flags2 !== void 0 ? { flags: flags2 } : {},
18548
18809
  ...fds.closesOnExec(fd) ? { cloexec: true } : {},
18549
- ...kind === "stream" ? { desc: descId(open) } : {}
18810
+ ...kind === "stream" ? { desc: descId(open) } : {},
18811
+ ...open.file.fifo ? { fifo: open.file.fifo } : {}
18550
18812
  };
18551
18813
  });
18552
18814
  }
@@ -18752,6 +19014,7 @@ function processOptions(opts, header4, hooks, created3) {
18752
19014
  net: opts.net,
18753
19015
  http: opts.http,
18754
19016
  locks: opts.locks,
19017
+ fifos: opts.fifos,
18755
19018
  ...opts.sems ? { sems: opts.sems } : {},
18756
19019
  onReap: opts.onReap,
18757
19020
  resolver: opts.resolver,
@@ -20690,9 +20953,9 @@ var HostfsClient = class {
20690
20953
  throw fsError2("ESTALE", "the folder was granted again, so its open files are gone");
20691
20954
  return this.send(path, init, false, true);
20692
20955
  }
20693
- const errno2 = response.headers.get("X-Hostfs-Errno") ?? "EIO";
20956
+ const errno3 = response.headers.get("X-Hostfs-Errno") ?? "EIO";
20694
20957
  const body = await response.json().catch(() => ({}));
20695
- throw fsError2(errno2, typeof body.message === "string" ? body.message : errno2);
20958
+ throw fsError2(errno3, typeof body.message === "string" ? body.message : errno3);
20696
20959
  }
20697
20960
  async call(op, body = {}, handle = false) {
20698
20961
  const response = await this.send(
@@ -21849,8 +22112,8 @@ var RULE = new RegExp(
21849
22112
  var TERM = /^[A-Za-z0-9._+-]+$/;
21850
22113
  var PLAIN = /^[A-Za-z0-9_@%+=:,./-]+$/;
21851
22114
  var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
21852
- function failed2(errno2, error) {
21853
- return { error, errno: errno2 };
22115
+ function failed2(errno3, error) {
22116
+ return { error, errno: errno3 };
21854
22117
  }
21855
22118
  function unescaped(double) {
21856
22119
  return double.replace(/\\(["\\$`])/g, "$1");
@@ -22507,6 +22770,7 @@ var Launcher = class {
22507
22770
  sudoer;
22508
22771
  jobs = new JobTable();
22509
22772
  locks = new LockTable();
22773
+ fifos = new FifoTable();
22510
22774
  sems = new SemTable();
22511
22775
  settling = new SettlingChildren((pid) => this.jobs.pgidOf(pid));
22512
22776
  ptys = new PtyTable(
@@ -23504,6 +23768,7 @@ var Launcher = class {
23504
23768
  net: this.net,
23505
23769
  http: new HttpHandles(this.transport, pid, this.loopbackFor(pid)),
23506
23770
  locks: this.locks,
23771
+ fifos: this.fifos,
23507
23772
  sems: this.sems,
23508
23773
  resolver: this.resolver,
23509
23774
  onReap: (child) => this.reaped(child, pid),