cmdop 0.1.21__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.
Files changed (36) hide show
  1. cmdop/__init__.py +1 -1
  2. cmdop/_generated/rpc_messages/browser_pb2.py +135 -85
  3. cmdop/_generated/rpc_messages/browser_pb2.pyi +270 -2
  4. cmdop/_generated/rpc_messages_pb2.pyi +25 -0
  5. cmdop/_generated/service_pb2.py +2 -2
  6. cmdop/_generated/service_pb2_grpc.py +345 -0
  7. cmdop/client.py +2 -8
  8. cmdop/services/browser/__init__.py +44 -31
  9. cmdop/services/browser/capabilities/__init__.py +17 -0
  10. cmdop/services/browser/capabilities/_base.py +28 -0
  11. cmdop/services/browser/capabilities/_helpers.py +16 -0
  12. cmdop/services/browser/capabilities/dom.py +76 -0
  13. cmdop/services/browser/capabilities/fetch.py +45 -0
  14. cmdop/services/browser/capabilities/input.py +49 -0
  15. cmdop/services/browser/capabilities/network.py +245 -0
  16. cmdop/services/browser/capabilities/scroll.py +147 -0
  17. cmdop/services/browser/capabilities/timing.py +66 -0
  18. cmdop/services/browser/js/__init__.py +6 -4
  19. cmdop/services/browser/js/interaction.py +34 -0
  20. cmdop/services/browser/models.py +103 -0
  21. cmdop/services/browser/service/__init__.py +5 -0
  22. cmdop/services/browser/service/aio.py +30 -0
  23. cmdop/services/browser/{sync/service.py → service/sync.py} +206 -6
  24. cmdop/services/browser/session.py +194 -0
  25. {cmdop-0.1.21.dist-info → cmdop-0.1.23.dist-info}/METADATA +107 -59
  26. {cmdop-0.1.21.dist-info → cmdop-0.1.23.dist-info}/RECORD +29 -24
  27. cmdop/services/browser/aio/__init__.py +0 -6
  28. cmdop/services/browser/aio/service.py +0 -420
  29. cmdop/services/browser/aio/session.py +0 -407
  30. cmdop/services/browser/base/__init__.py +0 -6
  31. cmdop/services/browser/base/session.py +0 -124
  32. cmdop/services/browser/sync/__init__.py +0 -6
  33. cmdop/services/browser/sync/session.py +0 -644
  34. /cmdop/services/browser/{base/service.py → service/_helpers.py} +0 -0
  35. {cmdop-0.1.21.dist-info → cmdop-0.1.23.dist-info}/WHEEL +0 -0
  36. {cmdop-0.1.21.dist-info → cmdop-0.1.23.dist-info}/licenses/LICENSE +0 -0
@@ -125,7 +125,7 @@ except AttributeError:
125
125
  file__operations_dot_requests__pb2 = file__operations__pb2.file_operations.requests_pb2
126
126
 
127
127
 
