{"_id":"@aistack/sandbox","name":"@aistack/sandbox","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@aistack/sandbox","version":"1.0.0","description":"Drop-in replacement for @vercel/sandbox - run AI sandboxes on your own infrastructure","author":{"name":"AIStack"},"license":"MIT","homepage":"https://github.com/aistackhq/sandbox#readme","repository":{"type":"git","url":"git+https://github.com/aistackhq/sandbox.git","directory":"packages/sdk"},"bugs":{"url":"https://github.com/aistackhq/sandbox/issues"},"keywords":["sandbox","vercel","ai","docker","container","code-execution","runtime","isolated","self-hosted","tailscale"],"main":"dist/index.cjs","module":"dist/index.js","types":"dist/index.d.ts","type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"sideEffects":false,"engines":{"node":">=18.0.0"},"scripts":{"build":"tsup src/index.ts --format esm,cjs --dts","dev":"tsup src/index.ts --format esm,cjs --dts --watch","prepublishOnly":"npm run build"},"dependencies":{"node-fetch":"^3.3.2","ws":"^8.16.0"},"devDependencies":{"@types/node":"^20.10.0","@types/ws":"^8.5.10","tsup":"^8.0.1","typescript":"^5.3.0"},"_id":"@aistack/sandbox@1.0.0","gitHead":"cdd62d61b2252dbbd33c2cb1c4c24ac948bd5f5f","_nodeVersion":"22.11.0","_npmVersion":"10.9.0","dist":{"integrity":"sha512-mVnki6hBk/VVTIZvvgCTRZeJJOXbm7zA1A19pkPXgYvhKWyaHqB2aCX4G2xpTpsMgrFdx7FmBXiEN+E5F5EPAg==","shasum":"f273a1d5bca950bc9feff38861dbd074c28fcf06","tarball":"https://registry.npmjs.org/@aistack/sandbox/-/sandbox-1.0.0.tgz","fileCount":6,"unpackedSize":48920,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDPdjqlERclnuv+C02iHx4HRkOeY+tJuiqQqanz8QoV9QIhAJ1FdpTgga/XsEsrqzaYix94wXGOTLu0pOFVGsYIkKBa"}]},"_npmUser":{"name":"aistackteam","email":"aistack.run@gmail.com"},"directories":{},"maintainers":[{"name":"aistackteam","email":"aistack.run@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sandbox_1.0.0_1766834436668_0.09229242484010913"},"_hasShrinkwrap":false}},"time":{"created":"2025-12-27T11:20:36.540Z","1.0.0":"2025-12-27T11:20:36.832Z","modified":"2025-12-27T11:20:37.103Z"},"maintainers":[{"name":"aistackteam","email":"aistack.run@gmail.com"}],"description":"Drop-in replacement for @vercel/sandbox - run AI sandboxes on your own infrastructure","homepage":"https://github.com/aistackhq/sandbox#readme","keywords":["sandbox","vercel","ai","docker","container","code-execution","runtime","isolated","self-hosted","tailscale"],"repository":{"type":"git","url":"git+https://github.com/aistackhq/sandbox.git","directory":"packages/sdk"},"author":{"name":"AIStack"},"bugs":{"url":"https://github.com/aistackhq/sandbox/issues"},"license":"MIT","readme":"# @aistack/sandbox\n\nA **drop-in replacement** for `sandbox` by vercel that runs on your own infrastructure using Docker and Tailscale.\n\n[![npm version](https://img.shields.io/npm/v/@aistack/sandbox.svg)](https://www.npmjs.com/package/@aistack/sandbox)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n## Why?\n\n- **100% API Compatible** with `@vercel/sandbox` - just change the import\n- **Self-hosted** - run on your own servers with full control\n- **Multiple Runtimes** - Bun, Node.js 22/24, Python 3.10\n- **Tailscale Integration** - secure networking with optional public URLs via Funnel\n- **No vendor lock-in** - migrate to/from Vercel Sandbox with one line change\n\n## Installation\n\n```bash\nnpm install @aistack/sandbox\n# or\nyarn add @aistack/sandbox\n# or\npnpm add @aistack/sandbox\n# or\nbun add @aistack/sandbox\n```\n\n## Quick Start\n\n### Migrating from Vercel Sandbox\n\n```javascript\n// Before (Vercel)\nimport { Sandbox } from '@vercel/sandbox';\n\n// After (AIStack) - just change the import and set your endpoint!\nimport { Sandbox } from '@aistack/sandbox';\n\nSandbox.setEndpoint('http://your-server:3456');\nSandbox.setApiSecret('your-api-secret');\n\n// Everything else stays exactly the same!\nconst sandbox = await Sandbox.create({\n  runtime: 'bun',\n  resources: { vcpus: 2 },\n  timeout: 5 * 60 * 1000,\n});\n```\n\n### Full Example\n\n```javascript\nimport { Sandbox } from '@aistack/sandbox';\n\n// Configure once\nSandbox.setEndpoint(process.env.SANDBOX_ENDPOINT || 'http://localhost:3456');\nSandbox.setApiSecret(process.env.SANDBOX_API_SECRET);\n\nasync function main() {\n  // Create a sandbox\n  const sandbox = await Sandbox.create({\n    runtime: 'bun', // 'bun' | 'node22' | 'node24' | 'nvm22' | 'python3.10'\n    resources: { vcpus: 2 },\n    timeout: 10 * 60 * 1000,\n    ports: [3000],\n  });\n\n  console.log(`Sandbox created: ${sandbox.sandboxId}`);\n\n  // Run commands\n  const result = await sandbox.runCommand('node', ['--version']);\n  console.log(`Node version: ${result.stdout}`);\n\n  // Run with streaming output\n  await sandbox.runCommand({\n    cmd: 'npm',\n    args: ['install'],\n    stdout: process.stdout,\n    stderr: process.stderr,\n  });\n\n  // Write files\n  await sandbox.writeFiles([{ path: 'index.js', content: Buffer.from('console.log(\"Hello!\")') }]);\n\n  // Read files\n  const stream = await sandbox.readFile({ path: 'package.json' });\n\n  // Run detached (background) processes\n  const server = await sandbox.runCommand({\n    cmd: 'npm',\n    args: ['start'],\n    detached: true,\n  });\n  console.log(`Server PID: ${server.pid}`);\n\n  // Get internal URL (Tailscale network)\n  const internalUrl = sandbox.domain(3000);\n\n  // Get public URL (via Tailscale Funnel)\n  const publicUrl = await sandbox.getPublicUrl(3000);\n\n  // Cleanup\n  await sandbox.stop();\n}\n\nmain();\n```\n\n## API Reference\n\n### Static Methods\n\n#### `Sandbox.setEndpoint(url: string)`\n\nSet the control plane URL.\n\n#### `Sandbox.setApiSecret(secret: string)`\n\nSet the API authentication secret.\n\n#### `Sandbox.create(options): Promise<Sandbox>`\n\nCreate a new sandbox.\n\n```typescript\nconst sandbox = await Sandbox.create({\n  runtime?: 'bun' | 'node22' | 'node24' | 'nvm22' | 'python3.10', // default: 'bun'\n  resources?: { vcpus?: number },  // default: { vcpus: 2 }\n  timeout?: number,                // milliseconds, default: 5 minutes\n  ports?: number[],                // ports to expose\n  source?: {                       // optional: clone a git repo\n    url: string,\n    type: 'git',\n    branch?: string,\n    token?: string,                // for private repos\n  },\n});\n```\n\n#### `Sandbox.get(sandboxId: string): Promise<Sandbox>`\n\nGet an existing sandbox by ID.\n\n#### `Sandbox.list(options?): Promise<{ sandboxes, pagination }>`\n\nList all sandboxes.\n\n### Instance Methods\n\n#### `sandbox.runCommand(cmd, args?, opts?): Promise<CommandFinished>`\n\nRun a command and wait for completion.\n\n```typescript\n// Simple form\nconst result = await sandbox.runCommand('ls', ['-la']);\nconsole.log(result.stdout);\nconsole.log(result.exitCode);\n\n// With options\nconst result = await sandbox.runCommand({\n  cmd: 'npm',\n  args: ['install'],\n  cwd: '/app',\n  env: { NODE_ENV: 'production' },\n  sudo: false,\n  stdout: process.stdout, // stream output\n  stderr: process.stderr,\n});\n```\n\n#### `sandbox.runCommand({ ...opts, detached: true }): Promise<Command>`\n\nRun a command in the background.\n\n```typescript\nconst cmd = await sandbox.runCommand({\n  cmd: 'npm',\n  args: ['start'],\n  detached: true,\n});\nconsole.log(`PID: ${cmd.pid}`);\nawait cmd.kill(); // stop it later\n```\n\n#### `sandbox.writeFiles(files): Promise<void>`\n\nWrite files to the sandbox.\n\n```typescript\nawait sandbox.writeFiles([\n  { path: 'app.js', content: Buffer.from('console.log(\"Hi\")') },\n  { path: 'config.json', content: Buffer.from('{\"debug\": true}') },\n]);\n```\n\n#### `sandbox.readFile(file): Promise<ReadableStream | null>`\n\nRead a file from the sandbox.\n\n```typescript\nconst stream = await sandbox.readFile({ path: 'output.txt' });\nif (stream) {\n  const reader = stream.getReader();\n  const { value } = await reader.read();\n  console.log(Buffer.from(value).toString());\n}\n```\n\n#### `sandbox.mkDir(path): Promise<void>`\n\nCreate a directory.\n\n#### `sandbox.domain(port): string`\n\nGet the internal Tailscale URL for a port.\n\n```typescript\nconst url = sandbox.domain(3000);\n// Returns: http://100.x.y.z:3000\n```\n\n#### `sandbox.getPublicUrl(port): Promise<string>`\n\nGet a public URL via Tailscale Funnel.\n\n```typescript\nconst publicUrl = await sandbox.getPublicUrl(3000);\n// Returns: https://sandbox-abc123.your-tailnet.ts.net\n```\n\n#### `sandbox.stop(): Promise<void>`\n\nStop and remove the sandbox.\n\n#### `sandbox.extendTimeout(ms): Promise<void>`\n\nExtend the sandbox timeout.\n\n### Properties\n\n- `sandbox.sandboxId` - Unique sandbox identifier\n- `sandbox.status` - Current status: `'pending' | 'running' | 'stopping' | 'stopped' | 'failed'`\n- `sandbox.timeout` - Timeout in milliseconds\n\n## Environment Variables\n\n| Variable             | Description                                        |\n| -------------------- | -------------------------------------------------- |\n| `SANDBOX_ENDPOINT`   | Control plane URL (alternative to `setEndpoint()`) |\n| `SANDBOX_API_SECRET` | API secret (alternative to `setApiSecret()`)       |\n| `API_SECRET`         | Fallback for API secret                            |\n\n## Available Runtimes\n\n| Runtime         | Description                             |\n| --------------- | --------------------------------------- |\n| `bun` (default) | Bun (latest) + Node.js 22 + Python 3.10 |\n| `node22`        | Node.js 22 LTS + Python 3.10            |\n| `node24`        | Node.js 24 + Python 3.10                |\n| `nvm22`         | NVM with Node 22 + Python 3.10          |\n| `python3.10`    | Python 3.10 only                        |\n\n## Self-Hosting\n\nThis SDK requires a self-hosted control plane. See the [full documentation](https://github.com/aistack/sandbox) for setup instructions.\n\n### Quick Setup\n\n```bash\ngit clone https://github.com/aistack/sandbox.git\ncd sandbox\nbun install\nbun run docker:build\nbun run start\n```\n\n## Comparison with Vercel Sandbox\n\n| Feature     | Vercel Sandbox | @aistack/sandbox        |\n| ----------- | -------------- | ----------------------- |\n| API         | ✅             | ✅ 100% compatible      |\n| Self-hosted | ❌             | ✅                      |\n| Runtimes    | Bun, Node      | Bun, Node 22/24, Python |\n| Networking  | Vercel domain  | Tailscale + Funnel      |\n| Cost        | Per-usage      | Your infrastructure     |\n| Max timeout | 5 hours (Pro)  | Configurable            |\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-3d419ec92e3f6984bdc1c0ea86c040ad"}