npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@bunnyshell/sdk

v0.1.13

Published

Official TypeScript/JavaScript SDK for Bunnyshell Sandboxes - 100% feature coverage

Downloads

69

Readme

Bunnyshell JavaScript/TypeScript SDK

npm version TypeScript License: MIT

Official TypeScript/JavaScript SDK for Bunnyshell Sandboxes - Execute code safely in isolated microVM environments.

Features

  • 🚀 47/47 Features - 100% API coverage
  • 🔒 Type Safe - Full TypeScript support with auto-complete
  • Async/Await - Native Promise-based API
  • 🌊 WebSocket Streaming - Real-time code execution, terminal, file watching
  • 🎨 Rich Outputs - Automatic capture of plots, images, DataFrames
  • 🔐 Security First - Environment variables for secrets, execution timeouts
  • 📦 Modern JavaScript - ESM and CommonJS support
  • 🎯 Zero Dependencies - Minimal bundle size

Installation

npm install @bunnyshell/sdk
# or
yarn add @bunnyshell/sdk
# or
pnpm add @bunnyshell/sdk

Quick Start

import { Sandbox } from '@bunnyshell/sdk';

// Create sandbox
const sandbox = await Sandbox.create({
  template: 'code-interpreter',
  apiKey: 'your-api-key'
});

try {
  // Execute code
  const result = await sandbox.runCode(`
import pandas as pd
df = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})
print(df.sum())
  `);
  
  console.log(result.stdout);
  // Output: a    6
  //         b   15
} finally {
  await sandbox.kill();
}

Environment Variables (IMPORTANT!)

✅ ALWAYS pass secrets via environment variables:

// ✅ GOOD: Secrets via environment variables
const result = await sandbox.runCode(`
const apiKey = process.env.OPENAI_API_KEY;
// Use apiKey safely...
`, {
  env: { OPENAI_API_KEY: 'sk-...' }
});

// ❌ BAD: Never hardcode secrets
// const result = await sandbox.runCode('const apiKey = "sk-..."');  // DON'T!

Core Features

Code Execution

// Synchronous execution
const result = await sandbox.runCode("console.log('Hello')");

// With environment variables
const result = await sandbox.runCode(
  "console.log(process.env.MY_VAR)",
  { env: { MY_VAR: 'value' } }
);

// Async execution (non-blocking)
const executionId = await sandbox.runCodeAsync("await sleep(10000)");

// Background execution (fire-and-forget)
const executionId = await sandbox.runCodeBackground("// long task...");

// IPython/Jupyter-style
const result = await sandbox.runIPython("df.describe()");

// Multiple languages
const pythonResult = await sandbox.runCode('print("Python")', { language: 'python' });
const jsResult = await sandbox.runCode('console.log("JS")', { language: 'javascript' });
const bashResult = await sandbox.runCode('echo "Bash"', { language: 'bash' });

Real-time Streaming (WebSocket)

for await (const message of sandbox.runCodeStream(`
import time
for i in range(5):
    print(f"Step {i+1}")
    time.sleep(1)
`)) {
  if (message.type === 'stdout') {
    process.stdout.write(message.data);
  } else if (message.type === 'result') {
    console.log(`Exit code: ${message.exit_code}`);
  }
}

File Operations

// Write file
await sandbox.files.write('/workspace/data.txt', 'Hello, World!');

// Read file
const content = await sandbox.files.read('/workspace/data.txt');

// List directory
const files = await sandbox.files.list('/workspace');
files.forEach(file => {
  console.log(`${file.name} (${file.sizeKb.toFixed(2)}KB)`);
});

// Upload local file
await sandbox.files.upload('./local.txt', '/workspace/remote.txt');

// Download remote file
await sandbox.files.download('/workspace/remote.txt', './local.txt');

// Check existence
if (await sandbox.files.exists('/workspace/data.txt')) {
  console.log('File exists!');
}

// Remove file/directory
await sandbox.files.remove('/workspace/data.txt');

// Create directory
await sandbox.files.mkdir('/workspace/mydir');

// Watch filesystem (WebSocket)
for await (const event of sandbox.files.watch('/workspace')) {
  console.log(`${event.event}: ${event.path}`);
}

Commands

// Run shell command
const result = await sandbox.commands.run('ls -la /workspace');
console.log(result.stdout);

// With environment variables
const result = await sandbox.commands.run(
  'echo "Key: $API_KEY"',
  { env: { API_KEY: 'secret' } }
);

// Custom working directory
const result = await sandbox.commands.run(
  'pwd',
  { workingDir: '/workspace/myproject' }
);

Environment Variables

// Get all
const envVars = await sandbox.env.getAll();

// Set all (replace)
await sandbox.env.setAll({ API_KEY: 'sk-...', DEBUG: 'true' });

// Update (merge)
await sandbox.env.update({ NEW_VAR: 'value' });

// Delete
await sandbox.env.delete(['VAR_TO_DELETE']);

// Get single
const value = await sandbox.env.get('API_KEY');

// Set single
await sandbox.env.set('API_KEY', 'sk-...');

Process Management

// List processes
const processes = await sandbox.listProcesses();
processes.forEach(proc => {
  console.log(`${proc.pid}: ${proc.name} (CPU: ${proc.cpu_percent}%)`);
});

// Kill process
await sandbox.killProcess(1234);

Metrics & Health

// Get metrics
const metrics = await sandbox.getMetricsSnapshot();
console.log(`Total executions: ${metrics.total_executions}`);
console.log(`Uptime: ${metrics.uptime_seconds}s`);

// Health check
const health = await sandbox.getHealth();
console.log(`Status: ${health.status}`);

