@ecopages/core 0.2.0-beta.2 → 0.2.0-beta.21

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 (273) hide show
  1. package/README.md +1 -1
  2. package/package.json +163 -3
  3. package/src/adapters/abstract/application-adapter.d.ts +104 -5
  4. package/src/adapters/abstract/application-adapter.js +125 -1
  5. package/src/adapters/abstract/server-adapter.d.ts +6 -2
  6. package/src/adapters/abstract/ws-pattern-matcher.d.ts +60 -0
  7. package/src/adapters/abstract/ws-pattern-matcher.js +61 -0
  8. package/src/adapters/bun/client-bridge.d.ts +1 -0
  9. package/src/adapters/bun/client-bridge.js +3 -0
  10. package/src/adapters/bun/create-app.d.ts +6 -4
  11. package/src/adapters/bun/create-app.js +65 -43
  12. package/src/adapters/bun/server-adapter.d.ts +90 -22
  13. package/src/adapters/bun/server-adapter.js +266 -84
  14. package/src/adapters/bun/static-preview-host.js +25 -20
  15. package/src/adapters/create-app.d.ts +13 -11
  16. package/src/adapters/create-app.js +2 -51
  17. package/src/adapters/index.d.ts +1 -1
  18. package/src/adapters/index.js +1 -2
  19. package/src/adapters/node/create-app.d.ts +5 -1
  20. package/src/adapters/node/create-app.js +51 -12
  21. package/src/adapters/node/node-client-bridge.d.ts +1 -0
  22. package/src/adapters/node/node-client-bridge.js +3 -0
  23. package/src/adapters/node/server-adapter-dependencies.js +4 -0
  24. package/src/adapters/node/server-adapter.d.ts +62 -20
  25. package/src/adapters/node/server-adapter.js +160 -131
  26. package/src/adapters/node/static-content-server.d.ts +1 -0
  27. package/src/adapters/node/static-content-server.js +10 -2
  28. package/src/adapters/node/static-preview-host.js +27 -12
  29. package/src/adapters/shared/bun-user-websocket-lifecycle.d.ts +22 -0
  30. package/src/adapters/shared/bun-user-websocket-lifecycle.js +96 -0
  31. package/src/adapters/shared/copy-runtime-public-dir.d.ts +6 -0
  32. package/src/adapters/shared/copy-runtime-public-dir.js +24 -0
  33. package/src/adapters/shared/fs-server-response-matcher.d.ts +2 -0
  34. package/src/adapters/shared/fs-server-response-matcher.js +40 -18
  35. package/src/adapters/shared/hmr-entrypoint-registrar.d.ts +21 -30
  36. package/src/adapters/shared/hmr-entrypoint-registrar.js +49 -54
  37. package/src/adapters/shared/hmr-html-response.d.ts +1 -1
  38. package/src/adapters/shared/hmr-html-response.js +4 -1
  39. package/src/adapters/shared/node-http-websocket-upgrades.d.ts +21 -0
  40. package/src/adapters/shared/node-http-websocket-upgrades.js +100 -0
  41. package/src/adapters/shared/port-manager.d.ts +116 -0
  42. package/src/adapters/shared/port-manager.js +196 -0
  43. package/src/adapters/shared/runtime-app-bootstrap.d.ts +2 -1
  44. package/src/adapters/shared/runtime-app-bootstrap.js +3 -6
  45. package/src/adapters/shared/runtime-server-lifecycle.d.ts +46 -0
  46. package/src/adapters/shared/runtime-server-lifecycle.js +50 -0
  47. package/src/adapters/shared/server-adapter.d.ts +2 -1
  48. package/src/adapters/shared/server-adapter.js +13 -6
  49. package/src/adapters/shared/server-route-handler.d.ts +4 -1
  50. package/src/adapters/shared/server-route-handler.js +5 -2
  51. package/src/adapters/shared/server-static-builder.d.ts +23 -32
  52. package/src/adapters/shared/server-static-builder.js +100 -73
  53. package/src/adapters/shared/shared-hmr-manager.d.ts +45 -11
  54. package/src/adapters/shared/shared-hmr-manager.js +204 -58
  55. package/src/adapters/shared/static-preview-host.d.ts +5 -0
  56. package/src/adapters/shared/websocket-lifecycle.d.ts +24 -0
  57. package/src/adapters/shared/websocket-lifecycle.js +55 -0
  58. package/src/build/README.md +77 -14
  59. package/src/build/app-build-manifest-runtime.d.ts +9 -0
  60. package/src/build/app-build-manifest-runtime.js +87 -0
  61. package/src/build/build-adapter.d.ts +17 -319
  62. package/src/build/build-adapter.js +28 -94
  63. package/src/build/build-contracts.d.ts +97 -0
  64. package/src/build/build-contracts.js +0 -0
  65. package/src/build/build-input-fingerprint.d.ts +28 -0
  66. package/src/build/build-input-fingerprint.js +31 -0
  67. package/src/build/build-profile-options.d.ts +7 -0
  68. package/src/build/build-profile-options.js +37 -0
  69. package/src/build/build-runtime.d.ts +24 -0
  70. package/src/build/build-runtime.js +65 -0
  71. package/src/build/deduping-build-executor.d.ts +28 -0
  72. package/src/build/deduping-build-executor.js +56 -0
  73. package/src/build/jsx-ownership-plugins.d.ts +24 -0
  74. package/src/build/jsx-ownership-plugins.js +41 -0
  75. package/src/build/pages-unified-graph-build.d.ts +31 -0
  76. package/src/build/pages-unified-graph-build.js +206 -0
  77. package/src/build/parallel-build-executor.d.ts +21 -0
  78. package/src/build/parallel-build-executor.js +52 -0
  79. package/src/build/production-build-cache.d.ts +20 -0
  80. package/src/build/production-build-cache.js +63 -0
  81. package/src/build/rolldown-adapter-helpers.d.ts +3 -6
  82. package/src/build/rolldown-adapter-helpers.js +71 -6
  83. package/src/build/rolldown-build-adapter.d.ts +2 -6
  84. package/src/build/rolldown-build-adapter.js +3 -3
  85. package/src/build/rolldown-build-invocation-metrics.d.ts +12 -0
  86. package/src/build/rolldown-build-invocation-metrics.js +43 -0
  87. package/src/build/rolldown-plugin-bridge.d.ts +15 -1
  88. package/src/build/rolldown-plugin-bridge.js +20 -5
  89. package/src/build/rolldown-source-transform-pass.d.ts +15 -0
  90. package/src/build/rolldown-source-transform-pass.js +58 -0
  91. package/src/build/runtime-build-executor.d.ts +8 -15
  92. package/src/build/runtime-build-executor.js +12 -15
  93. package/src/build/runtime-build-output-normalizer.d.ts +7 -0
  94. package/src/build/runtime-build-output-normalizer.js +94 -2
  95. package/src/build/server-entry-build-cache.d.ts +44 -0
  96. package/src/build/server-entry-build-cache.js +161 -0
  97. package/src/client/navigation-scripts/classification.d.ts +16 -0
  98. package/src/client/navigation-scripts/classification.js +41 -0
  99. package/src/client/navigation-scripts/index.d.ts +3 -0
  100. package/src/client/navigation-scripts/index.js +23 -0
  101. package/src/client/navigation-scripts/navigation-scripts.test.browser.js +65 -0
  102. package/src/client/navigation-scripts/registry.d.ts +11 -0
  103. package/src/client/navigation-scripts/registry.js +12 -0
  104. package/src/client/navigation-scripts/rerun-queue.d.ts +37 -0
  105. package/src/client/navigation-scripts/rerun-queue.js +73 -0
  106. package/src/client/scroll.d.ts +17 -0
  107. package/src/client/scroll.js +25 -0
  108. package/src/client/scroll.test.browser.js +37 -0
  109. package/src/client/view-transitions.d.ts +16 -0
  110. package/src/client/view-transitions.js +63 -0
  111. package/src/config/config-builder.d.ts +12 -7
  112. package/src/config/config-builder.js +12 -9
  113. package/src/dev/client-bridge-registry.d.ts +5 -0
  114. package/src/dev/client-bridge-registry.js +15 -0
  115. package/src/dev/dev-client-ownership.d.ts +7 -0
  116. package/src/dev/dev-client-ownership.js +6 -0
  117. package/src/dev/hmr-manager-registry.d.ts +8 -0
  118. package/src/dev/hmr-manager-registry.js +15 -0
  119. package/src/dev/host-runtime.d.ts +3 -0
  120. package/src/dev/host-runtime.js +7 -0
  121. package/src/dev/runtime-server-started-message.d.ts +2 -0
  122. package/src/dev/runtime-server-started-message.js +6 -0
  123. package/src/eco/README.md +11 -0
  124. package/src/eco/eco-declared-component.d.ts +14 -0
  125. package/src/eco/eco-declared-component.js +16 -0
  126. package/src/eco/eco.browser.js +5 -6
  127. package/src/eco/eco.js +5 -6
  128. package/src/eco/eco.types.d.ts +2 -2
  129. package/src/eco/page-layout-normalization.d.ts +21 -0
  130. package/src/eco/page-layout-normalization.js +59 -0
  131. package/src/errors/index.d.ts +1 -0
  132. package/src/errors/index.js +7 -1
  133. package/src/errors/undeclared-component-dependency-error.d.ts +11 -0
  134. package/src/errors/undeclared-component-dependency-error.js +17 -0
  135. package/src/hmr/client/hmr-runtime.js +5 -2
  136. package/src/hmr/hmr-entrypoint-output.d.ts +43 -0
  137. package/src/hmr/hmr-entrypoint-output.js +53 -0
  138. package/src/hmr/hmr-strategy.d.ts +15 -0
  139. package/src/hmr/hmr-strategy.js +19 -0
  140. package/src/hmr/strategies/js-hmr-strategy.d.ts +3 -5
  141. package/src/hmr/strategies/js-hmr-strategy.js +67 -19
  142. package/src/hmr/strategies/server-rendered-template-hmr-strategy.d.ts +17 -0
  143. package/src/hmr/strategies/server-rendered-template-hmr-strategy.js +29 -0
  144. package/src/integrations/ghtml/ghtml-renderer.d.ts +2 -6
  145. package/src/integrations/ghtml/ghtml-renderer.js +2 -51
  146. package/src/integrations/ghtml/ghtml.plugin.d.ts +3 -16
  147. package/src/integrations/ghtml/ghtml.plugin.js +7 -14
  148. package/src/plugins/define-integration.d.ts +26 -0
  149. package/src/plugins/define-integration.js +19 -0
  150. package/src/plugins/eco-component-meta-plugin.js +5 -8
  151. package/src/plugins/foreign-jsx-override-plugin.js +4 -6
  152. package/src/plugins/integration-plugin.d.ts +19 -9
  153. package/src/plugins/integration-plugin.js +7 -4
  154. package/src/plugins/jsx-import-source.utils.d.ts +8 -0
  155. package/src/plugins/jsx-import-source.utils.js +26 -0
  156. package/src/plugins/processor.d.ts +19 -4
  157. package/src/plugins/processor.js +22 -4
  158. package/src/plugins/source-transform.d.ts +31 -0
  159. package/src/plugins/source-transform.js +23 -1
  160. package/src/route-renderer/GRAPH.md +8 -8
  161. package/src/route-renderer/README.md +30 -28
  162. package/src/route-renderer/orchestration/component-graph-collectors.d.ts +10 -0
  163. package/src/route-renderer/orchestration/component-graph-collectors.js +143 -0
  164. package/src/route-renderer/orchestration/component-graph.d.ts +36 -0
  165. package/src/route-renderer/orchestration/component-graph.js +98 -0
  166. package/src/route-renderer/orchestration/component-render-context.d.ts +3 -10
  167. package/src/route-renderer/orchestration/component-render-context.js +3 -1
  168. package/src/route-renderer/orchestration/declared-ownership-graph.d.ts +1 -18
  169. package/src/route-renderer/orchestration/declared-ownership-graph.js +5 -31
  170. package/src/route-renderer/orchestration/document-shell-render.service.d.ts +90 -0
  171. package/src/route-renderer/orchestration/document-shell-render.service.js +120 -0
  172. package/src/route-renderer/orchestration/foreign-subtree-execution.service.d.ts +59 -29
  173. package/src/route-renderer/orchestration/foreign-subtree-execution.service.js +164 -35
  174. package/src/route-renderer/orchestration/global-injector-assets.service.d.ts +7 -0
  175. package/src/route-renderer/orchestration/global-injector-assets.service.js +32 -0
  176. package/src/route-renderer/orchestration/integration-renderer.d.ts +18 -54
  177. package/src/route-renderer/orchestration/integration-renderer.js +113 -195
  178. package/src/route-renderer/orchestration/integration-route-render-adapter.d.ts +38 -0
  179. package/src/route-renderer/orchestration/integration-route-render-adapter.js +27 -0
  180. package/src/route-renderer/orchestration/layout-shell-props.service.d.ts +20 -0
  181. package/src/route-renderer/orchestration/layout-shell-props.service.js +31 -0
  182. package/src/route-renderer/orchestration/ownership-validation.service.d.ts +5 -0
  183. package/src/route-renderer/orchestration/ownership-validation.service.js +29 -1
  184. package/src/route-renderer/orchestration/page-browser-graph-contribution.loader.d.ts +9 -0
  185. package/src/route-renderer/orchestration/page-browser-graph-contribution.loader.js +7 -0
  186. package/src/route-renderer/orchestration/page-browser-graph.service.d.ts +25 -0
  187. package/src/route-renderer/orchestration/page-browser-graph.service.js +174 -0
  188. package/src/route-renderer/orchestration/render-output.utils.d.ts +2 -0
  189. package/src/route-renderer/orchestration/render-output.utils.js +4 -0
  190. package/src/route-renderer/orchestration/route-html-finalization.service.d.ts +17 -0
  191. package/src/route-renderer/orchestration/route-html-finalization.service.js +26 -0
  192. package/src/route-renderer/orchestration/route-prepared-options.builder.d.ts +26 -0
  193. package/src/route-renderer/orchestration/route-prepared-options.builder.js +54 -0
  194. package/src/route-renderer/orchestration/route-prepared-options.utils.d.ts +4 -0
  195. package/src/route-renderer/orchestration/route-prepared-options.utils.js +33 -0
  196. package/src/route-renderer/orchestration/route-render-orchestrator.d.ts +8 -39
  197. package/src/route-renderer/orchestration/route-render-orchestrator.js +53 -461
  198. package/src/route-renderer/orchestration/string-markup-renderer.d.ts +14 -0
  199. package/src/route-renderer/orchestration/string-markup-renderer.js +55 -0
  200. package/src/route-renderer/page-loading/component-dependency-collection.js +5 -2
  201. package/src/router/client/link-intent.d.ts +11 -21
  202. package/src/router/client/link-intent.js +10 -0
  203. package/src/router/client/link-intent.test.browser.js +12 -1
  204. package/src/router/client/link-navigation-policy.d.ts +45 -0
  205. package/src/router/client/link-navigation-policy.js +101 -0
  206. package/src/router/client/link-navigation-policy.test.browser.d.ts +1 -0
  207. package/src/router/client/link-navigation-policy.test.browser.js +92 -0
  208. package/src/router/client/navigation-coordinator.d.ts +1 -1
  209. package/src/router/client/navigation-coordinator.js +12 -2
  210. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.d.ts +1 -0
  211. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.js +1 -0
  212. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.d.ts +4 -2
  213. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.js +27 -7
  214. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.d.ts +0 -1
  215. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.js +18 -15
  216. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.js +17 -3
  217. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.d.ts +0 -3
  218. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +2 -31
  219. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.d.ts +0 -3
  220. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +2 -30
  221. package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.d.ts +2 -0
  222. package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.js +43 -0
  223. package/src/services/assets/browser-bundle.service.d.ts +3 -1
  224. package/src/services/assets/browser-bundle.service.js +17 -5
  225. package/src/services/html/html-transformer.service.d.ts +1 -1
  226. package/src/services/html/html-transformer.service.js +4 -4
  227. package/src/services/invalidation/development-invalidation.service.d.ts +20 -2
  228. package/src/services/invalidation/development-invalidation.service.js +56 -2
  229. package/src/services/module-loading/README.md +49 -0
  230. package/src/services/module-loading/app-server-module-transpiler.service.js +5 -17
  231. package/src/services/module-loading/page-module-import.service.d.ts +5 -1
  232. package/src/services/module-loading/page-module-import.service.js +96 -45
  233. package/src/services/module-loading/route-module-build-cache-registry.d.ts +24 -0
  234. package/src/services/module-loading/route-module-build-cache-registry.js +37 -0
  235. package/src/services/module-loading/route-module-build-cache.d.ts +4 -0
  236. package/src/services/module-loading/route-module-build-cache.js +38 -0
  237. package/src/services/module-loading/route-module-build-cache.store.d.ts +57 -0
  238. package/src/services/module-loading/route-module-build-cache.store.js +207 -0
  239. package/src/services/module-loading/route-module-build-manifest.d.ts +61 -0
  240. package/src/services/module-loading/route-module-build-manifest.js +116 -0
  241. package/src/services/module-loading/route-module-dependency-hasher.d.ts +81 -0
  242. package/src/services/module-loading/route-module-dependency-hasher.js +122 -0
  243. package/src/services/module-loading/server-module-transpiler.service.js +1 -1
  244. package/src/static-site-generator/README.md +33 -0
  245. package/src/static-site-generator/static-build-invalidation.d.ts +10 -0
  246. package/src/static-site-generator/static-build-invalidation.js +59 -0
  247. package/src/static-site-generator/static-export-context.d.ts +22 -0
  248. package/src/static-site-generator/static-export-context.js +0 -0
  249. package/src/static-site-generator/static-site-generator.d.ts +17 -20
  250. package/src/static-site-generator/static-site-generator.js +188 -85
  251. package/src/types/internal-types.d.ts +16 -9
  252. package/src/types/public-types.d.ts +144 -40
  253. package/src/utils/parse-cli-args.d.ts +2 -0
  254. package/src/utils/parse-cli-args.js +6 -0
  255. package/src/utils/server-utils.module.d.ts +3 -2
  256. package/src/utils/server-utils.module.js +5 -6
  257. package/src/utils/static-file-extensions.d.ts +12 -0
  258. package/src/utils/static-file-extensions.js +48 -0
  259. package/src/watchers/project-watcher-ignore.d.ts +11 -0
  260. package/src/watchers/project-watcher-ignore.js +16 -0
  261. package/src/watchers/project-watcher.d.ts +26 -3
  262. package/src/watchers/project-watcher.js +132 -30
  263. package/src/watchers/project-watcher.test-helpers.js +5 -5
  264. package/src/build/rolldown-dev-build-adapter.d.ts +0 -82
  265. package/src/build/rolldown-dev-build-adapter.js +0 -166
  266. package/src/hmr/hmr.postcss.test.e2e.js +0 -31
  267. package/src/hmr/hmr.test.e2e.js +0 -43
  268. package/src/route-renderer/orchestration/ownership-planning.service.d.ts +0 -24
  269. package/src/route-renderer/orchestration/ownership-planning.service.js +0 -63
  270. package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.d.ts +0 -91
  271. package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.js +0 -170
  272. /package/src/{hmr/hmr.postcss.test.e2e.d.ts → client/navigation-scripts/navigation-scripts.test.browser.d.ts} +0 -0
  273. /package/src/{hmr/hmr.test.e2e.d.ts → client/scroll.test.browser.d.ts} +0 -0
