@nimbus-sh/worker 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/README.md +2 -2
  2. package/dist/cirrus-npm-cjs.generated.d.ts +1 -1
  3. package/dist/cirrus-npm-cjs.generated.js +1 -1
  4. package/dist/facets/cirrus-real.d.ts.map +1 -1
  5. package/dist/facets/cirrus-real.js +6 -5
  6. package/dist/facets/compose.d.ts +148 -0
  7. package/dist/facets/compose.d.ts.map +1 -0
  8. package/dist/facets/compose.js +146 -0
  9. package/dist/facets/durable-images.d.ts +9 -5
  10. package/dist/facets/durable-images.d.ts.map +1 -1
  11. package/dist/facets/durable-images.js +17 -7
  12. package/dist/facets/esbuild-bundle-pool.d.ts +49 -0
  13. package/dist/facets/esbuild-bundle-pool.d.ts.map +1 -0
  14. package/dist/facets/esbuild-bundle-pool.js +122 -0
  15. package/dist/facets/exec-telemetry.d.ts +8 -0
  16. package/dist/facets/exec-telemetry.d.ts.map +1 -1
  17. package/dist/facets/manager.d.ts +240 -109
  18. package/dist/facets/manager.d.ts.map +1 -1
  19. package/dist/facets/manager.js +677 -342
  20. package/dist/facets/process.d.ts +20 -16
  21. package/dist/facets/process.d.ts.map +1 -1
  22. package/dist/facets/process.js +59 -28
  23. package/dist/facets/real-vite-fs-shim.js +2 -2
  24. package/dist/facets/real-vite-hmr.d.ts +3 -1
  25. package/dist/facets/real-vite-hmr.d.ts.map +1 -1
  26. package/dist/facets/real-vite-hmr.js +18 -8
  27. package/dist/facets/vite-dev-server.d.ts +25 -47
  28. package/dist/facets/vite-dev-server.d.ts.map +1 -1
  29. package/dist/facets/vite-dev-server.js +185 -219
  30. package/dist/facets/wasm-image-digest.d.ts +25 -0
  31. package/dist/facets/wasm-image-digest.d.ts.map +1 -0
  32. package/dist/facets/wasm-image-digest.js +25 -0
  33. package/dist/facets/wasm-swap-registry.d.ts +51 -92
  34. package/dist/facets/wasm-swap-registry.d.ts.map +1 -1
  35. package/dist/facets/wasm-swap-registry.js +68 -227
  36. package/dist/facets/ws-terminal.d.ts +9 -31
  37. package/dist/facets/ws-terminal.d.ts.map +1 -1
  38. package/dist/facets/ws-terminal.js +58 -51
  39. package/dist/git/network-facet.d.ts.map +1 -1
  40. package/dist/git/network-facet.js +6 -5
  41. package/dist/hosted/commands.d.ts +12 -0
  42. package/dist/hosted/commands.d.ts.map +1 -0
  43. package/dist/hosted/commands.js +1658 -0
  44. package/dist/hosted/runtime.d.ts +114 -0
  45. package/dist/hosted/runtime.d.ts.map +1 -0
  46. package/dist/hosted/runtime.js +288 -0
  47. package/dist/hosted/services.d.ts +40 -0
  48. package/dist/hosted/services.d.ts.map +1 -0
  49. package/dist/hosted/services.js +512 -0
  50. package/dist/loaders/child-process/spawn-pool.d.ts +3 -2
  51. package/dist/loaders/child-process/spawn-pool.d.ts.map +1 -1
  52. package/dist/loaders/child-process/spawn-pool.js +3 -2
  53. package/dist/loaders/generated-workers.d.ts +2 -2
  54. package/dist/loaders/generated-workers.d.ts.map +1 -1
  55. package/dist/loaders/generated-workers.js +3 -3
  56. package/dist/loaders/npm-resolve-preamble.d.ts +3 -6
  57. package/dist/loaders/npm-resolve-preamble.d.ts.map +1 -1
  58. package/dist/loaders/npm-resolve-preamble.js +34 -108
  59. package/dist/node-shims-artifact.generated.js +3 -3
  60. package/dist/npm/install-batch-facet.d.ts +3 -2
  61. package/dist/npm/install-batch-facet.d.ts.map +1 -1
  62. package/dist/npm/install-batch-facet.js +45 -15
  63. package/dist/npm/installer.d.ts +22 -17
  64. package/dist/npm/installer.d.ts.map +1 -1
  65. package/dist/npm/installer.js +209 -193
  66. package/dist/npm/pre-bundle-facet.d.ts +1 -1
  67. package/dist/npm/pre-bundle-facet.d.ts.map +1 -1
  68. package/dist/npm/pre-bundle-facet.js +1 -1
  69. package/dist/npm/resolve-facet.d.ts +6 -0
  70. package/dist/npm/resolve-facet.d.ts.map +1 -1
  71. package/dist/npm/resolve-one-facet.d.ts +21 -20
  72. package/dist/npm/resolve-one-facet.d.ts.map +1 -1
  73. package/dist/npm/resolve-one-facet.js +85 -84
  74. package/dist/npm/semver.d.ts +59 -0
  75. package/dist/npm/semver.d.ts.map +1 -0
  76. package/dist/npm/semver.js +226 -0
  77. package/dist/router/remote-api.js +31 -1
  78. package/dist/runtime/bash-repl.d.ts +1 -1
  79. package/dist/runtime/bash-repl.d.ts.map +1 -1
  80. package/dist/runtime/bash-repl.js +38 -4
  81. package/dist/runtime/bun-runner.js +1 -1
  82. package/dist/runtime/html-entrypoint.d.ts +7 -0
  83. package/dist/runtime/html-entrypoint.d.ts.map +1 -1
  84. package/dist/runtime/html-entrypoint.js +18 -2
  85. package/dist/runtime/node-runner.d.ts +4 -1
  86. package/dist/runtime/node-runner.d.ts.map +1 -1
  87. package/dist/runtime/node-runner.js +9 -2
  88. package/dist/runtime/node-shims.d.ts.map +1 -1
  89. package/dist/runtime/node-shims.js +305 -29
  90. package/dist/runtime/opencode-facet-runner.js +16 -16
  91. package/dist/runtime/package-manager.d.ts +35 -122
  92. package/dist/runtime/package-manager.d.ts.map +1 -1
  93. package/dist/runtime/package-manager.js +61 -596
  94. package/dist/runtime/process-logs-api.d.ts +1 -1
  95. package/dist/runtime/process-logs-api.d.ts.map +1 -1
  96. package/dist/runtime/process-logs-api.js +1 -1
  97. package/dist/runtime/python-repl.d.ts +2 -1
  98. package/dist/runtime/python-repl.d.ts.map +1 -1
  99. package/dist/runtime/python-repl.js +82 -59
  100. package/dist/runtime/repl-session.d.ts +9 -47
  101. package/dist/runtime/repl-session.d.ts.map +1 -1
  102. package/dist/runtime/repl-session.js +105 -105
  103. package/dist/runtime/runtime-catalog.d.ts +13 -0
  104. package/dist/runtime/runtime-catalog.d.ts.map +1 -1
  105. package/dist/runtime/runtime-catalog.js +88 -0
  106. package/dist/session/agent.d.ts +1 -21
  107. package/dist/session/agent.d.ts.map +1 -1
  108. package/dist/session/ai.d.ts +5 -1
  109. package/dist/session/ai.d.ts.map +1 -1
  110. package/dist/session/ai.js +7 -0
  111. package/dist/session/helpers.d.ts +38 -0
  112. package/dist/session/helpers.d.ts.map +1 -1
  113. package/dist/session/helpers.js +76 -0
  114. package/dist/session/hibernation.d.ts +2 -1
  115. package/dist/session/hibernation.d.ts.map +1 -1
  116. package/dist/session/hibernation.js +7 -4
  117. package/dist/session/init-phases.d.ts +1 -1
  118. package/dist/session/init-phases.d.ts.map +1 -1
  119. package/dist/session/init-phases.js +2 -12
  120. package/dist/session/init.d.ts +15 -36
  121. package/dist/session/init.d.ts.map +1 -1
  122. package/dist/session/init.js +50 -2327
  123. package/dist/session/loopback.d.ts +2 -29
  124. package/dist/session/loopback.d.ts.map +1 -1
  125. package/dist/session/loopback.js +3 -27
  126. package/dist/session/nimbus-session.d.ts +77 -34
  127. package/dist/session/nimbus-session.d.ts.map +1 -1
  128. package/dist/session/nimbus-session.js +126 -514
  129. package/dist/session/npm-install-port.d.ts +18 -0
  130. package/dist/session/npm-install-port.d.ts.map +1 -0
  131. package/dist/session/npm-install-port.js +37 -0
  132. package/dist/session/port-capability.d.ts +44 -0
  133. package/dist/session/port-capability.d.ts.map +1 -1
  134. package/dist/session/port-capability.js +110 -0
  135. package/dist/session/programmatic.d.ts +36 -43
  136. package/dist/session/programmatic.d.ts.map +1 -1
  137. package/dist/session/programmatic.js +109 -115
  138. package/dist/session/routes.d.ts +30 -17
  139. package/dist/session/routes.d.ts.map +1 -1
  140. package/dist/session/routes.js +42 -131
  141. package/dist/session/rpc.d.ts +15 -15
  142. package/dist/session/rpc.d.ts.map +1 -1
  143. package/dist/session/rpc.js +98 -49
  144. package/dist/session/serving-port.d.ts +27 -0
  145. package/dist/session/serving-port.d.ts.map +1 -0
  146. package/dist/session/serving-port.js +27 -0
  147. package/dist/session/start-real-vite.d.ts +12 -0
  148. package/dist/session/start-real-vite.d.ts.map +1 -1
  149. package/dist/session/start-real-vite.js +4 -4
  150. package/dist/session/supervisor-op.d.ts +4 -4
  151. package/dist/session/supervisor-op.d.ts.map +1 -1
  152. package/dist/session/supervisor-op.js +24 -10
  153. package/dist/session/supervisor-rpc.d.ts +7 -7
  154. package/dist/session/supervisor-rpc.d.ts.map +1 -1
  155. package/dist/session/supervisor-rpc.js +4 -0
  156. package/dist/session/vite-command.d.ts +18 -0
  157. package/dist/session/vite-command.d.ts.map +1 -0
  158. package/dist/session/vite-command.js +609 -0
  159. package/dist/session/ws.d.ts +61 -0
  160. package/dist/session/ws.d.ts.map +1 -1
  161. package/dist/session/ws.js +122 -12
  162. package/dist/shell/npm-bin-entrypoints.d.ts +0 -35
  163. package/dist/shell/npm-bin-entrypoints.d.ts.map +1 -1
  164. package/dist/shell/npm-bin-entrypoints.js +12 -85
  165. package/dist/workspace-host.d.ts +6 -0
  166. package/dist/workspace-host.d.ts.map +1 -0
  167. package/dist/workspace-host.js +5 -0
  168. package/dist/workspace.d.ts +2 -0
  169. package/dist/workspace.d.ts.map +1 -0
  170. package/dist/workspace.js +1 -0
  171. package/package.json +34 -9
  172. package/public/_assets/runtime/{node-shims-9e1380d9ee430fcc.js → node-shims-8f8c64edd2a1f0f5.js} +305 -29
  173. package/public/index.html +1 -1
  174. package/scripts/bundle-facet-workers.mjs +1 -1
  175. package/scripts/bundle-npm-cjs.mjs +2 -2
  176. package/dist/facets/on-demand-bundle-gate.d.ts +0 -65
  177. package/dist/facets/on-demand-bundle-gate.d.ts.map +0 -1
  178. package/dist/facets/on-demand-bundle-gate.js +0 -125
  179. package/dist/npm/install-args.d.ts +0 -21
  180. package/dist/npm/install-args.d.ts.map +0 -1
  181. package/dist/npm/install-args.js +0 -70
  182. package/dist/npm/npm-log.d.ts +0 -31
  183. package/dist/npm/npm-log.d.ts.map +0 -1
  184. package/dist/npm/npm-log.js +0 -51
