pi-lean-dimension 0.1.0 → 0.2.0
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.
- package/README.md +96 -36
- package/node_modules/pi-lean-portal/AGENTS.md +146 -4
- package/node_modules/pi-lean-portal/README.md +112 -50
- package/node_modules/pi-lean-portal/__tests__/browser-data.test.ts +124 -0
- package/node_modules/pi-lean-portal/__tests__/browser-inspect.test.ts +192 -16
- package/node_modules/pi-lean-portal/__tests__/browser-toggle-profile.test.ts +3 -3
- package/node_modules/pi-lean-portal/__tests__/browser-toggle.test.ts +49 -35
- package/node_modules/pi-lean-portal/__tests__/chromium-py-persistence.test.ts +21 -195
- package/node_modules/pi-lean-portal/__tests__/chromium-py.test.ts +17 -81
- package/node_modules/pi-lean-portal/__tests__/chromium.test.ts +25 -0
- package/node_modules/pi-lean-portal/__tests__/contributed/invisible-py/invisible-py.test.ts +299 -0
- package/node_modules/pi-lean-portal/__tests__/cookie-persistence.test.ts +22 -182
- package/node_modules/pi-lean-portal/__tests__/fetch-backend.test.ts +1 -1
- package/node_modules/pi-lean-portal/__tests__/firefox-py-persistence.test.ts +21 -184
- package/node_modules/pi-lean-portal/__tests__/firefox-py.test.ts +17 -101
- package/node_modules/pi-lean-portal/__tests__/firefox.test.ts +2 -18
- package/node_modules/pi-lean-portal/__tests__/helpers/__pycache__/mock-python-bridge.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/__tests__/helpers/create-py-backend-harness.ts +105 -0
- package/node_modules/pi-lean-portal/__tests__/helpers/load-plugin-config-from-file.ts +53 -0
- package/node_modules/pi-lean-portal/__tests__/helpers/mock-plugin.ts +11 -7
- package/node_modules/pi-lean-portal/__tests__/helpers/mock-python-bridge.py +4 -0
- package/node_modules/pi-lean-portal/__tests__/helpers/persistence-suite.ts +218 -0
- package/node_modules/pi-lean-portal/__tests__/helpers/plugin-contract.ts +198 -318
- package/node_modules/pi-lean-portal/__tests__/helpers/probe-user-backend.ts +198 -0
- package/node_modules/pi-lean-portal/__tests__/helpers/test-server.ts +14 -0
- package/node_modules/pi-lean-portal/__tests__/plugin-config-browser.test.ts +150 -15
- package/node_modules/pi-lean-portal/__tests__/plugin-loading.test.ts +120 -18
- package/node_modules/pi-lean-portal/__tests__/plugin-registry.test.ts +6 -67
- package/node_modules/pi-lean-portal/__tests__/probe-user-backend.test.ts +236 -0
- package/node_modules/pi-lean-portal/__tests__/python-adapter.test.ts +401 -11
- package/node_modules/pi-lean-portal/__tests__/router-session.test.ts +4 -1
- package/node_modules/pi-lean-portal/__tests__/run-contributed-suites.test.ts +318 -0
- package/node_modules/pi-lean-portal/__tests__/session-manager.test.ts +50 -0
- package/node_modules/pi-lean-portal/__tests__/snapshot-cache.test.ts +2 -2
- package/node_modules/pi-lean-portal/__tests__/url-safety.test.ts +1 -1
- package/node_modules/pi-lean-portal/backends/chromium/index.ts +5 -13
- package/node_modules/pi-lean-portal/backends/chromium-py/__pycache__/bridge.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/chromium-py/bridge.py +0 -2
- package/node_modules/pi-lean-portal/backends/firefox/index.ts +6 -5
- package/node_modules/pi-lean-portal/backends/firefox-py/__pycache__/bridge.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/firefox-py/bridge.py +7 -6
- package/node_modules/pi-lean-portal/backends/playwright-base/playwright-plugin.ts +241 -398
- package/node_modules/pi-lean-portal/backends/python-adapter.ts +182 -83
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__init__.py +1 -42
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/__init__.cpython-312.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/__init__.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/accessibility.cpython-312.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/accessibility.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/bot_detection.cpython-312.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/bot_detection.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/bridge.cpython-312.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/bridge.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/browser_data.cpython-312.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/browser_data.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/patch_playwright.cpython-312.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/patch_playwright.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/playwright_base.cpython-312.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/playwright_base.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/transport.cpython-312.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/transport.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/accessibility.py +12 -147
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/bot_detection.py +12 -37
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/bridge.py +249 -322
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/browser_data.py +92 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/patch_playwright.py +321 -0
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/playwright_base.py +511 -299
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/conftest.cpython-313-pytest-9.1.1.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/{test_accessibility.cpython-313-pytest-9.1.0.pyc → test_accessibility.cpython-313-pytest-9.1.1.pyc} +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_accessibility.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_bot_detection.cpython-313-pytest-9.1.1.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_bot_detection.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_browser_data.cpython-313-pytest-9.1.1.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_browser_data.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/{test_chromium_py_bridge.cpython-313-pytest-9.1.0.pyc → test_chromium_py_bridge.cpython-313-pytest-9.1.1.pyc} +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/{test_firefox_py_bridge.cpython-313-pytest-9.1.0.pyc → test_firefox_py_bridge.cpython-313-pytest-9.1.1.pyc} +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_playwright_base_quirks.cpython-313-pytest-9.1.1.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_playwright_base_quirks.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_py_bridges.cpython-313-pytest-9.1.1.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/{test_transport.cpython-313-pytest-9.1.0.pyc → test_transport.cpython-313-pytest-9.1.1.pyc} +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/conftest.py +95 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/test_accessibility.py +8 -132
- package/node_modules/pi-lean-portal/backends/python-base/tests/test_bot_detection.py +8 -147
- package/node_modules/pi-lean-portal/backends/python-base/tests/test_browser_data.py +131 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/test_playwright_base_quirks.py +768 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/test_py_bridges.py +198 -0
- package/node_modules/pi-lean-portal/browser-toggle.ts +33 -69
- package/node_modules/pi-lean-portal/contributed/CHOOSING.md +126 -0
- package/node_modules/pi-lean-portal/contributed/README.md +304 -0
- package/node_modules/pi-lean-portal/contributed/camoufox-py/bridge.py +216 -0
- package/node_modules/pi-lean-portal/contributed/invisible-py/__pycache__/bridge.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/contributed/invisible-py/bridge.py +434 -0
- package/node_modules/pi-lean-portal/core/fetch-backend.ts +0 -5
- package/node_modules/pi-lean-portal/core/plugin-api.ts +6 -33
- package/node_modules/pi-lean-portal/core/plugin-config.ts +75 -58
- package/node_modules/pi-lean-portal/core/plugin-registry.ts +11 -49
- package/node_modules/pi-lean-portal/core/router.ts +59 -98
- package/node_modules/pi-lean-portal/core/shared/accessibility-tree.ts +10 -143
- package/node_modules/pi-lean-portal/core/shared/bot-detection.ts +31 -77
- package/node_modules/pi-lean-portal/core/shared/browser-data.json +183 -0
- package/node_modules/pi-lean-portal/core/shared/browser-data.ts +50 -0
- package/node_modules/pi-lean-portal/core/shared/browser-events.ts +6 -6
- package/node_modules/pi-lean-portal/core/shared/dom-extractor.ts +97 -36
- package/node_modules/pi-lean-portal/core/shared/nav-settle.ts +12 -15
- package/node_modules/pi-lean-portal/core/shared/paths.ts +3 -0
- package/node_modules/pi-lean-portal/core/shared/session-manager.ts +7 -21
- package/node_modules/pi-lean-portal/{verify-ship-manifest.ts → core/shared/ship-manifest.ts} +34 -9
- package/node_modules/pi-lean-portal/core/shared/snapshot-cache.ts +7 -6
- package/node_modules/pi-lean-portal/core/shared/storage-state.ts +40 -9
- package/node_modules/pi-lean-portal/index.ts +42 -7
- package/node_modules/pi-lean-portal/package.json +8 -3
- package/node_modules/pi-lean-portal/ship-manifest.test.ts +8 -3
- package/node_modules/pi-lean-portal/tools/browser-inspect.ts +2 -6
- package/node_modules/pi-lean-portal/tools/browser-navigate.ts +7 -5
- package/node_modules/pi-lean-portal/tools/browser-snapshot.ts +2 -5
- package/node_modules/pi-lean-portal/tools/utils.ts +22 -4
- package/node_modules/pi-lean-portal/tools/web-fetch.ts +3 -4
- package/node_modules/pi-lean-search/README.md +6 -2
- package/node_modules/pi-lean-search/__tests__/web-search.test.ts +11 -0
- package/node_modules/pi-lean-search/index.ts +4 -21
- package/node_modules/pi-lean-search/package.json +2 -2
- package/node_modules/pi-lean-search/verify-ship-manifest.ts +6 -92
- package/node_modules/pi-lean-search/web-search-tool.ts +19 -13
- package/package.json +4 -4
- package/node_modules/pi-lean-portal/__tests__/helpers/reddit-fixture.ts +0 -264
- package/node_modules/pi-lean-portal/__tests__/helpers/toggle-test-utils.ts +0 -31
- package/node_modules/pi-lean-portal/__tests__/reddit-dialog.test.ts +0 -302
- package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/occlusion.cpython-313.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_bot_detection.cpython-313-pytest-9.1.0.pyc +0 -0
- package/node_modules/pi-lean-portal/backends/python-base/tests/test_chromium_py_bridge.py +0 -281
- package/node_modules/pi-lean-portal/backends/python-base/tests/test_firefox_py_bridge.py +0 -212
|
@@ -7,91 +7,28 @@ parsed nodes so the TypeScript adapter can map interactions back via
|
|
|
7
7
|
get_by_role().
|
|
8
8
|
|
|
9
9
|
Mirrors the logic in core/shared/accessibility-tree.ts.
|
|
10
|
+
|
|
11
|
+
Role sets and icons are loaded from the shared ``browser-data.json``
|
|
12
|
+
— the same file used by the TypeScript side so the two
|
|
13
|
+
implementations never drift.
|
|
10
14
|
"""
|
|
11
15
|
|
|
12
16
|
import re
|
|
13
17
|
from dataclasses import dataclass, field
|
|
14
18
|
from typing import Optional
|
|
15
19
|
|
|
20
|
+
from .browser_data import ACCESSIBILITY
|
|
21
|
+
|
|
16
22
|
# ─── Role classification sets ─────────────────────────────────────────
|
|
17
23
|
|
|
18
|
-
INTERACTIVE_ROLES: set[str] =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"textbox",
|
|
22
|
-
"searchbox",
|
|
23
|
-
"combobox",
|
|
24
|
-
"checkbox",
|
|
25
|
-
"radio",
|
|
26
|
-
"heading",
|
|
27
|
-
"listbox",
|
|
28
|
-
"option",
|
|
29
|
-
"menuitem",
|
|
30
|
-
"menuitemcheckbox",
|
|
31
|
-
"menuitemradio",
|
|
32
|
-
"tab",
|
|
33
|
-
"treeitem",
|
|
34
|
-
"switch",
|
|
35
|
-
"slider",
|
|
36
|
-
"spinbutton",
|
|
37
|
-
"progressbar",
|
|
38
|
-
"meter",
|
|
39
|
-
"scrollbar",
|
|
40
|
-
"gridcell",
|
|
41
|
-
"cell",
|
|
42
|
-
"columnheader",
|
|
43
|
-
"rowheader",
|
|
44
|
-
"tabpanel",
|
|
45
|
-
"img",
|
|
46
|
-
"figure",
|
|
47
|
-
"listitem",
|
|
48
|
-
"dialog",
|
|
49
|
-
"alertdialog",
|
|
50
|
-
"tooltip",
|
|
51
|
-
"navigation",
|
|
52
|
-
"banner",
|
|
53
|
-
"form",
|
|
54
|
-
"search",
|
|
55
|
-
"toolbar",
|
|
56
|
-
"menu",
|
|
57
|
-
"menubar",
|
|
58
|
-
"note",
|
|
59
|
-
"alert",
|
|
60
|
-
"status",
|
|
61
|
-
"list",
|
|
62
|
-
"table",
|
|
63
|
-
"grid",
|
|
64
|
-
"treegrid",
|
|
65
|
-
"article",
|
|
66
|
-
"section",
|
|
67
|
-
"blockquote",
|
|
68
|
-
"code",
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
INFORMATIONAL_ROLES: set[str] = {
|
|
72
|
-
"paragraph",
|
|
73
|
-
"text",
|
|
74
|
-
"group",
|
|
75
|
-
"region",
|
|
76
|
-
"main",
|
|
77
|
-
"complementary",
|
|
78
|
-
"contentinfo",
|
|
79
|
-
"definition",
|
|
80
|
-
"term",
|
|
81
|
-
"math",
|
|
82
|
-
"marquee",
|
|
83
|
-
"timer",
|
|
84
|
-
"log",
|
|
85
|
-
"deletion",
|
|
86
|
-
"insertion",
|
|
87
|
-
"mark",
|
|
88
|
-
"suggestion",
|
|
89
|
-
"comment",
|
|
90
|
-
}
|
|
24
|
+
INTERACTIVE_ROLES: set[str] = set(ACCESSIBILITY["interactiveRoles"])
|
|
25
|
+
|
|
26
|
+
INFORMATIONAL_ROLES: set[str] = set(ACCESSIBILITY["informationalRoles"])
|
|
91
27
|
|
|
92
28
|
|
|
93
29
|
# ─── Data structures ──────────────────────────────────────────────────
|
|
94
30
|
|
|
31
|
+
|
|
95
32
|
@dataclass
|
|
96
33
|
class AriaCachedNode:
|
|
97
34
|
ref: str
|
|
@@ -113,82 +50,10 @@ class AriaParseResult:
|
|
|
113
50
|
count: int = 0
|
|
114
51
|
|
|
115
52
|
|
|
116
|
-
# ─── Role icons
|
|
117
|
-
|
|
118
|
-
_ROLE_ICONS: dict[str, str] = {
|
|
119
|
-
"button": "\U0001f518 ", # 🔘
|
|
120
|
-
"link": "\U0001f517 ", # 🔗
|
|
121
|
-
"textbox": "\U0001f4dd ", # 📝
|
|
122
|
-
"searchbox": "\U0001f50d ", # 🔍
|
|
123
|
-
"combobox": "\U0001f4cb ", # 📋
|
|
124
|
-
"checkbox": "\u2611 ", # ☑
|
|
125
|
-
"radio": "\u25cb ", # ○
|
|
126
|
-
"heading": "\U0001f4cc ", # 📌
|
|
127
|
-
"listbox": "\U0001f4cb ", # 📋
|
|
128
|
-
"option": "\u2022 ", # •
|
|
129
|
-
"tab": "\U0001f4d1 ", # 📑
|
|
130
|
-
"switch": "\U0001f500 ", # 🔀
|
|
131
|
-
"slider": "\U0001f527 ", # 🔧
|
|
132
|
-
"spinbutton": "\U0001f522 ", # 🔢
|
|
133
|
-
"img": "\U0001f5bc ", # 🖼
|
|
134
|
-
"figure": "\U0001f5bc ", # 🖼
|
|
135
|
-
"table": "\U0001f4ca ", # 📊
|
|
136
|
-
"grid": "\U0001f4ca ", # 📊
|
|
137
|
-
"gridcell": "\u25ab ", # ▫
|
|
138
|
-
"cell": "\u25ab ", # ▫
|
|
139
|
-
"dialog": "\U0001f4ac ", # 💬
|
|
140
|
-
"alertdialog": "\u26a0 ", # ⚠
|
|
141
|
-
"navigation": "\U0001f9ed ", # 🧭
|
|
142
|
-
"banner": "\U0001f4f0 ", # 📰
|
|
143
|
-
"main": "\U0001f4c4 ", # 📄
|
|
144
|
-
"complementary": "\U0001f4ce ", # 📎
|
|
145
|
-
"contentinfo": "\u2139 ", # ℹ
|
|
146
|
-
"form": "\U0001f4dd ", # 📝
|
|
147
|
-
"search": "\U0001f50d ", # 🔍
|
|
148
|
-
"group": "\U0001f4e6 ", # 📦
|
|
149
|
-
"toolbar": "\U0001f527 ", # 🔧
|
|
150
|
-
"treeitem": "\u2022 ", # •
|
|
151
|
-
"menu": "\U0001f4cb ", # 📋
|
|
152
|
-
"menubar": "\U0001f4cb ", # 📋
|
|
153
|
-
"paragraph": "\U0001f4c3 ", # 📃
|
|
154
|
-
"article": "\U0001f4f0 ", # 📰
|
|
155
|
-
"section": "\U0001f4c4 ", # 📄
|
|
156
|
-
"list": "\U0001f4cb ", # 📋
|
|
157
|
-
"listitem": "\u2022 ", # •
|
|
158
|
-
"note": "\U0001f4dd ", # 📝
|
|
159
|
-
"alert": "\U0001f514 ", # 🔔
|
|
160
|
-
"status": "\U0001f4ca ", # 📊
|
|
161
|
-
"code": "\U0001f4bb ", # 💻
|
|
162
|
-
"blockquote": "\U0001f4ac ", # 💬
|
|
163
|
-
"columnheader": "\U0001f4ca ", # 📊
|
|
164
|
-
"comment": "\U0001f4ac ", # 💬
|
|
165
|
-
"definition": "\U0001f4d6 ", # 📖
|
|
166
|
-
"deletion": "\u274c ", # ❌
|
|
167
|
-
"insertion": "\u2795 ", # ➕
|
|
168
|
-
"log": "\U0001f4cb ", # 📋
|
|
169
|
-
"mark": "\U0001f58d \ufe0f ", # 🖍️
|
|
170
|
-
"marquee": "\U0001f4dc ", # 📜
|
|
171
|
-
"math": "\U0001f9ee ", # 🧮
|
|
172
|
-
"menuitem": "\U0001f4cb ", # 📋
|
|
173
|
-
"menuitemcheckbox": "\u2611 ", # ☑
|
|
174
|
-
"menuitemradio": "\u25cb ", # ○
|
|
175
|
-
"meter": "\U0001f4ca ", # 📊
|
|
176
|
-
"progressbar": "\u23f3 ", # ⏳
|
|
177
|
-
"region": "\U0001f4e6 ", # 📦
|
|
178
|
-
"rowheader": "\U0001f4ca ", # 📊
|
|
179
|
-
"scrollbar": "\U0001f4dc ", # 📜
|
|
180
|
-
"suggestion": "\U0001f4a1 ", # 💡
|
|
181
|
-
"tabpanel": "\U0001f4d1 ", # 📑
|
|
182
|
-
"term": "\U0001f4d6 ", # 📖
|
|
183
|
-
"text": "\U0001f4dd ", # 📝
|
|
184
|
-
"timer": "\u23f1 \ufe0f ", # ⏱️
|
|
185
|
-
"tooltip": "\U0001f4a1 ", # 💡
|
|
186
|
-
"treegrid": "\U0001f4ca ", # 📊
|
|
187
|
-
}
|
|
188
|
-
|
|
53
|
+
# ─── Role icons ──────────────────────────────────────────────────────
|
|
189
54
|
|
|
190
55
|
def _role_icon(role: str) -> str:
|
|
191
|
-
return
|
|
56
|
+
return ACCESSIBILITY["roleIcons"].get(role, "")
|
|
192
57
|
|
|
193
58
|
|
|
194
59
|
def _truncate(s: str, max_len: int) -> str:
|
|
@@ -6,54 +6,29 @@ Mirrors the logic in ``core/shared/bot-detection.ts`` ``checkPage()``.
|
|
|
6
6
|
The matching *must* run in the Python process because it needs
|
|
7
7
|
``page.title()`` and ``page.evaluate()`` for body/HTML — shipping the
|
|
8
8
|
full HTML across JSON-RPC would be prohibitively expensive. However,
|
|
9
|
-
the signal lists are pure data and
|
|
10
|
-
|
|
9
|
+
the signal lists are pure data and are loaded from the shared
|
|
10
|
+
``browser-data.json`` file — the same file used by the TypeScript side
|
|
11
|
+
so the two implementations never drift.
|
|
11
12
|
"""
|
|
12
13
|
|
|
13
14
|
import re
|
|
14
15
|
from typing import Any
|
|
15
16
|
|
|
17
|
+
from .browser_data import BOT_SIGNALS
|
|
18
|
+
|
|
16
19
|
#: Block-level signals — checked against BOTH title and body text.
|
|
17
|
-
|
|
18
|
-
#: Only specific challenge phrases are included — generic single words
|
|
19
|
-
#: like "captcha", "cloudflare", "recaptcha" are excluded because they
|
|
20
|
-
#: cause false positives on legitimate pages mentioning them in passing.
|
|
21
|
-
_BLOCK_SIGNALS: tuple[str, ...] = (
|
|
22
|
-
"please verify you are human",
|
|
23
|
-
"attention required!",
|
|
24
|
-
"just a moment...",
|
|
25
|
-
"checking your browser",
|
|
26
|
-
"you have been blocked",
|
|
27
|
-
"sorry, you have been blocked",
|
|
28
|
-
"verify you are human",
|
|
29
|
-
"your request has been blocked",
|
|
30
|
-
"we are checking your browser",
|
|
31
|
-
"cf-challenge",
|
|
32
|
-
"_cf_chl_opt",
|
|
33
|
-
"cdn-cgi/challenge",
|
|
34
|
-
)
|
|
20
|
+
_BLOCK_SIGNALS: tuple[str, ...] = tuple(BOT_SIGNALS["blockSignals"])
|
|
35
21
|
|
|
36
22
|
#: Body-only string signals — high-specificity CDN patterns.
|
|
37
|
-
|
|
38
|
-
_BODY_ONLY_SIGNALS: tuple[str, ...] = (
|
|
39
|
-
"errors.edgesuite.net",
|
|
40
|
-
"you don't have permission to access",
|
|
41
|
-
)
|
|
23
|
+
_BODY_ONLY_SIGNALS: tuple[str, ...] = tuple(BOT_SIGNALS["bodyOnlySignals"])
|
|
42
24
|
|
|
43
|
-
#: Body-only regex patterns —
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
re.compile(r"reference\s*#[a-f0-9]+(?:\.[a-f0-9]+)+", re.IGNORECASE),
|
|
25
|
+
#: Body-only regex patterns — compiled from shared source strings.
|
|
26
|
+
_BODY_ONLY_PATTERNS: tuple[re.Pattern, ...] = tuple(
|
|
27
|
+
re.compile(p, re.IGNORECASE) for p in BOT_SIGNALS["bodyOnlyPatterns"]
|
|
47
28
|
)
|
|
48
29
|
|
|
49
|
-
#: HTML-level CAPTCHA/widget signals
|
|
50
|
-
_HTML_SIGNALS: tuple[str, ...] = (
|
|
51
|
-
"recaptcha",
|
|
52
|
-
"hcaptcha",
|
|
53
|
-
"turnstile",
|
|
54
|
-
"g-recaptcha",
|
|
55
|
-
"data-sitekey",
|
|
56
|
-
)
|
|
30
|
+
#: HTML-level CAPTCHA/widget signals.
|
|
31
|
+
_HTML_SIGNALS: tuple[str, ...] = tuple(BOT_SIGNALS["htmlSignals"])
|
|
57
32
|
|
|
58
33
|
|
|
59
34
|
def check_bot_detection(page: Any) -> bool:
|