@computesdk/provider

中文文档
2.1.22发布于 2026/11/06MITTypeScriptESM + CJS构建来源已验证近 30 天下载 4.8万

计算SDK的提供方框架 - 定义自定义的沙盒提供者

中文使用文档
文档目录24 节
  1. 概览
  2. 安装
  3. 快速启动
  4. API 参考
  5. defineProvider(config)
  6. 必要实例方法
  7. 可选文件系统方法
  8. 背景进程和流程
  9. 贝壳级
  10. 类型定义
  11. 核心类型
  12. 提供者模式
  13. 完整示例
  14. 供应商包中的使用
  15. 最佳做法
  16. 1. 提前验证配置
  17. 2. 提供帮助错误消息
  18. 3. 慷慨地处理缺失的地物
  19. 4. 文件提供者 -- -- 具体特点
  20. 测试您的提供者
  21. 实例
  22. 相关软件包
  23. 许可证
  24. 纯标准大小的能力钩

@ computesdk/ 提供者

构建自定义计算提供者的提供者框架.

概览

这个软件包为计算SDK生态系统提供了自定义沙盒提供商的工具和类型. 使用它来添加对新计算平台,云提供商,或沙盒环境的支持.

安装

npm install @computesdk/provider

快速启动

import { defineProvider } from '@computesdk/provider';
import type { ProviderConfig } from '@computesdk/provider';

interface MyProviderConfig extends ProviderConfig {
  apiKey: string;
  region?: string;
}

export const myProvider = defineProvider<any, MyProviderConfig>({
  name: 'my-provider',
  defaultMode: 'direct',
  methods: {
    instances: {
      create: async (config, options) => {
        // Create sandbox via your provider's API
        const response = await fetch(`https://api.example.com/sandboxes`, {
          method: 'POST',
          headers: { 'Authorization': `Bearer ${config.apiKey}` },
          body: JSON.stringify(options)
        });
        
        const data = await response.json();
        
        return {
          instance: data, // Your provider's sandbox object
          instanceId: data.id
        };
      },
      
      getById: async (config, instanceId) => {
        const response = await fetch(
          `https://api.example.com/sandboxes/${instanceId}`,
          { headers: { 'Authorization': `Bearer ${config.apiKey}` } }
        );
        
        if (!response.ok) return null;
        
        const data = await response.json();
        return { instance: data, instanceId: data.id };
      },
      
      list: async (config) => {
        const response = await fetch(
          `https://api.example.com/sandboxes`,
          { headers: { 'Authorization': `Bearer ${config.apiKey}` } }
        );
        
        const data = await response.json();
        return data.map((s: any) => ({ instance: s, instanceId: s.id }));
      },
      
      destroy: async (config, instanceId) => {
        await fetch(
          `https://api.example.com/sandboxes/${instanceId}`,
          {
            method: 'DELETE',
            headers: { 'Authorization': `Bearer ${config.apiKey}` }
          }
        );
      },
      
      runCommand: async (sandbox, command, args) => {
        // Run shell command
        const response = await fetch(
          `https://api.example.com/sandboxes/${sandbox.id}/command`,
          {
            method: 'POST',
            body: JSON.stringify({ command, args })
          }
        );
        
        const result = await response.json();
        return {
          stdout: result.stdout,
          stderr: result.stderr,
          exitCode: result.exitCode
        };
      },
      
      getInfo: async (sandbox) => {
        return {
          id: sandbox.id,
          status: sandbox.status,
          createdAt: new Date(sandbox.created_at)
        };
      },
      
      getUrl: async (sandbox, options) => {
        return `https://${sandbox.id}.example.com:${options.port}`;
      }
    }
  }
});

API 参考

defineProvider(config)

定义具有沙盒生命周期方法的新供应商.

参数:

interface ProviderConfig<TInstance, TConfig> {
  name: string;
  defaultMode?: 'direct' | 'gateway';
  methods: {
    instances: InstanceMethods<TInstance, TConfig>;
    template?: TemplateMethods<TTemplate, TConfig>;
    snapshot?: SnapshotMethods<TSnapshot, TConfig>;
  };
}

methods.sandbox 仍为 methods.instances ——使用 instances 在新供应商.

回返情况: 工厂功能 (config: TConfig) => Provider

必要实例方法

收集操作

这些方法管理收集层面的沙盒:

