@ecopages/core 0.2.0-beta.31 → 0.2.0-beta.33

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 (343) hide show
  1. package/README.md +1 -0
  2. package/package.json +90 -3
  3. package/src/adapters/abstract/application-adapter.d.ts +0 -8
  4. package/src/adapters/abstract/application-adapter.js +252 -261
  5. package/src/adapters/abstract/router-adapter.js +12 -4
  6. package/src/adapters/abstract/segment-path-matcher.js +132 -134
  7. package/src/adapters/abstract/server-adapter.js +22 -14
  8. package/src/adapters/abstract/ws-pattern-matcher.js +24 -26
  9. package/src/adapters/bun/bun-user-websocket-lifecycle.js +83 -86
  10. package/src/adapters/bun/client-bridge.js +51 -50
  11. package/src/adapters/bun/create-app.js +171 -161
  12. package/src/adapters/bun/hmr-manager.js +62 -57
  13. package/src/adapters/bun/index.js +2 -31
  14. package/src/adapters/bun/runtime-host.js +61 -54
  15. package/src/adapters/bun/server-adapter.d.ts +0 -1
  16. package/src/adapters/bun/server-adapter.js +561 -561
  17. package/src/adapters/bun/static-preview-host.js +43 -46
  18. package/src/adapters/create-app.js +11 -14
  19. package/src/adapters/index.js +2 -30
  20. package/src/adapters/node/create-app.js +123 -129
  21. package/src/adapters/node/http-request-bridge.js +147 -106
  22. package/src/adapters/node/node-client-bridge.js +62 -64
  23. package/src/adapters/node/node-hmr-manager.js +58 -48
  24. package/src/adapters/node/runtime-host.js +96 -89
  25. package/src/adapters/node/server-adapter-dependencies.js +18 -21
  26. package/src/adapters/node/server-adapter.d.ts +0 -1
  27. package/src/adapters/node/server-adapter.js +347 -326
  28. package/src/adapters/node/static-content-server.js +172 -191
  29. package/src/adapters/node/static-preview-host.js +87 -78
  30. package/src/adapters/shared/hmr/dev-transform-entrypoint-registry.d.ts +16 -0
  31. package/src/adapters/shared/hmr/dev-transform-entrypoint-registry.js +32 -0
  32. package/src/adapters/shared/hmr/hmr-html-response.js +46 -32
  33. package/src/adapters/shared/hmr/shared-hmr-manager.d.ts +29 -38
  34. package/src/adapters/shared/hmr/shared-hmr-manager.js +439 -425
  35. package/src/adapters/shared/http/api-request-pipeline.js +122 -119
  36. package/src/adapters/shared/http/api-response.js +77 -77
  37. package/src/adapters/shared/http/create-body-response.js +22 -19
  38. package/src/adapters/shared/http/define-api-handler.js +41 -55
  39. package/src/adapters/shared/http/explicit-static-render-preparation.js +26 -23
  40. package/src/adapters/shared/http/explicit-static-route-matcher.js +55 -62
  41. package/src/adapters/shared/http/file-route-middleware-pipeline.js +81 -75
  42. package/src/adapters/shared/http/fs-server-response-factory.js +101 -96
  43. package/src/adapters/shared/http/fs-server-response-matcher.js +239 -257
  44. package/src/adapters/shared/http/run-middleware-chain.js +15 -15
  45. package/src/adapters/shared/runtime/application-adapter.js +72 -87
  46. package/src/adapters/shared/runtime/copy-runtime-public-dir.js +25 -22
  47. package/src/adapters/shared/runtime/port-manager.js +207 -177
  48. package/src/adapters/shared/runtime/render-context.js +94 -79
  49. package/src/adapters/shared/runtime/runtime-app-bootstrap.js +33 -38
  50. package/src/adapters/shared/runtime/runtime-host.js +1 -0
  51. package/src/adapters/shared/runtime/runtime-server-lifecycle.d.ts +2 -3
  52. package/src/adapters/shared/runtime/runtime-server-lifecycle.js +65 -51
  53. package/src/adapters/shared/runtime/server-adapter.d.ts +1 -0
  54. package/src/adapters/shared/runtime/server-adapter.js +233 -217
  55. package/src/adapters/shared/runtime/server-route-handler.js +74 -70
  56. package/src/adapters/shared/runtime/server-static-builder.js +165 -184
  57. package/src/adapters/shared/runtime/static-preview-host.js +1 -0
  58. package/src/adapters/shared/ws/node-http-websocket-upgrades.js +97 -88
  59. package/src/adapters/shared/ws/websocket-lifecycle.js +57 -50
  60. package/src/build/README.md +52 -1
  61. package/src/build/app-build-manifest-runtime.js +129 -108
  62. package/src/build/browser/browser-runtime-manifest.js +47 -50
  63. package/src/build/browser/browser-runtime-plugin-helpers.js +32 -12
  64. package/src/build/browser/browser-runtime-plugin.js +206 -160
  65. package/src/build/browser/jsx-ownership-plugins.js +51 -37
  66. package/src/build/browser/lit-static-render-worker-context.js +3 -5
  67. package/src/build/build-adapter.js +276 -139
  68. package/src/build/cache/build-input-fingerprint.js +28 -26
  69. package/src/build/cache/cache-constants.js +4 -6
  70. package/src/build/cache/cache-keys.js +64 -56
  71. package/src/build/cache/pages-unified-graph-build.js +179 -178
  72. package/src/build/cache/production-build-cache.js +47 -54
  73. package/src/build/cache/server-entry-build-cache.js +134 -146
  74. package/src/build/contracts/build-contracts.d.ts +4 -4
  75. package/src/build/contracts/build-contracts.js +1 -0
  76. package/src/build/contracts/build-manifest.js +58 -43
  77. package/src/build/contracts/build-types.js +1 -0
  78. package/src/build/rolldown/rolldown-adapter-helpers.d.ts +9 -0
  79. package/src/build/rolldown/rolldown-adapter-helpers.js +405 -298
  80. package/src/build/rolldown/rolldown-build-adapter.js +53 -61
  81. package/src/build/rolldown/rolldown-build-invocation-metrics.js +31 -35
  82. package/src/build/rolldown/rolldown-plugin-bridge.js +264 -194
  83. package/src/build/rolldown/rolldown-source-transform-pass.js +59 -50
  84. package/src/build/rolldown/runtime-build-output-normalizer.js +227 -175
  85. package/src/build/rolldown/server-side-css-shim-plugin.js +54 -31
  86. package/src/build/runtime/build-profile-options.js +36 -36
  87. package/src/build/runtime/build-request-identity.js +70 -45
  88. package/src/build/runtime/build-request-policy.js +80 -42
  89. package/src/build/runtime/build-runtime.js +64 -54
  90. package/src/build/runtime/deduping-build-executor.js +38 -32
  91. package/src/build/runtime/parallel-build-executor.js +58 -50
  92. package/src/build/runtime/serialized-build-executor.js +78 -62
  93. package/src/cache/index.js +6 -6
  94. package/src/cache/module-parse-cache.js +99 -68
  95. package/src/client/navigation-scripts/classification.js +45 -37
  96. package/src/client/navigation-scripts/index.js +3 -23
  97. package/src/client/navigation-scripts/navigation-scripts.test.browser.js +58 -62
  98. package/src/client/navigation-scripts/registry.js +15 -11
  99. package/src/client/navigation-scripts/rerun-queue.js +81 -64
  100. package/src/client/scroll.js +32 -24
  101. package/src/client/scroll.test.browser.js +27 -33
  102. package/src/client/view-transitions.js +68 -55
  103. package/src/config/config-builder.d.ts +8 -0
  104. package/src/config/config-builder.js +637 -642
  105. package/src/config/constants.js +44 -24
  106. package/src/declarations.d.ts +1 -0
  107. package/src/dev/README.md +24 -0
  108. package/src/dev/client-bridge-registry.js +7 -12
  109. package/src/dev/dev-client-ownership.js +7 -5
  110. package/src/dev/hmr-manager-registry.js +7 -12
  111. package/src/dev/host-runtime.js +25 -30
  112. package/src/dev/runtime-server-started-message.js +2 -5
  113. package/src/dev/sc-server.js +106 -103
  114. package/src/dev/transform-server/dev-transform-bundler.d.ts +24 -0
  115. package/src/dev/transform-server/dev-transform-bundler.js +79 -0
  116. package/src/dev/transform-server/dev-transform-externalize-plugin.d.ts +12 -0
  117. package/src/dev/transform-server/dev-transform-externalize-plugin.js +29 -0
  118. package/src/dev/transform-server/dev-transform-import-rewriter.d.ts +16 -0
  119. package/src/dev/transform-server/dev-transform-import-rewriter.js +110 -0
  120. package/src/dev/transform-server/dev-transform-module-kind.d.ts +13 -0
  121. package/src/dev/transform-server/dev-transform-module-kind.js +17 -0
  122. package/src/dev/transform-server/dev-transform-runtime-specifiers.d.ts +5 -0
  123. package/src/dev/transform-server/dev-transform-runtime-specifiers.js +16 -0
  124. package/src/dev/transform-server/dev-transform-server.d.ts +41 -0
  125. package/src/dev/transform-server/dev-transform-server.js +191 -0
  126. package/src/dev/transform-server/dev-transform-url.d.ts +13 -0
  127. package/src/dev/transform-server/dev-transform-url.js +58 -0
  128. package/src/dev/transform-server/dev-transform-vendor-registry.d.ts +27 -0
  129. package/src/dev/transform-server/dev-transform-vendor-registry.js +145 -0
  130. package/src/dev/transform-server/index.d.ts +6 -0
  131. package/src/dev/transform-server/index.js +4 -0
  132. package/src/dev/transform-server/types.d.ts +15 -0
  133. package/src/dev/transform-server/types.js +1 -0
  134. package/src/dev-toolbar/README.md +51 -0
  135. package/src/dev-toolbar/define-dev-tool.d.ts +21 -0
  136. package/src/dev-toolbar/define-dev-tool.js +9 -0
  137. package/src/dev-toolbar/dev-toolbar-config.d.ts +25 -0
  138. package/src/dev-toolbar/dev-toolbar-config.js +19 -0
  139. package/src/dev-toolbar/dev-toolbar-host.d.ts +49 -0
  140. package/src/dev-toolbar/dev-toolbar-host.js +117 -0
  141. package/src/dev-toolbar/dev-toolbar-html-response.d.ts +11 -0
  142. package/src/dev-toolbar/dev-toolbar-html-response.js +14 -0
  143. package/src/dev-toolbar/dev-toolbar-manifest.d.ts +15 -0
  144. package/src/dev-toolbar/dev-toolbar-manifest.js +52 -0
  145. package/src/dev-toolbar/dev-toolbar-package.d.ts +31 -0
  146. package/src/dev-toolbar/dev-toolbar-package.js +72 -0
  147. package/src/dev-toolbar/dev-toolbar-runtime-paths.d.ts +10 -0
  148. package/src/dev-toolbar/dev-toolbar-runtime-paths.js +13 -0
  149. package/src/diagnostics/request-build-dedupe.js +34 -28
  150. package/src/diagnostics/startup-trace.d.ts +10 -1
  151. package/src/diagnostics/startup-trace.js +269 -241
  152. package/src/eco/README.md +6 -0
  153. package/src/eco/eco-declared-component.js +19 -14
  154. package/src/eco/eco.browser.js +56 -69
  155. package/src/eco/eco.js +156 -96
  156. package/src/eco/eco.types.js +5 -0
  157. package/src/eco/eco.utils.js +1 -10
  158. package/src/eco/global-injector-map.js +55 -41
  159. package/src/eco/lazy-injector-map.js +90 -60
  160. package/src/eco/module-dependencies.js +52 -44
  161. package/src/eco/page-layout-normalization.js +59 -49
  162. package/src/errors/http-error.js +50 -49
  163. package/src/errors/index.js +3 -12
  164. package/src/errors/locals-access-error.js +5 -8
  165. package/src/errors/undeclared-component-dependency-error.js +15 -15
  166. package/src/global/app-logger.js +3 -6
  167. package/src/hmr/README.md +10 -0
  168. package/src/hmr/client/hmr-runtime.js +117 -113
  169. package/src/hmr/client/module-update.d.ts +13 -0
  170. package/src/hmr/client/module-update.js +39 -0
  171. package/src/hmr/hmr-asset-paths.d.ts +14 -0
  172. package/src/hmr/hmr-asset-paths.js +22 -0
  173. package/src/hmr/hmr-entrypoint-output.d.ts +11 -39
  174. package/src/hmr/hmr-entrypoint-output.js +28 -54
  175. package/src/hmr/hmr-file-change-prep.js +13 -16
  176. package/src/hmr/hmr-registered-entrypoints-context.d.ts +7 -0
  177. package/src/hmr/hmr-registered-entrypoints-context.js +1 -0
  178. package/src/hmr/hmr-runtime-paths.d.ts +10 -0
  179. package/src/hmr/hmr-runtime-paths.js +13 -0
  180. package/src/hmr/hmr-strategy.d.ts +5 -11
  181. package/src/hmr/hmr-strategy.js +113 -61
  182. package/src/hmr/strategies/default-hmr-strategy.js +55 -33
  183. package/src/hmr/strategies/js-hmr-strategy.d.ts +6 -95
  184. package/src/hmr/strategies/js-hmr-strategy.js +104 -217
  185. package/src/hmr/strategies/server-rendered-template-hmr-strategy.js +33 -27
  186. package/src/index.browser.js +1 -4
  187. package/src/index.d.ts +1 -0
  188. package/src/index.js +6 -47
  189. package/src/integrations/ghtml/ghtml-renderer.js +12 -7
  190. package/src/integrations/ghtml/ghtml.constants.js +1 -4
  191. package/src/integrations/ghtml/ghtml.plugin.js +9 -12
  192. package/src/islands/README.md +25 -0
  193. package/src/islands/island-host.d.ts +37 -0
  194. package/src/islands/island-host.js +55 -0
  195. package/src/plugins/alias-resolver-cache.js +114 -97
  196. package/src/plugins/alias-resolver-plugin.js +33 -47
  197. package/src/plugins/define-integration.js +18 -17
  198. package/src/plugins/eco-component-meta-plugin.js +387 -145
  199. package/src/plugins/foreign-jsx-override-plugin.js +49 -35
  200. package/src/plugins/integration-plugin.js +212 -203
  201. package/src/plugins/jsx-import-source.utils.js +16 -21
  202. package/src/plugins/processor.js +159 -149
  203. package/src/plugins/runtime-capability.js +1 -0
  204. package/src/plugins/source-transform.js +109 -79
  205. package/src/plugins/tsconfig-import-resolver.d.ts +17 -0
  206. package/src/plugins/tsconfig-import-resolver.js +218 -142
  207. package/src/route-renderer/README.md +12 -1
  208. package/src/route-renderer/orchestration/document-shell/document-shell-render.service.js +143 -136
  209. package/src/route-renderer/orchestration/document-shell/layout-shell-props.service.js +33 -27
  210. package/src/route-renderer/orchestration/foreign-child/component-render-context.js +173 -126
  211. package/src/route-renderer/orchestration/foreign-child/foreign-child-output.utils.js +165 -154
  212. package/src/route-renderer/orchestration/foreign-child/foreign-subtree-execution.service.js +329 -341
  213. package/src/route-renderer/orchestration/foreign-child/owning-renderer-resolution.js +33 -32
  214. package/src/route-renderer/orchestration/integration-renderer.d.ts +1 -0
  215. package/src/route-renderer/orchestration/integration-renderer.js +731 -750
  216. package/src/route-renderer/orchestration/integration-renderer.test-fixtures.js +168 -172
  217. package/src/route-renderer/orchestration/ownership-graph/component-graph-collectors.js +119 -131
  218. package/src/route-renderer/orchestration/ownership-graph/component-graph.js +82 -91
  219. package/src/route-renderer/orchestration/ownership-graph/ownership-validation.service.js +82 -76
  220. package/src/route-renderer/orchestration/page-browser-graph/global-injector-assets.service.js +29 -31
  221. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-contribution.loader.js +10 -6
  222. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-merge.utils.js +31 -28
  223. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-session.d.ts +3 -0
  224. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-session.js +430 -413
  225. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph.service.js +191 -212
  226. package/src/route-renderer/orchestration/page-browser-graph/processed-asset-dedupe.js +20 -24
  227. package/src/route-renderer/orchestration/route-pipeline/integration-route-render-adapter.d.ts +4 -0
  228. package/src/route-renderer/orchestration/route-pipeline/integration-route-render-adapter.js +24 -24
  229. package/src/route-renderer/orchestration/route-pipeline/marker-artifact.utils.js +22 -24
  230. package/src/route-renderer/orchestration/route-pipeline/robots-meta.contribution.js +41 -34
  231. package/src/route-renderer/orchestration/route-pipeline/route-html-finalization.service.d.ts +5 -0
  232. package/src/route-renderer/orchestration/route-pipeline/route-html-finalization.service.js +42 -22
  233. package/src/route-renderer/orchestration/route-pipeline/route-prepared-options.builder.js +50 -48
  234. package/src/route-renderer/orchestration/route-pipeline/route-prepared-options.utils.js +29 -32
  235. package/src/route-renderer/orchestration/route-pipeline/route-render-orchestrator.js +150 -156
  236. package/src/route-renderer/orchestration/string-markup-renderer.js +48 -51
  237. package/src/route-renderer/page-loading/component-dependency-collection.js +120 -124
  238. package/src/route-renderer/page-loading/declared-asset-collection.js +66 -94
  239. package/src/route-renderer/page-loading/dependency-resolver.js +101 -104
  240. package/src/route-renderer/page-loading/ecopages-virtual-imports.js +68 -54
  241. package/src/route-renderer/page-loading/lazy-entry-collection.js +75 -98
  242. package/src/route-renderer/page-loading/lazy-trigger-planning.js +46 -36
  243. package/src/route-renderer/page-loading/module-declaration-aggregation.js +38 -31
  244. package/src/route-renderer/page-loading/module-declaration-scripts.js +10 -15
  245. package/src/route-renderer/page-loading/page-dependency-bundling.js +156 -113
  246. package/src/route-renderer/page-loading/page-module-loader.js +130 -124
  247. package/src/route-renderer/route-renderer.js +74 -76
  248. package/src/router/README.md +23 -0
  249. package/src/router/client/link-intent.js +55 -39
  250. package/src/router/client/link-intent.test.browser.js +49 -49
  251. package/src/router/client/link-navigation-policy.js +114 -93
  252. package/src/router/client/link-navigation-policy.test.browser.js +70 -80
  253. package/src/router/client/navigation-coordinator.js +235 -211
  254. package/src/router/client/navigation-lifecycle.d.ts +55 -0
  255. package/src/router/client/navigation-lifecycle.js +50 -0
  256. package/src/router/client/navigation-lifecycle.test.browser.d.ts +1 -0
  257. package/src/router/client/navigation-lifecycle.test.browser.js +118 -0
  258. package/src/router/server/route-registry.js +237 -242
  259. package/src/services/assets/asset-processing-service/asset-dependency-keys.js +64 -53
  260. package/src/services/assets/asset-processing-service/asset-processing.service.js +287 -303
  261. package/src/services/assets/asset-processing-service/asset.factory.js +78 -81
  262. package/src/services/assets/asset-processing-service/assets.types.js +1 -0
  263. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.js +57 -46
  264. package/src/services/assets/asset-processing-service/browser-runtime-entry-resolution.js +106 -69
  265. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.js +53 -53
  266. package/src/services/assets/asset-processing-service/finalize-processed-asset.js +4 -6
  267. package/src/services/assets/asset-processing-service/grouped-content-bundles.js +79 -80
  268. package/src/services/assets/asset-processing-service/index.js +8 -8
  269. package/src/services/assets/asset-processing-service/inline-content-script-body.js +22 -16
  270. package/src/services/assets/asset-processing-service/materialize-content-script-asset.js +21 -17
  271. package/src/services/assets/asset-processing-service/page-package.js +70 -72
  272. package/src/services/assets/asset-processing-service/processor.interface.js +7 -5
  273. package/src/services/assets/asset-processing-service/processor.registry.js +11 -14
  274. package/src/services/assets/asset-processing-service/processors/base/base-processor.js +59 -62
  275. package/src/services/assets/asset-processing-service/processors/base/base-script-processor.js +102 -117
  276. package/src/services/assets/asset-processing-service/processors/index.js +5 -5
  277. package/src/services/assets/asset-processing-service/processors/script/content-script.processor.js +110 -115
  278. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.js +95 -97
  279. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.js +136 -135
  280. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +27 -29
  281. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +34 -40
  282. package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.js +36 -35
  283. package/src/services/assets/asset-processing-service/resolve-integration-plugin.js +14 -16
  284. package/src/services/assets/asset-processing-service/ungrouped-dependency-processing.js +27 -39
  285. package/src/services/assets/browser-bundle.service.js +52 -47
  286. package/src/services/cache/cache.types.js +5 -0
  287. package/src/services/cache/index.js +6 -7
  288. package/src/services/cache/memory-cache-store.js +101 -89
  289. package/src/services/cache/page-cache-service.js +156 -145
  290. package/src/services/cache/page-request-cache-coordinator.service.js +102 -102
  291. package/src/services/html/html-rewriter-provider.service.js +61 -61
  292. package/src/services/html/html-transformer.service.js +249 -266
  293. package/src/services/invalidation/development-invalidation.service.js +252 -241
  294. package/src/services/module-loading/app-module-loader.service.js +1 -0
  295. package/src/services/module-loading/app-server-module-transpiler.service.js +107 -101
  296. package/src/services/module-loading/host-module-loader-registry.js +6 -11
  297. package/src/services/module-loading/module-loading-types.js +1 -0
  298. package/src/services/module-loading/page-module-import.service.js +235 -243
  299. package/src/services/module-loading/route-module-build-cache-registry.js +47 -33
  300. package/src/services/module-loading/route-module-build-cache.js +3 -38
  301. package/src/services/module-loading/route-module-build-cache.store.js +195 -200
  302. package/src/services/module-loading/route-module-build-manifest.js +61 -74
  303. package/src/services/module-loading/route-module-dependency-hasher.js +136 -110
  304. package/src/services/module-loading/server-module-transpiler.service.js +68 -62
  305. package/src/services/module-loading/source-module-support.js +15 -7
  306. package/src/services/runtime-state/dev-graph.service.js +165 -157
  307. package/src/services/runtime-state/entrypoint-dependency-graph.service.js +85 -76
  308. package/src/services/runtime-state/server-invalidation-state.service.js +38 -30
  309. package/src/services/validation/schema-validation-service.js +157 -95
  310. package/src/services/validation/standard-schema.types.js +1 -0
  311. package/src/services/validation/validate-standard-schema.js +13 -13
  312. package/src/static-site-generator/production-page-browser-graph-prebuild.js +35 -19
  313. package/src/static-site-generator/sitemap-routes.js +33 -28
  314. package/src/static-site-generator/sitemap.js +38 -29
  315. package/src/static-site-generator/static-build-invalidation.js +34 -56
  316. package/src/static-site-generator/static-export-context.js +1 -0
  317. package/src/static-site-generator/static-site-generator.js +517 -553
  318. package/src/types/internal-types.d.ts +19 -3
  319. package/src/types/internal-types.js +1 -0
  320. package/src/types/public-types.d.ts +16 -46
  321. package/src/types/public-types.js +1 -0
  322. package/src/utils/deep-merge.js +39 -26
  323. package/src/utils/ecopages-route-info.js +27 -23
  324. package/src/utils/hash.js +3 -6
  325. package/src/utils/html-escaping.js +21 -8
  326. package/src/utils/html.js +1 -4
  327. package/src/utils/invariant.js +11 -10
  328. package/src/utils/locals-utils.js +32 -22
  329. package/src/utils/parse-cli-args.js +73 -65
  330. package/src/utils/path-pattern.js +38 -23
  331. package/src/utils/path-utils.module.js +8 -11
  332. package/src/utils/resolve-entry-file.js +70 -38
  333. package/src/utils/resolve-work-dir.js +23 -27
  334. package/src/utils/runtime.js +24 -33
  335. package/src/utils/server-utils.module.js +60 -52
  336. package/src/utils/static-file-extensions.js +52 -46
  337. package/src/watchers/project-watcher-ignore.js +16 -15
  338. package/src/watchers/project-watcher.js +385 -366
  339. package/src/watchers/project-watcher.test-helpers.js +45 -50
  340. package/src/adapters/shared/hmr/hmr-entrypoint-registrar.d.ts +0 -56
  341. package/src/adapters/shared/hmr/hmr-entrypoint-registrar.js +0 -106
  342. package/src/build/cache/dev-browser-script-cache.d.ts +0 -34
  343. package/src/build/cache/dev-browser-script-cache.js +0 -90
