@ai-ecoverse/slicc-kernel 1.103.4 → 1.106.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +57 -16
  2. package/dist/driver-worker.js +36 -1
  3. package/dist/driver-worker.js.map +2 -2
  4. package/dist/index.js +89 -5
  5. package/dist/index.js.map +2 -2
  6. package/dist/kernel-worker.js +798 -295
  7. package/dist/kernel-worker.js.map +4 -4
  8. package/dist/meta.js.map +2 -2
  9. package/dist/node-driver-worker.js +36 -1
  10. package/dist/node-driver-worker.js.map +2 -2
  11. package/dist/node-process-worker.js +489 -234
  12. package/dist/node-process-worker.js.map +4 -4
  13. package/dist/node.js +846 -315
  14. package/dist/node.js.map +4 -4
  15. package/dist/process-worker.js +426 -171
  16. package/dist/process-worker.js.map +4 -4
  17. package/dist/types/commands.d.ts +6 -1
  18. package/dist/types/fs/command-stat.d.ts +3 -0
  19. package/dist/types/fs/commands.d.ts +7 -1
  20. package/dist/types/fs/engines.d.ts +5 -0
  21. package/dist/types/fs/types.d.ts +1 -0
  22. package/dist/types/kernel/host.d.ts +1 -0
  23. package/dist/types/kernel/net/http-syscalls.d.ts +10 -0
  24. package/dist/types/kernel/net/http1.d.ts +1 -0
  25. package/dist/types/kernel/net/remote-transport.d.ts +18 -0
  26. package/dist/types/kernel/net/transport.d.ts +2 -0
  27. package/dist/types/kernel/process.d.ts +8 -0
  28. package/dist/types/launcher.d.ts +4 -0
  29. package/dist/types/process/js/js-kernel.d.ts +2 -1
  30. package/dist/types/process/process-signals.d.ts +3 -0
  31. package/dist/types/process/wasi/wasi-cred.d.ts +11 -0
  32. package/dist/types/process/wasi/wasi-files.d.ts +1 -0
  33. package/dist/types/process/wasi/wasi-host.d.ts +9 -0
  34. package/dist/types/process/wasi/wasi-sigmask.d.ts +7 -1
  35. package/dist/types/process/wasi/wasix-epoll.d.ts +3 -0
  36. package/dist/types/refused-command.d.ts +4 -0
  37. package/dist/types/transport.d.ts +1 -0
  38. package/package.json +12 -12
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.3" : "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;
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);
7468
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
  }
@@ -12342,9 +12682,10 @@ var MAX_UNREAD = 16 * 1024 * 1024;
12342
12682
  function errno(code, message3) {
12343
12683
  return Object.assign(new Error(`${code}: ${message3}`), { code });
12344
12684
  }
