@ecopages/core 0.2.0-alpha.1

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 (342) hide show
  1. package/CHANGELOG.md +89 -0
  2. package/LICENSE +21 -0
  3. package/README.md +32 -0
  4. package/package.json +279 -0
  5. package/src/adapters/abstract/application-adapter.d.ts +168 -0
  6. package/src/adapters/abstract/application-adapter.js +109 -0
  7. package/src/adapters/abstract/application-adapter.ts +337 -0
  8. package/src/adapters/abstract/router-adapter.d.ts +26 -0
  9. package/src/adapters/abstract/router-adapter.js +5 -0
  10. package/src/adapters/abstract/router-adapter.ts +30 -0
  11. package/src/adapters/abstract/server-adapter.d.ts +69 -0
  12. package/src/adapters/abstract/server-adapter.js +15 -0
  13. package/src/adapters/abstract/server-adapter.ts +79 -0
  14. package/src/adapters/bun/client-bridge.d.ts +34 -0
  15. package/src/adapters/bun/client-bridge.js +48 -0
  16. package/src/adapters/bun/client-bridge.ts +62 -0
  17. package/src/adapters/bun/create-app.d.ts +60 -0
  18. package/src/adapters/bun/create-app.js +117 -0
  19. package/src/adapters/bun/create-app.ts +189 -0
  20. package/src/adapters/bun/define-api-handler.d.ts +61 -0
  21. package/src/adapters/bun/define-api-handler.js +15 -0
  22. package/src/adapters/bun/define-api-handler.ts +114 -0
  23. package/src/adapters/bun/hmr-manager.d.ts +84 -0
  24. package/src/adapters/bun/hmr-manager.js +227 -0
  25. package/src/adapters/bun/hmr-manager.ts +281 -0
  26. package/src/adapters/bun/index.d.ts +3 -0
  27. package/src/adapters/bun/index.js +8 -0
  28. package/src/adapters/bun/index.ts +3 -0
  29. package/src/adapters/bun/server-adapter.d.ts +155 -0
  30. package/src/adapters/bun/server-adapter.js +368 -0
  31. package/src/adapters/bun/server-adapter.ts +492 -0
  32. package/src/adapters/bun/server-lifecycle.d.ts +52 -0
  33. package/src/adapters/bun/server-lifecycle.js +120 -0
  34. package/src/adapters/bun/server-lifecycle.ts +154 -0
  35. package/src/adapters/index.d.ts +6 -0
  36. package/src/adapters/index.js +14 -0
  37. package/src/adapters/index.ts +6 -0
  38. package/src/adapters/node/create-app.d.ts +21 -0
  39. package/src/adapters/node/create-app.js +143 -0
  40. package/src/adapters/node/create-app.ts +179 -0
  41. package/src/adapters/node/index.d.ts +4 -0
  42. package/src/adapters/node/index.js +8 -0
  43. package/src/adapters/node/index.ts +9 -0
  44. package/src/adapters/node/node-client-bridge.d.ts +26 -0
  45. package/src/adapters/node/node-client-bridge.js +66 -0
  46. package/src/adapters/node/node-client-bridge.ts +79 -0
  47. package/src/adapters/node/node-hmr-manager.d.ts +62 -0
  48. package/src/adapters/node/node-hmr-manager.js +221 -0
  49. package/src/adapters/node/node-hmr-manager.ts +271 -0
  50. package/src/adapters/node/server-adapter.d.ts +190 -0
  51. package/src/adapters/node/server-adapter.js +420 -0
  52. package/src/adapters/node/server-adapter.ts +561 -0
  53. package/src/adapters/node/static-content-server.d.ts +24 -0
  54. package/src/adapters/node/static-content-server.js +166 -0
  55. package/src/adapters/node/static-content-server.ts +203 -0
  56. package/src/adapters/shared/api-response.d.ts +52 -0
  57. package/src/adapters/shared/api-response.js +96 -0
  58. package/src/adapters/shared/api-response.ts +104 -0
  59. package/src/adapters/shared/application-adapter.d.ts +18 -0
  60. package/src/adapters/shared/application-adapter.js +90 -0
  61. package/src/adapters/shared/application-adapter.ts +199 -0
  62. package/src/adapters/shared/explicit-static-route-matcher.d.ts +38 -0
  63. package/src/adapters/shared/explicit-static-route-matcher.js +100 -0
  64. package/src/adapters/shared/explicit-static-route-matcher.ts +134 -0
  65. package/src/adapters/shared/file-route-middleware-pipeline.d.ts +65 -0
  66. package/src/adapters/shared/file-route-middleware-pipeline.js +98 -0
  67. package/src/adapters/shared/file-route-middleware-pipeline.ts +123 -0
  68. package/src/adapters/shared/fs-server-response-factory.d.ts +19 -0
  69. package/src/adapters/shared/fs-server-response-factory.js +97 -0
  70. package/src/adapters/shared/fs-server-response-factory.ts +118 -0
  71. package/src/adapters/shared/fs-server-response-matcher.d.ts +71 -0
  72. package/src/adapters/shared/fs-server-response-matcher.js +155 -0
  73. package/src/adapters/shared/fs-server-response-matcher.ts +198 -0
  74. package/src/adapters/shared/render-context.d.ts +14 -0
  75. package/src/adapters/shared/render-context.js +69 -0
  76. package/src/adapters/shared/render-context.ts +105 -0
  77. package/src/adapters/shared/server-adapter.d.ts +87 -0
  78. package/src/adapters/shared/server-adapter.js +353 -0
  79. package/src/adapters/shared/server-adapter.ts +442 -0
  80. package/src/adapters/shared/server-route-handler.d.ts +89 -0
  81. package/src/adapters/shared/server-route-handler.js +120 -0
  82. package/src/adapters/shared/server-route-handler.ts +166 -0
  83. package/src/adapters/shared/server-static-builder.d.ts +38 -0
  84. package/src/adapters/shared/server-static-builder.js +46 -0
  85. package/src/adapters/shared/server-static-builder.ts +82 -0
  86. package/src/build/build-adapter.d.ts +74 -0
  87. package/src/build/build-adapter.js +54 -0
  88. package/src/build/build-adapter.ts +132 -0
  89. package/src/build/build-types.d.ts +57 -0
  90. package/src/build/build-types.js +0 -0
  91. package/src/build/build-types.ts +83 -0
  92. package/src/build/esbuild-build-adapter.d.ts +69 -0
  93. package/src/build/esbuild-build-adapter.js +390 -0
  94. package/src/build/esbuild-build-adapter.ts +510 -0
  95. package/src/config/config-builder.d.ts +227 -0
  96. package/src/config/config-builder.js +392 -0
  97. package/src/config/config-builder.ts +474 -0
  98. package/src/constants.d.ts +32 -0
  99. package/src/constants.js +21 -0
  100. package/src/constants.ts +39 -0
  101. package/src/create-app.d.ts +17 -0
  102. package/src/create-app.js +66 -0
  103. package/src/create-app.ts +87 -0
  104. package/src/declarations.d.ts +26 -0
  105. package/src/define-api-handler.d.ts +25 -0
  106. package/src/define-api-handler.js +15 -0
  107. package/src/define-api-handler.ts +66 -0
  108. package/src/dev/sc-server.d.ts +30 -0
  109. package/src/dev/sc-server.js +111 -0
  110. package/src/dev/sc-server.ts +143 -0
  111. package/src/eco/README.md +636 -0
  112. package/src/eco/component-render-context.d.ts +105 -0
  113. package/src/eco/component-render-context.js +77 -0
  114. package/src/eco/component-render-context.ts +202 -0
  115. package/src/eco/eco.d.ts +9 -0
  116. package/src/eco/eco.js +110 -0
  117. package/src/eco/eco.ts +221 -0
  118. package/src/eco/eco.types.d.ts +170 -0
  119. package/src/eco/eco.types.js +0 -0
  120. package/src/eco/eco.types.ts +202 -0
  121. package/src/eco/eco.utils.d.ts +40 -0
  122. package/src/eco/eco.utils.js +40 -0
  123. package/src/eco/eco.utils.ts +89 -0
  124. package/src/eco/global-injector-map.d.ts +16 -0
  125. package/src/eco/global-injector-map.js +80 -0
  126. package/src/eco/global-injector-map.ts +112 -0
  127. package/src/eco/lazy-injector-map.d.ts +8 -0
  128. package/src/eco/lazy-injector-map.js +70 -0
  129. package/src/eco/lazy-injector-map.ts +120 -0
  130. package/src/eco/module-dependencies.d.ts +18 -0
  131. package/src/eco/module-dependencies.js +49 -0
  132. package/src/eco/module-dependencies.ts +75 -0
  133. package/src/env.d.ts +20 -0
  134. package/src/errors/http-error.d.ts +31 -0
  135. package/src/errors/http-error.js +50 -0
  136. package/src/errors/http-error.ts +72 -0
  137. package/src/errors/index.d.ts +2 -0
  138. package/src/errors/index.js +4 -0
  139. package/src/errors/index.ts +2 -0
  140. package/src/errors/locals-access-error.d.ts +4 -0
  141. package/src/errors/locals-access-error.js +9 -0
  142. package/src/errors/locals-access-error.ts +7 -0
  143. package/src/global/app-logger.d.ts +2 -0
  144. package/src/global/app-logger.js +6 -0
  145. package/src/global/app-logger.ts +4 -0
  146. package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-HMR-Server-Integration-should-have-HMR-script-injected-in-page-1.png +0 -0
  147. package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-HMR-Server-Integration-should-load-fixture-app-page-1.png +0 -0
  148. package/src/hmr/client/__screenshots__/hmr-runtime.test.browser.ts/HMR-Runtime-WebSocket-Connection-should-connect-to-correct-HMR-endpoint-1.png +0 -0
  149. package/src/hmr/client/hmr-runtime.d.ts +10 -0
  150. package/src/hmr/client/hmr-runtime.js +86 -0
  151. package/src/hmr/client/hmr-runtime.ts +121 -0
  152. package/src/hmr/hmr-strategy.d.ts +159 -0
  153. package/src/hmr/hmr-strategy.js +29 -0
  154. package/src/hmr/hmr-strategy.ts +172 -0
  155. package/src/hmr/hmr.test.e2e.d.ts +1 -0
  156. package/src/hmr/hmr.test.e2e.js +50 -0
  157. package/src/hmr/hmr.test.e2e.ts +75 -0
  158. package/src/hmr/strategies/default-hmr-strategy.d.ts +43 -0
  159. package/src/hmr/strategies/default-hmr-strategy.js +34 -0
  160. package/src/hmr/strategies/default-hmr-strategy.ts +60 -0
  161. package/src/hmr/strategies/js-hmr-strategy.d.ts +136 -0
  162. package/src/hmr/strategies/js-hmr-strategy.js +179 -0
  163. package/src/hmr/strategies/js-hmr-strategy.ts +308 -0
  164. package/src/index.browser.d.ts +3 -0
  165. package/src/index.browser.js +4 -0
  166. package/src/index.browser.ts +3 -0
  167. package/src/index.d.ts +5 -0
  168. package/src/index.js +10 -0
  169. package/src/index.ts +5 -0
  170. package/src/integrations/ghtml/ghtml-renderer.d.ts +15 -0
  171. package/src/integrations/ghtml/ghtml-renderer.js +60 -0
  172. package/src/integrations/ghtml/ghtml-renderer.ts +93 -0
  173. package/src/integrations/ghtml/ghtml.plugin.d.ts +20 -0
  174. package/src/integrations/ghtml/ghtml.plugin.js +21 -0
  175. package/src/integrations/ghtml/ghtml.plugin.ts +32 -0
  176. package/src/internal-types.d.ts +200 -0
  177. package/src/internal-types.js +0 -0
  178. package/src/internal-types.ts +212 -0
  179. package/src/plugins/alias-resolver-plugin.d.ts +2 -0
  180. package/src/plugins/alias-resolver-plugin.js +39 -0
  181. package/src/plugins/alias-resolver-plugin.ts +45 -0
  182. package/src/plugins/eco-component-meta-plugin.d.ts +95 -0
  183. package/src/plugins/eco-component-meta-plugin.js +157 -0
  184. package/src/plugins/eco-component-meta-plugin.ts +474 -0
  185. package/src/plugins/integration-plugin.d.ts +102 -0
  186. package/src/plugins/integration-plugin.js +100 -0
  187. package/src/plugins/integration-plugin.ts +184 -0
  188. package/src/plugins/processor.d.ts +82 -0
  189. package/src/plugins/processor.js +122 -0
  190. package/src/plugins/processor.ts +220 -0
  191. package/src/public-types.d.ts +1094 -0
  192. package/src/public-types.js +0 -0
  193. package/src/public-types.ts +1255 -0
  194. package/src/route-renderer/GRAPH.md +387 -0
  195. package/src/route-renderer/README.md +135 -0
  196. package/src/route-renderer/component-graph-executor.d.ts +32 -0
  197. package/src/route-renderer/component-graph-executor.js +31 -0
  198. package/src/route-renderer/component-graph-executor.ts +84 -0
  199. package/src/route-renderer/component-graph.d.ts +42 -0
  200. package/src/route-renderer/component-graph.js +72 -0
  201. package/src/route-renderer/component-graph.ts +159 -0
  202. package/src/route-renderer/component-marker.d.ts +52 -0
  203. package/src/route-renderer/component-marker.js +46 -0
  204. package/src/route-renderer/component-marker.ts +117 -0
  205. package/src/route-renderer/dependency-resolver.d.ts +24 -0
  206. package/src/route-renderer/dependency-resolver.js +428 -0
  207. package/src/route-renderer/dependency-resolver.ts +596 -0
  208. package/src/route-renderer/html-post-processing.service.d.ts +40 -0
  209. package/src/route-renderer/html-post-processing.service.js +86 -0
  210. package/src/route-renderer/html-post-processing.service.ts +103 -0
  211. package/src/route-renderer/integration-renderer.d.ts +339 -0
  212. package/src/route-renderer/integration-renderer.js +526 -0
  213. package/src/route-renderer/integration-renderer.ts +696 -0
  214. package/src/route-renderer/marker-graph-resolver.d.ts +76 -0
  215. package/src/route-renderer/marker-graph-resolver.js +93 -0
  216. package/src/route-renderer/marker-graph-resolver.ts +153 -0
  217. package/src/route-renderer/page-module-loader.d.ts +61 -0
  218. package/src/route-renderer/page-module-loader.js +102 -0
  219. package/src/route-renderer/page-module-loader.ts +153 -0
  220. package/src/route-renderer/render-execution.service.d.ts +69 -0
  221. package/src/route-renderer/render-execution.service.js +91 -0
  222. package/src/route-renderer/render-execution.service.ts +158 -0
  223. package/src/route-renderer/render-preparation.service.d.ts +112 -0
  224. package/src/route-renderer/render-preparation.service.js +243 -0
  225. package/src/route-renderer/render-preparation.service.ts +358 -0
  226. package/src/route-renderer/route-renderer.d.ts +26 -0
  227. package/src/route-renderer/route-renderer.js +68 -0
  228. package/src/route-renderer/route-renderer.ts +80 -0
  229. package/src/router/fs-router-scanner.d.ts +41 -0
  230. package/src/router/fs-router-scanner.js +155 -0
  231. package/src/router/fs-router-scanner.ts +217 -0
  232. package/src/router/fs-router.d.ts +26 -0
  233. package/src/router/fs-router.js +100 -0
  234. package/src/router/fs-router.ts +122 -0
  235. package/src/services/asset-processing-service/asset-processing.service.d.ts +41 -0
  236. package/src/services/asset-processing-service/asset-processing.service.js +250 -0
  237. package/src/services/asset-processing-service/asset-processing.service.ts +306 -0
  238. package/src/services/asset-processing-service/asset.factory.d.ts +17 -0
  239. package/src/services/asset-processing-service/asset.factory.js +82 -0
  240. package/src/services/asset-processing-service/asset.factory.ts +105 -0
  241. package/src/services/asset-processing-service/assets.types.d.ts +88 -0
  242. package/src/services/asset-processing-service/assets.types.js +0 -0
  243. package/src/services/asset-processing-service/assets.types.ts +112 -0
  244. package/src/services/asset-processing-service/index.d.ts +3 -0
  245. package/src/services/asset-processing-service/index.js +3 -0
  246. package/src/services/asset-processing-service/index.ts +3 -0
  247. package/src/services/asset-processing-service/processor.interface.d.ts +22 -0
  248. package/src/services/asset-processing-service/processor.interface.js +6 -0
  249. package/src/services/asset-processing-service/processor.interface.ts +27 -0
  250. package/src/services/asset-processing-service/processor.registry.d.ts +8 -0
  251. package/src/services/asset-processing-service/processor.registry.js +15 -0
  252. package/src/services/asset-processing-service/processor.registry.ts +18 -0
  253. package/src/services/asset-processing-service/processors/base/base-processor.d.ts +24 -0
  254. package/src/services/asset-processing-service/processors/base/base-processor.js +59 -0
  255. package/src/services/asset-processing-service/processors/base/base-processor.ts +76 -0
  256. package/src/services/asset-processing-service/processors/base/base-script-processor.d.ts +16 -0
  257. package/src/services/asset-processing-service/processors/base/base-script-processor.js +80 -0
  258. package/src/services/asset-processing-service/processors/base/base-script-processor.ts +105 -0
  259. package/src/services/asset-processing-service/processors/index.d.ts +5 -0
  260. package/src/services/asset-processing-service/processors/index.js +5 -0
  261. package/src/services/asset-processing-service/processors/index.ts +5 -0
  262. package/src/services/asset-processing-service/processors/script/content-script.processor.d.ts +5 -0
  263. package/src/services/asset-processing-service/processors/script/content-script.processor.js +57 -0
  264. package/src/services/asset-processing-service/processors/script/content-script.processor.ts +66 -0
  265. package/src/services/asset-processing-service/processors/script/file-script.processor.d.ts +8 -0
  266. package/src/services/asset-processing-service/processors/script/file-script.processor.js +76 -0
  267. package/src/services/asset-processing-service/processors/script/file-script.processor.ts +88 -0
  268. package/src/services/asset-processing-service/processors/script/node-module-script.processor.d.ts +7 -0
  269. package/src/services/asset-processing-service/processors/script/node-module-script.processor.js +74 -0
  270. package/src/services/asset-processing-service/processors/script/node-module-script.processor.ts +84 -0
  271. package/src/services/asset-processing-service/processors/stylesheet/content-stylesheet.processor.d.ts +5 -0
  272. package/src/services/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +25 -0
  273. package/src/services/asset-processing-service/processors/stylesheet/content-stylesheet.processor.ts +27 -0
  274. package/src/services/asset-processing-service/processors/stylesheet/file-stylesheet.processor.d.ts +9 -0
  275. package/src/services/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +63 -0
  276. package/src/services/asset-processing-service/processors/stylesheet/file-stylesheet.processor.ts +77 -0
  277. package/src/services/cache/cache.types.d.ts +107 -0
  278. package/src/services/cache/cache.types.js +0 -0
  279. package/src/services/cache/cache.types.ts +126 -0
  280. package/src/services/cache/index.d.ts +7 -0
  281. package/src/services/cache/index.js +7 -0
  282. package/src/services/cache/index.ts +18 -0
  283. package/src/services/cache/memory-cache-store.d.ts +42 -0
  284. package/src/services/cache/memory-cache-store.js +98 -0
  285. package/src/services/cache/memory-cache-store.ts +130 -0
  286. package/src/services/cache/page-cache-service.d.ts +70 -0
  287. package/src/services/cache/page-cache-service.js +152 -0
  288. package/src/services/cache/page-cache-service.ts +202 -0
  289. package/src/services/html-transformer.service.d.ts +50 -0
  290. package/src/services/html-transformer.service.js +163 -0
  291. package/src/services/html-transformer.service.ts +217 -0
  292. package/src/services/page-module-import.service.d.ts +37 -0
  293. package/src/services/page-module-import.service.js +88 -0
  294. package/src/services/page-module-import.service.ts +129 -0
  295. package/src/services/page-request-cache-coordinator.service.d.ts +75 -0
  296. package/src/services/page-request-cache-coordinator.service.js +107 -0
  297. package/src/services/page-request-cache-coordinator.service.ts +128 -0
  298. package/src/services/schema-validation-service.d.ts +122 -0
  299. package/src/services/schema-validation-service.js +101 -0
  300. package/src/services/schema-validation-service.ts +204 -0
  301. package/src/services/validation/standard-schema.types.d.ts +65 -0
  302. package/src/services/validation/standard-schema.types.js +0 -0
  303. package/src/services/validation/standard-schema.types.ts +68 -0
  304. package/src/static-site-generator/static-site-generator.d.ts +57 -0
  305. package/src/static-site-generator/static-site-generator.js +272 -0
  306. package/src/static-site-generator/static-site-generator.ts +359 -0
  307. package/src/utils/css.d.ts +1 -0
  308. package/src/utils/css.js +7 -0
  309. package/src/utils/css.ts +5 -0
  310. package/src/utils/deep-merge.d.ts +14 -0
  311. package/src/utils/deep-merge.js +32 -0
  312. package/src/utils/deep-merge.ts +47 -0
  313. package/src/utils/hash.d.ts +1 -0
  314. package/src/utils/hash.js +7 -0
  315. package/src/utils/hash.ts +5 -0
  316. package/src/utils/html.d.ts +1 -0
  317. package/src/utils/html.js +4 -0
  318. package/src/utils/html.ts +1 -0
  319. package/src/utils/invariant.d.ts +5 -0
  320. package/src/utils/invariant.js +11 -0
  321. package/src/utils/invariant.ts +15 -0
  322. package/src/utils/locals-utils.d.ts +15 -0
  323. package/src/utils/locals-utils.js +24 -0
  324. package/src/utils/locals-utils.ts +37 -0
  325. package/src/utils/parse-cli-args.d.ts +24 -0
  326. package/src/utils/parse-cli-args.js +47 -0
  327. package/src/utils/parse-cli-args.ts +83 -0
  328. package/src/utils/path-utils.module.d.ts +5 -0
  329. package/src/utils/path-utils.module.js +14 -0
  330. package/src/utils/path-utils.module.ts +14 -0
  331. package/src/utils/runtime.d.ts +11 -0
  332. package/src/utils/runtime.js +40 -0
  333. package/src/utils/runtime.ts +44 -0
  334. package/src/utils/server-utils.module.d.ts +19 -0
  335. package/src/utils/server-utils.module.js +56 -0
  336. package/src/utils/server-utils.module.ts +67 -0
  337. package/src/watchers/project-watcher.d.ts +120 -0
  338. package/src/watchers/project-watcher.js +238 -0
  339. package/src/watchers/project-watcher.test-helpers.d.ts +4 -0
  340. package/src/watchers/project-watcher.test-helpers.js +51 -0
  341. package/src/watchers/project-watcher.test-helpers.ts +40 -0
  342. package/src/watchers/project-watcher.ts +306 -0
