# DO NOT EDIT THIS FILE!
#
# This file is generated from the WebDriver BiDi specification. If you need to make
# changes, edit the generator and regenerate all of the modules.
#
# WebDriver BiDi module: network
from __future__ import annotations

from collections.abc import Callable
from dataclasses import dataclass, field
from typing import Any

from selenium.webdriver.common.bidi.common import command_builder
from selenium.webdriver.common.bidi._event_manager import EventConfig, _EventWrapper, _EventManager

class SameSite:
    """SameSite."""

    STRICT = "strict"
    LAX = "lax"
    NONE = "none"
    DEFAULT = "default"


class DataType:
    """DataType."""

    REQUEST = "request"
    RESPONSE = "response"


class InterceptPhase:
    """InterceptPhase."""

    BEFOREREQUESTSENT = "beforeRequestSent"
    RESPONSESTARTED = "responseStarted"
    AUTHREQUIRED = "authRequired"


class ContinueWithAuthNoCredentials:
    """ContinueWithAuthNoCredentials."""

    DEFAULT = "default"
    CANCEL = "cancel"


@dataclass
class AuthChallenge:
    """AuthChallenge."""

    scheme: str | None = None
    realm: str | None = None


@dataclass
class AuthCredentials:
    """AuthCredentials."""

    type: str = field(default="password", init=False)
    username: str | None = None
    password: str | None = None


@dataclass
class BaseParameters:
    """BaseParameters."""

    context: Any | None = None
    is_blocked: bool | None = None
    navigation: Any | None = None
    redirect_count: Any | None = None
    request: Any | None = None
    timestamp: Any | None = None
    user_context: Any | None = None
    intercepts: list[Any] = field(default_factory=list)


@dataclass
class StringValue:
    """StringValue."""

    type: str = field(default="string", init=False)
    value: str | None = None


@dataclass
class Base64Value:
    """Base64Value."""

    type: str = field(default="base64", init=False)
    value: str | None = None


@dataclass
class Cookie:
    """Cookie."""

    name: str | None = None
    value: Any | None = None
    domain: str | None = None
    path: str | None = None
    size: Any | None = None
    http_only: bool | None = None
    secure: bool | None = None
    same_site: Any | None = None
    expiry: Any | None = None


@dataclass
class CookieHeader:
    """CookieHeader."""

    name: str | None = None
    value: Any | None = None


@dataclass
class FetchTimingInfo:
    """FetchTimingInfo."""

    time_origin: Any | None = None
    request_time: Any | None = None
    redirect_start: Any | None = None
    redirect_end: Any | None = None
    fetch_start: Any | None = None
    dns_start: Any | None = None
    dns_end: Any | None = None
    connect_start: Any | None = None
    connect_end: Any | None = None
    tls_start: Any | None = None
    request_start: Any | None = None
    response_start: Any | None = None
    response_end: Any | None = None


@dataclass
class Header:
    """Header."""

    name: str | None = None
    value: Any | None = None


@dataclass
class Initiator:
    """Initiator."""

    column_number: Any | None = None
    line_number: Any | None = None
    request: Any | None = None
    stack_trace: Any | None = None
    type: Any | None = None


@dataclass
class ResponseContent:
    """ResponseContent."""

    size: Any | None = None


@dataclass
class ResponseData:
    """ResponseData."""

    url: str | None = None
    protocol: str | None = None
    status: Any | None = None
    status_text: str | None = None
    from_cache: bool | None = None
    headers: list[Any] = field(default_factory=list)
    mime_type: str | None = None
    bytes_received: Any | None = None
    headers_size: Any | None = None
    body_size: Any | None = None
    content: Any | None = None
    auth_challenges: list[Any] = field(default_factory=list)


@dataclass
class SetCookieHeader:
    """SetCookieHeader."""

    name: str | None = None
    value: Any | None = None
    domain: str | None = None
    http_only: bool | None = None
    expiry: str | None = None
    max_age: Any | None = None
    path: str | None = None
    same_site: Any | None = None
    secure: bool | None = None


