function resolveApiUrl() { const raw = (import.meta.env.VITE_API_URL || "").trim(); const fallback = "/api/v1"; if (!raw) return fallback; try { const parsed = new URL(raw, window.location.origin); if (window.location.protocol === "https:" && parsed.protocol === "http:") { // Avoid mixed-content when UI is served over HTTPS. parsed.protocol = "https:"; } return parsed.toString().replace(/\/$/, ""); } catch { return fallback; } } const API_URL = resolveApiUrl(); export async function apiFetch(path, options = {}, tokens, onUnauthorized) { const headers = { "Content-Type": "application/json", ...(options.headers || {}), }; if (tokens?.accessToken) { headers.Authorization = `Bearer ${tokens.accessToken}`; } let res = await fetch(`${API_URL}${path}`, { ...options, headers }); if (res.status === 401 && tokens?.refreshToken && onUnauthorized) { const refreshed = await onUnauthorized(); if (refreshed) { headers.Authorization = `Bearer ${refreshed.accessToken}`; res = await fetch(`${API_URL}${path}`, { ...options, headers }); } } if (!res.ok) { const txt = await res.text(); throw new Error(txt || `HTTP ${res.status}`); } if (res.status === 204) return null; return res.json(); } export { API_URL };