cmdop 0.1.22__py3-none-any.whl → 0.1.23__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.
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from enum import Enum
5
6
  from typing import Any
6
7
 
7
8
  from pydantic import BaseModel
@@ -14,6 +15,25 @@ from cmdop.exceptions import (
14
15
  )
15
16
 
16
17
 
18
+ class WaitUntil(str, Enum):
19
+ """Wait strategy for navigation.
20
+
21
+ Determines when navigation is considered complete.
22
+ """
23
+
24
+ LOAD = "load"
25
+ """Wait for load event (default, not recommended for SPA)."""
26
+
27
+ DOMCONTENTLOADED = "domcontentloaded"
28
+ """Wait for DOMContentLoaded event."""
29
+
30
+ NETWORKIDLE = "networkidle"
31
+ """Wait until no network activity for 500ms (best for SPA)."""
32
+
33
+ COMMIT = "commit"
34
+ """Return immediately after navigation commits (fastest)."""
35
+
36
+
17
37
  def raise_browser_error(error: str, operation: str, **context: Any) -> None:
18
38
  """Raise appropriate browser exception based on error message."""
19
39
  error_lower = error.lower()
@@ -115,3 +135,86 @@ class InfiniteScrollResult(BaseModel):
115
135
  at_bottom: bool = False
116
136
  total_seen: int = 0
117
137
  error: str | None = None
138
+
139
+
140
+ # =============================================================================
141
+ # Network Capture Models (v2.19.0)
142
+ # =============================================================================
143
+
144
+
145
+ class NetworkRequest(BaseModel):
146
+ """Captured HTTP request."""
147
+
148
+ url: str = ""
149
+ method: str = "GET"
150
+ headers: dict[str, str] = {}
151
+ body: bytes = b""
152
+ content_type: str = ""
153
+ resource_type: str = "" # document, script, xhr, fetch, image, etc.
154
+
155
+
156
+ class NetworkResponse(BaseModel):
157
+ """Captured HTTP response."""
158
+
159
+ status: int = 0
160
+ status_text: str = ""
161
+ headers: dict[str, str] = {}
162
+ body: bytes = b""
163
+ content_type: str = ""
164
+ size: int = 0
165
+ from_cache: bool = False
166
+
167
+
168
+ class NetworkTiming(BaseModel):
169
+ """Request timing data."""
170
+
171
+ started_at_ms: int = 0
172
+ ended_at_ms: int = 0
173
+ duration_ms: int = 0
174
+ wait_time_ms: int = 0 # Time to first byte
175
+ receive_time_ms: int = 0 # Time to download body
176
+
177
+
178
+ class NetworkExchange(BaseModel):
179
+ """Complete request/response exchange."""
180
+
181
+ id: str = ""
182
+ request: NetworkRequest = NetworkRequest()
183
+ response: NetworkResponse | None = None
184
+ timing: NetworkTiming = NetworkTiming()
185
+ error: str = ""
186
+ frame_id: str = ""
187
+ initiator: str = "" # URL or script that initiated
188
+
189
+ def json_body(self) -> Any:
190
+ """Parse response body as JSON."""
191
+ import json
192
+ if self.response and self.response.body:
193
+ return json.loads(self.response.body)
194
+ return None
195
+
196
+ def text_body(self) -> str:
197
+ """Get response body as text."""
198
+ if self.response and self.response.body:
199
+ return self.response.body.decode("utf-8", errors="replace")
200
+ return ""
201
+
202
+
203
+ class NetworkStats(BaseModel):
204
+ """Network capture statistics."""
205
+
206
+ enabled: bool = False
207
+ total_captured: int = 0
208
+ total_errors: int = 0
209
+ total_bytes: int = 0
210
+ average_duration_ms: int = 0
211
+
212
+
213
+ class NetworkFilter(BaseModel):
214
+ """Filter for querying captured exchanges."""
215
+
216
+ url_pattern: str = ""
217
+ methods: list[str] = []
218
+ status_codes: list[int] = []
219
+ resource_types: list[str] = []
220
+ limit: int = 0
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Any
7
7
 
8
8
  from cmdop.services.base import BaseService
9
9
  from cmdop.services.browser.service._helpers import BaseServiceMixin, cookie_to_pb, pb_to_cookie
