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

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 (338) hide show
  1. package/README.md +1 -0
  2. package/package.json +82 -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/client/link-intent.js +55 -39
  249. package/src/router/client/link-intent.test.browser.js +49 -49
  250. package/src/router/client/link-navigation-policy.js +114 -93
  251. package/src/router/client/link-navigation-policy.test.browser.js +70 -80
  252. package/src/router/client/navigation-coordinator.js +235 -211
  253. package/src/router/server/route-registry.js +237 -242
  254. package/src/services/assets/asset-processing-service/asset-dependency-keys.js +64 -53
  255. package/src/services/assets/asset-processing-service/asset-processing.service.js +287 -303
  256. package/src/services/assets/asset-processing-service/asset.factory.js +78 -81
  257. package/src/services/assets/asset-processing-service/assets.types.js +1 -0
  258. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.js +57 -46
  259. package/src/services/assets/asset-processing-service/browser-runtime-entry-resolution.js +106 -69
  260. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.js +53 -53
  261. package/src/services/assets/asset-processing-service/finalize-processed-asset.js +4 -6
  262. package/src/services/assets/asset-processing-service/grouped-content-bundles.js +79 -80
  263. package/src/services/assets/asset-processing-service/index.js +8 -8
  264. package/src/services/assets/asset-processing-service/inline-content-script-body.js +22 -16
  265. package/src/services/assets/asset-processing-service/materialize-content-script-asset.js +21 -17
  266. package/src/services/assets/asset-processing-service/page-package.js +70 -72
  267. package/src/services/assets/asset-processing-service/processor.interface.js +7 -5
  268. package/src/services/assets/asset-processing-service/processor.registry.js +11 -14
  269. package/src/services/assets/asset-processing-service/processors/base/base-processor.js +59 -62
  270. package/src/services/assets/asset-processing-service/processors/base/base-script-processor.js +102 -117
  271. package/src/services/assets/asset-processing-service/processors/index.js +5 -5
  272. package/src/services/assets/asset-processing-service/processors/script/content-script.processor.js +110 -115
  273. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.js +95 -97
  274. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.js +136 -135
  275. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +27 -29
  276. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +34 -40
  277. package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.js +36 -35
  278. package/src/services/assets/asset-processing-service/resolve-integration-plugin.js +14 -16
  279. package/src/services/assets/asset-processing-service/ungrouped-dependency-processing.js +27 -39
  280. package/src/services/assets/browser-bundle.service.js +52 -47
  281. package/src/services/cache/cache.types.js +5 -0
  282. package/src/services/cache/index.js +6 -7
  283. package/src/services/cache/memory-cache-store.js +101 -89
  284. package/src/services/cache/page-cache-service.js +156 -145
  285. package/src/services/cache/page-request-cache-coordinator.service.js +102 -102
  286. package/src/services/html/html-rewriter-provider.service.js +61 -61
  287. package/src/services/html/html-transformer.service.js +249 -266
  288. package/src/services/invalidation/development-invalidation.service.js +252 -241
  289. package/src/services/module-loading/app-module-loader.service.js +1 -0
  290. package/src/services/module-loading/app-server-module-transpiler.service.js +107 -101
  291. package/src/services/module-loading/host-module-loader-registry.js +6 -11
  292. package/src/services/module-loading/module-loading-types.js +1 -0
  293. package/src/services/module-loading/page-module-import.service.js +235 -243
  294. package/src/services/module-loading/route-module-build-cache-registry.js +47 -33
  295. package/src/services/module-loading/route-module-build-cache.js +3 -38
  296. package/src/services/module-loading/route-module-build-cache.store.js +195 -200
  297. package/src/services/module-loading/route-module-build-manifest.js +61 -74
  298. package/src/services/module-loading/route-module-dependency-hasher.js +136 -110
  299. package/src/services/module-loading/server-module-transpiler.service.js +68 -62
  300. package/src/services/module-loading/source-module-support.js +15 -7
  301. package/src/services/runtime-state/dev-graph.service.js +165 -157
  302. package/src/services/runtime-state/entrypoint-dependency-graph.service.js +85 -76
  303. package/src/services/runtime-state/server-invalidation-state.service.js +38 -30
  304. package/src/services/validation/schema-validation-service.js +157 -95
  305. package/src/services/validation/standard-schema.types.js +1 -0
  306. package/src/services/validation/validate-standard-schema.js +13 -13
  307. package/src/static-site-generator/production-page-browser-graph-prebuild.js +35 -19
  308. package/src/static-site-generator/sitemap-routes.js +33 -28
  309. package/src/static-site-generator/sitemap.js +38 -29
  310. package/src/static-site-generator/static-build-invalidation.js +34 -56
  311. package/src/static-site-generator/static-export-context.js +1 -0
  312. package/src/static-site-generator/static-site-generator.js +517 -553
  313. package/src/types/internal-types.d.ts +19 -3
  314. package/src/types/internal-types.js +1 -0
  315. package/src/types/public-types.d.ts +16 -46
  316. package/src/types/public-types.js +1 -0
  317. package/src/utils/deep-merge.js +39 -26
  318. package/src/utils/ecopages-route-info.js +27 -23
  319. package/src/utils/hash.js +3 -6
  320. package/src/utils/html-escaping.js +21 -8
  321. package/src/utils/html.js +1 -4
  322. package/src/utils/invariant.js +11 -10
  323. package/src/utils/locals-utils.js +32 -22
  324. package/src/utils/parse-cli-args.js +73 -65
  325. package/src/utils/path-pattern.js +38 -23
  326. package/src/utils/path-utils.module.js +8 -11
  327. package/src/utils/resolve-entry-file.js +70 -38
  328. package/src/utils/resolve-work-dir.js +23 -27
  329. package/src/utils/runtime.js +24 -33
  330. package/src/utils/server-utils.module.js +60 -52
  331. package/src/utils/static-file-extensions.js +52 -46
  332. package/src/watchers/project-watcher-ignore.js +16 -15
  333. package/src/watchers/project-watcher.js +385 -366
  334. package/src/watchers/project-watcher.test-helpers.js +45 -50
  335. package/src/adapters/shared/hmr/hmr-entrypoint-registrar.d.ts +0 -56
  336. package/src/adapters/shared/hmr/hmr-entrypoint-registrar.js +0 -106
  337. package/src/build/cache/dev-browser-script-cache.d.ts +0 -34
  338. package/src/build/cache/dev-browser-script-cache.js +0 -90
