@docker/sandboxes

中文文档
0.53.0发布于 2026/10/07Apache-2.0TypeScriptES Module近 30 天下载 1.6万

TypeScript REST SDK for Docker Cloud Sandboxes, with typed HTTP and WebSocket streams.

原始使用文档
文档目录8 节
  1. Sign in
  2. Custom authentication transport
  3. Create a sandbox and run code
  4. Launch a bundled kit
  5. Manage personal network policies
  6. Handle errors and retries
  7. Clean up
  8. Advanced HTTP and browser use

Docker Sandboxes for TypeScript

Run code in isolated Docker Cloud Sandboxes from Node.js 20 or later. Your Docker account needs Cloud Sandboxes access.

npm install @docker/sandboxes

Sign in

The SDK gives your application a URL and code to show the user. It waits for sign-in, then keeps the session in memory and refreshes it when needed.

import { oauth, Sandboxes, SandboxesError } from '@docker/sandboxes';

const auth = oauth({
  onVerification({ verificationUriComplete, verificationUri, userCode }) {
    console.log(`Open ${verificationUriComplete ?? verificationUri} and enter ${userCode}`);
  },
});
await auth.getAccessToken(); // Complete attended sign-in before the first API deadline starts.
const client = new Sandboxes({ auth });

Attended sign-in follows the device code's lifetime, not the 30-second request timeout. Individual authentication requests remain bounded. Pass auth.getAccessToken({ signal }) to stop waiting; canceling one caller does not cancel a shared sign-in. API requests still have their own deadlines, so complete attended sign-in before making them.

OAuth credentials stay in memory by default, so a new process signs in again. For explicit local persistence, pass an intentional ignored path such as store: fileOAuthCredentialStore({path: '.docker-sandboxes/oauth.json'}); it stores plaintext credentials with restrictive POSIX permissions. Keep that path out of source control. Use a keychain, encrypted database, or secret manager for production workloads.

Custom credential stores should honor the supplied abort signal. The SDK waits for an in-flight save to settle before publishing the new credentials or starting another save.

For automation with a Docker personal access token, use the PAT authenticator. It exchanges the PAT over HTTPS for a short-lived access token, keeps it in memory, and refreshes it automatically. The API validates the token; the SDK reads its expiry only to schedule renewal.

import { pat } from '@docker/sandboxes';

declare const username: string;
declare const personalAccessToken: string;

const patAuth = pat({ username, personalAccessToken });
const automatedClient = new Sandboxes({ auth: patAuth });

Custom authentication transport

If sign-in must use a proxy or custom CA configuration, pass your Fetch-compatible function to pat() or oauth(). A client's fetch option controls API requests only; it does not reconfigure a shared authenticator. To use the same transport for both:

declare const customFetch: (request: Request) => Promise<Response>;
const proxyAuth = pat({
  username,
  personalAccessToken,
  fetch: customFetch,
  transportRetries: 'none',
});
const proxyClient = new Sandboxes({
  auth: proxyAuth,
  fetch: customFetch,
  transportRetries: 'none',
});

Each authenticator retains its custom function for initial sign-in and refresh. oauth() uses it for device-code requests and token polling too. The function must support concurrent requests, honor the request's abort signal and redirect policy, and make one attempt per call. Declare transportRetries: 'none' on each owner using custom fetch. Authentication keeps its existing deadlines and does not retry or fall back to global fetch when the custom transport fails. Without custom fetch, authentication uses the platform's global fetch. Closing a client does not close its authenticator or either borrowed transport.

By default, the same access token, token provider, or sign-in session authenticates Sandbox requests at https://connect.docker.com/sandboxes and personal Governance requests at https://hub.docker.com/rpc. Sign-in does not read or change Docker CLI credentials.

Inherited environment variables can change where the SDK sends credentials. Unless you intentionally use internal integration overrides, unset SANDBOXES_API_URL, DOCKER_OAUTH_ISSUER, DOCKER_TOKEN_EXCHANGE_URL, and DOCKER_GOVERNANCE_URL before creating clients or authenticators.

Internal integration overrides

These controls are retained for internal testing, not supported end-user configuration.

VariableSelectsDefault
SANDBOXES_API_URLManagement API base, without /v1https://connect.docker.com/sandboxes
DOCKER_OAUTH_ISSUEROAuth issuer and its device and token endpointshttps://login.docker.com/
DOCKER_TOKEN_EXCHANGE_URLPAT exchange endpointhttps://hub.docker.com/v2/auth/token
DOCKER_GOVERNANCE_URLPersonal Governance RPC basehttps://hub.docker.com/rpc

