@ai-ecoverse/slicc-kernel 1.125.11 → 1.126.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1096,6 +1096,7 @@ var ABSENT_NAMES = 4096;
1096
1096
  var FILE_HANDLES = 4096;
1097
1097
  var STALE = /* @__PURE__ */ new Set(["NotFoundError", "TypeMismatchError"]);
1098
1098
  var REPLACED_ATTEMPTS = 4;
1099
+ var RECONCILE_LISTINGS = 8;
1099
1100
  var EXECUTABLE = /\/node_modules\/(?:@[^/]+\/)?[^/]+\/bin\//;
1100
1101
  var ERRNO_BY_DOM_ERROR = {
1101
1102
  NotFoundError: "ENOENT",
@@ -2455,15 +2456,57 @@ var OpfsFs = class {
2455
2456
  timesBy: this.id
2456
2457
  }));
2457
2458
  }
2459
+ async present(paths) {
2460
+ const listed = /* @__PURE__ */ new Map();
2461
+ const done4 = /* @__PURE__ */ new Map();
2462
+ const list = (dir) => {
2463
+ const known = listed.get(dir);
2464
+ if (known !== void 0) return known;
2465
+ const listing = (async () => {
2466
+ const above = dir === "/" ? void 0 : await list(parentOf3(dir));
2467
+ if (above === null) return null;
2468
+ const handle = dir === "/" ? this.root : above?.get(baseOf(dir));
2469
+ if (handle?.kind !== "directory") return void 0;
2470
+ this.calls++;
2471
+ const children3 = /* @__PURE__ */ new Map();
2472
+ try {
2473
+ for await (const child of handle.values())
2474
+ children3.set(child.name, child);
2475
+ } catch {
2476
+ return null;
2477
+ }
2478
+ return children3;
2479
+ })().then((children3) => {
2480
+ done4.set(dir, children3);
2481
+ return children3;
2482
+ });
2483
+ listed.set(dir, listing);
2484
+ return listing;
2485
+ };
2486
+ const dirs = [...new Set(paths.filter((p) => split(p).length > 0).map(parentOf3))];
2487
+ let next3 = 0;
2488
+ const lister = async () => {
2489
+ while (next3 < dirs.length) await list(dirs[next3++]);
2490
+ };
2491
+ await Promise.all(Array.from({ length: Math.min(RECONCILE_LISTINGS, dirs.length) }, lister));
2492
+ return async (path) => {
2493
+ if (split(path).length === 0) return true;
2494
+ const listing = done4.get(parentOf3(path));
2495
+ if (listing === null) return this.real(path);
2496
+ return listing?.has(baseOf(path)) === true;
2497
+ };
2498
+ }
2458
2499
  async reconcile() {
2459
2500
  if (this.remote && await this.remote.peered()) return 0;
2460
2501
  let removed = 0;
2461
2502
  const entries = await this.meta.all();
2462
2503
  const carried = new Set(entries.filter((e) => !e.vacated).map((e) => e.ino));
2463
- for (const entry of entries) {
2464
- if (entry.vacated && carried.has(inodeOf(entry.path))) continue;
2465
- const real = await this.real(entry.path);
2466
- const stale = entry.link === void 0 ? !real : real || !await this.real(parentOf3(entry.path));
2504
+ const checked = entries.filter((e) => !(e.vacated && carried.has(inodeOf(e.path))));
2505
+ const real = await this.present(
2506
+ checked.flatMap((e) => e.link === void 0 ? [e.path] : [e.path, parentOf3(e.path)])
2507
+ );
2508
+ for (const entry of checked) {
2509
+ const stale = entry.link === void 0 ? !await real(entry.path) : await real(entry.path) || !await real(parentOf3(entry.path));
2467
2510
  if (!stale) continue;
2468
2511
  const seen = JSON.stringify(entry);
2469
2512
  await this.meta.update(
@@ -6656,7 +6699,7 @@ function satisfies(version, range2) {
6656
6699
  }
6657
6700
 
6658
6701
  // src/version.ts
6659
- var KERNEL_VERSION = true ? "1.125.11" : "0.0.0-dev";
6702
+ var KERNEL_VERSION = true ? "1.126.0" : "0.0.0-dev";
6660
6703
  var OS_RELEASE = "6.0.0-slicc";
6661
6704
  function procVersion() {
6662
6705
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -8288,10 +8331,10 @@ function tunnelRequestUrl(req, origin) {
8288
8331
  throw new HttpError(400, "malformed request target");
8289
8332
  }
8290
8333
  const hosts = fieldValues(req.headers, "host");
8291
- const hostOk = hosts.every(
8334
+ const hostOk2 = hosts.every(
8292
8335
  (h) => URL.canParse(`https://${h}`) && new URL(`https://${h}`).host === base.host
8293
8336
  );
8294
- if (url.origin !== base.origin || !hostOk) {
8337
+ if (url.origin !== base.origin || !hostOk2) {
8295
8338
  throw new HttpError(421, `this tunnel is for ${base.host}`);
8296
8339
  }
8297
8340
  return url.href;
@@ -17619,6 +17662,10 @@ function controlsOf(o, session, protocol, chain2, shape) {
17619
17662
  ...o.insecure ? insecureOf(session, chain2, shape) : { hostnameMatches: checked || !session.nameMismatch }
17620
17663
  };
17621
17664
  }
17665
+ function verdictOf(o, session) {
17666
+ if (o.bundled !== true || isIP(o.servername) || session.verifyResult !== 0) return false;
17667
+ return o.checkHostname !== false || !session.nameMismatch;
17668
+ }
17622
17669
  async function infoOf(o, session) {
17623
17670
  const flags2 = session.verifyResult;
17624
17671
  const code = verifyCode(flags2);
@@ -17631,7 +17678,9 @@ async function infoOf(o, session) {
17631
17678
  authorized: code === void 0,
17632
17679
  ...code ? { authorizationError: code, authorizationText: o.engine.verifyInfo(flags2).trim() } : {},
17633
17680
  peerCertificates: chain2,
17634
- ...controlsOf(o, session, protocol, chain2, shape)
17681
+ ...controlsOf(o, session, protocol, chain2, shape),
17682
+ verified: verdictOf(o, session),
17683
+ handshakeAt: Date.now()
17635
17684
  };
17636
17685
  }
17637
17686
  var FATAL_ALERT = -30592;
@@ -17749,6 +17798,7 @@ function sessionOf(info, servername) {
17749
17798
  return {
17750
17799
  path: "kernel",
17751
17800
  substitutes: false,
17801
+ verified: info.verified,
17752
17802
  protocol: info.protocol,
17753
17803
  alpnProtocol: info.alpnProtocol,
17754
17804
  authorized: info.authorized,
@@ -17862,7 +17912,8 @@ async function prepareWith(support, req, servername, cert) {
17862
17912
  insecure: req.insecure === true,
17863
17913
  ...req.sni === false ? { sni: false } : {},
17864
17914
  ...req.checkHostname === false ? { checkHostname: false } : {},
17865
- clientCertificate: cert !== void 0
17915
+ clientCertificate: cert !== void 0,
17916
+ bundled: own === void 0
17866
17917
  };
17867
17918
  let session;
17868
17919
  try {
@@ -18449,9 +18500,21 @@ var VfsNode = class {
18449
18500
  }
18450
18501
  async keep() {
18451
18502
  const ranged2 = await this.prepare();
18452
- await ranged2?.pin();
18503
+ if (ranged2) await this.followed(() => ranged2.pin());
18453
18504
  }
18454
18505
  moving = /* @__PURE__ */ new Set();
18506
+ async followed(op) {
18507
+ for (; ; ) {
18508
+ const at = this.path;
18509
+ try {
18510
+ return await op();
18511
+ } catch (err) {
18512
+ if (!isMissing(err)) throw err;
18513
+ while (this.moving.size > 0) await Promise.all(this.moving);
18514
+ if (this.path === at) throw err;
18515
+ }
18516
+ }
18517
+ }
18455
18518
  async load() {
18456
18519
  if (this.revoked) throw new KernelError("EIO");
18457
18520
  while (!this.data) {
@@ -18497,7 +18560,7 @@ var VfsNode = class {
18497
18560
  }
18498
18561
  async pread(max, at) {
18499
18562
  const ranged2 = await this.prepare();
18500
- if (ranged2) return ranged2.read(at, max);
18563
+ if (ranged2) return this.followed(() => ranged2.read(at, max));
18501
18564
  const bytes = await this.load();
18502
18565
  const n = Math.max(0, Math.min(max, this.length - at));
18503
18566
  return bytes.slice(at, at + n);
@@ -18540,7 +18603,7 @@ var VfsNode = class {
18540
18603
  await this.fits(at + bytes.length);
18541
18604
  const ranged2 = await this.prepare();
18542
18605
  if (ranged2) {
18543
- await ranged2.write(at, bytes);
18606
+ await this.followed(() => ranged2.write(at, bytes));
18544
18607
  this.markDirty();
18545
18608
  return bytes.length;
18546
18609
  }
@@ -18609,8 +18672,9 @@ var VfsNode = class {
18609
18672
  this.dirty = false;
18610
18673
  const started = performance.now();
18611
18674
  try {
18612
- if (this.ranged) await this.ranged.flush();
18613
- else await this.fs.writeFile(this.path, this.data.slice(0, this.length));
18675
+ await this.followed(
18676
+ () => this.ranged ? this.ranged.flush() : this.fs.writeFile(this.path, this.data.slice(0, this.length))
18677
+ );
18614
18678
  } catch (err) {
18615
18679
  this.dirty = true;
18616
18680
  throw err;
@@ -22589,6 +22653,79 @@ function scrubStdio(fds, scrubber) {
22589
22653
  }
22590
22654
  }
22591
22655
 
22656
+ // src/kernel/sealed-session.ts
22657
+ var SESSION_WINDOW_MS = 6e4;
22658
+ var SESSION_PLACEHOLDERS = 16;
22659
+ var SESSION_PLACEHOLDER = /^fnox_proxy_[0-9a-f]{24}$/;
22660
+ var SESSION_ID = /^[A-Za-z0-9_-]{16,128}$/;
22661
+ var TOKEN5 = "[!#$%&'*+.^_`|~0-9a-z-]+";
22662
+ var HEADER = new RegExp(`^header:${TOKEN5}$`);
22663
+ var METHOD = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
22664
+ var TARGET = /^[\x21-\x7e]+$/;
22665
+ var EXIT = /^(page|proxy|tailscale|device:[\x21-\x7e]+)$/;
22666
+ var HOST = /^[a-z0-9.:-]+$/;
22667
+ var UNSAFE = /[\r\n\0]/;
22668
+ var POSITIONS = {
22669
+ http1: (position) => HEADER.test(position),
22670
+ smtp: (position) => position === "auth-plain" || position === "auth-login",
22671
+ pg: (position) => position === "password-cleartext"
22672
+ };
22673
+ function boundHost(servername) {
22674
+ const lower = servername.toLowerCase();
22675
+ return lower.endsWith(".") ? lower.slice(0, -1) : lower;
22676
+ }
22677
+ function headOk(f) {
22678
+ if (f.protocol !== "http1") return f.head === void 0;
22679
+ const head = f.head;
22680
+ return head !== void 0 && typeof head.method === "string" && METHOD.test(head.method) && typeof head.path === "string" && TARGET.test(head.path);
22681
+ }
22682
+ function placeholdersOk(list) {
22683
+ if (!Array.isArray(list) || list.length === 0 || list.length > SESSION_PLACEHOLDERS) return false;
22684
+ return new Set(list).size === list.length && list.every((p) => typeof p === "string" && SESSION_PLACEHOLDER.test(p));
22685
+ }
22686
+ function hostOk(host) {
22687
+ return typeof host === "string" && HOST.test(host) && boundHost(host) === host;
22688
+ }
22689
+ function sessionAskable(f, now) {
22690
+ if (!Object.hasOwn(POSITIONS, f.protocol) || typeof f.position !== "string") return false;
22691
+ if (!POSITIONS[f.protocol](f.position)) return false;
22692
+ if (typeof f.session !== "string" || !SESSION_ID.test(f.session)) return false;
22693
+ if (f.verified !== true || !hostOk(f.host) || typeof f.handshakeAt !== "number") return false;
22694
+ if (!Number.isInteger(f.port) || f.port < 1 || f.port > 65535) return false;
22695
+ const age = now - f.handshakeAt;
22696
+ if (!Number.isFinite(age) || age < 0 || age > SESSION_WINDOW_MS) return false;
22697
+ return typeof f.exit === "string" && EXIT.test(f.exit) && placeholdersOk(f.placeholders) && headOk(f);
22698
+ }
22699
+ function sessionRequest(f) {
22700
+ return {
22701
+ v: 1,
22702
+ op: "sessionMaterialize",
22703
+ caller: f.stamp,
22704
+ stamp: f.stamp,
22705
+ session: f.session,
22706
+ host: f.host,
22707
+ port: f.port,
22708
+ protocol: f.protocol,
22709
+ position: f.position,
22710
+ verified: true,
22711
+ handshakeAt: f.handshakeAt,
22712
+ exit: f.exit,
22713
+ placeholders: [...f.placeholders],
22714
+ ...f.head ? { head: { method: f.head.method, path: f.head.path } } : {}
22715
+ };
22716
+ }
22717
+ function sessionValues(reply, asked) {
22718
+ if (typeof reply !== "object" || reply === null || Array.isArray(reply)) return void 0;
22719
+ const { error, values } = reply;
22720
+ if (error !== void 0 || typeof values !== "object" || values === null) return void 0;
22721
+ const out = {};
22722
+ for (const ph of asked) {
22723
+ const value2 = values[ph];
22724
+ if (typeof value2 === "string" && value2.length > 0 && !UNSAFE.test(value2)) out[ph] = value2;
22725
+ }
22726
+ return Object.keys(out).length > 0 ? out : void 0;
22727
+ }
22728
+
22592
22729
  // src/kernel/sealed.ts
22593
22730
  var SEALED_MAX_BYTES = 64 * 1024;
22594
22731
  var SEALED_TIMEOUT_MS = 1e4;
@@ -22783,6 +22920,15 @@ var SealedBroker = class {
22783
22920
  };
22784
22921
  }
22785
22922
  async consume(fields) {
22923
+ const req = { ...fields, v: 1, op: "materializeConsume", caller: fields.stamp };
22924
+ return this.ask(req, swapOf);
22925
+ }
22926
+ async sessionMaterialize(fields, now = Date.now()) {
22927
+ if (!sessionAskable(fields, now)) return void 0;
22928
+ const req = sessionRequest(fields);
22929
+ return this.ask(req, (reply) => sessionValues(reply, req.placeholders));
22930
+ }
22931
+ async ask(req, parse) {
22786
22932
  const { hook } = this;
22787
22933
  if (!hook) return void 0;
22788
22934
  const control = new AbortController();
@@ -22790,14 +22936,8 @@ var SealedBroker = class {
22790
22936
  const stopped = new Promise((resolve2) => {
22791
22937
  control.signal.addEventListener("abort", () => resolve2(void 0), { once: true });
22792
22938
  });
22793
- const req = {
22794
- ...fields,
22795
- v: 1,
22796
- op: "materializeConsume",
22797
- caller: fields.stamp
22798
- };
22799
22939
  try {
22800
- const asked = Promise.resolve().then(() => hook(req, { signal: control.signal })).then(swapOf, () => void 0);
22940
+ const asked = Promise.resolve().then(() => hook(req, { signal: control.signal })).then(parse, () => void 0);
22801
22941
  return await Promise.race([asked, stopped]);
22802
22942
  } finally {
22803
22943
  clearTimeout(timer);