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,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example Dynamic API Route: GET|PUT|DELETE /api/posts/[id]
|
|
3
|
+
*
|
|
4
|
+
* Example showing dynamic route parameters
|
|
5
|
+
*/
|
|
6
|
+
const posts = [
|
|
7
|
+
{ id: 1, title: "First Post", content: "Hello World" },
|
|
8
|
+
{ id: 2, title: "Second Post", content: "Jen.js is awesome" },
|
|
9
|
+
];
|
|
10
|
+
export default async function handler(req, res) {
|
|
11
|
+
const { id } = req.params;
|
|
12
|
+
const postId = parseInt(String(id), 10);
|
|
13
|
+
if (isNaN(postId)) {
|
|
14
|
+
return res.status(400).json({ error: "Invalid post ID" });
|
|
15
|
+
}
|
|
16
|
+
const post = posts.find((p) => p.id === postId);
|
|
17
|
+
if (!post) {
|
|
18
|
+
return res.status(404).json({ error: "Post not found" });
|
|
19
|
+
}
|
|
20
|
+
if (req.method === "GET") {
|
|
21
|
+
// Get single post
|
|
22
|
+
res.status(200).json({ data: post });
|
|
23
|
+
} else if (req.method === "PUT") {
|
|
24
|
+
// Update post
|
|
25
|
+
const { title, content } = req.body;
|
|
26
|
+
if (title) post.title = title;
|
|
27
|
+
if (content) post.content = content;
|
|
28
|
+
res.status(200).json({ data: post });
|
|
29
|
+
} else if (req.method === "DELETE") {
|
|
30
|
+
// Delete post
|
|
31
|
+
const index = posts.findIndex((p) => p.id === postId);
|
|
32
|
+
posts.splice(index, 1);
|
|
33
|
+
res.status(200).json({ message: "Post deleted" });
|
|
34
|
+
} else {
|
|
35
|
+
res.status(405).json({ error: "Method not allowed" });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example API Route: GET|POST /api/posts
|
|
3
|
+
*
|
|
4
|
+
* Example showing HTTP method handling and request body parsing
|
|
5
|
+
*/
|
|
6
|
+
const posts = [
|
|
7
|
+
{ id: 1, title: "First Post", content: "Hello World" },
|
|
8
|
+
{ id: 2, title: "Second Post", content: "Jen.js is awesome" },
|
|
9
|
+
];
|
|
10
|
+
export default async function handler(req, res) {
|
|
11
|
+
if (req.method === "GET") {
|
|
12
|
+
// Get all posts
|
|
13
|
+
res.status(200).json({ data: posts });
|
|
14
|
+
} else if (req.method === "POST") {
|
|
15
|
+
// Create new post
|
|
16
|
+
const { title, content } = req.body;
|
|
17
|
+
if (!title || !content) {
|
|
18
|
+
return res.status(400).json({ error: "Missing title or content" });
|
|
19
|
+
}
|
|
20
|
+
const newPost = {
|
|
21
|
+
id: posts.length + 1,
|
|
22
|
+
title,
|
|
23
|
+
content,
|
|
24
|
+
};
|
|
25
|
+
posts.push(newPost);
|
|
26
|
+
res.status(201).json({ data: newPost });
|
|
27
|
+
} else {
|
|
28
|
+
res.status(405).json({ error: "Method not allowed" });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Optional configuration
|
|
32
|
+
export const config = {
|
|
33
|
+
maxDuration: 30,
|
|
34
|
+
bodyParser: {
|
|
35
|
+
sizeLimit: "1mb",
|
|
36
|
+
},
|
|
37
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example API Route: GET /api/search
|
|
3
|
+
*
|
|
4
|
+
* Example showing query parameter handling
|
|
5
|
+
*/
|
|
6
|
+
export default async function handler(req, res) {
|
|
7
|
+
const { q, limit = "10" } = req.query;
|
|
8
|
+
if (!q) {
|
|
9
|
+
return res.status(400).json({ error: "Missing search query parameter" });
|
|
10
|
+
}
|
|
11
|
+
const limitNum = Math.min(parseInt(String(limit), 10) || 10, 100);
|
|
12
|
+
// Simulate search results
|
|
13
|
+
const results = [
|
|
14
|
+
{ id: 1, title: `Result for "${q}"`, relevance: 0.95 },
|
|
15
|
+
{ id: 2, title: `Another match for "${q}"`, relevance: 0.85 },
|
|
16
|
+
{ id: 3, title: `Third result`, relevance: 0.72 },
|
|
17
|
+
].slice(0, limitNum);
|
|
18
|
+
res.status(200).json({
|
|
19
|
+
query: q,
|
|
20
|
+
count: results.length,
|
|
21
|
+
results,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jen.js API Routes System
|
|
3
|
+
*
|
|
4
|
+
* File-based API routing system inspired by Next.js API Routes.
|
|
5
|
+
* All files in the `api/` directory are automatically mapped to `/api/*` routes.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```
|
|
9
|
+
* Directory structure:
|
|
10
|
+
* src/api/
|
|
11
|
+
* hello.ts -> GET /api/hello
|
|
12
|
+
* posts.ts -> GET|POST /api/posts
|
|
13
|
+
* posts/[id].ts -> GET /api/posts/123
|
|
14
|
+
* files/[...slug].ts -> GET /api/files/a/b/c
|
|
15
|
+
* admin/[[...path]].ts -> GET /api/admin or /api/admin/a/b
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @example Usage in handler
|
|
19
|
+
* ```ts
|
|
20
|
+
* // src/api/hello.ts
|
|
21
|
+
* import type { ApiRequest, ApiResponse } from '../api';
|
|
22
|
+
*
|
|
23
|
+
* export default function handler(req: ApiRequest, res: ApiResponse) {
|
|
24
|
+
* res.status(200).json({ message: 'Hello from Jen.js!' });
|
|
25
|
+
* }
|
|
26
|
+
*
|
|
27
|
+
* // Optional config
|
|
28
|
+
* export const config = {
|
|
29
|
+
* maxDuration: 60,
|
|
30
|
+
* bodyParser: { sizeLimit: '10mb' }
|
|
31
|
+
* };
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export {
|
|
35
|
+
ApiRouter,
|
|
36
|
+
parseQuery,
|
|
37
|
+
parseCookies,
|
|
38
|
+
createApiRequest,
|
|
39
|
+
createApiResponse,
|
|
40
|
+
} from "./router";
|
|
41
|
+
export { ApiLoader, createApiMiddleware } from "./loader";
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { readdirSync } from "fs";
|
|
2
|
+
import { join, resolve } from "path";
|
|
3
|
+
/**
|
|
4
|
+
* Loader for scanning and loading API route files
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* const loader = new ApiLoader();
|
|
9
|
+
* const routes = await loader.loadRoutes('./src/api');
|
|
10
|
+
* // Routes format: [
|
|
11
|
+
* // { path: '/api/hello', handler: ..., config: ... },
|
|
12
|
+
* // { path: '/api/posts/[id]', handler: ..., config: ... },
|
|
13
|
+
* // { path: '/api/files/[...slug]', handler: ..., config: ... }
|
|
14
|
+
* // ]
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export class ApiLoader {
|
|
18
|
+
/**
|
|
19
|
+
* Load all API routes from a directory
|
|
20
|
+
*
|
|
21
|
+
* @param apiDir Directory to scan for route files (e.g., 'src/api')
|
|
22
|
+
* @param baseRoute Base route prefix (default: '/api')
|
|
23
|
+
* @returns Array of loaded routes
|
|
24
|
+
*/
|
|
25
|
+
async loadRoutes(apiDir, baseRoute = "/api") {
|
|
26
|
+
const routes = [];
|
|
27
|
+
const fullPath = resolve(apiDir);
|
|
28
|
+
try {
|
|
29
|
+
await this.scanDirectory(fullPath, baseRoute, routes);
|
|
30
|
+
} catch (err) {
|
|
31
|
+
console.error(`Failed to load API routes from ${apiDir}:`, err);
|
|
32
|
+
}
|
|
33
|
+
// Sort routes by specificity: exact > dynamic > catch-all
|
|
34
|
+
routes.sort((a, b) => {
|
|
35
|
+
const aIsCatchAll = a.path.includes("[...");
|
|
36
|
+
const bIsCatchAll = b.path.includes("[...");
|
|
37
|
+
const aIsDynamic = a.path.includes("[");
|
|
38
|
+
const bIsDynamic = b.path.includes("[");
|
|
39
|
+
if (aIsCatchAll && !bIsCatchAll) return 1;
|
|
40
|
+
if (!aIsCatchAll && bIsCatchAll) return -1;
|
|
41
|
+
if (aIsDynamic && !bIsDynamic) return 1;
|
|
42
|
+
if (!aIsDynamic && bIsDynamic) return -1;
|
|
43
|
+
return a.path.length - b.path.length;
|
|
44
|
+
});
|
|
45
|
+
return routes;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Recursively scan directory for API route files
|
|
49
|
+
*
|
|
50
|
+
* @private
|
|
51
|
+
*/
|
|
52
|
+
async scanDirectory(dir, baseRoute, routes) {
|
|
53
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
54
|
+
for (const entry of entries) {
|
|
55
|
+
const fullPath = join(dir, entry.name);
|
|
56
|
+
// Skip hidden files and directories
|
|
57
|
+
if (entry.name.startsWith(".")) continue;
|
|
58
|
+
if (entry.isDirectory()) {
|
|
59
|
+
await this.scanDirectory(fullPath, baseRoute, routes);
|
|
60
|
+
} else if (this.isRouteFile(entry.name)) {
|
|
61
|
+
const routePath = this.filePathToRoute(fullPath, baseRoute);
|
|
62
|
+
const module = await this.loadModule(fullPath);
|
|
63
|
+
if (module && typeof module.default === "function") {
|
|
64
|
+
routes.push({
|
|
65
|
+
path: routePath,
|
|
66
|
+
handler: module.default,
|
|
67
|
+
config: module.config,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Check if file is a valid route file
|
|
75
|
+
*
|
|
76
|
+
* @private
|
|
77
|
+
*/
|
|
78
|
+
isRouteFile(filename) {
|
|
79
|
+
return (
|
|
80
|
+
/^[^.][^/]*\.(ts|tsx|js|jsx)$/.test(filename) &&
|
|
81
|
+
!filename.endsWith(".d.ts")
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Convert file path to API route path
|
|
86
|
+
*
|
|
87
|
+
* @private
|
|
88
|
+
* @example
|
|
89
|
+
* ```
|
|
90
|
+
* src/api/hello.ts -> /api/hello
|
|
91
|
+
* src/api/posts/[id].ts -> /api/posts/[id]
|
|
92
|
+
* src/api/files/[...slug].ts -> /api/files/[...slug]
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
filePathToRoute(filePath, baseRoute) {
|
|
96
|
+
let route = filePath
|
|
97
|
+
.replace(/\\/g, "/") // Windows path separator
|
|
98
|
+
.replace(/\.(ts|tsx|js|jsx)$/, "") // Remove extension
|
|
99
|
+
.replace(/\/index$/, ""); // Remove /index
|
|
100
|
+
// Extract path after 'api' directory
|
|
101
|
+
const apiIndex = route.lastIndexOf("/api");
|
|
102
|
+
if (apiIndex !== -1) {
|
|
103
|
+
route = route.slice(apiIndex);
|
|
104
|
+
}
|
|
105
|
+
return baseRoute + route;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Dynamically import a module
|
|
109
|
+
*
|
|
110
|
+
* @private
|
|
111
|
+
*/
|
|
112
|
+
async loadModule(filePath) {
|
|
113
|
+
try {
|
|
114
|
+
// Convert Windows path to file:// URL
|
|
115
|
+
let importPath = filePath;
|
|
116
|
+
if (process.platform === "win32") {
|
|
117
|
+
// Normalize: backslashes → forward slashes
|
|
118
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
119
|
+
// Add file:// scheme (with third slash for absolute paths)
|
|
120
|
+
importPath = "file:///" + normalized;
|
|
121
|
+
}
|
|
122
|
+
// Handle both CommonJS and ESM
|
|
123
|
+
const module = await import(importPath);
|
|
124
|
+
return module;
|
|
125
|
+
} catch (err) {
|
|
126
|
+
console.error(`Failed to load API route ${filePath}:`, err);
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Create a middleware function for Express-like servers
|
|
133
|
+
*
|
|
134
|
+
* @param routes Loaded API routes
|
|
135
|
+
* @returns Express middleware function
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```ts
|
|
139
|
+
* import express from 'express';
|
|
140
|
+
* import { createApiMiddleware } from '../api/loader';
|
|
141
|
+
* import { ApiRouter } from '../api/router';
|
|
142
|
+
*
|
|
143
|
+
* const app = express();
|
|
144
|
+
* const loader = new ApiLoader();
|
|
145
|
+
* const routes = await loader.loadRoutes('./src/api');
|
|
146
|
+
*
|
|
147
|
+
* const router = new ApiRouter();
|
|
148
|
+
* routes.forEach(route => router.register(route.path, route.handler));
|
|
149
|
+
*
|
|
150
|
+
* app.use(createApiMiddleware(routes));
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
export function createApiMiddleware(routes) {
|
|
154
|
+
return async (req, res, next) => {
|
|
155
|
+
// Only handle API routes
|
|
156
|
+
if (!req.url.startsWith("/api")) {
|
|
157
|
+
return next();
|
|
158
|
+
}
|
|
159
|
+
// Find matching route
|
|
160
|
+
const match = findMatchingRoute(req.path, routes);
|
|
161
|
+
if (!match) {
|
|
162
|
+
return next(); // Let next middleware handle 404
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
// Set up request/response
|
|
166
|
+
req.params = match.params;
|
|
167
|
+
// Execute handler
|
|
168
|
+
await match.route.handler(req, res);
|
|
169
|
+
} catch (err) {
|
|
170
|
+
console.error("API handler error:", err);
|
|
171
|
+
res.status(500).json({ error: "Internal server error" });
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Find matching route using simple path matching
|
|
177
|
+
*
|
|
178
|
+
* @private
|
|
179
|
+
*/
|
|
180
|
+
function findMatchingRoute(requestPath, routes) {
|
|
181
|
+
for (const route of routes) {
|
|
182
|
+
const match = matchPath(requestPath, route.path);
|
|
183
|
+
if (match) {
|
|
184
|
+
return { route, params: match };
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Match a request path against a route pattern
|
|
191
|
+
*
|
|
192
|
+
* @private
|
|
193
|
+
*/
|
|
194
|
+
function matchPath(requestPath, routePath) {
|
|
195
|
+
const routeParts = routePath.split("/").filter(Boolean);
|
|
196
|
+
const requestParts = requestPath.split("/").filter(Boolean);
|
|
197
|
+
// Skip 'api' prefix
|
|
198
|
+
if (routeParts[0] === "api") routeParts.shift();
|
|
199
|
+
if (requestParts[0] === "api") requestParts.shift();
|
|
200
|
+
const params = {};
|
|
201
|
+
let routeIndex = 0;
|
|
202
|
+
let requestIndex = 0;
|
|
203
|
+
while (routeIndex < routeParts.length && requestIndex < requestParts.length) {
|
|
204
|
+
const routePart = routeParts[routeIndex];
|
|
205
|
+
const requestPart = requestParts[requestIndex];
|
|
206
|
+
if (routePart.startsWith("[...")) {
|
|
207
|
+
// Catch-all
|
|
208
|
+
const paramName = routePart.slice(4, -1);
|
|
209
|
+
const remaining = requestParts.slice(requestIndex);
|
|
210
|
+
params[paramName] = remaining;
|
|
211
|
+
requestIndex = requestParts.length;
|
|
212
|
+
} else if (routePart.startsWith("[")) {
|
|
213
|
+
// Dynamic segment
|
|
214
|
+
const paramName = routePart.slice(1, -1);
|
|
215
|
+
params[paramName] = requestPart;
|
|
216
|
+
requestIndex++;
|
|
217
|
+
} else if (routePart === requestPart) {
|
|
218
|
+
// Exact match
|
|
219
|
+
requestIndex++;
|
|
220
|
+
} else {
|
|
221
|
+
// No match
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
routeIndex++;
|
|
225
|
+
}
|
|
226
|
+
// Check if all parts matched
|
|
227
|
+
if (
|
|
228
|
+
routeIndex === routeParts.length &&
|
|
229
|
+
requestIndex === requestParts.length
|
|
230
|
+
) {
|
|
231
|
+
return params;
|
|
232
|
+
}
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { URL } from "url";
|
|
2
|
+
/**
|
|
3
|
+
* API Router for matching requests to handlers
|
|
4
|
+
*/
|
|
5
|
+
export class ApiRouter {
|
|
6
|
+
routes = new Map();
|
|
7
|
+
/**
|
|
8
|
+
* Register an API route handler
|
|
9
|
+
*
|
|
10
|
+
* @param path Route path (e.g., '/api/posts', '/api/posts/[id]', '/api/posts/[...slug]')
|
|
11
|
+
* @param handler Request handler function
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* router.register('/api/posts', handler);
|
|
16
|
+
* router.register('/api/posts/[id]', handler);
|
|
17
|
+
* router.register('/api/files/[...path]', handler);
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
register(path, handler) {
|
|
21
|
+
const pattern = this.pathToRegex(path);
|
|
22
|
+
const isDynamic = path.includes("[");
|
|
23
|
+
const isCatchAll = path.includes("[...");
|
|
24
|
+
this.routes.set(path, { handler, pattern, isDynamic, isCatchAll });
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Match a request path to a registered route
|
|
28
|
+
*
|
|
29
|
+
* @param requestPath Request path
|
|
30
|
+
* @returns Matched handler and extracted params, or null if no match
|
|
31
|
+
*/
|
|
32
|
+
match(requestPath) {
|
|
33
|
+
// First try exact matches (non-dynamic routes)
|
|
34
|
+
for (const [path, route] of this.routes) {
|
|
35
|
+
if (!route.isDynamic && path === requestPath) {
|
|
36
|
+
return { handler: route.handler, params: {} };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Then try dynamic routes (sort by specificity)
|
|
40
|
+
const dynamicRoutes = Array.from(this.routes.entries())
|
|
41
|
+
.filter(([, route]) => route.isDynamic)
|
|
42
|
+
.sort(([a], [b]) => {
|
|
43
|
+
// Predefined routes before catch-all
|
|
44
|
+
if (a.includes("[...")) return 1;
|
|
45
|
+
if (b.includes("[...")) return -1;
|
|
46
|
+
// More specific before less specific
|
|
47
|
+
return a.split("/").length - b.split("/").length;
|
|
48
|
+
});
|
|
49
|
+
for (const [path, route] of dynamicRoutes) {
|
|
50
|
+
const match = requestPath.match(route.pattern);
|
|
51
|
+
if (match) {
|
|
52
|
+
const params = this.extractParams(path, requestPath);
|
|
53
|
+
return { handler: route.handler, params };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Convert a path pattern to a regex
|
|
60
|
+
*
|
|
61
|
+
* @private
|
|
62
|
+
*/
|
|
63
|
+
pathToRegex(path) {
|
|
64
|
+
// Convert /api/posts/[id] to /api/posts/([^/]+)
|
|
65
|
+
// Convert /api/files/[...slug] to /api/files/(.+)
|
|
66
|
+
// Convert /api/items/[[...optional]] to /api/items(/.*)?
|
|
67
|
+
let pattern = path
|
|
68
|
+
.replace(/\//g, "\\/")
|
|
69
|
+
.replace(/\[\[\.\.\.([^\]]+)\]\]/g, "(?:\\/(.+))?") // Optional catch-all (do first)
|
|
70
|
+
.replace(/\[\.\.\.([^\]]+)\]/g, "(.+)") // Required catch-all
|
|
71
|
+
.replace(/\[([^\]]+)\]/g, "([^\\/]+)"); // Dynamic segment
|
|
72
|
+
return new RegExp(`^${pattern}$`);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Extract parameters from a matched route
|
|
76
|
+
*
|
|
77
|
+
* @private
|
|
78
|
+
*/
|
|
79
|
+
extractParams(routePath, requestPath) {
|
|
80
|
+
const params = {};
|
|
81
|
+
// Extract parameter names from route
|
|
82
|
+
const paramMatches = routePath.matchAll(/\[\.{0,3}(\w+)\]/g);
|
|
83
|
+
const paramNames = Array.from(paramMatches, (m) => m[1]);
|
|
84
|
+
// Match request path and extract values
|
|
85
|
+
const pattern = this.pathToRegex(routePath);
|
|
86
|
+
const match = requestPath.match(pattern);
|
|
87
|
+
if (!match) return params;
|
|
88
|
+
for (let i = 0; i < paramNames.length; i++) {
|
|
89
|
+
const name = paramNames[i];
|
|
90
|
+
const value = match[i + 1];
|
|
91
|
+
if (
|
|
92
|
+
routePath.includes(`[...${name}]`) ||
|
|
93
|
+
routePath.includes(`[[...${name}]]`)
|
|
94
|
+
) {
|
|
95
|
+
// Catch-all: convert to array
|
|
96
|
+
params[name] = value ? value.split("/").filter(Boolean) : [];
|
|
97
|
+
} else {
|
|
98
|
+
params[name] = value;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return params;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Parse query string into object
|
|
106
|
+
*
|
|
107
|
+
* @private
|
|
108
|
+
*/
|
|
109
|
+
export function parseQuery(queryString) {
|
|
110
|
+
const params = {};
|
|
111
|
+
if (!queryString) return params;
|
|
112
|
+
const pairs = queryString.split("&");
|
|
113
|
+
for (const pair of pairs) {
|
|
114
|
+
const [key, value] = pair.split("=");
|
|
115
|
+
const decodedKey = decodeURIComponent(key || "");
|
|
116
|
+
const decodedValue = decodeURIComponent(value || "");
|
|
117
|
+
if (params[decodedKey]) {
|
|
118
|
+
if (Array.isArray(params[decodedKey])) {
|
|
119
|
+
params[decodedKey].push(decodedValue);
|
|
120
|
+
} else {
|
|
121
|
+
params[decodedKey] = [params[decodedKey], decodedValue];
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
params[decodedKey] = decodedValue;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return params;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Parse cookies from request headers
|
|
131
|
+
*
|
|
132
|
+
* @private
|
|
133
|
+
*/
|
|
134
|
+
export function parseCookies(cookieHeader) {
|
|
135
|
+
const cookies = {};
|
|
136
|
+
if (!cookieHeader) return cookies;
|
|
137
|
+
const pairs = cookieHeader.split(";");
|
|
138
|
+
for (const pair of pairs) {
|
|
139
|
+
const [key, value] = pair.trim().split("=");
|
|
140
|
+
if (key) cookies[key] = decodeURIComponent(value || "");
|
|
141
|
+
}
|
|
142
|
+
return cookies;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Create enhanced request object
|
|
146
|
+
*
|
|
147
|
+
* @private
|
|
148
|
+
*/
|
|
149
|
+
export async function createApiRequest(req, params = {}) {
|
|
150
|
+
const url = new URL(req.url || "", `http://${req.headers.host}`);
|
|
151
|
+
const query = parseQuery(url.search.slice(1));
|
|
152
|
+
const cookies = parseCookies(req.headers.cookie || "");
|
|
153
|
+
let body = null;
|
|
154
|
+
// Parse body if present
|
|
155
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
156
|
+
body = await new Promise((resolve, reject) => {
|
|
157
|
+
let data = "";
|
|
158
|
+
req.on("data", (chunk) => {
|
|
159
|
+
data += chunk.toString();
|
|
160
|
+
});
|
|
161
|
+
req.on("end", () => {
|
|
162
|
+
try {
|
|
163
|
+
const contentType = req.headers["content-type"] || "";
|
|
164
|
+
if (contentType.includes("application/json")) {
|
|
165
|
+
resolve(data ? JSON.parse(data) : null);
|
|
166
|
+
} else if (
|
|
167
|
+
contentType.includes("application/x-www-form-urlencoded")
|
|
168
|
+
) {
|
|
169
|
+
resolve(parseQuery(data));
|
|
170
|
+
} else {
|
|
171
|
+
resolve(data || null);
|
|
172
|
+
}
|
|
173
|
+
} catch (err) {
|
|
174
|
+
reject(err);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
req.on("error", reject);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
...req,
|
|
182
|
+
method: req.method || "GET",
|
|
183
|
+
url: req.url || "/",
|
|
184
|
+
query,
|
|
185
|
+
body,
|
|
186
|
+
params,
|
|
187
|
+
cookies,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Create enhanced response object
|
|
192
|
+
*
|
|
193
|
+
* @private
|
|
194
|
+
*/
|
|
195
|
+
export function createApiResponse(res) {
|
|
196
|
+
const apiRes = res;
|
|
197
|
+
let statusCode = 200;
|
|
198
|
+
let headersSent = false;
|
|
199
|
+
apiRes.status = function (code) {
|
|
200
|
+
statusCode = code;
|
|
201
|
+
res.statusCode = code;
|
|
202
|
+
return apiRes;
|
|
203
|
+
};
|
|
204
|
+
apiRes.header = function (key, value) {
|
|
205
|
+
res.setHeader(key, value);
|
|
206
|
+
return apiRes;
|
|
207
|
+
};
|
|
208
|
+
apiRes.json = function (body) {
|
|
209
|
+
if (!headersSent) {
|
|
210
|
+
res.setHeader("Content-Type", "application/json");
|
|
211
|
+
res.statusCode = statusCode;
|
|
212
|
+
headersSent = true;
|
|
213
|
+
}
|
|
214
|
+
res.end(JSON.stringify(body));
|
|
215
|
+
};
|
|
216
|
+
apiRes.send = function (body) {
|
|
217
|
+
if (!headersSent) {
|
|
218
|
+
if (typeof body === "object" && !(body instanceof Buffer)) {
|
|
219
|
+
res.setHeader("Content-Type", "application/json");
|
|
220
|
+
res.end(JSON.stringify(body));
|
|
221
|
+
} else {
|
|
222
|
+
res.end(body);
|
|
223
|
+
}
|
|
224
|
+
headersSent = true;
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
apiRes.redirect = function (statusOrPath, path) {
|
|
228
|
+
const redirectPath =
|
|
229
|
+
typeof statusOrPath === "string" ? statusOrPath : path || "/";
|
|
230
|
+
const code = typeof statusOrPath === "number" ? statusOrPath : 307;
|
|
231
|
+
res.statusCode = code;
|
|
232
|
+
res.setHeader("Location", redirectPath);
|
|
233
|
+
res.end();
|
|
234
|
+
headersSent = true;
|
|
235
|
+
};
|
|
236
|
+
apiRes.download = function (filepath, filename) {
|
|
237
|
+
res.setHeader(
|
|
238
|
+
"Content-Disposition",
|
|
239
|
+
`attachment; filename="${filename || filepath}"`,
|
|
240
|
+
);
|
|
241
|
+
apiRes.sendFile(filepath);
|
|
242
|
+
};
|
|
243
|
+
apiRes.sendFile = function (filepath) {
|
|
244
|
+
// Dynamic import for sendFile functionality
|
|
245
|
+
(async () => {
|
|
246
|
+
try {
|
|
247
|
+
const { createReadStream } = await import("fs");
|
|
248
|
+
const file = createReadStream(filepath);
|
|
249
|
+
file.pipe(res);
|
|
250
|
+
headersSent = true;
|
|
251
|
+
} catch (err) {
|
|
252
|
+
console.error("Error sending file:", err);
|
|
253
|
+
res.statusCode = 500;
|
|
254
|
+
res.end("Error sending file");
|
|
255
|
+
}
|
|
256
|
+
})();
|
|
257
|
+
};
|
|
258
|
+
return apiRes;
|
|
259
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,19 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
3
|
-
*
|
|
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/>.
|
|
1
|
+
/**
|
|
2
|
+
* Secure cookie utilities for session management
|
|
3
|
+
* Ensures cookies have proper security flags
|
|
17
4
|
*/
|
|
18
5
|
/**
|
|
19
6
|
* Generate secure cookie header value
|
|
@@ -1,19 +1,2 @@
|
|
|
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
|
export * from "./jwt";
|
|
19
2
|
export * from "./session";
|
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* This file is part of Jen.js.
|
|
3
|
-
* Copyright (C) 2026 oopsio
|
|
4
|
-
*
|
|
5
|
-
* This program is free software: you can redistribute it and/or modify
|
|
6
|
-
* it under the terms of the GNU General Public License as published by
|
|
7
|
-
* the Free Software Foundation, either version 3 of the License, or
|
|
8
|
-
* (at your option) any later version.
|
|
9
|
-
*
|
|
10
|
-
* This program is distributed in the hope that it will be useful,
|
|
11
|
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
-
* GNU General Public License for more details.
|
|
14
|
-
*
|
|
15
|
-
* You should have received a copy of the GNU General Public License
|
|
16
|
-
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
-
*/
|
|
18
1
|
/**
|
|
19
2
|
* JWT token utilities for creating and validating JSON Web Tokens.
|
|
20
3
|
* This module provides stub implementations that require an external JWT library.
|