Add logoutCurrentAccount()

This commit is contained in:
Dan Abramov
2024-08-15 01:19:34 +01:00
parent eded090ca8
commit 10a6a5fd24
4 changed files with 144 additions and 1 deletions
@@ -674,6 +674,103 @@ describe('session', () => {
expect(state.currentAgentState.did).toBe(undefined) expect(state.currentAgentState.did).toBe(undefined)
}) })
it('can log out of the current account', () => {
let state = getInitialState([])
const agent1 = new BskyAgent({service: 'https://alice.com'})
agent1.sessionManager.session = {
active: true,
did: 'alice-did',
handle: 'alice.test',
accessJwt: 'alice-access-jwt-1',
refreshJwt: 'alice-refresh-jwt-1',
}
state = run(state, [
{
type: 'switched-to-account',
newAgent: agent1,
newAccount: agentToSessionAccountOrThrow(agent1),
},
])
expect(state.accounts.length).toBe(1)
expect(state.accounts[0].accessJwt).toBe('alice-access-jwt-1')
expect(state.accounts[0].refreshJwt).toBe('alice-refresh-jwt-1')
expect(state.currentAgentState.did).toBe('alice-did')
const agent2 = new BskyAgent({service: 'https://bob.com'})
agent2.sessionManager.session = {
active: true,
did: 'bob-did',
handle: 'bob.test',
accessJwt: 'bob-access-jwt-1',
refreshJwt: 'bob-refresh-jwt-1',
}
state = run(state, [
{
type: 'switched-to-account',
newAgent: agent2,
newAccount: agentToSessionAccountOrThrow(agent2),
},
])
expect(state.accounts.length).toBe(2)
expect(state.accounts[0].accessJwt).toBe('bob-access-jwt-1')
expect(state.accounts[0].refreshJwt).toBe('bob-refresh-jwt-1')
expect(state.currentAgentState.did).toBe('bob-did')
state = run(state, [
{
type: 'logged-out-current-account',
},
])
expect(state.accounts.length).toBe(2)
expect(state.accounts[0].accessJwt).toBe(undefined)
expect(state.accounts[0].refreshJwt).toBe(undefined)
expect(state.accounts[1].accessJwt).toBe('alice-access-jwt-1')
expect(state.accounts[1].refreshJwt).toBe('alice-refresh-jwt-1')
expect(state.currentAgentState.did).toBe(undefined)
expect(printState(state)).toMatchInlineSnapshot(`
{
"accounts": [
{
"accessJwt": undefined,
"active": true,
"did": "bob-did",
"email": undefined,
"emailAuthFactor": false,
"emailConfirmed": false,
"handle": "bob.test",
"pdsUrl": undefined,
"refreshJwt": undefined,
"service": "https://bob.com/",
"signupQueued": false,
"status": undefined,
},
{
"accessJwt": "alice-access-jwt-1",
"active": true,
"did": "alice-did",
"email": undefined,
"emailAuthFactor": false,
"emailConfirmed": false,
"handle": "alice.test",
"pdsUrl": undefined,
"refreshJwt": "alice-refresh-jwt-1",
"service": "https://alice.com/",
"signupQueued": false,
"status": undefined,
},
],
"currentAgentState": {
"agent": {
"service": "https://public.api.bsky.app/",
},
"did": undefined,
},
"needsPersist": true,
}
`)
})
it('updates stored account with refreshed tokens', () => { it('updates stored account with refreshed tokens', () => {
let state = getInitialState([]) let state = getInitialState([])
+25 -1
View File
@@ -35,6 +35,7 @@ const AgentContext = React.createContext<BskyAgent | null>(null)
const ApiContext = React.createContext<SessionApiContext>({ const ApiContext = React.createContext<SessionApiContext>({
createAccount: async () => {}, createAccount: async () => {},
login: async () => {}, login: async () => {},
logoutCurrentAccount: async () => {},
logoutEveryAccount: async () => {}, logoutEveryAccount: async () => {},
resumeSession: async () => {}, resumeSession: async () => {},
removeAccount: () => {}, removeAccount: () => {},
@@ -115,6 +116,21 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
[onAgentSessionChange, cancelPendingTask], [onAgentSessionChange, cancelPendingTask],
) )
const logoutCurrentAccount = React.useCallback<
SessionApiContext['logoutEveryAccount']
>(
logContext => {
addSessionDebugLog({type: 'method:start', method: 'logout'})
cancelPendingTask()
dispatch({
type: 'logged-out-current-account',
})
logEvent('account:loggedOut', {logContext, scope: 'current'})
addSessionDebugLog({type: 'method:end', method: 'logout'})
},
[cancelPendingTask],
)
const logoutEveryAccount = React.useCallback< const logoutEveryAccount = React.useCallback<
SessionApiContext['logoutEveryAccount'] SessionApiContext['logoutEveryAccount']
>( >(
@@ -232,11 +248,19 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
() => ({ () => ({
createAccount, createAccount,
login, login,
logoutCurrentAccount,
logoutEveryAccount, logoutEveryAccount,
resumeSession, resumeSession,
removeAccount, removeAccount,
}), }),
[createAccount, login, logoutEveryAccount, resumeSession, removeAccount], [
createAccount,
login,
logoutCurrentAccount,
logoutEveryAccount,
resumeSession,
removeAccount,
],
) )
// @ts-ignore // @ts-ignore
+19
View File
@@ -41,6 +41,9 @@ export type Action =
type: 'removed-account' type: 'removed-account'
accountDid: string accountDid: string
} }
| {
type: 'logged-out-current-account'
}
| { | {
type: 'logged-out-every-account' type: 'logged-out-every-account'
} }
@@ -138,6 +141,22 @@ let reducer = (state: State, action: Action): State => {
needsPersist: true, needsPersist: true,
} }
} }
case 'logged-out-current-account': {
const {currentAgentState} = state
return {
accounts: state.accounts.map(a =>
a.did === currentAgentState.did
? {
...a,
refreshJwt: undefined,
accessJwt: undefined,
}
: a,
),
currentAgentState: createPublicAgentState(),
needsPersist: true,
}
}
case 'logged-out-every-account': { case 'logged-out-every-account': {
return { return {
accounts: state.accounts.map(a => ({ accounts: state.accounts.map(a => ({
+3
View File
@@ -29,6 +29,9 @@ export type SessionApiContext = {
}, },
logContext: LogEvents['account:loggedIn']['logContext'], logContext: LogEvents['account:loggedIn']['logContext'],
) => Promise<void> ) => Promise<void>
logoutCurrentAccount: (
logContext: LogEvents['account:loggedOut']['logContext'],
) => void
logoutEveryAccount: ( logoutEveryAccount: (
logContext: LogEvents['account:loggedOut']['logContext'], logContext: LogEvents['account:loggedOut']['logContext'],
) => void ) => void