From 58687a8732aa2a9fa1638755c34e8300e71db2a2 Mon Sep 17 00:00:00 2001 From: LekoArts Date: Mon, 8 Jul 2024 15:02:32 +0200 Subject: [PATCH 1/4] fix TODO comments --- .../sign-in/utils/starting-factors.ts | 17 ++++---- .../machines/sign-in/verification.machine.ts | 39 ++++++------------- .../machines/sign-in/verification.types.ts | 7 ++-- .../src/react/sign-in/verifications.tsx | 6 +-- 4 files changed, 26 insertions(+), 43 deletions(-) diff --git a/packages/elements/src/internals/machines/sign-in/utils/starting-factors.ts b/packages/elements/src/internals/machines/sign-in/utils/starting-factors.ts index 0ee87be6375..5903b37f7aa 100644 --- a/packages/elements/src/internals/machines/sign-in/utils/starting-factors.ts +++ b/packages/elements/src/internals/machines/sign-in/utils/starting-factors.ts @@ -1,7 +1,7 @@ // These utilities are ported from: packages/clerk-js/src/ui/components/SignIn/utils.ts // They should be functionally identical. import { isWebAuthnSupported } from '@clerk/shared/webauthn'; -import type { PreferredSignInStrategy, SignInFactor } from '@clerk/types'; +import type { PreferredSignInStrategy, SignInFactor, SignInFirstFactor, SignInSecondFactor } from '@clerk/types'; const ORDER_WHEN_PASSWORD_PREFERRED = ['passkey', 'password', 'email_link', 'email_code', 'phone_code'] as const; const ORDER_WHEN_OTP_PREFERRED = ['email_link', 'email_code', 'phone_code', 'passkey', 'password'] as const; @@ -14,10 +14,10 @@ const findFactorForIdentifier = (i: string | null) => (f: SignInFactor) => { // The algorithm can be found at // https://www.notion.so/clerkdev/Implement-sign-in-alt-methods-e6e60ffb644645b3a0553b50556468ce export function determineStartingSignInFactor( - firstFactors: SignInFactor[], + firstFactors: SignInFirstFactor[], identifier: string | null, preferredSignInStrategy?: PreferredSignInStrategy, -): SignInFactor | null { +) { if (!firstFactors || firstFactors.length === 0) { return null; } @@ -27,7 +27,7 @@ export function determineStartingSignInFactor( : determineStrategyWhenOTPIsPreferred(firstFactors, identifier); } -function findPasskeyStrategy(factors: SignInFactor[]): SignInFactor | null { +function findPasskeyStrategy(factors: SignInFirstFactor[]) { if (isWebAuthnSupported()) { const passkeyFactor = factors.find(({ strategy }) => strategy === 'passkey'); @@ -38,10 +38,7 @@ function findPasskeyStrategy(factors: SignInFactor[]): SignInFactor | null { return null; } -function determineStrategyWhenPasswordIsPreferred( - factors: SignInFactor[], - identifier: string | null, -): SignInFactor | null { +function determineStrategyWhenPasswordIsPreferred(factors: SignInFirstFactor[], identifier: string | null) { const passkeyFactor = findPasskeyStrategy(factors); if (passkeyFactor) { return passkeyFactor; @@ -69,7 +66,7 @@ function determineStrategyWhenPasswordIsPreferred( return null; } -function determineStrategyWhenOTPIsPreferred(factors: SignInFactor[], identifier: string | null): SignInFactor | null { +function determineStrategyWhenOTPIsPreferred(factors: SignInFirstFactor[], identifier: string | null) { const passkeyFactor = findPasskeyStrategy(factors); if (passkeyFactor) { return passkeyFactor; @@ -97,7 +94,7 @@ function determineStrategyWhenOTPIsPreferred(factors: SignInFactor[], identifier } // The priority of second factors is: TOTP -> Phone code -> any other factor -export function determineStartingSignInSecondFactor(secondFactors: SignInFactor[]): SignInFactor | null { +export function determineStartingSignInSecondFactor(secondFactors: SignInSecondFactor[]) { if (!secondFactors || secondFactors.length === 0) { return null; } diff --git a/packages/elements/src/internals/machines/sign-in/verification.machine.ts b/packages/elements/src/internals/machines/sign-in/verification.machine.ts index e0dacac80be..63dda692cb3 100644 --- a/packages/elements/src/internals/machines/sign-in/verification.machine.ts +++ b/packages/elements/src/internals/machines/sign-in/verification.machine.ts @@ -4,10 +4,9 @@ import type { EmailCodeAttempt, PasswordAttempt, PhoneCodeAttempt, - PrepareFirstFactorParams, + PrepareSecondFactorParams, ResetPasswordEmailCodeAttempt, ResetPasswordPhoneCodeAttempt, - SignInFactor, SignInFirstFactor, SignInResource, SignInSecondFactor, @@ -19,7 +18,7 @@ import { assign, fromPromise, log, sendTo, setup } from 'xstate'; import { RESENDABLE_COUNTDOWN_DEFAULT } from '~/internals/constants'; import { ClerkElementsRuntimeError } from '~/internals/errors'; import type { FormFields } from '~/internals/machines/form'; -import type { WithParams } from '~/internals/machines/shared'; +import type { SignInStrategyName, WithParams } from '~/internals/machines/shared'; import { sendToLoading } from '~/internals/machines/shared'; import { determineStartingSignInFactor, determineStartingSignInSecondFactor } from '~/internals/machines/sign-in/utils'; import { assertActorEventError, assertIsDefined } from '~/internals/machines/utils/assert'; @@ -39,7 +38,7 @@ export type PrepareFirstFactorInput = WithParams & { parent: SignInRouterMachineActorRef; resendable: boolean; }; -export type PrepareSecondFactorInput = WithParams & { +export type PrepareSecondFactorInput = WithParams & { parent: SignInRouterMachineActorRef; resendable: boolean; }; @@ -67,8 +66,8 @@ export const SignInVerificationMachineId = 'SignInVerification'; const SignInVerificationMachine = setup({ actors: { - determineStartingFactor: fromPromise(() => - Promise.reject(new ClerkElementsRuntimeError('Actor `determineStartingFactor` must be overridden')), + determineStartingFactor: fromPromise( + () => Promise.reject(new ClerkElementsRuntimeError('Actor `determineStartingFactor` must be overridden')), ), prepare: fromPromise(() => Promise.reject(new ClerkElementsRuntimeError('Actor `prepare` must be overridden')), @@ -96,10 +95,7 @@ const SignInVerificationMachine = setup({ // Only show these warnings in development! if (process.env.NODE_ENV === 'development') { if ( - !clerk.client.signIn.supportedFirstFactors.every(factor => - // TODO: These "as SignInFactor" assertions are incorrect, factor.strategy is SignInFactor['strategy']. This needs to be fixed together with SignInVerificationStrategyRegisterEvent and SignInStrategy React component - context.registeredStrategies.has(factor.strategy as unknown as SignInFactor), - ) + !clerk.client.signIn.supportedFirstFactors.every(factor => context.registeredStrategies.has(factor.strategy)) ) { console.warn( `Clerk: Your instance is configured to support these strategies: ${clerk.client.signIn.supportedFirstFactors @@ -112,9 +108,7 @@ const SignInVerificationMachine = setup({ if ( clerk.client.signIn.supportedSecondFactors && - !clerk.client.signIn.supportedSecondFactors.every(factor => - context.registeredStrategies.has(factor.strategy as unknown as SignInFactor), - ) + !clerk.client.signIn.supportedSecondFactors.every(factor => context.registeredStrategies.has(factor.strategy)) ) { console.warn( `Clerk: Your instance is configured to support these 2FA strategies: ${clerk.client.signIn.supportedSecondFactors @@ -125,14 +119,9 @@ const SignInVerificationMachine = setup({ ); } - // TODO: These "as SignInFactor" assertions are incorrect, factor.strategy is SignInFactor['strategy']. This needs to be fixed together with SignInVerificationStrategyRegisterEvent and SignInStrategy React component - // This type should also probably be SignInFirstFactor['strategy'] instead of SignInFactor['strategy'] !!! const strategiesUsedButNotActivated = Array.from(context.registeredStrategies).filter( - strategy => - !clerk.client.signIn.supportedFirstFactors.some( - supported => (supported.strategy as unknown as SignInFactor) === strategy, - ), - ) as unknown as Array; + strategy => !clerk.client.signIn.supportedFirstFactors.some(supported => supported.strategy === strategy), + ); if (strategiesUsedButNotActivated.length > 0) { console.warn( @@ -140,11 +129,7 @@ const SignInVerificationMachine = setup({ ); } - if ( - context.currentFactor?.strategy && - // TODO: These "as SignInFactor" assertions are incorrect, factor.strategy is SignInFactor['strategy']. This needs to be fixed together with SignInVerificationStrategyRegisterEvent and SignInStrategy React component - !context.registeredStrategies.has(context.currentFactor?.strategy as unknown as SignInFactor) - ) { + if (context.currentFactor?.strategy && !context.registeredStrategies.has(context.currentFactor?.strategy)) { throw new ClerkElementsRuntimeError( `Your sign-in attempt is missing a ${context.currentFactor?.strategy} strategy. Make sure is rendered in your flow. More information: https://clerk.com/docs/elements/reference/sign-in#strategy`, ); @@ -195,7 +180,7 @@ const SignInVerificationMachine = setup({ formRef: input.formRef, loadingStep: 'verifications', parent: input.parent, - registeredStrategies: new Set(), + registeredStrategies: new Set(), resendable: false, resendableAfter: RESENDABLE_COUNTDOWN_DEFAULT, }), @@ -393,7 +378,7 @@ export const SignInFirstFactorMachine = SignInVerificationMachine.provide({ assertIsDefined(params, 'First factor params'); - return await clerk.client.signIn.prepareFirstFactor(params as PrepareFirstFactorParams); + return await clerk.client.signIn.prepareFirstFactor(params); }), attempt: fromPromise(async ({ input }) => { const { currentFactor, fields, parent } = input as AttemptFirstFactorInput; diff --git a/packages/elements/src/internals/machines/sign-in/verification.types.ts b/packages/elements/src/internals/machines/sign-in/verification.types.ts index 2762ff82713..191c6f2e979 100644 --- a/packages/elements/src/internals/machines/sign-in/verification.types.ts +++ b/packages/elements/src/internals/machines/sign-in/verification.types.ts @@ -3,6 +3,7 @@ import type { SignInFactor } from '@clerk/types'; import type { ActorRefFrom, ErrorActorEvent } from 'xstate'; import type { FormMachine } from '~/internals/machines/form'; +import type { SignInStrategyName } from '~/internals/machines/shared'; import type { SignInRouterMachineActorRef } from './router.types'; @@ -21,8 +22,8 @@ export type SignInVerificationTags = export type SignInVerificationSubmitEvent = { type: 'SUBMIT' }; export type SignInVerificationFactorUpdateEvent = { type: 'STRATEGY.UPDATE'; factor: SignInFactor | undefined }; export type SignInVerificationRetryEvent = { type: 'RETRY' }; -export type SignInVerificationStrategyRegisterEvent = { type: 'STRATEGY.REGISTER'; factor: SignInFactor }; -export type SignInVerificationStrategyUnregisterEvent = { type: 'STRATEGY.UNREGISTER'; factor: SignInFactor }; +export type SignInVerificationStrategyRegisterEvent = { type: 'STRATEGY.REGISTER'; factor: SignInStrategyName }; +export type SignInVerificationStrategyUnregisterEvent = { type: 'STRATEGY.UNREGISTER'; factor: SignInStrategyName }; export type SignInVerificationEvents = | ErrorActorEvent @@ -47,7 +48,7 @@ export interface SignInVerificationContext { formRef: ActorRefFrom; parent: SignInRouterMachineActorRef; loadingStep: 'verifications'; - registeredStrategies: Set; + registeredStrategies: Set; resendable: boolean; resendableAfter: number; } diff --git a/packages/elements/src/react/sign-in/verifications.tsx b/packages/elements/src/react/sign-in/verifications.tsx index 93282bac20c..c3e971b8978 100644 --- a/packages/elements/src/react/sign-in/verifications.tsx +++ b/packages/elements/src/react/sign-in/verifications.tsx @@ -1,4 +1,4 @@ -import type { SignInFactor, SignInStrategy as ClerkSignInStrategy } from '@clerk/types'; +import type { SignInStrategy as ClerkSignInStrategy } from '@clerk/types'; import { useSelector } from '@xstate/react'; import { useCallback, useEffect } from 'react'; import type { ActorRefFrom, SnapshotFrom } from 'xstate'; @@ -76,12 +76,12 @@ export function SignInStrategy({ children, name }: SignInStrategyProps) { useEffect(() => { if (factorCtx) { - factorCtx.send({ type: 'STRATEGY.REGISTER', factor: name as unknown as SignInFactor }); + factorCtx.send({ type: 'STRATEGY.REGISTER', factor: name }); } return () => { if (factorCtx?.getSnapshot().status === 'active') { - factorCtx.send({ type: 'STRATEGY.UNREGISTER', factor: name as unknown as SignInFactor }); + factorCtx.send({ type: 'STRATEGY.UNREGISTER', factor: name }); } }; }, [factorCtx, name]); From 8dc64070c79e903a5decf3b8c14ef9354ebff2a3 Mon Sep 17 00:00:00 2001 From: LekoArts Date: Mon, 8 Jul 2024 15:48:21 +0200 Subject: [PATCH 2/4] fix types for build --- .../src/internals/machines/sign-in/verification.machine.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/elements/src/internals/machines/sign-in/verification.machine.ts b/packages/elements/src/internals/machines/sign-in/verification.machine.ts index 63dda692cb3..b6114eafc2a 100644 --- a/packages/elements/src/internals/machines/sign-in/verification.machine.ts +++ b/packages/elements/src/internals/machines/sign-in/verification.machine.ts @@ -4,6 +4,7 @@ import type { EmailCodeAttempt, PasswordAttempt, PhoneCodeAttempt, + PrepareFirstFactorParams, PrepareSecondFactorParams, ResetPasswordEmailCodeAttempt, ResetPasswordPhoneCodeAttempt, @@ -34,7 +35,7 @@ export type DetermineStartingFactorInput = { parent: SignInRouterMachineActorRef; }; -export type PrepareFirstFactorInput = WithParams & { +export type PrepareFirstFactorInput = WithParams & { parent: SignInRouterMachineActorRef; resendable: boolean; }; @@ -235,7 +236,7 @@ const SignInVerificationMachine = setup({ input: ({ context }) => ({ parent: context.parent, resendable: context.resendable, - params: context.currentFactor as SignInFirstFactor | null, + params: context.currentFactor as PrepareFirstFactorParams, }), onDone: { actions: 'resendableReset', @@ -333,7 +334,7 @@ const SignInVerificationMachine = setup({ src: 'attempt', input: ({ context }) => ({ parent: context.parent, - currentFactor: context.currentFactor as SignInFirstFactor, + currentFactor: context.currentFactor as SignInFirstFactor | null, fields: context.formRef.getSnapshot().context.fields, }), onDone: { From 8c59fa881f190263e8e09b2a7b5e489dd3b5b626 Mon Sep 17 00:00:00 2001 From: LekoArts Date: Mon, 8 Jul 2024 15:54:40 +0200 Subject: [PATCH 3/4] fix type --- .../src/internals/machines/sign-in/verification.machine.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/elements/src/internals/machines/sign-in/verification.machine.ts b/packages/elements/src/internals/machines/sign-in/verification.machine.ts index b6114eafc2a..b941385be56 100644 --- a/packages/elements/src/internals/machines/sign-in/verification.machine.ts +++ b/packages/elements/src/internals/machines/sign-in/verification.machine.ts @@ -366,7 +366,7 @@ export const SignInFirstFactorMachine = SignInVerificationMachine.provide({ ); }), prepare: fromPromise(async ({ input }) => { - const { params, parent, resendable } = input; + const { params, parent, resendable } = input as PrepareFirstFactorInput; const clerk = parent.getSnapshot().context.clerk; // If a prepare call has already been fired recently, don't re-send From 05bc219d772a79b2cc22d6ce292f3b48fa8c9304 Mon Sep 17 00:00:00 2001 From: LekoArts Date: Mon, 8 Jul 2024 15:55:48 +0200 Subject: [PATCH 4/4] add empty changeset --- .changeset/ninety-geese-drop.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changeset/ninety-geese-drop.md diff --git a/.changeset/ninety-geese-drop.md b/.changeset/ninety-geese-drop.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/ninety-geese-drop.md @@ -0,0 +1,2 @@ +--- +---