# Microsoft Edge в DuckoNet

Edge выбирается параметром `browser="edge"` у `HttpClient`/`AsyncHttpClient`. Библиотека использует подписанный профиль; браузер на компьютере запускать не требуется. Этот набор предназначен для CPython3.12 x64 на Windows и Ubuntu24.04.

Для запроса достаточно API-ключа и выбора браузера. Профили загружаются автоматически; права определяют доступные версии.

## Явная версия

В опубликованном каталоге Free использует Edge151.0.4129.107, Pro — Edge156.0.4314.42. Доступ определяют права API-ключа и подписанный каталог. Явная Pro-версия не предоставляет права Free-ключу. Промежуточные версии не обещаются. При появлении новых профилей каталог обновляется.

```python
from duckonet import HttpClient

def fetch_edge(api_key, state_dir, url):
    with HttpClient(api_key=api_key, state_dir=state_dir,
                    browser="edge", version="151.0.4129.107",
                    protocol="h2") as client:
        response = client.get(url)
        response.raise_for_status()
        return response.text
```

Для Pro используйте `version="156.0.4314.42"` с подходящим ключом. `browser_profile` показывает фактически выбранные browser,version,profile_id,generation. Выбор Edge не переходит на Chrome при отсутствии доступного Edge. Ручной User-Agent не заменяет профиль. Контекст браузера выбирается автоматически. Явно заданный контекст другого браузера вызовет ошибку.

## Последняя доступная версия и полный прогон

`version="last"` следит за последним совместимым разрешённым Edge. Оберните логически связанный сценарий в `run()`: он закрепляет поколение до выхода. Загрузка обновлений может происходить в фоне; новый прогон выбирает доступное подготовленное поколение. Если обновления нет, остаётся текущее допустимое. Параметр `check_interval` задаёт интервал проверок, а не гарантированное время появления новой версии.

```python
from duckonet import HttpClient

def run_edge(api_key, state_dir, first_url, second_url):
    with HttpClient(api_key=api_key, state_dir=state_dir,
                    browser="edge", version="last", protocol="auto") as client:
        with client.run():
            selected = client.browser_profile
            first = client.get(first_url)
            second = client.get(second_url)
        return selected, first, second
```

Параметр `protocol` принимает `"h1"`, `"h2"`, `"h3"` и `"auto"`. В автоматическом режиме используется предусмотренный профилем выбор HTTP/2 или HTTP/3. HTTP/3 требует доступного QUIC; для HTTP/3 через прокси нужен MASQUE. Открытые WebSocket/streams и незавершённые операции держат своё поколение до корректного закрытия.

```python
from duckonet import AsyncHttpClient

async def async_edge(api_key, state_dir, url):
    async with AsyncHttpClient(api_key=api_key, state_dir=state_dir,
                               browser="edge", version="last",
                               protocol="h2") as client:
        async with client.run():
            response = await client.get(url)
            return response.status_code, response.text
```

## Cookies

`client.cookies` — общий jar клиента. Можно добавить cookie и отдельное дополнение к запросу:

```python
def with_cookie(client, url):
    client.cookies.set("locale", "ru", url=url, path="/", secure=True)
    return client.get(url, cookies={"visit": "example"})
```

Jar учитывает domain/path/Secure/SameSite и контекст. Cookies сохраняются при переключении поколений между прогонами. `persist_cookies` управляет применением cookie-изменений запроса к jar; он не является автоматическим экспортом jar в файл. Для явного переноса между процессами есть `export_data()`/`import_data(data)`; экспорт содержит секреты и требует защищённого хранения. `state_dir` хранит состояние установки и защиты от отката, его не следует удалять для восстановления cookies или обновлений.

## Proxy и WebSocket

Обычные HTTP/HTTPS CONNECT и SOCKS задаются `ProxyRoute`. Учётные данные передаются отдельно от endpoint:

```python
from duckonet import ProxyRoute

def through_proxy(client, url, endpoint, username, password):
    route = ProxyRoute(endpoint, username=username, password=password)
    return client.get(url, protocol="h2", proxy=route)
```

Endpoint имеет вид `https://proxy.example:443` или `socks5h://proxy.example:1080`; адреса здесь — примеры. Для H3 через прокси нужен `MasqueProxy` с HTTPS/H2 CONNECT-UDP, canonical URI template и `protocol="h3"`. Обычный CONNECT/SOCKS не превращается в H3 carrier. Ошибка proxy не должна незаметно переводить запрос напрямую. Профиль браузера применяется к соединению с сайтом; соединение с самим прокси настраивается отдельно.

```python
from duckonet import MasqueProxy

def through_masque(client, url, endpoint):
    return client.get(url, protocol="h3", proxy=MasqueProxy(endpoint))

def echo_ws(client, websocket_url):
    with client.websocket(websocket_url) as ws:
        ws.send("hello")
        return ws.recv()
```

Для `AsyncHttpClient` используйте `async with client.websocket(...)`, `await ws.send(...)` и `await ws.recv()`. Поддерживаются WS/WSS; WebSocket поверх H2/H3 в этот контур не входит. Закрывайте контекст, чтобы освободить соединение и поколение.

## Состояние клиента и ошибки

При повторном запуске используйте прежний `state_dir`: библиотека сохраняет там данные установки и обновлений. Не удаляйте его после временной сетевой ошибки. Для необходимого обновления потребуется доступ к серверу DuckoLab; режим работы без сети не заменяет такое обновление.

Не повторяйте изменяющие данные запросы автоматически после тайм-аута: сервер мог уже выполнить действие. Правила повторения зависят от вашего приложения.

DuckoNet выполняет сетевые запросы и не исполняет JavaScript страницы. Параметры заголовков и низкоуровневые настройки позволяют изменить поведение запроса; используйте их, когда это требуется вашим сценарием.

## Контекст в расширенном API

У `HttpClient` и `AsyncHttpClient` контекст выбранного браузера создаётся автоматически. При прямой работе с `Distribution` метод `navigation_context(url, selection=...)` принимает `ProfileSelection`: его можно получить из `profile.catalog_selection_receipt` после выбора профиля Edge. Без `selection` этот метод сохраняет контекст Chrome.
