s-librarykit 0.3.0__tar.gz → 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/PKG-INFO +1 -1
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/__init__.py +127 -148
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/antibot/__init__.py +2 -1
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/antibot/cdp.py +25 -3
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/entities.py +27 -2
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/orchestration/__init__.py +1 -1
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/orchestration/health.py +8 -8
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/pyproject.toml +1 -1
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_orchestration.py +21 -4
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/.gitignore +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/.gitlab-ci.yml +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/AGENTS.md +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/CHANGELOG.md +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/LICENSE +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/README.md +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/docs/superpowers/specs/2026-06-24-unified-sessions-design.md +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/antibot/_helpers.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/antibot/curl_cffi.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/antibot/page_evaluate.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/antibot/warmup_minter.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/auth.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/blocks.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/browser/__init__.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/browser/_engine.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/browser/camoufox.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/browser/geometry.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/browser/launchers.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/browser/state.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/bulk.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/checkpoint.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/config_util.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/contract.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/enums.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/errmap.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/errors.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/factory.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/forms.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/graphql.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/limit.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/orchestration/onboarding.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/orchestration/session_loader.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/pagination.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/pool.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/ports.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/protocols.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/redaction.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/refresh.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/retry.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/rpc.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/secret_store.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/session_bridge.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/session_paths.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/sessions/__init__.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/sessions/_const.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/sessions/_fsutil.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/stream.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/transport/__init__.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/transport/_helpers.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/transport/http_client.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/transport/permissive.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/transport/rest_client.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/transport/transport_http.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/upload.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/windows.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/conftest.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_antibot.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_auth.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_blocks.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_browser.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_bulk.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_checkpoint.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_config_util.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_errmap.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_errors.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_factory.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_forms.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_graphql.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_limit.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_limit_contract.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_pagination.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_permissive_http.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_pool.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_redaction.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_refresh.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_retry.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_rpc.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_session_bridge.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_session_paths.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_sessions.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_stream.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_transport_client.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_transport_rest.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_transport_sync.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_upload.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_warmup_minter.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_windows.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.3.1}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: s-librarykit
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Жирный КОРЕНЬ китов: единая error-иерархия, config/retry/paths-утили, checkpoint/resume, транспорт/auth/sessions — общий код для clikit, adapterkit и доменных пакетов.
|
|
5
5
|
Author: Dmitry
|
|
6
6
|
License: MIT
|
|
@@ -249,161 +249,100 @@ from librarykit.windows import (
|
|
|
249
249
|
parse_window,
|
|
250
250
|
)
|
|
251
251
|
|
|
252
|
-
__version__ = "0.3.
|
|
252
|
+
__version__ = "0.3.1"
|
|
253
253
|
|
|
254
254
|
__all__ = [
|
|
255
255
|
"__version__",
|
|
256
|
-
#
|
|
257
|
-
"Checkpoint",
|
|
258
|
-
"JsonlSink",
|
|
259
|
-
"RunMetrics",
|
|
260
|
-
# errors (единая иерархия ERROR-HUB)
|
|
261
|
-
"CliError",
|
|
262
|
-
"ApiError",
|
|
263
|
-
"AuthRequired",
|
|
264
|
-
"SessionExpired",
|
|
265
|
-
"RateLimited",
|
|
266
|
-
"ValidationError",
|
|
267
|
-
"NotImplementedYet",
|
|
268
|
-
"NotFoundError",
|
|
269
|
-
"ServerError",
|
|
270
|
-
"TransportError",
|
|
271
|
-
"Blocked",
|
|
272
|
-
"RETRYABLE",
|
|
273
|
-
"AdapterError",
|
|
274
|
-
"NotFound",
|
|
275
|
-
"GraphQLError",
|
|
276
|
-
# config_util / paths
|
|
277
|
-
"deep_merge",
|
|
278
|
-
"interpolate_env",
|
|
279
|
-
"load_dotenv",
|
|
280
|
-
"slugify",
|
|
281
|
-
"normalize_account_id",
|
|
282
|
-
"atomic_write_text",
|
|
283
|
-
"chmod_600",
|
|
284
|
-
"AppPaths",
|
|
285
|
-
# session_paths — единый резолвер браузерных сессий (~/.sessions)
|
|
286
|
-
"sessions_home",
|
|
287
|
-
"browser_profile_dir",
|
|
288
|
-
"shared_google_profile_dir",
|
|
289
|
-
"make_profile_dir_resolver",
|
|
290
|
-
"make_session_store",
|
|
291
|
-
# contract — generic «талия» (Protocol + enums + DTO координат сессии/кредов)
|
|
292
|
-
"PaginationMode",
|
|
293
|
-
"AuthMode",
|
|
256
|
+
# requesting: транспорт-исполнители + режимы/протоколы запроса
|
|
294
257
|
"TransportKind",
|
|
295
258
|
"RequestExecutionMode",
|
|
296
|
-
"SessionRef",
|
|
297
|
-
"Creds",
|
|
298
259
|
"RequestBody",
|
|
299
260
|
"ResponseLike",
|
|
300
261
|
"Transport",
|
|
301
262
|
"SyncTransport",
|
|
302
263
|
"HttpRequestExecutor",
|
|
303
264
|
"SyncHttpRequestExecutor",
|
|
304
|
-
"
|
|
265
|
+
"Codec",
|
|
266
|
+
"make_transport",
|
|
267
|
+
"register_transport",
|
|
268
|
+
"create_request_executor",
|
|
269
|
+
"register_request_provider",
|
|
270
|
+
"HttpxTransport",
|
|
271
|
+
"HttpxRequestExecutor",
|
|
272
|
+
"HttpClient",
|
|
273
|
+
"RestHttpClient",
|
|
274
|
+
"HttpxSyncTransport",
|
|
275
|
+
"HttpxSyncRequestExecutor",
|
|
276
|
+
"SyncHttpClient",
|
|
277
|
+
# browser/сессии: ЖЦ браузер-сессии + профили + warmup-минт
|
|
305
278
|
"BrowserBackend",
|
|
306
279
|
"SyncBrowserBackend",
|
|
307
280
|
"BrowserSession",
|
|
308
281
|
"SyncBrowserSession",
|
|
309
|
-
"Codec",
|
|
310
|
-
"Auth",
|
|
311
|
-
# factory — нейтральный выбор транспорта/браузера по роли (Enum → фабрика → реестр)
|
|
312
282
|
"BrowserEngine",
|
|
313
283
|
"BrowserProvider",
|
|
314
284
|
"AutomationDriver",
|
|
315
285
|
"BrowserOptions",
|
|
316
286
|
"BrowserSessionSettings",
|
|
317
|
-
"make_transport",
|
|
318
|
-
"register_transport",
|
|
319
|
-
"create_request_executor",
|
|
320
|
-
"register_request_provider",
|
|
321
287
|
"make_browser_backend",
|
|
322
288
|
"register_browser_backend",
|
|
323
289
|
"create_browser_session",
|
|
324
290
|
"register_browser_provider",
|
|
291
|
+
"sessions_home",
|
|
292
|
+
"browser_profile_dir",
|
|
293
|
+
"shared_google_profile_dir",
|
|
294
|
+
"make_profile_dir_resolver",
|
|
295
|
+
"make_session_store",
|
|
296
|
+
"WarmupTokenMinter",
|
|
297
|
+
"TokenHarvest",
|
|
298
|
+
# auth + refresh: стратегии авторизации + проактивное обновление сессии
|
|
299
|
+
"AuthMode",
|
|
300
|
+
"Auth",
|
|
325
301
|
"Refreshable",
|
|
326
302
|
"ProactiveRefreshable",
|
|
327
303
|
"SyncRefreshable",
|
|
328
304
|
"SyncProactiveRefreshable",
|
|
329
|
-
"
|
|
330
|
-
"
|
|
305
|
+
"TokenAuth",
|
|
306
|
+
"CookieSessionAuth",
|
|
307
|
+
"OAuth2Auth",
|
|
308
|
+
"BrowserLoginAuth",
|
|
309
|
+
"CsrfHeaderAuth",
|
|
310
|
+
"CSRF_DEFAULT_HEADER",
|
|
311
|
+
"extract_token_from_text",
|
|
312
|
+
"dump_settings",
|
|
313
|
+
"load_settings",
|
|
314
|
+
"encrypt_settings",
|
|
315
|
+
"decrypt_settings",
|
|
316
|
+
"RotatingAuth",
|
|
317
|
+
"Keepalive",
|
|
318
|
+
"RefreshableChain",
|
|
319
|
+
"DEFAULT_ROTATE_INTERVAL",
|
|
320
|
+
# sessions + secrets: envelope-хранилище сессий + креды + keyring-стор
|
|
321
|
+
"SessionRef",
|
|
322
|
+
"Creds",
|
|
331
323
|
"SessionStoreProtocol",
|
|
332
|
-
# contract — квоты/лимиты (generic DTO)
|
|
333
|
-
"QuotaScope",
|
|
334
|
-
"QuotaInfo",
|
|
335
|
-
"LimitSpec",
|
|
336
|
-
# protocols — онбординг/health контракты (опциональные)
|
|
337
|
-
"LoginMode",
|
|
338
|
-
"LoginRequirements",
|
|
339
|
-
"InteractiveFlow",
|
|
340
|
-
"OnboardingProtocol",
|
|
341
|
-
"HealthState",
|
|
342
|
-
"HealthStatus",
|
|
343
|
-
"HealthProtocol",
|
|
344
|
-
# entities (W6) — нейтральные data-классы оркестраторов (почва под W7)
|
|
345
|
-
"Session",
|
|
346
|
-
"SessionChanges",
|
|
347
|
-
"SessionContext",
|
|
348
|
-
"HealthReport",
|
|
349
|
-
# secret_store — keyring + file-fallback
|
|
350
|
-
"SecretStore",
|
|
351
|
-
# sessions (W4): envelope-шифрованное хранилище сессий (spec §4)
|
|
352
324
|
"SessionStore",
|
|
353
325
|
"SessionStoreError",
|
|
354
326
|
"KekUnavailableError",
|
|
355
327
|
"resolve_kek",
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
"
|
|
359
|
-
"
|
|
360
|
-
"
|
|
361
|
-
|
|
362
|
-
"
|
|
363
|
-
"
|
|
364
|
-
"
|
|
365
|
-
|
|
366
|
-
"
|
|
367
|
-
|
|
368
|
-
"
|
|
369
|
-
|
|
370
|
-
"
|
|
371
|
-
"
|
|
372
|
-
|
|
373
|
-
"
|
|
374
|
-
"text_block",
|
|
375
|
-
"block_end",
|
|
376
|
-
"header_block",
|
|
377
|
-
"list_item_block",
|
|
378
|
-
"paragraphs",
|
|
379
|
-
"decode_text_block",
|
|
380
|
-
# limit: проактивный конфигуратор троттлинга / rate-limit по scope
|
|
381
|
-
"LimitWindow",
|
|
382
|
-
"LimitPolicy",
|
|
383
|
-
"LimitScope",
|
|
384
|
-
"RateLimiter",
|
|
385
|
-
# windows: обобщённые ОКНА лимитов (rolling/calendar/fixed) + фабрика
|
|
386
|
-
"Window",
|
|
387
|
-
"RollingWindow",
|
|
388
|
-
"CalendarWindow",
|
|
389
|
-
"FixedWindow",
|
|
390
|
-
"parse_window",
|
|
391
|
-
# antibot: warmup-минт одноразовых токенов тёплой страницей (генерик)
|
|
392
|
-
"WarmupTokenMinter",
|
|
393
|
-
"TokenHarvest",
|
|
394
|
-
# pool: балансер N аккаунтов одного сервиса (селектор поверх SessionStore)
|
|
395
|
-
"SessionPool",
|
|
396
|
-
"PoolChoice",
|
|
397
|
-
"DEFAULT_SKIP_STATUSES",
|
|
398
|
-
# rpc (E1): codec-слой + RPC choke-point поверх HttpClient
|
|
399
|
-
"JsonCodec",
|
|
400
|
-
"PrefixedJsonCodec",
|
|
401
|
-
"RpcClient",
|
|
402
|
-
# stream (E1): WS-подобные persistent-транспорты (Stub + websockets reference)
|
|
403
|
-
"StubStreamTransport",
|
|
404
|
-
"WebSocketsStreamTransport",
|
|
405
|
-
"StreamClosedError",
|
|
406
|
-
# errmap (W4): декларативная карта HTTP-ответ → доменная ошибка
|
|
328
|
+
"SecretStore",
|
|
329
|
+
# errors + errmap: единая иерархия ERROR-HUB + карта ответ→ошибка
|
|
330
|
+
"CliError",
|
|
331
|
+
"ApiError",
|
|
332
|
+
"AuthRequired",
|
|
333
|
+
"SessionExpired",
|
|
334
|
+
"RateLimited",
|
|
335
|
+
"ValidationError",
|
|
336
|
+
"NotImplementedYet",
|
|
337
|
+
"NotFoundError",
|
|
338
|
+
"ServerError",
|
|
339
|
+
"TransportError",
|
|
340
|
+
"Blocked",
|
|
341
|
+
"RETRYABLE",
|
|
342
|
+
"AdapterError",
|
|
343
|
+
"NotFound",
|
|
344
|
+
"GraphQLError",
|
|
345
|
+
"ErrorMapper",
|
|
407
346
|
"ErrorMap",
|
|
408
347
|
"ErrorMapBuilder",
|
|
409
348
|
"BodyRule",
|
|
@@ -411,7 +350,27 @@ __all__ = [
|
|
|
411
350
|
"AuthExpired",
|
|
412
351
|
"build_error_map",
|
|
413
352
|
"DEFAULT_ERROR_MAP",
|
|
414
|
-
#
|
|
353
|
+
# reliability: retry / limit / pool / checkpoint
|
|
354
|
+
"RetryPolicy",
|
|
355
|
+
"DEFAULT_RETRY",
|
|
356
|
+
"SimpleRetryPolicy",
|
|
357
|
+
"DEFAULT_SIMPLE_RETRY",
|
|
358
|
+
"LimitWindow",
|
|
359
|
+
"LimitPolicy",
|
|
360
|
+
"LimitScope",
|
|
361
|
+
"RateLimiter",
|
|
362
|
+
"LimitSpec",
|
|
363
|
+
"QuotaScope",
|
|
364
|
+
"QuotaInfo",
|
|
365
|
+
"SessionPool",
|
|
366
|
+
"PoolChoice",
|
|
367
|
+
"DEFAULT_SKIP_STATUSES",
|
|
368
|
+
"Checkpoint",
|
|
369
|
+
"JsonlSink",
|
|
370
|
+
"RunMetrics",
|
|
371
|
+
# pagination / bulk / upload: листание ресурса + батчи + resumable-догрузка
|
|
372
|
+
"PaginationMode",
|
|
373
|
+
"Paginator",
|
|
415
374
|
"CursorPaginator",
|
|
416
375
|
"PageParams",
|
|
417
376
|
"DEFAULT_PAGE_PARAMS",
|
|
@@ -420,40 +379,52 @@ __all__ = [
|
|
|
420
379
|
"default_extract_items",
|
|
421
380
|
"default_extract_cursor",
|
|
422
381
|
"with_page_params",
|
|
423
|
-
# pagination flat-page (W8): offset/total на верхнем уровне тела
|
|
424
382
|
"FlatPage",
|
|
425
383
|
"parse_flat_page",
|
|
426
384
|
"next_flat_offset",
|
|
427
|
-
# auth (W4): стратегии авторизации + персистентность сессии
|
|
428
|
-
"TokenAuth",
|
|
429
|
-
"CookieSessionAuth",
|
|
430
|
-
"OAuth2Auth",
|
|
431
|
-
"BrowserLoginAuth",
|
|
432
|
-
"CsrfHeaderAuth",
|
|
433
|
-
"CSRF_DEFAULT_HEADER",
|
|
434
|
-
"extract_token_from_text",
|
|
435
|
-
"dump_settings",
|
|
436
|
-
"load_settings",
|
|
437
|
-
"encrypt_settings",
|
|
438
|
-
"decrypt_settings",
|
|
439
|
-
# refresh: проактивное обновление ротируемой сессии + keepalive + fallback
|
|
440
|
-
"RotatingAuth",
|
|
441
|
-
"Keepalive",
|
|
442
|
-
"RefreshableChain",
|
|
443
|
-
"DEFAULT_ROTATE_INTERVAL",
|
|
444
|
-
# retry
|
|
445
|
-
"RetryPolicy",
|
|
446
|
-
"DEFAULT_RETRY",
|
|
447
|
-
"SimpleRetryPolicy",
|
|
448
|
-
"DEFAULT_SIMPLE_RETRY",
|
|
449
|
-
# bulk: движок батч-операций над набором id (per-item outcome, не роняет батч)
|
|
450
385
|
"BulkOutcome",
|
|
451
386
|
"BulkOperationError",
|
|
452
387
|
"BulkError",
|
|
453
388
|
"BulkOperationResult",
|
|
454
389
|
"run_bulk",
|
|
455
390
|
"run_bulk_async",
|
|
456
|
-
|
|
391
|
+
"ChunkedUploader",
|
|
392
|
+
"UploadResult",
|
|
393
|
+
# orchestration / protocols / entities: онбординг/health + нейтральные data-классы
|
|
394
|
+
"LoginMode",
|
|
395
|
+
"LoginRequirements",
|
|
396
|
+
"InteractiveFlow",
|
|
397
|
+
"OnboardingProtocol",
|
|
398
|
+
"HealthState",
|
|
399
|
+
"HealthStatus",
|
|
400
|
+
"HealthProtocol",
|
|
401
|
+
"Session",
|
|
402
|
+
"SessionChanges",
|
|
403
|
+
"SessionContext",
|
|
404
|
+
"HealthReport",
|
|
405
|
+
# rpc / stream / graphql: codec-слой + persistent-транспорты + GraphQL-клиент
|
|
406
|
+
"StreamTransport",
|
|
407
|
+
"JsonCodec",
|
|
408
|
+
"PrefixedJsonCodec",
|
|
409
|
+
"RpcClient",
|
|
410
|
+
"StubStreamTransport",
|
|
411
|
+
"WebSocketsStreamTransport",
|
|
412
|
+
"StreamClosedError",
|
|
413
|
+
"GraphQLClient",
|
|
414
|
+
# blocks / forms / windows / redaction / config: примитивы тел, окна, маски, утили путей
|
|
415
|
+
"blocks",
|
|
416
|
+
"text_block",
|
|
417
|
+
"block_end",
|
|
418
|
+
"header_block",
|
|
419
|
+
"list_item_block",
|
|
420
|
+
"paragraphs",
|
|
421
|
+
"decode_text_block",
|
|
422
|
+
"FormCodec",
|
|
423
|
+
"Window",
|
|
424
|
+
"RollingWindow",
|
|
425
|
+
"CalendarWindow",
|
|
426
|
+
"FixedWindow",
|
|
427
|
+
"parse_window",
|
|
457
428
|
"SECRET_MASK",
|
|
458
429
|
"HEADER_BLACKLIST",
|
|
459
430
|
"BODY_FIELD_PATTERNS",
|
|
@@ -461,4 +432,12 @@ __all__ = [
|
|
|
461
432
|
"sanitize_body",
|
|
462
433
|
"truncate_body",
|
|
463
434
|
"excerpt_response_body",
|
|
435
|
+
"deep_merge",
|
|
436
|
+
"interpolate_env",
|
|
437
|
+
"load_dotenv",
|
|
438
|
+
"slugify",
|
|
439
|
+
"normalize_account_id",
|
|
440
|
+
"atomic_write_text",
|
|
441
|
+
"chmod_600",
|
|
442
|
+
"AppPaths",
|
|
464
443
|
]
|
|
@@ -97,7 +97,8 @@ from .warmup_minter import TokenHarvest, WarmupTokenMinter
|
|
|
97
97
|
# ImpersonatedHttpExecutor — TLS/JA3-impersonate (curl-cffi) [было CurlCffiTransport];
|
|
98
98
|
# BrowserRequestExecutor — запрос «руками браузера» по CDP/CamouFox [было CdpTransport];
|
|
99
99
|
# BorrowedPageRequestExecutor — запрос в ЗАИМСТВОВАННОЙ странице [было PageEvaluateTransport];
|
|
100
|
-
# BrowserRequester — роль «умеет выполнить запрос в браузере»
|
|
100
|
+
# BrowserRequester — роль «умеет выполнить запрос в браузере» ПОВЕРХ живой
|
|
101
|
+
# contract.BrowserSession (fetch, не ЖЦ) [было CdpBrowserBackend].
|
|
101
102
|
# Старые имена остаются deprecated-псевдонимами (ничего не удалено).
|
|
102
103
|
ImpersonatedHttpExecutor = CurlCffiTransport
|
|
103
104
|
BrowserRequestExecutor = CdpTransport
|
|
@@ -23,12 +23,28 @@ from ._helpers import _as_transport_error, _to_httpx_response
|
|
|
23
23
|
|
|
24
24
|
@runtime_checkable
|
|
25
25
|
class CdpBrowserBackend(Protocol):
|
|
26
|
-
"""Контракт
|
|
26
|
+
"""Контракт «умеет ВЫПОЛНИТЬ запрос в браузере» (роль `BrowserRequester`), под
|
|
27
|
+
`CdpTransport` (точка DI).
|
|
27
28
|
|
|
28
29
|
Скрывает за собой запуск системного Edge/Chrome с `--remote-debugging-port`
|
|
29
30
|
и `connect_over_cdp` (см. recipes/antibot `cdp_real_browser.py`). Реализация —
|
|
30
31
|
в `librarykit.browser` (Playwright/patchright); здесь — только контракт, чтобы
|
|
31
32
|
`antibot` не тащил тяжёлый browser-стек и тестировался фейком той же формы.
|
|
33
|
+
|
|
34
|
+
Разделение с `librarykit.contract.BrowserSession` (= `BrowserBackend`) — это
|
|
35
|
+
ДВЕ РАЗНЫЕ роли, а не одна:
|
|
36
|
+
|
|
37
|
+
- `BrowserSession` — ЖИЗНЕННЫЙ ЦИКЛ живой сессии: поднять/держать/закрыть
|
|
38
|
+
браузер и отдать страницу с контекстом (`ensure_page`/`context`/`aclose`);
|
|
39
|
+
- `CdpBrowserBackend` (`BrowserRequester`) — СПОСОБНОСТЬ выполнить HTTP-запрос
|
|
40
|
+
руками уже живой сессии (`fetch`), поверх её страницы/контекста.
|
|
41
|
+
|
|
42
|
+
Как Protocol'ы они пересекаются лишь по `aclose()`; ни один не является
|
|
43
|
+
структурным подтипом другого (у Requester нет `ensure_page`/`context`, у
|
|
44
|
+
Session нет `fetch`). Конкретные бэкенды `librarykit.browser`
|
|
45
|
+
(`CdpChromeBackend`/`CamoufoxBackend`) реализуют ОБА контракта одним объектом:
|
|
46
|
+
он И держит живую сессию, И умеет `fetch` поверх неё — то есть
|
|
47
|
+
`BrowserRequester` НАДСТРАИВАЕТ исполнение запроса над сессией, не заменяя её.
|
|
32
48
|
"""
|
|
33
49
|
|
|
34
50
|
async def fetch(
|
|
@@ -174,11 +190,17 @@ class CdpTransport(Transport):
|
|
|
174
190
|
|
|
175
191
|
@runtime_checkable
|
|
176
192
|
class SyncCdpBrowserBackend(Protocol):
|
|
177
|
-
"""Sync-сиблинг `CdpBrowserBackend`:
|
|
193
|
+
"""Sync-сиблинг `CdpBrowserBackend`: роль `SyncBrowserRequester` БЕЗ await.
|
|
178
194
|
|
|
179
|
-
Та же роль
|
|
195
|
+
Та же роль «умеет ВЫПОЛНИТЬ запрос в браузере» (`fetch` → ответоподобный
|
|
180
196
|
объект под `_to_httpx_response`), но синхронная сигнатура — для навыков без
|
|
181
197
|
event-loop. Реализация — `librarykit.browser.SyncCamoufoxBackend`.
|
|
198
|
+
|
|
199
|
+
То же разделение, что у async-версии: это СПОСОБНОСТЬ исполнить запрос поверх
|
|
200
|
+
живой сессии, а не её жизненный цикл — ЖЦ (поднять/держать/закрыть, страница+
|
|
201
|
+
контекст) несёт `librarykit.contract.SyncBrowserSession` (= `SyncBrowserBackend`,
|
|
202
|
+
`ensure_page`/`context`). Пересечение Protocol'ов — только семантика закрытия;
|
|
203
|
+
конкретный sync-бэкенд реализует обе роли одним объектом.
|
|
182
204
|
"""
|
|
183
205
|
|
|
184
206
|
def fetch(
|
|
@@ -93,7 +93,7 @@ class SessionContext:
|
|
|
93
93
|
|
|
94
94
|
|
|
95
95
|
@dataclass
|
|
96
|
-
class
|
|
96
|
+
class RawHealthStatus:
|
|
97
97
|
"""RAW-результат health-check адаптера ДО классификации (нейтрально).
|
|
98
98
|
|
|
99
99
|
Это «сырая» форма, которую отдаёт ``NetworkAdapter.health_check()`` и которую
|
|
@@ -104,6 +104,8 @@ class HealthStatus:
|
|
|
104
104
|
Развязка vs `librarykit.protocols.HealthStatus`: тот — УЖЕ классифицированный
|
|
105
105
|
DTO (несёт `state: HealthState`, для `HealthProtocol`); ЭТОТ — сырой вход
|
|
106
106
|
классификатора (несёт `healthy: bool` + `rate_limit_remaining`, без `state`).
|
|
107
|
+
Раньше оба назывались `HealthStatus` — конфликт снят переименованием этой,
|
|
108
|
+
RAW-формы, в `RawHealthStatus` (старое имя — deprecated-алиас ниже).
|
|
107
109
|
|
|
108
110
|
`classify_health_state` читает поля по duck-typing (`.auth_valid`/
|
|
109
111
|
`.api_reachable`/`.notes`/`.rate_limit_remaining`/`.healthy`), поэтому
|
|
@@ -146,6 +148,29 @@ __all__ = [
|
|
|
146
148
|
"Session",
|
|
147
149
|
"SessionChanges",
|
|
148
150
|
"SessionContext",
|
|
149
|
-
"
|
|
151
|
+
"RawHealthStatus",
|
|
150
152
|
"HealthReport",
|
|
151
153
|
]
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def __getattr__(name: str) -> Any:
|
|
157
|
+
"""PEP 562: deprecated-алиас `HealthStatus` → `RawHealthStatus`.
|
|
158
|
+
|
|
159
|
+
RAW-снимок здоровья переименован в `RawHealthStatus`, чтобы снять конфликт
|
|
160
|
+
имён с классифицированным DTO `librarykit.protocols.HealthStatus`. Старое имя
|
|
161
|
+
остаётся импортируемым (`from librarykit.entities import HealthStatus`) ради
|
|
162
|
+
обратной совместимости, но предупреждает о переезде.
|
|
163
|
+
"""
|
|
164
|
+
if name == "HealthStatus":
|
|
165
|
+
import warnings
|
|
166
|
+
|
|
167
|
+
warnings.warn(
|
|
168
|
+
"librarykit.entities.HealthStatus переименован в RawHealthStatus. "
|
|
169
|
+
"Имя HealthStatus теперь закреплено за классифицированным DTO "
|
|
170
|
+
"librarykit.protocols.HealthStatus; RAW-снимок стал RawHealthStatus. "
|
|
171
|
+
"Обнови импорт на RawHealthStatus — старый алиас будет удалён позже.",
|
|
172
|
+
DeprecationWarning,
|
|
173
|
+
stacklevel=2,
|
|
174
|
+
)
|
|
175
|
+
return RawHealthStatus
|
|
176
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
в bublictr. Они переиспользуемы любым потребителем (bublictr / reverse-factory):
|
|
6
6
|
|
|
7
7
|
- стоят на `librarykit.entities` (нейтральные `Session`/`SessionContext`/
|
|
8
|
-
`HealthReport
|
|
8
|
+
`HealthReport`/`RawHealthStatus`, `network: str`) и `librarykit.enums.HealthState`;
|
|
9
9
|
- репо/сторы/probe инжектируются как `librarykit.ports`-Protocol;
|
|
10
10
|
- доменные привязки (реестр адаптеров, enum-значения `Operation`/`TargetKind`,
|
|
11
11
|
координаты `SessionRef`, audit-store, браузерный профиль) ИНЪЕКТИРУЮТСЯ доменом
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
Поднято из доменной архитектуры в КОРЕНЬ китов (переиспользуемый health-слой).
|
|
4
4
|
Развязка:
|
|
5
5
|
|
|
6
|
-
- стоит на `librarykit.entities` (`HealthReport
|
|
6
|
+
- стоит на `librarykit.entities` (`HealthReport`/`RawHealthStatus`, `network: str`)
|
|
7
7
|
и `librarykit.enums.HealthState` (канон);
|
|
8
8
|
- репо/probe инжектируются как `librarykit.ports`-Protocol — без доменных
|
|
9
9
|
SQLite/Keyring/registry импортов и без `NetworkId`;
|
|
10
10
|
- `classify_health_state` принимает ЛЮБОЙ объект с полями
|
|
11
11
|
`.auth_valid/.api_reachable/.notes/.rate_limit_remaining/.healthy` (duck-typing) —
|
|
12
|
-
и нейтральный
|
|
12
|
+
и нейтральный `RawHealthStatus`, и доменный pydantic-`HealthStatus`.
|
|
13
13
|
|
|
14
14
|
ЗАКОН СЛОЁВ: только stdlib + `librarykit.*`; никаких adapterkit/clikit/bublictr.
|
|
15
15
|
"""
|
|
@@ -19,7 +19,7 @@ from dataclasses import dataclass, field
|
|
|
19
19
|
from datetime import UTC, datetime
|
|
20
20
|
from typing import TYPE_CHECKING, Any
|
|
21
21
|
|
|
22
|
-
from librarykit.entities import HealthReport,
|
|
22
|
+
from librarykit.entities import HealthReport, RawHealthStatus
|
|
23
23
|
from librarykit.enums import HealthState
|
|
24
24
|
|
|
25
25
|
if TYPE_CHECKING:
|
|
@@ -37,7 +37,7 @@ __all__ = [
|
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
# =========================================================================== #
|
|
40
|
-
# 1. Классификатор
|
|
40
|
+
# 1. Классификатор RawHealthStatus → HealthState (SP-4 §8) #
|
|
41
41
|
# =========================================================================== #
|
|
42
42
|
|
|
43
43
|
# Порог warning: если rate_limit_remaining < этого значения (и не None) →
|
|
@@ -58,7 +58,7 @@ def classify_health_state(status: Any) -> HealthState:
|
|
|
58
58
|
7. иначе (есть rate-limit info → DEGRADED, нет → UNKNOWN)
|
|
59
59
|
|
|
60
60
|
`status` — ЛЮБОЙ объект с полями `.auth_valid/.api_reachable/.notes/
|
|
61
|
-
.rate_limit_remaining/.healthy` (нейтральный
|
|
61
|
+
.rate_limit_remaining/.healthy` (нейтральный `RawHealthStatus` ИЛИ доменный
|
|
62
62
|
pydantic-`HealthStatus`): классификатор домен-нейтрален.
|
|
63
63
|
"""
|
|
64
64
|
# 1. Нет аутентификации
|
|
@@ -145,7 +145,7 @@ class HealthMonitor:
|
|
|
145
145
|
return await probe.probe(binding=binding)
|
|
146
146
|
|
|
147
147
|
# Fallback: без реального адаптера — synthetic UNAUTHENTICATED report.
|
|
148
|
-
fallback_status =
|
|
148
|
+
fallback_status = RawHealthStatus(
|
|
149
149
|
network=network_str,
|
|
150
150
|
healthy=False,
|
|
151
151
|
auth_valid=False,
|
|
@@ -258,7 +258,7 @@ class GenericAdapterHealthProbe:
|
|
|
258
258
|
|
|
259
259
|
# Healthy.
|
|
260
260
|
notes = [f"ping ok; {ping}"]
|
|
261
|
-
status =
|
|
261
|
+
status = RawHealthStatus(
|
|
262
262
|
network=str(binding.network),
|
|
263
263
|
healthy=True,
|
|
264
264
|
auth_valid=True,
|
|
@@ -287,7 +287,7 @@ def _err_report(
|
|
|
287
287
|
kind: str = "error",
|
|
288
288
|
) -> HealthReport:
|
|
289
289
|
auth_valid = kind != "unauthenticated"
|
|
290
|
-
status =
|
|
290
|
+
status = RawHealthStatus(
|
|
291
291
|
network=str(binding.network),
|
|
292
292
|
healthy=False,
|
|
293
293
|
auth_valid=auth_valid,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "s-librarykit"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.1"
|
|
4
4
|
description = "Жирный КОРЕНЬ китов: единая error-иерархия, config/retry/paths-утили, checkpoint/resume, транспорт/auth/sessions — общий код для clikit, adapterkit и доменных пакетов."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
@@ -16,7 +16,7 @@ from typing import Any
|
|
|
16
16
|
|
|
17
17
|
import pytest
|
|
18
18
|
|
|
19
|
-
from librarykit.entities import HealthReport,
|
|
19
|
+
from librarykit.entities import HealthReport, RawHealthStatus, Session, SessionChanges
|
|
20
20
|
from librarykit.enums import HealthState
|
|
21
21
|
from librarykit.orchestration import (
|
|
22
22
|
GenericAdapterHealthProbe,
|
|
@@ -29,16 +29,16 @@ from librarykit.orchestration import (
|
|
|
29
29
|
)
|
|
30
30
|
|
|
31
31
|
# =========================================================================== #
|
|
32
|
-
# classify_health_state — нейтральный
|
|
32
|
+
# classify_health_state — нейтральный RawHealthStatus #
|
|
33
33
|
# =========================================================================== #
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
def _status(**kwargs: Any) ->
|
|
36
|
+
def _status(**kwargs: Any) -> RawHealthStatus:
|
|
37
37
|
defaults: dict[str, Any] = dict(
|
|
38
38
|
network="telegram", healthy=True, auth_valid=True, api_reachable=True
|
|
39
39
|
)
|
|
40
40
|
defaults.update(kwargs)
|
|
41
|
-
return
|
|
41
|
+
return RawHealthStatus(**defaults)
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
class TestClassifyHealthState:
|
|
@@ -100,6 +100,23 @@ class TestClassifyHealthState:
|
|
|
100
100
|
assert classify_health_state(DuckStatus()) == HealthState.HEALTHY
|
|
101
101
|
|
|
102
102
|
|
|
103
|
+
class TestRawHealthStatusDeprecatedAlias:
|
|
104
|
+
"""entities.HealthStatus — deprecated-алиас RawHealthStatus (back-compat)."""
|
|
105
|
+
|
|
106
|
+
def test_old_name_resolves_to_new_with_warning(self):
|
|
107
|
+
import librarykit.entities as ent
|
|
108
|
+
|
|
109
|
+
with pytest.warns(DeprecationWarning, match="RawHealthStatus"):
|
|
110
|
+
legacy = ent.HealthStatus
|
|
111
|
+
assert legacy is RawHealthStatus
|
|
112
|
+
|
|
113
|
+
def test_unknown_attr_still_raises(self):
|
|
114
|
+
import librarykit.entities as ent
|
|
115
|
+
|
|
116
|
+
with pytest.raises(AttributeError):
|
|
117
|
+
_ = ent.DoesNotExist
|
|
118
|
+
|
|
119
|
+
|
|
103
120
|
# =========================================================================== #
|
|
104
121
|
# HealthMonitor — фейковые репо по librarykit.ports #
|
|
105
122
|
# =========================================================================== #
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|