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.
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/PKG-INFO +3 -1
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/__init__.py +167 -148
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/antibot/__init__.py +2 -1
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/antibot/cdp.py +25 -3
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/auth.py +11 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/browser/__init__.py +27 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/browser/_engine.py +11 -0
- s_librarykit-0.5.0/librarykit/browser/capture_tap.py +590 -0
- s_librarykit-0.5.0/librarykit/browser/nodriver.py +178 -0
- s_librarykit-0.5.0/librarykit/browser/persistent.py +177 -0
- s_librarykit-0.5.0/librarykit/cookie_refresh.py +233 -0
- s_librarykit-0.5.0/librarykit/cookies.py +270 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/entities.py +27 -2
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/factory.py +28 -3
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/orchestration/__init__.py +1 -1
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/orchestration/health.py +8 -8
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/pyproject.toml +4 -1
- s_librarykit-0.5.0/tests/test_capture_tap.py +185 -0
- s_librarykit-0.5.0/tests/test_cookie_refresh.py +166 -0
- s_librarykit-0.5.0/tests/test_cookies.py +86 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_factory.py +1 -1
- s_librarykit-0.5.0/tests/test_nodriver_backend.py +76 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_orchestration.py +21 -4
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/.gitignore +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/.gitlab-ci.yml +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/AGENTS.md +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/CHANGELOG.md +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/LICENSE +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/README.md +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/docs/superpowers/specs/2026-06-24-unified-sessions-design.md +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/antibot/_helpers.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/antibot/curl_cffi.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/antibot/page_evaluate.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/antibot/warmup_minter.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/blocks.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/browser/camoufox.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/browser/geometry.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/browser/launchers.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/browser/state.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/bulk.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/checkpoint.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/config_util.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/contract.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/enums.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/errmap.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/errors.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/forms.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/graphql.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/limit.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/orchestration/onboarding.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/orchestration/session_loader.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/pagination.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/pool.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/ports.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/protocols.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/redaction.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/refresh.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/retry.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/rpc.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/secret_store.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/session_bridge.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/session_paths.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/sessions/__init__.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/sessions/_const.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/sessions/_fsutil.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/stream.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/transport/__init__.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/transport/_helpers.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/transport/http_client.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/transport/permissive.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/transport/rest_client.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/transport/transport_http.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/upload.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/librarykit/windows.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/conftest.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_antibot.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_auth.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_blocks.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_browser.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_bulk.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_checkpoint.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_config_util.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_errmap.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_errors.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_forms.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_graphql.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_limit.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_limit_contract.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_pagination.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_permissive_http.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_pool.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_redaction.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_refresh.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_retry.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_rpc.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_session_bridge.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_session_paths.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_sessions.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_stream.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_transport_client.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_transport_rest.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_transport_sync.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_upload.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_warmup_minter.py +0 -0
- {s_librarykit-0.3.0 → s_librarykit-0.5.0}/tests/test_windows.py +0 -0
- {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
|
+
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.
|
|
274
|
+
__version__ = "0.4.0"
|
|
253
275
|
|
|
254
276
|
__all__ = [
|
|
255
277
|
"__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",
|
|
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
|
-
"
|
|
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
|
-
"
|
|
330
|
-
"
|
|
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
|
-
|
|
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-ответ → доменная ошибка
|
|
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
|
-
#
|
|
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
|
-
|
|
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 — роль «умеет выполнить запрос в браузере»
|
|
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(
|
|
@@ -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()
|