create(config, options?)

创建新沙盒 .

create: async (config, options) => {
  // Return: { instance: YourSandboxObject, instanceId: string }
  return { instance: myInstance, instanceId: 'sandbox-123'
  };
}
getById(config, instanceId)

以身份证获取已有的沙盒 .

getById: async (config, instanceId) => {
  // Return: { instance, instanceId } or null if not found
  return { instance: myInstance, instanceId };
}
list(config)

列出所有沙盒 .

list: async (config) => {
  // Return: Array of { instance, instanceId }
  return [
    { instance: sandbox1, instanceId: 'id1' },
    { instance: sandbox2, instanceId: 'id2' }
  ];
}
destroy(config, instanceId)

毁一沙盒.

destroy: async (config, instanceId) => {
  await yourApi.deleteSandbox(instanceId);
}

实例操作

这些方法适用于单个沙盒实例:

runCommand(sandbox, command, args?, options?)

运行 shell 命令 .

runCommand: async (sandbox, command, args) => {
  const result = await yourApi.runCommand(sandbox.id, command, args);
  return {
    stdout: result.stdout,
    stderr: result.errors,
    exitCode: result.code
  };
}
getInfo(sandbox)

获取沙盒信息.

getInfo: async (sandbox) => {
  return {
    id: sandbox.id,
    status: 'running', // 'running' | 'stopped' | 'error'
    createdAt: new Date(sandbox.created_at)
  };
}
getUrl(sandbox, options)

访问沙盒服务时获取 URL .

getUrl: async (sandbox, options) => {
  return `https://${sandbox.id}.example.com:${options.port}`;
}

可选文件系统方法

通过执行 filesystem 方法。 。 。 导入 escapeShellArg 从 @computesdk/provider 并且总是插入 双引号——帮助者逃脱 \, (中文(简体) ), ", (中文(简体) ), $,并反向缩写,但不包括空格或外壳元体,例如 ; 财务报告和审定财务报表 |,因此未引用的用法会在有空格的路径上断开,对于用户控制的输入来说是不安全的.

import { defineProvider, escapeShellArg } from '@computesdk/provider';

// ...

methods: {
  instances: {
    // ... required methods
    
    filesystem: {
      readFile: async (sandbox, path, runCommand) => {
        const result = await runCommand(sandbox, `cat "${escapeShellArg(path)}"`);
        return result.stdout;
      },
      
      writeFile: async (sandbox, path, content, runCommand) => {
        await runCommand(sandbox, `cat > "${escapeShellArg(path)}" << 'EOF'\n${content}\nEOF`);
      },
      
      mkdir: async (sandbox, path, runCommand) => {
        await runCommand(sandbox, `mkdir -p "${escapeShellArg(path)}"`);
      },
      
      readdir: async (sandbox, path, runCommand) => {
        const result = await runCommand(sandbox, `ls -la "${escapeShellArg(path)}"`);
        // Parse ls output and return FileEntry[]
        return parseFileList(result.stdout);
      },
      
      exists: async (sandbox, path, runCommand) => {
        const result = await runCommand(sandbox, `test -e "${escapeShellArg(path)}"`);
        return result.exitCode === 0;
      },
      
      remove: async (sandbox, path, runCommand) => {
        await runCommand(sandbox, `rm -rf "${escapeShellArg(path)}"`);
      }
    }
  }
}

说明: 如果你不执行 filesystem,沙盒仍然会工作,但文件系统操作会抛出有用的"不支持"错误.

背景进程和流程

instance.startProcess(...) 财务报告和审定财务报表 runCommand(cmd, { onStdout, onStderr }) 每个供应商的工作。 框架按此顺序选择运行时间:

  1. 土著 - 供应商自己 streamCommand 编号 : startProcess 钩上 methods.instances。 。 。 .
  2. 外壳分级( 默认) —— POSIX- shell 进程记录只建立在提供者平原上 runCommand。节点、守护进程或下載等实例,因此它可以工作在任何图像上 sh包括高山和繁忙的盒子.
  3. 守护进程( opt- in) ——箱式守护进程,仅在提供者配置时 processRuntime: 'daemond'数字 :
const provider = e2b({ apiKey, processRuntime: 'daemond' });

instance.processRuntime (b) 报告为每一能力服务的级别,例如:. { streaming: 'native', processes: 'shell' }。 。 。 .

