oblien 1.3.0 → 2.0.1

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.
Files changed (187) hide show
  1. package/README.md +482 -422
  2. package/dist/client.d.ts +31 -0
  3. package/dist/client.d.ts.map +1 -0
  4. package/dist/client.js +33 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/error.d.ts +29 -0
  7. package/dist/error.d.ts.map +1 -0
  8. package/dist/error.js +52 -0
  9. package/dist/error.js.map +1 -0
  10. package/dist/http.d.ts +20 -0
  11. package/dist/http.d.ts.map +1 -0
  12. package/dist/http.js +108 -0
  13. package/dist/http.js.map +1 -0
  14. package/dist/index.d.ts +8 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +10 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/resources/api-access.d.ts +21 -0
  19. package/dist/resources/api-access.d.ts.map +1 -0
  20. package/dist/resources/api-access.js +32 -0
  21. package/dist/resources/api-access.js.map +1 -0
  22. package/dist/resources/base.d.ts +17 -0
  23. package/dist/resources/base.d.ts.map +1 -0
  24. package/dist/resources/base.js +21 -0
  25. package/dist/resources/base.js.map +1 -0
  26. package/dist/resources/images.d.ts +11 -0
  27. package/dist/resources/images.d.ts.map +1 -0
  28. package/dist/resources/images.js +16 -0
  29. package/dist/resources/images.js.map +1 -0
  30. package/dist/resources/lifecycle.d.ts +23 -0
  31. package/dist/resources/lifecycle.d.ts.map +1 -0
  32. package/dist/resources/lifecycle.js +32 -0
  33. package/dist/resources/lifecycle.js.map +1 -0
  34. package/dist/resources/logs.d.ts +25 -0
  35. package/dist/resources/logs.d.ts.map +1 -0
  36. package/dist/resources/logs.js +51 -0
  37. package/dist/resources/logs.js.map +1 -0
  38. package/dist/resources/metadata.d.ts +15 -0
  39. package/dist/resources/metadata.d.ts.map +1 -0
  40. package/dist/resources/metadata.js +20 -0
  41. package/dist/resources/metadata.js.map +1 -0
  42. package/dist/resources/metrics.d.ts +17 -0
  43. package/dist/resources/metrics.d.ts.map +1 -0
  44. package/dist/resources/metrics.js +27 -0
  45. package/dist/resources/metrics.js.map +1 -0
  46. package/dist/resources/network.d.ts +17 -0
  47. package/dist/resources/network.d.ts.map +1 -0
  48. package/dist/resources/network.js +20 -0
  49. package/dist/resources/network.js.map +1 -0
  50. package/dist/resources/public-access.d.ts +15 -0
  51. package/dist/resources/public-access.d.ts.map +1 -0
  52. package/dist/resources/public-access.js +21 -0
  53. package/dist/resources/public-access.js.map +1 -0
  54. package/dist/resources/resources.d.ts +15 -0
  55. package/dist/resources/resources.d.ts.map +1 -0
  56. package/dist/resources/resources.js +20 -0
  57. package/dist/resources/resources.js.map +1 -0
  58. package/dist/resources/snapshots.d.ts +27 -0
  59. package/dist/resources/snapshots.d.ts.map +1 -0
  60. package/dist/resources/snapshots.js +45 -0
  61. package/dist/resources/snapshots.js.map +1 -0
  62. package/dist/resources/ssh.d.ts +19 -0
  63. package/dist/resources/ssh.d.ts.map +1 -0
  64. package/dist/resources/ssh.js +28 -0
  65. package/dist/resources/ssh.js.map +1 -0
  66. package/dist/resources/usage.d.ts +25 -0
  67. package/dist/resources/usage.d.ts.map +1 -0
  68. package/dist/resources/usage.js +44 -0
  69. package/dist/resources/usage.js.map +1 -0
  70. package/dist/resources/workloads.d.ts +39 -0
  71. package/dist/resources/workloads.d.ts.map +1 -0
  72. package/dist/resources/workloads.js +83 -0
  73. package/dist/resources/workloads.js.map +1 -0
  74. package/dist/runtime/exec.d.ts +71 -0
  75. package/dist/runtime/exec.d.ts.map +1 -0
  76. package/dist/runtime/exec.js +163 -0
  77. package/dist/runtime/exec.js.map +1 -0
  78. package/dist/runtime/files.d.ts +39 -0
  79. package/dist/runtime/files.d.ts.map +1 -0
  80. package/dist/runtime/files.js +143 -0
  81. package/dist/runtime/files.js.map +1 -0
  82. package/dist/runtime/search.d.ts +23 -0
  83. package/dist/runtime/search.d.ts.map +1 -0
  84. package/dist/runtime/search.js +65 -0
  85. package/dist/runtime/search.js.map +1 -0
  86. package/dist/runtime/terminal.d.ts +29 -0
  87. package/dist/runtime/terminal.d.ts.map +1 -0
  88. package/dist/runtime/terminal.js +58 -0
  89. package/dist/runtime/terminal.js.map +1 -0
  90. package/dist/runtime/watcher.d.ts +27 -0
  91. package/dist/runtime/watcher.d.ts.map +1 -0
  92. package/dist/runtime/watcher.js +53 -0
  93. package/dist/runtime/watcher.js.map +1 -0
  94. package/dist/runtime/ws.d.ts +92 -0
  95. package/dist/runtime/ws.d.ts.map +1 -0
  96. package/dist/runtime/ws.js +228 -0
  97. package/dist/runtime/ws.js.map +1 -0
  98. package/dist/runtime-http.d.ts +35 -0
  99. package/dist/runtime-http.d.ts.map +1 -0
  100. package/dist/runtime-http.js +99 -0
  101. package/dist/runtime-http.js.map +1 -0
  102. package/dist/runtime.d.ts +77 -0
  103. package/dist/runtime.d.ts.map +1 -0
  104. package/dist/runtime.js +97 -0
  105. package/dist/runtime.js.map +1 -0
  106. package/dist/types/client.d.ts +7 -0
  107. package/dist/types/client.d.ts.map +1 -0
  108. package/dist/types/client.js +3 -0
  109. package/dist/types/client.js.map +1 -0
  110. package/dist/types/common.d.ts +13 -0
  111. package/dist/types/common.d.ts.map +1 -0
  112. package/dist/types/common.js +3 -0
  113. package/dist/types/common.js.map +1 -0
  114. package/dist/types/index.d.ts +8 -0
  115. package/dist/types/index.d.ts.map +1 -0
  116. package/dist/types/index.js +2 -0
  117. package/dist/types/index.js.map +1 -0
  118. package/dist/types/network.d.ts +15 -0
  119. package/dist/types/network.d.ts.map +1 -0
  120. package/dist/types/network.js +3 -0
  121. package/dist/types/network.js.map +1 -0
  122. package/dist/types/resources.d.ts +10 -0
  123. package/dist/types/resources.d.ts.map +1 -0
  124. package/dist/types/resources.js +3 -0
  125. package/dist/types/resources.js.map +1 -0
  126. package/dist/types/runtime.d.ts +302 -0
  127. package/dist/types/runtime.d.ts.map +1 -0
  128. package/dist/types/runtime.js +3 -0
  129. package/dist/types/runtime.js.map +1 -0
  130. package/dist/types/workspace-resources.d.ts +186 -0
  131. package/dist/types/workspace-resources.d.ts.map +1 -0
  132. package/dist/types/workspace-resources.js +3 -0
  133. package/dist/types/workspace-resources.js.map +1 -0
  134. package/dist/types/workspace.d.ts +41 -0
  135. package/dist/types/workspace.d.ts.map +1 -0
  136. package/dist/types/workspace.js +3 -0
  137. package/dist/types/workspace.js.map +1 -0
  138. package/dist/workspace.d.ts +135 -0
  139. package/dist/workspace.d.ts.map +1 -0
  140. package/dist/workspace.js +194 -0
  141. package/dist/workspace.js.map +1 -0
  142. package/package.json +30 -69
  143. package/LICENSE +0 -21
  144. package/agents.js +0 -14
  145. package/browser.js +0 -6
  146. package/cdn.js +0 -6
  147. package/chat.js +0 -21
  148. package/credits.js +0 -11
  149. package/icons.js +0 -11
  150. package/index.d.ts +0 -986
  151. package/index.js +0 -63
  152. package/namespaces.js +0 -12
  153. package/sandbox.js +0 -12
  154. package/search.js +0 -11
  155. package/src/agents/agent.js +0 -229
  156. package/src/agents/index.js +0 -227
  157. package/src/agents/settings.js +0 -100
  158. package/src/agents/tools.js +0 -155
  159. package/src/browser/index.js +0 -474
  160. package/src/cdn/index.js +0 -769
  161. package/src/chat/index.js +0 -724
  162. package/src/chat/session.js +0 -93
  163. package/src/client.js +0 -175
  164. package/src/credits/index.js +0 -492
  165. package/src/icons/index.js +0 -185
  166. package/src/namespaces/index.js +0 -236
  167. package/src/namespaces/namespace.js +0 -274
  168. package/src/sandbox/core/api/base.js +0 -89
  169. package/src/sandbox/core/api/database.js +0 -340
  170. package/src/sandbox/core/api/files.js +0 -141
  171. package/src/sandbox/core/api/git.js +0 -174
  172. package/src/sandbox/core/api/search.js +0 -29
  173. package/src/sandbox/core/api/snapshots.js +0 -132
  174. package/src/sandbox/core/api/terminal.js +0 -20
  175. package/src/sandbox/core/auth.js +0 -256
  176. package/src/sandbox/core/client.js +0 -197
  177. package/src/sandbox/core/index.js +0 -22
  178. package/src/sandbox/core/managers/terminal.js +0 -453
  179. package/src/sandbox/core/managers/watcher.js +0 -197
  180. package/src/sandbox/core/types.js +0 -92
  181. package/src/sandbox/core/utils/http.js +0 -89
  182. package/src/sandbox/core/websocket/connection.js +0 -479
  183. package/src/sandbox/index.d.ts +0 -542
  184. package/src/sandbox/index.js +0 -234
  185. package/src/sandbox/sandbox.js +0 -313
  186. package/src/search/index.js +0 -206
  187. package/src/utils/guest-manager.js +0 -454
