ai-dev-browser 0.5.3__py3-none-any.whl

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 (155) hide show
  1. ai_dev_browser/__init__.py +110 -0
  2. ai_dev_browser/_cli.py +428 -0
  3. ai_dev_browser/_version.py +13 -0
  4. ai_dev_browser/cdp/__init__.py +6 -0
  5. ai_dev_browser/cdp/accessibility.py +668 -0
  6. ai_dev_browser/cdp/animation.py +494 -0
  7. ai_dev_browser/cdp/audits.py +1990 -0
  8. ai_dev_browser/cdp/autofill.py +292 -0
  9. ai_dev_browser/cdp/background_service.py +215 -0
  10. ai_dev_browser/cdp/bluetooth_emulation.py +626 -0
  11. ai_dev_browser/cdp/browser.py +821 -0
  12. ai_dev_browser/cdp/cache_storage.py +311 -0
  13. ai_dev_browser/cdp/cast.py +172 -0
  14. ai_dev_browser/cdp/console.py +107 -0
  15. ai_dev_browser/cdp/crash_report_context.py +55 -0
  16. ai_dev_browser/cdp/css.py +2710 -0
  17. ai_dev_browser/cdp/debugger.py +1405 -0
  18. ai_dev_browser/cdp/device_access.py +141 -0
  19. ai_dev_browser/cdp/device_orientation.py +45 -0
  20. ai_dev_browser/cdp/dom.py +2257 -0
  21. ai_dev_browser/cdp/dom_debugger.py +321 -0
  22. ai_dev_browser/cdp/dom_snapshot.py +876 -0
  23. ai_dev_browser/cdp/dom_storage.py +222 -0
  24. ai_dev_browser/cdp/emulation.py +1779 -0
  25. ai_dev_browser/cdp/event_breakpoints.py +56 -0
  26. ai_dev_browser/cdp/extensions.py +246 -0
  27. ai_dev_browser/cdp/fed_cm.py +283 -0
  28. ai_dev_browser/cdp/fetch.py +507 -0
  29. ai_dev_browser/cdp/file_system.py +115 -0
  30. ai_dev_browser/cdp/headless_experimental.py +115 -0
  31. ai_dev_browser/cdp/heap_profiler.py +401 -0
  32. ai_dev_browser/cdp/indexed_db.py +528 -0
  33. ai_dev_browser/cdp/input_.py +701 -0
  34. ai_dev_browser/cdp/inspector.py +95 -0
  35. ai_dev_browser/cdp/io.py +101 -0
  36. ai_dev_browser/cdp/layer_tree.py +464 -0
  37. ai_dev_browser/cdp/log.py +190 -0
  38. ai_dev_browser/cdp/media.py +313 -0
  39. ai_dev_browser/cdp/memory.py +305 -0
  40. ai_dev_browser/cdp/network.py +5317 -0
  41. ai_dev_browser/cdp/overlay.py +1468 -0
  42. ai_dev_browser/cdp/page.py +3970 -0
  43. ai_dev_browser/cdp/performance.py +124 -0
  44. ai_dev_browser/cdp/performance_timeline.py +200 -0
  45. ai_dev_browser/cdp/preload.py +575 -0
  46. ai_dev_browser/cdp/profiler.py +420 -0
  47. ai_dev_browser/cdp/pwa.py +278 -0
  48. ai_dev_browser/cdp/py.typed +0 -0
  49. ai_dev_browser/cdp/runtime.py +1589 -0
  50. ai_dev_browser/cdp/schema.py +50 -0
  51. ai_dev_browser/cdp/security.py +518 -0
  52. ai_dev_browser/cdp/service_worker.py +401 -0
  53. ai_dev_browser/cdp/smart_card_emulation.py +891 -0
  54. ai_dev_browser/cdp/storage.py +1573 -0
  55. ai_dev_browser/cdp/system_info.py +327 -0
  56. ai_dev_browser/cdp/target.py +822 -0
  57. ai_dev_browser/cdp/tethering.py +65 -0
  58. ai_dev_browser/cdp/tracing.py +377 -0
  59. ai_dev_browser/cdp/util.py +17 -0
  60. ai_dev_browser/cdp/web_audio.py +606 -0
  61. ai_dev_browser/cdp/web_authn.py +598 -0
  62. ai_dev_browser/cdp/web_mcp.py +219 -0
  63. ai_dev_browser/core/__init__.py +218 -0
  64. ai_dev_browser/core/_case.py +38 -0
  65. ai_dev_browser/core/_cf_template.py +84 -0
  66. ai_dev_browser/core/_element.py +431 -0
  67. ai_dev_browser/core/_tab.py +817 -0
  68. ai_dev_browser/core/_transport.py +362 -0
  69. ai_dev_browser/core/ax.py +605 -0
  70. ai_dev_browser/core/browser.py +323 -0
  71. ai_dev_browser/core/cdp.py +66 -0
  72. ai_dev_browser/core/chrome.py +253 -0
  73. ai_dev_browser/core/cloudflare.py +77 -0
  74. ai_dev_browser/core/config.py +95 -0
  75. ai_dev_browser/core/connection.py +403 -0
  76. ai_dev_browser/core/cookies.py +103 -0
  77. ai_dev_browser/core/dialog.py +165 -0
  78. ai_dev_browser/core/download.py +38 -0
  79. ai_dev_browser/core/elements.py +913 -0
  80. ai_dev_browser/core/human.py +612 -0
  81. ai_dev_browser/core/login.py +122 -0
  82. ai_dev_browser/core/mouse.py +140 -0
  83. ai_dev_browser/core/navigation.py +225 -0
  84. ai_dev_browser/core/overlays.py +148 -0
  85. ai_dev_browser/core/page.py +302 -0
  86. ai_dev_browser/core/port.py +465 -0
  87. ai_dev_browser/core/process.py +114 -0
  88. ai_dev_browser/core/snapshot.py +425 -0
  89. ai_dev_browser/core/storage.py +50 -0
  90. ai_dev_browser/core/tabs.py +125 -0
  91. ai_dev_browser/core/text_match.py +217 -0
  92. ai_dev_browser/core/window.py +84 -0
  93. ai_dev_browser/pool/__init__.py +34 -0
  94. ai_dev_browser/pool/job.py +140 -0
  95. ai_dev_browser/pool/persistence.py +154 -0
  96. ai_dev_browser/pool/pool.py +873 -0
  97. ai_dev_browser/pool/worker.py +171 -0
  98. ai_dev_browser/profile.py +107 -0
  99. ai_dev_browser/py.typed +0 -0
  100. ai_dev_browser/tools/__init__.py +9 -0
  101. ai_dev_browser/tools/_generate.py +209 -0
  102. ai_dev_browser/tools/browser_list.py +14 -0
  103. ai_dev_browser/tools/browser_start.py +14 -0
  104. ai_dev_browser/tools/browser_stop.py +14 -0
  105. ai_dev_browser/tools/cdp_send.py +14 -0
  106. ai_dev_browser/tools/click_by_html_id.py +14 -0
  107. ai_dev_browser/tools/click_by_ref.py +14 -0
  108. ai_dev_browser/tools/click_by_text.py +14 -0
  109. ai_dev_browser/tools/click_by_xpath.py +14 -0
  110. ai_dev_browser/tools/cloudflare_verify.py +14 -0
  111. ai_dev_browser/tools/cookies_list.py +14 -0
  112. ai_dev_browser/tools/cookies_load.py +14 -0
  113. ai_dev_browser/tools/cookies_save.py +14 -0
  114. ai_dev_browser/tools/dialog_respond.py +14 -0
  115. ai_dev_browser/tools/download.py +14 -0
  116. ai_dev_browser/tools/drag_by_ref.py +14 -0
  117. ai_dev_browser/tools/find_by_html_id.py +14 -0
  118. ai_dev_browser/tools/find_by_xpath.py +14 -0
  119. ai_dev_browser/tools/focus_by_ref.py +14 -0
  120. ai_dev_browser/tools/highlight_by_ref.py +14 -0
  121. ai_dev_browser/tools/hover_by_ref.py +14 -0
  122. ai_dev_browser/tools/html_by_ref.py +14 -0
  123. ai_dev_browser/tools/js_evaluate.py +14 -0
  124. ai_dev_browser/tools/login_interactive.py +14 -0
  125. ai_dev_browser/tools/mouse_click.py +14 -0
  126. ai_dev_browser/tools/mouse_drag.py +14 -0
  127. ai_dev_browser/tools/mouse_move.py +14 -0
  128. ai_dev_browser/tools/page_discover.py +14 -0
  129. ai_dev_browser/tools/page_emulate_focus.py +14 -0
  130. ai_dev_browser/tools/page_goto.py +14 -0
  131. ai_dev_browser/tools/page_html.py +14 -0
  132. ai_dev_browser/tools/page_info.py +14 -0
  133. ai_dev_browser/tools/page_reload.py +14 -0
  134. ai_dev_browser/tools/page_screenshot.py +14 -0
  135. ai_dev_browser/tools/page_scroll.py +14 -0
  136. ai_dev_browser/tools/page_wait_element.py +14 -0
  137. ai_dev_browser/tools/page_wait_ready.py +14 -0
  138. ai_dev_browser/tools/page_wait_url.py +14 -0
  139. ai_dev_browser/tools/screenshot_by_ref.py +14 -0
  140. ai_dev_browser/tools/select_by_ref.py +14 -0
  141. ai_dev_browser/tools/storage_get.py +14 -0
  142. ai_dev_browser/tools/storage_set.py +14 -0
  143. ai_dev_browser/tools/tab_close.py +14 -0
  144. ai_dev_browser/tools/tab_list.py +14 -0
  145. ai_dev_browser/tools/tab_new.py +14 -0
  146. ai_dev_browser/tools/tab_switch.py +14 -0
  147. ai_dev_browser/tools/type_by_ref.py +14 -0
  148. ai_dev_browser/tools/type_by_text.py +14 -0
  149. ai_dev_browser/tools/upload_by_ref.py +14 -0
  150. ai_dev_browser/tools/window_set.py +14 -0
  151. ai_dev_browser-0.5.3.dist-info/METADATA +177 -0
  152. ai_dev_browser-0.5.3.dist-info/RECORD +155 -0
  153. ai_dev_browser-0.5.3.dist-info/WHEEL +5 -0
  154. ai_dev_browser-0.5.3.dist-info/licenses/LICENSE +25 -0
  155. ai_dev_browser-0.5.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,219 @@
