@ai-ecoverse/slicc-kernel 1.37.1 → 1.39.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 +3 -1
- package/dist/driver-worker.js +123 -0
- package/dist/driver-worker.js.map +3 -3
- package/dist/index.js +309 -6
- package/dist/index.js.map +4 -4
- package/dist/kernel-worker.js +647 -214
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-driver-worker.js +123 -0
- package/dist/node-driver-worker.js.map +3 -3
- package/dist/node-process-worker.js +370 -99
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +578 -66
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +370 -99
- package/dist/process-worker.js.map +4 -4
- package/package.json +1 -1
package/dist/node.js
CHANGED
|
@@ -1190,7 +1190,153 @@ async function readWithin(reader, ms) {
|
|
|
1190
1190
|
}
|
|
1191
1191
|
}
|
|
1192
1192
|
|
|
1193
|
+
// src/kernel/net/ws-queue.ts
|
|
1194
|
+
var INBOUND_LIMIT = 16 * 1024 * 1024;
|
|
1195
|
+
var MESSAGE_LIMIT = 64 * 1024 * 1024;
|
|
1196
|
+
var TOO_BIG = 1009;
|
|
1197
|
+
function payloadSize(message2) {
|
|
1198
|
+
return typeof message2 === "string" ? new TextEncoder().encode(message2).length : message2.length;
|
|
1199
|
+
}
|
|
1200
|
+
var MessageQueue = class {
|
|
1201
|
+
items = [];
|
|
1202
|
+
limit;
|
|
1203
|
+
waiter;
|
|
1204
|
+
size = 0;
|
|
1205
|
+
ended = false;
|
|
1206
|
+
overflow;
|
|
1207
|
+
taken;
|
|
1208
|
+
closed;
|
|
1209
|
+
settle;
|
|
1210
|
+
constructor(overflow, limit = INBOUND_LIMIT, taken) {
|
|
1211
|
+
this.overflow = overflow;
|
|
1212
|
+
this.limit = limit;
|
|
1213
|
+
this.taken = taken;
|
|
1214
|
+
this.closed = new Promise((resolve) => {
|
|
1215
|
+
this.settle = resolve;
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
push(message2) {
|
|
1219
|
+
if (this.ended) return;
|
|
1220
|
+
const size = payloadSize(message2);
|
|
1221
|
+
const huge = size > MESSAGE_LIMIT;
|
|
1222
|
+
if (huge || this.items.length > 0 && this.size + size > this.limit) {
|
|
1223
|
+
const reason = huge ? `a message is over ${MESSAGE_LIMIT} bytes` : `over ${this.limit} bytes of messages are waiting`;
|
|
1224
|
+
this.end({ code: TOO_BIG, reason });
|
|
1225
|
+
this.overflow();
|
|
1226
|
+
return;
|
|
1227
|
+
}
|
|
1228
|
+
this.size += size;
|
|
1229
|
+
this.items.push(message2);
|
|
1230
|
+
this.wake();
|
|
1231
|
+
}
|
|
1232
|
+
end(close) {
|
|
1233
|
+
if (this.ended) return;
|
|
1234
|
+
this.ended = true;
|
|
1235
|
+
this.settle(close);
|
|
1236
|
+
this.wake();
|
|
1237
|
+
}
|
|
1238
|
+
wake() {
|
|
1239
|
+
const waiter = this.waiter;
|
|
1240
|
+
this.waiter = void 0;
|
|
1241
|
+
waiter?.();
|
|
1242
|
+
}
|
|
1243
|
+
async *[Symbol.asyncIterator]() {
|
|
1244
|
+
for (; ; ) {
|
|
1245
|
+
const next = this.items.shift();
|
|
1246
|
+
if (next !== void 0) {
|
|
1247
|
+
const n = payloadSize(next);
|
|
1248
|
+
this.size -= n;
|
|
1249
|
+
this.taken?.(n);
|
|
1250
|
+
yield next;
|
|
1251
|
+
continue;
|
|
1252
|
+
}
|
|
1253
|
+
if (this.ended) return;
|
|
1254
|
+
await new Promise((resolve) => {
|
|
1255
|
+
this.waiter = resolve;
|
|
1256
|
+
});
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
};
|
|
1260
|
+
|
|
1261
|
+
// src/websocket-transport.ts
|
|
1262
|
+
var SENT_HEADERS_DROP = /* @__PURE__ */ new Set([
|
|
1263
|
+
"host",
|
|
1264
|
+
"connection",
|
|
1265
|
+
"upgrade",
|
|
1266
|
+
"sec-websocket-key",
|
|
1267
|
+
"sec-websocket-version",
|
|
1268
|
+
"sec-websocket-extensions",
|
|
1269
|
+
"sec-websocket-protocol"
|
|
1270
|
+
]);
|
|
1271
|
+
function headerRecord(headers) {
|
|
1272
|
+
const out = {};
|
|
1273
|
+
for (const [name2, value] of headers) {
|
|
1274
|
+
if (!SENT_HEADERS_DROP.has(name2.toLowerCase())) out[name2] = value;
|
|
1275
|
+
}
|
|
1276
|
+
return out;
|
|
1277
|
+
}
|
|
1278
|
+
function sendableClose(code) {
|
|
1279
|
+
return code === 1e3 || code !== void 0 && code >= 3e3 && code <= 4999 ? code : 1e3;
|
|
1280
|
+
}
|
|
1281
|
+
function blockedReason(url, e) {
|
|
1282
|
+
const name2 = e?.name;
|
|
1283
|
+
if (name2 === "SecurityError" && url.startsWith("ws:")) {
|
|
1284
|
+
return `${url}: ws:// is blocked from an https page; use wss:// or slicc-node`;
|
|
1285
|
+
}
|
|
1286
|
+
return `${url}: ${e instanceof Error ? e.message : String(e)}`;
|
|
1287
|
+
}
|
|
1288
|
+
function openWebSocket(Socket, request, withHeaders) {
|
|
1289
|
+
const { url, protocols, signal } = request;
|
|
1290
|
+
signal.throwIfAborted();
|
|
1291
|
+
let socket;
|
|
1292
|
+
try {
|
|
1293
|
+
socket = withHeaders ? new Socket(url, { protocols, headers: headerRecord(request.headers) }) : new Socket(url, protocols);
|
|
1294
|
+
} catch (e) {
|
|
1295
|
+
return Promise.reject(Object.assign(new Error(blockedReason(url, e)), { status: 502 }));
|
|
1296
|
+
}
|
|
1297
|
+
socket.binaryType = "arraybuffer";
|
|
1298
|
+
const queue = new MessageQueue(() => socket.close(1e3, "too many waiting messages"));
|
|
1299
|
+
return new Promise((resolve, reject) => {
|
|
1300
|
+
let open = false;
|
|
1301
|
+
const abort = () => {
|
|
1302
|
+
socket.close(1e3, "aborted");
|
|
1303
|
+
reject(signal.reason);
|
|
1304
|
+
};
|
|
1305
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
1306
|
+
socket.addEventListener("open", () => {
|
|
1307
|
+
open = true;
|
|
1308
|
+
signal.removeEventListener("abort", abort);
|
|
1309
|
+
resolve({
|
|
1310
|
+
protocol: socket.protocol,
|
|
1311
|
+
get buffered() {
|
|
1312
|
+
return socket.bufferedAmount;
|
|
1313
|
+
},
|
|
1314
|
+
send: (data) => socket.send(data),
|
|
1315
|
+
messages: queue,
|
|
1316
|
+
close: (code, reason) => socket.close(sendableClose(code), reason),
|
|
1317
|
+
closed: queue.closed
|
|
1318
|
+
});
|
|
1319
|
+
});
|
|
1320
|
+
socket.addEventListener("message", (event) => {
|
|
1321
|
+
queue.push(typeof event.data === "string" ? event.data : new Uint8Array(event.data));
|
|
1322
|
+
});
|
|
1323
|
+
socket.addEventListener("close", (event) => {
|
|
1324
|
+
queue.end({ code: event.code, reason: event.reason });
|
|
1325
|
+
if (open) return;
|
|
1326
|
+
signal.removeEventListener("abort", abort);
|
|
1327
|
+
reject(
|
|
1328
|
+
Object.assign(new Error(`${url}: the WebSocket closed (${event.code}) before it opened`), {
|
|
1329
|
+
status: 502
|
|
1330
|
+
})
|
|
1331
|
+
);
|
|
1332
|
+
});
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1193
1336
|
// src/transport.ts
|
|
1337
|
+
var SEND_BUFFER = 1024 * 1024;
|
|
1338
|
+
var CLOSE_WAIT_MS = 5e3;
|
|
1339
|
+
var NO_WEBSOCKET = "WebSocket not supported by this transport (fetchTransport needs { webSocket: true })";
|
|
1194
1340
|
var MAX_REQUEST_BODY = 64 * 1024 * 1024;
|
|
1195
1341
|
function joinHeaders(headers) {
|
|
1196
1342
|
const out = new Headers();
|
|
@@ -1215,13 +1361,17 @@ async function* chunks(body, idleMs) {
|
|
|
1215
1361
|
}
|
|
1216
1362
|
function fetchTransport(options = {}) {
|
|
1217
1363
|
const send = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
1364
|
+
const Socket = options.webSocket === true ? globalThis.WebSocket : options.webSocket || void 0;
|
|
1365
|
+
const headers = options.webSocketHeaders === true;
|
|
1218
1366
|
return {
|
|
1219
1367
|
traits: {
|
|
1220
1368
|
manualRedirects: false,
|
|
1221
1369
|
encodedBodies: false,
|
|
1222
1370
|
maxRequestBody: options.maxRequestBody ?? MAX_REQUEST_BODY,
|
|
1223
|
-
crossOrigin: "cors"
|
|
1371
|
+
crossOrigin: "cors",
|
|
1372
|
+
...Socket ? { websocket: true } : {}
|
|
1224
1373
|
},
|
|
1374
|
+
...Socket ? { websocket: (request) => openWebSocket(Socket, request, headers) } : {},
|
|
1225
1375
|
async fetch(request) {
|
|
1226
1376
|
let response;
|
|
1227
1377
|
try {
|
|
@@ -1243,15 +1393,15 @@ function fetchTransport(options = {}) {
|
|
|
1243
1393
|
{ status: 502 }
|
|
1244
1394
|
);
|
|
1245
1395
|
}
|
|
1246
|
-
const
|
|
1396
|
+
const headers2 = [];
|
|
1247
1397
|
response.headers.forEach((value, name2) => {
|
|
1248
|
-
|
|
1398
|
+
headers2.push([name2, value]);
|
|
1249
1399
|
});
|
|
1250
1400
|
const body = chunks(response.body, options.bodyIdleMs ?? BODY_IDLE_MS);
|
|
1251
1401
|
return {
|
|
1252
1402
|
status: response.status,
|
|
1253
1403
|
statusText: response.statusText,
|
|
1254
|
-
headers,
|
|
1404
|
+
headers: headers2,
|
|
1255
1405
|
body,
|
|
1256
1406
|
cancel: async () => {
|
|
1257
1407
|
await body.return(void 0);
|
|
@@ -1261,7 +1411,7 @@ function fetchTransport(options = {}) {
|
|
|
1261
1411
|
}
|
|
1262
1412
|
};
|
|
1263
1413
|
}
|
|
1264
|
-
function serveTransport(peer, transport) {
|
|
1414
|
+
function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS } = {}) {
|
|
1265
1415
|
const open = /* @__PURE__ */ new Map();
|
|
1266
1416
|
const fail2 = (nid, e) => {
|
|
1267
1417
|
open.delete(nid);
|
|
@@ -1302,6 +1452,96 @@ function serveTransport(peer, transport) {
|
|
|
1302
1452
|
fail2(call.nid, e);
|
|
1303
1453
|
}
|
|
1304
1454
|
};
|
|
1455
|
+
const sockets = /* @__PURE__ */ new Map();
|
|
1456
|
+
const credit = /* @__PURE__ */ new Map();
|
|
1457
|
+
const refill = (nid, n, closing = false) => {
|
|
1458
|
+
const flow = credit.get(nid);
|
|
1459
|
+
if (!flow) return;
|
|
1460
|
+
flow.inflight -= n;
|
|
1461
|
+
if (closing && !flow.closing) {
|
|
1462
|
+
flow.closing = true;
|
|
1463
|
+
flow.deadline();
|
|
1464
|
+
}
|
|
1465
|
+
flow.wake?.();
|
|
1466
|
+
};
|
|
1467
|
+
const openSocket = async (call) => {
|
|
1468
|
+
const abort = new AbortController();
|
|
1469
|
+
open.set(call.nid, { abort });
|
|
1470
|
+
try {
|
|
1471
|
+
if (!transport.websocket) throw new Error(NO_WEBSOCKET);
|
|
1472
|
+
const socket = await transport.websocket({
|
|
1473
|
+
url: call.url,
|
|
1474
|
+
protocols: call.protocols,
|
|
1475
|
+
headers: call.headers,
|
|
1476
|
+
signal: abort.signal
|
|
1477
|
+
});
|
|
1478
|
+
if (!open.delete(call.nid)) {
|
|
1479
|
+
socket.close(1e3, "cancelled");
|
|
1480
|
+
return;
|
|
1481
|
+
}
|
|
1482
|
+
sockets.set(call.nid, socket);
|
|
1483
|
+
peer.postMessage({ net: "ws-opened", nid: call.nid, protocol: socket.protocol });
|
|
1484
|
+
void relay(call.nid, socket);
|
|
1485
|
+
} catch (e) {
|
|
1486
|
+
fail2(call.nid, e);
|
|
1487
|
+
}
|
|
1488
|
+
};
|
|
1489
|
+
const relay = async (nid, socket) => {
|
|
1490
|
+
let ending;
|
|
1491
|
+
let late;
|
|
1492
|
+
const unanswered = new Promise((resolve) => {
|
|
1493
|
+
late = () => resolve("late");
|
|
1494
|
+
});
|
|
1495
|
+
const flow = {
|
|
1496
|
+
inflight: 0,
|
|
1497
|
+
closing: false,
|
|
1498
|
+
deadline: () => AbortSignal.timeout(closeWaitMs).addEventListener("abort", late, { once: true })
|
|
1499
|
+
};
|
|
1500
|
+
credit.set(nid, flow);
|
|
1501
|
+
const timedOut = { code: 1006, reason: "the far end did not answer the close" };
|
|
1502
|
+
let oversize = false;
|
|
1503
|
+
try {
|
|
1504
|
+
const messages = socket.messages[Symbol.asyncIterator]();
|
|
1505
|
+
for (; ; ) {
|
|
1506
|
+
const next = await Promise.race([messages.next(), unanswered]);
|
|
1507
|
+
if (next === "late" || next.done) break;
|
|
1508
|
+
const data = next.value;
|
|
1509
|
+
if (flow.closing) continue;
|
|
1510
|
+
if (payloadSize(data) > MESSAGE_LIMIT) {
|
|
1511
|
+
oversize = true;
|
|
1512
|
+
break;
|
|
1513
|
+
}
|
|
1514
|
+
if (typeof data === "string") peer.postMessage({ net: "ws-message", nid, data });
|
|
1515
|
+
else {
|
|
1516
|
+
const bytes = data.slice();
|
|
1517
|
+
peer.postMessage({ net: "ws-message", nid, data: bytes }, [bytes.buffer]);
|
|
1518
|
+
}
|
|
1519
|
+
flow.inflight += payloadSize(data);
|
|
1520
|
+
while (flow.inflight > INBOUND_LIMIT && !flow.closing) {
|
|
1521
|
+
await new Promise((resolve) => {
|
|
1522
|
+
flow.wake = resolve;
|
|
1523
|
+
});
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
if (oversize) socket.close(1e3, "a message is too big");
|
|
1527
|
+
ending = oversize ? { code: 1009, reason: `a message is over ${MESSAGE_LIMIT} bytes` } : await Promise.race([socket.closed, unanswered.then(() => timedOut)]);
|
|
1528
|
+
} catch (e) {
|
|
1529
|
+
socket.close(1e3, "the relay failed");
|
|
1530
|
+
ending = { code: 1011, reason: e instanceof Error ? e.message : String(e) };
|
|
1531
|
+
}
|
|
1532
|
+
sockets.delete(nid);
|
|
1533
|
+
credit.delete(nid);
|
|
1534
|
+
peer.postMessage({ net: "ws-closed", nid, ...ending });
|
|
1535
|
+
};
|
|
1536
|
+
const sendOn = async (call) => {
|
|
1537
|
+
const socket = sockets.get(call.nid);
|
|
1538
|
+
if (!socket) return;
|
|
1539
|
+
socket.send(call.data);
|
|
1540
|
+
while (socket.buffered > SEND_BUFFER && sockets.has(call.nid)) {
|
|
1541
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
1542
|
+
}
|
|
1543
|
+
peer.postMessage({ net: "ws-acked", nid: call.nid, n: payloadSize(call.data) });
|
|
1544
|
+
};
|
|
1305
1545
|
const read = async (nid) => {
|
|
1306
1546
|
const body = open.get(nid)?.body;
|
|
1307
1547
|
if (!body) return;
|
|
@@ -1319,6 +1559,8 @@ function serveTransport(peer, transport) {
|
|
|
1319
1559
|
}
|
|
1320
1560
|
};
|
|
1321
1561
|
const drop = (nid) => {
|
|
1562
|
+
sockets.get(nid)?.close(1e3, "cancelled");
|
|
1563
|
+
refill(nid, 0, true);
|
|
1322
1564
|
const entry = open.get(nid);
|
|
1323
1565
|
open.delete(nid);
|
|
1324
1566
|
entry?.abort.abort();
|
|
@@ -1328,10 +1570,16 @@ function serveTransport(peer, transport) {
|
|
|
1328
1570
|
answer(call) {
|
|
1329
1571
|
if (call.net === "fetch") void start(call);
|
|
1330
1572
|
else if (call.net === "read") void read(call.nid);
|
|
1573
|
+
else if (call.net === "ws-open") void openSocket(call);
|
|
1574
|
+
else if (call.net === "ws-send") void sendOn(call);
|
|
1575
|
+
else if (call.net === "ws-close") {
|
|
1576
|
+
sockets.get(call.nid)?.close(call.code, call.reason);
|
|
1577
|
+
refill(call.nid, 0, true);
|
|
1578
|
+
} else if (call.net === "ws-consumed") refill(call.nid, call.n);
|
|
1331
1579
|
else drop(call.nid);
|
|
1332
1580
|
},
|
|
1333
1581
|
close() {
|
|
1334
|
-
for (const nid of [...open.keys()]) drop(nid);
|
|
1582
|
+
for (const nid of [...open.keys(), ...sockets.keys()]) drop(nid);
|
|
1335
1583
|
}
|
|
1336
1584
|
};
|
|
1337
1585
|
}
|
|
@@ -2417,6 +2665,10 @@ var Incoming = class {
|
|
|
2417
2665
|
this.buf = this.buf.subarray(n);
|
|
2418
2666
|
return out;
|
|
2419
2667
|
}
|
|
2668
|
+
async peek(signal) {
|
|
2669
|
+
if (this.buf.length === 0) await this.fill(signal);
|
|
2670
|
+
return this.buf[0];
|
|
2671
|
+
}
|
|
2420
2672
|
async some(max, signal) {
|
|
2421
2673
|
if (this.buf.length > 0) return this.take(Math.min(max, this.buf.length));
|
|
2422
2674
|
if (this.eof) return new Uint8Array(0);
|
|
@@ -2614,7 +2866,15 @@ var CLOSE = {
|
|
|
2614
2866
|
error: 1011
|
|
2615
2867
|
};
|
|
2616
2868
|
var OP_TEXT = 1;
|
|
2617
|
-
var
|
|
2869
|
+
var OP_BINARY = 2;
|
|
2870
|
+
var OP = {
|
|
2871
|
+
continuation: 0,
|
|
2872
|
+
text: OP_TEXT,
|
|
2873
|
+
binary: OP_BINARY,
|
|
2874
|
+
close: 8,
|
|
2875
|
+
ping: 9,
|
|
2876
|
+
pong: 10
|
|
2877
|
+
};
|
|
2618
2878
|
var WsError = class extends Error {
|
|
2619
2879
|
code;
|
|
2620
2880
|
constructor(code, message2) {
|
|
@@ -2622,6 +2882,10 @@ var WsError = class extends Error {
|
|
|
2622
2882
|
this.code = code;
|
|
2623
2883
|
}
|
|
2624
2884
|
};
|
|
2885
|
+
function sendableCode(code) {
|
|
2886
|
+
if (code >= 3e3 && code <= 4999) return true;
|
|
2887
|
+
return code >= 1e3 && code <= 1014 && code !== 1004 && code !== 1005 && code !== 1006;
|
|
2888
|
+
}
|
|
2625
2889
|
function field(headers, name2) {
|
|
2626
2890
|
return headers.find(([n]) => n.toLowerCase() === name2)?.[1];
|
|
2627
2891
|
}
|
|
@@ -2660,7 +2924,11 @@ function frame(opcode, payload) {
|
|
|
2660
2924
|
}
|
|
2661
2925
|
function closeFrame(code, reason = "") {
|
|
2662
2926
|
let bytes = new TextEncoder().encode(reason);
|
|
2663
|
-
if (bytes.length > 123)
|
|
2927
|
+
if (bytes.length > 123) {
|
|
2928
|
+
let end = 123;
|
|
2929
|
+
while ((bytes[end] & 192) === 128) end--;
|
|
2930
|
+
bytes = bytes.subarray(0, end);
|
|
2931
|
+
}
|
|
2664
2932
|
const payload = new Uint8Array(2 + bytes.length);
|
|
2665
2933
|
new DataView(payload.buffer).setUint16(0, code);
|
|
2666
2934
|
payload.set(bytes, 2);
|
|
@@ -2691,9 +2959,12 @@ var WsReader = class {
|
|
|
2691
2959
|
parts = [];
|
|
2692
2960
|
size = 0;
|
|
2693
2961
|
continuing = false;
|
|
2694
|
-
|
|
2962
|
+
binaryMessage = false;
|
|
2963
|
+
binary;
|
|
2964
|
+
constructor(incoming, max = MAX_MESSAGE, binary) {
|
|
2695
2965
|
this.incoming = incoming;
|
|
2696
2966
|
this.max = max;
|
|
2967
|
+
this.binary = binary;
|
|
2697
2968
|
}
|
|
2698
2969
|
async next(signal) {
|
|
2699
2970
|
for (; ; ) {
|
|
@@ -2723,6 +2994,20 @@ var WsReader = class {
|
|
|
2723
2994
|
if (event) return event;
|
|
2724
2995
|
}
|
|
2725
2996
|
}
|
|
2997
|
+
data(opcode, fin, payload) {
|
|
2998
|
+
if (opcode === OP.continuation !== this.continuing) {
|
|
2999
|
+
throw new WsError(CLOSE.protocol, "unexpected continuation frame");
|
|
3000
|
+
}
|
|
3001
|
+
if (opcode !== OP.continuation) this.binaryMessage = opcode === OP.binary;
|
|
3002
|
+
this.parts.push(payload);
|
|
3003
|
+
this.size += payload.length;
|
|
3004
|
+
this.continuing = !fin;
|
|
3005
|
+
if (!fin) return void 0;
|
|
3006
|
+
const whole = this.parts.length === 1 ? payload : concat(this.parts, this.size);
|
|
3007
|
+
this.parts = [];
|
|
3008
|
+
this.size = 0;
|
|
3009
|
+
return this.binaryMessage ? { kind: "binary", bytes: whole } : { kind: "text", text: decode(whole) };
|
|
3010
|
+
}
|
|
2726
3011
|
async length(short, signal) {
|
|
2727
3012
|
if (short < 126) return short;
|
|
2728
3013
|
const ext = new Uint8Array(short === 126 ? 2 : 8);
|
|
@@ -2741,36 +3026,31 @@ var WsReader = class {
|
|
|
2741
3026
|
case OP.close: {
|
|
2742
3027
|
if (payload.length === 1) throw new WsError(CLOSE.protocol, "a close frame is malformed");
|
|
2743
3028
|
const code = payload.length >= 2 ? new DataView(payload.buffer).getUint16(0) : 1005;
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
case OP.text:
|
|
2747
|
-
case OP.continuation: {
|
|
2748
|
-
if (opcode === OP.continuation !== this.continuing) {
|
|
2749
|
-
throw new WsError(CLOSE.protocol, "unexpected continuation frame");
|
|
3029
|
+
if (payload.length >= 2 && !sendableCode(code)) {
|
|
3030
|
+
throw new WsError(CLOSE.protocol, `close code ${code} may not be sent`);
|
|
2750
3031
|
}
|
|
2751
|
-
|
|
2752
|
-
this.size += payload.length;
|
|
2753
|
-
this.continuing = !fin;
|
|
2754
|
-
if (!fin) return void 0;
|
|
2755
|
-
const whole = this.parts.length === 1 ? payload : concat(this.parts, this.size);
|
|
2756
|
-
this.parts = [];
|
|
2757
|
-
this.size = 0;
|
|
2758
|
-
return { kind: "text", text: decode(whole) };
|
|
3032
|
+
return { kind: "close", code, reason: decode(payload.subarray(2)) };
|
|
2759
3033
|
}
|
|
2760
3034
|
case OP.binary:
|
|
2761
|
-
throw new WsError(CLOSE.unsupported, "CDP messages are text");
|
|
3035
|
+
if (!this.binary) throw new WsError(CLOSE.unsupported, "CDP messages are text");
|
|
3036
|
+
return this.data(opcode, fin, payload);
|
|
3037
|
+
case OP.text:
|
|
3038
|
+
case OP.continuation:
|
|
3039
|
+
return this.data(opcode, fin, payload);
|
|
2762
3040
|
default:
|
|
2763
3041
|
throw new WsError(CLOSE.protocol, `unknown opcode ${opcode}`);
|
|
2764
3042
|
}
|
|
2765
3043
|
}
|
|
2766
3044
|
};
|
|
2767
|
-
function switchingHead(accept2) {
|
|
3045
|
+
function switchingHead(accept2, protocol = "") {
|
|
3046
|
+
const chosen = protocol ? `Sec-WebSocket-Protocol: ${protocol}\r
|
|
3047
|
+
` : "";
|
|
2768
3048
|
return latin1Bytes(
|
|
2769
3049
|
`HTTP/1.1 101 Switching Protocols\r
|
|
2770
3050
|
Upgrade: websocket\r
|
|
2771
3051
|
Connection: Upgrade\r
|
|
2772
3052
|
Sec-WebSocket-Accept: ${accept2}\r
|
|
2773
|
-
\r
|
|
3053
|
+
${chosen}\r
|
|
2774
3054
|
`
|
|
2775
3055
|
);
|
|
2776
3056
|
}
|
|
@@ -2778,7 +3058,7 @@ Sec-WebSocket-Accept: ${accept2}\r
|
|
|
2778
3058
|
// src/cdp/facade.ts
|
|
2779
3059
|
var MAX_HEAD = 64 * 1024;
|
|
2780
3060
|
var LIST_TIMEOUT = 1e4;
|
|
2781
|
-
var
|
|
3061
|
+
var CLOSE_WAIT_MS2 = 1e3;
|
|
2782
3062
|
function respond(status, body, type = "text/plain; charset=utf-8") {
|
|
2783
3063
|
const bytes = new TextEncoder().encode(body);
|
|
2784
3064
|
const head = latin1Bytes(
|
|
@@ -2926,7 +3206,7 @@ var CdpFacade = class {
|
|
|
2926
3206
|
const host = await this.host(runtime);
|
|
2927
3207
|
const limits = {
|
|
2928
3208
|
max: this.options.maxMessage ?? MAX_MESSAGE,
|
|
2929
|
-
closeWaitMs: this.options.closeWaitMs ??
|
|
3209
|
+
closeWaitMs: this.options.closeWaitMs ?? CLOSE_WAIT_MS2
|
|
2930
3210
|
};
|
|
2931
3211
|
await new Relay(conn, incoming, host, limits, this.stop.signal).start(switchingHead(accept2)).finally(() => host.close());
|
|
2932
3212
|
}
|
|
@@ -5276,12 +5556,17 @@ function ownNames(hostname) {
|
|
|
5276
5556
|
}
|
|
5277
5557
|
|
|
5278
5558
|
// src/kernel/net/proxy-service.ts
|
|
5559
|
+
var SEND_BUFFER2 = 1024 * 1024;
|
|
5560
|
+
var TLS_HANDSHAKE = 22;
|
|
5561
|
+
var TOKEN2 = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
5562
|
+
var NO_WEBSOCKET2 = "WebSocket not supported by this transport (fetchTransport needs { webSocket: true })";
|
|
5279
5563
|
var REALM_PROXY_PORT = 3128;
|
|
5280
5564
|
var DEFAULT_LIMITS = {
|
|
5281
5565
|
maxConnections: 64,
|
|
5282
5566
|
maxHead: 64 * 1024,
|
|
5283
5567
|
idleMs: 12e4,
|
|
5284
|
-
bodyBudget: 128 * 1024 * 1024
|
|
5568
|
+
bodyBudget: 128 * 1024 * 1024,
|
|
5569
|
+
closeWaitMs: 5e3
|
|
5285
5570
|
};
|
|
5286
5571
|
var HOP_BY_HOP = /* @__PURE__ */ new Set([
|
|
5287
5572
|
"connection",
|
|
@@ -5472,11 +5757,27 @@ function plainResponse(status, message2) {
|
|
|
5472
5757
|
cancel: async () => void 0
|
|
5473
5758
|
};
|
|
5474
5759
|
}
|
|
5475
|
-
function timedSource(conn,
|
|
5760
|
+
function timedSource(conn, idle, stop) {
|
|
5476
5761
|
return {
|
|
5477
|
-
read: (max) =>
|
|
5762
|
+
read: (max, signal) => {
|
|
5763
|
+
const own = signal ? [stop, signal] : [stop];
|
|
5764
|
+
if (Number.isFinite(idle.ms)) own.push(AbortSignal.timeout(idle.ms));
|
|
5765
|
+
return conn.read(max, AbortSignal.any(own));
|
|
5766
|
+
}
|
|
5478
5767
|
};
|
|
5479
5768
|
}
|
|
5769
|
+
function webSocketTarget(req) {
|
|
5770
|
+
return { ...req, target: req.target.replace(/^ws(s?):/i, (_, s) => `http${s.toLowerCase()}:`) };
|
|
5771
|
+
}
|
|
5772
|
+
function wireCode(code) {
|
|
5773
|
+
if (code === 1005) return 1e3;
|
|
5774
|
+
return sendableCode(code) ? code : 1011;
|
|
5775
|
+
}
|
|
5776
|
+
function quietly(ms) {
|
|
5777
|
+
return new Promise((resolve) => {
|
|
5778
|
+
AbortSignal.timeout(ms).addEventListener("abort", () => resolve(), { once: true });
|
|
5779
|
+
});
|
|
5780
|
+
}
|
|
5480
5781
|
var RealmProxy = class {
|
|
5481
5782
|
options;
|
|
5482
5783
|
listener;
|
|
@@ -5485,6 +5786,7 @@ var RealmProxy = class {
|
|
|
5485
5786
|
slots;
|
|
5486
5787
|
bodies;
|
|
5487
5788
|
connections = /* @__PURE__ */ new Set();
|
|
5789
|
+
warnedWebSocket = false;
|
|
5488
5790
|
closed;
|
|
5489
5791
|
port;
|
|
5490
5792
|
constructor(options) {
|
|
@@ -5533,9 +5835,10 @@ var RealmProxy = class {
|
|
|
5533
5835
|
}
|
|
5534
5836
|
async serve(conn) {
|
|
5535
5837
|
this.connections.add(conn);
|
|
5536
|
-
const
|
|
5838
|
+
const idle = { ms: this.limits.idleMs };
|
|
5839
|
+
const incoming = new Incoming(timedSource(conn, idle, this.stop.signal));
|
|
5537
5840
|
try {
|
|
5538
|
-
await this.requests({ sink: conn, incoming, conn, socket: conn });
|
|
5841
|
+
await this.requests({ sink: conn, incoming, conn, socket: conn, idle });
|
|
5539
5842
|
} finally {
|
|
5540
5843
|
this.connections.delete(conn);
|
|
5541
5844
|
conn.close();
|
|
@@ -5562,7 +5865,11 @@ var RealmProxy = class {
|
|
|
5562
5865
|
const req = parseRequestHead(head);
|
|
5563
5866
|
if (req.method === "CONNECT") {
|
|
5564
5867
|
if (!ctx.conn) throw new HttpError(400, "CONNECT inside a tunnel");
|
|
5565
|
-
await this.connect(ctx.conn, incoming, req);
|
|
5868
|
+
await this.connect(ctx.conn, incoming, req, ctx.idle);
|
|
5869
|
+
return false;
|
|
5870
|
+
}
|
|
5871
|
+
if (req.method === "GET" && isUpgrade(req.headers)) {
|
|
5872
|
+
await this.websocket(ctx, req);
|
|
5566
5873
|
return false;
|
|
5567
5874
|
}
|
|
5568
5875
|
const url = ctx.origin ? tunnelRequestUrl(req, ctx.origin) : requestUrl(req);
|
|
@@ -5657,33 +5964,149 @@ var RealmProxy = class {
|
|
|
5657
5964
|
if (chunked2) await conn.write(LAST_CHUNK, signal);
|
|
5658
5965
|
return keep;
|
|
5659
5966
|
}
|
|
5660
|
-
async connect(conn, incoming, req) {
|
|
5967
|
+
async connect(conn, incoming, req, idle) {
|
|
5661
5968
|
const target = tunnelTarget(req);
|
|
5662
|
-
const
|
|
5663
|
-
if (
|
|
5664
|
-
throw new HttpError(
|
|
5665
|
-
501,
|
|
5666
|
-
`CONNECT ${target.host}:${target.port}: no tunnels through this proxy`
|
|
5667
|
-
);
|
|
5668
|
-
}
|
|
5669
|
-
await this.options.tunnelReady?.().catch((e) => {
|
|
5670
|
-
throw new HttpError(
|
|
5671
|
-
501,
|
|
5672
|
-
`CONNECT ${target.host}:${target.port}: ${e instanceof Error ? e.message : String(e)}`
|
|
5673
|
-
);
|
|
5674
|
-
});
|
|
5969
|
+
const refused = target.port === 443 ? await this.tunnelReady(target) : void 0;
|
|
5970
|
+
if (refused) throw refused;
|
|
5675
5971
|
await conn.write(latin1Bytes("HTTP/1.1 200 Connection Established\r\n\r\n"), this.stop.signal);
|
|
5676
5972
|
try {
|
|
5973
|
+
const first = await incoming.peek(this.stop.signal);
|
|
5974
|
+
if (first === void 0) return;
|
|
5975
|
+
if (first !== TLS_HANDSHAKE) {
|
|
5976
|
+
const origin = `http://${target.port === 80 ? target.host : `${target.host}:${target.port}`}`;
|
|
5977
|
+
await this.requests({ sink: conn, incoming, origin, socket: conn, idle });
|
|
5978
|
+
return;
|
|
5979
|
+
}
|
|
5980
|
+
const tunnel = this.options.tunnel;
|
|
5981
|
+
if (!tunnel || target.port !== 443 && await this.tunnelReady(target)) return;
|
|
5677
5982
|
await tunnel(
|
|
5678
5983
|
conn,
|
|
5679
5984
|
incoming,
|
|
5680
5985
|
target,
|
|
5681
5986
|
this.stop.signal,
|
|
5682
|
-
(source, sink, origin) => this.requests({ sink, incoming: new Incoming(source), origin, socket: conn })
|
|
5987
|
+
(source, sink, origin) => this.requests({ sink, incoming: new Incoming(source), origin, socket: conn, idle })
|
|
5683
5988
|
);
|
|
5684
5989
|
} catch {
|
|
5685
5990
|
}
|
|
5686
5991
|
}
|
|
5992
|
+
async tunnelReady(target) {
|
|
5993
|
+
const name2 = `CONNECT ${target.host}:${target.port}`;
|
|
5994
|
+
if (!this.options.tunnel) return new HttpError(501, `${name2}: no tunnels through this proxy`);
|
|
5995
|
+
try {
|
|
5996
|
+
await this.options.tunnelReady?.();
|
|
5997
|
+
return void 0;
|
|
5998
|
+
} catch (e) {
|
|
5999
|
+
return new HttpError(501, `${name2}: ${e instanceof Error ? e.message : String(e)}`);
|
|
6000
|
+
}
|
|
6001
|
+
}
|
|
6002
|
+
async websocket(ctx, req) {
|
|
6003
|
+
const href = ctx.origin ? tunnelRequestUrl(req, ctx.origin) : requestUrl(webSocketTarget(req));
|
|
6004
|
+
const { transport } = this.options;
|
|
6005
|
+
if (!transport.traits.websocket || !transport.websocket) {
|
|
6006
|
+
if (!this.warnedWebSocket) {
|
|
6007
|
+
this.warnedWebSocket = true;
|
|
6008
|
+
console.warn(`slicc-kernel: a program asked for a WebSocket: ${NO_WEBSOCKET2}`);
|
|
6009
|
+
}
|
|
6010
|
+
throw new HttpError(501, NO_WEBSOCKET2);
|
|
6011
|
+
}
|
|
6012
|
+
const accept2 = await acceptKey(req.headers);
|
|
6013
|
+
const protocols = fieldValues(req.headers, "sec-websocket-protocol").flatMap((v) => v.split(",")).map((t) => t.trim()).filter((t) => t !== "");
|
|
6014
|
+
const hangup = new AbortController();
|
|
6015
|
+
const waiting = new AbortController();
|
|
6016
|
+
void watchHangup(ctx.socket, hangup, waiting.signal);
|
|
6017
|
+
let socket;
|
|
6018
|
+
try {
|
|
6019
|
+
socket = await transport.websocket({
|
|
6020
|
+
url: toHostLoopback(href).replace(/^http/, "ws"),
|
|
6021
|
+
protocols,
|
|
6022
|
+
headers: forwardRequestHeaders(req.headers),
|
|
6023
|
+
signal: AbortSignal.any([this.stop.signal, hangup.signal])
|
|
6024
|
+
});
|
|
6025
|
+
} catch (e) {
|
|
6026
|
+
waiting.abort();
|
|
6027
|
+
throw new HttpError(502, e instanceof Error ? e.message : String(e));
|
|
6028
|
+
}
|
|
6029
|
+
ctx.idle.ms = Number.POSITIVE_INFINITY;
|
|
6030
|
+
try {
|
|
6031
|
+
if (hangup.signal.aborted) throw hangup.signal.reason;
|
|
6032
|
+
if (socket.protocol && !(protocols.includes(socket.protocol) && TOKEN2.test(socket.protocol))) {
|
|
6033
|
+
throw new HttpError(502, "the far end chose a subprotocol the client did not offer");
|
|
6034
|
+
}
|
|
6035
|
+
await ctx.sink.write(switchingHead(accept2, socket.protocol), this.stop.signal);
|
|
6036
|
+
await this.bridge(ctx, socket, hangup.signal);
|
|
6037
|
+
} catch (e) {
|
|
6038
|
+
socket.close(1001, "the client went away");
|
|
6039
|
+
throw e;
|
|
6040
|
+
} finally {
|
|
6041
|
+
waiting.abort();
|
|
6042
|
+
}
|
|
6043
|
+
}
|
|
6044
|
+
async bridge(ctx, socket, hangup) {
|
|
6045
|
+
const stop = this.stop.signal;
|
|
6046
|
+
let chain = Promise.resolve();
|
|
6047
|
+
const toGuest = (bytes) => {
|
|
6048
|
+
chain = chain.then(() => ctx.sink.write(bytes, stop));
|
|
6049
|
+
return chain;
|
|
6050
|
+
};
|
|
6051
|
+
const done4 = new AbortController();
|
|
6052
|
+
const reading = AbortSignal.any([stop, done4.signal, hangup]);
|
|
6053
|
+
const stopping = () => socket.close(1001, "the proxy is stopping");
|
|
6054
|
+
stop.addEventListener("abort", stopping, { once: true });
|
|
6055
|
+
let guestDone = false;
|
|
6056
|
+
let closeSent = false;
|
|
6057
|
+
const outbound2 = (async () => {
|
|
6058
|
+
for await (const data of socket.messages) {
|
|
6059
|
+
if (guestDone) continue;
|
|
6060
|
+
const text = typeof data === "string";
|
|
6061
|
+
await toGuest(
|
|
6062
|
+
frame(text ? OP_TEXT : OP_BINARY, text ? new TextEncoder().encode(data) : data)
|
|
6063
|
+
);
|
|
6064
|
+
}
|
|
6065
|
+
const closed = await socket.closed;
|
|
6066
|
+
if (guestDone) return;
|
|
6067
|
+
closeSent = true;
|
|
6068
|
+
await toGuest(closeFrame(wireCode(closed.code), closed.reason));
|
|
6069
|
+
AbortSignal.timeout(this.limits.closeWaitMs).addEventListener("abort", () => done4.abort(), {
|
|
6070
|
+
once: true
|
|
6071
|
+
});
|
|
6072
|
+
})().catch(() => done4.abort());
|
|
6073
|
+
const reader = new WsReader(ctx.incoming, MESSAGE_LIMIT, true);
|
|
6074
|
+
try {
|
|
6075
|
+
for (; ; ) {
|
|
6076
|
+
const event = await reader.next(reading);
|
|
6077
|
+
if (!event) break;
|
|
6078
|
+
if (event.kind === "ping") {
|
|
6079
|
+
await toGuest(pongFrame(event.payload));
|
|
6080
|
+
continue;
|
|
6081
|
+
}
|
|
6082
|
+
if (event.kind === "close") {
|
|
6083
|
+
guestDone = true;
|
|
6084
|
+
if (closeSent) break;
|
|
6085
|
+
const code = wireCode(event.code);
|
|
6086
|
+
socket.close(code, event.reason);
|
|
6087
|
+
const reply = await Promise.race([
|
|
6088
|
+
socket.closed,
|
|
6089
|
+
quietly(this.limits.closeWaitMs).then(() => ({ code, reason: event.reason }))
|
|
6090
|
+
]);
|
|
6091
|
+
await toGuest(closeFrame(wireCode(reply.code), reply.reason));
|
|
6092
|
+
break;
|
|
6093
|
+
}
|
|
6094
|
+
while (socket.buffered > SEND_BUFFER2 && !reading.aborted) await quietly(10);
|
|
6095
|
+
socket.send(event.kind === "text" ? event.text : event.bytes);
|
|
6096
|
+
}
|
|
6097
|
+
} catch (e) {
|
|
6098
|
+
if (e instanceof WsError) {
|
|
6099
|
+
guestDone = true;
|
|
6100
|
+
socket.close(e.code, e.message);
|
|
6101
|
+
await toGuest(closeFrame(e.code, e.message)).catch(() => void 0);
|
|
6102
|
+
}
|
|
6103
|
+
} finally {
|
|
6104
|
+
guestDone = true;
|
|
6105
|
+
socket.close(1e3, "the client went away");
|
|
6106
|
+
stop.removeEventListener("abort", stopping);
|
|
6107
|
+
await Promise.race([outbound2, quietly(this.limits.closeWaitMs)]);
|
|
6108
|
+
}
|
|
6109
|
+
}
|
|
5687
6110
|
};
|
|
5688
6111
|
|
|
5689
6112
|
// src/kernel/net/x509.ts
|
|
@@ -8778,7 +9201,42 @@ var Dying = class {
|
|
|
8778
9201
|
return [typeof reported === "number" ? reported : CRASHED, void 0];
|
|
8779
9202
|
}
|
|
8780
9203
|
};
|
|
8781
|
-
function
|
|
9204
|
+
function notifiers(header3) {
|
|
9205
|
+
return {
|
|
9206
|
+
onPending(sig) {
|
|
9207
|
+
Atomics.or(header3, SAB_I_SIGNALS, sigbit(sig));
|
|
9208
|
+
Atomics.notify(header3, SAB_I_SIGNALS);
|
|
9209
|
+
},
|
|
9210
|
+
onAsync() {
|
|
9211
|
+
Atomics.add(header3, SAB_I_ASYNC, 1);
|
|
9212
|
+
Atomics.notify(header3, SAB_I_ASYNC);
|
|
9213
|
+
}
|
|
9214
|
+
};
|
|
9215
|
+
}
|
|
9216
|
+
function publishStops(process, header3) {
|
|
9217
|
+
process.onState((state) => {
|
|
9218
|
+
Atomics.store(header3, SAB_I_STOP, state === "stopped" ? 1 : 0);
|
|
9219
|
+
Atomics.notify(header3, SAB_I_STOP);
|
|
9220
|
+
});
|
|
9221
|
+
}
|
|
9222
|
+
function transferOf(opts, lane) {
|
|
9223
|
+
const transfer = opts.fork ? [opts.fork.memory.buffer] : [];
|
|
9224
|
+
return lane ? [...transfer, lane.port] : transfer;
|
|
9225
|
+
}
|
|
9226
|
+
function openLane(token, dispatch2) {
|
|
9227
|
+
const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
9228
|
+
const { port1, port2 } = new MessageChannel();
|
|
9229
|
+
const responder = attachSyncSabResponder(port1, sab, token, { dispatch: dispatch2 });
|
|
9230
|
+
port1.start();
|
|
9231
|
+
return {
|
|
9232
|
+
lane: { sab, port: port2 },
|
|
9233
|
+
dispose() {
|
|
9234
|
+
responder.dispose();
|
|
9235
|
+
port1.close();
|
|
9236
|
+
}
|
|
9237
|
+
};
|
|
9238
|
+
}
|
|
9239
|
+
function processInit(opts, sab, umask, lane) {
|
|
8782
9240
|
const base = {
|
|
8783
9241
|
type: WASM_PROCESS_INIT,
|
|
8784
9242
|
pid: opts.shownPid ?? opts.pid,
|
|
@@ -8791,7 +9249,12 @@ function processInit(opts, sab, umask) {
|
|
|
8791
9249
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {}
|
|
8792
9250
|
};
|
|
8793
9251
|
if (opts.program.abi === "js") {
|
|
8794
|
-
return {
|
|
9252
|
+
return {
|
|
9253
|
+
...base,
|
|
9254
|
+
program: opts.program,
|
|
9255
|
+
fds: inheritedFds(opts.fds),
|
|
9256
|
+
lane
|
|
9257
|
+
};
|
|
8795
9258
|
}
|
|
8796
9259
|
return {
|
|
8797
9260
|
...base,
|
|
@@ -8843,23 +9306,13 @@ function spawnWasmProcess(opts) {
|
|
|
8843
9306
|
locks: opts.locks,
|
|
8844
9307
|
onReap: opts.onReap,
|
|
8845
9308
|
resolver: opts.resolver,
|
|
8846
|
-
|
|
8847
|
-
Atomics.or(header3, SAB_I_SIGNALS, sigbit(sig));
|
|
8848
|
-
Atomics.notify(header3, SAB_I_SIGNALS);
|
|
8849
|
-
},
|
|
8850
|
-
onAsync: () => {
|
|
8851
|
-
Atomics.add(header3, SAB_I_ASYNC, 1);
|
|
8852
|
-
Atomics.notify(header3, SAB_I_ASYNC);
|
|
8853
|
-
},
|
|
9309
|
+
...notifiers(header3),
|
|
8854
9310
|
onTimer: (which) => void Atomics.or(header3, SAB_I_TIMERS, 1 << which),
|
|
8855
9311
|
hasPending: () => Atomics.load(header3, SAB_I_SIGNALS) !== 0 || Atomics.load(header3, SAB_I_TIMERS) !== 0,
|
|
8856
9312
|
raise: (sig) => signal(sig),
|
|
8857
9313
|
...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header3, SAB_I_SIGNALS) } : {}
|
|
8858
9314
|
});
|
|
8859
|
-
process
|
|
8860
|
-
Atomics.store(header3, SAB_I_STOP, state === "stopped" ? 1 : 0);
|
|
8861
|
-
Atomics.notify(header3, SAB_I_STOP);
|
|
8862
|
-
});
|
|
9315
|
+
publishStops(process, header3);
|
|
8863
9316
|
const holds = new HeldPaths();
|
|
8864
9317
|
opts.held?.add(holds);
|
|
8865
9318
|
const token = holdingToken(opts, holds);
|
|
@@ -8868,6 +9321,7 @@ function spawnWasmProcess(opts) {
|
|
|
8868
9321
|
const dying = new Dying();
|
|
8869
9322
|
const dispatch2 = (req) => dying.serving(() => isWasmSyscall(req) ? process.syscall(req) : dispatchSyncFs(req));
|
|
8870
9323
|
const responder = attachSyncSabResponder(worker, sab, token, { dispatch: dispatch2 });
|
|
9324
|
+
const lane = opts.program.abi === "js" ? openLane(token, dispatch2) : void 0;
|
|
8871
9325
|
const { promise: exited, resolve: settle } = Promise.withResolvers();
|
|
8872
9326
|
let done4 = false;
|
|
8873
9327
|
let endedBy;
|
|
@@ -8880,6 +9334,7 @@ function spawnWasmProcess(opts) {
|
|
|
8880
9334
|
worker.removeEventListener("error", onError);
|
|
8881
9335
|
for (const tid of [...threads.keys()]) endThread(tid);
|
|
8882
9336
|
responder.dispose();
|
|
9337
|
+
lane?.dispose();
|
|
8883
9338
|
revokeSyncFsToken(token);
|
|
8884
9339
|
opts.held?.delete(holds);
|
|
8885
9340
|
worker.terminate();
|
|
@@ -8950,8 +9405,10 @@ function spawnWasmProcess(opts) {
|
|
|
8950
9405
|
};
|
|
8951
9406
|
tw.postMessage(tinit);
|
|
8952
9407
|
};
|
|
8953
|
-
|
|
8954
|
-
|
|
9408
|
+
worker.postMessage(
|
|
9409
|
+
processInit(opts, sab, process.umask, lane?.lane),
|
|
9410
|
+
transferOf(opts, lane?.lane)
|
|
9411
|
+
);
|
|
8955
9412
|
const signal = (sig) => {
|
|
8956
9413
|
if (process.signal(sig) !== "terminate") return;
|
|
8957
9414
|
const code = sig === SIG.KILL ? 137 : 128 + sig;
|
|
@@ -11429,12 +11886,15 @@ var RemoteTransport = class {
|
|
|
11429
11886
|
port;
|
|
11430
11887
|
waiting = /* @__PURE__ */ new Map();
|
|
11431
11888
|
nextId = 0;
|
|
11889
|
+
sockets = /* @__PURE__ */ new Map();
|
|
11432
11890
|
failure;
|
|
11433
11891
|
constructor(port, traits) {
|
|
11434
11892
|
this.port = port;
|
|
11435
11893
|
this.traits = traits;
|
|
11436
11894
|
}
|
|
11437
11895
|
receive(reply) {
|
|
11896
|
+
const socket = this.sockets.get(reply.nid);
|
|
11897
|
+
if (socket && this.toSocket(reply, socket)) return;
|
|
11438
11898
|
const waiter = this.waiting.get(reply.nid);
|
|
11439
11899
|
if (!waiter) return;
|
|
11440
11900
|
this.waiting.delete(reply.nid);
|
|
@@ -11442,10 +11902,22 @@ var RemoteTransport = class {
|
|
|
11442
11902
|
waiter.reject(new TransportError(reply.message, reply.status, reply.code));
|
|
11443
11903
|
} else waiter.resolve(reply);
|
|
11444
11904
|
}
|
|
11905
|
+
toSocket(reply, socket) {
|
|
11906
|
+
if (reply.net === "ws-message") socket.queue.push(reply.data);
|
|
11907
|
+
else if (reply.net === "ws-acked") socket.acked(reply.n);
|
|
11908
|
+
else if (reply.net === "ws-closed") {
|
|
11909
|
+
this.sockets.delete(reply.nid);
|
|
11910
|
+
socket.queue.end({ code: reply.code, reason: reply.reason });
|
|
11911
|
+
} else return false;
|
|
11912
|
+
return true;
|
|
11913
|
+
}
|
|
11445
11914
|
fail(error) {
|
|
11446
11915
|
this.failure = error;
|
|
11447
11916
|
for (const waiter of this.waiting.values()) waiter.reject(error);
|
|
11448
11917
|
this.waiting.clear();
|
|
11918
|
+
for (const socket of this.sockets.values())
|
|
11919
|
+
socket.queue.end({ code: 1011, reason: error.message });
|
|
11920
|
+
this.sockets.clear();
|
|
11449
11921
|
}
|
|
11450
11922
|
ask(call) {
|
|
11451
11923
|
if (this.failure) return Promise.reject(this.failure);
|
|
@@ -11524,6 +11996,46 @@ var RemoteTransport = class {
|
|
|
11524
11996
|
}
|
|
11525
11997
|
};
|
|
11526
11998
|
}
|
|
11999
|
+
async websocket(request) {
|
|
12000
|
+
const nid = ++this.nextId;
|
|
12001
|
+
const { signal } = request;
|
|
12002
|
+
signal.throwIfAborted();
|
|
12003
|
+
const abort = () => this.cancel(nid);
|
|
12004
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
12005
|
+
let opened2;
|
|
12006
|
+
try {
|
|
12007
|
+
opened2 = await this.ask({
|
|
12008
|
+
net: "ws-open",
|
|
12009
|
+
nid,
|
|
12010
|
+
url: request.url,
|
|
12011
|
+
protocols: request.protocols,
|
|
12012
|
+
headers: request.headers
|
|
12013
|
+
});
|
|
12014
|
+
} finally {
|
|
12015
|
+
signal.removeEventListener("abort", abort);
|
|
12016
|
+
}
|
|
12017
|
+
const close = (code, reason) => this.port.postMessage({ net: "ws-close", nid, code, reason });
|
|
12018
|
+
const queue = new MessageQueue(
|
|
12019
|
+
() => close(1e3, "a message is too big"),
|
|
12020
|
+
Number.POSITIVE_INFINITY,
|
|
12021
|
+
(n) => this.port.postMessage({ net: "ws-consumed", nid, n })
|
|
12022
|
+
);
|
|
12023
|
+
let unacked = 0;
|
|
12024
|
+
this.sockets.set(nid, { queue, acked: (n) => void (unacked -= n) });
|
|
12025
|
+
return {
|
|
12026
|
+
protocol: opened2.protocol,
|
|
12027
|
+
get buffered() {
|
|
12028
|
+
return unacked;
|
|
12029
|
+
},
|
|
12030
|
+
send: (data) => {
|
|
12031
|
+
unacked += payloadSize(data);
|
|
12032
|
+
this.port.postMessage({ net: "ws-send", nid, data });
|
|
12033
|
+
},
|
|
12034
|
+
messages: queue,
|
|
12035
|
+
close,
|
|
12036
|
+
closed: queue.closed
|
|
12037
|
+
};
|
|
12038
|
+
}
|
|
11527
12039
|
};
|
|
11528
12040
|
|
|
11529
12041
|
// src/serve.ts
|
|
@@ -12145,7 +12657,7 @@ function hostfsFetchOf(options) {
|
|
|
12145
12657
|
};
|
|
12146
12658
|
}
|
|
12147
12659
|
function nodeTransport() {
|
|
12148
|
-
const transport = fetchTransport();
|
|
12660
|
+
const transport = fetchTransport({ webSocket: true, webSocketHeaders: true });
|
|
12149
12661
|
return { ...transport, traits: { ...transport.traits, crossOrigin: "any" } };
|
|
12150
12662
|
}
|
|
12151
12663
|
var TERMINATED = "the kernel is terminated";
|