import { ENV_CONSTANT } from '@/constants/secrect.constant'; import { useAppStore } from '@/store/app.store'; import { useAuthStore } from '@/store/auth.store'; import axios from 'axios'; const BASE_URL = ENV_CONSTANT.BASE_API_URL; const axiosClient = axios.create({ baseURL: BASE_URL, withCredentials: true, headers: { 'Content-Type': 'application/json', }, }); export const axiosAuth = axios.create({ baseURL: BASE_URL, withCredentials: true, headers: { 'Content-Type': 'application/json', }, }); let refreshPromise: Promise | null = null; const isInvalidSessionResponse = (error: unknown) => { if (!axios.isAxiosError(error)) return false; return error.response?.status === 401 || error.response?.status === 403; }; const refreshAccessToken = () => { if (!refreshPromise) { refreshPromise = axiosAuth .post('api/auth/refresh', {}) .then((response) => { const accessToken = response.data?.access_token; if (!accessToken) { throw new Error('Refresh failed: no access token'); } useAuthStore.getState().setAccessToken(accessToken); return accessToken; }) .catch((error: unknown) => { if (isInvalidSessionResponse(error)) { useAuthStore.getState().logout(); useAppStore.getState().clear(); if (typeof window !== 'undefined') { window.location.href = '/login'; } } throw error; }) .finally(() => { refreshPromise = null; }); } return refreshPromise; }; axiosClient.interceptors.request.use( (config) => { const token = useAuthStore.getState().accessToken; if (token && config.headers) { config.headers.Authorization = `Bearer ${token}`; } return config; }, (error) => { return Promise.reject(error); }, ); axiosClient.interceptors.response.use( (response) => response, async (error) => { const originalRequest = error?.config; const status = error?.response?.status; const requestUrl = originalRequest?.url ?? ''; const isAuthRoute = requestUrl.includes('api/auth/login') || requestUrl.includes('api/auth/refresh') || requestUrl.includes('api/auth/forget-password') || requestUrl.includes('api/auth/reset-password') || requestUrl.includes('api/auth/set-password'); if ( status === 401 && originalRequest && !originalRequest._retry && !isAuthRoute ) { originalRequest._retry = true; try { const accessToken = await refreshAccessToken(); originalRequest.headers.Authorization = `Bearer ${accessToken}`; return axiosClient(originalRequest); } catch (refreshError) { return Promise.reject(refreshError); } } return Promise.reject(error); }, ); export default axiosClient;