s-librarykit 0.3.0__tar.gz → 0.5.0__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 (106) hide show
  1. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/PKG-INFO +3 -1
  2. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/__init__.py +167 -148
  3. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/antibot/__init__.py +2 -1
  4. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/antibot/cdp.py +25 -3
  5. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/auth.py +11 -0
  6. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/browser/__init__.py +27 -0
  7. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/browser/_engine.py +11 -0
  8. s_librarykit-0.5.0/librarykit/browser/capture_tap.py +590 -0
  9. s_librarykit-0.5.0/librarykit/browser/nodriver.py +178 -0
  10. s_librarykit-0.5.0/librarykit/browser/persistent.py +177 -0
  11. s_librarykit-0.5.0/librarykit/cookie_refresh.py +233 -0
  12. s_librarykit-0.5.0/librarykit/cookies.py +270 -0
  13. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/entities.py +27 -2
  14. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/factory.py +28 -3
  15. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/orchestration/__init__.py +1 -1
  16. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/orchestration/health.py +8 -8
  17. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/pyproject.toml +4 -1
  18. s_librarykit-0.5.0/tests/test_capture_tap.py +185 -0
  19. s_librarykit-0.5.0/tests/test_cookie_refresh.py +166 -0
  20. s_librarykit-0.5.0/tests/test_cookies.py +86 -0
  21. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_factory.py +1 -1
  22. s_librarykit-0.5.0/tests/test_nodriver_backend.py +76 -0
  23. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_orchestration.py +21 -4
  24. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/.gitignore +0 -0
  25. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/.gitlab-ci.yml +0 -0
  26. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/AGENTS.md +0 -0
  27. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/CHANGELOG.md +0 -0
  28. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/LICENSE +0 -0
  29. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/README.md +0 -0
  30. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/docs/superpowers/specs/2026-06-24-unified-sessions-design.md +0 -0
  31. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/antibot/_helpers.py +0 -0
  32. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/antibot/curl_cffi.py +0 -0
  33. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/antibot/page_evaluate.py +0 -0
  34. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/antibot/warmup_minter.py +0 -0
  35. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/blocks.py +0 -0
  36. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/browser/camoufox.py +0 -0
  37. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/browser/geometry.py +0 -0
  38. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/browser/launchers.py +0 -0
  39. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/browser/state.py +0 -0
  40. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/bulk.py +0 -0
  41. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/checkpoint.py +0 -0
  42. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/config_util.py +0 -0
  43. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/contract.py +0 -0
  44. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/enums.py +0 -0
  45. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/errmap.py +0 -0
  46. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/errors.py +0 -0
  47. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/forms.py +0 -0
  48. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/graphql.py +0 -0
  49. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/limit.py +0 -0
  50. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/orchestration/onboarding.py +0 -0
  51. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/orchestration/session_loader.py +0 -0
  52. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/pagination.py +0 -0
  53. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/pool.py +0 -0
  54. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/ports.py +0 -0
  55. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/protocols.py +0 -0
  56. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/redaction.py +0 -0
  57. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/refresh.py +0 -0
  58. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/retry.py +0 -0
  59. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/rpc.py +0 -0
  60. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/secret_store.py +0 -0
  61. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/session_bridge.py +0 -0
  62. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/session_paths.py +0 -0
  63. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/sessions/__init__.py +0 -0
  64. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/sessions/_const.py +0 -0
  65. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/sessions/_fsutil.py +0 -0
  66. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/stream.py +0 -0
  67. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/transport/__init__.py +0 -0
  68. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/transport/_helpers.py +0 -0
  69. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/transport/http_client.py +0 -0
  70. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/transport/permissive.py +0 -0
  71. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/transport/rest_client.py +0 -0
  72. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/transport/transport_http.py +0 -0
  73. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/upload.py +0 -0
  74. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/windows.py +0 -0
  75. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/conftest.py +0 -0
  76. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_antibot.py +0 -0
  77. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_auth.py +0 -0
  78. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_blocks.py +0 -0
  79. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_browser.py +0 -0
  80. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_bulk.py +0 -0
  81. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_checkpoint.py +0 -0
  82. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_config_util.py +0 -0
  83. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_errmap.py +0 -0
  84. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_errors.py +0 -0
  85. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_forms.py +0 -0
  86. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_graphql.py +0 -0
  87. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_limit.py +0 -0
  88. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_limit_contract.py +0 -0
  89. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_pagination.py +0 -0
  90. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_permissive_http.py +0 -0
  91. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_pool.py +0 -0
  92. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_redaction.py +0 -0
  93. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_refresh.py +0 -0
  94. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_retry.py +0 -0
  95. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_rpc.py +0 -0
  96. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_session_bridge.py +0 -0
  97. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_session_paths.py +0 -0
  98. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_sessions.py +0 -0
  99. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_stream.py +0 -0
  100. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_transport_client.py +0 -0
  101. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_transport_rest.py +0 -0
  102. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_transport_sync.py +0 -0
  103. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_upload.py +0 -0
  104. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_warmup_minter.py +0 -0
  105. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_windows.py +0 -0
  106. {s_librarykit-0.3.0 → s_librarykit-0.5.0}/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.5.0
