@collidor/command

中文文档
7.3.4发布于 2026/10/09MITTypeScriptESM + CJS零依赖构建来源已验证近 30 天下载 7951

一个创建,注册和执行命令的小库.

中文使用文档
文档目录21 节
  1. 安装
  2. 特征
  3. 基本用途
  4. 使用类继承
  5. 使用 createCommand (邦德勒/无害安全)
  6. 串流方法
  7. 正在注册 Async Stream 处理器
  8. 正在消耗同步流
  9. 插件系统
  10. 同步操作
  11. 流程处理
  12. API 文档
  13. 构造器
  14. 方法
  15. 高级使用
  16. 自定义上下文
  17. 处理插件出错
  18. 插件
  19. HTTP 插件
  20. 端口频道插件
  21. 类型转换

Codecov npm version License: MIT

命令

具有插件支持的轻量级、 类型安全的命令模式执行 :

  • 零依赖关系
  • 宽插件系统
  • 🔄 Async/Stream/发电机支持
  • QQ 完整类型脚本类型推论
  • * 了解背景的处决

安装

npm install @collidor/command

特征

  • 类型安全的命令执行 - 返回类型自动匹配处理器
  • 插件架构 - 将输出转换为承诺、流或自定义类型
  • 灵活上下文 - 通过上下文对象执行状态
  • 简单的 API - 只有两种方法: 注册和执行
  • 运算器支持 -- -- 发电机和合成流的内置处理

基本用途

使用类继承

import { Command, CommandBus } from "@collidor/command";

// 1. Define command
class CreateUser extends Command<{name: string}, { id: string }> {}

// 2. Create bus
const bus = new CommandBus();

// 3. Register handler
bus.register(CreateUser, (command, context) => ({
  id: Math.random().toString(36).substr(2, 9),
}));

// 4. Execute (type inferred as { id: string })
const user = bus.execute(new CreateUser({ name: "Alice" }));

使用 createCommand (邦德勒/无害安全)