10
- from cmdop.services.browser.models import BrowserCookie, BrowserState, PageInfo, raise_browser_error
10
+ from cmdop.services.browser.models import BrowserCookie, BrowserState, PageInfo, WaitUntil, raise_browser_error
11
11
 
12
12
  if TYPE_CHECKING:
13
13
  from cmdop.transport.base import BaseTransport
@@ -75,11 +75,31 @@ class BrowserService(BaseService, BaseServiceMixin):
75
75
 
76
76
  # === Navigation & Interaction ===
77
77
 
78
- def navigate(self, session_id: str, url: str, timeout_ms: int = 30000) -> str:
79
- from cmdop._generated.rpc_messages.browser_pb2 import BrowserNavigateRequest
78
+ def navigate(
79
+ self,
80
+ session_id: str,
81
+ url: str,
82
+ timeout_ms: int = 30000,
83
+ wait_until: WaitUntil = WaitUntil.LOAD,
84
+ ) -> str:
85
+ from cmdop._generated.rpc_messages.browser_pb2 import (
86
+ BrowserNavigateRequest,
87
+ WaitUntil as PbWaitUntil,
88
+ )
89
+
90
+ # Convert Python enum to proto enum
91
+ pb_wait_until = {
92
+ WaitUntil.LOAD: PbWaitUntil.WAIT_LOAD,
93
+ WaitUntil.DOMCONTENTLOADED: PbWaitUntil.WAIT_DOMCONTENTLOADED,
94
+ WaitUntil.NETWORKIDLE: PbWaitUntil.WAIT_NETWORKIDLE,
95
+ WaitUntil.COMMIT: PbWaitUntil.WAIT_COMMIT,
96
+ }.get(wait_until, PbWaitUntil.WAIT_LOAD)
80
97
 
81
98
  request = BrowserNavigateRequest(
82
- browser_session_id=session_id, url=url, timeout_ms=timeout_ms
99
+ browser_session_id=session_id,
100
+ url=url,
101
+ timeout_ms=timeout_ms,
102
+ wait_until=pb_wait_until,
83
103
  )
84
104
  response = self._call_sync(self._get_stub.BrowserNavigate, request)
85
105
 
@@ -434,3 +454,183 @@ class BrowserService(BaseService, BaseServiceMixin):
434
454
  "items": json.loads(response.items_json) if response.items_json else [],
435
455
  "count": response.count,
436
456
  }
