@statewalker/cellb 0.2.0 → 0.4.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 +7 -5
- package/dist/bucket/celld-cells.js +25 -3
- package/dist/bucket/celld-cells.js.map +1 -1
- package/dist/isolate/host.d.ts +1 -1
- package/dist/isolate/host.js +17 -6
- package/dist/isolate/host.js.map +1 -1
- package/dist/isolate/isolate.js +8 -0
- package/dist/isolate/isolate.js.map +1 -1
- package/dist/isolate/protocol.d.ts +3 -2
- package/dist/isolate/protocol.js +47 -51
- package/dist/isolate/protocol.js.map +1 -1
- package/dist/peer/celld-peer.d.ts +17 -0
- package/dist/peer/celld-peer.js +49 -7
- package/dist/peer/celld-peer.js.map +1 -1
- package/dist/project/browser-shards.d.ts +8 -9
- package/dist/project/browser-shards.js +88 -52
- package/dist/project/browser-shards.js.map +1 -1
- package/dist/project/browser-tabs.d.ts +14 -4
- package/dist/project/browser-tabs.js +193 -208
- package/dist/project/browser-tabs.js.map +1 -1
- package/dist/project/wrangler.js +1 -1
- package/dist/project/wrangler.js.map +1 -1
- package/dist/transport/cells-http.d.ts +6 -0
- package/dist/transport/cells-http.js +22 -1
- package/dist/transport/cells-http.js.map +1 -1
- package/dist/transport/cells-link.d.ts +2 -0
- package/dist/transport/cells-link.js +5 -0
- package/dist/transport/cells-link.js.map +1 -1
- package/dist/transport/port.d.ts +3 -4
- package/dist/transport/port.js +25 -79
- package/dist/transport/port.js.map +1 -1
- package/dist/ws/client.d.ts +23 -8
- package/dist/ws/client.js +50 -189
- package/dist/ws/client.js.map +1 -1
- package/dist/ws/frames.d.ts +17 -8
- package/dist/ws/frames.js +3 -7
- package/dist/ws/frames.js.map +1 -1
- package/dist/ws/server.d.ts +17 -19
- package/dist/ws/server.js +53 -121
- package/dist/ws/server.js.map +1 -1
- package/package.json +5 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"celld-peer.js","sourceRoot":"","sources":["../../src/peer/celld-peer.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, createHmac, randomBytes, timingSafeEqual } from \"node:crypto\";\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport type { Duplex } from \"node:stream\";\nimport type { ObjectStore } from \"../bucket/object-store.js\";\nimport { toAnotherNode } from \"../core/handles.js\";\nimport type { CellRuntime } from \"../core/runtime.js\";\nimport { deserialize, serialize } from \"../v8/serialize.js\";\nimport { createWebSocketClass } from \"../ws/client.js\";\nimport { CellsResponse, type CfWebSocket, takeClientPort, WebSocketPair } from \"../ws/server.js\";\nimport { withUpgrade } from \"../ws/upgrade.js\";\n\n/**\n * celld's peer protocol (peer_auth.rs, main/peer_tunnel.rs, protocol 5) for a cellb node\n * hosted in Node, so celld nodes can route a cell's requests to it when it owns the cell.\n *\n * Authentication: every peer request carries an HMAC-SHA-256 over\n * \"cells-peer-request-v1\\n5\\n<method>\\n<path?query>\\n<sha256(body)>\\n<source>\\n<target>\\n<ts>\\n<nonce>\"\n * keyed by the fleet secret in `fleet/peer-auth.json`, with headers x-cells-peer-{version,\n * source,target,timestamp,nonce,body-sha256,signature}; ±30 s clock window, nonce replay cache,\n * and the target must be this node.\n *\n * Tunnel: `GET /peer/tunnel` with `Upgrade: celld-tunnel` (kind `do` or `rpc`) is answered with\n * 101; then the connection carries plain HTTP/1.1 requests, one call each, with control headers\n * x-cells-scope (the cell, \"<Class>:<idhex>\"), x-cells-do-name, x-cells-request-id:\n * do — the application request as is; the reply streams back.\n * rpc — POST, method in x-cells-rpc-method, arguments V8-serialized (an array) or JSON; the\n * reply is the V8-serialized result, or a tagged error (0, then [error, props]).\n * A cell this node does not own answers 409 with `x-cells-route-error: stale-owner`, so celld\n * re-resolves the owner.\n */\nconst PROTOCOL = \"5\";\nconst DOMAIN = \"cells-peer-request-v1\";\nconst CLOCK_WINDOW_MS = 30_000;\nconst PEER_HEADERS = {\n version: \"x-cells-peer-version\",\n source: \"x-cells-peer-source\",\n target: \"x-cells-peer-target\",\n timestamp: \"x-cells-peer-timestamp\",\n nonce: \"x-cells-peer-nonce\",\n bodySha: \"x-cells-peer-body-sha256\",\n signature: \"x-cells-peer-signature\",\n} as const;\nconst CONTROL = [\n \"x-cells-scope\",\n \"x-cells-do-name\",\n \"x-cells-request-id\",\n \"x-cells-capacity-handoff\",\n];\n\n/** The fleet's peer secret (celld creates it in the bucket). */\nexport async function loadPeerKey(store: ObjectStore): Promise<Uint8Array> {\n const o = await store.get(\"fleet/peer-auth.json\");\n if (!o) throw new Error(\"the fleet has no peer authentication secret; start a celld node first\");\n const { version, key } = JSON.parse(new TextDecoder().decode(o.body)) as {\n version: number;\n key: string;\n };\n if (version !== 1 || !/^[0-9a-f]{64}$/.test(key))\n throw new Error(\"unexpected fleet/peer-auth.json\");\n return Uint8Array.from(Buffer.from(key, \"hex\"));\n}\n\nconst sha256hex = (b: Uint8Array) => createHash(\"sha256\").update(b).digest(\"hex\");\nconst mac = (\n key: Uint8Array,\n c: {\n method: string;\n path: string;\n bodySha: string;\n source: string;\n target: string;\n ts: string;\n nonce: string;\n },\n) =>\n createHmac(\"sha256\", key)\n .update(\n `${DOMAIN}\\n${PROTOCOL}\\n${c.method}\\n${c.path}\\n${c.bodySha}\\n${c.source}\\n${c.target}\\n${c.ts}\\n${c.nonce}`,\n )\n .digest();\n\n/** Headers that sign one peer request from `source` to `target`. */\nexport function signPeerRequest(\n key: Uint8Array,\n source: string,\n target: string,\n method: string,\n pathAndQuery: string,\n body: Uint8Array = new Uint8Array(),\n) {\n const ts = String(Date.now());\n const nonce = randomBytes(16).toString(\"hex\");\n const bodySha = sha256hex(body);\n const signature = mac(key, {\n method,\n path: pathAndQuery,\n bodySha,\n source,\n target,\n ts,\n nonce,\n }).toString(\"hex\");\n return {\n [PEER_HEADERS.version]: PROTOCOL,\n [PEER_HEADERS.source]: source,\n [PEER_HEADERS.target]: target,\n [PEER_HEADERS.timestamp]: ts,\n [PEER_HEADERS.nonce]: nonce,\n [PEER_HEADERS.bodySha]: bodySha,\n [PEER_HEADERS.signature]: signature,\n };\n}\n\n/** celld's verification; returns a status and message on failure. */\nexport function verifyPeerRequest(\n key: Uint8Array,\n self: string,\n method: string,\n pathAndQuery: string,\n headers: Record<string, string | string[] | undefined>,\n body: Uint8Array,\n seen: Map<string, number>,\n): { status: number; message: string; stale?: boolean } | undefined {\n const h = (n: string) => (typeof headers[n] === \"string\" ? (headers[n] as string) : undefined);\n const version = h(PEER_HEADERS.version);\n if (version === undefined) return { status: 401, message: \"peer authentication failed\" };\n if (version !== PROTOCOL)\n return { status: 426, message: \"peer protocol version is incompatible\" };\n const [source, target, ts, nonce, bodySha, signature] = [\n PEER_HEADERS.source,\n PEER_HEADERS.target,\n PEER_HEADERS.timestamp,\n PEER_HEADERS.nonce,\n PEER_HEADERS.bodySha,\n PEER_HEADERS.signature,\n ].map(h);\n if (!source || !target || !ts || !nonce || !bodySha || !signature)\n return { status: 401, message: \"peer authentication failed\" };\n const now = Date.now();\n if (!/^\\d+$/.test(ts) || Math.abs(now - Number(ts)) > CLOCK_WINDOW_MS)\n return { status: 401, message: \"peer authentication failed\" };\n if (\n sha256hex(body) !== bodySha ||\n !/^[0-9a-f]{32}$/.test(nonce) ||\n !/^[0-9a-f]{64}$/.test(signature)\n )\n return { status: 401, message: \"peer authentication failed\" };\n const expected = mac(key, { method, path: pathAndQuery, bodySha, source, target, ts, nonce });\n if (!timingSafeEqual(expected, Buffer.from(signature, \"hex\")))\n return { status: 401, message: \"peer authentication failed\" };\n if (target !== self)\n return { status: 409, message: \"peer request targets a different node session\", stale: true };\n for (const [n, t] of seen) if (now - t > 2 * CLOCK_WINDOW_MS) seen.delete(n);\n if (seen.has(nonce)) return { status: 409, message: \"peer request replay rejected\" };\n seen.set(nonce, now);\n return undefined;\n}\n\nconst readBody = async (req: IncomingMessage) => {\n const chunks: Buffer[] = [];\n for await (const c of req) chunks.push(c as Buffer);\n return new Uint8Array(Buffer.concat(chunks));\n};\n\n/** The cell a scope names, as a stub of this runtime (undefined: not a class we host). */\nfunction stubFor(runtime: CellRuntime, scope: string, name: string | undefined): any {\n const m = /^([^:]+):([0-9a-f]{64})$/.exec(scope);\n if (!m) return undefined;\n const binding = Object.entries(runtime.durableObjectBindings).find(\n ([, cls]) => cls === m[1],\n )?.[0];\n if (!binding) return undefined;\n const ns = runtime.env[binding] as any;\n return name !== undefined ? ns.getByName(name) : ns.get(ns.idFromString(m[2]));\n}\n\nconst notOwner = (e: unknown) =>\n /owned by another|OwnedElsewhere|lease/i.test(String((e as Error)?.message ?? e)) ||\n (e as Error)?.name === \"CellOwnedElsewhereError\";\n\nfunction reply(\n res: ServerResponse,\n status: number,\n headers: Record<string, string>,\n body?: Uint8Array | string,\n) {\n res.writeHead(status, { [PEER_HEADERS.version]: PROTOCOL, ...headers });\n res.end(body);\n}\nconst stale = (res: ServerResponse) =>\n reply(\n res,\n 409,\n { \"x-cells-route-error\": \"stale-owner\", \"content-type\": \"text/plain\" },\n \"stale route\",\n );\n\nexport interface CelldPeerServer {\n /** host:port celld dials (put it in the node record: celldBucket({ addr })). */\n addr: string;\n close(): Promise<void>;\n}\n\n/**\n * Serves celld's peer tunnel for `runtime` on `host:port` (0: any free port). `node` is this\n * node's name in the fleet (the same as celldBucket's `node`).\n */\nexport async function startCelldPeerServer(opts: {\n runtime: CellRuntime;\n store: ObjectStore;\n node: string;\n host?: string;\n port?: number;\n /** Answers celld's signed probe (celldBucket(...).probe): `celld diagnose --peer` reaches us. */\n probe?: (challenge: string) => Promise<unknown>;\n}): Promise<CelldPeerServer> {\n const key = await loadPeerKey(opts.store);\n const seen = new Map<string, number>();\n const host = opts.host ?? \"127.0.0.1\";\n\n const serveDo = async (req: IncomingMessage, res: ServerResponse) => {\n const scope = String(req.headers[\"x-cells-scope\"] ?? \"\");\n const name = req.headers[\"x-cells-do-name\"] as string | undefined;\n const stub = stubFor(opts.runtime, scope, name);\n if (!stub) return reply(res, 400, {}, \"malformed cell scope\");\n const headers = new Headers();\n for (const [k, v] of Object.entries(req.headers))\n if (typeof v === \"string\" && !CONTROL.includes(k)) headers.set(k, v);\n const method = req.method ?? \"GET\";\n const body = method === \"GET\" || method === \"HEAD\" ? undefined : await readBody(req);\n const url = /^https?:\\/\\//.test(req.url ?? \"\")\n ? (req.url as string)\n : `http://${req.headers.host ?? \"cell\"}${req.url ?? \"/\"}`;\n try {\n const r: Response = await stub.fetch(new Request(url, { method, headers, body }));\n const out: Record<string, string> = {};\n r.headers.forEach((v, k) => {\n if (k !== \"content-length\" && k !== \"transfer-encoding\" && k !== \"connection\") out[k] = v;\n });\n reply(res, r.status, out, new Uint8Array(await r.arrayBuffer()));\n } catch (e) {\n if (notOwner(e)) return stale(res);\n reply(res, 500, { \"content-type\": \"text/plain\" }, String((e as Error)?.message ?? e));\n }\n };\n\n const serveRpc = async (req: IncomingMessage, res: ServerResponse) => {\n const scope = String(req.headers[\"x-cells-scope\"] ?? \"\");\n const stub = stubFor(opts.runtime, scope, req.headers[\"x-cells-do-name\"] as string | undefined);\n const method = req.headers[\"x-cells-rpc-method\"] as string | undefined;\n if (!stub) return reply(res, 400, {}, \"malformed cell scope\");\n if (!method) return reply(res, 400, {}, \"RPC method header is missing\");\n const raw = await readBody(req);\n const structured = req.headers[\"content-type\"] === \"application/octet-stream\";\n let args: unknown[];\n if (structured) {\n if (raw[0] !== 0xff) return reply(res, 501, {}, \"RPC stubs cannot cross to cellb\");\n args = deserialize(raw) as unknown[];\n } else args = JSON.parse(new TextDecoder().decode(raw)) as unknown[];\n try {\n const result = await stub[method](...(Array.isArray(args) ? args : [args]));\n if (structured)\n reply(\n res,\n 200,\n { \"content-type\": \"application/octet-stream\" },\n serialize(toAnotherNode(result)),\n );\n else reply(res, 200, { \"content-type\": \"application/json\" }, JSON.stringify(result ?? null));\n } catch (e) {\n if (notOwner(e)) return stale(res);\n if (!structured)\n return reply(\n res,\n 500,\n { \"content-type\": \"text/plain\" },\n `RPC failed: ${String((e as Error)?.message ?? e)}`,\n );\n // celld's callee exception: tag 0, then [error, own properties incl. name]\n const err = e instanceof Error ? e : new Error(String(e));\n const props = e instanceof Error ? { ...e, name: e.name } : { name: \"Error\" };\n const sc = serialize([err, props]);\n const tagged = new Uint8Array(sc.length + 1);\n tagged.set(sc, 1);\n reply(res, 200, { \"content-type\": \"application/octet-stream\" }, tagged);\n }\n };\n\n // One inner HTTP/1.1 server per tunnel kind: an upgraded socket becomes its connection.\n // celld's inner RPC requests carry no Host header: Node would answer 400 by default.\n const inner = {\n do: createServer({ requireHostHeader: false }, (q, s) => void serveDo(q, s)),\n rpc: createServer({ requireHostHeader: false }, (q, s) => void serveRpc(q, s)),\n };\n for (const s of Object.values(inner)) s.keepAliveTimeout = 0;\n // A tunneled WebSocket (celld: the client's own handshake crosses the tunnel and the owner\n // answers it): the cell's 101 + webSocket is bridged to the raw connection, framed by `ws`.\n const { WebSocketServer } = await import(\"ws\");\n const wss = new WebSocketServer({ noServer: true });\n inner.do.on(\"upgrade\", async (req: IncomingMessage, socket: Duplex, head: Buffer) => {\n const fail = (status: number, body: string, extra: Record<string, string> = {}) => {\n const lines = [\n `HTTP/1.1 ${status} ${status === 409 ? \"Conflict\" : \"Error\"}`,\n `${PEER_HEADERS.version}: ${PROTOCOL}`,\n `content-length: ${Buffer.byteLength(body)}`,\n \"connection: close\",\n ];\n for (const [k, v] of Object.entries(extra)) lines.push(`${k}: ${v}`);\n socket.end(`${lines.join(\"\\r\\n\")}\\r\\n\\r\\n${body}`);\n };\n const stub = stubFor(\n opts.runtime,\n String(req.headers[\"x-cells-scope\"] ?? \"\"),\n req.headers[\"x-cells-do-name\"] as string | undefined,\n );\n if (!stub) return fail(400, \"malformed cell scope\");\n const headers = new Headers();\n for (const [k, v] of Object.entries(req.headers))\n if (typeof v === \"string\" && !CONTROL.includes(k)) headers.set(k, v);\n const url = /^https?:\\/\\//.test(req.url ?? \"\")\n ? (req.url as string)\n : `http://${req.headers.host ?? \"cell\"}${req.url ?? \"/\"}`;\n const protocols = req.headers[\"sec-websocket-protocol\"] as string | undefined;\n let res: Response & { webSocket?: CfWebSocket | null };\n try {\n res = await stub.fetch(\n withUpgrade(\n new Request(url, { headers }),\n \"websocket\",\n protocols ? { \"Sec-WebSocket-Protocol\": protocols } : undefined,\n ),\n );\n } catch (e) {\n return notOwner(e)\n ? fail(409, \"stale route\", { \"x-cells-route-error\": \"stale-owner\" })\n : fail(500, String((e as Error)?.message ?? e));\n }\n if (res.status !== 101 || !res.webSocket) return fail(res.status, await res.text());\n const port = takeClientPort(res.webSocket);\n const WS = createWebSocketClass(async () => ({\n port,\n protocol: res.headers.get(\"Sec-WebSocket-Protocol\") ?? undefined,\n }));\n const cell = new WS(\"ws://cell/\") as WebSocket;\n cell.binaryType = \"arraybuffer\";\n const pending: (string | ArrayBuffer)[] = [];\n let open = false;\n wss.handleUpgrade(req, socket, head, (client) => {\n cell.onopen = () => {\n open = true;\n for (const m of pending.splice(0)) cell.send(m);\n };\n client.on(\"message\", (data: Buffer, isBinary: boolean) => {\n const m = isBinary ? (new Uint8Array(data).buffer as ArrayBuffer) : data.toString();\n if (open) cell.send(m);\n else pending.push(m);\n });\n cell.onmessage = (ev: MessageEvent) =>\n client.send(ev.data instanceof ArrayBuffer ? Buffer.from(ev.data) : ev.data);\n client.on(\"close\", (code: number, reason: Buffer) =>\n cell.close(\n code >= 1000 && code < 5000 && code !== 1005 && code !== 1006 ? code : 1000,\n reason.toString(),\n ),\n );\n cell.onclose = (ev: CloseEvent) =>\n client.close(\n ev.code >= 1000 && ev.code !== 1005 && ev.code !== 1006 ? ev.code : 1000,\n ev.reason,\n );\n });\n });\n\n const server: Server = createServer(async (req, res) => {\n if (req.url === \"/peer/probe\" && req.method === \"GET\" && opts.probe) {\n const denied = verifyPeerRequest(\n key,\n opts.node,\n \"GET\",\n \"/peer/probe\",\n req.headers,\n new Uint8Array(),\n seen,\n );\n if (denied)\n return reply(res, denied.status, { \"content-type\": \"text/plain\" }, denied.message);\n try {\n const answer = await opts.probe(String(req.headers[\"x-cells-probe-challenge\"] ?? \"\"));\n return reply(res, 200, { \"content-type\": \"application/json\" }, JSON.stringify(answer));\n } catch (e) {\n return reply(\n res,\n 400,\n { \"content-type\": \"text/plain\" },\n String((e as Error)?.message ?? e),\n );\n }\n }\n reply(res, 404, {}, \"not found\");\n });\n server.on(\"upgrade\", (req: IncomingMessage, socket: Duplex, head: Buffer) => {\n const path = req.url ?? \"/\";\n const refuse = (status: number, message: string, extra: Record<string, string> = {}) => {\n const lines = [\n `HTTP/1.1 ${status} ${message}`,\n `${PEER_HEADERS.version}: ${PROTOCOL}`,\n \"connection: close\",\n \"content-length: 0\",\n ];\n for (const [k, v] of Object.entries(extra)) lines.push(`${k}: ${v}`);\n socket.end(`${lines.join(\"\\r\\n\")}\\r\\n\\r\\n`);\n };\n if (path !== \"/peer/tunnel\" || req.headers.upgrade !== \"celld-tunnel\")\n return refuse(404, \"Not Found\");\n const denied = verifyPeerRequest(\n key,\n opts.node,\n req.method ?? \"GET\",\n path,\n req.headers,\n new Uint8Array(),\n seen,\n );\n if (denied)\n return refuse(\n denied.status,\n denied.message,\n denied.stale ? { \"x-cells-route-error\": \"stale-owner\" } : {},\n );\n if (req.headers[\"x-cells-tunnel-version\"] !== \"5\") return refuse(426, \"Upgrade Required\");\n const kind = req.headers[\"x-cells-tunnel-kind\"];\n if (kind !== \"do\" && kind !== \"rpc\") return refuse(400, \"Bad Request\");\n socket.write(\n [\n \"HTTP/1.1 101 Switching Protocols\",\n \"upgrade: celld-tunnel\",\n \"connection: upgrade\",\n \"x-cells-tunnel-version: 5\",\n `${PEER_HEADERS.version}: ${PROTOCOL}`,\n ].join(\"\\r\\n\") + \"\\r\\n\\r\\n\",\n );\n if (head?.length) socket.unshift(head);\n inner[kind].emit(\"connection\", socket);\n });\n await new Promise<void>((r) => server.listen(opts.port ?? 0, host, () => r()));\n const port = (server.address() as { port: number }).port;\n return {\n addr: `${host}:${port}`,\n close: () =>\n new Promise<void>((r) => {\n server.closeAllConnections?.();\n for (const s of Object.values(inner)) s.closeAllConnections?.();\n server.close(() => r());\n }),\n };\n}\n\n/**\n * The calling half (celld's node A): open a signed tunnel to the owner node and send one call\n * through it — `fetch` on a `do` tunnel, JS RPC on an `rpc` tunnel (V8-serialized arguments;\n * the reply decoded as celld encodes it, a callee exception rethrown with its properties).\n */\n/** A signed `celld-tunnel` upgrade to the owner node: the raw connection after its 101. */\nasync function openTunnel(\n key: Uint8Array,\n source: string,\n owner: { node: string; addr: string },\n kind: \"do\" | \"rpc\",\n): Promise<import(\"node:net\").Socket> {\n const { request } = await import(\"node:http\");\n const [host, port] = [\n owner.addr.slice(0, owner.addr.lastIndexOf(\":\")),\n Number(owner.addr.slice(owner.addr.lastIndexOf(\":\") + 1)),\n ];\n const socket = await new Promise<import(\"node:net\").Socket>((resolve, reject) => {\n const req = request({\n host,\n port,\n path: \"/peer/tunnel\",\n method: \"GET\",\n headers: {\n upgrade: \"celld-tunnel\",\n connection: \"upgrade\",\n \"x-cells-tunnel-version\": \"5\",\n \"x-cells-tunnel-kind\": kind,\n ...signPeerRequest(key, source, owner.node, \"GET\", \"/peer/tunnel\"),\n },\n });\n req.on(\"upgrade\", (_res, sock) => resolve(sock as import(\"node:net\").Socket));\n req.on(\"response\", (res) =>\n reject(\n Object.assign(new Error(`peer tunnel refused: ${res.statusCode}`), {\n stale: res.headers[\"x-cells-route-error\"] === \"stale-owner\",\n }),\n ),\n );\n req.on(\"error\", reject);\n req.end();\n });\n return socket;\n}\n\nasync function tunnelCall(\n key: Uint8Array,\n source: string,\n owner: { node: string; addr: string },\n kind: \"do\" | \"rpc\",\n inner: { method: string; path: string; headers: Record<string, string>; body?: Uint8Array },\n): Promise<{ status: number; headers: Record<string, string>; body: Uint8Array }> {\n const { request } = await import(\"node:http\");\n const socket = await openTunnel(key, source, owner, kind);\n try {\n return await new Promise((resolve, reject) => {\n const req = request(\n // no agent: the request runs on the upgraded socket itself\n {\n createConnection: () => socket,\n method: inner.method,\n path: inner.path,\n headers: inner.headers,\n },\n async (res) => {\n const chunks: Buffer[] = [];\n for await (const c of res) chunks.push(c as Buffer);\n const headers: Record<string, string> = {};\n for (const [k, v] of Object.entries(res.headers))\n if (typeof v === \"string\") headers[k] = v;\n resolve({\n status: res.statusCode ?? 500,\n headers,\n body: new Uint8Array(Buffer.concat(chunks)),\n });\n },\n );\n req.on(\"error\", reject);\n req.end(inner.body);\n });\n } finally {\n socket.destroy();\n }\n}\n\n/**\n * Routing to cells celld nodes own, for CellRuntimeOptions.peers: `ownerOf` reads the cell's\n * own.json, `endpoint` reaches the owner's address from its node record through the tunnel.\n */\nexport function celldPeers(opts: { store: ObjectStore; node: string }) {\n let key: Promise<Uint8Array> | undefined;\n const json = async <T>(k: string) => {\n const o = await opts.store.get(k);\n return o ? (JSON.parse(new TextDecoder().decode(o.body)) as T) : undefined;\n };\n const staleError = (cellKey: string) =>\n Object.assign(new Error(`${cellKey} is owned by another node`), {\n name: \"CellOwnedElsewhereError\",\n });\n return {\n async ownerOf(cellKey: string) {\n const own = await json<{ node: string }>(`cells/${cellKey.replace(\"/\", \":\")}/own.json`);\n return own?.node && own.node !== opts.node ? own.node : undefined;\n },\n link(): never {\n throw new Error(\"celld owners are reached through endpoint()\");\n },\n async endpoint(owner: string, cellKey: string, name: string | undefined) {\n const lease = await json<{ addr: string; expires_ms: number }>(`nodes/${owner}.json`);\n if (!lease?.addr || lease.expires_ms <= Date.now()) return undefined;\n key ??= loadPeerKey(opts.store);\n const k = await key;\n const target = { node: owner, addr: lease.addr };\n const scope = cellKey.replace(\"/\", \":\");\n const control = (h: Record<string, string>) => ({\n ...h,\n \"x-cells-scope\": scope,\n ...(name !== undefined ? { \"x-cells-do-name\": name } : {}),\n });\n // A WebSocket to a cell celld owns: the client handshake crosses a `do` tunnel and `ws`\n // speaks the frames on it; the caller gets a 101 with a WebSocketPair end bridged to it.\n const tunnelWebSocket = async (req: Request, url: URL) => {\n const socket = await openTunnel(k, opts.node, target, \"do\");\n const { WebSocket: WsClient } = await import(\"ws\");\n const protocols = req.headers\n .get(\"sec-websocket-protocol\")\n ?.split(\",\")\n .map((p) => p.trim())\n .filter(Boolean);\n const remote = new WsClient(`ws://${url.host}${url.pathname}${url.search}`, protocols, {\n createConnection: () => socket,\n headers: control({}),\n });\n await new Promise<void>((resolve, reject) => {\n remote.once(\"open\", () => resolve());\n remote.once(\n \"unexpected-response\",\n (_q: unknown, res: { statusCode?: number; headers: Record<string, unknown> }) =>\n reject(\n res.headers[\"x-cells-route-error\"] === \"stale-owner\"\n ? staleError(cellKey)\n : new Error(`WebSocket through the tunnel refused: ${res.statusCode}`),\n ),\n );\n remote.once(\"error\", reject);\n });\n const pair = new WebSocketPair();\n const [client, server] = [pair[0], pair[1]];\n server.accept();\n server.addEventListener(\"message\", (e) => remote.send((e as MessageEvent).data));\n remote.on(\"message\", (d: Buffer, isBinary: boolean) =>\n server.send(isBinary ? new Uint8Array(d) : d.toString()),\n );\n const code = (c: number) => (c >= 1000 && c !== 1005 && c !== 1006 ? c : 1000);\n server.addEventListener(\"close\", (e) =>\n remote.close(code((e as CloseEvent).code), (e as CloseEvent).reason),\n );\n remote.on(\"close\", (c: number, reason: Buffer) => server.close(code(c), reason.toString()));\n return new CellsResponse(null, {\n status: 101,\n webSocket: client,\n headers: remote.protocol ? { \"Sec-WebSocket-Protocol\": remote.protocol } : {},\n }) as Response;\n };\n return {\n async fetch(req: Request) {\n const url = new URL(req.url);\n if (req.headers.get(\"upgrade\")?.toLowerCase() === \"websocket\")\n return tunnelWebSocket(req, url);\n const headers: Record<string, string> = {};\n req.headers.forEach((v, h) => {\n if (!h.startsWith(\"x-cells-\")) headers[h] = v;\n });\n headers.host ??= url.host;\n const body =\n req.method === \"GET\" || req.method === \"HEAD\"\n ? undefined\n : new Uint8Array(await req.arrayBuffer());\n const r = await tunnelCall(k, opts.node, target, \"do\", {\n method: req.method,\n path: url.pathname + url.search,\n headers: control(headers),\n body,\n });\n if (r.status === 409 && r.headers[\"x-cells-route-error\"] === \"stale-owner\")\n throw staleError(cellKey);\n const out = new Headers();\n for (const [h, v] of Object.entries(r.headers))\n if (!h.startsWith(\"x-cells-\")) out.set(h, v);\n return new Response(r.status === 204 || r.status === 304 ? null : (r.body as BodyInit), {\n status: r.status,\n headers: out,\n });\n },\n async call(method: string, args: unknown[]) {\n const body = serialize(toAnotherNode(args));\n const r = await tunnelCall(k, opts.node, target, \"rpc\", {\n method: \"POST\",\n path: \"/\",\n headers: control({\n \"x-cells-rpc-method\": method,\n \"content-type\": \"application/octet-stream\",\n \"content-length\": String(body.length),\n }),\n body,\n });\n if (r.status === 409 && r.headers[\"x-cells-route-error\"] === \"stale-owner\")\n throw staleError(cellKey);\n if (r.status !== 200)\n throw new Error(\n `remote RPC failed with ${r.status}: ${new TextDecoder().decode(r.body)}`,\n );\n if (r.body[0] === 0xff) return deserialize(r.body);\n if (r.body[0] === 0) {\n const [error, props] = deserialize(r.body.subarray(1)) as [\n unknown,\n Record<string, unknown>,\n ];\n if (error instanceof Error) Object.assign(error, props, { remote: true });\n throw error;\n }\n throw new Error(\"RPC stubs cannot cross from celld to cellb\");\n },\n };\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"celld-peer.js","sourceRoot":"","sources":["../../src/peer/celld-peer.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, createHmac, randomBytes, timingSafeEqual } from \"node:crypto\";\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport type { Duplex } from \"node:stream\";\nimport type { ObjectStore } from \"../bucket/object-store.js\";\nimport { toAnotherNode } from \"../core/handles.js\";\nimport type { CellRuntime } from \"../core/runtime.js\";\nimport { deserialize, serialize } from \"../v8/serialize.js\";\nimport { createWebSocketClass } from \"../ws/client.js\";\nimport { CellsResponse, type CfWebSocket, takeClientPort, WebSocketPair } from \"../ws/server.js\";\nimport { withUpgrade } from \"../ws/upgrade.js\";\n\n/**\n * celld's peer protocol (peer_auth.rs, main/peer_tunnel.rs, protocol 5) for a cellb node\n * hosted in Node, so celld nodes can route a cell's requests to it when it owns the cell.\n *\n * Authentication: every peer request carries an HMAC-SHA-256 over\n * \"cells-peer-request-v1\\n5\\n<method>\\n<path?query>\\n<sha256(body)>\\n<source>\\n<target>\\n<ts>\\n<nonce>\"\n * keyed by the fleet secret in `fleet/peer-auth.json`, with headers x-cells-peer-{version,\n * source,target,timestamp,nonce,body-sha256,signature}; ±30 s clock window, nonce replay cache,\n * and the target must be this node.\n *\n * Tunnel: `GET /peer/tunnel` with `Upgrade: celld-tunnel` (kind `do` or `rpc`) is answered with\n * 101; then the connection carries plain HTTP/1.1 requests, one call each, with control headers\n * x-cells-scope (the cell, \"<Class>:<idhex>\"), x-cells-do-name, x-cells-request-id:\n * do — the application request as is; the reply streams back.\n * rpc — POST, method in x-cells-rpc-method, arguments V8-serialized (an array) or JSON; the\n * reply is the V8-serialized result, or a tagged error (0, then [error, props]).\n * A cell this node does not own answers 409 with `x-cells-route-error: stale-owner`, so celld\n * re-resolves the owner.\n */\nconst PROTOCOL = \"5\";\nconst DOMAIN = \"cells-peer-request-v1\";\nconst CLOCK_WINDOW_MS = 30_000;\nconst PEER_HEADERS = {\n version: \"x-cells-peer-version\",\n source: \"x-cells-peer-source\",\n target: \"x-cells-peer-target\",\n timestamp: \"x-cells-peer-timestamp\",\n nonce: \"x-cells-peer-nonce\",\n bodySha: \"x-cells-peer-body-sha256\",\n signature: \"x-cells-peer-signature\",\n} as const;\nconst CONTROL = [\n \"x-cells-scope\",\n \"x-cells-do-name\",\n \"x-cells-request-id\",\n \"x-cells-capacity-handoff\",\n];\n\n/** The fleet's peer secret (celld creates it in the bucket). */\nexport async function loadPeerKey(store: ObjectStore): Promise<Uint8Array> {\n const o = await store.get(\"fleet/peer-auth.json\");\n if (!o) throw new Error(\"the fleet has no peer authentication secret; start a celld node first\");\n const { version, key } = JSON.parse(new TextDecoder().decode(o.body)) as {\n version: number;\n key: string;\n };\n if (version !== 1 || !/^[0-9a-f]{64}$/.test(key))\n throw new Error(\"unexpected fleet/peer-auth.json\");\n return Uint8Array.from(Buffer.from(key, \"hex\"));\n}\n\nconst sha256hex = (b: Uint8Array) => createHash(\"sha256\").update(b).digest(\"hex\");\nconst mac = (\n key: Uint8Array,\n c: {\n method: string;\n path: string;\n bodySha: string;\n source: string;\n target: string;\n ts: string;\n nonce: string;\n },\n) =>\n createHmac(\"sha256\", key)\n .update(\n `${DOMAIN}\\n${PROTOCOL}\\n${c.method}\\n${c.path}\\n${c.bodySha}\\n${c.source}\\n${c.target}\\n${c.ts}\\n${c.nonce}`,\n )\n .digest();\n\n/** Headers that sign one peer request from `source` to `target`. */\nexport function signPeerRequest(\n key: Uint8Array,\n source: string,\n target: string,\n method: string,\n pathAndQuery: string,\n body: Uint8Array = new Uint8Array(),\n) {\n const ts = String(Date.now());\n const nonce = randomBytes(16).toString(\"hex\");\n const bodySha = sha256hex(body);\n const signature = mac(key, {\n method,\n path: pathAndQuery,\n bodySha,\n source,\n target,\n ts,\n nonce,\n }).toString(\"hex\");\n return {\n [PEER_HEADERS.version]: PROTOCOL,\n [PEER_HEADERS.source]: source,\n [PEER_HEADERS.target]: target,\n [PEER_HEADERS.timestamp]: ts,\n [PEER_HEADERS.nonce]: nonce,\n [PEER_HEADERS.bodySha]: bodySha,\n [PEER_HEADERS.signature]: signature,\n };\n}\n\n/** celld's verification; returns a status and message on failure. */\nexport function verifyPeerRequest(\n key: Uint8Array,\n self: string,\n method: string,\n pathAndQuery: string,\n headers: Record<string, string | string[] | undefined>,\n body: Uint8Array,\n seen: Map<string, number>,\n): { status: number; message: string; stale?: boolean } | undefined {\n const h = (n: string) => (typeof headers[n] === \"string\" ? (headers[n] as string) : undefined);\n const version = h(PEER_HEADERS.version);\n if (version === undefined) return { status: 401, message: \"peer authentication failed\" };\n if (version !== PROTOCOL)\n return { status: 426, message: \"peer protocol version is incompatible\" };\n const [source, target, ts, nonce, bodySha, signature] = [\n PEER_HEADERS.source,\n PEER_HEADERS.target,\n PEER_HEADERS.timestamp,\n PEER_HEADERS.nonce,\n PEER_HEADERS.bodySha,\n PEER_HEADERS.signature,\n ].map(h);\n if (!source || !target || !ts || !nonce || !bodySha || !signature)\n return { status: 401, message: \"peer authentication failed\" };\n const now = Date.now();\n if (!/^\\d+$/.test(ts) || Math.abs(now - Number(ts)) > CLOCK_WINDOW_MS)\n return { status: 401, message: \"peer authentication failed\" };\n if (\n sha256hex(body) !== bodySha ||\n !/^[0-9a-f]{32}$/.test(nonce) ||\n !/^[0-9a-f]{64}$/.test(signature)\n )\n return { status: 401, message: \"peer authentication failed\" };\n const expected = mac(key, { method, path: pathAndQuery, bodySha, source, target, ts, nonce });\n if (!timingSafeEqual(expected, Buffer.from(signature, \"hex\")))\n return { status: 401, message: \"peer authentication failed\" };\n if (target !== self)\n return { status: 409, message: \"peer request targets a different node session\", stale: true };\n for (const [n, t] of seen) if (now - t > 2 * CLOCK_WINDOW_MS) seen.delete(n);\n if (seen.has(nonce)) return { status: 409, message: \"peer request replay rejected\" };\n seen.set(nonce, now);\n return undefined;\n}\n\nconst readBody = async (req: IncomingMessage) => {\n const chunks: Buffer[] = [];\n for await (const c of req) chunks.push(c as Buffer);\n return new Uint8Array(Buffer.concat(chunks));\n};\n\n/** The cell a scope names, as a stub of this runtime (undefined: not a class we host). */\nfunction stubFor(runtime: CellRuntime, scope: string, name: string | undefined): any {\n const m = /^([^:]+):([0-9a-f]{64})$/.exec(scope);\n if (!m) return undefined;\n const binding = Object.entries(runtime.durableObjectBindings).find(\n ([, cls]) => cls === m[1],\n )?.[0];\n if (!binding) return undefined;\n const ns = runtime.env[binding] as any;\n return name !== undefined ? ns.getByName(name) : ns.get(ns.idFromString(m[2]));\n}\n\nconst notOwner = (e: unknown) =>\n /owned by another|OwnedElsewhere|lease/i.test(String((e as Error)?.message ?? e)) ||\n (e as Error)?.name === \"CellOwnedElsewhereError\";\n\nfunction reply(\n res: ServerResponse,\n status: number,\n headers: Record<string, string>,\n body?: Uint8Array | string,\n) {\n res.writeHead(status, { [PEER_HEADERS.version]: PROTOCOL, ...headers });\n res.end(body);\n}\nconst stale = (res: ServerResponse) =>\n reply(\n res,\n 409,\n { \"x-cells-route-error\": \"stale-owner\", \"content-type\": \"text/plain\" },\n \"stale route\",\n );\n\nexport interface CelldPeerServer {\n /** host:port celld dials (put it in the node record: celldBucket({ addr })). */\n addr: string;\n close(): Promise<void>;\n}\n\n/** RFC 7230 `token`: what a subprotocol name may be. */\nconst TOKEN = /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$/;\n\n/**\n * The subprotocols a `Sec-WebSocket-Protocol` header offers, as a client may ask for them: the\n * valid tokens, each once (case-insensitively), in the offered order. A header a client sent\n * through celld is not trusted to be well formed, and the client class refuses a malformed list.\n */\nexport function offeredProtocols(header: string | undefined): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const raw of (header ?? \"\").split(\",\")) {\n const p = raw.trim();\n if (!TOKEN.test(p) || seen.has(p.toLowerCase())) continue;\n seen.add(p.toLowerCase());\n out.push(p);\n }\n return out;\n}\n\n/**\n * The cell's side of a tunneled WebSocket: a client socket on the port of the 101's\n * WebSocketPair end. It asks for the subprotocols the far client offered (`offered`, the\n * `Sec-WebSocket-Protocol` header): a client refuses a subprotocol it did not ask for, and the\n * cell picks one of those. Should the socket not be made, the port is closed, and the cell's\n * end with it.\n */\nexport function cellSocket(\n res: Response & { webSocket: CfWebSocket },\n offered: string | undefined,\n): WebSocket {\n const port = takeClientPort(res.webSocket);\n try {\n const WS = createWebSocketClass(async () => ({\n port,\n protocol: res.headers.get(\"Sec-WebSocket-Protocol\") ?? undefined,\n }));\n const cell = new WS(\"ws://cell/\", offeredProtocols(offered)) as WebSocket;\n cell.binaryType = \"arraybuffer\";\n return cell;\n } catch (error) {\n port.close();\n throw error;\n }\n}\n\n/**\n * Serves celld's peer tunnel for `runtime` on `host:port` (0: any free port). `node` is this\n * node's name in the fleet (the same as celldBucket's `node`).\n */\nexport async function startCelldPeerServer(opts: {\n runtime: CellRuntime;\n store: ObjectStore;\n node: string;\n host?: string;\n port?: number;\n /** Answers celld's signed probe (celldBucket(...).probe): `celld diagnose --peer` reaches us. */\n probe?: (challenge: string) => Promise<unknown>;\n}): Promise<CelldPeerServer> {\n const key = await loadPeerKey(opts.store);\n const seen = new Map<string, number>();\n const host = opts.host ?? \"127.0.0.1\";\n\n const serveDo = async (req: IncomingMessage, res: ServerResponse) => {\n const scope = String(req.headers[\"x-cells-scope\"] ?? \"\");\n const name = req.headers[\"x-cells-do-name\"] as string | undefined;\n const stub = stubFor(opts.runtime, scope, name);\n if (!stub) return reply(res, 400, {}, \"malformed cell scope\");\n const headers = new Headers();\n for (const [k, v] of Object.entries(req.headers))\n if (typeof v === \"string\" && !CONTROL.includes(k)) headers.set(k, v);\n const method = req.method ?? \"GET\";\n const body = method === \"GET\" || method === \"HEAD\" ? undefined : await readBody(req);\n const url = /^https?:\\/\\//.test(req.url ?? \"\")\n ? (req.url as string)\n : `http://${req.headers.host ?? \"cell\"}${req.url ?? \"/\"}`;\n try {\n const r: Response = await stub.fetch(new Request(url, { method, headers, body }));\n const out: Record<string, string> = {};\n r.headers.forEach((v, k) => {\n if (k !== \"content-length\" && k !== \"transfer-encoding\" && k !== \"connection\") out[k] = v;\n });\n reply(res, r.status, out, new Uint8Array(await r.arrayBuffer()));\n } catch (e) {\n if (notOwner(e)) return stale(res);\n reply(res, 500, { \"content-type\": \"text/plain\" }, String((e as Error)?.message ?? e));\n }\n };\n\n const serveRpc = async (req: IncomingMessage, res: ServerResponse) => {\n const scope = String(req.headers[\"x-cells-scope\"] ?? \"\");\n const stub = stubFor(opts.runtime, scope, req.headers[\"x-cells-do-name\"] as string | undefined);\n const method = req.headers[\"x-cells-rpc-method\"] as string | undefined;\n if (!stub) return reply(res, 400, {}, \"malformed cell scope\");\n if (!method) return reply(res, 400, {}, \"RPC method header is missing\");\n const raw = await readBody(req);\n const structured = req.headers[\"content-type\"] === \"application/octet-stream\";\n let args: unknown[];\n if (structured) {\n if (raw[0] !== 0xff) return reply(res, 501, {}, \"RPC stubs cannot cross to cellb\");\n args = deserialize(raw) as unknown[];\n } else args = JSON.parse(new TextDecoder().decode(raw)) as unknown[];\n try {\n const result = await stub[method](...(Array.isArray(args) ? args : [args]));\n if (structured)\n reply(\n res,\n 200,\n { \"content-type\": \"application/octet-stream\" },\n serialize(toAnotherNode(result)),\n );\n else reply(res, 200, { \"content-type\": \"application/json\" }, JSON.stringify(result ?? null));\n } catch (e) {\n if (notOwner(e)) return stale(res);\n if (!structured)\n return reply(\n res,\n 500,\n { \"content-type\": \"text/plain\" },\n `RPC failed: ${String((e as Error)?.message ?? e)}`,\n );\n // celld's callee exception: tag 0, then [error, own properties incl. name]\n const err = e instanceof Error ? e : new Error(String(e));\n const props = e instanceof Error ? { ...e, name: e.name } : { name: \"Error\" };\n const sc = serialize([err, props]);\n const tagged = new Uint8Array(sc.length + 1);\n tagged.set(sc, 1);\n reply(res, 200, { \"content-type\": \"application/octet-stream\" }, tagged);\n }\n };\n\n // One inner HTTP/1.1 server per tunnel kind: an upgraded socket becomes its connection.\n // celld's inner RPC requests carry no Host header: Node would answer 400 by default.\n const inner = {\n do: createServer({ requireHostHeader: false }, (q, s) => void serveDo(q, s)),\n rpc: createServer({ requireHostHeader: false }, (q, s) => void serveRpc(q, s)),\n };\n for (const s of Object.values(inner)) s.keepAliveTimeout = 0;\n // A tunneled WebSocket (celld: the client's own handshake crosses the tunnel and the owner\n // answers it): the cell's 101 + webSocket is bridged to the raw connection, framed by `ws`.\n const { WebSocketServer } = await import(\"ws\");\n const wss = new WebSocketServer({ noServer: true });\n inner.do.on(\"upgrade\", async (req: IncomingMessage, socket: Duplex, head: Buffer) => {\n const fail = (status: number, body: string, extra: Record<string, string> = {}) => {\n const lines = [\n `HTTP/1.1 ${status} ${status === 409 ? \"Conflict\" : \"Error\"}`,\n `${PEER_HEADERS.version}: ${PROTOCOL}`,\n `content-length: ${Buffer.byteLength(body)}`,\n \"connection: close\",\n ];\n for (const [k, v] of Object.entries(extra)) lines.push(`${k}: ${v}`);\n socket.end(`${lines.join(\"\\r\\n\")}\\r\\n\\r\\n${body}`);\n };\n const stub = stubFor(\n opts.runtime,\n String(req.headers[\"x-cells-scope\"] ?? \"\"),\n req.headers[\"x-cells-do-name\"] as string | undefined,\n );\n if (!stub) return fail(400, \"malformed cell scope\");\n const headers = new Headers();\n for (const [k, v] of Object.entries(req.headers))\n if (typeof v === \"string\" && !CONTROL.includes(k)) headers.set(k, v);\n const url = /^https?:\\/\\//.test(req.url ?? \"\")\n ? (req.url as string)\n : `http://${req.headers.host ?? \"cell\"}${req.url ?? \"/\"}`;\n const protocols = req.headers[\"sec-websocket-protocol\"] as string | undefined;\n let res: Response & { webSocket?: CfWebSocket | null };\n try {\n res = await stub.fetch(\n withUpgrade(\n new Request(url, { headers }),\n \"websocket\",\n protocols ? { \"Sec-WebSocket-Protocol\": protocols } : undefined,\n ),\n );\n } catch (e) {\n return notOwner(e)\n ? fail(409, \"stale route\", { \"x-cells-route-error\": \"stale-owner\" })\n : fail(500, String((e as Error)?.message ?? e));\n }\n if (res.status !== 101 || !res.webSocket) return fail(res.status, await res.text());\n let cell: WebSocket;\n try {\n cell = cellSocket(res as Response & { webSocket: CfWebSocket }, protocols);\n } catch (e) {\n return fail(400, String((e as Error)?.message ?? e));\n }\n const pending: (string | ArrayBuffer)[] = [];\n let open = false;\n wss.handleUpgrade(req, socket, head, (client) => {\n cell.onopen = () => {\n open = true;\n for (const m of pending.splice(0)) cell.send(m);\n };\n client.on(\"message\", (data: Buffer, isBinary: boolean) => {\n const m = isBinary ? (new Uint8Array(data).buffer as ArrayBuffer) : data.toString();\n if (open) cell.send(m);\n else pending.push(m);\n });\n cell.onmessage = (ev: MessageEvent) =>\n client.send(ev.data instanceof ArrayBuffer ? Buffer.from(ev.data) : ev.data);\n client.on(\"close\", (code: number, reason: Buffer) =>\n cell.close(\n code >= 1000 && code < 5000 && code !== 1005 && code !== 1006 ? code : 1000,\n reason.toString(),\n ),\n );\n cell.onclose = (ev: CloseEvent) =>\n client.close(\n ev.code >= 1000 && ev.code !== 1005 && ev.code !== 1006 ? ev.code : 1000,\n ev.reason,\n );\n });\n });\n\n const server: Server = createServer(async (req, res) => {\n if (req.url === \"/peer/probe\" && req.method === \"GET\" && opts.probe) {\n const denied = verifyPeerRequest(\n key,\n opts.node,\n \"GET\",\n \"/peer/probe\",\n req.headers,\n new Uint8Array(),\n seen,\n );\n if (denied)\n return reply(res, denied.status, { \"content-type\": \"text/plain\" }, denied.message);\n try {\n const answer = await opts.probe(String(req.headers[\"x-cells-probe-challenge\"] ?? \"\"));\n return reply(res, 200, { \"content-type\": \"application/json\" }, JSON.stringify(answer));\n } catch (e) {\n return reply(\n res,\n 400,\n { \"content-type\": \"text/plain\" },\n String((e as Error)?.message ?? e),\n );\n }\n }\n reply(res, 404, {}, \"not found\");\n });\n server.on(\"upgrade\", (req: IncomingMessage, socket: Duplex, head: Buffer) => {\n const path = req.url ?? \"/\";\n const refuse = (status: number, message: string, extra: Record<string, string> = {}) => {\n const lines = [\n `HTTP/1.1 ${status} ${message}`,\n `${PEER_HEADERS.version}: ${PROTOCOL}`,\n \"connection: close\",\n \"content-length: 0\",\n ];\n for (const [k, v] of Object.entries(extra)) lines.push(`${k}: ${v}`);\n socket.end(`${lines.join(\"\\r\\n\")}\\r\\n\\r\\n`);\n };\n if (path !== \"/peer/tunnel\" || req.headers.upgrade !== \"celld-tunnel\")\n return refuse(404, \"Not Found\");\n const denied = verifyPeerRequest(\n key,\n opts.node,\n req.method ?? \"GET\",\n path,\n req.headers,\n new Uint8Array(),\n seen,\n );\n if (denied)\n return refuse(\n denied.status,\n denied.message,\n denied.stale ? { \"x-cells-route-error\": \"stale-owner\" } : {},\n );\n if (req.headers[\"x-cells-tunnel-version\"] !== \"5\") return refuse(426, \"Upgrade Required\");\n const kind = req.headers[\"x-cells-tunnel-kind\"];\n if (kind !== \"do\" && kind !== \"rpc\") return refuse(400, \"Bad Request\");\n socket.write(\n [\n \"HTTP/1.1 101 Switching Protocols\",\n \"upgrade: celld-tunnel\",\n \"connection: upgrade\",\n \"x-cells-tunnel-version: 5\",\n `${PEER_HEADERS.version}: ${PROTOCOL}`,\n ].join(\"\\r\\n\") + \"\\r\\n\\r\\n\",\n );\n if (head?.length) socket.unshift(head);\n inner[kind].emit(\"connection\", socket);\n });\n await new Promise<void>((r) => server.listen(opts.port ?? 0, host, () => r()));\n const port = (server.address() as { port: number }).port;\n return {\n addr: `${host}:${port}`,\n close: () =>\n new Promise<void>((r) => {\n server.closeAllConnections?.();\n for (const s of Object.values(inner)) s.closeAllConnections?.();\n server.close(() => r());\n }),\n };\n}\n\n/**\n * The calling half (celld's node A): open a signed tunnel to the owner node and send one call\n * through it — `fetch` on a `do` tunnel, JS RPC on an `rpc` tunnel (V8-serialized arguments;\n * the reply decoded as celld encodes it, a callee exception rethrown with its properties).\n */\n/** A signed `celld-tunnel` upgrade to the owner node: the raw connection after its 101. */\nasync function openTunnel(\n key: Uint8Array,\n source: string,\n owner: { node: string; addr: string },\n kind: \"do\" | \"rpc\",\n): Promise<import(\"node:net\").Socket> {\n const { request } = await import(\"node:http\");\n const [host, port] = [\n owner.addr.slice(0, owner.addr.lastIndexOf(\":\")),\n Number(owner.addr.slice(owner.addr.lastIndexOf(\":\") + 1)),\n ];\n const socket = await new Promise<import(\"node:net\").Socket>((resolve, reject) => {\n const req = request({\n host,\n port,\n path: \"/peer/tunnel\",\n method: \"GET\",\n headers: {\n upgrade: \"celld-tunnel\",\n connection: \"upgrade\",\n \"x-cells-tunnel-version\": \"5\",\n \"x-cells-tunnel-kind\": kind,\n ...signPeerRequest(key, source, owner.node, \"GET\", \"/peer/tunnel\"),\n },\n });\n req.on(\"upgrade\", (_res, sock) => resolve(sock as import(\"node:net\").Socket));\n req.on(\"response\", (res) =>\n reject(\n Object.assign(new Error(`peer tunnel refused: ${res.statusCode}`), {\n stale: res.headers[\"x-cells-route-error\"] === \"stale-owner\",\n }),\n ),\n );\n req.on(\"error\", reject);\n req.end();\n });\n return socket;\n}\n\nasync function tunnelCall(\n key: Uint8Array,\n source: string,\n owner: { node: string; addr: string },\n kind: \"do\" | \"rpc\",\n inner: { method: string; path: string; headers: Record<string, string>; body?: Uint8Array },\n): Promise<{ status: number; headers: Record<string, string>; body: Uint8Array }> {\n const { request } = await import(\"node:http\");\n const socket = await openTunnel(key, source, owner, kind);\n try {\n return await new Promise((resolve, reject) => {\n const req = request(\n // no agent: the request runs on the upgraded socket itself\n {\n createConnection: () => socket,\n method: inner.method,\n path: inner.path,\n headers: inner.headers,\n },\n async (res) => {\n const chunks: Buffer[] = [];\n for await (const c of res) chunks.push(c as Buffer);\n const headers: Record<string, string> = {};\n for (const [k, v] of Object.entries(res.headers))\n if (typeof v === \"string\") headers[k] = v;\n resolve({\n status: res.statusCode ?? 500,\n headers,\n body: new Uint8Array(Buffer.concat(chunks)),\n });\n },\n );\n req.on(\"error\", reject);\n req.end(inner.body);\n });\n } finally {\n socket.destroy();\n }\n}\n\n/**\n * Routing to cells celld nodes own, for CellRuntimeOptions.peers: `ownerOf` reads the cell's\n * own.json, `endpoint` reaches the owner's address from its node record through the tunnel.\n */\nexport function celldPeers(opts: { store: ObjectStore; node: string }) {\n let key: Promise<Uint8Array> | undefined;\n const json = async <T>(k: string) => {\n const o = await opts.store.get(k);\n return o ? (JSON.parse(new TextDecoder().decode(o.body)) as T) : undefined;\n };\n const staleError = (cellKey: string) =>\n Object.assign(new Error(`${cellKey} is owned by another node`), {\n name: \"CellOwnedElsewhereError\",\n });\n return {\n async ownerOf(cellKey: string) {\n const own = await json<{ node: string }>(`cells/${cellKey.replace(\"/\", \":\")}/own.json`);\n return own?.node && own.node !== opts.node ? own.node : undefined;\n },\n link(): never {\n throw new Error(\"celld owners are reached through endpoint()\");\n },\n async endpoint(owner: string, cellKey: string, name: string | undefined) {\n const lease = await json<{ addr: string; expires_ms: number }>(`nodes/${owner}.json`);\n if (!lease?.addr || lease.expires_ms <= Date.now()) return undefined;\n key ??= loadPeerKey(opts.store);\n const k = await key;\n const target = { node: owner, addr: lease.addr };\n const scope = cellKey.replace(\"/\", \":\");\n const control = (h: Record<string, string>) => ({\n ...h,\n \"x-cells-scope\": scope,\n ...(name !== undefined ? { \"x-cells-do-name\": name } : {}),\n });\n // A WebSocket to a cell celld owns: the client handshake crosses a `do` tunnel and `ws`\n // speaks the frames on it; the caller gets a 101 with a WebSocketPair end bridged to it.\n const tunnelWebSocket = async (req: Request, url: URL) => {\n const socket = await openTunnel(k, opts.node, target, \"do\");\n const { WebSocket: WsClient } = await import(\"ws\");\n const protocols = req.headers\n .get(\"sec-websocket-protocol\")\n ?.split(\",\")\n .map((p) => p.trim())\n .filter(Boolean);\n const remote = new WsClient(`ws://${url.host}${url.pathname}${url.search}`, protocols, {\n createConnection: () => socket,\n headers: control({}),\n });\n await new Promise<void>((resolve, reject) => {\n remote.once(\"open\", () => resolve());\n remote.once(\n \"unexpected-response\",\n (_q: unknown, res: { statusCode?: number; headers: Record<string, unknown> }) =>\n reject(\n res.headers[\"x-cells-route-error\"] === \"stale-owner\"\n ? staleError(cellKey)\n : new Error(`WebSocket through the tunnel refused: ${res.statusCode}`),\n ),\n );\n remote.once(\"error\", reject);\n });\n const pair = new WebSocketPair();\n const [client, server] = [pair[0], pair[1]];\n server.accept();\n server.addEventListener(\"message\", (e) => remote.send((e as MessageEvent).data));\n remote.on(\"message\", (d: Buffer, isBinary: boolean) =>\n server.send(isBinary ? new Uint8Array(d) : d.toString()),\n );\n const code = (c: number) => (c >= 1000 && c !== 1005 && c !== 1006 ? c : 1000);\n server.addEventListener(\"close\", (e) =>\n remote.close(code((e as CloseEvent).code), (e as CloseEvent).reason),\n );\n remote.on(\"close\", (c: number, reason: Buffer) => server.close(code(c), reason.toString()));\n return new CellsResponse(null, {\n status: 101,\n webSocket: client,\n headers: remote.protocol ? { \"Sec-WebSocket-Protocol\": remote.protocol } : {},\n }) as Response;\n };\n return {\n async fetch(req: Request) {\n const url = new URL(req.url);\n if (req.headers.get(\"upgrade\")?.toLowerCase() === \"websocket\")\n return tunnelWebSocket(req, url);\n const headers: Record<string, string> = {};\n req.headers.forEach((v, h) => {\n if (!h.startsWith(\"x-cells-\")) headers[h] = v;\n });\n headers.host ??= url.host;\n const body =\n req.method === \"GET\" || req.method === \"HEAD\"\n ? undefined\n : new Uint8Array(await req.arrayBuffer());\n const r = await tunnelCall(k, opts.node, target, \"do\", {\n method: req.method,\n path: url.pathname + url.search,\n headers: control(headers),\n body,\n });\n if (r.status === 409 && r.headers[\"x-cells-route-error\"] === \"stale-owner\")\n throw staleError(cellKey);\n const out = new Headers();\n for (const [h, v] of Object.entries(r.headers))\n if (!h.startsWith(\"x-cells-\")) out.set(h, v);\n return new Response(r.status === 204 || r.status === 304 ? null : (r.body as BodyInit), {\n status: r.status,\n headers: out,\n });\n },\n async call(method: string, args: unknown[]) {\n const body = serialize(toAnotherNode(args));\n const r = await tunnelCall(k, opts.node, target, \"rpc\", {\n method: \"POST\",\n path: \"/\",\n headers: control({\n \"x-cells-rpc-method\": method,\n \"content-type\": \"application/octet-stream\",\n \"content-length\": String(body.length),\n }),\n body,\n });\n if (r.status === 409 && r.headers[\"x-cells-route-error\"] === \"stale-owner\")\n throw staleError(cellKey);\n if (r.status !== 200)\n throw new Error(\n `remote RPC failed with ${r.status}: ${new TextDecoder().decode(r.body)}`,\n );\n if (r.body[0] === 0xff) return deserialize(r.body);\n if (r.body[0] === 0) {\n const [error, props] = deserialize(r.body.subarray(1)) as [\n unknown,\n Record<string, unknown>,\n ];\n if (error instanceof Error) Object.assign(error, props, { remote: true });\n throw error;\n }\n throw new Error(\"RPC stubs cannot cross from celld to cellb\");\n },\n };\n },\n };\n}\n"]}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type RemoteRuntime } from "../transport/cells-http.js";
|
|
2
2
|
import { type BrowserBucket, type BrowserProjectOptions } from "./browser-host.js";
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* A shard of a project shared by the tabs of an origin (`joinProjectShards`): it serves through
|
|
5
|
+
* the ServiceWorker's router (webrun-http-browser's `serveHttpInWorker`), which the tab attaches
|
|
6
|
+
* it to, and reaches the other shards through it.
|
|
7
|
+
*/
|
|
4
8
|
export declare const TAB_INIT = "cellb:tab-shard";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export declare const TAB_WATCH = "cellb:tab-shard-watch";
|
|
8
|
-
/** From a shard worker to its tab: a call waits for a router that is gone; wake the ServiceWorker. */
|
|
9
|
-
export declare const SHARD_WAKE = "cellb:tab-shard-wake";
|
|
10
|
-
/** From a shard worker to its tab: calls into other shards are in flight; keep the ServiceWorker up. */
|
|
11
|
-
export declare const SHARD_KEEPALIVE = "cellb:tab-shard-keepalive";
|
|
9
|
+
/** The host calls between shards go to through the router: `http://cellb.internal/<project>/`. */
|
|
10
|
+
export declare const INTERNAL_ORIGIN = "http://cellb.internal";
|
|
12
11
|
/** What a shard worker shared by tabs is told: no peers, it reaches them through the router. */
|
|
13
12
|
export interface TabShardInit {
|
|
14
13
|
type: typeof TAB_INIT;
|
|
@@ -10,22 +10,24 @@
|
|
|
10
10
|
* Placement is fixed by the cell id (no rebalancing), and a closed page takes its workers along:
|
|
11
11
|
* for cells that must outlive a tab, use a fleet bucket (`bucket`), as for one worker.
|
|
12
12
|
*/
|
|
13
|
+
import { serveHttpInWorker, webSocketUpgradeResponse, } from "@statewalker/webrun-http-browser/sw";
|
|
14
|
+
import { withUrl } from "../core/request-body.js";
|
|
13
15
|
import { shardOf } from "../core/shard.js";
|
|
14
|
-
import {
|
|
16
|
+
import { cellsHttpHandler } from "../transport/cells-http.js";
|
|
17
|
+
import { H, keepUpgrade } from "../transport/cells-link.js";
|
|
15
18
|
import { connectRuntime, linkOverPort, serveRuntime } from "../transport/port.js";
|
|
16
|
-
import { CfWebSocket } from "../ws/server.js";
|
|
19
|
+
import { CellsResponse, CfWebSocket, takeClientPort } from "../ws/server.js";
|
|
17
20
|
import { browserProjectRuntime, } from "./browser-host.js";
|
|
18
21
|
const INIT = "cellb:shard";
|
|
19
22
|
const CLOSE = "cellb:shard-close";
|
|
20
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* A shard of a project shared by the tabs of an origin (`joinProjectShards`): it serves through
|
|
25
|
+
* the ServiceWorker's router (webrun-http-browser's `serveHttpInWorker`), which the tab attaches
|
|
26
|
+
* it to, and reaches the other shards through it.
|
|
27
|
+
*/
|
|
21
28
|
export const TAB_INIT = "cellb:tab-shard";
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
export const TAB_WATCH = "cellb:tab-shard-watch";
|
|
25
|
-
/** From a shard worker to its tab: a call waits for a router that is gone; wake the ServiceWorker. */
|
|
26
|
-
export const SHARD_WAKE = "cellb:tab-shard-wake";
|
|
27
|
-
/** From a shard worker to its tab: calls into other shards are in flight; keep the ServiceWorker up. */
|
|
28
|
-
export const SHARD_KEEPALIVE = "cellb:tab-shard-keepalive";
|
|
29
|
+
/** The host calls between shards go to through the router: `http://cellb.internal/<project>/`. */
|
|
30
|
+
export const INTERNAL_ORIGIN = "http://cellb.internal";
|
|
29
31
|
/**
|
|
30
32
|
* The worker side: hosts one shard when a page says so — of `startProjectShards` (peers wired
|
|
31
33
|
* directly) or of `joinProjectShards` (shared by the tabs, linked to the ServiceWorker's router).
|
|
@@ -34,15 +36,13 @@ export const SHARD_KEEPALIVE = "cellb:tab-shard-keepalive";
|
|
|
34
36
|
export function serveProjectShard(opts) {
|
|
35
37
|
const scope = globalThis;
|
|
36
38
|
let host;
|
|
37
|
-
let
|
|
38
|
-
let releaseOwner;
|
|
39
|
-
let linkCount = 0; // TAB_LINKs so far: a router's watch drops only the links made for it
|
|
39
|
+
let service;
|
|
40
40
|
const sqlite3 = () => typeof opts.sqlite3 === "function"
|
|
41
41
|
? opts.sqlite3()
|
|
42
42
|
: Promise.resolve(opts.sqlite3);
|
|
43
43
|
scope.addEventListener("message", async (e) => {
|
|
44
44
|
const type = e.data?.type;
|
|
45
|
-
if (![INIT, CLOSE, TAB_INIT
|
|
45
|
+
if (![INIT, CLOSE, TAB_INIT].includes(type))
|
|
46
46
|
return;
|
|
47
47
|
const reply = e.ports[0];
|
|
48
48
|
try {
|
|
@@ -54,37 +54,16 @@ export function serveProjectShard(opts) {
|
|
|
54
54
|
}
|
|
55
55
|
finally {
|
|
56
56
|
host = undefined;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
// The router sees this shard's owner gone (its owner lock), even if closing failed.
|
|
58
|
+
await service?.close().catch(() => { });
|
|
59
|
+
service = undefined;
|
|
60
60
|
}
|
|
61
61
|
return reply.postMessage({ ok: true });
|
|
62
62
|
}
|
|
63
|
-
if (type === TAB_LINK) {
|
|
64
|
-
if (!routed)
|
|
65
|
-
throw new Error("shard not started");
|
|
66
|
-
linkCount++;
|
|
67
|
-
await routed.link(e.ports[1], e.ports[2], e.ports[3]);
|
|
68
|
-
return reply.postMessage({ ok: true });
|
|
69
|
-
}
|
|
70
|
-
if (type === TAB_WATCH) {
|
|
71
|
-
// The lock is ours once the router's ServiceWorker is gone (the browser stops an idle one):
|
|
72
|
-
// its ports are dead, though nothing says so. A call that waits wakes it through the tab.
|
|
73
|
-
const linked = linkCount;
|
|
74
|
-
const shard = routed;
|
|
75
|
-
void navigator.locks.request(e.data.routerLock, () => {
|
|
76
|
-
if (linkCount === linked && routed === shard)
|
|
77
|
-
shard?.unlink();
|
|
78
|
-
});
|
|
79
|
-
return reply.postMessage({ ok: true });
|
|
80
|
-
}
|
|
81
63
|
if (type === TAB_INIT) {
|
|
82
64
|
const init = e.data;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
onUnlinked: () => scope.postMessage({ type: SHARD_WAKE }),
|
|
86
|
-
keepAlive: () => scope.postMessage({ type: SHARD_KEEPALIVE }),
|
|
87
|
-
});
|
|
65
|
+
let ready;
|
|
66
|
+
const serviceReady = new Promise((r) => (ready = r));
|
|
88
67
|
host = await browserProjectRuntime({
|
|
89
68
|
config: init.config,
|
|
90
69
|
code: init.code,
|
|
@@ -95,19 +74,15 @@ export function serveProjectShard(opts) {
|
|
|
95
74
|
pool: init.pool,
|
|
96
75
|
filesDir: init.filesDir,
|
|
97
76
|
isolateScript: opts.isolateScript,
|
|
98
|
-
route:
|
|
77
|
+
route: throughRouter(init, serviceReady),
|
|
99
78
|
});
|
|
100
|
-
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
return new Promise((release) => (releaseOwner = release));
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
return reply.postMessage({ ok: true, ownerLock, unsupported: host.unsupported });
|
|
79
|
+
// Served through the ServiceWorker's router, which the tab attaches this worker to. The
|
|
80
|
+
// package keeps the link: an owner lock the router watches, re-linking after a restart,
|
|
81
|
+
// keep-alive while calls are in flight.
|
|
82
|
+
const handler = cellsHttpHandler(host.runtime, { passUpgrades: true });
|
|
83
|
+
service = serveHttpInWorker(async (req) => upgradeOverPort(await handler(req)));
|
|
84
|
+
ready(service);
|
|
85
|
+
return reply.postMessage({ ok: true, unsupported: host.unsupported });
|
|
111
86
|
}
|
|
112
87
|
const init = e.data;
|
|
113
88
|
const links = new Map();
|
|
@@ -143,6 +118,67 @@ export function serveProjectShard(opts) {
|
|
|
143
118
|
}
|
|
144
119
|
});
|
|
145
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* A 101 with a Workers WebSocket, as the ServiceWorker's router hands sockets over: the client
|
|
123
|
+
* end's port in webrun-http-browser's 101.
|
|
124
|
+
*/
|
|
125
|
+
function upgradeOverPort(res) {
|
|
126
|
+
const ws = res.webSocket;
|
|
127
|
+
if (res.status !== 101 || !ws)
|
|
128
|
+
return res;
|
|
129
|
+
return webSocketUpgradeResponse(takeClientPort(ws), res.headers.get("Sec-WebSocket-Protocol") ?? "");
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The cells of other shards, through the ServiceWorker's router: a call goes to
|
|
133
|
+
* `http://cellb.internal/<project>/` (the router's key for the project) naming its shard, with the
|
|
134
|
+
* url it was made with in `H.url`; a socket opens through the router the same way.
|
|
135
|
+
*/
|
|
136
|
+
function throughRouter(init, service) {
|
|
137
|
+
const target = `${INTERNAL_ORIGIN}/${encodeURIComponent(init.name)}/`;
|
|
138
|
+
return (_key, id) => {
|
|
139
|
+
const owner = shardOf(id.toString(), init.shards);
|
|
140
|
+
if (owner === init.shard)
|
|
141
|
+
return undefined;
|
|
142
|
+
// `postVia` (the runtime's) adds the scheme header and rethrows error responses.
|
|
143
|
+
return async (req) => {
|
|
144
|
+
const svc = await service;
|
|
145
|
+
if (req.headers.get("upgrade")?.toLowerCase() === "websocket") {
|
|
146
|
+
const protocols = (req.headers.get("sec-websocket-protocol") ?? "")
|
|
147
|
+
.split(",")
|
|
148
|
+
.map((p) => p.trim())
|
|
149
|
+
.filter(Boolean);
|
|
150
|
+
const headers = [];
|
|
151
|
+
for (const [k, v] of req.headers)
|
|
152
|
+
if (k.startsWith("x-cellb"))
|
|
153
|
+
headers.push([k, v]);
|
|
154
|
+
headers.push([H.shard, String(owner)], [H.url, req.url]);
|
|
155
|
+
const { port, protocol } = await svc.connectWebSocket(target, protocols, headers);
|
|
156
|
+
return new CellsResponse(null, {
|
|
157
|
+
status: 101,
|
|
158
|
+
webSocket: new CfWebSocket(port),
|
|
159
|
+
headers: protocol ? { "Sec-WebSocket-Protocol": protocol } : {},
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
const moved = await withUrl(req, target);
|
|
163
|
+
const headers = new Headers(req.headers);
|
|
164
|
+
headers.set(H.shard, String(owner));
|
|
165
|
+
headers.set(H.url, req.url);
|
|
166
|
+
try {
|
|
167
|
+
return await svc.fetch(keepUpgrade(req, new Request(moved, { headers })));
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
// The words Worker code has always seen for it (CellRouter's), for a call the
|
|
171
|
+
// ServiceWorker lost in flight only: a call that never left (no link, the handler
|
|
172
|
+
// closed) keeps the package's words, as it was certainly not applied.
|
|
173
|
+
if (err instanceof Error &&
|
|
174
|
+
err.name === "LinkLostError" &&
|
|
175
|
+
err.message.startsWith("The ServiceWorker was lost while this call was in flight"))
|
|
176
|
+
throw new Error("The router was lost while this call was in flight; it may or may not have been applied");
|
|
177
|
+
throw err;
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
}
|
|
146
182
|
/** The page side: starts `shards` workers that each run `serveProjectShard`, wired together. */
|
|
147
183
|
export async function startProjectShards(opts) {
|
|
148
184
|
const workers = Array.from({ length: opts.shards }, (_, i) => opts.spawn(i));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-shards.js","sourceRoot":"","sources":["../../src/project/browser-shards.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * One project in several browser workers, so that its cells run in parallel threads. Each worker\n * hosts the project with `browserProjectRuntime` and its own OPFS pool, owns the cells that\n * `shardOf(id, shards)` gives it, and reaches every other cell through the worker that owns it\n * over a MessagePort. Any worker takes ingress; the page spreads requests over them.\n *\n * page: startProjectShards({ shards, spawn, config, code, name }) → { fetch, close }\n * worker: serveProjectShard({ sqlite3 })\n *\n * Placement is fixed by the cell id (no rebalancing), and a closed page takes its workers along:\n * for cells that must outlive a tab, use a fleet bucket (`bucket`), as for one worker.\n */\nimport { shardOf } from \"../core/shard.js\";\nimport { type ShardWorker, shardRouting } from \"../router/shard-worker.js\";\nimport type { RemoteRuntime } from \"../transport/cells-http.js\";\nimport { connectRuntime, linkOverPort, serveRuntime } from \"../transport/port.js\";\nimport { CfWebSocket } from \"../ws/server.js\";\nimport {\n type BrowserBucket,\n type BrowserProjectOptions,\n browserProjectRuntime,\n} from \"./browser-host.js\";\n\nconst INIT = \"cellb:shard\";\nconst CLOSE = \"cellb:shard-close\";\n/** A shard of a project shared by the tabs of an origin (`joinProjectShards`): linked to a router. */\nexport const TAB_INIT = \"cellb:tab-shard\";\nexport const TAB_LINK = \"cellb:tab-shard-link\";\n/** The router the shard was just linked to: the Web Lock its ServiceWorker holds while alive. */\nexport const TAB_WATCH = \"cellb:tab-shard-watch\";\n/** From a shard worker to its tab: a call waits for a router that is gone; wake the ServiceWorker. */\nexport const SHARD_WAKE = \"cellb:tab-shard-wake\";\n/** From a shard worker to its tab: calls into other shards are in flight; keep the ServiceWorker up. */\nexport const SHARD_KEEPALIVE = \"cellb:tab-shard-keepalive\";\n\n/** What a shard worker shared by tabs is told: no peers, it reaches them through the router. */\nexport interface TabShardInit {\n type: typeof TAB_INIT;\n name: string;\n shard: number;\n shards: number;\n config: BrowserProjectOptions[\"config\"];\n code: BrowserProjectOptions[\"code\"];\n assetFiles?: BrowserProjectOptions[\"assetFiles\"];\n /** The OpenAI-compatible endpoint behind the project's `ai` binding. */\n ai?: BrowserProjectOptions[\"ai\"];\n bucket?: BrowserBucket;\n pool: string;\n filesDir: string;\n}\n\n/** What a shard worker is told (the ports travel next to it). */\ninterface ShardInit {\n type: typeof INIT;\n shard: number;\n shards: number;\n config: BrowserProjectOptions[\"config\"];\n code: BrowserProjectOptions[\"code\"];\n assetFiles?: BrowserProjectOptions[\"assetFiles\"];\n /** The OpenAI-compatible endpoint behind the project's `ai` binding. */\n ai?: BrowserProjectOptions[\"ai\"];\n bucket?: BrowserBucket;\n pool: string;\n filesDir: string;\n /** For ports[2..]: the shard each port links to (`link`) or is served to (`serve`). */\n peers: { shard: number; role: \"link\" | \"serve\" }[];\n}\n\n/**\n * The worker side: hosts one shard when a page says so — of `startProjectShards` (peers wired\n * directly) or of `joinProjectShards` (shared by the tabs, linked to the ServiceWorker's router).\n * Messages of other types are left to the worker's own listeners.\n */\nexport function serveProjectShard(opts: {\n /** An initialized SQLite WASM module, or a function that makes one. */\n sqlite3: unknown | (() => Promise<unknown>);\n /** `browserProjectRuntime`'s `isolateScript`. */\n isolateScript?: URL;\n}): void {\n const scope = globalThis as unknown as {\n addEventListener(type: \"message\", fn: (e: MessageEvent) => void): void;\n postMessage(message: unknown): void;\n };\n let host: Awaited<ReturnType<typeof browserProjectRuntime>> | undefined;\n let routed: ShardWorker | undefined;\n let releaseOwner: (() => void) | undefined;\n let linkCount = 0; // TAB_LINKs so far: a router's watch drops only the links made for it\n const sqlite3 = () =>\n typeof opts.sqlite3 === \"function\"\n ? (opts.sqlite3 as () => Promise<unknown>)()\n : Promise.resolve(opts.sqlite3);\n scope.addEventListener(\"message\", async (e: MessageEvent) => {\n const type = (e.data as { type?: string } | undefined)?.type;\n if (![INIT, CLOSE, TAB_INIT, TAB_LINK, TAB_WATCH].includes(type as string)) return;\n const reply = e.ports[0] as MessagePort;\n try {\n if (type === CLOSE) {\n try {\n // The cells move elsewhere: their sockets' clients reconnect there now.\n CfWebSocket.goAway();\n await host?.close();\n } finally {\n host = undefined;\n routed = undefined;\n releaseOwner?.(); // the router sees this shard's owner gone, even if closing failed\n releaseOwner = undefined;\n }\n return reply.postMessage({ ok: true });\n }\n if (type === TAB_LINK) {\n if (!routed) throw new Error(\"shard not started\");\n linkCount++;\n await routed.link(e.ports[1], e.ports[2], e.ports[3]);\n return reply.postMessage({ ok: true });\n }\n if (type === TAB_WATCH) {\n // The lock is ours once the router's ServiceWorker is gone (the browser stops an idle one):\n // its ports are dead, though nothing says so. A call that waits wakes it through the tab.\n const linked = linkCount;\n const shard = routed;\n void navigator.locks.request(e.data.routerLock, () => {\n if (linkCount === linked && routed === shard) shard?.unlink();\n });\n return reply.postMessage({ ok: true });\n }\n if (type === TAB_INIT) {\n const init = e.data as TabShardInit;\n const routing = shardRouting({\n ...init,\n onUnlinked: () => scope.postMessage({ type: SHARD_WAKE }),\n keepAlive: () => scope.postMessage({ type: SHARD_KEEPALIVE }),\n });\n host = await browserProjectRuntime({\n config: init.config,\n code: init.code,\n assetFiles: init.assetFiles,\n ai: init.ai,\n bucket: init.bucket,\n sqlite3: await sqlite3(),\n pool: init.pool,\n filesDir: init.filesDir,\n isolateScript: opts.isolateScript,\n route: routing.route,\n });\n routed = routing.attach(host.runtime);\n // A lock only this worker holds: the browser releases it the moment the worker or its tab\n // dies, which tells the router its links are dead (MessagePorts report nothing).\n const ownerLock = `cellb:${init.name}:owner:${init.shard}:${crypto.randomUUID()}`;\n await new Promise<void>((held) => {\n void navigator.locks.request(ownerLock, () => {\n held();\n return new Promise<void>((release) => (releaseOwner = release));\n });\n });\n return reply.postMessage({ ok: true, ownerLock, unsupported: host.unsupported });\n }\n const init = e.data as ShardInit;\n const links = new Map<number, (req: Request) => Promise<Response>>();\n const served: MessagePort[] = [e.ports[1] as MessagePort]; // ingress from the page\n for (const [i, peer] of init.peers.entries()) {\n const port = e.ports[i + 2] as MessagePort;\n if (peer.role === \"link\") links.set(peer.shard, (await linkOverPort(port)).send);\n else served.push(port);\n }\n host = await browserProjectRuntime({\n config: init.config,\n code: init.code,\n assetFiles: init.assetFiles,\n ai: init.ai,\n bucket: init.bucket,\n sqlite3: await sqlite3(),\n pool: init.pool,\n filesDir: init.filesDir,\n isolateScript: opts.isolateScript,\n route: (_key, id) => {\n const owner = shardOf(id.toString(), init.shards);\n return owner === init.shard ? undefined : links.get(owner);\n },\n });\n for (const port of served) await serveRuntime(port, host.runtime);\n reply.postMessage({ ok: true, unsupported: host.unsupported });\n } catch (err) {\n reply.postMessage({ ok: false, error: String((err as Error)?.stack ?? err) });\n }\n });\n}\n\nexport interface ProjectShards {\n /** Ingress: a request to the project's Worker, in the next shard (round robin). */\n fetch(req: Request): Promise<Response>;\n /** The shards' runtimes, by shard number. */\n readonly shards: RemoteRuntime[];\n /** Configuration entries the runtime does not support (as `browserProjectRuntime` reports). */\n readonly unsupported: string[];\n /** Closes every shard's runtime (releasing bucket leases), then its worker. */\n close(): Promise<void>;\n}\n\n/** The page side: starts `shards` workers that each run `serveProjectShard`, wired together. */\nexport async function startProjectShards(opts: {\n shards: number;\n /** Starts one worker whose script calls `serveProjectShard`. */\n spawn: (shard: number) => Worker;\n config: BrowserProjectOptions[\"config\"];\n code: BrowserProjectOptions[\"code\"];\n assetFiles?: BrowserProjectOptions[\"assetFiles\"];\n /** The OpenAI-compatible endpoint behind the project's `ai` binding. */\n ai?: BrowserProjectOptions[\"ai\"];\n /** Each shard is its own fleet node, named `<node>-s<shard>`. */\n bucket?: BrowserBucket;\n /** Prefix of the shards' OPFS pools and files directories (`<name>-<shard>`). */\n name: string;\n}): Promise<ProjectShards> {\n const workers = Array.from({ length: opts.shards }, (_, i) => opts.spawn(i));\n const ask = (w: Worker, data: unknown, ports: MessagePort[] = []) =>\n new Promise<{ ok: boolean; error?: string; unsupported?: string[] }>((resolve) => {\n const { port1, port2 } = new MessageChannel();\n port1.onmessage = (e) => {\n port1.close();\n resolve(e.data);\n };\n w.postMessage(data, [port2, ...ports]);\n });\n // A channel between every two shards: one end links (sends to), the other is served.\n const wiring = workers.map(() => ({\n peers: [] as ShardInit[\"peers\"],\n ports: [] as MessagePort[],\n }));\n for (let i = 0; i < opts.shards; i++)\n for (let j = 0; j < opts.shards; j++) {\n if (i === j) continue;\n const { port1, port2 } = new MessageChannel();\n wiring[i].peers.push({ shard: j, role: \"link\" });\n wiring[i].ports.push(port1);\n wiring[j].peers.push({ shard: i, role: \"serve\" });\n wiring[j].ports.push(port2);\n }\n const ingress = workers.map(() => new MessageChannel());\n try {\n const started = await Promise.all(\n workers.map((w, i) =>\n ask(\n w,\n {\n type: INIT,\n shard: i,\n shards: opts.shards,\n config: opts.config,\n code: opts.code,\n assetFiles: opts.assetFiles,\n ai: opts.ai,\n bucket: opts.bucket && { ...opts.bucket, node: `${opts.bucket.node}-s${i}` },\n pool: `${opts.name}-${i}`,\n filesDir: `${opts.name}-files-${i}`,\n peers: wiring[i].peers,\n } satisfies ShardInit,\n [ingress[i].port2, ...wiring[i].ports],\n ),\n ),\n );\n const failed = started.find((r) => !r.ok);\n if (failed) throw new Error(`a project shard did not start: ${failed.error}`);\n const remotes = await Promise.all(ingress.map((c) => connectRuntime(c.port1)));\n let next = 0;\n return {\n fetch: (req) => remotes[next++ % remotes.length].fetch(req),\n shards: remotes,\n unsupported: started[0].unsupported ?? [],\n async close() {\n await Promise.all(remotes.map((r) => r.close()));\n await Promise.all(workers.map((w) => ask(w, { type: CLOSE })));\n for (const w of workers) w.terminate();\n },\n };\n } catch (err) {\n for (const w of workers) w.terminate();\n throw err;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"browser-shards.js","sourceRoot":"","sources":["../../src/project/browser-shards.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * One project in several browser workers, so that its cells run in parallel threads. Each worker\n * hosts the project with `browserProjectRuntime` and its own OPFS pool, owns the cells that\n * `shardOf(id, shards)` gives it, and reaches every other cell through the worker that owns it\n * over a MessagePort. Any worker takes ingress; the page spreads requests over them.\n *\n * page: startProjectShards({ shards, spawn, config, code, name }) → { fetch, close }\n * worker: serveProjectShard({ sqlite3 })\n *\n * Placement is fixed by the cell id (no rebalancing), and a closed page takes its workers along:\n * for cells that must outlive a tab, use a fleet bucket (`bucket`), as for one worker.\n */\nimport {\n serveHttpInWorker,\n type WorkerHttpService,\n webSocketUpgradeResponse,\n} from \"@statewalker/webrun-http-browser/sw\";\nimport { withUrl } from \"../core/request-body.js\";\nimport type { CellRuntimeOptions } from \"../core/runtime.js\";\nimport { shardOf } from \"../core/shard.js\";\nimport { cellsHttpHandler, type RemoteRuntime } from \"../transport/cells-http.js\";\nimport { H, keepUpgrade } from \"../transport/cells-link.js\";\nimport { connectRuntime, linkOverPort, serveRuntime } from \"../transport/port.js\";\nimport { CellsResponse, CfWebSocket, takeClientPort } from \"../ws/server.js\";\nimport {\n type BrowserBucket,\n type BrowserProjectOptions,\n browserProjectRuntime,\n} from \"./browser-host.js\";\n\nconst INIT = \"cellb:shard\";\nconst CLOSE = \"cellb:shard-close\";\n/**\n * A shard of a project shared by the tabs of an origin (`joinProjectShards`): it serves through\n * the ServiceWorker's router (webrun-http-browser's `serveHttpInWorker`), which the tab attaches\n * it to, and reaches the other shards through it.\n */\nexport const TAB_INIT = \"cellb:tab-shard\";\n/** The host calls between shards go to through the router: `http://cellb.internal/<project>/`. */\nexport const INTERNAL_ORIGIN = \"http://cellb.internal\";\n\n/** What a shard worker shared by tabs is told: no peers, it reaches them through the router. */\nexport interface TabShardInit {\n type: typeof TAB_INIT;\n name: string;\n shard: number;\n shards: number;\n config: BrowserProjectOptions[\"config\"];\n code: BrowserProjectOptions[\"code\"];\n assetFiles?: BrowserProjectOptions[\"assetFiles\"];\n /** The OpenAI-compatible endpoint behind the project's `ai` binding. */\n ai?: BrowserProjectOptions[\"ai\"];\n bucket?: BrowserBucket;\n pool: string;\n filesDir: string;\n}\n\n/** What a shard worker is told (the ports travel next to it). */\ninterface ShardInit {\n type: typeof INIT;\n shard: number;\n shards: number;\n config: BrowserProjectOptions[\"config\"];\n code: BrowserProjectOptions[\"code\"];\n assetFiles?: BrowserProjectOptions[\"assetFiles\"];\n /** The OpenAI-compatible endpoint behind the project's `ai` binding. */\n ai?: BrowserProjectOptions[\"ai\"];\n bucket?: BrowserBucket;\n pool: string;\n filesDir: string;\n /** For ports[2..]: the shard each port links to (`link`) or is served to (`serve`). */\n peers: { shard: number; role: \"link\" | \"serve\" }[];\n}\n\n/**\n * The worker side: hosts one shard when a page says so — of `startProjectShards` (peers wired\n * directly) or of `joinProjectShards` (shared by the tabs, linked to the ServiceWorker's router).\n * Messages of other types are left to the worker's own listeners.\n */\nexport function serveProjectShard(opts: {\n /** An initialized SQLite WASM module, or a function that makes one. */\n sqlite3: unknown | (() => Promise<unknown>);\n /** `browserProjectRuntime`'s `isolateScript`. */\n isolateScript?: URL;\n}): void {\n const scope = globalThis as unknown as {\n addEventListener(type: \"message\", fn: (e: MessageEvent) => void): void;\n postMessage(message: unknown): void;\n };\n let host: Awaited<ReturnType<typeof browserProjectRuntime>> | undefined;\n let service: WorkerHttpService | undefined;\n const sqlite3 = () =>\n typeof opts.sqlite3 === \"function\"\n ? (opts.sqlite3 as () => Promise<unknown>)()\n : Promise.resolve(opts.sqlite3);\n scope.addEventListener(\"message\", async (e: MessageEvent) => {\n const type = (e.data as { type?: string } | undefined)?.type;\n if (![INIT, CLOSE, TAB_INIT].includes(type as string)) return;\n const reply = e.ports[0] as MessagePort;\n try {\n if (type === CLOSE) {\n try {\n // The cells move elsewhere: their sockets' clients reconnect there now.\n CfWebSocket.goAway();\n await host?.close();\n } finally {\n host = undefined;\n // The router sees this shard's owner gone (its owner lock), even if closing failed.\n await service?.close().catch(() => {});\n service = undefined;\n }\n return reply.postMessage({ ok: true });\n }\n if (type === TAB_INIT) {\n const init = e.data as TabShardInit;\n let ready!: (s: WorkerHttpService) => void;\n const serviceReady = new Promise<WorkerHttpService>((r) => (ready = r));\n host = await browserProjectRuntime({\n config: init.config,\n code: init.code,\n assetFiles: init.assetFiles,\n ai: init.ai,\n bucket: init.bucket,\n sqlite3: await sqlite3(),\n pool: init.pool,\n filesDir: init.filesDir,\n isolateScript: opts.isolateScript,\n route: throughRouter(init, serviceReady),\n });\n // Served through the ServiceWorker's router, which the tab attaches this worker to. The\n // package keeps the link: an owner lock the router watches, re-linking after a restart,\n // keep-alive while calls are in flight.\n const handler = cellsHttpHandler(host.runtime, { passUpgrades: true });\n service = serveHttpInWorker(async (req) => upgradeOverPort(await handler(req)));\n ready(service);\n return reply.postMessage({ ok: true, unsupported: host.unsupported });\n }\n const init = e.data as ShardInit;\n const links = new Map<number, (req: Request) => Promise<Response>>();\n const served: MessagePort[] = [e.ports[1] as MessagePort]; // ingress from the page\n for (const [i, peer] of init.peers.entries()) {\n const port = e.ports[i + 2] as MessagePort;\n if (peer.role === \"link\") links.set(peer.shard, (await linkOverPort(port)).send);\n else served.push(port);\n }\n host = await browserProjectRuntime({\n config: init.config,\n code: init.code,\n assetFiles: init.assetFiles,\n ai: init.ai,\n bucket: init.bucket,\n sqlite3: await sqlite3(),\n pool: init.pool,\n filesDir: init.filesDir,\n isolateScript: opts.isolateScript,\n route: (_key, id) => {\n const owner = shardOf(id.toString(), init.shards);\n return owner === init.shard ? undefined : links.get(owner);\n },\n });\n for (const port of served) await serveRuntime(port, host.runtime);\n reply.postMessage({ ok: true, unsupported: host.unsupported });\n } catch (err) {\n reply.postMessage({ ok: false, error: String((err as Error)?.stack ?? err) });\n }\n });\n}\n\n/**\n * A 101 with a Workers WebSocket, as the ServiceWorker's router hands sockets over: the client\n * end's port in webrun-http-browser's 101.\n */\nfunction upgradeOverPort(res: Response): Response {\n const ws = (res as Response & { webSocket?: CfWebSocket | null }).webSocket;\n if (res.status !== 101 || !ws) return res;\n return webSocketUpgradeResponse(\n takeClientPort(ws),\n res.headers.get(\"Sec-WebSocket-Protocol\") ?? \"\",\n );\n}\n\n/**\n * The cells of other shards, through the ServiceWorker's router: a call goes to\n * `http://cellb.internal/<project>/` (the router's key for the project) naming its shard, with the\n * url it was made with in `H.url`; a socket opens through the router the same way.\n */\nfunction throughRouter(\n init: { name: string; shard: number; shards: number },\n service: Promise<WorkerHttpService>,\n): NonNullable<CellRuntimeOptions[\"route\"]> {\n const target = `${INTERNAL_ORIGIN}/${encodeURIComponent(init.name)}/`;\n return (_key, id) => {\n const owner = shardOf(id.toString(), init.shards);\n if (owner === init.shard) return undefined;\n // `postVia` (the runtime's) adds the scheme header and rethrows error responses.\n return async (req) => {\n const svc = await service;\n if (req.headers.get(\"upgrade\")?.toLowerCase() === \"websocket\") {\n const protocols = (req.headers.get(\"sec-websocket-protocol\") ?? \"\")\n .split(\",\")\n .map((p) => p.trim())\n .filter(Boolean);\n const headers: [string, string][] = [];\n for (const [k, v] of req.headers) if (k.startsWith(\"x-cellb\")) headers.push([k, v]);\n headers.push([H.shard, String(owner)], [H.url, req.url]);\n const { port, protocol } = await svc.connectWebSocket(target, protocols, headers);\n return new CellsResponse(null, {\n status: 101,\n webSocket: new CfWebSocket(port),\n headers: protocol ? { \"Sec-WebSocket-Protocol\": protocol } : {},\n });\n }\n const moved = await withUrl(req, target);\n const headers = new Headers(req.headers);\n headers.set(H.shard, String(owner));\n headers.set(H.url, req.url);\n try {\n return await svc.fetch(keepUpgrade(req, new Request(moved, { headers })));\n } catch (err) {\n // The words Worker code has always seen for it (CellRouter's), for a call the\n // ServiceWorker lost in flight only: a call that never left (no link, the handler\n // closed) keeps the package's words, as it was certainly not applied.\n if (\n err instanceof Error &&\n err.name === \"LinkLostError\" &&\n err.message.startsWith(\"The ServiceWorker was lost while this call was in flight\")\n )\n throw new Error(\n \"The router was lost while this call was in flight; it may or may not have been applied\",\n );\n throw err;\n }\n };\n };\n}\n\nexport interface ProjectShards {\n /** Ingress: a request to the project's Worker, in the next shard (round robin). */\n fetch(req: Request): Promise<Response>;\n /** The shards' runtimes, by shard number. */\n readonly shards: RemoteRuntime[];\n /** Configuration entries the runtime does not support (as `browserProjectRuntime` reports). */\n readonly unsupported: string[];\n /** Closes every shard's runtime (releasing bucket leases), then its worker. */\n close(): Promise<void>;\n}\n\n/** The page side: starts `shards` workers that each run `serveProjectShard`, wired together. */\nexport async function startProjectShards(opts: {\n shards: number;\n /** Starts one worker whose script calls `serveProjectShard`. */\n spawn: (shard: number) => Worker;\n config: BrowserProjectOptions[\"config\"];\n code: BrowserProjectOptions[\"code\"];\n assetFiles?: BrowserProjectOptions[\"assetFiles\"];\n /** The OpenAI-compatible endpoint behind the project's `ai` binding. */\n ai?: BrowserProjectOptions[\"ai\"];\n /** Each shard is its own fleet node, named `<node>-s<shard>`. */\n bucket?: BrowserBucket;\n /** Prefix of the shards' OPFS pools and files directories (`<name>-<shard>`). */\n name: string;\n}): Promise<ProjectShards> {\n const workers = Array.from({ length: opts.shards }, (_, i) => opts.spawn(i));\n const ask = (w: Worker, data: unknown, ports: MessagePort[] = []) =>\n new Promise<{ ok: boolean; error?: string; unsupported?: string[] }>((resolve) => {\n const { port1, port2 } = new MessageChannel();\n port1.onmessage = (e) => {\n port1.close();\n resolve(e.data);\n };\n w.postMessage(data, [port2, ...ports]);\n });\n // A channel between every two shards: one end links (sends to), the other is served.\n const wiring = workers.map(() => ({\n peers: [] as ShardInit[\"peers\"],\n ports: [] as MessagePort[],\n }));\n for (let i = 0; i < opts.shards; i++)\n for (let j = 0; j < opts.shards; j++) {\n if (i === j) continue;\n const { port1, port2 } = new MessageChannel();\n wiring[i].peers.push({ shard: j, role: \"link\" });\n wiring[i].ports.push(port1);\n wiring[j].peers.push({ shard: i, role: \"serve\" });\n wiring[j].ports.push(port2);\n }\n const ingress = workers.map(() => new MessageChannel());\n try {\n const started = await Promise.all(\n workers.map((w, i) =>\n ask(\n w,\n {\n type: INIT,\n shard: i,\n shards: opts.shards,\n config: opts.config,\n code: opts.code,\n assetFiles: opts.assetFiles,\n ai: opts.ai,\n bucket: opts.bucket && { ...opts.bucket, node: `${opts.bucket.node}-s${i}` },\n pool: `${opts.name}-${i}`,\n filesDir: `${opts.name}-files-${i}`,\n peers: wiring[i].peers,\n } satisfies ShardInit,\n [ingress[i].port2, ...wiring[i].ports],\n ),\n ),\n );\n const failed = started.find((r) => !r.ok);\n if (failed) throw new Error(`a project shard did not start: ${failed.error}`);\n const remotes = await Promise.all(ingress.map((c) => connectRuntime(c.port1)));\n let next = 0;\n return {\n fetch: (req) => remotes[next++ % remotes.length].fetch(req),\n shards: remotes,\n unsupported: started[0].unsupported ?? [],\n async close() {\n await Promise.all(remotes.map((r) => r.close()));\n await Promise.all(workers.map((w) => ask(w, { type: CLOSE })));\n for (const w of workers) w.terminate();\n },\n };\n } catch (err) {\n for (const w of workers) w.terminate();\n throw err;\n }\n}\n"]}
|