@ai-ecoverse/slicc-kernel 1.103.4 → 1.106.2

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 (37) hide show
  1. package/README.md +56 -15
  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 +783 -289
  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 +447 -224
  12. package/dist/node-process-worker.js.map +4 -4
  13. package/dist/node.js +831 -309
  14. package/dist/node.js.map +4 -4
  15. package/dist/process-worker.js +384 -161
  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/process-signals.d.ts +3 -0
  30. package/dist/types/process/wasi/wasi-cred.d.ts +11 -0
  31. package/dist/types/process/wasi/wasi-files.d.ts +1 -0
  32. package/dist/types/process/wasi/wasi-host.d.ts +9 -0
  33. package/dist/types/process/wasi/wasi-sigmask.d.ts +7 -1
  34. package/dist/types/process/wasi/wasix-epoll.d.ts +3 -0
  35. package/dist/types/refused-command.d.ts +4 -0
  36. package/dist/types/transport.d.ts +1 -0
  37. package/package.json +12 -12
package/dist/node.js CHANGED
@@ -323,11 +323,11 @@ async function realDir(fs, dir, budget = { hops: 0 }) {
323
323
  at = parentOf(at);
324
324
  continue;
325
325
  }
326
- const next2 = at === "/" ? `/${part}` : `${at}/${part}`;
327
- const link2 = await linkOf(fs, next2);
326
+ const next3 = at === "/" ? `/${part}` : `${at}/${part}`;
327
+ const link2 = await linkOf(fs, next3);
328
328
  if (link2 === void 0) {
329
- if (queue.find((p) => p !== ".") === "..") await mustBeDir(fs, next2);
330
- at = next2;
329
+ if (queue.find((p) => p !== ".") === "..") await mustBeDir(fs, next3);
330
+ at = next3;
331
331
  continue;
332
332
  }
333
333
  if (budget.hops >= MAX_LINKS) throw fsError("ELOOP", dir);
@@ -430,18 +430,18 @@ async function walk(fs, cred, path, follow2, links) {
430
430
  at = parentOf(at);
431
431
  continue;
432
432
  }
433
- const next2 = joinName(at, part);
434
- const perm = await perms.at(next2);
433
+ const next3 = joinName(at, part);
434
+ const perm = await perms.at(next3);
435
435
  const last = queue.length === 0;
436
436
  if (perm?.link !== void 0 && (!last || follow2)) {
437
- if (!trustedLink(perm, links)) return { path, perm: void 0, denied: next2, link: true };
438
- if (++hops > MAX_LINKS2) return { path: next2, perm: void 0 };
437
+ if (!trustedLink(perm, links)) return { path, perm: void 0, denied: next3, link: true };
438
+ if (++hops > MAX_LINKS2) return { path: next3, perm: void 0 };
439
439
  queue.unshift(...parts(perm.link));
440
440
  if (perm.link.startsWith("/")) at = "/";
441
441
  continue;
442
442
  }
443
- if (last) return { path: next2, perm };
444
- at = next2;
443
+ if (last) return { path: next3, perm };
444
+ at = next3;
445
445
  }
446
446
  return { path: at, perm: await perms.at(at) };
447
447
  }
