@ai-ecoverse/slicc-kernel 1.152.1 → 1.153.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/index.js CHANGED
@@ -326,6 +326,111 @@ function clipboardAnswerer(port, hook) {
326
326
  };
327
327
  }
328
328
 
329
+ // src/embedder-relay.ts
330
+ function fresh2(bytes) {
331
+ return bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength ? bytes : bytes.slice();
332
+ }
333
+ function errorOf(err) {
334
+ const name = err?.name;
335
+ const message = err instanceof Error ? err.message : String(err);
336
+ return { name: typeof name === "string" ? name : "Error", message };
337
+ }
338
+ function bytesOf(reply) {
339
+ if (reply instanceof ReadableStream) return reply;
340
+ const bytes = typeof reply === "string" ? new TextEncoder().encode(reply) : reply instanceof Uint8Array ? reply : new Uint8Array(0);
341
+ return new ReadableStream({
342
+ start(controller) {
343
+ if (bytes.length > 0) controller.enqueue(bytes);
344
+ controller.close();
345
+ }
346
+ });
347
+ }
348
+ function bodyStream(id, state, post) {
349
+ return new ReadableStream(
350
+ {
351
+ pull: async (controller) => {
352
+ if (state.body.length === 0) post({ id, bodyPull: true });
353
+ while (state.body.length === 0 && !state.abort.signal.aborted) {
354
+ await new Promise((resolve) => {
355
+ state.wakeBody = resolve;
356
+ });
357
+ }
358
+ const next = state.body.shift();
359
+ if (next) controller.enqueue(next);
360
+ else controller.close();
361
+ }
362
+ },
363
+ { highWaterMark: 0 }
364
+ );
365
+ }
366
+ function embedderAnswerer(port, hookFor) {
367
+ const running = /* @__PURE__ */ new Map();
368
+ const post = (message, transfer = []) => port.postMessage({ embedderReply: message }, transfer);
369
+ const fail = (id, err) => {
370
+ running.delete(id);
371
+ post({ id, error: errorOf(err) });
372
+ };
373
+ const start = async (ask) => {
374
+ const state = { abort: new AbortController(), body: [], wakeBody: void 0 };
375
+ running.set(ask.id, state);
376
+ try {
377
+ const hook = hookFor(ask.client);
378
+ if (!hook || !Object.hasOwn(hook.kinds, ask.kind))
379
+ throw Object.assign(new Error(`this page does not answer ${ask.kind}`), {
380
+ name: "NotSupportedError"
381
+ });
382
+ const reply = await hook.handle({
383
+ kind: ask.kind,
384
+ options: ask.options,
385
+ body: bodyStream(ask.id, state, post),
386
+ stamp: ask.stamp,
387
+ signal: state.abort.signal,
388
+ progress: (line) => post({ id: ask.id, progress: String(line) })
389
+ });
390
+ state.reader = bytesOf(reply).getReader();
391
+ post({ id: ask.id, ready: true });
392
+ } catch (err) {
393
+ fail(ask.id, err);
394
+ }
395
+ };
396
+ const pull = async (id, state) => {
397
+ try {
398
+ const got = await state.reader.read();
399
+ if (got.done) {
400
+ running.delete(id);
401
+ post({ id, done: true });
402
+ return;
403
+ }
404
+ const bytes = fresh2(got.value);
405
+ post({ id, chunk: bytes }, [bytes.buffer]);
406
+ } catch (err) {
407
+ fail(id, err);
408
+ }
409
+ };
410
+ const step = (message) => {
411
+ const state = running.get(message.id);
412
+ if (!state) return;
413
+ if ("body" in message) state.body.push(message.body);
414
+ else if ("bodyEnd" in message) state.body.push(null);
415
+ else if ("pull" in message) void pull(message.id, state);
416
+ else {
417
+ running.delete(message.id);
418
+ state.abort.abort(new DOMException(message.cancel, "AbortError"));
419
+ void state.reader?.cancel(message.cancel).catch(() => void 0);
420
+ }
421
+ state.wakeBody?.();
422
+ };
423
+ return {
424
+ handle(data) {
425
+ const message = data?.embedder;
426
+ if (!message) return false;
427
+ if ("ask" in message) void start(message.ask);
428
+ else step(message);
429
+ return true;
430
+ }
431
+ };
432
+ }
433
+
329
434
  // src/facade/port.ts
330
435
  function serveFacadePort(port, hook, { name, stamp }, onDone) {
331
436
  let conn;
@@ -457,6 +562,24 @@ function integrityAnswerer(port, lookup) {
457
562
  };
458
563
  }
459
564
 
