import axios from 'axios'; import { API_BASE_URL } from '../utils/constants'; const api = axios.create({ baseURL: `${API_BASE_URL}/api`, timeout: 10000, // 10s timeout to prevent hanging requests withCredentials: true, // Send cookies with requests (httpOnly cookie authentication) headers: { 'Content-Type': 'application/json' } }); // Request interceptor - no longer needed for token handling (using httpOnly cookies) api.interceptors.request.use( (config) => { // Cookies are automatically sent with each request return config; }, (error) => { return Promise.reject(error); } ); // Response interceptor - handle errors with retry logic api.interceptors.response.use( (response) => { return response; }, async (error) => { const config = error.config; // Handle auth errors (don't retry) if (error.response?.status === 401 || error.response?.status === 403) { // Clear stored session data so React re-renders to login state sessionStorage.removeItem('user'); // Notify the app without a hard page navigation (SPA-safe) window.dispatchEvent(new CustomEvent('auth:unauthorized')); return Promise.reject(error); } // Ohne Request-Config (z. B. Fehler schon beim Aufbau der Anfrage) gibt es // nichts zu wiederholen – vorher lief das in einen TypeError auf undefined. if (!config) { return Promise.reject(error); } // Retry logic for network errors or 5xx errors if (config.retry === undefined) { config.retry = 2; // Default: 2 retries config.retryCount = 0; } const shouldRetry = ( error.code === 'ECONNABORTED' || // Timeout error.code === 'ERR_NETWORK' || // Network error (error.response?.status >= 500 && error.response?.status <= 599) // Server errors ); if (shouldRetry && config.retryCount < config.retry) { config.retryCount += 1; const backoffDelay = Math.min(1000 * Math.pow(2, config.retryCount - 1), 5000); // Exponential backoff await new Promise(resolve => setTimeout(resolve, backoffDelay)); return api.request(config); } return Promise.reject(error); } ); export default api;