贝壳级

每个工作都是目录 ${TMPDIR:-/tmp}/.computesdk/jobs/<jobId>/ (英语:Mode 0700). 一个执行官写工作文件 并派出一名主管 nohup setsid;主管通过 FIFOs 将命令在自己的流程组中运行并进行 stdout/stder 运行到被设定的日志中(out.log,记录 O<len>\n… 编号 : E<len>\n… ,然后写 pid 财务报告和审定财务报表 exit。 。 。 .

  • 读取 (单位:千美元)status, (中文(简体) ), wait, streaming)是每个执行器一个,取一个字节光标并只返回新输出,每执行器最多为16个日志的KiB(约22个KB Base64,在SSM的24000个字符内置封顶下). wait 每名执行官最多25分.
  • 静态 (单位:千美元)stdin: true- 持单人程序保持的FIFO; write 是一个执事者, closeStdin 杀死持有者.
  • 杀死 表示整个进程组。 流线 runCommand是因为 timeout 由监督员在盒子中执行,监督员是SIGKILLL 组(出局码为124),因此,当客户端消失时,最后期限就到了。 无 timeout 没有任何东西可以杀死指挥部.
  • 重装数字 : instance.attachProcess(jobId) 在新客户端中重建一个手柄.
  • 保留:退出后10分钟(杀后60分),工作目录被移除.
  • 执行者共享无状态的实例 (每个命令有一个新鲜的容器,例如Archil磁盘Exec):一个实例上的第一次发射会维持这个命令,直到第二个执行确认工作目录幸存,所以在任何东西运行之前都会发现这个. 在这种情况下,流出 runCommand 回到一个简单的执行器,其输出在出口交付 startProcess 掷出 ShellStateNotPersistentError。 。 。 .
  • 所需资源数字 : sh, (中文(简体) ), setsid, (中文(简体) ), mkfifo, (中文(简体) ), kill, (中文(简体) ), cat, (中文(简体) ), dd, (中文(简体) ), wc, (中文(简体) ), tail, (中文(简体) ), head, (中文(简体) ), base64, (中文(简体) ), mkdir, (中文(简体) ), rm, (中文(简体) ), mv, (中文(简体) ), sleep。一个缺失的失败 ShellProcessUnsupportedError 点名.

进取路由器( :CreateInstanceOptions.egress)留在守护进程上:它的shim是一个节点程序,守护进程靴子是将节点安装在图像上而没有它的东西.

类型定义

核心类型

import type {
  // Provider types
  Provider,
  ProviderConfig,
  ProviderInstance,
  
  // Method definitions
  InstanceMethods,
  TemplateMethods,
  SnapshotMethods,
  
  // Result types
  CodeResult,
  CommandResult,
  InstanceInfo,
  
  // Options
  CreateInstanceOptions,
  RunCommandOptions,
  
  // Filesystem
  FileEntry,
  InstanceFileSystem
} from '@computesdk/provider';

提供者模式

供应商可以以不同方式运作:

  • direct - 供应商具有本地沙盒能力(例如E2B、Modal)
  • gateway - 供应商只有基础设施 -- -- 通过网关的路线

在提供者配置中设置默认模式 :

export const myProvider = defineProvider({
  name: 'my-provider',
  defaultMode: 'direct', // or 'gateway'
  methods: { /* ... */ }
});

完整示例

这里有一个完整的最小提供者执行:

import { defineProvider } from '@computesdk/provider';

interface MinimalConfig {
  apiKey: string;
}

export const minimal = defineProvider<any, MinimalConfig>({
  name: 'minimal',
  defaultMode: 'direct',
  methods: {
    instances: {
      create: async (config, options) => {
        const id = `sandbox-${Date.now()}`;
        return {
          instance: { id, status: 'running' },
          instanceId: id
        };
      },
      
      getById: async (config, id) => {
        return {
          instance: { id, status: 'running' },
          instanceId: id
        };
      },
      
      list: async (config) => {
        return [];
      },
      
      destroy: async (config, id) => {
        // Clean up sandbox
      },
      
      runCommand: async (sandbox, command, args) => {
        return {
          stdout: `Ran: ${command} ${args?.join(' ')}`,
          stderr: '',
          exitCode: 0
        };
      },
      
      getInfo: async (sandbox) => {
        return {
          id: sandbox.id,
          status: 'running',
          createdAt: new Date()
        };
      },
      
      getUrl: async (sandbox, options) => {
        return `http://localhost:${options.port}`;
      }
    }
  }
});

