roveapi 1.0.0__tar.gz → 1.2.0__tar.gz

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.
@@ -6,3 +6,4 @@ dist/
6
6
  .DS_Store
7
7
  .turbo
8
8
  coverage/
9
+ .next/
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: roveapi
3
- Version: 1.0.0
3
+ Version: 1.2.0
4
4
  Summary: Browser automation SDK for AI agents — Playwright-as-a-Service with accessibility trees
5
5
  Project-URL: Homepage, https://roveapi.com
6
6
  Project-URL: Documentation, https://roveapi.com/docs
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "roveapi"
7
- version = "1.0.0"
7
+ version = "1.2.0"
8
8
  description = "Browser automation SDK for AI agents — Playwright-as-a-Service with accessibility trees"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -107,6 +107,7 @@ class BrowserClient:
107
107
  timezone: str | None = None,
108
108
  user_agent: str | None = None,
109
109
  block_resources: list[str] | None = None,
110
+ supervised: bool = False,
110
111
  ) -> Session:
111
112
  """Create a persistent browser session."""
112
113
  body: dict[str, Any] = {}
@@ -122,10 +123,74 @@ class BrowserClient:
122
123
  body["user_agent"] = user_agent
123
124
  if block_resources:
124
125
  body["block_resources"] = block_resources
126
+ if supervised:
127
+ body["supervised"] = True
125
128
 
126
129
  data = self._request("POST", "/v1/browser/session", json=body)
127
130
  return Session(data["session_id"], self)
128
131
 
132
+ def create_viewer_grant(self, session_id: str) -> dict[str, Any]:
133
+ """Mint a one-time, origin-bound grant for the public supervised viewer."""
134
+ from urllib.parse import urlparse
135
+ origin = f"{urlparse(self.base_url).scheme}://{urlparse(self.base_url).netloc}"
136
+ data = self._request(
137
+ "POST",
138
+ f"/v1/browser/sessions/{session_id}/viewer-grants",
139
+ json={"origin": origin},
140
+ )
141
+ return {
142
+ "admission_code": data["admission_code"],
143
+ "expires_in_seconds": data["expires_in_seconds"],
144
+ "viewer_url": data["viewer_url"],
145
+ "origin": origin,
146
+ }
147
+
148
+ def exchange_viewer_admission(self, code: str, origin: str) -> dict[str, Any]:
149
+ """Exchange a one-time admission code for viewer credentials."""
150
+ # Note: origin header required by the API
151
+ response = self._client.post(
152
+ "/viewer-admissions",
153
+ json={"code": code, "origin": origin},
154
+ headers={"origin": origin},
155
+ )
156
+ if response.is_success:
157
+ return response.json()
158
+ raise _map_error(response)
159
+
160
+ def transition_viewer_control(
161
+ self,
162
+ *,
163
+ credential: str,
164
+ origin: str,
165
+ action: str, # 'take' | 'resume' | 'return'
166
+ expected_generation: int,
167
+ ) -> dict[str, Any]:
168
+ """Take, resume, or return control of a supervised viewer session."""
169
+ response = self._client.post(
170
+ "/viewer-control",
171
+ json={
172
+ "credential": credential,
173
+ "origin": origin,
174
+ "action": action,
175
+ "expected_generation": expected_generation,
176
+ },
177
+ headers={"origin": origin},
178
+ )
179
+ if response.is_success:
180
+ return response.json()
181
+ raise _map_error(response)
182
+
183
+ def stop_viewer(self, *, credential: str, origin: str) -> dict[str, Any]:
184
+ """Stop a supervised viewer session."""
185
+ response = self._client.post(
186
+ "/viewer-stop",
187
+ json={"credential": credential, "origin": origin},
188
+ headers={"origin": origin},
189
+ )
190
+ if response.is_success:
191
+ return response.json()
192
+ raise _map_error(response)
193
+
129
194
  def screenshot(
130
195
  self,
131
196
  url: str,
File without changes
File without changes
File without changes
File without changes