import axios from 'axios'; import cookieService from '../services/cookieService'; // Create axios instance with default config const API_BASE_URL = import.meta.env.VITE_API_URL || (import.meta.env.VITE_NODE_ENV === 'production' ? 'https://zelyanoth-lin-cbfcff2.hf.space' : 'http://localhost:5000'); console.log('API_BASE_URL:', API_BASE_URL); // Ensure API_BASE_URL ends with /api for consistency const normalizedBaseUrl = API_BASE_URL.endsWith('/api') ? API_BASE_URL : `${API_BASE_URL}/api`; const apiClient = axios.create({ baseURL: normalizedBaseUrl, timeout: 30000, headers: { 'Content-Type': 'application/json', }, withCredentials: true, // Send cookies with requests }); // Request interceptor to add auth token apiClient.interceptors.request.use( async (config) => { // Enhanced logging for debugging const isDevelopment = import.meta.env.VITE_NODE_ENV === 'development'; if (isDevelopment) { console.log('🚀 [API Request]', { method: config.method?.toUpperCase(), url: config.baseURL + config.url, headers: config.headers, data: config.data }); } // Get token from cookie service with fallback to localStorage let token = null; try { const tokens = await cookieService.getAuthTokens(); token = tokens?.accessToken; } catch (error) { console.warn('🍪 [Cookie] Error getting auth tokens, trying localStorage:', error.message); token = localStorage.getItem('token'); } if (token) { config.headers.Authorization = `Bearer ${token}`; if (isDevelopment) { console.log('🔑 [Token] Added token to request headers'); } } else { if (isDevelopment) { console.log('🔑 [Token] No token found for request'); } } return config; }, (error) => { console.error('❌ [API Request Error]', error); return Promise.reject(error); } ); // Response interceptor to handle token refresh and errors apiClient.interceptors.response.use( (response) => { // Enhanced logging for debugging const isDevelopment = import.meta.env.VITE_NODE_ENV === 'development'; if (isDevelopment) { console.log('✅ [API Response]', { status: response.status, method: response.config.method?.toUpperCase(), url: response.config.baseURL + response.config.url, data: response.data }); } return response; }, async (error) => { const isDevelopment = import.meta.env.VITE_NODE_ENV === 'development'; const originalRequest = error.config; // Enhanced error logging if (isDevelopment) { console.error('❌ [API Response Error]', { status: error.response?.status, method: originalRequest?.method?.toUpperCase(), url: originalRequest ? originalRequest.baseURL + originalRequest.url : 'unknown', message: error.message, response: error.response?.data, headers: error.response?.headers }); } // Handle 401 Unauthorized errors if (error.response?.status === 401) { if (isDevelopment) { console.log('🔐 [Auth] 401 error detected, attempting token refresh'); } // If we haven't retried this request yet if (!originalRequest._retry) { originalRequest._retry = true; try { // Clear all authentication data await cookieService.clearAuthTokens(); localStorage.removeItem('token'); if (isDevelopment) { console.log('🔐 [Auth] Cleared all authentication data'); } // Redirect to login page const currentPath = window.location.pathname; if (currentPath !== '/login' && currentPath !== '/register') { if (isDevelopment) { console.log('🔐 [Auth] Redirecting to login page'); } window.location.href = '/login'; } } catch (refreshError) { if (isDevelopment) { console.error('🔐 [Auth] Error during token refresh:', refreshError); } // Even if refresh fails, clear auth data await cookieService.clearAuthTokens(); localStorage.removeItem('token'); window.location.href = '/login'; return Promise.reject(refreshError); } } } // Handle network errors if (!error.response) { if (isDevelopment) { console.error('🌐 [Network] No response received:', { url: originalRequest?.baseURL + originalRequest?.url, message: error.message }); } // You might want to implement offline mode here // For now, just reject the error return Promise.reject(error); } return Promise.reject(error); } ); export default apiClient;