@ai-ecoverse/slicc-kernel 1.171.0 → 1.172.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -182,13 +182,13 @@ var IndexedDbMeta = class {
182
182
  return [transaction, transaction.objectStore(META_STORE)];
183
183
  }
184
184
  async get(paths) {
185
- const missing5 = paths.filter((path) => !this.cache.has(path));
186
- if (missing5.length > 0) {
185
+ const missing6 = paths.filter((path) => !this.cache.has(path));
186
+ if (missing6.length > 0) {
187
187
  this.settleRemoves();
188
188
  const generation = this.generation;
189
189
  const [transaction, store] = this.transaction("readonly");
190
190
  const found = /* @__PURE__ */ new Map();
191
- for (const path of missing5) {
191
+ for (const path of missing6) {
192
192
  const request3 = store.get(path);
193
193
  request3.onsuccess = () => void found.set(path, request3.result ?? null);
194
194
  }
@@ -1237,10 +1237,10 @@ var RemoteWatch = class {
1237
1237
  });
1238
1238
  }
1239
1239
  }
1240
- heldBy({ tab, holds: holds2, seq: seq2 }) {
1240
+ heldBy({ tab, holds: holds3, seq: seq2 }) {
1241
1241
  const from = tab;
1242
- const { add, drop } = holds2;
1243
- if (holds2?.instance !== void 0) this.instances.set(from, holds2.instance);
1242
+ const { add, drop } = holds3;
1243
+ if (holds3?.instance !== void 0) this.instances.set(from, holds3.instance);
1244
1244
  const held = this.peerHolds.get(from) ?? /* @__PURE__ */ new Map();
1245
1245
  for (const path of drop) held.delete(path);
1246
1246
  for (const [path, fid] of add) held.set(path, fid);
@@ -1524,11 +1524,11 @@ var META_OPS = ["get", "update", "move", "remove", "links", "under", "all"];
1524
1524
  var FILE_ID_TRIES = 3;
1525
1525
  function sidecar(meta) {
1526
1526
  const pathOf = ([first]) => [first, "/"].flat().find((p) => typeof p === "string");
1527
- const guarded2 = (op) => (...args) => meta[op].apply(meta, args).catch((err) => {
1527
+ const guarded3 = (op) => (...args) => meta[op].apply(meta, args).catch((err) => {
1528
1528
  throw translate(err, pathOf(args), "sidecar", false);
1529
1529
  });
1530
1530
  const names2 = meta.fresh ? [...META_OPS, "fresh"] : META_OPS;
1531
- const ops = Object.fromEntries(names2.map((op) => [op, guarded2(op)]));
1531
+ const ops = Object.fromEntries(names2.map((op) => [op, guarded3(op)]));
1532
1532
  const { updateMany } = meta;
1533
1533
  ops.updateMany = updateMany ? (changes) => updateMany.call(meta, changes).catch((err) => {
1534
1534
  throw translate(err, changes[0]?.path ?? "/", "sidecar", false);
@@ -2033,11 +2033,11 @@ var OpfsFs = class {
2033
2033
  }
2034
2034
  const found = await this.locate(path, change.follow !== false);
2035
2035
  this.refuse(found.path);
2036
- const [stored] = found.link ? [found.link] : await this.meta.get([found.path]);
2037
- const current = await this.ownerAt(found.path, stored);
2036
+ const [stored2] = found.link ? [found.link] : await this.meta.get([found.path]);
2037
+ const current = await this.ownerAt(found.path, stored2);
2038
2038
  const next3 = { uid: change.uid ?? current.uid, gid: change.gid ?? current.gid };
2039
2039
  const handing = found.handle?.kind === "directory" && !sameOwner(next3, current);
2040
- const heir = change.kind === "adopt" ? void 0 : stored?.heir ?? (handing ? [current.uid, current.gid] : void 0);
2040
+ const heir = change.kind === "adopt" ? void 0 : stored2?.heir ?? (handing ? [current.uid, current.gid] : void 0);
2041
2041
  const ctimeMs = Date.now();
2042
2042
  await this.meta.update(found.path, (entry) => {
2043
2043
  const { heir: _, ...rest2 } = entry ?? found.link ?? { path: found.path };
@@ -2053,8 +2053,8 @@ var OpfsFs = class {
2053
2053
  }
2054
2054
  async movedOwner(source) {
2055
2055
  if (!this.owners) return void 0;
2056
- const [stored] = source.link ? [source.link] : await this.meta.get([source.path]);
2057
- return ownOf(stored) ? void 0 : this.ownerAt(source.path, stored);
2056
+ const [stored2] = source.link ? [source.link] : await this.meta.get([source.path]);
2057
+ return ownOf(stored2) ? void 0 : this.ownerAt(source.path, stored2);
2058
2058
  }
2059
2059
  async walk(parts2, from, start2) {
2060
2060
  let dir = start2;
@@ -3638,12 +3638,12 @@ var OpfsFs = class {
3638
3638
  if (!move) return false;
3639
3639
  for (let attempt = 0; ; attempt++) {
3640
3640
  this.others++;
3641
- const failed3 = await move.call(handle, dir, name2).then(
3641
+ const failed4 = await move.call(handle, dir, name2).then(
3642
3642
  () => void 0,
3643
3643
  (err) => ({ err })
3644
3644
  );
3645
- if (!failed3) return true;
3646
- const error = failed3.err?.name;
3645
+ if (!failed4) return true;
3646
+ const error = failed4.err?.name;
3647
3647
  if (handle.kind !== "file" || !LOCKED.has(error)) return false;
3648
3648
  const delay2 = SYNC_BACKOFF_MS[attempt];
3649
3649
  if (delay2 === void 0) throw fsError("EBUSY", name2);
@@ -3905,6 +3905,38 @@ for (const [names2, op] of [
3905
3905
  }
3906
3906
  }
3907
3907
 
3908
+ // src/fs/portable.ts
3909
+ var privateTop = () => navigator.storage.getDirectory();
3910
+ function clonable(handle) {
3911
+ const { port1, port2 } = new MessageChannel();
3912
+ try {
3913
+ port1.postMessage(handle);
3914
+ return true;
3915
+ } catch (err) {
3916
+ if (err?.name === "DataCloneError") return false;
3917
+ throw err;
3918
+ } finally {
3919
+ port1.close();
3920
+ port2.close();
3921
+ }
3922
+ }
3923
+ async function portable(handle, top = privateTop) {
3924
+ if (clonable(handle)) return { handle };
3925
+ const path = await (await top()).resolve(handle);
3926
+ if (path === null) {
3927
+ throw new Error(
3928
+ "this browser cannot hand a folder to a worker unless it is in the origin private file system"
3929
+ );
3930
+ }
3931
+ return { path };
3932
+ }
3933
+ async function directoryAt(top, path) {
3934
+ let dir = top;
3935
+ for (const name2 of path) dir = await dir.getDirectoryHandle(name2);
3936
+ return dir;
3937
+ }
3938
+ var samePath = (a, b) => a.length === b.length && a.every((name2, at) => name2 === b[at]);
3939
+
3908
3940
  // src/fs/roots.ts
3909
3941
  var ROOTS_DB = "slicc-kernel-roots";
3910
3942
  var ROOTS_STORE = "roots";
@@ -3926,6 +3958,10 @@ async function same(a, b) {
3926
3958
  return false;
3927
3959
  }
3928
3960
  }
3961
+ async function matches(record2, root, at) {
3962
+ if (record2.handle) return same(record2.handle, root);
3963
+ return "path" in at && record2.path !== void 0 && samePath(record2.path, at.path);
3964
+ }
3929
3965
  var nameOf = (id2) => `${META_DB}:${id2}`;
3930
3966
  function done(tx) {
3931
3967
  return new Promise((resolve2, reject) => {
@@ -3959,18 +3995,19 @@ async function seed(factory, name2) {
3959
3995
  to.close();
3960
3996
  }
3961
3997
  }
3962
- async function rootId(factory, root, locks = globalThis.navigator?.locks) {
3998
+ async function rootId(factory, root, locks = globalThis.navigator?.locks, top) {
3963
3999
  const find = async () => {
4000
+ const at = await portable(root, top);
3964
4001
  const db = await open(factory);
3965
4002
  try {
3966
4003
  const all = await request(
3967
4004
  db.transaction(ROOTS_STORE, "readonly").objectStore(ROOTS_STORE).getAll()
3968
4005
  );
3969
- for (const record2 of all) if (await same(record2.handle, root)) return record2.id;
4006
+ for (const record2 of all) if (await matches(record2, root, at)) return record2.id;
3970
4007
  const id2 = crypto.randomUUID();
3971
4008
  if (await used(root)) await seed(factory, nameOf(id2));
3972
4009
  const tx = db.transaction(ROOTS_STORE, "readwrite");
3973
- tx.objectStore(ROOTS_STORE).put({ id: id2, handle: root });
4010
+ tx.objectStore(ROOTS_STORE).put({ id: id2, ...at });
3974
4011
  await done(tx);
3975
4012
  return id2;
3976
4013
  } finally {
@@ -6842,9 +6879,9 @@ var KernelSocket = class _KernelSocket {
6842
6879
  case SO_TYPE:
6843
6880
  return SOCK_STREAM;
6844
6881
  case SO_ERROR: {
6845
- const failed3 = this.failed;
6882
+ const failed4 = this.failed;
6846
6883
  this.failed = void 0;
6847
- return failed3 ? wasiErrno(failed3) : 0;
6884
+ return failed4 ? wasiErrno(failed4) : 0;
6848
6885
  }
6849
6886
  case SO_ACCEPTCONN:
6850
6887
  return this.state === "listening" ? 1 : 0;
@@ -6924,6 +6961,7 @@ var LoopbackNet = class {
6924
6961
  internal = /* @__PURE__ */ new Set();
6925
6962
  reserved = /* @__PURE__ */ new Set();
6926
6963
  facades = /* @__PURE__ */ new Map();
6964
+ proxyStamped;
6927
6965
  nextEphemeral = EPHEMERAL_FIRST;
6928
6966
  route;
6929
6967
  origins;
@@ -6998,9 +7036,15 @@ var LoopbackNet = class {
6998
7036
  this.kernelOnly(port, true);
6999
7037
  this.facades.set(port, name2);
7000
7038
  }
7001
- facadeAt(addr) {
7002
- if (addr.family !== "inet" || !isLoopback(canonicalHost(addr.host))) return void 0;
7003
- return this.facades.get(addr.port);
7039
+ stampProxy(port) {
7040
+ this.proxyStamped = port;
7041
+ }
7042
+ get originsStamped() {
7043
+ return this.proxyStamped !== void 0;
7044
+ }
7045
+ stampsPeers(addr) {
7046
+ if (addr.family !== "inet" || !isLoopback(canonicalHost(addr.host))) return false;
7047
+ return this.facades.has(addr.port) || this.proxyStamped === addr.port;
7004
7048
  }
7005
7049
  activate(addr, start2) {
7006
7050
  this.activators.set(keyOf(addr), start2);
@@ -7323,7 +7367,21 @@ function headOf(nid, response) {
7323
7367
  headers: response.headers
7324
7368
  };
7325
7369
  }
7326
- function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS2 } = {}) {
7370
+ function requestOf(call, signal, uploads) {
7371
+ const { url, method, headers, streamed, body, redirect, nid } = call;
7372
+ return {
7373
+ url,
7374
+ method,
7375
+ headers,
7376
+ ...streamed ? { bodyStream: uploads.of(nid, signal) } : body ? { body } : {},
7377
+ ...redirect !== void 0 ? { redirect } : {},
7378
+ signal
7379
+ };
7380
+ }
7381
+ function serveTransport(peer, transport, {
7382
+ closeWaitMs = CLOSE_WAIT_MS2,
7383
+ attributed = false
7384
+ } = {}) {
7327
7385
  const open2 = /* @__PURE__ */ new Map();
7328
7386
  const fail2 = (nid, e) => {
7329
7387
  open2.delete(nid);
@@ -7343,14 +7401,11 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS2 } = {})
7343
7401
  const entry = { abort };
7344
7402
  open2.set(call.nid, entry);
7345
7403
  try {
7346
- const response = await transport.fetch({
7347
- url: call.url,
7348
- method: call.method,
7349
- headers: call.headers,
7350
- ...call.streamed ? { bodyStream: uploads.of(call.nid, abort.signal) } : call.body ? { body: call.body } : {},
7351
- ...call.redirect !== void 0 ? { redirect: call.redirect } : {},
7352
- signal: abort.signal
7353
- });
7404
+ const response = await transport.fetch(
7405
+ requestOf(call, abort.signal, uploads),
7406
+ attributed ? call.owner : void 0,
7407
+ attributed ? call.stamp : void 0
7408
+ );
7354
7409
  if (!open2.has(call.nid)) {
7355
7410
  await response.cancel();
7356
7411
  return;
@@ -8504,7 +8559,7 @@ function satisfies(version, range2) {
8504
8559
  }
8505
8560
 
8506
8561
  // src/version.ts
8507
- var KERNEL_VERSION = true ? "1.171.0" : "0.0.0-dev";
8562
+ var KERNEL_VERSION = true ? "1.172.2" : "0.0.0-dev";
8508
8563
  var OS_RELEASE = "6.0.0-slicc";
8509
8564
  function procVersion() {
8510
8565
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -9161,32 +9216,32 @@ function nextFire(schedule, after, utc = false) {
9161
9216
  }
9162
9217
  return null;
9163
9218
  }
9164
- function missedFires(schedule, from, until, utc = false, cap = MISSED_CAP) {
9219
+ function missedFires(schedule, from, until2, utc = false, cap = MISSED_CAP) {
9165
9220
  let count2 = 0;
9166
9221
  let last = null;
9167
9222
  let at = from;
9168
9223
  while (count2 < cap) {
9169
9224
  at = nextFire(schedule, at, utc);
9170
- if (at === null || at > until) return { count: count2, last, more: false };
9225
+ if (at === null || at > until2) return { count: count2, last, more: false };
9171
9226
  last = at;
9172
9227
  count2++;
9173
9228
  }
9174
9229
  const next3 = nextFire(schedule, last, utc);
9175
- if (next3 === null || next3 > until) return { count: count2, last, more: false };
9176
- return { count: count2, last: latestFire(schedule, last, until, utc), more: true };
9230
+ if (next3 === null || next3 > until2) return { count: count2, last, more: false };
9231
+ return { count: count2, last: latestFire(schedule, last, until2, utc), more: true };
9177
9232
  }
9178
- function latestFire(schedule, from, until, utc = false) {
9233
+ function latestFire(schedule, from, until2, utc = false) {
9179
9234
  let found = from;
9180
9235
  for (let span = 6e4; ; span *= 2) {
9181
- const start2 = Math.max(from, until - span);
9236
+ const start2 = Math.max(from, until2 - span);
9182
9237
  const first = nextFire(schedule, start2, utc);
9183
- if (first !== null && first <= until) {
9238
+ if (first !== null && first <= until2) {
9184
9239
  found = first;
9185
9240
  break;
9186
9241
  }
9187
9242
  if (start2 === from) return from;
9188
9243
  }
9189
- for (let at = nextFire(schedule, found, utc); at !== null && at <= until; ) {
9244
+ for (let at = nextFire(schedule, found, utc); at !== null && at <= until2; ) {
9190
9245
  found = at;
9191
9246
  at = nextFire(schedule, at, utc);
9192
9247
  }
@@ -9552,14 +9607,14 @@ var UnlinkedKeeper = class {
9552
9607
  linked = /* @__PURE__ */ new Map();
9553
9608
  dirOwner;
9554
9609
  peers;
9555
- constructor(fs, holders, rootOf, options = {}) {
9610
+ constructor(fs, holders, rootOf2, options = {}) {
9556
9611
  this.peers = options.peers;
9557
9612
  this.marks = options.marks ?? new PathMarks();
9558
9613
  const { locks, owner } = options;
9559
9614
  this.dirOwner = options.dirOwner;
9560
9615
  this.fs = fs;
9561
9616
  this.holders = holders;
9562
- this.rootOf = rootOf;
9617
+ this.rootOf = rootOf2;
9563
9618
  this.locks = locks;
9564
9619
  this.busy = options.busy ?? (() => false);
9565
9620
  this.owner = owner;
@@ -9898,12 +9953,12 @@ var UnlinkedKeeper = class {
9898
9953
  return this.locks;
9899
9954
  }
9900
9955
  async undoing(op, peers, sends, heard, shared2 = []) {
9901
- let failed3;
9956
+ let failed4;
9902
9957
  let out;
9903
9958
  try {
9904
9959
  out = await op();
9905
9960
  } catch (err) {
9906
- failed3 = err ?? new Error("failed");
9961
+ failed4 = err ?? new Error("failed");
9907
9962
  await this.rollBackAsides(sends, shared2);
9908
9963
  }
9909
9964
  const hiddenShared = new Set(shared2.map((one) => one.hidden));
@@ -9924,7 +9979,7 @@ var UnlinkedKeeper = class {
9924
9979
  const done5 = () => one.release().then(() => this.dropIfLast(one.hidden));
9925
9980
  void Promise.all(waits.map(({ told }) => told)).then(done5, done5);
9926
9981
  }
9927
- if (failed3 !== void 0) throw failed3;
9982
+ if (failed4 !== void 0) throw failed4;
9928
9983
  return out;
9929
9984
  }
9930
9985
  async rollBackAsides(sends, shared2) {
@@ -10071,7 +10126,7 @@ var UnlinkedKeeper = class {
10071
10126
  // src/cron/clock.ts
10072
10127
  var systemCronClock = {
10073
10128
  now: () => Date.now(),
10074
- sleep(until, signal) {
10129
+ sleep(until2, signal) {
10075
10130
  if (signal.aborted) return Promise.resolve();
10076
10131
  return new Promise((resolve2) => {
10077
10132
  const done5 = () => {
@@ -10079,7 +10134,7 @@ var systemCronClock = {
10079
10134
  signal.removeEventListener("abort", done5);
10080
10135
  resolve2();
10081
10136
  };
10082
- const timer = setTimeout(done5, Math.max(0, until - Date.now()));
10137
+ const timer = setTimeout(done5, Math.max(0, until2 - Date.now()));
10083
10138
  timer.unref?.();
10084
10139
  signal.addEventListener("abort", done5, { once: true });
10085
10140
  });
@@ -10183,15 +10238,15 @@ var CronService = class {
10183
10238
  async pass() {
10184
10239
  if (this.wake.signal.aborted) this.wake = new AbortController();
10185
10240
  const wake = this.wake;
10186
- let until;
10241
+ let until2;
10187
10242
  try {
10188
- until = await this.tick();
10243
+ until2 = await this.tick();
10189
10244
  } catch (err) {
10190
10245
  await this.error(`cron: ${messageOf(err)}`);
10191
- until = this.clock.now() + WAKE_MS;
10246
+ until2 = this.clock.now() + WAKE_MS;
10192
10247
  }
10193
10248
  if (this.stopping.signal.aborted) return;
10194
- await this.clock.sleep(until, wake.signal);
10249
+ await this.clock.sleep(until2, wake.signal);
10195
10250
  }
10196
10251
  async provision() {
10197
10252
  const { fs, owners } = this.host;
@@ -10408,14 +10463,17 @@ var PLACEHOLDER_REFUSED = "refused: this request has a sealed placeholder in its
10408
10463
  var PlaceholderRefused = class extends Error {
10409
10464
  status = 403;
10410
10465
  code = "EACCES";
10411
- constructor() {
10412
- super(PLACEHOLDER_REFUSED);
10466
+ constructor(reason = PLACEHOLDER_REFUSED) {
10467
+ super(reason);
10413
10468
  }
10414
10469
  };
10415
- function carries(text) {
10470
+ function holds2(text, known) {
10471
+ return PLACEHOLDER.test(text) || known.some((placeholder) => text.includes(placeholder));
10472
+ }
10473
+ function carries(text, known) {
10416
10474
  let layer = text;
10417
10475
  for (let i = 0; i < PERCENT_LAYERS; i++) {
10418
- if (PLACEHOLDER.test(layer)) return true;
10476
+ if (holds2(layer, known)) return true;
10419
10477
  const next3 = layer.replace(
10420
10478
  ESCAPE,
10421
10479
  (_, hex4) => String.fromCharCode(Number.parseInt(hex4, 16))
@@ -10423,35 +10481,36 @@ function carries(text) {
10423
10481
  if (next3 === layer) return false;
10424
10482
  layer = next3;
10425
10483
  }
10426
- return PLACEHOLDER.test(layer);
10484
+ return holds2(layer, known);
10427
10485
  }
10428
- function basicCarries(value2) {
10486
+ function basicCarries(value2, known) {
10429
10487
  const credential = BASIC.exec(value2)?.[1];
10430
10488
  if (credential === void 0) return false;
10431
10489
  const letters = credential.replace(/[^A-Za-z0-9+/_-]/g, "").replaceAll("-", "+").replaceAll("_", "/");
10432
10490
  for (let shift = 0; shift < BASE64_GROUP; shift++) {
10433
10491
  const part = letters.slice(shift);
10434
10492
  const whole = part.length % BASE64_GROUP === 1 ? part.slice(0, -1) : part;
10435
- if (carries(atob(whole))) return true;
10493
+ if (carries(atob(whole), known)) return true;
10436
10494
  }
10437
10495
  return false;
10438
10496
  }
10439
- function headersCarry(headers) {
10497
+ function headersCarry(headers, known) {
10440
10498
  return headers.some(
10441
- ([name2, value2]) => carries(name2.toLowerCase()) || carries(value2) || basicCarries(value2)
10499
+ ([name2, value2]) => carries(name2, known) || carries(name2.toLowerCase(), known) || carries(value2, known) || basicCarries(value2, known)
10442
10500
  );
10443
10501
  }
10444
- function urlCarries(url) {
10445
- return carries(url) || URL.canParse(url) && carries(new URL(url).href);
10502
+ function urlCarries(url, known) {
10503
+ return carries(url, known) || URL.canParse(url) && carries(new URL(url).href, known);
10446
10504
  }
10447
- function refuse(request3) {
10448
- if (urlCarries(request3.url) || headersCarry(request3.headers)) throw new PlaceholderRefused();
10505
+ function detected(request3, known) {
10506
+ return urlCarries(request3.url, known) || headersCarry(request3.headers, known);
10449
10507
  }
10450
- function refuseSocket(request3) {
10451
- refuse(request3);
10452
- if (request3.protocols.some(carries)) throw new PlaceholderRefused();
10508
+ function refuseSocket(request3, known) {
10509
+ if (detected(request3, known) || request3.protocols.some((p) => carries(p, known))) {
10510
+ throw new PlaceholderRefused();
10511
+ }
10453
10512
  }
10454
- function placeholderFloor(inner) {
10513
+ function placeholderFloor(inner, { known = () => [], fill: fill2 } = {}) {
10455
10514
  const open2 = inner.websocket?.bind(inner);
10456
10515
  return {
10457
10516
  get traits() {
@@ -10459,13 +10518,14 @@ function placeholderFloor(inner) {
10459
10518
  },
10460
10519
  ...open2 ? {
10461
10520
  websocket: async (request3) => {
10462
- refuseSocket(request3);
10521
+ refuseSocket(request3, known());
10463
10522
  return open2(request3);
10464
10523
  }
10465
10524
  } : {},
10466
- async fetch(request3, owner) {
10467
- refuse(request3);
10468
- return inner.fetch(request3, owner);
10525
+ async fetch(request3, owner, stamp) {
10526
+ if (!detected(request3, known())) return inner.fetch(request3, owner, stamp);
10527
+ if (!fill2 || !stamp) throw new PlaceholderRefused();
10528
+ return fill2(request3, stamp);
10469
10529
  }
10470
10530
  };
10471
10531
  }
@@ -10638,14 +10698,14 @@ function tunnelTarget(req) {
10638
10698
  }
10639
10699
  return { host, port };
10640
10700
  }
10641
- async function watchHangup(conn, abort, until) {
10642
- while (!until.aborted && !abort.signal.aborted) {
10701
+ async function watchHangup(conn, abort, until2) {
10702
+ while (!until2.aborted && !abort.signal.aborted) {
10643
10703
  if (conn.poll().hangup) {
10644
10704
  abort.abort(new KernelError("EPIPE"));
10645
10705
  return;
10646
10706
  }
10647
10707
  try {
10648
- await conn.changed(until);
10708
+ await conn.changed(until2);
10649
10709
  } catch {
10650
10710
  return;
10651
10711
  }
@@ -10836,7 +10896,7 @@ var RealmProxy = class {
10836
10896
  const waiting = new AbortController();
10837
10897
  void watchHangup(ctx.socket, abort, waiting.signal);
10838
10898
  try {
10839
- response = await this.upstream(req, url, body, abort.signal, ctx.socket.peerCred?.pid);
10899
+ response = await this.upstream(req, url, body, abort.signal, ctx.socket);
10840
10900
  } finally {
10841
10901
  waiting.abort();
10842
10902
  }
@@ -10863,7 +10923,7 @@ var RealmProxy = class {
10863
10923
  await conn.write(latin1Bytes("HTTP/1.1 100 Continue\r\n\r\n"), this.stop.signal);
10864
10924
  }
10865
10925
  }
10866
- async upstream(req, url, body, signal, owner) {
10926
+ async upstream(req, url, body, signal, socket) {
10867
10927
  const sent = BODILESS_METHODS.has(req.method) ? void 0 : body;
10868
10928
  try {
10869
10929
  const fetching = this.options.transport.fetch(
@@ -10874,7 +10934,8 @@ var RealmProxy = class {
10874
10934
  ...sent instanceof Uint8Array ? { body: sent } : sent ? { bodyStream: sent } : {},
10875
10935
  signal
10876
10936
  },
10877
- owner
10937
+ socket.peerCred?.pid,
10938
+ socket.peerStamp
10878
10939
  );
10879
10940
  return await untilAborted(fetching, signal);
10880
10941
  } catch (e) {
@@ -11191,7 +11252,7 @@ async function relay(socket, conn) {
11191
11252
  // src/fs/attest.ts
11192
11253
  var ATTEST_MAX = 1024 * 1024;
11193
11254
  var UNOWNED = 1e3;
11194
- function refuse2(code, path, why) {
11255
+ function refuse(code, path, why) {
11195
11256
  throw Object.assign(new Error(`attest ${path}: ${why}`), { code });
11196
11257
  }
11197
11258
  function chainOf(path) {
@@ -11233,39 +11294,49 @@ async function trustedParents(fs, path, o) {
11233
11294
  const parents = [];
11234
11295
  for (const dir of chainOf(path).slice(0, -1)) {
11235
11296
  const st = await fs.lstat(dir);
11236
- if (st.isSymbolicLink) refuse2("EACCES", path, `${dir} is a symlink`);
11237
- if (!st.isDirectory) refuse2("ENOTDIR", path, `${dir} is not a directory`);
11297
+ if (st.isSymbolicLink) refuse("EACCES", path, `${dir} is a symlink`);
11298
+ if (!st.isDirectory) refuse("ENOTDIR", path, `${dir} is not a directory`);
11238
11299
  const perm = owned(dir, st);
11239
11300
  if (o.users !== "off" && (perm.uid !== 0 || (perm.mode & 18) !== 0)) {
11240
- refuse2("EACCES", path, `${dir} is not root-owned or is writable by group or others`);
11301
+ refuse("EACCES", path, `${dir} is not root-owned or is writable by group or others`);
11241
11302
  }
11242
11303
  parents.push(perm);
11243
11304
  }
11244
11305
  return parents;
11245
11306
  }
11307
+ function missing3(e) {
11308
+ return e?.code === "ENOENT";
11309
+ }
11246
11310
  async function attest(fs, asked, o) {
11311
+ if (o.absent !== void 0 && o.absent !== "allow") {
11312
+ refuse("EINVAL", String(asked), "absent takes only allow");
11313
+ }
11247
11314
  if (typeof asked !== "string" || !asked.startsWith("/")) {
11248
- refuse2("EINVAL", String(asked), "not an absolute path");
11315
+ refuse("EINVAL", String(asked), "not an absolute path");
11249
11316
  }
11250
11317
  const path = normalizePath(asked);
11251
11318
  const mount = o.mounts.find((target) => {
11252
11319
  const at = normalizePath(target);
11253
11320
  return at === "/" || under2(path, at);
11254
11321
  });
11255
- if (mount !== void 0) refuse2("EACCES", path, `under the mount ${mount}`);
11322
+ if (mount !== void 0) refuse("EACCES", path, `under the mount ${mount}`);
11256
11323
  const parents = await trustedParents(fs, path, o);
11257
11324
  for (let tries = 0; ; tries++) {
11258
- const before = await fs.lstat(path);
11259
- if (before.isSymbolicLink) refuse2("EACCES", path, "is a symlink");
11325
+ const before = await fs.lstat(path).catch((e) => {
11326
+ if (o.absent === "allow" && missing3(e)) return void 0;
11327
+ throw e;
11328
+ });
11329
+ if (!before) return { path, absent: true, users: o.users, onRootFs: true, parents };
11330
+ if (before.isSymbolicLink) refuse("EACCES", path, "is a symlink");
11260
11331
  if (!before.isFile)
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`);
11332
+ refuse(before.isDirectory ? "EISDIR" : "EINVAL", path, "is not a regular file");
11333
+ if (before.size > ATTEST_MAX) refuse("EFBIG", path, `is over ${ATTEST_MAX} bytes`);
11263
11334
  const bytes = (await fs.readFileBuffer(path)).slice();
11264
11335
  const after = await fs.lstat(path);
11265
11336
  if (unchanged(before, after, bytes)) {
11266
11337
  return attested(path, after, bytes, await sha2562(bytes), o, parents);
11267
11338
  }
11268
- if (tries >= 1) refuse2("EAGAIN", path, "changed while it was read");
11339
+ if (tries >= 1) refuse("EAGAIN", path, "changed while it was read");
11269
11340
  }
11270
11341
  }
11271
11342
  var WATCH_DEBOUNCE_MS = 50;
@@ -11324,7 +11395,7 @@ var S_IFREG2 = 32768;
11324
11395
  var COMMAND = /^\/(?:usr\/)?bin\/([^/]+)$/;
11325
11396
  var MAX_LINKS6 = 40;
11326
11397
  var BIN_ENTRY = /\/bin\/[^/]+$/;
11327
- function missing3(err) {
11398
+ function missing4(err) {
11328
11399
  return err?.code === "ENOENT";
11329
11400
  }
11330
11401
  function synthetic(directory, path) {
@@ -11428,7 +11499,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
11428
11499
  }
11429
11500
  async function entryTarget(path) {
11430
11501
  if (!BIN_ENTRY.test(path) || !(await virtual(path))?.isFile) return void 0;
11431
- if (!await fs.lstat(path).then(() => false, missing3)) return void 0;
11502
+ if (!await fs.lstat(path).then(() => false, missing4)) return void 0;
11432
11503
  const target = await targetOf2(path);
11433
11504
  return target?.path === path ? void 0 : target;
11434
11505
  }
@@ -11440,11 +11511,11 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
11440
11511
  return target?.path;
11441
11512
  }
11442
11513
  const absent2 = (err) => {
11443
- if (missing3(err)) return EMPTY2;
11514
+ if (missing4(err)) return EMPTY2;
11444
11515
  throw err;
11445
11516
  };
11446
11517
  async function content(path, err) {
11447
- if (!missing3(err) || !(await linked2(path))?.isFile) throw err;
11518
+ if (!missing4(err) || !(await linked2(path))?.isFile) throw err;
11448
11519
  const target = await redirected2(path);
11449
11520
  return target === void 0 ? EMPTY2 : fs.readFileBuffer(target).catch(absent2);
11450
11521
  }
@@ -11453,7 +11524,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
11453
11524
  try {
11454
11525
  return await real(path);
11455
11526
  } catch (err) {
11456
- const found = missing3(err) ? await linked2(path) : void 0;
11527
+ const found = missing4(err) ? await linked2(path) : void 0;
11457
11528
  if (found) return found;
11458
11529
  throw err;
11459
11530
  }
@@ -11478,7 +11549,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
11478
11549
  const extra = await children3(path);
11479
11550
  if (!extra) return fs.readdir(path);
11480
11551
  const real = await fs.readdir(path).catch((err) => {
11481
- if (missing3(err)) return [];
11552
+ if (missing4(err)) return [];
11482
11553
  throw err;
11483
11554
  });
11484
11555
  return [.../* @__PURE__ */ new Set([...real, ...extra])].sort();
@@ -11487,7 +11558,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
11487
11558
  const extra = await children3(path);
11488
11559
  if (!extra) return fs.readdirStat(path);
11489
11560
  const real = await fs.readdirStat(path).catch((err) => {
11490
- if (missing3(err)) return [];
11561
+ if (missing4(err)) return [];
11491
11562
  throw err;
11492
11563
  });
11493
11564
  const seen = new Set(real.map(([name2]) => name2));
@@ -11521,7 +11592,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
11521
11592
  ...ranged2 ? {
11522
11593
  ...ranged2,
11523
11594
  pread: (path, offset, length2, version) => ranged2.pread(path, offset, length2, version).catch(async (err) => {
11524
- const target = missing3(err) ? await redirected2(path) : void 0;
11595
+ const target = missing4(err) ? await redirected2(path) : void 0;
11525
11596
  if (target === void 0) throw err;
11526
11597
  return ranged2.pread(target, offset, length2).catch(absent2);
11527
11598
  })
@@ -11552,7 +11623,7 @@ var S_IFREG3 = 32768;
11552
11623
  var MAX_HOPS2 = 40;
11553
11624
  var parentOf6 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
11554
11625
  var baseOf2 = (path) => path.slice(path.lastIndexOf("/") + 1);
11555
- function missing4(err) {
11626
+ function missing5(err) {
11556
11627
  return err?.code === "ENOENT";
11557
11628
  }
11558
11629
  function statOf(path, bytes) {
@@ -11605,11 +11676,11 @@ function withEtcFiles(fs, files) {
11605
11676
  const text = files.get(path)?.();
11606
11677
  return text === void 0 ? void 0 : new TextEncoder().encode(text);
11607
11678
  };
11608
- const absent2 = (path) => fs.lstat(path).then(() => false, missing4);
11679
+ const absent2 = (path) => fs.lstat(path).then(() => false, missing5);
11609
11680
  const follow2 = linkFollower(fs, files);
11610
11681
  const listedAbsent = async (path) => files.has(path) && await absent2(path) ? bytesOf2(path) : void 0;
11611
11682
  const fallback = (path, make) => async (err) => {
11612
- const at = missing4(err) ? await follow2(path) : void 0;
11683
+ const at = missing5(err) ? await follow2(path) : void 0;
11613
11684
  const bytes = at === void 0 ? void 0 : await listedAbsent(at);
11614
11685
  if (bytes === void 0 || at === void 0) throw err;
11615
11686
  return make(bytes, at);
@@ -13509,29 +13580,29 @@ var HeldSet = class extends Set {
13509
13580
  this.idle = idle2;
13510
13581
  this.moved = moved2;
13511
13582
  }
13512
- add(holds2) {
13513
- holds2.onIdle = this.idle;
13514
- holds2.onMoved = this.moved;
13515
- return super.add(holds2);
13583
+ add(holds3) {
13584
+ holds3.onIdle = this.idle;
13585
+ holds3.onMoved = this.moved;
13586
+ return super.add(holds3);
13516
13587
  }
13517
13588
  doubt(paths, over) {
13518
- for (const holds2 of this) {
13519
- for (const path of paths) holds2.doubt(path, true);
13520
- if (over !== void 0) holds2.doubt(over);
13589
+ for (const holds3 of this) {
13590
+ for (const path of paths) holds3.doubt(path, true);
13591
+ if (over !== void 0) holds3.doubt(over);
13521
13592
  }
13522
13593
  }
13523
13594
  async bindIds(id2) {
13524
- for (const holds2 of [...this]) await holds2.bindIds(id2);
13595
+ for (const holds3 of [...this]) await holds3.bindIds(id2);
13525
13596
  }
13526
13597
  heldIds() {
13527
13598
  const out = /* @__PURE__ */ new Map();
13528
- for (const holds2 of this) for (const [path, fid] of holds2.heldIds()) out.set(path, fid);
13599
+ for (const holds3 of this) for (const [path, fid] of holds3.heldIds()) out.set(path, fid);
13529
13600
  return [...out];
13530
13601
  }
13531
- delete(holds2) {
13532
- const removed = super.delete(holds2);
13533
- for (const path of /* @__PURE__ */ new Set([...holds2.keys(), ...holds2.opens.keys()])) this.idle(path);
13534
- holds2.releaseAll();
13602
+ delete(holds3) {
13603
+ const removed = super.delete(holds3);
13604
+ for (const path of /* @__PURE__ */ new Set([...holds3.keys(), ...holds3.opens.keys()])) this.idle(path);
13605
+ holds3.releaseAll();
13535
13606
  return removed;
13536
13607
  }
13537
13608
  };
@@ -15232,7 +15303,7 @@ async function timesOf(entry, path, req) {
15232
15303
  const st = await look.call(entry.fs, path).catch(() => void 0);
15233
15304
  if (!st || (st.uid ?? 0) === g.cred.euid) return given;
15234
15305
  const now = /* @__PURE__ */ new Date();
15235
- const kept = (ms, stored) => ms === stored.getTime() ? stored : now;
15306
+ const kept = (ms, stored2) => ms === stored2.getTime() ? stored2 : now;
15236
15307
  return [kept(req.atimeMs, st.atime), kept(req.mtimeMs, st.mtime)];
15237
15308
  }
15238
15309
  function guardOf(entry) {
@@ -16422,9 +16493,9 @@ var SYS_TREE = {
16422
16493
  `,
16423
16494
  slicc_file_ids: (listing) => `${listing.fileIds ?? 0}
16424
16495
  `,
16425
- slicc_peer_holds: ({ holds: holds2 }) => `${holds2?.mine ?? 0} ${holds2?.peers ?? 0} ${holds2?.sent ?? 0}
16496
+ slicc_peer_holds: ({ holds: holds3 }) => `${holds3?.mine ?? 0} ${holds3?.peers ?? 0} ${holds3?.sent ?? 0}
16426
16497
  `,
16427
- slicc_peer_held: ({ holds: holds2 }) => (holds2?.held ?? []).map((path) => `${path}
16498
+ slicc_peer_held: ({ holds: holds3 }) => (holds3?.held ?? []).map((path) => `${path}
16428
16499
  `).join(""),
16429
16500
  slicc_rename_acks: (listing) => {
16430
16501
  const samples = [...listing.renameAcks?.ackMs ?? []].sort((a, b) => a - b);
@@ -17165,11 +17236,11 @@ var EpollFile = class _EpollFile {
17165
17236
  const round = new AbortController();
17166
17237
  const stop = () => round.abort();
17167
17238
  signal.addEventListener("abort", stop, { once: true });
17168
- let failed3 = false;
17239
+ let failed4 = false;
17169
17240
  try {
17170
17241
  await file.changed(round.signal);
17171
17242
  } catch {
17172
- failed3 = true;
17243
+ failed4 = true;
17173
17244
  } finally {
17174
17245
  round.abort();
17175
17246
  signal.removeEventListener("abort", stop);
@@ -17177,7 +17248,7 @@ var EpollFile = class _EpollFile {
17177
17248
  if (signal.aborted) return;
17178
17249
  reg.gen++;
17179
17250
  this.changes.wake();
17180
- if (failed3) await pause(RETRY_MS, signal);
17251
+ if (failed4) await pause(RETRY_MS, signal);
17181
17252
  }
17182
17253
  }
17183
17254
  };
@@ -18158,11 +18229,11 @@ function ipv6(host) {
18158
18229
  const back = halves.length === 2 ? groups(halves[1]) : [];
18159
18230
  if (![...head, ...back].every((g) => /^[0-9A-Fa-f]{1,4}$/.test(g))) return void 0;
18160
18231
  const words2 = [...head, ...back].map((g) => Number.parseInt(g, 16));
18161
- const missing5 = 8 - words2.length - tail2.length;
18162
- if (halves.length === 2 ? missing5 < 1 : missing5 !== 0) return void 0;
18232
+ const missing6 = 8 - words2.length - tail2.length;
18233
+ if (halves.length === 2 ? missing6 < 1 : missing6 !== 0) return void 0;
18163
18234
  const all = [
18164
18235
  ...head.map((g) => Number.parseInt(g, 16)),
18165
- ...new Array(halves.length === 2 ? missing5 : 0).fill(0),
18236
+ ...new Array(halves.length === 2 ? missing6 : 0).fill(0),
18166
18237
  ...back.map((g) => Number.parseInt(g, 16)),
18167
18238
  ...tail2
18168
18239
  ];
@@ -18252,19 +18323,19 @@ function indexedDbCaStore(dbName = "slicc-realm-ca") {
18252
18323
  async swap(owner, expected, record2) {
18253
18324
  const tx = (await open2()).transaction("ca", "readwrite");
18254
18325
  const store = tx.objectStore("ca");
18255
- let stored = record2;
18326
+ let stored2 = record2;
18256
18327
  const read = store.get(owner);
18257
18328
  read.onsuccess = () => {
18258
18329
  const current = read.result;
18259
18330
  const kept = winner(current, expected, record2);
18260
18331
  if (kept === record2) store.put(record2, owner);
18261
- else stored = kept;
18332
+ else stored2 = kept;
18262
18333
  };
18263
18334
  await new Promise((resolve2, reject) => {
18264
18335
  tx.oncomplete = () => resolve2();
18265
18336
  tx.onerror = () => reject(tx.error);
18266
18337
  });
18267
- return stored;
18338
+ return stored2;
18268
18339
  }
18269
18340
  };
18270
18341
  }
@@ -18281,10 +18352,10 @@ var RealmCa = class _RealmCa {
18281
18352
  this.record = record2;
18282
18353
  }
18283
18354
  static async open(owner, store, now = Date.now()) {
18284
- const stored = await store.get(owner).catch(() => void 0);
18285
- if (stored && stored.notAfter - now > CA_RENEW_BEFORE) return new _RealmCa(stored);
18355
+ const stored2 = await store.get(owner).catch(() => void 0);
18356
+ if (stored2 && stored2.notAfter - now > CA_RENEW_BEFORE) return new _RealmCa(stored2);
18286
18357
  const record2 = await _RealmCa.create(owner, now);
18287
- return new _RealmCa(await store.swap(owner, stored, record2));
18358
+ return new _RealmCa(await store.swap(owner, stored2, record2));
18288
18359
  }
18289
18360
  static async create(owner, now) {
18290
18361
  const pair = await crypto.subtle.generateKey(ECDSA, false, ["sign", "verify"]);
@@ -19207,10 +19278,12 @@ var HttpHandles = class {
19207
19278
  ws;
19208
19279
  owner;
19209
19280
  local;
19210
- constructor(transport, owner, local2) {
19281
+ stamp;
19282
+ constructor(transport, owner, local2, stamp) {
19211
19283
  this.transport = transport;
19212
19284
  this.owner = owner;
19213
19285
  this.local = local2;
19286
+ this.stamp = stamp;
19214
19287
  this.ws = new WsHandles(transport, () => ++this.nextHandle, local2);
19215
19288
  }
19216
19289
  syscall(req) {
@@ -19286,7 +19359,7 @@ var HttpHandles = class {
19286
19359
  ...entry.upload ? { bodyStream: entry.upload } : req.body ? { body: req.body } : {},
19287
19360
  signal: entry.abort.signal
19288
19361
  };
19289
- const response = port === void 0 ? await this.transport.fetch(request3, this.owner) : await this.local.fetch(request3, port);
19362
+ const response = port === void 0 ? await this.transport.fetch(request3, this.owner, await this.stamp?.()) : await this.local.fetch(request3, port);
19290
19363
  entry.body = response.body[Symbol.asyncIterator]();
19291
19364
  entry.cancel = () => response.cancel();
19292
19365
  if (!this.open.has(handle)) await entry.cancel().catch(() => void 0);
@@ -19308,8 +19381,8 @@ var HttpHandles = class {
19308
19381
  if (text === NO_TRANSPORT || typeof status !== "number" || status === 502) {
19309
19382
  const code = codeOf2(e);
19310
19383
  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" } : {} };
19384
+ const failed4 = e.detail === "transport";
19385
+ return { ok: false, errno: errno3, message: text, ...failed4 ? { detail: "transport" } : {} };
19313
19386
  }
19314
19387
  entry.body = once(new TextEncoder().encode(text))[Symbol.asyncIterator]();
19315
19388
  return this.headOf(handle, req.url, {
@@ -21216,7 +21289,7 @@ function pass(c, input, final) {
21216
21289
  const partials = [];
21217
21290
  scanMain(c, input, best, partials);
21218
21291
  scanWrapped(c, input, best, partials);
21219
- const holds2 = final ? [] : [...new Set(partials)].sort((a, b) => a - b);
21292
+ const holds3 = final ? [] : [...new Set(partials)].sort((a, b) => a - b);
21220
21293
  const starts = [...best.keys()].sort((a, b) => a - b);
21221
21294
  const parts2 = [];
21222
21295
  const hits = /* @__PURE__ */ new Map();
@@ -21226,8 +21299,8 @@ function pass(c, input, final) {
21226
21299
  let h = 0;
21227
21300
  for (; ; ) {
21228
21301
  while (s < starts.length && starts[s] < pos) s++;
21229
- while (h < holds2.length && holds2[h] < pos) h++;
21230
- const hold = h < holds2.length ? holds2[h] : Infinity;
21302
+ while (h < holds3.length && holds3[h] < pos) h++;
21303
+ const hold = h < holds3.length ? holds3[h] : Infinity;
21231
21304
  const next3 = s < starts.length ? starts[s] : Infinity;
21232
21305
  if (hold <= next3) {
21233
21306
  cut = Math.min(hold, input.length);
@@ -21329,23 +21402,23 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
21329
21402
  let pending = 0;
21330
21403
  let busy = false;
21331
21404
  let timer;
21332
- let failed3;
21405
+ let failed4;
21333
21406
  const waiters = /* @__PURE__ */ new Set();
21334
21407
  const quiet2 = () => !busy && pending === 0;
21335
21408
  const wake = () => {
21336
21409
  for (const waiter of [...waiters]) waiter();
21337
21410
  };
21338
21411
  const raise = () => {
21339
- if (failed3 === void 0) return;
21340
- const err = failed3;
21341
- failed3 = void 0;
21412
+ if (failed4 === void 0) return;
21413
+ const err = failed4;
21414
+ failed4 = void 0;
21342
21415
  throw err;
21343
21416
  };
21344
21417
  const later = (bytes) => {
21345
21418
  if (bytes.length === 0) return;
21346
21419
  pending += 1;
21347
21420
  tail2 = tail2.then(() => writeAll3(file, bytes)).catch((err) => {
21348
- if (failed3 === void 0) failed3 = err;
21421
+ if (failed4 === void 0) failed4 = err;
21349
21422
  }).finally(() => {
21350
21423
  pending -= 1;
21351
21424
  if (quiet2()) wake();
@@ -22727,15 +22800,15 @@ async function scramKeys(password, x) {
22727
22800
  )
22728
22801
  );
22729
22802
  const clientKey = await hmac(salted, encoder9.encode("Client Key"));
22730
- const stored = new Uint8Array(
22803
+ const stored2 = new Uint8Array(
22731
22804
  await crypto.subtle.digest("SHA-256", clientKey)
22732
22805
  );
22733
22806
  const auth = encoder9.encode(`${x.clientFirstBare},${x.serverFirst},${x.clientFinalBare}`);
22734
- const signature = await hmac(stored, auth);
22807
+ const signature = await hmac(stored2, auth);
22735
22808
  const proof = clientKey.map((b, i) => b ^ signature[i]);
22736
22809
  const serverKey = await hmac(salted, encoder9.encode("Server Key"));
22737
22810
  const serverSignature = await hmac(serverKey, auth);
22738
- for (const k of [salted, clientKey, stored, signature, serverKey]) k.fill(0);
22811
+ for (const k of [salted, clientKey, stored2, signature, serverKey]) k.fill(0);
22739
22812
  return { proof, serverSignature };
22740
22813
  }
22741
22814
  var SPACES = /[\u00A0\u1680\u2000-\u200B\u202F\u205F\u3000]/g;
@@ -24420,7 +24493,7 @@ async function connect(req, proc) {
24420
24493
  }
24421
24494
  const path = filePath(req.addr);
24422
24495
  const name2 = path !== void 0 ? await proc.names?.find(path) : void 0;
24423
- const stamp = proc.net.facadeAt(req.addr) && await proc.stamp?.();
24496
+ const stamp = proc.net.stampsPeers(req.addr) && await proc.stamp?.();
24424
24497
  const dialing = target.connect(req.addr, true, proc.cred?.(), stamp || void 0, true, name2);
24425
24498
  if (req.nonblock) {
24426
24499
  dialing?.catch(() => void 0);
@@ -24542,7 +24615,7 @@ async function secureConnect(req, proc) {
24542
24615
  delete req.clientCert;
24543
24616
  throw new KernelError("ENOTSUP");
24544
24617
  }
24545
- return { ...tlsOverTransport(req, proc), path: "transport", substitutes: true };
24618
+ return { ...await tlsOverTransport(req, proc), path: "transport", substitutes: true };
24546
24619
  }
24547
24620
  const socket = proc.net.socket("inet");
24548
24621
  const fd = proc.fds.install(new OpenFile(socket), 3);
@@ -24561,7 +24634,7 @@ async function uplinked(proc, host) {
24561
24634
  return false;
24562
24635
  }
24563
24636
  }
24564
- function tlsOverTransport(req, proc) {
24637
+ async function tlsOverTransport(req, proc) {
24565
24638
  if (req.ca) throw new KernelError("ENOTSUP");
24566
24639
  if (req.alpn && req.alpn.length > 0 && !req.alpn.includes("http/1.1")) {
24567
24640
  throw new KernelError("EPROTONOSUPPORT");
@@ -24574,7 +24647,9 @@ function tlsOverTransport(req, proc) {
24574
24647
  if (isLoopbackHost(servername) || isLoopbackHost(req.host)) throw new KernelError("ENOTSUP");
24575
24648
  const host = servername.includes(":") && !servername.startsWith("[") ? `[${servername}]` : servername;
24576
24649
  const origin = req.port === 443 ? `https://${host}` : `https://${host}:${req.port}`;
24650
+ const stamp = proc.net.originsStamped ? await proc.stamp?.() : void 0;
24577
24651
  const [mine, theirs] = KernelSocket.pair(proc.net, "inet", proc.cred?.());
24652
+ theirs.peerStamp = stamp;
24578
24653
  mine.peer = { family: "inet", host: req.host, port: req.port };
24579
24654
  try {
24580
24655
  proc.net.serveOrigin(theirs, origin);
@@ -27733,13 +27808,13 @@ function inherited(opts) {
27733
27808
  ...opts.cred ? { cred: opts.cred } : {}
27734
27809
  };
27735
27810
  }
27736
- function heldBy(process, holds2, replacements) {
27737
- process.keptPath = (path) => holds2.keptAt(path)?.hidden;
27738
- process.keptHandle = (handle) => holds2.keptFor(handle)?.hidden;
27739
- process.holdsHandle = (handle) => holds2.holdsHandle(handle);
27811
+ function heldBy(process, holds3, replacements) {
27812
+ process.keptPath = (path) => holds3.keptAt(path)?.hidden;
27813
+ process.keptHandle = (handle) => holds3.keptFor(handle)?.hidden;
27814
+ process.holdsHandle = (handle) => holds3.holdsHandle(handle);
27740
27815
  if (replacements) process.replacements = replacements;
27741
27816
  }
27742
- function holdingToken(opts, holds2, caller) {
27817
+ function holdingToken(opts, holds3, caller) {
27743
27818
  return mintSyncFsToken({
27744
27819
  ...opts.owners ? caller : { umask: caller.umask },
27745
27820
  ...opts.dac ? { dac: opts.dac, pid: opts.pid, created: caller.created } : {},
@@ -27756,16 +27831,16 @@ function holdingToken(opts, holds2, caller) {
27756
27831
  ...opts.fileId ? { fileId: opts.fileId } : {},
27757
27832
  ...opts.announceHold ? { announceHold: opts.announceHold } : {},
27758
27833
  ...opts.renameSeq ? { renameSeq: opts.renameSeq } : {},
27759
- hold: (path, on, open2, real, handle, ino, fid) => holds2.hold(path, on, open2, real, handle, ino, fid),
27760
- boundIno: holds2.boundIno.bind(holds2),
27761
- trust: holds2.trust.bind(holds2),
27762
- keptFor: (handle) => holds2.keptFor(handle),
27763
- heldAt: (handle) => holds2.pathOf(handle),
27764
- unlinked: (path) => holds2.keptAt(path),
27765
- gate: (path, op) => opts.unlinkGate && holds2.holding(path) ? opts.unlinkGate.run(holds2.keyOf(path), op) : op(),
27766
- own: (path, op) => holds2.own(path, op),
27767
- revoked: (path) => holds2.isRevoked(path),
27768
- renamed: (from, to) => holds2.renamed(from, to)
27834
+ hold: (path, on, open2, real, handle, ino, fid) => holds3.hold(path, on, open2, real, handle, ino, fid),
27835
+ boundIno: holds3.boundIno.bind(holds3),
27836
+ trust: holds3.trust.bind(holds3),
27837
+ keptFor: (handle) => holds3.keptFor(handle),
27838
+ heldAt: (handle) => holds3.pathOf(handle),
27839
+ unlinked: (path) => holds3.keptAt(path),
27840
+ gate: (path, op) => opts.unlinkGate && holds3.holding(path) ? opts.unlinkGate.run(holds3.keyOf(path), op) : op(),
27841
+ own: (path, op) => holds3.own(path, op),
27842
+ revoked: (path) => holds3.isRevoked(path),
27843
+ renamed: (from, to) => holds3.renamed(from, to)
27769
27844
  });
27770
27845
  }
27771
27846
  function linksOf(opts) {
@@ -27922,15 +27997,15 @@ function spawnWasmProcess(opts) {
27922
27997
  )
27923
27998
  );
27924
27999
  publishStops(process, header4);
27925
- const holds2 = new HeldPaths();
27926
- opts.held?.add(holds2);
27927
- const token = holdingToken(opts, holds2, {
28000
+ const holds3 = new HeldPaths();
28001
+ opts.held?.add(holds3);
28002
+ const token = holdingToken(opts, holds3, {
27928
28003
  cred: () => process.cred,
27929
28004
  umask: () => process.umask,
27930
28005
  created: created4,
27931
- holdsKept: async (path) => path.includes(`/${UNLINKED_DIR}/`) && (holds2.keeps(path) || await process.holds(path))
28006
+ holdsKept: async (path) => path.includes(`/${UNLINKED_DIR}/`) && (holds3.keeps(path) || await process.holds(path))
27932
28007
  });
27933
- heldBy(process, holds2, opts.replacements);
28008
+ heldBy(process, holds3, opts.replacements);
27934
28009
  const worker = opts.createWorker();
27935
28010
  const dying = new Dying();
27936
28011
  const dispatch2 = (req, block) => dying.serve(
@@ -27962,7 +28037,7 @@ function spawnWasmProcess(opts) {
27962
28037
  responder.dispose();
27963
28038
  lane?.dispose();
27964
28039
  revokeSyncFsToken(token);
27965
- opts.held?.delete(holds2);
28040
+ opts.held?.delete(holds3);
27966
28041
  worker.terminate();
27967
28042
  settleExit(process.exit(), settle3, code);
27968
28043
  };
@@ -29148,7 +29223,7 @@ var RemoteTransport = class {
29148
29223
  waiter?.reject(new TransportError("the request was cancelled"));
29149
29224
  this.port.postMessage({ net: "cancel", nid });
29150
29225
  }
29151
- async fetch(request3) {
29226
+ async fetch(request3, owner, stamp) {
29152
29227
  const nid = ++this.nextId;
29153
29228
  const { signal, redirect } = request3;
29154
29229
  signal.throwIfAborted();
@@ -29178,7 +29253,9 @@ var RemoteTransport = class {
29178
29253
  method: request3.method,
29179
29254
  headers: request3.headers,
29180
29255
  ...request3.bodyStream ? { streamed: true } : request3.body ? { body: request3.body } : {},
29181
- ...redirect !== void 0 ? { redirect } : {}
29256
+ ...redirect !== void 0 ? { redirect } : {},
29257
+ ...owner !== void 0 ? { owner } : {},
29258
+ ...stamp ? { stamp } : {}
29182
29259
  });
29183
29260
  } catch (e) {
29184
29261
  finish();
@@ -29369,6 +29446,143 @@ function replayingHops(inner, heldMs = HELD_MS) {
29369
29446
  };
29370
29447
  }
29371
29448
 
29449
+ // src/kernel/net/sealed-fetch.ts
29450
+ var UNSAFE_FIELD = /[\r\n\0]/;
29451
+ function headerList(headers) {
29452
+ return Array.isArray(headers) && headers.every(
29453
+ (field4) => Array.isArray(field4) && field4.length === 2 && field4.every((text) => typeof text === "string" && !UNSAFE_FIELD.test(text))
29454
+ );
29455
+ }
29456
+ function sealedReplyValid(reply) {
29457
+ if (typeof reply !== "object" || reply === null) return false;
29458
+ const { redirects, redirected: redirected2, status, statusText, headers, url, body, cancel } = reply;
29459
+ return redirects === void 0 && redirected2 !== true && Number.isInteger(status) && status >= 100 && status <= 599 && typeof statusText === "string" && !UNSAFE_FIELD.test(statusText) && headerList(headers) && (url === void 0 || typeof url === "string") && typeof body?.[Symbol.asyncIterator] === "function" && typeof cancel === "function";
29460
+ }
29461
+ function dropSealedReply(reply) {
29462
+ const { cancel } = reply ?? {};
29463
+ if (typeof cancel !== "function") return;
29464
+ void Promise.resolve().then(() => cancel.call(reply)).catch(() => void 0);
29465
+ }
29466
+ function failed2(reason) {
29467
+ const text = reason instanceof Error ? reason.message : String(reason);
29468
+ return new PlaceholderRefused(
29469
+ `refused: the request with a sealed placeholder was not completed: ${text}`
29470
+ );
29471
+ }
29472
+ var Stall = class {
29473
+ idle = new AbortController();
29474
+ ms;
29475
+ timer;
29476
+ signal;
29477
+ constructor(signals, ms) {
29478
+ this.ms = ms;
29479
+ this.signal = AbortSignal.any([...signals, this.idle.signal]);
29480
+ }
29481
+ arm() {
29482
+ clearTimeout(this.timer);
29483
+ this.timer = setTimeout(() => this.idle.abort("timeout"), this.ms);
29484
+ this.timer.unref?.();
29485
+ }
29486
+ touch() {
29487
+ if (this.timer !== void 0) this.arm();
29488
+ }
29489
+ rest() {
29490
+ clearTimeout(this.timer);
29491
+ this.timer = void 0;
29492
+ }
29493
+ };
29494
+ async function until(work, signal) {
29495
+ const stopped = Promise.withResolvers();
29496
+ const stop = () => stopped.reject(signal.reason);
29497
+ if (signal.aborted) stop();
29498
+ else signal.addEventListener("abort", stop, { once: true });
29499
+ try {
29500
+ return await Promise.race([work, stopped.promise]);
29501
+ } finally {
29502
+ signal.removeEventListener("abort", stop);
29503
+ }
29504
+ }
29505
+ async function* ticking(stream, stall) {
29506
+ for await (const chunk2 of stream) {
29507
+ stall.touch();
29508
+ yield chunk2;
29509
+ }
29510
+ }
29511
+ function sealedRequest(request3, stamp, stall) {
29512
+ const { method, url, headers, body, bodyStream } = request3;
29513
+ return {
29514
+ v: 1,
29515
+ caller: structuredClone(stamp),
29516
+ method,
29517
+ url,
29518
+ headers: headers.map(([name2, value2]) => [name2, value2]),
29519
+ redirect: "manual",
29520
+ ...bodyStream ? { bodyStream: ticking(bodyStream, stall) } : body ? { body } : {}
29521
+ };
29522
+ }
29523
+ function guarded2(reply, stall) {
29524
+ let finished = false;
29525
+ const cancel = async () => {
29526
+ stall.signal.removeEventListener("abort", dropped2);
29527
+ stall.rest();
29528
+ if (finished) return;
29529
+ finished = true;
29530
+ await reply.cancel().catch(() => void 0);
29531
+ };
29532
+ const dropped2 = () => void cancel();
29533
+ stall.signal.addEventListener("abort", dropped2, { once: true });
29534
+ const source = reply.body[Symbol.asyncIterator]();
29535
+ const body = (async function* () {
29536
+ try {
29537
+ for (; ; ) {
29538
+ stall.arm();
29539
+ const next3 = await until(source.next(), stall.signal);
29540
+ stall.rest();
29541
+ if (next3.done) {
29542
+ finished = true;
29543
+ return;
29544
+ }
29545
+ if (!(next3.value instanceof Uint8Array)) throw failed2("a body chunk is not bytes");
29546
+ if (next3.value.byteLength > 0) yield next3.value;
29547
+ }
29548
+ } finally {
29549
+ await cancel();
29550
+ }
29551
+ })();
29552
+ return {
29553
+ ...reply.url !== void 0 ? { url: reply.url } : {},
29554
+ status: reply.status,
29555
+ statusText: reply.statusText,
29556
+ headers: reply.headers,
29557
+ body,
29558
+ cancel
29559
+ };
29560
+ }
29561
+ function sealedFetcher(hook, stop, idleMs = BODY_IDLE_MS) {
29562
+ return async (request3, stamp) => {
29563
+ const stall = new Stall([request3.signal, stop], idleMs);
29564
+ const { signal } = stall;
29565
+ if (signal.aborted) throw failed2(signal.reason);
29566
+ stall.arm();
29567
+ const asked = Promise.resolve().then(() => {
29568
+ signal.throwIfAborted();
29569
+ return hook(sealedRequest(request3, stamp, stall), { signal });
29570
+ });
29571
+ let reply;
29572
+ try {
29573
+ reply = await until(asked, signal);
29574
+ } catch (e) {
29575
+ void asked.then(dropSealedReply, () => void 0);
29576
+ throw failed2(e);
29577
+ } finally {
29578
+ stall.rest();
29579
+ }
29580
+ if (sealedReplyValid(reply)) return guarded2(reply, stall);
29581
+ dropSealedReply(reply);
29582
+ throw failed2("the reply is not a scrubbed response");
29583
+ };
29584
+ }
29585
+
29372
29586
  // src/kernel/package-swaps.ts
29373
29587
  var SWAP_GAP_MS = 2e3;
29374
29588
  var STAGES = ["_tmp_", "_pacquet-stage_"];
@@ -29541,11 +29755,11 @@ var PackageLocks = class {
29541
29755
  if (!locks) return Promise.resolve(() => {
29542
29756
  });
29543
29757
  const { promise: held, resolve: release } = Promise.withResolvers();
29544
- return new Promise((granted2, failed3) => {
29758
+ return new Promise((granted2, failed4) => {
29545
29759
  locks.request(replacingLock(this.metadata, root), { mode: "exclusive" }, () => {
29546
29760
  granted2(() => release());
29547
29761
  return held;
29548
- }).catch(failed3);
29762
+ }).catch(failed4);
29549
29763
  });
29550
29764
  }
29551
29765
  };
@@ -30147,22 +30361,22 @@ async function mountFstab(lines2, mount, signal, retries = FSTAB_RETRIES, discar
30147
30361
  );
30148
30362
  }
30149
30363
  async function mountLine({ line, spec, invalid }, mount, signal, retries, discard) {
30150
- let failed3 = invalid;
30364
+ let failed4 = invalid;
30151
30365
  for (let attempt = 0; !invalid && attempt <= retries.length && !signal.aborted; attempt++) {
30152
30366
  try {
30153
30367
  const entry = await mount(spec);
30154
30368
  if (!signal.aborted) return { line, target: spec.target, entry };
30155
30369
  discard(entry);
30156
- failed3 = Object.assign(new Error("the kernel stopped"), { code: "ECANCELED" });
30370
+ failed4 = Object.assign(new Error("the kernel stopped"), { code: "ECANCELED" });
30157
30371
  break;
30158
30372
  } catch (err) {
30159
- failed3 = err;
30373
+ failed4 = err;
30160
30374
  if (FINAL.has(codeOf6(err)) || attempt === retries.length) break;
30161
30375
  await wait(retries[attempt], signal);
30162
30376
  }
30163
30377
  }
30164
- const code = codeOf6(failed3);
30165
- return { line, target: spec.target, code, error: String(failed3?.message ?? code) };
30378
+ const code = codeOf6(failed4);
30379
+ return { line, target: spec.target, code, error: String(failed4?.message ?? code) };
30166
30380
  }
30167
30381
 
30168
30382
  // src/mount/hostfs.ts
@@ -30851,18 +31065,28 @@ function settle2(request3, value2) {
30851
31065
  request3.onerror = () => reject(request3.error);
30852
31066
  });
30853
31067
  }
30854
- function openMedia(name2, factory) {
31068
+ var privateTop2 = () => navigator.storage.getDirectory();
31069
+ async function stored(kept, top) {
31070
+ const path = kept?.path;
31071
+ if (!Array.isArray(path)) return kept;
31072
+ return directoryAt(await top(), path).catch(() => void 0);
31073
+ }
31074
+ function openMedia(name2, factory, top = privateTop2) {
30855
31075
  const request3 = factory.open(name2, 1);
30856
31076
  request3.onupgradeneeded = () => request3.result.createObjectStore(MEDIA_STORE);
30857
31077
  return settle2(request3, () => {
30858
31078
  const db = request3.result;
30859
31079
  const store = (mode) => db.transaction(MEDIA_STORE, mode).objectStore(MEDIA_STORE);
30860
31080
  return {
30861
- get: (id2) => {
31081
+ get: async (id2) => {
30862
31082
  const got = store("readonly").get(id2);
30863
- return settle2(got, () => got.result);
31083
+ return stored(await settle2(got, () => got.result), top);
30864
31084
  },
30865
- put: (id2, handle) => settle2(store("readwrite").put(handle, id2), () => void 0)
31085
+ put: async (id2, handle) => {
31086
+ const at = await portable(handle, top);
31087
+ const kept = "path" in at ? at : handle;
31088
+ await settle2(store("readwrite").put(kept, id2), () => void 0);
31089
+ }
30866
31090
  };
30867
31091
  });
30868
31092
  }
@@ -31336,7 +31560,7 @@ var RULE = new RegExp(
31336
31560
  var TERM = /^[A-Za-z0-9._+-]+$/;
31337
31561
  var PLAIN3 = /^[A-Za-z0-9_@%+=:,./-]+$/;
31338
31562
  var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
31339
- function failed2(errno3, error) {
31563
+ function failed3(errno3, error) {
31340
31564
  return { error, errno: errno3 };
31341
31565
  }
31342
31566
  function unescaped(double) {
@@ -31515,10 +31739,10 @@ var Sudo = class {
31515
31739
  }
31516
31740
  async untrusted(path, cwd, word) {
31517
31741
  const files = this.o.backing ? await this.o.backing(path, cwd) : [];
31518
- if (!files) return failed2("ENOENT", `sudo: ${word}: command not found`);
31742
+ if (!files) return failed3("ENOENT", `sudo: ${word}: command not found`);
31519
31743
  for (const file of [path, ...files]) {
31520
31744
  if (!await this.trusted(file)) {
31521
- return failed2("EPERM", `sudo: ${file} must be root's, and writable by root only`);
31745
+ return failed3("EPERM", `sudo: ${file} must be root's, and writable by root only`);
31522
31746
  }
31523
31747
  }
31524
31748
  return void 0;
@@ -31535,7 +31759,7 @@ var Sudo = class {
31535
31759
  }
31536
31760
  async request(caller, call, signal) {
31537
31761
  const parsed2 = parseArgs(call.args);
31538
- if (typeof parsed2 === "string") return failed2("EINVAL", parsed2);
31762
+ if (typeof parsed2 === "string") return failed3("EINVAL", parsed2);
31539
31763
  if (this.o.mode !== "enforce") {
31540
31764
  const mode = this.o.mode;
31541
31765
  if (parsed2.list) return { list: `sudo: users are '${mode}': commands run as the caller
@@ -31544,9 +31768,9 @@ var Sudo = class {
31544
31768
  }
31545
31769
  const { cred } = caller;
31546
31770
  const self = await this.o.users.lookup(cred.ruid);
31547
- if (!self) return failed2("EPERM", `sudo: uid ${cred.ruid} is not in the passwd database`);
31771
+ if (!self) return failed3("EPERM", `sudo: uid ${cred.ruid} is not in the passwd database`);
31548
31772
  const target = await this.lookup(parsed2.user);
31549
- if (!target) return failed2("ENOENT", `sudo: unknown user ${parsed2.user}`);
31773
+ if (!target) return failed3("ENOENT", `sudo: unknown user ${parsed2.user}`);
31550
31774
  const root = cred.euid === 0;
31551
31775
  const rules = root ? [] : await this.policy();
31552
31776
  const applies = await this.applies(self, cred);
@@ -31554,13 +31778,13 @@ var Sudo = class {
31554
31778
  const [word = "", ...args] = parsed2.command;
31555
31779
  const cwd = await this.canonical(call.cwd);
31556
31780
  if (cwd === void 0 || !await this.reachable(cred, cwd)) {
31557
- return failed2(
31781
+ return failed3(
31558
31782
  "EACCES",
31559
31783
  `sudo: cannot run in ${call.cwd}: it isn't a directory you can enter`
31560
31784
  );
31561
31785
  }
31562
31786
  const path = await this.locate(word, cwd);
31563
- if (!path) return failed2("ENOENT", `sudo: ${word}: command not found`);
31787
+ if (!path) return failed3("ENOENT", `sudo: ${word}: command not found`);
31564
31788
  const untrusted2 = await this.untrusted(path, cwd, word);
31565
31789
  if (untrusted2) return untrusted2;
31566
31790
  const argv = [path, ...args];
@@ -31571,24 +31795,24 @@ var Sudo = class {
31571
31795
  if (root || matching.some((rule) => rule.nopasswd)) return grant();
31572
31796
  const quoted = argv.map(quoteWord).join(" ");
31573
31797
  if (matching.length === 0) {
31574
- return failed2(
31798
+ return failed3(
31575
31799
  "EPERM",
31576
31800
  `sudo: ${self.name} is not allowed to run ${quoted} as ${target.name}`
31577
31801
  );
31578
31802
  }
31579
- if (parsed2.nonInteractive) return failed2("EPERM", "sudo: a password is required");
31580
- if (this.pending.has(cred.ruid)) return failed2("EBUSY", "sudo: another request is pending");
31803
+ if (parsed2.nonInteractive) return failed3("EPERM", "sudo: a password is required");
31804
+ if (this.pending.has(cred.ruid)) return failed3("EBUSY", "sudo: another request is pending");
31581
31805
  this.pending.add(cred.ruid);
31582
31806
  try {
31583
31807
  const answer2 = await this.ask(caller, self, target, parsed2.command, path, cwd, signal);
31584
31808
  if (typeof answer2 !== "string") return answer2;
31585
31809
  if (await this.canonical(call.cwd) !== cwd || !await this.reachable(cred, cwd)) {
31586
- return failed2("EACCES", `sudo: ${call.cwd} changed while the request waited`);
31810
+ return failed3("EACCES", `sudo: ${call.cwd} changed while the request waited`);
31587
31811
  }
31588
31812
  const changed = await this.untrusted(path, cwd, word);
31589
31813
  if (changed) return changed;
31590
31814
  if (answer2 === "always" && !await this.remember(self, target, cwd, argv)) {
31591
- return failed2("EIO", "sudo: the rule could not be recorded");
31815
+ return failed3("EIO", "sudo: the rule could not be recorded");
31592
31816
  }
31593
31817
  return grant();
31594
31818
  } finally {
@@ -31605,7 +31829,7 @@ var Sudo = class {
31605
31829
  };
31606
31830
  }
31607
31831
  if (rules.length === 0) {
31608
- return failed2("EPERM", `User ${self.name} is not allowed to run sudo on ${host}.`);
31832
+ return failed3("EPERM", `User ${self.name} is not allowed to run sudo on ${host}.`);
31609
31833
  }
31610
31834
  const lines2 = rules.map(described).join("\n");
31611
31835
  return { list: `User ${self.name} may run the following commands on ${host}:
@@ -31614,7 +31838,7 @@ ${lines2}
31614
31838
  }
31615
31839
  async ask(caller, self, target, argv, path, cwd, requester) {
31616
31840
  const { approve } = this.o;
31617
- if (!approve || requester.aborted) return failed2("EACCES", "sudo: approval denied");
31841
+ if (!approve || requester.aborted) return failed3("EACCES", "sudo: approval denied");
31618
31842
  const createdAt = Date.now();
31619
31843
  const timeout = this.o.timeoutMs ?? SUDO_TIMEOUT_MS;
31620
31844
  const req = {
@@ -31644,9 +31868,9 @@ ${lines2}
31644
31868
  const answered2 = Promise.resolve().then(() => approve(req, { signal: control.signal })).catch(() => "deny");
31645
31869
  const answer2 = await Promise.race([answered2, aborted3]);
31646
31870
  if (answer2 === "aborted" || control.signal.aborted) {
31647
- return control.signal.reason === "expired" ? failed2("ETIMEDOUT", "sudo: the request expired") : failed2("EINTR", "sudo: the request was withdrawn");
31871
+ return control.signal.reason === "expired" ? failed3("ETIMEDOUT", "sudo: the request expired") : failed3("EINTR", "sudo: the request was withdrawn");
31648
31872
  }
31649
- return answer2 === "once" || answer2 === "always" ? answer2 : failed2("EACCES", "sudo: approval denied");
31873
+ return answer2 === "once" || answer2 === "always" ? answer2 : failed3("EACCES", "sudo: approval denied");
31650
31874
  } finally {
31651
31875
  clearTimeout(timer);
31652
31876
  requester.removeEventListener("abort", withdraw);
@@ -31937,13 +32161,13 @@ function interpreter(head) {
31937
32161
  function expandDefaults(defaults2, env) {
31938
32162
  const out = {};
31939
32163
  for (const [key, value2] of Object.entries(defaults2 ?? {})) {
31940
- let missing5 = false;
32164
+ let missing6 = false;
31941
32165
  const expanded = value2.replace(ENV_REFERENCE, (_, name2) => {
31942
32166
  const set3 = Object.hasOwn(env, name2) ? env[name2] : void 0;
31943
- if (set3 === void 0) missing5 = true;
32167
+ if (set3 === void 0) missing6 = true;
31944
32168
  return set3 ?? "";
31945
32169
  });
31946
- if (!missing5) out[key] = expanded;
32170
+ if (!missing6) out[key] = expanded;
31947
32171
  }
31948
32172
  return out;
31949
32173
  }
@@ -32118,6 +32342,9 @@ var Launcher = class {
32118
32342
  usersMode;
32119
32343
  dac;
32120
32344
  sealed;
32345
+ fill;
32346
+ fills = new AbortController();
32347
+ placeholders = [];
32121
32348
  scrubs = /* @__PURE__ */ new Map();
32122
32349
  clipboard;
32123
32350
  embedder;
@@ -32199,7 +32426,7 @@ var Launcher = class {
32199
32426
  ...options.env
32200
32427
  };
32201
32428
  this.ca = kernelCa(options.caStore ?? memoryCaStore());
32202
- this.transport = placeholderFloor(replayingHops(options.transport ?? missingTransport()));
32429
+ this.transport = this.floored(options);
32203
32430
  this.announcedTraits = JSON.stringify(this.transport.traits);
32204
32431
  this.uplink = options.uplink;
32205
32432
  this.routes = new Routes(options.uplink?.traits.ipv6 === true);
@@ -33261,6 +33488,19 @@ var Launcher = class {
33261
33488
  groupSession(pgid) {
33262
33489
  return this.jobs.sessionOf(pgid);
33263
33490
  }
33491
+ floored(options) {
33492
+ const { sealedFetch } = options;
33493
+ this.fill = sealedFetch && this.usersMode === "enforce" ? sealedFetcher(sealedFetch, this.fills.signal) : void 0;
33494
+ if (this.fill) this.net.stampProxy(REALM_PROXY_PORT);
33495
+ return placeholderFloor(replayingHops(options.transport ?? missingTransport()), {
33496
+ known: () => this.placeholders,
33497
+ ...this.fill ? { fill: this.fill } : {}
33498
+ });
33499
+ }
33500
+ httpFor(pid) {
33501
+ const stamp = this.fill ? () => this.liveStamp(pid) : void 0;
33502
+ return new HttpHandles(this.transport, pid, this.loopbackFor(pid), stamp);
33503
+ }
33264
33504
  loopbackFor(pid) {
33265
33505
  return new KernelLoopback(
33266
33506
  this.net,
@@ -33268,7 +33508,7 @@ var Launcher = class {
33268
33508
  const cred = this.credOf(pid);
33269
33509
  return { pid, uid: cred.euid, gid: cred.egid };
33270
33510
  },
33271
- () => this.connectorStamp(pid)
33511
+ () => this.liveStamp(pid)
33272
33512
  );
33273
33513
  }
33274
33514
  sourceCheck(pid, writer) {
@@ -33433,7 +33673,7 @@ var Launcher = class {
33433
33673
  jobs: this.jobs,
33434
33674
  ptys: this.ptys,
33435
33675
  net: this.net,
33436
- http: new HttpHandles(this.transport, pid, this.loopbackFor(pid)),
33676
+ http: this.httpFor(pid),
33437
33677
  locks: this.locks,
33438
33678
  fifos: this.fifos,
33439
33679
  sems: this.sems,
@@ -33598,7 +33838,7 @@ var Launcher = class {
33598
33838
  }
33599
33839
  list(viewer = ROOT) {
33600
33840
  const members = new Map(this.jobs.list().map((member) => [member.pid, member]));
33601
- const rootOf = (member) => {
33841
+ const rootOf2 = (member) => {
33602
33842
  let root = member;
33603
33843
  for (let up = members.get(root.execParent ?? -1); up; up = members.get(up.execParent ?? -1)) {
33604
33844
  root = up;
@@ -33607,7 +33847,7 @@ var Launcher = class {
33607
33847
  };
33608
33848
  const shown = (pid) => {
33609
33849
  const member = pid === void 0 ? void 0 : members.get(pid);
33610
- const root = member && rootOf(member).pid;
33850
+ const root = member && rootOf2(member).pid;
33611
33851
  return root !== void 0 && this.running(root) ? root : INIT_PID;
33612
33852
  };
33613
33853
  const superseded = new Set([...members.values()].map((m) => m.execParent));
@@ -33617,7 +33857,7 @@ var Launcher = class {
33617
33857
  if (member.execed && superseded.has(member.pid) || !described2) continue;
33618
33858
  const cred = this.credOf(member.pid);
33619
33859
  if (!maySee(viewer, cred)) continue;
33620
- const root = rootOf(member);
33860
+ const root = rootOf2(member);
33621
33861
  const tags = this.tagsOf(member.pid) ?? this.tagsOf(root.pid);
33622
33862
  listed.push({
33623
33863
  pid: root.pid,
@@ -33748,6 +33988,19 @@ var Launcher = class {
33748
33988
  connectorStamp(pid) {
33749
33989
  return this.sealed.stamp(this.identityOf(pid), this.credOf(pid), this.tagsOf(pid));
33750
33990
  }
33991
+ async liveStamp(pid) {
33992
+ if (!this.creds.has(pid) || this.zombies.has(pid)) return void 0;
33993
+ return this.connectorStamp(pid);
33994
+ }
33995
+ setPlaceholders(list) {
33996
+ if (!Array.isArray(list) || !list.every((p) => typeof p === "string" && p !== "")) {
33997
+ throw fsError("EINVAL", "setPlaceholders takes a list of non-empty strings");
33998
+ }
33999
+ this.placeholders = [...list];
34000
+ }
34001
+ endFills() {
34002
+ this.fills.abort("terminated");
34003
+ }
33751
34004
  identityOf(pid) {
33752
34005
  const parent = this.jobs.shownParent(pid);
33753
34006
  const alive = parent !== void 0 && this.running(parent);
@@ -33870,7 +34123,7 @@ var Launcher = class {
33870
34123
  const at = normalizePath(path);
33871
34124
  this.unlinked.closed(at);
33872
34125
  this.writers?.unlinked.closed(at);
33873
- const holding = [...this.held].some((holds2) => holds2.holding(at)) || [...this.openFiles].some((open3) => open3.holdsAt(at));
34126
+ const holding = [...this.held].some((holds3) => holds3.holding(at)) || [...this.openFiles].some((open3) => open3.holdsAt(at));
33874
34127
  if (!holding) void this.rootFs.announceHolds?.([], [at], false);
33875
34128
  const open2 = [...this.openFiles].some((nodes) => nodes.writes(at)) || heldUnder(this.held, at);
33876
34129
  if (!open2) void this.mounts.commit(at).catch(() => void 0);
@@ -34003,9 +34256,9 @@ var Launcher = class {
34003
34256
  const served2 = serveFilesystem(port2, medium.handlers, FSA_CAPABILITIES);
34004
34257
  const id2 = source.slice("fsa:".length);
34005
34258
  this.removable.set(target, { id: id2, medium, served: served2 });
34006
- const stored = this.inserted.get(id2) ?? await this.media.get(id2);
34007
- if (stored && await granted(stored)) medium.insert(stored);
34008
- else ask(stored);
34259
+ const stored2 = this.inserted.get(id2) ?? await this.media.get(id2);
34260
+ if (stored2 && await granted(stored2)) medium.insert(stored2);
34261
+ else ask(stored2);
34009
34262
  return {
34010
34263
  port: port1,
34011
34264
  present: () => medium.present(),
@@ -34033,8 +34286,9 @@ var Launcher = class {
34033
34286
  for (const root of roots) this.integrity.forget(root);
34034
34287
  this.resetCatalogs();
34035
34288
  }
34036
- attest(path) {
34289
+ attest(path, options = {}) {
34037
34290
  return attest(this.rootFs, path, {
34291
+ ...options,
34038
34292
  users: this.usersMode,
34039
34293
  mounts: this.mounts.list().map((entry) => entry.target).filter((target) => this.mounts.mounted(target) !== void 0)
34040
34294
  });
@@ -34091,8 +34345,8 @@ var Launcher = class {
34091
34345
  for (const name2 of names2 ?? []) {
34092
34346
  const path = joinName(real, name2);
34093
34347
  if (await this.base.hasOwner(path)) continue;
34094
- const failed3 = this.inUse(path) ? "busy" : await this.base.rm(path, { recursive: true, force: true }).catch(String);
34095
- if (failed3 === void 0) removed++;
34348
+ const failed4 = this.inUse(path) ? "busy" : await this.base.rm(path, { recursive: true, force: true }).catch(String);
34349
+ if (failed4 === void 0) removed++;
34096
34350
  else left++;
34097
34351
  }
34098
34352
  if (removed > 0) {
@@ -34187,7 +34441,7 @@ var Launcher = class {
34187
34441
  this.pnpmStale();
34188
34442
  if (!detach) return;
34189
34443
  for (const nodes of this.openFiles) nodes.revoke(at);
34190
- for (const holds2 of this.held) holds2.revoke(at);
34444
+ for (const holds3 of this.held) holds3.revoke(at);
34191
34445
  }
34192
34446
  unmountAll() {
34193
34447
  this.cron.stop();
@@ -34398,9 +34652,9 @@ var Launcher = class {
34398
34652
  }
34399
34653
  boundTo(path, hidden, fids) {
34400
34654
  const keeping = [...this.held].map(
34401
- (holds2) => [
34402
- holds2,
34403
- fids.flatMap((fid) => [...holds2.boundAt(path, fid), ...holds2.boundAt(hidden, fid)])
34655
+ (holds3) => [
34656
+ holds3,
34657
+ fids.flatMap((fid) => [...holds3.boundAt(path, fid), ...holds3.boundAt(hidden, fid)])
34404
34658
  ]
34405
34659
  ).filter(([, ids]) => ids.length > 0);
34406
34660
  const nodes = [...this.openFiles].filter(
@@ -34411,7 +34665,7 @@ var Launcher = class {
34411
34665
  (open2) => fids.some((fid) => open2.keepBound([hidden, path], fid, file))
34412
34666
  ).length;
34413
34667
  for (let i = kept; i < nodes.length; i++) file.release();
34414
- for (const [holds2, ids] of keeping) holds2.keepBound(ids, path, file);
34668
+ for (const [holds3, ids] of keeping) holds3.keepBound(ids, path, file);
34415
34669
  void this.rootFs.announceHolds?.([], [path, hidden], false);
34416
34670
  };
34417
34671
  return { keeping, nodes, keep: keep2 };
@@ -34571,7 +34825,7 @@ var Launcher = class {
34571
34825
  }
34572
34826
  moved(from, to, source) {
34573
34827
  this.renameLog.add(from, to);
34574
- for (const holds2 of this.held) holds2.renamed(from, to);
34828
+ for (const holds3 of this.held) holds3.renamed(from, to);
34575
34829
  if (source) return;
34576
34830
  for (const nodes of this.openFiles) nodes.renamed(from, to);
34577
34831
  this.watchers.moved(from, to);
@@ -34784,6 +35038,98 @@ function integrityAsker(port) {
34784
35038
  }
34785
35039
 
34786
35040
  // src/sealed-relay.ts
35041
+ function textOf(err) {
35042
+ return err instanceof Error ? err.message : String(err);
35043
+ }
35044
+ function sendBytes(port, bytes) {
35045
+ const copy = fresh(bytes);
35046
+ port.postMessage({ t: "chunk", bytes: copy }, [copy.buffer]);
35047
+ }
35048
+ function askFetch(port, req, signal) {
35049
+ signal.throwIfAborted();
35050
+ const { bodyStream, ...wire } = req;
35051
+ const { port1: near, port2: far } = new MessageChannel();
35052
+ const upload = bodyStream?.[Symbol.asyncIterator]();
35053
+ const head = Promise.withResolvers();
35054
+ let reading;
35055
+ let ended = false;
35056
+ const end = (failure2) => {
35057
+ if (ended) return;
35058
+ ended = true;
35059
+ signal.removeEventListener("abort", abort);
35060
+ near.close();
35061
+ void upload?.return?.().catch(() => void 0);
35062
+ head.reject(failure2);
35063
+ reading?.reject(failure2);
35064
+ reading = void 0;
35065
+ };
35066
+ const abort = () => {
35067
+ near.postMessage({ t: "cancel", reason: String(signal.reason) });
35068
+ end(new Error(String(signal.reason)));
35069
+ };
35070
+ const pull = async () => {
35071
+ try {
35072
+ const next3 = await upload.next();
35073
+ if (ended) return;
35074
+ if (next3.done) near.postMessage({ t: "end" });
35075
+ else sendBytes(near, next3.value);
35076
+ } catch (err) {
35077
+ if (!ended) near.postMessage({ t: "error", message: textOf(err) });
35078
+ }
35079
+ };
35080
+ const respond2 = (message3) => {
35081
+ const { status, statusText, headers, url } = message3;
35082
+ const body = {
35083
+ [Symbol.asyncIterator]: () => ({
35084
+ next: () => {
35085
+ if (ended) return Promise.resolve({ value: void 0, done: true });
35086
+ reading = Promise.withResolvers();
35087
+ near.postMessage({ t: "read" });
35088
+ return reading.promise;
35089
+ },
35090
+ return: async () => {
35091
+ await cancel();
35092
+ return { value: void 0, done: true };
35093
+ }
35094
+ })
35095
+ };
35096
+ const cancel = async () => {
35097
+ if (ended) return;
35098
+ near.postMessage({ t: "cancel", reason: "cancelled" });
35099
+ end(new Error("the request was cancelled"));
35100
+ };
35101
+ head.resolve({
35102
+ ...url !== void 0 ? { url } : {},
35103
+ status,
35104
+ statusText,
35105
+ headers,
35106
+ body,
35107
+ cancel
35108
+ });
35109
+ };
35110
+ near.addEventListener("message", ({ data }) => {
35111
+ if (data.t === "pull") void pull();
35112
+ else if (data.t === "stop") void upload?.return?.().catch(() => void 0);
35113
+ else if (data.t === "head") respond2(data);
35114
+ else if (data.t === "chunk") {
35115
+ reading?.resolve({ value: data.bytes, done: false });
35116
+ reading = void 0;
35117
+ } else if (data.t === "end") {
35118
+ reading?.resolve({ value: void 0, done: true });
35119
+ reading = void 0;
35120
+ end(new Error("the response ended"));
35121
+ } else end(new Error(data.message));
35122
+ });
35123
+ near.addEventListener("close", () => end(new Error("the sealed fetch relay closed")));
35124
+ near.start();
35125
+ signal.addEventListener("abort", abort, { once: true });
35126
+ const ask = {
35127
+ req: { ...wire, ...upload ? { streamed: true } : {} },
35128
+ port: far
35129
+ };
35130
+ port.postMessage({ sealedFetch: ask }, [far]);
35131
+ return head.promise;
35132
+ }
34787
35133
  function sealedAsker(port) {
34788
35134
  const asks = /* @__PURE__ */ new Map();
34789
35135
  let next3 = 0;
@@ -34807,7 +35153,7 @@ function sealedAsker(port) {
34807
35153
  if (reply) waiting.resolve(reply);
34808
35154
  else waiting.reject(new Error(error ?? "no reply"));
34809
35155
  };
34810
- return { hook, answer: answer2 };
35156
+ return { hook, fetch: (req, { signal }) => askFetch(port, req, signal), answer: answer2 };
34811
35157
  }
34812
35158
 
34813
35159
  // src/serve.ts
@@ -34825,11 +35171,24 @@ async function inOpfs(deps, root) {
34825
35171
  return await opfs?.resolve(root).catch(() => null) != null;
34826
35172
  }
34827
35173
  async function rootNamed(deps, req, root) {
34828
- if (req.metadata !== void 0 || !req.root || !deps.rootId) return req;
35174
+ if (req.metadata !== void 0 || !req.root && !req.rootPath || !deps.rootId) return req;
34829
35175
  const top = await deps.storage().catch(() => void 0);
34830
35176
  const name2 = await metadataName(top, root, deps.rootId);
34831
35177
  return name2 === META_DB ? req : { ...req, metadata: name2 };
34832
35178
  }
35179
+ async function rootOf(deps, req) {
35180
+ if (req.root) return req.root;
35181
+ const top = await deps.storage();
35182
+ return req.rootPath ? directoryAt(top, req.rootPath) : top;
35183
+ }
35184
+ async function insertedHandle(deps, req) {
35185
+ return "path" in req ? directoryAt(await deps.storage(), req.path) : req.handle;
35186
+ }
35187
+ function crossable(medium) {
35188
+ if (!medium.handle || clonable(medium.handle)) return medium;
35189
+ const { handle: _, ...rest2 } = medium;
35190
+ return rest2;
35191
+ }
34833
35192
  function workers(deps) {
34834
35193
  return {
34835
35194
  createWorker: deps.createWorker,
@@ -34965,13 +35324,15 @@ function transferOf2(req, result) {
34965
35324
  if (result instanceof MessagePort) return [result];
34966
35325
  const bound3 = result?.port;
34967
35326
  if (req.op === "connect" && bound3 instanceof MessagePort) return [bound3];
34968
- if (req.op === "attest") return [result.bytes.buffer];
35327
+ if (req.op === "attest" && "bytes" in result) {
35328
+ return [result.bytes.buffer];
35329
+ }
34969
35330
  return void 0;
34970
35331
  }
34971
35332
  function attestOps(port) {
34972
35333
  const watches = /* @__PURE__ */ new Map();
34973
35334
  return async (l, req) => {
34974
- if (req.op === "attest") return l.attest(req.path);
35335
+ if (req.op === "attest") return l.attest(req.path, req.options);
34975
35336
  if (req.op === "chmod") return l.fs.chmod(req.path, modeOption(req.mode)).then(() => true);
34976
35337
  if (req.op === "integrity-revoke") return l.revokeIntegrity(req.path).then(() => true);
34977
35338
  if (req.op === "unwatch-files") {
@@ -35026,7 +35387,7 @@ async function connectClient(deps, { user, tag, bind: bind2 }) {
35026
35387
  });
35027
35388
  return unbind ? { port: port2, client } : port2;
35028
35389
  }
35029
- function hostOptions(req, port, sealed, clipboard, lookup2, requests) {
35390
+ function hostOptions(req, port, sealed, sealedFetch, clipboard, lookup2, requests) {
35030
35391
  return {
35031
35392
  cron: { lock: `slicc-kernel-cron:${req.metadata ?? META_DB}` },
35032
35393
  ...req.hostname !== void 0 ? { hostname: req.hostname } : {},
@@ -35035,6 +35396,7 @@ function hostOptions(req, port, sealed, clipboard, lookup2, requests) {
35035
35396
  ...req.denials ? { onDenial: (denial) => port.postMessage({ denial }) } : {},
35036
35397
  ...req.protect ? { protect: hostProtect(req.protect, lookup2) } : {},
35037
35398
  ...req.sealed ? { sealed } : {},
35399
+ ...req.sealedFetch ? { sealedFetch } : {},
35038
35400
  ...req.clipboard ? { clipboard } : {},
35039
35401
  ...req.requests ? { embedder: requests.hookFor(0, req.requests) } : {}
35040
35402
  };
@@ -35109,7 +35471,7 @@ function serveKernel(port, deps) {
35109
35471
  }
35110
35472
  }
35111
35473
  async function init(req) {
35112
- launcher = (req.root ? Promise.resolve(req.root) : deps.storage()).then(async (root) => {
35474
+ launcher = rootOf(deps, req).then(async (root) => {
35113
35475
  req = await rootNamed(deps, req, root);
35114
35476
  const name2 = req.metadata ?? META_DB;
35115
35477
  const { meta, media } = await stores(deps, name2, req.media);
@@ -35125,11 +35487,19 @@ function serveKernel(port, deps) {
35125
35487
  ...req.modules ? { modules: req.modules } : {},
35126
35488
  ...req.commands ? { commands: req.commands } : {},
35127
35489
  ...req.env ? { env: req.env } : {},
35128
- ...hostOptions(req, port, sealed.hook, clipboard.hook, integrity.lookup, requests),
35490
+ ...hostOptions(
35491
+ req,
35492
+ port,
35493
+ sealed.hook,
35494
+ sealed.fetch,
35495
+ clipboard.hook,
35496
+ integrity.lookup,
35497
+ requests
35498
+ ),
35129
35499
  ...req.approve ? { approve: approvals.ask } : {},
35130
35500
  ...net,
35131
35501
  ...media ? { media } : {},
35132
- onMountPending: (medium) => port.postMessage({ medium }),
35502
+ onMountPending: (medium) => port.postMessage({ medium: crossable(medium) }),
35133
35503
  ...req.hostfs ? { hostfs: askGrant } : {},
35134
35504
  ...pageHooks(req, port),
35135
35505
  ...mountPolicy(req.processMounts),
@@ -35145,13 +35515,15 @@ function serveKernel(port, deps) {
35145
35515
  const l = await ready2();
35146
35516
  if (req.op === "mount") return l.mount(req.spec);
35147
35517
  if (req.op === "umount") return l.umount(req.target);
35148
- if (req.op === "insert") return l.insert(req.target, req.handle, req.source);
35518
+ if (req.op === "insert")
35519
+ return l.insert(req.target, await insertedHandle(deps, req), req.source);
35149
35520
  return l.mounts.listed();
35150
35521
  }
35151
35522
  const attestOp = attestOps(port);
35152
35523
  async function handle(req) {
35153
35524
  if (req.op === "init") return init(req);
35154
35525
  if (isAttestRequest(req)) return attestOp(await ready2(), req);
35526
+ if (req.op === "sealed-placeholders") return (await ready2()).setPlaceholders(req.list);
35155
35527
  if (req.op === "open-terminal") return terminal(req);
35156
35528
  if (req.op === "connect") return connect2(req.user, req.tag, req.requests);
35157
35529
  if (isUsersRequest(req)) return usersOp(await ready2(), req);