// Export factory function
export function createMinimal(config: MinimalConfig) {
  return minimal(config);
}

供应商包中的使用

一旦您定义了您的供应商, 从您的软件包中导出 :

// In @computesdk/my-provider/src/index.ts
import { defineProvider } from '@computesdk/provider';

export const myProvider = defineProvider({ /* ... */ });

// Users can then use it directly
import { myProvider } from '@computesdk/my-provider';

const compute = myProvider({ apiKey: 'xxx' });
const sandbox = await compute.instances.create();

最佳做法

1. 提前验证配置

create: async (config, options) => {
  if (!config.apiKey) {
    throw new Error(
      'Missing API key for my-provider.\n\n' +
      'Setup instructions:\n' +
      '1. Get your API key from https://example.com/keys\n' +
      '2. Set environment variable: export MY_PROVIDER_API_KEY=your_key\n' +
      '3. Or pass it directly: myProvider({ apiKey: "your_key" })'
    );
  }
  
  if (!config.apiKey.startsWith('mp_')) {
    throw new Error(
      'Invalid API key format for my-provider.\n' +
      'API keys should start with "mp_"'
    );
  }
  
  // Continue with creation
}

2. 提供帮助错误消息

runCommand: async (sandbox, command, args) => {
  try {
    return await yourApi.runCommand(sandbox.id, command, args);
  } catch (error) {
    if (error.code === 'QUOTA_EXCEEDED') {
      throw new Error(
        'API quota exceeded for my-provider.\n' +
        'Upgrade your plan at https://example.com/pricing'
      );
    }
    throw error;
  }
}

3. 慷慨地处理缺失的地物

如果您的提供者不支持某些特性:

// Don't implement filesystem methods - ComputeSDK will auto-generate
// helpful error messages for users

4. 文件提供者 -- -- 具体特点

/**
 * My Provider - Fast cloud sandboxes
 * 
 * Features:
 * - Python and Node.js runtimes
 * - Full filesystem support
 * - GPU acceleration (premium plans)
 * - No terminal support
 */
export const myProvider = defineProvider({ /* ... */ });

测试您的提供者

创建测试以验证您的提供者执行 :

import { describe, it, expect } from 'vitest';
import { myProvider } from './index';

describe('MyProvider', () => {
  it('creates and destroys sandboxes', async () => {
    const compute = myProvider({ apiKey: process.env.MY_PROVIDER_API_KEY! });
    
    const sandbox = await compute.instances.create();
    expect(sandbox.instanceId).toBeDefined();
    
    const info = await sandbox.getInfo();
    expect(info.status).toBe('running');
    
    await sandbox.destroy();
  });
  
  it('executes code', async () => {
    const compute = myProvider({ apiKey: process.env.MY_PROVIDER_API_KEY! });
    const sandbox = await compute.instances.create();
    
    const result = await sandbox.runCommand('python -c "print(\"Hello\")"');
    expect(result.stdout).toContain('Hello');
    expect(result.exitCode).toBe(0);
    
    await sandbox.destroy();
  });
});

实例

参见这些提供者的实施参考:

许可证

麻省理工学院

纯标准大小的能力钩

defineProvider 接受可选同步 sizes(config, profile, options) 钩. 遗产习惯 Provider 执行不需要添加此字段。 工厂 供应商暴露出不可改变的 provider.sizes.list(context?) 编号 : resolve(class, context?) 管理器; 没有钩子报告的适配器 unknown 并且否认明白的 sizeClass 请求而不是忽略它们。 背景可以包括模式或 平台选择器,但不得合并标准大小控件和本地大小控件.

sizes: (_config, profile, options) => {
  if (options?.snapshotId) {
    return { status: 'unsupported', reason: 'Restores inherit resource sizing.' };
  }
  // Declare supported only after verifying exact CPU + RAM bounds and semantics.
  return {
    status: 'supported',
    nativeOptions: { vcpus: profile.vcpus, memoryMiB: profile.memoryMiB },
  };
},