@@ -1,7 +1,6 @@
1
1
  import type { Readable } from 'node:stream';
2
2
  import type { ApiResponseBuilder } from '../adapters/shared/api-response.js';
3
3
  import type { BuildExecutor } from '../build/build-adapter.js';
4
- import type { EcoBuildPlugin } from '../build/build-types.js';
5
4
  import type { ForeignChildRuntime } from '../route-renderer/orchestration/component-render-context.js';
6
5
  import type { EcoPageComponent } from '../eco/eco.types.js';
7
6
  import type { EcoPagesAppConfig } from './internal-types.js';
@@ -14,6 +13,82 @@ import type { EntrypointDependencyGraph } from '../services/runtime-state/entryp
14
13
  export type { EcoPagesAppConfig } from './internal-types.js';
15
14
  export type { EcoPageComponent } from '../eco/eco.types.js';
16
15
  export type { ProcessedAsset } from '../services/assets/asset-processing-service/assets.types.js';
16
+ /**
17
+ * Runtime-agnostic incoming WebSocket frame.
18
+ *
19
+ * Both Bun and Node `ws` deliver text and binary frames; this discriminated
20
+ * union lets handlers deal with both without runtime-specific casts.
21
+ */
22
+ export type IncomingWebSocketMessage = {
23
+ readonly kind: 'text';
24
+ readonly text: string;
25
+ } | {
26
+ readonly kind: 'binary';
27
+ readonly data: Uint8Array;
28
+ };
29
+ /**
30
+ * Runtime-agnostic outgoing WebSocket payload.
31
+ *
32
+ * Strings are sent as text frames. Anything binary-shaped is sent as binary
33
+ * frames. `Blob` is included for cross-runtime parity and is normalized to a
34
+ * binary frame by each adapter.
35
+ */
36
+ export type OutgoingWebSocketMessage = string | Uint8Array | ArrayBuffer | ArrayBufferView | Blob;
37
+ /**
38
+ * Close event delivered to `onClose` after a connection terminates.
39
+ */
40
+ export interface WebSocketCloseInfo {
41
+ readonly code: number;
42
+ readonly reason: string;
43
+ readonly wasClean: boolean;
44
+ }
45
+ /**
46
+ * Input passed to a WebSocket handler's `context()` factory.
47
+ *
48
+ * Adapters call `context()` exactly once per accepted upgrade. The returned
49
+ * value becomes `socket.context` and is shared by all lifecycle hooks.
50
+ */
51
+ export interface WebSocketContextFactoryInput<TParams extends Record<string, string> = Record<string, string>> {
52
+ readonly request: Request;
53
+ readonly kind: string;
54
+ readonly params: TParams;
55
+ readonly search: Readonly<Record<string, string>>;
56
+ readonly locals?: RequestLocals;
57
+ }
58
+ /**
59
+ * Runtime-agnostic WebSocket socket view exposed to handlers.
60
+ *
61
+ * Framework-owned fields:
62
+ * - `kind`: the registered route pattern (e.g. '/ws/chat/:roomId')
63
+ * - `params`: dynamic segments captured at match time
64
+ * - `search`: query string, always string-typed
65
+ *
66
+ * App-owned field:
67
+ * - `context`: returned by the handler's `context()` factory
68
+ */
69
+ export interface EcopagesSocket<TContext = unknown, TParams extends Record<string, string> = Record<string, string>> {
70
+ readonly kind: string;
71
+ readonly params: TParams;
72
+ readonly search: Readonly<Record<string, string>>;
73
+ readonly context: TContext;
74
+ send(message: OutgoingWebSocketMessage): void;
75
+ sendStream(stream: ReadableStream<Uint8Array>): Promise<void>;
76
+ close(code?: number, reason?: string): void;
77
+ }
78
+ /**
79
+ * Connection-lifecycle handler object.
80
+ *
81
+ * All hooks are optional. `context()` is the one-time initializer that
82
+ * produces the per-connection state shared by the lifecycle hooks. Returning
83
+ * a rejected promise from `context()` aborts the upgrade.
84
+ */
85
+ export interface EcopagesWebSocketHandler<TContext = unknown, TParams extends Record<string, string> = Record<string, string>> {
86
+ context?(input: WebSocketContextFactoryInput<TParams>): TContext | Promise<TContext>;
87
+ onConnect?(socket: EcopagesSocket<TContext, TParams>): void | Promise<void>;
88
+ onMessage?(socket: EcopagesSocket<TContext, TParams>, message: IncomingWebSocketMessage): void | Promise<void>;
89
+ onClose?(socket: EcopagesSocket<TContext, TParams>, event: WebSocketCloseInfo): void | Promise<void>;
90
+ onError?(socket: EcopagesSocket<TContext, TParams>, error: unknown): void | Promise<void>;
91
+ }
17
92
  import type { StandardSchema, StandardSchemaResult, StandardSchemaSuccessResult, StandardSchemaFailureResult, StandardSchemaIssue, InferOutput } from '../services/validation/standard-schema.types.js';
