'use client' import { useState } from 'react' import { SessionProvider } from 'next-auth/react' import { ThemeProvider } from 'next-themes' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { httpBatchLink } from '@trpc/client' import superjson from 'superjson' import { trpc } from '@/lib/trpc/client' function makeQueryClient() { return new QueryClient({ defaultOptions: { queries: { staleTime: 5 * 60 * 1000, // 5 minutes refetchOnWindowFocus: false, retry: (failureCount, error) => { // Retry up to 3 times on server errors (503 cold-start, etc.) if (failureCount >= 3) return false const msg = (error as Error)?.message ?? '' // Retry on JSON parse errors (HTML 503 from nginx) and server errors if (msg.includes('is not valid JSON') || msg.includes('Unexpected token')) return true if (msg.includes('500') || msg.includes('502') || msg.includes('503')) return true return failureCount < 2 }, retryDelay: (attemptIndex) => Math.min(2000 * (attemptIndex + 1), 8000), }, }, }) } let browserQueryClient: QueryClient | undefined = undefined function getQueryClient() { if (typeof window === 'undefined') { // Server: always make a new query client return makeQueryClient() } else { // Browser: make a new query client if we don't already have one if (!browserQueryClient) browserQueryClient = makeQueryClient() return browserQueryClient } } function getBaseUrl() { if (typeof window !== 'undefined') return '' if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}` return `http://localhost:${process.env.PORT ?? 3000}` } export function Providers({ children }: { children: React.ReactNode }) { const queryClient = getQueryClient() const [trpcClient] = useState(() => trpc.createClient({ links: [ httpBatchLink({ url: `${getBaseUrl()}/api/trpc`, transformer: superjson, async fetch(url, options) { const res = await globalThis.fetch(url, options) // Detect nginx 503 / HTML error pages before tRPC tries to JSON.parse if (!res.ok) { const ct = res.headers.get('content-type') ?? '' if (ct.includes('text/html') || !ct.includes('json')) { throw new Error( res.status >= 500 ? 'Server is starting up — please wait a moment and try again.' : `Server error (${res.status})` ) } } return res }, }), ], }) ) return ( {children} ) }