package/README.md CHANGED
@@ -216,8 +216,8 @@ config })`. The route requires a valid Nimbus JWT and `sandbox:use` scope.
216
216
  For an app server, start the process and expose its virtual port:
217
217
 
218
218
  ```ts
219
- await box.files.write('/home/user/app/server.js', serverSource);
220
- const proc = await box.startProcess('node --watch /home/user/app/server.js');
219
+ await box.files.write('/home/user/example-app/server.js', serverSource);
220
+ const proc = await box.startProcess('node --watch /home/user/example-app/server.js');
221
221
  const port = await box.ports.expose(3000);
222
222
  // proc.pid is live immediately: box.processes.logs(proc.pid) streams output,
223
223
  // box.processes.kill(proc.pid) stops it
@@ -6,7 +6,7 @@
6
6
  * (react, react-dom, scheduler). Ships as a static Worker asset alongside
7
7
  * cirrus-plugin-react.
8
8
  * Consumed by src/cirrus-real.ts — injected as LOADER modules, and
9
- * the Vite resolver's output (e.g. /home/user/app/node_modules/react/index.js)
9
+ * the Vite resolver's output (e.g. /home/user/example-app/node_modules/react/index.js)
10
10
  * is rewritten to point at one of these bundles at request time.
11
11
  */
