- **Motivations :** Assurer passage du lint strict et clarifier la logique paiements/publications. - **Root causes :** Fonctions trop longues, promesses non gérées et typages WebLN/Nostr incomplets. - **Correctifs :** Refactor PaymentModal (handlers void), extraction helpers articlePublisher, simplification polling sponsoring/zap, corrections curly et awaits. - **Evolutions :** Nouveau module articlePublisherHelpers pour présentation/aiguillage contenu privé. - **Page affectées :** components/PaymentModal.tsx, lib/articlePublisher.ts, lib/articlePublisherHelpers.ts, lib/paymentPolling.ts, lib/sponsoring.ts, lib/nostrZapVerification.ts et dépendances liées.
81 lines
1.9 KiB
TypeScript
81 lines
1.9 KiB
TypeScript
/**
|
|
* Retry utility with exponential backoff
|
|
*/
|
|
|
|
export interface RetryOptions {
|
|
maxRetries?: number
|
|
initialDelay?: number
|
|
maxDelay?: number
|
|
backoffMultiplier?: number
|
|
retryable?: (error: Error) => boolean
|
|
}
|
|
|
|
const DEFAULT_OPTIONS: Required<RetryOptions> = {
|
|
maxRetries: 3,
|
|
initialDelay: 1000,
|
|
maxDelay: 10000,
|
|
backoffMultiplier: 2,
|
|
retryable: () => true,
|
|
}
|
|
|
|
/**
|
|
* Retry a function with exponential backoff
|
|
*/
|
|
export function retryWithBackoff<T>(fn: () => Promise<T>, options: RetryOptions = {}): Promise<T> {
|
|
const opts = { ...DEFAULT_OPTIONS, ...options }
|
|
|
|
const attempt = (current: number): Promise<T> => {
|
|
return fn().catch((error) => {
|
|
const normalizedError = error instanceof Error ? error : new Error(String(error))
|
|
|
|
if (!opts.retryable(normalizedError) || current === opts.maxRetries) {
|
|
throw normalizedError
|
|
}
|
|
|
|
const delay = Math.min(opts.initialDelay * Math.pow(opts.backoffMultiplier, current), opts.maxDelay)
|
|
|
|
return new Promise((resolve) => {
|
|
setTimeout(() => {
|
|
resolve(attempt(current + 1))
|
|
}, delay)
|
|
})
|
|
})
|
|
}
|
|
|
|
return attempt(0).catch((error) => {
|
|
throw error ?? new Error('Retry failed')
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Check if an error is a network error that should be retried
|
|
*/
|
|
export function isRetryableNetworkError(error: Error): boolean {
|
|
// Network errors
|
|
if (error.message.includes('network') || error.message.includes('fetch')) {
|
|
return true
|
|
}
|
|
|
|
// Timeout errors
|
|
if (error.message.includes('timeout') || error.message.includes('timed out')) {
|
|
return true
|
|
}
|
|
|
|
// Connection errors
|
|
if (error.message.includes('ECONNRESET') || error.message.includes('ECONNREFUSED')) {
|
|
return true
|
|
}
|
|
|
|
// Rate limiting (429)
|
|
if (error.message.includes('429') || error.message.includes('rate limit')) {
|
|
return true
|
|
}
|
|
|
|
// Server errors (5xx)
|
|
if (error.message.includes('50')) {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|