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.
- package/dist/colors.js +0 -17
- package/dist/create.js +5 -17
- package/dist/generator.js +14 -31
- package/dist/index.js +6 -1
- package/package.json +1 -1
- package/templates/ssr-isr/README.md +77 -0
- package/templates/ssr-isr/build.js +118 -0
- package/templates/ssr-isr/jen.config.ts +109 -0
- package/templates/ssr-isr/jenjs.d.ts +22 -0
- package/templates/ssr-isr/lib/api/(hello).js +9 -0
- package/templates/ssr-isr/lib/auth/cookie-utils.js +79 -0
- package/templates/ssr-isr/lib/auth/index.js +2 -0
- package/templates/ssr-isr/lib/auth/jwt.js +57 -0
- package/templates/ssr-isr/lib/auth/session.js +92 -0
- package/templates/ssr-isr/lib/build/asset-hashing.d.ts +10 -0
- package/templates/ssr-isr/lib/build/asset-hashing.js +25 -0
- package/templates/ssr-isr/lib/build/asset-manifest.d.ts +11 -0
- package/templates/ssr-isr/lib/build/asset-manifest.js +21 -0
- package/templates/{static → ssr-isr}/lib/build/build.d.ts +1 -1
- package/templates/ssr-isr/lib/build/build.js +141 -0
- package/templates/{static → ssr-isr}/lib/build/island-hydration.d.ts +8 -5
- package/templates/ssr-isr/lib/build/island-hydration.js +44 -0
- package/templates/ssr-isr/lib/build/minifier.d.ts +20 -0
- package/templates/ssr-isr/lib/build/minifier.js +46 -0
- package/templates/ssr-isr/lib/build/page-renderer.d.ts +17 -0
- package/templates/ssr-isr/lib/build/page-renderer.js +28 -0
- package/templates/ssr-isr/lib/build/production-build.d.ts +10 -0
- package/templates/ssr-isr/lib/build/production-build.js +13 -0
- package/templates/ssr-isr/lib/build/ssg-pipeline.d.ts +15 -0
- package/templates/ssr-isr/lib/build/ssg-pipeline.js +113 -0
- package/templates/ssr-isr/lib/build-tools/build-site.js +36 -0
- package/templates/ssr-isr/lib/cache/index.js +10 -0
- package/templates/ssr-isr/lib/cache/memory.js +40 -0
- package/templates/ssr-isr/lib/cache/redis.js +61 -0
- package/templates/ssr-isr/lib/cli/banner.js +28 -0
- package/templates/ssr-isr/lib/cli/templates/ssg/jen.config.js +32 -0
- package/templates/ssr-isr/lib/cli/templates/ssg/site/index.js +9 -0
- package/templates/ssr-isr/lib/cli/templates/ssr/jen.config.js +32 -0
- package/templates/ssr-isr/lib/cli/templates/ssr/site/index.js +9 -0
- package/templates/ssr-isr/lib/compilers/esbuild-plugins.js +111 -0
- package/templates/ssr-isr/lib/compilers/svelte.js +44 -0
- package/templates/ssr-isr/lib/compilers/vue.js +90 -0
- package/templates/ssr-isr/lib/core/http.js +71 -0
- package/templates/ssr-isr/lib/core/middleware-hooks.js +97 -0
- package/templates/ssr-isr/lib/core/paths.js +39 -0
- package/templates/ssr-isr/lib/core/routes/match.js +47 -0
- package/templates/ssr-isr/lib/core/routes/scan.js +190 -0
- package/templates/ssr-isr/lib/core/types.js +1 -0
- package/templates/ssr-isr/lib/css/compiler.js +74 -0
- package/templates/ssr-isr/lib/db/connector.js +42 -0
- package/templates/ssr-isr/lib/db/drivers/jdb.js +44 -0
- package/templates/ssr-isr/lib/db/drivers/sql.js +182 -0
- package/templates/ssr-isr/lib/db/index.js +48 -0
- package/templates/ssr-isr/lib/db/types.js +1 -0
- package/templates/ssr-isr/lib/graphql/index.js +52 -0
- package/templates/ssr-isr/lib/graphql/resolvers.js +25 -0
- package/templates/ssr-isr/lib/graphql/schema.js +35 -0
- package/templates/ssr-isr/lib/i18n/en.json +4 -0
- package/templates/ssr-isr/lib/i18n/es.json +4 -0
- package/templates/ssr-isr/lib/i18n/index.js +15 -0
- package/templates/ssr-isr/lib/import/jen-import.js +161 -0
- package/templates/ssr-isr/lib/index.js +116 -0
- package/templates/ssr-isr/lib/jdb/engine.js +275 -0
- package/templates/ssr-isr/lib/jdb/index.js +34 -0
- package/templates/ssr-isr/lib/jdb/types.js +1 -0
- package/templates/ssr-isr/lib/jdb/utils.js +176 -0
- package/templates/{static → ssr-isr}/lib/middleware/builtins/body-parser.js +0 -17
- package/templates/ssr-isr/lib/middleware/builtins/cors.js +54 -0
- package/templates/{static → ssr-isr}/lib/middleware/builtins/logger.js +0 -17
- package/templates/{static → ssr-isr}/lib/middleware/builtins/rate-limit.js +0 -17
- package/templates/{static → ssr-isr}/lib/middleware/builtins/request-id.js +0 -17
- package/templates/{static → ssr-isr}/lib/middleware/builtins/security-headers.js +0 -17
- package/templates/ssr-isr/lib/middleware/context.js +124 -0
- package/templates/{static → ssr-isr}/lib/middleware/decorators.js +0 -17
- package/templates/{static → ssr-isr}/lib/middleware/errors/handler.js +0 -17
- package/templates/ssr-isr/lib/middleware/errors/http-error.js +10 -0
- package/templates/ssr-isr/lib/middleware/kernel.js +85 -0
- package/templates/ssr-isr/lib/middleware/pipeline.js +148 -0
- package/templates/ssr-isr/lib/middleware/registry.js +85 -0
- package/templates/ssr-isr/lib/middleware/response.js +107 -0
- package/templates/ssr-isr/lib/middleware/types.d.ts +1 -0
- package/templates/ssr-isr/lib/middleware/types.js +1 -0
- package/templates/ssr-isr/lib/middleware/utils/matcher.js +13 -0
- package/templates/{static → ssr-isr}/lib/native/bundle.js +0 -17
- package/templates/{static → ssr-isr}/lib/native/dev-server.js +0 -17
- package/templates/{static → ssr-isr}/lib/native/index.js +0 -17
- package/templates/{static → ssr-isr}/lib/native/optimizer.js +0 -17
- package/templates/ssr-isr/lib/native/style-compiler.js +19 -0
- package/templates/ssr-isr/lib/plugin/loader.js +36 -0
- package/templates/ssr-isr/lib/runtime/client-runtime.js +25 -0
- package/templates/ssr-isr/lib/runtime/hmr.js +59 -0
- package/templates/ssr-isr/lib/runtime/hydrate.js +55 -0
- package/templates/ssr-isr/lib/runtime/island-hydration-client.js +146 -0
- package/templates/ssr-isr/lib/runtime/islands.js +110 -0
- package/templates/ssr-isr/lib/runtime/render.js +244 -0
- package/templates/ssr-isr/lib/server/api-routes.js +237 -0
- package/templates/ssr-isr/lib/server/api.js +108 -0
- package/templates/ssr-isr/lib/server/app.js +438 -0
- package/templates/ssr-isr/lib/server/runtimeServe.js +169 -0
- package/templates/ssr-isr/lib/server/ssr.js +202 -0
- package/templates/ssr-isr/lib/shared/log.js +64 -0
- package/templates/ssr-isr/package.json +23 -0
- package/templates/ssr-isr/server.js +128 -0
- package/templates/ssr-isr/site/pages/(index).tsx +11 -0
- package/templates/ssr-isr/site/styles/global.scss +37 -0
- package/templates/ssr-isr/tsconfig.json +39 -0
- package/templates/static/build.js +30 -18
- package/templates/static/jen.config.ts +0 -18
- package/templates/static/jenjs.d.ts +0 -18
- package/templates/static/lib/api/(hello).js +0 -17
- package/templates/static/lib/api/examples/files/[...slug].js +22 -0
- package/templates/static/lib/api/examples/hello.js +11 -0
- package/templates/static/lib/api/examples/posts/[id].js +37 -0
- package/templates/static/lib/api/examples/posts.js +37 -0
- package/templates/static/lib/api/examples/search.js +23 -0
- package/templates/static/lib/api/index.js +41 -0
- package/templates/static/lib/api/loader.js +234 -0
- package/templates/static/lib/api/router.js +259 -0
- package/templates/static/lib/assets/types.js +1 -0
- package/templates/static/lib/auth/cookie-utils.js +3 -16
- package/templates/static/lib/auth/index.js +0 -17
- package/templates/static/lib/auth/jwt.js +0 -17
- package/templates/static/lib/auth/session.js +0 -17
- package/templates/static/lib/build/asset-hashing.js +44 -36
- package/templates/static/lib/build/asset-manifest.js +16 -33
- package/templates/static/lib/build/build.js +270 -125
- package/templates/static/lib/build/bundle-analyzer-ui.js +417 -0
- package/templates/static/lib/build/bundle-analyzer.js +945 -0
- package/templates/static/lib/build/code-splitter.js +194 -0
- package/templates/static/lib/build/feature-analyzer.js +190 -0
- package/templates/static/lib/build/feature-gate.js +257 -0
- package/templates/static/lib/build/island-hydration.js +17 -35
- package/templates/static/lib/build/lazy-loader.js +322 -0
- package/templates/static/lib/build/minifier.js +40 -59
- package/templates/static/lib/build/page-renderer.js +23 -40
- package/templates/static/lib/build/production-build.js +9 -26
- package/templates/static/lib/build/rust-hashing.js +71 -0
- package/templates/static/lib/build/script-optimizer.js +285 -0
- package/templates/static/lib/build/ssg-pipeline.js +100 -106
- package/templates/static/lib/build/vercel-output.js +298 -0
- package/templates/static/lib/build-tools/build-site.js +0 -17
- package/templates/static/lib/cache/index.js +0 -17
- package/templates/static/lib/cache/memory.js +0 -17
- package/templates/static/lib/cache/redis.js +0 -17
- package/templates/static/lib/cli/banner.js +0 -17
- package/templates/static/lib/cli/templates/ssg/jen.config.js +0 -17
- package/templates/static/lib/cli/templates/ssr/jen.config.js +0 -17
- package/templates/static/lib/client/Image.js +42 -0
- package/templates/static/lib/client/Link.js +190 -0
- package/templates/static/lib/client/PWA.js +46 -0
- package/templates/static/lib/client/Seo.js +97 -0
- package/templates/static/lib/client/index.js +9 -0
- package/templates/static/lib/client/useNavigation.js +25 -0
- package/templates/static/lib/client/useRouter.js +64 -0
- package/templates/static/lib/client-routing/Link.js +17 -0
- package/templates/static/lib/client-routing/index.js +19 -0
- package/templates/static/lib/client-routing/router.js +151 -0
- package/templates/static/lib/client-routing/signal.js +147 -0
- package/templates/static/lib/compilers/esbuild-plugins.js +0 -17
- package/templates/static/lib/compilers/svelte.js +0 -17
- package/templates/static/lib/compilers/vue.js +0 -17
- package/templates/static/lib/core/config.js +0 -17
- package/templates/static/lib/core/feature-guard.js +136 -0
- package/templates/static/lib/core/features.js +99 -0
- package/templates/static/lib/core/http.js +0 -17
- package/templates/static/lib/core/layouts/index.js +10 -0
- package/templates/static/lib/core/layouts/render.js +158 -0
- package/templates/static/lib/core/layouts/scan.js +112 -0
- package/templates/static/lib/core/layouts/types.js +1 -0
- package/templates/static/lib/core/lifecycle.js +129 -0
- package/templates/static/lib/core/loader-schema.js +81 -0
- package/templates/static/lib/core/middleware-hooks.js +0 -17
- package/templates/static/lib/core/paths.js +0 -17
- package/templates/static/lib/core/routes/advanced.js +114 -0
- package/templates/static/lib/core/routes/handlers.js +181 -0
- package/templates/static/lib/core/routes/match.js +89 -17
- package/templates/static/lib/core/routes/orchestrator.js +171 -0
- package/templates/static/lib/core/routes/rendering-config.js +131 -0
- package/templates/static/lib/core/routes/scan.js +0 -17
- package/templates/static/lib/core/types.js +0 -17
- package/templates/static/lib/css/compiler.js +1 -18
- package/templates/static/lib/data-fetching/cache.js +223 -0
- package/templates/static/lib/data-fetching/client.js +202 -0
- package/templates/static/lib/data-fetching/feature-guard.js +29 -0
- package/templates/static/lib/data-fetching/graphql.js +265 -0
- package/templates/static/lib/data-fetching/index.js +57 -0
- package/templates/static/lib/data-fetching/rest.js +256 -0
- package/templates/static/lib/data-fetching/server.js +182 -0
- package/templates/static/lib/data-fetching/types.js +5 -0
- package/templates/static/lib/db/connector.js +0 -17
- package/templates/static/lib/db/drivers/jdb.js +0 -17
- package/templates/static/lib/db/drivers/sql.js +0 -17
- package/templates/static/lib/db/index.js +0 -17
- package/templates/static/lib/db/types.js +0 -17
- package/templates/static/lib/devtools/component-tree.js +106 -0
- package/templates/static/lib/devtools/devtools.js +638 -0
- package/templates/static/lib/devtools/event-bus.js +29 -0
- package/templates/static/lib/devtools/event-logger.js +67 -0
- package/templates/static/lib/devtools/index.js +9 -0
- package/templates/static/lib/devtools/integration.js +149 -0
- package/templates/static/lib/devtools/performance.js +84 -0
- package/templates/static/lib/devtools/persistence.js +57 -0
- package/templates/static/lib/devtools/plugins.js +97 -0
- package/templates/static/lib/devtools/search.js +89 -0
- package/templates/static/lib/devtools/ui.js +769 -0
- package/templates/static/lib/features/api/handler.js +10 -0
- package/templates/static/lib/features/api/index.js +5 -0
- package/templates/static/lib/features/api/types.js +4 -0
- package/templates/static/lib/features/middleware/compiled.js +7 -0
- package/templates/static/lib/features/middleware/index.js +5 -0
- package/templates/static/lib/features/middleware/types.js +4 -0
- package/templates/static/lib/fonts/index.js +46 -0
- package/templates/static/lib/fonts/inject.js +125 -0
- package/templates/static/lib/fonts/loader.js +196 -0
- package/templates/static/lib/fonts/types.js +1 -0
- package/templates/static/lib/graphql/index.js +1 -18
- package/templates/static/lib/graphql/resolvers.js +20 -13
- package/templates/static/lib/graphql/schema.js +0 -17
- package/templates/static/lib/i18n/index.js +7 -19
- package/templates/static/lib/import/jen-import.js +1 -18
- package/templates/static/lib/index.js +79 -125
- package/templates/static/lib/jdb/engine.js +0 -17
- package/templates/static/lib/jdb/index.js +1 -18
- package/templates/static/lib/jdb/types.js +0 -17
- package/templates/static/lib/jdb/utils.js +0 -17
- package/templates/static/lib/middleware/builtins/cors.js +3 -16
- package/templates/static/lib/middleware/context.js +0 -17
- package/templates/static/lib/middleware/kernel.js +117 -25
- package/templates/static/lib/middleware/pipeline.js +0 -17
- package/templates/static/lib/middleware/registry.js +0 -17
- package/templates/static/lib/middleware/response.js +0 -17
- package/templates/static/lib/plugin/examples/analytics-plugin.js +183 -0
- package/templates/static/lib/plugin/examples/cdn-upload-plugin.js +94 -0
- package/templates/static/lib/plugin/loader.js +0 -17
- package/templates/static/lib/plugin/plugin-manager.js +177 -0
- package/templates/static/lib/plugin/types.js +28 -0
- package/templates/static/lib/runtime/client-runtime.js +0 -17
- package/templates/static/lib/runtime/hmr.js +0 -17
- package/templates/static/lib/runtime/hydrate.js +0 -17
- package/templates/static/lib/runtime/island-hydration-client.js +0 -17
- package/templates/static/lib/runtime/islands.js +0 -17
- package/templates/static/lib/runtime/render.js +208 -50
- package/templates/static/lib/security/security-config.js +60 -0
- package/templates/static/lib/security/security-middleware.js +229 -0
- package/templates/static/lib/server/api-routes.js +153 -43
- package/templates/static/lib/server/api.js +0 -17
- package/templates/static/lib/server/app.js +539 -223
- package/templates/static/lib/server/isr.js +365 -0
- package/templates/static/lib/server/runtimeServe.js +31 -24
- package/templates/static/lib/server/ssr.js +98 -22
- package/templates/static/lib/server-actions/handler.js +180 -0
- package/templates/static/lib/server-actions/index.js +19 -0
- package/templates/static/lib/server-actions/middleware.js +146 -0
- package/templates/static/lib/server-actions/scan.js +152 -0
- package/templates/static/lib/server-actions/types.js +1 -0
- package/templates/static/lib/server-actions/validators.js +156 -0
- package/templates/static/lib/shared/log.js +19 -20
- package/templates/static/lib/telemetry/api/rate-limiter.js +32 -0
- package/templates/static/lib/telemetry/api/validator.js +67 -0
- package/templates/static/lib/telemetry/client.js +121 -0
- package/templates/static/lib/telemetry/tests/rate-limiter.test.js +46 -0
- package/templates/static/lib/telemetry/tests/validator.test.js +62 -0
- package/templates/static/lib/vendor/glob/glob.js +4766 -0
- package/templates/static/lib/vendor/preact/LICENSE +21 -0
- package/templates/static/lib/vendor/preact/preact.module.js +797 -0
- package/templates/static/lib/vendor/sass/sass.node.mjs +212 -0
- package/templates/static/package.json +4 -0
- package/templates/static/server.js +22 -22
- package/templates/static/site/(home).tsx +0 -18
- package/templates/static/tsconfig.json +5 -1
- package/templates/static/.esbuild/jen.config.js +0 -19
- package/templates/static/lib/build/asset-hashing.d.ts +0 -10
- package/templates/static/lib/build/asset-manifest.d.ts +0 -11
- package/templates/static/lib/build/minifier.d.ts +0 -20
- package/templates/static/lib/build/page-renderer.d.ts +0 -17
- package/templates/static/lib/build/production-build.d.ts +0 -10
- package/templates/static/lib/build/ssg-pipeline.d.ts +0 -15
- package/templates/static/lib/middleware/errors/http-error.js +0 -27
- package/templates/static/lib/middleware/types.js +0 -18
- package/templates/static/lib/middleware/utils/matcher.js +0 -30
- package/templates/static/lib/native/style-compiler.js +0 -36
- /package/templates/{static → ssr-isr}/lib/api/(hello).d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/auth/cookie-utils.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/auth/index.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/auth/jwt.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/auth/session.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/build-tools/build-site.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/cache/index.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/cache/memory.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/cache/redis.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/cli/banner.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/cli/templates/ssg/jen.config.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/cli/templates/ssg/site/index.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/cli/templates/ssr/jen.config.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/cli/templates/ssr/site/index.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/compilers/esbuild-plugins.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/compilers/svelte.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/compilers/vue.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/core/config.d.ts +0 -0
- /package/templates/{static/lib/middleware/types.d.ts → ssr-isr/lib/core/config.js} +0 -0
- /package/templates/{static → ssr-isr}/lib/core/http.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/core/middleware-hooks.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/core/paths.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/core/routes/match.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/core/routes/scan.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/core/types.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/css/compiler.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/db/connector.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/db/drivers/jdb.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/db/drivers/sql.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/db/index.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/db/types.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/graphql/index.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/graphql/resolvers.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/graphql/schema.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/i18n/index.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/import/jen-import.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/index.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/jdb/engine.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/jdb/index.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/jdb/types.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/jdb/utils.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/middleware/builtins/body-parser.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/middleware/builtins/cors.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/middleware/builtins/logger.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/middleware/builtins/rate-limit.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/middleware/builtins/request-id.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/middleware/builtins/security-headers.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/middleware/context.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/middleware/decorators.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/middleware/errors/handler.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/middleware/errors/http-error.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/middleware/kernel.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/middleware/pipeline.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/middleware/registry.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/middleware/response.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/middleware/utils/matcher.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/native/bundle.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/native/dev-server.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/native/index.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/native/optimizer.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/native/style-compiler.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/plugin/loader.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/runtime/client-runtime.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/runtime/hmr.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/runtime/hydrate.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/runtime/island-hydration-client.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/runtime/islands.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/runtime/render.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/server/api-routes.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/server/api.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/server/app.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/server/runtimeServe.d.ts +0 -0
- /package/templates/{static → ssr-isr}/lib/server/ssr.d.ts +0 -0
- /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;
|