@estifanos-sh/convex-auth 0.0.2 → 0.0.4
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/README.md +29 -6
- package/dist/bin.js +2 -34
- package/dist/browser/index.d.ts +2 -2
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +15 -9
- package/dist/browser/index.js.map +1 -1
- package/dist/client/core/types.d.ts +68 -97
- package/dist/client/core/types.d.ts.map +1 -1
- package/dist/client/core/types.js.map +1 -1
- package/dist/client/errors.d.ts +15 -0
- package/dist/client/errors.d.ts.map +1 -0
- package/dist/client/errors.js +8 -1
- package/dist/client/errors.js.map +1 -1
- package/dist/client/factors/device.js +4 -4
- package/dist/client/factors/device.js.map +1 -1
- package/dist/client/factors/totp.js +20 -12
- package/dist/client/factors/totp.js.map +1 -1
- package/dist/client/factors/webauthn.js +6 -2
- package/dist/client/factors/webauthn.js.map +1 -1
- package/dist/client/index.d.ts +6 -3
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +13 -10
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/api.d.ts +13 -3
- package/dist/component/_generated/api.d.ts.map +1 -1
- package/dist/component/_generated/api.js.map +1 -1
- package/dist/component/_generated/component.d.ts +365 -74
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/_generated/dataModel.d.ts +2 -2
- package/dist/component/_generated/dataModel.d.ts.map +1 -1
- package/dist/component/_generated/server.d.ts +13 -2
- package/dist/component/_generated/server.d.ts.map +1 -1
- package/dist/component/_generated/server.js +2 -1
- package/dist/component/_generated/server.js.map +1 -1
- package/dist/component/account.d.ts +52 -38
- package/dist/component/account.d.ts.map +1 -1
- package/dist/component/account.js +42 -23
- package/dist/component/account.js.map +1 -1
- package/dist/component/batch.d.ts +3 -0
- package/dist/component/batch.d.ts.map +1 -0
- package/dist/component/batch.js +17 -0
- package/dist/component/batch.js.map +1 -0
- package/dist/component/connection/audit.d.ts +30 -27
- package/dist/component/connection/audit.d.ts.map +1 -1
- package/dist/component/connection/audit.js +16 -23
- package/dist/component/connection/audit.js.map +1 -1
- package/dist/component/connection/cache.d.ts +6 -6
- package/dist/component/connection/cache.js +0 -1
- package/dist/component/connection/cache.js.map +1 -1
- package/dist/component/connection/domain/verification.d.ts +19 -19
- package/dist/component/connection/domain/verification.js +1 -2
- package/dist/component/connection/domain/verification.js.map +1 -1
- package/dist/component/connection/domain.d.ts +20 -20
- package/dist/component/connection/domain.js +1 -2
- package/dist/component/connection/domain.js.map +1 -1
- package/dist/component/connection/saml/assertion.d.ts +4 -4
- package/dist/component/connection/saml/assertion.js +0 -1
- package/dist/component/connection/saml/assertion.js.map +1 -1
- package/dist/component/connection/saml/request.d.ts +8 -9
- package/dist/component/connection/saml/request.d.ts.map +1 -1
- package/dist/component/connection/saml/request.js +0 -2
- package/dist/component/connection/saml/request.js.map +1 -1
- package/dist/component/connection/scim/config.d.ts +13 -13
- package/dist/component/connection/scim/config.d.ts.map +1 -1
- package/dist/component/connection/scim/config.js +2 -2
- package/dist/component/connection/scim/config.js.map +1 -1
- package/dist/component/connection/scim/identity.d.ts +122 -61
- package/dist/component/connection/scim/identity.d.ts.map +1 -1
- package/dist/component/connection/scim/identity.js +408 -60
- package/dist/component/connection/scim/identity.js.map +1 -1
- package/dist/component/connection/secret.d.ts +15 -15
- package/dist/component/connection/secret.d.ts.map +1 -1
- package/dist/component/connection/secret.js +2 -2
- package/dist/component/connection/secret.js.map +1 -1
- package/dist/component/connection/webhook/delivery.d.ts +69 -53
- package/dist/component/connection/webhook/delivery.d.ts.map +1 -1
- package/dist/component/connection/webhook/delivery.js +129 -172
- package/dist/component/connection/webhook/delivery.js.map +1 -1
- package/dist/component/connection/webhook/endpoint.d.ts +21 -21
- package/dist/component/connection/webhook/endpoint.d.ts.map +1 -1
- package/dist/component/connection/webhook/endpoint.js +2 -2
- package/dist/component/connection/webhook/endpoint.js.map +1 -1
- package/dist/component/connection/webhook/events.d.ts +26 -0
- package/dist/component/connection/webhook/events.d.ts.map +1 -0
- package/dist/component/connection/webhook/events.js +39 -0
- package/dist/component/connection/webhook/events.js.map +1 -0
- package/dist/component/connection.d.ts +39 -39
- package/dist/component/connection.d.ts.map +1 -1
- package/dist/component/connection.js +9 -9
- package/dist/component/connection.js.map +1 -1
- package/dist/component/context.d.ts +115 -0
- package/dist/component/context.d.ts.map +1 -0
- package/dist/component/context.js +49 -0
- package/dist/component/context.js.map +1 -0
- package/dist/component/convex.config.d.ts +2 -2
- package/dist/component/crons.d.ts +2 -2
- package/dist/component/documents.d.ts +1244 -0
- package/dist/component/documents.d.ts.map +1 -0
- package/dist/component/documents.js +44 -0
- package/dist/component/documents.js.map +1 -0
- package/dist/component/event.d.ts +142 -141
- package/dist/component/event.d.ts.map +1 -1
- package/dist/component/event.js +90 -119
- package/dist/component/event.js.map +1 -1
- package/dist/component/eventstream.d.ts +30 -0
- package/dist/component/eventstream.d.ts.map +1 -0
- package/dist/component/eventstream.js +60 -0
- package/dist/component/eventstream.js.map +1 -0
- package/dist/component/factor/device.d.ts +25 -24
- package/dist/component/factor/device.d.ts.map +1 -1
- package/dist/component/factor/device.js +7 -4
- package/dist/component/factor/device.js.map +1 -1
- package/dist/component/factor/passkey.d.ts +173 -85
- package/dist/component/factor/passkey.d.ts.map +1 -1
- package/dist/component/factor/passkey.js +138 -27
- package/dist/component/factor/passkey.js.map +1 -1
- package/dist/component/factor/totp.d.ts +56 -50
- package/dist/component/factor/totp.d.ts.map +1 -1
- package/dist/component/factor/totp.js +6 -5
- package/dist/component/factor/totp.js.map +1 -1
- package/dist/component/group/active.d.ts +326 -22
- package/dist/component/group/active.d.ts.map +1 -1
- package/dist/component/group/active.js +22 -13
- package/dist/component/group/active.js.map +1 -1
- package/dist/component/group/invite.d.ts +30 -30
- package/dist/component/group/invite.d.ts.map +1 -1
- package/dist/component/group/invite.js +2 -2
- package/dist/component/group/invite.js.map +1 -1
- package/dist/component/group/member.d.ts +36 -36
- package/dist/component/group/member.d.ts.map +1 -1
- package/dist/component/group/member.js +5 -3
- package/dist/component/group/member.js.map +1 -1
- package/dist/component/group.d.ts +49 -64
- package/dist/component/group.d.ts.map +1 -1
- package/dist/component/group.js +5 -3
- package/dist/component/group.js.map +1 -1
- package/dist/component/http.d.ts +2 -2
- package/dist/component/index.d.ts +0 -10
- package/dist/component/index.js +1 -3
- package/dist/component/limits.d.ts +5 -4
- package/dist/component/limits.d.ts.map +1 -1
- package/dist/component/limits.js +7 -4
- package/dist/component/limits.js.map +1 -1
- package/dist/component/maintenance.d.ts +6 -3
- package/dist/component/maintenance.d.ts.map +1 -1
- package/dist/component/maintenance.js +45 -6
- package/dist/component/maintenance.js.map +1 -1
- package/dist/component/model.d.ts +847 -1723
- package/dist/component/model.d.ts.map +1 -1
- package/dist/component/model.js +28 -317
- package/dist/component/model.js.map +1 -1
- package/dist/component/modules.d.ts +11 -5
- package/dist/component/modules.d.ts.map +1 -1
- package/dist/component/modules.js +4 -1
- package/dist/component/modules.js.map +1 -1
- package/dist/component/oauth/client.d.ts +20 -20
- package/dist/component/oauth/client.d.ts.map +1 -1
- package/dist/component/oauth/client.js +2 -2
- package/dist/component/oauth/client.js.map +1 -1
- package/dist/component/oauth/code.d.ts +14 -14
- package/dist/component/oauth/code.js +1 -2
- package/dist/component/oauth/code.js.map +1 -1
- package/dist/component/oauth/refresh.d.ts +20 -20
- package/dist/component/oauth/refresh.js +1 -2
- package/dist/component/oauth/refresh.js.map +1 -1
- package/dist/component/schema.d.ts +1148 -607
- package/dist/component/schema.d.ts.map +1 -1
- package/dist/component/schema.js +43 -15
- package/dist/component/schema.js.map +1 -1
- package/dist/component/session.d.ts +68 -32
- package/dist/component/session.d.ts.map +1 -1
- package/dist/component/session.js +118 -34
- package/dist/component/session.js.map +1 -1
- package/dist/component/token/continuation.d.ts +47 -18
- package/dist/component/token/continuation.d.ts.map +1 -1
- package/dist/component/token/continuation.js +76 -18
- package/dist/component/token/continuation.js.map +1 -1
- package/dist/component/token/enrollment.d.ts +42 -0
- package/dist/component/token/enrollment.d.ts.map +1 -0
- package/dist/component/token/enrollment.js +57 -0
- package/dist/component/token/enrollment.js.map +1 -0
- package/dist/component/token/pkce.d.ts +31 -24
- package/dist/component/token/pkce.d.ts.map +1 -1
- package/dist/component/token/pkce.js +15 -20
- package/dist/component/token/pkce.js.map +1 -1
- package/dist/component/token/refresh.d.ts +42 -35
- package/dist/component/token/refresh.d.ts.map +1 -1
- package/dist/component/token/refresh.js +16 -8
- package/dist/component/token/refresh.js.map +1 -1
- package/dist/component/token/verification.d.ts +34 -30
- package/dist/component/token/verification.d.ts.map +1 -1
- package/dist/component/token/verification.js +7 -6
- package/dist/component/token/verification.js.map +1 -1
- package/dist/component/user/email.d.ts +21 -21
- package/dist/component/user/email.d.ts.map +1 -1
- package/dist/component/user/email.js +2 -2
- package/dist/component/user/email.js.map +1 -1
- package/dist/component/user/key.d.ts +36 -36
- package/dist/component/user/key.d.ts.map +1 -1
- package/dist/component/user/key.js +2 -2
- package/dist/component/user/key.js.map +1 -1
- package/dist/component/user.d.ts +52 -48
- package/dist/component/user.d.ts.map +1 -1
- package/dist/component/user.js +157 -36
- package/dist/component/user.js.map +1 -1
- package/dist/expo/index.d.ts +4 -4
- package/dist/expo/index.d.ts.map +1 -1
- package/dist/expo/index.js +20 -13
- package/dist/expo/index.js.map +1 -1
- package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/export/ReadableLogRecord.d.ts +2 -2
- package/dist/node_modules/.pnpm/@opentelemetry_sdk-logs@0.214.0_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-logs/build/src/export/SdkLogRecord.d.ts +1 -1
- package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/MeterProvider.d.ts +2 -2
- package/dist/node_modules/.pnpm/@opentelemetry_sdk-metrics@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-metrics/build/src/export/MetricData.d.ts +1 -1
- package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/Span.d.ts +1 -1
- package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/export/ReadableSpan.d.ts +1 -1
- package/dist/node_modules/.pnpm/@opentelemetry_sdk-trace-base@2.6.1_@opentelemetry_api@1.9.1/node_modules/@opentelemetry/sdk-trace-base/build/src/types.d.ts +1 -1
- package/dist/otel.d.ts +1 -1
- package/dist/providers/anonymous.d.ts +11 -5
- package/dist/providers/anonymous.d.ts.map +1 -1
- package/dist/providers/anonymous.js +4 -1
- package/dist/providers/anonymous.js.map +1 -1
- package/dist/providers/apple.d.ts +1 -1
- package/dist/providers/apple.js +19 -4
- package/dist/providers/apple.js.map +1 -1
- package/dist/providers/credentials.d.ts +22 -14
- package/dist/providers/credentials.d.ts.map +1 -1
- package/dist/providers/credentials.js +2 -0
- package/dist/providers/credentials.js.map +1 -1
- package/dist/providers/custom.d.ts +3 -3
- package/dist/providers/custom.d.ts.map +1 -1
- package/dist/providers/custom.js.map +1 -1
- package/dist/providers/email.d.ts +3 -3
- package/dist/providers/email.d.ts.map +1 -1
- package/dist/providers/email.js.map +1 -1
- package/dist/providers/github.d.ts +1 -1
- package/dist/providers/github.d.ts.map +1 -1
- package/dist/providers/github.js +9 -4
- package/dist/providers/github.js.map +1 -1
- package/dist/providers/google.d.ts +1 -1
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/google.js +9 -4
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/microsoft.d.ts +1 -1
- package/dist/providers/microsoft.d.ts.map +1 -1
- package/dist/providers/microsoft.js +12 -4
- package/dist/providers/microsoft.js.map +1 -1
- package/dist/providers/password.d.ts +117 -15
- package/dist/providers/password.d.ts.map +1 -1
- package/dist/providers/password.js +71 -26
- package/dist/providers/password.js.map +1 -1
- package/dist/providers/phone.d.ts +4 -3
- package/dist/providers/phone.d.ts.map +1 -1
- package/dist/providers/phone.js.map +1 -1
- package/dist/providers/webauthn.d.ts.map +1 -1
- package/dist/providers/webauthn.js +6 -0
- package/dist/providers/webauthn.js.map +1 -1
- package/dist/react/index.d.ts +40 -41
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +27 -52
- package/dist/react/index.js.map +1 -1
- package/dist/server/auth.d.ts +224 -126
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +44 -25
- package/dist/server/auth.js.map +1 -1
- package/dist/server/component/factor/db.js +13 -6
- package/dist/server/component/factor/db.js.map +1 -1
- package/dist/server/config.d.ts +2 -1
- package/dist/server/connection/domain.d.ts +4 -65
- package/dist/server/connection/domain.d.ts.map +1 -1
- package/dist/server/connection/domain.js +29 -5
- package/dist/server/connection/domain.js.map +1 -1
- package/dist/server/connection/group/service.js +7 -5
- package/dist/server/connection/group/service.js.map +1 -1
- package/dist/server/connection/http.js +136 -291
- package/dist/server/connection/http.js.map +1 -1
- package/dist/server/connection/oidc.js +8 -17
- package/dist/server/connection/oidc.js.map +1 -1
- package/dist/server/connection/policy/domain.js +4 -1
- package/dist/server/connection/policy/domain.js.map +1 -1
- package/dist/server/connection/policy.js +14 -13
- package/dist/server/connection/policy.js.map +1 -1
- package/dist/server/connection/provision.js +5 -19
- package/dist/server/connection/provision.js.map +1 -1
- package/dist/server/connection/saml/encoding.js +2 -6
- package/dist/server/connection/saml/encoding.js.map +1 -1
- package/dist/server/connection/saml/signature.js +2 -2
- package/dist/server/connection/saml/signature.js.map +1 -1
- package/dist/server/connection/saml/xmldsig.js +1 -1
- package/dist/server/connection/saml/xmldsig.js.map +1 -1
- package/dist/server/connection/webhook.js +4 -36
- package/dist/server/connection/webhook.js.map +1 -1
- package/dist/server/context.d.ts +2 -2
- package/dist/server/context.d.ts.map +1 -1
- package/dist/server/context.js +35 -24
- package/dist/server/context.js.map +1 -1
- package/dist/server/contract.d.ts.map +1 -1
- package/dist/server/contract.js +6 -14
- package/dist/server/contract.js.map +1 -1
- package/dist/server/core.js +46 -1
- package/dist/server/core.js.map +1 -1
- package/dist/server/cors.d.ts +2 -2
- package/dist/server/cors.d.ts.map +1 -1
- package/dist/server/crypto.js.map +1 -1
- package/dist/server/db.js +6 -2
- package/dist/server/db.js.map +1 -1
- package/dist/server/device.js +1 -1
- package/dist/server/domains/account.d.ts +9 -1
- package/dist/server/domains/account.d.ts.map +1 -1
- package/dist/server/domains/account.js +21 -9
- package/dist/server/domains/account.js.map +1 -1
- package/dist/server/domains/context.js +34 -0
- package/dist/server/domains/context.js.map +1 -0
- package/dist/server/domains/factor.d.ts +3 -2
- package/dist/server/domains/factor.d.ts.map +1 -1
- package/dist/server/domains/factor.js.map +1 -1
- package/dist/server/domains/group.js.map +1 -1
- package/dist/server/domains/invite.js.map +1 -1
- package/dist/server/domains/key.js.map +1 -1
- package/dist/server/domains/member.js.map +1 -1
- package/dist/server/domains/session.js.map +1 -1
- package/dist/server/domains/user.js.map +1 -1
- package/dist/server/env.js +2 -22
- package/dist/server/env.js.map +1 -1
- package/dist/server/events.d.ts +3 -1
- package/dist/server/events.d.ts.map +1 -1
- package/dist/server/events.js +6 -6
- package/dist/server/events.js.map +1 -1
- package/dist/server/facade.d.ts +1 -33
- package/dist/server/facade.d.ts.map +1 -1
- package/dist/server/facade.js +1 -2
- package/dist/server/facade.js.map +1 -1
- package/dist/server/http.d.ts +1 -0
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +4 -4
- package/dist/server/http.js.map +1 -1
- package/dist/server/identity/claims.js +1 -1
- package/dist/server/identity/convex.d.ts +2 -0
- package/dist/server/identity/convex.d.ts.map +1 -1
- package/dist/server/index.d.ts +6 -9
- package/dist/server/index.js +2 -4
- package/dist/server/limits.js +23 -2
- package/dist/server/limits.js.map +1 -1
- package/dist/server/mutations/calls.js +3 -2
- package/dist/server/mutations/credentials/signin.js +7 -3
- package/dist/server/mutations/credentials/signin.js.map +1 -1
- package/dist/server/mutations/enrollment.js +87 -0
- package/dist/server/mutations/enrollment.js.map +1 -0
- package/dist/server/mutations/invalidate.js +5 -10
- package/dist/server/mutations/invalidate.js.map +1 -1
- package/dist/server/mutations/oauth.js +3 -3
- package/dist/server/mutations/oauth.js.map +1 -1
- package/dist/server/mutations/refresh.js +1 -0
- package/dist/server/mutations/refresh.js.map +1 -1
- package/dist/server/mutations/register.js +52 -21
- package/dist/server/mutations/register.js.map +1 -1
- package/dist/server/mutations/retrieve.js +4 -1
- package/dist/server/mutations/retrieve.js.map +1 -1
- package/dist/server/mutations/signin.js +2 -2
- package/dist/server/mutations/signin.js.map +1 -1
- package/dist/server/mutations/store.js +6 -1
- package/dist/server/mutations/store.js.map +1 -1
- package/dist/server/mutations/verify.js +6 -4
- package/dist/server/mutations/verify.js.map +1 -1
- package/dist/server/oauth/client.d.ts +1 -1
- package/dist/server/oauth/client.js.map +1 -1
- package/dist/server/oauth/code.d.ts +1 -1
- package/dist/server/oauth/code.js.map +1 -1
- package/dist/server/oauth/factory.js +89 -13
- package/dist/server/oauth/factory.js.map +1 -1
- package/dist/server/oauth/handlers.js +2 -2
- package/dist/server/oauth/runtime.js +24 -9
- package/dist/server/oauth/runtime.js.map +1 -1
- package/dist/server/preload.d.ts.map +1 -1
- package/dist/server/preload.js +14 -11
- package/dist/server/preload.js.map +1 -1
- package/dist/server/runtime.d.ts +236 -148
- package/dist/server/runtime.d.ts.map +1 -1
- package/dist/server/runtime.js +92 -44
- package/dist/server/runtime.js.map +1 -1
- package/dist/server/session/lifecycle.d.ts +2 -1
- package/dist/server/session/lifecycle.d.ts.map +1 -1
- package/dist/server/session/lifecycle.js +29 -10
- package/dist/server/session/lifecycle.js.map +1 -1
- package/dist/server/signin/flow.js +2 -2
- package/dist/server/signin/flow.js.map +1 -1
- package/dist/server/telemetry.js +1 -1
- package/dist/server/tokens.js +6 -3
- package/dist/server/tokens.js.map +1 -1
- package/dist/server/totp.js +4 -3
- package/dist/server/totp.js.map +1 -1
- package/dist/server/types.d.ts +131 -45
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/user/account.js +0 -1
- package/dist/server/user/account.js.map +1 -1
- package/dist/server/validators.d.ts +930 -944
- package/dist/server/validators.d.ts.map +1 -1
- package/dist/server/validators.js +66 -39
- package/dist/server/validators.js.map +1 -1
- package/dist/server/webauthn.js +60 -29
- package/dist/server/webauthn.js.map +1 -1
- package/dist/shared/brand.d.ts +3 -7
- package/dist/shared/brand.d.ts.map +1 -1
- package/dist/shared/params.d.ts +78 -0
- package/dist/shared/params.d.ts.map +1 -0
- package/dist/shared/results.d.ts +13 -1
- package/dist/shared/results.d.ts.map +1 -1
- package/dist/svelte/context.svelte.d.ts +23 -12
- package/dist/svelte/context.svelte.d.ts.map +1 -1
- package/dist/svelte/context.svelte.js +20 -13
- package/dist/svelte/index.d.ts +1 -4
- package/dist/svelte/index.d.ts.map +1 -1
- package/dist/svelte/index.js +1 -4
- package/dist/test.d.ts +1204 -611
- package/dist/test.d.ts.map +1 -1
- package/dist/test.js +50 -1
- package/dist/test.js.map +1 -1
- package/package.json +5 -14
- package/dist/_generated/component.d.ts +0 -3074
- package/dist/_generated/component.d.ts.map +0 -1
- package/dist/component/functions.d.ts +0 -9
- package/dist/component/functions.d.ts.map +0 -1
- package/dist/component/functions.js +0 -3
- package/dist/core/index.d.ts +0 -533
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -86
- package/dist/core/index.js.map +0 -1
- package/dist/model.js.map +0 -1
- package/dist/server/env.d.ts +0 -28
- package/dist/server/env.d.ts.map +0 -1
- package/dist/svelte/AuthLoading.svelte +0 -13
- package/dist/svelte/AuthLoading.svelte.d.ts +0 -8
- package/dist/svelte/AuthLoading.svelte.d.ts.map +0 -1
- package/dist/svelte/SignedIn.svelte +0 -14
- package/dist/svelte/SignedIn.svelte.d.ts +0 -8
- package/dist/svelte/SignedIn.svelte.d.ts.map +0 -1
- package/dist/svelte/SignedOut.svelte +0 -13
- package/dist/svelte/SignedOut.svelte.d.ts +0 -8
- package/dist/svelte/SignedOut.svelte.d.ts.map +0 -1
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { ErrorCode } from "../../../shared/codes.js";
|
|
2
|
-
import {
|
|
2
|
+
import { vPaginated, vScimResourceType } from "../../model.js";
|
|
3
3
|
import schema_default from "../../schema.js";
|
|
4
4
|
import { mutation, query } from "../../_generated/server.js";
|
|
5
|
-
import "../../
|
|
5
|
+
import { vGroupConnectionScimIdentityDoc } from "../../documents.js";
|
|
6
|
+
import { revokeSessionState } from "../../session.js";
|
|
7
|
+
import { assertBatchSelectorSize } from "../../batch.js";
|
|
6
8
|
import { ConvexError, v } from "convex/values";
|
|
7
9
|
import { paginationOptsValidator } from "convex/server";
|
|
8
10
|
import { paginator } from "convex-helpers/server/pagination";
|
|
@@ -17,11 +19,24 @@ import { paginator } from "convex-helpers/server/pagination";
|
|
|
17
19
|
*
|
|
18
20
|
* @module
|
|
19
21
|
*/
|
|
20
|
-
const vScimUserData =
|
|
22
|
+
const vScimUserData = schema_default.tables.User.validator.omit("sessionEpoch");
|
|
23
|
+
const vProfileUpdate = v.union(v.literal("never"), v.literal("missing"), v.literal("always"));
|
|
24
|
+
/** Maximum memberships changed by one SCIM group mutation. */
|
|
25
|
+
const SCIM_GROUP_MEMBERSHIP_BATCH_SIZE = 100;
|
|
26
|
+
const vScimMembershipProgress = v.object({
|
|
27
|
+
isDone: v.boolean(),
|
|
28
|
+
continueCursor: v.string()
|
|
29
|
+
});
|
|
30
|
+
function assertScimMembershipBatchSize(memberIds) {
|
|
31
|
+
if (memberIds.length > SCIM_GROUP_MEMBERSHIP_BATCH_SIZE) throw new ConvexError({
|
|
32
|
+
code: ErrorCode.INVALID_PARAMETERS,
|
|
33
|
+
message: `SCIM group membership batches are limited to ${SCIM_GROUP_MEMBERSHIP_BATCH_SIZE} members.`
|
|
34
|
+
});
|
|
35
|
+
}
|
|
21
36
|
/**
|
|
22
37
|
* Read SCIM identities, overloaded by the args supplied. With
|
|
23
38
|
* `{ connectionId, userIds }` it batch-resolves and returns an array aligned to
|
|
24
|
-
* the input order (`null` per missing user). Otherwise it resolves a single
|
|
39
|
+
* the input order (`null` per missing user; max 100 IDs). Otherwise it resolves a single
|
|
25
40
|
* identity by `(connectionId, resourceType, externalId)`, `(connectionId,
|
|
26
41
|
* userId)`, `userId`, or `mappedGroupId`. Returns `null` when nothing matches.
|
|
27
42
|
*/
|
|
@@ -38,6 +53,7 @@ const get = query({
|
|
|
38
53
|
handler: async (ctx, args) => {
|
|
39
54
|
if (args.connectionId !== void 0 && args.userIds !== void 0) {
|
|
40
55
|
const userIds = args.userIds;
|
|
56
|
+
assertBatchSelectorSize(userIds, "userIds");
|
|
41
57
|
if (userIds.length === 0) return [];
|
|
42
58
|
const unique = Array.from(new Set(userIds));
|
|
43
59
|
const docs = await Promise.all(unique.map((userId) => ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_user_id", (idx) => idx.eq("connectionId", args.connectionId).eq("userId", userId)).first()));
|
|
@@ -62,43 +78,29 @@ const list = query({
|
|
|
62
78
|
return await paginator(ctx.db, schema_default).query("GroupConnectionScimIdentity").withIndex("group_connection_id", (idx) => idx.eq("connectionId", connectionId)).paginate(paginationOpts);
|
|
63
79
|
}
|
|
64
80
|
});
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
},
|
|
78
|
-
returns: v.id("GroupConnectionScimIdentity"),
|
|
79
|
-
handler: async (ctx, args) => {
|
|
80
|
-
const existing = await ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_resource_type_external_id", (idx) => idx.eq("connectionId", args.connectionId).eq("resourceType", args.resourceType).eq("externalId", args.externalId)).first();
|
|
81
|
-
if (existing) {
|
|
82
|
-
await ctx.db.patch("GroupConnectionScimIdentity", existing._id, args);
|
|
83
|
-
return existing._id;
|
|
84
|
-
}
|
|
85
|
-
return await ctx.db.insert("GroupConnectionScimIdentity", args);
|
|
86
|
-
}
|
|
87
|
-
});
|
|
81
|
+
function providerForConnection(connection) {
|
|
82
|
+
if (connection.protocol === "oidc") return `oidc:${connection._id}`;
|
|
83
|
+
if (connection.protocol === "saml") return `saml:${connection._id}`;
|
|
84
|
+
throw new ConvexError({
|
|
85
|
+
code: ErrorCode.PROVIDER_NOT_CONFIGURED,
|
|
86
|
+
message: "SCIM requires an OIDC or SAML connection."
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function patchProfile(current, next, mode) {
|
|
90
|
+
if (mode === "never") return {};
|
|
91
|
+
return Object.fromEntries(Object.entries(next).filter(([key, value]) => value === void 0 ? false : mode === "always" || current[key] === void 0 || current[key] === null || current[key] === ""));
|
|
92
|
+
}
|
|
88
93
|
/**
|
|
89
|
-
* Atomically provision
|
|
90
|
-
*
|
|
91
|
-
* A concurrent retry cannot commit a losing User because the identity and
|
|
92
|
-
* Account index reads participate in the same OCC transaction as the inserts.
|
|
93
|
-
* Existing ownership is preserved; conflicting owners are rejected.
|
|
94
|
+
* Atomically provision a directory-managed user, account, SCIM identity, and
|
|
95
|
+
* membership. Group and provider ownership are derived from the connection.
|
|
94
96
|
*/
|
|
95
97
|
const provision = mutation({
|
|
96
98
|
args: {
|
|
97
99
|
connectionId: v.id("GroupConnection"),
|
|
98
|
-
|
|
99
|
-
externalId: v.string(),
|
|
100
|
-
provider: v.string(),
|
|
100
|
+
externalId: v.optional(v.string()),
|
|
101
101
|
userData: vScimUserData,
|
|
102
|
+
profileUpdate: vProfileUpdate,
|
|
103
|
+
roleIds: v.array(v.string()),
|
|
102
104
|
lastProvisionedAt: v.optional(v.number()),
|
|
103
105
|
active: v.optional(v.boolean()),
|
|
104
106
|
raw: v.optional(v.any())
|
|
@@ -108,56 +110,402 @@ const provision = mutation({
|
|
|
108
110
|
created: v.boolean()
|
|
109
111
|
}),
|
|
110
112
|
handler: async (ctx, args) => {
|
|
111
|
-
const
|
|
112
|
-
const
|
|
113
|
+
const connection = await activeScimConnection(ctx, args.connectionId);
|
|
114
|
+
const provider = providerForConnection(connection);
|
|
115
|
+
const externalId = args.externalId;
|
|
116
|
+
const identity = externalId === void 0 ? null : await ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_resource_type_external_id", (idx) => idx.eq("connectionId", args.connectionId).eq("resourceType", "user").eq("externalId", externalId)).unique();
|
|
117
|
+
const account = externalId === void 0 ? null : await ctx.db.query("Account").withIndex("provider_account_id", (idx) => idx.eq("provider", provider).eq("providerAccountId", externalId)).unique();
|
|
113
118
|
if (identity?.userId !== void 0 && account !== null && identity.userId !== account.userId) throw new ConvexError({
|
|
114
119
|
code: ErrorCode.ACCOUNT_ALREADY_LINKED,
|
|
115
|
-
message: "
|
|
120
|
+
message: "SCIM account ownership conflicts."
|
|
116
121
|
});
|
|
117
122
|
let userId = identity?.userId ?? account?.userId;
|
|
118
123
|
let created = false;
|
|
119
|
-
if (userId
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
124
|
+
if (userId === void 0) {
|
|
125
|
+
userId = await ctx.db.insert("User", {
|
|
126
|
+
...args.userData,
|
|
127
|
+
sessionEpoch: 0
|
|
123
128
|
});
|
|
124
|
-
} else {
|
|
125
|
-
userId = await ctx.db.insert("User", args.userData);
|
|
126
129
|
created = true;
|
|
130
|
+
} else {
|
|
131
|
+
const user = await ctx.db.get("User", userId);
|
|
132
|
+
if (user === null) throw new ConvexError({
|
|
133
|
+
code: ErrorCode.ACCOUNT_NOT_FOUND,
|
|
134
|
+
message: "SCIM user not found."
|
|
135
|
+
});
|
|
136
|
+
if (await ctx.db.query("GroupConnectionScimIdentity").withIndex("user_id", (idx) => idx.eq("userId", userId)).filter((query$1) => query$1.neq(query$1.field("connectionId"), args.connectionId)).first() !== null) throw new ConvexError({
|
|
137
|
+
code: ErrorCode.ACCOUNT_ALREADY_LINKED,
|
|
138
|
+
message: "User is managed by another SCIM connection."
|
|
139
|
+
});
|
|
140
|
+
const patch = patchProfile(user, args.userData, args.profileUpdate);
|
|
141
|
+
if (Object.keys(patch).length > 0) await ctx.db.patch("User", userId, patch);
|
|
127
142
|
}
|
|
128
|
-
if (account === null) await ctx.db.insert("Account", {
|
|
143
|
+
if (externalId !== void 0 && account === null) await ctx.db.insert("Account", {
|
|
129
144
|
userId,
|
|
130
|
-
provider
|
|
131
|
-
providerAccountId:
|
|
145
|
+
provider,
|
|
146
|
+
providerAccountId: externalId
|
|
132
147
|
});
|
|
133
148
|
const identityData = {
|
|
134
149
|
connectionId: args.connectionId,
|
|
135
|
-
groupId:
|
|
150
|
+
groupId: connection.groupId,
|
|
136
151
|
resourceType: "user",
|
|
137
|
-
externalId:
|
|
138
|
-
userId
|
|
152
|
+
...externalId === void 0 ? {} : { externalId },
|
|
153
|
+
userId,
|
|
154
|
+
active: args.active !== false,
|
|
155
|
+
...args.lastProvisionedAt === void 0 ? {} : { lastProvisionedAt: args.lastProvisionedAt },
|
|
156
|
+
...args.raw === void 0 ? {} : { raw: args.raw }
|
|
139
157
|
};
|
|
140
|
-
if (args.lastProvisionedAt !== void 0) identityData.lastProvisionedAt = args.lastProvisionedAt;
|
|
141
|
-
if (args.active !== void 0) identityData.active = args.active;
|
|
142
|
-
if (args.raw !== void 0) identityData.raw = args.raw;
|
|
143
158
|
if (identity === null) await ctx.db.insert("GroupConnectionScimIdentity", identityData);
|
|
144
|
-
else
|
|
159
|
+
else {
|
|
160
|
+
if (identity.groupId !== connection.groupId) throw new ConvexError({
|
|
161
|
+
code: ErrorCode.INVALID_PARAMETERS,
|
|
162
|
+
message: "SCIM identity group mismatch."
|
|
163
|
+
});
|
|
164
|
+
await ctx.db.patch("GroupConnectionScimIdentity", identity._id, identityData);
|
|
165
|
+
}
|
|
166
|
+
const membership = await ctx.db.query("GroupMember").withIndex("group_id_user_id", (idx) => idx.eq("groupId", connection.groupId).eq("userId", userId)).unique();
|
|
167
|
+
const membershipPatch = {
|
|
168
|
+
roleIds: args.roleIds,
|
|
169
|
+
status: args.active === false ? "inactive" : "active"
|
|
170
|
+
};
|
|
171
|
+
if (membership === null) await ctx.db.insert("GroupMember", {
|
|
172
|
+
groupId: connection.groupId,
|
|
173
|
+
userId,
|
|
174
|
+
...membershipPatch
|
|
175
|
+
});
|
|
176
|
+
else await ctx.db.patch("GroupMember", membership._id, membershipPatch);
|
|
145
177
|
return {
|
|
146
178
|
userId,
|
|
147
179
|
created
|
|
148
180
|
};
|
|
149
181
|
}
|
|
150
182
|
});
|
|
151
|
-
/**
|
|
152
|
-
const
|
|
153
|
-
args: {
|
|
183
|
+
/** Atomically update a directory-managed user and its connection membership. */
|
|
184
|
+
const update = mutation({
|
|
185
|
+
args: {
|
|
186
|
+
connectionId: v.id("GroupConnection"),
|
|
187
|
+
userId: v.id("User"),
|
|
188
|
+
externalId: v.optional(v.string()),
|
|
189
|
+
userData: vScimUserData,
|
|
190
|
+
profileUpdate: vProfileUpdate,
|
|
191
|
+
roleIds: v.array(v.string()),
|
|
192
|
+
active: v.boolean(),
|
|
193
|
+
lastProvisionedAt: v.optional(v.number()),
|
|
194
|
+
raw: v.optional(v.any())
|
|
195
|
+
},
|
|
154
196
|
returns: v.null(),
|
|
155
|
-
handler: async (ctx,
|
|
156
|
-
await ctx
|
|
197
|
+
handler: async (ctx, args) => {
|
|
198
|
+
const connection = await activeScimConnection(ctx, args.connectionId);
|
|
199
|
+
const externalId = args.externalId;
|
|
200
|
+
const identity = await ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_user_id", (idx) => idx.eq("connectionId", args.connectionId).eq("userId", args.userId)).unique();
|
|
201
|
+
if (identity === null || identity.resourceType !== "user" || identity.groupId !== connection.groupId) throw new ConvexError({
|
|
202
|
+
code: ErrorCode.ACCOUNT_NOT_FOUND,
|
|
203
|
+
message: "SCIM user not found."
|
|
204
|
+
});
|
|
205
|
+
if (await ctx.db.query("GroupConnectionScimIdentity").withIndex("user_id", (idx) => idx.eq("userId", args.userId)).filter((query$1) => query$1.neq(query$1.field("connectionId"), args.connectionId)).first() !== null) throw new ConvexError({
|
|
206
|
+
code: ErrorCode.ACCOUNT_ALREADY_LINKED,
|
|
207
|
+
message: "User is managed by another SCIM connection."
|
|
208
|
+
});
|
|
209
|
+
const conflicting = externalId === void 0 ? null : await ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_resource_type_external_id", (idx) => idx.eq("connectionId", args.connectionId).eq("resourceType", "user").eq("externalId", externalId)).unique();
|
|
210
|
+
if (conflicting !== null && conflicting._id !== identity._id) throw new ConvexError({
|
|
211
|
+
code: ErrorCode.ACCOUNT_ALREADY_LINKED,
|
|
212
|
+
message: "SCIM external id is already linked."
|
|
213
|
+
});
|
|
214
|
+
const user = await ctx.db.get("User", args.userId);
|
|
215
|
+
if (user === null) throw new ConvexError({
|
|
216
|
+
code: ErrorCode.ACCOUNT_NOT_FOUND,
|
|
217
|
+
message: "User not found."
|
|
218
|
+
});
|
|
219
|
+
const provider = providerForConnection(connection);
|
|
220
|
+
const currentExternalId = identity.externalId;
|
|
221
|
+
const [currentAccount, nextAccount] = await Promise.all([currentExternalId === void 0 ? Promise.resolve(null) : ctx.db.query("Account").withIndex("provider_account_id", (idx) => idx.eq("provider", provider).eq("providerAccountId", currentExternalId)).unique(), externalId === void 0 || currentExternalId === externalId ? Promise.resolve(null) : ctx.db.query("Account").withIndex("provider_account_id", (idx) => idx.eq("provider", provider).eq("providerAccountId", externalId)).unique()]);
|
|
222
|
+
if (nextAccount !== null && nextAccount.userId !== args.userId) throw new ConvexError({
|
|
223
|
+
code: ErrorCode.ACCOUNT_ALREADY_LINKED,
|
|
224
|
+
message: "The replacement SCIM external id is already linked."
|
|
225
|
+
});
|
|
226
|
+
if (currentAccount !== null && currentAccount.userId !== args.userId) throw new ConvexError({
|
|
227
|
+
code: ErrorCode.ACCOUNT_ALREADY_LINKED,
|
|
228
|
+
message: "The SCIM account belongs to another user."
|
|
229
|
+
});
|
|
230
|
+
const patch = patchProfile(user, args.userData, args.profileUpdate);
|
|
231
|
+
if (Object.keys(patch).length > 0) await ctx.db.patch("User", args.userId, patch);
|
|
232
|
+
if (currentExternalId === externalId) {
|
|
233
|
+
if (externalId !== void 0 && currentAccount === null) await ctx.db.insert("Account", {
|
|
234
|
+
userId: args.userId,
|
|
235
|
+
provider,
|
|
236
|
+
providerAccountId: externalId
|
|
237
|
+
});
|
|
238
|
+
} else if (currentAccount !== null) if (externalId === void 0) await ctx.db.delete("Account", currentAccount._id);
|
|
239
|
+
else if (nextAccount === null) await ctx.db.patch("Account", currentAccount._id, { providerAccountId: externalId });
|
|
240
|
+
else await ctx.db.delete("Account", currentAccount._id);
|
|
241
|
+
else if (externalId !== void 0 && nextAccount === null) await ctx.db.insert("Account", {
|
|
242
|
+
userId: args.userId,
|
|
243
|
+
provider,
|
|
244
|
+
providerAccountId: externalId
|
|
245
|
+
});
|
|
246
|
+
await ctx.db.patch("GroupConnectionScimIdentity", identity._id, {
|
|
247
|
+
externalId,
|
|
248
|
+
active: args.active,
|
|
249
|
+
lastProvisionedAt: args.lastProvisionedAt,
|
|
250
|
+
raw: args.raw
|
|
251
|
+
});
|
|
252
|
+
const membership = await ctx.db.query("GroupMember").withIndex("group_id_user_id", (idx) => idx.eq("groupId", connection.groupId).eq("userId", args.userId)).unique();
|
|
253
|
+
const membershipPatch = {
|
|
254
|
+
roleIds: args.roleIds,
|
|
255
|
+
status: args.active ? "active" : "inactive"
|
|
256
|
+
};
|
|
257
|
+
if (membership === null) await ctx.db.insert("GroupMember", {
|
|
258
|
+
groupId: connection.groupId,
|
|
259
|
+
userId: args.userId,
|
|
260
|
+
...membershipPatch
|
|
261
|
+
});
|
|
262
|
+
else await ctx.db.patch("GroupMember", membership._id, membershipPatch);
|
|
157
263
|
return null;
|
|
158
264
|
}
|
|
159
265
|
});
|
|
266
|
+
/** Atomically revoke a directory-managed user's membership, sessions, and identity. */
|
|
267
|
+
const revoke = mutation({
|
|
268
|
+
args: {
|
|
269
|
+
connectionId: v.id("GroupConnection"),
|
|
270
|
+
userId: v.id("User"),
|
|
271
|
+
mode: v.union(v.literal("soft"), v.literal("hard"))
|
|
272
|
+
},
|
|
273
|
+
returns: v.object({
|
|
274
|
+
epoch: v.number(),
|
|
275
|
+
cleanedSessions: v.number(),
|
|
276
|
+
cleanupPending: v.boolean()
|
|
277
|
+
}),
|
|
278
|
+
handler: async (ctx, args) => {
|
|
279
|
+
const connection = await activeScimConnection(ctx, args.connectionId);
|
|
280
|
+
const identity = await ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_user_id", (idx) => idx.eq("connectionId", args.connectionId).eq("userId", args.userId)).unique();
|
|
281
|
+
if (identity === null || identity.resourceType !== "user" || identity.groupId !== connection.groupId) throw new ConvexError({
|
|
282
|
+
code: ErrorCode.ACCOUNT_NOT_FOUND,
|
|
283
|
+
message: "SCIM user not found."
|
|
284
|
+
});
|
|
285
|
+
if (await ctx.db.query("GroupConnectionScimIdentity").withIndex("user_id", (idx) => idx.eq("userId", args.userId)).filter((query$1) => query$1.neq(query$1.field("connectionId"), args.connectionId)).first() !== null) throw new ConvexError({
|
|
286
|
+
code: ErrorCode.ACCOUNT_ALREADY_LINKED,
|
|
287
|
+
message: "User is managed by another SCIM connection."
|
|
288
|
+
});
|
|
289
|
+
const provider = providerForConnection(connection);
|
|
290
|
+
const externalId = identity.externalId;
|
|
291
|
+
const account = externalId === void 0 ? null : await ctx.db.query("Account").withIndex("provider_account_id", (idx) => idx.eq("provider", provider).eq("providerAccountId", externalId)).unique();
|
|
292
|
+
if (account !== null && account.userId !== args.userId) throw new ConvexError({
|
|
293
|
+
code: ErrorCode.ACCOUNT_ALREADY_LINKED,
|
|
294
|
+
message: "The SCIM account belongs to another user."
|
|
295
|
+
});
|
|
296
|
+
const membership = await ctx.db.query("GroupMember").withIndex("group_id_user_id", (idx) => idx.eq("groupId", connection.groupId).eq("userId", args.userId)).unique();
|
|
297
|
+
if (membership !== null) await ctx.db.delete("GroupMember", membership._id);
|
|
298
|
+
if (account !== null) await ctx.db.delete("Account", account._id);
|
|
299
|
+
const { epoch, cleanedSessions, cleanupPending } = await revokeSessionState(ctx, args.userId);
|
|
300
|
+
if (args.mode === "hard") await ctx.db.delete("GroupConnectionScimIdentity", identity._id);
|
|
301
|
+
else await ctx.db.patch("GroupConnectionScimIdentity", identity._id, {
|
|
302
|
+
active: false,
|
|
303
|
+
lastProvisionedAt: Date.now()
|
|
304
|
+
});
|
|
305
|
+
return {
|
|
306
|
+
epoch,
|
|
307
|
+
cleanedSessions,
|
|
308
|
+
cleanupPending
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
async function activeScimConnection(ctx, connectionId) {
|
|
313
|
+
const connection = await ctx.db.get("GroupConnection", connectionId);
|
|
314
|
+
const scim = connection === null ? null : await ctx.db.query("GroupConnectionScimConfig").withIndex("group_connection_id", (idx) => idx.eq("connectionId", connectionId)).unique();
|
|
315
|
+
if (connection === null || connection.status !== "active" || scim === null || scim.status !== "active" || scim.groupId !== connection.groupId) throw new ConvexError({
|
|
316
|
+
code: ErrorCode.INVALID_PARAMETERS,
|
|
317
|
+
message: "SCIM connection is not active."
|
|
318
|
+
});
|
|
319
|
+
return connection;
|
|
320
|
+
}
|
|
321
|
+
async function assertScimMembers(ctx, connection, userIds) {
|
|
322
|
+
for (const userId of new Set(userIds)) {
|
|
323
|
+
const [user, identity, membership] = await Promise.all([
|
|
324
|
+
ctx.db.get("User", userId),
|
|
325
|
+
ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_user_id", (idx) => idx.eq("connectionId", connection._id).eq("userId", userId)).first(),
|
|
326
|
+
ctx.db.query("GroupMember").withIndex("group_id_user_id", (idx) => idx.eq("groupId", connection.groupId).eq("userId", userId)).first()
|
|
327
|
+
]);
|
|
328
|
+
if (user === null || identity === null && membership === null) throw new ConvexError({
|
|
329
|
+
code: ErrorCode.ACCOUNT_NOT_FOUND,
|
|
330
|
+
message: "A SCIM group member is not available through this connection."
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
async function replaceScimGroupMembers(ctx, groupId, memberIds, roleIds, cursor) {
|
|
335
|
+
assertScimMembershipBatchSize(memberIds);
|
|
336
|
+
const wanted = new Set(memberIds);
|
|
337
|
+
const patch = {
|
|
338
|
+
roleIds,
|
|
339
|
+
status: "active"
|
|
340
|
+
};
|
|
341
|
+
for (const userId of wanted) {
|
|
342
|
+
const member = await ctx.db.query("GroupMember").withIndex("group_id_user_id", (idx) => idx.eq("groupId", groupId).eq("userId", userId)).unique();
|
|
343
|
+
if (member === null) await ctx.db.insert("GroupMember", {
|
|
344
|
+
groupId,
|
|
345
|
+
userId,
|
|
346
|
+
...patch
|
|
347
|
+
});
|
|
348
|
+
else await ctx.db.patch("GroupMember", member._id, patch);
|
|
349
|
+
}
|
|
350
|
+
const current = await paginator(ctx.db, schema_default).query("GroupMember").withIndex("group_id", (idx) => idx.eq("groupId", groupId)).paginate({
|
|
351
|
+
numItems: SCIM_GROUP_MEMBERSHIP_BATCH_SIZE,
|
|
352
|
+
cursor: cursor ?? null
|
|
353
|
+
});
|
|
354
|
+
for (const member of current.page) if (!wanted.has(member.userId)) await ctx.db.delete("GroupMember", member._id);
|
|
355
|
+
return {
|
|
356
|
+
isDone: current.isDone,
|
|
357
|
+
continueCursor: current.continueCursor
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Provision a SCIM group and one bounded page of its authoritative membership.
|
|
362
|
+
* Repeat with `continueCursor` until `isDone` is true.
|
|
363
|
+
*/
|
|
364
|
+
const provisionGroup = mutation({
|
|
365
|
+
args: {
|
|
366
|
+
connectionId: v.id("GroupConnection"),
|
|
367
|
+
externalId: v.optional(v.string()),
|
|
368
|
+
name: v.string(),
|
|
369
|
+
memberIds: v.array(v.id("User")),
|
|
370
|
+
roleIds: v.array(v.string()),
|
|
371
|
+
raw: v.optional(v.any()),
|
|
372
|
+
cursor: v.optional(v.string())
|
|
373
|
+
},
|
|
374
|
+
returns: v.object({
|
|
375
|
+
groupId: v.id("Group"),
|
|
376
|
+
created: v.boolean(),
|
|
377
|
+
...vScimMembershipProgress.fields
|
|
378
|
+
}),
|
|
379
|
+
handler: async (ctx, args) => {
|
|
380
|
+
const connection = await activeScimConnection(ctx, args.connectionId);
|
|
381
|
+
const externalId = args.externalId;
|
|
382
|
+
assertScimMembershipBatchSize(args.memberIds);
|
|
383
|
+
await assertScimMembers(ctx, connection, args.memberIds);
|
|
384
|
+
const identity = externalId === void 0 ? null : await ctx.db.query("GroupConnectionScimIdentity").withIndex("group_connection_id_resource_type_external_id", (idx) => idx.eq("connectionId", args.connectionId).eq("resourceType", "group").eq("externalId", externalId)).unique();
|
|
385
|
+
if (identity !== null && identity.groupId !== connection.groupId) throw new ConvexError({
|
|
386
|
+
code: ErrorCode.INVALID_PARAMETERS,
|
|
387
|
+
message: "SCIM identity group mismatch."
|
|
388
|
+
});
|
|
389
|
+
let groupId = identity?.mappedGroupId;
|
|
390
|
+
let created = false;
|
|
391
|
+
if (groupId === void 0) {
|
|
392
|
+
const parent = await ctx.db.get("Group", connection.groupId);
|
|
393
|
+
if (parent === null) throw new ConvexError({
|
|
394
|
+
code: ErrorCode.INVALID_PARAMETERS,
|
|
395
|
+
message: "Connection group not found."
|
|
396
|
+
});
|
|
397
|
+
groupId = await ctx.db.insert("Group", {
|
|
398
|
+
name: args.name,
|
|
399
|
+
type: "organization",
|
|
400
|
+
parentGroupId: connection.groupId,
|
|
401
|
+
rootGroupId: parent.rootGroupId ?? parent._id,
|
|
402
|
+
isRoot: false
|
|
403
|
+
});
|
|
404
|
+
created = true;
|
|
405
|
+
} else {
|
|
406
|
+
const group = await ctx.db.get("Group", groupId);
|
|
407
|
+
if (group === null || group.parentGroupId !== connection.groupId) throw new ConvexError({
|
|
408
|
+
code: ErrorCode.INVALID_PARAMETERS,
|
|
409
|
+
message: "SCIM group ownership mismatch."
|
|
410
|
+
});
|
|
411
|
+
await ctx.db.patch("Group", groupId, { name: args.name });
|
|
412
|
+
}
|
|
413
|
+
const identityData = {
|
|
414
|
+
connectionId: args.connectionId,
|
|
415
|
+
groupId: connection.groupId,
|
|
416
|
+
resourceType: "group",
|
|
417
|
+
...externalId === void 0 ? {} : { externalId },
|
|
418
|
+
mappedGroupId: groupId,
|
|
419
|
+
active: true,
|
|
420
|
+
lastProvisionedAt: Date.now(),
|
|
421
|
+
...args.raw === void 0 ? {} : { raw: args.raw }
|
|
422
|
+
};
|
|
423
|
+
if (identity === null) await ctx.db.insert("GroupConnectionScimIdentity", identityData);
|
|
424
|
+
else await ctx.db.patch("GroupConnectionScimIdentity", identity._id, identityData);
|
|
425
|
+
return {
|
|
426
|
+
groupId,
|
|
427
|
+
created,
|
|
428
|
+
...await replaceScimGroupMembers(ctx, groupId, args.memberIds, args.roleIds, args.cursor)
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
/**
|
|
433
|
+
* Update a SCIM group and one bounded page of its authoritative membership.
|
|
434
|
+
* Repeat with `continueCursor` until `isDone` is true.
|
|
435
|
+
*/
|
|
436
|
+
const updateGroup = mutation({
|
|
437
|
+
args: {
|
|
438
|
+
connectionId: v.id("GroupConnection"),
|
|
439
|
+
groupId: v.id("Group"),
|
|
440
|
+
name: v.optional(v.string()),
|
|
441
|
+
memberIds: v.array(v.id("User")),
|
|
442
|
+
roleIds: v.array(v.string()),
|
|
443
|
+
raw: v.optional(v.any()),
|
|
444
|
+
cursor: v.optional(v.string())
|
|
445
|
+
},
|
|
446
|
+
returns: vScimMembershipProgress,
|
|
447
|
+
handler: async (ctx, args) => {
|
|
448
|
+
const connection = await activeScimConnection(ctx, args.connectionId);
|
|
449
|
+
assertScimMembershipBatchSize(args.memberIds);
|
|
450
|
+
const identity = await ctx.db.query("GroupConnectionScimIdentity").withIndex("mapped_group_id", (idx) => idx.eq("mappedGroupId", args.groupId)).unique();
|
|
451
|
+
if (identity === null || identity.connectionId !== args.connectionId || identity.groupId !== connection.groupId || identity.resourceType !== "group") throw new ConvexError({
|
|
452
|
+
code: ErrorCode.ACCOUNT_NOT_FOUND,
|
|
453
|
+
message: "SCIM group not found."
|
|
454
|
+
});
|
|
455
|
+
const group = await ctx.db.get("Group", args.groupId);
|
|
456
|
+
if (group === null || group.parentGroupId !== connection.groupId) throw new ConvexError({
|
|
457
|
+
code: ErrorCode.INVALID_PARAMETERS,
|
|
458
|
+
message: "SCIM group ownership mismatch."
|
|
459
|
+
});
|
|
460
|
+
await assertScimMembers(ctx, connection, args.memberIds);
|
|
461
|
+
if (args.name !== void 0) await ctx.db.patch("Group", args.groupId, { name: args.name });
|
|
462
|
+
await ctx.db.patch("GroupConnectionScimIdentity", identity._id, {
|
|
463
|
+
active: true,
|
|
464
|
+
lastProvisionedAt: Date.now(),
|
|
465
|
+
...args.raw === void 0 ? {} : { raw: args.raw }
|
|
466
|
+
});
|
|
467
|
+
return await replaceScimGroupMembers(ctx, args.groupId, args.memberIds, args.roleIds, args.cursor);
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
/**
|
|
471
|
+
* Revoke a SCIM group in bounded membership pages. The identity and group are
|
|
472
|
+
* removed only when the final page returns `isDone`.
|
|
473
|
+
*/
|
|
474
|
+
const revokeGroup = mutation({
|
|
475
|
+
args: {
|
|
476
|
+
connectionId: v.id("GroupConnection"),
|
|
477
|
+
groupId: v.id("Group"),
|
|
478
|
+
cursor: v.optional(v.string())
|
|
479
|
+
},
|
|
480
|
+
returns: vScimMembershipProgress,
|
|
481
|
+
handler: async (ctx, args) => {
|
|
482
|
+
const connection = await activeScimConnection(ctx, args.connectionId);
|
|
483
|
+
const identity = await ctx.db.query("GroupConnectionScimIdentity").withIndex("mapped_group_id", (idx) => idx.eq("mappedGroupId", args.groupId)).unique();
|
|
484
|
+
if (identity === null || identity.connectionId !== args.connectionId || identity.groupId !== connection.groupId || identity.resourceType !== "group") throw new ConvexError({
|
|
485
|
+
code: ErrorCode.ACCOUNT_NOT_FOUND,
|
|
486
|
+
message: "SCIM group not found."
|
|
487
|
+
});
|
|
488
|
+
const group = await ctx.db.get("Group", args.groupId);
|
|
489
|
+
if (group === null || group.parentGroupId !== identity.groupId) throw new ConvexError({
|
|
490
|
+
code: ErrorCode.INVALID_PARAMETERS,
|
|
491
|
+
message: "SCIM group ownership mismatch."
|
|
492
|
+
});
|
|
493
|
+
const members = await paginator(ctx.db, schema_default).query("GroupMember").withIndex("group_id", (idx) => idx.eq("groupId", args.groupId)).paginate({
|
|
494
|
+
numItems: SCIM_GROUP_MEMBERSHIP_BATCH_SIZE,
|
|
495
|
+
cursor: args.cursor ?? null
|
|
496
|
+
});
|
|
497
|
+
for (const member of members.page) await ctx.db.delete("GroupMember", member._id);
|
|
498
|
+
if (members.isDone) {
|
|
499
|
+
await ctx.db.delete("GroupConnectionScimIdentity", identity._id);
|
|
500
|
+
await ctx.db.delete("Group", args.groupId);
|
|
501
|
+
}
|
|
502
|
+
return {
|
|
503
|
+
isDone: members.isDone,
|
|
504
|
+
continueCursor: members.continueCursor
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
});
|
|
160
508
|
|
|
161
509
|
//#endregion
|
|
162
|
-
export { get, list, provision,
|
|
510
|
+
export { get, list, provision, provisionGroup, revoke, revokeGroup, update, updateGroup };
|
|
163
511
|
//# sourceMappingURL=identity.js.map
|