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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@voidrun/sdk

v0.0.40

Published

VoidRun AI Sandbox SDK

Downloads

1,080

Readme

VoidRun TypeScript SDK

A powerful, type-safe SDK for interacting with VoidRun AI Sandboxes. Execute code, manage files, watch file changes, and interact with pseudo-terminals in isolated environments.

The public surface is aligned with the VoidRun Python SDK (createSandbox, listSandboxes, remove, runCode, shared defaults).

npm version License: ISC

Table of contents

Features

  • 🏗️ Sandbox Management - Create, list, start, stop, pause, resume, and remove sandboxes
  • 🚀 Code Execution - Execute commands with real-time streaming output capture
  • 📁 File Operations - Create, read, delete, compress, and extract files
  • 👀 File Watching - Monitor file changes in real-time via WebSocket
  • 💻 Pseudo-Terminal (PTY) - Interactive terminal sessions (ephemeral & persistent)
  • 🧠 Code Interpreter - Easy multi-language code execution (Python, JavaScript, Bash)
  • Background Commands - Run, list, kill, and attach to background processes
  • 🔐 Type-Safe - Full TypeScript support with generated types from OpenAPI
  • 🎯 Async/await - Promise-based API throughout

Requirements

  • Node.js 18+ recommended (ESM package; Node 20+ for tsx examples)
  • TypeScript 5.x when compiling from source

Installation

npm install @voidrun/sdk

Or with yarn:

yarn add @voidrun/sdk

Configuration

