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.
@@ -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")