Compare commits

...

1 Commits

Author SHA1 Message Date
Samuel Newman c12c39bd4a abstract out sessionstore 2026-02-27 14:12:19 +02:00
2 changed files with 59 additions and 51 deletions
+2 -51
View File
@@ -10,7 +10,6 @@ import {
} from 'react'
import {type AtpSessionEvent, type BskyAgent} from '@atproto/api'
import * as persisted from '#/state/persisted'
import {useCloseAllActiveElements} from '#/state/util'
import {useGlobalDialogsControlContext} from '#/components/dialogs/Context'
import {AnalyticsContext, useAnalyticsBase, utils} from '#/analytics'
@@ -24,7 +23,7 @@ import {
createAgentAndResume,
sessionAccountToSession,
} from './agent'
import {type Action, getInitialState, reducer, type State} from './reducer'
import {SessionStore} from './store'
export {isSignupQueued} from './util'
import {addSessionDebugLog} from './logging'
export type {SessionAccount} from '#/state/session/types'
@@ -61,47 +60,6 @@ const ApiContext = createContext<SessionApiContext>({
})
ApiContext.displayName = 'SessionApiContext'
class SessionStore {
private state: State
private listeners = new Set<() => void>()
constructor() {
// Careful: By the time this runs, `persisted` needs to already be filled.
const initialState = getInitialState(persisted.get('session').accounts)
addSessionDebugLog({type: 'reducer:init', state: initialState})
this.state = initialState
}
getState = (): State => {
return this.state
}
subscribe = (listener: () => void) => {
this.listeners.add(listener)
return () => {
this.listeners.delete(listener)
}
}
dispatch = (action: Action) => {
const nextState = reducer(this.state, action)
this.state = nextState
// Persist synchronously without waiting for the React render cycle.
if (nextState.needsPersist) {
nextState.needsPersist = false
const persistedData = {
accounts: nextState.accounts,
currentAccount: nextState.accounts.find(
a => a.did === nextState.currentAgentState.did,
),
}
addSessionDebugLog({type: 'persisted:broadcast', data: persistedData})
persisted.write('session', persistedData)
}
this.listeners.forEach(listener => listener())
}
}
export function Provider({children}: React.PropsWithChildren<{}>) {
const ax = useAnalyticsBase()
const cancelPendingTask = useOneTaskAtATime()
@@ -308,14 +266,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
[store, cancelPendingTask],
)
useEffect(() => {
return persisted.onUpdate('session', nextSession => {
const synced = nextSession
addSessionDebugLog({type: 'persisted:receive', data: synced})
store.dispatch({
type: 'synced-accounts',
syncedAccounts: synced.accounts,
syncedCurrentDid: synced.currentAccount?.did,
})
return store.onUpdate(synced => {
const syncedAccount = synced.accounts.find(
a => a.did === synced.currentAccount?.did,
)
+57
View File
@@ -0,0 +1,57 @@
import * as persisted from '#/state/persisted'
import {type Schema} from '#/state/persisted/schema'
import {addSessionDebugLog} from './logging'
import {type Action, getInitialState, reducer, type State} from './reducer'
export class SessionStore {
private state: State
private listeners = new Set<() => void>()
constructor() {
// Careful: By the time this runs, `persisted` needs to already be filled.
const initialState = getInitialState(persisted.get('session').accounts)
addSessionDebugLog({type: 'reducer:init', state: initialState})
this.state = initialState
}
getState = (): State => {
return this.state
}
subscribe = (listener: () => void) => {
this.listeners.add(listener)
return () => {
this.listeners.delete(listener)
}
}
dispatch = (action: Action) => {
const nextState = reducer(this.state, action)
this.state = nextState
// Persist synchronously without waiting for the React render cycle.
if (nextState.needsPersist) {
nextState.needsPersist = false
const persistedData = {
accounts: nextState.accounts,
currentAccount: nextState.accounts.find(
a => a.did === nextState.currentAgentState.did,
),
}
addSessionDebugLog({type: 'persisted:broadcast', data: persistedData})
persisted.write('session', persistedData)
}
this.listeners.forEach(listener => listener())
}
onUpdate = (callback: (synced: Schema['session']) => void): (() => void) => {
return persisted.onUpdate('session', nextSession => {
addSessionDebugLog({type: 'persisted:receive', data: nextSession})
this.dispatch({
type: 'synced-accounts',
syncedAccounts: nextSession.accounts,
syncedCurrentDid: nextSession.currentAccount?.did,
})
callback(nextSession)
})
}
}