From 99ed1eb604932a66b625eba33e14fb2b1fd48d5e Mon Sep 17 00:00:00 2001 From: Hrishikesh Mandal Date: Wed, 4 Feb 2026 00:13:49 +0530 Subject: [PATCH] feat: add comprehensive error handling utilities for API services This file provides error handling utilities, including custom error types, type guards, and functions for async operations with timeout and retry logic.- Add custom error types: APIError, ValidationError, TimeoutError - Implement type guards for response validation - Add withTimeout() for async operation timeout handling - Add withRetry() with exponential backoff for failed requests - Add safeAPICall() wrapper for consistent error handling - Provides foundation for Issue #13 implementation Related to: #13 --- services/errorHandling.ts | 108 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 services/errorHandling.ts diff --git a/services/errorHandling.ts b/services/errorHandling.ts new file mode 100644 index 0000000..37f438a --- /dev/null +++ b/services/errorHandling.ts @@ -0,0 +1,108 @@ +/** + * Error Handling Utilities for Procastify + * Provides comprehensive error handling, validation, and recovery mechanisms + * for API services and async operations. + */ + +// Custom Error Types +export class APIError extends Error { + constructor( + public statusCode: number, + public originalError: unknown, + message: string + ) { + super(message); + this.name = 'APIError'; + } +} + +export class ValidationError extends Error { + constructor(message: string) { + super(message); + this.name = 'ValidationError'; + } +} + +export class TimeoutError extends Error { + constructor(message: string) { + super(message); + this.name = 'TimeoutError'; + } +} + +// Type Guard for API Responses +export function isValidResponse(data: unknown): data is T { + return data !== null && data !== undefined && typeof data === 'object'; +} + +// Async Operation with Timeout +export async function withTimeout( + promise: Promise, + timeoutMs: number = 30000 +): Promise { + const timeoutPromise = new Promise((_, reject) => { + setTimeout(() => { + reject(new TimeoutError(`Operation timed out after ${timeoutMs}ms`)); + }, timeoutMs); + }); + return Promise.race([promise, timeoutPromise]); +} + +// Retry Logic with Exponential Backoff +export async function withRetry( + fn: () => Promise, + maxRetries: number = 3, + initialDelay: number = 1000 +): Promise { + let lastError: Error | null = null; + + for (let attempt = 0; attempt <= maxRetries; attempt++) { + try { + return await fn(); + } catch (error) { + lastError = error as Error; + if (attempt < maxRetries) { + const delay = initialDelay * Math.pow(2, attempt); + await new Promise(resolve => setTimeout(resolve, delay)); + } + } + } + + throw lastError || new Error('Operation failed after retries'); +} + +// Safe API Call Wrapper +export async function safeAPICall( + apiFunction: () => Promise, + operationName: string, + timeoutMs?: number +): Promise<{ success: boolean; data?: T; error?: Error }> { + try { + const operation = timeoutMs + ? withTimeout(apiFunction(), timeoutMs) + : apiFunction(); + + const data = await operation; + return { success: true, data }; + } catch (error) { + const errorMessage = error instanceof Error + ? error.message + : 'Unknown error occurred'; + + console.error(`[${operationName}] Error:`, errorMessage); + return { + success: false, + error: new Error(`${operationName}: ${errorMessage}`) + }; + } +} + +export default { + APIError, + ValidationError, + TimeoutError, + isValidResponse, + withTimeout, + withRetry, + safeAPICall, +};