create-jen-app 1.2.3 → 1.2.4

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 (355) hide show
  1. package/dist/colors.js +0 -17
  2. package/dist/create.js +5 -17
  3. package/dist/generator.js +14 -31
  4. package/dist/index.js +6 -1
  5. package/package.json +1 -1
  6. package/templates/ssr-isr/README.md +77 -0
  7. package/templates/ssr-isr/build.js +118 -0
  8. package/templates/ssr-isr/jen.config.ts +109 -0
  9. package/templates/ssr-isr/jenjs.d.ts +22 -0
  10. package/templates/ssr-isr/lib/api/(hello).js +9 -0
  11. package/templates/ssr-isr/lib/auth/cookie-utils.js +79 -0
  12. package/templates/ssr-isr/lib/auth/index.js +2 -0
  13. package/templates/ssr-isr/lib/auth/jwt.js +57 -0
  14. package/templates/ssr-isr/lib/auth/session.js +92 -0
  15. package/templates/ssr-isr/lib/build/asset-hashing.d.ts +10 -0
  16. package/templates/ssr-isr/lib/build/asset-hashing.js +25 -0
  17. package/templates/ssr-isr/lib/build/asset-manifest.d.ts +11 -0
  18. package/templates/ssr-isr/lib/build/asset-manifest.js +21 -0
  19. package/templates/{static → ssr-isr}/lib/build/build.d.ts +1 -1
  20. package/templates/ssr-isr/lib/build/build.js +141 -0
  21. package/templates/{static → ssr-isr}/lib/build/island-hydration.d.ts +8 -5
  22. package/templates/ssr-isr/lib/build/island-hydration.js +44 -0
  23. package/templates/ssr-isr/lib/build/minifier.d.ts +20 -0
  24. package/templates/ssr-isr/lib/build/minifier.js +46 -0
  25. package/templates/ssr-isr/lib/build/page-renderer.d.ts +17 -0
  26. package/templates/ssr-isr/lib/build/page-renderer.js +28 -0
  27. package/templates/ssr-isr/lib/build/production-build.d.ts +10 -0
  28. package/templates/ssr-isr/lib/build/production-build.js +13 -0
  29. package/templates/ssr-isr/lib/build/ssg-pipeline.d.ts +15 -0
  30. package/templates/ssr-isr/lib/build/ssg-pipeline.js +113 -0
  31. package/templates/ssr-isr/lib/build-tools/build-site.js +36 -0
  32. package/templates/ssr-isr/lib/cache/index.js +10 -0
  33. package/templates/ssr-isr/lib/cache/memory.js +40 -0
  34. package/templates/ssr-isr/lib/cache/redis.js +61 -0
  35. package/templates/ssr-isr/lib/cli/banner.js +28 -0
  36. package/templates/ssr-isr/lib/cli/templates/ssg/jen.config.js +32 -0
  37. package/templates/ssr-isr/lib/cli/templates/ssg/site/index.js +9 -0
  38. package/templates/ssr-isr/lib/cli/templates/ssr/jen.config.js +32 -0
  39. package/templates/ssr-isr/lib/cli/templates/ssr/site/index.js +9 -0
  40. package/templates/ssr-isr/lib/compilers/esbuild-plugins.js +111 -0
  41. package/templates/ssr-isr/lib/compilers/svelte.js +44 -0
  42. package/templates/ssr-isr/lib/compilers/vue.js +90 -0
  43. package/templates/ssr-isr/lib/core/http.js +71 -0
  44. package/templates/ssr-isr/lib/core/middleware-hooks.js +97 -0
  45. package/templates/ssr-isr/lib/core/paths.js +39 -0
  46. package/templates/ssr-isr/lib/core/routes/match.js +47 -0
  47. package/templates/ssr-isr/lib/core/routes/scan.js +190 -0
  48. package/templates/ssr-isr/lib/core/types.js +1 -0
  49. package/templates/ssr-isr/lib/css/compiler.js +74 -0
  50. package/templates/ssr-isr/lib/db/connector.js +42 -0
  51. package/templates/ssr-isr/lib/db/drivers/jdb.js +44 -0
  52. package/templates/ssr-isr/lib/db/drivers/sql.js +182 -0
  53. package/templates/ssr-isr/lib/db/index.js +48 -0
  54. package/templates/ssr-isr/lib/db/types.js +1 -0
  55. package/templates/ssr-isr/lib/graphql/index.js +52 -0
  56. package/templates/ssr-isr/lib/graphql/resolvers.js +25 -0
  57. package/templates/ssr-isr/lib/graphql/schema.js +35 -0
  58. package/templates/ssr-isr/lib/i18n/en.json +4 -0
  59. package/templates/ssr-isr/lib/i18n/es.json +4 -0
  60. package/templates/ssr-isr/lib/i18n/index.js +15 -0
  61. package/templates/ssr-isr/lib/import/jen-import.js +161 -0
  62. package/templates/ssr-isr/lib/index.js +116 -0
  63. package/templates/ssr-isr/lib/jdb/engine.js +275 -0
  64. package/templates/ssr-isr/lib/jdb/index.js +34 -0
  65. package/templates/ssr-isr/lib/jdb/types.js +1 -0
  66. package/templates/ssr-isr/lib/jdb/utils.js +176 -0
  67. package/templates/{static → ssr-isr}/lib/middleware/builtins/body-parser.js +0 -17
  68. package/templates/ssr-isr/lib/middleware/builtins/cors.js +54 -0
  69. package/templates/{static → ssr-isr}/lib/middleware/builtins/logger.js +0 -17
  70. package/templates/{static → ssr-isr}/lib/middleware/builtins/rate-limit.js +0 -17
  71. package/templates/{static → ssr-isr}/lib/middleware/builtins/request-id.js +0 -17
  72. package/templates/{static → ssr-isr}/lib/middleware/builtins/security-headers.js +0 -17
  73. package/templates/ssr-isr/lib/middleware/context.js +124 -0
  74. package/templates/{static → ssr-isr}/lib/middleware/decorators.js +0 -17
  75. package/templates/{static → ssr-isr}/lib/middleware/errors/handler.js +0 -17
  76. package/templates/ssr-isr/lib/middleware/errors/http-error.js +10 -0
  77. package/templates/ssr-isr/lib/middleware/kernel.js +85 -0
  78. package/templates/ssr-isr/lib/middleware/pipeline.js +148 -0
  79. package/templates/ssr-isr/lib/middleware/registry.js +85 -0
  80. package/templates/ssr-isr/lib/middleware/response.js +107 -0
  81. package/templates/ssr-isr/lib/middleware/types.d.ts +1 -0
  82. package/templates/ssr-isr/lib/middleware/types.js +1 -0
  83. package/templates/ssr-isr/lib/middleware/utils/matcher.js +13 -0
  84. package/templates/{static → ssr-isr}/lib/native/bundle.js +0 -17
  85. package/templates/{static → ssr-isr}/lib/native/dev-server.js +0 -17
  86. package/templates/{static → ssr-isr}/lib/native/index.js +0 -17
  87. package/templates/{static → ssr-isr}/lib/native/optimizer.js +0 -17
  88. package/templates/ssr-isr/lib/native/style-compiler.js +19 -0
  89. package/templates/ssr-isr/lib/plugin/loader.js +36 -0
  90. package/templates/ssr-isr/lib/runtime/client-runtime.js +25 -0
  91. package/templates/ssr-isr/lib/runtime/hmr.js +59 -0
  92. package/templates/ssr-isr/lib/runtime/hydrate.js +55 -0
  93. package/templates/ssr-isr/lib/runtime/island-hydration-client.js +146 -0
  94. package/templates/ssr-isr/lib/runtime/islands.js +110 -0
  95. package/templates/ssr-isr/lib/runtime/render.js +244 -0
  96. package/templates/ssr-isr/lib/server/api-routes.js +237 -0
  97. package/templates/ssr-isr/lib/server/api.js +108 -0
  98. package/templates/ssr-isr/lib/server/app.js +438 -0
  99. package/templates/ssr-isr/lib/server/runtimeServe.js +169 -0
  100. package/templates/ssr-isr/lib/server/ssr.js +202 -0
  101. package/templates/ssr-isr/lib/shared/log.js +64 -0
  102. package/templates/ssr-isr/package.json +23 -0
  103. package/templates/ssr-isr/server.js +128 -0
  104. package/templates/ssr-isr/site/pages/(index).tsx +11 -0
  105. package/templates/ssr-isr/site/styles/global.scss +37 -0
  106. package/templates/ssr-isr/tsconfig.json +39 -0
  107. package/templates/static/build.js +30 -18
  108. package/templates/static/jen.config.ts +0 -18
  109. package/templates/static/jenjs.d.ts +0 -18
  110. package/templates/static/lib/api/(hello).js +0 -17
  111. package/templates/static/lib/api/examples/files/[...slug].js +22 -0
  112. package/templates/static/lib/api/examples/hello.js +11 -0
  113. package/templates/static/lib/api/examples/posts/[id].js +37 -0
  114. package/templates/static/lib/api/examples/posts.js +37 -0
  115. package/templates/static/lib/api/examples/search.js +23 -0
  116. package/templates/static/lib/api/index.js +41 -0
  117. package/templates/static/lib/api/loader.js +234 -0
  118. package/templates/static/lib/api/router.js +259 -0
  119. package/templates/static/lib/assets/types.js +1 -0
  120. package/templates/static/lib/auth/cookie-utils.js +3 -16
  121. package/templates/static/lib/auth/index.js +0 -17
  122. package/templates/static/lib/auth/jwt.js +0 -17
  123. package/templates/static/lib/auth/session.js +0 -17
  124. package/templates/static/lib/build/asset-hashing.js +44 -36
  125. package/templates/static/lib/build/asset-manifest.js +16 -33
  126. package/templates/static/lib/build/build.js +270 -125
  127. package/templates/static/lib/build/bundle-analyzer-ui.js +417 -0
  128. package/templates/static/lib/build/bundle-analyzer.js +945 -0
  129. package/templates/static/lib/build/code-splitter.js +194 -0
  130. package/templates/static/lib/build/feature-analyzer.js +190 -0
  131. package/templates/static/lib/build/feature-gate.js +257 -0
  132. package/templates/static/lib/build/island-hydration.js +17 -35
  133. package/templates/static/lib/build/lazy-loader.js +322 -0
  134. package/templates/static/lib/build/minifier.js +40 -59
  135. package/templates/static/lib/build/page-renderer.js +23 -40
  136. package/templates/static/lib/build/production-build.js +9 -26
  137. package/templates/static/lib/build/rust-hashing.js +71 -0
  138. package/templates/static/lib/build/script-optimizer.js +285 -0
  139. package/templates/static/lib/build/ssg-pipeline.js +100 -106
  140. package/templates/static/lib/build/vercel-output.js +298 -0
  141. package/templates/static/lib/build-tools/build-site.js +0 -17
  142. package/templates/static/lib/cache/index.js +0 -17
  143. package/templates/static/lib/cache/memory.js +0 -17
  144. package/templates/static/lib/cache/redis.js +0 -17
  145. package/templates/static/lib/cli/banner.js +0 -17
  146. package/templates/static/lib/cli/templates/ssg/jen.config.js +0 -17
  147. package/templates/static/lib/cli/templates/ssr/jen.config.js +0 -17
  148. package/templates/static/lib/client/Image.js +42 -0
  149. package/templates/static/lib/client/Link.js +190 -0
  150. package/templates/static/lib/client/PWA.js +46 -0
  151. package/templates/static/lib/client/Seo.js +97 -0
  152. package/templates/static/lib/client/index.js +9 -0
  153. package/templates/static/lib/client/useNavigation.js +25 -0
  154. package/templates/static/lib/client/useRouter.js +64 -0
  155. package/templates/static/lib/client-routing/Link.js +17 -0
  156. package/templates/static/lib/client-routing/index.js +19 -0
  157. package/templates/static/lib/client-routing/router.js +151 -0
  158. package/templates/static/lib/client-routing/signal.js +147 -0
  159. package/templates/static/lib/compilers/esbuild-plugins.js +0 -17
  160. package/templates/static/lib/compilers/svelte.js +0 -17
  161. package/templates/static/lib/compilers/vue.js +0 -17
  162. package/templates/static/lib/core/config.js +0 -17
  163. package/templates/static/lib/core/feature-guard.js +136 -0
  164. package/templates/static/lib/core/features.js +99 -0
  165. package/templates/static/lib/core/http.js +0 -17
  166. package/templates/static/lib/core/layouts/index.js +10 -0
  167. package/templates/static/lib/core/layouts/render.js +158 -0
  168. package/templates/static/lib/core/layouts/scan.js +112 -0
  169. package/templates/static/lib/core/layouts/types.js +1 -0
  170. package/templates/static/lib/core/lifecycle.js +129 -0
  171. package/templates/static/lib/core/loader-schema.js +81 -0
  172. package/templates/static/lib/core/middleware-hooks.js +0 -17
  173. package/templates/static/lib/core/paths.js +0 -17
  174. package/templates/static/lib/core/routes/advanced.js +114 -0
  175. package/templates/static/lib/core/routes/handlers.js +181 -0
  176. package/templates/static/lib/core/routes/match.js +89 -17
  177. package/templates/static/lib/core/routes/orchestrator.js +171 -0
  178. package/templates/static/lib/core/routes/rendering-config.js +131 -0
  179. package/templates/static/lib/core/routes/scan.js +0 -17
  180. package/templates/static/lib/core/types.js +0 -17
  181. package/templates/static/lib/css/compiler.js +1 -18
  182. package/templates/static/lib/data-fetching/cache.js +223 -0
  183. package/templates/static/lib/data-fetching/client.js +202 -0
  184. package/templates/static/lib/data-fetching/feature-guard.js +29 -0
  185. package/templates/static/lib/data-fetching/graphql.js +265 -0
  186. package/templates/static/lib/data-fetching/index.js +57 -0
  187. package/templates/static/lib/data-fetching/rest.js +256 -0
  188. package/templates/static/lib/data-fetching/server.js +182 -0
  189. package/templates/static/lib/data-fetching/types.js +5 -0
  190. package/templates/static/lib/db/connector.js +0 -17
  191. package/templates/static/lib/db/drivers/jdb.js +0 -17
  192. package/templates/static/lib/db/drivers/sql.js +0 -17
  193. package/templates/static/lib/db/index.js +0 -17
  194. package/templates/static/lib/db/types.js +0 -17
  195. package/templates/static/lib/devtools/component-tree.js +106 -0
  196. package/templates/static/lib/devtools/devtools.js +638 -0
  197. package/templates/static/lib/devtools/event-bus.js +29 -0
  198. package/templates/static/lib/devtools/event-logger.js +67 -0
  199. package/templates/static/lib/devtools/index.js +9 -0
  200. package/templates/static/lib/devtools/integration.js +149 -0
  201. package/templates/static/lib/devtools/performance.js +84 -0
  202. package/templates/static/lib/devtools/persistence.js +57 -0
  203. package/templates/static/lib/devtools/plugins.js +97 -0
  204. package/templates/static/lib/devtools/search.js +89 -0
  205. package/templates/static/lib/devtools/ui.js +769 -0
  206. package/templates/static/lib/features/api/handler.js +10 -0
  207. package/templates/static/lib/features/api/index.js +5 -0
  208. package/templates/static/lib/features/api/types.js +4 -0
  209. package/templates/static/lib/features/middleware/compiled.js +7 -0
  210. package/templates/static/lib/features/middleware/index.js +5 -0
  211. package/templates/static/lib/features/middleware/types.js +4 -0
  212. package/templates/static/lib/fonts/index.js +46 -0
  213. package/templates/static/lib/fonts/inject.js +125 -0
  214. package/templates/static/lib/fonts/loader.js +196 -0
  215. package/templates/static/lib/fonts/types.js +1 -0
  216. package/templates/static/lib/graphql/index.js +1 -18
  217. package/templates/static/lib/graphql/resolvers.js +20 -13
  218. package/templates/static/lib/graphql/schema.js +0 -17
  219. package/templates/static/lib/i18n/index.js +7 -19
  220. package/templates/static/lib/import/jen-import.js +1 -18
  221. package/templates/static/lib/index.js +79 -125
  222. package/templates/static/lib/jdb/engine.js +0 -17
  223. package/templates/static/lib/jdb/index.js +1 -18
  224. package/templates/static/lib/jdb/types.js +0 -17
  225. package/templates/static/lib/jdb/utils.js +0 -17
  226. package/templates/static/lib/middleware/builtins/cors.js +3 -16
  227. package/templates/static/lib/middleware/context.js +0 -17
  228. package/templates/static/lib/middleware/kernel.js +117 -25
  229. package/templates/static/lib/middleware/pipeline.js +0 -17
  230. package/templates/static/lib/middleware/registry.js +0 -17
  231. package/templates/static/lib/middleware/response.js +0 -17
  232. package/templates/static/lib/plugin/examples/analytics-plugin.js +183 -0
  233. package/templates/static/lib/plugin/examples/cdn-upload-plugin.js +94 -0
  234. package/templates/static/lib/plugin/loader.js +0 -17
  235. package/templates/static/lib/plugin/plugin-manager.js +177 -0
  236. package/templates/static/lib/plugin/types.js +28 -0
  237. package/templates/static/lib/runtime/client-runtime.js +0 -17
  238. package/templates/static/lib/runtime/hmr.js +0 -17
  239. package/templates/static/lib/runtime/hydrate.js +0 -17
  240. package/templates/static/lib/runtime/island-hydration-client.js +0 -17
  241. package/templates/static/lib/runtime/islands.js +0 -17
  242. package/templates/static/lib/runtime/render.js +208 -50
  243. package/templates/static/lib/security/security-config.js +60 -0
  244. package/templates/static/lib/security/security-middleware.js +229 -0
  245. package/templates/static/lib/server/api-routes.js +153 -43
  246. package/templates/static/lib/server/api.js +0 -17
  247. package/templates/static/lib/server/app.js +539 -223
  248. package/templates/static/lib/server/isr.js +365 -0
  249. package/templates/static/lib/server/runtimeServe.js +31 -24
  250. package/templates/static/lib/server/ssr.js +98 -22
  251. package/templates/static/lib/server-actions/handler.js +180 -0
  252. package/templates/static/lib/server-actions/index.js +19 -0
  253. package/templates/static/lib/server-actions/middleware.js +146 -0
  254. package/templates/static/lib/server-actions/scan.js +152 -0
  255. package/templates/static/lib/server-actions/types.js +1 -0
  256. package/templates/static/lib/server-actions/validators.js +156 -0
  257. package/templates/static/lib/shared/log.js +19 -20
  258. package/templates/static/lib/telemetry/api/rate-limiter.js +32 -0
  259. package/templates/static/lib/telemetry/api/validator.js +67 -0
  260. package/templates/static/lib/telemetry/client.js +121 -0
  261. package/templates/static/lib/telemetry/tests/rate-limiter.test.js +46 -0
  262. package/templates/static/lib/telemetry/tests/validator.test.js +62 -0
  263. package/templates/static/lib/vendor/glob/glob.js +4766 -0
  264. package/templates/static/lib/vendor/preact/LICENSE +21 -0
  265. package/templates/static/lib/vendor/preact/preact.module.js +797 -0
  266. package/templates/static/lib/vendor/sass/sass.node.mjs +212 -0
  267. package/templates/static/package.json +4 -0
  268. package/templates/static/server.js +22 -22
  269. package/templates/static/site/(home).tsx +0 -18
  270. package/templates/static/tsconfig.json +5 -1
  271. package/templates/static/.esbuild/jen.config.js +0 -19
  272. package/templates/static/lib/build/asset-hashing.d.ts +0 -10
  273. package/templates/static/lib/build/asset-manifest.d.ts +0 -11
  274. package/templates/static/lib/build/minifier.d.ts +0 -20
  275. package/templates/static/lib/build/page-renderer.d.ts +0 -17
  276. package/templates/static/lib/build/production-build.d.ts +0 -10
  277. package/templates/static/lib/build/ssg-pipeline.d.ts +0 -15
  278. package/templates/static/lib/middleware/errors/http-error.js +0 -27
  279. package/templates/static/lib/middleware/types.js +0 -18
  280. package/templates/static/lib/middleware/utils/matcher.js +0 -30
  281. package/templates/static/lib/native/style-compiler.js +0 -36
  282. /package/templates/{static → ssr-isr}/lib/api/(hello).d.ts +0 -0
  283. /package/templates/{static → ssr-isr}/lib/auth/cookie-utils.d.ts +0 -0
  284. /package/templates/{static → ssr-isr}/lib/auth/index.d.ts +0 -0
  285. /package/templates/{static → ssr-isr}/lib/auth/jwt.d.ts +0 -0
  286. /package/templates/{static → ssr-isr}/lib/auth/session.d.ts +0 -0
  287. /package/templates/{static → ssr-isr}/lib/build-tools/build-site.d.ts +0 -0
  288. /package/templates/{static → ssr-isr}/lib/cache/index.d.ts +0 -0
  289. /package/templates/{static → ssr-isr}/lib/cache/memory.d.ts +0 -0
  290. /package/templates/{static → ssr-isr}/lib/cache/redis.d.ts +0 -0
  291. /package/templates/{static → ssr-isr}/lib/cli/banner.d.ts +0 -0
  292. /package/templates/{static → ssr-isr}/lib/cli/templates/ssg/jen.config.d.ts +0 -0
  293. /package/templates/{static → ssr-isr}/lib/cli/templates/ssg/site/index.d.ts +0 -0
  294. /package/templates/{static → ssr-isr}/lib/cli/templates/ssr/jen.config.d.ts +0 -0
  295. /package/templates/{static → ssr-isr}/lib/cli/templates/ssr/site/index.d.ts +0 -0
  296. /package/templates/{static → ssr-isr}/lib/compilers/esbuild-plugins.d.ts +0 -0
  297. /package/templates/{static → ssr-isr}/lib/compilers/svelte.d.ts +0 -0
  298. /package/templates/{static → ssr-isr}/lib/compilers/vue.d.ts +0 -0
  299. /package/templates/{static → ssr-isr}/lib/core/config.d.ts +0 -0
  300. /package/templates/{static/lib/middleware/types.d.ts → ssr-isr/lib/core/config.js} +0 -0
  301. /package/templates/{static → ssr-isr}/lib/core/http.d.ts +0 -0
  302. /package/templates/{static → ssr-isr}/lib/core/middleware-hooks.d.ts +0 -0
  303. /package/templates/{static → ssr-isr}/lib/core/paths.d.ts +0 -0
  304. /package/templates/{static → ssr-isr}/lib/core/routes/match.d.ts +0 -0
  305. /package/templates/{static → ssr-isr}/lib/core/routes/scan.d.ts +0 -0
  306. /package/templates/{static → ssr-isr}/lib/core/types.d.ts +0 -0
  307. /package/templates/{static → ssr-isr}/lib/css/compiler.d.ts +0 -0
  308. /package/templates/{static → ssr-isr}/lib/db/connector.d.ts +0 -0
  309. /package/templates/{static → ssr-isr}/lib/db/drivers/jdb.d.ts +0 -0
  310. /package/templates/{static → ssr-isr}/lib/db/drivers/sql.d.ts +0 -0
  311. /package/templates/{static → ssr-isr}/lib/db/index.d.ts +0 -0
  312. /package/templates/{static → ssr-isr}/lib/db/types.d.ts +0 -0
  313. /package/templates/{static → ssr-isr}/lib/graphql/index.d.ts +0 -0
  314. /package/templates/{static → ssr-isr}/lib/graphql/resolvers.d.ts +0 -0
  315. /package/templates/{static → ssr-isr}/lib/graphql/schema.d.ts +0 -0
  316. /package/templates/{static → ssr-isr}/lib/i18n/index.d.ts +0 -0
  317. /package/templates/{static → ssr-isr}/lib/import/jen-import.d.ts +0 -0
  318. /package/templates/{static → ssr-isr}/lib/index.d.ts +0 -0
  319. /package/templates/{static → ssr-isr}/lib/jdb/engine.d.ts +0 -0
  320. /package/templates/{static → ssr-isr}/lib/jdb/index.d.ts +0 -0
  321. /package/templates/{static → ssr-isr}/lib/jdb/types.d.ts +0 -0
  322. /package/templates/{static → ssr-isr}/lib/jdb/utils.d.ts +0 -0
  323. /package/templates/{static → ssr-isr}/lib/middleware/builtins/body-parser.d.ts +0 -0
  324. /package/templates/{static → ssr-isr}/lib/middleware/builtins/cors.d.ts +0 -0
  325. /package/templates/{static → ssr-isr}/lib/middleware/builtins/logger.d.ts +0 -0
  326. /package/templates/{static → ssr-isr}/lib/middleware/builtins/rate-limit.d.ts +0 -0
  327. /package/templates/{static → ssr-isr}/lib/middleware/builtins/request-id.d.ts +0 -0
  328. /package/templates/{static → ssr-isr}/lib/middleware/builtins/security-headers.d.ts +0 -0
  329. /package/templates/{static → ssr-isr}/lib/middleware/context.d.ts +0 -0
  330. /package/templates/{static → ssr-isr}/lib/middleware/decorators.d.ts +0 -0
  331. /package/templates/{static → ssr-isr}/lib/middleware/errors/handler.d.ts +0 -0
  332. /package/templates/{static → ssr-isr}/lib/middleware/errors/http-error.d.ts +0 -0
  333. /package/templates/{static → ssr-isr}/lib/middleware/kernel.d.ts +0 -0
  334. /package/templates/{static → ssr-isr}/lib/middleware/pipeline.d.ts +0 -0
  335. /package/templates/{static → ssr-isr}/lib/middleware/registry.d.ts +0 -0
  336. /package/templates/{static → ssr-isr}/lib/middleware/response.d.ts +0 -0
  337. /package/templates/{static → ssr-isr}/lib/middleware/utils/matcher.d.ts +0 -0
  338. /package/templates/{static → ssr-isr}/lib/native/bundle.d.ts +0 -0
  339. /package/templates/{static → ssr-isr}/lib/native/dev-server.d.ts +0 -0
  340. /package/templates/{static → ssr-isr}/lib/native/index.d.ts +0 -0
  341. /package/templates/{static → ssr-isr}/lib/native/optimizer.d.ts +0 -0
  342. /package/templates/{static → ssr-isr}/lib/native/style-compiler.d.ts +0 -0
  343. /package/templates/{static → ssr-isr}/lib/plugin/loader.d.ts +0 -0
  344. /package/templates/{static → ssr-isr}/lib/runtime/client-runtime.d.ts +0 -0
  345. /package/templates/{static → ssr-isr}/lib/runtime/hmr.d.ts +0 -0
  346. /package/templates/{static → ssr-isr}/lib/runtime/hydrate.d.ts +0 -0
  347. /package/templates/{static → ssr-isr}/lib/runtime/island-hydration-client.d.ts +0 -0
  348. /package/templates/{static → ssr-isr}/lib/runtime/islands.d.ts +0 -0
  349. /package/templates/{static → ssr-isr}/lib/runtime/render.d.ts +0 -0
  350. /package/templates/{static → ssr-isr}/lib/server/api-routes.d.ts +0 -0
  351. /package/templates/{static → ssr-isr}/lib/server/api.d.ts +0 -0
  352. /package/templates/{static → ssr-isr}/lib/server/app.d.ts +0 -0
  353. /package/templates/{static → ssr-isr}/lib/server/runtimeServe.d.ts +0 -0
  354. /package/templates/{static → ssr-isr}/lib/server/ssr.d.ts +0 -0
  355. /package/templates/{static → ssr-isr}/lib/shared/log.d.ts +0 -0