@dataclass
class UrlPatternPattern:
    """UrlPatternPattern."""

    type: str = field(default="pattern", init=False)
    protocol: str | None = None
    hostname: str | None = None
    port: str | None = None
    pathname: str | None = None
    search: str | None = None


@dataclass
class UrlPatternString:
    """UrlPatternString."""

    type: str = field(default="string", init=False)
    pattern: str | None = None


@dataclass
class AddDataCollectorParameters:
    """AddDataCollectorParameters."""

    data_types: list[Any] = field(default_factory=list)
    max_encoded_data_size: Any | None = None
    collector_type: Any | None = None
    contexts: list[Any] = field(default_factory=list)
    user_contexts: list[Any] = field(default_factory=list)


@dataclass
class AddDataCollectorResult:
    """AddDataCollectorResult."""

    collector: Any | None = None


@dataclass
class AddInterceptParameters:
    """AddInterceptParameters."""

    phases: list[Any] = field(default_factory=list)
    contexts: list[Any] = field(default_factory=list)
    url_patterns: list[Any] = field(default_factory=list)


@dataclass
class AddInterceptResult:
    """AddInterceptResult."""

    intercept: Any | None = None


@dataclass
class ContinueResponseParameters:
    """ContinueResponseParameters."""

    request: Any | None = None
    cookies: list[Any] = field(default_factory=list)
    credentials: Any | None = None
    headers: list[Any] = field(default_factory=list)
    reason_phrase: str | None = None
    status_code: Any | None = None


@dataclass
class ContinueWithAuthParameters:
    """ContinueWithAuthParameters."""

    request: Any | None = None


@dataclass
class ContinueWithAuthCredentials:
    """ContinueWithAuthCredentials."""

    action: str = field(default="provideCredentials", init=False)
    credentials: Any | None = None


@dataclass
class FailRequestParameters:
    """FailRequestParameters."""

    request: Any | None = None


@dataclass
class GetDataParameters:
    """GetDataParameters."""

    data_type: Any | None = None
    collector: Any | None = None
    disown: bool | None = None
    request: Any | None = None


@dataclass
class GetDataResult:
    """GetDataResult."""

    bytes: Any | None = None


@dataclass
class ProvideResponseParameters:
    """ProvideResponseParameters."""

    request: Any | None = None
    body: Any | None = None
    cookies: list[Any] = field(default_factory=list)
    headers: list[Any] = field(default_factory=list)
    reason_phrase: str | None = None
    status_code: Any | None = None


@dataclass
class RemoveDataCollectorParameters:
    """RemoveDataCollectorParameters."""

    collector: Any | None = None


@dataclass
class RemoveInterceptParameters:
    """RemoveInterceptParameters."""

    intercept: Any | None = None


@dataclass
class SetCacheBehaviorParameters:
    """SetCacheBehaviorParameters."""

    cache_behavior: Any | None = None
    contexts: list[Any] = field(default_factory=list)


@dataclass
class SetExtraHeadersParameters:
    """SetExtraHeadersParameters."""

    headers: list[Any] = field(default_factory=list)
    contexts: list[Any] = field(default_factory=list)
    user_contexts: list[Any] = field(default_factory=list)


@dataclass
class AuthRequiredParameters:
    """AuthRequiredParameters."""

    response: Any | None = None


@dataclass
class BeforeRequestSentParameters:
    """BeforeRequestSentParameters."""

    initiator: Any | None = None


@dataclass
class FetchErrorParameters:
    """FetchErrorParameters."""

    error_text: str | None = None


@dataclass
class ResponseCompletedParameters:
    """ResponseCompletedParameters."""

    response: Any | None = None


@dataclass
class ResponseStartedParameters:
    """ResponseStartedParameters."""

    response: Any | None = None


