@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,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tenant-safe bulk status operations with ordered partial results.
|
|
3
|
+
*
|
|
4
|
+
* Whole-request validation completes before the first mutation. Each admitted item then owns one
|
|
5
|
+
* database transaction containing its lock, transition, update, and durable audit record. Domain
|
|
6
|
+
* rejections are isolated to that item. Dependency failures stop the operation and mark the
|
|
7
|
+
* current and remaining items as not attempted.
|
|
8
|
+
*/
|
|
9
|
+
import { randomUUID } from 'node:crypto';
|
|
10
|
+
import { getPool } from './database.js';
|
|
11
|
+
import { logger } from './logger.js';
|
|
12
|
+
import { writeAuditLogInTransaction } from './audit-log.js';
|
|
13
|
+
const ORGANIZATION_TRANSITIONS = Object.freeze({
|
|
14
|
+
activate: { from: ['suspended'], to: 'active' },
|
|
15
|
+
suspend: { from: ['active'], to: 'suspended' },
|
|
16
|
+
archive: { from: ['active', 'suspended'], to: 'archived' },
|
|
17
|
+
});
|
|
18
|
+
const USER_TRANSITIONS = Object.freeze({
|
|
19
|
+
activate: { from: ['inactive', 'suspended'], to: 'active' },
|
|
20
|
+
deactivate: { from: ['active'], to: 'inactive' },
|
|
21
|
+
suspend: { from: ['active'], to: 'suspended' },
|
|
22
|
+
lock: { from: ['active'], to: 'locked' },
|
|
23
|
+
unlock: { from: ['locked'], to: 'active' },
|
|
24
|
+
});
|
|
25
|
+
const MAXIMUM_ITEMS = 100;
|
|
26
|
+
const MAXIMUM_REASON_CHARACTERS = 500;
|
|
27
|
+
/** Validate every request-level invariant before opening an item transaction. */
|
|
28
|
+
function requireValidInput(input) {
|
|
29
|
+
if (input.entityIds.length === 0)
|
|
30
|
+
return undefined;
|
|
31
|
+
if (input.entityIds.length > MAXIMUM_ITEMS) {
|
|
32
|
+
throw new Error('Bulk operations are limited to 100 items at a time');
|
|
33
|
+
}
|
|
34
|
+
if (new Set(input.entityIds).size !== input.entityIds.length) {
|
|
35
|
+
throw new Error('Bulk operations require unique entity identifiers');
|
|
36
|
+
}
|
|
37
|
+
if (input.reason !== undefined && input.reason.length > MAXIMUM_REASON_CHARACTERS) {
|
|
38
|
+
throw new Error('Bulk operation reason is limited to 500 characters');
|
|
39
|
+
}
|
|
40
|
+
if (input.entityType === 'user' && !input.organizationId) {
|
|
41
|
+
throw new Error('Organization scope is required for user bulk operations');
|
|
42
|
+
}
|
|
43
|
+
const transitions = input.entityType === 'organization' ? ORGANIZATION_TRANSITIONS : USER_TRANSITIONS;
|
|
44
|
+
const transition = transitions[input.action];
|
|
45
|
+
if (!transition) {
|
|
46
|
+
throw new Error(`Invalid action '${input.action}' for entity type '${input.entityType}'`);
|
|
47
|
+
}
|
|
48
|
+
return transition;
|
|
49
|
+
}
|
|
50
|
+
/** Roll back an open item transaction before returning a domain rejection. */
|
|
51
|
+
async function rollback(client) {
|
|
52
|
+
await client.query('ROLLBACK');
|
|
53
|
+
}
|
|
54
|
+
/** Build the tenant-qualified row lock for the closed entity catalog. */
|
|
55
|
+
async function lockCurrentStatus(client, input, id) {
|
|
56
|
+
if (input.entityType === 'user') {
|
|
57
|
+
const result = await client.query(`SELECT status FROM users
|
|
58
|
+
WHERE id = $1 AND organization_id = $2
|
|
59
|
+
FOR UPDATE`, [id, input.organizationId]);
|
|
60
|
+
return result.rows[0]?.status;
|
|
61
|
+
}
|
|
62
|
+
const result = await client.query('SELECT status FROM organizations WHERE id = $1 FOR UPDATE', [id]);
|
|
63
|
+
return result.rows[0]?.status;
|
|
64
|
+
}
|
|
65
|
+
/** Persist the status transition using only closed table and field choices. */
|
|
66
|
+
async function updateStatus(client, input, id, nextStatus) {
|
|
67
|
+
if (input.entityType === 'user' &&
|
|
68
|
+
input.reason &&
|
|
69
|
+
(input.action === 'suspend' || input.action === 'lock')) {
|
|
70
|
+
await client.query(`UPDATE users
|
|
71
|
+
SET status = $1, updated_at = NOW(), suspension_reason = $2
|
|
72
|
+
WHERE id = $3 AND organization_id = $4`, [nextStatus, input.reason, id, input.organizationId]);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (input.entityType === 'user') {
|
|
76
|
+
await client.query(`UPDATE users SET status = $1, updated_at = NOW()
|
|
77
|
+
WHERE id = $2 AND organization_id = $3`, [nextStatus, id, input.organizationId]);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
await client.query('UPDATE organizations SET status = $1, updated_at = NOW() WHERE id = $2', [
|
|
81
|
+
nextStatus,
|
|
82
|
+
id,
|
|
83
|
+
]);
|
|
84
|
+
}
|
|
85
|
+
/** Insert the per-item audit record through the same transaction as the mutation. */
|
|
86
|
+
async function insertAudit(client, input, id, previousStatus, nextStatus) {
|
|
87
|
+
const organizationId = input.entityType === 'organization' ? id : input.organizationId;
|
|
88
|
+
const userId = input.entityType === 'user' ? id : null;
|
|
89
|
+
await writeAuditLogInTransaction(client, {
|
|
90
|
+
organizationId,
|
|
91
|
+
...(userId === null ? {} : { userId }),
|
|
92
|
+
...(input.actorId === undefined ? {} : { actorId: input.actorId }),
|
|
93
|
+
eventType: `admin.bulk.${input.entityType}.status_changed`,
|
|
94
|
+
eventCategory: 'admin',
|
|
95
|
+
metadata: { action: input.action, previousStatus, newStatus: nextStatus },
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
/** Create one concealed missing/foreign item result. */
|
|
99
|
+
function concealedResult(id) {
|
|
100
|
+
return {
|
|
101
|
+
id,
|
|
102
|
+
success: false,
|
|
103
|
+
outcome: 'failed',
|
|
104
|
+
code: 'not_found_or_not_authorized',
|
|
105
|
+
error: 'Entity not found or not authorized',
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/** Create one closed invalid-transition result. */
|
|
109
|
+
function invalidTransitionResult(id, previousStatus) {
|
|
110
|
+
return {
|
|
111
|
+
id,
|
|
112
|
+
success: false,
|
|
113
|
+
outcome: 'failed',
|
|
114
|
+
code: 'invalid_transition',
|
|
115
|
+
error: 'Status transition not allowed',
|
|
116
|
+
previousStatus,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/** Create an explicit result for work skipped after dependency failure. */
|
|
120
|
+
function notAttemptedResult(id) {
|
|
121
|
+
return {
|
|
122
|
+
id,
|
|
123
|
+
success: false,
|
|
124
|
+
outcome: 'not_attempted',
|
|
125
|
+
code: 'not_attempted',
|
|
126
|
+
error: 'Operation not attempted',
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Execute an ordered partial-result bulk status operation.
|
|
131
|
+
*
|
|
132
|
+
* @param input - Fully validated entity, action, scope, and actor input.
|
|
133
|
+
* @returns Ordered item outcomes. A dependency stop includes one server correlation ID.
|
|
134
|
+
*/
|
|
135
|
+
export async function bulkStatusChange(input) {
|
|
136
|
+
const transition = requireValidInput(input);
|
|
137
|
+
if (!transition) {
|
|
138
|
+
return { total: 0, succeeded: 0, failed: 0, results: [] };
|
|
139
|
+
}
|
|
140
|
+
const pool = getPool();
|
|
141
|
+
const results = [];
|
|
142
|
+
let correlationId;
|
|
143
|
+
for (let index = 0; index < input.entityIds.length; index += 1) {
|
|
144
|
+
const id = input.entityIds[index];
|
|
145
|
+
let client;
|
|
146
|
+
try {
|
|
147
|
+
client = await pool.connect();
|
|
148
|
+
await client.query('BEGIN');
|
|
149
|
+
const previousStatus = await lockCurrentStatus(client, input, id);
|
|
150
|
+
if (previousStatus === undefined) {
|
|
151
|
+
await rollback(client);
|
|
152
|
+
results.push(concealedResult(id));
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (!transition.from.includes(previousStatus)) {
|
|
156
|
+
await rollback(client);
|
|
157
|
+
results.push(invalidTransitionResult(id, previousStatus));
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
await updateStatus(client, input, id, transition.to);
|
|
161
|
+
await insertAudit(client, input, id, previousStatus, transition.to);
|
|
162
|
+
await client.query('COMMIT');
|
|
163
|
+
results.push({
|
|
164
|
+
id,
|
|
165
|
+
success: true,
|
|
166
|
+
outcome: 'succeeded',
|
|
167
|
+
code: null,
|
|
168
|
+
previousStatus,
|
|
169
|
+
newStatus: transition.to,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
if (client) {
|
|
174
|
+
try {
|
|
175
|
+
await rollback(client);
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// The public result remains the same when rollback outcome is unknown.
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
correlationId = randomUUID();
|
|
182
|
+
logger.warn({ correlationId, entityType: input.entityType, action: input.action }, 'Bulk operation stopped after a dependency failure');
|
|
183
|
+
for (let pending = index; pending < input.entityIds.length; pending += 1) {
|
|
184
|
+
results.push(notAttemptedResult(input.entityIds[pending]));
|
|
185
|
+
}
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
client?.release();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const succeeded = results.filter((result) => result.outcome === 'succeeded').length;
|
|
193
|
+
return {
|
|
194
|
+
total: input.entityIds.length,
|
|
195
|
+
succeeded,
|
|
196
|
+
failed: input.entityIds.length - succeeded,
|
|
197
|
+
results,
|
|
198
|
+
...(correlationId ? { correlationId } : {}),
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=bulk-operations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bulk-operations.js","sourceRoot":"","sources":["../../src/lib/bulk-operations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor-based pagination utility.
|
|
3
|
+
*
|
|
4
|
+
* Provides opaque cursor encoding and decoding for keyset pagination.
|
|
5
|
+
* Cursors encode the sort value and entity ID of the last item in a
|
|
6
|
+
* result set, enabling efficient "next page" queries using:
|
|
7
|
+
*
|
|
8
|
+
* WHERE (sort_column, id) > ($cursor_sort, $cursor_id)
|
|
9
|
+
*
|
|
10
|
+
* Cursors are base64url-encoded JSON strings — opaque to API consumers
|
|
11
|
+
* but decodable by the server. Invalid or tampered cursors are safely
|
|
12
|
+
* rejected (returns null from decodeCursor).
|
|
13
|
+
*
|
|
14
|
+
* @module lib/cursor
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Internal cursor payload — the data encoded inside an opaque cursor string.
|
|
18
|
+
*
|
|
19
|
+
* @property s - Sort field value at the cursor position (string, number, or null for NULLs)
|
|
20
|
+
* @property i - Entity ID at the cursor position (UUID) — ensures stable ordering for ties
|
|
21
|
+
*/
|
|
22
|
+
export interface CursorPayload {
|
|
23
|
+
/** Sort field value at the cursor position */
|
|
24
|
+
s: string | number | null;
|
|
25
|
+
/** Entity ID (UUID) — tie-breaker for stable ordering */
|
|
26
|
+
i: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Options for cursor-based pagination.
|
|
30
|
+
*
|
|
31
|
+
* When `cursor` is provided, keyset pagination is used.
|
|
32
|
+
* When `page` is provided (without cursor), offset pagination is used.
|
|
33
|
+
* When neither is provided, defaults to offset pagination page 1.
|
|
34
|
+
*/
|
|
35
|
+
export interface CursorPaginationOptions {
|
|
36
|
+
/** Opaque cursor string from a previous response */
|
|
37
|
+
cursor?: string;
|
|
38
|
+
/** Maximum items per page (default 25, max 100) */
|
|
39
|
+
limit?: number;
|
|
40
|
+
/** Sort column (must be whitelisted per-entity) */
|
|
41
|
+
sortBy?: string;
|
|
42
|
+
/** Sort direction */
|
|
43
|
+
sortOrder?: 'asc' | 'desc';
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Result shape for cursor-paginated queries.
|
|
47
|
+
*
|
|
48
|
+
* Includes the data array, navigation cursors, and a hasMore flag.
|
|
49
|
+
* `nextCursor` is null when there are no more results.
|
|
50
|
+
* `previousCursor` is the cursor of the first item (for potential reverse navigation).
|
|
51
|
+
*/
|
|
52
|
+
export interface CursorPaginatedResult<T> {
|
|
53
|
+
/** The page of results */
|
|
54
|
+
data: T[];
|
|
55
|
+
/** Cursor to fetch the next page — null if no more results */
|
|
56
|
+
nextCursor: string | null;
|
|
57
|
+
/** Cursor of the first item in this page — null if the page is empty */
|
|
58
|
+
previousCursor: string | null;
|
|
59
|
+
/** Whether there are more results after this page */
|
|
60
|
+
hasMore: boolean;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Encode a cursor from the last item in a result set.
|
|
64
|
+
*
|
|
65
|
+
* Produces an opaque base64url string safe for URL query parameters.
|
|
66
|
+
* The cursor encodes the sort value and entity ID, which together
|
|
67
|
+
* define the exact position in the ordered result set.
|
|
68
|
+
*
|
|
69
|
+
* @param sortValue - The sort field value of the item (string, number, or null)
|
|
70
|
+
* @param id - The entity UUID of the item
|
|
71
|
+
* @returns Opaque cursor string
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* const cursor = encodeCursor('2026-01-15T10:00:00Z', 'abc-123');
|
|
75
|
+
* // → 'eyJzIjoiMjAyNi0wMS0xNVQxMDowMDowMFoiLCJpIjoiYWJjLTEyMyJ9'
|
|
76
|
+
*/
|
|
77
|
+
export declare function encodeCursor(sortValue: string | number | null, id: string): string;
|
|
78
|
+
/**
|
|
79
|
+
* Decode an opaque cursor string back to a CursorPayload.
|
|
80
|
+
*
|
|
81
|
+
* Returns null if the cursor is invalid — malformed base64, invalid JSON,
|
|
82
|
+
* missing fields, or wrong types. This ensures tampered or corrupted
|
|
83
|
+
* cursors are safely rejected without throwing exceptions.
|
|
84
|
+
*
|
|
85
|
+
* @param cursor - The opaque cursor string to decode
|
|
86
|
+
* @returns Decoded payload, or null if invalid
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* const payload = decodeCursor('eyJzIjoiMjAyNi0wMS0xNVQxMDowMDowMFoiLCJpIjoiYWJjLTEyMyJ9');
|
|
90
|
+
* // → { s: '2026-01-15T10:00:00Z', i: 'abc-123' }
|
|
91
|
+
*
|
|
92
|
+
* const invalid = decodeCursor('not-a-cursor');
|
|
93
|
+
* // → null
|
|
94
|
+
*/
|
|
95
|
+
export declare function decodeCursor(cursor: string): CursorPayload | null;
|
|
96
|
+
/**
|
|
97
|
+
* Build a CursorPaginatedResult from a query result set.
|
|
98
|
+
*
|
|
99
|
+
* The caller should query for `limit + 1` rows. If the extra row exists,
|
|
100
|
+
* `hasMore` is true and the extra row is stripped from the result.
|
|
101
|
+
* Cursors are generated using the provided sort value extractor function.
|
|
102
|
+
*
|
|
103
|
+
* @param rows - Raw query rows (may include the extra hasMore row)
|
|
104
|
+
* @param limit - The requested page size
|
|
105
|
+
* @param getSortValue - Function to extract the sort value from a row
|
|
106
|
+
* @param getId - Function to extract the entity ID from a row
|
|
107
|
+
* @returns CursorPaginatedResult with cursors and hasMore flag
|
|
108
|
+
*/
|
|
109
|
+
export declare function buildCursorResult<T>(rows: T[], limit: number, getSortValue: (row: T) => string | number | null, getId: (row: T) => string): CursorPaginatedResult<T>;
|
|
110
|
+
//# sourceMappingURL=cursor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/lib/cursor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,8CAA8C;IAC9C,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC1B,yDAAyD;IACzD,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;;;;GAMG;AACH,MAAM,WAAW,uBAAuB;IACtC,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACtC,0BAA0B;IAC1B,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,8DAA8D;IAC9D,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,wEAAwE;IACxE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,qDAAqD;IACrD,OAAO,EAAE,OAAO,CAAC;CAClB;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAKlF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAoCjE;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,IAAI,EAAE,CAAC,EAAE,EACT,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,GAAG,IAAI,EAChD,KAAK,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,GACxB,qBAAqB,CAAC,CAAC,CAAC,CAa1B"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor-based pagination utility.
|
|
3
|
+
*
|
|
4
|
+
* Provides opaque cursor encoding and decoding for keyset pagination.
|
|
5
|
+
* Cursors encode the sort value and entity ID of the last item in a
|
|
6
|
+
* result set, enabling efficient "next page" queries using:
|
|
7
|
+
*
|
|
8
|
+
* WHERE (sort_column, id) > ($cursor_sort, $cursor_id)
|
|
9
|
+
*
|
|
10
|
+
* Cursors are base64url-encoded JSON strings — opaque to API consumers
|
|
11
|
+
* but decodable by the server. Invalid or tampered cursors are safely
|
|
12
|
+
* rejected (returns null from decodeCursor).
|
|
13
|
+
*
|
|
14
|
+
* @module lib/cursor
|
|
15
|
+
*/
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Encoding / Decoding
|
|
18
|
+
// ============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Encode a cursor from the last item in a result set.
|
|
21
|
+
*
|
|
22
|
+
* Produces an opaque base64url string safe for URL query parameters.
|
|
23
|
+
* The cursor encodes the sort value and entity ID, which together
|
|
24
|
+
* define the exact position in the ordered result set.
|
|
25
|
+
*
|
|
26
|
+
* @param sortValue - The sort field value of the item (string, number, or null)
|
|
27
|
+
* @param id - The entity UUID of the item
|
|
28
|
+
* @returns Opaque cursor string
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* const cursor = encodeCursor('2026-01-15T10:00:00Z', 'abc-123');
|
|
32
|
+
* // → 'eyJzIjoiMjAyNi0wMS0xNVQxMDowMDowMFoiLCJpIjoiYWJjLTEyMyJ9'
|
|
33
|
+
*/
|
|
34
|
+
export function encodeCursor(sortValue, id) {
|
|
35
|
+
const payload = { s: sortValue, i: id };
|
|
36
|
+
const json = JSON.stringify(payload);
|
|
37
|
+
// Use base64url encoding (no padding) for URL safety
|
|
38
|
+
return Buffer.from(json, 'utf-8').toString('base64url');
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Decode an opaque cursor string back to a CursorPayload.
|
|
42
|
+
*
|
|
43
|
+
* Returns null if the cursor is invalid — malformed base64, invalid JSON,
|
|
44
|
+
* missing fields, or wrong types. This ensures tampered or corrupted
|
|
45
|
+
* cursors are safely rejected without throwing exceptions.
|
|
46
|
+
*
|
|
47
|
+
* @param cursor - The opaque cursor string to decode
|
|
48
|
+
* @returns Decoded payload, or null if invalid
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* const payload = decodeCursor('eyJzIjoiMjAyNi0wMS0xNVQxMDowMDowMFoiLCJpIjoiYWJjLTEyMyJ9');
|
|
52
|
+
* // → { s: '2026-01-15T10:00:00Z', i: 'abc-123' }
|
|
53
|
+
*
|
|
54
|
+
* const invalid = decodeCursor('not-a-cursor');
|
|
55
|
+
* // → null
|
|
56
|
+
*/
|
|
57
|
+
export function decodeCursor(cursor) {
|
|
58
|
+
try {
|
|
59
|
+
const json = Buffer.from(cursor, 'base64url').toString('utf-8');
|
|
60
|
+
const parsed = JSON.parse(json);
|
|
61
|
+
// Validate shape: must be an object with 's' and 'i' fields
|
|
62
|
+
if (typeof parsed !== 'object' ||
|
|
63
|
+
parsed === null ||
|
|
64
|
+
!('s' in parsed) ||
|
|
65
|
+
!('i' in parsed)) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
const obj = parsed;
|
|
69
|
+
// Validate 'i' is a non-empty string (entity ID)
|
|
70
|
+
if (typeof obj.i !== 'string' || obj.i.length === 0) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
// Validate 's' is string, number, or null (sort value)
|
|
74
|
+
const sortType = typeof obj.s;
|
|
75
|
+
if (obj.s !== null && sortType !== 'string' && sortType !== 'number') {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
s: obj.s,
|
|
80
|
+
i: obj.i,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// JSON parse error, base64 decode error, etc.
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// ============================================================================
|
|
89
|
+
// Result Builder
|
|
90
|
+
// ============================================================================
|
|
91
|
+
/**
|
|
92
|
+
* Build a CursorPaginatedResult from a query result set.
|
|
93
|
+
*
|
|
94
|
+
* The caller should query for `limit + 1` rows. If the extra row exists,
|
|
95
|
+
* `hasMore` is true and the extra row is stripped from the result.
|
|
96
|
+
* Cursors are generated using the provided sort value extractor function.
|
|
97
|
+
*
|
|
98
|
+
* @param rows - Raw query rows (may include the extra hasMore row)
|
|
99
|
+
* @param limit - The requested page size
|
|
100
|
+
* @param getSortValue - Function to extract the sort value from a row
|
|
101
|
+
* @param getId - Function to extract the entity ID from a row
|
|
102
|
+
* @returns CursorPaginatedResult with cursors and hasMore flag
|
|
103
|
+
*/
|
|
104
|
+
export function buildCursorResult(rows, limit, getSortValue, getId) {
|
|
105
|
+
const hasMore = rows.length > limit;
|
|
106
|
+
const data = hasMore ? rows.slice(0, limit) : rows;
|
|
107
|
+
const nextCursor = hasMore && data.length > 0
|
|
108
|
+
? encodeCursor(getSortValue(data[data.length - 1]), getId(data[data.length - 1]))
|
|
109
|
+
: null;
|
|
110
|
+
const previousCursor = data.length > 0
|
|
111
|
+
? encodeCursor(getSortValue(data[0]), getId(data[0]))
|
|
112
|
+
: null;
|
|
113
|
+
return { data, nextCursor, previousCursor, hasMore };
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=cursor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/lib/cursor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded administrative data export.
|
|
3
|
+
*
|
|
4
|
+
* Every query selects an explicit public field list, reads one row beyond the public limit, and
|
|
5
|
+
* writes a content-free audit record in the same repeatable-read transaction. CSV output is
|
|
6
|
+
* neutralized before quoting so spreadsheet applications cannot execute imported formulas.
|
|
7
|
+
*/
|
|
8
|
+
/** Closed serialization formats accepted by the export service. */
|
|
9
|
+
export type ExportFormat = 'json' | 'csv';
|
|
10
|
+
/** Closed entity catalog accepted by the export service. */
|
|
11
|
+
export type ExportEntityType = 'users' | 'organizations' | 'clients' | 'roles' | 'audit';
|
|
12
|
+
/** Maximum number of rows returned by one export. */
|
|
13
|
+
export declare const MAXIMUM_EXPORT_ROWS = 10000;
|
|
14
|
+
/** Input for one authorized administrative export. */
|
|
15
|
+
export interface ExportOptions {
|
|
16
|
+
/** Entity catalog to serialize. */
|
|
17
|
+
entityType: ExportEntityType;
|
|
18
|
+
/** Public output representation. */
|
|
19
|
+
format: ExportFormat;
|
|
20
|
+
/** Exact tenant scope for tenant-owned data. */
|
|
21
|
+
organizationId?: string;
|
|
22
|
+
/** Exact application relationship required for role data. */
|
|
23
|
+
applicationId?: string;
|
|
24
|
+
/** Inclusive audit-window start. */
|
|
25
|
+
startDate?: Date;
|
|
26
|
+
/** Inclusive audit-window end. */
|
|
27
|
+
endDate?: Date;
|
|
28
|
+
/** Authenticated administrator recorded without export content. */
|
|
29
|
+
actorId?: string;
|
|
30
|
+
}
|
|
31
|
+
/** Serialized export admitted after scope, bound, and audit checks. */
|
|
32
|
+
export interface ExportResult {
|
|
33
|
+
/** Complete serialized document. */
|
|
34
|
+
data: string;
|
|
35
|
+
/** Public response media type. */
|
|
36
|
+
contentType: string;
|
|
37
|
+
/** Attachment filename without user-controlled input. */
|
|
38
|
+
filename: string;
|
|
39
|
+
/** Exact number of exported rows. */
|
|
40
|
+
rowCount: number;
|
|
41
|
+
}
|
|
42
|
+
/** Stable public export failures. */
|
|
43
|
+
export type ExportFailureCode = 'export_scope_required' | 'export_invalid_range' | 'export_too_large' | 'export_failed';
|
|
44
|
+
/** Minimal export failure which never retains query or row diagnostics. */
|
|
45
|
+
export declare class ExportOperationError extends Error {
|
|
46
|
+
/** Stable public failure discriminator. */
|
|
47
|
+
readonly code: ExportFailureCode;
|
|
48
|
+
/** Recommended HTTP status. */
|
|
49
|
+
readonly status: 400 | 413 | 503;
|
|
50
|
+
/**
|
|
51
|
+
* Create a closed export failure.
|
|
52
|
+
*
|
|
53
|
+
* @param code - Stable public failure discriminator.
|
|
54
|
+
* @param status - Recommended route status.
|
|
55
|
+
*/
|
|
56
|
+
constructor(code: ExportFailureCode, status: 400 | 413 | 503);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Export one authorized entity set through a bounded repeatable-read transaction.
|
|
60
|
+
*
|
|
61
|
+
* @param options - Exact entity, representation, scope, and actor.
|
|
62
|
+
* @returns Complete serialized export and exact row count.
|
|
63
|
+
* @throws ExportOperationError when scope is incomplete, the bound is exceeded, or persistence
|
|
64
|
+
* fails.
|
|
65
|
+
*/
|
|
66
|
+
export declare function exportData(options: ExportOptions): Promise<ExportResult>;
|
|
67
|
+
//# sourceMappingURL=data-export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-export.d.ts","sourceRoot":"","sources":["../../src/lib/data-export.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,mEAAmE;AACnE,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,KAAK,CAAC;AAE1C,4DAA4D;AAC5D,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,eAAe,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAEzF,qDAAqD;AACrD,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAE1C,sDAAsD;AACtD,MAAM,WAAW,aAAa;IAC5B,mCAAmC;IACnC,UAAU,EAAE,gBAAgB,CAAC;IAC7B,oCAAoC;IACpC,MAAM,EAAE,YAAY,CAAC;IACrB,gDAAgD;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6DAA6D;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oCAAoC;IACpC,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,kCAAkC;IAClC,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,uEAAuE;AACvE,MAAM,WAAW,YAAY;IAC3B,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qCAAqC;AACrC,MAAM,MAAM,iBAAiB,GAC3B,uBAAuB,GAAG,sBAAsB,GAAG,kBAAkB,GAAG,eAAe,CAAC;AAE1F,2EAA2E;AAC3E,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,2CAA2C;IAC3C,SAAgB,IAAI,EAAE,iBAAiB,CAAC;IAExC,+BAA+B;IAC/B,SAAgB,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAExC;;;;;OAKG;IACH,YAAmB,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAKlE;CACF;AAqMD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAgD9E"}
|