@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,254 @@
|
|
|
1
|
+
import { S as StandardSchemaV1, F as FortressPlugin } from '../config-GtlVt6ZD.cjs';
|
|
2
|
+
import { FetchFn } from '@bajustone/fetcher';
|
|
3
|
+
import { D as DatabaseAdapter } from '../index-CxEkfCA0.cjs';
|
|
4
|
+
import '../jwt.cjs';
|
|
5
|
+
import '../types-et0R8tsC.cjs';
|
|
6
|
+
import '../auth-service-BcyQ2PuZ.cjs';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Webhook delivery over `@bajustone/fetcher`.
|
|
10
|
+
*
|
|
11
|
+
* fetcher is 100% native `fetch` and does **no** IP pinning of its own, so the
|
|
12
|
+
* SSRF guard must live *inside* the transport: {@link ssrfSafeFetch} is a
|
|
13
|
+
* fetcher `FetchFn` that resolves + validates the target and issues the request
|
|
14
|
+
* through `node:https` with a custom `lookup` that pins the connection to the
|
|
15
|
+
* resolved IP — closing the DNS-rebinding window. A plain fetch (or a
|
|
16
|
+
* pre-flight check followed by a normal fetch) would re-resolve DNS and reopen
|
|
17
|
+
* that window, so the guard MUST be the transport.
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/** How retries are handled for a delivery client. See the webhook config docs. */
|
|
23
|
+
type RetryMode = 'pluginScheduled' | 'inProcess' | 'queue';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Bring-Your-Own-Queue interface. Delivery is always queued; consumers can
|
|
27
|
+
* back it with any system (in-memory, DB, BullMQ, SQS, Cloudflare Queues,
|
|
28
|
+
* Inngest, …) by implementing this small surface.
|
|
29
|
+
*
|
|
30
|
+
* @module
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/** One unit of delivery work — a single attempt of a single delivery row. */
|
|
34
|
+
interface WebhookQueueJob {
|
|
35
|
+
deliveryId: string;
|
|
36
|
+
endpointId: string;
|
|
37
|
+
eventType: string;
|
|
38
|
+
/** 1-based attempt number. */
|
|
39
|
+
attempt: number;
|
|
40
|
+
/** When this attempt should run (retries); absent means "now". */
|
|
41
|
+
scheduledFor?: Date;
|
|
42
|
+
}
|
|
43
|
+
/** Context handed to {@link WebhookQueue.start} so fortress-aware queues can reach the DB. */
|
|
44
|
+
interface WebhookQueueContext {
|
|
45
|
+
/** The fortress database adapter — used by the database queue to poll, and for the startup recovery sweep. */
|
|
46
|
+
db: DatabaseAdapter;
|
|
47
|
+
}
|
|
48
|
+
interface WebhookQueue {
|
|
49
|
+
/**
|
|
50
|
+
* If true, the plugin re-throws on failed delivery and the queue is expected
|
|
51
|
+
* to retry per its own policy (BullMQ/SQS/Inngest). If false/absent, the
|
|
52
|
+
* plugin schedules retries itself.
|
|
53
|
+
*/
|
|
54
|
+
handlesRetries?: boolean;
|
|
55
|
+
/** Enqueue a delivery job. (A no-op for the database queue — the table IS the queue.) */
|
|
56
|
+
enqueue: (job: WebhookQueueJob) => Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Optional worker registration. Pull queues (in-memory, database) implement
|
|
59
|
+
* this; push/serverless queues (Cloudflare Queues with a separate consumer,
|
|
60
|
+
* Inngest, …) leave it undefined. Returns a teardown the consumer calls on
|
|
61
|
+
* shutdown. Implementations SHOULD run a startup recovery sweep here —
|
|
62
|
+
* re-enqueue rows left `pending` by a prior process — so at-least-once holds
|
|
63
|
+
* across restarts.
|
|
64
|
+
*/
|
|
65
|
+
start?: (handler: (job: WebhookQueueJob) => Promise<void>, ctx: WebhookQueueContext) => Promise<() => Promise<void>>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Public types for the webhook plugin v1 (custom events + Bring-Your-Own-Queue).
|
|
70
|
+
*
|
|
71
|
+
* @module
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
/** A fortress lifecycle hook a built-in event auto-emits from. */
|
|
75
|
+
type BuiltinEventSource = 'afterLogin' | 'onLoginFailure' | 'beforeLogout' | 'afterRegister' | 'afterTokenRefresh';
|
|
76
|
+
/**
|
|
77
|
+
* Declares an event consumers (or the built-ins) can emit. Built-in auth events
|
|
78
|
+
* and user-defined events share this one shape and the same emit path.
|
|
79
|
+
*/
|
|
80
|
+
interface WebhookEventDeclaration<S extends StandardSchemaV1 = StandardSchemaV1> {
|
|
81
|
+
/** Dot-cased event name, e.g. `auth.login.success` or `order.paid`. */
|
|
82
|
+
name: string;
|
|
83
|
+
description?: string;
|
|
84
|
+
/** Standard Schema V1 validator (fortress builder, fetcher builder, Zod, …); the payload is validated at `emit()` time. */
|
|
85
|
+
schema?: S;
|
|
86
|
+
/** If set, the plugin auto-emits this event from the named fortress hook. */
|
|
87
|
+
source?: BuiltinEventSource;
|
|
88
|
+
}
|
|
89
|
+
/** Stable delivery failure taxonomy persisted in `webhook_delivery.error_kind`. */
|
|
90
|
+
type WebhookErrorKind = 'http' | 'network';
|
|
91
|
+
/** Stable endpoint deactivation reason taxonomy. */
|
|
92
|
+
type WebhookDeactivatedReason = `permanent_${number}` | 'too_many_failures';
|
|
93
|
+
/** A registered delivery endpoint. `secret` is redacted from `listEndpoints()`. */
|
|
94
|
+
interface WebhookEndpoint {
|
|
95
|
+
id: string;
|
|
96
|
+
url: string;
|
|
97
|
+
events: string;
|
|
98
|
+
secret: string;
|
|
99
|
+
isActive: boolean;
|
|
100
|
+
deactivatedReason: WebhookDeactivatedReason | null;
|
|
101
|
+
consecutiveFailures: number;
|
|
102
|
+
createdAt: Date;
|
|
103
|
+
}
|
|
104
|
+
/** A persisted delivery attempt row — the transactional outbox record. */
|
|
105
|
+
interface WebhookDelivery {
|
|
106
|
+
id: string;
|
|
107
|
+
endpointId: string;
|
|
108
|
+
eventType: string;
|
|
109
|
+
payload: string;
|
|
110
|
+
status: 'pending' | 'success' | 'failed';
|
|
111
|
+
attempts: number;
|
|
112
|
+
idempotencyKey: string | null;
|
|
113
|
+
lastAttemptAt: Date | null;
|
|
114
|
+
nextRetryAt: Date | null;
|
|
115
|
+
responseStatus: number | null;
|
|
116
|
+
responseBody: string | null;
|
|
117
|
+
errorKind: WebhookErrorKind | null;
|
|
118
|
+
createdAt: Date;
|
|
119
|
+
}
|
|
120
|
+
/** Delivery tuning + observability seams. */
|
|
121
|
+
interface WebhookDeliveryConfig {
|
|
122
|
+
/** Per-attempt timeout (ms). Default 10_000. */
|
|
123
|
+
timeoutMs?: number;
|
|
124
|
+
/** Who owns retries. Default `'pluginScheduled'`. */
|
|
125
|
+
retry?: RetryMode;
|
|
126
|
+
/** Statuses that permanently deactivate an endpoint. Default `[404, 410, 421]`. */
|
|
127
|
+
permanentStatuses?: number[];
|
|
128
|
+
/** Consecutive failures before the circuit breaker deactivates an endpoint. Default 15. */
|
|
129
|
+
maxConsecutiveFailures?: number;
|
|
130
|
+
/** Called on a terminal `failed` delivery — the DLQ/alert seam. */
|
|
131
|
+
onDeliveryFailed?: (delivery: WebhookDelivery) => void | Promise<void>;
|
|
132
|
+
/** Called when an endpoint is auto-deactivated (permanent status or circuit breaker). */
|
|
133
|
+
onEndpointDeactivated?: (endpoint: WebhookEndpoint, reason: WebhookDeactivatedReason) => void | Promise<void>;
|
|
134
|
+
/**
|
|
135
|
+
* Override the delivery transport (a fetcher `FetchFn`). Defaults to the
|
|
136
|
+
* SSRF-guarded `ssrfSafeFetch()`. Use for custom transports or to intercept
|
|
137
|
+
* delivery in tests — **bypasses the SSRF guard**, so only override when you
|
|
138
|
+
* control the targets.
|
|
139
|
+
*/
|
|
140
|
+
fetch?: FetchFn;
|
|
141
|
+
}
|
|
142
|
+
/** Options for `emit()`. */
|
|
143
|
+
interface EmitOptions {
|
|
144
|
+
/** Dedup key — a second `emit` with the same `(endpoint, idempotencyKey)` is a no-op. */
|
|
145
|
+
idempotencyKey?: string;
|
|
146
|
+
}
|
|
147
|
+
/** Options for `registerEndpoint()`. */
|
|
148
|
+
interface RegisterEndpointOptions {
|
|
149
|
+
/** Signing secret. If omitted, a CSPRNG secret is generated and returned once. */
|
|
150
|
+
secret?: string;
|
|
151
|
+
}
|
|
152
|
+
/** Patch accepted by `updateEndpoint()`. */
|
|
153
|
+
interface UpdateEndpointPatch {
|
|
154
|
+
url?: string;
|
|
155
|
+
events?: string[];
|
|
156
|
+
isActive?: boolean;
|
|
157
|
+
}
|
|
158
|
+
/** An endpoint with `secret` removed — the shape returned by `listEndpoints()`/`updateEndpoint()`. */
|
|
159
|
+
type RedactedWebhookEndpoint = Omit<WebhookEndpoint, 'secret'>;
|
|
160
|
+
interface WebhookConfig {
|
|
161
|
+
/** Event registry. Defaults to {@link import('./builtin-events').builtinEvents}(). */
|
|
162
|
+
events?: WebhookEventDeclaration[];
|
|
163
|
+
/** Delivery queue (BYOQ). Defaults to the dev-only `inMemoryQueue()`. */
|
|
164
|
+
queue?: WebhookQueue;
|
|
165
|
+
/** Maximum delivery retries. Default 5. */
|
|
166
|
+
maxRetries?: number;
|
|
167
|
+
/** Reject `emit()` payloads larger than this many bytes. Default 262144 (256 KB). */
|
|
168
|
+
maxPayloadBytes?: number;
|
|
169
|
+
delivery?: WebhookDeliveryConfig;
|
|
170
|
+
}
|
|
171
|
+
/** Distinct, catchable failure codes thrown by `emit()`. */
|
|
172
|
+
type WebhookEmitErrorCode = 'unknown_event' | 'invalid_payload' | 'payload_too_large';
|
|
173
|
+
/** Thrown by `emit()` so callers can branch on `code` instead of string-matching. */
|
|
174
|
+
declare class WebhookEmitError extends Error {
|
|
175
|
+
readonly code: WebhookEmitErrorCode;
|
|
176
|
+
constructor(code: WebhookEmitErrorCode, message: string);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Built-in auth events. These go through the same registry + emit path as
|
|
181
|
+
* user-defined events; the plugin merges them in by default and consumers can
|
|
182
|
+
* exclude individual ones via `builtinEvents({ exclude })`.
|
|
183
|
+
*
|
|
184
|
+
* @module
|
|
185
|
+
*/
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* The built-in auth event declarations. Pass `{ exclude: [...] }` to drop
|
|
189
|
+
* individual ones (their auto-emit hook then becomes a no-op).
|
|
190
|
+
*/
|
|
191
|
+
declare function builtinEvents(opts?: {
|
|
192
|
+
exclude?: string[];
|
|
193
|
+
}): WebhookEventDeclaration[];
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Crash-safe bundled queue: polls `webhook_delivery` for due `pending` rows and
|
|
197
|
+
* drives delivery. The `webhook_delivery` table is the transactional outbox, so
|
|
198
|
+
* `enqueue` is a no-op — the row already exists and the poller picks it up.
|
|
199
|
+
* This is the only bundled queue that survives a process restart.
|
|
200
|
+
*
|
|
201
|
+
* @module
|
|
202
|
+
*/
|
|
203
|
+
|
|
204
|
+
declare function databaseQueue(opts?: {
|
|
205
|
+
pollMs?: number;
|
|
206
|
+
}): WebhookQueue;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* `setTimeout`-driven, single-process queue. The **default** when no queue is
|
|
210
|
+
* configured.
|
|
211
|
+
*
|
|
212
|
+
* **Dev-only.** Scheduled retries live in in-process timers, so a restart
|
|
213
|
+
* **loses every pending retry** — the `webhook_delivery` row stays `pending`
|
|
214
|
+
* but nothing re-attempts it until the next process runs its startup recovery
|
|
215
|
+
* sweep (see {@link inMemoryQueue}'s `start`). Use {@link import('./database').databaseQueue}
|
|
216
|
+
* (or a real broker) in production.
|
|
217
|
+
*
|
|
218
|
+
* @module
|
|
219
|
+
*/
|
|
220
|
+
|
|
221
|
+
declare function inMemoryQueue(): WebhookQueue;
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Resolve `url` and throw when it points at a loopback, link-local, RFC1918,
|
|
225
|
+
* or otherwise non-public address. Exported for tests and for custom delivery
|
|
226
|
+
* transports that want to reuse fortress's SSRF guard. The built-in transport
|
|
227
|
+
* (`delivery.ts`) already calls {@link resolveSafeWebhookTarget} and pins the
|
|
228
|
+
* resolved IP, so callers using it do not need to invoke this themselves.
|
|
229
|
+
*/
|
|
230
|
+
declare function assertSafeWebhookUrl(url: string): Promise<void>;
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Webhook delivery plugin for fortress (v1).
|
|
234
|
+
*
|
|
235
|
+
* - **Custom events** — declare and `emit()` your own events through the same
|
|
236
|
+
* path the built-in auth events use.
|
|
237
|
+
* - **Bring-Your-Own-Queue** — delivery is always queued; plug in any backend
|
|
238
|
+
* via {@link import('./queue/types').WebhookQueue}. Defaults to the dev-only
|
|
239
|
+
* {@link inMemoryQueue}; use {@link databaseQueue} (crash-safe) or a broker in prod.
|
|
240
|
+
* - **Standard Webhooks** signing (HMAC-SHA256), with a stable per-delivery
|
|
241
|
+
* `webhook-id` for receiver-side idempotency.
|
|
242
|
+
* - **SSRF-safe delivery** over `@bajustone/fetcher` with connect-time IP pinning.
|
|
243
|
+
* - Failure classification, jittered backoff, circuit-breaker auto-deactivation,
|
|
244
|
+
* and DLQ observability hooks.
|
|
245
|
+
*
|
|
246
|
+
* @module
|
|
247
|
+
*/
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Webhook plugin factory. See the module docs for the full feature set.
|
|
251
|
+
*/
|
|
252
|
+
declare function webhook(config?: WebhookConfig): FortressPlugin;
|
|
253
|
+
|
|
254
|
+
export { type EmitOptions, type RedactedWebhookEndpoint, type RegisterEndpointOptions, type UpdateEndpointPatch, type WebhookConfig, type WebhookDeactivatedReason, type WebhookDelivery, type WebhookDeliveryConfig, WebhookEmitError, type WebhookEmitErrorCode, type WebhookEndpoint, type WebhookErrorKind, type WebhookEventDeclaration, type WebhookQueue, type WebhookQueueContext, type WebhookQueueJob, assertSafeWebhookUrl, builtinEvents, databaseQueue, inMemoryQueue, webhook };
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { S as StandardSchemaV1, F as FortressPlugin } from '../config-B2366s_G.js';
|
|
2
|
+
import { FetchFn } from '@bajustone/fetcher';
|
|
3
|
+
import { D as DatabaseAdapter } from '../index-CxEkfCA0.js';
|
|
4
|
+
import '../jwt.js';
|
|
5
|
+
import '../types-et0R8tsC.js';
|
|
6
|
+
import '../auth-service-BkzZkWfH.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Webhook delivery over `@bajustone/fetcher`.
|
|
10
|
+
*
|
|
11
|
+
* fetcher is 100% native `fetch` and does **no** IP pinning of its own, so the
|
|
12
|
+
* SSRF guard must live *inside* the transport: {@link ssrfSafeFetch} is a
|
|
13
|
+
* fetcher `FetchFn` that resolves + validates the target and issues the request
|
|
14
|
+
* through `node:https` with a custom `lookup` that pins the connection to the
|
|
15
|
+
* resolved IP — closing the DNS-rebinding window. A plain fetch (or a
|
|
16
|
+
* pre-flight check followed by a normal fetch) would re-resolve DNS and reopen
|
|
17
|
+
* that window, so the guard MUST be the transport.
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/** How retries are handled for a delivery client. See the webhook config docs. */
|
|
23
|
+
type RetryMode = 'pluginScheduled' | 'inProcess' | 'queue';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Bring-Your-Own-Queue interface. Delivery is always queued; consumers can
|
|
27
|
+
* back it with any system (in-memory, DB, BullMQ, SQS, Cloudflare Queues,
|
|
28
|
+
* Inngest, …) by implementing this small surface.
|
|
29
|
+
*
|
|
30
|
+
* @module
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/** One unit of delivery work — a single attempt of a single delivery row. */
|
|
34
|
+
interface WebhookQueueJob {
|
|
35
|
+
deliveryId: string;
|
|
36
|
+
endpointId: string;
|
|
37
|
+
eventType: string;
|
|
38
|
+
/** 1-based attempt number. */
|
|
39
|
+
attempt: number;
|
|
40
|
+
/** When this attempt should run (retries); absent means "now". */
|
|
41
|
+
scheduledFor?: Date;
|
|
42
|
+
}
|
|
43
|
+
/** Context handed to {@link WebhookQueue.start} so fortress-aware queues can reach the DB. */
|
|
44
|
+
interface WebhookQueueContext {
|
|
45
|
+
/** The fortress database adapter — used by the database queue to poll, and for the startup recovery sweep. */
|
|
46
|
+
db: DatabaseAdapter;
|
|
47
|
+
}
|
|
48
|
+
interface WebhookQueue {
|
|
49
|
+
/**
|
|
50
|
+
* If true, the plugin re-throws on failed delivery and the queue is expected
|
|
51
|
+
* to retry per its own policy (BullMQ/SQS/Inngest). If false/absent, the
|
|
52
|
+
* plugin schedules retries itself.
|
|
53
|
+
*/
|
|
54
|
+
handlesRetries?: boolean;
|
|
55
|
+
/** Enqueue a delivery job. (A no-op for the database queue — the table IS the queue.) */
|
|
56
|
+
enqueue: (job: WebhookQueueJob) => Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Optional worker registration. Pull queues (in-memory, database) implement
|
|
59
|
+
* this; push/serverless queues (Cloudflare Queues with a separate consumer,
|
|
60
|
+
* Inngest, …) leave it undefined. Returns a teardown the consumer calls on
|
|
61
|
+
* shutdown. Implementations SHOULD run a startup recovery sweep here —
|
|
62
|
+
* re-enqueue rows left `pending` by a prior process — so at-least-once holds
|
|
63
|
+
* across restarts.
|
|
64
|
+
*/
|
|
65
|
+
start?: (handler: (job: WebhookQueueJob) => Promise<void>, ctx: WebhookQueueContext) => Promise<() => Promise<void>>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Public types for the webhook plugin v1 (custom events + Bring-Your-Own-Queue).
|
|
70
|
+
*
|
|
71
|
+
* @module
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
/** A fortress lifecycle hook a built-in event auto-emits from. */
|
|
75
|
+
type BuiltinEventSource = 'afterLogin' | 'onLoginFailure' | 'beforeLogout' | 'afterRegister' | 'afterTokenRefresh';
|
|
76
|
+
/**
|
|
77
|
+
* Declares an event consumers (or the built-ins) can emit. Built-in auth events
|
|
78
|
+
* and user-defined events share this one shape and the same emit path.
|
|
79
|
+
*/
|
|
80
|
+
interface WebhookEventDeclaration<S extends StandardSchemaV1 = StandardSchemaV1> {
|
|
81
|
+
/** Dot-cased event name, e.g. `auth.login.success` or `order.paid`. */
|
|
82
|
+
name: string;
|
|
83
|
+
description?: string;
|
|
84
|
+
/** Standard Schema V1 validator (fortress builder, fetcher builder, Zod, …); the payload is validated at `emit()` time. */
|
|
85
|
+
schema?: S;
|
|
86
|
+
/** If set, the plugin auto-emits this event from the named fortress hook. */
|
|
87
|
+
source?: BuiltinEventSource;
|
|
88
|
+
}
|
|
89
|
+
/** Stable delivery failure taxonomy persisted in `webhook_delivery.error_kind`. */
|
|
90
|
+
type WebhookErrorKind = 'http' | 'network';
|
|
91
|
+
/** Stable endpoint deactivation reason taxonomy. */
|
|
92
|
+
type WebhookDeactivatedReason = `permanent_${number}` | 'too_many_failures';
|
|
93
|
+
/** A registered delivery endpoint. `secret` is redacted from `listEndpoints()`. */
|
|
94
|
+
interface WebhookEndpoint {
|
|
95
|
+
id: string;
|
|
96
|
+
url: string;
|
|
97
|
+
events: string;
|
|
98
|
+
secret: string;
|
|
99
|
+
isActive: boolean;
|
|
100
|
+
deactivatedReason: WebhookDeactivatedReason | null;
|
|
101
|
+
consecutiveFailures: number;
|
|
102
|
+
createdAt: Date;
|
|
103
|
+
}
|
|
104
|
+
/** A persisted delivery attempt row — the transactional outbox record. */
|
|
105
|
+
interface WebhookDelivery {
|
|
106
|
+
id: string;
|
|
107
|
+
endpointId: string;
|
|
108
|
+
eventType: string;
|
|
109
|
+
payload: string;
|
|
110
|
+
status: 'pending' | 'success' | 'failed';
|
|
111
|
+
attempts: number;
|
|
112
|
+
idempotencyKey: string | null;
|
|
113
|
+
lastAttemptAt: Date | null;
|
|
114
|
+
nextRetryAt: Date | null;
|
|
115
|
+
responseStatus: number | null;
|
|
116
|
+
responseBody: string | null;
|
|
117
|
+
errorKind: WebhookErrorKind | null;
|
|
118
|
+
createdAt: Date;
|
|
119
|
+
}
|
|
120
|
+
/** Delivery tuning + observability seams. */
|
|
121
|
+
interface WebhookDeliveryConfig {
|
|
122
|
+
/** Per-attempt timeout (ms). Default 10_000. */
|
|
123
|
+
timeoutMs?: number;
|
|
124
|
+
/** Who owns retries. Default `'pluginScheduled'`. */
|
|
125
|
+
retry?: RetryMode;
|
|
126
|
+
/** Statuses that permanently deactivate an endpoint. Default `[404, 410, 421]`. */
|
|
127
|
+
permanentStatuses?: number[];
|
|
128
|
+
/** Consecutive failures before the circuit breaker deactivates an endpoint. Default 15. */
|
|
129
|
+
maxConsecutiveFailures?: number;
|
|
130
|
+
/** Called on a terminal `failed` delivery — the DLQ/alert seam. */
|
|
131
|
+
onDeliveryFailed?: (delivery: WebhookDelivery) => void | Promise<void>;
|
|
132
|
+
/** Called when an endpoint is auto-deactivated (permanent status or circuit breaker). */
|
|
133
|
+
onEndpointDeactivated?: (endpoint: WebhookEndpoint, reason: WebhookDeactivatedReason) => void | Promise<void>;
|
|
134
|
+
/**
|
|
135
|
+
* Override the delivery transport (a fetcher `FetchFn`). Defaults to the
|
|
136
|
+
* SSRF-guarded `ssrfSafeFetch()`. Use for custom transports or to intercept
|
|
137
|
+
* delivery in tests — **bypasses the SSRF guard**, so only override when you
|
|
138
|
+
* control the targets.
|
|
139
|
+
*/
|
|
140
|
+
fetch?: FetchFn;
|
|
141
|
+
}
|
|
142
|
+
/** Options for `emit()`. */
|
|
143
|
+
interface EmitOptions {
|
|
144
|
+
/** Dedup key — a second `emit` with the same `(endpoint, idempotencyKey)` is a no-op. */
|
|
145
|
+
idempotencyKey?: string;
|
|
146
|
+
}
|
|
147
|
+
/** Options for `registerEndpoint()`. */
|
|
148
|
+
interface RegisterEndpointOptions {
|
|
149
|
+
/** Signing secret. If omitted, a CSPRNG secret is generated and returned once. */
|
|
150
|
+
secret?: string;
|
|
151
|
+
}
|
|
152
|
+
/** Patch accepted by `updateEndpoint()`. */
|
|
153
|
+
interface UpdateEndpointPatch {
|
|
154
|
+
url?: string;
|
|
155
|
+
events?: string[];
|
|
156
|
+
isActive?: boolean;
|
|
157
|
+
}
|
|
158
|
+
/** An endpoint with `secret` removed — the shape returned by `listEndpoints()`/`updateEndpoint()`. */
|
|
159
|
+
type RedactedWebhookEndpoint = Omit<WebhookEndpoint, 'secret'>;
|
|
160
|
+
interface WebhookConfig {
|
|
161
|
+
/** Event registry. Defaults to {@link import('./builtin-events').builtinEvents}(). */
|
|
162
|
+
events?: WebhookEventDeclaration[];
|
|
163
|
+
/** Delivery queue (BYOQ). Defaults to the dev-only `inMemoryQueue()`. */
|
|
164
|
+
queue?: WebhookQueue;
|
|
165
|
+
/** Maximum delivery retries. Default 5. */
|
|
166
|
+
maxRetries?: number;
|
|
167
|
+
/** Reject `emit()` payloads larger than this many bytes. Default 262144 (256 KB). */
|
|
168
|
+
maxPayloadBytes?: number;
|
|
169
|
+
delivery?: WebhookDeliveryConfig;
|
|
170
|
+
}
|
|
171
|
+
/** Distinct, catchable failure codes thrown by `emit()`. */
|
|
172
|
+
type WebhookEmitErrorCode = 'unknown_event' | 'invalid_payload' | 'payload_too_large';
|
|
173
|
+
/** Thrown by `emit()` so callers can branch on `code` instead of string-matching. */
|
|
174
|
+
declare class WebhookEmitError extends Error {
|
|
175
|
+
readonly code: WebhookEmitErrorCode;
|
|
176
|
+
constructor(code: WebhookEmitErrorCode, message: string);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Built-in auth events. These go through the same registry + emit path as
|
|
181
|
+
* user-defined events; the plugin merges them in by default and consumers can
|
|
182
|
+
* exclude individual ones via `builtinEvents({ exclude })`.
|
|
183
|
+
*
|
|
184
|
+
* @module
|
|
185
|
+
*/
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* The built-in auth event declarations. Pass `{ exclude: [...] }` to drop
|
|
189
|
+
* individual ones (their auto-emit hook then becomes a no-op).
|
|
190
|
+
*/
|
|
191
|
+
declare function builtinEvents(opts?: {
|
|
192
|
+
exclude?: string[];
|
|
193
|
+
}): WebhookEventDeclaration[];
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Crash-safe bundled queue: polls `webhook_delivery` for due `pending` rows and
|
|
197
|
+
* drives delivery. The `webhook_delivery` table is the transactional outbox, so
|
|
198
|
+
* `enqueue` is a no-op — the row already exists and the poller picks it up.
|
|
199
|
+
* This is the only bundled queue that survives a process restart.
|
|
200
|
+
*
|
|
201
|
+
* @module
|
|
202
|
+
*/
|
|
203
|
+
|
|
204
|
+
declare function databaseQueue(opts?: {
|
|
205
|
+
pollMs?: number;
|
|
206
|
+
}): WebhookQueue;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* `setTimeout`-driven, single-process queue. The **default** when no queue is
|
|
210
|
+
* configured.
|
|
211
|
+
*
|
|
212
|
+
* **Dev-only.** Scheduled retries live in in-process timers, so a restart
|
|
213
|
+
* **loses every pending retry** — the `webhook_delivery` row stays `pending`
|
|
214
|
+
* but nothing re-attempts it until the next process runs its startup recovery
|
|
215
|
+
* sweep (see {@link inMemoryQueue}'s `start`). Use {@link import('./database').databaseQueue}
|
|
216
|
+
* (or a real broker) in production.
|
|
217
|
+
*
|
|
218
|
+
* @module
|
|
219
|
+
*/
|
|
220
|
+
|
|
221
|
+
declare function inMemoryQueue(): WebhookQueue;
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Resolve `url` and throw when it points at a loopback, link-local, RFC1918,
|
|
225
|
+
* or otherwise non-public address. Exported for tests and for custom delivery
|
|
226
|
+
* transports that want to reuse fortress's SSRF guard. The built-in transport
|
|
227
|
+
* (`delivery.ts`) already calls {@link resolveSafeWebhookTarget} and pins the
|
|
228
|
+
* resolved IP, so callers using it do not need to invoke this themselves.
|
|
229
|
+
*/
|
|
230
|
+
declare function assertSafeWebhookUrl(url: string): Promise<void>;
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Webhook delivery plugin for fortress (v1).
|
|
234
|
+
*
|
|
235
|
+
* - **Custom events** — declare and `emit()` your own events through the same
|
|
236
|
+
* path the built-in auth events use.
|
|
237
|
+
* - **Bring-Your-Own-Queue** — delivery is always queued; plug in any backend
|
|
238
|
+
* via {@link import('./queue/types').WebhookQueue}. Defaults to the dev-only
|
|
239
|
+
* {@link inMemoryQueue}; use {@link databaseQueue} (crash-safe) or a broker in prod.
|
|
240
|
+
* - **Standard Webhooks** signing (HMAC-SHA256), with a stable per-delivery
|
|
241
|
+
* `webhook-id` for receiver-side idempotency.
|
|
242
|
+
* - **SSRF-safe delivery** over `@bajustone/fetcher` with connect-time IP pinning.
|
|
243
|
+
* - Failure classification, jittered backoff, circuit-breaker auto-deactivation,
|
|
244
|
+
* and DLQ observability hooks.
|
|
245
|
+
*
|
|
246
|
+
* @module
|
|
247
|
+
*/
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Webhook plugin factory. See the module docs for the full feature set.
|
|
251
|
+
*/
|
|
252
|
+
declare function webhook(config?: WebhookConfig): FortressPlugin;
|
|
253
|
+
|
|
254
|
+
export { type EmitOptions, type RedactedWebhookEndpoint, type RegisterEndpointOptions, type UpdateEndpointPatch, type WebhookConfig, type WebhookDeactivatedReason, type WebhookDelivery, type WebhookDeliveryConfig, WebhookEmitError, type WebhookEmitErrorCode, type WebhookEndpoint, type WebhookErrorKind, type WebhookEventDeclaration, type WebhookQueue, type WebhookQueueContext, type WebhookQueueJob, assertSafeWebhookUrl, builtinEvents, databaseQueue, inMemoryQueue, webhook };
|