[SDK] Migrate agent sugar to @bsky.app/sdk actions (#11382)

This commit is contained in:
Samuel Newman
2026-08-13 22:26:21 +03:00
committed by GitHub
parent a4f2811f39
commit dc31e7fd12
24 changed files with 520 additions and 389 deletions
@@ -16,7 +16,7 @@ import {Trans} from '@lingui/react/macro'
import {retry} from '#/lib/async/retry'
import {wait} from '#/lib/async/wait'
import {parseLinkingUrl} from '#/lib/parseLinkingUrl'
import {useAgent, useSession} from '#/state/session'
import {useAppviewClient, useSession} from '#/state/session'
import {atoms as a, platform, useBreakpoints, useTheme} from '#/alf'
import {AgeAssuranceBadge} from '#/components/ageAssurance/AgeAssuranceBadge'
import {Button, ButtonText} from '#/components/Button'
@@ -176,7 +176,7 @@ function Inner() {
const t = useTheme()
const ax = useAnalytics()
const {_} = useLingui()
const agent = useAgent()
const appviewClient = useAppviewClient()
const polling = useRef(false)
const unmounted = useRef(false)
const [error, setError] = useState(false)
@@ -196,10 +196,10 @@ function Inner() {
5,
() => true,
async () => {
if (!agent.session) return
if (!appviewClient.did) return
if (unmounted.current) return
const data = await refetchAgeAssuranceServerState({agent})
const data = await refetchAgeAssuranceServerState({appviewClient})
if (data?.state.status !== 'assured') {
throw new Error(
@@ -214,7 +214,7 @@ function Inner() {
)
.then(async data => {
if (!data) return
if (!agent.session) return
if (!appviewClient.did) return
if (unmounted.current) return
setSuccess(true)
@@ -230,7 +230,7 @@ function Inner() {
return () => {
unmounted.current = true
}
}, [ax, agent])
}, [ax, appviewClient])
if (success) {
return (
+65 -40
View File
@@ -7,6 +7,8 @@ import {
AtpAgent,
type ChatBskyActorDeclaration,
} from '@atproto/api'
import {type Client} from '@atproto/lex'
import {getPreferences} from '@bsky.app/sdk'
import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister'
import {focusManager, QueryClient, useQuery} from '@tanstack/react-query'
import {persistQueryClient} from '@tanstack/react-query-persist-client'
@@ -21,7 +23,7 @@ import {
snoozeBirthdateUpdateAllowedForDid,
} from '#/state/birthdate'
import {fetchActorDeclarationRecord} from '#/state/queries/messages/actor-declaration'
import {useAgent, useSession} from '#/state/session'
import {useAppviewClient, usePdsClient, useSession} from '#/state/session'
import {DEVICE_SIGNALS_SUPPORTED} from '#/ageAssurance/const'
import * as debug from '#/ageAssurance/debug'
import {logger} from '#/ageAssurance/logger'
@@ -37,6 +39,7 @@ import {
} from '#/ageAssurance/util'
import {IS_DEV} from '#/env'
import {useGeolocation} from '#/geolocation'
import {app} from '#/lexicons'
import {device} from '#/storage'
/**
@@ -63,12 +66,6 @@ const [, cacheHydrationPromise] = persistQueryClient({
persister,
})
export function getDidFromAgentSession(agent: AtpAgent) {
const sessionManager = agent.sessionManager
if (!sessionManager || !sessionManager.did) return
return sessionManager.did
}
/*
* Optimistic data
*/
@@ -187,7 +184,7 @@ export function useConfigQuery() {
export function createServerStateQueryKey({did}: {did: string}) {
return ['serverState', did]
}
export async function getServerState({agent}: {agent: AtpAgent}) {
export async function getServerState({appviewClient}: {appviewClient: Client}) {
if (debug.enabled && debug.serverState)
return debug.resolve(debug.serverState)
const geolocation = device.get(['mergedGeolocation'])
@@ -195,17 +192,21 @@ export async function getServerState({agent}: {agent: AtpAgent}) {
logger.error(`getServerState: missing geolocation countryCode`)
return null
}
const {data} = await agent.app.bsky.ageassurance.getState({
const data = await appviewClient.call(app.bsky.ageassurance.getState, {
countryCode: geolocation.countryCode,
regionCode: geolocation.regionCode,
})
const did = getDidFromAgentSession(agent)
const did = appviewClient.did
if (data && did && createdAtCache.has(did)) {
/*
* If account was just created, just use the local cache if available. On
* subsequent reloads, the server should have the correct value.
* subsequent reloads, the server should have the correct value. The cache
* holds ISO datetime strings (written from `new Date().toISOString()`), so
* assert the branded DatetimeString at this boundary.
*/
data.metadata.accountCreatedAt = createdAtCache.get(did)
data.metadata.accountCreatedAt = createdAtCache.get(
did,
) as typeof data.metadata.accountCreatedAt
}
return data ?? null
}
@@ -218,8 +219,12 @@ export function getServerStateFromCache({
createServerStateQueryKey({did}),
)
}
export async function prefetchServerState({agent}: {agent: AtpAgent}) {
const did = getDidFromAgentSession(agent)
export async function prefetchServerState({
appviewClient,
}: {
appviewClient: Client
}) {
const did = appviewClient.did
if (!did) return
@@ -234,7 +239,7 @@ export async function prefetchServerState({agent}: {agent: AtpAgent}) {
try {
logger.debug(`prefetchServerState: resolving...`)
const res = await networkRetry(3, () => getServerState({agent}))
const res = await networkRetry(3, () => getServerState({appviewClient}))
if (res) {
qc.setQueryData<AppBskyAgeassuranceGetState.OutputSchema>(qk, res)
}
@@ -245,11 +250,15 @@ export async function prefetchServerState({agent}: {agent: AtpAgent}) {
})
}
}
export async function refetchServerState({agent}: {agent: AtpAgent}) {
const did = getDidFromAgentSession(agent)
export async function refetchServerState({
appviewClient,
}: {
appviewClient: Client
}) {
const did = appviewClient.did
if (!did) return
logger.debug(`refetchServerState: fetching...`)
const res = await networkRetry(3, () => getServerState({agent}))
const res = await networkRetry(3, () => getServerState({appviewClient}))
if (res) {
qc.setQueryData<AppBskyAgeassuranceGetState.OutputSchema>(
createServerStateQueryKey({did}),
@@ -279,8 +288,8 @@ export function usePatchServerState() {
)
}
export function useServerStateQuery() {
const agent = useAgent()
const did = getDidFromAgentSession(agent)
const appviewClient = useAppviewClient()
const did = appviewClient.did
const query = useQuery(
{
enabled: !!did,
@@ -290,7 +299,7 @@ export function useServerStateQuery() {
},
queryKey: createServerStateQueryKey({did: did!}),
async queryFn() {
return getServerState({agent})
return getServerState({appviewClient})
},
},
qc,
@@ -342,15 +351,15 @@ export function createOtherRequiredDataQueryKey({did}: {did: string}) {
return ['otherRequiredData', did]
}
async function getOtherRequiredData({
agent,
accountClient,
}: {
agent: AtpAgent
accountClient: Client
}): Promise<OtherRequiredData> {
if (debug.enabled) return debug.resolve(debug.otherRequiredData)
const did = getDidFromAgentSession(agent)
const did = accountClient.did
const [prefs, actorDeclaration] = await Promise.all([
agent.getPreferences(),
fetchActorDeclarationRecord({did, agent}),
accountClient.call(getPreferences),
fetchActorDeclarationRecord({did, client: accountClient}),
])
const data: OtherRequiredData = {
birthdate: prefs.birthDate ? prefs.birthDate.toISOString() : undefined,
@@ -426,8 +435,12 @@ export function setOtherRequiredDataActorDeclarationCache({
next,
)
}
export async function prefetchOtherRequiredData({agent}: {agent: AtpAgent}) {
const did = getDidFromAgentSession(agent)
export async function prefetchOtherRequiredData({
accountClient,
}: {
accountClient: Client
}) {
const did = accountClient.did
if (!did) return
@@ -442,7 +455,9 @@ export async function prefetchOtherRequiredData({agent}: {agent: AtpAgent}) {
try {
logger.debug(`prefetchOtherRequiredData: resolving...`)
const res = await networkRetry(3, () => getOtherRequiredData({agent}))
const res = await networkRetry(3, () =>
getOtherRequiredData({accountClient}),
)
qc.setQueryData<OtherRequiredData>(qk, res)
} catch (err) {
const e = err as Error
@@ -471,8 +486,8 @@ export function usePatchOtherRequiredData() {
)
}
export function useOtherRequiredDataQuery() {
const agent = useAgent()
const did = getDidFromAgentSession(agent)
const accountClient = usePdsClient()
const did = accountClient.did
return useQuery(
{
enabled: !!did,
@@ -482,7 +497,7 @@ export function useOtherRequiredDataQuery() {
},
queryKey: createOtherRequiredDataQueryKey({did: did!}),
async queryFn() {
return getOtherRequiredData({agent})
return getOtherRequiredData({accountClient})
},
},
qc,
@@ -577,8 +592,12 @@ export function setDeviceSignalsForRegion({
prev => ({...prev, [regionKey]: signals}),
)
}
export async function prefetchDeviceSignals({agent}: {agent: AtpAgent}) {
const did = getDidFromAgentSession(agent)
export async function prefetchDeviceSignals({
appviewClient,
}: {
appviewClient: Client
}) {
const did = appviewClient.did
if (!did) return
/**
@@ -613,8 +632,8 @@ export async function prefetchDeviceSignals({agent}: {agent: AtpAgent}) {
*/
}
export function useDeviceSignalsQuery() {
const agent = useAgent()
const did = getDidFromAgentSession(agent)
const appviewClient = useAppviewClient()
const did = appviewClient.did
const {data: config} = useConfigQuery()
const geolocation = useGeolocation()
/*
@@ -659,13 +678,19 @@ export function useDeviceSignalsQuery() {
/**
* Helper to prefetch all age assurance data from the server.
*/
export function prefetchAgeAssuranceServerData({agent}: {agent: AtpAgent}) {
export function prefetchAgeAssuranceServerData({
appviewClient,
accountClient,
}: {
appviewClient: Client
accountClient: Client
}) {
return Promise.allSettled([
// config fetch initiated at the top of the App.platform.tsx files, awaited here
configPrefetchPromise,
prefetchServerState({agent}),
prefetchOtherRequiredData({agent}),
prefetchDeviceSignals({agent}),
prefetchServerState({appviewClient}),
prefetchOtherRequiredData({accountClient}),
prefetchDeviceSignals({appviewClient}),
])
}