128
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rservice.proto\x12\x08terminal\x1a\x14\x61gent_messages.proto\x1a\x16\x63ontrol_messages.proto\x1a\x12rpc_messages.proto\x1a\x0e\x66ile_rpc.proto\x1a\x15\x66ile_operations.proto2\x84&\n\x18TerminalStreamingService\x12G\n\x0f\x43onnectTerminal\x12\x16.terminal.AgentMessage\x1a\x18.terminal.ControlMessage(\x01\x30\x01\x12P\n\rCreateSession\x12\x1e.terminal.CreateSessionRequest\x1a\x1f.terminal.CreateSessionResponse\x12M\n\x0c\x43loseSession\x12\x1d.terminal.CloseSessionRequest\x1a\x1e.terminal.CloseSessionResponse\x12Y\n\x10GetSessionStatus\x12!.terminal.GetSessionStatusRequest\x1a\".terminal.GetSessionStatusResponse\x12M\n\x0cListSessions\x12\x1d.terminal.ListSessionsRequest\x1a\x1e.terminal.ListSessionsResponse\x12\x44\n\tSendInput\x12\x1a.terminal.SendInputRequest\x1a\x1b.terminal.SendInputResponse\x12G\n\nSendResize\x12\x1b.terminal.SendResizeRequest\x1a\x1c.terminal.SendResizeResponse\x12G\n\nSendSignal\x12\x1b.terminal.SendSignalRequest\x1a\x1c.terminal.SendSignalResponse\x12G\n\nGetHistory\x12\x1b.terminal.GetHistoryRequest\x1a\x1c.terminal.GetHistoryResponse\x12J\n\x0bHealthCheck\x12\x1c.terminal.HealthCheckRequest\x1a\x1d.terminal.HealthCheckResponse\x12\x62\n\x13RegisterDeviceToken\x12$.terminal.RegisterDeviceTokenRequest\x1a%.terminal.RegisterDeviceTokenResponse\x12h\n\x15UnregisterDeviceToken\x12&.terminal.UnregisterDeviceTokenRequest\x1a\'.terminal.UnregisterDeviceTokenResponse\x12V\n\x0f\x45nterBackground\x12 .terminal.EnterBackgroundRequest\x1a!.terminal.EnterBackgroundResponse\x12_\n\x12WakeFromBackground\x12#.terminal.WakeFromBackgroundRequest\x1a$.terminal.WakeFromBackgroundResponse\x12M\n\x0cQueueCommand\x12\x1d.terminal.QueueCommandRequest\x1a\x1e.terminal.QueueCommandResponse\x12\x62\n\x11\x46ileListDirectory\x12%.terminal.FileListDirectoryRpcRequest\x1a&.terminal.FileListDirectoryRpcResponse\x12G\n\x08\x46ileRead\x12\x1c.terminal.FileReadRpcRequest\x1a\x1d.terminal.FileReadRpcResponse\x12J\n\tFileWrite\x12\x1d.terminal.FileWriteRpcRequest\x1a\x1e.terminal.FileWriteRpcResponse\x12h\n\x13\x46ileCreateDirectory\x12\'.terminal.FileCreateDirectoryRpcRequest\x1a(.terminal.FileCreateDirectoryRpcResponse\x12M\n\nFileDelete\x12\x1e.terminal.FileDeleteRpcRequest\x1a\x1f.terminal.FileDeleteRpcResponse\x12G\n\x08\x46ileMove\x12\x1c.terminal.FileMoveRpcRequest\x1a\x1d.terminal.FileMoveRpcResponse\x12G\n\x08\x46ileCopy\x12\x1c.terminal.FileCopyRpcRequest\x1a\x1d.terminal.FileCopyRpcResponse\x12P\n\x0b\x46ileGetInfo\x12\x1f.terminal.FileGetInfoRpcRequest\x1a .terminal.FileGetInfoRpcResponse\x12\x62\n\x11\x46ileCreateArchive\x12%.terminal.FileCreateArchiveRpcRequest\x1a&.terminal.FileCreateArchiveRpcResponse\x12M\n\nFileSearch\x12\x1e.terminal.FileSearchRpcRequest\x1a\x1f.terminal.FileSearchRpcResponse\x12Y\n\x0eHlsGetPlaylist\x12\".terminal.HlsGetPlaylistRpcRequest\x1a#.terminal.HlsGetPlaylistRpcResponse\x12V\n\rHlsGetSegment\x12!.terminal.HlsGetSegmentRpcRequest\x1a\".terminal.HlsGetSegmentRpcResponse\x12Y\n\x0eHlsStopSession\x12\".terminal.HlsStopSessionRpcRequest\x1a#.terminal.HlsStopSessionRpcResponse\x12[\n\x16InitiateStreamingRelay\x12\x1f.terminal.StreamingRelayRequest\x1a .terminal.StreamingRelayResponse\x12H\n\nRelayChunk\x12\x1d.terminal.StreamingRelayChunk\x1a\x1b.terminal.StreamingRelayAck\x12`\n\x17GetStreamingRelayStatus\x12%.terminal.StreamingRelayStatusRequest\x1a\x1e.terminal.StreamingRelayStatus\x12\x65\n\x14\x43\x61ncelStreamingRelay\x12%.terminal.StreamingRelayCancelRequest\x1a&.terminal.StreamingRelayCancelResponse\x12\x65\n\x14SendPushNotification\x12%.terminal.SendPushNotificationRequest\x1a&.terminal.SendPushNotificationResponse\x12>\n\x07\x45xtract\x12\x18.terminal.ExtractRequest\x1a\x19.terminal.ExtractResponse\x12\x41\n\x08RunAgent\x12\x19.terminal.RunAgentRequest\x1a\x1a.terminal.RunAgentResponse\x12J\n\x0b\x43\x61ncelAgent\x12\x1c.terminal.CancelAgentRequest\x1a\x1d.terminal.CancelAgentResponse\x12\x65\n\x14\x42rowserCreateSession\x12%.terminal.BrowserCreateSessionRequest\x1a&.terminal.BrowserCreateSessionResponse\x12\x62\n\x13\x42rowserCloseSession\x12$.terminal.BrowserCloseSessionRequest\x1a%.terminal.BrowserCloseSessionResponse\x12V\n\x0f\x42rowserNavigate\x12 .terminal.BrowserNavigateRequest\x1a!.terminal.BrowserNavigateResponse\x12M\n\x0c\x42rowserClick\x12\x1d.terminal.BrowserClickRequest\x1a\x1e.terminal.BrowserClickResponse\x12J\n\x0b\x42rowserType\x12\x1c.terminal.BrowserTypeRequest\x1a\x1d.terminal.BrowserTypeResponse\x12J\n\x0b\x42rowserWait\x12\x1c.terminal.BrowserWaitRequest\x1a\x1d.terminal.BrowserWaitResponse\x12S\n\x0e\x42rowserExtract\x12\x1f.terminal.BrowserExtractRequest\x1a .terminal.BrowserExtractResponse\x12\x62\n\x13\x42rowserExtractRegex\x12$.terminal.BrowserExtractRegexRequest\x1a%.terminal.BrowserExtractRegexResponse\x12S\n\x0e\x42rowserGetHTML\x12\x1f.terminal.BrowserGetHTMLRequest\x1a .terminal.BrowserGetHTMLResponse\x12S\n\x0e\x42rowserGetText\x12\x1f.terminal.BrowserGetTextRequest\x1a .terminal.BrowserGetTextResponse\x12\x65\n\x14\x42rowserExecuteScript\x12%.terminal.BrowserExecuteScriptRequest\x1a&.terminal.BrowserExecuteScriptResponse\x12\\\n\x11\x42rowserScreenshot\x12\".terminal.BrowserScreenshotRequest\x1a#.terminal.BrowserScreenshotResponse\x12V\n\x0f\x42rowserGetState\x12 .terminal.BrowserGetStateRequest\x1a!.terminal.BrowserGetStateResponse\x12\\\n\x11\x42rowserSetCookies\x12\".terminal.BrowserSetCookiesRequest\x1a#.terminal.BrowserSetCookiesResponse\x12\\\n\x11\x42rowserGetCookies\x12\".terminal.BrowserGetCookiesRequest\x1a#.terminal.BrowserGetCookiesResponse\x12q\n\x18\x42rowserValidateSelectors\x12).terminal.BrowserValidateSelectorsRequest\x1a*.terminal.BrowserValidateSelectorsResponse\x12_\n\x12\x42rowserExtractData\x12#.terminal.BrowserExtractDataRequest\x1a$.terminal.BrowserExtractDataResponse\x12Y\n\x10\x42rowserMouseMove\x12!.terminal.BrowserMouseMoveRequest\x1a\".terminal.BrowserMouseMoveResponse\x12M\n\x0c\x42rowserHover\x12\x1d.terminal.BrowserHoverRequest\x1a\x1e.terminal.BrowserHoverResponse\x12P\n\rBrowserScroll\x12\x1e.terminal.BrowserScrollRequest\x1a\x1f.terminal.BrowserScrollResponseB\x10Z\x0eterminal/protob\x06proto3')
128
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rservice.proto\x12\x08terminal\x1a\x14\x61gent_messages.proto\x1a\x16\x63ontrol_messages.proto\x1a\x12rpc_messages.proto\x1a\x0e\x66ile_rpc.proto\x1a\x15\x66ile_operations.proto2\xe6,\n\x18TerminalStreamingService\x12G\n\x0f\x43onnectTerminal\x12\x16.terminal.AgentMessage\x1a\x18.terminal.ControlMessage(\x01\x30\x01\x12P\n\rCreateSession\x12\x1e.terminal.CreateSessionRequest\x1a\x1f.terminal.CreateSessionResponse\x12M\n\x0c\x43loseSession\x12\x1d.terminal.CloseSessionRequest\x1a\x1e.terminal.CloseSessionResponse\x12Y\n\x10GetSessionStatus\x12!.terminal.GetSessionStatusRequest\x1a\".terminal.GetSessionStatusResponse\x12M\n\x0cListSessions\x12\x1d.terminal.ListSessionsRequest\x1a\x1e.terminal.ListSessionsResponse\x12\x44\n\tSendInput\x12\x1a.terminal.SendInputRequest\x1a\x1b.terminal.SendInputResponse\x12G\n\nSendResize\x12\x1b.terminal.SendResizeRequest\x1a\x1c.terminal.SendResizeResponse\x12G\n\nSendSignal\x12\x1b.terminal.SendSignalRequest\x1a\x1c.terminal.SendSignalResponse\x12G\n\nGetHistory\x12\x1b.terminal.GetHistoryRequest\x1a\x1c.terminal.GetHistoryResponse\x12J\n\x0bHealthCheck\x12\x1c.terminal.HealthCheckRequest\x1a\x1d.terminal.HealthCheckResponse\x12\x62\n\x13RegisterDeviceToken\x12$.terminal.RegisterDeviceTokenRequest\x1a%.terminal.RegisterDeviceTokenResponse\x12h\n\x15UnregisterDeviceToken\x12&.terminal.UnregisterDeviceTokenRequest\x1a\'.terminal.UnregisterDeviceTokenResponse\x12V\n\x0f\x45nterBackground\x12 .terminal.EnterBackgroundRequest\x1a!.terminal.EnterBackgroundResponse\x12_\n\x12WakeFromBackground\x12#.terminal.WakeFromBackgroundRequest\x1a$.terminal.WakeFromBackgroundResponse\x12M\n\x0cQueueCommand\x12\x1d.terminal.QueueCommandRequest\x1a\x1e.terminal.QueueCommandResponse\x12\x62\n\x11\x46ileListDirectory\x12%.terminal.FileListDirectoryRpcRequest\x1a&.terminal.FileListDirectoryRpcResponse\x12G\n\x08\x46ileRead\x12\x1c.terminal.FileReadRpcRequest\x1a\x1d.terminal.FileReadRpcResponse\x12J\n\tFileWrite\x12\x1d.terminal.FileWriteRpcRequest\x1a\x1e.terminal.FileWriteRpcResponse\x12h\n\x13\x46ileCreateDirectory\x12\'.terminal.FileCreateDirectoryRpcRequest\x1a(.terminal.FileCreateDirectoryRpcResponse\x12M\n\nFileDelete\x12\x1e.terminal.FileDeleteRpcRequest\x1a\x1f.terminal.FileDeleteRpcResponse\x12G\n\x08\x46ileMove\x12\x1c.terminal.FileMoveRpcRequest\x1a\x1d.terminal.FileMoveRpcResponse\x12G\n\x08\x46ileCopy\x12\x1c.terminal.FileCopyRpcRequest\x1a\x1d.terminal.FileCopyRpcResponse\x12P\n\x0b\x46ileGetInfo\x12\x1f.terminal.FileGetInfoRpcRequest\x1a .terminal.FileGetInfoRpcResponse\x12\x62\n\x11\x46ileCreateArchive\x12%.terminal.FileCreateArchiveRpcRequest\x1a&.terminal.FileCreateArchiveRpcResponse\x12M\n\nFileSearch\x12\x1e.terminal.FileSearchRpcRequest\x1a\x1f.terminal.FileSearchRpcResponse\x12Y\n\x0eHlsGetPlaylist\x12\".terminal.HlsGetPlaylistRpcRequest\x1a#.terminal.HlsGetPlaylistRpcResponse\x12V\n\rHlsGetSegment\x12!.terminal.HlsGetSegmentRpcRequest\x1a\".terminal.HlsGetSegmentRpcResponse\x12Y\n\x0eHlsStopSession\x12\".terminal.HlsStopSessionRpcRequest\x1a#.terminal.HlsStopSessionRpcResponse\x12[\n\x16InitiateStreamingRelay\x12\x1f.terminal.StreamingRelayRequest\x1a .terminal.StreamingRelayResponse\x12H\n\nRelayChunk\x12\x1d.terminal.StreamingRelayChunk\x1a\x1b.terminal.StreamingRelayAck\x12`\n\x17GetStreamingRelayStatus\x12%.terminal.StreamingRelayStatusRequest\x1a\x1e.terminal.StreamingRelayStatus\x12\x65\n\x14\x43\x61ncelStreamingRelay\x12%.terminal.StreamingRelayCancelRequest\x1a&.terminal.StreamingRelayCancelResponse\x12\x65\n\x14SendPushNotification\x12%.terminal.SendPushNotificationRequest\x1a&.terminal.SendPushNotificationResponse\x12>\n\x07\x45xtract\x12\x18.terminal.ExtractRequest\x1a\x19.terminal.ExtractResponse\x12\x41\n\x08RunAgent\x12\x19.terminal.RunAgentRequest\x1a\x1a.terminal.RunAgentResponse\x12J\n\x0b\x43\x61ncelAgent\x12\x1c.terminal.CancelAgentRequest\x1a\x1d.terminal.CancelAgentResponse\x12\x65\n\x14\x42rowserCreateSession\x12%.terminal.BrowserCreateSessionRequest\x1a&.terminal.BrowserCreateSessionResponse\x12\x62\n\x13\x42rowserCloseSession\x12$.terminal.BrowserCloseSessionRequest\x1a%.terminal.BrowserCloseSessionResponse\x12V\n\x0f\x42rowserNavigate\x12 .terminal.BrowserNavigateRequest\x1a!.terminal.BrowserNavigateResponse\x12M\n\x0c\x42rowserClick\x12\x1d.terminal.BrowserClickRequest\x1a\x1e.terminal.BrowserClickResponse\x12J\n\x0b\x42rowserType\x12\x1c.terminal.BrowserTypeRequest\x1a\x1d.terminal.BrowserTypeResponse\x12J\n\x0b\x42rowserWait\x12\x1c.terminal.BrowserWaitRequest\x1a\x1d.terminal.BrowserWaitResponse\x12S\n\x0e\x42rowserExtract\x12\x1f.terminal.BrowserExtractRequest\x1a .terminal.BrowserExtractResponse\x12\x62\n\x13\x42rowserExtractRegex\x12$.terminal.BrowserExtractRegexRequest\x1a%.terminal.BrowserExtractRegexResponse\x12S\n\x0e\x42rowserGetHTML\x12\x1f.terminal.BrowserGetHTMLRequest\x1a .terminal.BrowserGetHTMLResponse\x12S\n\x0e\x42rowserGetText\x12\x1f.terminal.BrowserGetTextRequest\x1a .terminal.BrowserGetTextResponse\x12\x65\n\x14\x42rowserExecuteScript\x12%.terminal.BrowserExecuteScriptRequest\x1a&.terminal.BrowserExecuteScriptResponse\x12\\\n\x11\x42rowserScreenshot\x12\".terminal.BrowserScreenshotRequest\x1a#.terminal.BrowserScreenshotResponse\x12V\n\x0f\x42rowserGetState\x12 .terminal.BrowserGetStateRequest\x1a!.terminal.BrowserGetStateResponse\x12\\\n\x11\x42rowserSetCookies\x12\".terminal.BrowserSetCookiesRequest\x1a#.terminal.BrowserSetCookiesResponse\x12\\\n\x11\x42rowserGetCookies\x12\".terminal.BrowserGetCookiesRequest\x1a#.terminal.BrowserGetCookiesResponse\x12q\n\x18\x42rowserValidateSelectors\x12).terminal.BrowserValidateSelectorsRequest\x1a*.terminal.BrowserValidateSelectorsResponse\x12_\n\x12\x42rowserExtractData\x12#.terminal.BrowserExtractDataRequest\x1a$.terminal.BrowserExtractDataResponse\x12Y\n\x10\x42rowserMouseMove\x12!.terminal.BrowserMouseMoveRequest\x1a\".terminal.BrowserMouseMoveResponse\x12M\n\x0c\x42rowserHover\x12\x1d.terminal.BrowserHoverRequest\x1a\x1e.terminal.BrowserHoverResponse\x12P\n\rBrowserScroll\x12\x1e.terminal.BrowserScrollRequest\x1a\x1f.terminal.BrowserScrollResponse\x12\x65\n\x14\x42rowserNetworkEnable\x12%.terminal.BrowserNetworkEnableRequest\x1a&.terminal.BrowserNetworkEnableResponse\x12h\n\x15\x42rowserNetworkDisable\x12&.terminal.BrowserNetworkDisableRequest\x1a\'.terminal.BrowserNetworkDisableResponse\x12w\n\x1a\x42rowserNetworkGetExchanges\x12+.terminal.BrowserNetworkGetExchangesRequest\x1a,.terminal.BrowserNetworkGetExchangesResponse\x12t\n\x19\x42rowserNetworkGetExchange\x12*.terminal.BrowserNetworkGetExchangeRequest\x1a+.terminal.BrowserNetworkGetExchangeResponse\x12h\n\x15\x42rowserNetworkGetLast\x12&.terminal.BrowserNetworkGetLastRequest\x1a\'.terminal.BrowserNetworkGetLastResponse\x12\x62\n\x13\x42rowserNetworkClear\x12$.terminal.BrowserNetworkClearRequest\x1a%.terminal.BrowserNetworkClearResponse\x12\x62\n\x13\x42rowserNetworkStats\x12$.terminal.BrowserNetworkStatsRequest\x1a%.terminal.BrowserNetworkStatsResponse\x12n\n\x17\x42rowserNetworkExportHAR\x12(.terminal.BrowserNetworkExportHARRequest\x1a).terminal.BrowserNetworkExportHARResponseB\x10Z\x0eterminal/protob\x06proto3')
129
129
 
130
130
  _globals = globals()
131
131
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -134,5 +134,5 @@ if not _descriptor._USE_C_DESCRIPTORS:
134
134
  _globals['DESCRIPTOR']._loaded_options = None
135
135
  _globals['DESCRIPTOR']._serialized_options = b'Z\016terminal/proto'
136
136
  _globals['_TERMINALSTREAMINGSERVICE']._serialized_start=133
137
- _globals['_TERMINALSTREAMINGSERVICE']._serialized_end=5001
137
+ _globals['_TERMINALSTREAMINGSERVICE']._serialized_end=5867
138
138
  # @@protoc_insertion_point(module_scope)
@@ -335,6 +335,46 @@ class TerminalStreamingServiceStub(object):
335
335
  request_serializer=rpc__messages_dot_browser__pb2.BrowserScrollRequest.SerializeToString,
336
336
  response_deserializer=rpc__messages_dot_browser__pb2.BrowserScrollResponse.FromString,
337
337
  _registered_method=True)
338
+ self.BrowserNetworkEnable = channel.unary_unary(
339
+ '/terminal.TerminalStreamingService/BrowserNetworkEnable',
340
+ request_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkEnableRequest.SerializeToString,
341
+ response_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkEnableResponse.FromString,
342
+ _registered_method=True)
343
+ self.BrowserNetworkDisable = channel.unary_unary(
344
+ '/terminal.TerminalStreamingService/BrowserNetworkDisable',
345
+ request_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkDisableRequest.SerializeToString,
346
+ response_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkDisableResponse.FromString,
347
+ _registered_method=True)
348
+ self.BrowserNetworkGetExchanges = channel.unary_unary(
349
+ '/terminal.TerminalStreamingService/BrowserNetworkGetExchanges',
350
+ request_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangesRequest.SerializeToString,
351
+ response_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangesResponse.FromString,
352
+ _registered_method=True)
353
+ self.BrowserNetworkGetExchange = channel.unary_unary(
354
+ '/terminal.TerminalStreamingService/BrowserNetworkGetExchange',
355
+ request_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangeRequest.SerializeToString,
356
+ response_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangeResponse.FromString,
357
+ _registered_method=True)
358
+ self.BrowserNetworkGetLast = channel.unary_unary(
359
+ '/terminal.TerminalStreamingService/BrowserNetworkGetLast',
360
+ request_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetLastRequest.SerializeToString,
361
+ response_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetLastResponse.FromString,
362
+ _registered_method=True)
363
+ self.BrowserNetworkClear = channel.unary_unary(
364
+ '/terminal.TerminalStreamingService/BrowserNetworkClear',
365
+ request_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkClearRequest.SerializeToString,
366
+ response_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkClearResponse.FromString,
367
+ _registered_method=True)
368
+ self.BrowserNetworkStats = channel.unary_unary(
369
+ '/terminal.TerminalStreamingService/BrowserNetworkStats',
370
+ request_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkStatsRequest.SerializeToString,
371
+ response_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkStatsResponse.FromString,
372
+ _registered_method=True)
373
+ self.BrowserNetworkExportHAR = channel.unary_unary(
374
+ '/terminal.TerminalStreamingService/BrowserNetworkExportHAR',
375
+ request_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkExportHARRequest.SerializeToString,
376
+ response_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkExportHARResponse.FromString,
377
+ _registered_method=True)
338
378
 
339
379
 
340
380
  class TerminalStreamingServiceServicer(object):
@@ -713,6 +753,55 @@ class TerminalStreamingServiceServicer(object):
713
753
  context.set_details('Method not implemented!')
714
754
  raise NotImplementedError('Method not implemented!')
715
755
 
756
+ def BrowserNetworkEnable(self, request, context):
757
+ """Network Capture (v2.19.0)
758
+ """
759
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
760
+ context.set_details('Method not implemented!')
761
+ raise NotImplementedError('Method not implemented!')
762
+
763
+ def BrowserNetworkDisable(self, request, context):
764
+ """Missing associated documentation comment in .proto file."""
765
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
766
+ context.set_details('Method not implemented!')
767
+ raise NotImplementedError('Method not implemented!')
768
+
769
+ def BrowserNetworkGetExchanges(self, request, context):
770
+ """Missing associated documentation comment in .proto file."""
771
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
772
+ context.set_details('Method not implemented!')
773
+ raise NotImplementedError('Method not implemented!')
774
+
775
+ def BrowserNetworkGetExchange(self, request, context):
776
+ """Missing associated documentation comment in .proto file."""
777
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
778
+ context.set_details('Method not implemented!')
779
+ raise NotImplementedError('Method not implemented!')
780
+
781
+ def BrowserNetworkGetLast(self, request, context):
782
+ """Missing associated documentation comment in .proto file."""
783
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
784
+ context.set_details('Method not implemented!')
785
+ raise NotImplementedError('Method not implemented!')
786
+
787
+ def BrowserNetworkClear(self, request, context):
788
+ """Missing associated documentation comment in .proto file."""
789
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
790
+ context.set_details('Method not implemented!')
791
+ raise NotImplementedError('Method not implemented!')
792
+
793
+ def BrowserNetworkStats(self, request, context):
794
+ """Missing associated documentation comment in .proto file."""
795
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
796
+ context.set_details('Method not implemented!')
797
+ raise NotImplementedError('Method not implemented!')
798
+
799
+ def BrowserNetworkExportHAR(self, request, context):
800
+ """Missing associated documentation comment in .proto file."""
801
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
802
+ context.set_details('Method not implemented!')
803
+ raise NotImplementedError('Method not implemented!')
804
+
716
805
 
717
806
  def add_TerminalStreamingServiceServicer_to_server(servicer, server):
718
807
  rpc_method_handlers = {
@@ -996,6 +1085,46 @@ def add_TerminalStreamingServiceServicer_to_server(servicer, server):
996
1085
  request_deserializer=rpc__messages_dot_browser__pb2.BrowserScrollRequest.FromString,
997
1086
  response_serializer=rpc__messages_dot_browser__pb2.BrowserScrollResponse.SerializeToString,
998
1087
  ),
1088
+ 'BrowserNetworkEnable': grpc.unary_unary_rpc_method_handler(
1089
+ servicer.BrowserNetworkEnable,
1090
+ request_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkEnableRequest.FromString,
1091
+ response_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkEnableResponse.SerializeToString,
1092
+ ),
1093
+ 'BrowserNetworkDisable': grpc.unary_unary_rpc_method_handler(
1094
+ servicer.BrowserNetworkDisable,
1095
+ request_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkDisableRequest.FromString,
1096
+ response_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkDisableResponse.SerializeToString,
1097
+ ),
1098
+ 'BrowserNetworkGetExchanges': grpc.unary_unary_rpc_method_handler(
1099
+ servicer.BrowserNetworkGetExchanges,
1100
+ request_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangesRequest.FromString,
1101
+ response_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangesResponse.SerializeToString,
1102
+ ),
1103
+ 'BrowserNetworkGetExchange': grpc.unary_unary_rpc_method_handler(
1104
+ servicer.BrowserNetworkGetExchange,
1105
+ request_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangeRequest.FromString,
1106
+ response_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangeResponse.SerializeToString,
1107
+ ),
1108
+ 'BrowserNetworkGetLast': grpc.unary_unary_rpc_method_handler(
1109
+ servicer.BrowserNetworkGetLast,
1110
+ request_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetLastRequest.FromString,
1111
+ response_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkGetLastResponse.SerializeToString,
1112
+ ),
1113
+ 'BrowserNetworkClear': grpc.unary_unary_rpc_method_handler(
1114
+ servicer.BrowserNetworkClear,
1115
+ request_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkClearRequest.FromString,
1116
+ response_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkClearResponse.SerializeToString,
1117
+ ),
1118
+ 'BrowserNetworkStats': grpc.unary_unary_rpc_method_handler(
1119
+ servicer.BrowserNetworkStats,
1120
+ request_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkStatsRequest.FromString,
1121
+ response_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkStatsResponse.SerializeToString,
1122
+ ),
1123
+ 'BrowserNetworkExportHAR': grpc.unary_unary_rpc_method_handler(
1124
+ servicer.BrowserNetworkExportHAR,
1125
+ request_deserializer=rpc__messages_dot_browser__pb2.BrowserNetworkExportHARRequest.FromString,
1126
+ response_serializer=rpc__messages_dot_browser__pb2.BrowserNetworkExportHARResponse.SerializeToString,
1127
+ ),
999
1128
  }