VoidRun requires an API key. On the hosted platform the base URL defaults to BASE_PATH (see src/api-client/runtime.ts: https://platform.void-run.com/api without a trailing slash). Set VR_API_URL or pass baseUrl only when you target a self-hosted API.

import { VoidRun } from "@voidrun/sdk";

const vr = new VoidRun({
  apiKey: process.env.VR_API_KEY!, // or pass a string literal
});

| Environment variable | Purpose | |--------------------|---------| | VR_API_KEY | API key when not passed to the constructor. | | VR_API_URL | (Self-hosted only.) Overrides the packaged default API base URL. |

createSandbox defaults (when you omit fields) match the Python SDK: image code, 1 CPU, 1024 MB memory.

For self-hosted VoidRun, set VR_API_URL (or baseUrl) to your instance’s API root (including /api if that is how your server is mounted).

Quick start

Basic usage

import { VoidRun } from "@voidrun/sdk";

const vr = new VoidRun({
  apiKey: "your-api-key-here",
});

const sandbox = await vr.createSandbox({});

// Exec returns ExecResponse: stdout/stderr/exitCode live on .data (ExecResponseData)
const result = await sandbox.exec({ command: 'echo "Hello from VoidRun"' });
console.log(result.data?.stdout);

await sandbox.remove();

Core concepts

Sandboxes

An isolated environment where you can execute code, manage files, and run terminals.

// Create a sandbox with options
const sandbox = await vr.createSandbox({
  name: "my-sandbox",       // Optional: Sandbox name
  mem: 1024,                // Memory in MB (optional, has defaults)
  cpu: 1,                   // CPU cores (optional, has defaults)
  image: "code",            // Optional: Image name. Valid values are code, code:1.42.4. Check dashboard for more system images
  envVars: {                // Optional: Environment variables
    DEBUG: 'true',
    LOG_LEVEL: 'info'
  }
});

// List all sandboxes
const { sandboxes, meta } = await vr.listSandboxes();
console.log(`Total sandboxes: ${sandboxes.length}`);

// Get a specific sandbox
const existingSandbox = await vr.getSandbox(sandboxId);

// Sandbox lifecycle management
await sandbox.start();    // Start a stopped sandbox
await sandbox.stop();     // Stop a running sandbox
await sandbox.pause();    // Pause a running sandbox
await sandbox.resume();   // Resume a paused sandbox

// Remove a sandbox
await sandbox.remove();

Code execution

Execute commands and capture output, errors, and exit codes.

Non-streaming exec resolves to an ExecResponse from the OpenAPI client: use result.data for ExecResponseData (stdout, stderr, exitCode).

Synchronous execution

const result = await sandbox.exec({ command: "ls -la /home" });

console.log(result.data?.stdout);   // standard output
console.log(result.data?.stderr);   // standard error
console.log(result.data?.exitCode); // exit code

Streaming execution (SSE)

For real-time output, provide streaming handlers:

await sandbox.exec({
  command: "seq 1 10 | while read i; do echo \"Line $i\"; sleep 1; done"
}, {
  onStdout: (data) => console.log('stdout:', data),
  onStderr: (data) => console.log('stderr:', data),
  onExit: (result) => console.log('exit:', result),
  onError: (error) => console.error('error:', error),
  signal: abortController.signal // Optional: AbortSignal for cancellation
});

Execution with options

const result = await sandbox.exec({
  command: "echo $MY_VAR && pwd",
  cwd: "/tmp",                    // Working directory
  env: { MY_VAR: "test_value" },  // Environment variables
  timeout: 30                      // Timeout in seconds
});

Code interpreter

Execute code in multiple programming languages with a simple, intuitive API.

// Execute Python code
const result = await sandbox.runCode('print(2 + 2)', { language: 'python' });
console.log(result.stdout.trim());  // "4"
console.log(result.success);        // true

// Execute JavaScript code
const jsResult = await sandbox.runCode('console.log("Hello")', { language: 'javascript' });

// Execute with streaming output
const streamResult = await sandbox.runCode(`
  for i in range(5):
      print(f"Iteration {i}")
`, {
  language: 'python',
  onStdout: (data) => console.log(data),
  onStderr: (data) => console.error(data),
});

// Check execution result
console.log(streamResult.exitCode);  // 0 for success
console.log(streamResult.results);   // Parsed results
console.log(streamResult.logs);      // { stdout: [...], stderr: [...] }

Supported Languages: python, javascript, typescript, node, bash, sh

Background commands

Run long-running processes in the background and manage them.

// Start a background process
const runResult = await sandbox.commands.run(
  "sleep 100 && echo 'Done'",  // command
  { DEBUG: 'true' },           // env (optional)
  "/tmp",                      // cwd (optional)
  0                            // timeout (0 = no timeout)
);
console.log(runResult.pid);     // Process ID

// List all running processes
const listResult = await sandbox.commands.list();
console.log(listResult.processes);  // Array of ProcessInfo

// Attach to a process and stream output
await sandbox.commands.connect(runResult.pid, {
  onStdout: (data) => console.log(data),
  onStderr: (data) => console.error(data),
  onExit: ({ exitCode }) => console.log('Process exited:', exitCode),
});

// Wait for a process to complete
const waitResult = await sandbox.commands.wait(runResult.pid);
console.log(waitResult.exitCode);

// Kill a running process
const killResult = await sandbox.commands.kill(runResult.pid);
console.log(killResult.success);

File operations

Create, read, update, and manage files in the sandbox.

// Create a file
await sandbox.fs.createFile("/tmp/hello.txt");

// Upload content to file
await sandbox.fs.uploadFile("/tmp/hello.txt", "Hello, World!");

// Upload via stream
const stream = Readable.from(["line 1\n", "line 2\n"]);
await sandbox.fs.uploadFileStream("/tmp/streamed.txt", Readable.toWeb(stream));

// Read a file
const buffer = await sandbox.fs.downloadFile("/tmp/hello.txt");
const content = buffer.toString();

// Download as stream
const fileStream = await sandbox.fs.downloadFileStream("/tmp/hello.txt");
const reader = fileStream.getReader();
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  console.log(new TextDecoder().decode(value));
}

// Delete a file
await sandbox.fs.deleteFile("/tmp/hello.txt");

// List directory
const result = await sandbox.fs.listFiles("/tmp");
const files = result.data?.files;