457
+
458
+ # === Network Capture (v2.19.0) ===
459
+
460
+ def network_enable(
461
+ self, session_id: str, max_exchanges: int = 1000, max_response_size: int = 10_000_000
462
+ ) -> None:
463
+ """Enable network capture."""
464
+ from cmdop._generated.rpc_messages.browser_pb2 import BrowserNetworkEnableRequest
465
+
466
+ request = BrowserNetworkEnableRequest(
467
+ browser_session_id=session_id,
468
+ max_exchanges=max_exchanges,
469
+ max_response_size=max_response_size,
470
+ )
471
+ response = self._call_sync(self._get_stub.BrowserNetworkEnable, request)
472
+
473
+ if not response.success:
474
+ raise RuntimeError(f"NetworkEnable failed: {response.error}")
475
+
476
+ def network_disable(self, session_id: str) -> None:
477
+ """Disable network capture."""
478
+ from cmdop._generated.rpc_messages.browser_pb2 import BrowserNetworkDisableRequest
479
+
480
+ request = BrowserNetworkDisableRequest(browser_session_id=session_id)
481
+ response = self._call_sync(self._get_stub.BrowserNetworkDisable, request)
482
+
483
+ if not response.success:
484
+ raise RuntimeError(f"NetworkDisable failed: {response.error}")
485
+
486
+ def network_get_exchanges(
487
+ self,
488
+ session_id: str,
489
+ url_pattern: str = "",
490
+ methods: list[str] | None = None,
491
+ status_codes: list[int] | None = None,
492
+ resource_types: list[str] | None = None,
493
+ limit: int = 0,
494
+ ) -> dict:
495
+ """Get captured exchanges."""
496
+ from cmdop._generated.rpc_messages.browser_pb2 import BrowserNetworkGetExchangesRequest
497
+
498
+ request = BrowserNetworkGetExchangesRequest(
499
+ browser_session_id=session_id,
500
+ url_pattern=url_pattern,
501
+ methods=methods or [],
502
+ status_codes=status_codes or [],
503
+ resource_types=resource_types or [],
504
+ limit=limit,
505
+ )
506
+ response = self._call_sync(self._get_stub.BrowserNetworkGetExchanges, request)
507
+
508
+ if not response.success:
509
+ raise RuntimeError(f"NetworkGetExchanges failed: {response.error}")
510
+
511
+ return {
512
+ "exchanges": [self._pb_to_exchange(e) for e in response.exchanges],
513
+ "count": response.count,
514
+ }
515
+
516
+ def network_get_exchange(self, session_id: str, exchange_id: str) -> dict:
517
+ """Get specific exchange by ID."""
518
+ from cmdop._generated.rpc_messages.browser_pb2 import BrowserNetworkGetExchangeRequest
519
+
520
+ request = BrowserNetworkGetExchangeRequest(
521
+ browser_session_id=session_id, exchange_id=exchange_id
522
+ )
523
+ response = self._call_sync(self._get_stub.BrowserNetworkGetExchange, request)
524
+
525
+ if not response.success:
526
+ raise RuntimeError(f"NetworkGetExchange failed: {response.error}")
527
+
528
+ return {"exchange": self._pb_to_exchange(response.exchange) if response.exchange else None}
529
+
530
+ def network_get_last(self, session_id: str, url_pattern: str = "") -> dict:
531
+ """Get most recent exchange matching URL pattern."""
532
+ from cmdop._generated.rpc_messages.browser_pb2 import BrowserNetworkGetLastRequest
533
+
534
+ request = BrowserNetworkGetLastRequest(
535
+ browser_session_id=session_id, url_pattern=url_pattern
536
+ )
537
+ response = self._call_sync(self._get_stub.BrowserNetworkGetLast, request)
538
+
539
+ if not response.success:
540
+ raise RuntimeError(f"NetworkGetLast failed: {response.error}")
541
+
542
+ return {"exchange": self._pb_to_exchange(response.exchange) if response.exchange else None}
543
+
544
+ def network_clear(self, session_id: str) -> None:
545
+ """Clear all captured exchanges."""
546
+ from cmdop._generated.rpc_messages.browser_pb2 import BrowserNetworkClearRequest
547
+
548
+ request = BrowserNetworkClearRequest(browser_session_id=session_id)
549
+ response = self._call_sync(self._get_stub.BrowserNetworkClear, request)
550
+
551
+ if not response.success:
552
+ raise RuntimeError(f"NetworkClear failed: {response.error}")
553
+
554
+ def network_stats(self, session_id: str) -> dict:
555
+ """Get capture statistics."""
556
+ from cmdop._generated.rpc_messages.browser_pb2 import BrowserNetworkStatsRequest
557
+
558
+ request = BrowserNetworkStatsRequest(browser_session_id=session_id)
559
+ response = self._call_sync(self._get_stub.BrowserNetworkStats, request)
560
+
561
+ if not response.success:
562
+ raise RuntimeError(f"NetworkStats failed: {response.error}")
563
+
564
+ return {
565
+ "enabled": response.enabled,
566
+ "total_captured": response.total_captured,
567
+ "total_errors": response.total_errors,
568
+ "total_bytes": response.total_bytes,
569
+ "average_duration_ms": response.average_duration_ms,
570
+ }
571
+
572
+ def network_export_har(
573
+ self,
574
+ session_id: str,
575
+ url_pattern: str = "",
576
+ methods: list[str] | None = None,
577
+ status_codes: list[int] | None = None,
578
+ resource_types: list[str] | None = None,
579
+ ) -> dict:
580
+ """Export captured exchanges to HAR format."""
581
+ from cmdop._generated.rpc_messages.browser_pb2 import BrowserNetworkExportHARRequest
582
+
583
+ request = BrowserNetworkExportHARRequest(
584
+ browser_session_id=session_id,
585
+ url_pattern=url_pattern,
586
+ methods=methods or [],
587
+ status_codes=status_codes or [],
588
+ resource_types=resource_types or [],
589
+ )
590
+ response = self._call_sync(self._get_stub.BrowserNetworkExportHAR, request)
591
+
592
+ if not response.success:
593
+ raise RuntimeError(f"NetworkExportHAR failed: {response.error}")
594
+
595
+ return {"har_data": response.har_data}
596
+
597
+ def _pb_to_exchange(self, pb: Any) -> dict:
598
+ """Convert protobuf exchange to dict."""
599
+ result: dict[str, Any] = {
600
+ "id": pb.id,
601
+ "error": pb.error,
602
+ "frame_id": pb.frame_id,
603
+ "initiator": pb.initiator,
604
+ }
605
+
606
+ if pb.request:
607
+ result["request"] = {
608
+ "url": pb.request.url,
609
+ "method": pb.request.method,
610
+ "headers": dict(pb.request.headers),
611
+ "body": pb.request.body,
612
+ "content_type": pb.request.content_type,
613
+ "resource_type": pb.request.resource_type,
614
+ }
615
+
616
+ if pb.response:
617
+ result["response"] = {
618
+ "status": pb.response.status,
619
+ "status_text": pb.response.status_text,
620
+ "headers": dict(pb.response.headers),
621
+ "body": pb.response.body,
622
+ "content_type": pb.response.content_type,
623
+ "size": pb.response.size,
624
+ "from_cache": pb.response.from_cache,
625
+ }
626
+
627
+ if pb.timing:
628
+ result["timing"] = {
629
+ "started_at_ms": pb.timing.started_at_ms,
630
+ "ended_at_ms": pb.timing.ended_at_ms,
631
+ "duration_ms": pb.timing.duration_ms,
632
+ "wait_time_ms": pb.timing.wait_time_ms,
633
+ "receive_time_ms": pb.timing.receive_time_ms,
634
+ }
635
+
636
+ return result
@@ -3,7 +3,7 @@
3
3
  from __future__ import annotations
