instavm 0.8.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +201 -769
- package/dist/index.d.mts +351 -4
- package/dist/index.d.ts +351 -4
- package/dist/index.js +852 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +843 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,17 +1,8 @@
|
|
|
1
1
|
# InstaVM JavaScript SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+

|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
- **Code Execution**: Run Python, Bash, and other languages in secure cloud environments
|
|
8
|
-
- **Browser Automation**: Control web browsers for testing, scraping, and automation
|
|
9
|
-
- **Session Management**: Automatic session creation and persistent execution contexts
|
|
10
|
-
- **File Operations**: Upload files to execution environments
|
|
11
|
-
- **Async Support**: Execute commands asynchronously for long-running tasks
|
|
12
|
-
- **Error Handling**: Comprehensive exception hierarchy for different failure modes
|
|
13
|
-
- **TypeScript Support**: Full type safety with comprehensive TypeScript definitions
|
|
14
|
-
- **Modern JavaScript**: ES modules, CommonJS, and UMD support
|
|
5
|
+
Official JavaScript/TypeScript client for InstaVM code execution, VM lifecycle, snapshots, networking controls, browser automation, and platform APIs.
|
|
15
6
|
|
|
16
7
|
## Installation
|
|
17
8
|
|
|
@@ -21,905 +12,346 @@ npm install instavm
|
|
|
21
12
|
|
|
22
13
|
## Quick Start
|
|
23
14
|
|
|
24
|
-
###
|
|
15
|
+
### Cloud Quick Start
|
|
25
16
|
|
|
26
17
|
```typescript
|
|
27
|
-
import { InstaVM
|
|
18
|
+
import { InstaVM } from 'instavm';
|
|
28
19
|
|
|
29
|
-
|
|
30
|
-
const client = new InstaVM('your_api_key');
|
|
20
|
+
const client = new InstaVM(process.env.INSTAVM_API_KEY || 'your_api_key');
|
|
31
21
|
|
|
32
22
|
try {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
console.log(result);
|
|
23
|
+
const result = await client.execute("print('hello from instavm')");
|
|
24
|
+
console.log(result.stdout);
|
|
36
25
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
console.log(usage);
|
|
40
|
-
|
|
41
|
-
} catch (error) {
|
|
42
|
-
if (error instanceof ExecutionError) {
|
|
43
|
-
console.log(`Code execution failed: ${error.message}`);
|
|
44
|
-
} else if (error instanceof NetworkError) {
|
|
45
|
-
console.log(`Network issue: ${error.message}`);
|
|
46
|
-
}
|
|
26
|
+
const usage = await client.getUsage();
|
|
27
|
+
console.log(usage);
|
|
47
28
|
} finally {
|
|
48
|
-
|
|
29
|
+
await client.dispose();
|
|
49
30
|
}
|
|
50
31
|
```
|
|
51
32
|
|
|
52
|
-
### Local
|
|
53
|
-
|
|
54
|
-
Run code execution against a local container (e.g., [coderunner](https://github.com/instavm/coderunner)) instead of the cloud API:
|
|
33
|
+
### Local Mode Quick Start
|
|
55
34
|
|
|
56
35
|
```typescript
|
|
57
36
|
import { InstaVM } from 'instavm';
|
|
58
37
|
|
|
59
|
-
// Create client in local mode (no API key required)
|
|
60
38
|
const client = new InstaVM('', {
|
|
61
|
-
|
|
62
|
-
|
|
39
|
+
local: true,
|
|
40
|
+
localURL: 'http://coderunner.local:8222',
|
|
63
41
|
});
|
|
64
42
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
console.log(result.output);
|
|
43
|
+
const result = await client.execute("print('hello from local mode')");
|
|
44
|
+
console.log(result.stdout);
|
|
68
45
|
|
|
69
|
-
// Browser automation in local mode (no session required)
|
|
70
46
|
const content = await client.browser.extractContent({
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
47
|
+
url: 'https://example.com',
|
|
48
|
+
includeInteractive: true,
|
|
49
|
+
includeAnchors: true,
|
|
74
50
|
});
|
|
75
|
-
console.log('Page title:', content.readableContent.title);
|
|
76
|
-
console.log('Clean content:', content.readableContent.content);
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
**Note:** Local mode supports:
|
|
80
|
-
- ✅ Code execution (`execute()`)
|
|
81
|
-
- ✅ Browser navigation (`browser.navigate()`)
|
|
82
|
-
- ✅ Content extraction (`browser.extractContent()`)
|
|
83
|
-
|
|
84
|
-
Local mode does NOT support (cloud-only features):
|
|
85
|
-
- ❌ Session management (`createSession()`, `closeSession()`, `getUsage()`)
|
|
86
|
-
- ❌ File upload/download
|
|
87
|
-
- ❌ Async execution
|
|
88
|
-
- ❌ Browser session creation and complex interactions
|
|
89
51
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
```typescript
|
|
93
|
-
import { InstaVM } from 'instavm';
|
|
94
|
-
|
|
95
|
-
const client = new InstaVM('your_api_key');
|
|
96
|
-
|
|
97
|
-
// Upload files to the execution environment
|
|
98
|
-
const files = [
|
|
99
|
-
{
|
|
100
|
-
name: 'script.py',
|
|
101
|
-
content: 'print("Hello from uploaded file!")',
|
|
102
|
-
path: '/remote/path/script.py'
|
|
103
|
-
}
|
|
104
|
-
];
|
|
105
|
-
|
|
106
|
-
const result = await client.upload(files);
|
|
107
|
-
console.log(result);
|
|
108
|
-
|
|
109
|
-
// Execute the uploaded file
|
|
110
|
-
const execution = await client.execute('python /remote/path/script.py', {
|
|
111
|
-
language: 'bash'
|
|
112
|
-
});
|
|
113
|
-
console.log(execution.output);
|
|
52
|
+
console.log(content.readableContent.title);
|
|
114
53
|
```
|
|
115
54
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
import { InstaVM } from 'instavm';
|
|
120
|
-
import fs from 'fs';
|
|
121
|
-
|
|
122
|
-
const client = new InstaVM('your_api_key');
|
|
123
|
-
|
|
124
|
-
// Create a file in the remote environment
|
|
125
|
-
await client.execute(`
|
|
126
|
-
import pandas as pd
|
|
127
|
-
df = pd.DataFrame({'name': ['Alice', 'Bob'], 'age': [25, 30]})
|
|
128
|
-
df.to_csv('data.csv', index=False)
|
|
129
|
-
`);
|
|
130
|
-
|
|
131
|
-
// Download the file
|
|
132
|
-
const result = await client.download('data.csv');
|
|
133
|
-
console.log(`Downloaded ${result.size} bytes`);
|
|
55
|
+
## Table of Contents
|
|
134
56
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
57
|
+
- [Core Workflows](#core-workflows)
|
|
58
|
+
- [Infrastructure & Platform APIs](#infrastructure-platform-apis)
|
|
59
|
+
- [Browser & Computer Use](#browser-computer-use)
|
|
60
|
+
- [Error Handling](#error-handling)
|
|
61
|
+
- [Development & Testing](#development-testing)
|
|
62
|
+
- [Docs Map (Further Reading)](#docs-map-further-reading)
|
|
63
|
+
- [Version / Changelog](#version-changelog)
|
|
140
64
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
InstaVM,
|
|
144
|
-
AuthenticationError,
|
|
145
|
-
RateLimitError,
|
|
146
|
-
SessionError,
|
|
147
|
-
QuotaExceededError
|
|
148
|
-
} from 'instavm';
|
|
65
|
+
<a id="core-workflows"></a>
|
|
66
|
+
## Core Workflows
|
|
149
67
|
|
|
150
|
-
|
|
151
|
-
const client = new InstaVM('invalid_key');
|
|
152
|
-
await client.execute('print("test")');
|
|
153
|
-
} catch (error) {
|
|
154
|
-
if (error instanceof AuthenticationError) {
|
|
155
|
-
console.log("Invalid API key");
|
|
156
|
-
} else if (error instanceof RateLimitError) {
|
|
157
|
-
console.log(`Rate limit exceeded - retry after ${error.retryAfter} seconds`);
|
|
158
|
-
} else if (error instanceof QuotaExceededError) {
|
|
159
|
-
console.log("Usage quota exceeded");
|
|
160
|
-
} else if (error instanceof SessionError) {
|
|
161
|
-
console.log(`Session error: ${error.message}`);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
```
|
|
68
|
+
### Cloud Quick Start
|
|
165
69
|
|
|
166
|
-
|
|
70
|
+
Cloud mode supports sessions, VM/network controls, platform APIs, and browser sessions.
|
|
167
71
|
|
|
168
72
|
```typescript
|
|
169
73
|
import { InstaVM } from 'instavm';
|
|
170
74
|
|
|
171
|
-
const client = new InstaVM('your_api_key'
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
75
|
+
const client = new InstaVM('your_api_key', {
|
|
76
|
+
cpu_count: 2,
|
|
77
|
+
memory_mb: 1024,
|
|
78
|
+
env: { APP_ENV: 'dev' },
|
|
79
|
+
metadata: { team: 'platform' },
|
|
176
80
|
});
|
|
177
81
|
|
|
178
|
-
|
|
179
|
-
console.log(
|
|
82
|
+
const sessionId = await client.createSession();
|
|
83
|
+
console.log('session:', sessionId);
|
|
180
84
|
```
|
|
181
85
|
|
|
182
|
-
|
|
86
|
+
### Local Mode Quick Start
|
|
183
87
|
|
|
184
|
-
|
|
88
|
+
Local mode is optimized for direct execution and lightweight browser helpers.
|
|
185
89
|
|
|
186
90
|
```typescript
|
|
187
91
|
import { InstaVM } from 'instavm';
|
|
188
92
|
|
|
189
|
-
const client = new InstaVM('
|
|
190
|
-
|
|
191
|
-
// Create browser session
|
|
192
|
-
const session = await client.browser.createSession({
|
|
193
|
-
viewportWidth: 1920,
|
|
194
|
-
viewportHeight: 1080
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
// Navigate to website
|
|
198
|
-
await session.navigate('https://example.com');
|
|
199
|
-
|
|
200
|
-
// Take screenshot
|
|
201
|
-
const screenshot = await session.screenshot();
|
|
202
|
-
console.log(`Screenshot captured: ${screenshot.length} chars`);
|
|
203
|
-
|
|
204
|
-
// Extract page data
|
|
205
|
-
const elements = await session.extractElements('h1, p', ['text', 'href']);
|
|
206
|
-
console.log('Page content:', elements);
|
|
93
|
+
const client = new InstaVM('', { local: true });
|
|
207
94
|
|
|
208
|
-
|
|
209
|
-
await
|
|
95
|
+
await client.execute("print('local execution works')");
|
|
96
|
+
await client.browser.navigate('https://example.com');
|
|
210
97
|
```
|
|
211
98
|
|
|
212
|
-
###
|
|
99
|
+
### File Operations
|
|
213
100
|
|
|
214
101
|
```typescript
|
|
215
|
-
|
|
216
|
-
await session.navigate('https://github.com/login', {
|
|
217
|
-
waitTimeout: 30000,
|
|
218
|
-
waitUntil: 'networkidle'
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
// Fill login form
|
|
222
|
-
await session.fill('input[name="login"]', 'username');
|
|
223
|
-
await session.fill('input[name="password"]', 'password');
|
|
102
|
+
import { InstaVM } from 'instavm';
|
|
224
103
|
|
|
225
|
-
|
|
226
|
-
await
|
|
104
|
+
const client = new InstaVM('your_api_key');
|
|
105
|
+
const sessionId = await client.createSession();
|
|
227
106
|
|
|
228
|
-
|
|
229
|
-
|
|
107
|
+
await client.upload(
|
|
108
|
+
[{ name: 'script.py', content: "print('uploaded')", path: '/app/script.py' }],
|
|
109
|
+
{ sessionId }
|
|
110
|
+
);
|
|
230
111
|
|
|
231
|
-
|
|
232
|
-
await session.scroll({ y: 1000 });
|
|
112
|
+
await client.execute('python /app/script.py', { language: 'bash', sessionId });
|
|
233
113
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
console.log('Repositories found:', repos.length);
|
|
114
|
+
const download = await client.download('output.json', { sessionId });
|
|
115
|
+
console.log(download.filename, download.size);
|
|
237
116
|
```
|
|
238
117
|
|
|
239
|
-
###
|
|
118
|
+
### Async Execution
|
|
240
119
|
|
|
241
120
|
```typescript
|
|
242
|
-
|
|
243
|
-
const session = await client.browser.createSession({
|
|
244
|
-
viewportWidth: 1280,
|
|
245
|
-
viewportHeight: 720,
|
|
246
|
-
userAgent: 'CustomBot/1.0'
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
// Session supports event listeners
|
|
250
|
-
session.on('navigation', (result) => {
|
|
251
|
-
console.log(`Navigated to: ${result.url}`);
|
|
252
|
-
console.log(`Page title: ${result.title}`);
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
session.on('error', (error) => {
|
|
256
|
-
console.error('Session error:', error.message);
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
session.on('close', () => {
|
|
260
|
-
console.log('Session closed');
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
// Check if session is still active
|
|
264
|
-
if (session.isActive) {
|
|
265
|
-
await session.navigate('https://example.com');
|
|
266
|
-
}
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
### Context Manager Pattern
|
|
121
|
+
import { InstaVM } from 'instavm';
|
|
270
122
|
|
|
271
|
-
```typescript
|
|
272
|
-
// Use browser session with automatic cleanup
|
|
273
123
|
const client = new InstaVM('your_api_key');
|
|
274
124
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
try {
|
|
279
|
-
await session.navigate('https://httpbin.org/forms/post');
|
|
280
|
-
|
|
281
|
-
// Fill and submit form
|
|
282
|
-
await session.fill('input[name="custname"]', 'John Doe');
|
|
283
|
-
await session.fill('input[name="custtel"]', '555-1234');
|
|
284
|
-
await session.click('input[type="submit"]');
|
|
285
|
-
|
|
286
|
-
// Wait for result
|
|
287
|
-
await session.wait({ type: 'visible', selector: 'pre' });
|
|
288
|
-
|
|
289
|
-
// Extract result
|
|
290
|
-
const result = await session.extractElements('pre', ['text']);
|
|
291
|
-
return result[0]?.text;
|
|
292
|
-
|
|
293
|
-
} finally {
|
|
294
|
-
await session.close();
|
|
295
|
-
}
|
|
296
|
-
}
|
|
125
|
+
const task = await client.executeAsync("sleep 5 && echo 'done'", { language: 'bash' });
|
|
126
|
+
const result = await client.getTaskResult(task.taskId, 2, 60);
|
|
297
127
|
|
|
298
|
-
|
|
299
|
-
console.log('Form submission result:', result);
|
|
128
|
+
console.log(result.stdout);
|
|
300
129
|
```
|
|
301
130
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
Combine code execution with browser automation for powerful workflows:
|
|
131
|
+
### VMs + Snapshots
|
|
305
132
|
|
|
306
133
|
```typescript
|
|
307
134
|
import { InstaVM } from 'instavm';
|
|
308
135
|
|
|
309
136
|
const client = new InstaVM('your_api_key');
|
|
310
137
|
|
|
311
|
-
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
const headlines = await session.extractElements('.titleline > a', ['text', 'href']);
|
|
332
|
-
results.push({
|
|
333
|
-
term,
|
|
334
|
-
headlines: headlines.slice(0, 5) // Top 5 results
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
await session.close();
|
|
339
|
-
|
|
340
|
-
// Process results with Python
|
|
341
|
-
const analysis = await client.execute(`
|
|
342
|
-
import json
|
|
343
|
-
data = ${JSON.stringify(results)}
|
|
344
|
-
|
|
345
|
-
# Analyze results
|
|
346
|
-
total_headlines = sum(len(item['headlines']) for item in data)
|
|
347
|
-
print(f"Collected {total_headlines} headlines across {len(data)} search terms")
|
|
348
|
-
|
|
349
|
-
# Find most common words
|
|
350
|
-
all_text = ' '.join([headline['text'] for item in data for headline in item['headlines']])
|
|
351
|
-
words = all_text.lower().split()
|
|
352
|
-
word_counts = {}
|
|
353
|
-
for word in words:
|
|
354
|
-
if len(word) > 3: # Filter short words
|
|
355
|
-
word_counts[word] = word_counts.get(word, 0) + 1
|
|
356
|
-
|
|
357
|
-
# Top 10 words
|
|
358
|
-
top_words = sorted(word_counts.items(), key=lambda x: x[1], reverse=True)[:10]
|
|
359
|
-
print("Top words:", top_words)
|
|
360
|
-
`);
|
|
361
|
-
|
|
362
|
-
console.log(analysis.output);
|
|
363
|
-
await client.dispose();
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
## Language Support
|
|
367
|
-
|
|
368
|
-
### Python Code Execution
|
|
138
|
+
const vm = await client.vms.create({ metadata: { purpose: 'dev' } }, true);
|
|
139
|
+
const vmId = String(vm.vm_id);
|
|
140
|
+
|
|
141
|
+
const vmList = await client.vms.list(); // GET /v1/vms
|
|
142
|
+
const vmAllRecords = await client.vms.listAllRecords(); // GET /v1/vms/
|
|
143
|
+
|
|
144
|
+
await client.vms.snapshot(vmId, { name: 'dev-base' }, true);
|
|
145
|
+
|
|
146
|
+
await client.snapshots.create({
|
|
147
|
+
oci_image: 'docker.io/library/python:3.11-slim',
|
|
148
|
+
name: 'python-3-11-dev',
|
|
149
|
+
vcpu_count: 2,
|
|
150
|
+
memory_mb: 1024,
|
|
151
|
+
type: 'user',
|
|
152
|
+
build_args: {
|
|
153
|
+
git_clone_url: 'https://github.com/example/repo.git',
|
|
154
|
+
git_clone_branch: 'main',
|
|
155
|
+
envs: { NODE_ENV: 'production' },
|
|
156
|
+
},
|
|
157
|
+
});
|
|
369
158
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
const result = await client.execute(`
|
|
373
|
-
import pandas as pd
|
|
374
|
-
import numpy as np
|
|
375
|
-
|
|
376
|
-
# Create sample data
|
|
377
|
-
data = pd.DataFrame({
|
|
378
|
-
'numbers': np.random.randn(100),
|
|
379
|
-
'categories': np.random.choice(['A', 'B', 'C'], 100)
|
|
380
|
-
})
|
|
381
|
-
|
|
382
|
-
# Basic statistics
|
|
383
|
-
print(f"Mean: {data['numbers'].mean():.2f}")
|
|
384
|
-
print(f"Std: {data['numbers'].std():.2f}")
|
|
385
|
-
print(f"Categories: {data['categories'].value_counts().to_dict()}")
|
|
386
|
-
`);
|
|
387
|
-
|
|
388
|
-
console.log(result.output);
|
|
159
|
+
const userSnapshots = await client.snapshots.list({ type: 'user' });
|
|
160
|
+
console.log(vmList.length, vmAllRecords.length, userSnapshots.length);
|
|
389
161
|
```
|
|
390
162
|
|
|
391
|
-
###
|
|
163
|
+
### Networking (Egress, Shares, SSH)
|
|
392
164
|
|
|
393
165
|
```typescript
|
|
394
|
-
|
|
395
|
-
const sysInfo = await client.execute(`
|
|
396
|
-
echo "System Information:"
|
|
397
|
-
echo "==================="
|
|
398
|
-
uname -a
|
|
399
|
-
echo
|
|
400
|
-
echo "Disk Usage:"
|
|
401
|
-
df -h
|
|
402
|
-
echo
|
|
403
|
-
echo "Memory Info:"
|
|
404
|
-
free -h
|
|
405
|
-
`, { language: 'bash' });
|
|
406
|
-
|
|
407
|
-
console.log(sysInfo.output);
|
|
408
|
-
```
|
|
166
|
+
import { InstaVM } from 'instavm';
|
|
409
167
|
|
|
410
|
-
|
|
168
|
+
const client = new InstaVM('your_api_key');
|
|
169
|
+
const sessionId = await client.createSession();
|
|
170
|
+
|
|
171
|
+
await client.setSessionEgress(
|
|
172
|
+
{
|
|
173
|
+
allowPackageManagers: true,
|
|
174
|
+
allowHttp: false,
|
|
175
|
+
allowHttps: true,
|
|
176
|
+
allowedDomains: ['npmjs.com', 'registry.npmjs.org'],
|
|
177
|
+
},
|
|
178
|
+
sessionId
|
|
179
|
+
);
|
|
411
180
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
await client.execute('data = [1, 2, 3, 4, 5]');
|
|
415
|
-
await client.execute('total = sum(data)');
|
|
181
|
+
const share = await client.shares.create({ session_id: sessionId, port: 3000, is_public: false });
|
|
182
|
+
await client.shares.update(String(share.share_id), { is_public: true });
|
|
416
183
|
|
|
417
|
-
const
|
|
418
|
-
console.log(
|
|
184
|
+
const key = await client.addSshKey('ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... user@host');
|
|
185
|
+
console.log(key);
|
|
419
186
|
```
|
|
420
187
|
|
|
421
|
-
|
|
188
|
+
<a id="infrastructure-platform-apis"></a>
|
|
189
|
+
## Infrastructure & Platform APIs
|
|
422
190
|
|
|
423
|
-
###
|
|
191
|
+
### Platform APIs (API Keys, Audit, Webhooks)
|
|
424
192
|
|
|
425
193
|
```typescript
|
|
426
|
-
|
|
427
|
-
await session.wait({
|
|
428
|
-
type: 'visible',
|
|
429
|
-
selector: '.loading-complete',
|
|
430
|
-
timeout: 30000
|
|
431
|
-
});
|
|
432
|
-
|
|
433
|
-
// Wait for element to disappear
|
|
434
|
-
await session.wait({
|
|
435
|
-
type: 'hidden',
|
|
436
|
-
selector: '.spinner'
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
// Wait for page load
|
|
440
|
-
await session.wait({
|
|
441
|
-
type: 'networkidle'
|
|
442
|
-
});
|
|
443
|
-
|
|
444
|
-
// Simple timeout
|
|
445
|
-
await session.wait({
|
|
446
|
-
type: 'timeout',
|
|
447
|
-
ms: 5000
|
|
448
|
-
});
|
|
449
|
-
```
|
|
194
|
+
import { InstaVM } from 'instavm';
|
|
450
195
|
|
|
451
|
-
|
|
196
|
+
const client = new InstaVM('your_api_key');
|
|
452
197
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
const fullPage = await session.screenshot({
|
|
456
|
-
fullPage: true,
|
|
457
|
-
format: 'png'
|
|
458
|
-
});
|
|
198
|
+
const apiKey = await client.apiKeys.create({ description: 'ci key' });
|
|
199
|
+
const events = await client.audit.events({ status: 'success', limit: 25 });
|
|
459
200
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
x: 0,
|
|
464
|
-
y: 0,
|
|
465
|
-
width: 800,
|
|
466
|
-
height: 600
|
|
467
|
-
},
|
|
468
|
-
format: 'jpeg',
|
|
469
|
-
quality: 90
|
|
201
|
+
const endpoint = await client.webhooks.createEndpoint({
|
|
202
|
+
url: 'https://example.com/instavm/webhook',
|
|
203
|
+
event_patterns: ['vm.*', 'snapshot.*'],
|
|
470
204
|
});
|
|
471
205
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
// Save to file if needed
|
|
206
|
+
const deliveries = await client.webhooks.listDeliveries({ limit: 10 });
|
|
207
|
+
console.log(apiKey, events, endpoint, deliveries);
|
|
475
208
|
```
|
|
476
209
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
```typescript
|
|
480
|
-
// Extract multiple attributes
|
|
481
|
-
const links = await session.extractElements('a', ['href', 'text', 'title']);
|
|
482
|
-
|
|
483
|
-
// Extract with CSS selectors
|
|
484
|
-
const articles = await session.extractElements('article h2, .post-title', ['text']);
|
|
485
|
-
|
|
486
|
-
// Extract form data
|
|
487
|
-
const formData = await session.extractElements('input, select, textarea', [
|
|
488
|
-
'name', 'value', 'type', 'placeholder'
|
|
489
|
-
]);
|
|
210
|
+
<a id="browser-computer-use"></a>
|
|
211
|
+
## Browser & Computer Use
|
|
490
212
|
|
|
491
|
-
|
|
492
|
-
console.log('Articles:', articles);
|
|
493
|
-
console.log('Form fields:', formData);
|
|
494
|
-
```
|
|
213
|
+
### Browser Automation
|
|
495
214
|
|
|
496
|
-
|
|
215
|
+
Basic browser session flow:
|
|
497
216
|
|
|
498
217
|
```typescript
|
|
499
|
-
|
|
500
|
-
const content = await session.extractContent({
|
|
501
|
-
includeInteractive: true, // Include clickable/typeable elements
|
|
502
|
-
includeAnchors: true, // Include content-to-selector mappings
|
|
503
|
-
maxAnchors: 50 // Limit number of anchors
|
|
504
|
-
});
|
|
218
|
+
import { InstaVM } from 'instavm';
|
|
505
219
|
|
|
506
|
-
|
|
507
|
-
console.log('Title:', content.readableContent.title);
|
|
508
|
-
console.log('Article:', content.readableContent.content);
|
|
509
|
-
console.log('Author:', content.readableContent.byline);
|
|
220
|
+
const client = new InstaVM('your_api_key');
|
|
510
221
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
);
|
|
515
|
-
if (loginButton) {
|
|
516
|
-
await session.click(loginButton.selector);
|
|
517
|
-
}
|
|
222
|
+
const browser = await client.browser.createSession({ viewportWidth: 1366, viewportHeight: 768 });
|
|
223
|
+
await browser.navigate('https://example.com');
|
|
224
|
+
await browser.click('a');
|
|
225
|
+
const screenshot = await browser.screenshot({ fullPage: true });
|
|
518
226
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
const signupLink = content.contentAnchors?.find(
|
|
522
|
-
anchor => anchor.text.toLowerCase().includes('sign up')
|
|
523
|
-
);
|
|
524
|
-
if (signupLink) {
|
|
525
|
-
await session.click(signupLink.selector);
|
|
526
|
-
}
|
|
227
|
+
console.log(screenshot.length);
|
|
228
|
+
await browser.close();
|
|
527
229
|
```
|
|
528
230
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
### Error Types
|
|
231
|
+
Advanced flow with waits and extraction:
|
|
532
232
|
|
|
533
233
|
```typescript
|
|
534
|
-
import {
|
|
535
|
-
InstaVMError, // Base error class
|
|
536
|
-
AuthenticationError, // API key issues
|
|
537
|
-
RateLimitError, // Rate limiting (has retryAfter property)
|
|
538
|
-
QuotaExceededError, // Usage quota exceeded
|
|
539
|
-
NetworkError, // Connection issues
|
|
540
|
-
ExecutionError, // Code execution failures
|
|
541
|
-
SessionError, // Session management issues
|
|
542
|
-
BrowserError, // General browser errors
|
|
543
|
-
BrowserSessionError, // Browser session issues
|
|
544
|
-
BrowserInteractionError, // Browser interaction failures
|
|
545
|
-
BrowserTimeoutError, // Browser operation timeouts
|
|
546
|
-
BrowserNavigationError, // Navigation failures
|
|
547
|
-
ElementNotFoundError, // Element selection issues (has selector property)
|
|
548
|
-
UnsupportedOperationError // Operation not supported in local mode
|
|
549
|
-
} from 'instavm';
|
|
550
|
-
|
|
551
|
-
// Specific error handling
|
|
552
|
-
try {
|
|
553
|
-
await session.click('.non-existent-button');
|
|
554
|
-
} catch (error) {
|
|
555
|
-
if (error instanceof ElementNotFoundError) {
|
|
556
|
-
console.log(`Element not found: ${error.selector}`);
|
|
557
|
-
} else if (error instanceof BrowserTimeoutError) {
|
|
558
|
-
console.log('Operation timed out');
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
```
|
|
562
|
-
|
|
563
|
-
### Retry Logic
|
|
564
|
-
|
|
565
|
-
The SDK includes automatic retry logic for:
|
|
566
|
-
- Network errors (connection issues)
|
|
567
|
-
- Rate limiting (with exponential backoff)
|
|
568
|
-
- Server errors (5xx status codes)
|
|
234
|
+
import { InstaVM } from 'instavm';
|
|
569
235
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
const client = new InstaVM('your_api_key', {
|
|
573
|
-
maxRetries: 5,
|
|
574
|
-
retryDelay: 2000, // Base delay in milliseconds
|
|
575
|
-
timeout: 300000 // 5 minute timeout
|
|
576
|
-
});
|
|
577
|
-
```
|
|
236
|
+
const client = new InstaVM('your_api_key');
|
|
237
|
+
const browser = await client.browser.createSession();
|
|
578
238
|
|
|
579
|
-
|
|
239
|
+
await browser.navigate('https://news.ycombinator.com');
|
|
240
|
+
await browser.wait({ type: 'visible', selector: 'a.storylink' }, 10000);
|
|
580
241
|
|
|
581
|
-
|
|
242
|
+
const links = await browser.extractElements('a.storylink', ['text', 'href']);
|
|
243
|
+
console.log(links.slice(0, 5));
|
|
582
244
|
|
|
583
|
-
|
|
584
|
-
class InstaVM {
|
|
585
|
-
constructor(apiKey: string, options?: InstaVMOptions)
|
|
586
|
-
|
|
587
|
-
// Code execution
|
|
588
|
-
execute(command: string, options?: ExecuteOptions): Promise<ExecutionResult>
|
|
589
|
-
executeAsync(command: string, options?: ExecuteOptions): Promise<AsyncExecutionResult>
|
|
590
|
-
|
|
591
|
-
// File operations
|
|
592
|
-
upload(files: FileUpload[], options?: UploadOptions): Promise<UploadResult>
|
|
593
|
-
download(filename: string, options?: DownloadOptions): Promise<DownloadResult>
|
|
594
|
-
|
|
595
|
-
// Session management
|
|
596
|
-
createSession(): Promise<string>
|
|
597
|
-
closeSession(sessionId?: string): Promise<void>
|
|
598
|
-
getUsage(sessionId?: string): Promise<UsageStats>
|
|
599
|
-
|
|
600
|
-
// Browser automation
|
|
601
|
-
browser: BrowserManager
|
|
602
|
-
|
|
603
|
-
// Properties
|
|
604
|
-
readonly sessionId: string | null
|
|
605
|
-
|
|
606
|
-
// Cleanup
|
|
607
|
-
dispose(): Promise<void>
|
|
608
|
-
}
|
|
245
|
+
await browser.close();
|
|
609
246
|
```
|
|
610
247
|
|
|
611
|
-
###
|
|
248
|
+
### LLM-Friendly Content Extraction (concise pattern only)
|
|
612
249
|
|
|
613
250
|
```typescript
|
|
614
|
-
|
|
615
|
-
baseURL?: string; // Default: 'https://api.instavm.io' (ignored if local=true)
|
|
616
|
-
timeout?: number; // Default: 300000 (5 minutes)
|
|
617
|
-
maxRetries?: number; // Default: 3
|
|
618
|
-
retryDelay?: number; // Default: 1000ms
|
|
619
|
-
local?: boolean; // Default: false - Use local container instead of cloud
|
|
620
|
-
localURL?: string; // Default: 'http://coderunner.local:8222' - Local container URL
|
|
621
|
-
}
|
|
251
|
+
import { InstaVM } from 'instavm';
|
|
622
252
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
timeout?: number; // Default: 15 seconds
|
|
626
|
-
sessionId?: string; // Use specific session
|
|
627
|
-
}
|
|
628
|
-
```
|
|
253
|
+
const client = new InstaVM('your_api_key');
|
|
254
|
+
const browser = await client.browser.createSession();
|
|
629
255
|
|
|
630
|
-
|
|
256
|
+
await browser.navigate('https://example.com/docs');
|
|
631
257
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
getLocalSession(sessionId: string): BrowserSession | undefined
|
|
638
|
-
getLocalSessions(): BrowserSession[]
|
|
639
|
-
closeAllSessions(): Promise<void>
|
|
640
|
-
dispose(): Promise<void>
|
|
641
|
-
}
|
|
258
|
+
const content = await browser.extractContent({
|
|
259
|
+
includeInteractive: true,
|
|
260
|
+
includeAnchors: true,
|
|
261
|
+
maxAnchors: 30,
|
|
262
|
+
});
|
|
642
263
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
userAgent?: string; // Custom user agent
|
|
264
|
+
console.log(content.readableContent.title);
|
|
265
|
+
for (const anchor of (content.contentAnchors || []).slice(0, 5)) {
|
|
266
|
+
console.log(anchor.text, anchor.selector);
|
|
647
267
|
}
|
|
648
|
-
```
|
|
649
268
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
```typescript
|
|
653
|
-
class BrowserSession extends EventEmitter {
|
|
654
|
-
// Navigation
|
|
655
|
-
navigate(url: string, options?: NavigateOptions): Promise<NavigationResult>
|
|
656
|
-
|
|
657
|
-
// Interaction
|
|
658
|
-
click(selector: string, options?: ClickOptions): Promise<void>
|
|
659
|
-
type(selector: string, text: string, options?: TypeOptions): Promise<void>
|
|
660
|
-
fill(selector: string, value: string, options?: FillOptions): Promise<void>
|
|
661
|
-
scroll(options?: ScrollOptions): Promise<void>
|
|
662
|
-
|
|
663
|
-
// Data extraction
|
|
664
|
-
screenshot(options?: ScreenshotOptions): Promise<string>
|
|
665
|
-
extractElements(selector: string, attributes?: string[]): Promise<ExtractedElement[]>
|
|
666
|
-
extractContent(options?: ExtractContentOptions): Promise<ExtractedContent>
|
|
667
|
-
|
|
668
|
-
// Utilities
|
|
669
|
-
wait(condition: WaitCondition, timeout?: number): Promise<void>
|
|
670
|
-
close(): Promise<void>
|
|
671
|
-
|
|
672
|
-
// Properties
|
|
673
|
-
readonly sessionId: string
|
|
674
|
-
readonly isActive: boolean
|
|
675
|
-
|
|
676
|
-
// Events: 'navigation', 'error', 'close'
|
|
677
|
-
}
|
|
269
|
+
await browser.close();
|
|
678
270
|
```
|
|
679
271
|
|
|
680
|
-
###
|
|
272
|
+
### Computer Use
|
|
681
273
|
|
|
682
274
|
```typescript
|
|
683
|
-
|
|
684
|
-
output: string;
|
|
685
|
-
success: boolean;
|
|
686
|
-
executionTime: number;
|
|
687
|
-
sessionId?: string;
|
|
688
|
-
error?: string;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
interface NavigationResult {
|
|
692
|
-
success: boolean;
|
|
693
|
-
url: string;
|
|
694
|
-
title?: string;
|
|
695
|
-
status?: number;
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
interface ExtractedElement {
|
|
699
|
-
text?: string;
|
|
700
|
-
href?: string;
|
|
701
|
-
[attribute: string]: string | undefined;
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
type WaitCondition =
|
|
705
|
-
| { type: 'timeout'; ms: number }
|
|
706
|
-
| { type: 'visible'; selector: string }
|
|
707
|
-
| { type: 'hidden'; selector: string }
|
|
708
|
-
| { type: 'navigation' }
|
|
709
|
-
| { type: 'networkidle' };
|
|
710
|
-
```
|
|
711
|
-
|
|
712
|
-
## Best Practices
|
|
713
|
-
|
|
714
|
-
### Resource Management
|
|
275
|
+
import { InstaVM } from 'instavm';
|
|
715
276
|
|
|
716
|
-
```typescript
|
|
717
|
-
// Always dispose of the client when done
|
|
718
277
|
const client = new InstaVM('your_api_key');
|
|
719
|
-
|
|
720
|
-
// Your automation code
|
|
721
|
-
} finally {
|
|
722
|
-
await client.dispose(); // Closes all sessions and cleans up
|
|
723
|
-
}
|
|
278
|
+
const sessionId = await client.createSession();
|
|
724
279
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
const client = new InstaVM(apiKey);
|
|
728
|
-
try {
|
|
729
|
-
await callback(client);
|
|
730
|
-
} finally {
|
|
731
|
-
await client.dispose();
|
|
732
|
-
}
|
|
733
|
-
}
|
|
280
|
+
const viewer = await client.computerUse.viewerUrl(sessionId);
|
|
281
|
+
const state = await client.computerUse.get(sessionId, '/state');
|
|
734
282
|
|
|
735
|
-
|
|
736
|
-
const result = await client.execute('print("Hello, World!")');
|
|
737
|
-
console.log(result.output);
|
|
738
|
-
});
|
|
283
|
+
console.log(viewer, state);
|
|
739
284
|
```
|
|
740
285
|
|
|
741
|
-
|
|
286
|
+
<a id="error-handling"></a>
|
|
287
|
+
## Error Handling
|
|
742
288
|
|
|
743
289
|
```typescript
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
let retries = 3;
|
|
753
|
-
while (retries > 0) {
|
|
754
|
-
try {
|
|
755
|
-
await session.navigate('https://example.com');
|
|
756
|
-
break;
|
|
757
|
-
} catch (error) {
|
|
758
|
-
if (error instanceof BrowserTimeoutError && retries > 1) {
|
|
759
|
-
console.log(`Navigation timeout, retrying... (${retries - 1} attempts left)`);
|
|
760
|
-
retries--;
|
|
761
|
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
762
|
-
} else {
|
|
763
|
-
throw error;
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
// Safe element interaction
|
|
769
|
-
try {
|
|
770
|
-
await session.click('button.submit');
|
|
771
|
-
} catch (error) {
|
|
772
|
-
if (error instanceof ElementNotFoundError) {
|
|
773
|
-
console.log('Submit button not found, trying alternative selector');
|
|
774
|
-
await session.click('input[type="submit"]');
|
|
775
|
-
} else {
|
|
776
|
-
throw error;
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
} catch (error) {
|
|
781
|
-
console.error('Automation failed:', error.message);
|
|
782
|
-
throw error;
|
|
783
|
-
} finally {
|
|
784
|
-
if (session) {
|
|
785
|
-
await session.close();
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
```
|
|
790
|
-
|
|
791
|
-
### Performance Optimization
|
|
792
|
-
|
|
793
|
-
```typescript
|
|
794
|
-
// Batch operations when possible
|
|
795
|
-
const session = await client.browser.createSession();
|
|
796
|
-
|
|
797
|
-
// Instead of multiple separate calls
|
|
798
|
-
await session.navigate('https://example.com');
|
|
799
|
-
const title = await session.extractElements('title', ['text']);
|
|
800
|
-
const links = await session.extractElements('a', ['href']);
|
|
801
|
-
const images = await session.extractElements('img', ['src', 'alt']);
|
|
802
|
-
|
|
803
|
-
// Consider using a single extraction call for related elements
|
|
804
|
-
const pageData = await session.extractElements('title, a, img', ['text', 'href', 'src', 'alt']);
|
|
805
|
-
|
|
806
|
-
// Use appropriate timeouts
|
|
807
|
-
await session.navigate('https://slow-site.com', {
|
|
808
|
-
waitTimeout: 60000 // Increase timeout for slow sites
|
|
809
|
-
});
|
|
290
|
+
import {
|
|
291
|
+
InstaVM,
|
|
292
|
+
AuthenticationError,
|
|
293
|
+
ExecutionError,
|
|
294
|
+
NetworkError,
|
|
295
|
+
RateLimitError,
|
|
296
|
+
SessionError,
|
|
297
|
+
} from 'instavm';
|
|
810
298
|
|
|
811
|
-
|
|
812
|
-
const thumbnail = await session.screenshot({
|
|
813
|
-
clip: { x: 0, y: 0, width: 400, height: 300 },
|
|
814
|
-
format: 'jpeg',
|
|
815
|
-
quality: 70
|
|
816
|
-
});
|
|
817
|
-
```
|
|
299
|
+
const client = new InstaVM('your_api_key');
|
|
818
300
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
}
|
|
836
|
-
} finally {
|
|
837
|
-
await client.dispose();
|
|
838
|
-
}
|
|
301
|
+
try {
|
|
302
|
+
await client.execute("raise Exception('boom')");
|
|
303
|
+
} catch (error) {
|
|
304
|
+
if (error instanceof AuthenticationError) {
|
|
305
|
+
console.error('Invalid API key');
|
|
306
|
+
} else if (error instanceof RateLimitError) {
|
|
307
|
+
console.error('Rate limited');
|
|
308
|
+
} else if (error instanceof SessionError) {
|
|
309
|
+
console.error('Session issue:', error.message);
|
|
310
|
+
} else if (error instanceof ExecutionError) {
|
|
311
|
+
console.error('Execution failed:', error.message);
|
|
312
|
+
} else if (error instanceof NetworkError) {
|
|
313
|
+
console.error('Network issue:', error.message);
|
|
314
|
+
} else {
|
|
315
|
+
throw error;
|
|
316
|
+
}
|
|
839
317
|
}
|
|
840
|
-
|
|
841
|
-
main().catch(console.error);
|
|
842
318
|
```
|
|
843
319
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
### Running Tests
|
|
320
|
+
<a id="development-testing"></a>
|
|
321
|
+
## Development & Testing
|
|
847
322
|
|
|
848
323
|
```bash
|
|
849
324
|
# Install dependencies
|
|
850
325
|
npm install
|
|
851
326
|
|
|
852
|
-
# Run unit tests
|
|
327
|
+
# Run unit tests
|
|
853
328
|
npm run test:unit
|
|
854
329
|
|
|
855
|
-
#
|
|
856
|
-
INSTAVM_API_KEY=your_api_key npm run test:integration
|
|
857
|
-
|
|
858
|
-
# Run all tests
|
|
330
|
+
# Optional: full test run
|
|
859
331
|
npm test
|
|
860
332
|
|
|
861
|
-
# Build
|
|
333
|
+
# Build package
|
|
862
334
|
npm run build
|
|
863
|
-
|
|
864
|
-
# Type checking
|
|
865
|
-
npm run type-check
|
|
866
335
|
```
|
|
867
336
|
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
### Contributing
|
|
871
|
-
|
|
872
|
-
This is an official SDK. For issues and feature requests, please use the GitHub repository.
|
|
873
|
-
|
|
874
|
-
## Requirements
|
|
875
|
-
|
|
876
|
-
- Node.js 16+
|
|
877
|
-
- TypeScript 5+ (for TypeScript projects)
|
|
878
|
-
|
|
879
|
-
## License
|
|
880
|
-
|
|
881
|
-
Proprietary. This SDK is provided for use with InstaVM services only.
|
|
882
|
-
|
|
883
|
-
All rights reserved. No redistribution or modification permitted.
|
|
884
|
-
|
|
885
|
-
---
|
|
886
|
-
|
|
887
|
-
## Changelog
|
|
888
|
-
|
|
889
|
-
### Version 0.4.0
|
|
890
|
-
|
|
891
|
-
- ✅ **NEW**: Local execution mode support - Run code execution against local containers
|
|
892
|
-
- ✅ **NEW**: Local browser automation - Navigate and extract content without sessions
|
|
893
|
-
- ✅ **NEW**: `UnsupportedOperationError` - Better error messages for cloud-only features
|
|
894
|
-
- ✅ Parity with Python SDK v0.4.0 local mode features
|
|
895
|
-
- ✅ Improved flexibility for on-premise deployments
|
|
896
|
-
|
|
897
|
-
### Version 0.3.0
|
|
898
|
-
|
|
899
|
-
- ✅ **NEW**: File download functionality - Download files from remote VM
|
|
900
|
-
- ✅ **NEW**: LLM-friendly content extraction - Extract clean, readable content with interactive element mapping
|
|
901
|
-
- ✅ Enhanced browser automation with content anchors for intelligent LLM agents
|
|
902
|
-
- ✅ Full API parity with Python SDK
|
|
903
|
-
|
|
904
|
-
### Version 0.2.1
|
|
905
|
-
|
|
906
|
-
- ✅ Bug fixes and improvements
|
|
337
|
+
<a id="docs-map-further-reading"></a>
|
|
338
|
+
## Docs Map (Further Reading)
|
|
907
339
|
|
|
908
|
-
|
|
340
|
+
- [JavaScript SDK Docs](https://instavm.io/docs/sdks/javascript)
|
|
341
|
+
- [VMs API](https://instavm.io/docs/api/vms/)
|
|
342
|
+
- [Snapshots API](https://instavm.io/docs/api/snapshots/)
|
|
343
|
+
- [Shares API](https://instavm.io/docs/api/shares/)
|
|
344
|
+
- [Computer Use API (REST API Reference)](https://instavm.io/docs/api#endpoint-categories)
|
|
345
|
+
- [Webhooks API (REST API Reference)](https://instavm.io/docs/api#endpoint-categories)
|
|
909
346
|
|
|
910
|
-
-
|
|
911
|
-
|
|
347
|
+
<a id="version-changelog"></a>
|
|
348
|
+
## Version / Changelog
|
|
912
349
|
|
|
913
|
-
|
|
350
|
+
Current package version: `0.11.0`.
|
|
914
351
|
|
|
915
|
-
|
|
916
|
-
-
|
|
917
|
-
-
|
|
918
|
-
-
|
|
919
|
-
- ✅ Session management and automatic cleanup
|
|
920
|
-
- ✅ File upload capabilities
|
|
921
|
-
- ✅ Async execution support
|
|
922
|
-
- ✅ Event-driven browser sessions
|
|
923
|
-
- ✅ Modern build system with multiple output formats
|
|
352
|
+
Highlights in this line:
|
|
353
|
+
- Manager-based infrastructure APIs (VMs, snapshots, shares, custom domains, computer use, API keys, audit, webhooks)
|
|
354
|
+
- Snapshot build args support for env vars and Git clone inputs
|
|
355
|
+
- Distinct VM list helpers for `/v1/vms` and `/v1/vms/`
|
|
924
356
|
|
|
925
|
-
|
|
357
|
+
For detailed release history, see [GitHub Releases](https://github.com/instavm/js/releases).
|