@alibaba-group/opensandbox

中文文档
1.2.0发布于 2026/10/27Apache-2.0TypeScriptESM + CJS近 30 天下载 49.4万

OpenSandbox TypeScript/JavaScript SDK (sandbox lifecycle + execd APIs)

原始使用文档
文档目录23 节
  1. Installation
  2. npm
  3. pnpm
  4. yarn
  5. Quick Start
  6. Client-side sandbox pool
  7. Usage Examples
  8. 1. Lifecycle Management
  9. 2. Custom Health Check
  10. 3. Command Execution & Streaming
  11. 4. Comprehensive File Operations
  12. 5. Endpoints
  13. 6. Snapshots (Manager)
  14. 7. Isolated Sessions
  15. 8. Volume Mounts
  16. 9. Sandbox Management (Admin)
  17. Configuration
  18. 1. Connection Configuration
  19. 2. Sandbox Creation Configuration
  20. 3. Runtime Egress Policy Updates
  21. 4. Credential Vault
  22. 5. Resource cleanup
  23. Browser Notes

Alibaba Sandbox SDK for JavaScript/TypeScript

A TypeScript/JavaScript SDK for low-level interaction with OpenSandbox. It provides the ability to create, manage, and interact with secure sandbox environments, including executing shell commands, managing files, and reading resource metrics.

Installation

npm

npm install @alibaba-group/opensandbox

pnpm

pnpm add @alibaba-group/opensandbox

yarn

yarn add @alibaba-group/opensandbox

Quick Start

The following example shows how to create a sandbox and execute a shell command.

Note: Before running this example, ensure the OpenSandbox service is running. See the root README for startup instructions.

import { ConnectionConfig, Sandbox, SandboxException } from "@alibaba-group/opensandbox";

const config = new ConnectionConfig({
  domain: "api.opensandbox.io",
  apiKey: "your-api-key",
  // protocol: "https",
  // requestTimeoutSeconds: 60,
});

try {
  const sandbox = await Sandbox.create({
    connectionConfig: config,
    image: "ubuntu",
    timeoutSeconds: 10 * 60,
  });

  const execution = await sandbox.commands.run("echo 'Hello Sandbox!'");
  console.log(execution.logs.stdout[0]?.text);

  // Optional but recommended: terminate the remote instance when you are done.
  await sandbox.kill();
  await sandbox.close();
} catch (err) {
  if (err instanceof SandboxException) {
    console.error(
      `Sandbox Error: [${err.error.code}] ${err.error.message ?? ""}`,
    );
    console.error(`Request ID: ${err.requestId ?? "N/A"}`);
  } else {
    console.error(err);
  }
}

Client-side sandbox pool

SandboxPool maintains a best-effort buffer of clean, ready sandboxes. An acquired sandbox becomes caller-owned and is never returned to the pool; kill it when the work is complete. The pool replenishes the idle buffer in the background.

import {
  AcquirePolicy,
  InMemoryPoolStateStore,
  SandboxPool,
} from "@alibaba-group/opensandbox";

const pool = SandboxPool.create({
  poolName: "workers",
  maxIdle: 2,
  stateStore: new InMemoryPoolStateStore(),
  connectionConfig: { apiKey: process.env.OPEN_SANDBOX_API_KEY },
  creationSpec: { image: "ubuntu:24.04" },
});

await pool.start();
const sandbox = await pool.acquire({
  sandboxTimeoutSeconds: 3600,
  policy: AcquirePolicy.DIRECT_CREATE,
});

try {
  await sandbox.commands.run("echo ready");
} finally {
  await sandbox.kill();
  await sandbox.close();
  await pool.shutdown();
}

InMemoryPoolStateStore is process-local. For a distributed pool, install a Redis client only in the application that needs it and import the optional pool subpath:

npm install redis
import { createClient } from "redis";
import { RedisPoolStateStore } from "@alibaba-group/opensandbox/pool-redis";

const redis = createClient({ url: process.env.REDIS_URL });
await redis.connect();

const stateStore = new RedisPoolStateStore({ client: redis });

The SDK does not import redis from its main entry point and does not create, connect, or close the injected client. Any compatible client that implements sendCommand(string[]) can be used.

Pool warmup is admitted at warmupCreateQps per one-second reconcile tick. Creation is asynchronous; warmupConcurrency limits the post-create readiness, preparation, renewal, and commit stages. Use warmupSandboxPreparer, warmupPostPrepareHealthCheck, and the corresponding timeout/polling options for staged warmup. Set connectionConfig.enableTracing to emit OpenTelemetry pool.warmup traces with one child span per stage.

