@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
@@ -2,7 +2,8 @@
2
2
  * JavaScript HMR Strategy
3
3
  *
4
4
  * Handles hot module replacement for JavaScript and TypeScript entrypoints.
5
- * Bundles files, replaces bare specifiers, and injects HMR boilerplate.
5
+ * Bundles files, inspects the emitted output, and decides whether the browser
6
+ * can hot-accept the change or must reload.
6
7
  *
7
8
  * @module
8
9
  */
@@ -11,8 +12,9 @@ import path from 'node:path';
11
12
  import { fileSystem } from '@ecopages/file-system';
12
13
  import { HmrStrategy, HmrStrategyType, type HmrAction } from '../hmr-strategy';
13
14
  import { appLogger } from '../../global/app-logger';
14
- import { defaultBuildAdapter } from '../../build/build-adapter.ts';
15
15
  import type { EcoBuildPlugin } from '../../build/build-types.ts';
16
+ import type { BrowserBundleExecutor } from '../../services/assets/browser-bundle.service.ts';
17
+ import type { EntrypointDependencyGraph } from '../../services/runtime-state/entrypoint-dependency-graph.service.ts';
16
18
 
17
19
  /**
18
20
  * Context interface providing access to HmrManager state.
@@ -29,24 +31,7 @@ export interface JsHmrContext {
29
31
  */
30
32
  getSpecifierMap(): Map<string, string>;
31
33
 
32
- /**
33
- * Returns entrypoints impacted by a changed dependency path.
34
- *
35
- * @remarks
36
- * This hook is currently provided by the Node HMR manager where dependency
37
- * graph metadata is extracted from the Node/esbuild build adapter.
38
- */
39
- getDependencyEntrypoints?(filePath: string): Set<string>;
40
-
41
- /**
42
- * Stores latest dependency set for an entrypoint.
43
- *
44
- * @remarks
45
- * This hook is currently used only by the Node HMR manager to maintain a
46
- * reverse invalidation index. Runtimes that do not provide it keep rebuild-all
47
- * fallback semantics.
48
- */
49
- setEntrypointDependencies?(entrypointPath: string, dependencies: string[]): void;
34
+ getEntrypointDependencyGraph(): EntrypointDependencyGraph;
50
35
 
51
36
  /**
52
37
  * Directory where HMR bundles are written.
@@ -62,24 +47,53 @@ export interface JsHmrContext {
62
47
  * Absolute path to the source directory.
63
48
  */
64
49
  getSrcDir(): string;
50
+
51
+ /**
52
+ * Absolute path to the pages directory.
53
+ */
54
+ getPagesDir(): string;
55
+
56
+ /**
57
+ * Absolute path to the layouts directory.
58
+ */
59
+ getLayoutsDir(): string;
60
+
61
+ /**
62
+ * All configured route-template extensions across integrations.
63
+ */
64
+ getTemplateExtensions(): string[];
65
+
66
+ /**
67
+ * Browser bundler used to rebuild changed entrypoints.
68
+ */
69
+ getBrowserBundleService(): BrowserBundleExecutor;
70
+
71
+ /**
72
+ * Returns whether a watched entrypoint should be rebuilt by the generic JS strategy.
73
+ *
74
+ * @remarks
75
+ * Integrations with higher-priority HMR strategies can use this to keep the
76
+ * generic JS strategy from overwriting their emitted entrypoints when a shared
77
+ * dependency changes.
78
+ */
79
+ shouldProcessEntrypoint?(entrypointPath: string): boolean;
65
80
  }
66
81
 