12
12
  import { type AssetsFetcher } from '@nimbus-sh/core/runtime/assets-loader.js';
@@ -6,7 +6,7 @@
6
6
  * (react, react-dom, scheduler). Ships as a static Worker asset alongside
7
7
  * cirrus-plugin-react.
8
8
  * Consumed by src/cirrus-real.ts — injected as LOADER modules, and
9
- * the Vite resolver's output (e.g. /home/user/app/node_modules/react/index.js)
9
+ * the Vite resolver's output (e.g. /home/user/example-app/node_modules/react/index.js)
10
10
  * is rewritten to point at one of these bundles at request time.
11
11
  */
12
12
  import { loadAssetText } from '@nimbus-sh/core/runtime/assets-loader.js';
@@ -1 +1 @@
1
- {"version":3,"file":"cirrus-real.d.ts","sourceRoot":"","sources":["../../src/facets/cirrus-real.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAyBH,OAAO,EACL,SAAS,EAIV,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAmB,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAEpF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AAmBtF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IACrD,UAAU,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,WAAW,GAAG,mBAAmB,CAAC,GAAG,SAAS,CAAC;CACpF,GAAG,OAAO,CAiBV;AA0cD,qBAAa,UAAU;IACrB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,gBAAgB,CAAgB;IACxC,OAAO,CAAC,mBAAmB,CAAyB;IAEpD,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,GAAG,CAAa;IACxB,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,UAAU,CAAa;IAC/B;6BACyB;IACzB,OAAO,CAAC,UAAU,CAAuB;IACzC;;;;;;;;OAQG;IACH,OAAO,CAAC,KAAK,CAAgD;IAC7D;;;;4CAIwC;IACxC,OAAO,CAAC,gBAAgB,CAAa;IACrC;2BACuB;IACvB,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,cAAc,CAON;IAEhB,kEAAkE;IAC3D,GAAG,EAAE,SAAS,CAAmB;IAExC,6CAA6C;IAC7C,OAAO,CAAC,SAAS,CAA6B;gBAElC,IAAI,EAAE;QAChB,GAAG,EAAE,GAAG,CAAC;QACT,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,EAAE,SAAS,CAAC;QACf,SAAS,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;QACnC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAC9C;IAWD,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,IAAI,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgBnC;IAED;;;iEAG6D;IAC7D,OAAO,CAAC,YAAY,CAAc;IAE5B,KAAK,CAAC,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmQhE,IAAI,CAAC,GAAG,CAAC,EAAE,kBAAkB,GAAG,IAAI;IAqBpC;;;;OAIG;IACH,eAAe,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM;IAItC,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIjC,uBAAuB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAItD;;;;OAIG;IACG,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IA8C1E;;;;;;OAMG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAsBzD"}
1
+ {"version":3,"file":"cirrus-real.d.ts","sourceRoot":"","sources":["../../src/facets/cirrus-real.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAyBH,OAAO,EACL,SAAS,EAIV,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAmB,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAEpF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AAmBtF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IACrD,UAAU,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,WAAW,GAAG,mBAAmB,CAAC,GAAG,SAAS,CAAC;CACpF,GAAG,OAAO,CAiBV;AA0cD,qBAAa,UAAU;IACrB,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,gBAAgB,CAAgB;IACxC,OAAO,CAAC,mBAAmB,CAAyB;IAEpD,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,GAAG,CAAa;IACxB,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,UAAU,CAAa;IAC/B;6BACyB;IACzB,OAAO,CAAC,UAAU,CAAuB;IACzC;;;;;;;;OAQG;IACH,OAAO,CAAC,KAAK,CAAgD;IAC7D;;;;4CAIwC;IACxC,OAAO,CAAC,gBAAgB,CAAa;IACrC;2BACuB;IACvB,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,cAAc,CAON;IAEhB,kEAAkE;IAC3D,GAAG,EAAE,SAAS,CAAmB;IAExC,6CAA6C;IAC7C,OAAO,CAAC,SAAS,CAA6B;gBAElC,IAAI,EAAE;QAChB,GAAG,EAAE,GAAG,CAAC;QACT,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,EAAE,SAAS,CAAC;QACf,SAAS,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;QACnC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAC9C;IAWD,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,IAAI,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgBnC;IAED;;;iEAG6D;IAC7D,OAAO,CAAC,YAAY,CAAc;IAE5B,KAAK,CAAC,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoQhE,IAAI,CAAC,GAAG,CAAC,EAAE,kBAAkB,GAAG,IAAI;IAqBpC;;;;OAIG;IACH,eAAe,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM;IAItC,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIjC,uBAAuB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAItD;;;;OAIG;IACG,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IA8C1E;;;;;;OAMG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAsBzD"}
@@ -741,11 +741,12 @@ export class CirrusReal {
741
741
  // [D'.1] Spawn cirrus-real as a DO Facet, not a Worker.
742
742
  //
743
743
  // Step A: LOADER.get(stableId, configCb) → DynamicWorker stub. The
744
- // stable ID per-(supervisor-DO + cirrus-real-version) makes the
744
+ // stable ID per-(supervisor-DO + cirrus-real-version + pid) makes the
745
745
  // loader cache the bundled vite + plugin code across hibernation.
746
- // Two restarts within the same supervisor isolate hit the warm
747
- // cache; a different DO ID gets a fresh slot.
748
- //
746
+ // The pid is in the key because env.SUPERVISOR bakes it — a wake
747
+ // strides pids, and a warm worker credentialed to the dead pid
748
+ // would fail every supervisor RPC with "process pid … does not
749
+ // exist". Two restarts on the same pid hit the warm cache.
749
750
  // Step B: worker.getDurableObjectClass('CirrusRealVite') → the
750
751
  // class constructor from the dynamic worker's exports. Same
751
752
  // pattern facet-manager.ts uses for NodeProcess.
@@ -756,7 +757,7 @@ export class CirrusReal {
756
757
  // DO so eviction is coherent. The same name returns the same
757
758
  // facet on subsequent calls — that's what makes the cookie
758
759
  // persist across supervisor reconnects.
759
- const stableLoaderId = `${ctx.id.toString()}:cirrus-real-vite:${REAL_VITE_VERSION}`;
760
+ const stableLoaderId = `${ctx.id.toString()}:cirrus-real-vite:${REAL_VITE_VERSION}:${pid}`;
760
761
  const facetName = 'cirrus-real-vite';
761
762
  try {
762
763
  const worker = this.env.LOADER.get(stableLoaderId, async () => ({
@@ -0,0 +1,148 @@
1
+ /**
2
+ * facets/compose.ts — the one composition of a FacetManager.
3
+ *
4
+ * A FacetManager is the session's spawn path for every resident process —
5
+ * `spawnWorker`, `spawnNode`, the launch journal, `_redrive`, cold-start
6
+ * recovery and the paced launch pump — and until this module it was
7
+ * constructed in exactly one place, inside NimbusSession, with hooks that
8
+ * closed over the session. An embedder that composes NimbusWorkspace as a
9
+ * library over its own Durable Object has no session and must not boot one
10
+ * over its filesystem (a second process table hands out pids whose write
11
+ * authority the filesystem already revoked), so everything behind the
12
+ * manager was closed to it.
13
+ *
14
+ * `composeFacetManager` is that construction, taking exactly what an
15
+ * embedder can supply: the Durable Object's ctx and env, its process
16
+ * supervisor, port registry and SQLite filesystem, an optional shared
17
+ * esbuild service, and the hooks a host has to answer. NimbusSession's own
18
+ * `ensureFacetManager` calls this same factory — there is one path — and
19
+ * keeps only what is session-specific (terminal writes, scrollback notices,
20
+ * the alarm that grants launch turns) inside its hook implementations.
21
+ *
22
+ * What the factory owns and the host does not:
23
+ *
24
+ * - `transformLargeEsm`: the isolated esbuild transform for module text
25
+ * past the in-isolate size bound. It needs `env.LOADER`, `env.ASSETS`
26
+ * and `ctx.facets` and nothing of any host, so it is the factory's
27
+ * default rather than every host's copy.
28
+ * - `resolveWorkerLaunchFallback`: the durable image-store resolver a
29
+ * self-owned worker launch (the session's python/ruby residents, or an
30
+ * embedder spawn that let the manager persist its image) re-drives
31
+ * from. It needs only the filesystem. An embedder that keeps its own
32
+ * content store answers `resolveWorkerLaunch` and this is never reached
33
+ * for its recipes (see `WorkerRecipe.resident`).
34
+ */
35
+ import type { SqliteVFS } from '@nimbus-sh/core/vfs/sqlite-vfs.js';
36
+ import type { PortRegistry } from '@nimbus-sh/core/runtime/port-registry.js';
37
+ import type { SessionProcessSupervisor } from '@nimbus-sh/core/runtime/session-process-supervisor.js';
38
+ import type { EsbuildService } from '@nimbus-sh/core/runtime/esbuild-service.js';
39
+ import { FacetManager, type FacetManagerHooks } from './manager.js';
40
+ import { type PortVisibility } from '../session/port-capability.js';
41
+ export type { FacetManagerHooks, LongRunningWorkerSpawnOptions, ResidentSpawnOptions, ResolvedWorkerLaunch, ResidentAppSummary, ResidentIdentity, ResidentRestartPolicy, SpawnedWorker, WorkerFacet, WorkerRecipe, } from './manager.js';
42
+ export { FacetManager, DEFAULT_WORKER_MAIN_MODULE } from './manager.js';
43
+ /**
44
+ * The hooks a host answers. Names and types are the FacetManager's own
45
+ * (`FacetManagerHooks`); the three a host cannot do without are required
46
+ * here because a manager composed without them loses launches silently —
47
+ * a launch turn nobody grants never resumes, an exit nobody hears leaves a
48
+ * process table lying, a notice nobody shows is a reset the user never
49
+ * learns about.
50
+ */
51
+ export interface FacetManagerHostHooks {
52
+ onExternalExit: NonNullable<FacetManagerHooks['onExternalExit']>;
53
+ notify: NonNullable<FacetManagerHooks['notify']>;
54
+ requestLaunchTurn: NonNullable<FacetManagerHooks['requestLaunchTurn']>;
55
+ onSpawn?: FacetManagerHooks['onSpawn'];
56
+ resolveWorkerLaunch?: FacetManagerHooks['resolveWorkerLaunch'];
57
+ }
58
+ /** Everything a FacetManager is composed over. */
59
+ export interface FacetManagerDeps {
60
+ ctx: DurableObjectState;
61
+ /** The Worker's bindings: `LOADER` is required, `ASSETS` serves the esbuild wasm. */
62
+ env: unknown;
63
+ processes: SessionProcessSupervisor;
64
+ portRegistry: PortRegistry;
65
+ vfs: SqliteVFS;
66
+ /** A host's already-warm esbuild, shared so the wasm is initialized once. */
67
+ esbuild?: EsbuildService;
68
+ hooks: FacetManagerHostHooks;
69
+ }
70
+ /** What `composeFacetManager` hands back. */
71
+ export interface ComposedFacetManager {
72
+ manager: FacetManager;
73
+ /**
74
+ * The paced launch pump — the manager's own `pumpResidentLaunches`, not a
75
+ * second one. The host drives it from the turn `hooks.requestLaunchTurn`
76
+ * arranged (the session: its `'resident-launch'` alarm); the first pump on
77
+ * a fresh incarnation also drains cold-start recovery of the launch
78
+ * journal (fabric's `FencedWork.recoverInterrupted`, registered on the
79
+ * manager's `onColdStart`), so it is the cold-start recovery entry too:
80
+ * the session calls it once from initSession for exactly that reason.
81
+ */
82
+ pumpLaunches: () => Promise<void>;
83
+ /**
84
+ * The durable-application verbs a host answers for its embedder — the
85
+ * session answers the same four through its `_rpc*` surface. Each is a
86
+ * short composition of the exported port-capability primitives
87
+ * (`@nimbus-sh/worker/port-capability`) and the manager's own methods, so
88
+ * an embedder that wants a different composition has every piece; what is
89
+ * NOT here is what only the session has (dev-server restore, HMR sockets,
90
+ * the self-refreshing "starting" page).
91
+ */
92
+ apps: {
93
+ /**
94
+ * Reserve (or re-answer) the port `owner` holds, minting the capability
95
+ * its URL is built on — minted here, stored on the reservation, so a URL
96
+ * handed out before the application has ever booted is the one its
97
+ * eventual binding re-adopts, and the one a reset re-adopts again.
98
+ */
99
+ ensureDurableApp(input: {
100
+ owner: string;
101
+ preferredPort?: number;
102
+ visibility?: PortVisibility;
103
+ name?: string;
104
+ }): Promise<{
105
+ port: number;
106
+ capability: string | null;
107
+ visibility: PortVisibility;
108
+ }>;
109
+ /**
110
+ * End a durable application's contract: every launch the owner claims is
111
+ * killed, its journal rows purged, its port released and its durable slot
112
+ * freed. `port` is the address that was held; `removed` is false only
113
+ * when no durable application held that owner at all.
114
+ */
115
+ removeDurableApp(owner: string): Promise<{
116
+ owner: string;
117
+ removed: boolean;
118
+ port: number | null;
119
+ }>;
120
+ /**
121
+ * Every registered port with its live capability, persisted at the
122
+ * moment the embedder is told it — a capability nobody has been handed
123
+ * does not need to survive anything.
124
+ */
125
+ listPorts(): Promise<Array<{
126
+ port: number;
127
+ pid: number;
128
+ registeredAt: number;
129
+ capability: string;
130
+ }>>;
131
+ /**
132
+ * Route a request carrying a port capability to the process on `port`:
133
+ * a durable application a reset left dead is re-driven first
134
+ * (`manager.ensureDurableAppOnPort`), the persisted capability is
135
+ * re-adopted, and a wrong capability is a 404 — never a 403, which would
136
+ * confirm the port is listening. 503 with `Retry-After` while a re-drive
137
+ * is mid-launch; 502 when nothing serves the port. WebSocket upgrades
138
+ * keep fetch semantics through the registered facet.
139
+ */
140
+ routeCapabilityPort(port: number, capability: string, request: Request, innerPath: string): Promise<Response>;
141
+ };
142
+ }
143
+ /**
144
+ * Compose a FacetManager over a host's own ctx, env, process supervisor, port
145
+ * registry and filesystem. See the module comment for what is defaulted.
146
+ */
147
+ export declare function composeFacetManager(deps: FacetManagerDeps): ComposedFacetManager;
148
+ //# sourceMappingURL=compose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/facets/compose.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * facets/compose.ts — the one composition of a FacetManager.
3
+ *
4
+ * A FacetManager is the session's spawn path for every resident process —
5
+ * `spawnWorker`, `spawnNode`, the launch journal, `_redrive`, cold-start
6
+ * recovery and the paced launch pump — and until this module it was
7
+ * constructed in exactly one place, inside NimbusSession, with hooks that
8
+ * closed over the session. An embedder that composes NimbusWorkspace as a
9
+ * library over its own Durable Object has no session and must not boot one
10
+ * over its filesystem (a second process table hands out pids whose write
11
+ * authority the filesystem already revoked), so everything behind the
12
+ * manager was closed to it.
13
+ *
14
+ * `composeFacetManager` is that construction, taking exactly what an
15
+ * embedder can supply: the Durable Object's ctx and env, its process
16
+ * supervisor, port registry and SQLite filesystem, an optional shared
17
+ * esbuild service, and the hooks a host has to answer. NimbusSession's own
18
+ * `ensureFacetManager` calls this same factory — there is one path — and
19
+ * keeps only what is session-specific (terminal writes, scrollback notices,
20
+ * the alarm that grants launch turns) inside its hook implementations.
21
+ *
22
+ * What the factory owns and the host does not:
23
+ *
24
+ * - `transformLargeEsm`: the isolated esbuild transform for module text
25
+ * past the in-isolate size bound. It needs `env.LOADER`, `env.ASSETS`
26
+ * and `ctx.facets` and nothing of any host, so it is the factory's
27
+ * default rather than every host's copy.
28
+ * - `resolveWorkerLaunchFallback`: the durable image-store resolver a
29
+ * self-owned worker launch (the session's python/ruby residents, or an
30
+ * embedder spawn that let the manager persist its image) re-drives
31
+ * from. It needs only the filesystem. An embedder that keeps its own
32
+ * content store answers `resolveWorkerLaunch` and this is never reached
33
+ * for its recipes (see `WorkerRecipe.resident`).
34
+ */
35
+ import { createPortCapability } from '@nimbus-sh/core/runtime/port-registry.js';
36
+ import { FacetManager } from './manager.js';
37
+ import { processHostFor } from '../loaders/process-host.js';
38
+ import { resolveDurableWorkerImage } from './durable-images.js';
39
+ import { persistPortCapability, readPortReservation, readPortReservationByOwner, reservePort, routeCapabilityPort, } from '../session/port-capability.js';
40
+ import { bindPublicPortCapability } from '../router/public-directory.js';
41
+ import { ESBUILD_TRANSFORM_WORKER_ID, esbuildTransformWorkerCode, } from './esbuild-transform.js';
42
+ import { fetchEsbuildWasmBytes } from '../runtime/esbuild-wasm-bytes.js';
43
+ export { FacetManager, DEFAULT_WORKER_MAIN_MODULE } from './manager.js';
44
+ /**
45
+ * Compose a FacetManager over a host's own ctx, env, process supervisor, port
46
+ * registry and filesystem. See the module comment for what is defaulted.
47
+ */
48
+ export function composeFacetManager(deps) {
49
+ const { ctx, env, vfs } = deps;
50
+ const hooks = {
51
+ onExternalExit: deps.hooks.onExternalExit,
52
+ notify: deps.hooks.notify,
53
+ requestLaunchTurn: deps.hooks.requestLaunchTurn,
54
+ ...(deps.hooks.onSpawn !== undefined ? { onSpawn: deps.hooks.onSpawn } : {}),
55
+ ...(deps.hooks.resolveWorkerLaunch !== undefined
56
+ ? { resolveWorkerLaunch: deps.hooks.resolveWorkerLaunch }
57
+ : {}),
58
+ transformLargeEsm: isolatedEsmTransform(ctx, env),
59
+ resolveWorkerLaunchFallback: (recipe) => resolveDurableWorkerImage(vfs, recipe),
60
+ };
61
+ const manager = new FacetManager(ctx, env, deps.processes, deps.portRegistry, processHostFor, hooks);
62
+ manager.setVfs(vfs);
63
+ if (deps.esbuild)
64
+ manager.setEsbuildService(deps.esbuild);
65
+ const { portRegistry } = deps;
66
+ const capabilityHost = { ctx, portRegistry };
67
+ return {
68
+ manager,
69
+ pumpLaunches: () => manager.pumpResidentLaunches(),
70
+ apps: {
71
+ async ensureDurableApp(input) {
72
+ if (typeof input.owner !== 'string' || input.owner.length === 0) {
73
+ throw new Error('ensureDurableApp: owner must be a non-empty string');
74
+ }
75
+ const occupied = new Set(portRegistry.getAll().map((entry) => entry.port));
76
+ const port = await reservePort(ctx, {
77
+ owner: input.owner,
78
+ preferredPort: input.preferredPort,
79
+ occupiedPorts: occupied,
80
+ capability: createPortCapability(),
81
+ ...(input.visibility !== undefined ? { visibility: input.visibility } : {}),
82
+ ...(input.name !== undefined ? { name: input.name } : {}),
83
+ });
84
+ const record = await readPortReservation(ctx, port);
85
+ if (record?.visibility === 'public' && record.capability !== null) {
86
+ // A no-op for a host whose Durable Object is not a session (the
87
+ // public directory keys on the session name); loud when it is a
88
+ // session without the binding.
89
+ await bindPublicPortCapability({ env, ctx }, record.capability, port, input.name);
90
+ }
91
+ return {
92
+ port,
93
+ capability: record?.capability ?? null,
94
+ visibility: record?.visibility ?? 'scoped',
95
+ };
96
+ },
97
+ async removeDurableApp(owner) {
98
+ if (typeof owner !== 'string' || owner.length === 0) {
99
+ throw new Error('removeDurableApp: owner must be a non-empty string');
100
+ }
101
+ const held = await readPortReservationByOwner(ctx, owner);
102
+ const removed = await manager.removeDurableApp(owner);
103
+ return { owner, removed, port: held?.port ?? null };
104
+ },
105
+ async listPorts() {
106
+ const entries = portRegistry.getAll();
107
+ await Promise.all(entries.map((entry) => persistPortCapability(capabilityHost, entry.port, entry.capability)));
108
+ return entries.map((entry) => ({
109
+ port: Number(entry.port),
110
+ pid: Number(entry.pid),
111
+ registeredAt: Number(entry.registeredAt),
112
+ capability: String(entry.capability),
113
+ }));
114
+ },
115
+ routeCapabilityPort(port, capability, request, innerPath) {
116
+ // The session's routeToSessionPort is the one implementation —
117
+ // the capability gate AND the public-bearer visibility gate live
118
+ // there; a copy here dropped the latter. Session-only concerns
119
+ // (dev-server restore, the vite-shim branch) no-op on this host.
120
+ return routeCapabilityPort({ ctx, portRegistry, ensureDurableAppOnPort: (p) => manager.ensureDurableAppOnPort(p) }, port, capability, request, innerPath);
121
+ },
122
+ },
123
+ };
124
+ }
125
+ /**
126
+ * The isolated esbuild transform: module text past the in-isolate bound is
127
+ * transformed in a loader-backed facet that owns the esbuild wasm heap, so the
128
+ * host isolate never pays for it. Session-independent by construction —
129
+ * `env.LOADER`, `env.ASSETS` and `ctx.facets` are all it reads.
130
+ */
131
+ function isolatedEsmTransform(ctx, env) {
132
+ return async (code, options) => {
133
+ const loader = Reflect.get(Object(env), 'LOADER');
134
+ if (!loader || typeof loader.get !== 'function') {
135
+ throw new Error('Nimbus: env.LOADER unavailable for isolated esbuild transform');
136
+ }
137
+ const assets = Reflect.get(Object(env), 'ASSETS');
138
+ if (!assets || typeof assets.fetch !== 'function') {
139
+ throw new Error('Nimbus: env.ASSETS unavailable for isolated esbuild transform');
140
+ }
141
+ const worker = await loader.get(ESBUILD_TRANSFORM_WORKER_ID, async () => esbuildTransformWorkerCode(await fetchEsbuildWasmBytes({ ASSETS: assets })));
142
+ const transformClass = worker.getDurableObjectClass('EsbuildTransformFacet');
143
+ const facet = ctx.facets.get(`esbuild-transform-${ESBUILD_TRANSFORM_WORKER_ID}`, async () => ({ class: transformClass }));
144
+ return facet.transform(code, options);
145
+ };
146
+ }
@@ -12,11 +12,12 @@
12
12
  * durable spawn exists to survive. Durable images are kept for the
13
13
  * application's life and released only by explicit removal.
14
14
  *
15
- * Two blobs per launch: `runner` is the worker.js source text, `application`
16
- * is a JSON payload of `{ modules, env, vfsWasmModules }`. The digests in the
17
- * journal's `recipe.image` are sha256 hashes of those two payloads, and a
18
- * self-owned spawn mints them at spawn time; an embedder-owned spawn is given
19
- * them by its own bookkeeping instead.
15
+ * Two blobs per launch: `runner` is the main module's source text,
16
+ * `application` is a JSON payload of `{ modules, env, vfsWasmModules }` plus,
17
+ * when the launch set them, `vfsTextModules`, `mainModule` and `startArgs`.
18
+ * The digests in the journal's `recipe.image` are sha256 hashes of those two
19
+ * payloads, and a self-owned spawn mints them at spawn time; an
20
+ * embedder-owned spawn is given them by its own bookkeeping instead.
20
21
  */
21
22
  import type { SqliteVFS } from '@nimbus-sh/core/vfs/sqlite-vfs.js';
22
23
  import type { ResidentCodeSpec } from '@nimbus-sh/fabric/process-fabric.js';
@@ -43,6 +44,9 @@ export declare function persistDurableWorkerImage(vfs: SqliteVFS, workerCode: st
43
44
  }>;
44
45
  env?: ResidentCodeSpec['env'];
45
46
  vfsWasmModules?: Record<string, string>;
47
+ vfsTextModules?: Record<string, string>;
48
+ /** Recorded only when the launch named one; absent means `worker.js`. */
49
+ mainModule?: string;
46
50
  startArgs?: unknown;
47
51
  }): Promise<{
48
52
  runner: string;
@@ -1 +1 @@
1
- {"version":3,"file":"durable-images.d.ts","sourceRoot":"","sources":["../../src/facets/durable-images.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAC5E,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEvE,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,mBAAmB,CAAC;AAIlD,8EAA8E;AAC9E,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,QAAQ,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,EACxD,QAAQ,EAAE,QAAQ,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,GAC1D,MAAM,CAaR;AAOD;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,SAAS,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE;IACP,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,WAAW,CAAA;KAAE,CAAC,CAAC;IACxD,GAAG,CAAC,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,GACA,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAclD;AAED;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CA0BtC"}
1
+ {"version":3,"file":"durable-images.d.ts","sourceRoot":"","sources":["../../src/facets/durable-images.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAEnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAC5E,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEvE,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,mBAAmB,CAAC;AAIlD,8EAA8E;AAC9E,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,QAAQ,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,EACxD,QAAQ,EAAE,QAAQ,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,GAC1D,MAAM,CAaR;AAOD;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,SAAS,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE;IACP,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,WAAW,CAAA;KAAE,CAAC,CAAC;IACxD,GAAG,CAAC,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,GACA,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAkBlD;AAED;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAiCtC"}
@@ -12,11 +12,12 @@
12
12
  * durable spawn exists to survive. Durable images are kept for the
13
13
  * application's life and released only by explicit removal.
14
14
  *
15
- * Two blobs per launch: `runner` is the worker.js source text, `application`
16
- * is a JSON payload of `{ modules, env, vfsWasmModules }`. The digests in the
17
- * journal's `recipe.image` are sha256 hashes of those two payloads, and a
18
- * self-owned spawn mints them at spawn time; an embedder-owned spawn is given
19
- * them by its own bookkeeping instead.
15
+ * Two blobs per launch: `runner` is the main module's source text,
16
+ * `application` is a JSON payload of `{ modules, env, vfsWasmModules }` plus,
17
+ * when the launch set them, `vfsTextModules`, `mainModule` and `startArgs`.
18
+ * The digests in the journal's `recipe.image` are sha256 hashes of those two
19
+ * payloads, and a self-owned spawn mints them at spawn time; an
20
+ * embedder-owned spawn is given them by its own bookkeeping instead.
20
21
  */
21
22
  import { CRED_KERNEL } from '@nimbus-sh/core/runtime/os-contracts.js';
22
23
  /** The directory every durable application's image blobs live under. */
@@ -54,10 +55,14 @@ export async function persistDurableWorkerImage(vfs, workerCode, payload) {
54
55
  kernel.mkdir(DURABLE_IMAGE_DIR, { recursive: true });
55
56
  const runner = await sha256Hex(workerCode);
56
57
  kernel.writeFile(imagePath(runner), workerCode);
58
+ // Optional members are omitted rather than written null so an unchanged
59
+ // launch keeps the digest it had before the member existed.
57
60
  const applicationPayload = JSON.stringify({
58
61
  modules: payload.modules,
59
62
  env: payload.env ?? null,
60
63
  vfsWasmModules: payload.vfsWasmModules ?? null,
64
+ ...(payload.vfsTextModules !== undefined ? { vfsTextModules: payload.vfsTextModules } : {}),
65
+ ...(payload.mainModule !== undefined ? { mainModule: payload.mainModule } : {}),
61
66
  ...(payload.startArgs !== undefined ? { startArgs: payload.startArgs } : {}),
62
67
  });
63
68
  const application = await sha256Hex(applicationPayload);
@@ -83,12 +88,17 @@ export async function resolveDurableWorkerImage(vfs, recipe) {
83
88
  return null;
84
89
  }
85
90
  const runner = new TextDecoder().decode(runnerBytes);
86
- const { modules = {}, env = null, vfsWasmModules = undefined, startArgs } = JSON.parse(new TextDecoder().decode(applicationBytes));
91
+ const { modules = {}, env = null, vfsWasmModules = undefined, vfsTextModules, mainModule, startArgs, } = JSON.parse(new TextDecoder().decode(applicationBytes));
92
+ // The recipe's own record of the main module wins when the blob predates
93
+ // the member; both say the same thing for any launch written since.
94
+ const main = mainModule ?? recipe.mainModule ?? 'worker.js';
87
95
  return {
88
96
  env: env ?? null,
89
97
  globalOutbound: undefined,
90
- modules: { 'worker.js': runner, ...modules },
98
+ modules: { ...modules, [main]: runner },
99
+ mainModule: main,
91
100
  ...(startArgs !== undefined ? { startArgs } : {}),
92
101
  ...(vfsWasmModules !== null ? { vfsWasmModules } : {}),
102
+ ...(vfsTextModules !== undefined ? { vfsTextModules } : {}),
93
103
  };
94
104
  }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * EsbuildBundlePool — the session's single esbuild facet pool.
3
+ *
4
+ * Install-time pre-bundling and on-demand /@modules/ bundling dispatch the
5
+ * same worker (PRE_BUNDLE_PREAMBLE + esbuild.wasm, one slot). When each
6
+ * pipeline built its own IsolatePool the supervisor retained two copies of
7
+ * the ~12 MiB wasm bytes and warmed two loader slots per session, and the
8
+ * two pools never queued behind each other. One pool, owned by the session,
9
+ * holds one wasm copy — leased once from the shared supervisor allocation
10
+ * budget, the way the pre-bundler already accounted for its own — for as
11
+ * long as the installer and dev server live, and is disposed with them.
12
+ *
13
+ * Construction is lazy and everything heavy is imported on first use so
14
+ * the fabric/preamble/wasm subgraph stays out of the cold script-eval
15
+ * graph of sessions that never bundle.
16
+ */
17
+ import type { IsolatePool } from '@nimbus-sh/fabric/isolate-pool.js';
18
+ /** The pool surface both bundling pipelines dispatch through. */
19
+ export type BundlePool = Pick<IsolatePool, 'submit'>;
20
+ /** What a bundling pipeline receives from its host. */
21
+ export interface BundlePoolProvider {
22
+ /** The session's pool, constructed on first call. */
23
+ acquire(): Promise<BundlePool>;
24
+ }
25
+ export declare class EsbuildBundlePool implements BundlePoolProvider {
26
+ private readonly env;
27
+ private readonly ctx;
28
+ private pool;
29
+ private pending;
30
+ /** Releases the wasm bytes' supervisor credit; held until dispose(). */
31
+ private releaseWasmCredit;
32
+ /** Bumped by dispose() so a construction it interrupted tears itself down. */
33
+ private generation;
34
+ constructor(env: unknown, ctx: DurableObjectState);
35
+ /**
36
+ * Callers MUST acquire the pool before taking any slice lease: the
37
+ * first construction reserves the full supervisor budget while the wasm
38
+ * bytes are fetched, so a caller already holding slice credit would
39
+ * wait on itself.
40
+ */
41
+ acquire(): Promise<IsolatePool>;
42
+ private construct;
43
+ /**
44
+ * Tear the pool down with its host. A later acquire() constructs a fresh
45
+ * pool, so a session that installs again after a teardown still bundles.
46
+ */
47
+ dispose(): void;
48
+ }
49
+ //# sourceMappingURL=esbuild-bundle-pool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"esbuild-bundle-pool.d.ts","sourceRoot":"","sources":["../../src/facets/esbuild-bundle-pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AASrE,iEAAiE;AACjE,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;AAErD,uDAAuD;AACvD,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;CAChC;AAQD,qBAAa,iBAAkB,YAAW,kBAAkB;IASxD,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,GAAG;IATtB,OAAO,CAAC,IAAI,CAA4B;IACxC,OAAO,CAAC,OAAO,CAAqC;IACpD,wEAAwE;IACxE,OAAO,CAAC,iBAAiB,CAA6B;IACtD,8EAA8E;IAC9E,OAAO,CAAC,UAAU,CAAK;gBAGJ,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,kBAAkB;IAG1C;;;;;OAKG;IACH,OAAO,IAAI,OAAO,CAAC,WAAW,CAAC;YAqBjB,SAAS;IAmDvB;;;OAGG;IACH,OAAO,IAAI,IAAI;CAYhB"}
@@ -0,0 +1,122 @@
1
+ import { acquireResidentSupervisorAllocation } from '@nimbus-sh/platform/heavy-alloc-coord.js';
2
+ import { PRE_BUNDLE_CONCURRENCY, PRE_BUNDLE_SLICE_CAP_BYTES, SUPERVISOR_IN_FLIGHT_ALLOCATION_BUDGET_BYTES, } from '@nimbus-sh/platform/limits.js';
3
+ function hasAssetsFetcher(env) {
4
+ if (typeof env !== 'object' || env === null)
5
+ return false;
6
+ const assets = Reflect.get(env, 'ASSETS');
7
+ return typeof assets === 'object' && assets !== null && typeof Reflect.get(assets, 'fetch') === 'function';
8
+ }
9
+ export class EsbuildBundlePool {
10
+ env;
11
+ ctx;
12
+ pool = null;
13
+ pending = null;
14
+ /** Releases the wasm bytes' supervisor credit; held until dispose(). */
15
+ releaseWasmCredit = null;
16
+ /** Bumped by dispose() so a construction it interrupted tears itself down. */
17
+ generation = 0;
18
+ constructor(env, ctx) {
19
+ this.env = env;
20
+ this.ctx = ctx;
21
+ }
22
+ /**
23
+ * Callers MUST acquire the pool before taking any slice lease: the
24
+ * first construction reserves the full supervisor budget while the wasm
25
+ * bytes are fetched, so a caller already holding slice credit would
26
+ * wait on itself.
27
+ */
28
+ acquire() {
29
+ if (this.pool)
30
+ return Promise.resolve(this.pool);
31
+ if (this.pending)
32
+ return this.pending;
33
+ const generation = this.generation;
34
+ const pending = this.construct().then(({ pool, releaseWasmCredit }) => {
35
+ if (this.generation !== generation) {
36
+ // dispose() ran while the wasm bytes were in flight.
37
+ try {
38
+ pool.dispose();
39
+ }
40
+ catch { /* best-effort */ }
41
+ releaseWasmCredit();
42
+ throw new Error('EsbuildBundlePool: disposed during construction');
43
+ }
44
+ this.pool = pool;
45
+ this.releaseWasmCredit = releaseWasmCredit;
46
+ return pool;
47
+ }).finally(() => {
48
+ if (this.pending === pending)
49
+ this.pending = null;
50
+ });
51
+ this.pending = pending;
52
+ return pending;
53
+ }
54
+ async construct() {
55
+ if (!hasAssetsFetcher(this.env)) {
56
+ throw new Error('EsbuildBundlePool: env.ASSETS binding missing — the esbuild wasm asset cannot be fetched');
57
+ }
58
+ const env = this.env;
59
+ const [{ IsolatePool }, { PRE_BUNDLE_PREAMBLE }, { fetchEsbuildWasmBytes }] = await Promise.all([
60
+ import('@nimbus-sh/fabric/isolate-pool.js'),
61
+ import('../loaders/pre-bundle-preamble.js'),
62
+ import('../runtime/esbuild-wasm-bytes.js'),
63
+ ]);
64
+ // Resident, and sized to what the pool will KEEP — not the whole budget.
65
+ //
66
+ // The full-budget claim this used to make is grantable exactly once: the
67
+ // lease it shrinks to becomes a permanent floor, so a second pool
68
+ // construction asked for 40 MiB against 28.1 MiB that could ever be free
69
+ // and parked in the FIFO with no error and no CPU. Measured on a
70
+ // deployed worker: capacity 41,943,040, resident 11,907,565, queued 1 for
71
+ // 222 s with the isolate healthy the whole time — and because the queue
72
+ // refuses everyone behind a waiter, the whole session stopped making
73
+ // progress. The bound below is the same one the payload is checked
74
+ // against, so the slice cap stays free for the work the pool exists for.
75
+ const maxRetainedWasmBytes = SUPERVISOR_IN_FLIGHT_ALLOCATION_BUDGET_BYTES - PRE_BUNDLE_SLICE_CAP_BYTES;
76
+ const setupAllocation = await acquireResidentSupervisorAllocation(maxRetainedWasmBytes);
77
+ let retained = false;
78
+ try {
79
+ const wasmBytes = await fetchEsbuildWasmBytes(env);
80
+ if (wasmBytes.byteLength > maxRetainedWasmBytes) {
81
+ throw new RangeError(`esbuild wasm payload ${wasmBytes.byteLength} exceeds the ${maxRetainedWasmBytes}-byte retained budget`);
82
+ }
83
+ // IsolatePool keeps the constructor-time module bytes until dispose(),
84
+ // so retain their exact credit rather than treating construction as a
85
+ // handoff that immediately frees the ArrayBuffer.
86
+ setupAllocation.shrinkTo(wasmBytes.byteLength);
87
+ const pool = new IsolatePool(env, this.ctx, {
88
+ concurrency: PRE_BUNDLE_CONCURRENCY,
89
+ timeoutMs: 60_000,
90
+ retries: 0,
91
+ tag: 'esbuild-bundle',
92
+ preamble: PRE_BUNDLE_PREAMBLE,
93
+ wasmModules: { 'esbuild.wasm': wasmBytes },
94
+ });
95
+ retained = true;
96
+ return { pool, releaseWasmCredit: setupAllocation.release };
97
+ }
98
+ finally {
99
+ if (!retained)
100
+ setupAllocation.release();
101
+ }
102
+ }
103
+ /**
104
+ * Tear the pool down with its host. A later acquire() constructs a fresh
105
+ * pool, so a session that installs again after a teardown still bundles.
106
+ */
107
+ dispose() {
108
+ this.generation++;
109
+ const pool = this.pool;
110
+ this.pool = null;
111
+ this.pending = null;
112
+ if (pool) {
113
+ try {
114
+ pool.dispose();
115
+ }
116
+ catch { /* best-effort */ }
117
+ }
118
+ const release = this.releaseWasmCredit;
119
+ this.releaseWasmCredit = null;
120
+ release?.();
121
+ }
122
+ }