@@ -0,0 +1,365 @@
1
+ import { renderWithOptions } from "./ssr.js";
2
+ /**
3
+ * In-memory storage for ISR cache entries.
4
+ * Persists across requests using stale-while-revalidate pattern.
5
+ */
6
+ const isrCache = new Map();
7
+ /**
8
+ * Global default revalidation interval (seconds).
9
+ * Can be overridden per-route via RouteEntry.revalidateSeconds.
10
+ * Defaults to 1 hour.
11
+ */
12
+ let defaultRevalidateSeconds = 3600;
13
+ let isrConfig = {
14
+ defaultRevalidateSeconds: 3600,
15
+ maxConcurrentRevalidations: 5,
16
+ debug: false,
17
+ };
18
+ /** Counter to track concurrent revalidations */
19
+ let concurrentRevalidations = 0;
20
+ /**
21
+ * Configure ISR behavior globally.
22
+ * Allows customization of revalidation intervals and concurrency.
23
+ *
24
+ * @param config Partial ISR configuration to merge
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * import * as ISR from './isr.ts';
29
+ *
30
+ * ISR.setIsrConfig({
31
+ * defaultRevalidateSeconds: 300, // 5 minutes
32
+ * debug: true
33
+ * });
34
+ * ```
35
+ */
36
+ export function setIsrConfig(config) {
37
+ isrConfig = { ...isrConfig, ...config };
38
+ if (config.defaultRevalidateSeconds !== undefined) {
39
+ defaultRevalidateSeconds = config.defaultRevalidateSeconds;
40
+ }
41
+ }
42
+ /**
43
+ * Get the current ISR configuration.
44
+ *
45
+ * @returns Current ISR configuration
46
+ */
47
+ export function getIsrConfig() {
48
+ return { ...isrConfig };
49
+ }
50
+ /**
51
+ * Log debug message if ISR debug mode is enabled.
52
+ *
53
+ * @param message Log message
54
+ * @param args Additional log arguments
55
+ */
56
+ function debugLog(message, ...args) {
57
+ if (isrConfig.debug) {
58
+ console.log(`[ISR] ${message}`, ...args);
59
+ }
60
+ }
61
+ /**
62
+ * Determine if cached HTML has exceeded its revalidation TTL.
63
+ * Returns true if the cache should be regenerated in the background.
64
+ *
65
+ * @param entry ISR cache entry to check
66
+ * @returns true if revalidation is needed
67
+ */
68
+ function isRevalidationNeeded(entry) {
69
+ const now = Date.now();
70
+ const revalidateTtl =
71
+ (entry.revalidateSeconds ?? defaultRevalidateSeconds) * 1000;
72
+ const age = now - entry.timestamp;
73
+ return age > revalidateTtl;
74
+ }
75
+ /**
76
+ * Enqueue a background revalidation task.
77
+ * Respects maxConcurrentRevalidations to prevent overwhelming the server.
78
+ *
79
+ * @param fn Async function to execute in background
80
+ */
81
+ async function enqueueRevalidation(fn) {
82
+ // Wait for slot to become available if at capacity
83
+ while (concurrentRevalidations >= isrConfig.maxConcurrentRevalidations) {
84
+ await new Promise((resolve) => setTimeout(resolve, 10));
85
+ }
86
+ concurrentRevalidations++;
87
+ try {
88
+ await fn();
89
+ } finally {
90
+ concurrentRevalidations--;
91
+ }
92
+ }
93
+ /**
94
+ * Main ISR entry point: fetch or generate cached HTML for a route.
95
+ * Implements stale-while-revalidate pattern:
96
+ * - Serves cached HTML immediately if available
97
+ * - Regenerates in background if expired (without blocking response)
98
+ * - Regenerates on-demand if no cache exists
99
+ *
100
+ * This function integrates seamlessly with Jen.js's render() function.
101
+ *
102
+ * @param config Framework configuration
103
+ * @param route Route entry being requested
104
+ * @param ctx SSR context with request/response metadata
105
+ * @param options ISR-specific options
106
+ * @param options.revalidate Override revalidation TTL (seconds), overrides route.revalidateSeconds
107
+ * @returns Cached or freshly rendered HTML
108
+ *
109
+ * @throws Error if rendering fails and no cache exists
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * import * as ISR from './isr.ts';
114
+ * import { getIsrHtml, setIsrConfig } from './isr.ts';
115
+ *
116
+ * // Setup
117
+ * setIsrConfig({ defaultRevalidateSeconds: 300, debug: true });
118
+ *
119
+ * // In route handler
120
+ * app.get('/:path(*)', async (req, res) => {
121
+ * try {
122
+ * const html = await getIsrHtml(config, route, {
123
+ * req, res, url, params, query, headers, cookies
124
+ * });
125
+ * res.setHeader('content-type', 'text/html; charset=utf-8');
126
+ * res.end(html);
127
+ * } catch (err) {
128
+ * res.statusCode = 500;
129
+ * res.end('Rendering failed');
130
+ * }
131
+ * });
132
+ *
133
+ * // Per-route override
134
+ * const html = await getIsrHtml(config, route, ctx, {
135
+ * revalidate: 60 // Regenerate every 60 seconds for this request
136
+ * });
137
+ * ```
138
+ */
139
+ export async function getIsrHtml(config, route, ctx, options) {
140
+ const pathname = ctx.url.pathname;
141
+ const now = Date.now();
142
+ // Lookup existing cache entry
143
+ const cached = isrCache.get(pathname);
144
+ // If we have cached content, serve it immediately
145
+ if (cached) {
146
+ debugLog(`Cache hit for ${pathname}`);
147
+ // Check if revalidation is needed (stale-while-revalidate pattern)
148
+ const needsRevalidation = isRevalidationNeeded(cached);
149
+ if (needsRevalidation && !cached.revalidating) {
150
+ debugLog(`Initiating background revalidation for ${pathname}`);
151
+ // Mark as revalidating and enqueue background task
152
+ cached.revalidating = true;
153
+ cached.revalidationPromise = enqueueRevalidation(async () => {
154
+ try {
155
+ const freshHtml = await renderWithOptions(config, route, ctx, {
156
+ cache: false,
157
+ });
158
+ cached.html = freshHtml;
159
+ cached.timestamp = now;
160
+ debugLog(`Background revalidation complete for ${pathname}`);
161
+ } catch (err) {
162
+ debugLog(`Background revalidation failed for ${pathname}:`, err);
163
+ // Keep serving stale cache on error; don't propagate failure
164
+ } finally {
165
+ cached.revalidating = false;
166
+ }
167
+ });
168
+ }
169
+ // Return cached HTML immediately (stale-while-revalidate pattern)
170
+ return cached.html;
171
+ }
172
+ // No cache exists - render on-demand and cache result
173
+ debugLog(`Cache miss, rendering on-demand for ${pathname}`);
174
+ const html = await renderWithOptions(config, route, ctx, { cache: false });
175
+ // Determine revalidation TTL (order of precedence)
176
+ let revalidateTtl = defaultRevalidateSeconds;
177
+ if (options?.revalidate !== undefined) {
178
+ revalidateTtl = options.revalidate;
179
+ } else if (
180
+ "revalidateSeconds" in route &&
181
+ typeof route.revalidateSeconds === "number"
182
+ ) {
183
+ revalidateTtl = route.revalidateSeconds;
184
+ }
185
+ // Store in ISR cache
186
+ isrCache.set(pathname, {
187
+ html,
188
+ timestamp: now,
189
+ revalidateSeconds: revalidateTtl,
190
+ revalidating: false,
191
+ });
192
+ debugLog(`Cached ${pathname} with TTL ${revalidateTtl}s`);
193
+ return html;
194
+ }
195
+ /**
196
+ * Manually set or update ISR cache for a route.
197
+ * Useful for programmatic cache invalidation and updates.
198
+ *
199
+ * @param routePath URL pathname to cache (e.g., "/", "/about", "/posts/123")
200
+ * @param html Complete HTML document to cache
201
+ * @param options Cache options
202
+ * @param options.revalidate Custom revalidation interval (seconds), overrides default
203
+ *
204
+ * @example
205
+ * ```typescript
206
+ * import { setIsrCache } from './isr.ts';
207
+ *
208
+ * // After updating a blog post
209
+ * app.post('/api/posts/:id', async (req, res) => {
210
+ * // ... update database ...
211
+ *
212
+ * // Regenerate and cache the post page
213
+ * const html = await renderPost(req.params.id);
214
+ * setIsrCache(`/posts/${req.params.id}`, html, { revalidate: 3600 });
215
+ *
216
+ * res.json({ success: true });
217
+ * });
218
+ * ```
219
+ */
220
+ export function setIsrCache(routePath, html, options) {
221
+ const now = Date.now();
222
+ const revalidateTtl = options?.revalidate ?? defaultRevalidateSeconds;
223
+ isrCache.set(routePath, {
224
+ html,
225
+ timestamp: now,
226
+ revalidateSeconds: revalidateTtl,
227
+ revalidating: false,
228
+ });
229
+ debugLog(
230
+ `Manually set ISR cache for ${routePath} with TTL ${revalidateTtl}s`,
231
+ );
232
+ }
233
+ /**
234
+ * Invalidate ISR cache for a specific route.
235
+ * Forces regeneration on next request.
236
+ *
237
+ * @param routePath URL pathname to invalidate
238
+ *
239
+ * @example
240
+ * ```typescript
241
+ * import { invalidateIsrCache } from './isr.ts';
242
+ *
243
+ * app.post('/api/posts/:id/publish', async (req, res) => {
244
+ * // ... publish logic ...
245
+ * invalidateIsrCache(`/posts/${req.params.id}`);
246
+ * res.json({ success: true });
247
+ * });
248
+ * ```
249
+ */
250
+ export function invalidateIsrCache(routePath) {
251
+ isrCache.delete(routePath);
252
+ debugLog(`Invalidated ISR cache for ${routePath}`);
253
+ }
254
+ /**
255
+ * Clear the entire ISR cache.
256
+ * Useful after bulk data updates or deployment.
257
+ *
258
+ * @example
259
+ * ```typescript
260
+ * import { clearIsrCache } from './isr.ts';
261
+ *
262
+ * // After re-importing data
263
+ * await importDataFromSources();
264
+ * clearIsrCache();
265
+ * ```
266
+ */
267
+ export function clearIsrCache() {
268
+ isrCache.clear();
269
+ debugLog("Cleared entire ISR cache");
270
+ }
271
+ /**
272
+ * Get comprehensive ISR cache statistics.
273
+ * Useful for monitoring cache health and performance.
274
+ *
275
+ * Returns cache size, entry details (age, TTL, size), and revalidation status.
276
+ * All ages are calculated at call time.
277
+ *
278
+ * @returns ISR cache statistics
279
+ *
280
+ * @example
281
+ * ```typescript
282
+ * import { getIsrStats } from './isr.ts';
283
+ *
284
+ * app.get('/admin/isr-stats', (req, res) => {
285
+ * const stats = getIsrStats();
286
+ * console.log(`Cache size: ${stats.size} routes`);
287
+ * console.log(`Revalidating: ${stats.revalidating}/${stats.maxConcurrentRevalidations}`);
288
+ *
289
+ * stats.entries.forEach(entry => {
290
+ * console.log(`${entry.pathname}: age=${entry.age}s, ttl=${entry.revalidateSeconds}s`);
291
+ * });
292
+ *
293
+ * res.json(stats);
294
+ * });
295
+ * ```
296
+ */
297
+ export function getIsrStats() {
298
+ const now = Date.now();
299
+ const entries = [];
300
+ let revalidatingCount = 0;
301
+ for (const [pathname, entry] of isrCache.entries()) {
302
+ const age = (now - entry.timestamp) / 1000;
303
+ const revalidateSeconds =
304
+ entry.revalidateSeconds ?? defaultRevalidateSeconds;
305
+ entries.push({
306
+ pathname,
307
+ age,
308
+ revalidateSeconds,
309
+ size: entry.html.length,
310
+ revalidating: entry.revalidating,
311
+ });
312
+ if (entry.revalidating) {
313
+ revalidatingCount++;
314
+ }
315
+ }
316
+ return {
317
+ size: isrCache.size,
318
+ entries,
319
+ revalidating: revalidatingCount,
320
+ maxConcurrentRevalidations: isrConfig.maxConcurrentRevalidations,
321
+ defaultRevalidateSeconds,
322
+ };
323
+ }
324
+ /**
325
+ * Wait for all in-flight revalidations to complete.
326
+ * Useful in testing or graceful shutdown scenarios.
327
+ *
328
+ * @param timeout Maximum time to wait in milliseconds (default: 30000)
329
+ * @returns Promise that resolves when all revalidations complete or timeout occurs
330
+ *
331
+ * @example
332
+ * ```typescript
333
+ * import { waitForRevalidations } from './isr.ts';
334
+ *
335
+ * // In graceful shutdown
336
+ * process.on('SIGTERM', async () => {
337
+ * console.log('Waiting for revalidations to complete...');
338
+ * await waitForRevalidations(5000);
339
+ * server.close();
340
+ * });
341
+ * ```
342
+ */
343
+ export async function waitForRevalidations(timeout = 30000) {
344
+ const startTime = Date.now();
345
+ const promises = [];
346
+ for (const entry of isrCache.values()) {
347
+ if (entry.revalidating && entry.revalidationPromise) {
348
+ promises.push(entry.revalidationPromise);
349
+ }
350
+ }
351
+ if (promises.length === 0) {
352
+ return;
353
+ }
354
+ try {
355
+ await Promise.race([
356
+ Promise.all(promises),
357
+ new Promise((_, reject) =>
358
+ setTimeout(() => reject(new Error("Revalidation timeout")), timeout),
359
+ ),
360
+ ]);
361
+ } catch (err) {
362
+ const elapsed = Date.now() - startTime;
363
+ debugLog(`Revalidation wait timed out after ${elapsed}ms`);
364
+ }
365
+ }
@@ -1,24 +1,10 @@
1
- /*
2
- * This file is part of Jen.js.
3
- * Copyright (C) 2026 oopsio
4
- *
5
- * This program is free software: you can redistribute it and/or modify
6
- * it under the terms of the GNU General Public License as published by
7
- * the Free Software Foundation, either version 3 of the License, or
8
- * (at your option) any later version.
9
- *
10
- * This program is distributed in the hope that it will be useful,
11
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
- * GNU General Public License for more details.
14
- *
15
- * You should have received a copy of the GNU General Public License
16
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
- */
18
1
  import { buildSync } from "esbuild";