Each omitted variable keeps its own production default. Governance is not inferred from the management URL. Overrides must be nonempty HTTPS URLs without user information, a query or a fragment. A management base ending in a version such as /v1 is rejected rather than rewritten.

Set overrides before constructing pat(), oauth() or Sandboxes. Each retains its initial configuration; later environment changes do not redirect requests or token refreshes. A client using a Docker authenticator must match that authenticator's management and Governance bases. An explicit baseUrl takes precedence over SANDBOXES_API_URL, but does not bypass override validation or this authority check. Use a separate OAuth credential store for each issuer; stored records are not bound to an issuer.

The recommended credential configuration is auth: use oauth() for attended sign-in, pat() for automation, bearer() for an existing access token, or a custom Authenticator when the application owns token acquisition. SandboxesOptions also supports accessToken for a fixed bearer token and tokenProvider for a token read on each request.

Create a sandbox and run code

Creation returns when the server accepts the request. Wait separately when your next step needs a running sandbox; when accepted.status === 'running' and accepted.uid is set, the wait only reads it again, and you can use accepted directly. Keep the wait if you passed your own idempotencyKey: a reused key replays the original create result, even for a sandbox deleted since. withSandbox() and kits.launchAndWait() skip the read on the same conditions. Later examples reuse client and sandbox.

const accepted = await client.create({
  imageRef: 'python:3.12',
  displayName: 'python-worker',
  resources: { cpus: 2, memoryMib: '4096' },
});
const sandbox = await accepted.waitUntilRunning();

const result = await sandbox.processes.run({
  args: ['python', '-c', 'print("Hello from a sandbox")'],
});
process.stdout.write(result.stdout);
process.stderr.write(result.stderr);
console.log(result.exitCode);

await sandbox.files.write('/tmp/message.txt', 'Hello\n');
const message = await sandbox.files.read('/tmp/message.txt', { encoding: 'utf8' });
console.log(message);

Waiters default to five minutes. Pass { timeoutMs: 60_000 } to change the deadline. A timeout leaves the sandbox in place.

Use a returned name to reconnect. List one page or iterate over all pages:

const existing = await client.get(sandbox.name);
for await (const item of client.allSandboxes({ query: { pageSize: 25 } })) {
  console.log(item.name, item.core.status);
}

Pagination has no default total timeout; each page request retains its 30-second timeout. An explicit timeoutMs bounds the whole traversal from the start of iteration, including time spent processing items. Caller cancellation, client closure and an enclosing workflow deadline stop traversal before another request or buffered item. collect() and listAll*() retain all results in memory.

Launch a bundled kit

A kit supplies a sandbox image and its agent configuration. The SDK includes a versioned catalog; list() reads it locally. The server must support kit launches, and the selected agent may need its own credentials.

console.log(client.kits.list());

const agentSandbox = await client.kits.launchAndWait('claude', {
  displayName: 'coding-agent',
  resources: 'small',
});

launchAndWait() creates the sandbox and waits for its running state under one deadline. Use launch() when you want the accepted handle immediately and will wait separately. Neither starts an agent task or checks files created by kit setup.

Kit launches default to Small (2 vCPUs, 4 GiB). Choose micro, small, medium, large, or xl through resources, or supply an explicit CPU/memory object. The same named sizes work with client.create().

Manage personal network policies

Governance uses the same client credentials. These methods manage policies owned by the signed-in user; they do not select an organization or another user. This example creates an empty allowlist. Add the required network rules before attaching it to a sandbox.

const policy = await client.governance.policies.create({
  name: 'project-network',
  policyType: 'POLICY_TYPE_ALLOWLIST',
  allowlist: { rules: [] },
});

const policies = await client.governance.policies.list();
const currentPolicy = await client.governance.policies.get(policy.id);
const updatedPolicy = await client.governance.policies.update(
  policy.id,
  { description: 'Network access for this project' },
  { updateMask: 'description' },
);
await client.governance.policies.delete(policy.id);

To use an existing policy when creating a sandbox, pass its ID in network.policyIds.

Handle errors and retries

HTTP failures throw SandboxesError. Wait failures retain the last observed resource in WaitError.resource.

