migrate the join link and join request queries to the chat client
The logged-out join link preview path built an ad-hoc AtpAgent pointed at CHAT_SERVICE. It is now a module-level unauthenticated lex client against the same service, so the client is built once rather than per call. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,17 +1,19 @@
|
||||
import {useCallback} from 'react'
|
||||
import {
|
||||
type $Typed,
|
||||
AtpAgent,
|
||||
ChatBskyGroupDefs,
|
||||
type ChatBskyGroupGetJoinLinkPreviews,
|
||||
} from '@atproto/api'
|
||||
import {type Client} from '@atproto/lex'
|
||||
import {type QueryClient, useQuery, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {CHAT_SERVICE, DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||
import {CHAT_SERVICE} from '#/lib/constants'
|
||||
import {createLexClient} from '#/lib/lexClient'
|
||||
import {logger} from '#/logger'
|
||||
import {STALE} from '#/state/queries/index'
|
||||
import {createQueryKey, type StructuredQueryKey} from '#/state/queries/util'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {useChatClient} from '#/state/session'
|
||||
import {chat} from '#/lexicons'
|
||||
|
||||
/**
|
||||
* The three preview shapes we currently support. Excludes the `{$type: string}`
|
||||
@@ -154,23 +156,34 @@ export function invalidateJoinLinkPreviewsForConvo(
|
||||
})
|
||||
}
|
||||
|
||||
let publicChatClient: Client | undefined
|
||||
|
||||
/**
|
||||
* The unauthenticated {@link Client} for the chat service, used to resolve join
|
||||
* links before the viewer has a session.
|
||||
*
|
||||
* It talks to {@link CHAT_SERVICE} directly rather than proxying through a PDS,
|
||||
* so no `atproto-proxy` header is involved. A single module-level instance,
|
||||
* because there is no session to scope it to and reconstructing it per call
|
||||
* would be waste.
|
||||
*/
|
||||
function getPublicChatClient(): Client {
|
||||
return (publicChatClient ??= createLexClient({service: CHAT_SERVICE}))
|
||||
}
|
||||
|
||||
async function fetchJoinLinkPreviews({
|
||||
agent,
|
||||
client,
|
||||
codes,
|
||||
hasSession,
|
||||
}: {
|
||||
agent: AtpAgent
|
||||
client: Client
|
||||
codes: string[]
|
||||
hasSession: boolean
|
||||
}) {
|
||||
const previewAgent = new AtpAgent({service: CHAT_SERVICE})
|
||||
const res = hasSession
|
||||
? await agent.chat.bsky.group.getJoinLinkPreviews(
|
||||
{codes},
|
||||
{headers: DM_SERVICE_HEADERS},
|
||||
)
|
||||
: await previewAgent.chat.bsky.group.getJoinLinkPreviews({codes})
|
||||
return res.data
|
||||
return await (hasSession ? client : getPublicChatClient()).call(
|
||||
chat.bsky.group.getJoinLinkPreviews,
|
||||
{codes},
|
||||
)
|
||||
}
|
||||
|
||||
export function useJoinLinkPreviewsQuery({
|
||||
@@ -188,14 +201,14 @@ export function useJoinLinkPreviewsQuery({
|
||||
*/
|
||||
initialData?: ChatBskyGroupGetJoinLinkPreviews.OutputSchema
|
||||
}) {
|
||||
const agent = useAgent()
|
||||
const client = useChatClient()
|
||||
|
||||
return useQuery({
|
||||
queryKey: createJoinLinkPreviewQueryKey({codes: codes ?? [], hasSession}),
|
||||
queryFn: async () => {
|
||||
if (!codes) throw new Error('No invite code')
|
||||
try {
|
||||
return await fetchJoinLinkPreviews({agent, codes, hasSession})
|
||||
return await fetchJoinLinkPreviews({client, codes, hasSession})
|
||||
} catch (error) {
|
||||
logger.error('Failed to fetch join link preview', {safeMessage: error})
|
||||
throw error
|
||||
@@ -208,13 +221,13 @@ export function useJoinLinkPreviewsQuery({
|
||||
}
|
||||
|
||||
export function usePrefetchJoinLinkPreviews() {
|
||||
const agent = useAgent()
|
||||
const client = useChatClient()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return ({codes, hasSession}: {codes: string[]; hasSession: boolean}) => {
|
||||
return queryClient.prefetchQuery({
|
||||
queryKey: createJoinLinkPreviewQueryKey({codes, hasSession}),
|
||||
queryFn: () => fetchJoinLinkPreviews({agent, codes, hasSession}),
|
||||
queryFn: () => fetchJoinLinkPreviews({client, codes, hasSession}),
|
||||
staleTime: STALE.SECONDS.FIFTEEN,
|
||||
})
|
||||
}
|
||||
@@ -226,7 +239,7 @@ export function usePrefetchJoinLinkPreviews() {
|
||||
* Returns undefined if the preview can't be resolved.
|
||||
*/
|
||||
export function useGetJoinLinkPreview() {
|
||||
const agent = useAgent()
|
||||
const client = useChatClient()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useCallback(
|
||||
@@ -241,7 +254,7 @@ export function useGetJoinLinkPreview() {
|
||||
const data = await queryClient.fetchQuery({
|
||||
queryKey: createJoinLinkPreviewQueryKey({codes: [code], hasSession}),
|
||||
queryFn: () =>
|
||||
fetchJoinLinkPreviews({agent, codes: [code], hasSession}),
|
||||
fetchJoinLinkPreviews({client, codes: [code], hasSession}),
|
||||
staleTime: STALE.SECONDS.FIFTEEN,
|
||||
})
|
||||
const found = data.joinLinkPreviews[0]
|
||||
@@ -251,6 +264,6 @@ export function useGetJoinLinkPreview() {
|
||||
return undefined
|
||||
}
|
||||
},
|
||||
[agent, queryClient],
|
||||
[client, queryClient],
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ import {
|
||||
} from '@atproto/api'
|
||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {useChatClient} from '#/state/session'
|
||||
import {chat} from '#/lexicons'
|
||||
import {
|
||||
rollbackConvoOptimistic,
|
||||
updateConvoOptimistic,
|
||||
@@ -24,7 +24,7 @@ export function useCreateJoinLink(
|
||||
},
|
||||
) {
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
const client = useChatClient()
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
@@ -35,11 +35,11 @@ export function useCreateJoinLink(
|
||||
requireApproval: boolean
|
||||
}) => {
|
||||
if (!convoId) throw new Error('No convoId provided')
|
||||
const {data} = await agent.chat.bsky.group.createJoinLink(
|
||||
{convoId, joinRule, requireApproval},
|
||||
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'},
|
||||
)
|
||||
return data
|
||||
return await client.call(chat.bsky.group.createJoinLink, {
|
||||
convoId,
|
||||
joinRule,
|
||||
requireApproval,
|
||||
})
|
||||
},
|
||||
onMutate: ({joinRule, requireApproval}) => {
|
||||
if (!convoId) return
|
||||
|
||||
@@ -4,10 +4,10 @@ import {
|
||||
} from '@atproto/api'
|
||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {invalidateJoinLinkPreviewsForCode} from '#/state/queries/join-links'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {useChatClient} from '#/state/session'
|
||||
import {chat} from '#/lexicons'
|
||||
import {
|
||||
rollbackConvoOptimistic,
|
||||
updateConvoOptimistic,
|
||||
@@ -24,16 +24,12 @@ export function useDisableJoinLink(
|
||||
},
|
||||
) {
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
const client = useChatClient()
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
if (!convoId) throw new Error('No convoId provided')
|
||||
const {data} = await agent.chat.bsky.group.disableJoinLink(
|
||||
{convoId},
|
||||
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'},
|
||||
)
|
||||
return data
|
||||
return await client.call(chat.bsky.group.disableJoinLink, {convoId})
|
||||
},
|
||||
onMutate: () => {
|
||||
if (!convoId) return
|
||||
|
||||
@@ -5,9 +5,9 @@ import {
|
||||
} from '@atproto/api'
|
||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {useChatClient} from '#/state/session'
|
||||
import {chat} from '#/lexicons'
|
||||
import {
|
||||
rollbackConvoOptimistic,
|
||||
updateConvoOptimistic,
|
||||
@@ -24,7 +24,7 @@ export function useEditJoinLink(
|
||||
},
|
||||
) {
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
const client = useChatClient()
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
@@ -35,11 +35,11 @@ export function useEditJoinLink(
|
||||
requireApproval: boolean
|
||||
}) => {
|
||||
if (!convoId) throw new Error('No convoId provided')
|
||||
const {data} = await agent.chat.bsky.group.editJoinLink(
|
||||
{convoId, joinRule, requireApproval},
|
||||
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'},
|
||||
)
|
||||
return data
|
||||
return await client.call(chat.bsky.group.editJoinLink, {
|
||||
convoId,
|
||||
joinRule,
|
||||
requireApproval,
|
||||
})
|
||||
},
|
||||
onMutate: ({joinRule, requireApproval}) => {
|
||||
if (!convoId) return
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import {ChatBskyConvoDefs, type ChatBskyGroupEnableJoinLink} from '@atproto/api'
|
||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {invalidateJoinLinkPreviewsForCode} from '#/state/queries/join-links'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {useChatClient} from '#/state/session'
|
||||
import {chat} from '#/lexicons'
|
||||
import {
|
||||
rollbackConvoOptimistic,
|
||||
updateConvoOptimistic,
|
||||
@@ -21,16 +21,12 @@ export function useEnableJoinLink(
|
||||
},
|
||||
) {
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
const client = useChatClient()
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
if (!convoId) throw new Error('No convoId provided')
|
||||
const {data} = await agent.chat.bsky.group.enableJoinLink(
|
||||
{convoId},
|
||||
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'},
|
||||
)
|
||||
return data
|
||||
return await client.call(chat.bsky.group.enableJoinLink, {convoId})
|
||||
},
|
||||
onMutate: () => {
|
||||
if (!convoId) return
|
||||
|
||||
@@ -4,15 +4,16 @@ import {
|
||||
type ChatBskyGroupListJoinRequests,
|
||||
type ChatBskyGroupRejectJoinRequest,
|
||||
} from '@atproto/api'
|
||||
import {type DidString} from '@atproto/syntax'
|
||||
import {
|
||||
type InfiniteData,
|
||||
useMutation,
|
||||
useQueryClient,
|
||||
} from '@tanstack/react-query'
|
||||
|
||||
import {DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {useChatClient} from '#/state/session'
|
||||
import {chat} from '#/lexicons'
|
||||
import {listConvoMembersQueryKey} from './list-convo-members'
|
||||
import {createListJoinRequestsQueryKey} from './list-join-requests'
|
||||
|
||||
@@ -34,21 +35,28 @@ export function useJoinRequestMutation<A extends JoinRequestAction>(
|
||||
},
|
||||
) {
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
const client = useChatClient()
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({member}: {member: string}) => {
|
||||
if (!convoId) throw new Error('No convoId provided')
|
||||
const {data} =
|
||||
// callers pass an already-resolved actor did
|
||||
const memberDid = member as DidString
|
||||
const data =
|
||||
action === 'approve'
|
||||
? await agent.chat.bsky.group.approveJoinRequest(
|
||||
{convoId, member},
|
||||
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'},
|
||||
)
|
||||
: await agent.chat.bsky.group.rejectJoinRequest(
|
||||
{convoId, member},
|
||||
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'},
|
||||
)
|
||||
? await client.call(chat.bsky.group.approveJoinRequest, {
|
||||
convoId,
|
||||
member: memberDid,
|
||||
})
|
||||
: await client.call(chat.bsky.group.rejectJoinRequest, {
|
||||
convoId,
|
||||
member: memberDid,
|
||||
})
|
||||
/*
|
||||
* The two branches have different output schemas, so the union cannot be
|
||||
* narrowed from the `action` value alone - the cast carries the generic's
|
||||
* mapping through, exactly as the pre-migration code did.
|
||||
*/
|
||||
return data as JoinRequestOutput<A>
|
||||
},
|
||||
onMutate: ({member}) => {
|
||||
|
||||
@@ -2,10 +2,10 @@ import {useEffect} from 'react'
|
||||
import {ChatBskyConvoDefs} from '@atproto/api'
|
||||
import {useInfiniteQuery, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||
import {useMessagesEventBus} from '#/state/messages/events'
|
||||
import {createQueryKey} from '#/state/queries/util'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {useChatClient} from '#/state/session'
|
||||
import {chat} from '#/lexicons'
|
||||
import {STALE} from '..'
|
||||
|
||||
export const JOIN_REQUESTS_THRESHOLD = 20
|
||||
@@ -22,7 +22,7 @@ export function useListJoinRequestsQuery({
|
||||
convoId: string | undefined
|
||||
enabled?: boolean
|
||||
}) {
|
||||
const agent = useAgent()
|
||||
const client = useChatClient()
|
||||
const queryClient = useQueryClient()
|
||||
const messagesBus = useMessagesEventBus()
|
||||
const isEnabled = enabled !== false && !!convoId
|
||||
@@ -54,11 +54,12 @@ export function useListJoinRequestsQuery({
|
||||
enabled: isEnabled,
|
||||
queryKey: createListJoinRequestsQueryKey({convoId: convoId ?? ''}),
|
||||
queryFn: async ({pageParam}) => {
|
||||
const {data} = await agent.chat.bsky.group.listJoinRequests(
|
||||
{convoId: convoId!, cursor: pageParam, limit: JOIN_REQUESTS_THRESHOLD},
|
||||
{headers: DM_SERVICE_HEADERS},
|
||||
)
|
||||
return data
|
||||
return await client.call(chat.bsky.group.listJoinRequests, {
|
||||
// guarded by `isEnabled`
|
||||
convoId: convoId!,
|
||||
cursor: pageParam,
|
||||
limit: JOIN_REQUESTS_THRESHOLD,
|
||||
})
|
||||
},
|
||||
initialPageParam: undefined as string | undefined,
|
||||
getNextPageParam: page => page.cursor,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import {ChatBskyConvoDefs} from '@atproto/api'
|
||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {useChatClient} from '#/state/session'
|
||||
import {chat} from '#/lexicons'
|
||||
import {RQKEY as CONVO_KEY} from './conversation'
|
||||
import {
|
||||
type ConvoListQueryData,
|
||||
@@ -12,15 +12,12 @@ import {
|
||||
|
||||
export function useMarkJoinRequestsRead(convoId: string | undefined) {
|
||||
const queryClient = useQueryClient()
|
||||
const agent = useAgent()
|
||||
const client = useChatClient()
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async () => {
|
||||
if (!convoId) throw new Error('No convoId provided')
|
||||
await agent.chat.bsky.group.updateJoinRequestsRead(
|
||||
{convoId},
|
||||
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'},
|
||||
)
|
||||
await client.call(chat.bsky.group.updateJoinRequestsRead, {convoId})
|
||||
},
|
||||
onMutate: () => {
|
||||
if (!convoId) return
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import {type ChatBskyGroupRequestJoin} from '@atproto/api'
|
||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {useAgent, useSession} from '#/state/session'
|
||||
import {useChatClient, useSession} from '#/state/session'
|
||||
import {chat} from '#/lexicons'
|
||||
import {RQKEY_ROOT as REQUESTS_RQKEY_ROOT} from './list-conversation-requests'
|
||||
|
||||
export function useRequestJoinGroupChat({
|
||||
@@ -13,7 +13,7 @@ export function useRequestJoinGroupChat({
|
||||
onSuccess?: (data: ChatBskyGroupRequestJoin.OutputSchema) => void
|
||||
onError?: (error: Error) => void
|
||||
} = {}) {
|
||||
const agent = useAgent()
|
||||
const client = useChatClient()
|
||||
const queryClient = useQueryClient()
|
||||
const {hasSession} = useSession()
|
||||
|
||||
@@ -22,11 +22,7 @@ export function useRequestJoinGroupChat({
|
||||
if (!hasSession) throw new Error('Must be logged in to join')
|
||||
if (!code) throw new Error('No invite code')
|
||||
|
||||
const res = await agent.chat.bsky.group.requestJoin(
|
||||
{code},
|
||||
{headers: DM_SERVICE_HEADERS},
|
||||
)
|
||||
return res.data
|
||||
return await client.call(chat.bsky.group.requestJoin, {code})
|
||||
},
|
||||
onSuccess: data => {
|
||||
void queryClient.invalidateQueries({queryKey: [REQUESTS_RQKEY_ROOT]})
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import {type ChatBskyGroupWithdrawJoinRequest} from '@atproto/api'
|
||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {useAgent, useSession} from '#/state/session'
|
||||
import {useChatClient, useSession} from '#/state/session'
|
||||
import {chat} from '#/lexicons'
|
||||
import {
|
||||
type ConvoRequestListQueryData,
|
||||
optimisticDeleteJoinRequest,
|
||||
@@ -17,7 +17,7 @@ export function useWithdrawJoinGroupChatRequest({
|
||||
onSuccess?: (data: ChatBskyGroupWithdrawJoinRequest.OutputSchema) => void
|
||||
onError?: (error: Error) => void
|
||||
} = {}) {
|
||||
const agent = useAgent()
|
||||
const client = useChatClient()
|
||||
const queryClient = useQueryClient()
|
||||
const {hasSession} = useSession()
|
||||
|
||||
@@ -27,11 +27,7 @@ export function useWithdrawJoinGroupChatRequest({
|
||||
throw new Error('Must be logged in to withdraw a join request')
|
||||
if (!convoId) throw new Error('No convoId provided')
|
||||
|
||||
const res = await agent.chat.bsky.group.withdrawJoinRequest(
|
||||
{convoId},
|
||||
{headers: DM_SERVICE_HEADERS},
|
||||
)
|
||||
return res.data
|
||||
return await client.call(chat.bsky.group.withdrawJoinRequest, {convoId})
|
||||
},
|
||||
onSuccess: (data, {convoId}) => {
|
||||
queryClient.setQueriesData<ConvoRequestListQueryData>(
|
||||
|
||||
Reference in New Issue
Block a user