import axios, { AxiosError } from 'axios'; export interface ApiError { message: string; details?: string; code?: string; } interface ApiErrorResponse { message?: string; error?: string; details?: string; } export const handleApiError = (error: unknown): ApiError => { if (axios.isAxiosError(error)) { const axiosError = error as AxiosError; const responseData = axiosError.response?.data; return { message: axiosError.message, details: responseData?.message || responseData?.error || 'Unknown error occurred', code: axiosError.code, }; } if (error instanceof Error) { return { message: error.message, details: error.stack, }; } return { message: 'An unexpected error occurred', details: String(error), }; }; export const withRetry = async ( operation: () => Promise, maxRetries: number = 3, delay: number = 1000 ): Promise => { let lastError: unknown; for (let i = 0; i < maxRetries; i++) { try { return await operation(); } catch (error) { lastError = error; if (i < maxRetries - 1) { await new Promise(resolve => setTimeout(resolve, delay * Math.pow(2, i))); } } } throw lastError; }; export const validateInput = (input: string, maxLength: number = 100): boolean => { if (!input || typeof input !== 'string') return false; if (input.trim().length === 0) return false; if (input.length > maxLength) return false; return true; }; export const sanitizeInput = (input: string): string => { return input .trim() .replace(/[<>]/g, '') // Remove potential HTML tags .replace(/javascript:/gi, '') // Remove potential JavaScript protocol .slice(0, 100); // Limit length }; // Rate limiting utility export class RateLimiter { private timestamps: number[] = []; private readonly windowMs: number; private readonly maxRequests: number; constructor(windowMs: number = 60000, maxRequests: number = 100) { this.windowMs = windowMs; this.maxRequests = maxRequests; } canMakeRequest(): boolean { const now = Date.now(); this.timestamps = this.timestamps.filter(time => now - time < this.windowMs); if (this.timestamps.length >= this.maxRequests) { return false; } this.timestamps.push(now); return true; } } // Create a rate limiter instance export const rateLimiter = new RateLimiter(); // Wrapper for API calls with rate limiting export const rateLimitedApiCall = async ( apiCall: () => Promise, retryCount: number = 3 ): Promise => { if (!rateLimiter.canMakeRequest()) { throw new Error('Rate limit exceeded. Please try again later.'); } return withRetry(apiCall, retryCount); };