instavm 0.1.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/dist/index.mjs ADDED
@@ -0,0 +1,935 @@
1
+ "use strict";
2
+
3
+ // src/client/HTTPClient.ts
4
+ import axios from "axios";
5
+
6
+ // src/errors/BaseError.ts
7
+ var InstaVMError = class extends Error {
8
+ constructor(message, options) {
9
+ super(message);
10
+ this.name = this.constructor.name;
11
+ this.code = options?.code;
12
+ this.statusCode = options?.statusCode;
13
+ this.response = options?.response;
14
+ Object.setPrototypeOf(this, new.target.prototype);
15
+ if (Error.captureStackTrace) {
16
+ Error.captureStackTrace(this, this.constructor);
17
+ }
18
+ }
19
+ };
20
+ var AuthenticationError = class extends InstaVMError {
21
+ constructor(message = "Authentication failed", options) {
22
+ super(message, { ...options, statusCode: 401 });
23
+ }
24
+ };
25
+ var RateLimitError = class extends InstaVMError {
26
+ constructor(message = "Rate limit exceeded", retryAfter, options) {
27
+ super(message, { ...options, statusCode: 429 });
28
+ this.retryAfter = retryAfter;
29
+ }
30
+ };
31
+ var QuotaExceededError = class extends InstaVMError {
32
+ constructor(message = "Usage quota exceeded", options) {
33
+ super(message, { ...options, statusCode: 402 });
34
+ }
35
+ };
36
+ var NetworkError = class extends InstaVMError {
37
+ constructor(message = "Network error", options) {
38
+ super(message, options);
39
+ }
40
+ };
41
+ var ExecutionError = class extends InstaVMError {
42
+ constructor(message, executionOutput, executionTime, options) {
43
+ super(message, options);
44
+ this.executionOutput = executionOutput;
45
+ this.executionTime = executionTime;
46
+ }
47
+ };
48
+ var SessionError = class extends InstaVMError {
49
+ constructor(message = "Session error", options) {
50
+ super(message, options);
51
+ }
52
+ };
53
+ var BrowserError = class extends InstaVMError {
54
+ constructor(message = "Browser error", options) {
55
+ super(message, options);
56
+ }
57
+ };
58
+ var BrowserSessionError = class extends BrowserError {
59
+ constructor(message = "Browser session error", options) {
60
+ super(message, options);
61
+ }
62
+ };
63
+ var BrowserInteractionError = class extends BrowserError {
64
+ constructor(message = "Browser interaction error", options) {
65
+ super(message, options);
66
+ }
67
+ };
68
+ var BrowserTimeoutError = class extends BrowserError {
69
+ constructor(message = "Browser operation timed out", options) {
70
+ super(message, options);
71
+ }
72
+ };
73
+ var BrowserNavigationError = class extends BrowserError {
74
+ constructor(message = "Browser navigation error", options) {
75
+ super(message, options);
76
+ }
77
+ };
78
+ var ElementNotFoundError = class extends BrowserError {
79
+ constructor(message = "Element not found", selector, options) {
80
+ super(message, options);
81
+ this.selector = selector;
82
+ }
83
+ };
84
+
85
+ // src/utils/retry.ts
86
+ function defaultRetryCondition(error) {
87
+ if (error instanceof NetworkError) return true;
88
+ if (error instanceof RateLimitError) return true;
89
+ if (error.response?.status >= 500) return true;
90
+ if (error.code === "ECONNABORTED" || error.code === "ETIMEDOUT") return true;
91
+ if (error.code === "ECONNRESET" || error.code === "ENOTFOUND") return true;
92
+ return false;
93
+ }
94
+ function calculateRetryDelay(attempt, baseDelay, maxDelay = 3e4) {
95
+ const exponentialDelay = baseDelay * Math.pow(2, attempt - 1);
96
+ const jitteredDelay = exponentialDelay * (0.5 + Math.random() * 0.5);
97
+ return Math.min(jitteredDelay, maxDelay);
98
+ }
99
+ async function withRetry(fn, options) {
100
+ const {
101
+ retries,
102
+ retryDelay,
103
+ maxRetryDelay = 3e4,
104
+ retryCondition = defaultRetryCondition
105
+ } = options;
106
+ let lastError;
107
+ for (let attempt = 1; attempt <= retries + 1; attempt++) {
108
+ try {
109
+ return await fn();
110
+ } catch (error) {
111
+ lastError = error;
112
+ if (attempt === retries + 1) {
113
+ break;
114
+ }
115
+ if (!retryCondition(error)) {
116
+ break;
117
+ }
118
+ const delay = calculateRetryDelay(attempt, retryDelay, maxRetryDelay);
119
+ await new Promise((resolve) => setTimeout(resolve, delay));
120
+ }
121
+ }
122
+ throw lastError;
123
+ }
124
+
125
+ // src/client/HTTPClient.ts
126
+ var HTTPClient = class {
127
+ get apiKey() {
128
+ return this.config.apiKey;
129
+ }
130
+ constructor(config) {
131
+ this.config = config;
132
+ this.client = axios.create({
133
+ baseURL: config.baseURL,
134
+ timeout: config.timeout,
135
+ headers: {
136
+ "Content-Type": "application/json",
137
+ "User-Agent": "instavm-js-sdk/0.1.0"
138
+ }
139
+ });
140
+ this.setupInterceptors();
141
+ }
142
+ setupInterceptors() {
143
+ this.client.interceptors.request.use(
144
+ (config) => {
145
+ if (config.url?.includes("/browser/")) {
146
+ config.headers["X-API-Key"] = this.config.apiKey;
147
+ }
148
+ return config;
149
+ },
150
+ (error) => Promise.reject(error)
151
+ );
152
+ this.client.interceptors.response.use(
153
+ (response) => response,
154
+ (error) => {
155
+ const axiosError = error;
156
+ const status = axiosError.response?.status;
157
+ const data = axiosError.response?.data;
158
+ const message = data?.message || data?.error || axiosError.message;
159
+ switch (status) {
160
+ case 401:
161
+ throw new AuthenticationError(message, {
162
+ statusCode: status,
163
+ response: data
164
+ });
165
+ case 402:
166
+ throw new QuotaExceededError(message, {
167
+ statusCode: status,
168
+ response: data
169
+ });
170
+ case 429:
171
+ const retryAfter = parseInt(
172
+ axiosError.response?.headers["retry-after"] || "60"
173
+ );
174
+ throw new RateLimitError(message, retryAfter, {
175
+ statusCode: status,
176
+ response: data
177
+ });
178
+ case 500:
179
+ case 502:
180
+ case 503:
181
+ case 504:
182
+ throw new NetworkError(message, {
183
+ statusCode: status,
184
+ response: data
185
+ });
186
+ default:
187
+ if (axiosError.code === "ECONNABORTED") {
188
+ throw new NetworkError("Request timeout", {
189
+ code: axiosError.code
190
+ });
191
+ }
192
+ throw new InstaVMError(message, {
193
+ statusCode: status,
194
+ response: data,
195
+ code: axiosError.code
196
+ });
197
+ }
198
+ }
199
+ );
200
+ }
201
+ /**
202
+ * Make an HTTP request with retry logic
203
+ */
204
+ async request(requestConfig) {
205
+ const axiosConfig = {
206
+ method: requestConfig.method,
207
+ url: requestConfig.url,
208
+ headers: requestConfig.headers,
209
+ data: requestConfig.data,
210
+ params: requestConfig.params,
211
+ timeout: requestConfig.timeout || this.config.timeout
212
+ };
213
+ const makeRequest = async () => {
214
+ const response = await this.client.request(axiosConfig);
215
+ return response.data;
216
+ };
217
+ return withRetry(makeRequest, {
218
+ retries: this.config.maxRetries,
219
+ retryDelay: this.config.retryDelay
220
+ });
221
+ }
222
+ /**
223
+ * POST request with JSON body
224
+ */
225
+ async post(url, data, headers) {
226
+ return this.request({
227
+ method: "POST",
228
+ url,
229
+ data,
230
+ headers
231
+ });
232
+ }
233
+ /**
234
+ * POST request for code execution (uses X-API-Key header like Python client)
235
+ */
236
+ async postExecution(url, data, headers) {
237
+ const requestHeaders = {
238
+ "X-API-Key": this.config.apiKey,
239
+ ...headers
240
+ };
241
+ return this.request({
242
+ method: "POST",
243
+ url,
244
+ data,
245
+ headers: requestHeaders
246
+ });
247
+ }
248
+ /**
249
+ * POST request with form data (for file uploads)
250
+ */
251
+ async postFormData(url, formData, headers) {
252
+ const requestHeaders = {
253
+ ...formData.getHeaders(),
254
+ ...headers
255
+ };
256
+ return this.request({
257
+ method: "POST",
258
+ url,
259
+ data: formData,
260
+ headers: requestHeaders
261
+ });
262
+ }
263
+ /**
264
+ * GET request
265
+ */
266
+ async get(url, params, headers) {
267
+ return this.request({
268
+ method: "GET",
269
+ url,
270
+ params,
271
+ headers
272
+ });
273
+ }
274
+ /**
275
+ * DELETE request
276
+ */
277
+ async delete(url, headers) {
278
+ return this.request({
279
+ method: "DELETE",
280
+ url,
281
+ headers
282
+ });
283
+ }
284
+ };
285
+
286
+ // src/client/BrowserSession.ts
287
+ import { EventEmitter } from "eventemitter3";
288
+ function getErrorMessage(error) {
289
+ return error instanceof Error ? error.message : String(error);
290
+ }
291
+ var BrowserSession = class extends EventEmitter {
292
+ constructor(sessionId, httpClient) {
293
+ super();
294
+ this._isActive = true;
295
+ this.sessionId = sessionId;
296
+ this.httpClient = httpClient;
297
+ }
298
+ /**
299
+ * Navigate to a URL
300
+ */
301
+ async navigate(url, options = {}) {
302
+ this.ensureActive();
303
+ const requestData = {
304
+ url,
305
+ session_id: this.sessionId,
306
+ wait_timeout: options.waitTimeout || 3e4,
307
+ wait_until: options.waitUntil || "load"
308
+ };
309
+ try {
310
+ const response = await this.httpClient.post(
311
+ "/v1/browser/interactions/navigate",
312
+ requestData
313
+ );
314
+ const result = {
315
+ success: response.success !== false,
316
+ url: response.url || url,
317
+ title: response.title,
318
+ status: response.status
319
+ };
320
+ this.emit("navigation", result);
321
+ return result;
322
+ } catch (error) {
323
+ const navigationError = new BrowserNavigationError(
324
+ `Navigation failed: ${getErrorMessage(error)}`,
325
+ { cause: error }
326
+ );
327
+ this.emit("error", navigationError);
328
+ throw navigationError;
329
+ }
330
+ }
331
+ /**
332
+ * Click an element
333
+ */
334
+ async click(selector, options = {}) {
335
+ this.ensureActive();
336
+ const requestData = {
337
+ selector,
338
+ session_id: this.sessionId,
339
+ timeout: options.timeout || 1e4,
340
+ button: options.button || "left",
341
+ click_count: options.clickCount || 1,
342
+ force: options.force || false
343
+ };
344
+ try {
345
+ await this.httpClient.post(
346
+ "/v1/browser/interactions/click",
347
+ requestData
348
+ );
349
+ } catch (error) {
350
+ const errorMessage = getErrorMessage(error);
351
+ if (errorMessage.includes("not found") || errorMessage.includes("selector")) {
352
+ throw new ElementNotFoundError(
353
+ `Element not found: ${selector}`,
354
+ selector,
355
+ { cause: error }
356
+ );
357
+ }
358
+ if (errorMessage.includes("timeout")) {
359
+ throw new BrowserTimeoutError(
360
+ `Click timeout: ${selector}`,
361
+ { cause: error }
362
+ );
363
+ }
364
+ throw new BrowserInteractionError(
365
+ `Click failed: ${errorMessage}`,
366
+ { cause: error }
367
+ );
368
+ }
369
+ }
370
+ /**
371
+ * Type text into an element
372
+ */
373
+ async type(selector, text, options = {}) {
374
+ this.ensureActive();
375
+ const requestData = {
376
+ selector,
377
+ text,
378
+ session_id: this.sessionId,
379
+ timeout: options.timeout || 1e4,
380
+ delay: options.delay || 0,
381
+ clear: options.clear !== false
382
+ };
383
+ try {
384
+ await this.httpClient.post(
385
+ "/v1/browser/interactions/type",
386
+ requestData
387
+ );
388
+ } catch (error) {
389
+ const errorMessage = getErrorMessage(error);
390
+ if (errorMessage.includes("not found") || errorMessage.includes("selector")) {
391
+ throw new ElementNotFoundError(
392
+ `Element not found: ${selector}`,
393
+ selector,
394
+ { cause: error }
395
+ );
396
+ }
397
+ throw new BrowserInteractionError(
398
+ `Type failed: ${errorMessage}`,
399
+ { cause: error }
400
+ );
401
+ }
402
+ }
403
+ /**
404
+ * Fill a form field
405
+ */
406
+ async fill(selector, value, options = {}) {
407
+ this.ensureActive();
408
+ const requestData = {
409
+ selector,
410
+ value,
411
+ session_id: this.sessionId,
412
+ timeout: options.timeout || 1e4,
413
+ force: options.force || false
414
+ };
415
+ try {
416
+ await this.httpClient.post(
417
+ "/v1/browser/interactions/fill",
418
+ requestData
419
+ );
420
+ } catch (error) {
421
+ const errorMessage = getErrorMessage(error);
422
+ if (errorMessage.includes("not found") || errorMessage.includes("selector")) {
423
+ throw new ElementNotFoundError(
424
+ `Element not found: ${selector}`,
425
+ selector,
426
+ { cause: error }
427
+ );
428
+ }
429
+ throw new BrowserInteractionError(
430
+ `Fill failed: ${errorMessage}`,
431
+ { cause: error }
432
+ );
433
+ }
434
+ }
435
+ /**
436
+ * Scroll the page
437
+ */
438
+ async scroll(options = {}) {
439
+ this.ensureActive();
440
+ const requestData = {
441
+ session_id: this.sessionId,
442
+ x: options.x || 0,
443
+ y: options.y || 500,
444
+ behavior: options.behavior || "auto"
445
+ };
446
+ try {
447
+ await this.httpClient.post(
448
+ "/v1/browser/interactions/scroll",
449
+ requestData
450
+ );
451
+ } catch (error) {
452
+ throw new BrowserInteractionError(
453
+ `Scroll failed: ${getErrorMessage(error)}`,
454
+ { cause: error }
455
+ );
456
+ }
457
+ }
458
+ /**
459
+ * Take a screenshot
460
+ */
461
+ async screenshot(options = {}) {
462
+ this.ensureActive();
463
+ const requestData = {
464
+ session_id: this.sessionId,
465
+ full_page: options.fullPage !== false,
466
+ format: options.format || "png",
467
+ quality: options.quality || 90,
468
+ clip: options.clip
469
+ };
470
+ try {
471
+ const response = await this.httpClient.post(
472
+ "/v1/browser/interactions/screenshot",
473
+ requestData
474
+ );
475
+ if (!response.screenshot) {
476
+ throw new BrowserError("Screenshot data not returned");
477
+ }
478
+ return response.screenshot;
479
+ } catch (error) {
480
+ throw new BrowserInteractionError(
481
+ `Screenshot failed: ${getErrorMessage(error)}`,
482
+ { cause: error }
483
+ );
484
+ }
485
+ }
486
+ /**
487
+ * Extract elements from the page
488
+ */
489
+ async extractElements(selector, attributes = ["text"], options = {}) {
490
+ this.ensureActive();
491
+ const requestData = {
492
+ selector,
493
+ attributes,
494
+ session_id: this.sessionId,
495
+ max_results: options.maxResults || 100
496
+ };
497
+ try {
498
+ const response = await this.httpClient.post(
499
+ "/v1/browser/interactions/extract",
500
+ requestData
501
+ );
502
+ return response.elements || [];
503
+ } catch (error) {
504
+ throw new BrowserInteractionError(
505
+ `Element extraction failed: ${getErrorMessage(error)}`,
506
+ { cause: error }
507
+ );
508
+ }
509
+ }
510
+ /**
511
+ * Wait for a condition
512
+ */
513
+ async wait(condition, timeout = 1e4) {
514
+ this.ensureActive();
515
+ let requestData = {
516
+ session_id: this.sessionId,
517
+ timeout
518
+ };
519
+ if (condition.type === "timeout") {
520
+ await new Promise((resolve) => setTimeout(resolve, condition.ms));
521
+ return;
522
+ }
523
+ requestData = {
524
+ ...requestData,
525
+ condition: condition.type,
526
+ selector: "selector" in condition ? condition.selector : void 0
527
+ };
528
+ try {
529
+ await this.httpClient.post(
530
+ "/v1/browser/interactions/wait",
531
+ requestData
532
+ );
533
+ } catch (error) {
534
+ const errorMessage = getErrorMessage(error);
535
+ if (errorMessage.includes("timeout")) {
536
+ throw new BrowserTimeoutError(
537
+ `Wait condition timeout: ${condition.type}`,
538
+ { cause: error }
539
+ );
540
+ }
541
+ throw new BrowserInteractionError(
542
+ `Wait failed: ${errorMessage}`,
543
+ { cause: error }
544
+ );
545
+ }
546
+ }
547
+ /**
548
+ * Close the browser session
549
+ */
550
+ async close() {
551
+ if (!this._isActive) {
552
+ return;
553
+ }
554
+ try {
555
+ await this.httpClient.delete(`/v1/browser/sessions/${this.sessionId}`);
556
+ } catch (error) {
557
+ console.warn(`Failed to close browser session ${this.sessionId}:`, getErrorMessage(error));
558
+ } finally {
559
+ this._isActive = false;
560
+ this.emit("close");
561
+ }
562
+ }
563
+ /**
564
+ * Check if session is active
565
+ */
566
+ get isActive() {
567
+ return this._isActive;
568
+ }
569
+ /**
570
+ * Ensure session is active before operations
571
+ */
572
+ ensureActive() {
573
+ if (!this._isActive) {
574
+ throw new BrowserError("Browser session is not active");
575
+ }
576
+ }
577
+ };
578
+
579
+ // src/client/BrowserManager.ts
580
+ var BrowserManager = class {
581
+ constructor(httpClient) {
582
+ this.activeSessions = /* @__PURE__ */ new Map();
583
+ this.httpClient = httpClient;
584
+ }
585
+ /**
586
+ * Create a new browser session
587
+ */
588
+ async createSession(options = {}) {
589
+ const requestData = {
590
+ viewport_width: options.viewportWidth || 1920,
591
+ viewport_height: options.viewportHeight || 1080,
592
+ user_agent: options.userAgent
593
+ };
594
+ try {
595
+ const response = await this.httpClient.post(
596
+ "/v1/browser/sessions/",
597
+ requestData
598
+ );
599
+ if (!response.session_id) {
600
+ throw new BrowserSessionError("No session ID returned from server");
601
+ }
602
+ const session = new BrowserSession(response.session_id, this.httpClient);
603
+ this.activeSessions.set(response.session_id, session);
604
+ session.on("close", () => {
605
+ this.activeSessions.delete(response.session_id);
606
+ });
607
+ return session;
608
+ } catch (error) {
609
+ const errorMessage = error instanceof Error ? error.message : String(error);
610
+ throw new BrowserSessionError(
611
+ `Failed to create browser session: ${errorMessage}`,
612
+ { cause: error }
613
+ );
614
+ }
615
+ }
616
+ /**
617
+ * Get information about a specific session
618
+ */
619
+ async getSession(sessionId) {
620
+ try {
621
+ const response = await this.httpClient.get(
622
+ `/v1/browser/sessions/${sessionId}`
623
+ );
624
+ return {
625
+ sessionId: response.session_id,
626
+ status: response.status || "active",
627
+ createdAt: response.created_at,
628
+ viewportWidth: response.viewport_width,
629
+ viewportHeight: response.viewport_height,
630
+ userAgent: response.user_agent
631
+ };
632
+ } catch (error) {
633
+ const errorMessage = error instanceof Error ? error.message : String(error);
634
+ throw new BrowserSessionError(
635
+ `Failed to get session info: ${errorMessage}`,
636
+ { cause: error }
637
+ );
638
+ }
639
+ }
640
+ /**
641
+ * List all browser sessions
642
+ */
643
+ async listSessions() {
644
+ try {
645
+ const response = await this.httpClient.get("/v1/browser/sessions/");
646
+ if (!Array.isArray(response.sessions)) {
647
+ return [];
648
+ }
649
+ return response.sessions.map((session) => ({
650
+ sessionId: session.session_id,
651
+ status: session.status || "active",
652
+ createdAt: session.created_at,
653
+ viewportWidth: session.viewport_width,
654
+ viewportHeight: session.viewport_height,
655
+ userAgent: session.user_agent
656
+ }));
657
+ } catch (error) {
658
+ const errorMessage = error instanceof Error ? error.message : String(error);
659
+ throw new BrowserSessionError(
660
+ `Failed to list sessions: ${errorMessage}`,
661
+ { cause: error }
662
+ );
663
+ }
664
+ }
665
+ /**
666
+ * Get a locally tracked session
667
+ */
668
+ getLocalSession(sessionId) {
669
+ return this.activeSessions.get(sessionId);
670
+ }
671
+ /**
672
+ * Get all locally tracked sessions
673
+ */
674
+ getLocalSessions() {
675
+ return Array.from(this.activeSessions.values());
676
+ }
677
+ /**
678
+ * Close all active sessions
679
+ */
680
+ async closeAllSessions() {
681
+ const sessions = Array.from(this.activeSessions.values());
682
+ await Promise.allSettled(
683
+ sessions.map((session) => session.close())
684
+ );
685
+ this.activeSessions.clear();
686
+ }
687
+ /**
688
+ * Clean up resources
689
+ */
690
+ async dispose() {
691
+ await this.closeAllSessions();
692
+ }
693
+ };
694
+
695
+ // src/client/InstaVM.ts
696
+ import FormData from "form-data";
697
+ var InstaVM = class {
698
+ constructor(apiKey, options = {}) {
699
+ this._sessionId = null;
700
+ if (!apiKey) {
701
+ throw new Error("API key is required");
702
+ }
703
+ const config = {
704
+ baseURL: options.baseURL || "https://api.instavm.io",
705
+ timeout: options.timeout || 3e5,
706
+ // 5 minutes
707
+ maxRetries: options.maxRetries || 3,
708
+ retryDelay: options.retryDelay || 1e3,
709
+ apiKey
710
+ };
711
+ this.httpClient = new HTTPClient(config);
712
+ this.browser = new BrowserManager(this.httpClient);
713
+ }
714
+ /**
715
+ * Execute code synchronously
716
+ */
717
+ async execute(command, options = {}) {
718
+ let sessionId = options.sessionId || this._sessionId;
719
+ if (!sessionId) {
720
+ sessionId = await this.createSession();
721
+ }
722
+ const requestData = {
723
+ command,
724
+ language: options.language || "python",
725
+ timeout: options.timeout || 15,
726
+ session_id: sessionId
727
+ };
728
+ try {
729
+ const response = await this.httpClient.postExecution(
730
+ "/execute",
731
+ requestData
732
+ );
733
+ if (response.session_id) {
734
+ this._sessionId = response.session_id;
735
+ }
736
+ return {
737
+ output: response.stdout || response.output || "",
738
+ success: response.success !== false,
739
+ executionTime: response.execution_time || 0,
740
+ sessionId: response.session_id,
741
+ error: response.error
742
+ };
743
+ } catch (error) {
744
+ const errorMessage = error instanceof Error ? error.message : String(error);
745
+ throw new ExecutionError(
746
+ `Code execution failed: ${errorMessage}`,
747
+ void 0,
748
+ void 0,
749
+ { cause: error }
750
+ );
751
+ }
752
+ }
753
+ /**
754
+ * Execute code asynchronously
755
+ */
756
+ async executeAsync(command, options = {}) {
757
+ let sessionId = options.sessionId || this._sessionId;
758
+ if (!sessionId) {
759
+ sessionId = await this.createSession();
760
+ }
761
+ const requestData = {
762
+ command,
763
+ language: options.language || "python",
764
+ timeout: options.timeout || 15,
765
+ session_id: sessionId
766
+ };
767
+ try {
768
+ const response = await this.httpClient.postExecution(
769
+ "/execute_async",
770
+ requestData
771
+ );
772
+ if (response.session_id) {
773
+ this._sessionId = response.session_id;
774
+ }
775
+ return {
776
+ taskId: response.task_id,
777
+ status: response.status || "pending",
778
+ output: response.stdout || response.output,
779
+ success: response.success,
780
+ executionTime: response.execution_time,
781
+ sessionId: response.session_id,
782
+ error: response.error
783
+ };
784
+ } catch (error) {
785
+ const errorMessage = error instanceof Error ? error.message : String(error);
786
+ throw new ExecutionError(
787
+ `Async code execution failed: ${errorMessage}`,
788
+ void 0,
789
+ void 0,
790
+ { cause: error }
791
+ );
792
+ }
793
+ }
794
+ /**
795
+ * Upload files to the execution environment
796
+ */
797
+ async upload(files, options = {}) {
798
+ const formData = new FormData();
799
+ for (const file of files) {
800
+ if (Buffer.isBuffer(file.content)) {
801
+ formData.append("files", file.content, file.name);
802
+ } else {
803
+ formData.append("files", Buffer.from(file.content), file.name);
804
+ }
805
+ if (file.path) {
806
+ formData.append("paths", file.path);
807
+ }
808
+ }
809
+ if (options.sessionId || this._sessionId) {
810
+ formData.append("session_id", options.sessionId || this._sessionId);
811
+ }
812
+ if (options.remotePath) {
813
+ formData.append("remote_path", options.remotePath);
814
+ }
815
+ if (options.recursive !== void 0) {
816
+ formData.append("recursive", String(options.recursive));
817
+ }
818
+ try {
819
+ const response = await this.httpClient.postFormData(
820
+ "/upload",
821
+ formData
822
+ );
823
+ return {
824
+ success: response.success !== false,
825
+ files: response.files || [],
826
+ message: response.message
827
+ };
828
+ } catch (error) {
829
+ const errorMessage = error instanceof Error ? error.message : String(error);
830
+ throw new SessionError(
831
+ `File upload failed: ${errorMessage}`,
832
+ { cause: error }
833
+ );
834
+ }
835
+ }
836
+ /**
837
+ * Create a new execution session
838
+ */
839
+ async createSession() {
840
+ try {
841
+ const response = await this.httpClient.post("/v1/sessions/session", {
842
+ api_key: this.httpClient.apiKey
843
+ });
844
+ if (response.session_id) {
845
+ this._sessionId = response.session_id;
846
+ return response.session_id;
847
+ }
848
+ throw new SessionError("Session creation failed: No session ID returned");
849
+ } catch (error) {
850
+ const errorMessage = error instanceof Error ? error.message : String(error);
851
+ throw new SessionError(
852
+ `Session creation failed: ${errorMessage}`,
853
+ { cause: error }
854
+ );
855
+ }
856
+ }
857
+ /**
858
+ * Close a session
859
+ */
860
+ async closeSession(sessionId) {
861
+ const targetSessionId = sessionId || this._sessionId;
862
+ if (!targetSessionId) {
863
+ return;
864
+ }
865
+ try {
866
+ await this.httpClient.delete(`/v1/sessions/${targetSessionId}`);
867
+ if (targetSessionId === this._sessionId) {
868
+ this._sessionId = null;
869
+ }
870
+ } catch (error) {
871
+ const errorMessage = error instanceof Error ? error.message : String(error);
872
+ console.warn(`Failed to close session ${targetSessionId}:`, errorMessage);
873
+ }
874
+ }
875
+ /**
876
+ * Get usage statistics for a session
877
+ */
878
+ async getUsage(sessionId) {
879
+ const targetSessionId = sessionId || this._sessionId;
880
+ if (!targetSessionId) {
881
+ throw new SessionError("No active session to get usage for");
882
+ }
883
+ try {
884
+ const response = await this.httpClient.get(
885
+ `/v1/sessions/usage/${targetSessionId}`
886
+ );
887
+ return {
888
+ sessionsUsed: response.sessions_used || 0,
889
+ executionTime: response.execution_time || 0,
890
+ quotaRemaining: response.quota_remaining || 0,
891
+ quotaLimit: response.quota_limit || 0
892
+ };
893
+ } catch (error) {
894
+ const errorMessage = error instanceof Error ? error.message : String(error);
895
+ throw new SessionError(
896
+ `Failed to get usage stats: ${errorMessage}`,
897
+ { cause: error }
898
+ );
899
+ }
900
+ }
901
+ /**
902
+ * Get the current session ID
903
+ */
904
+ get sessionId() {
905
+ return this._sessionId;
906
+ }
907
+ /**
908
+ * Clean up resources
909
+ */
910
+ async dispose() {
911
+ if (this._sessionId) {
912
+ await this.closeSession();
913
+ }
914
+ await this.browser.dispose();
915
+ }
916
+ };
917
+ export {
918
+ AuthenticationError,
919
+ BrowserError,
920
+ BrowserInteractionError,
921
+ BrowserManager,
922
+ BrowserNavigationError,
923
+ BrowserSession,
924
+ BrowserSessionError,
925
+ BrowserTimeoutError,
926
+ ElementNotFoundError,
927
+ ExecutionError,
928
+ InstaVM,
929
+ InstaVMError,
930
+ NetworkError,
931
+ QuotaExceededError,
932
+ RateLimitError,
933
+ SessionError
934
+ };
935
+ //# sourceMappingURL=index.mjs.map