computesdk 2.0.0 → 2.0.2

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
@@ -1,746 +1,712 @@
1
- # ComputeSDK
1
+ # computesdk
2
2
 
3
- A unified abstraction layer for executing code in secure, isolated sandboxed environments across multiple cloud providers.
4
-
5
- Similar to how Vercel's AI SDK abstracts different LLM providers, ComputeSDK abstracts different compute sandbox providers into a single, consistent TypeScript interface.
6
-
7
- ## Features
8
-
9
- - 🚀 **Multi-provider support** - E2B, Vercel, Daytona
10
- - 📁 **Filesystem operations** - Read, write, create directories across providers
11
- - 🖥️ **Terminal support** - Interactive PTY terminals (E2B)
12
- - ⚡ **Command execution** - Run shell commands directly
13
- - 🔄 **Auto-detection** - Automatically selects providers based on environment variables
14
- - 🛡️ **Type-safe** - Full TypeScript support with comprehensive error handling
15
- - 📦 **Modular** - Install only the providers you need
16
- - 🔧 **Extensible** - Easy to add custom providers
17
-
18
- ## Supported Providers
19
-
20
- | Provider | Code Execution | Filesystem | Terminal | Use Cases |
21
- |----------|----------------|------------|----------|-----------|
22
- | **E2B** | Python | ✅ Full | ✅ PTY | Data science, AI/ML, interactive development |
23
- | **Vercel** | Node.js, Python | ✅ Full | ❌ | Web apps, APIs, serverless functions |
24
- | **Daytona** | Python, Node.js | ✅ Full | ❌ | Development workspaces, custom environments |
3
+ The gateway SDK for running code in remote sandboxes. Zero-config auto-detection with support for E2B, Modal, Railway, Daytona, Vercel, and more.
25
4
 
26
5
  ## Installation
27
6
 
28
7
  ```bash
29
- # Core SDK
30
8
  npm install computesdk
31
-
32
- # Provider packages (install only what you need)
33
- npm install @computesdk/e2b # E2B provider
34
- npm install @computesdk/vercel # Vercel provider
35
- npm install @computesdk/daytona # Daytona provider
36
9
  ```
37
10
 
38
11
  ## Quick Start
39
12
 
40
- ### Auto-detection (Recommended)
13
+ ### Zero-Config Mode (Recommended)
41
14
 
42
- ComputeSDK automatically detects available providers based on environment variables:
15
+ Set your provider credentials as environment variables and ComputeSDK automatically detects and configures everything:
16
+
17
+ ```bash
18
+ export E2B_API_KEY=your_e2b_api_key
19
+ ```
43
20
 
44
21
  ```typescript
45
- import { ComputeSDK } from 'computesdk';
22
+ import { compute } from 'computesdk';
46
23
 
47
- // Automatically detects and uses the first available provider
48
- const sandbox = ComputeSDK.createSandbox();
24
+ // Auto-detects E2B from environment
25
+ const sandbox = await compute.sandbox.create();
49
26
 
50
- const result = await sandbox.execute('print("Hello World!")');
51
- console.log(result.stdout); // "Hello World!"
27
+ // Execute code
28
+ const result = await sandbox.runCode('print("Hello World!")');
29
+ console.log(result.output); // "Hello World!"
52
30
 
53
- await sandbox.kill();
31
+ // Clean up
32
+ await sandbox.destroy();
54
33
  ```
55
34
 
56
- ### Provider-specific Usage
35
+ ### Explicit Configuration
36
+
37
+ For more control, use `setConfig()` to explicitly configure the provider:
57
38
 
58
39
  ```typescript
59
- import { executeSandbox } from 'computesdk';
60
- import { e2b } from '@computesdk/e2b';
40
+ import { compute } from 'computesdk';
61
41
 
62
- // Execute with specific provider
63
- const result = await executeSandbox({
64
- sandbox: e2b(),
65
- code: 'print("Hello from E2B!")',
66
- runtime: 'python'
42
+ compute.setConfig({
43
+ provider: 'your-provider',
44
+ apiKey: process.env.COMPUTESDK_API_KEY,
45
+ 'your-provider': {
46
+ apiKey: process.env.YOUR_PROVIDER_API_KEY
47
+ }
67
48
  });
68
49
 
69
- console.log(result.stdout);
50
+ const sandbox = await compute.sandbox.create();
70
51
  ```
71
52
 
72
- ### Advanced Usage with Type Safety
53
+ ## Supported Providers
73
54
 
74
- ComputeSDK provides rich TypeScript interfaces for different provider capabilities:
55
+ ComputeSDK automatically detects providers based on environment variables:
75
56
 
76
- ```typescript
77
- import { ComputeSDK, FilesystemComputeSandbox, TerminalComputeSandbox } from 'computesdk';
57
+ | Provider | Environment Variables | Use Cases |
58
+ |----------|----------------------|-----------|
59
+ | **E2B** | `E2B_API_KEY` | Data science, Python/Node.js, interactive terminals |
60
+ | **Modal** | `MODAL_TOKEN_ID`, `MODAL_TOKEN_SECRET` | GPU computing, ML inference, Python workloads |
61
+ | **Railway** | `RAILWAY_TOKEN` | Full-stack deployments, persistent storage |
62
+ | **Daytona** | `DAYTONA_API_KEY` | Development workspaces, custom environments |
63
+ | **Runloop** | `RUNLOOP_API_KEY` | Code execution, automation |
64
+ | **Vercel** | `VERCEL_TOKEN` or `VERCEL_OIDC_TOKEN` | Serverless functions, web apps |
65
+ | **Cloudflare** | `CLOUDFLARE_API_TOKEN` | Edge computing |
66
+ | **CodeSandbox** | `CODESANDBOX_TOKEN` | Collaborative development |
78
67
 
79
- const sandbox = ComputeSDK.createSandbox();
68
+ ### Provider Detection Order
80
69
 
81
- // Check provider capabilities at runtime
82
- if ('filesystem' in sandbox) {
83
- const fsSandbox = sandbox as FilesystemComputeSandbox;
84
-
85
- // Use filesystem operations
86
- await fsSandbox.filesystem.writeFile('/tmp/data.txt', 'Hello World!');
87
- const content = await fsSandbox.filesystem.readFile('/tmp/data.txt');
88
- console.log(content); // "Hello World!"
89
- }
70
+ When using zero-config mode, ComputeSDK detects providers in this order:
90
71
 
91
- if ('terminal' in sandbox) {
92
- const termSandbox = sandbox as TerminalComputeSandbox;
93
-
94
- // Create interactive terminal (E2B only)
95
- const terminal = await termSandbox.terminal.create({
96
- command: 'bash',
97
- cols: 80,
98
- rows: 24
99
- });
100
-
101
- await terminal.write('echo "Interactive terminal!"\n');
102
- await terminal.kill();
103
- }
104
- ```
105
-
106
- ## Environment Setup
72
+ **E2B Railway Daytona → Modal → Runloop → Vercel → Cloudflare → CodeSandbox**
107
73
 