@dataclass
class DisownDataParameters:
    """DisownDataParameters."""

    data_type: Any | None = None
    collector: Any | None = None
    request: Any | None = None


# Backward-compatible alias for existing imports
disownDataParameters = DisownDataParameters

class BytesValue:
    """A string or base64-encoded bytes value used in cookie operations.

    This corresponds to network.BytesValue in the WebDriver BiDi specification,
    wrapping either a plain string or a base64-encoded binary value.
    """

    TYPE_STRING = "string"
    TYPE_BASE64 = "base64"

    def __init__(self, type: Any | None, value: Any | None) -> None:
        self.type = type
        self.value = value

    def to_bidi_dict(self) -> dict:
        return {"type": self.type, "value": self.value}

from selenium.webdriver.common.bidi._network_handlers import (
    LEGACY_REQUEST_HANDLER_EVENTS,
    AuthenticationRequest,
    AuthHandlerRegistry,
    Request,
    RequestHandlerRegistry,
    Response,
    ResponseHandlerRegistry,
    looks_like_url_glob,
)

# BiDi Event Name to Parameter Type Mapping
EVENT_NAME_MAPPING = {
    "auth_required": "network.authRequired",
    "before_request_sent": "network.beforeRequestSent",
    "fetch_error": "network.fetchError",
    "response_completed": "network.responseCompleted",
    "response_started": "network.responseStarted",
    "auth_required": "network.authRequired",
    "before_request": "network.beforeRequestSent",
    "response_started": "network.responseStarted",
}

