@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/README.md +26 -2
- package/dist/driver-worker.js +147 -10
- package/dist/driver-worker.js.map +4 -4
- package/dist/index.js +168 -14
- package/dist/index.js.map +4 -4
- package/dist/kernel-worker.js +828 -152
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-driver-worker.js +147 -10
- package/dist/node-driver-worker.js.map +4 -4
- package/dist/node-process-worker.js +71 -21
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +966 -167
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +71 -21
- package/dist/process-worker.js.map +3 -3
- package/dist/types/client/attach.d.ts +2 -0
- package/dist/types/client/protocol.d.ts +4 -0
- package/dist/types/client/serve-client.d.ts +2 -0
- package/dist/types/embedder-relay.d.ts +58 -0
- package/dist/types/fs/unlinked.d.ts +4 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/kernel/embedder.d.ts +100 -0
- package/dist/types/kernel/fd-table.d.ts +3 -1
- package/dist/types/kernel/host.d.ts +8 -0
- package/dist/types/kernel/process.d.ts +17 -0
- package/dist/types/launcher.d.ts +13 -0
- package/dist/types/mount/mount-fs.d.ts +1 -0
- package/dist/types/node.d.ts +3 -0
- package/dist/types/process/kernel-streams.d.ts +2 -1
- package/dist/types/process/wasi/wasi-fds.d.ts +1 -0
- package/dist/types/realm/sync-fs-token-registry.d.ts +1 -0
- package/dist/types/serve.d.ts +3 -0
- package/package.json +2 -2
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,
|
|
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
|
|
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:
|
|
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:
|
|
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({
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
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:
|
|
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 }),
|