import axios from "axios"; import { AUTH_TOKEN_COOKIE, REFRESH_TOKEN_COOKIE, clearSessionCookies, getCookie, setCookie, } from "./cookies"; import type { AuthTokens } from "./types"; type RetriableRequest = { _retry?: boolean; headers?: Record; url?: string; }; const api = axios.create({ baseURL: `${import.meta.env.VITE_BASE_API_URL}/api`, withCredentials: true, }); let refreshPromise: Promise | null = null; const applyTokens = ({ token, refreshToken }: AuthTokens) => { setCookie(AUTH_TOKEN_COOKIE, token); setCookie(REFRESH_TOKEN_COOKIE, refreshToken); }; api.interceptors.request.use((config) => { const token = getCookie(AUTH_TOKEN_COOKIE); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); api.interceptors.response.use( (response) => { if ( response.data && typeof response.data === "object" && "success" in response.data && "data" in response.data ) { response.data = response.data.data; } return response; }, async (error) => { const originalRequest = error.config as RetriableRequest | undefined; if ( error.response?.status !== 401 || !originalRequest || originalRequest._retry || originalRequest.url?.includes("/auth/login") || originalRequest.url?.includes("/auth/mfa-verify") || originalRequest.url?.includes("/auth/refresh-token") ) { return Promise.reject(error); } const refreshToken = getCookie(REFRESH_TOKEN_COOKIE); if (!refreshToken) { clearSessionCookies(); return Promise.reject(error); } originalRequest._retry = true; try { refreshPromise ??= api .post("/auth/refresh-token", { refreshToken }) .then((response) => response.data) .finally(() => { refreshPromise = null; }); const tokens = await refreshPromise; applyTokens(tokens); originalRequest.headers = { ...originalRequest.headers, Authorization: `Bearer ${tokens.token}`, }; return api(originalRequest); } catch (refreshError) { clearSessionCookies(); window.location.replace("/auth"); return Promise.reject(refreshError); } }, ); export { api, applyTokens };