Replace resumeSession with getSession in the email check (#8670)

* replace resumeSession with getSession

* copy lil type tweak from the other PR

* Add partialRefreshSession to session API context, use session state to infer state further down tree

* Review

---------

Co-authored-by: Eric Bailey <git@esb.lol>
This commit is contained in:
Samuel Newman
2025-07-23 19:52:38 +03:00
committed by GitHub
parent b4938bc9df
commit 8fdcc3ee31
7 changed files with 98 additions and 65 deletions
+21 -1
View File
@@ -40,6 +40,7 @@ const ApiContext = React.createContext<SessionApiContext>({
logoutEveryAccount: async () => {},
resumeSession: async () => {},
removeAccount: () => {},
partialRefreshSession: async () => {},
})
export function Provider({children}: React.PropsWithChildren<{}>) {
@@ -119,7 +120,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
)
const logoutCurrentAccount = React.useCallback<
SessionApiContext['logoutEveryAccount']
SessionApiContext['logoutCurrentAccount']
>(
logContext => {
addSessionDebugLog({type: 'method:start', method: 'logout'})
@@ -182,6 +183,23 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
[onAgentSessionChange, cancelPendingTask],
)
const partialRefreshSession = React.useCallback<
SessionApiContext['partialRefreshSession']
>(async () => {
const agent = state.currentAgentState.agent as BskyAppAgent
const signal = cancelPendingTask()
const {data} = await agent.com.atproto.server.getSession()
if (signal.aborted) return
dispatch({
type: 'partial-refresh-session',
accountDid: agent.session!.did,
patch: {
emailConfirmed: data.emailConfirmed,
emailAuthFactor: data.emailAuthFactor,
},
})
}, [state, cancelPendingTask])
const removeAccount = React.useCallback<SessionApiContext['removeAccount']>(
account => {
addSessionDebugLog({
@@ -262,6 +280,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
logoutEveryAccount,
resumeSession,
removeAccount,
partialRefreshSession,
}),
[
createAccount,
@@ -270,6 +289,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
logoutEveryAccount,
resumeSession,
removeAccount,
partialRefreshSession,
],
)
+40 -2
View File
@@ -1,8 +1,8 @@
import {AtpSessionEvent} from '@atproto/api'
import {type AtpSessionEvent, type BskyAgent} from '@atproto/api'
import {createPublicAgent} from './agent'
import {wrapSessionReducerForLogging} from './logging'
import {SessionAccount} from './types'
import {type SessionAccount} from './types'
// A hack so that the reducer can't read anything from the agent.
// From the reducer's point of view, it should be a completely opaque object.
@@ -52,6 +52,11 @@ export type Action =
syncedAccounts: SessionAccount[]
syncedCurrentDid: string | undefined
}
| {
type: 'partial-refresh-session'
accountDid: string
patch: Pick<SessionAccount, 'emailConfirmed' | 'emailAuthFactor'>
}
function createPublicAgentState(): AgentState {
return {
@@ -180,6 +185,39 @@ let reducer = (state: State, action: Action): State => {
needsPersist: false, // Synced from another tab. Don't persist to avoid cycles.
}
}
case 'partial-refresh-session': {
const {accountDid, patch} = action
const agent = state.currentAgentState.agent as BskyAgent
/*
* Only mutating values that are safe. Be very careful with this.
*/
if (agent.session) {
agent.session.emailConfirmed =
patch.emailConfirmed ?? agent.session.emailConfirmed
agent.session.emailAuthFactor =
patch.emailAuthFactor ?? agent.session.emailAuthFactor
}
return {
...state,
currentAgentState: {
...state.currentAgentState,
agent,
},
accounts: state.accounts.map(a => {
if (a.did === accountDid) {
return {
...a,
emailConfirmed: patch.emailConfirmed ?? a.emailConfirmed,
emailAuthFactor: patch.emailAuthFactor ?? a.emailAuthFactor,
}
}
return a
}),
needsPersist: true,
}
}
}
}
reducer = wrapSessionReducerForLogging(reducer)
+8
View File
@@ -40,4 +40,12 @@ export type SessionApiContext = {
) => void
resumeSession: (account: SessionAccount) => Promise<void>
removeAccount: (account: SessionAccount) => void
/**
* Calls `getSession` and updates select fields on the current account and
* `BskyAgent`. This is an alternative to `resumeSession`, which updates
* current account/agent using the `persistSessionHandler`, but is more load
* bearing. This patches in updates without causing any side effects via
* `persistSessionHandler`.
*/
partialRefreshSession: () => Promise<void>
}