From 664822a4bbe58ff8d495b6eaf665ba716c91cf2a Mon Sep 17 00:00:00 2001 From: panteliselef Date: Wed, 3 Sep 2025 13:00:38 +0300 Subject: [PATCH 1/6] fix(clerk-js): Prepare calls would fire only once --- .changeset/crazy-days-tan.md | 5 +++++ .../SignIn/SignInFactorOneCodeForm.tsx | 18 +++++------------- .../components/SignUp/SignUpEmailCodeCard.tsx | 8 ++------ .../components/SignUp/SignUpPhoneCodeCard.tsx | 6 ++---- packages/clerk-js/src/ui/hooks/useFetch.ts | 9 +++++++++ 5 files changed, 23 insertions(+), 23 deletions(-) create mode 100644 .changeset/crazy-days-tan.md diff --git a/.changeset/crazy-days-tan.md b/.changeset/crazy-days-tan.md new file mode 100644 index 00000000000..995d6bf4a36 --- /dev/null +++ b/.changeset/crazy-days-tan.md @@ -0,0 +1,5 @@ +--- +'@clerk/clerk-js': patch +--- + +Fixes issue where "prepare" API request would only fire once, preventing end users from receiving fresh otp codes. diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx index 0a0a43162c5..67c20e17360 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx @@ -82,19 +82,11 @@ export const SignInFactorOneCodeForm = (props: SignInFactorOneCodeFormProps) => .catch(err => handleError(err, [], card.setError)); }; - useFetch( - shouldAvoidPrepare - ? undefined - : () => - signIn - ?.prepareFirstFactor(props.factor) - .then(() => props.onFactorPrepare()) - .catch(err => handleError(err, [], card.setError)), - cacheKey, - { - staleTime: 100, - }, - ); + useFetch(shouldAvoidPrepare ? undefined : () => signIn?.prepareFirstFactor(props.factor), cacheKey, { + staleTime: 100, + onSuccess: () => props.onFactorPrepare(), + onError: err => handleError(err, [], card.setError), + }); const action: VerificationCodeCardProps['onCodeEntryFinishedAction'] = (code, resolve, reject) => { signIn diff --git a/packages/clerk-js/src/ui/components/SignUp/SignUpEmailCodeCard.tsx b/packages/clerk-js/src/ui/components/SignUp/SignUpEmailCodeCard.tsx index dbf2b0e7256..65f6a2e1994 100644 --- a/packages/clerk-js/src/ui/components/SignUp/SignUpEmailCodeCard.tsx +++ b/packages/clerk-js/src/ui/components/SignUp/SignUpEmailCodeCard.tsx @@ -24,12 +24,7 @@ export const SignUpEmailCodeCard = () => { // TODO: Introduce a useMutation to handle mutating requests useFetch( - shouldAvoidPrepare - ? undefined - : () => - signUp - .prepareEmailAddressVerification({ strategy: 'email_code' }) - .catch(err => handleError(err, [], card.setError)), + shouldAvoidPrepare ? undefined : () => signUp.prepareEmailAddressVerification({ strategy: 'email_code' }), { name: 'prepare', strategy: 'email_code', @@ -37,6 +32,7 @@ export const SignUpEmailCodeCard = () => { }, { staleTime: 100, + onError: err => handleError(err, [], card.setError), }, ); diff --git a/packages/clerk-js/src/ui/components/SignUp/SignUpPhoneCodeCard.tsx b/packages/clerk-js/src/ui/components/SignUp/SignUpPhoneCodeCard.tsx index 57866b44f71..cd9b906ce93 100644 --- a/packages/clerk-js/src/ui/components/SignUp/SignUpPhoneCodeCard.tsx +++ b/packages/clerk-js/src/ui/components/SignUp/SignUpPhoneCodeCard.tsx @@ -36,10 +36,7 @@ export const SignUpPhoneCodeCard = withCardStateProvider(() => { // because the verification is already created on the Start screen shouldAvoidPrepare || isAlternativePhoneCodeProvider ? undefined - : () => - signUp - .preparePhoneNumberVerification({ strategy: 'phone_code', channel: undefined }) - .catch(err => handleError(err, [], card.setError)), + : () => signUp.preparePhoneNumberVerification({ strategy: 'phone_code', channel: undefined }), { name: 'signUp.preparePhoneNumberVerification', strategy: 'phone_code', @@ -47,6 +44,7 @@ export const SignUpPhoneCodeCard = withCardStateProvider(() => { }, { staleTime: 100, + onError: err => handleError(err, [], card.setError), }, ); diff --git a/packages/clerk-js/src/ui/hooks/useFetch.ts b/packages/clerk-js/src/ui/hooks/useFetch.ts index 7abe9207c49..881dfd139e3 100644 --- a/packages/clerk-js/src/ui/hooks/useFetch.ts +++ b/packages/clerk-js/src/ui/hooks/useFetch.ts @@ -88,6 +88,7 @@ export const useFetch = ( options?: { throttleTime?: number; onSuccess?: (data: T) => void; + onError?: (error: Error) => void; staleTime?: number; }, resourceId?: string, @@ -134,6 +135,13 @@ export const useFetch = ( typeof getCache()?.cachedAt === 'undefined' ? true : Date.now() - (getCache()?.cachedAt || 0) >= staleTime; const isRequestOnGoing = getCache()?.isValidating ?? false; + console.log('fetcherMissing', fetcherMissing); + console.log('isCacheStale', isCacheStale); + console.log('isRequestOnGoing', isRequestOnGoing); + + console.log('toSkip', fetcherMissing || !isCacheStale || isRequestOnGoing); + console.log('getCache()', getCache()); + if (fetcherMissing || !isCacheStale || isRequestOnGoing) { return; } @@ -174,6 +182,7 @@ export const useFetch = ( error: e, cachedAt: Date.now(), }); + options?.onError?.(e); }); }, [serialize(params), setCache, getCache, revalidateCache]); From cbca675308956fe48dc04c1c1c6e82f4151b63e8 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Wed, 3 Sep 2025 13:12:34 +0300 Subject: [PATCH 2/6] remove logs --- packages/clerk-js/src/ui/hooks/useFetch.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/clerk-js/src/ui/hooks/useFetch.ts b/packages/clerk-js/src/ui/hooks/useFetch.ts index 881dfd139e3..97f9a424706 100644 --- a/packages/clerk-js/src/ui/hooks/useFetch.ts +++ b/packages/clerk-js/src/ui/hooks/useFetch.ts @@ -135,13 +135,6 @@ export const useFetch = ( typeof getCache()?.cachedAt === 'undefined' ? true : Date.now() - (getCache()?.cachedAt || 0) >= staleTime; const isRequestOnGoing = getCache()?.isValidating ?? false; - console.log('fetcherMissing', fetcherMissing); - console.log('isCacheStale', isCacheStale); - console.log('isRequestOnGoing', isRequestOnGoing); - - console.log('toSkip', fetcherMissing || !isCacheStale || isRequestOnGoing); - console.log('getCache()', getCache()); - if (fetcherMissing || !isCacheStale || isRequestOnGoing) { return; } From e9bdff4db033964c3135f0144c244feb1b717d1c Mon Sep 17 00:00:00 2001 From: panteliselef Date: Wed, 3 Sep 2025 13:21:12 +0300 Subject: [PATCH 3/6] use return values instead of callback --- .../SignIn/SignInFactorOneCodeForm.tsx | 24 +++++++++++++++---- .../components/SignUp/SignUpEmailCodeCard.tsx | 9 +++++-- .../components/SignUp/SignUpPhoneCodeCard.tsx | 7 ++++-- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx index 67c20e17360..f49a5c749a4 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx @@ -82,11 +82,25 @@ export const SignInFactorOneCodeForm = (props: SignInFactorOneCodeFormProps) => .catch(err => handleError(err, [], card.setError)); }; - useFetch(shouldAvoidPrepare ? undefined : () => signIn?.prepareFirstFactor(props.factor), cacheKey, { - staleTime: 100, - onSuccess: () => props.onFactorPrepare(), - onError: err => handleError(err, [], card.setError), - }); + useFetch( + shouldAvoidPrepare + ? undefined + : () => + signIn + ?.prepareFirstFactor(props.factor) + .then(res => { + props.onFactorPrepare(); + return res; + }) + .catch(err => { + handleError(err, [], card.setError); + return err; + }), + cacheKey, + { + staleTime: 100, + }, + ); const action: VerificationCodeCardProps['onCodeEntryFinishedAction'] = (code, resolve, reject) => { signIn diff --git a/packages/clerk-js/src/ui/components/SignUp/SignUpEmailCodeCard.tsx b/packages/clerk-js/src/ui/components/SignUp/SignUpEmailCodeCard.tsx index 65f6a2e1994..93f944be5c7 100644 --- a/packages/clerk-js/src/ui/components/SignUp/SignUpEmailCodeCard.tsx +++ b/packages/clerk-js/src/ui/components/SignUp/SignUpEmailCodeCard.tsx @@ -24,7 +24,13 @@ export const SignUpEmailCodeCard = () => { // TODO: Introduce a useMutation to handle mutating requests useFetch( - shouldAvoidPrepare ? undefined : () => signUp.prepareEmailAddressVerification({ strategy: 'email_code' }), + shouldAvoidPrepare + ? undefined + : () => + signUp.prepareEmailAddressVerification({ strategy: 'email_code' }).catch(err => { + handleError(err, [], card.setError); + return err; + }), { name: 'prepare', strategy: 'email_code', @@ -32,7 +38,6 @@ export const SignUpEmailCodeCard = () => { }, { staleTime: 100, - onError: err => handleError(err, [], card.setError), }, ); diff --git a/packages/clerk-js/src/ui/components/SignUp/SignUpPhoneCodeCard.tsx b/packages/clerk-js/src/ui/components/SignUp/SignUpPhoneCodeCard.tsx index cd9b906ce93..a6ba8eae16e 100644 --- a/packages/clerk-js/src/ui/components/SignUp/SignUpPhoneCodeCard.tsx +++ b/packages/clerk-js/src/ui/components/SignUp/SignUpPhoneCodeCard.tsx @@ -36,7 +36,11 @@ export const SignUpPhoneCodeCard = withCardStateProvider(() => { // because the verification is already created on the Start screen shouldAvoidPrepare || isAlternativePhoneCodeProvider ? undefined - : () => signUp.preparePhoneNumberVerification({ strategy: 'phone_code', channel: undefined }), + : () => + signUp.preparePhoneNumberVerification({ strategy: 'phone_code', channel: undefined }).catch(err => { + handleError(err, [], card.setError); + return err; + }), { name: 'signUp.preparePhoneNumberVerification', strategy: 'phone_code', @@ -44,7 +48,6 @@ export const SignUpPhoneCodeCard = withCardStateProvider(() => { }, { staleTime: 100, - onError: err => handleError(err, [], card.setError), }, ); From 4a97f33dd7aeb8ee7e2be046c0c3ec3d15e85f3e Mon Sep 17 00:00:00 2001 From: panteliselef Date: Wed, 3 Sep 2025 13:21:48 +0300 Subject: [PATCH 4/6] Revert "use return values instead of callback" This reverts commit e9bdff4db033964c3135f0144c244feb1b717d1c. --- .../SignIn/SignInFactorOneCodeForm.tsx | 24 ++++--------------- .../components/SignUp/SignUpEmailCodeCard.tsx | 9 ++----- .../components/SignUp/SignUpPhoneCodeCard.tsx | 7 ++---- 3 files changed, 9 insertions(+), 31 deletions(-) diff --git a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx index f49a5c749a4..67c20e17360 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignInFactorOneCodeForm.tsx @@ -82,25 +82,11 @@ export const SignInFactorOneCodeForm = (props: SignInFactorOneCodeFormProps) => .catch(err => handleError(err, [], card.setError)); }; - useFetch( - shouldAvoidPrepare - ? undefined - : () => - signIn - ?.prepareFirstFactor(props.factor) - .then(res => { - props.onFactorPrepare(); - return res; - }) - .catch(err => { - handleError(err, [], card.setError); - return err; - }), - cacheKey, - { - staleTime: 100, - }, - ); + useFetch(shouldAvoidPrepare ? undefined : () => signIn?.prepareFirstFactor(props.factor), cacheKey, { + staleTime: 100, + onSuccess: () => props.onFactorPrepare(), + onError: err => handleError(err, [], card.setError), + }); const action: VerificationCodeCardProps['onCodeEntryFinishedAction'] = (code, resolve, reject) => { signIn diff --git a/packages/clerk-js/src/ui/components/SignUp/SignUpEmailCodeCard.tsx b/packages/clerk-js/src/ui/components/SignUp/SignUpEmailCodeCard.tsx index 93f944be5c7..65f6a2e1994 100644 --- a/packages/clerk-js/src/ui/components/SignUp/SignUpEmailCodeCard.tsx +++ b/packages/clerk-js/src/ui/components/SignUp/SignUpEmailCodeCard.tsx @@ -24,13 +24,7 @@ export const SignUpEmailCodeCard = () => { // TODO: Introduce a useMutation to handle mutating requests useFetch( - shouldAvoidPrepare - ? undefined - : () => - signUp.prepareEmailAddressVerification({ strategy: 'email_code' }).catch(err => { - handleError(err, [], card.setError); - return err; - }), + shouldAvoidPrepare ? undefined : () => signUp.prepareEmailAddressVerification({ strategy: 'email_code' }), { name: 'prepare', strategy: 'email_code', @@ -38,6 +32,7 @@ export const SignUpEmailCodeCard = () => { }, { staleTime: 100, + onError: err => handleError(err, [], card.setError), }, ); diff --git a/packages/clerk-js/src/ui/components/SignUp/SignUpPhoneCodeCard.tsx b/packages/clerk-js/src/ui/components/SignUp/SignUpPhoneCodeCard.tsx index a6ba8eae16e..cd9b906ce93 100644 --- a/packages/clerk-js/src/ui/components/SignUp/SignUpPhoneCodeCard.tsx +++ b/packages/clerk-js/src/ui/components/SignUp/SignUpPhoneCodeCard.tsx @@ -36,11 +36,7 @@ export const SignUpPhoneCodeCard = withCardStateProvider(() => { // because the verification is already created on the Start screen shouldAvoidPrepare || isAlternativePhoneCodeProvider ? undefined - : () => - signUp.preparePhoneNumberVerification({ strategy: 'phone_code', channel: undefined }).catch(err => { - handleError(err, [], card.setError); - return err; - }), + : () => signUp.preparePhoneNumberVerification({ strategy: 'phone_code', channel: undefined }), { name: 'signUp.preparePhoneNumberVerification', strategy: 'phone_code', @@ -48,6 +44,7 @@ export const SignUpPhoneCodeCard = withCardStateProvider(() => { }, { staleTime: 100, + onError: err => handleError(err, [], card.setError), }, ); From 487158c2a7a81ed2ac2180dc14e9300251fa05ed Mon Sep 17 00:00:00 2001 From: panteliselef Date: Wed, 3 Sep 2025 13:28:16 +0300 Subject: [PATCH 5/6] onError when error is not defined --- packages/clerk-js/src/ui/hooks/useFetch.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/clerk-js/src/ui/hooks/useFetch.ts b/packages/clerk-js/src/ui/hooks/useFetch.ts index 97f9a424706..a276a79c24b 100644 --- a/packages/clerk-js/src/ui/hooks/useFetch.ts +++ b/packages/clerk-js/src/ui/hooks/useFetch.ts @@ -167,7 +167,7 @@ export const useFetch = ( }, waitTime); } }) - .catch((e: Error) => { + .catch((e: Error | null) => { setCache({ data: getCache()?.data ?? null, isLoading: false, @@ -175,7 +175,9 @@ export const useFetch = ( error: e, cachedAt: Date.now(), }); - options?.onError?.(e); + if (e) { + options?.onError?.(e); + } }); }, [serialize(params), setCache, getCache, revalidateCache]); From 51340a1ef89945599c070d24899353cfa9466c7c Mon Sep 17 00:00:00 2001 From: panteliselef Date: Wed, 3 Sep 2025 16:23:48 +0300 Subject: [PATCH 6/6] fix test --- .../__tests__/SignInFactorOneCodeForm.spec.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOneCodeForm.spec.tsx b/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOneCodeForm.spec.tsx index 26eb2d40699..734502c1323 100644 --- a/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOneCodeForm.spec.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/__tests__/SignInFactorOneCodeForm.spec.tsx @@ -56,9 +56,11 @@ describe('SignInFactorOneCodeForm', () => { name: 'signIn.prepareFirstFactor', factorKey: 'phone_code_idn_123', }, - { + expect.objectContaining({ staleTime: 100, - }, + onSuccess: expect.any(Function), + onError: expect.any(Function), + }), ); }); @@ -91,9 +93,11 @@ describe('SignInFactorOneCodeForm', () => { name: 'signIn.prepareFirstFactor', factorKey: 'phone_code_idn_123_whatsapp', }, - { + expect.objectContaining({ staleTime: 100, - }, + onSuccess: expect.any(Function), + onError: expect.any(Function), + }), ); });