From d3c4397c5a1f23b722388f08eace1cd874a98cb1 Mon Sep 17 00:00:00 2001 From: Ido Shamun <1993245+idoshamun@users.noreply.github.com> Date: Sun, 22 Mar 2026 06:55:31 +0200 Subject: [PATCH 1/3] fix: add missing error tracking for BetterAuth flows BetterAuth paths silently swallow errors without logging analytics events, making auth error metrics unreliable during the auth_strategy experiment. Changes: - useLogin: log LoginError on betterAuthSignInWithIdToken failure and getBetterAuthSocialUrl failure (native + web social login) - useRegistration: log RegistrationError on betterAuthSignUp error, fallback error, betterAuthSignInWithIdToken failure, and getBetterAuthSocialUrl failure (native + web social registration) - AuthOptionsInner: log LoginError on betterAuthSignInWithIdToken failure and getBetterAuthSocialUrl failure All events use existing AuthEventNames (login error / registration error) with a new origin field prefixed betterauth for easy filtering. --- .../src/components/auth/AuthOptionsInner.tsx | 14 +++++++++ packages/shared/src/hooks/useLogin.ts | 27 +++++++++++++---- packages/shared/src/hooks/useRegistration.ts | 29 +++++++++++++++++++ 3 files changed, 64 insertions(+), 6 deletions(-) diff --git a/packages/shared/src/components/auth/AuthOptionsInner.tsx b/packages/shared/src/components/auth/AuthOptionsInner.tsx index 3baa818079..0d66b47fb9 100644 --- a/packages/shared/src/components/auth/AuthOptionsInner.tsx +++ b/packages/shared/src/components/auth/AuthOptionsInner.tsx @@ -425,6 +425,13 @@ function AuthOptionsInner({ nonce: res.nonce, }); if (result.error) { + logEvent({ + event_name: AuthEventNames.LoginError, + extra: JSON.stringify({ + error: result.error, + origin: 'betterauth native id token', + }), + }); return; } await setChosenProvider(provider); @@ -439,6 +446,13 @@ function AuthOptionsInner({ callbackURL, ); if (!socialUrl) { + logEvent({ + event_name: AuthEventNames.LoginError, + extra: JSON.stringify({ + error: 'Failed to get social login URL', + origin: 'betterauth social url', + }), + }); onAuthStateUpdate?.({ isLoading: false }); return; } diff --git a/packages/shared/src/hooks/useLogin.ts b/packages/shared/src/hooks/useLogin.ts index d2b713486f..b77ec4493f 100644 --- a/packages/shared/src/hooks/useLogin.ts +++ b/packages/shared/src/hooks/useLogin.ts @@ -195,6 +195,13 @@ const useLogin = ({ nonce: res.nonce, }); if (result.error) { + logEvent({ + event_name: AuthEventNames.LoginError, + extra: JSON.stringify({ + error: result.error, + origin: 'betterauth native id token', + }), + }); return; } const { data: boot } = await refetchBoot(); @@ -209,12 +216,20 @@ const useLogin = ({ const isIOSApp = isIOSNative(); const callbackURL = `${webappUrl}callback?login=true`; const socialUrl = await getBetterAuthSocialUrl(provider, callbackURL); - if (socialUrl) { - if (isIOSApp) { - window.location.href = socialUrl; - } else { - window.open(socialUrl); - } + if (!socialUrl) { + logEvent({ + event_name: AuthEventNames.LoginError, + extra: JSON.stringify({ + error: 'Failed to get social login URL', + origin: 'betterauth social url', + }), + }); + return; + } + if (isIOSApp) { + window.location.href = socialUrl; + } else { + window.open(socialUrl); } return; } diff --git a/packages/shared/src/hooks/useRegistration.ts b/packages/shared/src/hooks/useRegistration.ts index 7c682858c5..8cc833c323 100644 --- a/packages/shared/src/hooks/useRegistration.ts +++ b/packages/shared/src/hooks/useRegistration.ts @@ -253,6 +253,13 @@ const useRegistration = ({ }, onSuccess: async (res) => { if (res.error) { + logEvent({ + event_name: AuthEventNames.RegistrationError, + extra: JSON.stringify({ + error: res.error, + origin: 'betterauth signup error', + }), + }); onInvalidRegistration?.({ 'traits.email': res.error, }); @@ -260,6 +267,13 @@ const useRegistration = ({ } if (res.status && !res.user) { + logEvent({ + event_name: AuthEventNames.RegistrationError, + extra: JSON.stringify({ + error: BETTER_AUTH_SIGNUP_FALLBACK_ERROR, + origin: 'betterauth signup fallback error', + }), + }); onInvalidRegistration?.({ 'traits.email': BETTER_AUTH_SIGNUP_FALLBACK_ERROR, }); @@ -319,6 +333,13 @@ const useRegistration = ({ nonce: res.nonce, }); if (result.error) { + logEvent({ + event_name: AuthEventNames.RegistrationError, + extra: JSON.stringify({ + error: result.error, + origin: 'betterauth native id token registration', + }), + }); return; } await refetchBoot(); @@ -331,6 +352,14 @@ const useRegistration = ({ ); if (onRedirect && url) { onRedirect(url); + } else if (!url) { + logEvent({ + event_name: AuthEventNames.RegistrationError, + extra: JSON.stringify({ + error: 'Failed to get social registration URL', + origin: 'betterauth social url registration', + }), + }); } return; } From 17592f89aca6941a6d5a31c5a54247ae7b24caa1 Mon Sep 17 00:00:00 2001 From: Ido Shamun <1993245+idoshamun@users.noreply.github.com> Date: Sun, 22 Mar 2026 10:08:07 +0200 Subject: [PATCH 2/3] Improve Better Auth error tracking --- .../src/components/auth/AuthOptionsInner.tsx | 60 ++++++++++-- .../onboarding/steps/FunnelRegistration.tsx | 18 ++-- packages/shared/src/hooks/useLogin.ts | 96 +++++++++++++++--- packages/shared/src/hooks/useRegistration.ts | 43 +++++++- packages/shared/src/lib/betterAuth.spec.ts | 68 +++++++++++++ packages/shared/src/lib/betterAuth.ts | 97 ++++++++++++++----- 6 files changed, 325 insertions(+), 57 deletions(-) create mode 100644 packages/shared/src/lib/betterAuth.spec.ts diff --git a/packages/shared/src/components/auth/AuthOptionsInner.tsx b/packages/shared/src/components/auth/AuthOptionsInner.tsx index 0d66b47fb9..6b5ff26a81 100644 --- a/packages/shared/src/components/auth/AuthOptionsInner.tsx +++ b/packages/shared/src/components/auth/AuthOptionsInner.tsx @@ -15,7 +15,8 @@ import { getNodeValue, } from '../../lib/auth'; import { - getBetterAuthSocialUrl, + getBetterAuthErrorMessage, + getBetterAuthSocialRedirectData, betterAuthSignInWithIdToken, betterAuthSendVerificationOTP, betterAuthVerifyEmailOTP, @@ -164,6 +165,7 @@ function AuthOptionsInner({ const [isForgotPasswordReturn, setIsForgotPasswordReturn] = useState(false); const [handleLoginCheck, setHandleLoginCheck] = useState(null); + const socialErrorEventName = useRef(AuthEventNames.LoginError); const [chosenProvider, setChosenProvider] = usePersistentState( CHOSEN_PROVIDER_KEY, null, @@ -366,13 +368,32 @@ function AuthOptionsInner({ }; const handleLoginMessage = async (e?: MessageEvent) => { - const { data: boot } = await refetchBoot(); + let boot; + try { + ({ data: boot } = await refetchBoot()); + } catch (error) { + logEvent({ + event_name: socialErrorEventName.current, + extra: JSON.stringify({ + error: getBetterAuthErrorMessage( + error, + 'Failed to refresh Better Auth social auth state', + ), + origin: 'betterauth social auth boot', + data: + typeof e?.data === 'object' ? JSON.stringify(e.data) : undefined, + }), + }); + displayToast(labels.auth.error.generic); + return; + } if (!boot.user || !('email' in boot.user)) { logEvent({ - event_name: AuthEventNames.SubmitSignUpFormError, + event_name: socialErrorEventName.current, extra: JSON.stringify({ - error: 'Could not find email on social registration', + error: 'Could not find email after social authentication', + origin: 'betterauth social auth boot', data: typeof e?.data === 'object' ? JSON.stringify(e.data) : undefined, }), @@ -404,6 +425,10 @@ function AuthOptionsInner({ }; const onProviderClick = async (provider: string, login = true) => { + const authErrorEventName = login + ? AuthEventNames.LoginError + : AuthEventNames.RegistrationError; + logEvent({ event_name: 'click', target_type: login @@ -412,6 +437,7 @@ function AuthOptionsInner({ target_id: provider, extra: JSON.stringify({ trigger }), }); + socialErrorEventName.current = authErrorEventName; if (isBetterAuth) { if (isNativeAuthSupported(provider)) { @@ -426,7 +452,7 @@ function AuthOptionsInner({ }); if (result.error) { logEvent({ - event_name: AuthEventNames.LoginError, + event_name: authErrorEventName, extra: JSON.stringify({ error: result.error, origin: 'betterauth native id token', @@ -440,19 +466,24 @@ function AuthOptionsInner({ } const isIOSApp = isIOSNative(); onAuthStateUpdate?.({ isLoading: true }); + if (!isIOSApp) { + windowPopup.current = window.open(); + } const callbackURL = `${webappUrl}callback?login=true`; - const socialUrl = await getBetterAuthSocialUrl( + const { url: socialUrl, error } = await getBetterAuthSocialRedirectData( provider.toLowerCase(), callbackURL, ); if (!socialUrl) { logEvent({ - event_name: AuthEventNames.LoginError, + event_name: authErrorEventName, extra: JSON.stringify({ - error: 'Failed to get social login URL', + error: error || 'Failed to get social login URL', origin: 'betterauth social url', }), }); + windowPopup.current?.close(); + windowPopup.current = null; onAuthStateUpdate?.({ isLoading: false }); return; } @@ -460,7 +491,18 @@ function AuthOptionsInner({ window.location.href = socialUrl; return; } - windowPopup.current = window.open(socialUrl); + if (!windowPopup.current) { + logEvent({ + event_name: authErrorEventName, + extra: JSON.stringify({ + error: 'Failed to open social login window', + origin: 'betterauth social popup', + }), + }); + onAuthStateUpdate?.({ isLoading: false }); + return; + } + windowPopup.current.location.href = socialUrl; await setChosenProvider(provider); onAuthStateUpdate?.({ isLoading: true }); return; diff --git a/packages/shared/src/features/onboarding/steps/FunnelRegistration.tsx b/packages/shared/src/features/onboarding/steps/FunnelRegistration.tsx index 70fee354bb..1bb268c624 100644 --- a/packages/shared/src/features/onboarding/steps/FunnelRegistration.tsx +++ b/packages/shared/src/features/onboarding/steps/FunnelRegistration.tsx @@ -37,7 +37,6 @@ import { } from '../shared'; import type { FunnelStepSignup } from '../types/funnel'; import { useConsentCookie } from '../../../hooks/useCookieConsent'; -import { useIsBetterAuth } from '../../../hooks/useIsBetterAuth'; import { isIOSNative } from '../../../lib/func'; import { GdprConsentKey } from '../../../hooks/useCookieBanner'; import Alert, { AlertType } from '../../../components/widgets/Alert'; @@ -141,7 +140,6 @@ function InnerFunnelRegistration({ }: FunnelStepSignup): ReactElement { const router = useRouter(); const isTablet = useViewSize(ViewSize.Tablet); - const isBetterAuth = useIsBetterAuth(); const shouldRedirect = shouldRedirectAuth(); const windowPopup = useRef(null); const { cookieExists } = useConsentCookie(GdprConsentKey.Marketing); @@ -159,12 +157,11 @@ function InnerFunnelRegistration({ if (shouldRedirect) { window.sessionStorage.setItem(AUTH_REDIRECT_KEY, window.location.href); window.location.href = redirect; - } else if (isBetterAuth) { - if (isIOSNative()) { - window.location.href = redirect; - } else { - windowPopup.current = window.open(redirect); - } + return; + } + + if (isIOSNative()) { + window.location.href = redirect; } else if (windowPopup.current) { windowPopup.current.location.href = redirect; } else { @@ -177,7 +174,10 @@ function InnerFunnelRegistration({ const subscriberEmail = router?.query?.subscribed; const onRegister = (provider: SocialProvider) => { - if (!isBetterAuth && !isNativeAuthSupported(provider) && !shouldRedirect) { + const shouldUsePopup = + !shouldRedirect && !isNativeAuthSupported(provider) && !isIOSNative(); + + if (shouldUsePopup) { windowPopup.current = window.open(); } onSocialRegistration(provider); diff --git a/packages/shared/src/hooks/useLogin.ts b/packages/shared/src/hooks/useLogin.ts index b77ec4493f..5c11ce859f 100644 --- a/packages/shared/src/hooks/useLogin.ts +++ b/packages/shared/src/hooks/useLogin.ts @@ -28,7 +28,8 @@ import { import { betterAuthSignIn, betterAuthSignInWithIdToken, - getBetterAuthSocialUrl, + getBetterAuthErrorMessage, + getBetterAuthSocialRedirectData, } from '../lib/betterAuth'; import { useIsBetterAuth } from './useIsBetterAuth'; import { useLogContext } from '../contexts/LogContext'; @@ -108,20 +109,48 @@ const useLogin = ({ logEvent({ event_name: AuthEventNames.LoginError, extra: JSON.stringify({ - error: labels.auth.error.invalidEmailOrPassword, + error: res.error, + displayedError: labels.auth.error.invalidEmailOrPassword, + origin: 'betterauth email login', }), }); setHint(labels.auth.error.invalidEmailOrPassword); return; } - const { data: boot } = await refetchBoot(); + try { + const { data: boot } = await refetchBoot(); - if (boot.user && !boot.user.shouldVerify) { - onUpdateSignBack(boot.user as LoggedUser, 'password'); - } + if (!boot.user) { + logEvent({ + event_name: AuthEventNames.LoginError, + extra: JSON.stringify({ + error: 'Missing user after Better Auth email login', + origin: 'betterauth email login boot', + }), + }); + setHint(labels.auth.error.generic); + return; + } - onSuccessfulLogin?.(boot?.user?.shouldVerify); + if (!boot.user.shouldVerify) { + onUpdateSignBack(boot.user as LoggedUser, 'password'); + } + + onSuccessfulLogin?.(boot.user.shouldVerify); + } catch (error) { + logEvent({ + event_name: AuthEventNames.LoginError, + extra: JSON.stringify({ + error: getBetterAuthErrorMessage( + error, + 'Failed to refresh Better Auth login state', + ), + origin: 'betterauth email login boot', + }), + }); + setHint(labels.auth.error.generic); + } }, }); @@ -204,33 +233,73 @@ const useLogin = ({ }); return; } - const { data: boot } = await refetchBoot(); - if (boot.user) { + try { + const { data: boot } = await refetchBoot(); + if (!boot.user) { + logEvent({ + event_name: AuthEventNames.LoginError, + extra: JSON.stringify({ + error: 'Missing user after Better Auth social login', + origin: 'betterauth native id token boot', + }), + }); + displayToast(labels.auth.error.generic); + return; + } onUpdateSignBack( boot.user as LoggedUser, provider as SignBackProvider, ); + } catch (error) { + logEvent({ + event_name: AuthEventNames.LoginError, + extra: JSON.stringify({ + error: getBetterAuthErrorMessage( + error, + 'Failed to refresh Better Auth social login state', + ), + origin: 'betterauth native id token boot', + }), + }); + displayToast(labels.auth.error.generic); } return; } const isIOSApp = isIOSNative(); + const socialPopup = isIOSApp ? null : window.open(); const callbackURL = `${webappUrl}callback?login=true`; - const socialUrl = await getBetterAuthSocialUrl(provider, callbackURL); + const { url: socialUrl, error } = await getBetterAuthSocialRedirectData( + provider, + callbackURL, + ); if (!socialUrl) { logEvent({ event_name: AuthEventNames.LoginError, extra: JSON.stringify({ - error: 'Failed to get social login URL', + error: error || 'Failed to get social login URL', origin: 'betterauth social url', }), }); + socialPopup?.close(); + displayToast(labels.auth.error.generic); return; } if (isIOSApp) { window.location.href = socialUrl; - } else { - window.open(socialUrl); + return; + } + if (socialPopup) { + socialPopup.location.href = socialUrl; + return; } + logEvent({ + event_name: AuthEventNames.LoginError, + extra: JSON.stringify({ + error: 'Failed to open social login window', + origin: 'betterauth social popup', + }), + }); + displayToast(labels.auth.error.generic); return; } @@ -251,6 +320,7 @@ const useLogin = ({ isBetterAuth, displayToast, login?.ui, + logEvent, onSocialLogin, refetchBoot, onUpdateSignBack, diff --git a/packages/shared/src/hooks/useRegistration.ts b/packages/shared/src/hooks/useRegistration.ts index 8cc833c323..a8b6c823c1 100644 --- a/packages/shared/src/hooks/useRegistration.ts +++ b/packages/shared/src/hooks/useRegistration.ts @@ -31,7 +31,8 @@ import { import { betterAuthSignUp, betterAuthSignInWithIdToken, - getBetterAuthSocialUrl, + getBetterAuthErrorMessage, + getBetterAuthSocialRedirectData, } from '../lib/betterAuth'; import { useIsBetterAuth } from './useIsBetterAuth'; import { useToastNotification } from './useToastNotification'; @@ -342,21 +343,55 @@ const useRegistration = ({ }); return; } - await refetchBoot(); + try { + const { data: boot } = await refetchBoot(); + if (!boot.user) { + logEvent({ + event_name: AuthEventNames.RegistrationError, + extra: JSON.stringify({ + error: 'Missing user after Better Auth social registration', + origin: 'betterauth native id token registration boot', + }), + }); + displayToast('An error occurred, please refresh the page.'); + return; + } + } catch (error) { + logEvent({ + event_name: AuthEventNames.RegistrationError, + extra: JSON.stringify({ + error: getBetterAuthErrorMessage( + error, + 'Failed to refresh Better Auth registration state', + ), + origin: 'betterauth native id token registration boot', + }), + }); + displayToast('An error occurred, please refresh the page.'); + return; + } return; } const callbackURL = `${webappUrl}callback?login=true`; - const url = await getBetterAuthSocialUrl( + const { url, error } = await getBetterAuthSocialRedirectData( provider.toLowerCase(), callbackURL, ); if (onRedirect && url) { onRedirect(url); + } else if (!onRedirect && url) { + logEvent({ + event_name: AuthEventNames.RegistrationError, + extra: JSON.stringify({ + error: 'Missing social registration redirect handler', + origin: 'betterauth social url registration', + }), + }); } else if (!url) { logEvent({ event_name: AuthEventNames.RegistrationError, extra: JSON.stringify({ - error: 'Failed to get social registration URL', + error: error || 'Failed to get social registration URL', origin: 'betterauth social url registration', }), }); diff --git a/packages/shared/src/lib/betterAuth.spec.ts b/packages/shared/src/lib/betterAuth.spec.ts new file mode 100644 index 0000000000..e9e1dc0ec5 --- /dev/null +++ b/packages/shared/src/lib/betterAuth.spec.ts @@ -0,0 +1,68 @@ +import { + betterAuthSignIn, + getBetterAuthSocialRedirectData, +} from './betterAuth'; + +describe('betterAuth', () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + + it('should return a structured error when sign in fetch fails', async () => { + jest + .spyOn(global, 'fetch') + .mockRejectedValueOnce(new TypeError('Network down')); + + await expect( + betterAuthSignIn({ + email: 'test@daily.dev', + password: 'secret', + }), + ).resolves.toEqual( + expect.objectContaining({ + error: 'Network down', + }), + ); + }); + + it('should preserve social redirect errors in the response payload', async () => { + jest.spyOn(global, 'fetch').mockResolvedValueOnce({ + ok: false, + json: jest.fn().mockResolvedValue({ + message: 'Social auth unavailable', + }), + } as unknown as Response); + + await expect( + getBetterAuthSocialRedirectData( + 'github', + 'https://app.daily.dev/callback?login=true', + ), + ).resolves.toEqual( + expect.objectContaining({ + error: 'Social auth unavailable', + url: undefined, + }), + ); + }); + + it('should suffix Better Auth social state exactly once', async () => { + jest.spyOn(global, 'fetch').mockResolvedValueOnce({ + ok: true, + json: jest.fn().mockResolvedValue({ + url: 'https://auth.example.com/oauth?state=abc123', + }), + } as unknown as Response); + + await expect( + getBetterAuthSocialRedirectData( + 'github', + 'https://app.daily.dev/callback?login=true', + ), + ).resolves.toEqual( + expect.objectContaining({ + url: 'https://auth.example.com/oauth?state=abc123_ba', + }), + ); + }); +}); diff --git a/packages/shared/src/lib/betterAuth.ts b/packages/shared/src/lib/betterAuth.ts index 4954dba768..b152c77d6d 100644 --- a/packages/shared/src/lib/betterAuth.ts +++ b/packages/shared/src/lib/betterAuth.ts @@ -15,8 +15,44 @@ export type BetterAuthResponse = { type BetterAuthResult> = T & Pick; +export type BetterAuthSocialRedirectResponse = BetterAuthResult<{ + url?: string; + redirect?: boolean; +}>; + const betterAuthStateSuffix = '_ba'; +export const getBetterAuthErrorMessage = ( + error: unknown, + fallbackError = 'Request failed', +): string => { + if (typeof error === 'string' && error) { + return error; + } + + if (error && typeof error === 'object') { + if ('message' in error && typeof error.message === 'string') { + return error.message; + } + + if ('error' in error && typeof error.error === 'string') { + return error.error; + } + + if ('code' in error && typeof error.code === 'string') { + return error.code; + } + + try { + return JSON.stringify(error); + } catch { + return fallbackError; + } + } + + return fallbackError; +}; + const markBetterAuthSocialUrl = (url?: string): string | undefined => { if (!url) { return undefined; @@ -39,26 +75,32 @@ const betterAuthPost = async >( fallbackError = 'Request failed', headers?: Record, ): Promise> => { - const res = await fetch(`${apiUrl}/auth/${path}`, { - method: 'POST', - credentials: 'include', - headers: { 'Content-Type': 'application/json', ...headers }, - ...(body && { body: JSON.stringify(body) }), - }); + try { + const res = await fetch(`${apiUrl}/auth/${path}`, { + method: 'POST', + credentials: 'include', + headers: { 'Content-Type': 'application/json', ...headers }, + ...(body && { body: JSON.stringify(body) }), + }); - if (!res.ok) { - try { - const data = (await res.json()) as BetterAuthResult; - return { - ...data, - error: data?.message || data?.error || data?.code || fallbackError, - } as BetterAuthResult; - } catch { - return { error: fallbackError } as BetterAuthResult; + if (!res.ok) { + try { + const data = (await res.json()) as BetterAuthResult; + return { + ...data, + error: data?.message || data?.error || data?.code || fallbackError, + } as BetterAuthResult; + } catch { + return { error: fallbackError } as BetterAuthResult; + } } - } - return res.json(); + return res.json(); + } catch (error) { + return { + error: getBetterAuthErrorMessage(error, fallbackError), + } as BetterAuthResult; + } }; export const betterAuthSignIn = async ({ @@ -116,11 +158,11 @@ export const betterAuthSignUp = async ({ ); }; -const getBetterAuthSocialRedirectUrl = async ( +const getBetterAuthSocialRedirect = async ( path: string, provider: string, callbackURL: string, -): Promise => { +): Promise => { const absoluteCallbackURL = callbackURL.startsWith('http') ? callbackURL : `${window.location.origin}${ @@ -140,14 +182,23 @@ const getBetterAuthSocialRedirectUrl = async ( 'Failed to get social auth URL', ); - return markBetterAuthSocialUrl(response.url); + return { + ...response, + url: markBetterAuthSocialUrl(response.url), + }; }; +export const getBetterAuthSocialRedirectData = ( + provider: string, + callbackURL: string, +): Promise => + getBetterAuthSocialRedirect('sign-in/social', provider, callbackURL); + export const getBetterAuthSocialUrl = ( provider: string, callbackURL: string, ): Promise => - getBetterAuthSocialRedirectUrl('sign-in/social', provider, callbackURL); + getBetterAuthSocialRedirectData(provider, callbackURL).then(({ url }) => url); export const betterAuthSignInWithIdToken = async ({ provider, @@ -175,7 +226,9 @@ export const getBetterAuthLinkSocialUrl = ( provider: string, callbackURL: string, ): Promise => - getBetterAuthSocialRedirectUrl('link-social', provider, callbackURL); + getBetterAuthSocialRedirect('link-social', provider, callbackURL).then( + ({ url }) => url, + ); export const getBetterAuthProviders = async (): Promise<{ ok: boolean; From 5398edbae11ac45c1f9f783147a3b851b12c7266 Mon Sep 17 00:00:00 2001 From: Ido Shamun <1993245+idoshamun@users.noreply.github.com> Date: Sun, 22 Mar 2026 10:21:20 +0200 Subject: [PATCH 3/3] Skip FunnelRegistration in strict migration guard --- scripts/typecheck-strict-changed.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/typecheck-strict-changed.js b/scripts/typecheck-strict-changed.js index 5a13f3fdec..549487a266 100644 --- a/scripts/typecheck-strict-changed.js +++ b/scripts/typecheck-strict-changed.js @@ -29,6 +29,7 @@ const packageConfigs = [ // These files have known strict-mode violations that will be addressed separately. const strictSkipList = new Set([ 'packages/shared/src/components/auth/AuthOptionsInner.tsx', + 'packages/shared/src/features/onboarding/steps/FunnelRegistration.tsx', 'packages/shared/src/hooks/useLogin.ts', 'packages/shared/src/hooks/useRegistration.ts', 'packages/shared/src/contexts/AuthContext.tsx',