Bluesky app fork with some witchin' additions 💫

[Session] Align state and global agent switchpoints (#3845)

* Adopt synced accounts unconditionally

* Remove try/catch around resuming session

* Move to login form on resume failure

* Restructure code flow for easier reading

---------

Co-authored-by: Eric Bailey <git@esb.lol>

authored by danabra.mov

Eric Bailey and committed by
GitHub
4a2d4253 85b34418

+50 -70
+2 -10
src/lib/hooks/useAccountSwitcher.ts
··· 15 15 const [pendingDid, setPendingDid] = useState<string | null>(null) 16 16 const {_} = useLingui() 17 17 const {track} = useAnalytics() 18 - const {initSession, clearCurrentAccount} = useSessionApi() 18 + const {initSession} = useSessionApi() 19 19 const {requestSwitchToAccount} = useLoggedOutViewControls() 20 20 21 21 const onPressSwitchAccount = useCallback( ··· 53 53 logger.error(`switch account: selectAccount failed`, { 54 54 message: e.message, 55 55 }) 56 - clearCurrentAccount() // back user out to login 57 56 } finally { 58 57 setPendingDid(null) 59 58 } 60 59 }, 61 - [ 62 - _, 63 - track, 64 - clearCurrentAccount, 65 - initSession, 66 - requestSwitchToAccount, 67 - pendingDid, 68 - ], 60 + [_, track, initSession, requestSwitchToAccount, pendingDid], 69 61 ) 70 62 71 63 return {onPressSwitchAccount, pendingDid}
+26 -24
src/screens/Login/ChooseAccountForm.tsx
··· 39 39 // The session API isn't resilient to race conditions so let's just ignore this. 40 40 return 41 41 } 42 - if (account.accessJwt) { 43 - if (account.did === currentAccount?.did) { 44 - setShowLoggedOut(false) 45 - Toast.show(_(msg`Already signed in as @${account.handle}`)) 46 - } else { 47 - try { 48 - setPendingDid(account.did) 49 - await initSession(account) 50 - logEvent('account:loggedIn', { 51 - logContext: 'ChooseAccountForm', 52 - withPassword: false, 53 - }) 54 - track('Sign In', {resumedSession: true}) 55 - Toast.show(_(msg`Signed in as @${account.handle}`)) 56 - } catch (e: any) { 57 - logger.error('choose account: initSession failed', { 58 - message: e.message, 59 - }) 60 - onSelectAccount(account) 61 - } finally { 62 - setPendingDid(null) 63 - } 64 - } 65 - } else { 42 + if (!account.accessJwt) { 43 + // Move to login form. 66 44 onSelectAccount(account) 45 + return 46 + } 47 + if (account.did === currentAccount?.did) { 48 + setShowLoggedOut(false) 49 + Toast.show(_(msg`Already signed in as @${account.handle}`)) 50 + return 51 + } 52 + try { 53 + setPendingDid(account.did) 54 + await initSession(account) 55 + logEvent('account:loggedIn', { 56 + logContext: 'ChooseAccountForm', 57 + withPassword: false, 58 + }) 59 + track('Sign In', {resumedSession: true}) 60 + Toast.show(_(msg`Signed in as @${account.handle}`)) 61 + } catch (e: any) { 62 + logger.error('choose account: initSession failed', { 63 + message: e.message, 64 + }) 65 + // Move to login form. 66 + onSelectAccount(account) 67 + } finally { 68 + setPendingDid(null) 67 69 } 68 70 }, 69 71 [
+22 -36
src/state/session/index.tsx
··· 337 337 if (isSessionExpired(account)) { 338 338 logger.debug(`session: attempting to resume using previous session`) 339 339 340 - try { 341 - const freshAccount = await resumeSessionWithFreshAccount() 342 - __globalAgent = agent 343 - await fetchingGates 344 - setState(s => { 345 - return { 346 - accounts: [ 347 - freshAccount, 348 - ...s.accounts.filter(a => a.did !== freshAccount.did), 349 - ], 350 - currentAgentState: { 351 - did: freshAccount.did, 352 - agent: agent, 353 - }, 354 - needsPersist: true, 355 - } 356 - }) 357 - } catch (e) { 358 - /* 359 - * Note: `agent.persistSession` is also called when this fails, and 360 - * we handle that failure via `createPersistSessionHandler` 361 - */ 362 - logger.info(`session: resumeSessionWithFreshAccount failed`, { 363 - message: e, 364 - }) 365 - 366 - __globalAgent = PUBLIC_BSKY_AGENT 367 - // TODO: This needs a setState. 368 - } 340 + const freshAccount = await resumeSessionWithFreshAccount() 341 + __globalAgent = agent 342 + await fetchingGates 343 + setState(s => { 344 + return { 345 + accounts: [ 346 + freshAccount, 347 + ...s.accounts.filter(a => a.did !== freshAccount.did), 348 + ], 349 + currentAgentState: { 350 + did: freshAccount.did, 351 + agent: agent, 352 + }, 353 + needsPersist: true, 354 + } 355 + }) 369 356 } else { 370 357 logger.debug(`session: attempting to reuse previous session`) 371 358 ··· 480 467 const persistedSession = persisted.get('session') 481 468 482 469 logger.debug(`session: persisted onUpdate`, {}) 470 + setState(s => ({ 471 + accounts: persistedSession.accounts, 472 + currentAgentState: s.currentAgentState, 473 + needsPersist: false, // Synced from another tab. Don't persist to avoid cycles. 474 + })) 483 475 484 476 const selectedAccount = persistedSession.accounts.find( 485 477 a => a.did === persistedSession.currentAccount?.did, ··· 531 523 did: undefined, 532 524 agent: PUBLIC_BSKY_AGENT, 533 525 }, 534 - needsPersist: true, // TODO: This seems bad in this codepath. Existing behavior. 526 + needsPersist: false, // Synced from another tab. Don't persist to avoid cycles. 535 527 })) 536 528 } 537 - 538 - setState(s => ({ 539 - accounts: persistedSession.accounts, 540 - currentAgentState: s.currentAgentState, 541 - needsPersist: false, // Synced from another tab. Don't persist to avoid cycles. 542 - })) 543 529 }) 544 530 }, [state, setState, initSession]) 545 531