3d6f48c3bd
Fixes the offline-sync defects QA found on PR #120 (#237/#238/#220). Blank-shell / white-screen on offline reload (HIGH): - auth-query.tsx: the useCollabToken retry predicate read `error.response.status` unguarded. Offline the collab-token POST rejects as an axios NETWORK error (isAxiosError true, response undefined), so `.status` threw an uncaught TypeError in the React Query retryer BEFORE React mounted, white-screening every route. Extracted the predicate as `collabTokenRetry` and guarded it with optional chaining (`error.response?.status === 404`). - user-provider.tsx: gated the whole <Layout> on useCurrentUser() and returned a bare `<></>` on any error, blanking every authenticated route offline even when cached data existed. Now renders the cached app when a (stale) user is present and an explicit OfflineFallback when there is no user to fall back on. - query-persister.ts / make-offline.ts: persist and warm the ['currentUser'] query so the auth gate can hydrate offline (pinned pages now survive relaunch). Offline structural create/move/comment silently lost on reload (HIGH): - offline-mutations.ts: register setMutationDefaults (default mutationFns) for stable mutation keys and tag useCreatePageMutation / useMovePageMutation / useCreateCommentMutation with those keys. A paused mutation dehydrated to IndexedDB while offline now has a mutationFn after reload, so resumePausedMutations() replays it on reconnect instead of no-op'ing. Tests (client vitest): collabTokenRetry no longer throws on a no-response network error; UserProvider renders cached children / the offline fallback (not a blank fragment) on a network error; a rehydrated paused create/move is replayable via resumePausedMutations; currentUser persist-root coverage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>