12345
- function requestHead(method, url, headers, extra) {
12685
+ function requestHead(method, url, headers, extra, first = []) {
12346
12686
  if (!TOKEN3.test(method)) throw errno("EINVAL", `method ${method}`);
12347
- const lines2 = [`${method} ${url.pathname}${url.search} HTTP/1.1`, `Host: ${url.host}`];
12687
+ const lines2 = [`${method} ${url.pathname}${url.search} HTTP/1.1`, `host: ${url.host}`];
12688
+ for (const [name2, value] of first) lines2.push(`${name2}: ${value}`);
12348
12689
  for (const [name2, value] of headers) {
12349
12690
  if (OWN_HEADERS.has(name2.toLowerCase())) continue;
12350
12691
  if (!TOKEN3.test(name2) || !SAFE_VALUE.test(value)) throw errno("EINVAL", `header ${name2}`);
@@ -12459,8 +12800,8 @@ var KernelLoopback = class {
12459
12800
  async fetch(req, port) {
12460
12801
  const url = new URL(req.url);
12461
12802
  const body = req.body ?? (/^(POST|PUT|PATCH)$/i.test(req.method) ? new Uint8Array(0) : void 0);
12462
- const length2 = body ? [["Content-Length", String(body.length)]] : [];
12463
- const head = requestHead(req.method, url, req.headers, [...length2, ["Connection", "close"]]);
12803
+ const length2 = body ? [["content-length", String(body.length)]] : [];
12804
+ const head = requestHead(req.method, url, req.headers, length2, [["connection", "close"]]);
12464
12805
  const socket = await this.connect(url, port, req.signal);
12465
12806
  try {
12466
12807
  await writeAll2(socket, body ? concat([head, body]) : head, req.signal);
@@ -12553,7 +12894,7 @@ var LoopbackWebSocket = class {
12553
12894
  const queue = [];
12554
12895
  let wake;
12555
12896
  let ended = false;
12556
- void this.pump(new WsReader(incoming, void 0, true, true), (message3) => {
12897
+ void this.pump(incoming, (message3) => {
12557
12898
  queue.push(message3);
12558
12899
  this.unread += message3.length;
12559
12900
  wake?.();
@@ -12570,10 +12911,10 @@ var LoopbackWebSocket = class {
12570
12911
  this.messages = {
12571
12912
  [Symbol.asyncIterator]: async function* () {
12572
12913
  for (; ; ) {
12573
- const next2 = queue.shift();
12574
- if (next2 !== void 0) {
12575
- taken(next2);
12576
- yield next2;
12914
+ const next3 = queue.shift();
12915
+ if (next3 !== void 0) {
12916
+ taken(next3);
12917
+ yield next3;
12577
12918
  continue;
12578
12919
  }
12579
12920
  if (ended) return;
@@ -12608,7 +12949,8 @@ var LoopbackWebSocket = class {
12608
12949
  this.pending -= bytes.length;
12609
12950
  })();
12610
12951
  }
12611
- async pump(reader, deliver) {
12952
+ async pump(incoming, deliver) {
12953
+ const reader = new WsReader(incoming, void 0, true, true);
12612
12954
  let close = { code: 1006, reason: "", wasClean: false };
12613
12955
  try {
12614
12956
  for (; ; ) {
@@ -12630,11 +12972,18 @@ var LoopbackWebSocket = class {
12630
12972
  } finally {
12631
12973
  const late = setTimeout(() => this.stop.abort(), CLOSE_WAIT_MS3);
12632
12974
  await this.writes;
12975
+ if (close.wasClean) await this.serverEnd(incoming);
12633
12976
  clearTimeout(late);
12634
12977
  this.socket.close();
12635
12978
  this.settle(close);
12636
12979
  }
12637
12980
  }
12981
+ async serverEnd(incoming) {
12982
+ try {
12983
+ while ((await incoming.some(64 * 1024, this.stop.signal)).length > 0) ;
12984
+ } catch {
12985
+ }
12986
+ }
12638
12987
  sendClose(code, reason) {
12639
12988
  if (this.sentClose) return;
12640
12989
  this.sentClose = true;
@@ -12678,7 +13027,7 @@ function tlv(tag, ...contents2) {
12678
13027
  return concat4([Uint8Array.of(tag), length(body.length), body]);
12679
13028
  }
12680
13029
  var seq = (...parts2) => tlv(48, ...parts2);
12681
- var set = (...parts2) => tlv(49, ...parts2);
13030
+ var set2 = (...parts2) => tlv(49, ...parts2);
12682
13031
  var octets = (bytes) => tlv(4, bytes);
12683
13032
  var bits = (bytes, unused = 0) => tlv(3, Uint8Array.of(unused), bytes);
12684
13033
  var TRUE = tlv(1, Uint8Array.of(255));
@@ -12711,8 +13060,8 @@ function time(date) {
12711
13060
  var ECDSA_SHA256 = seq(oid("1.2.840.10045.4.3.2"));
12712
13061
  function name(dn) {
12713
13062
  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))));
13063
+ if (dn.organization) rdns.push(set2(seq(oid("2.5.4.10"), utf8(dn.organization))));
13064
+ rdns.push(set2(seq(oid("2.5.4.3"), utf8(dn.commonName))));
12716
13065
  return seq(...rdns);
12717
13066
  }
12718
13067
  function extension(id2, critical, value) {
@@ -13347,9 +13696,9 @@ var WsHandles = class {
13347
13696
  open = /* @__PURE__ */ new Map();
13348
13697
  next;
13349
13698
  local;
13350
- constructor(transport, next2, local) {
13699
+ constructor(transport, next3, local) {
13351
13700
  this.transport = transport;
13352
- this.next = next2;
13701
+ this.next = next3;
13353
13702
  this.local = local;
13354
13703
  }
13355
13704
  owns(handle) {
@@ -13411,9 +13760,9 @@ var WsHandles = class {
13411
13760
  }
13412
13761
  async recv(socket, entry) {
13413
13762
  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 };
13763
+ const next3 = await entry.messages.next();
13764
+ if (!next3.done) {
13765
+ return typeof next3.value === "string" ? { ok: true, kind: "json", json: { text: next3.value } } : { ok: true, kind: "bytes", bytes: next3.value };
13417
13766
  }
13418
13767
  const closed = await socket.closed;
13419
13768
  return {
@@ -13461,11 +13810,49 @@ var HTTP_OPS = [
13461
13810
  "net-open",
13462
13811
  "net-head",
13463
13812
  "net-read",
13813
+ "net-write",
13814
+ "net-end",
13464
13815
  "net-close",
13465
13816
  "net-traits",
13466
13817
  ...WS_OPS
13467
13818
  ];
13468
- var EMPTY = new Uint8Array(0);
13819
+ var Upload = class {
13820
+ queue = [];
13821
+ ended = false;
13822
+ wake;
13823
+ write(bytes) {
13824
+ if (this.ended) return Promise.resolve(false);
13825
+ return new Promise((taken) => {
13826
+ this.queue.push({ bytes, taken });
13827
+ this.wake?.();
13828
+ });
13829
+ }
13830
+ end() {
13831
+ this.ended = true;
13832
+ this.wake?.();
13833
+ }
13834
+ cancel() {
13835
+ this.ended = true;
13836
+ for (const { taken } of this.queue.splice(0)) taken(false);
13837
+ this.wake?.();
13838
+ }
13839
+ async *[Symbol.asyncIterator]() {
13840
+ for (; ; ) {
13841
+ const next3 = this.queue.shift();
13842
+ if (next3) {
13843
+ next3.taken(true);
13844
+ yield next3.bytes;
13845
+ continue;
13846
+ }
13847
+ if (this.ended) return;
13848
+ await new Promise((resolve2) => {
13849
+ this.wake = resolve2;
13850
+ });
13851
+ this.wake = void 0;
13852
+ }
13853
+ }
13854
+ };
13855
+ var EMPTY2 = new Uint8Array(0);
13469
13856
  function message2(e) {
13470
13857
  return e instanceof Error ? e.message : String(e);
13471
13858
  }
@@ -13495,6 +13882,8 @@ var HttpHandles = class {
13495
13882
  if (req.op === "net-open") return Promise.resolve(this.opened(req));
13496
13883
  if (req.op === "net-head") return this.head(req.handle);
13497
13884
  if (req.op === "net-read") return this.read(req.handle, req.max);
13885
+ if (req.op === "net-write") return this.write(req.handle, req.bytes);
13886
+ if (req.op === "net-end") return Promise.resolve(this.end(req.handle));
13498
13887
  if (req.op === "net-traits") return Promise.resolve(this.traits(req.url));
13499
13888
  return this.close(req.handle);
13500
13889
  }
@@ -13513,19 +13902,37 @@ var HttpHandles = class {
13513
13902
  return result;
13514
13903
  }
13515
13904
  opened(req) {
13905
+ if (req.stream && (this.local?.port(req.url) !== void 0 || !this.transport.traits.streamingBodies)) {
13906
+ return { ok: false, errno: "ENOTSUP", message: "this transport takes whole request bodies" };
13907
+ }
13516
13908
  return { ok: true, kind: "json", json: this.start(req).handle };
13517
13909
  }
13910
+ async write(handle, bytes) {
13911
+ const upload = this.open.get(handle)?.upload;
13912
+ if (!upload) return { ok: false, errno: "EBADF", message: `no upload ${handle}` };
13913
+ if (!await upload.write(bytes)) {
13914
+ return { ok: false, errno: "EPIPE", message: "the request no longer takes a body" };
13915
+ }
13916
+ return { ok: true, kind: "void" };
13917
+ }
13918
+ end(handle) {
13919
+ const upload = this.open.get(handle)?.upload;
13920
+ if (!upload) return { ok: false, errno: "EBADF", message: `no upload ${handle}` };
13921
+ upload.end();
13922
+ return { ok: true, kind: "void" };
13923
+ }
13518
13924
  start(req) {
13519
13925
  const handle = ++this.nextHandle;
13520
13926
  const abort = new AbortController();
13521
13927
  const entry = {
13522
13928
  abort,
13523
13929
  head: Promise.resolve({ ok: true, kind: "void" }),
13524
- body: once(EMPTY),
13525
- left: EMPTY,
13930
+ body: once(EMPTY2),
13931
+ left: EMPTY2,
13526
13932
  done: false,
13527
13933
  reading: Promise.resolve(),
13528
- cancel: async () => void 0
13934
+ cancel: async () => void 0,
13935
+ ...req.stream ? { upload: new Upload() } : {}
13529
13936
  };
13530
13937
  this.open.set(handle, entry);
13531
13938
  entry.head = this.respond(handle, req, entry);
@@ -13539,7 +13946,7 @@ var HttpHandles = class {
13539
13946
  url: target,
13540
13947
  method: req.method,
13541
13948
  headers: req.headers,
13542
- ...req.body ? { body: req.body } : {},
13949
+ ...entry.upload ? { bodyStream: entry.upload } : req.body ? { body: req.body } : {},
13543
13950
  signal: entry.abort.signal
13544
13951
  };
13545
13952
  const response = port === void 0 ? await this.transport.fetch(request, this.owner) : await this.local.fetch(request, port);
@@ -13550,6 +13957,7 @@ var HttpHandles = class {
13550
13957
  const head = this.headOf(handle, shown, response);
13551
13958
  return response.redirected ? { ...head, json: { ...head.json, redirected: true } } : head;
13552
13959
  } catch (e) {
13960
+ entry.upload?.cancel();
13553
13961
  const text = message2(e);
13554
13962
  if (port !== void 0) return { ok: false, errno: codeOf2(e), message: text };
13555
13963
  const status = e.status;
@@ -13586,9 +13994,9 @@ var HttpHandles = class {
13586
13994
  async take(entry, max) {
13587
13995
  if (entry.left.length === 0 && !entry.done) {
13588
13996
  try {
13589
- const next2 = await entry.body.next();
13590
- if (next2.done) entry.done = true;
13591
- else entry.left = next2.value;
13997
+ const next3 = await entry.body.next();
13998
+ if (next3.done) entry.done = true;
13999
+ else entry.left = next3.value;
13592
14000
  } catch (e) {
13593
14001
  entry.done = true;
13594
14002
  const timedOut = e?.code === "ETIMEDOUT";
@@ -13607,6 +14015,7 @@ var HttpHandles = class {
13607
14015
  const entry = this.open.get(handle);
13608
14016
  if (!entry) return { ok: false, errno: "EBADF", message: `no request ${handle}` };
13609
14017
  this.open.delete(handle);
14018
+ entry.upload?.cancel();
13610
14019
  entry.abort.abort();
13611
14020
  await entry.cancel().catch(() => void 0);
13612
14021
  return { ok: true, kind: "void" };
@@ -13961,12 +14370,12 @@ var KernelTty = class {
13961
14370
  const chunks2 = [];
13962
14371
  let n = 0;
13963
14372
  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);
14373
+ const next3 = this.readable[0];
14374
+ if (next3 === null || next3 === void 0) break;
14375
+ const take = next3.subarray(0, max - n);
13967
14376
  chunks2.push(take);
13968
14377
  n += take.length;
13969
- if (take.length < next2.length) this.readable[0] = next2.subarray(take.length);
14378
+ if (take.length < next3.length) this.readable[0] = next3.subarray(take.length);
13970
14379
  else this.readable.shift();
13971
14380
  if (this.canonical) break;
13972
14381
  }
@@ -14063,11 +14472,11 @@ var PtyPair = class {
14063
14472
  const chunks2 = [];
14064
14473
  let n = 0;
14065
14474
  while (this.queue.length > 0 && n < max - status) {
14066
- const next2 = this.queue[0];
14067
- const take = next2.subarray(0, max - status - n);
14475
+ const next3 = this.queue[0];
14476
+ const take = next3.subarray(0, max - status - n);
14068
14477
  chunks2.push(take);
14069
14478
  n += take.length;
14070
- if (take.length < next2.length) this.queue[0] = next2.subarray(take.length);
14479
+ if (take.length < next3.length) this.queue[0] = next3.subarray(take.length);
14071
14480
  else this.queue.shift();
14072
14481
  }
14073
14482
  const out = new Uint8Array(status + n);
@@ -14387,8 +14796,8 @@ var Semaphore = class {
14387
14796
  this.mode = mode;
14388
14797
  }
14389
14798
  post() {
14390
- const next2 = this.waiters.shift();
14391
- if (next2) next2.grant();
14799
+ const next3 = this.waiters.shift();
14800
+ if (next3) next3.grant();
14392
14801
  else if (this.value >= SEM_VALUE_MAX) throw new KernelError("EOVERFLOW");
14393
14802
  else this.value++;
14394
14803
  }
@@ -14816,9 +15225,9 @@ var VfsNode = class {
14816
15225
  if (dirty && contents2 !== void 0) this.markDirty();
14817
15226
  }
14818
15227
  serial(op) {
14819
- const next2 = this.queue.then(op);
14820
- this.queue = next2.catch(() => void 0);
14821
- return next2;
15228
+ const next3 = this.queue.then(op);
15229
+ this.queue = next3.catch(() => void 0);
15230
+ return next3;
14822
15231
  }
14823
15232
  revoke() {
14824
15233
  this.revoked = true;
@@ -15240,9 +15649,9 @@ var VfsNodes = class {
15240
15649
  }
15241
15650
  for (const [p] of moved2) this.byPath.delete(p);
15242
15651
  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);
15652
+ const next3 = to + p.slice(from.length);
15653
+ if (node.path === p) node.renamedTo(next3);
15654
+ this.byPath.set(next3, node);
15246
15655
  }
15247
15656
  }
15248
15657
  };
@@ -15617,6 +16026,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
15617
16026
  "tty-pgrp-get",
15618
16027
  "tty-pgrp-set",
15619
16028
  "sig-mask",
16029
+ "sig-waiting",
15620
16030
  "sig-pause",
15621
16031
  ...SOCKET_OPS,
15622
16032
  ...EPOLL_OPS,
@@ -15730,16 +16140,8 @@ var WasmProcess = class {
15730
16140
  if (sig === SIG.STOP) return this.stop(sig);
15731
16141
  const bit = sigbit(sig);
15732
16142
  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
- }
16143
+ if (((this.options.blockedBits?.() ?? 0) & bit) !== 0 && this.routeBlocked(sig, bit)) {
16144
+ return "deliver";
15743
16145
  }
15744
16146
  if (!(this.caught & bit)) {
15745
16147
  const action = defaultAction(sig);
@@ -15756,6 +16158,17 @@ var WasmProcess = class {
15756
16158
  blocked2.abort();
15757
16159
  return "deliver";
15758
16160
  }
16161
+ routeBlocked(sig, bit) {
16162
+ const waiter = this.waiterFor(bit);
16163
+ const tid = waiter ?? this.options.unblockedThread?.(sig);
16164
+ if (tid === void 0 || tid === 1) {
16165
+ this.options.onPending?.(sig);
16166
+ return true;
16167
+ }
16168
+ if (waiter === void 0 && !(this.caught & bit)) return false;
16169
+ this.options.threadKill?.(tid, sig);
16170
+ return true;
16171
+ }
15759
16172
  async spawn(req) {
15760
16173
  const { file, argv, argv0, env, cwd, chdir, stdio, inherit: inherit2, exec, pgid, session, deathSignal } = req;
15761
16174
  if (deathSignal !== void 0 && (exec || !isSignal(deathSignal))) {
@@ -15836,6 +16249,16 @@ var WasmProcess = class {
15836
16249
  }
15837
16250
  blocks = /* @__PURE__ */ new WeakMap();
15838
16251
  sizesRead = /* @__PURE__ */ new WeakMap();
16252
+ sigwaiters = /* @__PURE__ */ new Map();
16253
+ setSigwaiter(tid, set3) {
16254
+ if (set3 === 0) this.sigwaiters.delete(tid);
16255
+ else this.sigwaiters.set(tid, set3);
16256
+ }
16257
+ waiterFor(bit) {
16258
+ if (((this.sigwaiters.get(1) ?? 0) & bit) !== 0) return 1;
16259
+ for (const [tid, set3] of this.sigwaiters) if (set3 & bit) return tid;
16260
+ return void 0;
16261
+ }
15839
16262
  async syscall(req, cancelled, block) {
15840
16263
  this.options.onSyscall?.(req);
15841
16264
  const started = performance.now();
@@ -16092,18 +16515,18 @@ var WasmProcess = class {
16092
16515
  }
16093
16516
  if (this.writesAt(req) && this.options.readonlyAt?.(path)) throw new KernelError("EROFS");
16094
16517
  const open = { ...req, path };
16095
- const plain = this.plainMode(req.mode);
16518
+ const plain2 = this.plainMode(req.mode);
16096
16519
  if (req.exclusive) {
16097
16520
  await nodes.createExclusive(path, this.newOwner(req.mode));
16098
- if (plain !== void 0) await fs.chmod?.(path, plain);
16521
+ if (plain2 !== void 0) await fs.chmod?.(path, plain2);
16099
16522
  this.fds.installAt(fd, this.openVfsFile(open, void 0, fs));
16100
16523
  } else if (req.create) {
16101
16524
  await nodes.onEntry(path, async () => {
16102
- const marks = this.options.owners || plain !== void 0;
16525
+ const marks = this.options.owners || plain2 !== void 0;
16103
16526
  const fresh2 = marks && !await present2(fs, path, true);
16104
16527
  this.fds.installAt(fd, this.openVfsFile(open, await nodes.identify(path), fs));
16105
16528
  await this.fds.get(fd).file.stat?.();
16106
- if (fresh2 && plain !== void 0) await fs.chmod?.(path, plain);
16529
+ if (fresh2 && plain2 !== void 0) await fs.chmod?.(path, plain2);
16107
16530
  else if (fresh2) {
16108
16531
  await fs.chown?.(path, { ...this.newOwner(req.mode), kind: "new" });
16109
16532
  }
@@ -16744,6 +17167,9 @@ var WasmProcess = class {
16744
17167
  case "dl-unlock":
16745
17168
  this.unlockDl(req.owner);
16746
17169
  return { ok: true, kind: "void" };
17170
+ case "sig-waiting":
17171
+ this.setSigwaiter(req.tid, req.set);
17172
+ return { ok: true, kind: "void" };
16747
17173
  case "sig-mask":
16748
17174
  this.caught = req.caught;
16749
17175
  this.ignored = req.ignored;
@@ -16811,8 +17237,8 @@ var WasmProcess = class {
16811
17237
  };
16812
17238
  withDl(state) {
16813
17239
  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] };
17240
+ const { next: next3, handle, free, live } = this.closures;
17241
+ const dl = { log: [...this.dlLog], next: next3, handle, free: [...free], live: [...live] };
16816
17242
  return { ...state, dl };
16817
17243
  }
16818
17244
  seedDl(dl) {
@@ -16823,8 +17249,8 @@ var WasmProcess = class {
16823
17249
  this.closures.free.push(...dl.free);
16824
17250
  for (const index of dl.live) this.closures.live.add(index);
16825
17251
  }
16826
- allocateClosure(floor) {
16827
- const index = this.closures.free.pop() ?? Math.max(floor, this.closures.next);
17252
+ allocateClosure(floor2) {
17253
+ const index = this.closures.free.pop() ?? Math.max(floor2, this.closures.next);
16828
17254
  this.closures.next = Math.max(this.closures.next, index + 1);
16829
17255
  this.closures.live.add(index);
16830
17256
  this.dlLog.push({ kind: "closure", index });
@@ -16876,8 +17302,8 @@ var WasmProcess = class {
16876
17302
  wakeDl() {
16877
17303
  for (const waiter of [...this.dlLock.waiters]) waiter.wake(false);
16878
17304
  }
16879
- reserveSlots(floor, size) {
16880
- const base = Math.max(floor, this.closures.next);
17305
+ reserveSlots(floor2, size) {
17306
+ const base = Math.max(floor2, this.closures.next);
16881
17307
  this.closures.next = base + size;
16882
17308
  return base;
16883
17309
  }
@@ -16934,6 +17360,7 @@ var WASM_MAX_THREADS = 256;
16934
17360
  // src/kernel/host.ts
16935
17361
  var CRASHED = 70;
16936
17362
  var KILL_GRACE_MS = 2e3;
17363
+ var KILL_HARD_MS = 5e3;
16937
17364
  var descIds = /* @__PURE__ */ new WeakMap();
16938
17365
  var nextDescId = 1;
16939
17366
  function descId(file) {
@@ -16960,16 +17387,21 @@ function inheritedFds(fds) {
16960
17387
  var Dying = class {
16961
17388
  ending;
16962
17389
  timer;
17390
+ hard;
16963
17391
  busy = 0;
16964
17392
  finish;
16965
17393
  start(code, sig, header4, process2, finish) {
16966
17394
  if (this.ending) return;
16967
17395
  this.ending = { code, sig };
16968
17396
  this.finish = finish;
17397
+ this.hard = setTimeout(finish, KILL_HARD_MS);
16969
17398
  this.arm();
16970
17399
  Atomics.store(header4, SAB_I_KILLED, code);
16971
17400
  process2.die();
16972
17401
  }
17402
+ serve(req, work) {
17403
+ return this.ending && isWasmSyscall(req) ? work() : this.serving(work);
17404
+ }
16973
17405
  async serving(work) {
16974
17406
  this.busy++;
16975
17407
  clearTimeout(this.timer);
@@ -16986,6 +17418,7 @@ var Dying = class {
16986
17418
  }
16987
17419
  clear() {
16988
17420
  clearTimeout(this.timer);
17421
+ clearTimeout(this.hard);
16989
17422
  }
16990
17423
  status(reported2) {
16991
17424
  if (this.ending) return [this.ending.code, this.ending.sig];
@@ -16997,8 +17430,8 @@ function killThread(thread, caught, sig) {
16997
17430
  const held = (Atomics.load(thread.header, SAB_I_BLOCKED) & sigbit(sig)) !== 0;
16998
17431
  if (!held && (caught & sigbit(sig)) === 0) return false;
16999
17432
  Atomics.or(thread.header, SAB_I_SIGNALS, sigbit(sig));
17000
- if (held) return true;
17001
17433
  Atomics.notify(thread.header, SAB_I_SIGNALS);
17434
+ if (held) return true;
17002
17435
  const blocked2 = thread.interrupt;
17003
17436
  thread.interrupt = new AbortController();
17004
17437
  blocked2.abort();
@@ -17094,7 +17527,7 @@ function inherited(opts) {
17094
17527
  ...opts.cred ? { cred: opts.cred } : {}
17095
17528
  };
17096
17529
  }
17097
- function holdingToken(opts, holds, caller) {
17530
+ function holdingToken(opts, holds2, caller) {
17098
17531
  return mintSyncFsToken({
17099
17532
  ...opts.owners ? caller : { umask: caller.umask },
17100
17533
  ...opts.dac ? { dac: opts.dac, pid: opts.pid, created: caller.created } : {},
@@ -17105,13 +17538,13 @@ function holdingToken(opts, holds, caller) {
17105
17538
  noLinks: opts.noLinks,
17106
17539
  cwd: opts.cwd,
17107
17540
  ...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)
17541
+ hold: (path, on, open, real, handle) => holds2.hold(path, on, open, real, handle),
17542
+ keptFor: (handle) => holds2.keptFor(handle),
17543
+ unlinked: (path) => holds2.keptAt(path),
17544
+ gate: (path, op) => opts.unlinkGate && holds2.holding(path) ? opts.unlinkGate.run(holds2.keyOf(path), op) : op(),
17545
+ own: (path, op) => holds2.own(path, op),
17546
+ revoked: (path) => holds2.isRevoked(path),
17547
+ renamed: (from, to) => holds2.renamed(from, to)
17115
17548
  });
17116
17549
  }
17117
17550
  function linksOf(opts) {
@@ -17185,6 +17618,9 @@ function threadInit(opts, program, sab, cred, thread, main) {
17185
17618
  signals: main
17186
17619
  };
17187
17620
  }
17621
+ function settleExit(exit, settle, code) {
17622
+ void exit.catch(() => void 0).then(() => settle(code & 255));
17623
+ }
17188
17624
  function spawnWasmProcess(opts) {
17189
17625
  const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
17190
17626
  const header4 = new Int32Array(sab, 0, SAB_HEADER_I32);
@@ -17211,19 +17647,20 @@ function spawnWasmProcess(opts) {
17211
17647
  )
17212
17648
  );
17213
17649
  publishStops(process2, header4);
17214
- const holds = new HeldPaths();
17215
- opts.held?.add(holds);
17216
- const token = holdingToken(opts, holds, {
17650
+ const holds2 = new HeldPaths();
17651
+ opts.held?.add(holds2);
17652
+ const token = holdingToken(opts, holds2, {
17217
17653
  cred: () => process2.cred,
17218
17654
  umask: () => process2.umask,
17219
17655
  created: created3,
17220
- holdsKept: async (path) => path.includes(`/${UNLINKED_DIR}/`) && (holds.keeps(path) || await process2.holds(path))
17656
+ holdsKept: async (path) => path.includes(`/${UNLINKED_DIR}/`) && (holds2.keeps(path) || await process2.holds(path))
17221
17657
  });
17222
- process2.keptPath = (path) => holds.keptAt(path)?.hidden;
17223
- process2.keptHandle = (handle2) => holds.keptFor(handle2)?.hidden;
17658
+ process2.keptPath = (path) => holds2.keptAt(path)?.hidden;
17659
+ process2.keptHandle = (handle2) => holds2.keptFor(handle2)?.hidden;
17224
17660
  const worker = opts.createWorker();
17225
17661
  const dying = new Dying();
17226
- const dispatch2 = (req, block) => dying.serving(
17662
+ const dispatch2 = (req, block) => dying.serve(
17663
+ req,
17227
17664
  () => isWasmSyscall(req) ? process2.syscall(req, void 0, block) : dispatchSyncFs(req)
17228
17665
  );
17229
17666
  const clocks = new ProcessClocks(sab, opts.program.abi !== "js", process2);
@@ -17246,12 +17683,9 @@ function spawnWasmProcess(opts) {
17246
17683
  responder.dispose();
17247
17684
  lane?.dispose();
17248
17685
  revokeSyncFsToken(token);
17249
- opts.held?.delete(holds);
17686
+ opts.held?.delete(holds2);
17250
17687
  worker.terminate();
17251
- void process2.exit().then(
17252
- () => settle(code),
17253
- () => settle(code)
17254
- );
17688
+ settleExit(process2.exit(), settle, code);
17255
17689
  };
17256
17690
  const exitNow = (code) => {
17257
17691
  queueMicrotask(() => finish(...dying.status(code)));
@@ -17295,7 +17729,7 @@ function spawnWasmProcess(opts) {
17295
17729
  const tsignals = threadSignalsOf(tsab);
17296
17730
  if (thread.blocked) storeBlocked(tsignals.header, thread.blocked);
17297
17731
  threadSignals.set(thread.tid, tsignals);
17298
- const tdispatch = (req, block) => dying.serving(() => threadCall(process2, req, threadCancel(tsignals), block));
17732
+ const tdispatch = (req, block) => dying.serve(req, () => threadCall(process2, req, threadCancel(tsignals), block));
17299
17733
  const tresponder = attachSyncSabResponder(tw, tsab, token, {
17300
17734
  dispatch: clocks.timed(clocks.thread(thread.tid, tsab), tdispatch)
17301
17735
  });
@@ -17765,10 +18199,10 @@ var Automaton = class {
17765
18199
  let node = 0;
17766
18200
  for (const byte of bytes) {
17767
18201
  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);
18202
+ let next3 = this.edges.get(key);
18203
+ if (next3 === void 0) {
18204
+ next3 = this.depth.length;
18205
+ this.edges.set(key, next3);
17772
18206
  this.fail.push(0);
17773
18207
  this.depth.push(this.depth[node] + 1);
17774
18208
  this.children.push(0);
@@ -17776,7 +18210,7 @@ var Automaton = class {
17776
18210
  this.out.push([]);
17777
18211
  this.dict.push(-1);
17778
18212
  }
17779
- node = next2;
18213
+ node = next3;
17780
18214
  }
17781
18215
  const id2 = this.lengths.length;
17782
18216
  this.lengths.push(bytes.length);
@@ -17812,8 +18246,8 @@ var Automaton = class {
17812
18246
  step(state, byte) {
17813
18247
  let current = state;
17814
18248
  for (; ; ) {
17815
- const next2 = this.edges.get(current * 256 + byte);
17816
- if (next2 !== void 0) return next2;
18249
+ const next3 = this.edges.get(current * 256 + byte);
18250
+ if (next3 !== void 0) return next3;
17817
18251
  if (current === 0) return 0;
17818
18252
  current = this.fail[current];
17819
18253
  }
@@ -17841,7 +18275,7 @@ var RANK = {
17841
18275
  };
17842
18276
  var CR2 = 13;
17843
18277
  var LF2 = 10;
17844
- var EMPTY2 = new Uint8Array(0);
18278
+ var EMPTY3 = new Uint8Array(0);
17845
18279
  function register(automaton, sources, ids, bytes, source) {
17846
18280
  const key = Array.from(bytes).join(",");
17847
18281
  let id2 = ids.get(key);
@@ -17967,7 +18401,7 @@ function pass(c, input, final) {
17967
18401
  const partials = [];
17968
18402
  scanMain(c, input, best, partials);
17969
18403
  scanWrapped(c, input, best, partials);
17970
- const holds = final ? [] : [...new Set(partials)].sort((a, b) => a - b);
18404
+ const holds2 = final ? [] : [...new Set(partials)].sort((a, b) => a - b);
17971
18405
  const starts = [...best.keys()].sort((a, b) => a - b);
17972
18406
  const parts2 = [];
17973
18407
  const hits = /* @__PURE__ */ new Map();
@@ -17977,16 +18411,16 @@ function pass(c, input, final) {
17977
18411
  let h = 0;
17978
18412
  for (; ; ) {
17979
18413
  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) {
18414
+ while (h < holds2.length && holds2[h] < pos) h++;
18415
+ const hold = h < holds2.length ? holds2[h] : Infinity;
18416
+ const next3 = s < starts.length ? starts[s] : Infinity;
18417
+ if (hold <= next3) {
17984
18418
  cut = Math.min(hold, input.length);
17985
18419
  break;
17986
18420
  }
17987
- const candidate = best.get(next2);
18421
+ const candidate = best.get(next3);
17988
18422
  parts2.push(
17989
- input.subarray(pos, next2),
18423
+ input.subarray(pos, next3),
17990
18424
  c.replacements[candidate.secret][candidate.form === "raw" ? 0 : 1]
17991
18425
  );
17992
18426
  count(c, hits, candidate);
@@ -18021,12 +18455,12 @@ function compile(secrets, options = {}) {
18021
18455
  return { text: decoder4.decode(bytes), hits };
18022
18456
  },
18023
18457
  stream() {
18024
- let pending = EMPTY2;
18458
+ let pending = EMPTY3;
18025
18459
  const hits = /* @__PURE__ */ new Map();
18026
18460
  const run2 = (final) => {
18027
18461
  if (c.secrets.length === 0 || pending.length === 0) {
18028
18462
  const out = pending;
18029
- pending = EMPTY2;
18463
+ pending = EMPTY3;
18030
18464
  return out;
18031
18465
  }
18032
18466
  const result = pass(c, pending, final);
@@ -18040,7 +18474,7 @@ function compile(secrets, options = {}) {
18040
18474
  return run2(false);
18041
18475
  },
18042
18476
  idle() {
18043
- return pending.length < FRAGMENT ? run2(true) : EMPTY2;
18477
+ return pending.length < FRAGMENT ? run2(true) : EMPTY3;
18044
18478
  },
18045
18479
  end() {
18046
18480
  return run2(true);
@@ -18082,7 +18516,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
18082
18516
  let timer;
18083
18517
  let failed3;
18084
18518
  const waiters = /* @__PURE__ */ new Set();
18085
- const quiet2 = () => !busy && pending === 0;
18519
+ const quiet3 = () => !busy && pending === 0;
18086
18520
  const wake = () => {
18087
18521
  for (const waiter of [...waiters]) waiter();
18088
18522
  };
@@ -18099,7 +18533,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
18099
18533
  if (failed3 === void 0) failed3 = err;
18100
18534
  }).finally(() => {
18101
18535
  pending -= 1;
18102
- if (quiet2()) wake();
18536
+ if (quiet3()) wake();
18103
18537
  });
18104
18538
  };
18105
18539
  const settling = (signal) => new Promise((resolve2, reject) => {
@@ -18117,7 +18551,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
18117
18551
  signal?.addEventListener("abort", stop, { once: true });
18118
18552
  });
18119
18553
  const settled = async () => {
18120
- while (!quiet2()) await settling();
18554
+ while (!quiet3()) await settling();
18121
18555
  };
18122
18556
  const changed = async (signal) => {
18123
18557
  const round = new AbortController();
@@ -18133,7 +18567,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
18133
18567
  };
18134
18568
  const turn = async (signal) => {
18135
18569
  for (let waited = false; ; waited = true) {
18136
- if (quiet2() && (pollFile(file).writable || !file.changed)) {
18570
+ if (quiet3() && (pollFile(file).writable || !file.changed)) {
18137
18571
  busy = true;
18138
18572
  return;
18139
18573
  }
@@ -18162,7 +18596,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
18162
18596
  ...bound(file, "stat"),
18163
18597
  poll: () => {
18164
18598
  const state = pollFile(file);
18165
- return quiet2() ? state : { ...state, writable: false };
18599
+ return quiet3() ? state : { ...state, writable: false };
18166
18600
  },
18167
18601
  changed,
18168
18602
  ...file.tty ? { tty: file.tty } : {},
@@ -18178,7 +18612,7 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
18178
18612
  await send(stream2.push(taken), signal);
18179
18613
  } finally {
18180
18614
  busy = false;
18181
- if (quiet2()) wake();
18615
+ if (quiet3()) wake();
18182
18616
  }
18183
18617
  timer = setTimeout(release, idleMs);
18184
18618
  return taken.length;
@@ -18279,15 +18713,15 @@ function isRecord(value) {
18279
18713
  return typeof value === "object" && value !== null && !Array.isArray(value);
18280
18714
  }
18281
18715
  function serialized(reply) {
18282
- let plain;
18716
+ let plain2;
18283
18717
  try {
18284
18718
  const text = JSON.stringify(reply);
18285
- plain = text === void 0 ? void 0 : JSON.parse(text);
18719
+ plain2 = text === void 0 ? void 0 : JSON.parse(text);
18286
18720
  } catch (err) {
18287
18721
  return JSON.stringify(errorReply("EIO", lineOf2(err)));
18288
18722
  }
18289
- if (!isRecord(plain)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
18290
- const { v: _, ...rest2 } = plain;
18723
+ if (!isRecord(plain2)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
18724
+ const { v: _, ...rest2 } = plain2;
18291
18725
  return JSON.stringify({ v: 1, ...rest2 });
18292
18726
  }
18293
18727
  function lineOf2(err) {
@@ -19306,22 +19740,22 @@ function keepWatching(loop, signal) {
19306
19740
  const stop = () => session2.abort();
19307
19741
  signal.addEventListener("abort", stop);
19308
19742
  let timer;
19309
- const quiet2 = () => {
19743
+ const quiet3 = () => {
19310
19744
  clearTimeout(timer);
19311
19745
  timer = setTimeout(stop, silenceMs);
19312
19746
  };
19313
19747
  let opened2 = false;
19314
19748
  try {
19315
19749
  const client = await loop.connect();
19316
- quiet2();
19750
+ quiet3();
19317
19751
  await client.watch(
19318
19752
  session2.signal,
19319
19753
  (event) => {
19320
- quiet2();
19754
+ quiet3();
19321
19755
  if (!event.ping) loop.event(event);
19322
19756
  },
19323
19757
  () => {
19324
- quiet2();
19758
+ quiet3();
19325
19759
  opened2 = true;
19326
19760
  up = true;
19327
19761
  loop.up(client);
@@ -19866,9 +20300,9 @@ function tmpfs() {
19866
20300
  let node = root;
19867
20301
  for (const name2 of parts2(path)) {
19868
20302
  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;
20303
+ const next3 = node.children.get(name2);
20304
+ if (!next3) throw fsError2("ENOENT", path);
20305
+ node = next3;
19872
20306
  }
19873
20307
  return node;
19874
20308
  }
@@ -20174,6 +20608,28 @@ function foreignImports(bytes) {
20174
20608
  return {};
20175
20609
  }
20176
20610
 
20611
+ // src/refused-command.ts
20612
+ var REFUSED_PATH = "/usr/lib/slicc/refused";
20613
+ var REFUSED_SOURCE = [
20614
+ "export default async function refused(ctx) {",
20615
+ " await ctx.write(2, ctx.argv[1] + '\\n').catch(() => undefined);",
20616
+ " return 126;",
20617
+ "}"
20618
+ ].join("\n");
20619
+ function refusing(command) {
20620
+ if (!command.refused) return command;
20621
+ return {
20622
+ name: command.name,
20623
+ abi: "js",
20624
+ glue: REFUSED_PATH,
20625
+ wasm: REFUSED_PATH,
20626
+ argv0: command.name,
20627
+ args: [`${command.name}: ${command.refused}`],
20628
+ refused: command.refused,
20629
+ shows: command.script ?? command.wasm
20630
+ };
20631
+ }
20632
+
20177
20633
  // src/sudo.ts
20178
20634
  var SUDOERS = "/etc/sudoers";
20179
20635
  var SUDOERS_D = "/etc/sudoers.d";
@@ -20201,13 +20657,13 @@ function splitWords(text) {
20201
20657
  while (piece.lastIndex < text.length) {
20202
20658
  const m = piece.exec(text);
20203
20659
  if (!m) return void 0;
20204
- const [, single, double, escaped, plain, space] = m;
20660
+ const [, single, double, escaped, plain2, space] = m;
20205
20661
  if (space !== void 0) {
20206
20662
  if (word !== void 0) words2.push(word);
20207
20663
  word = void 0;
20208
20664
  continue;
20209
20665
  }
20210
- word = (word ?? "") + (single ?? (double !== void 0 ? unescaped(double) : escaped ?? plain));
20666
+ word = (word ?? "") + (single ?? (double !== void 0 ? unescaped(double) : escaped ?? plain2));
20211
20667
  }
20212
20668
  if (word !== void 0) words2.push(word);
20213
20669
  return words2;
@@ -20239,7 +20695,7 @@ function parseRule(line) {
20239
20695
  if (!cmnd?.[0]?.startsWith("/")) return void 0;
20240
20696
  return { ...rule, cmnd };
20241
20697
  }
20242
- function flags(parsed2, arg, next2) {
20698
+ function flags(parsed2, arg, next3) {
20243
20699
  for (let j = 1; j < arg.length; j++) {
20244
20700
  const flag = arg[j];
20245
20701
  if (flag === "n") parsed2.nonInteractive = true;
@@ -20247,7 +20703,7 @@ function flags(parsed2, arg, next2) {
20247
20703
  else if (flag !== "u") return `sudo: invalid option -- '${flag}'
20248
20704
  ${USAGE}`;
20249
20705
  else {
20250
- const user = arg.slice(j + 1) || next2;
20706
+ const user = arg.slice(j + 1) || next3;
20251
20707
  if (!user) return `sudo: option requires an argument -- 'u'
20252
20708
  ${USAGE}`;
20253
20709
  parsed2.user = user;
@@ -20697,9 +21153,9 @@ function appendedRoots(given) {
20697
21153
  return [...roots];
20698
21154
  }
20699
21155
  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("=");
21156
+ const next3 = words2[1];
21157
+ if (baseName2(words2[0] ?? "") !== "env" || next3 === void 0) return false;
21158
+ return next3 === "-S" || !next3.startsWith("-") && !next3.includes("=");
20703
21159
  }
20704
21160
  function shebangCommand(words2) {
20705
21161
  if (!plainEnv(words2)) {
@@ -20723,9 +21179,9 @@ function expandDefaults(defaults, env) {
20723
21179
  for (const [key, value] of Object.entries(defaults ?? {})) {
20724
21180
  let missing4 = false;
20725
21181
  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 ?? "";
21182
+ const set3 = Object.hasOwn(env, name2) ? env[name2] : void 0;
21183
+ if (set3 === void 0) missing4 = true;
21184
+ return set3 ?? "";
20729
21185
  });
20730
21186
  if (!missing4) out[key] = expanded;
20731
21187
  }
@@ -20950,7 +21406,7 @@ var Launcher = class {
20950
21406
  const holders = [this.held, this.openFiles];
20951
21407
  this.unlinked = new UnlinkedKeeper(
20952
21408
  fs,
20953
- { [Symbol.iterator]: () => holders.flatMap((set2) => [...set2]).values() },
21409
+ { [Symbol.iterator]: () => holders.flatMap((set3) => [...set3]).values() },
20954
21410
  (path) => this.mountRoot(path),
20955
21411
  {
20956
21412
  locks: webLocks(),
@@ -21035,11 +21491,21 @@ var Launcher = class {
21035
21491
  found = this.trustedAppended().then(async (appended2) => {
21036
21492
  const tiers = await this.tiers(scope, appended2);
21037
21493
  return scanCommands(this.scanned, tiers, tiers.length - appended2.length);
21038
- }).then((commands) => commands.set(SUDO_COMMAND.name, SUDO_COMMAND));
21494
+ }).then((commands) => this.refusals(commands).set(SUDO_COMMAND.name, SUDO_COMMAND));
21039
21495
  this.catalogs.set(scope, found);
21040
21496
  }
21041
21497
  return found;
21042
21498
  }
21499
+ refusals(commands) {
21500
+ for (const [name2, command] of commands) {
21501
+ if (!command.refused) continue;
21502
+ commands.set(name2, refusing(command));
21503
+ if (this.warned.has(command.refused)) continue;
21504
+ this.warned.add(command.refused);
21505
+ console.warn(`slicc-kernel: refusing the commands of ${command.refused}`);
21506
+ }
21507
+ return commands;
21508
+ }
21043
21509
  ownCommands(scope) {
21044
21510
  let found = this.ownCatalogs.get(scope);
21045
21511
  if (!found) {
@@ -21114,7 +21580,8 @@ var Launcher = class {
21114
21580
  );
21115
21581
  return {
21116
21582
  byUid: new Map(users.map((account, i) => [account.uid, homes[i]])),
21117
- byBin: new Map(homes.map((home) => [`${home}/bin`, home]))
21583
+ byBin: new Map(homes.map((home) => [`${home}/bin`, home])),
21584
+ owners: new Map(homes.map((home, i) => [home, credOf(users[i])]))
21118
21585
  };
21119
21586
  },
21120
21587
  () => ({ byUid: /* @__PURE__ */ new Map(), byBin: /* @__PURE__ */ new Map() })
@@ -21456,12 +21923,12 @@ var Launcher = class {
21456
21923
  return `${path}:${st.size}:${st.mtime.getTime()}`;
21457
21924
  }
21458
21925
  verified(path, caller, fs = this.base) {
21459
- const plain = () => fs.readFileBuffer(path);
21460
- return this.integrity ? this.integrity.read(path, caller, plain) : plain();
21926
+ const plain2 = () => fs.readFileBuffer(path);
21927
+ return this.integrity ? this.integrity.read(path, caller, plain2) : plain2();
21461
21928
  }
21462
21929
  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 }));
21930
+ const plain2 = async () => this.base.readFileBuffer(path);
21931
+ return this.integrity ? this.integrity.readKeyed(path, caller, plain2, asked) : plain2().then((bytes) => ({ bytes }));
21465
21932
  }
21466
21933
  cached(cache, key, load) {
21467
21934
  const hit = cache.get(key);
@@ -21532,6 +21999,9 @@ var Launcher = class {
21532
21999
  if (target.abi === "js" && target.wasm === SUDO_PATH) {
21533
22000
  return { abi: "js", glue: SUDO_SOURCE, path: SUDO_PATH };
21534
22001
  }
22002
+ if (target.abi === "js" && target.wasm === REFUSED_PATH) {
22003
+ return { abi: "js", glue: REFUSED_SOURCE, path: REFUSED_PATH };
22004
+ }
21535
22005
  const { asked } = target;
21536
22006
  if (target.abi === "js") {
21537
22007
  return { abi: "js", glue: await this.text(target.wasm, caller, asked), path: target.wasm };
@@ -21601,7 +22071,7 @@ var Launcher = class {
21601
22071
  });
21602
22072
  return {
21603
22073
  source: {
21604
- read: (path, plain) => integrity.readSource(path, caller(), plain),
22074
+ read: (path, plain2) => integrity.readSource(path, caller(), plain2),
21605
22075
  open: (path, real) => integrity.openSource(path, caller(), real)
21606
22076
  }
21607
22077
  };
@@ -22040,9 +22510,9 @@ var Launcher = class {
22040
22510
  const members = this.jobs.list();
22041
22511
  let image = pid;
22042
22512
  for (; ; ) {
22043
- const next2 = members.find((m) => m.execParent === image);
22044
- if (!next2) return image;
22045
- image = next2.pid;
22513
+ const next3 = members.find((m) => m.execParent === image);
22514
+ if (!next3) return image;
22515
+ image = next3.pid;
22046
22516
  }
22047
22517
  }
22048
22518
  credOf(pid) {
@@ -22329,7 +22799,7 @@ var Launcher = class {
22329
22799
  this.pnpmStale();
22330
22800
  if (!detach) return;
22331
22801
  for (const nodes of this.openFiles) nodes.revoke(at);
22332
- for (const holds of this.held) holds.revoke(at);
22802
+ for (const holds2 of this.held) holds2.revoke(at);
22333
22803
  }
22334
22804
  unmountAll() {
22335
22805
  this.booting.abort();
@@ -22475,7 +22945,7 @@ var Launcher = class {
22475
22945
  this.openFiles.add(nodes);
22476
22946
  const unlinked = new UnlinkedKeeper(
22477
22947
  fs,
22478
- { [Symbol.iterator]: () => [this.held, this.openFiles].flatMap((set2) => [...set2]).values() },
22948
+ { [Symbol.iterator]: () => [this.held, this.openFiles].flatMap((set3) => [...set3]).values() },
22479
22949
  (path) => this.mountRoot(path),
22480
22950
  {
22481
22951
  locks: webLocks(),
@@ -22503,11 +22973,32 @@ var Launcher = class {
22503
22973
  commandFs(root) {
22504
22974
  return withCommandDirs(
22505
22975
  root,
22506
- async () => new Set((await this.commands()).keys()),
22976
+ async () => this.commandNames(await this.commands()),
22507
22977
  (dir) => this.userCommandDir(dir),
22508
- this.owners
22978
+ this.owners,
22979
+ (path) => this.entryTarget(path)
22509
22980
  );
22510
22981
  }
22982
+ named = /* @__PURE__ */ new WeakMap();
22983
+ commandNames(commands) {
22984
+ let names = this.named.get(commands);
22985
+ if (!names) {
22986
+ names = new Set(commands.keys());
22987
+ this.named.set(commands, names);
22988
+ }
22989
+ return names;
22990
+ }
22991
+ async entryTarget(path) {
22992
+ const system = COMMAND2.exec(path)?.[1];
22993
+ const slash = path.lastIndexOf("/");
22994
+ const scopes = await this.userScopes();
22995
+ const scope = system === void 0 ? scopes.byBin.get(path.slice(0, slash)) : "";
22996
+ const name2 = system ?? path.slice(slash + 1);
22997
+ const command = scope === void 0 ? void 0 : (await this.commands(scope)).get(name2);
22998
+ const owner = scope ? scopes.owners?.get(scope) : void 0;
22999
+ const target = command && (command.shows ?? command.script ?? command.wasm);
23000
+ return target === void 0 ? void 0 : { path: target, ...owner ? { owner } : {} };
23001
+ }
22511
23002
  processChain(fs, nodes, unlinked) {
22512
23003
  nodes.changed = (path) => this.changes.publish(path);
22513
23004
  nodes.dirtied = (delta) => this.changes.dirtied(delta);
@@ -22634,11 +23125,11 @@ function ipv4Place(address) {
22634
23125
  return void 0;
22635
23126
  }
22636
23127
  function placeOf(address) {
22637
- const plain = address.replace(/^\[(.*)\]$/, "$1").toLowerCase();
22638
- const kind = isIP(plain);
22639
- if (kind === 4) return ipv4Place(plain);
23128
+ const plain2 = address.replace(/^\[(.*)\]$/, "$1").toLowerCase();
23129
+ const kind = isIP(plain2);
23130
+ if (kind === 4) return ipv4Place(plain2);
22640
23131
  if (kind !== 6) return void 0;
22641
- const words2 = hextets2(plain);
23132
+ const words2 = hextets2(plain2);
22642
23133
  const embedded2 = words2.slice(0, 5).every((w) => w === 0) && (words2[5] === 65535 || words2[5] === 0);
22643
23134
  if (embedded2 && (words2[5] === 65535 || words2[6] !== 0)) return ipv4Place(ipv4Of(words2));
22644
23135
  if (words2.slice(0, 7).every((w) => w === 0) && (words2[7] ?? 0) <= 1) return "loopback";
@@ -22687,10 +23178,10 @@ function connectRefusal(address, port, place) {
22687
23178
  return Object.assign(new Error(why), { status: 403, code: "EACCES" });
22688
23179
  }
22689
23180
  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(() => []);
23181
+ const plain2 = host.replace(/^\[(.*)\]$/, "$1");
23182
+ if (isIP(plain2)) return [plain2];
23183
+ if (loopbackName2(plain2)) return ["127.0.0.1"];
23184
+ return resolve2(plain2).catch(() => []);
22694
23185
  }
22695
23186
  async function checkDestination(target, policy, resolve2 = resolveHost) {
22696
23187
  const url = new URL(target);
@@ -22901,26 +23392,26 @@ var MemoryFile = class {
22901
23392
  return new File(this.data.blobs, this.name, { lastModified: this.lastModified });
22902
23393
  }
22903
23394
  async createWritable({ keepExistingData = false } = {}) {
22904
- const next2 = keepExistingData ? new Chunks([...this.data.blobs], this.data.size) : new Chunks();
23395
+ const next3 = keepExistingData ? new Chunks([...this.data.blobs], this.data.size) : new Chunks();
22905
23396
  let position = 0;
22906
23397
  const put = async (data) => {
22907
23398
  const bytes = await bytesOf(data);
22908
- await next2.write(position, bytes);
23399
+ await next3.write(position, bytes);
22909
23400
  position += bytes.length;
22910
23401
  };
22911
23402
  return {
22912
23403
  write: async (data) => {
22913
23404
  if (!isParams(data)) return put(data);
22914
- if (data.type === "truncate") return next2.truncate(data.size ?? 0);
23405
+ if (data.type === "truncate") return next3.truncate(data.size ?? 0);
22915
23406
  position = data.position ?? position;
22916
23407
  if (data.type === "write") await put(data.data);
22917
23408
  },
22918
23409
  seek: async (at) => {
22919
23410
  position = at;
22920
23411
  },
22921
- truncate: async (size) => next2.truncate(size),
23412
+ truncate: async (size) => next3.truncate(size),
22922
23413
  close: async () => {
22923
- this.data = next2;
23414
+ this.data = next3;
22924
23415
  this.lastModified = Date.now();
22925
23416
  },
22926
23417
  abort: async () => {
@@ -23118,12 +23609,17 @@ var RemoteTransport = class {
23118
23609
  waiting = /* @__PURE__ */ new Map();
23119
23610
  nextId = 0;
23120
23611
  sockets = /* @__PURE__ */ new Map();
23612
+ uploads = /* @__PURE__ */ new Map();
23121
23613
  failure;
23122
23614
  constructor(port, traits) {
23123
23615
  this.port = port;
23124
23616
  this.traits = traits;
23125
23617
  }
23126
23618
  receive(reply) {
23619
+ if (reply.net === "body-pull") {
23620
+ void this.pull(reply.nid);
23621
+ return;
23622
+ }
23127
23623
  const socket = this.sockets.get(reply.nid);
23128
23624
  if (socket && this.toSocket(reply, socket)) return;
23129
23625
  const waiter = this.waiting.get(reply.nid);
@@ -23142,8 +23638,35 @@ var RemoteTransport = class {
23142
23638
  } else return false;
23143
23639
  return true;
23144
23640
  }
23641
+ async pull(nid) {
23642
+ const upload = this.uploads.get(nid);
23643
+ if (!upload) {
23644
+ this.port.postMessage({ net: "body-error", nid, message: "the request body is gone" });
23645
+ return;
23646
+ }
23647
+ try {
23648
+ const next3 = await upload.next();
23649
+ if (next3.done) {
23650
+ this.uploads.delete(nid);
23651
+ this.port.postMessage({ net: "body-end", nid });
23652
+ } else this.port.postMessage({ net: "body-chunk", nid, bytes: next3.value });
23653
+ } catch (e) {
23654
+ this.uploads.delete(nid);
23655
+ this.port.postMessage({
23656
+ net: "body-error",
23657
+ nid,
23658
+ message: e instanceof Error ? e.message : String(e)
23659
+ });
23660
+ }
23661
+ }
23662
+ dropUpload(nid) {
23663
+ const upload = this.uploads.get(nid);
23664
+ this.uploads.delete(nid);
23665
+ void upload?.return?.().catch(() => void 0);
23666
+ }
23145
23667
  fail(error) {
23146
23668
  this.failure = error;
23669
+ for (const nid of [...this.uploads.keys()]) this.dropUpload(nid);
23147
23670
  for (const waiter of this.waiting.values()) waiter.reject(error);
23148
23671
  this.waiting.clear();
23149
23672
  for (const socket of this.sockets.values())
@@ -23170,14 +23693,17 @@ var RemoteTransport = class {
23170
23693
  let finished = false;
23171
23694
  const abort = () => {
23172
23695
  finished = true;
23696
+ this.dropUpload(nid);
23173
23697
  this.cancel(nid);
23174
23698
  };
23175
23699
  signal.addEventListener("abort", abort, { once: true });
23176
23700
  const finish = () => {
23701
+ this.dropUpload(nid);
23177
23702
  if (finished) return;
23178
23703
  finished = true;
23179
23704
  signal.removeEventListener("abort", abort);
23180
23705
  };
23706
+ if (request.bodyStream) this.uploads.set(nid, request.bodyStream[Symbol.asyncIterator]());
23181
23707
  let head;
23182
23708
  try {
23183
23709
  head = await this.ask({
@@ -23186,7 +23712,7 @@ var RemoteTransport = class {
23186
23712
  url: request.url,
23187
23713
  method: request.method,
23188
23714
  headers: request.headers,
23189
- ...request.body ? { body: request.body } : {}
23715
+ ...request.bodyStream ? { streamed: true } : request.body ? { body: request.body } : {}
23190
23716
  });
23191
23717
  } catch (e) {
23192
23718
  finish();
@@ -23455,11 +23981,11 @@ function stream(chunks2, socket, signal) {
23455
23981
  },
23456
23982
  async pull(controller) {
23457
23983
  try {
23458
- const next2 = await chunks2.next();
23459
- if (next2.done) {
23984
+ const next3 = await chunks2.next();
23985
+ if (next3.done) {
23460
23986
  controller.close();
23461
23987
  socket.close();
23462
- } else controller.enqueue(next2.value);
23988
+ } else controller.enqueue(next3.value);
23463
23989
  } catch (err) {
23464
23990
  controller.error(err);
23465
23991
  socket.close();
@@ -23816,9 +24342,9 @@ async function terminalOn(channel, argv, opts) {
23816
24342
  get onData() {
23817
24343
  return listener;
23818
24344
  },
23819
- set onData(next2) {
23820
- listener = next2;
23821
- if (next2) for (const bytes of backlog.splice(0)) next2(bytes);
24345
+ set onData(next3) {
24346
+ listener = next3;
24347
+ if (next3) for (const bytes of backlog.splice(0)) next3(bytes);
23822
24348
  },
23823
24349
  write: (data) => send({ action: "write", bytes: bytesOf2(data) }),
23824
24350
  resize: (cols, rows) => send({ action: "resize", cols, rows }),
@@ -23964,7 +24490,12 @@ function hostfsFetchOf(options) {
23964
24490
  };
23965
24491
  }
23966
24492
  function nodeTransport(options = {}) {
23967
- const transport = fetchTransport({ webSocket: true, webSocketHeaders: true, redirect: "manual" });
24493
+ const transport = fetchTransport({
24494
+ webSocket: true,
24495
+ webSocketHeaders: true,
24496
+ redirect: "manual",
24497
+ streamingBodies: true
24498
+ });
23968
24499
  const open = { ...transport, traits: { ...transport.traits, crossOrigin: "any" } };
23969
24500
  return diagnosing(guardedLoopback(open, options.hostLoopback ?? false));
23970
24501
  }
@@ -24110,9 +24641,9 @@ async function createNodeKernel(options = {}) {
24110
24641
  get onData() {
24111
24642
  return listener;
24112
24643
  },
24113
- set onData(next2) {
24114
- listener = next2;
24115
- if (next2) for (const bytes of backlog.splice(0)) next2(bytes);
24644
+ set onData(next3) {
24645
+ listener = next3;
24646
+ if (next3) for (const bytes of backlog.splice(0)) next3(bytes);
24116
24647
  },
24117
24648
  write: (data) => session.write(typeof data === "string" ? new TextEncoder().encode(data) : data),
24118
24649
  resize: (cols, rows) => session.resize(cols, rows),