SandboxPoolManager.destroy(poolName) writes a shared DESTROYING fence, drains and best-effort kills visible idle sandboxes, clears persistent pool state, and writes a DESTROYED tombstone. drainTimeoutSeconds is checked before each drain attempt and bounds in-flight sandbox deletion; set it to 0 to disable that bound. State-store calls remain subject to the store client's own request timeout. If drain or persistent-state cleanup cannot finish, the namespace remains fenced as DESTROYING. Retry destroy() with the same pool name to finish cleanup.

Usage Examples

1. Lifecycle Management

Manage the sandbox lifecycle, including renewal, pausing, and resuming.

const info = await sandbox.getInfo();
console.log("State:", info.status.state);
console.log("Created:", info.createdAt);
console.log("Expires:", info.expiresAt); // null when manual cleanup mode is used

await sandbox.pause();

// Resume returns a fresh, connected Sandbox instance.
const resumed = await sandbox.resume();

// Renew: expiresAt = now + timeoutSeconds
await resumed.renew(30 * 60);

Create a non-expiring sandbox by passing timeoutSeconds: null:

const manual = await Sandbox.create({
  connectionConfig: config,
  image: "ubuntu",
  timeoutSeconds: null,
});

2. Custom Health Check

Define custom logic to determine whether the sandbox is ready/healthy. This overrides the default ping check used during readiness checks.

const sandbox = await Sandbox.create({
  connectionConfig: config,
  image: "nginx:latest",
  healthCheck: async (sbx) => {
    // Example: consider the sandbox healthy when port 80 endpoint becomes available
    const ep = await sbx.getEndpoint(80);
    return !!ep.endpoint;
  },
});

3. Command Execution & Streaming

Execute commands and handle output streams in real-time.

import type { ExecutionHandlers } from "@alibaba-group/opensandbox";

const handlers: ExecutionHandlers = {
  onStdout: (m) => console.log("STDOUT:", m.text),
  onStderr: (m) => console.error("STDERR:", m.text),
  onExecutionComplete: (c) =>
    console.log("Finished in", c.executionTimeMs, "ms"),
};

await sandbox.commands.run(
  'for i in 1 2 3; do echo "Count $i"; sleep 0.2; done',
  undefined,
  handlers,
);

4. Comprehensive File Operations

Manage files and directories, including read, write, list/search, and delete.

await sandbox.files.createDirectories([{ path: "/tmp/demo", mode: 755 }]);

await sandbox.files.writeFiles([
  { path: "/tmp/demo/hello.txt", data: "Hello World", mode: 644 },
]);

const content = await sandbox.files.readFile("/tmp/demo/hello.txt");
console.log("Content:", content);

const files = await sandbox.files.search({
  path: "/tmp/demo",
  pattern: "*.txt",
});
console.log(files.map((f) => f.path));

await sandbox.files.deleteDirectories(["/tmp/demo"]);

5. Endpoints

getEndpoint() returns an endpoint without a scheme (for example "localhost:44772"). Use getEndpointUrl() if you want a ready-to-use absolute URL (for example "http://localhost:44772").

const { endpoint } = await sandbox.getEndpoint(44772);
const url = await sandbox.getEndpointUrl(44772);

6. Snapshots (Manager)

SandboxManager administers sandbox snapshots — capture a sandbox's state and restore new sandboxes from it via snapshotId:

import { SandboxManager } from "@alibaba-group/opensandbox";

const manager = SandboxManager.create({ connectionConfig: config });

// Create a snapshot from a running sandbox, then wait until it is Ready
const snapshot = await manager.createSnapshot(sandboxId, {
  name: "pre-migration",
});
let info = await manager.getSnapshot(snapshot.id);
while (info.status.state === "Creating") {
  await new Promise((r) => setTimeout(r, 2000));
  info = await manager.getSnapshot(snapshot.id);
}

// List all snapshots
const page = await manager.listSnapshots();

// Restore: create a new sandbox FROM a snapshot (exactly one of
// image / snapshotId must be provided)
const restored = await Sandbox.create({
  connectionConfig: config,
  snapshotId: snapshot.id,
});

// Only delete the snapshot after the restore has succeeded
await manager.deleteSnapshot(snapshot.id);

7. Isolated Sessions

Isolated sessions run multi-step code in a hardened, resource-bounded environment with bind mounts — reachable through sandbox.isolation:

const session = await sandbox.isolation.create({
  workspace: { path: "/workspace", mode: "rw" },
  profile: "strict",
  // Optional bind mounts (source on host, dest inside the session)
  binds: [{ source: "/data", dest: "/data", readonly: true }],
});

