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

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 (546) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/package.json +162 -72
  3. package/src/adapters/abstract/application-adapter.d.ts +194 -0
  4. package/src/adapters/abstract/application-adapter.js +121 -0
  5. package/src/adapters/abstract/router-adapter.d.ts +26 -0
  6. package/src/adapters/abstract/router-adapter.js +5 -0
  7. package/src/adapters/abstract/server-adapter.d.ts +69 -0
  8. package/src/adapters/abstract/server-adapter.js +15 -0
  9. package/src/adapters/bun/client-bridge.d.ts +34 -0
  10. package/src/adapters/bun/client-bridge.js +48 -0
  11. package/src/adapters/bun/create-app.d.ts +53 -0
  12. package/src/adapters/bun/create-app.js +153 -0
  13. package/src/adapters/bun/hmr-manager.d.ts +131 -0
  14. package/src/adapters/bun/hmr-manager.js +312 -0
  15. package/src/adapters/bun/index.d.ts +2 -0
  16. package/src/adapters/bun/index.js +8 -0
  17. package/src/adapters/bun/server-adapter.d.ts +155 -0
  18. package/src/adapters/bun/server-adapter.js +393 -0
  19. package/src/adapters/bun/server-lifecycle.d.ts +63 -0
  20. package/src/adapters/bun/server-lifecycle.js +92 -0
  21. package/src/adapters/create-app.d.ts +20 -0
  22. package/src/adapters/create-app.js +66 -0
  23. package/src/adapters/index.d.ts +2 -0
  24. package/src/adapters/index.js +8 -0
  25. package/src/adapters/node/create-app.d.ts +18 -0
  26. package/src/adapters/node/create-app.js +149 -0
  27. package/src/adapters/node/node-client-bridge.d.ts +26 -0
  28. package/src/adapters/node/node-client-bridge.js +66 -0
  29. package/src/adapters/node/node-hmr-manager.d.ts +121 -0
  30. package/src/adapters/node/node-hmr-manager.js +290 -0
  31. package/src/adapters/node/server-adapter.d.ts +162 -0
  32. package/src/adapters/node/server-adapter.js +368 -0
  33. package/src/adapters/node/static-content-server.d.ts +60 -0
  34. package/src/adapters/node/static-content-server.js +194 -0
  35. package/src/adapters/shared/api-response.d.ts +52 -0
  36. package/src/adapters/shared/api-response.js +96 -0
  37. package/src/adapters/shared/application-adapter.d.ts +18 -0
  38. package/src/adapters/shared/application-adapter.js +90 -0
  39. package/src/adapters/shared/define-api-handler.d.ts +25 -0
  40. package/src/adapters/shared/define-api-handler.js +15 -0
  41. package/src/adapters/shared/explicit-static-render-preparation.d.ts +25 -0
  42. package/src/adapters/shared/explicit-static-render-preparation.js +26 -0
  43. package/src/adapters/shared/explicit-static-route-matcher.d.ts +41 -0
  44. package/src/adapters/shared/explicit-static-route-matcher.js +101 -0
  45. package/src/adapters/shared/file-route-middleware-pipeline.d.ts +62 -0
  46. package/src/adapters/shared/file-route-middleware-pipeline.js +90 -0
  47. package/src/adapters/shared/fs-server-response-factory.d.ts +23 -0
  48. package/src/adapters/shared/fs-server-response-factory.js +81 -0
  49. package/src/adapters/shared/fs-server-response-matcher.d.ts +75 -0
  50. package/src/adapters/shared/fs-server-response-matcher.js +186 -0
  51. package/src/adapters/shared/hmr-entrypoint-registrar.d.ts +55 -0
  52. package/src/adapters/shared/hmr-entrypoint-registrar.js +87 -0
  53. package/src/adapters/shared/hmr-html-response.d.ts +22 -0
  54. package/src/adapters/shared/hmr-html-response.js +32 -0
  55. package/src/adapters/shared/render-context.d.ts +15 -0
  56. package/src/adapters/shared/render-context.js +72 -0
  57. package/src/adapters/shared/runtime-bootstrap.d.ts +38 -0
  58. package/src/adapters/shared/runtime-bootstrap.js +43 -0
  59. package/src/adapters/shared/server-adapter.d.ts +108 -0
  60. package/src/adapters/shared/server-adapter.js +429 -0
  61. package/src/adapters/shared/server-route-handler.d.ts +89 -0
  62. package/src/adapters/shared/server-route-handler.js +111 -0
  63. package/src/adapters/shared/server-static-builder.d.ts +71 -0
  64. package/src/adapters/shared/server-static-builder.js +100 -0
  65. package/src/build/build-adapter.d.ts +239 -0
  66. package/src/build/build-adapter.js +642 -0
  67. package/src/build/build-manifest.d.ts +27 -0
  68. package/src/build/build-manifest.js +30 -0
  69. package/src/build/build-types.d.ts +57 -0
  70. package/src/build/build-types.js +0 -0
  71. package/src/build/dev-build-coordinator.d.ts +72 -0
  72. package/src/build/dev-build-coordinator.js +154 -0
  73. package/src/build/esbuild-build-adapter.d.ts +78 -0
  74. package/src/build/esbuild-build-adapter.js +505 -0
  75. package/src/build/runtime-build-executor.d.ts +14 -0
  76. package/src/build/runtime-build-executor.js +22 -0
  77. package/src/build/runtime-specifier-alias-plugin.d.ts +15 -0
  78. package/src/build/runtime-specifier-alias-plugin.js +35 -0
  79. package/src/build/runtime-specifier-aliases.d.ts +5 -0
  80. package/src/build/runtime-specifier-aliases.js +95 -0
  81. package/src/config/config-builder.d.ts +252 -0
  82. package/src/config/config-builder.js +598 -0
  83. package/src/config/{constants.ts → constants.d.ts} +13 -22
  84. package/src/config/constants.js +25 -0
  85. package/src/dev/host-runtime.d.ts +10 -0
  86. package/src/dev/host-runtime.js +24 -0
  87. package/src/dev/sc-server.d.ts +30 -0
  88. package/src/dev/sc-server.js +111 -0
  89. package/src/eco/eco.browser.d.ts +2 -0
  90. package/src/eco/eco.browser.js +83 -0
  91. package/src/eco/eco.d.ts +9 -0
  92. package/src/eco/eco.js +85 -0
  93. package/src/eco/eco.types.d.ts +178 -0
  94. package/src/eco/eco.types.js +0 -0
  95. package/src/eco/eco.utils.d.ts +1 -0
  96. package/src/eco/eco.utils.js +10 -0
  97. package/src/eco/global-injector-map.d.ts +16 -0
  98. package/src/eco/global-injector-map.js +80 -0
  99. package/src/eco/lazy-injector-map.d.ts +8 -0
  100. package/src/eco/lazy-injector-map.js +70 -0
  101. package/src/eco/module-dependencies.d.ts +18 -0
  102. package/src/eco/module-dependencies.js +49 -0
  103. package/src/errors/http-error.d.ts +31 -0
  104. package/src/errors/http-error.js +50 -0
  105. package/src/errors/index.d.ts +3 -0
  106. package/src/errors/index.js +6 -0
  107. package/src/errors/locals-access-error.d.ts +4 -0
  108. package/src/errors/locals-access-error.js +9 -0
  109. package/src/global/app-logger.d.ts +2 -0
  110. package/src/global/app-logger.js +6 -0
  111. package/src/hmr/client/hmr-runtime.d.ts +5 -0
  112. package/src/hmr/client/hmr-runtime.js +117 -0
  113. package/src/hmr/hmr-strategy.d.ts +162 -0
  114. package/src/hmr/hmr-strategy.js +44 -0
  115. package/src/hmr/hmr.postcss.test.e2e.d.ts +1 -0
  116. package/src/hmr/hmr.postcss.test.e2e.js +31 -0
  117. package/src/hmr/hmr.test.e2e.d.ts +1 -0
  118. package/src/hmr/hmr.test.e2e.js +43 -0
  119. package/src/hmr/strategies/default-hmr-strategy.d.ts +43 -0
  120. package/src/hmr/strategies/default-hmr-strategy.js +34 -0
  121. package/src/hmr/strategies/js-hmr-strategy.d.ts +134 -0
  122. package/src/hmr/strategies/js-hmr-strategy.js +178 -0
  123. package/src/index.browser.d.ts +3 -0
  124. package/src/index.browser.js +4 -0
  125. package/src/index.d.ts +6 -0
  126. package/src/index.js +21 -0
  127. package/src/integrations/ghtml/ghtml-renderer.d.ts +16 -0
  128. package/src/integrations/ghtml/ghtml-renderer.js +57 -0
  129. package/src/integrations/ghtml/ghtml.constants.d.ts +1 -0
  130. package/src/integrations/ghtml/ghtml.constants.js +4 -0
  131. package/src/integrations/ghtml/ghtml.plugin.d.ts +16 -0
  132. package/src/integrations/ghtml/ghtml.plugin.js +20 -0
  133. package/src/plugins/alias-resolver-plugin.d.ts +2 -0
  134. package/src/plugins/alias-resolver-plugin.js +53 -0
  135. package/src/plugins/eco-component-meta-plugin.d.ts +108 -0
  136. package/src/plugins/eco-component-meta-plugin.js +162 -0
  137. package/src/plugins/foreign-jsx-override-plugin.d.ts +31 -0
  138. package/src/plugins/foreign-jsx-override-plugin.js +35 -0
  139. package/src/plugins/integration-plugin.d.ts +215 -0
  140. package/src/plugins/integration-plugin.js +189 -0
  141. package/src/plugins/processor.d.ts +97 -0
  142. package/src/plugins/processor.js +141 -0
  143. package/src/plugins/{runtime-capability.ts → runtime-capability.d.ts} +3 -8
  144. package/src/plugins/runtime-capability.js +0 -0
  145. package/src/plugins/source-transform.d.ts +46 -0
  146. package/src/plugins/source-transform.js +71 -0
  147. package/src/route-renderer/orchestration/component-render-context.d.ts +89 -0
  148. package/src/route-renderer/orchestration/component-render-context.js +147 -0
  149. package/src/route-renderer/orchestration/declared-ownership-graph.d.ts +18 -0
  150. package/src/route-renderer/orchestration/declared-ownership-graph.js +34 -0
  151. package/src/route-renderer/orchestration/foreign-subtree-execution.service.d.ts +108 -0
  152. package/src/route-renderer/orchestration/foreign-subtree-execution.service.js +206 -0
  153. package/src/route-renderer/orchestration/integration-renderer.d.ts +516 -0
  154. package/src/route-renderer/orchestration/integration-renderer.js +909 -0
  155. package/src/route-renderer/orchestration/ownership-planning.service.d.ts +24 -0
  156. package/src/route-renderer/orchestration/ownership-planning.service.js +63 -0
  157. package/src/route-renderer/orchestration/ownership-validation.service.d.ts +29 -0
  158. package/src/route-renderer/orchestration/ownership-validation.service.js +53 -0
  159. package/src/route-renderer/orchestration/processed-asset-dedupe.d.ts +2 -0
  160. package/src/route-renderer/orchestration/processed-asset-dedupe.js +23 -0
  161. package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.d.ts +90 -0
  162. package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.js +158 -0
  163. package/src/route-renderer/orchestration/render-output.utils.d.ts +66 -0
  164. package/src/route-renderer/orchestration/render-output.utils.js +171 -0
  165. package/src/route-renderer/orchestration/route-render-orchestrator.d.ts +120 -0
  166. package/src/route-renderer/orchestration/route-render-orchestrator.js +388 -0
  167. package/src/route-renderer/orchestration/template-serialization.d.ts +38 -0
  168. package/src/route-renderer/orchestration/template-serialization.js +45 -0
  169. package/src/route-renderer/page-loading/component-dependency-collection.d.ts +37 -0
  170. package/src/route-renderer/page-loading/component-dependency-collection.js +132 -0
  171. package/src/route-renderer/page-loading/declared-asset-collection.d.ts +24 -0
  172. package/src/route-renderer/page-loading/declared-asset-collection.js +106 -0
  173. package/src/route-renderer/page-loading/dependency-resolver.d.ts +35 -0
  174. package/src/route-renderer/page-loading/dependency-resolver.js +115 -0
  175. package/src/route-renderer/page-loading/ecopages-virtual-imports.d.ts +11 -0
  176. package/src/route-renderer/page-loading/ecopages-virtual-imports.js +57 -0
  177. package/src/route-renderer/page-loading/lazy-entry-collection.d.ts +45 -0
  178. package/src/route-renderer/page-loading/lazy-entry-collection.js +105 -0
  179. package/src/route-renderer/page-loading/lazy-trigger-planning.d.ts +19 -0
  180. package/src/route-renderer/page-loading/lazy-trigger-planning.js +40 -0
  181. package/src/route-renderer/page-loading/module-declaration-aggregation.d.ts +5 -0
  182. package/src/route-renderer/page-loading/module-declaration-aggregation.js +33 -0
  183. package/src/route-renderer/page-loading/module-declaration-scripts.d.ts +3 -0
  184. package/src/route-renderer/page-loading/module-declaration-scripts.js +18 -0
  185. package/src/route-renderer/page-loading/page-dependency-bundling.d.ts +13 -0
  186. package/src/route-renderer/page-loading/page-dependency-bundling.js +137 -0
  187. package/src/route-renderer/page-loading/page-module-loader.d.ts +90 -0
  188. package/src/route-renderer/page-loading/page-module-loader.js +127 -0
  189. package/src/route-renderer/route-renderer.d.ts +69 -0
  190. package/src/route-renderer/route-renderer.js +80 -0
  191. package/src/router/client/link-intent.js +34 -0
  192. package/src/router/client/link-intent.test.browser.d.ts +1 -0
  193. package/src/router/client/link-intent.test.browser.js +43 -0
  194. package/src/router/client/navigation-coordinator.d.ts +169 -0
  195. package/src/router/client/navigation-coordinator.js +215 -0
  196. package/src/router/server/route-registry.d.ts +78 -0
  197. package/src/router/server/route-registry.js +262 -0
  198. package/src/services/assets/asset-processing-service/asset-dependency-keys.d.ts +3 -0
  199. package/src/services/assets/asset-processing-service/asset-dependency-keys.js +56 -0
  200. package/src/services/assets/asset-processing-service/asset-processing.service.d.ts +103 -0
  201. package/src/services/assets/asset-processing-service/asset-processing.service.js +285 -0
  202. package/src/services/assets/asset-processing-service/asset.factory.d.ts +17 -0
  203. package/src/services/assets/asset-processing-service/asset.factory.js +82 -0
  204. package/src/services/assets/asset-processing-service/assets.types.d.ts +103 -0
  205. package/src/services/assets/asset-processing-service/assets.types.js +0 -0
  206. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.d.ts +55 -0
  207. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.js +49 -0
  208. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.d.ts +20 -0
  209. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.js +41 -0
  210. package/src/services/assets/asset-processing-service/grouped-content-bundles.d.ts +30 -0
  211. package/src/services/assets/asset-processing-service/grouped-content-bundles.js +65 -0
  212. package/src/services/assets/asset-processing-service/index.d.ts +6 -0
  213. package/src/services/assets/asset-processing-service/index.js +6 -0
  214. package/src/services/assets/asset-processing-service/page-package.d.ts +3 -0
  215. package/src/services/assets/asset-processing-service/page-package.js +74 -0
  216. package/src/services/assets/asset-processing-service/{processor.interface.ts → processor.interface.d.ts} +5 -10
  217. package/src/services/assets/asset-processing-service/processor.interface.js +6 -0
  218. package/src/services/assets/asset-processing-service/processor.registry.d.ts +8 -0
  219. package/src/services/assets/asset-processing-service/processor.registry.js +15 -0
  220. package/src/services/assets/asset-processing-service/processors/base/base-processor.d.ts +24 -0
  221. package/src/services/assets/asset-processing-service/processors/base/base-processor.js +65 -0
  222. package/src/services/assets/asset-processing-service/processors/base/base-script-processor.d.ts +22 -0
  223. package/src/services/assets/asset-processing-service/processors/base/base-script-processor.js +136 -0
  224. package/src/services/assets/asset-processing-service/processors/index.d.ts +5 -0
  225. package/src/services/assets/asset-processing-service/processors/index.js +5 -0
  226. package/src/services/assets/asset-processing-service/processors/script/content-script.processor.d.ts +6 -0
  227. package/src/services/assets/asset-processing-service/processors/script/content-script.processor.js +119 -0
  228. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.d.ts +9 -0
  229. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.js +97 -0
  230. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.d.ts +7 -0
  231. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.js +79 -0
  232. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.d.ts +8 -0
  233. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +59 -0
  234. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.d.ts +9 -0
  235. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +69 -0
  236. package/src/services/assets/asset-processing-service/ungrouped-dependency-processing.d.ts +18 -0
  237. package/src/services/assets/asset-processing-service/ungrouped-dependency-processing.js +45 -0
  238. package/src/services/assets/browser-bundle.service.d.ts +73 -0
  239. package/src/services/assets/browser-bundle.service.js +41 -0
  240. package/src/services/cache/cache.types.d.ts +107 -0
  241. package/src/services/cache/cache.types.js +0 -0
  242. package/src/services/cache/index.d.ts +7 -0
  243. package/src/services/cache/index.js +7 -0
  244. package/src/services/cache/memory-cache-store.d.ts +42 -0
  245. package/src/services/cache/memory-cache-store.js +98 -0
  246. package/src/services/cache/page-cache-service.d.ts +70 -0
  247. package/src/services/cache/page-cache-service.js +152 -0
  248. package/src/services/cache/page-request-cache-coordinator.service.d.ts +75 -0
  249. package/src/services/cache/page-request-cache-coordinator.service.js +109 -0
  250. package/src/services/html/html-rewriter-provider.service.d.ts +37 -0
  251. package/src/services/html/html-rewriter-provider.service.js +68 -0
  252. package/src/services/html/html-transformer.service.d.ts +87 -0
  253. package/src/services/html/html-transformer.service.js +216 -0
  254. package/src/services/invalidation/development-invalidation.service.d.ts +74 -0
  255. package/src/services/invalidation/development-invalidation.service.js +190 -0
  256. package/src/services/module-loading/app-module-loader.service.d.ts +7 -0
  257. package/src/services/module-loading/app-module-loader.service.js +0 -0
  258. package/src/services/module-loading/app-server-module-transpiler.service.d.ts +24 -0
  259. package/src/services/module-loading/app-server-module-transpiler.service.js +115 -0
  260. package/src/services/module-loading/host-module-loader-registry.d.ts +4 -0
  261. package/src/services/module-loading/host-module-loader-registry.js +15 -0
  262. package/src/services/module-loading/{module-loading-types.ts → module-loading-types.d.ts} +0 -1
  263. package/src/services/module-loading/module-loading-types.js +0 -0
  264. package/src/services/module-loading/node-bootstrap-plugin.d.ts +42 -0
  265. package/src/services/module-loading/node-bootstrap-plugin.js +216 -0
  266. package/src/services/module-loading/page-module-import.service.d.ts +76 -0
  267. package/src/services/module-loading/page-module-import.service.js +170 -0
  268. package/src/services/module-loading/server-module-transpiler.service.d.ts +63 -0
  269. package/src/services/module-loading/server-module-transpiler.service.js +64 -0
  270. package/src/services/module-loading/source-module-support.d.ts +5 -0
  271. package/src/services/module-loading/source-module-support.js +8 -0
  272. package/src/services/runtime-state/dev-graph.service.d.ts +118 -0
  273. package/src/services/runtime-state/dev-graph.service.js +162 -0
  274. package/src/services/runtime-state/entrypoint-dependency-graph.service.d.ts +41 -0
  275. package/src/services/runtime-state/entrypoint-dependency-graph.service.js +85 -0
  276. package/src/services/runtime-state/server-invalidation-state.service.d.ts +26 -0
  277. package/src/services/runtime-state/server-invalidation-state.service.js +35 -0
  278. package/src/services/validation/schema-validation-service.d.ts +122 -0
  279. package/src/services/validation/schema-validation-service.js +101 -0
  280. package/src/services/validation/{standard-schema.types.ts → standard-schema.types.d.ts} +17 -20
  281. package/src/services/validation/standard-schema.types.js +0 -0
  282. package/src/static-site-generator/static-site-generator.d.ts +104 -0
  283. package/src/static-site-generator/static-site-generator.js +316 -0
  284. package/src/types/internal-types.d.ts +232 -0
  285. package/src/types/internal-types.js +0 -0
  286. package/src/types/public-types.d.ts +1267 -0
  287. package/src/types/public-types.js +0 -0
  288. package/src/utils/deep-merge.d.ts +14 -0
  289. package/src/utils/deep-merge.js +32 -0
  290. package/src/utils/hash.d.ts +1 -0
  291. package/src/utils/hash.js +7 -0
  292. package/src/utils/html-escaping.d.ts +7 -0
  293. package/src/utils/html-escaping.js +6 -0
  294. package/src/utils/html.js +4 -0
  295. package/src/utils/invariant.d.ts +5 -0
  296. package/src/utils/invariant.js +11 -0
  297. package/src/utils/locals-utils.d.ts +15 -0
  298. package/src/utils/locals-utils.js +24 -0
  299. package/src/utils/parse-cli-args.d.ts +27 -0
  300. package/src/utils/parse-cli-args.js +62 -0
  301. package/src/utils/path-utils.module.d.ts +5 -0
  302. package/src/utils/path-utils.module.js +14 -0
  303. package/src/utils/resolve-work-dir.d.ts +11 -0
  304. package/src/utils/resolve-work-dir.js +31 -0
  305. package/src/utils/runtime.d.ts +11 -0
  306. package/src/utils/runtime.js +40 -0
  307. package/src/utils/server-utils.module.d.ts +19 -0
  308. package/src/utils/server-utils.module.js +56 -0
  309. package/src/watchers/project-watcher.d.ts +136 -0
  310. package/src/watchers/project-watcher.js +275 -0
  311. package/src/watchers/project-watcher.test-helpers.d.ts +4 -0
  312. package/src/watchers/project-watcher.test-helpers.js +52 -0
  313. package/src/adapters/abstract/application-adapter.test.ts +0 -172
  314. package/src/adapters/abstract/application-adapter.ts +0 -379
  315. package/src/adapters/abstract/router-adapter.ts +0 -30
  316. package/src/adapters/abstract/server-adapter.ts +0 -79
  317. package/src/adapters/bun/client-bridge.ts +0 -62
  318. package/src/adapters/bun/create-app.ts +0 -232
  319. package/src/adapters/bun/hmr-manager.test.ts +0 -265
  320. package/src/adapters/bun/hmr-manager.ts +0 -383
  321. package/src/adapters/bun/index.ts +0 -2
  322. package/src/adapters/bun/server-adapter.ts +0 -526
  323. package/src/adapters/bun/server-lifecycle.ts +0 -124
  324. package/src/adapters/create-app.test.ts +0 -10
  325. package/src/adapters/create-app.ts +0 -91
  326. package/src/adapters/index.ts +0 -2
  327. package/src/adapters/node/create-app.test.ts +0 -53
  328. package/src/adapters/node/create-app.ts +0 -183
  329. package/src/adapters/node/node-client-bridge.test.ts +0 -198
  330. package/src/adapters/node/node-client-bridge.ts +0 -79
  331. package/src/adapters/node/node-hmr-manager.test.ts +0 -320
  332. package/src/adapters/node/node-hmr-manager.ts +0 -355
  333. package/src/adapters/node/server-adapter.ts +0 -502
  334. package/src/adapters/node/static-content-server.test.ts +0 -60
  335. package/src/adapters/node/static-content-server.ts +0 -239
  336. package/src/adapters/shared/api-response.test.ts +0 -97
  337. package/src/adapters/shared/api-response.ts +0 -104
  338. package/src/adapters/shared/application-adapter.ts +0 -199
  339. package/src/adapters/shared/define-api-handler.ts +0 -66
  340. package/src/adapters/shared/explicit-static-render-preparation.ts +0 -58
  341. package/src/adapters/shared/explicit-static-route-matcher.test.ts +0 -381
  342. package/src/adapters/shared/explicit-static-route-matcher.ts +0 -131
  343. package/src/adapters/shared/file-route-middleware-pipeline.test.ts +0 -85
  344. package/src/adapters/shared/file-route-middleware-pipeline.ts +0 -118
  345. package/src/adapters/shared/fs-server-response-factory.test.ts +0 -176
  346. package/src/adapters/shared/fs-server-response-factory.ts +0 -96
  347. package/src/adapters/shared/fs-server-response-matcher.test.ts +0 -311
  348. package/src/adapters/shared/fs-server-response-matcher.ts +0 -240
  349. package/src/adapters/shared/hmr-entrypoint-registrar.ts +0 -149
  350. package/src/adapters/shared/hmr-html-response.ts +0 -52
  351. package/src/adapters/shared/hmr-manager.contract.test.ts +0 -228
  352. package/src/adapters/shared/hmr-manager.dispatch.test.ts +0 -220
  353. package/src/adapters/shared/render-context.test.ts +0 -150
  354. package/src/adapters/shared/render-context.ts +0 -123
  355. package/src/adapters/shared/runtime-bootstrap.ts +0 -79
  356. package/src/adapters/shared/server-adapter.test.ts +0 -130
  357. package/src/adapters/shared/server-adapter.ts +0 -562
  358. package/src/adapters/shared/server-route-handler.test.ts +0 -111
  359. package/src/adapters/shared/server-route-handler.ts +0 -153
  360. package/src/adapters/shared/server-static-builder.test.ts +0 -338
  361. package/src/adapters/shared/server-static-builder.ts +0 -170
  362. package/src/build/build-adapter-serialization.test.ts +0 -281
  363. package/src/build/build-adapter.test.ts +0 -1240
  364. package/src/build/build-adapter.ts +0 -1012
  365. package/src/build/build-manifest.ts +0 -54
  366. package/src/build/build-types.ts +0 -83
  367. package/src/build/dev-build-coordinator.ts +0 -220
  368. package/src/build/esbuild-build-adapter.ts +0 -660
  369. package/src/build/runtime-build-executor.test.ts +0 -81
  370. package/src/build/runtime-build-executor.ts +0 -40
  371. package/src/build/runtime-specifier-alias-plugin.test.ts +0 -67
  372. package/src/build/runtime-specifier-alias-plugin.ts +0 -62
  373. package/src/build/runtime-specifier-aliases.ts +0 -135
  374. package/src/config/config-builder.test.ts +0 -442
  375. package/src/config/config-builder.ts +0 -737
  376. package/src/config/config-builder.typecheck.test.ts +0 -96
  377. package/src/dev/host-runtime.ts +0 -34
  378. package/src/dev/sc-server.ts +0 -143
  379. package/src/eco/eco.browser.test.ts +0 -43
  380. package/src/eco/eco.browser.ts +0 -118
  381. package/src/eco/eco.test.ts +0 -654
  382. package/src/eco/eco.ts +0 -205
  383. package/src/eco/eco.types.ts +0 -221
  384. package/src/eco/eco.utils.test.ts +0 -219
  385. package/src/eco/eco.utils.ts +0 -5
  386. package/src/eco/global-injector-map.test.ts +0 -42
  387. package/src/eco/global-injector-map.ts +0 -112
  388. package/src/eco/lazy-injector-map.test.ts +0 -66
  389. package/src/eco/lazy-injector-map.ts +0 -120
  390. package/src/eco/module-dependencies.test.ts +0 -30
  391. package/src/eco/module-dependencies.ts +0 -75
  392. package/src/errors/http-error.test.ts +0 -134
  393. package/src/errors/http-error.ts +0 -72
  394. package/src/errors/index.ts +0 -3
  395. package/src/errors/locals-access-error.ts +0 -7
  396. package/src/global/app-logger.ts +0 -4
  397. package/src/global/utils.test.ts +0 -12
  398. 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
  399. package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-HMR-Server-Integration-should-load-fixture-app-page-1.png +0 -0
  400. package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-WebSocket-Connection-should-connect-to-correct-HMR-endpoint-1.png +0 -0
  401. package/src/hmr/client/hmr-runtime.ts +0 -162
  402. package/src/hmr/hmr-strategy.test.ts +0 -124
  403. package/src/hmr/hmr-strategy.ts +0 -177
  404. package/src/hmr/hmr.postcss.test.e2e.ts +0 -41
  405. package/src/hmr/hmr.test.e2e.ts +0 -66
  406. package/src/hmr/strategies/default-hmr-strategy.ts +0 -60
  407. package/src/hmr/strategies/js-hmr-strategy.test.ts +0 -334
  408. package/src/hmr/strategies/js-hmr-strategy.ts +0 -314
  409. package/src/index.browser.ts +0 -3
  410. package/src/index.ts +0 -15
  411. package/src/integrations/ghtml/ghtml-renderer.test.ts +0 -253
  412. package/src/integrations/ghtml/ghtml-renderer.ts +0 -87
  413. package/src/integrations/ghtml/ghtml.constants.ts +0 -1
  414. package/src/integrations/ghtml/ghtml.plugin.ts +0 -28
  415. package/src/plugins/alias-resolver-plugin.test.ts +0 -41
  416. package/src/plugins/alias-resolver-plugin.ts +0 -63
  417. package/src/plugins/eco-component-meta-plugin.test.ts +0 -406
  418. package/src/plugins/eco-component-meta-plugin.ts +0 -494
  419. package/src/plugins/foreign-jsx-override-plugin.test.ts +0 -65
  420. package/src/plugins/foreign-jsx-override-plugin.ts +0 -67
  421. package/src/plugins/integration-plugin.test.ts +0 -151
  422. package/src/plugins/integration-plugin.ts +0 -323
  423. package/src/plugins/processor.test.ts +0 -148
  424. package/src/plugins/processor.ts +0 -257
  425. package/src/plugins/source-transform.test.ts +0 -82
  426. package/src/plugins/source-transform.ts +0 -123
  427. package/src/route-renderer/orchestration/component-render-context.ts +0 -325
  428. package/src/route-renderer/orchestration/declared-ownership-graph.ts +0 -62
  429. package/src/route-renderer/orchestration/foreign-subtree-execution.service.ts +0 -383
  430. package/src/route-renderer/orchestration/integration-renderer.test.ts +0 -2085
  431. package/src/route-renderer/orchestration/integration-renderer.ts +0 -1244
  432. package/src/route-renderer/orchestration/ownership-planning.service.ts +0 -97
  433. package/src/route-renderer/orchestration/ownership-validation.service.ts +0 -76
  434. package/src/route-renderer/orchestration/processed-asset-dedupe.ts +0 -25
  435. package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.test.ts +0 -324
  436. package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.ts +0 -294
  437. package/src/route-renderer/orchestration/render-output.utils.ts +0 -310
  438. package/src/route-renderer/orchestration/route-render-orchestrator.prepare-render-options.test.ts +0 -644
  439. package/src/route-renderer/orchestration/route-render-orchestrator.test.ts +0 -265
  440. package/src/route-renderer/orchestration/route-render-orchestrator.ts +0 -592
  441. package/src/route-renderer/orchestration/template-serialization.test.ts +0 -110
  442. package/src/route-renderer/orchestration/template-serialization.ts +0 -117
  443. package/src/route-renderer/page-loading/component-dependency-collection.ts +0 -202
  444. package/src/route-renderer/page-loading/declared-asset-collection.ts +0 -153
  445. package/src/route-renderer/page-loading/dependency-resolver.test.ts +0 -761
  446. package/src/route-renderer/page-loading/dependency-resolver.ts +0 -144
  447. package/src/route-renderer/page-loading/ecopages-virtual-imports.ts +0 -75
  448. package/src/route-renderer/page-loading/lazy-entry-collection.ts +0 -167
  449. package/src/route-renderer/page-loading/lazy-trigger-planning.ts +0 -74
  450. package/src/route-renderer/page-loading/module-declaration-aggregation.ts +0 -60
  451. package/src/route-renderer/page-loading/module-declaration-scripts.ts +0 -16
  452. package/src/route-renderer/page-loading/page-dependency-bundling.ts +0 -244
  453. package/src/route-renderer/page-loading/page-module-loader.test.ts +0 -183
  454. package/src/route-renderer/page-loading/page-module-loader.ts +0 -184
  455. package/src/route-renderer/route-renderer.ts +0 -133
  456. package/src/router/client/link-intent.test.browser.ts +0 -51
  457. package/src/router/client/link-intent.ts +0 -92
  458. package/src/router/client/navigation-coordinator.test.ts +0 -237
  459. package/src/router/client/navigation-coordinator.ts +0 -453
  460. package/src/router/server/route-registry.test.ts +0 -176
  461. package/src/router/server/route-registry.ts +0 -382
  462. package/src/services/assets/asset-processing-service/asset-dependency-keys.ts +0 -66
  463. package/src/services/assets/asset-processing-service/asset-processing.service.test.ts +0 -473
  464. package/src/services/assets/asset-processing-service/asset-processing.service.ts +0 -344
  465. package/src/services/assets/asset-processing-service/asset.factory.test.ts +0 -63
  466. package/src/services/assets/asset-processing-service/asset.factory.ts +0 -105
  467. package/src/services/assets/asset-processing-service/assets.types.ts +0 -128
  468. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.test.ts +0 -74
  469. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.ts +0 -96
  470. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.test.ts +0 -67
  471. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.ts +0 -78
  472. package/src/services/assets/asset-processing-service/grouped-content-bundles.ts +0 -104
  473. package/src/services/assets/asset-processing-service/index.ts +0 -6
  474. package/src/services/assets/asset-processing-service/page-package.test.ts +0 -100
  475. package/src/services/assets/asset-processing-service/page-package.ts +0 -93
  476. package/src/services/assets/asset-processing-service/processor.registry.ts +0 -18
  477. package/src/services/assets/asset-processing-service/processors/base/base-processor.test.ts +0 -59
  478. package/src/services/assets/asset-processing-service/processors/base/base-processor.ts +0 -83
  479. package/src/services/assets/asset-processing-service/processors/base/base-script-processor.ts +0 -173
  480. package/src/services/assets/asset-processing-service/processors/index.ts +0 -5
  481. package/src/services/assets/asset-processing-service/processors/script/content-script.processor.test.ts +0 -195
  482. package/src/services/assets/asset-processing-service/processors/script/content-script.processor.ts +0 -137
  483. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.test.ts +0 -326
  484. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.ts +0 -116
  485. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.test.ts +0 -227
  486. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.ts +0 -89
  487. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.test.ts +0 -261
  488. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.ts +0 -72
  489. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.ts +0 -83
  490. package/src/services/assets/asset-processing-service/ungrouped-dependency-processing.ts +0 -65
  491. package/src/services/assets/browser-bundle.service.test.ts +0 -66
  492. package/src/services/assets/browser-bundle.service.ts +0 -109
  493. package/src/services/cache/cache.types.ts +0 -126
  494. package/src/services/cache/index.ts +0 -18
  495. package/src/services/cache/memory-cache-store.test.ts +0 -225
  496. package/src/services/cache/memory-cache-store.ts +0 -130
  497. package/src/services/cache/page-cache-service.test.ts +0 -175
  498. package/src/services/cache/page-cache-service.ts +0 -202
  499. package/src/services/cache/page-request-cache-coordinator.service.test.ts +0 -79
  500. package/src/services/cache/page-request-cache-coordinator.service.ts +0 -131
  501. package/src/services/html/html-rewriter-provider.service.test.ts +0 -183
  502. package/src/services/html/html-rewriter-provider.service.ts +0 -104
  503. package/src/services/html/html-transformer.service.test.ts +0 -476
  504. package/src/services/html/html-transformer.service.ts +0 -275
  505. package/src/services/invalidation/development-invalidation.service.test.ts +0 -87
  506. package/src/services/invalidation/development-invalidation.service.ts +0 -262
  507. package/src/services/module-loading/app-module-loader.service.ts +0 -9
  508. package/src/services/module-loading/app-server-module-transpiler.service.test.ts +0 -130
  509. package/src/services/module-loading/app-server-module-transpiler.service.ts +0 -141
  510. package/src/services/module-loading/host-module-loader-registry.ts +0 -15
  511. package/src/services/module-loading/node-bootstrap-plugin.test.ts +0 -335
  512. package/src/services/module-loading/node-bootstrap-plugin.ts +0 -311
  513. package/src/services/module-loading/page-module-import.service.test.ts +0 -504
  514. package/src/services/module-loading/page-module-import.service.ts +0 -251
  515. package/src/services/module-loading/server-module-transpiler.service.test.ts +0 -243
  516. package/src/services/module-loading/server-module-transpiler.service.ts +0 -104
  517. package/src/services/module-loading/source-module-support.ts +0 -19
  518. package/src/services/runtime-state/dev-graph.service.ts +0 -217
  519. package/src/services/runtime-state/entrypoint-dependency-graph.service.ts +0 -136
  520. package/src/services/runtime-state/server-invalidation-state.service.ts +0 -68
  521. package/src/services/validation/schema-validation-service.test.ts +0 -223
  522. package/src/services/validation/schema-validation-service.ts +0 -204
  523. package/src/static-site-generator/static-site-generator.test.ts +0 -408
  524. package/src/static-site-generator/static-site-generator.ts +0 -445
  525. package/src/types/internal-types.ts +0 -243
  526. package/src/types/public-types.ts +0 -1459
  527. package/src/utils/deep-merge.test.ts +0 -114
  528. package/src/utils/deep-merge.ts +0 -47
  529. package/src/utils/hash.ts +0 -5
  530. package/src/utils/html-escaping.ts +0 -9
  531. package/src/utils/invariant.test.ts +0 -22
  532. package/src/utils/invariant.ts +0 -15
  533. package/src/utils/locals-utils.ts +0 -37
  534. package/src/utils/parse-cli-args.test.ts +0 -69
  535. package/src/utils/parse-cli-args.ts +0 -105
  536. package/src/utils/path-utils.module.ts +0 -14
  537. package/src/utils/path-utils.test.ts +0 -15
  538. package/src/utils/resolve-work-dir.ts +0 -45
  539. package/src/utils/runtime.ts +0 -44
  540. package/src/utils/server-utils.module.ts +0 -67
  541. package/src/utils/server-utils.test.ts +0 -38
  542. package/src/watchers/project-watcher.integration.test.ts +0 -337
  543. package/src/watchers/project-watcher.test-helpers.ts +0 -42
  544. package/src/watchers/project-watcher.test.ts +0 -768
  545. package/src/watchers/project-watcher.ts +0 -357
  546. /package/src/utils/{html.ts → html.d.ts} +0 -0
