@ceki/sdk 1.9.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ceki.me
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,272 @@
1
+ # ceki-browser
2
+
3
+ TypeScript/Node.js SDK for [ceki.me](https://ceki.me) — rent real browsers from real people for AI agent automation.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install ceki-browser
9
+ ```
10
+
11
+ For the CLI (global):
12
+
13
+ ```bash
14
+ npm install -g ceki-browser
15
+ ```
16
+
17
+ ## Quickstart
18
+
19
+ ```typescript
20
+ import { connect } from 'ceki-browser';
21
+
22
+ const client = await connect(process.env.CEKI_API_KEY!);
23
+ const options = await client.search({ geo: 'US', language: 'en' });
24
+ const browser = await client.rent(options[0].schedule_id);
25
+
26
+ await browser.navigate('https://example.com');
27
+ const snap = await browser.snapshot();
28
+ // snap.screenshot — base64 PNG, snap.chat — new messages
29
+
30
+ await browser.close();
31
+ await client.close();
32
+ ```
33
+
34
+ ## Environment Variables
35
+
36
+ | Variable | Description |
37
+ |---|---|
38
+ | `CEKI_API_KEY` | Your API key (required) |
39
+ | `CEKI_API_URL` | Override REST API base URL |
40
+ | `CEKI_RELAY_URL` | Override relay WebSocket URL |
41
+ | `CEKI_CHAT_URL` | Override chat API base URL |
42
+ | `CEKI_BASIC_AUTH_USER` / `CEKI_BASIC_AUTH_PASS` | nginx htpasswd credentials |
43
+
44
+ ## API
45
+
46
+ ### `connect(apiKey, options?) -> Client`
47
+
48
+ Establish a WebSocket connection to the relay. Returns a `Client` instance.
49
+
50
+ ### `ConnectOptions`
51
+
52
+ | Field | Default | Description |
53
+ |---|---|---|
54
+ | `apiUrl` | `https://api.ceki.me` | REST API base URL |
55
+ | `relayUrl` | `wss://browser.ceki.me/ws/agent` | Relay WebSocket URL |
56
+ | `chatUrl` | `https://chat.ceki.me/api/chat` | Chat API URL |
57
+ | `basicAuth` | `undefined` | `[user, password]` for nginx htpasswd |
58
+ | `reconnect` | `true` | Auto-reconnect on disconnect |
59
+
60
+ ### `client.search(filters?, limit?) -> BrowserOption[]`
61
+
62
+ Search for available browsers. Filters: `geo`, `language`, etc.
63
+
64
+ ### `client.rent(scheduleId, opts?) -> Browser`
65
+
66
+ Rent a browser by schedule ID. Waits up to 60s for a match. Options:
67
+ - `human` — `'natural'` (default), `'careful'`, or `null` (no humanization)
68
+ - `maskingMode` — enable masking
69
+ - `fingerprint` — `true`, `false`, or fingerprint object
70
+
71
+ ### `client.resume(sessionId, opts?) -> Browser`
72
+
73
+ Resume an existing session within its 120s grace window.
74
+
75
+ ### `client.close()`
76
+
77
+ Close all sessions and the connection.
78
+
79
+ ## Browser Methods
80
+
81
+ ```typescript
82
+ await browser.navigate(url) // Navigate to URL
83
+ await browser.click(x, y) // Click at coordinates
84
+ await browser.type(text) // Type text (char-by-char with humanizer)
85
+ await browser.scroll({ deltaY: -300 }) // Scroll
86
+ await browser.screenshot({ format: 'png' }) // Screenshot as Buffer
87
+ await browser.screenshot({ format: 'base64' }) // Screenshot as {data: string}
88
+ await browser.snapshot() // Screenshot + chat history
89
+ await browser.switchTab() // Switch browser tab
90
+ await browser.configure({ maskingMode: true }) // Configure session
91
+ await browser.upload(selector, pathOrBuffer) // Upload file to input
92
+ await browser.send({ method, params }) // Raw CDP command
93
+ await browser.close() // End session (alias: release)
94
+ await browser.waitUntilEnded() // Block until session ends
95
+ ```
96
+
97
+ ## Chat
98
+
99
+ ```typescript
100
+ await browser.chat.send('Please solve the captcha')
101
+ await browser.chat.sendImage('/tmp/screenshot.png')
102
+ const messages = await browser.chat.history({ since: ts, limit: 50 })
103
+ browser.chat.onMessage(msg => console.log(msg.text))
104
+ ```
105
+
106
+ ## Profile (cookies + storage)
107
+
108
+ ```typescript
109
+ // Export profile
110
+ const profile = await browser.profile.export({
111
+ domains: ['.reddit.com', 'reddit.com'],
112
+ });
113
+ fs.writeFileSync('profile.json', JSON.stringify(profile));
114
+
115
+ // Import profile in next session
116
+ const saved = JSON.parse(fs.readFileSync('profile.json', 'utf-8'));
117
+ await browser.profile.import(saved);
118
+ ```
119
+
120
+ ## Human Mode
121
+
122
+ Browser actions include human-like timing by default — delays before/after actions and per-character typing with jitter.
123
+
124
+ ```typescript
125
+ // Default: natural profile (enabled by default)
126
+ const browser = await client.rent(scheduleId);
127
+
128
+ // Explicit profile
129
+ const browser = await client.rent(scheduleId, { human: 'careful' });
130
+
131
+ // Disable humanization
132
+ const browser = await client.rent(scheduleId, { human: null });
133
+ ```
134
+
135
+ ### Environment overrides
136
+
137
+ - `CEKI_HUMAN_PROFILE` — Override default profile name (`careful`)
138
+ - `CEKI_HUMAN_PROFILE_PATH` — Path to custom JSON profile file
139
+ - `CEKI_HUMAN_DISABLE=1` — Disable humanization entirely
140
+
141
+ ## Error Classes
142
+
143
+ | Exception | Cause |
144
+ |---|---|
145
+ | `AuthError` | Invalid API key or token revoked |
146
+ | `RateLimitExceeded` | Too many requests. Has `.retryAfter` (seconds) |
147
+ | `InsufficientFunds` | Account balance too low |
148
+ | `SessionEnded` | Provider ended the session. Has `.reason` |
149
+ | `SessionNotFound` | Session ID not found |
150
+ | `SessionExpired` | Session grace window expired |
151
+ | `NotOwner` | Not the session owner |
152
+ | `CdpUnrecoverable` | CDP connection lost permanently |
153
+ | `ConnectionLost` | Relay connection lost after max reconnects |
154
+ | `TimeoutError` | Operation timed out |
155
+ | `TransportError` | WebSocket or HTTP transport error |
156
+ | `ChatSendFailed` | Chat message failed to send |
157
+
158
+ ## CLI
159
+
160
+ Both SDKs install a single `ceki-browser` binary on your PATH. Same command set whether you came from Python or Node.js.
161
+
162
+ ### Install
163
+
164
+ Python:
165
+ ```bash
166
+ pip install ceki-browser
167
+ ```
168
+
169
+ Node.js:
170
+ ```bash
171
+ npm install -g ceki-browser
172
+ ```
173
+
174
+ ### Environment variables
175
+
176
+ | Variable | Required | Purpose |
177
+ |---|---|---|
178
+ | `CEKI_API_KEY` | yes | Agent token (`ag_...`) |
179
+ | `CEKI_API_URL` | no | Override API base URL (default: `https://api.ceki.me`) |
180
+ | `CEKI_RELAY_URL` | no | Override relay WS URL (default: `wss://browser.ceki.me/ws/agent`) |
181
+ | `CEKI_CHAT_URL` | no | Override chat-service URL |
182
+ | `CEKI_BASIC_AUTH_USER` / `_PASS` | no | HTTP Basic Auth for protected dev/stage endpoints |
183
+
184
+ ### Quick start
185
+
186
+ ```bash
187
+ export CEKI_API_KEY=ag_...
188
+
189
+ SCHEDULE=$(ceki-browser search --limit 1 | jq -r '.[0].schedule_id')
190
+ SID=$(ceki-browser rent --schedule $SCHEDULE | jq -r .session_id)
191
+ ceki-browser navigate $SID https://example.com
192
+ ceki-browser snapshot $SID -o snap.png
193
+ ceki-browser stop $SID
194
+ ```
195
+
196
+ The CLI persists session state locally — after `rent` it saves the session ID so subsequent commands resume it by SID without re-renting.
197
+
198
+ ### Commands
199
+
200
+ #### Discovery and lifecycle
201
+
202
+ | Command | Description |
203
+ |---|---|
204
+ | `search [--limit N] [--filter K=V]…` | List available browsers |
205
+ | `my-browsers` | List browsers with pre-arranged rent contracts |
206
+ | `rent --schedule ID [--mode incognito\|main] [--fingerprint-from FILE]` | Rent a browser |
207
+ | `sessions [--all] [--limit N] [--json]` | List your sessions |
208
+ | `stop SID` | End a session |
209
+ | `wait SID` | Block until the session ends |
210
+
211
+ #### Browser control
212
+
213
+ | Command | Description |
214
+ |---|---|
215
+ | `navigate SID URL` | Open URL |
216
+ | `click SID X Y` | Click at viewport coordinates |
217
+ | `type SID TEXT [--natural]` | Type text into focused element |
218
+ | `scroll SID X Y DY` | Scroll from (X, Y) by `DY` pixels |
219
+ | `screenshot SID -o FILE [--format png\|jpeg] [--full]` | Save screenshot |
220
+ | `snapshot SID -o FILE` | Screenshot + new chat messages |
221
+ | `switch-tab SID` | Switch active tab |
222
+ | `upload SID --selector CSS --file PATH [--filename NAME]` | Attach file to `<input type="file">` |
223
+
224
+ #### Chat with host
225
+
226
+ | Command | Description |
227
+ |---|---|
228
+ | `chat SID send TEXT` | Send message to host |
229
+ | `chat SID next [--timeout SEC]` | Wait for next host message |
230
+ | `chat SID history [--since TS] [--limit N]` | Fetch chat history |
231
+ | `chat SID send-image --image PATH [--text MSG]` | Send image to host |
232
+
233
+ #### Advanced
234
+
235
+ | Command | Description |
236
+ |---|---|
237
+ | `profile SID export -o FILE [--domains CSV] [--no-session-storage]` | Export cookies / localStorage |
238
+ | `profile SID import -i FILE` | Import previously exported profile |
239
+ | `request-captcha SID [--acceptance SEC] [--completion SEC] [--manual]` | Ask host to solve CAPTCHA |
240
+ | `configure SID [--masking-mode VAL] [--fingerprint VAL]` | Toggle masking / fingerprint |
241
+ | `cdp SID --method METHOD [--params JSON]` | Raw CDP command |
242
+
243
+ ### Output and errors
244
+
245
+ Successful commands write a single JSON line to stdout. Errors go to stderr as `{"error": "...", "code": "..."}`. Pipe stdout through `jq` to chain commands.
246
+
247
+ ### Exit codes
248
+
249
+ | Code | Meaning |
250
+ |---|---|
251
+ | `0` | success |
252
+ | `1` | generic error |
253
+ | `2` | `CEKI_API_KEY` not set |
254
+ | `3` | session not found or not owner |
255
+ | `4` | timeout |
256
+ | `5` | network / connection error |
257
+ | `130` | interrupted (Ctrl-C) |
258
+
259
+ Full reference (with EN+RU): https://browser.ceki.me/docs#cli
260
+
261
+ ## Development
262
+
263
+ ```bash
264
+ npm install
265
+ npm run typecheck
266
+ npm test
267
+ npm run build
268
+ ```
269
+
270
+ ## License
271
+
272
+ MIT