@@ -0,0 +1,154 @@
1
+ import path from 'node:path';
2
+ import { getBunRuntime } from '../../utils/runtime.ts';
3
+ import { RESOLVED_ASSETS_DIR } from '../../constants';
4
+ import { defaultBuildAdapter } from '../../build/build-adapter.ts';
5
+ import { appLogger } from '../../global/app-logger';
6
+ import type { EcoPagesAppConfig } from '../../internal-types';
7
+ import type { EcoBuildPlugin } from '../../build/build-types.ts';
8
+ import { fileSystem } from '@ecopages/file-system';
9
+ import { StaticSiteGenerator } from '../../static-site-generator/static-site-generator';
10
+ import { ProjectWatcher } from '../../watchers/project-watcher';
11
+ import type { ClientBridge } from './client-bridge';
12
+ import type { HmrManager } from './hmr-manager';
13
+
14
+ export interface WatcherCallbacks {
15
+ refreshRouterRoutesCallback: () => Promise<void>;
16
+ }
17
+
18
+ export interface ServerLifecycleParams {
19
+ appConfig: EcoPagesAppConfig;
20
+ runtimeOrigin: string;
21
+ hmrManager: HmrManager;
22
+ bridge: ClientBridge;
23
+ }
24
+
25
+ /**
26
+ * Handles server lifecycle: initialization, plugins, loaders, and file watching.
27
+ */
28
+ export class ServerLifecycle {
29
+ private readonly appConfig: EcoPagesAppConfig;
30
+ private readonly hmrManager: HmrManager;
31
+ private readonly bridge: ClientBridge;
32
+ private readonly runtimeOrigin: string;
33
+ private staticSiteGenerator!: StaticSiteGenerator;
34
+
35
+ constructor({ appConfig, runtimeOrigin, hmrManager, bridge }: ServerLifecycleParams) {
36
+ this.appConfig = appConfig;
37
+ this.runtimeOrigin = runtimeOrigin;
38
+ this.hmrManager = hmrManager;
39
+ this.bridge = bridge;
40
+ }
41
+
42
+ /**
43
+ * Initializes the server's core components.
44
+ * @returns The static site generator instance for use by other components
45
+ */
46
+ async initialize(): Promise<StaticSiteGenerator> {
47
+ this.staticSiteGenerator = new StaticSiteGenerator({ appConfig: this.appConfig });
48
+ await this.hmrManager.buildRuntime();
49
+
50
+ this.setupLoaders();
51
+ this.copyPublicDir();
52
+
53
+ return this.staticSiteGenerator;
54
+ }
55
+
56
+ /**
57
+ * Sets up Bun loaders from config.
58
+ * Note: This will be abstracted to a LoaderStrategy interface in #4 Runtime Abstraction.
59
+ */
60
+ setupLoaders(): void {
61
+ const loaders = this.appConfig.loaders;
62
+ for (const loader of loaders.values()) {
63
+ defaultBuildAdapter.registerPlugin(loader);
64
+ getBunRuntime()?.plugin(loader as any);
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Copies public directory contents to dist root.
70
+ * Static files are served from root (e.g., /favicon.ico, /robots.txt).
71
+ */
72
+ copyPublicDir(): void {
73
+ try {
74
+ const srcPublicDir = path.join(this.appConfig.rootDir, this.appConfig.srcDir, this.appConfig.publicDir);
75
+
76
+ if (fileSystem.exists(srcPublicDir)) {
77
+ fileSystem.copyDir(srcPublicDir, path.join(this.appConfig.rootDir, this.appConfig.distDir));
78
+ }
79
+
80
+ fileSystem.ensureDir(path.join(this.appConfig.absolutePaths.distDir, RESOLVED_ASSETS_DIR));
81
+ } catch (error) {
82
+ appLogger.error(
83
+ `Failed to copy public directory: ${error instanceof Error ? error.message : String(error)}`,
84
+ );
85
+ throw error;
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Initializes processors and integrations.
91
+ * @param options.watch - Whether watch mode is enabled
92
+ */
93
+ async initializePlugins(options?: { watch?: boolean }): Promise<EcoBuildPlugin[]> {
94
+ try {
95
+ const hmrEnabled = !!options?.watch;
96
+ this.hmrManager.setEnabled(hmrEnabled);
97
+
98
+ const processorBuildPlugins: EcoBuildPlugin[] = [];
99
+
100
+ const processorPromises = Array.from(this.appConfig.processors.values()).map(async (processor) => {
101
+ await processor.setup();
102
+ if (processor.plugins) {
103
+ for (const plugin of processor.plugins) {
104
+ defaultBuildAdapter.registerPlugin(plugin);
105
+ getBunRuntime()?.plugin(plugin as any);
106
+ }
107
+ }
108
+ if (processor.buildPlugins) {
109
+ processorBuildPlugins.push(...processor.buildPlugins);
110
+ }
111
+ });
112
+
113
+ const integrationPromises = this.appConfig.integrations.map(async (integration) => {
114
+ integration.setConfig(this.appConfig);
115
+ integration.setRuntimeOrigin(this.runtimeOrigin);
116
+ integration.setHmrManager(this.hmrManager);
117
+ await integration.setup();
118
+
119
+ for (const plugin of integration.plugins) {
120
+ defaultBuildAdapter.registerPlugin(plugin);
121
+ getBunRuntime()?.plugin(plugin as any);
122
+ }
123
+ });
124
+
125
+ await Promise.all([...processorPromises, ...integrationPromises]);
126
+
127
+ const loaderPlugins = Array.from(this.appConfig.loaders.values());
128
+ const allBuildPlugins = [...loaderPlugins, ...processorBuildPlugins];
129
+ this.hmrManager.setPlugins(allBuildPlugins);
130
+ return allBuildPlugins;
131
+ } catch (error) {
132
+ appLogger.error(`Failed to initialize plugins: ${error instanceof Error ? error.message : String(error)}`);
133
+ throw error;
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Starts file watching for HMR.
139
+ */
140
+ async startWatching(callbacks: WatcherCallbacks): Promise<void> {
141
+ const watcherInstance = new ProjectWatcher({
142
+ config: this.appConfig,
143
+ refreshRouterRoutesCallback: callbacks.refreshRouterRoutesCallback,
144
+ hmrManager: this.hmrManager,
145
+ bridge: this.bridge,
146
+ });
147
+
148
+ await watcherInstance.createWatcherSubscription();
149
+ }
150
+
151
+ getStaticSiteGenerator(): StaticSiteGenerator {
152
+ return this.staticSiteGenerator;
153
+ }
154
+ }
@@ -0,0 +1,6 @@
1
+ export { EcopagesApp, createApp } from './bun/create-app.js';
2
+ export { defineApiHandler, defineGroupHandler } from './bun/define-api-handler.js';
3
+ export { NodeServerAdapter, createNodeServerAdapter } from './node/server-adapter.js';
4
+ export { EcopagesApp as NodeAdapterEcopagesApp, createNodeApp } from './node/create-app.js';
5
+ export type { NodeServerAdapterParams, NodeServerAdapterResult } from './node/server-adapter.js';
6
+ export type { EcopagesAppOptions as NodeEcopagesAppOptions } from './node/create-app.js';
@@ -0,0 +1,14 @@
1
+ import { EcopagesApp, createApp } from "./bun/create-app.js";
2
+ import { defineApiHandler, defineGroupHandler } from "./bun/define-api-handler.js";
3
+ import { NodeServerAdapter, createNodeServerAdapter } from "./node/server-adapter.js";
4
+ import { EcopagesApp as EcopagesApp2, createNodeApp } from "./node/create-app.js";
5
+ export {
6
+ EcopagesApp,
7
+ EcopagesApp2 as NodeAdapterEcopagesApp,
8
+ NodeServerAdapter,
9
+ createApp,
10
+ createNodeApp,
11
+ createNodeServerAdapter,
12
+ defineApiHandler,
13
+ defineGroupHandler
14
+ };
@@ -0,0 +1,6 @@
1
+ export { EcopagesApp, createApp } from './bun/create-app.ts';
2
+ export { defineApiHandler, defineGroupHandler } from './bun/define-api-handler.ts';
3
+ export { NodeServerAdapter, createNodeServerAdapter } from './node/server-adapter.ts';
4
+ export { EcopagesApp as NodeAdapterEcopagesApp, createNodeApp } from './node/create-app.ts';
5
+ export type { NodeServerAdapterParams, NodeServerAdapterResult } from './node/server-adapter.ts';
6
+ export type { EcopagesAppOptions as NodeEcopagesAppOptions } from './node/create-app.ts';
@@ -0,0 +1,21 @@
1
+ import { type Server as NodeServerInstance } from 'node:http';
2
+ import type { EcoPagesAppConfig } from '../../internal-types.js';
3
+ import { type ApplicationAdapterOptions } from '../abstract/application-adapter.js';
4
+ import { SharedApplicationAdapter } from '../shared/application-adapter.js';
5
+ import { type NodeServerAdapterResult } from './server-adapter.js';
6
+ export interface EcopagesAppOptions extends ApplicationAdapterOptions {
7
+ appConfig: EcoPagesAppConfig;
8
+ serverOptions?: Record<string, any>;
9
+ }
10
+ export declare class EcopagesApp extends SharedApplicationAdapter<EcopagesAppOptions, NodeServerInstance, Request> {
11
+ serverAdapter: NodeServerAdapterResult | undefined;
12
+ private server;
13
+ private runtimeOrigin;
14
+ stop(force?: boolean): Promise<void>;
15
+ protected initializeServerAdapter(): Promise<NodeServerAdapterResult>;
16
+ start(): Promise<NodeServerInstance | void>;
17
+ private createWebRequest;
18
+ private sendNodeResponse;
19
+ fetch(request: Request): Promise<Response>;
20
+ }
21
+ export declare function createNodeApp(options: EcopagesAppOptions): Promise<EcopagesApp>;
@@ -0,0 +1,143 @@
1
+ import { createServer } from "node:http";
2
+ import { Readable } from "node:stream";
3
+ import { DEFAULT_ECOPAGES_HOSTNAME, DEFAULT_ECOPAGES_PORT } from "../../constants.js";
4
+ import { appLogger } from "../../global/app-logger.js";
5
+ import {} from "../abstract/application-adapter.js";
6
+ import { SharedApplicationAdapter } from "../shared/application-adapter.js";
7
+ import { createNodeServerAdapter } from "./server-adapter.js";
8
+ class EcopagesApp extends SharedApplicationAdapter {
9
+ serverAdapter;
10
+ server = null;
11
+ runtimeOrigin = "";
12
+ async stop(force = true) {
13
+ if (!this.server) {
14
+ return;
15
+ }
16
+ const activeServer = this.server;
17
+ this.server = null;
18
+ await new Promise((resolve, reject) => {
19
+ activeServer.close((error) => {
20
+ if (error) {
21
+ reject(error);
22
+ return;
23
+ }
24
+ resolve();
25
+ });
26
+ if (force) {
27
+ activeServer.closeAllConnections();
28
+ }
29
+ });
30
+ }
31
+ async initializeServerAdapter() {
32
+ const { dev } = this.cliArgs;
33
+ const { port: cliPort, hostname: cliHostname } = this.cliArgs;
34
+ const envPort = process.env.ECOPAGES_PORT;
35
+ const envHostname = process.env.ECOPAGES_HOSTNAME;
36
+ const preferredPort = cliPort ?? (envPort ? Number(envPort) : void 0) ?? DEFAULT_ECOPAGES_PORT;
37
+ const preferredHostname = cliHostname ?? envHostname ?? DEFAULT_ECOPAGES_HOSTNAME;
38
+ this.runtimeOrigin = `http://${preferredHostname}:${preferredPort}`;
39
+ return createNodeServerAdapter({
40
+ runtimeOrigin: this.runtimeOrigin,
41
+ appConfig: this.appConfig,
42
+ apiHandlers: this.apiHandlers,
43
+ staticRoutes: this.staticRoutes,
44
+ errorHandler: this.errorHandler,
45
+ options: { watch: dev },
46
+ serveOptions: {
47
+ port: preferredPort,
48
+ hostname: preferredHostname,
49
+ ...this.serverOptions
50
+ }
51
+ });
52
+ }
53
+ async start() {
54
+ if (!this.serverAdapter) {
55
+ this.serverAdapter = await this.initializeServerAdapter();
56
+ }
57
+ if (this.server) {
58
+ return this.server;
59
+ }
60
+ const { build, preview } = this.cliArgs;
61
+ if (build || preview) {
62
+ appLogger.debugTime("Building static pages");
63
+ await this.serverAdapter.buildStatic({ preview });
64
+ await this.stop(true);
65
+ appLogger.debugTimeEnd("Building static pages");
66
+ if (build) {
67
+ process.exit(0);
68
+ }
69
+ return;
70
+ }
71
+ const serveOptions = this.serverAdapter.getServerOptions();
72
+ const hostname = String(serveOptions.hostname ?? DEFAULT_ECOPAGES_HOSTNAME);
73
+ const port = Number(serveOptions.port ?? DEFAULT_ECOPAGES_PORT);
74
+ this.runtimeOrigin = `http://${hostname}:${port}`;
75
+ this.server = createServer(async (req, res) => {
76
+ try {
77
+ const webRequest = this.createWebRequest(req);
78
+ const response = await this.serverAdapter.handleRequest(webRequest);
79
+ await this.sendNodeResponse(res, response);
80
+ } catch (error) {
81
+ appLogger.error("Node server adapter request failed", error);
82
+ res.statusCode = 500;
83
+ res.end("Internal Server Error");
84
+ }
85
+ });
86
+ await new Promise((resolve) => {
87
+ this.server.listen(port, hostname, () => resolve());
88
+ });
89
+ await this.serverAdapter.completeInitialization(this.server);
90
+ appLogger.info(`Node server running at ${this.runtimeOrigin}`);
91
+ return this.server;
92
+ }
93
+ createWebRequest(req) {
94
+ const url = new URL(req.url ?? "/", this.runtimeOrigin);
95
+ const headers = new Headers();
96
+ for (const [key, value] of Object.entries(req.headers)) {
97
+ if (Array.isArray(value)) {
98
+ for (const item of value) {
99
+ headers.append(key, item);
100
+ }
101
+ continue;
102
+ }
103
+ if (value !== void 0) {
104
+ headers.set(key, value);
105
+ }
106
+ }
107
+ const method = (req.method ?? "GET").toUpperCase();
108
+ const requestInit = {
109
+ method,
110
+ headers
111
+ };
112
+ if (method !== "GET" && method !== "HEAD") {
113
+ requestInit.body = Readable.toWeb(req);
114
+ requestInit.duplex = "half";
115
+ }
116
+ return new Request(url, requestInit);
117
+ }
118
+ async sendNodeResponse(res, response) {
119
+ res.statusCode = response.status;
120
+ response.headers.forEach((value, key) => {
121
+ res.setHeader(key, value);
122
+ });
123
+ if (!response.body) {
124
+ res.end();
125
+ return;
126
+ }
127
+ const body = Buffer.from(await response.arrayBuffer());
128
+ res.end(body);
129
+ }
130
+ async fetch(request) {
131
+ if (!this.serverAdapter) {
132
+ this.serverAdapter = await this.initializeServerAdapter();
133
+ }
134
+ return this.serverAdapter.handleRequest(request);
135
+ }
136
+ }
137
+ async function createNodeApp(options) {
138
+ return new EcopagesApp(options);
139
+ }
140
+ export {
141
+ EcopagesApp,
142
+ createNodeApp
143
+ };
@@ -0,0 +1,179 @@
1
+ import { createServer, type IncomingMessage, type Server as NodeServerInstance, type ServerResponse } from 'node:http';
2
+ import { Readable } from 'node:stream';
3
+ import { DEFAULT_ECOPAGES_HOSTNAME, DEFAULT_ECOPAGES_PORT } from '../../constants.ts';
4
+ import { appLogger } from '../../global/app-logger.ts';
5
+ import type { EcoPagesAppConfig } from '../../internal-types.ts';
6
+ import type { StaticRoute } from '../../public-types.ts';
7
+ import { type ApplicationAdapterOptions } from '../abstract/application-adapter.ts';
8
+ import { SharedApplicationAdapter } from '../shared/application-adapter.ts';
9
+ import { type NodeServerAdapterResult, createNodeServerAdapter } from './server-adapter.ts';
10
+
11
+ export interface EcopagesAppOptions extends ApplicationAdapterOptions {
12
+ appConfig: EcoPagesAppConfig;
13
+ serverOptions?: Record<string, any>;
14
+ }
15
+
16
+ export class EcopagesApp extends SharedApplicationAdapter<EcopagesAppOptions, NodeServerInstance, Request> {
17
+ serverAdapter: NodeServerAdapterResult | undefined;
18
+ private server: NodeServerInstance | null = null;
19
+ private runtimeOrigin = '';
20
+
21
+ public async stop(force = true): Promise<void> {
22
+ if (!this.server) {
23
+ return;
24
+ }
25
+
26
+ const activeServer = this.server;
27
+ this.server = null;
28
+
29
+ await new Promise<void>((resolve, reject) => {
30
+ activeServer.close((error) => {
31
+ if (error) {
32
+ reject(error);
33
+ return;
34
+ }
35
+
36
+ resolve();
37
+ });
38
+
39
+ if (force) {
40
+ activeServer.closeAllConnections();
41
+ }
42
+ });
43
+ }
44
+
45
+ protected async initializeServerAdapter(): Promise<NodeServerAdapterResult> {
46
+ const { dev } = this.cliArgs;
47
+ const { port: cliPort, hostname: cliHostname } = this.cliArgs;
48
+
49
+ const envPort = process.env.ECOPAGES_PORT;
50
+ const envHostname = process.env.ECOPAGES_HOSTNAME;
51
+
52
+ const preferredPort = cliPort ?? (envPort ? Number(envPort) : undefined) ?? DEFAULT_ECOPAGES_PORT;
53
+ const preferredHostname = cliHostname ?? envHostname ?? DEFAULT_ECOPAGES_HOSTNAME;
54
+ this.runtimeOrigin = `http://${preferredHostname}:${preferredPort}`;
55
+
56
+ return createNodeServerAdapter({
57
+ runtimeOrigin: this.runtimeOrigin,
58
+ appConfig: this.appConfig,
59
+ apiHandlers: this.apiHandlers,
60
+ staticRoutes: this.staticRoutes as StaticRoute[],
61
+ errorHandler: this.errorHandler,
62
+ options: { watch: dev },
63
+ serveOptions: {
64
+ port: preferredPort,
65
+ hostname: preferredHostname,
66
+ ...this.serverOptions,
67
+ },
68
+ });
69
+ }
70
+
71
+ public async start(): Promise<NodeServerInstance | void> {
72
+ if (!this.serverAdapter) {
73
+ this.serverAdapter = await this.initializeServerAdapter();
74
+ }
75
+
76
+ if (this.server) {
77
+ return this.server;
78
+ }
79
+
80
+ const { build, preview } = this.cliArgs;
81
+
82
+ if (build || preview) {
83
+ appLogger.debugTime('Building static pages');
84
+ await this.serverAdapter.buildStatic({ preview });
85
+ await this.stop(true);
86
+ appLogger.debugTimeEnd('Building static pages');
87
+
88
+ if (build) {
89
+ process.exit(0);
90
+ }
91
+ return;
92
+ }
93
+
94
+ const serveOptions = this.serverAdapter.getServerOptions();
95
+ const hostname = String(serveOptions.hostname ?? DEFAULT_ECOPAGES_HOSTNAME);
96
+ const port = Number(serveOptions.port ?? DEFAULT_ECOPAGES_PORT);
97
+ this.runtimeOrigin = `http://${hostname}:${port}`;
98
+
99
+ this.server = createServer(async (req, res) => {
100
+ try {
101
+ const webRequest = this.createWebRequest(req);
102
+ const response = await this.serverAdapter!.handleRequest(webRequest);
103
+ await this.sendNodeResponse(res, response);
104
+ } catch (error) {
105
+ appLogger.error('Node server adapter request failed', error as Error);
106
+ res.statusCode = 500;
107
+ res.end('Internal Server Error');
108
+ }
109
+ });
110
+
111
+ await new Promise<void>((resolve) => {
112
+ this.server!.listen(port, hostname, () => resolve());
113
+ });
114
+
115
+ await this.serverAdapter.completeInitialization(this.server);
116
+ appLogger.info(`Node server running at ${this.runtimeOrigin}`);
117
+
118
+ return this.server;
119
+ }
120
+
121
+ private createWebRequest(req: IncomingMessage): Request {
122
+ const url = new URL(req.url ?? '/', this.runtimeOrigin);
123
+ const headers = new Headers();
124
+
125
+ for (const [key, value] of Object.entries(req.headers)) {
126
+ if (Array.isArray(value)) {
127
+ for (const item of value) {
128
+ headers.append(key, item);
129
+ }
130
+ continue;
131
+ }
132
+
133
+ if (value !== undefined) {
134
+ headers.set(key, value);
135
+ }
136
+ }
137
+
138
+ const method = (req.method ?? 'GET').toUpperCase();
139
+ const requestInit: RequestInit & { duplex?: 'half' } = {
140
+ method,
141
+ headers,
142
+ };
143
+
144
+ if (method !== 'GET' && method !== 'HEAD') {
145
+ requestInit.body = Readable.toWeb(req) as unknown as BodyInit;
146
+ requestInit.duplex = 'half';
147
+ }
148
+
149
+ return new Request(url, requestInit);
150
+ }
151
+
152
+ private async sendNodeResponse(res: ServerResponse, response: Response): Promise<void> {
153
+ res.statusCode = response.status;
154
+
155
+ response.headers.forEach((value, key) => {
156
+ res.setHeader(key, value);
157
+ });
158
+
159
+ if (!response.body) {
160
+ res.end();
161
+ return;
162
+ }
163
+
164
+ const body = Buffer.from(await response.arrayBuffer());
165
+ res.end(body);
166
+ }
167
+
168
+ public async fetch(request: Request): Promise<Response> {
169
+ if (!this.serverAdapter) {
170
+ this.serverAdapter = await this.initializeServerAdapter();
171
+ }
172
+
173
+ return this.serverAdapter.handleRequest(request);
174
+ }
175
+ }
176
+
177
+ export async function createNodeApp(options: EcopagesAppOptions): Promise<EcopagesApp> {
178
+ return new EcopagesApp(options);
179
+ }
@@ -0,0 +1,4 @@
1
+ export { NodeServerAdapter, createNodeServerAdapter } from './server-adapter.js';
2
+ export { EcopagesApp, createNodeApp } from './create-app.js';
3
+ export type { EcopagesAppOptions } from './create-app.js';
4
+ export type { NodeServerAdapterParams, NodeServerAdapterResult, NodeServerInstance, NodeServeAdapterServerOptions, } from './server-adapter.js';
@@ -0,0 +1,8 @@
1
+ import { NodeServerAdapter, createNodeServerAdapter } from "./server-adapter.js";
2
+ import { EcopagesApp, createNodeApp } from "./create-app.js";
3
+ export {
4
+ EcopagesApp,
5
+ NodeServerAdapter,
6
+ createNodeApp,
7
+ createNodeServerAdapter
8
+ };
@@ -0,0 +1,9 @@
1
+ export { NodeServerAdapter, createNodeServerAdapter } from './server-adapter.ts';
2
+ export { EcopagesApp, createNodeApp } from './create-app.ts';
3
+ export type { EcopagesAppOptions } from './create-app.ts';
4
+ export type {
5
+ NodeServerAdapterParams,
6
+ NodeServerAdapterResult,
7
+ NodeServerInstance,
8
+ NodeServeAdapterServerOptions,
9
+ } from './server-adapter.ts';
@@ -0,0 +1,26 @@
1
+ import type { WebSocket } from 'ws';
2
+ import type { ClientBridgeEvent, IClientBridge } from '../../public-types.js';
3
+ export declare class NodeClientBridge implements IClientBridge {
4
+ private subscribers;
5
+ private heartbeatTimer;
6
+ constructor();
7
+ /**
8
+ * Pings all open subscribers and removes any that are no longer in OPEN state.
9
+ * This prevents a slow memory leak caused by zombie connections that never
10
+ * send a close event (e.g. abruptly killed browsers, orphaned tabs, network drops).
11
+ */
12
+ private sweep;
13
+ subscribe(ws: WebSocket): void;
14
+ unsubscribe(ws: WebSocket): void;
15
+ broadcast(event: ClientBridgeEvent): void;
16
+ reload(): void;
17
+ cssUpdate(path: string): void;
18
+ update(path: string): void;
19
+ error(message: string): void;
20
+ get subscriberCount(): number;
21
+ /**
22
+ * Stops the heartbeat timer and clears all subscribers.
23
+ * Call this when the dev server is shutting down.
24
+ */
25
+ destroy(): void;
26
+ }
@@ -0,0 +1,66 @@
1
+ const HEARTBEAT_INTERVAL_MS = 3e4;
2
+ class NodeClientBridge {
3
+ subscribers = /* @__PURE__ */ new Set();
4
+ heartbeatTimer = null;
5
+ constructor() {
6
+ this.heartbeatTimer = setInterval(() => this.sweep(), HEARTBEAT_INTERVAL_MS);
7
+ this.heartbeatTimer.unref?.();
8
+ }
9
+ /**
10
+ * Pings all open subscribers and removes any that are no longer in OPEN state.
11
+ * This prevents a slow memory leak caused by zombie connections that never
12
+ * send a close event (e.g. abruptly killed browsers, orphaned tabs, network drops).
13
+ */
14
+ sweep() {
15
+ for (const ws of this.subscribers) {
16
+ if (ws.readyState !== 1) {
17
+ this.subscribers.delete(ws);
18
+ continue;
19
+ }
20
+ ws.ping();
21
+ }
22
+ }
23
+ subscribe(ws) {
24
+ this.subscribers.add(ws);
25
+ }
26
+ unsubscribe(ws) {
27
+ this.subscribers.delete(ws);
28
+ }
29
+ broadcast(event) {
30
+ const payload = JSON.stringify(event);
31
+ for (const ws of this.subscribers) {
32
+ if (ws.readyState === 1) {
33
+ ws.send(payload);
34
+ }
35
+ }
36
+ }
37
+ reload() {
38
+ this.broadcast({ type: "reload" });
39
+ }
40
+ cssUpdate(path) {
41
+ this.broadcast({ type: "css-update", path, timestamp: Date.now() });
42
+ }
43
+ update(path) {
44
+ this.broadcast({ type: "update", path, timestamp: Date.now() });
45
+ }
46
+ error(message) {
47
+ this.broadcast({ type: "error", message });
48
+ }
49
+ get subscriberCount() {
50
+ return this.subscribers.size;
51
+ }
52
+ /**
53
+ * Stops the heartbeat timer and clears all subscribers.
54
+ * Call this when the dev server is shutting down.
55
+ */
56
+ destroy() {
57
+ if (this.heartbeatTimer !== null) {
58
+ clearInterval(this.heartbeatTimer);
59
+ this.heartbeatTimer = null;
60
+ }
61
+ this.subscribers.clear();
62
+ }
63
+ }
64
+ export {
65
+ NodeClientBridge
66
+ };