@statewalker/cellb 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +40 -6
  2. package/dist/browser.d.ts +1 -0
  3. package/dist/browser.js.map +1 -1
  4. package/dist/bundle.d.ts +2 -0
  5. package/dist/bundle.js +5 -0
  6. package/dist/bundle.js.map +1 -0
  7. package/dist/core/object-host.d.ts +7 -0
  8. package/dist/core/object-host.js +40 -7
  9. package/dist/core/object-host.js.map +1 -1
  10. package/dist/node-compat/browser-registry.d.ts +1 -0
  11. package/dist/node-compat/browser-registry.js +5 -0
  12. package/dist/node-compat/browser-registry.js.map +1 -1
  13. package/dist/node-compat/util-guard.d.ts +2 -0
  14. package/dist/node-compat/util-guard.js +14 -0
  15. package/dist/node-compat/util-guard.js.map +1 -0
  16. package/dist/project/browser-host.js +2 -2
  17. package/dist/project/browser-host.js.map +1 -1
  18. package/dist/project/browser-load.d.ts +16 -4
  19. package/dist/project/browser-load.js +46 -9
  20. package/dist/project/browser-load.js.map +1 -1
  21. package/dist/project/build.js +2 -2
  22. package/dist/project/build.js.map +1 -1
  23. package/dist/project/bundle-compiler.d.ts +31 -0
  24. package/dist/project/bundle-compiler.js +73 -0
  25. package/dist/project/bundle-compiler.js.map +1 -0
  26. package/dist/project/node-project.js +3 -3
  27. package/dist/project/node-project.js.map +1 -1
  28. package/dist/project/site-compiler.d.ts +67 -0
  29. package/dist/project/site-compiler.js +134 -0
  30. package/dist/project/site-compiler.js.map +1 -0
  31. package/dist/project/source-project.d.ts +46 -0
  32. package/dist/project/source-project.js +45 -0
  33. package/dist/project/source-project.js.map +1 -0
  34. package/dist/project/wrangler.d.ts +4 -0
  35. package/dist/project/wrangler.js +7 -1
  36. package/dist/project/wrangler.js.map +1 -1
  37. package/dist/site.d.ts +2 -0
  38. package/dist/site.js +4 -3
  39. package/dist/site.js.map +1 -1
  40. package/package.json +11 -1
