import createClient from "openapi-fetch"; import createQueryClient from "openapi-react-query"; import type { paths } from "./generated/schema"; const apiBaseUrl = import.meta.env.VITE_API_BASE_URL ?? "http://localhost:3000"; type AuthHandlers = { accessToken: () => string | null; refresh: () => Promise; clear: () => void; }; let auth: AuthHandlers | null = null; let hasAuthenticatedSession = false; const authSessionListeners = new Set<() => void>(); function setAuthenticatedSession(next: boolean) { if (next === hasAuthenticatedSession) return; hasAuthenticatedSession = next; for (const listener of authSessionListeners) listener(); } function configureAuthClient(handlers: AuthHandlers | null) { auth = handlers; setAuthenticatedSession(Boolean(auth?.accessToken())); } function getAuthenticatedSessionSnapshot() { return hasAuthenticatedSession; } function subscribeAuthenticatedSession(listener: () => void) { authSessionListeners.add(listener); return () => authSessionListeners.delete(listener); } async function authenticatedFetch(request: Request): Promise { const isAuthRequest = new URL(request.url).pathname.startsWith( "/api/v1/auth/", ); const token = auth?.accessToken(); const withToken = (source: Request, value: string) => { const headers = new Headers(source.headers); headers.set("Authorization", `Bearer ${value}`); return new Request(source, { headers }); }; const authorized = token && !isAuthRequest ? withToken(request, token) : request; const retryRequest = authorized.clone(); const response = await fetch(authorized); if ( response.status !== 401 || isAuthRequest || !auth || ( await response .clone() .json() .catch(() => null) )?.code !== "UNAUTHORIZED" ) return response; if (!(await auth.refresh())) { auth.clear(); return response; } const refreshedToken = auth.accessToken(); return refreshedToken ? fetch(withToken(retryRequest, refreshedToken)) : response; } const apiClient = createClient({ baseUrl: apiBaseUrl, credentials: "include", fetch: authenticatedFetch, }); const apiQueryClient = createQueryClient(apiClient); export { apiClient, apiQueryClient, configureAuthClient, getAuthenticatedSessionSnapshot, subscribeAuthenticatedSession, };