4
4
  from typing import TYPE_CHECKING, Any
5
5
 
6
- from cmdop.services.browser.models import BrowserCookie, BrowserState, PageInfo
6
+ from cmdop.services.browser.models import BrowserCookie, BrowserState, PageInfo, WaitUntil
7
7
 
8
8
  from .capabilities import (
9
9
  ScrollCapability,
@@ -11,6 +11,7 @@ from .capabilities import (
11
11
  TimingCapability,
12
12
  DOMCapability,
13
13
  FetchCapability,
14
+ NetworkCapability,
14
15
  )
15
16
 
16
17
  if TYPE_CHECKING:
@@ -51,6 +52,7 @@ class BrowserSession:
51
52
  "_timing",
52
53
  "_dom",
53
54
  "_fetch",
55
+ "_network",
54
56
  )
55
57
 
56
58
  def __init__(self, service: "BrowserService", session_id: str) -> None:
@@ -61,6 +63,7 @@ class BrowserSession:
61
63
  self._timing: TimingCapability | None = None
62
64
  self._dom: DOMCapability | None = None
63
65
  self._fetch: FetchCapability | None = None
66
+ self._network: NetworkCapability | None = None
64
67
 
65
68
  @property
66
69
  def session_id(self) -> str:
@@ -103,11 +106,36 @@ class BrowserSession:
103
106
  self._fetch = FetchCapability(self)
104
107
  return self._fetch
105
108
 
109
+ @property
110
+ def network(self) -> NetworkCapability:
111
+ """Network: enable(), disable(), get_all(), filter(), last(), clear(), stats()"""
112
+ if self._network is None:
113
+ self._network = NetworkCapability(self)
114
+ return self._network
115
+
106
116
  # === Core Methods ===
107
117
 