@@ -1,340 +1,361 @@
1
- import {} from "node:http";
2
- import path from "node:path";
3
- import { fileSystem } from "@ecopages/file-system";
4
- import { setupAppRuntimePlugins } from "../../build/build-adapter.js";
5
- import { installBuildRuntime } from "../../build/runtime/build-runtime.js";
6
- import { appLogger } from "../../global/app-logger.js";
7
- import { NodeClientBridge } from "./node-client-bridge.js";
8
- import { NodeHmrManager } from "./node-hmr-manager.js";
9
- import { ProjectWatcher } from "../../watchers/project-watcher.js";
10
- import {
11
- attachNodeHttpWebSocketUpgrades
12
- } from "../shared/ws/node-http-websocket-upgrades.js";
13
- import { StaticSiteGenerator } from "../../static-site-generator/static-site-generator.js";
14
- import { SharedServerAdapter } from "../shared/runtime/server-adapter.js";
15
- import { ServerStaticBuilder } from "../shared/runtime/server-static-builder.js";
16
- import { DEFAULT_ECOPAGES_HOSTNAME, DEFAULT_ECOPAGES_PORT } from "../../config/constants.js";
17
- import {
18
- attachHmrToIntegrations,
19
- disposeDevResources,
20
- prepareRuntimePublicDir,
21
- startConfiguredIntegrationRuntimePrewarm
22
- } from "../shared/runtime/runtime-server-lifecycle.js";
23
- import { resolveServeRuntimeOrigin } from "../shared/runtime/runtime-app-bootstrap.js";
24
- import { NodeClientAbortError, NodeHttpRequestBridge } from "./http-request-bridge.js";
25
- import { NodeStaticPreviewHost } from "./static-preview-host.js";
26
- import { DefaultNodeServerDevRuntimeFactory } from "./server-adapter-dependencies.js";
27
- class NodeServerAdapter extends SharedServerAdapter {
28
- serverInstance = null;
29
- initialized = false;
30
- apiHandlers;
31
- staticRoutes;
32
- errorHandler;
33
- bridge = null;
34
- hmrManager = null;
35
- projectWatcher = null;
36
- adapterDisposed = false;
37
- deferRuntimeAssetSetup;
38
- allowPortFallback;
39
- previewHost;
40
- requestBridge;
41
- devRuntimeFactory;
42
- /**
43
- * Reference to the application-level WebSocket handlers map.
44
- *
45
- * @remarks
46
- * This is a reference to the map owned by `AbstractApplicationAdapter`,
47
- * passed in via the constructor. The Node adapter reads from it to wire
48
- * WebSocket upgrades for user-registered patterns.
49
- */
50
- websocketHandlers = /* @__PURE__ */ new Map();
51
- /**
52
- * Wires user WebSocket routes onto a foreign Node HTTP server.
53
- *
54
- * Host integrations such as the Vite plugin call this so `app.websocket()`
55
- * handlers work while HTTP is still served by the host dev server.
56
- */
57
- attachUserWebSocketUpgrades(server, options) {
58
- attachNodeHttpWebSocketUpgrades(server, {
59
- runtimeOrigin: this.runtimeOrigin,
60
- websocketHandlers: this.websocketHandlers,
61
- passthroughUnmatched: options?.passthroughUnmatched
62
- });
63
- }
64
- wireUserWebSocketUpgrades(server, preflight) {
65
- attachNodeHttpWebSocketUpgrades(server, {
66
- runtimeOrigin: this.runtimeOrigin,
67
- websocketHandlers: this.websocketHandlers,
68
- passthroughUnmatched: false,
69
- preflight
70
- });
71
- }
72
- /**
73
- * @remarks
74
- * `previewHost`, `requestBridge`, and `devRuntimeFactory` are optional on the
75
- * public {@link NodeServerAdapterParams} so factory callers can omit them, but
76
- * they are mandatory by the time the concrete adapter is constructed —
77
- * {@link createNodeServerAdapter} fills in Node-specific defaults first. The
78
- * constructor signature makes that invariant explicit instead of relying on
79
- * non-null assertions.
80
- */
81
- constructor(options) {
82
- super(options);
83
- this.deferRuntimeAssetSetup = options.deferRuntimeAssetSetup === true;
84
- this.allowPortFallback = options.allowPortFallback !== false;
85
- this.apiHandlers = options.apiHandlers || [];
86
- this.staticRoutes = options.staticRoutes || [];
87
- this.errorHandler = options.errorHandler;
88
- this.previewHost = options.previewHost;
89
- this.requestBridge = options.requestBridge;
90
- this.devRuntimeFactory = options.devRuntimeFactory;
91
- if (options.websocketHandlers) {
92
- this.websocketHandlers = options.websocketHandlers;
93
- }
94
- this.hostOwnsDevClient = options.hostOwnsDevClient === true;
95
- }
96
- /**
97
- * Prepares the adapter for use.
98
- *
99
- * Order is intentional:
100
- * 1. **Loaders** are registered first so processors and integrations can
101
- * reference loader-provided file types in their own plugins.
102
- * 2. **Public dir** is copied before any build so static assets are in `distDir`
103
- * before the first request arrives.
104
- * 3. **Plugins** (processors, then integrations) are set up after the public dir
105
- * is in place so they can safely reference dist-relative paths.
106
- * 4. **Router** is initialised last because it may depend on files written by
107
- * processors during their `setup()` calls.
108
- */
109
- async initialize() {
110
- installBuildRuntime(this.appConfig);
111
- prepareRuntimePublicDir(this.appConfig);
112
- if (!this.deferRuntimeAssetSetup) {
113
- await setupAppRuntimePlugins({
114
- appConfig: this.appConfig,
115
- runtimeOrigin: this.runtimeOrigin
116
- });
1
+ import {} from 'node:http';
2
+ import path from 'node:path';
3
+ import { fileSystem } from '@ecopages/file-system';
4
+ import { setupAppRuntimePlugins } from '../../build/build-adapter.js';
5
+ import { installBuildRuntime } from '../../build/runtime/build-runtime.js';
6
+ import { appLogger } from '../../global/app-logger.js';
7
+ import { NodeClientBridge } from './node-client-bridge.js';
8
+ import { NodeHmrManager } from './node-hmr-manager.js';
9
+ import { ProjectWatcher } from '../../watchers/project-watcher.js';
10
+ import { attachNodeHttpWebSocketUpgrades, } from '../shared/ws/node-http-websocket-upgrades.js';
11
+ import { StaticSiteGenerator } from '../../static-site-generator/static-site-generator.js';
12
+ import { SharedServerAdapter } from '../shared/runtime/server-adapter.js';
13
+ import { ServerStaticBuilder } from '../shared/runtime/server-static-builder.js';
14
+ import { DEFAULT_ECOPAGES_HOSTNAME, DEFAULT_ECOPAGES_PORT } from '../../config/constants.js';
15
+ import { attachHmrToIntegrations, disposeDevResources, prepareRuntimePublicDir, startDevWarmup, } from '../shared/runtime/runtime-server-lifecycle.js';
16
+ import { resolveServeRuntimeOrigin } from '../shared/runtime/runtime-app-bootstrap.js';
17
+ import { NodeClientAbortError, NodeHttpRequestBridge } from './http-request-bridge.js';
18
+ import { NodeStaticPreviewHost } from './static-preview-host.js';
19
+ import { DefaultNodeServerDevRuntimeFactory } from './server-adapter-dependencies.js';
20
+ /**
21
+ * Node.js HTTP server adapter for the Ecopages runtime.
22
+ *
23
+ * `NodeServerAdapter` bridges the Node.js `http` module and the Ecopages
24
+ * `SharedServerAdapter` abstraction, translating between Node's
25
+ * `IncomingMessage`/`ServerResponse` API and the platform-agnostic Web
26
+ * `Request`/`Response` model.
27
+ *
28
+ * Lifecycle:
29
+ * 1. `createAdapter()` — calls `initialize()` and returns the public adapter result.
30
+ * 2. `completeInitialization(server)` — called once the HTTP server is listening.
31
+ * Conditionally wires HMR, WebSocket upgrades, and the file watcher when
32
+ * `options.watch` is `true`.
33
+ * 3. `handleRequest(request)` — delegates to `handleSharedRequest` for routing;
34
+ * intercepts `ClientAbortError` to return 499 instead of 500.
35
+ * 4. `buildStatic()` — spins up an ephemeral runtime server, generates all static
36
+ * pages against it, then tears it down.
37
+ *
38
+ * @see SharedServerAdapter for routing, caching and response handler logic.
39
+ */
40
+ export class NodeServerAdapter extends SharedServerAdapter {
41
+ serverInstance = null;
42
+ initialized = false;
43
+ apiHandlers;
44
+ staticRoutes;
45
+ errorHandler;
46
+ bridge = null;
47
+ hmrManager = null;
48
+ projectWatcher = null;
49
+ adapterDisposed = false;
50
+ deferRuntimeAssetSetup;
51
+ allowPortFallback;
52
+ previewHost;
53
+ requestBridge;
54
+ devRuntimeFactory;
55
+ /**
56
+ * Reference to the application-level WebSocket handlers map.
57
+ *
58
+ * @remarks
59
+ * This is a reference to the map owned by `AbstractApplicationAdapter`,
60
+ * passed in via the constructor. The Node adapter reads from it to wire
61
+ * WebSocket upgrades for user-registered patterns.
62
+ */
63
+ websocketHandlers = new Map();
64
+ /**
65
+ * Wires user WebSocket routes onto a foreign Node HTTP server.
66
+ *
67
+ * Host integrations such as the Vite plugin call this so `app.websocket()`
68
+ * handlers work while HTTP is still served by the host dev server.
69
+ */
70
+ attachUserWebSocketUpgrades(server, options) {
71
+ attachNodeHttpWebSocketUpgrades(server, {
72
+ runtimeOrigin: this.runtimeOrigin,
73
+ websocketHandlers: this.websocketHandlers,
74
+ passthroughUnmatched: options?.passthroughUnmatched,
75
+ });
117
76
  }
118
- await this.initializeSharedRouteHandling({
119
- staticRoutes: this.staticRoutes,
120
- hmrManager: this.hmrManager ?? void 0
121
- });
122
- this.staticSiteGenerator = new StaticSiteGenerator({ appConfig: this.appConfig });
123
- this.staticBuilder = new ServerStaticBuilder({
124
- appConfig: this.appConfig,
125
- staticSiteGenerator: this.staticSiteGenerator,
126
- serveOptions: this.serveOptions,
127
- runtimeOrigin: this.runtimeOrigin,
128
- needsServerBundle: this.apiHandlers.length > 0 || this.websocketHandlers.size > 0,
129
- hmrManager: this.hmrManager ?? void 0
130
- });
131
- this.initialized = true;
132
- }
133
- getServerOptions() {
134
- return {
135
- ...this.serveOptions
136
- };
137
- }
138
- async buildStatic(options) {
139
- if (!this.initialized) {
140
- await this.initialize();
77
+ wireUserWebSocketUpgrades(server, preflight) {
78
+ attachNodeHttpWebSocketUpgrades(server, {
79
+ runtimeOrigin: this.runtimeOrigin,
80
+ websocketHandlers: this.websocketHandlers,
81
+ passthroughUnmatched: false,
82
+ preflight,
83
+ });
141
84
  }
142
- const baseUrl = resolveServeRuntimeOrigin(this.serveOptions);
143
- await this.staticBuilder.build(
144
- { baseUrl, force: options?.force },
145
- {
146
- router: this.router,
147
- routeRendererFactory: this.routeRendererFactory,
148
- staticRoutes: this.staticRoutes
149
- }
150
- );
151
- if (!options?.preview) {
152
- return void 0;
85
+ /**
86
+ * @remarks
87
+ * `previewHost`, `requestBridge`, and `devRuntimeFactory` are optional on the
88
+ * public {@link NodeServerAdapterParams} so factory callers can omit them, but
89
+ * they are mandatory by the time the concrete adapter is constructed —
90
+ * {@link createNodeServerAdapter} fills in Node-specific defaults first. The
91
+ * constructor signature makes that invariant explicit instead of relying on
92
+ * non-null assertions.
93
+ */
94
+ constructor(options) {
95
+ super(options);
96
+ this.deferRuntimeAssetSetup = options.deferRuntimeAssetSetup === true;
97
+ this.allowPortFallback = options.allowPortFallback !== false;
98
+ this.apiHandlers = options.apiHandlers || [];
99
+ this.staticRoutes = options.staticRoutes || [];
100
+ this.errorHandler = options.errorHandler;
101
+ this.previewHost = options.previewHost;
102
+ this.requestBridge = options.requestBridge;
103
+ this.devRuntimeFactory = options.devRuntimeFactory;
104
+ if (options.websocketHandlers) {
105
+ this.websocketHandlers = options.websocketHandlers;
106
+ }
107
+ this.hostOwnsDevClient = options.hostOwnsDevClient === true;
153
108
  }
154
- return this.startPreviewServer();
155
- }
156
- /**
157
- * Serves an existing static export without running SSG. Used by e2e preview
158
- * launchers after a shared prewarm build.
159
- */
160
- async servePreviewOnly() {
161
- if (!this.initialized) {
162
- await this.initialize();
109
+ /**
110
+ * Prepares the adapter for use.
111
+ *
112
+ * Order is intentional:
113
+ * 1. **Loaders** are registered first so processors and integrations can
114
+ * reference loader-provided file types in their own plugins.
115
+ * 2. **Public dir** is copied before any build so static assets are in `distDir`
116
+ * before the first request arrives.
117
+ * 3. **Plugins** (processors, then integrations) are set up after the public dir
118
+ * is in place so they can safely reference dist-relative paths.
119
+ * 4. **Router** is initialised last because it may depend on files written by
120
+ * processors during their `setup()` calls.
121
+ */
122
+ async initialize() {
123
+ installBuildRuntime(this.appConfig);
124
+ prepareRuntimePublicDir(this.appConfig);
125
+ if (!this.deferRuntimeAssetSetup) {
126
+ await setupAppRuntimePlugins({
127
+ appConfig: this.appConfig,
128
+ runtimeOrigin: this.runtimeOrigin,
129
+ });
130
+ }
131
+ await this.initializeSharedRouteHandling({
132
+ staticRoutes: this.staticRoutes,
133
+ hmrManager: this.hmrManager ?? undefined,
134
+ });
135
+ this.staticSiteGenerator = new StaticSiteGenerator({ appConfig: this.appConfig });
136
+ this.staticBuilder = new ServerStaticBuilder({
137
+ appConfig: this.appConfig,
138
+ staticSiteGenerator: this.staticSiteGenerator,
139
+ serveOptions: this.serveOptions,
140
+ runtimeOrigin: this.runtimeOrigin,
141
+ needsServerBundle: this.apiHandlers.length > 0 || this.websocketHandlers.size > 0,
142
+ hmrManager: this.hmrManager ?? undefined,
143
+ });
144
+ this.initialized = true;
163
145
  }
164
- const distPath = path.join(this.appConfig.rootDir, this.appConfig.distDir);
165
- if (!fileSystem.exists(distPath)) {
166
- throw new Error(
167
- `Cannot serve preview without building first: dist directory "${this.appConfig.distDir}" not found in "${this.appConfig.rootDir}".`
168
- );
146
+ getServerOptions() {
147
+ return {
148
+ ...this.serveOptions,
149
+ };
169
150
  }
170
- return this.startPreviewServer();
171
- }
172
- async startPreviewServer() {
173
- const activePreviewPort = await this.previewHost.start({
174
- appConfig: this.appConfig,
175
- hostname: String(this.serveOptions.hostname || DEFAULT_ECOPAGES_HOSTNAME),
176
- port: Number(this.serveOptions.port || DEFAULT_ECOPAGES_PORT),
177
- allowPortFallback: this.allowPortFallback
178
- });
179
- if (!activePreviewPort) {
180
- return void 0;
151
+ async buildStatic(options) {
152
+ if (!this.initialized) {
153
+ await this.initialize();
154
+ }
155
+ const baseUrl = resolveServeRuntimeOrigin(this.serveOptions);
156
+ await this.staticBuilder.build({ baseUrl, force: options?.force }, {
157
+ router: this.router,
158
+ routeRendererFactory: this.routeRendererFactory,
159
+ staticRoutes: this.staticRoutes,
160
+ });
161
+ if (!options?.preview) {
162
+ return undefined;
163
+ }
164
+ return this.startPreviewServer();
181
165
  }
182
- const previewHostname = this.serveOptions.hostname || DEFAULT_ECOPAGES_HOSTNAME;
183
- return `http://${previewHostname}:${activePreviewPort}`;
184
- }
185
- async createAdapter() {
186
- await this.initialize();
187
- return {
188
- getServerOptions: this.getServerOptions.bind(this),
189
- buildStatic: this.buildStatic.bind(this),
190
- servePreviewOnly: this.servePreviewOnly.bind(this),
191
- completeInitialization: this.completeInitialization.bind(this),
192
- handleRequest: this.handleRequest.bind(this),
193
- attachUserWebSocketUpgrades: this.attachUserWebSocketUpgrades.bind(this),
194
- listStaticGenerationRoutes: (input) => this.router.listStaticGenerationRoutes(input),
195
- dispose: this.dispose.bind(this)
196
- };
197
- }
198
- /**
199
- * Releases dev-time resources owned by the adapter.
200
- *
201
- * @remarks
202
- * Safe to call multiple times. Does not stop the bound HTTP server — callers
203
- * should shut down transport through the runtime host before disposing.
204
- */
205
- async dispose() {
206
- if (this.adapterDisposed) {
207
- return;
166
+ /**
167
+ * Serves an existing static export without running SSG. Used by e2e preview
168
+ * launchers after a shared prewarm build.
169
+ */
170
+ async servePreviewOnly() {
171
+ if (!this.initialized) {
172
+ await this.initialize();
173
+ }
174
+ const distPath = path.join(this.appConfig.rootDir, this.appConfig.distDir);
175
+ if (!fileSystem.exists(distPath)) {
176
+ throw new Error(`Cannot serve preview without building first: dist directory "${this.appConfig.distDir}" not found in "${this.appConfig.rootDir}".`);
177
+ }
178
+ return this.startPreviewServer();
208
179
  }
209
- this.adapterDisposed = true;
210
- await disposeDevResources({
211
- projectWatcher: this.projectWatcher,
212
- appConfig: this.appConfig,
213
- hmrManager: this.hmrManager,
214
- bridge: this.bridge,
215
- previewHost: this.previewHost
216
- });
217
- this.projectWatcher = null;
218
- this.hmrManager = null;
219
- this.bridge = null;
220
- }
221
- /**
222
- * Handles a single incoming Web `Request` and returns a Web `Response`.
223
- *
224
- * Delegates to `handleSharedRequest` for all routing, caching, and response
225
- * handler logic. The only Node-specific concern here is translating a
226
- * `ClientAbortError` — which the body `ReadableStream` raises when the
227
- * underlying socket closes early — into a 499 response so it does not
228
- * incorrectly surface as a 500 in application logs.
229
- */
230
- async handleRequest(request) {
231
- if (!this.initialized) {
232
- throw new Error("Node server adapter is not initialized. Call createAdapter() first.");
180
+ async startPreviewServer() {
181
+ const activePreviewPort = await this.previewHost.start({
182
+ appConfig: this.appConfig,
183
+ hostname: String(this.serveOptions.hostname || DEFAULT_ECOPAGES_HOSTNAME),
184
+ port: Number(this.serveOptions.port || DEFAULT_ECOPAGES_PORT),
185
+ allowPortFallback: this.allowPortFallback,
186
+ });
187
+ if (!activePreviewPort) {
188
+ return undefined;
189
+ }
190
+ const previewHostname = this.serveOptions.hostname || DEFAULT_ECOPAGES_HOSTNAME;
191
+ return `http://${previewHostname}:${activePreviewPort}`;
233
192
  }
234
- try {
235
- const response = await this.handleSharedRequest(request, {
236
- apiHandlers: this.apiHandlers,
237
- errorHandler: this.errorHandler,
238
- serverInstance: this.serverInstance,
239
- hmrManager: this.hmrManager ?? void 0
240
- });
241
- return response;
242
- } catch (error) {
243
- if (error instanceof NodeClientAbortError) {
244
- return new Response(null, { status: 499 });
245
- }
246
- throw error;
193
+ async createAdapter() {
194
+ await this.initialize();
195
+ return {
196
+ getServerOptions: this.getServerOptions.bind(this),
197
+ buildStatic: this.buildStatic.bind(this),
198
+ servePreviewOnly: this.servePreviewOnly.bind(this),
199
+ completeInitialization: this.completeInitialization.bind(this),
200
+ handleRequest: this.handleRequest.bind(this),
201
+ attachUserWebSocketUpgrades: this.attachUserWebSocketUpgrades.bind(this),
202
+ listStaticGenerationRoutes: (input) => this.router.listStaticGenerationRoutes(input),
203
+ dispose: this.dispose.bind(this),
204
+ };
247
205
  }
248
- }
249
- /**
250
- * Called once the HTTP server is bound and listening.
251
- *
252
- * When `options.watch` is `true` this method wires the full HMR pipeline:
253
- * - A `WebSocketServer` is attached to the existing HTTP server via the
254
- * `upgrade` event (no separate port needed).
255
- * - `NodeClientBridge` tracks active WebSocket connections and handles
256
- * broadcast + heartbeat cleanup.
257
- * - `NodeHmrManager` watches the filesystem and triggers incremental
258
- * rebuilds, notifying connected clients via the bridge.
259
- * - Shared watcher bootstrapping listens for route-level file changes and
260
- * refreshes the router and response handlers when pages are added or removed.
261
- *
262
- * WebSocket upgrade requests that do not match a known path are rejected with an
263
- * immediate socket destroy to prevent unhandled upgrade leaks.
264
- */
265
- async completeInitialization(server) {
266
- this.serverInstance = server;
267
- const hasUserWs = this.websocketHandlers.size > 0;
268
- if (this.options?.watch) {
269
- const devRuntime = this.devRuntimeFactory.create({ appConfig: this.appConfig });
270
- const wss = devRuntime.websocketServer;
271
- this.bridge = devRuntime.bridge;
272
- this.hmrManager = devRuntime.hmrManager;
273
- this.hmrManager.setEnabled(true);
274
- await this.hmrManager.ensureRuntimeReady();
275
- const hmrPreflight = (req, socket, head) => {
276
- const url = new URL(req.url ?? "/", this.runtimeOrigin);
277
- if (url.pathname !== "/_hmr") return false;
278
- wss.handleUpgrade(req, socket, head, (ws) => {
279
- this.bridge.subscribe(ws);
280
- ws.on("close", () => this.bridge.unsubscribe(ws));
281
- ws.on("error", (err) => appLogger.error("[HMR] WebSocket error:", err));
206
+ /**
207
+ * Releases dev-time resources owned by the adapter.
208
+ *
209
+ * @remarks
210
+ * Safe to call multiple times. Does not stop the bound HTTP server — callers
211
+ * should shut down transport through the runtime host before disposing.
212
+ */
213
+ async dispose() {
214
+ if (this.adapterDisposed) {
215
+ return;
216
+ }
217
+ this.adapterDisposed = true;
218
+ await disposeDevResources({
219
+ projectWatcher: this.projectWatcher,
220
+ appConfig: this.appConfig,
221
+ hmrManager: this.hmrManager,
222
+ bridge: this.bridge,
223
+ previewHost: this.previewHost,
282
224
  });
283
- return true;
284
- };
285
- if (hasUserWs) {
286
- this.wireUserWebSocketUpgrades(server, hmrPreflight);
287
- } else {
288
- server.on("upgrade", (req, socket, head) => {
289
- if (!hmrPreflight(req, socket, head)) {
290
- socket.destroy();
291
- }
225
+ this.projectWatcher = null;
226
+ this.hmrManager = null;
227
+ this.bridge = null;
228
+ }
229
+ /**
230
+ * Handles a single incoming Web `Request` and returns a Web `Response`.
231
+ *
232
+ * Delegates to `handleSharedRequest` for all routing, caching, and response
233
+ * handler logic. The only Node-specific concern here is translating a
234
+ * `ClientAbortError` — which the body `ReadableStream` raises when the
235
+ * underlying socket closes early — into a 499 response so it does not
236
+ * incorrectly surface as a 500 in application logs.
237
+ */
238
+ async handleRequest(request) {
239
+ if (!this.initialized) {
240
+ throw new Error('Node server adapter is not initialized. Call createAdapter() first.');
241
+ }
242
+ try {
243
+ const response = await this.handleSharedRequest(request, {
244
+ apiHandlers: this.apiHandlers,
245
+ errorHandler: this.errorHandler,
246
+ serverInstance: this.serverInstance,
247
+ hmrManager: this.hmrManager ?? undefined,
248
+ });
249
+ return response;
250
+ }
251
+ catch (error) {
252
+ if (error instanceof NodeClientAbortError) {
253
+ /**
254
+ * The client disconnected before the response was sent (killed tab,
255
+ * network drop, or programmatic abort). This is a normal browser behaviour,
256
+ * not a server fault. Return 499 (Client Closed Request) silently so the
257
+ * error does not surface in application logs as a 500.
258
+ */
259
+ return new Response(null, { status: 499 });
260
+ }
261
+ throw error;
262
+ }
263
+ }
264
+ /**
265
+ * Called once the HTTP server is bound and listening.
266
+ *
267
+ * When `options.watch` is `true` this method wires the full HMR pipeline:
268
+ * - A `WebSocketServer` is attached to the existing HTTP server via the
269
+ * `upgrade` event (no separate port needed).
270
+ * - `NodeClientBridge` tracks active WebSocket connections and handles
271
+ * broadcast + heartbeat cleanup.
272
+ * - `NodeHmrManager` watches the filesystem and triggers incremental
273
+ * rebuilds, notifying connected clients via the bridge.
274
+ * - Shared watcher bootstrapping listens for route-level file changes and
275
+ * refreshes the router and response handlers when pages are added or removed.
276
+ *
277
+ * WebSocket upgrade requests that do not match a known path are rejected with an
278
+ * immediate socket destroy to prevent unhandled upgrade leaks.
279
+ */
280
+ async completeInitialization(server) {
281
+ this.serverInstance = server;
282
+ const hasUserWs = this.websocketHandlers.size > 0;
283
+ if (this.options?.watch) {
284
+ const devRuntime = this.devRuntimeFactory.create({ appConfig: this.appConfig });
285
+ const wss = devRuntime.websocketServer;
286
+ this.bridge = devRuntime.bridge;
287
+ this.hmrManager = devRuntime.hmrManager;
288
+ this.hmrManager.setEnabled(true);
289
+ await this.hmrManager.ensureRuntimeReady();
290
+ const hmrPreflight = (req, socket, head) => {
291
+ const url = new URL(req.url ?? '/', this.runtimeOrigin);
292
+ if (url.pathname !== '/_hmr')
293
+ return false;
294
+ wss.handleUpgrade(req, socket, head, (ws) => {
295
+ this.bridge.subscribe(ws);
296
+ ws.on('close', () => this.bridge.unsubscribe(ws));
297
+ ws.on('error', (err) => appLogger.error('[HMR] WebSocket error:', err));
298
+ });
299
+ return true;
300
+ };
301
+ if (hasUserWs) {
302
+ this.wireUserWebSocketUpgrades(server, hmrPreflight);
303
+ }
304
+ else {
305
+ server.on('upgrade', (req, socket, head) => {
306
+ if (!hmrPreflight(req, socket, head)) {
307
+ socket.destroy();
308
+ }
309
+ });
310
+ }
311
+ attachHmrToIntegrations(this.appConfig, this.hmrManager);
312
+ startDevWarmup({
313
+ appConfig: this.appConfig,
314
+ runtimeOrigin: this.runtimeOrigin,
315
+ });
316
+ this.configureSharedResponseHandlers(this.staticRoutes, this.hmrManager);
317
+ const watcher = new ProjectWatcher({
318
+ config: this.appConfig,
319
+ refreshRouterRoutesCallback: this.createSharedWatchRefreshCallback({
320
+ staticRoutes: this.staticRoutes,
321
+ hmrManager: this.hmrManager ?? undefined,
322
+ }),
323
+ hmrManager: this.hmrManager ?? undefined,
324
+ bridge: this.bridge,
325
+ hostOwnsDevClient: this.hostOwnsDevClient,
326
+ });
327
+ this.projectWatcher = watcher;
328
+ await watcher.createWatcherSubscription();
329
+ }
330
+ else if (hasUserWs) {
331
+ this.wireUserWebSocketUpgrades(server);
332
+ }
333
+ appLogger.debug('Node server adapter initialization completed', {
334
+ apiHandlers: this.apiHandlers.length,
335
+ staticRoutes: this.staticRoutes.length,
336
+ hasErrorHandler: !!this.errorHandler,
337
+ hmrEnabled: !!this.hmrManager?.isEnabled(),
292
338
  });
293
- }
294
- attachHmrToIntegrations(this.appConfig, this.hmrManager);
295
- startConfiguredIntegrationRuntimePrewarm({
296
- appConfig: this.appConfig,
297
- runtimeOrigin: this.runtimeOrigin
298
- });
299
- this.configureSharedResponseHandlers(this.staticRoutes, this.hmrManager);
300
- const watcher = new ProjectWatcher({
301
- config: this.appConfig,
302
- refreshRouterRoutesCallback: this.createSharedWatchRefreshCallback({
303
- staticRoutes: this.staticRoutes,
304
- hmrManager: this.hmrManager ?? void 0
305
- }),
306
- hmrManager: this.hmrManager ?? void 0,
307
- bridge: this.bridge,
308
- hostOwnsDevClient: this.hostOwnsDevClient
309
- });
310
- this.projectWatcher = watcher;
311
- await watcher.createWatcherSubscription();
312
- } else if (hasUserWs) {
313
- this.wireUserWebSocketUpgrades(server);
314
339
  }
315
- appLogger.debug("Node server adapter initialization completed", {
316
- apiHandlers: this.apiHandlers.length,
317
- staticRoutes: this.staticRoutes.length,
318
- hasErrorHandler: !!this.errorHandler,
319
- hmrEnabled: !!this.hmrManager?.isEnabled()
320
- });
321
- }
322
340
  }
323
- async function createNodeServerAdapter(params) {
324
- const runtimeOrigin = params.runtimeOrigin ?? resolveServeRuntimeOrigin(params.serveOptions);
325
- const previewHost = params.previewHost ?? new NodeStaticPreviewHost();
326
- const requestBridge = params.requestBridge ?? new NodeHttpRequestBridge();
327
- const devRuntimeFactory = params.devRuntimeFactory ?? new DefaultNodeServerDevRuntimeFactory();
328
- const adapter = new NodeServerAdapter({
329
- ...params,
330
- runtimeOrigin,
331
- previewHost,
332
- requestBridge,
333
- devRuntimeFactory
334
- });
335
- return adapter.createAdapter();
341
+ /**
342
+ * Factory function that creates and fully initialises a `NodeServerAdapter`.
343
+ *
344
+ * `runtimeOrigin` is derived from `serveOptions` when not explicitly provided,
345
+ * so callers only need to set it when the server is behind a reverse proxy that
346
+ * changes the effective host or port.
347
+ */
348
+ export async function createNodeServerAdapter(params) {
349
+ const runtimeOrigin = params.runtimeOrigin ?? resolveServeRuntimeOrigin(params.serveOptions);
350
+ const previewHost = params.previewHost ?? new NodeStaticPreviewHost();
351
+ const requestBridge = params.requestBridge ?? new NodeHttpRequestBridge();
352
+ const devRuntimeFactory = params.devRuntimeFactory ?? new DefaultNodeServerDevRuntimeFactory();
353
+ const adapter = new NodeServerAdapter({
354
+ ...params,
355
+ runtimeOrigin,
356
+ previewHost,
357
+ requestBridge,
358
+ devRuntimeFactory,
359
+ });
360
+ return adapter.createAdapter();
336
361
  }
337
- export {
338
- NodeServerAdapter,
339
- createNodeServerAdapter
340
- };