package/README.md CHANGED
@@ -1,574 +1,634 @@
1
- # Oblien Core SDK
1
+ # Oblien SDK
2
2
 
3
- Complete Node.js SDK for the Oblien AI Platform. Manage agents, chat sessions, sandboxes, namespaces, and more.
3
+ Cloud workspaces that boot in milliseconds and run anything.
4
4
 
5
- ## Installation
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
- ```bash
8
- npm install oblien
9
- ```
10
-
11
- ## Quick Start
12
-
13
- ```javascript
14
- // Import client
15
- import { OblienClient } from 'oblien';
16
-
17
- // Import modules (tree-shakeable)
18
- import { OblienAgents } from 'oblien/agents'; // agent creation
19
- import { OblienChat } from 'oblien/chat'; // agent chat managment
20
- import { OblienSandboxes } from 'oblien/sandbox'; // sandbox for agent code execution
21
- import { OblienEmbeddings } from 'oblien/embeddings'; // embeddings store for semantic search
22
- import { OblienSearch } from 'oblien/search'; // search gateway for your agent
23
- import { OblienIcons } from 'oblien/icons'; // sematic based icons fetch
24
- import { OblienNamespaces } from 'oblien/namespaces'; // user and guest management
25
- import { OblienCredits } from 'oblien/credits'; // credits managemnt for your user
26
- import { OblienCDN } from 'oblien/cdn'; // cdn upload for your app
27
- import { OblienBrowser } from 'oblien/browser'; // browser api for scrap or any task
28
- import { OblienDeployments } from 'oblien/deployments'; // deployments gateway
29
-
30
- // Initialize client
31
- const client = new OblienClient({
32
- clientId: 'your-client-id',
33
- clientSecret: 'your-client-secret'
34
- });
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).
35
8
 
36
- // Use modules
37
- const agents = new OblienAgents(client);
38
- const chat = new OblienChat(client);
39
- const sandboxes = new OblienSandboxes(client);
40
- const search = new OblienSearch(client);
41
- const icons = new OblienIcons(client);
42
- ```
9
+ **Documentation:** [https://oblien.com/docs](https://oblien.com/docs)
43
10
 
44
11
  ---
45
12
 
46
- ## Modules Overview
13
+ ## Platform
47
14
 
48
- ### 🤖 Agents Module
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.
49
16
 
50
- Manage AI agents with settings, tools, and analytics.
17
+ The architecture is split into two planes:
51
18
 
52
- ```javascript
53
- import { OblienAgents } from 'oblien/agents';
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.
54
21
 
55
- const agents = new OblienAgents(client);
22
+ The SDK wraps both planes in a single client.
56
23
 
57
- // Create agent
58
- const agent = await agents.create({
59
- name: 'Support Agent',
60
- namespace: 'production',
61
- prompts: {
62
- identity: 'You are a helpful assistant.'
63
- }
64
- });
24
+ ### What people build with it
65
25
 
66
- // Configure settings
67
- const agentInstance = agents.agent(agent.agentId);
68
- await agentInstance.settings.updateModelConfig({
69
- model: 'oblien-master',
70
- temperature: 0.8
71
- });
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.
72
32
 
73
- // Assign tools
74
- await agentInstance.settings.updateTools(['web-search', 'calculator']);
33
+ ---
75
34
 
76
- // Get analytics
77
- const overview = await agentInstance.getOverview({ days: 7 });
78
- ```
35
+ ## Install
79
36
 
80
- **Features:**
81
- - CRUD operations (create, read, update, delete)
82
- - ✅ Settings management (5 sections: switches, model, tools, guest limits, context)
83
- - ✅ Tools management (list, search, create, validate)
84
- - ✅ Analytics & monitoring
85
- - ✅ Namespace support
86
- - ✅ User management
37
+ ```bash
38
+ npm install oblien
39
+ ```
87
40
 
88
- 📖 [Full Documentation](./docs/AGENTS_COMPLETE.md) | 💡 [Examples](./examples/agents-complete-example.js)
41
+ Requires Node.js 18 or later. Zero runtime dependencies.
89
42
 
90
43
  ---
91
44
 
92
- ### 💬 Chat Module
45
+ ## Quick start
93
46
 
94
- Create sessions, send messages, and manage guests with streaming support.
47
+ ```typescript
48
+ import Oblien from 'oblien';
95
49
 
96
- ```javascript
97
- import { OblienChat } from 'oblien/chat';
50
+ const client = new Oblien({
51
+ clientId: process.env.OBLIEN_CLIENT_ID,
52
+ clientSecret: process.env.OBLIEN_CLIENT_SECRET,
53
+ });
98
54
 
99
- const chat = new OblienChat(client);
55
+ const ws = client.workspaces;
100
56
 
101
- // Create session
102
- const session = await chat.createSession({
103
- agentId: 'agent-id',
104
- namespace: 'production'
57
+ // Create a workspace
58
+ const workspace = await ws.create({
59
+ image: 'node-20',
60
+ mode: 'permanent',
61
+ config: { cpus: 2, memory_mb: 4096 },
105
62
  });
106
63
 
107
- // Send message with streaming
108
- await chat.send({
109
- token: session.token,
110
- message: 'Tell me about AI',
111
- stream: true,
112
- onChunk: (data) => console.log(data)
113
- });
64
+ // Start it
65
+ await ws.start(workspace.id);
114
66
 
115
- // Upload files
116
- const uploadResult = await chat.upload({
117
- token: session.token,
118
- files: fileArray
119
- });
67
+ // Connect to the runtime -- filesystem, exec, terminal
68
+ const rt = await ws.runtime(workspace.id);
120
69
 
121
- // Send message with uploaded files
122
- await chat.send({
123
- token: session.token,
124
- message: 'Analyze these files',
125
- uploadId: uploadResult.uploadId
126
- });
70
+ // Run a command
71
+ const result = await rt.exec.run(['node', '--version']);
72
+ console.log(result.stdout);
127
73
 
128
- // Create guest session
129
- const guestSession = await chat.createGuestSession({
130
- ip: '192.168.1.1',
131
- fingerprint: 'abc123',
132
- agentId: 'agent-id'
133
- });
74
+ // Read a file
75
+ const file = await rt.files.read({ filePath: '/etc/os-release' });
76
+ console.log(file.content);
134
77
 
135
- // Get guest usage
136
- const usage = await chat.getGuestUsage(guestSession.token);
78
+ // Expose port 3000 to the internet
79
+ await ws.publicAccess.expose(workspace.id, { port: 3000 });
137
80
  ```
138
81
 
139
- **Features:**
140
- - ✅ Session management (create, list, delete)
141
- - ✅ Message sending with streaming support
142
- - ✅ File uploads for agent analysis
143
- - ✅ Guest sessions with IP + fingerprint tracking
144
- - ✅ Guest usage monitoring and rate limiting
145
- - ✅ Hybrid mode (works with token or client credentials)
146
- - ✅ Cache statistics for monitoring
82
+ ---
147
83
 
148
- 📖 [Full Documentation](./docs/CHAT.md) | 💡 [Examples](./examples/chat-example.js)
84
+ ## Architecture
149
85
 
150
- ---
86
+ ### Client and workspaces
151
87
 
152
- ### 📦 Sandboxes Module
88
+ ```typescript
89
+ import Oblien from 'oblien';
153
90
 
154
- Manage cloud sandboxes (containerized environments).
91
+ const client = new Oblien({ clientId, clientSecret });
92
+ const ws = client.workspaces;
93
+ ```
155
94
 
156
- ```javascript
157
- import { OblienSandboxes } from 'oblien/sandbox';
95
+ `client.workspaces` is the entry point for all control-plane operations. It provides CRUD methods, power controls, and 13 sub-resource namespaces:
96
+
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` | Internal API server -- enable, disable, rotate tokens |
110
+ | `ws.logs` | Boot and command logs |
111
+ | `ws.images` | Available workspace images |
112
+
113
+ ### CRUD
158
114
 
159
- const sandboxes = new OblienSandboxes(client);
115
+ ```typescript
116
+ // Create
117
+ const workspace = await ws.create({ image: 'node-20', mode: 'permanent' });
160
118
 
161
- // Create sandbox
162
- const sandbox = await sandboxes.create({
163
- name: 'my-dev-env',
164
- region: 'us-east-1',
165
- template: 'node-20',
166
- autoStart: true
167
- });
119
+ // List
120
+ const { workspaces } = await ws.list({ page: 1, limit: 20 });
168
121
 
169
- // Use sandbox
170
- const { url, token } = sandbox.sandbox;
171
- const response = await fetch(`${url}/files/list`, {
172
- headers: { 'Authorization': `Bearer ${token}` }
173
- });
122
+ // Get
123
+ const data = await ws.get('ws_a1b2c3d4');
124
+
125
+ // Update
126
+ await ws.update('ws_a1b2c3d4', { name: 'production-api' });
174
127
 
175
- // Control lifecycle
176
- await sandboxes.stop(sandboxId);
177
- await sandboxes.start(sandboxId);
178
- await sandboxes.restart(sandboxId);
128
+ // Delete
129
+ await ws.delete('ws_a1b2c3d4');
130
+ ```
179
131
 
180
- // Regenerate token (1h expiry)
181
- const newToken = await sandboxes.regenerateToken(sandboxId);
132
+ ### Power controls
182
133
 
183
- // Get metrics
184
- const metrics = await sandboxes.getMetrics(sandboxId);
134
+ ```typescript
135
+ await ws.start(id);
136
+ await ws.stop(id);
137
+ await ws.restart(id);
138
+ await ws.pause(id); // preserves memory state
139
+ await ws.resume(id);
140
+ await ws.ping(id); // renews TTL for temporary workspaces
185
141
  ```
186
142
 
187
- **Features:**
188
- - ✅ Create, start, stop, restart, delete sandboxes
189
- - ✅ Auto-start option
190
- - ✅ Token management (1h JWT)
191
- - ✅ Resource metrics
192
- - ✅ Multiple templates & regions
193
- - ✅ Platform statistics
143
+ ### Account-level queries
194
144
 
195
- 📖 [Full Documentation](./docs/SANDBOXES.md) | 💡 [Examples](./examples/sandbox-example.js)
145
+ ```typescript
146
+ const quota = await ws.getQuota();
147
+ const estimate = await ws.getEstimate({ cpu: 4, ram_mb: 8192 });
148
+ ```
196
149
 
197
150
  ---
198
151
 
199
- ### 🗂️ Namespaces Module
152
+ ## Runtime (data plane)
200
153
 
201
- Manage namespaces and service configurations.
154
+ The runtime connects to a running workspace and provides direct access to its filesystem, command execution, terminal sessions, search, and file watchers.
202
155
 
203
- ```javascript
204
- import { OblienNamespaces } from 'oblien/namespaces';
156
+ ```typescript
157
+ const rt = await ws.runtime('ws_a1b2c3d4');
158
+ ```
205
159
 
206
- const namespaces = new OblienNamespaces(client);
160
+ This call enables the workspace's internal 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.
207
161
 
208
- // Create namespace
209
- const namespace = await namespaces.create({
210
- name: 'production',
211
- slug: 'prod',
212
- type: 'production'
213
- });
162
+ ### Files
214
163
 
215
- // Configure services
216
- await namespaces.configureService(namespaceId, {
217
- service: 'ai',
218
- enabled: true,
219
- config: { /* ... */ }
220
- });
164
+ ```typescript
165
+ // List directory
166
+ const entries = await rt.files.list({ dirPath: '/app' });
221
167
 
222
- // Get usage stats
223
- const usage = await namespaces.getUsage(namespaceId);
224
- ```
168
+ // Read file
169
+ const { content } = await rt.files.read({ filePath: '/app/index.js' });
225
170
 
226
- **Features:**
227
- - Namespace CRUD
228
- - ✅ Service configuration
229
- - ✅ Usage tracking
230
- - ✅ Activity logs
171
+ // Write file
172
+ await rt.files.write({ fullPath: '/app/config.json', content: '{}' });
231
173
 
232
- 📖 [Documentation](./docs/NAMESPACES.md)
174
+ // Create directory
175
+ await rt.files.mkdir({ path: '/app/logs' });
233
176
 
234
- ---
177
+ // Stat
178
+ const stat = await rt.files.stat({ path: '/app/index.js' });
179
+
180
+ // Delete
181
+ await rt.files.delete({ path: '/app/tmp' });
235
182
 
236
- ### 🎨 Icons Module
183
+ // Stream directory tree (async generator)
184
+ for await (const entry of rt.files.stream({ dirPath: '/app' })) {
185
+ console.log(entry.path);
186
+ }
187
+ ```
237
188
 
238
- Search and fetch icons, images, and videos using AI-powered semantic search.
189
+ ### Exec
239
190
 
240
- ```javascript
241
- import { OblienIcons } from 'oblien/icons';
191
+ ```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);
242
195
 
243
- const icons = new OblienIcons(client);
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
+ }
244
200
 
245
- // Search for icons
246
- const results = await icons.search('home', { limit: 20 });
201
+ // List running tasks
202
+ const tasks = await rt.exec.list();
247
203
 
248
- // Fetch specific icons
249
- const icon = await icons.fetchIcon('settings gear');
204
+ // Kill a task
205
+ await rt.exec.kill(taskId);
250
206
 
251
- // Fetch multiple icons at once
252
- const iconSet = await icons.fetchIcons([
253
- 'home',
254
- 'user profile',
255
- 'settings',
256
- 'notification bell'
257
- ]);
207
+ // Send stdin to a running task
208
+ await rt.exec.input(taskId, 'yes\n');
258
209
 
259
- // Fetch mixed media (icons, images, videos)
260
- const media = await icons.fetch([
261
- { type: 'icon', description: 'user avatar' },
262
- { type: 'image', description: 'mountain landscape' },
263
- { type: 'video', description: 'product demo' }
264
- ]);
210
+ // Subscribe to a running task's output
211
+ for await (const event of rt.exec.subscribe(taskId)) {
212
+ console.log(event);
213
+ }
265
214
  ```
266
215
 
267
- **Features:**
268
- - ✅ Semantic icon search with AI embeddings
269
- - ✅ Fetch icons, images, and videos
270
- - ✅ Relevance scoring
271
- - ✅ Multiple icon styles (Outline, Filled, etc.)
272
- - ✅ Batch fetching
273
- - ✅ Pagination support
274
- - ✅ CDN-hosted assets
216
+ ### Terminal
275
217
 
276
- 📖 [Full Documentation](./docs/ICONS.md) | 💡 [Examples](./examples/icons-example.js)
218
+ ```typescript
219
+ // Create a terminal session
220
+ const session = await rt.terminal.create({ shell: '/bin/bash' });
277
221
 
278
- ---
222
+ // List sessions
223
+ const sessions = await rt.terminal.list();
279
224
 
280
- ### 💳 Credits Module
225
+ // Get scrollback buffer
226
+ const { data } = await rt.terminal.scrollback(session.id, { bytes: 4096 });
281
227
 
282
- Manage billing and credits.
228
+ // Close session
229
+ await rt.terminal.close(session.id);
230
+ ```
283
231
 
284
- ```javascript
285
- import { OblienCredits } from 'oblien/credits';
232
+ ### Search
286
233
 
287
- const credits = new OblienCredits(client);
234
+ ```typescript
235
+ // Search file contents (ripgrep)
236
+ const hits = await rt.search.content({ query: 'TODO', path: '/app' });
288
237
 
289
- // Get balance
290
- const balance = await credits.getBalance();
238
+ // Search file names
239
+ const files = await rt.search.files({ query: 'config', path: '/app' });
291
240
 
292
- // Get usage
293
- const usage = await credits.getUsage({ period: 'monthly' });
241
+ // Index status and initialization
242
+ const status = await rt.search.status();
243
+ await rt.search.init();
294
244
  ```
295
245
 
296
- **Features:**
297
- - ✅ Balance checking
298
- - ✅ Usage tracking
299
- - Transaction history
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();
254
+
255
+ // Get watcher info
256
+ const info = await rt.watcher.get(watcher.id);
257
+
258
+ // Stop watching
259
+ await rt.watcher.delete(watcher.id);
260
+ ```
300
261
 
301
262
  ---
302
263
 
303
- ## Complete Example
264
+ ## WebSocket
304
265
 
305
- ```javascript
306
- // Import client and modules
307
- import { OblienClient } from 'oblien';
308
- import { OblienAgents } from 'oblien/agents';
309
- import { OblienChat } from 'oblien/chat';
310
- import { OblienSandboxes } from 'oblien/sandbox';
266
+ For real-time terminal I/O and file watcher events, open a persistent WebSocket connection:
311
267
 
312
- // Initialize
313
- const client = new OblienClient({
314
- clientId: 'your-client-id',
315
- clientSecret: 'your-client-secret'
268
+ ```typescript
269
+ const socket = rt.ws();
270
+
271
+ socket.onOpen(() => {
272
+ console.log('connected');
316
273
  });
317
274
 
318
- const agents = new OblienAgents(client);
319
- const chat = new OblienChat(client);
320
- const sandboxes = new OblienSandboxes(client);
321
-
322
- async function main() {
323
- // 1. Create agent with tools
324
- const agent = await agents.create({
325
- name: 'Code Assistant',
326
- namespace: 'production',
327
- prompts: {
328
- identity: 'You are a coding assistant.'
329
- }
330
- });
331
-
332
- // Configure agent
333
- const agentInstance = agents.agent(agent.agentId);
334
- await agentInstance.settings.updateTools(['web-search', 'calculator']);
335
- await agentInstance.settings.updateModelConfig({
336
- temperature: 0.7,
337
- max_tokens: 3000
338
- });
339
-
340
- // 2. Create sandbox for code execution
341
- const sandbox = await sandboxes.create({
342
- name: 'code-env',
343
- template: 'node-20',
344
- autoStart: true
345
- });
346
-
347
- // 3. Create chat session
348
- const session = await chat.createSession({
349
- agentId: agent.agentId,
350
- namespace: 'production'
351
- });
352
-
353
- console.log('Setup complete!');
354
- console.log('- Agent ID:', agent.agentId);
355
- console.log('- Sandbox URL:', sandbox.sandbox.url);
356
- console.log('- Session ID:', session.sessionId);
357
- }
275
+ socket.onTerminalOutput((data) => {
276
+ process.stdout.write(data.output);
277
+ });
358
278
 
359
- main();
279
+ socket.onWatcherEvent((event) => {
280
+ console.log(event.type, event.path);
281
+ });
282
+
283
+ socket.onClose(() => {
284
+ console.log('disconnected');
285
+ });
286
+
287
+ socket.onError((err) => {
288
+ console.error(err);
289
+ });
290
+
291
+ await socket.connect();
292
+
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 });
360
298
  ```
361
299
 
362
300
  ---
363
301
 
364
- ## Module Structure
302
+ ## SSE streaming
365
303
 
366
- ```
367
- oblien/
368
- ├── src/
369
- │ ├── agents/ # Agents management
370
- │ │ ├── index.js # OblienAgents class
371
- │ │ ├── agent.js # Agent instance
372
- │ │ ├── settings.js # AgentSettings class
373
- │ │ └── tools.js # Tools class
374
- │ ├── chat/ # Chat sessions
375
- │ │ ├── index.js # OblienChat class
376
- │ │ └── session.js # ChatSession class
377
- │ ├── sandbox/ # Sandboxes management
378
- │ │ ├── index.js # OblienSandboxes class
379
- │ │ └── sandbox.js # Sandbox instance
380
- │ ├── namespaces/ # Namespaces management
381
- │ ├── credits/ # Credits & billing
382
- │ └── client.js # OblienClient (base)
383
- ├── docs/ # Documentation
384
- │ ├── AGENTS_COMPLETE.md
385
- │ ├── SANDBOXES.md
386
- │ ├── CHAT.md
387
- │ └── NAMESPACES.md
388
- └── examples/ # Usage examples
389
- ├── agents-complete-example.js
390
- ├── sandbox-example.js
391
- └── chat-example.js
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
+ }
392
326
  ```
393
327
 
394
328
  ---
395
329
 
396
- ## API Endpoints
330
+ ## Sub-resources
397
331
 
398
- | Module | Base Path | Operations |
399
- |--------|-----------|------------|
400
- | **Agents** | `/ai/agents` | CRUD, settings, tools, analytics |
401
- | **Chat** | `/ai/session` | Create, list, history |
402
- | **Sandboxes** | `/sandbox` | CRUD, start/stop/restart, metrics |
403
- | **Tools** | `/ai/tools` | List, search, create |
404
- | **Namespaces** | `/namespaces` | CRUD, services, usage |
332
+ ### Lifecycle
405
333
 
406
- ---
334
+ ```typescript
335
+ const status = await ws.lifecycle.get(id);
407
336
 
