@ecopages/core 0.2.0-beta.3 → 0.2.0-beta.31

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 (433) hide show
  1. package/README.md +38 -9
  2. package/package.json +241 -30
  3. package/src/adapters/README.md +6 -2
  4. package/src/adapters/abstract/application-adapter.d.ts +123 -6
  5. package/src/adapters/abstract/application-adapter.js +151 -1
  6. package/src/adapters/abstract/segment-path-matcher.d.ts +6 -0
  7. package/src/adapters/abstract/segment-path-matcher.js +149 -0
  8. package/src/adapters/abstract/server-adapter.d.ts +16 -2
  9. package/src/adapters/abstract/ws-pattern-matcher.d.ts +12 -0
  10. package/src/adapters/abstract/ws-pattern-matcher.js +30 -0
  11. package/src/adapters/bun/bun-user-websocket-lifecycle.d.ts +22 -0
  12. package/src/adapters/bun/bun-user-websocket-lifecycle.js +96 -0
  13. package/src/adapters/bun/client-bridge.d.ts +1 -0
  14. package/src/adapters/bun/client-bridge.js +3 -0
  15. package/src/adapters/bun/create-app.d.ts +9 -6
  16. package/src/adapters/bun/create-app.js +76 -45
  17. package/src/adapters/bun/hmr-manager.d.ts +1 -1
  18. package/src/adapters/bun/hmr-manager.js +1 -1
  19. package/src/adapters/bun/index.d.ts +1 -1
  20. package/src/adapters/bun/index.js +25 -2
  21. package/src/adapters/bun/runtime-host.d.ts +1 -1
  22. package/src/adapters/bun/runtime-host.js +1 -1
  23. package/src/adapters/bun/server-adapter.d.ts +92 -41
  24. package/src/adapters/bun/server-adapter.js +256 -117
  25. package/src/adapters/bun/static-preview-host.d.ts +1 -1
  26. package/src/adapters/bun/static-preview-host.js +25 -20
  27. package/src/adapters/create-app.d.ts +13 -11
  28. package/src/adapters/create-app.js +2 -51
  29. package/src/adapters/index.d.ts +2 -2
  30. package/src/adapters/index.js +26 -4
  31. package/src/adapters/node/create-app.d.ts +8 -3
  32. package/src/adapters/node/create-app.js +61 -13
  33. package/src/adapters/node/node-client-bridge.d.ts +1 -0
  34. package/src/adapters/node/node-client-bridge.js +3 -0
  35. package/src/adapters/node/node-hmr-manager.d.ts +1 -1
  36. package/src/adapters/node/node-hmr-manager.js +1 -1
  37. package/src/adapters/node/runtime-host.d.ts +1 -1
  38. package/src/adapters/node/runtime-host.js +1 -1
  39. package/src/adapters/node/server-adapter-dependencies.js +4 -0
  40. package/src/adapters/node/server-adapter.d.ts +64 -23
  41. package/src/adapters/node/server-adapter.js +169 -142
  42. package/src/adapters/node/static-content-server.d.ts +1 -0
  43. package/src/adapters/node/static-content-server.js +10 -2
  44. package/src/adapters/node/static-preview-host.d.ts +1 -1
  45. package/src/adapters/node/static-preview-host.js +27 -12
  46. package/src/adapters/shared/{hmr-entrypoint-registrar.d.ts → hmr/hmr-entrypoint-registrar.d.ts} +31 -30
  47. package/src/adapters/shared/hmr/hmr-entrypoint-registrar.js +106 -0
  48. package/src/adapters/shared/{hmr-html-response.d.ts → hmr/hmr-html-response.d.ts} +2 -2
  49. package/src/adapters/shared/{hmr-html-response.js → hmr/hmr-html-response.js} +4 -1
  50. package/src/adapters/shared/hmr/shared-hmr-manager.d.ts +101 -0
  51. package/src/adapters/shared/hmr/shared-hmr-manager.js +432 -0
  52. package/src/adapters/shared/http/api-request-pipeline.d.ts +23 -0
  53. package/src/adapters/shared/http/api-request-pipeline.js +129 -0
  54. package/src/adapters/shared/{api-response.d.ts → http/api-response.d.ts} +1 -1
  55. package/src/adapters/shared/{api-response.js → http/api-response.js} +6 -23
  56. package/src/adapters/shared/http/create-body-response.d.ts +12 -0
  57. package/src/adapters/shared/http/create-body-response.js +23 -0
  58. package/src/adapters/shared/http/define-api-handler.d.ts +90 -0
  59. package/src/adapters/shared/http/define-api-handler.js +63 -0
  60. package/src/adapters/shared/{explicit-static-render-preparation.d.ts → http/explicit-static-render-preparation.d.ts} +3 -3
  61. package/src/adapters/shared/{explicit-static-route-matcher.d.ts → http/explicit-static-route-matcher.d.ts} +3 -9
  62. package/src/adapters/shared/{explicit-static-route-matcher.js → http/explicit-static-route-matcher.js} +3 -38
  63. package/src/adapters/shared/{file-route-middleware-pipeline.d.ts → http/file-route-middleware-pipeline.d.ts} +2 -2
  64. package/src/adapters/shared/{file-route-middleware-pipeline.js → http/file-route-middleware-pipeline.js} +10 -22
  65. package/src/adapters/shared/{fs-server-response-factory.d.ts → http/fs-server-response-factory.d.ts} +7 -2
  66. package/src/adapters/shared/{fs-server-response-factory.js → http/fs-server-response-factory.js} +22 -2
  67. package/src/adapters/shared/{fs-server-response-matcher.d.ts → http/fs-server-response-matcher.d.ts} +25 -5
  68. package/src/adapters/shared/{fs-server-response-matcher.js → http/fs-server-response-matcher.js} +109 -27
  69. package/src/adapters/shared/http/run-middleware-chain.d.ts +5 -0
  70. package/src/adapters/shared/http/run-middleware-chain.js +17 -0
  71. package/src/adapters/shared/{application-adapter.d.ts → runtime/application-adapter.d.ts} +2 -2
  72. package/src/adapters/shared/{application-adapter.js → runtime/application-adapter.js} +1 -1
  73. package/src/adapters/shared/runtime/copy-runtime-public-dir.d.ts +6 -0
  74. package/src/adapters/shared/runtime/copy-runtime-public-dir.js +24 -0
  75. package/src/adapters/shared/runtime/port-manager.d.ts +116 -0
  76. package/src/adapters/shared/runtime/port-manager.js +196 -0
  77. package/src/adapters/shared/{render-context.d.ts → runtime/render-context.d.ts} +2 -2
  78. package/src/adapters/shared/{render-context.js → runtime/render-context.js} +8 -17
  79. package/src/adapters/shared/{runtime-app-bootstrap.d.ts → runtime/runtime-app-bootstrap.d.ts} +4 -3
  80. package/src/adapters/shared/{runtime-app-bootstrap.js → runtime/runtime-app-bootstrap.js} +4 -7
  81. package/src/adapters/shared/runtime/runtime-server-lifecycle.d.ts +46 -0
  82. package/src/adapters/shared/runtime/runtime-server-lifecycle.js +57 -0
  83. package/src/adapters/shared/{server-adapter.d.ts → runtime/server-adapter.d.ts} +23 -49
  84. package/src/adapters/shared/runtime/server-adapter.js +226 -0
  85. package/src/adapters/shared/{server-route-handler.d.ts → runtime/server-route-handler.d.ts} +6 -33
  86. package/src/adapters/shared/{server-route-handler.js → runtime/server-route-handler.js} +5 -43
  87. package/src/adapters/shared/{server-static-builder.d.ts → runtime/server-static-builder.d.ts} +27 -35
  88. package/src/adapters/shared/runtime/server-static-builder.js +191 -0
  89. package/src/adapters/shared/{static-preview-host.d.ts → runtime/static-preview-host.d.ts} +6 -1
  90. package/src/adapters/shared/ws/node-http-websocket-upgrades.d.ts +21 -0
  91. package/src/adapters/shared/ws/node-http-websocket-upgrades.js +100 -0
  92. package/src/adapters/shared/ws/websocket-lifecycle.d.ts +24 -0
  93. package/src/adapters/shared/ws/websocket-lifecycle.js +55 -0
  94. package/src/build/README.md +140 -31
  95. package/src/build/app-build-manifest-runtime.d.ts +39 -0
  96. package/src/build/app-build-manifest-runtime.js +124 -0
  97. package/src/build/{browser-runtime-plugin.d.ts → browser/browser-runtime-plugin.d.ts} +1 -1
  98. package/src/build/{browser-runtime-plugin.js → browser/browser-runtime-plugin.js} +1 -1
  99. package/src/build/browser/jsx-ownership-plugins.d.ts +24 -0
  100. package/src/build/browser/jsx-ownership-plugins.js +41 -0
  101. package/src/build/browser/lit-static-render-worker-context.d.ts +2 -0
  102. package/src/build/browser/lit-static-render-worker-context.js +6 -0
  103. package/src/build/build-adapter.d.ts +29 -334
  104. package/src/build/build-adapter.js +32 -133
  105. package/src/build/cache/build-input-fingerprint.d.ts +28 -0
  106. package/src/build/cache/build-input-fingerprint.js +31 -0
  107. package/src/build/cache/cache-constants.d.ts +4 -0
  108. package/src/build/cache/cache-constants.js +6 -0
  109. package/src/build/cache/cache-keys.d.ts +22 -0
  110. package/src/build/cache/cache-keys.js +63 -0
  111. package/src/build/cache/dev-browser-script-cache.d.ts +34 -0
  112. package/src/build/cache/dev-browser-script-cache.js +90 -0
  113. package/src/build/cache/pages-unified-graph-build.d.ts +31 -0
  114. package/src/build/cache/pages-unified-graph-build.js +198 -0
  115. package/src/build/cache/production-build-cache.d.ts +20 -0
  116. package/src/build/cache/production-build-cache.js +63 -0
  117. package/src/build/cache/server-entry-build-cache.d.ts +43 -0
  118. package/src/build/cache/server-entry-build-cache.js +165 -0
  119. package/src/build/contracts/build-contracts.d.ts +96 -0
  120. package/src/build/contracts/build-manifest.d.ts +90 -0
  121. package/src/build/{build-manifest.js → contracts/build-manifest.js} +2 -2
  122. package/src/build/contracts/build-types.js +0 -0
  123. package/src/build/{rolldown-adapter-helpers.d.ts → rolldown/rolldown-adapter-helpers.d.ts} +23 -9
  124. package/src/build/{rolldown-adapter-helpers.js → rolldown/rolldown-adapter-helpers.js} +99 -13
  125. package/src/build/{rolldown-build-adapter.d.ts → rolldown/rolldown-build-adapter.d.ts} +3 -7
  126. package/src/build/{rolldown-build-adapter.js → rolldown/rolldown-build-adapter.js} +3 -3
  127. package/src/build/rolldown/rolldown-build-invocation-metrics.d.ts +12 -0
  128. package/src/build/rolldown/rolldown-build-invocation-metrics.js +43 -0
  129. package/src/build/{rolldown-plugin-bridge.d.ts → rolldown/rolldown-plugin-bridge.d.ts} +16 -2
  130. package/src/build/{rolldown-plugin-bridge.js → rolldown/rolldown-plugin-bridge.js} +21 -6
  131. package/src/build/rolldown/rolldown-source-transform-pass.d.ts +15 -0
  132. package/src/build/rolldown/rolldown-source-transform-pass.js +61 -0
  133. package/src/build/rolldown/runtime-build-output-normalizer.d.ts +10 -0
  134. package/src/build/rolldown/runtime-build-output-normalizer.js +201 -0
  135. package/src/build/runtime/build-profile-options.d.ts +7 -0
  136. package/src/build/runtime/build-profile-options.js +37 -0
  137. package/src/build/runtime/build-request-identity.d.ts +17 -0
  138. package/src/build/runtime/build-request-identity.js +54 -0
  139. package/src/build/runtime/build-request-policy.d.ts +59 -0
  140. package/src/build/runtime/build-request-policy.js +46 -0
  141. package/src/build/runtime/build-runtime.d.ts +28 -0
  142. package/src/build/runtime/build-runtime.js +65 -0
  143. package/src/build/runtime/deduping-build-executor.d.ts +21 -0
  144. package/src/build/runtime/deduping-build-executor.js +34 -0
  145. package/src/build/runtime/parallel-build-executor.d.ts +21 -0
  146. package/src/build/runtime/parallel-build-executor.js +52 -0
  147. package/src/build/{serialized-build-executor.d.ts → runtime/serialized-build-executor.d.ts} +1 -1
  148. package/src/client/navigation-scripts/classification.d.ts +16 -0
  149. package/src/client/navigation-scripts/classification.js +41 -0
  150. package/src/client/navigation-scripts/index.d.ts +3 -0
  151. package/src/client/navigation-scripts/index.js +23 -0
  152. package/src/client/navigation-scripts/navigation-scripts.test.browser.js +65 -0
  153. package/src/client/navigation-scripts/registry.d.ts +11 -0
  154. package/src/client/navigation-scripts/registry.js +12 -0
  155. package/src/client/navigation-scripts/rerun-queue.d.ts +37 -0
  156. package/src/client/navigation-scripts/rerun-queue.js +73 -0
  157. package/src/client/scroll.d.ts +17 -0
  158. package/src/client/scroll.js +25 -0
  159. package/src/client/scroll.test.browser.js +37 -0
  160. package/src/client/view-transitions.d.ts +16 -0
  161. package/src/client/view-transitions.js +63 -0
  162. package/src/config/config-builder.d.ts +25 -10
  163. package/src/config/config-builder.js +53 -11
  164. package/src/config/constants.d.ts +1 -0
  165. package/src/config/constants.js +2 -1
  166. package/src/dev/client-bridge-registry.d.ts +5 -0
  167. package/src/dev/client-bridge-registry.js +15 -0
  168. package/src/dev/dev-client-ownership.d.ts +7 -0
  169. package/src/dev/dev-client-ownership.js +6 -0
  170. package/src/dev/hmr-manager-registry.d.ts +8 -0
  171. package/src/dev/hmr-manager-registry.js +15 -0
  172. package/src/dev/host-runtime.d.ts +3 -0
  173. package/src/dev/host-runtime.js +7 -0
  174. package/src/dev/runtime-server-started-message.d.ts +2 -0
  175. package/src/dev/runtime-server-started-message.js +6 -0
  176. package/src/diagnostics/request-build-dedupe.d.ts +18 -0
  177. package/src/diagnostics/request-build-dedupe.js +33 -0
  178. package/src/diagnostics/startup-trace.d.ts +72 -0
  179. package/src/diagnostics/startup-trace.js +253 -0
  180. package/src/eco/README.md +11 -0
  181. package/src/eco/eco-declared-component.d.ts +14 -0
  182. package/src/eco/eco-declared-component.js +16 -0
  183. package/src/eco/eco.browser.js +5 -6
  184. package/src/eco/eco.js +7 -8
  185. package/src/eco/eco.types.d.ts +14 -3
  186. package/src/eco/eco.utils.d.ts +1 -1
  187. package/src/eco/eco.utils.js +1 -1
  188. package/src/eco/page-layout-normalization.d.ts +21 -0
  189. package/src/eco/page-layout-normalization.js +59 -0
  190. package/src/env.d.ts +2 -0
  191. package/src/errors/index.d.ts +1 -0
  192. package/src/errors/index.js +7 -1
  193. package/src/errors/undeclared-component-dependency-error.d.ts +11 -0
  194. package/src/errors/undeclared-component-dependency-error.js +17 -0
  195. package/src/hmr/client/hmr-runtime.js +7 -4
  196. package/src/hmr/hmr-entrypoint-output.d.ts +49 -0
  197. package/src/hmr/hmr-entrypoint-output.js +60 -0
  198. package/src/hmr/hmr-file-change-prep.d.ts +10 -0
  199. package/src/hmr/hmr-file-change-prep.js +17 -0
  200. package/src/hmr/hmr-strategy.d.ts +15 -0
  201. package/src/hmr/hmr-strategy.js +19 -0
  202. package/src/hmr/strategies/js-hmr-strategy.d.ts +3 -5
  203. package/src/hmr/strategies/js-hmr-strategy.js +72 -19
  204. package/src/hmr/strategies/server-rendered-template-hmr-strategy.d.ts +17 -0
  205. package/src/hmr/strategies/server-rendered-template-hmr-strategy.js +29 -0
  206. package/src/index.d.ts +2 -1
  207. package/src/index.js +28 -2
  208. package/src/integrations/ghtml/ghtml-renderer.d.ts +2 -6
  209. package/src/integrations/ghtml/ghtml-renderer.js +2 -51
  210. package/src/integrations/ghtml/ghtml.plugin.d.ts +3 -16
  211. package/src/integrations/ghtml/ghtml.plugin.js +7 -14
  212. package/src/plugins/alias-resolver-cache.d.ts +6 -9
  213. package/src/plugins/alias-resolver-plugin.d.ts +3 -3
  214. package/src/plugins/alias-resolver-plugin.js +38 -51
  215. package/src/plugins/define-integration.d.ts +26 -0
  216. package/src/plugins/define-integration.js +19 -0
  217. package/src/plugins/eco-component-meta-plugin.d.ts +1 -1
  218. package/src/plugins/eco-component-meta-plugin.js +5 -8
  219. package/src/plugins/foreign-jsx-override-plugin.d.ts +1 -1
  220. package/src/plugins/foreign-jsx-override-plugin.js +4 -6
  221. package/src/plugins/integration-plugin.d.ts +43 -14
  222. package/src/plugins/integration-plugin.js +18 -5
  223. package/src/plugins/jsx-import-source.utils.d.ts +8 -0
  224. package/src/plugins/jsx-import-source.utils.js +26 -0
  225. package/src/plugins/processor.d.ts +61 -12
  226. package/src/plugins/processor.js +24 -5
  227. package/src/plugins/source-transform.d.ts +32 -1
  228. package/src/plugins/source-transform.js +23 -1
  229. package/src/plugins/tsconfig-import-resolver.d.ts +18 -0
  230. package/src/plugins/tsconfig-import-resolver.js +159 -0
  231. package/src/route-renderer/GRAPH.md +26 -32
  232. package/src/route-renderer/README.md +38 -31
  233. package/src/route-renderer/orchestration/document-shell/document-shell-render.service.d.ts +107 -0
  234. package/src/route-renderer/orchestration/document-shell/document-shell-render.service.js +148 -0
  235. package/src/route-renderer/orchestration/document-shell/layout-shell-props.service.d.ts +20 -0
  236. package/src/route-renderer/orchestration/document-shell/layout-shell-props.service.js +31 -0
  237. package/src/route-renderer/orchestration/{component-render-context.d.ts → foreign-child/component-render-context.d.ts} +8 -15
  238. package/src/route-renderer/orchestration/{component-render-context.js → foreign-child/component-render-context.js} +4 -2
  239. package/src/route-renderer/orchestration/{render-output.utils.d.ts → foreign-child/foreign-child-output.utils.d.ts} +17 -7
  240. package/src/route-renderer/orchestration/{render-output.utils.js → foreign-child/foreign-child-output.utils.js} +35 -26
  241. package/src/route-renderer/orchestration/{foreign-subtree-execution.service.d.ts → foreign-child/foreign-subtree-execution.service.d.ts} +64 -34
  242. package/src/route-renderer/orchestration/{foreign-subtree-execution.service.js → foreign-child/foreign-subtree-execution.service.js} +170 -37
  243. package/src/route-renderer/orchestration/foreign-child/owning-renderer-resolution.d.ts +19 -0
  244. package/src/route-renderer/orchestration/foreign-child/owning-renderer-resolution.js +35 -0
  245. package/src/route-renderer/orchestration/integration-renderer.d.ts +24 -143
  246. package/src/route-renderer/orchestration/integration-renderer.js +163 -402
  247. package/src/route-renderer/orchestration/integration-renderer.test-fixtures.d.ts +75 -0
  248. package/src/route-renderer/orchestration/integration-renderer.test-fixtures.js +177 -0
  249. package/src/route-renderer/orchestration/ownership-graph/component-graph-collectors.d.ts +10 -0
  250. package/src/route-renderer/orchestration/ownership-graph/component-graph-collectors.js +143 -0
  251. package/src/route-renderer/orchestration/ownership-graph/component-graph.d.ts +34 -0
  252. package/src/route-renderer/orchestration/ownership-graph/component-graph.js +96 -0
  253. package/src/route-renderer/orchestration/{ownership-validation.service.d.ts → ownership-graph/ownership-validation.service.d.ts} +7 -2
  254. package/src/route-renderer/orchestration/{ownership-validation.service.js → ownership-graph/ownership-validation.service.js} +30 -3
  255. package/src/route-renderer/orchestration/page-browser-graph/global-injector-assets.service.d.ts +7 -0
  256. package/src/route-renderer/orchestration/page-browser-graph/global-injector-assets.service.js +32 -0
  257. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-contribution.loader.d.ts +9 -0
  258. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-contribution.loader.js +7 -0
  259. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-merge.utils.d.ts +12 -0
  260. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-merge.utils.js +29 -0
  261. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-session.d.ts +106 -0
  262. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-session.js +436 -0
  263. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph.service.d.ts +31 -0
  264. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph.service.js +229 -0
  265. package/src/route-renderer/orchestration/{processed-asset-dedupe.d.ts → page-browser-graph/processed-asset-dedupe.d.ts} +1 -1
  266. package/src/route-renderer/orchestration/route-pipeline/integration-route-render-adapter.d.ts +31 -0
  267. package/src/route-renderer/orchestration/route-pipeline/integration-route-render-adapter.js +25 -0
  268. package/src/route-renderer/orchestration/route-pipeline/marker-artifact.utils.d.ts +6 -0
  269. package/src/route-renderer/orchestration/route-pipeline/marker-artifact.utils.js +27 -0
  270. package/src/route-renderer/orchestration/route-pipeline/robots-meta.contribution.d.ts +15 -0
  271. package/src/route-renderer/orchestration/route-pipeline/robots-meta.contribution.js +36 -0
  272. package/src/route-renderer/orchestration/route-pipeline/route-html-finalization.service.d.ts +20 -0
  273. package/src/route-renderer/orchestration/route-pipeline/route-html-finalization.service.js +24 -0
  274. package/src/route-renderer/orchestration/route-pipeline/route-prepared-options.builder.d.ts +25 -0
  275. package/src/route-renderer/orchestration/route-pipeline/route-prepared-options.builder.js +49 -0
  276. package/src/route-renderer/orchestration/route-pipeline/route-prepared-options.utils.d.ts +4 -0
  277. package/src/route-renderer/orchestration/route-pipeline/route-prepared-options.utils.js +33 -0
  278. package/src/route-renderer/orchestration/{route-render-orchestrator.d.ts → route-pipeline/route-render-orchestrator.d.ts} +13 -53
  279. package/src/route-renderer/orchestration/route-pipeline/route-render-orchestrator.js +162 -0
  280. package/src/route-renderer/orchestration/string-markup-renderer.d.ts +14 -0
  281. package/src/route-renderer/orchestration/string-markup-renderer.js +55 -0
  282. package/src/route-renderer/page-loading/component-dependency-collection.js +5 -2
  283. package/src/route-renderer/page-loading/ecopages-virtual-imports.d.ts +6 -0
  284. package/src/route-renderer/page-loading/ecopages-virtual-imports.js +7 -2
  285. package/src/route-renderer/page-loading/module-declaration-aggregation.js +4 -0
  286. package/src/router/client/link-intent.d.ts +11 -21
  287. package/src/router/client/link-intent.js +10 -0
  288. package/src/router/client/link-intent.test.browser.js +12 -1
  289. package/src/router/client/link-navigation-policy.d.ts +45 -0
  290. package/src/router/client/link-navigation-policy.js +101 -0
  291. package/src/router/client/link-navigation-policy.test.browser.d.ts +1 -0
  292. package/src/router/client/link-navigation-policy.test.browser.js +92 -0
  293. package/src/router/client/navigation-coordinator.d.ts +1 -1
  294. package/src/router/client/navigation-coordinator.js +12 -2
  295. package/src/services/assets/asset-processing-service/asset-dependency-keys.d.ts +13 -0
  296. package/src/services/assets/asset-processing-service/asset-dependency-keys.js +3 -0
  297. package/src/services/assets/asset-processing-service/asset-processing.service.d.ts +6 -1
  298. package/src/services/assets/asset-processing-service/asset-processing.service.js +44 -5
  299. package/src/services/assets/asset-processing-service/assets.types.d.ts +1 -1
  300. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.d.ts +2 -1
  301. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.js +1 -0
  302. package/src/services/assets/asset-processing-service/browser-runtime-entry-resolution.d.ts +52 -0
  303. package/src/services/assets/asset-processing-service/browser-runtime-entry-resolution.js +78 -0
  304. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.d.ts +4 -2
  305. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.js +28 -13
  306. package/src/services/assets/asset-processing-service/finalize-processed-asset.d.ts +3 -0
  307. package/src/services/assets/asset-processing-service/finalize-processed-asset.js +7 -0
  308. package/src/services/assets/asset-processing-service/grouped-content-bundles.d.ts +2 -1
  309. package/src/services/assets/asset-processing-service/grouped-content-bundles.js +38 -12
  310. package/src/services/assets/asset-processing-service/index.d.ts +2 -0
  311. package/src/services/assets/asset-processing-service/index.js +2 -0
  312. package/src/services/assets/asset-processing-service/inline-content-script-body.d.ts +11 -0
  313. package/src/services/assets/asset-processing-service/inline-content-script-body.js +17 -0
  314. package/src/services/assets/asset-processing-service/materialize-content-script-asset.d.ts +9 -0
  315. package/src/services/assets/asset-processing-service/materialize-content-script-asset.js +18 -0
  316. package/src/services/assets/asset-processing-service/processors/base/base-script-processor.d.ts +0 -2
  317. package/src/services/assets/asset-processing-service/processors/base/base-script-processor.js +2 -15
  318. package/src/services/assets/asset-processing-service/processors/script/content-script.processor.d.ts +8 -0
  319. package/src/services/assets/asset-processing-service/processors/script/content-script.processor.js +73 -68
  320. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.d.ts +0 -1
  321. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.js +18 -15
  322. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.js +17 -3
  323. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.d.ts +0 -3
  324. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +2 -31
  325. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.d.ts +0 -3
  326. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +2 -30
  327. package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.d.ts +2 -0
  328. package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.js +43 -0
  329. package/src/services/assets/asset-processing-service/resolve-integration-plugin.d.ts +4 -0
  330. package/src/services/assets/asset-processing-service/resolve-integration-plugin.js +17 -0
  331. package/src/services/assets/asset-processing-service/ungrouped-dependency-processing.d.ts +0 -1
  332. package/src/services/assets/asset-processing-service/ungrouped-dependency-processing.js +5 -10
  333. package/src/services/assets/browser-bundle.service.d.ts +28 -30
  334. package/src/services/assets/browser-bundle.service.js +28 -19
  335. package/src/services/html/html-transformer.service.d.ts +1 -1
  336. package/src/services/html/html-transformer.service.js +5 -5
  337. package/src/services/invalidation/development-invalidation.service.d.ts +25 -2
  338. package/src/services/invalidation/development-invalidation.service.js +64 -11
  339. package/src/services/module-loading/README.md +49 -0
  340. package/src/services/module-loading/app-server-module-transpiler.service.d.ts +8 -0
  341. package/src/services/module-loading/app-server-module-transpiler.service.js +3 -21
  342. package/src/services/module-loading/page-module-import.service.d.ts +6 -2
  343. package/src/services/module-loading/page-module-import.service.js +110 -47
  344. package/src/services/module-loading/route-module-build-cache-registry.d.ts +24 -0
  345. package/src/services/module-loading/route-module-build-cache-registry.js +37 -0
  346. package/src/services/module-loading/route-module-build-cache.d.ts +4 -0
  347. package/src/services/module-loading/route-module-build-cache.js +38 -0
  348. package/src/services/module-loading/route-module-build-cache.store.d.ts +57 -0
  349. package/src/services/module-loading/route-module-build-cache.store.js +207 -0
  350. package/src/services/module-loading/route-module-build-manifest.d.ts +54 -0
  351. package/src/services/module-loading/route-module-build-manifest.js +85 -0
  352. package/src/services/module-loading/route-module-dependency-hasher.d.ts +81 -0
  353. package/src/services/module-loading/route-module-dependency-hasher.js +122 -0
  354. package/src/services/module-loading/server-module-transpiler.service.d.ts +1 -1
  355. package/src/services/module-loading/server-module-transpiler.service.js +1 -1
  356. package/src/services/validation/schema-validation-service.d.ts +1 -4
  357. package/src/services/validation/schema-validation-service.js +12 -13
  358. package/src/services/validation/standard-schema.types.d.ts +9 -62
  359. package/src/services/validation/validate-standard-schema.d.ts +7 -0
  360. package/src/services/validation/validate-standard-schema.js +14 -0
  361. package/src/static-site-generator/README.md +41 -0
  362. package/src/static-site-generator/production-page-browser-graph-prebuild.d.ts +28 -0
  363. package/src/static-site-generator/production-page-browser-graph-prebuild.js +22 -0
  364. package/src/static-site-generator/sitemap-routes.d.ts +14 -0
  365. package/src/static-site-generator/sitemap-routes.js +31 -0
  366. package/src/static-site-generator/sitemap.d.ts +15 -0
  367. package/src/static-site-generator/sitemap.js +33 -0
  368. package/src/static-site-generator/static-build-invalidation.d.ts +10 -0
  369. package/src/static-site-generator/static-build-invalidation.js +59 -0
  370. package/src/static-site-generator/static-export-context.d.ts +30 -0
  371. package/src/static-site-generator/static-export-context.js +0 -0
  372. package/src/static-site-generator/static-site-generator.d.ts +43 -25
  373. package/src/static-site-generator/static-site-generator.js +381 -106
  374. package/src/types/internal-types.d.ts +39 -13
  375. package/src/types/public-types.d.ts +289 -52
  376. package/src/utils/ecopages-route-info.d.ts +26 -0
  377. package/src/utils/ecopages-route-info.js +26 -0
  378. package/src/utils/html-escaping.d.ts +7 -0
  379. package/src/utils/html-escaping.js +5 -1
  380. package/src/utils/parse-cli-args.d.ts +2 -0
  381. package/src/utils/parse-cli-args.js +6 -0
  382. package/src/utils/path-pattern.d.ts +23 -0
  383. package/src/utils/path-pattern.js +27 -0
  384. package/src/utils/server-utils.module.d.ts +3 -2
  385. package/src/utils/server-utils.module.js +5 -6
  386. package/src/utils/static-file-extensions.d.ts +12 -0
  387. package/src/utils/static-file-extensions.js +48 -0
  388. package/src/watchers/project-watcher-ignore.d.ts +11 -0
  389. package/src/watchers/project-watcher-ignore.js +16 -0
  390. package/src/watchers/project-watcher.d.ts +29 -6
  391. package/src/watchers/project-watcher.js +146 -34
  392. package/src/watchers/project-watcher.test-helpers.js +5 -5
  393. package/src/adapters/shared/define-api-handler.d.ts +0 -25
  394. package/src/adapters/shared/define-api-handler.js +0 -15
  395. package/src/adapters/shared/hmr-entrypoint-registrar.js +0 -87
  396. package/src/adapters/shared/server-adapter.js +0 -436
  397. package/src/adapters/shared/server-static-builder.js +0 -162
  398. package/src/adapters/shared/shared-hmr-manager.d.ts +0 -59
  399. package/src/adapters/shared/shared-hmr-manager.js +0 -241
  400. package/src/build/build-manifest.d.ts +0 -33
  401. package/src/build/rolldown-dev-build-adapter.d.ts +0 -82
  402. package/src/build/rolldown-dev-build-adapter.js +0 -166
  403. package/src/build/runtime-build-executor.d.ts +0 -21
  404. package/src/build/runtime-build-executor.js +0 -19
  405. package/src/build/runtime-build-output-normalizer.d.ts +0 -3
  406. package/src/build/runtime-build-output-normalizer.js +0 -111
  407. package/src/hmr/hmr.postcss.test.e2e.js +0 -31
  408. package/src/hmr/hmr.test.e2e.js +0 -43
  409. package/src/route-renderer/orchestration/declared-ownership-graph.d.ts +0 -18
  410. package/src/route-renderer/orchestration/declared-ownership-graph.js +0 -34
  411. package/src/route-renderer/orchestration/ownership-planning.service.d.ts +0 -24
  412. package/src/route-renderer/orchestration/ownership-planning.service.js +0 -63
  413. package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.d.ts +0 -91
  414. package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.js +0 -170
  415. package/src/route-renderer/orchestration/route-render-orchestrator.js +0 -577
  416. package/src/route-renderer/orchestration/template-serialization.d.ts +0 -38
  417. package/src/route-renderer/orchestration/template-serialization.js +0 -45
  418. /package/src/adapters/shared/{explicit-static-render-preparation.js → http/explicit-static-render-preparation.js} +0 -0
  419. /package/src/adapters/shared/{runtime-host.d.ts → runtime/runtime-host.d.ts} +0 -0
  420. /package/src/adapters/shared/{runtime-host.js → runtime/runtime-host.js} +0 -0
  421. /package/src/adapters/shared/{static-preview-host.js → runtime/static-preview-host.js} +0 -0
  422. /package/src/build/{browser-runtime-manifest.d.ts → browser/browser-runtime-manifest.d.ts} +0 -0
  423. /package/src/build/{browser-runtime-manifest.js → browser/browser-runtime-manifest.js} +0 -0
  424. /package/src/build/{browser-runtime-plugin-helpers.d.ts → browser/browser-runtime-plugin-helpers.d.ts} +0 -0
  425. /package/src/build/{browser-runtime-plugin-helpers.js → browser/browser-runtime-plugin-helpers.js} +0 -0
  426. /package/src/build/{build-types.js → contracts/build-contracts.js} +0 -0
  427. /package/src/build/{build-types.d.ts → contracts/build-types.d.ts} +0 -0
  428. /package/src/build/{server-side-css-shim-plugin.d.ts → rolldown/server-side-css-shim-plugin.d.ts} +0 -0
  429. /package/src/build/{server-side-css-shim-plugin.js → rolldown/server-side-css-shim-plugin.js} +0 -0
  430. /package/src/build/{serialized-build-executor.js → runtime/serialized-build-executor.js} +0 -0
  431. /package/src/{hmr/hmr.postcss.test.e2e.d.ts → client/navigation-scripts/navigation-scripts.test.browser.d.ts} +0 -0
  432. /package/src/{hmr/hmr.test.e2e.d.ts → client/scroll.test.browser.d.ts} +0 -0
  433. /package/src/route-renderer/orchestration/{processed-asset-dedupe.js → page-browser-graph/processed-asset-dedupe.js} +0 -0
