@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
@@ -0,0 +1,345 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { join } from 'node:path';
3
+ import { tmpdir } from 'node:os';
4
+ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
5
+ import { DEPENDENCY_ERRORS, DependencyResolverService } from './dependency-resolver.ts';
6
+ import type { EcoPagesAppConfig } from '../../internal-types.ts';
7
+ import type {
8
+ AssetDefinition,
9
+ AssetProcessingService,
10
+ ProcessedAsset,
11
+ ContentScriptAsset,
12
+ } from '../../services/assets/asset-processing-service/index.ts';
13
+ import type { EcoComponent } from '../../public-types.ts';
14
+
15
+ describe('DependencyResolverService', () => {
16
+ const appConfig = {
17
+ srcDir: '/app',
18
+ } as EcoPagesAppConfig;
19
+
20
+ it('should resolve dependency and lazy script paths', () => {
21
+ const assetProcessingService = {
22
+ processDependencies: vi.fn(async () => []),
23
+ } as unknown as AssetProcessingService;
24
+ const service = new DependencyResolverService(appConfig, assetProcessingService);
25
+
26
+ expect(service.resolveDependencyPath('/app/components/card', './style.css')).toBe(
27
+ '/app/components/card/style.css',
28
+ );
29
+ expect(service.resolveLazyScripts('/app/components/card', ['./client.ts', './widget.tsx'])).toBe(
30
+ '/assets/components/card/client.js,/assets/components/card/widget.js',
31
+ );
32
+ });
33
+
34
+ it('should emit module dependencies as content scripts and resolve lazy triggers by default', async () => {
35
+ let capturedDeps: AssetDefinition[] = [];
36
+ const assetProcessingService = {
37
+ processDependencies: vi.fn(async (deps: AssetDefinition[]) => {
38
+ capturedDeps = deps;
39
+ return [
40
+ {
41
+ kind: 'script',
42
+ filepath: '/app/components/table/table.client.ts',
43
+ srcUrl: '/assets/components/table/table.client.js',
44
+ },
45
+ ] as ProcessedAsset[];
46
+ }),
47
+ } as unknown as AssetProcessingService;
48
+ const service = new DependencyResolverService(appConfig, assetProcessingService);
49
+
50
+ const component = ((_) => '<table></table>') as EcoComponent<Record<string, unknown>>;
51
+ component.config = {
52
+ __eco: {
53
+ id: 'table',
54
+ integration: 'react',
55
+ file: '/app/components/table/table.tsx',
56
+ },
57
+ dependencies: {
58
+ modules: ['react-aria-components{Table,Button}', './client-utils'],
59
+ scripts: [{ src: './table.client.ts', lazy: { 'on:interaction': 'click' } }],
60
+ },
61
+ };
62
+
63
+ await service.processComponentDependencies([component], 'react');
64
+
65
+ const contentScripts = capturedDeps.filter(
66
+ (dep): dep is ContentScriptAsset => dep.kind === 'script' && dep.source === 'content',
67
+ );
68
+
69
+ expect(
70
+ contentScripts.some((script) =>
71
+ script.content.includes("export { Table, Button } from 'react-aria-components';"),
72
+ ),
73
+ ).toBe(true);
74
+ expect(contentScripts.some((script) => script.content.includes("export * from './client-utils';"))).toBe(true);
75
+ expect(contentScripts.every((script) => /^module-[a-f0-9]+$/.test(script.name ?? ''))).toBe(true);
76
+
77
+ const hasInjector = capturedDeps.some(
78
+ (dep) =>
79
+ dep.kind === 'script' &&
80
+ dep.source === 'node-module' &&
81
+ dep.importPath === '@ecopages/scripts-injector',
82
+ );
83
+ expect(hasInjector).toBe(false);
84
+
85
+ expect(component.config._resolvedLazyScripts).toBeUndefined();
86
+ expect(component.config._resolvedLazyTriggers).toHaveLength(1);
87
+ expect(component.config._resolvedLazyTriggers?.[0]?.rules).toEqual([
88
+ {
89
+ 'on:interaction': {
90
+ value: 'click',
91
+ scripts: ['/assets/components/table/table.client.js'],
92
+ },
93
+ },
94
+ ]);
95
+ });
96
+
97
+ it('should detect ecopages virtual imports via parser', async () => {
98
+ const tempDir = mkdtempSync(join(tmpdir(), 'ecopages-dependency-resolver-'));
99
+ const componentFile = join(tempDir, 'component.tsx');
100
+
101
+ writeFileSync(
102
+ componentFile,
103
+ "import { heroImage as imageAsset } from 'ecopages:images';\nexport const ok = imageAsset.src;\n",
104
+ 'utf-8',
105
+ );
106
+
107
+ let capturedDeps: AssetDefinition[] = [];
108
+ const assetProcessingService = {
109
+ processDependencies: vi.fn(async (deps: AssetDefinition[]) => {
110
+ capturedDeps = deps;
111
+ return [] as ProcessedAsset[];
112
+ }),
113
+ } as unknown as AssetProcessingService;
114
+
115
+ const service = new DependencyResolverService(appConfig, assetProcessingService);
116
+ const component = ((_) => '<div></div>') as EcoComponent<Record<string, unknown>>;
117
+ component.config = {
118
+ __eco: {
119
+ id: 'component',
120
+ integration: 'react',
121
+ file: componentFile,
122
+ },
123
+ };
124
+
125
+ try {
126
+ await service.processComponentDependencies([component], 'react');
127
+
128
+ const contentScripts = capturedDeps.filter(
129
+ (dep): dep is ContentScriptAsset => dep.kind === 'script' && dep.source === 'content',
130
+ );
131
+
132
+ expect(contentScripts.some((script) => script.content.includes("from 'ecopages:images';"))).toBe(true);
133
+ } finally {
134
+ rmSync(tempDir, { recursive: true, force: true });
135
+ }
136
+ });
137
+
138
+ it('should pass entry attributes and support inline stylesheet content', async () => {
139
+ let capturedDeps: AssetDefinition[] = [];
140
+ const assetProcessingService = {
141
+ processDependencies: vi.fn(async (deps: AssetDefinition[]) => {
142
+ capturedDeps = deps;
143
+ return [] as ProcessedAsset[];
144
+ }),
145
+ } as unknown as AssetProcessingService;
146
+
147
+ const service = new DependencyResolverService(appConfig, assetProcessingService);
148
+ const component = ((_) => '<div></div>') as EcoComponent<Record<string, unknown>>;
149
+ component.config = {
150
+ __eco: {
151
+ id: 'attrs-inline',
152
+ integration: 'react',
153
+ file: '/app/components/attrs-inline/component.tsx',
154
+ },
155
+ dependencies: {
156
+ scripts: [
157
+ {
158
+ src: './client.ts',
159
+ attributes: {
160
+ async: '',
161
+ 'data-script-id': 'main-client',
162
+ },
163
+ },
164
+ ],
165
+ stylesheets: [
166
+ {
167
+ src: './styles.css',
168
+ attributes: {
169
+ media: 'print',
170
+ },
171
+ },
172
+ {
173
+ content: 'body { background: red; }',
174
+ attributes: {
175
+ media: 'screen',
176
+ },
177
+ },
178
+ ],
179
+ },
180
+ };
181
+
182
+ await service.processComponentDependencies([component], 'react');
183
+
184
+ expect(
185
+ capturedDeps.some((dep) => {
186
+ if (dep.kind !== 'script' || dep.source !== 'file') return false;
187
+ return (
188
+ dep.filepath === '/app/components/attrs-inline/client.ts' &&
189
+ dep.attributes?.type === 'module' &&
190
+ dep.attributes?.defer === '' &&
191
+ dep.attributes?.async === '' &&
192
+ dep.attributes?.['data-script-id'] === 'main-client'
193
+ );
194
+ }),
195
+ ).toBe(true);
196
+
197
+ expect(
198
+ capturedDeps.some((dep) => {
199
+ if (dep.kind !== 'stylesheet' || dep.source !== 'file') return false;
200
+ return (
201
+ dep.filepath === '/app/components/attrs-inline/styles.css' &&
202
+ dep.attributes?.rel === 'stylesheet' &&
203
+ dep.attributes?.media === 'print'
204
+ );
205
+ }),
206
+ ).toBe(true);
207
+
208
+ expect(
209
+ capturedDeps.some((dep) => {
210
+ if (dep.kind !== 'stylesheet' || dep.source !== 'content') return false;
211
+ return dep.content === 'body { background: red; }' && dep.attributes?.media === 'screen';
212
+ }),
213
+ ).toBe(true);
214
+ });
215
+
216
+ it('should reject lazy script entry without src or content', async () => {
217
+ const assetProcessingService = {
218
+ processDependencies: vi.fn(async () => [] as ProcessedAsset[]),
219
+ } as unknown as AssetProcessingService;
220
+
221
+ const service = new DependencyResolverService(appConfig, assetProcessingService);
222
+ const component = ((_) => '<div></div>') as EcoComponent<Record<string, unknown>>;
223
+ component.config = {
224
+ __eco: {
225
+ id: 'invalid-lazy-entry',
226
+ integration: 'react',
227
+ file: '/app/components/invalid-lazy-entry/component.tsx',
228
+ },
229
+ dependencies: {
230
+ scripts: [
231
+ {
232
+ lazy: { 'on:idle': true },
233
+ },
234
+ ],
235
+ },
236
+ };
237
+
238
+ await expect(service.processComponentDependencies([component], 'react')).rejects.toThrow(
239
+ DEPENDENCY_ERRORS.LAZY_SCRIPT_MISSING_SRC,
240
+ );
241
+ });
242
+
243
+ it('should resolve lazy triggers by group, including lazy content entries', async () => {
244
+ const assetProcessingService = {
245
+ processDependencies: vi.fn(async (deps: AssetDefinition[]) => {
246
+ return deps.map((dep, index) => {
247
+ const lazyKey = dep.attributes?.['data-eco-lazy-key'];
248
+ const hasContent = dep.source === 'content' && typeof (dep as any).content === 'string';
249
+ const isLazyScript = dep.kind === 'script' && Boolean(lazyKey);
250
+ const srcUrl = isLazyScript
251
+ ? hasContent
252
+ ? `/assets/lazy/content-${index}.js`
253
+ : `/assets/lazy/file-${index}.js`
254
+ : undefined;
255
+
256
+ return {
257
+ kind: dep.kind ?? 'script',
258
+ filepath: (dep as Record<string, any>).filepath,
259
+ attributes: dep.attributes,
260
+ srcUrl,
261
+ } as ProcessedAsset;
262
+ });
263
+ }),
264
+ } as unknown as AssetProcessingService;
265
+
266
+ const service = new DependencyResolverService(appConfig, assetProcessingService);
267
+ const component = ((_) => '<div></div>') as EcoComponent<Record<string, unknown>>;
268
+ component.config = {
269
+ __eco: {
270
+ id: 'multi-lazy-groups',
271
+ integration: 'lit',
272
+ file: '/app/components/multi-lazy-groups/component.tsx',
273
+ },
274
+ dependencies: {
275
+ scripts: [
276
+ { src: './idle.ts', lazy: { 'on:idle': true } },
277
+ { content: 'console.log("visible")', lazy: { 'on:visible': '0.25' } },
278
+ ],
279
+ },
280
+ };
281
+
282
+ await service.processComponentDependencies([component], 'lit');
283
+
284
+ expect(component.config._resolvedLazyScripts).toBeUndefined();
285
+ expect(component.config._resolvedLazyTriggers).toHaveLength(1);
286
+
287
+ const rules = component.config._resolvedLazyTriggers?.[0]?.rules ?? [];
288
+ const idleRule = rules.find((rule) => 'on:idle' in rule);
289
+ const visibleRule = rules.find((rule) => 'on:visible' in rule);
290
+
291
+ expect(idleRule && 'on:idle' in idleRule ? idleRule['on:idle'].scripts[0] : undefined).toMatch(
292
+ /^\/assets\/lazy\/file-\d+\.js$/,
293
+ );
294
+ expect(visibleRule && 'on:visible' in visibleRule ? visibleRule['on:visible'].scripts[0] : undefined).toMatch(
295
+ /^\/assets\/lazy\/content-\d+\.js$/,
296
+ );
297
+ });
298
+
299
+ it('should ignore undefined component entries when collecting nested dependencies', async () => {
300
+ let capturedDeps: AssetDefinition[] = [];
301
+ const assetProcessingService = {
302
+ processDependencies: vi.fn(async (deps: AssetDefinition[]) => {
303
+ capturedDeps = deps;
304
+ return [] as ProcessedAsset[];
305
+ }),
306
+ } as unknown as AssetProcessingService;
307
+
308
+ const service = new DependencyResolverService(appConfig, assetProcessingService);
309
+ const nestedComponent = ((_) => '<button></button>') as EcoComponent<Record<string, unknown>>;
310
+ nestedComponent.config = {
311
+ __eco: {
312
+ id: 'theme-toggle',
313
+ integration: 'react',
314
+ file: '/app/components/theme-toggle.tsx',
315
+ },
316
+ dependencies: {
317
+ scripts: ['./theme-toggle.client.ts'],
318
+ },
319
+ };
320
+
321
+ const component = ((_) => '<div></div>') as EcoComponent<Record<string, unknown>>;
322
+ component.config = {
323
+ __eco: {
324
+ id: 'page',
325
+ integration: 'kitajs',
326
+ file: '/app/views/page.tsx',
327
+ },
328
+ dependencies: {
329
+ components: [undefined, nestedComponent] as unknown as EcoComponent[],
330
+ },
331
+ };
332
+
333
+ await expect(
334
+ service.processComponentDependencies([undefined as unknown as EcoComponent, component], 'kitajs'),
335
+ ).resolves.toEqual([]);
336
+
337
+ expect(capturedDeps).toEqual([
338
+ expect.objectContaining({
339
+ kind: 'script',
340
+ source: 'file',
341
+ filepath: '/app/components/theme-toggle.client.ts',
342
+ }),
343
+ ]);
344
+ });
345
+ });
@@ -6,16 +6,16 @@ import type {
6
6
  EcoComponentScriptEntry,
7
7
  LazyTriggerRule,
8
8
  ResolvedLazyTrigger,
9
- } from '../public-types.ts';
10
- import type { EcoPagesAppConfig } from '../internal-types.ts';
9
+ } from '../../public-types.ts';
10
+ import type { EcoPagesAppConfig } from '../../internal-types.ts';
11
11
  import type {
12
12
  AssetDefinition,
13
13
  AssetProcessingService,
14
14
  ProcessedAsset,
15
- } from '../services/asset-processing-service/index.ts';
16
- import { rapidhash } from '../utils/hash.ts';
17
- import { AssetFactory } from '../services/asset-processing-service/index.ts';
18
- import { normalizeModuleDeclarations } from '../eco/module-dependencies.ts';
15
+ } from '../../services/assets/asset-processing-service/index.ts';
16
+ import { rapidhash } from '../../utils/hash.ts';
17
+ import { AssetFactory } from '../../services/assets/asset-processing-service/index.ts';
18
+ import { normalizeModuleDeclarations } from '../../eco/module-dependencies.ts';
19
19
  import { parseSync } from 'oxc-parser';
