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.
Files changed (97) hide show
  1. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/PKG-INFO +1 -1
  2. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/__init__.py +127 -148
  3. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/antibot/__init__.py +2 -1
  4. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/antibot/cdp.py +25 -3
  5. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/entities.py +27 -2
  6. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/orchestration/__init__.py +1 -1
  7. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/orchestration/health.py +8 -8
  8. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/pyproject.toml +1 -1
  9. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_orchestration.py +21 -4
  10. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/.gitignore +0 -0
  11. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/.gitlab-ci.yml +0 -0
  12. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/AGENTS.md +0 -0
  13. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/CHANGELOG.md +0 -0
  14. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/LICENSE +0 -0
  15. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/README.md +0 -0
  16. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/docs/superpowers/specs/2026-06-24-unified-sessions-design.md +0 -0
  17. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/antibot/_helpers.py +0 -0
  18. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/antibot/curl_cffi.py +0 -0
  19. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/antibot/page_evaluate.py +0 -0
  20. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/antibot/warmup_minter.py +0 -0
  21. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/auth.py +0 -0
  22. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/blocks.py +0 -0
  23. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/browser/__init__.py +0 -0
  24. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/browser/_engine.py +0 -0
  25. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/browser/camoufox.py +0 -0
  26. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/browser/geometry.py +0 -0
  27. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/browser/launchers.py +0 -0
  28. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/browser/state.py +0 -0
  29. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/bulk.py +0 -0
  30. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/checkpoint.py +0 -0
  31. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/config_util.py +0 -0
  32. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/contract.py +0 -0
  33. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/enums.py +0 -0
  34. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/errmap.py +0 -0
  35. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/errors.py +0 -0
  36. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/factory.py +0 -0
  37. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/forms.py +0 -0
  38. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/graphql.py +0 -0
  39. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/limit.py +0 -0
  40. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/orchestration/onboarding.py +0 -0
  41. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/orchestration/session_loader.py +0 -0
  42. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/pagination.py +0 -0
  43. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/pool.py +0 -0
  44. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/ports.py +0 -0
  45. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/protocols.py +0 -0
  46. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/redaction.py +0 -0
  47. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/refresh.py +0 -0
  48. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/retry.py +0 -0
  49. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/rpc.py +0 -0
  50. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/secret_store.py +0 -0
  51. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/session_bridge.py +0 -0
  52. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/session_paths.py +0 -0
  53. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/sessions/__init__.py +0 -0
  54. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/sessions/_const.py +0 -0
  55. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/sessions/_fsutil.py +0 -0
  56. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/stream.py +0 -0
  57. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/transport/__init__.py +0 -0
  58. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/transport/_helpers.py +0 -0
  59. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/transport/http_client.py +0 -0
  60. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/transport/permissive.py +0 -0
  61. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/transport/rest_client.py +0 -0
  62. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/transport/transport_http.py +0 -0
  63. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/upload.py +0 -0
  64. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/librarykit/windows.py +0 -0
  65. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/conftest.py +0 -0
  66. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_antibot.py +0 -0
  67. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_auth.py +0 -0
  68. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_blocks.py +0 -0
  69. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_browser.py +0 -0
  70. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_bulk.py +0 -0
  71. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_checkpoint.py +0 -0
  72. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_config_util.py +0 -0
  73. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_errmap.py +0 -0
  74. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_errors.py +0 -0
  75. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_factory.py +0 -0
  76. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_forms.py +0 -0
  77. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_graphql.py +0 -0
  78. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_limit.py +0 -0
  79. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_limit_contract.py +0 -0
  80. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_pagination.py +0 -0
  81. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_permissive_http.py +0 -0
  82. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_pool.py +0 -0
  83. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_redaction.py +0 -0
  84. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_refresh.py +0 -0
  85. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_retry.py +0 -0
  86. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_rpc.py +0 -0
  87. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_session_bridge.py +0 -0
  88. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_session_paths.py +0 -0
  89. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_sessions.py +0 -0
  90. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_stream.py +0 -0
  91. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_transport_client.py +0 -0
  92. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_transport_rest.py +0 -0
  93. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_transport_sync.py +0 -0
  94. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_upload.py +0 -0
  95. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_warmup_minter.py +0 -0
  96. {s_librarykit-0.3.0 → s_librarykit-0.3.1}/tests/test_windows.py +0 -0
  97. {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.0
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.0"
252
+ __version__ = "0.3.1"
253
253
 
254
254
  __all__ = [
255
255
  "__version__",
256
- # checkpoint
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
- "StreamTransport",
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
- "ErrorMapper",
330
- "Paginator",
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
- # transport (W4): конкретный httpx-транспорт + choke-point клиент
357
- "HttpxTransport",
358
- "HttpxRequestExecutor",
359
- "HttpClient",
360
- "RestHttpClient",
361
- # transport sync-сиблинги (для навыков без event-loop)
362
- "HttpxSyncTransport",
363
- "HttpxSyncRequestExecutor",
364
- "SyncHttpClient",
365
- # forms (W8): кодек form-urlencoded тел с nested-JSON полями
366
- "FormCodec",
367
- # graphql (W8): GENERIC GraphQL-клиент поверх RestHttpClient/HttpClient
368
- "GraphQLClient",
369
- # upload (W8): GENERIC resumable chunked uploader
370
- "ChunkedUploader",
371
- "UploadResult",
372
- # blocks (W8): GENERIC draft.js richtext block-хелперы
373
- "blocks",
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
- # pagination (W4): листатель ресурса (offset/cursor/page) tweepy-стиля
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
- # redaction: маски секретов + truncation для HTTP-заголовков/body (audit/логи)
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 — роль «умеет выполнить запрос в браузере» [было CdpBrowserBackend].
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
- """Контракт «движка реального браузера» под `CdpTransport` (точка DI).
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`: движок реального/stealth-браузера БЕЗ await.
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 HealthStatus:
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
- "HealthStatus",
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`/RAW-`HealthStatus`, `network: str`) и `librarykit.enums.HealthState`;
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`/RAW-`HealthStatus`, `network: str`)
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
- и нейтральный RAW-`HealthStatus`, и доменный pydantic-`HealthStatus`.
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, HealthStatus
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. Классификатор RAW-HealthStatus → HealthState (SP-4 §8) #
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` (нейтральный RAW-`HealthStatus` ИЛИ доменный
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 = HealthStatus(
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 = HealthStatus(
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 = HealthStatus(
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.0"
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, HealthStatus, Session, SessionChanges
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 — нейтральный RAW-HealthStatus #
32
+ # classify_health_state — нейтральный RawHealthStatus #
33
33
  # =========================================================================== #
34
34
 
35
35
 
36
- def _status(**kwargs: Any) -> HealthStatus:
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 HealthStatus(**defaults)
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