当捆绑用于生产时,JavaScript分解器常常会操纵类名(例如. class CreateUser 变成 class a) (中文(简体) ). 由于总线、 DI 提供者和网络插件(httpPlugin, (中文(简体) ), portChannelPlugin, (中文(简体) ), windowCustomEventPlugin使用其构建器名称的路由命令, createCommand 提供一种类型安全的方法,以固定、不可忽略的名称定义命令:

import { createCommand, CommandBus } from "@collidor/command";

// Define command with explicit types and name: createCommand<PayloadType, ReturnType>("CommandName")
export const CreateUser = createCommand<{ name: string }, { id: string }>("CreateUser");

// Void payload command
export const PingCommand = createCommand<void, string>("PingCommand");

const bus = new CommandBus();

bus.register(CreateUser, (command) => ({
  id: "user_123",
}));

bus.register(PingCommand, () => "pong");

const user = bus.execute(new CreateUser({ name: "Alice" }));
const pong = bus.execute(new PingCommand());

串流方法

对于命令处理器产生多个同步事件的情景,您现在可以注册返回 AsyncIterable 的 Async 流处理器. 这样您就可以使用一个自然的等待程序来消耗命令流.

正在注册 Async Stream 处理器

使用寄存器StreamAsync来注册返回Async 转发器的处理器. 这个处理器可以进行同步的工作,并随着时间的推移产生出事件.

import { CommandBus, Command } from "@collidor/command";

// Define a command
class UpdateUser extends Command<number, { status: string }> {}

// Create a CommandBus instance
const commandBus = new CommandBus();

// Register an async stream handler
commandBus.registerStreamAsync(UpdateUser, async function* (command, context) {
  for (let i = 0; i < command.data; i++) {
    // Simulate asynchronous delay
    await new Promise((resolve) => setTimeout(resolve, 100));
    yield { status: `update-${i}` };
  }
});

正在消耗同步流

StreamAsync方法返回一个 Async 指示器. 您可以轻松地消耗流 等待... 循环:

(async () => {
  // Execute the command and consume the async stream
  for await (const result of commandBus.streamAsync(new UpdateUser(5))) {
    console.log(result);
  }
  // Expected output:
  // { status: 'update-0' }
  // { status: 'update-1' }
  // { status: 'update-2' }
  // { status: 'update-3' }
  // { status: 'update-4' }
})();

插件系统

同步操作

const asyncBus = new CommandBus({
  plugin: (command, ctx, handler) => {
    return Promise.resolve(handler?.(command, ctx));
  }
});

// Returns Promise<{ id: string }>
const futureUser = asyncBus.execute(new CreateUser());

流程处理

const streamBus = new CommandBus({
  plugin: async function* (command, ctx, handler) {
    yield await handler?.(command, ctx);
    yield await handler?.(command, ctx);
  }
});

// Returns AsyncIterable<{ id: string }>
for await (const result of streamBus.execute(new CreateUser())) {
  console.log(result);
}

API 文档

CommandBus<TContext, TPlugin>

构造器

方法

方法说明
register<C>注册命令处理器
execute<C>用类型推论执行命令
registerStream<C>注册流命令处理器
stream<C>执行命令,结果为调用超时
registerStreamAsync<C>注册返回的 Aync 流处理器 AsyncIterable
streamAsync<C>执行命令并返回串流事件的同步执行器.

高级使用

自定义上下文

interface AppContext {
  requestId: string;
  user: { id: string };
}

const bus = new CommandBus<AppContext>({
  context: {
    requestId: "123",
    user: { id: "system" }
  }
});

bus.register(CreateUser, (cmd, ctx) => {
  console.log(ctx.user.id); // "system"
  return { id: ctx.requestId };
});

处理插件出错


const errorHandlingPlugin: CommandBusPlugin<
    Command,
    typeof context,
    Command[COMMAND_RETURN]
  > = {
    handler: (command, ctx, handler) => {
        try {
            return {
                success: true,
                value: handler?.(command, ctx)
            };
        } catch (error) {
            console.error("Command failed:", command);
            return {
                success: false,
                error,
            }
        }
    },
  };

const safeCommandBus = new CommandBus({ plugin: errorHandlingPlugin });

插件

HTTP 插件

HTTP 插件将您的指令Bus 与 HTTP 端点—— 无论是在客户端还是服务器端—— 整合, 同时保留全类型安全并充分利用插件系统 .

HTTP 客户端插件

HttpClientPlugin拦截命令执行,并将 HTTP POST 请求发送给您的 API 端点 。 它支持:

  • 动态路由:提供根据命令和上下文生成URL的功能.
  • 自定义信头:供应静态信头或返回信头的函数.
  • 自定义序列器:覆盖不同内容类型的默认JSON序列器.

示例使用法:

import { CommandBus, Command, httpClientPlugin } from "@collidor/command";

// Define a command
class CreateUser extends Command<{ name: string }, { id: string }> {}

// Create the HTTP client plugin with custom headers
const clientPlugin = httpClientPlugin("http://api.example.com/createUser", {
  headers: () => ({
    "X-API-Key": "my-secret-key",
  }),
});

// Create the CommandBus with the HTTP client plugin installed.
// If a local handler is registered, it will take precedence.
const bus = new CommandBus({ plugin: clientPlugin });

// Execute the command.
// makes an HTTP POST.
const user = await bus.execute(new CreateUser({ name: "Alice" }));
console.log(user); // e.g. { id: "generated-id-xxx" }

注释:

如果提供了本地处理器,将会被使用;否则,HTTP客户端插件会发送POST请求. 默认序列器会将数据转换为JSON,并期望JSON响应,但你可以自行提供.

HTTP 服务器插件

HttpServerPlugin 允许您以 HTTP 端点曝光您的指令Bus 。 它提供帮助方法:

  • 从请求中提取一个命令: 获取命令从请求中获取
  • 处理请求: 处理请求

此插件将收到的请求解为命令, 在总线上执行, 并返回结果 .

示例使用法:

import { CommandBus, Command, httpServerPlugin } from "@collidor/command";

// Define a command
class CreateUser extends Command<{ name: string }, { id: string }> {}

// Create an HTTP server plugin instance
const serverPlugin = httpServerPlugin();

// Create the CommandBus with the server plugin installed
const bus = new CommandBus({ plugin: serverPlugin });

// Register a command handler
bus.register(CreateUser, (command) => ({
  id: "generated-id-" + Math.random().toString(36).substring(2, 9),
}));

// Simulate an HTTP POST request (e.g., within your web framework)
const request = new Request("http://api.example.com", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    data: { name: "Alice" },
    name: CreateUser.name,
  }),
});

// Handle the request using the plugin
serverPlugin.handleRequest(request).then((result) => {
  console.log(result);
  // Expected output: { id: "generated-id-xxx" }
});

注释:

确保插件通过命令Bus安装,以便获得命令From Request可以访问命令构造器. 服务器插件默认使用与客户端插件相同的序列器逻辑. 如果需要, 请自定义 .

自定义序列化