const run = await session.run("python -c 'print(1+1)'", {
  // timeout_seconds: 30, // seconds; applies to run() only —
  // runBackground() deliberately ignores it (background runs are not time-limited)
});
console.log(run.logs.stdout[0]?.text);

// Background runs: start, poll until finished, then fetch logs.
// NOTE: field names are snake_case (run_id) — they mirror the raw API
// response and are NOT converted to camelCase.
const bg = await session.runBackground("make build");
let status = await session.getRunStatus(bg.run_id);
while (status.running) {
  await new Promise((r) => setTimeout(r, 2000));
  status = await session.getRunStatus(bg.run_id);
}
const logs = await session.getRunLogs(bg.run_id);

await session.delete();

8. Volume Mounts

volumes supports host, pvc, and ossfs backends. Each volume must specify exactly one backend.

const sandbox = await Sandbox.create({
  connectionConfig: config,
  image: "ubuntu",
  volumes: [
    {
      name: "oss-data",
      ossfs: {
        bucket: "bucket-a",
        endpoint: "oss-cn-hangzhou.aliyuncs.com",
        accessKeyId: process.env.OSS_ACCESS_KEY_ID!,
        accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET!,
        version: "2.0",
      },
      mountPath: "/mnt/oss",
      subPath: "prefix",
    },
  ],
});

9. Sandbox Management (Admin)

Use SandboxManager for administrative tasks and finding existing sandboxes.

import { SandboxManager } from "@alibaba-group/opensandbox";

const manager = SandboxManager.create({ connectionConfig: config });
const list = await manager.listSandboxInfos({
  states: ["Running"],
  pageSize: 10,
});
console.log(list.items.map((s) => s.id));
await manager.close();

Configuration

1. Connection Configuration

The ConnectionConfig class manages API server connection settings.

