@ai-ecoverse/slicc-kernel 1.170.4 → 1.172.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 +24 -8
- package/dist/driver-worker.js +35 -11
- package/dist/driver-worker.js.map +3 -3
- package/dist/index.js +263 -53
- package/dist/index.js.map +4 -4
- package/dist/kernel-worker.js +779 -438
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-driver-worker.js +39 -15
- package/dist/node-driver-worker.js.map +3 -3
- package/dist/node-process-worker.cjs +1 -1
- package/dist/node-process-worker.js +1 -1
- package/dist/node.js +798 -488
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +1 -1
- package/dist/testing.js +498 -3
- package/dist/testing.js.map +4 -4
- package/dist/types/fs/attest.d.ts +12 -2
- package/dist/types/index.d.ts +13 -5
- package/dist/types/kernel/net/http-syscalls.d.ts +3 -1
- package/dist/types/kernel/net/loopback-transport.d.ts +1 -1
- package/dist/types/kernel/net/placeholder-floor.d.ts +9 -3
- package/dist/types/kernel/net/remote-transport.d.ts +8 -2
- package/dist/types/kernel/net/sealed-fetch.d.ts +27 -0
- package/dist/types/kernel/net/transport.d.ts +6 -1
- package/dist/types/kernel/socket.d.ts +4 -1
- package/dist/types/launcher.d.ts +12 -2
- package/dist/types/node/follow.d.ts +4 -0
- package/dist/types/node.d.ts +13 -4
- package/dist/types/sealed-relay.d.ts +12 -2
- package/dist/types/serve.d.ts +8 -1
- package/dist/types/testing.d.ts +3 -0
- package/dist/types/transport.d.ts +4 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -598,6 +598,54 @@ function isHostname(name) {
|
|
|
598
598
|
return name.split(".").every((l) => LABEL.test(l));
|
|
599
599
|
}
|
|
600
600
|
|
|
601
|
+
// src/body-idle.ts
|
|
602
|
+
var BODY_IDLE_MS = 5 * 60 * 1e3;
|
|
603
|
+
function idleFailure(ms) {
|
|
604
|
+
return Object.assign(new Error(`the response body sent no data for ${ms} ms`), {
|
|
605
|
+
code: "ETIMEDOUT"
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
async function readWithin(reader, ms) {
|
|
609
|
+
if (!(ms > 0 && ms < Number.POSITIVE_INFINITY)) return reader.read();
|
|
610
|
+
let timer;
|
|
611
|
+
const idle = new Promise((_, reject) => {
|
|
612
|
+
timer = setTimeout(() => reject(idleFailure(ms)), ms);
|
|
613
|
+
});
|
|
614
|
+
try {
|
|
615
|
+
return await Promise.race([reader.read(), idle]);
|
|
616
|
+
} finally {
|
|
617
|
+
clearTimeout(timer);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// src/kernel/net/sealed-fetch.ts
|
|
622
|
+
var SEALED_FETCH_VERSION = 1;
|
|
623
|
+
var UNSAFE_FIELD = /[\r\n\0]/;
|
|
624
|
+
function sealedHooks(option) {
|
|
625
|
+
if (!option) return {};
|
|
626
|
+
if (typeof option === "function") return { request: option };
|
|
627
|
+
const { request, fetch } = option;
|
|
628
|
+
if (typeof request !== "function" || fetch !== void 0 && typeof fetch !== "function") {
|
|
629
|
+
throw new TypeError("sealed takes a function or { request, fetch? }");
|
|
630
|
+
}
|
|
631
|
+
return { request, ...fetch ? { fetch } : {} };
|
|
632
|
+
}
|
|
633
|
+
function headerList(headers) {
|
|
634
|
+
return Array.isArray(headers) && headers.every(
|
|
635
|
+
(field) => Array.isArray(field) && field.length === 2 && field.every((text) => typeof text === "string" && !UNSAFE_FIELD.test(text))
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
function sealedReplyValid(reply) {
|
|
639
|
+
if (typeof reply !== "object" || reply === null) return false;
|
|
640
|
+
const { redirects, redirected, status, statusText, headers, url, body, cancel } = reply;
|
|
641
|
+
return redirects === void 0 && redirected !== true && Number.isInteger(status) && status >= 100 && status <= 599 && typeof statusText === "string" && !UNSAFE_FIELD.test(statusText) && headerList(headers) && (url === void 0 || typeof url === "string") && typeof body?.[Symbol.asyncIterator] === "function" && typeof cancel === "function";
|
|
642
|
+
}
|
|
643
|
+
function dropSealedReply(reply) {
|
|
644
|
+
const { cancel } = reply ?? {};
|
|
645
|
+
if (typeof cancel !== "function") return;
|
|
646
|
+
void Promise.resolve().then(() => cancel.call(reply)).catch(() => void 0);
|
|
647
|
+
}
|
|
648
|
+
|
|
601
649
|
// src/kernel/net/routes.ts
|
|
602
650
|
var HOST_ADDRESS = HOST_LOOPBACK_ADDRESS.join(".");
|
|
603
651
|
function ipv4Bytes(text) {
|
|
@@ -917,8 +965,129 @@ var KERNEL_SIGINFO = Object.freeze({
|
|
|
917
965
|
});
|
|
918
966
|
|
|
919
967
|
// src/sealed-relay.ts
|
|
920
|
-
function
|
|
968
|
+
function textOf(err) {
|
|
969
|
+
return err instanceof Error ? err.message : String(err);
|
|
970
|
+
}
|
|
971
|
+
function sendBytes(port, bytes) {
|
|
972
|
+
const copy = fresh(bytes);
|
|
973
|
+
port.postMessage({ t: "chunk", bytes: copy }, [copy.buffer]);
|
|
974
|
+
}
|
|
975
|
+
function uploadOf(far) {
|
|
976
|
+
let waiting;
|
|
977
|
+
let failure2;
|
|
978
|
+
const next = () => {
|
|
979
|
+
if (failure2) return Promise.reject(failure2);
|
|
980
|
+
waiting = Promise.withResolvers();
|
|
981
|
+
far.postMessage({ t: "pull" });
|
|
982
|
+
return waiting.promise;
|
|
983
|
+
};
|
|
984
|
+
return {
|
|
985
|
+
stream: {
|
|
986
|
+
[Symbol.asyncIterator]: () => ({
|
|
987
|
+
next,
|
|
988
|
+
return: async () => {
|
|
989
|
+
far.postMessage({ t: "stop" });
|
|
990
|
+
return { value: void 0, done: true };
|
|
991
|
+
}
|
|
992
|
+
})
|
|
993
|
+
},
|
|
994
|
+
answer(message) {
|
|
995
|
+
if (message.t === "chunk") waiting?.resolve({ value: message.bytes, done: false });
|
|
996
|
+
else if (message.t === "end") waiting?.resolve({ value: void 0, done: true });
|
|
997
|
+
else {
|
|
998
|
+
failure2 = new Error(message.message);
|
|
999
|
+
waiting?.reject(failure2);
|
|
1000
|
+
}
|
|
1001
|
+
waiting = void 0;
|
|
1002
|
+
},
|
|
1003
|
+
fail(reason) {
|
|
1004
|
+
failure2 = reason;
|
|
1005
|
+
waiting?.reject(reason);
|
|
1006
|
+
waiting = void 0;
|
|
1007
|
+
}
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
function answerFetch(hook, { req, port: far }, live) {
|
|
1011
|
+
const control = new AbortController();
|
|
1012
|
+
const { streamed, ...fields } = req;
|
|
1013
|
+
const upload = uploadOf(far);
|
|
1014
|
+
let source;
|
|
1015
|
+
let reply;
|
|
1016
|
+
let closed = false;
|
|
1017
|
+
const settle = () => {
|
|
1018
|
+
closed = true;
|
|
1019
|
+
live.delete(answer);
|
|
1020
|
+
upload.fail(new Error("the request ended"));
|
|
1021
|
+
};
|
|
1022
|
+
const answer = {
|
|
1023
|
+
close(reason) {
|
|
1024
|
+
if (closed) return;
|
|
1025
|
+
settle();
|
|
1026
|
+
control.abort(reason);
|
|
1027
|
+
dropSealedReply(reply);
|
|
1028
|
+
far.close();
|
|
1029
|
+
}
|
|
1030
|
+
};
|
|
1031
|
+
const finish = (message) => {
|
|
1032
|
+
if (closed) return;
|
|
1033
|
+
settle();
|
|
1034
|
+
far.postMessage(message);
|
|
1035
|
+
};
|
|
1036
|
+
const failWith = (err) => {
|
|
1037
|
+
dropSealedReply(reply);
|
|
1038
|
+
finish({ t: "error", message: textOf(err) });
|
|
1039
|
+
};
|
|
1040
|
+
const read = async () => {
|
|
1041
|
+
try {
|
|
1042
|
+
const next = await source.next();
|
|
1043
|
+
if (closed) return;
|
|
1044
|
+
if (next.done) finish({ t: "end" });
|
|
1045
|
+
else if (next.value instanceof Uint8Array) sendBytes(far, next.value);
|
|
1046
|
+
else failWith("a body chunk is not bytes");
|
|
1047
|
+
} catch (err) {
|
|
1048
|
+
failWith(err);
|
|
1049
|
+
}
|
|
1050
|
+
};
|
|
1051
|
+
const ask = async () => {
|
|
1052
|
+
try {
|
|
1053
|
+
if (!hook) throw new Error("no vault is connected");
|
|
1054
|
+
const request = {
|
|
1055
|
+
...fields,
|
|
1056
|
+
...streamed ? { bodyStream: upload.stream } : {}
|
|
1057
|
+
};
|
|
1058
|
+
const answered = await hook(request, { signal: control.signal });
|
|
1059
|
+
if (!sealedReplyValid(answered)) {
|
|
1060
|
+
dropSealedReply(answered);
|
|
1061
|
+
throw new Error("the reply is not a scrubbed response");
|
|
1062
|
+
}
|
|
1063
|
+
if (closed) return dropSealedReply(answered);
|
|
1064
|
+
reply = answered;
|
|
1065
|
+
source = answered.body[Symbol.asyncIterator]();
|
|
1066
|
+
const { status, statusText, headers, url } = answered;
|
|
1067
|
+
far.postMessage({
|
|
1068
|
+
t: "head",
|
|
1069
|
+
status,
|
|
1070
|
+
statusText,
|
|
1071
|
+
headers,
|
|
1072
|
+
...url !== void 0 ? { url } : {}
|
|
1073
|
+
});
|
|
1074
|
+
} catch (err) {
|
|
1075
|
+
failWith(err);
|
|
1076
|
+
}
|
|
1077
|
+
};
|
|
1078
|
+
far.addEventListener("message", ({ data }) => {
|
|
1079
|
+
if (data.t === "read") void read();
|
|
1080
|
+
else if (data.t === "cancel") answer.close(data.reason);
|
|
1081
|
+
else upload.answer(data);
|
|
1082
|
+
});
|
|
1083
|
+
far.addEventListener("close", () => answer.close("withdrawn"));
|
|
1084
|
+
far.start();
|
|
1085
|
+
live.add(answer);
|
|
1086
|
+
void ask();
|
|
1087
|
+
}
|
|
1088
|
+
function sealedAnswerer(port, hook, fetchHook) {
|
|
921
1089
|
const asked = /* @__PURE__ */ new Map();
|
|
1090
|
+
const fetches = /* @__PURE__ */ new Set();
|
|
922
1091
|
const ask = async ({ id, req }) => {
|
|
923
1092
|
const control = new AbortController();
|
|
924
1093
|
asked.set(id, control);
|
|
@@ -942,36 +1111,18 @@ function sealedAnswerer(port, hook) {
|
|
|
942
1111
|
const message = data;
|
|
943
1112
|
if (message?.sealedAsk) void ask(message.sealedAsk);
|
|
944
1113
|
else if (message?.sealedAbort) abort(message.sealedAbort);
|
|
1114
|
+
else if (message?.sealedFetch) answerFetch(fetchHook, message.sealedFetch, fetches);
|
|
945
1115
|
else return false;
|
|
946
1116
|
return true;
|
|
947
1117
|
},
|
|
948
1118
|
close() {
|
|
949
1119
|
for (const control of asked.values()) control.abort("withdrawn");
|
|
950
1120
|
asked.clear();
|
|
1121
|
+
for (const answer of [...fetches]) answer.close("withdrawn");
|
|
951
1122
|
}
|
|
952
1123
|
};
|
|
953
1124
|
}
|
|
954
1125
|
|
|
955
|
-
// src/body-idle.ts
|
|
956
|
-
var BODY_IDLE_MS = 5 * 60 * 1e3;
|
|
957
|
-
function idleFailure(ms) {
|
|
958
|
-
return Object.assign(new Error(`the response body sent no data for ${ms} ms`), {
|
|
959
|
-
code: "ETIMEDOUT"
|
|
960
|
-
});
|
|
961
|
-
}
|
|
962
|
-
async function readWithin(reader, ms) {
|
|
963
|
-
if (!(ms > 0 && ms < Number.POSITIVE_INFINITY)) return reader.read();
|
|
964
|
-
let timer;
|
|
965
|
-
const idle = new Promise((_, reject) => {
|
|
966
|
-
timer = setTimeout(() => reject(idleFailure(ms)), ms);
|
|
967
|
-
});
|
|
968
|
-
try {
|
|
969
|
-
return await Promise.race([reader.read(), idle]);
|
|
970
|
-
} finally {
|
|
971
|
-
clearTimeout(timer);
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
|
|
975
1126
|
// src/kernel/net/ws-queue.ts
|
|
976
1127
|
var INBOUND_LIMIT = 16 * 1024 * 1024;
|
|
977
1128
|
var MESSAGE_LIMIT = 64 * 1024 * 1024;
|
|
@@ -1189,10 +1340,11 @@ function fetchTransport(options = {}) {
|
|
|
1189
1340
|
const send = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
1190
1341
|
const Socket = options.webSocket === true ? globalThis.WebSocket : options.webSocket || void 0;
|
|
1191
1342
|
const headers = options.webSocketHeaders === true;
|
|
1192
|
-
const
|
|
1343
|
+
const instance = options.redirect ?? "follow";
|
|
1193
1344
|
return {
|
|
1194
1345
|
traits: {
|
|
1195
|
-
manualRedirects:
|
|
1346
|
+
manualRedirects: instance === "manual",
|
|
1347
|
+
redirectPolicy: true,
|
|
1196
1348
|
encodedBodies: false,
|
|
1197
1349
|
maxRequestBody: options.maxRequestBody ?? MAX_REQUEST_BODY,
|
|
1198
1350
|
crossOrigin: "cors",
|
|
@@ -1208,7 +1360,7 @@ function fetchTransport(options = {}) {
|
|
|
1208
1360
|
headers: joinHeaders(request.headers),
|
|
1209
1361
|
...requestBody(request),
|
|
1210
1362
|
signal: request.signal,
|
|
1211
|
-
redirect,
|
|
1363
|
+
redirect: request.redirect ?? instance,
|
|
1212
1364
|
credentials: "omit",
|
|
1213
1365
|
mode: "cors"
|
|
1214
1366
|
});
|
|
@@ -1232,6 +1384,7 @@ function fetchTransport(options = {}) {
|
|
|
1232
1384
|
const body = chunks(response.body, options.bodyIdleMs ?? BODY_IDLE_MS);
|
|
1233
1385
|
return {
|
|
1234
1386
|
...response.redirected ? { url: response.url, redirected: true } : {},
|
|
1387
|
+
...response.type === "opaqueredirect" ? { opaqueRedirect: true } : {},
|
|
1235
1388
|
status: response.status,
|
|
1236
1389
|
statusText: response.statusText,
|
|
1237
1390
|
headers: headers2,
|
|
@@ -1267,7 +1420,34 @@ function uploadsFor(peer) {
|
|
|
1267
1420
|
});
|
|
1268
1421
|
return { of, answer: (call) => pulls.get(call.nid)?.(call) };
|
|
1269
1422
|
}
|
|
1270
|
-
function
|
|
1423
|
+
function headOf(nid, response) {
|
|
1424
|
+
return {
|
|
1425
|
+
net: "head",
|
|
1426
|
+
nid,
|
|
1427
|
+
...response.url !== void 0 ? { url: response.url } : {},
|
|
1428
|
+
...response.redirected !== void 0 ? { redirected: response.redirected } : {},
|
|
1429
|
+
...response.redirects ? { redirects: response.redirects } : {},
|
|
1430
|
+
...response.opaqueRedirect ? { opaqueRedirect: true } : {},
|
|
1431
|
+
status: response.status,
|
|
1432
|
+
statusText: response.statusText,
|
|
1433
|
+
headers: response.headers
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
function requestOf(call, signal, uploads) {
|
|
1437
|
+
const { url, method, headers, streamed, body, redirect, nid } = call;
|
|
1438
|
+
return {
|
|
1439
|
+
url,
|
|
1440
|
+
method,
|
|
1441
|
+
headers,
|
|
1442
|
+
...streamed ? { bodyStream: uploads.of(nid, signal) } : body ? { body } : {},
|
|
1443
|
+
...redirect !== void 0 ? { redirect } : {},
|
|
1444
|
+
signal
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1447
|
+
function serveTransport(peer, transport, {
|
|
1448
|
+
closeWaitMs = CLOSE_WAIT_MS,
|
|
1449
|
+
attributed = false
|
|
1450
|
+
} = {}) {
|
|
1271
1451
|
const open = /* @__PURE__ */ new Map();
|
|
1272
1452
|
const fail = (nid, e) => {
|
|
1273
1453
|
open.delete(nid);
|
|
@@ -1287,27 +1467,17 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS } = {}) {
|
|
|
1287
1467
|
const entry = { abort };
|
|
1288
1468
|
open.set(call.nid, entry);
|
|
1289
1469
|
try {
|
|
1290
|
-
const response = await transport.fetch(
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
signal: abort.signal
|
|
1296
|
-
});
|
|
1470
|
+
const response = await transport.fetch(
|
|
1471
|
+
requestOf(call, abort.signal, uploads),
|
|
1472
|
+
attributed ? call.owner : void 0,
|
|
1473
|
+
attributed ? call.stamp : void 0
|
|
1474
|
+
);
|
|
1297
1475
|
if (!open.has(call.nid)) {
|
|
1298
1476
|
await response.cancel();
|
|
1299
1477
|
return;
|
|
1300
1478
|
}
|
|
1301
1479
|
open.set(call.nid, { abort, body: response.body[Symbol.asyncIterator](), response });
|
|
1302
|
-
peer.postMessage(
|
|
1303
|
-
net: "head",
|
|
1304
|
-
nid: call.nid,
|
|
1305
|
-
...response.redirected ? { url: response.url, redirected: true } : {},
|
|
1306
|
-
...response.redirects ? { redirects: response.redirects } : {},
|
|
1307
|
-
status: response.status,
|
|
1308
|
-
statusText: response.statusText,
|
|
1309
|
-
headers: response.headers
|
|
1310
|
-
});
|
|
1480
|
+
peer.postMessage(headOf(call.nid, response));
|
|
1311
1481
|
} catch (e) {
|
|
1312
1482
|
fail(call.nid, e);
|
|
1313
1483
|
}
|
|
@@ -1461,6 +1631,18 @@ var TransportError = class extends Error {
|
|
|
1461
1631
|
this.detail = detail === "transport" ? detail : void 0;
|
|
1462
1632
|
}
|
|
1463
1633
|
};
|
|
1634
|
+
function unfollowed(redirect) {
|
|
1635
|
+
return redirect !== void 0 && redirect !== "follow";
|
|
1636
|
+
}
|
|
1637
|
+
function honors(traits, redirect) {
|
|
1638
|
+
if (traits.redirectPolicy === true) return true;
|
|
1639
|
+
const hops = traits.redirectHops;
|
|
1640
|
+
const raw = traits.manualRedirects === true && (hops === void 0 || hops === false);
|
|
1641
|
+
return redirect === "manual" && raw;
|
|
1642
|
+
}
|
|
1643
|
+
function refused(message) {
|
|
1644
|
+
return new TransportError(message, 502, void 0, "transport");
|
|
1645
|
+
}
|
|
1464
1646
|
var RemoteTransport = class {
|
|
1465
1647
|
traits;
|
|
1466
1648
|
port;
|
|
@@ -1544,10 +1726,13 @@ var RemoteTransport = class {
|
|
|
1544
1726
|
waiter?.reject(new TransportError("the request was cancelled"));
|
|
1545
1727
|
this.port.postMessage({ net: "cancel", nid });
|
|
1546
1728
|
}
|
|
1547
|
-
async fetch(request) {
|
|
1729
|
+
async fetch(request, owner, stamp) {
|
|
1548
1730
|
const nid = ++this.nextId;
|
|
1549
|
-
const { signal } = request;
|
|
1731
|
+
const { signal, redirect } = request;
|
|
1550
1732
|
signal.throwIfAborted();
|
|
1733
|
+
if (unfollowed(redirect) && !honors(this.traits, redirect)) {
|
|
1734
|
+
throw refused(`this transport cannot honor redirect: ${redirect}`);
|
|
1735
|
+
}
|
|
1551
1736
|
let finished = false;
|
|
1552
1737
|
const abort = () => {
|
|
1553
1738
|
finished = true;
|
|
@@ -1570,13 +1755,16 @@ var RemoteTransport = class {
|
|
|
1570
1755
|
url: request.url,
|
|
1571
1756
|
method: request.method,
|
|
1572
1757
|
headers: request.headers,
|
|
1573
|
-
...request.bodyStream ? { streamed: true } : request.body ? { body: request.body } : {}
|
|
1758
|
+
...request.bodyStream ? { streamed: true } : request.body ? { body: request.body } : {},
|
|
1759
|
+
...redirect !== void 0 ? { redirect } : {},
|
|
1760
|
+
...owner !== void 0 ? { owner } : {},
|
|
1761
|
+
...stamp ? { stamp } : {}
|
|
1574
1762
|
});
|
|
1575
1763
|
} catch (e) {
|
|
1576
1764
|
finish();
|
|
1577
1765
|
throw e;
|
|
1578
1766
|
}
|
|
1579
|
-
const { status, statusText, headers, url, redirected, redirects } = head;
|
|
1767
|
+
const { status, statusText, headers, url, redirected, redirects, opaqueRedirect } = head;
|
|
1580
1768
|
const read = async () => {
|
|
1581
1769
|
if (finished) return void 0;
|
|
1582
1770
|
const reply = await this.ask({ net: "read", nid }).catch((e) => {
|
|
@@ -1592,9 +1780,15 @@ var RemoteTransport = class {
|
|
|
1592
1780
|
finish();
|
|
1593
1781
|
this.cancel(nid);
|
|
1594
1782
|
};
|
|
1783
|
+
if (unfollowed(redirect) && (redirected || redirects?.length)) {
|
|
1784
|
+
await cancel();
|
|
1785
|
+
throw refused(`this transport followed a redirect despite redirect: ${redirect}`);
|
|
1786
|
+
}
|
|
1595
1787
|
return {
|
|
1596
|
-
...
|
|
1788
|
+
...url !== void 0 ? { url } : {},
|
|
1789
|
+
...redirected !== void 0 ? { redirected } : {},
|
|
1597
1790
|
...redirects ? { redirects } : {},
|
|
1791
|
+
...opaqueRedirect ? { opaqueRedirect } : {},
|
|
1598
1792
|
status,
|
|
1599
1793
|
statusText,
|
|
1600
1794
|
headers,
|
|
@@ -2054,9 +2248,9 @@ async function greet(channel, lock, timeoutMs, requests) {
|
|
|
2054
2248
|
} finally {
|
|
2055
2249
|
clearTimeout(timer);
|
|
2056
2250
|
}
|
|
2057
|
-
const
|
|
2058
|
-
if (
|
|
2059
|
-
const error = new Error(
|
|
2251
|
+
const refused2 = hello.error ?? versionError(hello.protocol);
|
|
2252
|
+
if (refused2) {
|
|
2253
|
+
const error = new Error(refused2);
|
|
2060
2254
|
channel.end(error);
|
|
2061
2255
|
throw error;
|
|
2062
2256
|
}
|
|
@@ -2249,6 +2443,7 @@ function uplinkInit(uplink) {
|
|
|
2249
2443
|
return { uplink: { traits, ...uplink.routes ? { routes: uplink.routes } : {}, ...nameserver } };
|
|
2250
2444
|
}
|
|
2251
2445
|
function initCall(options, transport) {
|
|
2446
|
+
const hooks = sealedHooks(options.sealed);
|
|
2252
2447
|
return {
|
|
2253
2448
|
op: "init",
|
|
2254
2449
|
...options.root ? { root: options.root } : {},
|
|
@@ -2267,7 +2462,8 @@ function initCall(options, transport) {
|
|
|
2267
2462
|
...options.hostname !== void 0 ? { hostname: options.hostname } : {},
|
|
2268
2463
|
users: options.users === void 0 ? DEFAULT_USERS : options.users,
|
|
2269
2464
|
...options.onDenial ? { denials: true } : {},
|
|
2270
|
-
...
|
|
2465
|
+
...hooks.request ? { sealed: true } : {},
|
|
2466
|
+
...hooks.fetch ? { sealedFetch: true } : {},
|
|
2271
2467
|
...options.clipboard ? { clipboard: true } : {},
|
|
2272
2468
|
...options.requests ? { requests: kindsOf(options.requests) } : {},
|
|
2273
2469
|
...options.approve ? { approve: true } : {},
|
|
@@ -2428,6 +2624,7 @@ function checkOptions(options) {
|
|
|
2428
2624
|
if (options.protect) protectInit(options.protect);
|
|
2429
2625
|
integrityOptions(options.protect?.integrity);
|
|
2430
2626
|
facadesInit(options.facades);
|
|
2627
|
+
sealedHooks(options.sealed);
|
|
2431
2628
|
}
|
|
2432
2629
|
function connector(call, bound) {
|
|
2433
2630
|
return async (connectOptions = {}) => {
|
|
@@ -2444,7 +2641,8 @@ function connector(call, bound) {
|
|
|
2444
2641
|
};
|
|
2445
2642
|
}
|
|
2446
2643
|
function hookRelays(worker, options, bound) {
|
|
2447
|
-
const
|
|
2644
|
+
const hooks = sealedHooks(options.sealed);
|
|
2645
|
+
const sealed = sealedAnswerer(worker, hooks.request, hooks.fetch);
|
|
2448
2646
|
const clipboard = clipboardAnswerer(worker, options.clipboard);
|
|
2449
2647
|
const integrity = integrityAnswerer(worker, options.protect?.integrity?.lookup);
|
|
2450
2648
|
const requests = embedderAnswerer(
|
|
@@ -2479,6 +2677,17 @@ function traitsUpdater(transport, call) {
|
|
|
2479
2677
|
return await call({ op: "transport-traits", ...traits }) === true;
|
|
2480
2678
|
};
|
|
2481
2679
|
}
|
|
2680
|
+
function transportBridge(worker, transport) {
|
|
2681
|
+
return transport ? serveTransport(worker, transport, { attributed: true }) : void 0;
|
|
2682
|
+
}
|
|
2683
|
+
function pageOnly(call) {
|
|
2684
|
+
return {
|
|
2685
|
+
sealed: {
|
|
2686
|
+
setPlaceholders: async (list) => void await call({ op: "sealed-placeholders", list })
|
|
2687
|
+
},
|
|
2688
|
+
attest: ((path, options) => call({ op: "attest", path, ...options ? { options } : {} }))
|
|
2689
|
+
};
|
|
2690
|
+
}
|
|
2482
2691
|
async function createKernel(options = {}) {
|
|
2483
2692
|
checkOptions(options);
|
|
2484
2693
|
const url = options.worker ?? new URL("./kernel-worker.js", import.meta.url);
|
|
@@ -2509,7 +2718,7 @@ async function createKernel(options = {}) {
|
|
|
2509
2718
|
pending.clear();
|
|
2510
2719
|
};
|
|
2511
2720
|
const transport = options.network?.transport;
|
|
2512
|
-
const bridge =
|
|
2721
|
+
const bridge = transportBridge(worker, transport);
|
|
2513
2722
|
const uplinks = uplinkServer(worker, options.network?.uplink);
|
|
2514
2723
|
async function chosen(handle) {
|
|
2515
2724
|
if (handle) {
|
|
@@ -2633,7 +2842,7 @@ async function createKernel(options = {}) {
|
|
|
2633
2842
|
umount: async (target) => void await call({ op: "umount", target }),
|
|
2634
2843
|
mounts: async () => await call({ op: "mounts" }),
|
|
2635
2844
|
insert: async (target, handle) => void await call({ op: "insert", target, handle }),
|
|
2636
|
-
|
|
2845
|
+
...pageOnly(call),
|
|
2637
2846
|
watch: files.watch,
|
|
2638
2847
|
terminate() {
|
|
2639
2848
|
fail(new Error("slicc-kernel terminated"));
|
|
@@ -2644,6 +2853,7 @@ async function createKernel(options = {}) {
|
|
|
2644
2853
|
export {
|
|
2645
2854
|
KernelCallError,
|
|
2646
2855
|
KernelGoneError,
|
|
2856
|
+
SEALED_FETCH_VERSION,
|
|
2647
2857
|
attachKernel,
|
|
2648
2858
|
createKernel,
|
|
2649
2859
|
fetchTransport,
|