67
82
  /**
68
83
  * Strategy for handling JavaScript/TypeScript file changes with hot reloading.
69
84
  *
70
- * This strategy rebuilds all registered entrypoints when any file changes,
71
- * as we don't currently track dependencies. This is safe but inefficient.
72
- *
73
85
  * The processing steps are:
74
86
  * 1. Check if any entrypoints are registered
75
- * 2. Rebuild all entrypoints (the changed file could be a dependency)
76
- * 3. Replace bare specifiers with vendor URLs
87
+ * 2. Rebuild impacted entrypoints, or all watched entrypoints when no runtime
88
+ * dependency graph is available
89
+ * 3. Emit rebuilt entrypoint bundles for browser delivery
77
90
  * 4. Inject generic HMR boilerplate
78
91
  * 5. Broadcast update events for each rebuilt entrypoint
79
92
  *
80
93
  * @remarks
81
- * Future enhancement: Track dependencies using Bun's transpiler API to only
82
- * rebuild affected entrypoints instead of all of them.
94
+ * Node can provide dependency-graph metadata, so this strategy can rebuild only
95
+ * the entrypoints impacted by a changed dependency. Runtimes that do not expose
96
+ * that metadata intentionally keep the rebuild-all fallback.
83
97
  *
84
98
  * @see https://bun.sh/docs/runtime/transpiler
85
99
  *
@@ -97,9 +111,11 @@ export interface JsHmrContext {
97
111
  */