408
- ## Authentication
337
+ // Convert to permanent
338
+ await ws.lifecycle.makePermanent(id);
409
339
 
410
- All modules use client credentials authentication:
340
+ // Convert to temporary with TTL
341
+ await ws.lifecycle.makeTemporary(id, { ttl_seconds: 3600 });
411
342
 
412
- ```javascript
413
- const client = new OblienClient({
414
- clientId: 'your-client-id', // X-Client-ID header
415
- clientSecret: 'your-client-secret' // X-Client-Secret header
343
+ // Update TTL
344
+ await ws.lifecycle.updateTtl(id, { ttl_seconds: 7200 });
345
+
346
+ // Destroy (irreversible)
347
+ await ws.lifecycle.destroy(id);
348
+ ```
349
+
350
+ ### Network
351
+
352
+ ```typescript
353
+ const network = await ws.network.get(id);
354
+
355
+ await ws.network.update(id, {
356
+ ingress: ['10.0.1.5'],
357
+ egress: ['10.0.1.10'],
358
+ allow_internet: false,
416
359
  });
360
+
361
+ // Assign a dedicated outbound IP
362
+ await ws.network.applyOutboundIp(id, { ip: '203.0.113.50' });
417
363
  ```
418
364
 
419
- Get your credentials from the [Oblien Dashboard](https://dashboard.oblien.com).
365
+ ### SSH
420
366
 
421
- ---
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
+ ```
422
373
 
423
- ## TypeScript Support
374
+ ### Public access
424
375
 
425
- The SDK includes TypeScript definitions:
376
+ ```typescript
377
+ // Expose a port
378
+ const endpoint = await ws.publicAccess.expose(id, {
379
+ port: 3000,
380
+ domain: 'app.yourdomain.com',
381
+ });
382
+
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
426
391
 
427
392
  ```typescript
428
- import {
429
- OblienClient,
430
- OblienAgents,
431
- Agent,
432
- AgentSettings,
433
- Tools,
434
- OblienSandboxes,
435
- Sandbox
436
- } from 'oblien';
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
+ ```
437
406
 
438
- const client: OblienClient = new OblienClient({
439
- clientId: string,
440
- clientSecret: string
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' },
441
415
  });
416
+
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
+ }
442
430
  ```
443
431
 
444
- ---
432
+ ### Metrics
445
433
 
446
- ## Error Handling
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);
447
438
 
448
- ```javascript
449
- try {
450
- const agent = await agents.create({ /* ... */ });
451
- } catch (error) {
452
- console.error('Error:', error.message);
453
-
454
- if (error.message.includes('401')) {
455
- // Authentication failed
456
- } else if (error.message.includes('404')) {
457
- // Resource not found
458
- } else if (error.message.includes('429')) {
459
- // Rate limit exceeded
460
- }
439
+ for await (const snapshot of ws.metrics.statsStream(id)) {
440
+ console.log(snapshot);
461
441
  }
462
442
  ```
463
443
 
464
- ---
444
+ ### Usage
465
445
 
466
- ## Best Practices
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
+ ```
467
454
 
468
- 1. **Reuse Client**: Create one client instance and share across modules
469
- 2. **Error Handling**: Always wrap API calls in try-catch
470
- 3. **Token Management**: For sandboxes, refresh tokens before 1h expiry
471
- 4. **Resource Cleanup**: Stop/delete unused sandboxes and sessions
472
- 5. **Namespace Organization**: Use namespaces to separate environments
473
- 6. **Tool Validation**: Validate tools before assigning to agents
455
+ ### Metadata
474
456
 
475
- ---
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
+ ```
476
462
 
477
- ## Examples
463
+ ### API access
478
464
 
479
- ### Multi-Agent System
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
+ ```
480
473
 
481
- ```javascript
482
- // Create specialized agents
483
- const coder = await agents.create({
484
- name: 'Coder',
485
- prompts: { identity: 'Expert coder' }
486
- });
474
+ ### Logs
487
475
 
488
- const reviewer = await agents.create({
489
- name: 'Reviewer',
490
- prompts: { identity: 'Code reviewer' }
491
- });
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');
492
481
 
493
- // Configure each with specific tools
494
- await agents.agent(coder.agentId).settings.updateTools([
495
- 'web-search', 'code-interpreter'
496
- ]);
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
497
491
 
498
- await agents.agent(reviewer.agentId).settings.updateTools([
499
- 'code-analyzer', 'security-scanner'
500
- ]);
492
+ ```typescript
493
+ const images = await ws.images.list();
494
+ const image = await ws.images.get('node-20');
501
495
  ```
502
496
 
503
- ### Guest Chat System
497
+ ---
498
+
499
+ ## Standalone imports
504
500
 
505
- ```javascript
506
- // Create agent for customer support
507
- const supportAgent = await agents.create({
508
- name: 'Support Bot',
509
- namespace: 'production'
510
- });
501
+ The SDK exports `Workspace` and `Runtime` as standalone classes for cases where you need direct access without going through the main client:
502
+
503
+ ```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' });
511
509
 
512
- // Set guest limits
513
- await agents.agent(supportAgent.agentId).settings.updateGuestLimits({
514
- enabled: true,
515
- max_messages_per_day: 100,
516
- max_total_tokens_per_day: 50000
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',
517
515
  });
516
+ await rt.files.list({ dirPath: '/' });
518
517
 
519
- // Create guest session
520
- const session = await chat.createGuestSession({
521
- ip: req.ip,
522
- fingerprint: req.headers['x-fingerprint'],
523
- agentId: supportAgent.agentId
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',
524
522
  });
525
523
  ```
526
524
 
527
525
  ---
528
526
 
529
- ## Links
527
+ ## Error handling
528
+
529
+ Every API error is an instance of `OblienError` with typed subclasses:
530
+
531
+ ```typescript
532
+ import Oblien, {
533
+ OblienError,
534
+ AuthenticationError,
535
+ NotFoundError,
536
+ RateLimitError,
537
+ ValidationError,
538
+ PaymentRequiredError,
539
+ ConflictError,
540
+ } from 'oblien';
541
+
542
+ try {
543
+ await ws.get('ws_nonexistent');
544
+ } 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
+ }
560
+ }
561
+ ```
530
562
 
531
- - **Website**: https://oblien.com
532
- - **Documentation**: https://docs.oblien.com
533
- - **Dashboard**: https://dashboard.oblien.com
534
- - **API Reference**: https://api.oblien.com/docs
535
- - **Support**: support@oblien.com
536
- - **GitHub**: https://github.com/oblien/oblien
563
+ | Error class | HTTP status | When |
564
+ |-------------|-------------|------|
565
+ | `AuthenticationError` | 401 | Invalid or missing credentials |
566
+ | `PaymentRequiredError` | 402 | Credit quota exceeded |
567
+ | `NotFoundError` | 404 | Resource does not exist |
568
+ | `ConflictError` | 409 | Resource in wrong state for the operation |
569
+ | `ValidationError` | 422 | Invalid request parameters |
570
+ | `RateLimitError` | 429 | Too many requests |
537
571
 
538
572
  ---
539
573
 
540
- ## License
574
+ ## Configuration
575
+
576
+ ```typescript
577
+ const client = new Oblien({
578
+ clientId: 'your_client_id', // required
579
+ clientSecret: 'your_client_secret', // required
580
+ baseUrl: 'https://api.oblien.com', // optional, default
581
+ });
582
+ ```
583
+
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 |
541
589
 
542
- MIT License - see LICENSE file for details
590
+ Get your API keys from the [dashboard](https://oblien.com/dashboard).
543
591
 
544
592
  ---
545
593
 
546
- ## Changelog
594
+ ## TypeScript
547
595
 
548
- ### v1.3.0 (Latest)
549
- - ✅ Added `send()` method to Chat module with streaming support
550
- - ✅ Added `upload()` method for file attachments
551
- - ✅ Added guest usage monitoring (`getGuestUsage()`)
552
- - ✅ Added cache statistics (`getCacheStatistics()`)
553
- - ✅ Hybrid mode support (token or client credentials)
554
- - ✅ Complete Chat documentation with examples
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:
555
597
 
556
- ### v1.2.0
557
- - Added Sandboxes module
558
- - ✅ Enhanced Agents module with proper settings sections
559
- - ✅ Added Tools management
560
- - ✅ Improved documentation
598
+ ```typescript
599
+ import type {
600
+ WorkspaceCreateParams,
601
+ WorkspaceData,
602
+ ExecTask,
603
+ ExecStreamEvent,
604
+ FileEntry,
605
+ WSTerminalEvent,
606
+ WSWatcherEvent,
607
+ } from 'oblien';
608
+ ```
561
609
 
562
- ### v1.1.0
563
- - ✅ Added Agents module
564
- - ✅ Added Namespaces module
565
- - ✅ Guest session support
610
+ ---
611
+
612
+ ## Requirements
566
613
 
567
- ### v1.0.0
568
- - Initial release
569
- - Chat module
570
- - ✅ Credits module
614
+ - Node.js 18+
615
+ - TypeScript 5.0+ (if using TypeScript)
616
+ - ESM (`"type": "module"` in your package.json, or use dynamic `import()`)
571
617
 
572
618
  ---
573
619
 
574
- Made with ❤️ by the Oblien Team
620
+ ## Links
621
+
622
+ - [Documentation](https://oblien.com/docs)
623
+ - [SDK setup guide](https://oblien.com/docs/workspace/sdk-setup)
624
+ - [Quickstart](https://oblien.com/docs/workspace/quickstart)
625
+ - [API reference](https://oblien.com/docs/api)
626
+ - [Runtime / Internal API](https://oblien.com/docs/internal-api)
627
+ - [Dashboard](https://oblien.com/dashboard)
628
+ - [GitHub](https://github.com/oblien/sdk)
629
+
630
+ ---
631
+
632
+ ## License
633
+
634
+ MIT