−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 錯誤才會拋異常,例如權杖無效或餘額為零。

評論

目前還沒有評論。歡迎成為第一位。

發表評論

評論在顯示前會經過審核。