Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

[Session] Track agent in state (#3833)

* Expand currentAccountDid into currentAgentState

* Inline all callsites of upsertAccount

* Inline all internal callsites of clearCurrentAccount

* Add agent to currentAgentState

* Collapse extra setStates

* Add TODOs

authored by

dan and committed by
GitHub
0f827c32 a9af8369

+139 -47
+139 -47
src/state/session/index.tsx
··· 56 56 return __globalAgent 57 57 } 58 58 59 + type AgentState = { 60 + readonly agent: BskyAgent 61 + readonly did: string | undefined 62 + } 63 + 59 64 type State = { 60 65 accounts: SessionStateContext['accounts'] 61 - currentAccountDid: string | undefined 66 + currentAgentState: AgentState 62 67 needsPersist: boolean 63 68 } 64 69 65 70 export function Provider({children}: React.PropsWithChildren<{}>) { 66 - const [state, setState] = React.useState<State>({ 71 + const [state, setState] = React.useState<State>(() => ({ 67 72 accounts: persisted.get('session').accounts, 68 - currentAccountDid: undefined, // assume logged out to start 73 + currentAgentState: { 74 + agent: PUBLIC_BSKY_AGENT, 75 + did: undefined, // assume logged out to start 76 + }, 69 77 needsPersist: false, 70 - }) 71 - 72 - const upsertAccount = React.useCallback( 73 - (account: SessionAccount, expired = false) => { 74 - setState(s => { 75 - return { 76 - accounts: [account, ...s.accounts.filter(a => a.did !== account.did)], 77 - currentAccountDid: expired ? undefined : account.did, 78 - needsPersist: true, 79 - } 80 - }) 81 - }, 82 - [setState], 83 - ) 78 + })) 84 79 85 80 const clearCurrentAccount = React.useCallback(() => { 86 81 logger.warn(`session: clear current account`) ··· 88 83 configureModerationForGuest() 89 84 setState(s => ({ 90 85 accounts: s.accounts, 91 - currentAccountDid: undefined, 86 + currentAgentState: { 87 + agent: PUBLIC_BSKY_AGENT, 88 + did: undefined, 89 + }, 92 90 needsPersist: true, 93 91 })) 94 92 }, [setState]) ··· 106 104 logger.warn( 107 105 `session: persistSessionHandler received network-error event`, 108 106 ) 109 - clearCurrentAccount() 107 + logger.warn(`session: clear current account`) 108 + __globalAgent = PUBLIC_BSKY_AGENT 109 + configureModerationForGuest() 110 + setState(s => ({ 111 + accounts: s.accounts, 112 + currentAgentState: { 113 + agent: PUBLIC_BSKY_AGENT, 114 + did: undefined, 115 + }, 116 + needsPersist: true, 117 + })) 110 118 return 111 119 } 112 120 ··· 149 157 * to persist this data and wipe their tokens, effectively logging them 150 158 * out. 151 159 */ 152 - upsertAccount(refreshedAccount, expired) 160 + setState(s => { 161 + return { 162 + accounts: [ 163 + refreshedAccount, 164 + ...s.accounts.filter(a => a.did !== refreshedAccount.did), 165 + ], 166 + currentAgentState: expired 167 + ? { 168 + agent: PUBLIC_BSKY_AGENT, 169 + did: undefined, 170 + } 171 + : s.currentAgentState, 172 + needsPersist: true, 173 + } 174 + }) 153 175 }, 154 - [clearCurrentAccount, upsertAccount], 176 + [], 155 177 ) 156 178 157 179 const createAccount = React.useCallback<SessionApiContext['createAccount']>( ··· 185 207 186 208 __globalAgent = agent 187 209 await fetchingGates 188 - upsertAccount(account) 210 + setState(s => { 211 + return { 212 + accounts: [account, ...s.accounts.filter(a => a.did !== account.did)], 213 + currentAgentState: { 214 + did: account.did, 215 + agent: agent, 216 + }, 217 + needsPersist: true, 218 + } 219 + }) 189 220 190 221 logger.debug(`session: created account`, {}, logger.DebugContext.session) 191 222 track('Create Account') 192 223 logEvent('account:create:success', {}) 193 224 }, 194 - [upsertAccount, onAgentSessionChange], 225 + [onAgentSessionChange], 195 226 ) 196 227 197 228 const login = React.useCallback<SessionApiContext['login']>( ··· 212 243 // @ts-ignore 213 244 if (IS_DEV && isWeb) window.agent = agent 214 245 await fetchingGates 215 - upsertAccount(account) 246 + setState(s => { 247 + return { 248 + accounts: [account, ...s.accounts.filter(a => a.did !== account.did)], 249 + currentAgentState: { 250 + did: account.did, 251 + agent: agent, 252 + }, 253 + needsPersist: true, 254 + } 255 + }) 216 256 217 257 logger.debug(`session: logged in`, {}, logger.DebugContext.session) 218 258 219 259 track('Sign In', {resumedSession: false}) 220 260 logEvent('account:loggedIn', {logContext, withPassword: true}) 221 261 }, 222 - [upsertAccount, onAgentSessionChange], 262 + [onAgentSessionChange], 223 263 ) 224 264 225 265 const logout = React.useCallback<SessionApiContext['logout']>( 226 266 async logContext => { 227 267 logger.debug(`session: logout`) 228 - clearCurrentAccount() 268 + logger.warn(`session: clear current account`) 269 + __globalAgent = PUBLIC_BSKY_AGENT 270 + configureModerationForGuest() 229 271 setState(s => { 230 272 return { 231 273 accounts: s.accounts.map(a => ({ ··· 233 275 refreshJwt: undefined, 234 276 accessJwt: undefined, 235 277 })), 236 - currentAccountDid: s.currentAccountDid, 278 + currentAgentState: { 279 + did: undefined, 280 + agent: PUBLIC_BSKY_AGENT, 281 + }, 237 282 needsPersist: true, 238 283 } 239 284 }) 240 285 logEvent('account:loggedOut', {logContext}) 241 286 }, 242 - [clearCurrentAccount, setState], 287 + [setState], 243 288 ) 244 289 245 290 const initSession = React.useCallback<SessionApiContext['initSession']>( ··· 279 324 const freshAccount = await resumeSessionWithFreshAccount() 280 325 __globalAgent = agent 281 326 await fetchingGates 282 - upsertAccount(freshAccount) 327 + setState(s => { 328 + return { 329 + accounts: [ 330 + freshAccount, 331 + ...s.accounts.filter(a => a.did !== freshAccount.did), 332 + ], 333 + currentAgentState: { 334 + did: freshAccount.did, 335 + agent: agent, 336 + }, 337 + needsPersist: true, 338 + } 339 + }) 283 340 } catch (e) { 284 341 /* 285 342 * Note: `agent.persistSession` is also called when this fails, and ··· 290 347 }) 291 348 292 349 __globalAgent = PUBLIC_BSKY_AGENT 293 - // TODO: Should this update currentAccountDid? 350 + // TODO: This needs a setState. 294 351 } 295 352 } else { 296 353 logger.debug(`session: attempting to reuse previous session`) ··· 299 356 300 357 __globalAgent = agent 301 358 await fetchingGates 302 - upsertAccount(account) 359 + setState(s => { 360 + return { 361 + accounts: [ 362 + account, 363 + ...s.accounts.filter(a => a.did !== account.did), 364 + ], 365 + currentAgentState: { 366 + did: account.did, 367 + agent: agent, 368 + }, 369 + needsPersist: true, 370 + } 371 + }) 303 372 304 373 if (accountOrSessionDeactivated) { 305 374 // don't attempt to resume ··· 315 384 logger.info( 316 385 `session: reuse of previous session returned a fresh account, upserting`, 317 386 ) 318 - upsertAccount(freshAccount) 387 + setState(s => { 388 + return { 389 + accounts: [ 390 + freshAccount, 391 + ...s.accounts.filter(a => a.did !== freshAccount.did), 392 + ], 393 + currentAgentState: { 394 + did: freshAccount.did, 395 + agent: agent, 396 + }, 397 + needsPersist: true, 398 + } 399 + }) 319 400 } 320 401 }) 321 402 .catch(e => { ··· 328 409 }) 329 410 330 411 __globalAgent = PUBLIC_BSKY_AGENT 331 - // TODO: Should this update currentAccountDid? 412 + // TODO: This needs a setState. 332 413 }) 333 414 } 334 415 ··· 347 428 return sessionAccount 348 429 } 349 430 }, 350 - [upsertAccount, onAgentSessionChange], 431 + [onAgentSessionChange], 351 432 ) 352 433 353 434 const removeAccount = React.useCallback<SessionApiContext['removeAccount']>( ··· 355 436 setState(s => { 356 437 return { 357 438 accounts: s.accounts.filter(a => a.did !== account.did), 358 - currentAccountDid: s.currentAccountDid, 439 + currentAgentState: s.currentAgentState, 359 440 needsPersist: true, 360 441 } 361 442 }) ··· 369 450 account => { 370 451 setState(s => { 371 452 const currentAccount = s.accounts.find( 372 - a => a.did === s.currentAccountDid, 453 + a => a.did === s.currentAgentState.did, 373 454 ) 374 455 // ignore, should never happen 375 456 if (!currentAccount) return s ··· 393 474 updatedAccount, 394 475 ...s.accounts.filter(a => a.did !== currentAccount.did), 395 476 ], 396 - currentAccountDid: s.currentAccountDid, 477 + currentAgentState: s.currentAgentState, 397 478 needsPersist: true, 398 479 } 399 480 }) ··· 407 488 persisted.write('session', { 408 489 accounts: state.accounts, 409 490 currentAccount: state.accounts.find( 410 - a => a.did === state.currentAccountDid, 491 + a => a.did === state.currentAgentState.did, 411 492 ), 412 493 }) 413 494 } ··· 424 505 ) 425 506 426 507 if (selectedAccount && selectedAccount.refreshJwt) { 427 - if (selectedAccount.did !== state.currentAccountDid) { 508 + if (selectedAccount.did !== state.currentAgentState.did) { 428 509 logger.debug(`session: persisted onUpdate, switching accounts`, { 429 510 from: { 430 - did: state.currentAccountDid, 511 + did: state.currentAgentState.did, 431 512 }, 432 513 to: { 433 514 did: selectedAccount.did, ··· 445 526 */ 446 527 // @ts-ignore we checked for `refreshJwt` above 447 528 __globalAgent.session = selectedAccount 529 + // TODO: This needs a setState. 448 530 } 449 - } else if (!selectedAccount && state.currentAccountDid) { 531 + } else if (!selectedAccount && state.currentAgentState.did) { 450 532 logger.debug( 451 533 `session: persisted onUpdate, logging out`, 452 534 {}, ··· 459 541 * handled by `persistSession` (which nukes this accounts tokens only), 460 542 * or by a `logout` call which nukes all accounts tokens) 461 543 */ 462 - clearCurrentAccount() 544 + logger.warn(`session: clear current account`) 545 + __globalAgent = PUBLIC_BSKY_AGENT 546 + configureModerationForGuest() 547 + setState(s => ({ 548 + accounts: s.accounts, 549 + currentAgentState: { 550 + did: undefined, 551 + agent: PUBLIC_BSKY_AGENT, 552 + }, 553 + needsPersist: true, // TODO: This seems bad in this codepath. Existing behavior. 554 + })) 463 555 } 464 556 465 - setState(() => ({ 557 + setState(s => ({ 466 558 accounts: persistedSession.accounts, 467 - currentAccountDid: selectedAccount?.did, 559 + currentAgentState: s.currentAgentState, 468 560 needsPersist: false, // Synced from another tab. Don't persist to avoid cycles. 469 561 })) 470 562 }) 471 - }, [state, setState, clearCurrentAccount, initSession]) 563 + }, [state, setState, initSession]) 472 564 473 565 const stateContext = React.useMemo( 474 566 () => ({ 475 567 accounts: state.accounts, 476 568 currentAccount: state.accounts.find( 477 - a => a.did === state.currentAccountDid, 569 + a => a.did === state.currentAgentState.did, 478 570 ), 479 - hasSession: !!state.currentAccountDid, 571 + hasSession: !!state.currentAgentState.did, 480 572 }), 481 573 [state], 482 574 )