···11import {useMemo} from 'react'
22-import {type AppBskyFeedDefs, moderatePost} from '@atproto/api'
22+import {
33+ type AppBskyActorDefs,
44+ AppBskyFeedDefs,
55+ AtUri,
66+ moderatePost,
77+} from '@atproto/api'
38import {msg} from '@lingui/macro'
49import {useLingui} from '@lingui/react'
55-import {useInfiniteQuery} from '@tanstack/react-query'
1010+import {
1111+ type InfiniteData,
1212+ type QueryClient,
1313+ useInfiniteQuery,
1414+} from '@tanstack/react-query'
615716import {CustomFeedAPI} from '#/lib/api/feed/custom'
817import {aggregateUserInterests} from '#/lib/api/feed/utils'
···1423 type FeedPostSliceItem,
1524} from '#/state/queries/post-feed'
1625import {usePreferencesQuery} from '#/state/queries/preferences'
2626+import {
2727+ didOrHandleUriMatches,
2828+ embedViewRecordToPostView,
2929+ getEmbeddedPost,
3030+} from '#/state/queries/util'
1731import {useAgent} from '#/state/session'
18321933const RQKEY_ROOT = 'feed-previews'
···6882 uri: string
6983 }
70847171-export function useFeedPreviews(feeds: AppBskyFeedDefs.GeneratorView[]) {
8585+export function useFeedPreviews(
8686+ feedsMaybeWithDuplicates: AppBskyFeedDefs.GeneratorView[],
8787+) {
8888+ const feeds = useMemo(
8989+ () =>
9090+ feedsMaybeWithDuplicates.filter(
9191+ (f, i, a) => i === a.findIndex(f2 => f.uri === f2.uri),
9292+ ),
9393+ [feedsMaybeWithDuplicates],
9494+ )
9595+7296 const uris = feeds.map(feed => feed.uri)
7397 const {_} = useLingui()
7498 const agent = useAgent()
···262286 ]),
263287 }
264288}
289289+290290+export function* findAllPostsInQueryData(
291291+ queryClient: QueryClient,
292292+ uri: string,
293293+): Generator<AppBskyFeedDefs.PostView, undefined> {
294294+ const atUri = new AtUri(uri)
295295+296296+ const queryDatas = queryClient.getQueriesData<
297297+ InfiniteData<{
298298+ feed: AppBskyFeedDefs.GeneratorView
299299+ posts: AppBskyFeedDefs.FeedViewPost[]
300300+ }>
301301+ >({
302302+ queryKey: [RQKEY_ROOT],
303303+ })
304304+ for (const [_queryKey, queryData] of queryDatas) {
305305+ if (!queryData?.pages) {
306306+ continue
307307+ }
308308+ for (const page of queryData?.pages) {
309309+ for (const item of page.posts) {
310310+ if (didOrHandleUriMatches(atUri, item.post)) {
311311+ yield item.post
312312+ }
313313+314314+ const quotedPost = getEmbeddedPost(item.post.embed)
315315+ if (quotedPost && didOrHandleUriMatches(atUri, quotedPost)) {
316316+ yield embedViewRecordToPostView(quotedPost)
317317+ }
318318+319319+ if (AppBskyFeedDefs.isPostView(item.reply?.parent)) {
320320+ if (didOrHandleUriMatches(atUri, item.reply.parent)) {
321321+ yield item.reply.parent
322322+ }
323323+324324+ const parentQuotedPost = getEmbeddedPost(item.reply.parent.embed)
325325+ if (
326326+ parentQuotedPost &&
327327+ didOrHandleUriMatches(atUri, parentQuotedPost)
328328+ ) {
329329+ yield embedViewRecordToPostView(parentQuotedPost)
330330+ }
331331+ }
332332+333333+ if (AppBskyFeedDefs.isPostView(item.reply?.root)) {
334334+ if (didOrHandleUriMatches(atUri, item.reply.root)) {
335335+ yield item.reply.root
336336+ }
337337+338338+ const rootQuotedPost = getEmbeddedPost(item.reply.root.embed)
339339+ if (rootQuotedPost && didOrHandleUriMatches(atUri, rootQuotedPost)) {
340340+ yield embedViewRecordToPostView(rootQuotedPost)
341341+ }
342342+ }
343343+ }
344344+ }
345345+ }
346346+}
347347+348348+export function* findAllProfilesInQueryData(
349349+ queryClient: QueryClient,
350350+ did: string,
351351+): Generator<AppBskyActorDefs.ProfileViewBasic, undefined> {
352352+ const queryDatas = queryClient.getQueriesData<
353353+ InfiniteData<{
354354+ feed: AppBskyFeedDefs.GeneratorView
355355+ posts: AppBskyFeedDefs.FeedViewPost[]
356356+ }>
357357+ >({
358358+ queryKey: [RQKEY_ROOT],
359359+ })
360360+ for (const [_queryKey, queryData] of queryDatas) {
361361+ if (!queryData?.pages) {
362362+ continue
363363+ }
364364+ for (const page of queryData?.pages) {
365365+ for (const item of page.posts) {
366366+ if (item.post.author.did === did) {
367367+ yield item.post.author
368368+ }
369369+ const quotedPost = getEmbeddedPost(item.post.embed)
370370+ if (quotedPost?.author.did === did) {
371371+ yield quotedPost.author
372372+ }
373373+ if (
374374+ AppBskyFeedDefs.isPostView(item.reply?.parent) &&
375375+ item.reply?.parent?.author.did === did
376376+ ) {
377377+ yield item.reply.parent.author
378378+ }
379379+ if (
380380+ AppBskyFeedDefs.isPostView(item.reply?.root) &&
381381+ item.reply?.root?.author.did === did
382382+ ) {
383383+ yield item.reply.root.author
384384+ }
385385+ }
386386+ }
387387+ }
388388+}
+15-8
src/state/cache/post-shadow.ts
···22import {
33 AppBskyEmbedRecord,
44 AppBskyEmbedRecordWithMedia,
55- AppBskyFeedDefs,
55+ type AppBskyFeedDefs,
66} from '@atproto/api'
77-import {QueryClient} from '@tanstack/react-query'
77+import {type QueryClient} from '@tanstack/react-query'
88import EventEmitter from 'eventemitter3'
991010import {batchedUpdates} from '#/lib/batchedUpdates'
1111-import {findAllPostsInQueryData as findAllPostsInNotifsQueryData} from '../queries/notifications/feed'
1212-import {findAllPostsInQueryData as findAllPostsInFeedQueryData} from '../queries/post-feed'
1313-import {findAllPostsInQueryData as findAllPostsInQuoteQueryData} from '../queries/post-quotes'
1414-import {findAllPostsInQueryData as findAllPostsInThreadQueryData} from '../queries/post-thread'
1515-import {findAllPostsInQueryData as findAllPostsInSearchQueryData} from '../queries/search-posts'
1616-import {castAsShadow, Shadow} from './types'
1111+import {findAllPostsInQueryData as findAllPostsInExploreFeedPreviewsQueryData} from '#/state/queries/explore-feed-previews'
1212+import {findAllPostsInQueryData as findAllPostsInNotifsQueryData} from '#/state/queries/notifications/feed'
1313+import {findAllPostsInQueryData as findAllPostsInFeedQueryData} from '#/state/queries/post-feed'
1414+import {findAllPostsInQueryData as findAllPostsInQuoteQueryData} from '#/state/queries/post-quotes'
1515+import {findAllPostsInQueryData as findAllPostsInThreadQueryData} from '#/state/queries/post-thread'
1616+import {findAllPostsInQueryData as findAllPostsInSearchQueryData} from '#/state/queries/search-posts'
1717+import {castAsShadow, type Shadow} from './types'
1718export type {Shadow} from './types'
18191920export interface PostShadow {
···152153 yield post
153154 }
154155 for (let post of findAllPostsInQuoteQueryData(queryClient, uri)) {
156156+ yield post
157157+ }
158158+ for (let post of findAllPostsInExploreFeedPreviewsQueryData(
159159+ queryClient,
160160+ uri,
161161+ )) {
155162 yield post
156163 }
157164}
+20-18
src/state/cache/profile-shadow.ts
···11import {useEffect, useMemo, useState} from 'react'
22-import {QueryClient} from '@tanstack/react-query'
22+import {type QueryClient} from '@tanstack/react-query'
33import EventEmitter from 'eventemitter3'
4455import {batchedUpdates} from '#/lib/batchedUpdates'
66-import * as bsky from '#/types/bsky'
77-import {findAllProfilesInQueryData as findAllProfilesInActorSearchQueryData} from '../queries/actor-search'
88-import {findAllProfilesInQueryData as findAllProfilesInKnownFollowersQueryData} from '../queries/known-followers'
99-import {findAllProfilesInQueryData as findAllProfilesInListMembersQueryData} from '../queries/list-members'
1010-import {findAllProfilesInQueryData as findAllProfilesInListConvosQueryData} from '../queries/messages/list-conversations'
1111-import {findAllProfilesInQueryData as findAllProfilesInMyBlockedAccountsQueryData} from '../queries/my-blocked-accounts'
1212-import {findAllProfilesInQueryData as findAllProfilesInMyMutedAccountsQueryData} from '../queries/my-muted-accounts'
1313-import {findAllProfilesInQueryData as findAllProfilesInFeedsQueryData} from '../queries/post-feed'
1414-import {findAllProfilesInQueryData as findAllProfilesInPostLikedByQueryData} from '../queries/post-liked-by'
1515-import {findAllProfilesInQueryData as findAllProfilesInPostQuotesQueryData} from '../queries/post-quotes'
1616-import {findAllProfilesInQueryData as findAllProfilesInPostRepostedByQueryData} from '../queries/post-reposted-by'
1717-import {findAllProfilesInQueryData as findAllProfilesInPostThreadQueryData} from '../queries/post-thread'
1818-import {findAllProfilesInQueryData as findAllProfilesInProfileQueryData} from '../queries/profile'
1919-import {findAllProfilesInQueryData as findAllProfilesInProfileFollowersQueryData} from '../queries/profile-followers'
2020-import {findAllProfilesInQueryData as findAllProfilesInProfileFollowsQueryData} from '../queries/profile-follows'
2121-import {findAllProfilesInQueryData as findAllProfilesInSuggestedFollowsQueryData} from '../queries/suggested-follows'
2222-import {castAsShadow, Shadow} from './types'
66+import {findAllProfilesInQueryData as findAllProfilesInActorSearchQueryData} from '#/state/queries/actor-search'
77+import {findAllProfilesInQueryData as findAllProfilesInExploreFeedPreviewsQueryData} from '#/state/queries/explore-feed-previews'
88+import {findAllProfilesInQueryData as findAllProfilesInKnownFollowersQueryData} from '#/state/queries/known-followers'
99+import {findAllProfilesInQueryData as findAllProfilesInListMembersQueryData} from '#/state/queries/list-members'
1010+import {findAllProfilesInQueryData as findAllProfilesInListConvosQueryData} from '#/state/queries/messages/list-conversations'
1111+import {findAllProfilesInQueryData as findAllProfilesInMyBlockedAccountsQueryData} from '#/state/queries/my-blocked-accounts'
1212+import {findAllProfilesInQueryData as findAllProfilesInMyMutedAccountsQueryData} from '#/state/queries/my-muted-accounts'
1313+import {findAllProfilesInQueryData as findAllProfilesInFeedsQueryData} from '#/state/queries/post-feed'
1414+import {findAllProfilesInQueryData as findAllProfilesInPostLikedByQueryData} from '#/state/queries/post-liked-by'
1515+import {findAllProfilesInQueryData as findAllProfilesInPostQuotesQueryData} from '#/state/queries/post-quotes'
1616+import {findAllProfilesInQueryData as findAllProfilesInPostRepostedByQueryData} from '#/state/queries/post-reposted-by'
1717+import {findAllProfilesInQueryData as findAllProfilesInPostThreadQueryData} from '#/state/queries/post-thread'
1818+import {findAllProfilesInQueryData as findAllProfilesInProfileQueryData} from '#/state/queries/profile'
1919+import {findAllProfilesInQueryData as findAllProfilesInProfileFollowersQueryData} from '#/state/queries/profile-followers'
2020+import {findAllProfilesInQueryData as findAllProfilesInProfileFollowsQueryData} from '#/state/queries/profile-follows'
2121+import {findAllProfilesInQueryData as findAllProfilesInSuggestedFollowsQueryData} from '#/state/queries/suggested-follows'
2222+import type * as bsky from '#/types/bsky'
2323+import {castAsShadow, type Shadow} from './types'
23242425export type {Shadow} from './types'
2526···154155 yield* findAllProfilesInFeedsQueryData(queryClient, did)
155156 yield* findAllProfilesInPostThreadQueryData(queryClient, did)
156157 yield* findAllProfilesInKnownFollowersQueryData(queryClient, did)
158158+ yield* findAllProfilesInExploreFeedPreviewsQueryData(queryClient, did)
157159}
+23-7
src/state/queries/post-thread.ts
···11import {
22- AppBskyActorDefs,
33- AppBskyEmbedRecord,
22+ type AppBskyActorDefs,
33+ type AppBskyEmbedRecord,
44 AppBskyFeedDefs,
55- AppBskyFeedGetPostThread,
55+ type AppBskyFeedGetPostThread,
66 AppBskyFeedPost,
77 AtUri,
88 moderatePost,
99- ModerationDecision,
1010- ModerationOpts,
99+ type ModerationDecision,
1010+ type ModerationOpts,
1111} from '@atproto/api'
1212-import {QueryClient, useQuery, useQueryClient} from '@tanstack/react-query'
1212+import {type QueryClient, useQuery, useQueryClient} from '@tanstack/react-query'
13131414+import {
1515+ findAllPostsInQueryData as findAllPostsInExploreFeedPreviewsQueryData,
1616+ findAllProfilesInQueryData as findAllProfilesInExploreFeedPreviewsQueryData,
1717+} from '#/state/queries/explore-feed-previews'
1418import {findAllPostsInQueryData as findAllPostsInQuoteQueryData} from '#/state/queries/post-quotes'
1515-import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types'
1919+import {type UsePreferencesQueryResponse} from '#/state/queries/preferences/types'
1620import {
1721 findAllPostsInQueryData as findAllPostsInSearchQueryData,
1822 findAllProfilesInQueryData as findAllProfilesInSearchQueryData,
···495499 for (let post of findAllPostsInSearchQueryData(queryClient, uri)) {
496500 yield postViewToPlaceholderThread(post)
497501 }
502502+ for (let post of findAllPostsInExploreFeedPreviewsQueryData(
503503+ queryClient,
504504+ uri,
505505+ )) {
506506+ yield postViewToPlaceholderThread(post)
507507+ }
498508}
499509500510export function* findAllProfilesInQueryData(
···527537 yield profile
528538 }
529539 for (let profile of findAllProfilesInSearchQueryData(queryClient, did)) {
540540+ yield profile
541541+ }
542542+ for (let profile of findAllProfilesInExploreFeedPreviewsQueryData(
543543+ queryClient,
544544+ did,
545545+ )) {
530546 yield profile
531547 }
532548}