@statewalker/cellb 0.8.7 → 0.8.9
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 +1 -1
- package/dist/adapters/node-sqlite.js +42 -13
- package/dist/adapters/node-sqlite.js.map +1 -1
- package/dist/bindings/cjs-module.d.ts +7 -0
- package/dist/bindings/cjs-module.js +96 -0
- package/dist/bindings/cjs-module.js.map +1 -0
- package/dist/bindings/module-registry.d.ts +33 -0
- package/dist/bindings/module-registry.js +180 -0
- package/dist/bindings/module-registry.js.map +1 -0
- package/dist/bindings/worker-loader.d.ts +23 -5
- package/dist/bindings/worker-loader.js +75 -4
- package/dist/bindings/worker-loader.js.map +1 -1
- package/dist/core/handles.d.ts +21 -1
- package/dist/core/handles.js +49 -3
- package/dist/core/handles.js.map +1 -1
- package/dist/core/namespace.js +4 -1
- package/dist/core/namespace.js.map +1 -1
- package/dist/core/runtime.d.ts +8 -0
- package/dist/core/runtime.js +3 -3
- package/dist/core/runtime.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/isolate/browser.d.ts +1 -1
- package/dist/isolate/browser.js +3 -1
- package/dist/isolate/browser.js.map +1 -1
- package/dist/isolate/host.js +20 -2
- package/dist/isolate/host.js.map +1 -1
- package/dist/isolate/isolate-worker.js +13 -1
- package/dist/isolate/isolate-worker.js.map +1 -1
- package/dist/isolate/isolate.js +11 -0
- package/dist/isolate/isolate.js.map +1 -1
- package/dist/isolate/node-entry.js +33 -0
- package/dist/isolate/node-entry.js.map +1 -1
- package/dist/isolate/protocol.d.ts +1 -0
- package/dist/isolate/protocol.js +228 -13
- package/dist/isolate/protocol.js.map +1 -1
- package/dist/isolate/writable-globals.d.ts +9 -0
- package/dist/isolate/writable-globals.js +45 -0
- package/dist/isolate/writable-globals.js.map +1 -0
- package/dist/node-compat/bundle-files.d.ts +26 -0
- package/dist/node-compat/bundle-files.js +210 -0
- package/dist/node-compat/bundle-files.js.map +1 -0
- package/dist/node-compat/fs.d.ts +13 -1
- package/dist/node-compat/fs.js +54 -15
- package/dist/node-compat/fs.js.map +1 -1
- package/dist/project/browser-modules.d.ts +1 -1
- package/dist/project/browser-modules.js +25 -5
- package/dist/project/browser-modules.js.map +1 -1
- package/dist/project/cloudflare-workers.d.ts +9 -0
- package/dist/project/cloudflare-workers.js +14 -0
- package/dist/project/cloudflare-workers.js.map +1 -1
- package/dist/project/module-rules.js +31 -10
- package/dist/project/module-rules.js.map +1 -1
- package/dist/project/node-project.d.ts +2 -0
- package/dist/project/node-project.js +154 -25
- package/dist/project/node-project.js.map +1 -1
- package/dist/project/site-loader.js +2 -1
- package/dist/project/site-loader.js.map +1 -1
- package/dist/project/uint8array-base64.d.ts +7 -0
- package/dist/project/uint8array-base64.js +96 -0
- package/dist/project/uint8array-base64.js.map +1 -0
- package/dist/project/workers-globals-module.d.ts +1 -0
- package/dist/project/workers-globals-module.js +3 -0
- package/dist/project/workers-globals-module.js.map +1 -1
- package/dist/project/wrangler.js +8 -9
- package/dist/project/wrangler.js.map +1 -1
- package/dist/ws/upgrade.js +18 -1
- package/dist/ws/upgrade.js.map +1 -1
- package/package.json +10 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isolate.js","sourceRoot":"","sources":["../../src/isolate/isolate.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The isolate side: loads the Worker code in THIS realm and serves fetch/RPC for the host.\n * `importCode` is realm specific (data: URL of a bundle on Node, a site URL in browsers).\n */\nimport { ctxExports, entrypointStub } from \"../core/handles.js\";\nimport type { DurableObjectId } from \"../core/id.js\";\nimport { runInDurableObject } from \"../core/namespace.js\";\nimport { type CellRuntime, createCellRuntime, type WorkerModule } from \"../core/runtime.js\";\nimport type { Lease, LeaseHandle, OpenCellSql } from \"../ports.js\";\nimport { realmWorkerScope } from \"../project/worker-scope.js\";\nimport { CfWebSocket } from \"../ws/server.js\";\nimport { type FetchTarget, isolatePort, type PortLike } from \"./protocol.js\";\n\nexport function serveIsolate(\n port: PortLike,\n importCode: (\n load: any,\n logs: (level: string, args: unknown[]) => void,\n ) => Promise<Record<string, unknown>>,\n opts: {\n patchConsole?: boolean;\n /**\n * Storage for Durable Object classes run INSIDE this isolate (facets of loaded code):\n * each facet is a cell of an isolate-local runtime, with its own SQLite.\n */\n openSql?: (load: any) => OpenCellSql | Promise<OpenCellSql>;\n } = {},\n) {\n let module: Record<string, unknown> = {};\n const runtimes = new Map<string, CellRuntime>();\n // Facet logging through the host: the isolate-local cell key → the facet's key in the\n // root's storage (celld: <root>/facets/<sha>) and the root's epoch.\n const facetKeys = new Map<string, { key: string; epoch?: number }>();\n const images = new Map<number, () => unknown>();\n let nextImage = 0;\n const hostLogged = (internal: string) => facetKeys.get(internal);\n const durability = {\n capturePages: true,\n async committed(cellKey: string, info: any) {\n const f = hostLogged(cellKey);\n if (!f) return;\n const token = ++nextImage;\n if (typeof info.image === \"function\") images.set(token, info.image);\n try {\n await call({\n type: \"durable\",\n op: \"committed\",\n cellKey: f.key,\n info: {\n seq: info.seq,\n pages: info.pages,\n epoch: f.epoch,\n image: typeof info.image === \"function\" ? token : info.image,\n },\n });\n } finally {\n images.delete(token);\n }\n },\n };\n const backup = {\n async load(cellKey: string) {\n const f = hostLogged(cellKey);\n return f\n ? ((await call({ type: \"durable\", op: \"load\", cellKey: f.key })) as Uint8Array | undefined)\n : undefined;\n },\n async save() {},\n };\n // The host holds the root's lease and attaches each facet with its epoch: handing that epoch\n // out as the facet's own lease makes its ObjectHost rebuild the local database from the\n // bucket when it opens, as a root does under a lease (a pool kept from an earlier ownership\n // is older than what other nodes wrote since). Without an epoch, the local file stays primary.\n const ownership: Lease = {\n async tryAcquire(cellKey) {\n const lost = new AbortController().signal; // fencing stays with the root's lease, in the host\n return {\n name: cellKey,\n epoch: hostLogged(cellKey)?.epoch,\n lost,\n release: async () => {},\n } as LeaseHandle;\n },\n };\n let loadMsg: any;\n let sql: Promise<OpenCellSql> | undefined;\n const objectRuntime = async (className: string) => {\n let rt = runtimes.get(className);\n if (!rt) {\n if (!opts.openSql)\n throw new Error(\"this isolate cannot host Durable Object classes (no storage)\");\n sql ??= Promise.resolve(opts.openSql(loadMsg));\n const openSql = await sql;\n if (runtimes.has(className)) return runtimes.get(className)!;\n if (typeof module[className] !== \"function\")\n throw new Error(`Loaded worker does not export class \"${className}\"`);\n rt = createCellRuntime({\n worker: { ...(module as WorkerModule), default: {} },\n durableObjects: { [className]: { className } },\n openSql,\n vars: env, // the loaded Worker's env: plain values and host stubs\n storage: { durability, backup, ownership },\n facets: true, // rows move to this run's scope on open, as celld does for facets\n ctxIdOf: (key) => {\n const name = idNames.get(key);\n return name === undefined\n ? undefined\n : (rt!.env[className] as { idFromName(n: string): DurableObjectId }).idFromName(name);\n },\n });\n runtimes.set(className, rt);\n }\n return rt;\n };\n let env: Record<string, unknown> = {};\n let exports: Record<string, unknown> = {};\n // The loaded Worker is this realm's own: its `cloudflare:workers` reads `env` and `exports` here.\n const scope = realmWorkerScope();\n // The name of the `id` a facet was given by `ctx.facets.get`, by its isolate-local cell key:\n // the facet's `ctx.id` (partyserver's `this.name`). Two facets may be given the same id; each\n // keeps its own object and storage, addressed by the parent's facet cell key.\n const idNames = new Map<string, string>();\n // A facet of loaded code: the object lives here, named by the parent's facet cell key.\n const facet = async (className: string, cellKey: string) => {\n const rt = await objectRuntime(className);\n const ns = rt.env[className] as {\n getByName(n: string): any;\n idFromName(n: string): { toString(): string };\n };\n return { rt, stub: ns.getByName(cellKey), key: `${className}/${ns.idFromName(cellKey)}` };\n };\n const exported = (name: string, props?: unknown) => {\n const target = module[name];\n if (target === undefined) throw new Error(`Loaded worker does not export \"${name}\"`);\n return entrypointStub(target, env, props, exports);\n };\n const fetchTarget = async (t: FetchTarget, req: Request): Promise<Response> =>\n \"className\" in t\n ? (await facet(t.className, t.cellKey)).stub.fetch(req)\n : exported(t.name, t.props).fetch(req);\n const handle = async (m: any) => {\n if (m.type === \"load\") {\n loadMsg = m;\n env = m.env; // host bindings arrive as stubs: every call goes back to the host\n // Logs go to the host (Tail Workers, and the host prints them): through the global\n // console, or — where the realm has other code that logs — a console scoped to the\n // loaded modules (importCode receives the sink).\n const sink = (level: string, args: unknown[]) =>\n call({ type: \"log\", level, args: safe(args) }).catch(() => {});\n if (opts.patchConsole !== false)\n for (const level of [\"log\", \"info\", \"warn\", \"error\", \"debug\"] as const)\n console[level] = (...args: unknown[]) => sink(level, args);\n if (m.outbound === \"fetcher\")\n globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) =>\n outbound(new Request(input, init))) as typeof fetch;\n if (m.outbound === \"blocked\")\n globalThis.fetch = (async () => {\n throw new Error(\n \"This worker is not permitted to access the internet via global functions like fetch(). It must use capabilities (such as bindings in 'env') to talk to the outside world.\",\n );\n }) as typeof fetch;\n scope.bind({ env, exports }); // read while the module is evaluated\n module = await importCode(m, sink);\n exports = ctxExports(module, env);\n scope.bind({ env, exports });\n return Object.fromEntries(Object.entries(module).map(([k, v]) => [k, typeof v]));\n }\n if (m.type === \"image\") return await images.get(m.token)?.();\n // The host is stopping this isolate: the sockets served here hear 1001 first. A 101 carries\n // its early frames, so a socket's close normally goes straight to its client; only a client\n // end that had sent unacknowledged frames before its hand-over keeps a relay here\n // (takeClientEnd), and the answer waits a macrotask so that relay forwards the 1001 before\n // the host terminates the isolate.\n if (m.type === \"goAway\") {\n CfWebSocket.goAway(\"the loaded Worker stopped\");\n return await new Promise((r) => setTimeout(r, 0));\n }\n if (m.type === \"object\") {\n const { rt, stub, key } = await facet(m.className, m.cellKey);\n if (m.op === \"attach\") {\n facetKeys.set(key, { key: m.cellKey, epoch: m.epoch });\n if (typeof m.idName === \"string\") idNames.set(key, m.idName);\n return;\n }\n if (m.op === \"call\") return stub[m.method](...m.args);\n if (m.op === \"restart\") return rt.restartObject(key);\n if (m.op === \"delete\") {\n await runInDurableObject(\n stub,\n (_o: unknown, ctx: { storage: { deleteAll(): Promise<void> } }) =>\n ctx.storage.deleteAll(),\n );\n return rt.restartObject(key);\n }\n throw new Error(`unknown object op ${m.op}`);\n }\n if (m.type === \"call\") return exported(m.name, m.props)[m.method](...m.args);\n throw new Error(`unknown isolate message ${m.type}`);\n };\n const { call, outbound } = isolatePort(port, handle, fetchTarget);\n}\n\nconst safe = (args: unknown[]) =>\n args.map((a) => {\n try {\n return structuredClone(a);\n } catch {\n return String(a);\n }\n });\n"]}
|
|
1
|
+
{"version":3,"file":"isolate.js","sourceRoot":"","sources":["../../src/isolate/isolate.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The isolate side: loads the Worker code in THIS realm and serves fetch/RPC for the host.\n * `importCode` is realm specific (data: URL of a bundle on Node, a site URL in browsers).\n */\nimport { registerWasmModules } from \"../bindings/worker-loader.js\";\nimport { ctxExports, entrypointStub } from \"../core/handles.js\";\nimport type { DurableObjectId } from \"../core/id.js\";\nimport { runInDurableObject } from \"../core/namespace.js\";\nimport { type CellRuntime, createCellRuntime, type WorkerModule } from \"../core/runtime.js\";\nimport type { Lease, LeaseHandle, OpenCellSql } from \"../ports.js\";\nimport { ABORT_ISOLATE } from \"../project/cloudflare-workers.js\";\nimport { realmWorkerScope } from \"../project/worker-scope.js\";\nimport { CfWebSocket } from \"../ws/server.js\";\nimport { type FetchTarget, isolatePort, type PortLike } from \"./protocol.js\";\n\nexport function serveIsolate(\n port: PortLike,\n importCode: (\n load: any,\n logs: (level: string, args: unknown[]) => void,\n ) => Promise<Record<string, unknown>>,\n opts: {\n patchConsole?: boolean;\n /**\n * Storage for Durable Object classes run INSIDE this isolate (facets of loaded code):\n * each facet is a cell of an isolate-local runtime, with its own SQLite.\n */\n openSql?: (load: any) => OpenCellSql | Promise<OpenCellSql>;\n } = {},\n) {\n let module: Record<string, unknown> = {};\n const runtimes = new Map<string, CellRuntime>();\n // Facet logging through the host: the isolate-local cell key → the facet's key in the\n // root's storage (celld: <root>/facets/<sha>) and the root's epoch.\n const facetKeys = new Map<string, { key: string; epoch?: number }>();\n const images = new Map<number, () => unknown>();\n let nextImage = 0;\n const hostLogged = (internal: string) => facetKeys.get(internal);\n const durability = {\n capturePages: true,\n async committed(cellKey: string, info: any) {\n const f = hostLogged(cellKey);\n if (!f) return;\n const token = ++nextImage;\n if (typeof info.image === \"function\") images.set(token, info.image);\n try {\n await call({\n type: \"durable\",\n op: \"committed\",\n cellKey: f.key,\n info: {\n seq: info.seq,\n pages: info.pages,\n epoch: f.epoch,\n image: typeof info.image === \"function\" ? token : info.image,\n },\n });\n } finally {\n images.delete(token);\n }\n },\n };\n const backup = {\n async load(cellKey: string) {\n const f = hostLogged(cellKey);\n return f\n ? ((await call({ type: \"durable\", op: \"load\", cellKey: f.key })) as Uint8Array | undefined)\n : undefined;\n },\n async save() {},\n };\n // The host holds the root's lease and attaches each facet with its epoch: handing that epoch\n // out as the facet's own lease makes its ObjectHost rebuild the local database from the\n // bucket when it opens, as a root does under a lease (a pool kept from an earlier ownership\n // is older than what other nodes wrote since). Without an epoch, the local file stays primary.\n const ownership: Lease = {\n async tryAcquire(cellKey) {\n const lost = new AbortController().signal; // fencing stays with the root's lease, in the host\n return {\n name: cellKey,\n epoch: hostLogged(cellKey)?.epoch,\n lost,\n release: async () => {},\n } as LeaseHandle;\n },\n };\n let loadMsg: any;\n let sql: Promise<OpenCellSql> | undefined;\n const objectRuntime = async (className: string) => {\n let rt = runtimes.get(className);\n if (!rt) {\n if (!opts.openSql)\n throw new Error(\"this isolate cannot host Durable Object classes (no storage)\");\n sql ??= Promise.resolve(opts.openSql(loadMsg));\n const openSql = await sql;\n if (runtimes.has(className)) return runtimes.get(className)!;\n if (typeof module[className] !== \"function\")\n throw new Error(`Loaded worker does not export class \"${className}\"`);\n rt = createCellRuntime({\n worker: { ...(module as WorkerModule), default: {} },\n durableObjects: { [className]: { className } },\n openSql,\n vars: env, // the loaded Worker's env: plain values and host stubs\n storage: { durability, backup, ownership },\n facets: true, // rows move to this run's scope on open, as celld does for facets\n ctxIdOf: (key) => {\n const name = idNames.get(key);\n return name === undefined\n ? undefined\n : (rt!.env[className] as { idFromName(n: string): DurableObjectId }).idFromName(name);\n },\n });\n runtimes.set(className, rt);\n }\n return rt;\n };\n let env: Record<string, unknown> = {};\n let exports: Record<string, unknown> = {};\n // The loaded Worker is this realm's own: its `cloudflare:workers` reads `env` and `exports` here.\n const scope = realmWorkerScope();\n // The name of the `id` a facet was given by `ctx.facets.get`, by its isolate-local cell key:\n // the facet's `ctx.id` (partyserver's `this.name`). Two facets may be given the same id; each\n // keeps its own object and storage, addressed by the parent's facet cell key.\n const idNames = new Map<string, string>();\n // A facet of loaded code: the object lives here, named by the parent's facet cell key.\n const facet = async (className: string, cellKey: string) => {\n const rt = await objectRuntime(className);\n const ns = rt.env[className] as {\n getByName(n: string): any;\n idFromName(n: string): { toString(): string };\n };\n return { rt, stub: ns.getByName(cellKey), key: `${className}/${ns.idFromName(cellKey)}` };\n };\n const exported = (name: string, props?: unknown) => {\n const target = module[name];\n if (target === undefined) throw new Error(`Loaded worker does not export \"${name}\"`);\n return entrypointStub(target, env, props, exports);\n };\n const fetchTarget = async (t: FetchTarget, req: Request): Promise<Response> =>\n \"className\" in t\n ? (await facet(t.className, t.cellKey)).stub.fetch(req)\n : exported(t.name, t.props).fetch(req);\n const handle = async (m: any) => {\n if (m.type === \"load\") {\n loadMsg = m;\n env = m.env; // host bindings arrive as stubs: every call goes back to the host\n // Logs go to the host (Tail Workers, and the host prints them): through the global\n // console, or — where the realm has other code that logs — a console scoped to the\n // loaded modules (importCode receives the sink).\n const sink = (level: string, args: unknown[]) =>\n call({ type: \"log\", level, args: safe(args) }).catch(() => {});\n if (opts.patchConsole !== false)\n for (const level of [\"log\", \"info\", \"warn\", \"error\", \"debug\"] as const)\n console[level] = (...args: unknown[]) => sink(level, args);\n if (m.outbound === \"fetcher\")\n globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) =>\n outbound(new Request(input, init))) as typeof fetch;\n if (m.outbound === \"blocked\")\n globalThis.fetch = (async () => {\n throw new Error(\n \"This worker is not permitted to access the internet via global functions like fetch(). It must use capabilities (such as bindings in 'env') to talk to the outside world.\",\n );\n }) as typeof fetch;\n if (m.wasm) registerWasmModules(m.wasm); // compiled by the host (Node: wasmModulesOf)\n scope.bind({ env, exports }); // read while the module is evaluated\n module = await importCode(m, sink);\n exports = ctxExports(module, env);\n scope.bind({ env, exports });\n return Object.fromEntries(Object.entries(module).map(([k, v]) => [k, typeof v]));\n }\n if (m.type === \"image\") return await images.get(m.token)?.();\n // The host is stopping this isolate: the sockets served here hear 1001 first. A 101 carries\n // its early frames, so a socket's close normally goes straight to its client; only a client\n // end that had sent unacknowledged frames before its hand-over keeps a relay here\n // (takeClientEnd), and the answer waits a macrotask so that relay forwards the 1001 before\n // the host terminates the isolate.\n if (m.type === \"goAway\") {\n CfWebSocket.goAway(\"the loaded Worker stopped\");\n return await new Promise((r) => setTimeout(r, 0));\n }\n if (m.type === \"object\") {\n const { rt, stub, key } = await facet(m.className, m.cellKey);\n if (m.op === \"attach\") {\n facetKeys.set(key, { key: m.cellKey, epoch: m.epoch });\n if (typeof m.idName === \"string\") idNames.set(key, m.idName);\n return;\n }\n if (m.op === \"call\") return stub[m.method](...m.args);\n if (m.op === \"restart\") return rt.restartObject(key);\n if (m.op === \"delete\") {\n await runInDurableObject(\n stub,\n (_o: unknown, ctx: { storage: { deleteAll(): Promise<void> } }) =>\n ctx.storage.deleteAll(),\n );\n return rt.restartObject(key);\n }\n throw new Error(`unknown object op ${m.op}`);\n }\n if (m.type === \"call\") return exported(m.name, m.props)[m.method](...m.args);\n throw new Error(`unknown isolate message ${m.type}`);\n };\n const { call, outbound } = isolatePort(port, handle, fetchTarget);\n // `abortIsolate()`: the host ends this isolate. The caller sees workerd's error: the call that\n // aborted rejects with it, as do the host's calls in flight (the host closes the port with it).\n (globalThis as Record<symbol, unknown>)[ABORT_ISOLATE] = (reason: unknown): never => {\n const reference = crypto.randomUUID().replace(/-/g, \"\").slice(0, 24);\n void call({ type: \"abort\", reason: String(reason ?? \"\"), reference }).catch(() => {});\n throw new Error(`internal error; reference = ${reference}`);\n };\n}\n\nconst safe = (args: unknown[]) =>\n args.map((a) => {\n try {\n return structuredClone(a);\n } catch {\n return String(a);\n }\n });\n"]}
|
|
@@ -1,11 +1,44 @@
|
|
|
1
1
|
// A worker thread hosting ONE loaded Worker (an isolate); see src/isolate/protocol.ts.
|
|
2
|
+
import * as nodeModule from "node:module";
|
|
2
3
|
import { parentPort } from "node:worker_threads";
|
|
3
4
|
import { nodeSqliteOpener } from "../adapters/node-sqlite.js";
|
|
5
|
+
import { loadedModuleShim, resolveModuleName } from "../bindings/module-registry.js";
|
|
4
6
|
import { CellsRequest, CellsResponse, WebSocket, WebSocketPair, WebSocketRequestResponsePair, } from "../project/workers-globals-module.js";
|
|
5
7
|
import { serveIsolate } from "./isolate.js";
|
|
8
|
+
import { makeGlobalsWritable } from "./writable-globals.js";
|
|
6
9
|
// An exception no request awaits (a timer, ctx.abort() from one) is reported, and the isolate
|
|
7
10
|
// lives on, as in a browser Dedicated Worker and workerd; Node would end the thread.
|
|
8
11
|
process.on("uncaughtException", (e) => console.error("Uncaught", e));
|
|
12
|
+
// workerd lets Worker code assign its globals (Kitesurf's DOM shim sets `navigator` and
|
|
13
|
+
// `location`); this realm's getter-only ones become writable (writable-globals.ts).
|
|
14
|
+
makeGlobalsWritable();
|
|
15
|
+
// `import()` in code the loaded Worker builds with `Function` (Kitesurf imports page modules so)
|
|
16
|
+
// names its modules as on workerd, but no bundler saw it: this thread's module hooks resolve such
|
|
17
|
+
// a specifier against the loaded Worker's modules (the registry its bundle publishes) and load a
|
|
18
|
+
// shim that re-exports the bundled module. `registerHooks` is in Node 22.15 and later.
|
|
19
|
+
const LOADED = "cellb-loaded:";
|
|
20
|
+
const registerHooks = nodeModule.registerHooks;
|
|
21
|
+
registerHooks?.({
|
|
22
|
+
resolve(spec, context, next) {
|
|
23
|
+
const loaded = globalThis.__cellbLoadedModules;
|
|
24
|
+
const fromBundle = !context.parentURL || context.parentURL.startsWith("data:");
|
|
25
|
+
const name = loaded && fromBundle ? resolveModuleName(spec, loaded.main, loaded.names) : undefined;
|
|
26
|
+
if (name === undefined)
|
|
27
|
+
return next(spec, context);
|
|
28
|
+
return { url: LOADED + encodeURIComponent(name), shortCircuit: true };
|
|
29
|
+
},
|
|
30
|
+
load(url, context, next) {
|
|
31
|
+
if (!url.startsWith(LOADED))
|
|
32
|
+
return next(url, context);
|
|
33
|
+
const name = decodeURIComponent(url.slice(LOADED.length));
|
|
34
|
+
const loaded = globalThis.__cellbLoadedModules;
|
|
35
|
+
return {
|
|
36
|
+
format: "module",
|
|
37
|
+
shortCircuit: true,
|
|
38
|
+
source: loadedModuleShim(name, loaded?.exportNames[name] ?? []),
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
});
|
|
9
42
|
// This thread is the loaded Worker's realm: its globals are the Workers ones, as in a browser
|
|
10
43
|
// isolate (src/isolate/isolate-worker.ts). A `Response` that takes `{ status: 101, webSocket }`
|
|
11
44
|
// and a `WebSocketPair` are what a Worker that accepts WebSockets needs.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-entry.js","sourceRoot":"","sources":["../../src/isolate/node-entry.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EACL,YAAY,EACZ,aAAa,EACb,SAAS,EACT,aAAa,EACb,4BAA4B,GAC7B,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"node-entry.js","sourceRoot":"","sources":["../../src/isolate/node-entry.ts"],"names":[],"mappings":"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","sourcesContent":["// A worker thread hosting ONE loaded Worker (an isolate); see src/isolate/protocol.ts.\nimport * as nodeModule from \"node:module\";\nimport { parentPort } from \"node:worker_threads\";\nimport { nodeSqliteOpener } from \"../adapters/node-sqlite.js\";\nimport { loadedModuleShim, resolveModuleName } from \"../bindings/module-registry.js\";\nimport {\n CellsRequest,\n CellsResponse,\n WebSocket,\n WebSocketPair,\n WebSocketRequestResponsePair,\n} from \"../project/workers-globals-module.js\";\nimport { serveIsolate } from \"./isolate.js\";\nimport type { PortLike } from \"./protocol.js\";\nimport { makeGlobalsWritable } from \"./writable-globals.js\";\n\n// An exception no request awaits (a timer, ctx.abort() from one) is reported, and the isolate\n// lives on, as in a browser Dedicated Worker and workerd; Node would end the thread.\nprocess.on(\"uncaughtException\", (e) => console.error(\"Uncaught\", e));\n\n// workerd lets Worker code assign its globals (Kitesurf's DOM shim sets `navigator` and\n// `location`); this realm's getter-only ones become writable (writable-globals.ts).\nmakeGlobalsWritable();\n\n// `import()` in code the loaded Worker builds with `Function` (Kitesurf imports page modules so)\n// names its modules as on workerd, but no bundler saw it: this thread's module hooks resolve such\n// a specifier against the loaded Worker's modules (the registry its bundle publishes) and load a\n// shim that re-exports the bundled module. `registerHooks` is in Node 22.15 and later.\nconst LOADED = \"cellb-loaded:\";\ntype LoadedModules = { main: string; names: Set<string>; exportNames: Record<string, string[]> };\nconst registerHooks = (nodeModule as { registerHooks?: (hooks: object) => unknown }).registerHooks;\nregisterHooks?.({\n resolve(spec: string, context: { parentURL?: string }, next: (s: string, c: object) => unknown) {\n const loaded = (globalThis as { __cellbLoadedModules?: LoadedModules }).__cellbLoadedModules;\n const fromBundle = !context.parentURL || context.parentURL.startsWith(\"data:\");\n const name =\n loaded && fromBundle ? resolveModuleName(spec, loaded.main, loaded.names) : undefined;\n if (name === undefined) return next(spec, context);\n return { url: LOADED + encodeURIComponent(name), shortCircuit: true };\n },\n load(url: string, context: object, next: (u: string, c: object) => unknown) {\n if (!url.startsWith(LOADED)) return next(url, context);\n const name = decodeURIComponent(url.slice(LOADED.length));\n const loaded = (globalThis as { __cellbLoadedModules?: LoadedModules }).__cellbLoadedModules;\n return {\n format: \"module\",\n shortCircuit: true,\n source: loadedModuleShim(name, loaded?.exportNames[name] ?? []),\n };\n },\n});\n\n// This thread is the loaded Worker's realm: its globals are the Workers ones, as in a browser\n// isolate (src/isolate/isolate-worker.ts). A `Response` that takes `{ status: 101, webSocket }`\n// and a `WebSocketPair` are what a Worker that accepts WebSockets needs.\nObject.assign(globalThis, {\n Request: CellsRequest,\n Response: CellsResponse,\n WebSocket,\n WebSocketPair,\n WebSocketRequestResponsePair,\n});\n\nserveIsolate(\n parentPort as unknown as PortLike,\n async ({ source }) =>\n import(`data:text/javascript;base64,${Buffer.from(source ?? \"\").toString(\"base64\")}`),\n // Facets of the loaded code keep their SQLite here: files under `dataDir` when the host\n // gives one, else temporary files (lost with the isolate, as in memory). The isolate logs\n // every commit's pages to its host, so they are read from the WAL, not from an image.\n { openSql: (load) => nodeSqliteOpener(load?.dataDir, { pageCapture: true }) },\n);\n"]}
|
|
@@ -60,6 +60,7 @@ type Handle = (msg: any) => Promise<unknown>;
|
|
|
60
60
|
export declare function hostPort(port: PortLike, handle: Handle, outbound?: (req: Request) => Promise<Response>): Promise<{
|
|
61
61
|
call: Call;
|
|
62
62
|
fetch: Fetch;
|
|
63
|
+
close(reason: unknown): Promise<void>;
|
|
63
64
|
}>;
|
|
64
65
|
/**
|
|
65
66
|
* The isolate's end: accepts the ports the host opens. Everything the isolate calls the host
|
package/dist/isolate/protocol.js
CHANGED
|
@@ -11,23 +11,27 @@ import { carryWebSocketHeaders } from "../ws/upgrade.js";
|
|
|
11
11
|
* `fetch()` (its `globalOutbound` Fetcher).
|
|
12
12
|
*/
|
|
13
13
|
export async function hostPort(port, handle, outbound) {
|
|
14
|
+
const bodies = new Bodies();
|
|
14
15
|
const mux = multiplexPort(messageTarget(port), {
|
|
15
16
|
codec: structuredCodec,
|
|
16
17
|
side: "initiator",
|
|
17
18
|
maxPorts: maxPorts(),
|
|
18
19
|
onPort(p, meta) {
|
|
19
20
|
const m = meta;
|
|
21
|
+
if (m?.kind === "body")
|
|
22
|
+
return bodies.serve(p, m.id);
|
|
20
23
|
if (m?.kind !== "outbound" || !outbound)
|
|
21
24
|
return false;
|
|
22
25
|
serveFetch(p, m.url, outbound);
|
|
23
26
|
return true;
|
|
24
27
|
},
|
|
25
28
|
});
|
|
26
|
-
const call = callsOver(await mux.openPort({ kind: "calls" }), handle);
|
|
29
|
+
const call = callsOver(await mux.openPort({ kind: "calls" }), handle, mux, bodies);
|
|
27
30
|
const fetch = (target, req) => isUpgrade(req)
|
|
28
31
|
? upgradeOver(mux, { kind: "upgrade", target }, req)
|
|
29
32
|
: fetchOver(mux, { kind: "fetch", target }, req);
|
|
30
|
-
|
|
33
|
+
// Closing the multiplexer rejects every call in flight, and every later one, with `reason`.
|
|
34
|
+
return { call, fetch, close: (reason) => mux.close(reason) };
|
|
31
35
|
}
|
|
32
36
|
/**
|
|
33
37
|
* The isolate's end: accepts the ports the host opens. Everything the isolate calls the host
|
|
@@ -36,12 +40,15 @@ export async function hostPort(port, handle, outbound) {
|
|
|
36
40
|
*/
|
|
37
41
|
export function isolatePort(port, handle, fetch) {
|
|
38
42
|
let calls;
|
|
43
|
+
const bodies = new Bodies();
|
|
39
44
|
const mux = multiplexPort(messageTarget(port), {
|
|
40
45
|
codec: structuredCodec,
|
|
41
46
|
side: "responder",
|
|
42
47
|
maxPorts: maxPorts(),
|
|
43
48
|
onPort(p, meta) {
|
|
44
49
|
const m = meta;
|
|
50
|
+
if (m?.kind === "body")
|
|
51
|
+
return bodies.serve(p, m.id);
|
|
45
52
|
if (m?.kind === "fetch") {
|
|
46
53
|
serveFetch(p, m.url, (r) => fetch(m.target, r));
|
|
47
54
|
return true;
|
|
@@ -52,7 +59,7 @@ export function isolatePort(port, handle, fetch) {
|
|
|
52
59
|
}
|
|
53
60
|
if (m?.kind !== "calls" || calls)
|
|
54
61
|
return false;
|
|
55
|
-
calls = callsOver(p, handle);
|
|
62
|
+
calls = callsOver(p, handle, mux, bodies);
|
|
56
63
|
return true;
|
|
57
64
|
},
|
|
58
65
|
});
|
|
@@ -173,6 +180,170 @@ function serveUpgrade(p, meta, fetch) {
|
|
|
173
180
|
void p.close?.();
|
|
174
181
|
})();
|
|
175
182
|
}
|
|
183
|
+
/** Marks a Request, Response, Headers or ReadableStream in a message: `{ [WIRE]: kind, … }`. */
|
|
184
|
+
const WIRE = "\u0000cellb.wire";
|
|
185
|
+
// The realm's own classes, before the isolate entry replaces the globals with its subclasses
|
|
186
|
+
// (CellsRequest, CellsResponse): instances of either are instances of these.
|
|
187
|
+
const NativeRequest = globalThis.Request;
|
|
188
|
+
const NativeResponse = globalThis.Response;
|
|
189
|
+
const NativeHeaders = globalThis.Headers;
|
|
190
|
+
const NativeReadableStream = globalThis.ReadableStream;
|
|
191
|
+
/**
|
|
192
|
+
* The bodies one side has sent and the other has not read yet, by id. The reader opens a port
|
|
193
|
+
* `{ kind: "body", id }` on the multiplexer when it first pulls, and the body streams over it,
|
|
194
|
+
* as a fetch's body does; a reader that drops the body unread sends `release {body}` instead.
|
|
195
|
+
*/
|
|
196
|
+
class Bodies {
|
|
197
|
+
#last = 0;
|
|
198
|
+
#streams = new Map();
|
|
199
|
+
add(stream) {
|
|
200
|
+
this.#streams.set(++this.#last, stream);
|
|
201
|
+
return this.#last;
|
|
202
|
+
}
|
|
203
|
+
/** The last id handed out, for `releaseSince`. */
|
|
204
|
+
mark() {
|
|
205
|
+
return this.#last;
|
|
206
|
+
}
|
|
207
|
+
/** Releases the bodies added after `mark` (a message that could not be sent). */
|
|
208
|
+
releaseSince(mark) {
|
|
209
|
+
for (let id = mark + 1; id <= this.#last; id++)
|
|
210
|
+
this.release(id);
|
|
211
|
+
}
|
|
212
|
+
release(id) {
|
|
213
|
+
const stream = this.#streams.get(id);
|
|
214
|
+
this.#streams.delete(id);
|
|
215
|
+
void stream?.cancel().catch(() => { });
|
|
216
|
+
}
|
|
217
|
+
/** Serves body `id` on port `p`; false (the port is refused) if there is no such body. */
|
|
218
|
+
serve(p, id) {
|
|
219
|
+
const stream = this.#streams.get(id);
|
|
220
|
+
if (!stream)
|
|
221
|
+
return false;
|
|
222
|
+
this.#streams.delete(id);
|
|
223
|
+
const encoder = new TextEncoder();
|
|
224
|
+
serveDuplexOverPort(p, async function* () {
|
|
225
|
+
// A reader, not `for await`: not every engine iterates a ReadableStream (Safari).
|
|
226
|
+
const reader = stream.getReader();
|
|
227
|
+
try {
|
|
228
|
+
for (;;) {
|
|
229
|
+
const { done, value: chunk } = await reader.read();
|
|
230
|
+
if (done)
|
|
231
|
+
return;
|
|
232
|
+
yield typeof chunk === "string"
|
|
233
|
+
? encoder.encode(chunk)
|
|
234
|
+
: ArrayBuffer.isView(chunk)
|
|
235
|
+
? new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength)
|
|
236
|
+
: new Uint8Array(chunk);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
finally {
|
|
240
|
+
// The reader stopped early (the port was abandoned): the stream is cancelled.
|
|
241
|
+
void reader.cancel().catch(() => { });
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* A Request, Response, Headers or ReadableStream as a message can carry it (workerd's RPC passes
|
|
249
|
+
* them; a port cannot clone them): its head copied, its body registered in `bodies` to stream
|
|
250
|
+
* when read. Anything else is returned as it is.
|
|
251
|
+
*/
|
|
252
|
+
function toWire(v, bodies) {
|
|
253
|
+
if (v instanceof NativeHeaders)
|
|
254
|
+
return { [WIRE]: "headers", entries: [...v] };
|
|
255
|
+
if (v instanceof NativeReadableStream)
|
|
256
|
+
return { [WIRE]: "stream", body: bodies.add(v) };
|
|
257
|
+
if (v instanceof NativeResponse) {
|
|
258
|
+
if (v.webSocket)
|
|
259
|
+
throw new DOMException("A WebSocket response cannot be passed in an RPC call; return it from fetch().", "DataCloneError");
|
|
260
|
+
return {
|
|
261
|
+
[WIRE]: "response",
|
|
262
|
+
status: v.status,
|
|
263
|
+
statusText: v.statusText,
|
|
264
|
+
url: v.url,
|
|
265
|
+
headers: [...v.headers],
|
|
266
|
+
body: v.body ? bodies.add(v.body) : null,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
if (v instanceof NativeRequest)
|
|
270
|
+
return {
|
|
271
|
+
[WIRE]: "request",
|
|
272
|
+
url: v.url,
|
|
273
|
+
method: v.method,
|
|
274
|
+
headers: [...v.headers],
|
|
275
|
+
redirect: v.redirect,
|
|
276
|
+
body: v.body ? bodies.add(v.body) : null,
|
|
277
|
+
};
|
|
278
|
+
return v;
|
|
279
|
+
}
|
|
280
|
+
/** Releases a body that was never read, once its stream is collected. */
|
|
281
|
+
const unread = new FinalizationRegistry((release) => release());
|
|
282
|
+
/**
|
|
283
|
+
* The other side's body `id` as a stream: the first pull opens its port, so a body nobody
|
|
284
|
+
* reads costs nothing but its release.
|
|
285
|
+
*/
|
|
286
|
+
function remoteBody(mux, id, release) {
|
|
287
|
+
let chunks;
|
|
288
|
+
const token = {};
|
|
289
|
+
const stream = new NativeReadableStream({
|
|
290
|
+
async pull(controller) {
|
|
291
|
+
if (!chunks) {
|
|
292
|
+
unread.unregister(token);
|
|
293
|
+
const port = await mux.openPort({ kind: "body", id });
|
|
294
|
+
chunks = duplexOverPort(port)([])[Symbol.asyncIterator]();
|
|
295
|
+
}
|
|
296
|
+
const { done, value } = await chunks.next();
|
|
297
|
+
if (done)
|
|
298
|
+
controller.close();
|
|
299
|
+
else
|
|
300
|
+
controller.enqueue(value);
|
|
301
|
+
},
|
|
302
|
+
async cancel(reason) {
|
|
303
|
+
if (chunks)
|
|
304
|
+
await chunks.return?.(reason);
|
|
305
|
+
else {
|
|
306
|
+
unread.unregister(token);
|
|
307
|
+
release(id);
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
});
|
|
311
|
+
unread.register(stream, () => release(id), token);
|
|
312
|
+
return stream;
|
|
313
|
+
}
|
|
314
|
+
/** Statuses whose Response has no body. */
|
|
315
|
+
const NULL_BODY = [101, 103, 204, 205, 304];
|
|
316
|
+
/** The value `toWire` described, rebuilt; its body streams from the other side when read. */
|
|
317
|
+
function fromWire(v, mux, release) {
|
|
318
|
+
const body = (id) => (id === null ? null : remoteBody(mux, id, release));
|
|
319
|
+
switch (v[WIRE]) {
|
|
320
|
+
case "headers":
|
|
321
|
+
return new Headers(v.entries);
|
|
322
|
+
case "stream":
|
|
323
|
+
return body(v.body);
|
|
324
|
+
case "response": {
|
|
325
|
+
if (NULL_BODY.includes(v.status) && v.body !== null)
|
|
326
|
+
release(v.body);
|
|
327
|
+
const res = new Response(NULL_BODY.includes(v.status) ? null : body(v.body), {
|
|
328
|
+
status: v.status,
|
|
329
|
+
statusText: v.statusText,
|
|
330
|
+
headers: v.headers,
|
|
331
|
+
});
|
|
332
|
+
if (v.url)
|
|
333
|
+
Object.defineProperty(res, "url", { value: v.url, enumerable: true });
|
|
334
|
+
return res;
|
|
335
|
+
}
|
|
336
|
+
case "request":
|
|
337
|
+
return new Request(v.url, {
|
|
338
|
+
method: v.method,
|
|
339
|
+
headers: v.headers,
|
|
340
|
+
redirect: v.redirect,
|
|
341
|
+
body: body(v.body),
|
|
342
|
+
duplex: "half",
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
return v;
|
|
346
|
+
}
|
|
176
347
|
/** Marks a value passed by reference in a message: `{ [REF]: id }`. */
|
|
177
348
|
const REF = "\u0000cellb.ref";
|
|
178
349
|
/**
|
|
@@ -182,17 +353,26 @@ const REF = "\u0000cellb.ref";
|
|
|
182
353
|
* value runs the value's own `Symbol.dispose`, as workerd does for an `RpcTarget`. A call
|
|
183
354
|
* returns an RpcPromise: calls on it go to the other side at once, naming its answer.
|
|
184
355
|
*/
|
|
185
|
-
function callsOver(port, handle) {
|
|
356
|
+
function callsOver(port, handle, mux, bodies) {
|
|
186
357
|
const values = new Map();
|
|
187
358
|
const answers = new Map();
|
|
188
359
|
let lastAnswer = 0;
|
|
189
360
|
const holders = new Map();
|
|
190
361
|
let lastId = 0;
|
|
191
|
-
const encode = (v) =>
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
362
|
+
const encode = (v) => {
|
|
363
|
+
const mark = bodies.mark();
|
|
364
|
+
try {
|
|
365
|
+
return cloneable(cross(v, (x) => {
|
|
366
|
+
values.set(++lastId, x);
|
|
367
|
+
holders.set(x, (holders.get(x) ?? 0) + 1);
|
|
368
|
+
return { [REF]: lastId };
|
|
369
|
+
}, (x) => toWire(x, bodies)));
|
|
370
|
+
}
|
|
371
|
+
catch (e) {
|
|
372
|
+
bodies.releaseSince(mark); // the message is not sent: nobody will read its bodies
|
|
373
|
+
throw e;
|
|
374
|
+
}
|
|
375
|
+
};
|
|
196
376
|
const release = (id) => {
|
|
197
377
|
const v = values.get(id);
|
|
198
378
|
if (!values.delete(id))
|
|
@@ -206,9 +386,31 @@ function callsOver(port, handle) {
|
|
|
206
386
|
}
|
|
207
387
|
};
|
|
208
388
|
const send = (msg) => callPort(port, msg, { timeout: NO_TIMEOUT }).catch(() => { });
|
|
209
|
-
|
|
389
|
+
// Stubs of one id held here: `dup()` makes another, and the id is released (and the other
|
|
390
|
+
// side's value with it, once no other id holds it) when the last of them is disposed or
|
|
391
|
+
// collected.
|
|
392
|
+
const local = new Map();
|
|
393
|
+
const drop = (id) => {
|
|
394
|
+
const n = (local.get(id) ?? 1) - 1;
|
|
395
|
+
if (n)
|
|
396
|
+
local.set(id, n);
|
|
397
|
+
else {
|
|
398
|
+
local.delete(id);
|
|
399
|
+
send({ type: "release", id });
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
const collected = new FinalizationRegistry(drop);
|
|
210
403
|
const stubOf = (id) => {
|
|
211
|
-
|
|
404
|
+
local.set(id, (local.get(id) ?? 0) + 1);
|
|
405
|
+
let disposed = false;
|
|
406
|
+
const live = () => {
|
|
407
|
+
if (disposed)
|
|
408
|
+
throw new Error("A stub was used after it was disposed.");
|
|
409
|
+
};
|
|
410
|
+
const invoke = (path, args) => {
|
|
411
|
+
live();
|
|
412
|
+
return call({ type: "ref", id, path, args });
|
|
413
|
+
};
|
|
212
414
|
const stub = new Proxy(() => { }, {
|
|
213
415
|
apply: (_t, _this, args) => invoke([], args),
|
|
214
416
|
get(_t, prop) {
|
|
@@ -216,11 +418,20 @@ function callsOver(port, handle) {
|
|
|
216
418
|
return true;
|
|
217
419
|
if (prop === Symbol.dispose)
|
|
218
420
|
return () => {
|
|
421
|
+
if (disposed)
|
|
422
|
+
return;
|
|
423
|
+
disposed = true;
|
|
219
424
|
collected.unregister(stub);
|
|
220
|
-
|
|
425
|
+
drop(id);
|
|
221
426
|
};
|
|
222
427
|
if (prop === "then" || typeof prop === "symbol")
|
|
223
428
|
return undefined;
|
|
429
|
+
// workerd's `stub.dup()`: another stub of the same value, disposed on its own.
|
|
430
|
+
if (prop === "dup")
|
|
431
|
+
return () => {
|
|
432
|
+
live();
|
|
433
|
+
return stubOf(id);
|
|
434
|
+
};
|
|
224
435
|
return (...args) => invoke([prop], args);
|
|
225
436
|
},
|
|
226
437
|
});
|
|
@@ -233,6 +444,8 @@ function callsOver(port, handle) {
|
|
|
233
444
|
for (let i = 0; i < v.length; i++)
|
|
234
445
|
v[i] = decode(v[i]);
|
|
235
446
|
else if (v && Object.getPrototypeOf(v) === Object.prototype) {
|
|
447
|
+
if (typeof v[WIRE] === "string")
|
|
448
|
+
return fromWire(v, mux, (body) => send({ type: "release", body }));
|
|
236
449
|
if (typeof v[REF] === "number")
|
|
237
450
|
return stubOf(v[REF]);
|
|
238
451
|
for (const k of Object.keys(v))
|
|
@@ -254,7 +467,9 @@ function callsOver(port, handle) {
|
|
|
254
467
|
// settles.
|
|
255
468
|
const serve = async (m) => {
|
|
256
469
|
if (m.type === "release") {
|
|
257
|
-
if (m.
|
|
470
|
+
if (m.body !== undefined)
|
|
471
|
+
bodies.release(m.body);
|
|
472
|
+
else if (m.answer === undefined)
|
|
258
473
|
release(m.id);
|
|
259
474
|
else
|
|
260
475
|
answers.delete(m.answer);
|