@@ -1,10 +1,10 @@
1
1
  import path from "node:path";
2
- import { appLogger } from "../../global/app-logger.js";
3
- import { PageRequestCacheCoordinator } from "../../services/cache/page-request-cache-coordinator.service.js";
4
- import { ServerUtils } from "../../utils/server-utils.module.js";
2
+ import { appLogger } from "../../../global/app-logger.js";
3
+ import { PageRequestCacheCoordinator } from "../../../services/cache/page-request-cache-coordinator.service.js";
4
+ import { ServerUtils } from "../../../utils/server-utils.module.js";
5
5
  import { FileRouteMiddlewarePipeline } from "./file-route-middleware-pipeline.js";
6
- import { LocalsAccessError } from "../../errors/locals-access-error.js";
7
- import { isDevelopmentRuntime } from "../../utils/runtime.js";
6
+ import { LocalsAccessError } from "../../../errors/locals-access-error.js";
7
+ import { isDevelopmentRuntime } from "../../../utils/runtime.js";
8
8
  class FileSystemResponseMatcher {
9
9
  appConfig;
10
10
  assetPrefix;
@@ -37,15 +37,15 @@ class FileSystemResponseMatcher {
37
37
  * @returns Static file response or rendered 404 response.
38
38
  */
39
39
  async handleNoMatch(requestUrl) {
40
- const isStaticFileRequest = ServerUtils.hasKnownExtension(requestUrl);
40
+ const isStaticFileRequest = ServerUtils.hasKnownStaticExtension(requestUrl);
41
41
  if (!isStaticFileRequest) {
42
- return this.renderCustomNotFoundResponse();
42
+ return this.renderCustomNotFoundResponseOrServerError(requestUrl);
43
43
  }
44
44
  const relativeUrl = requestUrl.startsWith("/") ? requestUrl.slice(1) : requestUrl;
45
45
  const filePath = path.join(this.assetPrefix, relativeUrl);
46
46
  const contentType = ServerUtils.getContentType(filePath);
47
47
  const response = await this.fileSystemResponseFactory.createFileResponse(filePath, contentType);
48
- return response ?? this.renderCustomNotFoundResponse();
48
+ return response ?? this.renderCustomNotFoundResponseOrServerError(requestUrl);
49
49
  }
50
50
  /**
51
51
  * Handles a matched file-system page route.
@@ -100,17 +100,13 @@ class FileSystemResponseMatcher {
100
100
  return error;
101
101
  }
102
102
  if (error instanceof LocalsAccessError) {
103
- return new Response(error.message, {
104
- status: 500,
105
- headers: { "Content-Type": "text/plain; charset=utf-8" }
106
- });
107
- }
108
- if (error instanceof Error) {
109
- if (isDevelopmentRuntime() || appLogger.isDebugEnabled()) {
110
- appLogger.error(`[FileSystemResponseMatcher] ${error.message} at ${match.requestedPathname}`);
111
- }
103
+ return await this.createInternalServerErrorResponse(error.message, match.requestedPathname, error);
112
104
  }
113
- return this.renderCustomNotFoundResponse();
105
+ return await this.createInternalServerErrorResponse(
106
+ error instanceof Error ? error.message : "Internal Server Error",
107
+ match.requestedPathname,
108
+ error
109
+ );
114
110
  }
115
111
  }
116
112
  /**
@@ -118,19 +114,105 @@ class FileSystemResponseMatcher {
118
114
  * when the page template cannot be resolved.
119
115
  */
120
116
  async renderCustomNotFoundResponse() {
121
- const error404TemplatePath = this.appConfig.absolutePaths.error404TemplatePath;
117
+ return this.renderCustomErrorPageResponse({
118
+ templatePath: this.appConfig.absolutePaths.error404TemplatePath,
119
+ label: "404",
120
+ createDefaultResponse: () => this.fileSystemResponseFactory.createDefaultNotFoundResponse(),
121
+ createHtmlResponse: (body) => this.fileSystemResponseFactory.createHtmlNotFoundResponse(body)
122
+ });
123
+ }
124
+ /**
125
+ * Renders the app-owned custom 500 page, falling back to the default text 500
126
+ * when the page template cannot be resolved.
127
+ */
128
+ async renderCustomServerErrorResponse(error) {
129
+ return this.renderCustomErrorPageResponse({
130
+ templatePath: this.appConfig.absolutePaths.error500TemplatePath,
131
+ label: "500",
132
+ props: this.buildServerErrorPageProps(error),
133
+ createDefaultResponse: () => this.fileSystemResponseFactory.createDefaultServerErrorResponse(),
134
+ createHtmlResponse: (body) => this.fileSystemResponseFactory.createHtmlServerErrorResponse(body)
135
+ });
136
+ }
137
+ /**
138
+ * Builds development-only error details for the custom 500 page.
139
+ * @remarks Production omits these fields so stacks are not serialized into HTML.
140
+ */
141
+ buildServerErrorPageProps(error) {
142
+ if (!isDevelopmentRuntime()) {
143
+ return void 0;
144
+ }
145
+ if (error instanceof Error) {
146
+ return {
147
+ message: error.message,
148
+ stack: error.stack
149
+ };
150
+ }
151
+ return {
152
+ message: String(error)
153
+ };
154
+ }
155
+ async renderCustomErrorPageResponse({
156
+ templatePath,
157
+ label,
158
+ props,
159
+ createDefaultResponse,
160
+ createHtmlResponse
161
+ }) {
162
+ let routeRenderer;
122
163
  try {
123
- const routeRenderer = this.routeRendererFactory.getPageRenderer(error404TemplatePath);
124
- const result = await routeRenderer.execute({
125
- file: error404TemplatePath
126
- });
127
- return this.fileSystemResponseFactory.createHtmlNotFoundResponse(result.body);
164
+ routeRenderer = this.routeRendererFactory.getPageRenderer(templatePath);
128
165
  } catch {
129
166
  appLogger.debug(
130
- "Custom 404 template not found, falling back to default 404 response",
131
- error404TemplatePath
167
+ `Custom ${label} template not found, falling back to default ${label} response`,
168
+ templatePath
169
+ );
170
+ return createDefaultResponse();
171
+ }
172
+ const result = await routeRenderer.execute({
173
+ file: templatePath,
174
+ props
175
+ });
176
+ return createHtmlResponse(result.body);
177
+ }
178
+ async renderCustomNotFoundResponseOrServerError(pathname) {
179
+ try {
180
+ return await this.renderCustomNotFoundResponse();
181
+ } catch (error) {
182
+ if (error instanceof Response) {
183
+ return error;
184
+ }
185
+ return await this.createInternalServerErrorResponse(
186
+ error instanceof Error ? error.message : "Internal Server Error",
187
+ pathname,
188
+ error
189
+ );
190
+ }
191
+ }
192
+ /**
193
+ * Logs the original render failure, then tries the custom 500 page once.
194
+ * @remarks Any failure while rendering the custom 500 page falls back to the
195
+ * default plain-text response and never re-enters the custom page path.
196
+ * In development the thrown error's `message` and `stack` are passed into the
197
+ * custom 500 page props.
198
+ */
199
+ async createInternalServerErrorResponse(message, pathname, error) {
200
+ if (isDevelopmentRuntime() || appLogger.isDebugEnabled()) {
201
+ appLogger.error(`[FileSystemResponseMatcher] ${message} at ${pathname}`, error);
202
+ } else {
203
+ appLogger.error(`[FileSystemResponseMatcher] Render error at ${pathname}`, error);
204
+ }
205
+ try {
206
+ return await this.renderCustomServerErrorResponse(error);
207
+ } catch (serverErrorPageError) {
208
+ if (serverErrorPageError instanceof Response) {
209
+ return serverErrorPageError;
210
+ }
211
+ appLogger.error(
212
+ `[FileSystemResponseMatcher] Custom 500 template failed at ${pathname}`,
213
+ serverErrorPageError
132
214
  );
133
- return this.fileSystemResponseFactory.createDefaultNotFoundResponse();
215
+ return this.fileSystemResponseFactory.createDefaultServerErrorResponse();
134
216
  }
135
217
  }
136
218
  async createExecutionPlan(match, request) {
@@ -0,0 +1,5 @@
1
+ export type MiddlewareHandler<TContext> = (context: TContext, next: () => Promise<Response>) => Response | Promise<Response>;
2
+ /**
3
+ * Runs an onion middleware chain and invokes the terminal handler when the chain completes.
4
+ */
5
+ export declare function runMiddlewareChain<TContext>(middleware: readonly MiddlewareHandler<TContext>[], context: TContext, terminal: () => Promise<Response>): Promise<Response>;
@@ -0,0 +1,17 @@
1
+ async function runMiddlewareChain(middleware, context, terminal) {
2
+ if (middleware.length === 0) {
3
+ return terminal();
4
+ }
5
+ let index = 0;
6
+ const executeNext = async () => {
7
+ if (index < middleware.length) {
8
+ const current = middleware[index++];
9
+ return await current(context, executeNext);
10
+ }
11
+ return terminal();
12
+ };
13
+ return executeNext();
14
+ }
15
+ export {
16
+ runMiddlewareChain
17
+ };
@@ -1,5 +1,5 @@
1
- import type { ApiHandler, ApiHandlerContext, Middleware, RouteGroupBuilder, RouteOptions } from '../../types/public-types.js';
2
- import { AbstractApplicationAdapter, type ApplicationAdapterOptions, type RouteGroupDefinition, type RouteHandler } from '../abstract/application-adapter.js';
1
+ import type { ApiHandler, ApiHandlerContext, Middleware, RouteGroupBuilder, RouteOptions } from '../../../types/public-types.js';
2
+ import { AbstractApplicationAdapter, type ApplicationAdapterOptions, type RouteGroupDefinition, type RouteHandler } from '../../abstract/application-adapter.js';
3
3
  export declare abstract class SharedApplicationAdapter<TOptions extends ApplicationAdapterOptions = ApplicationAdapterOptions, TServer = any, TRequest extends Request = Request> extends AbstractApplicationAdapter<TOptions, TServer, TRequest> {
4
4
  protected register<P extends string, TContext extends ApiHandlerContext<TRequest, TServer> = ApiHandlerContext<TRequest, TServer>>(path: P, method: ApiHandler['method'], handler: RouteHandler<TRequest, TServer, TContext>, options?: RouteOptions<TRequest, TServer, TContext>): this;
5
5
  get<P extends string, TContext extends ApiHandlerContext<TRequest, TServer> = ApiHandlerContext<TRequest, TServer>>(path: P, handler: RouteHandler<TRequest, TServer, TContext>, options?: RouteOptions<TRequest, TServer, TContext>): this;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AbstractApplicationAdapter
3
- } from "../abstract/application-adapter.js";
3
+ } from "../../abstract/application-adapter.js";
4
4
  class SharedApplicationAdapter extends AbstractApplicationAdapter {
5
5
  register(path, method, handler, options) {
6
6
  return this.addRouteHandler(path, method, handler, options?.middleware, options?.schema);
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copies a source public directory into the runtime dist dir, skipping unchanged files.
3
+ *
4
+ * Dev restarts call this on every boot; byte comparison avoids rewriting identical assets.
5
+ */
6
+ export declare function copyRuntimePublicDirIfChanged(sourceDir: string, destinationDir: string): void;
@@ -0,0 +1,24 @@
1
+ import { readdirSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { fileSystem } from "@ecopages/file-system";
4
+ function copyRuntimePublicDirIfChanged(sourceDir, destinationDir) {
5
+ fileSystem.ensureDir(destinationDir);
6
+ for (const entry of readdirSync(sourceDir, { withFileTypes: true })) {
7
+ const sourcePath = path.join(sourceDir, entry.name);
8
+ const destinationPath = path.join(destinationDir, entry.name);
9
+ if (entry.isDirectory()) {
10
+ copyRuntimePublicDirIfChanged(sourcePath, destinationPath);
11
+ continue;
12
+ }
13
+ if (!entry.isFile()) {
14
+ continue;
15
+ }
16
+ if (fileSystem.exists(destinationPath) && Buffer.compare(fileSystem.readFileAsBuffer(sourcePath), fileSystem.readFileAsBuffer(destinationPath)) === 0) {
17
+ continue;
18
+ }
19
+ fileSystem.copyFile(sourcePath, destinationPath);
20
+ }
21
+ }
22
+ export {
23
+ copyRuntimePublicDirIfChanged
24
+ };
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Detects whether a thrown error indicates the requested port is already in
3
+ * use.
4
+ *
5
+ * @remarks
6
+ * Matches Node's `code: 'EADDRINUSE'` and Bun's surface, where the error
7
+ * carries the same `code` plus a human-readable message such as
8
+ * `"Failed to start server. Is port 3000 in use?"`. Older Bun builds that do
9
+ * not set `.code` are covered by a fallback match on `syscall === 'listen'`
10
+ * plus the message shape.
11
+ */
12
+ export declare function isPortInUseError(error: unknown): boolean;
13
+ /**
14
+ * Probes whether a TCP port is currently bindable from this process. Uses a
15
+ * short-lived Node `net.Server` so both Node and Bun can run it via their
16
+ * Node-compatible core.
17
+ *
18
+ * @remarks
19
+ * A successful probe only guarantees the port was free at probe time; callers
20
+ * must still handle EADDRINUSE when they actually bind, since release races
21
+ * can flip the answer between probe and bind.
22
+ */
23
+ export declare function isPortAvailable(port: number, hostname?: string): Promise<boolean>;
24
+ /**
25
+ * Default interactive prompt. Asks a yes/no question on stdin/stdout and
26
+ * auto-approves (returns `true`) after `timeoutMs` with no input.
27
+ *
28
+ * @returns `true` when the user accepted (or timed out), `false` when they declined.
29
+ */
30
+ export type PromptFunction = (message: string, timeoutMs: number) => Promise<boolean>;
31
+ export interface PortManagerOptions {
32
+ /**
33
+ * Bind factory. Should throw on EADDRINUSE (or return `null`/`undefined`
34
+ * when it declines without a port collision). Returning a non-null port
35
+ * marks the bind as successful.
36
+ */
37
+ startOnPort: (port: number) => Promise<number | null | undefined>;
38
+ /** Emits the "moved to port X" warning when the bound port differs from the preferred port. */
39
+ warn?: (message: string) => void;
40
+ /** Infers a free port to display in the prompt. Defaults to {@link isPortAvailable}. */
41
+ probePort?: (port: number) => Promise<boolean>;
42
+ /** Custom prompter. Defaults to a readline-based yes/no prompt on the process stdio. */
43
+ prompt?: PromptFunction;
44
+ /** Enables the prompt flow at all. Defaults to `process.stdin.isTTY && process.stdout.isTTY`. */
45
+ interactive?: boolean;
46
+ /** Auto-approve timeout (ms) for the prompt. Defaults to 10000. */
47
+ autoApproveMs?: number;
48
+ /** Maximum port offset to scan when falling back. Defaults to 20. */
49
+ maxPortOffset?: number;
50
+ /** Retry attempts for the same port before declaring it taken. Defaults to 2. */
51
+ releaseRaceRetries?: number;
52
+ /** Backoff between same-port retries. Defaults to 100 ms. */
53
+ releaseRaceDelayMs?: number;
54
+ }
55
+ export interface BindPortOptions {
56
+ /** Port the caller would prefer to bind. */
57
+ preferredPort: number;
58
+ /**
59
+ * Whether the caller permits moving to the next free port automatically when
60
+ * the preferred port is busy and no interactive prompt is available
61
+ * (non-TTY / CI). Explicit ports that fall back silently in CI would surprise
62
+ * operators, so this is honoured by the non-interactive path only.
63
+ */
64
+ allowPortFallback: boolean;
65
+ }
66
+ /**
67
+ * Owns preview-port assignment: probing, race-release retries, fallback, and
68
+ * an optional interactive auto-approve prompt.
69
+ *
70
+ * @remarks
71
+ * Single-process API. The manager does not cache ports across calls; each
72
+ * `bind()` runs fresh from the preferred port.
73
+ */
74
+ export declare class PortManager {
75
+ private readonly startOnPort;
76
+ private readonly warn;
77
+ private readonly probePort;
78
+ private readonly prompt;
79
+ private readonly interactive;
80
+ private readonly autoApproveMs;
81
+ private readonly maxPortOffset;
82
+ private readonly releaseRaceRetries;
83
+ private readonly releaseRaceDelayMs;
84
+ constructor(options: PortManagerOptions);
85
+ /**
86
+ * Binds the preview server to the preferred port.
87
+ *
88
+ * @remarks
89
+ * When the preferred port is free, binds it directly — no prompt, no
90
+ * fallback. The interactive prompt only fires on a genuine EADDRINUSE
91
+ * collision (TTY runs), and auto-approves after
92
+ * {@link PortManagerOptions.autoApproveMs}. In non-interactive (CI) runs,
93
+ * the manager falls back silently only when
94
+ * {@link BindPortOptions.allowPortFallback} is true (the default-port
95
+ * path); pinned ports rethrow EADDRINUSE so Docker-style fixed-port
96
+ * deployments fail loudly instead of silently moving.
97
+ */
98
+ bind(options: BindPortOptions): Promise<number | null>;
99
+ private shouldFallback;
100
+ private fallForward;
101
+ /**
102
+ * Attempts to bind via {@link PortManagerOptions.startOnPort} on `port`,
103
+ * retrying EADDRINUSE collisions up to
104
+ * {@link PortManagerOptions.releaseRaceRetries} to ride through TIME_WAIT
105
+ * race release.
106
+ *
107
+ * @remarks
108
+ * Only EADDRINUSE is retryable. Any other error is rethrown synchronously
109
+ * rather than swallowed as a soft "port taken" result, so a misconfigured
110
+ * factory surfaces loudly instead of causing a silent fallback. A `null`
111
+ * return from the factory (no throw) is reported as `factory-refused`, not
112
+ * conflated with a real collision.
113
+ */
114
+ private tryPort;
115
+ private findNextFreePort;
116
+ }
@@ -0,0 +1,196 @@
1
+ import { createServer as createNetServer } from "node:net";
2
+ import { createInterface } from "node:readline";
3
+ function isPortInUseError(error) {
4
+ if (!(error instanceof Error) && (typeof error !== "object" || error === null)) {
5
+ return false;
6
+ }
7
+ const maybeErr = error;
8
+ const code = typeof maybeErr.code === "string" || typeof maybeErr.code === "number" ? String(maybeErr.code) : void 0;
9
+ const syscall = typeof maybeErr.syscall === "string" ? maybeErr.syscall : void 0;
10
+ const message = error instanceof Error ? error.message : String(maybeErr.message ?? "");
11
+ if (code === "EADDRINUSE") {
12
+ return true;
13
+ }
14
+ if (message.includes("EADDRINUSE")) {
15
+ return true;
16
+ }
17
+ if (syscall === "listen" && /is port \d+ in use\??/i.test(message)) {
18
+ return true;
19
+ }
20
+ return false;
21
+ }
22
+ function sleep(ms) {
23
+ return new Promise((resolve) => setTimeout(resolve, ms));
24
+ }
25
+ function isPortAvailable(port, hostname = "127.0.0.1") {
26
+ return new Promise((resolve) => {
27
+ const tester = createNetServer();
28
+ tester.once("error", () => resolve(false));
29
+ tester.once("listening", () => {
30
+ tester.close(() => resolve(true));
31
+ });
32
+ tester.listen(port, hostname);
33
+ });
34
+ }
35
+ function createDefaultPrompt(stdin, stdout) {
36
+ return async (message, timeoutMs) => {
37
+ stdout.write(`${message} `);
38
+ return await new Promise((resolve) => {
39
+ const rl = createInterface({ input: stdin, output: void 0, terminal: false });
40
+ let settled = false;
41
+ const finish = (value) => {
42
+ if (settled) {
43
+ return;
44
+ }
45
+ settled = true;
46
+ clearTimeout(timer);
47
+ rl.close();
48
+ stdout.write("\n");
49
+ resolve(value);
50
+ };
51
+ const timer = setTimeout(() => finish(true), timeoutMs);
52
+ rl.once("line", (line) => {
53
+ const answer = line.trim().toLowerCase();
54
+ if (answer === "" || answer === "y" || answer === "yes") {
55
+ finish(true);
56
+ } else {
57
+ finish(false);
58
+ }
59
+ });
60
+ rl.once("close", () => finish(true));
61
+ });
62
+ };
63
+ }
64
+ const PREVIEW_PORT_RELEASE_RACE_RETRIES = 2;
65
+ const PREVIEW_PORT_FALLBACK_ATTEMPTS = 20;
66
+ const PREVIEW_PORT_RELEASE_RACE_DELAY_MS = 100;
67
+ const PREVIEW_PORT_AUTO_APPROVE_MS = 1e4;
68
+ class PortManager {
69
+ startOnPort;
70
+ warn;
71
+ probePort;
72
+ prompt;
73
+ interactive;
74
+ autoApproveMs;
75
+ maxPortOffset;
76
+ releaseRaceRetries;
77
+ releaseRaceDelayMs;
78
+ constructor(options) {
79
+ this.startOnPort = options.startOnPort;
80
+ this.warn = options.warn;
81
+ this.probePort = options.probePort ?? isPortAvailable;
82
+ this.maxPortOffset = options.maxPortOffset ?? PREVIEW_PORT_FALLBACK_ATTEMPTS - 1;
83
+ this.releaseRaceRetries = options.releaseRaceRetries ?? PREVIEW_PORT_RELEASE_RACE_RETRIES;
84
+ this.releaseRaceDelayMs = options.releaseRaceDelayMs ?? PREVIEW_PORT_RELEASE_RACE_DELAY_MS;
85
+ this.autoApproveMs = options.autoApproveMs ?? PREVIEW_PORT_AUTO_APPROVE_MS;
86
+ this.interactive = typeof options.interactive === "boolean" ? options.interactive : Boolean(typeof process !== "undefined" && process.stdin?.isTTY && process.stdout?.isTTY);
87
+ if (options.prompt) {
88
+ this.prompt = options.prompt;
89
+ } else if (this.interactive) {
90
+ this.prompt = createDefaultPrompt(process.stdin, process.stdout);
91
+ } else {
92
+ this.prompt = void 0;
93
+ }
94
+ }
95
+ /**
96
+ * Binds the preview server to the preferred port.
97
+ *
98
+ * @remarks
99
+ * When the preferred port is free, binds it directly — no prompt, no
100
+ * fallback. The interactive prompt only fires on a genuine EADDRINUSE
101
+ * collision (TTY runs), and auto-approves after
102
+ * {@link PortManagerOptions.autoApproveMs}. In non-interactive (CI) runs,
103
+ * the manager falls back silently only when
104
+ * {@link BindPortOptions.allowPortFallback} is true (the default-port
105
+ * path); pinned ports rethrow EADDRINUSE so Docker-style fixed-port
106
+ * deployments fail loudly instead of silently moving.
107
+ */
108
+ async bind(options) {
109
+ const preferredPort = options.preferredPort;
110
+ const firstAttempt = await this.tryPort(preferredPort);
111
+ if (firstAttempt.status === "bound") {
112
+ return firstAttempt.boundPort;
113
+ }
114
+ if (firstAttempt.status === "factory-refused") {
115
+ return null;
116
+ }
117
+ await this.shouldFallback(preferredPort, options.allowPortFallback, firstAttempt.error);
118
+ return await this.fallForward(preferredPort);
119
+ }
120
+ async shouldFallback(preferredPort, allowPortFallback, error) {
121
+ if (this.interactive && this.prompt) {
122
+ const nextFree = await this.findNextFreePort(preferredPort);
123
+ const nextFreeSuffix = typeof nextFree === "number" ? ` (next free: ${nextFree})` : "";
124
+ const autoApproveHint = `auto-yes in ${Math.round(this.autoApproveMs / 1e3)}s`;
125
+ const message = `[@ecopages/core] Port ${preferredPort} is already in use${nextFreeSuffix}. Bind there instead? [Y/n] (${autoApproveHint})`;
126
+ const accepted = await this.prompt(message, this.autoApproveMs);
127
+ if (!accepted) {
128
+ throw error;
129
+ }
130
+ return;
131
+ }
132
+ if (!allowPortFallback) {
133
+ throw error;
134
+ }
135
+ }
136
+ async fallForward(preferredPort) {
137
+ for (let offset = 1; offset <= this.maxPortOffset; offset += 1) {
138
+ const candidatePort = preferredPort + offset;
139
+ const attempt = await this.tryPort(candidatePort);
140
+ if (attempt.status === "bound") {
141
+ this.warn?.(
142
+ `Port ${preferredPort} is in use; preview serving on port ${attempt.boundPort} instead. Pin the preview port with --port or ECOPAGES_PORT when a fixed binding is required.`
143
+ );
144
+ return attempt.boundPort;
145
+ }
146
+ }
147
+ return null;
148
+ }
149
+ /**
150
+ * Attempts to bind via {@link PortManagerOptions.startOnPort} on `port`,
151
+ * retrying EADDRINUSE collisions up to
152
+ * {@link PortManagerOptions.releaseRaceRetries} to ride through TIME_WAIT
153
+ * race release.
154
+ *
155
+ * @remarks
156
+ * Only EADDRINUSE is retryable. Any other error is rethrown synchronously
157
+ * rather than swallowed as a soft "port taken" result, so a misconfigured
158
+ * factory surfaces loudly instead of causing a silent fallback. A `null`
159
+ * return from the factory (no throw) is reported as `factory-refused`, not
160
+ * conflated with a real collision.
161
+ */
162
+ async tryPort(port) {
163
+ for (let attempt = 0; attempt < this.releaseRaceRetries; attempt += 1) {
164
+ try {
165
+ const bound = await this.startOnPort(port);
166
+ if (bound) {
167
+ return { status: "bound", boundPort: bound };
168
+ }
169
+ return { status: "factory-refused" };
170
+ } catch (error) {
171
+ if (!isPortInUseError(error)) {
172
+ throw error;
173
+ }
174
+ if (attempt === this.releaseRaceRetries - 1) {
175
+ return { status: "port-in-use", error };
176
+ }
177
+ await sleep(this.releaseRaceDelayMs);
178
+ }
179
+ }
180
+ return { status: "factory-refused" };
181
+ }
182
+ async findNextFreePort(startPort) {
183
+ for (let offset = 1; offset <= this.maxPortOffset; offset += 1) {
184
+ const candidate = startPort + offset;
185
+ if (await this.probePort(candidate)) {
186
+ return candidate;
187
+ }
188
+ }
189
+ return null;
190
+ }
191
+ }
192
+ export {
193
+ PortManager,
194
+ isPortAvailable,
195
+ isPortInUseError
196
+ };
@@ -1,5 +1,5 @@
1
- import type { RenderContext } from '../../types/public-types.js';
2
- import type { AnyIntegrationPlugin } from '../../plugins/integration-plugin.js';
1
+ import type { RenderContext } from '../../../types/public-types.js';
2
+ import type { AnyIntegrationPlugin } from '../../../plugins/integration-plugin.js';
3
3
  export interface CreateRenderContextOptions {
4
4
  integrations: AnyIntegrationPlugin[];
5
5
  rendererModules?: unknown;
@@ -1,5 +1,6 @@
1
1
  import { fileURLToPath } from "node:url";
2
- import { invariant } from "../../utils/invariant.js";
2
+ import { invariant } from "../../../utils/invariant.js";
3
+ import { createBodyResponse } from "../http/create-body-response.js";
3
4
  function resolveServerModulePath(filePath) {
4
5
  return filePath instanceof URL ? fileURLToPath(filePath) : filePath;
5
6
  }
@@ -64,25 +65,15 @@ function createRenderContext(options) {
64
65
  return renderer.renderToResponse(view, mergedProps, ctx);
65
66
  },
66
67
  json(data, responseOptions) {
67
- const headers = new Headers({ "Content-Type": "application/json; charset=utf-8" });
68
- if (responseOptions?.headers) {
69
- const incomingHeaders = new Headers(responseOptions.headers);
70
- incomingHeaders.forEach((value, key) => headers.set(key, value));
71
- }
72
- return new Response(JSON.stringify(data), {
73
- status: responseOptions?.status ?? 200,
74
- headers
68
+ return createBodyResponse("json", data, {
69
+ status: responseOptions?.status,
70
+ headers: responseOptions?.headers
75
71
  });
76
72
  },
77
73
  html(content, responseOptions) {
78
- const headers = new Headers({ "Content-Type": "text/html; charset=utf-8" });
79
- if (responseOptions?.headers) {
80
- const incomingHeaders = new Headers(responseOptions.headers);
81
- incomingHeaders.forEach((value, key) => headers.set(key, value));
82
- }
83
- return new Response(content, {
84
- status: responseOptions?.status ?? 200,
85
- headers
74
+ return createBodyResponse("html", content, {
75
+ status: responseOptions?.status,
76
+ headers: responseOptions?.headers
86
77
  });
87
78
  }
88
79
  };
@@ -1,14 +1,15 @@
1
- import type { ReturnParseCliArgs } from '../../utils/parse-cli-args.js';
2
- import type { EcoPagesAppConfig } from '../../types/internal-types.js';
1
+ import type { ReturnParseCliArgs } from '../../../utils/parse-cli-args.js';
2
+ import type { EcoPagesAppConfig } from '../../../types/internal-types.js';
3
3
  export type RuntimeBinding = {
4
4
  preferredPort: number;
5
5
  preferredHostname: string;
6
6
  runtimeOrigin: string;
7
7
  serveOptions: Record<string, unknown>;
8
8
  watch: boolean;
9
+ /** Whether preview may bind to the next free port when the preferred port is busy. */
10
+ allowPortFallback: boolean;
9
11
  };
10
12
  export type StaticRuntimeMode = {
11
- requiresFetchRuntime: boolean;
12
13
  canBuildWithoutRuntimeServer: boolean;
13
14
  };
14
15
  export declare function resolveServeRuntimeOrigin(serveOptions: {
@@ -1,4 +1,4 @@
1
- import { DEFAULT_ECOPAGES_HOSTNAME, DEFAULT_ECOPAGES_PORT } from "../../config/constants.js";
1
+ import { DEFAULT_ECOPAGES_HOSTNAME, DEFAULT_ECOPAGES_PORT } from "../../../config/constants.js";
2
2
  function normalizeOriginHostname(hostname) {
3
3
  if (hostname.includes(":") && !hostname.startsWith("[") && !hostname.endsWith("]")) {
4
4
  return `[${hostname}]`;
@@ -12,11 +12,13 @@ function resolveServeRuntimeOrigin(serveOptions) {
12
12
  }
13
13
  function resolveRuntimeBinding(options) {
14
14
  const env = options.env ?? process.env;
15
+ const portExplicitlyConfigured = options.cliArgs.port !== void 0 || Boolean(env.ECOPAGES_PORT) || options.serverOptions?.port !== void 0;
15
16
  const preferredPort = options.cliArgs.port ?? (env.ECOPAGES_PORT ? Number(env.ECOPAGES_PORT) : void 0) ?? DEFAULT_ECOPAGES_PORT;
16
17
  const preferredHostname = options.cliArgs.hostname ?? env.ECOPAGES_HOSTNAME ?? DEFAULT_ECOPAGES_HOSTNAME;
17
18
  return {
18
19
  preferredPort,
19
20
  preferredHostname,
21
+ allowPortFallback: !portExplicitlyConfigured,
20
22
  runtimeOrigin: resolveServeRuntimeOrigin({
21
23
  hostname: preferredHostname,
22
24
  port: preferredPort
@@ -30,13 +32,8 @@ function resolveRuntimeBinding(options) {
30
32
  };
31
33
  }
32
34
  function resolveStaticRuntimeMode(options) {
33
- const requiresFetchRuntime = options.appConfig.integrations.some(
34
- (integration) => integration.staticBuildStep === "fetch"
35
- );
36
- const canBuildWithoutRuntimeServer = (options.cliArgs.build || options.cliArgs.preview) && !requiresFetchRuntime;
37
35
  return {
38
- requiresFetchRuntime,
39
- canBuildWithoutRuntimeServer
36
+ canBuildWithoutRuntimeServer: options.cliArgs.build || options.cliArgs.preview
40
37
  };
41
38
  }
42
39
  export {