const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000/api/v1'; export interface ApiError { error: { code: string; message: string; details?: unknown; }; } export interface PaginatedResponse { items: T[]; total: number; page: number; page_size: number; } export interface TokenResponse { access_token: string; refresh_token: string; token_type: string; expires_in: number; } export interface UserResponse { id: string; email: string; full_name: string; role: string; language: string; is_active: boolean; created_at?: string; updated_at?: string; } function getAuthToken(): string | null { if (typeof window === 'undefined') return null; return localStorage.getItem('access_token'); } function getRefreshToken(): string | null { if (typeof window === 'undefined') return null; return localStorage.getItem('refresh_token'); } export function setTokens(tokens: TokenResponse): void { if (typeof window === 'undefined') return; localStorage.setItem('access_token', tokens.access_token); localStorage.setItem('refresh_token', tokens.refresh_token); } export function clearTokens(): void { if (typeof window === 'undefined') return; localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); } export function isAuthenticated(): boolean { return getAuthToken() !== null; } async function apiFetch( path: string, options: RequestInit = {} ): Promise { const token = getAuthToken(); const headers: Record = { 'Content-Type': 'application/json', ...((options.headers as Record) || {}), }; if (token) { headers['Authorization'] = `Bearer ${token}`; } const response = await fetch(`${API_BASE_URL}${path}`, { ...options, headers, }); if (response.status === 401 && token) { const refreshToken = getRefreshToken(); if (refreshToken) { const refreshResult = await apiFetch('/auth/refresh', { method: 'POST', body: JSON.stringify({ refresh_token: refreshToken }), }); setTokens(refreshResult); headers['Authorization'] = `Bearer ${refreshResult.access_token}`; const retryResponse = await fetch(`${API_BASE_URL}${path}`, { ...options, headers, }); if (!retryResponse.ok) { const err = await retryResponse.json().catch(() => ({ error: { code: 'UNKNOWN', message: 'Request failed' } })); throw err as ApiError; } return retryResponse.json(); } clearTokens(); } if (!response.ok) { const err = await response.json().catch(() => ({ error: { code: 'UNKNOWN', message: 'Request failed' } })); throw err as ApiError; } return response.json(); } export async function login(email: string, password: string): Promise { return apiFetch('/auth/login', { method: 'POST', body: JSON.stringify({ email, password }), }); } export async function getCurrentUser(): Promise { return apiFetch('/auth/me'); } export async function listUsers(page = 1, pageSize = 20): Promise> { return apiFetch>(`/users/?page=${page}&page_size=${pageSize}`); } export async function createUser(data: { email: string; password: string; full_name: string; role: string; language: string; }): Promise { return apiFetch('/users/', { method: 'POST', body: JSON.stringify(data), }); } export async function deleteUser(userId: string): Promise { return apiFetch(`/users/${userId}`, { method: 'DELETE' }); } export async function healthCheck(): Promise<{ status: string }> { return apiFetch<{ status: string }>('/health'); } export { API_BASE_URL };