@@ -21,11 +21,14 @@ import {
2121 SecurityEvent ,
2222} from '../Account' ;
2323import { useLocalStorageSync } from '../../lib/hooks/useLocalStorageSync' ;
24+ import * as Sentry from '@sentry/browser' ;
2425import {
2526 getAccountData ,
2627 updateAccountData ,
2728 clearExtendedAccountState ,
2829 getCurrentAccountUid ,
30+ setCurrentAccountUid ,
31+ findLastActiveAccountUid ,
2932 UnifiedAccountData ,
3033} from '../../lib/account-storage' ;
3134
@@ -168,14 +171,36 @@ function unifiedToAccountState(
168171 } ;
169172}
170173
174+ /**
175+ * Recover the current account UID when it is missing from localStorage.
176+ * This primarily affects Firefox iOS where WKWebView storage eviction can
177+ * lose currentAccountUid while account data still exists.
178+ *
179+ * Recovery order: URL ?uid= param, then fallback UID, then scan for an
180+ * active session in accounts storage.
181+ */
182+ function recoverAccountUid ( fallbackUid ?: string | null ) : string | null {
183+ const urlUid = new URLSearchParams ( window . location . search ) . get ( 'uid' ) ;
184+ const recovered = urlUid || fallbackUid || findLastActiveAccountUid ( ) ;
185+ if ( recovered ) {
186+ setCurrentAccountUid ( recovered ) ;
187+ }
188+ return recovered ;
189+ }
190+
171191export function AccountStateProvider ( {
172192 children,
173193 initialState,
174194} : AccountStateProviderProps ) {
175195 // useLocalStorageSync triggers re-renders on storage changes;
176196 // we read from getAccountData() rather than the return value directly
177197 useLocalStorageSync ( 'accounts' ) ;
178- const currentAccountUid = useLocalStorageSync ( 'currentAccountUid' ) as string | undefined ;
198+ let currentAccountUid = useLocalStorageSync ( 'currentAccountUid' ) as string | undefined ;
199+
200+ // Recover UID when missing (iOS WKWebView storage eviction)
201+ if ( ! currentAccountUid ) {
202+ currentAccountUid = recoverAccountUid ( ) ?? undefined ;
203+ }
179204
180205 const accountState = unifiedToAccountState (
181206 getAccountData ( currentAccountUid ) ,
@@ -185,8 +210,24 @@ export function AccountStateProvider({
185210 // Serialize AccountState -> UnifiedAccountData for localStorage:
186211 // Set -> Array, Error -> {message,name}, exclude derived 'primaryEmail'
187212 const setAccountDataCallback = useCallback ( ( data : Partial < AccountState > ) => {
188- const uid = getCurrentAccountUid ( ) ;
189- if ( ! uid ) return ;
213+ let uid = getCurrentAccountUid ( ) ;
214+
215+ // Recover UID when currentAccountUid is missing
216+ if ( ! uid ) {
217+ uid = recoverAccountUid ( data . uid ) ;
218+ }
219+
220+ if ( ! uid ) {
221+ Sentry . captureMessage ( 'setAccountData called with no currentAccountUid' , {
222+ level : 'warning' ,
223+ extra : {
224+ pathname : window . location . pathname ,
225+ search : window . location . search ,
226+ hasAccountsKey : ! ! localStorage . getItem ( '__fxa_storage.accounts' ) ,
227+ } ,
228+ } ) ;
229+ return ;
230+ }
190231
191232 const { uid : dataUid , email : dataEmail , primaryEmail, ...rest } = data ;
192233 const storageData : Partial < UnifiedAccountData > = {
0 commit comments