personal web client for Bluesky
typescript solidjs bluesky atcute

refactor: fetch reply context in batches

mary.my.id f2f1b298 7efe784e

verified
Changed files
+46 -10
src
api
queries
components
+45 -10
src/api/queries/profile.ts
··· 2 2 3 3 import type { AppBskyActorDefs } from '@atcute/bluesky'; 4 4 import { ok } from '@atcute/client'; 5 - import type { ActorIdentifier } from '@atcute/lexicons'; 5 + import type { ActorIdentifier, Did } from '@atcute/lexicons'; 6 + import { isDid } from '@atcute/lexicons/syntax'; 7 + import { createBatchedFetch } from '@mary/batch-fetch'; 6 8 import { createQuery } from '@mary/solid-query'; 7 9 8 10 import { useAgent } from '~/lib/states/agent'; 9 11 import { useSession } from '~/lib/states/session'; 12 + import { define, inject } from '~/lib/states/singleton'; 10 13 11 14 import { dequal } from '../utils/dequal'; 12 15 13 16 export interface ProfileQueryOptions { 17 + batched?: boolean; 14 18 staleTime?: number; 15 19 gcTime?: number; 16 20 } 17 21 22 + const BatchedProfileService = define('batched-profile', () => { 23 + const { client } = useAgent(); 24 + 25 + const fetch = createBatchedFetch<Did, AppBskyActorDefs.ProfileViewDetailed>({ 26 + limit: 25, 27 + idFromResource: (profile) => profile.did, 28 + async fetch(queries, signal) { 29 + const data = await ok( 30 + client.get('app.bsky.actor.getProfiles', { 31 + signal, 32 + params: { 33 + actors: queries, 34 + }, 35 + }), 36 + ); 37 + 38 + return data.profiles; 39 + }, 40 + }); 41 + 42 + return { fetch }; 43 + }); 44 + 18 45 export const createProfileQuery = (didOrHandle: () => ActorIdentifier, opts: ProfileQueryOptions = {}) => { 19 46 const { client } = useAgent(); 20 47 const { currentAccount } = useSession(); 48 + 49 + const batched = inject(BatchedProfileService); 21 50 22 51 return createQuery((queryClient) => { 23 52 const $didOrHandle = didOrHandle(); ··· 26 55 queryKey: ['profile', $didOrHandle], 27 56 staleTime: opts.staleTime, 28 57 gcTime: opts.gcTime, 29 - async queryFn(ctx): Promise<AppBskyActorDefs.ProfileViewDetailed> { 30 - const data = await ok( 31 - client.get('app.bsky.actor.getProfile', { 32 - signal: ctx.signal, 33 - params: { 34 - actor: $didOrHandle!, 35 - }, 36 - }), 37 - ); 58 + async queryFn({ signal }): Promise<AppBskyActorDefs.ProfileViewDetailed> { 59 + let data: AppBskyActorDefs.ProfileViewDetailed; 60 + 61 + if (opts.batched && isDid($didOrHandle)) { 62 + data = await batched.fetch($didOrHandle, signal); 63 + } else { 64 + data = await ok( 65 + client.get('app.bsky.actor.getProfile', { 66 + signal, 67 + params: { 68 + actor: $didOrHandle!, 69 + }, 70 + }), 71 + ); 72 + } 38 73 39 74 if (currentAccount !== undefined && currentAccount.did === data.did) { 40 75 // Unset `knownFollowers` as we don't need that on our own profile.
+1
src/components/timeline/post-reply-context.tsx
··· 50 50 } 51 51 52 52 const profile = createProfileQuery(() => did, { 53 + batched: true, 53 54 staleTime: Infinity, 54 55 gcTime: 60_000 * 5, 55 56 });