1000
1129
  generic_handler = grpc.method_handlers_generic_handler(
1001
1130
  'terminal.TerminalStreamingService', rpc_method_handlers)
@@ -2522,3 +2651,219 @@ class TerminalStreamingService(object):
2522
2651
  timeout,
2523
2652
  metadata,
2524
2653
  _registered_method=True)
2654
+
2655
+ @staticmethod
2656
+ def BrowserNetworkEnable(request,
2657
+ target,
2658
+ options=(),
2659
+ channel_credentials=None,
2660
+ call_credentials=None,
2661
+ insecure=False,
2662
+ compression=None,
2663
+ wait_for_ready=None,
2664
+ timeout=None,
2665
+ metadata=None):
2666
+ return grpc.experimental.unary_unary(
2667
+ request,
2668
+ target,
2669
+ '/terminal.TerminalStreamingService/BrowserNetworkEnable',
2670
+ rpc__messages_dot_browser__pb2.BrowserNetworkEnableRequest.SerializeToString,
2671
+ rpc__messages_dot_browser__pb2.BrowserNetworkEnableResponse.FromString,
2672
+ options,
2673
+ channel_credentials,
2674
+ insecure,
2675
+ call_credentials,
2676
+ compression,
2677
+ wait_for_ready,
2678
+ timeout,
2679
+ metadata,
2680
+ _registered_method=True)
2681
+
2682
+ @staticmethod
2683
+ def BrowserNetworkDisable(request,
2684
+ target,
2685
+ options=(),
2686
+ channel_credentials=None,
2687
+ call_credentials=None,
2688
+ insecure=False,
2689
+ compression=None,
2690
+ wait_for_ready=None,
2691
+ timeout=None,
2692
+ metadata=None):
2693
+ return grpc.experimental.unary_unary(
2694
+ request,
2695
+ target,
2696
+ '/terminal.TerminalStreamingService/BrowserNetworkDisable',
2697
+ rpc__messages_dot_browser__pb2.BrowserNetworkDisableRequest.SerializeToString,
2698
+ rpc__messages_dot_browser__pb2.BrowserNetworkDisableResponse.FromString,
2699
+ options,
2700
+ channel_credentials,
2701
+ insecure,
2702
+ call_credentials,
2703
+ compression,
2704
+ wait_for_ready,
2705
+ timeout,
2706
+ metadata,
2707
+ _registered_method=True)
2708
+
2709
+ @staticmethod
2710
+ def BrowserNetworkGetExchanges(request,
2711
+ target,
2712
+ options=(),
2713
+ channel_credentials=None,
2714
+ call_credentials=None,
2715
+ insecure=False,
2716
+ compression=None,
2717
+ wait_for_ready=None,
2718
+ timeout=None,
2719
+ metadata=None):
2720
+ return grpc.experimental.unary_unary(
2721
+ request,
2722
+ target,
2723
+ '/terminal.TerminalStreamingService/BrowserNetworkGetExchanges',
2724
+ rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangesRequest.SerializeToString,
2725
+ rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangesResponse.FromString,
2726
+ options,
2727
+ channel_credentials,
2728
+ insecure,
2729
+ call_credentials,
2730
+ compression,
2731
+ wait_for_ready,
2732
+ timeout,
2733
+ metadata,
2734
+ _registered_method=True)
2735
+
2736
+ @staticmethod
2737
+ def BrowserNetworkGetExchange(request,
2738
+ target,
2739
+ options=(),
2740
+ channel_credentials=None,
2741
+ call_credentials=None,
2742
+ insecure=False,
2743
+ compression=None,
2744
+ wait_for_ready=None,
2745
+ timeout=None,
2746
+ metadata=None):
2747
+ return grpc.experimental.unary_unary(
2748
+ request,
2749
+ target,
2750
+ '/terminal.TerminalStreamingService/BrowserNetworkGetExchange',
2751
+ rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangeRequest.SerializeToString,
2752
+ rpc__messages_dot_browser__pb2.BrowserNetworkGetExchangeResponse.FromString,
2753
+ options,
2754
+ channel_credentials,
2755
+ insecure,
2756
+ call_credentials,
2757
+ compression,
2758
+ wait_for_ready,
2759
+ timeout,
2760
+ metadata,
2761
+ _registered_method=True)
2762
+
2763
+ @staticmethod
2764
+ def BrowserNetworkGetLast(request,
2765
+ target,
2766
+ options=(),
2767
+ channel_credentials=None,
2768
+ call_credentials=None,
2769
+ insecure=False,
2770
+ compression=None,
2771
+ wait_for_ready=None,
2772
+ timeout=None,
2773
+ metadata=None):
2774
+ return grpc.experimental.unary_unary(
2775
+ request,
2776
+ target,
2777
+ '/terminal.TerminalStreamingService/BrowserNetworkGetLast',
2778
+ rpc__messages_dot_browser__pb2.BrowserNetworkGetLastRequest.SerializeToString,
2779
+ rpc__messages_dot_browser__pb2.BrowserNetworkGetLastResponse.FromString,
2780
+ options,
2781
+ channel_credentials,
2782
+ insecure,
2783
+ call_credentials,
2784
+ compression,
2785
+ wait_for_ready,
2786
+ timeout,
2787
+ metadata,
2788
+ _registered_method=True)
2789
+
2790
+ @staticmethod
2791
+ def BrowserNetworkClear(request,
2792
+ target,
2793
+ options=(),
2794
+ channel_credentials=None,
2795
+ call_credentials=None,
2796
+ insecure=False,
2797
+ compression=None,
2798
+ wait_for_ready=None,
2799
+ timeout=None,
2800
+ metadata=None):
2801
+ return grpc.experimental.unary_unary(
2802
+ request,
2803
+ target,
2804
+ '/terminal.TerminalStreamingService/BrowserNetworkClear',
2805
+ rpc__messages_dot_browser__pb2.BrowserNetworkClearRequest.SerializeToString,
2806
+ rpc__messages_dot_browser__pb2.BrowserNetworkClearResponse.FromString,
2807
+ options,
2808
+ channel_credentials,
2809
+ insecure,
2810
+ call_credentials,
2811
+ compression,
2812
+ wait_for_ready,
2813
+ timeout,
2814
+ metadata,
2815
+ _registered_method=True)
2816
+
2817
+ @staticmethod
2818
+ def BrowserNetworkStats(request,
2819
+ target,
2820
+ options=(),
2821
+ channel_credentials=None,
2822
+ call_credentials=None,
2823
+ insecure=False,
2824
+ compression=None,
2825
+ wait_for_ready=None,
2826
+ timeout=None,
2827
+ metadata=None):
2828
+ return grpc.experimental.unary_unary(
2829
+ request,
2830
+ target,
2831
+ '/terminal.TerminalStreamingService/BrowserNetworkStats',
2832
+ rpc__messages_dot_browser__pb2.BrowserNetworkStatsRequest.SerializeToString,
2833
+ rpc__messages_dot_browser__pb2.BrowserNetworkStatsResponse.FromString,
2834
+ options,
2835
+ channel_credentials,
2836
+ insecure,
2837
+ call_credentials,
2838
+ compression,
2839
+ wait_for_ready,
2840
+ timeout,
2841
+ metadata,
2842
+ _registered_method=True)
2843
+
2844
+ @staticmethod
2845
+ def BrowserNetworkExportHAR(request,
2846
+ target,
2847
+ options=(),
2848
+ channel_credentials=None,
2849
+ call_credentials=None,
2850
+ insecure=False,
2851
+ compression=None,
2852
+ wait_for_ready=None,
2853
+ timeout=None,
2854
+ metadata=None):
2855
+ return grpc.experimental.unary_unary(
2856
+ request,
2857
+ target,
2858
+ '/terminal.TerminalStreamingService/BrowserNetworkExportHAR',
2859
+ rpc__messages_dot_browser__pb2.BrowserNetworkExportHARRequest.SerializeToString,
2860
+ rpc__messages_dot_browser__pb2.BrowserNetworkExportHARResponse.FromString,
2861
+ options,
2862
+ channel_credentials,
2863
+ insecure,
2864
+ call_credentials,
2865
+ compression,
2866
+ wait_for_ready,
2867
+ timeout,
2868
+ metadata,
2869
+ _registered_method=True)
cmdop/client.py CHANGED
@@ -439,15 +439,9 @@ class AsyncCMDOPClient:
439
439
  @property
