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/README.md ADDED
@@ -0,0 +1,795 @@
1
+ # InstaVM JavaScript SDK
2
+
3
+ A comprehensive JavaScript/TypeScript client library for InstaVM's code execution and browser automation APIs.
4
+
5
+ ## Features
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
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install instavm
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ### Code Execution
25
+
26
+ ```typescript
27
+ import { InstaVM, ExecutionError, NetworkError } from 'instavm';
28
+
29
+ // Create client with automatic session management
30
+ const client = new InstaVM('your_api_key');
31
+
32
+ try {
33
+ // Execute a command
34
+ const result = await client.execute("print(100**100)");
35
+ console.log(result);
36
+
37
+ // Get usage info for the session
38
+ const usage = await client.getUsage();
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
+ }
47
+ } finally {
48
+ await client.dispose();
49
+ }
50
+ ```
51
+
52
+ ### File Upload
53
+
54
+ ```typescript
55
+ import { InstaVM } from 'instavm';
56
+
57
+ const client = new InstaVM('your_api_key');
58
+
59
+ // Upload files to the execution environment
60
+ const files = [
61
+ {
62
+ name: 'script.py',
63
+ content: 'print("Hello from uploaded file!")',
64
+ path: '/remote/path/script.py'
65
+ }
66
+ ];
67
+
68
+ const result = await client.upload(files);
69
+ console.log(result);
70
+
71
+ // Execute the uploaded file
72
+ const execution = await client.execute('python /remote/path/script.py', {
73
+ language: 'bash'
74
+ });
75
+ console.log(execution.output);
76
+ ```
77
+
78
+ ### Error Handling
79
+
80
+ ```typescript
81
+ import {
82
+ InstaVM,
83
+ AuthenticationError,
84
+ RateLimitError,
85
+ SessionError,
86
+ QuotaExceededError
87
+ } from 'instavm';
88
+
89
+ try {
90
+ const client = new InstaVM('invalid_key');
91
+ await client.execute('print("test")');
92
+ } catch (error) {
93
+ if (error instanceof AuthenticationError) {
94
+ console.log("Invalid API key");
95
+ } else if (error instanceof RateLimitError) {
96
+ console.log(`Rate limit exceeded - retry after ${error.retryAfter} seconds`);
97
+ } else if (error instanceof QuotaExceededError) {
98
+ console.log("Usage quota exceeded");
99
+ } else if (error instanceof SessionError) {
100
+ console.log(`Session error: ${error.message}`);
101
+ }
102
+ }
103
+ ```
104
+
105
+ ### Async Execution
106
+
107
+ ```typescript
108
+ import { InstaVM } from 'instavm';
109
+
110
+ const client = new InstaVM('your_api_key');
111
+
112
+ // Execute command asynchronously (returns task info)
113
+ const result = await client.executeAsync("sleep 5 && echo 'Long task complete!'", {
114
+ language: 'bash'
115
+ });
116
+
117
+ console.log(`Task ${result.taskId} status: ${result.status}`);
118
+ console.log(`Output so far: ${result.output}`);
119
+ ```
120
+
121
+ ## Browser Automation
122
+
123
+ ### Basic Browser Usage
124
+
125
+ ```typescript
126
+ import { InstaVM } from 'instavm';
127
+
128
+ const client = new InstaVM('your_api_key');
129
+
130
+ // Create browser session
131
+ const session = await client.browser.createSession({
132
+ viewportWidth: 1920,
133
+ viewportHeight: 1080
134
+ });
135
+
136
+ // Navigate to website
137
+ await session.navigate('https://example.com');
138
+
139
+ // Take screenshot
140
+ const screenshot = await session.screenshot();
141
+ console.log(`Screenshot captured: ${screenshot.length} chars`);
142
+
143
+ // Extract page data
144
+ const elements = await session.extractElements('h1, p', ['text', 'href']);
145
+ console.log('Page content:', elements);
146
+
147
+ // Clean up
148
+ await session.close();
149
+ ```
150
+
151
+ ### Advanced Browser Interactions
152
+
153
+ ```typescript
154
+ // Navigate with options
155
+ await session.navigate('https://github.com/login', {
156
+ waitTimeout: 30000,
157
+ waitUntil: 'networkidle'
158
+ });
159
+
160
+ // Fill login form
161
+ await session.fill('input[name="login"]', 'username');
162
+ await session.fill('input[name="password"]', 'password');
163
+
164
+ // Click submit button
165
+ await session.click('input[type="submit"]');
166
+
167
+ // Wait for navigation
168
+ await session.wait({ type: 'navigation' });
169
+
170
+ // Scroll to load more content
171
+ await session.scroll({ y: 1000 });
172
+
173
+ // Extract dynamic content
174
+ const repos = await session.extractElements('.repo-list-item', ['text']);
175
+ console.log('Repositories found:', repos.length);
176
+ ```
177
+
178
+ ### Browser Session Management
179
+
180
+ ```typescript
181
+ // Create session with custom options
182
+ const session = await client.browser.createSession({
183
+ viewportWidth: 1280,
184
+ viewportHeight: 720,
185
+ userAgent: 'CustomBot/1.0'
186
+ });
187
+
188
+ // Session supports event listeners
189
+ session.on('navigation', (result) => {
190
+ console.log(`Navigated to: ${result.url}`);
191
+ console.log(`Page title: ${result.title}`);
192
+ });
193
+
194
+ session.on('error', (error) => {
195
+ console.error('Session error:', error.message);
196
+ });
197
+
198
+ session.on('close', () => {
199
+ console.log('Session closed');
200
+ });
201
+
202
+ // Check if session is still active
203
+ if (session.isActive) {
204
+ await session.navigate('https://example.com');
205
+ }
206
+ ```
207
+
208
+ ### Context Manager Pattern
209
+
210
+ ```typescript
211
+ // Use browser session with automatic cleanup
212
+ const client = new InstaVM('your_api_key');
213
+
214
+ async function automateWebsite() {
215
+ const session = await client.browser.createSession();
216
+
217
+ try {
218
+ await session.navigate('https://httpbin.org/forms/post');
219
+
220
+ // Fill and submit form
221
+ await session.fill('input[name="custname"]', 'John Doe');
222
+ await session.fill('input[name="custtel"]', '555-1234');
223
+ await session.click('input[type="submit"]');
224
+
225
+ // Wait for result
226
+ await session.wait({ type: 'visible', selector: 'pre' });
227
+
228
+ // Extract result
229
+ const result = await session.extractElements('pre', ['text']);
230
+ return result[0]?.text;
231
+
232
+ } finally {
233
+ await session.close();
234
+ }
235
+ }
236
+
237
+ const result = await automateWebsite();
238
+ console.log('Form submission result:', result);
239
+ ```
240
+
241
+ ## Mixed Code + Browser Automation
242
+
243
+ Combine code execution with browser automation for powerful workflows:
244
+
245
+ ```typescript
246
+ import { InstaVM } from 'instavm';
247
+
248
+ const client = new InstaVM('your_api_key');
249
+
250
+ // Execute Python code to prepare data
251
+ const dataPrep = await client.execute(`
252
+ import json
253
+ import pandas as pd
254
+
255
+ # Prepare search terms
256
+ search_terms = ["AI", "Machine Learning", "JavaScript"]
257
+ data = {"terms": search_terms, "timestamp": "2024-01-01"}
258
+ print(json.dumps(data))
259
+ `);
260
+
261
+ const searchData = JSON.parse(dataPrep.output.trim());
262
+
263
+ // Use browser to search and collect results
264
+ const session = await client.browser.createSession();
265
+ const results = [];
266
+
267
+ for (const term of searchData.terms) {
268
+ await session.navigate(`https://news.ycombinator.com/search?q=${encodeURIComponent(term)}`);
269
+
270
+ const headlines = await session.extractElements('.titleline > a', ['text', 'href']);
271
+ results.push({
272
+ term,
273
+ headlines: headlines.slice(0, 5) // Top 5 results
274
+ });
275
+ }
276
+
277
+ await session.close();
278
+
279
+ // Process results with Python
280
+ const analysis = await client.execute(`
281
+ import json
282
+ data = ${JSON.stringify(results)}
283
+
284
+ # Analyze results
285
+ total_headlines = sum(len(item['headlines']) for item in data)
286
+ print(f"Collected {total_headlines} headlines across {len(data)} search terms")
287
+
288
+ # Find most common words
289
+ all_text = ' '.join([headline['text'] for item in data for headline in item['headlines']])
290
+ words = all_text.lower().split()
291
+ word_counts = {}
292
+ for word in words:
293
+ if len(word) > 3: # Filter short words
294
+ word_counts[word] = word_counts.get(word, 0) + 1
295
+
296
+ # Top 10 words
297
+ top_words = sorted(word_counts.items(), key=lambda x: x[1], reverse=True)[:10]
298
+ print("Top words:", top_words)
299
+ `);
300
+
301
+ console.log(analysis.output);
302
+ await client.dispose();
303
+ ```
304
+
305
+ ## Language Support
306
+
307
+ ### Python Code Execution
308
+
309
+ ```typescript
310
+ // Python with libraries
311
+ const result = await client.execute(`
312
+ import pandas as pd
313
+ import numpy as np
314
+
315
+ # Create sample data
316
+ data = pd.DataFrame({
317
+ 'numbers': np.random.randn(100),
318
+ 'categories': np.random.choice(['A', 'B', 'C'], 100)
319
+ })
320
+
321
+ # Basic statistics
322
+ print(f"Mean: {data['numbers'].mean():.2f}")
323
+ print(f"Std: {data['numbers'].std():.2f}")
324
+ print(f"Categories: {data['categories'].value_counts().to_dict()}")
325
+ `);
326
+
327
+ console.log(result.output);
328
+ ```
329
+
330
+ ### Bash Commands
331
+
332
+ ```typescript
333
+ // System operations
334
+ const sysInfo = await client.execute(`
335
+ echo "System Information:"
336
+ echo "==================="
337
+ uname -a
338
+ echo
339
+ echo "Disk Usage:"
340
+ df -h
341
+ echo
342
+ echo "Memory Info:"
343
+ free -h
344
+ `, { language: 'bash' });
345
+
346
+ console.log(sysInfo.output);
347
+ ```
348
+
349
+ ### Session Persistence
350
+
351
+ ```typescript
352
+ // Variables persist across executions within the same session
353
+ await client.execute('data = [1, 2, 3, 4, 5]');
354
+ await client.execute('total = sum(data)');
355
+
356
+ const result = await client.execute('print(f"Total: {total}, Average: {total/len(data)}")');
357
+ console.log(result.output); // Output: Total: 15, Average: 3.0
358
+ ```
359
+
360
+ ## Advanced Features
361
+
362
+ ### Wait Conditions
363
+
364
+ ```typescript
365
+ // Wait for element to appear
366
+ await session.wait({
367
+ type: 'visible',
368
+ selector: '.loading-complete',
369
+ timeout: 30000
370
+ });
371
+
372
+ // Wait for element to disappear
373
+ await session.wait({
374
+ type: 'hidden',
375
+ selector: '.spinner'
376
+ });
377
+
378
+ // Wait for page load
379
+ await session.wait({
380
+ type: 'networkidle'
381
+ });
382
+
383
+ // Simple timeout
384
+ await session.wait({
385
+ type: 'timeout',
386
+ ms: 5000
387
+ });
388
+ ```
389
+
390
+ ### Screenshot Options
391
+
392
+ ```typescript
393
+ // Full page screenshot
394
+ const fullPage = await session.screenshot({
395
+ fullPage: true,
396
+ format: 'png'
397
+ });
398
+
399
+ // Clip specific area
400
+ const clipped = await session.screenshot({
401
+ clip: {
402
+ x: 0,
403
+ y: 0,
404
+ width: 800,
405
+ height: 600
406
+ },
407
+ format: 'jpeg',
408
+ quality: 90
409
+ });
410
+
411
+ // Screenshots return base64 encoded strings
412
+ const buffer = Buffer.from(fullPage, 'base64');
413
+ // Save to file if needed
414
+ ```
415
+
416
+ ### Element Extraction
417
+
418
+ ```typescript
419
+ // Extract multiple attributes
420
+ const links = await session.extractElements('a', ['href', 'text', 'title']);
421
+
422
+ // Extract with CSS selectors
423
+ const articles = await session.extractElements('article h2, .post-title', ['text']);
424
+
425
+ // Extract form data
426
+ const formData = await session.extractElements('input, select, textarea', [
427
+ 'name', 'value', 'type', 'placeholder'
428
+ ]);
429
+
430
+ console.log('Links found:', links);
431
+ console.log('Articles:', articles);
432
+ console.log('Form fields:', formData);
433
+ ```
434
+
435
+ ## Error Handling Reference
436
+
437
+ ### Error Types
438
+
439
+ ```typescript
440
+ import {
441
+ InstaVMError, // Base error class
442
+ AuthenticationError, // API key issues
443
+ RateLimitError, // Rate limiting (has retryAfter property)
444
+ QuotaExceededError, // Usage quota exceeded
445
+ NetworkError, // Connection issues
446
+ ExecutionError, // Code execution failures
447
+ SessionError, // Session management issues
448
+ BrowserError, // General browser errors
449
+ BrowserSessionError, // Browser session issues
450
+ BrowserInteractionError, // Browser interaction failures
451
+ BrowserTimeoutError, // Browser operation timeouts
452
+ BrowserNavigationError, // Navigation failures
453
+ ElementNotFoundError // Element selection issues (has selector property)
454
+ } from 'instavm';
455
+
456
+ // Specific error handling
457
+ try {
458
+ await session.click('.non-existent-button');
459
+ } catch (error) {
460
+ if (error instanceof ElementNotFoundError) {
461
+ console.log(`Element not found: ${error.selector}`);
462
+ } else if (error instanceof BrowserTimeoutError) {
463
+ console.log('Operation timed out');
464
+ }
465
+ }
466
+ ```
467
+
468
+ ### Retry Logic
469
+
470
+ The SDK includes automatic retry logic for:
471
+ - Network errors (connection issues)
472
+ - Rate limiting (with exponential backoff)
473
+ - Server errors (5xx status codes)
474
+
475
+ ```typescript
476
+ // Customize retry behavior
477
+ const client = new InstaVM('your_api_key', {
478
+ maxRetries: 5,
479
+ retryDelay: 2000, // Base delay in milliseconds
480
+ timeout: 300000 // 5 minute timeout
481
+ });
482
+ ```
483
+
484
+ ## API Reference
485
+
486
+ ### InstaVM Client
487
+
488
+ ```typescript
489
+ class InstaVM {
490
+ constructor(apiKey: string, options?: InstaVMOptions)
491
+
492
+ // Code execution
493
+ execute(command: string, options?: ExecuteOptions): Promise<ExecutionResult>
494
+ executeAsync(command: string, options?: ExecuteOptions): Promise<AsyncExecutionResult>
495
+
496
+ // File operations
497
+ upload(files: FileUpload[], options?: UploadOptions): Promise<UploadResult>
498
+
499
+ // Session management
500
+ createSession(): Promise<string>
501
+ closeSession(sessionId?: string): Promise<void>
502
+ getUsage(sessionId?: string): Promise<UsageStats>
503
+
504
+ // Browser automation
505
+ browser: BrowserManager
506
+
507
+ // Properties
508
+ readonly sessionId: string | null
509
+
510
+ // Cleanup
511
+ dispose(): Promise<void>
512
+ }
513
+ ```
514
+
515
+ ### Configuration Options
516
+
517
+ ```typescript
518
+ interface InstaVMOptions {
519
+ baseURL?: string; // Default: 'https://api.instavm.io'
520
+ timeout?: number; // Default: 300000 (5 minutes)
521
+ maxRetries?: number; // Default: 3
522
+ retryDelay?: number; // Default: 1000ms
523
+ }
524
+
525
+ interface ExecuteOptions {
526
+ language?: 'python' | 'bash'; // Default: 'python'
527
+ timeout?: number; // Default: 15 seconds
528
+ sessionId?: string; // Use specific session
529
+ }
530
+ ```
531
+
532
+ ### Browser Manager
533
+
534
+ ```typescript
535
+ class BrowserManager {
536
+ createSession(options?: BrowserSessionOptions): Promise<BrowserSession>
537
+ listSessions(): Promise<BrowserSessionInfo[]>
538
+ getSession(sessionId: string): Promise<BrowserSessionInfo>
539
+ getLocalSession(sessionId: string): BrowserSession | undefined
540
+ getLocalSessions(): BrowserSession[]
541
+ closeAllSessions(): Promise<void>
542
+ dispose(): Promise<void>
543
+ }
544
+
545
+ interface BrowserSessionOptions {
546
+ viewportWidth?: number; // Default: 1920
547
+ viewportHeight?: number; // Default: 1080
548
+ userAgent?: string; // Custom user agent
549
+ }
550
+ ```
551
+
552
+ ### Browser Session
553
+
554
+ ```typescript
555
+ class BrowserSession extends EventEmitter {
556
+ // Navigation
557
+ navigate(url: string, options?: NavigateOptions): Promise<NavigationResult>
558
+
559
+ // Interaction
560
+ click(selector: string, options?: ClickOptions): Promise<void>
561
+ type(selector: string, text: string, options?: TypeOptions): Promise<void>
562
+ fill(selector: string, value: string, options?: FillOptions): Promise<void>
563
+ scroll(options?: ScrollOptions): Promise<void>
564
+
565
+ // Data extraction
566
+ screenshot(options?: ScreenshotOptions): Promise<string>
567
+ extractElements(selector: string, attributes?: string[]): Promise<ExtractedElement[]>
568
+
569
+ // Utilities
570
+ wait(condition: WaitCondition, timeout?: number): Promise<void>
571
+ close(): Promise<void>
572
+
573
+ // Properties
574
+ readonly sessionId: string
575
+ readonly isActive: boolean
576
+
577
+ // Events: 'navigation', 'error', 'close'
578
+ }
579
+ ```
580
+
581
+ ### Type Definitions
582
+
583
+ ```typescript
584
+ interface ExecutionResult {
585
+ output: string;
586
+ success: boolean;
587
+ executionTime: number;
588
+ sessionId?: string;
589
+ error?: string;
590
+ }
591
+
592
+ interface NavigationResult {
593
+ success: boolean;
594
+ url: string;
595
+ title?: string;
596
+ status?: number;
597
+ }
598
+
599
+ interface ExtractedElement {
600
+ text?: string;
601
+ href?: string;
602
+ [attribute: string]: string | undefined;
603
+ }
604
+
605
+ type WaitCondition =
606
+ | { type: 'timeout'; ms: number }
607
+ | { type: 'visible'; selector: string }
608
+ | { type: 'hidden'; selector: string }
609
+ | { type: 'navigation' }
610
+ | { type: 'networkidle' };
611
+ ```
612
+
613
+ ## Best Practices
614
+
615
+ ### Resource Management
616
+
617
+ ```typescript
618
+ // Always dispose of the client when done
619
+ const client = new InstaVM('your_api_key');
620
+ try {
621
+ // Your automation code
622
+ } finally {
623
+ await client.dispose(); // Closes all sessions and cleans up
624
+ }
625
+
626
+ // Or use a wrapper function
627
+ async function withInstaVM(apiKey: string, callback: (client: InstaVM) => Promise<void>) {
628
+ const client = new InstaVM(apiKey);
629
+ try {
630
+ await callback(client);
631
+ } finally {
632
+ await client.dispose();
633
+ }
634
+ }
635
+
636
+ await withInstaVM('your_api_key', async (client) => {
637
+ const result = await client.execute('print("Hello, World!")');
638
+ console.log(result.output);
639
+ });
640
+ ```
641
+
642
+ ### Error Handling Strategy
643
+
644
+ ```typescript
645
+ // Implement comprehensive error handling
646
+ async function robustAutomation(client: InstaVM) {
647
+ let session: BrowserSession | null = null;
648
+
649
+ try {
650
+ session = await client.browser.createSession();
651
+
652
+ // Retry navigation with timeout
653
+ let retries = 3;
654
+ while (retries > 0) {
655
+ try {
656
+ await session.navigate('https://example.com');
657
+ break;
658
+ } catch (error) {
659
+ if (error instanceof BrowserTimeoutError && retries > 1) {
660
+ console.log(`Navigation timeout, retrying... (${retries - 1} attempts left)`);
661
+ retries--;
662
+ await new Promise(resolve => setTimeout(resolve, 2000));
663
+ } else {
664
+ throw error;
665
+ }
666
+ }
667
+ }
668
+
669
+ // Safe element interaction
670
+ try {
671
+ await session.click('button.submit');
672
+ } catch (error) {
673
+ if (error instanceof ElementNotFoundError) {
674
+ console.log('Submit button not found, trying alternative selector');
675
+ await session.click('input[type="submit"]');
676
+ } else {
677
+ throw error;
678
+ }
679
+ }
680
+
681
+ } catch (error) {
682
+ console.error('Automation failed:', error.message);
683
+ throw error;
684
+ } finally {
685
+ if (session) {
686
+ await session.close();
687
+ }
688
+ }
689
+ }
690
+ ```
691
+
692
+ ### Performance Optimization
693
+
694
+ ```typescript
695
+ // Batch operations when possible
696
+ const session = await client.browser.createSession();
697
+
698
+ // Instead of multiple separate calls
699
+ await session.navigate('https://example.com');
700
+ const title = await session.extractElements('title', ['text']);
701
+ const links = await session.extractElements('a', ['href']);
702
+ const images = await session.extractElements('img', ['src', 'alt']);
703
+
704
+ // Consider using a single extraction call for related elements
705
+ const pageData = await session.extractElements('title, a, img', ['text', 'href', 'src', 'alt']);
706
+
707
+ // Use appropriate timeouts
708
+ await session.navigate('https://slow-site.com', {
709
+ waitTimeout: 60000 // Increase timeout for slow sites
710
+ });
711
+
712
+ // Optimize screenshot size for performance
713
+ const thumbnail = await session.screenshot({
714
+ clip: { x: 0, y: 0, width: 400, height: 300 },
715
+ format: 'jpeg',
716
+ quality: 70
717
+ });
718
+ ```
719
+
720
+ ## CommonJS Usage
721
+
722
+ For projects using CommonJS:
723
+
724
+ ```javascript
725
+ const { InstaVM, AuthenticationError } = require('instavm');
726
+
727
+ async function main() {
728
+ const client = new InstaVM('your_api_key');
729
+
730
+ try {
731
+ const result = await client.execute('print("Hello from CommonJS!")');
732
+ console.log(result.output);
733
+ } catch (error) {
734
+ if (error instanceof AuthenticationError) {
735
+ console.error('Authentication failed');
736
+ }
737
+ } finally {
738
+ await client.dispose();
739
+ }
740
+ }
741
+
742
+ main().catch(console.error);
743
+ ```
744
+
745
+ ## Development and Testing
746
+
747
+ ### Running Tests
748
+
749
+ ```bash
750
+ # Install dependencies
751
+ npm install
752
+
753
+ # Run unit tests
754
+ npm test
755
+
756
+ # Run integration tests (requires API key)
757
+ INSTAVM_API_KEY=your_key npm run test:integration
758
+
759
+ # Build the package
760
+ npm run build
761
+
762
+ # Type checking
763
+ npm run type-check
764
+ ```
765
+
766
+ ### Contributing
767
+
768
+ This is an official SDK. For issues and feature requests, please use the GitHub repository.
769
+
770
+ ## Requirements
771
+
772
+ - Node.js 16+
773
+ - TypeScript 5+ (for TypeScript projects)
774
+
775
+ ## License
776
+
777
+ MIT
778
+
779
+ ---
780
+
781
+ ## Changelog
782
+
783
+ ### Version 0.1.0
784
+
785
+ - ✅ Code execution fully functional (Python, Bash)
786
+ - ✅ Browser automation complete (navigation, interaction, extraction)
787
+ - ✅ Comprehensive TypeScript support
788
+ - ✅ Error handling with specific error types
789
+ - ✅ Session management and automatic cleanup
790
+ - ✅ File upload capabilities
791
+ - ✅ Async execution support
792
+ - ✅ Event-driven browser sessions
793
+ - ✅ Modern build system with multiple output formats
794
+
795
+ The JavaScript SDK provides complete feature parity with the Python SDK and is ready for production use.