@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,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permission service — business logic for permission management.
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates permission CRUD operations with slug format validation,
|
|
5
|
+
* uniqueness checks, deletion guards, cache management, and audit logging.
|
|
6
|
+
*
|
|
7
|
+
* Permission slugs follow the module:resource:action format (e.g.,
|
|
8
|
+
* "crm:contacts:read") and are immutable after creation — only name
|
|
9
|
+
* and description can be updated.
|
|
10
|
+
*
|
|
11
|
+
* All write operations follow the pattern:
|
|
12
|
+
* validate → DB operation → cache invalidate → audit log
|
|
13
|
+
*
|
|
14
|
+
* @see permission-repository.ts — Database operations
|
|
15
|
+
* @see mapping-repository.ts — Role-permission lookups
|
|
16
|
+
* @see cache.ts — Redis cache operations
|
|
17
|
+
*/
|
|
18
|
+
import { insertPermission, findPermissionById as repoFindPermissionById, findPermissionBySlug as repoFindPermissionBySlug, updatePermission as repoUpdatePermission, deletePermission as repoDeletePermission, listPermissionsByApplication as repoListPermissionsByApplication, permissionSlugExists, countRolesWithPermission, } from './permission-repository.js';
|
|
19
|
+
import { getRolesWithPermission as repoGetRolesWithPermission } from './mapping-repository.js';
|
|
20
|
+
import { invalidateAllUserRbacCaches } from './cache.js';
|
|
21
|
+
import { validatePermissionSlug } from './slugs.js';
|
|
22
|
+
import { PermissionNotFoundError, RbacValidationError } from './errors.js';
|
|
23
|
+
import { writeAuditLog } from '../lib/audit-log.js';
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// Create
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
/**
|
|
28
|
+
* Create a new permission for an application.
|
|
29
|
+
*
|
|
30
|
+
* Validates that the slug follows the module:resource:action format
|
|
31
|
+
* and ensures uniqueness within the application.
|
|
32
|
+
*
|
|
33
|
+
* @param input - Permission creation data
|
|
34
|
+
* @param actorId - Optional UUID of the admin performing the action
|
|
35
|
+
* @returns The newly created permission
|
|
36
|
+
* @throws RbacValidationError if slug format is invalid or already exists
|
|
37
|
+
*/
|
|
38
|
+
export async function createPermission(input, actorId) {
|
|
39
|
+
// Validate permission slug format (module:resource:action)
|
|
40
|
+
if (!validatePermissionSlug(input.slug)) {
|
|
41
|
+
throw new RbacValidationError(`Invalid permission slug format: "${input.slug}". Must follow module:resource:action pattern with at least 3 colon-separated segments.`);
|
|
42
|
+
}
|
|
43
|
+
// Check slug uniqueness within the application
|
|
44
|
+
const exists = await permissionSlugExists(input.applicationId, input.slug);
|
|
45
|
+
if (exists) {
|
|
46
|
+
throw new RbacValidationError(`Permission slug "${input.slug}" already exists for this application.`);
|
|
47
|
+
}
|
|
48
|
+
// Insert the permission
|
|
49
|
+
const permission = await insertPermission(input);
|
|
50
|
+
// Audit log (fire-and-forget)
|
|
51
|
+
void writeAuditLog({
|
|
52
|
+
eventType: 'permission.created',
|
|
53
|
+
eventCategory: 'admin',
|
|
54
|
+
actorId,
|
|
55
|
+
metadata: {
|
|
56
|
+
permissionId: permission.id,
|
|
57
|
+
applicationId: permission.applicationId,
|
|
58
|
+
slug: permission.slug,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
return permission;
|
|
62
|
+
}
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Read
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
/**
|
|
67
|
+
* Find a permission by ID.
|
|
68
|
+
*
|
|
69
|
+
* @param id - Permission UUID
|
|
70
|
+
* @returns Permission or null if not found
|
|
71
|
+
*/
|
|
72
|
+
export async function findPermissionById(id) {
|
|
73
|
+
return repoFindPermissionById(id);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Find a permission by application ID and slug.
|
|
77
|
+
*
|
|
78
|
+
* @param applicationId - Application UUID
|
|
79
|
+
* @param slug - Permission slug
|
|
80
|
+
* @returns Permission or null if not found
|
|
81
|
+
*/
|
|
82
|
+
export async function findPermissionBySlug(applicationId, slug) {
|
|
83
|
+
return repoFindPermissionBySlug(applicationId, slug);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* List permissions for an application, optionally filtered by module.
|
|
87
|
+
*
|
|
88
|
+
* @param applicationId - Application UUID
|
|
89
|
+
* @param moduleId - Optional module UUID to filter by
|
|
90
|
+
* @returns Array of permissions
|
|
91
|
+
*/
|
|
92
|
+
export async function listPermissionsByApplication(applicationId, moduleId) {
|
|
93
|
+
return repoListPermissionsByApplication(applicationId, moduleId);
|
|
94
|
+
}
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
// Update
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
/**
|
|
99
|
+
* Update a permission by ID (name and description only — slug is immutable).
|
|
100
|
+
*
|
|
101
|
+
* @param id - Permission UUID
|
|
102
|
+
* @param input - Fields to update (name, description only)
|
|
103
|
+
* @param actorId - Optional UUID of the admin performing the action
|
|
104
|
+
* @returns Updated permission
|
|
105
|
+
* @throws PermissionNotFoundError if permission doesn't exist
|
|
106
|
+
*/
|
|
107
|
+
export async function updatePermission(id, input, actorId) {
|
|
108
|
+
// Verify permission exists
|
|
109
|
+
const existing = await repoFindPermissionById(id);
|
|
110
|
+
if (!existing) {
|
|
111
|
+
throw new PermissionNotFoundError(id);
|
|
112
|
+
}
|
|
113
|
+
// Perform the update (slug is not updatable at the repository level)
|
|
114
|
+
const updated = await repoUpdatePermission(id, input);
|
|
115
|
+
// Audit log (fire-and-forget)
|
|
116
|
+
void writeAuditLog({
|
|
117
|
+
eventType: 'permission.updated',
|
|
118
|
+
eventCategory: 'admin',
|
|
119
|
+
actorId,
|
|
120
|
+
metadata: { permissionId: id, changes: input },
|
|
121
|
+
});
|
|
122
|
+
return updated;
|
|
123
|
+
}
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
// Delete
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
/**
|
|
128
|
+
* Delete a permission by ID.
|
|
129
|
+
*
|
|
130
|
+
* By default (force=false), refuses to delete permissions that are
|
|
131
|
+
* assigned to any role. Pass force=true to delete regardless —
|
|
132
|
+
* CASCADE will remove role_permissions entries.
|
|
133
|
+
*
|
|
134
|
+
* @param id - Permission UUID
|
|
135
|
+
* @param force - If true, delete even if assigned to roles
|
|
136
|
+
* @param actorId - Optional UUID of the admin performing the action
|
|
137
|
+
* @throws PermissionNotFoundError if permission doesn't exist
|
|
138
|
+
* @throws RbacValidationError if assigned to roles and force is false
|
|
139
|
+
*/
|
|
140
|
+
export async function deletePermission(id, force = false, actorId) {
|
|
141
|
+
// Verify permission exists
|
|
142
|
+
const existing = await repoFindPermissionById(id);
|
|
143
|
+
if (!existing) {
|
|
144
|
+
throw new PermissionNotFoundError(id);
|
|
145
|
+
}
|
|
146
|
+
// Deletion guard: check for assigned roles
|
|
147
|
+
if (!force) {
|
|
148
|
+
const roleCount = await countRolesWithPermission(id);
|
|
149
|
+
if (roleCount > 0) {
|
|
150
|
+
throw new RbacValidationError(`Cannot delete permission "${existing.slug}": assigned to ${roleCount} role(s). Use force=true to override.`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Delete the permission (CASCADE handles related records)
|
|
154
|
+
await repoDeletePermission(id);
|
|
155
|
+
// Invalidate user caches — permissions may have changed for users who had this
|
|
156
|
+
if (force) {
|
|
157
|
+
await invalidateAllUserRbacCaches();
|
|
158
|
+
}
|
|
159
|
+
// Audit log (fire-and-forget)
|
|
160
|
+
void writeAuditLog({
|
|
161
|
+
eventType: 'permission.deleted',
|
|
162
|
+
eventCategory: 'admin',
|
|
163
|
+
actorId,
|
|
164
|
+
metadata: { permissionId: id, slug: existing.slug, force },
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
// ---------------------------------------------------------------------------
|
|
168
|
+
// Role lookups
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
/**
|
|
171
|
+
* Get all roles that have a specific permission assigned.
|
|
172
|
+
*
|
|
173
|
+
* @param permissionId - Permission UUID
|
|
174
|
+
* @returns Array of roles with this permission
|
|
175
|
+
*/
|
|
176
|
+
export async function getRolesWithPermission(permissionId) {
|
|
177
|
+
return repoGetRolesWithPermission(permissionId);
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=permission-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permission-service.js","sourceRoot":"","sources":["../../src/rbac/permission-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role repository — PostgreSQL data access layer.
|
|
3
|
+
*
|
|
4
|
+
* Provides CRUD operations for the `roles` table using parameterized
|
|
5
|
+
* queries. Each function acquires the pool via `getPool()` and returns
|
|
6
|
+
* mapped Role objects via `mapRowToRole()`.
|
|
7
|
+
*
|
|
8
|
+
* Roles are scoped to an application (application_id FK) with a unique
|
|
9
|
+
* slug per application enforced by the DB constraint UNIQUE(application_id, slug).
|
|
10
|
+
*
|
|
11
|
+
* Key patterns:
|
|
12
|
+
* - Dynamic UPDATE query builder for partial updates (name, slug, description)
|
|
13
|
+
* - Simple list by application (no pagination — typically <100 roles per app)
|
|
14
|
+
* - Slug existence check with optional excludeId for update scenarios
|
|
15
|
+
* - User count for deletion guard (prevent deleting roles with assigned users)
|
|
16
|
+
*
|
|
17
|
+
* Database table: roles (see migration 006_roles_permissions.sql)
|
|
18
|
+
*/
|
|
19
|
+
import type { Role, CreateRoleInput, UpdateRoleInput } from './types.js';
|
|
20
|
+
/**
|
|
21
|
+
* Insert a new role into the database.
|
|
22
|
+
*
|
|
23
|
+
* Uses RETURNING * to get the full row back in a single round trip.
|
|
24
|
+
* The (application_id, slug) pair must be unique (enforced by DB constraint).
|
|
25
|
+
*
|
|
26
|
+
* @param input - Role data to insert
|
|
27
|
+
* @returns The newly created role
|
|
28
|
+
* @throws If (application_id, slug) already exists (unique constraint violation)
|
|
29
|
+
*/
|
|
30
|
+
export declare function insertRole(input: CreateRoleInput): Promise<Role>;
|
|
31
|
+
/**
|
|
32
|
+
* Find a role by its UUID.
|
|
33
|
+
*
|
|
34
|
+
* @param id - Role UUID
|
|
35
|
+
* @returns Role or null if not found
|
|
36
|
+
*/
|
|
37
|
+
export declare function findRoleById(id: string): Promise<Role | null>;
|
|
38
|
+
/**
|
|
39
|
+
* Find a role by application ID and slug.
|
|
40
|
+
*
|
|
41
|
+
* @param applicationId - Application UUID
|
|
42
|
+
* @param slug - Role slug (unique within application)
|
|
43
|
+
* @returns Role or null if not found
|
|
44
|
+
*/
|
|
45
|
+
export declare function findRoleBySlug(applicationId: string, slug: string): Promise<Role | null>;
|
|
46
|
+
/**
|
|
47
|
+
* Update a role's fields using a dynamic SET clause.
|
|
48
|
+
*
|
|
49
|
+
* Only explicitly provided fields (not undefined) are included in the
|
|
50
|
+
* UPDATE statement. This allows partial updates without overwriting
|
|
51
|
+
* fields that weren't specified. Null is a valid value for description
|
|
52
|
+
* (clears it).
|
|
53
|
+
*
|
|
54
|
+
* @param id - Role UUID
|
|
55
|
+
* @param input - Fields to update (only non-undefined fields are applied)
|
|
56
|
+
* @returns Updated role
|
|
57
|
+
* @throws Error if role not found or no fields provided
|
|
58
|
+
*/
|
|
59
|
+
export declare function updateRole(id: string, input: UpdateRoleInput): Promise<Role>;
|
|
60
|
+
/**
|
|
61
|
+
* Delete a role by ID.
|
|
62
|
+
*
|
|
63
|
+
* Returns true if a row was deleted, false if the role didn't exist.
|
|
64
|
+
* CASCADE constraints will automatically remove related role_permissions
|
|
65
|
+
* and user_roles entries.
|
|
66
|
+
*
|
|
67
|
+
* @param id - Role UUID
|
|
68
|
+
* @returns true if deleted, false if not found
|
|
69
|
+
*/
|
|
70
|
+
export declare function deleteRole(id: string): Promise<boolean>;
|
|
71
|
+
/**
|
|
72
|
+
* List all roles for an application, ordered by name ascending.
|
|
73
|
+
*
|
|
74
|
+
* Returns a simple array (no pagination) since applications typically
|
|
75
|
+
* have a manageable number of roles (<100).
|
|
76
|
+
*
|
|
77
|
+
* @param applicationId - Application UUID
|
|
78
|
+
* @returns Array of roles for the application
|
|
79
|
+
*/
|
|
80
|
+
export declare function listRolesByApplication(applicationId: string): Promise<Role[]>;
|
|
81
|
+
/**
|
|
82
|
+
* Check if a role slug already exists for a given application.
|
|
83
|
+
*
|
|
84
|
+
* Used for uniqueness validation before insert or update. The optional
|
|
85
|
+
* excludeId parameter allows excluding a specific role (for updates —
|
|
86
|
+
* a role's own current slug should not block the update).
|
|
87
|
+
*
|
|
88
|
+
* @param applicationId - Application UUID
|
|
89
|
+
* @param slug - Slug to check
|
|
90
|
+
* @param excludeId - Optional role ID to exclude from the check
|
|
91
|
+
* @returns true if the slug already exists
|
|
92
|
+
*/
|
|
93
|
+
export declare function roleSlugExists(applicationId: string, slug: string, excludeId?: string): Promise<boolean>;
|
|
94
|
+
/**
|
|
95
|
+
* Count users assigned to a role.
|
|
96
|
+
*
|
|
97
|
+
* Used by the service layer as a deletion guard: if users are assigned,
|
|
98
|
+
* the role cannot be deleted without force=true.
|
|
99
|
+
*
|
|
100
|
+
* @param roleId - Role UUID
|
|
101
|
+
* @returns Number of users with this role
|
|
102
|
+
*/
|
|
103
|
+
export declare function countUsersWithRole(roleId: string): Promise<number>;
|
|
104
|
+
//# sourceMappingURL=role-repository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-repository.d.ts","sourceRoot":"","sources":["../../src/rbac/role-repository.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAW,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAOlF;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBtE;AAMD;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAUnE;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAU9F;AAgBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BlF;AAMD;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAS7D;AAMD;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CASnF;AAMD;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAClC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAgBlB;AAMD;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CASxE"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role repository — PostgreSQL data access layer.
|
|
3
|
+
*
|
|
4
|
+
* Provides CRUD operations for the `roles` table using parameterized
|
|
5
|
+
* queries. Each function acquires the pool via `getPool()` and returns
|
|
6
|
+
* mapped Role objects via `mapRowToRole()`.
|
|
7
|
+
*
|
|
8
|
+
* Roles are scoped to an application (application_id FK) with a unique
|
|
9
|
+
* slug per application enforced by the DB constraint UNIQUE(application_id, slug).
|
|
10
|
+
*
|
|
11
|
+
* Key patterns:
|
|
12
|
+
* - Dynamic UPDATE query builder for partial updates (name, slug, description)
|
|
13
|
+
* - Simple list by application (no pagination — typically <100 roles per app)
|
|
14
|
+
* - Slug existence check with optional excludeId for update scenarios
|
|
15
|
+
* - User count for deletion guard (prevent deleting roles with assigned users)
|
|
16
|
+
*
|
|
17
|
+
* Database table: roles (see migration 006_roles_permissions.sql)
|
|
18
|
+
*/
|
|
19
|
+
import { getPool } from '../lib/database.js';
|
|
20
|
+
import { mapRowToRole } from './types.js';
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Insert
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
/**
|
|
25
|
+
* Insert a new role into the database.
|
|
26
|
+
*
|
|
27
|
+
* Uses RETURNING * to get the full row back in a single round trip.
|
|
28
|
+
* The (application_id, slug) pair must be unique (enforced by DB constraint).
|
|
29
|
+
*
|
|
30
|
+
* @param input - Role data to insert
|
|
31
|
+
* @returns The newly created role
|
|
32
|
+
* @throws If (application_id, slug) already exists (unique constraint violation)
|
|
33
|
+
*/
|
|
34
|
+
export async function insertRole(input) {
|
|
35
|
+
const pool = getPool();
|
|
36
|
+
const result = await pool.query(`INSERT INTO roles (application_id, name, slug, description)
|
|
37
|
+
VALUES ($1, $2, $3, $4)
|
|
38
|
+
RETURNING *`, [
|
|
39
|
+
input.applicationId,
|
|
40
|
+
input.name,
|
|
41
|
+
input.slug ?? null,
|
|
42
|
+
input.description ?? null,
|
|
43
|
+
]);
|
|
44
|
+
return mapRowToRole(result.rows[0]);
|
|
45
|
+
}
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Find
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
/**
|
|
50
|
+
* Find a role by its UUID.
|
|
51
|
+
*
|
|
52
|
+
* @param id - Role UUID
|
|
53
|
+
* @returns Role or null if not found
|
|
54
|
+
*/
|
|
55
|
+
export async function findRoleById(id) {
|
|
56
|
+
const pool = getPool();
|
|
57
|
+
const result = await pool.query('SELECT * FROM roles WHERE id = $1', [id]);
|
|
58
|
+
if (result.rows.length === 0)
|
|
59
|
+
return null;
|
|
60
|
+
return mapRowToRole(result.rows[0]);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Find a role by application ID and slug.
|
|
64
|
+
*
|
|
65
|
+
* @param applicationId - Application UUID
|
|
66
|
+
* @param slug - Role slug (unique within application)
|
|
67
|
+
* @returns Role or null if not found
|
|
68
|
+
*/
|
|
69
|
+
export async function findRoleBySlug(applicationId, slug) {
|
|
70
|
+
const pool = getPool();
|
|
71
|
+
const result = await pool.query('SELECT * FROM roles WHERE application_id = $1 AND slug = $2', [applicationId, slug]);
|
|
72
|
+
if (result.rows.length === 0)
|
|
73
|
+
return null;
|
|
74
|
+
return mapRowToRole(result.rows[0]);
|
|
75
|
+
}
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
// Update
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
/**
|
|
80
|
+
* Mapping from UpdateRoleInput keys to database column names.
|
|
81
|
+
* Used by the dynamic query builder to construct SET clauses.
|
|
82
|
+
*/
|
|
83
|
+
const FIELD_TO_COLUMN = {
|
|
84
|
+
name: 'name',
|
|
85
|
+
slug: 'slug',
|
|
86
|
+
description: 'description',
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Update a role's fields using a dynamic SET clause.
|
|
90
|
+
*
|
|
91
|
+
* Only explicitly provided fields (not undefined) are included in the
|
|
92
|
+
* UPDATE statement. This allows partial updates without overwriting
|
|
93
|
+
* fields that weren't specified. Null is a valid value for description
|
|
94
|
+
* (clears it).
|
|
95
|
+
*
|
|
96
|
+
* @param id - Role UUID
|
|
97
|
+
* @param input - Fields to update (only non-undefined fields are applied)
|
|
98
|
+
* @returns Updated role
|
|
99
|
+
* @throws Error if role not found or no fields provided
|
|
100
|
+
*/
|
|
101
|
+
export async function updateRole(id, input) {
|
|
102
|
+
const pool = getPool();
|
|
103
|
+
// Build dynamic SET clause from provided fields
|
|
104
|
+
const setClauses = [];
|
|
105
|
+
const values = [id]; // $1 is always the ID
|
|
106
|
+
let paramIndex = 2;
|
|
107
|
+
for (const [field, column] of Object.entries(FIELD_TO_COLUMN)) {
|
|
108
|
+
const value = input[field];
|
|
109
|
+
// Include the field if it's explicitly set (including null for clearing)
|
|
110
|
+
if (value !== undefined) {
|
|
111
|
+
setClauses.push(`${column} = $${paramIndex}`);
|
|
112
|
+
values.push(value);
|
|
113
|
+
paramIndex++;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (setClauses.length === 0) {
|
|
117
|
+
throw new Error('No fields to update');
|
|
118
|
+
}
|
|
119
|
+
const sql = `UPDATE roles SET ${setClauses.join(', ')} WHERE id = $1 RETURNING *`;
|
|
120
|
+
const result = await pool.query(sql, values);
|
|
121
|
+
if (result.rows.length === 0) {
|
|
122
|
+
throw new Error('Role not found');
|
|
123
|
+
}
|
|
124
|
+
return mapRowToRole(result.rows[0]);
|
|
125
|
+
}
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
// Delete
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
/**
|
|
130
|
+
* Delete a role by ID.
|
|
131
|
+
*
|
|
132
|
+
* Returns true if a row was deleted, false if the role didn't exist.
|
|
133
|
+
* CASCADE constraints will automatically remove related role_permissions
|
|
134
|
+
* and user_roles entries.
|
|
135
|
+
*
|
|
136
|
+
* @param id - Role UUID
|
|
137
|
+
* @returns true if deleted, false if not found
|
|
138
|
+
*/
|
|
139
|
+
export async function deleteRole(id) {
|
|
140
|
+
const pool = getPool();
|
|
141
|
+
const result = await pool.query('DELETE FROM roles WHERE id = $1', [id]);
|
|
142
|
+
return (result.rowCount ?? 0) > 0;
|
|
143
|
+
}
|
|
144
|
+
// ---------------------------------------------------------------------------
|
|
145
|
+
// List
|
|
146
|
+
// ---------------------------------------------------------------------------
|
|
147
|
+
/**
|
|
148
|
+
* List all roles for an application, ordered by name ascending.
|
|
149
|
+
*
|
|
150
|
+
* Returns a simple array (no pagination) since applications typically
|
|
151
|
+
* have a manageable number of roles (<100).
|
|
152
|
+
*
|
|
153
|
+
* @param applicationId - Application UUID
|
|
154
|
+
* @returns Array of roles for the application
|
|
155
|
+
*/
|
|
156
|
+
export async function listRolesByApplication(applicationId) {
|
|
157
|
+
const pool = getPool();
|
|
158
|
+
const result = await pool.query('SELECT * FROM roles WHERE application_id = $1 ORDER BY name ASC', [applicationId]);
|
|
159
|
+
return result.rows.map(mapRowToRole);
|
|
160
|
+
}
|
|
161
|
+
// ---------------------------------------------------------------------------
|
|
162
|
+
// Slug existence check
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
/**
|
|
165
|
+
* Check if a role slug already exists for a given application.
|
|
166
|
+
*
|
|
167
|
+
* Used for uniqueness validation before insert or update. The optional
|
|
168
|
+
* excludeId parameter allows excluding a specific role (for updates —
|
|
169
|
+
* a role's own current slug should not block the update).
|
|
170
|
+
*
|
|
171
|
+
* @param applicationId - Application UUID
|
|
172
|
+
* @param slug - Slug to check
|
|
173
|
+
* @param excludeId - Optional role ID to exclude from the check
|
|
174
|
+
* @returns true if the slug already exists
|
|
175
|
+
*/
|
|
176
|
+
export async function roleSlugExists(applicationId, slug, excludeId) {
|
|
177
|
+
const pool = getPool();
|
|
178
|
+
if (excludeId) {
|
|
179
|
+
const result = await pool.query('SELECT EXISTS(SELECT 1 FROM roles WHERE application_id = $1 AND slug = $2 AND id != $3) as exists', [applicationId, slug, excludeId]);
|
|
180
|
+
return result.rows[0].exists;
|
|
181
|
+
}
|
|
182
|
+
const result = await pool.query('SELECT EXISTS(SELECT 1 FROM roles WHERE application_id = $1 AND slug = $2) as exists', [applicationId, slug]);
|
|
183
|
+
return result.rows[0].exists;
|
|
184
|
+
}
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
// User count (deletion guard)
|
|
187
|
+
// ---------------------------------------------------------------------------
|
|
188
|
+
/**
|
|
189
|
+
* Count users assigned to a role.
|
|
190
|
+
*
|
|
191
|
+
* Used by the service layer as a deletion guard: if users are assigned,
|
|
192
|
+
* the role cannot be deleted without force=true.
|
|
193
|
+
*
|
|
194
|
+
* @param roleId - Role UUID
|
|
195
|
+
* @returns Number of users with this role
|
|
196
|
+
*/
|
|
197
|
+
export async function countUsersWithRole(roleId) {
|
|
198
|
+
const pool = getPool();
|
|
199
|
+
const result = await pool.query('SELECT COUNT(*)::int as count FROM user_roles WHERE role_id = $1', [roleId]);
|
|
200
|
+
return parseInt(result.rows[0].count, 10);
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=role-repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-repository.js","sourceRoot":"","sources":["../../src/rbac/role-repository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role service — business logic for role management.
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates role CRUD operations with slug validation, uniqueness
|
|
5
|
+
* checks, deletion guards, cache management, and audit logging.
|
|
6
|
+
* Also handles role-permission assignment operations.
|
|
7
|
+
*
|
|
8
|
+
* All write operations follow the pattern:
|
|
9
|
+
* validate → DB operation → cache invalidate/re-cache → audit log
|
|
10
|
+
*
|
|
11
|
+
* Uses fire-and-forget audit logging — audit failures never block
|
|
12
|
+
* the primary operation.
|
|
13
|
+
*
|
|
14
|
+
* @see role-repository.ts — Database operations
|
|
15
|
+
* @see mapping-repository.ts — Role-permission join table operations
|
|
16
|
+
* @see cache.ts — Redis cache operations
|
|
17
|
+
*/
|
|
18
|
+
import type { Role, Permission, CreateRoleInput, UpdateRoleInput } from './types.js';
|
|
19
|
+
/**
|
|
20
|
+
* Create a new role for an application.
|
|
21
|
+
*
|
|
22
|
+
* Auto-generates a slug from the name if not explicitly provided.
|
|
23
|
+
* Validates slug format and ensures uniqueness within the application.
|
|
24
|
+
*
|
|
25
|
+
* @param input - Role creation data
|
|
26
|
+
* @param actorId - Optional UUID of the admin performing the action
|
|
27
|
+
* @returns The newly created role
|
|
28
|
+
* @throws RbacValidationError if slug is invalid or already exists
|
|
29
|
+
*/
|
|
30
|
+
export declare function createRole(input: CreateRoleInput, actorId?: string): Promise<Role>;
|
|
31
|
+
/**
|
|
32
|
+
* Find a role by ID. Cache-first, falls back to DB.
|
|
33
|
+
*
|
|
34
|
+
* @param id - Role UUID
|
|
35
|
+
* @returns Role or null if not found
|
|
36
|
+
*/
|
|
37
|
+
export declare function findRoleById(id: string): Promise<Role | null>;
|
|
38
|
+
/**
|
|
39
|
+
* Find a role by application ID and slug.
|
|
40
|
+
*
|
|
41
|
+
* @param applicationId - Application UUID
|
|
42
|
+
* @param slug - Role slug
|
|
43
|
+
* @returns Role or null if not found
|
|
44
|
+
*/
|
|
45
|
+
export declare function findRoleBySlug(applicationId: string, slug: string): Promise<Role | null>;
|
|
46
|
+
/**
|
|
47
|
+
* List all roles for an application.
|
|
48
|
+
*
|
|
49
|
+
* @param applicationId - Application UUID
|
|
50
|
+
* @returns Array of roles
|
|
51
|
+
*/
|
|
52
|
+
export declare function listRolesByApplication(applicationId: string): Promise<Role[]>;
|
|
53
|
+
/**
|
|
54
|
+
* Update a role by ID.
|
|
55
|
+
*
|
|
56
|
+
* If the slug is being changed, validates the new slug format and
|
|
57
|
+
* checks uniqueness within the application. Invalidates and re-caches
|
|
58
|
+
* the role after update.
|
|
59
|
+
*
|
|
60
|
+
* @param id - Role UUID
|
|
61
|
+
* @param input - Fields to update
|
|
62
|
+
* @param actorId - Optional UUID of the admin performing the action
|
|
63
|
+
* @returns Updated role
|
|
64
|
+
* @throws RoleNotFoundError if role doesn't exist
|
|
65
|
+
* @throws RbacValidationError if new slug is invalid or already exists
|
|
66
|
+
*/
|
|
67
|
+
export declare function updateRole(id: string, input: UpdateRoleInput, actorId?: string): Promise<Role>;
|
|
68
|
+
/**
|
|
69
|
+
* Delete a role by ID.
|
|
70
|
+
*
|
|
71
|
+
* By default (force=false), refuses to delete roles that have users
|
|
72
|
+
* assigned. Pass force=true to delete regardless — CASCADE will
|
|
73
|
+
* remove user_roles and role_permissions entries.
|
|
74
|
+
*
|
|
75
|
+
* @param id - Role UUID
|
|
76
|
+
* @param force - If true, delete even if users are assigned
|
|
77
|
+
* @param actorId - Optional UUID of the admin performing the action
|
|
78
|
+
* @throws RoleNotFoundError if role doesn't exist
|
|
79
|
+
* @throws RbacValidationError if users are assigned and force is false
|
|
80
|
+
*/
|
|
81
|
+
export declare function deleteRole(id: string, force?: boolean, actorId?: string): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* Assign permissions to a role.
|
|
84
|
+
*
|
|
85
|
+
* Delegates to the mapping repository for bulk insert. Invalidates
|
|
86
|
+
* all user RBAC caches since user permissions may have changed.
|
|
87
|
+
*
|
|
88
|
+
* @param roleId - Role UUID
|
|
89
|
+
* @param permissionIds - Array of permission UUIDs to assign
|
|
90
|
+
* @param actorId - Optional UUID of the admin performing the action
|
|
91
|
+
*/
|
|
92
|
+
export declare function assignPermissionsToRole(roleId: string, permissionIds: string[], actorId?: string): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Remove permissions from a role.
|
|
95
|
+
*
|
|
96
|
+
* Delegates to the mapping repository. Invalidates all user RBAC
|
|
97
|
+
* caches since user permissions may have changed.
|
|
98
|
+
*
|
|
99
|
+
* @param roleId - Role UUID
|
|
100
|
+
* @param permissionIds - Array of permission UUIDs to remove
|
|
101
|
+
* @param actorId - Optional UUID of the admin performing the action
|
|
102
|
+
*/
|
|
103
|
+
export declare function removePermissionsFromRole(roleId: string, permissionIds: string[], actorId?: string): Promise<void>;
|
|
104
|
+
/**
|
|
105
|
+
* Get all permissions assigned to a role.
|
|
106
|
+
*
|
|
107
|
+
* @param roleId - Role UUID
|
|
108
|
+
* @returns Array of permissions
|
|
109
|
+
*/
|
|
110
|
+
export declare function getPermissionsForRole(roleId: string): Promise<Permission[]>;
|
|
111
|
+
//# sourceMappingURL=role-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"role-service.d.ts","sourceRoot":"","sources":["../../src/rbac/role-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AA0BH,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAMrF;;;;;;;;;;GAUG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCxF;AAMD;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAanE;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAE9F;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAEnF;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,UAAU,CAC9B,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,eAAe,EACtB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAuCf;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAsB,UAAU,CAC9B,EAAE,EAAE,MAAM,EACV,KAAK,GAAE,OAAe,EACtB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAkCf;AAMD;;;;;;;;;GASG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EAAE,EACvB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;;;;;;;;GASG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EAAE,EACvB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAEjF"}
|