# @decocms/sandbox-controller 中文文档

规范地址：https://npmcn.com/package/%40decocms/sandbox-controller/

版本：0\.19\.0
npm 元数据更新时间：2026-11-10T18:28:39.285Z
中文译文更新时间：2026-11-11T19:36:05.173Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40decocms/sandbox-controller
原文对照：https://npmcn.com/package/%40decocms/sandbox-controller/?lang=original
项目主页：https://github.com/decocms/studio#readme
源码仓库：https://github.com/decocms/studio

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：639 kB，6 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：1 个
- peer 依赖：zod ^4\.3\.6，postgres ^3\.4\.5，@opentelemetry/api ^1\.9\.0
- 首次发布：2026-09-29T13:20:30.878Z
- 最新版本发布：2026-11-10T18:28:38.897Z
- 近 30 天下载量：4935（2026-10-12 至 2026-11-10，npm 官方下载统计）
- 已发布版本数：50（近 12 个月 50 个）

## 中文简介

运行工作室的代理沙盒 在Kubernetes, 并服务于远程工作室.

## 安装

```sh
npm install @decocms/sandbox-controller
```

也可以使用：`pnpm add @decocms/sandbox-controller`、`yarn add @decocms/sandbox-controller`、`bun add @decocms/sandbox-controller`

## README

# @ decocms/ sandbox- 控制器

运行工作室代理沙盒在Kubernetes上 服务于工作室外 服务于工作室 作为远程供应商.

| 属性 | 数值 |
| --- | --- |
| 工作空间 | `@decocms/sandbox-controller` (单位:千美元)`packages/sandbox-controller`(中文(简体) ) |
| 仁爱 | 公共图书馆,从 `@decocms/sandbox` |
| 运行时间 | 阿宝 |
| 分发 | 公共 npm 软件包 |

## 概览

沙盒控制器是一个库,不是服务. 一个主机进程—— deco's 分组, `decocms/control-plane` - 依赖它,建立一个 `AgentSandboxProvider` 并服务于沙盒 API. 录音室的 `RemoteSandboxProvider` (单位:千美元)`@decocms/sandbox/provider/remote`(电话) 当API `STUDIO_SANDBOX_CONTROL_PLANE_URL` 已设定; 没有它, Studio 运行 同一供应商在进程中.

软件包再导出代码 `@decocms/sandbox` 财务报告和审定财务报表 `@decocms/shared`, (中文(简体) ), 秘密地把它捆入一个有申报的模块.

## 责任