@@ -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;AAE9D,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,EACL,oBAAoB,EACpB,WAAW,EACX,mBAAmB,EACnB,YAAY,GAEb,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,CAAC;AA4G7C,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;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,OAAgB,EAChB,GAAW,EACX,YAAqB,EACrB,KAAqB,EACrB,QAAwD;IAExD,IAAI,GAAsB,CAAC;IAC3B,IAAI,IAA0B,CAAC;IAC/B,IAAI,OAAmB,CAAC;IACxB,IAAI,QAAQ,EAAE,CAAC;QACb,+DAA+D;QAC/D,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC;QACnB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;QAC3B,IAAI,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAClC,OAAO,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC/B,CAAC;SAAM,CAAC;QACN,MAAM,KAAK,GAAG,IAAI,MAAM,CACtB,IAAI,GAAG,CACL,4BAA4B,EAC5B,OAAO,IAAI,CAAC,GAAG,CAChB,CAAC,wCAAwC,EAC1C,EAAE,IAAI,EAAE,QAAQ,EAAE,CACnB,CAAC;QACF,GAAG,GAAG,IAAI,iBAAiB,CAAC,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,4CAA4C;QACzF,2FAA2F;QAC3F,yFAAyF;QACzF,MAAM,KAAK,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAClD,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;gBACtC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,OAAO;oBAAE,OAAO,EAAE,CAAC;qBACjC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,QAAQ;oBAC9B,MAAM,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC,IAAI,CAAC,KAAe,EAAE,CAAC,CAAC,CAAC;YACrE,CAAC,CAAC,CAAC;YACH,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;QAC9F,CAAC,CAAC,CAAC;QACH,6DAA6D;QAC7D,MAAM,QAAQ,GAAG,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3F,IAAI,CAAC;YACH,KAAK,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,QAAQ,CAAC,CAAC;YAC3E,MAAM,KAAK,CAAC;QACd,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,uDAAuD;YAC1E,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,IAAI,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QACnC,OAAO,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;IACpC,CAAC;IACD,MAAM,EAAE,IAAI,EAAE,GAAG,aAAa,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,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;QACP,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,CACb,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,MAAM,CAAC,GAAG,EACf,IAAI,CAAC,MAAM,CAAC,YAAY,EACxB,IAAI,CAAC,MAAM,CAAC,KAAK,EACjB,IAAI,CAAC,MAAM,CAAC,QAAQ,CACrB;QACH,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","sourcesContent":["import { BrowserFilesApi } from \"@statewalker/webrun-files-browser\";\nimport { installLtxVfs } from \"../adapters/ltx-vfs.js\";\nimport {\n sahpoolOpener,\n tuneCellConnection,\n WasmSqliteDriver,\n wasmMemoryOpener,\n} from \"../adapters/wasm-sqlite.js\";\nimport type { AssetFiles } from \"../bindings/assets.js\";\nimport type { WorkersAiOptions } from \"../bindings/workers-ai.js\";\nimport { celldBucket } from \"../bucket/celld-cells.js\";\nimport { idbObjectStore } from \"../bucket/idb-object-store.js\";\nimport { filesApiObjectStore, type ObjectStore } from \"../bucket/object-store.js\";\nimport { s3ObjectStore } from \"../bucket/s3-object-store.js\";\nimport type { CellRuntimeOptions, WorkerModule } from \"../core/runtime.js\";\nimport { browserIsolatedLoader } from \"../isolate/browser.js\";\nimport type { LtxStoreFiles } from \"../ltx/ltx-page-server.js\";\nimport { installAsyncContext } from \"../node-compat/async_hooks.js\";\nimport { installNodeGlobals } from \"../node-compat/install.js\";\nimport { browserModuleLoader } from \"./browser-modules.js\";\nimport * as workersModule from \"./cloudflare-workers.js\";\nimport { siteModuleLoader, workersHostRegistry } from \"./site-loader.js\";\nimport { type WorkerScope, workerScope } from \"./worker-scope.js\";\nimport * as workersGlobals from \"./workers-globals-module.js\";\nimport {\n createProjectRuntime,\n loadTimeEnv,\n populatesProcessEnv,\n processEnvOf,\n type WranglerConfig,\n} from \"./wrangler.js\";\n\nexport { populatesProcessEnv, processEnvOf };\n\n/**\n * Where a browser-hosted project keeps its cells when they must outlive the page or move to\n * other nodes: a celld fleet bucket. Cells, facets and alarms are then exactly celld's\n * (ownership in `own.json`, LTX logs, wake index) and R2 objects live in it too, so the same\n * cells can be served by this browser, by other browsers and by celld nodes, in turn.\n *\n * - `s3`: an S3-compatible bucket, reached directly (the bucket must allow CORS for the page's\n * origin: methods GET/PUT/DELETE/HEAD, request headers `authorization`, `content-type`,\n * `x-amz-*`, `if-match`, `if-none-match`; exposed headers `etag`, `last-modified`,\n * `x-amz-meta-celld-r2`) or through a same-origin proxy (`endpoint` = the proxy,\n * `signAs` = the real endpoint: SigV4 signs the real host and path).\n * - `opfs`: a bucket in this origin's OPFS — persistence without a server. Conditional writes\n * are atomic only within one writer, so one tab or worker at a time should own its cells.\n * - `store`: any ObjectStore.\n */\nexport type BrowserBucket =\n | {\n s3: {\n endpoint: string;\n signAs?: string;\n bucket: string;\n prefix?: string;\n region?: string;\n accessKeyId: string;\n secretAccessKey: string;\n };\n node: string;\n leaseTtlMs?: number;\n }\n | { opfs: string; node: string; leaseTtlMs?: number }\n /**\n * `idb`: a bucket in this origin's IndexedDB (atomic conditional writes across tabs and\n * workers). Cells then run SQLite in memory and persist through the bucket's page-level logs:\n * no OPFS pool, so any number of workers can serve cells at once.\n */\n | { idb: string; node: string; leaseTtlMs?: number }\n /**\n * `ltx`: cells as celld keeps them, LTX files (a snapshot and one file per commit) in an OPFS\n * directory, read page by page (a SQLite VFS over a store worker): no OPFS pool, and a\n * cell's memory is its page cache, not its database. A cell is folded into one snapshot\n * (streamed) past `compactAfter` files (default 64), or once the files after its snapshot hold\n * more than half of it. See docs/browser-host.md.\n */\n | {\n ltx: string;\n node: string;\n leaseTtlMs?: number;\n compactAfter?: number;\n /**\n * The cells' FilesApi in the store worker. A preset on OPFS directory `ltx`: synchronous\n * handles (default, `opfs-sync`), OPFS's asynchronous API (`opfs`), or memory (nothing\n * kept). Or the app's own FilesApi, opened before cellb starts: `{ port }` from\n * `filesApiPort(files)` (served where the app opened it), or `{ module, args }` (built in\n * the store worker). `ltx` then names the storage (the scope of the cells' Web Locks).\n * A port is transferred to the store worker, so it serves one runtime: give each\n * `browserProjectRuntime` a new `filesApiPort`.\n */\n files?: LtxStoreFiles;\n /**\n * A store already running elsewhere (`serveLtxStore(files)`, on the page): no store\n * worker; the VFS sends its reads and commits there. `files` is then ignored. One store\n * per runtime; the app calls its `close()` when the runtime ends.\n */\n ltxStore?: { sab: SharedArrayBuffer; port: MessagePort };\n }\n | { store: ObjectStore; node: string; leaseTtlMs?: number };\n\nexport interface BrowserProjectOptions {\n config: WranglerConfig;\n /**\n * The project's Worker code, imported in this realm once its Workers globals (and with\n * nodejs_compat `Buffer` and `process`) are installed:\n * - `bundle`: one ES module built for browsers (`bundleWorkerForBrowser`), whose\n * `cloudflare:workers` is `PROJECT_WORKERS_MODULE_SHIM` and whose Workers globals read\n * `globalThis.__cellsGlobals`\n * (`null`: the project has no `main`). Worker Loader code becomes Blob-URL modules.\n * - `site`: the base URL of the project's site (`createProjectSite`, hosted by\n * webrun-site-host). `main` and Worker Loader code are imported from it.\n */\n code: { bundle: string | null } | { site: string };\n /**\n * A Dedicated Worker script that serves one loaded Worker (`serveIsolate`): Worker Loader\n * code then runs isolated, one Dedicated Worker per loaded Worker, as celld's isolates.\n * The package ships one: `@statewalker/cellb/isolate-worker`. A function instead starts the\n * Dedicated Worker itself (`() => new Worker(new URL(…, import.meta.url), { type: \"module\" })`,\n * a form bundlers follow).\n */\n isolateScript?: URL | (() => Worker);\n /** An initialized SQLite WASM module (`@sqlite.org/sqlite-wasm`). */\n sqlite3: unknown;\n /** OPFS sahpool name for this host's SQLite files (one pool per worker). */\n pool: string;\n /** OPFS directory for the project's FilesApi (Workers' fs-like bindings, R2 without bucket). */\n filesDir: string;\n assetFiles?: AssetFiles;\n bucket?: BrowserBucket;\n /**\n * Cells this runtime does not host: where to send their events (a `Send` over a MessagePort\n * to the runtime that hosts them, `linkOverPort`), or undefined to host the cell here. With\n * one runtime per worker and `shardOf` as the placement, cells run in parallel threads.\n */\n route?: CellRuntimeOptions[\"route\"];\n /** The OpenAI-compatible endpoint behind the project's `ai` binding (Workers AI). */\n ai?: WorkersAiOptions;\n}\n\nasync function bucketStore(b: BrowserBucket): Promise<ObjectStore> {\n if (\"store\" in b) return b.store;\n if (\"s3\" in b) return s3ObjectStore({ region: \"us-east-1\", ...b.s3 });\n if (\"idb\" in b) return idbObjectStore(b.idb);\n if (\"ltx\" in b) throw new Error(\"an ltx directory is cell storage, not a bucket\");\n const root = await navigator.storage.getDirectory();\n return filesApiObjectStore(\n new BrowserFilesApi({ rootHandle: await root.getDirectoryHandle(b.opfs, { create: true }) }),\n \"\",\n );\n}\n\n/**\n * Cells on the LTX VFS: each cell is a SQLite database whose main file is its LTX files, read\n * page by page (src/adapters/ltx-vfs.ts) from a store: a store worker of this worker's own (on\n * OPFS, memory, or the app's FilesApi through a port or a module), or a store the app runs\n * elsewhere (`ltxStore`).\n */\nexport async function ltxOpener(\n sqlite3: unknown,\n dir: string,\n compactAfter?: number,\n files?: LtxStoreFiles,\n ltxStore?: { sab: SharedArrayBuffer; port: MessagePort },\n) {\n let sab: SharedArrayBuffer;\n let post: (m: unknown) => void;\n let release: () => void;\n if (ltxStore) {\n // The store runs elsewhere (serveLtxStore): only the VFS here.\n sab = ltxStore.sab;\n const port = ltxStore.port;\n post = (m) => port.postMessage(m);\n release = () => port.close();\n } else {\n const store = new Worker(\n new URL(\n \"../ltx/ltx-store-worker.ts\",\n import.meta.url,\n ) /* `.js` in dist/ (scripts/build.mjs) */,\n { type: \"module\" },\n );\n sab = new SharedArrayBuffer(8 + 16 * 65536); // room for a read-ahead run of 64 KiB pages\n // Wait until the store worker runs before any synchronous call: a nested worker is started\n // (its script fetched) through this worker's event loop, which Atomics.wait would block.\n const ready = new Promise<void>((resolve, reject) => {\n store.addEventListener(\"message\", (e) => {\n if (e.data?.op === \"ready\") resolve();\n else if (e.data?.op === \"failed\")\n reject(new Error(`ltx store worker: ${e.data.error as string}`));\n });\n store.addEventListener(\"error\", (e) => reject(new Error(`ltx store worker: ${e.message}`)));\n });\n // A port to the app's FilesApi moves on to the store worker.\n const transfer = files && typeof files === \"object\" && \"port\" in files ? [files.port] : [];\n try {\n store.postMessage({ op: \"init\", sab, dir, compactAfter, files }, transfer);\n await ready;\n } catch (err) {\n store.terminate(); // a store worker that did not start is not left behind\n throw err;\n }\n post = (m) => store.postMessage(m);\n release = () => store.terminate();\n }\n const { name } = installLtxVfs(sqlite3, { sab, post });\n const s3 = sqlite3 as { oo1: { DB: new (o: Record<string, unknown>) => any } };\n const open = (cellKey: string) => {\n const db = new s3.oo1.DB({ filename: cellKey, vfs: name, flags: \"c\" });\n tuneCellConnection(sqlite3, db);\n db.exec(\"PRAGMA journal_mode=MEMORY; PRAGMA synchronous=FULL;\");\n // SQLite's C API for inTransaction() only (no page hook or session capture on this VFS).\n return new WasmSqliteDriver(db, undefined, undefined, (sqlite3 as { capi: never }).capi);\n };\n return Object.assign(open, {\n release,\n reserve: async (n: number) => n,\n });\n}\n\n/** Installs the Workers globals the code reads, then imports its `main`. */\nasync function importWorkerCode(\n config: WranglerConfig,\n code: BrowserProjectOptions[\"code\"],\n scope: WorkerScope,\n): Promise<WorkerModule> {\n const flags = config.compatibility_flags ?? [];\n const nodeCompat = 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(\n opts.sqlite3,\n opts.bucket.ltx,\n opts.bucket.compactAfter,\n opts.bucket.files,\n opts.bucket.ltxStore,\n )\n : opts.bucket && \"idb\" in opts.bucket\n ? Object.assign(wasmMemoryOpener(opts.sqlite3 as never), {\n release() {},\n reserve: async (n: number) => n,\n })\n : await sahpoolOpener(opts.sqlite3 as never, {\n name: opts.pool,\n initialCapacity: 64, // grows on demand (sahpoolOpener)\n });\n const root = await navigator.storage.getDirectory();\n const files = new BrowserFilesApi({\n rootHandle: await root.getDirectoryHandle(opts.filesDir, { create: true }),\n });\n // An `ltx` directory is the cells' own storage (the VFS), not a fleet bucket.\n const store = opts.bucket && !(\"ltx\" in opts.bucket) ? await bucketStore(opts.bucket) : undefined;\n const shared =\n opts.bucket && store\n ? celldBucket(store, { node: opts.bucket.node, leaseTtlMs: opts.bucket.leaseTtlMs })\n : undefined;\n const { runtime, unsupported } = createProjectRuntime(opts.config, module, {\n openSql,\n files,\n assetFiles: opts.assetFiles,\n loadModules: site ? siteModuleLoader(site) : browserModuleLoader(),\n isolatedModules: opts.isolateScript\n ? browserIsolatedLoader({\n isolateScript: opts.isolateScript,\n siteBaseUrl: site,\n storagePrefix: `${opts.pool}-iso`,\n storage: () => shared, // facets of loaded code are logged like the root's own\n })\n : undefined,\n storage: shared, // R2 objects in the fleet bucket too, as celld keeps them\n route: opts.route,\n ai: opts.ai,\n });\n scope.bind(runtime);\n return {\n runtime,\n unsupported,\n bucket: shared,\n close: async () => {\n await runtime.close();\n openSql.release(); // the pool's files, for the next worker that opens it\n },\n };\n}\n"]}
1
+ {"version":3,"file":"browser-host.js","sourceRoot":"","sources":["../../src/project/browser-host.ts"],"names":[],"mappings":"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","sourcesContent":["import { BrowserFilesApi } from \"@statewalker/webrun-files-browser\";\nimport { installLtxVfs } from \"../adapters/ltx-vfs.js\";\nimport {\n sahpoolOpener,\n tuneCellConnection,\n WasmSqliteDriver,\n wasmMemoryOpener,\n} from \"../adapters/wasm-sqlite.js\";\nimport type { AssetFiles } from \"../bindings/assets.js\";\nimport type { WorkersAiOptions } from \"../bindings/workers-ai.js\";\nimport { celldBucket } from \"../bucket/celld-cells.js\";\nimport { idbObjectStore } from \"../bucket/idb-object-store.js\";\nimport { filesApiObjectStore, type ObjectStore } from \"../bucket/object-store.js\";\nimport { s3ObjectStore } from \"../bucket/s3-object-store.js\";\nimport type { CellRuntimeOptions, WorkerModule } from \"../core/runtime.js\";\nimport { browserIsolatedLoader } from \"../isolate/browser.js\";\nimport type { LtxStoreFiles } from \"../ltx/ltx-page-server.js\";\nimport { installAsyncContext } from \"../node-compat/async_hooks.js\";\nimport { installNodeGlobals } from \"../node-compat/install.js\";\nimport { browserModuleLoader } from \"./browser-modules.js\";\nimport * as workersModule from \"./cloudflare-workers.js\";\nimport { siteModuleLoader, workersHostRegistry } from \"./site-loader.js\";\nimport { type WorkerScope, workerScope } from \"./worker-scope.js\";\nimport * as workersGlobals from \"./workers-globals-module.js\";\nimport {\n createProjectRuntime,\n hasNodeCompat,\n loadTimeEnv,\n populatesProcessEnv,\n processEnvOf,\n type WranglerConfig,\n} from \"./wrangler.js\";\n\nexport { populatesProcessEnv, processEnvOf };\n\n/**\n * Where a browser-hosted project keeps its cells when they must outlive the page or move to\n * other nodes: a celld fleet bucket. Cells, facets and alarms are then exactly celld's\n * (ownership in `own.json`, LTX logs, wake index) and R2 objects live in it too, so the same\n * cells can be served by this browser, by other browsers and by celld nodes, in turn.\n *\n * - `s3`: an S3-compatible bucket, reached directly (the bucket must allow CORS for the page's\n * origin: methods GET/PUT/DELETE/HEAD, request headers `authorization`, `content-type`,\n * `x-amz-*`, `if-match`, `if-none-match`; exposed headers `etag`, `last-modified`,\n * `x-amz-meta-celld-r2`) or through a same-origin proxy (`endpoint` = the proxy,\n * `signAs` = the real endpoint: SigV4 signs the real host and path).\n * - `opfs`: a bucket in this origin's OPFS — persistence without a server. Conditional writes\n * are atomic only within one writer, so one tab or worker at a time should own its cells.\n * - `store`: any ObjectStore.\n */\nexport type BrowserBucket =\n | {\n s3: {\n endpoint: string;\n signAs?: string;\n bucket: string;\n prefix?: string;\n region?: string;\n accessKeyId: string;\n secretAccessKey: string;\n };\n node: string;\n leaseTtlMs?: number;\n }\n | { opfs: string; node: string; leaseTtlMs?: number }\n /**\n * `idb`: a bucket in this origin's IndexedDB (atomic conditional writes across tabs and\n * workers). Cells then run SQLite in memory and persist through the bucket's page-level logs:\n * no OPFS pool, so any number of workers can serve cells at once.\n */\n | { idb: string; node: string; leaseTtlMs?: number }\n /**\n * `ltx`: cells as celld keeps them, LTX files (a snapshot and one file per commit) in an OPFS\n * directory, read page by page (a SQLite VFS over a store worker): no OPFS pool, and a\n * cell's memory is its page cache, not its database. A cell is folded into one snapshot\n * (streamed) past `compactAfter` files (default 64), or once the files after its snapshot hold\n * more than half of it. See docs/browser-host.md.\n */\n | {\n ltx: string;\n node: string;\n leaseTtlMs?: number;\n compactAfter?: number;\n /**\n * The cells' FilesApi in the store worker. A preset on OPFS directory `ltx`: synchronous\n * handles (default, `opfs-sync`), OPFS's asynchronous API (`opfs`), or memory (nothing\n * kept). Or the app's own FilesApi, opened before cellb starts: `{ port }` from\n * `filesApiPort(files)` (served where the app opened it), or `{ module, args }` (built in\n * the store worker). `ltx` then names the storage (the scope of the cells' Web Locks).\n * A port is transferred to the store worker, so it serves one runtime: give each\n * `browserProjectRuntime` a new `filesApiPort`.\n */\n files?: LtxStoreFiles;\n /**\n * A store already running elsewhere (`serveLtxStore(files)`, on the page): no store\n * worker; the VFS sends its reads and commits there. `files` is then ignored. One store\n * per runtime; the app calls its `close()` when the runtime ends.\n */\n ltxStore?: { sab: SharedArrayBuffer; port: MessagePort };\n }\n | { store: ObjectStore; node: string; leaseTtlMs?: number };\n\nexport interface BrowserProjectOptions {\n config: WranglerConfig;\n /**\n * The project's Worker code, imported in this realm once its Workers globals (and with\n * nodejs_compat `Buffer` and `process`) are installed:\n * - `bundle`: one ES module built for browsers (`bundleWorkerForBrowser`), whose\n * `cloudflare:workers` is `PROJECT_WORKERS_MODULE_SHIM` and whose Workers globals read\n * `globalThis.__cellsGlobals`\n * (`null`: the project has no `main`). Worker Loader code becomes Blob-URL modules.\n * - `site`: the base URL of the project's site (`createProjectSite`, hosted by\n * webrun-site-host). `main` and Worker Loader code are imported from it.\n */\n code: { bundle: string | null } | { site: string };\n /**\n * A Dedicated Worker script that serves one loaded Worker (`serveIsolate`): Worker Loader\n * code then runs isolated, one Dedicated Worker per loaded Worker, as celld's isolates.\n * The package ships one: `@statewalker/cellb/isolate-worker`. A function instead starts the\n * Dedicated Worker itself (`() => new Worker(new URL(…, import.meta.url), { type: \"module\" })`,\n * a form bundlers follow).\n */\n isolateScript?: URL | (() => Worker);\n /** An initialized SQLite WASM module (`@sqlite.org/sqlite-wasm`). */\n sqlite3: unknown;\n /** OPFS sahpool name for this host's SQLite files (one pool per worker). */\n pool: string;\n /** OPFS directory for the project's FilesApi (Workers' fs-like bindings, R2 without bucket). */\n filesDir: string;\n assetFiles?: AssetFiles;\n bucket?: BrowserBucket;\n /**\n * Cells this runtime does not host: where to send their events (a `Send` over a MessagePort\n * to the runtime that hosts them, `linkOverPort`), or undefined to host the cell here. With\n * one runtime per worker and `shardOf` as the placement, cells run in parallel threads.\n */\n route?: CellRuntimeOptions[\"route\"];\n /** The OpenAI-compatible endpoint behind the project's `ai` binding (Workers AI). */\n ai?: WorkersAiOptions;\n}\n\nasync function bucketStore(b: BrowserBucket): Promise<ObjectStore> {\n if (\"store\" in b) return b.store;\n if (\"s3\" in b) return s3ObjectStore({ region: \"us-east-1\", ...b.s3 });\n if (\"idb\" in b) return idbObjectStore(b.idb);\n if (\"ltx\" in b) throw new Error(\"an ltx directory is cell storage, not a bucket\");\n const root = await navigator.storage.getDirectory();\n return filesApiObjectStore(\n new BrowserFilesApi({ rootHandle: await root.getDirectoryHandle(b.opfs, { create: true }) }),\n \"\",\n );\n}\n\n/**\n * Cells on the LTX VFS: each cell is a SQLite database whose main file is its LTX files, read\n * page by page (src/adapters/ltx-vfs.ts) from a store: a store worker of this worker's own (on\n * OPFS, memory, or the app's FilesApi through a port or a module), or a store the app runs\n * elsewhere (`ltxStore`).\n */\nexport async function ltxOpener(\n sqlite3: unknown,\n dir: string,\n compactAfter?: number,\n files?: LtxStoreFiles,\n ltxStore?: { sab: SharedArrayBuffer; port: MessagePort },\n) {\n let sab: SharedArrayBuffer;\n let post: (m: unknown) => void;\n let release: () => void;\n if (ltxStore) {\n // The store runs elsewhere (serveLtxStore): only the VFS here.\n sab = ltxStore.sab;\n const port = ltxStore.port;\n post = (m) => port.postMessage(m);\n release = () => port.close();\n } else {\n const store = new Worker(\n new URL(\n \"../ltx/ltx-store-worker.ts\",\n import.meta.url,\n ) /* `.js` in dist/ (scripts/build.mjs) */,\n { type: \"module\" },\n );\n sab = new SharedArrayBuffer(8 + 16 * 65536); // room for a read-ahead run of 64 KiB pages\n // Wait until the store worker runs before any synchronous call: a nested worker is started\n // (its script fetched) through this worker's event loop, which Atomics.wait would block.\n const ready = new Promise<void>((resolve, reject) => {\n store.addEventListener(\"message\", (e) => {\n if (e.data?.op === \"ready\") resolve();\n else if (e.data?.op === \"failed\")\n reject(new Error(`ltx store worker: ${e.data.error as string}`));\n });\n store.addEventListener(\"error\", (e) => reject(new Error(`ltx store worker: ${e.message}`)));\n });\n // A port to the app's FilesApi moves on to the store worker.\n const transfer = files && typeof files === \"object\" && \"port\" in files ? [files.port] : [];\n try {\n store.postMessage({ op: \"init\", sab, dir, compactAfter, files }, transfer);\n await ready;\n } catch (err) {\n store.terminate(); // a store worker that did not start is not left behind\n throw err;\n }\n post = (m) => store.postMessage(m);\n release = () => store.terminate();\n }\n const { name } = installLtxVfs(sqlite3, { sab, post });\n const s3 = sqlite3 as { oo1: { DB: new (o: Record<string, unknown>) => any } };\n const open = (cellKey: string) => {\n const db = new s3.oo1.DB({ filename: cellKey, vfs: name, flags: \"c\" });\n tuneCellConnection(sqlite3, db);\n db.exec(\"PRAGMA journal_mode=MEMORY; PRAGMA synchronous=FULL;\");\n // SQLite's C API for inTransaction() only (no page hook or session capture on this VFS).\n return new WasmSqliteDriver(db, undefined, undefined, (sqlite3 as { capi: never }).capi);\n };\n return Object.assign(open, {\n release,\n reserve: async (n: number) => n,\n });\n}\n\n/** Installs the Workers globals the code reads, then imports its `main`. */\nasync function importWorkerCode(\n config: WranglerConfig,\n code: BrowserProjectOptions[\"code\"],\n scope: WorkerScope,\n): Promise<WorkerModule> {\n const flags = config.compatibility_flags ?? [];\n const nodeCompat = hasNodeCompat(config);\n if (nodeCompat) {\n installNodeGlobals();\n // node:* for bundles built with cellbHostModule (another bundler than bundleWorkerForBrowser);\n // loaded after installNodeGlobals(), as the npm `util` polyfill reads `process`.\n (globalThis as Record<string, unknown>).__cellsNodeModules = (\n await import(\"../node-compat/browser-registry.js\")\n ).nodeRegistryEntries;\n if (populatesProcessEnv(config)) {\n const env = processEnvOf(config);\n // The bundle's own `process` reads it when evaluated; a site's modules use this realm's.\n (globalThis as Record<string, unknown>).__cellsProcessEnv = env;\n Object.assign((globalThis as { process: { env: Record<string, string> } }).process.env, env);\n }\n // node:async_hooks: continuations carry their AsyncLocalStorage stores (with AsyncContext\n // the engine does, and this installs nothing). The code's awaits are lowered so that they go\n // through them: by bundleWorkerForBrowser for a bundle, by createProjectSite (nodeCompat) for\n // a site's modules.\n installAsyncContext();\n }\n const globals = {\n ...workersGlobals,\n Request: workersGlobals.CellsRequest,\n Response: workersGlobals.CellsResponse,\n WebSocketPair: flags.includes(\"websocket_standard_binary_type\")\n ? workersGlobals.StandardWebSocketPair\n : workersGlobals.WebSocketPair,\n };\n if (\"site\" in code) {\n workersHostRegistry({\n workersModule,\n projectWorkersModule: {\n ...workersModule,\n env: scope.env,\n exports: scope.exports,\n waitUntil: scope.waitUntil,\n },\n loadedPrefix: `${code.site}loaded/`,\n emailModule: await import(\"./cloudflare-email.js\"),\n ...globals,\n // Loaded on demand, after installNodeGlobals(): the npm `util` polyfill reads `process`\n // when it is imported.\n node: nodeCompat\n ? (await import(\"../node-compat/browser-registry.js\")).nodeRegistryEntries\n : undefined,\n });\n return config.main\n ? await import(/* @vite-ignore */ `${code.site}modules/~/${config.main}`)\n : { default: {} };\n }\n const g = globalThis as Record<string, unknown>;\n g.__cellsWorkersModule = workersModule;\n g.__cellsProjectScope = scope; // `env` and `exports` of the bundle's cloudflare:workers\n g.__cellsGlobals = globals;\n return code.bundle\n ? await import(\n /* @vite-ignore */ URL.createObjectURL(new Blob([code.bundle], { type: \"text/javascript\" }))\n )\n : { default: {} };\n}\n\n/**\n * A project's runtime in this worker: installs the Workers globals, imports the code and\n * builds its Worker Loader; `close()` also releases the node's bucket lease.\n */\nexport async function browserProjectRuntime(opts: BrowserProjectOptions) {\n const scope = workerScope(loadTimeEnv(opts.config, opts.ai));\n const module = await importWorkerCode(opts.config, opts.code, scope);\n const site = \"site\" in opts.code ? opts.code.site : undefined;\n // With an IndexedDB bucket, cells live in memory and in the bucket's logs (no OPFS pool).\n const openSql =\n opts.bucket && \"ltx\" in opts.bucket\n ? await ltxOpener(\n opts.sqlite3,\n opts.bucket.ltx,\n opts.bucket.compactAfter,\n opts.bucket.files,\n opts.bucket.ltxStore,\n )\n : opts.bucket && \"idb\" in opts.bucket\n ? Object.assign(wasmMemoryOpener(opts.sqlite3 as never), {\n release() {},\n reserve: async (n: number) => n,\n })\n : await sahpoolOpener(opts.sqlite3 as never, {\n name: opts.pool,\n initialCapacity: 64, // grows on demand (sahpoolOpener)\n });\n const root = await navigator.storage.getDirectory();\n const files = new BrowserFilesApi({\n rootHandle: await root.getDirectoryHandle(opts.filesDir, { create: true }),\n });\n // An `ltx` directory is the cells' own storage (the VFS), not a fleet bucket.\n const store = opts.bucket && !(\"ltx\" in opts.bucket) ? await bucketStore(opts.bucket) : undefined;\n const shared =\n opts.bucket && store\n ? celldBucket(store, { node: opts.bucket.node, leaseTtlMs: opts.bucket.leaseTtlMs })\n : undefined;\n const { runtime, unsupported } = createProjectRuntime(opts.config, module, {\n openSql,\n files,\n assetFiles: opts.assetFiles,\n loadModules: site ? siteModuleLoader(site) : browserModuleLoader(),\n isolatedModules: opts.isolateScript\n ? browserIsolatedLoader({\n isolateScript: opts.isolateScript,\n siteBaseUrl: site,\n storagePrefix: `${opts.pool}-iso`,\n storage: () => shared, // facets of loaded code are logged like the root's own\n })\n : undefined,\n storage: shared, // R2 objects in the fleet bucket too, as celld keeps them\n route: opts.route,\n ai: opts.ai,\n });\n scope.bind(runtime);\n return {\n runtime,\n unsupported,\n bucket: shared,\n close: async () => {\n await runtime.close();\n openSql.release(); // the pool's files, for the next worker that opens it\n },\n };\n}\n"]}
@@ -1,9 +1,11 @@
1
1
  /**
2
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`.
3
+ * folder written by `cellb build`, or compiles a source folder with the `compile` it is given,
4
+ * and runs it with `browserProjectRuntime`.
4
5
  */
