import type { PersistQueryClientProviderProps } from '@tanstack/react-query-persist-client' import { QueryClient } from '@tanstack/react-query' import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister' const DEFAULT_STALE_TIME_MS = 30_000 const DEFAULT_GC_TIME_MS = 5 * 60_000 export const makeQueryClient = () => new QueryClient({ defaultOptions: { queries: { staleTime: DEFAULT_STALE_TIME_MS, gcTime: DEFAULT_GC_TIME_MS, refetchOnWindowFocus: true, refetchOnReconnect: true, retry: 1, }, }, }) let browserQueryClient: QueryClient | undefined /** Browser singleton so layout remounts share one cache. */ export const getQueryClient = () => { if (typeof window === 'undefined') { return makeQueryClient() } browserQueryClient ??= makeQueryClient() return browserQueryClient } const PERSIST_STORAGE_KEY = 'ghabilee-admin-query-cache-v1' const LEGACY_PERSIST_STORAGE_KEY = 'ghabilee-query-cache-v2' const PERSIST_MAX_AGE_MS = 24 * 60 * 60_000 /** Inert stand-in for `window.localStorage` during SSR. */ const noopStorage: Storage = { length: 0, clear() { /* SSR inert storage */ }, getItem: () => null, key: () => null, removeItem() { /* SSR inert storage */ }, setItem() { /* SSR inert storage */ }, } const removeStorageKey = (key: string) => { if (typeof window === 'undefined') return try { window.localStorage.removeItem(key) } catch { // Persistence is optional; blocked storage must not break the app. } } let didRemoveLegacyPersistedCache = false const removeLegacyPersistedCache = () => { if (didRemoveLegacyPersistedCache || typeof window === 'undefined') return removeStorageKey(LEGACY_PERSIST_STORAGE_KEY) removeStorageKey('ghabilee-query-cache') didRemoveLegacyPersistedCache = true } /** Remove persisted query state synchronously before ending a user session. */ export const clearPersistedQueryCache = () => { removeStorageKey(PERSIST_STORAGE_KEY) removeStorageKey(LEGACY_PERSIST_STORAGE_KEY) removeStorageKey('ghabilee-query-cache') } /** * Admin does not persist discovery/home-feed caches. Provider shape stays * stable for hydration; dehydrate always returns false. */ export const getQueryPersistOptions = (): PersistQueryClientProviderProps['persistOptions'] => { removeLegacyPersistedCache() return { // eslint-disable-next-line @typescript-eslint/no-deprecated -- sync persister intentional for localStorage persister: createSyncStoragePersister({ storage: typeof window === 'undefined' ? noopStorage : window.localStorage, key: PERSIST_STORAGE_KEY, }), maxAge: PERSIST_MAX_AGE_MS, buster: process.env.NEXT_PUBLIC_APP_VERSION ?? '', dehydrateOptions: { shouldDehydrateQuery: () => false, }, } }