instavm
v0.8.3
Published
Official JavaScript SDK for InstaVM API
Maintainers
Readme
InstaVM JavaScript SDK
A comprehensive JavaScript/TypeScript client library for InstaVM's code execution and browser automation APIs.
Features
- Code Execution: Run Python, Bash, and other languages in secure cloud environments
- Browser Automation: Control web browsers for testing, scraping, and automation
- Session Management: Automatic session creation and persistent execution contexts
- File Operations: Upload files to execution environments
- Async Support: Execute commands asynchronously for long-running tasks
- Error Handling: Comprehensive exception hierarchy for different failure modes
- TypeScript Support: Full type safety with comprehensive TypeScript definitions
- Modern JavaScript: ES modules, CommonJS, and UMD support
Installation
npm install instavmQuick Start
Code Execution (Cloud Mode)
import { InstaVM, ExecutionError, NetworkError } from 'instavm';
// Create client with automatic session management
const client = new InstaVM('your_api_key');
try {
// Execute a command
const result = await client.execute("print(100**100)");
console.log(result);
// Get usage info for the session
const usage = await client.getUsage();
console.log(usage);
} catch (error) {
if (error instanceof ExecutionError) {
console.log(`Code execution failed: ${error.message}`);
} else if (error instanceof NetworkError) {
console.log(`Network issue: ${error.message}`);
}
} finally {
await client.dispose();
}Local Execution Mode
Run code execution against a local container (e.g., coderunner) instead of the cloud API:
import { InstaVM } from 'instavm';
// Create client in local mode (no API key required)
const client = new InstaVM('', {
local: true,
localURL: 'http://coderunner.local:8222' // Optional, defaults to this URL
});
// Execute code locally without session management
const result = await client.execute("print('Hello from local container!')");
console.log(result.stdout);
// Browser automation in local mode (no session required)
const content = await client.browser.extractContent({
url: 'https://example.com',
includeInteractive: true,
includeAnchors: true
});
console.log('Page title:', content.readableContent.title);
console.log('Clean content:', content.readableContent.content);Note: Local mode supports:
- ✅ Code execution (
execute()) - ✅ Browser navigation (
browser.navigate()) - ✅ Content extraction (
browser.extractContent())
Local mode does NOT support (cloud-only features):
- ❌ Session management (
createSession(),closeSession(),getUsage()) - ❌ File upload/download
- ❌ Async execution
- ❌ Browser session creation and complex interactions
File Upload
import { InstaVM } from 'instavm';
const client = new InstaVM('your_api_key');
// Create a session first (required for upload)
await client.createSession();
// Upload files to the execution environment
const files = [
{
name: 'script.py',
content: 'print("Hello from uploaded file!")',
path: '/remote/path/script.py'
}
];
const result = await client.upload(files);
console.log(result);
// Execute the uploaded file
const execution = await client.execute('python /remote/path/script.py', {
language: 'bash'
});
console.log(execution.stdout);File Download
import { InstaVM } from 'instavm';
import fs from 'fs';
const client = new InstaVM('your_api_key');
// Create a file in the remote environment
await client.execute(`
import pandas as pd
df = pd.DataFrame({'name': ['Alice', 'Bob'], 'age': [25, 30]})
df.to_csv('data.csv', index=False)
`);
// Download the file
const result = await client.download('data.csv');
console.log(`Downloaded ${result.size} bytes`);
// Save to local file
fs.writeFileSync('local-data.csv', result.content);Error Handling
import {
InstaVM,
AuthenticationError,
RateLimitError,
SessionError,
QuotaExceededError
} from 'instavm';
try {
const client = new InstaVM('invalid_key');
await client.execute('print("test")');
} catch (error) {
if (error instanceof AuthenticationError) {
console.log("Invalid API key");
} else if (error instanceof RateLimitError) {
console.log(`Rate limit exceeded - retry after ${error.retryAfter} seconds`);
} else if (error instanceof QuotaExceededError) {
console.log("Usage quota exceeded");
} else if (error instanceof SessionError) {
console.log(`Session error: ${error.message}`);
}
}Async Execution
import { InstaVM } from 'instavm';
const client = new InstaVM('your_api_key');
// Execute command asynchronously (returns task ID)
const result = await client.executeAsync("sleep 5 && echo 'Long task complete!'", {
language: 'bash'
});
const taskId = result.taskId;
console.log(`Task ${taskId} is running in background...`);
// Poll for task result
const taskResult = await client.getTaskResult(taskId, 2, 30);
console.log('Task complete!');
console.log(`Stdout: ${taskResult.stdout}`);
console.log(`Stderr: ${taskResult.stderr}`);Browser Automation
Basic Browser Usage
import { InstaVM } from 'instavm';
const client = new InstaVM('your_api_key');
// Create browser session
const session = await client.browser.createSession({
viewportWidth: 1920,
viewportHeight: 1080
});
// Navigate to website
await session.navigate('https://example.com');
// Take screenshot
const screenshot = await session.screenshot();
console.log(`Screenshot captured: ${screenshot.length} chars`);
// Extract page data
const elements = await session.extractElements('h1, p', ['text', 'href']);
console.log('Page content:', elements);
// Clean up
await session.close();Advanced Browser Interactions
// Navigate with options
await session.navigate('https://github.com/login', {
waitTimeout: 30000,
waitUntil: 'networkidle'
});
// Fill login form
await session.fill('input[name="login"]', 'username');
await session.fill('input[name="password"]', 'password');
// Click submit button
await session.click('input[type="submit"]');
// Wait for navigation
await session.wait({ type: 'navigation' });
// Scroll to load more content
await session.scroll({ y: 1000 });
// Extract dynamic content
const repos = await session.extractElements('.repo-list-item', ['text']);
console.log('Repositories found:', repos.length);Browser Session Management
// Create session with custom options
const session = await client.browser.createSession({
viewportWidth: 1280,
viewportHeight: 720,
userAgent: 'CustomBot/1.0'
});
// Session supports event listeners
session.on('navigation', (result) => {
console.log(`Navigated to: ${result.url}`);
console.log(`Page title: ${result.title}`);
});
session.on('error', (error) => {
console.error('Session error:', error.message);
});
session.on('close', () => {
console.log('Session closed');
});
// Check if session is still active
if (session.isActive) {
await session.navigate('https://example.com');
}Context Manager Pattern
// Use browser session with automatic cleanup
const client = new InstaVM('your_api_key');
async function automateWebsite() {
const session = await client.browser.createSession();
try {
await session.navigate('https://httpbin.org/forms/post');
// Fill and submit form
await session.fill('input[name="custname"]', 'John Doe');
await session.fill('input[name="custtel"]', '555-1234');
await session.click('input[type="submit"]');
// Wait for result
await session.wait({ type: 'visible', selector: 'pre' });
// Extract result
const result = await session.extractElements('pre', ['text']);
return result[0]?.text;
} finally {
await session.close();
}
}
const result = await automateWebsite();
console.log('Form submission result:', result);Mixed Code + Browser Automation
Combine code execution with browser automation for powerful workflows:
import { InstaVM } from 'instavm';
const client = new InstaVM('your_api_key');
// Execute Python code to prepare data
const dataPrep = await client.execute(`
import json
import pandas as pd
# Prepare search terms
search_terms = ["AI", "Machine Learning", "JavaScript"]
data = {"terms": search_terms, "timestamp": "2024-01-01"}
print(json.dumps(data))
`);
const searchData = JSON.parse(dataPrep.stdout.trim());
// Use browser to search and collect results
const session = await client.browser.createSession();
const results = [];
for (const term of searchData.terms) {
await session.navigate(`https://news.ycombinator.com/search?q=${encodeURIComponent(term)}`);
const headlines = await session.extractElements('.titleline > a', ['text', 'href']);
results.push({
term,
headlines: headlines.slice(0, 5) // Top 5 results
});
}
await session.close();
// Process results with Python
const analysis = await client.execute(`
import json
data = ${JSON.stringify(results)}
# Analyze results
total_headlines = sum(len(item['headlines']) for item in data)
print(f"Collected {total_headlines} headlines across {len(data)} search terms")
# Find most common words
all_text = ' '.join([headline['text'] for item in data for headline in item['headlines']])
words = all_text.lower().split()
word_counts = {}
for word in words:
if len(word) > 3: # Filter short words
word_counts[word] = word_counts.get(word, 0) + 1
# Top 10 words
top_words = sorted(word_counts.items(), key=lambda x: x[1], reverse=True)[:10]
print("Top words:", top_words)
`);
console.log(analysis.stdout);
await client.dispose();Language Support
Python Code Execution
// Python with libraries
const result = await client.execute(`
import pandas as pd
import numpy as np
# Create sample data
data = pd.DataFrame({
'numbers': np.random.randn(100),
'categories': np.random.choice(['A', 'B', 'C'], 100)
})
# Basic statistics
print(f"Mean: {data['numbers'].mean():.2f}")
print(f"Std: {data['numbers'].std():.2f}")
print(f"Categories: {data['categories'].value_counts().to_dict()}")
`);
console.log(result.stdout);Bash Commands
// System operations
const sysInfo = await client.execute(`
echo "System Information:"
echo "==================="
uname -a
echo
echo "Disk Usage:"
df -h
echo
echo "Memory Info:"
free -h
`, { language: 'bash' });
console.log(sysInfo.stdout);Session Persistence
// Variables persist across executions within the same session
await client.execute('data = [1, 2, 3, 4, 5]');
await client.execute('total = sum(data)');
const result = await client.execute('print(f"Total: {total}, Average: {total/len(data)}")');
console.log(result.stdout); // Output: Total: 15, Average: 3.0Session Status Check
// Check if current session is still active
const isActive = await client.isSessionActive();
console.log(`Session active: ${isActive}`);
// Check specific session
const isOtherActive = await client.isSessionActive('session-id-123');
console.log(`Other session active: ${isOtherActive}`);Advanced Features
Wait Conditions
// Wait for element to appear
await session.wait({
type: 'visible',
selector: '.loading-complete',
timeout: 30000
});
// Wait for element to disappear
await session.wait({
type: 'hidden',
selector: '.spinner'
});
// Wait for page load
await session.wait({
type: 'networkidle'
});
// Simple timeout
await session.wait({
type: 'timeout',
ms: 5000
});Screenshot Options
// Full page screenshot
const fullPage = await session.screenshot({
fullPage: true,
format: 'png'
});
// Clip specific area
const clipped = await session.screenshot({
clip: {
x: 0,
y: 0,
width: 800,
height: 600
},
format: 'jpeg',
quality: 90
});
// Screenshots return base64 encoded strings
const buffer = Buffer.from(fullPage, 'base64');
// Save to file if neededElement Extraction
// Extract multiple attributes
const links = await session.extractElements('a', ['href', 'text', 'title']);
// Extract with CSS selectors
const articles = await session.extractElements('article h2, .post-title', ['text']);
// Extract form data
const formData = await session.extractElements('input, select, textarea', [
'name', 'value', 'type', 'placeholder'
]);
console.log('Links found:', links);
console.log('Articles:', articles);
console.log('Form fields:', formData);LLM-Friendly Content Extraction
// Extract clean, LLM-optimized content from a webpage
const content = await session.extractContent({
includeInteractive: true, // Include clickable/typeable elements
includeAnchors: true, // Include content-to-selector mappings
maxAnchors: 50 // Limit number of anchors
});
// Get clean article text (no ads, no navigation, no scripts)
console.log('Title:', content.readableContent.title);
console.log('Article:', content.readableContent.content);
console.log('Author:', content.readableContent.byline);
// Find interactive elements (buttons, links, inputs)
const loginButton = content.interactiveElements?.find(
el => el.text?.toLowerCase().includes('login')
);
if (loginButton) {
await session.click(loginButton.selector);
}
// Use content anchors to map text to selectors
// Perfect for LLM agents that need to "read then click"
const signupLink = content.contentAnchors?.find(
anchor => anchor.text.toLowerCase().includes('sign up')
);
if (signupLink) {
await session.click(signupLink.selector);
}Error Handling Reference
Error Types
import {
InstaVMError, // Base error class
AuthenticationError, // API key issues
RateLimitError, // Rate limiting (has retryAfter property)
QuotaExceededError, // Usage quota exceeded
NetworkError, // Connection issues
ExecutionError, // Code execution failures
SessionError, // Session management issues
BrowserError, // General browser errors
BrowserSessionError, // Browser session issues
BrowserInteractionError, // Browser interaction failures
BrowserTimeoutError, // Browser operation timeouts
BrowserNavigationError, // Navigation failures
ElementNotFoundError, // Element selection issues (has selector property)
UnsupportedOperationError // Operation not supported in local mode
} from 'instavm';
// Specific error handling
try {
await session.click('.non-existent-button');
} catch (error) {
if (error instanceof ElementNotFoundError) {
console.log(`Element not found: ${error.selector}`);
} else if (error instanceof BrowserTimeoutError) {
console.log('Operation timed out');
}
}Retry Logic
The SDK includes automatic retry logic for:
- Network errors (connection issues)
- Rate limiting (with exponential backoff)
- Server errors (5xx status codes)
// Customize retry behavior
const client = new InstaVM('your_api_key', {
maxRetries: 5,
retryDelay: 2000, // Base delay in milliseconds
timeout: 300000 // 5 minute timeout
});API Reference
InstaVM Client
class InstaVM {
constructor(apiKey: string, options?: InstaVMOptions)
// Code execution
execute(command: string, options?: ExecuteOptions): Promise<ExecutionResult>
executeAsync(command: string, options?: ExecuteOptions): Promise<AsyncExecutionResult>
getTaskResult(taskId: string, pollInterval?: number, timeout?: number): Promise<TaskResult>
// File operations
upload(files: FileUpload[], options?: UploadOptions): Promise<UploadResult>
download(filename: string, options?: DownloadOptions): Promise<DownloadResult>
// Session management
createSession(): Promise<string>
closeSession(sessionId?: string): Promise<void>
isSessionActive(sessionId?: string): Promise<boolean>
getUsage(sessionId?: string): Promise<UsageStats>
// Browser automation
browser: BrowserManager
// Properties
readonly sessionId: string | null
// Cleanup
dispose(): Promise<void>
}Configuration Options
interface InstaVMOptions {
baseURL?: string; // Default: 'https://api.instavm.io' (ignored if local=true)
timeout?: number; // Default: 300000 (5 minutes)
maxRetries?: number; // Default: 3
retryDelay?: number; // Default: 1000ms
local?: boolean; // Default: false - Use local container instead of cloud
localURL?: string; // Default: 'http://coderunner.local:8222' - Local container URL
}
interface ExecuteOptions {
language?: 'python' | 'bash'; // Default: 'python'
timeout?: number; // Default: 15 seconds
sessionId?: string; // Use specific session
}Browser Manager
class BrowserManager {
createSession(options?: BrowserSessionOptions): Promise<BrowserSession>
listSessions(): Promise<BrowserSessionInfo[]>
getSession(sessionId: string): Promise<BrowserSessionInfo>
getLocalSession(sessionId: string): BrowserSession | undefined
getLocalSessions(): BrowserSession[]
closeAllSessions(): Promise<void>
dispose(): Promise<void>
}
interface BrowserSessionOptions {
viewportWidth?: number; // Default: 1920
viewportHeight?: number; // Default: 1080
userAgent?: string; // Custom user agent
}Browser Session
class BrowserSession extends EventEmitter {
// Navigation
navigate(url: string, options?: NavigateOptions): Promise<NavigationResult>
// Interaction
click(selector: string, options?: ClickOptions): Promise<void>
type(selector: string, text: string, options?: TypeOptions): Promise<void>
fill(selector: string, value: string, options?: FillOptions): Promise<void>
scroll(options?: ScrollOptions): Promise<void>
// Data extraction
screenshot(options?: ScreenshotOptions): Promise<string>
extractElements(selector: string, attributes?: string[]): Promise<ExtractedElement[]>
extractContent(options?: ExtractContentOptions): Promise<ExtractedContent>
// Utilities
wait(condition: WaitCondition, timeout?: number): Promise<void>
close(): Promise<void>
// Properties
readonly sessionId: string
readonly isActive: boolean
// Events: 'navigation', 'error', 'close'
}Type Definitions
interface ExecutionResult {
stdout: string;
stderr: string;
success: boolean;
executionTime?: number;
cpuTime?: number;
createdAt?: string;
sessionId?: string;
error?: string;
}
interface TaskResult {
stdout: string;
stderr: string;
executionTime?: number;
cpuTime?: number;
createdAt?: string;
}
interface NavigationResult {
success: boolean;
url: string;
title?: string;
status?: number;
}
interface ExtractedElement {
text?: string;
href?: string;
[attribute: string]: string | undefined;
}
type WaitCondition =
| { type: 'timeout'; ms: number }
| { type: 'visible'; selector: string }
| { type: 'hidden'; selector: string }
| { type: 'navigation' }
| { type: 'networkidle' };Best Practices
Resource Management
// Always dispose of the client when done
const client = new InstaVM('your_api_key');
try {
// Your automation code
} finally {
await client.dispose(); // Closes all sessions and cleans up
}
// Or use a wrapper function
async function withInstaVM(apiKey: string, callback: (client: InstaVM) => Promise<void>) {
const client = new InstaVM(apiKey);
try {
await callback(client);
} finally {
await client.dispose();
}
}
await withInstaVM('your_api_key', async (client) => {
const result = await client.execute('print("Hello, World!")');
console.log(result.stdout);
});Error Handling Strategy
// Implement comprehensive error handling
async function robustAutomation(client: InstaVM) {
let session: BrowserSession | null = null;
try {
session = await client.browser.createSession();
// Retry navigation with timeout
let retries = 3;
while (retries > 0) {
try {
await session.navigate('https://example.com');
break;
} catch (error) {
if (error instanceof BrowserTimeoutError && retries > 1) {
console.log(`Navigation timeout, retrying... (${retries - 1} attempts left)`);
retries--;
await new Promise(resolve => setTimeout(resolve, 2000));
} else {
throw error;
}
}
}
// Safe element interaction
try {
await session.click('button.submit');
} catch (error) {
if (error instanceof ElementNotFoundError) {
console.log('Submit button not found, trying alternative selector');
await session.click('input[type="submit"]');
} else {
throw error;
}
}
} catch (error) {
console.error('Automation failed:', error.message);
throw error;
} finally {
if (session) {
await session.close();
}
}
}Performance Optimization
// Batch operations when possible
const session = await client.browser.createSession();
// Instead of multiple separate calls
await session.navigate('https://example.com');
const title = await session.extractElements('title', ['text']);
const links = await session.extractElements('a', ['href']);
const images = await session.extractElements('img', ['src', 'alt']);
// Consider using a single extraction call for related elements
const pageData = await session.extractElements('title, a, img', ['text', 'href', 'src', 'alt']);
// Use appropriate timeouts
await session.navigate('https://slow-site.com', {
waitTimeout: 60000 // Increase timeout for slow sites
});
// Optimize screenshot size for performance
const thumbnail = await session.screenshot({
clip: { x: 0, y: 0, width: 400, height: 300 },
format: 'jpeg',
quality: 70
});CommonJS Usage
For projects using CommonJS:
const { InstaVM, AuthenticationError } = require('instavm');
async function main() {
const client = new InstaVM('your_api_key');
try {
const result = await client.execute('print("Hello from CommonJS!")');
console.log(result.stdout);
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Authentication failed');
}
} finally {
await client.dispose();
}
}
main().catch(console.error);Development and Testing
Running Tests
# Install dependencies
npm install
# Run unit tests (no API key required)
npm run test:unit
# Run integration tests (requires API key)
INSTAVM_API_KEY=your_api_key npm run test:integration
# Run all tests
npm test
# Build the package
npm run build
# Type checking
npm run type-checkNote: Integration tests require a valid InstaVM API key. Set the INSTAVM_API_KEY environment variable before running integration tests. Unit tests do not require an API key.
Contributing
This is an official SDK. For issues and feature requests, please use the GitHub repository.
Requirements
- Node.js 16+
- TypeScript 5+ (for TypeScript projects)
License
Proprietary. This SDK is provided for use with InstaVM services only.
All rights reserved. No redistribution or modification permitted.
Changelog
Version 0.8.3
- ✅ NEW:
getTaskResult()method - Poll for async task completion with configurable intervals - ✅ NEW:
isSessionActive()method - Check if session is still active by querying VM status - ✅ IMPROVED: Execution result format - Now returns
stdoutandstderrseparately (matching Python SDK) - ✅ IMPROVED: Enhanced execution results - Added
cpuTime,executionTime, andcreatedAtfields - ✅ IMPROVED: Better error messages - Rate limit errors now show
detailfield from API response - ✅ FIXED: Session status check - Now uses
/v1/sessions/status/endpoint for accurate VM status - ✅ UPDATED: closeSession behavior - Sessions auto-expire on server, no longer makes DELETE API call
- ✅ Full parity with Python SDK v0.8.3
Version 0.4.0
- ✅ NEW: Local execution mode support - Run code execution against local containers
- ✅ NEW: Local browser automation - Navigate and extract content without sessions
- ✅ NEW:
UnsupportedOperationError- Better error messages for cloud-only features - ✅ Parity with Python SDK v0.4.0 local mode features
- ✅ Improved flexibility for on-premise deployments
Version 0.3.0
- ✅ NEW: File download functionality - Download files from remote VM
- ✅ NEW: LLM-friendly content extraction - Extract clean, readable content with interactive element mapping
- ✅ Enhanced browser automation with content anchors for intelligent LLM agents
- ✅ Full API parity with Python SDK
Version 0.2.1
- ✅ Bug fixes and improvements
Version 0.2.0
- ✅ Enhanced session management
- ✅ Improved error handling
Version 0.1.0
- ✅ Code execution fully functional (Python, Bash)
- ✅ Browser automation complete (navigation, interaction, extraction)
- ✅ Comprehensive TypeScript support
- ✅ Error handling with specific error types
- ✅ Session management and automatic cleanup
- ✅ File upload capabilities
- ✅ Async execution support
- ✅ Event-driven browser sessions
- ✅ Modern build system with multiple output formats
The JavaScript SDK provides complete feature parity with the Python SDK and is ready for production use.
