@ai-ecoverse/slicc-kernel 1.152.2 → 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.
@@ -46,6 +46,111 @@ function serveCdpPort(port, hook, request, onDone) {
46
46
  };
47
47
  }
48
48
 
49
+ // src/embedder-relay.ts
50
+ function fresh(bytes) {
51
+ return bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength ? bytes : bytes.slice();
52
+ }
53
+ function errorOf(err) {
54
+ const name = err?.name;
55
+ const message = err instanceof Error ? err.message : String(err);
56
+ return { name: typeof name === "string" ? name : "Error", message };
57
+ }
58
+ function bytesOf(reply) {
59
+ if (reply instanceof ReadableStream) return reply;
60
+ const bytes = typeof reply === "string" ? new TextEncoder().encode(reply) : reply instanceof Uint8Array ? reply : new Uint8Array(0);
61
+ return new ReadableStream({
62
+ start(controller) {
63
+ if (bytes.length > 0) controller.enqueue(bytes);
64
+ controller.close();
65
+ }
66
+ });
67
+ }
68
+ function bodyStream(id, state, post) {
69
+ return new ReadableStream(
70
+ {
71
+ pull: async (controller) => {
72
+ if (state.body.length === 0) post({ id, bodyPull: true });
73
+ while (state.body.length === 0 && !state.abort.signal.aborted) {
74
+ await new Promise((resolve) => {
75
+ state.wakeBody = resolve;
76
+ });
77
+ }
78
+ const next = state.body.shift();
79
+ if (next) controller.enqueue(next);
80
+ else controller.close();
81
+ }
82
+ },
83
+ { highWaterMark: 0 }
84
+ );
85
+ }
86
+ function embedderAnswerer(port, hookFor) {
87
+ const running = /* @__PURE__ */ new Map();
88
+ const post = (message, transfer = []) => port.postMessage({ embedderReply: message }, transfer);
89
+ const fail = (id, err) => {
90
+ running.delete(id);
91
+ post({ id, error: errorOf(err) });
92
+ };
93
+ const start = async (ask) => {
94
+ const state = { abort: new AbortController(), body: [], wakeBody: void 0 };
95
+ running.set(ask.id, state);
96
+ try {
97
+ const hook = hookFor(ask.client);
98
+ if (!hook || !Object.hasOwn(hook.kinds, ask.kind))
99
+ throw Object.assign(new Error(`this page does not answer ${ask.kind}`), {
100
+ name: "NotSupportedError"
101
+ });
102
+ const reply = await hook.handle({
103
+ kind: ask.kind,
104
+ options: ask.options,
105
+ body: bodyStream(ask.id, state, post),
106
+ stamp: ask.stamp,
107
+ signal: state.abort.signal,
108
+ progress: (line) => post({ id: ask.id, progress: String(line) })
109
+ });
110
+ state.reader = bytesOf(reply).getReader();
111
+ post({ id: ask.id, ready: true });
112
+ } catch (err) {
113
+ fail(ask.id, err);
114
+ }
115
+ };
116
+ const pull = async (id, state) => {
117
+ try {
118
+ const got = await state.reader.read();
119
+ if (got.done) {
120
+ running.delete(id);
121
+ post({ id, done: true });
122
+ return;
123
+ }
124
+ const bytes = fresh(got.value);
125
+ post({ id, chunk: bytes }, [bytes.buffer]);
126
+ } catch (err) {
127
+ fail(id, err);
128
+ }
129
+ };
130
+ const step = (message) => {
131
+ const state = running.get(message.id);
132
+ if (!state) return;
133
+ if ("body" in message) state.body.push(message.body);
134
+ else if ("bodyEnd" in message) state.body.push(null);
135
+ else if ("pull" in message) void pull(message.id, state);
136
+ else {
137
+ running.delete(message.id);
138
+ state.abort.abort(new DOMException(message.cancel, "AbortError"));
139
+ void state.reader?.cancel(message.cancel).catch(() => void 0);
140
+ }
141
+ state.wakeBody?.();
142
+ };
143
+ return {
144
+ handle(data) {
145
+ const message = data?.embedder;
146
+ if (!message) return false;
147
+ if ("ask" in message) void start(message.ask);
148
+ else step(message);
149
+ return true;
150
+ }
151
+ };
152
+ }
153
+
49
154
  // src/facade/port.ts
50
155
  function serveFacadePort(port, hook, { name, stamp }, onDone) {
51
156
  let conn;
@@ -96,6 +201,27 @@ function serveFacadePort(port, hook, { name, stamp }, onDone) {
96
201
  };
97
202
  }
98
203
 
204
+ // src/kernel/pipe.ts
205
+ var PIPE_CAPACITY = 64 * 1024;
206
+
207
+ // src/kernel/embedder.ts
208
+ var EMBEDDER_HEADER_MAX = 64 * 1024;
209
+ var EMBEDDER_WINDOW = 1024 * 1024;
210
+ var EMBEDDER_BUDGET = 256 * 1024 * 1024;
211
+ function kindsOf(hook) {
212
+ if (typeof hook?.handle !== "function" || typeof hook.kinds !== "object" || !hook.kinds)
213
+ throw new TypeError("requests needs kinds and handle");
214
+ return Object.fromEntries(
215
+ Object.entries(hook.kinds).map(([kind, policy]) => [
216
+ kind,
217
+ {
218
+ ...policy?.group !== void 0 ? { group: String(policy.group) } : {},
219
+ ...policy?.users ? { users: [...policy.users] } : {}
220
+ }
221
+ ])
222
+ );
223
+ }
224
+
99
225
  // src/kernel/net/ws-queue.ts
100
226
  var INBOUND_LIMIT = 16 * 1024 * 1024;
101
227
  var MESSAGE_LIMIT = 64 * 1024 * 1024;
