@ai-ecoverse/slicc-kernel 1.67.1 → 1.68.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.
package/dist/node.js CHANGED
@@ -866,6 +866,7 @@ function kernelFdKind(file) {
866
866
  if (file.held) return "held";
867
867
  if (file.heldMeta && "device" in file.heldMeta) return "device";
868
868
  if (file.tty) return "tty";
869
+ if (file.sealed) return "sealed";
869
870
  return file.seek ? "file" : "stream";
870
871
  }
871
872
  var FdTable = class _FdTable {
@@ -11182,6 +11183,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
11182
11183
  "fd-open-tty",
11183
11184
  "fd-tty-names",
11184
11185
  "fd-tty-owner",
11186
+ "fd-open-sealed",
11185
11187
  "tty-get",
11186
11188
  "tty-set",
11187
11189
  "tty-winsz",
@@ -11237,6 +11239,7 @@ var WasmProcess = class {
11237
11239
  ignored = 0;
11238
11240
  inherited = 0;
11239
11241
  interrupt = new AbortController();
11242
+ gone = new AbortController();
11240
11243
  dying = false;
11241
11244
  umask = DEFAULT_UMASK;
11242
11245
  cred;
@@ -11459,6 +11462,7 @@ var WasmProcess = class {
11459
11462
  }
11460
11463
  async write(fd, body, nonblock = false, cancelled) {
11461
11464
  const file = this.fds.get(fd).file;
11465
+ if (file.sealed) return file.sealed.send(body, await this.sealedCaller(), this.gone.signal);
11462
11466
  if (!file.write) throw new KernelError("EBADF");
11463
11467
  if (!pollFile(file).writable) {
11464
11468
  if (nonblock) throw new KernelError("EAGAIN");
@@ -11540,6 +11544,24 @@ var WasmProcess = class {
11540
11544
  if (name2 !== void 0) ttyOpenable(this.guarded(), tty);
11541
11545
  return this.fds.install(tty.file(), 3);
11542
11546
  }
11547
+ openSealed() {
11548
+ const broker = this.options.sealed;
11549
+ if (!broker) throw new KernelError("ENOENT");
11550
+ return this.fds.install(broker.open(), 3);
11551
+ }
11552
+ async sealedCaller() {
11553
+ const shown = await this.options.identity?.();
11554
+ const broker = this.options.sealed;
11555
+ const tag = broker.tagOf(this.pid);
11556
+ return {
11557
+ pid: shown?.pid ?? this.pid,
11558
+ ppid: shown?.ppid ?? 0,
11559
+ uid: this.cred.euid,
11560
+ gid: this.cred.egid,
11561
+ ...tag !== void 0 ? { tag } : {},
11562
+ users: broker.users
11563
+ };
11564
+ }
11543
11565
  guarded() {
11544
11566
  const { guard: guard2 } = this.options;
11545
11567
  return guard2 && { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid };
@@ -11660,6 +11682,8 @@ var WasmProcess = class {
11660
11682
  return { ok: true, kind: "json", json: this.openTty(req.name) };
11661
11683
  case "fd-tty-names":
11662
11684
  return { ok: true, kind: "json", json: this.options.jobs?.terminalNames() ?? [] };
11685
+ case "fd-open-sealed":
11686
+ return { ok: true, kind: "json", json: this.openSealed() };
11663
11687
  case "fd-tty-owner":
11664
11688
  return { ok: true, kind: "json", json: this.terminalByName(req.name).owner ?? null };
11665
11689
  case "fd-select": {
@@ -12095,6 +12119,7 @@ var WasmProcess = class {
12095
12119
  async exit() {
12096
12120
  if (this.exited) return;
12097
12121
  this.exited = true;
12122
+ this.gone.abort();
12098
12123
  this.die();
12099
12124
  this.clearAlarm();
12100
12125
  this.interrupt.abort();
@@ -12282,6 +12307,7 @@ function processOptions(opts, header4, hooks, created3) {
12282
12307
  return {
12283
12308
  ...inherited(opts),
12284
12309
  ...opts.owners ? { owners: true } : {},
12310
+ ...opts.sealed ? { sealed: opts.sealed } : {},
12285
12311
  ...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3 } } : {},
12286
12312
  ...opts.identity ? { identity: opts.identity } : {},
12287
12313
  ...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
@@ -12764,6 +12790,178 @@ function replayingHops(inner, heldMs = HELD_MS) {
12764
12790
  };
12765
12791
  }
12766
12792
 
12793
+ // src/kernel/sealed.ts
12794
+ var SEALED_MAX_BYTES = 64 * 1024;
12795
+ var SEALED_TIMEOUT_MS = 1e4;
12796
+ var SEALED_OPS = /* @__PURE__ */ new Set([
12797
+ "seal",
12798
+ "placeholder",
12799
+ "list",
12800
+ "test",
12801
+ "request",
12802
+ "status",
12803
+ "cancel",
12804
+ "materialize"
12805
+ ]);
12806
+ var encoder3 = new TextEncoder();
12807
+ var decoder2 = new TextDecoder("utf-8", { fatal: true });
12808
+ function parseSealed(bytes) {
12809
+ try {
12810
+ if (bytes.length > SEALED_MAX_BYTES) throw new KernelError("EMSGSIZE");
12811
+ let parsed2;
12812
+ try {
12813
+ parsed2 = JSON.parse(decoder2.decode(bytes));
12814
+ } catch {
12815
+ throw new KernelError("EINVAL");
12816
+ }
12817
+ if (typeof parsed2 !== "object" || parsed2 === null || Array.isArray(parsed2))
12818
+ throw new KernelError("EINVAL");
12819
+ const req = parsed2;
12820
+ if (req.v !== 1 || typeof req.op !== "string" || !SEALED_OPS.has(req.op))
12821
+ throw new KernelError("EINVAL");
12822
+ return req;
12823
+ } finally {
12824
+ bytes.fill(0);
12825
+ }
12826
+ }
12827
+ function errorReply(code, message3) {
12828
+ return { v: 1, error: { code, message: message3 } };
12829
+ }
12830
+ function isRecord(value) {
12831
+ return typeof value === "object" && value !== null && !Array.isArray(value);
12832
+ }
12833
+ function serialized(reply) {
12834
+ let plain;
12835
+ try {
12836
+ const text = JSON.stringify(reply);
12837
+ plain = text === void 0 ? void 0 : JSON.parse(text);
12838
+ } catch (err) {
12839
+ return JSON.stringify(errorReply("EIO", lineOf(err)));
12840
+ }
12841
+ if (!isRecord(plain)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
12842
+ const { v: _, ...rest2 } = plain;
12843
+ return JSON.stringify({ v: 1, ...rest2 });
12844
+ }
12845
+ function lineOf(err) {
12846
+ const text = err instanceof Error ? err.message : String(err);
12847
+ return (text.split("\n")[0] ?? "").slice(0, 200);
12848
+ }
12849
+ var SealedChannel = class {
12850
+ reply;
12851
+ offset = 0;
12852
+ inflight;
12853
+ broker;
12854
+ constructor(broker) {
12855
+ this.broker = broker;
12856
+ }
12857
+ send(bytes, caller, gone) {
12858
+ const length2 = bytes.length;
12859
+ const fields = parseSealed(bytes);
12860
+ this.reply = void 0;
12861
+ this.offset = 0;
12862
+ this.inflight?.control.abort("replaced");
12863
+ const control = new AbortController();
12864
+ const withdraw = () => control.abort("withdrawn");
12865
+ if (gone.aborted) withdraw();
12866
+ else gone.addEventListener("abort", withdraw, { once: true });
12867
+ const timer = setTimeout(() => control.abort("timeout"), this.broker.timeoutMs);
12868
+ const req = { ...fields, v: 1, op: fields.op, caller };
12869
+ const flight = { control, done: Promise.resolve() };
12870
+ flight.done = this.answer(req, control.signal).then((reply) => {
12871
+ clearTimeout(timer);
12872
+ gone.removeEventListener("abort", withdraw);
12873
+ if (this.inflight !== flight) return;
12874
+ this.inflight = void 0;
12875
+ if (reply) this.reply = encoder3.encode(serialized(reply));
12876
+ });
12877
+ this.inflight = flight;
12878
+ return length2;
12879
+ }
12880
+ async answer(req, signal) {
12881
+ const hook = this.broker.hook;
12882
+ if (!hook) return errorReply("ENOTCONN", "no vault is connected");
12883
+ const stopped = new Promise((resolve) => {
12884
+ signal.addEventListener("abort", () => resolve(void 0), { once: true });
12885
+ });
12886
+ if (signal.aborted) return void 0;
12887
+ const asked = Promise.resolve().then(() => hook(req, { signal })).then(
12888
+ (reply2) => isRecord(reply2) ? reply2 : errorReply("EIO", "the vault gave no reply"),
12889
+ (err) => errorReply("EIO", lineOf(err))
12890
+ );
12891
+ const reply = await Promise.race([asked, stopped]);
12892
+ if (!signal.aborted) return reply;
12893
+ return signal.reason === "timeout" ? errorReply("ETIMEDOUT", "the vault did not answer within 10 s") : void 0;
12894
+ }
12895
+ async read(max, signal) {
12896
+ for (; ; ) {
12897
+ if (this.reply) {
12898
+ const out = this.reply.slice(this.offset, this.offset + max);
12899
+ this.offset += out.length;
12900
+ if (this.offset >= this.reply.length) {
12901
+ this.reply = void 0;
12902
+ this.offset = 0;
12903
+ }
12904
+ return out;
12905
+ }
12906
+ const flight = this.inflight;
12907
+ if (!flight) return new Uint8Array(0);
12908
+ await this.until(flight, signal);
12909
+ }
12910
+ }
12911
+ async until(flight, signal) {
12912
+ if (!signal) return flight.done;
12913
+ if (signal.aborted) throw new KernelError("EINTR");
12914
+ let stop = () => {
12915
+ };
12916
+ const interrupted2 = new Promise((_, reject) => {
12917
+ stop = () => reject(new KernelError("EINTR"));
12918
+ signal.addEventListener("abort", stop, { once: true });
12919
+ });
12920
+ try {
12921
+ await Promise.race([flight.done, interrupted2]);
12922
+ } finally {
12923
+ signal.removeEventListener("abort", stop);
12924
+ }
12925
+ }
12926
+ poll() {
12927
+ return { readable: this.reply !== void 0 || !this.inflight, writable: true, hangup: false };
12928
+ }
12929
+ async changed(signal) {
12930
+ const flight = this.inflight;
12931
+ if (flight) await this.until(flight, signal);
12932
+ }
12933
+ close() {
12934
+ this.inflight?.control.abort("withdrawn");
12935
+ this.inflight = void 0;
12936
+ this.reply = void 0;
12937
+ }
12938
+ };
12939
+ var SealedBroker = class {
12940
+ hook;
12941
+ users;
12942
+ timeoutMs;
12943
+ tagOf;
12944
+ constructor(hook, users, timeoutMs = SEALED_TIMEOUT_MS, tagOf = () => void 0) {
12945
+ this.hook = hook;
12946
+ this.users = users;
12947
+ this.timeoutMs = timeoutMs;
12948
+ this.tagOf = tagOf;
12949
+ }
12950
+ open() {
12951
+ const channel = new SealedChannel(this);
12952
+ return new OpenFile({
12953
+ read: (max, signal) => channel.read(max, signal),
12954
+ write: async () => {
12955
+ throw new KernelError("EINVAL");
12956
+ },
12957
+ poll: () => channel.poll(),
12958
+ changed: (signal) => channel.changed(signal),
12959
+ close: () => channel.close(),
12960
+ sealed: channel
12961
+ });
12962
+ }
12963
+ };
12964
+
12767
12965
  // src/kernel/settling.ts
12768
12966
  var SETUP_OPS = /* @__PURE__ */ new Set([
12769
12967
  "proc-list",
@@ -13411,13 +13609,13 @@ var HostfsClient = class {
13411
13609
  const response = await this.send("/api/hostfs/watch", { method: "POST", signal });
13412
13610
  onOpen();
13413
13611
  const reader = response.body.getReader();
13414
- const decoder2 = new TextDecoder();
13612
+ const decoder3 = new TextDecoder();
13415
13613
  let buffered = "";
13416
13614
  try {
13417
13615
  for (; ; ) {
13418
13616
  const { done: done4, value } = await reader.read();
13419
13617
  if (done4) return;
13420
- buffered += decoder2.decode(value, { stream: true });
13618
+ buffered += decoder3.decode(value, { stream: true });
13421
13619
  let end = buffered.indexOf("\n");
13422
13620
  while (end >= 0) {
13423
13621
  const line = buffered.slice(0, end).trim();
@@ -14898,7 +15096,7 @@ var LAYOUT = [
14898
15096
  ];
14899
15097
  var LOAD_SAMPLE_MS = 5e3;
14900
15098
  var LOAD_WINDOWS_MS = [6e4, 3e5, 9e5];
14901
- var encoder3 = new TextEncoder();
15099
+ var encoder4 = new TextEncoder();
14902
15100
  var USERS_MODES = ["off", "report", "enforce"];
14903
15101
  function usersMode(mode = "off") {
14904
15102
  if (USERS_MODES.includes(mode)) return mode;
@@ -15048,12 +15246,19 @@ var Launcher = class {
15048
15246
  fstab = Promise.resolve([]);
15049
15247
  usersMode;
15050
15248
  dac;
15249
+ sealed;
15051
15250
  nextPid = 1e3;
15052
15251
  boot = Date.now();
15053
15252
  terminals = 0;
15054
15253
  constructor(options) {
15055
15254
  this.usersMode = usersMode(options.users);
15056
15255
  this.dac = this.usersMode === "off" ? void 0 : new Dac(this.usersMode, options.onDenial);
15256
+ this.sealed = new SealedBroker(
15257
+ options.sealed,
15258
+ this.usersMode,
15259
+ void 0,
15260
+ (pid) => this.tagOf(pid)
15261
+ );
15057
15262
  if (this.owners) options.fs.trackOwners?.();
15058
15263
  this.mounts = new MountTable({
15059
15264
  open: (type, spec) => this.driver(type, spec),
@@ -15453,6 +15658,7 @@ var Launcher = class {
15453
15658
  ...req.umask !== void 0 ? { umask: req.umask } : {},
15454
15659
  cred: req.cred,
15455
15660
  ...this.owners ? { owners: true } : {},
15661
+ sealed: this.sealed,
15456
15662
  ...this.dac ? { dac: this.dac } : {},
15457
15663
  program: req.program,
15458
15664
  argv0: req.argv0,
@@ -16091,7 +16297,7 @@ var Launcher = class {
16091
16297
  },
16092
16298
  account
16093
16299
  );
16094
- const report = (message3) => options.onData(encoder3.encode(`${message3}\r
16300
+ const report = (message3) => options.onData(encoder4.encode(`${message3}\r
16095
16301
  `));
16096
16302
  const handle = await this.launch(planned, {
16097
16303
  env,
@@ -16128,7 +16334,7 @@ var Launcher = class {
16128
16334
  };
16129
16335
  const stdout = collect(out, options.onStdout);
16130
16336
  const stderr = collect(err, options.onStderr);
16131
- const report = (message3) => stderr(encoder3.encode(`${message3}
16337
+ const report = (message3) => stderr(encoder4.encode(`${message3}
16132
16338
  `));
16133
16339
  if (!planned) {
16134
16340
  report(`${file}: command not found`);
@@ -16665,7 +16871,7 @@ function dialStream(port, onClose) {
16665
16871
 
16666
16872
  // src/client/loopback-fetch.ts
16667
16873
  var OWN_HEADERS = /* @__PURE__ */ new Set(["host", "connection", "content-length", "transfer-encoding"]);
16668
- var encoder4 = new TextEncoder();
16874
+ var encoder5 = new TextEncoder();
16669
16875
  var latin12 = new TextDecoder("latin1");
16670
16876
  var ByteSource = class {
16671
16877
  buffered = new Uint8Array(0);
@@ -16683,7 +16889,7 @@ var ByteSource = class {
16683
16889
  return true;
16684
16890
  }
16685
16891
  async until(marker) {
16686
- const needle = encoder4.encode(marker);
16892
+ const needle = encoder5.encode(marker);
16687
16893
  for (; ; ) {
16688
16894
  const at = indexOf(this.buffered, needle);
16689
16895
  if (at >= 0) return this.take(at + needle.length);
@@ -16791,7 +16997,7 @@ async function requestBytes(request) {
16791
16997
  });
16792
16998
  if (body) lines2.push(`Content-Length: ${body.length}`);
16793
16999
  lines2.push("Connection: close", "", "");
16794
- const head = encoder4.encode(lines2.join("\r\n"));
17000
+ const head = encoder5.encode(lines2.join("\r\n"));
16795
17001
  const out = new Uint8Array(head.length + (body?.length ?? 0));
16796
17002
  out.set(head);
16797
17003
  if (body) out.set(body, head.length);
@@ -16845,8 +17051,8 @@ var KernelCallError = class extends Error {
16845
17051
  this.code = code;
16846
17052
  }
16847
17053
  };
16848
- var encoder5 = new TextEncoder();
16849
- var bytesOf2 = (data) => typeof data === "string" ? encoder5.encode(data) : data;
17054
+ var encoder6 = new TextEncoder();
17055
+ var bytesOf2 = (data) => typeof data === "string" ? encoder6.encode(data) : data;
16850
17056
  var UNAVAILABLE = {
16851
17057
  manualRedirects: false,
16852
17058
  encodedBodies: false,
@@ -17264,8 +17470,8 @@ function nodeWorker(file, live, closed) {
17264
17470
  }
17265
17471
  function textOf(on) {
17266
17472
  if (!on) return void 0;
17267
- const decoder2 = new TextDecoder();
17268
- return (bytes) => on(decoder2.decode(bytes, { stream: true }));
17473
+ const decoder3 = new TextDecoder();
17474
+ return (bytes) => on(decoder3.decode(bytes, { stream: true }));
17269
17475
  }
17270
17476
  async function createNodeKernel(options = {}) {
17271
17477
  const root = options.root ?? memoryRoot();
@@ -17298,6 +17504,7 @@ async function createNodeKernel(options = {}) {
17298
17504
  ...options.hostname !== void 0 ? { hostname: options.hostname } : {},
17299
17505
  ...options.users !== void 0 ? { users: options.users } : {},
17300
17506
  ...options.onDenial ? { onDenial: options.onDenial } : {},
17507
+ ...options.sealed ? { sealed: options.sealed } : {},
17301
17508
  ...options.approve ? { approve: options.approve } : {}
17302
17509
  });
17303
17510
  await launcher.prepare();
@@ -17306,7 +17513,7 @@ async function createNodeKernel(options = {}) {
17306
17513
  pending.add(reject);
17307
17514
  work().then(resolve, reject).finally(() => pending.delete(reject));
17308
17515
  });
17309
- const decoder2 = new TextDecoder();
17516
+ const decoder3 = new TextDecoder();
17310
17517
  return {
17311
17518
  root,
17312
17519
  async run(argv, opts = {}) {
@@ -17323,8 +17530,8 @@ async function createNodeKernel(options = {}) {
17323
17530
  );
17324
17531
  return {
17325
17532
  status: result.status,
17326
- stdout: decoder2.decode(result.stdout),
17327
- stderr: decoder2.decode(result.stderr)
17533
+ stdout: decoder3.decode(result.stdout),
17534
+ stderr: decoder3.decode(result.stderr)
17328
17535
  };
17329
17536
  },
17330
17537
  async openTerminal(argv, opts = {}) {