5
6
  import { type BrowserBucket } from "./browser-host.js";
6
7
  import { type LoadedProject, type LoadProjectOptions, type ProjectSource } from "./built-project.js";
8
+ import { type ProjectCompiler } from "./source-project.js";
7
9
  export interface BrowserLoadProjectOptions extends LoadProjectOptions<BrowserBucket> {
8
10
  /**
9
11
  * Where loaded Workers (Worker Loader) run: the package's own isolate worker by default; a
@@ -11,12 +13,22 @@ export interface BrowserLoadProjectOptions extends LoadProjectOptions<BrowserBuc
11
13
  * realm.
12
14
  */
13
15
  isolateScript?: URL | (() => Worker) | false;
16
+ /**
17
+ * How a source folder (`wrangler.jsonc`, `main`, `package.json`, assets) becomes code, for a
18
+ * FilesApi that holds one: `bundleCompiler` (`@statewalker/cellb/bundle`: webrun-bundler and
19
+ * esbuild-wasm, one ES module) or `siteCompiler` (`@statewalker/cellb/site`: modules compiled
20
+ * one by one and served from a ServiceWorker). Without it, only `cellb build` folders load.
21
+ * A folder written by `cellb build` loads as built either way.
22
+ */
23
+ compile?: ProjectCompiler;
14
24
  }
