UNPKG

page-retry

Version:

Automatic retry and proxy fallback for Playwright powered by Aluvia.

136 lines (135 loc) 4.89 kB
import type { Page, Response } from "playwright"; export type RetryPattern = string | RegExp; type GoToOptions = NonNullable<Parameters<Page["goto"]>[1]>; export interface RetryWithProxyRunner { goto(url: string, options?: GoToOptions): Promise<{ response: Response | null; page: Page; }>; } export type ProxySettings = { server: string; username?: string; password?: string; }; export interface ProxyProvider { get(): Promise<ProxySettings>; } declare enum AluviaErrorCode { NoApiKey = "ALUVIA_NO_API_KEY", NoProxy = "ALUVIA_NO_PROXIES", ProxyFetchFailed = "ALUVIA_PROXY_FETCH_FAILED", InsufficientBalance = "ALUVIA_INSUFFICIENT_BALANCE", BalanceFetchFailed = "ALUVIA_BALANCE_FETCH_FAILED" } export declare class AluviaError extends Error { code?: AluviaErrorCode; constructor(message: string, code?: AluviaErrorCode); } export interface RetryWithProxyOptions { /** * Number of retry attempts after the first failed navigation. * * The first `page.goto()` is always attempted without a proxy. * If it fails with a retryable error (as defined by `retryOn`), * the helper will fetch a new proxy and relaunch the browser. * * @default process.env.ALUVIA_MAX_RETRIES || 1 * @example * // Try up to 3 proxy relaunches after the first failure * { maxRetries: 3 } */ maxRetries?: number; /** * Base delay (in milliseconds) for exponential backoff between retries. * * Each retry waits `backoffMs * 2^attempt + random(0–100)` before continuing. * Useful to avoid hammering proxy endpoints or triggering rate limits. * * @default process.env.ALUVIA_BACKOFF_MS || 300 * @example * // Start with 500ms and double each time (with jitter) * { backoffMs: 500 } */ backoffMs?: number; /** * List of error patterns that are considered retryable. * * A pattern can be a string or a regular expression. When a navigation error’s * message, name, or code matches any of these, the helper will trigger a retry. * * @default process.env.ALUVIA_RETRY_ON * or ["ECONNRESET", "ETIMEDOUT", "net::ERR", "Timeout"] * @example * // Retry on connection resets and 403 responses * { retryOn: ["ECONNRESET", /403/] } */ retryOn?: RetryPattern[]; /** * Whether to close the old browser instance when relaunching with a new proxy. * * Set to `true` (default) to prevent multiple browsers from staying open, * which is safer for most workflows. Set to `false` if you manage browser * lifecycles manually or reuse a shared browser across tasks. * * @default true * @example * // Keep old browser open (you must close it yourself) * { closeOldBrowser: false } */ closeOldBrowser?: boolean; /** * Optional custom proxy provider used to fetch proxy credentials. * * By default, `retryWithProxy` automatically uses the Aluvia API * via the `aluvia-ts-sdk` and reads the API key from * `process.env.ALUVIA_API_KEY`. * * Supplying your own `proxyProvider` allows you to integrate with * any proxy rotation service, database, or in-house pool instead. * * A proxy provider must expose a `get()` method that returns a * `Promise<ProxySettings>` object with `server`, and optionally * `username` and `password` fields. * * @default Uses the built-in Aluvia client with `process.env.ALUVIA_API_KEY` * @example * ```ts * import { retryWithProxy } from "page-retry"; * * // Custom proxy provider example * const myProxyProvider = { * async get() { * // Pull from your own proxy pool or API * return { * server: "http://myproxy.example.com:8000", * username: "user123", * password: "secret", * }; * }, * }; * * const { response, page } = await retryWithProxy(page, { * proxyProvider: myProxyProvider, * maxRetries: 3, * }); * ``` */ proxyProvider?: ProxyProvider; /** * Optional callback fired before each retry attempt (after backoff). * * @param attempt Current retry attempt number (1-based) * @param maxRetries Maximum number of retries * @param lastError The error that triggered the retry */ onRetry?: (attempt: number, maxRetries: number, lastError: unknown) => void | Promise<void>; /** * Optional callback fired when a proxy has been successfully fetched. * * @param proxy The proxy settings that were fetched or provided */ onProxyLoaded?: (proxy: ProxySettings) => void | Promise<void>; } export declare function retryWithProxy(page: Page, options?: RetryWithProxyOptions): RetryWithProxyRunner; export {};