migrate the actor search and autocomplete queries to the appview client
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,13 +6,14 @@ import {isJustAMute, moduiContainsHideableOffense} from '#/lib/moderation'
|
|||||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {STALE} from '#/state/queries'
|
import {STALE} from '#/state/queries'
|
||||||
import {DEFAULT_LOGGED_OUT_PREFERENCES} from '#/state/queries/preferences'
|
import {DEFAULT_LOGGED_OUT_PREFERENCES} from '#/state/queries/preferences'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAppviewClient} from '#/state/session'
|
||||||
import {
|
import {
|
||||||
type AutocompleteApi,
|
type AutocompleteApi,
|
||||||
type AutocompleteItem,
|
type AutocompleteItem,
|
||||||
type AutocompleteItemType,
|
type AutocompleteItemType,
|
||||||
type AutocompleteProfile,
|
type AutocompleteProfile,
|
||||||
} from '#/components/Autocomplete/types'
|
} from '#/components/Autocomplete/types'
|
||||||
|
import {app} from '#/lexicons'
|
||||||
import {useEmojiSearch} from './useEmojiSearch'
|
import {useEmojiSearch} from './useEmojiSearch'
|
||||||
|
|
||||||
const DEFAULT_MOD_OPTS = {
|
const DEFAULT_MOD_OPTS = {
|
||||||
@@ -31,7 +32,7 @@ export function useAutocomplete({
|
|||||||
limit?: number
|
limit?: number
|
||||||
showSearchFallback?: boolean
|
showSearchFallback?: boolean
|
||||||
}): AutocompleteApi {
|
}): AutocompleteApi {
|
||||||
const agent = useAgent()
|
const client = useAppviewClient()
|
||||||
const moderationOpts = useModerationOpts()
|
const moderationOpts = useModerationOpts()
|
||||||
const emojiSearch = useEmojiSearch()
|
const emojiSearch = useEmojiSearch()
|
||||||
|
|
||||||
@@ -52,12 +53,12 @@ export function useAutocomplete({
|
|||||||
// Going from "foo" to "foo." should not clear matches.
|
// Going from "foo" to "foo." should not clear matches.
|
||||||
q = q.toLowerCase().trim().replace(/\.$/, '')
|
q = q.toLowerCase().trim().replace(/\.$/, '')
|
||||||
|
|
||||||
const res = await agent.searchActorsTypeahead({
|
const data = await client.call(app.bsky.actor.searchActorsTypeahead, {
|
||||||
q,
|
q,
|
||||||
limit: limit || 8,
|
limit: limit || 8,
|
||||||
})
|
})
|
||||||
|
|
||||||
return (res?.data.actors || []).map(profile => ({
|
return (data?.actors || []).map(profile => ({
|
||||||
key: profile.did,
|
key: profile.did,
|
||||||
type: 'profile' as const,
|
type: 'profile' as const,
|
||||||
value: '@' + profile.handle,
|
value: '@' + profile.handle,
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import {keepPreviousData, useQuery, useQueryClient} from '@tanstack/react-query'
|
|||||||
import {isJustAMute, moduiContainsHideableOffense} from '#/lib/moderation'
|
import {isJustAMute, moduiContainsHideableOffense} from '#/lib/moderation'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {STALE} from '#/state/queries'
|
import {STALE} from '#/state/queries'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAppviewClient} from '#/state/session'
|
||||||
|
import {app} from '#/lexicons'
|
||||||
import {useModerationOpts} from '../preferences/moderation-opts'
|
import {useModerationOpts} from '../preferences/moderation-opts'
|
||||||
import {DEFAULT_LOGGED_OUT_PREFERENCES} from './preferences'
|
import {DEFAULT_LOGGED_OUT_PREFERENCES} from './preferences'
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ export function useActorAutocompleteQuery(
|
|||||||
limit?: number,
|
limit?: number,
|
||||||
) {
|
) {
|
||||||
const moderationOpts = useModerationOpts()
|
const moderationOpts = useModerationOpts()
|
||||||
const agent = useAgent()
|
const client = useAppviewClient()
|
||||||
|
|
||||||
prefix = prefix.toLowerCase().trim()
|
prefix = prefix.toLowerCase().trim()
|
||||||
if (prefix.endsWith('.')) {
|
if (prefix.endsWith('.')) {
|
||||||
@@ -39,13 +40,13 @@ export function useActorAutocompleteQuery(
|
|||||||
staleTime: STALE.MINUTES.ONE,
|
staleTime: STALE.MINUTES.ONE,
|
||||||
queryKey: RQKEY(prefix || ''),
|
queryKey: RQKEY(prefix || ''),
|
||||||
async queryFn() {
|
async queryFn() {
|
||||||
const res = prefix
|
const data = prefix
|
||||||
? await agent.searchActorsTypeahead({
|
? await client.call(app.bsky.actor.searchActorsTypeahead, {
|
||||||
q: prefix,
|
q: prefix,
|
||||||
limit: limit || 8,
|
limit: limit || 8,
|
||||||
})
|
})
|
||||||
: undefined
|
: undefined
|
||||||
return res?.data.actors || []
|
return data?.actors || []
|
||||||
},
|
},
|
||||||
select: useCallback(
|
select: useCallback(
|
||||||
(data: AppBskyActorDefs.ProfileViewBasic[]) => {
|
(data: AppBskyActorDefs.ProfileViewBasic[]) => {
|
||||||
@@ -65,7 +66,7 @@ export type ActorAutocompleteFn = ReturnType<typeof useActorAutocompleteFn>
|
|||||||
export function useActorAutocompleteFn() {
|
export function useActorAutocompleteFn() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const moderationOpts = useModerationOpts()
|
const moderationOpts = useModerationOpts()
|
||||||
const agent = useAgent()
|
const client = useAppviewClient()
|
||||||
|
|
||||||
return useCallback(
|
return useCallback(
|
||||||
async ({query, limit = 8}: {query: string; limit?: number}) => {
|
async ({query, limit = 8}: {query: string; limit?: number}) => {
|
||||||
@@ -77,7 +78,7 @@ export function useActorAutocompleteFn() {
|
|||||||
staleTime: STALE.MINUTES.ONE,
|
staleTime: STALE.MINUTES.ONE,
|
||||||
queryKey: RQKEY(query || ''),
|
queryKey: RQKEY(query || ''),
|
||||||
queryFn: () =>
|
queryFn: () =>
|
||||||
agent.searchActorsTypeahead({
|
client.call(app.bsky.actor.searchActorsTypeahead, {
|
||||||
q: query,
|
q: query,
|
||||||
limit,
|
limit,
|
||||||
}),
|
}),
|
||||||
@@ -91,11 +92,11 @@ export function useActorAutocompleteFn() {
|
|||||||
|
|
||||||
return computeSuggestions({
|
return computeSuggestions({
|
||||||
q: query,
|
q: query,
|
||||||
searched: res?.data.actors,
|
searched: res?.actors,
|
||||||
moderationOpts: moderationOpts || DEFAULT_MOD_OPTS,
|
moderationOpts: moderationOpts || DEFAULT_MOD_OPTS,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
[queryClient, moderationOpts, agent],
|
[queryClient, moderationOpts, client],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import {type AppBskyActorSearchActors} from '@atproto/api'
|
|
||||||
import {
|
import {
|
||||||
type InfiniteData,
|
type InfiniteData,
|
||||||
keepPreviousData,
|
keepPreviousData,
|
||||||
@@ -8,7 +7,8 @@ import {
|
|||||||
} from '@tanstack/react-query'
|
} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {STALE} from '#/state/queries'
|
import {STALE} from '#/state/queries'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAppviewClient} from '#/state/session'
|
||||||
|
import {app} from '#/lexicons'
|
||||||
|
|
||||||
export const RQKEY_ROOT = 'actor-search'
|
export const RQKEY_ROOT = 'actor-search'
|
||||||
export const RQKEY = (query: string, limit?: number) => [
|
export const RQKEY = (query: string, limit?: number) => [
|
||||||
@@ -28,23 +28,22 @@ export function useActorSearch({
|
|||||||
maintainData?: boolean
|
maintainData?: boolean
|
||||||
limit?: number
|
limit?: number
|
||||||
}) {
|
}) {
|
||||||
const agent = useAgent()
|
const client = useAppviewClient()
|
||||||
return useInfiniteQuery<
|
return useInfiniteQuery<
|
||||||
AppBskyActorSearchActors.OutputSchema,
|
app.bsky.actor.searchActors.$OutputBody,
|
||||||
Error,
|
Error,
|
||||||
InfiniteData<AppBskyActorSearchActors.OutputSchema>,
|
InfiniteData<app.bsky.actor.searchActors.$OutputBody>,
|
||||||
QueryKey,
|
QueryKey,
|
||||||
string | undefined
|
string | undefined
|
||||||
>({
|
>({
|
||||||
staleTime: STALE.MINUTES.FIVE,
|
staleTime: STALE.MINUTES.FIVE,
|
||||||
queryKey: RQKEY(query, limit),
|
queryKey: RQKEY(query, limit),
|
||||||
queryFn: async ({pageParam}) => {
|
queryFn: async ({pageParam}) => {
|
||||||
const res = await agent.searchActors({
|
return await client.call(app.bsky.actor.searchActors, {
|
||||||
q: query,
|
q: query,
|
||||||
limit,
|
limit,
|
||||||
cursor: pageParam,
|
cursor: pageParam,
|
||||||
})
|
})
|
||||||
return res.data
|
|
||||||
},
|
},
|
||||||
enabled: enabled && !!query,
|
enabled: enabled && !!query,
|
||||||
initialPageParam: undefined,
|
initialPageParam: undefined,
|
||||||
@@ -54,7 +53,7 @@ export function useActorSearch({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function select(data: InfiniteData<AppBskyActorSearchActors.OutputSchema>) {
|
function select(data: InfiniteData<app.bsky.actor.searchActors.$OutputBody>) {
|
||||||
// enforce uniqueness
|
// enforce uniqueness
|
||||||
const dids = new Set()
|
const dids = new Set()
|
||||||
|
|
||||||
@@ -77,7 +76,7 @@ export function* findAllProfilesInQueryData(
|
|||||||
did: string,
|
did: string,
|
||||||
) {
|
) {
|
||||||
const queryDatas = queryClient.getQueriesData<
|
const queryDatas = queryClient.getQueriesData<
|
||||||
InfiniteData<AppBskyActorSearchActors.OutputSchema>
|
InfiniteData<app.bsky.actor.searchActors.$OutputBody>
|
||||||
>({
|
>({
|
||||||
queryKey: [RQKEY_ROOT],
|
queryKey: [RQKEY_ROOT],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
import {type AtpAgent, AtUri} from '@atproto/api'
|
import {AtUri} from '@atproto/api'
|
||||||
|
import {type Client} from '@atproto/lex'
|
||||||
|
import {type HandleString} from '@atproto/syntax'
|
||||||
import {type QueryClient, queryOptions, useQuery} from '@tanstack/react-query'
|
import {type QueryClient, queryOptions, useQuery} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {STALE} from '#/state/queries'
|
import {STALE} from '#/state/queries'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAppviewClient} from '#/state/session'
|
||||||
|
import {com} from '#/lexicons'
|
||||||
import {useUnstableProfileViewCache} from './profile'
|
import {useUnstableProfileViewCache} from './profile'
|
||||||
|
|
||||||
const RQKEY_ROOT = 'resolved-did'
|
const RQKEY_ROOT = 'resolved-did'
|
||||||
export const RQKEY = (didOrHandle: string) => [RQKEY_ROOT, didOrHandle]
|
export const RQKEY = (didOrHandle: string) => [RQKEY_ROOT, didOrHandle]
|
||||||
|
|
||||||
const resolvedDidQueryOptions = (
|
const resolvedDidQueryOptions = (
|
||||||
agent: AtpAgent,
|
client: Client,
|
||||||
getUnstableProfile: (did: string) => {did: string} | undefined,
|
getUnstableProfile: (did: string) => {did: string} | undefined,
|
||||||
didOrHandle: string | undefined,
|
didOrHandle: string | undefined,
|
||||||
) =>
|
) =>
|
||||||
@@ -21,8 +24,15 @@ const resolvedDidQueryOptions = (
|
|||||||
// Just return the did if it's already one
|
// Just return the did if it's already one
|
||||||
if (didOrHandle.startsWith('did:')) return didOrHandle
|
if (didOrHandle.startsWith('did:')) return didOrHandle
|
||||||
|
|
||||||
const res = await agent.resolveHandle({handle: didOrHandle})
|
/*
|
||||||
return res.data.did
|
* Resolution stays on the appview client: the old agent call was proxied
|
||||||
|
* to the appview, and the PDS implementation is not equivalent for
|
||||||
|
* handles hosted elsewhere.
|
||||||
|
*/
|
||||||
|
const data = await client.call(com.atproto.identity.resolveHandle, {
|
||||||
|
handle: didOrHandle as HandleString,
|
||||||
|
})
|
||||||
|
return data.did
|
||||||
},
|
},
|
||||||
initialData: () => {
|
initialData: () => {
|
||||||
// Return undefined if no did or handle
|
// Return undefined if no did or handle
|
||||||
@@ -37,11 +47,11 @@ export function useResolveUriQuery(uri: string | undefined) {
|
|||||||
const urip = new AtUri(uri || '')
|
const urip = new AtUri(uri || '')
|
||||||
const host = urip.host
|
const host = urip.host
|
||||||
|
|
||||||
const agent = useAgent()
|
const client = useAppviewClient()
|
||||||
const {getUnstableProfile} = useUnstableProfileViewCache()
|
const {getUnstableProfile} = useUnstableProfileViewCache()
|
||||||
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
...resolvedDidQueryOptions(agent, getUnstableProfile, host),
|
...resolvedDidQueryOptions(client, getUnstableProfile, host),
|
||||||
select: did => ({
|
select: did => ({
|
||||||
did,
|
did,
|
||||||
uri: AtUri.make(did, urip.collection, urip.rkey).toString(),
|
uri: AtUri.make(did, urip.collection, urip.rkey).toString(),
|
||||||
@@ -50,11 +60,11 @@ export function useResolveUriQuery(uri: string | undefined) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useResolveDidQuery(didOrHandle: string | undefined) {
|
export function useResolveDidQuery(didOrHandle: string | undefined) {
|
||||||
const agent = useAgent()
|
const client = useAppviewClient()
|
||||||
const {getUnstableProfile} = useUnstableProfileViewCache()
|
const {getUnstableProfile} = useUnstableProfileViewCache()
|
||||||
|
|
||||||
return useQuery(
|
return useQuery(
|
||||||
resolvedDidQueryOptions(agent, getUnstableProfile, didOrHandle),
|
resolvedDidQueryOptions(client, getUnstableProfile, didOrHandle),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import {useCallback, useEffect, useState} from 'react'
|
import {useCallback, useEffect, useState} from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||||
|
import {type DidString} from '@atproto/syntax'
|
||||||
import {useLingui} from '@lingui/react/macro'
|
import {useLingui} from '@lingui/react/macro'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {PressableScale} from '#/lib/custom-animations/PressableScale'
|
import {PressableScale} from '#/lib/custom-animations/PressableScale'
|
||||||
import {STALE} from '#/state/queries'
|
import {STALE} from '#/state/queries'
|
||||||
import {profilesQueryKey} from '#/state/queries/profile'
|
import {profilesQueryKey} from '#/state/queries/profile'
|
||||||
import {useAgent, useSession} from '#/state/session'
|
import {useAppviewClient, useSession} from '#/state/session'
|
||||||
import {useSetActiveLanding} from '#/state/shell/landing'
|
import {useSetActiveLanding} from '#/state/shell/landing'
|
||||||
import {
|
import {
|
||||||
useLoggedOutView,
|
useLoggedOutView,
|
||||||
@@ -23,6 +24,7 @@ import {atoms as a, native, tokens, useTheme} from '#/alf'
|
|||||||
import {Button, ButtonIcon} from '#/components/Button'
|
import {Button, ButtonIcon} from '#/components/Button'
|
||||||
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
|
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
|
import {app} from '#/lexicons'
|
||||||
import {SplashScreen} from './SplashScreen'
|
import {SplashScreen} from './SplashScreen'
|
||||||
|
|
||||||
enum ScreenState {
|
enum ScreenState {
|
||||||
@@ -65,19 +67,18 @@ export function LoggedOut({onDismiss}: {onDismiss?: () => void}) {
|
|||||||
|
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const {accounts} = useSession()
|
const {accounts} = useSession()
|
||||||
const agent = useAgent()
|
const client = useAppviewClient()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const actors = accounts.map(acc => acc.did)
|
const actors = accounts.map(acc => acc.did as DidString)
|
||||||
if (actors.length === 0) return
|
if (actors.length === 0) return
|
||||||
void queryClient.prefetchQuery({
|
void queryClient.prefetchQuery({
|
||||||
queryKey: profilesQueryKey(actors),
|
queryKey: profilesQueryKey(actors),
|
||||||
staleTime: STALE.MINUTES.FIVE,
|
staleTime: STALE.MINUTES.FIVE,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const res = await agent.getProfiles({actors})
|
return await client.call(app.bsky.actor.getProfiles, {actors})
|
||||||
return res.data
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}, [accounts, agent, queryClient])
|
}, [accounts, client, queryClient])
|
||||||
|
|
||||||
const onPressDismiss = useCallback(() => {
|
const onPressDismiss = useCallback(() => {
|
||||||
if (onDismiss) {
|
if (onDismiss) {
|
||||||
|
|||||||
Reference in New Issue
Block a user