chaser-sdk 0.1.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.
- chaser_sdk-0.1.0/PKG-INFO +132 -0
- chaser_sdk-0.1.0/README.md +113 -0
- chaser_sdk-0.1.0/chaser_sdk/__init__.py +11 -0
- chaser_sdk-0.1.0/chaser_sdk/cdp.py +54 -0
- chaser_sdk-0.1.0/chaser_sdk/client.py +912 -0
- chaser_sdk-0.1.0/chaser_sdk/errors.py +89 -0
- chaser_sdk-0.1.0/chaser_sdk/types.py +365 -0
- chaser_sdk-0.1.0/chaser_sdk.egg-info/PKG-INFO +132 -0
- chaser_sdk-0.1.0/chaser_sdk.egg-info/SOURCES.txt +13 -0
- chaser_sdk-0.1.0/chaser_sdk.egg-info/dependency_links.txt +1 -0
- chaser_sdk-0.1.0/chaser_sdk.egg-info/requires.txt +3 -0
- chaser_sdk-0.1.0/chaser_sdk.egg-info/top_level.txt +1 -0
- chaser_sdk-0.1.0/pyproject.toml +30 -0
- chaser_sdk-0.1.0/setup.cfg +4 -0
- chaser_sdk-0.1.0/tests/test_client.py +194 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: chaser-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for Chaser
|
|
5
|
+
Author: Chaser Team
|
|
6
|
+
Keywords: chaser,sandbox,browser,microvm,automation
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Provides-Extra: cdp
|
|
18
|
+
Requires-Dist: websocket-client>=1.8.0; extra == "cdp"
|
|
19
|
+
|
|
20
|
+
# chaser-sdk
|
|
21
|
+
|
|
22
|
+
Official Python SDK for Chaser.
|
|
23
|
+
|
|
24
|
+
This package is the Python **beta** SDK for the core public Chaser surface:
|
|
25
|
+
|
|
26
|
+
- sessions
|
|
27
|
+
- workspaces
|
|
28
|
+
- exec
|
|
29
|
+
- command lifecycle
|
|
30
|
+
- files
|
|
31
|
+
- browser CDP helpers
|
|
32
|
+
- accounts and organizations
|
|
33
|
+
- service accounts and keys
|
|
34
|
+
- billing
|
|
35
|
+
- lifecycle webhooks
|
|
36
|
+
- audit
|
|
37
|
+
- jobs
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install chaser-sdk
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Optional CDP websocket support:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install 'chaser-sdk[cdp]'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Quickstart
|
|
52
|
+
|
|
53
|
+
```py
|
|
54
|
+
from chaser_sdk import ChaserClient
|
|
55
|
+
|
|
56
|
+
client = ChaserClient(api_key="sk_...", account="personal")
|
|
57
|
+
|
|
58
|
+
workspace = client.workspaces.create(
|
|
59
|
+
{
|
|
60
|
+
"name": "frontend-app",
|
|
61
|
+
"session_type": "sandbox",
|
|
62
|
+
"image": "ghcr.io/example/dev:latest",
|
|
63
|
+
}
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
session = client.sessions.create(
|
|
67
|
+
{
|
|
68
|
+
"workspace": workspace["name"],
|
|
69
|
+
"session_type": "sandbox",
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
client.sessions.wait_until_ready(session["id"])
|
|
74
|
+
result = client.exec.in_session(
|
|
75
|
+
session["id"],
|
|
76
|
+
{
|
|
77
|
+
"command": "node -v && pwd",
|
|
78
|
+
"cwd": "/workspace",
|
|
79
|
+
},
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
print(result.get("output"))
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Stateless exec
|
|
86
|
+
|
|
87
|
+
```py
|
|
88
|
+
result = client.exec.run(
|
|
89
|
+
{
|
|
90
|
+
"ephemeral": True,
|
|
91
|
+
"image": "node:20-bookworm",
|
|
92
|
+
"command": "python3 -c 'print(42)'",
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Files and previews
|
|
98
|
+
|
|
99
|
+
```py
|
|
100
|
+
client.files.upload_text(session["id"], "/workspace/hello.txt", "hello from sdk")
|
|
101
|
+
text = client.files.download_text(session["id"], "/workspace/hello.txt")
|
|
102
|
+
preview = client.sessions.forward_url(session["id"], 3000)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Browser CDP helper
|
|
106
|
+
|
|
107
|
+
```py
|
|
108
|
+
browser = client.sessions.create({"session_type": "browser", "ephemeral": True})
|
|
109
|
+
ws_url = client.browser.cdp_websocket_url(browser["id"])
|
|
110
|
+
print(ws_url)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
If you install the optional `cdp` extra, you can also open a lightweight websocket client:
|
|
114
|
+
|
|
115
|
+
```py
|
|
116
|
+
cdp = client.browser.connect(browser["id"])
|
|
117
|
+
print(cdp.send("Browser.getVersion"))
|
|
118
|
+
cdp.close()
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Organization automation
|
|
122
|
+
|
|
123
|
+
```py
|
|
124
|
+
org_client = client.with_account("Acme Engineering")
|
|
125
|
+
service_account = org_client.accounts.service_accounts.create("ci-bot")
|
|
126
|
+
key = org_client.accounts.service_accounts.keys.create(
|
|
127
|
+
service_account["id"],
|
|
128
|
+
name="ci-key",
|
|
129
|
+
scopes=["sessions.read", "workspaces.write", "exec.write", "files.read", "webhooks.write"],
|
|
130
|
+
)
|
|
131
|
+
print(key["key"])
|
|
132
|
+
```
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# chaser-sdk
|
|
2
|
+
|
|
3
|
+
Official Python SDK for Chaser.
|
|
4
|
+
|
|
5
|
+
This package is the Python **beta** SDK for the core public Chaser surface:
|
|
6
|
+
|
|
7
|
+
- sessions
|
|
8
|
+
- workspaces
|
|
9
|
+
- exec
|
|
10
|
+
- command lifecycle
|
|
11
|
+
- files
|
|
12
|
+
- browser CDP helpers
|
|
13
|
+
- accounts and organizations
|
|
14
|
+
- service accounts and keys
|
|
15
|
+
- billing
|
|
16
|
+
- lifecycle webhooks
|
|
17
|
+
- audit
|
|
18
|
+
- jobs
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install chaser-sdk
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Optional CDP websocket support:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install 'chaser-sdk[cdp]'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quickstart
|
|
33
|
+
|
|
34
|
+
```py
|
|
35
|
+
from chaser_sdk import ChaserClient
|
|
36
|
+
|
|
37
|
+
client = ChaserClient(api_key="sk_...", account="personal")
|
|
38
|
+
|
|
39
|
+
workspace = client.workspaces.create(
|
|
40
|
+
{
|
|
41
|
+
"name": "frontend-app",
|
|
42
|
+
"session_type": "sandbox",
|
|
43
|
+
"image": "ghcr.io/example/dev:latest",
|
|
44
|
+
}
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
session = client.sessions.create(
|
|
48
|
+
{
|
|
49
|
+
"workspace": workspace["name"],
|
|
50
|
+
"session_type": "sandbox",
|
|
51
|
+
}
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
client.sessions.wait_until_ready(session["id"])
|
|
55
|
+
result = client.exec.in_session(
|
|
56
|
+
session["id"],
|
|
57
|
+
{
|
|
58
|
+
"command": "node -v && pwd",
|
|
59
|
+
"cwd": "/workspace",
|
|
60
|
+
},
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
print(result.get("output"))
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Stateless exec
|
|
67
|
+
|
|
68
|
+
```py
|
|
69
|
+
result = client.exec.run(
|
|
70
|
+
{
|
|
71
|
+
"ephemeral": True,
|
|
72
|
+
"image": "node:20-bookworm",
|
|
73
|
+
"command": "python3 -c 'print(42)'",
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Files and previews
|
|
79
|
+
|
|
80
|
+
```py
|
|
81
|
+
client.files.upload_text(session["id"], "/workspace/hello.txt", "hello from sdk")
|
|
82
|
+
text = client.files.download_text(session["id"], "/workspace/hello.txt")
|
|
83
|
+
preview = client.sessions.forward_url(session["id"], 3000)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Browser CDP helper
|
|
87
|
+
|
|
88
|
+
```py
|
|
89
|
+
browser = client.sessions.create({"session_type": "browser", "ephemeral": True})
|
|
90
|
+
ws_url = client.browser.cdp_websocket_url(browser["id"])
|
|
91
|
+
print(ws_url)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
If you install the optional `cdp` extra, you can also open a lightweight websocket client:
|
|
95
|
+
|
|
96
|
+
```py
|
|
97
|
+
cdp = client.browser.connect(browser["id"])
|
|
98
|
+
print(cdp.send("Browser.getVersion"))
|
|
99
|
+
cdp.close()
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Organization automation
|
|
103
|
+
|
|
104
|
+
```py
|
|
105
|
+
org_client = client.with_account("Acme Engineering")
|
|
106
|
+
service_account = org_client.accounts.service_accounts.create("ci-bot")
|
|
107
|
+
key = org_client.accounts.service_accounts.keys.create(
|
|
108
|
+
service_account["id"],
|
|
109
|
+
name="ci-key",
|
|
110
|
+
scopes=["sessions.read", "workspaces.write", "exec.write", "files.read", "webhooks.write"],
|
|
111
|
+
)
|
|
112
|
+
print(key["key"])
|
|
113
|
+
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from .cdp import CdpClient
|
|
2
|
+
from .client import ChaserClient
|
|
3
|
+
from .errors import ChaserApiError, ChaserTimeoutError, RateLimitMetadata
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"CdpClient",
|
|
7
|
+
"ChaserApiError",
|
|
8
|
+
"ChaserClient",
|
|
9
|
+
"ChaserTimeoutError",
|
|
10
|
+
"RateLimitMetadata",
|
|
11
|
+
]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(slots=True)
|
|
9
|
+
class CdpClient:
|
|
10
|
+
websocket_url: str
|
|
11
|
+
_socket: Any = field(default=None, init=False, repr=False)
|
|
12
|
+
_next_id: int = field(default=1, init=False, repr=False)
|
|
13
|
+
|
|
14
|
+
def connect(self) -> None:
|
|
15
|
+
if self._socket is not None:
|
|
16
|
+
return
|
|
17
|
+
try:
|
|
18
|
+
import websocket # type: ignore
|
|
19
|
+
except ImportError as exc:
|
|
20
|
+
raise RuntimeError(
|
|
21
|
+
"CDP websocket support requires the optional 'websocket-client' dependency. "
|
|
22
|
+
"Install with: pip install chaser-sdk[cdp]"
|
|
23
|
+
) from exc
|
|
24
|
+
|
|
25
|
+
self._socket = websocket.create_connection(self.websocket_url)
|
|
26
|
+
|
|
27
|
+
def close(self) -> None:
|
|
28
|
+
if self._socket is not None:
|
|
29
|
+
self._socket.close()
|
|
30
|
+
self._socket = None
|
|
31
|
+
|
|
32
|
+
def send(self, method: str, params: dict[str, Any] | None = None, session_id: str | None = None) -> Any:
|
|
33
|
+
if self._socket is None:
|
|
34
|
+
raise RuntimeError("CDP websocket is not connected")
|
|
35
|
+
|
|
36
|
+
message = {
|
|
37
|
+
"id": self._next_id,
|
|
38
|
+
"method": method,
|
|
39
|
+
"params": params or {},
|
|
40
|
+
}
|
|
41
|
+
if session_id:
|
|
42
|
+
message["sessionId"] = session_id
|
|
43
|
+
request_id = self._next_id
|
|
44
|
+
self._next_id += 1
|
|
45
|
+
|
|
46
|
+
self._socket.send(json.dumps(message))
|
|
47
|
+
while True:
|
|
48
|
+
raw = self._socket.recv()
|
|
49
|
+
payload = json.loads(raw)
|
|
50
|
+
if payload.get("id") != request_id:
|
|
51
|
+
continue
|
|
52
|
+
if "error" in payload:
|
|
53
|
+
raise RuntimeError(payload["error"].get("message", "CDP request failed"))
|
|
54
|
+
return payload.get("result")
|