@ai-ecoverse/slicc-kernel 1.170.3 → 1.171.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7310,6 +7310,19 @@ function uploadsFor(peer) {
7310
7310
  });
7311
7311
  return { of, answer: (call) => pulls.get(call.nid)?.(call) };
7312
7312
  }
7313
+ function headOf(nid, response) {
7314
+ return {
7315
+ net: "head",
7316
+ nid,
7317
+ ...response.url !== void 0 ? { url: response.url } : {},
7318
+ ...response.redirected !== void 0 ? { redirected: response.redirected } : {},
7319
+ ...response.redirects ? { redirects: response.redirects } : {},
7320
+ ...response.opaqueRedirect ? { opaqueRedirect: true } : {},
7321
+ status: response.status,
7322
+ statusText: response.statusText,
7323
+ headers: response.headers
7324
+ };
7325
+ }
7313
7326
  function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS2 } = {}) {
7314
7327
  const open2 = /* @__PURE__ */ new Map();
7315
7328
  const fail2 = (nid, e) => {
@@ -7335,6 +7348,7 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS2 } = {})
7335
7348
  method: call.method,
7336
7349
  headers: call.headers,
7337
7350
  ...call.streamed ? { bodyStream: uploads.of(call.nid, abort.signal) } : call.body ? { body: call.body } : {},
7351
+ ...call.redirect !== void 0 ? { redirect: call.redirect } : {},
7338
7352
  signal: abort.signal
7339
7353
  });
7340
7354
  if (!open2.has(call.nid)) {
@@ -7342,15 +7356,7 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS2 } = {})
7342
7356
  return;
7343
7357
  }
7344
7358
  open2.set(call.nid, { abort, body: response.body[Symbol.asyncIterator](), response });
7345
- peer.postMessage({
7346
- net: "head",
7347
- nid: call.nid,
7348
- ...response.redirected ? { url: response.url, redirected: true } : {},
7349
- ...response.redirects ? { redirects: response.redirects } : {},
7350
- status: response.status,
7351
- statusText: response.statusText,
7352
- headers: response.headers
7353
- });
7359
+ peer.postMessage(headOf(call.nid, response));
7354
7360
  } catch (e) {
7355
7361
  fail2(call.nid, e);
7356
7362
  }
@@ -8206,9 +8212,9 @@ function serveClient(port, host) {
8206
8212
  ended.resolve();
8207
8213
  }