108
- def navigate(self, url: str, timeout_ms: int = 30000) -> str:
109
- """Navigate to URL. Returns final URL."""
110
- return self._service.navigate(self._session_id, url, timeout_ms)
118
+ def navigate(
119
+ self,
120
+ url: str,
121
+ timeout_ms: int = 30000,
122
+ wait_until: WaitUntil = WaitUntil.LOAD,
123
+ ) -> str:
124
+ """Navigate to URL with specified wait strategy.
125
+
126
+ Args:
127
+ url: URL to navigate to.
128
+ timeout_ms: Timeout in milliseconds.
129
+ wait_until: When navigation is considered complete:
130
+ - WaitUntil.LOAD: Wait for load event (default, slow for SPA)
131
+ - WaitUntil.DOMCONTENTLOADED: Wait for DOMContentLoaded event
132
+ - WaitUntil.NETWORKIDLE: Wait until network is idle (best for SPA)
133
+ - WaitUntil.COMMIT: Return immediately (fastest)
134
+
135
+ Returns:
136
+ Final URL after navigation (may differ due to redirects).
137
+ """
138
+ return self._service.navigate(self._session_id, url, timeout_ms, wait_until)
111
139
 
112
140
  def click(self, selector: str, timeout_ms: int = 5000, move_cursor: bool = False) -> None:
