@ecopages/core 0.2.0-beta.4 → 0.2.0-beta.41

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 (611) hide show
  1. package/README.md +40 -9
  2. package/package.json +371 -33
  3. package/src/adapters/README.md +6 -2
  4. package/src/adapters/abstract/application-adapter.d.ts +115 -6
  5. package/src/adapters/abstract/application-adapter.js +261 -120
  6. package/src/adapters/abstract/router-adapter.js +12 -4
  7. package/src/adapters/abstract/segment-path-matcher.d.ts +6 -0
  8. package/src/adapters/abstract/segment-path-matcher.js +147 -0
  9. package/src/adapters/abstract/server-adapter.d.ts +16 -2
  10. package/src/adapters/abstract/server-adapter.js +22 -14
  11. package/src/adapters/abstract/ws-pattern-matcher.d.ts +12 -0
  12. package/src/adapters/abstract/ws-pattern-matcher.js +28 -0
  13. package/src/adapters/bun/bun-user-websocket-lifecycle.d.ts +22 -0
  14. package/src/adapters/bun/bun-user-websocket-lifecycle.js +93 -0
  15. package/src/adapters/bun/client-bridge.d.ts +1 -0
  16. package/src/adapters/bun/client-bridge.js +51 -47
  17. package/src/adapters/bun/create-app.d.ts +9 -6
  18. package/src/adapters/bun/create-app.js +171 -130
  19. package/src/adapters/bun/hmr-manager.d.ts +1 -1
  20. package/src/adapters/bun/hmr-manager.js +62 -57
  21. package/src/adapters/bun/index.d.ts +1 -1
  22. package/src/adapters/bun/index.js +2 -8
  23. package/src/adapters/bun/runtime-host.d.ts +1 -1
  24. package/src/adapters/bun/runtime-host.js +61 -54
  25. package/src/adapters/bun/server-adapter.d.ts +91 -41
  26. package/src/adapters/bun/server-adapter.js +566 -426
  27. package/src/adapters/bun/static-preview-host.d.ts +1 -1
  28. package/src/adapters/bun/static-preview-host.js +43 -41
  29. package/src/adapters/create-app.d.ts +13 -11
  30. package/src/adapters/create-app.js +11 -63
  31. package/src/adapters/index.d.ts +2 -2
  32. package/src/adapters/index.js +2 -8
  33. package/src/adapters/node/create-app.d.ts +8 -3
  34. package/src/adapters/node/create-app.js +126 -84
  35. package/src/adapters/node/http-request-bridge.js +147 -106
  36. package/src/adapters/node/node-client-bridge.d.ts +1 -0
  37. package/src/adapters/node/node-client-bridge.js +62 -61
  38. package/src/adapters/node/node-hmr-manager.d.ts +1 -1
  39. package/src/adapters/node/node-hmr-manager.js +58 -48
  40. package/src/adapters/node/runtime-host.d.ts +1 -1
  41. package/src/adapters/node/runtime-host.js +96 -89
  42. package/src/adapters/node/server-adapter-dependencies.js +18 -17
  43. package/src/adapters/node/server-adapter.d.ts +63 -23
  44. package/src/adapters/node/server-adapter.js +346 -297
  45. package/src/adapters/node/static-content-server.d.ts +1 -0
  46. package/src/adapters/node/static-content-server.js +172 -183
  47. package/src/adapters/node/static-preview-host.d.ts +1 -1
  48. package/src/adapters/node/static-preview-host.js +88 -64
  49. package/src/adapters/shared/hmr/dev-transform-entrypoint-registry.d.ts +16 -0
  50. package/src/adapters/shared/hmr/dev-transform-entrypoint-registry.js +32 -0
  51. package/src/adapters/shared/{hmr-html-response.d.ts → hmr/hmr-html-response.d.ts} +2 -2
  52. package/src/adapters/shared/hmr/hmr-html-response.js +50 -0
  53. package/src/adapters/shared/hmr/shared-hmr-manager.d.ts +92 -0
  54. package/src/adapters/shared/hmr/shared-hmr-manager.js +446 -0
  55. package/src/adapters/shared/http/api-request-pipeline.d.ts +23 -0
  56. package/src/adapters/shared/http/api-request-pipeline.js +132 -0
  57. package/src/adapters/shared/{api-response.d.ts → http/api-response.d.ts} +1 -1
  58. package/src/adapters/shared/http/api-response.js +79 -0
  59. package/src/adapters/shared/http/create-body-response.d.ts +12 -0
  60. package/src/adapters/shared/http/create-body-response.js +26 -0
  61. package/src/adapters/shared/http/define-api-handler.d.ts +90 -0
  62. package/src/adapters/shared/http/define-api-handler.js +49 -0
  63. package/src/adapters/shared/{explicit-static-render-preparation.d.ts → http/explicit-static-render-preparation.d.ts} +3 -3
  64. package/src/adapters/shared/http/explicit-static-render-preparation.js +29 -0
  65. package/src/adapters/shared/{explicit-static-route-matcher.d.ts → http/explicit-static-route-matcher.d.ts} +3 -9
  66. package/src/adapters/shared/http/explicit-static-route-matcher.js +59 -0
  67. package/src/adapters/shared/{file-route-middleware-pipeline.d.ts → http/file-route-middleware-pipeline.d.ts} +2 -2
  68. package/src/adapters/shared/http/file-route-middleware-pipeline.js +84 -0
  69. package/src/adapters/shared/{fs-server-response-factory.d.ts → http/fs-server-response-factory.d.ts} +7 -2
  70. package/src/adapters/shared/http/fs-server-response-factory.js +106 -0
  71. package/src/adapters/shared/{fs-server-response-matcher.d.ts → http/fs-server-response-matcher.d.ts} +25 -5
  72. package/src/adapters/shared/http/fs-server-response-matcher.js +258 -0
  73. package/src/adapters/shared/http/run-middleware-chain.d.ts +5 -0
  74. package/src/adapters/shared/http/run-middleware-chain.js +17 -0
  75. package/src/adapters/shared/{application-adapter.d.ts → runtime/application-adapter.d.ts} +2 -2
  76. package/src/adapters/shared/runtime/application-adapter.js +75 -0
  77. package/src/adapters/shared/runtime/collect-dev-prewarm-plan.d.ts +11 -0
  78. package/src/adapters/shared/runtime/collect-dev-prewarm-plan.js +29 -0
  79. package/src/adapters/shared/runtime/copy-runtime-public-dir.d.ts +6 -0
  80. package/src/adapters/shared/runtime/copy-runtime-public-dir.js +27 -0
  81. package/src/adapters/shared/runtime/dev-static-route-prewarm.d.ts +16 -0
  82. package/src/adapters/shared/runtime/dev-static-route-prewarm.js +66 -0
  83. package/src/adapters/shared/runtime/port-manager.d.ts +116 -0
  84. package/src/adapters/shared/runtime/port-manager.js +226 -0
  85. package/src/adapters/shared/{render-context.d.ts → runtime/render-context.d.ts} +2 -2
  86. package/src/adapters/shared/runtime/render-context.js +99 -0
  87. package/src/adapters/shared/{runtime-app-bootstrap.d.ts → runtime/runtime-app-bootstrap.d.ts} +4 -3
  88. package/src/adapters/shared/runtime/runtime-app-bootstrap.js +38 -0
  89. package/src/adapters/shared/runtime/runtime-server-lifecycle.d.ts +45 -0
  90. package/src/adapters/shared/runtime/runtime-server-lifecycle.js +71 -0
  91. package/src/adapters/shared/{server-adapter.d.ts → runtime/server-adapter.d.ts} +31 -50
  92. package/src/adapters/shared/runtime/server-adapter.js +301 -0
  93. package/src/adapters/shared/{server-route-handler.d.ts → runtime/server-route-handler.d.ts} +6 -33
  94. package/src/adapters/shared/runtime/server-route-handler.js +77 -0
  95. package/src/adapters/shared/{server-static-builder.d.ts → runtime/server-static-builder.d.ts} +27 -35
  96. package/src/adapters/shared/runtime/server-static-builder.js +172 -0
  97. package/src/adapters/shared/{static-preview-host.d.ts → runtime/static-preview-host.d.ts} +6 -1
  98. package/src/adapters/shared/ws/node-http-websocket-upgrades.d.ts +21 -0
  99. package/src/adapters/shared/ws/node-http-websocket-upgrades.js +109 -0
  100. package/src/adapters/shared/ws/websocket-lifecycle.d.ts +24 -0
  101. package/src/adapters/shared/ws/websocket-lifecycle.js +62 -0
  102. package/src/build/README.md +191 -31
  103. package/src/build/app-build-manifest-runtime.d.ts +39 -0
  104. package/src/build/app-build-manifest-runtime.js +145 -0
  105. package/src/build/browser/browser-runtime-manifest.js +58 -0
  106. package/src/build/browser/browser-runtime-plugin-helpers.js +34 -0
  107. package/src/build/{browser-runtime-plugin.d.ts → browser/browser-runtime-plugin.d.ts} +1 -1
  108. package/src/build/browser/browser-runtime-plugin.js +216 -0
  109. package/src/build/browser/jsx-ownership-plugins.d.ts +24 -0
  110. package/src/build/browser/jsx-ownership-plugins.js +55 -0
  111. package/src/build/browser/lit-static-render-worker-context.d.ts +2 -0
  112. package/src/build/browser/lit-static-render-worker-context.js +4 -0
  113. package/src/build/build-adapter.d.ts +29 -334
  114. package/src/build/build-adapter.js +273 -237
  115. package/src/build/cache/build-input-fingerprint.d.ts +28 -0
  116. package/src/build/cache/build-input-fingerprint.js +33 -0
  117. package/src/build/cache/cache-constants.d.ts +4 -0
  118. package/src/build/cache/cache-constants.js +4 -0
  119. package/src/build/cache/cache-keys.d.ts +22 -0
  120. package/src/build/cache/cache-keys.js +71 -0
  121. package/src/build/cache/pages-unified-graph-build.d.ts +31 -0
  122. package/src/build/cache/pages-unified-graph-build.js +199 -0
  123. package/src/build/cache/production-build-cache.d.ts +21 -0
  124. package/src/build/cache/production-build-cache.js +56 -0
  125. package/src/build/cache/server-entry-build-cache.d.ts +43 -0
  126. package/src/build/cache/server-entry-build-cache.js +153 -0
  127. package/src/build/contracts/build-contracts.d.ts +96 -0
  128. package/src/build/contracts/build-contracts.js +1 -0
  129. package/src/build/contracts/build-manifest.d.ts +90 -0
  130. package/src/build/contracts/build-manifest.js +64 -0
  131. package/src/build/contracts/build-types.js +1 -0
  132. package/src/build/contracts/content-virtual-modules.d.ts +12 -0
  133. package/src/build/contracts/content-virtual-modules.js +29 -0
  134. package/src/build/{rolldown-adapter-helpers.d.ts → rolldown/rolldown-adapter-helpers.d.ts} +32 -9
  135. package/src/build/rolldown/rolldown-adapter-helpers.js +458 -0
  136. package/src/build/{rolldown-build-adapter.d.ts → rolldown/rolldown-build-adapter.d.ts} +3 -7
  137. package/src/build/rolldown/rolldown-build-adapter.js +57 -0
  138. package/src/build/rolldown/rolldown-build-invocation-metrics.d.ts +12 -0
  139. package/src/build/rolldown/rolldown-build-invocation-metrics.js +39 -0
  140. package/src/build/{rolldown-plugin-bridge.d.ts → rolldown/rolldown-plugin-bridge.d.ts} +16 -2
  141. package/src/build/rolldown/rolldown-plugin-bridge.js +284 -0
  142. package/src/build/rolldown/rolldown-source-transform-pass.d.ts +15 -0
  143. package/src/build/rolldown/rolldown-source-transform-pass.js +70 -0
  144. package/src/build/rolldown/runtime-build-output-normalizer.d.ts +10 -0
  145. package/src/build/rolldown/runtime-build-output-normalizer.js +253 -0
  146. package/src/build/rolldown/server-side-css-shim-plugin.js +58 -0
  147. package/src/build/runtime/build-profile-options.d.ts +7 -0
  148. package/src/build/runtime/build-profile-options.js +37 -0
  149. package/src/build/runtime/build-request-identity.d.ts +17 -0
  150. package/src/build/runtime/build-request-identity.js +79 -0
  151. package/src/build/runtime/build-request-policy.d.ts +58 -0
  152. package/src/build/runtime/build-request-policy.js +84 -0
  153. package/src/build/runtime/build-runtime.d.ts +28 -0
  154. package/src/build/runtime/build-runtime.js +75 -0
  155. package/src/build/runtime/deduping-build-executor.d.ts +21 -0
  156. package/src/build/runtime/deduping-build-executor.js +40 -0
  157. package/src/build/runtime/parallel-build-executor.d.ts +21 -0
  158. package/src/build/runtime/parallel-build-executor.js +60 -0
  159. package/src/build/{serialized-build-executor.d.ts → runtime/serialized-build-executor.d.ts} +1 -1
  160. package/src/build/runtime/serialized-build-executor.js +79 -0
  161. package/src/cache/index.d.ts +2 -1
  162. package/src/cache/index.js +7 -6
  163. package/src/cache/module-parse-cache.d.ts +5 -0
  164. package/src/cache/module-parse-cache.js +122 -67
  165. package/src/cache/module-transform-profiler.d.ts +8 -0
  166. package/src/cache/module-transform-profiler.js +8 -0
  167. package/src/client/navigation-scripts/classification.d.ts +16 -0
  168. package/src/client/navigation-scripts/classification.js +49 -0
  169. package/src/client/navigation-scripts/index.d.ts +3 -0
  170. package/src/client/navigation-scripts/index.js +3 -0
  171. package/src/client/navigation-scripts/navigation-scripts.test.browser.d.ts +1 -0
  172. package/src/client/navigation-scripts/navigation-scripts.test.browser.js +61 -0
  173. package/src/client/navigation-scripts/registry.d.ts +11 -0
  174. package/src/client/navigation-scripts/registry.js +16 -0
  175. package/src/client/navigation-scripts/rerun-queue.d.ts +37 -0
  176. package/src/client/navigation-scripts/rerun-queue.js +90 -0
  177. package/src/client/scroll.d.ts +17 -0
  178. package/src/client/scroll.js +33 -0
  179. package/src/client/scroll.test.browser.d.ts +1 -0
  180. package/src/client/scroll.test.browser.js +31 -0
  181. package/src/client/view-transitions.d.ts +32 -0
  182. package/src/client/view-transitions.js +120 -0
  183. package/src/client/view-transitions.test.browser.d.ts +1 -0
  184. package/src/client/view-transitions.test.browser.js +56 -0
  185. package/src/config/config-builder.d.ts +40 -10
  186. package/src/config/config-builder.js +647 -600
  187. package/src/config/constants.d.ts +1 -0
  188. package/src/config/constants.js +44 -23
  189. package/src/declarations.d.ts +1 -0
  190. package/src/dev/README.md +24 -0
  191. package/src/dev/client-bridge-registry.d.ts +5 -0
  192. package/src/dev/client-bridge-registry.js +10 -0
  193. package/src/dev/dev-client-ownership.d.ts +7 -0
  194. package/src/dev/dev-client-ownership.js +8 -0
  195. package/src/dev/hmr-manager-registry.d.ts +8 -0
  196. package/src/dev/hmr-manager-registry.js +10 -0
  197. package/src/dev/host-runtime.d.ts +3 -0
  198. package/src/dev/host-runtime.js +25 -23
  199. package/src/dev/runtime-server-started-message.d.ts +2 -0
  200. package/src/dev/runtime-server-started-message.js +3 -0
  201. package/src/dev/sc-server.js +106 -103
  202. package/src/dev/transform-server/dev-transform-bundler.d.ts +24 -0
  203. package/src/dev/transform-server/dev-transform-bundler.js +79 -0
  204. package/src/dev/transform-server/dev-transform-externalize-plugin.d.ts +12 -0
  205. package/src/dev/transform-server/dev-transform-externalize-plugin.js +29 -0
  206. package/src/dev/transform-server/dev-transform-import-rewriter.d.ts +16 -0
  207. package/src/dev/transform-server/dev-transform-import-rewriter.js +126 -0
  208. package/src/dev/transform-server/dev-transform-module-kind.d.ts +13 -0
  209. package/src/dev/transform-server/dev-transform-module-kind.js +17 -0
  210. package/src/dev/transform-server/dev-transform-runtime-specifiers.d.ts +5 -0
  211. package/src/dev/transform-server/dev-transform-runtime-specifiers.js +16 -0
  212. package/src/dev/transform-server/dev-transform-server.d.ts +41 -0
  213. package/src/dev/transform-server/dev-transform-server.js +191 -0
  214. package/src/dev/transform-server/dev-transform-url.d.ts +13 -0
  215. package/src/dev/transform-server/dev-transform-url.js +58 -0
  216. package/src/dev/transform-server/dev-transform-vendor-registry.d.ts +28 -0
  217. package/src/dev/transform-server/dev-transform-vendor-registry.js +158 -0
  218. package/src/dev/transform-server/index.d.ts +6 -0
  219. package/src/dev/transform-server/index.js +4 -0
  220. package/src/dev/transform-server/types.d.ts +15 -0
  221. package/src/dev/transform-server/types.js +1 -0
  222. package/src/dev-toolbar/README.md +52 -0
  223. package/src/dev-toolbar/define-dev-tool.d.ts +21 -0
  224. package/src/dev-toolbar/define-dev-tool.js +9 -0
  225. package/src/dev-toolbar/dev-toolbar-config.d.ts +25 -0
  226. package/src/dev-toolbar/dev-toolbar-config.js +19 -0
  227. package/src/dev-toolbar/dev-toolbar-host.d.ts +49 -0
  228. package/src/dev-toolbar/dev-toolbar-host.js +117 -0
  229. package/src/dev-toolbar/dev-toolbar-html-response.d.ts +11 -0
  230. package/src/dev-toolbar/dev-toolbar-html-response.js +14 -0
  231. package/src/dev-toolbar/dev-toolbar-manifest-contract.d.ts +22 -0
  232. package/src/dev-toolbar/dev-toolbar-manifest-contract.js +2 -0
  233. package/src/dev-toolbar/dev-toolbar-manifest.d.ts +15 -0
  234. package/src/dev-toolbar/dev-toolbar-manifest.js +52 -0
  235. package/src/dev-toolbar/dev-toolbar-package.d.ts +34 -0
  236. package/src/dev-toolbar/dev-toolbar-package.js +78 -0
  237. package/src/dev-toolbar/dev-toolbar-runtime-paths.d.ts +10 -0
  238. package/src/dev-toolbar/dev-toolbar-runtime-paths.js +13 -0
  239. package/src/diagnostics/request-build-dedupe.d.ts +18 -0
  240. package/src/diagnostics/request-build-dedupe.js +39 -0
  241. package/src/diagnostics/request-pipeline-metrics.d.ts +38 -0
  242. package/src/diagnostics/request-pipeline-metrics.js +121 -0
  243. package/src/diagnostics/startup-trace.d.ts +81 -0
  244. package/src/diagnostics/startup-trace.js +281 -0
  245. package/src/eco/README.md +17 -0
  246. package/src/eco/component-identity.d.ts +13 -0
  247. package/src/eco/component-identity.js +18 -0
  248. package/src/eco/eco-declared-component.d.ts +15 -0
  249. package/src/eco/eco-declared-component.js +23 -0
  250. package/src/eco/eco.browser.js +63 -70
  251. package/src/eco/eco.js +163 -97
  252. package/src/eco/eco.types.d.ts +47 -8
  253. package/src/eco/eco.types.js +5 -0
  254. package/src/eco/eco.utils.d.ts +1 -1
  255. package/src/eco/eco.utils.js +1 -10
  256. package/src/eco/global-injector-map.js +55 -41
  257. package/src/eco/lazy-injector-map.js +90 -60
  258. package/src/eco/module-dependencies.js +52 -44
  259. package/src/eco/page-layout-normalization.d.ts +21 -0
  260. package/src/eco/page-layout-normalization.js +69 -0
  261. package/src/env.d.ts +2 -0
  262. package/src/errors/http-error.d.ts +8 -0
  263. package/src/errors/http-error.js +66 -49
  264. package/src/errors/index.d.ts +1 -0
  265. package/src/errors/index.js +3 -6
  266. package/src/errors/locals-access-error.js +5 -8
  267. package/src/errors/undeclared-component-dependency-error.d.ts +11 -0
  268. package/src/errors/undeclared-component-dependency-error.js +17 -0
  269. package/src/global/app-logger.js +3 -6
  270. package/src/hmr/README.md +21 -0
  271. package/src/hmr/client/hmr-runtime.js +119 -110
  272. package/src/hmr/client/module-update.d.ts +13 -0
  273. package/src/hmr/client/module-update.js +39 -0
  274. package/src/hmr/hmr-asset-paths.d.ts +14 -0
  275. package/src/hmr/hmr-asset-paths.js +22 -0
  276. package/src/hmr/hmr-entrypoint-output.d.ts +21 -0
  277. package/src/hmr/hmr-entrypoint-output.js +34 -0
  278. package/src/hmr/hmr-file-change-prep.d.ts +10 -0
  279. package/src/hmr/hmr-file-change-prep.js +14 -0
  280. package/src/hmr/hmr-registered-entrypoints-context.d.ts +7 -0
  281. package/src/hmr/hmr-registered-entrypoints-context.js +1 -0
  282. package/src/hmr/hmr-runtime-paths.d.ts +10 -0
  283. package/src/hmr/hmr-runtime-paths.js +13 -0
  284. package/src/hmr/hmr-strategy.d.ts +9 -0
  285. package/src/hmr/hmr-strategy.js +113 -42
  286. package/src/hmr/strategies/default-hmr-strategy.js +55 -33
  287. package/src/hmr/strategies/js-hmr-strategy.d.ts +6 -97
  288. package/src/hmr/strategies/js-hmr-strategy.js +107 -167
  289. package/src/hmr/strategies/server-rendered-template-hmr-strategy.d.ts +17 -0
  290. package/src/hmr/strategies/server-rendered-template-hmr-strategy.js +35 -0
  291. package/src/index.browser.d.ts +1 -0
  292. package/src/index.browser.js +2 -4
  293. package/src/index.d.ts +4 -1
  294. package/src/index.js +7 -21
  295. package/src/integrations/ghtml/ghtml-renderer.d.ts +2 -6
  296. package/src/integrations/ghtml/ghtml-renderer.js +12 -56
  297. package/src/integrations/ghtml/ghtml.constants.js +1 -4
  298. package/src/integrations/ghtml/ghtml.plugin.d.ts +3 -16
  299. package/src/integrations/ghtml/ghtml.plugin.js +10 -20
  300. package/src/islands/README.md +25 -0
  301. package/src/islands/island-host.d.ts +37 -0
  302. package/src/islands/island-host.js +55 -0
  303. package/src/plugins/README.md +2 -1
  304. package/src/plugins/alias-resolver-cache.d.ts +6 -9
  305. package/src/plugins/alias-resolver-cache.js +114 -97
  306. package/src/plugins/alias-resolver-plugin.d.ts +3 -3
  307. package/src/plugins/alias-resolver-plugin.js +35 -62
  308. package/src/plugins/define-integration.d.ts +26 -0
  309. package/src/plugins/define-integration.js +20 -0
  310. package/src/plugins/eco-component-meta-plugin.d.ts +6 -102
  311. package/src/plugins/eco-component-meta-plugin.js +120 -162
  312. package/src/plugins/foreign-jsx-override-plugin.d.ts +1 -1
  313. package/src/plugins/foreign-jsx-override-plugin.js +49 -37
  314. package/src/plugins/integration-plugin.d.ts +43 -14
  315. package/src/plugins/integration-plugin.js +212 -190
  316. package/src/plugins/jsx-import-source.utils.d.ts +8 -0
  317. package/src/plugins/jsx-import-source.utils.js +21 -0
  318. package/src/plugins/processor.d.ts +71 -12
  319. package/src/plugins/processor.js +168 -130
  320. package/src/plugins/runtime-capability.js +1 -0
  321. package/src/plugins/source-transform.d.ts +32 -1
  322. package/src/plugins/source-transform.js +112 -60
  323. package/src/plugins/tsconfig-import-resolver.d.ts +35 -0
  324. package/src/plugins/tsconfig-import-resolver.js +235 -0
  325. package/src/route-renderer/GRAPH.md +26 -32
  326. package/src/route-renderer/README.md +54 -33
  327. package/src/route-renderer/orchestration/document-shell/document-shell-render.service.d.ts +107 -0
  328. package/src/route-renderer/orchestration/document-shell/document-shell-render.service.js +155 -0
  329. package/src/route-renderer/orchestration/document-shell/layout-shell-props.service.d.ts +20 -0
  330. package/src/route-renderer/orchestration/document-shell/layout-shell-props.service.js +37 -0
  331. package/src/route-renderer/orchestration/{component-render-context.d.ts → foreign-child/component-render-context.d.ts} +8 -15
  332. package/src/route-renderer/orchestration/foreign-child/component-render-context.js +196 -0
  333. package/src/route-renderer/orchestration/{render-output.utils.d.ts → foreign-child/foreign-child-output.utils.d.ts} +17 -7
  334. package/src/route-renderer/orchestration/foreign-child/foreign-child-output.utils.js +191 -0
  335. package/src/route-renderer/orchestration/{foreign-subtree-execution.service.d.ts → foreign-child/foreign-subtree-execution.service.d.ts} +64 -34
  336. package/src/route-renderer/orchestration/foreign-child/foreign-subtree-execution.service.js +354 -0
  337. package/src/route-renderer/orchestration/foreign-child/owning-renderer-resolution.d.ts +19 -0
  338. package/src/route-renderer/orchestration/foreign-child/owning-renderer-resolution.js +36 -0
  339. package/src/route-renderer/orchestration/integration-renderer.d.ts +41 -151
  340. package/src/route-renderer/orchestration/integration-renderer.js +798 -988
  341. package/src/route-renderer/orchestration/integration-renderer.test-fixtures.d.ts +75 -0
  342. package/src/route-renderer/orchestration/integration-renderer.test-fixtures.js +173 -0
  343. package/src/route-renderer/orchestration/ownership-graph/component-graph-collectors.d.ts +10 -0
  344. package/src/route-renderer/orchestration/ownership-graph/component-graph-collectors.js +132 -0
  345. package/src/route-renderer/orchestration/ownership-graph/component-graph.d.ts +34 -0
  346. package/src/route-renderer/orchestration/ownership-graph/component-graph.js +89 -0
  347. package/src/route-renderer/orchestration/{ownership-validation.service.d.ts → ownership-graph/ownership-validation.service.d.ts} +6 -2
  348. package/src/route-renderer/orchestration/ownership-graph/ownership-validation.service.js +77 -0
  349. package/src/route-renderer/orchestration/page-browser-graph/global-injector-assets.service.d.ts +7 -0
  350. package/src/route-renderer/orchestration/page-browser-graph/global-injector-assets.service.js +30 -0
  351. package/src/route-renderer/orchestration/page-browser-graph/grouped-graph-build-plan.d.ts +15 -0
  352. package/src/route-renderer/orchestration/page-browser-graph/grouped-graph-build-plan.js +9 -0
  353. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-contribution.merge.d.ts +5 -0
  354. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-contribution.merge.js +30 -0
  355. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-merge.utils.d.ts +12 -0
  356. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-merge.utils.js +32 -0
  357. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-session.d.ts +126 -0
  358. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph-session.js +542 -0
  359. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph.service.d.ts +47 -0
  360. package/src/route-renderer/orchestration/page-browser-graph/page-browser-graph.service.js +232 -0
  361. package/src/route-renderer/orchestration/{processed-asset-dedupe.d.ts → page-browser-graph/processed-asset-dedupe.d.ts} +1 -1
  362. package/src/route-renderer/orchestration/page-browser-graph/processed-asset-dedupe.js +23 -0
  363. package/src/route-renderer/orchestration/page-browser-graph/route-instance-key.d.ts +29 -0
  364. package/src/route-renderer/orchestration/page-browser-graph/route-instance-key.js +54 -0
  365. package/src/route-renderer/orchestration/route-pipeline/integration-route-render-adapter.d.ts +38 -0
  366. package/src/route-renderer/orchestration/route-pipeline/integration-route-render-adapter.js +26 -0
  367. package/src/route-renderer/orchestration/route-pipeline/marker-artifact.utils.d.ts +6 -0
  368. package/src/route-renderer/orchestration/route-pipeline/marker-artifact.utils.js +25 -0
  369. package/src/route-renderer/orchestration/route-pipeline/robots-meta.contribution.d.ts +15 -0
  370. package/src/route-renderer/orchestration/route-pipeline/robots-meta.contribution.js +43 -0
  371. package/src/route-renderer/orchestration/route-pipeline/route-html-finalization.service.d.ts +25 -0
  372. package/src/route-renderer/orchestration/route-pipeline/route-html-finalization.service.js +44 -0
  373. package/src/route-renderer/orchestration/route-pipeline/route-prepared-options.builder.d.ts +26 -0
  374. package/src/route-renderer/orchestration/route-pipeline/route-prepared-options.builder.js +49 -0
  375. package/src/route-renderer/orchestration/route-pipeline/route-prepared-options.utils.d.ts +4 -0
  376. package/src/route-renderer/orchestration/route-pipeline/route-prepared-options.utils.js +30 -0
  377. package/src/route-renderer/orchestration/{route-render-orchestrator.d.ts → route-pipeline/route-render-orchestrator.d.ts} +24 -54
  378. package/src/route-renderer/orchestration/route-pipeline/route-render-orchestrator.js +215 -0
  379. package/src/route-renderer/orchestration/string-markup-renderer.d.ts +14 -0
  380. package/src/route-renderer/orchestration/string-markup-renderer.js +52 -0
  381. package/src/route-renderer/page-loading/component-dependency-collection.js +121 -121
  382. package/src/route-renderer/page-loading/declared-asset-collection.js +66 -94
  383. package/src/route-renderer/page-loading/dependency-resolver.js +101 -104
  384. package/src/route-renderer/page-loading/ecopages-virtual-imports.d.ts +1 -0
  385. package/src/route-renderer/page-loading/ecopages-virtual-imports.js +64 -51
  386. package/src/route-renderer/page-loading/file-scoped-dependency-components.d.ts +42 -0
  387. package/src/route-renderer/page-loading/file-scoped-dependency-components.js +94 -0
  388. package/src/route-renderer/page-loading/lazy-entry-collection.js +75 -98
  389. package/src/route-renderer/page-loading/lazy-trigger-planning.js +47 -36
  390. package/src/route-renderer/page-loading/module-declaration-aggregation.js +39 -28
  391. package/src/route-renderer/page-loading/module-declaration-scripts.js +10 -15
  392. package/src/route-renderer/page-loading/page-dependency-bundling.js +156 -113
  393. package/src/route-renderer/page-loading/page-module-loader.d.ts +2 -1
  394. package/src/route-renderer/page-loading/page-module-loader.js +136 -124
  395. package/src/route-renderer/page-loading/resolved-page-dependencies.d.ts +12 -0
  396. package/src/route-renderer/page-loading/resolved-page-dependencies.js +38 -0
  397. package/src/route-renderer/route-renderer.js +74 -76
  398. package/src/router/README.md +31 -0
  399. package/src/router/client/link-intent.d.ts +11 -21
  400. package/src/router/client/link-intent.js +56 -30
  401. package/src/router/client/link-intent.test.browser.js +50 -39
  402. package/src/router/client/link-navigation-policy.d.ts +45 -0
  403. package/src/router/client/link-navigation-policy.js +122 -0
  404. package/src/router/client/link-navigation-policy.test.browser.d.ts +1 -0
  405. package/src/router/client/link-navigation-policy.test.browser.js +82 -0
  406. package/src/router/client/navigation-coordinator.d.ts +1 -1
  407. package/src/router/client/navigation-coordinator.js +235 -201
  408. package/src/router/client/navigation-lifecycle.d.ts +55 -0
  409. package/src/router/client/navigation-lifecycle.js +50 -0
  410. package/src/router/client/navigation-lifecycle.test.browser.d.ts +1 -0
  411. package/src/router/client/navigation-lifecycle.test.browser.js +118 -0
  412. package/src/router/server/route-registry.js +237 -242
  413. package/src/services/README.md +5 -0
  414. package/src/services/assets/asset-processing-service/asset-dependency-keys.d.ts +13 -0
  415. package/src/services/assets/asset-processing-service/asset-dependency-keys.js +64 -50
  416. package/src/services/assets/asset-processing-service/asset-processing.service.d.ts +7 -1
  417. package/src/services/assets/asset-processing-service/asset-processing.service.js +308 -268
  418. package/src/services/assets/asset-processing-service/asset.factory.js +78 -81
  419. package/src/services/assets/asset-processing-service/assets.types.d.ts +1 -1
  420. package/src/services/assets/asset-processing-service/assets.types.js +1 -0
  421. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.d.ts +2 -1
  422. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.js +57 -45
  423. package/src/services/assets/asset-processing-service/browser-runtime-entry-resolution.d.ts +52 -0
  424. package/src/services/assets/asset-processing-service/browser-runtime-entry-resolution.js +115 -0
  425. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.d.ts +4 -2
  426. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.js +53 -38
  427. package/src/services/assets/asset-processing-service/finalize-processed-asset.d.ts +3 -0
  428. package/src/services/assets/asset-processing-service/finalize-processed-asset.js +5 -0
  429. package/src/services/assets/asset-processing-service/grouped-content-bundles.d.ts +2 -1
  430. package/src/services/assets/asset-processing-service/grouped-content-bundles.js +85 -60
  431. package/src/services/assets/asset-processing-service/index.d.ts +2 -0
  432. package/src/services/assets/asset-processing-service/index.js +8 -6
  433. package/src/services/assets/asset-processing-service/inline-content-script-body.d.ts +11 -0
  434. package/src/services/assets/asset-processing-service/inline-content-script-body.js +23 -0
  435. package/src/services/assets/asset-processing-service/materialize-content-script-asset.d.ts +9 -0
  436. package/src/services/assets/asset-processing-service/materialize-content-script-asset.js +22 -0
  437. package/src/services/assets/asset-processing-service/page-package.js +70 -72
  438. package/src/services/assets/asset-processing-service/processor.interface.js +7 -5
  439. package/src/services/assets/asset-processing-service/processor.registry.js +11 -14
  440. package/src/services/assets/asset-processing-service/processors/base/base-processor.js +59 -62
  441. package/src/services/assets/asset-processing-service/processors/base/base-script-processor.d.ts +0 -2
  442. package/src/services/assets/asset-processing-service/processors/base/base-script-processor.js +102 -130
  443. package/src/services/assets/asset-processing-service/processors/index.js +5 -5
  444. package/src/services/assets/asset-processing-service/processors/script/content-script.processor.d.ts +8 -0
  445. package/src/services/assets/asset-processing-service/processors/script/content-script.processor.js +111 -111
  446. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.d.ts +0 -1
  447. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.js +95 -94
  448. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.js +136 -121
  449. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.d.ts +0 -3
  450. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +26 -57
  451. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.d.ts +0 -3
  452. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +33 -67
  453. package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.d.ts +2 -0
  454. package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.js +44 -0
  455. package/src/services/assets/asset-processing-service/resolve-integration-plugin.d.ts +4 -0
  456. package/src/services/assets/asset-processing-service/resolve-integration-plugin.js +15 -0
  457. package/src/services/assets/asset-processing-service/ungrouped-dependency-processing.d.ts +0 -1
  458. package/src/services/assets/asset-processing-service/ungrouped-dependency-processing.js +27 -44
  459. package/src/services/assets/browser-bundle.service.d.ts +28 -30
  460. package/src/services/assets/browser-bundle.service.js +54 -40
  461. package/src/services/cache/cache.types.d.ts +4 -2
  462. package/src/services/cache/cache.types.js +5 -0
  463. package/src/services/cache/html-page-cache-dependency-index.d.ts +34 -0
  464. package/src/services/cache/html-page-cache-dependency-index.js +88 -0
  465. package/src/services/cache/index.d.ts +2 -0
  466. package/src/services/cache/index.js +8 -7
  467. package/src/services/cache/memory-cache-store.js +101 -89
  468. package/src/services/cache/page-cache-service.d.ts +31 -1
  469. package/src/services/cache/page-cache-service.js +237 -150
  470. package/src/services/cache/page-request-cache-coordinator.service.js +106 -102
  471. package/src/services/html/html-rewriter-provider.service.js +61 -61
  472. package/src/services/html/html-transformer.service.d.ts +1 -1
  473. package/src/services/html/html-transformer.service.js +249 -266
  474. package/src/services/invalidation/development-invalidation.service.d.ts +25 -2
  475. package/src/services/invalidation/development-invalidation.service.js +239 -175
  476. package/src/services/module-loading/README.md +52 -0
  477. package/src/services/module-loading/app-module-loader.service.js +1 -0
  478. package/src/services/module-loading/app-server-module-transpiler.service.d.ts +8 -0
  479. package/src/services/module-loading/app-server-module-transpiler.service.js +103 -118
  480. package/src/services/module-loading/collection-server-module-build.service.d.ts +19 -0
  481. package/src/services/module-loading/collection-server-module-build.service.js +83 -0
  482. package/src/services/module-loading/host-module-loader-registry.js +6 -11
  483. package/src/services/module-loading/module-loading-types.js +1 -0
  484. package/src/services/module-loading/page-module-import.service.d.ts +11 -13
  485. package/src/services/module-loading/page-module-import.service.js +222 -184
  486. package/src/services/module-loading/route-module-build-cache-registry.d.ts +24 -0
  487. package/src/services/module-loading/route-module-build-cache-registry.js +51 -0
  488. package/src/services/module-loading/route-module-build-cache.d.ts +4 -0
  489. package/src/services/module-loading/route-module-build-cache.js +3 -0
  490. package/src/services/module-loading/route-module-build-cache.store.d.ts +57 -0
  491. package/src/services/module-loading/route-module-build-cache.store.js +202 -0
  492. package/src/services/module-loading/route-module-build-manifest.d.ts +57 -0
  493. package/src/services/module-loading/route-module-build-manifest.js +60 -0
  494. package/src/services/module-loading/route-module-dependency-hasher.d.ts +81 -0
  495. package/src/services/module-loading/route-module-dependency-hasher.js +148 -0
  496. package/src/services/module-loading/server-module-transpiler.service.d.ts +1 -3
  497. package/src/services/module-loading/server-module-transpiler.service.js +65 -62
  498. package/src/services/module-loading/source-module-support.js +15 -7
  499. package/src/services/runtime-state/dev-graph.service.js +165 -157
  500. package/src/services/runtime-state/entrypoint-dependency-graph.service.js +85 -76
  501. package/src/services/runtime-state/server-invalidation-state.service.js +38 -30
  502. package/src/services/validation/schema-validation-service.d.ts +1 -4
  503. package/src/services/validation/schema-validation-service.js +156 -95
  504. package/src/services/validation/standard-schema.types.d.ts +9 -62
  505. package/src/services/validation/standard-schema.types.js +1 -0
  506. package/src/services/validation/validate-standard-schema.d.ts +7 -0
  507. package/src/services/validation/validate-standard-schema.js +14 -0
  508. package/src/static-site-generator/README.md +41 -0
  509. package/src/static-site-generator/production-page-browser-graph-prebuild.d.ts +32 -0
  510. package/src/static-site-generator/production-page-browser-graph-prebuild.js +57 -0
  511. package/src/static-site-generator/sitemap-routes.d.ts +14 -0
  512. package/src/static-site-generator/sitemap-routes.js +36 -0
  513. package/src/static-site-generator/sitemap.d.ts +15 -0
  514. package/src/static-site-generator/sitemap.js +42 -0
  515. package/src/static-site-generator/static-build-invalidation.d.ts +10 -0
  516. package/src/static-site-generator/static-build-invalidation.js +37 -0
  517. package/src/static-site-generator/static-export-context.d.ts +30 -0
  518. package/src/static-site-generator/static-export-context.js +1 -0
  519. package/src/static-site-generator/static-site-generator.d.ts +43 -25
  520. package/src/static-site-generator/static-site-generator.js +536 -294
  521. package/src/types/internal-types.d.ts +59 -13
  522. package/src/types/internal-types.js +1 -0
  523. package/src/types/public-types.d.ts +310 -95
  524. package/src/types/public-types.js +1 -0
  525. package/src/utils/deep-merge.js +39 -26
  526. package/src/utils/ecopages-route-info.d.ts +26 -0
  527. package/src/utils/ecopages-route-info.js +30 -0
  528. package/src/utils/hash.js +3 -6
  529. package/src/utils/html-escaping.d.ts +7 -0
  530. package/src/utils/html-escaping.js +22 -5
  531. package/src/utils/html.js +1 -4
  532. package/src/utils/invariant.js +11 -10
  533. package/src/utils/locals-utils.js +32 -22
  534. package/src/utils/parse-cli-args.d.ts +2 -0
  535. package/src/utils/parse-cli-args.js +73 -59
  536. package/src/utils/path-pattern.d.ts +23 -0
  537. package/src/utils/path-pattern.js +42 -0
  538. package/src/utils/path-utils.module.js +8 -11
  539. package/src/utils/resolve-entry-file.js +70 -38
  540. package/src/utils/resolve-work-dir.js +23 -27
  541. package/src/utils/runtime.js +24 -33
  542. package/src/utils/server-utils.module.d.ts +3 -2
  543. package/src/utils/server-utils.module.js +60 -53
  544. package/src/utils/static-file-extensions.d.ts +12 -0
  545. package/src/utils/static-file-extensions.js +54 -0
  546. package/src/watchers/project-watcher-ignore.d.ts +11 -0
  547. package/src/watchers/project-watcher-ignore.js +17 -0
  548. package/src/watchers/project-watcher.d.ts +29 -6
  549. package/src/watchers/project-watcher.js +402 -257
  550. package/src/watchers/project-watcher.test-helpers.js +45 -50
  551. package/src/adapters/shared/api-response.js +0 -96
  552. package/src/adapters/shared/application-adapter.js +0 -90
  553. package/src/adapters/shared/define-api-handler.d.ts +0 -25
  554. package/src/adapters/shared/define-api-handler.js +0 -15
  555. package/src/adapters/shared/explicit-static-render-preparation.js +0 -26
  556. package/src/adapters/shared/explicit-static-route-matcher.js +0 -101
  557. package/src/adapters/shared/file-route-middleware-pipeline.js +0 -90
  558. package/src/adapters/shared/fs-server-response-factory.js +0 -81
  559. package/src/adapters/shared/fs-server-response-matcher.js +0 -186
  560. package/src/adapters/shared/hmr-entrypoint-registrar.d.ts +0 -55
  561. package/src/adapters/shared/hmr-entrypoint-registrar.js +0 -87
  562. package/src/adapters/shared/hmr-html-response.js +0 -33
  563. package/src/adapters/shared/render-context.js +0 -93
  564. package/src/adapters/shared/runtime-app-bootstrap.js +0 -46
  565. package/src/adapters/shared/runtime-host.js +0 -0
  566. package/src/adapters/shared/server-adapter.js +0 -436
  567. package/src/adapters/shared/server-route-handler.js +0 -111
  568. package/src/adapters/shared/server-static-builder.js +0 -162
  569. package/src/adapters/shared/shared-hmr-manager.d.ts +0 -59
  570. package/src/adapters/shared/shared-hmr-manager.js +0 -241
  571. package/src/adapters/shared/static-preview-host.js +0 -0
  572. package/src/build/browser-runtime-manifest.js +0 -61
  573. package/src/build/browser-runtime-plugin-helpers.js +0 -14
  574. package/src/build/browser-runtime-plugin.js +0 -173
  575. package/src/build/build-manifest.d.ts +0 -33
  576. package/src/build/build-manifest.js +0 -49
  577. package/src/build/build-types.js +0 -0
  578. package/src/build/rolldown-adapter-helpers.js +0 -265
  579. package/src/build/rolldown-build-adapter.js +0 -65
  580. package/src/build/rolldown-dev-build-adapter.d.ts +0 -82
  581. package/src/build/rolldown-dev-build-adapter.js +0 -166
  582. package/src/build/rolldown-plugin-bridge.js +0 -199
  583. package/src/build/runtime-build-executor.d.ts +0 -21
  584. package/src/build/runtime-build-executor.js +0 -19
  585. package/src/build/runtime-build-output-normalizer.d.ts +0 -3
  586. package/src/build/runtime-build-output-normalizer.js +0 -111
  587. package/src/build/serialized-build-executor.js +0 -63
  588. package/src/build/server-side-css-shim-plugin.js +0 -35
  589. package/src/hmr/hmr.postcss.test.e2e.js +0 -31
  590. package/src/hmr/hmr.test.e2e.js +0 -43
  591. package/src/route-renderer/orchestration/component-render-context.js +0 -147
  592. package/src/route-renderer/orchestration/declared-ownership-graph.d.ts +0 -18
  593. package/src/route-renderer/orchestration/declared-ownership-graph.js +0 -34
  594. package/src/route-renderer/orchestration/foreign-subtree-execution.service.js +0 -233
  595. package/src/route-renderer/orchestration/ownership-planning.service.d.ts +0 -24
  596. package/src/route-renderer/orchestration/ownership-planning.service.js +0 -63
  597. package/src/route-renderer/orchestration/ownership-validation.service.js +0 -53
  598. package/src/route-renderer/orchestration/processed-asset-dedupe.js +0 -27
  599. package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.d.ts +0 -91
  600. package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.js +0 -170
  601. package/src/route-renderer/orchestration/render-output.utils.js +0 -171
  602. package/src/route-renderer/orchestration/route-render-orchestrator.js +0 -577
  603. package/src/route-renderer/orchestration/template-serialization.d.ts +0 -38
  604. package/src/route-renderer/orchestration/template-serialization.js +0 -45
  605. /package/src/adapters/shared/{runtime-host.d.ts → runtime/runtime-host.d.ts} +0 -0
  606. /package/src/{hmr/hmr.postcss.test.e2e.d.ts → adapters/shared/runtime/runtime-host.js} +0 -0
  607. /package/src/{hmr/hmr.test.e2e.d.ts → adapters/shared/runtime/static-preview-host.js} +0 -0
  608. /package/src/build/{browser-runtime-manifest.d.ts → browser/browser-runtime-manifest.d.ts} +0 -0
  609. /package/src/build/{browser-runtime-plugin-helpers.d.ts → browser/browser-runtime-plugin-helpers.d.ts} +0 -0
  610. /package/src/build/{build-types.d.ts → contracts/build-types.d.ts} +0 -0
  611. /package/src/build/{server-side-css-shim-plugin.d.ts → rolldown/server-side-css-shim-plugin.d.ts} +0 -0
