/** * Human-like behavior helpers. * * Anti-bot stacks (Akamai, DataDome, PerimeterX) fingerprint behavior * on top of TLS/network: timing distributions, mouse activity, scroll * patterns, navigation chains. Fixed-interval `sleep(N)` loops are * the #1 tell. These helpers add the kind of variance a real session * exhibits without going overboard. * * What we DO simulate: * - Variable inter-action pauses (uniform jitter + occasional long pauses) * - Burst-pause patterns (humans cluster activity) * - Mouse paths on page load (Akamai's sensor data weighs these) * - Smooth/jittered scrolling (no scrollBy-every-500ms tell) * - Warmup navigation (homepage → search → result vs. direct deep-link) * * What we DON'T: * - Random keystrokes (overkill on SRPs) * - Random link clicks (would fire real conversion pixels — ethics) * - Mid-session UA rotation (itself a bot signal) */ import type { Page } from "playwright"; export interface HumanizeConfig { /** Base pace multiplier. 1.0 = normal, 2.0 = slow/cautious, 0.5 = fast. */ readonly pace?: number; /** Probability of a "long pause" between actions (mimics reading/distraction). 0..1. */ readonly longPauseProb?: number; } export interface HumanizeAPI { /** Sleep for a random duration in [minMs, maxMs] (multiplied by pace). */ pause: (minMs: number, maxMs: number) => Promise; /** * Process N items in bursts: groups of `burstSize` happen quickly, * then a long pause before the next group. Mimics "browse a few * listings, then step away" patterns. */ burst: (items: readonly T[], handler: (item: T, index: number) => Promise, options?: BurstOptions) => Promise; /** Move the mouse along a curved path across the viewport. */ moveMouse: (page: Page, options?: MouseOptions) => Promise; /** * Visit a homepage/landing URL first to seed cookies and trust signals, * then navigate to the target. Does nothing if the page is already on * the same origin. */ warmup: (page: Page, homepageUrl: string, options?: WarmupOptions) => Promise; /** Scroll a page with variable step and delay (less robotic than autoScroll). */ jitteredScroll: (page: Page, options?: JitteredScrollOptions) => Promise; } export interface BurstOptions { /** Items per fast group. Default 3. */ readonly burstSize?: number; /** Fast-pause range between items in the same burst, ms. Default [800, 2500]. */ readonly intraBurst?: readonly [number, number]; /** Long-pause range between bursts, ms. Default [8000, 25000]. */ readonly interBurst?: readonly [number, number]; } export interface MouseOptions { /** Number of waypoints in the path. Default 8. */ readonly steps?: number; /** Total duration of the move in ms. Default 600. */ readonly durationMs?: number; } export interface WarmupOptions { /** Skip if last warmup was within this many ms. Default 600_000 (10 min). */ readonly cooldownMs?: number; /** Pause range on the homepage before continuing, ms. Default [1500, 4000]. */ readonly dwell?: readonly [number, number]; } export interface JitteredScrollOptions { /** Min/max px per step. Default [200, 900]. */ readonly step?: readonly [number, number]; /** Min/max delay between steps, ms. Default [400, 1100]. */ readonly delay?: readonly [number, number]; /** Probability of scrolling UP a bit (mimics re-reading). 0..1. Default 0.1. */ readonly reverseProb?: number; /** Safety cap on iterations. Default 40. */ readonly maxSteps?: number; /** Stop after this many no-growth iterations. Default 3. */ readonly idleRounds?: number; } export interface JitteredScrollResult { readonly steps: number; readonly finalHeight: number; readonly hitMax: boolean; readonly reversals: number; } /** Uniform random integer in [min, max]. */ export declare function randInt(min: number, max: number): number; /** Uniform random float in [min, max). */ export declare function randFloat(min: number, max: number): number; export declare function makeHumanize(config?: HumanizeConfig): HumanizeAPI;