import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'; export interface APIClientConfig { baseURL: string; timeout?: number; headers?: Record; } export interface AuthTokens { accessToken: string; refreshToken?: string; } class APIClient { private client: AxiosInstance; private tokens: AuthTokens | null = null; constructor(config: APIClientConfig) { this.client = axios.create({ baseURL: config.baseURL, timeout: config.timeout || 30000, headers: { 'Content-Type': 'application/json', ...config.headers, }, }); // Request interceptor - add auth token this.client.interceptors.request.use((config) => { if (this.tokens?.accessToken) { config.headers.Authorization = `Bearer ${this.tokens.accessToken}`; } return config; }); // Response interceptor - handle token refresh this.client.interceptors.response.use( (response) => response, async (error) => { if (error.response?.status === 401 && this.tokens?.refreshToken) { try { const newTokens = await this.refreshAccessToken(); this.setTokens(newTokens); // Retry original request error.config.headers.Authorization = `Bearer ${newTokens.accessToken}`; return this.client.request(error.config); } catch (refreshError) { // Refresh failed, clear tokens this.clearTokens(); throw refreshError; } } throw error; } ); } setTokens(tokens: AuthTokens) { this.tokens = tokens; } clearTokens() { this.tokens = null; } private async refreshAccessToken(): Promise { const response = await this.client.post('/auth/refresh', { refreshToken: this.tokens?.refreshToken, }); return response.data; } // Auth async login(email: string, password: string) { const response = await this.client.post('/auth/login', { email, password }); return response.data; } async register(email: string, password: string, username: string) { const response = await this.client.post('/auth/register', { email, password, username, }); return response.data; } async getCurrentUser() { const response = await this.client.get('/auth/me'); return response.data; } // Messages async getConversations() { const response = await this.client.get('/conversations'); return response.data; } async getMessages(conversationId: string, limit = 50, before?: string) { const response = await this.client.get(`/messages/${conversationId}`, { params: { limit, before }, }); return response.data; } async sendMessage(conversationId: string, content: string, contentType = 'text') { const response = await this.client.post('/messages', { conversationId, content, contentType, }); return response.data; } // Friends (Nexus) async getFriends() { const response = await this.client.get('/nexus/friends'); return response.data; } async sendFriendRequest(userId: string) { const response = await this.client.post('/nexus/friends/request', { userId }); return response.data; } async acceptFriendRequest(requestId: string) { const response = await this.client.post(`/nexus/friends/accept/${requestId}`); return response.data; } // Calls async initiateCall(recipientId: string, callType: 'voice' | 'video') { const response = await this.client.post('/calls/initiate', { recipientId, callType, }); return response.data; } async joinCall(callId: string) { const response = await this.client.post(`/calls/join/${callId}`); return response.data; } async leaveCall(callId: string) { const response = await this.client.post(`/calls/leave/${callId}`); return response.data; } // Premium async checkDomainAvailability(domain: string) { const response = await this.client.post('/premium/domains/check-availability', { domain, }); return response.data; } async subscribe(tier: string, paymentMethodId: string, billingPeriod: string) { const response = await this.client.post('/premium/subscribe', { tier, paymentMethodId, billingPeriod, }); return response.data; } async getSubscription() { const response = await this.client.get('/premium/subscription'); return response.data; } async getAnalytics(period: string = '30d') { const response = await this.client.get('/premium/analytics', { params: { period }, }); return response.data; } // Generic request method async request(config: AxiosRequestConfig): Promise { const response = await this.client.request(config); return response.data; } } export default APIClient;