diff --git a/cloakbrowser/browser.py b/cloakbrowser/browser.py index 98d19d6..f6876e2 100644 --- a/cloakbrowser/browser.py +++ b/cloakbrowser/browser.py @@ -21,6 +21,7 @@ from urllib.parse import quote, unquote, urlparse, urlunparse from .config import DEFAULT_VIEWPORT, IGNORE_DEFAULT_ARGS, get_default_stealth_args from .download import ensure_binary +from .human.config import HumanConfigOverrides, HumanPreset logger = logging.getLogger("cloakbrowser") @@ -60,8 +61,8 @@ def launch( geoip: bool = False, backend: str | None = None, humanize: bool = False, - human_preset: str = "default", - human_config: dict | None = None, + human_preset: HumanPreset = "default", + human_config: HumanConfigOverrides | None = None, **kwargs: Any, ) -> Any: """Launch stealth Chromium browser. Returns a Playwright Browser object. @@ -87,7 +88,7 @@ def launch( Override globally with CLOAKBROWSER_BACKEND env var. humanize: Enable human-like mouse, keyboard, scroll behavior (default False). human_preset: Humanize preset — 'default' or 'careful' (default 'default'). - human_config: Custom humanize config dict to override preset values. + human_config: Custom humanize config mapping to override preset values. **kwargs: Passed directly to playwright.chromium.launch(). Returns: @@ -155,8 +156,8 @@ async def launch_async( # noqa: C901 geoip: bool = False, backend: str | None = None, humanize: bool = False, - human_preset: str = "default", - human_config: dict | None = None, + human_preset: HumanPreset = "default", + human_config: HumanConfigOverrides | None = None, **kwargs: Any, ) -> Any: """Async version of launch(). Returns a Playwright Browser object. @@ -172,7 +173,7 @@ async def launch_async( # noqa: C901 backend: Playwright backend — 'playwright' (default) or 'patchright'. humanize: Enable human-like mouse, keyboard, scroll behavior (default False). human_preset: Humanize preset — 'default' or 'careful' (default 'default'). - human_config: Custom humanize config dict to override preset values. + human_config: Custom humanize config mapping to override preset values. **kwargs: Passed directly to playwright.chromium.launch(). Returns: @@ -249,8 +250,8 @@ def launch_persistent_context( geoip: bool = False, backend: str | None = None, humanize: bool = False, - human_preset: str = "default", - human_config: dict | None = None, + human_preset: HumanPreset = "default", + human_config: HumanConfigOverrides | None = None, **kwargs: Any, ) -> Any: """Launch stealth browser with a persistent profile and return a BrowserContext. @@ -279,7 +280,7 @@ def launch_persistent_context( backend: Playwright backend — 'playwright' (default) or 'patchright'. humanize: Enable human-like mouse, keyboard, scroll behavior (default False). human_preset: Humanize preset — 'default' or 'careful' (default 'default'). - human_config: Custom humanize config dict to override preset values. + human_config: Custom humanize config mapping to override preset values. **kwargs: Passed directly to playwright.chromium.launch_persistent_context(). Returns: @@ -373,8 +374,8 @@ async def launch_persistent_context_async( geoip: bool = False, backend: str | None = None, humanize: bool = False, - human_preset: str = "default", - human_config: dict | None = None, + human_preset: HumanPreset = "default", + human_config: HumanConfigOverrides | None = None, **kwargs: Any, ) -> Any: """Async version of launch_persistent_context(). @@ -400,7 +401,7 @@ async def launch_persistent_context_async( backend: Playwright backend — 'playwright' (default) or 'patchright'. humanize: Enable human-like mouse, keyboard, scroll behavior (default False). human_preset: Humanize preset — 'default' or 'careful' (default 'default'). - human_config: Custom humanize config dict to override preset values. + human_config: Custom humanize config mapping to override preset values. **kwargs: Passed directly to playwright.chromium.launch_persistent_context(). Returns: @@ -498,8 +499,8 @@ def launch_context( geoip: bool = False, backend: str | None = None, humanize: bool = False, - human_preset: str = "default", - human_config: dict | None = None, + human_preset: HumanPreset = "default", + human_config: HumanConfigOverrides | None = None, **kwargs: Any, ) -> Any: """Launch stealth browser and return a BrowserContext with common options pre-set. @@ -523,7 +524,7 @@ def launch_context( backend: Playwright backend — 'playwright' (default) or 'patchright'. humanize: Enable human-like mouse, keyboard, scroll behavior (default False). human_preset: Humanize preset — 'default' or 'careful' (default 'default'). - human_config: Custom humanize config dict to override preset values. + human_config: Custom humanize config mapping to override preset values. **kwargs: Passed to browser.new_context(). Returns: diff --git a/cloakbrowser/human/config.py b/cloakbrowser/human/config.py index 1a00abd..ebf6dec 100644 --- a/cloakbrowser/human/config.py +++ b/cloakbrowser/human/config.py @@ -10,7 +10,7 @@ import math import random import time from dataclasses import dataclass, field -from typing import Literal, Tuple +from typing import Literal, Tuple, TypedDict # --------------------------------------------------------------------------- # Type alias @@ -20,6 +20,50 @@ Range = Tuple[float, float] HumanPreset = Literal["default", "careful"] +class HumanConfigOverrides(TypedDict, total=False): + typing_delay: float + typing_delay_spread: float + typing_pause_chance: float + typing_pause_range: Range + shift_down_delay: Range + shift_up_delay: Range + key_hold: Range + field_switch_delay: Range + mistype_chance: float + mistype_delay_notice: Range + mistype_delay_correct: Range + mouse_steps_divisor: float + mouse_min_steps: int + mouse_max_steps: int + mouse_wobble_max: float + mouse_overshoot_chance: float + mouse_overshoot_px: Range + mouse_burst_size: Range + mouse_burst_pause: Range + click_aim_delay_input: Range + click_aim_delay_button: Range + click_hold_input: Range + click_hold_button: Range + click_input_x_range: Range + idle_drift_px: float + idle_pause_range: Range + scroll_delta_base: Range + scroll_delta_variance: float + scroll_pause_fast: Range + scroll_pause_slow: Range + scroll_accel_steps: Range + scroll_decel_steps: Range + scroll_overshoot_chance: float + scroll_overshoot_px: Range + scroll_settle_delay: Range + scroll_target_zone: Range + scroll_pre_move_delay: Range + initial_cursor_x: Range + initial_cursor_y: Range + idle_between_actions: bool + idle_between_duration: Range + + # --------------------------------------------------------------------------- # Configuration dataclass # --------------------------------------------------------------------------- @@ -130,13 +174,13 @@ _PRESETS: dict[str, HumanConfig] = { def resolve_config( preset: HumanPreset = "default", - overrides: dict | None = None, + overrides: HumanConfigOverrides | None = None, ) -> HumanConfig: """Resolve a preset name + optional overrides into a full HumanConfig. Args: preset: 'default' or 'careful'. - overrides: Dict of field names to override values. + overrides: Typed mapping of HumanConfig field names to override values. Returns: A new HumanConfig instance. diff --git a/js/src/playwright.ts b/js/src/playwright.ts index eba5dd1..035acfb 100644 --- a/js/src/playwright.ts +++ b/js/src/playwright.ts @@ -60,8 +60,8 @@ export async function launch(options: LaunchOptions = {}): Promise { const { patchBrowser } = await import('./human/index.js'); const { resolveConfig } = await import('./human/config.js'); const cfg = resolveConfig( - (options.humanPreset as any) ?? 'default', - options.humanConfig as any, + options.humanPreset ?? 'default', + options.humanConfig, ); patchBrowser(browser, cfg); } @@ -125,8 +125,8 @@ export async function launchContext( const { patchContext } = await import('./human/index.js'); const { resolveConfig } = await import('./human/config.js'); const cfg = resolveConfig( - (options.humanPreset as any) ?? 'default', - options.humanConfig as any, + options.humanPreset ?? 'default', + options.humanConfig, ); patchContext(context, cfg); } @@ -189,8 +189,8 @@ export async function launchPersistentContext( const { patchContext } = await import('./human/index.js'); const { resolveConfig } = await import('./human/config.js'); const cfg = resolveConfig( - (options.humanPreset as any) ?? 'default', - options.humanConfig as any, + options.humanPreset ?? 'default', + options.humanConfig, ); patchContext(context, cfg); } diff --git a/js/src/puppeteer.ts b/js/src/puppeteer.ts index 6bb51a9..cc88242 100644 --- a/js/src/puppeteer.ts +++ b/js/src/puppeteer.ts @@ -94,8 +94,8 @@ export async function launch(options: LaunchOptions = {}): Promise { const { patchBrowser } = await import('./human-puppeteer/index.js'); const { resolveConfig } = await import('./human/config.js'); const cfg = resolveConfig( - (options.humanPreset as any) ?? 'default', - options.humanConfig as any, + options.humanPreset ?? 'default', + options.humanConfig, ); patchBrowser(browser, cfg); } diff --git a/js/src/types.ts b/js/src/types.ts index 0e24a6a..5426be7 100644 --- a/js/src/types.ts +++ b/js/src/types.ts @@ -2,6 +2,8 @@ * Shared types for cloakbrowser launch wrappers. */ +import type { HumanConfig, HumanPreset } from "./human/config.js"; + export interface LaunchOptions { /** Run in headless mode (default: true). */ headless?: boolean; @@ -27,9 +29,9 @@ export interface LaunchOptions { /** Enable human-like mouse, keyboard, and scroll behavior. */ humanize?: boolean; /** Human behavior preset: 'default' or 'careful'. */ - humanPreset?: 'default' | 'careful'; + humanPreset?: HumanPreset; /** Override individual human behavior parameters. */ - humanConfig?: Record; + humanConfig?: Partial; } export interface LaunchContextOptions extends LaunchOptions {