// Get file stats
const stats = await sandbox.fs.statFile("/tmp/hello.txt");

// Create directory
await sandbox.fs.createDirectory("/tmp/mydir");

// Move file
await sandbox.fs.moveFile("/tmp/file.txt", "/tmp/newfile.txt");

// Copy file
await sandbox.fs.copyFile("/tmp/file.txt", "/tmp/copy.txt");

// Change permissions
await sandbox.fs.changePermissions("/tmp/file.txt", "755");

// Head/Tail - read first or last lines
const head = await sandbox.fs.headTail("/tmp/file.txt", { head: true, lines: 10 });
const tail = await sandbox.fs.headTail("/tmp/file.txt", { head: false, lines: 10 });

// Search files by pattern
const search = await sandbox.fs.searchFiles("/tmp", "*.txt");

// Get folder size
const size = await sandbox.fs.folderSize("/tmp");

// Compress files
const archive = await sandbox.fs.compressFile("/tmp", "tar.gz");
console.log(archive.archivePath || archive.data?.archivePath);

// Extract archive
await sandbox.fs.extractArchive("/tmp/archive.tar.gz", "/tmp/extracted");

File watching

Monitor file changes in real-time.

const watcher = await sandbox.fs.watch("/app", {
  recursive: true,
  onEvent: (event) => {
    console.log(`File changed: ${event.path} - ${event.type}`);
  },
  onError: (err) => {
    console.error("Watch error:", err);
  },
  onClose: () => {
    console.log("Watcher closed");
  }
});

// Stop watching
watcher.close();

Pseudo-terminal (PTY)

Interactive terminal sessions with two modes:

Ephemeral sessions (temporary)

// No session management - temporary shell
const pty = await sandbox.pty.connect({
  onData: (data) => {
    process.stdout.write(data);
  },
  onError: (err) => {
    console.error("PTY error:", err);
  },
});

// Send commands
pty.sendInput('echo "Hello"\n');
pty.sendInput("pwd\n");

// Close connection
pty.close();

Persistent sessions

// Create a persistent session (CreatePTYSession200Response)
const response = await sandbox.pty.createSession();
const sessionId = response.data?.sessionId;

// Connect to the session
const pty = await sandbox.pty.connect({
  sessionId,
  onData: (data) => {
    process.stdout.write(data);
  },
});

// Send commands
pty.sendInput('echo "Hello"\n');

// Close connection (session persists)
pty.close();

// Reconnect later - session and output persist
const reconnected = await sandbox.pty.connect({
  sessionId,
  onData: (data) => {
    process.stdout.write(data); // Includes buffered output
  },
});

Interactive commands

Run commands with automatic prompt detection:

const pty = await sandbox.pty.connect({ sessionId });

