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.
Files changed (130) hide show
  1. package/README.md +96 -36
  2. package/node_modules/pi-lean-portal/AGENTS.md +146 -4
  3. package/node_modules/pi-lean-portal/README.md +112 -50
  4. package/node_modules/pi-lean-portal/__tests__/browser-data.test.ts +124 -0
  5. package/node_modules/pi-lean-portal/__tests__/browser-inspect.test.ts +192 -16
  6. package/node_modules/pi-lean-portal/__tests__/browser-toggle-profile.test.ts +3 -3
  7. package/node_modules/pi-lean-portal/__tests__/browser-toggle.test.ts +49 -35
  8. package/node_modules/pi-lean-portal/__tests__/chromium-py-persistence.test.ts +21 -195
  9. package/node_modules/pi-lean-portal/__tests__/chromium-py.test.ts +17 -81
  10. package/node_modules/pi-lean-portal/__tests__/chromium.test.ts +25 -0
  11. package/node_modules/pi-lean-portal/__tests__/contributed/invisible-py/invisible-py.test.ts +299 -0
  12. package/node_modules/pi-lean-portal/__tests__/cookie-persistence.test.ts +22 -182
  13. package/node_modules/pi-lean-portal/__tests__/fetch-backend.test.ts +1 -1
  14. package/node_modules/pi-lean-portal/__tests__/firefox-py-persistence.test.ts +21 -184
  15. package/node_modules/pi-lean-portal/__tests__/firefox-py.test.ts +17 -101
  16. package/node_modules/pi-lean-portal/__tests__/firefox.test.ts +2 -18
  17. package/node_modules/pi-lean-portal/__tests__/helpers/__pycache__/mock-python-bridge.cpython-313.pyc +0 -0
  18. package/node_modules/pi-lean-portal/__tests__/helpers/create-py-backend-harness.ts +105 -0
  19. package/node_modules/pi-lean-portal/__tests__/helpers/load-plugin-config-from-file.ts +53 -0
  20. package/node_modules/pi-lean-portal/__tests__/helpers/mock-plugin.ts +11 -7
  21. package/node_modules/pi-lean-portal/__tests__/helpers/mock-python-bridge.py +4 -0
  22. package/node_modules/pi-lean-portal/__tests__/helpers/persistence-suite.ts +218 -0
  23. package/node_modules/pi-lean-portal/__tests__/helpers/plugin-contract.ts +198 -318
  24. package/node_modules/pi-lean-portal/__tests__/helpers/probe-user-backend.ts +198 -0
  25. package/node_modules/pi-lean-portal/__tests__/helpers/test-server.ts +14 -0
  26. package/node_modules/pi-lean-portal/__tests__/plugin-config-browser.test.ts +150 -15
  27. package/node_modules/pi-lean-portal/__tests__/plugin-loading.test.ts +120 -18
  28. package/node_modules/pi-lean-portal/__tests__/plugin-registry.test.ts +6 -67
  29. package/node_modules/pi-lean-portal/__tests__/probe-user-backend.test.ts +236 -0
  30. package/node_modules/pi-lean-portal/__tests__/python-adapter.test.ts +401 -11
  31. package/node_modules/pi-lean-portal/__tests__/router-session.test.ts +4 -1
  32. package/node_modules/pi-lean-portal/__tests__/run-contributed-suites.test.ts +318 -0
  33. package/node_modules/pi-lean-portal/__tests__/session-manager.test.ts +50 -0
  34. package/node_modules/pi-lean-portal/__tests__/snapshot-cache.test.ts +2 -2
  35. package/node_modules/pi-lean-portal/__tests__/url-safety.test.ts +1 -1
  36. package/node_modules/pi-lean-portal/backends/chromium/index.ts +5 -13
  37. package/node_modules/pi-lean-portal/backends/chromium-py/__pycache__/bridge.cpython-313.pyc +0 -0
  38. package/node_modules/pi-lean-portal/backends/chromium-py/bridge.py +0 -2
  39. package/node_modules/pi-lean-portal/backends/firefox/index.ts +6 -5
  40. package/node_modules/pi-lean-portal/backends/firefox-py/__pycache__/bridge.cpython-313.pyc +0 -0
  41. package/node_modules/pi-lean-portal/backends/firefox-py/bridge.py +7 -6
  42. package/node_modules/pi-lean-portal/backends/playwright-base/playwright-plugin.ts +241 -398
  43. package/node_modules/pi-lean-portal/backends/python-adapter.ts +182 -83
  44. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__init__.py +1 -42
  45. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/__init__.cpython-312.pyc +0 -0
  46. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/__init__.cpython-313.pyc +0 -0
  47. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/accessibility.cpython-312.pyc +0 -0
  48. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/accessibility.cpython-313.pyc +0 -0
  49. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/bot_detection.cpython-312.pyc +0 -0
  50. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/bot_detection.cpython-313.pyc +0 -0
  51. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/bridge.cpython-312.pyc +0 -0
  52. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/bridge.cpython-313.pyc +0 -0
  53. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/browser_data.cpython-312.pyc +0 -0
  54. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/browser_data.cpython-313.pyc +0 -0
  55. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/patch_playwright.cpython-312.pyc +0 -0
  56. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/patch_playwright.cpython-313.pyc +0 -0
  57. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/playwright_base.cpython-312.pyc +0 -0
  58. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/playwright_base.cpython-313.pyc +0 -0
  59. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/transport.cpython-312.pyc +0 -0
  60. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/transport.cpython-313.pyc +0 -0
  61. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/accessibility.py +12 -147
  62. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/bot_detection.py +12 -37
  63. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/bridge.py +249 -322
  64. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/browser_data.py +92 -0
  65. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/patch_playwright.py +321 -0
  66. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/playwright_base.py +511 -299
  67. package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/conftest.cpython-313-pytest-9.1.1.pyc +0 -0
  68. 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
  69. package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_accessibility.cpython-313.pyc +0 -0
  70. package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_bot_detection.cpython-313-pytest-9.1.1.pyc +0 -0
  71. package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_bot_detection.cpython-313.pyc +0 -0
  72. package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_browser_data.cpython-313-pytest-9.1.1.pyc +0 -0
  73. package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_browser_data.cpython-313.pyc +0 -0
  74. 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
  75. 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
  76. package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_playwright_base_quirks.cpython-313-pytest-9.1.1.pyc +0 -0
  77. package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_playwright_base_quirks.cpython-313.pyc +0 -0
  78. package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_py_bridges.cpython-313-pytest-9.1.1.pyc +0 -0
  79. 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
  80. package/node_modules/pi-lean-portal/backends/python-base/tests/conftest.py +95 -0
  81. package/node_modules/pi-lean-portal/backends/python-base/tests/test_accessibility.py +8 -132
  82. package/node_modules/pi-lean-portal/backends/python-base/tests/test_bot_detection.py +8 -147
  83. package/node_modules/pi-lean-portal/backends/python-base/tests/test_browser_data.py +131 -0
  84. package/node_modules/pi-lean-portal/backends/python-base/tests/test_playwright_base_quirks.py +768 -0
  85. package/node_modules/pi-lean-portal/backends/python-base/tests/test_py_bridges.py +198 -0
  86. package/node_modules/pi-lean-portal/browser-toggle.ts +33 -69
  87. package/node_modules/pi-lean-portal/contributed/CHOOSING.md +126 -0
  88. package/node_modules/pi-lean-portal/contributed/README.md +304 -0
  89. package/node_modules/pi-lean-portal/contributed/camoufox-py/bridge.py +216 -0
  90. package/node_modules/pi-lean-portal/contributed/invisible-py/__pycache__/bridge.cpython-313.pyc +0 -0
  91. package/node_modules/pi-lean-portal/contributed/invisible-py/bridge.py +434 -0
  92. package/node_modules/pi-lean-portal/core/fetch-backend.ts +0 -5
  93. package/node_modules/pi-lean-portal/core/plugin-api.ts +6 -33
  94. package/node_modules/pi-lean-portal/core/plugin-config.ts +75 -58
  95. package/node_modules/pi-lean-portal/core/plugin-registry.ts +11 -49
  96. package/node_modules/pi-lean-portal/core/router.ts +59 -98
  97. package/node_modules/pi-lean-portal/core/shared/accessibility-tree.ts +10 -143
  98. package/node_modules/pi-lean-portal/core/shared/bot-detection.ts +31 -77
  99. package/node_modules/pi-lean-portal/core/shared/browser-data.json +183 -0
  100. package/node_modules/pi-lean-portal/core/shared/browser-data.ts +50 -0
  101. package/node_modules/pi-lean-portal/core/shared/browser-events.ts +6 -6
  102. package/node_modules/pi-lean-portal/core/shared/dom-extractor.ts +97 -36
  103. package/node_modules/pi-lean-portal/core/shared/nav-settle.ts +12 -15
  104. package/node_modules/pi-lean-portal/core/shared/paths.ts +3 -0
  105. package/node_modules/pi-lean-portal/core/shared/session-manager.ts +7 -21
  106. package/node_modules/pi-lean-portal/{verify-ship-manifest.ts → core/shared/ship-manifest.ts} +34 -9
  107. package/node_modules/pi-lean-portal/core/shared/snapshot-cache.ts +7 -6
  108. package/node_modules/pi-lean-portal/core/shared/storage-state.ts +40 -9
  109. package/node_modules/pi-lean-portal/index.ts +42 -7
  110. package/node_modules/pi-lean-portal/package.json +8 -3
  111. package/node_modules/pi-lean-portal/ship-manifest.test.ts +8 -3
  112. package/node_modules/pi-lean-portal/tools/browser-inspect.ts +2 -6
  113. package/node_modules/pi-lean-portal/tools/browser-navigate.ts +7 -5
  114. package/node_modules/pi-lean-portal/tools/browser-snapshot.ts +2 -5
  115. package/node_modules/pi-lean-portal/tools/utils.ts +22 -4
  116. package/node_modules/pi-lean-portal/tools/web-fetch.ts +3 -4
  117. package/node_modules/pi-lean-search/README.md +6 -2
  118. package/node_modules/pi-lean-search/__tests__/web-search.test.ts +11 -0
  119. package/node_modules/pi-lean-search/index.ts +4 -21
  120. package/node_modules/pi-lean-search/package.json +2 -2
  121. package/node_modules/pi-lean-search/verify-ship-manifest.ts +6 -92
  122. package/node_modules/pi-lean-search/web-search-tool.ts +19 -13
  123. package/package.json +4 -4
  124. package/node_modules/pi-lean-portal/__tests__/helpers/reddit-fixture.ts +0 -264
  125. package/node_modules/pi-lean-portal/__tests__/helpers/toggle-test-utils.ts +0 -31
  126. package/node_modules/pi-lean-portal/__tests__/reddit-dialog.test.ts +0 -302
  127. package/node_modules/pi-lean-portal/backends/python-base/pi_browser_bridge/__pycache__/occlusion.cpython-313.pyc +0 -0
  128. package/node_modules/pi-lean-portal/backends/python-base/tests/__pycache__/test_bot_detection.cpython-313-pytest-9.1.0.pyc +0 -0
  129. package/node_modules/pi-lean-portal/backends/python-base/tests/test_chromium_py_bridge.py +0 -281
  130. 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
- "button",
20
- "link",
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 (same mapping as TypeScript) ───────────────—──────────
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 _ROLE_ICONS.get(role, "")
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 live here as a single source of
10
- truth for all Python-based browser backends.
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
- #: Mirror of TypeScript bot-detection.ts BLOCK_SIGNALS.
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
- #: Mirror of TypeScript bot-detection.ts BODY_ONLY_SIGNALS.
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 — checked against raw body text.
44
- #: Mirror of TypeScript bot-detection.ts BODY_ONLY_PATTERNS.
45
- _BODY_ONLY_PATTERNS: tuple[re.Pattern, ...] = (
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 (Python-only enhancement).
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: