mirror of
https://github.com/block/buzz.git
synced 2026-11-07 09:52:03 +00:00
## Summary - skip the channel subscription catch-up request when the authoritative channel window was fetched successfully within the existing five-minute freshness period - keep the responsive deferred skeleton for populated channel switches instead of briefly rendering empty-channel actions - preserve a real empty-channel intro across the first appended message only after React has committed that empty state This is intentionally narrow. It does not claim to solve the separate sidebar startup cost or general main-thread stalls found during the investigation. ### Related issue N/A — no matching open issue or PR found. ### Testing - pre-push desktop gate on `f1be6beea90b9715e04e5fc65cc5cfbe8210e0d9`: - desktop tests: 4,621 passed - desktop check: passed - desktop typecheck: passed - branch-skew: passed - focused cache/surface/lifecycle tests: 62 passed - manual diagnostic trace after rollback: - 16/16 channel revisits skipped catch-up refresh - 0 revisit refresh starts - 0 populated-channel empty/intro flashes - cached switches retained the deferred skeleton-to-list path No screenshot: the regression is a transient channel-switch state and request behavior, covered by lifecycle tests and the diagnostic trace rather than a stable visual diff. Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
64 lines
2.0 KiB
TypeScript
64 lines
2.0 KiB
TypeScript
import type { QueryClient } from "@tanstack/react-query";
|
|
|
|
import type { RelayEvent } from "@/shared/api/types";
|
|
import { channelMessagesKey, channelWindowKey } from "./messageQueryKeys";
|
|
import {
|
|
emptyChannelWindowStore,
|
|
type ChannelWindowStore,
|
|
} from "./channelWindowStore";
|
|
import { reconcileChannelWindowMessages } from "./channelWindowReconciliation";
|
|
|
|
export const CHANNEL_WINDOW_FRESH_MS = 5 * 60_000;
|
|
|
|
/**
|
|
* Subscription setup closes the gap between the initial page and live events,
|
|
* but revisiting a channel with a fresh page has no gap to close. Reconnects
|
|
* still refresh unconditionally at their call site.
|
|
*/
|
|
export function shouldRefreshChannelWindowAfterSubscribe(
|
|
queryClient: QueryClient,
|
|
channelId: string,
|
|
now = Date.now(),
|
|
): boolean {
|
|
const messagesState = queryClient.getQueryState(
|
|
channelMessagesKey(channelId),
|
|
);
|
|
if (!messagesState) return true;
|
|
if (messagesState.fetchStatus === "fetching") return false;
|
|
const windowState = queryClient.getQueryState(channelWindowKey(channelId));
|
|
if (
|
|
messagesState.status !== "success" ||
|
|
windowState?.status !== "success" ||
|
|
windowState.dataUpdatedAt === 0
|
|
) {
|
|
return true;
|
|
}
|
|
return now - windowState.dataUpdatedAt >= CHANNEL_WINDOW_FRESH_MS;
|
|
}
|
|
|
|
/** Keep the rendered timeline cache aligned with its authoritative window. */
|
|
export function projectChannelWindowMessages(
|
|
queryClient: QueryClient,
|
|
channelId: string,
|
|
) {
|
|
const window =
|
|
queryClient.getQueryData<ChannelWindowStore>(channelWindowKey(channelId)) ??
|
|
emptyChannelWindowStore();
|
|
queryClient.setQueryData<RelayEvent[]>(
|
|
channelMessagesKey(channelId),
|
|
(messages = []) => reconcileChannelWindowMessages(window, messages),
|
|
);
|
|
}
|
|
|
|
export async function refreshChannelWindowMessages(
|
|
queryClient: QueryClient,
|
|
channelId: string,
|
|
) {
|
|
await queryClient.invalidateQueries({
|
|
queryKey: channelMessagesKey(channelId),
|
|
exact: true,
|
|
refetchType: "active",
|
|
});
|
|
projectChannelWindowMessages(queryClient, channelId);
|
|
}
|