@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,128 @@
1
+ import { getCacheControlHeader, type PageCacheService } from './cache/page-cache-service.ts';
2
+ import type { CacheStrategy, RenderResult } from './cache/cache.types.ts';
3
+
4
+ type CacheStatus = 'hit' | 'miss' | 'stale' | 'expired' | 'disabled';
5
+
6
+ /**
7
+ * Coordinates request-time page caching concerns around one render invocation.
8
+ *
9
+ * This service keeps `FileSystemResponseMatcher` from owning low-level cache
10
+ * policy mechanics such as cache key construction, `dynamic` bypass behavior,
11
+ * body normalization for cache storage, and final cache header generation.
12
+ */
13
+ export class PageRequestCacheCoordinator {
14
+ constructor(
15
+ private cacheService: PageCacheService | null,
16
+ private defaultCacheStrategy: CacheStrategy,
17
+ ) {}
18
+
19
+ /**
20
+ * Builds the cache key used for page lookups.
21
+ *
22
+ * Query parameters are part of the key so two requests that hit the same
23
+ * pathname but differ by search params do not share the same rendered entry.
24
+ *
25
+ * @param input Pathname plus optional query record.
26
+ * @returns Stable cache key for the request.
27
+ */
28
+ buildCacheKey(input: { pathname: string; query?: Record<string, string> }): string {
29
+ let key = input.pathname;
30
+ if (input.query && Object.keys(input.query).length > 0) {
31
+ const queryString = new URLSearchParams(input.query).toString();
32
+ key += `?${queryString}`;
33
+ }
34
+ return key;
35
+ }
36
+
37
+ /**
38
+ * Resolves a render request through the configured cache policy.
39
+ *
40
+ * Pages using `dynamic` rendering, or applications without a cache service,
41
+ * bypass cache lookup entirely and still receive the same response header
42
+ * contract as cached pages.
43
+ *
44
+ * @param options Cache coordination inputs for one page request.
45
+ * @returns HTTP response with cache headers applied.
46
+ */
47
+ async render(options: {
48
+ cacheKey: string;
49
+ pageCacheStrategy: CacheStrategy;
50
+ renderFn: () => Promise<RenderResult>;
51
+ }): Promise<Response> {
52
+ if (!this.cacheService || options.pageCacheStrategy === 'dynamic') {
53
+ const { html, strategy } = await options.renderFn();
54
+ return this.createCachedResponse(html, strategy, 'disabled');
55
+ }
56
+
57
+ const result = await this.cacheService.getOrCreate(
58
+ options.cacheKey,
59
+ options.pageCacheStrategy,
60
+ options.renderFn,
61
+ );
62
+
63
+ return this.createCachedResponse(result.html, result.strategy, result.status);
64
+ }
65
+
66
+ /**
67
+ * Exposes the underlying cache service for invalidation and adapter plumbing.
68
+ *
69
+ * @returns Configured cache service or `null` when caching is disabled.
70
+ */
71
+ getCacheService(): PageCacheService | null {
72
+ return this.cacheService;
73
+ }
74
+
75
+ /**
76
+ * Returns the default render strategy used when a page does not declare one.
77
+ *
78
+ * @returns Application-level fallback cache strategy.
79
+ */
80
+ getDefaultCacheStrategy(): CacheStrategy {
81
+ return this.defaultCacheStrategy;
82
+ }
83
+
84
+ /**
85
+ * Normalizes various route render body shapes into a cacheable string.
86
+ *
87
+ * Page rendering may produce strings, buffers, byte arrays, or streams. The
88
+ * matcher needs a single representation before passing HTML through the cache
89
+ * layer, so this method centralizes the conversion rules.
90
+ *
91
+ * @param body Render output body in any supported form.
92
+ * @returns HTML string representation.
93
+ */
94
+ async bodyToString(body: unknown): Promise<string> {
95
+ if (typeof body === 'string') {
96
+ return body;
97
+ }
98
+ if (Buffer.isBuffer(body)) {
99
+ return body.toString('utf-8');
100
+ }
101
+ if (body instanceof ReadableStream) {
102
+ return new Response(body).text();
103
+ }
104
+ if (body instanceof Uint8Array) {
105
+ return new TextDecoder().decode(body);
106
+ }
107
+ return String(body);
108
+ }
109
+
110
+ /**
111
+ * Creates the final HTML response with the current cache semantics encoded in
112
+ * response headers.
113
+ *
114
+ * @param html Rendered page HTML.
115
+ * @param strategy Effective cache strategy for the response.
116
+ * @param cacheStatus Status used for `X-Cache` and `Cache-Control` generation.
117
+ * @returns HTTP response ready to send to the client.
118
+ */
119
+ private createCachedResponse(html: string, strategy: CacheStrategy, cacheStatus: CacheStatus): Response {
120
+ const headers: HeadersInit = {
121
+ 'Content-Type': 'text/html',
122
+ 'Cache-Control': getCacheControlHeader(cacheStatus === 'disabled' ? 'disabled' : strategy),
123
+ 'X-Cache': cacheStatus.toUpperCase(),
124
+ };
125
+
126
+ return new Response(html, { headers });
127
+ }
128
+ }
@@ -0,0 +1,122 @@
1
+ import type { StandardSchema } from './validation/standard-schema.types.js';
2
+ export interface ValidationResult<T = unknown> {
3
+ success: boolean;
4
+ data?: T;
5
+ errors?: Array<{
6
+ message: string;
7
+ path?: Array<string | number>;
8
+ }>;
9
+ }
10
+ export interface ValidationSource {
11
+ body?: unknown;
12
+ query?: Record<string, string>;
13
+ headers?: Record<string, string>;
14
+ params?: Record<string, string>;
15
+ }
16
+ export interface ValidationSchemas {
17
+ body?: StandardSchema;
18
+ query?: StandardSchema;
19
+ headers?: StandardSchema;
20
+ params?: StandardSchema;
21
+ }
22
+ export interface ValidatedData {
23
+ body?: unknown;
24
+ query?: unknown;
25
+ headers?: unknown;
26
+ params?: unknown;
27
+ }
28
+ /**
29
+ * Service for validating request data using Standard Schema compliant validators.
30
+ *
31
+ * This service provides a unified interface for validating HTTP request data (body, query parameters, headers)
32
+ * using any validation library that implements the Standard Schema specification.
33
+ *
34
+ * @example Using with Zod
35
+ * ```typescript
36
+ * import { z } from 'zod';
37
+ * import { SchemaValidationService } from './schema-validation-service.js';
38
+ *
39
+ * const service = new SchemaValidationService();
40
+ * const result = await service.validateRequest(
41
+ * { body: { title: 'Hello', count: 42 } },
42
+ * { body: z.object({ title: z.string(), count: z.number() }) }
43
+ * );
44
+ *
45
+ * if (result.success) {
46
+ * console.log(result.data.body);
47
+ * }
48
+ * ```
49
+ *
50
+ * @example Using with Valibot
51
+ * ```typescript
52
+ * import * as v from 'valibot';
53
+ *
54
+ * const result = await service.validateRequest(
55
+ * { query: { page: '1' } },
56
+ * { query: v.object({ page: v.string() }) }
57
+ * );
58
+ * ```
59
+ *
60
+ * @example Using with ArkType
61
+ * ```typescript
62
+ * import { type } from 'arktype';
63
+ *
64
+ * const result = await service.validateRequest(
65
+ * { headers: { 'authorization': 'Bearer token' } },
66
+ * { headers: type({ authorization: 'string' }) }
67
+ * );
68
+ * ```
69
+ *
70
+ * @example Multiple sources
71
+ * ```typescript
72
+ * const result = await service.validateRequest(
73
+ * {
74
+ * body: { title: 'Post' },
75
+ * query: { format: 'json' },
76
+ * headers: { 'content-type': 'application/json' }
77
+ * },
78
+ * {
79
+ * body: z.object({ title: z.string() }),
80
+ * query: v.object({ format: v.string() }),
81
+ * headers: type({ 'content-type': 'string' })
82
+ * }
83
+ * );
84
+ * ```
85
+ *
86
+ * Supported libraries: Zod, Valibot, ArkType, Effect Schema (with standardSchemaV1 wrapper)
87
+ */
88
+ export declare class SchemaValidationService {
89
+ /**
90
+ * Validates request data against provided schemas.
91
+ *
92
+ * Validates body, query parameters, and headers against their respective schemas.
93
+ * All validations are performed, and errors are aggregated from all sources.
94
+ *
95
+ * @param source - The data to validate (body, query, headers)
96
+ * @param schemas - The Standard Schema validators for each source
97
+ * @returns Validation result with validated data or aggregated errors
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * const result = await service.validateRequest(
102
+ * { body: { name: 'John', age: 30 } },
103
+ * { body: z.object({ name: z.string(), age: z.number() }) }
104
+ * );
105
+ *
106
+ * if (result.success) {
107
+ * const validated = result.data.body;
108
+ * } else {
109
+ * console.error(result.errors);
110
+ * }
111
+ * ```
112
+ */
113
+ validateRequest(source: ValidationSource, schemas: ValidationSchemas): Promise<ValidationResult<ValidatedData>>;
114
+ /**
115
+ * Validates a single value against a Standard Schema.
116
+ *
117
+ * @param schema - The Standard Schema validator
118
+ * @param data - The data to validate
119
+ * @returns Validation result with validated data or errors
120
+ */
121
+ private validateWithSchema;
122
+ }
@@ -0,0 +1,101 @@
1
+ class SchemaValidationService {
2
+ /**
3
+ * Validates request data against provided schemas.
4
+ *
5
+ * Validates body, query parameters, and headers against their respective schemas.
6
+ * All validations are performed, and errors are aggregated from all sources.
7
+ *
8
+ * @param source - The data to validate (body, query, headers)
9
+ * @param schemas - The Standard Schema validators for each source
10
+ * @returns Validation result with validated data or aggregated errors
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const result = await service.validateRequest(
15
+ * { body: { name: 'John', age: 30 } },
16
+ * { body: z.object({ name: z.string(), age: z.number() }) }
17
+ * );
18
+ *
19
+ * if (result.success) {
20
+ * const validated = result.data.body;
21
+ * } else {
22
+ * console.error(result.errors);
23
+ * }
24
+ * ```
25
+ */
26
+ async validateRequest(source, schemas) {
27
+ const validated = {};
28
+ const allErrors = [];
29
+ if (schemas.body && source.body !== void 0) {
30
+ const result = await this.validateWithSchema(schemas.body, source.body);
31
+ if (!result.success) {
32
+ allErrors.push(...result.errors || []);
33
+ } else {
34
+ validated.body = result.data;
35
+ }
36
+ }
37
+ if (schemas.query && source.query) {
38
+ const result = await this.validateWithSchema(schemas.query, source.query);
39
+ if (!result.success) {
40
+ allErrors.push(...result.errors || []);
41
+ } else {
42
+ validated.query = result.data;
43
+ }
44
+ }
45
+ if (schemas.headers && source.headers) {
46
+ const result = await this.validateWithSchema(schemas.headers, source.headers);
47
+ if (!result.success) {
48
+ allErrors.push(...result.errors || []);
49
+ } else {
50
+ validated.headers = result.data;
51
+ }
52
+ }
53
+ if (schemas.params && source.params) {
54
+ const result = await this.validateWithSchema(schemas.params, source.params);
55
+ if (!result.success) {
56
+ allErrors.push(...result.errors || []);
57
+ } else {
58
+ validated.params = result.data;
59
+ }
60
+ }
61
+ if (allErrors.length > 0) {
62
+ return { success: false, errors: allErrors };
63
+ }
64
+ return { success: true, data: validated };
65
+ }
66
+ /**
67
+ * Validates a single value against a Standard Schema.
68
+ *
69
+ * @param schema - The Standard Schema validator
70
+ * @param data - The data to validate
71
+ * @returns Validation result with validated data or errors
72
+ */
73
+ async validateWithSchema(schema, data) {
74
+ try {
75
+ const resultOrPromise = schema["~standard"].validate(data);
76
+ const result = resultOrPromise instanceof Promise ? await resultOrPromise : resultOrPromise;
77
+ if (result.issues) {
78
+ return {
79
+ success: false,
80
+ errors: result.issues.map((issue) => ({
81
+ message: issue.message,
82
+ path: issue.path?.map((p) => typeof p === "object" && "key" in p ? p.key : p)
83
+ }))
84
+ };
85
+ }
86
+ return { success: true, data: result.value };
87
+ } catch (error) {
88
+ return {
89
+ success: false,
90
+ errors: [
91
+ {
92
+ message: error instanceof Error ? error.message : "Validation failed"
93
+ }
94
+ ]
95
+ };
96
+ }
97
+ }
98
+ }
99
+ export {
100
+ SchemaValidationService
101
+ };
@@ -0,0 +1,204 @@
1
+ import type { StandardSchema, StandardSchemaIssue } from './validation/standard-schema.types.ts';
2
+
3
+ export interface ValidationResult<T = unknown> {
4
+ success: boolean;
5
+ data?: T;
6
+ errors?: Array<{
7
+ message: string;
8
+ path?: Array<string | number>;
9
+ }>;
10
+ }
11
+
12
+ export interface ValidationSource {
13
+ body?: unknown;
14
+ query?: Record<string, string>;
15
+ headers?: Record<string, string>;
16
+ params?: Record<string, string>;
17
+ }
18
+
19
+ export interface ValidationSchemas {
20
+ body?: StandardSchema;
21
+ query?: StandardSchema;
22
+ headers?: StandardSchema;
23
+ params?: StandardSchema;
24
+ }
25
+
26
+ export interface ValidatedData {
27
+ body?: unknown;
28
+ query?: unknown;
29
+ headers?: unknown;
30
+ params?: unknown;
31
+ }
32
+
33
+ /**
34
+ * Service for validating request data using Standard Schema compliant validators.
35
+ *
36
+ * This service provides a unified interface for validating HTTP request data (body, query parameters, headers)
37
+ * using any validation library that implements the Standard Schema specification.
38
+ *
39
+ * @example Using with Zod
40
+ * ```typescript
41
+ * import { z } from 'zod';
42
+ * import { SchemaValidationService } from './schema-validation-service.ts';
43
+ *
44
+ * const service = new SchemaValidationService();
45
+ * const result = await service.validateRequest(
46
+ * { body: { title: 'Hello', count: 42 } },
47
+ * { body: z.object({ title: z.string(), count: z.number() }) }
48
+ * );
49
+ *
50
+ * if (result.success) {
51
+ * console.log(result.data.body);
52
+ * }
53
+ * ```
54
+ *
55
+ * @example Using with Valibot
56
+ * ```typescript
57
+ * import * as v from 'valibot';
58
+ *
59
+ * const result = await service.validateRequest(
60
+ * { query: { page: '1' } },
61
+ * { query: v.object({ page: v.string() }) }
62
+ * );
63
+ * ```
64
+ *
65
+ * @example Using with ArkType
66
+ * ```typescript
67
+ * import { type } from 'arktype';
68
+ *
69
+ * const result = await service.validateRequest(
70
+ * { headers: { 'authorization': 'Bearer token' } },
71
+ * { headers: type({ authorization: 'string' }) }
72
+ * );
73
+ * ```
74
+ *
75
+ * @example Multiple sources
76
+ * ```typescript
77
+ * const result = await service.validateRequest(
78
+ * {
79
+ * body: { title: 'Post' },
80
+ * query: { format: 'json' },
81
+ * headers: { 'content-type': 'application/json' }
82
+ * },
83
+ * {
84
+ * body: z.object({ title: z.string() }),
85
+ * query: v.object({ format: v.string() }),
86
+ * headers: type({ 'content-type': 'string' })
87
+ * }
88
+ * );
89
+ * ```
90
+ *
91
+ * Supported libraries: Zod, Valibot, ArkType, Effect Schema (with standardSchemaV1 wrapper)
92
+ */
93
+ export class SchemaValidationService {
94
+ /**
95
+ * Validates request data against provided schemas.
96
+ *
97
+ * Validates body, query parameters, and headers against their respective schemas.
98
+ * All validations are performed, and errors are aggregated from all sources.
99
+ *
100
+ * @param source - The data to validate (body, query, headers)
101
+ * @param schemas - The Standard Schema validators for each source
102
+ * @returns Validation result with validated data or aggregated errors
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * const result = await service.validateRequest(
107
+ * { body: { name: 'John', age: 30 } },
108
+ * { body: z.object({ name: z.string(), age: z.number() }) }
109
+ * );
110
+ *
111
+ * if (result.success) {
112
+ * const validated = result.data.body;
113
+ * } else {
114
+ * console.error(result.errors);
115
+ * }
116
+ * ```
117
+ */
118
+ async validateRequest(
119
+ source: ValidationSource,
120
+ schemas: ValidationSchemas,
121
+ ): Promise<ValidationResult<ValidatedData>> {
122
+ const validated: ValidatedData = {};
123
+ const allErrors: Array<{ message: string; path?: Array<string | number> }> = [];
124
+
125
+ if (schemas.body && source.body !== undefined) {
126
+ const result = await this.validateWithSchema(schemas.body, source.body);
127
+ if (!result.success) {
128
+ allErrors.push(...(result.errors || []));
129
+ } else {
130
+ validated.body = result.data;
131
+ }
132
+ }
133
+
134
+ if (schemas.query && source.query) {
135
+ const result = await this.validateWithSchema(schemas.query, source.query);
136
+ if (!result.success) {
137
+ allErrors.push(...(result.errors || []));
138
+ } else {
139
+ validated.query = result.data;
140
+ }
141
+ }
142
+
143
+ if (schemas.headers && source.headers) {
144
+ const result = await this.validateWithSchema(schemas.headers, source.headers);
145
+ if (!result.success) {
146
+ allErrors.push(...(result.errors || []));
147
+ } else {
148
+ validated.headers = result.data;
149
+ }
150
+ }
151
+
152
+ if (schemas.params && source.params) {
153
+ const result = await this.validateWithSchema(schemas.params, source.params);
154
+ if (!result.success) {
155
+ allErrors.push(...(result.errors || []));
156
+ } else {
157
+ validated.params = result.data;
158
+ }
159
+ }
160
+
161
+ if (allErrors.length > 0) {
162
+ return { success: false, errors: allErrors };
163
+ }
164
+
165
+ return { success: true, data: validated };
166
+ }
167
+
168
+ /**
169
+ * Validates a single value against a Standard Schema.
170
+ *
171
+ * @param schema - The Standard Schema validator
172
+ * @param data - The data to validate
173
+ * @returns Validation result with validated data or errors
174
+ */
175
+ private async validateWithSchema<T>(schema: StandardSchema, data: unknown): Promise<ValidationResult<T>> {
176
+ try {
177
+ const resultOrPromise = schema['~standard'].validate(data);
178
+ const result = resultOrPromise instanceof Promise ? await resultOrPromise : resultOrPromise;
179
+
180
+ if (result.issues) {
181
+ return {
182
+ success: false,
183
+ errors: result.issues.map((issue: StandardSchemaIssue) => ({
184
+ message: issue.message,
185
+ path: issue.path?.map((p) => (typeof p === 'object' && 'key' in p ? p.key : p)) as
186
+ | Array<string | number>
187
+ | undefined,
188
+ })),
189
+ };
190
+ }
191
+
192
+ return { success: true, data: result.value as T };
193
+ } catch (error) {
194
+ return {
195
+ success: false,
196
+ errors: [
197
+ {
198
+ message: error instanceof Error ? error.message : 'Validation failed',
199
+ },
200
+ ],
201
+ };
202
+ }
203
+ }
204
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Standard Schema interface for universal validation.
3
+ * Compatible with Zod, Valibot, ArkType, Effect Schema, and other validation libraries.
4
+ *
5
+ * @see https://standardschema.dev
6
+ *
7
+ * @example Using with Zod
8
+ * ```typescript
9
+ * import { z } from 'zod';
10
+ *
11
+ * const bodySchema = z.object({
12
+ * title: z.string().min(1),
13
+ * content: z.string()
14
+ * });
15
+ *
16
+ * app.post('/posts', async (ctx) => {
17
+ * const { title, content } = ctx.body;
18
+ * return ctx.json({ id: 1, title, content });
19
+ * }, {
20
+ * schema: { body: bodySchema }
21
+ * });
22
+ * ```
23
+ */
24
+ export interface StandardSchema<Input = unknown, Output = Input> {
25
+ readonly '~standard': {
26
+ readonly version: 1;
27
+ readonly vendor: string;
28
+ readonly validate: (value: unknown) => StandardSchemaResult<Output> | Promise<StandardSchemaResult<Output>>;
29
+ readonly types?: {
30
+ readonly input: Input;
31
+ readonly output: Output;
32
+ };
33
+ };
34
+ }
35
+ /**
36
+ * Result of Standard Schema validation.
37
+ */
38
+ export type StandardSchemaResult<Output> = StandardSchemaSuccessResult<Output> | StandardSchemaFailureResult;
39
+ /**
40
+ * Successful validation result.
41
+ */
42
+ export interface StandardSchemaSuccessResult<Output> {
43
+ readonly value: Output;
44
+ readonly issues?: undefined;
45
+ }
46
+ /**
47
+ * Failed validation result.
48
+ */
49
+ export interface StandardSchemaFailureResult {
50
+ readonly value?: undefined;
51
+ readonly issues: ReadonlyArray<StandardSchemaIssue>;
52
+ }
53
+ /**
54
+ * Validation issue details.
55
+ */
56
+ export interface StandardSchemaIssue {
57
+ readonly message: string;
58
+ readonly path?: ReadonlyArray<PropertyKey | {
59
+ key: PropertyKey;
60
+ }>;
61
+ }
62
+ /**
63
+ * Infers the output type from a Standard Schema.
64
+ */
65
+ export type InferOutput<T extends StandardSchema> = T extends StandardSchema<any, infer O> ? O : never;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Standard Schema interface for universal validation.
3
+ * Compatible with Zod, Valibot, ArkType, Effect Schema, and other validation libraries.
4
+ *
5
+ * @see https://standardschema.dev
6
+ *
7
+ * @example Using with Zod
8
+ * ```typescript
9
+ * import { z } from 'zod';
10
+ *
11
+ * const bodySchema = z.object({
12
+ * title: z.string().min(1),
13
+ * content: z.string()
14
+ * });
15
+ *
16
+ * app.post('/posts', async (ctx) => {
17
+ * const { title, content } = ctx.body;
18
+ * return ctx.json({ id: 1, title, content });
19
+ * }, {
20
+ * schema: { body: bodySchema }
21
+ * });
22
+ * ```
23
+ */
24
+ export interface StandardSchema<Input = unknown, Output = Input> {
25
+ readonly '~standard': {
26
+ readonly version: 1;
27
+ readonly vendor: string;
28
+ readonly validate: (value: unknown) => StandardSchemaResult<Output> | Promise<StandardSchemaResult<Output>>;
29
+ readonly types?: {
30
+ readonly input: Input;
31
+ readonly output: Output;
32
+ };
33
+ };
34
+ }
35
+
36
+ /**
37
+ * Result of Standard Schema validation.
38
+ */
39
+ export type StandardSchemaResult<Output> = StandardSchemaSuccessResult<Output> | StandardSchemaFailureResult;
40
+
41
+ /**
42
+ * Successful validation result.
43
+ */
44
+ export interface StandardSchemaSuccessResult<Output> {
45
+ readonly value: Output;
46
+ readonly issues?: undefined;
47
+ }
48
+
49
+ /**
50
+ * Failed validation result.
51
+ */
52
+ export interface StandardSchemaFailureResult {
53
+ readonly value?: undefined;
54
+ readonly issues: ReadonlyArray<StandardSchemaIssue>;
55
+ }
56
+
57
+ /**
58
+ * Validation issue details.
59
+ */
60
+ export interface StandardSchemaIssue {
61
+ readonly message: string;
62
+ readonly path?: ReadonlyArray<PropertyKey | { key: PropertyKey }>;
63
+ }
64
+
65
+ /**
66
+ * Infers the output type from a Standard Schema.
67
+ */
68
+ export type InferOutput<T extends StandardSchema> = T extends StandardSchema<any, infer O> ? O : never;