@ai-ecoverse/slicc-kernel 1.130.2 → 1.132.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.
@@ -350,6 +350,17 @@ async function openMeta(name2, factory) {
350
350
  return new IndexedDbMeta(await openMetaDb(name2, factory));
351
351
  }
352
352
 
353
+ // src/fs/notice.ts
354
+ function dirsChannel(metadata) {
355
+ return `slicc-kernel-dirs:${metadata}`;
356
+ }
357
+ function noticeOf(data) {
358
+ if (Array.isArray(data)) return { paths: data.filter((p) => typeof p === "string"), trees: [] };
359
+ const notice = data ?? {};
360
+ const strings = (list) => Array.isArray(list) ? list.filter((p) => typeof p === "string") : [];
361
+ return { paths: strings(notice.paths), trees: strings(notice.trees) };
362
+ }
363
+
353
364
  // src/fs/types.ts
354
365
  function rangedOps(fs) {
355
366
  const { pread, pwrite, truncate } = fs;
@@ -1288,8 +1299,9 @@ var OpfsFs = class {
1288
1299
  for (const path of [...c.paths, ...c.trees]) this.forget(path);
1289
1300
  });
1290
1301
  this.channel.onmessage = ({ data }) => {
1291
- for (const path of data) this.forget(path);
1292
- remote?.emit({ paths: data, trees: [] });
1302
+ const { paths, trees } = noticeOf(data);
1303
+ for (const path of [...paths, ...trees]) this.forget(normalizePath(path));
1304
+ remote?.emit({ paths, trees });
1293
1305
  };
1294
1306
  this.channel.unref?.();
1295
1307
  }
@@ -7022,7 +7034,7 @@ function satisfies(version, range2) {
7022
7034
  }
7023
7035
 
7024
7036
  // src/version.ts
7025
- var KERNEL_VERSION = true ? "1.130.2" : "0.0.0-dev";
7037
+ var KERNEL_VERSION = true ? "1.132.0" : "0.0.0-dev";
7026
7038
  var OS_RELEASE = "6.0.0-slicc";