Runtime notes:

  • In browsers, the SDK uses the global fetch implementation.
  • requestTimeoutSeconds bounds the wait for a response: it stops applying once the response headers arrive (streaming responses are not cut off). It never caps a healthy file upload body, which can legitimately take longer than the timeout; on Node.js a stalled upload, or an upload that gets no response headers within the timeout once the body has been sent, is aborted instead of hanging (the Go SDK's ResponseHeaderTimeout contract).
  • In Node.js, every Sandbox and SandboxManager gets its own transport via withTransportIfMissing() unless you pass an already-initialized ConnectionConfig; shared configs are reused, and the SDK only closes transports it allocated itself. Call sandbox.close() or manager.close() when you are done so the SDK can release the agent it owns.
ParameterDescriptionDefaultEnvironment Variable
apiKeyAPI key for authenticationOptionalOPEN_SANDBOX_API_KEY
domainSandbox service domain (host[:port]), or a full base URL including a path prefix (e.g. https://gw.example.com/opensandbox)localhost:8080OPEN_SANDBOX_DOMAIN
protocolHTTP protocol (http/https)http-
requestTimeoutSecondsRequest timeout applied to SDK HTTP calls30-
debugEnable basic HTTP debug loggingfalse-
headersExtra headers applied to every request{}-
useServerProxyUse sandbox server as proxy for execd/endpoint requests (e.g. when client cannot reach the sandbox directly)false-
endpointCacheTtlMsHow long a cached sandbox endpoint stays valid600000-
endpointCacheSizeMaximum number of cached endpoints1024-
endpointCacheDisabledDisable endpoint caching entirelyfalse-
disableMetricsOpt out of create-latency telemetryfalseOPENSANDBOX_DISABLE_METRICS=1
enableTracingEmit pool trace context headersfalse-
import { ConnectionConfig } from "@alibaba-group/opensandbox";

// 1. Basic configuration
const config = new ConnectionConfig({
  domain: "api.opensandbox.io",
  apiKey: "your-key",
  requestTimeoutSeconds: 60,
});

// 2. Advanced: custom headers
const config2 = new ConnectionConfig({
  domain: "api.opensandbox.io",
  apiKey: "your-key",
  headers: { "X-Custom-Header": "value" },
});

2. Sandbox Creation Configuration

Sandbox.create() allows configuring the sandbox environment.

ParameterDescriptionDefault
imageDocker image to useRequired
timeoutSecondsAutomatic termination timeout (server-side TTL)10 minutes
entrypointContainer entrypoint command["tail","-f","/dev/null"]
resourceCPU and memory limits (string map){"cpu":"1","memory":"2Gi"}
envEnvironment variables{}
metadataCustom metadata tags{}
networkPolicyOptional outbound network policy (egress)-
credentialProxyOptional Credential Vault proxy startup settings-
extensionsExtra server-defined fields{}
skipHealthCheckSkip readiness checks (Running + health check)false
healthCheckCustom readiness check-
readyTimeoutSecondsMax time to wait for readiness30 seconds
healthCheckPollingIntervalPoll interval while waiting (milliseconds)200 ms
signalAbort creation and readiness requests-

Note: metadata keys under opensandbox.io/ are reserved for system-managed labels and will be rejected by the server.

const sandbox = await Sandbox.create({
  connectionConfig: config,
  image: "python:3.11",
  networkPolicy: {
    defaultAction: "deny",
    egress: [{ action: "allow", target: "pypi.org" }],
  },
});

3. Runtime Egress Policy Updates

Runtime egress reads and patches go directly to the sandbox egress sidecar. The SDK first resolves the sandbox endpoint on port 18080, then calls the sidecar /policy API.

Patch uses merge semantics:

  • Incoming rules take priority over existing rules with the same target.
  • Existing rules for other targets remain unchanged.
  • Within a single patch payload, the first rule for a target wins.
  • The current defaultAction is preserved.
const policy = await sandbox.getEgressPolicy();

await sandbox.patchEgressRules([
  { action: "allow", target: "www.github.com" },
  { action: "deny", target: "pypi.org" },
]);

4. Credential Vault

Credential Vault injects outbound credentials from the egress sidecar while keeping real secrets out of sandbox environment variables, commands, files, and logs. Create the sandbox with credentialProxy enabled, then write credentials and bindings through sandbox.credentialVault.

const sandbox = await Sandbox.create({
  connectionConfig: config,
  image: "python:3.11",
  networkPolicy: {
    defaultAction: "deny",
    egress: [{ action: "allow", target: "api.example.com" }],
  },
  credentialProxy: { enabled: true },
});

await sandbox.credentialVault.create({
  credentials: [{ name: "api-token", source: { value: "<token>" } }],
  bindings: [
    {
      name: "api-token",
      match: {
        schemes: ["https"],
        hosts: ["api.example.com"],
        paths: ["/v1/*"],
      },
      auth: { type: "apiKey", name: "x-api-key", credential: "api-token" },
    },
  ],
});

See Credential Vault for auth types, binding guidance, and Git/curl examples.

5. Resource cleanup

Both Sandbox and SandboxManager own a scoped HTTP agent when running on Node.js so you can safely reuse the same ConnectionConfig. Once you are finished interacting with the sandbox or administration APIs, call sandbox.close() / manager.close() to release the underlying agent.

Browser Notes

  • The SDK can run in browsers, but streaming file uploads are Node-only.
  • If you pass ReadableStream or AsyncIterable for writeFiles, the browser will fall back to buffering in memory before upload.
  • Reason: browsers do not support streaming multipart/form-data bodies with custom boundaries (required by the execd upload API).
  • Redirects: same-origin redirects keep request headers, while cross-origin redirects drop OPEN-SANDBOX-* / OPENSANDBOX-* headers (plus Authorization, Cookie, and Proxy-Authorization) so credentials are never replayed. File uploads never follow redirects. Browsers cannot inspect a manual redirect target, so a request carrying protected headers fails closed when a redirect is received; Node.js is unaffected. See Redirects and protected headers.

版本与发布记录

@alibaba-group/opensandbox 共发布 26 个版本,首次发布于 2026/01/15;过去 12 个月发布了 26 个版本。

版本发布日期距今
1.2.0latest2026/10/2711 天前
1.1.12026/10/0929 天前
1.1.02026/09/211 个月前
0.1.112026/07/243 个月前
0.1.102026/07/084 个月前
0.1.92026/06/164 个月前

关于 @alibaba-group/opensandbox 的常见问题

@alibaba-group/opensandbox 是什么?

OpenSandbox TypeScript/JavaScript SDK (sandbox lifecycle + execd APIs)

如何安装 @alibaba-group/opensandbox?

在项目目录运行 npm install @alibaba-group/opensandbox,或使用 pnpm add / yarn add / bun add。

@alibaba-group/opensandbox 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@alibaba-group/opensandbox 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@alibaba-group/opensandbox 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@alibaba-group/opensandbox 可以商用吗?

@alibaba-group/opensandbox 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@alibaba-group/opensandbox 的下载量有多少?

根据 npm 官方下载统计,@alibaba-group/opensandbox 在 2026/10/06 – 2026/11/04 这 30 天内被下载 493,747 次,日均约 16,458 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@alibaba-group/opensandbox 还在维护吗?

最新版本 1.2.0 发布于 2026/10/27(11 天前);至今共发布 26 个版本,其中过去 12 个月发布了 26 个;首次发布于 2026/01/15。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。