export type RetryOptions = { maxAttempts: number; onAttemptFailure?: (error: unknown, remainingAttempts: number) => void; onAllAttemptsFailed?: (error: unknown) => void; }; export async function retry( action: () => Promise, options: RetryOptions ): Promise { const { maxAttempts, onAttemptFailure, onAllAttemptsFailed } = options; let remainingAttempts = maxAttempts; const delay = (ms: number): Promise => { return new Promise(resolve => setTimeout(resolve, ms)); }; while (remainingAttempts > 0) { try { const result = await action(); return result; } catch (error) { remainingAttempts--; if (onAttemptFailure) { onAttemptFailure(error, remainingAttempts); } if (remainingAttempts <= 0) { if (onAllAttemptsFailed) { onAllAttemptsFailed(error); } throw error; } const waitTime = 1000 * (2 ** (maxAttempts - remainingAttempts)); await delay(waitTime); } } throw new Error('This line should never be reached.'); }