4
4
  Summary: Жирный КОРЕНЬ китов: единая error-иерархия, config/retry/paths-утили, checkpoint/resume, транспорт/auth/sessions — общий код для clikit, adapterkit и доменных пакетов.
5
5
  Author: Dmitry
6
6
  License: MIT
@@ -25,6 +25,8 @@ Requires-Dist: hypothesis>=6; extra == 'dev'
25
25
  Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
26
26
  Requires-Dist: pytest>=8; extra == 'dev'
27
27
  Requires-Dist: respx>=0.21; extra == 'dev'
28
+ Provides-Extra: nodriver
29
+ Requires-Dist: nodriver>=0.50; extra == 'nodriver'
28
30
  Provides-Extra: oauth
29
31
  Requires-Dist: authlib>=1.3; extra == 'oauth'
30
32
  Provides-Extra: ws
@@ -22,12 +22,34 @@ from librarykit.auth import (
22
22
  CsrfHeaderAuth,
23
23
  OAuth2Auth,
24
24
  TokenAuth,
25
+ cookies_with_meta_from_state,
25
26
  decrypt_settings,
26
27
  dump_settings,
27
28
  encrypt_settings,
28
29
  extract_token_from_text,
29
30
  load_settings,
30
31
  )
32
+ from librarykit.cookie_refresh import (
33
+ COOKIE_REFRESH_META_KEY,
34
+ CategoryCookieAuth,
35
+ CategoryPolicy,
36
+ FreshnessOutcome,
37
+ LazyRefreshPolicy,
38
+ )
39
+ from librarykit.cookies import (
40
+ DEFAULT_MINT_NAMES,
41
+ DEFAULT_SESSION_NAMES,
42
+ CategoryFreshness,
43
+ Cookie,
44
+ CookieCategory,
45
+ CookieClassifier,
46
+ assess_freshness,
47
+ cookies_from_state,
48
+ earliest_expiry,
49
+ flat_cookies,
50
+ merge_state,
51
+ to_state_cookies,
52
+ )
31
53
  from librarykit.blocks import (
32
54
  block_end,
33
55
  decode_text_block,
@@ -249,161 +271,118 @@ from librarykit.windows import (
249
271
  parse_window,
250
272
  )
251
273
 
252
- __version__ = "0.3.0"
274
+ __version__ = "0.4.0"
253
275
 
254
276
  __all__ = [
255
277
  "__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",
278
+ # requesting: транспорт-исполнители + режимы/протоколы запроса
294
279
  "TransportKind",
295
280
  "RequestExecutionMode",
296
- "SessionRef",
297
- "Creds",
298
281
  "RequestBody",
299
282
  "ResponseLike",
300
283
  "Transport",
301
284
  "SyncTransport",
302
285
  "HttpRequestExecutor",
303
286
  "SyncHttpRequestExecutor",
304
- "StreamTransport",
287
+ "Codec",
288
+ "make_transport",
289
+ "register_transport",
290
+ "create_request_executor",
291
+ "register_request_provider",
292
+ "HttpxTransport",
293
+ "HttpxRequestExecutor",
294
+ "HttpClient",
295
+ "RestHttpClient",
296
+ "HttpxSyncTransport",
297
+ "HttpxSyncRequestExecutor",
298
+ "SyncHttpClient",
299
+ # browser/сессии: ЖЦ браузер-сессии + профили + warmup-минт
305
300
  "BrowserBackend",
306
301
  "SyncBrowserBackend",
307
302
  "BrowserSession",
308
303
  "SyncBrowserSession",
309
- "Codec",
310
- "Auth",
311
- # factory — нейтральный выбор транспорта/браузера по роли (Enum → фабрика → реестр)
312
304
  "BrowserEngine",
313
305
  "BrowserProvider",
314
306
  "AutomationDriver",
315
307
  "BrowserOptions",
316
308
  "BrowserSessionSettings",
317
- "make_transport",
318
- "register_transport",
319
- "create_request_executor",
320
- "register_request_provider",
321
309
  "make_browser_backend",
322
310
  "register_browser_backend",
323
311
  "create_browser_session",
324
312
  "register_browser_provider",
313
+ "sessions_home",
314
+ "browser_profile_dir",
315
+ "shared_google_profile_dir",
316
+ "make_profile_dir_resolver",
317
+ "make_session_store",
318
+ "WarmupTokenMinter",
319
+ "TokenHarvest",
320
+ # auth + refresh: стратегии авторизации + проактивное обновление сессии
321
+ "AuthMode",
322
+ "Auth",
325
323
  "Refreshable",
326
324
  "ProactiveRefreshable",
327
325
  "SyncRefreshable",
328
326
  "SyncProactiveRefreshable",
329
- "ErrorMapper",
330
- "Paginator",
327
+ "TokenAuth",
328
+ "CookieSessionAuth",
329
+ "cookies_with_meta_from_state",
330
+ "CategoryCookieAuth",
331
+ "CategoryPolicy",
332
+ "LazyRefreshPolicy",
333
+ "FreshnessOutcome",
334
+ "COOKIE_REFRESH_META_KEY",
335
+ "Cookie",
336
+ "CookieCategory",
337
+ "CookieClassifier",
338
+ "CategoryFreshness",
339
+ "cookies_from_state",
340
+ "flat_cookies",
341
+ "to_state_cookies",
342
+ "merge_state",
343
+ "earliest_expiry",
344
+ "assess_freshness",
345
+ "DEFAULT_MINT_NAMES",
346
+ "DEFAULT_SESSION_NAMES",
347
+ "OAuth2Auth",
348
+ "BrowserLoginAuth",
349
+ "CsrfHeaderAuth",
350
+ "CSRF_DEFAULT_HEADER",
351
+ "extract_token_from_text",
352
+ "dump_settings",
353
+ "load_settings",
354
+ "encrypt_settings",
355
+ "decrypt_settings",
356
+ "RotatingAuth",
357
+ "Keepalive",
358
+ "RefreshableChain",
359
+ "DEFAULT_ROTATE_INTERVAL",
360
+ # sessions + secrets: envelope-хранилище сессий + креды + keyring-стор
361
+ "SessionRef",
362
+ "Creds",
331
363
  "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
364
  "SessionStore",
353
365
  "SessionStoreError",
354
366
  "KekUnavailableError",
355
367
  "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-ответ → доменная ошибка
368
+ "SecretStore",
369
+ # errors + errmap: единая иерархия ERROR-HUB + карта ответ→ошибка
370
+ "CliError",
371
+ "ApiError",
372
+ "AuthRequired",
373
+ "SessionExpired",
374
+ "RateLimited",
375
+ "ValidationError",
376
+ "NotImplementedYet",
377
+ "NotFoundError",
378
+ "ServerError",
379
+ "TransportError",
380
+ "Blocked",
381
+ "RETRYABLE",
382
+ "AdapterError",
383
+ "NotFound",
384
+ "GraphQLError",
385
+ "ErrorMapper",
407
386
  "ErrorMap",
408
387
  "ErrorMapBuilder",
409
388
  "BodyRule",
@@ -411,7 +390,27 @@ __all__ = [
411
390
  "AuthExpired",
412
391
  "build_error_map",
413
392
  "DEFAULT_ERROR_MAP",
414
- # pagination (W4): листатель ресурса (offset/cursor/page) tweepy-стиля
393
+ # reliability: retry / limit / pool / checkpoint
394
+ "RetryPolicy",
395
+ "DEFAULT_RETRY",
396
+ "SimpleRetryPolicy",
397
+ "DEFAULT_SIMPLE_RETRY",
398
+ "LimitWindow",
399
+ "LimitPolicy",
400
+ "LimitScope",
401
+ "RateLimiter",
402
+ "LimitSpec",
403
+ "QuotaScope",
404
+ "QuotaInfo",
405
+ "SessionPool",
406
+ "PoolChoice",
407
+ "DEFAULT_SKIP_STATUSES",
408
+ "Checkpoint",
409
+ "JsonlSink",
410
+ "RunMetrics",
411
+ # pagination / bulk / upload: листание ресурса + батчи + resumable-догрузка
412
+ "PaginationMode",
413
+ "Paginator",
415
414
  "CursorPaginator",
416
415
  "PageParams",
417
416
  "DEFAULT_PAGE_PARAMS",
@@ -420,40 +419,52 @@ __all__ = [
420
419
  "default_extract_items",
421
420
  "default_extract_cursor",
422
421
  "with_page_params",
423
- # pagination flat-page (W8): offset/total на верхнем уровне тела
424
422
  "FlatPage",
425
423
  "parse_flat_page",
426
424
  "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
425
  "BulkOutcome",
451
426
  "BulkOperationError",
452
427
  "BulkError",
453
428
  "BulkOperationResult",
454
429
  "run_bulk",
455
430
  "run_bulk_async",
456
- # redaction: маски секретов + truncation для HTTP-заголовков/body (audit/логи)
431
+ "ChunkedUploader",
432
+ "UploadResult",
433
+ # orchestration / protocols / entities: онбординг/health + нейтральные data-классы
434
+ "LoginMode",
435
+ "LoginRequirements",
436
+ "InteractiveFlow",
437
+ "OnboardingProtocol",
438
+ "HealthState",
439
+ "HealthStatus",
440
+ "HealthProtocol",
441
+ "Session",
442
+ "SessionChanges",
443
+ "SessionContext",
444
+ "HealthReport",
445
+ # rpc / stream / graphql: codec-слой + persistent-транспорты + GraphQL-клиент
446
+ "StreamTransport",
447
+ "JsonCodec",
448
+ "PrefixedJsonCodec",
449
+ "RpcClient",
450
+ "StubStreamTransport",
451
+ "WebSocketsStreamTransport",
452
+ "StreamClosedError",
453
+ "GraphQLClient",
454
+ # blocks / forms / windows / redaction / config: примитивы тел, окна, маски, утили путей
455
+ "blocks",
456
+ "text_block",
457
+ "block_end",
458
+ "header_block",
459
+ "list_item_block",
460
+ "paragraphs",
461
+ "decode_text_block",
462
+ "FormCodec",
463
+ "Window",
464
+ "RollingWindow",
465
+ "CalendarWindow",
466
+ "FixedWindow",
467
+ "parse_window",
457
468
  "SECRET_MASK",
458
469
  "HEADER_BLACKLIST",
459
470
  "BODY_FIELD_PATTERNS",
@@ -461,4 +472,12 @@ __all__ = [
461
472
  "sanitize_body",
462
473
  "truncate_body",
463
474
  "excerpt_response_body",
475
+ "deep_merge",
476
+ "interpolate_env",
477
+ "load_dotenv",
478
+ "slugify",
479
+ "normalize_account_id",
480
+ "atomic_write_text",
481
+ "chmod_600",
482
+ "AppPaths",
464
483
  ]
@@ -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(
@@ -121,6 +121,17 @@ def _cookies_from_state(state: Mapping[str, Any]) -> dict[str, str]:
121
121
  return {str(k): str(v) for k, v in flat.items() if k != "origins"}
122
122
 
123
123
 
124
+ def cookies_with_meta_from_state(state: Mapping[str, Any]) -> list[Any]:
125
+ """Как `_cookies_from_state`, но СОХРАНЯЕТ domain/expires/категорию (`list[cookies.Cookie]`).
126
+
127
+ Аддитивный сосед: `_cookies_from_state`/`CookieSessionAuth` теряют срок и не
128
+ категоризируют — здесь нужно для ленивого TTL-обновления (`cookie_refresh`).
129
+ """
130
+ from .cookies import cookies_from_state
131
+
132
+ return cookies_from_state(state)
133
+
134
+
124
135
  class CookieSessionAuth:
125
136
  """Cookie-сессия: cookies из `storage_state` → заголовок ``Cookie`` (`AuthMode.COOKIE`).
126
137
 
@@ -55,9 +55,23 @@ from ._engine import (
55
55
  _load_async_playwright,
56
56
  _resolve_patchright,
57
57
  camoufox_available,
58
+ nodriver_available,
58
59
  playwright_available,
59
60
  )
60
61
  from .camoufox import CamoufoxBackend, SyncCamoufoxBackend
62
+ from .nodriver import NodriverBackend
63
+ from .persistent import PersistentChromiumBackend
64
+ from .capture_tap import (
65
+ CAPTURE_ENGINES,
66
+ NormalizedAction,
67
+ NormalizedFailure,
68
+ NormalizedRequest,
69
+ NormalizedResponse,
70
+ NormalizedWsFrame,
71
+ TapHandle,
72
+ attach_capture_tap,
73
+ build_capture_backend,
74
+ )
61
75
  from .geometry import (
62
76
  DEFAULT_ANTI_BOT_ARGS,
63
77
  detect_work_area,
@@ -807,7 +821,20 @@ __all__ = [
807
821
  "CamoufoxBackend",
808
822
  "SyncCamoufoxBackend",
809
823
  "camoufox_available",
824
+ "NodriverBackend",
825
+ "nodriver_available",
826
+ "PersistentChromiumBackend",
810
827
  "CdpChromeBackend",
828
+ # capture_tap: нормализованный event-tap над любым движком
829
+ "attach_capture_tap",
830
+ "build_capture_backend",
831
+ "CAPTURE_ENGINES",
832
+ "TapHandle",
833
+ "NormalizedRequest",
834
+ "NormalizedResponse",
835
+ "NormalizedFailure",
836
+ "NormalizedWsFrame",
837
+ "NormalizedAction",
811
838
  "detect_work_area",
812
839
  "find_chrome_exe",
813
840
  "is_session_dead",
@@ -54,6 +54,17 @@ def camoufox_available() -> bool:
54
54
  return importlib.util.find_spec("camoufox") is not None
55
55
 
56
56
 
57
+ def nodriver_available() -> bool:
58
+ """Установлен ли nodriver (undetected Chromium) — без его запуска.
59
+
60
+ Для `skipif` в тестах и выбора движка (nodriver против CDP-Chrome/CamouFox)
61
+ без побочных эффектов. Extra `[nodriver]`; браузер Chromium nodriver тянет сам.
62
+ """
63
+ import importlib.util
64
+
65
+ return importlib.util.find_spec("nodriver") is not None
66
+
67
+
57
68
  # Сентинел «легаси-параметр не передан явно»: отличает дефолт от осознанного
58
69
  # `use_patchright=...`, чтобы DeprecationWarning вылезал ТОЛЬКО на явную передачу.
59
70
  _LEGACY_UNSET: Any = object()