Skip to content

Repository files navigation

Sandbox0 JavaScript/TypeScript SDK

The official JavaScript/TypeScript SDK for Sandbox0, providing typed models and ergonomic high-level APIs for managing secure code execution sandboxes.

Installation

npm install sandbox0
# or
yarn add sandbox0
# or
pnpm add sandbox0

Requirements

  • Node.js 18.0.0 or later

Streaming APIs prefer a runtime-native globalThis.WebSocket when a Node-compatible host exposes one, and fall back to the ws package on older Node runtimes. This keeps the main SDK entry compatible with SandFunc-style runtimes that expose a standard outbound WebSocket client without requiring raw socket access in user code.

Configuration

Environment Variable Required Default Description
SANDBOX0_TOKEN Yes - API authentication token
SANDBOX0_BASE_URL No https://api.sandbox0.ai API base URL

Quick Start

import { Client } from "sandbox0";

const client = new Client({
  token: process.env.SANDBOX0_TOKEN!,
});

async function main() {
  // Claim a sandbox
  const sandbox = await client.sandboxes.claim("default");

  try {
    // Execute Python code (REPL - stateful)
    const result = await sandbox.run("python", "print('Hello, Sandbox0!')");
    process.stdout.write(result.outputRaw);
  } finally {
    // Cleanup
    await client.sandboxes.delete(sandbox.id);
  }
}

main().catch(console.error);

CMD Streaming

const stream = await sandbox.cmdStream("sh -c 'echo hello && echo warn >&2'", {
  command: ["sh", "-c", "echo hello && echo warn >&2"],
});

for await (const output of stream.outputs()) {
  process.stdout.write(output.data);
}

const done = await stream.wait();
console.log(`exit=${done.exitCode} state=${done.state}`);

Documentation

Bootstrap Mounts At Claim Time

const volume = await client.volumes.create({});

const sandbox = await client.sandboxes.claim("default", {
  mounts: [{ sandboxvolumeId: volume.id, mountPoint: "/workspace/data" }],
});

for (const mount of sandbox.bootstrapMounts) {
  console.log(mount.sandboxvolumeId, mount.state);
}

Wait For Lifecycle Changes

Pause is accepted before its rootfs checkpoint is fully committed. Use the waiting helpers when the next operation depends on committed lifecycle state:

const paused = await client.sandboxes.pauseAndWait(sandbox.id, {
  timeoutMs: 120_000,
  signal: abortController.signal,
});

const resumed = await client.sandboxes.resumeAndWait(paused.id);
console.log(resumed.status, resumed.runtimeGeneration);

waitForLifecycle() is available for other committed-state conditions. Aborting a wait stops polling locally; it does not undo a pause or resume already accepted by Sandbox0.

Create A Template From A Sandbox

Capture the current root filesystem of an existing sandbox into a new template:

const template = await client.templates.createFromSandbox(
  {
    templateId: "python-ready",
    sandboxId: sandbox.id,
    specOverrides: {
      displayName: "Python Ready",
      tags: ["python"],
    },
  },
  {
    idempotencyKey: "python-ready-v1",
    wait: true,
    timeoutMs: 10 * 60_000,
  },
);

console.log(template.templateId, template.status?.creation?.state);

Without wait: true, creation returns as soon as Sandbox0 accepts the request. The rootfs capture point is status.creation.capturedAt, not request acceptance, so keep the source sandbox available and avoid rootfs writes while the stage is capturing. waitUntilReady() can wait for the same template later. Aborting a wait only stops local polling; it does not cancel image creation on the server.

Runtime Metrics

getMetrics() returns bounded, chart-ready sandbox metrics. Each series is split into segments at runtime restarts and collector resets, so chart segments should not be connected across those boundaries.

import { SandboxRuntimeMetricName } from "sandbox0";

const metrics = await sandbox.getMetrics({
  startTime: new Date(Date.now() - 60 * 60 * 1000),
  metrics: [
    SandboxRuntimeMetricName.SandboxCpuUtilization,
    SandboxRuntimeMetricName.SandboxMemoryUtilization,
  ],
  maxPoints: 240,
});

for (const series of metrics.series) {
  for (const segment of series.segments) {
    console.log(series.metric, segment.points);
  }
}

Use sandbox.getMetricsCatalog() to discover metric kinds, units, and dimensions supported by the API.

Tenant Usage Windows

client.usage.listWindows() incrementally reads immutable, closed usage windows for the team derived from the SDK token. The API never accepts a team id from the caller. Retain nextCursor only after durably processing the returned page.

let cursor: string | undefined;

do {
  const page = await client.usage.listWindows({
    cursor,
    limit: 1000,
    windowType: "sandbox.runtime_mib_milliseconds",
  });

  for (const window of page.windows) {
    console.log(
      window.sandboxId,
      window.windowStart,
      window.windowEnd,
      window.value,
      window.unit,
    );
  }

  cursor = page.nextCursor || undefined;
} while (cursor);

The token needs usage:read, and the Sandbox0 region must have metering and its ClickHouse query projection enabled. GET /api/v1/quotas reports current operational quota status; it is not a cumulative usage API.

Links

License

Apache-2.0

Releases

Packages

Contributors

Languages