@daytona/convex

中文文档
2.2.0发布于 2026/11/03Apache-2.0TypeScriptES Module零依赖构建来源已验证近 30 天下载 4220

Daytona 的 Convex 组件 —— 创建沙盒, 运行命令和代码, 管理您的 Convex 后端的 sandbox 文件, 并在反应 Convex 表格中跟踪 sandbox 和执行状态

中文使用文档
文档目录13 节
  1. 安装
  2. 使用量
  3. 沙盒生命周期
  4. 运行命令和代码
  5. 反应状态
  6. 文件
  7. 预览 URL
  8. 授权
  9. 保持沙盒状态同步( webhooks)
  10. 限制长期工作( L)
  11. 发展
  12. 出版
  13. 许可证

Convex 组件

npm version

运行 代顿a 来自您的 Convex 后端的沙盒: 创建孤立的沙盒, 执行 shell 命令和代码, 读取/ 写入文件, 并获得实时预览 URL —— 在您可以订阅的 被动 Convex 表格中跟踪沙盒和执行状态 .

// convex/agent.ts
import { Daytona } from "@daytona/convex";
import { v } from "convex/values";
import { components } from "./_generated/api";
import { action } from "./_generated/server";

const daytona = new Daytona(components.daytona);

export const codeInterpreter = action({
  args: { code: v.string() },
  handler: async (ctx, args) => {
    const { sandboxId } = await daytona.createSandbox(ctx, {
      autoStopInterval: 15,
    });
    const { result, exitCode } = await daytona.runCode(ctx, {
      sandboxId,
      code: args.code,
      language: "python",
    });
    return { result, exitCode };
  },
});

为什么一个组件不直接呼叫代托纳API?

  • 反应状态 ——每个沙盒和执行都记录在成份表中. 驱动代理UIs("running...",出站代码,输出历史)来自现场Convex查询而不是投票.
  • 单独记账 ——组件将表格保存在自己的命名空间;无法触摸到您的应用程序的数据,您的应用程序通过一个打入的客户端来管理.
  • 没有SDK捆绑 - 与代托纳REST API的会谈 fetch 在 Convex 默认运行时间中: 否 "use node"没有重的依赖性, 快速的寒冷开始.

安装

npm install @daytona/convex

设置您部署的代托纳 API 密钥( 在 app.daytona.io/dashboard/键盘:

npx convex env set DAYTONA_API_KEY dtn_...

然后创建或更新 convex/convex.config.ts 在你的应用程序。 组件不能读取您的应用程序的env vars,所以将密钥传递到组件:

// convex/convex.config.ts
import { defineApp } from "convex/server";
import { v } from "convex/values";
import daytona from "@daytona/convex/convex.config.js";

const app = defineApp({
  env: { DAYTONA_API_KEY: v.string() },
});
app.use(daytona, {
  env: { DAYTONA_API_KEY: app.env.DAYTONA_API_KEY },
});

export default app;

通过引用传递,意味着组件总是看到当前值,因此旋转键不需要再调用.

可选 : DAYTONA_API_URL (自主办实例;默认为 https://app.daytona.io/api) (中文(简体) ). 设相同相. 这不是一个秘密,所以它不需要通过:客户端通过每通电话转发.

使用量

用安装的组件为客户端提供证据 。 从您的部署环境变量中获取的证书决心, 或明确通过这些变量:

import { Daytona } from "@daytona/convex";
import { components } from "./_generated/api";

const daytona = new Daytona(components.daytona);
// or: new Daytona(components.daytona, { apiKey: "dtn_..." })

runBackground 是例外: 它总是使用传递到组件的密钥 convex.config.ts。 。 。 .

沙盒生命周期

export const create = action({
  args: {},
  handler: async (ctx) => {
    return await daytona.createSandbox(ctx, {
      snapshot: "my-snapshot",     // optional — org default when omitted
      autoStopInterval: 15,        // pause after 15 idle minutes (fs preserved)
      autoDeleteInterval: -1,      // never auto-delete
      userKey: "user_123",         // scope sandboxes to a user/agent (see below)
    });
    // → { sandboxId: "…", state: "started" }
  },
});

从一个 简介 (你的,或兽类默认) 或者说 由 Docker 创建 图像 ——通过一个或另一个. cpu编号 :memory编号 :disk 仅适用于基于图像的创建; 快照定义了自己的资源 :

await daytona.createSandbox(ctx, { image: "python:3.12", cpu: 2, memory: 4 });

要跨越沙盒共享或粘接文件, 请挂起 代托纳卷。只有创建了沙盒,才能将音量挂起;用代托纳SDK、CLI或仪表板创建音量本身,并等待它 ready数字 :

await daytona.createSandbox(ctx, {
  volumes: [
    { volumeId: "shared-models", mountPath: "/home/daytona/models" }, // volume ID or name
    { volumeId: "tenants", mountPath: "/home/daytona/data", subpath: "users/alice" }, // only this prefix
  ],
});

还提供: startSandbox, (中文(简体) ), stopSandbox, (中文(简体) ), deleteSandbox,以及 refreshSandbox (将远程状态重新同步到组件的表格;返回) null 如果沙盒已经不复存在).

运行命令和代码

const { executionId, exitCode, result } = await daytona.run(ctx, {
  sandboxId,
  command: "python train.py",
  cwd: "/home/daytona/project",
  timeoutSeconds: 300,
});

const py = await daytona.runCode(ctx, {
  sandboxId,
  code: "print(sum(range(10)))",
  language: "python",
});

一个已停止或存档的沙盒首先透明地重新启动( 无法使用) autoStart: false) (中文(简体) ). 每一个电话记录一个行刑行(running → completed编号 :failed)带有被截断的输出,因此历史和状态是可以查询的.

