143 lines
3.8 KiB
TypeScript
143 lines
3.8 KiB
TypeScript
/**
|
|
* Error classification system for actionable error messages
|
|
*/
|
|
|
|
export type ErrorType = 'network' | 'payment' | 'validation' | 'loading' | 'unknown'
|
|
|
|
export interface ErrorClassification {
|
|
type: ErrorType
|
|
message: string
|
|
suggestion?: string
|
|
canRetry: boolean
|
|
canCheckConnection: boolean
|
|
needsDocumentation: boolean
|
|
}
|
|
|
|
function isNetworkError(lowerMessage: string): boolean {
|
|
return (
|
|
lowerMessage.includes('network') ||
|
|
lowerMessage.includes('fetch') ||
|
|
lowerMessage.includes('timeout') ||
|
|
lowerMessage.includes('timed out') ||
|
|
lowerMessage.includes('econnreset') ||
|
|
lowerMessage.includes('econnrefused') ||
|
|
lowerMessage.includes('enotfound') ||
|
|
lowerMessage.includes('eai_again') ||
|
|
lowerMessage.includes('dns') ||
|
|
lowerMessage.includes('failed to fetch')
|
|
)
|
|
}
|
|
|
|
function isPaymentError(lowerMessage: string): boolean {
|
|
return (
|
|
lowerMessage.includes('payment') ||
|
|
lowerMessage.includes('invoice') ||
|
|
lowerMessage.includes('webln') ||
|
|
lowerMessage.includes('alby') ||
|
|
lowerMessage.includes('insufficient funds') ||
|
|
lowerMessage.includes('funds')
|
|
)
|
|
}
|
|
|
|
function isValidationError(lowerMessage: string): boolean {
|
|
return (
|
|
lowerMessage.includes('invalid') ||
|
|
lowerMessage.includes('validation') ||
|
|
lowerMessage.includes('required') ||
|
|
lowerMessage.includes('missing')
|
|
)
|
|
}
|
|
|
|
function isLoadingError(lowerMessage: string): boolean {
|
|
return (
|
|
lowerMessage.includes('loading') ||
|
|
lowerMessage.includes('failed to load') ||
|
|
lowerMessage.includes('could not load')
|
|
)
|
|
}
|
|
|
|
function createNetworkClassification(errorMessage: string): ErrorClassification {
|
|
return {
|
|
type: 'network',
|
|
message: errorMessage,
|
|
suggestion: 'errors.network.suggestion',
|
|
canRetry: true,
|
|
canCheckConnection: true,
|
|
needsDocumentation: false,
|
|
}
|
|
}
|
|
|
|
function createPaymentClassification(errorMessage: string): ErrorClassification {
|
|
return {
|
|
type: 'payment',
|
|
message: errorMessage,
|
|
suggestion: 'errors.payment.suggestion',
|
|
canRetry: true,
|
|
canCheckConnection: false,
|
|
needsDocumentation: true,
|
|
}
|
|
}
|
|
|
|
function createValidationClassification(errorMessage: string): ErrorClassification {
|
|
return {
|
|
type: 'validation',
|
|
message: errorMessage,
|
|
suggestion: 'errors.validation.suggestion',
|
|
canRetry: false,
|
|
canCheckConnection: false,
|
|
needsDocumentation: false,
|
|
}
|
|
}
|
|
|
|
function createLoadingClassification(errorMessage: string): ErrorClassification {
|
|
return {
|
|
type: 'loading',
|
|
message: errorMessage,
|
|
suggestion: 'errors.loading.suggestion',
|
|
canRetry: true,
|
|
canCheckConnection: true,
|
|
needsDocumentation: false,
|
|
}
|
|
}
|
|
|
|
function createUnknownClassification(errorMessage: string): ErrorClassification {
|
|
return {
|
|
type: 'unknown',
|
|
message: errorMessage,
|
|
suggestion: 'errors.unknown.suggestion',
|
|
canRetry: true,
|
|
canCheckConnection: false,
|
|
needsDocumentation: false,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Classify an error to determine appropriate recovery actions
|
|
*/
|
|
export function classifyError(error: unknown): ErrorClassification {
|
|
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
const lowerMessage = errorMessage.toLowerCase()
|
|
|
|
if (isNetworkError(lowerMessage)) {
|
|
return createNetworkClassification(errorMessage)
|
|
}
|
|
if (isPaymentError(lowerMessage)) {
|
|
return createPaymentClassification(errorMessage)
|
|
}
|
|
if (isValidationError(lowerMessage)) {
|
|
return createValidationClassification(errorMessage)
|
|
}
|
|
if (isLoadingError(lowerMessage)) {
|
|
return createLoadingClassification(errorMessage)
|
|
}
|
|
|
|
return createUnknownClassification(errorMessage)
|
|
}
|
|
|
|
/**
|
|
* Get user-friendly error message based on classification
|
|
*/
|
|
export function getUserFriendlyMessage(classification: ErrorClassification): string {
|
|
return classification.message
|
|
}
|