@@ -1,1244 +0,0 @@
1
- /**
2
- * This module contains the abstract class for the Integration Renderer
3
- * Every integration renderer should extend this class
4
- * @module
5
- */
6
-
7
- import type { EcoPagesAppConfig, IHmrManager } from '../../types/internal-types.ts';
8
- import type {
9
- ComponentRenderInput,
10
- ComponentRenderResult,
11
- ForeignSubtreeRenderPayload,
12
- EcoComponent,
13
- EcoComponentDependencies,
14
- EcoFunctionComponent,
15
- EcoPageFile,
16
- EcoPagesElement,
17
- BaseIntegrationContext,
18
- HtmlTemplateProps,
19
- IntegrationRendererRenderOptions,
20
- PageMetadataProps,
21
- RouteRendererBody,
22
- RouteRendererOptions,
23
- RouteRenderResult,
24
- } from '../../types/public-types.ts';
25
- import {
26
- type AssetProcessingService,
27
- createPagePackage,
28
- type ProcessedAsset,
29
- } from '../../services/assets/asset-processing-service/index.ts';
30
- import { HtmlTransformerService } from '../../services/html/html-transformer.service.ts';
31
- import { invariant } from '../../utils/invariant.ts';
32
- import { HttpError } from '../../errors/http-error.ts';
33
- import { DependencyResolverService } from '../page-loading/dependency-resolver.ts';
34
- import { PageModuleLoaderService } from '../page-loading/page-module-loader.ts';
35
- import { OwnershipValidationService } from './ownership-validation.service.ts';
36
- import {
37
- type RouteHtmlFinalization,
38
- RouteRenderOrchestrator,
39
- type RouteRenderOrchestratorAdapter,
40
- type RouteRenderOrchestratorResolvedInputs,
41
- } from './route-render-orchestrator.ts';
42
- import type { ForeignChildRuntime } from './component-render-context.ts';
43
- import { normalizeUnresolvedMarkerArtifactHtml } from './render-output.utils.ts';
44
- import {
45
- ForeignSubtreeExecutionService,
46
- type ForeignSubtreeExecutionOwningRenderer,
47
- } from './foreign-subtree-execution.service.ts';
48
- import { type QueuedForeignSubtreeResolutionContext } from './queued-foreign-subtree-resolution.service.ts';
49
-
50
- /**
51
- * Controls how one route module is loaded outside the normal render path.
52
- *
53
- * Request-time metadata inspection and static-generation probes use these
54
- * options to isolate their module identity from the main render cache while
55
- * still going through the owning integration's import setup.
56
- */
57
- export type RouteModuleLoadOptions = {
58
- bypassCache?: boolean;
59
- cacheScope?: string;
60
- };
61
-
62
- /**
63
- * Context for renderToResponse method.
64
- */
65
- export interface RenderToResponseContext {
66
- partial?: boolean;
67
- status?: number;
68
- headers?: HeadersInit;
69
- }
70
-
71
- /**
72
- * The IntegrationRenderer class is an abstract class that provides a base for rendering integration-specific components in the EcoPages framework.
73
- * It handles the import of page files, collection of dependencies, and preparation of render options.
74
- * The class is designed to be extended by specific integration renderers.
75
- */
76
- export abstract class IntegrationRenderer<C = EcoPagesElement> {
77
- abstract name: string;
78
- protected appConfig: EcoPagesAppConfig;
79
- protected assetProcessingService: AssetProcessingService;
80
- protected htmlTransformer: HtmlTransformerService;
81
- protected hmrManager?: IHmrManager;
82
- protected resolvedIntegrationDependencies: ProcessedAsset[] = [];
83
- protected rendererModules?: unknown;
84
- declare protected options: Required<IntegrationRendererRenderOptions>;
85
- protected runtimeOrigin: string;
86
- protected dependencyResolverService: DependencyResolverService;
87
- protected pageModuleLoaderService: PageModuleLoaderService;
88
- protected routeRenderOrchestrator: RouteRenderOrchestrator;
89
- protected readonly foreignSubtreeExecutionService = new ForeignSubtreeExecutionService();
90
-
91
- protected DOC_TYPE = '<!DOCTYPE html>';
92
-
93
- /**
94
- * Loads one route module through the owning renderer's import path.
95
- *
96
- * Request-time infrastructure may need page metadata such as cache strategy or
97
- * middleware before full rendering starts. Exposing this narrow entrypoint lets
98
- * those callers reuse integration-specific import setup instead of bypassing it
99
- * with raw transpiler access.
100
- */
101
- public async loadPageModule(file: string, options?: RouteModuleLoadOptions): Promise<EcoPageFile> {
102
- return this.importPageFile(file, options);
103
- }
104
-
105
- /**
106
- * Reads the execution-scoped owning-renderer cache from one render input.
107
- *
108
- * Shared page/layout/document shell helpers pass one cache through
109
- * `integrationContext` so repeated delegation to the same foreign integration
110
- * can reuse a single initialized renderer instance during one render flow.
111
- * The cache is deliberately scoped to the current render execution rather than
112
- * stored on the renderer, which avoids leaking mutable integration state across
113
- * requests while still preventing redundant renderer initialization.
114
- *
115
- * @param integrationContext - Optional render context carried with one render input.
116
- * @returns The current execution cache when present.
117
- */
118
- private getOwningRendererCache(
119
- integrationContext?: BaseIntegrationContext,
120
- ): Map<string, IntegrationRenderer<any>> | undefined {
121
- if (integrationContext?.rendererCache instanceof Map) {
122
- return integrationContext.rendererCache as Map<string, IntegrationRenderer<any>>;
123
- }
124
-
125
- return undefined;
126
- }
127
-
128
- private getForeignOwnerIntegrationName(component: EcoComponent): string | undefined {
129
- const integrationName = component.config?.integration ?? component.config?.__eco?.integration;
130
- if (!integrationName || integrationName === this.name) {
131
- return undefined;
132
- }
133
-
134
- return this.appConfig.integrations.some((integration) => integration.name === integrationName)
135
- ? integrationName
136
- : undefined;
137
- }
138
-
139
- /**
140
- * Attaches an execution-scoped owning-renderer cache to one render input.
141
- *
142
- * Foreign-owned page, layout, or document shells may delegate several times in
143
- * the same render flow. Threading the cache through `integrationContext`
144
- * preserves renderer reuse without changing the public render input contract.
145
- * Existing integration-specific context is preserved and augmented.
146
- *
147
- * @param input - Original render input.
148
- * @param rendererCache - Execution-scoped renderer cache to propagate.
149
- * @returns Render input augmented with the shared renderer cache.
150
- */
151
- private withOwningRendererCache(
152
- input: ComponentRenderInput,
153
- rendererCache: Map<string, IntegrationRenderer<any>>,
154
- ): ComponentRenderInput {
155
- const integrationContext = input.integrationContext;
156
- const sharedRendererCache = rendererCache as BaseIntegrationContext['rendererCache'];
157
-
158
- return {
159
- ...input,
160
- integrationContext: integrationContext
161
- ? { ...integrationContext, rendererCache: sharedRendererCache }
162
- : { rendererCache: sharedRendererCache },
163
- };
164
- }
165
-
166
- protected getRendererModuleValue(key: string): unknown {
167
- if (!this.rendererModules || typeof this.rendererModules !== 'object') {
168
- return undefined;
169
- }
170
-
171
- return (this.rendererModules as Record<string, unknown>)[key];
172
- }
173
-
174
- protected getRendererModuleString(key: string): string | undefined {
175
- const value = this.getRendererModuleValue(key);
176
- return typeof value === 'string' && value.length > 0 ? value : undefined;
177
- }
178
-
179
- protected getRendererBootstrapDependencies(partial = false): ProcessedAsset[] {
180
- if (partial) {
181
- return [];
182
- }
183
-
184
- const islandClientModuleId = this.getRendererModuleString('islandClientModuleId');
185
- if (!islandClientModuleId) {
186
- return [];
187
- }
188
-
189
- return [
190
- {
191
- attributes: {
192
- crossorigin: 'anonymous',
193
- 'data-ecopages-runtime': 'islands',
194
- type: 'module',
195
- },
196
- content: `import ${JSON.stringify(islandClientModuleId)};`,
197
- inline: true,
198
- kind: 'script',
199
- packageRole: 'keep-separate',
200
- position: 'body',
201
- },
202
- ];
203
- }
204
-
205
- public setHmrManager(hmrManager: IHmrManager) {
206
- this.hmrManager = hmrManager;
207
- if (this.assetProcessingService) {
208
- this.assetProcessingService.setHmrManager(hmrManager);
209
- }
210
- }
211
-
212
- /**
213
- * Build response headers with optional custom headers.
214
- * @param contentType - The Content-Type header value
215
- * @param customHeaders - Optional custom headers to merge
216
- * @returns Headers object
217
- */
218
- protected buildHeaders(contentType: string, customHeaders?: HeadersInit): Headers {
219
- const headers = new Headers({ 'Content-Type': contentType });
220
- if (customHeaders) {
221
- const incoming = new Headers(customHeaders);
222
- incoming.forEach((value, key) => headers.set(key, value));
223
- }
224
- return headers;
225
- }
226
-
227
- /**
228
- * Create an HTML Response.
229
- * @param body - Response body (string or ReadableStream)
230
- * @param ctx - Render context with status and headers
231
- * @returns Response object
232
- */
233
- protected createHtmlResponse(body: BodyInit, ctx: RenderToResponseContext): Response {
234
- return new Response(body, {
235
- status: ctx.status ?? 200,
236
- headers: this.buildHeaders('text/html; charset=utf-8', ctx.headers),
237
- });
238
- }
239
-
240
- /**
241
- * Create an HttpError for render failures.
242
- * @param message - Error message
243
- * @param cause - Original error if available
244
- * @returns HttpError with 500 status
245
- */
246
- protected createRenderError(message: string, cause?: unknown): HttpError {
247
- const errorMessage = cause instanceof Error ? `${message}: ${cause.message}` : message;
248
- return HttpError.InternalServerError(errorMessage);
249
- }
250
-
251
- /**
252
- * Prepares dependencies for renderToResponse by resolving component dependencies
253
- * and configuring the HTML transformer.
254
- * @param view - The view component being rendered
255
- * @param layout - Optional layout component
256
- * @returns Resolved processed assets
257
- */
258
- protected async prepareViewDependencies(view: EcoComponent, layout?: EcoComponent): Promise<ProcessedAsset[]> {
259
- const HtmlTemplate = await this.getHtmlTemplate();
260
- const componentsToResolve = layout ? [HtmlTemplate, layout, view] : [HtmlTemplate, view];
261
- const resolvedDependencies = this.htmlTransformer.dedupeProcessedAssets(
262
- await this.resolveDependencies(componentsToResolve),
263
- );
264
- this.htmlTransformer.setPagePackage(createPagePackage(resolvedDependencies));
265
- return resolvedDependencies;
266
- }
267
-
268
- /**
269
- * Merges component-scoped assets into the active HTML transformer state.
270
- *
271
- * Explicit page, layout, and document shell composition can produce assets at
272
- * each foreign subtree. This helper deduplicates those groups and folds them back into
273
- * the transformer so downstream HTML finalization sees one canonical asset set.
274
- *
275
- * @param assetGroups - Optional groups of processed assets to merge.
276
- * @returns The deduplicated asset subset contributed by this merge operation.
277
- */
278
- protected appendProcessedDependencies(
279
- ...assetGroups: Array<readonly ProcessedAsset[] | undefined>
280
- ): ProcessedAsset[] {
281
- const nextDependencies = this.htmlTransformer.dedupeProcessedAssets(
282
- assetGroups.flatMap((assets) => assets ?? []),
283
- );
284
-
285
- if (nextDependencies.length === 0) {
286
- return nextDependencies;
287
- }
288
-
289
- const mergedDependencies = this.htmlTransformer.dedupeProcessedAssets([
290
- ...this.htmlTransformer.getProcessedDependencies(),
291
- ...nextDependencies,
292
- ]);
293
-
294
- this.htmlTransformer.setPagePackage(createPagePackage(mergedDependencies));
295
-
296
- return nextDependencies;
297
- }
298
-
299
- /**
300
- * Resolves metadata for explicit view rendering.
301
- *
302
- * When a view declares a `metadata()` function, that contract owns the final
303
- * metadata for the explicit render. Otherwise the app-level default metadata is
304
- * reused so explicit routes and page-module routes share the same fallback.
305
- *
306
- * @param view - View component being rendered.
307
- * @param props - Props passed to the view.
308
- * @returns Resolved metadata for the final document shell.
309
- */
310
- protected async resolveViewMetadata<P>(view: EcoComponent<P>, props: P): Promise<PageMetadataProps> {
311
- return view.metadata
312
- ? await view.metadata({
313
- params: {},
314
- query: {},
315
- props,
316
- appConfig: this.appConfig,
317
- })
318
- : this.appConfig.defaultMetadata;
319
- }
320
-
321
- /**
322
- * Renders one explicit view response in partial mode.
323
- *
324
- * Same-integration views can optionally stream or render inline via the caller's
325
- * `renderInline()` hook. Once a view may cross integration boundaries, this
326
- * helper routes the render through `renderComponentWithForeignChildren()` instead so mixed
327
- * shells can reuse the execution-scoped renderer cache and resolve nested
328
- * foreign ownership before the partial response is returned.
329
- *
330
- * @param input - View render options for the partial response.
331
- * @returns HTML response for the partial render.
332
- */
333
- protected async renderPartialViewResponse<P>(input: {
334
- view: EcoComponent<P>;
335
- props: P;
336
- ctx: RenderToResponseContext;
337
- renderInline?: () => Promise<BodyInit>;
338
- transformHtml?: (html: string) => string;
339
- }): Promise<Response> {
340
- if (input.renderInline && !this.hasForeignChildDescendants(input.view as EcoComponent)) {
341
- return this.createHtmlResponse(await input.renderInline(), input.ctx);
342
- }
343
-
344
- const rendererCache = new Map<string, unknown>() as BaseIntegrationContext['rendererCache'];
345
- const viewRender = await this.renderComponentWithForeignChildren({
346
- component: input.view as EcoComponent,
347
- props: (input.props ?? {}) as Record<string, unknown>,
348
- integrationContext: { rendererCache },
349
- });
350
- const html = input.transformHtml ? input.transformHtml(viewRender.html) : viewRender.html;
351
-
352
- return this.createHtmlResponse(html, input.ctx);
353
- }
354
-
355
- /**
356
- * Renders an explicit view through optional layout and document shells.
357
- *
358
- * This helper is the shared explicit-route path for string-oriented and mixed
359
- * integrations. It prepares view dependencies, resolves metadata, and composes
360
- * view, layout, and html template boundaries with one execution-scoped renderer
361
- * cache so repeated foreign shell delegation can reuse initialized renderers
362
- * during the same render flow.
363
- *
364
- * @param input - View, props, and optional layout metadata for the render.
365
- * @returns HTML response for the explicit view render.
366
- */
367
- protected async renderViewWithDocumentShell<P>(input: {
368
- view: EcoComponent<P>;
369
- props: P;
370
- ctx: RenderToResponseContext;
371
- layout?: EcoComponent;
372
- }): Promise<Response> {
373
- const normalizedProps = (input.props ?? {}) as Record<string, unknown>;
374
-
375
- if (input.ctx.partial) {
376
- return this.renderPartialViewResponse(input);
377
- }
378
-
379
- await this.prepareViewDependencies(input.view, input.layout);
380
-
381
- const HtmlTemplate = await this.getHtmlTemplate();
382
- const metadata = await this.resolveViewMetadata(input.view, input.props);
383
- const { documentHtml } = await this.composeDocumentShell({
384
- primaryComponent: input.view as EcoComponent,
385
- primaryProps: normalizedProps,
386
- layout: input.layout
387
- ? {
388
- component: input.layout,
389
- props: {},
390
- }
391
- : undefined,
392
- htmlTemplate: HtmlTemplate as EcoComponent,
393
- documentProps: {
394
- metadata,
395
- pageProps: normalizedProps,
396
- },
397
- });
398
-
399
- const html = await this.finalizeResolvedHtml({
400
- html: `${this.DOC_TYPE}${documentHtml}`,
401
- partial: false,
402
- });
403
-
404
- return this.createHtmlResponse(html, input.ctx);
405
- }
406
-
407
- /**
408
- * Renders a route page through optional layout and document shells.
409
- *
410
- * Route rendering and explicit view rendering now share the same renderer-owned
411
- * shell composition model. This helper composes page, layout, and html template
412
- * renders while threading one execution-scoped renderer cache through every
413
- * delegated foreign subtree so foreign shell ownership remains stable and renderer
414
- * initialization is reused inside the current request.
415
- *
416
- * @param input - Page, layout, document, and metadata inputs for the route render.
417
- * @returns Final serialized document HTML including the doctype prefix.
418
- */
419
- protected async renderPageWithDocumentShell(input: {
420
- page: {
421
- component: EcoComponent;
422
- props: Record<string, unknown>;
423
- };
424
- layout?: {
425
- component: EcoComponent;
426
- props?: Record<string, unknown>;
427
- };
428
- htmlTemplate: EcoComponent;
429
- metadata: PageMetadataProps;
430
- pageProps: Record<string, unknown>;
431
- documentProps?: Record<string, unknown>;
432
- transformDocumentHtml?: (html: string) => string;
433
- }): Promise<string> {
434
- const { documentHtml: composedDocumentHtml } = await this.composeDocumentShell({
435
- primaryComponent: input.page.component,
436
- primaryProps: input.page.props,
437
- layout: input.layout,
438
- htmlTemplate: input.htmlTemplate,
439
- documentProps: {
440
- metadata: input.metadata,
441
- pageProps: input.pageProps,
442
- ...(input.documentProps ?? {}),
443
- },
444
- });
445
-
446
- const documentHtml = input.transformDocumentHtml
447
- ? input.transformDocumentHtml(composedDocumentHtml)
448
- : composedDocumentHtml;
449
-
450
- return `${this.DOC_TYPE}${documentHtml}`;
451
- }
452
-
453
- private async composeDocumentShell(input: {
454
- primaryComponent: EcoComponent;
455
- primaryProps: Record<string, unknown>;
456
- layout?: {
457
- component: EcoComponent;
458
- props?: Record<string, unknown>;
459
- };
460
- htmlTemplate: EcoComponent;
461
- documentProps: Record<string, unknown>;
462
- }): Promise<{ documentHtml: string }> {
463
- const rendererCache = new Map<string, unknown>() as BaseIntegrationContext['rendererCache'];
464
- const primaryRender = await this.renderComponentWithForeignChildren({
465
- component: input.primaryComponent,
466
- props: input.primaryProps,
467
- integrationContext: { rendererCache },
468
- });
469
- const layoutRender = input.layout
470
- ? await this.renderComponentWithForeignChildren({
471
- component: input.layout.component,
472
- props: input.layout.props ?? {},
473
- children: primaryRender.html,
474
- integrationContext: { rendererCache },
475
- })
476
- : undefined;
477
- const documentRender = await this.renderComponentWithForeignChildren({
478
- component: input.htmlTemplate,
479
- props: input.documentProps,
480
- children: layoutRender?.html ?? primaryRender.html,
481
- integrationContext: { rendererCache },
482
- });
483
-
484
- this.appendProcessedDependencies(primaryRender.assets, layoutRender?.assets, documentRender.assets);
485
-
486
- return {
487
- documentHtml: documentRender.html,
488
- };
489
- }
490
-
491
- /**
492
- * Renders one string-first component with serialized children and collects its assets.
493
- *
494
- * String-oriented integrations frequently share the same component contract:
495
- * pass serialized children through props, coerce the render result to HTML, and
496
- * attach any component-scoped dependencies. This helper centralizes that flow
497
- * so integrations can opt into shared orchestration without repeating the same
498
- * string-render boilerplate.
499
- *
500
- * @param input - Component render input.
501
- * @param component - String-oriented component implementation to execute.
502
- * @returns Structured component render result for orchestration paths.
503
- */
504
- protected async renderStringComponentWithSerializedChildren(
505
- input: ComponentRenderInput,
506
- component: (props: Record<string, unknown>) => Promise<EcoPagesElement> | EcoPagesElement,
507
- ): Promise<ComponentRenderResult> {
508
- const props = input.children === undefined ? input.props : { ...input.props, children: input.children };
509
- const content = await component(props);
510
- const html = String(content);
511
- const assets =
512
- input.component.config?.dependencies &&
513
- typeof this.assetProcessingService?.processDependencies === 'function'
514
- ? await this.processComponentDependencies([input.component])
515
- : undefined;
516
-
517
- return {
518
- html,
519
- canAttachAttributes: true,
520
- rootTag: this.getRootTagName(html),
521
- integrationName: this.name,
522
- assets,
523
- };
524
- }
525
-
526
- protected getForeignSubtreeTokenPrefix(): string {
527
- return `__${this.name}_foreign_subtree__`;
528
- }
529
-
530
- protected getForeignSubtreeResolutionContextKey(): string {
531
- return `__${this.name}_foreign_subtree_runtime__`;
532
- }
533
-
534
- protected createQueuedForeignSubtreeExecutionRuntime<
535
- TContext extends QueuedForeignSubtreeResolutionContext,
536
- >(options: {
537
- renderInput: ComponentRenderInput;
538
- rendererCache: Map<string, IntegrationRenderer<any>>;
539
- runtimeContextKey?: string;
540
- tokenPrefix?: string;
541
- createRuntimeContext?: (
542
- integrationContext: BaseIntegrationContext & Record<string, unknown>,
543
- rendererCache: Map<string, unknown>,
544
- ) => TContext;
545
- }): ForeignChildRuntime {
546
- return this.foreignSubtreeExecutionService.createQueuedRuntime<TContext>({
547
- renderInput: options.renderInput,
548
- rendererCache: options.rendererCache,
549
- runtimeContextKey: options.runtimeContextKey ?? this.getForeignSubtreeResolutionContextKey(),
550
- tokenPrefix: options.tokenPrefix ?? this.getForeignSubtreeTokenPrefix(),
551
- createRuntimeContext: options.createRuntimeContext,
552
- });
553
- }
554
-
555
- protected getQueuedForeignSubtreeResolutionContext<TContext extends QueuedForeignSubtreeResolutionContext>(
556
- input: ComponentRenderInput,
557
- ): TContext | undefined {
558
- return this.foreignSubtreeExecutionService.getQueuedRuntimeContext<TContext>(
559
- input,
560
- this.getForeignSubtreeResolutionContextKey(),
561
- );
562
- }
563
-
564
- /**
565
- * Renders a string-first component, then resolves any queued foreign
566
- * boundaries before returning final component HTML.
567
- */
568
- protected async renderStringComponentWithQueuedForeignSubtrees(
569
- input: ComponentRenderInput,
570
- component: (props: Record<string, unknown>) => Promise<EcoPagesElement> | EcoPagesElement,
571
- ): Promise<ComponentRenderResult> {
572
- const componentRender = await this.renderStringComponentWithSerializedChildren(input, component);
573
- const queuedForeignSubtreeResolution = await this.foreignSubtreeExecutionService.resolveStringQueuedHtml({
574
- currentIntegrationName: this.name,
575
- renderInput: input,
576
- html: componentRender.html,
577
- runtimeContextKey: this.getForeignSubtreeResolutionContextKey(),
578
- queueLabel: 'String',
579
- getOwningRenderer: (integrationName, rendererCache) =>
580
- this.getIntegrationRendererForName(integrationName, rendererCache),
581
- applyAttributesToFirstElement: (html, attributes) =>
582
- this.htmlTransformer.applyAttributesToFirstElement(html, attributes),
583
- dedupeProcessedAssets: (assets) => this.htmlTransformer.dedupeProcessedAssets(assets),
584
- });
585
- const mergedAssets = this.htmlTransformer.dedupeProcessedAssets([
586
- ...(componentRender.assets ?? []),
587
- ...queuedForeignSubtreeResolution.assets,
588
- ]);
589
-
590
- return {
591
- ...componentRender,
592
- html: queuedForeignSubtreeResolution.html,
593
- rootTag: this.getRootTagName(queuedForeignSubtreeResolution.html),
594
- assets: mergedAssets.length > 0 ? mergedAssets : undefined,
595
- };
596
- }
597
-
598
- constructor({
599
- appConfig,
600
- assetProcessingService,
601
- resolvedIntegrationDependencies,
602
- rendererModules,
603
- runtimeOrigin,
604
- }: {
605
- appConfig: EcoPagesAppConfig;
606
- assetProcessingService: AssetProcessingService;
607
- resolvedIntegrationDependencies?: ProcessedAsset[];
608
- rendererModules?: unknown;
609
- runtimeOrigin: string;
610
- }) {
611
- this.appConfig = appConfig;
612
- this.assetProcessingService = assetProcessingService;
613
- this.htmlTransformer = new HtmlTransformerService();
614
- this.resolvedIntegrationDependencies = resolvedIntegrationDependencies || [];
615
- this.rendererModules = rendererModules ?? appConfig.runtime?.rendererModuleContext;
616
- this.runtimeOrigin = runtimeOrigin;
617
- this.dependencyResolverService = new DependencyResolverService(appConfig, assetProcessingService);
618
- this.pageModuleLoaderService = new PageModuleLoaderService(appConfig, runtimeOrigin);
619
- this.routeRenderOrchestrator = new RouteRenderOrchestrator(appConfig, assetProcessingService, {
620
- ownershipValidationService: new OwnershipValidationService(appConfig),
621
- });
622
- }
623
-
624
- /**
625
- * Returns the HTML path from the provided file path.
626
- * It extracts the path relative to the pages directory and removes the 'index' part if present.
627
- *
628
- * @param file - The file path to extract the HTML path from.
629
- * @returns The extracted HTML path.
630
- */
631
- protected getHtmlPath({ file }: { file: string }): string {
632
- const pagesDir = this.appConfig.absolutePaths.pagesDir;
633
- const pagesIndex = file.indexOf(pagesDir);
634
- if (pagesIndex === -1) return file;
635
- const startIndex = file.indexOf(pagesDir) + pagesDir.length;
636
- const endIndex = file.lastIndexOf('/');
637
- const path = file.substring(startIndex, endIndex);
638
- if (path === '/index') return '';
639
- return path;
640
- }
641
-
642
- /**
643
- * Returns the HTML template component.
644
- * It imports the HTML template from the specified path in the app configuration.
645
- *
646
- * @returns The HTML template component.
647
- */
648
- protected async getHtmlTemplate(): Promise<EcoComponent<HtmlTemplateProps>> {
649
- const htmlTemplatePath =
650
- this.getRendererModuleString('htmlTemplateModulePath') ?? this.appConfig.absolutePaths.htmlTemplatePath;
651
- try {
652
- const { default: HtmlTemplate } = await this.importPageFile(htmlTemplatePath);
653
- return HtmlTemplate as EcoComponent<HtmlTemplateProps>;
654
- } catch (error) {
655
- invariant(false, `Error importing HtmlTemplate: ${error}`);
656
- }
657
- }
658
-
659
- protected usesIntegrationPageImporter(_file: string): boolean {
660
- return false;
661
- }
662
-
663
- protected async importIntegrationPageFile(_file: string, _options?: RouteModuleLoadOptions): Promise<EcoPageFile> {
664
- invariant(false, 'Integration page importer must be implemented when enabled');
665
- }
666
-
667
- protected normalizeImportedPageFile<TPageModule extends EcoPageFile>(
668
- _file: string,
669
- pageModule: TPageModule,
670
- ): TPageModule {
671
- return pageModule;
672
- }
673
-
674
- /**
675
- * Imports the page file from the specified path.
676
- * It uses dynamic import to load the file and returns the imported module.
677
- *
678
- * @param file - The file path to import.
679
- * @returns The imported module.
680
- */
681
- protected async importPageFile(file: string, options?: RouteModuleLoadOptions): Promise<EcoPageFile> {
682
- const bypassCache =
683
- options?.bypassCache ?? (typeof Bun !== 'undefined' && process.env.NODE_ENV === 'development');
684
- const pageModule = this.usesIntegrationPageImporter(file)
685
- ? await this.importIntegrationPageFile(file, {
686
- bypassCache,
687
- cacheScope: options?.cacheScope,
688
- })
689
- : await this.pageModuleLoaderService.importPageFile(file, {
690
- bypassCache,
691
- cacheScope: options?.cacheScope,
692
- });
693
-
694
- return this.normalizeImportedPageFile(file, pageModule);
695
- }
696
-
697
- /**
698
- * Resolves the dependency path based on the component directory.
699
- * It combines the component directory with the provided path URL.
700
- *
701
- * @param componentDir - The component directory path.
702
- * @param pathUrl - The path URL to resolve.
703
- * @returns The resolved dependency path.
704
- */
705
- protected resolveDependencyPath(componentDir: string, pathUrl: string): string {
706
- return this.dependencyResolverService.resolveDependencyPath(componentDir, pathUrl);
707
- }
708
-
709
- /**
710
- * Extracts the dependencies from the provided component configuration.
711
- * It resolves the paths for scripts and stylesheets based on the component directory.
712
- *
713
- * @param componentDir - The component directory path.
714
- * @param scripts - The scripts to extract.
715
- * @param stylesheets - The stylesheets to extract.
716
- * @returns The extracted dependencies.
717
- */
718
- protected extractDependencies({
719
- componentDir,
720
- scripts,
721
- stylesheets,
722
- }: {
723
- componentDir: string;
724
- } & EcoComponentDependencies): EcoComponentDependencies {
725
- const scriptsPaths = [
726
- ...new Set(
727
- (scripts ?? [])
728
- .filter((script) => (typeof script === 'string' ? true : !script.lazy))
729
- .map((script) => (typeof script === 'string' ? script : script.src))
730
- .filter((script): script is string => Boolean(script))
731
- .map((script) => this.resolveDependencyPath(componentDir, script)),
732
- ),
733
- ];
734
-
735
- const stylesheetsPaths = [
736
- ...new Set(
737
- (stylesheets ?? [])
738
- .map((style) => (typeof style === 'string' ? style : style.src))
739
- .filter((style): style is string => Boolean(style))
740
- .map((style) => this.resolveDependencyPath(componentDir, style)),
741
- ),
742
- ];
743
-
744
- return {
745
- scripts: scriptsPaths,
746
- stylesheets: stylesheetsPaths,
747
- };
748
- }
749
-
750
- /**
751
- * Resolves lazy script paths to public asset URLs.
752
- * Converts source paths to their final bundled output paths.
753
- *
754
- * @param componentDir - The component directory path.
755
- * @param scripts - The lazy script paths to resolve.
756
- * @returns Comma-separated string of resolved public script paths.
757
- */
758
- protected resolveLazyScripts(componentDir: string, scripts: string[]): string {
759
- return this.dependencyResolverService.resolveLazyScripts(componentDir, scripts);
760
- }
761
-
762
- /**
763
- * Collects the dependencies for the provided components.
764
- * Combines component-specific dependencies with global integration dependencies.
765
- *
766
- * @param components - The components to collect dependencies from.
767
- */
768
- protected async resolveDependencies(
769
- components: (EcoComponent | Partial<EcoComponent>)[],
770
- ): Promise<ProcessedAsset[]> {
771
- const componentDeps = await this.processComponentDependencies(components);
772
- return this.resolvedIntegrationDependencies.concat(componentDeps);
773
- }
774
-
775
- /**
776
- * Processes component-specific dependencies WITHOUT prepending global integration dependencies.
777
- * Use this method when you need only the component's own assets.
778
- *
779
- * @param components - The components to collect dependencies from.
780
- */
781
- protected async processComponentDependencies(
782
- components: (EcoComponent | Partial<EcoComponent>)[],
783
- ): Promise<ProcessedAsset[]> {
784
- return this.dependencyResolverService.processComponentDependencies(components, this.name);
785
- }
786
-
787
- /**
788
- * Builds the internal route-render adapter consumed by `RouteRenderOrchestrator`.
789
- *
790
- * The route orchestrator needs a narrow orchestration contract, but those hooks should
791
- * not become public API on the renderer base class. Keeping the adapter object
792
- * local to the execution path lets the orchestrator depend on one explicit seam while
793
- * subclasses continue to override protected renderer behavior directly.
794
- */
795
- protected createRouteRenderOrchestratorAdapter(): RouteRenderOrchestratorAdapter<C> {
796
- return {
797
- name: this.name,
798
- resolveRouteRenderInputs: (routeOptions) => this.resolveRouteRenderInputs(routeOptions),
799
- resolveRouteAssets: (input) => this.resolveRouteAssets(input),
800
- resolveRoutePageComponentRender: (input) => this.resolveRoutePageComponentRender(input),
801
- renderRouteBody: (renderOptions) => this.renderRouteBody(renderOptions),
802
- getRouteHtmlFinalization: (renderOptions) => this.getRouteHtmlFinalization(renderOptions),
803
- transformRouteResponse: (response) => this.transformRouteResponse(response),
804
- };
805
- }
806
-
807
- protected async resolveRouteRenderInputs(
808
- routeOptions: RouteRendererOptions,
809
- ): Promise<RouteRenderOrchestratorResolvedInputs> {
810
- const pageModule = await this.pageModuleLoaderService.resolvePageModule({
811
- file: routeOptions.file,
812
- importPageFileFn: (targetFile) => this.importPageFile(targetFile),
813
- });
814
- const { Page, integrationSpecificProps } = pageModule;
815
- const HtmlTemplate = await this.getHtmlTemplate();
816
- const Layout = Page.config?.layout;
817
- const { props, metadata } = await this.pageModuleLoaderService.resolvePageData({
818
- pageModule,
819
- routeOptions,
820
- });
821
-
822
- return {
823
- Page,
824
- HtmlTemplate: HtmlTemplate as EcoComponent<HtmlTemplateProps>,
825
- Layout,
826
- props,
827
- metadata,
828
- integrationSpecificProps,
829
- };
830
- }
831
-
832
- protected async resolveRouteAssets(input: {
833
- routeOptions: RouteRendererOptions;
834
- components: (EcoComponent | Partial<EcoComponent>)[];
835
- }): Promise<{ resolvedDependencies: ProcessedAsset[]; pageBrowserGraph?: { assets: ProcessedAsset[] } }> {
836
- return {
837
- resolvedDependencies: await this.resolveDependencies(input.components),
838
- pageBrowserGraph: await this.buildPageBrowserGraph(input.routeOptions.file),
839
- };
840
- }
841
-
842
- protected async resolveRoutePageComponentRender(input: {
843
- Page: EcoComponent;
844
- Layout?: EcoComponent;
845
- props: Record<string, unknown>;
846
- routeOptions: RouteRendererOptions;
847
- }): Promise<ComponentRenderResult | undefined> {
848
- if (!this.shouldRenderPageComponent({ Page: input.Page, Layout: input.Layout, options: input.routeOptions })) {
849
- return undefined;
850
- }
851
-
852
- return this.renderComponentWithForeignChildren({
853
- component: input.Page,
854
- props: {
855
- ...input.props,
856
- params: input.routeOptions.params || {},
857
- query: input.routeOptions.query || {},
858
- },
859
- integrationContext: {
860
- componentInstanceId: 'eco-page-root',
861
- },
862
- });
863
- }
864
-
865
- protected async renderRouteBody(renderOptions: IntegrationRendererRenderOptions<C>): Promise<RouteRendererBody> {
866
- return this.render(renderOptions);
867
- }
868
-
869
- protected getRouteHtmlFinalization(renderOptions: IntegrationRendererRenderOptions<C>): RouteHtmlFinalization {
870
- const componentRootAttributes =
871
- renderOptions.componentRender?.canAttachAttributes &&
872
- renderOptions.componentRender.rootAttributes &&
873
- Object.keys(renderOptions.componentRender.rootAttributes).length > 0
874
- ? (renderOptions.componentRender.rootAttributes as Record<string, string>)
875
- : undefined;
876
- const documentAttributes = this.getDocumentAttributes(renderOptions);
877
- const hasStructuralFinalization =
878
- (componentRootAttributes && Object.keys(componentRootAttributes).length > 0) ||
879
- (documentAttributes && Object.keys(documentAttributes).length > 0);
880
-
881
- if (!hasStructuralFinalization) {
882
- return {};
883
- }
884
-
885
- return {
886
- finalizeHtml: (html) => {
887
- let renderedHtml = html;
888
-
889
- if (componentRootAttributes) {
890
- renderedHtml = this.htmlTransformer.applyAttributesToFirstBodyElement(
891
- renderedHtml,
892
- componentRootAttributes,
893
- );
894
- }
895
-
896
- if (documentAttributes) {
897
- renderedHtml = this.htmlTransformer.applyAttributesToHtmlElement(renderedHtml, documentAttributes);
898
- }
899
-
900
- return renderedHtml;
901
- },
902
- };
903
- }
904
-
905
- protected async transformRouteResponse(response: Response): Promise<RouteRendererBody> {
906
- const transformedResponse = await this.htmlTransformer.transform(response);
907
- return (transformedResponse.body ?? (await transformedResponse.text())) as RouteRendererBody;
908
- }
909
-
910
- /**
911
- * Prepares the render options for the integration renderer.
912
- * It imports the page file, collects dependencies, and prepares the render options.
913
- *
914
- * @param options - The route renderer options.
915
- * @returns The prepared render options.
916
- */
917
- protected async prepareRenderOptions(
918
- options: RouteRendererOptions,
919
- adapter = this.createRouteRenderOrchestratorAdapter(),
920
- ): Promise<IntegrationRendererRenderOptions<C>> {
921
- const renderOptions = await this.routeRenderOrchestrator.prepareRenderOptions(options, adapter);
922
- invariant(renderOptions.pagePackage !== undefined, 'Expected render preparation to produce a page package');
923
- this.htmlTransformer.setPagePackage(renderOptions.pagePackage);
924
- return renderOptions;
925
- }
926
-
927
- /**
928
- * Controls whether the page root should be rendered through `renderComponent()`
929
- * during route option preparation in component-capable modes.
930
- *
931
- * Integrations that already own page-level hydration (for example router-driven
932
- * React rendering) can override this and return `false` to avoid duplicate root
933
- * mount assets and competing hydration entrypoints.
934
- */
935
- protected shouldRenderPageComponent(_input: {
936
- Page: EcoComponent;
937
- Layout?: EcoComponent;
938
- options: RouteRendererOptions;
939
- }): boolean {
940
- return true;
941
- }
942
-
943
- /**
944
- * Executes the integration renderer with the provided options.
945
- *
946
- * Execution flow:
947
- * 1. Build normalized render options (`prepareRenderOptions`).
948
- * 2. Render the route body once.
949
- * 3. Reject unresolved route-level eco-marker artifacts.
950
- * 4. Optionally apply root attributes for page/component root boundaries.
951
- * 5. Run HTML transformer with final dependency set.
952
- *
953
- * Stream-safety note: the first render result is normalized to a string once,
954
- * then the pipeline continues with that immutable HTML value to avoid disturbed
955
- * response-body errors.
956
- *
957
- * @param options Route renderer options.
958
- * @returns Rendered route body plus effective cache strategy.
959
- */
960
- public async execute(options: RouteRendererOptions): Promise<RouteRenderResult> {
961
- const adapter = this.createRouteRenderOrchestratorAdapter();
962
- const renderOptions = await this.prepareRenderOptions(options, adapter);
963
- return this.routeRenderOrchestrator.executePrepared(renderOptions, adapter);
964
- }
965
-
966
- /**
967
- * Finalizes already-resolved HTML for explicit renderer-owned paths.
968
- *
969
- * This keeps document and root-attribute stamping plus HTML transformation
970
- * available after a renderer has completed nested foreign-subtree resolution without
971
- * routing back through shared route execution.
972
- */
973
- protected async finalizeResolvedHtml(options: {
974
- html: string;
975
- partial?: boolean;
976
- componentRootAttributes?: Record<string, string>;
977
- documentAttributes?: Record<string, string>;
978
- transformHtml?: boolean;
979
- }): Promise<string> {
980
- const rendererBootstrapDependencies = this.getRendererBootstrapDependencies(options.partial);
981
- this.appendProcessedDependencies(rendererBootstrapDependencies);
982
-
983
- let html = options.html;
984
-
985
- if (options.componentRootAttributes && Object.keys(options.componentRootAttributes).length > 0) {
986
- html = this.htmlTransformer.applyAttributesToFirstBodyElement(html, options.componentRootAttributes);
987
- }
988
-
989
- if (options.documentAttributes && Object.keys(options.documentAttributes).length > 0) {
990
- html = this.htmlTransformer.applyAttributesToHtmlElement(html, options.documentAttributes);
991
- }
992
-
993
- const shouldTransform = options.transformHtml ?? !options.partial;
994
- if (!shouldTransform) {
995
- return html;
996
- }
997
-
998
- const transformedResponse = await this.htmlTransformer.transform(
999
- new Response(html, {
1000
- headers: { 'Content-Type': 'text/html' },
1001
- }),
1002
- );
1003
-
1004
- return await transformedResponse.text();
1005
- }
1006
-
1007
- /**
1008
- * Returns document-level attributes to stamp onto the rendered `<html>` tag.
1009
- *
1010
- * Integrations can override this to expose explicit document ownership or
1011
- * other runtime coordination markers without relying on script sniffing.
1012
- */
1013
- protected getDocumentAttributes(
1014
- _renderOptions: IntegrationRendererRenderOptions<C>,
1015
- ): Record<string, string> | undefined {
1016
- return undefined;
1017
- }
1018
-
1019
- /**
1020
- * Returns a renderer instance for a given integration name.
1021
- *
1022
- * Uses a per-execution cache to avoid repeated renderer initialization.
1023
- *
1024
- * @param integrationName Target integration name.
1025
- * @param cache Render-pass renderer cache.
1026
- * @returns Renderer for the requested integration.
1027
- * @throws Error when no integration plugin matches `integrationName`.
1028
- */
1029
- protected getIntegrationRendererForName(
1030
- integrationName: string,
1031
- cache: Map<string, ForeignSubtreeExecutionOwningRenderer>,
1032
- ): ForeignSubtreeExecutionOwningRenderer {
1033
- if (cache.has(integrationName)) {
1034
- return cache.get(integrationName) as ForeignSubtreeExecutionOwningRenderer;
1035
- }
1036
-
1037
- if (integrationName === this.name) {
1038
- cache.set(integrationName, this);
1039
- return this;
1040
- }
1041
-
1042
- const integrationPlugin = this.appConfig.integrations.find(
1043
- (integration) => integration.name === integrationName,
1044
- );
1045
- invariant(!!integrationPlugin, `[ecopages] Integration not found for foreign owner: ${integrationName}`);
1046
- const renderer = integrationPlugin.initializeRenderer({
1047
- rendererModules: this.appConfig.runtime?.rendererModuleContext,
1048
- });
1049
- cache.set(integrationName, renderer);
1050
- return renderer;
1051
- }
1052
-
1053
- /**
1054
- * Abstract method to render the integration-specific component.
1055
- * This method should be implemented by the specific integration renderer.
1056
- *
1057
- * @param options - The integration renderer render options.
1058
- * @returns The rendered body.
1059
- */
1060
- abstract render(options: IntegrationRendererRenderOptions<C>): Promise<RouteRendererBody>;
1061
-
1062
- /**
1063
- * Renders one component under this integration's foreign-child runtime and resolves
1064
- * any nested foreign children captured during that render.
1065
- *
1066
- * Without this wrapper, a component tree with foreign-owned descendants would
1067
- * render them with no active foreign-child runtime, which bypasses the owning
1068
- * renderer's nested foreign-child handoff.
1069
- */
1070
- async renderComponentWithForeignChildren(input: ComponentRenderInput): Promise<ComponentRenderResult> {
1071
- return await this.foreignSubtreeExecutionService.executeComponentRender({
1072
- currentIntegrationName: this.name,
1073
- input,
1074
- renderComponent: (renderInput) => this.renderComponent(renderInput),
1075
- normalizeComponentRenderOutput: (result) => this.normalizeComponentRenderOutput(result),
1076
- hasForeignChildDescendants: (component) => this.hasForeignChildDescendants(component),
1077
- createForeignChildRuntime: ({ renderInput, rendererCache }) =>
1078
- this.createForeignChildRuntime({
1079
- renderInput,
1080
- rendererCache: rendererCache as Map<string, IntegrationRenderer<any>>,
1081
- }),
1082
- getOwningRenderer: (integrationName, rendererCache) =>
1083
- this.getIntegrationRendererForName(integrationName, rendererCache),
1084
- });
1085
- }
1086
-
1087
- /**
1088
- * Compatibility foreign-subtree contract that exposes a narrower payload shape for
1089
- * future route-composition work while preserving the current
1090
- * `renderComponentWithForeignChildren()` runtime semantics.
1091
- */
1092
- async renderForeignSubtree(input: ComponentRenderInput): Promise<ForeignSubtreeRenderPayload> {
1093
- const result = await this.renderComponentWithForeignChildren(input);
1094
-
1095
- return {
1096
- html: result.html,
1097
- assets: result.assets ?? [],
1098
- rootTag: result.rootTag,
1099
- rootAttributes: result.rootAttributes,
1100
- attachmentPolicy: result.canAttachAttributes ? { kind: 'first-element' } : { kind: 'none' },
1101
- integrationName: result.integrationName,
1102
- };
1103
- }
1104
-
1105
- private normalizeComponentRenderOutput(result: ComponentRenderResult): ComponentRenderResult {
1106
- const normalizedHtml = this.normalizeUnresolvedMarkerArtifactHtml(result.html);
1107
-
1108
- return normalizedHtml === result.html
1109
- ? result
1110
- : {
1111
- ...result,
1112
- html: normalizedHtml,
1113
- };
1114
- }
1115
-
1116
- protected normalizeUnresolvedMarkerArtifactHtml(html: string): string {
1117
- return normalizeUnresolvedMarkerArtifactHtml(html);
1118
- }
1119
-
1120
- /**
1121
- * Returns whether the component dependency tree crosses into another
1122
- * integration.
1123
- *
1124
- * This keeps foreign-child runtime setup narrow: same-integration trees can render
1125
- * directly without paying the queue orchestration cost.
1126
- */
1127
- protected hasForeignChildDescendants(component: EcoComponent): boolean {
1128
- const stack = [component];
1129
- const seen = new Set<EcoComponent>();
1130
-
1131
- while (stack.length > 0) {
1132
- const current = stack.pop();
1133
- if (!current || seen.has(current)) {
1134
- continue;
1135
- }
1136
-
1137
- seen.add(current);
1138
- const integrationName = current.config?.integration ?? current.config?.__eco?.integration;
1139
- if (integrationName && integrationName !== this.name) {
1140
- return true;
1141
- }
1142
-
1143
- stack.push(...(current.config?.dependencies?.components ?? []));
1144
- }
1145
-
1146
- return false;
1147
- }
1148
-
1149
- /**
1150
- * Render a view directly to a Response object.
1151
- * Used for explicit routing where views are rendered from route handlers.
1152
- *
1153
- * @param view - The eco.page component to render
1154
- * @param props - Props to pass to the view
1155
- * @param ctx - Render context with partial flag and response options
1156
- * @returns A Response object with the rendered content
1157
- */
1158
- abstract renderToResponse<P = Record<string, unknown>>(
1159
- view: EcoComponent<P>,
1160
- props: P,
1161
- ctx: RenderToResponseContext,
1162
- ): Promise<Response>;
1163
-
1164
- /**
1165
- * Render a single component and return structured output for orchestration paths.
1166
- *
1167
- * Default behavior delegates to `renderToResponse` in partial mode and wraps
1168
- * the resulting HTML into the `ComponentRenderResult` contract.
1169
- *
1170
- * In foreign-subtree resolution, this method is the integration-owned step that turns an
1171
- * already-resolved deferred foreign subtree into concrete HTML, assets, and optional
1172
- * root attributes.
1173
- *
1174
- * Integrations can override this for richer behavior (asset emission,
1175
- * root attributes, integration-specific hydration metadata).
1176
- *
1177
- * @param input Component render request.
1178
- * @returns Structured render result used by component/page orchestration.
1179
- */
1180
- async renderComponent(input: ComponentRenderInput): Promise<ComponentRenderResult> {
1181
- const response = await this.renderToResponse(
1182
- input.component as EcoFunctionComponent<Record<string, unknown>, EcoPagesElement>,
1183
- input.props,
1184
- { partial: true },
1185
- );
1186
- const html = await response.text();
1187
-
1188
- return {
1189
- html,
1190
- canAttachAttributes: true,
1191
- rootTag: this.getRootTagName(html),
1192
- integrationName: this.name,
1193
- };
1194
- }
1195
-
1196
- /**
1197
- * Extracts the first root element tag name from HTML output.
1198
- *
1199
- * @param html HTML fragment.
1200
- * @returns Root tag name when present; otherwise `undefined`.
1201
- */
1202
- protected getRootTagName(html: string): string | undefined {
1203
- const rootTag = html.match(/^(?:\s|<!--[\s\S]*?-->)*<([a-zA-Z][a-zA-Z0-9:-]*)\b/);
1204
- return rootTag?.[1];
1205
- }
1206
-
1207
- /**
1208
- * Builds the Page Browser Graph owned by this integration for one Page.
1209
- * This method can be optionally overridden by the specific integration renderer.
1210
- *
1211
- * @param file - The file path to build assets for.
1212
- * @returns The structured Page Browser Graph or undefined.
1213
- */
1214
- protected async buildPageBrowserGraph(_file: string): Promise<{ assets: ProcessedAsset[] } | undefined> {
1215
- return undefined;
1216
- }
1217
-
1218
- /**
1219
- * Creates the per-render foreign-child runtime adopted by the shared component
1220
- * render context.
1221
- *
1222
- * The default runtime queues delegated foreign subtrees inside the owning
1223
- * renderer so string and markup renderers do not need to re-declare the same
1224
- * handoff boilerplate. Override only when a renderer needs custom runtime
1225
- * context or a different foreign-child execution strategy.
1226
- */
1227
- protected createForeignChildRuntime(options: {
1228
- renderInput: ComponentRenderInput;
1229
- rendererCache: Map<string, IntegrationRenderer<any>>;
1230
- }): ForeignChildRuntime {
1231
- return this.createQueuedForeignSubtreeExecutionRuntime({
1232
- renderInput: options.renderInput,
1233
- rendererCache: options.rendererCache,
1234
- });
1235
- }
1236
-
1237
- /**
1238
- * Creates an explicit fail-fast runtime for tests or renderers that do not
1239
- * support cross-integration foreign-child execution.
1240
- */
1241
- protected createFailFastForeignChildRuntime(): ForeignChildRuntime {
1242
- return this.foreignSubtreeExecutionService.createFailFastRuntime(this.name);
1243
- }
1244
- }