113
141
  """Click element by CSS selector."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmdop
3
- Version: 0.1.22
3
+ Version: 0.1.23
4
4
  Summary: Python SDK for CMDOP agent interaction
5
5
  Project-URL: Homepage, https://cmdop.com
6
6
  Project-URL: Documentation, https://cmdop.com
@@ -148,8 +148,10 @@ health: Health = result.output # Typed!
148
148
  Capability-based API for browser automation.
149
149
 
150
150
  ```python
151
+ from cmdop.services.browser.models import WaitUntil
152
+
151
153
  with client.browser.create_session() as s:
152
- s.navigate("https://shop.com/products")
154
+ s.navigate("https://shop.com/products", wait_until=WaitUntil.NETWORKIDLE)
153
155
  s.dom.close_modal() # Close popups
154
156
 
155
157
  # BeautifulSoup parsing
@@ -182,7 +184,7 @@ with client.browser.create_session() as s:
182
184
 
183
185
  | Method | Description |
184
186
  |--------|-------------|
185
- | `navigate(url)` | Go to URL |
187
+ | `navigate(url, wait_until)` | Go to URL (wait_until: LOAD, DOMCONTENTLOADED, NETWORKIDLE, COMMIT) |
186
188
  | `click(selector, move_cursor)` | Click element |
187
189
  | `type(selector, text)` | Type text |
188
190
  | `wait_for(selector)` | Wait for element |
@@ -238,7 +240,44 @@ with client.browser.create_session() as s:
238
240
  |--------|-------------|
239
241
  | `json(url)` | Fetch JSON |
240
242
  | `all(requests)` | Parallel fetch |
241
- | `execute(method, url, ...)` | Custom request |
243
+ | `execute(js_code)` | Custom JS fetch code |
244
+
245
+ **`session.network`** - Network capture (v2.19.0)
246
+ | Method | Description |
247
+ |--------|-------------|
248
+ | `enable(max_exchanges)` | Start capturing HTTP traffic |
249
+ | `disable()` | Stop capturing |
250
+ | `get_all()` | Get all captured exchanges |
251
+ | `filter(url_pattern, methods, status_codes)` | Filter exchanges |
252
+ | `last(url_pattern)` | Get most recent matching exchange |
253
+ | `api_calls(url_pattern)` | Get XHR/Fetch calls matching pattern |
254
+ | `last_json(url_pattern)` | Get JSON body from last matching response |
255
+ | `wait_for(url_pattern, timeout_ms)` | Wait for matching request |
256
+ | `stats()` | Capture statistics |
257
+ | `export_har()` | Export to HAR format |
258
+ | `clear()` | Clear captured data |
259
+
260
+ ```python
261
+ # Example: Intercept API responses
262
+ from cmdop.services.browser.models import WaitUntil
263
+
264
+ with client.browser.create_session() as s:
265
+ s.network.enable()
266
+ s.navigate("https://app.example.com", wait_until=WaitUntil.NETWORKIDLE)
267
+
268
+ # Get last API response
269
+ api = s.network.last("/api/data")
270
+ data = api.json_body()
271
+
272
+ # Filter by criteria
273
+ posts = s.network.filter(
274
+ url_pattern="/api/posts",
275
+ methods=["GET"],
276
+ status_codes=[200],
277
+ )
278
+
279
+ s.network.disable()
280
+ ```
242
281
 
243
282
  ## SDKBaseModel
244
283
 
@@ -1,4 +1,4 @@
1
- cmdop/__init__.py,sha256=te8zdIJesHnMNTru-7YrTOnoUObhAm972gTFbhoHW5g,5200
1
+ cmdop/__init__.py,sha256=eqEIR3w99NYHsoGF6FioESxTgQhB2yWiARNYWbmNdkk,5200
2
2
  cmdop/client.py,sha256=nTotStZPBfYN3TrHH-OlEJMSVAXskYMQRkocsFmyaBY,14601
3
3
  cmdop/config.py,sha256=vpw1aGCyS4NKlZyzVur81Lt06QmN3FnscZji0bypUi0,4398
4
4
  cmdop/discovery.py,sha256=HNxSOa5tSuG7ppfFs21XdviW5ucjpRswVPguhX5j8Dg,7479
@@ -24,11 +24,11 @@ cmdop/_generated/file_rpc_pb2_grpc.py,sha256=HddeBZYoBOUkx4yPq2qdpwv2QmQouSbwCkf
24
24
  cmdop/_generated/message_pool.py,sha256=ncIr4Z2KeinOVGyzmR-Drc76DZnDTwWl4-bQYcIl8uM,97
25
25
  cmdop/_generated/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
26
  cmdop/_generated/rpc_messages_pb2.py,sha256=X3iog1k2vUDna-hBpEXy0E9-D05mkDWlmBSy0L_yhmQ,2734
27
- cmdop/_generated/rpc_messages_pb2.pyi,sha256=URIFseWilxDjTnLr-INgNLabALY85QgHwPW8yxIPQFI,8400
27
+ cmdop/_generated/rpc_messages_pb2.pyi,sha256=ddIPYj1axgsGwSc0KO1lTnCknJexEqeRz3VEwsLzG0E,10507
28
28
  cmdop/_generated/rpc_messages_pb2_grpc.py,sha256=WHRqOkW1r_9wP5Sd1Bc20jDVErtDN_xHvhsv8r8xyss,892
29
- cmdop/_generated/service_pb2.py,sha256=qMyy-hlP7pUotqDdsb0gt9Gg6oYYrWa9feQdB4T0s8Y,12310
29
+ cmdop/_generated/service_pb2.py,sha256=WRgcxz-wh7RWXTXcBTgw85V5uAgsc68UGaD0gAGwAxE,13315
30
30
  cmdop/_generated/service_pb2.pyi,sha256=-q-RU8TbkwpnKuBQGIhEsjGXj8ltD87sdzgC3B6zKYY,1649
31
- cmdop/_generated/service_pb2_grpc.py,sha256=cysF2oZthsUqaA8kqgNEhHbWFHNhAVDqVO1tveNSzJ4,108911
31
+ cmdop/_generated/service_pb2_grpc.py,sha256=ulLybECN-LLMMYlUG3XJw7Fmfz8PD0jRWwVHmhlYPjs,124703
32
32
  cmdop/_generated/tunnel_pb2.py,sha256=oF5qOSw_9faeXtVFELfEw1dq3TtPOUWl1v6DzUqguGo,3928
33
33
  cmdop/_generated/tunnel_pb2.pyi,sha256=ipcoNwnTLY16IfA95SbTP7REypE65ZVpf6akF7h4FCw,4925
34
34
  cmdop/_generated/tunnel_pb2_grpc.py,sha256=yutTebujge5cHC3h84FKWSdvGBuPVYOkRDy0UGtHZ6c,886
@@ -80,8 +80,8 @@ cmdop/_generated/rpc_messages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
80
80
  cmdop/_generated/rpc_messages/agent_pb2.py,sha256=1KCs4kwuuTwZm9Y8ql7t6Jjsutuepbq85E6DGVDWa84,3393
81
81
  cmdop/_generated/rpc_messages/agent_pb2.pyi,sha256=F7gy0PQlJ4cRQCli7U4v5A87-Lsw2_x0nV4hFXG1qj0,3866
82
82
  cmdop/_generated/rpc_messages/agent_pb2_grpc.py,sha256=ABbaG1eMcaWPZKdPoom2F-IjjVqjYNMDOjMp8X6QLHE,898
83
- cmdop/_generated/rpc_messages/browser_pb2.py,sha256=VAmjY4WUDXkpYOkS-q6w5qplbpIQGLmqDiS6b3O6UYE,16875
84
- cmdop/_generated/rpc_messages/browser_pb2.pyi,sha256=wA51sejGuiCfj9nEpAeymZwkvv1saQyIbAH5Ntlz0fc,25225
83
+ cmdop/_generated/rpc_messages/browser_pb2.py,sha256=2yuoDnRYtAq34NOg4xFPVo0jz0Tr1ulatT8Qe6Ibty8,24851
84
+ cmdop/_generated/rpc_messages/browser_pb2.pyi,sha256=HXQxtegycSDNrHXaxCnMKqukb2Na4dJTCUAg413c31k,37988
85
85
  cmdop/_generated/rpc_messages/browser_pb2_grpc.py,sha256=P8F8QYLT_kedGq7AXj37Us2hFQOaevdfYMHl0tTdY48,900
86
86
  cmdop/_generated/rpc_messages/device_pb2.py,sha256=nKj7axhR-FVSQoQUd4ENXpc5PU_UCjSlExajLIoeZY8,2435
87
87
  cmdop/_generated/rpc_messages/device_pb2.pyi,sha256=u5oLfTHuOSpYwMiVe2tw0vVQLLFvYgK3lxw-Vky1ZkA,1974
@@ -167,15 +167,16 @@ cmdop/services/extract.py,sha256=zwzikEKH4T4OnrprmJg3wqBWQJr-DYsSZgJGK_2yIHU,111
167
167
  cmdop/services/files.py,sha256=RGhfo7tW6diuUWC_EQQ-Y9zO1btm6mBTji0SWWa0fdo,12548
168
168
  cmdop/services/terminal.py,sha256=9SSWBexe2rWgMd-hGBEs9mcax3l7x_U84VHZpMC4xK8,17512
169
169
  cmdop/services/browser/__init__.py,sha256=31Ofu9RCYTAedPKLvnor8J7oGDgTjbqJ58OkxxHYwdk,1270
170
- cmdop/services/browser/models.py,sha256=qJ3da8hPvQn7Vtiqg3xg49G-GioidQGPPuLk2c_IBC4,2656
170
+ cmdop/services/browser/models.py,sha256=9MpNFgSgZDIznmTmsCUByEN31t_iQ6kAza1BsPSsuJs,5320
171
171
  cmdop/services/browser/parsing.py,sha256=0hQAy-0ZwJqtmhEqHO3EEdVB3iYmyhXRdouN_dCbig8,3820
172
- cmdop/services/browser/session.py,sha256=ZFZuzxEUEpwDenigBZdxr5aYePlo69LWre9YIK6LRSM,5363
173
- cmdop/services/browser/capabilities/__init__.py,sha256=SvaRxAiB8pq671bWtTThVe5BgVg0G-4wAPcgOvu9ab4,334
172
+ cmdop/services/browser/session.py,sha256=atSDDrTdkVJ6OrTiz8OaifegedZvbkUZUpfxGKUrDw8,6403
173
+ cmdop/services/browser/capabilities/__init__.py,sha256=UFmqG3XB2xm0MI2jRmsSXyvFyREPbfJnXLzgaragpbU,398
174
174
  cmdop/services/browser/capabilities/_base.py,sha256=mW0jKa2CyvK-8cjenv5JYvuCKiO3rpt5F7WtWFXBitA,749
175
175
  cmdop/services/browser/capabilities/_helpers.py,sha256=jXqYbeDocAHec2GwF2_BNnJ78vTyUnHteQoS-RSG00k,488
176
176
  cmdop/services/browser/capabilities/dom.py,sha256=DuXfildga23wGBNJWtNzx-t2Cq553HC48o9KAWAlyC0,2612
177
- cmdop/services/browser/capabilities/fetch.py,sha256=GAjOjk9XkCrMgUzRUrdMmVgOmIClwBWPUnmfA_OqITY,1392
177
+ cmdop/services/browser/capabilities/fetch.py,sha256=IpUrcUAOEanrN4TrB-JVtn3TtJ8GdkyN5qbTbpBWvLc,1310
178
178
  cmdop/services/browser/capabilities/input.py,sha256=uYmWGqturMDent44Us80oT_nk4kFNGyPJ0P5I35ulew,1749
179
+ cmdop/services/browser/capabilities/network.py,sha256=tZV4Oh_J5zUjEe9GBLQBDXEVh9EVTecPbyjE7lIUrd0,7775
179
180
  cmdop/services/browser/capabilities/scroll.py,sha256=sh0VuOPOv81BZg80-n8TABOj5RpshJT12qJwm4F_OY0,4808
180
181
  cmdop/services/browser/capabilities/timing.py,sha256=NH34G_4Kfukh6JCdhLRGoouA-uNTbx9ly7ybP9Kh558,1868
181
182
  cmdop/services/browser/js/__init__.py,sha256=gTiZguikKfztDtggZTux2FqhT8YTjyHCzQR4TEnT7z4,1177
@@ -186,7 +187,7 @@ cmdop/services/browser/js/scroll.py,sha256=yiOMAaR8ac8jCiWgNCVIt1pUGxdvktMUtzv-A
186
187
  cmdop/services/browser/service/__init__.py,sha256=AZH_r2FsxLfJGCVBaaAPw3dTGaUlgIFdlYd_RR8KxSg,100
187
188
  cmdop/services/browser/service/_helpers.py,sha256=w8foDUGZcD4HyF5eyLZUFxbx_fctAFsYRovvsksi3l4,1584
188
189
  cmdop/services/browser/service/aio.py,sha256=0E2D4igQb3YzAakdXsRMt8PEd0rFxI2gXfimwq_6nzk,767
189
- cmdop/services/browser/service/sync.py,sha256=meSoRacS5WVBTABiXopWvTIItzvR7nUiyaxnDuUMoUQ,15466
190
+ cmdop/services/browser/service/sync.py,sha256=40CIqdUAR-ZVFfQJVgUWVgGq3j7mgcpGs1SRe8zXjmI,23096
190
191
  cmdop/streaming/__init__.py,sha256=kG9UlJRqv8ndcwKMzWUddPlZT61pFO_Uf_c08A_8TxA,877
191
192
  cmdop/streaming/base.py,sha256=r7Q2QlRxgULzs9vlSGcOC_fwAQ_cF3Z3M7WsPQtxG5I,2990
192
193
  cmdop/streaming/handlers.py,sha256=FDEhADmCEFRbifvr9dU1X3C-K_96noz89Bl3tuDa_rQ,2616
@@ -197,7 +198,7 @@ cmdop/transport/base.py,sha256=2pkV8i9epgp_21dyReCfX47abRUrnALm0W5BXb-Fuz0,5571
197
198
  cmdop/transport/discovery.py,sha256=rcGAuVrR1l6jwcP0dqZxVhX1NsFK7sRHygFMCLmmUbA,10673
198
199
  cmdop/transport/local.py,sha256=ob6tWVxSdKwblHSMK8CkgjyuSdQoAeWgy5OAUd5ZNuE,7411
199
200
  cmdop/transport/remote.py,sha256=FNVqus9wOv7LlxKarXjLmSyvJiHwhvPbNDOPv1IQkmE,4329
200
- cmdop-0.1.22.dist-info/METADATA,sha256=OTt5H55-dBCDKBLpTJSiNtbsJAz5Wxy9jKTrIb7HTxE,7574
201
- cmdop-0.1.22.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
202
- cmdop-0.1.22.dist-info/licenses/LICENSE,sha256=6hyzbI1QVXW6B-XT7PaQ6UG9lns11Y_nnap8uUKGUqo,1062
203
- cmdop-0.1.22.dist-info/RECORD,,
201
+ cmdop-0.1.23.dist-info/METADATA,sha256=3BVnbTuAgOy-U2nU1g7gpiE1n1E81AZjepAvHM1N0hA,8929
202
+ cmdop-0.1.23.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
203
+ cmdop-0.1.23.dist-info/licenses/LICENSE,sha256=6hyzbI1QVXW6B-XT7PaQ6UG9lns11Y_nnap8uUKGUqo,1062
204
+ cmdop-0.1.23.dist-info/RECORD,,
File without changes