-   导出 `AgentSandboxProvider`,其选项和状态存储类型,以及 `kubeConfigForServer`,用于本地代理的无证书的 kubeconfig, 已建 和软件包的客户端.
-   导出 `migrateSandboxControllerSchema`,用于创建和升级 图书馆自己的 `sandbox_controller` Postgres schema, 以及里面的商店: `postgresRunnerStateStore`页:1 `RunnerStateStore` (数量) `scope` 保留多个 在一个数据库中将主机或环境的行和锁分开),以及 `postgresTenantPoolStore`每个沙盒组的租户暖水池 `tenantPoolReader`,用于提供者的缓存列表 `tenantPools`。 。 。 .
-   导出租户池模型 : `TenantPool` 财务报告和审定财务报表 `TenantPoolRepo`他们 校验符( e)`tenantPoolSchema`, (中文(简体) ), `tenantPoolFieldsSchema`, (中文(简体) ), `tenantPoolRepoSchema`, (中文(简体) ), `normalizeRepoUrl`,以及 `renderTenantPoolWarmPools`,它建立一个游泳池 `SandboxWarmPool` 对象供主机应用.
-   导出 `FreestyleSandboxProvider` (散装箱作为 Freestyle VM)和 `SandboxProviderRouter`服务于库伯内兹和弗里斯泰特 提供者; 见 [`packages/sandbox`](https://npmcn.com/package/%40decocms/sandbox/README.md)。 。 。 .
-   将电线合同导出 `sandbox-api`: 工具名称和计划,以及 监视路线.
-   导出主机助手 : `sandboxTools` (无框架工具定义), `sandboxWatchResponse` (称为SSE阶段), `PushedCredentials` (单位:千美元) 证书工作室推倒的记忆存储)和 `pushedCredentialOptions` (提供商的薄荷钩 在商店.

## 使用量

```ts
import {
  AgentSandboxProvider,
  kubeConfigForServer,
  migrateSandboxControllerSchema,
  postgresRunnerStateStore,
  postgresTenantPoolStore,
  PushedCredentials,
  pushedCredentialOptions,
  renderTenantPoolWarmPools,
  sandboxTools,
  sandboxWatchResponse,
  tenantPoolReader,
} from "@decocms/sandbox-controller";

// At boot, before any store serves a call. Each store opens its own pool.
await migrateSandboxControllerSchema({ url: databaseUrl });
const stateStore = postgresRunnerStateStore({ url: databaseUrl });
const poolStore = postgresTenantPoolStore({ url: databaseUrl });
// The host's admin surface writes pools and their repo allocations.
await poolStore.upsertPool("sandbox-cluster-1", {
  name: "acme",
  tenant: orgId,
  size: 4,
});
const acme = await poolStore.setRepos("sandbox-cluster-1", "acme", [
  { repoUrl: "https://github.com/acme/site", replicas: 2 },
]);
// The host applies these; the provider only binds and warms their pods.
const warmPools = renderTenantPoolWarmPools(acme!, {
  templateName: "studio-sandbox-prod",
});
const pools = tenantPoolReader(poolStore, "sandbox-cluster-1");
await pools.start();

// Memory only: a restart forgets it until Studio's next push.
const credentials = new PushedCredentials();

const provider = new AgentSandboxProvider({
  // The host's local proxy to the cluster; it authenticates on its own.
  kubeConfig: kubeConfigForServer("http://127.0.0.1:7777"),
  // Reach daemons the host's way instead of an apiserver port-forward.
  forwardPort: (pod, port) => openDaemonForward(pod, port),
  stateStore,
  // Warm-pool mode; tenant pools need it.
  sentinelToken,
  // Read on every ensure, push and reconcile tick: a synchronous snapshot.
  tenantPools: pools.current,
  // Mint hooks that read the store, and `persistCredentials: false`.
  ...pushedCredentialOptions(credentials),
});

// Wrap each definition in the host's tool type, behind the host's auth.
const tools = sandboxTools(() => provider, credentials);

// GET /api/sandbox/watch?handle=… behind the same auth.
const watch = (req: Request, handle: string) =>
  sandboxWatchResponse(provider, handle, req.signal);
```

## 建筑

```text
Studio ──MCP tools + SSE watch──▶ host (this library) ──▶ Kubernetes
Studio ──────── daemon and preview traffic ────────────▶ sandbox pod
```

主机回答沙盒守护进程在哪里, 哪个持卡人打开它; Studio 拨打守护进程本身( n)`daemonAddress: "service"` 解答分组 服务 URL. 控制平面没有集群证书:其库贝和 守护进程呼叫是沙盒操作 它的集群数据飞机代理运行 (单位:千美元)`decocms/operator` `internal/agent/ops.go`) (中文(简体) ).

### 租户暖水池

一个租户池是留给一个租户的温室容量: `size` 已建舱 从游泳池 `image`。租户是一个不透明的钥匙;供货商比较它 与索赔的租户密钥,即索赔用户的Org id. 重置为 顶部的可选分配 : `{ repoUrl, branch, workload, replicas }` 带 `replicas` 并不断复制、安装和复制 运行 Repo 的 Dev 服务器 。 分配的复制品最多加到 `size`其余的都是空白的温室, 复制在捆绑上像通用的 游泳池的。 游泳池的吗. `repoUrl` 是一个无证书的 https 克隆 URL,已正常存储 : 小写主机, 没有用户信息, 没有线索 `.git` 或者说 `/`。 。 。 .

