Skip to content
File

Blob: src/client/lib/query.ts

typescript57 lines
1import { QueryClient } from "@tanstack/react-query";
2import { useEffect, useRef } from "react";
3 
4import { apiRequest } from "@/client/lib/http";
5 
6export const queryClient = new QueryClient({
7 defaultOptions: {
8 queries: {
9 // tessera is an IdP/admin surface, so server state should be fresh by
10 // explicit invalidation and route entry, not ambient browser events.
11 gcTime: 0,
12 refetchOnReconnect: false,
13 refetchOnWindowFocus: false,
14 retry: false,
15 },
16 },
17});
18 
19export const queryKeys = {
20 accountApps: (userId: string | null) => ["account", userId, "apps"] as const,
21 accountIdentities: (userId: string | null) => ["account", userId, "identities"] as const,
22 accountSessions: (userId: string | null) => ["account", userId, "sessions"] as const,
23 adminClients: (userId: string | null) => ["admin", userId, "clients"] as const,
24 adminInvites: (userId: string | null) => ["admin", userId, "invites"] as const,
25 adminLauncherApps: (userId: string | null) => ["admin", userId, "launcher-apps"] as const,
26 adminUsers: (userId: string | null) => ["admin", userId, "users"] as const,
27 consentClient: (userId: string | null, clientId: string | null) => ["consent-client", userId, clientId] as const,
28 inviteLookup: (token: string | null) => ["invite", token] as const,
29 launcherApps: () => ["launcher", "apps"] as const,
30 preloginClient: (clientId: string | null, signedQuery: string | null) =>
31 ["prelogin-client", clientId, signedQuery] as const,
32};
33 
34export const fetchJson = async <T>(url: string): Promise<T> => {
35 const res = await apiRequest(url);
36 if (!res.ok) throw new Error(`HTTP ${res.status}`);
37 return (await res.json()) as T;
38};
39 
40export const useSessionQueryCacheBoundary = (userId: string | null, isPending: boolean): void => {
41 const previousResolvedUserId = useRef<string | null | undefined>(undefined);
42 
43 useEffect(() => {
44 if (isPending) return;
45 
46 if (previousResolvedUserId.current === undefined) {
47 previousResolvedUserId.current = userId;
48 return;
49 }
50 
51 if (previousResolvedUserId.current !== userId) {
52 queryClient.clear();
53 previousResolvedUserId.current = userId;
54 }
55 }, [isPending, userId]);
56};