Metadata-Version: 2.4
Name: s-librarykit
Version: 0.7.21
Summary: Жирный КОРЕНЬ китов: единая error-иерархия, config/retry/paths-утили, checkpoint/resume, транспорт/auth/sessions — общий код для clikit, adapterkit и доменных пакетов.
Author: Dmitry
License: MIT
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: cryptography>=43
Requires-Dist: httpx>=0.27
Requires-Dist: keyring>=25.0
Requires-Dist: oschmod>=0.3
Requires-Dist: platformdirs>=4.0
Requires-Dist: s-authkit-client>=0.0.4
Requires-Dist: s-corekit>=0.0.4
Requires-Dist: s-netkit>=0.0.5
Requires-Dist: tomli-w>=1.0
Provides-Extra: antibot
Requires-Dist: s-browserkit[antibot]>=0.0.5; extra == 'antibot'
Provides-Extra: browser
Requires-Dist: s-browserkit[browser]>=0.0.5; extra == 'browser'
Provides-Extra: camoufox
Requires-Dist: s-browserkit[camoufox]>=0.0.5; extra == 'camoufox'
Provides-Extra: dev
Requires-Dist: httpx[socks]>=0.28; extra == 'dev'
Requires-Dist: hypothesis>=6; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Provides-Extra: nodriver
Requires-Dist: s-browserkit[nodriver]>=0.0.5; extra == 'nodriver'
Provides-Extra: oauth
Requires-Dist: authlib>=1.3; extra == 'oauth'
Provides-Extra: ws
Requires-Dist: websockets>=12.0; extra == 'ws'
Description-Content-Type: text/markdown

# librarykit

**Жирное ядро экосистемы китов** — переиспользуемый фундамент, на котором строятся
тонкие надстройки (`adapterkit`, `clikit`) и любые доменные пакеты. Вся общая логика
живёт здесь один раз, вместо копипасты по проектам: единая иерархия ошибок,
config/paths-утили, политики повторов, HTTP-транспорт, авторизация, шифрованное
хранилище сессий, antibot/браузер, пагинация, RPC/stream и оркестраторы
онбординга/health.

```
librarykit   ← КОРЕНЬ: errors · config · retry · transport · auth · sessions ·
                        errmap · pagination · antibot · browser · rpc · stream ·
                        orchestration.  Зависит НИ ОТ ЧЕГО из китов.
   ▲
clikit       ← CLI-обёртка (поверх librarykit)
   ▲
adapterkit   ← SDK сетевых адаптеров (поверх librarykit + clikit)
   ▲
домен        ← конкретный продукт (поверх всех трёх)
```

Зависимости направлены **только внутрь, к корню**. librarykit не импортирует ни
один другой кит и ничего не знает о потребителях.

## Установка

```bash
uv add s-librarykit
```

Имя дистрибутива — `s-librarykit`, имя для импорта — `librarykit`.

Опциональные extra (тяжёлые зависимости ставятся по требованию):

```bash
uv add "s-librarykit[browser]"   # Playwright — warm/cold-login, snapshot сессий
uv add "s-librarykit[antibot]"   # curl-cffi — JA3-impersonate транспорт
uv add "s-librarykit[ws]"        # websockets — persistent stream-транспорт
```

Ядро (`errors`/`config_util`/`retry`/`checkpoint`/`contract`) почти-stdlib —
единственная не-stdlib зависимость ядра `platformdirs` (нативные пути ОС для
`AppPaths`). Сетевые модули тянут `httpx`/`stamina`, шифрование сессий —
`cryptography`/`keyring`.

## Состав

