@ecopages/core 0.2.0-alpha.4 → 0.2.0-alpha.6

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 (418) hide show
  1. package/README.md +213 -12
  2. package/package.json +100 -188
  3. package/src/adapters/README.md +39 -0
  4. package/src/adapters/bun/hmr-manager.test.ts +267 -0
  5. package/src/adapters/bun/hmr-manager.ts +181 -68
  6. package/src/adapters/bun/index.ts +1 -2
  7. package/src/adapters/bun/server-adapter.ts +41 -34
  8. package/src/adapters/bun/server-lifecycle.ts +40 -70
  9. package/src/adapters/index.ts +1 -1
  10. package/src/adapters/node/bootstrap-dependency-resolver.test.ts +282 -0
  11. package/src/adapters/node/bootstrap-dependency-resolver.ts +301 -0
  12. package/src/adapters/node/index.ts +7 -0
  13. package/src/adapters/node/node-client-bridge.test.ts +198 -0
  14. package/src/adapters/node/node-hmr-manager.test.ts +322 -0
  15. package/src/adapters/node/node-hmr-manager.ts +208 -116
  16. package/src/adapters/node/runtime-adapter.test.ts +868 -0
  17. package/src/adapters/node/runtime-adapter.ts +439 -0
  18. package/src/adapters/node/server-adapter.ts +31 -104
  19. package/src/adapters/node/static-content-server.test.ts +60 -0
  20. package/src/adapters/node/static-content-server.ts +36 -0
  21. package/src/adapters/node/write-runtime-manifest.ts +38 -0
  22. package/src/adapters/shared/api-response.test.ts +97 -0
  23. package/src/{define-api-handler.ts → adapters/shared/define-api-handler.ts} +1 -1
  24. package/src/adapters/shared/explicit-static-route-matcher.test.ts +381 -0
  25. package/src/adapters/shared/explicit-static-route-matcher.ts +7 -1
  26. package/src/adapters/shared/file-route-middleware-pipeline.test.ts +90 -0
  27. package/src/adapters/shared/file-route-middleware-pipeline.ts +6 -2
  28. package/src/adapters/shared/fs-server-response-factory.test.ts +187 -0
  29. package/src/adapters/shared/fs-server-response-matcher.test.ts +286 -0
  30. package/src/adapters/shared/fs-server-response-matcher.ts +17 -10
  31. package/src/adapters/shared/hmr-entrypoint-registrar.ts +149 -0
  32. package/src/adapters/shared/hmr-html-response.ts +52 -0
  33. package/src/adapters/shared/hmr-manager.contract.test.ts +196 -0
  34. package/src/adapters/shared/hmr-manager.dispatch.test.ts +220 -0
  35. package/src/adapters/shared/render-context.test.ts +146 -0
  36. package/src/adapters/shared/render-context.ts +21 -6
  37. package/src/adapters/shared/runtime-bootstrap.ts +79 -0
  38. package/src/adapters/shared/server-adapter.test.ts +77 -0
  39. package/src/adapters/shared/server-adapter.ts +51 -4
  40. package/src/adapters/shared/server-route-handler.test.ts +110 -0
  41. package/src/adapters/shared/server-route-handler.ts +5 -18
  42. package/src/adapters/shared/server-static-builder.test.ts +316 -0
  43. package/src/adapters/shared/server-static-builder.ts +92 -8
  44. package/src/build/README.md +101 -0
  45. package/src/build/build-adapter-serialization.test.ts +268 -0
  46. package/src/build/build-adapter.test.ts +815 -0
  47. package/src/build/build-adapter.ts +235 -6
  48. package/src/build/build-manifest.ts +54 -0
  49. package/src/build/dev-build-coordinator.ts +221 -0
  50. package/src/build/esbuild-build-adapter.ts +132 -83
  51. package/src/build/runtime-build-executor.ts +34 -0
  52. package/src/build/runtime-specifier-alias-plugin.test.ts +43 -0
  53. package/src/build/runtime-specifier-alias-plugin.ts +58 -0
  54. package/src/config/README.md +33 -0
  55. package/src/config/config-builder.test.ts +410 -0
  56. package/src/config/config-builder.ts +281 -49
  57. package/src/constants.ts +15 -0
  58. package/src/declarations.d.ts +18 -13
  59. package/src/eco/README.md +70 -16
  60. package/src/eco/component-render-context.ts +39 -17
  61. package/src/eco/eco.test.ts +678 -0
  62. package/src/eco/eco.ts +29 -8
  63. package/src/eco/eco.types.ts +20 -1
  64. package/src/eco/eco.utils.test.ts +124 -0
  65. package/src/eco/global-injector-map.test.ts +42 -0
  66. package/src/eco/lazy-injector-map.test.ts +66 -0
  67. package/src/eco/module-dependencies.test.ts +30 -0
  68. package/src/errors/http-error.test.ts +134 -0
  69. package/src/global/utils.test.ts +12 -0
  70. package/src/hmr/README.md +26 -0
  71. 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
  72. package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-HMR-Server-Integration-should-load-fixture-app-page-1.png +0 -0
  73. package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-WebSocket-Connection-should-connect-to-correct-HMR-endpoint-1.png +0 -0
  74. package/src/hmr/client/hmr-runtime.ts +38 -7
  75. package/src/hmr/hmr-strategy.test.ts +124 -0
  76. package/src/hmr/hmr.postcss.test.e2e.ts +41 -0
  77. package/src/hmr/hmr.test.e2e.ts +29 -38
  78. package/src/hmr/strategies/js-hmr-strategy.test.ts +335 -0
  79. package/src/hmr/strategies/js-hmr-strategy.ts +115 -115
  80. package/src/index.ts +1 -1
  81. package/src/integrations/ghtml/ghtml-renderer.test.ts +63 -0
  82. package/src/integrations/ghtml/ghtml-renderer.ts +4 -1
  83. package/src/internal-types.ts +39 -19
  84. package/src/plugins/README.md +34 -0
  85. package/src/plugins/alias-resolver-plugin.test.ts +41 -0
  86. package/src/plugins/alias-resolver-plugin.ts +21 -3
  87. package/src/plugins/eco-component-meta-plugin.test.ts +380 -0
  88. package/src/plugins/eco-component-meta-plugin.ts +10 -3
  89. package/src/plugins/integration-plugin.test.ts +111 -0
  90. package/src/plugins/integration-plugin.ts +45 -3
  91. package/src/plugins/processor.test.ts +148 -0
  92. package/src/plugins/processor.ts +22 -2
  93. package/src/plugins/runtime-capability.ts +14 -0
  94. package/src/public-types.ts +73 -16
  95. package/src/route-renderer/GRAPH.md +16 -20
  96. package/src/route-renderer/README.md +8 -21
  97. package/src/route-renderer/component-graph/component-graph-executor.test.ts +41 -0
  98. package/src/route-renderer/component-graph/component-graph.test.ts +63 -0
  99. package/src/route-renderer/component-graph/component-marker.test.ts +73 -0
  100. package/src/route-renderer/component-graph/component-reference.ts +29 -0
  101. package/src/route-renderer/component-graph/marker-graph-resolver.test.ts +135 -0
  102. package/src/route-renderer/{marker-graph-resolver.ts → component-graph/marker-graph-resolver.ts} +11 -9
  103. package/src/route-renderer/orchestration/integration-renderer.test.ts +936 -0
  104. package/src/route-renderer/{integration-renderer.ts → orchestration/integration-renderer.ts} +113 -19
  105. package/src/route-renderer/orchestration/render-execution.service.test.ts +97 -0
  106. package/src/route-renderer/{render-execution.service.ts → orchestration/render-execution.service.ts} +109 -37
  107. package/src/route-renderer/orchestration/render-preparation.service.test.ts +235 -0
  108. package/src/route-renderer/{render-preparation.service.ts → orchestration/render-preparation.service.ts} +127 -9
  109. package/src/route-renderer/page-loading/dependency-resolver.test.ts +345 -0
  110. package/src/route-renderer/{dependency-resolver.ts → page-loading/dependency-resolver.ts} +28 -12
  111. package/src/route-renderer/page-loading/page-module-loader.test.ts +96 -0
  112. package/src/route-renderer/{page-module-loader.ts → page-loading/page-module-loader.ts} +49 -21
  113. package/src/route-renderer/route-renderer.ts +36 -1
  114. package/src/router/README.md +26 -0
  115. package/src/router/client/link-intent.d.ts +53 -0
  116. package/src/router/client/link-intent.test.browser.ts +51 -0
  117. package/src/router/client/link-intent.ts +92 -0
  118. package/src/router/client/navigation-coordinator.test.ts +237 -0
  119. package/src/router/client/navigation-coordinator.ts +433 -0
  120. package/src/router/server/fs-router-scanner.test.ts +83 -0
  121. package/src/router/{fs-router-scanner.ts → server/fs-router-scanner.ts} +12 -10
  122. package/src/router/server/fs-router.test.ts +214 -0
  123. package/src/router/{fs-router.ts → server/fs-router.ts} +2 -2
  124. package/src/services/README.md +29 -0
  125. package/src/services/assets/asset-processing-service/asset-processing.service.test.ts +385 -0
  126. package/src/services/{asset-processing-service → assets/asset-processing-service}/asset-processing.service.ts +101 -6
  127. package/src/services/assets/asset-processing-service/asset.factory.test.ts +63 -0
  128. package/src/services/{asset-processing-service → assets/asset-processing-service}/asset.factory.ts +2 -2
  129. package/src/services/{asset-processing-service → assets/asset-processing-service}/assets.types.ts +2 -1
  130. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.test.ts +72 -0
  131. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.ts +95 -0
  132. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.test.ts +67 -0
  133. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.ts +78 -0
  134. package/src/services/{asset-processing-service → assets/asset-processing-service}/index.ts +2 -0
  135. package/src/services/{asset-processing-service → assets/asset-processing-service}/processor.interface.ts +1 -1
  136. package/src/services/assets/asset-processing-service/processors/base/base-processor.test.ts +59 -0
  137. package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/base/base-processor.ts +11 -5
  138. package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/base/base-script-processor.ts +17 -27
  139. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.test.ts +286 -0
  140. package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/script/file-script.processor.ts +3 -3
  141. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.test.ts +227 -0
  142. package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/script/node-module-script.processor.ts +5 -4
  143. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.test.ts +199 -0
  144. package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/stylesheet/file-stylesheet.processor.ts +4 -1
  145. package/src/services/assets/browser-bundle.service.test.ts +36 -0
  146. package/src/services/assets/browser-bundle.service.ts +53 -0
  147. package/src/services/cache/index.ts +3 -3
  148. package/src/services/cache/memory-cache-store.test.ts +225 -0
  149. package/src/services/cache/memory-cache-store.ts +1 -1
  150. package/src/services/cache/page-cache-service.test.ts +175 -0
  151. package/src/services/cache/page-cache-service.ts +3 -3
  152. package/src/services/cache/page-request-cache-coordinator.service.test.ts +79 -0
  153. package/src/services/{page-request-cache-coordinator.service.ts → cache/page-request-cache-coordinator.service.ts} +9 -6
  154. package/src/services/html/html-rewriter-provider.service.test.ts +183 -0
  155. package/src/services/html/html-rewriter-provider.service.ts +103 -0
  156. package/src/services/html/html-transformer.service.test.ts +378 -0
  157. package/src/services/html/html-transformer.service.ts +279 -0
  158. package/src/services/invalidation/development-invalidation.service.test.ts +77 -0
  159. package/src/services/invalidation/development-invalidation.service.ts +261 -0
  160. package/src/services/module-loading/app-server-module-transpiler.service.ts +52 -0
  161. package/src/services/module-loading/page-module-import.service.test.ts +253 -0
  162. package/src/services/module-loading/page-module-import.service.ts +200 -0
  163. package/src/services/module-loading/server-loader.service.test.ts +161 -0
  164. package/src/services/module-loading/server-loader.service.ts +130 -0
  165. package/src/services/module-loading/server-module-transpiler.service.test.ts +115 -0
  166. package/src/services/module-loading/server-module-transpiler.service.ts +105 -0
  167. package/src/services/runtime-manifest/node-runtime-manifest.service.test.ts +95 -0
  168. package/src/services/runtime-manifest/node-runtime-manifest.service.ts +101 -0
  169. package/src/services/runtime-state/dev-graph.service.ts +217 -0
  170. package/src/services/runtime-state/entrypoint-dependency-graph.service.ts +136 -0
  171. package/src/services/runtime-state/runtime-specifier-registry.service.ts +96 -0
  172. package/src/services/runtime-state/server-invalidation-state.service.ts +68 -0
  173. package/src/services/validation/schema-validation-service.test.ts +223 -0
  174. package/src/services/{schema-validation-service.ts → validation/schema-validation-service.ts} +1 -1
  175. package/src/static-site-generator/README.md +26 -0
  176. package/src/static-site-generator/static-site-generator.test.ts +307 -0
  177. package/src/static-site-generator/static-site-generator.ts +109 -6
  178. package/src/utils/deep-merge.test.ts +114 -0
  179. package/src/utils/invariant.test.ts +22 -0
  180. package/src/utils/path-utils.test.ts +15 -0
  181. package/src/utils/resolve-work-dir.ts +45 -0
  182. package/src/utils/server-utils.test.ts +38 -0
  183. package/src/watchers/project-watcher.integration.test.ts +337 -0
  184. package/src/watchers/project-watcher.test-helpers.ts +1 -1
  185. package/src/watchers/project-watcher.test.ts +678 -0
  186. package/src/watchers/project-watcher.ts +130 -111
  187. package/CHANGELOG.md +0 -91
  188. package/src/adapters/abstract/application-adapter.d.ts +0 -168
  189. package/src/adapters/abstract/application-adapter.js +0 -109
  190. package/src/adapters/abstract/router-adapter.d.ts +0 -26
  191. package/src/adapters/abstract/router-adapter.js +0 -5
  192. package/src/adapters/abstract/server-adapter.d.ts +0 -69
  193. package/src/adapters/abstract/server-adapter.js +0 -15
  194. package/src/adapters/bun/client-bridge.d.ts +0 -34
  195. package/src/adapters/bun/client-bridge.js +0 -48
  196. package/src/adapters/bun/create-app.d.ts +0 -60
  197. package/src/adapters/bun/create-app.js +0 -117
  198. package/src/adapters/bun/define-api-handler.d.ts +0 -61
  199. package/src/adapters/bun/define-api-handler.js +0 -15
  200. package/src/adapters/bun/define-api-handler.ts +0 -114
  201. package/src/adapters/bun/hmr-manager.d.ts +0 -85
  202. package/src/adapters/bun/hmr-manager.js +0 -240
  203. package/src/adapters/bun/index.d.ts +0 -3
  204. package/src/adapters/bun/index.js +0 -8
  205. package/src/adapters/bun/server-adapter.d.ts +0 -155
  206. package/src/adapters/bun/server-adapter.js +0 -368
  207. package/src/adapters/bun/server-lifecycle.d.ts +0 -52
  208. package/src/adapters/bun/server-lifecycle.js +0 -120
  209. package/src/adapters/index.d.ts +0 -6
  210. package/src/adapters/index.js +0 -14
  211. package/src/adapters/node/create-app.d.ts +0 -21
  212. package/src/adapters/node/create-app.js +0 -143
  213. package/src/adapters/node/index.d.ts +0 -4
  214. package/src/adapters/node/index.js +0 -8
  215. package/src/adapters/node/node-client-bridge.d.ts +0 -26
  216. package/src/adapters/node/node-client-bridge.js +0 -66
  217. package/src/adapters/node/node-hmr-manager.d.ts +0 -63
  218. package/src/adapters/node/node-hmr-manager.js +0 -237
  219. package/src/adapters/node/server-adapter.d.ts +0 -190
  220. package/src/adapters/node/server-adapter.js +0 -420
  221. package/src/adapters/node/static-content-server.d.ts +0 -24
  222. package/src/adapters/node/static-content-server.js +0 -166
  223. package/src/adapters/shared/api-response.d.ts +0 -52
  224. package/src/adapters/shared/api-response.js +0 -96
  225. package/src/adapters/shared/application-adapter.d.ts +0 -18
  226. package/src/adapters/shared/application-adapter.js +0 -90
  227. package/src/adapters/shared/explicit-static-route-matcher.d.ts +0 -38
  228. package/src/adapters/shared/explicit-static-route-matcher.js +0 -100
  229. package/src/adapters/shared/file-route-middleware-pipeline.d.ts +0 -65
  230. package/src/adapters/shared/file-route-middleware-pipeline.js +0 -98
  231. package/src/adapters/shared/fs-server-response-factory.d.ts +0 -19
  232. package/src/adapters/shared/fs-server-response-factory.js +0 -97
  233. package/src/adapters/shared/fs-server-response-matcher.d.ts +0 -71
  234. package/src/adapters/shared/fs-server-response-matcher.js +0 -155
  235. package/src/adapters/shared/render-context.d.ts +0 -14
  236. package/src/adapters/shared/render-context.js +0 -69
  237. package/src/adapters/shared/server-adapter.d.ts +0 -87
  238. package/src/adapters/shared/server-adapter.js +0 -353
  239. package/src/adapters/shared/server-route-handler.d.ts +0 -89
  240. package/src/adapters/shared/server-route-handler.js +0 -120
  241. package/src/adapters/shared/server-static-builder.d.ts +0 -38
  242. package/src/adapters/shared/server-static-builder.js +0 -46
  243. package/src/build/build-adapter.d.ts +0 -74
  244. package/src/build/build-adapter.js +0 -54
  245. package/src/build/build-types.d.ts +0 -57
  246. package/src/build/build-types.js +0 -0
  247. package/src/build/esbuild-build-adapter.d.ts +0 -69
  248. package/src/build/esbuild-build-adapter.js +0 -390
  249. package/src/config/config-builder.d.ts +0 -227
  250. package/src/config/config-builder.js +0 -392
  251. package/src/constants.d.ts +0 -32
  252. package/src/constants.js +0 -21
  253. package/src/create-app.d.ts +0 -17
  254. package/src/create-app.js +0 -66
  255. package/src/define-api-handler.d.ts +0 -25
  256. package/src/define-api-handler.js +0 -15
  257. package/src/dev/sc-server.d.ts +0 -30
  258. package/src/dev/sc-server.js +0 -111
  259. package/src/eco/component-render-context.d.ts +0 -105
  260. package/src/eco/component-render-context.js +0 -77
  261. package/src/eco/eco.d.ts +0 -9
  262. package/src/eco/eco.js +0 -110
  263. package/src/eco/eco.types.d.ts +0 -170
  264. package/src/eco/eco.types.js +0 -0
  265. package/src/eco/eco.utils.d.ts +0 -40
  266. package/src/eco/eco.utils.js +0 -40
  267. package/src/eco/global-injector-map.d.ts +0 -16
  268. package/src/eco/global-injector-map.js +0 -80
  269. package/src/eco/lazy-injector-map.d.ts +0 -8
  270. package/src/eco/lazy-injector-map.js +0 -70
  271. package/src/eco/module-dependencies.d.ts +0 -18
  272. package/src/eco/module-dependencies.js +0 -49
  273. package/src/errors/http-error.d.ts +0 -31
  274. package/src/errors/http-error.js +0 -50
  275. package/src/errors/index.d.ts +0 -2
  276. package/src/errors/index.js +0 -4
  277. package/src/errors/locals-access-error.d.ts +0 -4
  278. package/src/errors/locals-access-error.js +0 -9
  279. package/src/global/app-logger.d.ts +0 -2
  280. package/src/global/app-logger.js +0 -6
  281. package/src/hmr/client/hmr-runtime.d.ts +0 -10
  282. package/src/hmr/client/hmr-runtime.js +0 -86
  283. package/src/hmr/hmr-strategy.d.ts +0 -159
  284. package/src/hmr/hmr-strategy.js +0 -29
  285. package/src/hmr/hmr.test.e2e.d.ts +0 -1
  286. package/src/hmr/hmr.test.e2e.js +0 -50
  287. package/src/hmr/strategies/default-hmr-strategy.d.ts +0 -43
  288. package/src/hmr/strategies/default-hmr-strategy.js +0 -34
  289. package/src/hmr/strategies/js-hmr-strategy.d.ts +0 -136
  290. package/src/hmr/strategies/js-hmr-strategy.js +0 -188
  291. package/src/index.browser.d.ts +0 -3
  292. package/src/index.browser.js +0 -4
  293. package/src/index.d.ts +0 -5
  294. package/src/index.js +0 -10
  295. package/src/integrations/ghtml/ghtml-renderer.d.ts +0 -15
  296. package/src/integrations/ghtml/ghtml-renderer.js +0 -60
  297. package/src/integrations/ghtml/ghtml.plugin.d.ts +0 -20
  298. package/src/integrations/ghtml/ghtml.plugin.js +0 -21
  299. package/src/internal-types.d.ts +0 -200
  300. package/src/internal-types.js +0 -0
  301. package/src/plugins/alias-resolver-plugin.d.ts +0 -2
  302. package/src/plugins/alias-resolver-plugin.js +0 -39
  303. package/src/plugins/eco-component-meta-plugin.d.ts +0 -95
  304. package/src/plugins/eco-component-meta-plugin.js +0 -157
  305. package/src/plugins/integration-plugin.d.ts +0 -102
  306. package/src/plugins/integration-plugin.js +0 -100
  307. package/src/plugins/processor.d.ts +0 -82
  308. package/src/plugins/processor.js +0 -122
  309. package/src/public-types.d.ts +0 -1098
  310. package/src/public-types.js +0 -0
  311. package/src/route-renderer/component-graph-executor.d.ts +0 -32
  312. package/src/route-renderer/component-graph-executor.js +0 -31
  313. package/src/route-renderer/component-graph.d.ts +0 -42
  314. package/src/route-renderer/component-graph.js +0 -72
  315. package/src/route-renderer/component-marker.d.ts +0 -52
  316. package/src/route-renderer/component-marker.js +0 -46
  317. package/src/route-renderer/dependency-resolver.d.ts +0 -24
  318. package/src/route-renderer/dependency-resolver.js +0 -428
  319. package/src/route-renderer/html-post-processing.service.d.ts +0 -40
  320. package/src/route-renderer/html-post-processing.service.js +0 -86
  321. package/src/route-renderer/html-post-processing.service.ts +0 -103
  322. package/src/route-renderer/integration-renderer.d.ts +0 -339
  323. package/src/route-renderer/integration-renderer.js +0 -526
  324. package/src/route-renderer/marker-graph-resolver.d.ts +0 -76
  325. package/src/route-renderer/marker-graph-resolver.js +0 -93
  326. package/src/route-renderer/page-module-loader.d.ts +0 -61
  327. package/src/route-renderer/page-module-loader.js +0 -102
  328. package/src/route-renderer/render-execution.service.d.ts +0 -69
  329. package/src/route-renderer/render-execution.service.js +0 -91
  330. package/src/route-renderer/render-preparation.service.d.ts +0 -112
  331. package/src/route-renderer/render-preparation.service.js +0 -243
  332. package/src/route-renderer/route-renderer.d.ts +0 -26
  333. package/src/route-renderer/route-renderer.js +0 -68
  334. package/src/router/fs-router-scanner.d.ts +0 -41
  335. package/src/router/fs-router-scanner.js +0 -155
  336. package/src/router/fs-router.d.ts +0 -26
  337. package/src/router/fs-router.js +0 -100
  338. package/src/services/asset-processing-service/asset-processing.service.d.ts +0 -41
  339. package/src/services/asset-processing-service/asset-processing.service.js +0 -250
  340. package/src/services/asset-processing-service/asset.factory.d.ts +0 -17
  341. package/src/services/asset-processing-service/asset.factory.js +0 -82
  342. package/src/services/asset-processing-service/assets.types.d.ts +0 -88
  343. package/src/services/asset-processing-service/assets.types.js +0 -0
  344. package/src/services/asset-processing-service/index.d.ts +0 -3
  345. package/src/services/asset-processing-service/index.js +0 -3
  346. package/src/services/asset-processing-service/processor.interface.d.ts +0 -22
  347. package/src/services/asset-processing-service/processor.interface.js +0 -6
  348. package/src/services/asset-processing-service/processor.registry.d.ts +0 -8
  349. package/src/services/asset-processing-service/processor.registry.js +0 -15
  350. package/src/services/asset-processing-service/processors/base/base-processor.d.ts +0 -24
  351. package/src/services/asset-processing-service/processors/base/base-processor.js +0 -59
  352. package/src/services/asset-processing-service/processors/base/base-script-processor.d.ts +0 -16
  353. package/src/services/asset-processing-service/processors/base/base-script-processor.js +0 -80
  354. package/src/services/asset-processing-service/processors/index.d.ts +0 -5
  355. package/src/services/asset-processing-service/processors/index.js +0 -5
  356. package/src/services/asset-processing-service/processors/script/content-script.processor.d.ts +0 -5
  357. package/src/services/asset-processing-service/processors/script/content-script.processor.js +0 -57
  358. package/src/services/asset-processing-service/processors/script/file-script.processor.d.ts +0 -8
  359. package/src/services/asset-processing-service/processors/script/file-script.processor.js +0 -76
  360. package/src/services/asset-processing-service/processors/script/node-module-script.processor.d.ts +0 -7
  361. package/src/services/asset-processing-service/processors/script/node-module-script.processor.js +0 -74
  362. package/src/services/asset-processing-service/processors/stylesheet/content-stylesheet.processor.d.ts +0 -5
  363. package/src/services/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +0 -25
  364. package/src/services/asset-processing-service/processors/stylesheet/file-stylesheet.processor.d.ts +0 -9
  365. package/src/services/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +0 -63
  366. package/src/services/cache/cache.types.d.ts +0 -107
  367. package/src/services/cache/cache.types.js +0 -0
  368. package/src/services/cache/index.d.ts +0 -7
  369. package/src/services/cache/index.js +0 -7
  370. package/src/services/cache/memory-cache-store.d.ts +0 -42
  371. package/src/services/cache/memory-cache-store.js +0 -98
  372. package/src/services/cache/page-cache-service.d.ts +0 -70
  373. package/src/services/cache/page-cache-service.js +0 -152
  374. package/src/services/html-transformer.service.d.ts +0 -50
  375. package/src/services/html-transformer.service.js +0 -163
  376. package/src/services/html-transformer.service.ts +0 -217
  377. package/src/services/page-module-import.service.d.ts +0 -37
  378. package/src/services/page-module-import.service.js +0 -88
  379. package/src/services/page-module-import.service.ts +0 -129
  380. package/src/services/page-request-cache-coordinator.service.d.ts +0 -75
  381. package/src/services/page-request-cache-coordinator.service.js +0 -107
  382. package/src/services/schema-validation-service.d.ts +0 -122
  383. package/src/services/schema-validation-service.js +0 -101
  384. package/src/services/validation/standard-schema.types.d.ts +0 -65
  385. package/src/services/validation/standard-schema.types.js +0 -0
  386. package/src/static-site-generator/static-site-generator.d.ts +0 -57
  387. package/src/static-site-generator/static-site-generator.js +0 -272
  388. package/src/utils/css.d.ts +0 -1
  389. package/src/utils/css.js +0 -7
  390. package/src/utils/deep-merge.d.ts +0 -14
  391. package/src/utils/deep-merge.js +0 -32
  392. package/src/utils/hash.d.ts +0 -1
  393. package/src/utils/hash.js +0 -7
  394. package/src/utils/html.d.ts +0 -1
  395. package/src/utils/html.js +0 -4
  396. package/src/utils/invariant.d.ts +0 -5
  397. package/src/utils/invariant.js +0 -11
  398. package/src/utils/locals-utils.d.ts +0 -15
  399. package/src/utils/locals-utils.js +0 -24
  400. package/src/utils/parse-cli-args.d.ts +0 -24
  401. package/src/utils/parse-cli-args.js +0 -47
  402. package/src/utils/path-utils.module.d.ts +0 -5
  403. package/src/utils/path-utils.module.js +0 -14
  404. package/src/utils/runtime.d.ts +0 -11
  405. package/src/utils/runtime.js +0 -40
  406. package/src/utils/server-utils.module.d.ts +0 -19
  407. package/src/utils/server-utils.module.js +0 -56
  408. package/src/watchers/project-watcher.d.ts +0 -125
  409. package/src/watchers/project-watcher.js +0 -265
  410. package/src/watchers/project-watcher.test-helpers.d.ts +0 -4
  411. package/src/watchers/project-watcher.test-helpers.js +0 -52
  412. /package/src/route-renderer/{component-graph-executor.ts → component-graph/component-graph-executor.ts} +0 -0
  413. /package/src/route-renderer/{component-graph.ts → component-graph/component-graph.ts} +0 -0
  414. /package/src/route-renderer/{component-marker.ts → component-graph/component-marker.ts} +0 -0
  415. /package/src/services/{asset-processing-service → assets/asset-processing-service}/processor.registry.ts +0 -0
  416. /package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/index.ts +0 -0
  417. /package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/script/content-script.processor.ts +0 -0
  418. /package/src/services/{asset-processing-service → assets/asset-processing-service}/processors/stylesheet/content-stylesheet.processor.ts +0 -0