15
25
  /**
16
- * Loads a built project and runs it in this worker.
26
+ * Loads a project and runs it in this worker.
17
27
  *
18
28
  * `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`.
29
+ * worker), or a FilesApi holding one — or, with `options.compile`, a FilesApi holding the
30
+ * project's sources (`wrangler.jsonc` and `main` at its root, `package.json`, assets).
31
+ * `options.data` names the OPFS pool (`<data>`) and the project's files directory
32
+ * (`<data>-files`); it defaults to the project's `name`.
21
33
  */
22
34
  export declare function loadProject(source: ProjectSource, options?: BrowserLoadProjectOptions): Promise<LoadedProject>;
@@ -1,17 +1,21 @@
1
1
  /**
2
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`.
3
+ * folder written by `cellb build`, or compiles a source folder with the `compile` it is given,
4
+ * and runs it with `browserProjectRuntime`.
4
5
  */
5
6
  import { browserProjectRuntime } from "./browser-host.js";
6
7
  import { BUILD_MANIFEST, filesApiReader, isFilesApi, readBuildManifest, readBuiltProject, urlReader, } from "./built-project.js";
8
+ import { hasNodeCompat, readSourceProject, WRANGLER_FILES, } from "./source-project.js";
7
9
  /** The isolate worker this package ships (bundlers follow the `new Worker(new URL(…))` form). */
