@ai-ecoverse/slicc-kernel 1.151.1 → 1.152.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/node.js CHANGED
@@ -1898,6 +1898,7 @@ var KernelSocket = class _KernelSocket {
1898
1898
  return this.dial(addr, route2, secure2);
1899
1899
  }
1900
1900
  serving;
1901
+ pending;
1901
1902
  served = false;
1902
1903
  get loopbackLinked() {
1903
1904
  return this.state === "connected" && !this.switch;
@@ -2082,6 +2083,8 @@ var KernelSocket = class _KernelSocket {
2082
2083
  this.boundAt = void 0;
2083
2084
  this.serving?.release();
2084
2085
  this.serving = void 0;
2086
+ this.pending?.();
2087
+ this.pending = void 0;
2085
2088
  this.changes.wake();
2086
2089
  }
2087
2090
  static pair(net, domain, cred) {
@@ -2902,14 +2905,14 @@ var WsReader = class {
2902
2905
  }
2903
2906
  };
2904
2907
  function switchingHead(accept2, protocol = "") {
2905
- const chosen2 = protocol ? `Sec-WebSocket-Protocol: ${protocol}\r
2908
+ const chosen3 = protocol ? `Sec-WebSocket-Protocol: ${protocol}\r
2906
2909
  ` : "";
2907
2910
  return latin1Bytes(
2908
2911
  `HTTP/1.1 101 Switching Protocols\r
2909
2912
  Upgrade: websocket\r
2910
2913
  Connection: Upgrade\r
2911
2914
  Sec-WebSocket-Accept: ${accept2}\r
2912
- ${chosen2}\r
2915
+ ${chosen3}\r
2913
2916
  `
2914
2917
  );
2915
2918
  }
@@ -3362,7 +3365,7 @@ function satisfies(version, range2) {
3362
3365
  }
3363
3366
 
3364
3367
  // src/version.ts
3365
- var KERNEL_VERSION = true ? "1.151.1" : "0.0.0-dev";
3368
+ var KERNEL_VERSION = true ? "1.152.1" : "0.0.0-dev";
3366
3369
  var OS_RELEASE = "6.0.0-slicc";
3367
3370
  function procVersion() {
3368
3371
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -6321,9 +6324,9 @@ function withEtcFiles(fs, files) {
6321
6324
  readFileBuffer: (path) => fs.readFileBuffer(path).catch(fallback(path, (b) => b)),
6322
6325
  ...ranged2 ? {
6323
6326
  pread: (path, offset, length2, version) => ranged2.pread(path, offset, length2, version).catch(fallback(path, (b) => b.slice(offset, offset + length2))),
6324
- pwrite: async (path, offset, bytes, transfer) => {
6327
+ pwrite: async (path, offset, bytes, transfer, options) => {
6325
6328
  if (files.has(path)) await materialize(path);
6326
- return ranged2.pwrite(path, offset, bytes, transfer);
6329
+ return ranged2.pwrite(path, offset, bytes, transfer, options);
6327
6330
  },
6328
6331
  truncate: async (path, size) => {
6329
6332
  if (files.has(path)) await materialize(path);
@@ -6432,10 +6435,10 @@ var FreshModules = class {
6432
6435
  };
6433
6436
  const ranged2 = rangedOps(fs);
6434
6437
  if (ranged2) {
6435
- overrides.pwrite = async (path, at, bytes, transfer) => {
6438
+ overrides.pwrite = async (path, at, bytes, transfer, options) => {
6436
6439
  const touches3 = at < MAGIC.length && this.fresh.has(normalizePath(path));
6437
6440
  const first = at === 0 && bytes.length >= MAGIC.length ? bytes.slice(0, MAGIC.length) : void 0;
6438
- await ranged2.pwrite(path, at, bytes, transfer);
6441
+ await ranged2.pwrite(path, at, bytes, transfer, options);
6439
6442
  if (touches3) await decide(path, first);
6440
6443
  };
6441
6444
  overrides.truncate = async (path, size) => {
@@ -8116,6 +8119,9 @@ var HeldSet = class extends Set {
8116
8119
  if (over !== void 0) holds2.doubt(over);
8117
8120
  }
8118
8121
  }
8122
+ async bindIds(id2) {
8123
+ for (const holds2 of [...this]) await holds2.bindIds(id2);
8124
+ }
8119
8125
  delete(holds2) {
8120
8126
  const removed = super.delete(holds2);
8121
8127
  for (const path of /* @__PURE__ */ new Set([...holds2.keys(), ...holds2.opens.keys()])) this.idle(path);
@@ -8169,8 +8175,17 @@ var HeldPaths = class extends Map {
8169
8175
  }
8170
8176
  boundIno(handle) {
8171
8177
  const doubt = this.doubted.get(handle);
8172
- const ino = this.bound.get(handle);
8173
- return doubt === void 0 || ino === void 0 ? void 0 : { ino, doubt };
8178
+ const bound3 = this.bound.get(handle);
8179
+ return doubt === void 0 || bound3 === void 0 ? void 0 : { ...bound3, doubt };
8180
+ }
8181
+ async bindIds(id2) {
8182
+ for (const [handle, bound3] of [...this.bound]) {
8183
+ const key = this.handles.get(handle);
8184
+ if (bound3.fid !== void 0 || key === void 0) continue;
8185
+ const fid = await id2(key)?.catch(() => void 0);
8186
+ if (fid !== void 0 && this.bound.get(handle) === bound3)
8187
+ this.bound.set(handle, { ...bound3, fid });
8188
+ }
8174
8189
  }
8175
8190
  trust(handle, doubt) {
8176
8191
  if (this.doubted.get(handle) === doubt) this.doubted.delete(handle);
@@ -8211,14 +8226,15 @@ var HeldPaths = class extends Map {
8211
8226
  for (const file of [...this.uses.keys()]) this.letGo(file, true);
8212
8227
  this.keptHandles.clear();
8213
8228
  }
8214
- hold(path, on, open = false, real, handle, ino) {
8229
+ hold(path, on, open = false, real, handle, ino, fid) {
8215
8230
  if (open) {
8216
8231
  const made2 = this.holdOpen(path, on, real, handle);
8217
8232
  if (handle !== void 0) {
8218
8233
  this.bound.delete(handle);
8219
8234
  this.doubted.delete(handle);
8220
8235
  }
8221
- if (made2 !== void 0 && ino !== void 0) this.bound.set(made2, ino);
8236
+ if (made2 !== void 0 && ino !== void 0)
8237
+ this.bound.set(made2, fid === void 0 ? { ino } : { ino, fid });
8222
8238
  return made2;
8223
8239
  }
8224
8240
  this.holdWrite(path, on);
@@ -8954,7 +8970,7 @@ var MountFs = class _MountFs {
8954
8970
  );
8955
8971
  }
8956
8972
  }
8957
- async pwrite(path, offset, bytes, transfer = false, redirects = 0) {
8973
+ async pwrite(path, offset, bytes, transfer = false, options, redirects = 0) {
8958
8974
  const real = await this.follow(path, 0, true);
8959
8975
  const found = this.at(real);
8960
8976
  const { pwrite } = this.base;
@@ -8962,8 +8978,8 @@ var MountFs = class _MountFs {
8962
8978
  return this.based(
8963
8979
  [real],
8964
8980
  redirects,
8965
- () => pwrite.call(this.base, real, offset, bytes),
8966
- ([to], n) => this.pwrite(to, offset, bytes, transfer, n)
8981
+ () => pwrite.call(this.base, real, offset, bytes, false, options),
8982
+ ([to], n) => this.pwrite(to, offset, bytes, transfer, options, n)
8967
8983
  );
8968
8984
  }
8969
8985
  if (!found)
@@ -8987,7 +9003,7 @@ var MountFs = class _MountFs {
8987
9003
  op: "open",
8988
9004
  path: rel2,
8989
9005
  write: true,
8990
- create: true,
9006
+ create: options?.create !== false,
8991
9007
  truncate: false,
8992
9008
  exclusive: false
8993
9009
  });
@@ -9755,7 +9771,7 @@ async function run(entry, path, req) {
9755
9771
  case "truncate":
9756
9772
  return ranged(fs, path, req);
9757
9773
  case "append":
9758
- return json2(await appended(fs, path, req.body ?? new Uint8Array(0)));
9774
+ return json2(await appended(fs, path, req.body ?? new Uint8Array(0), req.handle));
9759
9775
  default:
9760
9776
  return { ok: false, errno: "EINVAL", message: `sync-fs: unknown op '${req.op}'` };
9761
9777
  }
@@ -9899,13 +9915,17 @@ async function holdOp(entry, path, req) {
9899
9915
  await entry.source?.open(path, real);
9900
9916
  await stillThere(entry, path, req);
9901
9917
  if (req.nofollow && !await ownEntry(entry, path, real ?? path)) continue;
9918
+ const fid = req.ino === void 0 ? void 0 : await idOf(entry, real ?? path);
9902
9919
  if (!r || !r.missed(path) && !r.changedSince(path, gen) && !r.inFlight?.(path))
9903
- return json2(entry.hold?.(path, on, open, real, void 0, req.ino) ?? null);
9920
+ return json2(entry.hold?.(path, on, open, real, void 0, req.ino, fid) ?? null);
9904
9921
  }
9905
9922
  }
9906
9923
  entry.hold?.(path, on, open, void 0, req.handle);
9907
9924
  return done;
9908
9925
  }
9926
+ async function idOf(entry, path) {
9927
+ return await entry.fileId?.(path)?.catch(() => void 0) ?? void 0;
9928
+ }
9909
9929
  async function ownEntry(entry, path, real) {
9910
9930
  const own = await entry.fs.realpath?.(path, false).catch((err) => {
9911
9931
  if (err.code !== "ENOENT") throw err;
@@ -10000,14 +10020,14 @@ async function createExclusive(fs, path, owner) {
10000
10020
  await fs.writeFile(path, new Uint8Array(0), owner);
10001
10021
  }
10002
10022
  var appending = /* @__PURE__ */ new Map();
10003
- async function appended(fs, path, body) {
10023
+ async function appended(fs, path, body, handle) {
10004
10024
  const key = await fs.realpath?.(path, true).catch(() => void 0) ?? path;
10005
10025
  const before = appending.get(key) ?? Promise.resolve();
10006
10026
  const run2 = before.then(async () => {
10007
10027
  if (fs.append) return fs.append(path, body);
10008
10028
  const size = (await fs.stat(path)).size;
10009
10029
  const ops = rangedOps(fs);
10010
- if (ops) await ops.pwrite(path, size, body, true);
10030
+ if (ops) await ops.pwrite(path, size, body, true, noCreate(handle));
10011
10031
  else {
10012
10032
  const whole = new Uint8Array(size + body.length);
10013
10033
  whole.set(await fs.readFileBuffer(path));
@@ -10023,6 +10043,9 @@ async function appended(fs, path, body) {
10023
10043
  });
10024
10044
  return run2;
10025
10045
  }
10046
+ function noCreate(handle) {
10047
+ return handle === void 0 ? void 0 : { create: false };
10048
+ }
10026
10049
  async function ranged(fs, path, req) {
10027
10050
  const ops = rangedOps(fs);
10028
10051
  if (!ops) throw syncError("ENOSYS", path);
@@ -10033,7 +10056,8 @@ async function ranged(fs, path, req) {
10033
10056
  kind: "bytes",
10034
10057
  bytes: await ops.pread(path, offset, req.length ?? 0, req.version)
10035
10058
  };
10036
- if (req.op === "pwrite") await ops.pwrite(path, offset, req.body ?? new Uint8Array(0), true);
10059
+ if (req.op === "pwrite")
10060
+ await ops.pwrite(path, offset, req.body ?? new Uint8Array(0), true, noCreate(req.handle));
10037
10061
  else await ops.truncate(path, req.length ?? 0);
10038
10062
  return done;
10039
10063
  }
@@ -10063,7 +10087,10 @@ async function bound(entry, path, handle) {
10063
10087
  const bound3 = entry.boundIno?.(handle);
10064
10088
  if (bound3 === void 0) return;
10065
10089
  const now = await entry.fs.stat(path).catch(() => void 0);
10066
- if (now?.ino === bound3.ino) {
10090
+ if (now === void 0 && bound3.fid !== void 0 && !await entry.fs.lstat(path).catch(() => void 0))
10091
+ throw syncError("ENOENT", path);
10092
+ const same2 = bound3.fid === void 0 ? now?.ino === bound3.ino : now?.fid === bound3.fid || await idOf(entry, path) === bound3.fid;
10093
+ if (same2) {
10067
10094
  entry.trust?.(handle, bound3.doubt);
10068
10095
  return;
10069
10096
  }
@@ -10877,6 +10904,8 @@ var SYS_TREE = {
10877
10904
  slicc_rename_ack_busy: (listing) => `${listing.renameAcks?.busy ?? 0}
10878
10905
  `,
10879
10906
  slicc_stale_fds: (listing) => `${listing.staleFds ?? 0}
10907
+ `,
10908
+ slicc_file_ids: (listing) => `${listing.fileIds ?? 0}
10880
10909
  `,
10881
10910
  slicc_rename_acks: (listing) => {
10882
10911
  const samples = [...listing.renameAcks?.ackMs ?? []].sort((a, b) => a - b);
@@ -12763,6 +12792,8 @@ var TLS_CLIENT_NO_SNI = 2;
12763
12792
  var TLS_CLIENT_VERIFY_CHAIN_ONLY = 4;
12764
12793
  var TLS_SERVER_REQUEST_CERT = 1;
12765
12794
  var TLS_SERVER_REQUIRE_CERT = 2;
12795
+ var TLS_SERVER_SELECT = 4;
12796
+ var TLS_HANDSHAKE_SELECT = 2;
12766
12797
  var SCRATCH = 64 * 1024;
12767
12798
  var EOF = -1;
12768
12799
  var TlsError = class extends Error {
@@ -12830,12 +12861,15 @@ var TlsEngine = class {
12830
12861
  if (!ptr) throw this.error(this.m._tls_last_error(), "server certificate");
12831
12862
  return new TlsLeaf(this, this.m, ptr);
12832
12863
  }
12864
+ get serverSelect() {
12865
+ return typeof this.m._tls_server_select === "function";
12866
+ }
12833
12867
  serverSession(leaf, alpn, clientCa, flags2) {
12834
12868
  const open = this.m._tls_server_new;
12835
12869
  const wire = alpnWire(alpn);
12836
12870
  const ptr = this.withBytes(
12837
12871
  wire,
12838
- (p) => open(leaf.ptr, wire.length > 0 ? p : 0, wire.length, clientCa?.ptr ?? 0, flags2)
12872
+ (p) => open(leaf?.ptr ?? 0, wire.length > 0 ? p : 0, wire.length, clientCa?.ptr ?? 0, flags2)
12839
12873
  );
12840
12874
  if (!ptr) throw this.error(this.m._tls_last_error(), "tls server");
12841
12875
  return new TlsSession(this, this.m, ptr);
@@ -13034,9 +13068,35 @@ var TlsSession = class {
13034
13068
  return this.m;
13035
13069
  }
13036
13070
  handshake() {
13071
+ return this.step() === 1;
13072
+ }
13073
+ step() {
13037
13074
  const ret = this.c._tls_handshake(this.ptr);
13038
13075
  if (ret < 0) throw this.engine.error(ret, "tls handshake");
13039
- return ret === 1;
13076
+ return ret;
13077
+ }
13078
+ clientAlpn() {
13079
+ const list = this.m._tls_client_alpn;
13080
+ const out = this.engine.intoScratch((p, max) => list(this.ptr, p, max));
13081
+ if (!(out instanceof Uint8Array)) return [];
13082
+ const names2 = [];
13083
+ for (let at = 0; at < out.length; at += 1 + out[at]) {
13084
+ names2.push(new TextDecoder().decode(out.subarray(at + 1, at + 1 + out[at])));
13085
+ }
13086
+ return names2;
13087
+ }
13088
+ select(leaf, alpn) {
13089
+ const pick = this.m._tls_server_select;
13090
+ const name2 = new TextEncoder().encode(alpn ?? "");
13091
+ const ret = this.engine.withBytes(
13092
+ name2,
13093
+ (p) => pick(this.ptr, leaf?.ptr ?? 0, name2.length > 0 ? p : 0, name2.length)
13094
+ );
13095
+ if (ret !== 0) throw this.engine.error(ret, "tls select");
13096
+ }
13097
+ refuse(alert) {
13098
+ const ret = this.m._tls_server_refuse(this.ptr, alert);
13099
+ if (ret !== 0) throw this.engine.error(ret, "tls refuse");
13040
13100
  }
13041
13101
  get verifyResult() {
13042
13102
  return this.c._tls_verify_result(this.ptr);
@@ -14758,17 +14818,39 @@ function serverRefusal(err, session, first) {
14758
14818
  const text = err instanceof TlsError ? err.message : String(err);
14759
14819
  return new KernelError("EPROTO", `ERR_SSL_HANDSHAKE_FAILURE: ${text}${alertOf(session)}`);
14760
14820
  }
14761
- async function serverHandshake(conn, session, inbox, first) {
14821
+ async function chosen(conn, session, select) {
14822
+ if (!select) throw new KernelError("EPROTO", "ERR_SSL_HANDSHAKE_FAILURE: no selection");
14823
+ const choice = await select({ servername: session.sni, protocols: session.clientAlpn() });
14824
+ if (choice.refuse === void 0) {
14825
+ try {
14826
+ session.select(choice.leaf, choice.alpn);
14827
+ } finally {
14828
+ choice.done?.();
14829
+ }
14830
+ return;
14831
+ }
14832
+ session.refuse(choice.refuse);
14833
+ await send(conn, session).catch(() => void 0);
14834
+ throw new KernelError(
14835
+ "EPROTO",
14836
+ `ERR_SSL_HANDSHAKE_FAILURE: the program refused the handshake (alert ${choice.refuse})`
14837
+ );
14838
+ }
14839
+ async function serverHandshake(conn, session, inbox, hooks) {
14762
14840
  for (; ; ) {
14763
- let done4;
14841
+ let step2;
14764
14842
  try {
14765
- done4 = session.handshake();
14843
+ step2 = session.step();
14766
14844
  } catch (err) {
14767
14845
  await send(conn, session).catch(() => void 0);
14768
- throw serverRefusal(err, session, first());
14846
+ throw serverRefusal(err, session, hooks.first());
14847
+ }
14848
+ if (step2 === TLS_HANDSHAKE_SELECT) {
14849
+ await chosen(conn, session, hooks.select);
14850
+ continue;
14769
14851
  }
14770
14852
  await send(conn, session);
14771
- if (done4) return;
14853
+ if (step2 === 1) return;
14772
14854
  if (!await inbox.more()) {
14773
14855
  throw new KernelError(
14774
14856
  "ECONNRESET",
@@ -14777,7 +14859,7 @@ async function serverHandshake(conn, session, inbox, first) {
14777
14859
  }
14778
14860
  }
14779
14861
  }
14780
- async function tlsServer(conn, session, clientCerts) {
14862
+ async function tlsServer(conn, session, clientCerts, select) {
14781
14863
  let first;
14782
14864
  const watched = {
14783
14865
  ...conn,
@@ -14789,7 +14871,7 @@ async function tlsServer(conn, session, clientCerts) {
14789
14871
  };
14790
14872
  const inbox = new Ciphertext(watched, session);
14791
14873
  try {
14792
- await serverHandshake(conn, session, inbox, () => first);
14874
+ await serverHandshake(conn, session, inbox, { first: () => first, select });
14793
14875
  const chain2 = session.peerChain();
14794
14876
  const code = clientCerts ? verifyCode(session.verifyResult) : void 0;
14795
14877
  const protocol = session.version === 772 ? "TLSv1.3" : "TLSv1.2";
@@ -17994,10 +18076,35 @@ function storeOf(engine, ca) {
17994
18076
  throw new KernelError("EINVAL", `ERR_INVALID_ARG_VALUE: ca: ${err.message}`);
17995
18077
  }
17996
18078
  }
17997
- function flagsOf(req) {
18079
+ function certFlags(req) {
17998
18080
  if (!req.requestCert) return 0;
17999
18081
  return req.rejectUnauthorized === false ? TLS_SERVER_REQUEST_CERT : TLS_SERVER_REQUIRE_CERT;
18000
18082
  }
18083
+ function flagsOf(req) {
18084
+ if (!req.select) return certFlags(req);
18085
+ if (req.alpn && req.alpn.length > 0)
18086
+ throw new KernelError("EINVAL", "ERR_TLS_ALPN_CALLBACK_WITH_PROTOCOLS: alpn with select");
18087
+ return certFlags(req) | TLS_SERVER_SELECT;
18088
+ }
18089
+ async function engineOf(proc, select) {
18090
+ const engine = await supportOf(proc.net).engine();
18091
+ if (!engine.serverSessions)
18092
+ throw new KernelError("ENOTSUP", "the installed tls engine has no server sessions");
18093
+ if (select && !engine.serverSelect)
18094
+ throw new KernelError("ENOTSUP", "the installed tls engine has no server selection");
18095
+ return engine;
18096
+ }
18097
+ async function importedLeaf(proc, own, select) {
18098
+ const cert = certBytes(own);
18099
+ let engine;
18100
+ try {
18101
+ engine = await engineOf(proc, select);
18102
+ } catch (err) {
18103
+ wipe(cert);
18104
+ throw err;
18105
+ }
18106
+ return { engine, leaf: leafOf(engine, cert) };
18107
+ }
18001
18108
  function timeoutOf(req) {
18002
18109
  const ms = req.handshakeTimeout ?? HANDSHAKE_TIMEOUT_MS;
18003
18110
  if (!Number.isInteger(ms) || ms <= 0)
@@ -18019,23 +18126,14 @@ function handshakeSignal(proc, ms) {
18019
18126
  async function serverOf(proc, req) {
18020
18127
  const own = req.cert;
18021
18128
  delete req.cert;
18022
- if (!own) throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: a server needs cert and key");
18023
- const cert = certBytes(own);
18024
- let engine;
18025
- try {
18026
- engine = await supportOf(proc.net).engine();
18027
- if (!engine.serverSessions)
18028
- throw new KernelError("ENOTSUP", "the installed tls engine has no server sessions");
18029
- } catch (err) {
18030
- wipe(cert);
18031
- throw err;
18032
- }
18033
- const leaf = leafOf(engine, cert);
18129
+ if (!own && !req.select)
18130
+ throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: a server needs cert and key");
18131
+ const { engine, leaf } = own ? await importedLeaf(proc, own, req.select) : { engine: await engineOf(proc, true), leaf: void 0 };
18034
18132
  let mine;
18035
18133
  try {
18036
18134
  mine = req.ca && req.ca.length > 0 ? storeOf(engine, req.ca) : void 0;
18037
18135
  const flags2 = flagsOf(req);
18038
- const store = mine ?? (flags2 ? await defaultStore(engine, supportOf(proc.net).roots) : void 0);
18136
+ const store = mine ?? (flags2 & ~TLS_SERVER_SELECT ? await defaultStore(engine, supportOf(proc.net).roots) : void 0);
18039
18137
  return {
18040
18138
  engine,
18041
18139
  leaf,
@@ -18044,12 +18142,12 @@ async function serverOf(proc, req) {
18044
18142
  flags: flags2,
18045
18143
  timeoutMs: timeoutOf(req),
18046
18144
  release() {
18047
- leaf.release();
18145
+ leaf?.release();
18048
18146
  mine?.release();
18049
18147
  }
18050
18148
  };
18051
18149
  } catch (err) {
18052
- leaf.release();
18150
+ leaf?.release();
18053
18151
  mine?.release();
18054
18152
  throw err;
18055
18153
  }
@@ -18060,30 +18158,133 @@ async function listenSecure(proc, socket, req) {
18060
18158
  socket.serving?.release();
18061
18159
  socket.serving = server;
18062
18160
  }
18161
+ function servedOf(info) {
18162
+ return {
18163
+ path: "kernel",
18164
+ protocol: info.protocol,
18165
+ alpnProtocol: info.alpnProtocol,
18166
+ servername: info.servername,
18167
+ authorized: info.authorized,
18168
+ ...info.authorizationError ? { authorizationError: info.authorizationError } : {},
18169
+ peerCertificates: info.peerCertificates.map(encode),
18170
+ cipher: info.cipher
18171
+ };
18172
+ }
18173
+ var selections = /* @__PURE__ */ new WeakMap();
18174
+ function pausing(signal) {
18175
+ let paused;
18176
+ const pausedAt = new Promise((resolve2) => {
18177
+ paused = resolve2;
18178
+ });
18179
+ const select = (offer) => new Promise((choose, fail3) => {
18180
+ if (signal.aborted) fail3(signal.reason);
18181
+ signal.addEventListener("abort", () => fail3(signal.reason), { once: true });
18182
+ paused({ offer, choose, fail: fail3 });
18183
+ });
18184
+ return { pausedAt, select };
18185
+ }
18063
18186
  async function serveSecure(proc, socket, req) {
18064
18187
  const shared = req.listener?.serving;
18065
18188
  if (req.listener && !shared) throw new KernelError("EINVAL", "the listener has no tls");
18066
18189
  const server = shared ?? await serverOf(proc, req);
18190
+ const { engine, leaf, alpn, store, flags: flags2 } = server;
18191
+ const limit = handshakeSignal(proc, server.timeoutMs);
18192
+ const { pausedAt, select } = pausing(limit.signal);
18193
+ const certs = (flags2 & ~TLS_SERVER_SELECT) !== 0;
18194
+ const run2 = socket.secureLink(
18195
+ (raw2) => tlsServer(
18196
+ raw2,
18197
+ engine.serverSession(leaf, alpn, store, flags2),
18198
+ certs,
18199
+ flags2 & TLS_SERVER_SELECT ? select : void 0
18200
+ ),
18201
+ limit.signal,
18202
+ (reason) => !shared && reason === timedOut
18203
+ ).finally(() => {
18204
+ limit.done();
18205
+ selections.delete(socket);
18206
+ socket.pending = void 0;
18207
+ if (!shared) server.release();
18208
+ });
18209
+ run2.catch(() => void 0);
18210
+ const first = await Promise.race([run2, pausedAt.then((pause2) => ({ pause: pause2 }))]);
18211
+ if (!("pause" in first)) return servedOf(first);
18212
+ selections.set(socket, { pause: first.pause, run: run2 });
18213
+ socket.pending = () => first.pause.fail(new KernelError("ECONNRESET"));
18214
+ return { select: first.pause.offer };
18215
+ }
18216
+ var REFUSALS = /* @__PURE__ */ new Set([112, 120, 40, 49, 80]);
18217
+ var TlsContext = class {
18218
+ leaf;
18219
+ constructor(leaf) {
18220
+ this.leaf = leaf;
18221
+ }
18222
+ close() {
18223
+ this.leaf.release();
18224
+ }
18225
+ };
18226
+ var TLS_CONTEXTS_MAX = 64;
18227
+ async function contextSecure(proc, cert) {
18228
+ if (!cert) throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: a context needs cert and key");
18229
+ const held = proc.fds.numbers().filter((fd) => proc.fds.get(fd).file instanceof TlsContext);
18230
+ if (held.length >= TLS_CONTEXTS_MAX) {
18231
+ wipe(certBytes(cert));
18232
+ throw new KernelError("EMFILE", `at most ${TLS_CONTEXTS_MAX} tls contexts per process`);
18233
+ }
18234
+ const { leaf } = await importedLeaf(proc, cert);
18235
+ const file = new OpenFile(new TlsContext(leaf));
18067
18236
  try {
18068
- const { engine, leaf, alpn, store, flags: flags2 } = server;
18069
- const limit = handshakeSignal(proc, server.timeoutMs);
18070
- const info = await socket.secureLink(
18071
- (raw2) => tlsServer(raw2, engine.serverSession(leaf, alpn, store, flags2), flags2 !== 0),
18072
- limit.signal,
18073
- (reason) => !shared && reason === timedOut
18074
- ).finally(limit.done);
18075
- return {
18076
- path: "kernel",
18077
- protocol: info.protocol,
18078
- alpnProtocol: info.alpnProtocol,
18079
- servername: info.servername,
18080
- authorized: info.authorized,
18081
- ...info.authorizationError ? { authorizationError: info.authorizationError } : {},
18082
- peerCertificates: info.peerCertificates.map(encode),
18083
- cipher: info.cipher
18084
- };
18237
+ const fd = proc.fds.install(file, 3);
18238
+ proc.fds.setCloseOnExec(fd);
18239
+ return fd;
18240
+ } catch (err) {
18241
+ leaf.release();
18242
+ throw err;
18243
+ }
18244
+ }
18245
+ function contextAt(fds, fd) {
18246
+ const open = fds.get(fd);
18247
+ const file = open.file;
18248
+ if (!(file instanceof TlsContext)) throw new KernelError("EBADF", "not a tls context");
18249
+ const held = open.retain();
18250
+ let released2 = false;
18251
+ return {
18252
+ leaf: file.leaf,
18253
+ done: () => {
18254
+ if (released2) return;
18255
+ released2 = true;
18256
+ void held.release();
18257
+ }
18258
+ };
18259
+ }
18260
+ function choiceOf(fds, pause2, req) {
18261
+ if (req.refuse !== void 0) {
18262
+ if (!REFUSALS.has(req.refuse)) throw new KernelError("EINVAL", "not a refusal alert");
18263
+ return { refuse: req.refuse };
18264
+ }
18265
+ if (req.alpn !== void 0 && !pause2.offer.protocols.includes(req.alpn))
18266
+ throw new KernelError("EINVAL", "ERR_TLS_ALPN_CALLBACK_INVALID_RESULT: not offered");
18267
+ return {
18268
+ ...req.context === void 0 ? {} : contextAt(fds, req.context),
18269
+ ...req.alpn === void 0 ? {} : { alpn: req.alpn }
18270
+ };
18271
+ }
18272
+ async function selectSecure(fds, socket, req) {
18273
+ const selecting = selections.get(socket);
18274
+ if (!selecting) throw new KernelError("EINVAL", "no handshake waits for a selection");
18275
+ selections.delete(socket);
18276
+ let choice;
18277
+ try {
18278
+ choice = choiceOf(fds, selecting.pause, req);
18279
+ } catch (err) {
18280
+ selecting.pause.choose({ refuse: 40 });
18281
+ throw err;
18282
+ }
18283
+ selecting.pause.choose(choice);
18284
+ try {
18285
+ return servedOf(await selecting.run);
18085
18286
  } finally {
18086
- if (!shared) server.release();
18287
+ choice.done?.();
18087
18288
  }
18088
18289
  }
18089
18290
 
@@ -18251,7 +18452,9 @@ var SOCKET_OPS = [
18251
18452
  "sock-tls",
18252
18453
  "sock-tls-upgrade",
18253
18454
  "sock-tls-serve",
18254
- "sock-tls-listen"
18455
+ "sock-tls-listen",
18456
+ "sock-tls-context",
18457
+ "sock-tls-select"
18255
18458
  ];
18256
18459
  function socketAt(fds, fd) {
18257
18460
  const file = anySocketAt(fds, fd);
@@ -18332,6 +18535,12 @@ async function socketSyscall(req, proc) {
18332
18535
  const listener = from === void 0 ? {} : { listener: socketAt(fds, from) };
18333
18536
  return ok3(await serveSecure(proc, socketAt(fds, req.fd), { ...rest2, ...listener }));
18334
18537
  }
18538
+ case "sock-tls-context":
18539
+ return ok3(await contextSecure(proc, req.cert));
18540
+ case "sock-tls-select": {
18541
+ const { fd, ...choice } = req;
18542
+ return ok3(await selectSecure(fds, socketAt(fds, fd), choice));
18543
+ }
18335
18544
  case "sock-tls-listen":
18336
18545
  await listenSecure(proc, socketAt(fds, req.fd), req);
18337
18546
  return ok3({});
@@ -19204,10 +19413,10 @@ function heldIo(fs, nodes, changed) {
19204
19413
  const held = await node(path);
19205
19414
  return held ? held.byName(() => held.pread(n, at)) : ranged2.pread(path, at, n, version);
19206
19415
  },
19207
- pwrite: (path, at, bytes, transfer) => write(
19416
+ pwrite: (path, at, bytes, transfer, options) => write(
19208
19417
  path,
19209
19418
  async (held) => void await held.pwrite(bytes, at),
19210
- () => ranged2.pwrite(path, at, bytes, transfer)
19419
+ () => ranged2.pwrite(path, at, bytes, transfer, options)
19211
19420
  ),
19212
19421
  truncate: (path, size) => write(
19213
19422
  path,
@@ -21492,8 +21701,9 @@ function holdingToken(opts, holds2, caller) {
21492
21701
  cwd: opts.cwd,
21493
21702
  ...opts.statfs ? { statfs: opts.statfs } : {},
21494
21703
  ...opts.renames ? { renames: opts.renames } : {},
21704
+ ...opts.fileId ? { fileId: opts.fileId } : {},
21495
21705
  ...opts.renameSeq ? { renameSeq: opts.renameSeq } : {},
21496
- hold: (path, on, open, real, handle, ino) => holds2.hold(path, on, open, real, handle, ino),
21706
+ hold: (path, on, open, real, handle, ino, fid) => holds2.hold(path, on, open, real, handle, ino, fid),
21497
21707
  boundIno: holds2.boundIno.bind(holds2),
21498
21708
  trust: holds2.trust.bind(holds2),
21499
21709
  keptFor: (handle) => holds2.keptFor(handle),
@@ -23912,9 +24122,10 @@ var OpfsFs = class {
23912
24122
  }
23913
24123
  async fileId(path) {
23914
24124
  const found = await this.locate(path, true);
23915
- const [entry] = await this.meta.get([found.path]);
24125
+ const [entry] = await (this.meta.fresh ?? this.meta.get).call(this.meta, [found.path]);
23916
24126
  if (entry?.fid !== void 0) return entry.fid;
23917
24127
  const fid = crypto.randomUUID();
24128
+ this.idWrites++;
23918
24129
  await this.meta.update(found.path, (now) => ({
23919
24130
  ...occupied(now),
23920
24131
  path: found.path,
@@ -24185,6 +24396,10 @@ var OpfsFs = class {
24185
24396
  opfsCalls() {
24186
24397
  return this.calls;
24187
24398
  }
24399
+ idWrites = 0;
24400
+ fileIdWrites() {
24401
+ return this.idWrites;
24402
+ }
24188
24403
  opfsOps() {
24189
24404
  return this.calls + this.others;
24190
24405
  }
@@ -24644,7 +24859,7 @@ var OpfsFs = class {
24644
24859
  return new Uint8Array(await file.slice(offset, offset + length2).arrayBuffer());
24645
24860
  });
24646
24861
  }
24647
- async pwrite(path, offset, bytes) {
24862
+ async pwrite(path, offset, bytes, _transfer, options) {
24648
24863
  const at = normalizePath(path);
24649
24864
  const movedAway = this.renamesInFlight() ? await this.writeWaits(at) : false;
24650
24865
  this.fileWrites.set(at, (this.fileWrites.get(at) ?? 0) + 1);
@@ -24659,7 +24874,10 @@ var OpfsFs = class {
24659
24874
  this.files.delete(target);
24660
24875
  }
24661
24876
  }
24662
- const [handle] = await this.fileFor(path, !existed && !movedAway);
24877
+ const [handle] = await this.fileFor(
24878
+ path,
24879
+ !existed && !movedAway && options?.create !== false
24880
+ );
24663
24881
  await this.writeAt(handle, target, path, offset, bytes);
24664
24882
  } finally {
24665
24883
  this.writeEnded(at);
@@ -28442,7 +28660,7 @@ function targetOf(command) {
28442
28660
  ...command.variants ? { variants: command.variants } : {}
28443
28661
  };
28444
28662
  }
28445
- function chosen(planned, env) {
28663
+ function chosen2(planned, env) {
28446
28664
  const { target } = planned;
28447
28665
  const wasm = variantFor(target.variants, env);
28448
28666
  if (wasm === void 0) return planned;
@@ -29601,7 +29819,7 @@ var Launcher = class {
29601
29819
  delete env[TICKET_ENV];
29602
29820
  const own = env.HOSTNAME;
29603
29821
  if (asked.target.abi === "wasi") env.HOSTNAME = this.hostname;
29604
- const planned = chosen(asked, env);
29822
+ const planned = chosen2(asked, env);
29605
29823
  const { target, args } = planned;
29606
29824
  let program;
29607
29825
  let exeId;
@@ -29791,7 +30009,8 @@ var Launcher = class {
29791
30009
  opfsOps: this.rootFs.opfsOps?.() ?? 0,
29792
30010
  cwdChecks: this.cwds.checks,
29793
30011
  renameAcks: this.rootFs.renameWaits?.(),
29794
- staleFds: staleFdCount()
30012
+ staleFds: staleFdCount(),
30013
+ fileIds: this.rootFs.fileIdWrites?.() ?? 0
29795
30014
  }),
29796
30015
  sudo: (call, signal) => this.sudo(pid, call, signal),
29797
30016
  crontab: (call) => this.crontab(pid, call),
@@ -29802,6 +30021,7 @@ var Launcher = class {
29802
30021
  replacements: stack.unlinked,
29803
30022
  statfs: (path) => this.mounts.statfs(path),
29804
30023
  renames: (since2, held) => this.renameLog.since(since2, held),
30024
+ fileId: (path) => this.locks.shared?.() === true ? this.rootFileId(path) : void 0,
29805
30025
  renameSeq: (from, to) => this.renameLog.seqOf(from, to),
29806
30026
  mounts: () => this.mounts.list(),
29807
30027
  mount: (call, signal) => this.processMount(pid, call, signal),
@@ -30681,12 +30901,16 @@ var Launcher = class {
30681
30901
  this.writers ??= this.writerStack();
30682
30902
  return this.writers;
30683
30903
  }
30904
+ rootFileId(path) {
30905
+ return this.mounts.locate(path) === void 0 ? this.rootFs.fileId?.(path) : void 0;
30906
+ }
30684
30907
  flushingPeers(fs) {
30685
30908
  const peers = fs.peers?.();
30686
30909
  if (!peers) return void 0;
30687
30910
  peers.watch((crowded) => {
30688
30911
  this.changes.flush();
30689
30912
  this.changes.foreign(crowded);
30913
+ if (crowded) void this.held?.bindIds((path) => this.rootFileId(path));
30690
30914
  });
30691
30915
  return {
30692
30916
  ...peers,