−25%

Windows 按年付费,截至 10 月 31 日。 查看套餐

EQVPS
开始使用

5 分钟上手沙箱 TypeScript SDK:从 npm i @eqvps/sdk 到第一次运行

安装 @eqvps/sdk,在 Node.js、Deno 或 Bun 中启动 Firecracker 沙箱,在里面运行 Python、Node 和 shell 代码,传输文件,并实时查看长任务输出。六个步骤,每行代码都给出。

本教程从 JavaScript 或 TypeScript 中运行一个沙箱。你会启动一台隔离的 Firecracker 微虚拟机,用三种语言运行代码、传输文件,并查看长任务的输出。每一步都是一小段代码。

你需要 Node.js 18+(或 Deno、Bun)以及一个 EQVPS 账户。

1. 获取令牌

SDK 使用普通的账户令牌进行认证。连接账户页面介绍了如何从控制面板、API 或 MCP 服务器获取令牌。

export EQVPS_API_KEY="your-token"

没有余额的新账户第一次创建沙箱时会获得 1 美元沙箱额度,足够把本教程跑很多遍。

2. 安装 SDK

npm i @eqvps/sdk

示例使用 ES 模块和顶层 await。请保存为 .mjs 文件,或保存为 .ts 并用 npx tsx 运行。

3. 启动沙箱并运行代码

import { Sandbox } from "@eqvps/sdk";

await Sandbox.with({ tariff: "small" }, async (sb) => {
  console.log(sb.id);
  const r = await sb.run("import platform; print(platform.python_version())");
  console.log(r.exit_code, r.stdout);
});

输出是沙箱 id(sb_ 加 24 个字符),然后是 0 3.12.x。回调结束时 Sandbox.with 会删除沙箱,即使回调抛出异常也一样。

默认语言是 Python,另外两种只差一个选项:

await Sandbox.with({}, async (sb) => {
  const js = await sb.run("console.log(process.version)", { language: "node" });
  const sh = await sb.run("uname -r && nproc", { language: "bash" });
  console.log(js.stdout, sh.stdout);
});

失败的脚本不会抛出异常。请检查 r.ok:exit_code 为 0 且命令没有超时,它才为 true。

4. shell 命令和软件包

exec 接受 shell 字符串或 argv 数组。沙箱可以访问互联网,所以 npm 和 pip 安装都能用:

await Sandbox.with({ tariff: "small" }, async (sb) => {
  await sb.exec("mkdir -p /root/app && cd /root/app && npm init -y && npm i lodash", { timeout: 55 });
  const r = await sb.exec(["node", "-e", "console.log(require('/root/app/node_modules/lodash').VERSION)"]);
  console.log(r.stdout);
});

一次同步调用最多 55 秒,更长的任务放到后台任务里(第 6 步)。

5. 文件

await Sandbox.with({}, async (sb) => {
  await sb.upload("/root/input.json", JSON.stringify({ values: [3, 5, 8] }));
  await sb.run("import json; d = json.load(open('/root/input.json')); open('/root/out.txt', 'w').write(str(sum(d['values'])))");
  console.log(await sb.downloadText("/root/out.txt"));   // 16
});

upload 接受字符串或 Uint8Array。download 返回 Uint8Array,downloadText 返回字符串。单次传输上限 5 MB。

6. 带实时输出的长任务

await Sandbox.with({ tariff: "standard" }, async (sb) => {
  const task = await sb.exec("for i in 1 2 3 4 5; do echo step $i; sleep 20; done", { background: true });
  const res = await task.wait({ onOutput: (out) => process.stdout.write(out) });
  console.log(res.state, res.exit_code);   // done 0
});

任务会立即返回,没有 55 秒的限制。wait 默认每 2 秒轮询一次(可用 pollIntervalMs 修改)。task.kill() 停止任务;sb.task(id) 可以从另一个进程重新连接。

错误

import { Sandbox, InsufficientBalanceError, RateLimitError } from "@eqvps/sdk";

try {
  await Sandbox.with({}, async (sb) => console.log((await sb.run("print(1)")).stdout));
} catch (e) {
  if (e instanceof InsufficientBalanceError) console.log("Top up the balance");
  else if (e instanceof RateLimitError) console.log("Busy, retry in", e.retryAfter);
  else throw e;
}

服务器发送 Retry-After 时,SDK 会自动重试 429 和 503,最多 3 次。最常见的 429 来自同一账户同时运行超过两条命令。所有错误类型见 SDK 参考。

本教程的花费

每个示例只存在了几秒,按最低 60 秒计费:small 上 0.00055 美元,standard 上 0.0011 美元。第 6 步的任务在 standard 上运行约 100 秒,约 0.002 美元。全部加起来远不到 1 美分。完整价目见沙箱限制与计费。

下一步

常见问题

@eqvps/sdk 支持哪些运行时?

Node.js 18 及以上、Deno 和 Bun。它没有依赖,使用内置的 fetch,所以也能在浏览器中运行,但不要把账户令牌放进前端代码。

我的应用是 TypeScript 写的,沙箱能运行 Python 吗?

能。应用的语言和沙箱里代码的语言互不相关。run 的 language 可以是 python、node 或 bash,exec 可以运行任何 shell 命令。

怎样确保沙箱一定被删除?

使用 Sandbox.with(options, fn),fn 结束或抛出异常时都会删除沙箱。TypeScript 5.2 及以上还可以写 await using sb = await Sandbox.create()。

代码失败时 run 返回什么?

一个 exit_code 非零、错误信息在 stderr 中的 ExecResult,不会抛出异常。只有 API 错误才会抛异常,例如令牌无效或余额为零。

评论

暂无评论。来做第一个吧。

发表评论

评论在显示前会经过审核。