instavm 0.8.0 → 0.8.3
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 +64 -20
- package/dist/index.d.mts +33 -2
- package/dist/index.d.ts +33 -2
- package/dist/index.js +107 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +107 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -64,7 +64,7 @@ const client = new InstaVM('', {
|
|
|
64
64
|
|
|
65
65
|
// Execute code locally without session management
|
|
66
66
|
const result = await client.execute("print('Hello from local container!')");
|
|
67
|
-
console.log(result.
|
|
67
|
+
console.log(result.stdout);
|
|
68
68
|
|
|
69
69
|
// Browser automation in local mode (no session required)
|
|
70
70
|
const content = await client.browser.extractContent({
|
|
@@ -94,6 +94,9 @@ import { InstaVM } from 'instavm';
|
|
|
94
94
|
|
|
95
95
|
const client = new InstaVM('your_api_key');
|
|
96
96
|
|
|
97
|
+
// Create a session first (required for upload)
|
|
98
|
+
await client.createSession();
|
|
99
|
+
|
|
97
100
|
// Upload files to the execution environment
|
|
98
101
|
const files = [
|
|
99
102
|
{
|
|
@@ -110,7 +113,7 @@ console.log(result);
|
|
|
110
113
|
const execution = await client.execute('python /remote/path/script.py', {
|
|
111
114
|
language: 'bash'
|
|
112
115
|
});
|
|
113
|
-
console.log(execution.
|
|
116
|
+
console.log(execution.stdout);
|
|
114
117
|
```
|
|
115
118
|
|
|
116
119
|
### File Download
|
|
@@ -170,13 +173,18 @@ import { InstaVM } from 'instavm';
|
|
|
170
173
|
|
|
171
174
|
const client = new InstaVM('your_api_key');
|
|
172
175
|
|
|
173
|
-
// Execute command asynchronously (returns task
|
|
176
|
+
// Execute command asynchronously (returns task ID)
|
|
174
177
|
const result = await client.executeAsync("sleep 5 && echo 'Long task complete!'", {
|
|
175
178
|
language: 'bash'
|
|
176
179
|
});
|
|
177
|
-
|
|
178
|
-
console.log(`Task ${
|
|
179
|
-
|
|
180
|
+
const taskId = result.taskId;
|
|
181
|
+
console.log(`Task ${taskId} is running in background...`);
|
|
182
|
+
|
|
183
|
+
// Poll for task result
|
|
184
|
+
const taskResult = await client.getTaskResult(taskId, 2, 30);
|
|
185
|
+
console.log('Task complete!');
|
|
186
|
+
console.log(`Stdout: ${taskResult.stdout}`);
|
|
187
|
+
console.log(`Stderr: ${taskResult.stderr}`);
|
|
180
188
|
```
|
|
181
189
|
|
|
182
190
|
## Browser Automation
|
|
@@ -319,7 +327,7 @@ data = {"terms": search_terms, "timestamp": "2024-01-01"}
|
|
|
319
327
|
print(json.dumps(data))
|
|
320
328
|
`);
|
|
321
329
|
|
|
322
|
-
const searchData = JSON.parse(dataPrep.
|
|
330
|
+
const searchData = JSON.parse(dataPrep.stdout.trim());
|
|
323
331
|
|
|
324
332
|
// Use browser to search and collect results
|
|
325
333
|
const session = await client.browser.createSession();
|
|
@@ -359,7 +367,7 @@ top_words = sorted(word_counts.items(), key=lambda x: x[1], reverse=True)[:10]
|
|
|
359
367
|
print("Top words:", top_words)
|
|
360
368
|
`);
|
|
361
369
|
|
|
362
|
-
console.log(analysis.
|
|
370
|
+
console.log(analysis.stdout);
|
|
363
371
|
await client.dispose();
|
|
364
372
|
```
|
|
365
373
|
|
|
@@ -385,7 +393,7 @@ print(f"Std: {data['numbers'].std():.2f}")
|
|
|
385
393
|
print(f"Categories: {data['categories'].value_counts().to_dict()}")
|
|
386
394
|
`);
|
|
387
395
|
|
|
388
|
-
console.log(result.
|
|
396
|
+
console.log(result.stdout);
|
|
389
397
|
```
|
|
390
398
|
|
|
391
399
|
### Bash Commands
|
|
@@ -404,7 +412,7 @@ echo "Memory Info:"
|
|
|
404
412
|
free -h
|
|
405
413
|
`, { language: 'bash' });
|
|
406
414
|
|
|
407
|
-
console.log(sysInfo.
|
|
415
|
+
console.log(sysInfo.stdout);
|
|
408
416
|
```
|
|
409
417
|
|
|
410
418
|
### Session Persistence
|
|
@@ -415,7 +423,19 @@ await client.execute('data = [1, 2, 3, 4, 5]');
|
|
|
415
423
|
await client.execute('total = sum(data)');
|
|
416
424
|
|
|
417
425
|
const result = await client.execute('print(f"Total: {total}, Average: {total/len(data)}")');
|
|
418
|
-
console.log(result.
|
|
426
|
+
console.log(result.stdout); // Output: Total: 15, Average: 3.0
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### Session Status Check
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
// Check if current session is still active
|
|
433
|
+
const isActive = await client.isSessionActive();
|
|
434
|
+
console.log(`Session active: ${isActive}`);
|
|
435
|
+
|
|
436
|
+
// Check specific session
|
|
437
|
+
const isOtherActive = await client.isSessionActive('session-id-123');
|
|
438
|
+
console.log(`Other session active: ${isOtherActive}`);
|
|
419
439
|
```
|
|
420
440
|
|
|
421
441
|
## Advanced Features
|
|
@@ -583,11 +603,12 @@ const client = new InstaVM('your_api_key', {
|
|
|
583
603
|
```typescript
|
|
584
604
|
class InstaVM {
|
|
585
605
|
constructor(apiKey: string, options?: InstaVMOptions)
|
|
586
|
-
|
|
606
|
+
|
|
587
607
|
// Code execution
|
|
588
608
|
execute(command: string, options?: ExecuteOptions): Promise<ExecutionResult>
|
|
589
609
|
executeAsync(command: string, options?: ExecuteOptions): Promise<AsyncExecutionResult>
|
|
590
|
-
|
|
610
|
+
getTaskResult(taskId: string, pollInterval?: number, timeout?: number): Promise<TaskResult>
|
|
611
|
+
|
|
591
612
|
// File operations
|
|
592
613
|
upload(files: FileUpload[], options?: UploadOptions): Promise<UploadResult>
|
|
593
614
|
download(filename: string, options?: DownloadOptions): Promise<DownloadResult>
|
|
@@ -595,14 +616,15 @@ class InstaVM {
|
|
|
595
616
|
// Session management
|
|
596
617
|
createSession(): Promise<string>
|
|
597
618
|
closeSession(sessionId?: string): Promise<void>
|
|
619
|
+
isSessionActive(sessionId?: string): Promise<boolean>
|
|
598
620
|
getUsage(sessionId?: string): Promise<UsageStats>
|
|
599
|
-
|
|
621
|
+
|
|
600
622
|
// Browser automation
|
|
601
623
|
browser: BrowserManager
|
|
602
|
-
|
|
624
|
+
|
|
603
625
|
// Properties
|
|
604
626
|
readonly sessionId: string | null
|
|
605
|
-
|
|
627
|
+
|
|
606
628
|
// Cleanup
|
|
607
629
|
dispose(): Promise<void>
|
|
608
630
|
}
|
|
@@ -681,13 +703,24 @@ class BrowserSession extends EventEmitter {
|
|
|
681
703
|
|
|
682
704
|
```typescript
|
|
683
705
|
interface ExecutionResult {
|
|
684
|
-
|
|
706
|
+
stdout: string;
|
|
707
|
+
stderr: string;
|
|
685
708
|
success: boolean;
|
|
686
|
-
executionTime
|
|
709
|
+
executionTime?: number;
|
|
710
|
+
cpuTime?: number;
|
|
711
|
+
createdAt?: string;
|
|
687
712
|
sessionId?: string;
|
|
688
713
|
error?: string;
|
|
689
714
|
}
|
|
690
715
|
|
|
716
|
+
interface TaskResult {
|
|
717
|
+
stdout: string;
|
|
718
|
+
stderr: string;
|
|
719
|
+
executionTime?: number;
|
|
720
|
+
cpuTime?: number;
|
|
721
|
+
createdAt?: string;
|
|
722
|
+
}
|
|
723
|
+
|
|
691
724
|
interface NavigationResult {
|
|
692
725
|
success: boolean;
|
|
693
726
|
url: string;
|
|
@@ -734,7 +767,7 @@ async function withInstaVM(apiKey: string, callback: (client: InstaVM) => Promis
|
|
|
734
767
|
|
|
735
768
|
await withInstaVM('your_api_key', async (client) => {
|
|
736
769
|
const result = await client.execute('print("Hello, World!")');
|
|
737
|
-
console.log(result.
|
|
770
|
+
console.log(result.stdout);
|
|
738
771
|
});
|
|
739
772
|
```
|
|
740
773
|
|
|
@@ -828,7 +861,7 @@ async function main() {
|
|
|
828
861
|
|
|
829
862
|
try {
|
|
830
863
|
const result = await client.execute('print("Hello from CommonJS!")');
|
|
831
|
-
console.log(result.
|
|
864
|
+
console.log(result.stdout);
|
|
832
865
|
} catch (error) {
|
|
833
866
|
if (error instanceof AuthenticationError) {
|
|
834
867
|
console.error('Authentication failed');
|
|
@@ -886,6 +919,17 @@ All rights reserved. No redistribution or modification permitted.
|
|
|
886
919
|
|
|
887
920
|
## Changelog
|
|
888
921
|
|
|
922
|
+
### Version 0.8.3
|
|
923
|
+
|
|
924
|
+
- ✅ **NEW**: `getTaskResult()` method - Poll for async task completion with configurable intervals
|
|
925
|
+
- ✅ **NEW**: `isSessionActive()` method - Check if session is still active by querying VM status
|
|
926
|
+
- ✅ **IMPROVED**: Execution result format - Now returns `stdout` and `stderr` separately (matching Python SDK)
|
|
927
|
+
- ✅ **IMPROVED**: Enhanced execution results - Added `cpuTime`, `executionTime`, and `createdAt` fields
|
|
928
|
+
- ✅ **IMPROVED**: Better error messages - Rate limit errors now show `detail` field from API response
|
|
929
|
+
- ✅ **FIXED**: Session status check - Now uses `/v1/sessions/status/` endpoint for accurate VM status
|
|
930
|
+
- ✅ **UPDATED**: closeSession behavior - Sessions auto-expire on server, no longer makes DELETE API call
|
|
931
|
+
- ✅ Full parity with Python SDK v0.8.3
|
|
932
|
+
|
|
889
933
|
### Version 0.4.0
|
|
890
934
|
|
|
891
935
|
- ✅ **NEW**: Local execution mode support - Run code execution against local containers
|
package/dist/index.d.mts
CHANGED
|
@@ -53,6 +53,10 @@ declare class HTTPClient {
|
|
|
53
53
|
* POST request with form data (for file uploads)
|
|
54
54
|
*/
|
|
55
55
|
postFormData<T = any>(url: string, formData: FormData, headers?: Record<string, string>): Promise<T>;
|
|
56
|
+
/**
|
|
57
|
+
* POST request with URL-encoded form data (like Python requests data= parameter)
|
|
58
|
+
*/
|
|
59
|
+
postFormUrlEncoded<T = any>(url: string, data: any, headers?: Record<string, string>): Promise<T>;
|
|
56
60
|
/**
|
|
57
61
|
* GET request
|
|
58
62
|
*/
|
|
@@ -312,9 +316,12 @@ interface ExecuteOptions {
|
|
|
312
316
|
sessionId?: string;
|
|
313
317
|
}
|
|
314
318
|
interface ExecutionResult {
|
|
315
|
-
|
|
319
|
+
stdout: string;
|
|
320
|
+
stderr: string;
|
|
316
321
|
success: boolean;
|
|
317
|
-
executionTime
|
|
322
|
+
executionTime?: number;
|
|
323
|
+
cpuTime?: number;
|
|
324
|
+
createdAt?: string;
|
|
318
325
|
sessionId?: string;
|
|
319
326
|
error?: string;
|
|
320
327
|
}
|
|
@@ -327,6 +334,13 @@ interface AsyncExecutionResult {
|
|
|
327
334
|
sessionId?: string;
|
|
328
335
|
error?: string;
|
|
329
336
|
}
|
|
337
|
+
interface TaskResult {
|
|
338
|
+
stdout: string;
|
|
339
|
+
stderr: string;
|
|
340
|
+
executionTime?: number;
|
|
341
|
+
cpuTime?: number;
|
|
342
|
+
createdAt?: string;
|
|
343
|
+
}
|
|
330
344
|
interface FileUpload {
|
|
331
345
|
name: string;
|
|
332
346
|
content: Buffer | string;
|
|
@@ -397,6 +411,16 @@ declare class InstaVM {
|
|
|
397
411
|
* Execute code asynchronously
|
|
398
412
|
*/
|
|
399
413
|
executeAsync(command: string, options?: ExecuteOptions): Promise<AsyncExecutionResult>;
|
|
414
|
+
/**
|
|
415
|
+
* Poll for async task result
|
|
416
|
+
*
|
|
417
|
+
* @param taskId - The task ID from executeAsync
|
|
418
|
+
* @param pollInterval - Seconds between polls (default: 1)
|
|
419
|
+
* @param timeout - Maximum seconds to wait (default: 60)
|
|
420
|
+
* @returns Task result with stdout, stderr, execution time, etc.
|
|
421
|
+
* @throws Error if task doesn't complete within timeout
|
|
422
|
+
*/
|
|
423
|
+
getTaskResult(taskId: string, pollInterval?: number, timeout?: number): Promise<TaskResult>;
|
|
400
424
|
/**
|
|
401
425
|
* Upload files to the execution environment
|
|
402
426
|
*/
|
|
@@ -407,8 +431,15 @@ declare class InstaVM {
|
|
|
407
431
|
createSession(): Promise<string>;
|
|
408
432
|
/**
|
|
409
433
|
* Close a session
|
|
434
|
+
* Note: Sessions auto-expire on the server side. This just clears local state.
|
|
410
435
|
*/
|
|
411
436
|
closeSession(sessionId?: string): Promise<void>;
|
|
437
|
+
/**
|
|
438
|
+
* Check if current session is still active by checking VM status
|
|
439
|
+
*
|
|
440
|
+
* @returns true if session is active, false otherwise
|
|
441
|
+
*/
|
|
442
|
+
isSessionActive(sessionId?: string): Promise<boolean>;
|
|
412
443
|
/**
|
|
413
444
|
* Get usage statistics for a session
|
|
414
445
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -53,6 +53,10 @@ declare class HTTPClient {
|
|
|
53
53
|
* POST request with form data (for file uploads)
|
|
54
54
|
*/
|
|
55
55
|
postFormData<T = any>(url: string, formData: FormData, headers?: Record<string, string>): Promise<T>;
|
|
56
|
+
/**
|
|
57
|
+
* POST request with URL-encoded form data (like Python requests data= parameter)
|
|
58
|
+
*/
|
|
59
|
+
postFormUrlEncoded<T = any>(url: string, data: any, headers?: Record<string, string>): Promise<T>;
|
|
56
60
|
/**
|
|
57
61
|
* GET request
|
|
58
62
|
*/
|
|
@@ -312,9 +316,12 @@ interface ExecuteOptions {
|
|
|
312
316
|
sessionId?: string;
|
|
313
317
|
}
|
|
314
318
|
interface ExecutionResult {
|
|
315
|
-
|
|
319
|
+
stdout: string;
|
|
320
|
+
stderr: string;
|
|
316
321
|
success: boolean;
|
|
317
|
-
executionTime
|
|
322
|
+
executionTime?: number;
|
|
323
|
+
cpuTime?: number;
|
|
324
|
+
createdAt?: string;
|
|
318
325
|
sessionId?: string;
|
|
319
326
|
error?: string;
|
|
320
327
|
}
|
|
@@ -327,6 +334,13 @@ interface AsyncExecutionResult {
|
|
|
327
334
|
sessionId?: string;
|
|
328
335
|
error?: string;
|
|
329
336
|
}
|
|
337
|
+
interface TaskResult {
|
|
338
|
+
stdout: string;
|
|
339
|
+
stderr: string;
|
|
340
|
+
executionTime?: number;
|
|
341
|
+
cpuTime?: number;
|
|
342
|
+
createdAt?: string;
|
|
343
|
+
}
|
|
330
344
|
interface FileUpload {
|
|
331
345
|
name: string;
|
|
332
346
|
content: Buffer | string;
|
|
@@ -397,6 +411,16 @@ declare class InstaVM {
|
|
|
397
411
|
* Execute code asynchronously
|
|
398
412
|
*/
|
|
399
413
|
executeAsync(command: string, options?: ExecuteOptions): Promise<AsyncExecutionResult>;
|
|
414
|
+
/**
|
|
415
|
+
* Poll for async task result
|
|
416
|
+
*
|
|
417
|
+
* @param taskId - The task ID from executeAsync
|
|
418
|
+
* @param pollInterval - Seconds between polls (default: 1)
|
|
419
|
+
* @param timeout - Maximum seconds to wait (default: 60)
|
|
420
|
+
* @returns Task result with stdout, stderr, execution time, etc.
|
|
421
|
+
* @throws Error if task doesn't complete within timeout
|
|
422
|
+
*/
|
|
423
|
+
getTaskResult(taskId: string, pollInterval?: number, timeout?: number): Promise<TaskResult>;
|
|
400
424
|
/**
|
|
401
425
|
* Upload files to the execution environment
|
|
402
426
|
*/
|
|
@@ -407,8 +431,15 @@ declare class InstaVM {
|
|
|
407
431
|
createSession(): Promise<string>;
|
|
408
432
|
/**
|
|
409
433
|
* Close a session
|
|
434
|
+
* Note: Sessions auto-expire on the server side. This just clears local state.
|
|
410
435
|
*/
|
|
411
436
|
closeSession(sessionId?: string): Promise<void>;
|
|
437
|
+
/**
|
|
438
|
+
* Check if current session is still active by checking VM status
|
|
439
|
+
*
|
|
440
|
+
* @returns true if session is active, false otherwise
|
|
441
|
+
*/
|
|
442
|
+
isSessionActive(sessionId?: string): Promise<boolean>;
|
|
412
443
|
/**
|
|
413
444
|
* Get usage statistics for a session
|
|
414
445
|
*/
|
package/dist/index.js
CHANGED
|
@@ -211,7 +211,7 @@ var HTTPClient = class {
|
|
|
211
211
|
const axiosError = error;
|
|
212
212
|
const status = axiosError.response?.status;
|
|
213
213
|
const data = axiosError.response?.data;
|
|
214
|
-
const message = data?.message || data?.error || axiosError.message;
|
|
214
|
+
const message = data?.message || data?.error || data?.detail || axiosError.message;
|
|
215
215
|
switch (status) {
|
|
216
216
|
case 401:
|
|
217
217
|
throw new AuthenticationError(message, {
|
|
@@ -223,14 +223,16 @@ var HTTPClient = class {
|
|
|
223
223
|
statusCode: status,
|
|
224
224
|
response: data
|
|
225
225
|
});
|
|
226
|
-
case 429:
|
|
226
|
+
case 429: {
|
|
227
227
|
const retryAfter = parseInt(
|
|
228
228
|
axiosError.response?.headers["retry-after"] || "60"
|
|
229
229
|
);
|
|
230
|
-
|
|
230
|
+
const rateLimitMessage = data?.detail || message;
|
|
231
|
+
throw new RateLimitError(rateLimitMessage, retryAfter, {
|
|
231
232
|
statusCode: status,
|
|
232
233
|
response: data
|
|
233
234
|
});
|
|
235
|
+
}
|
|
234
236
|
case 500:
|
|
235
237
|
case 502:
|
|
236
238
|
case 503:
|
|
@@ -308,6 +310,7 @@ var HTTPClient = class {
|
|
|
308
310
|
*/
|
|
309
311
|
async postFormData(url, formData, headers) {
|
|
310
312
|
const requestHeaders = {
|
|
313
|
+
"X-API-Key": this.config.apiKey,
|
|
311
314
|
...formData.getHeaders(),
|
|
312
315
|
...headers
|
|
313
316
|
};
|
|
@@ -318,6 +321,26 @@ var HTTPClient = class {
|
|
|
318
321
|
headers: requestHeaders
|
|
319
322
|
});
|
|
320
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* POST request with URL-encoded form data (like Python requests data= parameter)
|
|
326
|
+
*/
|
|
327
|
+
async postFormUrlEncoded(url, data, headers) {
|
|
328
|
+
const params = new URLSearchParams();
|
|
329
|
+
for (const [key, value] of Object.entries(data)) {
|
|
330
|
+
params.append(key, String(value));
|
|
331
|
+
}
|
|
332
|
+
const requestHeaders = {
|
|
333
|
+
"X-API-Key": this.config.apiKey,
|
|
334
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
335
|
+
...headers
|
|
336
|
+
};
|
|
337
|
+
return this.request({
|
|
338
|
+
method: "POST",
|
|
339
|
+
url,
|
|
340
|
+
data: params.toString(),
|
|
341
|
+
headers: requestHeaders
|
|
342
|
+
});
|
|
343
|
+
}
|
|
321
344
|
/**
|
|
322
345
|
* GET request
|
|
323
346
|
*/
|
|
@@ -970,9 +993,12 @@ var InstaVM = class {
|
|
|
970
993
|
this._sessionId = response.session_id;
|
|
971
994
|
}
|
|
972
995
|
return {
|
|
973
|
-
|
|
996
|
+
stdout: response.stdout || "",
|
|
997
|
+
stderr: response.stderr || "",
|
|
974
998
|
success: response.success !== false,
|
|
975
|
-
executionTime: response.execution_time
|
|
999
|
+
executionTime: response.execution_time,
|
|
1000
|
+
cpuTime: response.cpu_time,
|
|
1001
|
+
createdAt: response.created_at,
|
|
976
1002
|
sessionId: response.session_id,
|
|
977
1003
|
error: response.error
|
|
978
1004
|
};
|
|
@@ -1028,11 +1054,58 @@ var InstaVM = class {
|
|
|
1028
1054
|
);
|
|
1029
1055
|
}
|
|
1030
1056
|
}
|
|
1057
|
+
/**
|
|
1058
|
+
* Poll for async task result
|
|
1059
|
+
*
|
|
1060
|
+
* @param taskId - The task ID from executeAsync
|
|
1061
|
+
* @param pollInterval - Seconds between polls (default: 1)
|
|
1062
|
+
* @param timeout - Maximum seconds to wait (default: 60)
|
|
1063
|
+
* @returns Task result with stdout, stderr, execution time, etc.
|
|
1064
|
+
* @throws Error if task doesn't complete within timeout
|
|
1065
|
+
*/
|
|
1066
|
+
async getTaskResult(taskId, pollInterval = 1, timeout = 60) {
|
|
1067
|
+
this.ensureNotLocal("Async task result retrieval");
|
|
1068
|
+
const startTime = Date.now();
|
|
1069
|
+
while (Date.now() - startTime < timeout * 1e3) {
|
|
1070
|
+
try {
|
|
1071
|
+
const response = await this.httpClient.get(
|
|
1072
|
+
`/v1/executions/${taskId}`,
|
|
1073
|
+
void 0,
|
|
1074
|
+
{ "X-API-Key": this.httpClient.apiKey }
|
|
1075
|
+
);
|
|
1076
|
+
if (response.is_complete) {
|
|
1077
|
+
return {
|
|
1078
|
+
stdout: response.serialized_stdout || "",
|
|
1079
|
+
stderr: response.serialized_stderr || "",
|
|
1080
|
+
cpuTime: response.cpu_time,
|
|
1081
|
+
executionTime: response.execution_time,
|
|
1082
|
+
createdAt: response.created_at
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval * 1e3));
|
|
1086
|
+
} catch (error) {
|
|
1087
|
+
if (error instanceof AuthenticationError || error instanceof RateLimitError || error instanceof NetworkError) {
|
|
1088
|
+
throw error;
|
|
1089
|
+
}
|
|
1090
|
+
if (Date.now() - startTime >= timeout * 1e3) {
|
|
1091
|
+
throw new ExecutionError(
|
|
1092
|
+
`Failed to get task result: ${error instanceof Error ? error.message : String(error)}`
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval * 1e3));
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
throw new ExecutionError(`Task ${taskId} timed out after ${timeout}s`);
|
|
1099
|
+
}
|
|
1031
1100
|
/**
|
|
1032
1101
|
* Upload files to the execution environment
|
|
1033
1102
|
*/
|
|
1034
1103
|
async upload(files, options = {}) {
|
|
1035
1104
|
this.ensureNotLocal("File upload");
|
|
1105
|
+
const sessionId = options.sessionId || this._sessionId;
|
|
1106
|
+
if (!sessionId) {
|
|
1107
|
+
throw new SessionError("Session ID not set. Please create a session first using createSession().");
|
|
1108
|
+
}
|
|
1036
1109
|
const formData = new import_form_data.default();
|
|
1037
1110
|
for (const file of files) {
|
|
1038
1111
|
if (Buffer.isBuffer(file.content)) {
|
|
@@ -1044,9 +1117,7 @@ var InstaVM = class {
|
|
|
1044
1117
|
formData.append("paths", file.path);
|
|
1045
1118
|
}
|
|
1046
1119
|
}
|
|
1047
|
-
|
|
1048
|
-
formData.append("session_id", options.sessionId || this._sessionId);
|
|
1049
|
-
}
|
|
1120
|
+
formData.append("session_id", sessionId);
|
|
1050
1121
|
if (options.remotePath) {
|
|
1051
1122
|
formData.append("remote_path", options.remotePath);
|
|
1052
1123
|
}
|
|
@@ -1096,20 +1167,39 @@ var InstaVM = class {
|
|
|
1096
1167
|
}
|
|
1097
1168
|
/**
|
|
1098
1169
|
* Close a session
|
|
1170
|
+
* Note: Sessions auto-expire on the server side. This just clears local state.
|
|
1099
1171
|
*/
|
|
1100
1172
|
async closeSession(sessionId) {
|
|
1101
1173
|
const targetSessionId = sessionId || this._sessionId;
|
|
1102
1174
|
if (!targetSessionId) {
|
|
1103
1175
|
return;
|
|
1104
1176
|
}
|
|
1177
|
+
if (targetSessionId === this._sessionId) {
|
|
1178
|
+
this._sessionId = null;
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* Check if current session is still active by checking VM status
|
|
1183
|
+
*
|
|
1184
|
+
* @returns true if session is active, false otherwise
|
|
1185
|
+
*/
|
|
1186
|
+
async isSessionActive(sessionId) {
|
|
1187
|
+
const targetSessionId = sessionId || this._sessionId;
|
|
1188
|
+
if (!targetSessionId) {
|
|
1189
|
+
return false;
|
|
1190
|
+
}
|
|
1105
1191
|
try {
|
|
1106
|
-
await this.httpClient.
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1192
|
+
const response = await this.httpClient.get(
|
|
1193
|
+
`/v1/sessions/status/${targetSessionId}`,
|
|
1194
|
+
void 0,
|
|
1195
|
+
{ "X-API-Key": this.httpClient.apiKey }
|
|
1196
|
+
);
|
|
1197
|
+
return response.vm_status === "active";
|
|
1110
1198
|
} catch (error) {
|
|
1111
|
-
|
|
1112
|
-
|
|
1199
|
+
if (error instanceof SessionError || error instanceof AuthenticationError || error instanceof NetworkError) {
|
|
1200
|
+
return false;
|
|
1201
|
+
}
|
|
1202
|
+
return false;
|
|
1113
1203
|
}
|
|
1114
1204
|
}
|
|
1115
1205
|
/**
|
|
@@ -1149,11 +1239,12 @@ var InstaVM = class {
|
|
|
1149
1239
|
throw new SessionError("No active session to download from");
|
|
1150
1240
|
}
|
|
1151
1241
|
try {
|
|
1152
|
-
const response = await this.httpClient.
|
|
1242
|
+
const response = await this.httpClient.postFormUrlEncoded("/download", {
|
|
1153
1243
|
filename,
|
|
1154
1244
|
session_id: targetSessionId
|
|
1155
1245
|
});
|
|
1156
|
-
const
|
|
1246
|
+
const encodedContent = response.content || "";
|
|
1247
|
+
const content = encodedContent ? Buffer.from(encodedContent, "base64") : Buffer.from(response);
|
|
1157
1248
|
return {
|
|
1158
1249
|
success: true,
|
|
1159
1250
|
filename,
|