"use client"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { useState } from "react"; export function Providers({ children }: { children: React.ReactNode }) { const [client] = useState( () => new QueryClient({ defaultOptions: { queries: { staleTime: 5 * 60_000, refetchOnWindowFocus: false, // #800: errored query + дефолтный refetchOnMount=true → каждый новый // observer (Topbar/UserMenu/useBrand все дёргают useMe) ре-фетчит при // mount → re-subscribe storm на стойком 401. Выключаем глобально: данные // и так staleTime-кэшируются, а auth/quota не должны бить бэк на ремаунт. refetchOnMount: false, refetchOnReconnect: false, // #770 finding #26 + #800: не ретраить 4xx (401/403/429) — иначе на // rate-limit/протухшей сессии дефолтные 3 ретрая превращаются в шторм // в собственный бэкенд. Ретраим только 5xx/сеть, ≤2 раза. retry: (failureCount, error) => { const status = (error as { status?: number } | null)?.status; if (typeof status === "number" && status >= 400 && status < 500) return false; return failureCount < 2; }, // #800: экспоненциальный backoff на сетевых/5xx ретраях (1s, 2s, 4s… // capped 30s) — никаких немедленных повторов, мягко к бэкенду. retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30_000), }, mutations: { retry: false, }, }, }), ); return {children}; }