diff --git a/packages/shared/src/store/useChannelPosts/queries.test.ts b/packages/shared/src/store/useChannelPosts/queries.test.ts index 72ee9939f9..41208be599 100644 --- a/packages/shared/src/store/useChannelPosts/queries.test.ts +++ b/packages/shared/src/store/useChannelPosts/queries.test.ts @@ -1,7 +1,11 @@ import { afterEach, describe, expect, it } from 'vitest'; import * as db from '../../db'; -import { getLatestChannelPostsInitialPage, queryKeyPrefix } from './queries'; +import { + getLatestChannelPostsInitialPage, + queryKeyPrefix, + supportsChangedPostsRefresh, +} from './queries'; type TestPageParam = { mode: string; cursorPostId?: string; count?: number }; @@ -15,6 +19,17 @@ const data = (...entries: [string, TestPageParam, number?][]) => ({ const newest = { mode: 'newest' }; +describe('supportsChangedPostsRefresh', () => { + it.each([ + ['chat/~zod/general', true], + ['heap/~zod/gallery', true], + ['~pinser-botter-podfyl-parseb', false], + ['0v4.00000.qd4mk.d4htu.er4b8.eao21', false], + ])('classifies %s', (channelId, expected) => { + expect(supportsChangedPostsRefresh(channelId)).toBe(expected); + }); +}); + describe('getLatestChannelPostsInitialPage', () => { afterEach(() => { db.queryClient.clear(); diff --git a/packages/shared/src/store/useChannelPosts/queries.ts b/packages/shared/src/store/useChannelPosts/queries.ts index 301d072160..c5538dcb49 100644 --- a/packages/shared/src/store/useChannelPosts/queries.ts +++ b/packages/shared/src/store/useChannelPosts/queries.ts @@ -1,9 +1,17 @@ import type { InfiniteData } from '@tanstack/react-query'; +import { isGroupChannelId } from '@tloncorp/api'; import * as db from '../../db'; export const queryKeyPrefix = ['channelPosts']; +// The server's changed-posts endpoint is implemented by group channel nests, +// not %chat DMs or clubs. Those conversations are refreshed by their normal +// DM sync/subscription paths. +export function supportsChangedPostsRefresh(channelId: string): boolean { + return isGroupChannelId(channelId); +} + export function getLatestChannelPostsInitialPage< TPage extends { fetchedAt: number }, TPageParam extends { diff --git a/packages/shared/src/store/useChannelPosts/useChannelPosts.ts b/packages/shared/src/store/useChannelPosts/useChannelPosts.ts index fc26d482ca..488a2a2c97 100644 --- a/packages/shared/src/store/useChannelPosts/useChannelPosts.ts +++ b/packages/shared/src/store/useChannelPosts/useChannelPosts.ts @@ -16,7 +16,11 @@ import * as sync from '../sync'; import { SyncPriority } from '../syncQueue'; import { useDetectSequenceRegression } from '../useDetectSequenceRegression'; import { mergePendingPosts } from '../useMergePendingPosts'; -import { getLatestChannelPostsInitialPage, queryKeyPrefix } from './queries'; +import { + getLatestChannelPostsInitialPage, + queryKeyPrefix, + supportsChangedPostsRefresh, +} from './queries'; import { useDeletedPosts, useNewPostListener } from './subscriptions'; const postsLogger = createDevLogger('useChannelPosts', false); @@ -509,6 +513,10 @@ function useRefreshPosts(channelId: string, posts: db.Post[] | null) { const pendingStalePosts = useRef(new Set()); useEffect(() => { + if (!supportsChangedPostsRefresh(channelId)) { + return; + } + const toSync = posts?.filter( (post) => @@ -527,23 +535,32 @@ function useRefreshPosts(channelId: string, posts: db.Post[] | null) { } postsLogger.log('chunked', chunked.length); - chunked.forEach((chunk, i) => { + chunked.forEach((chunk) => { const startCursor = chunk[chunk.length - 1].id; const endCursor = chunk[0].id; + const pendingIds = chunk.map((post) => post.id); postsLogger.log('syncing chunk', startCursor, 'through', endCursor); - sync.syncUpdatedPosts( - { - channelId, - startCursor, - endCursor, - afterTime: new Date(session?.startTime ?? 0), - }, - { priority: 4 } - ); pendingStalePosts.current = new Set([ - ...chunk.map((p) => p.id), + ...pendingIds, ...pendingStalePosts.current, ]); + void sync + .syncUpdatedPosts( + { + channelId, + startCursor, + endCursor, + afterTime: new Date(session?.startTime ?? 0), + }, + { priority: 4 } + ) + .catch((error) => { + pendingIds.forEach((id) => pendingStalePosts.current.delete(id)); + postsLogger.trackError( + 'failed to refresh stale posts', + error instanceof Error ? error : { error } + ); + }); }); }, [channelId, posts, session]); }