const output = await pty.runCommand("ls -la", {
  timeout: 5000,
  prompt: /[#$] $/, // Regex to detect shell prompt
});

console.log("Output:", output);

Resize terminal

pty.resize(80, 24); // columns, rows

Session management

// List all sessions
const sessions = await sandbox.pty.list();

// Delete a session
await sandbox.pty.deleteSession(sessionId);

API reference

VoidRun class

Main client for interacting with the API.

new VoidRun(options?: VoidRunConfig)

Options:

  • apiKey?: string - API key (defaults to process.env.VR_API_KEY; empty throws)

Methods:

  • createSandbox(options: SandboxOptions) - Create a new sandbox
    • name?: string - Sandbox name
    • image?: string - Image id (defaults to code when omitted)
    • cpu?: number - CPU cores (default 1)
    • mem?: number - Memory in MB (default 1024)
    • orgId?: string - Organization ID
    • userId?: string - User ID
    • sync?: boolean - Sync mode (default: true)
    • envVars?: Record<string, string> - Environment variables
    • autoSleep?: boolean, region?: string, refId?: string - optional passthrough fields
  • listSandboxes(options?: { page?: number; limit?: number }) - Returns { sandboxes, meta } where meta has total, page, limit, totalPages
  • getSandbox(id: string) - Get a specific sandbox
  • removeSandbox(id: string) - Delete a sandbox by id

Sandbox class

Represents an isolated sandbox environment.

Properties:

  • id: string - Sandbox ID
  • name: string - Sandbox name
  • cpu: number - CPU cores
  • mem: number - Memory in MB
  • orgId: string - Organization ID
  • createdAt: Date - Creation timestamp
  • createdBy: string - Creator ID
  • status: string - Sandbox status
  • envVars?: { [key: string]: string } - Environment variables
  • region?: string, refId?: string, autoSleep?: boolean - Optional metadata
  • fs: FS - File system interface
  • pty: PTY - PTY interface
  • interpreter: CodeInterpreter - Code interpreter
  • commands: Commands - Background commands interface

Methods:

  • exec(request: ExecRequest, handlers?: ExecStreamHandlers) - Execute a command
    • request.command: string - Command to execute
    • request.cwd?: string - Working directory
    • request.env?: Record<string, string> - Environment variables
    • request.timeout?: number - Timeout in seconds
    • handlers.onStdout?: (data: string) => void - Stream stdout
    • handlers.onStderr?: (data: string) => void - Stream stderr
    • handlers.onExit?: (result: ExecStreamExit) => void - Exit handler
    • handlers.onError?: (error: Error) => void - Error handler
    • handlers.signal?: AbortSignal - Abort signal
  • execStream(request: ExecRequest, handlers: ExecStreamHandlers) - Streaming execution
  • runCode(code: string, options?: CodeExecutionOptions) - Execute code
  • start() - Start the sandbox
  • stop() - Stop the sandbox
  • pause() - Pause the sandbox
  • resume() - Resume the sandbox
  • remove() - Delete the sandbox
  • info() - Returns the same sandbox instance (Promise<this>)

Exec response (ExecResponse):

// Returned from non-streaming exec()
{
  status?: string;
  message?: string;
  data?: {
    stdout?: string;
    stderr?: string;
    exitCode?: number;
  };
}

Code Execution Result:

{
  success: boolean;
  results: any;           // Parsed results
  stdout: string;         // Combined stdout
  stderr: string;         // Combined stderr
  error?: string;         // Error message if any
  exitCode?: number;      // Process exit code
  logs: {
    stdout: string[];     // Individual stdout lines
    stderr: string[];     // Individual stderr lines
  };
}

Commands class

Background process management.

Methods:

  • run(command: string, env?: Record<string, string>, cwd?: string, timeout?: number) - Start a background process
  • list() - List all running processes
  • kill(pid: number) - Kill a process
  • connect(pid: number, handlers: ProcessAttachHandlers) - Attach to process output stream
  • wait(pid: number) - Wait for process to complete

FS (file system) class

Manage files and directories.

Methods:

  • createFile(path: string) - Create a file
  • uploadFile(path: string, content: string) - Upload file content
  • uploadFileStream(path: string, stream: ReadableStream) - Upload file as stream
  • downloadFile(path: string) - Download file as Buffer
  • downloadFileStream(path: string) - Download file as ReadableStream
  • deleteFile(path: string) - Delete a file/directory
  • listFiles(path: string) - List directory contents
  • statFile(path: string) - Get file metadata
  • createDirectory(path: string) - Create a directory
  • compressFile(path: string, format: 'tar' | 'tar.gz' | 'tar.bz2' | 'zip') - Create archive
  • extractArchive(archivePath: string, destPath?: string) - Extract archive
  • moveFile(from: string, to: string) - Move/rename file
  • copyFile(from: string, to: string) - Copy file
  • changePermissions(path: string, mode: string) - Change file permissions
  • headTail(path: string, options?: { lines?: number; head?: boolean }) - Read file head/tail
  • searchFiles(path: string, pattern: string) - Search files by pattern
  • folderSize(path: string) - Get folder size
  • watch(path: string, options: FileWatchOptions) - Watch for file changes

FileWatcher

Monitor file changes in real-time.

Methods:

  • watch(path: string, options: FileWatchOptions) - Start watching a path
    • recursive?: boolean - Watch subdirectories
    • onEvent(event: FileChangeEvent) - Called on file change
    • onError(error: Error) - Called on error
    • onClose() - Called when watcher closes (optional)

Watcher Methods:

  • close() - Stop watching

PTY class

Pseudo-terminal operations.

Methods:

  • list() - List active sessions
  • createSession() - Create a persistent session
  • connect(options: PtyOptions) - Connect to PTY
    • sessionId?: string - For persistent sessions
    • onData(data: string) - Receive data
    • onError(error: Error) - Handle errors
    • onClose() - Connection closed (optional)
  • deleteSession(sessionId: string) - Delete a session

PtySession Methods:

  • sendInput(data: string) - Send data to terminal
  • runCommand(cmd: string, options: RunCommandOptions) - Execute with prompt detection
  • resize(cols: number, rows: number) - Resize terminal
  • close() - Close connection

Examples

Execute Python Script

import { VoidRun } from "@voidrun/sdk";

const vr = new VoidRun({});
const sandbox = await vr.createSandbox({ mem: 1024, cpu: 1 });

// Create Python script
await sandbox.fs.createFile("/tmp/script.py");
await sandbox.fs.uploadFile(
  "/tmp/script.py",
  `
import sys
print("Python version:", sys.version)
print("Hello from Python!")
`,
);

const result = await sandbox.exec({ command: "python3 /tmp/script.py" });
console.log(result.data?.stdout);

await sandbox.remove();

Code Interpreter Workflow

const sandbox = await vr.createSandbox({ name: 'interpreter-demo' });

// Python data analysis
const result = await sandbox.runCode(`
import json
data = [1, 2, 3, 4, 5]
result = {
    "sum": sum(data),
    "avg": sum(data) / len(data),
    "max": max(data)
}
print(json.dumps(result))
`, { language: 'python' });

console.log(result.results);  // Parsed JSON output

// JavaScript
const jsResult = await sandbox.runCode(`
const fib = (n) => n <= 1 ? n : fib(n-1) + fib(n-2);
console.log(fib(10));
`, { language: 'javascript' });

await sandbox.remove();

Background Process Management

const sandbox = await vr.createSandbox({});

// Start a long-running process
const { pid } = await sandbox.commands.run("tail -f /var/log/syslog");

// Attach to stream output
await sandbox.commands.connect(pid, {
  onStdout: (data) => console.log(data),
  onExit: ({ exitCode }) => console.log('Exited:', exitCode),
});

// Later, kill the process
await sandbox.commands.kill(pid);

await sandbox.remove();

Monitor Code Changes

const sandbox = await vr.createSandbox({ mem: 1024, cpu: 1 });

// Watch for TypeScript file changes
const watcher = await sandbox.fs.watch("/app/src", {
  recursive: true,
  onEvent: async (event) => {
    console.log(`File ${event.type}: ${event.path}`);

    // Auto-compile on change
    await sandbox.exec({ command: "npm run build" });
  },
});

// Clean up
setTimeout(() => watcher.close(), 60000);

Build & Test Workflow

const sandbox = await vr.createSandbox({ mem: 2048, cpu: 2 });

// Upload source code
const sourceCode = `console.log('Hello World');`;
await sandbox.fs.createFile("/app/main.js");
await sandbox.fs.uploadFile("/app/main.js", sourceCode);

// Install dependencies
let result = await sandbox.exec({ command: "npm install" });
if (result.data?.exitCode !== 0) throw new Error("Install failed");

// Run tests
result = await sandbox.exec({ command: "npm test" });
console.log("Test output:", result.data?.stdout);

// Build
result = await sandbox.exec({ command: "npm run build" });
console.log("Build output:", result.data?.stdout);

await sandbox.remove();

Interactive Development Shell

const sandbox = await vr.createSandbox({ mem: 1024, cpu: 1 });

// Create a persistent session
const sessionResp = await sandbox.pty.createSession();
const sessionId = sessionResp.data?.sessionId;

const pty = await sandbox.pty.connect({
  sessionId,
  onData: (data) => process.stdout.write(data),
  onClose: () => console.log("Shell closed"),
});

// Interactive commands
pty.sendInput("npm init -y\n");
await new Promise((r) => setTimeout(r, 1000));

pty.sendInput("npm install express\n");
await new Promise((r) => setTimeout(r, 2000));

pty.sendInput('node -e "console.log(process.version)"\n');
await new Promise((r) => setTimeout(r, 500));

pty.close();
await sandbox.remove();

Error handling

Failed HTTP calls from the generated client are thrown as an Error whose message combines status text with the API body when JSON parsing succeeds: fields error, details, and message are concatenated so you see the same hints as in the Python SDK.

try {
  const sandbox = await vr.createSandbox({ mem: 1024, cpu: 1 });
  // ...
} catch (error) {
  if (error instanceof Error) {
    console.error("Error:", error.message);
  }
}

Common cases:

  • Validation: Invalid sandbox parameters for your org/plan
  • Authentication: Missing/invalid API key
  • Not found: Wrong sandbox or session id
  • Timeout: Network or long-running command limits

Testing and examples runner

From the ts-sdk directory:

npm install
chmod +x scripts/run_all_examples.sh   # once
./scripts/run_all_examples.sh

Each example is run with npx tsx --env-file=.env <file>. Create a .env with at least VR_API_KEY= (add VR_API_URL= only for self-hosted). The script exits with status 1 if any example fails (suitable for CI).

Run a single script:

npx tsx --env-file=.env example/test-sandbox-exec.ts

Notable scripts under example/:

  • test-sandbox-exec.ts: Command execution (incl. streaming)
  • test-sandbox-fs.ts: File system operations
  • test-sandbox-lifecycle.ts: Sandbox lifecycle
  • test-pty.ts / test-pty-comprehensive.ts: PTY
  • test-watch.ts: File watching
  • test-background-exec.ts: Background commands
  • test-ts-exec.ts: TypeScript via runCode
  • code-interpreter-example.ts: Interpreter workflow
  • test-commonjs-import.cjs / test-esm-import.mjs: Package exports

Building from source

# Install dependencies
npm install

# Build TypeScript
npm run build

# Clean build artifacts
npm run clean

Publishing

npm run build
npm publish --access public

(prepublishOnly in package.json runs a clean build and bumps the patch version: adjust your release workflow if you do not want an automatic version bump.)

Troubleshooting

"API key is required"

Pass the key in the constructor or set VR_API_KEY:

const vr = new VoidRun({ apiKey: "your-api-key" });
export VR_API_KEY="your-api-key"

"Base URL is required"

The resolved base URL is empty (for example VR_API_URL= with no value). Omit it to use the default host, or set VR_API_URL / baseUrl to your self-hosted API root.

"Sandbox creation failed"

Ensure your sandbox parameters are valid:

  • mem: minimum 1024 MB
  • cpu: minimum 1 core
const sandbox = await vr.createSandbox({
  mem: 1024, // At least 1GB
  cpu: 1,    // At least 1 core
});

"PTY Connection Timeout"

Increase timeout for slow systems:

const pty = await sandbox.pty.connect({
  sessionId,
  onData: (data) => console.log(data),
});

// For runCommand
const output = await pty.runCommand("slow-command", {
  timeout: 30000, // 30 seconds
});

"File Not Found"

Check the file path:

// List files to verify path
const files = await sandbox.fs.listFiles("/app");
console.log(files.data?.files);

// Then access specific file
const content = await sandbox.fs.downloadFile("/app/file.txt");

API Documentation

Full API documentation is available at:

Contributing

Contributions are welcome! Please check the main repository for guidelines.

License

ISC License - See LICENSE file for details

Support


Made with ❤️ by VoidRun