import axios, { type AxiosRequestConfig } from "axios"; const BASE_URL = import.meta.env.VITE_API_BASE_URL ?? "http://localhost:8000"; export const apiClient = axios.create({ baseURL: BASE_URL, withCredentials: true, headers: { "Content-Type": "application/json" } }); export const shouldSkipAuthRedirect = (path: string): boolean => { return path.startsWith("/login") || path.startsWith("/auth"); }; // Retry config for transient network errors const MAX_RETRIES = 2; const RETRY_DELAY_MS = 1000; // Track retry count per request const retryCount = new WeakMap(); apiClient.interceptors.response.use( (response) => response, async (error) => { const status = error?.response?.status; if (status === 401 && !shouldSkipAuthRedirect(window.location.pathname)) { window.location.assign(`${BASE_URL}/auth/login`); return Promise.reject(error); } // Retry on transient network errors (ERR_NETWORK_CHANGED, etc.) const isNetworkError = !error.response && error.message?.includes("Network"); const isRetryable = isNetworkError || status >= 502; // 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout if (isRetryable) { const config = error.config; const currentRetry = retryCount.get(config) || 0; if (currentRetry < MAX_RETRIES) { retryCount.set(config, currentRetry + 1); // Wait before retrying await new Promise(resolve => setTimeout(resolve, RETRY_DELAY_MS * (currentRetry + 1))); return apiClient(config); } } return Promise.reject(error); } );