diff options
Diffstat (limited to 'src/state/session/index.tsx')
-rw-r--r-- | src/state/session/index.tsx | 132 |
1 files changed, 91 insertions, 41 deletions
diff --git a/src/state/session/index.tsx b/src/state/session/index.tsx index b555a997b..c7dba3089 100644 --- a/src/state/session/index.tsx +++ b/src/state/session/index.tsx @@ -1,18 +1,26 @@ import React from 'react' -import {BskyAgent, AtpPersistSessionHandler} from '@atproto/api' +import { + AtpPersistSessionHandler, + BSKY_LABELER_DID, + BskyAgent, +} from '@atproto/api' import {useQueryClient} from '@tanstack/react-query' import {jwtDecode} from 'jwt-decode' +import {track} from '#/lib/analytics/analytics' import {networkRetry} from '#/lib/async/retry' +import {IS_TEST_USER} from '#/lib/constants' +import {logEvent, LogEvents} from '#/lib/statsig/statsig' +import {hasProp} from '#/lib/type-guards' import {logger} from '#/logger' +import {isWeb} from '#/platform/detection' import * as persisted from '#/state/persisted' import {PUBLIC_BSKY_AGENT} from '#/state/queries' -import {IS_PROD} from '#/lib/constants' -import {emitSessionDropped} from '../events' import {useLoggedOutViewControls} from '#/state/shell/logged-out' import {useCloseAllActiveElements} from '#/state/util' -import {track} from '#/lib/analytics/analytics' -import {hasProp} from '#/lib/type-guards' +import {IS_DEV} from '#/env' +import {emitSessionDropped} from '../events' +import {readLabelers} from './agent-config' let __globalAgent: BskyAgent = PUBLIC_BSKY_AGENT @@ -36,7 +44,6 @@ export type SessionState = { } export type StateContext = SessionState & { hasSession: boolean - isSandbox: boolean } export type ApiContext = { createAccount: (props: { @@ -48,17 +55,22 @@ export type ApiContext = { verificationPhone?: string verificationCode?: string }) => Promise<void> - login: (props: { - service: string - identifier: string - password: string - }) => Promise<void> + login: ( + props: { + service: string + identifier: string + password: string + }, + logContext: LogEvents['account:loggedIn']['logContext'], + ) => Promise<void> /** * A full logout. Clears the `currentAccount` from session, AND removes * access tokens from all accounts, so that returning as any user will * require a full login. */ - logout: () => Promise<void> + logout: ( + logContext: LogEvents['account:loggedOut']['logContext'], + ) => Promise<void> /** * A partial logout. Clears the `currentAccount` from session, but DOES NOT * clear access tokens from accounts, allowing the user to return to their @@ -70,7 +82,10 @@ export type ApiContext = { initSession: (account: SessionAccount) => Promise<void> resumeSession: (account?: SessionAccount) => Promise<void> removeAccount: (account: SessionAccount) => void - selectAccount: (account: SessionAccount) => Promise<void> + selectAccount: ( + account: SessionAccount, + logContext: LogEvents['account:loggedIn']['logContext'], + ) => Promise<void> updateCurrentAccount: ( account: Partial< Pick<SessionAccount, 'handle' | 'email' | 'emailConfirmed'> @@ -84,7 +99,6 @@ const StateContext = React.createContext<StateContext>({ accounts: [], currentAccount: undefined, hasSession: false, - isSandbox: false, }) const ApiContext = React.createContext<ApiContext>({ @@ -136,7 +150,7 @@ function createPersistSessionHandler( accessJwt: session?.accessJwt, } - logger.info(`session: persistSession`, { + logger.debug(`session: persistSession`, { event, deactivated: refreshedAccount.deactivated, }) @@ -216,6 +230,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) { }: any) => { logger.info(`session: creating account`) track('Try Create Account') + logEvent('account:create:begin', {}) const agent = new BskyAgent({service}) @@ -258,6 +273,8 @@ export function Provider({children}: React.PropsWithChildren<{}>) { deactivated, } + await configureModeration(agent, account) + agent.setPersistSessionHandler( createPersistSessionHandler( account, @@ -274,12 +291,13 @@ export function Provider({children}: React.PropsWithChildren<{}>) { logger.debug(`session: created account`, {}, logger.DebugContext.session) track('Create Account') + logEvent('account:create:success', {}) }, [upsertAccount, queryClient, clearCurrentAccount], ) const login = React.useCallback<ApiContext['login']>( - async ({service, identifier, password}) => { + async ({service, identifier, password}, logContext) => { logger.debug(`session: login`, {}, logger.DebugContext.session) const agent = new BskyAgent({service}) @@ -301,6 +319,8 @@ export function Provider({children}: React.PropsWithChildren<{}>) { deactivated: isSessionDeactivated(agent.session.accessJwt), } + await configureModeration(agent, account) + agent.setPersistSessionHandler( createPersistSessionHandler( account, @@ -312,30 +332,37 @@ export function Provider({children}: React.PropsWithChildren<{}>) { ) __globalAgent = agent + // @ts-ignore + if (IS_DEV && isWeb) window.agent = agent queryClient.clear() upsertAccount(account) logger.debug(`session: logged in`, {}, logger.DebugContext.session) track('Sign In', {resumedSession: false}) + logEvent('account:loggedIn', {logContext, withPassword: true}) }, [upsertAccount, queryClient, clearCurrentAccount], ) - const logout = React.useCallback<ApiContext['logout']>(async () => { - logger.info(`session: logout`) - clearCurrentAccount() - setStateAndPersist(s => { - return { - ...s, - accounts: s.accounts.map(a => ({ - ...a, - refreshJwt: undefined, - accessJwt: undefined, - })), - } - }) - }, [clearCurrentAccount, setStateAndPersist]) + const logout = React.useCallback<ApiContext['logout']>( + async logContext => { + logger.debug(`session: logout`) + clearCurrentAccount() + setStateAndPersist(s => { + return { + ...s, + accounts: s.accounts.map(a => ({ + ...a, + refreshJwt: undefined, + accessJwt: undefined, + })), + } + }) + logEvent('account:loggedOut', {logContext}) + }, + [clearCurrentAccount, setStateAndPersist], + ) const initSession = React.useCallback<ApiContext['initSession']>( async account => { @@ -351,6 +378,9 @@ export function Provider({children}: React.PropsWithChildren<{}>) { {networkErrorCallback: clearCurrentAccount}, ), }) + // @ts-ignore + if (IS_DEV && isWeb) window.agent = agent + await configureModeration(agent, account) let canReusePrevSession = false try { @@ -377,7 +407,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) { } if (canReusePrevSession) { - logger.info(`session: attempting to reuse previous session`) + logger.debug(`session: attempting to reuse previous session`) agent.session = prevSession __globalAgent = agent @@ -387,7 +417,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) { if (prevSession.deactivated) { // don't attempt to resume // use will be taken to the deactivated screen - logger.info(`session: reusing session for deactivated account`) + logger.debug(`session: reusing session for deactivated account`) return } @@ -413,7 +443,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) { __globalAgent = PUBLIC_BSKY_AGENT }) } else { - logger.info(`session: attempting to resume using previous session`) + logger.debug(`session: attempting to resume using previous session`) try { const freshAccount = await resumeSessionWithFreshAccount() @@ -434,7 +464,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) { } async function resumeSessionWithFreshAccount(): Promise<SessionAccount> { - logger.info(`session: resumeSessionWithFreshAccount`) + logger.debug(`session: resumeSessionWithFreshAccount`) await networkRetry(1, () => agent.resumeSession(prevSession)) @@ -526,11 +556,12 @@ export function Provider({children}: React.PropsWithChildren<{}>) { ) const selectAccount = React.useCallback<ApiContext['selectAccount']>( - async account => { + async (account, logContext) => { setState(s => ({...s, isSwitchingAccounts: true})) try { await initSession(account) setState(s => ({...s, isSwitchingAccounts: false})) + logEvent('account:loggedIn', {logContext, withPassword: false}) } catch (e) { // reset this in case of error setState(s => ({...s, isSwitchingAccounts: false})) @@ -555,11 +586,11 @@ export function Provider({children}: React.PropsWithChildren<{}>) { return persisted.onUpdate(() => { const session = persisted.get('session') - logger.info(`session: persisted onUpdate`, {}) + logger.debug(`session: persisted onUpdate`, {}) if (session.currentAccount && session.currentAccount.refreshJwt) { if (session.currentAccount?.did !== state.currentAccount?.did) { - logger.info(`session: persisted onUpdate, switching accounts`, { + logger.debug(`session: persisted onUpdate, switching accounts`, { from: { did: state.currentAccount?.did, handle: state.currentAccount?.handle, @@ -572,7 +603,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) { initSession(session.currentAccount) } else { - logger.info(`session: persisted onUpdate, updating session`, {}) + logger.debug(`session: persisted onUpdate, updating session`, {}) /* * Use updated session in this tab's agent. Do not call @@ -610,9 +641,6 @@ export function Provider({children}: React.PropsWithChildren<{}>) { () => ({ ...state, hasSession: !!state.currentAccount, - isSandbox: state.currentAccount - ? !IS_PROD(state.currentAccount?.service) - : false, }), [state], ) @@ -649,6 +677,28 @@ export function Provider({children}: React.PropsWithChildren<{}>) { ) } +async function configureModeration(agent: BskyAgent, account: SessionAccount) { + if (IS_TEST_USER(account.handle)) { + const did = ( + await agent + .resolveHandle({handle: 'mod-authority.test'}) + .catch(_ => undefined) + )?.data.did + if (did) { + console.warn('USING TEST ENV MODERATION') + BskyAgent.configure({appLabelers: [did]}) + } + } else { + BskyAgent.configure({appLabelers: [BSKY_LABELER_DID]}) + const labelerDids = await readLabelers(account.did).catch(_ => {}) + if (labelerDids) { + agent.configureLabelersHeader( + labelerDids.filter(did => did !== BSKY_LABELER_DID), + ) + } + } +} + export function useSession() { return React.useContext(StateContext) } |