操作员绑定任何温室 `SandboxWarmPool` 索赔名称,以及 守护进程拒绝将一个被克隆的吊舱移动到另一个 repo, 因此每次分配 这是它自己的 `SandboxWarmPool`。 。 。 . `renderTenantPoolWarmPools(pool, { templateName })` 返回每个分配符中的一个,命名 `<pool>-<8 hex of repoUrl#branch>`,和一个空白的,命名 `<pool>` 与 剩下的复制品,即使0点也做成 这样就应用了收缩器 他们都用 页:1 `-medium` 游泳池图像模板, 即一个有约束要求的模板 名称。 主机应用并删除这些对象; 库从来不写 他们.

一项索赔按其顺序对下列事项具有约束力: repo,在索赔的分行(如果有),其他的分行;其租户的空白 舱; 通用池. 只有一个池子,它的图像是要求的图像 合格,没有空白复制品的游泳池被跳过。 调和器暖和 仅分配吊舱,每波德刷新和故障后退;空白吊舱是 由约束它的权利要求所配置。 供应商把池子当作 `tenantPools`,列表或函数,并在每次使用时读取函数,所以 更改在下一个保证和对齐时生效,而不重新启动. 调和器会忘记一个被删除的分配器的吊舱,并且会使其深度计为零. `markTenantPoolsDirty(repoUrl, ref)` 刷新该 repo 上的配置 和树枝相接.

### 全权证书

主持人从不给工作室打电话. 只有工作室才能做薄荷(clone sorders, org-fs API 键) 到达它有两个方法: `SANDBOX_ENSURE` 带着他们 保持有效多久,每10分钟工作室打电话 `SANDBOX_LIST` (租户和回购户,以及每个游泳池的名称、租户、形象和回购分配, (没有全权证书),然后 `SANDBOX_CREDENTIALS_PUSH`工作室处理 列表为不信任 : 它只对租户使用薄荷, 而用户是其中的一员 ,并且仅用于连接或寄存器属于 那个鸟人 对于一个游泳池,它只从它自己的寄存器记录中取出薄荷 org 由该游泳池的租户命名,其克隆 URL 与所列 URL 相匹配 推一无相. 集合证书以下列方式送达: `poolCloneUrls`键入 租户和收回的URL,以及 `pushedCredentialOptions` 把他们交给 分配舱. `STUDIO_SANDBOX_TENANT_POOLS` 仅配置池 Studio的流程中供应商;带有控制平面,Studio忽略了它. 商店保存每个条目的过期, 从未替换一个寿命更长的条目 更短的,当一个入口的生命减少时, 以一无所有的方式回答再薄荷 离跑者要求的远 与 `persistCredentials: false` 坚持 状态不保留克隆令牌、子模块令牌或org-fs配置;恢复需要 他们从商店。 在主机重启后, 沙盒在下次启动前恢复 推力只有在10分钟后才能有证书.

### 存储

州立商店每个沙盒保留一行 `sandbox_controller.runner_state`, (中文(简体) ), 与 Studio 的同名语义库在进程商店. `withLock` 序列化 用交易范围为复制品提供一个沙盒 由用户和项目管理员键入的咨询锁定; 等待时间超过 90秒( 秒数 )`lockWaitMs`)获得可重试的"沙箱咨询锁"繁忙出错. 每个锁持有人都保持连接 整个供给,所以商店 打开自己的集合 `maxConnections` (违约4)而不是共享 东道方; `close()` 结束它。 主机运行 `migrateSandboxControllerSchema` 在靴子时; 店里从不独自迁移 迁移是天能的 并且持有 咨询锁,所以每个复制品可以同时运行. 应用版本为: 记录 `sandbox_controller.migrations`。 。 。 . `state` 嵌入短寿命 证书;永远不要登录.