440
440
  def browser(self) -> AsyncBrowserService:
441
441
  """
442
- Async browser service for direct programmatic control.
442
+ Async browser service (stub - not implemented).
443
443
 
444
- Provides: create_session, navigate, click, type, extract, etc.
445
-
446
- Example:
447
- >>> async with client.browser.create_session() as session:
448
- ... await session.navigate("https://google.com")
449
- ... await session.type("input[name='q']", "Python")
450
- ... results = await session.extract(".result-title")
444
+ Use sync CMDOPClient.browser instead.
451
445
  """
452
446
  if self._browser is None:
453
447
  self._browser = AsyncBrowserService(self._transport)
@@ -1,46 +1,59 @@
1
- """Browser automation service.
2
-
3
- Structure:
4
- browser/
5
- models.py - Data models (BrowserCookie, BrowserState)
6
- js.py - JavaScript code builders
7
- base/ - Base classes (BaseSession, BaseServiceMixin)
8
- sync/ - Sync implementation (BrowserSession, BrowserService)
9
- aio/ - Async implementation (AsyncBrowserSession, AsyncBrowserService)
1
+ """Browser SDK with capability-based API.
10
2
 
11
3
  Usage:
12
- # Sync
13
- with client.browser.create_session() as session:
4
+ from cmdop.services.browser import BrowserSession
5
+
6
+ with service.create_session() as session:
14
7
  session.navigate("https://example.com")
