@ai-ecoverse/slicc-kernel 1.37.1 → 1.39.1

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.
@@ -2032,9 +2032,80 @@ var SIGNAL_BY_NAME = {
2032
2032
  // src/body-idle.ts
2033
2033
  var BODY_IDLE_MS = 5 * 60 * 1e3;
2034
2034
 
2035
+ // src/kernel/net/ws-queue.ts
2036
+ var INBOUND_LIMIT = 16 * 1024 * 1024;
2037
+ var MESSAGE_LIMIT = 64 * 1024 * 1024;
2038
+ var TOO_BIG = 1009;
2039
+ function payloadSize(message2) {
2040
+ return typeof message2 === "string" ? new TextEncoder().encode(message2).length : message2.length;
2041
+ }
2042
+ var MessageQueue = class {
2043
+ items = [];
2044
+ limit;
2045
+ waiter;
2046
+ size = 0;
2047
+ ended = false;
2048
+ overflow;
2049
+ taken;
2050
+ closed;
2051
+ settle;
2052
+ constructor(overflow, limit = INBOUND_LIMIT, taken) {
2053
+ this.overflow = overflow;
2054
+ this.limit = limit;
2055
+ this.taken = taken;
2056
+ this.closed = new Promise((resolve) => {
2057
+ this.settle = resolve;
2058
+ });
2059
+ }
2060
+ push(message2) {
2061
+ if (this.ended) return;
2062
+ const size = payloadSize(message2);
2063
+ const huge = size > MESSAGE_LIMIT;
2064
+ if (huge || this.items.length > 0 && this.size + size > this.limit) {
2065
+ const reason = huge ? `a message is over ${MESSAGE_LIMIT} bytes` : `over ${this.limit} bytes of messages are waiting`;
2066
+ this.end({ code: TOO_BIG, reason });
2067
+ this.overflow();
2068
+ return;
2069
+ }
2070
+ this.size += size;
2071
+ this.items.push(message2);
2072
+ this.wake();
2073
+ }
2074
+ end(close) {
2075
+ if (this.ended) return;
2076
+ this.ended = true;
2077
+ this.settle(close);
2078
+ this.wake();
2079
+ }
2080
+ wake() {
2081
+ const waiter = this.waiter;
2082
+ this.waiter = void 0;
2083
+ waiter?.();
2084
+ }
2085
+ async *[Symbol.asyncIterator]() {
2086
+ for (; ; ) {
2087
+ const next = this.items.shift();
2088
+ if (next !== void 0) {
2089
+ const n = payloadSize(next);
2090
+ this.size -= n;
2091
+ this.taken?.(n);
2092
+ yield next;
2093
+ continue;
2094
+ }
2095
+ if (this.ended) return;
2096
+ await new Promise((resolve) => {
2097
+ this.waiter = resolve;
2098
+ });
2099
+ }
2100
+ }
2101
+ };
2102
+
2035
2103
  // src/transport.ts
2104
+ var SEND_BUFFER = 1024 * 1024;
2105
+ var CLOSE_WAIT_MS = 5e3;
2106
+ var NO_WEBSOCKET = "WebSocket not supported by this transport (fetchTransport needs { webSocket: true })";
2036
2107
  var MAX_REQUEST_BODY = 64 * 1024 * 1024;
2037
- function serveTransport(peer, transport) {
2108
+ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS } = {}) {
2038
2109
  const open = /* @__PURE__ */ new Map();
2039
2110
  const fail = (nid, e) => {
2040
2111
  open.delete(nid);
@@ -2075,6 +2146,96 @@ function serveTransport(peer, transport) {
2075
2146
  fail(call.nid, e);
2076
2147
  }
2077
2148
  };
2149
+ const sockets = /* @__PURE__ */ new Map();
2150
+ const credit = /* @__PURE__ */ new Map();
2151
+ const refill = (nid, n, closing = false) => {
2152
+ const flow = credit.get(nid);
2153
+ if (!flow) return;
2154
+ flow.inflight -= n;
2155
+ if (closing && !flow.closing) {
2156
+ flow.closing = true;
2157
+ flow.deadline();
2158
+ }
2159
+ flow.wake?.();
2160
+ };
2161
+ const openSocket = async (call) => {
2162
+ const abort = new AbortController();
2163
+ open.set(call.nid, { abort });
2164
+ try {
2165
+ if (!transport.websocket) throw new Error(NO_WEBSOCKET);
2166
+ const socket = await transport.websocket({
2167
+ url: call.url,
2168
+ protocols: call.protocols,
2169
+ headers: call.headers,
2170
+ signal: abort.signal
2171
+ });
2172
+ if (!open.delete(call.nid)) {
2173
+ socket.close(1e3, "cancelled");
2174
+ return;
2175
+ }
2176
+ sockets.set(call.nid, socket);
2177
+ peer.postMessage({ net: "ws-opened", nid: call.nid, protocol: socket.protocol });
2178
+ void relay(call.nid, socket);
2179
+ } catch (e) {
2180
+ fail(call.nid, e);
2181
+ }
2182
+ };
2183
+ const relay = async (nid, socket) => {
2184
+ let ending;
2185
+ let late;
2186
+ const unanswered = new Promise((resolve) => {
2187
+ late = () => resolve("late");
2188
+ });
2189
+ const flow = {
2190
+ inflight: 0,
2191
+ closing: false,
2192
+ deadline: () => AbortSignal.timeout(closeWaitMs).addEventListener("abort", late, { once: true })
2193
+ };
2194
+ credit.set(nid, flow);
2195
+ const timedOut = { code: 1006, reason: "the far end did not answer the close" };
2196
+ let oversize = false;
2197
+ try {
2198
+ const messages = socket.messages[Symbol.asyncIterator]();
2199
+ for (; ; ) {
2200
+ const next = await Promise.race([messages.next(), unanswered]);
2201
+ if (next === "late" || next.done) break;
2202
+ const data = next.value;
2203
+ if (flow.closing) continue;
2204
+ if (payloadSize(data) > MESSAGE_LIMIT) {
2205
+ oversize = true;
2206
+ break;
2207
+ }
2208
+ if (typeof data === "string") peer.postMessage({ net: "ws-message", nid, data });
2209
+ else {
2210
+ const bytes = data.slice();
2211
+ peer.postMessage({ net: "ws-message", nid, data: bytes }, [bytes.buffer]);
2212
+ }
2213
+ flow.inflight += payloadSize(data);
2214
+ while (flow.inflight > INBOUND_LIMIT && !flow.closing) {
2215
+ await new Promise((resolve) => {
2216
+ flow.wake = resolve;
2217
+ });
2218
+ }
2219
+ }
2220
+ if (oversize) socket.close(1e3, "a message is too big");
2221
+ ending = oversize ? { code: 1009, reason: `a message is over ${MESSAGE_LIMIT} bytes` } : await Promise.race([socket.closed, unanswered.then(() => timedOut)]);
2222
+ } catch (e) {
2223
+ socket.close(1e3, "the relay failed");
2224
+ ending = { code: 1011, reason: e instanceof Error ? e.message : String(e) };
2225
+ }
2226
+ sockets.delete(nid);
2227
+ credit.delete(nid);
2228
+ peer.postMessage({ net: "ws-closed", nid, ...ending });
2229
+ };
2230
+ const sendOn = async (call) => {
2231
+ const socket = sockets.get(call.nid);
2232
+ if (!socket) return;
2233
+ socket.send(call.data);
2234
+ while (socket.buffered > SEND_BUFFER && sockets.has(call.nid)) {
2235
+ await new Promise((resolve) => setTimeout(resolve, 10));
2236
+ }
2237
+ peer.postMessage({ net: "ws-acked", nid: call.nid, n: payloadSize(call.data) });
2238
+ };
2078
2239
  const read = async (nid) => {
2079
2240
  const body = open.get(nid)?.body;
2080
2241
  if (!body) return;
@@ -2092,6 +2253,8 @@ function serveTransport(peer, transport) {
2092
2253
  }
2093
2254
  };
2094
2255
  const drop = (nid) => {
2256
+ sockets.get(nid)?.close(1e3, "cancelled");
2257
+ refill(nid, 0, true);
2095
2258
  const entry = open.get(nid);
2096
2259
  open.delete(nid);
2097
2260
  entry?.abort.abort();
@@ -2101,10 +2264,16 @@ function serveTransport(peer, transport) {
2101
2264
  answer(call) {
2102
2265
  if (call.net === "fetch") void start(call);
2103
2266
  else if (call.net === "read") void read(call.nid);
2267
+ else if (call.net === "ws-open") void openSocket(call);
2268
+ else if (call.net === "ws-send") void sendOn(call);
2269
+ else if (call.net === "ws-close") {
2270
+ sockets.get(call.nid)?.close(call.code, call.reason);
2271
+ refill(call.nid, 0, true);
2272
+ } else if (call.net === "ws-consumed") refill(call.nid, call.n);
2104
2273
  else drop(call.nid);
2105
2274
  },
2106
2275
  close() {
2107
- for (const nid of [...open.keys()]) drop(nid);
2276
+ for (const nid of [...open.keys(), ...sockets.keys()]) drop(nid);
2108
2277
  }
2109
2278
  };
2110
2279
  }
@@ -2494,6 +2663,10 @@ var Incoming = class {
2494
2663
  this.buf = this.buf.subarray(n);
2495
2664
  return out;
2496
2665
  }
2666
+ async peek(signal) {
2667
+ if (this.buf.length === 0) await this.fill(signal);
2668
+ return this.buf[0];
2669
+ }
2497
2670
  async some(max, signal) {
2498
2671
  if (this.buf.length > 0) return this.take(Math.min(max, this.buf.length));
2499
2672
  if (this.eof) return new Uint8Array(0);
@@ -2675,13 +2848,219 @@ function chunk(bytes) {
2675
2848
  }
2676
2849
  var LAST_CHUNK = latin1Bytes("0\r\n\r\n");
2677
2850
 
2851
+ // src/cdp/websocket.ts
2852
+ var GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
2853
+ var MAX_MESSAGE = 256 * 1024 * 1024;
2854
+ var CLOSE = {
2855
+ normal: 1e3,
2856
+ protocol: 1002,
2857
+ unsupported: 1003,
2858
+ invalid: 1007,
2859
+ tooBig: 1009,
2860
+ error: 1011
2861
+ };
2862
+ var OP_TEXT = 1;
2863
+ var OP_BINARY = 2;
2864
+ var OP = {
2865
+ continuation: 0,
2866
+ text: OP_TEXT,
2867
+ binary: OP_BINARY,
2868
+ close: 8,
2869
+ ping: 9,
2870
+ pong: 10
2871
+ };
2872
+ var WsError = class extends Error {
2873
+ code;
2874
+ constructor(code, message2) {
2875
+ super(message2);
2876
+ this.code = code;
2877
+ }
2878
+ };
2879
+ function sendableCode(code) {
2880
+ if (code >= 3e3 && code <= 4999) return true;
2881
+ return code >= 1e3 && code <= 1014 && code !== 1004 && code !== 1005 && code !== 1006;
2882
+ }
2883
+ function field(headers, name2) {
2884
+ return headers.find(([n]) => n.toLowerCase() === name2)?.[1];
2885
+ }
2886
+ async function acceptKey(headers) {
2887
+ const tokens = (name2) => (field(headers, name2) ?? "").split(",").map((t) => t.trim().toLowerCase());
2888
+ if (!tokens("upgrade").includes("websocket") || !tokens("connection").includes("upgrade")) {
2889
+ throw new HttpError(400, "expected a WebSocket upgrade");
2890
+ }
2891
+ if (field(headers, "sec-websocket-version") !== "13") {
2892
+ throw new HttpError(400, "Sec-WebSocket-Version must be 13");
2893
+ }
2894
+ const key = field(headers, "sec-websocket-key") ?? "";
2895
+ if (!/^[A-Za-z0-9+/]{22}==$/.test(key)) throw new HttpError(400, "bad Sec-WebSocket-Key");
2896
+ const digest = await crypto.subtle.digest("SHA-1", new TextEncoder().encode(key + GUID));
2897
+ return btoa(String.fromCharCode(...new Uint8Array(digest)));
2898
+ }
2899
+ function isUpgrade(headers) {
2900
+ return (field(headers, "upgrade") ?? "").toLowerCase().includes("websocket");
2901
+ }
2902
+ function frame(opcode, payload) {
2903
+ const n = payload.length;
2904
+ const size = n < 126 ? 2 : n < 65536 ? 4 : 10;
2905
+ const out = new Uint8Array(size + n);
2906
+ const view = new DataView(out.buffer);
2907
+ out[0] = 128 | opcode;
2908
+ if (n < 126) out[1] = n;
2909
+ else if (n < 65536) {
2910
+ out[1] = 126;
2911
+ view.setUint16(2, n);
2912
+ } else {
2913
+ out[1] = 127;
2914
+ view.setBigUint64(2, BigInt(n));
2915
+ }
2916
+ out.set(payload, size);
2917
+ return out;
2918
+ }
2919
+ function closeFrame(code, reason = "") {
2920
+ let bytes = new TextEncoder().encode(reason);
2921
+ if (bytes.length > 123) {
2922
+ let end = 123;
2923
+ while ((bytes[end] & 192) === 128) end--;
2924
+ bytes = bytes.subarray(0, end);
2925
+ }
2926
+ const payload = new Uint8Array(2 + bytes.length);
2927
+ new DataView(payload.buffer).setUint16(0, code);
2928
+ payload.set(bytes, 2);
2929
+ return frame(OP.close, payload);
2930
+ }
2931
+ function pongFrame(payload) {
2932
+ return frame(OP.pong, payload);
2933
+ }
2934
+ async function fill(incoming, out, signal) {
2935
+ for (let at = 0; at < out.length; ) {
2936
+ const piece = await incoming.some(out.length - at, signal);
2937
+ if (piece.length === 0) throw new WsError(CLOSE.protocol, "the connection closed mid-frame");
2938
+ out.set(piece, at);
2939
+ at += piece.length;
2940
+ }
2941
+ }
2942
+ var fatal = new TextDecoder("utf-8", { fatal: true });
2943
+ function decode(bytes) {
2944
+ try {
2945
+ return fatal.decode(bytes);
2946
+ } catch {
2947
+ throw new WsError(CLOSE.invalid, "a text message is not UTF-8");
2948
+ }
2949
+ }
2950
+ var WsReader = class {
2951
+ incoming;
2952
+ max;
2953
+ parts = [];
2954
+ size = 0;
2955
+ continuing = false;
2956
+ binaryMessage = false;
2957
+ binary;
2958
+ constructor(incoming, max = MAX_MESSAGE, binary) {
2959
+ this.incoming = incoming;
2960
+ this.max = max;
2961
+ this.binary = binary;
2962
+ }
2963
+ async next(signal) {
2964
+ for (; ; ) {
2965
+ const first = await this.incoming.some(1, signal);
2966
+ if (first.length === 0) return null;
2967
+ const head = new Uint8Array(2);
2968
+ head[0] = first[0];
2969
+ await fill(this.incoming, head.subarray(1), signal);
2970
+ const fin = (head[0] & 128) !== 0;
2971
+ const opcode = head[0] & 15;
2972
+ if ((head[0] & 112) !== 0) throw new WsError(CLOSE.protocol, "reserved bits are set");
2973
+ if ((head[1] & 128) === 0) throw new WsError(CLOSE.protocol, "client frames must be masked");
2974
+ const length2 = await this.length(head[1] & 127, signal);
2975
+ const control = opcode >= 8;
2976
+ if (control && (length2 > 125 || !fin)) {
2977
+ throw new WsError(CLOSE.protocol, "a control frame is too long or fragmented");
2978
+ }
2979
+ if (!control && this.size + length2 > this.max) {
2980
+ throw new WsError(CLOSE.tooBig, `a message is over ${this.max} bytes`);
2981
+ }
2982
+ const mask = new Uint8Array(4);
2983
+ await fill(this.incoming, mask, signal);
2984
+ const payload = new Uint8Array(length2);
2985
+ await fill(this.incoming, payload, signal);
2986
+ for (let i = 0; i < length2; i++) payload[i] ^= mask[i & 3];
2987
+ const event = this.take(opcode, fin, payload);
2988
+ if (event) return event;
2989
+ }
2990
+ }
2991
+ data(opcode, fin, payload) {
2992
+ if (opcode === OP.continuation !== this.continuing) {
2993
+ throw new WsError(CLOSE.protocol, "unexpected continuation frame");
2994
+ }
2995
+ if (opcode !== OP.continuation) this.binaryMessage = opcode === OP.binary;
2996
+ this.parts.push(payload);
2997
+ this.size += payload.length;
2998
+ this.continuing = !fin;
2999
+ if (!fin) return void 0;
3000
+ const whole = this.parts.length === 1 ? payload : concat(this.parts, this.size);
3001
+ this.parts = [];
3002
+ this.size = 0;
3003
+ return this.binaryMessage ? { kind: "binary", bytes: whole } : { kind: "text", text: decode(whole) };
3004
+ }
3005
+ async length(short, signal) {
3006
+ if (short < 126) return short;
3007
+ const ext = new Uint8Array(short === 126 ? 2 : 8);
3008
+ await fill(this.incoming, ext, signal);
3009
+ const view = new DataView(ext.buffer);
3010
+ if (short === 126) return view.getUint16(0);
3011
+ const long = view.getBigUint64(0);
3012
+ return long > BigInt(this.max) ? this.max + 1 : Number(long);
3013
+ }
3014
+ take(opcode, fin, payload) {
3015
+ switch (opcode) {
3016
+ case OP.ping:
3017
+ return { kind: "ping", payload };
3018
+ case OP.pong:
3019
+ return void 0;
3020
+ case OP.close: {
3021
+ if (payload.length === 1) throw new WsError(CLOSE.protocol, "a close frame is malformed");
3022
+ const code = payload.length >= 2 ? new DataView(payload.buffer).getUint16(0) : 1005;
3023
+ if (payload.length >= 2 && !sendableCode(code)) {
3024
+ throw new WsError(CLOSE.protocol, `close code ${code} may not be sent`);
3025
+ }
3026
+ return { kind: "close", code, reason: decode(payload.subarray(2)) };
3027
+ }
3028
+ case OP.binary:
3029
+ if (!this.binary) throw new WsError(CLOSE.unsupported, "CDP messages are text");
3030
+ return this.data(opcode, fin, payload);
3031
+ case OP.text:
3032
+ case OP.continuation:
3033
+ return this.data(opcode, fin, payload);
3034
+ default:
3035
+ throw new WsError(CLOSE.protocol, `unknown opcode ${opcode}`);
3036
+ }
3037
+ }
3038
+ };
3039
+ function switchingHead(accept2, protocol = "") {
3040
+ const chosen = protocol ? `Sec-WebSocket-Protocol: ${protocol}\r
3041
+ ` : "";
3042
+ return latin1Bytes(
3043
+ `HTTP/1.1 101 Switching Protocols\r
3044
+ Upgrade: websocket\r
3045
+ Connection: Upgrade\r
3046
+ Sec-WebSocket-Accept: ${accept2}\r
3047
+ ${chosen}\r
3048
+ `
3049
+ );
3050
+ }
3051
+
2678
3052
  // src/kernel/net/proxy-service.ts
3053
+ var SEND_BUFFER2 = 1024 * 1024;
3054
+ var TLS_HANDSHAKE = 22;
3055
+ var TOKEN2 = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
3056
+ var NO_WEBSOCKET2 = "WebSocket not supported by this transport (fetchTransport needs { webSocket: true })";
2679
3057
  var REALM_PROXY_PORT = 3128;
2680
3058
  var DEFAULT_LIMITS = {
2681
3059
  maxConnections: 64,
2682
3060
  maxHead: 64 * 1024,
2683
3061
  idleMs: 12e4,
2684
- bodyBudget: 128 * 1024 * 1024
3062
+ bodyBudget: 128 * 1024 * 1024,
3063
+ closeWaitMs: 5e3
2685
3064
  };
2686
3065
  var HOP_BY_HOP = /* @__PURE__ */ new Set([
2687
3066
  "connection",
@@ -2872,11 +3251,27 @@ function plainResponse(status, message2) {
2872
3251
  cancel: async () => void 0
2873
3252
  };
2874
3253
  }
2875
- function timedSource(conn, idleMs, stop) {
3254
+ function timedSource(conn, idle, stop) {
2876
3255
  return {
2877
- read: (max) => conn.read(max, AbortSignal.any([stop, AbortSignal.timeout(idleMs)]))
3256
+ read: (max, signal) => {
3257
+ const own = signal ? [stop, signal] : [stop];
3258
+ if (Number.isFinite(idle.ms)) own.push(AbortSignal.timeout(idle.ms));
3259
+ return conn.read(max, AbortSignal.any(own));
3260
+ }
2878
3261
  };
2879
3262
  }
3263
+ function webSocketTarget(req) {
3264
+ return { ...req, target: req.target.replace(/^ws(s?):/i, (_, s) => `http${s.toLowerCase()}:`) };
3265
+ }
3266
+ function wireCode(code) {
3267
+ if (code === 1005) return 1e3;
3268
+ return sendableCode(code) ? code : 1011;
3269
+ }
3270
+ function quietly(ms) {
3271
+ return new Promise((resolve) => {
3272
+ AbortSignal.timeout(ms).addEventListener("abort", () => resolve(), { once: true });
3273
+ });
3274
+ }
2880
3275
  var RealmProxy = class {
2881
3276
  options;
2882
3277
  listener;
@@ -2885,6 +3280,7 @@ var RealmProxy = class {
2885
3280
  slots;
2886
3281
  bodies;
2887
3282
  connections = /* @__PURE__ */ new Set();
3283
+ warnedWebSocket = false;
2888
3284
  closed;
2889
3285
  port;
2890
3286
  constructor(options) {
@@ -2933,9 +3329,10 @@ var RealmProxy = class {
2933
3329
  }
2934
3330
  async serve(conn) {
2935
3331
  this.connections.add(conn);
2936
- const incoming = new Incoming(timedSource(conn, this.limits.idleMs, this.stop.signal));
3332
+ const idle = { ms: this.limits.idleMs };
3333
+ const incoming = new Incoming(timedSource(conn, idle, this.stop.signal));
2937
3334
  try {
2938
- await this.requests({ sink: conn, incoming, conn, socket: conn });
3335
+ await this.requests({ sink: conn, incoming, conn, socket: conn, idle });
2939
3336
  } finally {
2940
3337
  this.connections.delete(conn);
2941
3338
  conn.close();
@@ -2962,7 +3359,11 @@ var RealmProxy = class {
2962
3359
  const req = parseRequestHead(head);
2963
3360
  if (req.method === "CONNECT") {
2964
3361
  if (!ctx.conn) throw new HttpError(400, "CONNECT inside a tunnel");
2965
- await this.connect(ctx.conn, incoming, req);
3362
+ await this.connect(ctx.conn, incoming, req, ctx.idle);
3363
+ return false;
3364
+ }
3365
+ if (req.method === "GET" && isUpgrade(req.headers)) {
3366
+ await this.websocket(ctx, req);
2966
3367
  return false;
2967
3368
  }
2968
3369
  const url = ctx.origin ? tunnelRequestUrl(req, ctx.origin) : requestUrl(req);
@@ -3057,33 +3458,149 @@ var RealmProxy = class {
3057
3458
  if (chunked) await conn.write(LAST_CHUNK, signal);
3058
3459
  return keep;
3059
3460
  }
3060
- async connect(conn, incoming, req) {
3461
+ async connect(conn, incoming, req, idle) {
3061
3462
  const target = tunnelTarget(req);
3062
- const tunnel = this.options.tunnel;
3063
- if (!tunnel) {
3064
- throw new HttpError(
3065
- 501,
3066
- `CONNECT ${target.host}:${target.port}: no tunnels through this proxy`
3067
- );
3068
- }
3069
- await this.options.tunnelReady?.().catch((e) => {
3070
- throw new HttpError(
3071
- 501,
3072
- `CONNECT ${target.host}:${target.port}: ${e instanceof Error ? e.message : String(e)}`
3073
- );
3074
- });
3463
+ const refused = target.port === 443 ? await this.tunnelReady(target) : void 0;
3464
+ if (refused) throw refused;
3075
3465
  await conn.write(latin1Bytes("HTTP/1.1 200 Connection Established\r\n\r\n"), this.stop.signal);
3076
3466
  try {
3467
+ const first = await incoming.peek(this.stop.signal);
3468
+ if (first === void 0) return;
3469
+ if (first !== TLS_HANDSHAKE) {
3470
+ const origin = `http://${target.port === 80 ? target.host : `${target.host}:${target.port}`}`;
3471
+ await this.requests({ sink: conn, incoming, origin, socket: conn, idle });
3472
+ return;
3473
+ }
3474
+ const tunnel = this.options.tunnel;
3475
+ if (!tunnel || target.port !== 443 && await this.tunnelReady(target)) return;
3077
3476
  await tunnel(
3078
3477
  conn,
3079
3478
  incoming,
3080
3479
  target,
3081
3480
  this.stop.signal,
3082
- (source, sink, origin) => this.requests({ sink, incoming: new Incoming(source), origin, socket: conn })
3481
+ (source, sink, origin) => this.requests({ sink, incoming: new Incoming(source), origin, socket: conn, idle })
3083
3482
  );
3084
3483
  } catch {
3085
3484
  }
3086
3485
  }
3486
+ async tunnelReady(target) {
3487
+ const name2 = `CONNECT ${target.host}:${target.port}`;
3488
+ if (!this.options.tunnel) return new HttpError(501, `${name2}: no tunnels through this proxy`);
3489
+ try {
3490
+ await this.options.tunnelReady?.();
3491
+ return void 0;
3492
+ } catch (e) {
3493
+ return new HttpError(501, `${name2}: ${e instanceof Error ? e.message : String(e)}`);
3494
+ }
3495
+ }
3496
+ async websocket(ctx, req) {
3497
+ const href = ctx.origin ? tunnelRequestUrl(req, ctx.origin) : requestUrl(webSocketTarget(req));
3498
+ const { transport } = this.options;
3499
+ if (!transport.traits.websocket || !transport.websocket) {
3500
+ if (!this.warnedWebSocket) {
3501
+ this.warnedWebSocket = true;
3502
+ console.warn(`slicc-kernel: a program asked for a WebSocket: ${NO_WEBSOCKET2}`);
3503
+ }
3504
+ throw new HttpError(501, NO_WEBSOCKET2);
3505
+ }
3506
+ const accept2 = await acceptKey(req.headers);
3507
+ const protocols = fieldValues(req.headers, "sec-websocket-protocol").flatMap((v) => v.split(",")).map((t) => t.trim()).filter((t) => t !== "");
3508
+ const hangup = new AbortController();
3509
+ const waiting = new AbortController();
3510
+ void watchHangup(ctx.socket, hangup, waiting.signal);
3511
+ let socket;
3512
+ try {
3513
+ socket = await transport.websocket({
3514
+ url: toHostLoopback(href).replace(/^http/, "ws"),
3515
+ protocols,
3516
+ headers: forwardRequestHeaders(req.headers),
3517
+ signal: AbortSignal.any([this.stop.signal, hangup.signal])
3518
+ });
3519
+ } catch (e) {
3520
+ waiting.abort();
3521
+ throw new HttpError(502, e instanceof Error ? e.message : String(e));
3522
+ }
3523
+ ctx.idle.ms = Number.POSITIVE_INFINITY;
3524
+ try {
3525
+ if (hangup.signal.aborted) throw hangup.signal.reason;
3526
+ if (socket.protocol && !(protocols.includes(socket.protocol) && TOKEN2.test(socket.protocol))) {
3527
+ throw new HttpError(502, "the far end chose a subprotocol the client did not offer");
3528
+ }
3529
+ await ctx.sink.write(switchingHead(accept2, socket.protocol), this.stop.signal);
3530
+ await this.bridge(ctx, socket, hangup.signal);
3531
+ } catch (e) {
3532
+ socket.close(1001, "the client went away");
3533
+ throw e;
3534
+ } finally {
3535
+ waiting.abort();
3536
+ }
3537
+ }
3538
+ async bridge(ctx, socket, hangup) {
3539
+ const stop = this.stop.signal;
3540
+ let chain = Promise.resolve();
3541
+ const toGuest = (bytes) => {
3542
+ chain = chain.then(() => ctx.sink.write(bytes, stop));
3543
+ return chain;
3544
+ };
3545
+ const done4 = new AbortController();
3546
+ const reading = AbortSignal.any([stop, done4.signal, hangup]);
3547
+ const stopping = () => socket.close(1001, "the proxy is stopping");
3548
+ stop.addEventListener("abort", stopping, { once: true });
3549
+ let guestDone = false;
3550
+ let closeSent = false;
3551
+ const outbound2 = (async () => {
3552
+ for await (const data of socket.messages) {
3553
+ if (guestDone) continue;
3554
+ const text = typeof data === "string";
3555
+ await toGuest(
3556
+ frame(text ? OP_TEXT : OP_BINARY, text ? new TextEncoder().encode(data) : data)
3557
+ );
3558
+ }
3559
+ const closed = await socket.closed;
3560
+ if (guestDone) return;
3561
+ closeSent = true;
3562
+ await toGuest(closeFrame(wireCode(closed.code), closed.reason));
3563
+ AbortSignal.timeout(this.limits.closeWaitMs).addEventListener("abort", () => done4.abort(), {
3564
+ once: true
3565
+ });
3566
+ })().catch(() => done4.abort());
3567
+ const reader = new WsReader(ctx.incoming, MESSAGE_LIMIT, true);
3568
+ try {
3569
+ for (; ; ) {
3570
+ const event = await reader.next(reading);
3571
+ if (!event) break;
3572
+ if (event.kind === "ping") {
3573
+ await toGuest(pongFrame(event.payload));
3574
+ continue;
3575
+ }
3576
+ if (event.kind === "close") {
3577
+ guestDone = true;
3578
+ if (closeSent) break;
3579
+ const code = wireCode(event.code);
3580
+ socket.close(code, event.reason);
3581
+ const reply = await Promise.race([
3582
+ socket.closed,
3583
+ quietly(this.limits.closeWaitMs).then(() => ({ code, reason: event.reason }))
3584
+ ]);
3585
+ await toGuest(closeFrame(wireCode(reply.code), reply.reason));
3586
+ break;
3587
+ }
3588
+ while (socket.buffered > SEND_BUFFER2 && !reading.aborted) await quietly(10);
3589
+ socket.send(event.kind === "text" ? event.text : event.bytes);
3590
+ }
3591
+ } catch (e) {
3592
+ if (e instanceof WsError) {
3593
+ guestDone = true;
3594
+ socket.close(e.code, e.message);
3595
+ await toGuest(closeFrame(e.code, e.message)).catch(() => void 0);
3596
+ }
3597
+ } finally {
3598
+ guestDone = true;
3599
+ socket.close(1e3, "the client went away");
3600
+ stop.removeEventListener("abort", stopping);
3601
+ await Promise.race([outbound2, quietly(this.limits.closeWaitMs)]);
3602
+ }
3603
+ }
3087
3604
  };
3088
3605
 
3089
3606
  // src/kernel/net/x509.ts
@@ -3813,12 +4330,15 @@ var RemoteTransport = class {
3813
4330
  port;
3814
4331
  waiting = /* @__PURE__ */ new Map();
3815
4332
  nextId = 0;
4333
+ sockets = /* @__PURE__ */ new Map();
3816
4334
  failure;
3817
4335
  constructor(port, traits) {
3818
4336
  this.port = port;
3819
4337
  this.traits = traits;
3820
4338
  }
3821
4339
  receive(reply) {
4340
+ const socket = this.sockets.get(reply.nid);
4341
+ if (socket && this.toSocket(reply, socket)) return;
3822
4342
  const waiter = this.waiting.get(reply.nid);
3823
4343
  if (!waiter) return;
3824
4344
  this.waiting.delete(reply.nid);
@@ -3826,10 +4346,22 @@ var RemoteTransport = class {
3826
4346
  waiter.reject(new TransportError(reply.message, reply.status, reply.code));
3827
4347
  } else waiter.resolve(reply);
3828
4348
  }
4349
+ toSocket(reply, socket) {
4350
+ if (reply.net === "ws-message") socket.queue.push(reply.data);
4351
+ else if (reply.net === "ws-acked") socket.acked(reply.n);
4352
+ else if (reply.net === "ws-closed") {
4353
+ this.sockets.delete(reply.nid);
4354
+ socket.queue.end({ code: reply.code, reason: reply.reason });
4355
+ } else return false;
4356
+ return true;
4357
+ }
3829
4358
  fail(error) {
3830
4359
  this.failure = error;
3831
4360
  for (const waiter of this.waiting.values()) waiter.reject(error);
3832
4361
  this.waiting.clear();
4362
+ for (const socket of this.sockets.values())
4363
+ socket.queue.end({ code: 1011, reason: error.message });
4364
+ this.sockets.clear();
3833
4365
  }
3834
4366
  ask(call) {
3835
4367
  if (this.failure) return Promise.reject(this.failure);
@@ -3908,6 +4440,46 @@ var RemoteTransport = class {
3908
4440
  }
3909
4441
  };
3910
4442
  }
4443
+ async websocket(request2) {
4444
+ const nid = ++this.nextId;
4445
+ const { signal } = request2;
4446
+ signal.throwIfAborted();
4447
+ const abort = () => this.cancel(nid);
4448
+ signal.addEventListener("abort", abort, { once: true });
4449
+ let opened2;
4450
+ try {
4451
+ opened2 = await this.ask({
4452
+ net: "ws-open",
4453
+ nid,
4454
+ url: request2.url,
4455
+ protocols: request2.protocols,
4456
+ headers: request2.headers
4457
+ });
4458
+ } finally {
4459
+ signal.removeEventListener("abort", abort);
4460
+ }
4461
+ const close = (code, reason) => this.port.postMessage({ net: "ws-close", nid, code, reason });
4462
+ const queue = new MessageQueue(
4463
+ () => close(1e3, "a message is too big"),
4464
+ Number.POSITIVE_INFINITY,
4465
+ (n) => this.port.postMessage({ net: "ws-consumed", nid, n })
4466
+ );
4467
+ let unacked = 0;
4468
+ this.sockets.set(nid, { queue, acked: (n) => void (unacked -= n) });
4469
+ return {
4470
+ protocol: opened2.protocol,
4471
+ get buffered() {
4472
+ return unacked;
4473
+ },
4474
+ send: (data) => {
4475
+ unacked += payloadSize(data);
4476
+ this.port.postMessage({ net: "ws-send", nid, data });
4477
+ },
4478
+ messages: queue,
4479
+ close,
4480
+ closed: queue.closed
4481
+ };
4482
+ }
3911
4483
  };
3912
4484
 
3913
4485
  // src/kernel/net/routes.ts
@@ -4086,183 +4658,10 @@ var RemoteUplink = class {
4086
4658
  var CDP_PORT = 9222;
4087
4659
  var NO_CDP_HOST = "slicc-kernel: no CDP host is attached (createKernel({ cdp }) or client.serveCdp)";
4088
4660
 
4089
- // src/cdp/websocket.ts
4090
- var GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
4091
- var MAX_MESSAGE = 256 * 1024 * 1024;
4092
- var CLOSE = {
4093
- normal: 1e3,
4094
- protocol: 1002,
4095
- unsupported: 1003,
4096
- invalid: 1007,
4097
- tooBig: 1009,
4098
- error: 1011
4099
- };
4100
- var OP_TEXT = 1;
4101
- var OP = { continuation: 0, text: OP_TEXT, binary: 2, close: 8, ping: 9, pong: 10 };
4102
- var WsError = class extends Error {
4103
- code;
4104
- constructor(code, message2) {
4105
- super(message2);
4106
- this.code = code;
4107
- }
4108
- };
4109
- function field(headers, name2) {
4110
- return headers.find(([n]) => n.toLowerCase() === name2)?.[1];
4111
- }
4112
- async function acceptKey(headers) {
4113
- const tokens = (name2) => (field(headers, name2) ?? "").split(",").map((t) => t.trim().toLowerCase());
4114
- if (!tokens("upgrade").includes("websocket") || !tokens("connection").includes("upgrade")) {
4115
- throw new HttpError(400, "expected a WebSocket upgrade");
4116
- }
4117
- if (field(headers, "sec-websocket-version") !== "13") {
4118
- throw new HttpError(400, "Sec-WebSocket-Version must be 13");
4119
- }
4120
- const key = field(headers, "sec-websocket-key") ?? "";
4121
- if (!/^[A-Za-z0-9+/]{22}==$/.test(key)) throw new HttpError(400, "bad Sec-WebSocket-Key");
4122
- const digest = await crypto.subtle.digest("SHA-1", new TextEncoder().encode(key + GUID));
4123
- return btoa(String.fromCharCode(...new Uint8Array(digest)));
4124
- }
4125
- function isUpgrade(headers) {
4126
- return (field(headers, "upgrade") ?? "").toLowerCase().includes("websocket");
4127
- }
4128
- function frame(opcode, payload) {
4129
- const n = payload.length;
4130
- const size = n < 126 ? 2 : n < 65536 ? 4 : 10;
4131
- const out = new Uint8Array(size + n);
4132
- const view = new DataView(out.buffer);
4133
- out[0] = 128 | opcode;
4134
- if (n < 126) out[1] = n;
4135
- else if (n < 65536) {
4136
- out[1] = 126;
4137
- view.setUint16(2, n);
4138
- } else {
4139
- out[1] = 127;
4140
- view.setBigUint64(2, BigInt(n));
4141
- }
4142
- out.set(payload, size);
4143
- return out;
4144
- }
4145
- function closeFrame(code, reason = "") {
4146
- let bytes = new TextEncoder().encode(reason);
4147
- if (bytes.length > 123) bytes = bytes.subarray(0, 123);
4148
- const payload = new Uint8Array(2 + bytes.length);
4149
- new DataView(payload.buffer).setUint16(0, code);
4150
- payload.set(bytes, 2);
4151
- return frame(OP.close, payload);
4152
- }
4153
- function pongFrame(payload) {
4154
- return frame(OP.pong, payload);
4155
- }
4156
- async function fill(incoming, out, signal) {
4157
- for (let at = 0; at < out.length; ) {
4158
- const piece = await incoming.some(out.length - at, signal);
4159
- if (piece.length === 0) throw new WsError(CLOSE.protocol, "the connection closed mid-frame");
4160
- out.set(piece, at);
4161
- at += piece.length;
4162
- }
4163
- }
4164
- var fatal = new TextDecoder("utf-8", { fatal: true });
4165
- function decode(bytes) {
4166
- try {
4167
- return fatal.decode(bytes);
4168
- } catch {
4169
- throw new WsError(CLOSE.invalid, "a text message is not UTF-8");
4170
- }
4171
- }
4172
- var WsReader = class {
4173
- incoming;
4174
- max;
4175
- parts = [];
4176
- size = 0;
4177
- continuing = false;
4178
- constructor(incoming, max = MAX_MESSAGE) {
4179
- this.incoming = incoming;
4180
- this.max = max;
4181
- }
4182
- async next(signal) {
4183
- for (; ; ) {
4184
- const first = await this.incoming.some(1, signal);
4185
- if (first.length === 0) return null;
4186
- const head = new Uint8Array(2);
4187
- head[0] = first[0];
4188
- await fill(this.incoming, head.subarray(1), signal);
4189
- const fin = (head[0] & 128) !== 0;
4190
- const opcode = head[0] & 15;
4191
- if ((head[0] & 112) !== 0) throw new WsError(CLOSE.protocol, "reserved bits are set");
4192
- if ((head[1] & 128) === 0) throw new WsError(CLOSE.protocol, "client frames must be masked");
4193
- const length2 = await this.length(head[1] & 127, signal);
4194
- const control = opcode >= 8;
4195
- if (control && (length2 > 125 || !fin)) {
4196
- throw new WsError(CLOSE.protocol, "a control frame is too long or fragmented");
4197
- }
4198
- if (!control && this.size + length2 > this.max) {
4199
- throw new WsError(CLOSE.tooBig, `a message is over ${this.max} bytes`);
4200
- }
4201
- const mask = new Uint8Array(4);
4202
- await fill(this.incoming, mask, signal);
4203
- const payload = new Uint8Array(length2);
4204
- await fill(this.incoming, payload, signal);
4205
- for (let i = 0; i < length2; i++) payload[i] ^= mask[i & 3];
4206
- const event = this.take(opcode, fin, payload);
4207
- if (event) return event;
4208
- }
4209
- }
4210
- async length(short, signal) {
4211
- if (short < 126) return short;
4212
- const ext = new Uint8Array(short === 126 ? 2 : 8);
4213
- await fill(this.incoming, ext, signal);
4214
- const view = new DataView(ext.buffer);
4215
- if (short === 126) return view.getUint16(0);
4216
- const long = view.getBigUint64(0);
4217
- return long > BigInt(this.max) ? this.max + 1 : Number(long);
4218
- }
4219
- take(opcode, fin, payload) {
4220
- switch (opcode) {
4221
- case OP.ping:
4222
- return { kind: "ping", payload };
4223
- case OP.pong:
4224
- return void 0;
4225
- case OP.close: {
4226
- if (payload.length === 1) throw new WsError(CLOSE.protocol, "a close frame is malformed");
4227
- const code = payload.length >= 2 ? new DataView(payload.buffer).getUint16(0) : 1005;
4228
- return { kind: "close", code, reason: decode(payload.subarray(2)) };
4229
- }
4230
- case OP.text:
4231
- case OP.continuation: {
4232
- if (opcode === OP.continuation !== this.continuing) {
4233
- throw new WsError(CLOSE.protocol, "unexpected continuation frame");
4234
- }
4235
- this.parts.push(payload);
4236
- this.size += payload.length;
4237
- this.continuing = !fin;
4238
- if (!fin) return void 0;
4239
- const whole = this.parts.length === 1 ? payload : concat(this.parts, this.size);
4240
- this.parts = [];
4241
- this.size = 0;
4242
- return { kind: "text", text: decode(whole) };
4243
- }
4244
- case OP.binary:
4245
- throw new WsError(CLOSE.unsupported, "CDP messages are text");
4246
- default:
4247
- throw new WsError(CLOSE.protocol, `unknown opcode ${opcode}`);
4248
- }
4249
- }
4250
- };
4251
- function switchingHead(accept2) {
4252
- return latin1Bytes(
4253
- `HTTP/1.1 101 Switching Protocols\r
4254
- Upgrade: websocket\r
4255
- Connection: Upgrade\r
4256
- Sec-WebSocket-Accept: ${accept2}\r
4257
- \r
4258
- `
4259
- );
4260
- }
4261
-
4262
4661
  // src/cdp/facade.ts
4263
4662
  var MAX_HEAD = 64 * 1024;
4264
4663
  var LIST_TIMEOUT = 1e4;
4265
- var CLOSE_WAIT_MS = 1e3;
4664
+ var CLOSE_WAIT_MS2 = 1e3;
4266
4665
  function respond(status, body, type = "text/plain; charset=utf-8") {
4267
4666
  const bytes = new TextEncoder().encode(body);
4268
4667
  const head = latin1Bytes(
@@ -4410,7 +4809,7 @@ var CdpFacade = class {
4410
4809
  const host = await this.host(runtime);
4411
4810
  const limits = {
4412
4811
  max: this.options.maxMessage ?? MAX_MESSAGE,
4413
- closeWaitMs: this.options.closeWaitMs ?? CLOSE_WAIT_MS
4812
+ closeWaitMs: this.options.closeWaitMs ?? CLOSE_WAIT_MS2
4414
4813
  };
4415
4814
  await new Relay(conn, incoming, host, limits, this.stop.signal).start(switchingHead(accept2)).finally(() => host.close());
4416
4815
  }
@@ -9060,7 +9459,42 @@ var Dying = class {
9060
9459
  return [typeof reported === "number" ? reported : CRASHED, void 0];
9061
9460
  }
9062
9461
  };
9063
- function processInit(opts, sab, umask) {
9462
+ function notifiers(header2) {
9463
+ return {
9464
+ onPending(sig) {
9465
+ Atomics.or(header2, SAB_I_SIGNALS, sigbit(sig));
9466
+ Atomics.notify(header2, SAB_I_SIGNALS);
9467
+ },
9468
+ onAsync() {
9469
+ Atomics.add(header2, SAB_I_ASYNC, 1);
9470
+ Atomics.notify(header2, SAB_I_ASYNC);
9471
+ }
9472
+ };
9473
+ }
9474
+ function publishStops(process, header2) {
9475
+ process.onState((state) => {
9476
+ Atomics.store(header2, SAB_I_STOP, state === "stopped" ? 1 : 0);
9477
+ Atomics.notify(header2, SAB_I_STOP);
9478
+ });
9479
+ }
9480
+ function transferOf(opts, lane) {
9481
+ const transfer = opts.fork ? [opts.fork.memory.buffer] : [];
9482
+ return lane ? [...transfer, lane.port] : transfer;
9483
+ }
9484
+ function openLane(token, dispatch2) {
9485
+ const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
9486
+ const { port1, port2 } = new MessageChannel();
9487
+ const responder = attachSyncSabResponder(port1, sab, token, { dispatch: dispatch2 });
9488
+ port1.start();
9489
+ return {
9490
+ lane: { sab, port: port2 },
9491
+ dispose() {
9492
+ responder.dispose();
9493
+ port1.close();
9494
+ }
9495
+ };
9496
+ }
9497
+ function processInit(opts, sab, umask, lane) {
9064
9498
  const base = {
9065
9499
  type: WASM_PROCESS_INIT,
9066
9500
  pid: opts.shownPid ?? opts.pid,
@@ -9073,7 +9507,12 @@ function processInit(opts, sab, umask) {
9073
9507
  ...opts.ppid !== void 0 ? { ppid: opts.ppid } : {}
9074
9508
  };
9075
9509
  if (opts.program.abi === "js") {
9076
- return { ...base, program: opts.program, fds: inheritedFds(opts.fds) };
9510
+ return {
9511
+ ...base,
9512
+ program: opts.program,
9513
+ fds: inheritedFds(opts.fds),
9514
+ lane
9515
+ };
9077
9516
  }
9078
9517
  return {
9079
9518
  ...base,
@@ -9125,23 +9564,13 @@ function spawnWasmProcess(opts) {
9125
9564
  locks: opts.locks,
9126
9565
  onReap: opts.onReap,
9127
9566
  resolver: opts.resolver,
9128
- onPending: (sig) => {
9129
- Atomics.or(header2, SAB_I_SIGNALS, sigbit(sig));
9130
- Atomics.notify(header2, SAB_I_SIGNALS);
9131
- },
9132
- onAsync: () => {
9133
- Atomics.add(header2, SAB_I_ASYNC, 1);
9134
- Atomics.notify(header2, SAB_I_ASYNC);
9135
- },
9567
+ ...notifiers(header2),
9136
9568
  onTimer: (which) => void Atomics.or(header2, SAB_I_TIMERS, 1 << which),
9137
9569
  hasPending: () => Atomics.load(header2, SAB_I_SIGNALS) !== 0 || Atomics.load(header2, SAB_I_TIMERS) !== 0,
9138
9570
  raise: (sig) => signal(sig),
9139
9571
  ...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header2, SAB_I_SIGNALS) } : {}
9140
9572
  });
9141
- process.onState((state) => {
9142
- Atomics.store(header2, SAB_I_STOP, state === "stopped" ? 1 : 0);
9143
- Atomics.notify(header2, SAB_I_STOP);
9144
- });
9573
+ publishStops(process, header2);
9145
9574
  const holds = new HeldPaths();
9146
9575
  opts.held?.add(holds);
9147
9576
  const token = holdingToken(opts, holds);
@@ -9150,6 +9579,7 @@ function spawnWasmProcess(opts) {
9150
9579
  const dying = new Dying();
9151
9580
  const dispatch2 = (req) => dying.serving(() => isWasmSyscall(req) ? process.syscall(req) : dispatchSyncFs(req));
9152
9581
  const responder = attachSyncSabResponder(worker, sab, token, { dispatch: dispatch2 });
9582
+ const lane = opts.program.abi === "js" ? openLane(token, dispatch2) : void 0;
9153
9583
  const { promise: exited, resolve: settle3 } = Promise.withResolvers();
9154
9584
  let done4 = false;
9155
9585
  let endedBy;
@@ -9162,6 +9592,7 @@ function spawnWasmProcess(opts) {
9162
9592
  worker.removeEventListener("error", onError);
9163
9593
  for (const tid of [...threads.keys()]) endThread(tid);
9164
9594
  responder.dispose();
9595
+ lane?.dispose();
9165
9596
  revokeSyncFsToken(token);
9166
9597
  opts.held?.delete(holds);
9167
9598
  worker.terminate();
@@ -9232,8 +9663,10 @@ function spawnWasmProcess(opts) {
9232
9663
  };
9233
9664
  tw.postMessage(tinit);
9234
9665
  };
9235
- const init = processInit(opts, sab, process.umask);
9236
- worker.postMessage(init, opts.fork ? [opts.fork.memory.buffer] : []);
9666
+ worker.postMessage(
9667
+ processInit(opts, sab, process.umask, lane?.lane),
9668
+ transferOf(opts, lane?.lane)
9669
+ );
9237
9670
  const signal = (sig) => {
9238
9671
  if (process.signal(sig) !== "terminate") return;
9239
9672
  const code = sig === SIG.KILL ? 137 : 128 + sig;