diff --git a/.changeset/forty-kings-roll.md b/.changeset/forty-kings-roll.md new file mode 100644 index 00000000000..6a8a0517efb --- /dev/null +++ b/.changeset/forty-kings-roll.md @@ -0,0 +1,5 @@ +--- +"@clerk/elements": patch +--- + +Refactors sign-up loading logic to be in-line with sign-in diff --git a/.changeset/tricky-hotels-smell.md b/.changeset/tricky-hotels-smell.md new file mode 100644 index 00000000000..781090341c8 --- /dev/null +++ b/.changeset/tricky-hotels-smell.md @@ -0,0 +1,5 @@ +--- +"@clerk/elements": patch +--- + +Fixes persistent loading states within the `forgot-password` step diff --git a/packages/elements/src/internals/machines/sign-in/router.machine.ts b/packages/elements/src/internals/machines/sign-in/router.machine.ts index 89226f70567..32e53ca8f2a 100644 --- a/packages/elements/src/internals/machines/sign-in/router.machine.ts +++ b/packages/elements/src/internals/machines/sign-in/router.machine.ts @@ -309,7 +309,7 @@ export const SignInRouterMachine = setup({ ], }, Start: { - tags: 'route:start', + tags: ['step:start'], exit: 'clearFormErrors', invoke: { id: 'start', @@ -358,7 +358,7 @@ export const SignInRouterMachine = setup({ }, }, FirstFactor: { - tags: 'route:first-factor', + tags: ['step:first-factor', 'step:verifications'], invoke: { id: 'firstFactor', src: 'firstFactorMachine', @@ -414,7 +414,7 @@ export const SignInRouterMachine = setup({ }, }, ChoosingStrategy: { - tags: ['route:choose-strategy'], + tags: ['step:choose-strategy'], on: { 'NAVIGATE.PREVIOUS': { description: 'Go to Idle, and also tell firstFactor to go to Pending', @@ -424,7 +424,7 @@ export const SignInRouterMachine = setup({ }, }, ForgotPassword: { - tags: ['route:forgot-password'], + tags: ['step:forgot-password'], on: { 'NAVIGATE.PREVIOUS': 'Idle', }, @@ -432,7 +432,7 @@ export const SignInRouterMachine = setup({ }, }, SecondFactor: { - tags: 'route:second-factor', + tags: ['step:second-factor', 'step:verifications'], invoke: { id: 'secondFactor', src: 'secondFactorMachine', @@ -478,7 +478,7 @@ export const SignInRouterMachine = setup({ }, }, ChoosingStrategy: { - tags: ['route:choose-strategy'], + tags: ['step:choose-strategy'], on: { 'NAVIGATE.PREVIOUS': { description: 'Go to Idle, and also tell firstFactor to go to Pending', @@ -490,7 +490,7 @@ export const SignInRouterMachine = setup({ }, }, ResetPassword: { - tags: 'route:reset-password', + tags: ['step:reset-password'], invoke: { id: 'resetPassword', src: 'resetPasswordMachine', @@ -526,7 +526,7 @@ export const SignInRouterMachine = setup({ }, }, Callback: { - tags: 'route:callback', + tags: ['step:callback'], entry: sendTo(ThirdPartyMachineId, { type: 'CALLBACK' }), on: { NEXT: [ @@ -562,7 +562,7 @@ export const SignInRouterMachine = setup({ }, }, Error: { - tags: 'route:error', + tags: ['step:error'], on: { NEXT: { target: 'Start', diff --git a/packages/elements/src/internals/machines/sign-in/router.types.ts b/packages/elements/src/internals/machines/sign-in/router.types.ts index 2f2b277a79a..9d1b5e333f4 100644 --- a/packages/elements/src/internals/machines/sign-in/router.types.ts +++ b/packages/elements/src/internals/machines/sign-in/router.types.ts @@ -22,19 +22,20 @@ import type { SignInVerificationFactorUpdateEvent } from './verification.types'; // ---------------------------------- Tags ---------------------------------- // -export const SignInRouterRoutes = { - start: 'route:start', - firstFactor: 'route:first-factor', - secondFactor: 'route:second-factor', - callback: 'route:callback', - error: 'route:error', - forgotPassword: 'route:forgot-password', - resetPassword: 'route:reset-password', - chooseStrategy: 'route:choose-strategy', +export const SignInRouterSteps = { + start: 'step:start', + verifications: 'step:verifications', + firstFactor: 'step:first-factor', + secondFactor: 'step:second-factor', + callback: 'step:callback', + error: 'step:error', + forgotPassword: 'step:forgot-password', + resetPassword: 'step:reset-password', + chooseStrategy: 'step:choose-strategy', } as const; -export type SignInRouterRoutes = keyof typeof SignInRouterRoutes; -export type SignInRouterTags = (typeof SignInRouterRoutes)[keyof typeof SignInRouterRoutes]; +export type SignInRouterSteps = keyof typeof SignInRouterSteps; +export type SignInRouterTags = (typeof SignInRouterSteps)[keyof typeof SignInRouterSteps]; // ---------------------------------- Children ---------------------------------- // @@ -60,7 +61,9 @@ export type SignInRouterTransferEvent = BaseRouterTransferEvent; export type SignInRouterRedirectEvent = BaseRouterRedirectEvent; export type SignInRouterResetEvent = BaseRouterResetEvent; export type SignInRouterResetStepEvent = BaseRouterResetStepEvent; -export type SignInRouterLoadingEvent = BaseRouterLoadingEvent<'start' | 'verifications' | 'reset-password'>; +export type SignInRouterLoadingEvent = BaseRouterLoadingEvent< + 'start' | 'verifications' | 'reset-password' | 'forgot-password' | 'choose-strategy' +>; export type SignInRouterSetClerkEvent = BaseRouterSetClerkEvent; export type SignInRouterSubmitEvent = { type: 'SUBMIT' }; export type SignInRouterPasskeyEvent = { type: 'AUTHENTICATE.PASSKEY' }; diff --git a/packages/elements/src/internals/machines/sign-up/router.machine.ts b/packages/elements/src/internals/machines/sign-up/router.machine.ts index 7fa4ec7ad6b..4bc353e5345 100644 --- a/packages/elements/src/internals/machines/sign-up/router.machine.ts +++ b/packages/elements/src/internals/machines/sign-up/router.machine.ts @@ -284,7 +284,7 @@ export const SignUpRouterMachine = setup({ ], }, Start: { - tags: 'route:start', + tags: ['step:start'], exit: 'clearFormErrors', invoke: { id: 'start', @@ -322,7 +322,7 @@ export const SignUpRouterMachine = setup({ }, }, Continue: { - tags: 'route:continue', + tags: ['step:continue'], invoke: { id: 'continue', src: 'continueMachine', @@ -354,7 +354,7 @@ export const SignUpRouterMachine = setup({ }, }, Verification: { - tags: 'route:verification', + tags: ['step:verification'], invoke: { id: 'verification', src: 'verificationMachine', @@ -406,7 +406,7 @@ export const SignUpRouterMachine = setup({ }, }, Callback: { - tags: 'route:callback', + tags: ['step:callback'], entry: sendTo(ThirdPartyMachineId, { type: 'CALLBACK' }), on: { NEXT: [ @@ -437,7 +437,7 @@ export const SignUpRouterMachine = setup({ }, }, Error: { - tags: 'route:error', + tags: ['step:error'], on: { NEXT: { target: 'Start', diff --git a/packages/elements/src/internals/machines/sign-up/router.types.ts b/packages/elements/src/internals/machines/sign-up/router.types.ts index cd0b69a8bd6..7614f02ee00 100644 --- a/packages/elements/src/internals/machines/sign-up/router.types.ts +++ b/packages/elements/src/internals/machines/sign-up/router.types.ts @@ -20,16 +20,16 @@ import type { // ---------------------------------- Tags ---------------------------------- // -export const SignUpRouterRoutes = { - start: 'route:start', - continue: 'route:continue', - verification: 'route:verification', - callback: 'route:callback', - error: 'route:error', +export const SignUpRouterSteps = { + start: 'step:start', + continue: 'step:continue', + verification: 'step:verification', + callback: 'step:callback', + error: 'step:error', } as const; -export type SignUpRouterRoutes = keyof typeof SignUpRouterRoutes; -export type SignUpRouterTags = (typeof SignUpRouterRoutes)[keyof typeof SignUpRouterRoutes]; +export type SignUpRouterSteps = keyof typeof SignUpRouterSteps; +export type SignUpRouterTags = (typeof SignUpRouterSteps)[keyof typeof SignUpRouterSteps]; // ---------------------------------- Children ---------------------------------- // diff --git a/packages/elements/src/internals/machines/types/router.types.ts b/packages/elements/src/internals/machines/types/router.types.ts index f28ad584774..6db5af79fe7 100644 --- a/packages/elements/src/internals/machines/types/router.types.ts +++ b/packages/elements/src/internals/machines/types/router.types.ts @@ -14,7 +14,14 @@ import type { ClerkRouter } from '~/react/router'; // ---------------------------------- Events ---------------------------------- // -export type BaseRouterLoadingStep = 'start' | 'verifications' | 'continue' | 'reset-password'; +export type BaseRouterLoadingStep = + | 'start' + | 'verifications' + | 'continue' + | 'reset-password' + | 'forgot-password' + | 'choose-strategy' + | 'error'; export type BaseRouterNextEvent = { type: 'NEXT'; resource?: T }; export type BaseRouterFormAttachEvent = { type: 'FORM.ATTACH'; formRef: ActorRefFrom }; diff --git a/packages/elements/src/react/common/loading.tsx b/packages/elements/src/react/common/loading.tsx index 5bd9e1c826a..a0a4d55626a 100644 --- a/packages/elements/src/react/common/loading.tsx +++ b/packages/elements/src/react/common/loading.tsx @@ -1,24 +1,19 @@ import { useClerk } from '@clerk/clerk-react'; import { eventComponentMounted } from '@clerk/shared/telemetry'; import type { OAuthProvider, SamlStrategy } from '@clerk/types'; +import { useSelector } from '@xstate/react'; import * as React from 'react'; import { ClerkElementsRuntimeError } from '~/internals/errors'; import type { ActorSignIn, ActorSignUp } from '~/react/hooks/use-loading.hook'; import { useLoading } from '~/react/hooks/use-loading.hook'; -import { SignInChooseStrategyCtx } from '~/react/sign-in/choose-strategy'; import { SignInRouterCtx } from '~/react/sign-in/context'; -import { SignInStartCtx } from '~/react/sign-in/start'; import type { TSignInStep } from '~/react/sign-in/step'; import { SIGN_IN_STEPS } from '~/react/sign-in/step'; -import { SignInFirstFactorCtx, SignInSecondFactorCtx } from '~/react/sign-in/verifications'; import { SignUpRouterCtx } from '~/react/sign-up/context'; -import { SignUpContinueCtx } from '~/react/sign-up/continue'; -import { SignUpStartCtx } from '~/react/sign-up/start'; import type { TSignUpStep } from '~/react/sign-up/step'; import { SIGN_UP_STEPS } from '~/react/sign-up/step'; -import { SignUpVerificationCtx } from '~/react/sign-up/verifications'; -import { mapScopeToStrategy } from '~/react/utils/map-scope-to-strategy'; +import { isProviderStrategyScope, mapScopeToStrategy } from '~/react/utils/map-scope-to-strategy'; type Strategy = OAuthProvider | SamlStrategy | 'metamask'; type LoadingScope = 'global' | `step:${T}` | `provider:${Strategy}` | undefined; @@ -140,67 +135,33 @@ type SignInLoadingProps = { function SignInLoading({ children, scope, routerRef }: SignInLoadingProps) { const [isLoading, { step: loadingStep, strategy }] = useLoading(routerRef); - - let computedScope: LoadingScope; - - // Figure out if the component is inside a `` component - const startCtx = SignInStartCtx.useActorRef(true); - const firstFactorCtx = SignInFirstFactorCtx.useActorRef(true); - const secondFactorCtx = SignInSecondFactorCtx.useActorRef(true); - const chooseStrategyCtx = SignInChooseStrategyCtx.useDomValidation(true); - - // A user can explicitly define the scope, otherwise we'll try to infer it from the surrounding context - if (scope) { - computedScope = scope; - } else { - let inferredScope: LoadingScope; - - if (startCtx) { - inferredScope = 'step:start'; - } else if (firstFactorCtx || secondFactorCtx) { - inferredScope = 'step:verifications'; - } else if (chooseStrategyCtx) { - inferredScope = 'step:choose-strategy'; - } else { - inferredScope = 'global'; - } - - computedScope = inferredScope; - } - - const snapshot = routerRef.getSnapshot(); - const isFirstFactor = snapshot.hasTag('route:first-factor'); - - // Determine loading states based on the step - const isStartLoading = isLoading && loadingStep === 'start'; - const isVerificationsLoading = isLoading && loadingStep === 'verifications'; - const isChooseStrategyLoading = isLoading && isFirstFactor && snapshot.hasTag('route:choose-strategy'); - const isForgotPasswordLoading = isFirstFactor && snapshot.hasTag('route:forgot-password'); - const isResetPasswordLoading = isFirstFactor && snapshot.hasTag('route:reset-password'); - const isStrategyLoading = isLoading && loadingStep === undefined && strategy !== undefined; - - let returnValue: boolean; - - if (computedScope === 'global') { - returnValue = isLoading; - } else if (computedScope === 'step:start') { - returnValue = isStartLoading; - } else if (computedScope === 'step:verifications') { - returnValue = isVerificationsLoading; - } else if (computedScope === 'step:choose-strategy') { - returnValue = isChooseStrategyLoading; - } else if (computedScope === 'step:forgot-password') { - returnValue = isForgotPasswordLoading; - } else if (computedScope === 'step:reset-password') { - returnValue = isResetPasswordLoading; - } else if (computedScope.startsWith('provider:')) { - const computedStrategy = mapScopeToStrategy(computedScope); - returnValue = isStrategyLoading && strategy === computedStrategy; + const tags = useSelector(routerRef, s => s.tags); + + const isStepLoading = (step: TSignInStep) => isLoading && loadingStep === step; + const isInferredStepLoading = (step: TSignInStep) => tags.has(`step:${step}`) && isStepLoading(step); + + let loadingResult = false; + + if (scope === 'global') { + // Global Loading Scope + loadingResult = isLoading; + } else if (scope && isProviderStrategyScope(scope)) { + // Provider-Specific Loading Scope + loadingResult = isLoading && loadingStep === undefined && strategy === mapScopeToStrategy(scope); + } else if (scope) { + // Specified Loading Scope + loadingResult = isStepLoading(scope.replace('step:', '') as TSignInStep); } else { - throw new ClerkElementsRuntimeError(`Invalid scope "${computedScope}" used for `); + // Inferred Loading Scope + loadingResult = + isInferredStepLoading('start') || + isInferredStepLoading('verifications') || + isInferredStepLoading('choose-strategy') || + isInferredStepLoading('forgot-password') || + isInferredStepLoading('reset-password'); } - return children(returnValue); + return children(loadingResult); } type SignUpLoadingProps = { @@ -211,54 +172,26 @@ type SignUpLoadingProps = { function SignUpLoading({ children, scope, routerRef }: SignUpLoadingProps) { const [isLoading, { step: loadingStep, strategy }] = useLoading(routerRef); + const tags = useSelector(routerRef, s => s.tags); - let computedScope: LoadingScope; - - // Figure out if the component is inside a `` component - const startCtx = SignUpStartCtx.useActorRef(true); - const continueCtx = SignUpContinueCtx.useActorRef(true); - const verificationsCtx = SignUpVerificationCtx.useActorRef(true); - - if (scope) { - computedScope = scope; - } else { - let inferredScope: LoadingScope; - - if (startCtx) { - inferredScope = `step:start`; - } else if (continueCtx) { - inferredScope = `step:continue`; - } else if (verificationsCtx) { - inferredScope = `step:verifications`; - } else { - inferredScope = `global`; - } - - computedScope = inferredScope; - } - - // Determine loading states based on the step - const isStartLoading = isLoading && loadingStep === 'start'; - const isVerificationsLoading = isLoading && loadingStep === 'verifications'; - const isContinueLoading = isLoading && loadingStep === 'continue'; - const isStrategyLoading = isLoading && loadingStep === undefined && strategy !== undefined; + const isStepLoading = (step: TSignUpStep) => isLoading && loadingStep === step; + const isInferredStepLoading = (step: TSignUpStep) => tags.has(`step:${step}`) && isStepLoading(step); - let returnValue: boolean; + let loadingResult = false; - if (computedScope === 'global') { - returnValue = isLoading; - } else if (computedScope === 'step:start') { - returnValue = isStartLoading; - } else if (computedScope === 'step:verifications') { - returnValue = isVerificationsLoading; - } else if (computedScope === 'step:continue') { - returnValue = isContinueLoading; - } else if (computedScope.startsWith('provider:')) { - const computedStrategy = mapScopeToStrategy(computedScope); - returnValue = isStrategyLoading && strategy === computedStrategy; + if (scope === 'global') { + // Global Loading Scope + loadingResult = isLoading; + } else if (scope && isProviderStrategyScope(scope)) { + // Provider-Specific Loading Scope + loadingResult = isLoading && loadingStep === undefined && strategy === mapScopeToStrategy(scope); + } else if (scope) { + loadingResult = isStepLoading(scope.replace('step:', '') as TSignUpStep); } else { - throw new ClerkElementsRuntimeError(`Invalid scope "${computedScope}" used for `); + // Inferred Loading Scope + loadingResult = + isInferredStepLoading('start') || isInferredStepLoading('continue') || isInferredStepLoading('verifications'); } - return children(returnValue); + return children(loadingResult); } diff --git a/packages/elements/src/react/sign-in/choose-strategy.tsx b/packages/elements/src/react/sign-in/choose-strategy.tsx index d71814e6563..24f3e91103e 100644 --- a/packages/elements/src/react/sign-in/choose-strategy.tsx +++ b/packages/elements/src/react/sign-in/choose-strategy.tsx @@ -45,13 +45,13 @@ export function SignInChooseStrategy({ children, ...props }: SignInChooseStrateg const routerRef = SignInRouterCtx.useActorRef(); const activeStateFirstFactor = useActiveTags( routerRef, - ['route:first-factor', 'route:choose-strategy'], + ['step:verifications', 'step:first-factor', 'step:choose-strategy'], ActiveTagsMode.all, ); const activeStateSecondFactor = useActiveTags( routerRef, - ['route:second-factor', 'route:choose-strategy'], + ['step:verifications', 'step:second-factor', 'step:choose-strategy'], ActiveTagsMode.all, ); @@ -66,7 +66,7 @@ export function SignInChooseStrategy({ children, ...props }: SignInChooseStrateg export function SignInForgotPassword({ children, ...props }: SignInForgotPasswordProps) { const routerRef = SignInRouterCtx.useActorRef(); - const activeState = useActiveTags(routerRef, ['route:first-factor', 'route:forgot-password'], ActiveTagsMode.all); + const activeState = useActiveTags(routerRef, ['step:first-factor', 'step:forgot-password'], ActiveTagsMode.all); return activeState ? ( @@ -104,11 +104,9 @@ export const SignInSupportedStrategy = React.forwardRef name === factor.strategy, - ); + const supportedFirstFactors = snapshot.context.clerk.client.signIn.supportedFirstFactors || []; + const supportedSecondFactors = snapshot.context.clerk.client.signIn.supportedSecondFactors || []; + const factor = [...supportedFirstFactors, ...supportedSecondFactors].find(factor => name === factor.strategy); const currentFactor = useSelector( (snapshot.children[SignInRouterSystemId.firstFactor] || diff --git a/packages/elements/src/react/sign-in/reset-password.tsx b/packages/elements/src/react/sign-in/reset-password.tsx index 7616462b503..0af73a61ce5 100644 --- a/packages/elements/src/react/sign-in/reset-password.tsx +++ b/packages/elements/src/react/sign-in/reset-password.tsx @@ -11,7 +11,7 @@ export const SignInResetPasswordCtx = createContextFromActorRef : null; } diff --git a/packages/elements/src/react/sign-in/start.tsx b/packages/elements/src/react/sign-in/start.tsx index 033bf07c063..52a2c55357d 100644 --- a/packages/elements/src/react/sign-in/start.tsx +++ b/packages/elements/src/react/sign-in/start.tsx @@ -11,7 +11,7 @@ export const SignInStartCtx = createContextFromActorRef('Si export function SignInStart(props: SignInStartProps) { const routerRef = SignInRouterCtx.useActorRef(); - const activeState = useActiveTags(routerRef, 'route:start'); + const activeState = useActiveTags(routerRef, 'step:start'); return activeState ? : null; } diff --git a/packages/elements/src/react/sign-in/verifications.tsx b/packages/elements/src/react/sign-in/verifications.tsx index 6b3d647ae5d..93282bac20c 100644 --- a/packages/elements/src/react/sign-in/verifications.tsx +++ b/packages/elements/src/react/sign-in/verifications.tsx @@ -34,7 +34,7 @@ function SignInStrategiesProvider({ }: SignInVerificationsProps & { actorRef: ActorRefFrom }) { const routerRef = SignInRouterCtx.useActorRef(); const current = useSelector(actorRef, strategiesSelector); - const isChoosingAltStrategy = useActiveTags(routerRef, ['route:choose-strategy', 'route:forgot-password']); + const isChoosingAltStrategy = useActiveTags(routerRef, ['step:choose-strategy', 'step:forgot-password']); const isActive = useCallback((name: string) => (current ? matchStrategy(current, name) : false), [current]); return ( @@ -97,13 +97,13 @@ export function SignInStrategy({ children, name }: SignInStrategyProps) { */ export function SignInVerifications(props: SignInVerificationsProps) { const routerRef = SignInRouterCtx.useActorRef(); - const { activeTags: activeRoutes } = useActiveTags(routerRef, ['route:first-factor', 'route:second-factor']); + const { activeTags: activeRoutes } = useActiveTags(routerRef, ['step:first-factor', 'step:second-factor']); - if (activeRoutes.has('route:first-factor')) { + if (activeRoutes.has('step:first-factor')) { return ; } - if (activeRoutes.has('route:second-factor')) { + if (activeRoutes.has('step:second-factor')) { return ; } @@ -119,7 +119,7 @@ export function SignInVerifications(props: SignInVerificationsProps) { */ export function SignInFirstFactor(props: SignInVerificationsProps) { const routerRef = SignInRouterCtx.useActorRef(); - const activeState = useActiveTags(routerRef, 'route:first-factor'); + const activeState = useActiveTags(routerRef, 'step:first-factor'); return activeState ? : null; } @@ -133,7 +133,7 @@ export function SignInFirstFactor(props: SignInVerificationsProps) { */ export function SignInSecondFactor(props: SignInVerificationsProps) { const routerRef = SignInRouterCtx.useActorRef(); - const activeState = useActiveTags(routerRef, 'route:second-factor'); + const activeState = useActiveTags(routerRef, 'step:second-factor'); return activeState ? : null; } diff --git a/packages/elements/src/react/sign-up/continue.tsx b/packages/elements/src/react/sign-up/continue.tsx index b1d101dc1d5..2fa3b1dc854 100644 --- a/packages/elements/src/react/sign-up/continue.tsx +++ b/packages/elements/src/react/sign-up/continue.tsx @@ -11,7 +11,7 @@ export const SignUpContinueCtx = createContextFromActorRef : null; } diff --git a/packages/elements/src/react/sign-up/start.tsx b/packages/elements/src/react/sign-up/start.tsx index dfbbe47e266..eb6525f575c 100644 --- a/packages/elements/src/react/sign-up/start.tsx +++ b/packages/elements/src/react/sign-up/start.tsx @@ -11,7 +11,7 @@ export const SignUpStartCtx = createContextFromActorRef('Si export function SignUpStart(props: SignUpStartProps) { const routerRef = SignUpRouterCtx.useActorRef(); - const activeState = useActiveTags(routerRef, 'route:start'); + const activeState = useActiveTags(routerRef, 'step:start'); return activeState ? : null; } diff --git a/packages/elements/src/react/sign-up/verifications.tsx b/packages/elements/src/react/sign-up/verifications.tsx index cbfbe912934..0fbcbc1e06d 100644 --- a/packages/elements/src/react/sign-up/verifications.tsx +++ b/packages/elements/src/react/sign-up/verifications.tsx @@ -31,7 +31,7 @@ export const SignUpVerificationCtx = createContextFromActorRef : null; } diff --git a/packages/elements/src/react/utils/map-scope-to-strategy.ts b/packages/elements/src/react/utils/map-scope-to-strategy.ts index 5669251034c..8bac8fbc43a 100644 --- a/packages/elements/src/react/utils/map-scope-to-strategy.ts +++ b/packages/elements/src/react/utils/map-scope-to-strategy.ts @@ -2,6 +2,10 @@ import type { OAuthProvider, SamlStrategy, SignInStrategy } from '@clerk/types'; type Strategy = OAuthProvider | SamlStrategy | 'metamask'; +export function isProviderStrategyScope(value: string): value is Strategy { + return value.startsWith('provider:'); +} + export function mapScopeToStrategy(scope: T): SignInStrategy { if (scope === 'provider:metamask') { return 'web3_metamask_signature';