@portaidentity/server 1.7.0
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 +11 -0
- package/LICENSE +21 -0
- package/README.md +33 -0
- package/dist/applications/cache.d.ts +64 -0
- package/dist/applications/cache.d.ts.map +1 -0
- package/dist/applications/cache.js +161 -0
- package/dist/applications/cache.js.map +1 -0
- package/dist/applications/errors.d.ts +25 -0
- package/dist/applications/errors.d.ts.map +1 -0
- package/dist/applications/errors.js +31 -0
- package/dist/applications/errors.js.map +1 -0
- package/dist/applications/index.d.ts +17 -0
- package/dist/applications/index.d.ts.map +1 -0
- package/dist/applications/index.js +19 -0
- package/dist/applications/index.js.map +1 -0
- package/dist/applications/repository.d.ts +184 -0
- package/dist/applications/repository.d.ts.map +1 -0
- package/dist/applications/repository.js +367 -0
- package/dist/applications/repository.js.map +1 -0
- package/dist/applications/service.d.ts +160 -0
- package/dist/applications/service.d.ts.map +1 -0
- package/dist/applications/service.js +388 -0
- package/dist/applications/service.js.map +1 -0
- package/dist/applications/slugs.d.ts +61 -0
- package/dist/applications/slugs.d.ts.map +1 -0
- package/dist/applications/slugs.js +115 -0
- package/dist/applications/slugs.js.map +1 -0
- package/dist/applications/types.d.ts +129 -0
- package/dist/applications/types.d.ts.map +1 -0
- package/dist/applications/types.js +62 -0
- package/dist/applications/types.js.map +1 -0
- package/dist/auth/csrf.d.ts +71 -0
- package/dist/auth/csrf.d.ts.map +1 -0
- package/dist/auth/csrf.js +112 -0
- package/dist/auth/csrf.js.map +1 -0
- package/dist/auth/email-renderer.d.ts +37 -0
- package/dist/auth/email-renderer.d.ts.map +1 -0
- package/dist/auth/email-renderer.js +116 -0
- package/dist/auth/email-renderer.js.map +1 -0
- package/dist/auth/email-service.d.ts +154 -0
- package/dist/auth/email-service.d.ts.map +1 -0
- package/dist/auth/email-service.js +415 -0
- package/dist/auth/email-service.js.map +1 -0
- package/dist/auth/email-transport.d.ts +65 -0
- package/dist/auth/email-transport.d.ts.map +1 -0
- package/dist/auth/email-transport.js +82 -0
- package/dist/auth/email-transport.js.map +1 -0
- package/dist/auth/i18n.d.ts +81 -0
- package/dist/auth/i18n.d.ts.map +1 -0
- package/dist/auth/i18n.js +395 -0
- package/dist/auth/i18n.js.map +1 -0
- package/dist/auth/index.d.ts +28 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +31 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/interaction-authority.d.ts +39 -0
- package/dist/auth/interaction-authority.d.ts.map +1 -0
- package/dist/auth/interaction-authority.js +30 -0
- package/dist/auth/interaction-authority.js.map +1 -0
- package/dist/auth/magic-link-session.d.ts +81 -0
- package/dist/auth/magic-link-session.d.ts.map +1 -0
- package/dist/auth/magic-link-session.js +183 -0
- package/dist/auth/magic-link-session.js.map +1 -0
- package/dist/auth/rate-limiter.d.ts +143 -0
- package/dist/auth/rate-limiter.d.ts.map +1 -0
- package/dist/auth/rate-limiter.js +220 -0
- package/dist/auth/rate-limiter.js.map +1 -0
- package/dist/auth/recovery-crypto.d.ts +34 -0
- package/dist/auth/recovery-crypto.d.ts.map +1 -0
- package/dist/auth/recovery-crypto.js +103 -0
- package/dist/auth/recovery-crypto.js.map +1 -0
- package/dist/auth/recovery-job-processor.d.ts +24 -0
- package/dist/auth/recovery-job-processor.d.ts.map +1 -0
- package/dist/auth/recovery-job-processor.js +123 -0
- package/dist/auth/recovery-job-processor.js.map +1 -0
- package/dist/auth/recovery-job-repository.d.ts +219 -0
- package/dist/auth/recovery-job-repository.d.ts.map +1 -0
- package/dist/auth/recovery-job-repository.js +340 -0
- package/dist/auth/recovery-job-repository.js.map +1 -0
- package/dist/auth/recovery-service.d.ts +27 -0
- package/dist/auth/recovery-service.d.ts.map +1 -0
- package/dist/auth/recovery-service.js +53 -0
- package/dist/auth/recovery-service.js.map +1 -0
- package/dist/auth/recovery-worker.d.ts +158 -0
- package/dist/auth/recovery-worker.d.ts.map +1 -0
- package/dist/auth/recovery-worker.js +306 -0
- package/dist/auth/recovery-worker.js.map +1 -0
- package/dist/auth/template-engine.d.ts +134 -0
- package/dist/auth/template-engine.d.ts.map +1 -0
- package/dist/auth/template-engine.js +225 -0
- package/dist/auth/template-engine.js.map +1 -0
- package/dist/auth/token-repository.d.ts +238 -0
- package/dist/auth/token-repository.d.ts.map +1 -0
- package/dist/auth/token-repository.js +475 -0
- package/dist/auth/token-repository.js.map +1 -0
- package/dist/auth/tokens.d.ts +45 -0
- package/dist/auth/tokens.d.ts.map +1 -0
- package/dist/auth/tokens.js +51 -0
- package/dist/auth/tokens.js.map +1 -0
- package/dist/cli/bootstrap.d.ts +55 -0
- package/dist/cli/bootstrap.d.ts.map +1 -0
- package/dist/cli/bootstrap.js +90 -0
- package/dist/cli/bootstrap.js.map +1 -0
- package/dist/cli/commands/health.d.ts +20 -0
- package/dist/cli/commands/health.d.ts.map +1 -0
- package/dist/cli/commands/health.js +80 -0
- package/dist/cli/commands/health.js.map +1 -0
- package/dist/cli/commands/init.d.ts +48 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +349 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/migrate.d.ts +19 -0
- package/dist/cli/commands/migrate.d.ts.map +1 -0
- package/dist/cli/commands/migrate.js +88 -0
- package/dist/cli/commands/migrate.js.map +1 -0
- package/dist/cli/commands/seed.d.ts +19 -0
- package/dist/cli/commands/seed.d.ts.map +1 -0
- package/dist/cli/commands/seed.js +71 -0
- package/dist/cli/commands/seed.js.map +1 -0
- package/dist/cli/commands/user-2fa.d.ts +29 -0
- package/dist/cli/commands/user-2fa.d.ts.map +1 -0
- package/dist/cli/commands/user-2fa.js +113 -0
- package/dist/cli/commands/user-2fa.js.map +1 -0
- package/dist/cli/error-handler.d.ts +31 -0
- package/dist/cli/error-handler.d.ts.map +1 -0
- package/dist/cli/error-handler.js +65 -0
- package/dist/cli/error-handler.js.map +1 -0
- package/dist/cli/index.d.ts +48 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +99 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/output.d.ts +94 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +124 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/prompt.d.ts +48 -0
- package/dist/cli/prompt.d.ts.map +1 -0
- package/dist/cli/prompt.js +96 -0
- package/dist/cli/prompt.js.map +1 -0
- package/dist/clients/cache.d.ts +63 -0
- package/dist/clients/cache.d.ts.map +1 -0
- package/dist/clients/cache.js +160 -0
- package/dist/clients/cache.js.map +1 -0
- package/dist/clients/crypto.d.ts +69 -0
- package/dist/clients/crypto.d.ts.map +1 -0
- package/dist/clients/crypto.js +83 -0
- package/dist/clients/crypto.js.map +1 -0
- package/dist/clients/errors.d.ts +27 -0
- package/dist/clients/errors.d.ts.map +1 -0
- package/dist/clients/errors.js +33 -0
- package/dist/clients/errors.js.map +1 -0
- package/dist/clients/index.d.ts +19 -0
- package/dist/clients/index.d.ts.map +1 -0
- package/dist/clients/index.js +23 -0
- package/dist/clients/index.js.map +1 -0
- package/dist/clients/repository.d.ts +161 -0
- package/dist/clients/repository.d.ts.map +1 -0
- package/dist/clients/repository.js +318 -0
- package/dist/clients/repository.js.map +1 -0
- package/dist/clients/resolve-login-methods.d.ts +74 -0
- package/dist/clients/resolve-login-methods.d.ts.map +1 -0
- package/dist/clients/resolve-login-methods.js +68 -0
- package/dist/clients/resolve-login-methods.js.map +1 -0
- package/dist/clients/secret-repository.d.ts +109 -0
- package/dist/clients/secret-repository.d.ts.map +1 -0
- package/dist/clients/secret-repository.js +166 -0
- package/dist/clients/secret-repository.js.map +1 -0
- package/dist/clients/secret-service.d.ts +87 -0
- package/dist/clients/secret-service.d.ts.map +1 -0
- package/dist/clients/secret-service.js +204 -0
- package/dist/clients/secret-service.js.map +1 -0
- package/dist/clients/service.d.ts +158 -0
- package/dist/clients/service.d.ts.map +1 -0
- package/dist/clients/service.js +523 -0
- package/dist/clients/service.js.map +1 -0
- package/dist/clients/types.d.ts +214 -0
- package/dist/clients/types.d.ts.map +1 -0
- package/dist/clients/types.js +77 -0
- package/dist/clients/types.js.map +1 -0
- package/dist/clients/validators.d.ts +87 -0
- package/dist/clients/validators.d.ts.map +1 -0
- package/dist/clients/validators.js +164 -0
- package/dist/clients/validators.js.map +1 -0
- package/dist/config/index.d.ts +23 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +52 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/schema.d.ts +35 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +167 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/custom-claims/cache.d.ts +48 -0
- package/dist/custom-claims/cache.d.ts.map +1 -0
- package/dist/custom-claims/cache.js +122 -0
- package/dist/custom-claims/cache.js.map +1 -0
- package/dist/custom-claims/errors.d.ts +25 -0
- package/dist/custom-claims/errors.d.ts.map +1 -0
- package/dist/custom-claims/errors.js +31 -0
- package/dist/custom-claims/errors.js.map +1 -0
- package/dist/custom-claims/index.d.ts +14 -0
- package/dist/custom-claims/index.d.ts.map +1 -0
- package/dist/custom-claims/index.js +17 -0
- package/dist/custom-claims/index.js.map +1 -0
- package/dist/custom-claims/repository.d.ts +147 -0
- package/dist/custom-claims/repository.d.ts.map +1 -0
- package/dist/custom-claims/repository.js +338 -0
- package/dist/custom-claims/repository.js.map +1 -0
- package/dist/custom-claims/service.d.ts +129 -0
- package/dist/custom-claims/service.d.ts.map +1 -0
- package/dist/custom-claims/service.js +296 -0
- package/dist/custom-claims/service.js.map +1 -0
- package/dist/custom-claims/types.d.ts +132 -0
- package/dist/custom-claims/types.d.ts.map +1 -0
- package/dist/custom-claims/types.js +61 -0
- package/dist/custom-claims/types.js.map +1 -0
- package/dist/custom-claims/validators.d.ts +61 -0
- package/dist/custom-claims/validators.d.ts.map +1 -0
- package/dist/custom-claims/validators.js +136 -0
- package/dist/custom-claims/validators.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +91 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/admin-permissions.d.ts +147 -0
- package/dist/lib/admin-permissions.d.ts.map +1 -0
- package/dist/lib/admin-permissions.js +261 -0
- package/dist/lib/admin-permissions.js.map +1 -0
- package/dist/lib/audit-log.d.ts +45 -0
- package/dist/lib/audit-log.d.ts.map +1 -0
- package/dist/lib/audit-log.js +79 -0
- package/dist/lib/audit-log.js.map +1 -0
- package/dist/lib/branding-assets.d.ts +47 -0
- package/dist/lib/branding-assets.d.ts.map +1 -0
- package/dist/lib/branding-assets.js +93 -0
- package/dist/lib/branding-assets.js.map +1 -0
- package/dist/lib/bulk-operations.d.ts +54 -0
- package/dist/lib/bulk-operations.d.ts.map +1 -0
- package/dist/lib/bulk-operations.js +201 -0
- package/dist/lib/bulk-operations.js.map +1 -0
- package/dist/lib/cursor.d.ts +110 -0
- package/dist/lib/cursor.d.ts.map +1 -0
- package/dist/lib/cursor.js +115 -0
- package/dist/lib/cursor.js.map +1 -0
- package/dist/lib/data-export.d.ts +67 -0
- package/dist/lib/data-export.d.ts.map +1 -0
- package/dist/lib/data-export.js +272 -0
- package/dist/lib/data-export.js.map +1 -0
- package/dist/lib/data-import-plan.d.ts +50 -0
- package/dist/lib/data-import-plan.d.ts.map +1 -0
- package/dist/lib/data-import-plan.js +235 -0
- package/dist/lib/data-import-plan.js.map +1 -0
- package/dist/lib/data-import.d.ts +276 -0
- package/dist/lib/data-import.d.ts.map +1 -0
- package/dist/lib/data-import.js +1694 -0
- package/dist/lib/data-import.js.map +1 -0
- package/dist/lib/database.d.ts +22 -0
- package/dist/lib/database.d.ts.map +1 -0
- package/dist/lib/database.js +103 -0
- package/dist/lib/database.js.map +1 -0
- package/dist/lib/entity-history.d.ts +52 -0
- package/dist/lib/entity-history.d.ts.map +1 -0
- package/dist/lib/entity-history.js +121 -0
- package/dist/lib/entity-history.js.map +1 -0
- package/dist/lib/etag.d.ts +92 -0
- package/dist/lib/etag.d.ts.map +1 -0
- package/dist/lib/etag.js +155 -0
- package/dist/lib/etag.js.map +1 -0
- package/dist/lib/image-validator.d.ts +44 -0
- package/dist/lib/image-validator.d.ts.map +1 -0
- package/dist/lib/image-validator.js +204 -0
- package/dist/lib/image-validator.js.map +1 -0
- package/dist/lib/logger.d.ts +15 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +84 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/migrator.d.ts +14 -0
- package/dist/lib/migrator.d.ts.map +1 -0
- package/dist/lib/migrator.js +34 -0
- package/dist/lib/migrator.js.map +1 -0
- package/dist/lib/redis.d.ts +5 -0
- package/dist/lib/redis.d.ts.map +1 -0
- package/dist/lib/redis.js +29 -0
- package/dist/lib/redis.js.map +1 -0
- package/dist/lib/runtime-paths.d.ts +38 -0
- package/dist/lib/runtime-paths.d.ts.map +1 -0
- package/dist/lib/runtime-paths.js +50 -0
- package/dist/lib/runtime-paths.js.map +1 -0
- package/dist/lib/session-tracking.d.ts +81 -0
- package/dist/lib/session-tracking.d.ts.map +1 -0
- package/dist/lib/session-tracking.js +145 -0
- package/dist/lib/session-tracking.js.map +1 -0
- package/dist/lib/signing-key-crypto.d.ts +53 -0
- package/dist/lib/signing-key-crypto.d.ts.map +1 -0
- package/dist/lib/signing-key-crypto.js +108 -0
- package/dist/lib/signing-key-crypto.js.map +1 -0
- package/dist/lib/signing-keys.d.ts +141 -0
- package/dist/lib/signing-keys.d.ts.map +1 -0
- package/dist/lib/signing-keys.js +206 -0
- package/dist/lib/signing-keys.js.map +1 -0
- package/dist/lib/stats.d.ts +83 -0
- package/dist/lib/stats.d.ts.map +1 -0
- package/dist/lib/stats.js +187 -0
- package/dist/lib/stats.js.map +1 -0
- package/dist/lib/super-admin-protection.d.ts +69 -0
- package/dist/lib/super-admin-protection.d.ts.map +1 -0
- package/dist/lib/super-admin-protection.js +102 -0
- package/dist/lib/super-admin-protection.js.map +1 -0
- package/dist/lib/system-config.d.ts +79 -0
- package/dist/lib/system-config.d.ts.map +1 -0
- package/dist/lib/system-config.js +159 -0
- package/dist/lib/system-config.js.map +1 -0
- package/dist/middleware/admin-auth.d.ts +100 -0
- package/dist/middleware/admin-auth.d.ts.map +1 -0
- package/dist/middleware/admin-auth.js +241 -0
- package/dist/middleware/admin-auth.js.map +1 -0
- package/dist/middleware/admin-cors.d.ts +41 -0
- package/dist/middleware/admin-cors.d.ts.map +1 -0
- package/dist/middleware/admin-cors.js +83 -0
- package/dist/middleware/admin-cors.js.map +1 -0
- package/dist/middleware/admin-mutation-audit.d.ts +9 -0
- package/dist/middleware/admin-mutation-audit.d.ts.map +1 -0
- package/dist/middleware/admin-mutation-audit.js +76 -0
- package/dist/middleware/admin-mutation-audit.js.map +1 -0
- package/dist/middleware/admin-rate-limiter.d.ts +56 -0
- package/dist/middleware/admin-rate-limiter.d.ts.map +1 -0
- package/dist/middleware/admin-rate-limiter.js +97 -0
- package/dist/middleware/admin-rate-limiter.js.map +1 -0
- package/dist/middleware/client-secret-hash.d.ts +34 -0
- package/dist/middleware/client-secret-hash.d.ts.map +1 -0
- package/dist/middleware/client-secret-hash.js +74 -0
- package/dist/middleware/client-secret-hash.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +3 -0
- package/dist/middleware/error-handler.d.ts.map +1 -0
- package/dist/middleware/error-handler.js +93 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/health.d.ts +3 -0
- package/dist/middleware/health.d.ts.map +1 -0
- package/dist/middleware/health.js +35 -0
- package/dist/middleware/health.js.map +1 -0
- package/dist/middleware/metrics.d.ts +40 -0
- package/dist/middleware/metrics.d.ts.map +1 -0
- package/dist/middleware/metrics.js +75 -0
- package/dist/middleware/metrics.js.map +1 -0
- package/dist/middleware/oidc-client-tenant.d.ts +37 -0
- package/dist/middleware/oidc-client-tenant.d.ts.map +1 -0
- package/dist/middleware/oidc-client-tenant.js +156 -0
- package/dist/middleware/oidc-client-tenant.js.map +1 -0
- package/dist/middleware/oidc-cors.d.ts +33 -0
- package/dist/middleware/oidc-cors.d.ts.map +1 -0
- package/dist/middleware/oidc-cors.js +68 -0
- package/dist/middleware/oidc-cors.js.map +1 -0
- package/dist/middleware/oidc-preflight-cors.d.ts +54 -0
- package/dist/middleware/oidc-preflight-cors.d.ts.map +1 -0
- package/dist/middleware/oidc-preflight-cors.js +267 -0
- package/dist/middleware/oidc-preflight-cors.js.map +1 -0
- package/dist/middleware/prompt-login-reset.d.ts +103 -0
- package/dist/middleware/prompt-login-reset.d.ts.map +1 -0
- package/dist/middleware/prompt-login-reset.js +204 -0
- package/dist/middleware/prompt-login-reset.js.map +1 -0
- package/dist/middleware/ready.d.ts +23 -0
- package/dist/middleware/ready.d.ts.map +1 -0
- package/dist/middleware/ready.js +60 -0
- package/dist/middleware/ready.js.map +1 -0
- package/dist/middleware/request-logger.d.ts +27 -0
- package/dist/middleware/request-logger.d.ts.map +1 -0
- package/dist/middleware/request-logger.js +46 -0
- package/dist/middleware/request-logger.js.map +1 -0
- package/dist/middleware/require-permission.d.ts +28 -0
- package/dist/middleware/require-permission.d.ts.map +1 -0
- package/dist/middleware/require-permission.js +63 -0
- package/dist/middleware/require-permission.js.map +1 -0
- package/dist/middleware/require-user-organization.d.ts +18 -0
- package/dist/middleware/require-user-organization.d.ts.map +1 -0
- package/dist/middleware/require-user-organization.js +53 -0
- package/dist/middleware/require-user-organization.js.map +1 -0
- package/dist/middleware/root-page.d.ts +62 -0
- package/dist/middleware/root-page.d.ts.map +1 -0
- package/dist/middleware/root-page.js +134 -0
- package/dist/middleware/root-page.js.map +1 -0
- package/dist/middleware/security-headers.d.ts +98 -0
- package/dist/middleware/security-headers.d.ts.map +1 -0
- package/dist/middleware/security-headers.js +159 -0
- package/dist/middleware/security-headers.js.map +1 -0
- package/dist/middleware/tenant-resolver.d.ts +37 -0
- package/dist/middleware/tenant-resolver.d.ts.map +1 -0
- package/dist/middleware/tenant-resolver.js +71 -0
- package/dist/middleware/tenant-resolver.js.map +1 -0
- package/dist/middleware/token-rate-limiter.d.ts +89 -0
- package/dist/middleware/token-rate-limiter.d.ts.map +1 -0
- package/dist/middleware/token-rate-limiter.js +189 -0
- package/dist/middleware/token-rate-limiter.js.map +1 -0
- package/dist/oidc/account-finder.d.ts +52 -0
- package/dist/oidc/account-finder.d.ts.map +1 -0
- package/dist/oidc/account-finder.js +134 -0
- package/dist/oidc/account-finder.js.map +1 -0
- package/dist/oidc/adapter-factory.d.ts +90 -0
- package/dist/oidc/adapter-factory.d.ts.map +1 -0
- package/dist/oidc/adapter-factory.js +165 -0
- package/dist/oidc/adapter-factory.js.map +1 -0
- package/dist/oidc/configuration.d.ts +155 -0
- package/dist/oidc/configuration.d.ts.map +1 -0
- package/dist/oidc/configuration.js +531 -0
- package/dist/oidc/configuration.js.map +1 -0
- package/dist/oidc/postgres-adapter.d.ts +159 -0
- package/dist/oidc/postgres-adapter.d.ts.map +1 -0
- package/dist/oidc/postgres-adapter.js +222 -0
- package/dist/oidc/postgres-adapter.js.map +1 -0
- package/dist/oidc/protocol-security-observer.d.ts +38 -0
- package/dist/oidc/protocol-security-observer.d.ts.map +1 -0
- package/dist/oidc/protocol-security-observer.js +93 -0
- package/dist/oidc/protocol-security-observer.js.map +1 -0
- package/dist/oidc/provider.d.ts +37 -0
- package/dist/oidc/provider.d.ts.map +1 -0
- package/dist/oidc/provider.js +71 -0
- package/dist/oidc/provider.js.map +1 -0
- package/dist/oidc/redis-adapter.d.ts +140 -0
- package/dist/oidc/redis-adapter.d.ts.map +1 -0
- package/dist/oidc/redis-adapter.js +344 -0
- package/dist/oidc/redis-adapter.js.map +1 -0
- package/dist/organizations/cache.d.ts +60 -0
- package/dist/organizations/cache.d.ts.map +1 -0
- package/dist/organizations/cache.js +157 -0
- package/dist/organizations/cache.js.map +1 -0
- package/dist/organizations/errors.d.ts +25 -0
- package/dist/organizations/errors.d.ts.map +1 -0
- package/dist/organizations/errors.js +31 -0
- package/dist/organizations/errors.js.map +1 -0
- package/dist/organizations/index.d.ts +15 -0
- package/dist/organizations/index.d.ts.map +1 -0
- package/dist/organizations/index.js +15 -0
- package/dist/organizations/index.js.map +1 -0
- package/dist/organizations/repository.d.ts +183 -0
- package/dist/organizations/repository.d.ts.map +1 -0
- package/dist/organizations/repository.js +354 -0
- package/dist/organizations/repository.js.map +1 -0
- package/dist/organizations/service.d.ts +168 -0
- package/dist/organizations/service.d.ts.map +1 -0
- package/dist/organizations/service.js +511 -0
- package/dist/organizations/service.js.map +1 -0
- package/dist/organizations/slugs.d.ts +57 -0
- package/dist/organizations/slugs.d.ts.map +1 -0
- package/dist/organizations/slugs.js +130 -0
- package/dist/organizations/slugs.js.map +1 -0
- package/dist/organizations/types.d.ts +146 -0
- package/dist/organizations/types.d.ts.map +1 -0
- package/dist/organizations/types.js +49 -0
- package/dist/organizations/types.js.map +1 -0
- package/dist/rbac/cache.d.ts +110 -0
- package/dist/rbac/cache.d.ts.map +1 -0
- package/dist/rbac/cache.js +271 -0
- package/dist/rbac/cache.js.map +1 -0
- package/dist/rbac/errors.d.ts +34 -0
- package/dist/rbac/errors.d.ts.map +1 -0
- package/dist/rbac/errors.js +43 -0
- package/dist/rbac/errors.js.map +1 -0
- package/dist/rbac/index.d.ts +17 -0
- package/dist/rbac/index.d.ts.map +1 -0
- package/dist/rbac/index.js +21 -0
- package/dist/rbac/index.js.map +1 -0
- package/dist/rbac/mapping-repository.d.ts +121 -0
- package/dist/rbac/mapping-repository.d.ts.map +1 -0
- package/dist/rbac/mapping-repository.js +224 -0
- package/dist/rbac/mapping-repository.js.map +1 -0
- package/dist/rbac/permission-repository.d.ts +100 -0
- package/dist/rbac/permission-repository.d.ts.map +1 -0
- package/dist/rbac/permission-repository.js +190 -0
- package/dist/rbac/permission-repository.js.map +1 -0
- package/dist/rbac/permission-service.d.ts +85 -0
- package/dist/rbac/permission-service.d.ts.map +1 -0
- package/dist/rbac/permission-service.js +179 -0
- package/dist/rbac/permission-service.js.map +1 -0
- package/dist/rbac/role-repository.d.ts +104 -0
- package/dist/rbac/role-repository.d.ts.map +1 -0
- package/dist/rbac/role-repository.js +202 -0
- package/dist/rbac/role-repository.js.map +1 -0
- package/dist/rbac/role-service.d.ts +111 -0
- package/dist/rbac/role-service.d.ts.map +1 -0
- package/dist/rbac/role-service.js +256 -0
- package/dist/rbac/role-service.js.map +1 -0
- package/dist/rbac/slugs.d.ts +116 -0
- package/dist/rbac/slugs.d.ts.map +1 -0
- package/dist/rbac/slugs.js +178 -0
- package/dist/rbac/slugs.js.map +1 -0
- package/dist/rbac/types.d.ts +187 -0
- package/dist/rbac/types.d.ts.map +1 -0
- package/dist/rbac/types.js +75 -0
- package/dist/rbac/types.js.map +1 -0
- package/dist/rbac/user-role-service.d.ts +101 -0
- package/dist/rbac/user-role-service.d.ts.map +1 -0
- package/dist/rbac/user-role-service.js +166 -0
- package/dist/rbac/user-role-service.js.map +1 -0
- package/dist/routes/applications.d.ts +40 -0
- package/dist/routes/applications.d.ts.map +1 -0
- package/dist/routes/applications.js +284 -0
- package/dist/routes/applications.js.map +1 -0
- package/dist/routes/audit.d.ts +31 -0
- package/dist/routes/audit.d.ts.map +1 -0
- package/dist/routes/audit.js +140 -0
- package/dist/routes/audit.js.map +1 -0
- package/dist/routes/branding.d.ts +17 -0
- package/dist/routes/branding.d.ts.map +1 -0
- package/dist/routes/branding.js +104 -0
- package/dist/routes/branding.js.map +1 -0
- package/dist/routes/bulk.d.ts +37 -0
- package/dist/routes/bulk.d.ts.map +1 -0
- package/dist/routes/bulk.js +94 -0
- package/dist/routes/bulk.js.map +1 -0
- package/dist/routes/clients.d.ts +44 -0
- package/dist/routes/clients.d.ts.map +1 -0
- package/dist/routes/clients.js +353 -0
- package/dist/routes/clients.js.map +1 -0
- package/dist/routes/config.d.ts +35 -0
- package/dist/routes/config.d.ts.map +1 -0
- package/dist/routes/config.js +115 -0
- package/dist/routes/config.js.map +1 -0
- package/dist/routes/custom-claims.d.ts +38 -0
- package/dist/routes/custom-claims.d.ts.map +1 -0
- package/dist/routes/custom-claims.js +208 -0
- package/dist/routes/custom-claims.js.map +1 -0
- package/dist/routes/exports.d.ts +21 -0
- package/dist/routes/exports.d.ts.map +1 -0
- package/dist/routes/exports.js +98 -0
- package/dist/routes/exports.js.map +1 -0
- package/dist/routes/imports.d.ts +18 -0
- package/dist/routes/imports.d.ts.map +1 -0
- package/dist/routes/imports.js +72 -0
- package/dist/routes/imports.js.map +1 -0
- package/dist/routes/interactions.d.ts +111 -0
- package/dist/routes/interactions.d.ts.map +1 -0
- package/dist/routes/interactions.js +1074 -0
- package/dist/routes/interactions.js.map +1 -0
- package/dist/routes/invitation.d.ts +31 -0
- package/dist/routes/invitation.d.ts.map +1 -0
- package/dist/routes/invitation.js +342 -0
- package/dist/routes/invitation.js.map +1 -0
- package/dist/routes/keys.d.ts +28 -0
- package/dist/routes/keys.d.ts.map +1 -0
- package/dist/routes/keys.js +91 -0
- package/dist/routes/keys.js.map +1 -0
- package/dist/routes/magic-link.d.ts +43 -0
- package/dist/routes/magic-link.d.ts.map +1 -0
- package/dist/routes/magic-link.js +264 -0
- package/dist/routes/magic-link.js.map +1 -0
- package/dist/routes/organizations.d.ts +38 -0
- package/dist/routes/organizations.d.ts.map +1 -0
- package/dist/routes/organizations.js +347 -0
- package/dist/routes/organizations.js.map +1 -0
- package/dist/routes/password-reset.d.ts +65 -0
- package/dist/routes/password-reset.d.ts.map +1 -0
- package/dist/routes/password-reset.js +493 -0
- package/dist/routes/password-reset.js.map +1 -0
- package/dist/routes/permissions.d.ts +33 -0
- package/dist/routes/permissions.d.ts.map +1 -0
- package/dist/routes/permissions.js +166 -0
- package/dist/routes/permissions.js.map +1 -0
- package/dist/routes/roles.d.ts +37 -0
- package/dist/routes/roles.d.ts.map +1 -0
- package/dist/routes/roles.js +222 -0
- package/dist/routes/roles.js.map +1 -0
- package/dist/routes/sessions.d.ts +37 -0
- package/dist/routes/sessions.d.ts.map +1 -0
- package/dist/routes/sessions.js +121 -0
- package/dist/routes/sessions.js.map +1 -0
- package/dist/routes/stats.d.ts +28 -0
- package/dist/routes/stats.d.ts.map +1 -0
- package/dist/routes/stats.js +65 -0
- package/dist/routes/stats.js.map +1 -0
- package/dist/routes/two-factor-admin.d.ts +54 -0
- package/dist/routes/two-factor-admin.d.ts.map +1 -0
- package/dist/routes/two-factor-admin.js +344 -0
- package/dist/routes/two-factor-admin.js.map +1 -0
- package/dist/routes/two-factor.d.ts +31 -0
- package/dist/routes/two-factor.d.ts.map +1 -0
- package/dist/routes/two-factor.js +595 -0
- package/dist/routes/two-factor.js.map +1 -0
- package/dist/routes/user-roles.d.ts +33 -0
- package/dist/routes/user-roles.d.ts.map +1 -0
- package/dist/routes/user-roles.js +129 -0
- package/dist/routes/user-roles.js.map +1 -0
- package/dist/routes/users.d.ts +61 -0
- package/dist/routes/users.d.ts.map +1 -0
- package/dist/routes/users.js +868 -0
- package/dist/routes/users.js.map +1 -0
- package/dist/security/decision-context.d.ts +52 -0
- package/dist/security/decision-context.d.ts.map +1 -0
- package/dist/security/decision-context.js +150 -0
- package/dist/security/decision-context.js.map +1 -0
- package/dist/security/decision-event.d.ts +128 -0
- package/dist/security/decision-event.d.ts.map +1 -0
- package/dist/security/decision-event.js +225 -0
- package/dist/security/decision-event.js.map +1 -0
- package/dist/security/transport-decision.d.ts +6 -0
- package/dist/security/transport-decision.d.ts.map +1 -0
- package/dist/security/transport-decision.js +37 -0
- package/dist/security/transport-decision.js.map +1 -0
- package/dist/server.d.ts +50 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +491 -0
- package/dist/server.js.map +1 -0
- package/dist/two-factor/cache.d.ts +47 -0
- package/dist/two-factor/cache.d.ts.map +1 -0
- package/dist/two-factor/cache.js +122 -0
- package/dist/two-factor/cache.js.map +1 -0
- package/dist/two-factor/crypto.d.ts +41 -0
- package/dist/two-factor/crypto.d.ts.map +1 -0
- package/dist/two-factor/crypto.js +94 -0
- package/dist/two-factor/crypto.js.map +1 -0
- package/dist/two-factor/errors.d.ts +82 -0
- package/dist/two-factor/errors.d.ts.map +1 -0
- package/dist/two-factor/errors.js +112 -0
- package/dist/two-factor/errors.js.map +1 -0
- package/dist/two-factor/index.d.ts +18 -0
- package/dist/two-factor/index.d.ts.map +1 -0
- package/dist/two-factor/index.js +25 -0
- package/dist/two-factor/index.js.map +1 -0
- package/dist/two-factor/otp.d.ts +43 -0
- package/dist/two-factor/otp.d.ts.map +1 -0
- package/dist/two-factor/otp.js +57 -0
- package/dist/two-factor/otp.js.map +1 -0
- package/dist/two-factor/recovery.d.ts +45 -0
- package/dist/two-factor/recovery.d.ts.map +1 -0
- package/dist/two-factor/recovery.js +104 -0
- package/dist/two-factor/recovery.js.map +1 -0
- package/dist/two-factor/repository.d.ts +156 -0
- package/dist/two-factor/repository.d.ts.map +1 -0
- package/dist/two-factor/repository.js +251 -0
- package/dist/two-factor/repository.js.map +1 -0
- package/dist/two-factor/service.d.ts +232 -0
- package/dist/two-factor/service.d.ts.map +1 -0
- package/dist/two-factor/service.js +599 -0
- package/dist/two-factor/service.js.map +1 -0
- package/dist/two-factor/totp.d.ts +57 -0
- package/dist/two-factor/totp.d.ts.map +1 -0
- package/dist/two-factor/totp.js +96 -0
- package/dist/two-factor/totp.js.map +1 -0
- package/dist/two-factor/types.d.ts +152 -0
- package/dist/two-factor/types.d.ts.map +1 -0
- package/dist/two-factor/types.js +64 -0
- package/dist/two-factor/types.js.map +1 -0
- package/dist/users/cache.d.ts +49 -0
- package/dist/users/cache.d.ts.map +1 -0
- package/dist/users/cache.js +140 -0
- package/dist/users/cache.js.map +1 -0
- package/dist/users/claims.d.ts +67 -0
- package/dist/users/claims.d.ts.map +1 -0
- package/dist/users/claims.js +104 -0
- package/dist/users/claims.js.map +1 -0
- package/dist/users/errors.d.ts +25 -0
- package/dist/users/errors.d.ts.map +1 -0
- package/dist/users/errors.js +31 -0
- package/dist/users/errors.js.map +1 -0
- package/dist/users/gdpr.d.ts +110 -0
- package/dist/users/gdpr.d.ts.map +1 -0
- package/dist/users/gdpr.js +211 -0
- package/dist/users/gdpr.js.map +1 -0
- package/dist/users/index.d.ts +20 -0
- package/dist/users/index.d.ts.map +1 -0
- package/dist/users/index.js +19 -0
- package/dist/users/index.js.map +1 -0
- package/dist/users/password.d.ts +85 -0
- package/dist/users/password.d.ts.map +1 -0
- package/dist/users/password.js +138 -0
- package/dist/users/password.js.map +1 -0
- package/dist/users/repository.d.ts +263 -0
- package/dist/users/repository.d.ts.map +1 -0
- package/dist/users/repository.js +499 -0
- package/dist/users/repository.js.map +1 -0
- package/dist/users/service.d.ts +299 -0
- package/dist/users/service.d.ts.map +1 -0
- package/dist/users/service.js +698 -0
- package/dist/users/service.js.map +1 -0
- package/dist/users/types.d.ts +220 -0
- package/dist/users/types.d.ts.map +1 -0
- package/dist/users/types.js +77 -0
- package/dist/users/types.js.map +1 -0
- package/locales/default/en/common.json +10 -0
- package/locales/default/en/consent.json +13 -0
- package/locales/default/en/emails.json +17 -0
- package/locales/default/en/errors.json +21 -0
- package/locales/default/en/forgot-password.json +11 -0
- package/locales/default/en/invitation.json +18 -0
- package/locales/default/en/login.json +17 -0
- package/locales/default/en/logout.json +9 -0
- package/locales/default/en/magic-link.json +12 -0
- package/locales/default/en/reset-password.json +16 -0
- package/locales/default/en/two-factor.json +29 -0
- package/migrations/.gitkeep +0 -0
- package/migrations/001_extensions.sql +22 -0
- package/migrations/002_organizations.sql +43 -0
- package/migrations/003_applications.sql +50 -0
- package/migrations/004_clients.sql +74 -0
- package/migrations/005_users.sql +119 -0
- package/migrations/006_roles_permissions.sql +80 -0
- package/migrations/007_custom_claims.sql +55 -0
- package/migrations/008_config.sql +51 -0
- package/migrations/009_audit_log.sql +31 -0
- package/migrations/010_oidc_adapter.sql +34 -0
- package/migrations/011_seed.sql +53 -0
- package/migrations/012_two_factor.sql +88 -0
- package/migrations/013_client_secret_sha256.sql +22 -0
- package/migrations/014_login_methods.sql +34 -0
- package/migrations/015_signing_key_encryption.sql +20 -0
- package/migrations/016_failed_login_count.sql +27 -0
- package/migrations/017_audit_retention.sql +11 -0
- package/migrations/018_admin_api_enhancements.sql +78 -0
- package/migrations/019_invitation_details.sql +27 -0
- package/migrations/020_two_factor_admin_permission.sql +108 -0
- package/migrations/021_auth_recovery_jobs.sql +74 -0
- package/migrations/022_recovery_artifact_ownership.sql +25 -0
- package/migrations/023_magic_link_authority.sql +39 -0
- package/package.json +106 -0
- package/templates/default/emails/invitation.hbs +39 -0
- package/templates/default/emails/invitation.txt.hbs +18 -0
- package/templates/default/emails/magic-link.hbs +30 -0
- package/templates/default/emails/magic-link.txt.hbs +11 -0
- package/templates/default/emails/otp-code.hbs +31 -0
- package/templates/default/emails/otp-code.txt.hbs +15 -0
- package/templates/default/emails/password-changed.hbs +24 -0
- package/templates/default/emails/password-changed.txt.hbs +7 -0
- package/templates/default/emails/password-reset.hbs +30 -0
- package/templates/default/emails/password-reset.txt.hbs +11 -0
- package/templates/default/emails/welcome.hbs +25 -0
- package/templates/default/emails/welcome.txt.hbs +9 -0
- package/templates/default/layouts/main.hbs +49 -0
- package/templates/default/pages/accept-invite.hbs +25 -0
- package/templates/default/pages/consent.hbs +27 -0
- package/templates/default/pages/error.hbs +15 -0
- package/templates/default/pages/forgot-password.hbs +21 -0
- package/templates/default/pages/invite-expired.hbs +6 -0
- package/templates/default/pages/invite-success.hbs +9 -0
- package/templates/default/pages/login.hbs +108 -0
- package/templates/default/pages/logout-success.hbs +5 -0
- package/templates/default/pages/logout.hbs +24 -0
- package/templates/default/pages/magic-link-sent.hbs +10 -0
- package/templates/default/pages/magic-link-success.hbs +17 -0
- package/templates/default/pages/reset-password.hbs +20 -0
- package/templates/default/pages/reset-success.hbs +9 -0
- package/templates/default/pages/two-factor-setup.hbs +65 -0
- package/templates/default/pages/two-factor-verify.hbs +77 -0
- package/templates/default/partials/flash-messages.hbs +10 -0
- package/templates/default/partials/footer.hbs +4 -0
- package/templates/default/partials/header.hbs +8 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* High-level email service for auth workflow emails.
|
|
3
|
+
*
|
|
4
|
+
* Provides specific methods for each email type (magic link, password reset,
|
|
5
|
+
* invitation, welcome, password-changed). Each method:
|
|
6
|
+
* 1. Renders HTML + plaintext templates via the email renderer
|
|
7
|
+
* 2. Sends via the email transport
|
|
8
|
+
* 3. Writes an audit log entry
|
|
9
|
+
*
|
|
10
|
+
* All methods use fire-and-forget semantics: send failures are caught,
|
|
11
|
+
* logged as warnings, and audit-logged — they never propagate to callers.
|
|
12
|
+
* This ensures email delivery never blocks core authentication flows.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* await sendMagicLinkEmail(user, org, 'https://...', 'en');
|
|
16
|
+
*/
|
|
17
|
+
import type { EmailTransport } from './email-transport.js';
|
|
18
|
+
/** Minimal user fields needed by email service */
|
|
19
|
+
export interface EmailUser {
|
|
20
|
+
id: string;
|
|
21
|
+
email: string;
|
|
22
|
+
givenName?: string | null;
|
|
23
|
+
familyName?: string | null;
|
|
24
|
+
}
|
|
25
|
+
/** Minimal org fields needed by email service */
|
|
26
|
+
export interface EmailOrganization {
|
|
27
|
+
id: string;
|
|
28
|
+
slug: string;
|
|
29
|
+
brandingLogoUrl?: string | null;
|
|
30
|
+
brandingPrimaryColor?: string | null;
|
|
31
|
+
brandingCompanyName?: string | null;
|
|
32
|
+
}
|
|
33
|
+
/** Closed recovery email variants sent by the durable worker. */
|
|
34
|
+
export type RecoveryEmailType = 'magic_link' | 'password_reset';
|
|
35
|
+
/** Input for strict recovery delivery with propagated transport failures. */
|
|
36
|
+
export interface StrictRecoveryEmailInput {
|
|
37
|
+
/** Recovery template and subject selection. */
|
|
38
|
+
readonly type: RecoveryEmailType;
|
|
39
|
+
/** Eligible recipient account. */
|
|
40
|
+
readonly user: EmailUser;
|
|
41
|
+
/** Tenant branding and template authority. */
|
|
42
|
+
readonly organization: EmailOrganization;
|
|
43
|
+
/** Complete recovery URL containing the single-use artifact. */
|
|
44
|
+
readonly recoveryUrl: string;
|
|
45
|
+
/** Resolved locale. */
|
|
46
|
+
readonly locale: string;
|
|
47
|
+
/** Stable RFC 5322 message identity for bounded retries. */
|
|
48
|
+
readonly messageId: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Render and deliver one recovery email while propagating template and SMTP failures.
|
|
52
|
+
*
|
|
53
|
+
* The durable worker owns retry and terminal policy. This function deliberately performs no
|
|
54
|
+
* catch-and-ignore behavior and emits no recipient, URL, or transport-error details.
|
|
55
|
+
*
|
|
56
|
+
* @param input - Recovery template, recipient, tenant, link, locale, and message identity.
|
|
57
|
+
*/
|
|
58
|
+
export declare function sendRecoveryEmailStrict(input: StrictRecoveryEmailInput): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Override the email transport (for testing).
|
|
61
|
+
* Pass null to reset to the default SMTP transport.
|
|
62
|
+
*
|
|
63
|
+
* @param override - Custom transport or null to reset
|
|
64
|
+
*/
|
|
65
|
+
export declare function setEmailTransport(override: EmailTransport | null): void;
|
|
66
|
+
/**
|
|
67
|
+
* Send a magic link email to a user.
|
|
68
|
+
*
|
|
69
|
+
* @param user - Recipient user
|
|
70
|
+
* @param org - Organization (for branding and template override)
|
|
71
|
+
* @param magicLinkUrl - Full URL the user clicks to authenticate
|
|
72
|
+
* @param locale - Locale for i18n (e.g., 'en')
|
|
73
|
+
*/
|
|
74
|
+
export declare function sendMagicLinkEmail(user: EmailUser, org: EmailOrganization, magicLinkUrl: string, locale: string): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Send a password reset email to a user.
|
|
77
|
+
*
|
|
78
|
+
* @param user - Recipient user
|
|
79
|
+
* @param org - Organization (for branding and template override)
|
|
80
|
+
* @param resetUrl - Full URL the user clicks to reset their password
|
|
81
|
+
* @param locale - Locale for i18n
|
|
82
|
+
*/
|
|
83
|
+
export declare function sendPasswordResetEmail(user: EmailUser, org: EmailOrganization, resetUrl: string, locale: string): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Optional parameters for enhanced invitation emails.
|
|
86
|
+
*
|
|
87
|
+
* Supports personal messages from the inviting admin and pre-assignment
|
|
88
|
+
* metadata display in the invitation email.
|
|
89
|
+
*/
|
|
90
|
+
export interface InvitationEmailOptions {
|
|
91
|
+
/** Optional personal message from the admin (HTML-escaped before rendering) */
|
|
92
|
+
personalMessage?: string;
|
|
93
|
+
/** Display name of the admin who sent the invitation */
|
|
94
|
+
inviterName?: string;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Send an invitation email to a newly created user.
|
|
98
|
+
*
|
|
99
|
+
* @param user - Recipient user (newly created)
|
|
100
|
+
* @param org - Organization (for branding and template override)
|
|
101
|
+
* @param inviteUrl - Full URL the user clicks to accept the invitation
|
|
102
|
+
* @param locale - Locale for i18n
|
|
103
|
+
* @param options - Optional personal message and inviter name
|
|
104
|
+
*/
|
|
105
|
+
export declare function sendInvitationEmail(user: EmailUser, org: EmailOrganization, inviteUrl: string, locale: string, options?: InvitationEmailOptions): Promise<void>;
|
|
106
|
+
/**
|
|
107
|
+
* Render an invitation email without sending it (for preview).
|
|
108
|
+
*
|
|
109
|
+
* Returns the HTML, plain text, and subject line that would be sent,
|
|
110
|
+
* allowing admins to preview the invitation before sending.
|
|
111
|
+
*
|
|
112
|
+
* @param user - Recipient user
|
|
113
|
+
* @param org - Organization for branding
|
|
114
|
+
* @param inviteUrl - Full URL (can be a placeholder for preview)
|
|
115
|
+
* @param locale - Locale for i18n
|
|
116
|
+
* @param options - Optional personal message and inviter name
|
|
117
|
+
* @returns Rendered HTML, plain text, and subject line
|
|
118
|
+
*/
|
|
119
|
+
export declare function renderInvitationEmail(user: EmailUser, org: EmailOrganization, inviteUrl: string, locale: string, options?: InvitationEmailOptions): Promise<{
|
|
120
|
+
html: string;
|
|
121
|
+
text: string;
|
|
122
|
+
subject: string;
|
|
123
|
+
}>;
|
|
124
|
+
/**
|
|
125
|
+
* Send a welcome email to a user (for passwordless users after first login).
|
|
126
|
+
*
|
|
127
|
+
* @param user - Recipient user
|
|
128
|
+
* @param org - Organization (for branding and template override)
|
|
129
|
+
* @param locale - Locale for i18n
|
|
130
|
+
*/
|
|
131
|
+
export declare function sendWelcomeEmail(user: EmailUser, org: EmailOrganization, locale: string): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Send a 2FA OTP verification code email.
|
|
134
|
+
*
|
|
135
|
+
* Used during login when the user's 2FA method is 'email'. The email
|
|
136
|
+
* contains a 6-digit code that expires in the specified number of minutes.
|
|
137
|
+
* Follows the same fire-and-forget pattern as other email methods.
|
|
138
|
+
*
|
|
139
|
+
* @param user - Recipient user
|
|
140
|
+
* @param org - Organization (for branding and template override)
|
|
141
|
+
* @param code - 6-digit OTP code to include in the email
|
|
142
|
+
* @param expiresMinutes - Minutes until the code expires (e.g., 10)
|
|
143
|
+
* @param locale - Locale for i18n
|
|
144
|
+
*/
|
|
145
|
+
export declare function sendOtpCodeEmail(user: EmailUser, org: EmailOrganization, code: string, expiresMinutes: number, locale: string): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Send a password-changed confirmation email.
|
|
148
|
+
*
|
|
149
|
+
* @param user - Recipient user
|
|
150
|
+
* @param org - Organization (for branding and template override)
|
|
151
|
+
* @param locale - Locale for i18n
|
|
152
|
+
*/
|
|
153
|
+
export declare function sendPasswordChangedEmail(user: EmailUser, org: EmailOrganization, locale: string): Promise<void>;
|
|
154
|
+
//# sourceMappingURL=email-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-service.d.ts","sourceRoot":"","sources":["../../src/auth/email-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* High-level email service for auth workflow emails.
|
|
3
|
+
*
|
|
4
|
+
* Provides specific methods for each email type (magic link, password reset,
|
|
5
|
+
* invitation, welcome, password-changed). Each method:
|
|
6
|
+
* 1. Renders HTML + plaintext templates via the email renderer
|
|
7
|
+
* 2. Sends via the email transport
|
|
8
|
+
* 3. Writes an audit log entry
|
|
9
|
+
*
|
|
10
|
+
* All methods use fire-and-forget semantics: send failures are caught,
|
|
11
|
+
* logged as warnings, and audit-logged — they never propagate to callers.
|
|
12
|
+
* This ensures email delivery never blocks core authentication flows.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* await sendMagicLinkEmail(user, org, 'https://...', 'en');
|
|
16
|
+
*/
|
|
17
|
+
import { createSmtpTransport } from './email-transport.js';
|
|
18
|
+
import { renderEmail } from './email-renderer.js';
|
|
19
|
+
import { writeAuditLog } from '../lib/audit-log.js';
|
|
20
|
+
import { logger } from '../lib/logger.js';
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Module-level transport (lazy-initialized)
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
let transport = null;
|
|
25
|
+
/**
|
|
26
|
+
* Get or create the email transport singleton.
|
|
27
|
+
* Lazy-initialized on first use to avoid startup dependency issues.
|
|
28
|
+
*/
|
|
29
|
+
function getTransport() {
|
|
30
|
+
if (!transport) {
|
|
31
|
+
transport = createSmtpTransport();
|
|
32
|
+
}
|
|
33
|
+
return transport;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Render and deliver one recovery email while propagating template and SMTP failures.
|
|
37
|
+
*
|
|
38
|
+
* The durable worker owns retry and terminal policy. This function deliberately performs no
|
|
39
|
+
* catch-and-ignore behavior and emits no recipient, URL, or transport-error details.
|
|
40
|
+
*
|
|
41
|
+
* @param input - Recovery template, recipient, tenant, link, locale, and message identity.
|
|
42
|
+
*/
|
|
43
|
+
export async function sendRecoveryEmailStrict(input) {
|
|
44
|
+
const isMagicLink = input.type === 'magic_link';
|
|
45
|
+
const { html, text } = await renderEmail(isMagicLink ? 'magic-link' : 'password-reset', input.organization.slug, {
|
|
46
|
+
userName: getUserDisplayName(input.user),
|
|
47
|
+
[isMagicLink ? 'magicLinkUrl' : 'resetUrl']: input.recoveryUrl,
|
|
48
|
+
expiresMinutes: isMagicLink ? 15 : 60,
|
|
49
|
+
branding: buildBrandingContext(input.organization),
|
|
50
|
+
locale: input.locale,
|
|
51
|
+
});
|
|
52
|
+
await getTransport().send({
|
|
53
|
+
to: input.user.email,
|
|
54
|
+
subject: isMagicLink ? 'Sign in to your account' : 'Reset your password',
|
|
55
|
+
html,
|
|
56
|
+
text,
|
|
57
|
+
messageId: input.messageId,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Override the email transport (for testing).
|
|
62
|
+
* Pass null to reset to the default SMTP transport.
|
|
63
|
+
*
|
|
64
|
+
* @param override - Custom transport or null to reset
|
|
65
|
+
*/
|
|
66
|
+
export function setEmailTransport(override) {
|
|
67
|
+
transport = override;
|
|
68
|
+
}
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// Helpers
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
/**
|
|
73
|
+
* Build branding context object from organization data.
|
|
74
|
+
*
|
|
75
|
+
* @param org - Organization with branding fields
|
|
76
|
+
* @returns Branding object for template context
|
|
77
|
+
*/
|
|
78
|
+
function buildBrandingContext(org) {
|
|
79
|
+
return {
|
|
80
|
+
logoUrl: org.brandingLogoUrl ?? '',
|
|
81
|
+
primaryColor: org.brandingPrimaryColor ?? '#3B82F6',
|
|
82
|
+
companyName: org.brandingCompanyName ?? org.slug,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Build the display name for a user.
|
|
87
|
+
* Falls back to email prefix if no name is set.
|
|
88
|
+
*
|
|
89
|
+
* @param user - User with optional name fields
|
|
90
|
+
* @returns Display name string
|
|
91
|
+
*/
|
|
92
|
+
function getUserDisplayName(user) {
|
|
93
|
+
if (user.givenName) {
|
|
94
|
+
return user.familyName ? `${user.givenName} ${user.familyName}` : user.givenName;
|
|
95
|
+
}
|
|
96
|
+
// Fall back to email prefix (everything before @)
|
|
97
|
+
return user.email.split('@')[0];
|
|
98
|
+
}
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// Email methods (fire-and-forget)
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
/**
|
|
103
|
+
* Send a magic link email to a user.
|
|
104
|
+
*
|
|
105
|
+
* @param user - Recipient user
|
|
106
|
+
* @param org - Organization (for branding and template override)
|
|
107
|
+
* @param magicLinkUrl - Full URL the user clicks to authenticate
|
|
108
|
+
* @param locale - Locale for i18n (e.g., 'en')
|
|
109
|
+
*/
|
|
110
|
+
export async function sendMagicLinkEmail(user, org, magicLinkUrl, locale) {
|
|
111
|
+
try {
|
|
112
|
+
const { html, text } = await renderEmail('magic-link', org.slug, {
|
|
113
|
+
userName: getUserDisplayName(user),
|
|
114
|
+
magicLinkUrl,
|
|
115
|
+
expiresMinutes: 15,
|
|
116
|
+
branding: buildBrandingContext(org),
|
|
117
|
+
locale,
|
|
118
|
+
});
|
|
119
|
+
await getTransport().send({
|
|
120
|
+
to: user.email,
|
|
121
|
+
subject: 'Sign in to your account',
|
|
122
|
+
html,
|
|
123
|
+
text,
|
|
124
|
+
});
|
|
125
|
+
// Fire-and-forget audit log
|
|
126
|
+
writeAuditLog({
|
|
127
|
+
organizationId: org.id,
|
|
128
|
+
userId: user.id,
|
|
129
|
+
eventType: 'email.send.magic_link',
|
|
130
|
+
eventCategory: 'auth',
|
|
131
|
+
description: `Magic link email sent to ${user.email}`,
|
|
132
|
+
});
|
|
133
|
+
logger.debug({ userId: user.id, email: user.email }, 'Magic link email sent');
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
logger.warn({ error, userId: user.id, email: user.email }, 'Failed to send magic link email');
|
|
137
|
+
writeAuditLog({
|
|
138
|
+
organizationId: org.id,
|
|
139
|
+
userId: user.id,
|
|
140
|
+
eventType: 'email.send.failed',
|
|
141
|
+
eventCategory: 'auth',
|
|
142
|
+
description: `Failed to send magic link email to ${user.email}`,
|
|
143
|
+
metadata: { error: String(error), template: 'magic-link' },
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Send a password reset email to a user.
|
|
149
|
+
*
|
|
150
|
+
* @param user - Recipient user
|
|
151
|
+
* @param org - Organization (for branding and template override)
|
|
152
|
+
* @param resetUrl - Full URL the user clicks to reset their password
|
|
153
|
+
* @param locale - Locale for i18n
|
|
154
|
+
*/
|
|
155
|
+
export async function sendPasswordResetEmail(user, org, resetUrl, locale) {
|
|
156
|
+
try {
|
|
157
|
+
const { html, text } = await renderEmail('password-reset', org.slug, {
|
|
158
|
+
userName: getUserDisplayName(user),
|
|
159
|
+
resetUrl,
|
|
160
|
+
expiresMinutes: 60,
|
|
161
|
+
branding: buildBrandingContext(org),
|
|
162
|
+
locale,
|
|
163
|
+
});
|
|
164
|
+
await getTransport().send({
|
|
165
|
+
to: user.email,
|
|
166
|
+
subject: 'Reset your password',
|
|
167
|
+
html,
|
|
168
|
+
text,
|
|
169
|
+
});
|
|
170
|
+
writeAuditLog({
|
|
171
|
+
organizationId: org.id,
|
|
172
|
+
userId: user.id,
|
|
173
|
+
eventType: 'email.send.password_reset',
|
|
174
|
+
eventCategory: 'auth',
|
|
175
|
+
description: `Password reset email sent to ${user.email}`,
|
|
176
|
+
});
|
|
177
|
+
logger.debug({ userId: user.id, email: user.email }, 'Password reset email sent');
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
logger.warn({ error, userId: user.id, email: user.email }, 'Failed to send password reset email');
|
|
181
|
+
writeAuditLog({
|
|
182
|
+
organizationId: org.id,
|
|
183
|
+
userId: user.id,
|
|
184
|
+
eventType: 'email.send.failed',
|
|
185
|
+
eventCategory: 'auth',
|
|
186
|
+
description: `Failed to send password reset email to ${user.email}`,
|
|
187
|
+
metadata: { error: String(error), template: 'password-reset' },
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Build the template context for an invitation email.
|
|
193
|
+
*
|
|
194
|
+
* Shared between sendInvitationEmail() and renderInvitationEmail()
|
|
195
|
+
* to ensure consistency between sent emails and preview renders.
|
|
196
|
+
*
|
|
197
|
+
* @param user - Recipient user
|
|
198
|
+
* @param org - Organization for branding
|
|
199
|
+
* @param inviteUrl - Full URL the user clicks to accept
|
|
200
|
+
* @param locale - Locale for i18n
|
|
201
|
+
* @param options - Optional personal message and inviter name
|
|
202
|
+
* @returns Template context and computed subject line
|
|
203
|
+
*/
|
|
204
|
+
function buildInvitationContext(user, org, inviteUrl, locale, options) {
|
|
205
|
+
const orgName = org.brandingCompanyName ?? org.slug;
|
|
206
|
+
return {
|
|
207
|
+
context: {
|
|
208
|
+
userName: getUserDisplayName(user),
|
|
209
|
+
inviteUrl,
|
|
210
|
+
orgName,
|
|
211
|
+
expiresDays: 7,
|
|
212
|
+
branding: buildBrandingContext(org),
|
|
213
|
+
locale,
|
|
214
|
+
// Enhanced invitation fields — only included when provided
|
|
215
|
+
personalMessage: options?.personalMessage ?? null,
|
|
216
|
+
inviterName: options?.inviterName ?? null,
|
|
217
|
+
},
|
|
218
|
+
subject: options?.inviterName
|
|
219
|
+
? `${options.inviterName} has invited you to ${orgName}`
|
|
220
|
+
: `You've been invited to ${orgName}`,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Send an invitation email to a newly created user.
|
|
225
|
+
*
|
|
226
|
+
* @param user - Recipient user (newly created)
|
|
227
|
+
* @param org - Organization (for branding and template override)
|
|
228
|
+
* @param inviteUrl - Full URL the user clicks to accept the invitation
|
|
229
|
+
* @param locale - Locale for i18n
|
|
230
|
+
* @param options - Optional personal message and inviter name
|
|
231
|
+
*/
|
|
232
|
+
export async function sendInvitationEmail(user, org, inviteUrl, locale, options) {
|
|
233
|
+
try {
|
|
234
|
+
const { context, subject } = buildInvitationContext(user, org, inviteUrl, locale, options);
|
|
235
|
+
const { html, text } = await renderEmail('invitation', org.slug, context);
|
|
236
|
+
await getTransport().send({
|
|
237
|
+
to: user.email,
|
|
238
|
+
subject,
|
|
239
|
+
html,
|
|
240
|
+
text,
|
|
241
|
+
});
|
|
242
|
+
writeAuditLog({
|
|
243
|
+
organizationId: org.id,
|
|
244
|
+
userId: user.id,
|
|
245
|
+
eventType: 'email.send.invitation',
|
|
246
|
+
eventCategory: 'auth',
|
|
247
|
+
description: `Invitation email sent to ${user.email}`,
|
|
248
|
+
});
|
|
249
|
+
logger.debug({ userId: user.id, email: user.email }, 'Invitation email sent');
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
logger.warn({ error, userId: user.id, email: user.email }, 'Failed to send invitation email');
|
|
253
|
+
writeAuditLog({
|
|
254
|
+
organizationId: org.id,
|
|
255
|
+
userId: user.id,
|
|
256
|
+
eventType: 'email.send.failed',
|
|
257
|
+
eventCategory: 'auth',
|
|
258
|
+
description: `Failed to send invitation email to ${user.email}`,
|
|
259
|
+
metadata: { error: String(error), template: 'invitation' },
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Render an invitation email without sending it (for preview).
|
|
265
|
+
*
|
|
266
|
+
* Returns the HTML, plain text, and subject line that would be sent,
|
|
267
|
+
* allowing admins to preview the invitation before sending.
|
|
268
|
+
*
|
|
269
|
+
* @param user - Recipient user
|
|
270
|
+
* @param org - Organization for branding
|
|
271
|
+
* @param inviteUrl - Full URL (can be a placeholder for preview)
|
|
272
|
+
* @param locale - Locale for i18n
|
|
273
|
+
* @param options - Optional personal message and inviter name
|
|
274
|
+
* @returns Rendered HTML, plain text, and subject line
|
|
275
|
+
*/
|
|
276
|
+
export async function renderInvitationEmail(user, org, inviteUrl, locale, options) {
|
|
277
|
+
const { context, subject } = buildInvitationContext(user, org, inviteUrl, locale, options);
|
|
278
|
+
const { html, text } = await renderEmail('invitation', org.slug, context);
|
|
279
|
+
return { html, text, subject };
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Send a welcome email to a user (for passwordless users after first login).
|
|
283
|
+
*
|
|
284
|
+
* @param user - Recipient user
|
|
285
|
+
* @param org - Organization (for branding and template override)
|
|
286
|
+
* @param locale - Locale for i18n
|
|
287
|
+
*/
|
|
288
|
+
export async function sendWelcomeEmail(user, org, locale) {
|
|
289
|
+
try {
|
|
290
|
+
const { html, text } = await renderEmail('welcome', org.slug, {
|
|
291
|
+
userName: getUserDisplayName(user),
|
|
292
|
+
orgName: org.brandingCompanyName ?? org.slug,
|
|
293
|
+
branding: buildBrandingContext(org),
|
|
294
|
+
locale,
|
|
295
|
+
});
|
|
296
|
+
await getTransport().send({
|
|
297
|
+
to: user.email,
|
|
298
|
+
subject: `Welcome to ${org.brandingCompanyName ?? org.slug}`,
|
|
299
|
+
html,
|
|
300
|
+
text,
|
|
301
|
+
});
|
|
302
|
+
writeAuditLog({
|
|
303
|
+
organizationId: org.id,
|
|
304
|
+
userId: user.id,
|
|
305
|
+
eventType: 'email.send.welcome',
|
|
306
|
+
eventCategory: 'auth',
|
|
307
|
+
description: `Welcome email sent to ${user.email}`,
|
|
308
|
+
});
|
|
309
|
+
logger.debug({ userId: user.id, email: user.email }, 'Welcome email sent');
|
|
310
|
+
}
|
|
311
|
+
catch (error) {
|
|
312
|
+
logger.warn({ error, userId: user.id, email: user.email }, 'Failed to send welcome email');
|
|
313
|
+
writeAuditLog({
|
|
314
|
+
organizationId: org.id,
|
|
315
|
+
userId: user.id,
|
|
316
|
+
eventType: 'email.send.failed',
|
|
317
|
+
eventCategory: 'auth',
|
|
318
|
+
description: `Failed to send welcome email to ${user.email}`,
|
|
319
|
+
metadata: { error: String(error), template: 'welcome' },
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Send a 2FA OTP verification code email.
|
|
325
|
+
*
|
|
326
|
+
* Used during login when the user's 2FA method is 'email'. The email
|
|
327
|
+
* contains a 6-digit code that expires in the specified number of minutes.
|
|
328
|
+
* Follows the same fire-and-forget pattern as other email methods.
|
|
329
|
+
*
|
|
330
|
+
* @param user - Recipient user
|
|
331
|
+
* @param org - Organization (for branding and template override)
|
|
332
|
+
* @param code - 6-digit OTP code to include in the email
|
|
333
|
+
* @param expiresMinutes - Minutes until the code expires (e.g., 10)
|
|
334
|
+
* @param locale - Locale for i18n
|
|
335
|
+
*/
|
|
336
|
+
export async function sendOtpCodeEmail(user, org, code, expiresMinutes, locale) {
|
|
337
|
+
try {
|
|
338
|
+
const { html, text } = await renderEmail('otp-code', org.slug, {
|
|
339
|
+
userName: getUserDisplayName(user),
|
|
340
|
+
code,
|
|
341
|
+
expiresMinutes,
|
|
342
|
+
orgName: org.brandingCompanyName ?? org.slug,
|
|
343
|
+
branding: buildBrandingContext(org),
|
|
344
|
+
locale,
|
|
345
|
+
});
|
|
346
|
+
await getTransport().send({
|
|
347
|
+
to: user.email,
|
|
348
|
+
subject: `Your verification code: ${code}`,
|
|
349
|
+
html,
|
|
350
|
+
text,
|
|
351
|
+
});
|
|
352
|
+
// Fire-and-forget audit log
|
|
353
|
+
writeAuditLog({
|
|
354
|
+
organizationId: org.id,
|
|
355
|
+
userId: user.id,
|
|
356
|
+
eventType: 'email.send.otp_code',
|
|
357
|
+
eventCategory: 'auth',
|
|
358
|
+
description: `OTP code email sent to ${user.email}`,
|
|
359
|
+
});
|
|
360
|
+
logger.debug({ userId: user.id, email: user.email }, 'OTP code email sent');
|
|
361
|
+
}
|
|
362
|
+
catch (error) {
|
|
363
|
+
logger.warn({ error, userId: user.id, email: user.email }, 'Failed to send OTP code email');
|
|
364
|
+
writeAuditLog({
|
|
365
|
+
organizationId: org.id,
|
|
366
|
+
userId: user.id,
|
|
367
|
+
eventType: 'email.send.failed',
|
|
368
|
+
eventCategory: 'auth',
|
|
369
|
+
description: `Failed to send OTP code email to ${user.email}`,
|
|
370
|
+
metadata: { error: String(error), template: 'otp-code' },
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Send a password-changed confirmation email.
|
|
376
|
+
*
|
|
377
|
+
* @param user - Recipient user
|
|
378
|
+
* @param org - Organization (for branding and template override)
|
|
379
|
+
* @param locale - Locale for i18n
|
|
380
|
+
*/
|
|
381
|
+
export async function sendPasswordChangedEmail(user, org, locale) {
|
|
382
|
+
try {
|
|
383
|
+
const { html, text } = await renderEmail('password-changed', org.slug, {
|
|
384
|
+
userName: getUserDisplayName(user),
|
|
385
|
+
branding: buildBrandingContext(org),
|
|
386
|
+
locale,
|
|
387
|
+
});
|
|
388
|
+
await getTransport().send({
|
|
389
|
+
to: user.email,
|
|
390
|
+
subject: 'Your password has been changed',
|
|
391
|
+
html,
|
|
392
|
+
text,
|
|
393
|
+
});
|
|
394
|
+
writeAuditLog({
|
|
395
|
+
organizationId: org.id,
|
|
396
|
+
userId: user.id,
|
|
397
|
+
eventType: 'email.send.password_changed',
|
|
398
|
+
eventCategory: 'auth',
|
|
399
|
+
description: `Password changed email sent to ${user.email}`,
|
|
400
|
+
});
|
|
401
|
+
logger.debug({ userId: user.id, email: user.email }, 'Password changed email sent');
|
|
402
|
+
}
|
|
403
|
+
catch (error) {
|
|
404
|
+
logger.warn({ error, userId: user.id, email: user.email }, 'Failed to send password changed email');
|
|
405
|
+
writeAuditLog({
|
|
406
|
+
organizationId: org.id,
|
|
407
|
+
userId: user.id,
|
|
408
|
+
eventType: 'email.send.failed',
|
|
409
|
+
eventCategory: 'auth',
|
|
410
|
+
description: `Failed to send password changed email to ${user.email}`,
|
|
411
|
+
metadata: { error: String(error), template: 'password-changed' },
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
//# sourceMappingURL=email-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-service.js","sourceRoot":"","sources":["../../src/auth/email-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pluggable email transport abstraction.
|
|
3
|
+
*
|
|
4
|
+
* Defines a transport interface and provides a default SMTP implementation
|
|
5
|
+
* using Nodemailer. The interface allows swapping transports for testing
|
|
6
|
+
* (mock transport) or future providers (SES, SendGrid, etc.).
|
|
7
|
+
*
|
|
8
|
+
* SMTP configuration is read from the app config (`config.smtp.*`).
|
|
9
|
+
* Auth is only applied when `smtp.user` is provided — MailHog in dev
|
|
10
|
+
* doesn't need authentication.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const transport = createSmtpTransport();
|
|
14
|
+
* const result = await transport.send({
|
|
15
|
+
* to: 'user@example.com',
|
|
16
|
+
* subject: 'Welcome',
|
|
17
|
+
* html: '<h1>Hello</h1>',
|
|
18
|
+
* text: 'Hello',
|
|
19
|
+
* });
|
|
20
|
+
*/
|
|
21
|
+
/** Options for sending an email */
|
|
22
|
+
export interface SendEmailOptions {
|
|
23
|
+
/** Recipient email address */
|
|
24
|
+
to: string;
|
|
25
|
+
/** Sender address — falls back to config.smtp.from if not provided */
|
|
26
|
+
from?: string;
|
|
27
|
+
/** Email subject line */
|
|
28
|
+
subject: string;
|
|
29
|
+
/** HTML body */
|
|
30
|
+
html: string;
|
|
31
|
+
/** Plaintext body (fallback for clients that don't render HTML) */
|
|
32
|
+
text: string;
|
|
33
|
+
/** Reply-to address (optional) */
|
|
34
|
+
replyTo?: string;
|
|
35
|
+
/** Stable RFC 5322 message identity used for idempotent recovery retries. */
|
|
36
|
+
messageId?: string;
|
|
37
|
+
}
|
|
38
|
+
/** Result of sending an email */
|
|
39
|
+
export interface EmailResult {
|
|
40
|
+
/** SMTP message ID */
|
|
41
|
+
messageId: string;
|
|
42
|
+
/** Email addresses that accepted the message */
|
|
43
|
+
accepted: string[];
|
|
44
|
+
/** Email addresses that rejected the message */
|
|
45
|
+
rejected: string[];
|
|
46
|
+
}
|
|
47
|
+
/** Pluggable transport interface — SMTP is the default, others can be added */
|
|
48
|
+
export interface EmailTransport {
|
|
49
|
+
/** Send an email with the given options */
|
|
50
|
+
send(options: SendEmailOptions): Promise<EmailResult>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Create an SMTP email transport using Nodemailer.
|
|
54
|
+
*
|
|
55
|
+
* Reads SMTP configuration from the app config:
|
|
56
|
+
* - `config.smtp.host` — SMTP server hostname
|
|
57
|
+
* - `config.smtp.port` — SMTP port (465 = TLS, 587 = STARTTLS, 1025 = MailHog)
|
|
58
|
+
* - `config.smtp.user` — Username (optional, omit for MailHog)
|
|
59
|
+
* - `config.smtp.pass` — Password (optional)
|
|
60
|
+
* - `config.smtp.from` — Default sender address
|
|
61
|
+
*
|
|
62
|
+
* @returns EmailTransport implementation backed by Nodemailer SMTP
|
|
63
|
+
*/
|
|
64
|
+
export declare function createSmtpTransport(): EmailTransport;
|
|
65
|
+
//# sourceMappingURL=email-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-transport.d.ts","sourceRoot":"","sources":["../../src/auth/email-transport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAWH,mCAAmC;AACnC,MAAM,WAAW,gBAAgB;IAC/B,8BAA8B;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,iCAAiC;AACjC,MAAM,WAAW,WAAW;IAC1B,sBAAsB;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,2CAA2C;IAC3C,IAAI,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACvD;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,IAAI,cAAc,CAqDpD"}
|