// Client-side fetch helper with automatic HttpOnly cookie refresh. export interface ApiResponse { data: T; meta: { timestamp: string; version: "v1" }; error: null | { message: string; code?: string }; } const USER_KEY = "ledgerone_user"; export function getStoredToken(): string { return ""; } export function getStoredUser(): T | null { if (typeof window === "undefined") return null; try { const raw = localStorage.getItem(USER_KEY); return raw ? (JSON.parse(raw) as T) : null; } catch { return null; } } export function storeAuthTokens(data: { accessToken?: string; refreshToken?: string; user: unknown; }): void { localStorage.setItem(USER_KEY, JSON.stringify(data.user)); } export function clearAuth(): void { localStorage.removeItem(USER_KEY); } async function tryRefresh(): Promise { try { const res = await fetch("/api/auth/refresh", { method: "POST", headers: { "Content-Type": "application/json" }, }); if (!res.ok) { clearAuth(); return false; } const payload = (await res.json()) as ApiResponse; if (payload.error) { clearAuth(); return false; } return true; } catch { clearAuth(); return false; } } export async function apiFetch( path: string, options: RequestInit = {} ): Promise> { const headers: Record = { ...(options.headers as Record), }; if ( options.body && typeof options.body === "string" && !headers["Content-Type"] ) { headers["Content-Type"] = "application/json"; } let res = await fetch(path, { ...options, headers }); // Auto-refresh on 401 if (res.status === 401) { const refreshed = await tryRefresh(); if (refreshed) { res = await fetch(path, { ...options, headers }); } else { if (typeof window !== "undefined") { window.location.href = "/login"; } return { data: null as T, meta: { timestamp: new Date().toISOString(), version: "v1" }, error: { message: "Session expired. Please sign in again." }, }; } } return res.json() as Promise>; }