import { QueryClient } from "@tanstack/react-query"; import { useEffect, useRef } from "react"; import { apiRequest } from "@/client/lib/http"; export const queryClient = new QueryClient({ defaultOptions: { queries: { // tessera is an IdP/admin surface, so server state should be fresh by // explicit invalidation and route entry, not ambient browser events. gcTime: 0, refetchOnReconnect: false, refetchOnWindowFocus: false, retry: false, }, }, }); export const queryKeys = { accountApps: (userId: string | null) => ["account", userId, "apps"] as const, accountIdentities: (userId: string | null) => ["account", userId, "identities"] as const, accountSessions: (userId: string | null) => ["account", userId, "sessions"] as const, adminClients: (userId: string | null) => ["admin", userId, "clients"] as const, adminInvites: (userId: string | null) => ["admin", userId, "invites"] as const, adminLauncherApps: (userId: string | null) => ["admin", userId, "launcher-apps"] as const, adminUsers: (userId: string | null) => ["admin", userId, "users"] as const, consentClient: (userId: string | null, clientId: string | null) => ["consent-client", userId, clientId] as const, inviteLookup: (token: string | null) => ["invite", token] as const, launcherApps: () => ["launcher", "apps"] as const, preloginClient: (clientId: string | null, signedQuery: string | null) => ["prelogin-client", clientId, signedQuery] as const, }; export const fetchJson = async (url: string): Promise => { const res = await apiRequest(url); if (!res.ok) throw new Error(`HTTP ${res.status}`); return (await res.json()) as T; }; export const useSessionQueryCacheBoundary = (userId: string | null, isPending: boolean): void => { const previousResolvedUserId = useRef(undefined); useEffect(() => { if (isPending) return; if (previousResolvedUserId.current === undefined) { previousResolvedUserId.current = userId; return; } if (previousResolvedUserId.current !== userId) { queryClient.clear(); previousResolvedUserId.current = userId; } }, [isPending, userId]); };