15
- data = session.fetch_all(urls, headers={"Accept": "application/json"})
16
8
 
17
- # Async
18
- async with client.browser.create_session() as session:
19
- await session.navigate("https://example.com")
20
- data = await session.fetch_all(urls, headers={"Accept": "application/json"})
21
- """
9
+ # Capabilities
10
+ session.scroll.js("down", 500)
11
+ session.scroll.to_bottom()
22
12
 
23
- from cmdop.services.browser.models import BrowserCookie, BrowserState, PageInfo, ScrollResult, raise_browser_error
13
+ session.input.click_js(".button")
14
+ session.input.key("Escape")
24
15
 
25
- # Sync
26
- from cmdop.services.browser.sync.session import BrowserSession
27
- from cmdop.services.browser.sync.service import BrowserService
16
+ session.timing.wait(1000)
28
17
 
29
- # Async
30
- from cmdop.services.browser.aio.session import AsyncBrowserSession
31
- from cmdop.services.browser.aio.service import AsyncBrowserService
18
+ soup = session.dom.soup()
19
+ data = session.fetch.json("/api/data")
20
+ """
21
+
22
+ from .session import BrowserSession
23
+ from .service.sync import BrowserService
24
+ from .service.aio import AsyncBrowserService
25
+ from .models import (
26
+ BrowserCookie,
27
+ BrowserState,
28
+ PageInfo,
29
+ ScrollResult,
30
+ ScrollInfo,
31
+ InfiniteScrollResult,
32
+ )
33
+ from .capabilities import (
34
+ ScrollCapability,
35
+ InputCapability,
36
+ TimingCapability,
37
+ DOMCapability,
38
+ FetchCapability,
39
+ )
32
40
 