@@ -546,8 +546,13 @@ function ttyOpenable(g, tty) {
546
546
  async function need(g, op, path, want, options = {}, shown = path) {
547
547
  const walked = await access(g.fs, g.cred, path, want, linked(g, options));
548
548
  if (walked.denied !== void 0) deny(g, op, walked.link ? walked.denied : shown);
549
+ else if (want & R_OK && g.fs.commandTarget) await readsAs(g, op, walked.path, shown);
549
550
  return walked;
550
551
  }
552
+ async function readsAs(g, op, path, shown) {
553
+ const target = await g.fs.commandTarget?.(path);
554
+ if (target !== void 0) await need(g, op, target, R_OK, { directory: false }, shown);
555
+ }
551
556
  function entryIn(dir, path) {
552
557
  return joinName(dir.path, path.slice(path.lastIndexOf("/") + 1));
553
558
  }
@@ -706,14 +711,14 @@ function changeCred(cur, change) {
706
711
  throw fsError("EINVAL", "not a change");
707
712
  }
708
713
  const privileged = cur.euid === 0;
709
- const next2 = copyCred(cur);
714
+ const next3 = copyCred(cur);
710
715
  for (const keys of [UIDS, GIDS]) {
711
716
  const own = keys.map((key) => cur[key]);
712
717
  for (const key of keys) {
713
718
  const value = id(change[key]);
714
719
  if (value === void 0) continue;
715
720
  if (!privileged && !own.includes(value)) throw fsError("EPERM", `${key} ${value}`);
716
- next2[key] = value;
721
+ next3[key] = value;
717
722
  }
718
723
  }
719
724
  if (change.groups !== void 0) {
@@ -723,9 +728,9 @@ function changeCred(cur, change) {
723
728
  const groups = change.groups.map((g) => id(g) ?? Number.NaN);
724
729
  if (groups.some(Number.isNaN)) throw fsError("EINVAL", "not a group list");
725
730
  if (!privileged) throw fsError("EPERM", "setgroups");
726
- next2.groups = groups;
731
+ next3.groups = groups;
727
732
  }
728
- return next2;
733
+ return next3;
729
734
  }
730
735
  function maySignal(sender, target) {
731
736
  if (sender.euid === 0) return true;
@@ -1638,10 +1643,10 @@ var KernelSocket = class _KernelSocket {
1638
1643
  async accept(signal, nonblock = false) {
1639
1644
  for (; ; ) {
1640
1645
  if (this.state !== "listening") throw new KernelError("EINVAL");
1641
- const next2 = this.queue.shift();
1642
- if (next2) {
1646
+ const next3 = this.queue.shift();
1647
+ if (next3) {
1643
1648
  this.room.wake();
1644
- return next2;
1649
+ return next3;
1645
1650
  }
1646
1651
  if (nonblock) throw new KernelError("EAGAIN");
1647
1652
  await this.changes.wait(signal);
@@ -2181,12 +2186,12 @@ var MessageQueue = class {
2181
2186
  }
2182
2187
  async *[Symbol.asyncIterator]() {
2183
2188
  for (; ; ) {
2184
- const next2 = this.items.shift();
2185
- if (next2 !== void 0) {
2186
- const n = payloadSize(next2);
2189
+ const next3 = this.items.shift();
2190
+ if (next3 !== void 0) {
2191
+ const n = payloadSize(next3);
2187
2192
  this.size -= n;
2188
2193
  this.taken?.(n);
2189
- yield next2;
2194
+ yield next3;
2190
2195
  continue;
2191
2196
  }
2192
2197
  if (this.ended) return;
@@ -2313,13 +2318,35 @@ async function* chunks(body, idleMs) {
2313
2318
  if (!body) return;
2314
2319
  const reader = body.getReader();
2315
2320
  try {
2316
- for (let next2 = await readWithin(reader, idleMs); !next2.done; next2 = await readWithin(reader, idleMs)) {
2317
- if (next2.value.byteLength > 0) yield next2.value;
2321
+ for (let next3 = await readWithin(reader, idleMs); !next3.done; next3 = await readWithin(reader, idleMs)) {
2322
+ if (next3.value.byteLength > 0) yield next3.value;
2318
2323
  }
2319
2324
  } finally {
2320
2325
  await reader.cancel().catch(() => void 0);
2321
2326
  }
2322
2327
  }
2328
+ function streamOf(body) {
2329
+ const it = body[Symbol.asyncIterator]();
2330
+ return new ReadableStream(
2331
+ {
2332
+ async pull(controller) {
2333
+ const next3 = await it.next();
2334
+ if (next3.done) controller.close();
2335
+ else controller.enqueue(next3.value);
2336
+ },
2337
+ async cancel(reason) {
2338
+ await it.return?.(reason);
2339
+ }
2340
+ },
2341
+ { highWaterMark: 0 }
2342
+ );
2343
+ }
2344
+ function requestBody(request) {
2345
+ if (request.bodyStream) {
2346
+ return { body: streamOf(request.bodyStream), duplex: "half" };
2347
+ }
2348
+ return request.body ? { body: request.body } : {};
2349
+ }
2323
2350
  function fetchTransport(options = {}) {
2324
2351
  const send = options.fetch ?? globalThis.fetch.bind(globalThis);
2325
2352
  const Socket = options.webSocket === true ? globalThis.WebSocket : options.webSocket || void 0;
@@ -2331,7 +2358,8 @@ function fetchTransport(options = {}) {
2331
2358
  encodedBodies: false,
2332
2359
  maxRequestBody: options.maxRequestBody ?? MAX_REQUEST_BODY,
2333
2360
  crossOrigin: "cors",
2334
- ...Socket ? { websocket: true } : {}
2361
+ ...Socket ? { websocket: true } : {},
2362
+ ...options.streamingBodies ? { streamingBodies: true } : {}
2335
2363
  },
2336
2364
  ...Socket ? { websocket: (request) => openWebSocket(Socket, request, headers) } : {},
2337
2365
  async fetch(request) {
@@ -2340,7 +2368,7 @@ function fetchTransport(options = {}) {
2340
2368
  response = await send(request.url, {
2341
2369
  method: request.method,
2342
2370
  headers: joinHeaders(request.headers),
2343
- ...request.body ? { body: request.body } : {},
2371
+ ...requestBody(request),
2344
2372
  signal: request.signal,
2345
2373
  redirect,
2346
2374
  credentials: "omit",
@@ -2377,6 +2405,29 @@ function fetchTransport(options = {}) {
2377
2405
  }
2378
2406
  };
2379
2407
  }
2408
+ function uploadsFor(peer) {
2409
+ const pulls = /* @__PURE__ */ new Map();
2410
+ const of = (nid, signal) => ({
2411
+ async *[Symbol.asyncIterator]() {
2412
+ for (; ; ) {
2413
+ signal.throwIfAborted();
2414
+ const got = await new Promise((resolve2, reject) => {
2415
+ const stop = () => reject(signal.reason);
2416
+ signal.addEventListener("abort", stop, { once: true });
2417
+ pulls.set(nid, (call) => {
2418
+ signal.removeEventListener("abort", stop);
2419
+ resolve2(call);
2420
+ });
2421
+ peer.postMessage({ net: "body-pull", nid });
2422
+ }).finally(() => pulls.delete(nid));
2423
+ if (got.net === "body-end") return;
2424
+ if (got.net === "body-error") throw new Error(got.message);
2425
+ if (got.net === "body-chunk") yield got.bytes;
2426
+ }
2427
+ }
2428
+ });
2429
+ return { of, answer: (call) => pulls.get(call.nid)?.(call) };
2430
+ }
2380
2431
  function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS } = {}) {
2381
2432
  const open = /* @__PURE__ */ new Map();
2382
2433
  const fail3 = (nid, e) => {
@@ -2390,6 +2441,7 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS } = {}) {
2390
2441
  ...typeof code === "string" ? { code } : {}
2391
2442
  });
2392
2443
  };
2444
+ const uploads = uploadsFor(peer);
2393
2445
  const start2 = async (call) => {
2394
2446
  const abort = new AbortController();
2395
2447
  const entry = { abort };
@@ -2399,7 +2451,7 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS } = {}) {
2399
2451
  url: call.url,
2400
2452
  method: call.method,
2401
2453
  headers: call.headers,
2402
- ...call.body ? { body: call.body } : {},
2454
+ ...call.streamed ? { bodyStream: uploads.of(call.nid, abort.signal) } : call.body ? { body: call.body } : {},
2403
2455
  signal: abort.signal
2404
2456
  });
2405
2457
  if (!open.has(call.nid)) {
@@ -2471,9 +2523,9 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS } = {}) {
2471
2523
  try {
2472
2524
  const messages = socket.messages[Symbol.asyncIterator]();
2473
2525
  for (; ; ) {
2474
- const next2 = await Promise.race([messages.next(), unanswered]);
2475
- if (next2 === "late" || next2.done) break;
2476
- const data = next2.value;
2526
+ const next3 = await Promise.race([messages.next(), unanswered]);
2527
+ if (next3 === "late" || next3.done) break;
2528
+ const data = next3.value;
2477
2529
  if (flow.closing) continue;
2478
2530
  if (payloadSize(data) > MESSAGE_LIMIT) {
2479
2531
  oversize = true;
@@ -2514,12 +2566,12 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS } = {}) {
2514
2566
  const body = open.get(nid)?.body;
2515
2567
  if (!body) return;
2516
2568
  try {
2517
- const next2 = await body.next();
2518
- if (next2.done) {
2569
+ const next3 = await body.next();
2570
+ if (next3.done) {
2519
2571
  open.delete(nid);
2520
2572
  peer.postMessage({ net: "end", nid });
2521
2573
  } else {
2522
- const bytes = fresh(next2.value);
2574
+ const bytes = fresh(next3.value);
2523
2575
  peer.postMessage({ net: "chunk", nid, bytes }, [bytes.buffer]);
2524
2576
  }
2525
2577
  } catch (e) {
@@ -2537,7 +2589,9 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS } = {}) {
2537
2589
  return {
2538
2590
  answer(call) {
2539
2591
  if (call.net === "fetch") void start2(call);
2540
- else if (call.net === "read") void read(call.nid);
2592
+ else if (call.net === "body-chunk" || call.net === "body-end" || call.net === "body-error") {
2593
+ uploads.answer(call);
2594
+ } else if (call.net === "read") void read(call.nid);
2541
2595
  else if (call.net === "ws-open") void openSocket(call);
2542
2596
  else if (call.net === "ws-send") void sendOn(call);
2543
2597
  else if (call.net === "ws-close") {
@@ -2747,9 +2801,9 @@ var UserDb = class {
2747
2801
  }
2748
2802
  }
2749
2803
  serial(work) {
2750
- const next2 = this.writing.then(work);
2751
- this.writing = next2.catch(() => void 0);
2752
- return next2;
2804
+ const next3 = this.writing.then(work);
2805
+ this.writing = next3.catch(() => void 0);
2806
+ return next3;
2753
2807
  }
2754
2808
  async ensure() {
2755
2809
  await this.fs.mkdir("/etc", { recursive: true });
@@ -2948,14 +3002,14 @@ async function realpath(fs, path) {
2948
3002
  let resolved2 = "";
2949
3003
  for (let hops = 0; parts2.length > 0; ) {
2950
3004
  const [name2, ...rest2] = parts2;
2951
- const next2 = `${resolved2}/${name2}`;
2952
- if (!(await fs.lstat(next2)).isSymbolicLink) {
2953
- resolved2 = next2;
3005
+ const next3 = `${resolved2}/${name2}`;
3006
+ if (!(await fs.lstat(next3)).isSymbolicLink) {
3007
+ resolved2 = next3;
2954
3008
  parts2 = rest2;
2955
3009
  continue;
2956
3010
  }
2957
3011
  if (++hops > MAX_LINKS3) throw fsError("ELOOP", path);
2958
- const target = await fs.readlink(next2);
3012
+ const target = await fs.readlink(next3);
2959
3013
  const base = target.startsWith("/") ? "/" : resolved2 || "/";
2960
3014
  parts2 = [...fs.resolvePath(base, target).split("/").filter(Boolean), ...rest2];
2961
3015
  resolved2 = "";
@@ -3434,9 +3488,9 @@ var PathMap = class {
3434
3488
  }
3435
3489
  link(path) {
3436
3490
  for (let child = path, parent = parentOf2(path); parent !== void 0; ) {
3437
- const set2 = this.children.get(parent);
3438
- if (set2?.has(child)) return;
3439
- if (set2) set2.add(child);
3491
+ const set3 = this.children.get(parent);
3492
+ if (set3?.has(child)) return;
3493
+ if (set3) set3.add(child);
3440
3494
  else this.children.set(parent, /* @__PURE__ */ new Set([child]));
3441
3495
  child = parent;
3442
3496
  parent = parentOf2(parent);
@@ -3445,9 +3499,9 @@ var PathMap = class {
3445
3499
  prune(path) {
3446
3500
  for (let child = path, parent = parentOf2(path); parent !== void 0; ) {
3447
3501
  if (this.values.has(child) || this.children.has(child)) return;
3448
- const set2 = this.children.get(parent);
3449
- set2?.delete(child);
3450
- if (set2 && set2.size > 0) return;
3502
+ const set3 = this.children.get(parent);
3503
+ set3?.delete(child);
3504
+ if (set3 && set3.size > 0) return;
3451
3505
  this.children.delete(parent);
3452
3506
  child = parent;
3453
3507
  parent = parentOf2(parent);
@@ -3588,14 +3642,14 @@ var Integrity = class {
3588
3642
  if (!this.root.version) return void 0;
3589
3643
  return `${real}\0${await this.root.version(real)}`;
3590
3644
  }
3591
- async read(path, caller, plain, asked) {
3592
- return (await this.readKeyed(path, caller, plain, asked)).bytes;
3645
+ async read(path, caller, plain2, asked) {
3646
+ return (await this.readKeyed(path, caller, plain2, asked)).bytes;
3593
3647
  }
3594
- async readKeyed(path, caller, plain, asked) {
3648
+ async readKeyed(path, caller, plain2, asked) {
3595
3649
  const found = await this.real(path, asked);
3596
- if (found === void 0) return { bytes: await plain() };
3650
+ if (found === void 0) return { bytes: await plain2() };
3597
3651
  const { real, name: name2 } = found;
3598
- const read = name2 !== real ? { bytes: await plain(), version: void 0 } : this.root.readVersioned ? await this.root.readVersioned(real) : { bytes: await this.root.readFileBuffer(real), version: void 0 };
3652
+ const read = name2 !== real ? { bytes: await plain2(), version: void 0 } : this.root.readVersioned ? await this.root.readVersioned(real) : { bytes: await this.root.readFileBuffer(real), version: void 0 };
3599
3653
  const { bytes } = read;
3600
3654
  const keyed = read.version === void 0 ? { bytes } : { bytes, key: `${real}\0${read.version}` };
3601
3655
  await this.verify(name2, bytes, caller, EXEC_OPS);
@@ -3604,9 +3658,9 @@ var Integrity = class {
3604
3658
  get readsChecked() {
3605
3659
  return this.sources.length > 0;
3606
3660
  }
3607
- async readSource(path, caller, plain) {
3661
+ async readSource(path, caller, plain2) {
3608
3662
  const found = await this.source(path);
3609
- return found === void 0 ? plain() : this.checked(found, caller, plain);
3663
+ return found === void 0 ? plain2() : this.checked(found, caller, plain2);
3610
3664
  }
3611
3665
  async openSource(path, caller, real) {
3612
3666
  const found = await this.source(path, real);
@@ -3616,10 +3670,10 @@ var Integrity = class {
3616
3670
  }
3617
3671
  await this.checked(found, caller, () => this.root.readFileBuffer(found.real));
3618
3672
  }
3619
- async checked(found, caller, plain) {
3673
+ async checked(found, caller, plain2) {
3620
3674
  const { real, name: name2 } = found;
3621
3675
  if (name2 !== real || !this.root.readVersioned) {
3622
- const bytes2 = await plain();
3676
+ const bytes2 = await plain2();
3623
3677
  await this.verify(name2, bytes2, caller, READ_OPS);
3624
3678
  return bytes2;
3625
3679
  }
@@ -4328,8 +4382,8 @@ var OpfsFs = class {
4328
4382
  this.refuse(found.path);
4329
4383
  const [stored] = found.link ? [found.link] : await this.meta.get([found.path]);
4330
4384
  const current = await this.ownerAt(found.path, stored);
4331
- const next2 = { uid: change.uid ?? current.uid, gid: change.gid ?? current.gid };
4332
- const handing = found.handle?.kind === "directory" && !sameOwner(next2, current);
4385
+ const next3 = { uid: change.uid ?? current.uid, gid: change.gid ?? current.gid };
4386
+ const handing = found.handle?.kind === "directory" && !sameOwner(next3, current);
4333
4387
  const heir = change.kind === "adopt" ? void 0 : stored?.heir ?? (handing ? [current.uid, current.gid] : void 0);
4334
4388
  const ctimeMs = Date.now();
4335
4389
  await this.meta.update(found.path, (entry) => {
@@ -4337,7 +4391,7 @@ var OpfsFs = class {
4337
4391
  return {
4338
4392
  ...rest2,
4339
4393
  path: found.path,
4340
- ...next2,
4394
+ ...next3,
4341
4395
  ...heir ? { heir } : {},
4342
4396
  ...change.mode !== void 0 ? { mode: change.mode & PERM_MASK } : {},
4343
4397
  ctimeMs
@@ -5264,9 +5318,9 @@ var UnlinkedKeeper = class {
5264
5318
  void locks?.request(lockName(this.instance), () => new Promise(() => void 0));
5265
5319
  }
5266
5320
  serial(op) {
5267
- const next2 = this.queue.then(op);
5268
- this.queue = next2.catch(() => void 0);
5269
- return next2;
5321
+ const next3 = this.queue.then(op);
5322
+ this.queue = next3.catch(() => void 0);
5323
+ return next3;
5270
5324
  }
5271
5325
  wrap(fs = this.fs) {
5272
5326
  const keeper = this;
@@ -5475,10 +5529,10 @@ var Incoming = class {
5475
5529
  this.eof = true;
5476
5530
  return false;
5477
5531
  }
5478
- const next2 = new Uint8Array(this.buf.length + chunk2.length);
5479
- next2.set(this.buf);
5480
- next2.set(chunk2, this.buf.length);
5481
- this.buf = next2;
5532
+ const next3 = new Uint8Array(this.buf.length + chunk2.length);
5533
+ next3.set(this.buf);
5534
+ next3.set(chunk2, this.buf.length);
5535
+ this.buf = next3;
5482
5536
  return true;
5483
5537
  }
5484
5538
  take(n) {
@@ -5618,23 +5672,50 @@ async function readBody(incoming, framing, cap, signal) {
5618
5672
  const chunks2 = [];
5619
5673
  let total = 0;
5620
5674
  for (; ; ) {
5621
- const sizeLine = await incoming.line(MAX_CHUNK_LINE, signal);
5622
- const size = /^([0-9A-Fa-f]{1,12})[ \t]*(;.*)?$/.exec(sizeLine);
5623
- if (!size) throw new HttpError(400, "malformed chunk size");
5624
- const n = Number.parseInt(size[1], 16);
5675
+ const n = await chunkSize(incoming, signal);
5625
5676
  if (n === 0) break;
5626
5677
  total += n;
5627
5678
  if (total > cap) throw new HttpError(413, `request body over ${cap} bytes`);
5628
5679
  chunks2.push(await incoming.exactly(n, signal));
5629
5680
  if (await incoming.line(2, signal) !== "") throw new HttpError(400, "malformed chunk");
5630
5681
  }
5682
+ await skipTrailers(incoming, signal);
5683
+ return concat(chunks2, total);
5684
+ }
5685
+ async function chunkSize(incoming, signal) {
5686
+ const sizeLine = await incoming.line(MAX_CHUNK_LINE, signal);
5687
+ const size = /^([0-9A-Fa-f]{1,12})[ \t]*(;.*)?$/.exec(sizeLine);
5688
+ if (!size) throw new HttpError(400, "malformed chunk size");
5689
+ return Number.parseInt(size[1], 16);
5690
+ }
5691
+ async function skipTrailers(incoming, signal) {
5631
5692
  let trailers = 0;
5632
5693
  for (let line = await incoming.line(MAX_TRAILERS, signal); line !== ""; ) {
5633
5694
  trailers += line.length;
5634
5695
  if (trailers > MAX_TRAILERS) throw new HttpError(431, "trailers too large");
5635
5696
  line = await incoming.line(MAX_TRAILERS, signal);
5636
5697
  }
5637
- return concat(chunks2, total);
5698
+ }
5699
+ var STREAM_PIECE = 64 * 1024;
5700
+ async function* pieces(incoming, n, signal) {
5701
+ for (let left = n; left > 0; ) {
5702
+ const piece = await incoming.some(Math.min(left, STREAM_PIECE), signal);
5703
+ if (piece.length === 0) throw new HttpError(400, "connection closed inside a body");
5704
+ left -= piece.length;
5705
+ yield piece;
5706
+ }
5707
+ }
5708
+ async function* streamBody(incoming, framing, signal) {
5709
+ if (framing.kind === "none") return;
5710
+ if (framing.kind === "length") {
5711
+ yield* pieces(incoming, framing.length, signal);
5712
+ return;
5713
+ }
5714
+ for (let n = await chunkSize(incoming, signal); n !== 0; n = await chunkSize(incoming, signal)) {
5715
+ yield* pieces(incoming, n, signal);
5716
+ if (await incoming.line(2, signal) !== "") throw new HttpError(400, "malformed chunk");
5717
+ }
5718
+ await skipTrailers(incoming, signal);
5638
5719
  }
5639
5720
  function concat(chunks2, total = chunks2.reduce((n, c) => n + c.length, 0)) {
5640
5721
  const out = new Uint8Array(total);
@@ -5747,11 +5828,11 @@ function frame(opcode, payload) {
5747
5828
  return out;
5748
5829
  }
5749
5830
  function clientFrame(opcode, payload) {
5750
- const plain = frame(opcode, payload);
5751
- const head = plain.length - payload.length;
5831
+ const plain2 = frame(opcode, payload);
5832
+ const head = plain2.length - payload.length;
5752
5833
  const mask = crypto.getRandomValues(new Uint8Array(4));
5753
- const out = new Uint8Array(plain.length + 4);
5754
- out.set(plain.subarray(0, head));
5834
+ const out = new Uint8Array(plain2.length + 4);
5835
+ out.set(plain2.subarray(0, head));
5755
5836
  out[1] = out[1] | 128;
5756
5837
  out.set(mask, head);
5757
5838
  for (let i = 0; i < payload.length; i++) {
@@ -6203,6 +6284,164 @@ function closeAll(entry) {
6203
6284
  }
6204
6285
  }
6205
6286
 
6287
+ // src/fs/engines.ts
6288
+ var NUMBER = /^(0|[1-9]\d*)$/;
6289
+ var PART = /^(?:0|[1-9]\d*|[xX*])$/;
6290
+ var IDENTIFIER = /^(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)$/;
6291
+ function identifiers(pre) {
6292
+ if (pre === void 0) return [];
6293
+ const ids = pre.split(".");
6294
+ return ids.every((id2) => IDENTIFIER.test(id2)) ? ids : void 0;
6295
+ }
6296
+ function parseVersion(text) {
6297
+ const m = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(text.trim());
6298
+ const pre = identifiers(m?.[4]);
6299
+ if (!m || !pre || ![m[1], m[2], m[3]].every((n) => NUMBER.test(n))) return void 0;
6300
+ return [Number(m[1]), Number(m[2]), Number(m[3]), pre];
6301
+ }
6302
+ function comparePre(a, b) {
6303
+ if (a.length === 0 || b.length === 0) return b.length - a.length;
6304
+ for (let i = 0; i < Math.max(a.length, b.length); i++) {
6305
+ const [x, y] = [a[i], b[i]];
6306
+ if (x === void 0 || y === void 0) return x === void 0 ? -1 : 1;
6307
+ if (x === y) continue;
6308
+ const [nx, ny] = [NUMBER.test(x), NUMBER.test(y)];
6309
+ if (nx && ny) return Number(x) - Number(y);
6310
+ if (nx !== ny) return nx ? -1 : 1;
6311
+ return x < y ? -1 : 1;
6312
+ }
6313
+ return 0;
6314
+ }
6315
+ function compare(a, b) {
6316
+ return a[0] - b[0] || a[1] - b[1] || a[2] - b[2] || comparePre(a[3], b[3]);
6317
+ }
6318
+ function partial(text) {
6319
+ const m = /^v?([^.+-]+)(?:\.([^.+-]+))?(?:\.([^.+-]+))?(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(
6320
+ text
6321
+ );
6322
+ if (!m) return void 0;
6323
+ const raw = [m[1], m[2], m[3]];
6324
+ if (!raw.every((p) => p === void 0 || PART.test(p))) return void 0;
6325
+ const parts2 = [];
6326
+ for (const p of raw) {
6327
+ if (p === void 0 || /^[xX*]$/.test(p) || parts2.includes(void 0)) parts2.push(void 0);
6328
+ else parts2.push(Number(p));
6329
+ }
6330
+ const pre = identifiers(m[4]);
6331
+ return pre && { parts: parts2, pre };
6332
+ }
6333
+ function floor(p) {
6334
+ const [a = 0, b = 0, c = 0] = p.parts;
6335
+ return [a, b, c, p.parts.includes(void 0) ? [] : p.pre];
6336
+ }
6337
+ function next(p) {
6338
+ const [a, b] = p.parts;
6339
+ if (a === void 0) return void 0;
6340
+ if (b === void 0) return [a + 1, 0, 0, ["0"]];
6341
+ return [a, b + 1, 0, ["0"]];
6342
+ }
6343
+ var ANY = [[">=", [0, 0, 0, []]]];
6344
+ var NOTHING = [["<", [0, 0, 0, ["0"]]]];
6345
+ function plain(op, p) {
6346
+ const exact = !p.parts.includes(void 0);
6347
+ const low = floor(p);
6348
+ const high = next(p);
6349
+ if (op === ">=") return [[">=", low]];
6350
+ if (op === "<") return [["<", exact ? low : [low[0], low[1], low[2], ["0"]]]];
6351
+ if (exact) return [[op === "" ? "=" : op, low]];
6352
+ if (op === ">") return high ? [[">=", high]] : NOTHING;
6353
+ if (op === "<=") return high ? [["<", high]] : ANY;
6354
+ return high ? [
6355
+ [">=", low],
6356
+ ["<", high]
6357
+ ] : ANY;
6358
+ }
6359
+ function caret(p) {
6360
+ const [a = 0, b, c] = p.parts;
6361
+ const low = floor(p);
6362
+ if (b === void 0)
6363
+ return [
6364
+ [">=", low],
6365
+ ["<", [a + 1, 0, 0, ["0"]]]
6366
+ ];
6367
+ if (a > 0)
6368
+ return [
6369
+ [">=", low],
6370
+ ["<", [a + 1, 0, 0, ["0"]]]
6371
+ ];
6372
+ if (c === void 0 || b > 0)
6373
+ return [
6374
+ [">=", low],
6375
+ ["<", [0, b + 1, 0, ["0"]]]
6376
+ ];
6377
+ return [
6378
+ [">=", low],
6379
+ ["<", [0, b, c + 1, ["0"]]]
6380
+ ];
6381
+ }
6382
+ function tilde(p) {
6383
+ const [a = 0, b] = p.parts;
6384
+ const low = floor(p);
6385
+ return [
6386
+ [">=", low],
6387
+ ["<", b === void 0 ? [a + 1, 0, 0, ["0"]] : [a, b + 1, 0, ["0"]]]
6388
+ ];
6389
+ }
6390
+ function hyphen(from, to) {
6391
+ const high = to.parts.includes(void 0) ? next(to) : void 0;
6392
+ const upper = to.parts.includes(void 0) ? high ? [["<", high]] : [] : [["<=", floor(to)]];
6393
+ return [[">=", floor(from)], ...upper];
6394
+ }
6395
+ function comparator(token) {
6396
+ const m = /^(<=|>=|<|>|=|\^|~>?)?\s*(.*)$/.exec(token);
6397
+ const op = m?.[1] ?? "";
6398
+ const p = partial(m?.[2] ?? "");
6399
+ if (!p) return void 0;
6400
+ const wild = p.parts[0] === void 0;
6401
+ if (op === "^") return wild ? ANY : caret(p);
6402
+ if (op.startsWith("~")) return wild ? ANY : tilde(p);
6403
+ return plain(op, p);
6404
+ }
6405
+ function set(text) {
6406
+ const trimmed = text.trim().replace(/(<=|>=|<|>|=|\^|~>?)\s+/g, "$1");
6407
+ if (trimmed === "") return ANY;
6408
+ const range = /^(\S+)\s+-\s+(\S+)$/.exec(trimmed);
6409
+ if (range) {
6410
+ const [from, to] = [partial(range[1]), partial(range[2])];
6411
+ return from && to ? hyphen(from, to) : void 0;
6412
+ }
6413
+ const out = [];
6414
+ for (const token of trimmed.split(/\s+/)) {
6415
+ const found = comparator(token);
6416
+ if (!found) return void 0;
6417
+ out.push(...found);
6418
+ }
6419
+ return out;
6420
+ }
6421
+ function holds(v, [op, w]) {
6422
+ const c = compare(v, w);
6423
+ if (op === "<") return c < 0;
6424
+ if (op === "<=") return c <= 0;
6425
+ if (op === ">") return c > 0;
6426
+ if (op === ">=") return c >= 0;
6427
+ return c === 0;
6428
+ }
6429
+ function satisfies(version, range) {
6430
+ const v = parseVersion(version);
6431
+ if (!v) return void 0;
6432
+ const sets = range.split("||").map(set);
6433
+ if (sets.some((s) => s === void 0)) return void 0;
6434
+ return sets.some((s) => s.every((c) => holds(v, c)));
6435
+ }
6436
+
6437
+ // src/version.ts
6438
+ var KERNEL_VERSION = true ? "1.106.2" : "0.0.0-dev";
6439
+ var OS_RELEASE = "6.0.0-slicc";
6440
+ function procVersion() {
6441
+ return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
6442
+ `;
6443
+ }
6444
+
6206
6445
  // src/commands.ts
6207
6446
  var NAME2 = /^[A-Za-z0-9._+-]+$/;
6208
6447
  var COMMAND_NAME = /^[^/\s\p{Cc}]+$/u;
@@ -6414,13 +6653,25 @@ async function binCommandsOf(physical, pkg, manifest, taken) {
6414
6653
  }
6415
6654
  return out;
6416
6655
  }
6656
+ function engineRefusal(manifest, kernel) {
6657
+ const engines = manifest.engines;
6658
+ const range = engines && typeof engines === "object" ? engines["slicc-kernel"] : void 0;
6659
+ const running = parseVersion(kernel);
6660
+ if (typeof range !== "string" || !running || running.slice(0, 3).every((n) => n === 0)) {
6661
+ return void 0;
6662
+ }
6663
+ const fits = satisfies(kernel, range);
6664
+ if (fits) return void 0;
6665
+ const who = `${String(manifest.name ?? "?")}@${String(manifest.version ?? "?")}`;
6666
+ return fits === false ? `${who} needs slicc-kernel ${range}; this kernel is ${kernel}` : `${who} has an engines.slicc-kernel range this kernel can't read: ${JSON.stringify(range)}`;
6667
+ }
6417
6668
  var PACKAGE_NAME = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
6418
6669
  function replacesOf(manifest) {
6419
6670
  const replaces = manifest.slicc?.replaces;
6420
6671
  if (!Array.isArray(replaces)) return [];
6421
6672
  return replaces.every((name2) => typeof name2 === "string" && PACKAGE_NAME.test(name2)) ? replaces : [];
6422
6673
  }
6423
- async function tierPackages(fs, physical, roots, bins) {
6674
+ async function tierPackages(fs, physical, roots, bins, kernel) {
6424
6675
  const out = [];
6425
6676
  for (const root of roots) {
6426
6677
  for (const pkg of await packages(fs, root)) {
@@ -6433,11 +6684,13 @@ async function tierPackages(fs, physical, roots, bins) {
6433
6684
  const own = commandsOf(pkg, manifest);
6434
6685
  const named = new Set(own.map((command) => command.name));
6435
6686
  const extra = bins ? await binCommandsOf(physical, pkg, manifest, named) : [];
6687
+ const refused2 = engineRefusal(manifest, kernel);
6688
+ const commands = [...own, ...extra];
6436
6689
  out.push({
6437
6690
  name: pkg.slice(root.length + 1),
6438
6691
  pkg,
6439
6692
  replaces: replacesOf(manifest),
6440
- commands: [...own, ...extra]
6693
+ commands: refused2 ? commands.map((command) => ({ ...command, refused: refused2 })) : commands
6441
6694
  });
6442
6695
  }
6443
6696
  }
@@ -6463,14 +6716,14 @@ function winners(tier) {
6463
6716
  }
6464
6717
  return out;
6465
6718
  }
6466
- async function scanCommands(fs, modules, binsFrom = Number.POSITIVE_INFINITY) {
6719
+ async function scanCommands(fs, modules, binsFrom = Number.POSITIVE_INFINITY, kernel = KERNEL_VERSION) {
6467
6720
  const found = /* @__PURE__ */ new Map();
6468
6721
  const physical = physicalResolver(fs);
6469
6722
  const tiers = (typeof modules === "string" ? [modules] : modules).map(
6470
6723
  (tier) => typeof tier === "string" ? [tier] : tier
6471
6724
  );
6472
6725
  for (const [index, roots] of tiers.entries()) {
6473
- const tier = await tierPackages(fs, physical, roots, index >= binsFrom);
6726
+ const tier = await tierPackages(fs, physical, roots, index >= binsFrom, kernel);
6474
6727
  for (const [name2, { pkg, command }] of winners(tier)) {
6475
6728
  if (!found.has(name2)) found.set(name2, await withPackagePaths(fs, pkg, command));
6476
6729
  }
@@ -6719,6 +6972,11 @@ async function watchHangup(conn, abort, until) {
6719
6972
  }
6720
6973
  }
6721
6974
  }
6975
+ var BODILESS_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD"]);
6976
+ async function* drain(body, done4) {
6977
+ yield* body;
6978
+ done4();
6979
+ }
6722
6980
  function untilAborted(response, signal) {
6723
6981
  return new Promise((resolve2, reject) => {
6724
6982
  const onAbort = () => {
@@ -6861,7 +7119,8 @@ var RealmProxy = class {
6861
7119
  const url = ctx.origin ? tunnelRequestUrl(req, ctx.origin) : requestUrl(req);
6862
7120
  const keep2 = keepsAlive(req);
6863
7121
  const framing = requestFraming(req.headers);
6864
- const reserve = framing.kind === "length" ? framing.length : framing.kind === "chunked" ? this.cap() : 0;
7122
+ const streaming = this.options.transport.traits.streamingBodies === true && framing.kind !== "none" && !BODILESS_METHODS.has(req.method);
7123
+ const reserve = streaming ? 0 : framing.kind === "length" ? framing.length : framing.kind === "chunked" ? this.cap() : 0;
6865
7124
  if (reserve > this.cap()) throw new HttpError(413, `request body over ${this.cap()} bytes`);
6866
7125
  await this.expectContinue(conn, req, framing.kind !== "none");
6867
7126
  await this.bodies.acquire(reserve, this.stop.signal);
@@ -6869,9 +7128,12 @@ var RealmProxy = class {
6869
7128
  const abort = new AbortController();
6870
7129
  const stopExchange = () => abort.abort();
6871
7130
  this.stop.signal.addEventListener("abort", stopExchange, { once: true });
7131
+ let drained = !streaming;
6872
7132
  try {
6873
7133
  try {
6874
- const body = await readBody(incoming, framing, this.cap());
7134
+ const body = streaming ? drain(streamBody(incoming, framing, abort.signal), () => {
7135
+ drained = true;
7136
+ }) : await readBody(incoming, framing, this.cap());
6875
7137
  const waiting = new AbortController();
6876
7138
  void watchHangup(ctx.socket, abort, waiting.signal);
6877
7139
  try {
@@ -6882,7 +7144,8 @@ var RealmProxy = class {
6882
7144
  } finally {
6883
7145
  this.bodies.release(reserve);
6884
7146
  }
6885
- return await this.relay(conn, req.method, req.minor, response, keep2);
7147
+ const kept = await this.relay(conn, req.method, req.minor, response, keep2 && drained);
7148
+ return kept && drained;
6886
7149
  } finally {
6887
7150
  this.stop.signal.removeEventListener("abort", stopExchange);
6888
7151
  abort.abort();
@@ -6902,13 +7165,14 @@ var RealmProxy = class {
6902
7165
  }
6903
7166
  }
6904
7167
  async upstream(req, url, body, signal, owner) {
7168
+ const sent = BODILESS_METHODS.has(req.method) ? void 0 : body;
6905
7169
  try {
6906
7170
  const fetching = this.options.transport.fetch(
6907
7171
  {
6908
7172
  url: toHostLoopback(url),
6909
7173
  method: req.method.toUpperCase(),
6910
7174
  headers: forwardRequestHeaders(req.headers),
6911
- body: req.method === "GET" || req.method === "HEAD" ? void 0 : body,
7175
+ ...sent instanceof Uint8Array ? { body: sent } : sent ? { bodyStream: sent } : {},
6912
7176
  signal
6913
7177
  },
6914
7178
  owner
@@ -7404,6 +7668,7 @@ var S_IFDIR2 = 16384;
7404
7668
  var S_IFREG2 = 32768;
7405
7669
  var COMMAND = /^\/(?:usr\/)?bin\/([^/]+)$/;
7406
7670
  var MAX_LINKS6 = 40;
7671
+ var BIN_ENTRY = /\/bin\/[^/]+$/;
7407
7672
  function missing3(err) {
7408
7673
  return err?.code === "ENOENT";
7409
7674
  }
@@ -7431,7 +7696,20 @@ async function followLinks(fs, path) {
7431
7696
  }
7432
7697
  return current;
7433
7698
  }
7434
- function withCommandDirs(fs, names, userDir = async () => void 0, owners = false) {
7699
+ var NOBODY = { ruid: -1, euid: -1, suid: -1, rgid: -1, egid: -1, sgid: -1, groups: [] };
7700
+ var EMPTY = new Uint8Array(0);
7701
+ function quiet2(promise) {
7702
+ return promise.catch(() => void 0);
7703
+ }
7704
+ async function readsAs2(fs, cred, target) {
7705
+ const walked = await quiet2(access(fs, cred, target, R_OK, { directory: false }));
7706
+ return walked !== void 0 && walked.denied === void 0 && !walked.missing;
7707
+ }
7708
+ async function shownTarget(fs, target) {
7709
+ const st = await quiet2(fs.stat(target));
7710
+ return st?.isFile && await readsAs2(fs, NOBODY, target) ? st : void 0;
7711
+ }
7712
+ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false, targetOf2 = async () => void 0) {
7435
7713
  async function nearest(path) {
7436
7714
  const st = await fs.stat(path).catch(() => void 0);
7437
7715
  if (st || path === "/") return st ?? {};
@@ -7463,9 +7741,54 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
7463
7741
  const own = await userDir(dir);
7464
7742
  return own?.has(path.slice(slash + 1)) ? owned4(synthetic(false, path), dir) : void 0;
7465
7743
  }
7744
+ let generation;
7745
+ const targets = /* @__PURE__ */ new Map();
7746
+ async function targetStat(target) {
7747
+ const now = await names();
7748
+ if (now !== generation) {
7749
+ generation = now;
7750
+ targets.clear();
7751
+ }
7752
+ let found = targets.get(target);
7753
+ if (!found) {
7754
+ found = shownTarget(fs, target);
7755
+ targets.set(target, found);
7756
+ }
7757
+ return found;
7758
+ }
7759
+ async function shown(path) {
7760
+ const st = await virtual(path);
7761
+ if (!st?.isFile) return st;
7762
+ const target = await targetOf2(path);
7763
+ const real = target === void 0 ? void 0 : await targetStat(target.path);
7764
+ return real ? { ...st, size: real.size, mtime: real.mtime, ctime: real.mtime, atime: real.mtime } : st;
7765
+ }
7466
7766
  async function linked2(path) {
7467
- return await virtual(path) ?? virtual(await followLinks(fs, path));
7767
+ return await shown(path) ?? shown(await followLinks(fs, path));
7768
+ }
7769
+ async function entryTarget(path) {
7770
+ if (!BIN_ENTRY.test(path) || !(await virtual(path))?.isFile) return void 0;
7771
+ if (!await fs.lstat(path).then(() => false, missing3)) return void 0;
7772
+ const target = await targetOf2(path);
7773
+ return target?.path === path ? void 0 : target;
7468
7774
  }
7775
+ async function redirected2(path) {
7776
+ const target = await entryTarget(path) ?? await entryTarget(await followLinks(fs, path));
7777
+ if (owners && target?.owner && !await readsAs2(fs, target.owner, target.path)) {
7778
+ throw fsError("EACCES", path);
7779
+ }
7780
+ return target?.path;
7781
+ }
7782
+ const absent2 = (err) => {
7783
+ if (missing3(err)) return EMPTY;
7784
+ throw err;
7785
+ };
7786
+ async function content(path, err) {
7787
+ if (!missing3(err) || !(await linked2(path))?.isFile) throw err;
7788
+ const target = await redirected2(path);
7789
+ return target === void 0 ? EMPTY : fs.readFileBuffer(target).catch(absent2);
7790
+ }
7791
+ const ranged2 = rangedOps(fs);
7469
7792
  async function stat(path, real) {
7470
7793
  try {
7471
7794
  return await real(path);
@@ -7477,16 +7800,13 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
7477
7800
  }
7478
7801
  return {
7479
7802
  resolvePath: (base, path) => fs.resolvePath(base, path),
7480
- readFile: (path) => fs.readFile(path),
7481
- async readFileBuffer(path) {
7482
- try {
7483
- return await fs.readFileBuffer(path);
7484
- } catch (err) {
7485
- if (missing3(err) && (await linked2(path))?.isFile) return new Uint8Array(0);
7486
- throw err;
7487
- }
7488
- },
7489
- writeFile: (path, content, owner) => fs.writeFile(path, content, owner),
7803
+ readFile: (path) => fs.readFile(path).catch(async (err) => {
7804
+ if (!BIN_ENTRY.test(await followLinks(fs, path))) throw err;
7805
+ return new TextDecoder().decode(await content(path, err));
7806
+ }),
7807
+ readFileBuffer: (path) => fs.readFileBuffer(path).catch((err) => content(path, err)),
7808
+ commandTarget: async (path) => (await entryTarget(path))?.path,
7809
+ writeFile: (path, content2, owner) => fs.writeFile(path, content2, owner),
7490
7810
  link: (from, to, follow2) => fs.link(from, to, follow2),
7491
7811
  links: (path) => mayLink(fs, path),
7492
7812
  async exists(path) {
@@ -7517,7 +7837,7 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
7517
7837
  added.map(
7518
7838
  async (name2) => [
7519
7839
  name2,
7520
- await virtual(`${base}/${name2}`)
7840
+ await shown(`${base}/${name2}`)
7521
7841
  ]
7522
7842
  )
7523
7843
  );
@@ -7535,7 +7855,14 @@ function withCommandDirs(fs, names, userDir = async () => void 0, owners = false
7535
7855
  chmod: (path, mode) => fs.chmod(path, mode),
7536
7856
  utimes: (path, atime, mtime) => fs.utimes(path, atime, mtime),
7537
7857
  lutimes: (path, atime, mtime) => lutimesOf(fs, path, atime, mtime),
7538
- ...rangedOps(fs) ?? {}
7858
+ ...ranged2 ? {
7859
+ ...ranged2,
7860
+ pread: (path, offset, length2, version) => ranged2.pread(path, offset, length2, version).catch(async (err) => {
7861
+ const target = missing3(err) ? await redirected2(path) : void 0;
7862
+ if (target === void 0) throw err;
7863
+ return ranged2.pread(target, offset, length2).catch(absent2);
7864
+ })
7865
+ } : {}
7539
7866
  };
7540
7867
  }
7541
7868
 
@@ -7680,7 +8007,7 @@ var MAX_HOPS2 = 40;
7680
8007
  function start(path) {
7681
8008
  return { done: [], todo: path.split("/").filter((p) => p !== ""), hops: 0 };
7682
8009
  }
7683
- function next(walk2) {
8010
+ function next2(walk2) {
7684
8011
  while (walk2.todo.length > 0) {
7685
8012
  const part = walk2.todo.shift();
7686
8013
  if (part === ".") continue;
@@ -7694,7 +8021,7 @@ function next(walk2) {
7694
8021
  }
7695
8022
  function lexical(path) {
7696
8023
  const walk2 = start(path);
7697
- for (let part = next(walk2); part !== void 0; part = next(walk2)) walk2.done.push(part);
8024
+ for (let part = next2(walk2); part !== void 0; part = next2(walk2)) walk2.done.push(part);
7698
8025
  return `/${walk2.done.join("/")}`;
7699
8026
  }
7700
8027
  function rest(walk2, part) {
@@ -7708,7 +8035,7 @@ function follow(walk2, target) {
7708
8035
  }
7709
8036
  async function physicalPathAsync(fs, path) {
7710
8037
  const walk2 = start(path);
7711
- for (let part = next(walk2); part !== void 0; part = next(walk2)) {
8038
+ for (let part = next2(walk2); part !== void 0; part = next2(walk2)) {
7712
8039
  const at = `/${[...walk2.done, part].join("/")}`;
7713
8040
  let target;
7714
8041
  try {
@@ -8006,7 +8333,8 @@ var ChildTable = class {
8006
8333
  const child = this.children.get(pid);
8007
8334
  if (!child) return;
8008
8335
  this.watchers.set(pid, listener);
8009
- if (child.stoppedBy !== void 0) listener("stopped", child.stoppedBy);
8336
+ if (child.stoppedBy !== void 0 && child.code === void 0)
8337
+ listener("stopped", child.stoppedBy);
8010
8338
  }
8011
8339
  openSlot(slot2, n, captured) {
8012
8340
  if ("fd" in slot2) return this.parentFds.get(slot2.fd).retain();
@@ -8475,14 +8803,14 @@ var HeldSet = class extends Set {
8475
8803
  super();
8476
8804
  this.idle = idle;
8477
8805
  }
8478
- add(holds) {
8479
- holds.onIdle = this.idle;
8480
- return super.add(holds);
8806
+ add(holds2) {
8807
+ holds2.onIdle = this.idle;
8808
+ return super.add(holds2);
8481
8809
  }
8482
- delete(holds) {
8483
- const removed = super.delete(holds);
8484
- for (const path of /* @__PURE__ */ new Set([...holds.keys(), ...holds.opens.keys()])) this.idle(path);
8485
- holds.releaseAll();
8810
+ delete(holds2) {
8811
+ const removed = super.delete(holds2);
8812
+ for (const path of /* @__PURE__ */ new Set([...holds2.keys(), ...holds2.opens.keys()])) this.idle(path);
8813
+ holds2.releaseAll();
8486
8814
  return removed;
8487
8815
  }
8488
8816
  };
@@ -9669,9 +9997,9 @@ var MountFs = class _MountFs {
9669
9997
  this.writable(mount, real);
9670
9998
  const { uid, gid, mode } = change;
9671
9999
  const fresh2 = change.kind === "new" && { uid, gid, mode };
9672
- const set2 = fresh2 ? await this.driverOwner(found, real, fresh2, false) : change;
10000
+ const set3 = fresh2 ? await this.driverOwner(found, real, fresh2, false) : change;
9673
10001
  this.table.forget(mount, real);
9674
- const attrs = Object.entries({ uid: set2.uid, gid: set2.gid, mode: set2.mode });
10002
+ const attrs = Object.entries({ uid: set3.uid, gid: set3.gid, mode: set3.mode });
9675
10003
  await mount.conn.call({
9676
10004
  op: "setattr",
9677
10005
  path: rel2,
@@ -9698,11 +10026,11 @@ var MountFs = class _MountFs {
9698
10026
  const real = await this.follow(path);
9699
10027
  const found = this.at(real);
9700
10028
  if (!found) {
9701
- const set2 = () => this.base.utimes(real, atime, mtime);
10029
+ const set3 = () => this.base.utimes(real, atime, mtime);
9702
10030
  return this.based(
9703
10031
  [real],
9704
10032
  redirects,
9705
- set2,
10033
+ set3,
9706
10034
  ([to], n) => this.utimes(to, atime, mtime, n)
9707
10035
  );
9708
10036
  }
@@ -9711,11 +10039,11 @@ var MountFs = class _MountFs {
9711
10039
  async lutimes(path, atime, mtime, redirects = 0) {
9712
10040
  const found = this.at(path);
9713
10041
  if (!found) {
9714
- const set2 = () => lutimesOf(this.base, path, atime, mtime);
10042
+ const set3 = () => lutimesOf(this.base, path, atime, mtime);
9715
10043
  return this.based(
9716
10044
  [path],
9717
10045
  redirects,
9718
- set2,
10046
+ set3,
9719
10047
  ([to], n) => this.lutimes(to, atime, mtime, n)
9720
10048
  );
9721
10049
  }
@@ -9737,6 +10065,20 @@ var MountFs = class _MountFs {
9737
10065
  }
9738
10066
  };
9739
10067
 
10068
+ // src/fs/command-stat.ts
10069
+ async function callerStat(g, path, st) {
10070
+ if (!g?.fs.commandTarget || !st.isFile || st.size > 0) return st;
10071
+ const target = await g.fs.commandTarget(path);
10072
+ if (target === void 0) return st;
10073
+ const options = { directory: false, ...g.links === void 0 ? {} : { links: g.links } };
10074
+ const walked = await access(g.fs, g.cred, target, R_OK, options).catch(() => void 0);
10075
+ if (!walked || walked.denied !== void 0 || walked.missing) return st;
10076
+ const real = await g.fs.stat(target).catch(() => void 0);
10077
+ if (!real?.isFile) return st;
10078
+ const { size, mtime } = real;
10079
+ return { ...st, size, mtime, atime: mtime, ctime: mtime };
10080
+ }
10081
+
9740
10082
  // src/realm/sync-fs-token-registry.ts
9741
10083
  var registry = /* @__PURE__ */ new Map();
9742
10084
  function mintSyncFsToken(entry) {
@@ -9823,8 +10165,10 @@ function statJson(s) {
9823
10165
  ...s.gid !== void 0 ? { gid: s.gid } : {}
9824
10166
  };
9825
10167
  }
9826
- async function readdirStat(fs, dir) {
9827
- return (await fs.readdirStat(dir)).map(([name2, stat]) => [name2, stat && statJson(stat)]);
10168
+ async function readdirStat(fs, dir, g) {
10169
+ const listed = await fs.readdirStat(dir);
10170
+ const shown = async (name2, stat) => stat && statJson(await callerStat(g, joinName(dir, name2), stat));
10171
+ return Promise.all(listed.map(async ([name2, stat]) => [name2, await shown(name2, stat)]));
9828
10172
  }
9829
10173
  async function usageAt(entry, path) {
9830
10174
  if (!entry.statfs) return void 0;
@@ -9893,18 +10237,22 @@ async function chown(entry, path, req) {
9893
10237
  }
9894
10238
  async function runMkdir(entry, path, req) {
9895
10239
  const { fs } = entry;
9896
- const plain = plainDirMode(entry, req.mode);
10240
+ const plain2 = plainDirMode(entry, req.mode);
9897
10241
  const parentsMode = !req.exclusive ? plainParentsMode(entry) : void 0;
9898
10242
  const fixParents = parentsMode !== void 0 ? await missingParents(fs, path, parentsMode) : void 0;
9899
- const fresh2 = plain !== void 0 && !await fs.exists(path);
10243
+ const fresh2 = plain2 !== void 0 && !await fs.exists(path);
9900
10244
  await (req.exclusive ? mkdirExclusive(entry, path, req.mode) : fs.mkdir(path, mkdirOptions(entry, req.mode)));
9901
10245
  await fixParents?.();
9902
- if (fresh2) await fs.chmod(path, plain);
10246
+ if (fresh2) await fs.chmod(path, plain2);
9903
10247
  return done;
9904
10248
  }
10249
+ async function shownAs(entry, path, st) {
10250
+ const real = st.isFile && st.size === 0 ? entry.fs.realpath?.(path, true) : void 0;
10251
+ return callerStat(guardOf(entry), await real?.catch(() => path) ?? path, st);
10252
+ }
9905
10253
  function readSource(entry, path) {
9906
- const plain = () => entry.fs.readFileBuffer(path);
9907
- return entry.source ? entry.source.read(path, plain) : plain();
10254
+ const plain2 = () => entry.fs.readFileBuffer(path);
10255
+ return entry.source ? entry.source.read(path, plain2) : plain2();
9908
10256
  }
9909
10257
  async function run(entry, path, req) {
9910
10258
  const { fs, cwd } = entry;
@@ -9917,13 +10265,13 @@ async function run(entry, path, req) {
9917
10265
  case "exists":
9918
10266
  return json2(await fs.exists(path));
9919
10267
  case "stat":
9920
- return json2(statJson(await fs.stat(path)));
10268
+ return json2(statJson(await shownAs(entry, path, await fs.stat(path))));
9921
10269
  case "lstat":
9922
- return json2(statJson(await fs.lstat(path)));
10270
+ return json2(statJson(await shownAs(entry, path, await fs.lstat(path))));
9923
10271
  case "readdir":
9924
10272
  return json2(await fs.readdir(path));
9925
10273
  case "readdir-stat":
9926
- return json2(await readdirStat(fs, path));
10274
+ return json2(await readdirStat(fs, path, guardOf(entry)));
9927
10275
  case "mkdir":
9928
10276
  return runMkdir(entry, path, req);
9929
10277
  case "rm":
@@ -10859,18 +11207,18 @@ var KernelDgram = class {
10859
11207
  const pending = this.takeError();
10860
11208
  if (pending) throw new KernelError(pending);
10861
11209
  if (this.closed) throw new KernelError("EBADF");
10862
- const next2 = this.queue[0];
10863
- if (next2) {
11210
+ const next3 = this.queue[0];
11211
+ if (next3) {
10864
11212
  if (!peek) {
10865
11213
  this.queue.shift();
10866
- this.queued -= next2.bytes.length;
11214
+ this.queued -= next3.bytes.length;
10867
11215
  this.changes.wake();
10868
11216
  }
10869
11217
  const size = Math.max(0, max);
10870
11218
  return {
10871
- bytes: next2.bytes.slice(0, size),
10872
- from: next2.from,
10873
- truncated: next2.bytes.length > size
11219
+ bytes: next3.bytes.slice(0, size),
11220
+ from: next3.from,
11221
+ truncated: next3.bytes.length > size
10874
11222
  };
10875
11223
  }
10876
11224
  await this.changes.wait(signal);
@@ -11189,14 +11537,6 @@ var PATH_OPS = new Set(SYNC_FS_OPS);
11189
11537
  // src/realm/live-vfs-fs.ts
11190
11538
  var EARLY_WHOLE_FILE = 64 * 1024;
11191
11539
 
11192
- // src/version.ts
11193
- var KERNEL_VERSION = true ? "1.103.4" : "0.0.0-dev";
11194
- var OS_RELEASE = "6.0.0-slicc";
11195
- function procVersion() {
11196
- return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
11197
- `;
11198
- }
11199
-
11200
11540
  // src/process/process-fds.ts
11201
11541
  var field2 = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
11202
11542
  var pinnedRoot;
@@ -11588,7 +11928,7 @@ function* procWalk(path, follow2) {
11588
11928
  const whole = normalize(`/${[...done4, part, ...todo].join("/")}`);
11589
11929
  if (inProc(at) && inProc(whole)) return broken ?? whole;
11590
11930
  if (!follow2 && todo.length === 0) return void 0;
11591
- const target = yield { at, check: todo.find((next2) => next2 !== ".") === ".." };
11931
+ const target = yield { at, check: todo.find((next3) => next3 !== ".") === ".." };
11592
11932
  if (typeof target === "string") {
11593
11933
  if (++hops > MAX_HOPS3) return void 0;
11594
11934
  [done4, todo] = throughLink(target, done4, todo);
@@ -11724,18 +12064,18 @@ function timerAfter(ms, fire) {
11724
12064
  return timerAt(performance.now() + ms, fire);
11725
12065
  }
11726
12066
  function repeating(first, every, fire) {
11727
- let next2 = performance.now() + first;
12067
+ let next3 = performance.now() + first;
11728
12068
  let cancel = () => {
11729
12069
  };
11730
12070
  const tick = () => {
11731
12071
  fire();
11732
12072
  if (every <= 0) return;
11733
- next2 += every;
12073
+ next3 += every;
11734
12074
  const now = performance.now();
11735
- if (next2 <= now) next2 += (Math.floor((now - next2) / every) + 1) * every;
11736
- cancel = timerAt(next2, tick);
12075
+ if (next3 <= now) next3 += (Math.floor((now - next3) / every) + 1) * every;
12076
+ cancel = timerAt(next3, tick);
11737
12077
  };
11738
- cancel = timerAt(next2, tick);
12078
+ cancel = timerAt(next3, tick);
11739
12079
  return () => cancel();
11740
12080
  }
11741
12081
 
@@ -12026,11 +12366,11 @@ var LockTable = class {
12026
12366
  }
12027
12367
  changed(key, signal) {
12028
12368
  return new Promise((resolve2, reject) => {
12029
- const set2 = this.wakers.get(key) ?? /* @__PURE__ */ new Set();
12030
- this.wakers.set(key, set2);
12369
+ const set3 = this.wakers.get(key) ?? /* @__PURE__ */ new Set();
12370
+ this.wakers.set(key, set3);
12031
12371
  const done4 = () => {
12032
- set2.delete(wake);
12033
- if (set2.size === 0 && this.wakers.get(key) === set2) this.wakers.delete(key);
12372
+ set3.delete(wake);
12373
+ if (set3.size === 0 && this.wakers.get(key) === set3) this.wakers.delete(key);
12034
12374
  signal.removeEventListener("abort", abort);
12035
12375
  };
12036
12376
  const wake = () => {
@@ -12041,7 +12381,7 @@ var LockTable = class {
12041
12381
  done4();
12042
12382
  reject(new KernelError("EINTR"));
12043
12383
  };
12044
- set2.add(wake);
12384
+ set3.add(wake);
12045
12385
  signal.addEventListener("abort", abort, { once: true });
12046
12386
  });
12047
12387
  }
@@ -12570,10 +12910,10 @@ var LoopbackWebSocket = class {
12570
12910
  this.messages = {
12571
12911
  [Symbol.asyncIterator]: async function* () {
12572
12912
  for (; ; ) {
12573
- const next2 = queue.shift();
12574
- if (next2 !== void 0) {
12575
- taken(next2);
12576
- yield next2;
12913
+ const next3 = queue.shift();
12914
+ if (next3 !== void 0) {
12915
+ taken(next3);
12916
+ yield next3;
12577
12917
  continue;
12578
12918
  }
12579
12919
  if (ended) return;
@@ -12678,7 +13018,7 @@ function tlv(tag, ...contents2) {
12678
13018
  return concat4([Uint8Array.of(tag), length(body.length), body]);
12679
13019
  }
12680
13020
  var seq = (...parts2) => tlv(48, ...parts2);
12681
- var set = (...parts2) => tlv(49, ...parts2);
13021
+ var set2 = (...parts2) => tlv(49, ...parts2);
12682
13022
  var octets = (bytes) => tlv(4, bytes);
12683
13023
  var bits = (bytes, unused = 0) => tlv(3, Uint8Array.of(unused), bytes);
12684
13024
  var TRUE = tlv(1, Uint8Array.of(255));
@@ -12711,8 +13051,8 @@ function time(date) {
12711
13051
  var ECDSA_SHA256 = seq(oid("1.2.840.10045.4.3.2"));
12712
13052
  function name(dn) {
12713
13053
  const rdns = [];
12714
- if (dn.organization) rdns.push(set(seq(oid("2.5.4.10"), utf8(dn.organization))));
12715
- rdns.push(set(seq(oid("2.5.4.3"), utf8(dn.commonName))));
13054
+ if (dn.organization) rdns.push(set2(seq(oid("2.5.4.10"), utf8(dn.organization))));
13055
+ rdns.push(set2(seq(oid("2.5.4.3"), utf8(dn.commonName))));
12716
13056
  return seq(...rdns);
12717
13057
  }
12718
13058
  function extension(id2, critical, value) {
@@ -13347,9 +13687,9 @@ var WsHandles = class {
13347
13687
  open = /* @__PURE__ */ new Map();
13348
13688
  next;
13349
13689
  local;
13350
- constructor(transport, next2, local) {
13690
+ constructor(transport, next3, local) {
13351
13691
  this.transport = transport;
13352
- this.next = next2;
13692
+ this.next = next3;
13353
13693
  this.local = local;
13354
13694
  }
13355
13695
  owns(handle) {
@@ -13411,9 +13751,9 @@ var WsHandles = class {
13411
13751
  }
13412
13752
  async recv(socket, entry) {
13413
13753
  try {
13414
- const next2 = await entry.messages.next();
13415
- if (!next2.done) {
13416
- return typeof next2.value === "string" ? { ok: true, kind: "json", json: { text: next2.value } } : { ok: true, kind: "bytes", bytes: next2.value };
13754
+ const next3 = await entry.messages.next();
13755
+ if (!next3.done) {
13756
+ return typeof next3.value === "string" ? { ok: true, kind: "json", json: { text: next3.value } } : { ok: true, kind: "bytes", bytes: next3.value };
13417
13757
  }
13418
13758
  const closed = await socket.closed;
13419
13759
  return {
@@ -13461,11 +13801,49 @@ var HTTP_OPS = [
13461
13801
  "net-open",
13462
13802
  "net-head",
13463
13803
  "net-read",
13804
+ "net-write",
13805
+ "net-end",
13464
13806
  "net-close",
13465
13807
  "net-traits",
13466
13808
  ...WS_OPS
13467
13809
  ];
13468
- var EMPTY = new Uint8Array(0);
13810
+ var Upload = class {
13811
+ queue = [];
13812
+ ended = false;
13813
+ wake;
13814
+ write(bytes) {
13815
+ if (this.ended) return Promise.resolve(false);
13816
+ return new Promise((taken) => {
13817
+ this.queue.push({ bytes, taken });
13818
+ this.wake?.();
13819
+ });
13820
+ }
13821
+ end() {
13822
+ this.ended = true;
13823
+ this.wake?.();
13824
+ }
13825
+ cancel() {
13826
+ this.ended = true;
13827
+ for (const { taken } of this.queue.splice(0)) taken(false);
13828
+ this.wake?.();
13829
+ }
13830
+ async *[Symbol.asyncIterator]() {
13831
+ for (; ; ) {
13832
+ const next3 = this.queue.shift();
13833
+ if (next3) {
13834
+ next3.taken(true);
13835
+ yield next3.bytes;
13836
+ continue;
13837
+ }
13838
+ if (this.ended) return;
13839
+ await new Promise((resolve2) => {
13840
+ this.wake = resolve2;
13841
+ });
13842
+ this.wake = void 0;
13843
+ }
13844
+ }
13845
+ };
13846
+ var EMPTY2 = new Uint8Array(0);
13469
13847
  function message2(e) {
13470
13848
  return e instanceof Error ? e.message : String(e);
13471
13849
  }
@@ -13495,6 +13873,8 @@ var HttpHandles = class {
13495
13873
  if (req.op === "net-open") return Promise.resolve(this.opened(req));
13496
13874
  if (req.op === "net-head") return this.head(req.handle);
13497
13875
  if (req.op === "net-read") return this.read(req.handle, req.max);
13876
+ if (req.op === "net-write") return this.write(req.handle, req.bytes);
13877
+ if (req.op === "net-end") return Promise.resolve(this.end(req.handle));
13498
13878
  if (req.op === "net-traits") return Promise.resolve(this.traits(req.url));
13499
13879
  return this.close(req.handle);
13500
13880
  }
@@ -13513,19 +13893,37 @@ var HttpHandles = class {
13513
13893
  return result;
13514
13894
  }
13515
13895
  opened(req) {
13896
+ if (req.stream && (this.local?.port(req.url) !== void 0 || !this.transport.traits.streamingBodies)) {
13897
+ return { ok: false, errno: "ENOTSUP", message: "this transport takes whole request bodies" };
13898
+ }
13516
13899
  return { ok: true, kind: "json", json: this.start(req).handle };
13517
13900
  }
13901
+ async write(handle, bytes) {
13902
+ const upload = this.open.get(handle)?.upload;
13903
+ if (!upload) return { ok: false, errno: "EBADF", message: `no upload ${handle}` };
13904
+ if (!await upload.write(bytes)) {
13905
+ return { ok: false, errno: "EPIPE", message: "the request no longer takes a body" };
13906
+ }
13907
+ return { ok: true, kind: "void" };
13908
+ }
13909
+ end(handle) {
13910
+ const upload = this.open.get(handle)?.upload;
13911
+ if (!upload) return { ok: false, errno: "EBADF", message: `no upload ${handle}` };
13912
+ upload.end();
13913
+ return { ok: true, kind: "void" };
13914
+ }
13518
13915
  start(req) {
13519
13916
  const handle = ++this.nextHandle;
13520
13917
  const abort = new AbortController();
13521
13918
  const entry = {
13522
13919
  abort,
13523
13920
  head: Promise.resolve({ ok: true, kind: "void" }),
13524
- body: once(EMPTY),
13525
- left: EMPTY,
13921
+ body: once(EMPTY2),
13922
+ left: EMPTY2,
13526
13923
  done: false,
13527
13924
  reading: Promise.resolve(),
13528
- cancel: async () => void 0
13925
+ cancel: async () => void 0,
13926
+ ...req.stream ? { upload: new Upload() } : {}
13529
13927
  };
13530
13928
  this.open.set(handle, entry);
13531
13929
  entry.head = this.respond(handle, req, entry);
@@ -13539,7 +13937,7 @@ var HttpHandles = class {
13539
13937
  url: target,
13540
13938
  method: req.method,
13541
13939
  headers: req.headers,
13542
- ...req.body ? { body: req.body } : {},
13940
+ ...entry.upload ? { bodyStream: entry.upload } : req.body ? { body: req.body } : {},
13543
13941
  signal: entry.abort.signal
13544
13942
  };
13545
13943
  const response = port === void 0 ? await this.transport.fetch(request, this.owner) : await this.local.fetch(request, port);
@@ -13550,6 +13948,7 @@ var HttpHandles = class {
13550
13948
  const head = this.headOf(handle, shown, response);
13551
13949
  return response.redirected ? { ...head, json: { ...head.json, redirected: true } } : head;
13552
13950
  } catch (e) {
13951
+ entry.upload?.cancel();
13553
13952
  const text = message2(e);
13554
13953
  if (port !== void 0) return { ok: false, errno: codeOf2(e), message: text };
13555
13954
  const status = e.status;
@@ -13586,9 +13985,9 @@ var HttpHandles = class {
13586
13985
  async take(entry, max) {
13587
13986
  if (entry.left.length === 0 && !entry.done) {
13588
13987
  try {
13589
- const next2 = await entry.body.next();
13590
- if (next2.done) entry.done = true;
13591
- else entry.left = next2.value;
13988
+ const next3 = await entry.body.next();
13989
+ if (next3.done) entry.done = true;
13990
+ else entry.left = next3.value;
13592
13991
  } catch (e) {
13593
13992
  entry.done = true;
13594
13993
  const timedOut = e?.code === "ETIMEDOUT";
@@ -13607,6 +14006,7 @@ var HttpHandles = class {
13607
14006
  const entry = this.open.get(handle);
13608
14007
  if (!entry) return { ok: false, errno: "EBADF", message: `no request ${handle}` };
13609
14008
  this.open.delete(handle);
14009
+ entry.upload?.cancel();
13610
14010
  entry.abort.abort();
13611
14011
  await entry.cancel().catch(() => void 0);
13612
14012
  return { ok: true, kind: "void" };
@@ -13961,12 +14361,12 @@ var KernelTty = class {
13961
14361
  const chunks2 = [];
13962
14362
  let n = 0;
13963
14363
  while (this.readable.length > 0 && n < max) {
13964
- const next2 = this.readable[0];
13965
- if (next2 === null || next2 === void 0) break;
13966
- const take = next2.subarray(0, max - n);
14364
+ const next3 = this.readable[0];
14365
+ if (next3 === null || next3 === void 0) break;
14366
+ const take = next3.subarray(0, max - n);
13967
14367
  chunks2.push(take);
13968
14368
  n += take.length;
13969
- if (take.length < next2.length) this.readable[0] = next2.subarray(take.length);
14369
+ if (take.length < next3.length) this.readable[0] = next3.subarray(take.length);
13970
14370
  else this.readable.shift();
13971
14371
  if (this.canonical) break;
13972
14372
  }
@@ -14063,11 +14463,11 @@ var PtyPair = class {
14063
14463
  const chunks2 = [];
14064
14464
  let n = 0;
14065
14465
  while (this.queue.length > 0 && n < max - status) {
14066
- const next2 = this.queue[0];
14067
- const take = next2.subarray(0, max - status - n);
14466
+ const next3 = this.queue[0];
14467
+ const take = next3.subarray(0, max - status - n);
14068
14468
  chunks2.push(take);
14069
14469
  n += take.length;
14070
- if (take.length < next2.length) this.queue[0] = next2.subarray(take.length);
14470
+ if (take.length < next3.length) this.queue[0] = next3.subarray(take.length);
14071
14471
  else this.queue.shift();
14072
14472
  }
14073
14473
  const out = new Uint8Array(status + n);
@@ -14387,8 +14787,8 @@ var Semaphore = class {
14387
14787
  this.mode = mode;
14388
14788
  }
14389
14789
  post() {
14390
- const next2 = this.waiters.shift();
14391
- if (next2) next2.grant();
14790
+ const next3 = this.waiters.shift();
14791
+ if (next3) next3.grant();
14392
14792
  else if (this.value >= SEM_VALUE_MAX) throw new KernelError("EOVERFLOW");
14393
14793
  else this.value++;
14394
14794
  }
@@ -14816,9 +15216,9 @@ var VfsNode = class {
14816
15216
  if (dirty && contents2 !== void 0) this.markDirty();
14817
15217
  }
14818
15218
  serial(op) {
14819
- const next2 = this.queue.then(op);
14820
- this.queue = next2.catch(() => void 0);
14821
- return next2;
15219
+ const next3 = this.queue.then(op);
15220
+ this.queue = next3.catch(() => void 0);
15221
+ return next3;
14822
15222
  }
14823
15223
  revoke() {
14824
15224
  this.revoked = true;
@@ -15240,9 +15640,9 @@ var VfsNodes = class {
15240
15640
  }
15241
15641
  for (const [p] of moved2) this.byPath.delete(p);
15242
15642
  for (const [p, node] of moved2) {
15243
- const next2 = to + p.slice(from.length);
15244
- if (node.path === p) node.renamedTo(next2);
15245
- this.byPath.set(next2, node);
15643
+ const next3 = to + p.slice(from.length);
15644
+ if (node.path === p) node.renamedTo(next3);
15645
+ this.byPath.set(next3, node);
15246
15646
  }
15247
15647
  }
15248
15648
  };
@@ -15617,6 +16017,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
15617
16017
  "tty-pgrp-get",
15618
16018
  "tty-pgrp-set",
15619
16019
  "sig-mask",
16020
+ "sig-waiting",
15620
16021
  "sig-pause",
15621
16022
  ...SOCKET_OPS,
15622
16023
  ...EPOLL_OPS,
@@ -15730,16 +16131,8 @@ var WasmProcess = class {
15730
16131
  if (sig === SIG.STOP) return this.stop(sig);
15731
16132
  const bit = sigbit(sig);
15732
16133
  if (this.ignores(bit)) return "ignore";
15733
- if (((this.options.blockedBits?.() ?? 0) & bit) !== 0) {
15734
- const tid = this.options.unblockedThread?.(sig);
15735
- if (tid === void 0) {
15736
- this.options.onPending?.(sig);
15737
- return "deliver";
15738
- }
15739
- if (this.caught & bit) {
15740
- this.options.threadKill?.(tid, sig);
15741
- return "deliver";
15742
- }
16134
+ if (((this.options.blockedBits?.() ?? 0) & bit) !== 0 && this.routeBlocked(sig, bit)) {
16135
+ return "deliver";
15743
16136
  }
15744
16137
  if (!(this.caught & bit)) {
15745
16138
  const action = defaultAction(sig);
@@ -15756,6 +16149,17 @@ var WasmProcess = class {
15756
16149
  blocked2.abort();
15757
16150
  return "deliver";
15758
16151
  }
16152
+ routeBlocked(sig, bit) {
16153
+ const waiter = this.waiterFor(bit);
16154
+ const tid = waiter ?? this.options.unblockedThread?.(sig);
16155
+ if (tid === void 0 || tid === 1) {
16156
+ this.options.onPending?.(sig);
16157
+ return true;
16158
+ }
16159
+ if (waiter === void 0 && !(this.caught & bit)) return false;
16160
+ this.options.threadKill?.(tid, sig);
16161
+ return true;
16162
+ }
15759
16163
  async spawn(req) {
15760
16164
  const { file, argv, argv0, env, cwd, chdir, stdio, inherit: inherit2, exec, pgid, session, deathSignal } = req;
15761
16165
  if (deathSignal !== void 0 && (exec || !isSignal(deathSignal))) {
@@ -15836,6 +16240,16 @@ var WasmProcess = class {
15836
16240
  }
15837
16241
  blocks = /* @__PURE__ */ new WeakMap();
15838
16242
  sizesRead = /* @__PURE__ */ new WeakMap();
16243
+ sigwaiters = /* @__PURE__ */ new Map();
16244
+ setSigwaiter(tid, set3) {
16245
+ if (set3 === 0) this.sigwaiters.delete(tid);
16246
+ else this.sigwaiters.set(tid, set3);
16247
+ }
16248
+ waiterFor(bit) {
16249
+ if (((this.sigwaiters.get(1) ?? 0) & bit) !== 0) return 1;
16250
+ for (const [tid, set3] of this.sigwaiters) if (set3 & bit) return tid;
16251
+ return void 0;
16252
+ }
15839
16253
  async syscall(req, cancelled, block) {
15840
16254
  this.options.onSyscall?.(req);
15841
16255
  const started = performance.now();
@@ -16092,18 +16506,18 @@ var WasmProcess = class {
16092
16506
  }
16093
16507
  if (this.writesAt(req) && this.options.readonlyAt?.(path)) throw new KernelError("EROFS");
16094
16508
  const open = { ...req, path };
16095
- const plain = this.plainMode(req.mode);
16509
+ const plain2 = this.plainMode(req.mode);
16096
16510
  if (req.exclusive) {
16097
16511
  await nodes.createExclusive(path, this.newOwner(req.mode));
16098
- if (plain !== void 0) await fs.chmod?.(path, plain);
16512
+ if (plain2 !== void 0) await fs.chmod?.(path, plain2);
16099
16513
  this.fds.installAt(fd, this.openVfsFile(open, void 0, fs));
16100
16514
  } else if (req.create) {
16101
16515
  await nodes.onEntry(path, async () => {
16102
- const marks = this.options.owners || plain !== void 0;
16516
+ const marks = this.options.owners || plain2 !== void 0;
16103
16517
  const fresh2 = marks && !await present2(fs, path, true);
16104
16518
  this.fds.installAt(fd, this.openVfsFile(open, await nodes.identify(path), fs));
16105
16519
  await this.fds.get(fd).file.stat?.();
16106
- if (fresh2 && plain !== void 0) await fs.chmod?.(path, plain);
16520
+ if (fresh2 && plain2 !== void 0) await fs.chmod?.(path, plain2);
16107
16521
  else if (fresh2) {
16108
16522
  await fs.chown?.(path, { ...this.newOwner(req.mode), kind: "new" });
16109
16523
  }
@@ -16744,6 +17158,9 @@ var WasmProcess = class {
16744
17158
  case "dl-unlock":
16745
17159
  this.unlockDl(req.owner);
16746
17160
  return { ok: true, kind: "void" };
17161
+ case "sig-waiting":
17162
+ this.setSigwaiter(req.tid, req.set);
17163
+ return { ok: true, kind: "void" };
16747
17164
  case "sig-mask":
16748
17165
  this.caught = req.caught;
16749
17166
  this.ignored = req.ignored;
@@ -16811,8 +17228,8 @@ var WasmProcess = class {
16811
17228
  };
16812
17229
  withDl(state) {
16813
17230
  if (this.dlLog.length === 0) return state;
16814
- const { next: next2, handle, free, live } = this.closures;
16815
- const dl = { log: [...this.dlLog], next: next2, handle, free: [...free], live: [...live] };
17231
+ const { next: next3, handle, free, live } = this.closures;
17232
+ const dl = { log: [...this.dlLog], next: next3, handle, free: [...free], live: [...live] };
16816
17233
  return { ...state, dl };
16817
17234
  }
16818
17235
  seedDl(dl) {
@@ -16823,8 +17240,8 @@ var WasmProcess = class {
16823
17240
  this.closures.free.push(...dl.free);
16824
17241
  for (const index of dl.live) this.closures.live.add(index);
16825
17242
  }
16826
- allocateClosure(floor) {
16827
- const index = this.closures.free.pop() ?? Math.max(floor, this.closures.next);
17243
+ allocateClosure(floor2) {
17244
+ const index = this.closures.free.pop() ?? Math.max(floor2, this.closures.next);
16828
17245
  this.closures.next = Math.max(this.closures.next, index + 1);
16829
17246
  this.closures.live.add(index);
16830
17247
  this.dlLog.push({ kind: "closure", index });
@@ -16876,8 +17293,8 @@ var WasmProcess = class {
16876
17293
  wakeDl() {
16877
17294
  for (const waiter of [...this.dlLock.waiters]) waiter.wake(false);
16878
17295
  }
16879
- reserveSlots(floor, size) {
16880
- const base = Math.max(floor, this.closures.next);
17296
+ reserveSlots(floor2, size) {
17297
+ const base = Math.max(floor2, this.closures.next);
16881
17298
  this.closures.next = base + size;
16882
17299
  return base;
16883
17300
  }
@@ -16934,6 +17351,7 @@ var WASM_MAX_THREADS = 256;
16934
17351
  // src/kernel/host.ts
16935
17352
  var CRASHED = 70;
16936
17353
  var KILL_GRACE_MS = 2e3;
17354
+ var KILL_HARD_MS = 5e3;
16937
17355
  var descIds = /* @__PURE__ */ new WeakMap();
16938
17356
  var nextDescId = 1;
16939
17357
  function descId(file) {
@@ -16960,16 +17378,21 @@ function inheritedFds(fds) {
16960
17378
  var Dying = class {
16961
17379
  ending;
16962
17380
  timer;
17381
+ hard;
16963
17382
  busy = 0;
16964
17383
  finish;
16965
17384
  start(code, sig, header4, process2, finish) {
16966
17385
  if (this.ending) return;
16967
17386
  this.ending = { code, sig };
16968
17387
  this.finish = finish;
17388
+ this.hard = setTimeout(finish, KILL_HARD_MS);
16969
17389
  this.arm();
16970
17390
  Atomics.store(header4, SAB_I_KILLED, code);
16971
17391
  process2.die();
16972
17392
  }
17393
+ serve(req, work) {
17394
+ return this.ending && isWasmSyscall(req) ? work() : this.serving(work);
17395
+ }
16973
17396
  async serving(work) {
16974
17397
  this.busy++;
16975
17398
  clearTimeout(this.timer);
@@ -16986,6 +17409,7 @@ var Dying = class {
16986
17409
  }
16987
17410
  clear() {
16988
17411
  clearTimeout(this.timer);
17412
+ clearTimeout(this.hard);
16989
17413
  }
16990
17414
  status(reported2) {
16991
17415
  if (this.ending) return [this.ending.code, this.ending.sig];
@@ -16997,8 +17421,8 @@ function killThread(thread, caught, sig) {
16997
17421
  const held = (Atomics.load(thread.header, SAB_I_BLOCKED) & sigbit(sig)) !== 0;
16998
17422
  if (!held && (caught & sigbit(sig)) === 0) return false;
16999
17423
  Atomics.or(thread.header, SAB_I_SIGNALS, sigbit(sig));
17000
- if (held) return true;
17001
17424
  Atomics.notify(thread.header, SAB_I_SIGNALS);
17425
+ if (held) return true;
17002
17426
  const blocked2 = thread.interrupt;
17003
17427
  thread.interrupt = new AbortController();
17004
17428
  blocked2.abort();
@@ -17094,7 +17518,7 @@ function inherited(opts) {
17094
17518
  ...opts.cred ? { cred: opts.cred } : {}
17095
17519
  };
17096
17520
  }
17097
- function holdingToken(opts, holds, caller) {
17521
+ function holdingToken(opts, holds2, caller) {
17098
17522
  return mintSyncFsToken({
17099
17523
  ...opts.owners ? caller : { umask: caller.umask },
17100
17524
  ...opts.dac ? { dac: opts.dac, pid: opts.pid, created: caller.created } : {},
@@ -17105,13 +17529,13 @@ function holdingToken(opts, holds, caller) {
17105
17529
  noLinks: opts.noLinks,
17106
17530
  cwd: opts.cwd,
17107
17531
  ...opts.statfs ? { statfs: opts.statfs } : {},
17108
- hold: (path, on, open, real, handle) => holds.hold(path, on, open, real, handle),
17109
- keptFor: (handle) => holds.keptFor(handle),
17110
- unlinked: (path) => holds.keptAt(path),
17111
- gate: (path, op) => opts.unlinkGate && holds.holding(path) ? opts.unlinkGate.run(holds.keyOf(path), op) : op(),
17112
- own: (path, op) => holds.own(path, op),
17113
- revoked: (path) => holds.isRevoked(path),
17114
- renamed: (from, to) => holds.renamed(from, to)
17532
+ hold: (path, on, open, real, handle) => holds2.hold(path, on, open, real, handle),
17533
+ keptFor: (handle) => holds2.keptFor(handle),
17534
+ unlinked: (path) => holds2.keptAt(path),
17535
+ gate: (path, op) => opts.unlinkGate && holds2.holding(path) ? opts.unlinkGate.run(holds2.keyOf(path), op) : op(),
17536
+ own: (path, op) => holds2.own(path, op),
17537
+ revoked: (path) => holds2.isRevoked(path),
17538
+ renamed: (from, to) => holds2.renamed(from, to)
17115
17539
  });
17116
17540
  }
17117
17541
  function linksOf(opts) {
@@ -17185,6 +17609,9 @@ function threadInit(opts, program, sab, cred, thread, main) {
17185
17609
  signals: main
17186
17610
  };
17187
17611
  }
17612
+ function settleExit(exit, settle, code) {
17613
+ void exit.catch(() => void 0).then(() => settle(code & 255));
17614
+ }
17188
17615
  function spawnWasmProcess(opts) {
17189
17616
  const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
17190
17617
  const header4 = new Int32Array(sab, 0, SAB_HEADER_I32);
@@ -17211,19 +17638,20 @@ function spawnWasmProcess(opts) {
17211
17638
  )
17212
17639
  );
17213
17640
  publishStops(process2, header4);
17214
- const holds = new HeldPaths();
17215
- opts.held?.add(holds);
17216
- const token = holdingToken(opts, holds, {
17641
+ const holds2 = new HeldPaths();
17642
+ opts.held?.add(holds2);
17643
+ const token = holdingToken(opts, holds2, {
17217
17644
  cred: () => process2.cred,
17218
17645
  umask: () => process2.umask,
17219
17646
  created: created3,
17220
- holdsKept: async (path) => path.includes(`/${UNLINKED_DIR}/`) && (holds.keeps(path) || await process2.holds(path))
17647
+ holdsKept: async (path) => path.includes(`/${UNLINKED_DIR}/`) && (holds2.keeps(path) || await process2.holds(path))
17221
17648
  });
17222
- process2.keptPath = (path) => holds.keptAt(path)?.hidden;
17223
- process2.keptHandle = (handle2) => holds.keptFor(handle2)?.hidden;
17649
+ process2.keptPath = (path) => holds2.keptAt(path)?.hidden;
17650
+ process2.keptHandle = (handle2) => holds2.keptFor(handle2)?.hidden;
17224
17651
  const worker = opts.createWorker();
17225
17652
  const dying = new Dying();
17226
- const dispatch2 = (req, block) => dying.serving(
17653
+ const dispatch2 = (req, block) => dying.serve(
17654
+ req,
17227
17655
  () => isWasmSyscall(req) ? process2.syscall(req, void 0, block) : dispatchSyncFs(req)
17228
17656
  );
17229
17657
  const clocks = new ProcessClocks(sab, opts.program.abi !== "js", process2);
@@ -17246,12 +17674,9 @@ function spawnWasmProcess(opts) {
17246
17674
  responder.dispose();
17247
17675
  lane?.dispose();
17248
17676
  revokeSyncFsToken(token);
17249
- opts.held?.delete(holds);
17677
+ opts.held?.delete(holds2);
17250
17678
  worker.terminate();
17251
- void process2.exit().then(
17252
- () => settle(code),
17253
- () => settle(code)
17254
- );
17679
+ settleExit(process2.exit(), settle, code);
17255
17680
  };
17256
17681
  const exitNow = (code) => {
17257
17682
  queueMicrotask(() => finish(...dying.status(code)));
@@ -17295,7 +17720,7 @@ function spawnWasmProcess(opts) {
17295
17720
  const tsignals = threadSignalsOf(tsab);
17296
17721
  if (thread.blocked) storeBlocked(tsignals.header, thread.blocked);
17297
17722
  threadSignals.set(thread.tid, tsignals);
17298
- const tdispatch = (req, block) => dying.serving(() => threadCall(process2, req, threadCancel(tsignals), block));
17723
+ const tdispatch = (req, block) => dying.serve(req, () => threadCall(process2, req, threadCancel(tsignals), block));
17299
17724
  const tresponder = attachSyncSabResponder(tw, tsab, token, {
17300
17725
  dispatch: clocks.timed(clocks.thread(thread.tid, tsab), tdispatch)
17301
17726
  });
@@ -17765,10 +18190,10 @@ var Automaton = class {
17765
18190
  let node = 0;
17766
18191
  for (const byte of bytes) {
17767
18192
  const key = node * 256 + byte;
17768
- let next2 = this.edges.get(key);
17769
- if (next2 === void 0) {
17770
- next2 = this.depth.length;
17771
- this.edges.set(key, next2);
18193
+ let next3 = this.edges.get(key);
18194
+ if (next3 === void 0) {
18195
+ next3 = this.depth.length;
18196
+ this.edges.set(key, next3);
17772
18197
  this.fail.push(0);
17773
18198
  this.depth.push(this.depth[node] + 1);
17774
18199
  this.children.push(0);
@@ -17776,7 +18201,7 @@ var Automaton = class {
17776
18201
  this.out.push([]);
17777
18202
  this.dict.push(-1);
17778
18203
  }
17779
- node = next2;
18204
+ node = next3;
17780
18205
  }
17781
18206
  const id2 = this.lengths.length;
17782
18207
  this.lengths.push(bytes.length);
@@ -17812,8 +18237,8 @@ var Automaton = class {
17812
18237
  step(state, byte) {
17813
18238
  let current = state;
17814
18239
  for (; ; ) {
17815
- const next2 = this.edges.get(current * 256 + byte);
17816
- if (next2 !== void 0) return next2;
18240
+ const next3 = this.edges.get(current * 256 + byte);
18241
+ if (next3 !== void 0) return next3;
17817
18242
  if (current === 0) return 0;
17818
18243
  current = this.fail[current];
17819
18244
  }
@@ -17841,7 +18266,7 @@ var RANK = {
17841
18266
  };
17842
18267
  var CR2 = 13;
17843
18268
  var LF2 = 10;
17844
- var EMPTY2 = new Uint8Array(0);
18269
+ var EMPTY3 = new Uint8Array(0);
17845
18270
  function register(automaton, sources, ids, bytes, source) {
17846
18271
  const key = Array.from(bytes).join(",");
17847
18272
  let id2 = ids.get(key);
@@ -17967,7 +18392,7 @@ function pass(c, input, final) {
17967
18392
  const partials = [];
17968
18393
  scanMain(c, input, best, partials);
17969
18394
  scanWrapped(c, input, best, partials);
17970
- const holds = final ? [] : [...new Set(partials)].sort((a, b) => a - b);
18395
+ const holds2 = final ? [] : [...new Set(partials)].sort((a, b) => a - b);
17971
18396
  const starts = [...best.keys()].sort((a, b) => a - b);
17972
18397
  const parts2 = [];
17973
18398
  const hits = /* @__PURE__ */ new Map();
@@ -17977,16 +18402,16 @@ function pass(c, input, final) {
17977
18402
  let h = 0;
17978
18403
  for (; ; ) {
17979
18404
  while (s < starts.length && starts[s] < pos) s++;
17980
- while (h < holds.length && holds[h] < pos) h++;
17981
- const hold = h < holds.length ? holds[h] : Infinity;
17982
- const next2 = s < starts.length ? starts[s] : Infinity;
17983
- if (hold <= next2) {
18405
+ while (h < holds2.length && holds2[h] < pos) h++;
18406
+ const hold = h < holds2.length ? holds2[h] : Infinity;
18407
+ const next3 = s < starts.length ? starts[s] : Infinity;
18408
+ if (hold <= next3) {
17984
18409
  cut = Math.min(hold, input.length);
17985
18410
  break;
17986
18411
  }
17987
- const candidate = best.get(next2);
18412
+ const candidate = best.get(next3);
17988
18413
  parts2.push(
17989
- input.subarray(pos, next2),
18414
+ input.subarray(pos, next3),
17990
18415
  c.replacements[candidate.secret][candidate.form === "raw" ? 0 : 1]
17991
18416
  );
17992
18417
  count(c, hits, candidate);
@@ -18021,12 +18446,12 @@ function compile(secrets, options = {}) {
18021
18446
  return { text: decoder4.decode(bytes), hits };
18022
18447
  },
18023
18448
  stream() {
18024
- let pending = EMPTY2;
18449
+ let pending = EMPTY3;
18025
18450
  const hits = /* @__PURE__ */ new Map();
18026
18451
  const run2 = (final) => {
18027
18452
  if (c.secrets.length === 0 || pending.length === 0) {
18028
18453
  const out = pending;
18029
- pending = EMPTY2;
18454
+ pending = EMPTY3;
18030
18455
  return out;
18031
18456
  }
18032
18457
  const result = pass(c, pending, final);
@@ -18040,7 +18465,7 @@ function compile(secrets, options = {}) {
18040
18465
  return run2(false);
18041
18466
  },
18042
18467
  idle() {
18043
- return pending.length < FRAGMENT ? run2(true) : EMPTY2;
18468
+ return pending.length < FRAGMENT ? run2(true) : EMPTY3;
18044
18469
  },
18045
18470
  end() {
18046
18471
  return run2(true);
@@ -18082,7 +18507,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
18082
18507
  let timer;
18083
18508
  let failed3;
18084
18509
  const waiters = /* @__PURE__ */ new Set();
18085
- const quiet2 = () => !busy && pending === 0;
18510
+ const quiet3 = () => !busy && pending === 0;
18086
18511
  const wake = () => {
18087
18512
  for (const waiter of [...waiters]) waiter();
18088
18513
  };
@@ -18099,7 +18524,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
18099
18524
  if (failed3 === void 0) failed3 = err;
18100
18525
  }).finally(() => {
18101
18526
  pending -= 1;
18102
- if (quiet2()) wake();
18527
+ if (quiet3()) wake();
18103
18528
  });
18104
18529
  };
18105
18530
  const settling = (signal) => new Promise((resolve2, reject) => {
@@ -18117,7 +18542,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
18117
18542
  signal?.addEventListener("abort", stop, { once: true });
18118
18543
  });
18119
18544
  const settled = async () => {
18120
- while (!quiet2()) await settling();
18545
+ while (!quiet3()) await settling();
18121
18546
  };
18122
18547
  const changed = async (signal) => {
18123
18548
  const round = new AbortController();
@@ -18133,7 +18558,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
18133
18558
  };
18134
18559
  const turn = async (signal) => {
18135
18560
  for (let waited = false; ; waited = true) {
18136
- if (quiet2() && (pollFile(file).writable || !file.changed)) {
18561
+ if (quiet3() && (pollFile(file).writable || !file.changed)) {
18137
18562
  busy = true;
18138
18563
  return;
18139
18564
  }
@@ -18162,7 +18587,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
18162
18587
  ...bound(file, "stat"),
18163
18588
  poll: () => {
18164
18589
  const state = pollFile(file);
18165
- return quiet2() ? state : { ...state, writable: false };
18590
+ return quiet3() ? state : { ...state, writable: false };
18166
18591
  },
18167
18592
  changed,
18168
18593
  ...file.tty ? { tty: file.tty } : {},
@@ -18178,7 +18603,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
18178
18603
  await send(stream2.push(taken), signal);
18179
18604
  } finally {
18180
18605
  busy = false;
18181
- if (quiet2()) wake();
18606
+ if (quiet3()) wake();
18182
18607
  }
18183
18608
  timer = setTimeout(release, idleMs);
18184
18609
  return taken.length;
@@ -18279,15 +18704,15 @@ function isRecord(value) {
18279
18704
  return typeof value === "object" && value !== null && !Array.isArray(value);
18280
18705
  }
18281
18706
  function serialized(reply) {
18282
- let plain;
18707
+ let plain2;
18283
18708
  try {
18284
18709
  const text = JSON.stringify(reply);
18285
- plain = text === void 0 ? void 0 : JSON.parse(text);
18710
+ plain2 = text === void 0 ? void 0 : JSON.parse(text);
18286
18711
  } catch (err) {
18287
18712
  return JSON.stringify(errorReply("EIO", lineOf2(err)));
18288
18713
  }
18289
- if (!isRecord(plain)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
18290
- const { v: _, ...rest2 } = plain;
18714
+ if (!isRecord(plain2)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
18715
+ const { v: _, ...rest2 } = plain2;
18291
18716
  return JSON.stringify({ v: 1, ...rest2 });
18292
18717
  }
18293
18718
  function lineOf2(err) {
@@ -19306,22 +19731,22 @@ function keepWatching(loop, signal) {
19306
19731
  const stop = () => session2.abort();
19307
19732
  signal.addEventListener("abort", stop);
19308
19733
  let timer;
19309
- const quiet2 = () => {
19734
+ const quiet3 = () => {
19310
19735
  clearTimeout(timer);
19311
19736
  timer = setTimeout(stop, silenceMs);
19312
19737
  };
19313
19738
  let opened2 = false;
19314
19739
  try {
19315
19740
  const client = await loop.connect();
19316
- quiet2();
19741
+ quiet3();
19317
19742
  await client.watch(
19318
19743
  session2.signal,
19319
19744
  (event) => {
19320
- quiet2();
19745
+ quiet3();
19321
19746
  if (!event.ping) loop.event(event);
19322
19747
  },
19323
19748
  () => {
19324
- quiet2();
19749
+ quiet3();
19325
19750
  opened2 = true;
19326
19751
  up = true;
19327
19752
  loop.up(client);
@@ -19866,9 +20291,9 @@ function tmpfs() {
19866
20291
  let node = root;
19867
20292
  for (const name2 of parts2(path)) {
19868
20293
  if (node.kind !== "directory") throw fsError2("ENOTDIR", path);
19869
- const next2 = node.children.get(name2);
19870
- if (!next2) throw fsError2("ENOENT", path);
19871
- node = next2;
20294
+ const next3 = node.children.get(name2);
20295
+ if (!next3) throw fsError2("ENOENT", path);
20296
+ node = next3;
19872
20297
  }
19873
20298
  return node;
19874
20299
  }
@@ -20174,6 +20599,28 @@ function foreignImports(bytes) {
20174
20599
  return {};
20175
20600
  }
20176
20601
 
20602
+ // src/refused-command.ts
20603
+ var REFUSED_PATH = "/usr/lib/slicc/refused";
20604
+ var REFUSED_SOURCE = [
20605
+ "export default async function refused(ctx) {",
20606
+ " await ctx.write(2, ctx.argv[1] + '\\n').catch(() => undefined);",
20607
+ " return 126;",
20608
+ "}"
20609
+ ].join("\n");
20610
+ function refusing(command) {
20611
+ if (!command.refused) return command;
20612
+ return {
20613
+ name: command.name,
20614
+ abi: "js",
20615
+ glue: REFUSED_PATH,
20616
+ wasm: REFUSED_PATH,
20617
+ argv0: command.name,
20618
+ args: [`${command.name}: ${command.refused}`],
20619
+ refused: command.refused,
20620
+ shows: command.script ?? command.wasm
20621
+ };
20622
+ }
20623
+
20177
20624
  // src/sudo.ts
20178
20625
  var SUDOERS = "/etc/sudoers";
20179
20626
  var SUDOERS_D = "/etc/sudoers.d";
@@ -20201,13 +20648,13 @@ function splitWords(text) {
20201
20648
  while (piece.lastIndex < text.length) {
20202
20649
  const m = piece.exec(text);
20203
20650
  if (!m) return void 0;
20204
- const [, single, double, escaped, plain, space] = m;
20651
+ const [, single, double, escaped, plain2, space] = m;
20205
20652
  if (space !== void 0) {
20206
20653
  if (word !== void 0) words2.push(word);
20207
20654
  word = void 0;
20208
20655
  continue;
20209
20656
  }
20210
- word = (word ?? "") + (single ?? (double !== void 0 ? unescaped(double) : escaped ?? plain));
20657
+ word = (word ?? "") + (single ?? (double !== void 0 ? unescaped(double) : escaped ?? plain2));
20211
20658
  }
20212
20659
  if (word !== void 0) words2.push(word);
20213
20660
  return words2;
@@ -20239,7 +20686,7 @@ function parseRule(line) {
20239
20686
  if (!cmnd?.[0]?.startsWith("/")) return void 0;
20240
20687
  return { ...rule, cmnd };
20241
20688
  }
20242
- function flags(parsed2, arg, next2) {
20689
+ function flags(parsed2, arg, next3) {
20243
20690
  for (let j = 1; j < arg.length; j++) {
20244
20691
  const flag = arg[j];
20245
20692
  if (flag === "n") parsed2.nonInteractive = true;
@@ -20247,7 +20694,7 @@ function flags(parsed2, arg, next2) {
20247
20694
  else if (flag !== "u") return `sudo: invalid option -- '${flag}'
20248
20695
  ${USAGE}`;
20249
20696
  else {
20250
- const user = arg.slice(j + 1) || next2;
20697
+ const user = arg.slice(j + 1) || next3;
20251
20698
  if (!user) return `sudo: option requires an argument -- 'u'
20252
20699
  ${USAGE}`;
20253
20700
  parsed2.user = user;
@@ -20697,9 +21144,9 @@ function appendedRoots(given) {
20697
21144
  return [...roots];
20698
21145
  }
20699
21146
  function plainEnv(words2) {
20700
- const next2 = words2[1];
20701
- if (baseName2(words2[0] ?? "") !== "env" || next2 === void 0) return false;
20702
- return next2 === "-S" || !next2.startsWith("-") && !next2.includes("=");
21147
+ const next3 = words2[1];
21148
+ if (baseName2(words2[0] ?? "") !== "env" || next3 === void 0) return false;
21149
+ return next3 === "-S" || !next3.startsWith("-") && !next3.includes("=");
20703
21150
  }
20704
21151
  function shebangCommand(words2) {
20705
21152
  if (!plainEnv(words2)) {
@@ -20723,9 +21170,9 @@ function expandDefaults(defaults, env) {
20723
21170
  for (const [key, value] of Object.entries(defaults ?? {})) {
20724
21171
  let missing4 = false;
20725
21172
  const expanded = value.replace(ENV_REFERENCE, (_, name2) => {
20726
- const set2 = Object.hasOwn(env, name2) ? env[name2] : void 0;
20727
- if (set2 === void 0) missing4 = true;
20728
- return set2 ?? "";
21173
+ const set3 = Object.hasOwn(env, name2) ? env[name2] : void 0;
21174
+ if (set3 === void 0) missing4 = true;
21175
+ return set3 ?? "";
20729
21176
  });
20730
21177
  if (!missing4) out[key] = expanded;
20731
21178
  }
@@ -20950,7 +21397,7 @@ var Launcher = class {
20950
21397
  const holders = [this.held, this.openFiles];
20951
21398
  this.unlinked = new UnlinkedKeeper(
20952
21399
  fs,
20953
- { [Symbol.iterator]: () => holders.flatMap((set2) => [...set2]).values() },
21400
+ { [Symbol.iterator]: () => holders.flatMap((set3) => [...set3]).values() },
20954
21401
  (path) => this.mountRoot(path),
20955
21402
  {
20956
21403
  locks: webLocks(),
@@ -21035,11 +21482,21 @@ var Launcher = class {
21035
21482
  found = this.trustedAppended().then(async (appended2) => {
21036
21483
  const tiers = await this.tiers(scope, appended2);
21037
21484
  return scanCommands(this.scanned, tiers, tiers.length - appended2.length);
21038
- }).then((commands) => commands.set(SUDO_COMMAND.name, SUDO_COMMAND));
21485
+ }).then((commands) => this.refusals(commands).set(SUDO_COMMAND.name, SUDO_COMMAND));
21039
21486
  this.catalogs.set(scope, found);
21040
21487
  }
21041
21488
  return found;
21042
21489
  }
21490
+ refusals(commands) {
21491
+ for (const [name2, command] of commands) {
21492
+ if (!command.refused) continue;
21493
+ commands.set(name2, refusing(command));
21494
+ if (this.warned.has(command.refused)) continue;
21495
+ this.warned.add(command.refused);
21496
+ console.warn(`slicc-kernel: refusing the commands of ${command.refused}`);
21497
+ }
21498
+ return commands;
21499
+ }
21043
21500
  ownCommands(scope) {
21044
21501
  let found = this.ownCatalogs.get(scope);
21045
21502
  if (!found) {
@@ -21114,7 +21571,8 @@ var Launcher = class {
21114
21571
  );
21115
21572
  return {
21116
21573
  byUid: new Map(users.map((account, i) => [account.uid, homes[i]])),
21117
- byBin: new Map(homes.map((home) => [`${home}/bin`, home]))
21574
+ byBin: new Map(homes.map((home) => [`${home}/bin`, home])),
21575
+ owners: new Map(homes.map((home, i) => [home, credOf(users[i])]))
21118
21576
  };
21119
21577
  },
21120
21578
  () => ({ byUid: /* @__PURE__ */ new Map(), byBin: /* @__PURE__ */ new Map() })
@@ -21456,12 +21914,12 @@ var Launcher = class {
21456
21914
  return `${path}:${st.size}:${st.mtime.getTime()}`;
21457
21915
  }
21458
21916
  verified(path, caller, fs = this.base) {
21459
- const plain = () => fs.readFileBuffer(path);
21460
- return this.integrity ? this.integrity.read(path, caller, plain) : plain();
21917
+ const plain2 = () => fs.readFileBuffer(path);
21918
+ return this.integrity ? this.integrity.read(path, caller, plain2) : plain2();
21461
21919
  }
21462
21920
  keyed(path, caller, asked) {
21463
- const plain = async () => this.base.readFileBuffer(path);
21464
- return this.integrity ? this.integrity.readKeyed(path, caller, plain, asked) : plain().then((bytes) => ({ bytes }));
21921
+ const plain2 = async () => this.base.readFileBuffer(path);
21922
+ return this.integrity ? this.integrity.readKeyed(path, caller, plain2, asked) : plain2().then((bytes) => ({ bytes }));
21465
21923
  }
21466
21924
  cached(cache, key, load) {
21467
21925
  const hit = cache.get(key);
@@ -21532,6 +21990,9 @@ var Launcher = class {
21532
21990
  if (target.abi === "js" && target.wasm === SUDO_PATH) {
21533
21991
  return { abi: "js", glue: SUDO_SOURCE, path: SUDO_PATH };
21534
21992
  }
21993
+ if (target.abi === "js" && target.wasm === REFUSED_PATH) {
21994
+ return { abi: "js", glue: REFUSED_SOURCE, path: REFUSED_PATH };
21995
+ }
21535
21996
  const { asked } = target;
21536
21997
  if (target.abi === "js") {
21537
21998
  return { abi: "js", glue: await this.text(target.wasm, caller, asked), path: target.wasm };
@@ -21601,7 +22062,7 @@ var Launcher = class {
21601
22062
  });
21602
22063
  return {
21603
22064
  source: {
21604
- read: (path, plain) => integrity.readSource(path, caller(), plain),
22065
+ read: (path, plain2) => integrity.readSource(path, caller(), plain2),
21605
22066
  open: (path, real) => integrity.openSource(path, caller(), real)
21606
22067
  }
21607
22068
  };
@@ -22040,9 +22501,9 @@ var Launcher = class {
22040
22501
  const members = this.jobs.list();
22041
22502
  let image = pid;
22042
22503
  for (; ; ) {
22043
- const next2 = members.find((m) => m.execParent === image);
22044
- if (!next2) return image;
22045
- image = next2.pid;
22504
+ const next3 = members.find((m) => m.execParent === image);
22505
+ if (!next3) return image;
22506
+ image = next3.pid;
22046
22507
  }
22047
22508
  }
22048
22509
  credOf(pid) {
@@ -22329,7 +22790,7 @@ var Launcher = class {
22329
22790
  this.pnpmStale();
22330
22791
  if (!detach) return;
22331
22792
  for (const nodes of this.openFiles) nodes.revoke(at);
22332
- for (const holds of this.held) holds.revoke(at);
22793
+ for (const holds2 of this.held) holds2.revoke(at);
22333
22794
  }
22334
22795
  unmountAll() {
22335
22796
  this.booting.abort();
@@ -22475,7 +22936,7 @@ var Launcher = class {
22475
22936
  this.openFiles.add(nodes);
22476
22937
  const unlinked = new UnlinkedKeeper(
22477
22938
  fs,
22478
- { [Symbol.iterator]: () => [this.held, this.openFiles].flatMap((set2) => [...set2]).values() },
22939
+ { [Symbol.iterator]: () => [this.held, this.openFiles].flatMap((set3) => [...set3]).values() },
22479
22940
  (path) => this.mountRoot(path),
22480
22941
  {
22481
22942
  locks: webLocks(),
@@ -22503,11 +22964,32 @@ var Launcher = class {
22503
22964
  commandFs(root) {
22504
22965
  return withCommandDirs(
22505
22966
  root,
22506
- async () => new Set((await this.commands()).keys()),
22967
+ async () => this.commandNames(await this.commands()),
22507
22968
  (dir) => this.userCommandDir(dir),
22508
- this.owners
22969
+ this.owners,
22970
+ (path) => this.entryTarget(path)
22509
22971
  );
22510
22972
  }
22973
+ named = /* @__PURE__ */ new WeakMap();
22974
+ commandNames(commands) {
22975
+ let names = this.named.get(commands);
22976
+ if (!names) {
22977
+ names = new Set(commands.keys());
22978
+ this.named.set(commands, names);
22979
+ }
22980
+ return names;
22981
+ }
22982
+ async entryTarget(path) {
22983
+ const system = COMMAND2.exec(path)?.[1];
22984
+ const slash = path.lastIndexOf("/");
22985
+ const scopes = await this.userScopes();
22986
+ const scope = system === void 0 ? scopes.byBin.get(path.slice(0, slash)) : "";
22987
+ const name2 = system ?? path.slice(slash + 1);
22988
+ const command = scope === void 0 ? void 0 : (await this.commands(scope)).get(name2);
22989
+ const owner = scope ? scopes.owners?.get(scope) : void 0;
22990
+ const target = command && (command.shows ?? command.script ?? command.wasm);
22991
+ return target === void 0 ? void 0 : { path: target, ...owner ? { owner } : {} };
22992
+ }
22511
22993
  processChain(fs, nodes, unlinked) {
22512
22994
  nodes.changed = (path) => this.changes.publish(path);
22513
22995
  nodes.dirtied = (delta) => this.changes.dirtied(delta);
@@ -22634,11 +23116,11 @@ function ipv4Place(address) {
22634
23116
  return void 0;
22635
23117
  }
22636
23118
  function placeOf(address) {
22637
- const plain = address.replace(/^\[(.*)\]$/, "$1").toLowerCase();
22638
- const kind = isIP(plain);
22639
- if (kind === 4) return ipv4Place(plain);
23119
+ const plain2 = address.replace(/^\[(.*)\]$/, "$1").toLowerCase();
23120
+ const kind = isIP(plain2);
23121
+ if (kind === 4) return ipv4Place(plain2);
22640
23122
  if (kind !== 6) return void 0;
22641
- const words2 = hextets2(plain);
23123
+ const words2 = hextets2(plain2);
22642
23124
  const embedded2 = words2.slice(0, 5).every((w) => w === 0) && (words2[5] === 65535 || words2[5] === 0);
22643
23125
  if (embedded2 && (words2[5] === 65535 || words2[6] !== 0)) return ipv4Place(ipv4Of(words2));
22644
23126
  if (words2.slice(0, 7).every((w) => w === 0) && (words2[7] ?? 0) <= 1) return "loopback";
@@ -22687,10 +23169,10 @@ function connectRefusal(address, port, place) {
22687
23169
  return Object.assign(new Error(why), { status: 403, code: "EACCES" });
22688
23170
  }
22689
23171
  async function addressesOf(host, resolve2) {
22690
- const plain = host.replace(/^\[(.*)\]$/, "$1");
22691
- if (isIP(plain)) return [plain];
22692
- if (loopbackName2(plain)) return ["127.0.0.1"];
22693
- return resolve2(plain).catch(() => []);
23172
+ const plain2 = host.replace(/^\[(.*)\]$/, "$1");
23173
+ if (isIP(plain2)) return [plain2];
23174
+ if (loopbackName2(plain2)) return ["127.0.0.1"];
23175
+ return resolve2(plain2).catch(() => []);
22694
23176
  }
22695
23177
  async function checkDestination(target, policy, resolve2 = resolveHost) {
22696
23178
  const url = new URL(target);
@@ -22901,26 +23383,26 @@ var MemoryFile = class {
22901
23383
  return new File(this.data.blobs, this.name, { lastModified: this.lastModified });
22902
23384
  }
22903
23385
  async createWritable({ keepExistingData = false } = {}) {
22904
- const next2 = keepExistingData ? new Chunks([...this.data.blobs], this.data.size) : new Chunks();
23386
+ const next3 = keepExistingData ? new Chunks([...this.data.blobs], this.data.size) : new Chunks();
22905
23387
  let position = 0;
22906
23388
  const put = async (data) => {
22907
23389
  const bytes = await bytesOf(data);
22908
- await next2.write(position, bytes);
23390
+ await next3.write(position, bytes);
22909
23391
  position += bytes.length;
22910
23392
  };
22911
23393
  return {
22912
23394
  write: async (data) => {
22913
23395
  if (!isParams(data)) return put(data);
22914
- if (data.type === "truncate") return next2.truncate(data.size ?? 0);
23396
+ if (data.type === "truncate") return next3.truncate(data.size ?? 0);
22915
23397
  position = data.position ?? position;
22916
23398
  if (data.type === "write") await put(data.data);
22917
23399
  },
22918
23400
  seek: async (at) => {
22919
23401
  position = at;
22920
23402
  },
22921
- truncate: async (size) => next2.truncate(size),
23403
+ truncate: async (size) => next3.truncate(size),
22922
23404
  close: async () => {
22923
- this.data = next2;
23405
+ this.data = next3;
22924
23406
  this.lastModified = Date.now();
22925
23407
  },
22926
23408
  abort: async () => {
@@ -23118,12 +23600,17 @@ var RemoteTransport = class {
23118
23600
  waiting = /* @__PURE__ */ new Map();
23119
23601
  nextId = 0;
23120
23602
  sockets = /* @__PURE__ */ new Map();
23603
+ uploads = /* @__PURE__ */ new Map();
23121
23604
  failure;
23122
23605
  constructor(port, traits) {
23123
23606
  this.port = port;
23124
23607
  this.traits = traits;
23125
23608
  }
23126
23609
  receive(reply) {
23610
+ if (reply.net === "body-pull") {
23611
+ void this.pull(reply.nid);
23612
+ return;
23613
+ }
23127
23614
  const socket = this.sockets.get(reply.nid);
23128
23615
  if (socket && this.toSocket(reply, socket)) return;
23129
23616
  const waiter = this.waiting.get(reply.nid);
@@ -23142,8 +23629,35 @@ var RemoteTransport = class {
23142
23629
  } else return false;
23143
23630
  return true;
23144
23631
  }
23632
+ async pull(nid) {
23633
+ const upload = this.uploads.get(nid);
23634
+ if (!upload) {
23635
+ this.port.postMessage({ net: "body-error", nid, message: "the request body is gone" });
23636
+ return;
23637
+ }
23638
+ try {
23639
+ const next3 = await upload.next();
23640
+ if (next3.done) {
23641
+ this.uploads.delete(nid);
23642
+ this.port.postMessage({ net: "body-end", nid });
23643
+ } else this.port.postMessage({ net: "body-chunk", nid, bytes: next3.value });
23644
+ } catch (e) {
23645
+ this.uploads.delete(nid);
23646
+ this.port.postMessage({
23647
+ net: "body-error",
23648
+ nid,
23649
+ message: e instanceof Error ? e.message : String(e)
23650
+ });
23651
+ }
23652
+ }
23653
+ dropUpload(nid) {
23654
+ const upload = this.uploads.get(nid);
23655
+ this.uploads.delete(nid);
23656
+ void upload?.return?.().catch(() => void 0);
23657
+ }
23145
23658
  fail(error) {
23146
23659
  this.failure = error;
23660
+ for (const nid of [...this.uploads.keys()]) this.dropUpload(nid);
23147
23661
  for (const waiter of this.waiting.values()) waiter.reject(error);
23148
23662
  this.waiting.clear();
23149
23663
  for (const socket of this.sockets.values())
@@ -23170,14 +23684,17 @@ var RemoteTransport = class {
23170
23684
  let finished = false;
23171
23685
  const abort = () => {
23172
23686
  finished = true;
23687
+ this.dropUpload(nid);
23173
23688
  this.cancel(nid);
23174
23689
  };
23175
23690
  signal.addEventListener("abort", abort, { once: true });
23176
23691
  const finish = () => {
23692
+ this.dropUpload(nid);
23177
23693
  if (finished) return;
23178
23694
  finished = true;
23179
23695
  signal.removeEventListener("abort", abort);
23180
23696
  };
23697
+ if (request.bodyStream) this.uploads.set(nid, request.bodyStream[Symbol.asyncIterator]());
23181
23698
  let head;
23182
23699
  try {
23183
23700
  head = await this.ask({
@@ -23186,7 +23703,7 @@ var RemoteTransport = class {
23186
23703
  url: request.url,
23187
23704
  method: request.method,
23188
23705
  headers: request.headers,
23189
- ...request.body ? { body: request.body } : {}
23706
+ ...request.bodyStream ? { streamed: true } : request.body ? { body: request.body } : {}
23190
23707
  });
23191
23708
  } catch (e) {
23192
23709
  finish();
@@ -23455,11 +23972,11 @@ function stream(chunks2, socket, signal) {
23455
23972
  },
23456
23973
  async pull(controller) {
23457
23974
  try {
23458
- const next2 = await chunks2.next();
23459
- if (next2.done) {
23975
+ const next3 = await chunks2.next();
23976
+ if (next3.done) {
23460
23977
  controller.close();
23461
23978
  socket.close();
23462
- } else controller.enqueue(next2.value);
23979
+ } else controller.enqueue(next3.value);
23463
23980
  } catch (err) {
23464
23981
  controller.error(err);
23465
23982
  socket.close();
@@ -23816,9 +24333,9 @@ async function terminalOn(channel, argv, opts) {
23816
24333
  get onData() {
23817
24334
  return listener;
23818
24335
  },
23819
- set onData(next2) {
23820
- listener = next2;
23821
- if (next2) for (const bytes of backlog.splice(0)) next2(bytes);
24336
+ set onData(next3) {
24337
+ listener = next3;
24338
+ if (next3) for (const bytes of backlog.splice(0)) next3(bytes);
23822
24339
  },
23823
24340
  write: (data) => send({ action: "write", bytes: bytesOf2(data) }),
23824
24341
  resize: (cols, rows) => send({ action: "resize", cols, rows }),
@@ -23964,7 +24481,12 @@ function hostfsFetchOf(options) {
23964
24481
  };
23965
24482
  }
23966
24483
  function nodeTransport(options = {}) {
23967
- const transport = fetchTransport({ webSocket: true, webSocketHeaders: true, redirect: "manual" });
24484
+ const transport = fetchTransport({
24485
+ webSocket: true,
24486
+ webSocketHeaders: true,
24487
+ redirect: "manual",
24488
+ streamingBodies: true
24489
+ });
23968
24490
  const open = { ...transport, traits: { ...transport.traits, crossOrigin: "any" } };
23969
24491
  return diagnosing(guardedLoopback(open, options.hostLoopback ?? false));
23970
24492
  }
@@ -24110,9 +24632,9 @@ async function createNodeKernel(options = {}) {
24110
24632
  get onData() {
24111
24633
  return listener;
24112
24634
  },
24113
- set onData(next2) {
24114
- listener = next2;
24115
- if (next2) for (const bytes of backlog.splice(0)) next2(bytes);
24635
+ set onData(next3) {
24636
+ listener = next3;
24637
+ if (next3) for (const bytes of backlog.splice(0)) next3(bytes);
24116
24638
  },
24117
24639
  write: (data) => session.write(typeof data === "string" ? new TextEncoder().encode(data) : data),
24118
24640
  resize: (cols, rows) => session.resize(cols, rows),