@ecopages/core 0.2.0-alpha.26 → 0.2.0-alpha.27

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 (550) hide show
  1. package/README.md +63 -7
  2. package/package.json +73 -249
  3. package/src/adapters/abstract/application-adapter.test.ts +172 -0
  4. package/src/adapters/abstract/application-adapter.ts +379 -0
  5. package/src/adapters/abstract/router-adapter.ts +30 -0
  6. package/src/adapters/abstract/server-adapter.ts +79 -0
  7. package/src/adapters/bun/client-bridge.ts +62 -0
  8. package/src/adapters/bun/create-app.ts +232 -0
  9. package/src/adapters/bun/hmr-manager.test.ts +265 -0
  10. package/src/adapters/bun/hmr-manager.ts +383 -0
  11. package/src/adapters/bun/index.ts +2 -0
  12. package/src/adapters/bun/server-adapter.ts +526 -0
  13. package/src/adapters/bun/server-lifecycle.ts +124 -0
  14. package/src/adapters/create-app.test.ts +10 -0
  15. package/src/adapters/create-app.ts +91 -0
  16. package/src/adapters/index.ts +2 -0
  17. package/src/adapters/node/create-app.test.ts +53 -0
  18. package/src/adapters/node/create-app.ts +183 -0
  19. package/src/adapters/node/node-client-bridge.test.ts +198 -0
  20. package/src/adapters/node/node-client-bridge.ts +79 -0
  21. package/src/adapters/node/node-hmr-manager.test.ts +320 -0
  22. package/src/adapters/node/node-hmr-manager.ts +355 -0
  23. package/src/adapters/node/server-adapter.ts +502 -0
  24. package/src/adapters/node/static-content-server.test.ts +60 -0
  25. package/src/adapters/node/static-content-server.ts +239 -0
  26. package/src/adapters/shared/api-response.test.ts +97 -0
  27. package/src/adapters/shared/api-response.ts +104 -0
  28. package/src/adapters/shared/application-adapter.ts +199 -0
  29. package/src/adapters/shared/define-api-handler.ts +66 -0
  30. package/src/adapters/shared/explicit-static-render-preparation.ts +58 -0
  31. package/src/adapters/shared/explicit-static-route-matcher.test.ts +381 -0
  32. package/src/adapters/shared/explicit-static-route-matcher.ts +131 -0
  33. package/src/adapters/shared/file-route-middleware-pipeline.test.ts +85 -0
  34. package/src/adapters/shared/file-route-middleware-pipeline.ts +118 -0
  35. package/src/adapters/shared/fs-server-response-factory.test.ts +176 -0
  36. package/src/adapters/shared/fs-server-response-factory.ts +96 -0
  37. package/src/adapters/shared/fs-server-response-matcher.test.ts +311 -0
  38. package/src/adapters/shared/fs-server-response-matcher.ts +240 -0
  39. package/src/adapters/shared/hmr-entrypoint-registrar.ts +149 -0
  40. package/src/adapters/shared/hmr-html-response.ts +52 -0
  41. package/src/adapters/shared/hmr-manager.contract.test.ts +228 -0
  42. package/src/adapters/shared/hmr-manager.dispatch.test.ts +220 -0
  43. package/src/adapters/shared/render-context.test.ts +150 -0
  44. package/src/adapters/shared/render-context.ts +123 -0
  45. package/src/adapters/shared/runtime-bootstrap.ts +79 -0
  46. package/src/adapters/shared/server-adapter.test.ts +130 -0
  47. package/src/adapters/shared/server-adapter.ts +562 -0
  48. package/src/adapters/shared/server-route-handler.test.ts +111 -0
  49. package/src/adapters/shared/server-route-handler.ts +153 -0
  50. package/src/adapters/shared/server-static-builder.test.ts +338 -0
  51. package/src/adapters/shared/server-static-builder.ts +170 -0
  52. package/src/build/build-adapter-serialization.test.ts +281 -0
  53. package/src/build/build-adapter.test.ts +1240 -0
  54. package/src/build/build-adapter.ts +1012 -0
  55. package/src/build/build-manifest.ts +54 -0
  56. package/src/build/build-types.ts +83 -0
  57. package/src/build/dev-build-coordinator.ts +220 -0
  58. package/src/build/esbuild-build-adapter.ts +660 -0
  59. package/src/build/runtime-build-executor.test.ts +81 -0
  60. package/src/build/runtime-build-executor.ts +40 -0
  61. package/src/build/runtime-specifier-alias-plugin.test.ts +67 -0
  62. package/src/build/runtime-specifier-alias-plugin.ts +62 -0
  63. package/src/build/runtime-specifier-aliases.ts +135 -0
  64. package/src/config/README.md +1 -1
  65. package/src/config/config-builder.test.ts +442 -0
  66. package/src/config/config-builder.ts +737 -0
  67. package/src/config/config-builder.typecheck.test.ts +96 -0
  68. package/src/config/{constants.d.ts → constants.ts} +22 -13
  69. package/src/dev/host-runtime.ts +34 -0
  70. package/src/dev/sc-server.ts +143 -0
  71. package/src/eco/eco.browser.test.ts +43 -0
  72. package/src/eco/eco.browser.ts +118 -0
  73. package/src/eco/eco.test.ts +654 -0
  74. package/src/eco/eco.ts +205 -0
  75. package/src/eco/eco.types.ts +221 -0
  76. package/src/eco/eco.utils.test.ts +219 -0
  77. package/src/eco/eco.utils.ts +5 -0
  78. package/src/eco/global-injector-map.test.ts +42 -0
  79. package/src/eco/global-injector-map.ts +112 -0
  80. package/src/eco/lazy-injector-map.test.ts +66 -0
  81. package/src/eco/lazy-injector-map.ts +120 -0
  82. package/src/eco/module-dependencies.test.ts +30 -0
  83. package/src/eco/module-dependencies.ts +75 -0
  84. package/src/errors/http-error.test.ts +134 -0
  85. package/src/errors/http-error.ts +72 -0
  86. package/src/errors/index.ts +3 -0
  87. package/src/errors/locals-access-error.ts +7 -0
  88. package/src/global/app-logger.ts +4 -0
  89. package/src/global/utils.test.ts +12 -0
  90. package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-HMR-Server-Integration-should-have-HMR-script-injected-in-page-1.png +0 -0
  91. package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-HMR-Server-Integration-should-load-fixture-app-page-1.png +0 -0
  92. package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-WebSocket-Connection-should-connect-to-correct-HMR-endpoint-1.png +0 -0
  93. package/src/hmr/client/hmr-runtime.ts +162 -0
  94. package/src/hmr/hmr-strategy.test.ts +124 -0
  95. package/src/hmr/hmr-strategy.ts +177 -0
  96. package/src/hmr/hmr.postcss.test.e2e.ts +41 -0
  97. package/src/hmr/hmr.test.e2e.ts +66 -0
  98. package/src/hmr/strategies/default-hmr-strategy.ts +60 -0
  99. package/src/hmr/strategies/js-hmr-strategy.test.ts +334 -0
  100. package/src/hmr/strategies/js-hmr-strategy.ts +314 -0
  101. package/src/index.browser.ts +3 -0
  102. package/src/index.ts +15 -0
  103. package/src/integrations/ghtml/ghtml-renderer.test.ts +253 -0
  104. package/src/integrations/ghtml/ghtml-renderer.ts +87 -0
  105. package/src/integrations/ghtml/ghtml.constants.ts +1 -0
  106. package/src/integrations/ghtml/ghtml.plugin.ts +28 -0
  107. package/src/plugins/alias-resolver-plugin.test.ts +41 -0
  108. package/src/plugins/alias-resolver-plugin.ts +63 -0
  109. package/src/plugins/eco-component-meta-plugin.test.ts +406 -0
  110. package/src/plugins/eco-component-meta-plugin.ts +494 -0
  111. package/src/plugins/foreign-jsx-override-plugin.test.ts +65 -0
  112. package/src/plugins/foreign-jsx-override-plugin.ts +67 -0
  113. package/src/plugins/integration-plugin.test.ts +151 -0
  114. package/src/plugins/integration-plugin.ts +323 -0
  115. package/src/plugins/processor.test.ts +148 -0
  116. package/src/plugins/processor.ts +257 -0
  117. package/src/plugins/{runtime-capability.d.ts → runtime-capability.ts} +8 -3
  118. package/src/plugins/source-transform.test.ts +82 -0
  119. package/src/plugins/source-transform.ts +123 -0
  120. package/src/route-renderer/GRAPH.md +81 -289
  121. package/src/route-renderer/README.md +67 -105
  122. package/src/route-renderer/orchestration/component-render-context.ts +325 -0
  123. package/src/route-renderer/orchestration/declared-ownership-graph.ts +62 -0
  124. package/src/route-renderer/orchestration/foreign-subtree-execution.service.ts +383 -0
  125. package/src/route-renderer/orchestration/integration-renderer.test.ts +2085 -0
  126. package/src/route-renderer/orchestration/integration-renderer.ts +1244 -0
  127. package/src/route-renderer/orchestration/ownership-planning.service.ts +97 -0
  128. package/src/route-renderer/orchestration/ownership-validation.service.ts +76 -0
  129. package/src/route-renderer/orchestration/processed-asset-dedupe.ts +25 -0
  130. package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.test.ts +324 -0
  131. package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.ts +294 -0
  132. package/src/route-renderer/orchestration/render-output.utils.ts +310 -0
  133. package/src/route-renderer/orchestration/route-render-orchestrator.prepare-render-options.test.ts +644 -0
  134. package/src/route-renderer/orchestration/route-render-orchestrator.test.ts +265 -0
  135. package/src/route-renderer/orchestration/route-render-orchestrator.ts +592 -0
  136. package/src/route-renderer/orchestration/template-serialization.test.ts +110 -0
  137. package/src/route-renderer/orchestration/template-serialization.ts +117 -0
  138. package/src/route-renderer/page-loading/component-dependency-collection.ts +202 -0
  139. package/src/route-renderer/page-loading/declared-asset-collection.ts +153 -0
  140. package/src/route-renderer/page-loading/dependency-resolver.test.ts +761 -0
  141. package/src/route-renderer/page-loading/dependency-resolver.ts +144 -0
  142. package/src/route-renderer/page-loading/ecopages-virtual-imports.ts +75 -0
  143. package/src/route-renderer/page-loading/lazy-entry-collection.ts +167 -0
  144. package/src/route-renderer/page-loading/lazy-trigger-planning.ts +74 -0
  145. package/src/route-renderer/page-loading/module-declaration-aggregation.ts +60 -0
  146. package/src/route-renderer/page-loading/module-declaration-scripts.ts +16 -0
  147. package/src/route-renderer/page-loading/page-dependency-bundling.ts +244 -0
  148. package/src/route-renderer/page-loading/page-module-loader.test.ts +183 -0
  149. package/src/route-renderer/page-loading/page-module-loader.ts +184 -0
  150. package/src/route-renderer/route-renderer.ts +133 -0
  151. package/src/router/README.md +16 -19
  152. package/src/router/client/link-intent.test.browser.ts +51 -0
  153. package/src/router/client/link-intent.ts +92 -0
  154. package/src/router/client/navigation-coordinator.test.ts +237 -0
  155. package/src/router/client/navigation-coordinator.ts +453 -0
  156. package/src/router/server/route-registry.test.ts +176 -0
  157. package/src/router/server/route-registry.ts +382 -0
  158. package/src/services/README.md +1 -2
  159. package/src/services/assets/asset-processing-service/asset-dependency-keys.ts +66 -0
  160. package/src/services/assets/asset-processing-service/asset-processing.service.test.ts +473 -0
  161. package/src/services/assets/asset-processing-service/asset-processing.service.ts +344 -0
  162. package/src/services/assets/asset-processing-service/asset.factory.test.ts +63 -0
  163. package/src/services/assets/asset-processing-service/asset.factory.ts +105 -0
  164. package/src/services/assets/asset-processing-service/assets.types.ts +128 -0
  165. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.test.ts +74 -0
  166. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.ts +96 -0
  167. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.test.ts +67 -0
  168. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.ts +78 -0
  169. package/src/services/assets/asset-processing-service/grouped-content-bundles.ts +104 -0
  170. package/src/services/assets/asset-processing-service/index.ts +6 -0
  171. package/src/services/assets/asset-processing-service/page-package.test.ts +100 -0
  172. package/src/services/assets/asset-processing-service/page-package.ts +93 -0
  173. package/src/services/assets/asset-processing-service/{processor.interface.d.ts → processor.interface.ts} +10 -5
  174. package/src/services/assets/asset-processing-service/processor.registry.ts +18 -0
  175. package/src/services/assets/asset-processing-service/processors/base/base-processor.test.ts +59 -0
  176. package/src/services/assets/asset-processing-service/processors/base/base-processor.ts +83 -0
  177. package/src/services/assets/asset-processing-service/processors/base/base-script-processor.ts +173 -0
  178. package/src/services/assets/asset-processing-service/processors/index.ts +5 -0
  179. package/src/services/assets/asset-processing-service/processors/script/content-script.processor.test.ts +195 -0
  180. package/src/services/assets/asset-processing-service/processors/script/content-script.processor.ts +137 -0
  181. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.test.ts +326 -0
  182. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.ts +116 -0
  183. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.test.ts +227 -0
  184. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.ts +89 -0
  185. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.test.ts +261 -0
  186. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.ts +72 -0
  187. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.ts +83 -0
  188. package/src/services/assets/asset-processing-service/ungrouped-dependency-processing.ts +65 -0
  189. package/src/services/assets/browser-bundle.service.test.ts +66 -0
  190. package/src/services/assets/browser-bundle.service.ts +109 -0
  191. package/src/services/cache/cache.types.ts +126 -0
  192. package/src/services/cache/index.ts +18 -0
  193. package/src/services/cache/memory-cache-store.test.ts +225 -0
  194. package/src/services/cache/memory-cache-store.ts +130 -0
  195. package/src/services/cache/page-cache-service.test.ts +175 -0
  196. package/src/services/cache/page-cache-service.ts +202 -0
  197. package/src/services/cache/page-request-cache-coordinator.service.test.ts +79 -0
  198. package/src/services/cache/page-request-cache-coordinator.service.ts +131 -0
  199. package/src/services/html/html-rewriter-provider.service.test.ts +183 -0
  200. package/src/services/html/html-rewriter-provider.service.ts +104 -0
  201. package/src/services/html/html-transformer.service.test.ts +476 -0
  202. package/src/services/html/html-transformer.service.ts +275 -0
  203. package/src/services/invalidation/development-invalidation.service.test.ts +87 -0
  204. package/src/services/invalidation/development-invalidation.service.ts +262 -0
  205. package/src/services/module-loading/app-module-loader.service.ts +9 -0
  206. package/src/services/module-loading/app-server-module-transpiler.service.test.ts +130 -0
  207. package/src/services/module-loading/app-server-module-transpiler.service.ts +141 -0
  208. package/src/services/module-loading/host-module-loader-registry.ts +15 -0
  209. package/src/services/module-loading/{module-loading-types.d.ts → module-loading-types.ts} +1 -0
  210. package/src/services/module-loading/node-bootstrap-plugin.test.ts +335 -0
  211. package/src/services/module-loading/node-bootstrap-plugin.ts +311 -0
  212. package/src/services/module-loading/page-module-import.service.test.ts +504 -0
  213. package/src/services/module-loading/page-module-import.service.ts +251 -0
  214. package/src/services/module-loading/server-module-transpiler.service.test.ts +243 -0
  215. package/src/services/module-loading/server-module-transpiler.service.ts +104 -0
  216. package/src/services/module-loading/source-module-support.ts +19 -0
  217. package/src/services/runtime-state/dev-graph.service.ts +217 -0
  218. package/src/services/runtime-state/entrypoint-dependency-graph.service.ts +136 -0
  219. package/src/services/runtime-state/server-invalidation-state.service.ts +68 -0
  220. package/src/services/validation/schema-validation-service.test.ts +223 -0
  221. package/src/services/validation/schema-validation-service.ts +204 -0
  222. package/src/services/validation/{standard-schema.types.d.ts → standard-schema.types.ts} +20 -17
  223. package/src/static-site-generator/static-site-generator.test.ts +408 -0
  224. package/src/static-site-generator/static-site-generator.ts +445 -0
  225. package/src/types/internal-types.ts +243 -0
  226. package/src/types/public-types.ts +1459 -0
  227. package/src/utils/deep-merge.test.ts +114 -0
  228. package/src/utils/deep-merge.ts +47 -0
  229. package/src/utils/hash.ts +5 -0
  230. package/src/utils/html-escaping.ts +9 -0
  231. package/src/utils/invariant.test.ts +22 -0
  232. package/src/utils/invariant.ts +15 -0
  233. package/src/utils/locals-utils.ts +37 -0
  234. package/src/utils/parse-cli-args.test.ts +69 -0
  235. package/src/utils/parse-cli-args.ts +105 -0
  236. package/src/utils/path-utils.module.ts +14 -0
  237. package/src/utils/path-utils.test.ts +15 -0
  238. package/src/utils/resolve-work-dir.ts +45 -0
  239. package/src/utils/runtime.ts +44 -0
  240. package/src/utils/server-utils.module.ts +67 -0
  241. package/src/utils/server-utils.test.ts +38 -0
  242. package/src/watchers/project-watcher.integration.test.ts +337 -0
  243. package/src/watchers/project-watcher.test-helpers.ts +42 -0
  244. package/src/watchers/project-watcher.test.ts +768 -0
  245. package/src/watchers/project-watcher.ts +357 -0
  246. package/CHANGELOG.md +0 -66
  247. package/src/adapters/abstract/application-adapter.d.ts +0 -194
  248. package/src/adapters/abstract/application-adapter.js +0 -121
  249. package/src/adapters/abstract/router-adapter.d.ts +0 -26
  250. package/src/adapters/abstract/router-adapter.js +0 -5
  251. package/src/adapters/abstract/server-adapter.d.ts +0 -69
  252. package/src/adapters/abstract/server-adapter.js +0 -15
  253. package/src/adapters/bun/client-bridge.d.ts +0 -34
  254. package/src/adapters/bun/client-bridge.js +0 -48
  255. package/src/adapters/bun/create-app.d.ts +0 -52
  256. package/src/adapters/bun/create-app.js +0 -116
  257. package/src/adapters/bun/hmr-manager.d.ts +0 -143
  258. package/src/adapters/bun/hmr-manager.js +0 -333
  259. package/src/adapters/bun/index.d.ts +0 -2
  260. package/src/adapters/bun/index.js +0 -8
  261. package/src/adapters/bun/server-adapter.d.ts +0 -155
  262. package/src/adapters/bun/server-adapter.js +0 -374
  263. package/src/adapters/bun/server-lifecycle.d.ts +0 -63
  264. package/src/adapters/bun/server-lifecycle.js +0 -92
  265. package/src/adapters/create-app.d.ts +0 -20
  266. package/src/adapters/create-app.js +0 -66
  267. package/src/adapters/index.d.ts +0 -2
  268. package/src/adapters/index.js +0 -8
  269. package/src/adapters/node/create-app.d.ts +0 -18
  270. package/src/adapters/node/create-app.js +0 -149
  271. package/src/adapters/node/node-client-bridge.d.ts +0 -26
  272. package/src/adapters/node/node-client-bridge.js +0 -66
  273. package/src/adapters/node/node-hmr-manager.d.ts +0 -133
  274. package/src/adapters/node/node-hmr-manager.js +0 -311
  275. package/src/adapters/node/server-adapter.d.ts +0 -162
  276. package/src/adapters/node/server-adapter.js +0 -368
  277. package/src/adapters/node/static-content-server.d.ts +0 -60
  278. package/src/adapters/node/static-content-server.js +0 -194
  279. package/src/adapters/shared/api-response.d.ts +0 -52
  280. package/src/adapters/shared/api-response.js +0 -96
  281. package/src/adapters/shared/application-adapter.d.ts +0 -18
  282. package/src/adapters/shared/application-adapter.js +0 -90
  283. package/src/adapters/shared/define-api-handler.d.ts +0 -25
  284. package/src/adapters/shared/define-api-handler.js +0 -15
  285. package/src/adapters/shared/explicit-static-route-matcher.d.ts +0 -38
  286. package/src/adapters/shared/explicit-static-route-matcher.js +0 -103
  287. package/src/adapters/shared/file-route-middleware-pipeline.d.ts +0 -65
  288. package/src/adapters/shared/file-route-middleware-pipeline.js +0 -99
  289. package/src/adapters/shared/fs-server-response-factory.d.ts +0 -19
  290. package/src/adapters/shared/fs-server-response-factory.js +0 -97
  291. package/src/adapters/shared/fs-server-response-matcher.d.ts +0 -67
  292. package/src/adapters/shared/fs-server-response-matcher.js +0 -147
  293. package/src/adapters/shared/hmr-entrypoint-registrar.d.ts +0 -55
  294. package/src/adapters/shared/hmr-entrypoint-registrar.js +0 -87
  295. package/src/adapters/shared/hmr-html-response.d.ts +0 -22
  296. package/src/adapters/shared/hmr-html-response.js +0 -32
  297. package/src/adapters/shared/render-context.d.ts +0 -15
  298. package/src/adapters/shared/render-context.js +0 -72
  299. package/src/adapters/shared/runtime-bootstrap.d.ts +0 -38
  300. package/src/adapters/shared/runtime-bootstrap.js +0 -43
  301. package/src/adapters/shared/server-adapter.d.ts +0 -97
  302. package/src/adapters/shared/server-adapter.js +0 -390
  303. package/src/adapters/shared/server-route-handler.d.ts +0 -89
  304. package/src/adapters/shared/server-route-handler.js +0 -111
  305. package/src/adapters/shared/server-static-builder.d.ts +0 -71
  306. package/src/adapters/shared/server-static-builder.js +0 -100
  307. package/src/build/build-adapter.d.ts +0 -239
  308. package/src/build/build-adapter.js +0 -642
  309. package/src/build/build-manifest.d.ts +0 -27
  310. package/src/build/build-manifest.js +0 -30
  311. package/src/build/build-types.d.ts +0 -57
  312. package/src/build/build-types.js +0 -0
  313. package/src/build/dev-build-coordinator.d.ts +0 -72
  314. package/src/build/dev-build-coordinator.js +0 -154
  315. package/src/build/esbuild-build-adapter.d.ts +0 -78
  316. package/src/build/esbuild-build-adapter.js +0 -505
  317. package/src/build/runtime-build-executor.d.ts +0 -14
  318. package/src/build/runtime-build-executor.js +0 -22
  319. package/src/build/runtime-specifier-alias-plugin.d.ts +0 -15
  320. package/src/build/runtime-specifier-alias-plugin.js +0 -35
  321. package/src/build/runtime-specifier-aliases.d.ts +0 -5
  322. package/src/build/runtime-specifier-aliases.js +0 -95
  323. package/src/config/config-builder.d.ts +0 -252
  324. package/src/config/config-builder.js +0 -603
  325. package/src/config/constants.js +0 -25
  326. package/src/dev/sc-server.d.ts +0 -30
  327. package/src/dev/sc-server.js +0 -111
  328. package/src/eco/eco.browser.d.ts +0 -2
  329. package/src/eco/eco.browser.js +0 -83
  330. package/src/eco/eco.d.ts +0 -9
  331. package/src/eco/eco.js +0 -85
  332. package/src/eco/eco.types.d.ts +0 -178
  333. package/src/eco/eco.types.js +0 -0
  334. package/src/eco/eco.utils.d.ts +0 -1
  335. package/src/eco/eco.utils.js +0 -10
  336. package/src/eco/global-injector-map.d.ts +0 -16
  337. package/src/eco/global-injector-map.js +0 -80
  338. package/src/eco/lazy-injector-map.d.ts +0 -8
  339. package/src/eco/lazy-injector-map.js +0 -70
  340. package/src/eco/module-dependencies.d.ts +0 -18
  341. package/src/eco/module-dependencies.js +0 -49
  342. package/src/errors/http-error.d.ts +0 -31
  343. package/src/errors/http-error.js +0 -50
  344. package/src/errors/index.d.ts +0 -2
  345. package/src/errors/index.js +0 -4
  346. package/src/errors/locals-access-error.d.ts +0 -4
  347. package/src/errors/locals-access-error.js +0 -9
  348. package/src/global/app-logger.d.ts +0 -2
  349. package/src/global/app-logger.js +0 -6
  350. package/src/hmr/client/hmr-runtime.d.ts +0 -5
  351. package/src/hmr/client/hmr-runtime.js +0 -117
  352. package/src/hmr/hmr-strategy.d.ts +0 -162
  353. package/src/hmr/hmr-strategy.js +0 -44
  354. package/src/hmr/hmr.postcss.test.e2e.d.ts +0 -1
  355. package/src/hmr/hmr.postcss.test.e2e.js +0 -31
  356. package/src/hmr/hmr.test.e2e.d.ts +0 -1
  357. package/src/hmr/hmr.test.e2e.js +0 -43
  358. package/src/hmr/strategies/default-hmr-strategy.d.ts +0 -43
  359. package/src/hmr/strategies/default-hmr-strategy.js +0 -34
  360. package/src/hmr/strategies/js-hmr-strategy.d.ts +0 -139
  361. package/src/hmr/strategies/js-hmr-strategy.js +0 -178
  362. package/src/index.browser.d.ts +0 -3
  363. package/src/index.browser.js +0 -4
  364. package/src/index.d.ts +0 -6
  365. package/src/index.js +0 -21
  366. package/src/integrations/ghtml/ghtml-renderer.d.ts +0 -20
  367. package/src/integrations/ghtml/ghtml-renderer.js +0 -63
  368. package/src/integrations/ghtml/ghtml.constants.d.ts +0 -1
  369. package/src/integrations/ghtml/ghtml.constants.js +0 -4
  370. package/src/integrations/ghtml/ghtml.plugin.d.ts +0 -16
  371. package/src/integrations/ghtml/ghtml.plugin.js +0 -20
  372. package/src/plugins/alias-resolver-plugin.d.ts +0 -2
  373. package/src/plugins/alias-resolver-plugin.js +0 -53
  374. package/src/plugins/eco-component-meta-plugin.d.ts +0 -108
  375. package/src/plugins/eco-component-meta-plugin.js +0 -163
  376. package/src/plugins/foreign-jsx-override-plugin.d.ts +0 -31
  377. package/src/plugins/foreign-jsx-override-plugin.js +0 -35
  378. package/src/plugins/integration-plugin.d.ts +0 -219
  379. package/src/plugins/integration-plugin.js +0 -196
  380. package/src/plugins/processor.d.ts +0 -95
  381. package/src/plugins/processor.js +0 -136
  382. package/src/plugins/runtime-capability.js +0 -0
  383. package/src/plugins/source-transform.d.ts +0 -46
  384. package/src/plugins/source-transform.js +0 -71
  385. package/src/route-renderer/orchestration/boundary-planning.service.d.ts +0 -25
  386. package/src/route-renderer/orchestration/boundary-planning.service.js +0 -97
  387. package/src/route-renderer/orchestration/component-render-context.d.ts +0 -83
  388. package/src/route-renderer/orchestration/component-render-context.js +0 -147
  389. package/src/route-renderer/orchestration/integration-renderer.d.ts +0 -556
  390. package/src/route-renderer/orchestration/integration-renderer.js +0 -932
  391. package/src/route-renderer/orchestration/page-packaging.service.d.ts +0 -16
  392. package/src/route-renderer/orchestration/page-packaging.service.js +0 -66
  393. package/src/route-renderer/orchestration/processed-asset-dedupe.d.ts +0 -2
  394. package/src/route-renderer/orchestration/processed-asset-dedupe.js +0 -23
  395. package/src/route-renderer/orchestration/queued-boundary-runtime.service.d.ts +0 -89
  396. package/src/route-renderer/orchestration/queued-boundary-runtime.service.js +0 -155
  397. package/src/route-renderer/orchestration/render-execution.service.d.ts +0 -43
  398. package/src/route-renderer/orchestration/render-execution.service.js +0 -106
  399. package/src/route-renderer/orchestration/render-output.utils.d.ts +0 -66
  400. package/src/route-renderer/orchestration/render-output.utils.js +0 -171
  401. package/src/route-renderer/orchestration/render-preparation.service.d.ts +0 -120
  402. package/src/route-renderer/orchestration/render-preparation.service.js +0 -364
  403. package/src/route-renderer/orchestration/route-shell-composer.service.d.ts +0 -50
  404. package/src/route-renderer/orchestration/route-shell-composer.service.js +0 -81
  405. package/src/route-renderer/orchestration/template-serialization.d.ts +0 -38
  406. package/src/route-renderer/orchestration/template-serialization.js +0 -45
  407. package/src/route-renderer/page-loading/component-dependency-collection.d.ts +0 -37
  408. package/src/route-renderer/page-loading/component-dependency-collection.js +0 -125
  409. package/src/route-renderer/page-loading/declared-asset-collection.d.ts +0 -24
  410. package/src/route-renderer/page-loading/declared-asset-collection.js +0 -106
  411. package/src/route-renderer/page-loading/dependency-resolver.d.ts +0 -35
  412. package/src/route-renderer/page-loading/dependency-resolver.js +0 -117
  413. package/src/route-renderer/page-loading/ecopages-virtual-imports.d.ts +0 -11
  414. package/src/route-renderer/page-loading/ecopages-virtual-imports.js +0 -57
  415. package/src/route-renderer/page-loading/lazy-entry-collection.d.ts +0 -45
  416. package/src/route-renderer/page-loading/lazy-entry-collection.js +0 -105
  417. package/src/route-renderer/page-loading/lazy-trigger-planning.d.ts +0 -19
  418. package/src/route-renderer/page-loading/lazy-trigger-planning.js +0 -40
  419. package/src/route-renderer/page-loading/module-declaration-aggregation.d.ts +0 -5
  420. package/src/route-renderer/page-loading/module-declaration-aggregation.js +0 -33
  421. package/src/route-renderer/page-loading/module-declaration-scripts.d.ts +0 -3
  422. package/src/route-renderer/page-loading/module-declaration-scripts.js +0 -18
  423. package/src/route-renderer/page-loading/page-dependency-bundling.d.ts +0 -13
  424. package/src/route-renderer/page-loading/page-dependency-bundling.js +0 -115
  425. package/src/route-renderer/page-loading/page-module-loader.d.ts +0 -90
  426. package/src/route-renderer/page-loading/page-module-loader.js +0 -127
  427. package/src/route-renderer/route-renderer.d.ts +0 -67
  428. package/src/route-renderer/route-renderer.js +0 -103
  429. package/src/router/client/link-intent.js +0 -34
  430. package/src/router/client/link-intent.test.browser.d.ts +0 -1
  431. package/src/router/client/link-intent.test.browser.js +0 -43
  432. package/src/router/client/navigation-coordinator.d.ts +0 -169
  433. package/src/router/client/navigation-coordinator.js +0 -215
  434. package/src/router/server/fs-router-scanner.d.ts +0 -41
  435. package/src/router/server/fs-router-scanner.js +0 -161
  436. package/src/router/server/fs-router.d.ts +0 -26
  437. package/src/router/server/fs-router.js +0 -100
  438. package/src/services/assets/asset-processing-service/asset-dependency-keys.d.ts +0 -3
  439. package/src/services/assets/asset-processing-service/asset-dependency-keys.js +0 -56
  440. package/src/services/assets/asset-processing-service/asset-processing.service.d.ts +0 -103
  441. package/src/services/assets/asset-processing-service/asset-processing.service.js +0 -285
  442. package/src/services/assets/asset-processing-service/asset.factory.d.ts +0 -17
  443. package/src/services/assets/asset-processing-service/asset.factory.js +0 -82
  444. package/src/services/assets/asset-processing-service/assets.types.d.ts +0 -100
  445. package/src/services/assets/asset-processing-service/assets.types.js +0 -0
  446. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.d.ts +0 -55
  447. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.js +0 -49
  448. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.d.ts +0 -20
  449. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.js +0 -41
  450. package/src/services/assets/asset-processing-service/grouped-content-bundles.d.ts +0 -30
  451. package/src/services/assets/asset-processing-service/grouped-content-bundles.js +0 -65
  452. package/src/services/assets/asset-processing-service/index.d.ts +0 -5
  453. package/src/services/assets/asset-processing-service/index.js +0 -5
  454. package/src/services/assets/asset-processing-service/processor.interface.js +0 -6
  455. package/src/services/assets/asset-processing-service/processor.registry.d.ts +0 -8
  456. package/src/services/assets/asset-processing-service/processor.registry.js +0 -15
  457. package/src/services/assets/asset-processing-service/processors/base/base-processor.d.ts +0 -24
  458. package/src/services/assets/asset-processing-service/processors/base/base-processor.js +0 -65
  459. package/src/services/assets/asset-processing-service/processors/base/base-script-processor.d.ts +0 -22
  460. package/src/services/assets/asset-processing-service/processors/base/base-script-processor.js +0 -136
  461. package/src/services/assets/asset-processing-service/processors/index.d.ts +0 -5
  462. package/src/services/assets/asset-processing-service/processors/index.js +0 -5
  463. package/src/services/assets/asset-processing-service/processors/script/content-script.processor.d.ts +0 -6
  464. package/src/services/assets/asset-processing-service/processors/script/content-script.processor.js +0 -116
  465. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.d.ts +0 -9
  466. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.js +0 -91
  467. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.d.ts +0 -7
  468. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.js +0 -77
  469. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.d.ts +0 -8
  470. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +0 -58
  471. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.d.ts +0 -9
  472. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +0 -67
  473. package/src/services/assets/asset-processing-service/ungrouped-dependency-processing.d.ts +0 -18
  474. package/src/services/assets/asset-processing-service/ungrouped-dependency-processing.js +0 -45
  475. package/src/services/assets/browser-bundle.service.d.ts +0 -73
  476. package/src/services/assets/browser-bundle.service.js +0 -41
  477. package/src/services/cache/cache.types.d.ts +0 -107
  478. package/src/services/cache/cache.types.js +0 -0
  479. package/src/services/cache/index.d.ts +0 -7
  480. package/src/services/cache/index.js +0 -7
  481. package/src/services/cache/memory-cache-store.d.ts +0 -42
  482. package/src/services/cache/memory-cache-store.js +0 -98
  483. package/src/services/cache/page-cache-service.d.ts +0 -70
  484. package/src/services/cache/page-cache-service.js +0 -152
  485. package/src/services/cache/page-request-cache-coordinator.service.d.ts +0 -75
  486. package/src/services/cache/page-request-cache-coordinator.service.js +0 -109
  487. package/src/services/html/html-rewriter-provider.service.d.ts +0 -37
  488. package/src/services/html/html-rewriter-provider.service.js +0 -68
  489. package/src/services/html/html-transformer.service.d.ts +0 -87
  490. package/src/services/html/html-transformer.service.js +0 -216
  491. package/src/services/invalidation/development-invalidation.service.d.ts +0 -74
  492. package/src/services/invalidation/development-invalidation.service.js +0 -190
  493. package/src/services/module-loading/app-module-loader.service.d.ts +0 -7
  494. package/src/services/module-loading/app-module-loader.service.js +0 -0
  495. package/src/services/module-loading/app-server-module-transpiler.service.d.ts +0 -24
  496. package/src/services/module-loading/app-server-module-transpiler.service.js +0 -115
  497. package/src/services/module-loading/host-module-loader-registry.d.ts +0 -4
  498. package/src/services/module-loading/host-module-loader-registry.js +0 -15
  499. package/src/services/module-loading/module-loading-types.js +0 -0
  500. package/src/services/module-loading/node-bootstrap-plugin.d.ts +0 -42
  501. package/src/services/module-loading/node-bootstrap-plugin.js +0 -204
  502. package/src/services/module-loading/page-module-import.service.d.ts +0 -76
  503. package/src/services/module-loading/page-module-import.service.js +0 -170
  504. package/src/services/module-loading/server-module-transpiler.service.d.ts +0 -63
  505. package/src/services/module-loading/server-module-transpiler.service.js +0 -64
  506. package/src/services/module-loading/source-module-support.d.ts +0 -5
  507. package/src/services/module-loading/source-module-support.js +0 -8
  508. package/src/services/runtime-state/dev-graph.service.d.ts +0 -118
  509. package/src/services/runtime-state/dev-graph.service.js +0 -162
  510. package/src/services/runtime-state/entrypoint-dependency-graph.service.d.ts +0 -41
  511. package/src/services/runtime-state/entrypoint-dependency-graph.service.js +0 -85
  512. package/src/services/runtime-state/runtime-specifier-registry.service.d.ts +0 -69
  513. package/src/services/runtime-state/runtime-specifier-registry.service.js +0 -37
  514. package/src/services/runtime-state/server-invalidation-state.service.d.ts +0 -26
  515. package/src/services/runtime-state/server-invalidation-state.service.js +0 -35
  516. package/src/services/validation/schema-validation-service.d.ts +0 -122
  517. package/src/services/validation/schema-validation-service.js +0 -101
  518. package/src/services/validation/standard-schema.types.js +0 -0
  519. package/src/static-site-generator/static-site-generator.d.ts +0 -105
  520. package/src/static-site-generator/static-site-generator.js +0 -349
  521. package/src/types/internal-types.d.ts +0 -231
  522. package/src/types/internal-types.js +0 -0
  523. package/src/types/public-types.d.ts +0 -1257
  524. package/src/types/public-types.js +0 -0
  525. package/src/utils/deep-merge.d.ts +0 -14
  526. package/src/utils/deep-merge.js +0 -32
  527. package/src/utils/hash.d.ts +0 -1
  528. package/src/utils/hash.js +0 -7
  529. package/src/utils/html-escaping.d.ts +0 -7
  530. package/src/utils/html-escaping.js +0 -6
  531. package/src/utils/html.js +0 -4
  532. package/src/utils/invariant.d.ts +0 -5
  533. package/src/utils/invariant.js +0 -11
  534. package/src/utils/locals-utils.d.ts +0 -15
  535. package/src/utils/locals-utils.js +0 -24
  536. package/src/utils/parse-cli-args.d.ts +0 -27
  537. package/src/utils/parse-cli-args.js +0 -62
  538. package/src/utils/path-utils.module.d.ts +0 -5
  539. package/src/utils/path-utils.module.js +0 -14
  540. package/src/utils/resolve-work-dir.d.ts +0 -11
  541. package/src/utils/resolve-work-dir.js +0 -31
  542. package/src/utils/runtime.d.ts +0 -11
  543. package/src/utils/runtime.js +0 -40
  544. package/src/utils/server-utils.module.d.ts +0 -19
  545. package/src/utils/server-utils.module.js +0 -56
  546. package/src/watchers/project-watcher.d.ts +0 -136
  547. package/src/watchers/project-watcher.js +0 -275
  548. package/src/watchers/project-watcher.test-helpers.d.ts +0 -4
  549. package/src/watchers/project-watcher.test-helpers.js +0 -52
  550. /package/src/utils/{html.d.ts → html.ts} +0 -0
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Ecopages HMR Runtime
3
+ * Injected into the browser to handle Hot Module Replacement updates.
4
+ */
5
+
6
+ import { getEcoNavigationRuntime } from '../../router/client/navigation-coordinator.ts';
7
+
8
+ interface HMRPayload {
9
+ type: 'reload' | 'error' | 'update' | 'css-update' | 'layout-update';
10
+ path?: string;
11
+ message?: string;
12
+ timestamp?: number;
13
+ }
14
+
15
+ (function () {
16
+ const WS_URL = 'ws://' + location.host + '/_hmr';
17
+ let socket: WebSocket;
18
+ let reconnectAttempts = 0;
19
+
20
+ function connect() {
21
+ socket = new WebSocket(WS_URL);
22
+
23
+ socket.addEventListener('open', () => {
24
+ console.log('[ecopages] HMR Connected');
25
+ reconnectAttempts = 0;
26
+ });
27
+
28
+ socket.addEventListener('message', async (event) => {
29
+ try {
30
+ const payload: HMRPayload = JSON.parse(event.data);
31
+ handleMessage(payload);
32
+ } catch (e) {
33
+ console.error('[ecopages] Invalid HMR message:', e);
34
+ }
35
+ });
36
+
37
+ socket.addEventListener('close', () => {
38
+ if (reconnectAttempts < 10) {
39
+ setTimeout(connect, 1000 * 2 ** reconnectAttempts);
40
+ reconnectAttempts++;
41
+ }
42
+ });
43
+ }
44
+
45
+ async function handleMessage(payload: HMRPayload) {
46
+ const navigationRuntime = getEcoNavigationRuntime(window);
47
+
48
+ switch (payload.type) {
49
+ case 'reload':
50
+ await waitForNavigationToSettle(navigationRuntime);
51
+ location.reload();
52
+ break;
53
+ case 'layout-update': {
54
+ await waitForNavigationToSettle(navigationRuntime);
55
+ if (
56
+ await navigationRuntime.reloadCurrentPage({ clearCache: true, moduleUrl: getActiveHmrModuleUrl() })
57
+ ) {
58
+ } else {
59
+ location.reload();
60
+ }
61
+ break;
62
+ }
63
+ case 'error':
64
+ console.error('[ecopages] HMR Error:', payload.message);
65
+ break;
66
+ case 'update':
67
+ if (payload.path) {
68
+ await applyUpdate(payload.path, payload.timestamp);
69
+ }
70
+ break;
71
+ case 'css-update':
72
+ if (payload.path) {
73
+ refreshStylesheet(payload.path);
74
+ }
75
+ break;
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Applies a module update by calling registered HMR handlers or re-importing the module.
81
+ * @param path - The module path to update
82
+ * @param timestamp - Optional timestamp for cache busting
83
+ */
84
+ async function applyUpdate(path: string, timestamp?: number) {
85
+ try {
86
+ const url = path + '?t=' + (timestamp || Date.now());
87
+ const handlers = window.__ECO_PAGES__?.hmrHandlers;
88
+ const navigationRuntime = getEcoNavigationRuntime(window);
89
+ await waitForNavigationToSettle(navigationRuntime);
90
+
91
+ if (handlers?.[path]) {
92
+ await handlers[path](url);
93
+ return;
94
+ }
95
+
96
+ await import(url);
97
+
98
+ if (await navigationRuntime.reloadCurrentPage({ clearCache: false })) {
99
+ }
100
+ } catch (e) {
101
+ console.error('[ecopages] Failed to apply HMR update:', e);
102
+ }
103
+ }
104
+
105
+ function getActiveHmrModuleUrl(): string | undefined {
106
+ const pageModule = window.__ECO_PAGES__?.page?.module;
107
+ if (pageModule && pageModule.includes('/assets/_hmr/')) {
108
+ return pageModule.split('?')[0];
109
+ }
110
+
111
+ const handlerPaths = Object.keys(window.__ECO_PAGES__?.hmrHandlers ?? {});
112
+ return handlerPaths[handlerPaths.length - 1];
113
+ }
114
+
115
+ async function waitForNavigationToSettle(navigationRuntime: ReturnType<typeof getEcoNavigationRuntime>) {
116
+ if (!navigationRuntime.hasPendingNavigationTransaction()) {
117
+ return;
118
+ }
119
+
120
+ await new Promise<void>((resolve) => {
121
+ const startedAt = performance.now();
122
+ const timeoutMs = 2000;
123
+
124
+ const poll = () => {
125
+ if (!navigationRuntime.hasPendingNavigationTransaction()) {
126
+ resolve();
127
+ return;
128
+ }
129
+
130
+ if (performance.now() - startedAt >= timeoutMs) {
131
+ resolve();
132
+ return;
133
+ }
134
+
135
+ requestAnimationFrame(poll);
136
+ };
137
+
138
+ requestAnimationFrame(poll);
139
+ });
140
+ }
141
+
142
+ /**
143
+ * Hot-reload CSS by updating stylesheet link href with cache-busting query param.
144
+ * This causes the browser to re-fetch the stylesheet without a full page reload.
145
+ */
146
+ function refreshStylesheet(path: string) {
147
+ const filename = path.split('/').pop() || '';
148
+ const links = document.querySelectorAll('link[rel="stylesheet"]');
149
+
150
+ links.forEach((link) => {
151
+ const href = (link as HTMLLinkElement).href;
152
+ if (href.includes(filename) || href.includes(path.replace(/^.*\/src\//, '/assets/'))) {
153
+ const url = new URL(href, location.origin);
154
+ url.searchParams.set('t', Date.now().toString());
155
+ (link as HTMLLinkElement).href = url.toString();
156
+ console.log('[ecopages] CSS updated:', filename);
157
+ }
158
+ });
159
+ }
160
+
161
+ connect();
162
+ })();
@@ -0,0 +1,124 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { HmrStrategy, HmrStrategyType, type HmrAction } from './hmr-strategy';
3
+
4
+ /**
5
+ * Mock strategy for testing the base class behavior
6
+ */
7
+ class MockStrategy extends HmrStrategy {
8
+ readonly type: HmrStrategyType;
9
+ override readonly priorityOffset: number;
10
+ private matchPattern: string;
11
+
12
+ constructor(options: { type: HmrStrategyType; priorityOffset?: number; matchPattern?: string }) {
13
+ super();
14
+ this.type = options.type;
15
+ this.priorityOffset = options.priorityOffset ?? 0;
16
+ this.matchPattern = options.matchPattern ?? '.';
17
+ }
18
+
19
+ matches(filePath: string): boolean {
20
+ return filePath.endsWith(this.matchPattern);
21
+ }
22
+
23
+ async process(filePath: string): Promise<HmrAction> {
24
+ return {
25
+ type: 'broadcast',
26
+ events: [{ type: 'update', path: filePath, timestamp: Date.now() }],
27
+ };
28
+ }
29
+ }
30
+
31
+ describe('HmrStrategyType', () => {
32
+ it('INTEGRATION has value 100', () => {
33
+ expect(HmrStrategyType.INTEGRATION).toBe(100);
34
+ });
35
+
36
+ it('ASSET has value 50', () => {
37
+ expect(HmrStrategyType.ASSET).toBe(50);
38
+ });
39
+
40
+ it('SCRIPT has value 25', () => {
41
+ expect(HmrStrategyType.SCRIPT).toBe(25);
42
+ });
43
+
44
+ it('FALLBACK has value 0', () => {
45
+ expect(HmrStrategyType.FALLBACK).toBe(0);
46
+ });
47
+
48
+ it('maintains priority order: INTEGRATION > ASSET > SCRIPT > FALLBACK', () => {
49
+ expect(HmrStrategyType.INTEGRATION).toBeGreaterThan(HmrStrategyType.ASSET);
50
+ expect(HmrStrategyType.ASSET).toBeGreaterThan(HmrStrategyType.SCRIPT);
51
+ expect(HmrStrategyType.SCRIPT).toBeGreaterThan(HmrStrategyType.FALLBACK);
52
+ });
53
+ });
54
+
55
+ describe('HmrStrategy', () => {
56
+ describe('priority', () => {
57
+ it('returns type value when priorityOffset is 0', () => {
58
+ const strategy = new MockStrategy({ type: HmrStrategyType.INTEGRATION });
59
+ expect(strategy.priority).toBe(100);
60
+ });
61
+
62
+ it('returns type + priorityOffset', () => {
63
+ const strategy = new MockStrategy({ type: HmrStrategyType.INTEGRATION, priorityOffset: 5 });
64
+ expect(strategy.priority).toBe(105);
65
+ });
66
+
67
+ it('allows negative priorityOffset', () => {
68
+ const strategy = new MockStrategy({ type: HmrStrategyType.ASSET, priorityOffset: -10 });
69
+ expect(strategy.priority).toBe(40);
70
+ });
71
+ });
72
+
73
+ describe('strategy selection by priority', () => {
74
+ it('higher priority strategies are selected first', () => {
75
+ const strategies = [
76
+ new MockStrategy({ type: HmrStrategyType.FALLBACK, matchPattern: '.test' }),
77
+ new MockStrategy({ type: HmrStrategyType.INTEGRATION, matchPattern: '.test' }),
78
+ new MockStrategy({ type: HmrStrategyType.SCRIPT, matchPattern: '.test' }),
79
+ new MockStrategy({ type: HmrStrategyType.ASSET, matchPattern: '.test' }),
80
+ ];
81
+
82
+ const sorted = [...strategies].sort((a, b) => b.priority - a.priority);
83
+
84
+ expect(sorted[0].type).toBe(HmrStrategyType.INTEGRATION);
85
+ expect(sorted[1].type).toBe(HmrStrategyType.ASSET);
86
+ expect(sorted[2].type).toBe(HmrStrategyType.SCRIPT);
87
+ expect(sorted[3].type).toBe(HmrStrategyType.FALLBACK);
88
+ });
89
+
90
+ it('priorityOffset can override default ordering', () => {
91
+ const assetWithHighOffset = new MockStrategy({
92
+ type: HmrStrategyType.ASSET,
93
+ priorityOffset: 60,
94
+ matchPattern: '.test',
95
+ });
96
+ const integration = new MockStrategy({
97
+ type: HmrStrategyType.INTEGRATION,
98
+ matchPattern: '.test',
99
+ });
100
+
101
+ expect(assetWithHighOffset.priority).toBeGreaterThan(integration.priority);
102
+ });
103
+ });
104
+
105
+ describe('matches', () => {
106
+ it('should be implemented by subclasses', () => {
107
+ const strategy = new MockStrategy({ type: HmrStrategyType.ASSET, matchPattern: '.css' });
108
+ expect(strategy.matches('styles.css')).toBe(true);
109
+ expect(strategy.matches('script.js')).toBe(false);
110
+ });
111
+ });
112
+
113
+ describe('process', () => {
114
+ it('should return an HmrAction', async () => {
115
+ const strategy = new MockStrategy({ type: HmrStrategyType.ASSET });
116
+ const action = await strategy.process('/path/to/file.');
117
+
118
+ expect(action.type).toBe('broadcast');
119
+ expect(action.events).toBeDefined();
120
+ expect(action.events?.[0].type).toBe('update');
121
+ expect(action.events?.[0].path).toBe('/path/to/file.');
122
+ });
123
+ });
124
+ });
@@ -0,0 +1,177 @@
1
+ import type { ClientBridgeEvent } from '../types/public-types.ts';
2
+
3
+ /**
4
+ * HMR Strategy Pattern
5
+ *
6
+ * This module defines the base classes and types for Hot Module Replacement strategies.
7
+ * Each strategy handles a specific type of file change and determines how to process it.
8
+ *
9
+ * @module
10
+ * @example
11
+ * ```typescript
12
+ * class CustomHmrStrategy extends HmrStrategy {
13
+ * readonly type = HmrStrategyType.INTEGRATION;
14
+ *
15
+ * matches(filePath: string): boolean {
16
+ * return filePath.endsWith('.custom');
17
+ * }
18
+ *
19
+ * async process(filePath: string): Promise<HmrAction> {
20
+ * return {
21
+ * type: 'broadcast',
22
+ * events: [{ type: 'update', path: filePath, timestamp: Date.now() }],
23
+ * };
24
+ * }
25
+ * }
26
+ * ```
27
+ */
28
+
29
+ /**
30
+ * Defines the category of an HMR strategy, which determines its execution priority.
31
+ * Strategies are evaluated in descending order: INTEGRATION → ASSET → SCRIPT → FALLBACK.
32
+ *
33
+ * @remarks
34
+ * The numeric values represent base priorities. Strategies can fine-tune their priority
35
+ * using the `priorityOffset` property.
36
+ */
37
+ export const HmrStrategyType = {
38
+ /**
39
+ * Integration-specific strategies (React, Lit, etc.)
40
+ * Highest priority to allow framework-specific HMR handling.
41
+ */
42
+ INTEGRATION: 100,
43
+
44
+ /**
45
+ * Asset processing strategies (CSS, images, etc.)
46
+ * High priority for specialized asset handling.
47
+ */
48
+ ASSET: 50,
49
+
50
+ /**
51
+ * Generic script bundling strategies (JS/TS)
52
+ * Medium priority for standard script processing.
53
+ */
54
+ SCRIPT: 25,
55
+
56
+ /**
57
+ * Fallback strategy for unhandled file types.
58
+ * Lowest priority, triggers full page reload.
59
+ */
60
+ FALLBACK: 0,
61
+ } as const;
62
+
63
+ export type HmrStrategyType = (typeof HmrStrategyType)[keyof typeof HmrStrategyType];
64
+
65
+ /**
66
+ * Represents an action to be taken after processing a file change.
67
+ */
68
+ export interface HmrAction {
69
+ /**
70
+ * Whether to broadcast an HMR event to connected clients.
71
+ */
72
+ type: 'broadcast' | 'none';
73
+
74
+ /**
75
+ * The HMR events to broadcast, if type is 'broadcast'.
76
+ * Multiple events may be broadcast in one action.
77
+ */
78
+ events?: ClientBridgeEvent[];
79
+ }
80
+
81
+ /**
82
+ * Base class for HMR strategies.
83
+ *
84
+ * Each strategy handles a specific type of file change and determines how to process it.
85
+ * Strategies are selected based on their priority (higher values are evaluated first) and
86
+ * whether they match the changed file path.
87
+ *
88
+ * @remarks
89
+ * Strategies are expected to be stateless and idempotent. The same file change
90
+ * should produce the same result when processed by the same strategy.
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * class MyAssetStrategy extends HmrStrategy {
95
+ * readonly type = HmrStrategyType.ASSET;
96
+ * readonly priorityOffset = 5;
97
+ *
98
+ * matches(filePath: string): boolean {
99
+ * return /\.(png|jpg|svg)$/.test(filePath);
100
+ * }
101
+ *
102
+ * async process(filePath: string): Promise<HmrAction> {
103
+ * await this.optimizeImage(filePath);
104
+ * return {
105
+ * type: 'broadcast',
106
+ * events: [{ type: 'update', path: filePath, timestamp: Date.now() }]
107
+ * };
108
+ * }
109
+ * }
110
+ * ```
111
+ */
112
+ export abstract class HmrStrategy {
113
+ /**
114
+ * The category of this strategy, determining its base priority.
115
+ */
116
+ abstract readonly type: HmrStrategyType;
117
+
118
+ /**
119
+ * Optional offset to fine-tune priority within the same category.
120
+ * Useful when multiple strategies share the same type.
121
+ *
122
+ * @defaultValue 0
123
+ */
124
+ readonly priorityOffset: number = 0;
125
+
126
+ /**
127
+ * Computed priority for strategy selection.
128
+ * Higher values are evaluated first.
129
+ *
130
+ * @returns The sum of the strategy type and priority offset
131
+ */
132
+ get priority(): number {
133
+ return this.type + this.priorityOffset;
134
+ }
135
+
136
+ /**
137
+ * Determines if this strategy can handle the given file path.
138
+ *
139
+ * @param filePath - Absolute path to the changed file
140
+ * @returns `true` when this strategy should process the file
141
+ *
142
+ * @example
143
+ * ```typescript
144
+ * matches(filePath: string): boolean {
145
+ * return filePath.endsWith('.css');
146
+ * }
147
+ * ```
148
+ */
149
+ abstract matches(filePath: string): boolean;
150
+
151
+ /**
152
+ * Processes a file change and returns the action to take.
153
+ *
154
+ * This method may perform side effects such as:
155
+ * - Rebuilding files
156
+ * - Writing to disk
157
+ * - Transforming code
158
+ * - Updating caches
159
+ *
160
+ * @param filePath - Absolute path to the changed file
161
+ * @returns Action to take (broadcast event or none)
162
+ *
163
+ * @example
164
+ * ```typescript
165
+ * async process(filePath: string): Promise<HmrAction> {
166
+ * const processed = await this.transform(filePath);
167
+ * await Bun.write(outputPath, processed);
168
+ *
169
+ * return {
170
+ * type: 'broadcast',
171
+ * events: [{ type: 'update', path: outputPath, timestamp: Date.now() }]
172
+ * };
173
+ * }
174
+ * ```
175
+ */
176
+ abstract process(filePath: string): Promise<HmrAction>;
177
+ }
@@ -0,0 +1,41 @@
1
+ import { test, expect } from '@playwright/test';
2
+ import { readFileSync } from 'node:fs';
3
+ import { writeFile } from 'node:fs/promises';
4
+ import { resolve } from 'node:path';
5
+
6
+ const FIXTURE_DIR = resolve(process.cwd(), 'packages/core/__fixtures__/app');
7
+ const TEST_CSS_FILE = resolve(FIXTURE_DIR, 'src/pages/postcss-hmr.css');
8
+
9
+ test.describe('HMR E2E PostCSS', () => {
10
+ test('should hot-update processor-owned CSS without a full page reload', async ({ page }) => {
11
+ const originalCss = readFileSync(TEST_CSS_FILE, 'utf-8');
12
+ const title = page.locator('.postcss-title').first();
13
+
14
+ try {
15
+ await page.goto('/postcss-hmr', { waitUntil: 'networkidle' });
16
+ await expect(title).toBeVisible();
17
+
18
+ const initialColor = await title.evaluate((el) => getComputedStyle(el).color);
19
+ expect(initialColor).toBeTruthy();
20
+ await page.evaluate(() => {
21
+ (window as typeof window & { __postcssReloadProbe?: string }).__postcssReloadProbe = 'before-change';
22
+ });
23
+
24
+ const modifiedCss = originalCss.replace('.postcss-title {', '.postcss-title {\n\tcolor: rgb(255, 0, 0);');
25
+
26
+ await writeFile(TEST_CSS_FILE, modifiedCss, { flush: true });
27
+
28
+ await expect
29
+ .poll(async () => title.evaluate((el) => getComputedStyle(el).color), { timeout: 10000 })
30
+ .toBe('rgb(255, 0, 0)');
31
+
32
+ await expect(
33
+ page.evaluate(
34
+ () => (window as typeof window & { __postcssReloadProbe?: string }).__postcssReloadProbe ?? null,
35
+ ),
36
+ ).resolves.toBe('before-change');
37
+ } finally {
38
+ await writeFile(TEST_CSS_FILE, originalCss, { flush: true });
39
+ }
40
+ });
41
+ });
@@ -0,0 +1,66 @@
1
+ import { test, expect } from '@playwright/test';
2
+ import { readFileSync } from 'node:fs';
3
+ import { writeFile } from 'node:fs/promises';
4
+ import { resolve } from 'node:path';
5
+
6
+ /**
7
+ * HMR E2E Tests
8
+ *
9
+ * True end-to-end tests for Hot Module Replacement using Playwright.
10
+ * These tests modify actual source files and verify the browser updates.
11
+ *
12
+ * Run with: bunx playwright test packages/core/src/hmr/hmr.e2e.test.ts
13
+ */
14
+
15
+ const FIXTURE_DIR = resolve(process.cwd(), 'packages/core/__fixtures__/app');
16
+ const TEST_CSS_FILE = resolve(FIXTURE_DIR, 'src/pages/index.css');
17
+
18
+ test.describe('HMR E2E', () => {
19
+ test('should load page with .main-title element', async ({ page }) => {
20
+ await page.goto('/', { waitUntil: 'networkidle' });
21
+ const title = page.locator('.main-title').first();
22
+ await expect(title).toBeVisible();
23
+ });
24
+
25
+ test('should connect to HMR WebSocket', async ({ page }) => {
26
+ const socketPromise = page.waitForEvent('websocket', {
27
+ predicate: (socket) => socket.url().endsWith('/_hmr'),
28
+ timeout: 10000,
29
+ });
30
+
31
+ await page.goto('/', { waitUntil: 'networkidle' });
32
+ const socket = await socketPromise;
33
+
34
+ expect(socket.url()).toMatch(/\/_hmr$/);
35
+ });
36
+
37
+ test('should fall back to a full page reload when raw CSS file changes', async ({ page }) => {
38
+ const originalCss = readFileSync(TEST_CSS_FILE, 'utf-8');
39
+ const title = page.locator('.main-title').first();
40
+
41
+ try {
42
+ await page.goto('/', { waitUntil: 'networkidle' });
43
+ await expect(title).toBeVisible();
44
+
45
+ const initialColor = await title.evaluate((el) => getComputedStyle(el).color);
46
+ expect(initialColor).toBeTruthy();
47
+
48
+ const modifiedCss = originalCss.replace('.main-title {', '.main-title {\n\tcolor: rgb(255, 0, 0);');
49
+ const reloadPromise = page.waitForEvent('framenavigated', {
50
+ predicate: (frame) => frame === page.mainFrame(),
51
+ timeout: 10000,
52
+ });
53
+
54
+ await writeFile(TEST_CSS_FILE, modifiedCss, { flush: true });
55
+
56
+ await reloadPromise;
57
+ await page.waitForLoadState('networkidle');
58
+
59
+ await expect
60
+ .poll(async () => title.evaluate((el) => getComputedStyle(el).color), { timeout: 10000 })
61
+ .toBe('rgb(255, 0, 0)');
62
+ } finally {
63
+ await writeFile(TEST_CSS_FILE, originalCss, { flush: true });
64
+ }
65
+ });
66
+ });
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Default HMR Strategy
3
+ *
4
+ * Fallback strategy for file types that don't have specialized handling.
5
+ * Triggers a full page reload to ensure changes are reflected.
6
+ *
7
+ * @module
8
+ */
9
+
10
+ import { HmrStrategy, HmrStrategyType, type HmrAction } from '../hmr-strategy.ts';
11
+
12
+ /**
13
+ * Default fallback strategy for unhandled file types.
14
+ *
15
+ * This strategy matches all files and triggers a full page reload.
16
+ * It has the lowest priority (FALLBACK) and acts as a catch-all when
17
+ * no other strategy matches the changed file.
18
+ *
19
+ * @remarks
20
+ * This strategy ensures that all file changes result in some action,
21
+ * even if we don't have specialized handling for that file type.
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const strategy = new DefaultHmrStrategy();
26
+ * const action = await strategy.process('/path/to/unknown.file');
27
+ * ```
28
+ */
29
+ export class DefaultHmrStrategy extends HmrStrategy {
30
+ readonly type = HmrStrategyType.FALLBACK;
31
+
32
+ /**
33
+ * Matches all file paths.
34
+ *
35
+ * @param _filePath - Absolute path to the changed file (unused)
36
+ * @returns Always returns true as this is a catch-all strategy
37
+ */
38
+ matches(_filePath: string): boolean {
39
+ return true;
40
+ }
41
+
42
+ /**
43
+ * Processes a file change by triggering a full page reload.
44
+ *
45
+ * @param filePath - Absolute path to the changed file
46
+ * @returns Action to broadcast a reload event
47
+ */
48
+ async process(filePath: string): Promise<HmrAction> {
49
+ return {
50
+ type: 'broadcast',
51
+ events: [
52
+ {
53
+ type: 'reload',
54
+ path: filePath,
55
+ message: 'fallback-strategy',
56
+ },
57
+ ],
58
+ };
59
+ }
60
+ }