| Слой | Модуль | Что даёт |
|------|--------|----------|
| Ошибки | `librarykit.errors` | единая иерархия `CliError`/`ApiError` + сетевые подклассы (`AuthRequired`/`RateLimited`/`NotFound`/`ServerError`/`TransportError`/`Blocked`) + множество `RETRYABLE` |
| Конфиг/пути | `librarykit.config_util` | `deep_merge`, `interpolate_env`, `load_dotenv`, `slugify`, `normalize_account_id`, `atomic_write_text`, `chmod_600`, `AppPaths` |
| Контракт | `librarykit.contract` | граничные `Protocol` (`Transport`/`Auth`/`Refreshable`/`ErrorMapper`/`Paginator`/`SessionStoreProtocol`/`StreamTransport`/`Codec`) + DTO/enum (`SessionRef`/`Creds`/`PaginationMode`/`AuthMode`/`TransportKind`) |
| Протоколы | `librarykit.protocols` | опциональные онбординг/health-контракты (`LoginMode`/`OnboardingProtocol`/`HealthProtocol`/`HealthState`/`InteractiveFlow`) |
| Повторы | `librarykit.retry` | `RetryPolicy` (header-driven: `Retry-After`/rate-limit) поверх `stamina` + `SimpleRetryPolicy` |
| Транспорт | `librarykit.transport` | `HttpxTransport` + `HttpClient` — единый choke-point HTTP-вызовов |
| Ошибки→исключения | `librarykit.errmap` | декларативная карта `{status\|code\|body-predicate → ErrorSubclass}` (`build_error_map`) |
| Пагинация | `librarykit.pagination` | `CursorPaginator` (offset/cursor/page) + tweepy-стиль обёртки |
| Авторизация | `librarykit.auth` | `TokenAuth`/`CookieSessionAuth`/`OAuth2Auth`/`BrowserLoginAuth` + dump/load/encrypt настроек |
| Сессии | `librarykit.sessions` | `SessionStore` — envelope-шифрованное файловое хранилище сессий (DEK под KEK), `resolve_kek` |
| Секреты | `librarykit.secret_store` | `SecretStore` — keyring + file-fallback |
| Antibot | `librarykit.antibot` | выбор транспорта Tier 0-4 (curl-cffi JA3 / реальный браузер по CDP) |
| Браузер | `librarykit.browser` | warm/cold-login, snapshot/restore storage-state |
| RPC | `librarykit.rpc` | `RpcClient` + codec-слой (`JsonCodec`/`PrefixedJsonCodec`) поверх `HttpClient` |
| Stream | `librarykit.stream` | persistent-транспорты (`StubStreamTransport` + `WebSocketsStreamTransport`) |
| Checkpoint | `librarykit.checkpoint` | `Checkpoint` (атомарный JSON-state), `JsonlSink` (forensic-лог), `RunMetrics` |
| Веер задач | `librarykit.fanout` | `fan_out` — N параллельных задач на `asyncio.TaskGroup`: результаты И ошибки, привязанные к ключам (падение одной ветки не рвёт остальные); `fan_out_all` — «нужны все» |
| Кеш диалогов | `librarykit.dialog_cache` | `DialogCache` — активные диалоги + маркер «где остановились» (SQLite/WAL, мультитенантно), `pull_new` — «дай мне только новое» ([docs/DIALOG_CACHE.md](docs/DIALOG_CACHE.md)) |
| Проба доступа | `librarykit.access_probe` | `probe_access(service, ctx)` — ЖИВОЙ вердикт по ответу сервера вместо «есть файл с куками = залогинен»; плагин объявляет заход (`probe_for`/`AccessProbe`), ядро исполняет и кэширует на короткий TTL (ключ включает egress) |
| Отпечаток сессии | `librarykit.session_fingerprint` | инвариант «один egress + один профиль»: `capture_fingerprint`/`save_fingerprint` при логине, `guard_session_fingerprint` ДО сетевого вызова → `SessionEgressMismatch` («при логине было X, сейчас Y») |
| Здоровье профиля | `librarykit.profile_health` | `check_profile` ДО спавна браузера (размер, битые ключевые JSON, зависший `SingletonLock`) → `INFRA_DOWN`, а не «login expired»; `quarantine_profile`/`ensure_healthy_profile` |
| Эфемерный минт | `librarykit.ephemeral` | `mint_ephemeral` — минт с инъекцией кук из хранилища и извлечением обратно БЕЗ дискового профиля (каталог профилей не растёт); `ephemeral_context` — сам примитив контекста |
| OAuth и TTL | `librarykit.oauth` | `OAuthTokens`/`OAuthSession`/`exchange_code` — пара токенов со СРОКОМ рядом и ПРОАКТИВНЫМ обновлением: живой токен = ноль запросов, истекающий = один refresh ДО вызова, отозванный = `OAuthRevoked` вместо бесконечного ретрая |
| Поверхность API | `librarykit.ladder.capabilities` | `ApiSurface` (white/hidden) + `AccessCapability` (прямой запрос / обход отпечатка / браузерный минт / продвинутый стелс): навык объявляет НУЖДУ, движок выбирает кит (`ENGINE_BINDING`/`bind_capability`). У белого API минта и антибота нет вовсе |
| Порты хранилищ | `librarykit.repositories` | сессии/лимиты/идемпотентность через `Protocol`-порты; реализации память / SQLite / форма Redis / форма asyncpg выбираются в composition root (`RepositorySet`, `memory_repositories`, `local_repositories`) |
| Сущности | `librarykit.entities` | нейтральные data-классы (`Session`/`SessionContext`/`HealthReport`) |
| Оркестрация | `librarykit.orchestration` | `OnboardingService`, `HealthMonitor`, `SessionLoader` — переиспользуемые сценарии онбординга/health |
| Якоря разметки | `librarykit.anchors` | привязка к фронту как ПРАВИЛО ПОИСКА, а не строка-константа: `Anchor` (сигнатуры по убыванию устойчивости + валидатор ФОРМЫ), `AnchorCache` (сработавшая сигнатура закрепляется и пробуется первой), самолечение со сменой якоря вместо молчаливой пустоты и три разных диагноза (`AnchorLost` / `AnchorPageMismatch`) ([docs/ANCHORS.md](docs/ANCHORS.md)) |
| Диагностика доступа | `librarykit.diagnosis` | ПОЧЕМУ не работает: `Reason`/`Verdict` + порядок разбора (`REASON_ORDER`), гео-блок сервиса (`classify_geo`), «лёг выход» vs авторизация (`classify_failure`), passive-разлогин по цепочке (`classify_landing_chain`), сведение улик (`diagnose`), ЧТО именно мертво — сессия / эндпоинт / инфраструктура (`AccessState`/`classify_access`) |

Топ-уровневый `import librarykit` ре-экспортирует публичный API (см. `librarykit.__all__`).

## Быстрый старт

```python
import librarykit as lk

# единая иерархия ошибок
try:
    ...
except lk.RateLimited as e:
    ...

# header-driven повторы + choke-point HTTP-клиент
client = lk.HttpClient(base_url="https://api.example.com", retry=lk.DEFAULT_RETRY)

# декларативная карта ответ → доменная ошибка
err_map = lk.build_error_map()

# envelope-шифрованное хранилище сессий
store = lk.SessionStore(root=..., kek=lk.resolve_kek())
```

## Разработка

```bash
uv sync --extra dev
uv run --extra dev pytest -q
uv run --extra dev ruff check librarykit
```

## Лицензия

MIT © 2026 Dmitry.
