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
|
@@ -1,33 +1,14 @@
|
|
|
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 { existsSync, watch } from "node:fs";
|
|
19
|
-
import { join, extname } from "node:path";
|
|
20
|
-
import sirv from "sirv";
|
|
2
|
+
import { join, extname, resolve } from "node:path";
|
|
21
3
|
import { createScssCompiler } from "../css/compiler.js";
|
|
22
4
|
import { scanRoutes } from "../core/routes/scan.js";
|
|
23
|
-
import {
|
|
5
|
+
import { createAdvancedRouter } from "../core/routes/orchestrator.js";
|
|
24
6
|
import { log } from "../shared/log.js";
|
|
25
7
|
import { Kernel } from "../middleware/kernel.js";
|
|
26
8
|
import { renderRouteToHtml } from "../runtime/render.js";
|
|
27
9
|
import { HMR_CLIENT_SCRIPT } from "../runtime/hmr.js";
|
|
28
10
|
import { headersToObject, parseCookies } from "../core/http.js";
|
|
29
11
|
import { tryHandleApiRoute } from "./api-routes.js";
|
|
30
|
-
import { resolve } from "node:path";
|
|
31
12
|
import {
|
|
32
13
|
buildHydrationModule,
|
|
33
14
|
runtimeHydrateModule,
|
|
@@ -37,6 +18,177 @@ import {
|
|
|
37
18
|
invalidateVueCache,
|
|
38
19
|
invalidateSvelteCache,
|
|
39
20
|
} from "../compilers/esbuild-plugins.js";
|
|
21
|
+
import { fontServeMiddleware } from "../fonts/inject.js";
|
|
22
|
+
import { createServerActionsMiddleware } from "../server-actions/middleware.js";
|
|
23
|
+
import { runQuery } from "../graphql/index.js";
|
|
24
|
+
import { I18n } from "../i18n/index.js";
|
|
25
|
+
import sirv from "sirv";
|
|
26
|
+
/**
|
|
27
|
+
* Manages the lifecycle of file watchers and HMR connections.
|
|
28
|
+
* Ensures proper cleanup on shutdown to prevent memory leaks.
|
|
29
|
+
*/
|
|
30
|
+
class AppLifecycle {
|
|
31
|
+
watcher = null;
|
|
32
|
+
debounceTimer = null;
|
|
33
|
+
hmrClients = new Set();
|
|
34
|
+
setWatcher(watcher) {
|
|
35
|
+
this.watcher = watcher;
|
|
36
|
+
}
|
|
37
|
+
setDebounceTimer(timer) {
|
|
38
|
+
this.debounceTimer = timer;
|
|
39
|
+
}
|
|
40
|
+
addHmrClient(client) {
|
|
41
|
+
this.hmrClients.add(client);
|
|
42
|
+
}
|
|
43
|
+
removeHmrClient(client) {
|
|
44
|
+
this.hmrClients.delete(client);
|
|
45
|
+
}
|
|
46
|
+
getHmrClients() {
|
|
47
|
+
return this.hmrClients;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Properly closes all resources.
|
|
51
|
+
* Called on server shutdown.
|
|
52
|
+
*/
|
|
53
|
+
async close() {
|
|
54
|
+
// Clear debounce timer
|
|
55
|
+
if (this.debounceTimer) {
|
|
56
|
+
clearTimeout(this.debounceTimer);
|
|
57
|
+
this.debounceTimer = null;
|
|
58
|
+
}
|
|
59
|
+
// Close all HMR connections
|
|
60
|
+
for (const client of this.hmrClients) {
|
|
61
|
+
if (!client.writableEnded && !client.destroyed) {
|
|
62
|
+
client.end();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
this.hmrClients.clear();
|
|
66
|
+
// Close file watcher
|
|
67
|
+
if (this.watcher) {
|
|
68
|
+
return new Promise((resolve) => {
|
|
69
|
+
const w = this.watcher;
|
|
70
|
+
if (w) {
|
|
71
|
+
w.close();
|
|
72
|
+
this.watcher = null;
|
|
73
|
+
}
|
|
74
|
+
resolve();
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* HTML template for 500 Internal Server Error responses.
|
|
81
|
+
* Used when middleware or request handlers throw uncaught exceptions.
|
|
82
|
+
*/
|
|
83
|
+
const ERROR_500_TEMPLATE = `<!DOCTYPE html>
|
|
84
|
+
<html lang="en">
|
|
85
|
+
<head>
|
|
86
|
+
<meta charset="UTF-8">
|
|
87
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
88
|
+
<title>500 - Internal Server Error</title>
|
|
89
|
+
<style>
|
|
90
|
+
body {
|
|
91
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
92
|
+
background: #f5f5f5;
|
|
93
|
+
margin: 0;
|
|
94
|
+
padding: 20px;
|
|
95
|
+
}
|
|
96
|
+
.container {
|
|
97
|
+
max-width: 600px;
|
|
98
|
+
margin: 60px auto;
|
|
99
|
+
background: white;
|
|
100
|
+
padding: 40px;
|
|
101
|
+
border-radius: 8px;
|
|
102
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
103
|
+
}
|
|
104
|
+
h1 {
|
|
105
|
+
color: #d32f2f;
|
|
106
|
+
margin: 0 0 20px 0;
|
|
107
|
+
font-size: 32px;
|
|
108
|
+
}
|
|
109
|
+
p {
|
|
110
|
+
color: #666;
|
|
111
|
+
line-height: 1.6;
|
|
112
|
+
margin: 10px 0;
|
|
113
|
+
}
|
|
114
|
+
.error-details {
|
|
115
|
+
background: #fafafa;
|
|
116
|
+
border-left: 4px solid #d32f2f;
|
|
117
|
+
padding: 15px;
|
|
118
|
+
margin: 20px 0;
|
|
119
|
+
font-family: monospace;
|
|
120
|
+
font-size: 12px;
|
|
121
|
+
color: #333;
|
|
122
|
+
overflow-x: auto;
|
|
123
|
+
white-space: pre-wrap;
|
|
124
|
+
word-break: break-word;
|
|
125
|
+
}
|
|
126
|
+
</style>
|
|
127
|
+
</head>
|
|
128
|
+
<body>
|
|
129
|
+
<div class="container">
|
|
130
|
+
<h1>500 - Internal Server Error</h1>
|
|
131
|
+
<p>The server encountered an unexpected error while processing your request.</p>
|
|
132
|
+
<p>Our team has been notified. Please try again later.</p>
|
|
133
|
+
<div class="error-details" id="details" style="display:none;"></div>
|
|
134
|
+
</div>
|
|
135
|
+
</body>
|
|
136
|
+
</html>`;
|
|
137
|
+
/**
|
|
138
|
+
* Sends a safe 500 error response, checking if headers have already been sent.
|
|
139
|
+
* If headers were sent, attempts to destroy the socket to prevent further data transmission.
|
|
140
|
+
* Logs the error with stack trace for debugging.
|
|
141
|
+
*
|
|
142
|
+
* @param res Node.js ServerResponse object
|
|
143
|
+
* @param error Error object or string to log
|
|
144
|
+
* @param showDetails Whether to include error details in response (dev mode)
|
|
145
|
+
*/
|
|
146
|
+
function sendSafeError(res, error, showDetails = false) {
|
|
147
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
148
|
+
const errorStack = error instanceof Error ? error.stack : "";
|
|
149
|
+
// Log error with full stack trace
|
|
150
|
+
log.error(`[Error] ${errorMsg}`);
|
|
151
|
+
if (errorStack) {
|
|
152
|
+
log.error(`Stack:\n${errorStack}`);
|
|
153
|
+
}
|
|
154
|
+
// If headers already sent, destroy socket to prevent data corruption
|
|
155
|
+
if (res.headersSent) {
|
|
156
|
+
log.error("[Error Response] Headers already sent, destroying socket");
|
|
157
|
+
if (res.socket && !res.socket.destroyed) {
|
|
158
|
+
res.socket.destroy();
|
|
159
|
+
}
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
// Send 500 response with safe error template
|
|
163
|
+
try {
|
|
164
|
+
let html = ERROR_500_TEMPLATE;
|
|
165
|
+
if (showDetails && errorStack) {
|
|
166
|
+
// In dev mode, include error details
|
|
167
|
+
html = html.replace('id="details" style="display:none;"', 'id="details"');
|
|
168
|
+
html = html.replace(
|
|
169
|
+
"<script>",
|
|
170
|
+
`<script>
|
|
171
|
+
document.getElementById('details').textContent = ${JSON.stringify(errorStack)};
|
|
172
|
+
`,
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
res.statusCode = 500;
|
|
176
|
+
res.setHeader("content-type", "text/html; charset=utf-8");
|
|
177
|
+
res.setHeader("cache-control", "no-store, no-cache, must-revalidate");
|
|
178
|
+
res.end(html);
|
|
179
|
+
} catch (e) {
|
|
180
|
+
// If error sending response, just try to end the response
|
|
181
|
+
log.error(`[Error Response] Failed to send error page: ${e}`);
|
|
182
|
+
try {
|
|
183
|
+
res.end();
|
|
184
|
+
} catch {
|
|
185
|
+
// Last resort: destroy socket
|
|
186
|
+
if (res.socket && !res.socket.destroyed) {
|
|
187
|
+
res.socket.destroy();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
40
192
|
/**
|
|
41
193
|
* Creates and configures the main HTTP application handler.
|
|
42
194
|
*
|
|
@@ -68,74 +220,86 @@ import {
|
|
|
68
220
|
export async function createApp(opts) {
|
|
69
221
|
const { config, mode, viteServer } = opts;
|
|
70
222
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* Each response object in this set receives change events for CSS updates and full reloads.
|
|
223
|
+
* Lifecycle manager for watchers and HMR connections.
|
|
224
|
+
* Ensures proper cleanup on app shutdown.
|
|
74
225
|
*/
|
|
75
|
-
const
|
|
226
|
+
const lifecycle = new AppLifecycle();
|
|
76
227
|
if (mode === "dev") {
|
|
77
228
|
const sitePath = join(process.cwd(), config.siteDir);
|
|
78
229
|
log.info(`[HMR] Watching ${sitePath} for changes...`);
|
|
79
|
-
/**
|
|
80
|
-
* Debounce timer prevents multiple rapid change notifications.
|
|
81
|
-
* Filesystem watchers often emit multiple events for a single file change.
|
|
82
|
-
* This delay coalesces rapid changes into a single notification (100ms threshold).
|
|
83
|
-
*/
|
|
84
|
-
let debounceTimer;
|
|
85
230
|
try {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
231
|
+
const watcher = watch(
|
|
232
|
+
sitePath,
|
|
233
|
+
{ recursive: true },
|
|
234
|
+
(eventType, filename) => {
|
|
235
|
+
if (!filename) return;
|
|
236
|
+
/**
|
|
237
|
+
* Filter out files that should not trigger HMR notifications.
|
|
238
|
+
* Temporary files, build artifacts, and hidden files cause infinite loops
|
|
239
|
+
* or are not meant for hot reload.
|
|
240
|
+
*/
|
|
241
|
+
if (
|
|
242
|
+
filename.startsWith(".") ||
|
|
243
|
+
filename.includes("node_modules") ||
|
|
244
|
+
filename.endsWith("~") ||
|
|
245
|
+
filename.endsWith(".tmp") ||
|
|
246
|
+
filename.endsWith(".esbuild.mjs") || // Ignore build artifacts
|
|
247
|
+
filename.includes("\\.") || // Windows hidden files
|
|
248
|
+
filename.includes("/.") // Unix hidden files
|
|
249
|
+
) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Debounce timer prevents multiple rapid change notifications.
|
|
254
|
+
* Filesystem watchers often emit multiple events for a single file change.
|
|
255
|
+
* This delay coalesces rapid changes into a single notification (100ms threshold).
|
|
256
|
+
* maxWait cap prevents indefinite waiting on continuous changes.
|
|
257
|
+
*/
|
|
258
|
+
let debounceTimer = setTimeout(() => {
|
|
259
|
+
const ext = extname(filename);
|
|
260
|
+
// Normalize path
|
|
261
|
+
const fullPath = join(sitePath, filename);
|
|
262
|
+
log.info(`[HMR] Change detected: ${filename}`);
|
|
263
|
+
if (ext === ".css" || ext === ".scss") {
|
|
264
|
+
/**
|
|
265
|
+
* For CSS/SCSS changes, send a style-update event.
|
|
266
|
+
* This allows the client to reload CSS without full page reload,
|
|
267
|
+
* preserving component state and providing better developer experience.
|
|
268
|
+
*/
|
|
269
|
+
const cssName = filename.replace(/\.scss$/, ".css");
|
|
270
|
+
for (const client of lifecycle.getHmrClients()) {
|
|
271
|
+
if (!client.writableEnded && !client.destroyed) {
|
|
272
|
+
client.write(
|
|
273
|
+
`event: style-update\ndata: ${JSON.stringify({ file: cssName })}\n\n`,
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
} else {
|
|
278
|
+
/**
|
|
279
|
+
* For JavaScript/TypeScript/component changes, invalidate build caches
|
|
280
|
+
* and send a full reload event.
|
|
281
|
+
* Cache invalidation ensures the latest code is loaded on next request.
|
|
282
|
+
*/
|
|
283
|
+
invalidateCache(fullPath);
|
|
284
|
+
if (ext === ".vue") invalidateVueCache(fullPath);
|
|
285
|
+
if (ext === ".svelte") invalidateSvelteCache(fullPath);
|
|
286
|
+
// Full reload for JS/TS/Vue/Svelte/Other
|
|
287
|
+
for (const client of lifecycle.getHmrClients()) {
|
|
288
|
+
if (!client.writableEnded && !client.destroyed) {
|
|
289
|
+
client.write(`event: reload\ndata: {}\n\n`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
135
292
|
}
|
|
293
|
+
}, 100);
|
|
294
|
+
// Use unref() to allow Node.js to exit if this is the only pending operation
|
|
295
|
+
if (debounceTimer.unref) {
|
|
296
|
+
debounceTimer.unref();
|
|
136
297
|
}
|
|
137
|
-
|
|
138
|
-
|
|
298
|
+
lifecycle.setDebounceTimer(debounceTimer);
|
|
299
|
+
},
|
|
300
|
+
);
|
|
301
|
+
// Store watcher for cleanup on shutdown
|
|
302
|
+
lifecycle.setWatcher(watcher);
|
|
139
303
|
} catch (err) {
|
|
140
304
|
log.warn(`[HMR] Watch failed: ${err}`);
|
|
141
305
|
}
|
|
@@ -146,6 +310,7 @@ export async function createApp(opts) {
|
|
|
146
310
|
* See scanRoutes() for details on route naming conventions.
|
|
147
311
|
*/
|
|
148
312
|
const routes = scanRoutes(config);
|
|
313
|
+
const router = createAdvancedRouter(routes, config);
|
|
149
314
|
log.info(`Routes discovered: ${routes.length}`);
|
|
150
315
|
for (const r of routes) log.info(` ${r.urlPath} -> ${r.filePath}`);
|
|
151
316
|
const serveAssets = sirv(join(process.cwd(), config.siteDir), {
|
|
@@ -156,29 +321,76 @@ export async function createApp(opts) {
|
|
|
156
321
|
dev: mode === "dev",
|
|
157
322
|
etag: true,
|
|
158
323
|
});
|
|
324
|
+
// Font serving middleware
|
|
325
|
+
const fontCacheDir = join(
|
|
326
|
+
process.cwd(),
|
|
327
|
+
config.build?.cacheDir ?? ".jen",
|
|
328
|
+
"fonts",
|
|
329
|
+
);
|
|
330
|
+
const serveFonts = fontServeMiddleware(fontCacheDir);
|
|
331
|
+
// Server actions middleware
|
|
332
|
+
const serverActionsMiddleware = await createServerActionsMiddleware({
|
|
333
|
+
config,
|
|
334
|
+
});
|
|
159
335
|
const middlewares = [
|
|
160
336
|
async (ctx, next) => {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
337
|
+
try {
|
|
338
|
+
log.info(`${ctx.req.method} ${ctx.url.pathname}`);
|
|
339
|
+
// i18n middleware
|
|
340
|
+
if (config.features?.i18n !== false) {
|
|
341
|
+
const locales = config.i18n?.locales || ["en", "es"];
|
|
342
|
+
const defaultLocale = config.i18n?.defaultLocale || "en";
|
|
343
|
+
const firstSegment = ctx.url.pathname.split("/")[1];
|
|
344
|
+
const locale = locales.includes(firstSegment)
|
|
345
|
+
? firstSegment
|
|
346
|
+
: defaultLocale;
|
|
347
|
+
ctx.i18n = new I18n(locale);
|
|
348
|
+
}
|
|
349
|
+
await next();
|
|
350
|
+
} catch (err) {
|
|
351
|
+
sendSafeError(
|
|
352
|
+
ctx.res,
|
|
353
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
354
|
+
mode === "dev",
|
|
171
355
|
);
|
|
172
|
-
ctx.res.end(runtimeHydrateModule());
|
|
173
|
-
return;
|
|
174
356
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
357
|
+
},
|
|
358
|
+
async (ctx, next) => {
|
|
359
|
+
try {
|
|
360
|
+
// GraphQL endpoint
|
|
361
|
+
if (ctx.url.pathname === "/graphql" && config.features?.graphql) {
|
|
362
|
+
if (ctx.req.method !== "POST") {
|
|
363
|
+
ctx.res.statusCode = 405;
|
|
364
|
+
ctx.res.end("Method Not Allowed");
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
let body = "";
|
|
368
|
+
ctx.req.on("data", (chunk) => (body += chunk.toString()));
|
|
369
|
+
await new Promise((resolve) => ctx.req.on("end", resolve));
|
|
370
|
+
const { query, variables } = JSON.parse(body);
|
|
371
|
+
const result = await runQuery(query, variables);
|
|
372
|
+
ctx.res.statusCode = 200;
|
|
373
|
+
ctx.res.setHeader("content-type", "application/json");
|
|
374
|
+
ctx.res.end(JSON.stringify(result));
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
// runtime internal modules
|
|
378
|
+
if (ctx.url.pathname === "/__runtime/hydrate.js") {
|
|
379
|
+
ctx.res.statusCode = 200;
|
|
380
|
+
ctx.res.setHeader(
|
|
381
|
+
"content-type",
|
|
382
|
+
"application/javascript; charset=utf-8",
|
|
383
|
+
);
|
|
384
|
+
ctx.res.end(runtimeHydrateModule());
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
if (ctx.url.pathname === "/__runtime/island-hydration-client.js") {
|
|
388
|
+
ctx.res.statusCode = 200;
|
|
389
|
+
ctx.res.setHeader(
|
|
390
|
+
"content-type",
|
|
391
|
+
"application/javascript; charset=utf-8",
|
|
392
|
+
);
|
|
393
|
+
const islandCode = `
|
|
182
394
|
import { hydrate } from "https://esm.sh/preact@10";
|
|
183
395
|
import { h } from "https://esm.sh/preact@10";
|
|
184
396
|
|
|
@@ -272,151 +484,239 @@ export function initializeIslands() {
|
|
|
272
484
|
|
|
273
485
|
initializeIslands();
|
|
274
486
|
`;
|
|
275
|
-
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
// HMR Endpoint (SSE)
|
|
279
|
-
if (ctx.url.pathname === "/__hmr" && mode === "dev") {
|
|
280
|
-
ctx.res.statusCode = 200;
|
|
281
|
-
ctx.res.setHeader("content-type", "text/event-stream");
|
|
282
|
-
ctx.res.setHeader("cache-control", "no-cache");
|
|
283
|
-
ctx.res.setHeader("connection", "keep-alive");
|
|
284
|
-
ctx.res.write("data: connected\n\n");
|
|
285
|
-
hmrClients.add(ctx.res);
|
|
286
|
-
ctx.req.on("close", () => {
|
|
287
|
-
hmrClients.delete(ctx.res);
|
|
288
|
-
});
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
if (ctx.url.pathname === "/__hydrate") {
|
|
292
|
-
const file = ctx.url.searchParams.get("file");
|
|
293
|
-
if (!file) {
|
|
294
|
-
ctx.res.statusCode = 400;
|
|
295
|
-
ctx.res.end("missing file");
|
|
487
|
+
ctx.res.end(islandCode);
|
|
296
488
|
return;
|
|
297
489
|
}
|
|
298
|
-
|
|
299
|
-
ctx.
|
|
300
|
-
|
|
301
|
-
"content-type",
|
|
302
|
-
"
|
|
490
|
+
// HMR Endpoint (SSE)
|
|
491
|
+
if (ctx.url.pathname === "/__hmr" && mode === "dev") {
|
|
492
|
+
ctx.res.statusCode = 200;
|
|
493
|
+
ctx.res.setHeader("content-type", "text/event-stream");
|
|
494
|
+
ctx.res.setHeader("cache-control", "no-cache");
|
|
495
|
+
ctx.res.setHeader("connection", "keep-alive");
|
|
496
|
+
ctx.res.write("data: connected\n\n");
|
|
497
|
+
lifecycle.addHmrClient(ctx.res);
|
|
498
|
+
ctx.req.on("close", () => {
|
|
499
|
+
lifecycle.removeHmrClient(ctx.res);
|
|
500
|
+
});
|
|
501
|
+
// Cleanup on response error
|
|
502
|
+
ctx.res.on("error", () => {
|
|
503
|
+
lifecycle.removeHmrClient(ctx.res);
|
|
504
|
+
});
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
if (ctx.url.pathname === "/__hydrate") {
|
|
508
|
+
const file = ctx.url.searchParams.get("file");
|
|
509
|
+
if (!file) {
|
|
510
|
+
ctx.res.statusCode = 400;
|
|
511
|
+
ctx.res.end("missing file");
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
const js = buildHydrationModule(file);
|
|
515
|
+
ctx.res.statusCode = 200;
|
|
516
|
+
ctx.res.setHeader(
|
|
517
|
+
"content-type",
|
|
518
|
+
"application/javascript; charset=utf-8",
|
|
519
|
+
);
|
|
520
|
+
ctx.res.setHeader("cache-control", "no-store");
|
|
521
|
+
ctx.res.end(js);
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
await next();
|
|
525
|
+
} catch (err) {
|
|
526
|
+
sendSafeError(
|
|
527
|
+
ctx.res,
|
|
528
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
529
|
+
mode === "dev",
|
|
303
530
|
);
|
|
304
|
-
ctx.res.setHeader("cache-control", "no-store");
|
|
305
|
-
ctx.res.end(js);
|
|
306
|
-
return;
|
|
307
531
|
}
|
|
308
|
-
await next();
|
|
309
532
|
},
|
|
310
533
|
async (ctx, next) => {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
})
|
|
317
|
-
|
|
318
|
-
|
|
534
|
+
try {
|
|
535
|
+
// Font serving (with proper cache headers)
|
|
536
|
+
const handled = await serveFonts(ctx.req, ctx.res);
|
|
537
|
+
if (handled) return;
|
|
538
|
+
await next();
|
|
539
|
+
} catch (err) {
|
|
540
|
+
sendSafeError(
|
|
541
|
+
ctx.res,
|
|
542
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
543
|
+
mode === "dev",
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
},
|
|
547
|
+
async (ctx, next) => {
|
|
548
|
+
try {
|
|
549
|
+
// Server actions
|
|
550
|
+
await serverActionsMiddleware(ctx, next);
|
|
551
|
+
} catch (err) {
|
|
552
|
+
sendSafeError(
|
|
553
|
+
ctx.res,
|
|
554
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
555
|
+
mode === "dev",
|
|
556
|
+
);
|
|
557
|
+
}
|
|
319
558
|
},
|
|
320
559
|
async (ctx, next) => {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
560
|
+
try {
|
|
561
|
+
// API routes
|
|
562
|
+
const handled = await tryHandleApiRoute({
|
|
563
|
+
req: ctx.req,
|
|
564
|
+
res: ctx.res,
|
|
565
|
+
siteDir: config.siteDir,
|
|
325
566
|
});
|
|
326
|
-
if (
|
|
567
|
+
if (handled) return;
|
|
568
|
+
await next();
|
|
569
|
+
} catch (err) {
|
|
570
|
+
sendSafeError(
|
|
571
|
+
ctx.res,
|
|
572
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
573
|
+
mode === "dev",
|
|
574
|
+
);
|
|
327
575
|
}
|
|
328
|
-
await next();
|
|
329
576
|
},
|
|
330
577
|
async (ctx, next) => {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
if (
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
578
|
+
try {
|
|
579
|
+
// dist
|
|
580
|
+
if (mode === "prod") {
|
|
581
|
+
await new Promise((resolve) => {
|
|
582
|
+
serveDist(ctx.req, ctx.res, () => resolve());
|
|
583
|
+
});
|
|
584
|
+
if (ctx.res.writableEnded || ctx.res.headersSent) return;
|
|
585
|
+
}
|
|
586
|
+
await next();
|
|
587
|
+
} catch (err) {
|
|
588
|
+
sendSafeError(
|
|
589
|
+
ctx.res,
|
|
590
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
591
|
+
mode === "dev",
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
},
|
|
595
|
+
async (ctx, next) => {
|
|
596
|
+
try {
|
|
597
|
+
// SCSS Compilation (Dev)
|
|
598
|
+
if (mode === "dev" && ctx.url.pathname.endsWith(".css")) {
|
|
599
|
+
let scssFile = null;
|
|
600
|
+
const basePath = resolve(process.cwd());
|
|
601
|
+
if (ctx.url.pathname === "/styles.css") {
|
|
602
|
+
// Global SCSS
|
|
603
|
+
if (config.css?.globalScss) {
|
|
604
|
+
// Already includes siteDir if needed, but add it if it doesn't
|
|
605
|
+
const scssPath = config.css.globalScss.startsWith(config.siteDir)
|
|
606
|
+
? config.css.globalScss
|
|
607
|
+
: join(config.siteDir, config.css.globalScss);
|
|
608
|
+
scssFile = join(basePath, scssPath);
|
|
609
|
+
console.log(
|
|
610
|
+
"[DEBUG CSS] Looking for global SCSS:",
|
|
611
|
+
scssFile,
|
|
612
|
+
"exists:",
|
|
613
|
+
existsSync(scssFile),
|
|
614
|
+
);
|
|
615
|
+
} else {
|
|
616
|
+
console.log("[DEBUG CSS] No config.css.globalScss found");
|
|
617
|
+
}
|
|
349
618
|
} else {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
if (existsSync(tryPath)) {
|
|
361
|
-
scssFile = tryPath;
|
|
619
|
+
// Map /foo.css -> siteDir/foo.scss
|
|
620
|
+
const rel = ctx.url.pathname.slice(1);
|
|
621
|
+
const tryPath = join(
|
|
622
|
+
basePath,
|
|
623
|
+
config.siteDir,
|
|
624
|
+
rel.replace(/\.css$/, ".scss"),
|
|
625
|
+
);
|
|
626
|
+
if (existsSync(tryPath)) {
|
|
627
|
+
scssFile = tryPath;
|
|
628
|
+
}
|
|
362
629
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
630
|
+
if (scssFile && existsSync(scssFile)) {
|
|
631
|
+
const compiler = createScssCompiler();
|
|
632
|
+
const result = compiler.compile({
|
|
633
|
+
inputPath: scssFile,
|
|
634
|
+
minified: false,
|
|
635
|
+
sourceMap: true,
|
|
636
|
+
});
|
|
637
|
+
if (result.error) {
|
|
638
|
+
ctx.res.statusCode = 500;
|
|
639
|
+
ctx.res.setHeader("content-type", "text/css");
|
|
640
|
+
ctx.res.end(
|
|
641
|
+
`/* SCSS Error: ${result.error.replace(/\*\//g, "* /")} */ body::before { position:fixed; top:0; left:0; width:100%; content: "SCSS Error: ${result.error
|
|
642
|
+
.replace(/\\/g, "\\\\")
|
|
643
|
+
.replace(
|
|
644
|
+
/"/g,
|
|
645
|
+
'\\"',
|
|
646
|
+
)}"; display: block; background: red; color: white; padding: 1em; z-index:9999; white-space: pre-wrap; }`,
|
|
647
|
+
);
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
ctx.res.statusCode = 200;
|
|
373
651
|
ctx.res.setHeader("content-type", "text/css");
|
|
374
|
-
ctx.res.end(
|
|
375
|
-
`/* SCSS Error: ${result.error.replace(/\*\//g, "* /")} */ body::before { position:fixed; top:0; left:0; width:100%; content: "SCSS Error: ${result.error
|
|
376
|
-
.replace(/\\/g, "\\\\")
|
|
377
|
-
.replace(
|
|
378
|
-
/"/g,
|
|
379
|
-
'\\"',
|
|
380
|
-
)}"; display: block; background: red; color: white; padding: 1em; z-index:9999; white-space: pre-wrap; }`,
|
|
381
|
-
);
|
|
652
|
+
ctx.res.end(result.css);
|
|
382
653
|
return;
|
|
383
654
|
}
|
|
384
|
-
ctx.res.statusCode = 200;
|
|
385
|
-
ctx.res.setHeader("content-type", "text/css");
|
|
386
|
-
ctx.res.end(result.css);
|
|
387
|
-
return;
|
|
388
655
|
}
|
|
656
|
+
await next();
|
|
657
|
+
} catch (err) {
|
|
658
|
+
sendSafeError(
|
|
659
|
+
ctx.res,
|
|
660
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
661
|
+
mode === "dev",
|
|
662
|
+
);
|
|
389
663
|
}
|
|
390
|
-
await next();
|
|
391
664
|
},
|
|
392
665
|
async (ctx, next) => {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
666
|
+
try {
|
|
667
|
+
// site assets in dev
|
|
668
|
+
if (mode === "dev") {
|
|
669
|
+
await new Promise((resolve) => {
|
|
670
|
+
serveAssets(ctx.req, ctx.res, () => resolve());
|
|
671
|
+
});
|
|
672
|
+
if (ctx.res.writableEnded || ctx.res.headersSent) return;
|
|
673
|
+
}
|
|
674
|
+
await next();
|
|
675
|
+
} catch (err) {
|
|
676
|
+
sendSafeError(
|
|
677
|
+
ctx.res,
|
|
678
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
679
|
+
mode === "dev",
|
|
680
|
+
);
|
|
399
681
|
}
|
|
400
|
-
await next();
|
|
401
682
|
},
|
|
402
683
|
async (ctx, next) => {
|
|
403
|
-
// SSR
|
|
404
|
-
if (ctx.req.method !== "GET") return next();
|
|
405
|
-
const m = matchRoute(routes, ctx.url.pathname);
|
|
406
|
-
if (!m) return next();
|
|
407
|
-
const reqHeaders = headersToObject(ctx.req.headers);
|
|
408
|
-
const cookies = parseCookies(ctx.req);
|
|
409
|
-
const query = {};
|
|
410
|
-
for (const [k, v] of ctx.url.searchParams.entries()) query[k] = v;
|
|
411
684
|
try {
|
|
685
|
+
// Advanced routing with guards, redirects, and 404 handling
|
|
686
|
+
if (ctx.req.method !== "GET") return next();
|
|
687
|
+
const reqHeaders = headersToObject(ctx.req.headers);
|
|
688
|
+
const cookies = parseCookies(ctx.req);
|
|
689
|
+
// Use advanced router to resolve the route
|
|
690
|
+
const resolution = await router.resolve(
|
|
691
|
+
ctx.url.pathname,
|
|
692
|
+
ctx.url,
|
|
693
|
+
reqHeaders,
|
|
694
|
+
cookies,
|
|
695
|
+
);
|
|
696
|
+
if (resolution.type === "redirect") {
|
|
697
|
+
// Handle redirects (both app-level and route-level)
|
|
698
|
+
router.handleRedirect(
|
|
699
|
+
ctx.res,
|
|
700
|
+
resolution.location,
|
|
701
|
+
resolution.status,
|
|
702
|
+
);
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
if (resolution.type === "not_found") {
|
|
706
|
+
// Handle 404 responses
|
|
707
|
+
await router.handle404(ctx.res, resolution.pathname);
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
// Route matched - render the page
|
|
711
|
+
if (resolution.type !== "matched") return next();
|
|
412
712
|
const html = await renderRouteToHtml({
|
|
413
713
|
config,
|
|
414
|
-
route:
|
|
714
|
+
route: resolution.route,
|
|
415
715
|
req: ctx.req,
|
|
416
716
|
res: ctx.res,
|
|
417
717
|
url: ctx.url,
|
|
418
|
-
params:
|
|
419
|
-
query,
|
|
718
|
+
params: resolution.params,
|
|
719
|
+
query: resolution.query,
|
|
420
720
|
headers: reqHeaders,
|
|
421
721
|
cookies,
|
|
422
722
|
});
|
|
@@ -433,23 +733,39 @@ initializeIslands();
|
|
|
433
733
|
ctx.res.end(finalHtml);
|
|
434
734
|
} catch (err) {
|
|
435
735
|
// Middleware may have sent a response (redirect/json)
|
|
436
|
-
if (
|
|
736
|
+
if (
|
|
737
|
+
err &&
|
|
738
|
+
(err.message === "__REDIRECT__" || err.message === "__JSON__")
|
|
739
|
+
) {
|
|
437
740
|
return; // Response already sent
|
|
438
741
|
}
|
|
439
|
-
|
|
742
|
+
sendSafeError(
|
|
743
|
+
ctx.res,
|
|
744
|
+
err instanceof Error ? err : new Error(String(err)),
|
|
745
|
+
mode === "dev",
|
|
746
|
+
);
|
|
440
747
|
}
|
|
441
748
|
},
|
|
442
|
-
async (ctx) => {
|
|
443
|
-
ctx.res.statusCode = 404;
|
|
444
|
-
ctx.res.setHeader("content-type", "text/plain; charset=utf-8");
|
|
445
|
-
ctx.res.end("404 Not Found");
|
|
446
|
-
},
|
|
447
749
|
];
|
|
448
750
|
const kernel = new Kernel();
|
|
449
751
|
middlewares.forEach((m) => kernel.use(m));
|
|
450
752
|
return {
|
|
451
753
|
async handle(req, res) {
|
|
754
|
+
const start = Date.now();
|
|
755
|
+
const originalEnd = res.end.bind(res);
|
|
756
|
+
res.end = function (...args) {
|
|
757
|
+
const duration = Date.now() - start;
|
|
758
|
+
console.log(`${req.method} ${req.url} ${res.statusCode} ${duration}ms`);
|
|
759
|
+
return originalEnd(...args);
|
|
760
|
+
};
|
|
452
761
|
await kernel.handle(req, res);
|
|
453
762
|
},
|
|
763
|
+
/**
|
|
764
|
+
* Gracefully closes the app and cleans up resources.
|
|
765
|
+
* Should be called on server shutdown.
|
|
766
|
+
*/
|
|
767
|
+
async close() {
|
|
768
|
+
await lifecycle.close();
|
|
769
|
+
},
|
|
454
770
|
};
|
|
455
771
|
}
|