hyperbrowser 0.90.1__tar.gz → 0.90.3__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.
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/PKG-INFO +30 -1
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/README.md +29 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/async_client.py +2 -0
- hyperbrowser-0.90.3/hyperbrowser/client/managers/async_manager/volume.py +26 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sandboxes/shared.py +23 -6
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/sandboxes/sandbox_files.py +2 -2
- hyperbrowser-0.90.3/hyperbrowser/client/managers/sync_manager/volume.py +26 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/sync.py +2 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/__init__.py +9 -0
- hyperbrowser-0.90.3/hyperbrowser/models/_parsers.py +11 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/sandbox.py +12 -10
- hyperbrowser-0.90.3/hyperbrowser/models/volume.py +29 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/sandbox_common.py +50 -2
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/pyproject.toml +1 -1
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/LICENSE +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/__init__.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/base.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/agents/__init__.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/agents/browser_use.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/agents/claude_computer_use.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/agents/cua.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/agents/gemini_computer_use.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/agents/hyper_agent.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/computer_action.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/crawl.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/extension.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/extract.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/profile.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/sandbox.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/sandboxes/__init__.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/sandboxes/sandbox_files.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/sandboxes/sandbox_processes.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/sandboxes/sandbox_terminal.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/sandboxes/sandbox_transport.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/scrape.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/session.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/team.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/web/__init__.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/web/batch_fetch.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/web/crawl.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sandboxes/__init__.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/agents/__init__.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/agents/browser_use.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/agents/claude_computer_use.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/agents/cua.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/agents/gemini_computer_use.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/agents/hyper_agent.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/computer_action.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/crawl.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/extension.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/extract.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/profile.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/sandbox.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/sandboxes/__init__.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/sandboxes/sandbox_processes.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/sandboxes/sandbox_terminal.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/sandboxes/sandbox_transport.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/scrape.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/session.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/team.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/web/__init__.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/web/batch_fetch.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/web/crawl.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/config.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/exceptions.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/agents/browser_use.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/agents/claude_computer_use.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/agents/cua.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/agents/gemini_computer_use.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/agents/hyper_agent.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/computer_action.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/consts.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/crawl.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/extension.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/extract.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/profile.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/scrape.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/session.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/team.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/web/batch_fetch.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/web/common.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/web/crawl.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/web/fetch.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/web/search.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/tools/__init__.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/tools/anthropic.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/tools/openai.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/tools/schema.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/transport/async_transport.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/transport/base.py +0 -0
- {hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/transport/sync.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hyperbrowser
|
|
3
|
-
Version: 0.90.
|
|
3
|
+
Version: 0.90.3
|
|
4
4
|
Summary: Python SDK for hyperbrowser
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -156,6 +156,35 @@ client.close()
|
|
|
156
156
|
|
|
157
157
|
`cpu`, `memory_mib`, and `disk_mib` are only supported for image launches.
|
|
158
158
|
|
|
159
|
+
### Manage volumes and mount them in a sandbox
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from hyperbrowser import Hyperbrowser
|
|
163
|
+
from hyperbrowser.models import CreateSandboxParams, CreateVolumeParams, SandboxVolumeMount
|
|
164
|
+
|
|
165
|
+
client = Hyperbrowser(api_key="test-key")
|
|
166
|
+
|
|
167
|
+
volume = client.volumes.create(CreateVolumeParams(name="project-cache"))
|
|
168
|
+
all_volumes = client.volumes.list()
|
|
169
|
+
same_volume = client.volumes.get(volume.id)
|
|
170
|
+
|
|
171
|
+
sandbox = client.sandboxes.create(
|
|
172
|
+
CreateSandboxParams(
|
|
173
|
+
image_name="node",
|
|
174
|
+
mounts={
|
|
175
|
+
"/workspace/cache": SandboxVolumeMount(
|
|
176
|
+
id=same_volume.id,
|
|
177
|
+
type="rw",
|
|
178
|
+
shared=True,
|
|
179
|
+
)
|
|
180
|
+
},
|
|
181
|
+
)
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
sandbox.stop()
|
|
185
|
+
client.close()
|
|
186
|
+
```
|
|
187
|
+
|
|
159
188
|
### List sandboxes with filters
|
|
160
189
|
|
|
161
190
|
```python
|
|
@@ -130,6 +130,35 @@ client.close()
|
|
|
130
130
|
|
|
131
131
|
`cpu`, `memory_mib`, and `disk_mib` are only supported for image launches.
|
|
132
132
|
|
|
133
|
+
### Manage volumes and mount them in a sandbox
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from hyperbrowser import Hyperbrowser
|
|
137
|
+
from hyperbrowser.models import CreateSandboxParams, CreateVolumeParams, SandboxVolumeMount
|
|
138
|
+
|
|
139
|
+
client = Hyperbrowser(api_key="test-key")
|
|
140
|
+
|
|
141
|
+
volume = client.volumes.create(CreateVolumeParams(name="project-cache"))
|
|
142
|
+
all_volumes = client.volumes.list()
|
|
143
|
+
same_volume = client.volumes.get(volume.id)
|
|
144
|
+
|
|
145
|
+
sandbox = client.sandboxes.create(
|
|
146
|
+
CreateSandboxParams(
|
|
147
|
+
image_name="node",
|
|
148
|
+
mounts={
|
|
149
|
+
"/workspace/cache": SandboxVolumeMount(
|
|
150
|
+
id=same_volume.id,
|
|
151
|
+
type="rw",
|
|
152
|
+
shared=True,
|
|
153
|
+
)
|
|
154
|
+
},
|
|
155
|
+
)
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
sandbox.stop()
|
|
159
|
+
client.close()
|
|
160
|
+
```
|
|
161
|
+
|
|
133
162
|
### List sandboxes with filters
|
|
134
163
|
|
|
135
164
|
```python
|
|
@@ -14,6 +14,7 @@ from .managers.async_manager.scrape import ScrapeManager
|
|
|
14
14
|
from .managers.async_manager.session import SessionManager
|
|
15
15
|
from .managers.async_manager.team import TeamManager
|
|
16
16
|
from .managers.async_manager.computer_action import ComputerActionManager
|
|
17
|
+
from .managers.async_manager.volume import VolumeManager
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
class AsyncHyperbrowser(HyperbrowserBase):
|
|
@@ -47,6 +48,7 @@ class AsyncHyperbrowser(HyperbrowserBase):
|
|
|
47
48
|
self.team = TeamManager(self)
|
|
48
49
|
self.computer_action = ComputerActionManager(self)
|
|
49
50
|
self.sandboxes = SandboxManager(self)
|
|
51
|
+
self.volumes = VolumeManager(self)
|
|
50
52
|
|
|
51
53
|
async def close(self) -> None:
|
|
52
54
|
await self.transport.close()
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from hyperbrowser.models.volume import CreateVolumeParams, Volume, VolumeListResponse
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class VolumeManager:
|
|
5
|
+
def __init__(self, client):
|
|
6
|
+
self._client = client
|
|
7
|
+
|
|
8
|
+
async def create(self, params: CreateVolumeParams) -> Volume:
|
|
9
|
+
if not isinstance(params, CreateVolumeParams):
|
|
10
|
+
raise TypeError("params must be a CreateVolumeParams instance")
|
|
11
|
+
|
|
12
|
+
response = await self._client.transport.post(
|
|
13
|
+
self._client._build_url("/volume"),
|
|
14
|
+
data=params.model_dump(exclude_none=True, by_alias=True),
|
|
15
|
+
)
|
|
16
|
+
return Volume(**response.data)
|
|
17
|
+
|
|
18
|
+
async def list(self) -> VolumeListResponse:
|
|
19
|
+
response = await self._client.transport.get(self._client._build_url("/volume"))
|
|
20
|
+
return VolumeListResponse(**response.data)
|
|
21
|
+
|
|
22
|
+
async def get(self, volume_id: str) -> Volume:
|
|
23
|
+
response = await self._client.transport.get(
|
|
24
|
+
self._client._build_url(f"/volume/{volume_id}")
|
|
25
|
+
)
|
|
26
|
+
return Volume(**response.data)
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sandboxes/shared.py
RENAMED
|
@@ -17,6 +17,7 @@ from ....sandbox_common import (
|
|
|
17
17
|
RUNTIME_SESSION_REFRESH_BUFFER_MS,
|
|
18
18
|
normalize_network_error,
|
|
19
19
|
parse_error_payload,
|
|
20
|
+
runtime_base_url_session_id,
|
|
20
21
|
)
|
|
21
22
|
|
|
22
23
|
DEFAULT_WATCH_TIMEOUT_MS = 60_000
|
|
@@ -84,13 +85,31 @@ def _normalize_exec_params(
|
|
|
84
85
|
return _normalize_legacy_process_fields(normalized)
|
|
85
86
|
|
|
86
87
|
|
|
88
|
+
def _resolve_sandbox_runtime_session_host(runtime, base_url) -> str:
|
|
89
|
+
session_id_from_base_path = runtime_base_url_session_id(base_url.path)
|
|
90
|
+
if session_id_from_base_path and base_url.hostname:
|
|
91
|
+
return f"{session_id_from_base_path}.{base_url.hostname}"
|
|
92
|
+
|
|
93
|
+
runtime_host = str(getattr(runtime, "host", "") or "").strip()
|
|
94
|
+
if runtime_host:
|
|
95
|
+
parsed_host = urlsplit(runtime_host)
|
|
96
|
+
if parsed_host.hostname:
|
|
97
|
+
session_id_from_host_path = runtime_base_url_session_id(parsed_host.path)
|
|
98
|
+
if session_id_from_host_path:
|
|
99
|
+
return f"{session_id_from_host_path}.{parsed_host.hostname}"
|
|
100
|
+
return parsed_host.hostname
|
|
101
|
+
return runtime_host
|
|
102
|
+
|
|
103
|
+
return base_url.hostname or ""
|
|
104
|
+
|
|
105
|
+
|
|
87
106
|
def _build_sandbox_exposed_url(runtime, port: int) -> str:
|
|
88
107
|
parsed = urlsplit(runtime.base_url)
|
|
89
|
-
|
|
90
|
-
if not
|
|
108
|
+
session_host = _resolve_sandbox_runtime_session_host(runtime, parsed)
|
|
109
|
+
if not session_host:
|
|
91
110
|
return runtime.base_url
|
|
92
111
|
|
|
93
|
-
exposed_host = f"{port}-{
|
|
112
|
+
exposed_host = f"{port}-{session_host}"
|
|
94
113
|
netloc = exposed_host
|
|
95
114
|
if parsed.port:
|
|
96
115
|
netloc = f"{netloc}:{parsed.port}"
|
|
@@ -100,9 +119,7 @@ def _build_sandbox_exposed_url(runtime, port: int) -> str:
|
|
|
100
119
|
credentials = f"{credentials}:{parsed.password}"
|
|
101
120
|
netloc = f"{credentials}@{netloc}"
|
|
102
121
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return urlunsplit((parsed.scheme, netloc, path, parsed.query, parsed.fragment))
|
|
122
|
+
return urlunsplit((parsed.scheme, netloc, "/", "", ""))
|
|
106
123
|
|
|
107
124
|
|
|
108
125
|
def _expires_within_buffer(expires_at: Optional[datetime]) -> bool:
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from hyperbrowser.models.volume import CreateVolumeParams, Volume, VolumeListResponse
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class VolumeManager:
|
|
5
|
+
def __init__(self, client):
|
|
6
|
+
self._client = client
|
|
7
|
+
|
|
8
|
+
def create(self, params: CreateVolumeParams) -> Volume:
|
|
9
|
+
if not isinstance(params, CreateVolumeParams):
|
|
10
|
+
raise TypeError("params must be a CreateVolumeParams instance")
|
|
11
|
+
|
|
12
|
+
response = self._client.transport.post(
|
|
13
|
+
self._client._build_url("/volume"),
|
|
14
|
+
data=params.model_dump(exclude_none=True, by_alias=True),
|
|
15
|
+
)
|
|
16
|
+
return Volume(**response.data)
|
|
17
|
+
|
|
18
|
+
def list(self) -> VolumeListResponse:
|
|
19
|
+
response = self._client.transport.get(self._client._build_url("/volume"))
|
|
20
|
+
return VolumeListResponse(**response.data)
|
|
21
|
+
|
|
22
|
+
def get(self, volume_id: str) -> Volume:
|
|
23
|
+
response = self._client.transport.get(
|
|
24
|
+
self._client._build_url(f"/volume/{volume_id}")
|
|
25
|
+
)
|
|
26
|
+
return Volume(**response.data)
|
|
@@ -14,6 +14,7 @@ from .managers.sync_manager.scrape import ScrapeManager
|
|
|
14
14
|
from .managers.sync_manager.session import SessionManager
|
|
15
15
|
from .managers.sync_manager.team import TeamManager
|
|
16
16
|
from .managers.sync_manager.computer_action import ComputerActionManager
|
|
17
|
+
from .managers.sync_manager.volume import VolumeManager
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
class Hyperbrowser(HyperbrowserBase):
|
|
@@ -47,6 +48,7 @@ class Hyperbrowser(HyperbrowserBase):
|
|
|
47
48
|
self.team = TeamManager(self)
|
|
48
49
|
self.computer_action = ComputerActionManager(self)
|
|
49
50
|
self.sandboxes = SandboxManager(self)
|
|
51
|
+
self.volumes = VolumeManager(self)
|
|
50
52
|
|
|
51
53
|
def close(self) -> None:
|
|
52
54
|
self.transport.close()
|
|
@@ -173,6 +173,7 @@ from .profile import (
|
|
|
173
173
|
ProfileListResponse,
|
|
174
174
|
ProfileResponse,
|
|
175
175
|
)
|
|
176
|
+
from .volume import CreateVolumeParams, Volume, VolumeListResponse
|
|
176
177
|
from .scrape import (
|
|
177
178
|
BatchScrapeJobResponse,
|
|
178
179
|
BatchScrapeJobStatusResponse,
|
|
@@ -245,6 +246,8 @@ from .sandbox import (
|
|
|
245
246
|
Sandbox,
|
|
246
247
|
SandboxDetail,
|
|
247
248
|
SandboxRuntimeSession,
|
|
249
|
+
SandboxVolumeMountType,
|
|
250
|
+
SandboxVolumeMount,
|
|
248
251
|
CreateSandboxParams,
|
|
249
252
|
StartSandboxFromSnapshotParams,
|
|
250
253
|
SandboxListParams,
|
|
@@ -450,6 +453,10 @@ __all__ = [
|
|
|
450
453
|
"ProfileListParams",
|
|
451
454
|
"ProfileListResponse",
|
|
452
455
|
"ProfileResponse",
|
|
456
|
+
# volume
|
|
457
|
+
"CreateVolumeParams",
|
|
458
|
+
"Volume",
|
|
459
|
+
"VolumeListResponse",
|
|
453
460
|
# scrape
|
|
454
461
|
"BatchScrapeJobResponse",
|
|
455
462
|
"BatchScrapeJobStatusResponse",
|
|
@@ -499,6 +506,8 @@ __all__ = [
|
|
|
499
506
|
"Sandbox",
|
|
500
507
|
"SandboxDetail",
|
|
501
508
|
"SandboxRuntimeSession",
|
|
509
|
+
"SandboxVolumeMountType",
|
|
510
|
+
"SandboxVolumeMount",
|
|
502
511
|
"CreateSandboxParams",
|
|
503
512
|
"StartSandboxFromSnapshotParams",
|
|
504
513
|
"SandboxListParams",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def _parse_optional_int(value: Any):
|
|
5
|
+
if value is None or isinstance(value, int):
|
|
6
|
+
return value
|
|
7
|
+
if isinstance(value, str) and value.strip() == "":
|
|
8
|
+
return None
|
|
9
|
+
if isinstance(value, str):
|
|
10
|
+
return int(value)
|
|
11
|
+
return value
|
|
@@ -3,6 +3,7 @@ from typing import Callable, Dict, List, Literal, Optional, Union
|
|
|
3
3
|
|
|
4
4
|
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
|
5
5
|
|
|
6
|
+
from ._parsers import _parse_optional_int
|
|
6
7
|
from .session import SessionLaunchState, SessionStatus
|
|
7
8
|
|
|
8
9
|
SandboxStatus = SessionStatus
|
|
@@ -29,6 +30,7 @@ SandboxFileEncoding = Literal["utf8", "base64"]
|
|
|
29
30
|
SandboxFileReadFormat = Literal["text", "bytes", "blob", "stream"]
|
|
30
31
|
SandboxFileWatchRoute = Literal["ws", "stream"]
|
|
31
32
|
SandboxFileSystemEventType = Literal["chmod", "create", "remove", "rename", "write"]
|
|
33
|
+
SandboxVolumeMountType = Literal["rw", "ro"]
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
def _parse_optional_datetime(value):
|
|
@@ -37,16 +39,6 @@ def _parse_optional_datetime(value):
|
|
|
37
39
|
return value
|
|
38
40
|
|
|
39
41
|
|
|
40
|
-
def _parse_optional_int(value):
|
|
41
|
-
if value is None or isinstance(value, int):
|
|
42
|
-
return value
|
|
43
|
-
if isinstance(value, str) and value.strip() == "":
|
|
44
|
-
return None
|
|
45
|
-
if isinstance(value, str):
|
|
46
|
-
return int(value)
|
|
47
|
-
return value
|
|
48
|
-
|
|
49
|
-
|
|
50
42
|
def _parse_optional_datetime_from_millis(value):
|
|
51
43
|
if value in (None, ""):
|
|
52
44
|
return None
|
|
@@ -95,6 +87,12 @@ class SandboxUnexposeResult(SandboxBaseModel):
|
|
|
95
87
|
exposed: bool
|
|
96
88
|
|
|
97
89
|
|
|
90
|
+
class SandboxVolumeMount(SandboxBaseModel):
|
|
91
|
+
id: str
|
|
92
|
+
type: Optional[SandboxVolumeMountType] = None
|
|
93
|
+
shared: Optional[bool] = None
|
|
94
|
+
|
|
95
|
+
|
|
98
96
|
class Sandbox(SandboxBaseModel):
|
|
99
97
|
id: str
|
|
100
98
|
team_id: str = Field(alias="teamId")
|
|
@@ -180,6 +178,10 @@ class CreateSandboxParams(SandboxBaseModel):
|
|
|
180
178
|
default=None,
|
|
181
179
|
serialization_alias="exposedPorts",
|
|
182
180
|
)
|
|
181
|
+
mounts: Optional[Dict[str, SandboxVolumeMount]] = Field(
|
|
182
|
+
default=None,
|
|
183
|
+
serialization_alias="mounts",
|
|
184
|
+
)
|
|
183
185
|
timeout_minutes: Optional[int] = Field(
|
|
184
186
|
default=None, serialization_alias="timeoutMinutes"
|
|
185
187
|
)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from typing import List, Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
4
|
+
|
|
5
|
+
from ._parsers import _parse_optional_int
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class VolumeBaseModel(BaseModel):
|
|
9
|
+
model_config = ConfigDict(populate_by_name=True)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CreateVolumeParams(VolumeBaseModel):
|
|
13
|
+
name: str
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Volume(VolumeBaseModel):
|
|
17
|
+
id: str
|
|
18
|
+
name: str
|
|
19
|
+
size: Optional[int] = None
|
|
20
|
+
transfer_amount: Optional[int] = Field(default=None, alias="transferAmount")
|
|
21
|
+
|
|
22
|
+
@field_validator("size", "transfer_amount", mode="before")
|
|
23
|
+
@classmethod
|
|
24
|
+
def parse_optional_int_fields(cls, value):
|
|
25
|
+
return _parse_optional_int(value)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class VolumeListResponse(VolumeBaseModel):
|
|
29
|
+
volumes: List[Volume]
|
|
@@ -114,13 +114,61 @@ def has_scheme(value: str) -> bool:
|
|
|
114
114
|
return "://" in value
|
|
115
115
|
|
|
116
116
|
|
|
117
|
+
def runtime_base_url_session_id(runtime_base_url: str) -> Optional[str]:
|
|
118
|
+
parsed_base_url = urlsplit(runtime_base_url.strip())
|
|
119
|
+
segments = [
|
|
120
|
+
segment
|
|
121
|
+
for segment in parsed_base_url.path.strip().strip("/").split("/")
|
|
122
|
+
if segment
|
|
123
|
+
]
|
|
124
|
+
if len(segments) < 2 or segments[0] != "sandbox" or not segments[1].strip():
|
|
125
|
+
return None
|
|
126
|
+
return segments[1].strip()
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def should_prepend_sandbox_to_runtime_api(runtime_base_url: str) -> bool:
|
|
130
|
+
return runtime_base_url_session_id(runtime_base_url) is None
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def normalize_runtime_api_path(pathname: str, prepend_sandbox: bool) -> str:
|
|
134
|
+
trimmed = pathname.strip()
|
|
135
|
+
if trimmed == "":
|
|
136
|
+
return "/sandbox" if prepend_sandbox else "/"
|
|
137
|
+
|
|
138
|
+
absolute = trimmed if trimmed.startswith("/") else f"/{trimmed}"
|
|
139
|
+
if prepend_sandbox:
|
|
140
|
+
if absolute == "/sandbox" or absolute.startswith("/sandbox/"):
|
|
141
|
+
return absolute
|
|
142
|
+
return f"/sandbox{absolute}"
|
|
143
|
+
|
|
144
|
+
if absolute == "/sandbox":
|
|
145
|
+
return "/"
|
|
146
|
+
if absolute.startswith("/sandbox/"):
|
|
147
|
+
return f"/{absolute[len('/sandbox/'):]}"
|
|
148
|
+
return absolute
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def normalize_runtime_relative_path(base_url: str, path: str) -> str:
|
|
152
|
+
trimmed = path.strip()
|
|
153
|
+
if trimmed == "":
|
|
154
|
+
return ""
|
|
155
|
+
|
|
156
|
+
parsed_path = urlsplit(trimmed)
|
|
157
|
+
prepend_sandbox = should_prepend_sandbox_to_runtime_api(base_url)
|
|
158
|
+
normalized_path = normalize_runtime_api_path(parsed_path.path, prepend_sandbox)
|
|
159
|
+
relative_path = normalized_path.lstrip("/")
|
|
160
|
+
return urlunsplit(
|
|
161
|
+
("", "", relative_path, parsed_path.query, parsed_path.fragment)
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
|
|
117
165
|
def resolve_runtime_transport_target(
|
|
118
166
|
base_url: str,
|
|
119
167
|
path: str,
|
|
120
168
|
runtime_proxy_override: Optional[str] = None,
|
|
121
169
|
) -> RuntimeTransportTarget:
|
|
122
170
|
normalized_base = base_url if base_url.endswith("/") else f"{base_url}/"
|
|
123
|
-
url = urljoin(normalized_base, path
|
|
171
|
+
url = urljoin(normalized_base, normalize_runtime_relative_path(base_url, path))
|
|
124
172
|
|
|
125
173
|
if not runtime_proxy_override:
|
|
126
174
|
return RuntimeTransportTarget(url=url)
|
|
@@ -151,7 +199,7 @@ def to_websocket_transport_target(
|
|
|
151
199
|
runtime_proxy_override: Optional[str] = None,
|
|
152
200
|
) -> RuntimeTransportTarget:
|
|
153
201
|
normalized_base = base_url if base_url.endswith("/") else f"{base_url}/"
|
|
154
|
-
url = urljoin(normalized_base, path
|
|
202
|
+
url = urljoin(normalized_base, normalize_runtime_relative_path(base_url, path))
|
|
155
203
|
parts = urlsplit(url)
|
|
156
204
|
scheme = parts.scheme
|
|
157
205
|
if scheme == "https":
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/agents/cua.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/crawl.py
RENAMED
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/extension.py
RENAMED
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/extract.py
RENAMED
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/profile.py
RENAMED
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/sandbox.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/scrape.py
RENAMED
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/session.py
RENAMED
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/team.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/async_manager/web/crawl.py
RENAMED
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sandboxes/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/agents/cua.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/crawl.py
RENAMED
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/extension.py
RENAMED
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/extract.py
RENAMED
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/profile.py
RENAMED
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/sandbox.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/scrape.py
RENAMED
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/session.py
RENAMED
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/team.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/client/managers/sync_manager/web/crawl.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/agents/claude_computer_use.py
RENAMED
|
File without changes
|
|
File without changes
|
{hyperbrowser-0.90.1 → hyperbrowser-0.90.3}/hyperbrowser/models/agents/gemini_computer_use.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|