import { useAuthStore } from '@/stores/auth' const API_BASE = '/api' interface RequestOptions { method?: string body?: unknown headers?: Record } let isRefreshing = false let refreshPromise: Promise | null = null /** * Composable for making authenticated API requests. * Automatically attaches JWT token and handles token refresh. */ export function useApi() { const auth = useAuthStore() async function attemptRefresh(): Promise { if (isRefreshing && refreshPromise) { return refreshPromise } isRefreshing = true refreshPromise = (async () => { try { const response = await fetch(`${API_BASE}/auth/refresh`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ refresh_token: auth.refreshToken }), }) if (!response.ok) { throw new Error('Refresh failed') } const data = await response.json() auth.setAuth({ access_token: data.access_token, refresh_token: data.refresh_token, user: auth.user!, }) } catch { auth.logout() window.location.href = '/login' throw new Error('Session expired') } finally { isRefreshing = false refreshPromise = null } })() return refreshPromise } async function request(path: string, options: RequestOptions = {}): Promise { const headers: Record = { 'Content-Type': 'application/json', ...options.headers, } if (auth.accessToken) { headers['Authorization'] = `Bearer ${auth.accessToken}` } let response = await fetch(`${API_BASE}${path}`, { method: options.method || 'GET', headers, body: options.body ? JSON.stringify(options.body) : undefined, }) if (response.status === 401 && auth.refreshToken) { await attemptRefresh() // Retry original request with new token headers['Authorization'] = `Bearer ${auth.accessToken}` response = await fetch(`${API_BASE}${path}`, { method: options.method || 'GET', headers, body: options.body ? JSON.stringify(options.body) : undefined, }) } if (!response.ok) { const error = await response.json().catch(() => ({ message: 'Request failed' })) throw new Error(error.message || `HTTP ${response.status}`) } return response.json() } function get(path: string) { return request(path) } function post(path: string, body?: unknown) { return request(path, { method: 'POST', body }) } function put(path: string, body?: unknown) { return request(path, { method: 'PUT', body }) } function del(path: string) { return request(path, { method: 'DELETE' }) } return { request, get, post, put, del } }