游泳池店每游泳池一排 `sandbox_controller.tenant_pools`, (中文(简体) ), 单个的集群和名称,所以一个数据库可以服务于多个沙盒 组,每个分配单位一行 `sandbox_controller.tenant_pool_repos`, (中文(简体) ), 按池、 repo URL 和分支并与其池一起删除. `upsertPool(cluster, pool)` 用 `tenantPoolFieldsSchema` 创建 或更新该名称的池,保留其原样,但抛出 `TenantPoolConflictError` 当这个名字属于另一个租户时: 它的温暖的舱 保持租户的退房. `setRepos(cluster, name, repos)` 用 `tenantPoolRepoSchema` 并替换一个池的所有分配 ,当没有这样的池时,则无效回答。 都锁上泳池一行 掷出 `TenantPoolCapacityError` 而不是让分配额超过 尺寸. `deletePool` 回答是否删除了游泳池; `list(cluster)` 返回时 组群的池与它们的回放. `tenantPoolReader(store, cluster)` 装入集群的池 `start()`打开 `refresh()` 和每个 `refreshMs` (默认为30秒); `current()` 同步回答上次加载的列表。 保存失败的负载 最后的列表, 以及一个在更新的列表被丢弃后完成的负载。 写作 从另一个复制到读者的下个勾点; 作者自己的 进程可以调用 `refresh()` 马上.

### 看着

监视路由中每写一个 SSE 保留评论 `SANDBOX_WATCH_KEEPALIVE_MS`。工作室读取表作为主持人的标志 生活:它重新连接了一条流水, 放弃了只给养电话 在宿主沉默了4个守口如瓶后.

## 发展

```bash
bun run --cwd=packages/sandbox-controller build   # dist/index.js + index.d.ts
bun run --cwd=packages/sandbox-controller pack    # dist/sandbox-controller.tgz
bun test packages/sandbox/server/provider/remote.test.ts
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres \
  bun test packages/sandbox/server/provider/postgres-state-store.integration.test.ts
```

本地主机可以依赖包装的柏油球 `bun add @decocms/sandbox-controller@file:<path>/dist/sandbox-controller.tgz`。 。 。 .

## 边界

-   主机拥有授权:工具没有自己的授权.
-   默认 `daemonAddress: "forward"`,守护进程地址是 主机本身 `127.0.0.1` 前进,只能从同一机器上到达.
-   来源于 `packages/sandbox`换个位置 改为a 被捆绑的源头在发布时碰倒了这个软件包的版本,由它发布.
-   `zod`, (中文(简体) ), `@opentelemetry/api` 财务报告和审定财务报表 `postgres` 是同级依赖关系: 主办单位 `zod` 解析导出的计划, 提供者的测量选项是 `@opentelemetry/api` 类型,并运行在主机上 `postgres`。 。 。 .

## 相关文件

-   [`packages/sandbox`](https://npmcn.com/package/%40decocms/sandbox/README.md)
-   [`apps/api`](https://npmcn.com/package/apps/api/README.md)

## 常见问题

### @decocms/sandbox-controller 是什么？

运行工作室的代理沙盒 在Kubernetes, 并服务于远程工作室\.

### 如何安装 @decocms/sandbox-controller？

在项目目录运行 npm install @decocms/sandbox-controller，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：zod（^4\.3\.6）、postgres（^3\.4\.5）、@opentelemetry/api（^1\.9\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @decocms/sandbox-controller 支持 TypeScript 吗？

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

### @decocms/sandbox-controller 支持 ESM 还是 CommonJS？

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

### @decocms/sandbox-controller 可以商用吗？

@decocms/sandbox-controller 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @decocms/sandbox-controller 的下载量有多少？

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

### @decocms/sandbox-controller 还在维护吗？

最新版本 0\.19\.0 发布于 2026/11/11（1 天前）；至今共发布 50 个版本，其中过去 12 个月发布了 50 个；首次发布于 2026/09/29。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

