From e52f069fc63423b76033a622cc57a52ca4473fb0 Mon Sep 17 00:00:00 2001 From: claude code agent 227 Date: Sun, 21 Jun 2026 03:17:37 +0300 Subject: [PATCH] fix(ws): resync the sidebar tree on socket reconnect (#66) WS events missed during a disconnect (wifi blip, sleep) were lost, so the sidebar tree silently diverged until a manual reload. On RECONNECT (not the first connect) invalidate the root-sidebar-pages + sidebar-pages queries so the tree refetches through the authorized API and re-converges. Co-Authored-By: Claude Opus 4.8 --- apps/client/src/features/user/user-provider.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/apps/client/src/features/user/user-provider.tsx b/apps/client/src/features/user/user-provider.tsx index 4e7c726c..5720f29e 100644 --- a/apps/client/src/features/user/user-provider.tsx +++ b/apps/client/src/features/user/user-provider.tsx @@ -11,6 +11,7 @@ import { useTreeSocket } from "@/features/websocket/use-tree-socket.ts"; import { useNotificationSocket } from "@/features/notification/hooks/use-notification-socket.ts"; import { useCollabToken } from "@/features/auth/queries/auth-query.tsx"; import { Error404 } from "@/components/ui/error-404.tsx"; +import { queryClient } from "@/main.tsx"; export function UserProvider({ children }: React.PropsWithChildren) { const [, setCurrentUser] = useAtom(currentUserAtom); @@ -33,8 +34,19 @@ export function UserProvider({ children }: React.PropsWithChildren) { // @ts-ignore setSocket(newSocket); + // Distinguish the first connect from a reconnect so we only resync after a gap. + let firstConnect = true; newSocket.on("connect", () => { console.log("ws connected"); + if (!firstConnect) { + // On RECONNECT (not the first connect) refetch the sidebar tree through the + // authorized API so the view re-converges after a gap where ws events were + // missed (wifi blip, laptop sleep). Invalidate both the root level and the + // nested-page levels of every space tree. + queryClient.invalidateQueries({ queryKey: ["root-sidebar-pages"] }); + queryClient.invalidateQueries({ queryKey: ["sidebar-pages"] }); + } + firstConnect = false; }); return () => {