HTTP 两种插件都允许您提供自定义的序列器,如果您需要使用不同的数据格式或内容类型工作的话.

示例

import { Serializer } from "@collidor/command/plugins/httpPlugin";

const customSerializer: Serializer<Blob> = {
  serialize: (data, headers) => {
    headers.set("Content-Type", "application/octet-stream");
    return new Blob([JSON.stringify(data)], { type: "application/octet-stream" });
  },
  deserializeResponse: async (response) => {
    if (!response.ok) {
      throw new Error(`HTTP error: ${response.status}`);
    }
    const text = await response.text();
    return JSON.parse(text);
  },
  deserializeRequest: async (request) => {
    const text = await request.text();
    return JSON.parse(text);
  },
};

const clientPlugin = httpClientPlugin("http://api.example.com", {
  serializer: customSerializer,
});

通过集成HTTP客户端和服务器插件,您可以轻松地将您的命令处理器与远程HTTP服务连接起来,同时仍然享受到由命令库提供的类型安全和插件扩展性的所有好处.

端口频道插件

新的PortChannel插件从@collidor/event 调用基本的PortChannel,在不同的环境中(例如服务器和客户端之间)连接命令执行. 它规定:

  • 缓冲事件 :

    如果某一事件在任何订阅者连接之前发布,插件会缓冲该事件,并在订阅者出现时立即冲出.

  • 最大缓冲超时 :

    缓冲事件在可配置的超时后被自动丢弃(默认为5000ms)来防止内存出漏.

  • 程序间沟通:

    允许通过 MessagePort 发送命令并接收回复,使其对网络工人,iframes 或其他多文本环境等情景最为理想.

示例使用法:

import { CommandBus, Command, PortChannelPlugin } from "@collidor/command";

// Define a command
class CreateUser extends Command<{ name: string }, { id: string }> {}

// Create an instance of the PortChannel Plugin.
// Optionally, configure the buffer timeout (in milliseconds)
const portPlugin = new PortChannelPlugin({ bufferTimeout: 5000 });

// Create a CommandBus with the PortChannel Plugin installed.
const bus = new CommandBus({ plugin: portPlugin });

// Register a command handler on the bus.
bus.register(CreateUser, (command, context) => ({
  id: "user-" + Math.random().toString(36).slice(2),
}));

// Dispatch a command via the PortChannel Plugin.
// The plugin buffers events until a subscriber (e.g. a connected MessagePort) attaches.
const user = await bus.execute(new CreateUser({ name: "Alice" }));
console.log(user); // e.g. { id: "user-..." }

注释:

  • 缓行:

    在订阅者连接之前发送的命令或事件将存储在缓冲器中,然后在订阅者(通过添加Port订阅)附加后立即冲出.

  • 超时控制 :

    缓冲事件的最大时间由缓冲Timeout选项控制.

  • 互通性:

    这个插件在服务器和客户端分别居住在执行上下文(如网络工人或iframes)的情景中特别有用,确保事件不会在初始连接延迟时丢失.

类型转换

基于插件的自动返回类型包装 :

// Given this plugin:
  const plugin: CommandBusPlugin<
    Command,
    typeof context,
    Command[COMMAND_RETURN][]
  > = {
    handler: (command, c, h) => [(h?.(command, c))],
  };

// Return type becomes Array<{ id: string }>
const result = bus.execute(new CreateUser());

捐款

  1. 分叉仓库
  2. 创建特性分支( git checkout - b 特性/ fooBar)
  3. 执行更改( git 承诺 - a 添加一些 fooBar)
  4. 推到分支( git 推出源功能/ fooBar)
  5. 创建新的拉请求

许可证

麻省理工学院

版本与发布记录

@collidor/command 共发布 87 个版本,首次发布于 2021/10/14;过去 12 个月发布了 14 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
7.3.4latest2026/10/091 个月前
7.3.32026/10/091 个月前
7.3.22026/10/081 个月前
7.3.12026/10/081 个月前
7.3.02026/10/021 个月前
7.2.12026/09/261 个月前

关于 @collidor/command 的常见问题

@collidor/command 是什么?

一个创建,注册和执行命令的小库.

如何安装 @collidor/command?

在项目目录运行 npm install @collidor/command,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@collidor/event(^4.7.2)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@collidor/command 支持 TypeScript 吗?

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

@collidor/command 支持 ESM 还是 CommonJS?

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

@collidor/command 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=24.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@collidor/command 可以商用吗?

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

@collidor/command 的下载量有多少?

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

@collidor/command 还在维护吗?

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