migrate the remaining agent reads outside the session layer
The last non-session `useAgent` consumers, all thin aliases over calls the clients already make: - `handle.ts`: `getProfile` / `resolveHandle` to the appview client. - `post.ts`: the three post readers share one `fetchPost` helper on the appview client. Their consumers still want `@atproto/api` views, so the generated view is asserted across at that single boundary rather than at each call site. - `post-feed.ts`: `agent.session` gated the logged-out "did any post survive moderation" assertion, which is a question about the session, not the transport - it reads `hasSession` from the session context now. - `ChangeHandleDialog`: `agent.serviceUrl` becomes `currentAccount.service`. - `TestCtrls.e2e`: drops the `configureProxy` call. The appview client reads `BLUESKY_PROXY_HEADER` when the bundle builds it, and the gate around this input means no bundle exists yet, so setting the constant is sufficient. `preferences/index.ts` still writes labeler subscriptions to the agent; that one moves with the bundle rework, which is what gives it a client to write to. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -27,7 +27,7 @@ import {useFetchDid, useUpdateHandleMutation} from '#/state/queries/handle'
|
||||
import {RQKEY as RQKEY_PROFILE} from '#/state/queries/profile'
|
||||
import {useServiceQuery} from '#/state/queries/service'
|
||||
import {useCurrentAccountProfile} from '#/state/queries/useCurrentAccountProfile'
|
||||
import {useAgent, useSession, useSessionApi} from '#/state/session'
|
||||
import {useSession, useSessionApi} from '#/state/session'
|
||||
import {ErrorScreen} from '#/view/com/util/error/ErrorScreen'
|
||||
import {atoms as a, native, useBreakpoints, useTheme} from '#/alf'
|
||||
import {Admonition} from '#/components/Admonition'
|
||||
@@ -63,12 +63,12 @@ export function ChangeHandleDialog({
|
||||
function ChangeHandleDialogInner() {
|
||||
const control = Dialog.useDialogContext()
|
||||
const {_} = useLingui()
|
||||
const agent = useAgent()
|
||||
const {currentAccount} = useSession()
|
||||
const {
|
||||
data: serviceInfo,
|
||||
error: serviceInfoError,
|
||||
refetch,
|
||||
} = useServiceQuery(agent.serviceUrl.toString())
|
||||
} = useServiceQuery(currentAccount?.service ?? '')
|
||||
|
||||
const [page, setPage] = useState<'provided-handle' | 'own-handle'>(
|
||||
'provided-handle',
|
||||
|
||||
+17
-13
@@ -1,10 +1,10 @@
|
||||
import {useCallback} from 'react'
|
||||
import {type HandleString} from '@atproto/syntax'
|
||||
import {type DidString, type HandleString} from '@atproto/syntax'
|
||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {STALE} from '#/state/queries'
|
||||
import {useAgent, usePdsClient} from '#/state/session'
|
||||
import {com} from '#/lexicons'
|
||||
import {useAppviewClient, usePdsClient} from '#/state/session'
|
||||
import {app, com} from '#/lexicons'
|
||||
|
||||
const handleQueryKeyRoot = 'handle'
|
||||
const fetchHandleQueryKey = (handleOrDid: string) => [
|
||||
@@ -16,21 +16,24 @@ const fetchDidQueryKey = (handleOrDid: string) => [didQueryKeyRoot, handleOrDid]
|
||||
|
||||
export function useFetchHandle() {
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
const client = useAppviewClient()
|
||||
|
||||
return useCallback(
|
||||
async (handleOrDid: string) => {
|
||||
if (handleOrDid.startsWith('did:')) {
|
||||
const res = await queryClient.fetchQuery({
|
||||
const data = await queryClient.fetchQuery({
|
||||
staleTime: STALE.MINUTES.FIVE,
|
||||
queryKey: fetchHandleQueryKey(handleOrDid),
|
||||
queryFn: () => agent.getProfile({actor: handleOrDid}),
|
||||
queryFn: () =>
|
||||
client.call(app.bsky.actor.getProfile, {
|
||||
actor: handleOrDid as DidString,
|
||||
}),
|
||||
})
|
||||
return res.data.handle
|
||||
return data.handle
|
||||
}
|
||||
return handleOrDid
|
||||
},
|
||||
[queryClient, agent],
|
||||
[queryClient, client],
|
||||
)
|
||||
}
|
||||
|
||||
@@ -42,7 +45,6 @@ export function useUpdateHandleMutation(opts?: {
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({handle}: {handle: string}) => {
|
||||
// `agent.updateHandle` was a pure alias for this method
|
||||
await client.call(com.atproto.identity.updateHandle, {
|
||||
// callers validate the handle before submitting
|
||||
handle: handle as HandleString,
|
||||
@@ -59,7 +61,7 @@ export function useUpdateHandleMutation(opts?: {
|
||||
|
||||
export function useFetchDid() {
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
const client = useAppviewClient()
|
||||
|
||||
return useCallback(
|
||||
async (handleOrDid: string) => {
|
||||
@@ -69,13 +71,15 @@ export function useFetchDid() {
|
||||
queryFn: async () => {
|
||||
let identifier = handleOrDid
|
||||
if (!identifier.startsWith('did:')) {
|
||||
const res = await agent.resolveHandle({handle: identifier})
|
||||
identifier = res.data.did
|
||||
const data = await client.call(com.atproto.identity.resolveHandle, {
|
||||
handle: identifier as HandleString,
|
||||
})
|
||||
identifier = data.did
|
||||
}
|
||||
return identifier
|
||||
},
|
||||
})
|
||||
},
|
||||
[queryClient, agent],
|
||||
[queryClient, client],
|
||||
)
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ import {moderatePost} from '#/lib/moderation/subjects'
|
||||
import {logger} from '#/logger'
|
||||
import {STALE} from '#/state/queries'
|
||||
import {DEFAULT_LOGGED_OUT_PREFERENCES} from '#/state/queries/preferences/const'
|
||||
import {useAgent, useAppviewClient} from '#/state/session'
|
||||
import {useAppviewClient, useSession} from '#/state/session'
|
||||
import * as userActionHistory from '#/state/userActionHistory'
|
||||
import {KnownError} from '#/view/com/posts/PostFeedErrorMessage'
|
||||
import {useFeedTuners} from '../preferences/feed-tuners'
|
||||
@@ -151,7 +151,7 @@ export function usePostFeedQuery(
|
||||
f => f.pinned && f.value === 'following',
|
||||
) ?? -1
|
||||
const enableFollowingToDiscoverFallback = followingPinnedIndex === 0
|
||||
const agent = useAgent()
|
||||
const {hasSession} = useSession()
|
||||
const client = useAppviewClient()
|
||||
const lastRun = useRef<{
|
||||
data: InfiniteData<FeedPageUnselected>
|
||||
@@ -214,7 +214,7 @@ export function usePostFeedQuery(
|
||||
* moderations happen later, which results in some posts being shown and
|
||||
* some not.
|
||||
*/
|
||||
if (!agent.session) {
|
||||
if (!hasSession) {
|
||||
assertSomePostsPassModeration(
|
||||
res.feed,
|
||||
preferences?.moderationPrefs ||
|
||||
|
||||
+46
-50
@@ -1,6 +1,7 @@
|
||||
import {useCallback} from 'react'
|
||||
import {type AppBskyActorDefs, type AppBskyFeedDefs, AtUri} from '@atproto/api'
|
||||
import {type AtUriString} from '@atproto/syntax'
|
||||
import {type Client} from '@atproto/lex'
|
||||
import {type AtUriString, type HandleString} from '@atproto/syntax'
|
||||
import {deleteLike, deletePost, deleteRepost, like, repost} from '@bsky.app/sdk'
|
||||
import {
|
||||
type QueryClient,
|
||||
@@ -12,16 +13,11 @@ import {
|
||||
import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue'
|
||||
import {updatePostShadow} from '#/state/cache/post-shadow'
|
||||
import {type Shadow} from '#/state/cache/types'
|
||||
import {
|
||||
useAgent,
|
||||
useAppviewClient,
|
||||
usePdsClient,
|
||||
useSession,
|
||||
} from '#/state/session'
|
||||
import {useAppviewClient, usePdsClient, useSession} from '#/state/session'
|
||||
import * as userActionHistory from '#/state/userActionHistory'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {type Metrics, toClout} from '#/analytics/metrics'
|
||||
import {app} from '#/lexicons'
|
||||
import {app, com} from '#/lexicons'
|
||||
import {useIsThreadMuted, useSetThreadMute} from '../cache/thread-mutes'
|
||||
import {findProfileQueryData} from './profile'
|
||||
|
||||
@@ -29,25 +25,15 @@ const RQKEY_ROOT = 'post'
|
||||
export const RQKEY = (postUri: string) => [RQKEY_ROOT, postUri]
|
||||
|
||||
export function usePostQuery(uri: string | undefined) {
|
||||
const agent = useAgent()
|
||||
const client = useAppviewClient()
|
||||
return useQuery<AppBskyFeedDefs.PostView>({
|
||||
queryKey: RQKEY(uri || ''),
|
||||
queryFn: async () => {
|
||||
if (!uri) throw new Error('[unreachable] No URI provided')
|
||||
|
||||
const urip = new AtUri(uri)
|
||||
|
||||
if (!urip.host.startsWith('did:')) {
|
||||
const res = await agent.resolveHandle({
|
||||
handle: urip.host,
|
||||
})
|
||||
// @ts-expect-error TODO new-sdk-migration
|
||||
urip.host = res.data.did
|
||||
}
|
||||
|
||||
const res = await agent.getPosts({uris: [urip.toString()]})
|
||||
if (res.success && res.data.posts[0]) {
|
||||
return res.data.posts[0]
|
||||
const post = await fetchPost(client, uri)
|
||||
if (post) {
|
||||
return post
|
||||
}
|
||||
|
||||
throw new Error('No data')
|
||||
@@ -56,6 +42,33 @@ export function usePostQuery(uri: string | undefined) {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Read one post by AT-URI, resolving a handle authority first when the URI
|
||||
* carries one.
|
||||
*
|
||||
* The appview still answers with `@atproto/api`-shaped views for the callers of
|
||||
* these hooks, so the generated view is asserted across at this single
|
||||
* boundary rather than at every consumer.
|
||||
*/
|
||||
async function fetchPost(
|
||||
client: Client,
|
||||
uri: string,
|
||||
): Promise<AppBskyFeedDefs.PostView | undefined> {
|
||||
const urip = new AtUri(uri)
|
||||
|
||||
if (!urip.host.startsWith('did:')) {
|
||||
const data = await client.call(com.atproto.identity.resolveHandle, {
|
||||
handle: urip.host as HandleString,
|
||||
})
|
||||
urip.host = data.did
|
||||
}
|
||||
|
||||
const data = await client.call(app.bsky.feed.getPosts, {
|
||||
uris: [urip.toString()],
|
||||
})
|
||||
return data.posts[0]
|
||||
}
|
||||
|
||||
export function precachePost(
|
||||
queryClient: QueryClient,
|
||||
uri: string,
|
||||
@@ -66,59 +79,42 @@ export function precachePost(
|
||||
|
||||
export function useGetPost() {
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
const client = useAppviewClient()
|
||||
return useCallback(
|
||||
async ({uri}: {uri: string}) => {
|
||||
return queryClient.fetchQuery({
|
||||
queryKey: RQKEY(uri || ''),
|
||||
async queryFn() {
|
||||
const urip = new AtUri(uri)
|
||||
|
||||
if (!urip.host.startsWith('did:')) {
|
||||
const res = await agent.resolveHandle({
|
||||
handle: urip.host,
|
||||
})
|
||||
// @ts-expect-error TODO new-sdk-migration
|
||||
urip.host = res.data.did
|
||||
}
|
||||
|
||||
const res = await agent.getPosts({
|
||||
uris: [urip.toString()],
|
||||
})
|
||||
|
||||
if (res.success && res.data.posts[0]) {
|
||||
return res.data.posts[0]
|
||||
const post = await fetchPost(client, uri)
|
||||
if (post) {
|
||||
return post
|
||||
}
|
||||
|
||||
throw new Error('useGetPost: post not found')
|
||||
},
|
||||
})
|
||||
},
|
||||
[queryClient, agent],
|
||||
[queryClient, client],
|
||||
)
|
||||
}
|
||||
|
||||
export function useGetPosts() {
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
const client = useAppviewClient()
|
||||
return useCallback(
|
||||
async ({uris}: {uris: string[]}) => {
|
||||
return queryClient.fetchQuery({
|
||||
queryKey: RQKEY(uris.join(',') || ''),
|
||||
async queryFn() {
|
||||
const res = await agent.getPosts({
|
||||
uris,
|
||||
const data = await client.call(app.bsky.feed.getPosts, {
|
||||
uris: uris as AtUriString[],
|
||||
})
|
||||
|
||||
if (res.success) {
|
||||
return res.data.posts
|
||||
} else {
|
||||
throw new Error('useGetPosts failed')
|
||||
}
|
||||
// See the note on `fetchPost` about the view shapes.
|
||||
return data.posts as AppBskyFeedDefs.PostView[]
|
||||
},
|
||||
})
|
||||
},
|
||||
[queryClient, agent],
|
||||
[queryClient, client],
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import {LogBox, Pressable, TextInput, View} from 'react-native'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {BLUESKY_PROXY_HEADER} from '#/lib/constants'
|
||||
import {useAgent, useSessionApi} from '#/state/session'
|
||||
import {useSessionApi} from '#/state/session'
|
||||
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
||||
import {useOnboardingDispatch} from '#/state/shell/onboarding'
|
||||
import {navigate} from '../../../Navigation'
|
||||
@@ -31,7 +31,6 @@ const BTN = {height: 1, width: 1, backgroundColor: 'red'}
|
||||
let hasConfiguredProxy = false
|
||||
|
||||
export function TestCtrls() {
|
||||
const agent = useAgent()
|
||||
const queryClient = useQueryClient()
|
||||
const {logoutEveryAccount, login} = useSessionApi()
|
||||
const onboardingDispatch = useOnboardingDispatch()
|
||||
@@ -74,8 +73,13 @@ export function TestCtrls() {
|
||||
autoCapitalize="none"
|
||||
onSubmitEditing={() => {
|
||||
const header = `${proxyHeader}#bsky_appview`
|
||||
/*
|
||||
* The appview client reads `BLUESKY_PROXY_HEADER.get()` when the
|
||||
* bundle builds it (see clients.ts), so setting the mutable constant
|
||||
* retargets the proxy for the sign-ins below without reconfiguring
|
||||
* anything: the gate above means no bundle exists yet.
|
||||
*/
|
||||
BLUESKY_PROXY_HEADER.set(header)
|
||||
agent.configureProxy(header as any)
|
||||
hasConfiguredProxy = true
|
||||
setIsProxyConfigured(true)
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user