// Cache management
const cacheStats = await sandbox.cache.stats();
console.log(`Cache size: ${cacheStats.cache.size}`);

await sandbox.cache.clear();

Desktop Automation

// Note: Requires 'desktop' template
const sandbox = await Sandbox.create({ template: 'desktop', apiKey: '...' });

// Mouse operations
await sandbox.desktop.mouseClick({ x: 500, y: 300, button: 'left' });
await sandbox.desktop.mouseMove({ x: 600, y: 400 });
await sandbox.desktop.dragDrop({ fromX: 100, fromY: 100, toX: 300, toY: 300 });

// Keyboard
await sandbox.desktop.keyboardType('Hello, World!');
await sandbox.desktop.keyboardPress('Return');
await sandbox.desktop.keyboardPress('Control_L+c');  // Ctrl+C

// Clipboard
await sandbox.desktop.clipboardSet('text to copy');
const content = await sandbox.desktop.clipboardGet();

// Screenshots
const screenshot = await sandbox.desktop.screenshot();
fs.writeFileSync('screenshot.png', screenshot);

// OCR (text recognition)
const text = await sandbox.desktop.ocr();
console.log(`Found text: ${text}`);

// Find elements
const element = await sandbox.desktop.findElement({ text: 'Button' });
if (element) {
  await sandbox.desktop.mouseClick({ x: element.x, y: element.y });
}

// VNC connection
const vncInfo = await sandbox.desktop.getVncUrl();
console.log(`VNC URL: ${vncInfo.url}`);

Interactive Terminal (WebSocket)

const terminal = await sandbox.terminal.connect();

// Send commands
await sandbox.terminal.sendInput(terminal, 'ls -la\n');

// Receive output
for await (const message of sandbox.terminal.iterOutput(terminal)) {
  if (message.type === 'output') {
    process.stdout.write(message.data);
  }
}

Advanced Configuration

const sandbox = await Sandbox.create({
  template: 'code-interpreter',
  apiKey: 'your-api-key',
  vcpu: 4,              // 4 vCPUs
  memoryMb: 4096,       // 4GB RAM
  diskGb: 20,           // 20GB disk
  region: 'us-west-2',  // Specific region
  timeout: 600,         // 10 minute timeout
  envVars: {            // Pre-set environment variables
    DATABASE_URL: 'postgres://...',
    API_KEY: 'sk-...'
  }
});

Error Handling

import {
  BunnyshellError,
  AuthenticationError,
  NotFoundError,
  FileNotFoundError,
  CodeExecutionError,
  RateLimitError,
  ServerError
} from '@bunnyshell/sdk/errors';

try {
  const sandbox = await Sandbox.create({
    template: 'code-interpreter',
    apiKey: '...'
  });
  
  try {
    const result = await sandbox.runCode("print('Hello')");
  } finally {
    await sandbox.kill();
  }
  
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.log(`Auth failed: ${error.message}`);
    console.log(`Request ID: ${error.requestId}`);
  } else if (error instanceof FileNotFoundError) {
    console.log(`File not found: ${error.path}`);
  } else if (error instanceof CodeExecutionError) {
    console.log(`Code execution failed: ${error.message}`);
  } else if (error instanceof RateLimitError) {
    console.log(`Rate limited: ${error.message}`);
  } else if (error instanceof BunnyshellError) {
    console.log(`API error: ${error.message}`);
    console.log(`Status code: ${error.statusCode}`);
  }
}

Best Practices

1. Always Use Try/Finally

// ✅ GOOD: Guaranteed cleanup
const sandbox = await Sandbox.create({ ... });
try {
  // Work here
} finally {
  await sandbox.kill();  // Always executed
}

// ❌ BAD: May leak if error occurs
const sandbox = await Sandbox.create({ ... });
// ... work ...
await sandbox.kill();  // Might not execute if error!

2. Set Timeouts

// Prevent infinite execution
const result = await sandbox.runCode(code, { timeout: 30 });

3. Optimize Performance

// Set environment variables once
await sandbox.env.setAll({ API_KEY: 'sk-...', DB_URL: '...' });

// Now available in all executions
for (let i = 0; i < 100; i++) {
  await sandbox.runCode('...');  // Env vars already set
}

// Parallel execution
const [r1, r2, r3] = await Promise.all([
  sandbox.runCode('print(1)'),
  sandbox.runCode('print(2)'),
  sandbox.runCode('print(3)')
]);

Use Cases

OpenAI: ChatGPT Code Interpreter

async function executeUserCode(userCode: string) {
  const sandbox = await Sandbox.create({ template: 'code-interpreter' });
  
  try {
    const result = await sandbox.runCode(userCode, { timeout: 30 });
    return {
      output: result.stdout,
      error: result.stderr,
      richOutputs: result.rich_outputs  // Images, plots
    };
  } finally {
    await sandbox.kill();
  }
}

Stripe: Payment Reports

const sandbox = await Sandbox.create({ template: 'code-interpreter' });

try {
  await sandbox.env.set('STRIPE_SECRET_KEY', process.env.STRIPE_SECRET_KEY!);
  
  const result = await sandbox.runCode(`
import stripe
stripe.api_key = os.environ['STRIPE_SECRET_KEY']
charges = stripe.Charge.list(limit=100)
# Generate report...
  `);
} finally {
  await sandbox.kill();
}

TypeScript Support

Full TypeScript support with auto-complete and type checking:

import { Sandbox, ExecutionResult, FileInfo } from '@bunnyshell/sdk';

const sandbox: Sandbox = await Sandbox.create({ ... });
const result: ExecutionResult = await sandbox.runCode('...');
const files: FileInfo[] = await sandbox.files.list('/workspace');

Documentation

License

MIT License - See LICENSE file for details.

Support