@everruns/bashkit-wasm (英语)
Sandboxed bash 解译器编译到WebAssembly,用于 浏览器和任意 其他 JavaScript 运行时间:边缘工人/无服务工人(云雾工人,Vercel) 边缘、德诺部署、节点、德诺和邦.
与WASI线程构建不同,这个包是 单行: 需要没有
SharedArrayBuffer 财务报告和审定财务报表 无跨源隔离 (单位:千美元)COOP编号 :COEP)头.
包括嵌入式和第三方
iframe 无法设置这些信头的上下文, 以及限制的边缘
无法使用线程的运行时间 .
这是一个 wasm-bindgen 模块,所以它运行 在任何JS主机,但 没有 (单位:千美元)
非JS/WASI运行时间(wasmtime, (中文(简体) ), wasmer) (中文(简体) ). 用于本地节点.js / Bun /
Deno 加通( 较快, 无相机), 使用
@everruns/bashkit 改为:;
当本地加通无法加载、浏览器和边缘时, 访问此软件包
运行时间.
现场演示
在这个软件包上搭建了一个完整的交互式终端,
examples/browser。 。 。 .
单曲 index.html 维特: pnpm install && pnpm start,没有建设步骤
并且没有特别的标题.
安装
npm install @everruns/bashkit-wasm
快开始
import { initBashkit, Bash } from "@everruns/bashkit-wasm";
// Load the .wasm once before constructing Bash.
await initBashkit();
const bash = new Bash();
const result = bash.executeSync('echo "Hello, browser!" | tr a-z A-Z');
console.log(result.stdout); // HELLO, BROWSER!
平面 <script type="module"> (没有捆绑)
<script type="module">
import { initBashkit, Bash } from "https://esm.sh/@everruns/bashkit-wasm";
await initBashkit();
const bash = new Bash();
document.body.textContent = bash.executeSync("seq 1 5 | paste -sd+ | bc").stdout;
</script>
Async 自定义内建
将JS召回登记为bash命令。 Async召回(例如:
fetch / 图QL 请求) execute(),Aync API : (中文(简体) )
const bash = new Bash({
customBuiltins: {
graphql: async (ctx) => {
const res = await fetch("/graphql", {
method: "POST",
headers: { "content-type": "application/json" },
body: ctx.stdin ?? "{}",
});
return await res.text();
},
},
});
const out = await bash.execute('echo "{ me { id } }" | graphql | jq .data');
console.log(out.stdout);
ctx 实值 { name, argv, stdin, env, cwd, fs }。将内建的 stdout作为一个
字符串(或 Promise<string>; 抛出以退出码 1 成为 stderr.
ctx.fs 是一个活柄 不变 脚本看到的虚拟文件系统, 所以
a 内建可读取输入并写入以后命令取取的输出 :
const bash = new Bash({
customBuiltins: {
"uppercase-file": (ctx) => {
const text = ctx.fs.readFile(ctx.argv[0]);
ctx.fs.writeFile("/out.txt", text.toUpperCase());
return "done\n";
},
},
});
bash.writeFile("/in.txt", "hello\n");
await bash.execute("uppercase-file /in.txt && cat /out.txt"); // -> HELLO
ctx.fs 已经 readFile, (中文(简体) ), writeFile, (中文(简体) ), appendFile他们的二进制安全
*FileBytes 变体, exists, (中文(简体) ), mkdir, (中文(简体) ), remove,以及 ls,同样的表面
作为 Bash 下面的VFS助手.
同步 vs 同步
executeSync(cmd),为直击和jq返回一个ExecResult直接说 脚本暂停时抛出, 例如sleep或自动同步 习惯内置.execute(cmd)返回Promise<ExecResult>同步时需要 自定义内置或墙钟操作可能运行.executeWithOutput(cmd, callback),同步执行加递增(stdout, stderr)块. 回来的ExecResult仍然具有权威性.
交互式终端
Terminal 在模拟终端上运行交互式 shell 会话: 您
前键键键, 它会返回像 :
x 任期.js。 。 。 . vi, (中文(简体) ), less 财务报告和审定财务报表 more 运行全屏。 试试看
编辑 bashkit.sh 游乐场。 。 。 .
import { Terminal as XTerm } from "@xterm/xterm";
import { initBashkit, Terminal } from "@everruns/bashkit-wasm";
await initBashkit();
const xterm = new XTerm();
xterm.open(document.getElementById("term"));
const term = new Terminal({ rows: xterm.rows, cols: xterm.cols, cwd: "/home/user" });
let running = false;
let again = false;
async function pump() {
if (running) return void (again = true);
running = true;
do {
again = false;
await term.runUntilIdle(); // { status: "idle" } or { status: "exited", exitCode }
xterm.write(term.takeOutput());
} while (again);
running = false;
}
xterm.onData((keys) => { term.send(keys); pump(); });
xterm.onResize(({ rows, cols }) => term.resize(rows, cols));
pump();
runUntilIdle() 当会话等待输入时解决; 键中键已发送
在命令运行中排队. screenText() 返回可见屏幕为
纯文本和 fs() 读什么 vi 已保存 . Terminal 将每个 Bash
选项加 rows 财务报告和审定财务报表 cols这是 undefined 在自定义建筑中
BASHKIT_WASM_FEATURES=""见 终端指南
对于行编辑器, vi 键和限制.
选项
new Bash({
username, hostname, cwd,
env: { KEY: "value" },
maxCommands, maxLoopIterations, maxMemory,
files: { "/config.json": '{"debug":true}' },
customBuiltins: { name: (ctx) => "..." },
fs: hostFileSystem, // host-backed filesystem; see below
});
虚拟文件系统
通过帮助创建的文件可见脚本,反之亦然:
bash.mkdir("/data");
bash.writeFile("/data/x.txt", "hi\n");
bash.appendFile("/data/x.txt", "there\n");
bash.readFile("/data/x.txt"); // "hi\nthere\n"
bash.exists("/data/x.txt"); // true
bash.ls("/data"); // ["x.txt"]
bash.executeSync("cat /data/x.txt").stdout; // "hi\nthere\n"
bash.remove("/data/x.txt");
// Binary-safe I/O avoids UTF-8 conversion.
bash.writeFileBytes("/data/blob", Uint8Array.from([0, 255]));
bash.readFileBytes("/data/blob");
// bash.fs() returns the same live handle passed to builtins as ctx.fs
const fs = bash.fs();
分析、取消和持久性
analyze(script) 提供与2004年相同的守门员预测
本地装订。 处理解析错误或 isOpaque 作为否定/即时,不安全:
const analysis = bash.analyze("cat input.txt | jq . > output.json");
if (analysis.isOpaque) throw new Error("permission prompt required");
cancel() 在命令边界上设置粘性合作旗帜;
clearCancel() 使实例可以重新使用. commit() 返回 a
内容地址对象集和 checkout(id, objects, policy?) 恢复:
const saved = bash.commit();
const resumed = new Bash();
resumed.checkout(saved.id, saved.objects); // policy defaults to "superset"
主机支持的文件系统
过 fs 来直接运行脚本,以对抗您拥有的存储,一个持久对象,一个
OPFS handle, IndexedDB,取而代之的是内相VFS. 没有复制到或
diffed back out:运行期间的每个读写都是对对象的调用.
const bash = new Bash({ cwd: "/workspace", fs: myHost });
const r = await bash.execute("grep -rl TODO . | head -5");
实施7个所需方法;每个方法可直接或作为
Promise数字 :
read(path) // -> Uint8Array | string (throw ENOENT when absent)
write(path, bytes) // -> void
mkdir(path, recursive) // -> void
remove(path, recursive) // -> void
stat(path) // -> { type: "file" | "dir" | "symlink", size?, mode?, mtimeMs? }
readDir(path) // -> [{ name, type, size?, mode?, mtimeMs? }]
exists(path) // -> boolean
append, (中文(简体) ), copy, (中文(简体) ), rename,以及 chmod 是可选的:省略它们,它们是
由所需原始物合成(chmod 被接受和忽略,所以
chmod +x 仍可工作). symlink 财务报告和审定财务报表 readLink 也可以选择,但脚本
无法到达他们 ENOSYS 当宿主忘记他们的时候.
您的主机只执行原始存储, POSIX 语义( 父目录)
检查,"是目录",同位素解析)被执行在其上方. 扔一个
Error 携带 code (单位:千美元)ENOENT, (中文(简体) ), EEXIST, (中文(简体) ), EACCES, (中文(简体) ), EPERM, (中文(简体) ), EISDIR, (中文(简体) ),
ENOTDIR, (中文(简体) ), ENOTEMPTY, (中文(简体) ), EXDEV, (中文(简体) ), ENOSYS所以,击打报告失败的方式
真实的外壳.
两份合同说明:
execute()只有这个. 主机呼叫可以暂停口译,而且executeSync它不能等待,它报告中止而不是封锁. 同步bash.readFile(...)帮助者的行为也一样.files与fs。 。 。 . 种子通过 VFS 写入 同步的, 一个承诺返回的宿主永远无法满足。 写入种子 数据直接通过主机.
提供 /dev/null 如果您的脚本重定向到主机中; 带有主机
文件系统下面没有内置的 VFS 来提供它 .
包括什么
平面击打加内置的文本工具(grep, (中文(简体) ), sed, (中文(简体) ), awk, (中文(简体) ), jq, (中文(简体) ), find, (中文(简体) ),
(......)和(......) jq。不包括在浏览器构建中: 输出 HTTP (curl编号 :wget, (中文(简体) ),
ssh 财务报告和审定财务报表 sqlite,这些需要套接字、线程或主机
文件系统浏览器沙盒不提供。 通向网络的桥梁
自定义内置( 见上文) 因此请求要通过您的应用程序 fetch。 。 。 .
限制
- 取消是合作的. 主机定时器驱动
sleep, (中文(简体) ),timeout,以及 配置执行期限 。 同步 CPU 循环无法观察到 JS 回调或cancel()直到控制返回到事件循环,所以命令, 循环, 解析燃料, 和内存限制 仍然是这种工作的硬约束 . executeSync无法运行 aync 内建. 单条事件循环 不能解决一个Promise而不产生; 内建于executeSync快速失败 。 使用execute()。 。 。 .
实例
examples/browser,上面显示的完整交互式终端,在Vite上(没有建设步骤,没有标题).- 最小、无依赖性演示
example/,交互式 终端和一个合成已建/ctx.fs演示, 由任何静态文件服务器服务 . 见example/README.md。 。 。 .
发展
# Build the bundle and run the headless integration tests:
bash scripts/build.sh
node --test "__test__/*.test.mjs"
# or, from the repo root:
just build-wasm
许可证
麻省理工学院 巴什基特语Name 项目.
部署和冷却启动
服务 bashkit_wasm_bg.wasm 作为 application/wasm 与 Brotli 或 gzip HTTP 连接
压缩. Raw npm 文件大小不是传输大小 。 使用含有内容的资产
URL 有长生不老的卡通; 保持JS胶水和WASM 从相同的
一起建设. initBashkit() 使用 ham-bindgen 的流载器
服务器发送正确的 MIME 类型。 缓慢的移动连接可能要超过
15秒下载多兆字节捆绑,所以从中选择启动最后期限
您的应用程序的测量网络条件.
软件包包括 build-info.json:来源承诺,脏检查状态,
编译器/工具、货物简介/地物以及装运的WASM的SHA-256.
没有Git元数据的源文件记录了一个无效源身份. 来源
发行版之间的取出可与旧 npm 版本相同
释放; 比较源承诺和版本.
维护者可以运行受限相容性和压缩大小的门 :
node crates/bashkit-wasm/bench/compat.mjs
node crates/bashkit-wasm/bench/artifact.mjs crates/bashkit-wasm/pkg --check
这个 浏览器基准方法 描述可复制 冷启动和执行实验 和测量的剖面交易.
可选 Python/ TypeScript 和主机函数
导入 @everruns/bashkit-wasm/runtimes 用于运行时启用的单线
捆绑; 默认导入会保持微弱 。 启用 python编号 :typescript 明确
通过 externalFunctions编号 :externalHandler (P)或
typescriptExternalFunctions编号 :typescriptExternalHandler (编).
回调支持 JSON 值以及执行本地中止符号 。 使用同步
Bash.execute,每例执行一次。 见
主机函数指南。 。 。 .
构建两个变体 scripts/build.sh release,然后是
BASHKIT_WASM_VARIANT=runtimes BASHKIT_WASM_FEATURES=terminal,python,typescript scripts/build.sh release。 。 。 .
