import axios from 'axios'; import { tokenStorage } from '../utils/tokenStorage'; // Replace with your machine's LAN IP when testing on a physical device export const BASE_URL = 'http://192.168.2.56:8000/api/v1'; export const apiClient = axios.create({ baseURL: BASE_URL, timeout: 10000, }); // Attach access token from in-memory cache (synchronous — no await needed) apiClient.interceptors.request.use((config) => { const token = tokenStorage.getAccessTokenSync(); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); // Refresh token on 401 let isRefreshing = false; let queue: Array<{ resolve: (token: string) => void; reject: (err: unknown) => void }> = []; function processQueue(error: unknown, token: string | null = null) { queue.forEach((p) => (error ? p.reject(error) : p.resolve(token!))); queue = []; } apiClient.interceptors.response.use( (res) => res, async (error) => { const original = error.config; if (error.response?.status === 401 && !original._retry) { if (isRefreshing) { return new Promise((resolve, reject) => { queue.push({ resolve: (token) => { original.headers.Authorization = `Bearer ${token}`; resolve(apiClient(original)); }, reject, }); }); } original._retry = true; isRefreshing = true; try { const refreshToken = tokenStorage.getRefreshTokenSync(); if (!refreshToken) throw new Error('No refresh token'); const { data } = await axios.post(`${BASE_URL}/auth/refresh`, { refresh_token: refreshToken, }); await tokenStorage.saveTokens(data.access_token, data.refresh_token); apiClient.defaults.headers.common.Authorization = `Bearer ${data.access_token}`; processQueue(null, data.access_token); original.headers.Authorization = `Bearer ${data.access_token}`; return apiClient(original); } catch (err) { processQueue(err, null); await tokenStorage.clearTokens(); return Promise.reject(err); } finally { isRefreshing = false; } } return Promise.reject(error); } );