Metadata-Version: 2.5
Name: s-clientkit
Version: 0.0.1
Summary: КИТ-СБОРЩИК: по ДЕКЛАРАЦИИ сервиса (TOML/dataclass) собирает готовый клиент из слоёв — белый API прямыми запросами, скрытый с удержанием доступа. Потребитель зовёт одинаково.
Author: Dmitry
License: MIT
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: s-corekit>=0.0.2
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Provides-Extra: endpoints
Requires-Dist: s-adapterkit>=0.1.8; extra == 'endpoints'
Provides-Extra: hidden
Requires-Dist: s-authkit-client>=0.0.2; extra == 'hidden'
Provides-Extra: http
Requires-Dist: httpx>=0.27; extra == 'http'
Provides-Extra: net
Requires-Dist: s-netkit>=0.0.2; extra == 'net'
Description-Content-Type: text/markdown

# s-clientkit — кит-сборщик клиентов

Готовый клиент сервиса **собирается по декларации**, а не пишется заново.

```
    clientkit                     <- СБОРЩИК (этот кит)
    /        \
authkit-client  browserkit        <- доступ (кто ты) / чеканка (как войти)
    \        /
      netkit                      <- сеть (чем ходить)
         |
      corekit                     <- основание
```

## Один вызов на оба мира

```python
from clientkit import build_from_toml

white  = build_from_toml("examples/white_service.toml",  secrets=os.environ.get)
hidden = build_from_toml("examples/hidden_service.toml", session_store=store)

await white.call("me")      # белый REST с api-ключом
await hidden.call("me")     # скрытый API с сессией и лестницей деградации
```

Потребитель зовёт **одинаково** и по поверхности клиента не может отличить один
от другого. Разница — в цене:

| | белый | скрытый |
| --- | --- | --- |
| поднимает сессии/чеканку/антибот | **нет** | да |
| запросов на `call("me")` | **ровно 1** | 1 (+чеканка, если доступа нет) |
| авторизация | заголовок (`api_key` / `bearer` / `oauth` с проактивным TTL) | cookies живой сессии |
| смерть адреса | ошибка сервиса | следующий кандидат, без релиза |

Обе половины проверяются тестом `tests/test_same_call_both_kinds.py` — по
`sys.modules` свежего интерпретатора и по счётчику запросов, а не декларацией.

## Декларация — данные

`ServiceDecl` (frozen dataclass) читается из TOML и валидируется при загрузке:
белый сервис с рецептом доступа или скрытый без чеканщика — опечатка, о которой
надо узнать при сборке, а не ночью в бою. Round-trip
`decl_to_data ∘ decl_from_data` проверяется тестом.

Смотри `examples/white_service.toml` и `examples/hidden_service.toml`.

## Чего в ките нет

* **своего HTTP** — «чем ходить» приходит аргументом (`RequestPort`), умолчание
  (netkit → httpx) резолвится лениво;
* **своего браузера** — чеканка приходит через порт слоя доступа;
* **своей таксономии отказов** — диагноз ставит `corekit.diagnosis.access`, та же
  функция, что у живой пробы и у реестра эндпоинтов.
