import axios, { AxiosInstance, AxiosRequestConfig } from 'axios' import { getSession } from 'next-auth/react' class APIClient { private client: AxiosInstance private baseURL: string constructor() { this.baseURL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000' this.client = axios.create({ baseURL: this.baseURL, timeout: 30000, headers: { 'Content-Type': 'application/json', }, }) // Request interceptor for auth this.client.interceptors.request.use( async (config) => { const session = await getSession() if (session?.accessToken) { config.headers.Authorization = `Bearer ${session.accessToken}` } return config }, (error) => Promise.reject(error) ) // Response interceptor for error handling this.client.interceptors.response.use( (response) => response, async (error) => { if (error.response?.status === 401) { // Handle token refresh or redirect to login window.location.href = '/login' } return Promise.reject(error) } ) } // Generic request method async request(config: AxiosRequestConfig): Promise { const response = await this.client.request(config) return response.data } // Convenience methods async get(url: string, config?: AxiosRequestConfig): Promise { return this.request({ ...config, method: 'GET', url }) } async post(url: string, data?: any, config?: AxiosRequestConfig): Promise { return this.request({ ...config, method: 'POST', url, data }) } async put(url: string, data?: any, config?: AxiosRequestConfig): Promise { return this.request({ ...config, method: 'PUT', url, data }) } async delete(url: string, config?: AxiosRequestConfig): Promise { return this.request({ ...config, method: 'DELETE', url }) } // File upload async upload( url: string, file: File, onProgress?: (progress: number) => void ): Promise { const formData = new FormData() formData.append('file', file) return this.request({ method: 'POST', url, data: formData, headers: { 'Content-Type': 'multipart/form-data', }, onUploadProgress: (progressEvent) => { if (onProgress && progressEvent.total) { const progress = Math.round( (progressEvent.loaded * 100) / progressEvent.total ) onProgress(progress) } }, }) } // WebSocket connection for real-time updates createWebSocket(path: string): WebSocket { const wsURL = this.baseURL.replace(/^http/, 'ws') return new WebSocket(`${wsURL}${path}`) } } // Export singleton instance export const apiClient = new APIClient() // Export typed API methods export const api = { // Auth auth: { login: (credentials: { email: string; password: string }) => apiClient.post<{ token: string; user: any }>('/auth/login', credentials), register: (data: { email: string; password: string; name: string }) => apiClient.post<{ token: string; user: any }>('/auth/register', data), logout: () => apiClient.post('/auth/logout'), refreshToken: () => apiClient.post<{ token: string }>('/auth/refresh'), }, // Processing processing: { removeBackground: (file: File, options?: any, onProgress?: (p: number) => void) => apiClient.upload<{ id: string; result: string }>('/process/remove-background', file, onProgress), replaceBackground: (imageId: string, backgroundId: string) => apiClient.post<{ result: string }>('/process/replace-background', { imageId, backgroundId, }), batchProcess: (files: File[], options?: any) => { const formData = new FormData() files.forEach((file) => formData.append('files', file)) if (options) { formData.append('options', JSON.stringify(options)) } return apiClient.post<{ jobId: string }>('/process/batch', formData, { headers: { 'Content-Type': 'multipart/form-data' }, }) }, getJobStatus: (jobId: string) => apiClient.get<{ status: string; progress: number; results?: any[] }>( `/process/jobs/${jobId}` ), }, // Projects projects: { list: (params?: { page?: number; limit?: number; search?: string }) => apiClient.get<{ items: any[]; total: number }>('/projects', { params }), get: (id: string) => apiClient.get(`/projects/${id}`), create: (data: any) => apiClient.post('/projects', data), update: (id: string, data: any) => apiClient.put(`/projects/${id}`, data), delete: (id: string) => apiClient.delete(`/projects/${id}`), }, // Backgrounds backgrounds: { list: (category?: string) => apiClient.get('/backgrounds', { params: { category } }), upload: (file: File) => apiClient.upload<{ id: string; url: string }>('/backgrounds/upload', file), generate: (prompt: string) => apiClient.post<{ id: string; url: string }>('/backgrounds/generate', { prompt }), }, // User user: { profile: () => apiClient.get('/user/profile'), updateProfile: (data: any) => apiClient.put('/user/profile', data), usage: () => apiClient.get<{ images: number; videos: number; storage: number }>( '/user/usage' ), billing: () => apiClient.get('/user/billing'), }, } export default api