2
+ import { readFileSync } from "node:fs";
19
3
  import { createHash } from "node:crypto";
20
4
  import { existsSync } from "node:fs";
21
- import { basename, dirname } from "node:path";
5
+ import { basename, dirname, resolve } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
22
8
  /**
23
9
  * Cache for compiled hydration modules.
24
10
  * Stores transpiled JS code and computed ETag hash per source file path.
@@ -46,10 +32,17 @@ function etagOf(s) {
46
32
  * @returns ES module code string for browser hydration runtime
47
33
  */
48
34
  export function runtimeHydrateModule() {
49
- // Browser-safe runtime (ESM) using CDN preact (fast + zero bundler)
35
+ // Browser-safe runtime (ESM) using local vendored preact code
36
+ // Inline preact directly from vendor directory for zero external dependencies
37
+ const preactCode = readFileSync(
38
+ resolve(__dirname, "../vendor/preact/preact.module.js"),
39
+ "utf-8",
40
+ );
50
41
  return `
51
- import { hydrate } from "https://esm.sh/preact@10.25.4";
52
- import { h } from "https://esm.sh/preact@10.25.4";
42
+ ${preactCode}
43
+
44
+ const { hydrate, h } = preact;
45
+ delete globalThis.preact;
53
46
 
54
47
  function getFrameworkData() {
55
48
  const el = document.getElementById("__FRAMEWORK_DATA__");
@@ -164,10 +157,24 @@ export function buildHydrationModule(routeIdOrPath) {
164
157
  console.error("[HYDRATION] Failed to build module for:", filePath);
165
158
  return `export default function Page(){ return null }`;
166
159
  }
160
+ // Read vendored preact and inject it with proper globals
161
+ const preactCode = readFileSync(
162
+ resolve(__dirname, "../vendor/preact/preact.module.js"),
163
+ "utf-8",
164
+ );
165
+ // Wrap the hydration module with inlined preact
166
+ const mappedOutput = `
167
+ ${preactCode}
168
+
169
+ ${jsOutput
170
+ .replace(/from ["']preact\/jsx-runtime["']/g, 'from "preact/jsx-runtime"')
171
+ .replace(/from ["']preact\/hooks["']/g, 'from "preact/hooks"')
172
+ .replace(/from ["']preact(?!\/|["'])/g, 'from "preact"')}
173
+ `;
167
174
  // Cache result with ETag
168
- const etag = etagOf(jsOutput);
169
- cache.set(key, { js: jsOutput, etag });
170
- return jsOutput;
175
+ const etag = etagOf(mappedOutput);
176
+ cache.set(key, { js: mappedOutput, etag });
177
+ return mappedOutput;
171
178
  } catch (err) {
172
179
  console.error("[HYDRATION] Build error for", filePath, ":", err);
173
180
  return `export default function Page(){ return null }`;
@@ -1,38 +1,109 @@
1
- /*
2
- * This file is part of Jen.js.
3
- * Copyright (C) 2026 oopsio
4
- *
5
- * This program is free software: you can redistribute it and/or modify
6
- * it under the terms of the GNU General Public License as published by
7
- * the Free Software Foundation, either version 3 of the License, or
8
- * (at your option) any later version.
9
- *
10
- * This program is distributed in the hope that it will be useful,
11
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
- * GNU General Public License for more details.
14
- *
15
- * You should have received a copy of the GNU General Public License
16
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
- */
18
1
  import { renderRouteToHtml } from "../runtime/render.js";
19
2
  /**
20
- * HTML rendering cache for performance optimization.
21
- * Cache key is URL pathname. Useful for frequently accessed pages.
22
- * In production, consider using Redis or external cache for distributed rendering.
3
+ * Lightweight LRU (Least Recently Used) Cache implementation.
4
+ * Maintains insertion order and tracks access time for eviction.
23
5
  */
24
- const renderCache = new Map();
6
+ class LRUCache {
7
+ map = new Map();
8
+ maxSize;
9
+ constructor(maxSize) {
10
+ this.maxSize = maxSize;
11
+ }
12
+ get(key) {
13
+ const entry = this.map.get(key);
14
+ if (entry) {
15
+ // Move to end (most recently used)
16
+ this.map.delete(key);
17
+ entry.accessedAt = Date.now();
18
+ this.map.set(key, entry);
19
+ }
20
+ return entry;
21
+ }
22
+ set(key, entry) {
23
+ // Remove if exists to re-insert at end
24
+ if (this.map.has(key)) {
25
+ this.map.delete(key);
26
+ }
27
+ this.map.set(key, entry);
28
+ // Evict least recently used if over capacity
29
+ if (this.map.size > this.maxSize) {
30
+ const firstKey = this.map.keys().next().value;
31
+ if (firstKey) {
32
+ this.map.delete(firstKey);
33
+ }
34
+ }
35
+ }
36
+ delete(key) {
37
+ this.map.delete(key);
38
+ }
39
+ clear() {
40
+ this.map.clear();
41
+ }
42
+ get size() {
43
+ return this.map.size;
44
+ }
45
+ entries() {
46
+ return this.map.entries();
47
+ }
48
+ }
49
+ const renderCache = new LRUCache(1000);
25
50
  let cacheConfig = {
26
51
  enabled: true,
27
52
  ttlSeconds: 3600, // Default: 1 hour
53
+ maxEntries: 1000, // Default: 1000 max cached pages
28
54
  };
55
+ /**
56
+ * Background sweep interval (ms) to clean expired entries.
57
+ */
58
+ const CACHE_SWEEP_INTERVAL = 5 * 60 * 1000; // 5 minutes
59
+ /**
60
+ * Start periodic cache cleanup to remove expired entries.
61
+ */
62
+ function startCacheSweep() {
63
+ const sweepTimer = setInterval(() => {
64
+ if (!cacheConfig.enabled) return;
65
+ const now = Date.now();
66
+ const ttlMs = (cacheConfig.ttlSeconds ?? 3600) * 1000;
67
+ for (const [key, entry] of renderCache.entries()) {
68
+ const age = now - entry.timestamp;
69
+ if (age > ttlMs) {
70
+ renderCache.delete(key);
71
+ }
72
+ }
73
+ }, CACHE_SWEEP_INTERVAL);
74
+ // Prevent Node.js process from exiting due to this timer
75
+ if (typeof sweepTimer.unref === "function") {
76
+ sweepTimer.unref();
77
+ }
78
+ return sweepTimer;
79
+ }
80
+ // Start the background sweep
81
+ if (typeof global !== "undefined") {
82
+ try {
83
+ startCacheSweep();
84
+ } catch {
85
+ // Ignore if called in non-Node environment
86
+ }
87
+ }
29
88
  /**
30
89
  * Configure the SSR HTML cache behavior.
90
+ * Updates maxEntries for the LRU cache if provided.
31
91
  *
32
92
  * @param config Cache configuration options
33
93
  */
34
94
  export function configureSsrCache(config) {
35
95
  cacheConfig = { ...cacheConfig, ...config };
96
+ // Update LRU cache size if maxEntries changed
97
+ if (config.maxEntries && config.maxEntries > 0) {
98
+ // Reinitialize LRU cache with new size
99
+ const existing = Array.from(renderCache.entries());
100
+ renderCache.clear();
101
+ // Recreate with new size (this is a limitation of the current approach,
102
+ // but maxEntries rarely changes at runtime)
103
+ for (const [key, entry] of existing) {
104
+ renderCache.set(key, entry);
105
+ }
106
+ }
36
107
  }
37
108
  /**
38
109
  * Clear the entire SSR render cache.
@@ -68,13 +139,18 @@ function getCachedHtml(pathname) {
68
139
  }
69
140
  /**
70
141
  * Cache rendered HTML for a page.
142
+ * LRU eviction occurs automatically when maxEntries is exceeded.
71
143
  *
72
144
  * @param pathname URL pathname
73
145
  * @param html Complete HTML string to cache
74
146
  */
75
147
  function cacheHtml(pathname, html) {
76
148
  if (!cacheConfig.enabled) return;
77
- renderCache.set(pathname, { html, timestamp: Date.now() });
149
+ renderCache.set(pathname, {
150
+ html,
151
+ timestamp: Date.now(),
152
+ accessedAt: Date.now(),
153
+ });
78
154
  }
79
155
  /**
80
156
  * Core SSR render function: converts a component/template to HTML string.