import { getSession } from 'next-auth/react'; const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001/api'; /** * API client configuration */ interface RequestConfig extends RequestInit { params?: Record; } /** * Build URL with query parameters */ function buildUrl(endpoint: string, params?: RequestConfig['params']): string { const url = new URL(`${API_URL}${endpoint}`); if (params) { Object.entries(params).forEach(([key, value]) => { if (value !== undefined) { url.searchParams.append(key, String(value)); } }); } return url.toString(); } /** * Make an authenticated API request */ async function request(endpoint: string, config: RequestConfig = {}): Promise { const { params, ...init } = config; // Get session for auth token const session = await getSession(); const headers: HeadersInit = { 'Content-Type': 'application/json', ...(init.headers || {}), }; // Add auth header if session exists if (session?.accessToken) { (headers as Record)['Authorization'] = `Bearer ${session.accessToken}`; } const response = await fetch(buildUrl(endpoint, params), { ...init, headers, }); // Handle non-OK responses if (!response.ok) { const error = await response.json().catch(() => ({ message: 'An error occurred' })); throw new Error(error.message || `HTTP error ${response.status}`); } // Handle empty responses const contentType = response.headers.get('content-type'); if (contentType?.includes('application/json')) { const json = await response.json(); // Unwrap backend's {success, data, timestamp} envelope if (json && typeof json === 'object' && 'success' in json && 'data' in json) { return json.data as T; } return json as T; } return {} as T; } /** * API client with typed methods */ export const api = { /** * GET request */ get(endpoint: string, config?: RequestConfig): Promise { return request(endpoint, { ...config, method: 'GET' }); }, /** * POST request */ post(endpoint: string, data?: unknown, config?: RequestConfig): Promise { return request(endpoint, { ...config, method: 'POST', body: data ? JSON.stringify(data) : undefined, }); }, /** * PUT request */ put(endpoint: string, data?: unknown, config?: RequestConfig): Promise { return request(endpoint, { ...config, method: 'PUT', body: data ? JSON.stringify(data) : undefined, }); }, /** * PATCH request */ patch(endpoint: string, data?: unknown, config?: RequestConfig): Promise { return request(endpoint, { ...config, method: 'PATCH', body: data ? JSON.stringify(data) : undefined, }); }, /** * DELETE request */ delete(endpoint: string, config?: RequestConfig): Promise { return request(endpoint, { ...config, method: 'DELETE' }); }, }; export default api;