@statewalker/cellb 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -3
- package/bin/cellb.mjs +20 -0
- package/dist/browser.d.ts +2 -0
- package/dist/browser.js +1 -0
- package/dist/browser.js.map +1 -1
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +62 -0
- package/dist/cli.js.map +1 -0
- package/dist/isolate/browser.d.ts +2 -1
- package/dist/isolate/browser.js +2 -1
- package/dist/isolate/browser.js.map +1 -1
- package/dist/isolate/isolate.js +5 -3
- package/dist/isolate/isolate.js.map +1 -1
- package/dist/isolate/protocol.d.ts +4 -2
- package/dist/isolate/protocol.js +4 -4
- package/dist/isolate/protocol.js.map +1 -1
- package/dist/node.d.ts +3 -0
- package/dist/node.js +2 -0
- package/dist/node.js.map +1 -1
- package/dist/project/browser-host.d.ts +6 -12
- package/dist/project/browser-host.js +2 -25
- package/dist/project/browser-host.js.map +1 -1
- package/dist/project/browser-load.d.ts +22 -0
- package/dist/project/browser-load.js +63 -0
- package/dist/project/browser-load.js.map +1 -0
- package/dist/project/build.d.ts +14 -0
- package/dist/project/build.js +53 -0
- package/dist/project/build.js.map +1 -0
- package/dist/project/built-project.d.ts +88 -0
- package/dist/project/built-project.js +118 -0
- package/dist/project/built-project.js.map +1 -0
- package/dist/project/node-load.d.ts +14 -0
- package/dist/project/node-load.js +187 -0
- package/dist/project/node-load.js.map +1 -0
- package/dist/project/wrangler.d.ts +9 -0
- package/dist/project/wrangler.js +24 -0
- package/dist/project/wrangler.js.map +1 -1
- package/dist/ws/server.d.ts +24 -6
- package/dist/ws/server.js +52 -16
- package/dist/ws/server.js.map +1 -1
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ mix celld nodes, cellb nodes and browsers.
|
|
|
24
24
|
|
|
25
25
|
```sh
|
|
26
26
|
npm install @statewalker/cellb
|
|
27
|
-
npm install esbuild # for
|
|
27
|
+
npm install esbuild # for loadProject and cellb build on Node (an optional peer dependency)
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
The package has three entry points, one per platform, and two more for bundling. Published, it is
|
|
@@ -37,8 +37,8 @@ worker is started that way (checked with a Vite build, see `scripts/pack-check.m
|
|
|
37
37
|
| Import | What it gives |
|
|
38
38
|
|---|---|
|
|
39
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 |
|
|
40
|
-
| `@statewalker/cellb/node` | `nodeSqliteOpener`, `sqliteObjectStore` (celld dev's local bucket), `loadNodeProject`, `applyNodeD1Migrations`, and celld's peer protocol (`startCelldPeerServer`, `celldPeers`) |
|
|
41
|
-
| `@statewalker/cellb/browser` | `browserProjectRuntime`, `startProjectShards`, `joinProjectShards` and `serveProjectShard` (shards in workers and tabs), `installProjectRouter` (the ServiceWorker side), `sahpoolOpener`, `idbObjectStore`, `serviceWorkerConnector` |
|
|
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
|
+
| `@statewalker/cellb/browser` | `loadProject` (a `cellb build` folder by URL), `browserProjectRuntime`, `startProjectShards`, `joinProjectShards` and `serveProjectShard` (shards in workers and tabs), `installProjectRouter` (the ServiceWorker side), `sahpoolOpener`, `idbObjectStore`, `serviceWorkerConnector` |
|
|
42
42
|
| `@statewalker/cellb/site` | `createProjectSite`: a project's sources compiled in the browser and served by an in-browser HTTP server (`browserProjectRuntime({ site })`). Needs the optional peer dependencies `@statewalker/webrun-modules` and `@statewalker/webrun-site-builder`; the site is hosted in a ServiceWorker with `@statewalker/webrun-site-host`, also an optional peer |
|
|
43
43
|
| `@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`) |
|
|
44
44
|
| `@statewalker/cellb/isolate-worker` | the Dedicated Worker that runs a Worker-Loader Worker in a realm of its own (`isolateScript`) |
|
|
@@ -56,6 +56,49 @@ runtime answers requests with 503, and an object's code still running fails with
|
|
|
56
56
|
|
|
57
57
|
## Examples
|
|
58
58
|
|
|
59
|
+
### One project loader for Node and browsers
|
|
60
|
+
|
|
61
|
+
`loadProject(source, options)` has the same name and options in both entry points:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
// Node: a folder with wrangler.json(c), its `main` bundled with esbuild
|
|
65
|
+
import { loadProject } from "@statewalker/cellb/node";
|
|
66
|
+
const project = await loadProject("./counter", { data: "./data" });
|
|
67
|
+
|
|
68
|
+
// Browser, in a Dedicated Worker: the URL of a folder written by `cellb build`
|
|
69
|
+
import { loadProject } from "@statewalker/cellb/browser";
|
|
70
|
+
const project = await loadProject("/apps/counter/", { data: "counter" });
|
|
71
|
+
|
|
72
|
+
// Both
|
|
73
|
+
const res = await project.fetch(new Request("http://localhost/increment?name=alpha"));
|
|
74
|
+
project.unsupported; // configuration cellb does not run
|
|
75
|
+
await project.close();
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
A browser loads a project built ahead of time, on Node:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
npx cellb build ./counter --out public/apps/counter
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The folder holds `wrangler.json`, `worker.js` (`main` bundled for browsers, with nodejs_compat
|
|
85
|
+
when the flags ask for it), `assets/` (the files of `assets.directory`) and `cellb.json`, the
|
|
86
|
+
manifest that lists the assets, since a static host cannot list a folder. Any static host serves
|
|
87
|
+
it; Node loads it too.
|
|
88
|
+
|
|
89
|
+
- `source`: Node takes a folder (built or not), a `file:` or `http(s):` URL of a built folder, or
|
|
90
|
+
a FilesApi holding either; a browser takes the URL of a built folder or a FilesApi holding one.
|
|
91
|
+
- `data`: where cells keep their data. On Node, a directory (SQLite files, and the project's files
|
|
92
|
+
under `<data>/files`); without it, memory. In a browser, an OPFS name: the SQLite pool `<data>`
|
|
93
|
+
and the files directory `<data>-files` (default: the project's `name`).
|
|
94
|
+
- `bucket`: a fleet bucket, as `loadNodeProject`'s `storage` (a `CellStorage`) and
|
|
95
|
+
`browserProjectRuntime`'s `bucket` (a `BrowserBucket`).
|
|
96
|
+
- `ai`: the Workers AI endpoint. `sqlite3` (browser): a SQLite WASM module, if the caller has one
|
|
97
|
+
(default: `@sqlite.org/sqlite-wasm`). `isolateScript` (browser): where Worker Loader code runs,
|
|
98
|
+
the package's own isolate worker by default, `false` for this realm.
|
|
99
|
+
|
|
100
|
+
`loadNodeProject` and `browserProjectRuntime`, below, stay as the lower-level calls.
|
|
101
|
+
|
|
59
102
|
### A Worker and a Durable Object in Node
|
|
60
103
|
|
|
61
104
|
```ts
|
package/bin/cellb.mjs
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The `cellb` command: the compiled CLI of the published package (dist/), or the TypeScript
|
|
3
|
+
// sources in the repository (Node strips their types; `.js` specifiers resolve to `.ts`).
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { register } from "node:module";
|
|
6
|
+
|
|
7
|
+
const dist = new URL("../dist/cli.js", import.meta.url);
|
|
8
|
+
let entry = dist;
|
|
9
|
+
if (!existsSync(dist)) {
|
|
10
|
+
const hook = `export async function resolve(s, c, next) {
|
|
11
|
+
try { return await next(s, c); } catch (e) {
|
|
12
|
+
if (s.startsWith(".") && s.endsWith(".js")) return next(s.slice(0, -3) + ".ts", c);
|
|
13
|
+
throw e;
|
|
14
|
+
}
|
|
15
|
+
}`;
|
|
16
|
+
register(`data:text/javascript,${encodeURIComponent(hook)}`);
|
|
17
|
+
entry = new URL("../src/cli.ts", import.meta.url);
|
|
18
|
+
}
|
|
19
|
+
const { main } = await import(entry.href);
|
|
20
|
+
process.exitCode = await main(process.argv.slice(2));
|
package/dist/browser.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { sahpoolOpener } from "./adapters/wasm-sqlite.js";
|
|
2
2
|
export { idbObjectStore } from "./bucket/idb-object-store.js";
|
|
3
3
|
export { type BrowserBucket, type BrowserProjectOptions, browserProjectRuntime, } from "./project/browser-host.js";
|
|
4
|
+
export { type BrowserLoadProjectOptions, loadProject } from "./project/browser-load.js";
|
|
4
5
|
export { type ProjectShards, serveProjectShard, startProjectShards, } from "./project/browser-shards.js";
|
|
5
6
|
export { installProjectRouter, joinProjectShards, type ProjectTabs, type ProjectTabsOptions, type ServiceWorkerScope, shardOwner, } from "./project/browser-tabs.js";
|
|
7
|
+
export type { LoadedProject, LoadProjectOptions, ProjectSource, } from "./project/built-project.js";
|
|
6
8
|
export { serviceWorkerConnector } from "./ws/sw-connector.js";
|
package/dist/browser.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { sahpoolOpener } from "./adapters/wasm-sqlite.js";
|
|
2
2
|
export { idbObjectStore } from "./bucket/idb-object-store.js";
|
|
3
3
|
export { browserProjectRuntime, } from "./project/browser-host.js";
|
|
4
|
+
export { loadProject } from "./project/browser-load.js";
|
|
4
5
|
export { serveProjectShard, startProjectShards, } from "./project/browser-shards.js";
|
|
5
6
|
export { installProjectRouter, joinProjectShards, shardOwner, } from "./project/browser-tabs.js";
|
|
6
7
|
export { serviceWorkerConnector } from "./ws/sw-connector.js";
|
package/dist/browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAGL,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAEL,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EAIjB,UAAU,GACX,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAGL,qBAAqB,GACtB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAkC,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxF,OAAO,EAEL,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EAIjB,UAAU,GACX,MAAM,2BAA2B,CAAC;AAMnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC","sourcesContent":["export { sahpoolOpener } from \"./adapters/wasm-sqlite.js\";\nexport { idbObjectStore } from \"./bucket/idb-object-store.js\";\nexport {\n type BrowserBucket,\n type BrowserProjectOptions,\n browserProjectRuntime,\n} from \"./project/browser-host.js\";\nexport { type BrowserLoadProjectOptions, loadProject } from \"./project/browser-load.js\";\nexport {\n type ProjectShards,\n serveProjectShard,\n startProjectShards,\n} from \"./project/browser-shards.js\";\nexport {\n installProjectRouter,\n joinProjectShards,\n type ProjectTabs,\n type ProjectTabsOptions,\n type ServiceWorkerScope,\n shardOwner,\n} from \"./project/browser-tabs.js\";\nexport type {\n LoadedProject,\n LoadProjectOptions,\n ProjectSource,\n} from \"./project/built-project.js\";\nexport { serviceWorkerConnector } from \"./ws/sw-connector.js\";\n"]}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* The `cellb` command.
|
|
4
|
+
*
|
|
5
|
+
* cellb build <project-dir> [--out <dir>] writes a folder `loadProject` loads in a browser
|
|
6
|
+
*/
|
|
7
|
+
import { buildProject } from "./project/build.js";
|
|
8
|
+
const USAGE = `Usage:
|
|
9
|
+
cellb build <project-dir> [--out <dir>] [--no-lower-await]
|
|
10
|
+
|
|
11
|
+
Bundles the project's \`main\` for browsers and writes wrangler.json, worker.js, assets/ and
|
|
12
|
+
cellb.json into <dir> (default: <project-dir>/dist/cellb), for loadProject() from
|
|
13
|
+
@statewalker/cellb/browser or @statewalker/cellb/node.`;
|
|
14
|
+
/** Runs the command line `args` (without node and the script); returns the exit code. */
|
|
15
|
+
export async function main(args) {
|
|
16
|
+
const [command, ...rest] = args;
|
|
17
|
+
if (!command || command === "--help" || command === "-h" || command === "help") {
|
|
18
|
+
console.log(USAGE);
|
|
19
|
+
return command ? 0 : 1;
|
|
20
|
+
}
|
|
21
|
+
if (command !== "build") {
|
|
22
|
+
console.error(`cellb: unknown command ${JSON.stringify(command)}\n\n${USAGE}`);
|
|
23
|
+
return 1;
|
|
24
|
+
}
|
|
25
|
+
let dir;
|
|
26
|
+
let out;
|
|
27
|
+
let lowerAwait;
|
|
28
|
+
for (let i = 0; i < rest.length; i++) {
|
|
29
|
+
const a = rest[i];
|
|
30
|
+
if (a === "--out" || a === "-o")
|
|
31
|
+
out = rest[++i];
|
|
32
|
+
else if (a.startsWith("--out="))
|
|
33
|
+
out = a.slice(6);
|
|
34
|
+
else if (a === "--no-lower-await")
|
|
35
|
+
lowerAwait = false;
|
|
36
|
+
else if (a.startsWith("-")) {
|
|
37
|
+
console.error(`cellb build: unknown option ${a}\n\n${USAGE}`);
|
|
38
|
+
return 1;
|
|
39
|
+
}
|
|
40
|
+
else if (dir === undefined)
|
|
41
|
+
dir = a;
|
|
42
|
+
else {
|
|
43
|
+
console.error(`cellb build: one project directory only\n\n${USAGE}`);
|
|
44
|
+
return 1;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (!dir || (out !== undefined && !out)) {
|
|
48
|
+
console.error(USAGE);
|
|
49
|
+
return 1;
|
|
50
|
+
}
|
|
51
|
+
out ??= `${dir.replace(/\/+$/, "")}/dist/cellb`;
|
|
52
|
+
try {
|
|
53
|
+
const manifest = await buildProject(dir, out, { lowerAwait });
|
|
54
|
+
console.log(`cellb build: ${out} (${manifest.main ?? "no main"}, ${manifest.assets.length} asset file(s))`);
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
console.error(`cellb build: ${err.message ?? err}`);
|
|
59
|
+
return 1;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;GAIG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,KAAK,GAAG;;;;;2DAK6C,CAAC;AAE5D,yFAAyF;AACzF,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAc;IACvC,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAChC,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QAC/E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACnB,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC;IACD,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,CAAC,0BAA0B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,KAAK,EAAE,CAAC,CAAC;QAC/E,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,GAAuB,CAAC;IAC5B,IAAI,GAAuB,CAAC;IAC5B,IAAI,UAA+B,CAAC;IACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aAC5C,IAAI,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;aAC7C,IAAI,CAAC,KAAK,kBAAkB;YAAE,UAAU,GAAG,KAAK,CAAC;aACjD,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,OAAO,KAAK,EAAE,CAAC,CAAC;YAC9D,OAAO,CAAC,CAAC;QACX,CAAC;aAAM,IAAI,GAAG,KAAK,SAAS;YAAE,GAAG,GAAG,CAAC,CAAC;aACjC,CAAC;YACJ,OAAO,CAAC,KAAK,CAAC,8CAA8C,KAAK,EAAE,CAAC,CAAC;YACrE,OAAO,CAAC,CAAC;QACX,CAAC;IACH,CAAC;IACD,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACxC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACrB,OAAO,CAAC,CAAC;IACX,CAAC;IACD,GAAG,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,aAAa,CAAC;IAChD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;QAC9D,OAAO,CAAC,GAAG,CACT,gBAAgB,GAAG,KAAK,QAAQ,CAAC,IAAI,IAAI,SAAS,KAAK,QAAQ,CAAC,MAAM,CAAC,MAAM,iBAAiB,CAC/F,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,gBAAiB,GAAa,CAAC,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC;QAC/D,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC","sourcesContent":["#!/usr/bin/env node\n/**\n * The `cellb` command.\n *\n * cellb build <project-dir> [--out <dir>] writes a folder `loadProject` loads in a browser\n */\nimport { buildProject } from \"./project/build.js\";\n\nconst USAGE = `Usage:\n cellb build <project-dir> [--out <dir>] [--no-lower-await]\n\n Bundles the project's \\`main\\` for browsers and writes wrangler.json, worker.js, assets/ and\n cellb.json into <dir> (default: <project-dir>/dist/cellb), for loadProject() from\n @statewalker/cellb/browser or @statewalker/cellb/node.`;\n\n/** Runs the command line `args` (without node and the script); returns the exit code. */\nexport async function main(args: string[]): Promise<number> {\n const [command, ...rest] = args;\n if (!command || command === \"--help\" || command === \"-h\" || command === \"help\") {\n console.log(USAGE);\n return command ? 0 : 1;\n }\n if (command !== \"build\") {\n console.error(`cellb: unknown command ${JSON.stringify(command)}\\n\\n${USAGE}`);\n return 1;\n }\n let dir: string | undefined;\n let out: string | undefined;\n let lowerAwait: boolean | undefined;\n for (let i = 0; i < rest.length; i++) {\n const a = rest[i];\n if (a === \"--out\" || a === \"-o\") out = rest[++i];\n else if (a.startsWith(\"--out=\")) out = a.slice(6);\n else if (a === \"--no-lower-await\") lowerAwait = false;\n else if (a.startsWith(\"-\")) {\n console.error(`cellb build: unknown option ${a}\\n\\n${USAGE}`);\n return 1;\n } else if (dir === undefined) dir = a;\n else {\n console.error(`cellb build: one project directory only\\n\\n${USAGE}`);\n return 1;\n }\n }\n if (!dir || (out !== undefined && !out)) {\n console.error(USAGE);\n return 1;\n }\n out ??= `${dir.replace(/\\/+$/, \"\")}/dist/cellb`;\n try {\n const manifest = await buildProject(dir, out, { lowerAwait });\n console.log(\n `cellb build: ${out} (${manifest.main ?? \"no main\"}, ${manifest.assets.length} asset file(s))`,\n );\n return 0;\n } catch (err) {\n console.error(`cellb build: ${(err as Error).message ?? err}`);\n return 1;\n }\n}\n"]}
|
|
@@ -7,7 +7,8 @@ import type { CellStorage } from "../ports.js";
|
|
|
7
7
|
* travel to the isolate and become Blob-URL modules there.
|
|
8
8
|
*/
|
|
9
9
|
export declare function browserIsolatedLoader(opts: {
|
|
10
|
-
|
|
10
|
+
/** The isolate's script, or a function that starts a Dedicated Worker running it. */
|
|
11
|
+
isolateScript: URL | (() => Worker);
|
|
11
12
|
siteBaseUrl?: string;
|
|
12
13
|
/** Prefix of the OPFS SQLite pool each isolate keeps its facets in (one pool per loaded id). */
|
|
13
14
|
storagePrefix?: string;
|
package/dist/isolate/browser.js
CHANGED
|
@@ -11,7 +11,8 @@ export function browserIsolatedLoader(opts) {
|
|
|
11
11
|
return isolatedModuleLoader({
|
|
12
12
|
storage: opts.storage,
|
|
13
13
|
spawn: () => {
|
|
14
|
-
const
|
|
14
|
+
const script = opts.isolateScript;
|
|
15
|
+
const w = typeof script === "function" ? script() : new Worker(script, { type: "module" });
|
|
15
16
|
return { port: w, terminate: () => w.terminate() };
|
|
16
17
|
},
|
|
17
18
|
prepare: async (id, code) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/isolate/browser.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAGjD;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/isolate/browser.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAGjD;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAQrC;IACC,MAAM,WAAW,GAAG,CAAC,EAAU,EAAE,EAAE,CACjC,GAAG,IAAI,CAAC,aAAa,IAAI,SAAS,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACtE,OAAO,oBAAoB,CAAC;QAC1B,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,KAAK,EAAE,GAAG,EAAE;YACV,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC;YAClC,MAAM,CAAC,GAAG,OAAO,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC3F,OAAO,EAAE,IAAI,EAAE,CAAwB,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC;QAC5E,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,EAAU,EAAE,IAAgB,EAAE,EAAE;YAC9C,IAAI,CAAC,IAAI,CAAC,WAAW;gBACnB,OAAO;oBACL,OAAO,EAAE,IAAI,CAAC,OAAO;oBACrB,UAAU,EAAE,IAAI,CAAC,UAAU;oBAC3B,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC;iBACpB,CAAC;YACb,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,GAAG,CAAC;YACxF,MAAM,GAAG,GAAG,kBAAkB,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAChD,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBACrD,MAAM,eAAe,CAAC,GAAG,IAAI,cAAc,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;YAC/D,CAAC;YACD,OAAO;gBACL,GAAG,EAAE,GAAG,IAAI,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE;gBAChD,SAAS,EAAE,WAAW,EAAE,EAAE;gBAC1B,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC;aACpB,CAAC;QACb,CAAC;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { ModuleLoader, WorkerCode } from \"../bindings/worker-loader.js\";\nimport type { CellStorage } from \"../ports.js\";\nimport { putLoadedModule } from \"../project/site-loader.js\";\nimport { isolatedModuleLoader } from \"./host.js\";\nimport type { PortLike } from \"./protocol.js\";\n\n/**\n * Isolated loading in browsers: each loaded Worker runs in its own Dedicated Worker\n * (`isolateScript`, e.g. src/isolate/isolate-worker.ts). With `siteBaseUrl` (the in-browser\n * HTTP server, docs/browser-host.md) its modules are uploaded and imported from URLs; otherwise they\n * travel to the isolate and become Blob-URL modules there.\n */\nexport function browserIsolatedLoader(opts: {\n /** The isolate's script, or a function that starts a Dedicated Worker running it. */\n isolateScript: URL | (() => Worker);\n siteBaseUrl?: string;\n /** Prefix of the OPFS SQLite pool each isolate keeps its facets in (one pool per loaded id). */\n storagePrefix?: string;\n /** The host's storage: facets of loaded code are logged and restored through it. */\n storage?: () => CellStorage | undefined;\n}): ModuleLoader {\n const storageName = (id: string) =>\n `${opts.storagePrefix ?? \"isolate\"}-${id}`.replace(/[^\\w.-]/g, \"_\");\n return isolatedModuleLoader({\n storage: opts.storage,\n spawn: () => {\n const script = opts.isolateScript;\n const w = typeof script === \"function\" ? script() : new Worker(script, { type: \"module\" });\n return { port: w as unknown as PortLike, terminate: () => w.terminate() };\n },\n prepare: async (id: string, code: WorkerCode) => {\n if (!opts.siteBaseUrl)\n return {\n modules: code.modules,\n mainModule: code.mainModule,\n storageName: storageName(id),\n } as never;\n const base = opts.siteBaseUrl.endsWith(\"/\") ? opts.siteBaseUrl : `${opts.siteBaseUrl}/`;\n const dir = encodeURIComponent(`isolate-${id}`);\n for (const [name, m] of Object.entries(code.modules)) {\n await putLoadedModule(`${base}loaded-src/${dir}/${name}`, m);\n }\n return {\n url: `${base}loaded/${dir}/~/${code.mainModule}`,\n consoleId: `isolate-${id}`,\n storageName: storageName(id),\n } as never;\n },\n });\n}\n"]}
|
package/dist/isolate/isolate.js
CHANGED
|
@@ -147,9 +147,11 @@ export function serveIsolate(port, importCode, opts = {}) {
|
|
|
147
147
|
}
|
|
148
148
|
if (m.type === "image")
|
|
149
149
|
return await images.get(m.token)?.();
|
|
150
|
-
// The host is stopping this isolate: the sockets
|
|
151
|
-
//
|
|
152
|
-
//
|
|
150
|
+
// The host is stopping this isolate: the sockets served here hear 1001 first. A 101 carries
|
|
151
|
+
// its early frames, so a socket's close normally goes straight to its client; only a client
|
|
152
|
+
// end that had sent unacknowledged frames before its hand-over keeps a relay here
|
|
153
|
+
// (takeClientEnd), and the answer waits a macrotask so that relay forwards the 1001 before
|
|
154
|
+
// the host terminates the isolate.
|
|
153
155
|
if (m.type === "goAway") {
|
|
154
156
|
CfWebSocket.goAway("the loaded Worker stopped");
|
|
155
157
|
return await new Promise((r) => setTimeout(r, 0));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isolate.js","sourceRoot":"","sources":["../../src/isolate/isolate.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The isolate side: loads the Worker code in THIS realm and serves fetch/RPC for the host.\n * `importCode` is realm specific (data: URL of a bundle on Node, a site URL in browsers).\n */\nimport { ctxExports, entrypointStub } from \"../core/handles.js\";\nimport type { DurableObjectId } from \"../core/id.js\";\nimport { runInDurableObject } from \"../core/namespace.js\";\nimport { type CellRuntime, createCellRuntime, type WorkerModule } from \"../core/runtime.js\";\nimport type { Lease, LeaseHandle, OpenCellSql } from \"../ports.js\";\nimport { realmWorkerScope } from \"../project/worker-scope.js\";\nimport { CfWebSocket } from \"../ws/server.js\";\nimport { type FetchTarget, isolatePort, type PortLike } from \"./protocol.js\";\n\nexport function serveIsolate(\n port: PortLike,\n importCode: (\n load: any,\n logs: (level: string, args: unknown[]) => void,\n ) => Promise<Record<string, unknown>>,\n opts: {\n patchConsole?: boolean;\n /**\n * Storage for Durable Object classes run INSIDE this isolate (facets of loaded code):\n * each facet is a cell of an isolate-local runtime, with its own SQLite.\n */\n openSql?: (load: any) => OpenCellSql | Promise<OpenCellSql>;\n } = {},\n) {\n let module: Record<string, unknown> = {};\n const runtimes = new Map<string, CellRuntime>();\n // Facet logging through the host: the isolate-local cell key → the facet's key in the\n // root's storage (celld: <root>/facets/<sha>) and the root's epoch.\n const facetKeys = new Map<string, { key: string; epoch?: number }>();\n const images = new Map<number, () => unknown>();\n let nextImage = 0;\n const hostLogged = (internal: string) => facetKeys.get(internal);\n const durability = {\n capturePages: true,\n async committed(cellKey: string, info: any) {\n const f = hostLogged(cellKey);\n if (!f) return;\n const token = ++nextImage;\n if (typeof info.image === \"function\") images.set(token, info.image);\n try {\n await call({\n type: \"durable\",\n op: \"committed\",\n cellKey: f.key,\n info: {\n seq: info.seq,\n pages: info.pages,\n epoch: f.epoch,\n image: typeof info.image === \"function\" ? token : info.image,\n },\n });\n } finally {\n images.delete(token);\n }\n },\n };\n const backup = {\n async load(cellKey: string) {\n const f = hostLogged(cellKey);\n return f\n ? ((await call({ type: \"durable\", op: \"load\", cellKey: f.key })) as Uint8Array | undefined)\n : undefined;\n },\n async save() {},\n };\n // The host holds the root's lease and attaches each facet with its epoch: handing that epoch\n // out as the facet's own lease makes its ObjectHost rebuild the local database from the\n // bucket when it opens, as a root does under a lease (a pool kept from an earlier ownership\n // is older than what other nodes wrote since). Without an epoch, the local file stays primary.\n const ownership: Lease = {\n async tryAcquire(cellKey) {\n const lost = new AbortController().signal; // fencing stays with the root's lease, in the host\n return {\n name: cellKey,\n epoch: hostLogged(cellKey)?.epoch,\n lost,\n release: async () => {},\n } as LeaseHandle;\n },\n };\n let loadMsg: any;\n let sql: Promise<OpenCellSql> | undefined;\n const objectRuntime = async (className: string) => {\n let rt = runtimes.get(className);\n if (!rt) {\n if (!opts.openSql)\n throw new Error(\"this isolate cannot host Durable Object classes (no storage)\");\n sql ??= Promise.resolve(opts.openSql(loadMsg));\n const openSql = await sql;\n if (runtimes.has(className)) return runtimes.get(className)!;\n if (typeof module[className] !== \"function\")\n throw new Error(`Loaded worker does not export class \"${className}\"`);\n rt = createCellRuntime({\n worker: { ...(module as WorkerModule), default: {} },\n durableObjects: { [className]: { className } },\n openSql,\n vars: env, // the loaded Worker's env: plain values and host stubs\n storage: { durability, backup, ownership },\n facets: true, // rows move to this run's scope on open, as celld does for facets\n ctxIdOf: (key) => {\n const name = idNames.get(key);\n return name === undefined\n ? undefined\n : (rt!.env[className] as { idFromName(n: string): DurableObjectId }).idFromName(name);\n },\n });\n runtimes.set(className, rt);\n }\n return rt;\n };\n let env: Record<string, unknown> = {};\n let exports: Record<string, unknown> = {};\n // The loaded Worker is this realm's own: its `cloudflare:workers` reads `env` and `exports` here.\n const scope = realmWorkerScope();\n // The name of the `id` a facet was given by `ctx.facets.get`, by its isolate-local cell key:\n // the facet's `ctx.id` (partyserver's `this.name`). Two facets may be given the same id; each\n // keeps its own object and storage, addressed by the parent's facet cell key.\n const idNames = new Map<string, string>();\n // A facet of loaded code: the object lives here, named by the parent's facet cell key.\n const facet = async (className: string, cellKey: string) => {\n const rt = await objectRuntime(className);\n const ns = rt.env[className] as {\n getByName(n: string): any;\n idFromName(n: string): { toString(): string };\n };\n return { rt, stub: ns.getByName(cellKey), key: `${className}/${ns.idFromName(cellKey)}` };\n };\n const exported = (name: string, props?: unknown) => {\n const target = module[name];\n if (target === undefined) throw new Error(`Loaded worker does not export \"${name}\"`);\n return entrypointStub(target, env, props, exports);\n };\n const fetchTarget = async (t: FetchTarget, req: Request): Promise<Response> =>\n \"className\" in t\n ? (await facet(t.className, t.cellKey)).stub.fetch(req)\n : exported(t.name, t.props).fetch(req);\n const handle = async (m: any) => {\n if (m.type === \"load\") {\n loadMsg = m;\n env = m.env; // host bindings arrive as stubs: every call goes back to the host\n // Logs go to the host (Tail Workers, and the host prints them): through the global\n // console, or — where the realm has other code that logs — a console scoped to the\n // loaded modules (importCode receives the sink).\n const sink = (level: string, args: unknown[]) =>\n call({ type: \"log\", level, args: safe(args) }).catch(() => {});\n if (opts.patchConsole !== false)\n for (const level of [\"log\", \"info\", \"warn\", \"error\", \"debug\"] as const)\n console[level] = (...args: unknown[]) => sink(level, args);\n if (m.outbound === \"fetcher\")\n globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) =>\n outbound(new Request(input, init))) as typeof fetch;\n if (m.outbound === \"blocked\")\n globalThis.fetch = (async () => {\n throw new Error(\n \"This worker is not permitted to access the internet via global functions like fetch(). It must use capabilities (such as bindings in 'env') to talk to the outside world.\",\n );\n }) as typeof fetch;\n scope.bind({ env, exports }); // read while the module is evaluated\n module = await importCode(m, sink);\n exports = ctxExports(module, env);\n scope.bind({ env, exports });\n return Object.fromEntries(Object.entries(module).map(([k, v]) => [k, typeof v]));\n }\n if (m.type === \"image\") return await images.get(m.token)?.();\n // The host is stopping this isolate: the sockets accepted here hear 1001 first.\n // A socket whose early frames went through a relay port hears it one hop later: the\n // answer waits a macrotask, so the host does not terminate the isolate before that.\n if (m.type === \"goAway\") {\n CfWebSocket.goAway(\"the loaded Worker stopped\");\n return await new Promise((r) => setTimeout(r, 0));\n }\n if (m.type === \"object\") {\n const { rt, stub, key } = await facet(m.className, m.cellKey);\n if (m.op === \"attach\") {\n facetKeys.set(key, { key: m.cellKey, epoch: m.epoch });\n if (typeof m.idName === \"string\") idNames.set(key, m.idName);\n return;\n }\n if (m.op === \"call\") return stub[m.method](...m.args);\n if (m.op === \"restart\") return rt.restartObject(key);\n if (m.op === \"delete\") {\n await runInDurableObject(\n stub,\n (_o: unknown, ctx: { storage: { deleteAll(): Promise<void> } }) =>\n ctx.storage.deleteAll(),\n );\n return rt.restartObject(key);\n }\n throw new Error(`unknown object op ${m.op}`);\n }\n if (m.type === \"call\") return exported(m.name, m.props)[m.method](...m.args);\n throw new Error(`unknown isolate message ${m.type}`);\n };\n const { call, outbound } = isolatePort(port, handle, fetchTarget);\n}\n\nconst safe = (args: unknown[]) =>\n args.map((a) => {\n try {\n return structuredClone(a);\n } catch {\n return String(a);\n }\n });\n"]}
|
|
1
|
+
{"version":3,"file":"isolate.js","sourceRoot":"","sources":["../../src/isolate/isolate.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The isolate side: loads the Worker code in THIS realm and serves fetch/RPC for the host.\n * `importCode` is realm specific (data: URL of a bundle on Node, a site URL in browsers).\n */\nimport { ctxExports, entrypointStub } from \"../core/handles.js\";\nimport type { DurableObjectId } from \"../core/id.js\";\nimport { runInDurableObject } from \"../core/namespace.js\";\nimport { type CellRuntime, createCellRuntime, type WorkerModule } from \"../core/runtime.js\";\nimport type { Lease, LeaseHandle, OpenCellSql } from \"../ports.js\";\nimport { realmWorkerScope } from \"../project/worker-scope.js\";\nimport { CfWebSocket } from \"../ws/server.js\";\nimport { type FetchTarget, isolatePort, type PortLike } from \"./protocol.js\";\n\nexport function serveIsolate(\n port: PortLike,\n importCode: (\n load: any,\n logs: (level: string, args: unknown[]) => void,\n ) => Promise<Record<string, unknown>>,\n opts: {\n patchConsole?: boolean;\n /**\n * Storage for Durable Object classes run INSIDE this isolate (facets of loaded code):\n * each facet is a cell of an isolate-local runtime, with its own SQLite.\n */\n openSql?: (load: any) => OpenCellSql | Promise<OpenCellSql>;\n } = {},\n) {\n let module: Record<string, unknown> = {};\n const runtimes = new Map<string, CellRuntime>();\n // Facet logging through the host: the isolate-local cell key → the facet's key in the\n // root's storage (celld: <root>/facets/<sha>) and the root's epoch.\n const facetKeys = new Map<string, { key: string; epoch?: number }>();\n const images = new Map<number, () => unknown>();\n let nextImage = 0;\n const hostLogged = (internal: string) => facetKeys.get(internal);\n const durability = {\n capturePages: true,\n async committed(cellKey: string, info: any) {\n const f = hostLogged(cellKey);\n if (!f) return;\n const token = ++nextImage;\n if (typeof info.image === \"function\") images.set(token, info.image);\n try {\n await call({\n type: \"durable\",\n op: \"committed\",\n cellKey: f.key,\n info: {\n seq: info.seq,\n pages: info.pages,\n epoch: f.epoch,\n image: typeof info.image === \"function\" ? token : info.image,\n },\n });\n } finally {\n images.delete(token);\n }\n },\n };\n const backup = {\n async load(cellKey: string) {\n const f = hostLogged(cellKey);\n return f\n ? ((await call({ type: \"durable\", op: \"load\", cellKey: f.key })) as Uint8Array | undefined)\n : undefined;\n },\n async save() {},\n };\n // The host holds the root's lease and attaches each facet with its epoch: handing that epoch\n // out as the facet's own lease makes its ObjectHost rebuild the local database from the\n // bucket when it opens, as a root does under a lease (a pool kept from an earlier ownership\n // is older than what other nodes wrote since). Without an epoch, the local file stays primary.\n const ownership: Lease = {\n async tryAcquire(cellKey) {\n const lost = new AbortController().signal; // fencing stays with the root's lease, in the host\n return {\n name: cellKey,\n epoch: hostLogged(cellKey)?.epoch,\n lost,\n release: async () => {},\n } as LeaseHandle;\n },\n };\n let loadMsg: any;\n let sql: Promise<OpenCellSql> | undefined;\n const objectRuntime = async (className: string) => {\n let rt = runtimes.get(className);\n if (!rt) {\n if (!opts.openSql)\n throw new Error(\"this isolate cannot host Durable Object classes (no storage)\");\n sql ??= Promise.resolve(opts.openSql(loadMsg));\n const openSql = await sql;\n if (runtimes.has(className)) return runtimes.get(className)!;\n if (typeof module[className] !== \"function\")\n throw new Error(`Loaded worker does not export class \"${className}\"`);\n rt = createCellRuntime({\n worker: { ...(module as WorkerModule), default: {} },\n durableObjects: { [className]: { className } },\n openSql,\n vars: env, // the loaded Worker's env: plain values and host stubs\n storage: { durability, backup, ownership },\n facets: true, // rows move to this run's scope on open, as celld does for facets\n ctxIdOf: (key) => {\n const name = idNames.get(key);\n return name === undefined\n ? undefined\n : (rt!.env[className] as { idFromName(n: string): DurableObjectId }).idFromName(name);\n },\n });\n runtimes.set(className, rt);\n }\n return rt;\n };\n let env: Record<string, unknown> = {};\n let exports: Record<string, unknown> = {};\n // The loaded Worker is this realm's own: its `cloudflare:workers` reads `env` and `exports` here.\n const scope = realmWorkerScope();\n // The name of the `id` a facet was given by `ctx.facets.get`, by its isolate-local cell key:\n // the facet's `ctx.id` (partyserver's `this.name`). Two facets may be given the same id; each\n // keeps its own object and storage, addressed by the parent's facet cell key.\n const idNames = new Map<string, string>();\n // A facet of loaded code: the object lives here, named by the parent's facet cell key.\n const facet = async (className: string, cellKey: string) => {\n const rt = await objectRuntime(className);\n const ns = rt.env[className] as {\n getByName(n: string): any;\n idFromName(n: string): { toString(): string };\n };\n return { rt, stub: ns.getByName(cellKey), key: `${className}/${ns.idFromName(cellKey)}` };\n };\n const exported = (name: string, props?: unknown) => {\n const target = module[name];\n if (target === undefined) throw new Error(`Loaded worker does not export \"${name}\"`);\n return entrypointStub(target, env, props, exports);\n };\n const fetchTarget = async (t: FetchTarget, req: Request): Promise<Response> =>\n \"className\" in t\n ? (await facet(t.className, t.cellKey)).stub.fetch(req)\n : exported(t.name, t.props).fetch(req);\n const handle = async (m: any) => {\n if (m.type === \"load\") {\n loadMsg = m;\n env = m.env; // host bindings arrive as stubs: every call goes back to the host\n // Logs go to the host (Tail Workers, and the host prints them): through the global\n // console, or — where the realm has other code that logs — a console scoped to the\n // loaded modules (importCode receives the sink).\n const sink = (level: string, args: unknown[]) =>\n call({ type: \"log\", level, args: safe(args) }).catch(() => {});\n if (opts.patchConsole !== false)\n for (const level of [\"log\", \"info\", \"warn\", \"error\", \"debug\"] as const)\n console[level] = (...args: unknown[]) => sink(level, args);\n if (m.outbound === \"fetcher\")\n globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) =>\n outbound(new Request(input, init))) as typeof fetch;\n if (m.outbound === \"blocked\")\n globalThis.fetch = (async () => {\n throw new Error(\n \"This worker is not permitted to access the internet via global functions like fetch(). It must use capabilities (such as bindings in 'env') to talk to the outside world.\",\n );\n }) as typeof fetch;\n scope.bind({ env, exports }); // read while the module is evaluated\n module = await importCode(m, sink);\n exports = ctxExports(module, env);\n scope.bind({ env, exports });\n return Object.fromEntries(Object.entries(module).map(([k, v]) => [k, typeof v]));\n }\n if (m.type === \"image\") return await images.get(m.token)?.();\n // The host is stopping this isolate: the sockets served here hear 1001 first. A 101 carries\n // its early frames, so a socket's close normally goes straight to its client; only a client\n // end that had sent unacknowledged frames before its hand-over keeps a relay here\n // (takeClientEnd), and the answer waits a macrotask so that relay forwards the 1001 before\n // the host terminates the isolate.\n if (m.type === \"goAway\") {\n CfWebSocket.goAway(\"the loaded Worker stopped\");\n return await new Promise((r) => setTimeout(r, 0));\n }\n if (m.type === \"object\") {\n const { rt, stub, key } = await facet(m.className, m.cellKey);\n if (m.op === \"attach\") {\n facetKeys.set(key, { key: m.cellKey, epoch: m.epoch });\n if (typeof m.idName === \"string\") idNames.set(key, m.idName);\n return;\n }\n if (m.op === \"call\") return stub[m.method](...m.args);\n if (m.op === \"restart\") return rt.restartObject(key);\n if (m.op === \"delete\") {\n await runInDurableObject(\n stub,\n (_o: unknown, ctx: { storage: { deleteAll(): Promise<void> } }) =>\n ctx.storage.deleteAll(),\n );\n return rt.restartObject(key);\n }\n throw new Error(`unknown object op ${m.op}`);\n }\n if (m.type === \"call\") return exported(m.name, m.props)[m.method](...m.args);\n throw new Error(`unknown isolate message ${m.type}`);\n };\n const { call, outbound } = isolatePort(port, handle, fetchTarget);\n}\n\nconst safe = (args: unknown[]) =>\n args.map((a) => {\n try {\n return structuredClone(a);\n } catch {\n return String(a);\n }\n });\n"]}
|
|
@@ -23,8 +23,10 @@
|
|
|
23
23
|
* A WebSocket upgrade (host → isolate) has a port of its own instead, since HTTP/1.1 drops the
|
|
24
24
|
* `Upgrade` header: its meta carries the request's method and headers; the isolate answers with
|
|
25
25
|
* the response's head and closes the port. A 101's head carries the socket's own MessagePort,
|
|
26
|
-
* transferred
|
|
27
|
-
*
|
|
26
|
+
* transferred, and the frames the server sent before the 101 (replayed by the host's end): the
|
|
27
|
+
* socket's frames then go straight between the client and the isolate, outside the multiplexer
|
|
28
|
+
* and through no relay in the isolate, so open sockets hold none of its ports (it allows
|
|
29
|
+
* `maxPorts` at once) and a socket's 1001 reaches its client before the isolate ends.
|
|
28
30
|
*/
|
|
29
31
|
export interface PortLike {
|
|
30
32
|
postMessage(msg: unknown, transfer?: Transferable[]): void;
|
package/dist/isolate/protocol.js
CHANGED
|
@@ -2,7 +2,7 @@ import { fetchOverDuplex, serveFetchOverDuplex } from "@statewalker/webrun-http-
|
|
|
2
2
|
import { callPort, duplexOverPort, getPortCloseSignal, listenPort, multiplexPort, NO_TIMEOUT, serveDuplexOverPort, structuredCodec, } from "@statewalker/webrun-rpc";
|
|
3
3
|
import { cross, pipeTo, rpcPromise, STUB } from "../core/handles.js";
|
|
4
4
|
import { withUrl } from "../core/request-body.js";
|
|
5
|
-
import { CellsResponse, CfWebSocket,
|
|
5
|
+
import { CellsResponse, CfWebSocket, takeClientEnd } from "../ws/server.js";
|
|
6
6
|
import { carryWebSocketHeaders } from "../ws/upgrade.js";
|
|
7
7
|
/**
|
|
8
8
|
* The host's end of an isolate's port: one webrun-rpc multiplexer over it, a calls port on
|
|
@@ -112,7 +112,7 @@ async function upgradeOver(mux, meta, req) {
|
|
|
112
112
|
return resolve(new CellsResponse(null, {
|
|
113
113
|
status: 101,
|
|
114
114
|
headers: head.headers,
|
|
115
|
-
webSocket: new CfWebSocket(head.socket),
|
|
115
|
+
webSocket: new CfWebSocket(head.socket, head.frames),
|
|
116
116
|
}));
|
|
117
117
|
resolve(new Response(nullBody(head.status) ? null : head.body, {
|
|
118
118
|
status: head.status,
|
|
@@ -156,8 +156,8 @@ function serveUpgrade(p, meta, fetch) {
|
|
|
156
156
|
const res = await fetch(req);
|
|
157
157
|
const ws = res.webSocket;
|
|
158
158
|
if (res.status === 101 && ws) {
|
|
159
|
-
const socket =
|
|
160
|
-
answer({ status: 101, headers: [...res.headers], body: null, socket }, [socket]);
|
|
159
|
+
const { port: socket, frames } = takeClientEnd(ws);
|
|
160
|
+
answer({ status: 101, headers: [...res.headers], body: null, socket, frames }, [socket]);
|
|
161
161
|
}
|
|
162
162
|
else
|
|
163
163
|
answer({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/isolate/protocol.ts"],"names":[],"mappings":"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","sourcesContent":["import { fetchOverDuplex, serveFetchOverDuplex } from \"@statewalker/webrun-http-streams\";\nimport {\n callPort,\n duplexOverPort,\n getPortCloseSignal,\n listenPort,\n type MessageTarget,\n multiplexPort,\n NO_TIMEOUT,\n type PortMux,\n serveDuplexOverPort,\n structuredCodec,\n} from \"@statewalker/webrun-rpc\";\nimport { cross, pipeTo, rpcPromise, STUB } from \"../core/handles.js\";\nimport { withUrl } from \"../core/request-body.js\";\nimport { CellsResponse, CfWebSocket, takeClientPort } from \"../ws/server.js\";\nimport { carryWebSocketHeaders } from \"../ws/upgrade.js\";\n\n/**\n * Isolation for loaded Workers (celld runs each in its own V8 isolate): the loaded code runs\n * in a separate realm — a worker thread on Node, a Dedicated Worker in browsers — and talks\n * to the host over one MessagePort, multiplexed with `@statewalker/webrun-rpc`. The host keeps\n * everything else: bindings in the loaded Worker's env are reached through stubs, and its logs\n * come back for Tail Workers. Errors cross with their own properties (`name`, `code`, …).\n * Functions, `RpcTarget`s and stubs anywhere in a call or result cross by reference (as\n * workerd passes them): the far side gets a stub whose calls come back.\n *\n * Calls (one port, both directions; each names an `answer`, which the serving side keeps until\n * the caller has the result, so calls on it can be sent before then — promise pipelining):\n * host → isolate load {source|url, env, outbound} → loaded {exports}\n * call {name, method, args, props} → result\n * isolate → host log {level, args}\n * either way ref {id|on, path, args} (a call on a stub of the other side's value, or\n * on answer `on`: `path` is the property path\n * called, [] the value itself)\n * release {id|answer} (that stub was disposed or collected; the caller\n * has that answer)\n * Fetches: one port per request (meta: its target and URL), HTTP/1.1 with streamed bodies,\n * as cells-http over a port (src/transport/port.ts): host → isolate to an export or facet,\n * isolate → host for the loaded code's global `fetch()` when a `globalOutbound` Fetcher routes it.\n * A WebSocket upgrade (host → isolate) has a port of its own instead, since HTTP/1.1 drops the\n * `Upgrade` header: its meta carries the request's method and headers; the isolate answers with\n * the response's head and closes the port. A 101's head carries the socket's own MessagePort,\n * transferred: the socket's frames then go straight between the client and the isolate, outside\n * the multiplexer, so open sockets hold none of its ports (it allows `maxPorts` at once).\n */\nexport interface PortLike {\n postMessage(msg: unknown, transfer?: Transferable[]): void;\n addEventListener?(type: \"message\", fn: (e: { data: unknown }) => void): void;\n removeEventListener?(type: \"message\", fn: (e: { data: unknown }) => void): void;\n on?(type: \"message\", fn: (data: unknown) => void): void;\n off?(type: \"message\", fn: (data: unknown) => void): void;\n start?(): void;\n}\n\n/** Where a fetch goes in the isolate: an export of the loaded Worker, or one of its facets. */\nexport type FetchTarget =\n | { name: string; props?: unknown }\n | { className: string; cellKey: string };\ntype Fetch = (target: FetchTarget, req: Request) => Promise<Response>;\n\nexport type Call = <T = unknown>(msg: object) => Promise<T>;\ntype Handle = (msg: any) => Promise<unknown>;\n\n/**\n * The host's end of an isolate's port: one webrun-rpc multiplexer over it, a calls port on\n * which each side calls the other (`callPort`/`listenPort`, no timeout: a call lasts as long\n * as the work it starts), and a port per fetch. `outbound` serves the loaded code's global\n * `fetch()` (its `globalOutbound` Fetcher).\n */\nexport async function hostPort(\n port: PortLike,\n handle: Handle,\n outbound?: (req: Request) => Promise<Response>,\n): Promise<{ call: Call; fetch: Fetch }> {\n const mux = multiplexPort(messageTarget(port), {\n codec: structuredCodec,\n side: \"initiator\",\n maxPorts: maxPorts(),\n onPort(p, meta) {\n const m = meta as { kind?: string; url: string } | undefined;\n if (m?.kind !== \"outbound\" || !outbound) return false;\n serveFetch(p, m.url, outbound);\n return true;\n },\n });\n const call = callsOver(await mux.openPort({ kind: \"calls\" }), handle);\n const fetch: Fetch = (target, req) =>\n isUpgrade(req)\n ? upgradeOver(mux, { kind: \"upgrade\", target }, req)\n : fetchOver(mux, { kind: \"fetch\", target }, req);\n return { call, fetch };\n}\n\n/**\n * The isolate's end: accepts the ports the host opens. Everything the isolate calls the host\n * for happens while serving a host call, so the calls port is open by then. `outbound` sends\n * a fetch to the host's `globalOutbound`.\n */\nexport function isolatePort(\n port: PortLike,\n handle: Handle,\n fetch: Fetch,\n): { call: Call; outbound: (req: Request) => Promise<Response> } {\n let calls: Call | undefined;\n const mux = multiplexPort(messageTarget(port), {\n codec: structuredCodec,\n side: \"responder\",\n maxPorts: maxPorts(),\n onPort(p, meta) {\n const m = meta as { kind?: string; target: FetchTarget; url: string } | undefined;\n if (m?.kind === \"fetch\") {\n serveFetch(p, m.url, (r) => fetch(m.target, r));\n return true;\n }\n if (m?.kind === \"upgrade\") {\n serveUpgrade(p, m as unknown as UpgradeMeta, (r) => fetch(m.target, r));\n return true;\n }\n if (m?.kind !== \"calls\" || calls) return false;\n calls = callsOver(p, handle);\n return true;\n },\n });\n return {\n call: (msg) => calls!(msg),\n outbound: (req) => fetchOver(mux, { kind: \"outbound\" }, req),\n };\n}\n\n/** A fetch over a new port of `mux`; the URL rides in the meta (the HTTP/1.1 wire drops its scheme). */\nfunction fetchOver(mux: PortMux, meta: object, req: Request): Promise<Response> {\n return fetchOverDuplex(\n (input) =>\n (async function* () {\n yield* duplexOverPort(await mux.openPort({ ...meta, url: req.url }))(input);\n })(),\n req,\n );\n}\n\n/** Serves the fetch on port `p` (its URL from the meta) with `fetch`. */\nfunction serveFetch(p: MessageTarget, url: string, fetch: (req: Request) => Promise<Response>) {\n serveDuplexOverPort(\n p,\n serveFetchOverDuplex((req) => withUrl(req, url).then(fetch).catch(throwOwn)),\n );\n}\n\nconst isUpgrade = (req: Request) => req.headers.get(\"upgrade\")?.toLowerCase() === \"websocket\";\n\ninterface UpgradeMeta {\n url: string;\n method: string;\n headers: [string, string][];\n}\n/**\n * Ports of an isolate's multiplexer open at once: the calls port, and one per fetch or upgrade\n * in flight (each closes when its exchange ends). `globalThis.__cellbMaxPorts` overrides it, as\n * for src/transport/port.ts.\n */\nconst maxPorts = () => (globalThis as { __cellbMaxPorts?: number }).__cellbMaxPorts ?? 4096;\n\n/** The isolate's answer to an upgrade: the head of its response, or the error it threw. */\ntype UpgradeHead =\n | {\n status: number;\n statusText?: string;\n headers: [string, string][];\n body: ArrayBuffer | null;\n /** A 101's socket: the port of its client end, transferred. */\n socket?: MessagePort;\n }\n | { error: unknown };\n\n/** Statuses whose response has no body (`new Response(body, …)` refuses one). */\nconst nullBody = (status: number) => [101, 204, 205, 304].includes(status);\n\n/**\n * A WebSocket upgrade over a port of its own, closed once the isolate's answer is in. A 101\n * becomes a Workers response whose `webSocket` is a client end over the socket's own port.\n */\nasync function upgradeOver(mux: PortMux, meta: object, req: Request): Promise<Response> {\n const p = await mux.openPort({\n ...meta,\n url: req.url,\n method: req.method,\n headers: [...req.headers],\n } satisfies UpgradeMeta);\n return new Promise((resolve, reject) => {\n // A port closed without an answer (the isolate refused it, or could not post one)\n // fails the upgrade rather than leaving it pending.\n const closed = getPortCloseSignal(p);\n const onClosed = () => {\n p.removeEventListener(\"message\", onHead);\n reject(\n closed?.reason ?? new Error(\"cellb: the isolate closed the upgrade without an answer\"),\n );\n };\n closed?.addEventListener(\"abort\", onClosed, { once: true });\n const onHead = (e: MessageEvent) => {\n p.removeEventListener(\"message\", onHead);\n closed?.removeEventListener(\"abort\", onClosed);\n void p.close?.();\n try {\n const head = e.data as UpgradeHead;\n if (\"error\" in head) throw head.error;\n if (head.status === 101 && head.socket)\n return resolve(\n new CellsResponse(null, {\n status: 101,\n headers: head.headers,\n webSocket: new CfWebSocket(head.socket),\n }),\n );\n resolve(\n new Response(nullBody(head.status) ? null : head.body, {\n status: head.status,\n statusText: head.statusText,\n headers: head.headers,\n }),\n );\n } catch (err) {\n reject(err);\n }\n };\n p.addEventListener(\"message\", onHead);\n void p.start?.();\n });\n}\n\n/** Serves an upgrade on port `p`: a 101 hands over its client end's port; then `p` closes. */\nfunction serveUpgrade(\n p: MessageTarget,\n meta: UpgradeMeta,\n fetch: (req: Request) => Promise<Response>,\n) {\n // A browser drops `Upgrade` and `Sec-WebSocket-*` from `new Request()`: carried over here.\n const headers = new Headers(meta.headers);\n const req = carryWebSocketHeaders(\n headers,\n new Request(meta.url, { method: meta.method, headers }),\n );\n const answer = (head: UpgradeHead, transfer: Transferable[] = []) => {\n try {\n // The multiplexer drops a message it cannot copy, so check before posting; a 101\n // head is not checked, since its socket port is transferred rather than copied.\n if (transfer.length === 0) cloneable(head);\n p.postMessage(head, transfer);\n } catch {\n // An error that cannot be copied (a function in its `cause`, say): its name and message.\n const e = (head as { error?: { name?: unknown; message?: unknown } }).error;\n p.postMessage({\n error: Object.assign(new Error(String(e?.message ?? e)), {\n name: String(e?.name ?? \"Error\"),\n }),\n } satisfies UpgradeHead);\n }\n };\n void (async () => {\n try {\n const res = await fetch(req);\n const ws = (res as { webSocket?: CfWebSocket | null }).webSocket;\n if (res.status === 101 && ws) {\n const socket = takeClientPort(ws);\n answer({ status: 101, headers: [...res.headers], body: null, socket }, [socket]);\n } else\n answer({\n status: res.status,\n statusText: res.statusText,\n headers: [...res.headers],\n body: nullBody(res.status) ? null : await res.arrayBuffer(),\n });\n } catch (error) {\n answer({ error });\n }\n void p.close?.();\n })();\n}\n\n/** Marks a value passed by reference in a message: `{ [REF]: id }`. */\nconst REF = \"\\u0000cellb.ref\";\n\n/**\n * The calls of one port, with values passed by reference: each side keeps the values it\n * passed (by id, and how many ids hold each); the other side calls them through stubs. A\n * stub's `Symbol.dispose` (or its garbage collection) releases its id; the last release of a\n * value runs the value's own `Symbol.dispose`, as workerd does for an `RpcTarget`. A call\n * returns an RpcPromise: calls on it go to the other side at once, naming its answer.\n */\nfunction callsOver(port: MessageTarget, handle: Handle): Call {\n const values = new Map<number, any>();\n const answers = new Map<number, unknown>();\n let lastAnswer = 0;\n const holders = new Map<unknown, number>();\n let lastId = 0;\n const encode = (v: unknown) =>\n cloneable(\n cross(\n v,\n (x) => {\n values.set(++lastId, x);\n holders.set(x, (holders.get(x) ?? 0) + 1);\n return { [REF]: lastId };\n },\n (x) => x, // the port copies the rest\n ),\n );\n const release = (id: number) => {\n const v = values.get(id);\n if (!values.delete(id)) return;\n const n = (holders.get(v) ?? 1) - 1;\n if (n) holders.set(v, n);\n else {\n holders.delete(v);\n v[Symbol.dispose]?.();\n }\n };\n const send = (msg: object) => callPort(port, msg, { timeout: NO_TIMEOUT }).catch(() => {});\n const collected = new FinalizationRegistry<number>((id) => send({ type: \"release\", id }));\n const stubOf = (id: number) => {\n const invoke = (path: string[], args: unknown[]) => call({ type: \"ref\", id, path, args });\n const stub: any = new Proxy(() => {}, {\n apply: (_t, _this, args) => invoke([], args),\n get(_t, prop) {\n if (prop === STUB) return true;\n if (prop === Symbol.dispose)\n return () => {\n collected.unregister(stub);\n send({ type: \"release\", id });\n };\n if (prop === \"then\" || typeof prop === \"symbol\") return undefined;\n return (...args: unknown[]) => invoke([prop], args);\n },\n });\n collected.register(stub, id, stub);\n return stub;\n };\n // Messages arrive as fresh copies: stubs replace the markers in place.\n const decode = (v: any): any => {\n if (Array.isArray(v)) for (let i = 0; i < v.length; i++) v[i] = decode(v[i]);\n else if (v && Object.getPrototypeOf(v) === Object.prototype) {\n if (typeof v[REF] === \"number\") return stubOf(v[REF]);\n for (const k of Object.keys(v)) v[k] = decode(v[k]);\n }\n return v;\n };\n const run = (m: any): unknown => {\n if (m.type !== \"ref\") return handle(m);\n if (m.on !== undefined) return pipeTo(answers.get(m.on), m.path, m.args);\n const v = values.get(m.id);\n if (v === undefined) throw new Error(\"A stub was used after it was disposed.\");\n return pipeTo(v, m.path, m.args);\n };\n // The answer is kept as the message arrives: a pipelined call on it may arrive before it\n // settles.\n const serve = async (m: any) => {\n if (m.type === \"release\") {\n if (m.answer === undefined) release(m.id);\n else answers.delete(m.answer);\n return;\n }\n let r: unknown;\n try {\n r = run(m);\n } catch (e) {\n r = Promise.reject(e);\n }\n answers.set(m.answer, r);\n return r;\n };\n listenPort(port, (msg) => serve(decode(msg)).then(encode).catch(throwOwn));\n const call: Call = (msg) => {\n const answer = ++lastAnswer;\n const result = (async () =>\n decode(await callPort(port, encode({ ...msg, answer }), { timeout: NO_TIMEOUT })))();\n // Calls on the answer sent before now are ahead of this release on the port.\n const done = () => send({ type: \"release\", answer });\n result.then(done, done);\n return rpcPromise(result, (path, args) => call({ type: \"ref\", on: answer, path, args }));\n };\n return call;\n}\n\n/** Errors cross with their own properties (so `code` does); `name` is inherited, so copy it. */\nfunction throwOwn(e: unknown): never {\n if (e && typeof e === \"object\")\n Object.defineProperty(e, \"name\", { value: (e as Error).name, enumerable: true });\n throw e;\n}\n\n/**\n * Throws `DataCloneError` for a value the port cannot carry: the multiplexer drops a message\n * it fails to post, and the call would wait forever.\n */\nfunction cloneable<T>(value: T): T {\n structuredClone(value);\n return value;\n}\n\n/** A worker_threads Worker is an EventEmitter; MessagePorts and Dedicated Workers are targets. */\nfunction messageTarget(port: PortLike): MessageTarget {\n if (port.addEventListener) return port as MessageTarget;\n const on = port.on!.bind(port);\n const listeners = new Map<unknown, (data: unknown) => void>();\n return {\n postMessage: (msg, transfer) => port.postMessage(msg, transfer),\n addEventListener(_type, fn) {\n const listener = (data: unknown) => void fn({ data } as MessageEvent);\n listeners.set(fn, listener);\n on(\"message\", listener);\n },\n removeEventListener(_type, fn) {\n port.off?.(\"message\", listeners.get(fn)!);\n listeners.delete(fn);\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/isolate/protocol.ts"],"names":[],"mappings":"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","sourcesContent":["import { fetchOverDuplex, serveFetchOverDuplex } from \"@statewalker/webrun-http-streams\";\nimport {\n callPort,\n duplexOverPort,\n getPortCloseSignal,\n listenPort,\n type MessageTarget,\n multiplexPort,\n NO_TIMEOUT,\n type PortMux,\n serveDuplexOverPort,\n structuredCodec,\n} from \"@statewalker/webrun-rpc\";\nimport { cross, pipeTo, rpcPromise, STUB } from \"../core/handles.js\";\nimport { withUrl } from \"../core/request-body.js\";\nimport type { Frame } from \"../ws/frames.js\";\nimport { CellsResponse, CfWebSocket, takeClientEnd } from \"../ws/server.js\";\nimport { carryWebSocketHeaders } from \"../ws/upgrade.js\";\n\n/**\n * Isolation for loaded Workers (celld runs each in its own V8 isolate): the loaded code runs\n * in a separate realm — a worker thread on Node, a Dedicated Worker in browsers — and talks\n * to the host over one MessagePort, multiplexed with `@statewalker/webrun-rpc`. The host keeps\n * everything else: bindings in the loaded Worker's env are reached through stubs, and its logs\n * come back for Tail Workers. Errors cross with their own properties (`name`, `code`, …).\n * Functions, `RpcTarget`s and stubs anywhere in a call or result cross by reference (as\n * workerd passes them): the far side gets a stub whose calls come back.\n *\n * Calls (one port, both directions; each names an `answer`, which the serving side keeps until\n * the caller has the result, so calls on it can be sent before then — promise pipelining):\n * host → isolate load {source|url, env, outbound} → loaded {exports}\n * call {name, method, args, props} → result\n * isolate → host log {level, args}\n * either way ref {id|on, path, args} (a call on a stub of the other side's value, or\n * on answer `on`: `path` is the property path\n * called, [] the value itself)\n * release {id|answer} (that stub was disposed or collected; the caller\n * has that answer)\n * Fetches: one port per request (meta: its target and URL), HTTP/1.1 with streamed bodies,\n * as cells-http over a port (src/transport/port.ts): host → isolate to an export or facet,\n * isolate → host for the loaded code's global `fetch()` when a `globalOutbound` Fetcher routes it.\n * A WebSocket upgrade (host → isolate) has a port of its own instead, since HTTP/1.1 drops the\n * `Upgrade` header: its meta carries the request's method and headers; the isolate answers with\n * the response's head and closes the port. A 101's head carries the socket's own MessagePort,\n * transferred, and the frames the server sent before the 101 (replayed by the host's end): the\n * socket's frames then go straight between the client and the isolate, outside the multiplexer\n * and through no relay in the isolate, so open sockets hold none of its ports (it allows\n * `maxPorts` at once) and a socket's 1001 reaches its client before the isolate ends.\n */\nexport interface PortLike {\n postMessage(msg: unknown, transfer?: Transferable[]): void;\n addEventListener?(type: \"message\", fn: (e: { data: unknown }) => void): void;\n removeEventListener?(type: \"message\", fn: (e: { data: unknown }) => void): void;\n on?(type: \"message\", fn: (data: unknown) => void): void;\n off?(type: \"message\", fn: (data: unknown) => void): void;\n start?(): void;\n}\n\n/** Where a fetch goes in the isolate: an export of the loaded Worker, or one of its facets. */\nexport type FetchTarget =\n | { name: string; props?: unknown }\n | { className: string; cellKey: string };\ntype Fetch = (target: FetchTarget, req: Request) => Promise<Response>;\n\nexport type Call = <T = unknown>(msg: object) => Promise<T>;\ntype Handle = (msg: any) => Promise<unknown>;\n\n/**\n * The host's end of an isolate's port: one webrun-rpc multiplexer over it, a calls port on\n * which each side calls the other (`callPort`/`listenPort`, no timeout: a call lasts as long\n * as the work it starts), and a port per fetch. `outbound` serves the loaded code's global\n * `fetch()` (its `globalOutbound` Fetcher).\n */\nexport async function hostPort(\n port: PortLike,\n handle: Handle,\n outbound?: (req: Request) => Promise<Response>,\n): Promise<{ call: Call; fetch: Fetch }> {\n const mux = multiplexPort(messageTarget(port), {\n codec: structuredCodec,\n side: \"initiator\",\n maxPorts: maxPorts(),\n onPort(p, meta) {\n const m = meta as { kind?: string; url: string } | undefined;\n if (m?.kind !== \"outbound\" || !outbound) return false;\n serveFetch(p, m.url, outbound);\n return true;\n },\n });\n const call = callsOver(await mux.openPort({ kind: \"calls\" }), handle);\n const fetch: Fetch = (target, req) =>\n isUpgrade(req)\n ? upgradeOver(mux, { kind: \"upgrade\", target }, req)\n : fetchOver(mux, { kind: \"fetch\", target }, req);\n return { call, fetch };\n}\n\n/**\n * The isolate's end: accepts the ports the host opens. Everything the isolate calls the host\n * for happens while serving a host call, so the calls port is open by then. `outbound` sends\n * a fetch to the host's `globalOutbound`.\n */\nexport function isolatePort(\n port: PortLike,\n handle: Handle,\n fetch: Fetch,\n): { call: Call; outbound: (req: Request) => Promise<Response> } {\n let calls: Call | undefined;\n const mux = multiplexPort(messageTarget(port), {\n codec: structuredCodec,\n side: \"responder\",\n maxPorts: maxPorts(),\n onPort(p, meta) {\n const m = meta as { kind?: string; target: FetchTarget; url: string } | undefined;\n if (m?.kind === \"fetch\") {\n serveFetch(p, m.url, (r) => fetch(m.target, r));\n return true;\n }\n if (m?.kind === \"upgrade\") {\n serveUpgrade(p, m as unknown as UpgradeMeta, (r) => fetch(m.target, r));\n return true;\n }\n if (m?.kind !== \"calls\" || calls) return false;\n calls = callsOver(p, handle);\n return true;\n },\n });\n return {\n call: (msg) => calls!(msg),\n outbound: (req) => fetchOver(mux, { kind: \"outbound\" }, req),\n };\n}\n\n/** A fetch over a new port of `mux`; the URL rides in the meta (the HTTP/1.1 wire drops its scheme). */\nfunction fetchOver(mux: PortMux, meta: object, req: Request): Promise<Response> {\n return fetchOverDuplex(\n (input) =>\n (async function* () {\n yield* duplexOverPort(await mux.openPort({ ...meta, url: req.url }))(input);\n })(),\n req,\n );\n}\n\n/** Serves the fetch on port `p` (its URL from the meta) with `fetch`. */\nfunction serveFetch(p: MessageTarget, url: string, fetch: (req: Request) => Promise<Response>) {\n serveDuplexOverPort(\n p,\n serveFetchOverDuplex((req) => withUrl(req, url).then(fetch).catch(throwOwn)),\n );\n}\n\nconst isUpgrade = (req: Request) => req.headers.get(\"upgrade\")?.toLowerCase() === \"websocket\";\n\ninterface UpgradeMeta {\n url: string;\n method: string;\n headers: [string, string][];\n}\n/**\n * Ports of an isolate's multiplexer open at once: the calls port, and one per fetch or upgrade\n * in flight (each closes when its exchange ends). `globalThis.__cellbMaxPorts` overrides it, as\n * for src/transport/port.ts.\n */\nconst maxPorts = () => (globalThis as { __cellbMaxPorts?: number }).__cellbMaxPorts ?? 4096;\n\n/** The isolate's answer to an upgrade: the head of its response, or the error it threw. */\ntype UpgradeHead =\n | {\n status: number;\n statusText?: string;\n headers: [string, string][];\n body: ArrayBuffer | null;\n /** A 101's socket: the port of its client end, transferred. */\n socket?: MessagePort;\n /** A 101's frames that reached its client end before the hand-over. */\n frames?: Frame[];\n }\n | { error: unknown };\n\n/** Statuses whose response has no body (`new Response(body, …)` refuses one). */\nconst nullBody = (status: number) => [101, 204, 205, 304].includes(status);\n\n/**\n * A WebSocket upgrade over a port of its own, closed once the isolate's answer is in. A 101\n * becomes a Workers response whose `webSocket` is a client end over the socket's own port.\n */\nasync function upgradeOver(mux: PortMux, meta: object, req: Request): Promise<Response> {\n const p = await mux.openPort({\n ...meta,\n url: req.url,\n method: req.method,\n headers: [...req.headers],\n } satisfies UpgradeMeta);\n return new Promise((resolve, reject) => {\n // A port closed without an answer (the isolate refused it, or could not post one)\n // fails the upgrade rather than leaving it pending.\n const closed = getPortCloseSignal(p);\n const onClosed = () => {\n p.removeEventListener(\"message\", onHead);\n reject(\n closed?.reason ?? new Error(\"cellb: the isolate closed the upgrade without an answer\"),\n );\n };\n closed?.addEventListener(\"abort\", onClosed, { once: true });\n const onHead = (e: MessageEvent) => {\n p.removeEventListener(\"message\", onHead);\n closed?.removeEventListener(\"abort\", onClosed);\n void p.close?.();\n try {\n const head = e.data as UpgradeHead;\n if (\"error\" in head) throw head.error;\n if (head.status === 101 && head.socket)\n return resolve(\n new CellsResponse(null, {\n status: 101,\n headers: head.headers,\n webSocket: new CfWebSocket(head.socket, head.frames),\n }),\n );\n resolve(\n new Response(nullBody(head.status) ? null : head.body, {\n status: head.status,\n statusText: head.statusText,\n headers: head.headers,\n }),\n );\n } catch (err) {\n reject(err);\n }\n };\n p.addEventListener(\"message\", onHead);\n void p.start?.();\n });\n}\n\n/** Serves an upgrade on port `p`: a 101 hands over its client end's port; then `p` closes. */\nfunction serveUpgrade(\n p: MessageTarget,\n meta: UpgradeMeta,\n fetch: (req: Request) => Promise<Response>,\n) {\n // A browser drops `Upgrade` and `Sec-WebSocket-*` from `new Request()`: carried over here.\n const headers = new Headers(meta.headers);\n const req = carryWebSocketHeaders(\n headers,\n new Request(meta.url, { method: meta.method, headers }),\n );\n const answer = (head: UpgradeHead, transfer: Transferable[] = []) => {\n try {\n // The multiplexer drops a message it cannot copy, so check before posting; a 101\n // head is not checked, since its socket port is transferred rather than copied.\n if (transfer.length === 0) cloneable(head);\n p.postMessage(head, transfer);\n } catch {\n // An error that cannot be copied (a function in its `cause`, say): its name and message.\n const e = (head as { error?: { name?: unknown; message?: unknown } }).error;\n p.postMessage({\n error: Object.assign(new Error(String(e?.message ?? e)), {\n name: String(e?.name ?? \"Error\"),\n }),\n } satisfies UpgradeHead);\n }\n };\n void (async () => {\n try {\n const res = await fetch(req);\n const ws = (res as { webSocket?: CfWebSocket | null }).webSocket;\n if (res.status === 101 && ws) {\n const { port: socket, frames } = takeClientEnd(ws);\n answer({ status: 101, headers: [...res.headers], body: null, socket, frames }, [socket]);\n } else\n answer({\n status: res.status,\n statusText: res.statusText,\n headers: [...res.headers],\n body: nullBody(res.status) ? null : await res.arrayBuffer(),\n });\n } catch (error) {\n answer({ error });\n }\n void p.close?.();\n })();\n}\n\n/** Marks a value passed by reference in a message: `{ [REF]: id }`. */\nconst REF = \"\\u0000cellb.ref\";\n\n/**\n * The calls of one port, with values passed by reference: each side keeps the values it\n * passed (by id, and how many ids hold each); the other side calls them through stubs. A\n * stub's `Symbol.dispose` (or its garbage collection) releases its id; the last release of a\n * value runs the value's own `Symbol.dispose`, as workerd does for an `RpcTarget`. A call\n * returns an RpcPromise: calls on it go to the other side at once, naming its answer.\n */\nfunction callsOver(port: MessageTarget, handle: Handle): Call {\n const values = new Map<number, any>();\n const answers = new Map<number, unknown>();\n let lastAnswer = 0;\n const holders = new Map<unknown, number>();\n let lastId = 0;\n const encode = (v: unknown) =>\n cloneable(\n cross(\n v,\n (x) => {\n values.set(++lastId, x);\n holders.set(x, (holders.get(x) ?? 0) + 1);\n return { [REF]: lastId };\n },\n (x) => x, // the port copies the rest\n ),\n );\n const release = (id: number) => {\n const v = values.get(id);\n if (!values.delete(id)) return;\n const n = (holders.get(v) ?? 1) - 1;\n if (n) holders.set(v, n);\n else {\n holders.delete(v);\n v[Symbol.dispose]?.();\n }\n };\n const send = (msg: object) => callPort(port, msg, { timeout: NO_TIMEOUT }).catch(() => {});\n const collected = new FinalizationRegistry<number>((id) => send({ type: \"release\", id }));\n const stubOf = (id: number) => {\n const invoke = (path: string[], args: unknown[]) => call({ type: \"ref\", id, path, args });\n const stub: any = new Proxy(() => {}, {\n apply: (_t, _this, args) => invoke([], args),\n get(_t, prop) {\n if (prop === STUB) return true;\n if (prop === Symbol.dispose)\n return () => {\n collected.unregister(stub);\n send({ type: \"release\", id });\n };\n if (prop === \"then\" || typeof prop === \"symbol\") return undefined;\n return (...args: unknown[]) => invoke([prop], args);\n },\n });\n collected.register(stub, id, stub);\n return stub;\n };\n // Messages arrive as fresh copies: stubs replace the markers in place.\n const decode = (v: any): any => {\n if (Array.isArray(v)) for (let i = 0; i < v.length; i++) v[i] = decode(v[i]);\n else if (v && Object.getPrototypeOf(v) === Object.prototype) {\n if (typeof v[REF] === \"number\") return stubOf(v[REF]);\n for (const k of Object.keys(v)) v[k] = decode(v[k]);\n }\n return v;\n };\n const run = (m: any): unknown => {\n if (m.type !== \"ref\") return handle(m);\n if (m.on !== undefined) return pipeTo(answers.get(m.on), m.path, m.args);\n const v = values.get(m.id);\n if (v === undefined) throw new Error(\"A stub was used after it was disposed.\");\n return pipeTo(v, m.path, m.args);\n };\n // The answer is kept as the message arrives: a pipelined call on it may arrive before it\n // settles.\n const serve = async (m: any) => {\n if (m.type === \"release\") {\n if (m.answer === undefined) release(m.id);\n else answers.delete(m.answer);\n return;\n }\n let r: unknown;\n try {\n r = run(m);\n } catch (e) {\n r = Promise.reject(e);\n }\n answers.set(m.answer, r);\n return r;\n };\n listenPort(port, (msg) => serve(decode(msg)).then(encode).catch(throwOwn));\n const call: Call = (msg) => {\n const answer = ++lastAnswer;\n const result = (async () =>\n decode(await callPort(port, encode({ ...msg, answer }), { timeout: NO_TIMEOUT })))();\n // Calls on the answer sent before now are ahead of this release on the port.\n const done = () => send({ type: \"release\", answer });\n result.then(done, done);\n return rpcPromise(result, (path, args) => call({ type: \"ref\", on: answer, path, args }));\n };\n return call;\n}\n\n/** Errors cross with their own properties (so `code` does); `name` is inherited, so copy it. */\nfunction throwOwn(e: unknown): never {\n if (e && typeof e === \"object\")\n Object.defineProperty(e, \"name\", { value: (e as Error).name, enumerable: true });\n throw e;\n}\n\n/**\n * Throws `DataCloneError` for a value the port cannot carry: the multiplexer drops a message\n * it fails to post, and the call would wait forever.\n */\nfunction cloneable<T>(value: T): T {\n structuredClone(value);\n return value;\n}\n\n/** A worker_threads Worker is an EventEmitter; MessagePorts and Dedicated Workers are targets. */\nfunction messageTarget(port: PortLike): MessageTarget {\n if (port.addEventListener) return port as MessageTarget;\n const on = port.on!.bind(port);\n const listeners = new Map<unknown, (data: unknown) => void>();\n return {\n postMessage: (msg, transfer) => port.postMessage(msg, transfer),\n addEventListener(_type, fn) {\n const listener = (data: unknown) => void fn({ data } as MessageEvent);\n listeners.set(fn, listener);\n on(\"message\", listener);\n },\n removeEventListener(_type, fn) {\n port.off?.(\"message\", listeners.get(fn)!);\n listeners.delete(fn);\n },\n };\n}\n"]}
|
package/dist/node.d.ts
CHANGED
|
@@ -2,4 +2,7 @@ export { nodeSqliteOpener } from "./adapters/node-sqlite.js";
|
|
|
2
2
|
export { sqliteObjectStore } from "./bucket/sqlite-object-store.js";
|
|
3
3
|
export { type CelldPeerServer, celldPeers, startCelldPeerServer } from "./peer/celld-peer.js";
|
|
4
4
|
export { bundleWorkerForBrowser } from "./project/browser-bundle.js";
|
|
5
|
+
export { type BuildProjectOptions, buildProject } from "./project/build.js";
|
|
6
|
+
export type { BuildManifest, LoadedProject, LoadProjectOptions, ProjectSource, } from "./project/built-project.js";
|
|
7
|
+
export { loadProject, type NodeLoadProjectOptions } from "./project/node-load.js";
|
|
5
8
|
export { applyNodeD1Migrations, loadNodeProject } from "./project/node-project.js";
|
package/dist/node.js
CHANGED
|
@@ -2,5 +2,7 @@ export { nodeSqliteOpener } from "./adapters/node-sqlite.js";
|
|
|
2
2
|
export { sqliteObjectStore } from "./bucket/sqlite-object-store.js";
|
|
3
3
|
export { celldPeers, startCelldPeerServer } from "./peer/celld-peer.js";
|
|
4
4
|
export { bundleWorkerForBrowser } from "./project/browser-bundle.js";
|
|
5
|
+
export { buildProject } from "./project/build.js";
|
|
6
|
+
export { loadProject } from "./project/node-load.js";
|
|
5
7
|
export { applyNodeD1Migrations, loadNodeProject } from "./project/node-project.js";
|
|
6
8
|
//# sourceMappingURL=node.js.map
|
package/dist/node.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAwB,UAAU,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC9F,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC","sourcesContent":["export { nodeSqliteOpener } from \"./adapters/node-sqlite.js\";\nexport { sqliteObjectStore } from \"./bucket/sqlite-object-store.js\";\nexport { type CelldPeerServer, celldPeers, startCelldPeerServer } from \"./peer/celld-peer.js\";\nexport { bundleWorkerForBrowser } from \"./project/browser-bundle.js\";\nexport { applyNodeD1Migrations, loadNodeProject } from \"./project/node-project.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAwB,UAAU,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC9F,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAA4B,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAO5E,OAAO,EAAE,WAAW,EAA+B,MAAM,wBAAwB,CAAC;AAClF,OAAO,EAAE,qBAAqB,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC","sourcesContent":["export { nodeSqliteOpener } from \"./adapters/node-sqlite.js\";\nexport { sqliteObjectStore } from \"./bucket/sqlite-object-store.js\";\nexport { type CelldPeerServer, celldPeers, startCelldPeerServer } from \"./peer/celld-peer.js\";\nexport { bundleWorkerForBrowser } from \"./project/browser-bundle.js\";\nexport { type BuildProjectOptions, buildProject } from \"./project/build.js\";\nexport type {\n BuildManifest,\n LoadedProject,\n LoadProjectOptions,\n ProjectSource,\n} from \"./project/built-project.js\";\nexport { loadProject, type NodeLoadProjectOptions } from \"./project/node-load.js\";\nexport { applyNodeD1Migrations, loadNodeProject } from \"./project/node-project.js\";\n"]}
|
|
@@ -2,7 +2,8 @@ import type { AssetFiles } from "../bindings/assets.js";
|
|
|
2
2
|
import type { WorkersAiOptions } from "../bindings/workers-ai.js";
|
|
3
3
|
import { type ObjectStore } from "../bucket/object-store.js";
|
|
4
4
|
import type { CellRuntimeOptions } from "../core/runtime.js";
|
|
5
|
-
import { type WranglerConfig } from "./wrangler.js";
|
|
5
|
+
import { populatesProcessEnv, processEnvOf, type WranglerConfig } from "./wrangler.js";
|
|
6
|
+
export { populatesProcessEnv, processEnvOf };
|
|
6
7
|
/**
|
|
7
8
|
* Where a browser-hosted project keeps its cells when they must outlive the page or move to
|
|
8
9
|
* other nodes: a celld fleet bucket. Cells, facets and alarms are then exactly celld's
|
|
@@ -87,9 +88,11 @@ export interface BrowserProjectOptions {
|
|
|
87
88
|
/**
|
|
88
89
|
* A Dedicated Worker script that serves one loaded Worker (`serveIsolate`): Worker Loader
|
|
89
90
|
* code then runs isolated, one Dedicated Worker per loaded Worker, as celld's isolates.
|
|
90
|
-
* The package ships one: `@statewalker/cellb/isolate-worker`.
|
|
91
|
+
* The package ships one: `@statewalker/cellb/isolate-worker`. A function instead starts the
|
|
92
|
+
* Dedicated Worker itself (`() => new Worker(new URL(…, import.meta.url), { type: "module" })`,
|
|
93
|
+
* a form bundlers follow).
|
|
91
94
|
*/
|
|
92
|
-
isolateScript?: URL;
|
|
95
|
+
isolateScript?: URL | (() => Worker);
|
|
93
96
|
/** An initialized SQLite WASM module (`@sqlite.org/sqlite-wasm`). */
|
|
94
97
|
sqlite3: unknown;
|
|
95
98
|
/** OPFS sahpool name for this host's SQLite files (one pool per worker). */
|
|
@@ -162,12 +165,3 @@ export declare function browserProjectRuntime(opts: BrowserProjectOptions): Prom
|
|
|
162
165
|
} | undefined;
|
|
163
166
|
close: () => Promise<void>;
|
|
164
167
|
}>;
|
|
165
|
-
/**
|
|
166
|
-
* workerd fills `process.env` with the project's text `vars` under nodejs_compat from
|
|
167
|
-
* compatibility date 2025-04-01 (`nodejs_compat_populate_process_env`), unless
|
|
168
|
-
* `nodejs_compat_do_not_populate_process_env` is set. Frameworks read their settings there
|
|
169
|
-
* (EmDash's `EMDASH_SITE_URL`, for one).
|
|
170
|
-
*/
|
|
171
|
-
export declare function populatesProcessEnv(config: WranglerConfig): boolean;
|
|
172
|
-
/** The text `vars` of a project, as `process.env` holds them. */
|
|
173
|
-
export declare function processEnvOf(config: WranglerConfig): Record<string, string>;
|