Metadata-Version: 2.4
Name: s-accountpoolkit
Version: 0.0.3
Summary: Зрелый пул аккаунтов/сессий поверх librarykit: статус-машина аккаунта, quota/подписки, rate-limit + circuit-breaker, OAuth-ротация (single-flight DCL-lock), egress-пул с quarantine, import/export, headless-фасад. Обобщение gemini-balancer в переиспользуемый доменный слой.
Author: Dmitry
License: MIT
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: pydantic>=2.6
Requires-Dist: s-librarykit>=0.1.17
Provides-Extra: cli
Requires-Dist: s-clikit>=0.1; extra == 'cli'
Provides-Extra: egress
Requires-Dist: s-librarykit[antibot]>=0.1.17; extra == 'egress'
Provides-Extra: rest
Requires-Dist: starlette>=0.37; extra == 'rest'
Requires-Dist: uvicorn>=0.30; extra == 'rest'
Description-Content-Type: text/markdown

# s-accountpoolkit

Зрелый **пул аккаунтов/сессий** поверх [`s-librarykit`](https://gitlab.com/S-kits/librarykit) — доменный слой над `SessionStore`/`SessionPool`/`RateLimiter`/`RotatingAuth`/antibot-транспортами. Обобщение gemini-balancer в переиспользуемый кит.

**import-имя** `accountpoolkit` · **dist-имя** `s-accountpoolkit` (как s-librarykit → librarykit).

## Что даёт (сверх librarykit)

- **Account со статус-машиной** — `available / cooldown / quota_exhausted / disabled / blocked` с причинами и таймстемпами (не строка+`is_active`).
- **Quota / подписки** — `QuotaData` union (dual-window weekly+5h / header-based / JWT-claims), приоритет `ULTRA > PRO > FREE`, model-level изоляция.
- **Rate-limit + circuit-breaker** — разбор 429/403/5xx/Retry-After, exp-backoff по причинам, cooldown отдельно от CB-open, авто-recovery.
- **Selector** — двухслойный (жёсткий eligibility-фильтр → Power-of-Two-Choices), приоритет-каскад подписка→квота→health→reset, sticky-сессии, slow-start.
- **OAuth-ротация** — single-flight (double-checked-locking) на аккаунт, атомарный rolling-refresh, fallback-цепочка OAuth-клиентов, `invalid_grant` → карантин, проактивный фоновый рефреш, keyring-экспорт токена.
- **Egress-пул** — привязка аккаунт↔прокси (sticky IP) vs глобальный пул, стратегии (RR/Weighted/LeastConn/Priority/P2C), health-check, **настоящий per-proxy circuit-breaker/quarantine**.
- **Import/export** — версионированный конверт, идемпотентный upsert, чтение чужих сторов.
- **Headless `AccountService`-фасад** + `clikit` CLI (json-by-default); опц. REST admin (`[rest]`, `accountpoolkit.rest.create_admin_app`) + cloudflared quick-tunnel (`accountpoolkit.tunnel`, нужен бинарь `cloudflared` на PATH — не pip-пакет).

Секреты — только через librarykit `SessionStore` (envelope KEK/DEK) / `SecretStore` (keyring+fallback). Никакого plaintext.

Провайдер-специфика (gemini / codex / …) — через `AccountProvider` Protocol-плагины; ядро её не знает.

## Установка

```bash
uv add s-accountpoolkit          # ядро
uv add "s-accountpoolkit[egress]"  # + antibot health-транспорт для egress-пула
uv add "s-accountpoolkit[cli]"     # + CLI `accountpool` (json-by-default)
```

import-имя — `accountpoolkit`. `AccountService` — headless-фасад над всеми слоями:

```python
import accountpoolkit as apk
from librarykit.sessions import SessionStore

store = apk.AccountStore(SessionStore(root=None, encrypt=True), social="myservice")
pool = apk.AccountPool(store, tracker=apk.RateLimitTracker())
svc = apk.AccountService(store=store, pool=pool)

choice = await svc.acquire(require_tier=apk.SubscriptionTier.PRO)
if choice:
    ...  # запрос через choice.proxy (egress) + choice.account (device);
    # секреты хранятся отдельно (envelope): await store.load_creds(choice.ref)
    await svc.report(choice.ref, response=resp)  # 429/5xx → cooldown/circuit-breaker
```

## Статус

Ядро стабильно: статус-машина аккаунта, quota/подписки, rate-limit + circuit-breaker,
OAuth-ротация (single-flight), egress-пул, import/export, `AccountService`-фасад + CLI.
Провайдер-плагины подключаются через entry-points `accountpoolkit.providers`.