class Network:
    """WebDriver BiDi network module."""

    EVENT_CONFIGS: dict[str, EventConfig] = {}
    def __init__(self, conn) -> None:
        self._conn = conn
        self._event_manager = _EventManager(conn, self.EVENT_CONFIGS)
        self.intercepts: list[Any] = []
        self._handler_intercepts: dict[str, Any] = {}
        self._request_handlers = RequestHandlerRegistry(self)
        self._response_handlers = ResponseHandlerRegistry(self)
        self._auth_handlers = AuthHandlerRegistry(self)

    def add_data_collector(
        self,
        data_types: list[Any] | None = None,
        max_encoded_data_size: Any | None = None,
        collector_type: Any | None = None,
        contexts: list[Any] | None = None,
        user_contexts: list[Any] | None = None,
    ):
        """Execute network.addDataCollector"""
        if data_types is None:
            raise TypeError("add_data_collector() missing required argument: 'data_types'")
        if max_encoded_data_size is None:
            raise TypeError("add_data_collector() missing required argument: 'max_encoded_data_size'")

        params = {
            "dataTypes": data_types,
            "maxEncodedDataSize": max_encoded_data_size,
            "collectorType": collector_type,
            "contexts": contexts,
            "userContexts": user_contexts,
        }
        params = {k: v for k, v in params.items() if v is not None}
        cmd = command_builder("network.addDataCollector", params)
        result = self._conn.execute(cmd)
        return result

    def add_intercept(
        self,
        phases: list[Any] | None = None,
        contexts: list[Any] | None = None,
        url_patterns: list[Any] | None = None,
    ):
        """Execute network.addIntercept"""
        if phases is None:
            raise TypeError("add_intercept() missing required argument: 'phases'")

        params = {
            "phases": phases,
            "contexts": contexts,
            "urlPatterns": url_patterns,
        }
        params = {k: v for k, v in params.items() if v is not None}
        cmd = command_builder("network.addIntercept", params)
        result = self._conn.execute(cmd)
        return result

    def continue_request(
        self,
        request: Any | None = None,
        body: Any | None = None,
        cookies: list[Any] | None = None,
        headers: list[Any] | None = None,
        method: Any | None = None,
        url: Any | None = None,
    ):
        """Execute network.continueRequest"""
        if request is None:
            raise TypeError("continue_request() missing required argument: 'request'")

        params = {
            "request": request,
            "body": body,
            "cookies": cookies,
            "headers": headers,
            "method": method,
            "url": url,
        }
        params = {k: v for k, v in params.items() if v is not None}
        cmd = command_builder("network.continueRequest", params)
        result = self._conn.execute(cmd)
        return result

    def continue_response(
        self,
        request: Any | None = None,
        cookies: list[Any] | None = None,
        credentials: Any | None = None,
        headers: list[Any] | None = None,
        reason_phrase: Any | None = None,
        status_code: Any | None = None,
    ):
        """Execute network.continueResponse"""
        if request is None:
            raise TypeError("continue_response() missing required argument: 'request'")

        params = {
            "request": request,
            "cookies": cookies,
            "credentials": credentials,
            "headers": headers,
            "reasonPhrase": reason_phrase,
            "statusCode": status_code,
        }
        params = {k: v for k, v in params.items() if v is not None}
        cmd = command_builder("network.continueResponse", params)
        result = self._conn.execute(cmd)
        return result

    def continue_with_auth(self, request: Any | None = None):
        """Execute network.continueWithAuth"""
        if request is None:
            raise TypeError("continue_with_auth() missing required argument: 'request'")

        params = {
            "request": request,
        }
        params = {k: v for k, v in params.items() if v is not None}
        cmd = command_builder("network.continueWithAuth", params)
        result = self._conn.execute(cmd)
        return result

    def disown_data(self, data_type: Any | None = None, collector: Any | None = None, request: Any | None = None):
        """Execute network.disownData"""
        if data_type is None:
            raise TypeError("disown_data() missing required argument: 'data_type'")
        if collector is None:
            raise TypeError("disown_data() missing required argument: 'collector'")
        if request is None:
            raise TypeError("disown_data() missing required argument: 'request'")

        params = {
            "dataType": data_type,
            "collector": collector,
            "request": request,
        }
        params = {k: v for k, v in params.items() if v is not None}
        cmd = command_builder("network.disownData", params)
        result = self._conn.execute(cmd)
        return result

    def fail_request(self, request: Any | None = None):
        """Execute network.failRequest"""
        if request is None:
            raise TypeError("fail_request() missing required argument: 'request'")

        params = {
            "request": request,
        }
        params = {k: v for k, v in params.items() if v is not None}
        cmd = command_builder("network.failRequest", params)
        result = self._conn.execute(cmd)
        return result

    def get_data(
        self,
        data_type: Any | None = None,
        collector: Any | None = None,
        disown: bool | None = None,
        request: Any | None = None,
    ):
        """Execute network.getData"""
        if data_type is None:
            raise TypeError("get_data() missing required argument: 'data_type'")
        if request is None:
            raise TypeError("get_data() missing required argument: 'request'")

        params = {
            "dataType": data_type,
            "collector": collector,
            "disown": disown,
            "request": request,
        }
        params = {k: v for k, v in params.items() if v is not None}
        cmd = command_builder("network.getData", params)
        result = self._conn.execute(cmd)
        return result

    def provide_response(
        self,
        request: Any | None = None,
        body: Any | None = None,
        cookies: list[Any] | None = None,
        headers: list[Any] | None = None,
        reason_phrase: Any | None = None,
        status_code: Any | None = None,
    ):
        """Execute network.provideResponse"""
        if request is None:
            raise TypeError("provide_response() missing required argument: 'request'")

        params = {
            "request": request,
            "body": body,
            "cookies": cookies,
            "headers": headers,
            "reasonPhrase": reason_phrase,
            "statusCode": status_code,
        }
        params = {k: v for k, v in params.items() if v is not None}
        cmd = command_builder("network.provideResponse", params)
        result = self._conn.execute(cmd)
        return result

    def remove_data_collector(self, collector: Any | None = None):
        """Execute network.removeDataCollector"""
        if collector is None:
            raise TypeError("remove_data_collector() missing required argument: 'collector'")

        params = {
            "collector": collector,
        }
        params = {k: v for k, v in params.items() if v is not None}
        cmd = command_builder("network.removeDataCollector", params)
        result = self._conn.execute(cmd)
        return result

    def remove_intercept(self, intercept: Any | None = None):
        """Execute network.removeIntercept"""
        if intercept is None:
            raise TypeError("remove_intercept() missing required argument: 'intercept'")

        params = {
            "intercept": intercept,
        }
        params = {k: v for k, v in params.items() if v is not None}
        cmd = command_builder("network.removeIntercept", params)
        result = self._conn.execute(cmd)
        return result

    def set_cache_behavior(self, cache_behavior: Any | None = None, contexts: list[Any] | None = None):
        """Execute network.setCacheBehavior"""
        if cache_behavior is None:
            raise TypeError("set_cache_behavior() missing required argument: 'cache_behavior'")

        params = {
            "cacheBehavior": cache_behavior,
            "contexts": contexts,
        }
        params = {k: v for k, v in params.items() if v is not None}
        cmd = command_builder("network.setCacheBehavior", params)
        result = self._conn.execute(cmd)
        return result

    def set_extra_headers(
        self,
        headers: list[Any] | None = None,
        contexts: list[Any] | None = None,
        user_contexts: list[Any] | None = None,
    ):
        """Execute network.setExtraHeaders"""
        if headers is None:
            raise TypeError("set_extra_headers() missing required argument: 'headers'")

        params = {
            "headers": headers,
            "contexts": contexts,
            "userContexts": user_contexts,
        }
        params = {k: v for k, v in params.items() if v is not None}
        cmd = command_builder("network.setExtraHeaders", params)
        result = self._conn.execute(cmd)
        return result

    def _add_intercept(self, phases=None, url_patterns=None):
        """Add a low-level network intercept.

        Args:
            phases: list of intercept phases (default: ["beforeRequestSent"])
            url_patterns: optional URL patterns to filter

        Returns:
            dict with "intercept" key containing the intercept ID
        """
        from selenium.webdriver.common.bidi.common import command_builder as _cb

        if phases is None:
            phases = ["beforeRequestSent"]
        params = {"phases": phases}
        if url_patterns:
            params["urlPatterns"] = url_patterns
        result = self._conn.execute(_cb("network.addIntercept", params))
        if result:
            intercept_id = result.get("intercept")
            if intercept_id and intercept_id not in self.intercepts:
                self.intercepts.append(intercept_id)
        return result
    def _remove_intercept(self, intercept_id):
        """Remove a low-level network intercept."""
        from selenium.webdriver.common.bidi.common import command_builder as _cb

        self._conn.execute(_cb("network.removeIntercept", {"intercept": intercept_id}))
        if intercept_id in self.intercepts:
            self.intercepts.remove(intercept_id)
    def _canonical_request_handler_event(self, event):
        """Map public request-handler aliases to supported event keys."""
        event_aliases = {
            "auth_required": "auth_required",
            "before_request": "before_request",
            "before_request_sent": "before_request",
        }
        canonical_event = event_aliases.get(event)
        if canonical_event is None:
            available_events = ", ".join(sorted(event_aliases))
            raise ValueError(
                f"Unsupported request handler event '{event}'. Available events: {available_events}"
            )
        return canonical_event
    def add_request_handler(self, event=None, callback=None, url_patterns=None):
        """Add a handler for network requests.

        Two calling styles are supported.

        High-level (recommended)::

            driver.network.add_request_handler(handler)
            driver.network.add_request_handler(["**/api/**"], handler)

        The handler receives a :class:`Request` and may observe it, mutate it
        via ``set_url``/``set_method``/``set_headers``/``set_cookies``/``set_body``,
        call ``fail()``, or call ``provide_response(...)``.  After all matching
        handlers run, Selenium reconciles the outcome (fail > provide_response >
        continue with mutations > continue) and continues the request
        automatically — observers never stall the page.  URL patterns are glob
        strings supporting ``*``, ``**`` and ``?`` (default: match everything).
        Returns a string handler ID for ``remove_request_handler(handler_id)``.

        Legacy (phase-based)::

            driver.network.add_request_handler("before_request", handler, url_patterns=[...])

        The callback must call ``request.continue_request()`` itself and
        url_patterns are wire-level UrlPattern dicts.  Returns an int callback
        ID for ``remove_request_handler(event, callback_id)``.
        """
        if callable(event) and callback is None:
            return self._request_handlers.add_handler(url_patterns, event)
        if callable(callback) and event not in LEGACY_REQUEST_HANDLER_EVENTS:
            if not isinstance(event, str) or looks_like_url_glob(event):
                return self._request_handlers.add_handler(event, callback)
        canonical_event = self._canonical_request_handler_event(event)
        phase_map = {
            "before_request": "beforeRequestSent",
            "auth_required": "authRequired",
        }
        phase = phase_map[canonical_event]
        intercept_result = self._add_intercept(phases=[phase], url_patterns=url_patterns)
        intercept_id = intercept_result.get("intercept") if intercept_result else None

        def _request_callback(params):
            raw = (
                params
                if isinstance(params, dict)
                else (params.__dict__ if hasattr(params, "__dict__") else {})
            )
            request = Request(self._conn, raw)
            callback(request)

        callback_id = self.add_event_handler(canonical_event, _request_callback)
        if intercept_id:
            self._handler_intercepts[callback_id] = intercept_id
        return callback_id
    def remove_request_handler(self, event, callback_id=None):
        """Remove a network request handler and its associated network intercept.

        Args:
            event: The handler ID string returned by the high-level
                ``add_request_handler(callback)`` form, or the event name used
                with the legacy phase-based form.
            callback_id: The int returned by the legacy form. Omit when
                removing a high-level handler by its ID.
        """
        if callback_id is None:
            self._request_handlers.remove_handler(event)
            return
        canonical_event = self._canonical_request_handler_event(event)
        self.remove_event_handler(canonical_event, callback_id)
        intercept_id = self._handler_intercepts.pop(callback_id, None)
        if intercept_id:
            self._remove_intercept(intercept_id)
    def clear_request_handlers(self):
        """Clear all request handlers and remove all tracked intercepts.

        Response handlers registered via ``add_response_handler``,
        authentication handlers registered via ``add_authentication_handler``
        and extra headers registered via ``add_extra_header`` are preserved;
        use ``clear_response_handlers`` / ``clear_authentication_handlers`` /
        ``clear_extra_headers`` to remove those.
        """
        self._request_handlers.clear()
        self.clear_event_handlers()
        # After clear() the request registry's intercept_ids() only contains
        # the extra-headers intercept, which survives like the other
        # registries' intercepts.
        preserved_intercepts = (
            self._request_handlers.intercept_ids()
            | self._response_handlers.intercept_ids()
            | self._auth_handlers.intercept_ids()
        )
        for intercept_id in list(self.intercepts):
            if intercept_id not in preserved_intercepts:
                self._remove_intercept(intercept_id)
        # clear_event_handlers dropped every subscription, including the
        # other registries'; restore them so their handlers keep working.
        self._request_handlers.resubscribe()
        self._response_handlers.resubscribe()
        self._auth_handlers.resubscribe()
    def add_response_handler(self, url_patterns=None, callback=None):
        """Add a handler for network responses.

        Usage::

            driver.network.add_response_handler(handler)
            driver.network.add_response_handler(["**/api/**"], handler)

        The handler receives a :class:`Response` at the ``responseStarted``
        phase and may observe it or mutate it via
        ``set_status``/``set_headers``/``set_cookies``/``set_body``.  After all
        matching handlers run, Selenium reconciles the outcome — a mutated body
        is delivered via ``network.provideResponse``, other mutations via
        ``network.continueResponse`` — and continues the response
        automatically, so observers never stall the page.  URL patterns are
        glob strings supporting ``*``, ``**`` and ``?`` (default: match
        everything).

        Returns:
            A string handler ID for ``remove_response_handler(handler_id)``.
        """
        if callable(url_patterns) and callback is None:
            return self._response_handlers.add_handler(None, url_patterns)
        if not callable(callback):
            raise TypeError("add_response_handler requires a callable handler")
        return self._response_handlers.add_handler(url_patterns, callback)
    def remove_response_handler(self, handler_id):
        """Remove a response handler and its intercept by handler ID.

        Args:
            handler_id: The ID returned by ``add_response_handler``.
        """
        self._response_handlers.remove_handler(handler_id)
    def clear_response_handlers(self):
        """Clear all response handlers and their intercepts."""
        self._response_handlers.clear()
    def add_authentication_handler(self, url_patterns=None, callback=None):
        """Add a handler for authentication challenges.

        Usage::

            driver.network.add_authentication_handler(handler)
            driver.network.add_authentication_handler(
                ["https://secure-api.example.com/**"], handler
            )

        The handler receives an :class:`AuthenticationRequest` at the
        ``authRequired`` phase and may respond with
        ``provide_credentials(username, password)`` or ``cancel()``.  After all
        matching handlers run, Selenium reconciles the outcome (cancel >
        provide_credentials > browser default) and continues the challenge
        automatically, so observers never stall the page.  URL patterns are
        glob strings supporting ``*``, ``**`` and ``?`` (default: match
        everything).

        Do not combine with the credentials-only ``add_auth_handler``: both
        would answer the same challenge and the second response fails.

        Returns:
            A string handler ID for ``remove_authentication_handler(handler_id)``.
        """
        if callable(url_patterns) and callback is None:
            return self._auth_handlers.add_handler(None, url_patterns)
        if not callable(callback):
            raise TypeError("add_authentication_handler requires a callable handler")
        return self._auth_handlers.add_handler(url_patterns, callback)
    def remove_authentication_handler(self, handler_id):
        """Remove an authentication handler and its intercept by handler ID.

        Args:
            handler_id: The ID returned by ``add_authentication_handler``.
        """
        self._auth_handlers.remove_handler(handler_id)
    def clear_authentication_handlers(self):
        """Clear all authentication handlers and their intercepts."""
        self._auth_handlers.clear()
    def add_extra_header(self, name, value):
        """Add a header that is merged into every subsequent request.

        Usage::

            driver.network.add_extra_header("x-test", "value")

        BiDi has no dedicated command for extra headers, so while any extra
        header is set every request is paused at the ``beforeRequestSent``
        phase and continued with the merged headers — this adds a round trip
        per request, so remove the headers when no longer needed.  Header
        names are case-insensitive; adding a header replaces any existing
        request header of the same name.

        Args:
            name: The header name.
            value: The header value.
        """
        self._request_handlers.set_extra_header(name, value)
    def remove_extra_header(self, name):
        """Stop adding an extra header to subsequent requests.

        Args:
            name: The (case-insensitive) header name passed to
                ``add_extra_header``.
        """
        self._request_handlers.remove_extra_header(name)
    def clear_extra_headers(self):
        """Stop adding all extra headers to subsequent requests."""
        self._request_handlers.clear_extra_headers()
    def add_auth_handler(self, username, password):
        """Add an auth handler that automatically provides credentials.

        For callback-based handling with URL scoping and the ability to cancel
        a challenge, prefer ``add_authentication_handler``.  Do not combine the
        two: both would answer the same challenge and the second response
        fails.

        Args:
            username: The username for basic authentication.
            password: The password for basic authentication.

        Returns:
            callback_id int for later removal via remove_auth_handler.
        """
        from selenium.webdriver.common.bidi.common import command_builder as _cb

        # Set up network intercept for authRequired phase
        intercept_result = self._add_intercept(phases=["authRequired"])
        intercept_id = intercept_result.get("intercept") if intercept_result else None

        def _auth_callback(params):
            raw = (
                params
                if isinstance(params, dict)
                else (params.__dict__ if hasattr(params, "__dict__") else {})
            )
            request_id = (
                raw.get("request", {}).get("request")
                if isinstance(raw, dict)
                else None
            )
            if request_id:
                self._conn.execute(
                    _cb(
                        "network.continueWithAuth",
                        {
                            "request": request_id,
                            "action": "provideCredentials",
                            "credentials": {
                                "type": "password",
                                "username": username,
                                "password": password,
                            },
                        },
                    )
                )

        callback_id = self.add_event_handler("auth_required", _auth_callback)
        if intercept_id:
            self._handler_intercepts[callback_id] = intercept_id
        return callback_id
    def remove_auth_handler(self, callback_id):
        """Remove an auth handler by callback ID and its associated network intercept.

        Args:
            callback_id: The handler ID returned by add_auth_handler.
        """
        self.remove_event_handler("auth_required", callback_id)
        intercept_id = self._handler_intercepts.pop(callback_id, None)
        if intercept_id:
            self._remove_intercept(intercept_id)

    def add_event_handler(self, event: str, callback: Callable, contexts: list[str] | None = None) -> int:
        """Add an event handler.

        Args:
            event: The event to subscribe to.
            callback: The callback function to execute on event.
            contexts: The context IDs to subscribe to (optional).

        Returns:
            The callback ID.
        """
        return self._event_manager.add_event_handler(event, callback, contexts)

    def remove_event_handler(self, event: str, callback_id: int) -> None:
        """Remove an event handler.

        Args:
            event: The event to unsubscribe from.
            callback_id: The callback ID.
        """
        return self._event_manager.remove_event_handler(event, callback_id)

    def clear_event_handlers(self) -> None:
        """Clear all event handlers."""
        return self._event_manager.clear_event_handlers()