@@ -3,30 +3,58 @@ import type { IntegrationPlugin } from '../plugins/integration-plugin.ts';
3
3
  import type { RouteRenderResult, RouteRendererOptions } from '../public-types.ts';
4
4
  import { invariant } from '../utils/invariant.ts';
5
5
  import { PathUtils } from '../utils/path-utils.module.ts';
6
- import type { IntegrationRenderer } from './integration-renderer.ts';
6
+ import type { IntegrationRenderer } from './orchestration/integration-renderer.ts';
7
7
 
8
+ /**
9
+ * Thin wrapper around one initialized integration renderer.
10
+ *
11
+ * @remarks
12
+ * This type exists so higher-level routing code can ask for a route renderer
13
+ * without depending on the full integration plugin lifecycle. It delegates all
14
+ * real work to the integration-specific renderer selected by the factory.
15
+ */
8
16
  export class RouteRenderer {
9
17
  private renderer: IntegrationRenderer;
10
18
 
19
+ /**
20
+ * Creates a route renderer bound to one integration renderer instance.
21
+ */
11
22
  constructor(renderer: IntegrationRenderer) {
12
23
  this.renderer = renderer;
13
24
  }
14
25
 
26
+ /**
27
+ * Executes the render pipeline for one matched route.
28
+ */
15
29
  async createRoute(options: RouteRendererOptions): Promise<RouteRenderResult> {
16
30
  return this.renderer.execute(options);
17
31
  }
18
32
  }
