import axios, { AxiosInstance } from 'axios'; import type { User, AuthTokens, Asset, AssetListResponse, CreateUploadRequest, CreateUploadResponse, DownloadUrlResponse, Share, CreateShareRequest, ShareWithAssetResponse, } from '../types'; const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000'; class ApiClient { private client: AxiosInstance; constructor() { this.client = axios.create({ baseURL: `${API_URL}/api/v1`, headers: { 'Content-Type': 'application/json', }, }); // Add auth token to requests this.client.interceptors.request.use((config) => { const token = localStorage.getItem('access_token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); // Handle 401 errors this.client.interceptors.response.use( (response) => response, (error) => { if (error.response?.status === 401) { localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); window.location.href = '/login'; } return Promise.reject(error); } ); } // Auth async register(email: string, password: string): Promise { const { data } = await this.client.post('/auth/register', { email, password }); return data; } async login(email: string, password: string): Promise { const { data } = await this.client.post('/auth/login', { email, password }); localStorage.setItem('access_token', data.access_token); localStorage.setItem('refresh_token', data.refresh_token); return data; } async getMe(): Promise { const { data } = await this.client.get('/auth/me'); return data; } logout(): void { localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); } // Assets async listAssets(params?: { cursor?: string; limit?: number; type?: string; }): Promise { const { data } = await this.client.get('/assets', { params }); return data; } async getAsset(assetId: string): Promise { const { data } = await this.client.get(`/assets/${assetId}`); return data; } async getDownloadUrl(assetId: string, kind: 'original' | 'thumb' = 'original'): Promise { const { data } = await this.client.get( `/assets/${assetId}/download-url`, { params: { kind } } ); return data.url; } async getMediaBlob(assetId: string, kind: 'original' | 'thumb' = 'original'): Promise { const response = await this.client.get(`/assets/${assetId}/media`, { params: { kind }, responseType: 'blob', }); return response.data; } async deleteAsset(assetId: string): Promise { const { data } = await this.client.delete(`/assets/${assetId}`); return data; } async restoreAsset(assetId: string): Promise { const { data } = await this.client.post(`/assets/${assetId}/restore`); return data; } async purgeAsset(assetId: string): Promise { await this.client.delete(`/assets/${assetId}/purge`); } // Upload async createUpload(request: CreateUploadRequest): Promise { const { data } = await this.client.post('/uploads/create', request); return data; } async uploadToS3(url: string, file: File, fields?: Record): Promise { const formData = new FormData(); // Add fields first (for pre-signed POST) if (fields) { Object.entries(fields).forEach(([key, value]) => { formData.append(key, value); }); } // Add file last formData.append('file', file); await axios.post(url, formData, { headers: { 'Content-Type': 'multipart/form-data', }, }); } async uploadFileToBackend(assetId: string, file: File): Promise { const formData = new FormData(); formData.append('file', file); await this.client.post(`/uploads/${assetId}/file`, formData, { headers: { 'Content-Type': 'multipart/form-data', }, }); } async finalizeUpload(assetId: string, etag?: string, sha256?: string): Promise { const { data } = await this.client.post(`/uploads/${assetId}/finalize`, { etag, sha256 }); return data; } // Shares async createShare(request: CreateShareRequest): Promise { const { data } = await this.client.post('/shares', request); return data; } async getShare(token: string, password?: string): Promise { const { data } = await this.client.get(`/shares/${token}`, { params: password ? { password } : undefined, }); return data; } async getShareDownloadUrl( token: string, assetId: string, kind: 'original' | 'thumb' = 'original', password?: string ): Promise { const { data } = await this.client.get( `/shares/${token}/download-url`, { params: { asset_id: assetId, kind, password }, } ); return data.url; } async revokeShare(token: string): Promise { const { data } = await this.client.post(`/shares/${token}/revoke`); return data; } } export default new ApiClient();