565
+ // src/kernel/embedder.ts
566
+ var EMBEDDER_HEADER_MAX = 64 * 1024;
567
+ var EMBEDDER_WINDOW = 1024 * 1024;
568
+ var EMBEDDER_BUDGET = 256 * 1024 * 1024;
569
+ function kindsOf(hook) {
570
+ if (typeof hook?.handle !== "function" || typeof hook.kinds !== "object" || !hook.kinds)
571
+ throw new TypeError("requests needs kinds and handle");
572
+ return Object.fromEntries(
573
+ Object.entries(hook.kinds).map(([kind, policy]) => [
574
+ kind,
575
+ {
576
+ ...policy?.group !== void 0 ? { group: String(policy.group) } : {},
577
+ ...policy?.users ? { users: [...policy.users] } : {}
578
+ }
579
+ ])
580
+ );
581
+ }
582
+
460
583
  // src/kernel/net/loopback-names.ts
461
584
  var HOST_LOOPBACK = "host.slicc.internal";
462
585
  var HOST_LOOPBACK_ADDRESS = [10, 0, 2, 2];
@@ -1526,7 +1649,7 @@ var RemoteTransport = class {
1526
1649
  };
1527
1650
 
1528
1651
  // src/client/protocol.ts
1529
- var PROTOCOL = [1, 12];
1652
+ var PROTOCOL = [1, 13];
1530
1653
  function locksOf(scope = globalThis) {
1531
1654
  const locks = scope.navigator?.locks;
1532
1655
  return typeof locks?.request === "function" ? locks : void 0;
@@ -1554,7 +1677,7 @@ var KernelCallError = class extends Error {
1554
1677
  }
1555
1678
  };
1556
1679
  var encoder3 = new TextEncoder();
