rework session layer on PasswordSession + three-client pattern
- PasswordSession (@atproto/lex-password-session) is now the single auth
core; SessionAgent bridges it to the base Agent from @atproto/api so
the ~148 useAgent() consumer files keep working unchanged
- SessionBundle carries {session, agent, accountClient, appviewClient};
useLexClient() now returns the authed appview client, new
useAppviewClient()/usePdsClient() hooks
- reducer: OpaqueSessionBundle, new replaced-current-bundle action for
network-free cross-tab same-did sync (PasswordSession is immutable, so
the bundle is rebuilt instead of mutated in place)
- moderation: AtpAgent.configure -> Client.configure + Agent.configure,
per-account labelers on both the bridge and the appview client
- push-token unregistration uses temporary PasswordSessions
- hard-tail migrations: SignupQueued refresh via resumeSession shim,
useBeginAgeAssurance scoped-token raw Client, useAccountEmailState
reads currentAccount
- PDS routing preserved on the no-network resume fast path by
synthesizing a minimal didDoc from the persisted pdsUrl
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,7 +21,7 @@ import {
|
||||
snoozeBirthdateUpdateAllowedForDid,
|
||||
} from '#/state/birthdate'
|
||||
import {fetchActorDeclarationRecord} from '#/state/queries/messages/actor-declaration'
|
||||
import {useAgent, useSession} from '#/state/session'
|
||||
import {type SessionAgent, useAgent, useSession} from '#/state/session'
|
||||
import {DEVICE_SIGNALS_SUPPORTED} from '#/ageAssurance/const'
|
||||
import * as debug from '#/ageAssurance/debug'
|
||||
import {logger} from '#/ageAssurance/logger'
|
||||
@@ -63,7 +63,7 @@ const [, cacheHydrationPromise] = persistQueryClient({
|
||||
persister,
|
||||
})
|
||||
|
||||
export function getDidFromAgentSession(agent: AtpAgent) {
|
||||
export function getDidFromAgentSession(agent: SessionAgent) {
|
||||
const sessionManager = agent.sessionManager
|
||||
if (!sessionManager || !sessionManager.did) return
|
||||
return sessionManager.did
|
||||
@@ -187,7 +187,7 @@ export function useConfigQuery() {
|
||||
export function createServerStateQueryKey({did}: {did: string}) {
|
||||
return ['serverState', did]
|
||||
}
|
||||
export async function getServerState({agent}: {agent: AtpAgent}) {
|
||||
export async function getServerState({agent}: {agent: SessionAgent}) {
|
||||
if (debug.enabled && debug.serverState)
|
||||
return debug.resolve(debug.serverState)
|
||||
const geolocation = device.get(['mergedGeolocation'])
|
||||
@@ -218,7 +218,7 @@ export function getServerStateFromCache({
|
||||
createServerStateQueryKey({did}),
|
||||
)
|
||||
}
|
||||
export async function prefetchServerState({agent}: {agent: AtpAgent}) {
|
||||
export async function prefetchServerState({agent}: {agent: SessionAgent}) {
|
||||
const did = getDidFromAgentSession(agent)
|
||||
|
||||
if (!did) return
|
||||
@@ -245,7 +245,7 @@ export async function prefetchServerState({agent}: {agent: AtpAgent}) {
|
||||
})
|
||||
}
|
||||
}
|
||||
export async function refetchServerState({agent}: {agent: AtpAgent}) {
|
||||
export async function refetchServerState({agent}: {agent: SessionAgent}) {
|
||||
const did = getDidFromAgentSession(agent)
|
||||
if (!did) return
|
||||
logger.debug(`refetchServerState: fetching...`)
|
||||
@@ -344,7 +344,7 @@ export function createOtherRequiredDataQueryKey({did}: {did: string}) {
|
||||
async function getOtherRequiredData({
|
||||
agent,
|
||||
}: {
|
||||
agent: AtpAgent
|
||||
agent: SessionAgent
|
||||
}): Promise<OtherRequiredData> {
|
||||
if (debug.enabled) return debug.resolve(debug.otherRequiredData)
|
||||
const did = getDidFromAgentSession(agent)
|
||||
@@ -426,7 +426,11 @@ export function setOtherRequiredDataActorDeclarationCache({
|
||||
next,
|
||||
)
|
||||
}
|
||||
export async function prefetchOtherRequiredData({agent}: {agent: AtpAgent}) {
|
||||
export async function prefetchOtherRequiredData({
|
||||
agent,
|
||||
}: {
|
||||
agent: SessionAgent
|
||||
}) {
|
||||
const did = getDidFromAgentSession(agent)
|
||||
|
||||
if (!did) return
|
||||
@@ -577,7 +581,7 @@ export function setDeviceSignalsForRegion({
|
||||
prev => ({...prev, [regionKey]: signals}),
|
||||
)
|
||||
}
|
||||
export async function prefetchDeviceSignals({agent}: {agent: AtpAgent}) {
|
||||
export async function prefetchDeviceSignals({agent}: {agent: SessionAgent}) {
|
||||
const did = getDidFromAgentSession(agent)
|
||||
if (!did) return
|
||||
|
||||
@@ -659,7 +663,7 @@ export function useDeviceSignalsQuery() {
|
||||
/**
|
||||
* Helper to prefetch all age assurance data from the server.
|
||||
*/
|
||||
export function prefetchAgeAssuranceServerData({agent}: {agent: AtpAgent}) {
|
||||
export function prefetchAgeAssuranceServerData({agent}: {agent: SessionAgent}) {
|
||||
return Promise.allSettled([
|
||||
// config fetch initiated at the top of the App.platform.tsx files, awaited here
|
||||
configPrefetchPromise,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Platform} from 'react-native'
|
||||
import {type AppBskyAgeassuranceBegin, AtpAgent} from '@atproto/api'
|
||||
import {Client} from '@atproto/lex-client'
|
||||
import {useMutation} from '@tanstack/react-query'
|
||||
|
||||
import {wait} from '#/lib/async/wait'
|
||||
@@ -15,6 +15,7 @@ import {logger} from '#/ageAssurance/logger'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {BLUESKY_PROXY_DID} from '#/env'
|
||||
import {useGeolocation} from '#/geolocation'
|
||||
import {app} from '#/lexicons'
|
||||
|
||||
const IS_DEV_ENV = BLUESKY_PROXY_DID !== PUBLIC_APPVIEW_DID
|
||||
const APPVIEW = IS_DEV_ENV ? DEV_ENV_APPVIEW : PUBLIC_APPVIEW
|
||||
@@ -28,7 +29,7 @@ export function useBeginAgeAssurance() {
|
||||
return useMutation({
|
||||
async mutationFn(
|
||||
props: Omit<
|
||||
AppBskyAgeassuranceBegin.InputSchema,
|
||||
app.bsky.ageassurance.begin.$InputBody,
|
||||
'countryCode' | 'regionCode'
|
||||
>,
|
||||
) {
|
||||
@@ -45,10 +46,16 @@ export function useBeginAgeAssurance() {
|
||||
lxm: `app.bsky.ageassurance.begin`,
|
||||
})
|
||||
|
||||
const appView = new AtpAgent({service: APPVIEW})
|
||||
appView.sessionManager.session = {...agent.session!}
|
||||
appView.sessionManager.session.accessJwt = token
|
||||
appView.sessionManager.session.refreshJwt = ''
|
||||
/*
|
||||
* A non-refreshing throwaway client scoped to the service-auth token: it
|
||||
* has no session, so nothing can refresh it. Requests go straight to the
|
||||
* appview with the token as a static Authorization header (a raw client,
|
||||
* unlike a session, is allowed to preset that header).
|
||||
*/
|
||||
const scopedClient = new Client({
|
||||
service: APPVIEW,
|
||||
headers: {authorization: `Bearer ${token}`},
|
||||
})
|
||||
|
||||
ax.metric('ageAssurance:api:begin', {
|
||||
platform: Platform.OS,
|
||||
@@ -60,9 +67,9 @@ export function useBeginAgeAssurance() {
|
||||
* 2s wait is good actually. Email sending takes a hot sec and this helps
|
||||
* ensure the email is ready for the user once they open their inbox.
|
||||
*/
|
||||
const {data} = await wait(
|
||||
const data = await wait(
|
||||
2e3,
|
||||
appView.app.bsky.ageassurance.begin({
|
||||
scopedClient.call(app.bsky.ageassurance.begin, {
|
||||
...props,
|
||||
countryCode,
|
||||
regionCode,
|
||||
|
||||
Reference in New Issue
Block a user