try {
  await client.get(sandbox.name, { timeoutMs: 30_000, maxRetries: 0 });
} catch (error) {
  if (!(error instanceof SandboxesError)) throw error;
  console.error(error.message, error.requestId);
}

The default is at most two additional attempts for transient failures on safe unary requests. Supported mutations get one idempotency key per call, reused with the same body on retries. Supply { idempotencyKey: 'your-request-id' } to reuse a key across application calls. maxRetries: 0 disables retries for a call or client. processes.run(), raw streams and Governance mutations are never replayed.

processes.run() has no default total deadline; process creation and each output read retain their 30-second request timeout. Pass { timeoutMs: 300_000 } as its second argument to bound the whole run, including creation. Caller cancellation, client closure and an enclosing workflow deadline also stop local waiting. run() does not kill the process; withSandbox() retains its separate sandbox cleanup policy. After creation, a failure retains the process identity in ResourceWaitError.resource.

sandbox.run(['node', '-v']) runs a short command in one request to the sandbox endpoint, instead of creating a process and reading its output. It returns the same result without process, and it is never replayed. The command must finish within one request timeout, 30 seconds unless you pass { timeoutMs } as its third argument. After a failure, cancellation or timeout, the command may or may not have run. The service caps the captured output, and incomplete reports when it was cut. Use processes.run() for longer commands, a terminal, a label or session, or when you need the process afterwards.

process.connect() automatically reconnects while you consume output after a temporary disconnect. It resumes after the last chunk delivered to your iterator, without restarting the process or replaying input. Each recovery episode has a 30-second budget. Set { reconnect: false } or { reconnectTimeoutMs: 60_000 } in the second argument to control recovery. Authentication failures, service refusals and invalid output cursors stop the connection.

Connection setup has a 30-second timeout, but an attached process session has no default lifetime limit. An explicit timeoutMs, abort signal or enclosing workflow deadline still applies to the whole session. A failed input write may have reached the process; inspect its state before sending the input again.

Custom fetch implementations and borrowed clients require transportRetries: 'none': disable any retries inside that transport first. Each call retains its selected credential; the SDK never refreshes it to rescue an in-flight call. After a token rejection, a later independent call can renew the managed login or PAT. Retries and waiters use valid server delay guidance exactly when the deadline allows it.

Clean up

Fetch the latest resource before deleting it. HTTP 204 confirms deletion; otherwise, wait on the returned resource. An unexplained 404 does not confirm deletion.

const latest = await sandbox.refresh();
const deleting = await latest.delete();
if (deleting) await deleting.waitUntilDeleted();

const latestAgent = await agentSandbox.refresh();
const deletingAgent = await latestAgent.delete();
if (deletingAgent) await deletingAgent.waitUntilDeleted();

await automatedClient.close();
await client.close();

close() cancels client-owned work and clears its in-memory credentials. It does not delete sandboxes or revoke remote credentials.

Advanced HTTP and browser use

client.api exposes explicit request envelopes. For a conditional read, pass If-None-Match; a 304 response becomes undefined. client.api.raw retains HTTP status and response headers.

Browser bundles support sandbox management, process WebSockets and raw file reads where the service permits cross-origin requests. Streaming uploads and multipart transfers require Node.js. Closing a process connection detaches it without killing its process.

See the API specification for request fields and supported operations.

版本与发布记录

@docker/sandboxes 共发布 8 个版本,首次发布于 2026/09/24;过去 12 个月发布了 8 个版本。

版本发布日期距今
0.53.0latest2026/10/071 个月前
0.52.02026/09/301 个月前
0.51.02026/09/261 个月前
0.50.02026/09/251 个月前
0.49.02026/09/241 个月前
0.48.02026/09/241 个月前

其他发布通道:bootstrap → 0.0.0。

关于 @docker/sandboxes 的常见问题

@docker/sandboxes 是什么?

TypeScript REST SDK for Docker Cloud Sandboxes, with typed HTTP and WebSocket streams.

如何安装 @docker/sandboxes?

在项目目录运行 npm install @docker/sandboxes,或使用 pnpm add / yarn add / bun add。

@docker/sandboxes 支持 TypeScript 吗?

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

@docker/sandboxes 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@docker/sandboxes 需要什么版本的 Node.js?

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

@docker/sandboxes 可以商用吗?

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

@docker/sandboxes 的下载量有多少?

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

@docker/sandboxes 还在维护吗?

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