/**
 * @file `pRetry` — exponential-backoff retry with optional jitter, abort-signal
 *   support, and an `onRetry` hook for customizing delays or canceling retries
 *   entirely. Cycles with `iterate.ts`: pRetry is called by pEach / pEachChunk
 *   / pFilter / pFilterChunk to apply per-item retry. ESM tolerates the cycle
 *   since both sides reference each other through functions only.
 */
import type { RetryOptions } from './types';
/**
 * Retry an async function with exponential backoff.
 *
 * Attempts to execute a function multiple times with increasing delays between
 * attempts. Implements exponential backoff with optional jitter to prevent
 * thundering herd problems. Supports custom retry logic via `onRetry`
 * callback.
 *
 * The delay calculation follows: `min(baseDelayMs * (backoffFactor ** attempt),
 * maxDelayMs)` With jitter: adds random value between 0 and calculated delay.
 *
 * @example
 *   // Simple retry: 3 attempts with default backoff
 *   const data = await pRetry(async () => {
 *     return await fetchData()
 *   }, 3)
 *
 * @example
 *   // Custom backoff strategy
 *   const result = await pRetry(
 *     async () => {
 *       return await unreliableOperation()
 *     },
 *     {
 *       retries: 5,
 *       baseDelayMs: 1000, // Start at 1 second
 *       backoffFactor: 2, // Double each time
 *       maxDelayMs: 30000, // Cap at 30 seconds
 *       jitter: true, // Add randomness
 *     },
 *   )
 *   // Delays: ~1s, ~2s, ~4s, ~8s, ~16s (each ± random jitter)
 *
 * @example
 *   // With custom retry logic
 *   const data = await pRetry(
 *     async () => {
 *       return await apiCall()
 *     },
 *     {
 *       retries: 3,
 *       onRetry: (attempt, error, delay) => {
 *         console.log(`Attempt ${attempt} failed: ${error}`)
 *         console.log(`Waiting ${delay}ms before retry...`)
 *
 *         // Cancel retries for client errors (4xx)
 *         if (error.statusCode >= 400 && error.statusCode < 500) {
 *           return false
 *         }
 *
 *         // Use longer delay for rate limit errors
 *         if (error.statusCode === 429) {
 *           return 60000 // Wait 1 minute
 *         }
 *       },
 *       onRetryCancelOnFalse: true,
 *     },
 *   )
 *
 * @example
 *   // With cancellation support
 *   const controller = new AbortController()
 *   setTimeout(() => controller.abort(), 5000) // Cancel after 5s
 *
 *   const result = await pRetry(
 *     async ({ signal }) => {
 *       return await longRunningTask(signal)
 *     },
 *     {
 *       retries: 10,
 *       signal: controller.signal,
 *     },
 *   )
 *   // Returns undefined if aborted
 *
 * @example
 *   // Pass arguments to callback
 *   const result = await pRetry(
 *     async (url, options) => {
 *       return await fetch(url, options)
 *     },
 *     {
 *       retries: 3,
 *       args: ['https://api.example.com', { method: 'POST' }],
 *     },
 *   )
 *
 * @template T - The return type of the callback function.
 *
 * @param callbackFn - Async function to retry.
 * @param options - Retry count as number, or full retry options, or undefined.
 *
 * @returns Promise resolving to callback result, or `undefined` if aborted
 *
 * @throws {Error} The last error if all retry attempts fail
 */
export declare function pRetry<T>(callbackFn: (...args: unknown[]) => Promise<T>, options?: number | RetryOptions | undefined): Promise<T | undefined>;