@@ -424,7 +550,7 @@ var KERNEL_SIGINFO = Object.freeze({
424
550
  });
425
551
 
426
552
  // src/bytes.ts
427
- function fresh(bytes, start = 0, end = bytes.length) {
553
+ function fresh2(bytes, start = 0, end = bytes.length) {
428
554
  return new Uint8Array(bytes.subarray(start, end));
429
555
  }
430
556
 
@@ -481,7 +607,7 @@ function dialStream(port, onClose) {
481
607
  const writable = new WritableStream({
482
608
  write(chunk) {
483
609
  if (closed) throw errorWithCode("EPIPE: the connection is closed");
484
- const copy = fresh(chunk);
610
+ const copy = fresh2(chunk);
485
611
  const acked = new Promise((resolve, reject) => acks.push({ resolve, reject }));
486
612
  port.postMessage(copy, [copy.buffer]);
487
613
  return acked;
@@ -668,7 +794,7 @@ async function loopbackFetch(dial, input, options) {
668
794
  }
669
795
 
670
796
  // src/client/protocol.ts
671
- var PROTOCOL = [1, 12];
797
+ var PROTOCOL = [1, 13];
672
798
  function locksOf(scope = globalThis) {
673
799
  const locks = scope.navigator?.locks;
674
800
  return typeof locks?.request === "function" ? locks : void 0;
@@ -696,7 +822,7 @@ var KernelCallError = class extends Error {
696
822
  }
697
823
  };
698
824
  var encoder2 = new TextEncoder();
699
- var bytesOf = (data) => typeof data === "string" ? encoder2.encode(data) : data;
825
+ var bytesOf2 = (data) => typeof data === "string" ? encoder2.encode(data) : data;
700
826
  var UNAVAILABLE = {
701
827
  manualRedirects: false,
702
828
  encodedBodies: false,
@@ -780,7 +906,9 @@ var Channel = class {
780
906
  call(call) {
781
907
  return this.request(call).done;
782
908
  }
909
+ requests;
783
910
  receive(data) {
911
+ if (this.requests?.handle(data)) return;
784
912
  if (data.traits && data.id === void 0) {
785
913
  if (this.remote) this.remote.traits = data.traits;
786
914
  for (const listener of [...this.traitsListeners]) listener(data.traits);
@@ -903,7 +1031,7 @@ async function spawnOn(channel, argv, opts) {
903
1031
  });
904
1032
  const started = Promise.withResolvers();
905
1033
  let endedBy;
906
- const options = { ...rest, ...stdin !== void 0 ? { stdin: bytesOf(stdin) } : {} };
1034
+ const options = { ...rest, ...stdin !== void 0 ? { stdin: bytesOf2(stdin) } : {} };
907
1035
  const { done } = channel.request(
908
1036
  { op: "spawn", argv, options },
909
1037
  {
@@ -986,7 +1114,7 @@ async function terminalOn(channel, argv, opts) {
986
1114
  listener = next;
987
1115
  if (next) for (const bytes of backlog.splice(0)) next(bytes);
988
1116
  },
989
- write: (data) => send({ action: "write", bytes: bytesOf(data) }),
1117
+ write: (data) => send({ action: "write", bytes: bytesOf2(data) }),
990
1118
  resize: (cols, rows) => send({ action: "resize", cols, rows }),
991
1119
  signal: (name) => send({ action: "signal", signal: name }),
992
1120
  close: () => send({ action: "close" })
@@ -1048,8 +1176,10 @@ function since(channel, minor, what, run) {
1048
1176
  }
1049
1177
  return run();
1050
1178
  }
1051
- async function greet(channel, lock, timeoutMs) {
1052
- channel.post({ hello: { protocol: PROTOCOL, ...lock ? { lock } : {} } });
1179
+ async function greet(channel, lock, timeoutMs, requests) {
1180
+ channel.post({
1181
+ hello: { protocol: PROTOCOL, ...lock ? { lock } : {}, ...requests ? { requests } : {} }
1182
+ });
1053
1183
  const timer = setTimeout(
1054
1184
  () => channel.end(
1055
1185
  new KernelGoneError(`no slicc-kernel answered on this port within ${timeoutMs} ms`)
@@ -1074,7 +1204,14 @@ async function attachKernel(port, options = {}) {
1074
1204
  const locks = options.locks === null ? void 0 : options.locks ?? locksOf();
1075
1205
  const own = await holdLock(locks);
1076
1206
  const channel = new Channel(port, own.release);
1077
- const hello = await greet(channel, own.name, options.timeoutMs ?? 1e4);
1207
+ const requests = options.requests;
1208
+ if (requests) channel.requests = embedderAnswerer(port, () => requests);
1209
+ const hello = await greet(
1210
+ channel,
1211
+ own.name,
1212
+ options.timeoutMs ?? 1e4,
1213
+ requests ? kindsOf(requests) : void 0
1214
+ );
1078
1215
  channel.protocol = hello.protocol;
1079
1216
  if (hello.lock && locks) void locks.request(hello.lock, () => channel.end(new KernelGoneError()));
1080
1217
  const transport = new RemoteTransport(
@@ -1237,7 +1374,7 @@ function serveFilesystem(port, handlers, capabilities = {}, options = {}) {
1237
1374
  (result) => {
1238
1375
  if (result instanceof Uint8Array) {
1239
1376
  const whole = result.byteOffset === 0 && result.byteLength === result.buffer.byteLength;
1240
- const bytes = options.owned && whole ? result : fresh(result);
1377
+ const bytes = options.owned && whole ? result : fresh2(result);
1241
1378
  reply({ id: data.id, result: bytes }, [bytes.buffer]);
1242
1379
  } else reply({ id: data.id, result: result ?? null });
1243
1380
  },