@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.
Files changed (41) hide show
  1. package/README.md +46 -3
  2. package/bin/cellb.mjs +20 -0
  3. package/dist/browser.d.ts +2 -0
  4. package/dist/browser.js +1 -0
  5. package/dist/browser.js.map +1 -1
  6. package/dist/cli.d.ts +3 -0
  7. package/dist/cli.js +62 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/isolate/browser.d.ts +2 -1
  10. package/dist/isolate/browser.js +2 -1
  11. package/dist/isolate/browser.js.map +1 -1
  12. package/dist/isolate/isolate.js +5 -3
  13. package/dist/isolate/isolate.js.map +1 -1
  14. package/dist/isolate/protocol.d.ts +4 -2
  15. package/dist/isolate/protocol.js +4 -4
  16. package/dist/isolate/protocol.js.map +1 -1
  17. package/dist/node.d.ts +3 -0
  18. package/dist/node.js +2 -0
  19. package/dist/node.js.map +1 -1
  20. package/dist/project/browser-host.d.ts +6 -12
  21. package/dist/project/browser-host.js +2 -25
  22. package/dist/project/browser-host.js.map +1 -1
  23. package/dist/project/browser-load.d.ts +22 -0
  24. package/dist/project/browser-load.js +63 -0
  25. package/dist/project/browser-load.js.map +1 -0
  26. package/dist/project/build.d.ts +14 -0
  27. package/dist/project/build.js +53 -0
  28. package/dist/project/build.js.map +1 -0
  29. package/dist/project/built-project.d.ts +88 -0
  30. package/dist/project/built-project.js +118 -0
  31. package/dist/project/built-project.js.map +1 -0
  32. package/dist/project/node-load.d.ts +14 -0
  33. package/dist/project/node-load.js +187 -0
  34. package/dist/project/node-load.js.map +1 -0
  35. package/dist/project/wrangler.d.ts +9 -0
  36. package/dist/project/wrangler.js +24 -0
  37. package/dist/project/wrangler.js.map +1 -1
  38. package/dist/ws/server.d.ts +24 -6
  39. package/dist/ws/server.js +52 -16
  40. package/dist/ws/server.js.map +1 -1
  41. package/package.json +6 -1
@@ -13,7 +13,8 @@ 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, loadTimeEnv } from "./wrangler.js";
16
+ import { createProjectRuntime, loadTimeEnv, populatesProcessEnv, processEnvOf, } from "./wrangler.js";
17
+ export { populatesProcessEnv, processEnvOf };
17
18
  async function bucketStore(b) {
18
19
  if ("store" in b)
19
20
  return b.store;
@@ -174,28 +175,4 @@ export async function browserProjectRuntime(opts) {
174
175
  },
175
176
  };
176
177
  }