98
112
  export class JsHmrStrategy extends HmrStrategy {
99
113
  readonly type = HmrStrategyType.SCRIPT;
114
+ private context: JsHmrContext;
100
115
 
101
- constructor(private context: JsHmrContext) {
116
+ constructor(context: JsHmrContext) {
102
117
  super();
118
+ this.context = context;
103
119
  }
104
120
 
105
121
  /**
@@ -116,6 +132,10 @@ export class JsHmrStrategy extends HmrStrategy {
116
132
  const watchedFiles = this.context.getWatchedFiles();
117
133
  const isJsTs = /\.(ts|tsx|js|jsx)$/.test(filePath);
118
134
  const isInSrc = filePath.startsWith(this.context.getSrcDir());
135
+ const isRouteTemplate =
136
+ filePath.startsWith(this.context.getPagesDir()) || filePath.startsWith(this.context.getLayoutsDir());
137
+ const isIntegrationTemplate =
138
+ isRouteTemplate && this.context.getTemplateExtensions().some((extension) => filePath.endsWith(extension));
119
139
 
120
140
  if (watchedFiles.size === 0) {
121
141
  return false;
@@ -125,12 +145,17 @@ export class JsHmrStrategy extends HmrStrategy {
125
145
  return false;
126
146
  }
127
147
 
148
+ if (isIntegrationTemplate) {
149
+ return false;
150
+ }
151
+
128
152
  if (watchedFiles.has(filePath)) {
129
153
  return true;
130
154
  }
131
155
 
132
- if (this.context.getDependencyEntrypoints) {
133
- return this.context.getDependencyEntrypoints(filePath).size > 0;
156
+ const entrypointDependencyGraph = this.context.getEntrypointDependencyGraph();
157
+ if (entrypointDependencyGraph.supportsSelectiveInvalidation()) {
158
+ return entrypointDependencyGraph.getDependencyEntrypoints(filePath).size > 0;
134
159
  }
135
160
 
136
161
  return true;
@@ -144,6 +169,8 @@ export class JsHmrStrategy extends HmrStrategy {
144
169
  * @remarks
145
170
  * If runtime-specific dependency graph hooks are unavailable, this strategy
146
171
  * falls back to rebuilding all watched entrypoints.
172
+ * When multiple entrypoints are impacted they are bundled in a single esbuild
173
+ * invocation to share AST parsing and chunk deduplication.
147
174
  * @returns Action to broadcast update events
148
175
  */
149
176
  async process(filePath: string): Promise<HmrAction> {
@@ -155,30 +182,48 @@ export class JsHmrStrategy extends HmrStrategy {
155
182
  return { type: 'none' };
156
183
  }
157
184
 
158
- const updates: string[] = [];
159
- let reloadRequired = false;
160
- const dependencyHits = this.context.getDependencyEntrypoints?.(filePath) ?? new Set<string>();
185
+ const dependencyHits = this.context.getEntrypointDependencyGraph().getDependencyEntrypoints(filePath);
161
186
  const hasDependencyHit = dependencyHits.size > 0;
162
187
  const impactedEntrypoints = hasDependencyHit
163
188
  ? Array.from(dependencyHits).filter((entrypoint) => watchedFiles.has(entrypoint))
164
189
  : Array.from(watchedFiles.keys());
190
+ const buildableEntrypoints = impactedEntrypoints.filter(
191
+ (entrypoint) => this.context.shouldProcessEntrypoint?.(entrypoint) ?? true,
192
+ );
165
193
 
166
194
  if (!hasDependencyHit) {
167
195
  appLogger.debug('[JsHmrStrategy] Dependency graph miss, rebuilding all watched entrypoints');
168
196
  }
169
197
 
170
- for (const entrypoint of impactedEntrypoints) {
198
+ if (buildableEntrypoints.length === 0) {
199
+ return { type: 'none' };
200
+ }
201
+
202
+ const buildResult = await this.bundleEntrypoints(buildableEntrypoints);
203
+
204
+ if (!buildResult.success) {
205
+ return { type: 'none' };
206
+ }
207
+
208
+ const updates: string[] = [];
209
+ let reloadRequired = false;
210
+
211
+ for (const entrypoint of buildableEntrypoints) {
171
212
  const outputUrl = watchedFiles.get(entrypoint);
172
- if (!outputUrl) {
173
- continue;
213
+ if (!outputUrl) continue;
214
+
215
+ if (buildResult.dependencies) {
216
+ const entrypointDeps = buildResult.dependencies.get(path.resolve(entrypoint)) ?? [];
217
+ this.context.getEntrypointDependencyGraph().setEntrypointDependencies(entrypoint, entrypointDeps);
174
218
  }
175
219
 
176
- const result = await this.bundleEntrypoint(entrypoint, outputUrl);
177
- if (result.success) {
178
- if (result.dependencies && this.context.setEntrypointDependencies) {
179
- this.context.setEntrypointDependencies(entrypoint, result.dependencies);
180
- }
220
+ const srcDir = this.context.getSrcDir();
221
+ const relativePath = path.relative(srcDir, entrypoint);
222
+ const relativePathJs = relativePath.replace(/\.(tsx?|jsx?|mdx?)$/, '.js');
223
+ const outputPath = path.join(this.context.getDistDir(), relativePathJs);
181
224
 
225
+ const result = await this.processOutput(outputPath, outputUrl);
226
+ if (result.success) {
182
227
  updates.push(outputUrl);
183
228
  if (result.requiresReload) {
184
229
  reloadRequired = true;
@@ -191,19 +236,15 @@ export class JsHmrStrategy extends HmrStrategy {
191
236
  appLogger.debug(`[JsHmrStrategy] Full reload required (no HMR accept found)`);
192
237
  return {
193
238
  type: 'broadcast',
194
- events: [
195
- {
196
- type: 'reload',
197
- },
198
- ],
239
+ events: [{ type: 'reload' }],
199
240
  };
200
241
  }
201
242
 
202
243
  return {
203
244
  type: 'broadcast',
204
- events: updates.map((path) => ({
245
+ events: updates.map((p) => ({
205
246
  type: 'update',
206
- path,
247
+ path: p,
207
248
  timestamp: Date.now(),
208
249
  })),
209
250
  };
@@ -213,52 +254,46 @@ export class JsHmrStrategy extends HmrStrategy {
213
254
  }
214
255
 
215
256
  /**
216
- * Bundles a single entrypoint and processes the output.
217
- *
218
- * @param entrypointPath - Absolute path to the source file
219
- * @param outputUrl - URL path for the bundled file
220
- * @returns True if bundling was successful
257
+ * Bundles one or more entrypoints in a single esbuild invocation.
258
+ * Uses the source directory as the output base so that the directory structure
259
+ * is preserved under the HMR dist folder.
221
260
  */
222
- private async bundleEntrypoint(
223
- entrypointPath: string,
224
- outputUrl: string,
225
- ): Promise<{ success: boolean; requiresReload: boolean; dependencies?: string[] }> {
261
+ private async bundleEntrypoints(
262
+ entrypoints: string[],
263
+ ): Promise<{ success: boolean; dependencies?: Map<string, string[]> }> {
226
264
  try {
227
- const srcDir = this.context.getSrcDir();
228
- const relativePath = path.relative(srcDir, entrypointPath);
229
- const relativePathJs = relativePath.replace(/\.(tsx?|jsx?)$/, '.js');
230
- const outputPath = path.join(this.context.getDistDir(), relativePathJs);
231
-
232
- const result = await defaultBuildAdapter.build({
233
- entrypoints: [entrypointPath],
265
+ const result = await this.context.getBrowserBundleService().bundle({
266
+ profile: 'hmr-entrypoint',
267
+ entrypoints,
234
268
  outdir: this.context.getDistDir(),
235
- naming: relativePathJs,
236
- ...defaultBuildAdapter.getTranspileOptions('hmr-entrypoint'),
269
+ outbase: this.context.getSrcDir(),
270
+ naming: '[dir]/[name]',
237
271
  plugins: this.context.getPlugins(),
238
272
  minify: false,
239
- external: ['react', 'react-dom'],
240
273
  });
241
274
 
242
275
  if (!result.success) {
243
- appLogger.error(`[JsHmrStrategy] Failed to build ${entrypointPath}:`, result.logs);
244
- return { success: false, requiresReload: false, dependencies: undefined };
276
+ appLogger.error('[JsHmrStrategy] Batched build failed:', result.logs);
277
+ return { success: false };
245
278
  }
246
279
 
247
- const dependencyGraph = result.dependencyGraph?.entrypoints?.[path.resolve(entrypointPath)] ?? [];
248
- const output = await this.processOutput(outputPath, outputUrl);
280
+ const dependencies = new Map<string, string[]>();
281
+ if (result.dependencyGraph?.entrypoints) {
282
+ for (const [entrypoint, deps] of Object.entries(result.dependencyGraph.entrypoints)) {
283
+ dependencies.set(path.resolve(entrypoint), deps);
284
+ }
285
+ }
249
286
 
250
- return {
251
- ...output,
252
- dependencies: dependencyGraph,
253
- };
287
+ return { success: true, dependencies };
254
288
  } catch (error) {
255
- appLogger.error(`[JsHmrStrategy] Error bundling ${entrypointPath}:`, error as Error);
256
- return { success: false, requiresReload: false, dependencies: undefined };
289
+ appLogger.error('[JsHmrStrategy] Error in batched build:', error as Error);
290
+ return { success: false };
257
291
  }
258
292
  }
259
293
 
260
294
  /**
261
- * Processes bundled output by replacing specifiers and injecting HMR code.
295
+ * Processes bundled output and determines whether the browser can hot-accept
296
+ * the update or must fall back to a full reload.
262
297
  *
263
298
  * @param filepath - Path to the bundled output file
264
299
  * @param url - URL path for the bundled file
@@ -266,25 +301,15 @@ export class JsHmrStrategy extends HmrStrategy {
266
301
  */
267
302
  private async processOutput(filepath: string, url: string): Promise<{ success: boolean; requiresReload: boolean }> {
268
303
  try {
269
- let code = await fileSystem.readFile(filepath);
304
+ const code = await fileSystem.readFile(filepath);
270
305
 
271
306
  if (code.includes('/* [ecopages] hmr */')) {
272
- /**
273
- * Already processed, assume it supports HMR if it has the header (legacy safety)
274
- * or check specifically for accept
275
- */
307
+ // Legacy safety: previously processed bundles already carry the marker.
276
308
  return { success: true, requiresReload: !code.includes('import.meta.hot.accept') };
277
309
  }
278
310
 
279
- code = this.replaceBareSpecifiers(code);
280
- await fileSystem.writeAsync(filepath, code);
281
-
282
311
  appLogger.debug(`[JsHmrStrategy] Processed ${url}`);
283
312
 
284
- /**
285
- * Implicit HMR check: if the code explicitly accepts HMR, we broadcast update.
286
- * Otherwise, we must reload the page to ensure fresh execution (e.g. for Custom Elements or side effects).
287
- */
288
313
  const hasHmrAccept = code.includes('import.meta.hot.accept');
289
314
  return { success: true, requiresReload: !hasHmrAccept };
290
315
  } catch (error) {
@@ -292,29 +317,4 @@ export class JsHmrStrategy extends HmrStrategy {
292
317
  return { success: false, requiresReload: false };
293
318
  }
294
319
  }
295
-
296
- /**
297
- * Replaces bare specifiers with vendor URLs.
298
- *
299
- * Handles both static imports and dynamic imports.
300
- *
301
- * @param code - The bundled code to transform
302
- * @returns The transformed code with vendor URLs
303
- */
304
- private replaceBareSpecifiers(code: string): string {
305
- const specifierMap = this.context.getSpecifierMap();
306
-
307
- if (specifierMap.size === 0) {
308
- return code;
309
- }
310
-
311
- let result = code;
312
- for (const [bareSpec, vendorUrl] of specifierMap.entries()) {
313
- const escaped = bareSpec.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
314
- result = result.replace(new RegExp(`from\\s*["']${escaped}["']`, 'g'), `from "${vendorUrl}"`);
315
- result = result.replace(new RegExp(`import\\(["']${escaped}["']\\)`, 'g'), `import("${vendorUrl}")`);
316
- }
317
-
318
- return result;
319
- }
320
320
  }
package/src/index.ts CHANGED
@@ -2,4 +2,4 @@ export type * from './public-types.ts';
2
2
  export type * from './eco/eco.types.ts';
3
3
  export { eco } from './eco/eco.ts';
4
4
  export { EcopagesApp, createApp, type EcopagesAppOptions } from './create-app.ts';
5
- export { defineApiHandler, defineGroupHandler, type GroupHandler } from './define-api-handler.ts';
5
+ export { defineApiHandler, defineGroupHandler, type GroupHandler } from './adapters/shared/define-api-handler.ts';
@@ -0,0 +1,63 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import HtmlTemplate from '../../../__fixtures__/app/src/includes/html.ghtml.js';
3
+ import { FIXTURE_APP_PROJECT_DIR } from '../../../__fixtures__/constants.js';
4
+ import { ConfigBuilder } from '../../config/config-builder.ts';
5
+ import { GhtmlRenderer } from './ghtml-renderer.ts';
6
+
7
+ const appConfig = await new ConfigBuilder().setRootDir(FIXTURE_APP_PROJECT_DIR).build();
8
+
9
+ const metadata = {
10
+ title: 'Ecopages',
11
+ description: 'Ecopages',
12
+ };
13
+
14
+ const pageBody = '<body>Hello World</body>';
15
+
16
+ const rendererContext = {
17
+ appConfig,
18
+ } as unknown as any;
19
+
20
+ describe('GhtmlRenderer', () => {
21
+ it('should render the page', async () => {
22
+ const renderer = new GhtmlRenderer(rendererContext);
23
+
24
+ renderer
25
+ .render({
26
+ params: {},
27
+ query: {},
28
+ props: {},
29
+ file: 'file',
30
+ metadata,
31
+ Page: async () => pageBody,
32
+ resolvedDependencies: [],
33
+ HtmlTemplate,
34
+ })
35
+ .then((body) => {
36
+ expect(body).toContain('<!DOCTYPE html>');
37
+ expect(body).toContain('<body>Hello World</body>');
38
+ expect(body).toContain('<title>Ecopages</title>');
39
+ expect(body).toContain('<meta name="description" content="Ecopages" />');
40
+ });
41
+ });
42
+
43
+ it('should throw an error if the page fails to render', async () => {
44
+ const renderer = new GhtmlRenderer(rendererContext);
45
+
46
+ renderer
47
+ .render({
48
+ params: {},
49
+ query: {},
50
+ props: {},
51
+ file: 'file',
52
+ resolvedDependencies: [],
53
+ metadata,
54
+ Page: async () => {
55
+ throw new Error('Page failed to render');
56
+ },
57
+ HtmlTemplate,
58
+ })
59
+ .catch((error) => {
60
+ expect(error.message).toBe('Error rendering page: Page failed to render');
61
+ });
62
+ });
63
+ });
@@ -10,7 +10,10 @@ import type {
10
10
  PageMetadataProps,
11
11
  RouteRendererBody,
12
12
  } from '../../public-types.ts';
13
- import { IntegrationRenderer, type RenderToResponseContext } from '../../route-renderer/integration-renderer.ts';
13
+ import {
14
+ IntegrationRenderer,
15
+ type RenderToResponseContext,
16
+ } from '../../route-renderer/orchestration/integration-renderer.ts';
14
17
  import { GHTML_PLUGIN_NAME } from './ghtml.plugin.ts';
15
18
 
16
19
  /**
@@ -1,18 +1,17 @@
1
1
  import type { EcoBuildPlugin } from './build/build-types.ts';
2
+ import type { AppBuildManifest } from './build/build-manifest.ts';
3
+ import type { BuildAdapter, BuildExecutor } from './build/build-adapter.ts';
2
4
  import type { IntegrationPlugin } from './plugins/integration-plugin.ts';
3
5
  import type { Processor } from './plugins/processor.ts';
4
6
  import type { PageMetadataProps } from './public-types.ts';
5
- import type { FSRouter } from './router/fs-router.ts';
7
+ import type { FSRouter } from './router/server/fs-router.ts';
6
8
  import type { CacheConfig } from './services/cache/cache.types.ts';
7
-
8
- /**
9
- * The templates used to build the pages and loaded via the includes directory.
10
- */
11
- export type IncludesTemplates = {
12
- head: string;
13
- html: string;
14
- seo: string;
15
- };
9
+ import type { DevGraphService } from './services/runtime-state/dev-graph.service.ts';
10
+ import type { EntrypointDependencyGraph } from './services/runtime-state/entrypoint-dependency-graph.service.ts';
11
+ import type { NodeRuntimeManifest } from './services/runtime-manifest/node-runtime-manifest.service.ts';
12
+ import type { RuntimeSpecifierRegistry } from './services/runtime-state/runtime-specifier-registry.service.ts';
13
+ import type { ServerInvalidationState } from './services/runtime-state/server-invalidation-state.service.ts';
14
+ import type { ServerModuleTranspiler } from './services/module-loading/server-module-transpiler.service.ts';
16
15
 
17
16
  export interface RobotsPreference {
18
17
  /**
@@ -61,20 +60,22 @@ export type EcoPagesAppConfig = {
61
60
  * @default "layouts"
62
61
  */
63
62
  layoutsDir: string;
64
- /**
65
- * The templates used for the pages
66
- * @default "{head: 'head.kita.tsx', html: 'html.kita.tsx', seo: 'seo.kita.tsx'}"
67
- */
68
- includesTemplates: IncludesTemplates;
69
- /** Error 404 page
70
- * @default "404.kita.tsx"
71
- */
72
- error404Template: string;
73
63
  /**
74
64
  * The directory where the output will be located
75
65
  * @default "dist"
76
66
  */
77
67
  distDir: string;
68
+ /**
69
+ * The directory where internal runtime and build artifacts are stored.
70
+ *
71
+ * @remarks
72
+ * This directory is not intended for deployment. It owns transpiled server
73
+ * modules, runtime manifests, and processor caches so `distDir` can remain a
74
+ * clean export tree.
75
+ *
76
+ * @default ".eco"
77
+ */
78
+ workDir: string;
78
79
  /**
79
80
  * The templates extensions based on the integrations
80
81
  */
@@ -109,6 +110,7 @@ export type EcoPagesAppConfig = {
109
110
  config: string;
110
111
  componentsDir: string;
111
112
  distDir: string;
113
+ workDir: string;
112
114
  includesDir: string;
113
115
  layoutsDir: string;
114
116
  pagesDir: string;
@@ -131,6 +133,24 @@ export type EcoPagesAppConfig = {
131
133
  * @default { store: 'memory', defaultStrategy: 'static', enabled: true }
132
134
  */
133
135
  cache?: CacheConfig;
136
+ /**
137
+ * Runtime-owned services attached after config construction.
138
+ *
139
+ * These values are internal implementation details used to thread per-app
140
+ * executors and similar runtime state through the system without relying on
141
+ * process-global registries.
142
+ */
143
+ runtime?: {
144
+ buildAdapter?: BuildAdapter;
145
+ buildManifest?: AppBuildManifest;
146
+ buildExecutor?: BuildExecutor;
147
+ devGraphService?: DevGraphService;
148
+ entrypointDependencyGraph?: EntrypointDependencyGraph;
149
+ nodeRuntimeManifest?: NodeRuntimeManifest;
150
+ runtimeSpecifierRegistry?: RuntimeSpecifierRegistry;
151
+ serverInvalidationState?: ServerInvalidationState;
152
+ serverModuleTranspiler?: ServerModuleTranspiler;
153
+ };
134
154
  /**
135
155
  * Experimental features.
136
156
  */
@@ -0,0 +1,34 @@
1
+ # Plugin Contracts
2
+
3
+ This directory contains the authoring contracts for Ecopages integrations, processors, and related plugin-facing runtime declarations.
4
+
5
+ ## Purpose
6
+
7
+ The plugin layer defines what packages are allowed to declare about themselves, while core retains orchestration ownership.
8
+
9
+ These contracts are responsible for:
10
+
11
+ - integration registration and lifecycle hooks
12
+ - processor registration and asset capability declaration
13
+ - runtime capability declaration and validation input
14
+ - shared build-plugin bridge types used by integrations and processors
15
+
16
+ ## Main Files
17
+
18
+ - `integration-plugin.ts`: framework-semantics contract for render integrations
19
+ - `processor.ts`: asset-transformation contract for processors
20
+ - `runtime-capability.ts`: runtime compatibility declaration types
21
+ - `eco-component-meta-plugin.ts`: shared metadata transform used by core loading/build paths
22
+
23
+ ## Ownership Rules
24
+
25
+ - Integrations own rendering semantics, hydration behavior, and integration-specific HMR strategy.
26
+ - Processors own asset semantics, cache ownership, and processor-specific watch behavior.
27
+ - Core owns lifecycle ordering, startup orchestration, and manifest assembly.
28
+
29
+ ## Lifecycle Summary
30
+
31
+ 1. Config build validates and prepares plugin contributions.
32
+ 2. Core seals the app-owned build manifest.
33
+ 3. Runtime startup calls runtime-only setup hooks.
34
+ 4. Request-time rendering and development invalidation reuse those finalized contracts.
@@ -0,0 +1,41 @@
1
+ import assert from 'node:assert/strict';
2
+ import fs from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import path from 'node:path';
5
+ import { test } from 'vitest';
6
+ import type { EcoBuildOnResolveResult } from '../build/build-types.ts';
7
+ import { createAliasResolverPlugin } from './alias-resolver-plugin.ts';
8
+
9
+ test('createAliasResolverPlugin resolves @ aliases to concrete barrel targets', async () => {
10
+ const rootDir = fs.mkdtempSync(path.join(tmpdir(), 'ecopages-alias-resolver-'));
11
+ const srcDir = path.join(rootDir, 'src');
12
+ const layoutDir = path.join(srcDir, 'layouts', 'base-layout');
13
+ fs.mkdirSync(layoutDir, { recursive: true });
14
+ fs.writeFileSync(path.join(layoutDir, 'base-layout.kita.tsx'), 'export const BaseLayout = {};\n', 'utf8');
15
+ fs.writeFileSync(path.join(layoutDir, 'index.ts'), "export * from './base-layout.kita';\n", 'utf8');
16
+
17
+ try {
18
+ const registrations: Array<{
19
+ filter: RegExp;
20
+ callback: (args: {
21
+ path: string;
22
+ }) => EcoBuildOnResolveResult | undefined | Promise<EcoBuildOnResolveResult | undefined>;
23
+ }> = [];
24
+ const plugin = createAliasResolverPlugin(srcDir);
25
+
26
+ plugin.setup({
27
+ onResolve(options, callback) {
28
+ registrations.push({ filter: options.filter, callback });
29
+ },
30
+ onLoad() {},
31
+ module() {},
32
+ });
33
+
34
+ assert.equal(registrations.length, 1);
35
+ assert.deepEqual(await registrations[0]?.callback({ path: '@/layouts/base-layout' }), {
36
+ path: path.join(layoutDir, 'base-layout.kita.tsx'),
37
+ });
38
+ } finally {
39
+ fs.rmSync(rootDir, { recursive: true, force: true });
40
+ }
41
+ });
@@ -1,4 +1,4 @@
1
- import { existsSync } from 'node:fs';
1
+ import { existsSync, readFileSync } from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import type { EcoBuildPlugin } from '../build/build-types.ts';
4
4
 
@@ -6,7 +6,9 @@ const RESOLVABLE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.m
6
6
 
7
7
  function findResolvablePath(candidate: string): string | undefined {
8
8
  if (path.extname(candidate)) {
9
- return existsSync(candidate) ? candidate : undefined;
9
+ if (existsSync(candidate)) {
10
+ return candidate;
11
+ }
10
12
  }
11
13
 
12
14
  for (const extension of RESOLVABLE_EXTENSIONS) {
@@ -26,6 +28,22 @@ function findResolvablePath(candidate: string): string | undefined {
26
28
  return undefined;
27
29
  }
28
30
 
31
+ function resolveAliasedBarrelTarget(resolvedPath: string): string {
32
+ if (!path.basename(resolvedPath).startsWith('index.')) {
33
+ return resolvedPath;
34
+ }
35
+
36
+ const source = readFileSync(resolvedPath, 'utf8').trim();
37
+ const match = source.match(/^export\s+\*\s+from\s+['"]([^'"]+)['"]\s*;?$/);
38
+
39
+ if (!match?.[1]?.startsWith('.')) {
40
+ return resolvedPath;
41
+ }
42
+
43
+ const target = findResolvablePath(path.resolve(path.dirname(resolvedPath), match[1]));
44
+ return target ?? resolvedPath;
45
+ }
46
+
29
47
  export function createAliasResolverPlugin(srcDir: string): EcoBuildPlugin {
30
48
  return {
31
49
  name: 'ecopages-alias-resolver',
@@ -35,7 +53,7 @@ export function createAliasResolverPlugin(srcDir: string): EcoBuildPlugin {
35
53
  const resolved = findResolvablePath(candidate);
36
54
 
37
55
  if (resolved) {
38
- return { path: resolved };
56
+ return { path: resolveAliasedBarrelTarget(resolved) };
39
57
  }
40
58
 
41
59
  return {};