@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,307 @@
|
|
|
1
|
+
import { S as Subject, P as PermissionContext, b as Permission, c as PermissionInput, d as Role, a as SubjectType, G as Group, e as RoleBinding, F as FortressUser, C as CreateServiceAccountInput, f as ServiceAccount, R as RequestMeta, A as AuthResult, g as AuthMethod, h as AuthTokenPair, i as CreateUserInput, T as TokenClaims, j as SessionInfo, L as LoginIdentifierType, k as LoginIdentifier, l as PendingReason } from './types-et0R8tsC.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Structural logger contract. Shaped to be assignment-compatible with pino's
|
|
5
|
+
* `BaseLogger` and Fastify's `FastifyBaseLogger`, so consumers can drop a
|
|
6
|
+
* `pino()` instance or `fastify.log` in directly with zero adapter code.
|
|
7
|
+
*
|
|
8
|
+
* The default is {@link SILENT_LOGGER} — libraries that log to stderr by
|
|
9
|
+
* default are universally hated. Opt-in logging only.
|
|
10
|
+
*/
|
|
11
|
+
type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
12
|
+
interface LogFn {
|
|
13
|
+
(msg: string): void;
|
|
14
|
+
(obj: Record<string, unknown>, msg?: string): void;
|
|
15
|
+
(msg: string, ...args: unknown[]): void;
|
|
16
|
+
}
|
|
17
|
+
interface FortressLogger {
|
|
18
|
+
level: LogLevel | 'silent' | string;
|
|
19
|
+
fatal: LogFn;
|
|
20
|
+
error: LogFn;
|
|
21
|
+
warn: LogFn;
|
|
22
|
+
info: LogFn;
|
|
23
|
+
debug: LogFn;
|
|
24
|
+
trace: LogFn;
|
|
25
|
+
silent: LogFn;
|
|
26
|
+
/** Optional on pino/Fastify; Fortress calls it defensively. */
|
|
27
|
+
child?: (bindings: Record<string, unknown>) => FortressLogger;
|
|
28
|
+
/** Optional guard for lazy evaluation of expensive log metadata. */
|
|
29
|
+
isLevelEnabled?: (level: LogLevel) => boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Fortress-internal telemetry interfaces.
|
|
34
|
+
*
|
|
35
|
+
* Core code depends on these shapes, never on `@opentelemetry/api`. The OTel
|
|
36
|
+
* adapter in `src/otel/index.ts` is the only file in the repo that imports
|
|
37
|
+
* `@opentelemetry/api`; it returns a {@link TelemetryProvider} that satisfies
|
|
38
|
+
* these interfaces. This keeps `@opentelemetry/api` off the core critical
|
|
39
|
+
* path — runtimes like Cloudflare Workers and Deno never resolve it unless
|
|
40
|
+
* the user explicitly imports `@bajustone/fortress/otel`.
|
|
41
|
+
*/
|
|
42
|
+
type AttributeValue = string | number | boolean;
|
|
43
|
+
type Attributes = Record<string, AttributeValue>;
|
|
44
|
+
interface Span {
|
|
45
|
+
setAttribute: (key: string, value: AttributeValue) => void;
|
|
46
|
+
recordException: (error: unknown) => void;
|
|
47
|
+
setStatus: (status: {
|
|
48
|
+
code: 'ok' | 'error';
|
|
49
|
+
message?: string;
|
|
50
|
+
}) => void;
|
|
51
|
+
end: () => void;
|
|
52
|
+
}
|
|
53
|
+
interface Tracer {
|
|
54
|
+
startSpan: (name: string, attributes?: Attributes) => Span;
|
|
55
|
+
/** Run a callback with this span as the active parent for nested spans. */
|
|
56
|
+
startActiveSpan?: <T>(name: string, attributes: Attributes | undefined, callback: (span: Span) => T | Promise<T>) => Promise<T>;
|
|
57
|
+
}
|
|
58
|
+
interface Counter {
|
|
59
|
+
add: (value: number, attributes?: Attributes) => void;
|
|
60
|
+
}
|
|
61
|
+
interface Histogram {
|
|
62
|
+
record: (value: number, attributes?: Attributes) => void;
|
|
63
|
+
}
|
|
64
|
+
interface Meter {
|
|
65
|
+
createCounter: (name: string, options?: {
|
|
66
|
+
description?: string;
|
|
67
|
+
unit?: string;
|
|
68
|
+
}) => Counter;
|
|
69
|
+
createHistogram: (name: string, options?: {
|
|
70
|
+
description?: string;
|
|
71
|
+
unit?: string;
|
|
72
|
+
boundaries?: number[];
|
|
73
|
+
}) => Histogram;
|
|
74
|
+
}
|
|
75
|
+
interface TelemetryProvider {
|
|
76
|
+
tracer: Tracer;
|
|
77
|
+
meter: Meter;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
type Unsubscribe = () => void;
|
|
81
|
+
|
|
82
|
+
interface ResourceDefinition {
|
|
83
|
+
actions: string[];
|
|
84
|
+
description?: string;
|
|
85
|
+
}
|
|
86
|
+
interface ResourceFile {
|
|
87
|
+
resources: Record<string, ResourceDefinition>;
|
|
88
|
+
}
|
|
89
|
+
/** Validate and normalize the canonical map-shaped resource document. */
|
|
90
|
+
declare function parseResourceFile(value: unknown): ResourceFile;
|
|
91
|
+
|
|
92
|
+
interface IamEvent {
|
|
93
|
+
eventType: string;
|
|
94
|
+
actorId?: string | null;
|
|
95
|
+
targetId?: string | null;
|
|
96
|
+
targetType?: string | null;
|
|
97
|
+
metadata?: Record<string, unknown>;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Async IAM event listener. May return a Promise — if you `return` it, any
|
|
101
|
+
* rejection is routed to `config.logger.error`. Firing work via
|
|
102
|
+
* `void asyncWork()` inside a sync body is an explicit opt-out of that
|
|
103
|
+
* safety net; rejections will escape to the runtime's unhandled-rejection
|
|
104
|
+
* handler instead.
|
|
105
|
+
*/
|
|
106
|
+
type IamEventListener = (event: IamEvent) => void | Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* High-frequency event fired on every permission check. Emitted by a
|
|
109
|
+
* separate observer list from {@link IamEvent} so audit-log consumers
|
|
110
|
+
* (which subscribe to mutations) aren't spammed with per-check traffic.
|
|
111
|
+
*
|
|
112
|
+
* Listeners are invoked **synchronously**. The type signature intentionally
|
|
113
|
+
* returns `void` (not `Promise<void>`) to discourage awaiting expensive
|
|
114
|
+
* work on the hot path. If an observer needs async work it should fire
|
|
115
|
+
* and forget with `void asyncWork()`.
|
|
116
|
+
*/
|
|
117
|
+
interface PermissionCheckEvent {
|
|
118
|
+
subjectType: 'USER' | 'SERVICE_ACCOUNT' | 'GROUP';
|
|
119
|
+
subjectId: string;
|
|
120
|
+
resource: string;
|
|
121
|
+
action: string;
|
|
122
|
+
allowed: boolean;
|
|
123
|
+
cached: boolean;
|
|
124
|
+
/** Pre-divided monotonic duration in seconds; ready to feed into a histogram. */
|
|
125
|
+
durationSeconds: number;
|
|
126
|
+
tenantId?: string;
|
|
127
|
+
}
|
|
128
|
+
type PermissionCheckListener = (event: PermissionCheckEvent) => void;
|
|
129
|
+
interface IamService {
|
|
130
|
+
checkPermission: (subject: Subject, resource: string, action: string, context?: PermissionContext) => Promise<boolean>;
|
|
131
|
+
getPermissionsForSubject: (subject: Subject, tenantId?: string) => Promise<Permission[]>;
|
|
132
|
+
createRole: (name: string, permissions: PermissionInput[], description?: string) => Promise<Role>;
|
|
133
|
+
deleteRole: (roleId: string) => Promise<void>;
|
|
134
|
+
bindRole: (subjectType: SubjectType, subjectId: string, roleId: string, tenantId?: string) => Promise<void>;
|
|
135
|
+
bindRoleToUser: (userId: string, roleId: string, tenantId?: string) => Promise<void>;
|
|
136
|
+
bindRoleToGroup: (groupId: string, roleId: string, tenantId?: string) => Promise<void>;
|
|
137
|
+
/** Omitted removes all scopes; null removes only the global binding; a string removes one tenant. */
|
|
138
|
+
unbindRole: (subjectType: SubjectType, subjectId: string, roleId: string, tenantId?: string | null) => Promise<void>;
|
|
139
|
+
bindPermissionToUser: (userId: string, permission: PermissionInput, tenantId?: string) => Promise<void>;
|
|
140
|
+
bindPermissionToGroup: (groupId: string, permission: PermissionInput, tenantId?: string) => Promise<void>;
|
|
141
|
+
unbindPermissionFromUser: (userId: string, permissionId: string, tenantId?: string | null) => Promise<void>;
|
|
142
|
+
unbindPermissionFromGroup: (groupId: string, permissionId: string, tenantId?: string | null) => Promise<void>;
|
|
143
|
+
createGroup: (name: string, description?: string) => Promise<Group>;
|
|
144
|
+
addUserToGroup: (groupId: string, userId: string) => Promise<void>;
|
|
145
|
+
removeUserFromGroup: (groupId: string, userId: string) => Promise<void>;
|
|
146
|
+
getResources: () => Promise<ResourceFile>;
|
|
147
|
+
getRoles: () => Promise<Role[]>;
|
|
148
|
+
/** Apply a resource map directly without filesystem access. */
|
|
149
|
+
pushResources: (resources: ResourceFile) => Promise<void>;
|
|
150
|
+
/** List role bindings: omitted scope means all, `null` means global only, string means one tenant. */
|
|
151
|
+
listRoleBindingsForSubject: (subject: Subject, tenantId?: string | null) => Promise<RoleBinding[]>;
|
|
152
|
+
syncResources: (direction: 'push' | 'pull', filePath?: string) => Promise<void>;
|
|
153
|
+
clearPermissionCache: () => void;
|
|
154
|
+
/**
|
|
155
|
+
* Register a listener for IAM mutation events. Multiple listeners are
|
|
156
|
+
* supported — each is invoked in registration order. Observer failures
|
|
157
|
+
* are routed to the configured logger at `error` level and never break
|
|
158
|
+
* IAM operations. Returns an unsubscribe function.
|
|
159
|
+
*/
|
|
160
|
+
addIamObserver: (listener: IamEventListener) => Unsubscribe;
|
|
161
|
+
/**
|
|
162
|
+
* Register a listener for individual permission checks. Fires on every
|
|
163
|
+
* `checkPermission` call with latency and cache-hit information. The
|
|
164
|
+
* listener signature is synchronous — see {@link PermissionCheckEvent}
|
|
165
|
+
* for rationale. Returns an unsubscribe function.
|
|
166
|
+
*/
|
|
167
|
+
addPermissionCheckObserver: (listener: PermissionCheckListener) => Unsubscribe;
|
|
168
|
+
getRole: (roleId: string) => Promise<Role & {
|
|
169
|
+
permissions: Permission[];
|
|
170
|
+
}>;
|
|
171
|
+
updateRole: (roleId: string, data: {
|
|
172
|
+
name?: string;
|
|
173
|
+
description?: string | null;
|
|
174
|
+
}) => Promise<Role>;
|
|
175
|
+
listGroups: (options?: {
|
|
176
|
+
limit?: number;
|
|
177
|
+
offset?: number;
|
|
178
|
+
}) => Promise<{
|
|
179
|
+
groups: Group[];
|
|
180
|
+
total: number;
|
|
181
|
+
}>;
|
|
182
|
+
getGroup: (groupId: string) => Promise<Group & {
|
|
183
|
+
users: FortressUser[];
|
|
184
|
+
}>;
|
|
185
|
+
updateGroup: (groupId: string, data: {
|
|
186
|
+
name?: string;
|
|
187
|
+
description?: string;
|
|
188
|
+
}) => Promise<Group>;
|
|
189
|
+
deleteGroup: (groupId: string) => Promise<void>;
|
|
190
|
+
getGroupUsers: (groupId: string) => Promise<FortressUser[]>;
|
|
191
|
+
listPermissions: (options?: {
|
|
192
|
+
resource?: string;
|
|
193
|
+
}) => Promise<Permission[]>;
|
|
194
|
+
createPermission: (permission: PermissionInput) => Promise<Permission>;
|
|
195
|
+
deletePermission: (permissionId: string) => Promise<void>;
|
|
196
|
+
addPermissionToRole: (roleId: string, permission: PermissionInput) => Promise<void>;
|
|
197
|
+
removePermissionFromRole: (roleId: string, permission: PermissionInput) => Promise<void>;
|
|
198
|
+
createServiceAccount: (input: CreateServiceAccountInput) => Promise<ServiceAccount>;
|
|
199
|
+
getServiceAccount: (id: string) => Promise<ServiceAccount>;
|
|
200
|
+
listServiceAccounts: (options?: {
|
|
201
|
+
limit?: number;
|
|
202
|
+
offset?: number;
|
|
203
|
+
}) => Promise<{
|
|
204
|
+
serviceAccounts: ServiceAccount[];
|
|
205
|
+
total: number;
|
|
206
|
+
}>;
|
|
207
|
+
updateServiceAccount: (id: string, data: {
|
|
208
|
+
displayName?: string | null;
|
|
209
|
+
description?: string | null;
|
|
210
|
+
isActive?: boolean;
|
|
211
|
+
}) => Promise<ServiceAccount>;
|
|
212
|
+
deleteServiceAccount: (id: string) => Promise<void>;
|
|
213
|
+
bindRoleToServiceAccount: (serviceAccountId: string, roleId: string, tenantId?: string) => Promise<void>;
|
|
214
|
+
/** Unbind across all scopes when omitted, global only for `null`, or one tenant for a string scope. */
|
|
215
|
+
unbindRoleFromServiceAccount: (serviceAccountId: string, roleId: string, tenantId?: string | null) => Promise<void>;
|
|
216
|
+
bindPermissionToServiceAccount: (serviceAccountId: string, permission: PermissionInput, tenantId?: string) => Promise<void>;
|
|
217
|
+
unbindPermissionFromServiceAccount: (serviceAccountId: string, permissionId: string, tenantId?: string | null) => Promise<void>;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Lifecycle event emitted by the auth service. Mirrors the IAM observer
|
|
222
|
+
* pattern (`addIamObserver`) so consumers — audit log, SIEM webhooks,
|
|
223
|
+
* telemetry plugins, Datadog adapters — can subscribe to auth events
|
|
224
|
+
* without reimplementing every hook individually.
|
|
225
|
+
*/
|
|
226
|
+
interface AuthEvent {
|
|
227
|
+
eventType: 'LOGIN_SUCCESS' | 'LOGIN_FAILURE' | 'LOGIN_PENDING' | 'LOGOUT' | 'REGISTER' | 'TOKEN_REFRESH' | 'TOKEN_REUSE_DETECTED' | 'TOKEN_REUSE_GRACED' | 'TOKEN_FINGERPRINT_MISMATCH' | 'MFA_VERIFY_SUCCESS' | 'MFA_VERIFY_FAILURE' | 'SESSION_EXPIRED_IDLE' | 'SESSION_EXPIRED_ABSOLUTE' | 'PASSWORD_BREACH_CHECK_DEGRADED' | 'IMPERSONATE';
|
|
228
|
+
actorId?: string;
|
|
229
|
+
identifier?: string;
|
|
230
|
+
method?: 'password' | 'oauth' | 'magic_link' | 'webauthn' | '2fa' | 'api_key';
|
|
231
|
+
ipAddress?: string;
|
|
232
|
+
userAgent?: string;
|
|
233
|
+
outcome?: 'success' | 'failure' | 'pending';
|
|
234
|
+
/** Set on `LOGIN_PENDING` — which additional step the sign-in is waiting on. */
|
|
235
|
+
pendingReason?: PendingReason;
|
|
236
|
+
/** Free-form sub-action label (e.g. the specific fingerprint/session action that fired the event). */
|
|
237
|
+
action?: string;
|
|
238
|
+
error?: {
|
|
239
|
+
message: string;
|
|
240
|
+
code?: string;
|
|
241
|
+
};
|
|
242
|
+
metadata?: Record<string, unknown>;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Async auth event listener. May return a Promise — if you `return` it, any
|
|
246
|
+
* rejection is routed to `config.logger.error`. Firing work via
|
|
247
|
+
* `void asyncWork()` inside a sync body is an explicit opt-out of that
|
|
248
|
+
* safety net; rejections will escape to the runtime's unhandled-rejection
|
|
249
|
+
* handler instead.
|
|
250
|
+
*/
|
|
251
|
+
type AuthEventListener = (event: AuthEvent) => void | Promise<void>;
|
|
252
|
+
interface AuthService {
|
|
253
|
+
login: (identifier: string, password: string, meta?: RequestMeta) => Promise<AuthResult>;
|
|
254
|
+
/** Consume a verified factor's continuation, rerun remaining gates, then issue tokens. */
|
|
255
|
+
completePendingAuth: (continuationToken: string, completion: unknown, meta?: RequestMeta) => Promise<AuthResult>;
|
|
256
|
+
/** Finish a trusted plugin-owned primary credential (for example a magic link). */
|
|
257
|
+
completePluginAuth: (userId: string, method: Exclude<AuthMethod, 'refresh' | 'impersonation'>, meta?: RequestMeta) => Promise<AuthResult>;
|
|
258
|
+
refresh: (refreshToken: string, meta?: RequestMeta) => Promise<AuthTokenPair>;
|
|
259
|
+
logout: (refreshToken: string) => Promise<void>;
|
|
260
|
+
me: (userId: string) => Promise<FortressUser>;
|
|
261
|
+
createUser: (data: CreateUserInput) => Promise<FortressUser>;
|
|
262
|
+
verifyToken: (token: string) => Promise<TokenClaims>;
|
|
263
|
+
signToken: (claims: Omit<TokenClaims, 'iat' | 'exp' | 'aud'>) => Promise<string>;
|
|
264
|
+
listSessions: (userId: string) => Promise<SessionInfo[]>;
|
|
265
|
+
revokeSession: (userId: string, tokenId: string) => Promise<void>;
|
|
266
|
+
revokeAllOtherSessions: (userId: string, currentTokenId: string) => Promise<void>;
|
|
267
|
+
addLoginIdentifier: (userId: string, type: LoginIdentifierType, value: string) => Promise<void>;
|
|
268
|
+
removeLoginIdentifier: (userId: string, type: LoginIdentifierType, value: string) => Promise<void>;
|
|
269
|
+
getLoginIdentifiers: (userId: string) => Promise<LoginIdentifier[]>;
|
|
270
|
+
/**
|
|
271
|
+
* Issue a short-lived, non-renewable access token that lets an admin act as another user.
|
|
272
|
+
* The token carries an RFC 8693 `act` claim identifying the real admin.
|
|
273
|
+
*
|
|
274
|
+
* Requires the admin user to hold `fortress:impersonate`. The built-in HTTP route also enforces this via endpoint metadata.
|
|
275
|
+
*/
|
|
276
|
+
impersonate: (adminUserId: string, targetUserId: string, options?: {
|
|
277
|
+
reason?: string;
|
|
278
|
+
expirySeconds?: number;
|
|
279
|
+
}) => Promise<AuthResult>;
|
|
280
|
+
listUsers: (options: {
|
|
281
|
+
limit?: number;
|
|
282
|
+
offset?: number;
|
|
283
|
+
search?: string;
|
|
284
|
+
sortBy?: string;
|
|
285
|
+
sortDirection?: 'asc' | 'desc';
|
|
286
|
+
}) => Promise<{
|
|
287
|
+
users: FortressUser[];
|
|
288
|
+
total: number;
|
|
289
|
+
}>;
|
|
290
|
+
getUserById: (userId: string) => Promise<FortressUser>;
|
|
291
|
+
updateUser: (userId: string, data: {
|
|
292
|
+
name?: string;
|
|
293
|
+
email?: string;
|
|
294
|
+
isActive?: boolean;
|
|
295
|
+
password?: string;
|
|
296
|
+
}) => Promise<FortressUser>;
|
|
297
|
+
deleteUser: (userId: string) => Promise<void>;
|
|
298
|
+
/**
|
|
299
|
+
* Register a listener for auth lifecycle events. Multiple listeners are
|
|
300
|
+
* supported — each is invoked in registration order. Listener failures
|
|
301
|
+
* never break auth operations; they are routed to the configured logger
|
|
302
|
+
* at `error` level. Returns an unsubscribe function.
|
|
303
|
+
*/
|
|
304
|
+
addAuthObserver: (listener: AuthEventListener) => Unsubscribe;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export { type AttributeValue as A, type Counter as C, type FortressLogger as F, type Histogram as H, type IamEvent as I, type Meter as M, type PermissionCheckEvent as P, type ResourceDefinition as R, type Span as S, type TelemetryProvider as T, type Unsubscribe as U, type Attributes as a, type AuthEvent as b, type AuthEventListener as c, type IamEventListener as d, type PermissionCheckListener as e, type Tracer as f, type IamService as g, type ResourceFile as h, type AuthService as i, parseResourceFile as p };
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { S as Subject, P as PermissionContext, b as Permission, c as PermissionInput, d as Role, a as SubjectType, G as Group, e as RoleBinding, F as FortressUser, C as CreateServiceAccountInput, f as ServiceAccount, R as RequestMeta, A as AuthResult, g as AuthMethod, h as AuthTokenPair, i as CreateUserInput, T as TokenClaims, j as SessionInfo, L as LoginIdentifierType, k as LoginIdentifier, l as PendingReason } from './types-et0R8tsC.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Structural logger contract. Shaped to be assignment-compatible with pino's
|
|
5
|
+
* `BaseLogger` and Fastify's `FastifyBaseLogger`, so consumers can drop a
|
|
6
|
+
* `pino()` instance or `fastify.log` in directly with zero adapter code.
|
|
7
|
+
*
|
|
8
|
+
* The default is {@link SILENT_LOGGER} — libraries that log to stderr by
|
|
9
|
+
* default are universally hated. Opt-in logging only.
|
|
10
|
+
*/
|
|
11
|
+
type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
12
|
+
interface LogFn {
|
|
13
|
+
(msg: string): void;
|
|
14
|
+
(obj: Record<string, unknown>, msg?: string): void;
|
|
15
|
+
(msg: string, ...args: unknown[]): void;
|
|
16
|
+
}
|
|
17
|
+
interface FortressLogger {
|
|
18
|
+
level: LogLevel | 'silent' | string;
|
|
19
|
+
fatal: LogFn;
|
|
20
|
+
error: LogFn;
|
|
21
|
+
warn: LogFn;
|
|
22
|
+
info: LogFn;
|
|
23
|
+
debug: LogFn;
|
|
24
|
+
trace: LogFn;
|
|
25
|
+
silent: LogFn;
|
|
26
|
+
/** Optional on pino/Fastify; Fortress calls it defensively. */
|
|
27
|
+
child?: (bindings: Record<string, unknown>) => FortressLogger;
|
|
28
|
+
/** Optional guard for lazy evaluation of expensive log metadata. */
|
|
29
|
+
isLevelEnabled?: (level: LogLevel) => boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Fortress-internal telemetry interfaces.
|
|
34
|
+
*
|
|
35
|
+
* Core code depends on these shapes, never on `@opentelemetry/api`. The OTel
|
|
36
|
+
* adapter in `src/otel/index.ts` is the only file in the repo that imports
|
|
37
|
+
* `@opentelemetry/api`; it returns a {@link TelemetryProvider} that satisfies
|
|
38
|
+
* these interfaces. This keeps `@opentelemetry/api` off the core critical
|
|
39
|
+
* path — runtimes like Cloudflare Workers and Deno never resolve it unless
|
|
40
|
+
* the user explicitly imports `@bajustone/fortress/otel`.
|
|
41
|
+
*/
|
|
42
|
+
type AttributeValue = string | number | boolean;
|
|
43
|
+
type Attributes = Record<string, AttributeValue>;
|
|
44
|
+
interface Span {
|
|
45
|
+
setAttribute: (key: string, value: AttributeValue) => void;
|
|
46
|
+
recordException: (error: unknown) => void;
|
|
47
|
+
setStatus: (status: {
|
|
48
|
+
code: 'ok' | 'error';
|
|
49
|
+
message?: string;
|
|
50
|
+
}) => void;
|
|
51
|
+
end: () => void;
|
|
52
|
+
}
|
|
53
|
+
interface Tracer {
|
|
54
|
+
startSpan: (name: string, attributes?: Attributes) => Span;
|
|
55
|
+
/** Run a callback with this span as the active parent for nested spans. */
|
|
56
|
+
startActiveSpan?: <T>(name: string, attributes: Attributes | undefined, callback: (span: Span) => T | Promise<T>) => Promise<T>;
|
|
57
|
+
}
|
|
58
|
+
interface Counter {
|
|
59
|
+
add: (value: number, attributes?: Attributes) => void;
|
|
60
|
+
}
|
|
61
|
+
interface Histogram {
|
|
62
|
+
record: (value: number, attributes?: Attributes) => void;
|
|
63
|
+
}
|
|
64
|
+
interface Meter {
|
|
65
|
+
createCounter: (name: string, options?: {
|
|
66
|
+
description?: string;
|
|
67
|
+
unit?: string;
|
|
68
|
+
}) => Counter;
|
|
69
|
+
createHistogram: (name: string, options?: {
|
|
70
|
+
description?: string;
|
|
71
|
+
unit?: string;
|
|
72
|
+
boundaries?: number[];
|
|
73
|
+
}) => Histogram;
|
|
74
|
+
}
|
|
75
|
+
interface TelemetryProvider {
|
|
76
|
+
tracer: Tracer;
|
|
77
|
+
meter: Meter;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
type Unsubscribe = () => void;
|
|
81
|
+
|
|
82
|
+
interface ResourceDefinition {
|
|
83
|
+
actions: string[];
|
|
84
|
+
description?: string;
|
|
85
|
+
}
|
|
86
|
+
interface ResourceFile {
|
|
87
|
+
resources: Record<string, ResourceDefinition>;
|
|
88
|
+
}
|
|
89
|
+
/** Validate and normalize the canonical map-shaped resource document. */
|
|
90
|
+
declare function parseResourceFile(value: unknown): ResourceFile;
|
|
91
|
+
|
|
92
|
+
interface IamEvent {
|
|
93
|
+
eventType: string;
|
|
94
|
+
actorId?: string | null;
|
|
95
|
+
targetId?: string | null;
|
|
96
|
+
targetType?: string | null;
|
|
97
|
+
metadata?: Record<string, unknown>;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Async IAM event listener. May return a Promise — if you `return` it, any
|
|
101
|
+
* rejection is routed to `config.logger.error`. Firing work via
|
|
102
|
+
* `void asyncWork()` inside a sync body is an explicit opt-out of that
|
|
103
|
+
* safety net; rejections will escape to the runtime's unhandled-rejection
|
|
104
|
+
* handler instead.
|
|
105
|
+
*/
|
|
106
|
+
type IamEventListener = (event: IamEvent) => void | Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* High-frequency event fired on every permission check. Emitted by a
|
|
109
|
+
* separate observer list from {@link IamEvent} so audit-log consumers
|
|
110
|
+
* (which subscribe to mutations) aren't spammed with per-check traffic.
|
|
111
|
+
*
|
|
112
|
+
* Listeners are invoked **synchronously**. The type signature intentionally
|
|
113
|
+
* returns `void` (not `Promise<void>`) to discourage awaiting expensive
|
|
114
|
+
* work on the hot path. If an observer needs async work it should fire
|
|
115
|
+
* and forget with `void asyncWork()`.
|
|
116
|
+
*/
|
|
117
|
+
interface PermissionCheckEvent {
|
|
118
|
+
subjectType: 'USER' | 'SERVICE_ACCOUNT' | 'GROUP';
|
|
119
|
+
subjectId: string;
|
|
120
|
+
resource: string;
|
|
121
|
+
action: string;
|
|
122
|
+
allowed: boolean;
|
|
123
|
+
cached: boolean;
|
|
124
|
+
/** Pre-divided monotonic duration in seconds; ready to feed into a histogram. */
|
|
125
|
+
durationSeconds: number;
|
|
126
|
+
tenantId?: string;
|
|
127
|
+
}
|
|
128
|
+
type PermissionCheckListener = (event: PermissionCheckEvent) => void;
|
|
129
|
+
interface IamService {
|
|
130
|
+
checkPermission: (subject: Subject, resource: string, action: string, context?: PermissionContext) => Promise<boolean>;
|
|
131
|
+
getPermissionsForSubject: (subject: Subject, tenantId?: string) => Promise<Permission[]>;
|
|
132
|
+
createRole: (name: string, permissions: PermissionInput[], description?: string) => Promise<Role>;
|
|
133
|
+
deleteRole: (roleId: string) => Promise<void>;
|
|
134
|
+
bindRole: (subjectType: SubjectType, subjectId: string, roleId: string, tenantId?: string) => Promise<void>;
|
|
135
|
+
bindRoleToUser: (userId: string, roleId: string, tenantId?: string) => Promise<void>;
|
|
136
|
+
bindRoleToGroup: (groupId: string, roleId: string, tenantId?: string) => Promise<void>;
|
|
137
|
+
/** Omitted removes all scopes; null removes only the global binding; a string removes one tenant. */
|
|
138
|
+
unbindRole: (subjectType: SubjectType, subjectId: string, roleId: string, tenantId?: string | null) => Promise<void>;
|
|
139
|
+
bindPermissionToUser: (userId: string, permission: PermissionInput, tenantId?: string) => Promise<void>;
|
|
140
|
+
bindPermissionToGroup: (groupId: string, permission: PermissionInput, tenantId?: string) => Promise<void>;
|
|
141
|
+
unbindPermissionFromUser: (userId: string, permissionId: string, tenantId?: string | null) => Promise<void>;
|
|
142
|
+
unbindPermissionFromGroup: (groupId: string, permissionId: string, tenantId?: string | null) => Promise<void>;
|
|
143
|
+
createGroup: (name: string, description?: string) => Promise<Group>;
|
|
144
|
+
addUserToGroup: (groupId: string, userId: string) => Promise<void>;
|
|
145
|
+
removeUserFromGroup: (groupId: string, userId: string) => Promise<void>;
|
|
146
|
+
getResources: () => Promise<ResourceFile>;
|
|
147
|
+
getRoles: () => Promise<Role[]>;
|
|
148
|
+
/** Apply a resource map directly without filesystem access. */
|
|
149
|
+
pushResources: (resources: ResourceFile) => Promise<void>;
|
|
150
|
+
/** List role bindings: omitted scope means all, `null` means global only, string means one tenant. */
|
|
151
|
+
listRoleBindingsForSubject: (subject: Subject, tenantId?: string | null) => Promise<RoleBinding[]>;
|
|
152
|
+
syncResources: (direction: 'push' | 'pull', filePath?: string) => Promise<void>;
|
|
153
|
+
clearPermissionCache: () => void;
|
|
154
|
+
/**
|
|
155
|
+
* Register a listener for IAM mutation events. Multiple listeners are
|
|
156
|
+
* supported — each is invoked in registration order. Observer failures
|
|
157
|
+
* are routed to the configured logger at `error` level and never break
|
|
158
|
+
* IAM operations. Returns an unsubscribe function.
|
|
159
|
+
*/
|
|
160
|
+
addIamObserver: (listener: IamEventListener) => Unsubscribe;
|
|
161
|
+
/**
|
|
162
|
+
* Register a listener for individual permission checks. Fires on every
|
|
163
|
+
* `checkPermission` call with latency and cache-hit information. The
|
|
164
|
+
* listener signature is synchronous — see {@link PermissionCheckEvent}
|
|
165
|
+
* for rationale. Returns an unsubscribe function.
|
|
166
|
+
*/
|
|
167
|
+
addPermissionCheckObserver: (listener: PermissionCheckListener) => Unsubscribe;
|
|
168
|
+
getRole: (roleId: string) => Promise<Role & {
|
|
169
|
+
permissions: Permission[];
|
|
170
|
+
}>;
|
|
171
|
+
updateRole: (roleId: string, data: {
|
|
172
|
+
name?: string;
|
|
173
|
+
description?: string | null;
|
|
174
|
+
}) => Promise<Role>;
|
|
175
|
+
listGroups: (options?: {
|
|
176
|
+
limit?: number;
|
|
177
|
+
offset?: number;
|
|
178
|
+
}) => Promise<{
|
|
179
|
+
groups: Group[];
|
|
180
|
+
total: number;
|
|
181
|
+
}>;
|
|
182
|
+
getGroup: (groupId: string) => Promise<Group & {
|
|
183
|
+
users: FortressUser[];
|
|
184
|
+
}>;
|
|
185
|
+
updateGroup: (groupId: string, data: {
|
|
186
|
+
name?: string;
|
|
187
|
+
description?: string;
|
|
188
|
+
}) => Promise<Group>;
|
|
189
|
+
deleteGroup: (groupId: string) => Promise<void>;
|
|
190
|
+
getGroupUsers: (groupId: string) => Promise<FortressUser[]>;
|
|
191
|
+
listPermissions: (options?: {
|
|
192
|
+
resource?: string;
|
|
193
|
+
}) => Promise<Permission[]>;
|
|
194
|
+
createPermission: (permission: PermissionInput) => Promise<Permission>;
|
|
195
|
+
deletePermission: (permissionId: string) => Promise<void>;
|
|
196
|
+
addPermissionToRole: (roleId: string, permission: PermissionInput) => Promise<void>;
|
|
197
|
+
removePermissionFromRole: (roleId: string, permission: PermissionInput) => Promise<void>;
|
|
198
|
+
createServiceAccount: (input: CreateServiceAccountInput) => Promise<ServiceAccount>;
|
|
199
|
+
getServiceAccount: (id: string) => Promise<ServiceAccount>;
|
|
200
|
+
listServiceAccounts: (options?: {
|
|
201
|
+
limit?: number;
|
|
202
|
+
offset?: number;
|
|
203
|
+
}) => Promise<{
|
|
204
|
+
serviceAccounts: ServiceAccount[];
|
|
205
|
+
total: number;
|
|
206
|
+
}>;
|
|
207
|
+
updateServiceAccount: (id: string, data: {
|
|
208
|
+
displayName?: string | null;
|
|
209
|
+
description?: string | null;
|
|
210
|
+
isActive?: boolean;
|
|
211
|
+
}) => Promise<ServiceAccount>;
|
|
212
|
+
deleteServiceAccount: (id: string) => Promise<void>;
|
|
213
|
+
bindRoleToServiceAccount: (serviceAccountId: string, roleId: string, tenantId?: string) => Promise<void>;
|
|
214
|
+
/** Unbind across all scopes when omitted, global only for `null`, or one tenant for a string scope. */
|
|
215
|
+
unbindRoleFromServiceAccount: (serviceAccountId: string, roleId: string, tenantId?: string | null) => Promise<void>;
|
|
216
|
+
bindPermissionToServiceAccount: (serviceAccountId: string, permission: PermissionInput, tenantId?: string) => Promise<void>;
|
|
217
|
+
unbindPermissionFromServiceAccount: (serviceAccountId: string, permissionId: string, tenantId?: string | null) => Promise<void>;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Lifecycle event emitted by the auth service. Mirrors the IAM observer
|
|
222
|
+
* pattern (`addIamObserver`) so consumers — audit log, SIEM webhooks,
|
|
223
|
+
* telemetry plugins, Datadog adapters — can subscribe to auth events
|
|
224
|
+
* without reimplementing every hook individually.
|
|
225
|
+
*/
|
|
226
|
+
interface AuthEvent {
|
|
227
|
+
eventType: 'LOGIN_SUCCESS' | 'LOGIN_FAILURE' | 'LOGIN_PENDING' | 'LOGOUT' | 'REGISTER' | 'TOKEN_REFRESH' | 'TOKEN_REUSE_DETECTED' | 'TOKEN_REUSE_GRACED' | 'TOKEN_FINGERPRINT_MISMATCH' | 'MFA_VERIFY_SUCCESS' | 'MFA_VERIFY_FAILURE' | 'SESSION_EXPIRED_IDLE' | 'SESSION_EXPIRED_ABSOLUTE' | 'PASSWORD_BREACH_CHECK_DEGRADED' | 'IMPERSONATE';
|
|
228
|
+
actorId?: string;
|
|
229
|
+
identifier?: string;
|
|
230
|
+
method?: 'password' | 'oauth' | 'magic_link' | 'webauthn' | '2fa' | 'api_key';
|
|
231
|
+
ipAddress?: string;
|
|
232
|
+
userAgent?: string;
|
|
233
|
+
outcome?: 'success' | 'failure' | 'pending';
|
|
234
|
+
/** Set on `LOGIN_PENDING` — which additional step the sign-in is waiting on. */
|
|
235
|
+
pendingReason?: PendingReason;
|
|
236
|
+
/** Free-form sub-action label (e.g. the specific fingerprint/session action that fired the event). */
|
|
237
|
+
action?: string;
|
|
238
|
+
error?: {
|
|
239
|
+
message: string;
|
|
240
|
+
code?: string;
|
|
241
|
+
};
|
|
242
|
+
metadata?: Record<string, unknown>;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Async auth event listener. May return a Promise — if you `return` it, any
|
|
246
|
+
* rejection is routed to `config.logger.error`. Firing work via
|
|
247
|
+
* `void asyncWork()` inside a sync body is an explicit opt-out of that
|
|
248
|
+
* safety net; rejections will escape to the runtime's unhandled-rejection
|
|
249
|
+
* handler instead.
|
|
250
|
+
*/
|
|
251
|
+
type AuthEventListener = (event: AuthEvent) => void | Promise<void>;
|
|
252
|
+
interface AuthService {
|
|
253
|
+
login: (identifier: string, password: string, meta?: RequestMeta) => Promise<AuthResult>;
|
|
254
|
+
/** Consume a verified factor's continuation, rerun remaining gates, then issue tokens. */
|
|
255
|
+
completePendingAuth: (continuationToken: string, completion: unknown, meta?: RequestMeta) => Promise<AuthResult>;
|
|
256
|
+
/** Finish a trusted plugin-owned primary credential (for example a magic link). */
|
|
257
|
+
completePluginAuth: (userId: string, method: Exclude<AuthMethod, 'refresh' | 'impersonation'>, meta?: RequestMeta) => Promise<AuthResult>;
|
|
258
|
+
refresh: (refreshToken: string, meta?: RequestMeta) => Promise<AuthTokenPair>;
|
|
259
|
+
logout: (refreshToken: string) => Promise<void>;
|
|
260
|
+
me: (userId: string) => Promise<FortressUser>;
|
|
261
|
+
createUser: (data: CreateUserInput) => Promise<FortressUser>;
|
|
262
|
+
verifyToken: (token: string) => Promise<TokenClaims>;
|
|
263
|
+
signToken: (claims: Omit<TokenClaims, 'iat' | 'exp' | 'aud'>) => Promise<string>;
|
|
264
|
+
listSessions: (userId: string) => Promise<SessionInfo[]>;
|
|
265
|
+
revokeSession: (userId: string, tokenId: string) => Promise<void>;
|
|
266
|
+
revokeAllOtherSessions: (userId: string, currentTokenId: string) => Promise<void>;
|
|
267
|
+
addLoginIdentifier: (userId: string, type: LoginIdentifierType, value: string) => Promise<void>;
|
|
268
|
+
removeLoginIdentifier: (userId: string, type: LoginIdentifierType, value: string) => Promise<void>;
|
|
269
|
+
getLoginIdentifiers: (userId: string) => Promise<LoginIdentifier[]>;
|
|
270
|
+
/**
|
|
271
|
+
* Issue a short-lived, non-renewable access token that lets an admin act as another user.
|
|
272
|
+
* The token carries an RFC 8693 `act` claim identifying the real admin.
|
|
273
|
+
*
|
|
274
|
+
* Requires the admin user to hold `fortress:impersonate`. The built-in HTTP route also enforces this via endpoint metadata.
|
|
275
|
+
*/
|
|
276
|
+
impersonate: (adminUserId: string, targetUserId: string, options?: {
|
|
277
|
+
reason?: string;
|
|
278
|
+
expirySeconds?: number;
|
|
279
|
+
}) => Promise<AuthResult>;
|
|
280
|
+
listUsers: (options: {
|
|
281
|
+
limit?: number;
|
|
282
|
+
offset?: number;
|
|
283
|
+
search?: string;
|
|
284
|
+
sortBy?: string;
|
|
285
|
+
sortDirection?: 'asc' | 'desc';
|
|
286
|
+
}) => Promise<{
|
|
287
|
+
users: FortressUser[];
|
|
288
|
+
total: number;
|
|
289
|
+
}>;
|
|
290
|
+
getUserById: (userId: string) => Promise<FortressUser>;
|
|
291
|
+
updateUser: (userId: string, data: {
|
|
292
|
+
name?: string;
|
|
293
|
+
email?: string;
|
|
294
|
+
isActive?: boolean;
|
|
295
|
+
password?: string;
|
|
296
|
+
}) => Promise<FortressUser>;
|
|
297
|
+
deleteUser: (userId: string) => Promise<void>;
|
|
298
|
+
/**
|
|
299
|
+
* Register a listener for auth lifecycle events. Multiple listeners are
|
|
300
|
+
* supported — each is invoked in registration order. Listener failures
|
|
301
|
+
* never break auth operations; they are routed to the configured logger
|
|
302
|
+
* at `error` level. Returns an unsubscribe function.
|
|
303
|
+
*/
|
|
304
|
+
addAuthObserver: (listener: AuthEventListener) => Unsubscribe;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export { type AttributeValue as A, type Counter as C, type FortressLogger as F, type Histogram as H, type IamEvent as I, type Meter as M, type PermissionCheckEvent as P, type ResourceDefinition as R, type Span as S, type TelemetryProvider as T, type Unsubscribe as U, type Attributes as a, type AuthEvent as b, type AuthEventListener as c, type IamEventListener as d, type PermissionCheckListener as e, type Tracer as f, type IamService as g, type ResourceFile as h, type AuthService as i, parseResourceFile as p };
|