@ecopages/core 0.2.0-alpha.5 → 0.2.0-alpha.7

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 +180 -47
  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 +207 -97
  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 +234 -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 -84
  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 +71 -78
  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 -11
  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 -0
  185. package/src/watchers/project-watcher.test.ts +678 -0
  186. package/src/watchers/project-watcher.ts +49 -50
  187. package/CHANGELOG.md +0 -94
  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 -79
  202. package/src/adapters/bun/hmr-manager.js +0 -222
  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 -62
  218. package/src/adapters/node/node-hmr-manager.js +0 -221
  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 -75
  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 -391
  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 -192
  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 -1094
  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 -132
  409. package/src/watchers/project-watcher.js +0 -281
  410. package/src/watchers/project-watcher.test-helpers.d.ts +0 -4
  411. package/src/watchers/project-watcher.test-helpers.js +0 -51
  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
@@ -10,11 +10,22 @@ type NodeStaticContentServerOptions = {
10
10
  port?: number;
11
11
  };
12
12
 
13
+ /**
14
+ * Serves prebuilt static Ecopages output through Node's HTTP server.
15
+ *
16
+ * @remarks
17
+ * This server is used by the Node preview/build path once the app has already
18
+ * emitted its static output. It intentionally stays small: path sanitization,
19
+ * content-type selection, optional gzip serving, and 404 handling.
20
+ */
13
21
  export class NodeStaticContentServer {
14
22
  private readonly appConfig: EcoPagesAppConfig;
15
23
  private readonly options: NodeStaticContentServerOptions;
16
24
  private server: NodeHttpServer | null = null;
17
25
 
26
+ /**
27
+ * Creates the Node static-content server for one built app output directory.
28
+ */
18
29
  constructor({ appConfig, options }: { appConfig: EcoPagesAppConfig; options?: NodeStaticContentServerOptions }) {
19
30
  this.appConfig = appConfig;
20
31
  this.options = {
@@ -23,10 +34,17 @@ export class NodeStaticContentServer {
23
34
  };
24
35
  }
25
36
 
37
+ /**
38
+ * Returns whether the given content type should be served from a pre-gzipped
39
+ * companion file when available.
40
+ */
26
41
  private shouldServeGzip(contentType: string): boolean {
27
42
  return ['text/javascript', 'text/css'].includes(contentType);
28
43
  }
29
44
 
45
+ /**
46
+ * Normalizes a request pathname and rejects directory traversal attempts.
47
+ */
30
48
  private sanitizePath(pathname: string): string | null {
31
49
  const withoutLeadingSlash = pathname.replace(/^\/+/, '');
32
50
  const normalizedPath = normalize(withoutLeadingSlash);
@@ -38,6 +56,9 @@ export class NodeStaticContentServer {
38
56
  return normalizedPath;
39
57
  }
40
58
 
59
+ /**
60
+ * Writes one HTTP response with the provided headers and optional body.
61
+ */
41
62
  private sendResponse(res: ServerResponse, status: number, headers: Record<string, string>, body?: Buffer): void {
42
63
  res.statusCode = status;
43
64
  for (const [key, value] of Object.entries(headers)) {
@@ -52,6 +73,9 @@ export class NodeStaticContentServer {
52
73
  res.end(body);
53
74
  }
54
75
 
76
+ /**
77
+ * Serves the generated 404 page when present, or a plain-text fallback.
78
+ */
55
79
  private sendNotFoundPage(req: IncomingMessage, res: ServerResponse): void {
56
80
  const error404TemplatePath = join(this.appConfig.absolutePaths.distDir, '404.html');
57
81
  const isHead = (req.method ?? 'GET').toUpperCase() === 'HEAD';
@@ -70,6 +94,9 @@ export class NodeStaticContentServer {
70
94
  this.sendResponse(res, 404, { 'Content-Type': 'text/html' }, isHead ? undefined : file);
71
95
  }
72
96
 
97
+ /**
98
+ * Serves one concrete file path, honoring gzip and HEAD semantics.
99
+ */
73
100
  private serveFile(req: IncomingMessage, res: ServerResponse, filePath: string, status = 200): void {
74
101
  const contentType = ServerUtils.getContentType(extname(filePath));
75
102
  const acceptsGzip = req.headers['accept-encoding']?.includes('gzip');
@@ -102,6 +129,9 @@ export class NodeStaticContentServer {
102
129
  this.sendResponse(res, status, { 'Content-Type': contentType }, isHead ? undefined : file);
103
130
  }
104
131
 
132
+ /**
133
+ * Handles one incoming Node HTTP request against the built static output tree.
134
+ */
105
135
  private handleRequest(req: IncomingMessage, res: ServerResponse): void {
106
136
  const method = (req.method ?? 'GET').toUpperCase();
107
137
  const isHead = method === 'HEAD';
@@ -161,6 +191,9 @@ export class NodeStaticContentServer {
161
191
  this.sendNotFoundPage(req, res);
162
192
  }
163
193
 
194
+ /**
195
+ * Starts the static preview server.
196
+ */
164
197
  public async start(): Promise<NodeHttpServer> {
165
198
  if (this.server) {
166
199
  return this.server;
@@ -177,6 +210,9 @@ export class NodeStaticContentServer {
177
210
  return this.server;
178
211
  }
179
212
 
213
+ /**
214
+ * Stops the static preview server and optionally closes active connections.
215
+ */
180
216
  public async stop(force = true): Promise<void> {
181
217
  if (!this.server) {
182
218
  return;
@@ -0,0 +1,38 @@
1
+ import {
2
+ writeAppNodeRuntimeManifest,
3
+ type NodeRuntimeManifest,
4
+ } from '../../services/runtime-manifest/node-runtime-manifest.service.ts';
5
+
6
+ /**
7
+ * Writes the app-owned Node runtime manifest from a bundled manifest-writer
8
+ * entrypoint.
9
+ *
10
+ * @remarks
11
+ * The Node thin-host launch plan executes a bundled JavaScript prep artifact
12
+ * instead of evaluating TypeScript config directly in the launcher. This helper
13
+ * is the narrow bridge between that bundle and the core-owned manifest writer.
14
+ */
15
+ export function writeBundledNodeRuntimeManifest(
16
+ appConfig: {
17
+ rootDir: string;
18
+ absolutePaths: {
19
+ config: string;
20
+ srcDir: string;
21
+ distDir: string;
22
+ workDir?: string;
23
+ };
24
+ loaders: Map<string, unknown>;
25
+ runtime?: {
26
+ nodeRuntimeManifest?: NodeRuntimeManifest;
27
+ };
28
+ },
29
+ options: {
30
+ entryModulePath: string;
31
+ manifestFilePath: string;
32
+ },
33
+ ): void {
34
+ writeAppNodeRuntimeManifest(appConfig as never, {
35
+ entryModulePath: options.entryModulePath,
36
+ manifestFilePath: options.manifestFilePath,
37
+ });
38
+ }
@@ -0,0 +1,97 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest';
2
+ import { ApiResponseBuilder } from './api-response';
3
+
4
+ describe('ApiResponseBuilder', () => {
5
+ let builder: ApiResponseBuilder;
6
+
7
+ beforeEach(() => {
8
+ builder = new ApiResponseBuilder();
9
+ });
10
+
11
+ describe('json()', () => {
12
+ it('should create JSON response with correct content type and data', async () => {
13
+ const data = { foo: 'bar' };
14
+ const response = builder.json(data);
15
+
16
+ expect(response.headers.get('Content-Type')).toBe('application/json; charset=utf-8');
17
+ expect(await response.json()).toEqual(data);
18
+ expect(response.status).toBe(200);
19
+ });
20
+ });
21
+
22
+ describe('text()', () => {
23
+ it('should create text response with correct content type and data', async () => {
24
+ const text = 'Hello World';
25
+ const response = builder.text(text);
26
+
27
+ expect(response.headers.get('Content-Type')).toBe('text/plain; charset=utf-8');
28
+ expect(await response.text()).toBe(text);
29
+ expect(response.status).toBe(200);
30
+ });
31
+ });
32
+
33
+ describe('html()', () => {
34
+ it('should create HTML response with correct content type and data', async () => {
35
+ const html = '<h1>Hello</h1>';
36
+ const response = builder.html(html);
37
+
38
+ expect(response.headers.get('Content-Type')).toBe('text/html; charset=utf-8');
39
+ expect(await response.text()).toBe(html);
40
+ expect(response.status).toBe(200);
41
+ });
42
+ });
43
+
44
+ describe('status()', () => {
45
+ it('should set custom status code', () => {
46
+ const response = builder.status(404).json({ message: 'Not Found' });
47
+ expect(response.status).toBe(404);
48
+ });
49
+ });
50
+
51
+ describe('headers()', () => {
52
+ it('should set custom headers', () => {
53
+ const response = builder.headers({ 'X-Custom': 'Value' }).json({});
54
+ expect(response.headers.get('X-Custom')).toBe('Value');
55
+ });
56
+ });
57
+
58
+ describe('redirect()', () => {
59
+ it('should create redirect response with location header', () => {
60
+ const url = 'https://example.com';
61
+ const response = builder.redirect(url);
62
+
63
+ expect(response.headers.get('Location')).toBe(url);
64
+ expect(response.status).toBe(302);
65
+ });
66
+
67
+ it('should use explicit status for redirect', () => {
68
+ const response = builder.redirect('https://example.com', 301);
69
+ expect(response.status).toBe(301);
70
+ });
71
+ });
72
+
73
+ describe('error()', () => {
74
+ it('should create JSON error response for object data', async () => {
75
+ const error = { code: 'ERR_1', message: 'Error occurred' };
76
+ const response = builder.error(error);
77
+
78
+ expect(response.headers.get('Content-Type')).toBe('application/json; charset=utf-8');
79
+ expect(await response.json()).toEqual({ error });
80
+ expect(response.status).toBe(500);
81
+ });
82
+
83
+ it('should create text error response for string data', async () => {
84
+ const error = 'Error occurred';
85
+ const response = builder.error(error);
86
+
87
+ expect(response.headers.get('Content-Type')).toBe('text/plain; charset=utf-8');
88
+ expect(await response.text()).toBe(error);
89
+ expect(response.status).toBe(500);
90
+ });
91
+
92
+ it('should use explicit status for error', () => {
93
+ const response = builder.error('Not Found', 404);
94
+ expect(response.status).toBe(404);
95
+ });
96
+ });
97
+ });
@@ -4,7 +4,7 @@ import type {
4
4
  Middleware,
5
5
  RouteSchema,
6
6
  TypedGroupHandlerContext,
7
- } from './public-types.ts';
7
+ } from '../../public-types.ts';
8
8
 
9
9
  type UniversalContext = ApiHandlerContext<Request, unknown>;
10
10
 
@@ -0,0 +1,381 @@
1
+ import { describe, expect, test, vi } from 'vitest';
2
+ import type { EcoPageComponent, StaticRoute, ViewLoader } from '../../public-types.ts';
3
+ import { ExplicitStaticRouteMatcher } from './explicit-static-route-matcher.ts';
4
+
5
+ function createMockView(integration = 'ghtml'): EcoPageComponent<any> {
6
+ const view = (() => '<div>Test</div>') as EcoPageComponent<any>;
7
+ view.config = {
8
+ integration,
9
+ __eco: { id: 'test', file: '/test/-view.ts', integration },
10
+ };
11
+ return view;
12
+ }
13
+
14
+ function createMockLoader(view?: EcoPageComponent<any>): ViewLoader<any> {
15
+ const actualView = view ?? createMockView();
16
+ return () => Promise.resolve({ default: actualView });
17
+ }
18
+
19
+ function createMockRoute(path: string, view?: EcoPageComponent<any>): StaticRoute {
20
+ return {
21
+ path,
22
+ loader: createMockLoader(view),
23
+ };
24
+ }
25
+
26
+ function createMatcher(staticRoutes: StaticRoute[]) {
27
+ return new ExplicitStaticRouteMatcher({
28
+ appConfig: { baseUrl: 'http://localhost:3000' } as any,
29
+ routeRendererFactory: {} as any,
30
+ staticRoutes,
31
+ });
32
+ }
33
+
34
+ describe('ExplicitStaticRouteMatcher', () => {
35
+ describe('match', () => {
36
+ test('should match exact static path', () => {
37
+ const matcher = createMatcher([createMockRoute('/about')]);
38
+
39
+ const result = matcher.match('http://localhost:3000/about');
40
+
41
+ expect(result).not.toBeNull();
42
+ expect(result?.route.path).toBe('/about');
43
+ expect(result?.params).toEqual({});
44
+ });
45
+
46
+ test('should match root path', () => {
47
+ const matcher = createMatcher([createMockRoute('/')]);
48
+
49
+ const result = matcher.match('http://localhost:3000/');
50
+
51
+ expect(result).not.toBeNull();
52
+ expect(result?.route.path).toBe('/');
53
+ expect(result?.params).toEqual({});
54
+ });
55
+
56
+ test('should match nested static path', () => {
57
+ const matcher = createMatcher([createMockRoute('/docs/getting-started')]);
58
+
59
+ const result = matcher.match('http://localhost:3000/docs/getting-started');
60
+
61
+ expect(result).not.toBeNull();
62
+ expect(result?.route.path).toBe('/docs/getting-started');
63
+ });
64
+
65
+ test('should return null for non-matching path', () => {
66
+ const matcher = createMatcher([createMockRoute('/about')]);
67
+
68
+ const result = matcher.match('http://localhost:3000/contact');
69
+
70
+ expect(result).toBeNull();
71
+ });
72
+
73
+ test('should return null for partial match', () => {
74
+ const matcher = createMatcher([createMockRoute('/about')]);
75
+
76
+ const result = matcher.match('http://localhost:3000/about/team');
77
+
78
+ expect(result).toBeNull();
79
+ });
80
+ });
81
+
82
+ describe('match with :param syntax', () => {
83
+ test('should match dynamic segment with colon syntax', () => {
84
+ const matcher = createMatcher([createMockRoute('/blog/:slug')]);
85
+
86
+ const result = matcher.match('http://localhost:3000/blog/hello-world');
87
+
88
+ expect(result).not.toBeNull();
89
+ expect(result?.params).toEqual({ slug: 'hello-world' });
90
+ });
91
+
92
+ test('should match multiple dynamic segments', () => {
93
+ const matcher = createMatcher([createMockRoute('/blog/:year/:month/:slug')]);
94
+
95
+ const result = matcher.match('http://localhost:3000/blog/2024/01/hello-world');
96
+
97
+ expect(result).not.toBeNull();
98
+ expect(result?.params).toEqual({
99
+ year: '2024',
100
+ month: '01',
101
+ slug: 'hello-world',
102
+ });
103
+ });
104
+
105
+ test('should match mixed static and dynamic segments', () => {
106
+ const matcher = createMatcher([createMockRoute('/users/:id/posts')]);
107
+
108
+ const result = matcher.match('http://localhost:3000/users/123/posts');
109
+
110
+ expect(result).not.toBeNull();
111
+ expect(result?.params).toEqual({ id: '123' });
112
+ });
113
+ });
114
+
115
+ describe('match with [param] syntax', () => {
116
+ test('should match dynamic segment with bracket syntax', () => {
117
+ const matcher = createMatcher([createMockRoute('/blog/[slug]')]);
118
+
119
+ const result = matcher.match('http://localhost:3000/blog/hello-world');
120
+
121
+ expect(result).not.toBeNull();
122
+ expect(result?.params).toEqual({ slug: 'hello-world' });
123
+ });
124
+
125
+ test('should match multiple bracket parameters', () => {
126
+ const matcher = createMatcher([createMockRoute('/products/[category]/[id]')]);
127
+
128
+ const result = matcher.match('http://localhost:3000/products/electronics/12345');
129
+
130
+ expect(result).not.toBeNull();
131
+ expect(result?.params).toEqual({
132
+ category: 'electronics',
133
+ id: '12345',
134
+ });
135
+ });
136
+ });
137
+
138
+ describe('match with catch-all routes', () => {
139
+ test('should match catch-all with bracket syntax', () => {
140
+ const matcher = createMatcher([createMockRoute('/docs/[...path]')]);
141
+
142
+ const result = matcher.match('http://localhost:3000/docs/api/reference/components');
143
+
144
+ expect(result).not.toBeNull();
145
+ expect(result?.params).toEqual({ path: 'api/reference/components' });
146
+ });
147
+
148
+ test('should match catch-all with colon syntax', () => {
149
+ const matcher = createMatcher([createMockRoute('/files/:...path')]);
150
+
151
+ const result = matcher.match('http://localhost:3000/files/images/2024/photo.jpg');
152
+
153
+ expect(result).not.toBeNull();
154
+ expect(result?.params).toEqual({ path: 'images/2024/photo.jpg' });
155
+ });
156
+
157
+ test('should match catch-all with single segment', () => {
158
+ const matcher = createMatcher([createMockRoute('/docs/[...path]')]);
159
+
160
+ const result = matcher.match('http://localhost:3000/docs/intro');
161
+
162
+ expect(result).not.toBeNull();
163
+ expect(result?.params).toEqual({ path: 'intro' });
164
+ });
165
+ });
166
+
167
+ describe('route priority', () => {
168
+ test('should match first route when multiple routes match', () => {
169
+ const aboutView = createMockView();
170
+ const catchAllView = createMockView();
171
+
172
+ const matcher = createMatcher([
173
+ createMockRoute('/about', aboutView),
174
+ createMockRoute('/[...path]', catchAllView),
175
+ ]);
176
+
177
+ const result = matcher.match('http://localhost:3000/about');
178
+
179
+ expect(result).not.toBeNull();
180
+ expect(result?.route.path).toBe('/about');
181
+ });
182
+
183
+ test('should match exact route before dynamic route', () => {
184
+ const exactView = createMockView();
185
+ const dynamicView = createMockView();
186
+
187
+ const matcher = createMatcher([
188
+ createMockRoute('/blog/featured', exactView),
189
+ createMockRoute('/blog/:slug', dynamicView),
190
+ ]);
191
+
192
+ const result = matcher.match('http://localhost:3000/blog/featured');
193
+
194
+ expect(result).not.toBeNull();
195
+ expect(result?.route.path).toBe('/blog/featured');
196
+ });
197
+ });
198
+
199
+ describe('edge cases', () => {
200
+ test('should handle URL with query parameters', () => {
201
+ const matcher = createMatcher([createMockRoute('/search')]);
202
+
203
+ const result = matcher.match('http://localhost:3000/search?q=test&page=1');
204
+
205
+ expect(result).not.toBeNull();
206
+ expect(result?.route.path).toBe('/search');
207
+ });
208
+
209
+ test('should handle URL with hash', () => {
210
+ const matcher = createMatcher([createMockRoute('/docs/intro')]);
211
+
212
+ const result = matcher.match('http://localhost:3000/docs/intro#section-1');
213
+
214
+ expect(result).not.toBeNull();
215
+ expect(result?.route.path).toBe('/docs/intro');
216
+ });
217
+
218
+ test('should handle trailing slash', () => {
219
+ const matcher = createMatcher([createMockRoute('/about')]);
220
+
221
+ const result = matcher.match('http://localhost:3000/about/');
222
+
223
+ expect(result).not.toBeNull();
224
+ expect(result?.route.path).toBe('/about');
225
+ });
226
+
227
+ test('should return null for empty routes array', () => {
228
+ const matcher = createMatcher([]);
229
+
230
+ const result = matcher.match('http://localhost:3000/anything');
231
+
232
+ expect(result).toBeNull();
233
+ });
234
+ });
235
+
236
+ describe('handleMatch', () => {
237
+ test('should accept integration metadata from view.config.integration', async () => {
238
+ const view = (() => '<div>Test</div>') as EcoPageComponent<any>;
239
+ view.config = {
240
+ integration: 'ghtml',
241
+ __eco: { id: 'test', file: '/test/-view.ts', integration: 'ghtml' },
242
+ };
243
+
244
+ const mockResponse = new Response('<html>Test</html>');
245
+ const renderToResponse = vi.fn(() => mockResponse);
246
+ const matcher = new ExplicitStaticRouteMatcher({
247
+ appConfig: { baseUrl: 'http://localhost:3000' } as any,
248
+ routeRendererFactory: {
249
+ getRendererByIntegration: vi.fn(() => ({
250
+ renderToResponse,
251
+ })),
252
+ } as any,
253
+ staticRoutes: [createMockRoute('/about', view)],
254
+ });
255
+
256
+ const match = matcher.match('http://localhost:3000/about');
257
+ const response = await matcher.handleMatch(match!);
258
+
259
+ expect(response).toBe(mockResponse);
260
+ expect(renderToResponse).toHaveBeenCalledWith(view, {}, {});
261
+ });
262
+
263
+ test('should throw error when view is missing __eco.integration', async () => {
264
+ const viewWithoutIntegration = (() => '<div>Test</div>') as EcoPageComponent<any>;
265
+ viewWithoutIntegration.config = {
266
+ __eco: undefined,
267
+ };
268
+
269
+ const matcher = new ExplicitStaticRouteMatcher({
270
+ appConfig: { baseUrl: 'http://localhost:3000' } as any,
271
+ routeRendererFactory: {
272
+ getRendererByIntegration: vi.fn(() => null),
273
+ } as any,
274
+ staticRoutes: [createMockRoute('/about', viewWithoutIntegration)],
275
+ });
276
+ const match = matcher.match('http://localhost:3000/about');
277
+
278
+ expect(match).not.toBeNull();
279
+ await expect(matcher.handleMatch(match!)).rejects.toThrow('missing __eco.integration');
280
+ });
281
+
282
+ test('should throw error when renderer is not found', async () => {
283
+ const view = createMockView('nonexistent-integration');
284
+ const RendererFactory = {
285
+ getRendererByIntegration: vi.fn(() => null),
286
+ };
287
+
288
+ const matcher = new ExplicitStaticRouteMatcher({
289
+ appConfig: { baseUrl: 'http://localhost:3000' } as any,
290
+ routeRendererFactory: RendererFactory as any,
291
+ staticRoutes: [createMockRoute('/about', view)],
292
+ });
293
+
294
+ const match = matcher.match('http://localhost:3000/about');
295
+
296
+ await expect(matcher.handleMatch(match!)).rejects.toThrow(
297
+ 'No renderer found for integration: nonexistent-integration',
298
+ );
299
+ });
300
+
301
+ test('should call renderer.renderToResponse with correct arguments', async () => {
302
+ const view = createMockView('ghtml');
303
+ const mockResponse = new Response('<html>Test</html>');
304
+ const RenderToResponse = vi.fn(() => mockResponse);
305
+ const RendererFactory = {
306
+ getRendererByIntegration: vi.fn(() => ({
307
+ renderToResponse: RenderToResponse,
308
+ })),
309
+ };
310
+
311
+ const matcher = new ExplicitStaticRouteMatcher({
312
+ appConfig: { baseUrl: 'http://localhost:3000' } as any,
313
+ routeRendererFactory: RendererFactory as any,
314
+ staticRoutes: [createMockRoute('/about', view)],
315
+ });
316
+
317
+ const match = matcher.match('http://localhost:3000/about');
318
+ const response = await matcher.handleMatch(match!);
319
+
320
+ expect(response).toBe(mockResponse);
321
+ expect(RenderToResponse).toHaveBeenCalledTimes(1);
322
+ expect(RenderToResponse).toHaveBeenCalledWith(view, {}, {});
323
+ });
324
+
325
+ test('should resolve staticProps and pass to renderer', async () => {
326
+ const view = createMockView('ghtml');
327
+ view.staticProps = vi.fn(async () => ({
328
+ props: { title: 'About Page', content: 'Hello' },
329
+ }));
330
+
331
+ const mockResponse = new Response('<html>Test</html>');
332
+ const RenderToResponse = vi.fn(() => mockResponse);
333
+ const RendererFactory = {
334
+ getRendererByIntegration: vi.fn(() => ({
335
+ renderToResponse: RenderToResponse,
336
+ })),
337
+ };
338
+
339
+ const matcher = new ExplicitStaticRouteMatcher({
340
+ appConfig: { baseUrl: 'http://localhost:3000' } as any,
341
+ routeRendererFactory: RendererFactory as any,
342
+ staticRoutes: [createMockRoute('/about', view)],
343
+ });
344
+
345
+ const match = matcher.match('http://localhost:3000/about');
346
+ await matcher.handleMatch(match!);
347
+
348
+ expect(view.staticProps).toHaveBeenCalledTimes(1);
349
+ expect(RenderToResponse).toHaveBeenCalledWith(view, { title: 'About Page', content: 'Hello' }, {});
350
+ });
351
+
352
+ test('should pass params to staticProps', async () => {
353
+ const view = createMockView('ghtml');
354
+ view.staticProps = vi.fn(async ({ pathname }) => ({
355
+ props: { slug: pathname.params.slug },
356
+ }));
357
+
358
+ const mockResponse = new Response('<html>Test</html>');
359
+ const RendererFactory = {
360
+ getRendererByIntegration: vi.fn(() => ({
361
+ renderToResponse: vi.fn(() => mockResponse),
362
+ })),
363
+ };
364
+
365
+ const matcher = new ExplicitStaticRouteMatcher({
366
+ appConfig: { baseUrl: 'http://localhost:3000' } as any,
367
+ routeRendererFactory: RendererFactory as any,
368
+ staticRoutes: [createMockRoute('/blog/:slug', view)],
369
+ });
370
+
371
+ const match = matcher.match('http://localhost:3000/blog/hello-world');
372
+ await matcher.handleMatch(match!);
373
+
374
+ expect(view.staticProps).toHaveBeenCalledWith(
375
+ expect.objectContaining({
376
+ pathname: { params: { slug: 'hello-world' } },
377
+ }),
378
+ );
379
+ });
380
+ });
381
+ });
@@ -9,6 +9,12 @@ export const EXPLICIT_STATIC_ROUTE_MATCHER_ERRORS = {
9
9
  noRendererForIntegration: (integrationName: string) => `No renderer found for integration: ${integrationName}`,
10
10
  } as const;
11
11
 
12
+ function getViewIntegrationName(view: {
13
+ config?: { integration?: string; __eco?: { integration?: string } };
14
+ }): string | undefined {
15
+ return view.config?.integration ?? view.config?.__eco?.integration;
16
+ }
17
+
12
18
  export interface ExplicitStaticRouteMatcherOptions {
13
19
  appConfig: EcoPagesAppConfig;
14
20
  routeRendererFactory: RouteRendererFactory;
@@ -102,7 +108,7 @@ export class ExplicitStaticRouteMatcher {
102
108
  const mod = await route.loader();
103
109
  const view = mod.default;
104
110
 
105
- const integrationName = view.config?.__eco?.integration;
111
+ const integrationName = getViewIntegrationName(view);
106
112
  if (!integrationName) {
107
113
  throw new Error(EXPLICIT_STATIC_ROUTE_MATCHER_ERRORS.missingIntegration(route.path));
108
114
  }