instavm 0.3.0 → 0.8.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 CHANGED
@@ -21,7 +21,7 @@ npm install instavm
21
21
 
22
22
  ## Quick Start
23
23
 
24
- ### Code Execution
24
+ ### Code Execution (Cloud Mode)
25
25
 
26
26
  ```typescript
27
27
  import { InstaVM, ExecutionError, NetworkError } from 'instavm';
@@ -30,7 +30,7 @@ import { InstaVM, ExecutionError, NetworkError } from 'instavm';
30
30
  const client = new InstaVM('your_api_key');
31
31
 
32
32
  try {
33
- // Execute a command
33
+ // Execute a command
34
34
  const result = await client.execute("print(100**100)");
35
35
  console.log(result);
36
36
 
@@ -49,6 +49,44 @@ try {
49
49
  }
50
50
  ```
51
51
 
52
+ ### Local Execution Mode
53
+
54
+ Run code execution against a local container (e.g., [coderunner](https://github.com/instavm/coderunner)) instead of the cloud API:
55
+
56
+ ```typescript
57
+ import { InstaVM } from 'instavm';
58
+
59
+ // Create client in local mode (no API key required)
60
+ const client = new InstaVM('', {
61
+ local: true,
62
+ localURL: 'http://coderunner.local:8222' // Optional, defaults to this URL
63
+ });
64
+
65
+ // Execute code locally without session management
66
+ const result = await client.execute("print('Hello from local container!')");
67
+ console.log(result.output);
68
+
69
+ // Browser automation in local mode (no session required)
70
+ const content = await client.browser.extractContent({
71
+ url: 'https://example.com',
72
+ includeInteractive: true,
73
+ includeAnchors: true
74
+ });
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
+
52
90
  ### File Upload
53
91
 
54
92
  ```typescript
@@ -494,19 +532,20 @@ if (signupLink) {
494
532
 
495
533
  ```typescript
496
534
  import {
497
- InstaVMError, // Base error class
498
- AuthenticationError, // API key issues
499
- RateLimitError, // Rate limiting (has retryAfter property)
500
- QuotaExceededError, // Usage quota exceeded
501
- NetworkError, // Connection issues
502
- ExecutionError, // Code execution failures
503
- SessionError, // Session management issues
504
- BrowserError, // General browser errors
505
- BrowserSessionError, // Browser session issues
506
- BrowserInteractionError, // Browser interaction failures
507
- BrowserTimeoutError, // Browser operation timeouts
508
- BrowserNavigationError, // Navigation failures
509
- ElementNotFoundError // Element selection issues (has selector property)
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
510
549
  } from 'instavm';
511
550
 
512
551
  // Specific error handling
@@ -573,10 +612,12 @@ class InstaVM {
573
612
 
574
613
  ```typescript
575
614
  interface InstaVMOptions {
576
- baseURL?: string; // Default: 'https://api.instavm.io'
615
+ baseURL?: string; // Default: 'https://api.instavm.io' (ignored if local=true)
577
616
  timeout?: number; // Default: 300000 (5 minutes)
578
617
  maxRetries?: number; // Default: 3
579
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
580
621
  }
581
622
 
582
623
  interface ExecuteOptions {
@@ -845,6 +886,14 @@ All rights reserved. No redistribution or modification permitted.
845
886
 
846
887
  ## Changelog
847
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
+
848
897
  ### Version 0.3.0
849
898
 
850
899
  - ✅ **NEW**: File download functionality - Download files from remote VM
package/dist/index.d.mts CHANGED
@@ -44,11 +44,11 @@ declare class HTTPClient {
44
44
  /**
45
45
  * POST request with JSON body
46
46
  */
47
- post<T = any>(url: string, data?: any, headers?: Record<string, string>): Promise<T>;
47
+ post<T = any>(url: string, data?: any, headers?: Record<string, string>, timeout?: number): Promise<T>;
48
48
  /**
49
49
  * POST request for code execution (uses X-API-Key header like Python client)
50
50
  */
51
- postExecution<T = any>(url: string, data: any, headers?: Record<string, string>): Promise<T>;
51
+ postExecution<T = any>(url: string, data: any, headers?: Record<string, string>, timeout?: number): Promise<T>;
52
52
  /**
53
53
  * POST request with form data (for file uploads)
54
54
  */
@@ -151,6 +151,7 @@ interface ExtractOptions {
151
151
  maxResults?: number;
152
152
  }
153
153
  interface ExtractContentOptions {
154
+ url?: string;
154
155
  includeInteractive?: boolean;
155
156
  includeAnchors?: boolean;
156
157
  maxAnchors?: number;
@@ -265,7 +266,8 @@ declare class BrowserSession extends EventEmitter {
265
266
  declare class BrowserManager {
266
267
  private httpClient;
267
268
  private activeSessions;
268
- constructor(httpClient: HTTPClient);
269
+ private local;
270
+ constructor(httpClient: HTTPClient, local?: boolean);
269
271
  /**
270
272
  * Create a new browser session
271
273
  */
@@ -290,6 +292,14 @@ declare class BrowserManager {
290
292
  * Close all active sessions
291
293
  */
292
294
  closeAllSessions(): Promise<void>;
295
+ /**
296
+ * Navigate to a URL (local mode support - no session required)
297
+ */
298
+ navigate(url: string, options?: NavigateOptions): Promise<NavigationResult>;
299
+ /**
300
+ * Extract LLM-friendly content (local mode support - no session required)
301
+ */
302
+ extractContent(options?: ExtractContentOptions): Promise<ExtractedContent>;
293
303
  /**
294
304
  * Clean up resources
295
305
  */
@@ -350,9 +360,15 @@ interface DownloadResult {
350
360
 
351
361
  interface InstaVMOptions {
352
362
  baseURL?: string;
363
+ /**
364
+ * Timeout in milliseconds. Used for HTTP request timeout and sent to API as VM lifetime (in seconds).
365
+ * Default: 300000 (5 minutes)
366
+ */
353
367
  timeout?: number;
354
368
  maxRetries?: number;
355
369
  retryDelay?: number;
370
+ local?: boolean;
371
+ localURL?: string;
356
372
  }
357
373
  /**
358
374
  * Main InstaVM client class
@@ -361,9 +377,20 @@ declare class InstaVM {
361
377
  private httpClient;
362
378
  private _sessionId;
363
379
  readonly browser: BrowserManager;
380
+ readonly local: boolean;
381
+ private readonly timeout;
364
382
  constructor(apiKey: string, options?: InstaVMOptions);
383
+ /**
384
+ * Ensure operation is not called in local mode
385
+ */
386
+ private ensureNotLocal;
365
387
  /**
366
388
  * Execute code synchronously
389
+ *
390
+ * @param command - Command to execute
391
+ * @param options - Execution options
392
+ * @param options.timeout - Request timeout in milliseconds (used for HTTP request timeout and sent to API in seconds)
393
+ * @returns Execution result
367
394
  */
368
395
  execute(command: string, options?: ExecuteOptions): Promise<ExecutionResult>;
369
396
  /**
@@ -491,5 +518,11 @@ declare class ElementNotFoundError extends BrowserError {
491
518
  readonly selector?: string;
492
519
  constructor(message?: string, selector?: string, options?: any);
493
520
  }
521
+ /**
522
+ * Unsupported operation error (e.g., operations not available in local mode)
523
+ */
524
+ declare class UnsupportedOperationError extends InstaVMError {
525
+ constructor(message?: string, options?: any);
526
+ }
494
527
 
495
- export { type ApiResponse, type AsyncExecutionResult, AuthenticationError, BrowserError, BrowserInteractionError, BrowserManager, BrowserNavigationError, BrowserSession, BrowserSessionError, type BrowserSessionInfo, type BrowserSessionOptions, BrowserTimeoutError, type ClickOptions, type ContentAnchor, type DownloadOptions, type DownloadResult, ElementNotFoundError, type ExecuteOptions, ExecutionError, type ExecutionResult, type ExtractContentOptions, type ExtractOptions, type ExtractedContent, type ExtractedElement, type FileUpload, type FillOptions, type HttpClientConfig, InstaVM, InstaVMError, type InstaVMOptions, type InteractiveElement, type NavigateOptions, type NavigationResult, NetworkError, QuotaExceededError, RateLimitError, type RequestConfig, type RetryConfig, type ScreenshotOptions, type ScrollOptions, SessionError, type TypeOptions, type UploadOptions, type UploadResult, type UsageStats, type WaitCondition };
528
+ export { type ApiResponse, type AsyncExecutionResult, AuthenticationError, BrowserError, BrowserInteractionError, BrowserManager, BrowserNavigationError, BrowserSession, BrowserSessionError, type BrowserSessionInfo, type BrowserSessionOptions, BrowserTimeoutError, type ClickOptions, type ContentAnchor, type DownloadOptions, type DownloadResult, ElementNotFoundError, type ExecuteOptions, ExecutionError, type ExecutionResult, type ExtractContentOptions, type ExtractOptions, type ExtractedContent, type ExtractedElement, type FileUpload, type FillOptions, type HttpClientConfig, InstaVM, InstaVMError, type InstaVMOptions, type InteractiveElement, type NavigateOptions, type NavigationResult, NetworkError, QuotaExceededError, RateLimitError, type RequestConfig, type RetryConfig, type ScreenshotOptions, type ScrollOptions, SessionError, type TypeOptions, UnsupportedOperationError, type UploadOptions, type UploadResult, type UsageStats, type WaitCondition };
package/dist/index.d.ts CHANGED
@@ -44,11 +44,11 @@ declare class HTTPClient {
44
44
  /**
45
45
  * POST request with JSON body
46
46
  */
47
- post<T = any>(url: string, data?: any, headers?: Record<string, string>): Promise<T>;
47
+ post<T = any>(url: string, data?: any, headers?: Record<string, string>, timeout?: number): Promise<T>;
48
48
  /**
49
49
  * POST request for code execution (uses X-API-Key header like Python client)
50
50
  */
51
- postExecution<T = any>(url: string, data: any, headers?: Record<string, string>): Promise<T>;
51
+ postExecution<T = any>(url: string, data: any, headers?: Record<string, string>, timeout?: number): Promise<T>;
52
52
  /**
53
53
  * POST request with form data (for file uploads)
54
54
  */
@@ -151,6 +151,7 @@ interface ExtractOptions {
151
151
  maxResults?: number;
152
152
  }
153
153
  interface ExtractContentOptions {
154
+ url?: string;
154
155
  includeInteractive?: boolean;
155
156
  includeAnchors?: boolean;
156
157
  maxAnchors?: number;
@@ -265,7 +266,8 @@ declare class BrowserSession extends EventEmitter {
265
266
  declare class BrowserManager {
266
267
  private httpClient;
267
268
  private activeSessions;
268
- constructor(httpClient: HTTPClient);
269
+ private local;
270
+ constructor(httpClient: HTTPClient, local?: boolean);
269
271
  /**
270
272
  * Create a new browser session
271
273
  */
@@ -290,6 +292,14 @@ declare class BrowserManager {
290
292
  * Close all active sessions
291
293
  */
292
294
  closeAllSessions(): Promise<void>;
295
+ /**
296
+ * Navigate to a URL (local mode support - no session required)
297
+ */
298
+ navigate(url: string, options?: NavigateOptions): Promise<NavigationResult>;
299
+ /**
300
+ * Extract LLM-friendly content (local mode support - no session required)
301
+ */
302
+ extractContent(options?: ExtractContentOptions): Promise<ExtractedContent>;
293
303
  /**
294
304
  * Clean up resources
295
305
  */
@@ -350,9 +360,15 @@ interface DownloadResult {
350
360
 
351
361
  interface InstaVMOptions {
352
362
  baseURL?: string;
363
+ /**
364
+ * Timeout in milliseconds. Used for HTTP request timeout and sent to API as VM lifetime (in seconds).
365
+ * Default: 300000 (5 minutes)
366
+ */
353
367
  timeout?: number;
354
368
  maxRetries?: number;
355
369
  retryDelay?: number;
370
+ local?: boolean;
371
+ localURL?: string;
356
372
  }
357
373
  /**
358
374
  * Main InstaVM client class
@@ -361,9 +377,20 @@ declare class InstaVM {
361
377
  private httpClient;
362
378
  private _sessionId;
363
379
  readonly browser: BrowserManager;
380
+ readonly local: boolean;
381
+ private readonly timeout;
364
382
  constructor(apiKey: string, options?: InstaVMOptions);
383
+ /**
384
+ * Ensure operation is not called in local mode
385
+ */
386
+ private ensureNotLocal;
365
387
  /**
366
388
  * Execute code synchronously
389
+ *
390
+ * @param command - Command to execute
391
+ * @param options - Execution options
392
+ * @param options.timeout - Request timeout in milliseconds (used for HTTP request timeout and sent to API in seconds)
393
+ * @returns Execution result
367
394
  */
368
395
  execute(command: string, options?: ExecuteOptions): Promise<ExecutionResult>;
369
396
  /**
@@ -491,5 +518,11 @@ declare class ElementNotFoundError extends BrowserError {
491
518
  readonly selector?: string;
492
519
  constructor(message?: string, selector?: string, options?: any);
493
520
  }
521
+ /**
522
+ * Unsupported operation error (e.g., operations not available in local mode)
523
+ */
524
+ declare class UnsupportedOperationError extends InstaVMError {
525
+ constructor(message?: string, options?: any);
526
+ }
494
527
 
495
- export { type ApiResponse, type AsyncExecutionResult, AuthenticationError, BrowserError, BrowserInteractionError, BrowserManager, BrowserNavigationError, BrowserSession, BrowserSessionError, type BrowserSessionInfo, type BrowserSessionOptions, BrowserTimeoutError, type ClickOptions, type ContentAnchor, type DownloadOptions, type DownloadResult, ElementNotFoundError, type ExecuteOptions, ExecutionError, type ExecutionResult, type ExtractContentOptions, type ExtractOptions, type ExtractedContent, type ExtractedElement, type FileUpload, type FillOptions, type HttpClientConfig, InstaVM, InstaVMError, type InstaVMOptions, type InteractiveElement, type NavigateOptions, type NavigationResult, NetworkError, QuotaExceededError, RateLimitError, type RequestConfig, type RetryConfig, type ScreenshotOptions, type ScrollOptions, SessionError, type TypeOptions, type UploadOptions, type UploadResult, type UsageStats, type WaitCondition };
528
+ export { type ApiResponse, type AsyncExecutionResult, AuthenticationError, BrowserError, BrowserInteractionError, BrowserManager, BrowserNavigationError, BrowserSession, BrowserSessionError, type BrowserSessionInfo, type BrowserSessionOptions, BrowserTimeoutError, type ClickOptions, type ContentAnchor, type DownloadOptions, type DownloadResult, ElementNotFoundError, type ExecuteOptions, ExecutionError, type ExecutionResult, type ExtractContentOptions, type ExtractOptions, type ExtractedContent, type ExtractedElement, type FileUpload, type FillOptions, type HttpClientConfig, InstaVM, InstaVMError, type InstaVMOptions, type InteractiveElement, type NavigateOptions, type NavigationResult, NetworkError, QuotaExceededError, RateLimitError, type RequestConfig, type RetryConfig, type ScreenshotOptions, type ScrollOptions, SessionError, type TypeOptions, UnsupportedOperationError, type UploadOptions, type UploadResult, type UsageStats, type WaitCondition };
package/dist/index.js CHANGED
@@ -46,7 +46,8 @@ __export(index_exports, {
46
46
  NetworkError: () => NetworkError,
47
47
  QuotaExceededError: () => QuotaExceededError,
48
48
  RateLimitError: () => RateLimitError,
49
- SessionError: () => SessionError
49
+ SessionError: () => SessionError,
50
+ UnsupportedOperationError: () => UnsupportedOperationError
50
51
  });
51
52
  module.exports = __toCommonJS(index_exports);
52
53
 
@@ -131,6 +132,11 @@ var ElementNotFoundError = class extends BrowserError {
131
132
  this.selector = selector;
132
133
  }
133
134
  };
135
+ var UnsupportedOperationError = class extends InstaVMError {
136
+ constructor(message = "Operation not supported", options) {
137
+ super(message, options);
138
+ }
139
+ };
134
140
 
135
141
  // src/utils/retry.ts
136
142
  function defaultRetryCondition(error) {
@@ -272,18 +278,19 @@ var HTTPClient = class {
272
278
  /**
273
279
  * POST request with JSON body
274
280
  */
275
- async post(url, data, headers) {
281
+ async post(url, data, headers, timeout) {
276
282
  return this.request({
277
283
  method: "POST",
278
284
  url,
279
285
  data,
280
- headers
286
+ headers,
287
+ timeout
281
288
  });
282
289
  }
283
290
  /**
284
291
  * POST request for code execution (uses X-API-Key header like Python client)
285
292
  */
286
- async postExecution(url, data, headers) {
293
+ async postExecution(url, data, headers, timeout) {
287
294
  const requestHeaders = {
288
295
  "X-API-Key": this.config.apiKey,
289
296
  ...headers
@@ -292,7 +299,8 @@ var HTTPClient = class {
292
299
  method: "POST",
293
300
  url,
294
301
  data,
295
- headers: requestHeaders
302
+ headers: requestHeaders,
303
+ timeout
296
304
  });
297
305
  }
298
306
  /**
@@ -706,14 +714,20 @@ var BrowserSession = class extends import_eventemitter3.EventEmitter {
706
714
 
707
715
  // src/client/BrowserManager.ts
708
716
  var BrowserManager = class {
709
- constructor(httpClient) {
717
+ constructor(httpClient, local = false) {
710
718
  this.activeSessions = /* @__PURE__ */ new Map();
711
719
  this.httpClient = httpClient;
720
+ this.local = local;
712
721
  }
713
722
  /**
714
723
  * Create a new browser session
715
724
  */
716
725
  async createSession(options = {}) {
726
+ if (this.local) {
727
+ throw new UnsupportedOperationError(
728
+ "Browser session management is not supported in local mode. Use navigate() or extractContent() with URL directly."
729
+ );
730
+ }
717
731
  const requestData = {
718
732
  viewport_width: options.viewportWidth || 1920,
719
733
  viewport_height: options.viewportHeight || 1080,
@@ -812,6 +826,77 @@ var BrowserManager = class {
812
826
  );
813
827
  this.activeSessions.clear();
814
828
  }
829
+ /**
830
+ * Navigate to a URL (local mode support - no session required)
831
+ */
832
+ async navigate(url, options = {}) {
833
+ if (!this.local) {
834
+ throw new UnsupportedOperationError(
835
+ "navigate() without session is only supported in local mode. In cloud mode, create a session first."
836
+ );
837
+ }
838
+ const requestData = {
839
+ url,
840
+ wait_timeout: options.waitTimeout || 3e4
841
+ };
842
+ try {
843
+ const response = await this.httpClient.post(
844
+ "/v1/browser/interactions/navigate",
845
+ requestData
846
+ );
847
+ return {
848
+ success: response.success !== false,
849
+ url: response.url || url,
850
+ title: response.title,
851
+ status: response.status
852
+ };
853
+ } catch (error) {
854
+ const errorMessage = error instanceof Error ? error.message : String(error);
855
+ throw new BrowserNavigationError(
856
+ `Navigation failed: ${errorMessage}`,
857
+ { cause: error }
858
+ );
859
+ }
860
+ }
861
+ /**
862
+ * Extract LLM-friendly content (local mode support - no session required)
863
+ */
864
+ async extractContent(options = {}) {
865
+ if (!this.local) {
866
+ throw new UnsupportedOperationError(
867
+ "extractContent() without session is only supported in local mode. In cloud mode, create a session first."
868
+ );
869
+ }
870
+ if (!options.url) {
871
+ throw new BrowserInteractionError("url is required in local mode");
872
+ }
873
+ const requestData = {
874
+ url: options.url,
875
+ include_interactive: options.includeInteractive !== false,
876
+ include_anchors: options.includeAnchors !== false,
877
+ max_anchors: options.maxAnchors ?? 50
878
+ };
879
+ try {
880
+ const response = await this.httpClient.post(
881
+ "/v1/browser/interactions/content",
882
+ requestData
883
+ );
884
+ return {
885
+ readableContent: {
886
+ ...response.readable_content || {},
887
+ content: response.readable_content?.content || ""
888
+ },
889
+ interactiveElements: response.interactive_elements,
890
+ contentAnchors: response.content_anchors
891
+ };
892
+ } catch (error) {
893
+ const errorMessage = error instanceof Error ? error.message : String(error);
894
+ throw new BrowserInteractionError(
895
+ `Content extraction failed: ${errorMessage}`,
896
+ { cause: error }
897
+ );
898
+ }
899
+ }
815
900
  /**
816
901
  * Clean up resources
817
902
  */
@@ -825,38 +910,61 @@ var import_form_data = __toESM(require("form-data"));
825
910
  var InstaVM = class {
826
911
  constructor(apiKey, options = {}) {
827
912
  this._sessionId = null;
828
- if (!apiKey) {
829
- throw new Error("API key is required");
913
+ this.local = options.local || false;
914
+ this.timeout = options.timeout || 3e5;
915
+ if (!this.local && !apiKey) {
916
+ throw new AuthenticationError("API key is required for cloud mode");
830
917
  }
831
918
  const config = {
832
- baseURL: options.baseURL || "https://api.instavm.io",
833
- timeout: options.timeout || 3e5,
834
- // 5 minutes
919
+ baseURL: this.local ? options.localURL || "http://coderunner.local:8222" : options.baseURL || "https://api.instavm.io",
920
+ timeout: this.timeout,
835
921
  maxRetries: options.maxRetries || 3,
836
922
  retryDelay: options.retryDelay || 1e3,
837
- apiKey
923
+ apiKey: apiKey || ""
838
924
  };
839
925
  this.httpClient = new HTTPClient(config);
840
- this.browser = new BrowserManager(this.httpClient);
926
+ this.browser = new BrowserManager(this.httpClient, this.local);
927
+ }
928
+ /**
929
+ * Ensure operation is not called in local mode
930
+ */
931
+ ensureNotLocal(operationName) {
932
+ if (this.local) {
933
+ throw new UnsupportedOperationError(
934
+ `${operationName} is not supported in local mode. This operation is only available when using the cloud API.`
935
+ );
936
+ }
841
937
  }
842
938
  /**
843
939
  * Execute code synchronously
940
+ *
941
+ * @param command - Command to execute
942
+ * @param options - Execution options
943
+ * @param options.timeout - Request timeout in milliseconds (used for HTTP request timeout and sent to API in seconds)
944
+ * @returns Execution result
844
945
  */
845
946
  async execute(command, options = {}) {
846
947
  let sessionId = options.sessionId || this._sessionId;
847
- if (!sessionId) {
948
+ if (!this.local && !sessionId) {
848
949
  sessionId = await this.createSession();
849
950
  }
850
951
  const requestData = {
851
952
  command,
852
- language: options.language || "python",
853
- timeout: options.timeout || 15,
854
- session_id: sessionId
953
+ language: options.language || "python"
855
954
  };
955
+ if (options.timeout !== void 0) {
956
+ requestData.timeout = Math.floor(options.timeout / 1e3);
957
+ }
958
+ if (!this.local && sessionId) {
959
+ requestData.session_id = sessionId;
960
+ }
961
+ const requestTimeout = options.timeout !== void 0 ? options.timeout : this.timeout;
856
962
  try {
857
963
  const response = await this.httpClient.postExecution(
858
964
  "/execute",
859
- requestData
965
+ requestData,
966
+ void 0,
967
+ requestTimeout
860
968
  );
861
969
  if (response.session_id) {
862
970
  this._sessionId = response.session_id;
@@ -882,6 +990,7 @@ var InstaVM = class {
882
990
  * Execute code asynchronously
883
991
  */
884
992
  async executeAsync(command, options = {}) {
993
+ this.ensureNotLocal("Async execution");
885
994
  let sessionId = options.sessionId || this._sessionId;
886
995
  if (!sessionId) {
887
996
  sessionId = await this.createSession();
@@ -923,6 +1032,7 @@ var InstaVM = class {
923
1032
  * Upload files to the execution environment
924
1033
  */
925
1034
  async upload(files, options = {}) {
1035
+ this.ensureNotLocal("File upload");
926
1036
  const formData = new import_form_data.default();
927
1037
  for (const file of files) {
928
1038
  if (Buffer.isBuffer(file.content)) {
@@ -965,9 +1075,11 @@ var InstaVM = class {
965
1075
  * Create a new execution session
966
1076
  */
967
1077
  async createSession() {
1078
+ this.ensureNotLocal("Session management");
968
1079
  try {
969
1080
  const response = await this.httpClient.post("/v1/sessions/session", {
970
- api_key: this.httpClient.apiKey
1081
+ api_key: this.httpClient.apiKey,
1082
+ vm_lifetime_seconds: Math.floor(this.timeout / 1e3)
971
1083
  });
972
1084
  if (response.session_id) {
973
1085
  this._sessionId = response.session_id;
@@ -1004,6 +1116,7 @@ var InstaVM = class {
1004
1116
  * Get usage statistics for a session
1005
1117
  */
1006
1118
  async getUsage(sessionId) {
1119
+ this.ensureNotLocal("Usage tracking");
1007
1120
  const targetSessionId = sessionId || this._sessionId;
1008
1121
  if (!targetSessionId) {
1009
1122
  throw new SessionError("No active session to get usage for");
@@ -1030,6 +1143,7 @@ var InstaVM = class {
1030
1143
  * Download a file from the remote VM
1031
1144
  */
1032
1145
  async download(filename, options = {}) {
1146
+ this.ensureNotLocal("File download");
1033
1147
  const targetSessionId = options.sessionId || this._sessionId;
1034
1148
  if (!targetSessionId) {
1035
1149
  throw new SessionError("No active session to download from");
@@ -1087,6 +1201,7 @@ var InstaVM = class {
1087
1201
  NetworkError,
1088
1202
  QuotaExceededError,
1089
1203
  RateLimitError,
1090
- SessionError
1204
+ SessionError,
1205
+ UnsupportedOperationError
1091
1206
  });
1092
1207
  //# sourceMappingURL=index.js.map