@statewalker/cellb 0.7.0 → 0.8.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.
Files changed (37) hide show
  1. package/README.md +2 -1
  2. package/dist/bindings/html-rewriter.d.ts +7 -0
  3. package/dist/bindings/html-rewriter.js +4 -11
  4. package/dist/bindings/html-rewriter.js.map +1 -1
  5. package/dist/index.d.ts +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/project/browser-bundle.d.ts +3 -0
  9. package/dist/project/browser-bundle.js +2 -0
  10. package/dist/project/browser-bundle.js.map +1 -1
  11. package/dist/project/browser-host.js +2 -1
  12. package/dist/project/browser-host.js.map +1 -1
  13. package/dist/project/browser-shards.d.ts +2 -23
  14. package/dist/project/browser-shards.js +2 -8
  15. package/dist/project/browser-shards.js.map +1 -1
  16. package/dist/project/browser-tab-protocol.d.ts +30 -0
  17. package/dist/project/browser-tab-protocol.js +9 -0
  18. package/dist/project/browser-tab-protocol.js.map +1 -0
  19. package/dist/project/browser-tabs.js +1 -1
  20. package/dist/project/browser-tabs.js.map +1 -1
  21. package/dist/project/build.js +1 -0
  22. package/dist/project/build.js.map +1 -1
  23. package/dist/project/module-rules.d.ts +26 -0
  24. package/dist/project/module-rules.js +131 -0
  25. package/dist/project/module-rules.js.map +1 -0
  26. package/dist/project/node-load.js +2 -1
  27. package/dist/project/node-load.js.map +1 -1
  28. package/dist/project/node-project.d.ts +3 -0
  29. package/dist/project/node-project.js +5 -1
  30. package/dist/project/node-project.js.map +1 -1
  31. package/dist/project/wrangler.d.ts +27 -3
  32. package/dist/project/wrangler.js +45 -22
  33. package/dist/project/wrangler.js.map +1 -1
  34. package/dist/tabs.d.ts +1 -0
  35. package/dist/tabs.js +8 -0
  36. package/dist/tabs.js.map +1 -0
  37. package/package.json +5 -1
