import { ENV } from '@/configs/env';
import useAuthStore from '@/store/use-auth-store';
import axios from 'axios';
type FailedQueue = Array<{
resolve: (token: string | null) => void;
reject: (error: unknown) => void;
}>;
export const apiCall = axios.create({
baseURL: ENV.NEXT_PUBLIC_SERVER_URL,
withCredentials: true,
});
apiCall.interceptors.request.use((config) => {
const { accessToken } = useAuthStore.getState();
if (accessToken) {
config.headers.Authorization = `Bearer ${accessToken}`;
}
return config;
});
let isRefreshing = false;
let failedQueue: FailedQueue = [];
const processQueue = (error: unknown, token: string | null = null) => {
for (const { resolve, reject } of failedQueue) {
if (error) {
reject(error);
} else {
resolve(token);
}
}
failedQueue = [];
};
apiCall.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;
if (error.response?.status !== 401 || originalRequest._retry || originalRequest.url === '/auth/refresh') {
throw error;
}
if (isRefreshing) {
return new Promise((resolve, reject) => {
failedQueue.push({ resolve, reject });
}).then((token) => {
originalRequest.headers.Authorization = `Bearer ${token}`;
return apiCall(originalRequest);
});
}
originalRequest._retry = true;
isRefreshing = true;
try {
const newToken = await useAuthStore.getState().refreshAccessToken();
if (!newToken) {
processQueue(new Error('Refresh failed'));
throw error;
}
processQueue(null, newToken);
originalRequest.headers.Authorization = `Bearer ${newToken}`;
return apiCall(originalRequest);
} catch (refreshError) {
processQueue(refreshError);
throw refreshError;
} finally {
isRefreshing = false;
}
},
);