20
20
 
21
21
  export const DEPENDENCY_ERRORS = {
@@ -243,11 +243,25 @@ function buildResolvedLazyTriggers(
243
243
  }
244
244
 
245
245
  export class DependencyResolverService {
246
- constructor(
247
- private appConfig: EcoPagesAppConfig,
248
- private assetProcessingService: AssetProcessingService,
249
- ) {}
246
+ private appConfig: EcoPagesAppConfig;
247
+ private assetProcessingService: AssetProcessingService;
250
248
 
249
+ /**
250
+ * Creates the dependency resolver used by route and component rendering.
251
+ *
252
+ * @remarks
253
+ * The resolver stays intentionally separate from HTML rendering so component
254
+ * dependency collection, lazy trigger grouping, and processed-asset generation
255
+ * can evolve without changing renderer implementations.
256
+ */
257
+ constructor(appConfig: EcoPagesAppConfig, assetProcessingService: AssetProcessingService) {
258
+ this.appConfig = appConfig;
259
+ this.assetProcessingService = assetProcessingService;
260
+ }
261
+
262
+ /**
263
+ * Resolves one dependency path relative to the component that declared it.
264
+ */
251
265
  resolveDependencyPath(componentDir: string, pathUrl: string): string {
252
266
  return resolveDependencyPath(componentDir, pathUrl);
253
267
  }
@@ -265,7 +279,7 @@ export class DependencyResolverService {
265
279
  * Lazy dependencies are always resolved into global-injector trigger maps.
266
280
  */
267
281
  async processComponentDependencies(
268
- components: (EcoComponent | Partial<EcoComponent>)[],
282
+ components: Array<EcoComponent | Partial<EcoComponent> | undefined | null>,
269
283
  integrationName: string,
270
284
  ): Promise<ProcessedAsset[]> {
271
285
  if (!this.assetProcessingService?.processDependencies) return [];
@@ -282,6 +296,8 @@ export class DependencyResolverService {
282
296
  const lazyDependencyKeys = new Set<string>();
283
297
 
284
298
  for (const component of components) {
299
+ if (!component) continue;
300
+
285
301
  const componentFile = component.config?.__eco?.file;
286
302
  if (!componentFile) continue;
287
303
 
@@ -511,7 +527,7 @@ export class DependencyResolverService {
511
527
 
512
528
  if (dependenciesConfig?.components) {
513
529
  for (const nestedComponent of dependenciesConfig.components) {
514
- if (nestedComponent.config) {
530
+ if (nestedComponent?.config) {
515
531
  collect(nestedComponent.config);
516
532
  }
517
533
  }
@@ -0,0 +1,96 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { PageModuleLoaderService } from './page-module-loader.ts';
3
+ import type { EcoPagesAppConfig } from '../../internal-types.ts';
4
+ import type { EcoPageFile } from '../../public-types.ts';
5
+ import type { EcoPageComponent } from '../../eco/eco.types.ts';
6
+
7
+ describe('PageModuleLoaderService', () => {
8
+ const appConfig = {
9
+ defaultMetadata: {
10
+ title: 'Default title',
11
+ description: 'Default description',
12
+ },
13
+ } as EcoPagesAppConfig;
14
+
15
+ it('should resolve static props via getStaticPropsForPage', async () => {
16
+ const service = new PageModuleLoaderService(appConfig, 'http://localhost:3000');
17
+ const result = await service.getStaticPropsForPage({
18
+ getStaticProps: async () => ({
19
+ props: { title: 'Page title' },
20
+ }),
21
+ params: { slug: 'a' },
22
+ });
23
+
24
+ expect(result.props).toEqual({ title: 'Page title' });
25
+ });
26
+
27
+ it('should merge default and dynamic metadata', async () => {
28
+ const service = new PageModuleLoaderService(appConfig, 'http://localhost:3000');
29
+ const metadata = await service.getMetadataPropsForPage({
30
+ getMetadata: async ({ props }) => ({
31
+ title: String(props.title),
32
+ description: 'Dynamic description',
33
+ }),
34
+ context: {
35
+ props: { title: 'Dynamic title' },
36
+ appConfig,
37
+ params: {},
38
+ query: {},
39
+ },
40
+ });
41
+
42
+ expect(metadata).toEqual({
43
+ title: 'Dynamic title',
44
+ description: 'Dynamic description',
45
+ });
46
+ });
47
+
48
+ it('should resolve page module using provided importer and prefer component static exports', async () => {
49
+ const service = new PageModuleLoaderService(appConfig, 'http://localhost:3000');
50
+ const Page = (() => 'ok') as EcoPageComponent<any>;
51
+ Page.staticProps = async () => ({ props: { from: 'component-static' } });
52
+ Page.metadata = async () => ({
53
+ title: 'component-metadata',
54
+ description: 'component-description',
55
+ });
56
+
57
+ const module = {
58
+ default: Page,
59
+ getStaticProps: async () => ({ props: { from: 'module-static' } }),
60
+ getMetadata: async () => ({ title: 'module-metadata' }),
61
+ extra: 'integration-value',
62
+ } as unknown as EcoPageFile;
63
+
64
+ const result = await service.resolvePageModule({
65
+ file: '/app/pages/index.tsx',
66
+ importPageFileFn: async () => module,
67
+ });
68
+
69
+ expect(result.getStaticProps).toBe(Page.staticProps);
70
+ expect(result.getMetadata).toBe(Page.metadata);
71
+ expect(result.integrationSpecificProps).toEqual({ extra: 'integration-value' });
72
+ });
73
+
74
+ it('should resolve page data end-to-end', async () => {
75
+ const service = new PageModuleLoaderService(appConfig, 'http://localhost:3000');
76
+ const result = await service.resolvePageData({
77
+ pageModule: {
78
+ getStaticProps: async () => ({ props: { title: 'From props' } }),
79
+ getMetadata: async ({ props }) => ({
80
+ title: String(props.title),
81
+ description: 'From metadata',
82
+ }),
83
+ },
84
+ routeOptions: {
85
+ file: '/app/pages/index.tsx',
86
+ params: {},
87
+ query: {},
88
+ },
89
+ });
90
+
91
+ expect(result).toEqual({
92
+ props: { title: 'From props' },
93
+ metadata: { title: 'From props', description: 'From metadata' },
94
+ });
95
+ });
96
+ });
@@ -1,4 +1,4 @@
1
- import { invariant } from '../utils/invariant.ts';
1
+ import { invariant } from '../../utils/invariant.ts';
2
2
  import type {
3
3
  EcoPageFile,
4
4
  GetMetadata,
@@ -7,33 +7,50 @@ import type {
7
7
  PageMetadataProps,
8
8
  RouteRendererOptions,
9
9
  EcoPageComponent,
10
- } from '../public-types.ts';
11
- import type { EcoPagesAppConfig } from '../internal-types.ts';
12
- import { PageModuleImportService } from '../services/page-module-import.service.ts';
10
+ } from '../../public-types.ts';
11
+ import type { EcoPagesAppConfig } from '../../internal-types.ts';
12
+ import { getAppServerModuleTranspiler } from '../../services/module-loading/app-server-module-transpiler.service.ts';
13
+ import type { ServerModuleTranspiler } from '../../services/module-loading/server-module-transpiler.service.ts';
14
+ import { resolveInternalExecutionDir } from '../../utils/resolve-work-dir.ts';
13
15
 
14
16
  /**
15
- * Handles page module loading plus static props/metadata resolution.
17
+ * Loads route page modules and normalizes their data hooks for rendering.
18
+ *
19
+ * @remarks
20
+ * This service keeps the render pipeline from depending directly on raw module
21
+ * imports. It owns the shared server-module transpiler setup, the precedence
22
+ * rules between component statics and module exports, and the normalization of
23
+ * page props and metadata into one renderer-facing shape.
16
24
  */
17
25
  export class PageModuleLoaderService {
18
- private pageModuleImportService: PageModuleImportService;
26
+ private serverModuleTranspiler: ServerModuleTranspiler;
27
+ private appConfig: EcoPagesAppConfig;
28
+ private runtimeOrigin: string;
19
29
 
20
- constructor(
21
- private appConfig: EcoPagesAppConfig,
22
- private runtimeOrigin: string,
23
- ) {
24
- this.pageModuleImportService = new PageModuleImportService();
30
+ /**
31
+ * Creates the page-module loader for one app/runtime instance.
32
+ *
33
+ * @param appConfig Finalized app config that owns build and invalidation state.
34
+ * @param runtimeOrigin Runtime origin exposed to page data hooks.
35
+ */
36
+ constructor(appConfig: EcoPagesAppConfig, runtimeOrigin: string) {
37
+ this.appConfig = appConfig;
38
+ this.runtimeOrigin = runtimeOrigin;
39
+ this.serverModuleTranspiler = getAppServerModuleTranspiler(appConfig);
25
40
  }
26
41
 
27
42
  /**
28
- * Imports a page module from source.
29
- * Uses direct dynamic import in Bun and transpile+import fallback for other runtimes.
43
+ * Imports one page module through the shared server-side module loading path.
44
+ *
45
+ * @remarks
46
+ * The underlying transpiler keeps Bun and Node aligned on one framework-owned
47
+ * loading contract even though the runtime-specific execution transport differs.
30
48
  */
31
49
  async importPageFile(file: string): Promise<EcoPageFile> {
32
50
  try {
33
- return await this.pageModuleImportService.importModule<EcoPageFile>({
51
+ return await this.serverModuleTranspiler.importModule<EcoPageFile>({
34
52
  filePath: file,
35
- rootDir: this.appConfig.rootDir,
36
- outdir: `${this.appConfig.absolutePaths.distDir}/.server-modules`,
53
+ outdir: `${resolveInternalExecutionDir(this.appConfig)}/.server-modules`,
37
54
  transpileErrorMessage: (details) => `Error transpiling page file: ${details}`,
38
55
  noOutputMessage: (targetFilePath) => `No transpiled output generated for page: ${targetFilePath}`,
39
56
  });
@@ -43,8 +60,11 @@ export class PageModuleLoaderService {
43
60
  }
44
61
 
45
62
  /**
46
- * Executes `getStaticProps` with Ecopages runtime context.
47
- * Returns an empty props object when no static props function is defined.
63
+ * Executes the page's static-props hook with Ecopages runtime context.
64
+ *
65
+ * @remarks
66
+ * Pages without a static-props hook still return a normalized empty props
67
+ * object so downstream render preparation does not branch on hook presence.
48
68
  */
49
69
  async getStaticPropsForPage(options: {
50
70
  getStaticProps?: GetStaticProps<Record<string, unknown>>;
@@ -71,8 +91,11 @@ export class PageModuleLoaderService {
71
91
  }
72
92
 
73
93
  /**
74
- * Builds final page metadata using app-level defaults as a baseline.
75
- * If `getMetadata` exists, its result overlays defaults so page-level fields take precedence.
94
+ * Builds the final page metadata object for one render request.
95
+ *
96
+ * @remarks
97
+ * App-level default metadata forms the baseline, then page-level metadata is
98
+ * overlaid so route-specific fields win without dropping global defaults.
76
99
  */
77
100
  async getMetadataPropsForPage(options: {
78
101
  getMetadata: GetMetadata | undefined;
@@ -122,7 +145,12 @@ export class PageModuleLoaderService {
122
145
  }
123
146
 
124
147
  /**
125
- * Resolves render-time page data in order: static props first, then metadata derived from those props.
148
+ * Resolves the page data needed by the render pipeline.
149
+ *
150
+ * @remarks
151
+ * Static props are resolved first because page metadata may depend on those
152
+ * props. This preserves the same ordering whether data hooks are declared as
153
+ * component statics or module exports.
126
154
  */
127
155
  async resolvePageData(options: {
128
156
  pageModule: {