177
- /**
178
- * workerd fills `process.env` with the project's text `vars` under nodejs_compat from
179
- * compatibility date 2025-04-01 (`nodejs_compat_populate_process_env`), unless
180
- * `nodejs_compat_do_not_populate_process_env` is set. Frameworks read their settings there
181
- * (EmDash's `EMDASH_SITE_URL`, for one).
182
- */
183
- export function populatesProcessEnv(config) {
184
- const flags = config.compatibility_flags ?? [];
185
- if (!flags.some((f) => f.startsWith("nodejs_compat")))
186
- return false;
187
- if (flags.includes("nodejs_compat_do_not_populate_process_env"))
188
- return false;
189
- if (flags.includes("nodejs_compat_populate_process_env"))
190
- return true;
191
- return (config.compatibility_date ?? "") >= "2025-04-01";
192
- }
193
- /** The text `vars` of a project, as `process.env` holds them. */
194
- export function processEnvOf(config) {
195
- const env = {};
196
- for (const [k, v] of Object.entries(config.vars ?? {}))
197
- if (typeof v === "string")
198
- env[k] = v;
199
- return env;
200
- }
201
178
  //# sourceMappingURL=browser-host.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"browser-host.js","sourceRoot":"","sources":["../../src/project/browser-host.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAoB,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,aAAa,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAAoB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,KAAK,cAAc,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAuB,MAAM,eAAe,CAAC;AA+FvF,KAAK,UAAU,WAAW,CAAC,CAAgB;IACzC,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC,KAAK,CAAC;IACjC,IAAI,IAAI,IAAI,CAAC;QAAE,OAAO,aAAa,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACtE,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,KAAK,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IAClF,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;IACpD,OAAO,mBAAmB,CACxB,IAAI,eAAe,CAAC,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAC5F,EAAE,CACH,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,SAAS,CAAC,OAAgB,EAAE,GAAW,EAAE,YAAqB,EAAE,KAAc;IAC3F,MAAM,KAAK,GAAG,IAAI,MAAM,CACtB,IAAI,GAAG,CAAC,4BAA4B,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,wCAAwC,EAC/F,EAAE,IAAI,EAAE,QAAQ,EAAE,CACnB,CAAC;IACF,MAAM,GAAG,GAAG,IAAI,iBAAiB,CAAC,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,4CAA4C;IAC/F,2FAA2F;IAC3F,yFAAyF;IACzF,MAAM,KAAK,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAClD,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,OAAO,IAAI,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC/F,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9F,CAAC,CAAC,CAAC;IACH,KAAK,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;IACjE,MAAM,KAAK,CAAC;IACZ,MAAM,EAAE,IAAI,EAAE,GAAG,aAAa,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpF,MAAM,EAAE,GAAG,OAAmE,CAAC;IAC/E,MAAM,IAAI,GAAG,CAAC,OAAe,EAAE,EAAE;QAC/B,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACvE,kBAAkB,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAChC,EAAE,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAC;QAChE,yFAAyF;QACzF,OAAO,IAAI,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,SAAS,EAAG,OAA2B,CAAC,IAAI,CAAC,CAAC;IAC3F,CAAC,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE;QACzB,OAAO;YACL,KAAK,CAAC,SAAS,EAAE,CAAC;QACpB,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC;KAChC,CAAC,CAAC;AACL,CAAC;AAED,4EAA4E;AAC5E,KAAK,UAAU,gBAAgB,CAC7B,MAAsB,EACtB,IAAmC,EACnC,KAAkB;IAElB,MAAM,KAAK,GAAG,MAAM,CAAC,mBAAmB,IAAI,EAAE,CAAC;IAC/C,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC;IACpE,IAAI,UAAU,EAAE,CAAC;QACf,kBAAkB,EAAE,CAAC;QACrB,+FAA+F;QAC/F,iFAAiF;QAChF,UAAsC,CAAC,kBAAkB,GAAG,CAC3D,MAAM,MAAM,CAAC,oCAAoC,CAAC,CACnD,CAAC,mBAAmB,CAAC;QACtB,IAAI,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC;YAChC,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;YACjC,yFAAyF;YACxF,UAAsC,CAAC,iBAAiB,GAAG,GAAG,CAAC;YAChE,MAAM,CAAC,MAAM,CAAE,UAA2D,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC/F,CAAC;QACD,0FAA0F;QAC1F,6FAA6F;QAC7F,8FAA8F;QAC9F,oBAAoB;QACpB,mBAAmB,EAAE,CAAC;IACxB,CAAC;IACD,MAAM,OAAO,GAAG;QACd,GAAG,cAAc;QACjB,OAAO,EAAE,cAAc,CAAC,YAAY;QACpC,QAAQ,EAAE,cAAc,CAAC,aAAa;QACtC,aAAa,EAAE,KAAK,CAAC,QAAQ,CAAC,gCAAgC,CAAC;YAC7D,CAAC,CAAC,cAAc,CAAC,qBAAqB;YACtC,CAAC,CAAC,cAAc,CAAC,aAAa;KACjC,CAAC;IACF,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QACnB,mBAAmB,CAAC;YAClB,aAAa;YACb,oBAAoB,EAAE;gBACpB,GAAG,aAAa;gBAChB,GAAG,EAAE,KAAK,CAAC,GAAG;gBACd,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,SAAS,EAAE,KAAK,CAAC,SAAS;aAC3B;YACD,YAAY,EAAE,GAAG,IAAI,CAAC,IAAI,SAAS;YACnC,WAAW,EAAE,MAAM,MAAM,CAAC,uBAAuB,CAAC;YAClD,GAAG,OAAO;YACV,wFAAwF;YACxF,uBAAuB;YACvB,IAAI,EAAE,UAAU;gBACd,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,oCAAoC,CAAC,CAAC,CAAC,mBAAmB;gBAC1E,CAAC,CAAC,SAAS;SACd,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,IAAI;YAChB,CAAC,CAAC,MAAM,MAAM,CAAC,kBAAkB,CAAC,GAAG,IAAI,CAAC,IAAI,aAAa,MAAM,CAAC,IAAI,EAAE,CAAC;YACzE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACtB,CAAC;IACD,MAAM,CAAC,GAAG,UAAqC,CAAC;IAChD,CAAC,CAAC,oBAAoB,GAAG,aAAa,CAAC;IACvC,CAAC,CAAC,mBAAmB,GAAG,KAAK,CAAC,CAAC,yDAAyD;IACxF,CAAC,CAAC,cAAc,GAAG,OAAO,CAAC;IAC3B,OAAO,IAAI,CAAC,MAAM;QAChB,CAAC,CAAC,MAAM,MAAM;QACV,kBAAkB,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAC7F;QACH,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,IAA2B;IACrE,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACrE,MAAM,IAAI,GAAG,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9D,0FAA0F;IAC1F,MAAM,OAAO,GACX,IAAI,CAAC,MAAM,IAAI,KAAK,IAAI,IAAI,CAAC,MAAM;QACjC,CAAC,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;QAC7F,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,KAAK,IAAI,IAAI,CAAC,MAAM;YACnC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,OAAgB,CAAC,EAAE;gBACrD,OAAO,KAAI,CAAC;gBACZ,OAAO,EAAE,KAAK,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC;aAChC,CAAC;YACJ,CAAC,CAAC,MAAM,aAAa,CAAC,IAAI,CAAC,OAAgB,EAAE;gBACzC,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,eAAe,EAAE,EAAE,EAAE,kCAAkC;aACxD,CAAC,CAAC;IACX,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;IACpD,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC;QAChC,UAAU,EAAE,MAAM,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;KAC3E,CAAC,CAAC;IACH,8EAA8E;IAC9E,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAClG,MAAM,MAAM,GACV,IAAI,CAAC,MAAM,IAAI,KAAK;QAClB,CAAC,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACpF,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,oBAAoB,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE;QACzE,OAAO;QACP,KAAK;QACL,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,mBAAmB,EAAE;QAClE,eAAe,EAAE,IAAI,CAAC,aAAa;YACjC,CAAC,CAAC,qBAAqB,CAAC;gBACpB,aAAa,EAAE,IAAI,CAAC,aAAa;gBACjC,WAAW,EAAE,IAAI;gBACjB,aAAa,EAAE,GAAG,IAAI,CAAC,IAAI,MAAM;gBACjC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,uDAAuD;aAC/E,CAAC;YACJ,CAAC,CAAC,SAAS;QACb,OAAO,EAAE,MAAM,EAAE,0DAA0D;QAC3E,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,EAAE,EAAE,IAAI,CAAC,EAAE;KACZ,CAAC,CAAC;IACH,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpB,OAAO;QACL,OAAO;QACP,WAAW;QACX,MAAM,EAAE,MAAM;QACd,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,sDAAsD;QAC3E,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAsB;IACxD,MAAM,KAAK,GAAG,MAAM,CAAC,mBAAmB,IAAI,EAAE,CAAC;IAC/C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACpE,IAAI,KAAK,CAAC,QAAQ,CAAC,2CAA2C,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9E,IAAI,KAAK,CAAC,QAAQ,CAAC,oCAAoC,CAAC;QAAE,OAAO,IAAI,CAAC;IACtE,OAAO,CAAC,MAAM,CAAC,kBAAkB,IAAI,EAAE,CAAC,IAAI,YAAY,CAAC;AAC3D,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,YAAY,CAAC,MAAsB;IACjD,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QAAE,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC9F,OAAO,GAAG,CAAC;AACb,CAAC","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 { 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 { createProjectRuntime, loadTimeEnv, type WranglerConfig } from \"./wrangler.js\";\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: OPFS through synchronous handles (default,\n * `opfs-sync`), OPFS through its asynchronous API (`opfs`), or memory (nothing kept).\n */\n files?: \"opfs\" | \"opfs-sync\" | \"memory\";\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`.\n */\n isolateScript?: URL;\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: a store worker owns the OPFS directory; each cell is a SQLite database\n * whose main file is its LTX files, read page by page (src/adapters/ltx-vfs.ts).\n */\nasync function ltxOpener(sqlite3: unknown, dir: string, compactAfter?: number, files?: string) {\n const store = new Worker(\n new URL(\"../ltx/ltx-store-worker.ts\", import.meta.url) /* `.js` in dist/ (scripts/build.mjs) */,\n { type: \"module\" },\n );\n const 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) => e.data?.op === \"ready\" && resolve(), { once: false });\n store.addEventListener(\"error\", (e) => reject(new Error(`ltx store worker: ${e.message}`)));\n });\n store.postMessage({ op: \"init\", sab, dir, compactAfter, files });\n await ready;\n const { name } = installLtxVfs(sqlite3, { sab, post: (m) => store.postMessage(m) });\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 store.terminate();\n },\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 = flags.some((f) => f.startsWith(\"nodejs_compat\"));\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(opts.sqlite3, opts.bucket.ltx, opts.bucket.compactAfter, opts.bucket.files)\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\n/**\n * workerd fills `process.env` with the project's text `vars` under nodejs_compat from\n * compatibility date 2025-04-01 (`nodejs_compat_populate_process_env`), unless\n * `nodejs_compat_do_not_populate_process_env` is set. Frameworks read their settings there\n * (EmDash's `EMDASH_SITE_URL`, for one).\n */\nexport function populatesProcessEnv(config: WranglerConfig): boolean {\n const flags = config.compatibility_flags ?? [];\n if (!flags.some((f) => f.startsWith(\"nodejs_compat\"))) return false;\n if (flags.includes(\"nodejs_compat_do_not_populate_process_env\")) return false;\n if (flags.includes(\"nodejs_compat_populate_process_env\")) return true;\n return (config.compatibility_date ?? \"\") >= \"2025-04-01\";\n}\n\n/** The text `vars` of a project, as `process.env` holds them. */\nexport function processEnvOf(config: WranglerConfig): Record<string, string> {\n const env: Record<string, string> = {};\n for (const [k, v] of Object.entries(config.vars ?? {})) if (typeof v === \"string\") env[k] = v;\n return env;\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 { 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 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: OPFS through synchronous handles (default,\n * `opfs-sync`), OPFS through its asynchronous API (`opfs`), or memory (nothing kept).\n */\n files?: \"opfs\" | \"opfs-sync\" | \"memory\";\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: a store worker owns the OPFS directory; each cell is a SQLite database\n * whose main file is its LTX files, read page by page (src/adapters/ltx-vfs.ts).\n */\nasync function ltxOpener(sqlite3: unknown, dir: string, compactAfter?: number, files?: string) {\n const store = new Worker(\n new URL(\"../ltx/ltx-store-worker.ts\", import.meta.url) /* `.js` in dist/ (scripts/build.mjs) */,\n { type: \"module\" },\n );\n const 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) => e.data?.op === \"ready\" && resolve(), { once: false });\n store.addEventListener(\"error\", (e) => reject(new Error(`ltx store worker: ${e.message}`)));\n });\n store.postMessage({ op: \"init\", sab, dir, compactAfter, files });\n await ready;\n const { name } = installLtxVfs(sqlite3, { sab, post: (m) => store.postMessage(m) });\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 store.terminate();\n },\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 = flags.some((f) => f.startsWith(\"nodejs_compat\"));\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(opts.sqlite3, opts.bucket.ltx, opts.bucket.compactAfter, opts.bucket.files)\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"]}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * `loadProject` in a browser (`@statewalker/cellb/browser`), in a Dedicated Worker: fetches a
