[Session] Call persist handler directly (#3828)

zio/stable
dan 2024-05-02 23:05:53 +01:00 committed by GitHub
parent b86c3b486f
commit 6405ad7cba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 62 additions and 95 deletions

View File

@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import {AtpPersistSessionHandler, BskyAgent} from '@atproto/api' import {AtpSessionData, AtpSessionEvent, BskyAgent} from '@atproto/api'
import {track} from '#/lib/analytics/analytics' import {track} from '#/lib/analytics/analytics'
import {networkRetry} from '#/lib/async/retry' import {networkRetry} from '#/lib/async/retry'
@ -93,77 +93,65 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
})) }))
}, [setState]) }, [setState])
const createPersistSessionHandler = React.useCallback( const onAgentSessionChange = React.useCallback(
( (
agent: BskyAgent, agent: BskyAgent,
account: SessionAccount, account: SessionAccount,
persistSessionCallback: (props: { event: AtpSessionEvent,
expired: boolean session: AtpSessionData | undefined,
refreshedAccount: SessionAccount ) => {
}) => void, const expired = event === 'expired' || event === 'create-failed'
{
networkErrorCallback,
}: {
networkErrorCallback?: () => void
} = {},
): AtpPersistSessionHandler => {
return function persistSession(event, session) {
const expired = event === 'expired' || event === 'create-failed'
if (event === 'network-error') { if (event === 'network-error') {
logger.warn( logger.warn(
`session: persistSessionHandler received network-error event`, `session: persistSessionHandler received network-error event`,
) )
networkErrorCallback?.() clearCurrentAccount()
return return
} }
// TODO: use agentToSessionAccount for this too. // TODO: use agentToSessionAccount for this too.
const refreshedAccount: SessionAccount = { const refreshedAccount: SessionAccount = {
service: account.service, service: account.service,
did: session?.did || account.did, did: session?.did || account.did,
handle: session?.handle || account.handle, handle: session?.handle || account.handle,
email: session?.email || account.email, email: session?.email || account.email,
emailConfirmed: session?.emailConfirmed || account.emailConfirmed, emailConfirmed: session?.emailConfirmed || account.emailConfirmed,
emailAuthFactor: session?.emailAuthFactor || account.emailAuthFactor, emailAuthFactor: session?.emailAuthFactor || account.emailAuthFactor,
deactivated: isSessionDeactivated(session?.accessJwt), deactivated: isSessionDeactivated(session?.accessJwt),
pdsUrl: agent.pdsUrl?.toString(), pdsUrl: agent.pdsUrl?.toString(),
/*
* Tokens are undefined if the session expires, or if creation fails for
* any reason e.g. tokens are invalid, network error, etc.
*/
refreshJwt: session?.refreshJwt,
accessJwt: session?.accessJwt,
}
logger.debug(`session: persistSession`, {
event,
deactivated: refreshedAccount.deactivated,
})
if (expired) {
logger.warn(`session: expired`)
emitSessionDropped()
}
/* /*
* If the session expired, or it was successfully created/updated, we want * Tokens are undefined if the session expires, or if creation fails for
* to update/persist the data. * any reason e.g. tokens are invalid, network error, etc.
*
* If the session creation failed, it could be a network error, or it could
* be more serious like an invalid token(s). We can't differentiate, so in
* order to allow the user to get a fresh token (if they need it), we need
* to persist this data and wipe their tokens, effectively logging them
* out.
*/ */
persistSessionCallback({ refreshJwt: session?.refreshJwt,
expired, accessJwt: session?.accessJwt,
refreshedAccount,
})
} }
logger.debug(`session: persistSession`, {
event,
deactivated: refreshedAccount.deactivated,
})
if (expired) {
logger.warn(`session: expired`)
emitSessionDropped()
}
/*
* If the session expired, or it was successfully created/updated, we want
* to update/persist the data.
*
* If the session creation failed, it could be a network error, or it could
* be more serious like an invalid token(s). We can't differentiate, so in
* order to allow the user to get a fresh token (if they need it), we need
* to persist this data and wipe their tokens, effectively logging them
* out.
*/
upsertAccount(refreshedAccount, expired)
}, },
[], [clearCurrentAccount, upsertAccount],
) )
const createAccount = React.useCallback<SessionApiContext['createAccount']>( const createAccount = React.useCallback<SessionApiContext['createAccount']>(
@ -191,16 +179,9 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
}, },
) )
agent.setPersistSessionHandler( agent.setPersistSessionHandler((event, session) => {
createPersistSessionHandler( onAgentSessionChange(agent, account, event, session)
agent, })
account,
({expired, refreshedAccount}) => {
upsertAccount(refreshedAccount, expired)
},
{networkErrorCallback: clearCurrentAccount},
),
)
__globalAgent = agent __globalAgent = agent
await fetchingGates await fetchingGates
@ -210,7 +191,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
track('Create Account') track('Create Account')
logEvent('account:create:success', {}) logEvent('account:create:success', {})
}, },
[upsertAccount, clearCurrentAccount, createPersistSessionHandler], [upsertAccount, onAgentSessionChange],
) )
const login = React.useCallback<SessionApiContext['login']>( const login = React.useCallback<SessionApiContext['login']>(
@ -223,16 +204,9 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
authFactorToken, authFactorToken,
}) })
agent.setPersistSessionHandler( agent.setPersistSessionHandler((event, session) => {
createPersistSessionHandler( onAgentSessionChange(agent, account, event, session)
agent, })
account,
({expired, refreshedAccount}) => {
upsertAccount(refreshedAccount, expired)
},
{networkErrorCallback: clearCurrentAccount},
),
)
__globalAgent = agent __globalAgent = agent
// @ts-ignore // @ts-ignore
@ -245,7 +219,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
track('Sign In', {resumedSession: false}) track('Sign In', {resumedSession: false})
logEvent('account:loggedIn', {logContext, withPassword: true}) logEvent('account:loggedIn', {logContext, withPassword: true})
}, },
[upsertAccount, clearCurrentAccount, createPersistSessionHandler], [upsertAccount, onAgentSessionChange],
) )
const logout = React.useCallback<SessionApiContext['logout']>( const logout = React.useCallback<SessionApiContext['logout']>(
@ -280,16 +254,9 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
agent.pdsUrl = agent.api.xrpc.uri = new URL(account.pdsUrl) agent.pdsUrl = agent.api.xrpc.uri = new URL(account.pdsUrl)
} }
agent.setPersistSessionHandler( agent.setPersistSessionHandler((event, session) => {
createPersistSessionHandler( onAgentSessionChange(agent, account, event, session)
agent, })
account,
({expired, refreshedAccount}) => {
upsertAccount(refreshedAccount, expired)
},
{networkErrorCallback: clearCurrentAccount},
),
)
// @ts-ignore // @ts-ignore
if (IS_DEV && isWeb) window.agent = agent if (IS_DEV && isWeb) window.agent = agent
@ -380,7 +347,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
return sessionAccount return sessionAccount
} }
}, },
[upsertAccount, clearCurrentAccount, createPersistSessionHandler], [upsertAccount, onAgentSessionChange],
) )
const removeAccount = React.useCallback<SessionApiContext['removeAccount']>( const removeAccount = React.useCallback<SessionApiContext['removeAccount']>(