diff options
author | Samuel Newman <mozzius@protonmail.com> | 2025-07-23 19:52:38 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-07-23 11:52:38 -0500 |
commit | 8fdcc3ee31aefae91ce5552c3aa74bfb867893ac (patch) | |
tree | d9cdf9186300f7e25c04cb9161be25744fb16850 /src/state | |
parent | b4938bc9df3cc9bd2588ab0e34fd8cfda095c797 (diff) | |
download | voidsky-8fdcc3ee31aefae91ce5552c3aa74bfb867893ac.tar.zst |
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>
Diffstat (limited to 'src/state')
-rw-r--r-- | src/state/session/index.tsx | 22 | ||||
-rw-r--r-- | src/state/session/reducer.ts | 42 | ||||
-rw-r--r-- | src/state/session/types.ts | 8 |
3 files changed, 69 insertions, 3 deletions
diff --git a/src/state/session/index.tsx b/src/state/session/index.tsx index 45384c4f5..8223a7b3a 100644 --- a/src/state/session/index.tsx +++ b/src/state/session/index.tsx @@ -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, ], ) diff --git a/src/state/session/reducer.ts b/src/state/session/reducer.ts index 22ba47162..f6452a391 100644 --- a/src/state/session/reducer.ts +++ b/src/state/session/reducer.ts @@ -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) diff --git a/src/state/session/types.ts b/src/state/session/types.ts index aa8b9a99e..4621b4f04 100644 --- a/src/state/session/types.ts +++ b/src/state/session/types.ts @@ -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> } |