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,136 @@
1
+ import { isFeatureEnabled } from "./features.js";
2
+ /**
3
+ * Feature guard errors provide helpful context when code tries to use disabled features.
4
+ * Includes the feature name and guidance on how to enable it.
5
+ */
6
+ export class FeatureDisabledError extends Error {
7
+ feature;
8
+ constructor(feature, context) {
9
+ const msg =
10
+ `Feature "${feature}" is not enabled. ` +
11
+ `Enable it in jen.config.ts with: features: { ${feature}: true }${context ? ` (${context})` : ""}`;
12
+ super(msg);
13
+ this.feature = feature;
14
+ this.name = "FeatureDisabledError";
15
+ }
16
+ }
17
+ /**
18
+ * Feature configuration errors indicate invalid feature configuration.
19
+ */
20
+ export class FeatureConfigError extends Error {
21
+ feature;
22
+ constructor(feature, details) {
23
+ super(`Invalid configuration for feature "${feature}": ${details}`);
24
+ this.feature = feature;
25
+ this.name = "FeatureConfigError";
26
+ }
27
+ }
28
+ /**
29
+ * Validates that a feature is enabled before execution.
30
+ * Throws helpful error if feature is disabled.
31
+ *
32
+ * Use in feature module entry points to prevent disabled features from running.
33
+ *
34
+ * @param features Resolved feature configuration
35
+ * @param feature Feature name to validate
36
+ * @param context Optional context (e.g., function name) for error message
37
+ * @throws FeatureDisabledError if feature is not enabled
38
+ *
39
+ * @example
40
+ * export function setupApiRoutes(features: ResolvedFeatures) {
41
+ * guardFeature(features, "api", "API route handling");
42
+ * // ... API setup code
43
+ * }
44
+ */
45
+ export function guardFeature(features, feature, context) {
46
+ if (!isFeatureEnabled(features, feature)) {
47
+ throw new FeatureDisabledError(feature, context);
48
+ }
49
+ }
50
+ /**
51
+ * Guards multiple features, throwing if any are disabled.
52
+ * Useful for features that depend on other features.
53
+ *
54
+ * @example
55
+ * export function setupAdvancedMiddleware(features: ResolvedFeatures) {
56
+ * guardFeatures(features, ["middleware", "cache"], "Advanced middleware");
57
+ * // ... code that uses both features
58
+ * }
59
+ */
60
+ export function guardFeatures(features, required, context) {
61
+ const missing = required.filter((f) => !isFeatureEnabled(features, f));
62
+ if (missing.length > 0) {
63
+ const list = missing.join(", ");
64
+ throw new Error(
65
+ `Features required: ${list}. ` +
66
+ `Enable them in jen.config.ts${context ? ` (${context})` : ""}`,
67
+ );
68
+ }
69
+ }
70
+ /**
71
+ * Type guard that narrows feature type based on enabled status.
72
+ * Allows TypeScript to enforce feature availability at compile time.
73
+ *
74
+ * @example
75
+ * if (isFeatureAvailable(features, "api")) {
76
+ * // TypeScript knows "api" is enabled here
77
+ * const result = handleApiRequest(...);
78
+ * }
79
+ */
80
+ export function isFeatureAvailable(features, feature) {
81
+ return isFeatureEnabled(features, feature);
82
+ }
83
+ /**
84
+ * Wraps a function to guard against disabled features.
85
+ * Returns a function that checks feature before execution.
86
+ *
87
+ * @example
88
+ * export const setupCache = guardedFunction("cache", (features) => {
89
+ * // This only runs if cache feature is enabled
90
+ * });
91
+ */
92
+ export function guardedFunction(feature, fn, context) {
93
+ return (...args) => {
94
+ const features = args[0];
95
+ guardFeature(features, feature, context);
96
+ return fn(...args);
97
+ };
98
+ }
99
+ /**
100
+ * Async version of guardedFunction for async handlers.
101
+ */
102
+ export function guardedAsyncFunction(feature, fn, context) {
103
+ return async (...args) => {
104
+ const features = args[0];
105
+ guardFeature(features, feature, context);
106
+ return fn(...args);
107
+ };
108
+ }
109
+ /**
110
+ * Creates a feature validation middleware.
111
+ * Checks if required feature is enabled before processing request.
112
+ *
113
+ * @example
114
+ * app.use(featureMiddleware("api", (ctx, next) => {
115
+ * // Only runs if api feature is enabled
116
+ * return handleApiRequest(ctx);
117
+ * }));
118
+ */
119
+ export function createFeatureMiddleware(feature, context) {
120
+ return (features) => {
121
+ guardFeature(features, feature, context);
122
+ };
123
+ }
124
+ /**
125
+ * Validates feature configuration against a schema.
126
+ */
127
+ export function validateFeatureConfig(feature, config, validator) {
128
+ if (!validator) return;
129
+ const result = validator.validate(config);
130
+ if (!result.valid) {
131
+ throw new FeatureConfigError(
132
+ feature,
133
+ result.errors?.join("; ") || "Invalid configuration",
134
+ );
135
+ }
136
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Feature System for Jen.js
3
+ *
4
+ * Allows optional features to be enabled/disabled at build time.
5
+ * Disabled features are completely tree-shaken, adding zero runtime overhead.
6
+ *
7
+ * Features are configured in jen.config.ts and enabled/disabled individually.
8
+ * Each feature must be explicitly enabled for its code to be included in the bundle.
9
+ */
10
+ /**
11
+ * Default features enabled when none specified.
12
+ * Minimal set to maintain backward compatibility.
13
+ * Users should explicitly enable features they use.
14
+ */
15
+ export const DEFAULT_FEATURES = {
16
+ api: false,
17
+ middleware: false,
18
+ markdown: false,
19
+ imageOpt: false,
20
+ env: true, // Environment variables needed by default
21
+ cache: false,
22
+ streaming: false,
23
+ auth: false,
24
+ graphql: false,
25
+ db: false,
26
+ i18n: false,
27
+ jdb: false,
28
+ compilers: false,
29
+ import: false,
30
+ };
31
+ /**
32
+ * Validates and normalizes user feature configuration.
33
+ * Ensures all features have explicit enabled/disabled status.
34
+ *
35
+ * @param userConfig User-provided feature config from jen.config.ts
36
+ * @returns Resolved features with all present and validated
37
+ */
38
+ export function resolveFeatures(userConfig) {
39
+ const resolved = { ...DEFAULT_FEATURES };
40
+ if (!userConfig) return resolved;
41
+ for (const [key, value] of Object.entries(userConfig)) {
42
+ if (!(key in DEFAULT_FEATURES)) {
43
+ console.warn(
44
+ `⚠️ Unknown feature: "${key}". Valid features are: ${Object.keys(DEFAULT_FEATURES).join(", ")}`,
45
+ );
46
+ continue;
47
+ }
48
+ // Support boolean shorthand and object with enabled property
49
+ const isEnabled =
50
+ typeof value === "boolean" ? value : value?.enabled !== false;
51
+ resolved[key] = isEnabled;
52
+ }
53
+ return resolved;
54
+ }
55
+ /**
56
+ * Returns list of enabled feature names.
57
+ */
58
+ export function getEnabledFeatures(resolved) {
59
+ return Object.entries(resolved)
60
+ .filter(([, enabled]) => enabled)
61
+ .map(([name]) => name);
62
+ }
63
+ /**
64
+ * Returns list of disabled feature names.
65
+ */
66
+ export function getDisabledFeatures(resolved) {
67
+ return Object.entries(resolved)
68
+ .filter(([, enabled]) => !enabled)
69
+ .map(([name]) => name);
70
+ }
71
+ /**
72
+ * Checks if a specific feature is enabled.
73
+ */
74
+ export function isFeatureEnabled(resolved, feature) {
75
+ return resolved[feature] ?? false;
76
+ }
77
+ /**
78
+ * Runtime assertion that a feature is enabled.
79
+ * Throws helpful error if feature is disabled.
80
+ */
81
+ export function requireFeature(resolved, feature, context) {
82
+ if (!isFeatureEnabled(resolved, feature)) {
83
+ const msg =
84
+ `Feature "${feature}" is not enabled. ` +
85
+ `Enable it in jen.config.ts: features: { ${feature}: true }${context ? ` (${context})` : ""}`;
86
+ throw new Error(msg);
87
+ }
88
+ }
89
+ /**
90
+ * Creates build metadata for introspection and debugging.
91
+ */
92
+ export function createBuildMetadata(resolved, config) {
93
+ return {
94
+ buildTime: new Date().toISOString(),
95
+ enabledFeatures: getEnabledFeatures(resolved),
96
+ disabledFeatures: getDisabledFeatures(resolved),
97
+ config,
98
+ };
99
+ }
@@ -1,20 +1,3 @@
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
  /**
19
2
  * Parses the HTTP Cookie header into an object of name-value pairs.
20
3
  *
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Nested layouts system for Jen.js
3
+ * Provides automatic parent-child layout relationships with inheritance and overrides.
4
+ */
5
+ export { scanLayouts, buildLayoutHierarchy } from "./scan.js";
6
+ export {
7
+ resolveLayoutStack,
8
+ renderWithLayoutStack,
9
+ collectLayoutHeads,
10
+ } from "./render.js";
@@ -0,0 +1,158 @@
1
+ import { h } from "preact";
2
+ import { pathToFileURL } from "node:url";
3
+ import esbuild from "esbuild";
4
+ import { join } from "node:path";
5
+ import { mkdirSync, existsSync } from "node:fs";
6
+ import {
7
+ vueEsbuildPlugin,
8
+ svelteEsbuildPlugin,
9
+ } from "../../compilers/esbuild-plugins.js";
10
+ /**
11
+ * Resolves the cache directory path for compiled layout modules.
12
+ * Similar to route module caching to avoid repeated compilation.
13
+ *
14
+ * @param filePath The absolute path to the original layout file
15
+ * @returns The absolute path to the cached compiled output file
16
+ */
17
+ function getCachePath(filePath) {
18
+ const cacheDir = join(process.cwd(), "node_modules", ".jen", "cache");
19
+ if (!existsSync(cacheDir)) {
20
+ mkdirSync(cacheDir, { recursive: true });
21
+ }
22
+ const flatName = filePath.replace(/[\\/:]/g, "_").replace(/^_+/, "");
23
+ return join(cacheDir, flatName + ".layout.mjs");
24
+ }
25
+ /**
26
+ * Loads and compiles a layout module from file.
27
+ * Handles TypeScript/JSX/Vue/Svelte transpilation.
28
+ *
29
+ * @param filePath The absolute path to the layout file
30
+ * @returns The imported LayoutModule
31
+ * @throws Error if compilation or import fails
32
+ */
33
+ async function loadLayoutModule(filePath) {
34
+ let moduleUrl = filePath;
35
+ const ext = filePath.slice(-4).toLowerCase();
36
+ const requiresTranspile = [".tsx", ".ts", ".vue", ".svelte"].some((e) =>
37
+ filePath.toLowerCase().endsWith(e),
38
+ );
39
+ if (requiresTranspile) {
40
+ const outfile = getCachePath(filePath);
41
+ await esbuild.build({
42
+ entryPoints: [filePath],
43
+ outfile,
44
+ format: "esm",
45
+ platform: "node",
46
+ target: "es2022",
47
+ bundle: true,
48
+ external: ["preact", "preact-render-to-string", "jenjs"],
49
+ write: true,
50
+ plugins: [vueEsbuildPlugin(), svelteEsbuildPlugin()],
51
+ });
52
+ moduleUrl = outfile;
53
+ }
54
+ let mod;
55
+ try {
56
+ mod = await import(pathToFileURL(moduleUrl).href + "?t=" + Date.now());
57
+ } catch (err) {
58
+ throw new Error(
59
+ `Failed to import layout module ${filePath}: ${err instanceof Error ? err.message : String(err)}`,
60
+ );
61
+ }
62
+ // Validate that default export exists
63
+ if (!mod.default) {
64
+ throw new Error(
65
+ `Layout module ${filePath} does not export a default component`,
66
+ );
67
+ }
68
+ return mod;
69
+ }
70
+ /**
71
+ * Resolves the complete layout stack for a route.
72
+ * Loads all applicable layouts, merges their configuration, and prepares them for rendering.
73
+ *
74
+ * Configuration is merged from root to leaf, with child configurations overriding parent values.
75
+ *
76
+ * @param layoutEntries All layout entries applicable to this route (from buildLayoutHierarchy)
77
+ * @returns Resolved layout stack with modules and merged configuration
78
+ * @throws Error if any layout file fails to load
79
+ */
80
+ export async function resolveLayoutStack(layoutEntries) {
81
+ const modules = [];
82
+ let mergedConfig = {};
83
+ // Load and process layouts in order (root to leaf)
84
+ for (const entry of layoutEntries) {
85
+ const mod = await loadLayoutModule(entry.filePath);
86
+ modules.push(mod);
87
+ // Merge configuration (child overrides parent)
88
+ if (mod.layout) {
89
+ mergedConfig = {
90
+ ...mergedConfig,
91
+ ...mod.layout,
92
+ };
93
+ }
94
+ }
95
+ return {
96
+ modules,
97
+ config: mergedConfig,
98
+ };
99
+ }
100
+ /**
101
+ * Renders a component wrapped in a layout hierarchy.
102
+ * Composes all layouts from root to leaf, passing the child content down the tree.
103
+ *
104
+ * The composition works as:
105
+ * RootLayout wraps (BlogLayout wraps (PageLayout wraps (PageComponent)))
106
+ *
107
+ * Each layout receives:
108
+ * - children: The rendered output from the child layout or page component
109
+ * - data: Data passed from page loader
110
+ * - params: URL parameters
111
+ * - query: Query string parameters
112
+ *
113
+ * @param layoutStack The resolved layout stack
114
+ * @param pageComponent The Preact component to render as the deepest child
115
+ * @param props Props to pass through the layout hierarchy (data, params, query)
116
+ * @returns Preact VNode representing the composed layout tree
117
+ */
118
+ export function renderWithLayoutStack(layoutStack, pageComponent, props) {
119
+ // Start with the page component as the innermost content
120
+ let content = h(pageComponent, props);
121
+ // Wrap with layouts from deepest to root (reverse order)
122
+ for (let i = layoutStack.modules.length - 1; i >= 0; i--) {
123
+ const layoutMod = layoutStack.modules[i];
124
+ const Layout = layoutMod.default;
125
+ // Pass children and props to each layout
126
+ content = h(Layout, {
127
+ children: content,
128
+ ...props,
129
+ });
130
+ }
131
+ return content;
132
+ }
133
+ /**
134
+ * Collects all Head components from the layout stack.
135
+ * Head components are rendered in order from root to leaf, allowing layouts
136
+ * to contribute to document head (meta tags, title, links, etc.).
137
+ *
138
+ * @param layoutStack The resolved layout stack
139
+ * @param pageHeadComponent Optional Head component from the page
140
+ * @param props Props to pass to Head components
141
+ * @returns Array of rendered Head VNodes
142
+ */
143
+ export function collectLayoutHeads(layoutStack, pageHeadComponent, props) {
144
+ const heads = [];
145
+ // Collect heads from layouts (root to leaf)
146
+ for (const layoutMod of layoutStack.modules) {
147
+ if (layoutMod.Head) {
148
+ const headNode = h(layoutMod.Head, props);
149
+ heads.push(headNode);
150
+ }
151
+ }
152
+ // Page head comes last
153
+ if (pageHeadComponent) {
154
+ const headNode = h(pageHeadComponent, props);
155
+ heads.push(headNode);
156
+ }
157
+ return heads;
158
+ }
@@ -0,0 +1,112 @@
1
+ import { readdirSync, statSync } from "node:fs";
2
+ import { join, relative, sep, dirname } from "node:path";
3
+ /**
4
+ * Recursively walks a directory and returns all file paths.
5
+ * Used to discover all layout files in the siteDir.
6
+ *
7
+ * @param dir Directory path to walk
8
+ * @returns Flat array of all file paths found
9
+ */
10
+ function walk(dir) {
11
+ const out = [];
12
+ try {
13
+ for (const name of readdirSync(dir)) {
14
+ const p = join(dir, name);
15
+ const st = statSync(p);
16
+ if (st.isDirectory()) out.push(...walk(p));
17
+ else out.push(p);
18
+ }
19
+ } catch {
20
+ // Ignore errors reading directories
21
+ }
22
+ return out;
23
+ }
24
+ /**
25
+ * Normalizes filesystem path separators to forward slashes.
26
+ * Ensures consistent path format across Windows and Unix systems.
27
+ *
28
+ * @param p Path with possibly mixed separators
29
+ * @returns Path with forward slashes only
30
+ */
31
+ function normalizeSlashes(p) {
32
+ return p.split(sep).join("/");
33
+ }
34
+ /**
35
+ * Scans the configured siteDir for layout files and returns an ordered list.
36
+ * Layout files must be named (layout).tsx, (layout).ts, (layout).jsx, or (layout).js
37
+ * and are discovered at any directory level within siteDir.
38
+ *
39
+ * Layouts are automatically discovered and organized by their directory depth,
40
+ * allowing for automatic hierarchy building based on file structure.
41
+ *
42
+ * @param config Framework configuration with siteDir and route patterns
43
+ * @returns Array of LayoutEntry objects, sorted by depth (root layout first)
44
+ */
45
+ export function scanLayouts(config) {
46
+ const siteRoot = join(process.cwd(), config.siteDir);
47
+ const files = walk(siteRoot);
48
+ const layouts = [];
49
+ for (const abs of files) {
50
+ const rel = normalizeSlashes(relative(siteRoot, abs));
51
+ // Check if this is a layout file with correct extension
52
+ const extMatch = config.routes.fileExtensions.some((ext) =>
53
+ rel.endsWith(`(layout)${ext}`),
54
+ );
55
+ if (!extMatch) continue;
56
+ // Get the directory containing this layout file
57
+ const dirPath = normalizeSlashes(dirname(rel));
58
+ const depth = dirPath === "." ? 0 : dirPath.split("/").length;
59
+ layouts.push({
60
+ id: `layout_${rel.replaceAll("/", "_").replace(/\.\w+$/, "")}`,
61
+ filePath: abs,
62
+ depth,
63
+ dirPath: dirPath === "." ? "" : dirPath,
64
+ });
65
+ }
66
+ // Sort by depth (root/shallowest first)
67
+ layouts.sort((a, b) => a.depth - b.depth);
68
+ return layouts;
69
+ }
70
+ /**
71
+ * Builds the layout hierarchy for a given route path.
72
+ * Finds all parent layouts that should apply to this route by tracing
73
+ * the directory structure from root down to the route's directory.
74
+ *
75
+ * Example: For route "pages/blog/post/(post).tsx", returns layouts at:
76
+ * - (layout).tsx (root)
77
+ * - pages/(layout).tsx (if exists)
78
+ * - pages/blog/(layout).tsx (if exists)
79
+ *
80
+ * @param layoutEntries All discovered layout entries (from scanLayouts)
81
+ * @param routePath The filesystem path of the route file
82
+ * @returns Array of LayoutEntry objects in order (root to leaf)
83
+ */
84
+ export function buildLayoutHierarchy(layoutEntries, routePath, siteDir) {
85
+ // Get the directory containing the route
86
+ const routeDir = dirname(routePath);
87
+ // Normalize path relative to siteDir
88
+ const siteRoot = join(process.cwd(), siteDir);
89
+ const relRouteDir = normalizeSlashes(relative(siteRoot, routeDir));
90
+ // Split the route directory into segments
91
+ const segments = relRouteDir === "." ? [] : relRouteDir.split("/");
92
+ // Find applicable layouts by checking each level of the hierarchy
93
+ const applicable = [];
94
+ // Check root layout first
95
+ const rootLayout = layoutEntries.find(
96
+ (l) => l.depth === 0 && l.dirPath === "",
97
+ );
98
+ if (rootLayout) {
99
+ applicable.push(rootLayout);
100
+ }
101
+ // Check layouts at each level
102
+ for (let i = 1; i <= segments.length; i++) {
103
+ const dirPath = segments.slice(0, i).join("/");
104
+ const layout = layoutEntries.find(
105
+ (l) => l.dirPath === dirPath && l.depth === i,
106
+ );
107
+ if (layout) {
108
+ applicable.push(layout);
109
+ }
110
+ }
111
+ return applicable;
112
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,129 @@
1
+ import { log } from "../shared/log.js";
2
+ /**
3
+ * Lifecycle manager for graceful shutdown of the HTTP server.
4
+ * Tracks active requests and ensures they complete before closing.
5
+ * Handles signal interrupts (SIGTERM, SIGINT) gracefully.
6
+ */
7
+ export class GracefulShutdown {
8
+ activeRequests = new Set();
9
+ isShuttingDown = false;
10
+ shutdownTimeout = 30000; // 30s timeout for graceful shutdown
11
+ signalHandlers = [];
12
+ /**
13
+ * Tracks an incoming request.
14
+ * Call this when a request begins.
15
+ */
16
+ trackRequest(req) {
17
+ this.activeRequests.add(req);
18
+ }
19
+ /**
20
+ * Untrack a request when it completes.
21
+ * Call this when a request ends.
22
+ */
23
+ releaseRequest(req) {
24
+ this.activeRequests.delete(req);
25
+ }
26
+ /**
27
+ * Get the count of active requests still in flight.
28
+ */
29
+ getActiveRequestCount() {
30
+ return this.activeRequests.size;
31
+ }
32
+ /**
33
+ * Check if shutdown is in progress.
34
+ */
35
+ isShuttingDown_() {
36
+ return this.isShuttingDown;
37
+ }
38
+ /**
39
+ * Wait for all active requests to complete, with timeout.
40
+ * Useful before closing server resources.
41
+ *
42
+ * @returns Promise that resolves when all requests complete or timeout
43
+ */
44
+ async waitForActiveRequests() {
45
+ const startTime = Date.now();
46
+ const pollInterval = 100; // ms
47
+ return new Promise((resolve) => {
48
+ const poll = () => {
49
+ if (this.activeRequests.size === 0) {
50
+ log.info(
51
+ `[Graceful Shutdown] All ${this.activeRequests.size} requests completed`,
52
+ );
53
+ resolve();
54
+ return;
55
+ }
56
+ const elapsed = Date.now() - startTime;
57
+ if (elapsed > this.shutdownTimeout) {
58
+ log.warn(
59
+ `[Graceful Shutdown] Timeout after ${elapsed}ms with ${this.activeRequests.size} requests still active`,
60
+ );
61
+ resolve();
62
+ return;
63
+ }
64
+ setTimeout(poll, pollInterval);
65
+ };
66
+ poll();
67
+ });
68
+ }
69
+ /**
70
+ * Handle shutdown signal (SIGTERM or SIGINT).
71
+ * Prevents accepting new requests and waits for in-flight ones.
72
+ *
73
+ * @param signal Signal name that was received
74
+ * @param onClose Callback to execute when ready to close server
75
+ */
76
+ async handleShutdownSignal(signal, onClose) {
77
+ if (this.isShuttingDown) {
78
+ log.warn(`[Graceful Shutdown] Already shutting down, ignoring ${signal}`);
79
+ return;
80
+ }
81
+ this.isShuttingDown = true;
82
+ log.warn(
83
+ `[Graceful Shutdown] ${signal} received, starting graceful shutdown`,
84
+ );
85
+ log.info(
86
+ `[Graceful Shutdown] ${this.activeRequests.size} active request(s)`,
87
+ );
88
+ // Wait for active requests to complete
89
+ await this.waitForActiveRequests();
90
+ // Close server resources
91
+ log.info("[Graceful Shutdown] Closing server resources");
92
+ await onClose();
93
+ log.info("[Graceful Shutdown] Clean shutdown complete");
94
+ }
95
+ /**
96
+ * Register signal handlers for graceful shutdown.
97
+ * Handles SIGTERM and SIGINT.
98
+ *
99
+ * @param onClose Callback to execute when closing resources
100
+ */
101
+ registerSignalHandlers(onClose) {
102
+ const handleSignal = async (signal) => {
103
+ await this.handleShutdownSignal(signal, onClose);
104
+ process.exit(0);
105
+ };
106
+ // Handle both SIGTERM (terminate) and SIGINT (Ctrl+C)
107
+ process.on("SIGTERM", () => handleSignal("SIGTERM"));
108
+ process.on("SIGINT", () => handleSignal("SIGINT"));
109
+ log.info("[Graceful Shutdown] Signal handlers registered");
110
+ }
111
+ /**
112
+ * Clean up signal handlers.
113
+ * Useful for cleanup in tests or when you need to unregister.
114
+ */
115
+ unregisterSignalHandlers() {
116
+ process.removeAllListeners("SIGTERM");
117
+ process.removeAllListeners("SIGINT");
118
+ }
119
+ /**
120
+ * Set the timeout for graceful shutdown (in milliseconds).
121
+ * Default is 30s.
122
+ *
123
+ * @param timeoutMs Timeout in milliseconds
124
+ */
125
+ setShutdownTimeout(timeoutMs) {
126
+ this.shutdownTimeout = timeoutMs;
127
+ }
128
+ }
129
+ export default GracefulShutdown;