1557
- var bytesOf = (data) => typeof data === "string" ? encoder3.encode(data) : data;
1680
+ var bytesOf2 = (data) => typeof data === "string" ? encoder3.encode(data) : data;
1558
1681
  var UNAVAILABLE = {
1559
1682
  manualRedirects: false,
1560
1683
  encodedBodies: false,
@@ -1638,7 +1761,9 @@ var Channel = class {
1638
1761
  call(call) {
1639
1762
  return this.request(call).done;
1640
1763
  }
1764
+ requests;
1641
1765
  receive(data) {
1766
+ if (this.requests?.handle(data)) return;
1642
1767
  if (data.traits && data.id === void 0) {
1643
1768
  if (this.remote) this.remote.traits = data.traits;
1644
1769
  for (const listener of [...this.traitsListeners]) listener(data.traits);
@@ -1761,7 +1886,7 @@ async function spawnOn(channel, argv, opts) {
1761
1886
  });
1762
1887
  const started = Promise.withResolvers();
1763
1888
  let endedBy;
1764
- const options = { ...rest, ...stdin !== void 0 ? { stdin: bytesOf(stdin) } : {} };
1889
+ const options = { ...rest, ...stdin !== void 0 ? { stdin: bytesOf2(stdin) } : {} };
1765
1890
  const { done } = channel.request(
1766
1891
  { op: "spawn", argv, options },
1767
1892
  {
@@ -1844,7 +1969,7 @@ async function terminalOn(channel, argv, opts) {
1844
1969
  listener = next;
1845
1970
  if (next) for (const bytes of backlog.splice(0)) next(bytes);
1846
1971
  },
1847
- write: (data) => send2({ action: "write", bytes: bytesOf(data) }),
1972
+ write: (data) => send2({ action: "write", bytes: bytesOf2(data) }),
1848
1973
  resize: (cols, rows) => send2({ action: "resize", cols, rows }),
1849
1974
  signal: (name) => send2({ action: "signal", signal: name }),
1850
1975
  close: () => send2({ action: "close" })
@@ -1906,8 +2031,10 @@ function since(channel, minor, what, run) {
1906
2031
  }
1907
2032
  return run();
1908
2033
  }
1909
- async function greet(channel, lock, timeoutMs) {
1910
- channel.post({ hello: { protocol: PROTOCOL, ...lock ? { lock } : {} } });
2034
+ async function greet(channel, lock, timeoutMs, requests) {
2035
+ channel.post({
2036
+ hello: { protocol: PROTOCOL, ...lock ? { lock } : {}, ...requests ? { requests } : {} }
2037
+ });
1911
2038
  const timer = setTimeout(
1912
2039
  () => channel.end(
1913
2040
  new KernelGoneError(`no slicc-kernel answered on this port within ${timeoutMs} ms`)
@@ -1932,7 +2059,14 @@ async function attachKernel(port, options = {}) {
1932
2059
  const locks = options.locks === null ? void 0 : options.locks ?? locksOf();
1933
2060
  const own = await holdLock(locks);
1934
2061
  const channel = new Channel(port, own.release);
1935
- const hello = await greet(channel, own.name, options.timeoutMs ?? 1e4);
2062
+ const requests = options.requests;
2063
+ if (requests) channel.requests = embedderAnswerer(port, () => requests);
2064
+ const hello = await greet(
2065
+ channel,
2066
+ own.name,
2067
+ options.timeoutMs ?? 1e4,
2068
+ requests ? kindsOf(requests) : void 0
2069
+ );
1936
2070
  channel.protocol = hello.protocol;
1937
2071
  if (hello.lock && locks) void locks.request(hello.lock, () => channel.end(new KernelGoneError()));
1938
2072
  const transport = new RemoteTransport(
@@ -2163,7 +2297,7 @@ function fsError2(code, message = code) {
2163
2297
  // src/mount/hostfs.ts
2164
2298
  var HOSTFS_IO = 16 * 1024 * 1024;
2165
2299
  var codeOf = (err) => err?.code;
2166
- var errorOf = (err) => ({
2300
+ var errorOf2 = (err) => ({
2167
2301
  code: typeof codeOf(err) === "string" ? codeOf(err) : "EIO",
2168
2302
  message: err?.message ?? String(err)
2169
2303
  });
@@ -2213,7 +2347,7 @@ function serveHostfsPort(port, transport) {
2213
2347
  );
2214
2348
  send2({ id, end: true });
2215
2349
  } catch (err) {
2216
- send2({ id, error: errorOf(err) });
2350
+ send2({ id, error: errorOf2(err) });
2217
2351
  } finally {
2218
2352
  watches.delete(id);
2219
2353
  }
@@ -2241,7 +2375,7 @@ function serveHostfsPort(port, transport) {
2241
2375
  if (op !== "call") throw fsError2("EINVAL", `unknown hostfs port op ${op}`);
2242
2376
  send2({ id, result: await answer(data.name, data.body) });
2243
2377
  } catch (err) {
2244
- send2({ id, error: errorOf(err) });
2378
+ send2({ id, error: errorOf2(err) });
2245
2379
  }
2246
2380
  };
2247
2381
  const stop = () => {
@@ -2309,6 +2443,7 @@ function initCall(options, transport) {
2309
2443
  ...options.onDenial ? { denials: true } : {},
2310
2444
  ...options.sealed ? { sealed: true } : {},
2311
2445
  ...options.clipboard ? { clipboard: true } : {},
2446
+ ...options.requests ? { requests: kindsOf(options.requests) } : {},
2312
2447
  ...options.approve ? { approve: true } : {},
2313
2448
  ...options.protect ? { protect: protectInit(options.protect) } : {},
2314
2449
  ...options.processMounts !== void 0 ? {
@@ -2468,12 +2603,30 @@ function checkOptions(options) {
2468
2603
  integrityOptions(options.protect?.integrity);
2469
2604
  facadesInit(options.facades);
2470
2605
  }
2471
- function hookRelays(worker, options) {
2606
+ function connector(call, bound) {
2607
+ return async (connectOptions = {}) => {
2608
+ const { requests, ...rest } = connectOptions;
2609
+ if (requests === void 0 || requests === "attach")
2610
+ return await call({
2611
+ op: "connect",
2612
+ ...rest,
2613
+ ...requests ? { requests } : {}
2614
+ });
2615
+ const made = await call({ op: "connect", ...rest, requests: kindsOf(requests) });
2616
+ bound.set(made.client, requests);
2617
+ return made.port;
2618
+ };
2619
+ }
2620
+ function hookRelays(worker, options, bound) {
2472
2621
  const sealed = sealedAnswerer(worker, options.sealed);
2473
2622
  const clipboard = clipboardAnswerer(worker, options.clipboard);
2474
2623
  const integrity = integrityAnswerer(worker, options.protect?.integrity?.lookup);
2624
+ const requests = embedderAnswerer(
2625
+ worker,
2626
+ (client) => client === 0 ? options.requests : bound.get(client)
2627
+ );
2475
2628
  return {
2476
- handle: (data) => sealed.handle(data) || clipboard.handle(data) || integrity(data),
2629
+ handle: (data) => sealed.handle(data) || clipboard.handle(data) || requests.handle(data) || integrity(data),
2477
2630
  close: () => sealed.close()
2478
2631
  };
2479
2632
  }
@@ -2514,7 +2667,8 @@ async function createKernel(options = {}) {
2514
2667
  );
2515
2668
  const cdp = cdpBridge(options.cdp);
2516
2669
  const facades = facadeBridge(options.facades);
2517
- const sealed = hookRelays(worker, options);
2670
+ const bound = /* @__PURE__ */ new Map();
2671
+ const sealed = hookRelays(worker, options, bound);
2518
2672
  const approvals = approver(options.approve, worker);
2519
2673
  const fail = (error) => {
2520
2674
  dials.reset();
@@ -2639,7 +2793,7 @@ async function createKernel(options = {}) {
2639
2793
  return decodedRun(result);
2640
2794
  },
2641
2795
  openTerminal,
2642
- connect: async (connectOptions = {}) => await call({ op: "connect", ...connectOptions }),
2796
+ connect: connector(call, bound),
2643
2797
  ...accounts(call, options.users === void 0 ? DEFAULT_USERS : options.users),
2644
2798
  setRoutes: async (routes) => void await call({ op: "routes", routes }),
2645
2799
  chmod: async (path, mode) => void await call({ op: "chmod", path, mode }),