@revrag-ai/embed-react-native
Version:
A powerful React Native library for integrating AI-powered voice agents into mobile applications. Features real-time voice communication, intelligent speech processing, customizable UI components, and comprehensive event handling for building conversation
226 lines (210 loc) • 6.52 kB
JavaScript
;
/**
* API Error handling system
* Centralizes all error handling logic with status codes and definitions
*/
/**
* HTTP Status Code definitions
*/
export const HTTP_STATUS_CODES = {
// 2xx Success
200: 'OK',
201: 'Created',
204: 'No Content',
// 4xx Client Errors
400: 'Bad Request',
401: 'Unauthorized',
403: 'Forbidden',
404: 'Not Found',
408: 'Request Timeout',
422: 'Unprocessable Entity',
429: 'Too Many Requests',
// 5xx Server Errors
500: 'Internal Server Error',
502: 'Bad Gateway',
503: 'Service Unavailable',
504: 'Gateway Timeout'
};
/**
* Predefined error types and their definitions
*/
export const ERROR_TYPES = {
NETWORK: {
code: 'NETWORK_ERROR',
message: 'Network request failed. Please check your internet connection and try again.',
type: 'NETWORK'
},
ATS: {
code: 'ATS_ERROR',
message: 'Network request blocked by iOS App Transport Security. Please configure ATS exceptions in Info.plist for HTTP endpoints, or use HTTPS instead.',
type: 'ATS'
},
TIMEOUT: {
code: 'TIMEOUT_ERROR',
message: 'Request timeout. The API server may be slow to respond or unreachable.',
type: 'TIMEOUT'
},
AUTH: {
code: 'AUTH_ERROR',
message: 'Authentication failed. Please check your API credentials.',
type: 'AUTH'
},
SERVER: {
code: 'SERVER_ERROR',
message: 'Server error occurred. Please try again later.',
type: 'SERVER'
},
VALIDATION: {
code: 'VALIDATION_ERROR',
message: 'Invalid request data. Please check your input.',
type: 'VALIDATION'
},
UNKNOWN: {
code: 'UNKNOWN_ERROR',
message: 'An unknown error occurred. Please try again.',
type: 'UNKNOWN'
}
};
/**
* Enhanced error handler that categorizes and formats errors
*/
export class ApiErrorHandler {
/**
* Handle HTTP response errors
*/
static handleHttpError(response, responseData) {
const statusCode = response.status;
const statusText = HTTP_STATUS_CODES[statusCode] || 'Unknown Status';
// Extract error message from response data if available
const serverMessage = responseData?.error || responseData?.message || '';
// Determine error type based on status code
let errorType = 'SERVER';
let code;
let baseMessage;
if (statusCode >= 400 && statusCode < 500) {
if (statusCode === 401 || statusCode === 403) {
errorType = 'AUTH';
code = ERROR_TYPES.AUTH.code;
baseMessage = ERROR_TYPES.AUTH.message;
} else if (statusCode === 408) {
errorType = 'TIMEOUT';
code = ERROR_TYPES.TIMEOUT.code;
baseMessage = ERROR_TYPES.TIMEOUT.message;
} else if (statusCode === 422) {
errorType = 'VALIDATION';
code = ERROR_TYPES.VALIDATION.code;
baseMessage = ERROR_TYPES.VALIDATION.message;
} else {
errorType = 'VALIDATION';
code = ERROR_TYPES.VALIDATION.code;
baseMessage = ERROR_TYPES.VALIDATION.message;
}
} else {
code = ERROR_TYPES.SERVER.code;
baseMessage = ERROR_TYPES.SERVER.message;
}
return {
code,
message: serverMessage || `${baseMessage} (${statusCode}: ${statusText})`,
statusCode,
details: serverMessage ? `HTTP ${statusCode}: ${statusText}` : undefined,
type: errorType
};
}
/**
* Handle network and other runtime errors
*/
static handleRuntimeError(error, apiBaseUrl) {
const errorMessage = error.message.toLowerCase();
// iOS ATS related errors
if (errorMessage.includes('the resource could not be loaded') || errorMessage.includes('app transport security')) {
return {
...ERROR_TYPES.ATS,
message: `${ERROR_TYPES.ATS.message} Error: ${error.message}`,
details: `API endpoint: ${apiBaseUrl}`
};
}
// Network connectivity errors
if (errorMessage.includes('network request failed') || errorMessage.includes('failed to fetch') || errorMessage.includes('fetch')) {
return {
...ERROR_TYPES.NETWORK,
message: `${ERROR_TYPES.NETWORK.message} API endpoint: ${apiBaseUrl}. Error: ${error.message}`,
details: `Endpoint: ${apiBaseUrl}`
};
}
// Timeout errors
if (errorMessage.includes('timeout') || errorMessage.includes('aborted')) {
return {
...ERROR_TYPES.TIMEOUT,
message: `${ERROR_TYPES.TIMEOUT.message} Error: ${error.message}`,
details: `Endpoint: ${apiBaseUrl}`
};
}
// Authentication errors
if (errorMessage.includes('unauthorized') || errorMessage.includes('authentication') || errorMessage.includes('api key')) {
return {
...ERROR_TYPES.AUTH,
message: `${ERROR_TYPES.AUTH.message} Error: ${error.message}`
};
}
// Default to unknown error
return {
...ERROR_TYPES.UNKNOWN,
message: `${ERROR_TYPES.UNKNOWN.message} Error: ${error.message}`
};
}
/**
* Format error for API response
*/
static formatErrorResponse(apiError) {
return {
success: false,
error: apiError.message,
errorCode: apiError.code,
statusCode: apiError.statusCode,
type: apiError.type
};
}
/**
* Main error processing method
*/
static async processApiError(error, response, apiBaseUrl) {
let apiError;
if (response && !response.ok) {
// HTTP error - try to get response data
let responseData;
try {
responseData = await response.json();
} catch (e) {
// If JSON parsing fails, use response text or status
responseData = {
error: response.statusText
};
}
apiError = this.handleHttpError(response, responseData);
} else if (error instanceof Error) {
// Runtime error
apiError = this.handleRuntimeError(error, apiBaseUrl);
} else {
// Unknown error type
apiError = {
...ERROR_TYPES.UNKNOWN,
message: `${ERROR_TYPES.UNKNOWN.message} Details: ${String(error)}`
};
}
return this.formatErrorResponse(apiError);
}
}
/**
* Convenience function for processing API errors
*/
export const processApiError = async (error, response, apiBaseUrl) => {
return ApiErrorHandler.processApiError(error, response, apiBaseUrl);
};
/**
* Type guard to check if a response is an error response
*/
export const isApiErrorResponse = response => {
return response && typeof response === 'object' && response.success === false;
};
//# sourceMappingURL=api.error.js.map