108
- Each provider requires specific environment variables for authentication:
74
+ You can force a specific provider:
109
75
 
110
- ### E2B (Full Features)
111
76
  ```bash
112
- export E2B_API_KEY=e2b_your_api_key_here
77
+ export COMPUTESDK_PROVIDER=modal
113
78
  ```
114
- Get your API key from [e2b.dev](https://e2b.dev/)
115
79
 
116
- ### Vercel (Filesystem + Code Execution)
117
- ```bash
118
- export VERCEL_TOKEN=your_vercel_token_here
119
- export VERCEL_TEAM_ID=your_team_id_here
120
- export VERCEL_PROJECT_ID=your_project_id_here
121
- ```
122
- Get your token from [Vercel Account Tokens](https://vercel.com/account/tokens)
80
+ ## API Reference
123
81
 
124
- ### Daytona (Development Workspaces)
125
- ```bash
126
- export DAYTONA_API_KEY=your_daytona_api_key_here
82
+ ### Configuration
83
+
84
+ #### `compute.setConfig(config)`
85
+
86
+ Configure the gateway with explicit provider settings.
87
+
88
+ ```typescript
89
+ compute.setConfig({
90
+ provider: 'your-provider',
91
+ apiKey: process.env.COMPUTESDK_API_KEY,
92
+ 'your-provider': {
93
+ apiKey: process.env.YOUR_PROVIDER_API_KEY
94
+ }
95
+ });
127
96
  ```
128
97
 
98
+ **Provider-specific configs:**
129
99
 
100
+ ```typescript
101
+ // E2B
102
+ compute.setConfig({
103
+ provider: 'e2b',
104
+ apiKey: process.env.COMPUTESDK_API_KEY,
105
+ e2b: {
106
+ apiKey: 'e2b_xxx',
107
+ templateId: 'optional_template'
108
+ }
109
+ });
130
110
 
131
- ## API Reference
111
+ // Modal
112
+ compute.setConfig({
113
+ provider: 'modal',
114
+ apiKey: process.env.COMPUTESDK_API_KEY,
115
+ modal: {
116
+ tokenId: 'ak-xxx',
117
+ tokenSecret: 'as-xxx'
118
+ }
119
+ });
120
+
121
+ // Railway
122
+ compute.setConfig({
123
+ provider: 'railway',
124
+ apiKey: process.env.COMPUTESDK_API_KEY,
125
+ railway: {
126
+ apiToken: 'your_token',
127
+ projectId: 'project_id',
128
+ environmentId: 'env_id'
129
+ }
130
+ });
131
+
132
+ // Daytona
133
+ compute.setConfig({
134
+ provider: 'daytona',
135
+ apiKey: process.env.COMPUTESDK_API_KEY,
136
+ daytona: { apiKey: 'your_api_key' }
137
+ });
132
138
 
133
- ### Core SDK
139
+ // Vercel
140
+ compute.setConfig({
141
+ provider: 'vercel',
142
+ apiKey: process.env.COMPUTESDK_API_KEY,
143
+ vercel: {
144
+ token: 'your_token',
145
+ teamId: 'team_xxx',
146
+ projectId: 'prj_xxx'
147
+ }
148
+ });
149
+ ```
134
150
 
135
- #### `ComputeSDK.createSandbox(config?)`
151
+ ### Sandbox Management
136
152
 
137
- Creates a sandbox using auto-detection or specified configuration.
153
+ #### `compute.sandbox.create(options?)`
138
154
 
139
- ```typescript
140
- // Auto-detection
141
- const sandbox = ComputeSDK.createSandbox();
155
+ Create a new sandbox.
142
156
 
143
- // With configuration
144
- const sandbox = ComputeSDK.createSandbox({
145
- provider: 'e2b',
146
- runtime: 'python',
147
- timeout: 600000 // 10 minutes
157
+ ```typescript
158
+ const sandbox = await compute.sandbox.create();
159
+
160
+ // With options
161
+ const sandbox = await compute.sandbox.create({
162
+ timeout: 300000, // 5 minutes
163
+ metadata: { userId: '123' },
164
+ namespace: 'my-org',
165
+ name: 'my-sandbox',
148
166
  });
149
167
  ```
150
168
 
151
- **Parameters:**
152
- - `config` (optional): Sandbox configuration object
169
+ **Options:**
170
+ - `timeout?: number` - Timeout in milliseconds
171
+ - `metadata?: Record<string, any>` - Custom metadata
172
+ - `envs?: Record<string, string>` - Environment variables
173
+ - `namespace?: string` - Namespace for organizing sandboxes
174
+ - `name?: string` - Name for the sandbox (enables findOrCreate)
175
+ - `overlays?: SetupOverlayConfig[]` - Template overlays to apply
176
+ - `servers?: ServerStartOptions[]` - Servers to start automatically
177
+
178
+ #### `compute.sandbox.getById(sandboxId)`
153
179
 
154
- **Returns:** `ComputeSandbox` - The appropriate sandbox type based on provider capabilities
180
+ Get an existing sandbox by ID.
155
181
 
156
- #### `ComputeSDK.detectProviders()`
182
+ ```typescript
183
+ const sandbox = await compute.sandbox.getById('sandbox-id');
184
+ ```
157
185
 
158
- Detects available providers based on environment variables.
186
+ #### `compute.sandbox.findOrCreate(options)`
187
+
188
+ Find an existing sandbox by namespace and name, or create a new one.
159
189
 
160
190
  ```typescript
161
- const providers = ComputeSDK.detectProviders();
162
- console.log('Available providers:', providers); // ['e2b', 'vercel']
191
+ const sandbox = await compute.sandbox.findOrCreate({
192
+ namespace: 'my-org',
193
+ name: 'my-project',
194
+ });
163
195
  ```
164
196
 
165
- **Returns:** `ProviderType[]` - Array of available provider names
197
+ #### `compute.sandbox.find(options)`
166
198
 
167
- ### Utility Functions
199
+ Find an existing sandbox by namespace and name (returns null if not found).
168
200
 
169
- #### `executeSandbox(params)`
201
+ ```typescript
202
+ const sandbox = await compute.sandbox.find({
203
+ namespace: 'my-org',
204
+ name: 'my-project',
205
+ });
206
+ ```
207
+
208
+ ### Sandbox Operations
170
209
 
171
- Utility function for one-off code execution.
210
+ #### `sandbox.runCode(code, language?)`
211
+
212
+ Execute code in the sandbox.
172
213
 
173
214
  ```typescript
174
- import { executeSandbox } from 'computesdk';
175
- import { vercel } from '@computesdk/vercel';
215
+ const result = await sandbox.runCode('print("Hello")', 'python');
216
+ console.log(result.output); // "Hello"
217
+ console.log(result.exitCode);
218
+ ```
219
+
220
+ #### `sandbox.runCommand(command, options?)`
176
221
 
177
- const result = await executeSandbox({
178
- sandbox: vercel({ runtime: 'node' }),
179
- code: 'console.log("Hello from Node.js!");',
180
- runtime: 'node'
222
+ Run a shell command.
223
+
224
+ ```typescript
225
+ const result = await sandbox.runCommand('npm install express');
226
+ console.log(result.stdout);
227
+ console.log(result.exitCode);
228
+
229
+ // With options
230
+ const result = await sandbox.runCommand('npm install', {
231
+ cwd: '/app',
232
+ env: { NODE_ENV: 'production' },
233
+ background: true,
181
234
  });
182
235
  ```
183
236
 
184
- **Parameters:**
237
+ #### `sandbox.destroy()`
238
+
239
+ Destroy the sandbox and clean up resources.
240
+
185
241
  ```typescript
186
- interface ExecuteSandboxParams {
187
- sandbox: ComputeSandbox;
188
- code: string;
189
- runtime?: Runtime;
190
- }
242
+ await sandbox.destroy();
191
243
  ```
192
244
 
193
- ### Sandbox Interfaces
245
+ ### Filesystem Operations
194
246
 
195
- ComputeSDK provides a rich type system for different provider capabilities:
247
+ The sandbox provides full filesystem access:
196
248
 
197
- #### `BaseComputeSandbox`
249
+ #### `sandbox.filesystem.writeFile(path, content)`
198
250
 
199
- Basic code execution capabilities (all providers support this):
251
+ Write a file to the sandbox.
200
252
 
201
253
  ```typescript
202
- interface BaseComputeSandbox {
203
- provider: string;
204
- sandboxId: string;
205
-
206
- execute(code: string, runtime?: Runtime): Promise<ExecutionResult>;
207
- runCode(code: string, runtime?: Runtime): Promise<ExecutionResult>;
208
- runCommand(command: string, args?: string[]): Promise<ExecutionResult>;
209
- kill(): Promise<void>;
210
- getInfo(): Promise<SandboxInfo>;
211
- }
254
+ await sandbox.filesystem.writeFile('/tmp/hello.py', 'print("Hello World")');
212
255
  ```
213
256
 
214
- #### `FilesystemComputeSandbox`
257
+ #### `sandbox.filesystem.readFile(path)`
215
258
 
216
- Extends base capabilities with filesystem operations (E2B, Vercel, Daytona):
259
+ Read a file from the sandbox.
217
260
 
218
261
  ```typescript
219
- interface FilesystemComputeSandbox extends BaseComputeSandbox {
220
- readonly filesystem: SandboxFileSystem;
221
- }
262
+ const content = await sandbox.filesystem.readFile('/tmp/hello.py');
263
+ console.log(content); // 'print("Hello World")'
264
+ ```
222
265
 
223
- interface SandboxFileSystem {
224
- readFile(path: string): Promise<string>;
225
- writeFile(path: string, content: string): Promise<void>;
226
- mkdir(path: string): Promise<void>;
227
- readdir(path: string): Promise<FileEntry[]>;
228
- exists(path: string): Promise<boolean>;
229
- remove(path: string): Promise<void>;
230
- }
266
+ #### `sandbox.filesystem.mkdir(path)`
267
+
268
+ Create a directory.
269
+
270
+ ```typescript
271
+ await sandbox.filesystem.mkdir('/tmp/mydir');
231
272
  ```
232
273
 
233
- #### `TerminalComputeSandbox`
274
+ #### `sandbox.filesystem.readdir(path)`
234
275
 
235
- Extends base capabilities with terminal operations (E2B only):
276
+ List directory contents.
236
277
 
237
278
  ```typescript
238
- interface TerminalComputeSandbox extends BaseComputeSandbox {
239
- readonly terminal: SandboxTerminal;
240
- }
279
+ const files = await sandbox.filesystem.readdir('/tmp');
280
+ console.log(files); // [{ name: 'hello.py', type: 'file', size: 123 }, ...]
281
+ ```
241
282
 
242
- interface SandboxTerminal {
243
- create(options?: TerminalCreateOptions): Promise<InteractiveTerminalSession>;
244
- list(): Promise<InteractiveTerminalSession[]>;
245
- }
283
+ #### `sandbox.filesystem.exists(path)`
284
+
285
+ Check if a file or directory exists.
286
+
287
+ ```typescript
288
+ const exists = await sandbox.filesystem.exists('/tmp/hello.py');
289
+ console.log(exists); // true
246
290
  ```
247
291
 
248
- #### `FullComputeSandbox`
292
+ #### `sandbox.filesystem.remove(path)`
249
293
 
250
- Full capabilities including filesystem and terminal (E2B only):
294
+ Remove a file or directory.
251
295
 
252
296
  ```typescript
253
- interface FullComputeSandbox extends FilesystemComputeSandbox, TerminalComputeSandbox {}
297
+ await sandbox.filesystem.remove('/tmp/hello.py');
254
298
  ```
255
299
 
256
- ### Data Types
300
+ ### Terminal Operations
257
301
 
258
- #### `ExecutionResult`
302
+ The sandbox provides terminal access in two modes: **PTY mode** (interactive shell) and **Exec mode** (command tracking).
259
303
 
260
- Result object returned by all execution methods:
304
+ #### `sandbox.terminal.create(options?)`
305
+
306
+ Create a new terminal session.
261
307
 
262
308
  ```typescript
263
- interface ExecutionResult {
264
- stdout: string;
265
- stderr: string;
266
- exitCode: number;
267
- executionTime: number;
268
- sandboxId: string;
269
- provider: string;
270
- }
309
+ // PTY mode - Interactive shell
310
+ const pty = await sandbox.terminal.create({ pty: true, shell: '/bin/bash' });
311
+
312
+ // Exec mode - Command tracking (default)
313
+ const exec = await sandbox.terminal.create({ pty: false });
271
314
  ```
272
315
 
273
- #### `SandboxInfo`
316
+ **Options:**
317
+ - `pty?: boolean` - Terminal mode: `true` = PTY (interactive), `false` = exec (command tracking). Default: `false`
318
+ - `shell?: string` - Shell to use (e.g., '/bin/bash'). PTY mode only
319
+ - `encoding?: 'raw' | 'base64'` - Output encoding. Default: `'raw'`
274
320
 
275
- Information about a sandbox instance:
321
+ **Returns:** `TerminalInstance`
322
+
323
+ #### `sandbox.terminal.list()`
324
+
325
+ List all active terminals.
276
326
 
277
327
  ```typescript
278
- interface SandboxInfo {
279
- id: string;
280
- provider: string;
281
- runtime: Runtime;
282
- status: 'running' | 'stopped' | 'error';
283
- createdAt: Date;
284
- timeout: number;
285
- metadata?: Record<string, any>;
286
- }
328
+ const terminals = await sandbox.terminal.list();
329
+ console.log(terminals); // [{ id: 'term-1', pty: true, status: 'running', ... }]
287
330
  ```
288
331
 
289
- #### `FileEntry`
332
+ #### `sandbox.terminal.retrieve(id)`
290
333
 
291
- File system entry information:
334
+ Retrieve a specific terminal by ID.
292
335
 
293
336
  ```typescript
294
- interface FileEntry {
295
- name: string;
296
- path: string;
297
- isDirectory: boolean;
298
- size: number;
299
- lastModified: Date;
300
- }
337
+ const terminal = await sandbox.terminal.retrieve('term-123');
338
+ console.log(terminal.id, terminal.status);
301
339
  ```
302
340
 
303
- ## Examples
341
+ #### `sandbox.terminal.destroy(id)`
304
342
 
305
- ### Cross-Provider Data Processing
343
+ Destroy a terminal by ID.
306
344
 
307
345
  ```typescript
308
- import { ComputeSDK, FilesystemComputeSandbox } from 'computesdk';
346
+ await sandbox.terminal.destroy('term-123');
347
+ ```
309
348
 
310
- async function processData() {
311
- // Auto-detect best available provider
312
- const sandbox = ComputeSDK.createSandbox();
313
-
314
- if ('filesystem' in sandbox) {
315
- const fsSandbox = sandbox as FilesystemComputeSandbox;
316
-
317
- // Create project structure
318
- await fsSandbox.filesystem.mkdir('/project/data');
319
- await fsSandbox.filesystem.mkdir('/project/output');
320
-
321
- // Write input data
322
- const data = JSON.stringify([
323
- { name: 'Alice', sales: 1000 },
324
- { name: 'Bob', sales: 1500 },
325
- { name: 'Charlie', sales: 800 }
326
- ]);
327
-
328
- await fsSandbox.filesystem.writeFile('/project/data/sales.json', data);
329
-
330
- // Process data based on provider
331
- let code: string;
332
- if (sandbox.provider === 'e2b') {
333
- // Python processing for E2B
334
- code = `
335
- import json
336
- import pandas as pd
337
-
338
- # Read data
339
- with open('/project/data/sales.json', 'r') as f:
340
- data = json.load(f)
341
-
342
- # Process with pandas
343
- df = pd.DataFrame(data)
344
- total_sales = df['sales'].sum()
345
- avg_sales = df['sales'].mean()
346
-
347
- # Write results
348
- results = {
349
- 'total_sales': total_sales,
350
- 'average_sales': avg_sales,
351
- 'top_performer': df.loc[df['sales'].idxmax(), 'name']
352
- }
349
+ ### PTY Mode (Interactive Shell)
353
350
 
354
- with open('/project/output/results.json', 'w') as f:
355
- json.dump(results, f, indent=2)
356
-
357
- print(f"Total Sales: ${total_sales}")
358
- print(f"Average Sales: ${avg_sales:.2f}")
359
- print(f"Top Performer: {results['top_performer']}")
360
- `;
361
- } else {
362
- // JavaScript processing for Vercel/Daytona
363
- code = `
364
- const fs = require('fs');
365
-
366
- // Read data
367
- const data = JSON.parse(fs.readFileSync('/project/data/sales.json', 'utf8'));
368
-
369
- // Process data
370
- const totalSales = data.reduce((sum, person) => sum + person.sales, 0);
371
- const avgSales = totalSales / data.length;
372
- const topPerformer = data.reduce((top, person) =>
373
- person.sales > top.sales ? person : top
374
- );
375
-
376
- // Write results
377
- const results = {
378
- total_sales: totalSales,
379
- average_sales: avgSales,
380
- top_performer: topPerformer.name
381
- };
382
-
383
- fs.writeFileSync('/project/output/results.json', JSON.stringify(results, null, 2));
384
-
385
- console.log(\`Total Sales: $\${totalSales}\`);
386
- console.log(\`Average Sales: $\${avgSales.toFixed(2)}\`);
387
- console.log(\`Top Performer: \${results.top_performer}\`);
388
- `;
389
- }
390
-
391
- // Execute processing
392
- const result = await fsSandbox.execute(code);
393
- console.log('Processing Output:', result.stdout);
394
-
395
- // Read results
396
- const results = await fsSandbox.filesystem.readFile('/project/output/results.json');
397
- console.log('Results:', JSON.parse(results));
398
-
399
- // List generated files
400
- const outputFiles = await fsSandbox.filesystem.readdir('/project/output');
401
- console.log('Generated files:', outputFiles.map(f => f.name));
402
- }
403
-
404
- await sandbox.kill();
405
- }
351
+ PTY mode creates an interactive shell session with real-time input/output over WebSocket.
352
+
353
+ #### `terminal.write(input)`
406
354
 
407
- processData().catch(console.error);
355
+ Send input to the terminal shell.
356
+
357
+ ```typescript
358
+ const pty = await sandbox.terminal.create({ pty: true });
359
+ pty.on('output', (data) => console.log(data));
360
+ pty.write('ls -la\n');
361
+ pty.write('pwd\n');
362
+ await pty.destroy();
408
363
  ```
409
364
 
410
- ### Interactive Development with E2B
365
+ #### `terminal.resize(cols, rows)`
366
+
367
+ Resize the terminal window.
411
368
 
412
369
  ```typescript
413
- import { e2b } from '@computesdk/e2b';
414
- import { TerminalComputeSandbox, FilesystemComputeSandbox } from 'computesdk';
370
+ pty.resize(120, 40);
371
+ ```
415
372
 
416
- async function interactiveDevelopment() {
417
- const sandbox = e2b() as TerminalComputeSandbox & FilesystemComputeSandbox;
418
-
419
- // Set up development environment
420
- await sandbox.filesystem.mkdir('/workspace');
421
- await sandbox.filesystem.writeFile('/workspace/requirements.txt',
422
- 'pandas\nnumpy\nmatplotlib\nscikit-learn'
423
- );
424
-
425
- // Create interactive terminal
426
- const terminal = await sandbox.terminal.create({
427
- command: 'bash',
428
- cols: 120,
429
- rows: 30
430
- });
431
-
432
- // Set up output handler
433
- terminal.onData = (data: Uint8Array) => {
434
- const output = new TextDecoder().decode(data);
435
- console.log('Terminal:', output);
436
- };
437
-
438
- // Install dependencies
439
- await terminal.write('cd /workspace\n');
440
- await terminal.write('pip install -r requirements.txt\n');
441
-
442
- // Start interactive Python session
443
- await terminal.write('python3\n');
444
- await terminal.write('import pandas as pd\n');
445
- await terminal.write('import numpy as np\n');
446
- await terminal.write('print("Development environment ready!")\n');
447
-
448
- // Simulate interactive development
449
- await new Promise(resolve => setTimeout(resolve, 5000));
450
-
451
- // Clean up
452
- await terminal.kill();
453
- await sandbox.kill();
454
- }
373
+ #### `terminal.on(event, handler)`
455
374
 
456
- interactiveDevelopment().catch(console.error);
375
+ Register an event handler. Events: `'output'`, `'error'`, `'destroyed'`.
376
+
377
+ ```typescript
378
+ pty.on('output', (data) => console.log('Output:', data));
379
+ pty.on('error', (error) => console.error('Error:', error));
380
+ pty.on('destroyed', () => console.log('Terminal destroyed'));
457
381
  ```
458
382
 
459
- ### Multi-Provider Comparison
383
+ #### `terminal.off(event, handler)`
384
+
385
+ Unregister an event handler.
460
386
 
461
387
  ```typescript
462
- import { executeSandbox } from 'computesdk';
463
- import { e2b } from '@computesdk/e2b';
464
- import { vercel } from '@computesdk/vercel';
465
- import { daytona } from '@computesdk/daytona';
466
-
467
- async function compareProviders() {
468
- const testCode = `
469
- import json
470
- import time
471
- start = time.time()
472
-
473
- # Simple computation
474
- result = sum(range(1000))
475
- elapsed = time.time() - start
476
-
477
- output = {
478
- "result": result,
479
- "elapsed_ms": round(elapsed * 1000, 2),
480
- "provider": "will_be_set"
481
- }
388
+ const handler = (data) => console.log(data);
389
+ pty.on('output', handler);
390
+ pty.off('output', handler);
391
+ ```
482
392
 
483
- print(json.dumps(output))
484
- `;
485
-
486
- const providers = [
487
- { name: 'E2B', factory: () => e2b() },
488
- { name: 'Vercel', factory: () => vercel({ runtime: 'python' }) },
489
- { name: 'Daytona', factory: () => daytona({ runtime: 'python' }) },
490
- ];
491
-
492
- console.log('Performance Comparison:');
493
- console.log('='.repeat(50));
494
-
495
- for (const { name, factory } of providers) {
496
- try {
497
- const start = Date.now();
498
- const result = await executeSandbox({
499
- sandbox: factory(),
500
- code: testCode,
501
- runtime: 'python'
502
- });
503
- const totalTime = Date.now() - start;
504
-
505
- const output = JSON.parse(result.stdout);
506
- console.log(`${name}:`);
507
- console.log(` Computation: ${output.result}`);
508
- console.log(` Execution time: ${output.elapsed_ms}ms`);
509
- console.log(` Total time: ${totalTime}ms`);
510
- console.log(` Provider overhead: ${totalTime - output.elapsed_ms}ms`);
511
- console.log();
512
-
513
- } catch (error) {
514
- console.log(`${name}: Failed - ${error.message}`);
515
- console.log();
516
- }
517
- }
518
- }
393
+ #### Terminal Properties
519
394
 
520
- compareProviders().catch(console.error);
395
+ ```typescript
396
+ console.log(pty.id); // Terminal ID
397
+ console.log(pty.status); // 'running' | 'stopped' | 'active' | 'ready'
398
+ console.log(pty.channel); // WebSocket channel (PTY only)
399
+ console.log(pty.pty); // true for PTY mode
521
400
  ```
522
401
 
523
- ## Error Handling
402
+ ### Exec Mode (Command Tracking)
524
403
 
525
- ComputeSDK provides comprehensive error handling with specific error types:
404
+ Exec mode executes commands with structured result tracking, suitable for automation.
526
405
 
527
- ```typescript
528
- import { ComputeSDK } from 'computesdk';
406
+ #### `terminal.command.run(command, options?)`
529
407
 
530
- try {
531
- const sandbox = ComputeSDK.createSandbox();
532
- const result = await sandbox.execute('invalid python code');
533
- } catch (error) {
534
- if (error.message.includes('Missing') && error.message.includes('API key')) {
535
- console.error('Authentication Error: Check your environment variables');
536
- console.error('Required: E2B_API_KEY, VERCEL_TOKEN, etc.');
537
- } else if (error.message.includes('timeout')) {
538
- console.error('Timeout Error: Execution took too long');
539
- } else if (error.message.includes('quota') || error.message.includes('limit')) {
540
- console.error('Quota Error: API usage limits exceeded');
541
- } else if (error.message.includes('not installed')) {
542
- console.error('Configuration Error: Provider package not installed');
543
- console.error('Run: npm install @computesdk/[provider-name]');
544
- } else {
545
- console.error('Execution Error:', error.message);
546
- }
547
- }
408
+ Execute a command in the terminal.
409
+
410
+ ```typescript
411
+ const exec = await sandbox.terminal.create({ pty: false });
412
+
413
+ // Foreground execution (waits for completion)
414
+ const cmd = await exec.command.run('npm test');
415
+ console.log(cmd.stdout);
416
+ console.log(cmd.stderr);
417
+ console.log(cmd.exitCode);
418
+
419
+ // Background execution (returns immediately)
420
+ const bgCmd = await exec.command.run('npm install', { background: true });
421
+ console.log(bgCmd.status); // 'running'
422
+ await bgCmd.wait(); // Wait for completion
423
+ console.log(bgCmd.exitCode);
548
424
  ```
549
425
 
550
- ## Provider-Specific Features
426
+ **Parameters:**
427
+ - `command: string` - The command to execute
428
+ - `options?: { background?: boolean }` - Execution options
429
+
430
+ **Returns:** `Command` object
551
431
 
552
- ### E2B - Full Development Environment
432
+ #### `terminal.command.list()`
553
433
 
554
- E2B provides the richest feature set with full filesystem and terminal support:
434
+ List all commands executed in this terminal.
555
435
 
556
436
  ```typescript
557
- import { e2b } from '@computesdk/e2b';
437
+ const commands = await exec.command.list();
438
+ commands.forEach(cmd => {
439
+ console.log(cmd.id, cmd.command, cmd.status, cmd.exitCode);
440
+ });
441
+ ```
558
442
 
559
- const sandbox = e2b();
443
+ #### `terminal.command.retrieve(cmdId)`
560
444
 
561
- // Full Python environment with data science libraries
562
- const result = await sandbox.execute(`
563
- import pandas as pd
564
- import matplotlib.pyplot as plt
565
- import numpy as np
445
+ Retrieve a specific command by ID.
566
446
 
567
- # Create and visualize data
568
- data = np.random.randn(1000)
569
- plt.hist(data, bins=50)
570
- plt.savefig('/tmp/histogram.png')
571
- print("Histogram saved!")
572
- `);
447
+ ```typescript
448
+ const cmd = await exec.command.retrieve('cmd-123');
449
+ console.log(cmd.stdout);
450
+ ```
451
+
452
+ ### Command Object
453
+
454
+ The `Command` object represents a command execution result.
455
+
456
+ #### Command Properties
573
457
 
574
- // Check if file was created
575
- const exists = await sandbox.filesystem.exists('/tmp/histogram.png');
576
- console.log('Histogram created:', exists);
458
+ ```typescript
459
+ console.log(cmd.id); // Command ID
460
+ console.log(cmd.terminalId); // Parent terminal ID
461
+ console.log(cmd.command); // Executed command
462
+ console.log(cmd.status); // 'running' | 'completed' | 'failed'
463
+ console.log(cmd.stdout); // Standard output
464
+ console.log(cmd.stderr); // Standard error
465
+ console.log(cmd.exitCode); // Exit code (undefined if running)
466
+ console.log(cmd.durationMs); // Execution time in milliseconds
467
+ console.log(cmd.startedAt); // Start timestamp
468
+ console.log(cmd.finishedAt); // Finish timestamp (undefined if running)
577
469
  ```
578
470
 
579
- ### Vercel - Scalable Serverless Execution
471
+ #### `command.wait(timeout?)`
580
472
 
581
- Vercel provides reliable execution with filesystem support:
473
+ Wait for a background command to complete.
582
474
 
583
475
  ```typescript
584
- import { vercel } from '@computesdk/vercel';
476
+ const cmd = await exec.command.run('sleep 5', { background: true });
477
+ await cmd.wait(); // Waits up to default timeout
478
+ console.log(cmd.exitCode);
479
+
480
+ // With custom timeout (in seconds, 0 = no timeout)
481
+ await cmd.wait(10);
482
+ ```
585
483
 
586
- const sandbox = vercel({ runtime: 'node' });
484
+ #### `command.refresh()`
587
485
 
588
- // Process data with Node.js
589
- const result = await sandbox.execute(`
590
- const fs = require('fs');
591
- const path = require('path');
486
+ Refresh the command status from the server.
592
487
 
593
- // Create API simulation
594
- const apiData = {
595
- users: 1000,
596
- active: 750,
597
- revenue: 50000
598
- };
488
+ ```typescript
489
+ const cmd = await exec.command.run('npm build', { background: true });
490
+ // ... later ...
491
+ await cmd.refresh();
492
+ console.log(cmd.status, cmd.exitCode);
493
+ ```
599
494
 
600
- // Write to filesystem
601
- fs.writeFileSync('/tmp/api-data.json', JSON.stringify(apiData, null, 2));
495
+ #### `terminal.destroy()`
602
496
 
603
- console.log('API data processed and saved');
604
- console.log('Active users:', apiData.active);
605
- `);
497
+ Destroy the terminal and clean up resources.
606
498
 
607
- // Read the generated data
608
- const data = await sandbox.filesystem.readFile('/tmp/api-data.json');
609
- console.log('Generated data:', JSON.parse(data));
499
+ ```typescript
500
+ await exec.destroy();
610
501
  ```
611
502
 
612
- ### Daytona - Development Workspaces
503
+ ## Examples
613
504
 
614
- Daytona provides development workspace environments with full filesystem support:
505
+ ### Multi-Step Build Process
615
506
 
616
507
  ```typescript
617
- import { daytona } from '@computesdk/daytona';
508
+ import { compute } from 'computesdk';
618
509
 
619
- const sandbox = daytona({ runtime: 'python' });
510
+ const sandbox = await compute.sandbox.create();
620
511
 
621
- // Execute Python code in workspace
622
- const result = await sandbox.execute(`
623
- import json
624
- import os
512
+ // Create project structure
513
+ await sandbox.filesystem.mkdir('/app');
514
+ await sandbox.filesystem.mkdir('/app/src');
515
+
516
+ // Write package.json
517
+ await sandbox.filesystem.writeFile('/app/package.json', JSON.stringify({
518
+ name: 'my-app',
519
+ version: '1.0.0',
520
+ dependencies: {
521
+ 'express': '^4.18.0'
522
+ }
523
+ }, null, 2));
625
524
 
626
- # Create project structure
627
- os.makedirs('/workspace/src', exist_ok=True)
628
- os.makedirs('/workspace/tests', exist_ok=True)
525
+ // Write source code
526
+ await sandbox.filesystem.writeFile('/app/src/index.js', `
527
+ const express = require('express');
528
+ const app = express();
629
529
 
630
- # Write project files
631
- with open('/workspace/src/main.py', 'w') as f:
632
- f.write('def hello():\\n return "Hello from Daytona!"\\n')
530
+ app.get('/', (req, res) => {
531
+ res.json({ message: 'Hello World!' });
532
+ });
533
+
534
+ console.log('Server ready!');
535
+ `);
633
536
 
634
- with open('/workspace/tests/test_main.py', 'w') as f:
635
- f.write('from src.main import hello\\n\\ndef test_hello():\\n assert hello() == "Hello from Daytona!"\\n')
537
+ // Install dependencies
538
+ const installResult = await sandbox.runCommand('npm install', { cwd: '/app' });
539
+ console.log('Install:', installResult.stdout);
636
540
 
637
- print("Project structure created!")
638
- print("Files:", os.listdir('/workspace'))
541
+ // Run the app
542
+ const runResult = await sandbox.runCode(`
543
+ const { spawn } = require('child_process');
544
+ const proc = spawn('node', ['src/index.js'], { cwd: '/app' });
545
+ proc.stdout.on('data', (data) => console.log(data.toString()));
639
546
  `);
640
547
 
641
- // Check created files
642
- const files = await sandbox.filesystem.readdir('/workspace');
643
- console.log('Workspace files:', files.map(f => f.name));
548
+ console.log(runResult.output);
644
549
 
645
- // Read project file
646
- const mainPy = await sandbox.filesystem.readFile('/workspace/src/main.py');
647
- console.log('main.py content:', mainPy);
550
+ await sandbox.destroy();
648
551
  ```
649
552
 
553
+ ### Terminal Command Execution
650
554
 
555
+ ```typescript
556
+ import { compute } from 'computesdk';
651
557
 
652
- ## Best Practices
558
+ const sandbox = await compute.sandbox.create();
653
559
 
654
- ### 1. Provider Selection
560
+ // Create exec mode terminal for command tracking
561
+ const terminal = await sandbox.terminal.create({ pty: false });
655
562
 
656
- Choose providers based on your use case:
563
+ // Run build commands with tracking
564
+ const install = await terminal.command.run('npm install');
565
+ console.log('Install exit code:', install.exitCode);
657
566
 
658
- - **E2B**: Data science, ML, interactive development, full Python environment
659
- - **Vercel**: Web applications, APIs, serverless functions, long-running tasks
660
- - **Daytona**: Development workspaces, custom environments, team collaboration
567
+ const build = await terminal.command.run('npm run build');
568
+ console.log('Build output:', build.stdout);
661
569
 
662
- ### 2. Resource Management
570
+ // Run tests in background
571
+ const tests = await terminal.command.run('npm test', { background: true });
572
+ console.log('Tests started:', tests.status);
663
573
 
664
- Always clean up resources:
574
+ // Wait for tests to complete
575
+ await tests.wait(60); // 60 second timeout
576
+ console.log('Tests completed:', tests.exitCode === 0 ? 'PASSED' : 'FAILED');
577
+ console.log('Test output:', tests.stdout);
665
578
 
666
- ```typescript
667
- const sandbox = ComputeSDK.createSandbox();
668
- try {
669
- // Your code here
670
- const result = await sandbox.execute('print("Hello")');
671
- } finally {
672
- // Always clean up
673
- await sandbox.kill();
674
- }
675
- ```
579
+ // List all commands
580
+ const commands = await terminal.command.list();
581
+ console.log(`Executed ${commands.length} commands`);
676
582
 
677
- ### 3. Error Handling
583
+ await terminal.destroy();
584
+ await sandbox.destroy();
585
+ ```
678
586
 
679
- Implement comprehensive error handling:
587
+ ### Interactive Terminal Session
680
588
 
681
589
  ```typescript
682
- async function robustExecution(code: string) {
683
- let sandbox;
684
- try {
685
- sandbox = ComputeSDK.createSandbox();
686
- return await sandbox.execute(code);
687
- } catch (error) {
688
- console.error('Execution failed:', error.message);
689
- throw error;
690
- } finally {
691
- if (sandbox) {
692
- await sandbox.kill();
693
- }
694
- }
695
- }
696
- ```
590
+ import { compute } from 'computesdk';
591
+
592
+ const sandbox = await compute.sandbox.create();
593
+
594
+ // Create PTY terminal for interactive shell
595
+ const pty = await sandbox.terminal.create({
596
+ pty: true,
597
+ shell: '/bin/bash'
598
+ });
599
+
600
+ // Collect all output
601
+ let output = '';
602
+ pty.on('output', (data) => {
603
+ output += data;
604
+ console.log(data);
605
+ });
606
+
607
+ pty.on('error', (error) => {
608
+ console.error('Terminal error:', error);
609
+ });
610
+
611
+ // Execute interactive commands
612
+ pty.write('echo "Starting project setup"\n');
613
+ pty.write('mkdir -p /workspace/myproject\n');
614
+ pty.write('cd /workspace/myproject\n');
615
+ pty.write('npm init -y\n');
616
+ pty.write('npm install express\n');
617
+ pty.write('echo "Setup complete"\n');
618
+
619
+ // Wait for operations to complete
620
+ await new Promise(resolve => setTimeout(resolve, 5000));
697
621
 
698
- ### 4. Type Safety
622
+ // Clean up
623
+ await pty.destroy();
624
+ await sandbox.destroy();
699
625
 
700
- Use TypeScript interfaces for better development experience:
626
+ console.log('Complete output:', output);
627
+ ```
628
+
629
+ ### Using Different Providers
701
630
 
702
631
  ```typescript
703
- import { FilesystemComputeSandbox, TerminalComputeSandbox } from 'computesdk';
632
+ import { compute } from 'computesdk';
704
633
 
705
- function requiresFilesystem(sandbox: FilesystemComputeSandbox) {
706
- // TypeScript ensures filesystem operations are available
707
- return sandbox.filesystem.readFile('/path/to/file');
708
- }
634
+ // Use E2B for data science
635
+ compute.setConfig({
636
+ provider: 'e2b',
637
+ e2b: { apiKey: process.env.E2B_API_KEY }
638
+ });
639
+
640
+ const e2bSandbox = await compute.sandbox.create();
641
+ await e2bSandbox.runCode('import pandas as pd; print(pd.__version__)');
642
+ await e2bSandbox.destroy();
643
+
644
+ // Switch to Modal for GPU workloads
645
+ compute.setConfig({
646
+ provider: 'modal',
647
+ modal: {
648
+ tokenId: process.env.MODAL_TOKEN_ID,
649
+ tokenSecret: process.env.MODAL_TOKEN_SECRET
650
+ }
651
+ });
652
+
653
+ const modalSandbox = await compute.sandbox.create();
654
+ await modalSandbox.runCode('import torch; print(torch.cuda.is_available())');
655
+ await modalSandbox.destroy();
656
+ ```
657
+
658
+ ## Error Handling
709
659
 
710
- function requiresTerminal(sandbox: TerminalComputeSandbox) {
711
- // TypeScript ensures terminal operations are available
712
- return sandbox.terminal.create({ command: 'bash' });
660
+ ```typescript
661
+ try {
662
+ const sandbox = await compute.sandbox.create();
663
+ const result = await sandbox.runCode('invalid python code');
664
+ } catch (error) {
665
+ console.error('Execution failed:', error.message);
666
+
667
+ // Check for specific error types
668
+ if (error.message.includes('No provider detected')) {
669
+ console.error('Set provider credentials in environment variables');
670
+ }
713
671
  }
714
672
  ```
715
673
 
716
- ## Contributing
674
+ ## Direct Mode (Advanced)
717
675
 
718
- We welcome contributions! Please see our [Contributing Guide](https://github.com/computesdk/computesdk/blob/main/CONTRIBUTING.md) for details.
676
+ For advanced use cases where you want to bypass the gateway and use provider SDKs directly, see individual provider packages:
719
677
 
720
- ### Adding New Providers
678
+ - **[@computesdk/e2b](../e2b)** - E2B provider
679
+ - **[@computesdk/modal](../modal)** - Modal provider
680
+ - **[@computesdk/railway](../railway)** - Railway provider
681
+ - **[@computesdk/daytona](../daytona)** - Daytona provider
721
682
 
722
- 1. Implement the appropriate `ComputeSpecification` interface:
723
- - `BaseComputeSpecification` for basic execution
724
- - `FilesystemComputeSpecification` for filesystem support
725
- - `TerminalComputeSpecification` for terminal support
726
- - `FullComputeSpecification` for complete functionality
683
+ Example direct mode usage:
727
684
 
728
- 2. Add comprehensive tests covering all implemented interfaces
685
+ ```typescript
686
+ import { e2b } from '@computesdk/e2b';
729
687
 
730
- 3. Include documentation and examples
688
+ const compute = e2b({ apiKey: 'your_api_key' });
689
+ const sandbox = await compute.sandbox.create();
690
+ ```
731
691
 
732
- 4. Submit a pull request
692
+ ## Building Custom Providers
733
693
 
734
- ## License
694
+ Want to add support for a new compute provider? See **[@computesdk/provider](../provider)** for the provider framework and documentation on building custom providers.
735
695
 
736
- MIT - see [LICENSE](https://github.com/computesdk/computesdk/blob/main/LICENSE) for details.
696
+ ## TypeScript Support
737
697
 
738
- ## Support
698
+ Full TypeScript support with comprehensive type definitions:
739
699
 
740
- - [GitHub Issues](https://github.com/computesdk/computesdk/issues)
741
- - [Documentation](https://github.com/computesdk/computesdk)
742
- - [Examples](https://github.com/computesdk/computesdk/tree/main/examples)
700
+ ```typescript
701
+ import type {
702
+ Sandbox,
703
+ SandboxInfo,
704
+ CodeResult,
705
+ CommandResult,
706
+ CreateSandboxOptions
707
+ } from 'computesdk';
708
+ ```
743
709
 
744
- ---
710
+ ## License
745
711
 
746
- Made with ❤️ by the ComputeSDK team
712
+ MIT