MogensR commited on
Commit
5883557
·
1 Parent(s): 04e54a9

Create web/src/lib/api/clients.ts

Browse files
Files changed (1) hide show
  1. web/src/lib/api/clients.ts +196 -0
web/src/lib/api/clients.ts ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'
2
+ import { getSession } from 'next-auth/react'
3
+
4
+ class APIClient {
5
+ private client: AxiosInstance
6
+ private baseURL: string
7
+
8
+ constructor() {
9
+ this.baseURL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000'
10
+
11
+ this.client = axios.create({
12
+ baseURL: this.baseURL,
13
+ timeout: 30000,
14
+ headers: {
15
+ 'Content-Type': 'application/json',
16
+ },
17
+ })
18
+
19
+ // Request interceptor for auth
20
+ this.client.interceptors.request.use(
21
+ async (config) => {
22
+ const session = await getSession()
23
+ if (session?.accessToken) {
24
+ config.headers.Authorization = `Bearer ${session.accessToken}`
25
+ }
26
+ return config
27
+ },
28
+ (error) => Promise.reject(error)
29
+ )
30
+
31
+ // Response interceptor for error handling
32
+ this.client.interceptors.response.use(
33
+ (response) => response,
34
+ async (error) => {
35
+ if (error.response?.status === 401) {
36
+ // Handle token refresh or redirect to login
37
+ window.location.href = '/login'
38
+ }
39
+ return Promise.reject(error)
40
+ }
41
+ )
42
+ }
43
+
44
+ // Generic request method
45
+ async request<T>(config: AxiosRequestConfig): Promise<T> {
46
+ const response = await this.client.request<T>(config)
47
+ return response.data
48
+ }
49
+
50
+ // Convenience methods
51
+ async get<T>(url: string, config?: AxiosRequestConfig): Promise<T> {
52
+ return this.request<T>({ ...config, method: 'GET', url })
53
+ }
54
+
55
+ async post<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
56
+ return this.request<T>({ ...config, method: 'POST', url, data })
57
+ }
58
+
59
+ async put<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
60
+ return this.request<T>({ ...config, method: 'PUT', url, data })
61
+ }
62
+
63
+ async delete<T>(url: string, config?: AxiosRequestConfig): Promise<T> {
64
+ return this.request<T>({ ...config, method: 'DELETE', url })
65
+ }
66
+
67
+ // File upload
68
+ async upload<T>(
69
+ url: string,
70
+ file: File,
71
+ onProgress?: (progress: number) => void
72
+ ): Promise<T> {
73
+ const formData = new FormData()
74
+ formData.append('file', file)
75
+
76
+ return this.request<T>({
77
+ method: 'POST',
78
+ url,
79
+ data: formData,
80
+ headers: {
81
+ 'Content-Type': 'multipart/form-data',
82
+ },
83
+ onUploadProgress: (progressEvent) => {
84
+ if (onProgress && progressEvent.total) {
85
+ const progress = Math.round(
86
+ (progressEvent.loaded * 100) / progressEvent.total
87
+ )
88
+ onProgress(progress)
89
+ }
90
+ },
91
+ })
92
+ }
93
+
94
+ // WebSocket connection for real-time updates
95
+ createWebSocket(path: string): WebSocket {
96
+ const wsURL = this.baseURL.replace(/^http/, 'ws')
97
+ return new WebSocket(`${wsURL}${path}`)
98
+ }
99
+ }
100
+
101
+ // Export singleton instance
102
+ export const apiClient = new APIClient()
103
+
104
+ // Export typed API methods
105
+ export const api = {
106
+ // Auth
107
+ auth: {
108
+ login: (credentials: { email: string; password: string }) =>
109
+ apiClient.post<{ token: string; user: any }>('/auth/login', credentials),
110
+
111
+ register: (data: { email: string; password: string; name: string }) =>
112
+ apiClient.post<{ token: string; user: any }>('/auth/register', data),
113
+
114
+ logout: () => apiClient.post('/auth/logout'),
115
+
116
+ refreshToken: () =>
117
+ apiClient.post<{ token: string }>('/auth/refresh'),
118
+ },
119
+
120
+ // Processing
121
+ processing: {
122
+ removeBackground: (file: File, options?: any, onProgress?: (p: number) => void) =>
123
+ apiClient.upload<{ id: string; result: string }>('/process/remove-background', file, onProgress),
124
+
125
+ replaceBackground: (imageId: string, backgroundId: string) =>
126
+ apiClient.post<{ result: string }>('/process/replace-background', {
127
+ imageId,
128
+ backgroundId,
129
+ }),
130
+
131
+ batchProcess: (files: File[], options?: any) => {
132
+ const formData = new FormData()
133
+ files.forEach((file) => formData.append('files', file))
134
+ if (options) {
135
+ formData.append('options', JSON.stringify(options))
136
+ }
137
+ return apiClient.post<{ jobId: string }>('/process/batch', formData, {
138
+ headers: { 'Content-Type': 'multipart/form-data' },
139
+ })
140
+ },
141
+
142
+ getJobStatus: (jobId: string) =>
143
+ apiClient.get<{ status: string; progress: number; results?: any[] }>(
144
+ `/process/jobs/${jobId}`
145
+ ),
146
+ },
147
+
148
+ // Projects
149
+ projects: {
150
+ list: (params?: { page?: number; limit?: number; search?: string }) =>
151
+ apiClient.get<{ items: any[]; total: number }>('/projects', { params }),
152
+
153
+ get: (id: string) =>
154
+ apiClient.get<any>(`/projects/${id}`),
155
+
156
+ create: (data: any) =>
157
+ apiClient.post<any>('/projects', data),
158
+
159
+ update: (id: string, data: any) =>
160
+ apiClient.put<any>(`/projects/${id}`, data),
161
+
162
+ delete: (id: string) =>
163
+ apiClient.delete(`/projects/${id}`),
164
+ },
165
+
166
+ // Backgrounds
167
+ backgrounds: {
168
+ list: (category?: string) =>
169
+ apiClient.get<any[]>('/backgrounds', { params: { category } }),
170
+
171
+ upload: (file: File) =>
172
+ apiClient.upload<{ id: string; url: string }>('/backgrounds/upload', file),
173
+
174
+ generate: (prompt: string) =>
175
+ apiClient.post<{ id: string; url: string }>('/backgrounds/generate', { prompt }),
176
+ },
177
+
178
+ // User
179
+ user: {
180
+ profile: () =>
181
+ apiClient.get<any>('/user/profile'),
182
+
183
+ updateProfile: (data: any) =>
184
+ apiClient.put<any>('/user/profile', data),
185
+
186
+ usage: () =>
187
+ apiClient.get<{ images: number; videos: number; storage: number }>(
188
+ '/user/usage'
189
+ ),
190
+
191
+ billing: () =>
192
+ apiClient.get<any>('/user/billing'),
193
+ },
194
+ }
195
+
196
+ export default api