oblien 2.1.5 → 2.1.7

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/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  Cloud workspaces that boot in milliseconds and run anything.
4
4
 
5
- Oblien gives you hardware-isolated microVMs -- each with its own kernel, its own memory, and full root access. Use them to give an AI agent a live environment, deploy a service with a public URL, run untrusted code in a throwaway sandbox, or spin up a dev machine you can SSH into. The workspace is the only primitive. What it becomes is up to you.
5
+ Oblien gives you hardware-isolated microVMs each with its own kernel, its own memory, and full root access. Use them to give an AI agent a live environment, deploy a service with a public URL, run untrusted code in a throwaway sandbox, or spin up a dev machine you can SSH into. The workspace is the only primitive. What it becomes is up to you.
6
6
 
7
- This is the official TypeScript SDK. It covers the full Oblien API surface: workspace lifecycle, networking, snapshots, workloads, metrics, SSH, public access, and the in-workspace runtime (files, exec, terminal, search, watchers, WebSocket).
7
+ This is the official TypeScript SDK. It covers the full Oblien API surface.
8
8
 
9
9
  **Documentation:** [https://oblien.com/docs](https://oblien.com/docs)
10
10
 
@@ -12,23 +12,23 @@ This is the official TypeScript SDK. It covers the full Oblien API surface: work
12
12
 
13
13
  ## Platform
14
14
 
15
- Oblien is a workspace platform. Every workspace is a microVM that boots in under a second from any Docker image. Workspaces can be temporary (auto-delete after a TTL) or permanent (run indefinitely). They can be air-gapped or wired to other workspaces over a private internal network. They can expose ports to the internet through Oblien's edge proxy with automatic TLS -- or stay completely invisible.
15
+ Oblien is a workspace platform. Every workspace is a microVM that boots in under a second from any Docker image. Workspaces can be temporary (auto-delete after a TTL) or permanent (run indefinitely). They can be air-gapped or wired to other workspaces over a private internal network. They can expose ports to the internet with automatic TLS or stay completely invisible.
16
16
 
17
17
  The architecture is split into two planes:
18
18
 
19
- - **Control plane** (`api.oblien.com`) -- Create, configure, start, stop, snapshot, and destroy workspaces. Manage networking, firewall rules, SSH keys, workloads, images, billing, and metadata.
20
- - **Data plane** (`workspace.oblien.com`) -- Interact with a running workspace's filesystem, execute commands, open terminal sessions, watch files, and stream events over WebSocket.
19
+ - **Control plane** (`api.oblien.com`) Create, configure, start, stop, snapshot, and destroy workspaces. Manage networking, domains, pages, namespaces, and billing.
20
+ - **Data plane** (`workspace.oblien.com`) Interact with a running workspace's filesystem, execute commands, open terminal sessions, watch files, and stream events over WebSocket.
21
21
 
22
22
  The SDK wraps both planes in a single client.
23
23
 
24
24
  ### What people build with it
25
25
 
26
- - **AI agent environments** -- A permanent workspace is the agent's home. It creates short-lived sandboxes on demand for tasks, user code, or deployments.
27
- - **Service hosting** -- Run an API server, a queue worker, or a database as a permanent workspace. Map it to a custom domain.
28
- - **Remote development** -- SSH into a workspace, install your stack, expose a port for live preview.
29
- - **CI/CD** -- Spin up ephemeral workspaces per build, run tests in full isolation, auto-destroy when done.
30
- - **Code sandboxes** -- Air-gapped throwaway VMs that auto-delete after a TTL. No internet, no persistence.
31
- - **Per-user environments** -- One workspace per customer with scoped networking, credit quotas, and full isolation.
26
+ - **AI agent environments** A permanent workspace is the agent's home. It creates short-lived sandboxes on demand for tasks, user code, or deployments.
27
+ - **Service hosting** Run an API server, a queue worker, or a database. Map it to a custom domain.
28
+ - **Static pages** Deploy build output from a workspace to the edge CDN. No running VM required.
29
+ - **Remote development** SSH into a workspace, install your stack, expose a port for live preview.
30
+ - **Per-user environments** One workspace per customer with scoped networking, credit quotas, and full isolation.
31
+ - **Enterprise routing** Route subdomains to external upstreams through the edge proxy.
32
32
 
33
33
  ---
34
34
 
@@ -52,20 +52,16 @@ const client = new Oblien({
52
52
  clientSecret: process.env.OBLIEN_CLIENT_SECRET,
53
53
  });
54
54
 
55
- const ws = client.workspaces;
56
-
57
55
  // Create a workspace
58
- const workspace = await ws.create({
56
+ const workspace = await client.workspaces.create({
59
57
  image: 'node-20',
60
58
  mode: 'permanent',
61
- config: { cpus: 2, memory_mb: 4096 },
59
+ cpus: 2,
60
+ memory_mb: 4096,
62
61
  });
63
62
 
64
- // Start it
65
- await ws.start(workspace.id);
66
-
67
- // Connect to the runtime -- filesystem, exec, terminal
68
- const rt = await ws.runtime(workspace.id);
63
+ // Connect to the runtime — filesystem, exec, terminal
64
+ const rt = await client.workspaces.runtime(workspace.id);
69
65
 
70
66
  // Run a command
71
67
  const result = await rt.exec.run(['node', '--version']);
@@ -74,454 +70,188 @@ console.log(result.stdout);
74
70
  // Read a file
75
71
  const file = await rt.files.read({ filePath: '/etc/os-release' });
76
72
  console.log(file.content);
77
-
78
- // Expose port 3000 to the internet
79
- await ws.publicAccess.expose(workspace.id, { port: 3000 });
80
73
  ```
81
74
 
82
75
  ---
83
76
 
84
- ## Architecture
85
-
86
- ### Client and workspaces
77
+ ## SDK structure
87
78
 
88
- ```typescript
89
- import Oblien from 'oblien';
90
-
91
- const client = new Oblien({ clientId, clientSecret });
92
- const ws = client.workspaces;
79
+ ```
80
+ client
81
+ ├── workspaces Control-plane workspace CRUD + power + sub-resources
82
+ │ ├── lifecycle Permanent/temporary mode, TTL, ping
83
+ │ ├── network Firewall, private links, outbound IP
84
+ │ ├── ssh SSH enable/disable, password/key
85
+ │ ├── publicAccess Expose ports with public URLs
86
+ │ ├── domains Custom domains with automatic SSL
87
+ │ ├── resources CPU, memory, disk allocation
88
+ │ ├── snapshots Snapshots and versioned archives
89
+ │ ├── workloads Managed background processes
90
+ │ ├── metrics Live stats, VM info/config
91
+ │ ├── usage Credit usage and activity tracking
92
+ │ ├── metadata Key-value metadata store
93
+ │ ├── apiAccess Runtime API tokens (gateway JWT / raw)
94
+ │ ├── logs Boot and command logs
95
+ │ └── images Available base images
96
+
97
+ ├── pages Static pages — deploy to the edge CDN from any workspace
98
+ ├── namespaces Group workspaces, enforce resource limits and quotas
99
+ ├── edgeProxy Enterprise reverse proxy — route subdomains to upstreams
100
+ ├── domain Pre-flight checks — slug availability + DNS verification
101
+
102
+ └── workspace(id) Scoped handle — all methods pre-filled with a workspace ID
93
103
  ```
94
104
 
95
- `client.workspaces` is the entry point for all control-plane operations. It provides CRUD methods, power controls, and 13 sub-resource namespaces:
105
+ ---
96
106
 
97
- | Namespace | Description |
98
- |-----------|-------------|
99
- | `ws.lifecycle` | Permanent/temporary mode, TTL, ping, destroy |
100
- | `ws.network` | Firewall rules, private links, outbound IP |
101
- | `ws.ssh` | Enable SSH, set password or public key |
102
- | `ws.publicAccess` | Expose and revoke public ports |
103
- | `ws.resources` | CPU, memory, disk allocation |
104
- | `ws.snapshots` | Create, restore, archive, and manage snapshots |
105
- | `ws.workloads` | Managed background processes with log streaming |
106
- | `ws.metrics` | Live CPU/memory/disk/network stats, VM info and config |
107
- | `ws.usage` | Credit usage, activity tracking |
108
- | `ws.metadata` | Key-value metadata store |
109
- | `ws.apiAccess` | Runtime API server -- enable, disable, rotate tokens |
110
- | `ws.logs` | Boot and command logs |
111
- | `ws.images` | Available workspace images |
112
-
113
- ### CRUD
107
+ ## Workspaces
114
108
 
115
109
  ```typescript
116
- // Create
117
- const workspace = await ws.create({ image: 'node-20', mode: 'permanent' });
118
-
119
- // List
120
- const { workspaces } = await ws.list({ page: 1, limit: 20 });
121
-
122
- // Get
123
- const data = await ws.get('ws_a1b2c3d4');
124
-
125
- // Update
126
- await ws.update('ws_a1b2c3d4', { name: 'production-api' });
127
-
128
- // Delete
129
- await ws.delete('ws_a1b2c3d4');
130
- ```
110
+ const ws = client.workspaces;
131
111
 
132
- ### Power controls
112
+ // CRUD
113
+ const workspace = await ws.create({ image: 'node-20' });
114
+ const { workspaces } = await ws.list();
115
+ const data = await ws.get(workspace.id);
116
+ await ws.update(workspace.id, { name: 'my-api' });
117
+ await ws.delete(workspace.id);
133
118
 
134
- ```typescript
119
+ // Power
135
120
  await ws.start(id);
136
121
  await ws.stop(id);
137
122
  await ws.restart(id);
138
- await ws.pause(id); // preserves memory state
123
+ await ws.pause(id);
139
124
  await ws.resume(id);
140
- await ws.ping(id); // renews TTL for temporary workspaces
141
- ```
142
-
143
- ### Account-level queries
144
-
145
- ```typescript
146
- const quota = await ws.getQuota();
147
- const estimate = await ws.getEstimate({ cpu: 4, ram_mb: 8192 });
148
- ```
149
-
150
- ---
151
-
152
- ## Runtime (data plane)
153
-
154
- The runtime connects to a running workspace and provides direct access to its filesystem, command execution, terminal sessions, search, and file watchers.
155
-
156
- ```typescript
157
- const rt = await ws.runtime('ws_a1b2c3d4');
158
125
  ```
159
126
 
160
- This call enables the workspace's Runtime API server (if not already enabled), fetches a gateway JWT, and returns a `Runtime` instance. The token is cached -- subsequent calls for the same workspace return instantly.
161
-
162
- ### Files
163
-
164
- ```typescript
165
- // List directory
166
- const entries = await rt.files.list({ dirPath: '/app' });
167
-
168
- // Read file
169
- const { content } = await rt.files.read({ filePath: '/app/index.js' });
170
-
171
- // Write file
172
- await rt.files.write({ fullPath: '/app/config.json', content: '{}' });
127
+ Sub-resources are accessed through namespaces on the workspaces object `ws.lifecycle`, `ws.network`, `ws.domains`, etc. See the [API reference](https://oblien.com/docs/api) for full details on each.
173
128
 
174
- // Create directory
175
- await rt.files.mkdir({ path: '/app/logs' });
129
+ ### Scoped handle
176
130
 
177
- // Stat
178
- const stat = await rt.files.stat({ path: '/app/index.js' });
179
-
180
- // Delete
181
- await rt.files.delete({ path: '/app/tmp' });
182
-
183
- // Stream directory tree (async generator)
184
- for await (const entry of rt.files.stream({ dirPath: '/app' })) {
185
- console.log(entry.path);
186
- }
187
- ```
188
-
189
- ### Exec
131
+ Bind to a single workspace so you don't have to pass the ID every time:
190
132
 
191
133
  ```typescript
192
- // Run a command and wait for result
193
- const result = await rt.exec.run(['npm', 'test']);
194
- console.log(result.exitCode, result.stdout, result.stderr);
195
-
196
- // Stream output as it happens (async generator)
197
- for await (const event of rt.exec.stream(['npm', 'run', 'build'])) {
198
- process.stdout.write(event.data);
199
- }
200
-
201
- // List running tasks
202
- const tasks = await rt.exec.list();
203
-
204
- // Kill a task
205
- await rt.exec.kill(taskId);
134
+ const handle = client.workspace('ws_abc');
206
135
 
207
- // Send stdin to a running task
208
- await rt.exec.input(taskId, 'yes\n');
209
-
210
- // Subscribe to a running task's output
211
- for await (const event of rt.exec.subscribe(taskId)) {
212
- console.log(event);
213
- }
136
+ await handle.start();
137
+ const rt = await handle.runtime();
138
+ await rt.exec.run(['npm', 'test']);
139
+ await handle.stop();
214
140
  ```
215
141
 
216
- ### Terminal
217
-
218
- ```typescript
219
- // Create a terminal session
220
- const session = await rt.terminal.create({ shell: '/bin/bash' });
221
-
222
- // List sessions
223
- const sessions = await rt.terminal.list();
224
-
225
- // Get scrollback buffer
226
- const { data } = await rt.terminal.scrollback(session.id, { bytes: 4096 });
142
+ ---
227
143
 
228
- // Close session
229
- await rt.terminal.close(session.id);
230
- ```
144
+ ## Runtime (data plane)
231
145
 
232
- ### Search
146
+ The runtime connects to a running workspace and gives you direct access to its filesystem, command execution, terminal sessions, code search, and file watchers.
233
147
 
234
148
  ```typescript
235
- // Search file contents (ripgrep)
236
- const hits = await rt.search.content({ query: 'TODO', path: '/app' });
237
-
238
- // Search file names
239
- const files = await rt.search.files({ query: 'config', path: '/app' });
240
-
241
- // Index status and initialization
242
- const status = await rt.search.status();
243
- await rt.search.init();
149
+ const rt = await client.workspaces.runtime('ws_abc');
244
150
  ```
245
151
 
246
- ### Watcher
247
-
248
- ```typescript
249
- // Watch a directory for changes
250
- const watcher = await rt.watcher.create({ path: '/app/src' });
251
-
252
- // List active watchers
253
- const watchers = await rt.watcher.list();
152
+ This enables the Runtime API server (if needed), fetches a gateway JWT, and returns a `Runtime` instance. The token is cached — subsequent calls for the same workspace return instantly.
254
153
 
255
- // Get watcher info
256
- const info = await rt.watcher.get(watcher.id);
154
+ | Namespace | What it does |
155
+ |-----------|-------------|
156
+ | `rt.files` | List, read, write, stat, mkdir, delete, stream directory trees |
157
+ | `rt.exec` | Run commands, stream output, list/kill tasks, send stdin |
158
+ | `rt.terminal` | Create PTY sessions, get scrollback, close sessions |
159
+ | `rt.search` | Content search (ripgrep) and filename search |
160
+ | `rt.watcher` | Watch directories for real-time file change events |
161
+ | `rt.ws()` | WebSocket — persistent connection for terminal I/O and watcher events |
257
162
 
258
- // Stop watching
259
- await rt.watcher.delete(watcher.id);
260
- ```
163
+ See the [Runtime API docs](https://oblien.com/docs/runtime-api) for full endpoint reference.
261
164
 
262
165
  ---
263
166
 
264
- ## WebSocket
167
+ ## Pages
265
168
 
266
- For real-time terminal I/O and file watcher events, open a persistent WebSocket connection:
169
+ Deploy static files from a workspace to the edge CDN. The workspace can stop or be deleted after export — the page stays live with automatic TLS.
267
170
 
268
171
  ```typescript
269
- const socket = rt.ws();
270
-
271
- socket.onOpen(() => {
272
- console.log('connected');
273
- });
274
-
275
- socket.onTerminalOutput((data) => {
276
- process.stdout.write(data.output);
277
- });
278
-
279
- socket.onWatcherEvent((event) => {
280
- console.log(event.type, event.path);
281
- });
282
-
283
- socket.onClose(() => {
284
- console.log('disconnected');
172
+ // Deploy a page
173
+ const { page } = await client.pages.create({
174
+ workspace_id: 'ws_abc',
175
+ path: '/app/dist',
176
+ name: 'my-app',
285
177
  });
286
178
 
287
- socket.onError((err) => {
288
- console.error(err);
179
+ // Re-deploy with fresh files
180
+ await client.pages.deploy(page.slug, {
181
+ workspace_id: 'ws_abc',
182
+ path: '/app/dist',
289
183
  });
290
184
 
291
- await socket.connect();
185
+ // Custom domain
186
+ await client.pages.connectDomain(page.slug, { domain: 'app.example.com' });
292
187
 
293
- // Send input to a terminal
294
- socket.writeTerminalInput(sessionId, 'ls -la\n');
295
-
296
- // Resize terminal
297
- socket.resizeTerminal(sessionId, { cols: 120, rows: 40 });
188
+ // Toggle
189
+ await client.pages.disable(page.slug);
190
+ await client.pages.enable(page.slug);
298
191
  ```
299
192
 
300
- ---
301
-
302
- ## SSE streaming
303
-
304
- Several endpoints return server-sent events as async generators. Consume them with `for await`:
305
-
306
- ```typescript
307
- // Stream workspace logs
308
- for await (const line of ws.logs.streamBoot(id)) {
309
- console.log(line);
310
- }
311
-
312
- // Stream workload output
313
- for await (const event of ws.workloads.logsStream(id, workloadId)) {
314
- process.stdout.write(event.data);
315
- }
316
-
317
- // Stream live metrics
318
- for await (const snapshot of ws.metrics.statsStream(id)) {
319
- console.log(snapshot.cpu_percent, snapshot.memory_used_mb);
320
- }
321
-
322
- // Stream workload stats
323
- for await (const stats of ws.workloads.statsStream(id, workloadId)) {
324
- console.log(stats);
325
- }
326
- ```
193
+ See the [Pages docs](https://oblien.com/docs/concepts/pages) for concepts and the [Pages API](https://oblien.com/docs/api/pages) for the full reference.
327
194
 
328
195
  ---
329
196
 
330
- ## Sub-resources
331
-
332
- ### Lifecycle
333
-
334
- ```typescript
335
- const status = await ws.lifecycle.get(id);
336
-
337
- // Convert to permanent
338
- await ws.lifecycle.makePermanent(id);
339
-
340
- // Convert to temporary with TTL
341
- await ws.lifecycle.makeTemporary(id, { ttl_seconds: 3600 });
342
-
343
- // Update TTL
344
- await ws.lifecycle.updateTtl(id, { ttl_seconds: 7200 });
345
-
346
- // Destroy (irreversible)
347
- await ws.lifecycle.destroy(id);
348
- ```
197
+ ## Domains
349
198
 
350
- ### Network
199
+ Pre-flight checks before connecting custom domains or claiming slugs. These are standalone — not scoped to a specific workspace or page.
351
200
 
352
201
  ```typescript
353
- const network = await ws.network.get(id);
202
+ // Check if a slug is available
203
+ const { available, url } = await client.domain.checkSlug({ slug: 'my-app' });
354
204
 
355
- await ws.network.update(id, {
356
- ingress: ['10.0.1.5'],
357
- egress: ['10.0.1.10'],
358
- allow_internet: false,
205
+ // Verify DNS for a custom domain
206
+ const { verified, cname, required_records } = await client.domain.verify({
207
+ domain: 'app.example.com',
208
+ resource_id: 'ws_abc',
359
209
  });
360
-
361
- // Assign a dedicated outbound IP
362
- await ws.network.applyOutboundIp(id, { ip: '203.0.113.50' });
363
210
  ```
364
211
 
365
- ### SSH
212
+ ---
366
213
 
367
- ```typescript
368
- await ws.ssh.enable(id, { password: 'secure-password' });
369
- await ws.ssh.enable(id, { publicKey: 'ssh-ed25519 AAAA...' });
370
- await ws.ssh.disable(id);
371
- const sshStatus = await ws.ssh.status(id);
372
- ```
214
+ ## Namespaces
373
215
 
374
- ### Public access
216
+ Group workspaces into isolated namespaces with resource limits, spending quotas, and lifecycle controls.
375
217
 
376
218
  ```typescript
377
- // Expose a port
378
- const endpoint = await ws.publicAccess.expose(id, {
379
- port: 3000,
380
- domain: 'app.yourdomain.com',
219
+ const ns = await client.namespaces.create({
220
+ name: 'production',
221
+ resource_limits: { max_workspaces: 50, max_cpus: 100 },
381
222
  });
382
223
 
383
- // List exposed ports
384
- const ports = await ws.publicAccess.list(id);
385
-
386
- // Revoke
387
- await ws.publicAccess.revoke(id, { port: 3000 });
388
- ```
389
-
390
- ### Snapshots
391
-
392
- ```typescript
393
- // Create a snapshot
394
- await ws.snapshots.create(id, { label: 'before-deploy' });
395
-
396
- // Restore
397
- await ws.snapshots.restore(id);
398
-
399
- // Archives
400
- await ws.snapshots.createArchive(id, { label: 'v1.0' });
401
- const archives = await ws.snapshots.listArchives(id);
402
- const archive = await ws.snapshots.getArchive(id, 'v1');
403
- await ws.snapshots.deleteArchive(id, 'v1');
404
- await ws.snapshots.deleteAllArchives(id);
405
- ```
406
-
407
- ### Workloads
408
-
409
- ```typescript
410
- // Create a managed workload
411
- await ws.workloads.create(id, {
412
- name: 'server',
413
- cmd: ['node', 'server.js'],
414
- env: { PORT: '3000' },
224
+ await client.namespaces.setQuota(ns.id, {
225
+ period: 'monthly',
226
+ max_credits: 500,
227
+ overdraft_action: 'stop',
415
228
  });
416
229
 
417
- const workloads = await ws.workloads.list(id);
418
- const workload = await ws.workloads.get(id, workloadId);
419
- await ws.workloads.start(id, workloadId);
420
- await ws.workloads.stop(id, workloadId);
421
- await ws.workloads.delete(id, workloadId);
422
-
423
- // Logs and stats (async generators)
424
- for await (const line of ws.workloads.logsStream(id, workloadId)) {
425
- console.log(line);
426
- }
427
- for await (const snapshot of ws.workloads.statsStream(id, workloadId)) {
428
- console.log(snapshot);
429
- }
230
+ const { namespaces } = await client.namespaces.list();
430
231
  ```
431
232
 
432
- ### Metrics
433
-
434
- ```typescript
435
- const stats = await ws.metrics.stats(id);
436
- const info = await ws.metrics.info(id);
437
- const config = await ws.metrics.config(id);
438
-
439
- for await (const snapshot of ws.metrics.statsStream(id)) {
440
- console.log(snapshot);
441
- }
442
- ```
443
-
444
- ### Usage
445
-
446
- ```typescript
447
- const usage = await ws.usage.get(id);
448
- const totals = await ws.usage.totals(id);
449
- const chart = await ws.usage.creditsChart(id);
450
- const global = await ws.usage.global();
451
- const activity = await ws.usage.activity();
452
- await ws.usage.wipe(id);
453
- ```
454
-
455
- ### Metadata
456
-
457
- ```typescript
458
- const meta = await ws.metadata.get(id);
459
- await ws.metadata.update(id, { key: 'env', value: 'production' });
460
- await ws.metadata.patch(id, { key: 'version', value: '2.1.0' });
461
- ```
462
-
463
- ### API access
464
-
465
- ```typescript
466
- const status = await ws.apiAccess.status(id);
467
- const access = await ws.apiAccess.enable(id);
468
- await ws.apiAccess.disable(id);
469
- await ws.apiAccess.rotateToken(id);
470
- const token = await ws.apiAccess.getToken(id);
471
- const raw = await ws.apiAccess.rawToken(id);
472
- ```
473
-
474
- ### Logs
475
-
476
- ```typescript
477
- const log = await ws.logs.get(id);
478
- await ws.logs.clear(id);
479
- const files = await ws.logs.listFiles(id);
480
- const file = await ws.logs.getFile(id, 'boot.log');
481
-
482
- for await (const line of ws.logs.streamBoot(id)) {
483
- console.log(line);
484
- }
485
- for await (const line of ws.logs.streamCmd(id)) {
486
- console.log(line);
487
- }
488
- ```
489
-
490
- ### Images
491
-
492
- ```typescript
493
- const images = await ws.images.list();
494
- const image = await ws.images.get('node-20');
495
- ```
233
+ See the [Namespaces API](https://oblien.com/docs/api/namespaces) for the full reference.
496
234
 
497
235
  ---
498
236
 
499
- ## Standalone imports
237
+ ## Edge Proxy
500
238
 
501
- The SDK exports `Workspace` and `Runtime` as standalone classes for cases where you need direct access without going through the main client:
239
+ Enterprise-only reverse proxy route subdomains to external upstreams through the edge.
502
240
 
503
241
  ```typescript
504
- // Workspace (control plane) -- standalone
505
- import { Workspace } from 'oblien/workspace';
506
-
507
- const ws = new Workspace(client);
508
- await ws.create({ image: 'python-3.12' });
509
-
510
- // Runtime (data plane) -- standalone with a raw token
511
- import { Runtime } from 'oblien/runtime';
512
-
513
- const rt = new Runtime({
514
- token: 'your_gateway_jwt',
242
+ const { proxy } = await client.edgeProxy.create({
243
+ name: 'staging-api',
244
+ slug: 'staging-api',
245
+ domain: 'edge.example.com',
246
+ target: 'https://internal-staging.example.com:8080',
515
247
  });
516
- await rt.files.list({ dirPath: '/' });
517
248
 
518
- // Runtime with a direct IP (bypass edge proxy)
519
- const directRt = new Runtime({
520
- token: 'raw_token',
521
- baseUrl: 'http://10.0.1.5:9990',
522
- });
249
+ await client.edgeProxy.disable(proxy.id);
250
+ await client.edgeProxy.enable(proxy.id);
523
251
  ```
524
252
 
253
+ See the [Edge Proxy docs](https://oblien.com/docs/concepts/edge-proxy) for details.
254
+
525
255
  ---
526
256
 
527
257
  ## Error handling
@@ -529,44 +259,24 @@ const directRt = new Runtime({
529
259
  Every API error is an instance of `OblienError` with typed subclasses:
530
260
 
531
261
  ```typescript
532
- import Oblien, {
533
- OblienError,
534
- AuthenticationError,
535
- NotFoundError,
536
- RateLimitError,
537
- ValidationError,
538
- PaymentRequiredError,
539
- ConflictError,
540
- } from 'oblien';
262
+ import { NotFoundError, RateLimitError, PaymentRequiredError } from 'oblien';
541
263
 
542
264
  try {
543
- await ws.get('ws_nonexistent');
265
+ await client.workspaces.get('ws_nonexistent');
544
266
  } catch (err) {
545
- if (err instanceof NotFoundError) {
546
- console.log('Workspace does not exist');
547
- } else if (err instanceof AuthenticationError) {
548
- console.log('Bad credentials');
549
- } else if (err instanceof RateLimitError) {
550
- console.log('Slow down -- retry after backoff');
551
- } else if (err instanceof PaymentRequiredError) {
552
- console.log('Quota exceeded -- upgrade your plan');
553
- } else if (err instanceof ValidationError) {
554
- console.log('Invalid parameters:', err.message);
555
- } else if (err instanceof ConflictError) {
556
- console.log('Workspace is in the wrong state for this operation');
557
- } else if (err instanceof OblienError) {
558
- console.log(`API error ${err.status}: ${err.message}`);
559
- }
267
+ if (err instanceof NotFoundError) { /* 404 */ }
268
+ if (err instanceof RateLimitError) { /* 429 — back off */ }
269
+ if (err instanceof PaymentRequiredError) { /* 402 — quota exceeded */ }
560
270
  }
561
271
  ```
562
272
 
563
- | Error class | HTTP status | When |
564
- |-------------|-------------|------|
273
+ | Error class | HTTP | When |
274
+ |-------------|------|------|
565
275
  | `AuthenticationError` | 401 | Invalid or missing credentials |
566
276
  | `PaymentRequiredError` | 402 | Credit quota exceeded |
567
277
  | `NotFoundError` | 404 | Resource does not exist |
568
- | `ConflictError` | 409 | Resource in wrong state for the operation |
569
- | `ValidationError` | 422 | Invalid request parameters |
278
+ | `ConflictError` | 409 | Resource in wrong state |
279
+ | `ValidationError` | 422 | Invalid parameters |
570
280
  | `RateLimitError` | 429 | Too many requests |
571
281
 
572
282
  ---
@@ -581,29 +291,21 @@ const client = new Oblien({
581
291
  });
582
292
  ```
583
293
 
584
- | Option | Type | Default | Description |
585
- |--------|------|---------|-------------|
586
- | `clientId` | `string` | -- | Your API client ID |
587
- | `clientSecret` | `string` | -- | Your API client secret |
588
- | `baseUrl` | `string` | `https://api.oblien.com` | Control plane API base URL |
589
-
590
- Get your API keys from the [dashboard](https://oblien.com/dashboard).
294
+ Get your API keys from the [dashboard](https://oblien.com/dashboard/settings).
591
295
 
592
296
  ---
593
297
 
594
298
  ## TypeScript
595
299
 
596
- The SDK is written in TypeScript and ships its own type declarations. All request parameters, response shapes, and event types are fully typed and exported from the top-level package:
300
+ Written in TypeScript with full type declarations shipped. All request parameters, response shapes, and event types are exported:
597
301
 
598
302
  ```typescript
599
303
  import type {
600
- WorkspaceCreateParams,
601
- WorkspaceData,
602
- ExecTask,
603
- ExecStreamEvent,
604
- FileEntry,
605
- WSTerminalEvent,
606
- WSWatcherEvent,
304
+ WorkspaceCreateParams, WorkspaceData,
305
+ PageCreateParams, PageData,
306
+ CheckSlugParams, VerifyDomainParams,
307
+ EdgeProxyCreateParams,
308
+ ExecStreamEvent, WSTerminalEvent,
607
309
  } from 'oblien';
608
310
  ```
609
311
 
@@ -620,12 +322,11 @@ import type {
620
322
  ## Links
621
323
 
622
324
  - [Documentation](https://oblien.com/docs)
623
- - [SDK setup guide](https://oblien.com/docs/workspace/sdk-setup)
624
325
  - [Quickstart](https://oblien.com/docs/workspace/quickstart)
326
+ - [SDK setup guide](https://oblien.com/docs/workspace/sdk-setup)
625
327
  - [API reference](https://oblien.com/docs/api)
626
- - [Runtime / Runtime API](https://oblien.com/docs/runtime-api)
328
+ - [Runtime API](https://oblien.com/docs/runtime-api)
627
329
  - [Dashboard](https://oblien.com/dashboard)
628
- - [GitHub](https://github.com/oblien/sdk)
629
330
 
630
331
  ---
631
332