sessionkit
Владение сессией аккаунта: дверь, адрес, порт хранилища, окно записи, четыре раскладки как слои, порт селектора. Один дом вместо четырёх — где сессия лежит, решает кит, а не потребитель.
Зачем
«Сессия аккаунта» физически живёт сразу в нескольких местах: файловым деревом
(s-authkit-client, envelope KEK/DEK), строкой в общей базе
(s-accountpoolkit, документ хранится запечатанным целиком) и профилем
браузера как кэшем узнавания устройства. Какое из них главное, до сих пор
решала переменная окружения, прочитанная посторонним китом.
У этого две цены. Первая: одна команда пишет туда, где другая ничего не находит. Вторая, дороже: у сессии нет владельца — спросить «где она на самом деле» не у кого, и спор «почему навык не видит вход» решается догадками.
Этот кит — владелец. Носители объявляют себя ему сами (entry-points), он
находит общую базу сам, выбирает носитель и говорит, кого выбрал и почему.
Здоровье аккаунта пишется одним словом (authkit_contracts.status.Status) и
только под окном записи.
Как спрашивают
import sessionkit
address = sessionkit.SessionAddress(service="gemini", account="me@example.com")
try:
state = sessionkit.load_state(address) # None — входа ещё не было
sessionkit.save_state(address, state or {"cookies": []})
with sessionkit.write_window(address) as window: # здоровье — только под окном
sessionkit.mark(address, status=sessionkit.Status.LIVE, window=window)
choice = sessionkit.where() # КТО ответил и ПОЧЕМУ
print(choice.name, choice.reason)
for verdict in choice.verdicts:
print(" ", verdict) # включая тех, кто отказался
except sessionkit.StoreUnavailable as refusal:
print(refusal) # носителей в установке нет — отказ называет, какой пакет ставить
mark без окна — WriteWindowRequired, а не молчаливая запись: статус в
индексе расходился с телом сессии ровно потому, что его писали полтора десятка
мест мимо единой отметки.
Разбор полётов «почему выбрали не то» — sessionkit.explain(): опрашивает всех
кандидатов, а не останавливается на первом согласившемся.
Что умеет выбранное хранилище сверх обязательного минимума (аренда на минт,
набор аккаунтов, запись без слияния) — sessionkit.capabilities(). Способность
спрашивают, а не предполагают: предположение оборачивается тишиной на месте
защиты.
Адрес
Шесть координат, ровно те же, которыми адресует хранилище
(corekit.dto.SessionRef):
| координата | вопрос | умолчание |
|---|---|---|
tenant |
чья сессия в общем хосте | local |
profile |
чей это набор входов (рабочий, личный) | default |
service |
к какому сервису | обязательна |
instance |
какой ИМЕННО вход сервиса (портал, национальный домен) | пусто |
account |
под каким аккаунтом | default |
stage |
боевая сессия или черновик записи трафика | live |
instance — не украшение: без него два разных портала Битрикса одного аккаунта
получают одно имя, а хранилище считает уникальность по шести координатам — и
запись уходит не туда, откуда читали.
Где что лежит
sessionkit.locate отвечает на вопрос «где» один раз на всех:
- корень сессий —
SESSIONS_HOME, иначе~/.sessions; - общая база находится сама в
<корень>/sessions.db;SESSIONS_DB_URL— переопределение (другой сервер, другой тенант), а не условие работы; - ключ шифрования имеет три состояния: файл (
SESSIONS_DB_KEY_FILEили<корень>/.session-db.key), явное «хранить открыто» (SESSIONS_DB_PLAINTEXT=1) и «не задан» — последнее НЕ равно «открыто».
Порядок опроса: сначала база, потом дерево. Если общая база заведена, то она и есть сессия; читать в этот момент дерево значит завести второй носитель — обе копии выглядят рабочими, а ротацию получает только та, через которую сходили.
Носители: объявляются сами
Кит не называет ни одной реализации по имени — это держит .importlinter.
Пакет, умеющий хранить сессии, записывается в группу entry-points
sessionkit.stores:
[project.entry-points."sessionkit.stores"]
file = "authkit_client.sessions:store_provider" # s-authkit-client
db = "accountpoolkit.session_db:store_provider" # s-accountpoolkit
Провайдер — функция dsn -> хранилище | StoreOffer | None. Носителя нет —
StoreProviderMissing с рецептом установки (pip install s-authkit-client /
s-accountpoolkit) и перечнем объявленных. Явная register_provider под тем же
именем сильнее объявленной пакетом: подмена в тесте остаётся подменой.
Окно записи
sessionkit.write_window(address) — окно записи на два слоя (лок внутри
процесса + файл между процессами) со сроком и держателем; ждёт не дольше 5 с.
Всё, что меняет тело или здоровье сессии, идёт внутри. Нужно там, где вход
ВЫПУСКАЮТ: у сервисов вида Google одна сессия на аккаунт, и второй
одновременный вход инвалидирует первый. Слово «аренда» (lease) отсюда ушло —
в портфеле оно означало ещё аренду на минт в базе и JWS-пропуск leasekit;
sessionkit.lease живёт один релиз как алиас с DeprecationWarning.
Четыре раскладки — слои одной двери
sessionkit.layouts (переезд librarykit.session_layers): общая база,
шифрованное дерево, снимок рядом с профилем движка, файл в папке навыка —
опрашиваются по старшинству. read() возвращает тело вместе с уликой, кто
ответил; write() пишет в канон, а без канона — обратно в тот же слой (нового
носителя не заводит); migration_plan()/migrate(confirm=True) — перенос
только с показанной дельтой. python -m sessionkit.layouts [--plan] — всё
одним перечнем.
Селектор — порт
sessionkit.select: Candidate, Policy, Choice, протокол Selector
(pick/candidates/report/release) и чистая choose(candidates, policy, cursor=, rng=) — фильтр → каскад приоритета → Power-of-Two-Choices. Ядро
(priority_key, power_of_two_choices, health_from, ratio, reset_epoch,
is_dead_health) переехало из accountpoolkit.selection_core с теми же
сигнатурами; пулы librarykit/accountpoolkit становятся адаптерами.
Что живёт МИМО двери
Честный список (подробности — в CHANGELOG.md): отпечаток выхода
egress_fingerprint.json, персона устройства (corekit.persona), секреты,
профиль браузера, а также координаты instance/stage, которые файловое дерево
пока игнорирует. Дверь отдаёт тело сессии; всё перечисленное адресуется своими
способами и ждёт своей очереди.
Разработка
uv sync --extra dev --extra live
uv run --extra dev --extra live pytest -q
uv run --extra dev ruff check sessionkit tests
Набор live ставит НАСТОЯЩИЕ хранилища: утверждение «обе реализации доступны
через дверь» подделкой не доказывается — она подтверждает лишь то, что мы её так
и написали. Без набора живые тесты пропускаются с внятной причиной.
Статус
- Type:
kit - Status:
active - Priority: P0
- Slug:
sessionkit· Prefix:ses
atlas project get sessionkit
Физический layout:
- Storage:
_storage/sessionkit/ - Junction:
Products\sessionkit→_storage/sessionkit
Metadata
Release files for s-sessionkit 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| s_sessionkit-0.1.1.tar.gz | 85.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| s_sessionkit-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 142.9 kB
Release files / s_sessionkit-0.1.1.tar.gz
| Download URL | s_sessionkit-0.1.1.tar.gz |
|---|---|
| Size | 85.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cc830a13388eb578cac75a0d946f418b96d99fa04f2d02fe72c7df696928b250
|
|
BLAKE2b-256 checksum How to use checksums |
85aabeb703639b9cfcc723f35d5406fe317778708516e21208fdd5cc47dea002
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / s_sessionkit-0.1.1-py3-none-any.whl
| Download URL | s_sessionkit-0.1.1-py3-none-any.whl |
|---|---|
| Size | 57.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
99b3c1299291bfbfb115f573af5ae942d32e27b7a90deec23557a3f21fce09f5
|
|
BLAKE2b-256 checksum How to use checksums |
2862684030e0ac720db53fcfb927ea9c9c4268b8536336a1ada3d2c2e659b352
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|