@bajustone/fortress 1.0.0-rc.1
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/CHANGELOG.md +1011 -0
- package/LICENSE +21 -0
- package/README.md +760 -0
- package/SECURITY.md +197 -0
- package/bin/fortress.ts +667 -0
- package/dist/auth-service-BcyQ2PuZ.d.cts +307 -0
- package/dist/auth-service-BkzZkWfH.d.ts +307 -0
- package/dist/config-B2366s_G.d.ts +665 -0
- package/dist/config-GtlVt6ZD.d.cts +665 -0
- package/dist/convert-routes-BLCQT57f.d.ts +72 -0
- package/dist/convert-routes-BdMvP2_X.d.cts +72 -0
- package/dist/crypto.cjs +61 -0
- package/dist/crypto.d.cts +36 -0
- package/dist/crypto.d.ts +36 -0
- package/dist/crypto.js +35 -0
- package/dist/drift-BT1wtMDJ.d.cts +22 -0
- package/dist/drift-k9LiYpRP.d.ts +22 -0
- package/dist/drizzle/pg.cjs +481 -0
- package/dist/drizzle/pg.d.cts +15 -0
- package/dist/drizzle/pg.d.ts +15 -0
- package/dist/drizzle/pg.js +454 -0
- package/dist/drizzle.cjs +1442 -0
- package/dist/drizzle.d.cts +85 -0
- package/dist/drizzle.d.ts +85 -0
- package/dist/drizzle.js +1411 -0
- package/dist/express.cjs +1357 -0
- package/dist/express.d.cts +333 -0
- package/dist/express.d.ts +333 -0
- package/dist/express.js +1314 -0
- package/dist/fetcher.cjs +77 -0
- package/dist/fetcher.d.cts +7 -0
- package/dist/fetcher.d.ts +7 -0
- package/dist/fetcher.js +41 -0
- package/dist/fortress-BmSvFfqK.d.cts +1089 -0
- package/dist/fortress-uA-_cheR.d.ts +1089 -0
- package/dist/hono.cjs +1530 -0
- package/dist/hono.d.cts +514 -0
- package/dist/hono.d.ts +514 -0
- package/dist/hono.js +1483 -0
- package/dist/index-CxEkfCA0.d.cts +77 -0
- package/dist/index-CxEkfCA0.d.ts +77 -0
- package/dist/index-D054pcb-.d.cts +146 -0
- package/dist/index-jAMbbUAY.d.ts +146 -0
- package/dist/index.cjs +9046 -0
- package/dist/index.d.cts +717 -0
- package/dist/index.d.ts +717 -0
- package/dist/index.js +8935 -0
- package/dist/jwt.cjs +255 -0
- package/dist/jwt.d.cts +90 -0
- package/dist/jwt.d.ts +90 -0
- package/dist/jwt.js +227 -0
- package/dist/otel.cjs +108 -0
- package/dist/otel.d.cts +62 -0
- package/dist/otel.d.ts +62 -0
- package/dist/otel.js +73 -0
- package/dist/plugins/account-lockout.cjs +322 -0
- package/dist/plugins/account-lockout.d.cts +42 -0
- package/dist/plugins/account-lockout.d.ts +42 -0
- package/dist/plugins/account-lockout.js +295 -0
- package/dist/plugins/admin.cjs +2378 -0
- package/dist/plugins/admin.d.cts +72 -0
- package/dist/plugins/admin.d.ts +72 -0
- package/dist/plugins/admin.js +2351 -0
- package/dist/plugins/api-key.cjs +792 -0
- package/dist/plugins/api-key.d.cts +121 -0
- package/dist/plugins/api-key.d.ts +121 -0
- package/dist/plugins/api-key.js +765 -0
- package/dist/plugins/audit-log.cjs +493 -0
- package/dist/plugins/audit-log.d.cts +86 -0
- package/dist/plugins/audit-log.d.ts +86 -0
- package/dist/plugins/audit-log.js +468 -0
- package/dist/plugins/data-isolation.cjs +211 -0
- package/dist/plugins/data-isolation.d.cts +49 -0
- package/dist/plugins/data-isolation.d.ts +49 -0
- package/dist/plugins/data-isolation.js +186 -0
- package/dist/plugins/email-verification.cjs +273 -0
- package/dist/plugins/email-verification.d.cts +44 -0
- package/dist/plugins/email-verification.d.ts +44 -0
- package/dist/plugins/email-verification.js +246 -0
- package/dist/plugins/magic-link.cjs +231 -0
- package/dist/plugins/magic-link.d.cts +39 -0
- package/dist/plugins/magic-link.d.ts +39 -0
- package/dist/plugins/magic-link.js +204 -0
- package/dist/plugins/oauth.cjs +1696 -0
- package/dist/plugins/oauth.d.cts +406 -0
- package/dist/plugins/oauth.d.ts +406 -0
- package/dist/plugins/oauth.js +1669 -0
- package/dist/plugins/openapi.cjs +1185 -0
- package/dist/plugins/openapi.d.cts +6 -0
- package/dist/plugins/openapi.d.ts +6 -0
- package/dist/plugins/openapi.js +1158 -0
- package/dist/plugins/rate-limit/express.cjs +55 -0
- package/dist/plugins/rate-limit/express.d.cts +64 -0
- package/dist/plugins/rate-limit/express.d.ts +64 -0
- package/dist/plugins/rate-limit/express.js +30 -0
- package/dist/plugins/rate-limit/hono.cjs +51 -0
- package/dist/plugins/rate-limit/hono.d.cts +59 -0
- package/dist/plugins/rate-limit/hono.d.ts +59 -0
- package/dist/plugins/rate-limit/hono.js +26 -0
- package/dist/plugins/rate-limit/sveltekit.cjs +49 -0
- package/dist/plugins/rate-limit/sveltekit.d.cts +59 -0
- package/dist/plugins/rate-limit/sveltekit.d.ts +59 -0
- package/dist/plugins/rate-limit/sveltekit.js +24 -0
- package/dist/plugins/rate-limit.cjs +354 -0
- package/dist/plugins/rate-limit.d.cts +140 -0
- package/dist/plugins/rate-limit.d.ts +140 -0
- package/dist/plugins/rate-limit.js +325 -0
- package/dist/plugins/social-login.cjs +905 -0
- package/dist/plugins/social-login.d.cts +114 -0
- package/dist/plugins/social-login.d.ts +114 -0
- package/dist/plugins/social-login.js +880 -0
- package/dist/plugins/tenancy.cjs +780 -0
- package/dist/plugins/tenancy.d.cts +108 -0
- package/dist/plugins/tenancy.d.ts +108 -0
- package/dist/plugins/tenancy.js +753 -0
- package/dist/plugins/two-factor.cjs +555 -0
- package/dist/plugins/two-factor.d.cts +67 -0
- package/dist/plugins/two-factor.d.ts +67 -0
- package/dist/plugins/two-factor.js +526 -0
- package/dist/plugins/webauthn.cjs +786 -0
- package/dist/plugins/webauthn.d.cts +72 -0
- package/dist/plugins/webauthn.d.ts +72 -0
- package/dist/plugins/webauthn.js +766 -0
- package/dist/plugins/webhook.cjs +819 -0
- package/dist/plugins/webhook.d.cts +254 -0
- package/dist/plugins/webhook.d.ts +254 -0
- package/dist/plugins/webhook.js +789 -0
- package/dist/protect-D1v_0upK.d.cts +123 -0
- package/dist/protect-DsxV_-dJ.d.ts +123 -0
- package/dist/sveltekit.cjs +1258 -0
- package/dist/sveltekit.d.cts +420 -0
- package/dist/sveltekit.d.ts +420 -0
- package/dist/sveltekit.js +1207 -0
- package/dist/testing.cjs +4294 -0
- package/dist/testing.d.cts +197 -0
- package/dist/testing.d.ts +197 -0
- package/dist/testing.js +4264 -0
- package/dist/types-et0R8tsC.d.cts +217 -0
- package/dist/types-et0R8tsC.d.ts +217 -0
- package/docs/adapter-typed-helpers.md +192 -0
- package/docs/admin-recipes.md +227 -0
- package/docs/architecture.md +434 -0
- package/docs/ci/github-actions.yml +59 -0
- package/docs/ci.md +109 -0
- package/docs/compatibility.md +115 -0
- package/docs/deployment.md +305 -0
- package/docs/hardening.md +118 -0
- package/docs/host-owned-routes.md +154 -0
- package/docs/migrations/0001-schema-version.md +54 -0
- package/docs/migrations/0002-initial-schema.md +84 -0
- package/docs/migrations/upgrade-guide.md +160 -0
- package/docs/observability.md +394 -0
- package/docs/plugins/account-lockout.md +131 -0
- package/docs/plugins/admin.md +402 -0
- package/docs/plugins/api-key.md +327 -0
- package/docs/plugins/audit-log.md +261 -0
- package/docs/plugins/data-isolation.md +186 -0
- package/docs/plugins/email-verification.md +121 -0
- package/docs/plugins/magic-link.md +123 -0
- package/docs/plugins/oauth.md +544 -0
- package/docs/plugins/openapi.md +250 -0
- package/docs/plugins/rate-limit.md +223 -0
- package/docs/plugins/social-login.md +337 -0
- package/docs/plugins/tenancy.md +122 -0
- package/docs/plugins/two-factor.md +191 -0
- package/docs/plugins/webauthn.md +188 -0
- package/docs/plugins/webhook.md +242 -0
- package/docs/policy-as-code.md +156 -0
- package/docs/route-manifest.md +46 -0
- package/docs/security.md +261 -0
- package/docs/threat-model.md +161 -0
- package/examples/README.md +119 -0
- package/examples/express-app/index.ts +747 -0
- package/examples/hono-app/docker-compose.yml +14 -0
- package/examples/hono-app/index.ts +1009 -0
- package/examples/policy/fortress.policy.json +47 -0
- package/examples/sveltekit-app/README.md +125 -0
- package/examples/sveltekit-app/src/app.d.ts +16 -0
- package/examples/sveltekit-app/src/hooks.server.ts +23 -0
- package/examples/sveltekit-app/src/lib/server/fortress.ts +81 -0
- package/examples/sveltekit-app/src/routes/api/echo/[id]/+server.ts +32 -0
- package/examples/sveltekit-app/src/routes/api/fortress/[...path]/+server.ts +15 -0
- package/examples/sveltekit-app/src/routes/dashboard/+page.server.ts +20 -0
- package/examples/sveltekit-app/src/routes/login/+page.server.ts +48 -0
- package/examples/sveltekit-app/src/routes/oauth/consent/+page.server.ts +69 -0
- package/examples/sveltekit-app/src/routes/oauth/consent/+page.svelte +83 -0
- package/migrations/pg/0001_schema_version.down.sql +2 -0
- package/migrations/pg/0001_schema_version.sql +8 -0
- package/migrations/pg/0002_initial_schema.down.sql +36 -0
- package/migrations/pg/0002_initial_schema.sql +376 -0
- package/migrations/pg/0003_auth_continuation.down.sql +6 -0
- package/migrations/pg/0003_auth_continuation.sql +30 -0
- package/migrations/pg/0004_tenant_default_unique.down.sql +1 -0
- package/migrations/pg/0004_tenant_default_unique.sql +14 -0
- package/migrations/pg/0005_hot_indexes_timestamptz.down.sql +71 -0
- package/migrations/pg/0005_hot_indexes_timestamptz.sql +71 -0
- package/migrations/pg/0006_canonical_email.down.sql +3 -0
- package/migrations/pg/0006_canonical_email.sql +8 -0
- package/migrations/pg/0007_audit_chain_anchor.down.sql +1 -0
- package/migrations/pg/0007_audit_chain_anchor.sql +8 -0
- package/migrations/pg/0008_two_factor_hardening.down.sql +8 -0
- package/migrations/pg/0008_two_factor_hardening.sql +8 -0
- package/migrations/pg/0009_encrypt_totp_secrets.down.sql +2 -0
- package/migrations/pg/0009_encrypt_totp_secrets.sql +5 -0
- package/migrations/pg/0010_bigint_append_only_ids.down.sql +2 -0
- package/migrations/pg/0010_bigint_append_only_ids.sql +23 -0
- package/migrations/sqlite/0001_schema_version.down.sql +2 -0
- package/migrations/sqlite/0001_schema_version.sql +8 -0
- package/migrations/sqlite/0002_initial_schema.down.sql +36 -0
- package/migrations/sqlite/0002_initial_schema.sql +376 -0
- package/migrations/sqlite/0003_auth_continuation.down.sql +27 -0
- package/migrations/sqlite/0003_auth_continuation.sql +45 -0
- package/migrations/sqlite/0004_tenant_default_unique.down.sql +1 -0
- package/migrations/sqlite/0004_tenant_default_unique.sql +13 -0
- package/migrations/sqlite/0005_hot_indexes_timestamptz.down.sql +10 -0
- package/migrations/sqlite/0005_hot_indexes_timestamptz.sql +10 -0
- package/migrations/sqlite/0006_canonical_email.down.sql +3 -0
- package/migrations/sqlite/0006_canonical_email.sql +8 -0
- package/migrations/sqlite/0007_audit_chain_anchor.down.sql +1 -0
- package/migrations/sqlite/0007_audit_chain_anchor.sql +8 -0
- package/migrations/sqlite/0008_two_factor_hardening.down.sql +14 -0
- package/migrations/sqlite/0008_two_factor_hardening.sql +7 -0
- package/migrations/sqlite/0009_encrypt_totp_secrets.down.sql +2 -0
- package/migrations/sqlite/0009_encrypt_totp_secrets.sql +5 -0
- package/migrations/sqlite/0010_bigint_append_only_ids.down.sql +1 -0
- package/migrations/sqlite/0010_bigint_append_only_ids.sql +2 -0
- package/package.json +398 -0
- package/src/adapters/database/index.ts +63 -0
- package/src/adapters/database/types.ts +22 -0
- package/src/changelog-script.test.ts +21 -0
- package/src/cli.test.ts +79 -0
- package/src/core/auth/auth-admin.test.ts +247 -0
- package/src/core/auth/auth-endpoints.ts +558 -0
- package/src/core/auth/auth-observer.test.ts +191 -0
- package/src/core/auth/auth-service.ts +1464 -0
- package/src/core/auth/email.test.ts +17 -0
- package/src/core/auth/email.ts +11 -0
- package/src/core/auth/hooks.test.ts +251 -0
- package/src/core/auth/impersonation.test.ts +179 -0
- package/src/core/auth/jwt.test.ts +184 -0
- package/src/core/auth/jwt.ts +239 -0
- package/src/core/auth/login-timing.test.ts +77 -0
- package/src/core/auth/password-policy.test.ts +253 -0
- package/src/core/auth/password-policy.ts +220 -0
- package/src/core/auth/password.test.ts +42 -0
- package/src/core/auth/password.ts +62 -0
- package/src/core/auth/post-auth-gate.test.ts +258 -0
- package/src/core/auth/post-auth-gate.ts +228 -0
- package/src/core/auth/refresh-token.test.ts +86 -0
- package/src/core/auth/refresh-token.ts +105 -0
- package/src/core/auth/timing-safe.ts +23 -0
- package/src/core/config.ts +212 -0
- package/src/core/endpoint.ts +149 -0
- package/src/core/errors.ts +199 -0
- package/src/core/fetcher-interop.test.ts +106 -0
- package/src/core/fortress.test.ts +354 -0
- package/src/core/fortress.ts +550 -0
- package/src/core/http/call.test.ts +148 -0
- package/src/core/http/call.ts +149 -0
- package/src/core/http/cookie-serialize.test.ts +198 -0
- package/src/core/http/cookie-serialize.ts +107 -0
- package/src/core/http/csrf.test.ts +140 -0
- package/src/core/http/csrf.ts +173 -0
- package/src/core/http/dispatch.ts +652 -0
- package/src/core/http/error-response.test.ts +69 -0
- package/src/core/http/error-response.ts +93 -0
- package/src/core/http/fortress-rbac.test.ts +43 -0
- package/src/core/http/fortress-rbac.ts +127 -0
- package/src/core/http/handle-request.test.ts +441 -0
- package/src/core/http/handle-request.ts +354 -0
- package/src/core/http/match.test.ts +122 -0
- package/src/core/http/match.ts +126 -0
- package/src/core/http/outbound.test.ts +34 -0
- package/src/core/http/outbound.ts +105 -0
- package/src/core/http/plugin-middleware.ts +67 -0
- package/src/core/http/principal.test.ts +345 -0
- package/src/core/http/principal.ts +86 -0
- package/src/core/http/protect.test.ts +220 -0
- package/src/core/http/protect.ts +394 -0
- package/src/core/http/token-extraction.test.ts +59 -0
- package/src/core/http/token-extraction.ts +53 -0
- package/src/core/iam/explain.test.ts +177 -0
- package/src/core/iam/explain.ts +302 -0
- package/src/core/iam/iam-endpoints.ts +779 -0
- package/src/core/iam/iam-service.test.ts +829 -0
- package/src/core/iam/iam-service.ts +1137 -0
- package/src/core/iam/permission-cache.test.ts +115 -0
- package/src/core/iam/permission-cache.ts +71 -0
- package/src/core/iam/permission-check-observer.test.ts +90 -0
- package/src/core/iam/permission-evaluator.test.ts +291 -0
- package/src/core/iam/permission-evaluator.ts +198 -0
- package/src/core/iam/permission-sync.test.ts +166 -0
- package/src/core/iam/permission-sync.ts +192 -0
- package/src/core/iam/resource-sync.test.ts +70 -0
- package/src/core/iam/resource-sync.ts +182 -0
- package/src/core/iam/service-account-http.test.ts +529 -0
- package/src/core/iam/service-account.test.ts +282 -0
- package/src/core/internal-adapter.test.ts +389 -0
- package/src/core/internal-adapter.ts +435 -0
- package/src/core/json-schema.ts +50 -0
- package/src/core/manifest/__snapshots__/route-manifest.test.ts.snap +192 -0
- package/src/core/manifest/drift.ts +103 -0
- package/src/core/manifest/route-manifest.test.ts +142 -0
- package/src/core/manifest/route-manifest.ts +154 -0
- package/src/core/migrate.test.ts +72 -0
- package/src/core/migrations/engine.test.ts +308 -0
- package/src/core/migrations/engine.ts +548 -0
- package/src/core/migrations/migrations.ts +1771 -0
- package/src/core/migrations/pg-migration.integration-test.ts +353 -0
- package/src/core/migrations/upgrade-fixture.test.ts +378 -0
- package/src/core/observability/db-instrumentation.ts +205 -0
- package/src/core/observability/listener-list.test.ts +124 -0
- package/src/core/observability/listener-list.ts +73 -0
- package/src/core/observability/logger.test.ts +43 -0
- package/src/core/observability/logger.ts +49 -0
- package/src/core/observability/spans.test.ts +193 -0
- package/src/core/observability/types.ts +80 -0
- package/src/core/openapi-drift.test.ts +41 -0
- package/src/core/openapi.ts +47 -0
- package/src/core/plugin-methods-map.ts +75 -0
- package/src/core/plugin-runner.test.ts +233 -0
- package/src/core/plugin-runner.ts +276 -0
- package/src/core/plugin.ts +210 -0
- package/src/core/policy/apply.ts +272 -0
- package/src/core/policy/diff.ts +288 -0
- package/src/core/policy/loader.test.ts +63 -0
- package/src/core/policy/loader.ts +214 -0
- package/src/core/policy/policy.test.ts +232 -0
- package/src/core/policy/types.ts +105 -0
- package/src/core/schema-builder.test.ts +660 -0
- package/src/core/schema-builder.ts +881 -0
- package/src/core/standard-schema.ts +56 -0
- package/src/core/types.ts +258 -0
- package/src/core/validation.test.ts +195 -0
- package/src/core/validation.ts +192 -0
- package/src/drizzle/adapter.test.ts +425 -0
- package/src/drizzle/adapter.ts +474 -0
- package/src/drizzle/index.ts +31 -0
- package/src/drizzle/pg/adapter.integration-test.ts +456 -0
- package/src/drizzle/pg/index.ts +13 -0
- package/src/drizzle/pg/pg.integration-test.ts +1539 -0
- package/src/drizzle/pg/schema.ts +539 -0
- package/src/drizzle/pg-error-map.test.ts +218 -0
- package/src/drizzle/pg-error-map.ts +151 -0
- package/src/drizzle/schema.ts +544 -0
- package/src/drizzle/sqlite-serialization.test.ts +106 -0
- package/src/express/express-api-key-user-routes.test.ts +241 -0
- package/src/express/express.test.ts +442 -0
- package/src/express/handle.ts +191 -0
- package/src/express/index.ts +62 -0
- package/src/express/middleware.ts +551 -0
- package/src/express/protect.ts +154 -0
- package/src/express/validated.test.ts +86 -0
- package/src/express/validated.ts +99 -0
- package/src/fetcher/index.ts +81 -0
- package/src/hono/convert-routes.test.ts +220 -0
- package/src/hono/convert-routes.ts +196 -0
- package/src/hono/converters.test.ts +50 -0
- package/src/hono/converters.ts +43 -0
- package/src/hono/handle.ts +79 -0
- package/src/hono/helpers.ts +2 -0
- package/src/hono/hono-api-key-user-routes.test.ts +225 -0
- package/src/hono/hono-handlers.test.ts +861 -0
- package/src/hono/hono.test.ts +454 -0
- package/src/hono/index.ts +101 -0
- package/src/hono/middleware/auth.ts +236 -0
- package/src/hono/middleware/auth.types.test.ts +94 -0
- package/src/hono/middleware/csrf.test.ts +127 -0
- package/src/hono/middleware/csrf.ts +68 -0
- package/src/hono/middleware/error-handler.ts +12 -0
- package/src/hono/middleware/plugin-middleware.ts +35 -0
- package/src/hono/middleware/rbac.ts +131 -0
- package/src/hono/middleware/security-headers.test.ts +88 -0
- package/src/hono/middleware/security-headers.ts +68 -0
- package/src/hono/openapi.ts +237 -0
- package/src/hono/protect.ts +87 -0
- package/src/hono/validated.test.ts +123 -0
- package/src/hono/validated.ts +62 -0
- package/src/index.ts +309 -0
- package/src/integration.test.ts +718 -0
- package/src/internal/changelog.ts +56 -0
- package/src/otel/index.ts +158 -0
- package/src/otel/otel-types.test.ts +35 -0
- package/src/otel/otel.test.ts +235 -0
- package/src/plugins/account-lockout/account-lockout.test.ts +367 -0
- package/src/plugins/account-lockout/index.ts +267 -0
- package/src/plugins/admin/admin-api-key.test.ts +438 -0
- package/src/plugins/admin/index.ts +1612 -0
- package/src/plugins/api-key/api-key.test.ts +684 -0
- package/src/plugins/api-key/core.ts +336 -0
- package/src/plugins/api-key/index.ts +315 -0
- package/src/plugins/audit-log/audit-log.test.ts +749 -0
- package/src/plugins/audit-log/index.ts +680 -0
- package/src/plugins/data-isolation/data-isolation.test.ts +197 -0
- package/src/plugins/data-isolation/index.ts +157 -0
- package/src/plugins/email-verification/email-verification.test.ts +199 -0
- package/src/plugins/email-verification/index.ts +190 -0
- package/src/plugins/magic-link/index.ts +129 -0
- package/src/plugins/magic-link/magic-link.test.ts +156 -0
- package/src/plugins/oauth/id-token.ts +86 -0
- package/src/plugins/oauth/index.ts +2145 -0
- package/src/plugins/oauth/jwks.test.ts +32 -0
- package/src/plugins/oauth/jwks.ts +182 -0
- package/src/plugins/oauth/oauth.test.ts +2220 -0
- package/src/plugins/oauth/pkce.ts +58 -0
- package/src/plugins/openapi/index.ts +298 -0
- package/src/plugins/openapi/openapi.test.ts +425 -0
- package/src/plugins/openapi/spec-builder.ts +287 -0
- package/src/plugins/rate-limit/express.test.ts +89 -0
- package/src/plugins/rate-limit/express.ts +86 -0
- package/src/plugins/rate-limit/hono.test.ts +60 -0
- package/src/plugins/rate-limit/hono.ts +74 -0
- package/src/plugins/rate-limit/index.ts +383 -0
- package/src/plugins/rate-limit/memory-store.ts +61 -0
- package/src/plugins/rate-limit/rate-limit.test.ts +756 -0
- package/src/plugins/rate-limit/sveltekit.test.ts +58 -0
- package/src/plugins/rate-limit/sveltekit.ts +66 -0
- package/src/plugins/social-login/index.ts +715 -0
- package/src/plugins/social-login/providers/apple.ts +34 -0
- package/src/plugins/social-login/providers/discord.ts +26 -0
- package/src/plugins/social-login/providers/github.ts +54 -0
- package/src/plugins/social-login/providers/google.ts +23 -0
- package/src/plugins/social-login/providers/index.ts +22 -0
- package/src/plugins/social-login/providers/microsoft.ts +35 -0
- package/src/plugins/social-login/providers/oidc.ts +37 -0
- package/src/plugins/social-login/providers/providers.test.ts +211 -0
- package/src/plugins/social-login/social-login.test.ts +675 -0
- package/src/plugins/social-login/types.ts +80 -0
- package/src/plugins/tenancy/index.ts +544 -0
- package/src/plugins/tenancy/tenancy.test.ts +323 -0
- package/src/plugins/two-factor/index.ts +569 -0
- package/src/plugins/two-factor/two-factor.test.ts +235 -0
- package/src/plugins/webauthn/index.ts +554 -0
- package/src/plugins/webauthn/webauthn.test.ts +472 -0
- package/src/plugins/webhook/builtin-events.ts +29 -0
- package/src/plugins/webhook/delivery.test.ts +51 -0
- package/src/plugins/webhook/delivery.ts +154 -0
- package/src/plugins/webhook/hooks.ts +89 -0
- package/src/plugins/webhook/index.ts +445 -0
- package/src/plugins/webhook/queue/database.ts +67 -0
- package/src/plugins/webhook/queue/in-memory.test.ts +48 -0
- package/src/plugins/webhook/queue/in-memory.ts +71 -0
- package/src/plugins/webhook/queue/types.ts +51 -0
- package/src/plugins/webhook/registry.test.ts +48 -0
- package/src/plugins/webhook/registry.ts +64 -0
- package/src/plugins/webhook/signing.ts +45 -0
- package/src/plugins/webhook/ssrf.ts +198 -0
- package/src/plugins/webhook/types.ts +138 -0
- package/src/plugins/webhook/webhook.test.ts +324 -0
- package/src/sveltekit/actions.ts +233 -0
- package/src/sveltekit/catch-all.ts +43 -0
- package/src/sveltekit/cookies.ts +136 -0
- package/src/sveltekit/handle.ts +356 -0
- package/src/sveltekit/helpers.ts +69 -0
- package/src/sveltekit/index.ts +74 -0
- package/src/sveltekit/protect.ts +80 -0
- package/src/sveltekit/sveltekit-types.test.ts +31 -0
- package/src/sveltekit/sveltekit.test.ts +799 -0
- package/src/sveltekit/types.ts +134 -0
- package/src/sveltekit/validated.test.ts +117 -0
- package/src/sveltekit/validated.ts +78 -0
- package/src/testing/adapter-conformance.test.ts +408 -0
- package/src/testing/checks.test.ts +124 -0
- package/src/testing/checks.ts +304 -0
- package/src/testing/index.ts +107 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SvelteKit form-action helpers for the common auth flows.
|
|
3
|
+
*
|
|
4
|
+
* Use these in `+page.server.ts` to wire `<form method="POST">` to
|
|
5
|
+
* fortress's auth methods. They handle:
|
|
6
|
+
*
|
|
7
|
+
* - parsing form data
|
|
8
|
+
* - calling `fortress.auth.*`
|
|
9
|
+
* - setting cookies via `event.cookies.set` (so SvelteKit's `Set-Cookie`
|
|
10
|
+
* handling sees them, not just the browser)
|
|
11
|
+
* - returning `fail(...)` on `FortressError`
|
|
12
|
+
* - throwing a `redirect(...)` on success when `redirectTo` is supplied
|
|
13
|
+
*
|
|
14
|
+
* Redirects and failures use SvelteKit's real `redirect()` / `fail()`
|
|
15
|
+
* primitives, so the action runtime recognizes them without casts or
|
|
16
|
+
* raw-Response 500s.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* // src/routes/login/+page.server.ts
|
|
21
|
+
* import { fortressActions } from '@bajustone/fortress/sveltekit';
|
|
22
|
+
* import { fortress } from '$lib/server/fortress';
|
|
23
|
+
*
|
|
24
|
+
* export const actions = {
|
|
25
|
+
* default: fortressActions.login(fortress, { redirectTo: '/dashboard' }),
|
|
26
|
+
* };
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import type { ActionFailure } from '@sveltejs/kit';
|
|
31
|
+
import type { Fortress } from '../core/fortress';
|
|
32
|
+
import type { AuthChallenge, CreateUserInput, LoginIdentifierType } from '../core/types';
|
|
33
|
+
import type { SvelteKitAction, SvelteKitRequestEvent } from './types';
|
|
34
|
+
import { FortressError } from '../core/errors';
|
|
35
|
+
import { clearAuthCookies, setAuthCookies } from './cookies';
|
|
36
|
+
|
|
37
|
+
/** Shape returned by form-action helpers when something goes wrong. */
|
|
38
|
+
export type FortressActionFailure = ActionFailure<{ error: string; code?: string }>;
|
|
39
|
+
|
|
40
|
+
/** Discriminated result returned when no `redirectTo` is configured. */
|
|
41
|
+
export type FortressActionSuccess
|
|
42
|
+
= | { success: true; pending: false }
|
|
43
|
+
| { success: true; pending: true; challenge: AuthChallenge };
|
|
44
|
+
|
|
45
|
+
/** Common options for the auth-issuing helpers. */
|
|
46
|
+
export interface FortressActionOptions {
|
|
47
|
+
/**
|
|
48
|
+
* On success, throw a redirect to this path. SvelteKit's action runtime
|
|
49
|
+
* picks up the thrown 3xx and emits a normal HTTP redirect.
|
|
50
|
+
*/
|
|
51
|
+
redirectTo?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function actionFailure(
|
|
55
|
+
status: number,
|
|
56
|
+
data: { error: string; code?: string },
|
|
57
|
+
): Promise<FortressActionFailure> {
|
|
58
|
+
const { fail } = await import('@sveltejs/kit');
|
|
59
|
+
return fail(status, data);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function actionRedirect(location: string): Promise<never> {
|
|
63
|
+
const { redirect } = await import('@sveltejs/kit');
|
|
64
|
+
return redirect(303, location);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Read a single string field from a form, defaulting to '' if missing. */
|
|
68
|
+
function field(form: FormData, name: string): string {
|
|
69
|
+
const v = form.get(name);
|
|
70
|
+
return typeof v === 'string' ? v : '';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function buildMeta(event: SvelteKitRequestEvent): { ipAddress?: string; userAgent?: string } {
|
|
74
|
+
return {
|
|
75
|
+
ipAddress:
|
|
76
|
+
event.request.headers.get('x-forwarded-for')
|
|
77
|
+
?? event.request.headers.get('x-real-ip')
|
|
78
|
+
?? undefined,
|
|
79
|
+
userAgent: event.request.headers.get('user-agent') ?? undefined,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Type of the {@link fortressActions} namespace — explicit so JSR's slow-type check is happy. */
|
|
84
|
+
export interface FortressActions {
|
|
85
|
+
login: (
|
|
86
|
+
fortress: Fortress<any, any>,
|
|
87
|
+
opts?: FortressActionOptions,
|
|
88
|
+
) => SvelteKitAction<FortressActionFailure | FortressActionSuccess>;
|
|
89
|
+
register: (
|
|
90
|
+
fortress: Fortress<any, any>,
|
|
91
|
+
opts?: FortressActionOptions,
|
|
92
|
+
) => SvelteKitAction<FortressActionFailure | FortressActionSuccess>;
|
|
93
|
+
logout: (
|
|
94
|
+
fortress: Fortress<any, any>,
|
|
95
|
+
opts?: FortressActionOptions,
|
|
96
|
+
) => SvelteKitAction<FortressActionSuccess>;
|
|
97
|
+
refresh: (
|
|
98
|
+
fortress: Fortress<any, any>,
|
|
99
|
+
) => SvelteKitAction<FortressActionFailure | FortressActionSuccess>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Form-action helpers exported as a single namespace. */
|
|
103
|
+
export const fortressActions: FortressActions = {
|
|
104
|
+
/**
|
|
105
|
+
* Sign in with `identifier` + `password` form fields. Sets the access +
|
|
106
|
+
* refresh cookies on success. Optionally redirects.
|
|
107
|
+
*/
|
|
108
|
+
login(
|
|
109
|
+
fortress: Fortress<any, any>,
|
|
110
|
+
opts: FortressActionOptions = {},
|
|
111
|
+
): SvelteKitAction<FortressActionFailure | FortressActionSuccess> {
|
|
112
|
+
return async (event) => {
|
|
113
|
+
const form = await event.request.formData();
|
|
114
|
+
const identifier = field(form, 'identifier');
|
|
115
|
+
const password = field(form, 'password');
|
|
116
|
+
try {
|
|
117
|
+
const result = await fortress.auth.login(identifier, password, buildMeta(event));
|
|
118
|
+
if (result.status === 'pending')
|
|
119
|
+
return { success: true, pending: true, challenge: result.pending } as const;
|
|
120
|
+
if (result.status !== 'success')
|
|
121
|
+
return { success: true, pending: false } as const;
|
|
122
|
+
setAuthCookies(event, fortress, {
|
|
123
|
+
accessToken: result.accessToken,
|
|
124
|
+
refreshToken: result.refreshToken,
|
|
125
|
+
});
|
|
126
|
+
if (opts.redirectTo)
|
|
127
|
+
await actionRedirect(opts.redirectTo);
|
|
128
|
+
return { success: true, pending: false } as const;
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
if (err instanceof FortressError) {
|
|
132
|
+
return actionFailure(err.statusCode, { error: err.message, code: err.code });
|
|
133
|
+
}
|
|
134
|
+
throw err;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Register a new user from `email`, `name`, `password` form fields. On
|
|
141
|
+
* success, immediately logs them in (sets cookies) and optionally
|
|
142
|
+
* redirects. Mirrors the typical sign-up UX.
|
|
143
|
+
*/
|
|
144
|
+
register(
|
|
145
|
+
fortress: Fortress<any, any>,
|
|
146
|
+
opts: FortressActionOptions = {},
|
|
147
|
+
): SvelteKitAction<FortressActionFailure | FortressActionSuccess> {
|
|
148
|
+
return async (event) => {
|
|
149
|
+
const form = await event.request.formData();
|
|
150
|
+
const data: CreateUserInput = {
|
|
151
|
+
email: field(form, 'email'),
|
|
152
|
+
name: field(form, 'name'),
|
|
153
|
+
password: field(form, 'password'),
|
|
154
|
+
};
|
|
155
|
+
try {
|
|
156
|
+
await fortress.auth.createUser(data);
|
|
157
|
+
const result = await fortress.auth.login(data.email, data.password ?? '', buildMeta(event));
|
|
158
|
+
if (result.status === 'pending')
|
|
159
|
+
return { success: true, pending: true, challenge: result.pending } as const;
|
|
160
|
+
if (result.status !== 'success')
|
|
161
|
+
return { success: true, pending: false } as const;
|
|
162
|
+
setAuthCookies(event, fortress, {
|
|
163
|
+
accessToken: result.accessToken,
|
|
164
|
+
refreshToken: result.refreshToken,
|
|
165
|
+
});
|
|
166
|
+
if (opts.redirectTo)
|
|
167
|
+
await actionRedirect(opts.redirectTo);
|
|
168
|
+
return { success: true, pending: false } as const;
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
if (err instanceof FortressError) {
|
|
172
|
+
return actionFailure(err.statusCode, { error: err.message, code: err.code });
|
|
173
|
+
}
|
|
174
|
+
throw err;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Revoke the current refresh token (if present) and clear both auth
|
|
181
|
+
* cookies. Optionally redirects.
|
|
182
|
+
*/
|
|
183
|
+
logout(
|
|
184
|
+
fortress: Fortress<any, any>,
|
|
185
|
+
opts: FortressActionOptions = {},
|
|
186
|
+
): SvelteKitAction<FortressActionSuccess> {
|
|
187
|
+
return async (event) => {
|
|
188
|
+
const refreshToken = event.cookies.get(fortress.cookies.refreshName);
|
|
189
|
+
if (refreshToken) {
|
|
190
|
+
try {
|
|
191
|
+
await fortress.auth.logout(refreshToken);
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
// Ignore — clearing cookies is the important part.
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
clearAuthCookies(event, fortress);
|
|
198
|
+
if (opts.redirectTo)
|
|
199
|
+
await actionRedirect(opts.redirectTo);
|
|
200
|
+
return { success: true, pending: false } as const;
|
|
201
|
+
};
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Manually rotate the access + refresh tokens using the cookie. Useful
|
|
206
|
+
* if you want a `?/refresh` form action for SPAs that need to extend a
|
|
207
|
+
* session without a full reload.
|
|
208
|
+
*/
|
|
209
|
+
refresh(
|
|
210
|
+
fortress: Fortress<any, any>,
|
|
211
|
+
): SvelteKitAction<FortressActionFailure | FortressActionSuccess> {
|
|
212
|
+
return async (event) => {
|
|
213
|
+
const refreshToken = event.cookies.get(fortress.cookies.refreshName);
|
|
214
|
+
if (!refreshToken) {
|
|
215
|
+
return actionFailure(401, { error: 'No refresh token', code: 'UNAUTHORIZED' });
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
const result = await fortress.auth.refresh(refreshToken, buildMeta(event));
|
|
219
|
+
setAuthCookies(event, fortress, result);
|
|
220
|
+
return { success: true, pending: false } as const;
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
if (err instanceof FortressError) {
|
|
224
|
+
return actionFailure(err.statusCode, { error: err.message, code: err.code });
|
|
225
|
+
}
|
|
226
|
+
throw err;
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
},
|
|
230
|
+
} as const;
|
|
231
|
+
|
|
232
|
+
// Re-export so consumers can pattern-match against the field type.
|
|
233
|
+
export type { LoginIdentifierType };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional catch-all `+server.ts` escape hatch.
|
|
3
|
+
*
|
|
4
|
+
* Lets users colocate Fortress routes inside their normal `src/routes/`
|
|
5
|
+
* tree instead of (or in addition to) the handle-hook approach.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* // src/routes/api/fortress/[...path]/+server.ts
|
|
10
|
+
* import { toSvelteKitHandler } from '@bajustone/fortress/sveltekit';
|
|
11
|
+
* import { fortress } from '$lib/server/fortress';
|
|
12
|
+
*
|
|
13
|
+
* export const { GET, POST, PUT, DELETE, PATCH } = toSvelteKitHandler(fortress);
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { Fortress } from '../core/fortress';
|
|
18
|
+
import type { SvelteKitRequestEvent } from './types';
|
|
19
|
+
|
|
20
|
+
/** Per-method handler signature compatible with SvelteKit `+server.ts` exports. */
|
|
21
|
+
export type SvelteKitRouteHandler = (event: SvelteKitRequestEvent) => Promise<Response>;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Build a `{ GET, POST, PUT, DELETE, PATCH }` set of handlers that all
|
|
25
|
+
* delegate to `fortress.handleRequest`. Suitable for `export const { ... } =
|
|
26
|
+
* toSvelteKitHandler(fortress)` in a catch-all `+server.ts`.
|
|
27
|
+
*/
|
|
28
|
+
export function toSvelteKitHandler(fortress: Fortress<any, any>): {
|
|
29
|
+
GET: SvelteKitRouteHandler;
|
|
30
|
+
POST: SvelteKitRouteHandler;
|
|
31
|
+
PUT: SvelteKitRouteHandler;
|
|
32
|
+
DELETE: SvelteKitRouteHandler;
|
|
33
|
+
PATCH: SvelteKitRouteHandler;
|
|
34
|
+
} {
|
|
35
|
+
const handler: SvelteKitRouteHandler = event => fortress.handleRequest(event.request);
|
|
36
|
+
return {
|
|
37
|
+
GET: handler,
|
|
38
|
+
POST: handler,
|
|
39
|
+
PUT: handler,
|
|
40
|
+
DELETE: handler,
|
|
41
|
+
PATCH: handler,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SvelteKit cookie bridging.
|
|
3
|
+
*
|
|
4
|
+
* Translates between fortress's auth result objects and SvelteKit's
|
|
5
|
+
* `event.cookies` API. Cookie attributes (name, secure, sameSite, path,
|
|
6
|
+
* domain) come from the resolved {@link ResolvedCookieConfig} on the
|
|
7
|
+
* Fortress instance, so SvelteKit, Hono, and Express all emit cookies with
|
|
8
|
+
* the same shape.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { ResolvedCookieConfig } from '../core/config';
|
|
12
|
+
import type { Fortress } from '../core/fortress';
|
|
13
|
+
import type { AuthCookiePayload } from '../core/http/cookie-serialize';
|
|
14
|
+
import type { SvelteKitCookieOptions, SvelteKitRequestEvent } from './types';
|
|
15
|
+
import { parseCookieHeader } from '../core/http/cookie-serialize';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Set the access + refresh cookies on a SvelteKit `RequestEvent` from a
|
|
19
|
+
* fortress auth result. Used by the form-action helpers and the auto-refresh
|
|
20
|
+
* path inside `createSvelteKitHandle`.
|
|
21
|
+
*/
|
|
22
|
+
export function setAuthCookies(
|
|
23
|
+
event: SvelteKitRequestEvent,
|
|
24
|
+
fortress: Fortress<any, any>,
|
|
25
|
+
payload: AuthCookiePayload,
|
|
26
|
+
): void {
|
|
27
|
+
const cookies = fortress.cookies;
|
|
28
|
+
const accessExpiry = fortress.config.jwt.accessTokenExpirySeconds ?? 900;
|
|
29
|
+
const refreshExpiry = fortress.config.jwt.refreshTokenExpirySeconds ?? 604_800;
|
|
30
|
+
|
|
31
|
+
event.cookies.set(cookies.accessName, payload.accessToken, optsFor(cookies, accessExpiry));
|
|
32
|
+
if (payload.refreshToken) {
|
|
33
|
+
event.cookies.set(cookies.refreshName, payload.refreshToken, optsFor(cookies, refreshExpiry));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Clear both fortress auth cookies (logout). */
|
|
38
|
+
export function clearAuthCookies(event: SvelteKitRequestEvent, fortress: Fortress<any, any>): void {
|
|
39
|
+
const cookies = fortress.cookies;
|
|
40
|
+
event.cookies.delete(cookies.accessName, optsFor(cookies));
|
|
41
|
+
event.cookies.delete(cookies.refreshName, optsFor(cookies));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Replay any `Set-Cookie` headers from a `Response` (typically returned by
|
|
46
|
+
* `fortress.handleRequest`) through `event.cookies.set` so they're visible
|
|
47
|
+
* to subsequent same-request reads. Returns the original response unchanged
|
|
48
|
+
* — the cookies are already on it; this just mirrors them into SvelteKit's
|
|
49
|
+
* cookie jar for in-request use.
|
|
50
|
+
*/
|
|
51
|
+
export function replayCookies(response: Response, event: SvelteKitRequestEvent): void {
|
|
52
|
+
const setCookies = response.headers.getSetCookie();
|
|
53
|
+
for (const raw of setCookies) {
|
|
54
|
+
const parsed = parseSetCookie(raw);
|
|
55
|
+
if (!parsed)
|
|
56
|
+
continue;
|
|
57
|
+
event.cookies.set(parsed.name, parsed.value, parsed.opts);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type RequiredPathCookieOptions = SvelteKitCookieOptions & { path: string };
|
|
62
|
+
|
|
63
|
+
function optsFor(cookies: ResolvedCookieConfig, maxAgeSeconds?: number): RequiredPathCookieOptions {
|
|
64
|
+
const opts: RequiredPathCookieOptions = {
|
|
65
|
+
path: cookies.path,
|
|
66
|
+
httpOnly: true,
|
|
67
|
+
secure: cookies.secure,
|
|
68
|
+
sameSite: cookies.sameSite,
|
|
69
|
+
};
|
|
70
|
+
if (cookies.domain)
|
|
71
|
+
opts.domain = cookies.domain;
|
|
72
|
+
if (maxAgeSeconds !== undefined)
|
|
73
|
+
opts.maxAge = maxAgeSeconds;
|
|
74
|
+
return opts;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
interface ParsedSetCookie {
|
|
78
|
+
name: string;
|
|
79
|
+
value: string;
|
|
80
|
+
opts: RequiredPathCookieOptions;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Parse a single `Set-Cookie` header string into name/value/options.
|
|
85
|
+
*
|
|
86
|
+
* Handles the attributes fortress emits (Path, Domain, HttpOnly, Secure,
|
|
87
|
+
* SameSite, Max-Age, Expires). Unknown attributes are ignored.
|
|
88
|
+
*/
|
|
89
|
+
function parseSetCookie(raw: string): ParsedSetCookie | null {
|
|
90
|
+
const parts = raw.split(';').map(p => p.trim());
|
|
91
|
+
if (parts.length === 0)
|
|
92
|
+
return null;
|
|
93
|
+
const first = parts.shift();
|
|
94
|
+
if (!first)
|
|
95
|
+
return null;
|
|
96
|
+
const eq = first.indexOf('=');
|
|
97
|
+
if (eq === -1)
|
|
98
|
+
return null;
|
|
99
|
+
|
|
100
|
+
const name = first.slice(0, eq).trim();
|
|
101
|
+
const rawValue = first.slice(eq + 1).trim();
|
|
102
|
+
let value: string;
|
|
103
|
+
try {
|
|
104
|
+
value = decodeURIComponent(rawValue);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
value = rawValue;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Reuse parseCookieHeader by formatting the attribute list as a single
|
|
111
|
+
// header string would not work — attributes have boolean variants like
|
|
112
|
+
// `Secure` and `HttpOnly`. Walk parts manually.
|
|
113
|
+
const opts: RequiredPathCookieOptions = { path: '/' };
|
|
114
|
+
for (const part of parts) {
|
|
115
|
+
const [k, v = ''] = part.split('=', 2);
|
|
116
|
+
const key = k.toLowerCase();
|
|
117
|
+
if (key === 'path')
|
|
118
|
+
opts.path = v;
|
|
119
|
+
else if (key === 'domain')
|
|
120
|
+
opts.domain = v;
|
|
121
|
+
else if (key === 'httponly')
|
|
122
|
+
opts.httpOnly = true;
|
|
123
|
+
else if (key === 'secure')
|
|
124
|
+
opts.secure = true;
|
|
125
|
+
else if (key === 'samesite')
|
|
126
|
+
opts.sameSite = v.toLowerCase() as 'lax' | 'strict' | 'none';
|
|
127
|
+
else if (key === 'max-age')
|
|
128
|
+
opts.maxAge = Number(v);
|
|
129
|
+
else if (key === 'expires')
|
|
130
|
+
opts.expires = new Date(v);
|
|
131
|
+
}
|
|
132
|
+
return { name, value, opts };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Re-export so callers can use it from this module too
|
|
136
|
+
export { parseCookieHeader };
|