@ deno/ sandbox (英语)
在 Deno 部署上创建孤立的沙盒, 在轻量级 Linux 微VM 中安全运行代码 。 你个 可以安全运行 shell 脚本, 产卵过程, 执行 JavaScript 应用程序和 RePL,以及 远程与文件交互.
此类型脚本/ JavaScript SDK 允许您从 Deno 程序创建和管理沙盒 节点.js.
说明: Bun 不支持 。 包替换
wsWebSocket 具有本地特性的库 执行,不支持upgrade用于沙盒连接的事件。 见 烤箱-sh/bun#5951 详细情况.
特征
- 创建安全、孤立和麻黄的Linux微VM沙盒,以执行任意代码和 子进程.
- 在沙盒内运行任意的 shell 命令和脚本 .
- 在沙盒中运行JavaScript应用程序和REPL.
- 在沙盒中安装国家预防机制和JSR软件包.
- 执行网络框架 Dev 服务器, 如 Vite 或
next dev。 。 。 . - 简单地执行 JS 代码的片段,一个接一个,在片段之间保持状态 由人工智能代理逐渐生成的代码
- 通过随机和安全的HTTPS URL将沙盒中的任何HTTP端点向公共互联网曝光.
- 获取 SSH 访问沙盒进行交互调试.
- 将本地文件或目录上传到沙盒中 .
- 控制沙盒超时和内存分配.
- 限制沙盒网络访问特定主机/ 使用
allowNet。 。 。 .
安装
# Using Deno
deno add jsr:@deno/sandbox
# Using npm
npm install @deno/sandbox
# Using pnpm
pnpm install jsr:@deno/sandbox
# Using yarn
yarn add jsr:@deno/sandbox
运行时间支持
此 SDK 测试和支持于 :
- 德诺: 最新稳定版本
- 节点.js页:1
说明: await using 例子中的语法需要节点.js 24+. 对于早期的Node.js版本,
使用情况 try编号 :finally 块取而代之(参见 兼容性说明) (中文(简体) ).
快速启动
-
转到“ 样式” 标签 部署仪表板。 。 。 .
-
创建访问符并设定为
DENO_DEPLOY_TOKEN环境变量. -
使用
@deno/sandboxSDK来创建一个新的沙盒,并与它互动.
import { Sandbox } from "@deno/sandbox";
await using sandbox = await Sandbox.create();
await sandbox.sh`ls -lh /`;
APIs 密码
实例
下面的片段假设 package.json 包含 { "type": "module" },则 @deno/sandbox
软件包已安装,而且 DENO_DEPLOY_TOKEN 已经准备好了.
评估联署材料片断
import { Sandbox } from "@deno/sandbox";
await using sandbox = await Sandbox.create();
const result = await sandbox.deno.eval(`
const a = 1;
const b = 2;
a + b;
`);
console.log("result:", result);
复制一个子进程, 并获得缓冲输出
import { Sandbox } from "@deno/sandbox";
await using sandbox = await Sandbox.create();
const text = await sandbox.sh`pwd`.text();
console.log("result:", text); // → "/home/sandbox\n"
Tip: 对于长跑进程或大输出, 流出 stdout/ stderr .
创建一个 packet.json, 安装 dips, 运行一个网页框架( Express), 并公开曝光
这在沙盒内部创造了一个最小的Express应用程序,在3000端口运行,并公开曝光
使用 sandbox.exposeHttp()。 。 。 .
import { Sandbox } from "@deno/sandbox";
await using sandbox = await Sandbox.create();
// 1) Write package.json and server.js in the sandbox
const PACKAGE_JSON = {
name: "sandbox-express-demo",
private: true,
type: "module",
dependencies: { express: "^4.19.2" },
};
await sandbox.fs.writeTextFile("package.json", JSON.stringify(PACKAGE_JSON, null, 2));
await sandbox.fs.writeTextFile(
"server.js",
`import express from 'express';
const app = express();
app.get('/', (req, res) => res.send('Hello from Express in @deno/sandbox!'));
app.get('/time', (req, res) => res.json({ now: new Date().toISOString() }));
app.listen(3000, () => console.log('listening on :3000'));
`,
);
// 2) Install dependencies
await sandbox.sh`deno install`;
// 3) Start the server
const server = await sandbox.deno.run({ entrypoint: "server.js" });
// 4) Publish to the internet
const publicUrl = await sandbox.exposeHttp({ port: 3000 });
console.log("Public URL:", publicUrl); // e.g. https://<random>.sandbox.deno.net
// Fetch from your local machine to verify
const resp = await fetch(`${publicUrl}/time`);
console.log(await resp.json());
// Keep the process alive as long as you need; when done, closing the sandbox
// will tear it down.
让 SSH 进入沙盒
import { Sandbox } from "@deno/sandbox";
await using sandbox = await Sandbox.create();
// Get SSH credentials
const { hostname, username } = await sandbox.exposeSsh();
console.log(`ssh ${username}@${hostname}`);
// Keep the process alive by sleeping, otherwise the sandbox will be destroyed
// when the script exits.
await new Promise((resolve) => setTimeout(resolve, 10 * 60 * 1000)); // 10 minutes
交互式 Java 脚本 REPL
import { Sandbox } from "@deno/sandbox";
await using sandbox = await Sandbox.create();
// Start a Deno REPL
const repl = await sandbox.deno.repl();
// Execute code interactively, maintaining state
await repl.eval("const x = 42;");
await repl.eval("const y = 8;");
const result = await repl.eval("x + y");
console.log("result:", result); // 50
VSCode 浏览器实例
import { Sandbox } from "@deno/sandbox";
await using sandbox = await Sandbox.create();
// Start a VSCode instance
const vscode = await sandbox.exposeVscode();
console.log(vscode.url); // print the url of the running instance
await vscode.status; // wait until it exits
带有可变插件的模板字面命令
import { Sandbox } from "@deno/sandbox";
await using sandbox = await Sandbox.create();
// Variables are automatically escaped
const filename = "file with spaces.txt";
const content = "Hello, world!";
await sandbox.sh`echo ${content} > ${filename}`;
// Arrays are expanded to multiple arguments
const files = ["file1.txt", "file2.txt", "file3.txt"];
await sandbox.sh`rm ${files}`;
// Get JSON output
const data = await sandbox.sh`echo '{"count": 42}'`.json<{ count: number }>();
console.log(data.count); // → 42
无 Throw 处理出错 ()
import { Sandbox } from "@deno/sandbox";
await using sandbox = await Sandbox.create();
// Commands throw by default on non-zero exit
try {
await sandbox.sh`exit 1`;
} catch (error) {
console.log("Command failed:", error);
}
// Use noThrow() to handle errors manually
const result = await sandbox.sh`exit 1`.noThrow();
console.log("Exit code:", result.status.code); // → 1
console.log("Success:", result.status.success); // → false
命令取消
import { KillController, Sandbox } from "@deno/sandbox";
await using sandbox = await Sandbox.create();
// Start a long-running command
const controller = new KillController();
const cmd = sandbox.sh`sleep 30`.signal(controller.signal);
const promise = cmd.text();
// Cancel after 2 seconds
setTimeout(() => {
controller.kill(); // Kill the process
}, 2000);
try {
await promise;
} catch (error) {
console.log("Command was cancelled:", error);
}
访问字符串和二进制输出
import { Sandbox } from "@deno/sandbox";
await using sandbox = await Sandbox.create();
// Get both string and binary data
const result = await sandbox.sh`cat binary-file.png`
.stdout("piped");
console.log("Binary length:", result.stdout!.length);
console.log("Text length:", result.stdoutText!.length);
// Use the binary data
import fs from "node:fs";
fs.writeFileSync("output.png", result.stdout!);
处理自定义错误类别出错
import { Sandbox, SandboxCommandError } from "@deno/sandbox";
await using sandbox = await Sandbox.create();
try {
await sandbox.sh`exit 42`;
} catch (error) {
if (error instanceof SandboxCommandError) {
console.log("Exit code:", error.code); // → 42
console.log("Error message:", error.message);
}
}
设置环境变量
import { Sandbox } from "@deno/sandbox";
await using sandbox = await Sandbox.create();
// Set environment variables
await sandbox.env.set("API_KEY", "secret-key-123");
await sandbox.env.set("NODE_ENV", "production");
// Use them in a script
const apiKey = await sandbox.sh`echo $API_KEY`.text();
console.log("API_KEY:", apiKey.trim());
将命令输出流到本地文件
child.stdout 是一个网络 ReadableStream在节点中,转换节点 fs.WriteStream 到网络
WritableStream 以高效的管道.
import { Sandbox } from "@deno/sandbox";
import fs from "node:fs";
import { Writable } from "node:stream";
await using sandbox = await Sandbox.create();
// Create a large file in the sandbox
await sandbox.fs.writeTextFile("big.txt", "#".repeat(5_000_000));
// Stream it out to a local file
const child = await sandbox.spawn("cat", {
args: ["big.txt"],
stdout: "piped",
});
const file = fs.createWriteStream("./big-local-copy.txt");
await child.stdout.pipeTo(Writable.toWeb(file));
const status = await child.status;
console.log("done:", status);
上传本地文件或目录
使用 sandbox.upload(localPath, sandboxPath)。 。 。 .
import { Sandbox } from "@deno/sandbox";
await using sandbox = await Sandbox.create();
// Upload a single file to a specific path in the sandbox
await sandbox.fs.upload("./README.md", "./readme-copy.md");
// Upload a local directory tree into the sandbox current directory
await sandbox.fs.upload("./my-project", ".");
控制沙盒超时
你可以控制你的沙盒能活多久 用它 timeout 选项 :
import { Sandbox } from "@deno/sandbox";
// Default: "session" - sandbox shuts down when you close/dispose the client
await using sandbox = await Sandbox.create({ timeout: "session" });
import { Sandbox } from "@deno/sandbox";
// Duration-based: keep sandbox alive for a specific time period
// Useful when you want the sandbox to persist after the script exits
const sandbox = await Sandbox.create({ timeout: "5m" }); // 5 minutes
const id = sandbox.id;
// Close the *connection* to the sandbox; the sandbox keeps running
await sandbox.close();
// Later, reconnect to the same sandbox using its ID
const reconnected = await Sandbox.connect(id);
await reconnected.sh`echo 'Still alive!'`;
// You can still forcibly terminate it before its timeout expires
await reconnected.kill();
// At this point, the sandbox is no longer reconnectable
支持的持续时间后缀 : s (秒数), m (分钟). 实例: "30s", (中文(简体) ), "5m", (中文(简体) ), "90s"。 。 。 .
需要其他超时模式吗 ? 联系人 部署@ deno.com。 。 。 .
配置沙盒内存
您可以使用 : memory 选项。 这个
允许您为内存密集的工作量分配更多资源,或减少较轻的内存
任务.
这个 memory 选项支持带有二进制(GiB, MiB, KiB)或小数(GB, MB,
kB) 单位,以及平数(被解释为字节).
import { Sandbox } from "@deno/sandbox";
// Create a sandbox with 1GiB of memory
await using sandbox = await Sandbox.create({ memory: "1GiB" });
import { Sandbox } from "@deno/sandbox";
// Create a sandbox with 4GiB of memory for memory-intensive workloads
await using sandbox = await Sandbox.create({ memory: "4GiB" });
// Check available memory
const memInfo = await sandbox.deno.eval<{ total: number }>("Deno.systemMemoryInfo()");
console.log("Total memory:", memInfo.total);
内存限制(未来可能有所改变):
- 最低:768个米B
- 最大值: 4096 MiB (4 GiB)
沙盒内实际可用的内存可能略小于配置值,原因是 系统管理费.
想分配更多的记忆吗? 联系人 部署@ deno.com。 。 。 .
限制外出网络访问
您可以限制哪个主机的沙盒可以向外部的网络请求使用 allowNet
选项。 这对于安全敏感环境是有用的,您想要限制网络访问.
import { Sandbox } from "@deno/sandbox";
// Only allow requests to specific hosts
await using sandbox = await Sandbox.create({
allowNet: ["example.com", "*.example.net"],
});
// Requests to allowed hosts will work
await sandbox.sh`curl https://example.com`;
// Requests to other hosts will be blocked
支持的模式 :
- 带有可选端口的精确主机名 :
"example.com", (中文(简体) ),"example.com:80" - 带有可选端口的通配符子域 :
"*.example.com", (中文(简体) ),"*.example.com:443" - 可选端口的IP地址 :
"203.0.113.110", (中文(简体) ),"203.0.113.110:80" - 带有可选端口的IPv6地址 :
"[2001:db8::1]", (中文(简体) ),"[2001:db8::1]:443"
若为 allowNet 未指定,没有实施网络限制.
电线上的秘密
设置从未接触到沙盒代码的秘密环境变量 。 真正的秘密价值是: 当沙盒向指定的主机提出 HTTPS 请求时,在线上被注入.
import { Sandbox } from "@deno/sandbox";
await using sandbox = await Sandbox.create({
secrets: {
OPENAI_API_KEY: {
hosts: ["api.openai.com"],
value: "sk-proj-your-real-key",
},
ANTHROPIC_API_KEY: {
hosts: ["api.anthropic.com"],
value: "sk-ant-your-real-key",
},
},
});
兼容性说明 await using
实例 明确资源管理 (单位:千美元)await using页:1.
对于节点js 22/23或更早,使用 try编号 :finally数字 :
import { Sandbox } from "@deno/sandbox";
const sandbox = await Sandbox.create();
try {
// ... use sandbox ...
} finally {
await sandbox.close();
}
App 管理实例
此软件包还提供了您组织的 Apps 管理功能.
创建 App
import { Client } from "@deno/sandbox";
const client = new Client();
const app = await client.apps.create({
slug: "my-app-from-sdk",
});
console.log(app);
// => {
// id: "4416a358-4a5f-45b2-99b5-3ebcb4b63b5f",
// slug: "my-app-from-sdk",
// updated_at: "2025-11-25T05:29:08.777Z",
// created_at: "2025-11-25T05:29:08.777Z"
// }
列出应用程序
import { Client } from "@deno/sandbox";
const client = new Client();
const list = await client.apps.list();
console.log(list.items); // => this list up to 30 apps (newly updated apps first)
for await (const app of list) {
console.log(app); // => this lists the all apps in your organization
}
获取应用程序
import { Client } from "@deno/sandbox";
const client = new Client();
// You can get app by either App's slug or UUID
const appBySlug = await client.apps.get("my-app-from-sdk");
const appById = await client.apps.get("bec265c1-ed8e-4a7e-ad24-e2465b93be88");
更新应用程序信息
import { Client } from "@deno/sandbox";
const client = new Client();
const updatedApp = await client.apps.update("bec265c1-ed8e-4a7e-ad24-e2465b93be88", {
slug: "my-cool-app",
});
删除应用程序
import { Client } from "@deno/sandbox";
const client = new Client();
// You can delete apps by either App's slug or UUID
await client.apps.delete("legacy-chaotic-app");
await client.apps.delete("bec265c1-ed8e-4a7e-ad24-e2465b93be88");
财务问题
我怎么得到一个标志?
转到控制台 https://console.deno.com (中文(中国大陆) ) 导航到 Settings 您可以找到的页面
Organization Tokens 节。 点击 Create a new token 按钮.
怎么会这样?
在创建新的沙盒时,SDK与Deno部署API通信,以提供安全, 孤立 Linux microVM. SDK然后与沙盒建立安全连接,允许您 与它进行方案互动.
当你把沙盒弄完了,你可以直接摧毁 Sandbox 对象。 这样做
自动关闭了沙盒并释放出它使用的任何资源.
我的沙盒在哪个区域运行?
您可以指定创建新沙盒时创建沙盒的区域 :
import { Sandbox } from "@deno/sandbox";
await using sandbox = await Sandbox.create({ region: "ams" });
如果不指定, 沙盒将在默认区域创建 .
沙盒有什么限制?
沙盒有以下限制:
- CPU: 2个vCPU
- 记忆:768个米B至4096个米B
- 磁盘: 10 GiB
超过这些限度可能导致你的沙盒被挤出或被终止.