# Event Info Type Aliases
# Event: network.authRequired
AuthRequired = globals().get('AuthRequiredParameters', dict)  # Fallback to dict if type not defined

# Event: network.beforeRequestSent
BeforeRequestSent = globals().get('BeforeRequestSentParameters', dict)  # Fallback to dict if type not defined

# Event: network.fetchError
FetchError = globals().get('FetchErrorParameters', dict)  # Fallback to dict if type not defined

# Event: network.responseCompleted
ResponseCompleted = globals().get('ResponseCompletedParameters', dict)  # Fallback to dict if type not defined

# Event: network.responseStarted
ResponseStarted = globals().get('ResponseStartedParameters', dict)  # Fallback to dict if type not defined


# Populate EVENT_CONFIGS with event configuration mappings
_globals = globals()
Network.EVENT_CONFIGS = {
    "auth_required": EventConfig(
        "auth_required",
        "network.authRequired",
        _globals.get("AuthRequired", dict) if _globals.get("AuthRequired") else dict,
    ),
    "before_request_sent": EventConfig(
        "before_request_sent",
        "network.beforeRequestSent",
        _globals.get("BeforeRequestSent", dict) if _globals.get("BeforeRequestSent") else dict,
    ),
    "fetch_error": EventConfig(
        "fetch_error",
        "network.fetchError",
        _globals.get("FetchError", dict) if _globals.get("FetchError") else dict,
    ),
    "response_completed": EventConfig(
        "response_completed",
        "network.responseCompleted",
        _globals.get("ResponseCompleted", dict) if _globals.get("ResponseCompleted") else dict,
    ),
    "response_started": EventConfig(
        "response_started",
        "network.responseStarted",
        _globals.get("ResponseStarted", dict) if _globals.get("ResponseStarted") else dict,
    ),
    "auth_required": EventConfig("auth_required", "network.authRequired", _globals.get("dict", dict)),
    "before_request": EventConfig("before_request", "network.beforeRequestSent", _globals.get("dict", dict)),
    "response_started": EventConfig("response_started", "network.responseStarted", _globals.get("dict", dict)),
}
