import axios, { type AxiosInstance, type AxiosRequestConfig, type AxiosResponse, type InternalAxiosRequestConfig, } from 'axios' import { clearAuthStorage, AUTH_TOKEN_KEY } from '@/utils/auth-storage' const DEFAULT_TIMEOUT = 15_000 const DEFAULT_API_BASE_URL = '/api' function redirectToLogin() { if (typeof window === 'undefined' || window.location.pathname === '/login') { return } const redirect = `${window.location.pathname}${window.location.search}${window.location.hash}` window.location.assign(`/login?redirect=${encodeURIComponent(redirect)}`) } class Request { private readonly instance: AxiosInstance constructor( baseURL = import.meta.env.VITE_API_BASE_URL || DEFAULT_API_BASE_URL, timeout = DEFAULT_TIMEOUT, ) { this.instance = axios.create({ baseURL, timeout, withCredentials: false, }) this.instance.interceptors.request.use((config: InternalAxiosRequestConfig) => { const token = localStorage.getItem(AUTH_TOKEN_KEY) if (token) { config.headers.set('X-Token', token) } return config }) this.instance.interceptors.response.use( (response: AxiosResponse) => response, (error: unknown) => { if (axios.isAxiosError(error) && error.response?.status === 401) { clearAuthStorage() redirectToLogin() } return Promise.reject(error) }, ) } request(config: AxiosRequestConfig): Promise { return this.instance.request>(config).then((response) => response.data) } get(url: string, config: AxiosRequestConfig = {}): Promise { return this.request({ ...config, url, method: 'GET', }) } post(url: string, data?: unknown, config: AxiosRequestConfig = {}): Promise { return this.request({ ...config, url, data, method: 'POST', }) } put(url: string, data?: unknown, config: AxiosRequestConfig = {}): Promise { return this.request({ ...config, url, data, method: 'PUT', }) } delete(url: string, config: AxiosRequestConfig = {}): Promise { return this.request({ ...config, url, method: 'DELETE', }) } } export const request = new Request() export default request