page-retry
Version:
Automatic retry and proxy fallback for Playwright powered by Aluvia.
136 lines (135 loc) • 4.89 kB
TypeScript
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 {};