package/README.md CHANGED
@@ -36,9 +36,10 @@ worker is started that way (checked with a Vite build, see `scripts/pack-check.m
36
36
 
37
37
  | Import | What it gives |
38
38
  |---|---|
39
- | `@statewalker/cellb` | the runtime (`createCellRuntime`, `createProjectRuntime`), `DurableObject` and `WorkerEntrypoint`, the ports and `CellStorage`, `celldBucket`, the object stores (`s3ObjectStore`, `memoryObjectStore`, `filesApiObjectStore`), `filesApiLtxLog`, `filesApiChangeLog`, `filesApiBackup`, `wasmMemoryOpener` (in-memory SQLite WASM), links over ports, `CellRouter`, `createShardWorker`, the WebSocket classes, and the errors embedders catch |
39
+ | `@statewalker/cellb` | the runtime (`createCellRuntime`, `createProjectRuntime` with `loadProjectBindings`), `DurableObject` and `WorkerEntrypoint`, the ports and `CellStorage`, `celldBucket`, the object stores (`s3ObjectStore`, `memoryObjectStore`, `filesApiObjectStore`), `filesApiLtxLog`, `filesApiChangeLog`, `filesApiBackup`, `wasmMemoryOpener` (in-memory SQLite WASM), links over ports, `CellRouter`, `createShardWorker`, the WebSocket classes, and the errors embedders catch |
40
40
  | `@statewalker/cellb/node` | `loadProject` and `buildProject` (the `cellb build` command), `nodeSqliteOpener`, `sqliteObjectStore` (celld dev's local bucket), `loadNodeProject`, `applyNodeD1Migrations`, and celld's peer protocol (`startCelldPeerServer`, `celldPeers`) |
41
41
  | `@statewalker/cellb/browser` | `loadProject` (a `cellb build` folder by URL, or sources with a compiler), `browserProjectRuntime`, `startProjectShards`, `joinProjectShards` and `serveProjectShard` (shards in workers and tabs), `installProjectRouter` (the ServiceWorker side), `sahpoolOpener`, `idbObjectStore`, `serviceWorkerConnector` |
42
+ | `@statewalker/cellb/tabs` | the tab side and the ServiceWorker side of a project shared by the tabs (`joinProjectShards`, `installProjectRouter`, `shardOwner`) without the shard runtime: what a page and its ServiceWorker import |
42
43
  | `@statewalker/cellb/site` | `createProjectSite`: a project's sources compiled in the browser and served by an in-browser HTTP server (`browserProjectRuntime({ site })`); `siteCompiler` for `loadProject`, and `siteHostOverPort` / `hostSitesForWorker` to host a worker's site from its page. Needs the optional peer dependencies `@statewalker/webrun-modules`, `@statewalker/webrun-site-builder` and `@statewalker/webrun-site-host` (the ServiceWorker host) |
43
44
  | `@statewalker/cellb/bundle` | `bundleCompiler`: a project's sources bundled in the browser for `loadProject`, with webrun-bundler on esbuild-wasm. Needs the optional peer dependency `@statewalker/webrun-bundler`; the caller passes esbuild-wasm, initialized |
44
45
  | `@statewalker/cellb/host-modules` | for bundlers other than cellb's own (webrun-bundler in a browser, say): the sources of `cloudflare:workers`, `node:*` and the Workers globals as cellb's realms provide them (`cellbHostModule`, `CELLS_GLOBALS_MODULE`) |
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Workers `HTMLRewriter` on lol-html compiled to WASM: Miniflare's `html-rewriter-wasm`
3
+ * (async handlers via asyncify), vendored as an ES module by scripts/vendor-html-rewriter.mjs.
4
+ * The glue and the WASM are loaded on first use — the WASM from the file system on Node, with
5
+ * fetch() in browsers — so importing the runtime costs nothing until a Worker rewrites HTML.
6
+ * The streaming wrapper follows Miniflare 2's (packages/html-rewriter/src/rewriter.ts).
7
+ */
1
8
  type Handlers = Record<string, unknown>;
2
9
  export declare class HTMLRewriter {
3
10
  #private;
@@ -1,16 +1,9 @@
1
- /**
2
- * Workers `HTMLRewriter` on lol-html compiled to WASM: Miniflare's `html-rewriter-wasm`
3
- * (async handlers via asyncify), vendored as an ES module by scripts/vendor-html-rewriter.mjs.
4
- * The WASM is instantiated on first use — from the file system on Node, with fetch() in
5
- * browsers — so importing the runtime costs nothing until a Worker rewrites HTML.
6
- * The streaming wrapper follows Miniflare 2's (packages/html-rewriter/src/rewriter.ts).
7
- */
8
- // @ts-expect-error — generated JS, no declarations
9
- import glue from "../../vendor/html-rewriter-wasm/html_rewriter.js";
10
1
  const wasmUrl = new URL("../../vendor/html-rewriter-wasm/html_rewriter_bg.wasm", import.meta.url);
11
2
  let ready;
12
3
  function instantiate() {
13
4
  ready ??= (async () => {
5
+ // @ts-expect-error — generated JS, no declarations
6
+ const glue = (await import("../../vendor/html-rewriter-wasm/html_rewriter.js")).default;
14
7
  let source;
15
8
  if (wasmUrl.protocol === "file:") {
16
9
  const fsName = "node:fs"; // not statically visible to browser bundlers
@@ -20,6 +13,7 @@ function instantiate() {
20
13
  else
21
14
  source = await fetch(wasmUrl);
22
15
  await glue.__instantiate(source);
16
+ return glue;
23
17
  })();
24
18
  return ready;
25
19
  }
@@ -42,8 +36,7 @@ export class HTMLRewriter {
42
36
  let rewriter;
43
37
  const stream = new TransformStream({
44
38
  start: async (controller) => {
45
- await instantiate();
46
- const Raw = glue.HTMLRewriter;
39
+ const Raw = (await instantiate()).HTMLRewriter;
47
40
  rewriter = new Raw((out) => {
48
41
  if (out.length !== 0)
49
42
  controller.enqueue(out); // enqueue throws on empty chunks
@@ -1 +1 @@
1
- {"version":3,"file":"html-rewriter.js","sourceRoot":"","sources":["../../src/bindings/html-rewriter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Workers `HTMLRewriter` on lol-html compiled to WASM: Miniflare's `html-rewriter-wasm`\n * (async handlers via asyncify), vendored as an ES module by scripts/vendor-html-rewriter.mjs.\n * The WASM is instantiated on first use — from the file system on Node, with fetch() in\n * browsers — so importing the runtime costs nothing until a Worker rewrites HTML.\n * The streaming wrapper follows Miniflare 2's (packages/html-rewriter/src/rewriter.ts).\n */\n// @ts-expect-error — generated JS, no declarations\nimport glue from \"../../vendor/html-rewriter-wasm/html_rewriter.js\";\n\ntype Handlers = Record<string, unknown>;\ninterface RawRewriter {\n on(selector: string, handlers: Handlers): void;\n onDocument(handlers: Handlers): void;\n write(chunk: Uint8Array): Promise<void>;\n end(): Promise<void>;\n free(): void;\n}\n\nconst wasmUrl = new URL(\"../../vendor/html-rewriter-wasm/html_rewriter_bg.wasm\", import.meta.url);\nlet ready: Promise<void> | undefined;\nfunction instantiate(): Promise<void> {\n ready ??= (async () => {\n let source: unknown;\n if (wasmUrl.protocol === \"file:\") {\n const fsName = \"node:fs\"; // not statically visible to browser bundlers\n const fs = (await import(/* @vite-ignore */ fsName)) as { readFileSync(u: URL): Uint8Array };\n source = fs.readFileSync(wasmUrl);\n } else source = await fetch(wasmUrl);\n await (glue as { __instantiate(s: unknown): Promise<void> }).__instantiate(source);\n })();\n return ready;\n}\n\nexport class HTMLRewriter {\n readonly #elements: [string, Handlers][] = [];\n readonly #documents: Handlers[] = [];\n\n on(selector: string, handlers: Handlers): this {\n this.#elements.push([selector, handlers]);\n return this;\n }\n\n onDocument(handlers: Handlers): this {\n this.#documents.push(handlers);\n return this;\n }\n\n transform(response: Response): Response {\n const body = response.body;\n // No body: the end handler would not run anyway.\n if (body === null) return new Response(null, response);\n let rewriter: RawRewriter | undefined;\n const stream = new TransformStream<Uint8Array, Uint8Array>({\n start: async (controller) => {\n await instantiate();\n const Raw = (\n glue as { HTMLRewriter: new (sink: (out: Uint8Array) => void, o?: object) => RawRewriter }\n ).HTMLRewriter;\n rewriter = new Raw(\n (out) => {\n if (out.length !== 0) controller.enqueue(out); // enqueue throws on empty chunks\n },\n { enableEsiTags: false },\n );\n for (const [selector, handlers] of this.#elements) rewriter.on(selector, handlers);\n for (const handlers of this.#documents) rewriter.onDocument(handlers);\n },\n transform: (chunk) =>\n rewriter!.write(typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk),\n flush: async () => {\n try {\n await rewriter!.end();\n } finally {\n rewriter!.free();\n }\n },\n });\n const headers = new Headers(response.headers);\n headers.delete(\"content-length\"); // the rewritten body has another length\n return new Response(body.pipeThrough(stream), {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n}\n"]}
1
+ {"version":3,"file":"html-rewriter.js","sourceRoot":"","sources":["../../src/bindings/html-rewriter.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Workers `HTMLRewriter` on lol-html compiled to WASM: Miniflare's `html-rewriter-wasm`\n * (async handlers via asyncify), vendored as an ES module by scripts/vendor-html-rewriter.mjs.\n * The glue and the WASM are loaded on first use — the WASM from the file system on Node, with\n * fetch() in browsers — so importing the runtime costs nothing until a Worker rewrites HTML.\n * The streaming wrapper follows Miniflare 2's (packages/html-rewriter/src/rewriter.ts).\n */\ntype Handlers = Record<string, unknown>;\ninterface RawRewriter {\n on(selector: string, handlers: Handlers): void;\n onDocument(handlers: Handlers): void;\n write(chunk: Uint8Array): Promise<void>;\n end(): Promise<void>;\n free(): void;\n}\n\nconst wasmUrl = new URL(\"../../vendor/html-rewriter-wasm/html_rewriter_bg.wasm\", import.meta.url);\ninterface Glue {\n __instantiate(source: unknown): Promise<void>;\n HTMLRewriter: new (sink: (out: Uint8Array) => void, o?: object) => RawRewriter;\n}\nlet ready: Promise<Glue> | undefined;\nfunction instantiate(): Promise<Glue> {\n ready ??= (async () => {\n // @ts-expect-error — generated JS, no declarations\n const glue = (await import(\"../../vendor/html-rewriter-wasm/html_rewriter.js\")).default as Glue;\n let source: unknown;\n if (wasmUrl.protocol === \"file:\") {\n const fsName = \"node:fs\"; // not statically visible to browser bundlers\n const fs = (await import(/* @vite-ignore */ fsName)) as { readFileSync(u: URL): Uint8Array };\n source = fs.readFileSync(wasmUrl);\n } else source = await fetch(wasmUrl);\n await glue.__instantiate(source);\n return glue;\n })();\n return ready;\n}\n\nexport class HTMLRewriter {\n readonly #elements: [string, Handlers][] = [];\n readonly #documents: Handlers[] = [];\n\n on(selector: string, handlers: Handlers): this {\n this.#elements.push([selector, handlers]);\n return this;\n }\n\n onDocument(handlers: Handlers): this {\n this.#documents.push(handlers);\n return this;\n }\n\n transform(response: Response): Response {\n const body = response.body;\n // No body: the end handler would not run anyway.\n if (body === null) return new Response(null, response);\n let rewriter: RawRewriter | undefined;\n const stream = new TransformStream<Uint8Array, Uint8Array>({\n start: async (controller) => {\n const Raw = (await instantiate()).HTMLRewriter;\n rewriter = new Raw(\n (out) => {\n if (out.length !== 0) controller.enqueue(out); // enqueue throws on empty chunks\n },\n { enableEsiTags: false },\n );\n for (const [selector, handlers] of this.#elements) rewriter.on(selector, handlers);\n for (const handlers of this.#documents) rewriter.onDocument(handlers);\n },\n transform: (chunk) =>\n rewriter!.write(typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk),\n flush: async () => {\n try {\n await rewriter!.end();\n } finally {\n rewriter!.free();\n }\n },\n });\n const headers = new Headers(response.headers);\n headers.delete(\"content-length\"); // the rewritten body has another length\n return new Response(body.pipeThrough(stream), {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -15,7 +15,7 @@ export { DurableObjectState } from "./core/state.js";
15
15
  export { type FilesRpcOptions, rpcFilesClient, serveFilesApi } from "./ltx/files-rpc.js";
16
16
  export * from "./ports.js";
17
17
  export { parseJsonc } from "./project/jsonc.js";
18
- export { createProjectRuntime, type ProjectHost, type ProjectRuntime, type WranglerConfig, } from "./project/wrangler.js";
18
+ export { createProjectRuntime, loadProjectBindings, type ProjectBindings, type ProjectHost, type ProjectRuntime, type WranglerConfig, } from "./project/wrangler.js";
19
19
  export { CellRouter, type CellRouterOptions, ShardOwnerLostError } from "./router/cell-router.js";
20
20
  export { createShardWorker, type ShardWorker, type ShardWorkerOptions, shardRouting, } from "./router/shard-worker.js";
21
21
  export { type CellsHttpOptions, cellsHttpHandler, type RemoteRuntime, remoteRuntime, } from "./transport/cells-http.js";
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ export { DurableObjectState } from "./core/state.js";
15
15
  export { rpcFilesClient, serveFilesApi } from "./ltx/files-rpc.js";
16
16
  export * from "./ports.js";
17
17
  export { parseJsonc } from "./project/jsonc.js";
18
- export { createProjectRuntime, } from "./project/wrangler.js";
18
+ export { createProjectRuntime, loadProjectBindings, } from "./project/wrangler.js";
19
19
  export { CellRouter, ShardOwnerLostError } from "./router/cell-router.js";
20
20
  export { createShardWorker, shardRouting, } from "./router/shard-worker.js";
21
21
  export { cellsHttpHandler, remoteRuntime, } from "./transport/cells-http.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACxF,OAAO,EAAyB,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACzF,OAAO,EAA8B,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EACL,OAAO,EAGP,SAAS,GACV,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAA2B,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC/E,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EAEjB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAkB,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAyB,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAClG,OAAO,EACL,sBAAsB,EAEtB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAGL,iBAAiB,GAElB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAwB,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACzF,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACL,oBAAoB,GAIrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,UAAU,EAA0B,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAClG,OAAO,EACL,iBAAiB,EAGjB,YAAY,GACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAEL,gBAAgB,EAEhB,aAAa,GACd,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAEL,cAAc,EACd,YAAY,EACZ,oBAAoB,EACpB,YAAY,GACb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,oBAAoB,GAErB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC","sourcesContent":["export { type FilesApiBackupOptions, filesApiBackup } from \"./adapters/files-backup.js\";\nexport { type ChangeLogOptions, filesApiChangeLog } from \"./adapters/files-changelog.js\";\nexport { type FilesApiLtxLogOptions, filesApiLtxLog } from \"./adapters/files-ltx.js\";\nexport { wasmMemoryOpener } from \"./adapters/wasm-sqlite.js\";\nexport {\n AiError,\n type AiRunOptions,\n type WorkersAiOptions,\n workersAi,\n} from \"./bindings/workers-ai.js\";\nexport { type CelldBucketOptions, celldBucket } from \"./bucket/celld-cells.js\";\nexport {\n filesApiObjectStore,\n memoryObjectStore,\n type ObjectStore,\n PreconditionFailedError,\n} from \"./bucket/object-store.js\";\nexport { type S3Options, s3ObjectStore } from \"./bucket/s3-object-store.js\";\nexport { DurableObject, type ExecutionContext, WorkerEntrypoint } from \"./core/durable-object.js\";\nexport {\n DurableObjectNamespace,\n type DurableObjectStub,\n runInDurableObject,\n} from \"./core/namespace.js\";\nexport {\n BrokenObjectError,\n CellOwnedElsewhereError,\n ObjectClosedError,\n} from \"./core/object-host.js\";\nexport {\n type CellRuntime,\n type CellRuntimeOptions,\n createCellRuntime,\n type WorkerModule,\n} from \"./core/runtime.js\";\nexport { shardOf } from \"./core/shard.js\";\nexport { DurableObjectState } from \"./core/state.js\";\nexport { type FilesRpcOptions, rpcFilesClient, serveFilesApi } from \"./ltx/files-rpc.js\";\nexport * from \"./ports.js\";\nexport { parseJsonc } from \"./project/jsonc.js\";\nexport {\n createProjectRuntime,\n type ProjectHost,\n type ProjectRuntime,\n type WranglerConfig,\n} from \"./project/wrangler.js\";\nexport { CellRouter, type CellRouterOptions, ShardOwnerLostError } from \"./router/cell-router.js\";\nexport {\n createShardWorker,\n type ShardWorker,\n type ShardWorkerOptions,\n shardRouting,\n} from \"./router/shard-worker.js\";\nexport {\n type CellsHttpOptions,\n cellsHttpHandler,\n type RemoteRuntime,\n remoteRuntime,\n} from \"./transport/cells-http.js\";\nexport {\n type CellPort,\n connectRuntime,\n linkOverPort,\n serveHandlerOverPort,\n serveRuntime,\n} from \"./transport/port.js\";\nexport {\n type CellsWebSocketClass,\n createWebSocketClass,\n type WebSocketConnector,\n} from \"./ws/client.js\";\nexport { CellsResponse, takeClientPort, WebSocketPair } from \"./ws/server.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACxF,OAAO,EAAyB,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACzF,OAAO,EAA8B,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EACL,OAAO,EAGP,SAAS,GACV,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAA2B,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC/E,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EAEjB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAkB,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAyB,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAClG,OAAO,EACL,sBAAsB,EAEtB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAGL,iBAAiB,GAElB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAwB,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACzF,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACL,oBAAoB,EACpB,mBAAmB,GAKpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,UAAU,EAA0B,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAClG,OAAO,EACL,iBAAiB,EAGjB,YAAY,GACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAEL,gBAAgB,EAEhB,aAAa,GACd,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAEL,cAAc,EACd,YAAY,EACZ,oBAAoB,EACpB,YAAY,GACb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,oBAAoB,GAErB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC","sourcesContent":["export { type FilesApiBackupOptions, filesApiBackup } from \"./adapters/files-backup.js\";\nexport { type ChangeLogOptions, filesApiChangeLog } from \"./adapters/files-changelog.js\";\nexport { type FilesApiLtxLogOptions, filesApiLtxLog } from \"./adapters/files-ltx.js\";\nexport { wasmMemoryOpener } from \"./adapters/wasm-sqlite.js\";\nexport {\n AiError,\n type AiRunOptions,\n type WorkersAiOptions,\n workersAi,\n} from \"./bindings/workers-ai.js\";\nexport { type CelldBucketOptions, celldBucket } from \"./bucket/celld-cells.js\";\nexport {\n filesApiObjectStore,\n memoryObjectStore,\n type ObjectStore,\n PreconditionFailedError,\n} from \"./bucket/object-store.js\";\nexport { type S3Options, s3ObjectStore } from \"./bucket/s3-object-store.js\";\nexport { DurableObject, type ExecutionContext, WorkerEntrypoint } from \"./core/durable-object.js\";\nexport {\n DurableObjectNamespace,\n type DurableObjectStub,\n runInDurableObject,\n} from \"./core/namespace.js\";\nexport {\n BrokenObjectError,\n CellOwnedElsewhereError,\n ObjectClosedError,\n} from \"./core/object-host.js\";\nexport {\n type CellRuntime,\n type CellRuntimeOptions,\n createCellRuntime,\n type WorkerModule,\n} from \"./core/runtime.js\";\nexport { shardOf } from \"./core/shard.js\";\nexport { DurableObjectState } from \"./core/state.js\";\nexport { type FilesRpcOptions, rpcFilesClient, serveFilesApi } from \"./ltx/files-rpc.js\";\nexport * from \"./ports.js\";\nexport { parseJsonc } from \"./project/jsonc.js\";\nexport {\n createProjectRuntime,\n loadProjectBindings,\n type ProjectBindings,\n type ProjectHost,\n type ProjectRuntime,\n type WranglerConfig,\n} from \"./project/wrangler.js\";\nexport { CellRouter, type CellRouterOptions, ShardOwnerLostError } from \"./router/cell-router.js\";\nexport {\n createShardWorker,\n type ShardWorker,\n type ShardWorkerOptions,\n shardRouting,\n} from \"./router/shard-worker.js\";\nexport {\n type CellsHttpOptions,\n cellsHttpHandler,\n type RemoteRuntime,\n remoteRuntime,\n} from \"./transport/cells-http.js\";\nexport {\n type CellPort,\n connectRuntime,\n linkOverPort,\n serveHandlerOverPort,\n serveRuntime,\n} from \"./transport/port.js\";\nexport {\n type CellsWebSocketClass,\n createWebSocketClass,\n type WebSocketConnector,\n} from \"./ws/client.js\";\nexport { CellsResponse, takeClientPort, WebSocketPair } from \"./ws/server.js\";\n"]}
@@ -4,6 +4,7 @@
4
4
  * Workers globals (`Response` with status 101, `WebSocketPair`) from what that runtime installs;
5
5
  * with nodejs_compat, `node:*` modules (and their bare names) become browser polyfills.
6
6
  */
7
+ import { type ModuleRule } from "./module-rules.js";
7
8
  /** Bundles the Worker module at `entry` into one ES module for `browserProjectRuntime`. */
8
9
  export declare function bundleWorkerForBrowser(entry: string, opts?: {
9
10
  nodeCompat?: boolean;
@@ -14,4 +15,6 @@ export declare function bundleWorkerForBrowser(entry: string, opts?: {
14
15
  * too.
15
16
  */
16
17
  lowerAwait?: boolean;
18
+ /** wrangler `rules` for non-JS imports (the defaults: `.wasm`, `.bin`, `.txt`…, as wrangler). */
19
+ rules?: ModuleRule[];
17
20
  }): Promise<string>;
@@ -10,6 +10,7 @@ import { build } from "esbuild";
10
10
  import { NODE_POLYFILL_FILES, NODE_POLYFILL_PACKAGES } from "../node-compat/modules.js";
11
11
  import { PROJECT_WORKERS_MODULE_SHIM } from "./browser-modules.js";
12
12
  import { lowerAwait } from "./lower-await.js";
13
+ import { moduleRulesPlugin } from "./module-rules.js";
13
14
  import { ownModule } from "./own-module.js";
14
15
  import { SCHEDULER_EXPRESSION } from "./scheduler.js";
15
16
  import { WORKERS_GLOBAL_NAMES } from "./workers-global-names.js";
@@ -107,6 +108,7 @@ export async function bundleWorkerForBrowser(entry, opts = {}) {
107
108
  }));
108
109
  },
109
110
  },
111
+ moduleRulesPlugin(opts.rules),
110
112
  ],
111
113
  });
112
114
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"browser-bundle.js","sourceRoot":"","sources":["../../src/project/browser-bundle.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Node side of a browser-hosted project: bundles Worker code for a browser realm, for\n * `browserProjectRuntime({ code: { bundle } })`. The bundle reads `cloudflare:workers` and the\n * Workers globals (`Response` with status 101, `WebSocketPair`) from what that runtime installs;\n * with nodejs_compat, `node:*` modules (and their bare names) become browser polyfills.\n */\n\nimport { builtinModules, createRequire } from \"node:module\";\nimport { resolve } from \"node:path\";\nimport { type BuildOptions, build } from \"esbuild\";\nimport { NODE_POLYFILL_FILES, NODE_POLYFILL_PACKAGES } from \"../node-compat/modules.js\";\nimport { PROJECT_WORKERS_MODULE_SHIM } from \"./browser-modules.js\";\nimport { lowerAwait } from \"./lower-await.js\";\nimport { ownModule } from \"./own-module.js\";\nimport { SCHEDULER_EXPRESSION } from \"./scheduler.js\";\nimport { WORKERS_GLOBAL_NAMES } from \"./workers-global-names.js\";\n\nconst pkg = resolve(import.meta.dirname, \"../..\");\nconst requireFromPkg = createRequire(resolve(pkg, \"package.json\"));\n\n/**\n * A Node.js module with no browser polyfill, as an ES module: every export the module has on\n * this Node.js (the bundler runs on it) is a function that throws when called (a class to extend\n * too), and the default export answers any member the same way.\n */\nfunction nodeStub(name: string): string {\n let names: string[] = [];\n try {\n names = Object.keys(requireFromPkg(name)).filter((n) => n !== \"default\");\n } catch {\n // not a module of this Node.js: the default export only\n }\n const what = JSON.stringify(name);\n return [\n `const fail = (key) => { throw new Error(${what} + \".\" + key + \" is not available in browsers (nodejs_compat)\"); };`,\n \"const stub = (key) => function () { fail(key); };\",\n ...names.map(\n (n, i) =>\n `const s${i} = stub(${JSON.stringify(n)}); export { s${i} as ${JSON.stringify(n)} };`,\n ),\n \"export default new Proxy(Object.create(null), {\",\n \" get(target, key) {\",\n ' if (typeof key === \"symbol\" || key === \"then\" || key === \"__esModule\") return undefined;',\n \" if (!Object.hasOwn(target, key)) target[key] = stub(String(key));\",\n \" return target[key];\",\n \" },\",\n \"});\",\n ].join(\"\\n\");\n}\n\nconst GLOBALS_SHIM = `${WORKERS_GLOBAL_NAMES.map((n) => `export const ${n} = globalThis.__cellsGlobals.${n};`).join(\" \")} export const scheduler = ${SCHEDULER_EXPRESSION};`;\n\n/** A bare Node.js built-in name (\"path\", \"fs/promises\"): nodejs_compat takes it as `node:…`. */\nconst bareBuiltin = new Set(builtinModules.filter((m) => !m.startsWith(\"_\") && !m.includes(\":\")));\n\n/** Bundles the Worker module at `entry` into one ES module for `browserProjectRuntime`. */\nexport async function bundleWorkerForBrowser(\n entry: string,\n opts: {\n nodeCompat?: boolean;\n /**\n * Lower `await` to generators (default: with `nodeCompat`), so that the node:async_hooks\n * polyfill carries AsyncLocalStorage stores through it. `false` only for browsers with TC39\n * AsyncContext, whose engine carries them through native awaits; a lowered bundle runs there\n * too.\n */\n lowerAwait?: boolean;\n } = {},\n): Promise<string> {\n const lower = opts.lowerAwait ?? opts.nodeCompat;\n const options = (esbuildLowers: boolean): BuildOptions & { write: false } => ({\n entryPoints: [entry],\n write: false,\n bundle: true,\n format: \"esm\",\n platform: \"browser\",\n target: \"es2022\",\n // Function names are observable (the npm assert polyfill reports its caller's name as the\n // operator); bundling must not rename them.\n keepNames: true,\n // nodejs_compat: `await` lowered to generators, so that each one resumes through\n // Promise.prototype.then and carries its AsyncLocalStorage stores (node-compat/async_hooks.ts).\n ...(esbuildLowers\n ? { supported: { \"async-await\": false, \"async-generator\": false, \"for-await\": false } }\n : {}),\n logLevel: \"silent\",\n inject: [\n \"cells:globals\",\n ...(opts.nodeCompat ? [ownModule(import.meta.dirname, \"../node-compat/globals\")] : []),\n ],\n plugins: [\n {\n name: \"cells-browser\",\n setup(b) {\n // nodejs_compat: node:* → browser polyfills, bundled in.\n if (opts.nodeCompat)\n b.onResolve({ filter: /^(node:)?[a-z_/]+$/ }, (a) => {\n const name = a.path.startsWith(\"node:\") ? a.path : `node:${a.path}`;\n if (!a.path.startsWith(\"node:\") && !bareBuiltin.has(a.path)) return undefined;\n const file = NODE_POLYFILL_FILES[name];\n if (file) return { path: ownModule(import.meta.dirname, `../node-compat/${file}`) };\n const polyfill = NODE_POLYFILL_PACKAGES[name];\n // \"buffer/\" (trailing slash): the npm package, not the Node.js built-in of that name\n if (polyfill) return { path: requireFromPkg.resolve(`${polyfill}/`) };\n // No browser polyfill: a stub that loads and throws when used, as wrangler's\n // nodejs_compat stubs do on Cloudflare (libraries import such modules in code\n // paths a Worker never takes, e.g. a CLI's login).\n return { path: name, namespace: \"cells-node-stub\" };\n });\n b.onLoad({ filter: /.*/, namespace: \"cells-node-stub\" }, (a) => ({\n contents: nodeStub(a.path),\n loader: \"js\",\n }));\n b.onResolve({ filter: /^cloudflare:email$/ }, () => ({\n path: ownModule(import.meta.dirname, \"cloudflare-email\"),\n }));\n b.onResolve({ filter: /^cloudflare:workers$|^cells:globals$/ }, (a) => ({\n path: a.path,\n namespace: \"cells\",\n }));\n b.onLoad({ filter: /.*/, namespace: \"cells\" }, (a) => ({\n contents: a.path === \"cloudflare:workers\" ? PROJECT_WORKERS_MODULE_SHIM : GLOBALS_SHIM,\n loader: \"js\",\n }));\n },\n },\n ],\n });\n try {\n return (await build(options(!!lower))).outputFiles[0].text;\n } catch (err) {\n // esbuild cannot lower a top-level await, and refuses to keep one while it lowers the rest\n // (Astro's builds have one: `await import(…)` of the live content config). Such code is\n // bundled as it is, then lowered by lowerAwait, which leaves top-level awaits native: module\n // evaluation runs in no request's context, so they carry no store anyway.\n if (!lower || !/Top-level await is not available/.test(String(err))) throw err;\n return lowerAwait((await build(options(false))).outputFiles[0].text);\n }\n}\n"]}
1
+ {"version":3,"file":"browser-bundle.js","sourceRoot":"","sources":["../../src/project/browser-bundle.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAqB,KAAK,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACxF,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAmB,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAClD,MAAM,cAAc,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC;AAEnE;;;;GAIG;AACH,SAAS,QAAQ,CAAC,IAAY;IAC5B,IAAI,KAAK,GAAa,EAAE,CAAC;IACzB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACP,wDAAwD;IAC1D,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAClC,OAAO;QACL,2CAA2C,IAAI,qEAAqE;QACpH,mDAAmD;QACnD,GAAG,KAAK,CAAC,GAAG,CACV,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,UAAU,CAAC,WAAW,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CACxF;QACD,iDAAiD;QACjD,sBAAsB;QACtB,8FAA8F;QAC9F,uEAAuE;QACvE,yBAAyB;QACzB,MAAM;QACN,KAAK;KACN,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,YAAY,GAAG,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,gCAAgC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,6BAA6B,oBAAoB,GAAG,CAAC;AAE7K,gGAAgG;AAChG,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAElG,2FAA2F;AAC3F,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,KAAa,EACb,IAAI,GAWA,EAAE;IAEN,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,CAAC;IACjD,MAAM,OAAO,GAAG,CAAC,aAAsB,EAAmC,EAAE,CAAC,CAAC;QAC5E,WAAW,EAAE,CAAC,KAAK,CAAC;QACpB,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,IAAI;QACZ,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,SAAS;QACnB,MAAM,EAAE,QAAQ;QAChB,0FAA0F;QAC1F,4CAA4C;QAC5C,SAAS,EAAE,IAAI;QACf,iFAAiF;QACjF,gGAAgG;QAChG,GAAG,CAAC,aAAa;YACf,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE;YACvF,CAAC,CAAC,EAAE,CAAC;QACP,QAAQ,EAAE,QAAQ;QAClB,MAAM,EAAE;YACN,eAAe;YACf,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SACvF;QACD,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,eAAe;gBACrB,KAAK,CAAC,CAAC;oBACL,yDAAyD;oBACzD,IAAI,IAAI,CAAC,UAAU;wBACjB,CAAC,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,oBAAoB,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE;4BAClD,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;4BACpE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;gCAAE,OAAO,SAAS,CAAC;4BAC9E,MAAM,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;4BACvC,IAAI,IAAI;gCAAE,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE,kBAAkB,IAAI,EAAE,CAAC,EAAE,CAAC;4BACpF,MAAM,QAAQ,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC;4BAC9C,qFAAqF;4BACrF,IAAI,QAAQ;gCAAE,OAAO,EAAE,IAAI,EAAE,cAAc,CAAC,OAAO,CAAC,GAAG,QAAQ,GAAG,CAAC,EAAE,CAAC;4BACtE,6EAA6E;4BAC7E,8EAA8E;4BAC9E,mDAAmD;4BACnD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAC;wBACtD,CAAC,CAAC,CAAC;oBACL,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;wBAC/D,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;wBAC1B,MAAM,EAAE,IAAI;qBACb,CAAC,CAAC,CAAC;oBACJ,CAAC,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,oBAAoB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;wBACnD,IAAI,EAAE,SAAS,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC;qBACzD,CAAC,CAAC,CAAC;oBACJ,CAAC,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,sCAAsC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;wBACtE,IAAI,EAAE,CAAC,CAAC,IAAI;wBACZ,SAAS,EAAE,OAAO;qBACnB,CAAC,CAAC,CAAC;oBACJ,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;wBACrD,QAAQ,EAAE,CAAC,CAAC,IAAI,KAAK,oBAAoB,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,YAAY;wBACtF,MAAM,EAAE,IAAI;qBACb,CAAC,CAAC,CAAC;gBACN,CAAC;aACF;YACD,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC;SAC9B;KACF,CAAC,CAAC;IACH,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,2FAA2F;QAC3F,wFAAwF;QACxF,6FAA6F;QAC7F,0EAA0E;QAC1E,IAAI,CAAC,KAAK,IAAI,CAAC,kCAAkC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAAE,MAAM,GAAG,CAAC;QAC/E,OAAO,UAAU,CAAC,CAAC,MAAM,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACvE,CAAC;AACH,CAAC","sourcesContent":["/**\n * Node side of a browser-hosted project: bundles Worker code for a browser realm, for\n * `browserProjectRuntime({ code: { bundle } })`. The bundle reads `cloudflare:workers` and the\n * Workers globals (`Response` with status 101, `WebSocketPair`) from what that runtime installs;\n * with nodejs_compat, `node:*` modules (and their bare names) become browser polyfills.\n */\n\nimport { builtinModules, createRequire } from \"node:module\";\nimport { resolve } from \"node:path\";\nimport { type BuildOptions, build } from \"esbuild\";\nimport { NODE_POLYFILL_FILES, NODE_POLYFILL_PACKAGES } from \"../node-compat/modules.js\";\nimport { PROJECT_WORKERS_MODULE_SHIM } from \"./browser-modules.js\";\nimport { lowerAwait } from \"./lower-await.js\";\nimport { type ModuleRule, moduleRulesPlugin } from \"./module-rules.js\";\nimport { ownModule } from \"./own-module.js\";\nimport { SCHEDULER_EXPRESSION } from \"./scheduler.js\";\nimport { WORKERS_GLOBAL_NAMES } from \"./workers-global-names.js\";\n\nconst pkg = resolve(import.meta.dirname, \"../..\");\nconst requireFromPkg = createRequire(resolve(pkg, \"package.json\"));\n\n/**\n * A Node.js module with no browser polyfill, as an ES module: every export the module has on\n * this Node.js (the bundler runs on it) is a function that throws when called (a class to extend\n * too), and the default export answers any member the same way.\n */\nfunction nodeStub(name: string): string {\n let names: string[] = [];\n try {\n names = Object.keys(requireFromPkg(name)).filter((n) => n !== \"default\");\n } catch {\n // not a module of this Node.js: the default export only\n }\n const what = JSON.stringify(name);\n return [\n `const fail = (key) => { throw new Error(${what} + \".\" + key + \" is not available in browsers (nodejs_compat)\"); };`,\n \"const stub = (key) => function () { fail(key); };\",\n ...names.map(\n (n, i) =>\n `const s${i} = stub(${JSON.stringify(n)}); export { s${i} as ${JSON.stringify(n)} };`,\n ),\n \"export default new Proxy(Object.create(null), {\",\n \" get(target, key) {\",\n ' if (typeof key === \"symbol\" || key === \"then\" || key === \"__esModule\") return undefined;',\n \" if (!Object.hasOwn(target, key)) target[key] = stub(String(key));\",\n \" return target[key];\",\n \" },\",\n \"});\",\n ].join(\"\\n\");\n}\n\nconst GLOBALS_SHIM = `${WORKERS_GLOBAL_NAMES.map((n) => `export const ${n} = globalThis.__cellsGlobals.${n};`).join(\" \")} export const scheduler = ${SCHEDULER_EXPRESSION};`;\n\n/** A bare Node.js built-in name (\"path\", \"fs/promises\"): nodejs_compat takes it as `node:…`. */\nconst bareBuiltin = new Set(builtinModules.filter((m) => !m.startsWith(\"_\") && !m.includes(\":\")));\n\n/** Bundles the Worker module at `entry` into one ES module for `browserProjectRuntime`. */\nexport async function bundleWorkerForBrowser(\n entry: string,\n opts: {\n nodeCompat?: boolean;\n /**\n * Lower `await` to generators (default: with `nodeCompat`), so that the node:async_hooks\n * polyfill carries AsyncLocalStorage stores through it. `false` only for browsers with TC39\n * AsyncContext, whose engine carries them through native awaits; a lowered bundle runs there\n * too.\n */\n lowerAwait?: boolean;\n /** wrangler `rules` for non-JS imports (the defaults: `.wasm`, `.bin`, `.txt`…, as wrangler). */\n rules?: ModuleRule[];\n } = {},\n): Promise<string> {\n const lower = opts.lowerAwait ?? opts.nodeCompat;\n const options = (esbuildLowers: boolean): BuildOptions & { write: false } => ({\n entryPoints: [entry],\n write: false,\n bundle: true,\n format: \"esm\",\n platform: \"browser\",\n target: \"es2022\",\n // Function names are observable (the npm assert polyfill reports its caller's name as the\n // operator); bundling must not rename them.\n keepNames: true,\n // nodejs_compat: `await` lowered to generators, so that each one resumes through\n // Promise.prototype.then and carries its AsyncLocalStorage stores (node-compat/async_hooks.ts).\n ...(esbuildLowers\n ? { supported: { \"async-await\": false, \"async-generator\": false, \"for-await\": false } }\n : {}),\n logLevel: \"silent\",\n inject: [\n \"cells:globals\",\n ...(opts.nodeCompat ? [ownModule(import.meta.dirname, \"../node-compat/globals\")] : []),\n ],\n plugins: [\n {\n name: \"cells-browser\",\n setup(b) {\n // nodejs_compat: node:* → browser polyfills, bundled in.\n if (opts.nodeCompat)\n b.onResolve({ filter: /^(node:)?[a-z_/]+$/ }, (a) => {\n const name = a.path.startsWith(\"node:\") ? a.path : `node:${a.path}`;\n if (!a.path.startsWith(\"node:\") && !bareBuiltin.has(a.path)) return undefined;\n const file = NODE_POLYFILL_FILES[name];\n if (file) return { path: ownModule(import.meta.dirname, `../node-compat/${file}`) };\n const polyfill = NODE_POLYFILL_PACKAGES[name];\n // \"buffer/\" (trailing slash): the npm package, not the Node.js built-in of that name\n if (polyfill) return { path: requireFromPkg.resolve(`${polyfill}/`) };\n // No browser polyfill: a stub that loads and throws when used, as wrangler's\n // nodejs_compat stubs do on Cloudflare (libraries import such modules in code\n // paths a Worker never takes, e.g. a CLI's login).\n return { path: name, namespace: \"cells-node-stub\" };\n });\n b.onLoad({ filter: /.*/, namespace: \"cells-node-stub\" }, (a) => ({\n contents: nodeStub(a.path),\n loader: \"js\",\n }));\n b.onResolve({ filter: /^cloudflare:email$/ }, () => ({\n path: ownModule(import.meta.dirname, \"cloudflare-email\"),\n }));\n b.onResolve({ filter: /^cloudflare:workers$|^cells:globals$/ }, (a) => ({\n path: a.path,\n namespace: \"cells\",\n }));\n b.onLoad({ filter: /.*/, namespace: \"cells\" }, (a) => ({\n contents: a.path === \"cloudflare:workers\" ? PROJECT_WORKERS_MODULE_SHIM : GLOBALS_SHIM,\n loader: \"js\",\n }));\n },\n },\n moduleRulesPlugin(opts.rules),\n ],\n });\n try {\n return (await build(options(!!lower))).outputFiles[0].text;\n } catch (err) {\n // esbuild cannot lower a top-level await, and refuses to keep one while it lowers the rest\n // (Astro's builds have one: `await import(…)` of the live content config). Such code is\n // bundled as it is, then lowered by lowerAwait, which leaves top-level awaits native: module\n // evaluation runs in no request's context, so they carry no store anyway.\n if (!lower || !/Top-level await is not available/.test(String(err))) throw err;\n return lowerAwait((await build(options(false))).outputFiles[0].text);\n }\n}\n"]}
@@ -13,7 +13,7 @@ import * as workersModule from "./cloudflare-workers.js";
13
13
  import { siteModuleLoader, workersHostRegistry } from "./site-loader.js";
14
14
  import { workerScope } from "./worker-scope.js";
15
15
  import * as workersGlobals from "./workers-globals-module.js";
16
- import { createProjectRuntime, hasNodeCompat, loadTimeEnv, populatesProcessEnv, processEnvOf, } from "./wrangler.js";
16
+ import { createProjectRuntime, hasNodeCompat, loadProjectBindings, loadTimeEnv, populatesProcessEnv, processEnvOf, } from "./wrangler.js";
17
17
  export { populatesProcessEnv, processEnvOf };
18
18
  async function bucketStore(b) {
19
19
  if ("store" in b)
@@ -175,6 +175,7 @@ export async function browserProjectRuntime(opts) {
175
175
  ? celldBucket(store, { node: opts.bucket.node, leaseTtlMs: opts.bucket.leaseTtlMs })
176
176
  : undefined;
177
177
  const { runtime, unsupported } = createProjectRuntime(opts.config, module, {
178
+ bindings: await loadProjectBindings(opts.config),
178
179
  openSql,
179
180
  files,
180
181
  assetFiles: opts.assetFiles,
@@ -1 +1 @@
1
- {"version":3,"file":"browser-host.js","sourceRoot":"","sources":["../../src/project/browser-host.ts"],"names":[],"mappings":"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","sourcesContent":["import { BrowserFilesApi } from \"@statewalker/webrun-files-browser\";\nimport { installLtxVfs } from \"../adapters/ltx-vfs.js\";\nimport {\n sahpoolOpener,\n tuneCellConnection,\n WasmSqliteDriver,\n wasmMemoryOpener,\n} from \"../adapters/wasm-sqlite.js\";\nimport type { AssetFiles } from \"../bindings/assets.js\";\nimport type { WorkersAiOptions } from \"../bindings/workers-ai.js\";\nimport { celldBucket } from \"../bucket/celld-cells.js\";\nimport { idbObjectStore } from \"../bucket/idb-object-store.js\";\nimport { filesApiObjectStore, type ObjectStore } from \"../bucket/object-store.js\";\nimport { s3ObjectStore } from \"../bucket/s3-object-store.js\";\nimport type { CellRuntimeOptions, WorkerModule } from \"../core/runtime.js\";\nimport { browserIsolatedLoader } from \"../isolate/browser.js\";\nimport type { LtxStoreFiles } from \"../ltx/ltx-page-server.js\";\nimport { installAsyncContext } from \"../node-compat/async_hooks.js\";\nimport { installNodeGlobals } from \"../node-compat/install.js\";\nimport { browserModuleLoader } from \"./browser-modules.js\";\nimport * as workersModule from \"./cloudflare-workers.js\";\nimport { siteModuleLoader, workersHostRegistry } from \"./site-loader.js\";\nimport { type WorkerScope, workerScope } from \"./worker-scope.js\";\nimport * as workersGlobals from \"./workers-globals-module.js\";\nimport {\n createProjectRuntime,\n hasNodeCompat,\n loadTimeEnv,\n populatesProcessEnv,\n processEnvOf,\n type WranglerConfig,\n} from \"./wrangler.js\";\n\nexport { populatesProcessEnv, processEnvOf };\n\n/**\n * Where a browser-hosted project keeps its cells when they must outlive the page or move to\n * other nodes: a celld fleet bucket. Cells, facets and alarms are then exactly celld's\n * (ownership in `own.json`, LTX logs, wake index) and R2 objects live in it too, so the same\n * cells can be served by this browser, by other browsers and by celld nodes, in turn.\n *\n * - `s3`: an S3-compatible bucket, reached directly (the bucket must allow CORS for the page's\n * origin: methods GET/PUT/DELETE/HEAD, request headers `authorization`, `content-type`,\n * `x-amz-*`, `if-match`, `if-none-match`; exposed headers `etag`, `last-modified`,\n * `x-amz-meta-celld-r2`) or through a same-origin proxy (`endpoint` = the proxy,\n * `signAs` = the real endpoint: SigV4 signs the real host and path).\n * - `opfs`: a bucket in this origin's OPFS — persistence without a server. Conditional writes\n * are atomic only within one writer, so one tab or worker at a time should own its cells.\n * - `store`: any ObjectStore.\n */\nexport type BrowserBucket =\n | {\n s3: {\n endpoint: string;\n signAs?: string;\n bucket: string;\n prefix?: string;\n region?: string;\n accessKeyId: string;\n secretAccessKey: string;\n };\n node: string;\n leaseTtlMs?: number;\n }\n | { opfs: string; node: string; leaseTtlMs?: number }\n /**\n * `idb`: a bucket in this origin's IndexedDB (atomic conditional writes across tabs and\n * workers). Cells then run SQLite in memory and persist through the bucket's page-level logs:\n * no OPFS pool, so any number of workers can serve cells at once.\n */\n | { idb: string; node: string; leaseTtlMs?: number }\n /**\n * `ltx`: cells as celld keeps them, LTX files (a snapshot and one file per commit) in an OPFS\n * directory, read page by page (a SQLite VFS over a store worker): no OPFS pool, and a\n * cell's memory is its page cache, not its database. A cell is folded into one snapshot\n * (streamed) past `compactAfter` files (default 64), or once the files after its snapshot hold\n * more than half of it. See docs/browser-host.md.\n */\n | {\n ltx: string;\n node: string;\n leaseTtlMs?: number;\n compactAfter?: number;\n /**\n * The cells' FilesApi in the store worker. A preset on OPFS directory `ltx`: synchronous\n * handles (default, `opfs-sync`), OPFS's asynchronous API (`opfs`), or memory (nothing\n * kept). Or the app's own FilesApi, opened before cellb starts: `{ port }` from\n * `filesApiPort(files)` (served where the app opened it), or `{ module, args }` (built in\n * the store worker). `ltx` then names the storage (the scope of the cells' Web Locks).\n * A port is transferred to the store worker, so it serves one runtime: give each\n * `browserProjectRuntime` a new `filesApiPort`.\n */\n files?: LtxStoreFiles;\n /**\n * A store already running elsewhere (`serveLtxStore(files)`, on the page): no store\n * worker; the VFS sends its reads and commits there. `files` is then ignored. One store\n * per runtime; the app calls its `close()` when the runtime ends.\n */\n ltxStore?: { sab: SharedArrayBuffer; port: MessagePort };\n }\n | { store: ObjectStore; node: string; leaseTtlMs?: number };\n\nexport interface BrowserProjectOptions {\n config: WranglerConfig;\n /**\n * The project's Worker code, imported in this realm once its Workers globals (and with\n * nodejs_compat `Buffer` and `process`) are installed:\n * - `bundle`: one ES module built for browsers (`bundleWorkerForBrowser`), whose\n * `cloudflare:workers` is `PROJECT_WORKERS_MODULE_SHIM` and whose Workers globals read\n * `globalThis.__cellsGlobals`\n * (`null`: the project has no `main`). Worker Loader code becomes Blob-URL modules.\n * - `site`: the base URL of the project's site (`createProjectSite`, hosted by\n * webrun-site-host). `main` and Worker Loader code are imported from it.\n */\n code: { bundle: string | null } | { site: string };\n /**\n * A Dedicated Worker script that serves one loaded Worker (`serveIsolate`): Worker Loader\n * code then runs isolated, one Dedicated Worker per loaded Worker, as celld's isolates.\n * The package ships one: `@statewalker/cellb/isolate-worker`. A function instead starts the\n * Dedicated Worker itself (`() => new Worker(new URL(…, import.meta.url), { type: \"module\" })`,\n * a form bundlers follow).\n */\n isolateScript?: URL | (() => Worker);\n /** An initialized SQLite WASM module (`@sqlite.org/sqlite-wasm`). */\n sqlite3: unknown;\n /** OPFS sahpool name for this host's SQLite files (one pool per worker). */\n pool: string;\n /** OPFS directory for the project's FilesApi (Workers' fs-like bindings, R2 without bucket). */\n filesDir: string;\n assetFiles?: AssetFiles;\n bucket?: BrowserBucket;\n /**\n * Cells this runtime does not host: where to send their events (a `Send` over a MessagePort\n * to the runtime that hosts them, `linkOverPort`), or undefined to host the cell here. With\n * one runtime per worker and `shardOf` as the placement, cells run in parallel threads.\n */\n route?: CellRuntimeOptions[\"route\"];\n /** The OpenAI-compatible endpoint behind the project's `ai` binding (Workers AI). */\n ai?: WorkersAiOptions;\n}\n\nasync function bucketStore(b: BrowserBucket): Promise<ObjectStore> {\n if (\"store\" in b) return b.store;\n if (\"s3\" in b) return s3ObjectStore({ region: \"us-east-1\", ...b.s3 });\n if (\"idb\" in b) return idbObjectStore(b.idb);\n if (\"ltx\" in b) throw new Error(\"an ltx directory is cell storage, not a bucket\");\n const root = await navigator.storage.getDirectory();\n return filesApiObjectStore(\n new BrowserFilesApi({ rootHandle: await root.getDirectoryHandle(b.opfs, { create: true }) }),\n \"\",\n );\n}\n\n/**\n * Cells on the LTX VFS: each cell is a SQLite database whose main file is its LTX files, read\n * page by page (src/adapters/ltx-vfs.ts) from a store: a store worker of this worker's own (on\n * OPFS, memory, or the app's FilesApi through a port or a module), or a store the app runs\n * elsewhere (`ltxStore`).\n */\nexport async function ltxOpener(\n sqlite3: unknown,\n dir: string,\n compactAfter?: number,\n files?: LtxStoreFiles,\n ltxStore?: { sab: SharedArrayBuffer; port: MessagePort },\n) {\n let sab: SharedArrayBuffer;\n let post: (m: unknown) => void;\n let release: () => void;\n if (ltxStore) {\n // The store runs elsewhere (serveLtxStore): only the VFS here.\n sab = ltxStore.sab;\n const port = ltxStore.port;\n post = (m) => port.postMessage(m);\n release = () => port.close();\n } else {\n const store = new Worker(\n new URL(\n \"../ltx/ltx-store-worker.ts\",\n import.meta.url,\n ) /* `.js` in dist/ (scripts/build.mjs) */,\n { type: \"module\" },\n );\n sab = new SharedArrayBuffer(8 + 16 * 65536); // room for a read-ahead run of 64 KiB pages\n // Wait until the store worker runs before any synchronous call: a nested worker is started\n // (its script fetched) through this worker's event loop, which Atomics.wait would block.\n const ready = new Promise<void>((resolve, reject) => {\n store.addEventListener(\"message\", (e) => {\n if (e.data?.op === \"ready\") resolve();\n else if (e.data?.op === \"failed\")\n reject(new Error(`ltx store worker: ${e.data.error as string}`));\n });\n store.addEventListener(\"error\", (e) => reject(new Error(`ltx store worker: ${e.message}`)));\n });\n // A port to the app's FilesApi moves on to the store worker.\n const transfer = files && typeof files === \"object\" && \"port\" in files ? [files.port] : [];\n try {\n store.postMessage({ op: \"init\", sab, dir, compactAfter, files }, transfer);\n await ready;\n } catch (err) {\n store.terminate(); // a store worker that did not start is not left behind\n throw err;\n }\n post = (m) => store.postMessage(m);\n release = () => store.terminate();\n }\n const { name } = installLtxVfs(sqlite3, { sab, post });\n const s3 = sqlite3 as { oo1: { DB: new (o: Record<string, unknown>) => any } };\n const open = (cellKey: string) => {\n const db = new s3.oo1.DB({ filename: cellKey, vfs: name, flags: \"c\" });\n tuneCellConnection(sqlite3, db);\n db.exec(\"PRAGMA journal_mode=MEMORY; PRAGMA synchronous=FULL;\");\n // SQLite's C API for inTransaction() only (no page hook or session capture on this VFS).\n return new WasmSqliteDriver(db, undefined, undefined, (sqlite3 as { capi: never }).capi);\n };\n return Object.assign(open, {\n release,\n reserve: async (n: number) => n,\n });\n}\n\n/** Installs the Workers globals the code reads, then imports its `main`. */\nasync function importWorkerCode(\n config: WranglerConfig,\n code: BrowserProjectOptions[\"code\"],\n scope: WorkerScope,\n): Promise<WorkerModule> {\n const flags = config.compatibility_flags ?? [];\n const nodeCompat = hasNodeCompat(config);\n if (nodeCompat) {\n installNodeGlobals();\n // node:* for bundles built with cellbHostModule (another bundler than bundleWorkerForBrowser);\n // loaded after installNodeGlobals(), as the npm `util` polyfill reads `process`.\n (globalThis as Record<string, unknown>).__cellsNodeModules = (\n await import(\"../node-compat/browser-registry.js\")\n ).nodeRegistryEntries;\n if (populatesProcessEnv(config)) {\n const env = processEnvOf(config);\n // The bundle's own `process` reads it when evaluated; a site's modules use this realm's.\n (globalThis as Record<string, unknown>).__cellsProcessEnv = env;\n Object.assign((globalThis as { process: { env: Record<string, string> } }).process.env, env);\n }\n // node:async_hooks: continuations carry their AsyncLocalStorage stores (with AsyncContext\n // the engine does, and this installs nothing). The code's awaits are lowered so that they go\n // through them: by bundleWorkerForBrowser for a bundle, by createProjectSite (nodeCompat) for\n // a site's modules.\n installAsyncContext();\n }\n const globals = {\n ...workersGlobals,\n Request: workersGlobals.CellsRequest,\n Response: workersGlobals.CellsResponse,\n WebSocketPair: flags.includes(\"websocket_standard_binary_type\")\n ? workersGlobals.StandardWebSocketPair\n : workersGlobals.WebSocketPair,\n };\n if (\"site\" in code) {\n workersHostRegistry({\n workersModule,\n projectWorkersModule: {\n ...workersModule,\n env: scope.env,\n exports: scope.exports,\n waitUntil: scope.waitUntil,\n },\n loadedPrefix: `${code.site}loaded/`,\n emailModule: await import(\"./cloudflare-email.js\"),\n ...globals,\n // Loaded on demand, after installNodeGlobals(): the npm `util` polyfill reads `process`\n // when it is imported.\n node: nodeCompat\n ? (await import(\"../node-compat/browser-registry.js\")).nodeRegistryEntries\n : undefined,\n });\n return config.main\n ? await import(/* @vite-ignore */ `${code.site}modules/~/${config.main}`)\n : { default: {} };\n }\n const g = globalThis as Record<string, unknown>;\n g.__cellsWorkersModule = workersModule;\n g.__cellsProjectScope = scope; // `env` and `exports` of the bundle's cloudflare:workers\n g.__cellsGlobals = globals;\n return code.bundle\n ? await import(\n /* @vite-ignore */ URL.createObjectURL(new Blob([code.bundle], { type: \"text/javascript\" }))\n )\n : { default: {} };\n}\n\n/**\n * A project's runtime in this worker: installs the Workers globals, imports the code and\n * builds its Worker Loader; `close()` also releases the node's bucket lease.\n */\nexport async function browserProjectRuntime(opts: BrowserProjectOptions) {\n const scope = workerScope(loadTimeEnv(opts.config, opts.ai));\n const module = await importWorkerCode(opts.config, opts.code, scope);\n const site = \"site\" in opts.code ? opts.code.site : undefined;\n // With an IndexedDB bucket, cells live in memory and in the bucket's logs (no OPFS pool).\n const openSql =\n opts.bucket && \"ltx\" in opts.bucket\n ? await ltxOpener(\n opts.sqlite3,\n opts.bucket.ltx,\n opts.bucket.compactAfter,\n opts.bucket.files,\n opts.bucket.ltxStore,\n )\n : opts.bucket && \"idb\" in opts.bucket\n ? Object.assign(wasmMemoryOpener(opts.sqlite3 as never), {\n release() {},\n reserve: async (n: number) => n,\n })\n : await sahpoolOpener(opts.sqlite3 as never, {\n name: opts.pool,\n initialCapacity: 64, // grows on demand (sahpoolOpener)\n });\n const root = await navigator.storage.getDirectory();\n const files = new BrowserFilesApi({\n rootHandle: await root.getDirectoryHandle(opts.filesDir, { create: true }),\n });\n // An `ltx` directory is the cells' own storage (the VFS), not a fleet bucket.\n const store = opts.bucket && !(\"ltx\" in opts.bucket) ? await bucketStore(opts.bucket) : undefined;\n const shared =\n opts.bucket && store\n ? celldBucket(store, { node: opts.bucket.node, leaseTtlMs: opts.bucket.leaseTtlMs })\n : undefined;\n const { runtime, unsupported } = createProjectRuntime(opts.config, module, {\n openSql,\n files,\n assetFiles: opts.assetFiles,\n loadModules: site ? siteModuleLoader(site) : browserModuleLoader(),\n isolatedModules: opts.isolateScript\n ? browserIsolatedLoader({\n isolateScript: opts.isolateScript,\n siteBaseUrl: site,\n storagePrefix: `${opts.pool}-iso`,\n storage: () => shared, // facets of loaded code are logged like the root's own\n })\n : undefined,\n storage: shared, // R2 objects in the fleet bucket too, as celld keeps them\n route: opts.route,\n ai: opts.ai,\n });\n scope.bind(runtime);\n return {\n runtime,\n unsupported,\n bucket: shared,\n close: async () => {\n await runtime.close();\n openSql.release(); // the pool's files, for the next worker that opens it\n },\n };\n}\n"]}
1
+ {"version":3,"file":"browser-host.js","sourceRoot":"","sources":["../../src/project/browser-host.ts"],"names":[],"mappings":"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","sourcesContent":["import { BrowserFilesApi } from \"@statewalker/webrun-files-browser\";\nimport { installLtxVfs } from \"../adapters/ltx-vfs.js\";\nimport {\n sahpoolOpener,\n tuneCellConnection,\n WasmSqliteDriver,\n wasmMemoryOpener,\n} from \"../adapters/wasm-sqlite.js\";\nimport type { AssetFiles } from \"../bindings/assets.js\";\nimport type { WorkersAiOptions } from \"../bindings/workers-ai.js\";\nimport { celldBucket } from \"../bucket/celld-cells.js\";\nimport { idbObjectStore } from \"../bucket/idb-object-store.js\";\nimport { filesApiObjectStore, type ObjectStore } from \"../bucket/object-store.js\";\nimport { s3ObjectStore } from \"../bucket/s3-object-store.js\";\nimport type { CellRuntimeOptions, WorkerModule } from \"../core/runtime.js\";\nimport { browserIsolatedLoader } from \"../isolate/browser.js\";\nimport type { LtxStoreFiles } from \"../ltx/ltx-page-server.js\";\nimport { installAsyncContext } from \"../node-compat/async_hooks.js\";\nimport { installNodeGlobals } from \"../node-compat/install.js\";\nimport { browserModuleLoader } from \"./browser-modules.js\";\nimport * as workersModule from \"./cloudflare-workers.js\";\nimport { siteModuleLoader, workersHostRegistry } from \"./site-loader.js\";\nimport { type WorkerScope, workerScope } from \"./worker-scope.js\";\nimport * as workersGlobals from \"./workers-globals-module.js\";\nimport {\n createProjectRuntime,\n hasNodeCompat,\n loadProjectBindings,\n loadTimeEnv,\n populatesProcessEnv,\n processEnvOf,\n type WranglerConfig,\n} from \"./wrangler.js\";\n\nexport { populatesProcessEnv, processEnvOf };\n\n/**\n * Where a browser-hosted project keeps its cells when they must outlive the page or move to\n * other nodes: a celld fleet bucket. Cells, facets and alarms are then exactly celld's\n * (ownership in `own.json`, LTX logs, wake index) and R2 objects live in it too, so the same\n * cells can be served by this browser, by other browsers and by celld nodes, in turn.\n *\n * - `s3`: an S3-compatible bucket, reached directly (the bucket must allow CORS for the page's\n * origin: methods GET/PUT/DELETE/HEAD, request headers `authorization`, `content-type`,\n * `x-amz-*`, `if-match`, `if-none-match`; exposed headers `etag`, `last-modified`,\n * `x-amz-meta-celld-r2`) or through a same-origin proxy (`endpoint` = the proxy,\n * `signAs` = the real endpoint: SigV4 signs the real host and path).\n * - `opfs`: a bucket in this origin's OPFS — persistence without a server. Conditional writes\n * are atomic only within one writer, so one tab or worker at a time should own its cells.\n * - `store`: any ObjectStore.\n */\nexport type BrowserBucket =\n | {\n s3: {\n endpoint: string;\n signAs?: string;\n bucket: string;\n prefix?: string;\n region?: string;\n accessKeyId: string;\n secretAccessKey: string;\n };\n node: string;\n leaseTtlMs?: number;\n }\n | { opfs: string; node: string; leaseTtlMs?: number }\n /**\n * `idb`: a bucket in this origin's IndexedDB (atomic conditional writes across tabs and\n * workers). Cells then run SQLite in memory and persist through the bucket's page-level logs:\n * no OPFS pool, so any number of workers can serve cells at once.\n */\n | { idb: string; node: string; leaseTtlMs?: number }\n /**\n * `ltx`: cells as celld keeps them, LTX files (a snapshot and one file per commit) in an OPFS\n * directory, read page by page (a SQLite VFS over a store worker): no OPFS pool, and a\n * cell's memory is its page cache, not its database. A cell is folded into one snapshot\n * (streamed) past `compactAfter` files (default 64), or once the files after its snapshot hold\n * more than half of it. See docs/browser-host.md.\n */\n | {\n ltx: string;\n node: string;\n leaseTtlMs?: number;\n compactAfter?: number;\n /**\n * The cells' FilesApi in the store worker. A preset on OPFS directory `ltx`: synchronous\n * handles (default, `opfs-sync`), OPFS's asynchronous API (`opfs`), or memory (nothing\n * kept). Or the app's own FilesApi, opened before cellb starts: `{ port }` from\n * `filesApiPort(files)` (served where the app opened it), or `{ module, args }` (built in\n * the store worker). `ltx` then names the storage (the scope of the cells' Web Locks).\n * A port is transferred to the store worker, so it serves one runtime: give each\n * `browserProjectRuntime` a new `filesApiPort`.\n */\n files?: LtxStoreFiles;\n /**\n * A store already running elsewhere (`serveLtxStore(files)`, on the page): no store\n * worker; the VFS sends its reads and commits there. `files` is then ignored. One store\n * per runtime; the app calls its `close()` when the runtime ends.\n */\n ltxStore?: { sab: SharedArrayBuffer; port: MessagePort };\n }\n | { store: ObjectStore; node: string; leaseTtlMs?: number };\n\nexport interface BrowserProjectOptions {\n config: WranglerConfig;\n /**\n * The project's Worker code, imported in this realm once its Workers globals (and with\n * nodejs_compat `Buffer` and `process`) are installed:\n * - `bundle`: one ES module built for browsers (`bundleWorkerForBrowser`), whose\n * `cloudflare:workers` is `PROJECT_WORKERS_MODULE_SHIM` and whose Workers globals read\n * `globalThis.__cellsGlobals`\n * (`null`: the project has no `main`). Worker Loader code becomes Blob-URL modules.\n * - `site`: the base URL of the project's site (`createProjectSite`, hosted by\n * webrun-site-host). `main` and Worker Loader code are imported from it.\n */\n code: { bundle: string | null } | { site: string };\n /**\n * A Dedicated Worker script that serves one loaded Worker (`serveIsolate`): Worker Loader\n * code then runs isolated, one Dedicated Worker per loaded Worker, as celld's isolates.\n * The package ships one: `@statewalker/cellb/isolate-worker`. A function instead starts the\n * Dedicated Worker itself (`() => new Worker(new URL(…, import.meta.url), { type: \"module\" })`,\n * a form bundlers follow).\n */\n isolateScript?: URL | (() => Worker);\n /** An initialized SQLite WASM module (`@sqlite.org/sqlite-wasm`). */\n sqlite3: unknown;\n /** OPFS sahpool name for this host's SQLite files (one pool per worker). */\n pool: string;\n /** OPFS directory for the project's FilesApi (Workers' fs-like bindings, R2 without bucket). */\n filesDir: string;\n assetFiles?: AssetFiles;\n bucket?: BrowserBucket;\n /**\n * Cells this runtime does not host: where to send their events (a `Send` over a MessagePort\n * to the runtime that hosts them, `linkOverPort`), or undefined to host the cell here. With\n * one runtime per worker and `shardOf` as the placement, cells run in parallel threads.\n */\n route?: CellRuntimeOptions[\"route\"];\n /** The OpenAI-compatible endpoint behind the project's `ai` binding (Workers AI). */\n ai?: WorkersAiOptions;\n}\n\nasync function bucketStore(b: BrowserBucket): Promise<ObjectStore> {\n if (\"store\" in b) return b.store;\n if (\"s3\" in b) return s3ObjectStore({ region: \"us-east-1\", ...b.s3 });\n if (\"idb\" in b) return idbObjectStore(b.idb);\n if (\"ltx\" in b) throw new Error(\"an ltx directory is cell storage, not a bucket\");\n const root = await navigator.storage.getDirectory();\n return filesApiObjectStore(\n new BrowserFilesApi({ rootHandle: await root.getDirectoryHandle(b.opfs, { create: true }) }),\n \"\",\n );\n}\n\n/**\n * Cells on the LTX VFS: each cell is a SQLite database whose main file is its LTX files, read\n * page by page (src/adapters/ltx-vfs.ts) from a store: a store worker of this worker's own (on\n * OPFS, memory, or the app's FilesApi through a port or a module), or a store the app runs\n * elsewhere (`ltxStore`).\n */\nexport async function ltxOpener(\n sqlite3: unknown,\n dir: string,\n compactAfter?: number,\n files?: LtxStoreFiles,\n ltxStore?: { sab: SharedArrayBuffer; port: MessagePort },\n) {\n let sab: SharedArrayBuffer;\n let post: (m: unknown) => void;\n let release: () => void;\n if (ltxStore) {\n // The store runs elsewhere (serveLtxStore): only the VFS here.\n sab = ltxStore.sab;\n const port = ltxStore.port;\n post = (m) => port.postMessage(m);\n release = () => port.close();\n } else {\n const store = new Worker(\n new URL(\n \"../ltx/ltx-store-worker.ts\",\n import.meta.url,\n ) /* `.js` in dist/ (scripts/build.mjs) */,\n { type: \"module\" },\n );\n sab = new SharedArrayBuffer(8 + 16 * 65536); // room for a read-ahead run of 64 KiB pages\n // Wait until the store worker runs before any synchronous call: a nested worker is started\n // (its script fetched) through this worker's event loop, which Atomics.wait would block.\n const ready = new Promise<void>((resolve, reject) => {\n store.addEventListener(\"message\", (e) => {\n if (e.data?.op === \"ready\") resolve();\n else if (e.data?.op === \"failed\")\n reject(new Error(`ltx store worker: ${e.data.error as string}`));\n });\n store.addEventListener(\"error\", (e) => reject(new Error(`ltx store worker: ${e.message}`)));\n });\n // A port to the app's FilesApi moves on to the store worker.\n const transfer = files && typeof files === \"object\" && \"port\" in files ? [files.port] : [];\n try {\n store.postMessage({ op: \"init\", sab, dir, compactAfter, files }, transfer);\n await ready;\n } catch (err) {\n store.terminate(); // a store worker that did not start is not left behind\n throw err;\n }\n post = (m) => store.postMessage(m);\n release = () => store.terminate();\n }\n const { name } = installLtxVfs(sqlite3, { sab, post });\n const s3 = sqlite3 as { oo1: { DB: new (o: Record<string, unknown>) => any } };\n const open = (cellKey: string) => {\n const db = new s3.oo1.DB({ filename: cellKey, vfs: name, flags: \"c\" });\n tuneCellConnection(sqlite3, db);\n db.exec(\"PRAGMA journal_mode=MEMORY; PRAGMA synchronous=FULL;\");\n // SQLite's C API for inTransaction() only (no page hook or session capture on this VFS).\n return new WasmSqliteDriver(db, undefined, undefined, (sqlite3 as { capi: never }).capi);\n };\n return Object.assign(open, {\n release,\n reserve: async (n: number) => n,\n });\n}\n\n/** Installs the Workers globals the code reads, then imports its `main`. */\nasync function importWorkerCode(\n config: WranglerConfig,\n code: BrowserProjectOptions[\"code\"],\n scope: WorkerScope,\n): Promise<WorkerModule> {\n const flags = config.compatibility_flags ?? [];\n const nodeCompat = hasNodeCompat(config);\n if (nodeCompat) {\n installNodeGlobals();\n // node:* for bundles built with cellbHostModule (another bundler than bundleWorkerForBrowser);\n // loaded after installNodeGlobals(), as the npm `util` polyfill reads `process`.\n (globalThis as Record<string, unknown>).__cellsNodeModules = (\n await import(\"../node-compat/browser-registry.js\")\n ).nodeRegistryEntries;\n if (populatesProcessEnv(config)) {\n const env = processEnvOf(config);\n // The bundle's own `process` reads it when evaluated; a site's modules use this realm's.\n (globalThis as Record<string, unknown>).__cellsProcessEnv = env;\n Object.assign((globalThis as { process: { env: Record<string, string> } }).process.env, env);\n }\n // node:async_hooks: continuations carry their AsyncLocalStorage stores (with AsyncContext\n // the engine does, and this installs nothing). The code's awaits are lowered so that they go\n // through them: by bundleWorkerForBrowser for a bundle, by createProjectSite (nodeCompat) for\n // a site's modules.\n installAsyncContext();\n }\n const globals = {\n ...workersGlobals,\n Request: workersGlobals.CellsRequest,\n Response: workersGlobals.CellsResponse,\n WebSocketPair: flags.includes(\"websocket_standard_binary_type\")\n ? workersGlobals.StandardWebSocketPair\n : workersGlobals.WebSocketPair,\n };\n if (\"site\" in code) {\n workersHostRegistry({\n workersModule,\n projectWorkersModule: {\n ...workersModule,\n env: scope.env,\n exports: scope.exports,\n waitUntil: scope.waitUntil,\n },\n loadedPrefix: `${code.site}loaded/`,\n emailModule: await import(\"./cloudflare-email.js\"),\n ...globals,\n // Loaded on demand, after installNodeGlobals(): the npm `util` polyfill reads `process`\n // when it is imported.\n node: nodeCompat\n ? (await import(\"../node-compat/browser-registry.js\")).nodeRegistryEntries\n : undefined,\n });\n return config.main\n ? await import(/* @vite-ignore */ `${code.site}modules/~/${config.main}`)\n : { default: {} };\n }\n const g = globalThis as Record<string, unknown>;\n g.__cellsWorkersModule = workersModule;\n g.__cellsProjectScope = scope; // `env` and `exports` of the bundle's cloudflare:workers\n g.__cellsGlobals = globals;\n return code.bundle\n ? await import(\n /* @vite-ignore */ URL.createObjectURL(new Blob([code.bundle], { type: \"text/javascript\" }))\n )\n : { default: {} };\n}\n\n/**\n * A project's runtime in this worker: installs the Workers globals, imports the code and\n * builds its Worker Loader; `close()` also releases the node's bucket lease.\n */\nexport async function browserProjectRuntime(opts: BrowserProjectOptions) {\n const scope = workerScope(loadTimeEnv(opts.config, opts.ai));\n const module = await importWorkerCode(opts.config, opts.code, scope);\n const site = \"site\" in opts.code ? opts.code.site : undefined;\n // With an IndexedDB bucket, cells live in memory and in the bucket's logs (no OPFS pool).\n const openSql =\n opts.bucket && \"ltx\" in opts.bucket\n ? await ltxOpener(\n opts.sqlite3,\n opts.bucket.ltx,\n opts.bucket.compactAfter,\n opts.bucket.files,\n opts.bucket.ltxStore,\n )\n : opts.bucket && \"idb\" in opts.bucket\n ? Object.assign(wasmMemoryOpener(opts.sqlite3 as never), {\n release() {},\n reserve: async (n: number) => n,\n })\n : await sahpoolOpener(opts.sqlite3 as never, {\n name: opts.pool,\n initialCapacity: 64, // grows on demand (sahpoolOpener)\n });\n const root = await navigator.storage.getDirectory();\n const files = new BrowserFilesApi({\n rootHandle: await root.getDirectoryHandle(opts.filesDir, { create: true }),\n });\n // An `ltx` directory is the cells' own storage (the VFS), not a fleet bucket.\n const store = opts.bucket && !(\"ltx\" in opts.bucket) ? await bucketStore(opts.bucket) : undefined;\n const shared =\n opts.bucket && store\n ? celldBucket(store, { node: opts.bucket.node, leaseTtlMs: opts.bucket.leaseTtlMs })\n : undefined;\n const { runtime, unsupported } = createProjectRuntime(opts.config, module, {\n bindings: await loadProjectBindings(opts.config),\n openSql,\n files,\n assetFiles: opts.assetFiles,\n loadModules: site ? siteModuleLoader(site) : browserModuleLoader(),\n isolatedModules: opts.isolateScript\n ? browserIsolatedLoader({\n isolateScript: opts.isolateScript,\n siteBaseUrl: site,\n storagePrefix: `${opts.pool}-iso`,\n storage: () => shared, // facets of loaded code are logged like the root's own\n })\n : undefined,\n storage: shared, // R2 objects in the fleet bucket too, as celld keeps them\n route: opts.route,\n ai: opts.ai,\n });\n scope.bind(runtime);\n return {\n runtime,\n unsupported,\n bucket: shared,\n close: async () => {\n await runtime.close();\n openSql.release(); // the pool's files, for the next worker that opens it\n },\n };\n}\n"]}
@@ -1,28 +1,7 @@
1
1
  import { type RemoteRuntime } from "../transport/cells-http.js";
2
2
  import { type BrowserBucket, type BrowserProjectOptions } from "./browser-host.js";
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
- */
8
- export declare const TAB_INIT = "cellb:tab-shard";
9
- /** The host calls between shards go to through the router: `http://cellb.internal/<project>/`. */
10
- export declare const INTERNAL_ORIGIN = "http://cellb.internal";
11
- /** What a shard worker shared by tabs is told: no peers, it reaches them through the router. */
12
- export interface TabShardInit {
13
- type: typeof TAB_INIT;
14
- name: string;
15
- shard: number;
16
- shards: number;
17
- config: BrowserProjectOptions["config"];
18
- code: BrowserProjectOptions["code"];
19
- assetFiles?: BrowserProjectOptions["assetFiles"];
20
- /** The OpenAI-compatible endpoint behind the project's `ai` binding. */
21
- ai?: BrowserProjectOptions["ai"];
22
- bucket?: BrowserBucket;
23
- pool: string;
24
- filesDir: string;
25
- }
3
+ import { INTERNAL_ORIGIN, TAB_INIT, type TabShardInit } from "./browser-tab-protocol.js";
4
+ export { INTERNAL_ORIGIN, TAB_INIT, type TabShardInit };
26
5
  /**
27
6
  * The worker side: hosts one shard when a page says so — of `startProjectShards` (peers wired
28
7
  * directly) or of `joinProjectShards` (shared by the tabs, linked to the ServiceWorker's router).
@@ -18,16 +18,10 @@ import { H, keepUpgrade } from "../transport/cells-link.js";
18
18
  import { connectRuntime, linkOverPort, serveRuntime } from "../transport/port.js";
19
19
  import { CellsResponse, CfWebSocket, takeClientPort } from "../ws/server.js";
20
20
  import { browserProjectRuntime, } from "./browser-host.js";
21
+ import { INTERNAL_ORIGIN, TAB_INIT } from "./browser-tab-protocol.js";
22
+ export { INTERNAL_ORIGIN, TAB_INIT };
21
23
  const INIT = "cellb:shard";
22
24
  const CLOSE = "cellb:shard-close";
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
- */
28
- export const TAB_INIT = "cellb:tab-shard";
29
- /** The host calls between shards go to through the router: `http://cellb.internal/<project>/`. */
30
- export const INTERNAL_ORIGIN = "http://cellb.internal";
31
25
  /**
32
26
  * The worker side: hosts one shard when a page says so — of `startProjectShards` (peers wired
33
27
  * directly) or of `joinProjectShards` (shared by the tabs, linked to the ServiceWorker's router).
@@ -1 +1 @@
1
- {"version":3,"file":"browser-shards.js","sourceRoot":"","sources":["../../src/project/browser-shards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,iBAAiB,EAEjB,wBAAwB,GACzB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAElD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAsB,MAAM,4BAA4B,CAAC;AAClF,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC7E,OAAO,EAGL,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,IAAI,GAAG,aAAa,CAAC;AAC3B,MAAM,KAAK,GAAG,mBAAmB,CAAC;AAClC;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,iBAAiB,CAAC;AAC1C,kGAAkG;AAClG,MAAM,CAAC,MAAM,eAAe,GAAG,uBAAuB,CAAC;AAmCvD;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAKjC;IACC,MAAM,KAAK,GAAG,UAGb,CAAC;IACF,IAAI,IAAmE,CAAC;IACxE,IAAI,OAAsC,CAAC;IAC3C,MAAM,OAAO,GAAG,GAAG,EAAE,CACnB,OAAO,IAAI,CAAC,OAAO,KAAK,UAAU;QAChC,CAAC,CAAE,IAAI,CAAC,OAAkC,EAAE;QAC5C,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpC,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,KAAK,EAAE,CAAe,EAAE,EAAE;QAC1D,MAAM,IAAI,GAAI,CAAC,CAAC,IAAsC,EAAE,IAAI,CAAC;QAC7D,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,IAAc,CAAC;YAAE,OAAO;QAC9D,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAgB,CAAC;QACxC,IAAI,CAAC;YACH,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;gBACnB,IAAI,CAAC;oBACH,wEAAwE;oBACxE,WAAW,CAAC,MAAM,EAAE,CAAC;oBACrB,MAAM,IAAI,EAAE,KAAK,EAAE,CAAC;gBACtB,CAAC;wBAAS,CAAC;oBACT,IAAI,GAAG,SAAS,CAAC;oBACjB,oFAAoF;oBACpF,MAAM,OAAO,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;oBACvC,OAAO,GAAG,SAAS,CAAC;gBACtB,CAAC;gBACD,OAAO,KAAK,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,CAAC;YACD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACtB,MAAM,IAAI,GAAG,CAAC,CAAC,IAAoB,CAAC;gBACpC,IAAI,KAAsC,CAAC;gBAC3C,MAAM,YAAY,GAAG,IAAI,OAAO,CAAoB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;gBACxE,IAAI,GAAG,MAAM,qBAAqB,CAAC;oBACjC,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,UAAU,EAAE,IAAI,CAAC,UAAU;oBAC3B,EAAE,EAAE,IAAI,CAAC,EAAE;oBACX,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,OAAO,EAAE,MAAM,OAAO,EAAE;oBACxB,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,aAAa,EAAE,IAAI,CAAC,aAAa;oBACjC,KAAK,EAAE,aAAa,CAAC,IAAI,EAAE,YAAY,CAAC;iBACzC,CAAC,CAAC;gBACH,wFAAwF;gBACxF,wFAAwF;gBACxF,wCAAwC;gBACxC,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;gBACvE,OAAO,GAAG,iBAAiB,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,eAAe,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBAChF,KAAK,CAAC,OAAO,CAAC,CAAC;gBACf,OAAO,KAAK,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;YACxE,CAAC;YACD,MAAM,IAAI,GAAG,CAAC,CAAC,IAAiB,CAAC;YACjC,MAAM,KAAK,GAAG,IAAI,GAAG,EAA+C,CAAC;YACrE,MAAM,MAAM,GAAkB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAgB,CAAC,CAAC,CAAC,wBAAwB;YACnF,KAAK,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;gBAC7C,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAgB,CAAC;gBAC3C,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;oBAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;;oBAC5E,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACzB,CAAC;YACD,IAAI,GAAG,MAAM,qBAAqB,CAAC;gBACjC,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,EAAE,EAAE,IAAI,CAAC,EAAE;gBACX,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,OAAO,EAAE,MAAM,OAAO,EAAE;gBACxB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,aAAa,EAAE,IAAI,CAAC,aAAa;gBACjC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE;oBAClB,MAAM,KAAK,GAAG,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;oBAClD,OAAO,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBAC7D,CAAC;aACF,CAAC,CAAC;YACH,KAAK,MAAM,IAAI,IAAI,MAAM;gBAAE,MAAM,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YAClE,KAAK,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QACjE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,KAAK,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAE,GAAa,EAAE,KAAK,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC;QAChF,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,GAAa;IACpC,MAAM,EAAE,GAAI,GAAqD,CAAC,SAAS,CAAC;IAC5E,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE;QAAE,OAAO,GAAG,CAAC;IAC1C,OAAO,wBAAwB,CAC7B,cAAc,CAAC,EAAE,CAAC,EAClB,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,IAAI,EAAE,CAChD,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CACpB,IAAqD,EACrD,OAAmC;IAEnC,MAAM,MAAM,GAAG,GAAG,eAAe,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;IACtE,OAAO,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE;QAClB,MAAM,KAAK,GAAG,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAClD,IAAI,KAAK,KAAK,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAC3C,iFAAiF;QACjF,OAAO,KAAK,EAAE,GAAG,EAAE,EAAE;YACnB,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC;YAC1B,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,CAAC;gBAC9D,MAAM,SAAS,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,IAAI,EAAE,CAAC;qBAChE,KAAK,CAAC,GAAG,CAAC;qBACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;qBACpB,MAAM,CAAC,OAAO,CAAC,CAAC;gBACnB,MAAM,OAAO,GAAuB,EAAE,CAAC;gBACvC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO;oBAAE,IAAI,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC;wBAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBACpF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;gBACzD,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,GAAG,CAAC,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;gBAClF,OAAO,IAAI,aAAa,CAAC,IAAI,EAAE;oBAC7B,MAAM,EAAE,GAAG;oBACX,SAAS,EAAE,IAAI,WAAW,CAAC,IAAI,CAAC;oBAChC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,wBAAwB,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE;iBAChE,CAAC,CAAC;YACL,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YACzC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACzC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,CAAC;gBACH,OAAO,MAAM,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,OAAO,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;YAC5E,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,8EAA8E;gBAC9E,kFAAkF;gBAClF,sEAAsE;gBACtE,IACE,GAAG,YAAY,KAAK;oBACpB,GAAG,CAAC,IAAI,KAAK,eAAe;oBAC5B,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,0DAA0D,CAAC;oBAElF,MAAM,IAAI,KAAK,CACb,wFAAwF,CACzF,CAAC;gBACJ,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAaD,gGAAgG;AAChG,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAaxC;IACC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7E,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,IAAa,EAAE,KAAK,GAAkB,EAAE,EAAE,EAAE,CAClE,IAAI,OAAO,CAA0D,CAAC,OAAO,EAAE,EAAE;QAC/E,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,cAAc,EAAE,CAAC;QAC9C,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,EAAE,EAAE;YACtB,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC,CAAC;QACF,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IACL,qFAAqF;IACrF,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;QAChC,KAAK,EAAE,EAAwB;QAC/B,KAAK,EAAE,EAAmB;KAC3B,CAAC,CAAC,CAAC;IACJ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE;QAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,IAAI,CAAC,KAAK,CAAC;gBAAE,SAAS;YACtB,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,cAAc,EAAE,CAAC;YAC9C,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;YACjD,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC5B,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;YAClD,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;IACH,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,cAAc,EAAE,CAAC,CAAC;IACxD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACnB,GAAG,CACD,CAAC,EACD;YACE,IAAI,EAAE,IAAI;YACV,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,EAAE,EAAE;YAC5E,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE;YACzB,QAAQ,EAAE,GAAG,IAAI,CAAC,IAAI,UAAU,CAAC,EAAE;YACnC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK;SACH,EACrB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CACvC,CACF,CACF,CAAC;QACF,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC1C,IAAI,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QAC9E,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/E,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,OAAO;YACL,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;YAC3D,MAAM,EAAE,OAAO;YACf,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE;YACzC,KAAK,CAAC,KAAK;gBACT,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gBACjD,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC/D,KAAK,MAAM,CAAC,IAAI,OAAO;oBAAE,CAAC,CAAC,SAAS,EAAE,CAAC;YACzC,CAAC;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,KAAK,MAAM,CAAC,IAAI,OAAO;YAAE,CAAC,CAAC,SAAS,EAAE,CAAC;QACvC,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC","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"]}
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\";\nimport { INTERNAL_ORIGIN, TAB_INIT, type TabShardInit } from \"./browser-tab-protocol.js\";\n\nexport { INTERNAL_ORIGIN, TAB_INIT, type TabShardInit };\n\nconst INIT = \"cellb:shard\";\nconst CLOSE = \"cellb:shard-close\";\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"]}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * What a tab and a shard worker it starts agree on (`joinProjectShards` → `serveProjectShard`).
3
+ * Its own module, with type-only imports, so that the tab side and the ServiceWorker do not
4
+ * import the shard's runtime (browser-shards.ts → browser-host.ts and every binding) for two
5
+ * constants.
6
+ */
7
+ import type { BrowserBucket, BrowserProjectOptions } from "./browser-host.js";
8
+ /**
9
+ * A shard of a project shared by the tabs of an origin (`joinProjectShards`): it serves through
10
+ * the ServiceWorker's router (webrun-http-browser's `serveHttpInWorker`), which the tab attaches
11
+ * it to, and reaches the other shards through it.
12
+ */
13
+ export declare const TAB_INIT = "cellb:tab-shard";
14
+ /** The host calls between shards go to through the router: `http://cellb.internal/<project>/`. */
15
+ export declare const INTERNAL_ORIGIN = "http://cellb.internal";
16
+ /** What a shard worker shared by tabs is told: no peers, it reaches them through the router. */
17
+ export interface TabShardInit {
18
+ type: typeof TAB_INIT;
19
+ name: string;
20
+ shard: number;
21
+ shards: number;
22
+ config: BrowserProjectOptions["config"];
23
+ code: BrowserProjectOptions["code"];
24
+ assetFiles?: BrowserProjectOptions["assetFiles"];
25
+ /** The OpenAI-compatible endpoint behind the project's `ai` binding. */
26
+ ai?: BrowserProjectOptions["ai"];
27
+ bucket?: BrowserBucket;
28
+ pool: string;
29
+ filesDir: string;
30
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * A shard of a project shared by the tabs of an origin (`joinProjectShards`): it serves through
3
+ * the ServiceWorker's router (webrun-http-browser's `serveHttpInWorker`), which the tab attaches
4
+ * it to, and reaches the other shards through it.
5
+ */
6
+ export const TAB_INIT = "cellb:tab-shard";
7
+ /** The host calls between shards go to through the router: `http://cellb.internal/<project>/`. */
8
+ export const INTERNAL_ORIGIN = "http://cellb.internal";
9
+ //# sourceMappingURL=browser-tab-protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-tab-protocol.js","sourceRoot":"","sources":["../../src/project/browser-tab-protocol.ts"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,iBAAiB,CAAC;AAC1C,kGAAkG;AAClG,MAAM,CAAC,MAAM,eAAe,GAAG,uBAAuB,CAAC","sourcesContent":["/**\n * What a tab and a shard worker it starts agree on (`joinProjectShards` → `serveProjectShard`).\n * Its own module, with type-only imports, so that the tab side and the ServiceWorker do not\n * import the shard's runtime (browser-shards.ts → browser-host.ts and every binding) for two\n * constants.\n */\nimport type { BrowserBucket, BrowserProjectOptions } from \"./browser-host.js\";\n\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"]}
@@ -22,7 +22,7 @@ import { errorResponse } from "../transport/cells-http.js";
22
22
  import { H } from "../transport/cells-link.js";
23
23
  import { SW_SOCKET } from "../ws/sw-connector.js";
24
24
  import { applyWorkerCookies, withPageCookies } from "./browser-cookies.js";
25
- import { INTERNAL_ORIGIN, TAB_INIT } from "./browser-shards.js";
25
+ import { INTERNAL_ORIGIN, TAB_INIT } from "./browser-tab-protocol.js";
26
26
  /** The ServiceWorker asks a project's tabs to attach their shards again (a host page's wait). */
27
27
  const NEED_LINKS = "cellb:need-links";
28
28
  /** A page opens a socket (`serviceWorkerConnector`). */