@ai-ecoverse/slicc-kernel 1.67.1 → 1.69.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
@@ -838,6 +838,16 @@ function written(device, bytes) {
838
838
  if (device === "full" && bytes.length > 0) throw new KernelError("ENOSPC");
839
839
  return bytes.length;
840
840
  }
841
+ var DEVICE_PATHS = /* @__PURE__ */ new Map([
842
+ ["/dev/null", "null"],
843
+ ["/dev/zero", "zero"],
844
+ ["/dev/full", "full"],
845
+ ["/dev/urandom", "urandom"],
846
+ ["/dev/random", "urandom"]
847
+ ]);
848
+ function deviceAt(path) {
849
+ return DEVICE_PATHS.get(path);
850
+ }
841
851
  function deviceFile(device, access2) {
842
852
  const read = async (max) => {
843
853
  if (device === "null") return new Uint8Array(0);
@@ -866,6 +876,7 @@ function kernelFdKind(file) {
866
876
  if (file.held) return "held";
867
877
  if (file.heldMeta && "device" in file.heldMeta) return "device";
868
878
  if (file.tty) return "tty";
879
+ if (file.sealed) return "sealed";
869
880
  return file.seek ? "file" : "stream";
870
881
  }
871
882
  var FdTable = class _FdTable {
@@ -11182,6 +11193,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
11182
11193
  "fd-open-tty",
11183
11194
  "fd-tty-names",
11184
11195
  "fd-tty-owner",
11196
+ "fd-open-sealed",
11185
11197
  "tty-get",
11186
11198
  "tty-set",
11187
11199
  "tty-winsz",
@@ -11237,6 +11249,7 @@ var WasmProcess = class {
11237
11249
  ignored = 0;
11238
11250
  inherited = 0;
11239
11251
  interrupt = new AbortController();
11252
+ gone = new AbortController();
11240
11253
  dying = false;
11241
11254
  umask = DEFAULT_UMASK;
11242
11255
  cred;
@@ -11459,6 +11472,7 @@ var WasmProcess = class {
11459
11472
  }
11460
11473
  async write(fd, body, nonblock = false, cancelled) {
11461
11474
  const file = this.fds.get(fd).file;
11475
+ if (file.sealed) return file.sealed.send(body, await this.sealedCaller(), this.gone.signal);
11462
11476
  if (!file.write) throw new KernelError("EBADF");
11463
11477
  if (!pollFile(file).writable) {
11464
11478
  if (nonblock) throw new KernelError("EAGAIN");
@@ -11472,6 +11486,8 @@ var WasmProcess = class {
11472
11486
  }
11473
11487
  async openVfs(req) {
11474
11488
  if (inProc(req.path)) return this.openProc(req, req.path);
11489
+ const device = req.orphan ? void 0 : deviceAt(req.path);
11490
+ if (device) return this.openDevice(req, device);
11475
11491
  const alias = req.orphan ? void 0 : await procAlias(this.options.fs, req.path, !req.exclusive);
11476
11492
  if (typeof alias === "object")
11477
11493
  throw Object.assign(new Error(alias.refused), { code: alias.refused });
@@ -11509,6 +11525,14 @@ var WasmProcess = class {
11509
11525
  }
11510
11526
  return fd;
11511
11527
  }
11528
+ openDevice(req, device) {
11529
+ if (req.exclusive) throw Object.assign(new Error(req.path), { code: "EEXIST" });
11530
+ const access2 = req.flags & WRITE_ACCESS;
11531
+ return this.fds.install(
11532
+ deviceFile(device, access2 === 0 ? "read" : access2 === 1 ? "write" : void 0),
11533
+ 3
11534
+ );
11535
+ }
11512
11536
  async identified(stat, known) {
11513
11537
  const first = await stat();
11514
11538
  if (first.orphan) return first;
@@ -11540,6 +11564,24 @@ var WasmProcess = class {
11540
11564
  if (name2 !== void 0) ttyOpenable(this.guarded(), tty);
11541
11565
  return this.fds.install(tty.file(), 3);
11542
11566
  }
11567
+ openSealed() {
11568
+ const broker = this.options.sealed;
11569
+ if (!broker) throw new KernelError("ENOENT");
11570
+ return this.fds.install(broker.open(), 3);
11571
+ }
11572
+ async sealedCaller() {
11573
+ const shown = await this.options.identity?.();
11574
+ const broker = this.options.sealed;
11575
+ const tag = broker.tagOf(this.pid);
11576
+ return {
11577
+ pid: shown?.pid ?? this.pid,
11578
+ ppid: shown?.ppid ?? 0,
11579
+ uid: this.cred.euid,
11580
+ gid: this.cred.egid,
11581
+ ...tag !== void 0 ? { tag } : {},
11582
+ users: broker.users
11583
+ };
11584
+ }
11543
11585
  guarded() {
11544
11586
  const { guard: guard2 } = this.options;
11545
11587
  return guard2 && { fs: guard2.fs, dac: guard2.dac, cred: this.cred, pid: this.pid };
@@ -11660,6 +11702,8 @@ var WasmProcess = class {
11660
11702
  return { ok: true, kind: "json", json: this.openTty(req.name) };
11661
11703
  case "fd-tty-names":
11662
11704
  return { ok: true, kind: "json", json: this.options.jobs?.terminalNames() ?? [] };
11705
+ case "fd-open-sealed":
11706
+ return { ok: true, kind: "json", json: this.openSealed() };
11663
11707
  case "fd-tty-owner":
11664
11708
  return { ok: true, kind: "json", json: this.terminalByName(req.name).owner ?? null };
11665
11709
  case "fd-select": {
@@ -12095,6 +12139,7 @@ var WasmProcess = class {
12095
12139
  async exit() {
12096
12140
  if (this.exited) return;
12097
12141
  this.exited = true;
12142
+ this.gone.abort();
12098
12143
  this.die();
12099
12144
  this.clearAlarm();
12100
12145
  this.interrupt.abort();
@@ -12282,6 +12327,7 @@ function processOptions(opts, header4, hooks, created3) {
12282
12327
  return {
12283
12328
  ...inherited(opts),
12284
12329
  ...opts.owners ? { owners: true } : {},
12330
+ ...opts.sealed ? { sealed: opts.sealed } : {},
12285
12331
  ...opts.dac ? { guard: { dac: opts.dac, fs: opts.fs, created: created3 } } : {},
12286
12332
  ...opts.identity ? { identity: opts.identity } : {},
12287
12333
  ...opts.onSyscall ? { onSyscall: opts.onSyscall } : {},
@@ -12764,6 +12810,178 @@ function replayingHops(inner, heldMs = HELD_MS) {
12764
12810
  };
12765
12811
  }
12766
12812
 
12813
+ // src/kernel/sealed.ts
12814
+ var SEALED_MAX_BYTES = 64 * 1024;
12815
+ var SEALED_TIMEOUT_MS = 1e4;
12816
+ var SEALED_OPS = /* @__PURE__ */ new Set([
12817
+ "seal",
12818
+ "placeholder",
12819
+ "list",
12820
+ "test",
12821
+ "request",
12822
+ "status",
12823
+ "cancel",
12824
+ "materialize"
12825
+ ]);
12826
+ var encoder3 = new TextEncoder();
12827
+ var decoder2 = new TextDecoder("utf-8", { fatal: true });
12828
+ function parseSealed(bytes) {
12829
+ try {
12830
+ if (bytes.length > SEALED_MAX_BYTES) throw new KernelError("EMSGSIZE");
12831
+ let parsed2;
12832
+ try {
12833
+ parsed2 = JSON.parse(decoder2.decode(bytes));
12834
+ } catch {
12835
+ throw new KernelError("EINVAL");
12836
+ }
12837
+ if (typeof parsed2 !== "object" || parsed2 === null || Array.isArray(parsed2))
12838
+ throw new KernelError("EINVAL");
12839
+ const req = parsed2;
12840
+ if (req.v !== 1 || typeof req.op !== "string" || !SEALED_OPS.has(req.op))
12841
+ throw new KernelError("EINVAL");
12842
+ return req;
12843
+ } finally {
12844
+ bytes.fill(0);
12845
+ }
12846
+ }
12847
+ function errorReply(code, message3) {
12848
+ return { v: 1, error: { code, message: message3 } };
12849
+ }
12850
+ function isRecord(value) {
12851
+ return typeof value === "object" && value !== null && !Array.isArray(value);
12852
+ }
12853
+ function serialized(reply) {
12854
+ let plain;
12855
+ try {
12856
+ const text = JSON.stringify(reply);
12857
+ plain = text === void 0 ? void 0 : JSON.parse(text);
12858
+ } catch (err) {
12859
+ return JSON.stringify(errorReply("EIO", lineOf(err)));
12860
+ }
12861
+ if (!isRecord(plain)) return JSON.stringify(errorReply("EIO", "the vault gave no reply"));
12862
+ const { v: _, ...rest2 } = plain;
12863
+ return JSON.stringify({ v: 1, ...rest2 });
12864
+ }
12865
+ function lineOf(err) {
12866
+ const text = err instanceof Error ? err.message : String(err);
12867
+ return (text.split("\n")[0] ?? "").slice(0, 200);
12868
+ }
12869
+ var SealedChannel = class {
12870
+ reply;
12871
+ offset = 0;
12872
+ inflight;
12873
+ broker;
12874
+ constructor(broker) {
12875
+ this.broker = broker;
12876
+ }
12877
+ send(bytes, caller, gone) {
12878
+ const length2 = bytes.length;
12879
+ const fields = parseSealed(bytes);
12880
+ this.reply = void 0;
12881
+ this.offset = 0;
12882
+ this.inflight?.control.abort("replaced");
12883
+ const control = new AbortController();
12884
+ const withdraw = () => control.abort("withdrawn");
12885
+ if (gone.aborted) withdraw();
12886
+ else gone.addEventListener("abort", withdraw, { once: true });
12887
+ const timer = setTimeout(() => control.abort("timeout"), this.broker.timeoutMs);
12888
+ const req = { ...fields, v: 1, op: fields.op, caller };
12889
+ const flight = { control, done: Promise.resolve() };
12890
+ flight.done = this.answer(req, control.signal).then((reply) => {
12891
+ clearTimeout(timer);
12892
+ gone.removeEventListener("abort", withdraw);
12893
+ if (this.inflight !== flight) return;
12894
+ this.inflight = void 0;
12895
+ if (reply) this.reply = encoder3.encode(serialized(reply));
12896
+ });
12897
+ this.inflight = flight;
12898
+ return length2;
12899
+ }
12900
+ async answer(req, signal) {
12901
+ const hook = this.broker.hook;
12902
+ if (!hook) return errorReply("ENOTCONN", "no vault is connected");
12903
+ const stopped = new Promise((resolve) => {
12904
+ signal.addEventListener("abort", () => resolve(void 0), { once: true });
12905
+ });
12906
+ if (signal.aborted) return void 0;
12907
+ const asked = Promise.resolve().then(() => hook(req, { signal })).then(
12908
+ (reply2) => isRecord(reply2) ? reply2 : errorReply("EIO", "the vault gave no reply"),
12909
+ (err) => errorReply("EIO", lineOf(err))
12910
+ );
12911
+ const reply = await Promise.race([asked, stopped]);
12912
+ if (!signal.aborted) return reply;
12913
+ return signal.reason === "timeout" ? errorReply("ETIMEDOUT", "the vault did not answer within 10 s") : void 0;
12914
+ }
12915
+ async read(max, signal) {
12916
+ for (; ; ) {
12917
+ if (this.reply) {
12918
+ const out = this.reply.slice(this.offset, this.offset + max);
12919
+ this.offset += out.length;
12920
+ if (this.offset >= this.reply.length) {
12921
+ this.reply = void 0;
12922
+ this.offset = 0;
12923
+ }
12924
+ return out;
12925
+ }
12926
+ const flight = this.inflight;
12927
+ if (!flight) return new Uint8Array(0);
12928
+ await this.until(flight, signal);
12929
+ }
12930
+ }
12931
+ async until(flight, signal) {
12932
+ if (!signal) return flight.done;
12933
+ if (signal.aborted) throw new KernelError("EINTR");
12934
+ let stop = () => {
12935
+ };
12936
+ const interrupted2 = new Promise((_, reject) => {
12937
+ stop = () => reject(new KernelError("EINTR"));
12938
+ signal.addEventListener("abort", stop, { once: true });
12939
+ });
12940
+ try {
12941
+ await Promise.race([flight.done, interrupted2]);
12942
+ } finally {
12943
+ signal.removeEventListener("abort", stop);
12944
+ }
12945
+ }
12946
+ poll() {
12947
+ return { readable: this.reply !== void 0 || !this.inflight, writable: true, hangup: false };
12948
+ }
12949
+ async changed(signal) {
12950
+ const flight = this.inflight;
12951
+ if (flight) await this.until(flight, signal);
12952
+ }
12953
+ close() {
12954
+ this.inflight?.control.abort("withdrawn");
12955
+ this.inflight = void 0;
12956
+ this.reply = void 0;
12957
+ }
12958
+ };
12959
+ var SealedBroker = class {
12960
+ hook;
12961
+ users;
12962
+ timeoutMs;
12963
+ tagOf;
12964
+ constructor(hook, users, timeoutMs = SEALED_TIMEOUT_MS, tagOf = () => void 0) {
12965
+ this.hook = hook;
12966
+ this.users = users;
12967
+ this.timeoutMs = timeoutMs;
12968
+ this.tagOf = tagOf;
12969
+ }
12970
+ open() {
12971
+ const channel = new SealedChannel(this);
12972
+ return new OpenFile({
12973
+ read: (max, signal) => channel.read(max, signal),
12974
+ write: async () => {
12975
+ throw new KernelError("EINVAL");
12976
+ },
12977
+ poll: () => channel.poll(),
12978
+ changed: (signal) => channel.changed(signal),
12979
+ close: () => channel.close(),
12980
+ sealed: channel
12981
+ });
12982
+ }
12983
+ };
12984
+
12767
12985
  // src/kernel/settling.ts
12768
12986
  var SETUP_OPS = /* @__PURE__ */ new Set([
12769
12987
  "proc-list",
@@ -13411,13 +13629,13 @@ var HostfsClient = class {
13411
13629
  const response = await this.send("/api/hostfs/watch", { method: "POST", signal });
13412
13630
  onOpen();
13413
13631
  const reader = response.body.getReader();
13414
- const decoder2 = new TextDecoder();
13632
+ const decoder3 = new TextDecoder();
13415
13633
  let buffered = "";
13416
13634
  try {
13417
13635
  for (; ; ) {
13418
13636
  const { done: done4, value } = await reader.read();
13419
13637
  if (done4) return;
13420
- buffered += decoder2.decode(value, { stream: true });
13638
+ buffered += decoder3.decode(value, { stream: true });
13421
13639
  let end = buffered.indexOf("\n");
13422
13640
  while (end >= 0) {
13423
13641
  const line = buffered.slice(0, end).trim();
@@ -14898,7 +15116,7 @@ var LAYOUT = [
14898
15116
  ];
14899
15117
  var LOAD_SAMPLE_MS = 5e3;
14900
15118
  var LOAD_WINDOWS_MS = [6e4, 3e5, 9e5];
14901
- var encoder3 = new TextEncoder();
15119
+ var encoder4 = new TextEncoder();
14902
15120
  var USERS_MODES = ["off", "report", "enforce"];
14903
15121
  function usersMode(mode = "off") {
14904
15122
  if (USERS_MODES.includes(mode)) return mode;
@@ -15048,12 +15266,19 @@ var Launcher = class {
15048
15266
  fstab = Promise.resolve([]);
15049
15267
  usersMode;
15050
15268
  dac;
15269
+ sealed;
15051
15270
  nextPid = 1e3;
15052
15271
  boot = Date.now();
15053
15272
  terminals = 0;
15054
15273
  constructor(options) {
15055
15274
  this.usersMode = usersMode(options.users);
15056
15275
  this.dac = this.usersMode === "off" ? void 0 : new Dac(this.usersMode, options.onDenial);
15276
+ this.sealed = new SealedBroker(
15277
+ options.sealed,
15278
+ this.usersMode,
15279
+ void 0,
15280
+ (pid) => this.tagOf(pid)
15281
+ );
15057
15282
  if (this.owners) options.fs.trackOwners?.();
15058
15283
  this.mounts = new MountTable({
15059
15284
  open: (type, spec) => this.driver(type, spec),
@@ -15453,6 +15678,7 @@ var Launcher = class {
15453
15678
  ...req.umask !== void 0 ? { umask: req.umask } : {},
15454
15679
  cred: req.cred,
15455
15680
  ...this.owners ? { owners: true } : {},
15681
+ sealed: this.sealed,
15456
15682
  ...this.dac ? { dac: this.dac } : {},
15457
15683
  program: req.program,
15458
15684
  argv0: req.argv0,
@@ -16091,7 +16317,7 @@ var Launcher = class {
16091
16317
  },
16092
16318
  account
16093
16319
  );
16094
- const report = (message3) => options.onData(encoder3.encode(`${message3}\r
16320
+ const report = (message3) => options.onData(encoder4.encode(`${message3}\r
16095
16321
  `));
16096
16322
  const handle = await this.launch(planned, {
16097
16323
  env,
@@ -16128,7 +16354,7 @@ var Launcher = class {
16128
16354
  };
16129
16355
  const stdout = collect(out, options.onStdout);
16130
16356
  const stderr = collect(err, options.onStderr);
16131
- const report = (message3) => stderr(encoder3.encode(`${message3}
16357
+ const report = (message3) => stderr(encoder4.encode(`${message3}
16132
16358
  `));
16133
16359
  if (!planned) {
16134
16360
  report(`${file}: command not found`);
@@ -16665,7 +16891,7 @@ function dialStream(port, onClose) {
16665
16891
 
16666
16892
  // src/client/loopback-fetch.ts
16667
16893
  var OWN_HEADERS = /* @__PURE__ */ new Set(["host", "connection", "content-length", "transfer-encoding"]);
16668
- var encoder4 = new TextEncoder();
16894
+ var encoder5 = new TextEncoder();
16669
16895
  var latin12 = new TextDecoder("latin1");
16670
16896
  var ByteSource = class {
16671
16897
  buffered = new Uint8Array(0);
@@ -16683,7 +16909,7 @@ var ByteSource = class {
16683
16909
  return true;
16684
16910
  }
16685
16911
  async until(marker) {
16686
- const needle = encoder4.encode(marker);
16912
+ const needle = encoder5.encode(marker);
16687
16913
  for (; ; ) {
16688
16914
  const at = indexOf(this.buffered, needle);
16689
16915
  if (at >= 0) return this.take(at + needle.length);
@@ -16791,7 +17017,7 @@ async function requestBytes(request) {
16791
17017
  });
16792
17018
  if (body) lines2.push(`Content-Length: ${body.length}`);
16793
17019
  lines2.push("Connection: close", "", "");
16794
- const head = encoder4.encode(lines2.join("\r\n"));
17020
+ const head = encoder5.encode(lines2.join("\r\n"));
16795
17021
  const out = new Uint8Array(head.length + (body?.length ?? 0));
16796
17022
  out.set(head);
16797
17023
  if (body) out.set(body, head.length);
@@ -16845,8 +17071,8 @@ var KernelCallError = class extends Error {
16845
17071
  this.code = code;
16846
17072
  }
16847
17073
  };
16848
- var encoder5 = new TextEncoder();
16849
- var bytesOf2 = (data) => typeof data === "string" ? encoder5.encode(data) : data;
17074
+ var encoder6 = new TextEncoder();
17075
+ var bytesOf2 = (data) => typeof data === "string" ? encoder6.encode(data) : data;
16850
17076
  var UNAVAILABLE = {
16851
17077
  manualRedirects: false,
16852
17078
  encodedBodies: false,
@@ -17264,8 +17490,8 @@ function nodeWorker(file, live, closed) {
17264
17490
  }
17265
17491
  function textOf(on) {
17266
17492
  if (!on) return void 0;
17267
- const decoder2 = new TextDecoder();
17268
- return (bytes) => on(decoder2.decode(bytes, { stream: true }));
17493
+ const decoder3 = new TextDecoder();
17494
+ return (bytes) => on(decoder3.decode(bytes, { stream: true }));
17269
17495
  }
17270
17496
  async function createNodeKernel(options = {}) {
17271
17497
  const root = options.root ?? memoryRoot();
@@ -17298,6 +17524,7 @@ async function createNodeKernel(options = {}) {
17298
17524
  ...options.hostname !== void 0 ? { hostname: options.hostname } : {},
17299
17525
  ...options.users !== void 0 ? { users: options.users } : {},
17300
17526
  ...options.onDenial ? { onDenial: options.onDenial } : {},
17527
+ ...options.sealed ? { sealed: options.sealed } : {},
17301
17528
  ...options.approve ? { approve: options.approve } : {}
17302
17529
  });
17303
17530
  await launcher.prepare();
@@ -17306,7 +17533,7 @@ async function createNodeKernel(options = {}) {
17306
17533
  pending.add(reject);
17307
17534
  work().then(resolve, reject).finally(() => pending.delete(reject));
17308
17535
  });
17309
- const decoder2 = new TextDecoder();
17536
+ const decoder3 = new TextDecoder();
17310
17537
  return {
17311
17538
  root,
17312
17539
  async run(argv, opts = {}) {
@@ -17323,8 +17550,8 @@ async function createNodeKernel(options = {}) {
17323
17550
  );
17324
17551
  return {
17325
17552
  status: result.status,
17326
- stdout: decoder2.decode(result.stdout),
17327
- stderr: decoder2.decode(result.stderr)
17553
+ stdout: decoder3.decode(result.stdout),
17554
+ stderr: decoder3.decode(result.stderr)
17328
17555
  };
17329
17556
  },
17330
17557
  async openTerminal(argv, opts = {}) {