@@ -1,191 +1,172 @@
1
- import path from "node:path";
2
- import { fileSystem } from "@ecopages/file-system";
3
- import { DEFAULT_ECOPAGES_HOSTNAME, DEFAULT_ECOPAGES_PORT } from "../../../config/constants.js";
4
- import { appLogger } from "../../../global/app-logger.js";
5
- import { build, getAppBuildAdapter, setupAppRuntimePlugins } from "../../../build/build-adapter.js";
6
- import { createServerBuildRequest } from "../../../build/runtime/build-request-policy.js";
7
- import { requireBuildRuntime } from "../../../build/runtime/build-runtime.js";
8
- import { attachHmrToIntegrations } from "./runtime-server-lifecycle.js";
9
- import {
10
- getServerBundleOutputPaths,
11
- lookupServerEntryBuildCache,
12
- recordServerEntryBuildCache,
13
- writeServerBundleDeployManifest
14
- } from "../../../build/cache/server-entry-build-cache.js";
15
- import {
16
- clearProductionBuildCaches,
17
- shouldResetStaticExportDirectory
18
- } from "../../../static-site-generator/static-build-invalidation.js";
19
- import { resolveEntryFile, SERVER_BUNDLE_FILENAME } from "../../../utils/resolve-entry-file.js";
20
- class ServerStaticBuilder {
21
- appConfig;
22
- staticSiteGenerator;
23
- serveOptions;
24
- runtimeOrigin;
25
- needsServerBundle;
26
- logger;
27
- entryFile;
28
- hmrManager;
29
- onRuntimePlugin;
30
- constructor({
31
- appConfig,
32
- staticSiteGenerator,
33
- serveOptions,
34
- runtimeOrigin,
35
- needsServerBundle,
36
- logger,
37
- entryFile,
38
- hmrManager,
39
- onRuntimePlugin
40
- }) {
41
- this.appConfig = appConfig;
42
- this.staticSiteGenerator = staticSiteGenerator;
43
- this.serveOptions = serveOptions;
44
- this.runtimeOrigin = runtimeOrigin;
45
- this.needsServerBundle = needsServerBundle ?? false;
46
- this.logger = logger ?? appLogger;
47
- this.entryFile = resolveEntryFile({ entryFile });
48
- this.hmrManager = hmrManager;
49
- this.onRuntimePlugin = onRuntimePlugin;
50
- }
51
- prepareExportDirectory(force) {
52
- if (force) {
53
- clearProductionBuildCaches(this.appConfig);
1
+ import path from 'node:path';
2
+ import { fileSystem } from '@ecopages/file-system';
3
+ import { DEFAULT_ECOPAGES_HOSTNAME, DEFAULT_ECOPAGES_PORT } from '../../../config/constants.js';
4
+ import { appLogger } from '../../../global/app-logger.js';
5
+ import { build, getAppBuildAdapter, setupAppRuntimePlugins } from '../../../build/build-adapter.js';
6
+ import { createServerBuildRequest } from '../../../build/runtime/build-request-policy.js';
7
+ import { requireBuildRuntime } from '../../../build/runtime/build-runtime.js';
8
+ import { attachHmrToIntegrations } from './runtime-server-lifecycle.js';
9
+ import { getServerBundleOutputPaths, lookupServerEntryBuildCache, recordServerEntryBuildCache, writeServerBundleDeployManifest, } from '../../../build/cache/server-entry-build-cache.js';
10
+ import { clearProductionBuildCaches, shouldResetStaticExportDirectory, } from '../../../static-site-generator/static-build-invalidation.js';
11
+ import { resolveEntryFile, SERVER_BUNDLE_FILENAME } from '../../../utils/resolve-entry-file.js';
12
+ /**
13
+ * Handles static site generation.
14
+ */
15
+ export class ServerStaticBuilder {
16
+ appConfig;
17
+ staticSiteGenerator;
18
+ serveOptions;
19
+ runtimeOrigin;
20
+ needsServerBundle;
21
+ logger;
22
+ entryFile;
23
+ hmrManager;
24
+ onRuntimePlugin;
25
+ constructor({ appConfig, staticSiteGenerator, serveOptions, runtimeOrigin, needsServerBundle, logger, entryFile, hmrManager, onRuntimePlugin, }) {
26
+ this.appConfig = appConfig;
27
+ this.staticSiteGenerator = staticSiteGenerator;
28
+ this.serveOptions = serveOptions;
29
+ this.runtimeOrigin = runtimeOrigin;
30
+ this.needsServerBundle = needsServerBundle ?? false;
31
+ this.logger = logger ?? appLogger;
32
+ this.entryFile = resolveEntryFile({ entryFile });
33
+ this.hmrManager = hmrManager;
34
+ this.onRuntimePlugin = onRuntimePlugin;
54
35
  }
55
- const exportDir = this.appConfig.absolutePaths?.distDir ?? path.join(this.appConfig.rootDir, this.appConfig.distDir);
56
- const shouldCleanDist = shouldResetStaticExportDirectory(this.appConfig, force);
57
- fileSystem.ensureDir(exportDir, shouldCleanDist);
58
- if (shouldCleanDist) {
59
- this.appConfig.runtime = {
60
- ...this.appConfig.runtime ?? {},
61
- runtimeAssetsPrepared: false
62
- };
36
+ prepareExportDirectory(force) {
37
+ if (force) {
38
+ clearProductionBuildCaches(this.appConfig);
39
+ }
40
+ const exportDir = this.appConfig.absolutePaths?.distDir ?? path.join(this.appConfig.rootDir, this.appConfig.distDir);
41
+ const shouldCleanDist = shouldResetStaticExportDirectory(this.appConfig, force);
42
+ fileSystem.ensureDir(exportDir, shouldCleanDist);
43
+ if (shouldCleanDist) {
44
+ this.appConfig.runtime = {
45
+ ...(this.appConfig.runtime ?? {}),
46
+ runtimeAssetsPrepared: false,
47
+ };
48
+ }
49
+ const srcPublicDir = path.join(this.appConfig.rootDir, this.appConfig.srcDir ?? 'src', this.appConfig.publicDir ?? 'public');
50
+ if (fileSystem.exists(srcPublicDir)) {
51
+ fileSystem.copyDir(srcPublicDir, exportDir);
52
+ }
53
+ return !shouldCleanDist;
63
54
  }
64
- const srcPublicDir = path.join(
65
- this.appConfig.rootDir,
66
- this.appConfig.srcDir ?? "src",
67
- this.appConfig.publicDir ?? "public"
68
- );
69
- if (fileSystem.exists(srcPublicDir)) {
70
- fileSystem.copyDir(srcPublicDir, exportDir);
55
+ async refreshRuntimeAssets() {
56
+ appLogger.debugTime('refreshRuntimeAssets');
57
+ try {
58
+ await setupAppRuntimePlugins({
59
+ appConfig: this.appConfig,
60
+ runtimeOrigin: this.runtimeOrigin,
61
+ onRuntimePlugin: this.onRuntimePlugin,
62
+ });
63
+ if (this.hmrManager?.isEnabled()) {
64
+ attachHmrToIntegrations(this.appConfig, this.hmrManager);
65
+ }
66
+ }
67
+ finally {
68
+ appLogger.debugTimeEnd('refreshRuntimeAssets');
69
+ }
71
70
  }
72
- return !shouldCleanDist;
73
- }
74
- async refreshRuntimeAssets() {
75
- appLogger.debugTime("refreshRuntimeAssets");
76
- try {
77
- await setupAppRuntimePlugins({
78
- appConfig: this.appConfig,
79
- runtimeOrigin: this.runtimeOrigin,
80
- onRuntimePlugin: this.onRuntimePlugin
81
- });
82
- if (this.hmrManager?.isEnabled()) {
83
- attachHmrToIntegrations(this.appConfig, this.hmrManager);
84
- }
85
- } finally {
86
- appLogger.debugTimeEnd("refreshRuntimeAssets");
87
- }
88
- }
89
- /**
90
- * Bundles the server entry file for production use.
91
- *
92
- * @remarks
93
- * Only invoked when the app requires a runtime server (API handlers,
94
- * websocket handlers, etc.). Static-only apps skip this step entirely.
95
- * Incremental builds may skip Rolldown when the `.eco/.server-entry`
96
- * cache is still valid.
97
- *
98
- * Package imports remain external so native addons and runtime-owned
99
- * dependencies continue to load through the app's installed
100
- * `node_modules` tree. Only the app entry graph is bundled.
101
- *
102
- * Throws if the build adapter is unavailable, is owned by a host
103
- * runtime, or bundling fails.
104
- *
105
- * @throws If the build adapter is unavailable, is host-owned, or bundling fails.
106
- */
107
- async bundleServerEntry(options) {
108
- const buildAdapter = getAppBuildAdapter(this.appConfig);
109
- if (buildAdapter.ownership === "vite-host") {
110
- throw new Error(
111
- 'Cannot bundle the server entry file: build ownership is "vite-host". The host runtime is expected to produce its own server bundle.'
112
- );
113
- }
114
- const entryPath = path.isAbsolute(this.entryFile) ? this.entryFile : path.join(this.appConfig.rootDir, this.entryFile);
115
- if (!fileSystem.exists(entryPath)) {
116
- throw new Error(
117
- `Cannot bundle server entry: file "${this.entryFile}" not found in "${this.appConfig.rootDir}".`
118
- );
119
- }
120
- const { serverOutdir, serverEntryPath } = getServerBundleOutputPaths(this.appConfig);
121
- const cached = lookupServerEntryBuildCache({
122
- appConfig: this.appConfig,
123
- entryPath,
124
- force: options?.force
125
- });
126
- if (cached) {
127
- const hasBundle = cached.outputPaths.some(
128
- (outputPath) => path.resolve(outputPath) === path.resolve(serverEntryPath) && fileSystem.exists(outputPath)
129
- );
130
- if (hasBundle) {
131
- this.logger.info("Reusing cached server entry bundle");
71
+ /**
72
+ * Bundles the server entry file for production use.
73
+ *
74
+ * @remarks
75
+ * Only invoked when the app requires a runtime server (API handlers,
76
+ * websocket handlers, etc.). Static-only apps skip this step entirely.
77
+ * Incremental builds may skip Rolldown when the `.eco/.server-entry`
78
+ * cache is still valid.
79
+ *
80
+ * Package imports remain external so native addons and runtime-owned
81
+ * dependencies continue to load through the app's installed
82
+ * `node_modules` tree. Only the app entry graph is bundled.
83
+ *
84
+ * Throws if the build adapter is unavailable, is owned by a host
85
+ * runtime, or bundling fails.
86
+ *
87
+ * @throws If the build adapter is unavailable, is host-owned, or bundling fails.
88
+ */
89
+ async bundleServerEntry(options) {
90
+ const buildAdapter = getAppBuildAdapter(this.appConfig);
91
+ if (buildAdapter.ownership === 'vite-host') {
92
+ throw new Error('Cannot bundle the server entry file: build ownership is "vite-host". ' +
93
+ 'The host runtime is expected to produce its own server bundle.');
94
+ }
95
+ const entryPath = path.isAbsolute(this.entryFile)
96
+ ? this.entryFile
97
+ : path.join(this.appConfig.rootDir, this.entryFile);
98
+ if (!fileSystem.exists(entryPath)) {
99
+ throw new Error(`Cannot bundle server entry: file "${this.entryFile}" not found in "${this.appConfig.rootDir}".`);
100
+ }
101
+ const { serverOutdir, serverEntryPath } = getServerBundleOutputPaths(this.appConfig);
102
+ const cached = lookupServerEntryBuildCache({
103
+ appConfig: this.appConfig,
104
+ entryPath,
105
+ force: options?.force,
106
+ });
107
+ if (cached) {
108
+ const hasBundle = cached.outputPaths.some((outputPath) => path.resolve(outputPath) === path.resolve(serverEntryPath) && fileSystem.exists(outputPath));
109
+ if (hasBundle) {
110
+ this.logger.info('Reusing cached server entry bundle');
111
+ writeServerBundleDeployManifest(this.appConfig, serverEntryPath);
112
+ return;
113
+ }
114
+ }
115
+ this.logger.info('Bundling server entry file...');
116
+ const buildOptions = createServerBuildRequest(this.appConfig, {
117
+ profile: 'server-entry',
118
+ entrypoints: [entryPath],
119
+ outdir: serverOutdir,
120
+ naming: SERVER_BUNDLE_FILENAME,
121
+ sourcemap: 'hidden',
122
+ });
123
+ const result = await build(buildOptions, requireBuildRuntime(this.appConfig).getProfile('server-entry'));
124
+ if (!result.success) {
125
+ const errorMessages = result.logs.map((log) => log.message).join('\n');
126
+ throw new Error(`Failed to bundle server entry file:\n${errorMessages}`);
127
+ }
128
+ const outputPaths = result.outputs.length > 0
129
+ ? result.outputs.map((output) => output.path)
130
+ : fileSystem.exists(serverEntryPath)
131
+ ? [serverEntryPath]
132
+ : [];
133
+ recordServerEntryBuildCache({
134
+ appConfig: this.appConfig,
135
+ entryPath,
136
+ buildResult: result,
137
+ outputPaths,
138
+ });
132
139
  writeServerBundleDeployManifest(this.appConfig, serverEntryPath);
133
- return;
134
- }
135
- }
136
- this.logger.info("Bundling server entry file...");
137
- const buildOptions = createServerBuildRequest(this.appConfig, {
138
- profile: "server-entry",
139
- entrypoints: [entryPath],
140
- outdir: serverOutdir,
141
- naming: SERVER_BUNDLE_FILENAME,
142
- sourcemap: "hidden"
143
- });
144
- const result = await build(buildOptions, requireBuildRuntime(this.appConfig).getProfile("server-entry"));
145
- if (!result.success) {
146
- const errorMessages = result.logs.map((log) => log.message).join("\n");
147
- throw new Error(`Failed to bundle server entry file:
148
- ${errorMessages}`);
149
- }
150
- const outputPaths = result.outputs.length > 0 ? result.outputs.map((output) => output.path) : fileSystem.exists(serverEntryPath) ? [serverEntryPath] : [];
151
- recordServerEntryBuildCache({
152
- appConfig: this.appConfig,
153
- entryPath,
154
- buildResult: result,
155
- outputPaths
156
- });
157
- writeServerBundleDeployManifest(this.appConfig, serverEntryPath);
158
- this.logger.info("Server entry file bundled successfully");
159
- }
160
- /**
161
- * Generates a static build of the site for deployment.
162
- * @param dependencies.router - The initialized router
163
- * @param dependencies.routeRendererFactory - The route renderer factory
164
- * @param dependencies.staticRoutes - Explicit static routes registered via app.static()
165
- */
166
- async build(options, dependencies) {
167
- const { baseUrl: explicitBaseUrl, force = false } = options ?? {};
168
- const baseUrl = explicitBaseUrl ?? `http://${this.serveOptions.hostname || DEFAULT_ECOPAGES_HOSTNAME}:${this.serveOptions.port || DEFAULT_ECOPAGES_PORT}`;
169
- const preserveExportDirectory = this.prepareExportDirectory(force);
170
- await this.refreshRuntimeAssets();
171
- if (this.needsServerBundle) {
172
- await this.bundleServerEntry({ force });
140
+ this.logger.info('Server entry file bundled successfully');
173
141
  }
174
- await this.staticSiteGenerator.run({
175
- router: dependencies.router,
176
- baseUrl,
177
- routeRendererFactory: dependencies.routeRendererFactory,
178
- staticRoutes: dependencies.staticRoutes,
179
- force,
180
- preserveExportDirectory
181
- });
182
- if (process.env.ECOPAGES_BENCH === "1" && process.env.ECOPAGES_BENCH_VERBOSE !== "1") {
183
- this.logger.debug("Build completed");
184
- } else {
185
- this.logger.info("Build completed");
142
+ /**
143
+ * Generates a static build of the site for deployment.
144
+ * @param dependencies.router - The initialized router
145
+ * @param dependencies.routeRendererFactory - The route renderer factory
146
+ * @param dependencies.staticRoutes - Explicit static routes registered via app.static()
147
+ */
148
+ async build(options, dependencies) {
149
+ const { baseUrl: explicitBaseUrl, force = false } = options ?? {};
150
+ const baseUrl = explicitBaseUrl ??
151
+ `http://${this.serveOptions.hostname || DEFAULT_ECOPAGES_HOSTNAME}:${this.serveOptions.port || DEFAULT_ECOPAGES_PORT}`;
152
+ const preserveExportDirectory = this.prepareExportDirectory(force);
153
+ await this.refreshRuntimeAssets();
154
+ if (this.needsServerBundle) {
155
+ await this.bundleServerEntry({ force });
156
+ }
157
+ await this.staticSiteGenerator.run({
158
+ router: dependencies.router,
159
+ baseUrl,
160
+ routeRendererFactory: dependencies.routeRendererFactory,
161
+ staticRoutes: dependencies.staticRoutes,
162
+ force,
163
+ preserveExportDirectory,
164
+ });
165
+ if (process.env.ECOPAGES_BENCH === '1' && process.env.ECOPAGES_BENCH_VERBOSE !== '1') {
166
+ this.logger.debug('Build completed');
167
+ }
168
+ else {
169
+ this.logger.info('Build completed');
170
+ }
186
171
  }
187
- }
188
172
  }
189
- export {
190
- ServerStaticBuilder
191
- };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,100 +1,109 @@
1
- import { WebSocketServer } from "ws";
2
- import { appLogger } from "../../../global/app-logger.js";
3
- import { findWebSocketRoute } from "../../abstract/ws-pattern-matcher.js";
4
- import { createEcopagesSocket, invokeWebSocketHandlerHook, toWebSocketCloseInfo } from "./websocket-lifecycle.js";
5
- const attachedUpgradeServers = /* @__PURE__ */ new WeakSet();
1
+ import { WebSocketServer } from 'ws';
2
+ import { appLogger } from '../../../global/app-logger.js';
3
+ import { findWebSocketRoute } from '../../abstract/ws-pattern-matcher.js';
4
+ import { createEcopagesSocket, invokeWebSocketHandlerHook, toWebSocketCloseInfo } from './websocket-lifecycle.js';
5
+ const attachedUpgradeServers = new WeakSet();
6
6
  function adaptNodeWebSocket(ws, kind, params, search, context) {
7
- return createEcopagesSocket(
8
- {
9
- send: (data) => ws.send(data),
10
- close: (code, reason) => ws.close(code, reason)
11
- },
12
- { kind, params, search, context }
13
- );
7
+ return createEcopagesSocket({
8
+ send: (data) => ws.send(data),
9
+ close: (code, reason) => ws.close(code, reason),
10
+ }, { kind, params, search, context });
14
11
  }
15
12
  function toUpgradeRequest(runtimeOrigin, req) {
16
- const upgradeUrl = new URL(req.url ?? "/", runtimeOrigin);
17
- return new Request(upgradeUrl, {
18
- method: req.method,
19
- headers: req.headers
20
- });
13
+ const upgradeUrl = new URL(req.url ?? '/', runtimeOrigin);
14
+ return new Request(upgradeUrl, {
15
+ method: req.method,
16
+ headers: req.headers,
17
+ });
21
18
  }
22
19
  async function resolveNodeContext(request, handler, kind, params, search) {
23
- if (!handler.context) {
24
- return void 0;
25
- }
26
- try {
27
- return await handler.context({ request, kind, params, search });
28
- } catch (error) {
29
- appLogger.error(`[WS:${kind}] context() failed; closing connection.`, error);
30
- throw error;
31
- }
20
+ if (!handler.context) {
21
+ return undefined;
22
+ }
23
+ try {
24
+ return (await handler.context({ request, kind, params, search }));
25
+ }
26
+ catch (error) {
27
+ appLogger.error(`[WS:${kind}] context() failed; closing connection.`, error);
28
+ throw error;
29
+ }
32
30
  }
33
31
  async function setupNodeWebSocketConnection(ws, wsMatch, req, runtimeOrigin, search) {
34
- const handler = wsMatch.handler;
35
- const baseRequest = toUpgradeRequest(runtimeOrigin, req);
36
- let context;
37
- try {
38
- context = await resolveNodeContext(baseRequest, handler, wsMatch.kind, wsMatch.params, search);
39
- } catch {
40
- ws.close(1011, "context initialization failed");
41
- return;
42
- }
43
- const socket = adaptNodeWebSocket(ws, wsMatch.kind, wsMatch.params, search, context);
44
- try {
45
- await handler.onConnect?.(socket);
46
- } catch (error) {
47
- appLogger.error(`[WS:${wsMatch.kind}] onConnect failed:`, error);
48
- ws.close(1011, "onConnect failed");
49
- return;
50
- }
51
- ws.on("message", (msg, isBinary) => {
52
- const message = isBinary ? {
53
- kind: "binary",
54
- data: msg instanceof ArrayBuffer ? new Uint8Array(msg) : Array.isArray(msg) ? new Uint8Array(Buffer.concat(msg)) : new Uint8Array(msg)
55
- } : { kind: "text", text: msg.toString() };
56
- invokeWebSocketHandlerHook(wsMatch.kind, "onMessage", handler.onMessage?.(socket, message));
57
- });
58
- ws.on("close", (code, reason) => {
59
- const event = toWebSocketCloseInfo(code, reason.toString());
60
- invokeWebSocketHandlerHook(wsMatch.kind, "onClose", handler.onClose?.(socket, event));
61
- });
62
- ws.on("error", (err) => {
63
- appLogger.error(`[WS:${wsMatch.kind}] error:`, err);
64
- invokeWebSocketHandlerHook(wsMatch.kind, "onError", handler.onError?.(socket, err));
65
- });
32
+ const handler = wsMatch.handler;
33
+ const baseRequest = toUpgradeRequest(runtimeOrigin, req);
34
+ let context;
35
+ try {
36
+ context = await resolveNodeContext(baseRequest, handler, wsMatch.kind, wsMatch.params, search);
37
+ }
38
+ catch {
39
+ ws.close(1011, 'context initialization failed');
40
+ return;
41
+ }
42
+ const socket = adaptNodeWebSocket(ws, wsMatch.kind, wsMatch.params, search, context);
43
+ try {
44
+ await handler.onConnect?.(socket);
45
+ }
46
+ catch (error) {
47
+ appLogger.error(`[WS:${wsMatch.kind}] onConnect failed:`, error);
48
+ ws.close(1011, 'onConnect failed');
49
+ return;
50
+ }
51
+ ws.on('message', (msg, isBinary) => {
52
+ const message = isBinary
53
+ ? {
54
+ kind: 'binary',
55
+ data: msg instanceof ArrayBuffer
56
+ ? new Uint8Array(msg)
57
+ : Array.isArray(msg)
58
+ ? new Uint8Array(Buffer.concat(msg))
59
+ : new Uint8Array(msg),
60
+ }
61
+ : { kind: 'text', text: msg.toString() };
62
+ invokeWebSocketHandlerHook(wsMatch.kind, 'onMessage', handler.onMessage?.(socket, message));
63
+ });
64
+ ws.on('close', (code, reason) => {
65
+ const event = toWebSocketCloseInfo(code, reason.toString());
66
+ invokeWebSocketHandlerHook(wsMatch.kind, 'onClose', handler.onClose?.(socket, event));
67
+ });
68
+ ws.on('error', (err) => {
69
+ appLogger.error(`[WS:${wsMatch.kind}] error:`, err);
70
+ invokeWebSocketHandlerHook(wsMatch.kind, 'onError', handler.onError?.(socket, err));
71
+ });
66
72
  }
67
- function attachNodeHttpWebSocketUpgrades(server, options) {
68
- if (options.websocketHandlers.size === 0) {
69
- return;
70
- }
71
- if (attachedUpgradeServers.has(server)) {
72
- appLogger.warn("[WS] WebSocket upgrades already attached to this HTTP server; skipping duplicate attach.");
73
- return;
74
- }
75
- attachedUpgradeServers.add(server);
76
- const userWss = new WebSocketServer({ noServer: true });
77
- server.on("upgrade", (req, socket, head) => {
78
- if (options.preflight?.(req, socket, head)) {
79
- return;
73
+ /**
74
+ * Wires Ecopages user WebSocket routes onto a Node HTTP server's `upgrade` event.
75
+ *
76
+ * Used by the Node adapter in standalone mode and by host integrations such as
77
+ * the Vite plugin that embed Ecopages behind a foreign HTTP server.
78
+ */
79
+ export function attachNodeHttpWebSocketUpgrades(server, options) {
80
+ if (options.websocketHandlers.size === 0) {
81
+ return;
80
82
  }
81
- const url = new URL(req.url ?? "/", options.runtimeOrigin);
82
- const wsMatch = findWebSocketRoute(options.websocketHandlers, url.pathname);
83
- if (!wsMatch) {
84
- if (!options.passthroughUnmatched) {
85
- socket.destroy();
86
- }
87
- return;
83
+ if (attachedUpgradeServers.has(server)) {
84
+ appLogger.warn('[WS] WebSocket upgrades already attached to this HTTP server; skipping duplicate attach.');
85
+ return;
88
86
  }
89
- userWss.handleUpgrade(req, socket, head, (ws) => {
90
- const search = Object.fromEntries(url.searchParams.entries());
91
- void setupNodeWebSocketConnection(ws, wsMatch, req, options.runtimeOrigin, search).catch((error) => {
92
- appLogger.error(`[WS:${wsMatch.kind}] unexpected error:`, error);
93
- ws.close(1011, "internal error");
94
- });
87
+ attachedUpgradeServers.add(server);
88
+ const userWss = new WebSocketServer({ noServer: true });
89
+ server.on('upgrade', (req, socket, head) => {
90
+ if (options.preflight?.(req, socket, head)) {
91
+ return;
92
+ }
93
+ const url = new URL(req.url ?? '/', options.runtimeOrigin);
94
+ const wsMatch = findWebSocketRoute(options.websocketHandlers, url.pathname);
95
+ if (!wsMatch) {
96
+ if (!options.passthroughUnmatched) {
97
+ socket.destroy();
98
+ }
99
+ return;
100
+ }
101
+ userWss.handleUpgrade(req, socket, head, (ws) => {
102
+ const search = Object.fromEntries(url.searchParams.entries());
103
+ void setupNodeWebSocketConnection(ws, wsMatch, req, options.runtimeOrigin, search).catch((error) => {
104
+ appLogger.error(`[WS:${wsMatch.kind}] unexpected error:`, error);
105
+ ws.close(1011, 'internal error');
106
+ });
107
+ });
95
108
  });
96
- });
97
109
  }
98
- export {
99
- attachNodeHttpWebSocketUpgrades
100
- };