@lastshotlabs/bunshot 0.0.25 → 0.0.28
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/.oclif.manifest.json +39 -0
- package/README.md +8282 -2147
- package/dist/cli/commands/init.js +690 -0
- package/dist/cli/index.js +6 -0
- package/dist/cli.js +4 -4
- package/dist/packages/bunshot-admin/src/index.d.ts +15 -0
- package/dist/packages/bunshot-admin/src/index.js +11 -0
- package/dist/packages/bunshot-admin/src/lib/resourceTypes.d.ts +8 -0
- package/dist/packages/bunshot-admin/src/lib/resourceTypes.js +33 -0
- package/dist/packages/bunshot-admin/src/lib/typedRoute.d.ts +14 -0
- package/dist/packages/bunshot-admin/src/lib/typedRoute.js +17 -0
- package/dist/packages/bunshot-admin/src/plugin.d.ts +4 -0
- package/dist/packages/bunshot-admin/src/plugin.js +46 -0
- package/dist/packages/bunshot-admin/src/providers/auth0Access.d.ts +6 -0
- package/dist/packages/bunshot-admin/src/providers/auth0Access.js +32 -0
- package/dist/packages/bunshot-admin/src/routes/admin.d.ts +10 -0
- package/dist/packages/bunshot-admin/src/routes/admin.js +923 -0
- package/dist/packages/bunshot-admin/src/routes/mail.d.ts +6 -0
- package/dist/packages/bunshot-admin/src/routes/mail.js +114 -0
- package/dist/packages/bunshot-admin/src/routes/permissions.d.ts +8 -0
- package/dist/packages/bunshot-admin/src/routes/permissions.js +315 -0
- package/dist/packages/bunshot-admin/src/types/config.d.ts +16 -0
- package/dist/packages/bunshot-admin/src/types/config.js +37 -0
- package/dist/packages/bunshot-admin/src/types/env.d.ts +14 -0
- package/dist/packages/bunshot-admin/src/types/provider.d.ts +1 -0
- package/dist/packages/bunshot-admin/src/types/provider.js +4 -0
- package/dist/packages/bunshot-auth/src/adapters/memoryAuth.d.ts +66 -0
- package/dist/packages/bunshot-auth/src/adapters/memoryAuth.js +1063 -0
- package/dist/packages/bunshot-auth/src/adapters/mongoAuth.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/adapters/mongoAuth.js +536 -0
- package/dist/packages/bunshot-auth/src/adapters/sqliteAuth.d.ts +88 -0
- package/dist/packages/bunshot-auth/src/adapters/sqliteAuth.js +1366 -0
- package/dist/packages/bunshot-auth/src/admin/bunshotAccess.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/admin/bunshotAccess.js +23 -0
- package/dist/packages/bunshot-auth/src/admin/bunshotUsers.d.ts +5 -0
- package/dist/packages/bunshot-auth/src/admin/bunshotUsers.js +131 -0
- package/dist/packages/bunshot-auth/src/bootstrap.d.ts +38 -0
- package/dist/packages/bunshot-auth/src/bootstrap.js +384 -0
- package/dist/packages/bunshot-auth/src/config/appConfig.d.ts +3 -0
- package/dist/packages/bunshot-auth/src/config/appConfig.js +4 -0
- package/dist/packages/bunshot-auth/src/config/authConfig.d.ts +478 -0
- package/dist/packages/bunshot-auth/src/config/authConfig.js +46 -0
- package/dist/packages/bunshot-auth/src/config/configLock.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/config/configLock.js +10 -0
- package/dist/packages/bunshot-auth/src/index.d.ts +25 -0
- package/dist/packages/bunshot-auth/src/index.js +23 -0
- package/dist/packages/bunshot-auth/src/infra/mongo.d.ts +15 -0
- package/dist/packages/bunshot-auth/src/infra/mongo.js +44 -0
- package/dist/packages/bunshot-auth/src/infra/queue.d.ts +14 -0
- package/dist/packages/bunshot-auth/src/infra/queue.js +27 -0
- package/dist/packages/bunshot-auth/src/infra/redis.d.ts +5 -0
- package/dist/packages/bunshot-auth/src/infra/redis.js +15 -0
- package/dist/packages/bunshot-auth/src/infra/signing.d.ts +7 -0
- package/dist/packages/bunshot-auth/src/infra/signing.js +8 -0
- package/dist/packages/bunshot-auth/src/lib/accountLockout.d.ts +34 -0
- package/dist/packages/bunshot-auth/src/lib/accountLockout.js +244 -0
- package/dist/packages/bunshot-auth/src/lib/adapterTiers.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/lib/adapterTiers.js +1 -0
- package/dist/packages/bunshot-auth/src/lib/authAdapter.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/lib/authAdapter.js +1 -0
- package/dist/packages/bunshot-auth/src/lib/authContext.d.ts +15 -0
- package/dist/packages/bunshot-auth/src/lib/authContext.js +1 -0
- package/dist/packages/bunshot-auth/src/lib/authEventBus.d.ts +4 -0
- package/dist/packages/bunshot-auth/src/lib/authEventBus.js +15 -0
- package/dist/packages/bunshot-auth/src/lib/authRateLimit.d.ts +28 -0
- package/dist/packages/bunshot-auth/src/lib/authRateLimit.js +205 -0
- package/dist/packages/bunshot-auth/src/lib/breachedPassword.d.ts +19 -0
- package/dist/packages/bunshot-auth/src/lib/breachedPassword.js +61 -0
- package/dist/packages/bunshot-auth/src/lib/cache.d.ts +12 -0
- package/dist/packages/bunshot-auth/src/lib/cache.js +120 -0
- package/dist/packages/bunshot-auth/src/lib/clientIp.d.ts +4 -0
- package/dist/{lib → packages/bunshot-auth/src/lib}/clientIp.js +14 -7
- package/dist/packages/bunshot-auth/src/lib/cookieOptions.d.ts +27 -0
- package/dist/packages/bunshot-auth/src/lib/cookieOptions.js +33 -0
- package/dist/packages/bunshot-auth/src/lib/credentialStuffing.d.ts +40 -0
- package/dist/packages/bunshot-auth/src/lib/credentialStuffing.js +221 -0
- package/dist/packages/bunshot-auth/src/lib/deletionCancelToken.d.ts +19 -0
- package/dist/packages/bunshot-auth/src/lib/deletionCancelToken.js +148 -0
- package/dist/packages/bunshot-auth/src/lib/emailTemplates.d.ts +23 -0
- package/dist/packages/bunshot-auth/src/lib/emailTemplates.js +265 -0
- package/dist/packages/bunshot-auth/src/lib/emailVerification.d.ts +30 -0
- package/dist/packages/bunshot-auth/src/lib/emailVerification.js +200 -0
- package/dist/packages/bunshot-auth/src/lib/env.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/lib/env.js +3 -0
- package/dist/packages/bunshot-auth/src/lib/fingerprint.js +36 -0
- package/dist/{lib → packages/bunshot-auth/src/lib}/groups.d.ts +15 -16
- package/dist/{lib → packages/bunshot-auth/src/lib}/groups.js +22 -34
- package/dist/packages/bunshot-auth/src/lib/jwks.d.ts +28 -0
- package/dist/packages/bunshot-auth/src/lib/jwks.js +79 -0
- package/dist/packages/bunshot-auth/src/lib/jwt.d.ts +12 -0
- package/dist/packages/bunshot-auth/src/lib/jwt.js +86 -0
- package/dist/packages/bunshot-auth/src/lib/logger.d.ts +3 -0
- package/dist/packages/bunshot-auth/src/lib/logger.js +13 -0
- package/dist/packages/bunshot-auth/src/lib/m2m.d.ts +30 -0
- package/dist/packages/bunshot-auth/src/lib/m2m.js +44 -0
- package/dist/packages/bunshot-auth/src/lib/magicLink.d.ts +13 -0
- package/dist/packages/bunshot-auth/src/lib/magicLink.js +145 -0
- package/dist/packages/bunshot-auth/src/lib/mfaChallenge.d.ts +60 -0
- package/dist/packages/bunshot-auth/src/lib/mfaChallenge.js +419 -0
- package/dist/packages/bunshot-auth/src/lib/oauth.d.ts +82 -0
- package/dist/packages/bunshot-auth/src/lib/oauth.js +177 -0
- package/dist/packages/bunshot-auth/src/lib/oauthCode.d.ts +19 -0
- package/dist/packages/bunshot-auth/src/lib/oauthCode.js +182 -0
- package/dist/packages/bunshot-auth/src/lib/oauthReauth.d.ts +19 -0
- package/dist/packages/bunshot-auth/src/lib/oauthReauth.js +255 -0
- package/dist/packages/bunshot-auth/src/lib/organization.d.ts +66 -0
- package/dist/packages/bunshot-auth/src/lib/organization.js +225 -0
- package/dist/packages/bunshot-auth/src/lib/passwordHistory.d.ts +12 -0
- package/dist/packages/bunshot-auth/src/lib/passwordHistory.js +31 -0
- package/dist/packages/bunshot-auth/src/lib/resetPassword.d.ts +20 -0
- package/dist/packages/bunshot-auth/src/lib/resetPassword.js +148 -0
- package/dist/packages/bunshot-auth/src/lib/roles.d.ts +9 -0
- package/dist/packages/bunshot-auth/src/lib/roles.js +93 -0
- package/dist/packages/bunshot-auth/src/lib/saml.d.ts +29 -0
- package/dist/packages/bunshot-auth/src/lib/saml.js +73 -0
- package/dist/packages/bunshot-auth/src/lib/samlRequestId.d.ts +13 -0
- package/dist/packages/bunshot-auth/src/lib/samlRequestId.js +129 -0
- package/dist/packages/bunshot-auth/src/lib/scim.d.ts +44 -0
- package/dist/packages/bunshot-auth/src/lib/scim.js +56 -0
- package/dist/packages/bunshot-auth/src/lib/securityEventWiring.d.ts +22 -0
- package/dist/packages/bunshot-auth/src/lib/securityEventWiring.js +65 -0
- package/dist/packages/bunshot-auth/src/lib/session.d.ts +45 -0
- package/dist/packages/bunshot-auth/src/lib/session.js +1211 -0
- package/dist/packages/bunshot-auth/src/lib/storeInfra.d.ts +26 -0
- package/dist/packages/bunshot-auth/src/lib/storeInfra.js +18 -0
- package/dist/packages/bunshot-auth/src/lib/suspension.d.ts +14 -0
- package/dist/packages/bunshot-auth/src/lib/suspension.js +20 -0
- package/dist/packages/bunshot-auth/src/lib/validateAdapter.d.ts +16 -0
- package/dist/packages/bunshot-auth/src/lib/validateAdapter.js +161 -0
- package/dist/packages/bunshot-auth/src/middleware/bearerAuth.d.ts +13 -0
- package/dist/packages/bunshot-auth/src/middleware/bearerAuth.js +58 -0
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/csrf.d.ts +5 -4
- package/dist/packages/bunshot-auth/src/middleware/csrf.js +138 -0
- package/dist/packages/bunshot-auth/src/middleware/identify.d.ts +4 -0
- package/dist/packages/bunshot-auth/src/middleware/identify.js +124 -0
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireMfaSetup.d.ts +2 -2
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireMfaSetup.js +10 -7
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireRole.d.ts +2 -2
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireRole.js +20 -16
- package/dist/packages/bunshot-auth/src/middleware/requireScope.d.ts +10 -0
- package/dist/packages/bunshot-auth/src/middleware/requireScope.js +25 -0
- package/dist/packages/bunshot-auth/src/middleware/requireStepUp.d.ts +18 -0
- package/dist/packages/bunshot-auth/src/middleware/requireStepUp.js +30 -0
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireVerifiedEmail.d.ts +2 -2
- package/dist/{middleware → packages/bunshot-auth/src/middleware}/requireVerifiedEmail.js +7 -6
- package/dist/packages/bunshot-auth/src/middleware/scimAuth.d.ts +8 -0
- package/dist/packages/bunshot-auth/src/middleware/scimAuth.js +29 -0
- package/dist/packages/bunshot-auth/src/middleware/userAuth.d.ts +3 -0
- package/dist/packages/bunshot-auth/src/middleware/userAuth.js +6 -0
- package/dist/{models → packages/bunshot-auth/src/models}/AuthUser.d.ts +19 -8
- package/dist/packages/bunshot-auth/src/models/AuthUser.js +53 -0
- package/dist/packages/bunshot-auth/src/models/Group.d.ts +19 -0
- package/dist/packages/bunshot-auth/src/models/Group.js +22 -0
- package/dist/{models → packages/bunshot-auth/src/models}/GroupMembership.d.ts +6 -8
- package/dist/packages/bunshot-auth/src/models/GroupMembership.js +19 -0
- package/dist/packages/bunshot-auth/src/models/M2MClient.d.ts +18 -0
- package/dist/packages/bunshot-auth/src/models/M2MClient.js +18 -0
- package/dist/packages/bunshot-auth/src/models/TenantRole.d.ts +13 -0
- package/dist/packages/bunshot-auth/src/models/TenantRole.js +17 -0
- package/dist/packages/bunshot-auth/src/plugin.d.ts +4 -0
- package/dist/packages/bunshot-auth/src/plugin.js +274 -0
- package/dist/packages/bunshot-auth/src/routes/auth.d.ts +15 -0
- package/dist/packages/bunshot-auth/src/routes/auth.js +1624 -0
- package/dist/packages/bunshot-auth/src/routes/groups.d.ts +4 -0
- package/dist/packages/bunshot-auth/src/routes/groups.js +481 -0
- package/dist/packages/bunshot-auth/src/routes/m2m.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/routes/m2m.js +145 -0
- package/dist/packages/bunshot-auth/src/routes/mfa.d.ts +6 -0
- package/dist/packages/bunshot-auth/src/routes/mfa.js +991 -0
- package/dist/packages/bunshot-auth/src/routes/oauth.d.ts +3 -0
- package/dist/packages/bunshot-auth/src/routes/oauth.js +1727 -0
- package/dist/packages/bunshot-auth/src/routes/oidc.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/routes/oidc.js +84 -0
- package/dist/packages/bunshot-auth/src/routes/organizations.d.ts +3 -0
- package/dist/packages/bunshot-auth/src/routes/organizations.js +741 -0
- package/dist/packages/bunshot-auth/src/routes/passkey.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/routes/passkey.js +199 -0
- package/dist/packages/bunshot-auth/src/routes/saml.d.ts +2 -0
- package/dist/packages/bunshot-auth/src/routes/saml.js +226 -0
- package/dist/packages/bunshot-auth/src/routes/scim.d.ts +3 -0
- package/dist/packages/bunshot-auth/src/routes/scim.js +588 -0
- package/dist/packages/bunshot-auth/src/runtime.d.ts +52 -0
- package/dist/packages/bunshot-auth/src/runtime.js +11 -0
- package/dist/{schemas → packages/bunshot-auth/src/schemas}/auth.d.ts +4 -5
- package/dist/packages/bunshot-auth/src/schemas/auth.js +24 -0
- package/dist/packages/bunshot-auth/src/schemas/error.d.ts +10 -0
- package/dist/packages/bunshot-auth/src/schemas/error.js +10 -0
- package/dist/packages/bunshot-auth/src/schemas/success.d.ts +10 -0
- package/dist/packages/bunshot-auth/src/schemas/success.js +10 -0
- package/dist/packages/bunshot-auth/src/services/auth.d.ts +39 -0
- package/dist/packages/bunshot-auth/src/services/auth.js +378 -0
- package/dist/{services → packages/bunshot-auth/src/services}/mfa.d.ts +41 -17
- package/dist/{services → packages/bunshot-auth/src/services}/mfa.js +259 -183
- package/dist/packages/bunshot-auth/src/testing.d.ts +31 -0
- package/dist/packages/bunshot-auth/src/testing.js +23 -0
- package/dist/packages/bunshot-auth/src/types/adapter.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/types/adapter.js +1 -0
- package/dist/packages/bunshot-auth/src/types/config.d.ts +152 -0
- package/dist/packages/bunshot-auth/src/types/config.js +179 -0
- package/dist/{routes → packages/bunshot-auth/src/types}/groups.d.ts +2 -3
- package/dist/packages/bunshot-auth/src/types/groups.js +1 -0
- package/dist/packages/bunshot-auth/src/types/oauthCode.d.ts +6 -0
- package/dist/packages/bunshot-auth/src/types/oauthCode.js +1 -0
- package/dist/packages/bunshot-auth/src/types/oauthReauth.d.ts +13 -0
- package/dist/packages/bunshot-auth/src/types/oauthReauth.js +1 -0
- package/dist/packages/bunshot-auth/src/types/redis.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/types/redis.js +1 -0
- package/dist/packages/bunshot-auth/src/types/saml.d.ts +10 -0
- package/dist/packages/bunshot-auth/src/types/saml.js +1 -0
- package/dist/packages/bunshot-auth/src/types/session.d.ts +18 -0
- package/dist/packages/bunshot-auth/src/types/session.js +1 -0
- package/dist/packages/bunshot-auth/src/types/store.d.ts +1 -0
- package/dist/packages/bunshot-auth/src/types/store.js +1 -0
- package/dist/packages/bunshot-core/src/adminProvider.d.ts +95 -0
- package/dist/packages/bunshot-core/src/adminProvider.js +1 -0
- package/dist/packages/bunshot-core/src/auditLog.d.ts +34 -0
- package/dist/packages/bunshot-core/src/auditLog.js +1 -0
- package/dist/packages/bunshot-core/src/auth-adapter.d.ts +227 -0
- package/dist/packages/bunshot-core/src/auth-adapter.js +4 -0
- package/dist/packages/bunshot-core/src/authVariables.d.ts +14 -0
- package/dist/packages/bunshot-core/src/authVariables.js +4 -0
- package/dist/packages/bunshot-core/src/cache.d.ts +12 -0
- package/dist/packages/bunshot-core/src/cache.js +21 -0
- package/dist/packages/bunshot-core/src/captcha.d.ts +16 -0
- package/dist/packages/bunshot-core/src/captcha.js +1 -0
- package/dist/packages/bunshot-core/src/clearRegistry.d.ts +6 -0
- package/dist/packages/bunshot-core/src/clearRegistry.js +17 -0
- package/dist/packages/bunshot-core/src/clientIp.d.ts +3 -0
- package/dist/packages/bunshot-core/src/clientIp.js +45 -0
- package/dist/packages/bunshot-core/src/configLock.d.ts +4 -0
- package/dist/packages/bunshot-core/src/configLock.js +7 -0
- package/dist/packages/bunshot-core/src/configValidation.d.ts +22 -0
- package/dist/packages/bunshot-core/src/configValidation.js +39 -0
- package/dist/packages/bunshot-core/src/constants.js +10 -0
- package/dist/packages/bunshot-core/src/context/bunshotContext.d.ts +232 -0
- package/dist/packages/bunshot-core/src/context/bunshotContext.js +1 -0
- package/dist/packages/bunshot-core/src/context/contextAccess.d.ts +3 -0
- package/dist/packages/bunshot-core/src/context/contextAccess.js +16 -0
- package/dist/packages/bunshot-core/src/context/contextStore.d.ts +16 -0
- package/dist/packages/bunshot-core/src/context/contextStore.js +31 -0
- package/dist/packages/bunshot-core/src/context/frameworkConfig.d.ts +38 -0
- package/dist/packages/bunshot-core/src/context/frameworkConfig.js +1 -0
- package/dist/packages/bunshot-core/src/context/index.d.ts +4 -0
- package/dist/packages/bunshot-core/src/context/index.js +2 -0
- package/dist/packages/bunshot-core/src/context.d.ts +40 -0
- package/dist/packages/bunshot-core/src/context.js +35 -0
- package/dist/packages/bunshot-core/src/coreContracts.d.ts +47 -0
- package/dist/packages/bunshot-core/src/coreContracts.js +1 -0
- package/dist/packages/bunshot-core/src/coreRegistrar.d.ts +6 -0
- package/dist/packages/bunshot-core/src/coreRegistrar.js +42 -0
- package/dist/{lib → packages/bunshot-core/src}/createRoute.d.ts +4 -30
- package/dist/{lib → packages/bunshot-core/src}/createRoute.js +39 -88
- package/dist/packages/bunshot-core/src/cronRegistry.d.ts +11 -0
- package/dist/packages/bunshot-core/src/cronRegistry.js +1 -0
- package/dist/packages/bunshot-core/src/crypto.d.ts +43 -0
- package/dist/packages/bunshot-core/src/crypto.js +74 -0
- package/dist/packages/bunshot-core/src/csrf.d.ts +8 -0
- package/dist/packages/bunshot-core/src/csrf.js +1 -0
- package/dist/packages/bunshot-core/src/defaults/defaultFingerprint.d.ts +7 -0
- package/dist/packages/bunshot-core/src/defaults/defaultFingerprint.js +19 -0
- package/dist/packages/bunshot-core/src/defaults/memoryCacheAdapter.d.ts +6 -0
- package/dist/packages/bunshot-core/src/defaults/memoryCacheAdapter.js +40 -0
- package/dist/packages/bunshot-core/src/defaults/memoryRateLimit.d.ts +6 -0
- package/dist/packages/bunshot-core/src/defaults/memoryRateLimit.js +24 -0
- package/dist/packages/bunshot-core/src/emailTemplates.d.ts +5 -0
- package/dist/packages/bunshot-core/src/emailTemplates.js +10 -0
- package/dist/packages/bunshot-core/src/errors.d.ts +13 -0
- package/dist/packages/bunshot-core/src/errors.js +22 -0
- package/dist/packages/bunshot-core/src/eventBus.d.ts +270 -0
- package/dist/packages/bunshot-core/src/eventBus.js +143 -0
- package/dist/packages/bunshot-core/src/idempotency.d.ts +18 -0
- package/dist/packages/bunshot-core/src/idempotency.js +1 -0
- package/dist/packages/bunshot-core/src/index.d.ts +60 -0
- package/dist/packages/bunshot-core/src/index.js +34 -0
- package/dist/packages/bunshot-core/src/mail.d.ts +14 -0
- package/dist/packages/bunshot-core/src/mail.js +8 -0
- package/dist/packages/bunshot-core/src/memoryEviction.d.ts +24 -0
- package/dist/packages/bunshot-core/src/memoryEviction.js +52 -0
- package/dist/packages/bunshot-core/src/pagination.d.ts +45 -0
- package/dist/packages/bunshot-core/src/pagination.js +61 -0
- package/dist/packages/bunshot-core/src/permissions.d.ts +64 -0
- package/dist/packages/bunshot-core/src/permissions.js +27 -0
- package/dist/packages/bunshot-core/src/plugin.d.ts +44 -0
- package/dist/packages/bunshot-core/src/plugin.js +1 -0
- package/dist/packages/bunshot-core/src/rateLimit.d.ts +5 -0
- package/dist/packages/bunshot-core/src/rateLimit.js +18 -0
- package/dist/packages/bunshot-core/src/redis.d.ts +21 -0
- package/dist/packages/bunshot-core/src/redis.js +1 -0
- package/dist/packages/bunshot-core/src/routeAuth.d.ts +5 -0
- package/dist/packages/bunshot-core/src/routeAuth.js +11 -0
- package/dist/packages/bunshot-core/src/routeOverrides.d.ts +24 -0
- package/dist/packages/bunshot-core/src/routeOverrides.js +25 -0
- package/dist/packages/bunshot-core/src/routerAdapter.d.ts +6 -0
- package/dist/packages/bunshot-core/src/routerAdapter.js +56 -0
- package/dist/packages/bunshot-core/src/secrets.d.ts +48 -0
- package/dist/packages/bunshot-core/src/secrets.js +8 -0
- package/dist/packages/bunshot-core/src/signing.d.ts +41 -0
- package/dist/packages/bunshot-core/src/signing.js +1 -0
- package/dist/packages/bunshot-core/src/sse.d.ts +36 -0
- package/dist/packages/bunshot-core/src/sse.js +1 -0
- package/dist/packages/bunshot-core/src/storageAdapter.js +1 -0
- package/dist/packages/bunshot-core/src/storeInfra.d.ts +44 -0
- package/dist/packages/bunshot-core/src/storeInfra.js +18 -0
- package/dist/packages/bunshot-core/src/storeType.d.ts +7 -0
- package/dist/packages/bunshot-core/src/storeType.js +1 -0
- package/dist/packages/bunshot-core/src/testing.d.ts +1 -0
- package/dist/packages/bunshot-core/src/testing.js +1 -0
- package/dist/packages/bunshot-core/src/uploadRegistry.d.ts +23 -0
- package/dist/packages/bunshot-core/src/uploadRegistry.js +4 -0
- package/dist/packages/bunshot-core/src/userResolver.d.ts +5 -0
- package/dist/packages/bunshot-core/src/userResolver.js +14 -0
- package/dist/packages/bunshot-core/src/wsMessages.d.ts +42 -0
- package/dist/packages/bunshot-core/src/wsMessages.js +4 -0
- package/dist/packages/bunshot-permissions/src/adapters/memory.d.ts +7 -0
- package/dist/packages/bunshot-permissions/src/adapters/memory.js +73 -0
- package/dist/packages/bunshot-permissions/src/index.d.ts +10 -0
- package/dist/packages/bunshot-permissions/src/index.js +5 -0
- package/dist/packages/bunshot-permissions/src/lib/bootstrap.d.ts +7 -0
- package/dist/packages/bunshot-permissions/src/lib/bootstrap.js +12 -0
- package/dist/packages/bunshot-permissions/src/lib/evaluator.d.ts +10 -0
- package/dist/packages/bunshot-permissions/src/lib/evaluator.js +165 -0
- package/dist/packages/bunshot-permissions/src/lib/registry.d.ts +2 -0
- package/dist/packages/bunshot-permissions/src/lib/registry.js +31 -0
- package/dist/packages/bunshot-permissions/src/lib/validation.d.ts +1 -0
- package/dist/packages/bunshot-permissions/src/lib/validation.js +1 -0
- package/dist/packages/bunshot-permissions/src/types/adapter.d.ts +1 -0
- package/dist/packages/bunshot-permissions/src/types/adapter.js +1 -0
- package/dist/packages/bunshot-permissions/src/types/evaluator.d.ts +1 -0
- package/dist/packages/bunshot-permissions/src/types/evaluator.js +1 -0
- package/dist/packages/bunshot-permissions/src/types/models.d.ts +1 -0
- package/dist/packages/bunshot-permissions/src/types/models.js +1 -0
- package/dist/packages/bunshot-permissions/src/types/registry.d.ts +1 -0
- package/dist/packages/bunshot-permissions/src/types/registry.js +1 -0
- package/dist/packages/bunshot-postgres/src/adapter.d.ts +6 -0
- package/dist/packages/bunshot-postgres/src/adapter.js +794 -0
- package/dist/packages/bunshot-postgres/src/connection.d.ts +15 -0
- package/dist/packages/bunshot-postgres/src/connection.js +16 -0
- package/dist/packages/bunshot-postgres/src/index.d.ts +4 -0
- package/dist/packages/bunshot-postgres/src/index.js +2 -0
- package/dist/packages/bunshot-postgres/src/schema.d.ts +997 -0
- package/dist/packages/bunshot-postgres/src/schema.js +105 -0
- package/dist/src/app.d.ts +230 -0
- package/dist/src/app.js +182 -0
- package/dist/src/cli/commands/init.d.ts +10 -0
- package/dist/src/cli/commands/init.js +709 -0
- package/dist/src/cli/index.d.ts +1 -0
- package/dist/src/cli/index.js +3 -0
- package/dist/src/entrypoints/mongo.d.ts +6 -0
- package/dist/src/entrypoints/mongo.js +4 -0
- package/dist/src/entrypoints/queue.d.ts +2 -0
- package/dist/src/entrypoints/queue.js +1 -0
- package/dist/src/entrypoints/redis.d.ts +1 -0
- package/dist/src/entrypoints/redis.js +1 -0
- package/dist/{adapters → src/framework/adapters}/localStorage.d.ts +1 -1
- package/dist/{adapters → src/framework/adapters}/localStorage.js +23 -8
- package/dist/src/framework/adapters/memoryStorage.d.ts +2 -0
- package/dist/src/framework/adapters/memoryStorage.js +45 -0
- package/dist/{adapters → src/framework/adapters}/s3Storage.d.ts +1 -1
- package/dist/{adapters → src/framework/adapters}/s3Storage.js +12 -12
- package/dist/src/framework/admin/bunshotAccess.d.ts +2 -0
- package/dist/src/framework/admin/bunshotAccess.js +23 -0
- package/dist/src/framework/admin/bunshotUsers.d.ts +2 -0
- package/dist/src/framework/admin/bunshotUsers.js +103 -0
- package/dist/src/framework/admin/index.d.ts +7 -0
- package/dist/src/framework/admin/index.js +21 -0
- package/dist/src/framework/boundaryAdapters/cacheFactories.d.ts +13 -0
- package/dist/src/framework/boundaryAdapters/cacheFactories.js +86 -0
- package/dist/src/framework/boundaryAdapters/index.d.ts +2 -0
- package/dist/src/framework/boundaryAdapters/index.js +1 -0
- package/dist/src/framework/boundaryAdapters.d.ts +17 -0
- package/dist/src/framework/boundaryAdapters.js +62 -0
- package/dist/src/framework/buildContext.d.ts +33 -0
- package/dist/src/framework/buildContext.js +119 -0
- package/dist/src/framework/config/schema.d.ts +447 -0
- package/dist/src/framework/config/schema.js +528 -0
- package/dist/src/framework/createInfrastructure.d.ts +76 -0
- package/dist/src/framework/createInfrastructure.js +221 -0
- package/dist/src/framework/lib/auditLog.d.ts +23 -0
- package/dist/src/framework/lib/auditLog.js +416 -0
- package/dist/src/framework/lib/captcha.d.ts +11 -0
- package/dist/src/framework/lib/captcha.js +40 -0
- package/dist/{lib → src/framework/lib}/createDtoMapper.js +4 -4
- package/dist/src/framework/lib/createRoute.d.ts +1 -0
- package/dist/src/framework/lib/createRoute.js +2 -0
- package/dist/{lib → src/framework/lib}/idempotency.d.ts +2 -6
- package/dist/src/framework/lib/idempotency.js +74 -0
- package/dist/src/framework/lib/logger.d.ts +3 -0
- package/dist/src/framework/lib/logger.js +14 -0
- package/dist/src/framework/lib/metrics.d.ts +34 -0
- package/dist/{lib → src/framework/lib}/metrics.js +49 -57
- package/dist/src/framework/lib/pagination.d.ts +42 -0
- package/dist/src/framework/lib/pagination.js +51 -0
- package/dist/src/framework/lib/redisTransport.d.ts +38 -0
- package/dist/src/framework/lib/redisTransport.js +107 -0
- package/dist/src/framework/lib/resolveUserId.d.ts +2 -0
- package/dist/src/framework/lib/resolveUserId.js +5 -0
- package/dist/src/framework/lib/sseCollision.d.ts +6 -0
- package/dist/src/framework/lib/sseCollision.js +26 -0
- package/dist/src/framework/lib/storageAdapter.d.ts +1 -0
- package/dist/src/framework/lib/storageAdapter.js +1 -0
- package/dist/{lib → src/framework/lib}/stripUnreferencedSchemas.js +4 -4
- package/dist/src/framework/lib/tenant.d.ts +21 -0
- package/dist/src/framework/lib/tenant.js +70 -0
- package/dist/{lib → src/framework/lib}/upload.d.ts +14 -9
- package/dist/src/framework/lib/upload.js +132 -0
- package/dist/src/framework/lib/uploadRegistry.d.ts +23 -0
- package/dist/src/framework/lib/uploadRegistry.js +34 -0
- package/dist/{lib → src/framework/lib}/validate.d.ts +1 -1
- package/dist/{lib → src/framework/lib}/validate.js +2 -2
- package/dist/src/framework/lib/ws.d.ts +19 -0
- package/dist/src/framework/lib/ws.js +130 -0
- package/dist/src/framework/lib/wsHeartbeat.d.ts +12 -0
- package/dist/src/framework/lib/wsHeartbeat.js +53 -0
- package/dist/src/framework/lib/wsMessages.d.ts +25 -0
- package/dist/src/framework/lib/wsMessages.js +45 -0
- package/dist/src/framework/lib/wsNamespace.d.ts +17 -0
- package/dist/src/framework/lib/wsNamespace.js +19 -0
- package/dist/src/framework/lib/wsPresence.d.ts +17 -0
- package/dist/src/framework/lib/wsPresence.js +84 -0
- package/dist/src/framework/lib/wsTransport.d.ts +38 -0
- package/dist/src/framework/lib/wsTransport.js +9 -0
- package/dist/{lib → src/framework/lib}/zodToMongoose.d.ts +1 -1
- package/dist/{lib → src/framework/lib}/zodToMongoose.js +11 -11
- package/dist/{middleware → src/framework/middleware}/auditLog.d.ts +4 -3
- package/dist/src/framework/middleware/auditLog.js +42 -0
- package/dist/{middleware → src/framework/middleware}/botProtection.d.ts +2 -2
- package/dist/{middleware → src/framework/middleware}/botProtection.js +8 -9
- package/dist/src/framework/middleware/cacheResponse.d.ts +35 -0
- package/dist/src/framework/middleware/cacheResponse.js +126 -0
- package/dist/src/framework/middleware/captcha.d.ts +9 -0
- package/dist/src/framework/middleware/captcha.js +37 -0
- package/dist/{middleware → src/framework/middleware}/errorHandler.d.ts +1 -1
- package/dist/src/framework/middleware/errorHandler.js +16 -0
- package/dist/src/framework/middleware/index.js +1 -0
- package/dist/{middleware → src/framework/middleware}/logger.d.ts +1 -1
- package/dist/src/framework/middleware/metrics.d.ts +12 -0
- package/dist/src/framework/middleware/metrics.js +26 -0
- package/dist/{middleware → src/framework/middleware}/rateLimit.d.ts +2 -2
- package/dist/src/framework/middleware/rateLimit.js +22 -0
- package/dist/src/framework/middleware/requestId.d.ts +3 -0
- package/dist/{middleware → src/framework/middleware}/requestId.js +2 -2
- package/dist/{middleware → src/framework/middleware}/requestLogger.d.ts +3 -3
- package/dist/{middleware → src/framework/middleware}/requestLogger.js +17 -12
- package/dist/{middleware → src/framework/middleware}/requestSigning.d.ts +2 -2
- package/dist/{middleware → src/framework/middleware}/requestSigning.js +18 -19
- package/dist/src/framework/middleware/tenant.d.ts +14 -0
- package/dist/{middleware → src/framework/middleware}/tenant.js +31 -27
- package/dist/src/framework/middleware/upload.d.ts +5 -0
- package/dist/{middleware → src/framework/middleware}/upload.js +4 -4
- package/dist/{middleware → src/framework/middleware}/webhookAuth.d.ts +3 -3
- package/dist/{middleware → src/framework/middleware}/webhookAuth.js +11 -11
- package/dist/src/framework/models/AuditLog.d.ts +21 -0
- package/dist/src/framework/models/AuditLog.js +31 -0
- package/dist/src/framework/mountMiddleware.d.ts +91 -0
- package/dist/src/framework/mountMiddleware.js +128 -0
- package/dist/src/framework/mountOptionalEndpoints.d.ts +103 -0
- package/dist/src/framework/mountOptionalEndpoints.js +47 -0
- package/dist/src/framework/mountRoutes.d.ts +21 -0
- package/dist/src/framework/mountRoutes.js +144 -0
- package/dist/src/framework/persistence/cronRegistry.d.ts +28 -0
- package/dist/src/framework/persistence/cronRegistry.js +139 -0
- package/dist/src/framework/persistence/idempotency.d.ts +26 -0
- package/dist/src/framework/persistence/idempotency.js +178 -0
- package/dist/src/framework/persistence/index.d.ts +6 -0
- package/dist/src/framework/persistence/index.js +8 -0
- package/dist/src/framework/persistence/storeInfra.d.ts +9 -0
- package/dist/src/framework/persistence/storeInfra.js +1 -0
- package/dist/src/framework/persistence/uploadRegistry.d.ts +35 -0
- package/dist/src/framework/persistence/uploadRegistry.js +235 -0
- package/dist/src/framework/persistence/wsMessages.d.ts +22 -0
- package/dist/src/framework/persistence/wsMessages.js +296 -0
- package/dist/src/framework/preloadSchemas.d.ts +24 -0
- package/dist/src/framework/preloadSchemas.js +42 -0
- package/dist/src/framework/registerBoundaryAdapters.d.ts +23 -0
- package/dist/src/framework/registerBoundaryAdapters.js +46 -0
- package/dist/src/framework/routes/admin.d.ts +9 -0
- package/dist/src/framework/routes/admin.js +361 -0
- package/dist/src/framework/routes/health.d.ts +1 -0
- package/dist/src/framework/routes/health.js +21 -0
- package/dist/src/framework/routes/home.d.ts +1 -0
- package/dist/src/framework/routes/home.js +18 -0
- package/dist/src/framework/routes/jobs.d.ts +3 -0
- package/dist/src/framework/routes/jobs.js +315 -0
- package/dist/src/framework/routes/metrics.d.ts +10 -0
- package/dist/src/framework/routes/metrics.js +57 -0
- package/dist/src/framework/routes/uploads.d.ts +14 -0
- package/dist/src/framework/routes/uploads.js +262 -0
- package/dist/src/framework/runPluginLifecycle.d.ts +27 -0
- package/dist/src/framework/runPluginLifecycle.js +121 -0
- package/dist/src/framework/secrets/frameworkSecretSchema.d.ts +58 -0
- package/dist/src/framework/secrets/frameworkSecretSchema.js +20 -0
- package/dist/src/framework/secrets/index.d.ts +9 -0
- package/dist/src/framework/secrets/index.js +7 -0
- package/dist/src/framework/secrets/providers/envProvider.d.ts +15 -0
- package/dist/src/framework/secrets/providers/envProvider.js +18 -0
- package/dist/src/framework/secrets/providers/fileProvider.d.ts +8 -0
- package/dist/src/framework/secrets/providers/fileProvider.js +82 -0
- package/dist/src/framework/secrets/providers/ssmProvider.d.ts +20 -0
- package/dist/src/framework/secrets/providers/ssmProvider.js +127 -0
- package/dist/src/framework/secrets/resolveSecretBundle.d.ts +53 -0
- package/dist/src/framework/secrets/resolveSecretBundle.js +84 -0
- package/dist/src/framework/secrets/resolveSecrets.d.ts +18 -0
- package/dist/src/framework/secrets/resolveSecrets.js +34 -0
- package/dist/src/framework/sse/index.d.ts +21 -0
- package/dist/src/framework/sse/index.js +109 -0
- package/dist/src/framework/ws/index.d.ts +11 -0
- package/dist/src/framework/ws/index.js +8 -0
- package/dist/src/index.d.ts +87 -0
- package/dist/src/index.js +58 -0
- package/dist/src/lib/appConfig.d.ts +7 -0
- package/dist/src/lib/appConfig.js +27 -0
- package/dist/src/lib/appMeta.d.ts +7 -0
- package/dist/src/lib/appMeta.js +3 -0
- package/dist/src/lib/authConfig.d.ts +532 -0
- package/dist/src/lib/authConfig.js +179 -0
- package/dist/{lib → src/lib}/context.d.ts +6 -7
- package/dist/{lib → src/lib}/context.js +5 -5
- package/dist/src/lib/logger.d.ts +1 -0
- package/dist/src/lib/logger.js +1 -0
- package/dist/src/lib/mongo.d.ts +58 -0
- package/dist/src/lib/mongo.js +96 -0
- package/dist/src/lib/queue.d.ts +72 -0
- package/dist/src/lib/queue.js +152 -0
- package/dist/src/lib/redis.d.ts +28 -0
- package/dist/src/lib/redis.js +72 -0
- package/dist/{lib → src/lib}/signing.d.ts +2 -2
- package/dist/src/lib/signing.js +210 -0
- package/dist/src/lib/signingConfig.d.ts +40 -0
- package/dist/src/lib/signingConfig.js +28 -0
- package/dist/src/server.d.ts +146 -0
- package/dist/src/server.js +469 -0
- package/dist/src/shared/lib/HttpError.d.ts +1 -0
- package/dist/src/shared/lib/HttpError.js +2 -0
- package/dist/src/shared/lib/constants.d.ts +10 -0
- package/dist/src/shared/lib/crypto.d.ts +43 -0
- package/dist/src/shared/lib/crypto.js +74 -0
- package/dist/src/shared/lib/signing.d.ts +52 -0
- package/dist/{lib → src/shared/lib}/signing.js +40 -10
- package/dist/src/testing.d.ts +34 -0
- package/dist/src/testing.js +93 -0
- package/package.json +62 -25
- package/dist/adapters/memoryAuth.d.ts +0 -46
- package/dist/adapters/memoryAuth.js +0 -634
- package/dist/adapters/memoryStorage.d.ts +0 -3
- package/dist/adapters/memoryStorage.js +0 -44
- package/dist/adapters/mongoAuth.d.ts +0 -2
- package/dist/adapters/mongoAuth.js +0 -307
- package/dist/adapters/sqliteAuth.d.ts +0 -49
- package/dist/adapters/sqliteAuth.js +0 -707
- package/dist/app.d.ts +0 -456
- package/dist/app.js +0 -548
- package/dist/entrypoints/mongo.d.ts +0 -5
- package/dist/entrypoints/mongo.js +0 -4
- package/dist/entrypoints/queue.d.ts +0 -2
- package/dist/entrypoints/queue.js +0 -1
- package/dist/entrypoints/redis.d.ts +0 -1
- package/dist/entrypoints/redis.js +0 -1
- package/dist/index.d.ts +0 -98
- package/dist/index.js +0 -77
- package/dist/lib/HttpError.d.ts +0 -9
- package/dist/lib/HttpError.js +0 -14
- package/dist/lib/appConfig.d.ts +0 -162
- package/dist/lib/appConfig.js +0 -83
- package/dist/lib/auditLog.d.ts +0 -52
- package/dist/lib/auditLog.js +0 -201
- package/dist/lib/authAdapter.d.ts +0 -176
- package/dist/lib/authAdapter.js +0 -7
- package/dist/lib/authRateLimit.d.ts +0 -13
- package/dist/lib/authRateLimit.js +0 -81
- package/dist/lib/clientIp.d.ts +0 -14
- package/dist/lib/crypto.d.ts +0 -11
- package/dist/lib/crypto.js +0 -22
- package/dist/lib/deletionCancelToken.d.ts +0 -12
- package/dist/lib/deletionCancelToken.js +0 -88
- package/dist/lib/emailVerification.d.ts +0 -13
- package/dist/lib/emailVerification.js +0 -86
- package/dist/lib/fingerprint.js +0 -36
- package/dist/lib/idempotency.js +0 -182
- package/dist/lib/jwt.d.ts +0 -2
- package/dist/lib/jwt.js +0 -24
- package/dist/lib/logger.d.ts +0 -1
- package/dist/lib/logger.js +0 -7
- package/dist/lib/metrics.d.ts +0 -14
- package/dist/lib/mfaChallenge.d.ts +0 -42
- package/dist/lib/mfaChallenge.js +0 -293
- package/dist/lib/mongo.d.ts +0 -39
- package/dist/lib/mongo.js +0 -124
- package/dist/lib/oauth.d.ts +0 -40
- package/dist/lib/oauth.js +0 -101
- package/dist/lib/oauthCode.d.ts +0 -15
- package/dist/lib/oauthCode.js +0 -90
- package/dist/lib/pagination.d.ts +0 -119
- package/dist/lib/pagination.js +0 -166
- package/dist/lib/queue.d.ts +0 -37
- package/dist/lib/queue.js +0 -117
- package/dist/lib/redis.d.ts +0 -9
- package/dist/lib/redis.js +0 -61
- package/dist/lib/resetPassword.d.ts +0 -12
- package/dist/lib/resetPassword.js +0 -91
- package/dist/lib/roles.d.ts +0 -7
- package/dist/lib/roles.js +0 -49
- package/dist/lib/session.d.ts +0 -39
- package/dist/lib/session.js +0 -535
- package/dist/lib/tenant.d.ts +0 -15
- package/dist/lib/tenant.js +0 -65
- package/dist/lib/upload.js +0 -87
- package/dist/lib/ws.d.ts +0 -22
- package/dist/lib/ws.js +0 -89
- package/dist/lib/wsHeartbeat.d.ts +0 -12
- package/dist/lib/wsHeartbeat.js +0 -57
- package/dist/lib/wsMessages.d.ts +0 -40
- package/dist/lib/wsMessages.js +0 -330
- package/dist/lib/wsPresence.d.ts +0 -25
- package/dist/lib/wsPresence.js +0 -99
- package/dist/middleware/auditLog.js +0 -39
- package/dist/middleware/bearerAuth.d.ts +0 -2
- package/dist/middleware/bearerAuth.js +0 -11
- package/dist/middleware/cacheResponse.d.ts +0 -15
- package/dist/middleware/cacheResponse.js +0 -178
- package/dist/middleware/csrf.js +0 -125
- package/dist/middleware/errorHandler.js +0 -13
- package/dist/middleware/identify.d.ts +0 -3
- package/dist/middleware/identify.js +0 -95
- package/dist/middleware/index.js +0 -1
- package/dist/middleware/metrics.d.ts +0 -9
- package/dist/middleware/metrics.js +0 -26
- package/dist/middleware/rateLimit.js +0 -22
- package/dist/middleware/requestId.d.ts +0 -3
- package/dist/middleware/tenant.d.ts +0 -5
- package/dist/middleware/upload.d.ts +0 -5
- package/dist/middleware/userAuth.d.ts +0 -3
- package/dist/middleware/userAuth.js +0 -6
- package/dist/models/AuditLog.d.ts +0 -30
- package/dist/models/AuditLog.js +0 -39
- package/dist/models/AuthUser.js +0 -48
- package/dist/models/Group.d.ts +0 -21
- package/dist/models/Group.js +0 -28
- package/dist/models/GroupMembership.js +0 -25
- package/dist/models/TenantRole.d.ts +0 -15
- package/dist/models/TenantRole.js +0 -23
- package/dist/routes/auth.d.ts +0 -11
- package/dist/routes/auth.js +0 -605
- package/dist/routes/groups.js +0 -346
- package/dist/routes/health.d.ts +0 -1
- package/dist/routes/health.js +0 -22
- package/dist/routes/home.d.ts +0 -1
- package/dist/routes/home.js +0 -16
- package/dist/routes/jobs.d.ts +0 -2
- package/dist/routes/jobs.js +0 -272
- package/dist/routes/metrics.d.ts +0 -7
- package/dist/routes/metrics.js +0 -52
- package/dist/routes/mfa.d.ts +0 -5
- package/dist/routes/mfa.js +0 -620
- package/dist/routes/oauth.d.ts +0 -2
- package/dist/routes/oauth.js +0 -514
- package/dist/routes/uploads.d.ts +0 -2
- package/dist/routes/uploads.js +0 -135
- package/dist/schemas/auth.js +0 -30
- package/dist/server.d.ts +0 -57
- package/dist/server.js +0 -112
- package/dist/services/auth.d.ts +0 -27
- package/dist/services/auth.js +0 -159
- package/dist/ws/index.d.ts +0 -10
- package/dist/ws/index.js +0 -38
- package/docs/sections/adding-middleware/full.md +0 -35
- package/docs/sections/adding-models/full.md +0 -125
- package/docs/sections/adding-models/overview.md +0 -13
- package/docs/sections/adding-routes/full.md +0 -182
- package/docs/sections/adding-routes/overview.md +0 -23
- package/docs/sections/auth-flow/full.md +0 -779
- package/docs/sections/auth-flow/overview.md +0 -10
- package/docs/sections/auth-security-examples/full.md +0 -365
- package/docs/sections/authentication/full.md +0 -130
- package/docs/sections/authentication/overview.md +0 -5
- package/docs/sections/cli/full.md +0 -42
- package/docs/sections/configuration/full.md +0 -172
- package/docs/sections/configuration/overview.md +0 -18
- package/docs/sections/configuration-example/full.md +0 -117
- package/docs/sections/configuration-example/overview.md +0 -30
- package/docs/sections/documentation/full.md +0 -171
- package/docs/sections/environment-variables/full.md +0 -55
- package/docs/sections/exports/full.md +0 -123
- package/docs/sections/extending-context/full.md +0 -59
- package/docs/sections/header.md +0 -3
- package/docs/sections/installation/full.md +0 -6
- package/docs/sections/jobs/full.md +0 -140
- package/docs/sections/jobs/overview.md +0 -15
- package/docs/sections/logging/full.md +0 -83
- package/docs/sections/metrics/full.md +0 -127
- package/docs/sections/mongodb-connections/full.md +0 -45
- package/docs/sections/mongodb-connections/overview.md +0 -7
- package/docs/sections/multi-tenancy/full.md +0 -66
- package/docs/sections/multi-tenancy/overview.md +0 -15
- package/docs/sections/oauth/full.md +0 -189
- package/docs/sections/oauth/overview.md +0 -16
- package/docs/sections/package-development/full.md +0 -7
- package/docs/sections/pagination/full.md +0 -93
- package/docs/sections/peer-dependencies/full.md +0 -47
- package/docs/sections/quick-start/full.md +0 -43
- package/docs/sections/response-caching/full.md +0 -117
- package/docs/sections/response-caching/overview.md +0 -13
- package/docs/sections/roles/full.md +0 -225
- package/docs/sections/roles/overview.md +0 -14
- package/docs/sections/running-without-redis/full.md +0 -16
- package/docs/sections/running-without-redis-or-mongodb/full.md +0 -60
- package/docs/sections/signing/full.md +0 -203
- package/docs/sections/stack/full.md +0 -10
- package/docs/sections/uploads/full.md +0 -199
- package/docs/sections/versioning/full.md +0 -85
- package/docs/sections/webhook-auth/full.md +0 -100
- package/docs/sections/websocket/full.md +0 -184
- package/docs/sections/websocket/overview.md +0 -5
- package/docs/sections/websocket-rooms/full.md +0 -102
- package/docs/sections/websocket-rooms/overview.md +0 -5
- /package/dist/{lib/storageAdapter.js → packages/bunshot-admin/src/types/env.js} +0 -0
- /package/dist/{lib → packages/bunshot-auth/src/lib}/fingerprint.d.ts +0 -0
- /package/dist/{lib → packages/bunshot-core/src}/constants.d.ts +0 -0
- /package/dist/{lib → packages/bunshot-core/src}/storageAdapter.d.ts +0 -0
- /package/dist/{lib → src/framework/lib}/createDtoMapper.d.ts +0 -0
- /package/dist/{lib → src/framework/lib}/stripUnreferencedSchemas.d.ts +0 -0
- /package/dist/{middleware → src/framework/middleware}/cors.d.ts +0 -0
- /package/dist/{middleware → src/framework/middleware}/cors.js +0 -0
- /package/dist/{middleware → src/framework/middleware}/index.d.ts +0 -0
- /package/dist/{middleware → src/framework/middleware}/logger.js +0 -0
- /package/dist/{lib → src/shared/lib}/constants.js +0 -0
|
@@ -0,0 +1,794 @@
|
|
|
1
|
+
import { and, asc, eq, gt, ilike, isNull, or, sql } from 'drizzle-orm';
|
|
2
|
+
import { drizzle } from 'drizzle-orm/node-postgres';
|
|
3
|
+
import { HttpError } from '../../bunshot-core/src/index.js';
|
|
4
|
+
import { groupMemberships, groups, oauthAccounts, recoveryCodes, tenantRoles, userRoles, users, webauthnCredentials, } from './schema.js';
|
|
5
|
+
function encodeCursor(createdAt, id) {
|
|
6
|
+
return btoa(JSON.stringify({ createdAt: createdAt.toISOString(), id }));
|
|
7
|
+
}
|
|
8
|
+
function decodeCursor(cursor) {
|
|
9
|
+
try {
|
|
10
|
+
const parsed = JSON.parse(atob(cursor));
|
|
11
|
+
if (typeof parsed.createdAt === 'string' && typeof parsed.id === 'string') {
|
|
12
|
+
return { createdAt: parsed.createdAt, id: parsed.id };
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// PostgreSQL error code 23505 = unique_violation
|
|
21
|
+
function isUniqueViolation(err) {
|
|
22
|
+
return (typeof err === 'object' &&
|
|
23
|
+
err !== null &&
|
|
24
|
+
'code' in err &&
|
|
25
|
+
err.code === '23505');
|
|
26
|
+
}
|
|
27
|
+
const MIGRATIONS = [
|
|
28
|
+
// v1: core auth tables
|
|
29
|
+
async (client) => {
|
|
30
|
+
await client.query(`
|
|
31
|
+
CREATE TABLE IF NOT EXISTS bunshot_users (
|
|
32
|
+
id TEXT PRIMARY KEY,
|
|
33
|
+
email TEXT UNIQUE,
|
|
34
|
+
password_hash TEXT,
|
|
35
|
+
email_verified BOOLEAN NOT NULL DEFAULT FALSE,
|
|
36
|
+
suspended BOOLEAN NOT NULL DEFAULT FALSE,
|
|
37
|
+
suspended_reason TEXT,
|
|
38
|
+
suspended_at TIMESTAMPTZ,
|
|
39
|
+
display_name TEXT,
|
|
40
|
+
first_name TEXT,
|
|
41
|
+
last_name TEXT,
|
|
42
|
+
external_id TEXT,
|
|
43
|
+
user_metadata JSONB,
|
|
44
|
+
app_metadata JSONB,
|
|
45
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
46
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
47
|
+
)
|
|
48
|
+
`);
|
|
49
|
+
await client.query(`
|
|
50
|
+
CREATE TABLE IF NOT EXISTS bunshot_oauth_accounts (
|
|
51
|
+
user_id TEXT NOT NULL REFERENCES bunshot_users(id) ON DELETE CASCADE,
|
|
52
|
+
provider TEXT NOT NULL,
|
|
53
|
+
provider_user_id TEXT NOT NULL,
|
|
54
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
55
|
+
PRIMARY KEY (provider, provider_user_id)
|
|
56
|
+
)
|
|
57
|
+
`);
|
|
58
|
+
await client.query(`
|
|
59
|
+
CREATE TABLE IF NOT EXISTS bunshot_user_roles (
|
|
60
|
+
user_id TEXT NOT NULL REFERENCES bunshot_users(id) ON DELETE CASCADE,
|
|
61
|
+
role TEXT NOT NULL,
|
|
62
|
+
PRIMARY KEY (user_id, role)
|
|
63
|
+
)
|
|
64
|
+
`);
|
|
65
|
+
await client.query(`
|
|
66
|
+
CREATE TABLE IF NOT EXISTS bunshot_tenant_roles (
|
|
67
|
+
user_id TEXT NOT NULL REFERENCES bunshot_users(id) ON DELETE CASCADE,
|
|
68
|
+
tenant_id TEXT NOT NULL,
|
|
69
|
+
role TEXT NOT NULL,
|
|
70
|
+
PRIMARY KEY (user_id, tenant_id, role)
|
|
71
|
+
)
|
|
72
|
+
`);
|
|
73
|
+
},
|
|
74
|
+
// v2: MFA, WebAuthn, and Groups
|
|
75
|
+
async (client) => {
|
|
76
|
+
// MFA columns on users
|
|
77
|
+
await client.query(`ALTER TABLE bunshot_users ADD COLUMN IF NOT EXISTS mfa_secret TEXT`);
|
|
78
|
+
await client.query(`ALTER TABLE bunshot_users ADD COLUMN IF NOT EXISTS mfa_enabled BOOLEAN NOT NULL DEFAULT FALSE`);
|
|
79
|
+
await client.query(`ALTER TABLE bunshot_users ADD COLUMN IF NOT EXISTS mfa_methods TEXT[] NOT NULL DEFAULT '{}'`);
|
|
80
|
+
// Recovery codes — separate table for atomic single-query consume
|
|
81
|
+
await client.query(`
|
|
82
|
+
CREATE TABLE IF NOT EXISTS bunshot_recovery_codes (
|
|
83
|
+
user_id TEXT NOT NULL REFERENCES bunshot_users(id) ON DELETE CASCADE,
|
|
84
|
+
code_hash TEXT NOT NULL,
|
|
85
|
+
PRIMARY KEY (user_id, code_hash)
|
|
86
|
+
)
|
|
87
|
+
`);
|
|
88
|
+
// WebAuthn credentials
|
|
89
|
+
await client.query(`
|
|
90
|
+
CREATE TABLE IF NOT EXISTS bunshot_webauthn_credentials (
|
|
91
|
+
credential_id TEXT PRIMARY KEY,
|
|
92
|
+
user_id TEXT NOT NULL REFERENCES bunshot_users(id) ON DELETE CASCADE,
|
|
93
|
+
public_key TEXT NOT NULL,
|
|
94
|
+
sign_count INTEGER NOT NULL DEFAULT 0,
|
|
95
|
+
transports TEXT[],
|
|
96
|
+
name TEXT,
|
|
97
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
98
|
+
)
|
|
99
|
+
`);
|
|
100
|
+
await client.query(`CREATE INDEX IF NOT EXISTS idx_bunshot_webauthn_user_id ON bunshot_webauthn_credentials(user_id)`);
|
|
101
|
+
// Groups — partial unique indexes enforce name uniqueness within scope
|
|
102
|
+
await client.query(`
|
|
103
|
+
CREATE TABLE IF NOT EXISTS bunshot_groups (
|
|
104
|
+
id TEXT PRIMARY KEY,
|
|
105
|
+
name TEXT NOT NULL,
|
|
106
|
+
display_name TEXT,
|
|
107
|
+
description TEXT,
|
|
108
|
+
roles TEXT[] NOT NULL DEFAULT '{}',
|
|
109
|
+
tenant_id TEXT,
|
|
110
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
111
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
112
|
+
)
|
|
113
|
+
`);
|
|
114
|
+
await client.query(`CREATE UNIQUE INDEX IF NOT EXISTS idx_bunshot_groups_name_appwide ON bunshot_groups(name) WHERE tenant_id IS NULL`);
|
|
115
|
+
await client.query(`CREATE UNIQUE INDEX IF NOT EXISTS idx_bunshot_groups_name_tenant ON bunshot_groups(name, tenant_id) WHERE tenant_id IS NOT NULL`);
|
|
116
|
+
await client.query(`CREATE INDEX IF NOT EXISTS idx_bunshot_groups_tenant ON bunshot_groups(tenant_id)`);
|
|
117
|
+
// Group memberships
|
|
118
|
+
await client.query(`
|
|
119
|
+
CREATE TABLE IF NOT EXISTS bunshot_group_memberships (
|
|
120
|
+
user_id TEXT NOT NULL REFERENCES bunshot_users(id) ON DELETE CASCADE,
|
|
121
|
+
group_id TEXT NOT NULL REFERENCES bunshot_groups(id) ON DELETE CASCADE,
|
|
122
|
+
roles TEXT[] NOT NULL DEFAULT '{}',
|
|
123
|
+
tenant_id TEXT,
|
|
124
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
125
|
+
PRIMARY KEY (user_id, group_id)
|
|
126
|
+
)
|
|
127
|
+
`);
|
|
128
|
+
await client.query(`CREATE INDEX IF NOT EXISTS idx_bunshot_gm_group_id ON bunshot_group_memberships(group_id)`);
|
|
129
|
+
await client.query(`CREATE INDEX IF NOT EXISTS idx_bunshot_gm_user_tenant ON bunshot_group_memberships(user_id, tenant_id)`);
|
|
130
|
+
},
|
|
131
|
+
// Add future migrations here. Never edit or reorder existing entries.
|
|
132
|
+
];
|
|
133
|
+
// Arbitrary but stable lock IDs for pg_advisory_xact_lock(int, int).
|
|
134
|
+
// These serialize concurrent migration runs across multiple processes.
|
|
135
|
+
const MIGRATION_LOCK_KEY1 = 7283;
|
|
136
|
+
const MIGRATION_LOCK_KEY2 = 4829;
|
|
137
|
+
async function runMigrations(pool) {
|
|
138
|
+
const client = await pool.connect();
|
|
139
|
+
try {
|
|
140
|
+
await client.query('BEGIN');
|
|
141
|
+
// Advisory lock is released automatically when the transaction ends.
|
|
142
|
+
await client.query('SELECT pg_advisory_xact_lock($1, $2)', [
|
|
143
|
+
MIGRATION_LOCK_KEY1,
|
|
144
|
+
MIGRATION_LOCK_KEY2,
|
|
145
|
+
]);
|
|
146
|
+
await client.query(`
|
|
147
|
+
CREATE TABLE IF NOT EXISTS _bunshot_auth_schema_version (
|
|
148
|
+
version INTEGER NOT NULL DEFAULT 0
|
|
149
|
+
)
|
|
150
|
+
`);
|
|
151
|
+
await client.query(`
|
|
152
|
+
INSERT INTO _bunshot_auth_schema_version (version)
|
|
153
|
+
SELECT 0 WHERE NOT EXISTS (SELECT 1 FROM _bunshot_auth_schema_version)
|
|
154
|
+
`);
|
|
155
|
+
const result = await client.query('SELECT version FROM _bunshot_auth_schema_version');
|
|
156
|
+
const currentVersion = result.rows[0]?.version ?? 0;
|
|
157
|
+
for (let i = currentVersion; i < MIGRATIONS.length; i++) {
|
|
158
|
+
await MIGRATIONS[i](client);
|
|
159
|
+
await client.query('UPDATE _bunshot_auth_schema_version SET version = $1', [i + 1]);
|
|
160
|
+
}
|
|
161
|
+
await client.query('COMMIT');
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
await client.query('ROLLBACK');
|
|
165
|
+
throw err;
|
|
166
|
+
}
|
|
167
|
+
finally {
|
|
168
|
+
client.release();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
export async function createPostgresAdapter(opts) {
|
|
172
|
+
await runMigrations(opts.pool);
|
|
173
|
+
const db = drizzle(opts.pool);
|
|
174
|
+
return {
|
|
175
|
+
// ── Tier 1 — CoreAuthAdapter ──────────────────────────────────────────────
|
|
176
|
+
async findByEmail(email) {
|
|
177
|
+
const row = await db
|
|
178
|
+
.select({ id: users.id, passwordHash: users.passwordHash })
|
|
179
|
+
.from(users)
|
|
180
|
+
.where(eq(users.email, email))
|
|
181
|
+
.then(r => r[0] ?? null);
|
|
182
|
+
if (!row)
|
|
183
|
+
return null;
|
|
184
|
+
return { id: row.id, passwordHash: row.passwordHash ?? '' };
|
|
185
|
+
},
|
|
186
|
+
async create(email, passwordHash) {
|
|
187
|
+
const id = crypto.randomUUID();
|
|
188
|
+
await db.insert(users).values({
|
|
189
|
+
id,
|
|
190
|
+
email: email.toLowerCase(),
|
|
191
|
+
passwordHash,
|
|
192
|
+
emailVerified: false,
|
|
193
|
+
suspended: false,
|
|
194
|
+
});
|
|
195
|
+
return { id };
|
|
196
|
+
},
|
|
197
|
+
async verifyPassword(userId, password) {
|
|
198
|
+
const row = await db
|
|
199
|
+
.select({ passwordHash: users.passwordHash })
|
|
200
|
+
.from(users)
|
|
201
|
+
.where(eq(users.id, userId))
|
|
202
|
+
.then(r => r[0] ?? null);
|
|
203
|
+
if (!row?.passwordHash)
|
|
204
|
+
return false;
|
|
205
|
+
return Bun.password.verify(password, row.passwordHash);
|
|
206
|
+
},
|
|
207
|
+
async getIdentifier(userId) {
|
|
208
|
+
const row = await db
|
|
209
|
+
.select({ email: users.email })
|
|
210
|
+
.from(users)
|
|
211
|
+
.where(eq(users.id, userId))
|
|
212
|
+
.then(r => r[0] ?? null);
|
|
213
|
+
return row?.email ?? userId;
|
|
214
|
+
},
|
|
215
|
+
async consumeRecoveryCode(userId, hashedCode) {
|
|
216
|
+
const deleted = await db
|
|
217
|
+
.delete(recoveryCodes)
|
|
218
|
+
.where(and(eq(recoveryCodes.userId, userId), eq(recoveryCodes.codeHash, hashedCode)))
|
|
219
|
+
.returning({ codeHash: recoveryCodes.codeHash });
|
|
220
|
+
return deleted.length > 0;
|
|
221
|
+
},
|
|
222
|
+
// ── Tier 1 — CoreAuthAdapter optional methods ─────────────────────────────
|
|
223
|
+
async getUser(userId) {
|
|
224
|
+
const row = await db
|
|
225
|
+
.select()
|
|
226
|
+
.from(users)
|
|
227
|
+
.where(eq(users.id, userId))
|
|
228
|
+
.then(r => r[0] ?? null);
|
|
229
|
+
if (!row)
|
|
230
|
+
return null;
|
|
231
|
+
return {
|
|
232
|
+
email: row.email ?? undefined,
|
|
233
|
+
displayName: row.displayName ?? undefined,
|
|
234
|
+
firstName: row.firstName ?? undefined,
|
|
235
|
+
lastName: row.lastName ?? undefined,
|
|
236
|
+
externalId: row.externalId ?? undefined,
|
|
237
|
+
emailVerified: row.emailVerified,
|
|
238
|
+
suspended: row.suspended,
|
|
239
|
+
suspendedReason: row.suspendedReason ?? undefined,
|
|
240
|
+
userMetadata: row.userMetadata ?? undefined,
|
|
241
|
+
appMetadata: row.appMetadata ?? undefined,
|
|
242
|
+
};
|
|
243
|
+
},
|
|
244
|
+
async setPassword(userId, passwordHash) {
|
|
245
|
+
await db
|
|
246
|
+
.update(users)
|
|
247
|
+
.set({ passwordHash, updatedAt: new Date() })
|
|
248
|
+
.where(eq(users.id, userId));
|
|
249
|
+
},
|
|
250
|
+
async deleteUser(userId) {
|
|
251
|
+
await db.delete(users).where(eq(users.id, userId));
|
|
252
|
+
},
|
|
253
|
+
async setEmailVerified(userId, verified) {
|
|
254
|
+
await db
|
|
255
|
+
.update(users)
|
|
256
|
+
.set({ emailVerified: verified, updatedAt: new Date() })
|
|
257
|
+
.where(eq(users.id, userId));
|
|
258
|
+
},
|
|
259
|
+
async getEmailVerified(userId) {
|
|
260
|
+
const row = await db
|
|
261
|
+
.select({ emailVerified: users.emailVerified })
|
|
262
|
+
.from(users)
|
|
263
|
+
.where(eq(users.id, userId))
|
|
264
|
+
.then(r => r[0] ?? null);
|
|
265
|
+
return row?.emailVerified ?? false;
|
|
266
|
+
},
|
|
267
|
+
async hasPassword(userId) {
|
|
268
|
+
const row = await db
|
|
269
|
+
.select({ passwordHash: users.passwordHash })
|
|
270
|
+
.from(users)
|
|
271
|
+
.where(eq(users.id, userId))
|
|
272
|
+
.then(r => r[0] ?? null);
|
|
273
|
+
return !!row?.passwordHash;
|
|
274
|
+
},
|
|
275
|
+
async updateProfile(userId, fields) {
|
|
276
|
+
await db
|
|
277
|
+
.update(users)
|
|
278
|
+
.set({
|
|
279
|
+
displayName: fields.displayName,
|
|
280
|
+
firstName: fields.firstName,
|
|
281
|
+
lastName: fields.lastName,
|
|
282
|
+
externalId: fields.externalId,
|
|
283
|
+
updatedAt: new Date(),
|
|
284
|
+
})
|
|
285
|
+
.where(eq(users.id, userId));
|
|
286
|
+
},
|
|
287
|
+
async getUserMetadata(userId) {
|
|
288
|
+
const row = await db
|
|
289
|
+
.select({ userMetadata: users.userMetadata, appMetadata: users.appMetadata })
|
|
290
|
+
.from(users)
|
|
291
|
+
.where(eq(users.id, userId))
|
|
292
|
+
.then(r => r[0] ?? null);
|
|
293
|
+
return {
|
|
294
|
+
userMetadata: row?.userMetadata ?? undefined,
|
|
295
|
+
appMetadata: row?.appMetadata ?? undefined,
|
|
296
|
+
};
|
|
297
|
+
},
|
|
298
|
+
async setUserMetadata(userId, data) {
|
|
299
|
+
await db
|
|
300
|
+
.update(users)
|
|
301
|
+
.set({ userMetadata: data, updatedAt: new Date() })
|
|
302
|
+
.where(eq(users.id, userId));
|
|
303
|
+
},
|
|
304
|
+
async setAppMetadata(userId, data) {
|
|
305
|
+
await db
|
|
306
|
+
.update(users)
|
|
307
|
+
.set({ appMetadata: data, updatedAt: new Date() })
|
|
308
|
+
.where(eq(users.id, userId));
|
|
309
|
+
},
|
|
310
|
+
// ── Tier 2 — OAuthAdapter ─────────────────────────────────────────────────
|
|
311
|
+
async findOrCreateByProvider(provider, providerId, profile) {
|
|
312
|
+
const existing = await db
|
|
313
|
+
.select({ userId: oauthAccounts.userId })
|
|
314
|
+
.from(oauthAccounts)
|
|
315
|
+
.where(and(eq(oauthAccounts.provider, provider), eq(oauthAccounts.providerUserId, providerId)))
|
|
316
|
+
.then(r => r[0] ?? null);
|
|
317
|
+
if (existing) {
|
|
318
|
+
return { id: existing.userId, created: false };
|
|
319
|
+
}
|
|
320
|
+
const normalizedEmail = profile.email?.toLowerCase();
|
|
321
|
+
if (normalizedEmail) {
|
|
322
|
+
const emailConflict = await db
|
|
323
|
+
.select({ id: users.id })
|
|
324
|
+
.from(users)
|
|
325
|
+
.where(eq(users.email, normalizedEmail))
|
|
326
|
+
.then(r => r[0] ?? null);
|
|
327
|
+
if (emailConflict) {
|
|
328
|
+
throw new HttpError(409, 'An account with this email already exists. Sign in with your credentials, then link the provider from your account settings.', 'PROVIDER_EMAIL_CONFLICT');
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
const id = crypto.randomUUID();
|
|
332
|
+
await db.transaction(async (tx) => {
|
|
333
|
+
await tx.insert(users).values({
|
|
334
|
+
id,
|
|
335
|
+
email: normalizedEmail,
|
|
336
|
+
emailVerified: false,
|
|
337
|
+
suspended: false,
|
|
338
|
+
displayName: profile.displayName,
|
|
339
|
+
firstName: profile.firstName,
|
|
340
|
+
lastName: profile.lastName,
|
|
341
|
+
externalId: profile.externalId,
|
|
342
|
+
});
|
|
343
|
+
await tx.insert(oauthAccounts).values({ userId: id, provider, providerUserId: providerId });
|
|
344
|
+
});
|
|
345
|
+
return { id, created: true };
|
|
346
|
+
},
|
|
347
|
+
async linkProvider(userId, provider, providerId) {
|
|
348
|
+
await db
|
|
349
|
+
.insert(oauthAccounts)
|
|
350
|
+
.values({ userId, provider, providerUserId: providerId })
|
|
351
|
+
.onConflictDoNothing();
|
|
352
|
+
},
|
|
353
|
+
async unlinkProvider(userId, provider) {
|
|
354
|
+
await db
|
|
355
|
+
.delete(oauthAccounts)
|
|
356
|
+
.where(and(eq(oauthAccounts.userId, userId), eq(oauthAccounts.provider, provider)));
|
|
357
|
+
},
|
|
358
|
+
// ── Tier 3 — MfaAdapter ───────────────────────────────────────────────────
|
|
359
|
+
async setMfaSecret(userId, secret) {
|
|
360
|
+
await db
|
|
361
|
+
.update(users)
|
|
362
|
+
.set({ mfaSecret: secret, updatedAt: new Date() })
|
|
363
|
+
.where(eq(users.id, userId));
|
|
364
|
+
},
|
|
365
|
+
async getMfaSecret(userId) {
|
|
366
|
+
const row = await db
|
|
367
|
+
.select({ mfaSecret: users.mfaSecret })
|
|
368
|
+
.from(users)
|
|
369
|
+
.where(eq(users.id, userId))
|
|
370
|
+
.then(r => r[0] ?? null);
|
|
371
|
+
return row?.mfaSecret ?? null;
|
|
372
|
+
},
|
|
373
|
+
async isMfaEnabled(userId) {
|
|
374
|
+
const row = await db
|
|
375
|
+
.select({ mfaEnabled: users.mfaEnabled })
|
|
376
|
+
.from(users)
|
|
377
|
+
.where(eq(users.id, userId))
|
|
378
|
+
.then(r => r[0] ?? null);
|
|
379
|
+
return row?.mfaEnabled ?? false;
|
|
380
|
+
},
|
|
381
|
+
async setMfaEnabled(userId, enabled) {
|
|
382
|
+
await db
|
|
383
|
+
.update(users)
|
|
384
|
+
.set({ mfaEnabled: enabled, updatedAt: new Date() })
|
|
385
|
+
.where(eq(users.id, userId));
|
|
386
|
+
},
|
|
387
|
+
async setRecoveryCodes(userId, codes) {
|
|
388
|
+
await db.transaction(async (tx) => {
|
|
389
|
+
await tx.delete(recoveryCodes).where(eq(recoveryCodes.userId, userId));
|
|
390
|
+
if (codes.length > 0) {
|
|
391
|
+
await tx.insert(recoveryCodes).values(codes.map(codeHash => ({ userId, codeHash })));
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
},
|
|
395
|
+
async getRecoveryCodes(userId) {
|
|
396
|
+
const rows = await db
|
|
397
|
+
.select({ codeHash: recoveryCodes.codeHash })
|
|
398
|
+
.from(recoveryCodes)
|
|
399
|
+
.where(eq(recoveryCodes.userId, userId));
|
|
400
|
+
return rows.map(r => r.codeHash);
|
|
401
|
+
},
|
|
402
|
+
async removeRecoveryCode(userId, code) {
|
|
403
|
+
await db
|
|
404
|
+
.delete(recoveryCodes)
|
|
405
|
+
.where(and(eq(recoveryCodes.userId, userId), eq(recoveryCodes.codeHash, code)));
|
|
406
|
+
},
|
|
407
|
+
async getMfaMethods(userId) {
|
|
408
|
+
const row = await db
|
|
409
|
+
.select({ mfaMethods: users.mfaMethods })
|
|
410
|
+
.from(users)
|
|
411
|
+
.where(eq(users.id, userId))
|
|
412
|
+
.then(r => r[0] ?? null);
|
|
413
|
+
return row?.mfaMethods ?? [];
|
|
414
|
+
},
|
|
415
|
+
async setMfaMethods(userId, methods) {
|
|
416
|
+
await db
|
|
417
|
+
.update(users)
|
|
418
|
+
.set({ mfaMethods: methods, updatedAt: new Date() })
|
|
419
|
+
.where(eq(users.id, userId));
|
|
420
|
+
},
|
|
421
|
+
// ── Tier 4 — WebAuthnAdapter ──────────────────────────────────────────────
|
|
422
|
+
async getWebAuthnCredentials(userId) {
|
|
423
|
+
const rows = await db
|
|
424
|
+
.select()
|
|
425
|
+
.from(webauthnCredentials)
|
|
426
|
+
.where(eq(webauthnCredentials.userId, userId));
|
|
427
|
+
return rows.map(row => ({
|
|
428
|
+
credentialId: row.credentialId,
|
|
429
|
+
publicKey: row.publicKey,
|
|
430
|
+
signCount: row.signCount,
|
|
431
|
+
transports: row.transports ?? undefined,
|
|
432
|
+
name: row.name ?? undefined,
|
|
433
|
+
createdAt: row.createdAt.getTime(),
|
|
434
|
+
}));
|
|
435
|
+
},
|
|
436
|
+
async addWebAuthnCredential(userId, credential) {
|
|
437
|
+
await db.insert(webauthnCredentials).values({
|
|
438
|
+
credentialId: credential.credentialId,
|
|
439
|
+
userId,
|
|
440
|
+
publicKey: credential.publicKey,
|
|
441
|
+
signCount: credential.signCount,
|
|
442
|
+
transports: credential.transports ?? null,
|
|
443
|
+
name: credential.name ?? null,
|
|
444
|
+
createdAt: new Date(credential.createdAt),
|
|
445
|
+
});
|
|
446
|
+
},
|
|
447
|
+
async removeWebAuthnCredential(userId, credentialId) {
|
|
448
|
+
await db
|
|
449
|
+
.delete(webauthnCredentials)
|
|
450
|
+
.where(and(eq(webauthnCredentials.credentialId, credentialId), eq(webauthnCredentials.userId, userId)));
|
|
451
|
+
},
|
|
452
|
+
async updateWebAuthnCredentialSignCount(userId, credentialId, signCount) {
|
|
453
|
+
await db
|
|
454
|
+
.update(webauthnCredentials)
|
|
455
|
+
.set({ signCount })
|
|
456
|
+
.where(and(eq(webauthnCredentials.credentialId, credentialId), eq(webauthnCredentials.userId, userId)));
|
|
457
|
+
},
|
|
458
|
+
async findUserByWebAuthnCredentialId(credentialId) {
|
|
459
|
+
const row = await db
|
|
460
|
+
.select({ userId: webauthnCredentials.userId })
|
|
461
|
+
.from(webauthnCredentials)
|
|
462
|
+
.where(eq(webauthnCredentials.credentialId, credentialId))
|
|
463
|
+
.then(r => r[0] ?? null);
|
|
464
|
+
return row?.userId ?? null;
|
|
465
|
+
},
|
|
466
|
+
// ── Tier 5 — RolesAdapter ─────────────────────────────────────────────────
|
|
467
|
+
async getRoles(userId) {
|
|
468
|
+
const rows = await db
|
|
469
|
+
.select({ role: userRoles.role })
|
|
470
|
+
.from(userRoles)
|
|
471
|
+
.where(eq(userRoles.userId, userId));
|
|
472
|
+
return rows.map(r => r.role);
|
|
473
|
+
},
|
|
474
|
+
async setRoles(userId, roles) {
|
|
475
|
+
await db.transaction(async (tx) => {
|
|
476
|
+
await tx.delete(userRoles).where(eq(userRoles.userId, userId));
|
|
477
|
+
if (roles.length > 0) {
|
|
478
|
+
await tx.insert(userRoles).values(roles.map(role => ({ userId, role })));
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
},
|
|
482
|
+
async addRole(userId, role) {
|
|
483
|
+
await db.insert(userRoles).values({ userId, role }).onConflictDoNothing();
|
|
484
|
+
},
|
|
485
|
+
async removeRole(userId, role) {
|
|
486
|
+
await db.delete(userRoles).where(and(eq(userRoles.userId, userId), eq(userRoles.role, role)));
|
|
487
|
+
},
|
|
488
|
+
async getTenantRoles(userId, tenantId) {
|
|
489
|
+
const rows = await db
|
|
490
|
+
.select({ role: tenantRoles.role })
|
|
491
|
+
.from(tenantRoles)
|
|
492
|
+
.where(and(eq(tenantRoles.userId, userId), eq(tenantRoles.tenantId, tenantId)));
|
|
493
|
+
return rows.map(r => r.role);
|
|
494
|
+
},
|
|
495
|
+
async setTenantRoles(userId, tenantId, roles) {
|
|
496
|
+
await db.transaction(async (tx) => {
|
|
497
|
+
await tx
|
|
498
|
+
.delete(tenantRoles)
|
|
499
|
+
.where(and(eq(tenantRoles.userId, userId), eq(tenantRoles.tenantId, tenantId)));
|
|
500
|
+
if (roles.length > 0) {
|
|
501
|
+
await tx.insert(tenantRoles).values(roles.map(role => ({ userId, tenantId, role })));
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
},
|
|
505
|
+
async addTenantRole(userId, tenantId, role) {
|
|
506
|
+
await db.insert(tenantRoles).values({ userId, tenantId, role }).onConflictDoNothing();
|
|
507
|
+
},
|
|
508
|
+
async removeTenantRole(userId, tenantId, role) {
|
|
509
|
+
await db
|
|
510
|
+
.delete(tenantRoles)
|
|
511
|
+
.where(and(eq(tenantRoles.userId, userId), eq(tenantRoles.tenantId, tenantId), eq(tenantRoles.role, role)));
|
|
512
|
+
},
|
|
513
|
+
// ── Tier 6 — GroupsAdapter ────────────────────────────────────────────────
|
|
514
|
+
async createGroup(group) {
|
|
515
|
+
const id = crypto.randomUUID();
|
|
516
|
+
const now = new Date();
|
|
517
|
+
try {
|
|
518
|
+
await db.insert(groups).values({
|
|
519
|
+
id,
|
|
520
|
+
name: group.name,
|
|
521
|
+
displayName: group.displayName,
|
|
522
|
+
description: group.description,
|
|
523
|
+
roles: group.roles ?? [],
|
|
524
|
+
tenantId: group.tenantId,
|
|
525
|
+
createdAt: now,
|
|
526
|
+
updatedAt: now,
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
catch (err) {
|
|
530
|
+
if (isUniqueViolation(err)) {
|
|
531
|
+
throw new HttpError(409, 'A group with this name already exists in this scope', 'GROUP_NAME_CONFLICT');
|
|
532
|
+
}
|
|
533
|
+
throw err;
|
|
534
|
+
}
|
|
535
|
+
return { id };
|
|
536
|
+
},
|
|
537
|
+
async deleteGroup(groupId) {
|
|
538
|
+
await db.delete(groups).where(eq(groups.id, groupId));
|
|
539
|
+
},
|
|
540
|
+
async getGroup(groupId) {
|
|
541
|
+
const row = await db
|
|
542
|
+
.select()
|
|
543
|
+
.from(groups)
|
|
544
|
+
.where(eq(groups.id, groupId))
|
|
545
|
+
.then(r => r[0] ?? null);
|
|
546
|
+
if (!row)
|
|
547
|
+
return null;
|
|
548
|
+
return {
|
|
549
|
+
id: row.id,
|
|
550
|
+
name: row.name,
|
|
551
|
+
displayName: row.displayName ?? undefined,
|
|
552
|
+
description: row.description ?? undefined,
|
|
553
|
+
roles: row.roles,
|
|
554
|
+
tenantId: row.tenantId,
|
|
555
|
+
createdAt: row.createdAt.getTime(),
|
|
556
|
+
updatedAt: row.updatedAt.getTime(),
|
|
557
|
+
};
|
|
558
|
+
},
|
|
559
|
+
async listGroups(tenantId, opts) {
|
|
560
|
+
const limit = Math.min(opts?.limit ?? 50, 200);
|
|
561
|
+
const cursor = opts?.cursor ? decodeCursor(opts.cursor) : null;
|
|
562
|
+
const conditions = [
|
|
563
|
+
tenantId === null ? isNull(groups.tenantId) : eq(groups.tenantId, tenantId),
|
|
564
|
+
cursor !== null
|
|
565
|
+
? or(gt(groups.createdAt, new Date(cursor.createdAt)), and(eq(groups.createdAt, new Date(cursor.createdAt)), gt(groups.id, cursor.id)))
|
|
566
|
+
: undefined,
|
|
567
|
+
].filter((c) => c !== undefined);
|
|
568
|
+
const rows = await db
|
|
569
|
+
.select()
|
|
570
|
+
.from(groups)
|
|
571
|
+
.where(and(...conditions))
|
|
572
|
+
.orderBy(asc(groups.createdAt), asc(groups.id))
|
|
573
|
+
.limit(limit + 1);
|
|
574
|
+
const hasMore = rows.length > limit;
|
|
575
|
+
const page = hasMore ? rows.slice(0, limit) : rows;
|
|
576
|
+
const lastRow = page[page.length - 1];
|
|
577
|
+
return {
|
|
578
|
+
items: page.map(row => ({
|
|
579
|
+
id: row.id,
|
|
580
|
+
name: row.name,
|
|
581
|
+
displayName: row.displayName ?? undefined,
|
|
582
|
+
description: row.description ?? undefined,
|
|
583
|
+
roles: row.roles,
|
|
584
|
+
tenantId: row.tenantId,
|
|
585
|
+
createdAt: row.createdAt.getTime(),
|
|
586
|
+
updatedAt: row.updatedAt.getTime(),
|
|
587
|
+
})),
|
|
588
|
+
nextCursor: hasMore && lastRow ? encodeCursor(lastRow.createdAt, lastRow.id) : undefined,
|
|
589
|
+
};
|
|
590
|
+
},
|
|
591
|
+
async updateGroup(groupId, updates) {
|
|
592
|
+
const patch = { updatedAt: new Date() };
|
|
593
|
+
if (updates.name !== undefined)
|
|
594
|
+
patch.name = updates.name;
|
|
595
|
+
if ('displayName' in updates)
|
|
596
|
+
patch.displayName = updates.displayName ?? null;
|
|
597
|
+
if ('description' in updates)
|
|
598
|
+
patch.description = updates.description ?? null;
|
|
599
|
+
if (updates.roles !== undefined)
|
|
600
|
+
patch.roles = updates.roles;
|
|
601
|
+
await db.update(groups).set(patch).where(eq(groups.id, groupId));
|
|
602
|
+
},
|
|
603
|
+
async addGroupMember(groupId, userId, roles = []) {
|
|
604
|
+
const group = await db
|
|
605
|
+
.select({ tenantId: groups.tenantId })
|
|
606
|
+
.from(groups)
|
|
607
|
+
.where(eq(groups.id, groupId))
|
|
608
|
+
.then(r => r[0] ?? null);
|
|
609
|
+
if (!group)
|
|
610
|
+
throw new HttpError(404, 'Group not found');
|
|
611
|
+
try {
|
|
612
|
+
await db.insert(groupMemberships).values({
|
|
613
|
+
userId,
|
|
614
|
+
groupId,
|
|
615
|
+
roles,
|
|
616
|
+
tenantId: group.tenantId,
|
|
617
|
+
createdAt: new Date(),
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
catch (err) {
|
|
621
|
+
if (isUniqueViolation(err)) {
|
|
622
|
+
throw new HttpError(409, 'User is already a member of this group', 'GROUP_MEMBER_CONFLICT');
|
|
623
|
+
}
|
|
624
|
+
throw err;
|
|
625
|
+
}
|
|
626
|
+
},
|
|
627
|
+
async updateGroupMembership(groupId, userId, roles) {
|
|
628
|
+
await db
|
|
629
|
+
.update(groupMemberships)
|
|
630
|
+
.set({ roles })
|
|
631
|
+
.where(and(eq(groupMemberships.userId, userId), eq(groupMemberships.groupId, groupId)));
|
|
632
|
+
},
|
|
633
|
+
async removeGroupMember(groupId, userId) {
|
|
634
|
+
await db
|
|
635
|
+
.delete(groupMemberships)
|
|
636
|
+
.where(and(eq(groupMemberships.userId, userId), eq(groupMemberships.groupId, groupId)));
|
|
637
|
+
},
|
|
638
|
+
async getGroupMembers(groupId, opts) {
|
|
639
|
+
const limit = Math.min(opts?.limit ?? 50, 200);
|
|
640
|
+
const cursor = opts?.cursor ? decodeCursor(opts.cursor) : null;
|
|
641
|
+
const conditions = [
|
|
642
|
+
eq(groupMemberships.groupId, groupId),
|
|
643
|
+
cursor !== null
|
|
644
|
+
? or(gt(groupMemberships.createdAt, new Date(cursor.createdAt)), and(eq(groupMemberships.createdAt, new Date(cursor.createdAt)), gt(groupMemberships.userId, cursor.id)))
|
|
645
|
+
: undefined,
|
|
646
|
+
].filter((c) => c !== undefined);
|
|
647
|
+
const rows = await db
|
|
648
|
+
.select({
|
|
649
|
+
userId: groupMemberships.userId,
|
|
650
|
+
roles: groupMemberships.roles,
|
|
651
|
+
createdAt: groupMemberships.createdAt,
|
|
652
|
+
})
|
|
653
|
+
.from(groupMemberships)
|
|
654
|
+
.where(and(...conditions))
|
|
655
|
+
.orderBy(asc(groupMemberships.createdAt), asc(groupMemberships.userId))
|
|
656
|
+
.limit(limit + 1);
|
|
657
|
+
const hasMore = rows.length > limit;
|
|
658
|
+
const page = hasMore ? rows.slice(0, limit) : rows;
|
|
659
|
+
const lastRow = page[page.length - 1];
|
|
660
|
+
return {
|
|
661
|
+
items: page.map(r => ({ userId: r.userId, roles: r.roles })),
|
|
662
|
+
nextCursor: hasMore && lastRow ? encodeCursor(lastRow.createdAt, lastRow.userId) : undefined,
|
|
663
|
+
};
|
|
664
|
+
},
|
|
665
|
+
async getUserGroups(userId, tenantId) {
|
|
666
|
+
const memberCondition = tenantId === null
|
|
667
|
+
? and(eq(groupMemberships.userId, userId), isNull(groupMemberships.tenantId))
|
|
668
|
+
: and(eq(groupMemberships.userId, userId), eq(groupMemberships.tenantId, tenantId));
|
|
669
|
+
const rows = await db
|
|
670
|
+
.select({
|
|
671
|
+
groupId: groups.id,
|
|
672
|
+
groupName: groups.name,
|
|
673
|
+
groupDisplayName: groups.displayName,
|
|
674
|
+
groupDescription: groups.description,
|
|
675
|
+
groupRoles: groups.roles,
|
|
676
|
+
groupTenantId: groups.tenantId,
|
|
677
|
+
groupCreatedAt: groups.createdAt,
|
|
678
|
+
groupUpdatedAt: groups.updatedAt,
|
|
679
|
+
memberRoles: groupMemberships.roles,
|
|
680
|
+
})
|
|
681
|
+
.from(groupMemberships)
|
|
682
|
+
.innerJoin(groups, eq(groupMemberships.groupId, groups.id))
|
|
683
|
+
.where(memberCondition);
|
|
684
|
+
return rows.map(row => ({
|
|
685
|
+
group: {
|
|
686
|
+
id: row.groupId,
|
|
687
|
+
name: row.groupName,
|
|
688
|
+
displayName: row.groupDisplayName ?? undefined,
|
|
689
|
+
description: row.groupDescription ?? undefined,
|
|
690
|
+
roles: row.groupRoles,
|
|
691
|
+
tenantId: row.groupTenantId,
|
|
692
|
+
createdAt: row.groupCreatedAt.getTime(),
|
|
693
|
+
updatedAt: row.groupUpdatedAt.getTime(),
|
|
694
|
+
},
|
|
695
|
+
membershipRoles: row.memberRoles,
|
|
696
|
+
}));
|
|
697
|
+
},
|
|
698
|
+
async getEffectiveRoles(userId, tenantId) {
|
|
699
|
+
// Direct roles
|
|
700
|
+
let direct;
|
|
701
|
+
if (tenantId !== null) {
|
|
702
|
+
const rows = await db
|
|
703
|
+
.select({ role: tenantRoles.role })
|
|
704
|
+
.from(tenantRoles)
|
|
705
|
+
.where(and(eq(tenantRoles.userId, userId), eq(tenantRoles.tenantId, tenantId)));
|
|
706
|
+
direct = rows.map(r => r.role);
|
|
707
|
+
}
|
|
708
|
+
else {
|
|
709
|
+
const rows = await db
|
|
710
|
+
.select({ role: userRoles.role })
|
|
711
|
+
.from(userRoles)
|
|
712
|
+
.where(eq(userRoles.userId, userId));
|
|
713
|
+
direct = rows.map(r => r.role);
|
|
714
|
+
}
|
|
715
|
+
// Group roles — single JOIN query, not N+1
|
|
716
|
+
const memberCondition = tenantId === null
|
|
717
|
+
? and(eq(groupMemberships.userId, userId), isNull(groupMemberships.tenantId))
|
|
718
|
+
: and(eq(groupMemberships.userId, userId), eq(groupMemberships.tenantId, tenantId));
|
|
719
|
+
const memberRows = await db
|
|
720
|
+
.select({ groupRoles: groups.roles, memberRoles: groupMemberships.roles })
|
|
721
|
+
.from(groupMemberships)
|
|
722
|
+
.innerJoin(groups, eq(groupMemberships.groupId, groups.id))
|
|
723
|
+
.where(memberCondition);
|
|
724
|
+
const fromGroups = memberRows.flatMap(r => [...r.groupRoles, ...r.memberRoles]);
|
|
725
|
+
return [...new Set([...direct, ...fromGroups])];
|
|
726
|
+
},
|
|
727
|
+
// ── Tier 7 — SuspensionAdapter ────────────────────────────────────────────
|
|
728
|
+
async setSuspended(userId, suspended, reason) {
|
|
729
|
+
await db
|
|
730
|
+
.update(users)
|
|
731
|
+
.set({
|
|
732
|
+
suspended,
|
|
733
|
+
suspendedReason: suspended ? (reason ?? null) : null,
|
|
734
|
+
suspendedAt: suspended ? new Date() : null,
|
|
735
|
+
updatedAt: new Date(),
|
|
736
|
+
})
|
|
737
|
+
.where(eq(users.id, userId));
|
|
738
|
+
},
|
|
739
|
+
async getSuspended(userId) {
|
|
740
|
+
const row = await db
|
|
741
|
+
.select({ suspended: users.suspended, suspendedReason: users.suspendedReason })
|
|
742
|
+
.from(users)
|
|
743
|
+
.where(eq(users.id, userId))
|
|
744
|
+
.then(r => r[0] ?? null);
|
|
745
|
+
if (!row)
|
|
746
|
+
return null;
|
|
747
|
+
return {
|
|
748
|
+
suspended: row.suspended,
|
|
749
|
+
suspendedReason: row.suspendedReason ?? undefined,
|
|
750
|
+
};
|
|
751
|
+
},
|
|
752
|
+
// ── Tier 8 — EnterpriseAdapter ────────────────────────────────────────────
|
|
753
|
+
async listUsers(query) {
|
|
754
|
+
const { startIndex = 0, count = 50, email: emailFilter, externalId, suspended } = query ?? {};
|
|
755
|
+
const limit = Math.min(count, 200);
|
|
756
|
+
const conditions = [
|
|
757
|
+
emailFilter !== undefined ? ilike(users.email, `%${emailFilter}%`) : undefined,
|
|
758
|
+
externalId !== undefined ? eq(users.externalId, externalId) : undefined,
|
|
759
|
+
suspended !== undefined ? eq(users.suspended, suspended) : undefined,
|
|
760
|
+
].filter((c) => c !== undefined);
|
|
761
|
+
const whereClause = conditions.length > 0 ? and(...conditions) : undefined;
|
|
762
|
+
const { userRows, total } = await db.transaction(async (tx) => {
|
|
763
|
+
const userRows = await tx
|
|
764
|
+
.select()
|
|
765
|
+
.from(users)
|
|
766
|
+
.where(whereClause)
|
|
767
|
+
.limit(limit)
|
|
768
|
+
.offset(startIndex);
|
|
769
|
+
const countResult = await tx
|
|
770
|
+
.select({ count: sql `count(*)` })
|
|
771
|
+
.from(users)
|
|
772
|
+
.where(whereClause);
|
|
773
|
+
return { userRows, total: Number(countResult[0].count) };
|
|
774
|
+
});
|
|
775
|
+
return {
|
|
776
|
+
users: userRows.map(row => ({
|
|
777
|
+
id: row.id,
|
|
778
|
+
email: row.email ?? undefined,
|
|
779
|
+
displayName: row.displayName ?? undefined,
|
|
780
|
+
firstName: row.firstName ?? undefined,
|
|
781
|
+
lastName: row.lastName ?? undefined,
|
|
782
|
+
externalId: row.externalId ?? undefined,
|
|
783
|
+
emailVerified: row.emailVerified,
|
|
784
|
+
suspended: row.suspended,
|
|
785
|
+
suspendedAt: row.suspendedAt ?? undefined,
|
|
786
|
+
suspendedReason: row.suspendedReason ?? undefined,
|
|
787
|
+
userMetadata: row.userMetadata ?? undefined,
|
|
788
|
+
appMetadata: row.appMetadata ?? undefined,
|
|
789
|
+
})),
|
|
790
|
+
totalResults: total,
|
|
791
|
+
};
|
|
792
|
+
},
|
|
793
|
+
};
|
|
794
|
+
}
|