@@ -1,275 +1,420 @@
1
- import path from "node:path";
2
- import chokidar, {} from "chokidar";
3
- import { fileSystem } from "@ecopages/file-system";
4
- import { appLogger } from "../global/app-logger.js";
5
- import { DevelopmentInvalidationService } from "../services/invalidation/development-invalidation.service.js";
6
- class ProjectWatcher {
7
- /**
8
- * Duplicate identical watcher events within this window are ignored.
9
- *
10
- * Some editors or save pipelines emit two near-identical filesystem change
11
- * notifications for the same file. Ecopages should treat those as one logical
12
- * update so HMR and route refresh work are not repeated unnecessarily.
13
- */
14
- static duplicateChangeWindowMs = 150;
15
- appConfig;
16
- refreshRouterRoutesCallback;
17
- hmrManager;
18
- bridge;
19
- invalidationService;
20
- watcher = null;
21
- lastHandledChange = /* @__PURE__ */ new Map();
22
- changeQueue = Promise.resolve();
23
- constructor({ config, refreshRouterRoutesCallback, hmrManager, bridge }) {
24
- this.appConfig = config;
25
- this.refreshRouterRoutesCallback = refreshRouterRoutesCallback;
26
- this.hmrManager = hmrManager;
27
- this.bridge = bridge;
28
- this.invalidationService = new DevelopmentInvalidationService(config);
29
- this.triggerRouterRefresh = this.triggerRouterRefresh.bind(this);
30
- this.handleError = this.handleError.bind(this);
31
- this.handleFileChange = this.handleFileChange.bind(this);
32
- }
33
- /**
34
- * Uncaches modules in the source directory to ensure fresh imports.
35
- * This is necessary for hot module replacement to work correctly.
36
- * @private
37
- */
38
- uncacheModules() {
39
- if (typeof require === "undefined") return;
40
- const { srcDir, rootDir } = this.appConfig;
41
- const regex = new RegExp(`${rootDir}/${srcDir}/.*`);
42
- for (const key in require.cache) {
43
- if (regex.test(key)) {
44
- delete require.cache[key];
45
- }
1
+ import path from 'node:path';
2
+ import chokidar, {} from 'chokidar';
3
+ import { fileSystem } from '@ecopages/file-system';
4
+ import { appLogger } from '../global/app-logger.js';
5
+ import { DevelopmentInvalidationService, } from '../services/invalidation/development-invalidation.service.js';
6
+ import { prepareHmrFileChange } from '../hmr/hmr-file-change-prep.js';
7
+ import { invalidateAppPageCacheBySourcePaths, clearAppPageCache } from '../services/cache/page-cache-service.js';
8
+ import { getAppPageBrowserGraphSession } from '../route-renderer/orchestration/page-browser-graph/page-browser-graph-session.js';
9
+ import { isRegisteredDevTransformEntrypoint } from '../hmr/hmr-entrypoint-output.js';
10
+ import { resolveInternalExecutionDir } from '../utils/resolve-work-dir.js';
11
+ import { createProjectWatcherIgnorePredicate } from './project-watcher-ignore.js';
12
+ /**
13
+ * ProjectWatcher handles file system changes for hot module replacement (HMR).
14
+ * It uses chokidar to watch for file changes and triggers appropriate actions:
15
+ * - Uncaches modules when files change
16
+ * - Refreshes router routes for page files
17
+ * - Triggers HMR server reload
18
+ * - Handles processor-specific file changes
19
+ *
20
+ * The watcher uses chokidar's built-in debouncing through `awaitWriteFinish`
21
+ * to handle rapid file changes efficiently:
22
+ * - stabilityThreshold: 50ms - Time to wait for writes to stabilize
23
+ * - pollInterval: 50ms - Interval to poll for file changes
24
+ *
25
+ * @class ProjectWatcher
26
+ */
27
+ export class ProjectWatcher {
28
+ /**
29
+ * Duplicate identical watcher events within this window are ignored.
30
+ *
31
+ * Some editors or save pipelines emit two near-identical filesystem change
32
+ * notifications for the same file. Ecopages should treat those as one logical
33
+ * update so HMR and route refresh work are not repeated unnecessarily.
34
+ */
35
+ static duplicateChangeWindowMs = 150;
36
+ appConfig;
37
+ refreshRouterRoutesCallback;
38
+ hmrManager;
39
+ bridge;
40
+ hostOwnsDevClient;
41
+ invalidationService;
42
+ changeDebounceMs;
43
+ watcher = null;
44
+ closed = false;
45
+ pendingChangeEvents = new Map();
46
+ changeQueue = Promise.resolve();
47
+ constructor({ config, refreshRouterRoutesCallback, hmrManager, bridge, hostOwnsDevClient, changeDebounceMs, }) {
48
+ this.appConfig = config;
49
+ this.refreshRouterRoutesCallback = refreshRouterRoutesCallback;
50
+ this.hmrManager = hmrManager;
51
+ this.bridge = bridge;
52
+ this.hostOwnsDevClient = hostOwnsDevClient === true;
53
+ const envDebounceMs = process.env.ECOPAGES_WATCH_CHANGE_DEBOUNCE_MS;
54
+ this.changeDebounceMs =
55
+ changeDebounceMs ??
56
+ (envDebounceMs !== undefined && envDebounceMs !== '' ? Number(envDebounceMs) : undefined) ??
57
+ ProjectWatcher.duplicateChangeWindowMs;
58
+ this.invalidationService = new DevelopmentInvalidationService(config);
59
+ this.triggerRouterRefresh = this.triggerRouterRefresh.bind(this);
60
+ this.handleError = this.handleError.bind(this);
61
+ this.handleFileChange = this.handleFileChange.bind(this);
62
+ this.processFileChange = this.processFileChange.bind(this);
46
63
  }
47
- }
48
- isRouteSourceFile(filePath) {
49
- return this.invalidationService.isRouteSourceFile(filePath);
50
- }
51
- isIncludeSourceFile(filePath) {
52
- return this.invalidationService.isIncludeSourceFile(filePath);
53
- }
54
- /**
55
- * Handles public directory file changes by copying only the changed file.
56
- * @param filePath - Absolute path of the changed file
57
- */
58
- async handlePublicDirFileChange(filePath) {
59
- try {
60
- const relativePath = path.relative(this.appConfig.absolutePaths.publicDir, filePath);
61
- const destPath = path.join(this.appConfig.absolutePaths.distDir, relativePath);
62
- if (fileSystem.exists(filePath)) {
63
- const destDir = path.dirname(destPath);
64
- fileSystem.ensureDir(destDir);
65
- await fileSystem.copyFileAsync(filePath, destPath);
66
- }
67
- this.bridge.reload();
68
- } catch (error) {
69
- appLogger.error(`Failed to copy public file: ${error instanceof Error ? error.message : String(error)}`);
70
- this.bridge.reload();
64
+ /**
65
+ * Uncaches modules in the source directory to ensure fresh imports.
66
+ * This is necessary for hot module replacement to work correctly.
67
+ * @private
68
+ */
69
+ uncacheModules() {
70
+ if (typeof require === 'undefined')
71
+ return;
72
+ const { srcDir, rootDir } = this.appConfig;
73
+ const regex = new RegExp(`${rootDir}/${srcDir}/.*`);
74
+ for (const key in require.cache) {
75
+ if (regex.test(key)) {
76
+ delete require.cache[key];
77
+ }
78
+ }
71
79
  }
72
- }
73
- /**
74
- * Serializes file change handling so that concurrent chokidar events are
75
- * processed one at a time, preventing overlapping builds and race conditions.
76
- */
77
- enqueueChange(task) {
78
- const queuedTask = this.changeQueue.then(task, task);
79
- this.changeQueue = queuedTask.catch(() => void 0);
80
- }
81
- /**
82
- * Handles file changes by uncaching modules, refreshing routes, and delegating appropriately.
83
- * Follows 5-rule priority:
84
- * 0. Public directory match? -> copy file and reload
85
- * 1. additionalWatchPaths match? -> reload
86
- * 2. Include template source? -> reload after processor notifications
87
- * 3. Processor-owned asset? -> processor already handled it via notification, skip HMR
88
- * 4. Otherwise -> HMR strategies
89
- *
90
- * Processors that watch a file extension as a dependency (e.g. PostCSS watching
91
- * .tsx for Tailwind class scanning) are always notified first, but do not
92
- * prevent the file from flowing through the normal HMR strategy pipeline.
93
- *
94
- * Duplicate identical watcher events for the same file are coalesced within a
95
- * short window before any of the priority rules run.
96
- * @param rawPath - Path of the changed file
97
- * @param event - The type of file system event
98
- */
99
- async handleFileChange(rawPath, event = "change") {
100
- const filePath = path.resolve(rawPath);
101
- const now = Date.now();
102
- const lastHandledAt = this.lastHandledChange.get(filePath);
103
- if (lastHandledAt !== void 0 && now - lastHandledAt < ProjectWatcher.duplicateChangeWindowMs) {
104
- return;
80
+ isRouteSourceFile(filePath) {
81
+ return this.invalidationService.isRouteSourceFile(filePath);
105
82
  }
106
- this.lastHandledChange.set(filePath, now);
107
- try {
108
- const plan = this.invalidationService.planFileChange(filePath);
109
- if (plan.category === "public-asset") {
110
- await this.handlePublicDirFileChange(filePath);
111
- return;
112
- }
113
- this.uncacheModules();
114
- if (plan.invalidateServerModules) {
115
- this.invalidationService.invalidateServerModules([filePath]);
116
- }
117
- if (plan.refreshRoutes) {
118
- await this.refreshRouterRoutesCallback();
119
- }
120
- if (plan.category === "additional-watch") {
121
- this.bridge.reload();
122
- return;
123
- }
124
- await this.notifyProcessors(filePath, event);
125
- if (plan.category === "include-source") {
83
+ isIncludeSourceFile(filePath) {
84
+ return this.invalidationService.isIncludeSourceFile(filePath);
85
+ }
86
+ requestBrowserReload() {
87
+ if (this.hostOwnsDevClient) {
88
+ return;
89
+ }
126
90
  this.bridge.reload();
127
- return;
128
- }
129
- if (plan.processorHandledAsset) {
130
- return;
131
- }
132
- if (plan.delegateToHmr) {
133
- await this.hmrManager.handleFileChange(filePath);
134
- }
135
- } catch (error) {
136
- if (error instanceof Error) {
137
- this.bridge.error(error.message);
138
- this.handleError(error);
139
- }
140
91
  }
141
- }
142
- /**
143
- * Notifies all processors whose watch config matches the given file extension.
144
- * This is called before checking processor ownership so that dependency-only
145
- * processors (e.g. PostCSS watching .tsx for class scanning) receive their
146
- * notifications regardless of whether they own the file.
147
- */
148
- async notifyProcessors(filePath, event) {
149
- const ctx = { path: filePath, bridge: this.bridge };
150
- for (const processor of this.appConfig.processors.values()) {
151
- const watchConfig = processor.getWatchConfig();
152
- if (!watchConfig) continue;
153
- const { extensions = [] } = watchConfig;
154
- if (extensions.length && !extensions.some((ext) => filePath.endsWith(ext))) {
155
- continue;
156
- }
157
- const handler = this.getProcessorHandler(watchConfig, event);
158
- if (handler) {
159
- await handler(ctx);
160
- }
92
+ /**
93
+ * Handles public directory file changes by copying only the changed file.
94
+ * @param filePath - Absolute path of the changed file
95
+ */
96
+ async handlePublicDirFileChange(filePath) {
97
+ try {
98
+ const relativePath = path.relative(this.appConfig.absolutePaths.publicDir, filePath);
99
+ const destPath = path.join(this.appConfig.absolutePaths.distDir, relativePath);
100
+ if (fileSystem.exists(filePath)) {
101
+ const destDir = path.dirname(destPath);
102
+ fileSystem.ensureDir(destDir);
103
+ await fileSystem.copyFileAsync(filePath, destPath);
104
+ }
105
+ this.requestBrowserReload();
106
+ }
107
+ catch (error) {
108
+ appLogger.error(`Failed to copy public file: ${error instanceof Error ? error.message : String(error)}`);
109
+ this.requestBrowserReload();
110
+ }
111
+ }
112
+ /**
113
+ * Serializes file change handling so that concurrent chokidar events are
114
+ * processed one at a time, preventing overlapping builds and race conditions.
115
+ */
116
+ enqueueChange(task) {
117
+ const queuedTask = this.changeQueue.then(task, task);
118
+ this.changeQueue = queuedTask.catch(() => undefined);
119
+ return queuedTask;
161
120
  }
162
- }
163
- getProcessorHandler(watchConfig, event) {
164
- switch (event) {
165
- case "change":
166
- return watchConfig.onChange;
167
- case "add":
168
- return watchConfig.onCreate;
169
- case "unlink":
170
- return watchConfig.onDelete;
121
+ /**
122
+ * Handles file changes by uncaching modules, refreshing routes, and delegating appropriately.
123
+ * Follows 5-rule priority:
124
+ * 0. Public directory match? -> copy file and reload
125
+ * 1. additionalWatchPaths match? -> reload
126
+ * 2. Include template source? -> current-page refresh via HMR after processor notifications are deferred
127
+ * 3. Processor-owned asset? -> processor already handled it via notification, skip HMR
128
+ * 4. Otherwise -> HMR strategies
129
+ *
130
+ * Processors that watch a file extension as a dependency (e.g. PostCSS watching
131
+ * .tsx for Tailwind class scanning) are always notified first, but do not
132
+ * prevent the file from flowing through the normal HMR strategy pipeline.
133
+ *
134
+ * Duplicate identical watcher events for the same file are coalesced within a
135
+ * short window before any of the priority rules run.
136
+ * @param rawPath - Path of the changed file
137
+ * @param event - The type of file system event
138
+ */
139
+ handleFileChange(rawPath, event = 'change') {
140
+ if (this.closed) {
141
+ return Promise.resolve();
142
+ }
143
+ const filePath = path.resolve(rawPath);
144
+ if (this.changeDebounceMs === 0) {
145
+ return this.enqueueChange(() => this.processFileChange(filePath, event));
146
+ }
147
+ const existing = this.pendingChangeEvents.get(filePath);
148
+ if (existing) {
149
+ clearTimeout(existing.timer);
150
+ }
151
+ const timer = setTimeout(() => {
152
+ this.pendingChangeEvents.delete(filePath);
153
+ void this.enqueueChange(() => this.processFileChange(filePath, event));
154
+ }, this.changeDebounceMs);
155
+ this.pendingChangeEvents.set(filePath, { event, timer });
156
+ return Promise.resolve();
171
157
  }
172
- }
173
- /**
174
- * Checks if a file is in the public directory.
175
- */
176
- isPublicDirFile(filePath) {
177
- return this.invalidationService.isPublicDirFile(filePath);
178
- }
179
- /**
180
- * Checks if file path matches any additionalWatchPaths patterns.
181
- */
182
- matchesAdditionalWatchPaths(filePath) {
183
- return this.invalidationService.matchesAdditionalWatchPaths(filePath);
184
- }
185
- /**
186
- * Checks if a file is handled by a processor.
187
- * Processors that declare asset capabilities own those file types.
188
- * Processors without capabilities fall back to checking watch extensions.
189
- */
190
- isHandledByProcessor(filePath) {
191
- return this.invalidationService.isProcessorOwnedAsset(filePath);
192
- }
193
- /**
194
- * Triggers router refresh for page directory changes.
195
- * This ensures the router is updated when pages are added or removed.
196
- *
197
- * @param {string} path - Path of the changed directory
198
- */
199
- async triggerRouterRefresh(changedPath) {
200
- const resolvedPath = path.resolve(changedPath);
201
- const isPageDir = resolvedPath.startsWith(this.appConfig.absolutePaths.pagesDir) && path.extname(resolvedPath) === "";
202
- if (isPageDir || this.isRouteSourceFile(resolvedPath)) {
203
- await this.refreshRouterRoutesCallback();
158
+ async processFileChange(filePath, event) {
159
+ try {
160
+ const plan = this.invalidationService.planFileChange(filePath);
161
+ if (plan.category === 'public-asset') {
162
+ await this.handlePublicDirFileChange(filePath);
163
+ return;
164
+ }
165
+ this.uncacheModules();
166
+ const resolvedFilePath = path.resolve(filePath);
167
+ if (shouldClearAllPageHtmlCache(plan.category)) {
168
+ await clearAppPageCache(this.appConfig);
169
+ }
170
+ else {
171
+ await invalidateAppPageCacheBySourcePaths(this.appConfig, [resolvedFilePath]);
172
+ }
173
+ const graphPreparation = this.hmrManager.isEnabled()
174
+ ? prepareHmrFileChange(this.appConfig, resolvedFilePath)
175
+ : undefined;
176
+ if (plan.refreshRoutes && (event === 'unlink' || event === 'add')) {
177
+ getAppPageBrowserGraphSession(this.appConfig).invalidateByRouteFile(resolvedFilePath);
178
+ }
179
+ const isRegisteredDevTransformEdit = isRegisteredDevTransformEntrypoint(this.hmrManager.getRegisteredEntrypoints(), resolvedFilePath);
180
+ if (plan.invalidateServerModules && !isRegisteredDevTransformEdit) {
181
+ this.invalidationService.invalidateServerModules([filePath]);
182
+ }
183
+ if (plan.refreshRoutes) {
184
+ await this.refreshRouterRoutesCallback();
185
+ }
186
+ if (plan.reloadBrowser) {
187
+ this.requestBrowserReload();
188
+ return;
189
+ }
190
+ const deferProcessorNotifications = plan.category === 'include-source' ||
191
+ plan.category === 'explicit-server-view' ||
192
+ isRegisteredDevTransformEdit;
193
+ if (deferProcessorNotifications && plan.delegateToHmr) {
194
+ await this.prewarmBeforeHmr(resolvedFilePath, plan);
195
+ await this.hmrManager.handleFileChange(filePath, {
196
+ graphIdentities: graphPreparation?.affectedGraphIdentities,
197
+ });
198
+ await this.notifyProcessors(filePath, event);
199
+ return;
200
+ }
201
+ await this.notifyProcessors(filePath, event);
202
+ if (plan.processorHandledAsset) {
203
+ return;
204
+ }
205
+ if (plan.delegateToHmr) {
206
+ await this.hmrManager.handleFileChange(filePath, {
207
+ graphIdentities: graphPreparation?.affectedGraphIdentities,
208
+ });
209
+ }
210
+ }
211
+ catch (error) {
212
+ if (error instanceof Error) {
213
+ this.bridge.error(error.message);
214
+ this.handleError(error);
215
+ }
216
+ }
204
217
  }
205
- }
206
- /**
207
- * Handles and logs errors that occur during file watching.
208
- *
209
- * @param {unknown} error - The error to handle
210
- */
211
- handleError(error) {
212
- if (error instanceof Error) {
213
- this.hmrManager.broadcast({ type: "error", message: error.message });
218
+ /**
219
+ * Re-imports server modules before HMR broadcast so reload/refetch does not
220
+ * race stale in-memory imports or custom-element registry state.
221
+ */
222
+ async prewarmBeforeHmr(filePath, plan) {
223
+ if (plan.category !== 'include-source' && plan.category !== 'explicit-server-view') {
224
+ return;
225
+ }
226
+ const modulePaths = plan.category === 'include-source'
227
+ ? [this.appConfig.absolutePaths.htmlTemplatePath]
228
+ : [path.resolve(filePath)];
229
+ await this.prewarmServerModuleImports(modulePaths, { scope: 'server template' });
214
230
  }
215
- appLogger.error(`Watcher error: ${error}`);
216
- }
217
- /**
218
- * Creates and configures the file system watcher.
219
- * This sets up:
220
- * 1. Page file watching
221
- * 2. Directory watching
222
- * 3. Error handling
223
- *
224
- * Processor notifications are dispatched inside handleFileChange, ensuring
225
- * a single unified event pipeline with no parallel chokidar bindings.
226
- *
227
- * Uses chokidar's built-in debouncing through `awaitWriteFinish` to handle
228
- * rapid file changes efficiently.
229
- */
230
- async createWatcherSubscription() {
231
- if (this.watcher) {
232
- return this.watcher;
231
+ async prewarmServerModuleImports(modulePaths, options) {
232
+ const appModuleLoader = this.appConfig.runtime?.appModuleLoader;
233
+ if (!appModuleLoader) {
234
+ return;
235
+ }
236
+ const outdir = path.join(resolveInternalExecutionDir(this.appConfig), '.server-modules');
237
+ for (const modulePath of modulePaths) {
238
+ if (!modulePath) {
239
+ continue;
240
+ }
241
+ try {
242
+ await appModuleLoader.importModule({
243
+ filePath: modulePath,
244
+ rootDir: this.appConfig.rootDir,
245
+ outdir,
246
+ externalPackages: true,
247
+ bypassCache: options.bypassCache,
248
+ });
249
+ }
250
+ catch (error) {
251
+ appLogger.error(`Failed to prewarm ${options.scope} ${modulePath}: ${error instanceof Error ? error.message : String(error)}`);
252
+ }
253
+ }
233
254
  }
234
- const processorPaths = [];
235
- for (const processor of this.appConfig.processors.values()) {
236
- const watchConfig = processor.getWatchConfig();
237
- if (!watchConfig) continue;
238
- processorPaths.push(...watchConfig.paths);
255
+ /**
256
+ * Notifies all processors whose watch config matches the given file extension.
257
+ * This is called before checking processor ownership so that dependency-only
258
+ * processors (e.g. PostCSS watching .tsx for class scanning) receive their
259
+ * notifications regardless of whether they own the file.
260
+ */
261
+ async notifyProcessors(filePath, event) {
262
+ const ctx = { path: filePath, bridge: this.bridge };
263
+ for (const processor of this.appConfig.processors.values()) {
264
+ const watchConfig = processor.getWatchConfig();
265
+ if (!watchConfig)
266
+ continue;
267
+ const { extensions = [] } = watchConfig;
268
+ if (extensions.length && !extensions.some((ext) => filePath.endsWith(ext))) {
269
+ continue;
270
+ }
271
+ const handler = this.getProcessorHandler(watchConfig, event);
272
+ if (handler) {
273
+ await handler(ctx);
274
+ }
275
+ }
239
276
  }
240
- if (fileSystem.exists(this.appConfig.absolutePaths.includesDir)) {
241
- processorPaths.push(this.appConfig.absolutePaths.includesDir);
277
+ getProcessorHandler(watchConfig, event) {
278
+ switch (event) {
279
+ case 'change':
280
+ return watchConfig.onChange;
281
+ case 'add':
282
+ return watchConfig.onCreate;
283
+ case 'unlink':
284
+ return watchConfig.onDelete;
285
+ }
242
286
  }
243
- if (fileSystem.exists(this.appConfig.absolutePaths.srcDir)) {
244
- processorPaths.push(this.appConfig.absolutePaths.srcDir);
287
+ /**
288
+ * Checks if a file is in the public directory.
289
+ */
290
+ isPublicDirFile(filePath) {
291
+ return this.invalidationService.isPublicDirFile(filePath);
245
292
  }
246
- if (fileSystem.exists(this.appConfig.absolutePaths.pagesDir)) {
247
- processorPaths.push(this.appConfig.absolutePaths.pagesDir);
293
+ /**
294
+ * Checks if file path matches any additionalWatchPaths patterns.
295
+ */
296
+ matchesAdditionalWatchPaths(filePath) {
297
+ return this.invalidationService.matchesAdditionalWatchPaths(filePath);
248
298
  }
249
- if (fileSystem.exists(this.appConfig.absolutePaths.publicDir)) {
250
- processorPaths.push(this.appConfig.absolutePaths.publicDir);
299
+ /**
300
+ * Checks if a file is owned by a processor as an asset input.
301
+ * Ownership requires declared asset capabilities; watch config only drives
302
+ * {@link notifyProcessors} notifications.
303
+ */
304
+ isHandledByProcessor(filePath) {
305
+ return this.invalidationService.isProcessorOwnedAsset(filePath);
251
306
  }
252
- if (this.appConfig.additionalWatchPaths.length) {
253
- processorPaths.push(...this.appConfig.additionalWatchPaths);
307
+ /**
308
+ * Triggers router refresh for page directory changes.
309
+ * This ensures the router is updated when pages are added or removed.
310
+ *
311
+ * @param {string} path - Path of the changed directory
312
+ */
313
+ async triggerRouterRefresh(changedPath) {
314
+ const resolvedPath = path.resolve(changedPath);
315
+ const isPageDir = resolvedPath.startsWith(this.appConfig.absolutePaths.pagesDir) && path.extname(resolvedPath) === '';
316
+ if (isPageDir || this.isRouteSourceFile(resolvedPath)) {
317
+ await this.refreshRouterRoutesCallback();
318
+ }
254
319
  }
255
- this.watcher = chokidar.watch(processorPaths, {
256
- ignoreInitial: true,
257
- ignorePermissionErrors: true,
258
- awaitWriteFinish: {
259
- stabilityThreshold: 50,
260
- pollInterval: 50
261
- }
262
- });
263
- this.watcher.on("change", (p) => this.enqueueChange(() => this.handleFileChange(p, "change"))).on("add", (p) => this.enqueueChange(() => this.handleFileChange(p, "add"))).on("addDir", (p) => this.enqueueChange(() => this.triggerRouterRefresh(p))).on("unlink", (p) => this.enqueueChange(() => this.handleFileChange(p, "unlink"))).on("unlinkDir", (p) => this.enqueueChange(() => this.triggerRouterRefresh(p))).on("error", (error) => this.handleError(error));
264
- for (const processor of this.appConfig.processors.values()) {
265
- const watchConfig = processor.getWatchConfig();
266
- if (watchConfig?.onError) {
267
- this.watcher.on("error", watchConfig.onError);
268
- }
320
+ /**
321
+ * Handles and logs errors that occur during file watching.
322
+ *
323
+ * @param {unknown} error - The error to handle
324
+ */
325
+ handleError(error) {
326
+ if (error instanceof Error) {
327
+ this.hmrManager.broadcast({ type: 'error', message: error.message });
328
+ }
329
+ appLogger.error(`Watcher error: ${error}`);
269
330
  }
270
- return this.watcher;
271
- }
331
+ /**
332
+ * Creates and configures the file system watcher.
333
+ * This sets up:
334
+ * 1. Page file watching
335
+ * 2. Directory watching
336
+ * 3. Error handling
337
+ *
338
+ * Processor notifications are dispatched inside handleFileChange, ensuring
339
+ * a single unified event pipeline with no parallel chokidar bindings.
340
+ *
341
+ * Uses chokidar's built-in debouncing through `awaitWriteFinish` to handle
342
+ * rapid file changes efficiently.
343
+ */
344
+ async createWatcherSubscription() {
345
+ if (this.watcher) {
346
+ return this.watcher;
347
+ }
348
+ const processorPaths = new Set();
349
+ for (const processor of this.appConfig.processors.values()) {
350
+ const watchConfig = processor.getWatchConfig();
351
+ if (!watchConfig)
352
+ continue;
353
+ for (const watchPath of watchConfig.paths) {
354
+ processorPaths.add(watchPath);
355
+ }
356
+ }
357
+ if (fileSystem.exists(this.appConfig.absolutePaths.includesDir)) {
358
+ processorPaths.add(this.appConfig.absolutePaths.includesDir);
359
+ }
360
+ if (fileSystem.exists(this.appConfig.absolutePaths.srcDir)) {
361
+ processorPaths.add(this.appConfig.absolutePaths.srcDir);
362
+ }
363
+ if (fileSystem.exists(this.appConfig.absolutePaths.publicDir)) {
364
+ processorPaths.add(this.appConfig.absolutePaths.publicDir);
365
+ }
366
+ for (const watchPath of this.appConfig.additionalWatchPaths) {
367
+ processorPaths.add(watchPath);
368
+ }
369
+ const ignored = createProjectWatcherIgnorePredicate(this.appConfig.absolutePaths);
370
+ this.watcher = chokidar.watch(Array.from(processorPaths), {
371
+ ignoreInitial: true,
372
+ ignorePermissionErrors: true,
373
+ ignored,
374
+ awaitWriteFinish: {
375
+ stabilityThreshold: 50,
376
+ pollInterval: 50,
377
+ },
378
+ });
379
+ this.watcher
380
+ .on('change', (p) => this.handleFileChange(p, 'change'))
381
+ .on('add', (p) => this.handleFileChange(p, 'add'))
382
+ .on('addDir', (p) => this.enqueueChange(() => this.triggerRouterRefresh(p)))
383
+ .on('unlink', (p) => this.handleFileChange(p, 'unlink'))
384
+ .on('unlinkDir', (p) => this.enqueueChange(() => this.triggerRouterRefresh(p)))
385
+ .on('error', (error) => this.handleError(error));
386
+ for (const processor of this.appConfig.processors.values()) {
387
+ const watchConfig = processor.getWatchConfig();
388
+ if (watchConfig?.onError) {
389
+ this.watcher.on('error', watchConfig.onError);
390
+ }
391
+ }
392
+ return this.watcher;
393
+ }
394
+ /**
395
+ * Closes the active filesystem watcher subscription.
396
+ *
397
+ * @remarks
398
+ * Safe to call multiple times. Used when tearing down dev servers in tests
399
+ * and other short-lived Ecopages runtimes.
400
+ */
401
+ async close() {
402
+ this.closed = true;
403
+ for (const pending of this.pendingChangeEvents.values()) {
404
+ clearTimeout(pending.timer);
405
+ }
406
+ this.pendingChangeEvents.clear();
407
+ if (this.watcher) {
408
+ await this.watcher.close();
409
+ this.watcher = null;
410
+ }
411
+ await this.changeQueue.catch(() => undefined);
412
+ }
413
+ }
414
+ function shouldClearAllPageHtmlCache(category) {
415
+ return (category === 'other' ||
416
+ category === 'server-source' ||
417
+ category === 'additional-watch' ||
418
+ category === 'include-source' ||
419
+ category === 'explicit-server-view');
272
420
  }
273
- export {
274
- ProjectWatcher
275
- };