对于长期运行的命令, runBackground 在沙盒会话中启动命令并立即返回 —— 启动行动没有在命令的持续时间内开放(而是定期进行轻量级调度器驱动的计票员检查), 命令不受10分钟行动上限的约束 :

const { executionId } = await daytona.runBackground(ctx, {
  sandboxId,
  command: "python train.py",
  cwd: "/home/daytona/project",
});
// Watch it reactively: a scheduler-driven poller streams logs into the row
// while it runs and records the exit code when it finishes.
export const training = query({
  // Component table IDs cross the boundary as plain strings.
  args: { executionId: v.string() },
  handler: async (ctx, args) => daytona.getExecution(ctx, args),
});

当命令完成时(而不是投票时),让你的后端作出反应,通过一个 onComplete 突变——组件在每个终端状态上引用(completed, (中文(简体) ), failed,或 cancelled结果和可选 context 您提供 :

const { executionId } = await daytona.runBackground(ctx, {
  sandboxId,
  command: "cargo build",
  onComplete: internal.build.buildFinished, // (ctx, { executionId, status, exitCode, result, error, context })
  onCompleteContext: { appId },
  minPollMs: 500,   // first poll + backoff floor (default 1000, min 250)
  maxPollMs: 5000,  // backoff ceiling (default 10000, max 120000)
});

取消正在运行的背景执行 daytona.cancelExecution(ctx, { executionId }) 它停止命令( 杀死它的会话) , 标记行 cancelled,并发射 onComplete 处理者.

运行的背景命令不会重置沙盒 闲置自动停止计时器 - 为长工创建沙盒 autoStopInterval: 0。 。 。 .

runBackground 需要按 安装它的传粉器从排程器,在你的任何电话之外, 所以它读到 DAYTONA_API_KEY 而不是用预定的函数参数来表示.

反应状态

他们阅读了组件的表格

export const sandboxes = query({
  args: {},
  handler: async (ctx) => daytona.listSandboxes(ctx, { userKey: "user_123" }),
});

export const executions = query({
  args: { sandboxId: v.string() },
  handler: async (ctx, args) => daytona.listExecutions(ctx, args),
});

还: getSandbox, (中文(简体) ), getExecution。 。 。 .

文件

await daytona.writeFile(ctx, { sandboxId, path: "/home/daytona/app.py", content });
const text = await daytona.readFile(ctx, { sandboxId, path: "/home/daytona/app.py" });
const entries = await daytona.listFiles(ctx, { sandboxId, path: "/home/daytona" });
await daytona.deleteFile(ctx, { sandboxId, path: "/home/daytona/tmp", recursive: true });

readFile编号 :writeFile 将内容移动为 UTF-8 字符串——代码、配置和日志的正确默认值。 对于二进制文件(图像、PDF、档案),使用字节变体,通过生 ArrayBuffer穿过未触及的:

const png = await daytona.readFileBytes(ctx, { sandboxId, path: "/home/daytona/chart.png" });
await ctx.storage.store(new Blob([png], { type: "image/png" })); // e.g. into Convex file storage

await daytona.writeFileBytes(ctx, { sandboxId, path: "/home/daytona/data.zip", content: zipBuffer });

无论哪种方式,文件内容都会跨越 Convex 函数边界,所以将单个文件保留在 Convex 的 16 MiB 参数/返回限制下.

预览 URL

const { url } = await daytona.getPreviewUrl(ctx, { sandboxId, port: 3000 });

已签名的 URL( 默认) 嵌入一个短命符; pass signed: false 用于标准 URL + 符号对.

授权

组件看不到你的应用程序 ctx.auth - 认证在自己的功能和瞄准镜沙箱中的呼叫者 userKey数字 :

export const mySandboxes = query({
  args: {},
  handler: async (ctx) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) throw new Error("Unauthorized");
    return await daytona.listSandboxes(ctx, { userKey: identity.subject });
  },
});

保持沙盒状态同步( webhooks)

Sandbox记录反映了组件最后观察到的内容. 当代托纳独自改变一个沙盒(自动停止,自动存档,自动删除)时,记录会延后到呼叫 refreshSandbox保留 sandboxes 列表在实时同步中连接一个代顿纳 Webhook。 选入,并分出三个步骤:

1. 挂载组件的网路并传递秘密 内 convex/convex.config.ts数字 :

