gorsee 0.2.4 → 0.2.6
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/README.md +283 -212
- package/dist-pkg/ai/artifact-lifecycle.d.ts +25 -0
- package/dist-pkg/ai/artifact-lifecycle.js +98 -0
- package/dist-pkg/ai/bridge.d.ts +26 -0
- package/dist-pkg/ai/bridge.js +82 -0
- package/dist-pkg/ai/bundle.d.ts +46 -0
- package/dist-pkg/ai/bundle.js +247 -0
- package/dist-pkg/ai/contracts.d.ts +1 -0
- package/dist-pkg/ai/contracts.js +1 -0
- package/dist-pkg/ai/ide.d.ts +37 -0
- package/dist-pkg/ai/ide.js +56 -0
- package/dist-pkg/ai/index.d.ts +85 -0
- package/dist-pkg/ai/index.js +267 -0
- package/dist-pkg/ai/json.d.ts +6 -0
- package/dist-pkg/ai/json.js +14 -0
- package/dist-pkg/ai/mcp.d.ts +28 -0
- package/dist-pkg/ai/mcp.js +173 -0
- package/dist-pkg/ai/session-pack.d.ts +28 -0
- package/dist-pkg/ai/session-pack.js +57 -0
- package/dist-pkg/ai/store.d.ts +67 -0
- package/dist-pkg/ai/store.js +174 -0
- package/dist-pkg/ai/summary.d.ts +57 -0
- package/dist-pkg/ai/summary.js +148 -0
- package/dist-pkg/ai/watch.d.ts +15 -0
- package/dist-pkg/ai/watch.js +66 -0
- package/dist-pkg/auth/action-tokens.d.ts +50 -0
- package/dist-pkg/auth/action-tokens.js +79 -0
- package/dist-pkg/auth/index.d.ts +70 -0
- package/dist-pkg/auth/index.js +199 -0
- package/dist-pkg/auth/redis-session-store.d.ts +7 -0
- package/dist-pkg/auth/redis-session-store.js +42 -0
- package/dist-pkg/auth/signing.d.ts +4 -0
- package/dist-pkg/auth/signing.js +33 -0
- package/dist-pkg/auth/sqlite-session-store.d.ts +12 -0
- package/dist-pkg/auth/sqlite-session-store.js +83 -0
- package/dist-pkg/auth/store-utils.d.ts +2 -0
- package/dist-pkg/auth/store-utils.js +20 -0
- package/dist-pkg/bin/gorsee.js +2 -0
- package/dist-pkg/build/backends/experimental-rolldown.d.ts +6 -0
- package/dist-pkg/build/backends/experimental-rolldown.js +9 -0
- package/dist-pkg/build/backends/register.d.ts +7 -0
- package/dist-pkg/build/backends/register.js +24 -0
- package/dist-pkg/build/backends/rolldown.d.ts +16 -0
- package/dist-pkg/build/backends/rolldown.js +176 -0
- package/dist-pkg/build/client-backend.d.ts +31 -0
- package/dist-pkg/build/client-backend.js +97 -0
- package/dist-pkg/build/client.d.ts +12 -0
- package/dist-pkg/build/client.js +93 -0
- package/dist-pkg/build/css-modules.d.ts +10 -0
- package/dist-pkg/build/css-modules.js +51 -0
- package/dist-pkg/build/devalue-parse.d.ts +1 -0
- package/dist-pkg/build/devalue-parse.js +1 -0
- package/dist-pkg/build/diagnostics.d.ts +20 -0
- package/dist-pkg/build/diagnostics.js +35 -0
- package/dist-pkg/build/fixtures.d.ts +7 -0
- package/dist-pkg/build/fixtures.js +60 -0
- package/dist-pkg/build/framework-imports.d.ts +4 -0
- package/dist-pkg/build/framework-imports.js +58 -0
- package/dist-pkg/build/init.d.ts +1 -0
- package/dist-pkg/build/init.js +6 -0
- package/dist-pkg/build/manifest.d.ts +3 -0
- package/dist-pkg/build/manifest.js +23 -0
- package/dist-pkg/build/parity.d.ts +32 -0
- package/dist-pkg/build/parity.js +71 -0
- package/dist-pkg/build/plugin.d.ts +11 -0
- package/dist-pkg/build/plugin.js +8 -0
- package/dist-pkg/build/readiness.d.ts +11 -0
- package/dist-pkg/build/readiness.js +18 -0
- package/dist-pkg/build/route-client-transform.d.ts +17 -0
- package/dist-pkg/build/route-client-transform.js +48 -0
- package/dist-pkg/build/route-metadata.d.ts +6 -0
- package/dist-pkg/build/route-metadata.js +8 -0
- package/dist-pkg/build/rpc-transform.d.ts +1 -0
- package/dist-pkg/build/rpc-transform.js +44 -0
- package/dist-pkg/build/server-bundle.d.ts +4 -0
- package/dist-pkg/build/server-bundle.js +261 -0
- package/dist-pkg/build/server-strip.d.ts +2 -0
- package/dist-pkg/build/server-strip.js +32 -0
- package/dist-pkg/build/ssg.d.ts +12 -0
- package/dist-pkg/build/ssg.js +36 -0
- package/dist-pkg/cli/bun-plugin.d.ts +2 -0
- package/dist-pkg/cli/bun-plugin.js +14 -0
- package/dist-pkg/cli/canonical-import-rewrite.d.ts +18 -0
- package/dist-pkg/cli/canonical-import-rewrite.js +94 -0
- package/dist-pkg/cli/canonical-imports.d.ts +8 -0
- package/dist-pkg/cli/canonical-imports.js +131 -0
- package/dist-pkg/cli/check-ast.d.ts +20 -0
- package/dist-pkg/cli/check-ast.js +126 -0
- package/dist-pkg/cli/cmd-ai.d.ts +4 -0
- package/dist-pkg/cli/cmd-ai.js +290 -0
- package/dist-pkg/cli/cmd-build.d.ts +12 -0
- package/dist-pkg/cli/cmd-build.js +198 -0
- package/dist-pkg/cli/cmd-check.d.ts +25 -0
- package/dist-pkg/cli/cmd-check.js +573 -0
- package/dist-pkg/cli/cmd-create.d.ts +6 -0
- package/dist-pkg/cli/cmd-create.js +600 -0
- package/dist-pkg/cli/cmd-deploy.d.ts +6 -0
- package/dist-pkg/cli/cmd-deploy.js +381 -0
- package/dist-pkg/cli/cmd-dev.d.ts +5 -0
- package/dist-pkg/cli/cmd-dev.js +5 -0
- package/dist-pkg/cli/cmd-docs.d.ts +50 -0
- package/dist-pkg/cli/cmd-docs.js +122 -0
- package/dist-pkg/cli/cmd-generate.d.ts +12 -0
- package/dist-pkg/cli/cmd-generate.js +320 -0
- package/dist-pkg/cli/cmd-migrate.d.ts +7 -0
- package/dist-pkg/cli/cmd-migrate.js +42 -0
- package/dist-pkg/cli/cmd-routes.d.ts +6 -0
- package/dist-pkg/cli/cmd-routes.js +24 -0
- package/dist-pkg/cli/cmd-start.d.ts +13 -0
- package/dist-pkg/cli/cmd-start.js +32 -0
- package/dist-pkg/cli/cmd-test.d.ts +20 -0
- package/dist-pkg/cli/cmd-test.js +103 -0
- package/dist-pkg/cli/cmd-typegen.d.ts +7 -0
- package/dist-pkg/cli/cmd-typegen.js +66 -0
- package/dist-pkg/cli/cmd-upgrade.d.ts +38 -0
- package/dist-pkg/cli/cmd-upgrade.js +232 -0
- package/dist-pkg/cli/context.d.ts +4 -0
- package/dist-pkg/cli/context.js +4 -0
- package/dist-pkg/cli/framework-md.d.ts +1 -0
- package/dist-pkg/cli/framework-md.js +391 -0
- package/dist-pkg/cli/index.d.ts +6 -0
- package/dist-pkg/cli/index.js +106 -0
- package/dist-pkg/cli/release-version.d.ts +2 -0
- package/dist-pkg/cli/release-version.js +33 -0
- package/dist-pkg/client.d.ts +16 -0
- package/dist-pkg/client.js +71 -0
- package/dist-pkg/compat.d.ts +1 -0
- package/dist-pkg/compat.js +1 -0
- package/dist-pkg/compiler/analysis-backend.d.ts +20 -0
- package/dist-pkg/compiler/analysis-backend.js +164 -0
- package/dist-pkg/compiler/backends/experimental-oxc.d.ts +6 -0
- package/dist-pkg/compiler/backends/experimental-oxc.js +9 -0
- package/dist-pkg/compiler/backends/oxc.d.ts +16 -0
- package/dist-pkg/compiler/backends/oxc.js +198 -0
- package/dist-pkg/compiler/backends/register.d.ts +7 -0
- package/dist-pkg/compiler/backends/register.js +22 -0
- package/dist-pkg/compiler/fixtures.d.ts +2 -0
- package/dist-pkg/compiler/fixtures.js +118 -0
- package/dist-pkg/compiler/init.d.ts +1 -0
- package/dist-pkg/compiler/init.js +6 -0
- package/dist-pkg/compiler/module-analysis.d.ts +13 -0
- package/dist-pkg/compiler/module-analysis.js +50 -0
- package/dist-pkg/compiler/parity.d.ts +35 -0
- package/dist-pkg/compiler/parity.js +89 -0
- package/dist-pkg/compiler/readiness.d.ts +11 -0
- package/dist-pkg/compiler/readiness.js +18 -0
- package/dist-pkg/compiler/route-facts.d.ts +34 -0
- package/dist-pkg/compiler/route-facts.js +75 -0
- package/dist-pkg/content/index.d.ts +27 -0
- package/dist-pkg/content/index.js +287 -0
- package/dist-pkg/db/index.d.ts +3 -0
- package/dist-pkg/db/index.js +6 -0
- package/dist-pkg/db/migrate.d.ts +7 -0
- package/dist-pkg/db/migrate.js +53 -0
- package/dist-pkg/db/postgres.d.ts +29 -0
- package/dist-pkg/db/postgres.js +59 -0
- package/dist-pkg/db/sqlite.d.ts +10 -0
- package/dist-pkg/db/sqlite.js +22 -0
- package/dist-pkg/deploy/cloudflare.d.ts +8 -0
- package/{src/deploy/cloudflare.ts → dist-pkg/deploy/cloudflare.js} +44 -28
- package/dist-pkg/deploy/conformance.d.ts +21 -0
- package/dist-pkg/deploy/conformance.js +98 -0
- package/dist-pkg/deploy/dockerfile.d.ts +3 -0
- package/{src/deploy/dockerfile.ts → dist-pkg/deploy/dockerfile.js} +8 -10
- package/dist-pkg/deploy/fly.d.ts +3 -0
- package/{src/deploy/fly.ts → dist-pkg/deploy/fly.js} +11 -12
- package/dist-pkg/deploy/index.d.ts +6 -0
- package/dist-pkg/deploy/index.js +26 -0
- package/dist-pkg/deploy/netlify.d.ts +2 -0
- package/{src/deploy/netlify.ts → dist-pkg/deploy/netlify.js} +17 -11
- package/dist-pkg/deploy/runtime.d.ts +2 -0
- package/dist-pkg/deploy/runtime.js +3 -0
- package/dist-pkg/deploy/vercel.d.ts +22 -0
- package/dist-pkg/deploy/vercel.js +53 -0
- package/dist-pkg/dev/error-overlay.d.ts +1 -0
- package/{src/dev/error-overlay.ts → dist-pkg/dev/error-overlay.js} +13 -23
- package/dist-pkg/dev/hmr.d.ts +30 -0
- package/dist-pkg/dev/hmr.js +86 -0
- package/dist-pkg/dev/partial-handler.d.ts +9 -0
- package/dist-pkg/dev/partial-handler.js +24 -0
- package/dist-pkg/dev/request-handler.d.ts +30 -0
- package/dist-pkg/dev/request-handler.js +67 -0
- package/dist-pkg/dev/watcher.d.ts +6 -0
- package/dist-pkg/dev/watcher.js +34 -0
- package/dist-pkg/dev.d.ts +11 -0
- package/dist-pkg/dev.js +268 -0
- package/dist-pkg/env/index.d.ts +3 -0
- package/dist-pkg/env/index.js +57 -0
- package/dist-pkg/errors/catalog.d.ts +9 -0
- package/{src/errors/catalog.ts → dist-pkg/errors/catalog.js} +8 -24
- package/dist-pkg/errors/formatter.d.ts +22 -0
- package/dist-pkg/errors/formatter.js +43 -0
- package/dist-pkg/errors/index.d.ts +2 -0
- package/dist-pkg/errors/index.js +2 -0
- package/dist-pkg/forms/action.d.ts +15 -0
- package/dist-pkg/forms/action.js +20 -0
- package/dist-pkg/forms/index.d.ts +4 -0
- package/dist-pkg/forms/index.js +12 -0
- package/dist-pkg/i18n/index.d.ts +61 -0
- package/dist-pkg/i18n/index.js +147 -0
- package/dist-pkg/index-client.d.ts +1 -0
- package/dist-pkg/index-client.js +1 -0
- package/dist-pkg/index.d.ts +32 -0
- package/dist-pkg/index.js +79 -0
- package/dist-pkg/jsx-runtime-client.d.ts +8 -0
- package/dist-pkg/jsx-runtime-client.js +1 -0
- package/dist-pkg/jsx-runtime.d.ts +13 -0
- package/dist-pkg/jsx-runtime.js +5 -0
- package/dist-pkg/jsx-types-html.d.ts +221 -0
- package/dist-pkg/jsx-types-html.js +0 -0
- package/dist-pkg/log/index.d.ts +8 -0
- package/dist-pkg/log/index.js +55 -0
- package/dist-pkg/plugins/drizzle.d.ts +16 -0
- package/dist-pkg/plugins/drizzle.js +53 -0
- package/dist-pkg/plugins/index.d.ts +62 -0
- package/dist-pkg/plugins/index.js +159 -0
- package/dist-pkg/plugins/lucia.d.ts +26 -0
- package/dist-pkg/plugins/lucia.js +63 -0
- package/dist-pkg/plugins/prisma.d.ts +14 -0
- package/dist-pkg/plugins/prisma.js +60 -0
- package/dist-pkg/plugins/resend.d.ts +21 -0
- package/dist-pkg/plugins/resend.js +45 -0
- package/dist-pkg/plugins/s3.d.ts +18 -0
- package/dist-pkg/plugins/s3.js +63 -0
- package/dist-pkg/plugins/stripe.d.ts +32 -0
- package/dist-pkg/plugins/stripe.js +69 -0
- package/dist-pkg/plugins/tailwind.d.ts +15 -0
- package/dist-pkg/plugins/tailwind.js +58 -0
- package/dist-pkg/prod.d.ts +21 -0
- package/dist-pkg/prod.js +347 -0
- package/dist-pkg/reactive/computed.d.ts +3 -0
- package/dist-pkg/reactive/computed.js +15 -0
- package/dist-pkg/reactive/data.d.ts +25 -0
- package/dist-pkg/reactive/data.js +56 -0
- package/dist-pkg/reactive/diagnostics.d.ts +100 -0
- package/dist-pkg/reactive/diagnostics.js +363 -0
- package/dist-pkg/reactive/effect.d.ts +3 -0
- package/dist-pkg/reactive/effect.js +6 -0
- package/dist-pkg/reactive/index.d.ts +9 -0
- package/dist-pkg/reactive/index.js +18 -0
- package/dist-pkg/reactive/live.d.ts +15 -0
- package/dist-pkg/reactive/live.js +70 -0
- package/dist-pkg/reactive/optimistic.d.ts +20 -0
- package/dist-pkg/reactive/optimistic.js +67 -0
- package/dist-pkg/reactive/resource.d.ts +25 -0
- package/dist-pkg/reactive/resource.js +153 -0
- package/dist-pkg/reactive/signal.d.ts +4 -0
- package/dist-pkg/reactive/signal.js +17 -0
- package/dist-pkg/reactive/store.d.ts +6 -0
- package/dist-pkg/reactive/store.js +19 -0
- package/dist-pkg/router/index.d.ts +2 -0
- package/dist-pkg/router/index.js +2 -0
- package/dist-pkg/router/matcher.d.ts +7 -0
- package/dist-pkg/router/matcher.js +40 -0
- package/dist-pkg/router/scanner.d.ts +14 -0
- package/dist-pkg/router/scanner.js +141 -0
- package/dist-pkg/routes/index.d.ts +1 -0
- package/dist-pkg/routes/index.js +10 -0
- package/dist-pkg/runtime/app-config.d.ts +26 -0
- package/dist-pkg/runtime/app-config.js +69 -0
- package/dist-pkg/runtime/client.d.ts +3 -0
- package/dist-pkg/runtime/client.js +42 -0
- package/dist-pkg/runtime/devtools.d.ts +64 -0
- package/dist-pkg/runtime/devtools.js +132 -0
- package/dist-pkg/runtime/error-boundary.d.ts +6 -0
- package/dist-pkg/runtime/error-boundary.js +17 -0
- package/dist-pkg/runtime/event-replay.d.ts +3 -0
- package/{src/runtime/event-replay.ts → dist-pkg/runtime/event-replay.js} +20 -22
- package/dist-pkg/runtime/event-source.d.ts +7 -0
- package/dist-pkg/runtime/event-source.js +24 -0
- package/dist-pkg/runtime/form.d.ts +24 -0
- package/dist-pkg/runtime/form.js +65 -0
- package/dist-pkg/runtime/head.d.ts +7 -0
- package/dist-pkg/runtime/head.js +90 -0
- package/dist-pkg/runtime/html-escape.d.ts +7 -0
- package/dist-pkg/runtime/html-escape.js +39 -0
- package/dist-pkg/runtime/hydration.d.ts +15 -0
- package/dist-pkg/runtime/hydration.js +103 -0
- package/dist-pkg/runtime/image.d.ts +49 -0
- package/dist-pkg/runtime/image.js +144 -0
- package/dist-pkg/runtime/index.d.ts +17 -0
- package/dist-pkg/runtime/index.js +59 -0
- package/dist-pkg/runtime/island-hydrator.d.ts +12 -0
- package/dist-pkg/runtime/island-hydrator.js +74 -0
- package/dist-pkg/runtime/island.d.ts +19 -0
- package/dist-pkg/runtime/island.js +36 -0
- package/dist-pkg/runtime/jsx-runtime.d.ts +12 -0
- package/dist-pkg/runtime/jsx-runtime.js +176 -0
- package/dist-pkg/runtime/link.d.ts +16 -0
- package/dist-pkg/runtime/link.js +47 -0
- package/dist-pkg/runtime/project.d.ts +37 -0
- package/dist-pkg/runtime/project.js +36 -0
- package/dist-pkg/runtime/renderable.d.ts +6 -0
- package/dist-pkg/runtime/renderable.js +0 -0
- package/dist-pkg/runtime/router.d.ts +47 -0
- package/dist-pkg/runtime/router.js +487 -0
- package/dist-pkg/runtime/server.d.ts +8 -0
- package/dist-pkg/runtime/server.js +71 -0
- package/dist-pkg/runtime/stream.d.ts +29 -0
- package/dist-pkg/runtime/stream.js +106 -0
- package/dist-pkg/runtime/suspense.d.ts +6 -0
- package/dist-pkg/runtime/suspense.js +16 -0
- package/dist-pkg/runtime/typed-routes.d.ts +24 -0
- package/dist-pkg/runtime/typed-routes.js +77 -0
- package/dist-pkg/runtime/validated-form.d.ts +40 -0
- package/dist-pkg/runtime/validated-form.js +120 -0
- package/dist-pkg/security/cors.d.ts +10 -0
- package/dist-pkg/security/cors.js +56 -0
- package/dist-pkg/security/csrf.d.ts +9 -0
- package/dist-pkg/security/csrf.js +53 -0
- package/dist-pkg/security/headers.d.ts +11 -0
- package/dist-pkg/security/headers.js +31 -0
- package/dist-pkg/security/index.d.ts +5 -0
- package/dist-pkg/security/index.js +5 -0
- package/dist-pkg/security/rate-limit.d.ts +10 -0
- package/dist-pkg/security/rate-limit.js +49 -0
- package/dist-pkg/security/redis-rate-limit.d.ts +14 -0
- package/dist-pkg/security/redis-rate-limit.js +23 -0
- package/dist-pkg/server/action.d.ts +21 -0
- package/dist-pkg/server/action.js +64 -0
- package/dist-pkg/server/cache-utils.d.ts +2 -0
- package/dist-pkg/server/cache-utils.js +26 -0
- package/dist-pkg/server/cache.d.ts +33 -0
- package/dist-pkg/server/cache.js +236 -0
- package/dist-pkg/server/compress.d.ts +2 -0
- package/dist-pkg/server/compress.js +77 -0
- package/dist-pkg/server/endpoint-execution.d.ts +28 -0
- package/dist-pkg/server/endpoint-execution.js +37 -0
- package/dist-pkg/server/etag.d.ts +3 -0
- package/dist-pkg/server/etag.js +18 -0
- package/dist-pkg/server/guard.d.ts +16 -0
- package/dist-pkg/server/guard.js +45 -0
- package/dist-pkg/server/html-shell.d.ts +12 -0
- package/dist-pkg/server/html-shell.js +52 -0
- package/dist-pkg/server/index.d.ts +36 -0
- package/dist-pkg/server/index.js +170 -0
- package/dist-pkg/server/jobs.d.ts +41 -0
- package/dist-pkg/server/jobs.js +83 -0
- package/dist-pkg/server/manifest.d.ts +19 -0
- package/dist-pkg/server/manifest.js +36 -0
- package/dist-pkg/server/middleware.d.ts +39 -0
- package/dist-pkg/server/middleware.js +127 -0
- package/dist-pkg/server/mime.d.ts +1 -0
- package/{src/server/mime.ts → dist-pkg/server/mime.js} +6 -17
- package/dist-pkg/server/not-found.d.ts +6 -0
- package/dist-pkg/server/not-found.js +27 -0
- package/dist-pkg/server/page-render.d.ts +29 -0
- package/dist-pkg/server/page-render.js +70 -0
- package/dist-pkg/server/partial-navigation.d.ts +4 -0
- package/dist-pkg/server/partial-navigation.js +16 -0
- package/dist-pkg/server/pipe.d.ts +9 -0
- package/dist-pkg/server/pipe.js +32 -0
- package/dist-pkg/server/redis-cache-store.d.ts +10 -0
- package/dist-pkg/server/redis-cache-store.js +73 -0
- package/dist-pkg/server/redis-client.d.ts +37 -0
- package/dist-pkg/server/redis-client.js +37 -0
- package/dist-pkg/server/request-policy.d.ts +55 -0
- package/dist-pkg/server/request-policy.js +216 -0
- package/dist-pkg/server/request-preflight.d.ts +23 -0
- package/dist-pkg/server/request-preflight.js +46 -0
- package/dist-pkg/server/request-security-policy.d.ts +17 -0
- package/dist-pkg/server/request-security-policy.js +34 -0
- package/dist-pkg/server/request-surface.d.ts +8 -0
- package/dist-pkg/server/request-surface.js +19 -0
- package/dist-pkg/server/route-request.d.ts +31 -0
- package/dist-pkg/server/route-request.js +112 -0
- package/dist-pkg/server/route-response.d.ts +22 -0
- package/dist-pkg/server/route-response.js +61 -0
- package/dist-pkg/server/rpc-hash.d.ts +2 -0
- package/dist-pkg/server/rpc-hash.js +7 -0
- package/dist-pkg/server/rpc-protocol.d.ts +22 -0
- package/dist-pkg/server/rpc-protocol.js +28 -0
- package/dist-pkg/server/rpc-utils.d.ts +2 -0
- package/dist-pkg/server/rpc-utils.js +26 -0
- package/dist-pkg/server/rpc.d.ts +20 -0
- package/dist-pkg/server/rpc.js +147 -0
- package/dist-pkg/server/runtime-dispatch.d.ts +19 -0
- package/dist-pkg/server/runtime-dispatch.js +67 -0
- package/dist-pkg/server/server-execution.d.ts +22 -0
- package/dist-pkg/server/server-execution.js +53 -0
- package/dist-pkg/server/sqlite-cache-store.d.ts +13 -0
- package/dist-pkg/server/sqlite-cache-store.js +88 -0
- package/dist-pkg/server/sse.d.ts +9 -0
- package/dist-pkg/server/sse.js +34 -0
- package/dist-pkg/server/static-file.d.ts +9 -0
- package/dist-pkg/server/static-file.js +43 -0
- package/dist-pkg/server/ws.d.ts +18 -0
- package/dist-pkg/server/ws.js +40 -0
- package/dist-pkg/server-entry.d.ts +19 -0
- package/dist-pkg/server-entry.js +93 -0
- package/dist-pkg/testing/index.d.ts +98 -0
- package/dist-pkg/testing/index.js +257 -0
- package/dist-pkg/types/index.d.ts +4 -0
- package/dist-pkg/types/index.js +4 -0
- package/dist-pkg/types/safe-html.d.ts +7 -0
- package/dist-pkg/types/safe-html.js +19 -0
- package/dist-pkg/types/safe-sql.d.ts +8 -0
- package/dist-pkg/types/safe-sql.js +14 -0
- package/dist-pkg/types/safe-url.d.ts +7 -0
- package/dist-pkg/types/safe-url.js +20 -0
- package/dist-pkg/types/user-input.d.ts +9 -0
- package/dist-pkg/types/user-input.js +3 -0
- package/dist-pkg/unsafe/index.d.ts +12 -0
- package/dist-pkg/unsafe/index.js +6 -0
- package/package.json +110 -45
- package/bin/gorsee.js +0 -2
- package/src/auth/index.ts +0 -178
- package/src/auth/redis-session-store.ts +0 -46
- package/src/auth/sqlite-session-store.ts +0 -98
- package/src/auth/store-utils.ts +0 -21
- package/src/build/client.ts +0 -139
- package/src/build/css-modules.ts +0 -69
- package/src/build/devalue-parse.ts +0 -2
- package/src/build/manifest.ts +0 -34
- package/src/build/route-metadata.ts +0 -12
- package/src/build/rpc-transform.ts +0 -62
- package/src/build/server-strip.ts +0 -87
- package/src/build/ssg.ts +0 -70
- package/src/cli/bun-plugin.ts +0 -58
- package/src/cli/cmd-build.ts +0 -153
- package/src/cli/cmd-check.ts +0 -239
- package/src/cli/cmd-create.ts +0 -328
- package/src/cli/cmd-deploy.ts +0 -149
- package/src/cli/cmd-dev.ts +0 -13
- package/src/cli/cmd-docs.ts +0 -152
- package/src/cli/cmd-generate.ts +0 -155
- package/src/cli/cmd-migrate.ts +0 -53
- package/src/cli/cmd-routes.ts +0 -36
- package/src/cli/cmd-start.ts +0 -30
- package/src/cli/cmd-test.ts +0 -129
- package/src/cli/cmd-typegen.ts +0 -93
- package/src/cli/cmd-upgrade.ts +0 -143
- package/src/cli/context.ts +0 -12
- package/src/cli/framework-md.ts +0 -223
- package/src/cli/index.ts +0 -107
- package/src/client.ts +0 -26
- package/src/db/index.ts +0 -2
- package/src/db/migrate.ts +0 -89
- package/src/db/sqlite.ts +0 -40
- package/src/deploy/index.ts +0 -31
- package/src/deploy/vercel.ts +0 -94
- package/src/dev/hmr.ts +0 -31
- package/src/dev/partial-handler.ts +0 -52
- package/src/dev/request-handler.ts +0 -127
- package/src/dev/watcher.ts +0 -48
- package/src/dev.ts +0 -208
- package/src/env/index.ts +0 -74
- package/src/errors/formatter.ts +0 -63
- package/src/errors/index.ts +0 -2
- package/src/i18n/index.ts +0 -72
- package/src/index-client.ts +0 -4
- package/src/index.ts +0 -43
- package/src/jsx-runtime-client.ts +0 -13
- package/src/jsx-runtime.ts +0 -20
- package/src/jsx-types-html.ts +0 -242
- package/src/log/index.ts +0 -44
- package/src/plugins/drizzle.ts +0 -84
- package/src/plugins/index.ts +0 -86
- package/src/plugins/lucia.ts +0 -111
- package/src/plugins/prisma.ts +0 -85
- package/src/plugins/resend.ts +0 -78
- package/src/plugins/s3.ts +0 -102
- package/src/plugins/stripe.ts +0 -133
- package/src/plugins/tailwind.ts +0 -92
- package/src/prod.ts +0 -252
- package/src/reactive/computed.ts +0 -7
- package/src/reactive/effect.ts +0 -7
- package/src/reactive/index.ts +0 -7
- package/src/reactive/live.ts +0 -97
- package/src/reactive/optimistic.ts +0 -83
- package/src/reactive/resource.ts +0 -138
- package/src/reactive/signal.ts +0 -20
- package/src/reactive/store.ts +0 -36
- package/src/router/index.ts +0 -2
- package/src/router/matcher.ts +0 -53
- package/src/router/scanner.ts +0 -206
- package/src/runtime/client.ts +0 -28
- package/src/runtime/error-boundary.ts +0 -35
- package/src/runtime/form.ts +0 -49
- package/src/runtime/head.ts +0 -113
- package/src/runtime/html-escape.ts +0 -30
- package/src/runtime/hydration.ts +0 -95
- package/src/runtime/image.ts +0 -48
- package/src/runtime/index.ts +0 -12
- package/src/runtime/island-hydrator.ts +0 -84
- package/src/runtime/island.ts +0 -88
- package/src/runtime/jsx-runtime.ts +0 -167
- package/src/runtime/link.ts +0 -45
- package/src/runtime/project.ts +0 -73
- package/src/runtime/router.ts +0 -224
- package/src/runtime/server.ts +0 -102
- package/src/runtime/stream.ts +0 -182
- package/src/runtime/suspense.ts +0 -37
- package/src/runtime/typed-routes.ts +0 -26
- package/src/runtime/validated-form.ts +0 -106
- package/src/security/cors.ts +0 -80
- package/src/security/csrf.ts +0 -85
- package/src/security/headers.ts +0 -50
- package/src/security/index.ts +0 -4
- package/src/security/rate-limit.ts +0 -80
- package/src/server/action.ts +0 -48
- package/src/server/cache-utils.ts +0 -23
- package/src/server/cache.ts +0 -125
- package/src/server/compress.ts +0 -60
- package/src/server/etag.ts +0 -23
- package/src/server/guard.ts +0 -69
- package/src/server/html-shell.ts +0 -69
- package/src/server/index.ts +0 -57
- package/src/server/manifest.ts +0 -36
- package/src/server/middleware.ts +0 -159
- package/src/server/not-found.ts +0 -35
- package/src/server/page-render.ts +0 -123
- package/src/server/pipe.ts +0 -46
- package/src/server/redis-cache-store.ts +0 -87
- package/src/server/redis-client.ts +0 -71
- package/src/server/request-preflight.ts +0 -45
- package/src/server/route-request.ts +0 -72
- package/src/server/rpc-hash.ts +0 -17
- package/src/server/rpc-utils.ts +0 -27
- package/src/server/rpc.ts +0 -177
- package/src/server/sqlite-cache-store.ts +0 -109
- package/src/server/sse.ts +0 -96
- package/src/server/static-file.ts +0 -63
- package/src/server/ws.ts +0 -56
- package/src/server-entry.ts +0 -36
- package/src/testing/index.ts +0 -74
- package/src/types/index.ts +0 -4
- package/src/types/safe-html.ts +0 -32
- package/src/types/safe-sql.ts +0 -28
- package/src/types/safe-url.ts +0 -40
- package/src/types/user-input.ts +0 -12
- package/src/unsafe/index.ts +0 -18
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
// Type-safe validated forms with branded types
|
|
2
|
-
// Combines client-side validation with server-side action safety
|
|
3
|
-
|
|
4
|
-
export interface FieldRule {
|
|
5
|
-
required?: boolean
|
|
6
|
-
minLength?: number
|
|
7
|
-
maxLength?: number
|
|
8
|
-
pattern?: RegExp
|
|
9
|
-
min?: number
|
|
10
|
-
max?: number
|
|
11
|
-
custom?: (value: string) => string | null // return error message or null
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface FormField {
|
|
15
|
-
name: string
|
|
16
|
-
rules: FieldRule
|
|
17
|
-
label?: string
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface FormSchema {
|
|
21
|
-
fields: FormField[]
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface ValidationError {
|
|
25
|
-
field: string
|
|
26
|
-
message: string
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface ValidationResult<T> {
|
|
30
|
-
valid: boolean
|
|
31
|
-
data: T | null
|
|
32
|
-
errors: ValidationError[]
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** Define a form schema for validation */
|
|
36
|
-
export function defineForm(fields: FormField[]): FormSchema {
|
|
37
|
-
return { fields }
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function validateField(value: string | undefined, field: FormField): string | null {
|
|
41
|
-
const { rules, label } = field
|
|
42
|
-
const name = label ?? field.name
|
|
43
|
-
const v = value ?? ""
|
|
44
|
-
|
|
45
|
-
if (rules.required && !v.trim()) return `${name} is required`
|
|
46
|
-
if (!v && !rules.required) return null
|
|
47
|
-
if (rules.minLength !== undefined && v.length < rules.minLength)
|
|
48
|
-
return `${name} must be at least ${rules.minLength} characters`
|
|
49
|
-
if (rules.maxLength !== undefined && v.length > rules.maxLength)
|
|
50
|
-
return `${name} must be at most ${rules.maxLength} characters`
|
|
51
|
-
if (rules.pattern && !rules.pattern.test(v)) return `${name} format is invalid`
|
|
52
|
-
if (rules.min !== undefined && Number(v) < rules.min) return `${name} must be at least ${rules.min}`
|
|
53
|
-
if (rules.max !== undefined && Number(v) > rules.max) return `${name} must be at most ${rules.max}`
|
|
54
|
-
if (rules.custom) return rules.custom(v)
|
|
55
|
-
return null
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** Validate form data against schema */
|
|
59
|
-
export function validateForm<T extends Record<string, string>>(
|
|
60
|
-
data: Record<string, string>,
|
|
61
|
-
schema: FormSchema,
|
|
62
|
-
): ValidationResult<T> {
|
|
63
|
-
const errors: ValidationError[] = []
|
|
64
|
-
|
|
65
|
-
for (const field of schema.fields) {
|
|
66
|
-
const error = validateField(data[field.name], field)
|
|
67
|
-
if (error) errors.push({ field: field.name, message: error })
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
valid: errors.length === 0,
|
|
72
|
-
data: errors.length === 0 ? (data as T) : null,
|
|
73
|
-
errors,
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** Server action helper: parse request and validate */
|
|
78
|
-
export async function validateAction<T extends Record<string, string>>(
|
|
79
|
-
request: Request,
|
|
80
|
-
schema: FormSchema,
|
|
81
|
-
): Promise<ValidationResult<T>> {
|
|
82
|
-
const contentType = request.headers.get("content-type") ?? ""
|
|
83
|
-
let data: Record<string, string>
|
|
84
|
-
|
|
85
|
-
if (contentType.includes("application/json")) {
|
|
86
|
-
data = await request.json()
|
|
87
|
-
} else {
|
|
88
|
-
const formData = await request.formData()
|
|
89
|
-
data = {}
|
|
90
|
-
formData.forEach((v, k) => { data[k] = String(v) })
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return validateForm<T>(data, schema)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/** Generate client-side validation attributes for HTML inputs */
|
|
97
|
-
export function fieldAttrs(field: FormField): Record<string, unknown> {
|
|
98
|
-
const attrs: Record<string, unknown> = { name: field.name }
|
|
99
|
-
if (field.rules.required) attrs.required = true
|
|
100
|
-
if (field.rules.minLength !== undefined) attrs.minlength = field.rules.minLength
|
|
101
|
-
if (field.rules.maxLength !== undefined) attrs.maxlength = field.rules.maxLength
|
|
102
|
-
if (field.rules.pattern) attrs.pattern = field.rules.pattern.source
|
|
103
|
-
if (field.rules.min !== undefined) attrs.min = field.rules.min
|
|
104
|
-
if (field.rules.max !== undefined) attrs.max = field.rules.max
|
|
105
|
-
return attrs
|
|
106
|
-
}
|
package/src/security/cors.ts
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
// CORS middleware — configurable Cross-Origin Resource Sharing
|
|
2
|
-
|
|
3
|
-
import type { MiddlewareFn } from "../server/middleware.ts"
|
|
4
|
-
|
|
5
|
-
export interface CORSOptions {
|
|
6
|
-
origin?: string | string[] | ((origin: string) => boolean)
|
|
7
|
-
methods?: string[]
|
|
8
|
-
allowHeaders?: string[]
|
|
9
|
-
exposeHeaders?: string[]
|
|
10
|
-
credentials?: boolean
|
|
11
|
-
maxAge?: number
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const DEFAULT_METHODS = ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"]
|
|
15
|
-
const DEFAULT_HEADERS = ["Content-Type", "Authorization", "X-Requested-With"]
|
|
16
|
-
|
|
17
|
-
function isOriginAllowed(origin: string, allowed: CORSOptions["origin"]): boolean {
|
|
18
|
-
if (!allowed) return false
|
|
19
|
-
if (allowed === "*") return true
|
|
20
|
-
if (typeof allowed === "string") return origin === allowed
|
|
21
|
-
if (Array.isArray(allowed)) return allowed.includes(origin)
|
|
22
|
-
if (typeof allowed === "function") return allowed(origin)
|
|
23
|
-
return false
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function cors(options: CORSOptions = {}): MiddlewareFn {
|
|
27
|
-
const {
|
|
28
|
-
origin = "*",
|
|
29
|
-
methods = DEFAULT_METHODS,
|
|
30
|
-
allowHeaders = DEFAULT_HEADERS,
|
|
31
|
-
exposeHeaders = [],
|
|
32
|
-
credentials = false,
|
|
33
|
-
maxAge = 86400,
|
|
34
|
-
} = options
|
|
35
|
-
|
|
36
|
-
return async (ctx, next) => {
|
|
37
|
-
const requestOrigin = ctx.request.headers.get("origin") ?? ""
|
|
38
|
-
|
|
39
|
-
// Preflight
|
|
40
|
-
if (ctx.request.method === "OPTIONS") {
|
|
41
|
-
const headers = new Headers()
|
|
42
|
-
|
|
43
|
-
if (origin === "*" && !credentials) {
|
|
44
|
-
headers.set("Access-Control-Allow-Origin", "*")
|
|
45
|
-
} else if (isOriginAllowed(requestOrigin, origin)) {
|
|
46
|
-
headers.set("Access-Control-Allow-Origin", requestOrigin)
|
|
47
|
-
headers.set("Vary", "Origin")
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
headers.set("Access-Control-Allow-Methods", methods.join(", "))
|
|
51
|
-
headers.set("Access-Control-Allow-Headers", allowHeaders.join(", "))
|
|
52
|
-
if (exposeHeaders.length > 0) {
|
|
53
|
-
headers.set("Access-Control-Expose-Headers", exposeHeaders.join(", "))
|
|
54
|
-
}
|
|
55
|
-
if (credentials) headers.set("Access-Control-Allow-Credentials", "true")
|
|
56
|
-
headers.set("Access-Control-Max-Age", String(maxAge))
|
|
57
|
-
|
|
58
|
-
return new Response(null, { status: 204, headers })
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Actual request
|
|
62
|
-
const response = await next()
|
|
63
|
-
|
|
64
|
-
if (origin === "*" && !credentials) {
|
|
65
|
-
response.headers.set("Access-Control-Allow-Origin", "*")
|
|
66
|
-
} else if (isOriginAllowed(requestOrigin, origin)) {
|
|
67
|
-
response.headers.set("Access-Control-Allow-Origin", requestOrigin)
|
|
68
|
-
response.headers.append("Vary", "Origin")
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (credentials) {
|
|
72
|
-
response.headers.set("Access-Control-Allow-Credentials", "true")
|
|
73
|
-
}
|
|
74
|
-
if (exposeHeaders.length > 0) {
|
|
75
|
-
response.headers.set("Access-Control-Expose-Headers", exposeHeaders.join(", "))
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return response
|
|
79
|
-
}
|
|
80
|
-
}
|
package/src/security/csrf.ts
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
// CSRF protection using Signed Double-Submit Cookie pattern
|
|
2
|
-
// Works for both SSR (token in HTML) and SPA (cookie-based)
|
|
3
|
-
|
|
4
|
-
import { timingSafeEqual } from "node:crypto"
|
|
5
|
-
|
|
6
|
-
const CSRF_COOKIE = "__gorsee_csrf"
|
|
7
|
-
const CSRF_HEADER = "x-gorsee-csrf"
|
|
8
|
-
const TOKEN_LENGTH = 32
|
|
9
|
-
|
|
10
|
-
function randomBytes(length: number): string {
|
|
11
|
-
const bytes = new Uint8Array(length)
|
|
12
|
-
crypto.getRandomValues(bytes)
|
|
13
|
-
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("")
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
async function hmacSign(token: string, secret: string): Promise<string> {
|
|
17
|
-
const key = await crypto.subtle.importKey(
|
|
18
|
-
"raw",
|
|
19
|
-
new TextEncoder().encode(secret),
|
|
20
|
-
{ name: "HMAC", hash: "SHA-256" },
|
|
21
|
-
false,
|
|
22
|
-
["sign"]
|
|
23
|
-
)
|
|
24
|
-
const sig = await crypto.subtle.sign(
|
|
25
|
-
"HMAC",
|
|
26
|
-
key,
|
|
27
|
-
new TextEncoder().encode(token)
|
|
28
|
-
)
|
|
29
|
-
return Array.from(new Uint8Array(sig), (b) => b.toString(16).padStart(2, "0")).join("")
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function generateCSRFToken(): string {
|
|
33
|
-
return randomBytes(TOKEN_LENGTH)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export async function validateCSRFToken(
|
|
37
|
-
request: Request,
|
|
38
|
-
secret: string
|
|
39
|
-
): Promise<boolean> {
|
|
40
|
-
// Skip safe methods
|
|
41
|
-
if (["GET", "HEAD", "OPTIONS"].includes(request.method)) return true
|
|
42
|
-
|
|
43
|
-
const cookieHeader = request.headers.get("cookie") ?? ""
|
|
44
|
-
const headerToken = request.headers.get(CSRF_HEADER) ?? ""
|
|
45
|
-
|
|
46
|
-
// Parse cookie
|
|
47
|
-
let cookieToken = ""
|
|
48
|
-
for (const pair of cookieHeader.split(";")) {
|
|
49
|
-
const [key, ...rest] = pair.trim().split("=")
|
|
50
|
-
if (key === CSRF_COOKIE) {
|
|
51
|
-
cookieToken = rest.join("=")
|
|
52
|
-
break
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (!cookieToken || !headerToken) return false
|
|
57
|
-
|
|
58
|
-
// Verify: cookie contains "token.signature", header contains "token"
|
|
59
|
-
const [token, signature] = cookieToken.split(".")
|
|
60
|
-
if (!token || !signature) return false
|
|
61
|
-
|
|
62
|
-
// Header must match token part of cookie
|
|
63
|
-
if (headerToken !== token) return false
|
|
64
|
-
|
|
65
|
-
// Verify HMAC signature (timing-safe comparison)
|
|
66
|
-
const expectedSig = await hmacSign(token, secret)
|
|
67
|
-
if (signature.length !== expectedSig.length) return false
|
|
68
|
-
return timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSig))
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export async function csrfProtection(secret: string): Promise<{
|
|
72
|
-
token: string
|
|
73
|
-
cookie: string
|
|
74
|
-
headerName: string
|
|
75
|
-
}> {
|
|
76
|
-
const token = generateCSRFToken()
|
|
77
|
-
const signature = await hmacSign(token, secret)
|
|
78
|
-
const cookieValue = `${token}.${signature}`
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
token,
|
|
82
|
-
cookie: `${CSRF_COOKIE}=${cookieValue}; Path=/; SameSite=Lax; Secure`,
|
|
83
|
-
headerName: CSRF_HEADER,
|
|
84
|
-
}
|
|
85
|
-
}
|
package/src/security/headers.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
export interface SecurityConfig {
|
|
2
|
-
csp: boolean
|
|
3
|
-
hsts: boolean
|
|
4
|
-
csrf: boolean
|
|
5
|
-
rateLimit: { requests: number; window: string } | false
|
|
6
|
-
nonce?: string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const DEFAULT_CONFIG: SecurityConfig = {
|
|
10
|
-
csp: true,
|
|
11
|
-
hsts: true,
|
|
12
|
-
csrf: true,
|
|
13
|
-
rateLimit: { requests: 100, window: "1m" },
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function securityHeaders(
|
|
17
|
-
config: Partial<SecurityConfig> = {},
|
|
18
|
-
nonce?: string
|
|
19
|
-
): Record<string, string> {
|
|
20
|
-
const cfg = { ...DEFAULT_CONFIG, ...config }
|
|
21
|
-
const headers: Record<string, string> = {}
|
|
22
|
-
|
|
23
|
-
if (cfg.csp) {
|
|
24
|
-
const scriptSrc = nonce ? `'nonce-${nonce}'` : "'self'"
|
|
25
|
-
headers["Content-Security-Policy"] = [
|
|
26
|
-
"default-src 'self'",
|
|
27
|
-
`script-src ${scriptSrc}`,
|
|
28
|
-
"style-src 'self' 'unsafe-inline'",
|
|
29
|
-
"img-src 'self' data: https:",
|
|
30
|
-
"font-src 'self'",
|
|
31
|
-
"connect-src 'self' ws: wss:",
|
|
32
|
-
"frame-ancestors 'none'",
|
|
33
|
-
"base-uri 'self'",
|
|
34
|
-
"form-action 'self'",
|
|
35
|
-
].join("; ")
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (cfg.hsts) {
|
|
39
|
-
headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains; preload"
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Always set these
|
|
43
|
-
headers["X-Content-Type-Options"] = "nosniff"
|
|
44
|
-
headers["X-Frame-Options"] = "DENY"
|
|
45
|
-
headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
|
|
46
|
-
headers["X-XSS-Protection"] = "0" // Modern browsers: CSP is better
|
|
47
|
-
headers["Permissions-Policy"] = "camera=(), microphone=(), geolocation=()"
|
|
48
|
-
|
|
49
|
-
return headers
|
|
50
|
-
}
|
package/src/security/index.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export { securityHeaders, type SecurityConfig } from "./headers.ts"
|
|
2
|
-
export { csrfProtection, generateCSRFToken, validateCSRFToken } from "./csrf.ts"
|
|
3
|
-
export { createRateLimiter, type RateLimiter } from "./rate-limit.ts"
|
|
4
|
-
export { cors, type CORSOptions } from "./cors.ts"
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
// In-memory token bucket rate limiter (for Bun runtime)
|
|
2
|
-
// For Cloudflare Workers: use Durable Objects adapter (future)
|
|
3
|
-
|
|
4
|
-
export interface RateLimiter {
|
|
5
|
-
check(key: string): { allowed: boolean; remaining: number; resetAt: number }
|
|
6
|
-
reset(key: string): void
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
interface Bucket {
|
|
10
|
-
tokens: number
|
|
11
|
-
lastRefill: number
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function parseWindow(window: string): number {
|
|
15
|
-
const match = window.match(/^(\d+)(s|m|h)$/)
|
|
16
|
-
if (!match) throw new Error(`Invalid rate limit window: "${window}"`)
|
|
17
|
-
const value = Number(match[1])
|
|
18
|
-
switch (match[2]) {
|
|
19
|
-
case "s": return value * 1000
|
|
20
|
-
case "m": return value * 60_000
|
|
21
|
-
case "h": return value * 3_600_000
|
|
22
|
-
default: throw new Error(`Invalid unit: ${match[2]}`)
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function createRateLimiter(
|
|
27
|
-
maxRequests: number,
|
|
28
|
-
window: string
|
|
29
|
-
): RateLimiter {
|
|
30
|
-
const windowMs = parseWindow(window)
|
|
31
|
-
const buckets = new Map<string, Bucket>()
|
|
32
|
-
|
|
33
|
-
// Cleanup old entries periodically
|
|
34
|
-
const CLEANUP_INTERVAL = Math.max(windowMs * 2, 60_000)
|
|
35
|
-
const cleanup = setInterval(() => {
|
|
36
|
-
const now = Date.now()
|
|
37
|
-
for (const [key, bucket] of buckets) {
|
|
38
|
-
if (now - bucket.lastRefill > windowMs * 2) {
|
|
39
|
-
buckets.delete(key)
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}, CLEANUP_INTERVAL)
|
|
43
|
-
|
|
44
|
-
// Don't prevent process from exiting
|
|
45
|
-
if (typeof cleanup === "object" && "unref" in cleanup) {
|
|
46
|
-
(cleanup as NodeJS.Timeout).unref()
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
check(key: string): { allowed: boolean; remaining: number; resetAt: number } {
|
|
51
|
-
const now = Date.now()
|
|
52
|
-
let bucket = buckets.get(key)
|
|
53
|
-
|
|
54
|
-
if (!bucket) {
|
|
55
|
-
bucket = { tokens: maxRequests, lastRefill: now }
|
|
56
|
-
buckets.set(key, bucket)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Refill tokens based on elapsed time
|
|
60
|
-
const elapsed = now - bucket.lastRefill
|
|
61
|
-
if (elapsed >= windowMs) {
|
|
62
|
-
bucket.tokens = maxRequests
|
|
63
|
-
bucket.lastRefill = now
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const resetAt = bucket.lastRefill + windowMs
|
|
67
|
-
|
|
68
|
-
if (bucket.tokens > 0) {
|
|
69
|
-
bucket.tokens--
|
|
70
|
-
return { allowed: true, remaining: bucket.tokens, resetAt }
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return { allowed: false, remaining: 0, resetAt }
|
|
74
|
-
},
|
|
75
|
-
|
|
76
|
-
reset(key: string): void {
|
|
77
|
-
buckets.delete(key)
|
|
78
|
-
},
|
|
79
|
-
}
|
|
80
|
-
}
|
package/src/server/action.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// Server Actions -- form mutations with progressive enhancement
|
|
2
|
-
// Usage in route:
|
|
3
|
-
// export const action = defineAction(async (ctx) => { ... })
|
|
4
|
-
//
|
|
5
|
-
// Client-side: submits via fetch, returns result
|
|
6
|
-
// SSR: handles POST form submissions with redirect
|
|
7
|
-
|
|
8
|
-
import type { Context } from "./middleware.ts"
|
|
9
|
-
|
|
10
|
-
export type ActionFn<T = unknown> = (ctx: Context) => Promise<T | Response>
|
|
11
|
-
|
|
12
|
-
export interface ActionResult<T = unknown> {
|
|
13
|
-
data?: T
|
|
14
|
-
error?: string
|
|
15
|
-
status: number
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function defineAction<T = unknown>(fn: ActionFn<T>): ActionFn<T> {
|
|
19
|
-
return fn
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export async function handleAction<T>(
|
|
23
|
-
actionFn: ActionFn<T>,
|
|
24
|
-
ctx: Context,
|
|
25
|
-
): Promise<ActionResult<T>> {
|
|
26
|
-
try {
|
|
27
|
-
const result = await actionFn(ctx)
|
|
28
|
-
if (result instanceof Response) {
|
|
29
|
-
return { status: result.status }
|
|
30
|
-
}
|
|
31
|
-
return { data: result, status: 200 }
|
|
32
|
-
} catch (err) {
|
|
33
|
-
const message = err instanceof Error ? err.message : String(err)
|
|
34
|
-
return { error: message, status: 500 }
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Parse form data from request into a typed object
|
|
39
|
-
export async function parseFormData(request: Request): Promise<Record<string, string>> {
|
|
40
|
-
const formData = await request.formData()
|
|
41
|
-
const result: Record<string, string> = {}
|
|
42
|
-
for (const [key, value] of formData.entries()) {
|
|
43
|
-
if (typeof value === "string") {
|
|
44
|
-
result[key] = value
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return result
|
|
48
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { CacheEntry, CacheStore } from "./cache.ts"
|
|
2
|
-
|
|
3
|
-
export function createNamespacedCacheStore(store: CacheStore, namespace: string): CacheStore {
|
|
4
|
-
const prefix = `${namespace}:`
|
|
5
|
-
return {
|
|
6
|
-
get: (key) => store.get(prefix + key),
|
|
7
|
-
set: async (key, entry) => { await store.set(prefix + key, entry) },
|
|
8
|
-
delete: async (key) => { await store.delete(prefix + key) },
|
|
9
|
-
clear: async () => {
|
|
10
|
-
const keys = await store.keys()
|
|
11
|
-
for await (const key of keys) {
|
|
12
|
-
if (key.startsWith(prefix)) await store.delete(key)
|
|
13
|
-
}
|
|
14
|
-
},
|
|
15
|
-
keys: async function* () {
|
|
16
|
-
const keys = await store.keys()
|
|
17
|
-
for await (const key of keys) {
|
|
18
|
-
if (!key.startsWith(prefix)) continue
|
|
19
|
-
yield key.slice(prefix.length)
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
}
|
|
23
|
-
}
|
package/src/server/cache.ts
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
// Route-level response cache with stale-while-revalidate
|
|
2
|
-
// Usage: export const cache = { maxAge: 60, staleWhileRevalidate: 300 }
|
|
3
|
-
|
|
4
|
-
import type { MiddlewareFn } from "./middleware.ts"
|
|
5
|
-
|
|
6
|
-
export interface CacheOptions {
|
|
7
|
-
maxAge: number // fresh cache TTL in seconds
|
|
8
|
-
staleWhileRevalidate?: number // serve stale while revalidating (seconds)
|
|
9
|
-
vary?: string[] // cache key varies by these headers
|
|
10
|
-
key?: (url: URL) => string // custom cache key generator
|
|
11
|
-
store?: CacheStore
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
type Awaitable<T> = T | Promise<T>
|
|
15
|
-
|
|
16
|
-
export interface CacheEntry {
|
|
17
|
-
body: string
|
|
18
|
-
headers: Record<string, string>
|
|
19
|
-
status: number
|
|
20
|
-
createdAt: number
|
|
21
|
-
revalidating?: boolean
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface CacheStore {
|
|
25
|
-
get(key: string): Awaitable<CacheEntry | undefined>
|
|
26
|
-
set(key: string, entry: CacheEntry): Awaitable<void>
|
|
27
|
-
delete(key: string): Awaitable<void>
|
|
28
|
-
clear(): Awaitable<void>
|
|
29
|
-
keys(): Awaitable<Iterable<string> | AsyncIterable<string>>
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function createMemoryCacheStore(): CacheStore {
|
|
33
|
-
const store = new Map<string, CacheEntry>()
|
|
34
|
-
return {
|
|
35
|
-
get: (key) => store.get(key),
|
|
36
|
-
set: (key, entry) => { store.set(key, entry) },
|
|
37
|
-
delete: (key) => { store.delete(key) },
|
|
38
|
-
clear: () => { store.clear() },
|
|
39
|
-
keys: () => store.keys(),
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const defaultCacheStore = createMemoryCacheStore()
|
|
44
|
-
|
|
45
|
-
function buildKey(url: URL, vary: string[], request: Request, customKey?: (url: URL) => string): string {
|
|
46
|
-
const base = customKey ? customKey(url) : url.pathname + url.search
|
|
47
|
-
if (vary.length === 0) return base
|
|
48
|
-
const varyParts = vary.map((h) => `${h}=${request.headers.get(h) ?? ""}`).join("&")
|
|
49
|
-
return `${base}?__vary=${varyParts}`
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function routeCache(options: CacheOptions): MiddlewareFn {
|
|
53
|
-
const { maxAge, staleWhileRevalidate = 0, vary = [], key: customKey, store = defaultCacheStore } = options
|
|
54
|
-
|
|
55
|
-
return async (ctx, next) => {
|
|
56
|
-
if (ctx.request.method !== "GET") return next()
|
|
57
|
-
|
|
58
|
-
const cacheKey = buildKey(ctx.url, vary, ctx.request, customKey)
|
|
59
|
-
const entry = await store.get(cacheKey)
|
|
60
|
-
const now = Date.now()
|
|
61
|
-
|
|
62
|
-
if (entry) {
|
|
63
|
-
const age = (now - entry.createdAt) / 1000
|
|
64
|
-
// Fresh — serve from cache
|
|
65
|
-
if (age < maxAge) {
|
|
66
|
-
return new Response(entry.body, {
|
|
67
|
-
status: entry.status,
|
|
68
|
-
headers: { ...entry.headers, "X-Cache": "HIT", "Age": String(Math.floor(age)) },
|
|
69
|
-
})
|
|
70
|
-
}
|
|
71
|
-
// Stale but within revalidation window — serve stale, revalidate in background
|
|
72
|
-
if (age < maxAge + staleWhileRevalidate && !entry.revalidating) {
|
|
73
|
-
entry.revalidating = true
|
|
74
|
-
revalidate(cacheKey, store, next)
|
|
75
|
-
return new Response(entry.body, {
|
|
76
|
-
status: entry.status,
|
|
77
|
-
headers: { ...entry.headers, "X-Cache": "STALE", "Age": String(Math.floor(age)) },
|
|
78
|
-
})
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Miss — fetch and cache
|
|
83
|
-
const response = await next()
|
|
84
|
-
if (response.status === 200) {
|
|
85
|
-
const body = await response.text()
|
|
86
|
-
const headers: Record<string, string> = {}
|
|
87
|
-
response.headers.forEach((v, k) => { headers[k] = v })
|
|
88
|
-
await store.set(cacheKey, { body, headers, status: response.status, createdAt: now })
|
|
89
|
-
return new Response(body, {
|
|
90
|
-
status: response.status,
|
|
91
|
-
headers: { ...headers, "X-Cache": "MISS" },
|
|
92
|
-
})
|
|
93
|
-
}
|
|
94
|
-
return response
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
async function revalidate(key: string, store: CacheStore, next: () => Promise<Response>): Promise<void> {
|
|
99
|
-
try {
|
|
100
|
-
const response = await next()
|
|
101
|
-
if (response.status === 200) {
|
|
102
|
-
const body = await response.text()
|
|
103
|
-
const headers: Record<string, string> = {}
|
|
104
|
-
response.headers.forEach((v, k) => { headers[k] = v })
|
|
105
|
-
await store.set(key, { body, headers, status: response.status, createdAt: Date.now() })
|
|
106
|
-
}
|
|
107
|
-
} catch {
|
|
108
|
-
// revalidation failed, stale entry stays
|
|
109
|
-
const entry = await store.get(key)
|
|
110
|
-
if (entry) entry.revalidating = false
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/** Invalidate cached entry by path */
|
|
115
|
-
export async function invalidateCache(path: string): Promise<void> {
|
|
116
|
-
const keys = await defaultCacheStore.keys()
|
|
117
|
-
for await (const key of keys) {
|
|
118
|
-
if (key.startsWith(path)) await defaultCacheStore.delete(key)
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/** Clear all cached entries */
|
|
123
|
-
export async function clearCache(): Promise<void> {
|
|
124
|
-
await defaultCacheStore.clear()
|
|
125
|
-
}
|
package/src/server/compress.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
// Response compression middleware — gzip/deflate
|
|
2
|
-
// Uses Web Streams API (native in Bun)
|
|
3
|
-
|
|
4
|
-
import type { MiddlewareFn } from "./middleware.ts"
|
|
5
|
-
|
|
6
|
-
const COMPRESSIBLE_TYPES = new Set([
|
|
7
|
-
"text/html",
|
|
8
|
-
"text/css",
|
|
9
|
-
"text/javascript",
|
|
10
|
-
"application/javascript",
|
|
11
|
-
"application/json",
|
|
12
|
-
"text/xml",
|
|
13
|
-
"application/xml",
|
|
14
|
-
"image/svg+xml",
|
|
15
|
-
])
|
|
16
|
-
|
|
17
|
-
function isCompressible(contentType: string | null): boolean {
|
|
18
|
-
if (!contentType) return false
|
|
19
|
-
const type = contentType.split(";")[0]!.trim()
|
|
20
|
-
return COMPRESSIBLE_TYPES.has(type)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function compress(): MiddlewareFn {
|
|
24
|
-
return async (_ctx, next) => {
|
|
25
|
-
const response = await next()
|
|
26
|
-
const contentType = response.headers.get("content-type")
|
|
27
|
-
|
|
28
|
-
if (!isCompressible(contentType)) return response
|
|
29
|
-
if (response.headers.has("content-encoding")) return response
|
|
30
|
-
if (!response.body) return response
|
|
31
|
-
|
|
32
|
-
const acceptEncoding = _ctx.request.headers.get("accept-encoding") ?? ""
|
|
33
|
-
|
|
34
|
-
if (acceptEncoding.includes("gzip")) {
|
|
35
|
-
const compressed = response.body.pipeThrough(new CompressionStream("gzip"))
|
|
36
|
-
const headers = new Headers(response.headers)
|
|
37
|
-
headers.set("Content-Encoding", "gzip")
|
|
38
|
-
headers.delete("Content-Length")
|
|
39
|
-
return new Response(compressed, {
|
|
40
|
-
status: response.status,
|
|
41
|
-
statusText: response.statusText,
|
|
42
|
-
headers,
|
|
43
|
-
})
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (acceptEncoding.includes("deflate")) {
|
|
47
|
-
const compressed = response.body.pipeThrough(new CompressionStream("deflate"))
|
|
48
|
-
const headers = new Headers(response.headers)
|
|
49
|
-
headers.set("Content-Encoding", "deflate")
|
|
50
|
-
headers.delete("Content-Length")
|
|
51
|
-
return new Response(compressed, {
|
|
52
|
-
status: response.status,
|
|
53
|
-
statusText: response.statusText,
|
|
54
|
-
headers,
|
|
55
|
-
})
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return response
|
|
59
|
-
}
|
|
60
|
-
}
|
package/src/server/etag.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// ETag support for static file serving
|
|
2
|
-
// Generates weak ETags based on file size + modification time
|
|
3
|
-
|
|
4
|
-
import { stat } from "node:fs/promises"
|
|
5
|
-
|
|
6
|
-
export function generateETag(size: number, mtimeMs: number): string {
|
|
7
|
-
return `W/"${size.toString(16)}-${Math.floor(mtimeMs).toString(16)}"`
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export async function fileETag(filePath: string): Promise<string | null> {
|
|
11
|
-
try {
|
|
12
|
-
const s = await stat(filePath)
|
|
13
|
-
return generateETag(s.size, s.mtimeMs)
|
|
14
|
-
} catch {
|
|
15
|
-
return null
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function isNotModified(request: Request, etag: string): boolean {
|
|
20
|
-
const ifNoneMatch = request.headers.get("if-none-match")
|
|
21
|
-
if (!ifNoneMatch) return false
|
|
22
|
-
return ifNoneMatch.split(",").some((t) => t.trim() === etag)
|
|
23
|
-
}
|