工厂应用平地并合并已知的命名空间 instanceOptions.shape 资源路径 创建选项的副本,条 sizeClass,并记录不可更改的请求 元数据为 instance.sizing. 虎克必须只返回资源绘图场, 永远不要复制呼叫器 env/metadata/ 授权/通过机构进入补丁 . 这种被捆绑的合并保留了无关的嵌入地,没有被冻结的呼叫器 对象; 它不会递归正态任意创建选项。 标准 资源背景和释放的补丁拒绝不安全的密钥/存取器; 普通和 接受无效原型数据对象。 没有阶级的要求是没有改变的. 业务 resolution.nativeOptions 与 instance.sizing,哪个 只包含已请求/已解决的CPU/RAM/类和出处. 它们必须是纯的: 没有客户端构建, 证书检查,模板列表, 网络接入、构建或提供。 支持的映射是适配器声明 * 请求、未计量资源或账户/区域可用性担保. 返回时 unconfigured, (中文(简体) ), unavailable, (中文(简体) ), requires-build, (中文(简体) ), unknown,或 unsupported 当精确的映射无法宣告时, 没有后退或自动 建设发生。 发现结果被复制并被冻结(包括巢原生地) 选项);调用输入不被冻结或变异.

createCompute 保护传统定制供应商 缺乏规模合同. defineInfraProvider 目前拒绝标准大小请求为 unknown; 其编号 传统本地创建路径不变。 直接调用到手写习惯 提供者仍然是提供者作者的责任.

一个 InstanceSizeManager 携带 contract: 'computesdk.instance-sizes.v1' 将制作 明确和区分不相关的遗产 sizes 属性。 手写 宣布该合同的供应商对实际消费负有责任 sizeClass (b) 框架保证: defineProvider 适应器. 核心拒绝不兼容/有缺陷的声明.

标准选项、限定的本地资源背景以及释放的补丁使用 假设自己的字符串键数据描述符。 符号/不可假设/接入域 在钩/复制/创建之前拒绝; 带有定义的函数 sizeClass 无法 选择退出验证。 失踪/未定义 sizeClass 保留遗产通过.

关于源相容性, 基础 Provider.sizes 编号 : DirectProvider.sizes 是一个 选项 unknown 扩展槽:遗留数组、函数或无关对象 即使没有标准要求,仍然可以转让。 使用 isInstanceSizeManager 在发现前缩小这个位置. defineProvider sDK适配器工厂 仍然返回需要的, 强烈键入 sizes 管理器; 缺失/不兼容 运行时合同在创建前仍然拒绝定义的标准请求 .

仅由编译器保存的相容性覆盖包含在本包中 tsconfig.json (单位:千美元)src/**/*,包括: src/__tests__/legacy-size-types.ts) (中文(简体) ). 运行 它明确来自没有网络/安装的工作空间根:

pnpm exec tsc --noEmit --strict --target es2020 --moduleResolution node --esModuleInterop --skipLibCheck packages/provider/src/__tests__/legacy-size-types.ts

一般的模拟套房也运行 legacy-size-types.test.ts,引用 已安装此固定线上的 TypeScript 编译器(--noEmit; 计 数 fixture 的只类型实例调用从未执行 。 没有安装/ 网络步骤 需要,所以结构后退失败 pnpm test 我也一样.

版本与发布记录

@computesdk/provider 共发布 59 个版本,首次发布于 2026/01/01;过去 12 个月发布了 59 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
2.1.22latest2026/11/064 天前
2.1.212026/11/046 天前
2.1.202026/10/2812 天前
2.1.192026/10/2317 天前
2.1.182026/10/2318 天前
2.1.172026/10/2218 天前

关于 @computesdk/provider 的常见问题

@computesdk/provider 是什么?

计算SDK的提供方框架 - 定义自定义的沙盒提供者

如何安装 @computesdk/provider?

在项目目录运行 npm install @computesdk/provider,或使用 pnpm add / yarn add / bun add。

@computesdk/provider 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@computesdk/provider 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@computesdk/provider 可以商用吗?

@computesdk/provider 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@computesdk/provider 的下载量有多少?

根据 npm 官方下载统计,@computesdk/provider 在 2026/10/11 – 2026/11/09 这 30 天内被下载 48,359 次,日均约 1,612 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@computesdk/provider 还在维护吗?

最新版本 2.1.22 发布于 2026/11/06(4 天前);至今共发布 59 个版本,其中过去 12 个月发布了 59 个;首次发布于 2026/01/01。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。