33
41
  __all__ = [
42
+ # Session & Service
43
+ "BrowserSession",
44
+ "BrowserService",
45
+ "AsyncBrowserService",
34
46
  # Models
35
47
  "BrowserCookie",
36
48
  "BrowserState",
37
49
  "PageInfo",
38
50
  "ScrollResult",
39
- "raise_browser_error",
40
- # Sync
41
- "BrowserSession",
42
- "BrowserService",
43
- # Async
44
- "AsyncBrowserSession",
45
- "AsyncBrowserService",
51
+ "ScrollInfo",
52
+ "InfiniteScrollResult",
53
+ # Capabilities
54
+ "ScrollCapability",
55
+ "InputCapability",
56
+ "TimingCapability",
57
+ "DOMCapability",
58
+ "FetchCapability",
46
59
  ]
@@ -0,0 +1,17 @@
1
+ """Browser capabilities."""
2
+
3
+ from .scroll import ScrollCapability
4
+ from .input import InputCapability
5
+ from .timing import TimingCapability
6
+ from .dom import DOMCapability
7
+ from .fetch import FetchCapability
8
+ from .network import NetworkCapability
9
+
10
+ __all__ = [
11
+ "ScrollCapability",
12
+ "InputCapability",
13
+ "TimingCapability",
14
+ "DOMCapability",
15
+ "FetchCapability",
16
+ "NetworkCapability",
17
+ ]
@@ -0,0 +1,28 @@
1
+ """Base capability class."""
2
+
3
+ from __future__ import annotations
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ if TYPE_CHECKING:
7
+ from ..session import BrowserSession
8
+
9
+
10
+ class BaseCapability:
11
+ """Base class for all capabilities.
12
+
13
+ Capabilities group related browser operations and delegate
14
+ actual execution to the session.
15
+ """
16
+
17
+ __slots__ = ("_s",)
18
+
19
+ def __init__(self, session: "BrowserSession") -> None:
20
+ self._s = session
21
+
22
+ def _js(self, script: str) -> str:
23
+ """Execute JS via session."""
24
+ return self._s.execute_script(script)
25
+
26
+ def _call(self, method: str, *args: Any, **kwargs: Any) -> Any:
27
+ """Call service method via session."""
28
+ return self._s._call_service(method, *args, **kwargs)
@@ -0,0 +1,16 @@
1
+ """Shared parsing helpers for capabilities."""
2
+
3
+ from typing import Any
4
+ from cmdop.services.browser.js import parse_json_result
5
+
6
+
7
+ def to_dict(raw: str) -> dict[str, Any]:
8
+ """Parse JS result to dict, default empty."""
9
+ result = parse_json_result(raw)
10
+ return result if isinstance(result, dict) else {}
11
+
12
+
13
+ def to_list(raw: str) -> list[Any]:
14
+ """Parse JS result to list, default empty."""
15
+ result = parse_json_result(raw)
16
+ return result if isinstance(result, list) else []
@@ -0,0 +1,76 @@
1
+ """DOM capability."""
2
+
3
+ from __future__ import annotations
4
+ from typing import TYPE_CHECKING
5
+
6
+ from cmdop.services.browser.js import build_select_js, build_close_modal_js
7
+ from cmdop.services.browser.parsing import parse_html, SoupWrapper
8
+
9
+ from ._base import BaseCapability
10
+ from ._helpers import to_dict
11
+
12
+ if TYPE_CHECKING:
13
+ from bs4 import BeautifulSoup
14
+
15
+
16
+ class DOMCapability(BaseCapability):
17
+ """DOM operations: extraction, forms, modals.
18
+
19
+ Usage:
20
+ html = session.dom.html()
21
+ soup = session.dom.soup()
22
+ session.dom.select("#country", value="US")
23
+ """
24
+
25
+ def html(self, selector: str | None = None) -> str:
26
+ """Get page HTML."""
27
+ return self._call("get_html", selector)
28
+
29
+ def text(self, selector: str | None = None) -> str:
30
+ """Get page text content."""
31
+ return self._call("get_text", selector)
32
+
33
+ def soup(self, selector: str | None = None) -> SoupWrapper:
34
+ """Get HTML as SoupWrapper with chainable API."""
35
+ return SoupWrapper(html=self.html(selector))
36
+
37
+ def parse(self, html: str | None = None, selector: str | None = None) -> "BeautifulSoup":
38
+ """Parse HTML with BeautifulSoup."""
39
+ if html is None:
40
+ html = self.html(selector)
41
+ return parse_html(html)
42
+
43
+ def select(
44
+ self,
45
+ selector: str,
46
+ value: str | None = None,
47
+ text: str | None = None,
48
+ ) -> dict:
49
+ """Select dropdown option by value or text."""
50
+ js = build_select_js(selector, value, text)
51
+ return to_dict(self._js(js))
52
+
53
+ def close_modal(self, selectors: list[str] | None = None) -> bool:
54
+ """Try to close modal/dialog."""
55
+ js = build_close_modal_js(selectors)
56
+ return to_dict(self._js(js)).get("success", False)
57
+
58
+ def extract(
59
+ self, selector: str, attr: str | None = None, limit: int = 100
60
+ ) -> list[str]:
61
+ """Extract text or attribute from elements."""
62
+ return self._call("extract", selector, attr, limit)
63
+
64
+ def extract_regex(
65
+ self, pattern: str, from_html: bool = False, limit: int = 100
66
+ ) -> list[str]:
67
+ """Extract matches using regex pattern."""
68
+ return self._call("extract_regex", pattern, from_html, limit)
69
+
70
+ def validate_selectors(self, item: str, fields: dict[str, str]) -> dict:
71
+ """Validate CSS selectors on page."""
72
+ return self._call("validate_selectors", item, fields)
73
+
74
+ def extract_data(self, item: str, fields_json: str, limit: int = 100) -> dict:
75
+ """Extract structured data from page."""
76
+ return self._call("extract_data", item, fields_json, limit)