19
33
 
34
+ /**
35
+ * Selects and caches integration renderers for route files and explicit views.
36
+ *
37
+ * @remarks
38
+ * The factory owns the policy that maps a route file or explicit integration
39
+ * name to one initialized integration renderer. Renderer instances are cached by
40
+ * integration name so repeated requests do not rebuild renderer state.
41
+ */
20
42
  export class RouteRendererFactory {
21
43
  private appConfig: EcoPagesAppConfig;
22
44
  runtimeOrigin: string;
23
45
  private rendererCache = new Map<string, IntegrationRenderer>();
24
46
 
47
+ /**
48
+ * Creates the route-renderer factory for one app/runtime instance.
49
+ */
25
50
  constructor({ appConfig, runtimeOrigin }: { appConfig: EcoPagesAppConfig; runtimeOrigin: string }) {
26
51
  this.appConfig = appConfig;
27
52
  this.runtimeOrigin = runtimeOrigin;
28
53
  }
29
54
 
55
+ /**
56
+ * Returns a route renderer for the supplied route file.
57
+ */
30
58
  createRenderer(filePath: string): RouteRenderer {
31
59
  const integrationRenderer = this.getRouteRendererEngine(filePath);
32
60
  invariant(!!integrationRenderer, `No integration renderer found for file: ${filePath}`);
@@ -53,6 +81,9 @@ export class RouteRendererFactory {
53
81
  return renderer;
54
82
  }
55
83
 
84
+ /**
85
+ * Resolves the integration plugin that owns a given route file.
86
+ */
56
87
  getIntegrationPlugin(filePath: string): IntegrationPlugin {
57
88
  const templateExtension = PathUtils.getEcoTemplateExtension(filePath);
58
89
  const isIntegrationPlugin = (plugin: IntegrationPlugin): boolean => {
@@ -66,6 +97,10 @@ export class RouteRendererFactory {
66
97
  return integrationPlugin as IntegrationPlugin;
67
98
  }
68
99
 
100
+ /**
101
+ * Returns the cached renderer engine for the file's owning integration,
102
+ * creating it on first use.
103
+ */
69
104
  private getRouteRendererEngine(filePath: string): IntegrationRenderer {
70
105
  const integrationPlugin = this.getIntegrationPlugin(filePath);
71
106
  const cached = this.rendererCache.get(integrationPlugin.name);
@@ -0,0 +1,26 @@
1
+ # Router Layer
2
+
3
+ This directory contains route discovery, matching, and browser-side navigation infrastructure.
4
+
5
+ ## Purpose
6
+
7
+ The router layer determines what route is being handled and how the client runtime coordinates navigation.
8
+
9
+ It is responsible for:
10
+
11
+ - filesystem route scanning and matching
12
+ - explicit-route support and response matching
13
+ - client-side navigation coordination and ownership handoff
14
+ - keeping route discovery separate from rendering execution
15
+
16
+ ## Main Areas
17
+
18
+ - server-side route discovery and matchers used by adapters
19
+ - `client/`: shared browser-side navigation coordination
20
+
21
+ ## Relationship To Rendering
22
+
23
+ The router layer answers which route should run.
24
+ The route-renderer layer answers how that route gets rendered.
25
+
26
+ Keeping those seams separate avoids mixing route ownership, module loading, and component orchestration into one service.
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Shared client-side navigation intent helpers.
3
+ *
4
+ * Browser runtimes use the same low-level mechanics to:
5
+ * - locate the anchor associated with a click, pointer, or hover event,
6
+ * - persist the last valid pointer or hover target while a navigation is in flight,
7
+ * - recover the final intended href when the DOM changes before the click lands.
8
+ *
9
+ * Keeping those mechanics here lets browser-router and react-router share one
10
+ * implementation while preserving their router-specific interception rules.
11
+ *
12
+ * @module
13
+ */
14
+ /**
15
+ * Timestamped navigation intent captured from pointer or hover activity.
16
+ */
17
+ export type EcoPendingNavigationIntent = {
18
+ href: string;
19
+ timestamp: number;
20
+ };
21
+ /**
22
+ * Finds the nearest matching anchor within an event's composed path.
23
+ *
24
+ * This works across Shadow DOM boundaries, which is required for delegated
25
+ * navigation handling when links are rendered inside custom elements.
26
+ *
27
+ * @param event - Pointer or mouse event being inspected.
28
+ * @param linkSelector - Selector that identifies navigable anchors.
29
+ * @returns The matched anchor element, or `null` when no matching anchor exists.
30
+ */
31
+ export declare function getAnchorFromNavigationEvent(
32
+ event: MouseEvent | PointerEvent,
33
+ linkSelector: string,
34
+ ): HTMLAnchorElement | null;
35
+ /**
36
+ * Resolves a previously captured intent while a navigation is still in flight.
37
+ *
38
+ * Pending intents expire quickly because they are only meant to bridge the gap
39
+ * between pointer or hover capture and the later click event when the DOM or
40
+ * active runtime changes during a rapid navigation sequence.
41
+ *
42
+ * @param intent - Previously captured pointer or hover intent.
43
+ * @param hasInFlightNavigation - Whether a router navigation is still active.
44
+ * @param now - Current monotonic timestamp, usually from `performance.now()`.
45
+ * @param maxAgeMs - Maximum allowed age for the recovered intent.
46
+ * @returns The intended href when still valid, otherwise `null`.
47
+ */
48
+ export declare function recoverPendingNavigationHref(
49
+ intent: EcoPendingNavigationIntent | null,
50
+ hasInFlightNavigation: boolean,
51
+ now: number,
52
+ maxAgeMs?: number,
53
+ ): string | null;
@@ -0,0 +1,51 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { getAnchorFromNavigationEvent, recoverPendingNavigationHref } from './link-intent.ts';
3
+
4
+ describe('getAnchorFromNavigationEvent', () => {
5
+ it('returns the anchor when the event target is a text node inside it', () => {
6
+ const anchor = document.createElement('a');
7
+ anchor.href = '/fast';
8
+ anchor.setAttribute('data-eco-link', 'true');
9
+ const textNode = document.createTextNode('fast-link');
10
+ anchor.append(textNode);
11
+ document.body.append(anchor);
12
+
13
+ const event = new MouseEvent('click', { bubbles: true, cancelable: true, composed: true });
14
+ Object.defineProperty(event, 'target', {
15
+ configurable: true,
16
+ value: textNode,
17
+ });
18
+
19
+ expect(getAnchorFromNavigationEvent(event, 'a[data-eco-link]')).toBe(anchor);
20
+ });
21
+
22
+ it('returns the closest matching anchor for nested element targets', () => {
23
+ const anchor = document.createElement('a');
24
+ anchor.href = '/fast';
25
+ anchor.setAttribute('data-eco-link', 'true');
26
+ const span = document.createElement('span');
27
+ span.textContent = 'fast-link';
28
+ anchor.append(span);
29
+ document.body.append(anchor);
30
+
31
+ const event = new MouseEvent('click', { bubbles: true, cancelable: true, composed: true });
32
+ Object.defineProperty(event, 'target', {
33
+ configurable: true,
34
+ value: span,
35
+ });
36
+
37
+ expect(getAnchorFromNavigationEvent(event, 'a[data-eco-link]')).toBe(anchor);
38
+ });
39
+ });
40
+
41
+ describe('recoverPendingNavigationHref', () => {
42
+ it('returns null for stale or missing pending intent state', () => {
43
+ expect(recoverPendingNavigationHref(null, true, 10)).toBeNull();
44
+ expect(recoverPendingNavigationHref({ href: '/fast', timestamp: 0 }, false, 10)).toBeNull();
45
+ expect(recoverPendingNavigationHref({ href: '/fast', timestamp: 0 }, true, 2000, 1000)).toBeNull();
46
+ });
47
+
48
+ it('returns the captured href while a navigation is still in flight', () => {
49
+ expect(recoverPendingNavigationHref({ href: '/fast', timestamp: 10 }, true, 20, 1000)).toBe('/fast');
50
+ });
51
+ });
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Shared client-side navigation intent helpers.
3
+ *
4
+ * Browser runtimes use the same low-level mechanics to:
5
+ * - locate the anchor associated with a click, pointer, or hover event,
6
+ * - persist the last valid pointer or hover target while a navigation is in flight,
7
+ * - recover the final intended href when the DOM changes before the click lands.
8
+ *
9
+ * Keeping those mechanics here lets browser-router and react-router share one
10
+ * implementation while preserving their router-specific interception rules.
11
+ *
12
+ * @module
13
+ */
14
+
15
+ /**
16
+ * Timestamped navigation intent captured from pointer or hover activity.
17
+ */
18
+ export type EcoPendingNavigationIntent = {
19
+ href: string;
20
+ timestamp: number;
21
+ };
22
+
23
+ /**
24
+ * Finds the nearest matching anchor within an event's composed path.
25
+ *
26
+ * This works across Shadow DOM boundaries, which is required for delegated
27
+ * navigation handling when links are rendered inside custom elements.
28
+ *
29
+ * @param event - Pointer or mouse event being inspected.
30
+ * @param linkSelector - Selector that identifies navigable anchors.
31
+ * @returns The matched anchor element, or `null` when no matching anchor exists.
32
+ */
33
+ export function getAnchorFromNavigationEvent(
34
+ event: MouseEvent | PointerEvent,
35
+ linkSelector: string,
36
+ ): HTMLAnchorElement | null {
37
+ const eventTarget = event.target;
38
+
39
+ if (eventTarget instanceof HTMLAnchorElement && eventTarget.matches(linkSelector)) {
40
+ return eventTarget;
41
+ }
42
+
43
+ if (eventTarget instanceof Element) {
44
+ const closestAnchor = eventTarget.closest(linkSelector);
45
+ if (closestAnchor instanceof HTMLAnchorElement) {
46
+ return closestAnchor;
47
+ }
48
+ }
49
+
50
+ if (eventTarget instanceof Text) {
51
+ const parentAnchor = eventTarget.parentElement?.closest(linkSelector);
52
+ if (parentAnchor instanceof HTMLAnchorElement) {
53
+ return parentAnchor;
54
+ }
55
+ }
56
+
57
+ return event
58
+ .composedPath()
59
+ .find(
60
+ (target) => target instanceof HTMLAnchorElement && target.matches(linkSelector),
61
+ ) as HTMLAnchorElement | null;
62
+ }
63
+
64
+ /**
65
+ * Resolves a previously captured intent while a navigation is still in flight.
66
+ *
67
+ * Pending intents expire quickly because they are only meant to bridge the gap
68
+ * between pointer or hover capture and the later click event when the DOM or
69
+ * active runtime changes during a rapid navigation sequence.
70
+ *
71
+ * @param intent - Previously captured pointer or hover intent.
72
+ * @param hasInFlightNavigation - Whether a router navigation is still active.
73
+ * @param now - Current monotonic timestamp, usually from `performance.now()`.
74
+ * @param maxAgeMs - Maximum allowed age for the recovered intent.
75
+ * @returns The intended href when still valid, otherwise `null`.
76
+ */
77
+ export function recoverPendingNavigationHref(
78
+ intent: EcoPendingNavigationIntent | null,
79
+ hasInFlightNavigation: boolean,
80
+ now: number,
81
+ maxAgeMs = 1000,
82
+ ): string | null {
83
+ if (!intent || !hasInFlightNavigation) {
84
+ return null;
85
+ }
86
+
87
+ if (now - intent.timestamp > maxAgeMs) {
88
+ return null;
89
+ }
90
+
91
+ return intent.href;
92
+ }
@@ -0,0 +1,237 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { getEcoNavigationRuntime } from './navigation-coordinator.ts';
3
+
4
+ function createWindowLike() {
5
+ return {} as Window &
6
+ typeof globalThis & {
7
+ __ECO_PAGES__?: { navigation?: ReturnType<typeof getEcoNavigationRuntime> };
8
+ };
9
+ }
10
+
11
+ describe('getEcoNavigationRuntime', () => {
12
+ it('returns the same coordinator instance for the same window', () => {
13
+ const windowLike = createWindowLike();
14
+ const first = getEcoNavigationRuntime(windowLike);
15
+ const second = getEcoNavigationRuntime(windowLike);
16
+
17
+ expect(first).toBe(second);
18
+ });
19
+
20
+ it('tracks explicit ownership claims', () => {
21
+ const windowLike = createWindowLike();
22
+ const runtime = getEcoNavigationRuntime(windowLike);
23
+
24
+ runtime.claimOwnership('react-router');
25
+
26
+ expect(runtime.getOwnerState()).toEqual({
27
+ owner: 'react-router',
28
+ canHandleSpaNavigation: false,
29
+ });
30
+ });
31
+
32
+ it('shares one navigation transaction sequence across runtimes', () => {
33
+ const windowLike = createWindowLike();
34
+ const runtime = getEcoNavigationRuntime(windowLike);
35
+
36
+ const first = runtime.beginNavigationTransaction();
37
+ expect(runtime.hasPendingNavigationTransaction()).toBe(true);
38
+ expect(first.isCurrent()).toBe(true);
39
+ expect(first.signal.aborted).toBe(false);
40
+
41
+ const second = runtime.beginNavigationTransaction();
42
+
43
+ expect(first.isCurrent()).toBe(false);
44
+ expect(first.signal.aborted).toBe(true);
45
+ expect(second.isCurrent()).toBe(true);
46
+ expect(second.signal.aborted).toBe(false);
47
+ second.complete();
48
+ expect(runtime.hasPendingNavigationTransaction()).toBe(false);
49
+ });
50
+
51
+ it('cancels only the current navigation transaction', () => {
52
+ const windowLike = createWindowLike();
53
+ const runtime = getEcoNavigationRuntime(windowLike);
54
+
55
+ const first = runtime.beginNavigationTransaction();
56
+ const second = runtime.beginNavigationTransaction();
57
+
58
+ first.cancel();
59
+ expect(second.isCurrent()).toBe(true);
60
+ expect(second.signal.aborted).toBe(false);
61
+
62
+ second.cancel();
63
+ expect(second.isCurrent()).toBe(false);
64
+ expect(second.signal.aborted).toBe(true);
65
+ expect(runtime.hasPendingNavigationTransaction()).toBe(false);
66
+ });
67
+
68
+ it('adopts ownership from the rendered document marker', () => {
69
+ const windowLike = createWindowLike();
70
+ const runtime = getEcoNavigationRuntime(windowLike);
71
+ const documentLike = {
72
+ documentElement: {
73
+ getAttribute: vi.fn(() => 'custom-router'),
74
+ },
75
+ } as unknown as Document;
76
+
77
+ expect(runtime.adoptDocumentOwner(documentLike, 'browser-router')).toBe('custom-router');
78
+ expect(runtime.getOwnerState().owner).toBe('custom-router');
79
+ });
80
+
81
+ it('delegates navigation to another registered runtime when the source cannot handle it', async () => {
82
+ const windowLike = createWindowLike();
83
+ const runtime = getEcoNavigationRuntime(windowLike);
84
+ const navigateSpy = vi.fn(async () => true);
85
+
86
+ runtime.register({ owner: 'browser-router', navigate: navigateSpy });
87
+ runtime.register({ owner: 'react-router', navigate: vi.fn(async () => true) });
88
+ runtime.claimOwnership('react-router');
89
+
90
+ const handled = await runtime.requestNavigation({
91
+ href: '/docs',
92
+ direction: 'forward',
93
+ source: 'react-router',
94
+ });
95
+
96
+ expect(handled).toBe(true);
97
+ expect(navigateSpy).toHaveBeenCalledWith({
98
+ href: '/docs',
99
+ direction: 'forward',
100
+ source: 'react-router',
101
+ });
102
+ });
103
+
104
+ it('delegates a fetched document handoff to the targeted runtime without forcing source cleanup first', async () => {
105
+ const windowLike = createWindowLike();
106
+ const runtime = getEcoNavigationRuntime(windowLike);
107
+ const cleanupSpy = vi.fn(async () => undefined);
108
+ const handoffSpy = vi.fn(async () => true);
109
+ const documentLike = {
110
+ documentElement: {
111
+ getAttribute: vi.fn(() => null),
112
+ },
113
+ } as unknown as Document;
114
+
115
+ runtime.register({ owner: 'react-router', cleanupBeforeHandoff: cleanupSpy });
116
+ runtime.register({ owner: 'browser-router', handoffNavigation: handoffSpy });
117
+ runtime.claimOwnership('react-router');
118
+
119
+ const handled = await runtime.requestHandoff({
120
+ href: '/docs',
121
+ finalHref: '/docs',
122
+ direction: 'forward',
123
+ source: 'react-router',
124
+ targetOwner: 'browser-router',
125
+ document: documentLike,
126
+ });
127
+
128
+ expect(handled).toBe(true);
129
+ expect(cleanupSpy).not.toHaveBeenCalled();
130
+ expect(handoffSpy).toHaveBeenCalledWith({
131
+ href: '/docs',
132
+ finalHref: '/docs',
133
+ direction: 'forward',
134
+ source: 'react-router',
135
+ targetOwner: 'browser-router',
136
+ document: documentLike,
137
+ });
138
+ });
139
+
140
+ it('ignores stale handoff requests before cleaning up the active owner', async () => {
141
+ const windowLike = createWindowLike();
142
+ const runtime = getEcoNavigationRuntime(windowLike);
143
+ const cleanupSpy = vi.fn(async () => undefined);
144
+ const handoffSpy = vi.fn(async () => true);
145
+ const documentLike = {
146
+ documentElement: {
147
+ getAttribute: vi.fn(() => null),
148
+ },
149
+ } as unknown as Document;
150
+
151
+ runtime.register({ owner: 'react-router', cleanupBeforeHandoff: cleanupSpy });
152
+ runtime.register({ owner: 'browser-router', handoffNavigation: handoffSpy });
153
+ runtime.claimOwnership('react-router');
154
+
155
+ const handled = await runtime.requestHandoff({
156
+ href: '/docs',
157
+ finalHref: '/docs',
158
+ direction: 'forward',
159
+ source: 'react-router',
160
+ targetOwner: 'browser-router',
161
+ document: documentLike,
162
+ isStaleSourceNavigation: () => true,
163
+ });
164
+
165
+ expect(handled).toBe(true);
166
+ expect(cleanupSpy).not.toHaveBeenCalled();
167
+ expect(handoffSpy).not.toHaveBeenCalled();
168
+ expect(runtime.getOwnerState().owner).toBe('react-router');
169
+ });
170
+
171
+ it('reloads the current owner through its registration', async () => {
172
+ const windowLike = createWindowLike();
173
+ const runtime = getEcoNavigationRuntime(windowLike);
174
+ const reloadSpy = vi.fn(async () => undefined);
175
+
176
+ runtime.register({ owner: 'react-router', reloadCurrentPage: reloadSpy });
177
+ runtime.claimOwnership('react-router');
178
+
179
+ const handled = await runtime.reloadCurrentPage({ clearCache: true, source: 'browser-router' });
180
+
181
+ expect(handled).toBe(true);
182
+ expect(reloadSpy).toHaveBeenCalledWith({ clearCache: true, source: 'browser-router' });
183
+ });
184
+
185
+ it('reloads the current owner even when the request source matches that owner', async () => {
186
+ const windowLike = createWindowLike();
187
+ const runtime = getEcoNavigationRuntime(windowLike);
188
+ const reloadSpy = vi.fn(async () => undefined);
189
+
190
+ runtime.register({ owner: 'react-router', reloadCurrentPage: reloadSpy });
191
+ runtime.claimOwnership('react-router');
192
+
193
+ const handled = await runtime.reloadCurrentPage({ clearCache: false, source: 'react-router' });
194
+
195
+ expect(handled).toBe(true);
196
+ expect(reloadSpy).toHaveBeenCalledWith({ clearCache: false, source: 'react-router' });
197
+ });
198
+
199
+ it('cleans up an explicit owner via its registration', async () => {
200
+ const windowLike = createWindowLike();
201
+ const runtime = getEcoNavigationRuntime(windowLike);
202
+ const cleanupSpy = vi.fn();
203
+
204
+ runtime.register({ owner: 'react-router', cleanupBeforeHandoff: cleanupSpy });
205
+ runtime.claimOwnership('react-router');
206
+
207
+ await runtime.cleanupOwner('react-router');
208
+
209
+ expect(cleanupSpy).toHaveBeenCalledTimes(1);
210
+ expect(runtime.getOwnerState().owner).toBe('none');
211
+ });
212
+
213
+ it('emits events for registrations and ownership changes', () => {
214
+ const windowLike = createWindowLike();
215
+ const runtime = getEcoNavigationRuntime(windowLike);
216
+ const listener = vi.fn();
217
+ const unsubscribe = runtime.subscribe(listener);
218
+
219
+ const unregister = runtime.register({ owner: 'custom-router' });
220
+ runtime.claimOwnership('custom-router');
221
+ runtime.releaseOwnership('custom-router');
222
+ unregister();
223
+ unsubscribe();
224
+
225
+ expect(listener).toHaveBeenCalledWith({
226
+ type: 'registration-change',
227
+ owner: 'custom-router',
228
+ status: 'registered',
229
+ });
230
+ expect(listener).toHaveBeenCalledWith({
231
+ type: 'owner-change',
232
+ owner: 'custom-router',
233
+ previousOwner: 'none',
234
+ reason: 'claim',
235
+ });
236
+ });
237
+ });