const app = defineApp({
  env: {
    DAYTONA_API_KEY: v.string(),
    DAYTONA_WEBHOOK_SECRET: v.optional(v.string()),
  },
});
app.use(daytona, {
  httpPrefix: "/daytona/",
  env: {
    DAYTONA_API_KEY: app.env.DAYTONA_API_KEY,
    DAYTONA_WEBHOOK_SECRET: app.env.DAYTONA_WEBHOOK_SECRET,
  },
});

2. 在 Daytona Dashboard 中创建一个网点 (单位:千美元)如何创建终点:

  • 端点 URL数字 : https://<your-deployment>.convex.site/daytona/webhook (您的部署中的 HTTP 动作 URL, 加上上面的前缀)
  • 活动: 订阅 sandbox.state.updated。该组件忽略了所有其他事件,因此订阅其他任何信息只会产生额外交付.

在 戴托纳组织和你 DAYTONA_API_KEY:webhooks是每个组织,所以另一个org中的一个终点从未收到你的沙盒事件.

3. 将端点签名的秘密复制到您的部署中. Daytona 生成签名密钥( 开始于 whsec_对于每一个端点,你创建 并签注每一次送货。 在代托纳板 网络呼号 页面,单击端点表格中的端点;其细节显示签名秘密,准备复制。 设定为您的 Convex 部署 :

npx convex env set DAYTONA_WEBHOOK_SECRET whsec_...

从那时起 代托纳的每个州都出现了 getSandbox编号 :listSandboxes 事情就是这样 譬如说, listSandboxes(ctx, { state: "started" }) 成为准确的活计。 每一次送货的签名都经过验证(超过5分钟的货被拒),尽可能重复播放. 重复交付和订单外交付自动处理。 沙盒事件 这个部署没有被确认和忽略, 因为一个端点接收到你组织的每一个沙盒。 如果秘密没有设定的话,路线会拒绝所有的交货.

限制长期工作( L)

  • 10分钟后对流动作暂停,所以同步 run编号 :runCode 命令始终被限制在该上限以下: timeoutSeconds 默认值为540,上限为570。 用于较长的工作 runBackground 它没有期限,也没有采取行动.
  • 沙盒和行刑行作为审计历史保存. 他们从不清理自己 daytona.purgeSandboxes(ctx, { olderThanMs }) 财务报告和审定财务报表 daytona.purgeExecutions(ctx, { olderThanMs }) (每个呼叫返回) hasMore;只有终端行,远程沙盒没有被移动). listSandboxes 接受一个 state 过滤器(例如). "started" )和 listSandboxesPaginated 提供光标页.
  • 存储的执行输出被截取( 64 KB); 动作的返回值载出最多 4 MB.
  • 运行时沙盒成本: 设置 autoStopInterval,并删除你用完的沙盒. refreshSandbox 核对索要的记录; 网络用户 所有记录自动同步.

见 实例/会议/实例 一个完整的实例应用程序.

找到窃听器了吗? 特质请求? 放在这。 。 。 .

发展

这个包裹住在 daytona/integrations 单重 packages/convex 并且自成一体的 package.json,锁定文件,没有工作空间工具.

git clone https://github.com/daytona/integrations
cd integrations/packages/convex
npm install

组件 src/component/_generated 代码被承诺; 在改变组件函数后重生 :

npx convex init           # one-time: bootstrap a local anonymous deployment
npm run codegen           # component codegen (src/component/_generated)
npx convex codegen        # example app codegen (example/convex/_generated)

检查 :

npm run build             # compile to dist/
npm run typecheck         # package sources
npm run typecheck:example # example app (needs codegen above)
npm test                  # offline unit tests (mocked Daytona API)
npm run test:live         # live E2E: local Convex deployment + real Daytona (needs DAYTONA_API_KEY)

npm run dev 启动 Convex dev 部署服务, 为示例应用服务 —— set DAYTONA_API_KEY 用来对抗真正的沙盒.

出版

释放是自动的 请放行:将这个软件包的"放出PR"标签合并,并从repo的放出工作流程发布到npm(公开,有出处).

许可证

阿帕奇 - 2.0

版本与发布记录

@daytona/convex 共发布 6 个版本,首次发布于 2026/09/24;过去 12 个月发布了 6 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
2.2.0latest2026/11/038 天前
2.1.02026/10/101 个月前
2.0.02026/10/021 个月前
1.1.02026/09/301 个月前
1.0.02026/09/251 个月前
0.0.02026/09/241 个月前

关于 @daytona/convex 的常见问题

@daytona/convex 是什么?

Daytona 的 Convex 组件 —— 创建沙盒, 运行命令和代码, 管理您的 Convex 后端的 sandbox 文件, 并在反应 Convex 表格中跟踪 sandbox 和执行状态

如何安装 @daytona/convex?

在项目目录运行 npm install @daytona/convex,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:convex(^1.43.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@daytona/convex 支持 TypeScript 吗?

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

@daytona/convex 支持 ESM 还是 CommonJS?

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

@daytona/convex 可以商用吗?

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

@daytona/convex 的下载量有多少?

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

@daytona/convex 还在维护吗?

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