3
+ * folder written by `cellb build` and runs it with `browserProjectRuntime`.
4
+ */
5
+ import { type BrowserBucket } from "./browser-host.js";
6
+ import { type LoadedProject, type LoadProjectOptions, type ProjectSource } from "./built-project.js";
7
+ export interface BrowserLoadProjectOptions extends LoadProjectOptions<BrowserBucket> {
8
+ /**
9
+ * Where loaded Workers (Worker Loader) run: the package's own isolate worker by default; a
10
+ * script URL or a function starting a Dedicated Worker instead; `false` to run them in this
11
+ * realm.
12
+ */
13
+ isolateScript?: URL | (() => Worker) | false;
14
+ }
15
+ /**
16
+ * Loads a built project and runs it in this worker.
17
+ *
18
+ * `source`: the URL of a `cellb build` folder (relative URLs resolve against the page or
19
+ * worker), or a FilesApi holding one. `options.data` names the OPFS pool (`<data>`) and the
20
+ * project's files directory (`<data>-files`); it defaults to the project's `name`.
21
+ */
22
+ export declare function loadProject(source: ProjectSource, options?: BrowserLoadProjectOptions): Promise<LoadedProject>;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * `loadProject` in a browser (`@statewalker/cellb/browser`), in a Dedicated Worker: fetches a
3
+ * folder written by `cellb build` and runs it with `browserProjectRuntime`.
4
+ */
5
+ import { browserProjectRuntime } from "./browser-host.js";
6
+ import { BUILD_MANIFEST, filesApiReader, isFilesApi, readBuildManifest, readBuiltProject, urlReader, } from "./built-project.js";
7
+ /** The isolate worker this package ships (bundlers follow the `new Worker(new URL(…))` form). */
8
+ const ownIsolate = () => new Worker(new URL("../isolate/isolate-worker.js", import.meta.url), { type: "module" });
9
+ /**
10
+ * Loads a built project and runs it in this worker.
11
+ *
12
+ * `source`: the URL of a `cellb build` folder (relative URLs resolve against the page or
13
+ * worker), or a FilesApi holding one. `options.data` names the OPFS pool (`<data>`) and the
14
+ * project's files directory (`<data>-files`); it defaults to the project's `name`.
15
+ */
16
+ export async function loadProject(source, options = {}) {
17
+ let reader;
18
+ let where;
19
+ if (isFilesApi(source)) {
20
+ reader = filesApiReader(source);
21
+ where = "the FilesApi";
22
+ }
23
+ else {
24
+ const url = new URL(String(source), globalThis.location?.href);
25
+ if (!url.pathname.endsWith("/"))
26
+ url.pathname += "/";
27
+ reader = urlReader(url);
28
+ where = url.href;
29
+ }
30
+ const manifest = await readBuildManifest(reader);
31
+ if (!manifest)
32
+ throw new Error(`${where} has no ${BUILD_MANIFEST}: browsers load folders written by \`cellb build\``);
33
+ const built = await readBuiltProject(reader, manifest);
34
+ const data = options.data ?? built.config.name ?? "cellb";
35
+ const sqlite3 = options.sqlite3 ?? (await defaultSqlite3());
36
+ const isolateScript = options.isolateScript === false ? undefined : (options.isolateScript ?? ownIsolate);
37
+ const project = await browserProjectRuntime({
38
+ config: built.config,
39
+ code: { bundle: built.code },
40
+ assetFiles: built.assets,
41
+ sqlite3,
42
+ pool: data,
43
+ filesDir: `${data}-files`,
44
+ bucket: options.bucket,
45
+ ai: options.ai,
46
+ isolateScript,
47
+ });
48
+ const { runtime } = project;
49
+ return {
50
+ config: built.config,
51
+ runtime,
52
+ unsupported: project.unsupported,
53
+ fetch: (req) => runtime.fetch(req),
54
+ close: project.close,
55
+ };
56
+ }
57
+ let sqlite3Module;
58
+ /** `@sqlite.org/sqlite-wasm`, initialized once per worker. */
59
+ function defaultSqlite3() {
60
+ sqlite3Module ??= import("@sqlite.org/sqlite-wasm").then(({ default: init }) => init({ print() { }, printErr() { } }));
61
+ return sqlite3Module;
62
+ }
63
+ //# sourceMappingURL=browser-load.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-load.js","sourceRoot":"","sources":["../../src/project/browser-load.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `loadProject` in a browser (`@statewalker/cellb/browser`), in a Dedicated Worker: fetches a\n * folder written by `cellb build` and runs it with `browserProjectRuntime`.\n */\n\nimport { type BrowserBucket, browserProjectRuntime } from \"./browser-host.js\";\nimport {\n BUILD_MANIFEST,\n filesApiReader,\n isFilesApi,\n type LoadedProject,\n type LoadProjectOptions,\n type ProjectSource,\n readBuildManifest,\n readBuiltProject,\n urlReader,\n} from \"./built-project.js\";\n\nexport interface BrowserLoadProjectOptions extends LoadProjectOptions<BrowserBucket> {\n /**\n * Where loaded Workers (Worker Loader) run: the package's own isolate worker by default; a\n * script URL or a function starting a Dedicated Worker instead; `false` to run them in this\n * realm.\n */\n isolateScript?: URL | (() => Worker) | false;\n}\n\n/** The isolate worker this package ships (bundlers follow the `new Worker(new URL(…))` form). */\nconst ownIsolate = () =>\n new Worker(new URL(\"../isolate/isolate-worker.ts\", import.meta.url), { type: \"module\" });\n\n/**\n * Loads a built project and runs it in this worker.\n *\n * `source`: the URL of a `cellb build` folder (relative URLs resolve against the page or\n * worker), or a FilesApi holding one. `options.data` names the OPFS pool (`<data>`) and the\n * project's files directory (`<data>-files`); it defaults to the project's `name`.\n */\nexport async function loadProject(\n source: ProjectSource,\n options: BrowserLoadProjectOptions = {},\n): Promise<LoadedProject> {\n let reader: ReturnType<typeof urlReader>;\n let where: string;\n if (isFilesApi(source)) {\n reader = filesApiReader(source);\n where = \"the FilesApi\";\n } else {\n const url = new URL(String(source), (globalThis as { location?: Location }).location?.href);\n if (!url.pathname.endsWith(\"/\")) url.pathname += \"/\";\n reader = urlReader(url);\n where = url.href;\n }\n const manifest = await readBuildManifest(reader);\n if (!manifest)\n throw new Error(\n `${where} has no ${BUILD_MANIFEST}: browsers load folders written by \\`cellb build\\``,\n );\n const built = await readBuiltProject(reader, manifest);\n const data = options.data ?? built.config.name ?? \"cellb\";\n const sqlite3 = options.sqlite3 ?? (await defaultSqlite3());\n const isolateScript =\n options.isolateScript === false ? undefined : (options.isolateScript ?? ownIsolate);\n const project = await browserProjectRuntime({\n config: built.config,\n code: { bundle: built.code },\n assetFiles: built.assets,\n sqlite3,\n pool: data,\n filesDir: `${data}-files`,\n bucket: options.bucket,\n ai: options.ai,\n isolateScript,\n });\n const { runtime } = project;\n return {\n config: built.config,\n runtime,\n unsupported: project.unsupported,\n fetch: (req) => runtime.fetch(req),\n close: project.close,\n };\n}\n\nlet sqlite3Module: Promise<unknown> | undefined;\n/** `@sqlite.org/sqlite-wasm`, initialized once per worker. */\nfunction defaultSqlite3(): Promise<unknown> {\n sqlite3Module ??= import(\"@sqlite.org/sqlite-wasm\").then(({ default: init }) =>\n (init as (o: object) => Promise<unknown>)({ print() {}, printErr() {} }),\n );\n return sqlite3Module;\n}\n"]}
@@ -0,0 +1,14 @@
1
+ import { type BuildManifest } from "./built-project.js";
2
+ export interface BuildProjectOptions {
3
+ /**
4
+ * Lower `await` to generators (default: with nodejs_compat), as `bundleWorkerForBrowser`;
5
+ * `false` for browsers with TC39 AsyncContext only.
6
+ */
7
+ lowerAwait?: boolean;
8
+ }
9
+ /**
10
+ * `cellb build`: writes the project in `dir` as a folder any static host serves and
11
+ * `loadProject` (browser or Node) loads: `wrangler.json`, `worker.js` (`main` bundled for a
12
+ * browser realm, with nodejs_compat when the flags ask for it), `assets/` and `cellb.json`.
13
+ */
14
+ export declare function buildProject(dir: string, outDir: string, opts?: BuildProjectOptions): Promise<BuildManifest>;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * `buildProject` (`cellb build`): the build step whose output folder `loadProject` loads, in a
3
+ * browser or on Node. Imports no SQLite: the command stays quiet and light.
4
+ */
5
+ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
6
+ import { dirname, join, resolve } from "node:path";
7
+ import { bundleWorkerForBrowser } from "./browser-bundle.js";
8
+ import { BUILD_FORMAT, BUILD_MANIFEST, BUILT_ASSETS, BUILT_WORKER, builtConfig, } from "./built-project.js";
9
+ import { readAssetDirectory, readWranglerConfig } from "./node-project.js";
10
+ /**
11
+ * `cellb build`: writes the project in `dir` as a folder any static host serves and
12
+ * `loadProject` (browser or Node) loads: `wrangler.json`, `worker.js` (`main` bundled for a
13
+ * browser realm, with nodejs_compat when the flags ask for it), `assets/` and `cellb.json`.
14
+ */
15
+ export async function buildProject(dir, outDir, opts = {}) {
16
+ dir = resolve(dir);
17
+ outDir = resolve(outDir);
18
+ const config = readWranglerConfig(dir);
19
+ if (!config.main && !config.assets)
20
+ throw new Error("wrangler config has neither `main` nor `assets`");
21
+ const flags = config.compatibility_flags ?? [];
22
+ const nodeCompat = flags.some((f) => f.startsWith("nodejs_compat"));
23
+ const code = config.main
24
+ ? await bundleWorkerForBrowser(resolve(dir, config.main), {
25
+ nodeCompat,
26
+ lowerAwait: opts.lowerAwait,
27
+ })
28
+ : null;
29
+ const assets = config.assets?.directory
30
+ ? readAssetDirectory(resolve(dir, config.assets.directory))
31
+ : new Map();
32
+ // A fresh folder: files of an earlier build must not linger as assets.
33
+ for (const name of [BUILD_MANIFEST, "wrangler.json", BUILT_WORKER, BUILT_ASSETS])
34
+ rmSync(join(outDir, name), { recursive: true, force: true });
35
+ mkdirSync(outDir, { recursive: true });
36
+ writeFileSync(join(outDir, "wrangler.json"), `${JSON.stringify(builtConfig(config), null, 2)}\n`);
37
+ if (code !== null)
38
+ writeFileSync(join(outDir, BUILT_WORKER), code);
39
+ for (const [path, bytes] of assets) {
40
+ const out = join(outDir, BUILT_ASSETS, path);
41
+ mkdirSync(dirname(out), { recursive: true });
42
+ writeFileSync(out, bytes);
43
+ }
44
+ const manifest = {
45
+ format: BUILD_FORMAT,
46
+ main: code !== null ? BUILT_WORKER : null,
47
+ assets: [...assets.keys()].sort(),
48
+ };
49
+ // Written last: a folder with a manifest is a complete build.
50
+ writeFileSync(join(outDir, BUILD_MANIFEST), `${JSON.stringify(manifest, null, 2)}\n`);
51
+ return manifest;
52
+ }
53
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/project/build.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `buildProject` (`cellb build`): the build step whose output folder `loadProject` loads, in a\n * browser or on Node. Imports no SQLite: the command stays quiet and light.\n */\nimport { mkdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { bundleWorkerForBrowser } from \"./browser-bundle.js\";\nimport {\n BUILD_FORMAT,\n BUILD_MANIFEST,\n BUILT_ASSETS,\n BUILT_WORKER,\n type BuildManifest,\n builtConfig,\n} from \"./built-project.js\";\nimport { readAssetDirectory, readWranglerConfig } from \"./node-project.js\";\n\nexport interface BuildProjectOptions {\n /**\n * Lower `await` to generators (default: with nodejs_compat), as `bundleWorkerForBrowser`;\n * `false` for browsers with TC39 AsyncContext only.\n */\n lowerAwait?: boolean;\n}\n\n/**\n * `cellb build`: writes the project in `dir` as a folder any static host serves and\n * `loadProject` (browser or Node) loads: `wrangler.json`, `worker.js` (`main` bundled for a\n * browser realm, with nodejs_compat when the flags ask for it), `assets/` and `cellb.json`.\n */\nexport async function buildProject(\n dir: string,\n outDir: string,\n opts: BuildProjectOptions = {},\n): Promise<BuildManifest> {\n dir = resolve(dir);\n outDir = resolve(outDir);\n const config = readWranglerConfig(dir);\n if (!config.main && !config.assets)\n throw new Error(\"wrangler config has neither `main` nor `assets`\");\n const flags = config.compatibility_flags ?? [];\n const nodeCompat = flags.some((f) => f.startsWith(\"nodejs_compat\"));\n const code = config.main\n ? await bundleWorkerForBrowser(resolve(dir, config.main), {\n nodeCompat,\n lowerAwait: opts.lowerAwait,\n })\n : null;\n const assets = config.assets?.directory\n ? readAssetDirectory(resolve(dir, config.assets.directory))\n : new Map<string, Uint8Array>();\n // A fresh folder: files of an earlier build must not linger as assets.\n for (const name of [BUILD_MANIFEST, \"wrangler.json\", BUILT_WORKER, BUILT_ASSETS])\n rmSync(join(outDir, name), { recursive: true, force: true });\n mkdirSync(outDir, { recursive: true });\n writeFileSync(join(outDir, \"wrangler.json\"), `${JSON.stringify(builtConfig(config), null, 2)}\\n`);\n if (code !== null) writeFileSync(join(outDir, BUILT_WORKER), code);\n for (const [path, bytes] of assets) {\n const out = join(outDir, BUILT_ASSETS, path);\n mkdirSync(dirname(out), { recursive: true });\n writeFileSync(out, bytes);\n }\n const manifest: BuildManifest = {\n format: BUILD_FORMAT,\n main: code !== null ? BUILT_WORKER : null,\n assets: [...assets.keys()].sort(),\n };\n // Written last: a folder with a manifest is a complete build.\n writeFileSync(join(outDir, BUILD_MANIFEST), `${JSON.stringify(manifest, null, 2)}\\n`);\n return manifest;\n}\n"]}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * The folder `cellb build` writes, and what `loadProject` reads, on both platforms:
3
+ *
4
+ * wrangler.json the project's configuration (`main` → "worker.js", `assets.directory` → "assets")
5
+ * worker.js `main` bundled for a browser realm (bundleWorkerForBrowser), if there is a `main`
6
+ * assets/… the files of `assets.directory`, as they are
7
+ * cellb.json this manifest: the format, and the asset paths (a static host cannot list a folder)
8
+ *
9
+ * Platform-neutral: it reads through a `ProjectReader` (Node's fs, `fetch` of a URL, a FilesApi).
10
+ */
11
+ import type { FilesApi } from "@statewalker/webrun-files";
12
+ import type { AssetFiles } from "../bindings/assets.js";
13
+ import type { WorkersAiOptions } from "../bindings/workers-ai.js";
14
+ import type { CellRuntime } from "../core/runtime.js";
15
+ import type { WranglerConfig } from "./wrangler.js";
16
+ /** The manifest's file name in a built folder. */
17
+ export declare const BUILD_MANIFEST = "cellb.json";
18
+ /** The format a built folder declares in its manifest. */
19
+ export declare const BUILD_FORMAT = "cellb-build/1";
20
+ /** The bundled `main` in a built folder. */
21
+ export declare const BUILT_WORKER = "worker.js";
22
+ /** The assets directory in a built folder. */
23
+ export declare const BUILT_ASSETS = "assets";
24
+ export interface BuildManifest {
25
+ format: typeof BUILD_FORMAT;
26
+ /** `worker.js`, or null for a project without `main` (assets only). */
27
+ main: string | null;
28
+ /** The asset files, as paths under `assets/` ("/index.html", "/css/site.css"). */
29
+ assets: string[];
30
+ }
31
+ /** A built project in memory: what `browserProjectRuntime` takes. */
32
+ export interface BuiltProject {
33
+ config: WranglerConfig;
34
+ /** `main` bundled for a browser realm, or null. */
35
+ code: string | null;
36
+ assets: AssetFiles;
37
+ }
38
+ /** Reads the files of a project folder, wherever it lives; `undefined` for a missing file. */
39
+ export interface ProjectReader {
40
+ bytes(path: string): Promise<Uint8Array | undefined>;
41
+ /** The files under `dir`, as paths relative to it ("/a/b.html"); only where the source can list. */
42
+ list?(dir: string): Promise<string[]>;
43
+ }
44
+ /** Where `loadProject` finds a project. */
45
+ export type ProjectSource =
46
+ /** Node: a folder with wrangler.json(c), built or not; browser: the URL of a `cellb build` folder. */
47
+ string | URL
48
+ /** Any FilesApi holding either kind of folder at its root. */
49
+ | FilesApi;
50
+ /** Options of `loadProject`, the same on Node and in browsers. */
51
+ export interface LoadProjectOptions<Bucket = unknown> {
52
+ /**
53
+ * Where cells keep their data. Node: a directory (SQLite files and the project's files under
54
+ * it; default: memory). Browser: an OPFS name, the pool (`<data>`) and the files directory
55
+ * (`<data>-files`) (default: the project's `name`).
56
+ */
57
+ data?: string;
58
+ /** A fleet bucket: a `BrowserBucket` in browsers, a `CellStorage` on Node. */
59
+ bucket?: Bucket;
60
+ /** The OpenAI-compatible endpoint behind the project's `ai` binding (Workers AI). */
61
+ ai?: WorkersAiOptions;
62
+ /** Browser only: an initialized SQLite WASM module (default: loads `@sqlite.org/sqlite-wasm`). */
63
+ sqlite3?: unknown;
64
+ }
65
+ /** A running project. */
66
+ export interface LoadedProject {
67
+ config: WranglerConfig;
68
+ runtime: CellRuntime;
69
+ /** Configuration entries cellb does not run (reported, not silently ignored). */
70
+ unsupported: string[];
71
+ /** A request to the project, as its Worker (and assets) answer it. */
72
+ fetch(req: Request): Promise<Response>;
73
+ close(): Promise<void>;
74
+ }
75
+ /** Reads JSON (or JSONC) at `path`, or undefined when the file is missing. */
76
+ export declare function readJson<T>(reader: ProjectReader, path: string): Promise<T | undefined>;
77
+ /** The manifest of a built folder, or undefined when the folder is not one. */
78
+ export declare function readBuildManifest(reader: ProjectReader): Promise<BuildManifest | undefined>;
79
+ /** Reads a `cellb build` folder: its configuration, its bundled `main` and its assets. */
80
+ export declare function readBuiltProject(reader: ProjectReader, manifest?: BuildManifest): Promise<BuiltProject>;
81
+ /** A reader over a FilesApi, rooted at `root` ("/" by default). */
82
+ export declare function filesApiReader(files: FilesApi, root?: string): ProjectReader;
83
+ /** A reader over HTTP: files of the folder at `base` (a URL ending in "/"). */
84
+ export declare function urlReader(base: URL, fetchFn?: typeof fetch): ProjectReader;
85
+ /** Whether `v` is a FilesApi (a source given as files rather than a path or URL). */
86
+ export declare function isFilesApi(v: unknown): v is FilesApi;
87
+ /** A built project's configuration as `wrangler.json` holds it: `main` and assets renamed. */
88
+ export declare function builtConfig(config: WranglerConfig): WranglerConfig;
@@ -0,0 +1,118 @@
1
+ import { parseJsonc } from "./jsonc.js";
2
+ /** The manifest's file name in a built folder. */
3
+ export const BUILD_MANIFEST = "cellb.json";
4
+ /** The format a built folder declares in its manifest. */
5
+ export const BUILD_FORMAT = "cellb-build/1";
6
+ /** The bundled `main` in a built folder. */
7
+ export const BUILT_WORKER = "worker.js";
8
+ /** The assets directory in a built folder. */
9
+ export const BUILT_ASSETS = "assets";
10
+ const decoder = new TextDecoder();
11
+ /** Reads JSON (or JSONC) at `path`, or undefined when the file is missing. */
12
+ export async function readJson(reader, path) {
13
+ const bytes = await reader.bytes(path);
14
+ return bytes ? parseJsonc(decoder.decode(bytes)) : undefined;
15
+ }
16
+ /** The manifest of a built folder, or undefined when the folder is not one. */
17
+ export async function readBuildManifest(reader) {
18
+ const manifest = await readJson(reader, BUILD_MANIFEST);
19
+ if (!manifest)
20
+ return undefined;
21
+ if (manifest.format !== BUILD_FORMAT)
22
+ throw new Error(`${BUILD_MANIFEST}: unknown format ${JSON.stringify(manifest.format)}`);
23
+ return manifest;
24
+ }
25
+ /** Reads a `cellb build` folder: its configuration, its bundled `main` and its assets. */
26
+ export async function readBuiltProject(reader, manifest) {
27
+ manifest ??= await readBuildManifest(reader);
28
+ if (!manifest)
29
+ throw new Error(`no ${BUILD_MANIFEST}: not a folder written by \`cellb build\``);
30
+ const config = await readJson(reader, "wrangler.json");
31
+ if (!config)
32
+ throw new Error("no wrangler.json in the built folder");
33
+ let code = null;
34
+ if (manifest.main) {
35
+ const bytes = await reader.bytes(manifest.main);
36
+ if (!bytes)
37
+ throw new Error(`${manifest.main} is missing from the built folder`);
38
+ code = decoder.decode(bytes);
39
+ }
40
+ const assets = new Map();
41
+ await Promise.all(manifest.assets.map(async (p) => {
42
+ const bytes = await reader.bytes(`${BUILT_ASSETS}${p}`);
43
+ if (!bytes)
44
+ throw new Error(`${BUILT_ASSETS}${p} is missing from the built folder`);
45
+ assets.set(p, bytes);
46
+ }));
47
+ return { config, code, assets };
48
+ }
49
+ /** A reader over a FilesApi, rooted at `root` ("/" by default). */
50
+ export function filesApiReader(files, root = "/") {
51
+ const base = root.endsWith("/") ? root : `${root}/`;
52
+ const at = (p) => `${base}${p.replace(/^\/+/, "")}`;
53
+ return {
54
+ async bytes(path) {
55
+ const full = at(path);
56
+ const stats = await files.stats(full);
57
+ if (!stats || stats.kind !== "file")
58
+ return undefined;
59
+ const chunks = [];
60
+ for await (const c of files.read(full))
61
+ chunks.push(c);
62
+ return concat(chunks);
63
+ },
64
+ async list(dir) {
65
+ const full = at(dir).replace(/\/+$/, "");
66
+ const out = [];
67
+ for await (const e of files.list(full, { recursive: true }))
68
+ if (e.kind === "file")
69
+ out.push(e.path.slice(full.length));
70
+ return out;
71
+ },
72
+ };
73
+ }
74
+ /** A reader over HTTP: files of the folder at `base` (a URL ending in "/"). */
75
+ export function urlReader(base, fetchFn = fetch) {
76
+ return {
77
+ async bytes(path) {
78
+ const res = await fetchFn(new URL(path.replace(/^\/+/, ""), base));
79
+ if (res.status === 404) {
80
+ await res.body?.cancel();
81
+ return undefined;
82
+ }
83
+ if (!res.ok)
84
+ throw new Error(`GET ${new URL(path, base)}: ${res.status} ${res.statusText}`);
85
+ return new Uint8Array(await res.arrayBuffer());
86
+ },
87
+ };
88
+ }
89
+ /** Whether `v` is a FilesApi (a source given as files rather than a path or URL). */
90
+ export function isFilesApi(v) {
91
+ return (typeof v === "object" &&
92
+ v !== null &&
93
+ !(v instanceof URL) &&
94
+ typeof v.read === "function" &&
95
+ typeof v.list === "function" &&
96
+ typeof v.stats === "function");
97
+ }
98
+ /** A built project's configuration as `wrangler.json` holds it: `main` and assets renamed. */
99
+ export function builtConfig(config) {
100
+ const out = { ...config };
101
+ if (config.main)
102
+ out.main = BUILT_WORKER;
103
+ if (config.assets)
104
+ out.assets = { ...config.assets, directory: BUILT_ASSETS };
105
+ return out;
106
+ }
107
+ function concat(chunks) {
108
+ if (chunks.length === 1)
109
+ return chunks[0];
110
+ const out = new Uint8Array(chunks.reduce((n, c) => n + c.length, 0));
111
+ let at = 0;
112
+ for (const c of chunks) {
113
+ out.set(c, at);
114
+ at += c.length;
115
+ }
116
+ return out;
117
+ }
118
+ //# sourceMappingURL=built-project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"built-project.js","sourceRoot":"","sources":["../../src/project/built-project.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The folder `cellb build` writes, and what `loadProject` reads, on both platforms:\n *\n * wrangler.json the project's configuration (`main` → \"worker.js\", `assets.directory` → \"assets\")\n * worker.js `main` bundled for a browser realm (bundleWorkerForBrowser), if there is a `main`\n * assets/… the files of `assets.directory`, as they are\n * cellb.json this manifest: the format, and the asset paths (a static host cannot list a folder)\n *\n * Platform-neutral: it reads through a `ProjectReader` (Node's fs, `fetch` of a URL, a FilesApi).\n */\nimport type { FilesApi } from \"@statewalker/webrun-files\";\nimport type { AssetFiles } from \"../bindings/assets.js\";\nimport type { WorkersAiOptions } from \"../bindings/workers-ai.js\";\nimport type { CellRuntime } from \"../core/runtime.js\";\nimport { parseJsonc } from \"./jsonc.js\";\nimport type { WranglerConfig } from \"./wrangler.js\";\n\n/** The manifest's file name in a built folder. */\nexport const BUILD_MANIFEST = \"cellb.json\";\n/** The format a built folder declares in its manifest. */\nexport const BUILD_FORMAT = \"cellb-build/1\";\n/** The bundled `main` in a built folder. */\nexport const BUILT_WORKER = \"worker.js\";\n/** The assets directory in a built folder. */\nexport const BUILT_ASSETS = \"assets\";\n\nexport interface BuildManifest {\n format: typeof BUILD_FORMAT;\n /** `worker.js`, or null for a project without `main` (assets only). */\n main: string | null;\n /** The asset files, as paths under `assets/` (\"/index.html\", \"/css/site.css\"). */\n assets: string[];\n}\n\n/** A built project in memory: what `browserProjectRuntime` takes. */\nexport interface BuiltProject {\n config: WranglerConfig;\n /** `main` bundled for a browser realm, or null. */\n code: string | null;\n assets: AssetFiles;\n}\n\n/** Reads the files of a project folder, wherever it lives; `undefined` for a missing file. */\nexport interface ProjectReader {\n bytes(path: string): Promise<Uint8Array | undefined>;\n /** The files under `dir`, as paths relative to it (\"/a/b.html\"); only where the source can list. */\n list?(dir: string): Promise<string[]>;\n}\n\n/** Where `loadProject` finds a project. */\nexport type ProjectSource =\n /** Node: a folder with wrangler.json(c), built or not; browser: the URL of a `cellb build` folder. */\n | string\n | URL\n /** Any FilesApi holding either kind of folder at its root. */\n | FilesApi;\n\n/** Options of `loadProject`, the same on Node and in browsers. */\nexport interface LoadProjectOptions<Bucket = unknown> {\n /**\n * Where cells keep their data. Node: a directory (SQLite files and the project's files under\n * it; default: memory). Browser: an OPFS name, the pool (`<data>`) and the files directory\n * (`<data>-files`) (default: the project's `name`).\n */\n data?: string;\n /** A fleet bucket: a `BrowserBucket` in browsers, a `CellStorage` on Node. */\n bucket?: Bucket;\n /** The OpenAI-compatible endpoint behind the project's `ai` binding (Workers AI). */\n ai?: WorkersAiOptions;\n /** Browser only: an initialized SQLite WASM module (default: loads `@sqlite.org/sqlite-wasm`). */\n sqlite3?: unknown;\n}\n\n/** A running project. */\nexport interface LoadedProject {\n config: WranglerConfig;\n runtime: CellRuntime;\n /** Configuration entries cellb does not run (reported, not silently ignored). */\n unsupported: string[];\n /** A request to the project, as its Worker (and assets) answer it. */\n fetch(req: Request): Promise<Response>;\n close(): Promise<void>;\n}\n\nconst decoder = new TextDecoder();\n\n/** Reads JSON (or JSONC) at `path`, or undefined when the file is missing. */\nexport async function readJson<T>(reader: ProjectReader, path: string): Promise<T | undefined> {\n const bytes = await reader.bytes(path);\n return bytes ? (parseJsonc(decoder.decode(bytes)) as T) : undefined;\n}\n\n/** The manifest of a built folder, or undefined when the folder is not one. */\nexport async function readBuildManifest(reader: ProjectReader): Promise<BuildManifest | undefined> {\n const manifest = await readJson<BuildManifest>(reader, BUILD_MANIFEST);\n if (!manifest) return undefined;\n if (manifest.format !== BUILD_FORMAT)\n throw new Error(`${BUILD_MANIFEST}: unknown format ${JSON.stringify(manifest.format)}`);\n return manifest;\n}\n\n/** Reads a `cellb build` folder: its configuration, its bundled `main` and its assets. */\nexport async function readBuiltProject(\n reader: ProjectReader,\n manifest?: BuildManifest,\n): Promise<BuiltProject> {\n manifest ??= await readBuildManifest(reader);\n if (!manifest) throw new Error(`no ${BUILD_MANIFEST}: not a folder written by \\`cellb build\\``);\n const config = await readJson<WranglerConfig>(reader, \"wrangler.json\");\n if (!config) throw new Error(\"no wrangler.json in the built folder\");\n let code: string | null = null;\n if (manifest.main) {\n const bytes = await reader.bytes(manifest.main);\n if (!bytes) throw new Error(`${manifest.main} is missing from the built folder`);\n code = decoder.decode(bytes);\n }\n const assets: AssetFiles = new Map();\n await Promise.all(\n manifest.assets.map(async (p) => {\n const bytes = await reader.bytes(`${BUILT_ASSETS}${p}`);\n if (!bytes) throw new Error(`${BUILT_ASSETS}${p} is missing from the built folder`);\n assets.set(p, bytes);\n }),\n );\n return { config, code, assets };\n}\n\n/** A reader over a FilesApi, rooted at `root` (\"/\" by default). */\nexport function filesApiReader(files: FilesApi, root = \"/\"): ProjectReader {\n const base = root.endsWith(\"/\") ? root : `${root}/`;\n const at = (p: string) => `${base}${p.replace(/^\\/+/, \"\")}`;\n return {\n async bytes(path) {\n const full = at(path);\n const stats = await files.stats(full);\n if (!stats || stats.kind !== \"file\") return undefined;\n const chunks: Uint8Array[] = [];\n for await (const c of files.read(full)) chunks.push(c);\n return concat(chunks);\n },\n async list(dir) {\n const full = at(dir).replace(/\\/+$/, \"\");\n const out: string[] = [];\n for await (const e of files.list(full, { recursive: true }))\n if (e.kind === \"file\") out.push(e.path.slice(full.length));\n return out;\n },\n };\n}\n\n/** A reader over HTTP: files of the folder at `base` (a URL ending in \"/\"). */\nexport function urlReader(base: URL, fetchFn: typeof fetch = fetch): ProjectReader {\n return {\n async bytes(path) {\n const res = await fetchFn(new URL(path.replace(/^\\/+/, \"\"), base));\n if (res.status === 404) {\n await res.body?.cancel();\n return undefined;\n }\n if (!res.ok) throw new Error(`GET ${new URL(path, base)}: ${res.status} ${res.statusText}`);\n return new Uint8Array(await res.arrayBuffer());\n },\n };\n}\n\n/** Whether `v` is a FilesApi (a source given as files rather than a path or URL). */\nexport function isFilesApi(v: unknown): v is FilesApi {\n return (\n typeof v === \"object\" &&\n v !== null &&\n !(v instanceof URL) &&\n typeof (v as FilesApi).read === \"function\" &&\n typeof (v as FilesApi).list === \"function\" &&\n typeof (v as FilesApi).stats === \"function\"\n );\n}\n\n/** A built project's configuration as `wrangler.json` holds it: `main` and assets renamed. */\nexport function builtConfig(config: WranglerConfig): WranglerConfig {\n const out: WranglerConfig = { ...config };\n if (config.main) out.main = BUILT_WORKER;\n if (config.assets) out.assets = { ...config.assets, directory: BUILT_ASSETS };\n return out;\n}\n\nfunction concat(chunks: Uint8Array[]): Uint8Array {\n if (chunks.length === 1) return chunks[0];\n const out = new Uint8Array(chunks.reduce((n, c) => n + c.length, 0));\n let at = 0;\n for (const c of chunks) {\n out.set(c, at);\n at += c.length;\n }\n return out;\n}\n"]}
@@ -0,0 +1,14 @@
1
+ import type { CellStorage } from "../ports.js";
2
+ import { type LoadedProject, type LoadProjectOptions, type ProjectSource } from "./built-project.js";
3
+ export type NodeLoadProjectOptions = LoadProjectOptions<CellStorage>;
4
+ /**
5
+ * Loads a project and runs it in this process.
6
+ *
7
+ * `source`: a folder with `wrangler.json(c)` (its `main` bundled with esbuild, as
8
+ * `loadNodeProject` does), a folder written by `cellb build` (its `worker.js` imported as built),
9
+ * an `http(s):` URL of a built folder, or a FilesApi holding either kind of folder.
10
+ *
11
+ * `options.data`: a directory for the cells' SQLite files and the project's files
12
+ * (`<data>/files`); without it, both are in memory.
13
+ */
14
+ export declare function loadProject(source: ProjectSource, options?: NodeLoadProjectOptions): Promise<LoadedProject>;