1
+ # DO NOT EDIT THIS FILE!
2
+ #
3
+ # This file is generated from the CDP specification. If you need to make
4
+ # changes, edit the generator and regenerate all of the modules.
5
+ #
6
+ # CDP domain: WebMCP (experimental)
7
+
8
+ from __future__ import annotations
9
+ import enum
10
+ import typing
11
+ from dataclasses import dataclass
12
+ from .util import event_class, T_JSON_DICT
13
+
14
+ from . import dom
15
+ from . import page
16
+ from . import runtime
17
+
18
+
19
+ @dataclass
20
+ class Annotation:
21
+ '''
22
+ Tool annotations
23
+ '''
24
+ #: A hint indicating that the tool does not modify any state.
25
+ read_only: typing.Optional[bool] = None
26
+
27
+ #: If the declarative tool was declared with the autosubmit attribute.
28
+ autosubmit: typing.Optional[bool] = None
29
+
30
+ def to_json(self) -> T_JSON_DICT:
31
+ json: T_JSON_DICT = dict()
32
+ if self.read_only is not None:
33
+ json['readOnly'] = self.read_only
34
+ if self.autosubmit is not None:
35
+ json['autosubmit'] = self.autosubmit
36
+ return json
37
+
38
+ @classmethod
39
+ def from_json(cls, json: T_JSON_DICT) -> Annotation:
40
+ return cls(
41
+ read_only=bool(json['readOnly']) if json.get('readOnly', None) is not None else None,
42
+ autosubmit=bool(json['autosubmit']) if json.get('autosubmit', None) is not None else None,
43
+ )
44
+
45
+
46
+ class InvocationStatus(enum.Enum):
47
+ '''
48
+ Represents the status of a tool invocation.
49
+ '''
50
+ SUCCESS = "Success"
51
+ CANCELED = "Canceled"
52
+ ERROR = "Error"
53
+
54
+ def to_json(self) -> str:
55
+ return self.value
56
+
57
+ @classmethod
58
+ def from_json(cls, json: str) -> InvocationStatus:
59
+ return cls(json)
60
+
61
+
62
+ @dataclass
63
+ class Tool:
64
+ '''
65
+ Definition of a tool that can be invoked.
66
+ '''
67
+ #: Tool name.
68
+ name: str
69
+
70
+ #: Tool description.
71
+ description: str
72
+
73
+ #: Frame identifier associated with the tool registration.
74
+ frame_id: page.FrameId
75
+
76
+ #: Schema for the tool's input parameters.
77
+ input_schema: typing.Optional[dict] = None
78
+
79
+ #: Optional annotations for the tool.
80
+ annotations: typing.Optional[Annotation] = None
81
+
82
+ #: Optional node ID for declarative tools.
83
+ backend_node_id: typing.Optional[dom.BackendNodeId] = None
84
+
85
+ #: The stack trace at the time of the registration.
86
+ stack_trace: typing.Optional[runtime.StackTrace] = None
87
+
88
+ def to_json(self) -> T_JSON_DICT:
89
+ json: T_JSON_DICT = dict()
90
+ json['name'] = self.name
91
+ json['description'] = self.description
92
+ json['frameId'] = self.frame_id.to_json()
93
+ if self.input_schema is not None:
94
+ json['inputSchema'] = self.input_schema
95
+ if self.annotations is not None:
96
+ json['annotations'] = self.annotations.to_json()
97
+ if self.backend_node_id is not None:
98
+ json['backendNodeId'] = self.backend_node_id.to_json()
99
+ if self.stack_trace is not None:
100
+ json['stackTrace'] = self.stack_trace.to_json()
101
+ return json
102
+
103
+ @classmethod
104
+ def from_json(cls, json: T_JSON_DICT) -> Tool:
105
+ return cls(
106
+ name=str(json['name']),
107
+ description=str(json['description']),
108
+ frame_id=page.FrameId.from_json(json['frameId']),
109
+ input_schema=dict(json['inputSchema']) if json.get('inputSchema', None) is not None else None,
110
+ annotations=Annotation.from_json(json['annotations']) if json.get('annotations', None) is not None else None,
111
+ backend_node_id=dom.BackendNodeId.from_json(json['backendNodeId']) if json.get('backendNodeId', None) is not None else None,
112
+ stack_trace=runtime.StackTrace.from_json(json['stackTrace']) if json.get('stackTrace', None) is not None else None,
113
+ )
114
+
115
+
116
+ def enable() -> typing.Generator[T_JSON_DICT,T_JSON_DICT,None]:
117
+ '''
118
+ Enables the WebMCP domain, allowing events to be sent. Enabling the domain will trigger a toolsAdded event for
119
+ all currently registered tools.
120
+ '''
121
+ cmd_dict: T_JSON_DICT = {
122
+ 'method': 'WebMCP.enable',
123
+ }
124
+ json = yield cmd_dict
125
+
126
+
127
+ def disable() -> typing.Generator[T_JSON_DICT,T_JSON_DICT,None]:
128
+ '''
129
+ Disables the WebMCP domain.
130
+ '''
131
+ cmd_dict: T_JSON_DICT = {
132
+ 'method': 'WebMCP.disable',
133
+ }
134
+ json = yield cmd_dict
135
+
136
+
137
+ @event_class('WebMCP.toolsAdded')
138
+ @dataclass
139
+ class ToolsAdded:
140
+ '''
141
+ Event fired when new tools are added.
142
+ '''
143
+ #: Array of tools that were added.
144
+ tools: typing.List[Tool]
145
+
146
+ @classmethod
147
+ def from_json(cls, json: T_JSON_DICT) -> ToolsAdded:
148
+ return cls(
149
+ tools=[Tool.from_json(i) for i in json['tools']]
150
+ )
151
+
152
+
153
+ @event_class('WebMCP.toolsRemoved')
154
+ @dataclass
155
+ class ToolsRemoved:
156
+ '''
157
+ Event fired when tools are removed.
158
+ '''
159
+ #: Array of tools that were removed.
160
+ tools: typing.List[Tool]
161
+
162
+ @classmethod
163
+ def from_json(cls, json: T_JSON_DICT) -> ToolsRemoved:
164
+ return cls(
165
+ tools=[Tool.from_json(i) for i in json['tools']]
166
+ )
167
+
168
+
169
+ @event_class('WebMCP.toolInvoked')
170
+ @dataclass
171
+ class ToolInvoked:
172
+ '''
173
+ Event fired when a tool invocation starts.
174
+ '''
175
+ #: Name of the tool to invoke.
176
+ tool_name: str
177
+ #: Frame id
178
+ frame_id: page.FrameId
179
+ #: Invocation identifier.
180
+ invocation_id: str
181
+ #: The input parameters used for the invocation.
182
+ input_: str
183
+
184
+ @classmethod
185
+ def from_json(cls, json: T_JSON_DICT) -> ToolInvoked:
186
+ return cls(
187
+ tool_name=str(json['toolName']),
188
+ frame_id=page.FrameId.from_json(json['frameId']),
189
+ invocation_id=str(json['invocationId']),
190
+ input_=str(json['input'])
191
+ )
192
+
193
+
194
+ @event_class('WebMCP.toolResponded')
195
+ @dataclass
196
+ class ToolResponded:
197
+ '''
198
+ Event fired when a tool invocation completes or fails.
199
+ '''
200
+ #: Invocation identifier.
201
+ invocation_id: str
202
+ #: Status of the invocation.
203
+ status: InvocationStatus
204
+ #: Output or error delivered as delivered to the agent. Missing if ``status`` is anything other than Success.
205
+ output: typing.Optional[typing.Any]
206
+ #: Error text for protocol users.
207
+ error_text: typing.Optional[str]
208
+ #: The exception object, if the javascript tool threw an error>
209
+ exception: typing.Optional[runtime.RemoteObject]
210
+
211
+ @classmethod
212
+ def from_json(cls, json: T_JSON_DICT) -> ToolResponded:
213
+ return cls(
214
+ invocation_id=str(json['invocationId']),
215
+ status=InvocationStatus.from_json(json['status']),
216
+ output=json['output'] if json.get('output', None) is not None else None,
217
+ error_text=str(json['errorText']) if json.get('errorText', None) is not None else None,
218
+ exception=runtime.RemoteObject.from_json(json['exception']) if json.get('exception', None) is not None else None
219
+ )
@@ -0,0 +1,218 @@
1
+ """Core browser operations - shared by tools/ and Python package.
2
+
3
+ This module provides async functions for common browser operations.
4
+ Both CLI tools and Python code can use these functions.
5
+
6
+ Usage:
7
+ from ai_dev_browser.core import page_goto, click_by_text, page_discover
8
+
9
+ # In async context
10
+ await page_goto(tab, "https://example.com")
11
+ await click_by_text(tab, text="Sign in")
12
+ result = await page_discover(tab, interactable_only=True)
13
+ """
14
+
15
+ # Accessibility tree interactions
16
+ # CDP
17
+ # Config (shared constants)
18
+ from .ax import (
19
+ click_by_ref,
20
+ drag_by_ref,
21
+ focus_by_ref,
22
+ highlight_by_ref,
23
+ hover_by_ref,
24
+ html_by_ref,
25
+ screenshot_by_ref,
26
+ select_by_ref,
27
+ type_by_ref,
28
+ upload_by_ref,
29
+ )
30
+
31
+ # Browser lifecycle
32
+ from .browser import browser_list, browser_start, browser_stop
33
+ from .cdp import cdp_send
34
+
35
+ # Chrome detection and launching
36
+ from .chrome import find_chrome, launch_chrome
37
+
38
+ # Cloudflare
39
+ from .cloudflare import cloudflare_verify
40
+ from .config import (
41
+ DEFAULT_BASE_DIR,
42
+ DEFAULT_COOKIES_DIR,
43
+ DEFAULT_COOKIES_FILE,
44
+ DEFAULT_DEBUG_HOST,
45
+ DEFAULT_DEBUG_PORT,
46
+ DEFAULT_PORT_RANGE,
47
+ DEFAULT_PROFILE_DIR,
48
+ DEFAULT_PROFILE_PREFIX,
49
+ DEFAULT_REUSE_STRATEGY,
50
+ ReuseStrategy,
51
+ get_workspace_profile_dir,
52
+ get_workspace_slug,
53
+ )
54
+
55
+ # Connection
56
+ from .connection import connect_browser, get_active_tab, graceful_close_browser
57
+
58
+ # Cookies
59
+ from .cookies import cookies_list, cookies_load, cookies_save
60
+
61
+ # Dialog (only tool-facing function)
62
+ from .dialog import dialog_respond
63
+
64
+ # Download
65
+ from .download import download
66
+
67
+ # Login (human-in-the-loop)
68
+ from .login import login_interactive
69
+
70
+ # Elements (only tool-facing functions)
71
+ from .elements import (
72
+ click_by_html_id,
73
+ click_by_text,
74
+ click_by_xpath,
75
+ find_by_html_id,
76
+ find_by_xpath,
77
+ page_scroll,
78
+ page_wait_element,
79
+ type_by_text,
80
+ )
81
+
82
+ # Mouse
83
+ from .mouse import mouse_click, mouse_drag, mouse_move
84
+
85
+ # Navigation (only tool-facing functions)
86
+ from .navigation import (
87
+ page_goto,
88
+ page_reload,
89
+ page_wait_ready,
90
+ page_wait_url,
91
+ )
92
+
93
+ # Page info
94
+ from .page import page_html, page_info, js_evaluate, page_screenshot
95
+
96
+ # Port management
97
+ from .port import (
98
+ find_debug_chromes,
99
+ find_workspace_chromes,
100
+ get_available_port,
101
+ is_port_in_use,
102
+ )
103
+
104
+ # Process management
105
+ from .process import get_pid_on_port
106
+
107
+ # Text matching (only the dataclass is public)
108
+ from .text_match import MatchResult
109
+
110
+ # Snapshot (AI-friendly accessibility tree) - only tool-facing function
111
+ from .snapshot import page_discover
112
+
113
+ # Storage
114
+ from .storage import storage_get, storage_set
115
+
116
+ # Tabs
117
+ from .tabs import tab_close, tab_list, tab_new, tab_switch
118
+
119
+ # Window
120
+ from .window import page_emulate_focus, window_set
121
+
122
+
123
+ __all__ = [
124
+ # Accessibility tree interactions (by ref)
125
+ "click_by_ref",
126
+ "drag_by_ref",
127
+ "focus_by_ref",
128
+ "highlight_by_ref",
129
+ "hover_by_ref",
130
+ "html_by_ref",
131
+ "screenshot_by_ref",
132
+ "select_by_ref",
133
+ "type_by_ref",
134
+ "upload_by_ref",
135
+ # Browser lifecycle
136
+ "browser_start",
137
+ "browser_stop",
138
+ "browser_list",
139
+ # Config
140
+ "DEFAULT_BASE_DIR",
141
+ "DEFAULT_PROFILE_DIR",
142
+ "DEFAULT_COOKIES_FILE",
143
+ "DEFAULT_COOKIES_DIR",
144
+ "DEFAULT_PROFILE_PREFIX",
145
+ "DEFAULT_DEBUG_HOST",
146
+ "DEFAULT_DEBUG_PORT",
147
+ "DEFAULT_PORT_RANGE",
148
+ "DEFAULT_REUSE_STRATEGY",
149
+ "ReuseStrategy",
150
+ "get_workspace_slug",
151
+ "get_workspace_profile_dir",
152
+ # Chrome
153
+ "find_chrome",
154
+ "launch_chrome",
155
+ # Cloudflare
156
+ "cloudflare_verify",
157
+ # CDP
158
+ "cdp_send",
159
+ # Port
160
+ "is_port_in_use",
161
+ "find_debug_chromes",
162
+ "find_workspace_chromes",
163
+ "get_available_port",
164
+ # Process
165
+ "get_pid_on_port",
166
+ # Connection
167
+ "connect_browser",
168
+ "get_active_tab",
169
+ "graceful_close_browser",
170
+ # Navigation
171
+ "page_goto",
172
+ "page_reload",
173
+ "page_wait_ready",
174
+ "page_wait_url",
175
+ # Elements
176
+ "click_by_text",
177
+ "type_by_text",
178
+ "page_scroll",
179
+ "page_wait_element",
180
+ "find_by_html_id",
181
+ "click_by_html_id",
182
+ "find_by_xpath",
183
+ "click_by_xpath",
184
+ # Text matching
185
+ "MatchResult",
186
+ # Snapshot
187
+ "page_discover",
188
+ # Tabs
189
+ "tab_new",
190
+ "tab_list",
191
+ "tab_switch",
192
+ "tab_close",
193
+ # Page
194
+ "page_info",
195
+ "page_html",
196
+ "js_evaluate",
197
+ "page_screenshot",
198
+ # Mouse
199
+ "mouse_move",
200
+ "mouse_click",
201
+ "mouse_drag",
202
+ # Window
203
+ "window_set",
204
+ "page_emulate_focus",
205
+ # Storage
206
+ "storage_get",
207
+ "storage_set",
208
+ # Download
209
+ "download",
210
+ # Dialog
211
+ "dialog_respond",
212
+ # Login
213
+ "login_interactive",
214
+ # Cookies
215
+ "cookies_load",
216
+ "cookies_save",
217
+ "cookies_list",
218
+ ]
@@ -0,0 +1,38 @@
1
+ """Case conversion utilities — single source of truth.
2
+
3
+ CDP wire format uses camelCase (`allowUnsafeEvalBlockedByCSP`); the vendored
4
+ cdp-python module exposes snake_case kwargs (`allow_unsafe_eval_blocked_by_csp`).
5
+ Anywhere we bridge the two we use one tested function so acronym handling stays
6
+ consistent.
7
+
8
+ The naive `re.sub(r"(?<!^)(?=[A-Z])", "_", name).lower()` shipped before this
9
+ module mishandled trailing/embedded acronyms — `...ByCSP` became
10
+ `..._by_c_s_p` and `getHTML` became `get_h_t_m_l`. Those names don't exist in
11
+ cdp-python, so every CDP command carrying an acronym parameter raised TypeError
12
+ on the retry path of `_transport.send_raw`.
13
+ """
14
+
15
+ import re
16
+
17
+
18
+ # Two-pass regex handling acronym boundaries:
19
+ # 1. lower/digit → Upper ("userAgent" → "user_Agent")
20
+ # 2. acronym end → next word ("CSPNext", "XMLHttp" → "CSP_Next", "XML_Http")
21
+ # Then lowercase. Order matters: pass 1 splits the easy cases first so pass 2
22
+ # only has to handle runs of uppercase that precede a capitalized word.
23
+ _LOWER_UPPER = re.compile(r"([a-z0-9])([A-Z])")
24
+ _ACRONYM_WORD = re.compile(r"([A-Z]+)([A-Z][a-z])")
25
+
26
+
27
+ def camel_to_snake(name: str) -> str:
28
+ """Convert a camelCase / PascalCase identifier to snake_case.
29
+
30
+ Handles trailing acronyms (`...ByCSP` → `..._by_csp`), embedded acronyms
31
+ (`XMLHttpRequest` → `xml_http_request`), all-caps (`URL` → `url`), digits
32
+ (`ipv4Address` → `ipv4_address`), and identifiers already in snake_case.
33
+
34
+ Empty string returns empty string.
35
+ """
36
+ s = _LOWER_UPPER.sub(r"\1_\2", name)
37
+ s = _ACRONYM_WORD.sub(r"\1_\2", s)
38
+ return s.lower()
@@ -0,0 +1,84 @@
1
+ """Cloudflare checkbox template image for verify_cf()."""
2
+
3
+ import base64
4
+
5
+ _CF_TEMPLATE_B64 = (
6
+ "iVBORw0KGgoAAAANSUhEUgAAAG8AAABJCAYAAAAzMHhLAAAAAXNSR0IArs4c6QAAAARnQU1BAACx"
7
+ "jwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAA/VSURBVHhe7VxprFXVGV13nt/Ae4BgCdICohFD"
8
+ "baWRoSCGQUXBNO2v1tbWiDRpqwVq0tRawCgVE3809p9BpaaWxqGoJQ7RggM4ULFoFKwgw5NBgTfc"
9
+ "eexa+9z9uIBM9T77bt9Zujnn7Hl/a3/f/vY5+z5PhcCXiOMb81SvJ8VJCxQZvExnEDwF51oJONcT"
10
+ "nvWPyqhCHyoqZ+KUr8wQMv9WayNyDHpieRbxeJRa5q3fKVbhM2/yzKNc/pLS+exzagiW+cxyFT4r"
11
+ "xWdiVb7abEk3XhSZXelBxZmxlvlfEUWP2ikhkGek14eCLgFfb/9Upk/IK7PjHo+HAqqYe7/fj0Kh"
12
+ "gECgKsi6QN23QxH0LNQOTzhVHuFoXK9gDU6Wt/pczWyF56neVKoV2Geb52i9VRyfX//0lhHJaody"
13
+ "7J2cx9Zj7utNniXM53Pmmou+w5diNjOZjCHV6/UiFApVY118UfQpedLAUqmEgwcPIhgMGgJzOa0l"
14
+ "LuqBupMnwgSteSJO2tbR0YFBgwaZeK1/LuqDPtU8kae1b9euXRgxYoTRPBf1w5dC3ocffohRo0b1"
15
+ "aqWL+qDu5Kk6mcza++3bt2P06NGGTJvm4oujz8iTlmm9E/bs2YOhQ4ea5zo3N6BRuwN10WBwyWtg"
16
+ "uOQ1MFzyGhgueQ0Ml7wGhkteA8Mlr4HhktfAcMlrYLjkNTBc8hoYLnkNDJe8BoZLXgOj333PU7q+"
17
+ "vvf09CAej5szL6orm83isccew9atW1EsFk1Q/PEfd22bJ4PKRCIRU78ORU2ePBnz5s3rLaezpTrt"
18
+ "Fg6H0dnZidbWVlMmn8+btvRBORqNmjz2eKPKKE11qtypoDK2Hh3GUl3d3d1IJBKmDxqXoHGrTV0V"
19
+ "p7rb2trM+VeLfkee8qiD9qCSBqlBrF+/3gQJTXkU1I6tT/eKE8mngtIlMAlZ+SW4WbNmYfbs2SY+"
20
+ "nU6bfLq3B4VrDwzrXn0S8SovqI5YLGaIqRXu50Fj0fFH5VU9giVKbWvC6qq6Fa98alvjVP5a+fU7"
21
+ "8tTZVCplZqI6K2Gr3IoVK7B3716sXLnSDF5B8cpj21JQ+dPB5t+3bx+WL1+O9vZ2LFmy5BhBWeHa"
22
+ "PjQ1NRkBS2s1gXQVabpKg1SfyonUU0GESItEtuqzdUq77ITSvWSoPuhe9aqcjlDaU3jCqW3M/wga"
23
+ "gKBO616D6urqMrNSQtTANRilSdgiUlcNVsScKtRCE0qQedRksWdLlU+EqA3VrXZVtxWmJdVqhtKV"
24
+ "T9p6OogUQeXU5+bmZkOgyqpuq/maMLpXP9SWytn+WvQ78iQ8O7slRHVag5M5ElkKtWRYYWuAGrzN"
25
+ "c7Kg/ILVFglNZRWvNnSVYO3ksG0oTf1Qf5SmtqzAJWhpk637VFAdmijKr3Iqb7U1mUyaq+pX3YrX"
26
+ "RNVV8jjeJPc78tRBCUiCkPCsGdO9hKyrTRd0rzgr8DOBzS+ojOoSSdIePatNXTXz7fojsqVh6oMs"
27
+ "gcqICKXpuaWlxRByOogs22fVJ6guESeTaNvV0qH6LGFqX+Vq0S/NpoQigViyrElU5yVkQc9KO1tY"
28
+ "Aais6pKgJFCruTbYtqQlEujhw4fNs/qmq8qrjNJ2795t6pRJPx1URkEapTVcxGnS2HqlZSJNxMrT"
29
+ "lcYJkofaqkW/I08DkfAkHM02BcEOToOtnYF6ljB0PTOUOZsdk6lQYVWhSBgBCq1UcUgxbfA//dSO"
30
+ "Oo5cqhtrHnkYK+9ZgRiF2pWiE8X8QTktXWksXbocTz2zFoc7D8FXplYzqJ2KRz/RklfoiFk/24pz"
31
+ "MqRSGXQfPoQbfvR9/PWJJ5EvlzCoOYqdO7ZjzIUX4/JZc7HhHy+rAAtz0rJPqBSQSXebehza2H/n"
32
+ "of9AxNmZKLsvDRM5ihNp1txZ2LhaQk8OaW0ZPr/ycp0kWRVpGMWQLVDbfDTRvFd7SvfKZBWzCHkr"
33
+ "+M6VM/HAH+/Hrr2H4GG/NKU6s1zvMhVsfuMdTLh0AiIJbh/Yl2I6T9NQJCkZ+D3UlhLbIwm5Ij1j"
34
+ "EuKtBOEnGc+/sA5zv/ddpMtsx5PGimW/wdLf34+X33gTl319ImdsgRMrhmS2gHBEkyLNCVyEP8At"
35
+ "SVG9HoDg/qh6JzId7RNp5p5pRov5v08TQr+AJXmtTTFceP5YvLl5C/LklvTA4/fh8SeexsRvTcaw"
36
+ "IW0ok+h8dxbBeAReD01jMMBJSGH7tU576YgFub0oUfuCiLYk8Nn+T5DlZPX5w+g+0IGD+zowYtQY"
37
+ "9HCrGoiGTNv6wS2nG1vTdoF9LHvQ2Z0hqYGBSd7xMKatei8Y8oyyUDzm3oMWOhNTpk7Do3/5s+Fc"
38
+ "vzIM+TzY8NpGXHX1XJq0Toq4iJlXz8OY0eMZvoZ7770bAQqZCooHV6/GgoULseRXt2LkyK/irQ0b"
39
+ "sPS3S/HM2mewZ28Hrpk7H1u3vodZs2bg+ut/gpt/fAOeXPMo13utd14c+OQAfnnrEqxatZrPEWp9"
40
+ "cgCSJy6kaoRIo1Idg17zK9IMeWRKeRJNmDRlsvndRT6dQT6XxKZX1mPLv7bi0ssm0bqmcO1VV2Lx"
41
+ "bb/Gu+9vxebXN+HvT6/F9h0dNHv0agNBrH/pRSxccCN27f43vjnxUmOeo+EEzhk8HC+9+CrGnj8O"
42
+ "Lzz/HJ762wOYOn0S1r/yEmhpQeVFjpb15VffwpzZV9Opcbo0cDWPoxdNCrUEijw5LWWzHlLJlCYC"
43
+ "eT/2gnF8KGPL25u5rnXjzY2vYMHNP+V6mce+3R8jQjWZPG0avGGgta0dN9+0AA8+tJprITBkyDm4"
44
+ "5BsTMHbMSJrLPVInmtAkUgyxkAddXUlqWQRdRz41pMycNR3vvf8uNm95m95nFhs3bsGUKVfgvFHD"
45
+ "6cQB8XBsIJJXHbLIs0GxNQRywSJpXPu4TpE2ZlAZDwa1t+G2JYvw8EMPIBoK4umn1mLcBWMw4txm"
46
+ "HNx/ANs++IDaOQUjRk7A+aPHYvHixehJpdHDvfeejg7j+icSYbQPa+eGNosICQiQ6R46ka3Dz0Pn"
47
+ "kW7GOe9Qh4wYhhkzp+PZZ5/FoNawWVt/8MMb6dBpbwr0dHUOTLP5+aD3Jm0jadK8Xvjpgfr8KNHz"
48
+ "9FJq02k6d+/YgXXr1mEwtevbky421jVfKGPOlXOx8bUN2Lt7C7Z99BF27t6He1Yu4wbeefmgbU9P"
49
+ "6giyqS5GcM+YoxfNuukLoUwPNRKJIhELoZv7vGT3EUyfeTlep/n955btKNB8XnDRxcjQjip9cFPr"
50
+ "ACPP/lmMXui5uhdzIhxnxV7p3nu93IZwCyHXXHHhkB8XjRuD22+/A+PHj0eQjmA+XcS0GXPwzrsf"
51
+ "4DWug12deivC/WpFr9GAdBpoHzKUCuznehVAOBZlWtm8fIiEwshxH57loiYHqZBNIxEPIN6UwIRL"
52
+ "LmG5Ntx553I6RfMQjnIZDvvQSk+1mC31P/L0FkEzVG8a9PZDi7r2cYqT8Jw92FHYOCv004IsVYrK"
53
+ "y6FXN+QiMBj0o8x6PFX7abYPDNoLFkp094POG59YNIgrZkynQoZx7fz59DDLNHU+aoQXj6x5Estu"
54
+ "vw2XT52IeEs7pl8xB29t2oSA6mHZdC7PqzHEyHEPV2EDPs4cbttopj3g/OBNEWHuDUu8hkJRTJ0y"
55
+ "Cdu2bcN1181HMqWJ4Lxx8Wtvy86f4ajPDKpOi759hSSczSchDVLlNStlakSi6lq0aJEpe99995n0"
56
+ "Xq/wbGCadoSnix5vueUW84L4D/f/0YnvXfycfNJK/VEbe++nJnJjhr2f7MNXhg9DjmuPn6a1SPdd"
57
+ "fc8cOow2jjXLsXYn0xgcd740dGVoIrnRDlZS8NDB8XJvl01S6wNx7gXLSEQpK18ZmXKenmUGiQhl"
58
+ "wUm25vHn8OL6N7DsjrvolYa1zUOBkyBG77XfaZ4gwiRQaZyIE4lWu+yE0LPSzgriW+rEYZdYVq+d"
59
+ "zFucgD7t6GsBN9MkyAm6V1sMulZNbkGv6dj2sOHnUsjSjgB8kbBZF+EPkTg6I9D7S44jFGHeCvKZ"
60
+ "LGuhmTRq74c3GGFcAeFEnP0o0Inxcv3Lcl3Nc55U0ByJsx3g450dWHHX3bj1Fz/nWkgXlsXLrLdI"
61
+ "FS2SZKdH/Qj2K4LVXvuVQfeWTJsu6F5xIrOoBeY0EHfaBii/hCGTqLo0Kex71BNRJZEhEArhyJEj"
62
+ "XAPZHk0fC3PbQI+yJ02tZBaSm+nqMpMv6Fe9HBMXxhDXOnaTjmyIO48AgrEENUuflTRemu0ITWWp"
63
+ "AL2503Kx8Kaf0TzPwfLfLcd5I4YjRqcmmdJnqRLiJLJQ6ofkSZD2S7U1s9JEkSqSFBRvgxW8iNV6"
64
+ "afOcLCi/CAyGQ+ZZgrLvRtXGiThKnNE+5mtrb6eX6HO+gFNTPCwXI6llraXsQ6S5GS0UMLdv5guB"
65
+ "go9GOsDi3dyzdXZmSBTHmaMn4ykw7hDrL1JT9UkqQA0NYtWqP2EnN/jXzJ2LkF9nepLUvgCiER8+"
66
+ "/ewQHadQ/yNPMFpBSKASsGaxvjjrm5eOHuhbl7RMadYFt6a1ltjPC1rCBF33Hzxg7u23OL0MPxW0"
67
+ "78txvZHZPLh/P4XHiUPT6KPHGKV2lWj68lyUUpk8twMZEzQhmppb6WB4kE7m0MTFrGlQAl6ZaWpj"
68
+ "oZBGcwsXOKXT0yykc8hnC8imNdHUKA0uNbIlEUVXzxHkOW59TtJbogF1AEkal2a61jl9H1OZFEnT"
69
+ "AaQ5s5wDSMYUHgM7v9l3Oi4ybUG5h0Xu++iBZsteZNJJRDkdQiyf4ryTJof15yFZtELPsaDXNNyU"
70
+ "l0ta+UIkmHm8NH9RnRI4TLK4i/eFqVlttOmcBNkKJ4SPGlki8T4UaSI/PXwAg4cMYXkfkuxzcyXU"
71
+ "/8hTugZvP0haUyhSvujRP5FXZBmZO9Ufpjm2R/985i0KJ8EJ3Ttan8o7XiidD5qypHz3YIx7NTo8"
72
+ "FHCRk6wYjDtjyCdJEB0jf5COTYmmUF/gY+Z1m95TymnNZbvQFNcklaUJoCeZgb9EcxynlUlVOH4P"
73
+ "r1lOixzi1LxkLokM62qLD4KPe8t+R15fwyHAwYlEnTk4QgpVZtgZo9f8IVbR6lgM+2zysM3etuht"
74
+ "2kmgOuBRPiUykibSeri2Xmeb4oSjfffCz6ij02qA4OhWoBrxX8IKVwTUEnn8s8lT2xbJon9q8hiQ"
75
+ "TPPXeHVVGXEowkSqIbaaT3VXyVV9+r474Mj7f4JLXgPDJa+B4ZLXwHDJa2C45DUwXPIaGC55DQyX"
76
+ "vAaGS14DwyWvgeGS18BwyWtguOQ1MPqMPH270zc9QedE9Kwv5C7qh7qTZwkT7Fdu+5NcHSRyUT/U"
77
+ "nTwdYbCwX811DkWHhuxfO3BRH9T9GEQtrBbqGETtH8VxUR/0yRkWofZgkDROptNFfdEn5Enjas2n"
78
+ "i75Bn5jN2pNjFsWifljv/MEaF/VBn5Ens1l7BNCS56JeAP4DSJ3/Y5GXBHwAAAAASUVORK5CYII="
79
+ )
80
+
81
+
82
+ def get_cf_template() -> bytearray:
83
+ """Return CF checkbox template image as bytes."""
84
+ return bytearray(base64.b64decode(_CF_TEMPLATE_B64))