npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@runko/sandbox-cloudflare

v0.1.2

Published

RunkoFS & RunkoExec 同源工作区:适配 Cloudflare Sandbox(网关形态——`.` 纯 fetch 客户端跑在任意 Node,`./worker` 网关部署在宿主 wrangler 项目)

Readme

@runko/sandbox-cloudflare

把一个 Cloudflare Sandbox(真实 Linux 容器)通过一个自部署的 HTTP 网关包成 RunkoFS & RunkoExec,一次注入 createSession(agent, { workspace })——"模式 A 同源工作区"落在真实云沙盒上的实现(对照 core-sdk · 技术方案 §4.5a / 沙盒工作区(Sandbox Workspace) · 技术方案 §8)。

与 E2B/Vercel 两个适配器架构不同:Cloudflare Sandbox 只能从 Cloudflare Worker 内部访问(Durable Object binding),没有办法从任意 Node 进程直连——因此本包是两个入口

  • .(本文档的客户端,跑在任意 Node ≥20 进程):纯 fetch 协议客户端,不 import @cloudflare/sandbox(该包只能在 workerd 里加载)。
  • ./worker(网关,部署在宿主自己的 wrangler 项目里):把协议翻译成对真实 @cloudflare/sandbox 的调用。

安装

pnpm add @runko/sandbox-cloudflare

客户端侧零 provider SDK——本包不随 @runko/sdk 一起装,属于按需显式安装的可选集成。网关侧 @cloudflare/sandbox 是本包的 peerDependency(版本跟宿主的 wrangler 项目走),装在部署网关的那个 wrangler 项目里,不装在跑 agent 的 Node 进程里。

网关部署

先把网关部署到你自己的 Cloudflare 账号(需要 Workers Paid 计划,无免费层)。一个完整可跑可部署的参考项目见 apps/cloudflare-worker-server/——自备 CF 账号后 pnpm --filter @runko-chat/cloudflare-worker-server deploy 即可部署;本包自身只发布 createSandboxGateway 这层纯函数,网关的部署形态维护在该项目里。核心装配只有几行:

// 你的 wrangler 项目的 Worker 入口(见 apps/cloudflare-worker-server/src/index.ts)
import { getSandbox } from "@cloudflare/sandbox";
import { createSandboxGateway } from "@runko/sandbox-cloudflare/worker";

export { Sandbox } from "@cloudflare/sandbox"; // Durable Object 类必须从 Worker 入口导出

export default {
  async fetch(request: Request, env: { Sandbox: DurableObjectNamespace; RUNKO_GATEWAY_TOKEN: string }) {
    const gateway = createSandboxGateway({
      token: env.RUNKO_GATEWAY_TOKEN,
      getSandbox: (sandboxId) => getSandbox(env.Sandbox, sandboxId),
    });
    return gateway.fetch(request);
  },
};

快速上手(客户端)

import { cloudflareWorkspace } from "@runko/sandbox-cloudflare";
import { createSession, defineAgent } from "@runko/sdk";

const workspace = cloudflareWorkspace({
  url: process.env.RUNKO_CF_GATEWAY_URL!,     // 部署好的网关 URL
  token: process.env.RUNKO_CF_GATEWAY_TOKEN!, // 与 `wrangler secret put RUNKO_GATEWAY_TOKEN` 相同的值
});
const session = createSession(defineAgent({ model: "anthropic/claude-sonnet-5" }), { workspace });
const result = await session.send("在 notes.txt 里写一句问候语,然后用 bash 验证内容。");
console.log(result.finalResponse);

没有 Sandbox 风格的 SDK 对象需要创建/销毁——沙盒生命周期由宿主的 wrangler 项目(getSandbox() 那一行)管理,不由这个客户端管理。

完整可跑示例(含零部署的进程内 client → gateway → fake sandbox 完整协议往返演示)见 examples/src/11-sandbox-cloudflare.ts

结构化接口 / BYO

// 客户端(".")
function cloudflareWorkspace(opts: { url: string; token: string; sandboxId?: string; fetch?: typeof fetch }): RunkoFS & RunkoExec;

// 网关("./worker")
function createSandboxGateway(opts: { token: string; getSandbox: (sandboxId: string) => CfSandboxLike | Promise<CfSandboxLike> }): {
  fetch(request: Request): Promise<Response>;
};
  • 客户端没有"实例"概念(E2B/Vercel 是 BYO 一个已创建的沙盒对象;这里 BYO 的是一个已部署的网关——一个 URL + token);fetch 可注入自定义传输(测试/演示用直连网关 handler,见 examples 11 的进程内演示)。
  • CfSandboxLike 是以 @cloudflare/[email protected]ISandbox 为蓝本手写的结构化最小子集(exec/readFile/writeFile/mkdir/deleteFile/listFiles)——./worker 运行时零 import "@cloudflare/sandbox",真实装配(getSandbox(env.Sandbox, id) 的返回值)天然结构兼容这个接口,留给宿主项目经 createSandboxGateway({ getSandbox }) 注入。
  • 全部 POST + JSON body,Authorization: Bearer <token> 鉴权,x-runko-sandbox 头选择沙盒(缺省 "default"),二进制经 base64,/exec 走 NDJSON 流式响应——完整协议见 沙盒工作区(Sandbox Workspace) · 技术方案 §8.3

已知限制(docs/host/contract/tech/sandbox.md §8.2–§8.3 / docs/logic/engine/plans/core-sdk.md P10-3 实际改动,如实照抄不发明)

  • 路径锚定是隐式的、发生在网关一侧,没有 root 配置项:不同于 E2B/Vercel 的客户端 opts.root,这里的虚拟根 / 锚定在沙盒自身的默认工作目录——网关把客户端送来的虚拟绝对路径去掉前导 / 就得到沙盒相对路径,两端都不需要显式配置真实目录。副作用:bash 命令里带前导 / 的绝对路径(如 cat /notes.txt)落在沙盒真实文件系统根,而不是虚拟工作区根——同一份文件要在文件工具和 bash 之间互通,bash 侧要用相对路径。这是"真实 FS + root 锚定"的固有语义,E2B(/home/user)/Vercel(/vercel/sandbox)同样存在,只是那两家的锚点是客户端可见的配置项,这里锚点藏在网关内部。
  • readdir/stat 对 symlink 与其他非常规条目一律归一为 "file"——真实沙盒文件系统没有 MemoryFS 那种"reference"概念。
  • mtime 精度是容器真实的文件修改时间(常见是秒级精度),不是 MemoryFS 那种毫秒级递增时间戳。
  • 每次 RunkoFS/RunkoExec 调用都是一次 HTTP 往返(经 Durable Object,几十到几百毫秒)——扫描类操作(globbing 大目录树、grep-like 搜索)优先用一条 bash 命令(find/grep),而不是逐个文件工具调用。
  • 沙盒生命周期(idle 睡眠、重启、过期)由宿主的 wrangler 项目管理,不由这个客户端/网关管理——沙盒不可达时以网关错误的形式从 exec()/文件方法浮出,宿主负责唤醒或重建沙盒。沙盒磁盘本身是临时的:Durable Object idle 睡眠(默认 10 分钟)后文件系统丢失(见 apps/cloudflare-worker-server/README.md),长期数据需要宿主自己接 R2 backup,v1 网关不代理这一层。