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