7027
7039
  function procVersion() {
7028
7040
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -17746,7 +17758,7 @@ var TOKEN5 = "[!#$%&'*+.^_`|~0-9a-z-]+";
17746
17758
  var HEADER = new RegExp(`^header:${TOKEN5}$`);
17747
17759
  var METHOD = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
17748
17760
  var TARGET = /^[\x21-\x7e]+$/;
17749
- var SESSION_EXIT = /^(tailscale|device:[A-Za-z0-9._-]+)$/;
17761
+ var SESSION_EXIT = /^(tailscale|device:[A-Za-z0-9._:-]+)$/;
17750
17762
  var HOST = /^[a-z0-9.:-]+$/;
17751
17763
  var UNSAFE = /[\r\n\0]/;
17752
17764
  var POSITIONS = {
@@ -18495,6 +18507,90 @@ async function substituteHead(head, ask) {
18495
18507
  `, values };
18496
18508
  }
18497
18509
 
18510
+ // src/kernel/net/sealed-pg.ts
18511
+ var PG_MESSAGE_MAX = 16 * 1024;
18512
+ var PROTOCOL_3 = 196608;
18513
+ var CLEARTEXT = 3;
18514
+ function int32(bytes, at) {
18515
+ return bytes[at] << 24 | bytes[at + 1] << 16 | bytes[at + 2] << 8 | bytes[at + 3];
18516
+ }
18517
+ function sniffPg(start2) {
18518
+ const bytes = Uint8Array.from(start2, (c) => c.charCodeAt(0));
18519
+ if (bytes.length === 0 || bytes[0] !== 0) return bytes.length === 0 ? "more" : "no";
18520
+ if (bytes.length < 8) return "more";
18521
+ const length2 = int32(bytes, 0);
18522
+ return length2 >= 8 && length2 <= PG_MESSAGE_MAX && int32(bytes, 4) === PROTOCOL_3 ? "yes" : "no";
18523
+ }
18524
+ var PgServer = class {
18525
+ buffer = new Uint8Array(0);
18526
+ skip = 0;
18527
+ lost = false;
18528
+ cleartext = false;
18529
+ feed(bytes) {
18530
+ if (this.lost) return;
18531
+ const data = new Uint8Array(this.buffer.length + bytes.length);
18532
+ data.set(this.buffer);
18533
+ data.set(bytes, this.buffer.length);
18534
+ let at = 0;
18535
+ for (; ; ) {
18536
+ const left = data.length - at;
18537
+ if (this.skip > 0) {
18538
+ const n = Math.min(this.skip, left);
18539
+ this.skip -= n;
18540
+ at += n;
18541
+ if (this.skip > 0) break;
18542
+ continue;
18543
+ }
18544
+ if (left < 5) break;
18545
+ const type = data[at];
18546
+ const whole = 1 + int32(data, at + 1);
18547
+ if (whole < 5 || type === 82 && whole > PG_MESSAGE_MAX) {
18548
+ this.lost = true;
18549
+ this.cleartext = false;
18550
+ this.buffer = new Uint8Array(0);
18551
+ return;
18552
+ }
18553
+ if (type !== 82) {
18554
+ this.skip = whole;
18555
+ continue;
18556
+ }
18557
+ if (left < whole) break;
18558
+ this.cleartext = whole === 9 && int32(data, at + 5) === CLEARTEXT;
18559
+ at += whole;
18560
+ }
18561
+ this.buffer = data.slice(at);
18562
+ }
18563
+ };
18564
+ function frame3(type, body) {
18565
+ const out = new Uint8Array(5 + body.length);
18566
+ out[0] = type;
18567
+ const length2 = 4 + body.length;
18568
+ out.set([length2 >>> 24 & 255, length2 >>> 16 & 255, length2 >>> 8 & 255, length2 & 255], 1);
18569
+ for (let i = 0; i < body.length; i++) out[5 + i] = body.charCodeAt(i);
18570
+ return out;
18571
+ }
18572
+ function pgLength(bytes, started) {
18573
+ const header3 = started ? 5 : 4;
18574
+ if (bytes.length < header3) return void 0;
18575
+ const length2 = int32(bytes, started ? 1 : 0);
18576
+ return started ? 1 + length2 : length2;
18577
+ }
18578
+ async function pgPassword(message3, server, ask) {
18579
+ if (message3[0] !== 112 || !server.cleartext) return { bytes: message3, done: true };
18580
+ server.cleartext = false;
18581
+ let body = "";
18582
+ for (const b of message3.subarray(5)) body += String.fromCharCode(b);
18583
+ if (!body.endsWith("\0") || body.indexOf("\0") !== body.length - 1)
18584
+ return { bytes: message3, done: true };
18585
+ const password = body.slice(0, -1);
18586
+ const placeholders = placeholdersIn(password);
18587
+ if (placeholders.length === 0 || placeholders.length > SESSION_PLACEHOLDERS)
18588
+ return { bytes: message3, done: true };
18589
+ const values = usable(await ask(placeholders));
18590
+ if (Object.keys(values).length === 0) return { bytes: message3, done: true };
18591
+ return { bytes: frame3(112, `${replaced(password, values)}\0`), values, done: true };
18592
+ }
18593
+
18498
18594
  // src/kernel/net/sealed-smtp.ts
18499
18595
  var SMTP_LINE_MAX = 4096;
18500
18596
  var GREETING = ["EHLO ", "HELO "];
@@ -18616,11 +18712,14 @@ function headEnd2(bytes) {
18616
18712
  return -1;
18617
18713
  }
18618
18714
  function modeOf(start2) {
18619
- const http = sniffHttp1(start2);
18620
- const smtp = sniffSmtp(start2);
18621
- if (http === "yes") return "http1";
18622
- if (smtp === "yes") return "smtp";
18623
- return http === "no" && smtp === "no" ? "pass" : void 0;
18715
+ const sniffs = [
18716
+ ["http1", sniffHttp1(start2)],
18717
+ ["smtp", sniffSmtp(start2)],
18718
+ ["pg", sniffPg(start2)]
18719
+ ];
18720
+ const hit = sniffs.find(([, v]) => v === "yes");
18721
+ if (hit) return hit[0];
18722
+ return sniffs.every(([, v]) => v === "no") ? "pass" : void 0;
18624
18723
  }
18625
18724
  function crlf(bytes) {
18626
18725
  for (let i = 0; i + 1 < bytes.length; i++) if (bytes[i] === 13 && bytes[i + 1] === 10) return i;
@@ -18634,12 +18733,15 @@ var SessionWriter = class {
18634
18733
  failed;
18635
18734
  session = sessionId();
18636
18735
  smtp;
18736
+ pgStarted = false;
18637
18737
  conn;
18638
18738
  s;
18739
+ pg;
18639
18740
  scope;
18640
- constructor(conn, s, scope) {
18741
+ constructor(conn, s, pg, scope) {
18641
18742
  this.conn = conn;
18642
18743
  this.s = s;
18744
+ this.pg = pg;
18643
18745
  this.scope = scope;
18644
18746
  this.smtp = new SmtpClient(
18645
18747
  (position, placeholders) => this.ask("smtp", position, placeholders)
@@ -18688,6 +18790,7 @@ var SessionWriter = class {
18688
18790
  if (this.mode === "pass") await this.release();
18689
18791
  else if (this.mode === "http1") await this.http1();
18690
18792
  else if (this.mode === "smtp") await this.lines();
18793
+ else if (this.mode === "pg") await this.messages();
18691
18794
  if (this.mode !== "pass" && this.buffer.length > 0)
18692
18795
  this.timer = setTimeout(() => this.idle(), HEAD_IDLE_MS);
18693
18796
  return bytes.length;
@@ -18718,6 +18821,33 @@ var SessionWriter = class {
18718
18821
  }
18719
18822
  if (this.buffer.length > SMTP_LINE_MAX) await this.release();
18720
18823
  }
18824
+ async messages() {
18825
+ for (; ; ) {
18826
+ const whole = pgLength(this.buffer, this.pgStarted);
18827
+ if (whole === void 0 || whole < 4 || whole > PG_MESSAGE_MAX) {
18828
+ if (whole !== void 0) await this.release();
18829
+ return;
18830
+ }
18831
+ if (this.buffer.length < whole) return;
18832
+ const message3 = this.buffer.slice(0, whole);
18833
+ this.buffer = this.buffer.slice(whole);
18834
+ const started = this.pgStarted;
18835
+ this.pgStarted = true;
18836
+ const out = started ? await pgPassword(
18837
+ message3,
18838
+ this.pg,
18839
+ (placeholders) => this.ask("pg", "password-cleartext", placeholders)
18840
+ ).catch(() => ({ bytes: message3, done: true })) : { bytes: message3, done: false };
18841
+ if ("values" in out && out.values) this.remember(out.values);
18842
+ try {
18843
+ await writeAll4(this.conn, out.bytes);
18844
+ } finally {
18845
+ out.bytes.fill(0);
18846
+ message3.fill(0);
18847
+ }
18848
+ if (out.done) return this.release();
18849
+ }
18850
+ }
18721
18851
  idle() {
18722
18852
  this.chain = this.chain.then(() => this.release()).catch((err) => {
18723
18853
  this.failed ??= err;
@@ -18831,9 +18961,18 @@ function idle() {
18831
18961
  return new Promise((resolve2) => setTimeout(() => resolve2(IDLE2), SCRUB_IDLE_MS));
18832
18962
  }
18833
18963
  function sealedConn(conn, s) {
18964
+ const pg = new PgServer();
18834
18965
  const scope = s.broker.sessions.scope(s.pid, s.host);
18835
- const writer = substitutes(s) ? new SessionWriter(conn, s, scope) : void 0;
18836
- const reader = new ScrubReader(conn, scope);
18966
+ const writer = substitutes(s) ? new SessionWriter(conn, s, pg, scope) : void 0;
18967
+ const observed = {
18968
+ ...conn,
18969
+ read: async () => {
18970
+ const bytes = await conn.read();
18971
+ if (bytes) pg.feed(bytes);
18972
+ return bytes;
18973
+ }
18974
+ };
18975
+ const reader = new ScrubReader(writer ? observed : conn, scope);
18837
18976
  return {
18838
18977
  localAddr: conn.localAddr,
18839
18978
  remoteAddr: conn.remoteAddr,
@@ -20477,6 +20616,9 @@ var VfsNodes = class {
20477
20616
  rewritten(path) {
20478
20617
  this.byPath.get(path)?.reread();
20479
20618
  }
20619
+ rewrittenUnder(tree2) {
20620
+ for (const [p, node] of this.byPath) if (within7(p, tree2)) node.reread();
20621
+ }
20480
20622
  doubted(path) {
20481
20623
  for (const [p, node] of this.byPath) if (within7(p, path)) node.doubted();
20482
20624
  }
@@ -26663,7 +26805,7 @@ var Launcher = class {
26663
26805
  options.fs.onPeer?.(() => this.flushOpen());
26664
26806
  options.fs.remoteChanges?.((change) => {
26665
26807
  this.changes.flush();
26666
- this.rewritten(change.paths);
26808
+ this.rewritten(change.paths, change.trees);
26667
26809
  });
26668
26810
  const holders = [this.held, this.openFiles];
26669
26811
  this.unlinked = new UnlinkedKeeper(
@@ -28449,8 +28591,11 @@ var Launcher = class {
28449
28591
  }
28450
28592
  };
28451
28593
  }
28452
- rewritten(paths) {
28453
- for (const nodes of this.openFiles) for (const path of paths) nodes.rewritten(path);
28594
+ rewritten(paths, trees = []) {
28595
+ for (const nodes of this.openFiles) {
28596
+ for (const path of paths) nodes.rewritten(path);
28597
+ for (const tree2 of trees) nodes.rewrittenUnder(tree2);
28598
+ }
28454
28599
  this.changes.publish(...paths);
28455
28600
  }
28456
28601
  async flushOpen() {
@@ -28972,8 +29117,8 @@ function act2(session, req) {
28972
29117
  else if (req.action === "signal") session.signal(signalNumber(req.signal));
28973
29118
  else session.close();
28974
29119
  }
28975
- function dirsChannel(name2) {
28976
- return name2 === false ? void 0 : `slicc-kernel-dirs:${name2}`;
29120
+ function dirsChannelOf(name2) {
29121
+ return name2 === false ? void 0 : dirsChannel(name2);
28977
29122
  }
28978
29123
  function caDb(req) {
28979
29124
  const name2 = req.ca ?? (req.metadata ? `${req.metadata}-ca` : CA_DB);
@@ -29215,7 +29360,7 @@ function serveKernel(port, deps) {
29215
29360
  const net = remotes(port, req);
29216
29361
  ({ transport: remote, uplink } = net);
29217
29362
  const ranged2 = await inOpfs(deps, root);
29218
- const fs = new OpfsFs(root, meta, dirsChannel(name2), { ranged: ranged2 });
29363
+ const fs = new OpfsFs(root, meta, dirsChannelOf(name2), { ranged: ranged2 });
29219
29364
  await fs.reconcile();
29220
29365
  const started = new Launcher({
29221
29366
  fs,