8208
8214
  async function hello(message3) {
8209
- const refused3 = versionError(message3.protocol) ?? await hosts.requests.accept(host, message3);
8210
- if (refused3) {
8211
- send2({ hello: { protocol: PROTOCOL, error: refused3 } });
8215
+ const refused4 = versionError(message3.protocol) ?? await hosts.requests.accept(host, message3);
8216
+ if (refused4) {
8217
+ send2({ hello: { protocol: PROTOCOL, error: refused4 } });
8212
8218
  detach();
8213
8219
  return;
8214
8220
  }
@@ -8498,7 +8504,7 @@ function satisfies(version, range2) {
8498
8504
  }
8499
8505
 
8500
8506
  // src/version.ts
8501
- var KERNEL_VERSION = true ? "1.170.3" : "0.0.0-dev";
8507
+ var KERNEL_VERSION = true ? "1.171.0" : "0.0.0-dev";
8502
8508
  var OS_RELEASE = "6.0.0-slicc";
8503
8509
  function procVersion() {
8504
8510
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -8790,10 +8796,10 @@ async function tierPackages(fs, physical, roots, bins, kernel, global) {
8790
8796
  const own = commandsOf(pkg, manifest);
8791
8797
  const named = new Set(own.map((command) => command.name));
8792
8798
  const extra = bins ? await binCommandsOf(physical, pkg, manifest, named) : [];
8793
- const refused3 = engineRefusal(manifest, kernel);
8799
+ const refused4 = engineRefusal(manifest, kernel);
8794
8800
  const name2 = pkg.slice(root.length + 1);
8795
8801
  const dependency = direct?.has(name2) === false;
8796
- const marks = { ...refused3 ? { refused: refused3 } : {}, ...dependency ? { dependency } : {} };
8802
+ const marks = { ...refused4 ? { refused: refused4 } : {}, ...dependency ? { dependency } : {} };
8797
8803
  out.push({
8798
8804
  name: name2,
8799
8805
  pkg,
@@ -8825,7 +8831,7 @@ function winners(tier) {
8825
8831
  }
8826
8832
  return out;
8827
8833
  }
8828
- async function scanCommands(fs, modules, binsFrom = Number.POSITIVE_INFINITY, kernel = KERNEL_VERSION, refused3, global = /* @__PURE__ */ new Set()) {
8834
+ async function scanCommands(fs, modules, binsFrom = Number.POSITIVE_INFINITY, kernel = KERNEL_VERSION, refused4, global = /* @__PURE__ */ new Set()) {
8829
8835
  const found = /* @__PURE__ */ new Map();
8830
8836
  const physical = physicalResolver(fs);
8831
8837
  const tiers = (typeof modules === "string" ? [modules] : modules).map(
@@ -8839,7 +8845,7 @@ async function scanCommands(fs, modules, binsFrom = Number.POSITIVE_INFINITY, ke
8839
8845
  const dependencies = [];
8840
8846
  for (const [index, roots] of tiers.entries()) {
8841
8847
  const tier = await tierPackages(fs, physical, roots, index >= binsFrom, kernel, global);
8842
- if (refused3) refused3.push(...tier.flatMap((entry) => entry.commands.filter((c) => c.refused)));
8848
+ if (refused4) refused4.push(...tier.flatMap((entry) => entry.commands.filter((c) => c.refused)));
8843
8849
  await take(tier.filter((entry) => !entry.dependency));
8844
8850
  dependencies.push(tier.filter((entry) => entry.dependency));
8845
8851
  }
@@ -10392,6 +10398,78 @@ var CronService = class {
10392
10398
  }
10393
10399
  };
10394
10400
 
10401
+ // src/kernel/net/placeholder-floor.ts
10402
+ var PLACEHOLDER = /fnox_proxy_[0-9a-f]{24}/;
10403
+ var ESCAPE = /%([0-9a-f]{2})/gi;
10404
+ var BASIC = /\bbasic\b(.*)/is;
10405
+ var PERCENT_LAYERS = 8;
10406
+ var BASE64_GROUP = 4;
10407
+ var PLACEHOLDER_REFUSED = "refused: this request has a sealed placeholder in its URL, a header or a Basic credential, and nothing fills it, so it was not sent";
10408
+ var PlaceholderRefused = class extends Error {
10409
+ status = 403;
10410
+ code = "EACCES";
10411
+ constructor() {
10412
+ super(PLACEHOLDER_REFUSED);
10413
+ }
10414
+ };
10415
+ function carries(text) {
10416
+ let layer = text;
10417
+ for (let i = 0; i < PERCENT_LAYERS; i++) {
10418
+ if (PLACEHOLDER.test(layer)) return true;
10419
+ const next3 = layer.replace(
10420
+ ESCAPE,
10421
+ (_, hex4) => String.fromCharCode(Number.parseInt(hex4, 16))
10422
+ );
10423
+ if (next3 === layer) return false;
10424
+ layer = next3;
10425
+ }
10426
+ return PLACEHOLDER.test(layer);
10427
+ }
10428
+ function basicCarries(value2) {
10429
+ const credential = BASIC.exec(value2)?.[1];
10430
+ if (credential === void 0) return false;
10431
+ const letters = credential.replace(/[^A-Za-z0-9+/_-]/g, "").replaceAll("-", "+").replaceAll("_", "/");
10432
+ for (let shift = 0; shift < BASE64_GROUP; shift++) {
10433
+ const part = letters.slice(shift);
10434
+ const whole = part.length % BASE64_GROUP === 1 ? part.slice(0, -1) : part;
10435
+ if (carries(atob(whole))) return true;
10436
+ }
10437
+ return false;
10438
+ }
10439
+ function headersCarry(headers) {
10440
+ return headers.some(
10441
+ ([name2, value2]) => carries(name2.toLowerCase()) || carries(value2) || basicCarries(value2)
10442
+ );
10443
+ }
10444
+ function urlCarries(url) {
10445
+ return carries(url) || URL.canParse(url) && carries(new URL(url).href);
10446
+ }
10447
+ function refuse(request3) {
10448
+ if (urlCarries(request3.url) || headersCarry(request3.headers)) throw new PlaceholderRefused();
10449
+ }
10450
+ function refuseSocket(request3) {
10451
+ refuse(request3);
10452
+ if (request3.protocols.some(carries)) throw new PlaceholderRefused();
10453
+ }
10454
+ function placeholderFloor(inner) {
10455
+ const open2 = inner.websocket?.bind(inner);
10456
+ return {
10457
+ get traits() {
10458
+ return inner.traits;
10459
+ },
10460
+ ...open2 ? {
10461
+ websocket: async (request3) => {
10462
+ refuseSocket(request3);
10463
+ return open2(request3);
10464
+ }
10465
+ } : {},
10466
+ async fetch(request3, owner) {
10467
+ refuse(request3);
10468
+ return inner.fetch(request3, owner);
10469
+ }
10470
+ };
10471
+ }
10472
+
10395
10473
  // src/kernel/net/proxy-service.ts
10396
10474
  var SEND_BUFFER2 = 1024 * 1024;
10397
10475
  var TLS_HANDSHAKE = 22;
@@ -10840,8 +10918,8 @@ var RealmProxy = class {
10840
10918
  }
10841
10919
  async connect(conn, incoming, req, idle2) {
10842
10920
  const target = tunnelTarget(req);
10843
- const refused3 = target.port === 443 ? await this.tunnelReady(target) : void 0;
10844
- if (refused3) throw refused3;
10921
+ const refused4 = target.port === 443 ? await this.tunnelReady(target) : void 0;
10922
+ if (refused4) throw refused4;
10845
10923
  await conn.write(latin1Bytes("HTTP/1.1 200 Connection Established\r\n\r\n"), this.stop.signal);
10846
10924
  try {
10847
10925
  const first = await incoming.peek(this.stop.signal);
@@ -10898,7 +10976,8 @@ var RealmProxy = class {
10898
10976
  });
10899
10977
  } catch (e) {
10900
10978
  waiting.abort();
10901
- throw new HttpError(502, e instanceof Error ? e.message : String(e));
10979
+ const status = e instanceof PlaceholderRefused ? e.status : 502;
10980
+ throw new HttpError(status, e instanceof Error ? e.message : String(e));
10902
10981
  }
10903
10982
  ctx.idle.ms = Number.POSITIVE_INFINITY;
10904
10983
  try {
@@ -11112,7 +11191,7 @@ async function relay(socket, conn) {
11112
11191
  // src/fs/attest.ts
11113
11192
  var ATTEST_MAX = 1024 * 1024;
11114
11193
  var UNOWNED = 1e3;
11115
- function refuse(code, path, why) {
11194
+ function refuse2(code, path, why) {
11116
11195
  throw Object.assign(new Error(`attest ${path}: ${why}`), { code });
11117
11196
  }
11118
11197
  function chainOf(path) {
@@ -11154,11 +11233,11 @@ async function trustedParents(fs, path, o) {
11154
11233
  const parents = [];
11155
11234
  for (const dir of chainOf(path).slice(0, -1)) {
11156
11235
  const st = await fs.lstat(dir);
11157
- if (st.isSymbolicLink) refuse("EACCES", path, `${dir} is a symlink`);
11158
- if (!st.isDirectory) refuse("ENOTDIR", path, `${dir} is not a directory`);
11236
+ if (st.isSymbolicLink) refuse2("EACCES", path, `${dir} is a symlink`);
11237
+ if (!st.isDirectory) refuse2("ENOTDIR", path, `${dir} is not a directory`);
11159
11238
  const perm = owned(dir, st);
11160
11239
  if (o.users !== "off" && (perm.uid !== 0 || (perm.mode & 18) !== 0)) {
11161
- refuse("EACCES", path, `${dir} is not root-owned or is writable by group or others`);
11240
+ refuse2("EACCES", path, `${dir} is not root-owned or is writable by group or others`);
11162
11241
  }
11163
11242
  parents.push(perm);
11164
11243
  }
@@ -11166,27 +11245,27 @@ async function trustedParents(fs, path, o) {
11166
11245
  }
11167
11246
  async function attest(fs, asked, o) {
11168
11247
  if (typeof asked !== "string" || !asked.startsWith("/")) {
11169
- refuse("EINVAL", String(asked), "not an absolute path");
11248
+ refuse2("EINVAL", String(asked), "not an absolute path");
11170
11249
  }
11171
11250
  const path = normalizePath(asked);
11172
11251
  const mount = o.mounts.find((target) => {
11173
11252
  const at = normalizePath(target);
11174
11253
  return at === "/" || under2(path, at);
11175
11254
  });
11176
- if (mount !== void 0) refuse("EACCES", path, `under the mount ${mount}`);
11255
+ if (mount !== void 0) refuse2("EACCES", path, `under the mount ${mount}`);
11177
11256
  const parents = await trustedParents(fs, path, o);
11178
11257
  for (let tries = 0; ; tries++) {
11179
11258
  const before = await fs.lstat(path);
11180
- if (before.isSymbolicLink) refuse("EACCES", path, "is a symlink");
11259
+ if (before.isSymbolicLink) refuse2("EACCES", path, "is a symlink");
11181
11260
  if (!before.isFile)
11182
- refuse(before.isDirectory ? "EISDIR" : "EINVAL", path, "is not a regular file");
11183
- if (before.size > ATTEST_MAX) refuse("EFBIG", path, `is over ${ATTEST_MAX} bytes`);
11261
+ refuse2(before.isDirectory ? "EISDIR" : "EINVAL", path, "is not a regular file");
11262
+ if (before.size > ATTEST_MAX) refuse2("EFBIG", path, `is over ${ATTEST_MAX} bytes`);
11184
11263
  const bytes = (await fs.readFileBuffer(path)).slice();
11185
11264
  const after = await fs.lstat(path);
11186
11265
  if (unchanged(before, after, bytes)) {
11187
11266
  return attested(path, after, bytes, await sha2562(bytes), o, parents);
11188
11267
  }
11189
- if (tries >= 1) refuse("EAGAIN", path, "changed while it was read");
11268
+ if (tries >= 1) refuse2("EAGAIN", path, "changed while it was read");
11190
11269
  }
11191
11270
  }
11192
11271
  var WATCH_DEBOUNCE_MS = 50;
@@ -13345,8 +13424,8 @@ var DriverConnection = class _DriverConnection {
13345
13424
  } finally {
13346
13425
  clearTimeout(timer);
13347
13426
  }
13348
- const refused3 = driverVersionError(hello.protocol);
13349
- if (refused3) throw errnoError("EPROTO", refused3);
13427
+ const refused4 = driverVersionError(hello.protocol);
13428
+ if (refused4) throw errnoError("EPROTO", refused4);
13350
13429
  if (hello.error) throw errnoError(hello.errno ?? "EIO", hello.error);
13351
13430
  return new _DriverConnection(port, hello.capabilities ?? {}, waiting, timeoutMs, options);
13352
13431
  }
@@ -15370,8 +15449,8 @@ async function guarded(entry, path, req) {
15370
15449
  return { paths };
15371
15450
  } catch (err) {
15372
15451
  const refusal2 = err.code === "EACCES";
15373
- const refused3 = req.op === "exists" && refusal2 ? json2(false) : toErrno(err);
15374
- return { refused: refused3 };
15452
+ const refused4 = req.op === "exists" && refusal2 ? json2(false) : toErrno(err);
15453
+ return { refused: refused4 };
15375
15454
  }
15376
15455
  }
15377
15456
  async function copyOp(entry, path, req) {
@@ -15567,13 +15646,13 @@ async function created2(entry, req) {
15567
15646
  return seen === void 0 ? looked : json2({ ...looked.json, seen });
15568
15647
  }
15569
15648
  var DENIED = /* @__PURE__ */ new Set(["EACCES", "EPERM"]);
15570
- async function rmPermitted(entry, path, req, refused3) {
15649
+ async function rmPermitted(entry, path, req, refused4) {
15571
15650
  const st = await entry.fs.lstat(path).catch(() => void 0);
15572
- if (!st?.isDirectory) return refused3;
15651
+ if (!st?.isDirectory) return refused4;
15573
15652
  const unlisted = await guarded(entry, path, { ...req, op: "readdir" });
15574
15653
  if ("refused" in unlisted) return unlisted.refused;
15575
15654
  const names2 = await entry.fs.readdir(path).catch(() => void 0);
15576
- if (!names2) return refused3;
15655
+ if (!names2) return refused4;
15577
15656
  let first;
15578
15657
  for (const name2 of names2) {
15579
15658
  const child = await dispatchOne(entry, {
@@ -15624,14 +15703,14 @@ async function newDevName(entry, path, req) {
15624
15703
  const named = NAMING.has(req.op);
15625
15704
  if (!named && !CREATIONS.has(req.op)) return void 0;
15626
15705
  const target = named ? entry.fs.resolvePath(entry.cwd, req.arg2 ?? "") : path;
15627
- const refused3 = devCreation(target, entry.cred?.());
15628
- if (!refused3) return void 0;
15706
+ const refused4 = devCreation(target, entry.cred?.());
15707
+ if (!refused4) return void 0;
15629
15708
  const there = await entry.fs.lstat(target).then(
15630
15709
  () => true,
15631
15710
  () => false
15632
15711
  );
15633
15712
  if (there) return void 0;
15634
- return { ok: false, errno: refused3, message: `${target}: no new names in /dev or /proc` };
15713
+ return { ok: false, errno: refused4, message: `${target}: no new names in /dev or /proc` };
15635
15714
  }
15636
15715
  var MISS_OPS = /* @__PURE__ */ new Set(["stat", "lstat"]);
15637
15716
  async function linkFree(fs, path) {
@@ -15754,7 +15833,7 @@ function encodeSabResult(result) {
15754
15833
  message: result.message,
15755
15834
  ...result.direct ? { direct: true } : {},
15756
15835
  ...result.dev !== void 0 ? { dev: result.dev } : {},
15757
- ...result.detail === "transport" ? { detail: result.detail } : {}
15836
+ ...result.detail ? { detail: result.detail } : {}
15758
15837
  })
15759
15838
  )
15760
15839
  };
@@ -17734,8 +17813,8 @@ var KernelLoopback = class {
17734
17813
  );
17735
17814
  } catch (err) {
17736
17815
  socket.close();
17737
- const refused3 = err instanceof KernelError && err.code === "ECONNREFUSED";
17738
- throw refused3 ? errno2("ECONNREFUSED", `nothing listens on the kernel's port ${port}`) : err;
17816
+ const refused4 = err instanceof KernelError && err.code === "ECONNREFUSED";
17817
+ throw refused4 ? errno2("ECONNREFUSED", `nothing listens on the kernel's port ${port}`) : err;
17739
17818
  }
17740
17819
  signal.addEventListener("abort", () => socket.close(), { once: true });
17741
17820
  return socket;
@@ -19216,22 +19295,28 @@ var HttpHandles = class {
19216
19295
  return response.redirected ? { ...head, json: { ...head.json, redirected: true } } : head;
19217
19296
  } catch (e) {
19218
19297
  entry.upload?.cancel();
19219
- const text = message2(e);
19220
- if (port !== void 0) return { ok: false, errno: codeOf2(e), message: text };
19221
- const status = e.status;
19222
- if (text === NO_TRANSPORT || typeof status !== "number" || status === 502) {
19223
- const code = codeOf2(e);
19224
- const errno3 = text === NO_TRANSPORT ? "ENETUNREACH" : code !== "EIO" ? code : "ECONNREFUSED";
19225
- const failed3 = e.detail === "transport";
19226
- return { ok: false, errno: errno3, message: text, ...failed3 ? { detail: "transport" } : {} };
19227
- }
19228
- entry.body = once(new TextEncoder().encode(text))[Symbol.asyncIterator]();
19229
- return this.headOf(handle, req.url, {
19230
- status,
19231
- statusText: "",
19232
- headers: [["content-type", "text/plain; charset=utf-8"]]
19233
- });
19298
+ if (port !== void 0) return { ok: false, errno: codeOf2(e), message: message2(e) };
19299
+ return this.failure(handle, req, e, entry);
19300
+ }
19301
+ }
19302
+ failure(handle, req, e, entry) {
19303
+ const text = message2(e);
19304
+ if (e instanceof PlaceholderRefused) {
19305
+ return { ok: false, errno: e.code, message: text, detail: "placeholder" };
19234
19306
  }
19307
+ const status = e.status;
19308
+ if (text === NO_TRANSPORT || typeof status !== "number" || status === 502) {
19309
+ const code = codeOf2(e);
19310
+ const errno3 = text === NO_TRANSPORT ? "ENETUNREACH" : code !== "EIO" ? code : "ECONNREFUSED";
19311
+ const failed3 = e.detail === "transport";
19312
+ return { ok: false, errno: errno3, message: text, ...failed3 ? { detail: "transport" } : {} };
19313
+ }
19314
+ entry.body = once(new TextEncoder().encode(text))[Symbol.asyncIterator]();
19315
+ return this.headOf(handle, req.url, {
19316
+ status,
19317
+ statusText: "",
19318
+ headers: [["content-type", "text/plain; charset=utf-8"]]
19319
+ });
19235
19320
  }
19236
19321
  headOf(handle, url, response) {
19237
19322
  const { status, statusText, headers } = response;
@@ -22442,7 +22527,7 @@ var HEAD_MAX = 16 * 1024;
22442
22527
  var ANY_PLACEHOLDER = /fnox_proxy_[0-9a-f]{24}/g;
22443
22528
  var REQUEST_LINE2 = /^([!#$%&'*+.^_`|~0-9A-Za-z-]+) ([\x21-\x7e]+) HTTP\/1\.[01]$/;
22444
22529
  var HEADER_LINE = /^([!#$%&'*+.^_`|~0-9A-Za-z-]+):[ \t]*(.*?)[ \t]*$/;
22445
- var BASIC = /^(Basic[ \t]+)([A-Za-z0-9+/]+={0,2})$/i;
22530
+ var BASIC2 = /^(Basic[ \t]+)([A-Za-z0-9+/]+={0,2})$/i;
22446
22531
  var encoder8 = new TextEncoder();
22447
22532
  function binary(text) {
22448
22533
  let out = "";
@@ -22458,7 +22543,7 @@ function sniffHttp1(start2) {
22458
22543
  return "no";
22459
22544
  }
22460
22545
  function basicOf(value2) {
22461
- const m = BASIC.exec(value2);
22546
+ const m = BASIC2.exec(value2);
22462
22547
  if (!m) return void 0;
22463
22548
  try {
22464
22549
  return { scheme: m[1], decoded: atob(m[2]) };
@@ -28956,6 +29041,234 @@ function enableDnsStub(net, stub) {
28956
29041
  });
28957
29042
  }
28958
29043
 
29044
+ // src/kernel/net/remote-transport.ts
29045
+ var TransportError = class extends Error {
29046
+ status;
29047
+ code;
29048
+ detail;
29049
+ constructor(message3, status, code, detail) {
29050
+ super(message3);
29051
+ this.status = status;
29052
+ this.code = code;
29053
+ this.detail = detail === "transport" ? detail : void 0;
29054
+ }
29055
+ };
29056
+ function unfollowed2(redirect) {
29057
+ return redirect !== void 0 && redirect !== "follow";
29058
+ }
29059
+ function honors(traits, redirect) {
29060
+ if (traits.redirectPolicy === true) return true;
29061
+ const hops = traits.redirectHops;
29062
+ const raw2 = traits.manualRedirects === true && (hops === void 0 || hops === false);
29063
+ return redirect === "manual" && raw2;
29064
+ }
29065
+ function refused3(message3) {
29066
+ return new TransportError(message3, 502, void 0, "transport");
29067
+ }
29068
+ var RemoteTransport = class {
29069
+ traits;
29070
+ port;
29071
+ waiting = /* @__PURE__ */ new Map();
29072
+ nextId = 0;
29073
+ sockets = /* @__PURE__ */ new Map();
29074
+ uploads = /* @__PURE__ */ new Map();
29075
+ failure;
29076
+ constructor(port, traits) {
29077
+ this.port = port;
29078
+ this.traits = traits;
29079
+ }
29080
+ receive(reply) {
29081
+ if (reply.net === "body-pull") {
29082
+ void this.pull(reply.nid);
29083
+ return;
29084
+ }
29085
+ const socket = this.sockets.get(reply.nid);
29086
+ if (socket && this.toSocket(reply, socket)) return;
29087
+ const waiter = this.waiting.get(reply.nid);
29088
+ if (!waiter) return;
29089
+ this.waiting.delete(reply.nid);
29090
+ if (reply.net === "error") {
29091
+ waiter.reject(new TransportError(reply.message, reply.status, reply.code, reply.detail));
29092
+ } else waiter.resolve(reply);
29093
+ }
29094
+ toSocket(reply, socket) {
29095
+ if (reply.net === "ws-message") socket.queue.push(reply.data);
29096
+ else if (reply.net === "ws-acked") socket.acked(reply.n);
29097
+ else if (reply.net === "ws-closed") {
29098
+ this.sockets.delete(reply.nid);
29099
+ socket.queue.end({ code: reply.code, reason: reply.reason });
29100
+ } else return false;
29101
+ return true;
29102
+ }
29103
+ async pull(nid) {
29104
+ const upload = this.uploads.get(nid);
29105
+ if (!upload) {
29106
+ this.port.postMessage({ net: "body-error", nid, message: "the request body is gone" });
29107
+ return;
29108
+ }
29109
+ try {
29110
+ const next3 = await upload.next();
29111
+ if (next3.done) {
29112
+ this.uploads.delete(nid);
29113
+ this.port.postMessage({ net: "body-end", nid });
29114
+ } else this.port.postMessage({ net: "body-chunk", nid, bytes: next3.value });
29115
+ } catch (e) {
29116
+ this.uploads.delete(nid);
29117
+ this.port.postMessage({
29118
+ net: "body-error",
29119
+ nid,
29120
+ message: e instanceof Error ? e.message : String(e)
29121
+ });
29122
+ }
29123
+ }
29124
+ dropUpload(nid) {
29125
+ const upload = this.uploads.get(nid);
29126
+ this.uploads.delete(nid);
29127
+ void upload?.return?.().catch(() => void 0);
29128
+ }
29129
+ fail(error) {
29130
+ this.failure = error;
29131
+ for (const nid of [...this.uploads.keys()]) this.dropUpload(nid);
29132
+ for (const waiter of this.waiting.values()) waiter.reject(error);
29133
+ this.waiting.clear();
29134
+ for (const socket of this.sockets.values())
29135
+ socket.queue.end({ code: 1011, reason: error.message });
29136
+ this.sockets.clear();
29137
+ }
29138
+ ask(call) {
29139
+ if (this.failure) return Promise.reject(this.failure);
29140
+ return new Promise((resolve2, reject) => {
29141
+ this.waiting.set(call.nid, { resolve: resolve2, reject });
29142
+ this.port.postMessage(call);
29143
+ });
29144
+ }
29145
+ cancel(nid) {
29146
+ const waiter = this.waiting.get(nid);
29147
+ this.waiting.delete(nid);
29148
+ waiter?.reject(new TransportError("the request was cancelled"));
29149
+ this.port.postMessage({ net: "cancel", nid });
29150
+ }
29151
+ async fetch(request3) {
29152
+ const nid = ++this.nextId;
29153
+ const { signal, redirect } = request3;
29154
+ signal.throwIfAborted();
29155
+ if (unfollowed2(redirect) && !honors(this.traits, redirect)) {
29156
+ throw refused3(`this transport cannot honor redirect: ${redirect}`);
29157
+ }
29158
+ let finished = false;
29159
+ const abort = () => {
29160
+ finished = true;
29161
+ this.dropUpload(nid);
29162
+ this.cancel(nid);
29163
+ };
29164
+ signal.addEventListener("abort", abort, { once: true });
29165
+ const finish = () => {
29166
+ this.dropUpload(nid);
29167
+ if (finished) return;
29168
+ finished = true;
29169
+ signal.removeEventListener("abort", abort);
29170
+ };
29171
+ if (request3.bodyStream) this.uploads.set(nid, request3.bodyStream[Symbol.asyncIterator]());
29172
+ let head;
29173
+ try {
29174
+ head = await this.ask({
29175
+ net: "fetch",
29176
+ nid,
29177
+ url: request3.url,
29178
+ method: request3.method,
29179
+ headers: request3.headers,
29180
+ ...request3.bodyStream ? { streamed: true } : request3.body ? { body: request3.body } : {},
29181
+ ...redirect !== void 0 ? { redirect } : {}
29182
+ });
29183
+ } catch (e) {
29184
+ finish();
29185
+ throw e;
29186
+ }
29187
+ const { status, statusText, headers, url, redirected: redirected2, redirects, opaqueRedirect } = head;
29188
+ const read = async () => {
29189
+ if (finished) return void 0;
29190
+ const reply = await this.ask({ net: "read", nid }).catch((e) => {
29191
+ finish();
29192
+ throw e;
29193
+ });
29194
+ if (reply.net === "chunk") return reply.bytes;
29195
+ finish();
29196
+ return void 0;
29197
+ };
29198
+ const cancel = async () => {
29199
+ if (finished) return;
29200
+ finish();
29201
+ this.cancel(nid);
29202
+ };
29203
+ if (unfollowed2(redirect) && (redirected2 || redirects?.length)) {
29204
+ await cancel();
29205
+ throw refused3(`this transport followed a redirect despite redirect: ${redirect}`);
29206
+ }
29207
+ return {
29208
+ ...url !== void 0 ? { url } : {},
29209
+ ...redirected2 !== void 0 ? { redirected: redirected2 } : {},
29210
+ ...redirects ? { redirects } : {},
29211
+ ...opaqueRedirect ? { opaqueRedirect } : {},
29212
+ status,
29213
+ statusText,
29214
+ headers,
29215
+ cancel,
29216
+ body: {
29217
+ [Symbol.asyncIterator]: () => ({
29218
+ next: async () => {
29219
+ const bytes = await read();
29220
+ return bytes ? { value: bytes, done: false } : { value: void 0, done: true };
29221
+ },
29222
+ return: async () => {
29223
+ await cancel();
29224
+ return { value: void 0, done: true };
29225
+ }
29226
+ })
29227
+ }
29228
+ };
29229
+ }
29230
+ async websocket(request3) {
29231
+ const nid = ++this.nextId;
29232
+ const { signal } = request3;
29233
+ signal.throwIfAborted();
29234
+ const abort = () => this.cancel(nid);
29235
+ signal.addEventListener("abort", abort, { once: true });
29236
+ let opened2;
29237
+ try {
29238
+ opened2 = await this.ask({
29239
+ net: "ws-open",
29240
+ nid,
29241
+ url: request3.url,
29242
+ protocols: request3.protocols,
29243
+ headers: request3.headers
29244
+ });
29245
+ } finally {
29246
+ signal.removeEventListener("abort", abort);
29247
+ }
29248
+ const close = (code, reason) => this.port.postMessage({ net: "ws-close", nid, code, reason });
29249
+ const queue = new MessageQueue(
29250
+ () => close(1e3, "a message is too big"),
29251
+ Number.POSITIVE_INFINITY,
29252
+ (n) => this.port.postMessage({ net: "ws-consumed", nid, n })
29253
+ );
29254
+ let unacked = 0;
29255
+ this.sockets.set(nid, { queue, acked: (n) => void (unacked -= n) });
29256
+ return {
29257
+ protocol: opened2.protocol,
29258
+ get buffered() {
29259
+ return unacked;
29260
+ },
29261
+ send: (data) => {
29262
+ unacked += payloadSize(data);
29263
+ this.port.postMessage({ net: "ws-send", nid, data });
29264
+ },
29265
+ messages: queue,
29266
+ close,
29267
+ closed: queue.closed
29268
+ };
29269
+ }
29270
+ };
29271
+
28959
29272
  // src/kernel/net/redirect-hops.ts
28960
29273
  var HELD_MS = 3e4;
28961
29274
  var HELD_MAX2 = 64;
@@ -29031,7 +29344,10 @@ function replayingHops(inner, heldMs = HELD_MS) {
29031
29344
  return { ...inner.traits, manualRedirects: true };
29032
29345
  },
29033
29346
  ...inner.websocket ? { websocket: inner.websocket.bind(inner) } : {},
29034
- async fetch(request3, owner = KERNEL) {
29347
+ async fetch(request3, ...rest2) {
29348
+ if (unfollowed2(request3.redirect)) return inner.fetch(request3, ...rest2);
29349
+ const [caller] = rest2;
29350
+ const owner = caller ?? KERNEL;
29035
29351
  const key = keyOf3(owner, request3.method, request3.url);
29036
29352
  const waiting = held.get(key);
29037
29353
  if (waiting && waiting.fingerprint === fingerprint(request3.headers)) {
@@ -29040,7 +29356,7 @@ function replayingHops(inner, heldMs = HELD_MS) {
29040
29356
  return replay(waiting);
29041
29357
  }
29042
29358
  if (waiting) drop(key);
29043
- const response = await inner.fetch(request3);
29359
+ const response = await inner.fetch(request3, ...rest2);
29044
29360
  if (!response.redirects?.length) return response;
29045
29361
  return replay({
29046
29362
  owner,
@@ -29479,9 +29795,9 @@ function serveFilesystem(port, handlers, capabilities = {}, options = {}) {
29479
29795
  let open2 = false;
29480
29796
  const reply = (message3, transfer = []) => port.postMessage(message3, transfer);
29481
29797
  async function hello(message3) {
29482
- const refused3 = driverVersionError(message3.protocol);
29483
- if (refused3) {
29484
- reply({ hello: { protocol: DRIVER_PROTOCOL, error: refused3, errno: "EPROTO" } });
29798
+ const refused4 = driverVersionError(message3.protocol);
29799
+ if (refused4) {
29800
+ reply({ hello: { protocol: DRIVER_PROTOCOL, error: refused4, errno: "EPROTO" } });
29485
29801
  return;
29486
29802
  }
29487
29803
  try {
@@ -31883,7 +32199,7 @@ var Launcher = class {
31883
32199
  ...options.env
31884
32200
  };
31885
32201
  this.ca = kernelCa(options.caStore ?? memoryCaStore());
31886
- this.transport = replayingHops(options.transport ?? missingTransport());
32202
+ this.transport = placeholderFloor(replayingHops(options.transport ?? missingTransport()));
31887
32203
  this.announcedTraits = JSON.stringify(this.transport.traits);
31888
32204
  this.uplink = options.uplink;
31889
32205
  this.routes = new Routes(options.uplink?.traits.ipv6 === true);
@@ -32038,16 +32354,16 @@ var Launcher = class {
32038
32354
  if (!found) {
32039
32355
  found = this.swaps.settled().then(() => this.trustedAppended()).then(async (appended2) => {
32040
32356
  const tiers = await this.tiers(scope, appended2);
32041
- const refused3 = [];
32357
+ const refused4 = [];
32042
32358
  const commands = await scanCommands(
32043
32359
  this.scanned,
32044
32360
  tiers,
32045
32361
  tiers.length - appended2.length,
32046
32362
  void 0,
32047
- refused3,
32363
+ refused4,
32048
32364
  await this.globalRoots(scope)
32049
32365
  );
32050
- this.refusedOf.set(commands, refused3.map(refusing));
32366
+ this.refusedOf.set(commands, refused4.map(refusing));
32051
32367
  return commands;
32052
32368
  }).then(
32053
32369
  (commands) => this.refusals(commands).set(SUDO_COMMAND.name, SUDO_COMMAND).set(CRONTAB_COMMAND.name, CRONTAB_COMMAND)
@@ -32253,14 +32569,14 @@ var Launcher = class {
32253
32569
  return await this.commandAt(path, scope) ?? await this.refusedAt(path, name2, scope);
32254
32570
  }
32255
32571
  async refusedAt(path, name2, scope) {
32256
- const refused3 = this.refusedOf.get(await this.commands(scope)) ?? [];
32257
- if (refused3.length === 0) return void 0;
32572
+ const refused4 = this.refusedOf.get(await this.commands(scope)) ?? [];
32573
+ if (refused4.length === 0) return void 0;
32258
32574
  const st = await this.base.stat(path).catch(() => void 0);
32259
32575
  if (!st?.isFile) return void 0;
32260
32576
  const real = await physicalPathAsync(this.base, path).catch(() => path);
32261
32577
  const same3 = async (own) => own === path || await physicalPathAsync(this.base, own).catch(() => own) === real;
32262
32578
  const owners = [];
32263
- for (const c of refused3) {
32579
+ for (const c of refused4) {
32264
32580
  const origin = c.origin;
32265
32581
  for (const own of [origin.glue, origin.wasm, ...origin.variants ?? []]) {
32266
32582
  if (!await same3(own)) continue;
@@ -32270,11 +32586,11 @@ var Launcher = class {
32270
32586
  }
32271
32587
  const stem = name2.replace(/\.wasm$/, "");
32272
32588
  const named = owners.find((c) => c.name === name2) ?? owners.find((c) => c.name === stem);
32273
- return named ?? owners[0] ?? await this.refusedCopy(real, name2, refused3);
32589
+ return named ?? owners[0] ?? await this.refusedCopy(real, name2, refused4);
32274
32590
  }
32275
- async refusedCopy(real, name2, refused3) {
32591
+ async refusedCopy(real, name2, refused4) {
32276
32592
  const dir = real.slice(0, real.lastIndexOf("/"));
32277
- for (const c of refused3) {
32593
+ for (const c of refused4) {
32278
32594
  const origin = c.origin;
32279
32595
  if (origin.abi !== "emscripten" || origin.script || c.name !== name2) continue;
32280
32596
  const own = await physicalPathAsync(this.base, origin.glue).catch(() => origin.glue);
@@ -32482,12 +32798,12 @@ var Launcher = class {
32482
32798
  return void 0;
32483
32799
  }
32484
32800
  async planOne(req, { ppid, cred, scope }, catalogOnly = false) {
32485
- const refused3 = (err) => {
32801
+ const refused4 = (err) => {
32486
32802
  throw codeOf8(err) === "EACCES" ? new SpawnError("EACCES") : err;
32487
32803
  };
32488
- const file = await this.execFile(req.file, req.cwd, this.execGuard(cred, ppid)).catch(refused3);
32804
+ const file = await this.execFile(req.file, req.cwd, this.execGuard(cred, ppid)).catch(refused4);
32489
32805
  const planned = await this.plan(file, req.argv, req.cwd, scope, req.argv0, catalogOnly);
32490
- await this.mayExec(cred, { ...req, file, pid: ppid }, planned).catch(refused3);
32806
+ await this.mayExec(cred, { ...req, file, pid: ppid }, planned).catch(refused4);
32491
32807
  if (planned) return planned;
32492
32808
  throw new SpawnError(catalogOnly ? "ENOENT" : await this.unrunnable(file, req.cwd, scope));
32493
32809
  }
@@ -34467,212 +34783,6 @@ function integrityAsker(port) {
34467
34783
  return { lookup: lookup2, answer: answer2 };
34468
34784
  }
34469
34785
 
34470
- // src/kernel/net/remote-transport.ts
34471
- var TransportError = class extends Error {
34472
- status;
34473
- code;
34474
- detail;
34475
- constructor(message3, status, code, detail) {
34476
- super(message3);
34477
- this.status = status;
34478
- this.code = code;
34479
- this.detail = detail === "transport" ? detail : void 0;
34480
- }
34481
- };
34482
- var RemoteTransport = class {
34483
- traits;
34484
- port;
34485
- waiting = /* @__PURE__ */ new Map();
34486
- nextId = 0;
34487
- sockets = /* @__PURE__ */ new Map();
34488
- uploads = /* @__PURE__ */ new Map();
34489
- failure;
34490
- constructor(port, traits) {
34491
- this.port = port;
34492
- this.traits = traits;
34493
- }
34494
- receive(reply) {
34495
- if (reply.net === "body-pull") {
34496
- void this.pull(reply.nid);
34497
- return;
34498
- }
34499
- const socket = this.sockets.get(reply.nid);
34500
- if (socket && this.toSocket(reply, socket)) return;
34501
- const waiter = this.waiting.get(reply.nid);
34502
- if (!waiter) return;
34503
- this.waiting.delete(reply.nid);
34504
- if (reply.net === "error") {
34505
- waiter.reject(new TransportError(reply.message, reply.status, reply.code, reply.detail));
34506
- } else waiter.resolve(reply);
34507
- }
34508
- toSocket(reply, socket) {
34509
- if (reply.net === "ws-message") socket.queue.push(reply.data);
34510
- else if (reply.net === "ws-acked") socket.acked(reply.n);
34511
- else if (reply.net === "ws-closed") {
34512
- this.sockets.delete(reply.nid);
34513
- socket.queue.end({ code: reply.code, reason: reply.reason });
34514
- } else return false;
34515
- return true;
34516
- }
34517
- async pull(nid) {
34518
- const upload = this.uploads.get(nid);
34519
- if (!upload) {
34520
- this.port.postMessage({ net: "body-error", nid, message: "the request body is gone" });
34521
- return;
34522
- }
34523
- try {
34524
- const next3 = await upload.next();
34525
- if (next3.done) {
34526
- this.uploads.delete(nid);
34527
- this.port.postMessage({ net: "body-end", nid });
34528
- } else this.port.postMessage({ net: "body-chunk", nid, bytes: next3.value });
34529
- } catch (e) {
34530
- this.uploads.delete(nid);
34531
- this.port.postMessage({
34532
- net: "body-error",
34533
- nid,
34534
- message: e instanceof Error ? e.message : String(e)
34535
- });
34536
- }
34537
- }
34538
- dropUpload(nid) {
34539
- const upload = this.uploads.get(nid);
34540
- this.uploads.delete(nid);
34541
- void upload?.return?.().catch(() => void 0);
34542
- }
34543
- fail(error) {
34544
- this.failure = error;
34545
- for (const nid of [...this.uploads.keys()]) this.dropUpload(nid);
34546
- for (const waiter of this.waiting.values()) waiter.reject(error);
34547
- this.waiting.clear();
34548
- for (const socket of this.sockets.values())
34549
- socket.queue.end({ code: 1011, reason: error.message });
34550
- this.sockets.clear();
34551
- }
34552
- ask(call) {
34553
- if (this.failure) return Promise.reject(this.failure);
34554
- return new Promise((resolve2, reject) => {
34555
- this.waiting.set(call.nid, { resolve: resolve2, reject });
34556
- this.port.postMessage(call);
34557
- });
34558
- }
34559
- cancel(nid) {
34560
- const waiter = this.waiting.get(nid);
34561
- this.waiting.delete(nid);
34562
- waiter?.reject(new TransportError("the request was cancelled"));
34563
- this.port.postMessage({ net: "cancel", nid });
34564
- }
34565
- async fetch(request3) {
34566
- const nid = ++this.nextId;
34567
- const { signal } = request3;
34568
- signal.throwIfAborted();
34569
- let finished = false;
34570
- const abort = () => {
34571
- finished = true;
34572
- this.dropUpload(nid);
34573
- this.cancel(nid);
34574
- };
34575
- signal.addEventListener("abort", abort, { once: true });
34576
- const finish = () => {
34577
- this.dropUpload(nid);
34578
- if (finished) return;
34579
- finished = true;
34580
- signal.removeEventListener("abort", abort);
34581
- };
34582
- if (request3.bodyStream) this.uploads.set(nid, request3.bodyStream[Symbol.asyncIterator]());
34583
- let head;
34584
- try {
34585
- head = await this.ask({
34586
- net: "fetch",
34587
- nid,
34588
- url: request3.url,
34589
- method: request3.method,
34590
- headers: request3.headers,
34591
- ...request3.bodyStream ? { streamed: true } : request3.body ? { body: request3.body } : {}
34592
- });
34593
- } catch (e) {
34594
- finish();
34595
- throw e;
34596
- }
34597
- const { status, statusText, headers, url, redirected: redirected2, redirects } = head;
34598
- const read = async () => {
34599
- if (finished) return void 0;
34600
- const reply = await this.ask({ net: "read", nid }).catch((e) => {
34601
- finish();
34602
- throw e;
34603
- });
34604
- if (reply.net === "chunk") return reply.bytes;
34605
- finish();
34606
- return void 0;
34607
- };
34608
- const cancel = async () => {
34609
- if (finished) return;
34610
- finish();
34611
- this.cancel(nid);
34612
- };
34613
- return {
34614
- ...redirected2 ? { url, redirected: redirected2 } : {},
34615
- ...redirects ? { redirects } : {},
34616
- status,
34617
- statusText,
34618
- headers,
34619
- cancel,
34620
- body: {
34621
- [Symbol.asyncIterator]: () => ({
34622
- next: async () => {
34623
- const bytes = await read();
34624
- return bytes ? { value: bytes, done: false } : { value: void 0, done: true };
34625
- },
34626
- return: async () => {
34627
- await cancel();
34628
- return { value: void 0, done: true };
34629
- }
34630
- })
34631
- }
34632
- };
34633
- }
34634
- async websocket(request3) {
34635
- const nid = ++this.nextId;
34636
- const { signal } = request3;
34637
- signal.throwIfAborted();
34638
- const abort = () => this.cancel(nid);
34639
- signal.addEventListener("abort", abort, { once: true });
34640
- let opened2;
34641
- try {
34642
- opened2 = await this.ask({
34643
- net: "ws-open",
34644
- nid,
34645
- url: request3.url,
34646
- protocols: request3.protocols,
34647
- headers: request3.headers
34648
- });
34649
- } finally {
34650
- signal.removeEventListener("abort", abort);
34651
- }
34652
- const close = (code, reason) => this.port.postMessage({ net: "ws-close", nid, code, reason });
34653
- const queue = new MessageQueue(
34654
- () => close(1e3, "a message is too big"),
34655
- Number.POSITIVE_INFINITY,
34656
- (n) => this.port.postMessage({ net: "ws-consumed", nid, n })
34657
- );
34658
- let unacked = 0;
34659
- this.sockets.set(nid, { queue, acked: (n) => void (unacked -= n) });
34660
- return {
34661
- protocol: opened2.protocol,
34662
- get buffered() {
34663
- return unacked;
34664
- },
34665
- send: (data) => {
34666
- unacked += payloadSize(data);
34667
- this.port.postMessage({ net: "ws-send", nid, data });
34668
- },
34669
- messages: queue,
34670
- close,
34671
- closed: queue.closed
34672
- };
34673
- }
34674
- };
34675
-
34676
34786
  // src/sealed-relay.ts
34677
34787
  function sealedAsker(port) {
34678
34788
  const asks = /* @__PURE__ */ new Map();