8
10
  const ownIsolate = () => new Worker(new URL("../isolate/isolate-worker.js", import.meta.url), { type: "module" });
9
11
  /**
10
- * Loads a built project and runs it in this worker.
12
+ * Loads a project and runs it in this worker.
11
13
  *
12
14
  * `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
+ * worker), or a FilesApi holding one — or, with `options.compile`, a FilesApi holding the
16
+ * project's sources (`wrangler.jsonc` and `main` at its root, `package.json`, assets).
17
+ * `options.data` names the OPFS pool (`<data>`) and the project's files directory
18
+ * (`<data>-files`); it defaults to the project's `name`.
15
19
  */
16
20
  export async function loadProject(source, options = {}) {
17
21
  let reader;
@@ -28,15 +32,41 @@ export async function loadProject(source, options = {}) {
28
32
  where = url.href;
29
33
  }
30
34
  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);
35
+ let built;
36
+ let compiled;
37
+ if (manifest)
38
+ built = await readBuiltProject(reader, manifest);
39
+ else if (isFilesApi(source) && options.compile) {
40
+ const project = await readSourceProject(source);
41
+ if (!project)
42
+ throw new Error(`the FilesApi has neither ${BUILD_MANIFEST} nor ${WRANGLER_FILES.join(" nor ")}`);
43
+ const { config } = project;
44
+ compiled = config.main
45
+ ? await options.compile.compile({ files: source, config, nodeCompat: hasNodeCompat(config) })
46
+ : { code: { bundle: null } };
47
+ built = { config, code: null, assets: project.assets ?? new Map() };
48
+ }
49
+ else
50
+ throw new Error(isFilesApi(source)
51
+ ? `${where} has no ${BUILD_MANIFEST}: pass \`compile\` to load a source folder, or load a folder written by \`cellb build\``
52
+ : `${where} has no ${BUILD_MANIFEST}: browsers load folders written by \`cellb build\` by URL (a source folder loads from a FilesApi, with \`compile\`)`);
53
+ try {
54
+ const close = compiled?.close?.bind(compiled);
55
+ const release = close && (() => close());
56
+ return await run(built, compiled?.code ?? { bundle: built.code }, options, release);
57
+ }
58
+ catch (err) {
59
+ await compiled?.close?.().catch(() => { });
60
+ throw err;
61
+ }
62
+ }
63
+ async function run(built, code, options, release) {
34
64
  const data = options.data ?? built.config.name ?? "cellb";
35
65
  const sqlite3 = options.sqlite3 ?? (await defaultSqlite3());
36
66
  const isolateScript = options.isolateScript === false ? undefined : (options.isolateScript ?? ownIsolate);
37
67
  const project = await browserProjectRuntime({
38
68
  config: built.config,
39
- code: { bundle: built.code },
69
+ code,
40
70
  assetFiles: built.assets,
41
71
  sqlite3,
42
72
  pool: data,
@@ -51,7 +81,14 @@ export async function loadProject(source, options = {}) {
51
81
  runtime,
52
82
  unsupported: project.unsupported,
53
83
  fetch: (req) => runtime.fetch(req),
54
- close: project.close,
84
+ close: async () => {
85
+ try {
86
+ await project.close();
87
+ }
88
+ finally {
89
+ await release?.();
90
+ }
91
+ },
55
92
  };
56
93
  }
57
94
  let sqlite3Module;
@@ -1 +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"]}
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`, or compiles a source folder with the `compile` it is given,\n * and runs it with `browserProjectRuntime`.\n */\n\nimport { type BrowserBucket, browserProjectRuntime } from \"./browser-host.js\";\nimport {\n BUILD_MANIFEST,\n type BuiltProject,\n filesApiReader,\n isFilesApi,\n type LoadedProject,\n type LoadProjectOptions,\n type ProjectSource,\n readBuildManifest,\n readBuiltProject,\n urlReader,\n} from \"./built-project.js\";\nimport {\n type CompiledProject,\n hasNodeCompat,\n type ProjectCompiler,\n readSourceProject,\n WRANGLER_FILES,\n} from \"./source-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 * How a source folder (`wrangler.jsonc`, `main`, `package.json`, assets) becomes code, for a\n * FilesApi that holds one: `bundleCompiler` (`@statewalker/cellb/bundle`: webrun-bundler and\n * esbuild-wasm, one ES module) or `siteCompiler` (`@statewalker/cellb/site`: modules compiled\n * one by one and served from a ServiceWorker). Without it, only `cellb build` folders load.\n * A folder written by `cellb build` loads as built either way.\n */\n compile?: ProjectCompiler;\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 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 — or, with `options.compile`, a FilesApi holding the\n * project's sources (`wrangler.jsonc` and `main` at its root, `package.json`, assets).\n * `options.data` names the OPFS pool (`<data>`) and the project's files directory\n * (`<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 let built: BuiltProject;\n let compiled: CompiledProject | undefined;\n if (manifest) built = await readBuiltProject(reader, manifest);\n else if (isFilesApi(source) && options.compile) {\n const project = await readSourceProject(source);\n if (!project)\n throw new Error(\n `the FilesApi has neither ${BUILD_MANIFEST} nor ${WRANGLER_FILES.join(\" nor \")}`,\n );\n const { config } = project;\n compiled = config.main\n ? await options.compile.compile({ files: source, config, nodeCompat: hasNodeCompat(config) })\n : { code: { bundle: null } };\n built = { config, code: null, assets: project.assets ?? new Map() };\n } else\n throw new Error(\n isFilesApi(source)\n ? `${where} has no ${BUILD_MANIFEST}: pass \\`compile\\` to load a source folder, or load a folder written by \\`cellb build\\``\n : `${where} has no ${BUILD_MANIFEST}: browsers load folders written by \\`cellb build\\` by URL (a source folder loads from a FilesApi, with \\`compile\\`)`,\n );\n try {\n const close = compiled?.close?.bind(compiled);\n const release = close && (() => close());\n return await run(built, compiled?.code ?? { bundle: built.code }, options, release);\n } catch (err) {\n await compiled?.close?.().catch(() => {});\n throw err;\n }\n}\n\nasync function run(\n built: BuiltProject,\n code: CompiledProject[\"code\"],\n options: BrowserLoadProjectOptions,\n release?: () => Promise<void>,\n): Promise<LoadedProject> {\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,\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: async () => {\n try {\n await project.close();\n } finally {\n await release?.();\n }\n },\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"]}
@@ -7,6 +7,7 @@ import { dirname, join, resolve } from "node:path";
7
7
  import { bundleWorkerForBrowser } from "./browser-bundle.js";
8
8
  import { BUILD_FORMAT, BUILD_MANIFEST, BUILT_ASSETS, BUILT_WORKER, builtConfig, } from "./built-project.js";
9
9
  import { readAssetDirectory, readWranglerConfig } from "./node-project.js";
10
+ import { hasNodeCompat } from "./wrangler.js";
10
11
  /**
11
12
  * `cellb build`: writes the project in `dir` as a folder any static host serves and
12
13
  * `loadProject` (browser or Node) loads: `wrangler.json`, `worker.js` (`main` bundled for a
@@ -18,8 +19,7 @@ export async function buildProject(dir, outDir, opts = {}) {
18
19
  const config = readWranglerConfig(dir);
19
20
  if (!config.main && !config.assets)
20
21
  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"));
22
+ const nodeCompat = hasNodeCompat(config);
23
23
  const code = config.main
24
24
  ? await bundleWorkerForBrowser(resolve(dir, config.main), {
25
25
  nodeCompat,
@@ -1 +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"]}
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/project/build.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EACL,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,YAAY,EAEZ,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAU9C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAW,EACX,MAAc,EACd,IAAI,GAAwB,EAAE;IAE9B,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACnB,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACzB,MAAM,MAAM,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM;QAChC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI;QACtB,CAAC,CAAC,MAAM,sBAAsB,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE;YACtD,UAAU;YACV,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAC;QACJ,CAAC,CAAC,IAAI,CAAC;IACT,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS;QACrC,CAAC,CAAC,kBAAkB,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC3D,CAAC,CAAC,IAAI,GAAG,EAAsB,CAAC;IAClC,uEAAuE;IACvE,KAAK,MAAM,IAAI,IAAI,CAAC,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,YAAY,CAAC;QAC9E,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAClG,IAAI,IAAI,KAAK,IAAI;QAAE,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,IAAI,CAAC,CAAC;IACnE,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC;QAC7C,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,aAAa,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC5B,CAAC;IACD,MAAM,QAAQ,GAAkB;QAC9B,MAAM,EAAE,YAAY;QACpB,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI;QACzC,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;KAClC,CAAC;IACF,8DAA8D;IAC9D,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IACtF,OAAO,QAAQ,CAAC;AAClB,CAAC","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\";\nimport { hasNodeCompat } from \"./wrangler.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 nodeCompat = hasNodeCompat(config);\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,31 @@
1
+ /**
2
+ * `bundleCompiler`: a project's sources bundled in the browser by webrun-bundler on esbuild-wasm,
3
+ * into one ES module that `browserProjectRuntime({ code: { bundle } })` runs as it runs a built
4
+ * folder's `worker.js`. npm packages come from the project's `node_modules` (in its FilesApi) or
5
+ * the npm registry, at the versions its `package.json` asks for.
6
+ */
7
+ import { type BundleOptions, type PackageStore } from "@statewalker/webrun-bundler";
8
+ import type { ProjectCompiler } from "./source-project.js";
9
+ export interface BundleCompilerOptions {
10
+ /** esbuild-wasm, initialized (`await esbuild.initialize({ wasmURL })`). */
11
+ esbuild: BundleOptions["esbuild"];
12
+ /**
13
+ * Where bare specifiers go. Default: the project's own `node_modules`, then the npm registry.
14
+ * Keep one store for several compiles (`npmPackages()`) and a second build fetches nothing.
15
+ */
16
+ packages?: PackageStore;
17
+ /**
18
+ * Lower `await` to generators, so that AsyncLocalStorage stores follow them (the
19
+ * node:async_hooks polyfill rides on promise continuations). Default: with nodejs_compat, as
20
+ * `cellb build` does; a lowered bundle runs on engines with AsyncContext too.
21
+ */
22
+ lowerAwait?: boolean;
23
+ /** `package.json` `exports` conditions (default: workerd's, `["workerd", "worker", "browser"]`). */
24
+ conditions?: string[];
25
+ }
26
+ /**
27
+ * A compiler for `loadProject(files, { compile })` that bundles `main` and its packages into one
28
+ * ES module. `cloudflare:workers`, `node:*` (nodejs_compat) and the Workers globals come from
29
+ * the runtime (`cellbHostModule`), as in a folder `cellb build` writes.
30
+ */
31
+ export declare function bundleCompiler(options: BundleCompilerOptions): ProjectCompiler;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * `bundleCompiler`: a project's sources bundled in the browser by webrun-bundler on esbuild-wasm,
3
+ * into one ES module that `browserProjectRuntime({ code: { bundle } })` runs as it runs a built
4
+ * folder's `worker.js`. npm packages come from the project's `node_modules` (in its FilesApi) or
5
+ * the npm registry, at the versions its `package.json` asks for.
6
+ */
7
+ import { bundle, chainPackages, nodeModulesPackages, npmPackages, } from "@statewalker/webrun-bundler";
8
+ import { CELLS_GLOBALS_MODULE, cellbHostModule } from "./host-modules.js";
9
+ /** One store per compiler: a second compile of the same project fetches nothing. */
10
+ function defaultPackages() {
11
+ return chainPackages(nodeModulesPackages(), npmPackages());
12
+ }
13
+ /**
14
+ * A compiler for `loadProject(files, { compile })` that bundles `main` and its packages into one
15
+ * ES module. `cloudflare:workers`, `node:*` (nodejs_compat) and the Workers globals come from
16
+ * the runtime (`cellbHostModule`), as in a folder `cellb build` writes.
17
+ */
18
+ export function bundleCompiler(options) {
19
+ const packages = options.packages ?? defaultPackages();
20
+ return {
21
+ kind: "bundle",
22
+ async compile({ files, config, nodeCompat }) {
23
+ if (!config.main)
24
+ return { code: { bundle: null } };
25
+ // `node:*` only with nodejs_compat, which also takes a bare built-in name ("buffer") as one
26
+ // when cellb has a polyfill for it. A `node:*` module without one is a stub that throws when
27
+ // used, as `cellb build` and wrangler's nodejs_compat do (libraries import such modules in
28
+ // code paths a Worker never takes).
29
+ const modules = (spec) => spec.startsWith("node:")
30
+ ? nodeCompat
31
+ ? (cellbHostModule(spec) ?? nodeStub(spec))
32
+ : undefined
33
+ : (cellbHostModule(spec) ??
34
+ (nodeCompat && !spec.includes(":") ? cellbHostModule(`node:${spec}`) : undefined));
35
+ const { code } = await bundle({
36
+ esbuild: options.esbuild,
37
+ files,
38
+ entry: `/${config.main.replace(/^\.?\/+/, "")}`,
39
+ packages,
40
+ modules,
41
+ inject: [CELLS_GLOBALS_MODULE], // Response, WebSocketPair… of the runtime, not the realm's
42
+ conditions: options.conditions ?? ["workerd", "worker", "browser"],
43
+ lowerAwait: options.lowerAwait ?? nodeCompat,
44
+ sourcemap: false,
45
+ // Function names are observable (the npm assert polyfill reports its caller's name as
46
+ // the operator): bundling must not rename them, as in `cellb build`.
47
+ esbuildOptions: { keepNames: true },
48
+ });
49
+ return { code: { bundle: code } };
50
+ },
51
+ };
52
+ }
53
+ /**
54
+ * A Node.js module with no browser polyfill: CommonJS, so that every import links. Its default
55
+ * export answers any member with a function that throws when called (or extended). A named import
56
+ * is undefined (esbuild copies the members of a CommonJS module, and a stub cannot list them), so
57
+ * it fails when used, not when loaded. `cellb build` lists the members from Node itself; a browser
58
+ * cannot.
59
+ */
60
+ function nodeStub(spec) {
61
+ const what = JSON.stringify(spec);
62
+ return [
63
+ `const fail = (key) => { throw new Error(${what} + "." + key + " is not available in browsers (nodejs_compat)"); };`,
64
+ "module.exports = new Proxy(Object.create(null), {",
65
+ " get(target, key) {",
66
+ ' if (typeof key === "symbol" || key === "then" || key === "__esModule") return undefined;',
67
+ " if (!(key in target)) target[key] = function () { fail(String(key)); };",
68
+ " return target[key];",
69
+ " },",
70
+ "});",
71
+ ].join("\n");
72
+ }
73
+ //# sourceMappingURL=bundle-compiler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle-compiler.js","sourceRoot":"","sources":["../../src/project/bundle-compiler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAEL,MAAM,EACN,aAAa,EACb,mBAAmB,EACnB,WAAW,GAEZ,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAqB1E,oFAAoF;AACpF,SAAS,eAAe;IACtB,OAAO,aAAa,CAAC,mBAAmB,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,OAA8B;IAC3D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,eAAe,EAAE,CAAC;IACvD,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,KAAK,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE;YACzC,IAAI,CAAC,MAAM,CAAC,IAAI;gBAAE,OAAO,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;YACpD,4FAA4F;YAC5F,6FAA6F;YAC7F,2FAA2F;YAC3F,oCAAoC;YACpC,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,EAAE,CAC/B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;gBACtB,CAAC,CAAC,UAAU;oBACV,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;oBAC3C,CAAC,CAAC,SAAS;gBACb,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC;oBACtB,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;YACzF,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC;gBAC5B,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,KAAK;gBACL,KAAK,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,EAAE;gBAC/C,QAAQ;gBACR,OAAO;gBACP,MAAM,EAAE,CAAC,oBAAoB,CAAC,EAAE,2DAA2D;gBAC3F,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAC;gBAClE,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,UAAU;gBAC5C,SAAS,EAAE,KAAK;gBAChB,sFAAsF;gBACtF,qEAAqE;gBACrE,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;aACpC,CAAC,CAAC;YACH,OAAO,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;QACpC,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,QAAQ,CAAC,IAAY;IAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAClC,OAAO;QACL,2CAA2C,IAAI,qEAAqE;QACpH,mDAAmD;QACnD,sBAAsB;QACtB,8FAA8F;QAC9F,6EAA6E;QAC7E,yBAAyB;QACzB,MAAM;QACN,KAAK;KACN,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC","sourcesContent":["/**\n * `bundleCompiler`: a project's sources bundled in the browser by webrun-bundler on esbuild-wasm,\n * into one ES module that `browserProjectRuntime({ code: { bundle } })` runs as it runs a built\n * folder's `worker.js`. npm packages come from the project's `node_modules` (in its FilesApi) or\n * the npm registry, at the versions its `package.json` asks for.\n */\nimport {\n type BundleOptions,\n bundle,\n chainPackages,\n nodeModulesPackages,\n npmPackages,\n type PackageStore,\n} from \"@statewalker/webrun-bundler\";\nimport { CELLS_GLOBALS_MODULE, cellbHostModule } from \"./host-modules.js\";\nimport type { ProjectCompiler } from \"./source-project.js\";\n\nexport interface BundleCompilerOptions {\n /** esbuild-wasm, initialized (`await esbuild.initialize({ wasmURL })`). */\n esbuild: BundleOptions[\"esbuild\"];\n /**\n * Where bare specifiers go. Default: the project's own `node_modules`, then the npm registry.\n * Keep one store for several compiles (`npmPackages()`) and a second build fetches nothing.\n */\n packages?: PackageStore;\n /**\n * Lower `await` to generators, so that AsyncLocalStorage stores follow them (the\n * node:async_hooks polyfill rides on promise continuations). Default: with nodejs_compat, as\n * `cellb build` does; a lowered bundle runs on engines with AsyncContext too.\n */\n lowerAwait?: boolean;\n /** `package.json` `exports` conditions (default: workerd's, `[\"workerd\", \"worker\", \"browser\"]`). */\n conditions?: string[];\n}\n\n/** One store per compiler: a second compile of the same project fetches nothing. */\nfunction defaultPackages(): PackageStore {\n return chainPackages(nodeModulesPackages(), npmPackages());\n}\n\n/**\n * A compiler for `loadProject(files, { compile })` that bundles `main` and its packages into one\n * ES module. `cloudflare:workers`, `node:*` (nodejs_compat) and the Workers globals come from\n * the runtime (`cellbHostModule`), as in a folder `cellb build` writes.\n */\nexport function bundleCompiler(options: BundleCompilerOptions): ProjectCompiler {\n const packages = options.packages ?? defaultPackages();\n return {\n kind: \"bundle\",\n async compile({ files, config, nodeCompat }) {\n if (!config.main) return { code: { bundle: null } };\n // `node:*` only with nodejs_compat, which also takes a bare built-in name (\"buffer\") as one\n // when cellb has a polyfill for it. A `node:*` module without one is a stub that throws when\n // used, as `cellb build` and wrangler's nodejs_compat do (libraries import such modules in\n // code paths a Worker never takes).\n const modules = (spec: string) =>\n spec.startsWith(\"node:\")\n ? nodeCompat\n ? (cellbHostModule(spec) ?? nodeStub(spec))\n : undefined\n : (cellbHostModule(spec) ??\n (nodeCompat && !spec.includes(\":\") ? cellbHostModule(`node:${spec}`) : undefined));\n const { code } = await bundle({\n esbuild: options.esbuild,\n files,\n entry: `/${config.main.replace(/^\\.?\\/+/, \"\")}`,\n packages,\n modules,\n inject: [CELLS_GLOBALS_MODULE], // Response, WebSocketPair… of the runtime, not the realm's\n conditions: options.conditions ?? [\"workerd\", \"worker\", \"browser\"],\n lowerAwait: options.lowerAwait ?? nodeCompat,\n sourcemap: false,\n // Function names are observable (the npm assert polyfill reports its caller's name as\n // the operator): bundling must not rename them, as in `cellb build`.\n esbuildOptions: { keepNames: true },\n });\n return { code: { bundle: code } };\n },\n };\n}\n\n/**\n * A Node.js module with no browser polyfill: CommonJS, so that every import links. Its default\n * export answers any member with a function that throws when called (or extended). A named import\n * is undefined (esbuild copies the members of a CommonJS module, and a stub cannot list them), so\n * it fails when used, not when loaded. `cellb build` lists the members from Node itself; a browser\n * cannot.\n */\nfunction nodeStub(spec: string): string {\n const what = JSON.stringify(spec);\n return [\n `const fail = (key) => { throw new Error(${what} + \".\" + key + \" is not available in browsers (nodejs_compat)\"); };`,\n \"module.exports = new Proxy(Object.create(null), {\",\n \" get(target, key) {\",\n ' if (typeof key === \"symbol\" || key === \"then\" || key === \"__esModule\") return undefined;',\n \" if (!(key in target)) target[key] = function () { fail(String(key)); };\",\n \" return target[key];\",\n \" },\",\n \"});\",\n ].join(\"\\n\");\n}\n"]}
@@ -12,10 +12,10 @@ import * as workersClasses from "./cloudflare-workers.js";
12
12
  import { parseJsonc } from "./jsonc.js";
13
13
  import { ownModule } from "./own-module.js";
14
14
  import { workerScope } from "./worker-scope.js";
15
- import { createProjectRuntime, loadTimeEnv, } from "./wrangler.js";
15
+ import { createProjectRuntime, hasNodeCompat, loadTimeEnv, WRANGLER_FILES, } from "./wrangler.js";
16
16
  /** Reads `wrangler.jsonc` / `wrangler.json` of a project directory (celld reads the same files). */
17
17
  export function readWranglerConfig(dir) {
18
- for (const name of ["wrangler.jsonc", "wrangler.json"]) {
18
+ for (const name of WRANGLER_FILES) {
19
19
  const p = join(dir, name);
20
20
  if (existsSync(p))
21
21
  return parseJsonc(readFileSync(p, "utf8"));
@@ -203,7 +203,7 @@ export async function loadNodeProject(dir, host) {
203
203
  if (!config.main && !config.assets)
204
204
  throw new Error("wrangler config has neither `main` nor `assets`");
205
205
  const flags = config.compatibility_flags ?? [];
206
- const nodeCompat = flags.some((f) => f.startsWith("nodejs_compat"));
206
+ const nodeCompat = hasNodeCompat(config);
207
207
  const standardBinaryType = flags.includes("websocket_standard_binary_type");
208
208
  // The module reads `env` from `cloudflare:workers` while it is evaluated, before the
209
209
  // runtime exists: until then the scope holds the configuration's vars (and `ai`).