18
93
  export type { StandardSchema, StandardSchemaResult, StandardSchemaSuccessResult, StandardSchemaFailureResult, StandardSchemaIssue, InferOutput, ForeignChildRuntime, };
19
94
  export type InteractionEventsString = ScriptsInjectorInteractionEventsString;
@@ -99,10 +174,6 @@ export interface DefaultHmrContext {
99
174
  * Directory where HMR bundles are written.
100
175
  */
101
176
  getDistDir(): string;
102
- /**
103
- * Build plugins to use during bundling.
104
- */
105
- getPlugins(): EcoBuildPlugin[];
106
177
  /**
107
178
  * Absolute path to the source directory.
108
179
  */
@@ -167,6 +238,14 @@ export interface IClientBridge {
167
238
  error(message: string): void;
168
239
  subscriberCount: number;
169
240
  }
241
+ /**
242
+ * Verified HMR entrypoint artifact produced by registration.
243
+ */
244
+ export interface ResolvedHmrEntrypoint {
245
+ sourcePath: string;
246
+ outputPath: string;
247
+ outputUrl: string;
248
+ }
170
249
  /**
171
250
  * Interface for the HMR Manager.
172
251
  * Used by integration plugins to register entrypoints and strategies.
@@ -188,19 +267,19 @@ export interface IHmrManager {
188
267
  * framework integration. Unlike `registerEntrypoint()`, it may use the generic
189
268
  * script bundling path.
190
269
  */
191
- registerScriptEntrypoint(entrypointPath: string): Promise<string>;
270
+ registerScriptEntrypoint(entrypointPath: string): Promise<ResolvedHmrEntrypoint>;
192
271
  /**
193
272
  * Registers a custom HMR strategy.
194
273
  */
195
274
  registerStrategy(strategy: HmrStrategy): void;
196
- /**
197
- * Sets the build plugins to use during bundling.
198
- */
199
- setPlugins(plugins: EcoBuildPlugin[]): void;
200
275
  /**
201
276
  * Enables or disables HMR.
202
277
  */
203
278
  setEnabled(enabled: boolean): void;
279
+ /**
280
+ * Stops active HMR watchers and releases dev-time resources.
281
+ */
282
+ stop(): void;
204
283
  /**
205
284
  * Returns whether HMR is enabled.
206
285
  */
@@ -213,6 +292,10 @@ export interface IHmrManager {
213
292
  * Gets the output URL for a registered entrypoint.
214
293
  */
215
294
  getOutputUrl(entrypointPath: string): string | undefined;
295
+ /**
296
+ * Returns an existing emitted HMR script artifact without registering it.
297
+ */
298
+ getResolvedScriptOutput?(entrypointPath: string): ResolvedHmrEntrypoint | undefined;
216
299
  /**
217
300
  * Gets the map of watched files.
218
301
  */
@@ -221,10 +304,6 @@ export interface IHmrManager {
221
304
  * Gets the HMR dist directory.
222
305
  */
223
306
  getDistDir(): string;
224
- /**
225
- * Gets the build plugins.
226
- */
227
- getPlugins(): EcoBuildPlugin[];
228
307
  /**
229
308
  * Gets the default HMR context.
230
309
  */
@@ -247,8 +326,21 @@ export type EcoComponentDependencies = {
247
326
  * to express explicit module imports for client bundles.
248
327
  */
249
328
  modules?: string[];
250
- components?: EcoComponent[];
329
+ /**
330
+ * Child components whose assets and foreign-child graph are collected transitively.
331
+ * Each entry must be an `eco.component()`, `eco.layout()`, or `eco.html()` result
332
+ * with plugin-injected `config.__eco` metadata.
333
+ */
334
+ components?: EcoDeclaredComponent[];
251
335
  };
336
+ /**
337
+ * Component returned from `eco.component()`, `eco.layout()`, or `eco.html()`.
338
+ *
339
+ * @remarks
340
+ * Used for `dependencies.components` and eco factory return types. Plugin-injected
341
+ * `config.__eco` is enforced at runtime via `isEcoDeclaredComponent()`, not by this alias.
342
+ */
343
+ export type EcoDeclaredComponent<P = any, R = any> = EcoComponent<P, R>;
252
344
  export type EcoPagesElement = string | Promise<string>;
253
345
  /**
254
346
  * Serializable child payloads accepted by cross-integration deferred rendering.
@@ -314,11 +406,13 @@ export type EcoComponentConfig = {
314
406
  * );
315
407
  *
316
408
  * // Page using the layout
317
- * const MyPage = () => <h1>Hello</h1>;
318
- * MyPage.config = { layout: Layout };
409
+ * const MyPage = eco.page({ layout: Layout, render: () => <h1>Hello</h1> });
319
410
  * ```
320
411
  */
321
- layout?: EcoPageLayoutComponent<any>;
412
+ /** Normalized outer→inner layout stack from `eco.page({ layout: [...] })`. */
413
+ layouts?: EcoDeclaredComponent[];
414
+ /** Layout entries retained for per-tier prop factories. */
415
+ layoutEntries?: EcoPageLayoutEntry[];
322
416
  dependencies?: EcoComponentDependencies;
323
417
  /**
324
418
  * Internal: Resolved lazy scripts grouped by trigger.
@@ -442,6 +536,36 @@ export interface HtmlTemplateProps<T = EcoPagesElement> extends PageHeadProps<T>
442
536
  headContent?: T;
443
537
  pageProps: Record<string, unknown>;
444
538
  }
539
+ /**
540
+ * Request-scoped context available to layout prop factories on `eco.page`.
541
+ */
542
+ export type LayoutPropsContext = {
543
+ params?: Record<string, string>;
544
+ query?: Record<string, string>;
545
+ locals?: RequestLocals;
546
+ };
547
+ /**
548
+ * One layout tier in a page layout stack (outer→inner).
549
+ */
550
+ export type EcoPageLayoutEntry<E = EcoPagesElement> = {
551
+ component: EcoDeclaredComponent<any, E>;
552
+ props?: (context: LayoutPropsContext) => Record<string, unknown>;
553
+ };
554
+ /**
555
+ * Layout declaration accepted by `eco.page()`.
556
+ *
557
+ * @remarks
558
+ * Array order is outer→inner, matching Next.js App Router segment nesting.
559
+ */
560
+ export type EcoPageLayoutSpec<E = EcoPagesElement> = EcoDeclaredComponent<any, E> | EcoPageLayoutEntry<E>;
561
+ /**
562
+ * One or more layout tiers for `eco.page({ layout })`.
563
+ *
564
+ * @remarks
565
+ * When an array, order is **outer → inner** (outermost layout wraps all inner tiers).
566
+ * Normalized at factory time to `config.layouts` and `config.layoutEntries`.
567
+ */
568
+ export type EcoPageLayouts<E = EcoPagesElement> = EcoPageLayoutSpec<E> | EcoPageLayoutSpec<E>[];
445
569
  /**
446
570
  * Layout components accepted by pages.
447
571
  *
@@ -659,7 +783,9 @@ export type IntegrationRendererRenderOptions<C = EcoPagesElement> = RouteRendere
659
783
  metadata: PageMetadataProps;
660
784
  HtmlTemplate: EcoHtmlComponent<C>;
661
785
  Page: EcoComponent<PageProps, C>;
786
+ Layouts?: EcoDeclaredComponent[];
662
787
  Layout?: EcoPageLayoutComponent<any>;
788
+ layoutEntries?: EcoPageLayoutEntry[];
663
789
  dependencies?: EcoComponentDependencies;
664
790
  resolvedDependencies: ProcessedAsset[];
665
791
  pagePackage?: PagePackageResult;
@@ -667,7 +793,6 @@ export type IntegrationRendererRenderOptions<C = EcoPagesElement> = RouteRendere
667
793
  pageProps?: Record<string, unknown>;
668
794
  cacheStrategy?: CacheStrategy;
669
795
  pageLocals?: RequestLocals;
670
- ownershipPlan?: OwnershipPlan;
671
796
  };
672
797
  /**
673
798
  * Structured page asset package produced after dependency resolution.
@@ -746,27 +871,6 @@ export interface OwnershipValidationError {
746
871
  integrationName?: string;
747
872
  }
748
873
  export type OwnershipPlanNodeSource = 'route' | 'page' | 'layout' | 'html-template' | 'dependency';
749
- export interface IntegrationOwnership {
750
- integrationName: string;
751
- componentId: string;
752
- componentFile?: string;
753
- isPageEntry: boolean;
754
- isForeignToParent: boolean;
755
- }
756
- export interface OwnershipPlanNode {
757
- id: string;
758
- source: OwnershipPlanNodeSource;
759
- ownership: IntegrationOwnership;
760
- children: OwnershipPlanNode[];
761
- declaredDependenciesValid: boolean;
762
- }
763
- export interface OwnershipPlan {
764
- root: OwnershipPlanNode;
765
- rendererNames: string[];
766
- foreignEdgeCount: number;
767
- hasValidationErrors: boolean;
768
- validationErrors: OwnershipValidationError[];
769
- }
770
874
  export type ForeignSubtreeAttachmentPolicy = {
771
875
  kind: 'none';
772
876
  } | {
@@ -13,6 +13,8 @@ export type ReturnParseCliArgs = {
13
13
  build: boolean;
14
14
  start: boolean;
15
15
  dev: boolean;
16
+ force: boolean;
17
+ serveOnly: boolean;
16
18
  port?: number;
17
19
  hostname?: string;
18
20
  reactFastRefresh?: boolean;
@@ -7,6 +7,8 @@ function getEmbeddedRuntimeCommandOptions() {
7
7
  build: false,
8
8
  start: !isDevelopment,
9
9
  dev: isDevelopment,
10
+ force: false,
11
+ serveOnly: false,
10
12
  port: void 0,
11
13
  hostname: void 0,
12
14
  reactFastRefresh: void 0
@@ -25,6 +27,8 @@ function parseCliArgs(options = {}) {
25
27
  dev: { type: "boolean" },
26
28
  preview: { type: "boolean" },
27
29
  build: { type: "boolean" },
30
+ force: { type: "boolean" },
31
+ "serve-only": { type: "boolean" },
28
32
  port: { type: "string" },
29
33
  hostname: { type: "string" },
30
34
  "react-fast-refresh": { type: "boolean" }
@@ -48,6 +52,8 @@ function parseCliArgs(options = {}) {
48
52
  build: isBuildCommand,
49
53
  start: isStartCommand,
50
54
  dev: isDevCommand,
55
+ force: !!values.force,
56
+ serveOnly: !!values["serve-only"] || process.env.ECOPAGES_PREVIEW_SERVE_ONLY === "true",
51
57
  port: values.port ? Number(values.port) : void 0,
52
58
  hostname: values.hostname,
53
59
  reactFastRefresh: values["react-fast-refresh"]
@@ -1,3 +1,4 @@
1
+ import { hasKnownStaticExtension } from './static-file-extensions.js';
1
2
  /**
2
3
  * Get the content type of a file based on its extension.
3
4
  * @param file - The file name.
@@ -9,11 +10,11 @@ export declare const getContentType: (file: string) => string;
9
10
  * @param file - The file name or path.
10
11
  * @returns true if the extension is recognized.
11
12
  */
12
- export declare const hasKnownExtension: (file: string) => boolean;
13
+ export { hasKnownStaticExtension } from './static-file-extensions.js';
13
14
  /**
14
15
  * A module for server utilities.
15
16
  */
16
17
  export declare const ServerUtils: {
17
18
  getContentType: (file: string) => string;
18
- hasKnownExtension: (file: string) => boolean;
19
+ hasKnownStaticExtension: typeof hasKnownStaticExtension;
19
20
  };
@@ -1,3 +1,4 @@
1
+ import { hasKnownStaticExtension } from "./static-file-extensions.js";
1
2
  const ContentTypeMap = /* @__PURE__ */ new Map([
2
3
  ["jpg", "image/jpeg"],
3
4
  ["jpeg", "image/jpeg"],
@@ -17,6 +18,7 @@ const ContentTypeMap = /* @__PURE__ */ new Map([
17
18
  ["ogv", "video/ogg"],
18
19
  ["mov", "video/quicktime"],
19
20
  ["txt", "text/plain"],
21
+ ["md", "text/markdown"],
20
22
  ["html", "text/html"],
21
23
  ["css", "text/css"],
22
24
  ["js", "text/javascript"],
@@ -41,16 +43,13 @@ const getContentType = (file) => {
41
43
  const extension = file.split(".").pop() || "txt";
42
44
  return ContentTypeMap.get(extension) || "text/plain";
43
45
  };
44
- const hasKnownExtension = (file) => {
45
- const extension = file.split(".").pop();
46
- return extension !== void 0 && ContentTypeMap.has(extension);
47
- };
46
+ import { hasKnownStaticExtension as hasKnownStaticExtension2 } from "./static-file-extensions.js";
48
47
  const ServerUtils = {
49
48
  getContentType,
50
- hasKnownExtension
49
+ hasKnownStaticExtension
51
50
  };
52
51
  export {
53
52
  ServerUtils,
54
53
  getContentType,
55
- hasKnownExtension
54
+ hasKnownStaticExtension2 as hasKnownStaticExtension
56
55
  };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Known static asset extensions served directly from disk.
3
+ *
4
+ * @remarks
5
+ * Keep this list aligned with server static-file handling and client routers
6
+ * that must bypass SPA navigation for same-origin asset links.
7
+ */
8
+ export declare const STATIC_FILE_EXTENSIONS: Set<string>;
9
+ /**
10
+ * Returns whether a path or filename ends with a known static asset extension.
11
+ */
12
+ export declare function hasKnownStaticExtension(fileOrPath: string): boolean;
@@ -0,0 +1,48 @@
1
+ const STATIC_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
2
+ "jpg",
3
+ "jpeg",
4
+ "png",
5
+ "gif",
6
+ "bmp",
7
+ "svg",
8
+ "tiff",
9
+ "webp",
10
+ "avif",
11
+ "ico",
12
+ "mp3",
13
+ "ogg",
14
+ "wav",
15
+ "mp4",
16
+ "webm",
17
+ "ogv",
18
+ "mov",
19
+ "txt",
20
+ "md",
21
+ "html",
22
+ "css",
23
+ "js",
24
+ "mjs",
25
+ "json",
26
+ "map",
27
+ "xml",
28
+ "webmanifest",
29
+ "wasm",
30
+ "csv",
31
+ "ttf",
32
+ "woff",
33
+ "woff2",
34
+ "otf",
35
+ "eot",
36
+ "gz",
37
+ "zip",
38
+ "pdf",
39
+ "doc"
40
+ ]);
41
+ function hasKnownStaticExtension(fileOrPath) {
42
+ const extension = fileOrPath.split(".").pop();
43
+ return extension !== void 0 && STATIC_FILE_EXTENSIONS.has(extension);
44
+ }
45
+ export {
46
+ STATIC_FILE_EXTENSIONS,
47
+ hasKnownStaticExtension
48
+ };
@@ -0,0 +1,11 @@
1
+ export type ProjectWatcherIgnorePaths = {
2
+ workDir: string;
3
+ distDir: string;
4
+ };
5
+ /**
6
+ * @remarks
7
+ * chokidar v4+ no longer treats glob strings in `ignored` as patterns. A path
8
+ * predicate keeps node_modules, VCS metadata, and scoped artifact dirs out of
9
+ * the watch tree without descending into symlinked monorepo node_modules.
10
+ */
11
+ export declare function createProjectWatcherIgnorePredicate(absolutePaths: ProjectWatcherIgnorePaths): (watchedPath: string) => boolean;
@@ -0,0 +1,16 @@
1
+ import path from "node:path";
2
+ function createProjectWatcherIgnorePredicate(absolutePaths) {
3
+ const ignoredPrefixes = [absolutePaths.workDir, absolutePaths.distDir];
4
+ return (watchedPath) => {
5
+ const segments = watchedPath.split(path.sep);
6
+ if (segments.includes("node_modules") || segments.includes(".git")) {
7
+ return true;
8
+ }
9
+ return ignoredPrefixes.some(
10
+ (prefix) => watchedPath === prefix || watchedPath.startsWith(`${prefix}${path.sep}`)
11
+ );
12
+ };
13
+ }
14
+ export {
15
+ createProjectWatcherIgnorePredicate
16
+ };
@@ -13,6 +13,10 @@ export interface ProjectWatcherConfig {
13
13
  refreshRouterRoutesCallback: () => Promise<void>;
14
14
  hmrManager: IHmrManager;
15
15
  bridge: IClientBridge;
16
+ /** When true, the host dev server owns browser dev-client bootstrap. */
17
+ hostOwnsDevClient?: boolean;
18
+ /** Delay before a change event is processed; 0 disables debouncing. */
19
+ changeDebounceMs?: number;
16
20
  }
17
21
  /**
18
22
  * ProjectWatcher handles file system changes for hot module replacement (HMR).
@@ -42,11 +46,14 @@ export declare class ProjectWatcher {
42
46
  private refreshRouterRoutesCallback;
43
47
  private hmrManager;
44
48
  private bridge;
49
+ private readonly hostOwnsDevClient;
45
50
  private readonly invalidationService;
51
+ private readonly changeDebounceMs;
46
52
  private watcher;
47
- private lastHandledChange;
53
+ private closed;
54
+ private pendingChangeEvents;
48
55
  private changeQueue;
49
- constructor({ config, refreshRouterRoutesCallback, hmrManager, bridge }: ProjectWatcherConfig);
56
+ constructor({ config, refreshRouterRoutesCallback, hmrManager, bridge, hostOwnsDevClient, changeDebounceMs, }: ProjectWatcherConfig);
50
57
  /**
51
58
  * Uncaches modules in the source directory to ensure fresh imports.
52
59
  * This is necessary for hot module replacement to work correctly.
@@ -55,6 +62,7 @@ export declare class ProjectWatcher {
55
62
  private uncacheModules;
56
63
  private isRouteSourceFile;
57
64
  private isIncludeSourceFile;
65
+ private requestBrowserReload;
58
66
  /**
59
67
  * Handles public directory file changes by copying only the changed file.
60
68
  * @param filePath - Absolute path of the changed file
@@ -70,7 +78,7 @@ export declare class ProjectWatcher {
70
78
  * Follows 5-rule priority:
71
79
  * 0. Public directory match? -> copy file and reload
72
80
  * 1. additionalWatchPaths match? -> reload
73
- * 2. Include template source? -> reload after processor notifications
81
+ * 2. Include template source? -> current-page refresh via HMR after processor notifications are deferred
74
82
  * 3. Processor-owned asset? -> processor already handled it via notification, skip HMR
75
83
  * 4. Otherwise -> HMR strategies
76
84
  *
@@ -84,6 +92,13 @@ export declare class ProjectWatcher {
84
92
  * @param event - The type of file system event
85
93
  */
86
94
  private handleFileChange;
95
+ private processFileChange;
96
+ /**
97
+ * Re-imports server modules before HMR broadcast so reload/refetch does not
98
+ * race stale in-memory imports or custom-element registry state.
99
+ */
100
+ private prewarmBeforeHmr;
101
+ private prewarmServerModuleImports;
87
102
  /**
88
103
  * Notifies all processors whose watch config matches the given file extension.
89
104
  * This is called before checking processor ownership so that dependency-only
@@ -133,4 +148,12 @@ export declare class ProjectWatcher {
133
148
  * rapid file changes efficiently.
134
149
  */
135
150
  createWatcherSubscription(): Promise<FSWatcher>;
151
+ /**
152
+ * Closes the active filesystem watcher subscription.
153
+ *
154
+ * @remarks
155
+ * Safe to call multiple times. Used when tearing down dev servers in tests
156
+ * and other short-lived Ecopages runtimes.
157
+ */
158
+ close(): Promise<void>;
136
159
  }