@crvouga/mockingbird-service-emqx

中文文档
0.10.0发布于 2026/11/11MITTypeScriptES Module构建来源已验证近 30 天下载 2962

状态模拟器 EMQQQT 5 MQTT 经纪人: MQTT 5 超越 TCP 和 WebSocket, 密码和 JWT 认证 JWT ACLs, 有离线QoS 1 队列的持续会话, REST v5 发布和客户端 Kick 端点.

中文使用文档
文档目录9 节
  1. 安装
  2. 使用量
  3. MQTT 数据
  4. 路线
  5. 管理员(超过标准合同)
  6. 命名空间
  7. 未核实
  8. 故意不模拟
  9. API 密码

@crvouga/mockingbird-service-emqx (英语)

本地模拟器。 真正的API合同. 部分 嘲笑鸟。 。 。 .

国家模拟器 EMQX. 5 测试套房和本地开发的MQTT经纪人:一个MQTT 5 tCP和WebSocket的经纪人(/mqtt),EMQX的密码和JWT认证与JWT ACLs, 持续会话带有离线的 QoS 1 队列, 而两个 REST v5 端点只发布 客户需求(POST /api/v5/publish, (中文(简体) ), DELETE /api/v5/clients/{clientid}) (中文(简体) ). 它在测试中运行 在 OS 指定端口上的进程,没有安装经纪人、 Docker 或本地二进制和会话 到期时间跟随一个时钟 套房移动而不是等待.

安装

npm install -D @crvouga/mockingbird-service-emqx

仅限无害环境管理。 节点 22或 Bun 1.2. 无土生属地. 给它服务 npx mockingbird-emqx serve 或者说 createServer 从 ./server (节点和邦). createRuntime (默认条目)是可移植的: 它服务于 REST API over fetch 和 MQTT 通过 runtime.attach没有听者.

使用量

将应用程序的 MQTT URL 指向 mqttUrl (或 wsUrl),其EMQX API来源于 url,并给它 您在此配置的 API 密钥、 MQTT 用户和 JWT 密钥 .

import { createServer } from "@crvouga/mockingbird-service-emqx/server"
import mqtt from "mqtt"

const emqx = await createServer({
  settings: {
    apiKeys: [{ key: "test-key", secret: "test-secret" }],
    users: [{ username: "service", password: "service-password", superuser: true }],
    jwt: { secret: "test-jwt-secret" }, // HS256 token in the CONNECT password
    authorization: { noMatch: "deny" },
  },
})
// emqx.url      http://127.0.0.1:<port>       REST API and /__admin
// emqx.mqttUrl  mqtt://127.0.0.1:<port>       MQTT 5 over TCP
// emqx.wsUrl    ws://127.0.0.1:<port>/mqtt    MQTT 5 over WebSocket

const client = await mqtt.connectAsync(emqx.mqttUrl, {
  protocolVersion: 5,
  clientId: "device-1",
  clean: false,
  properties: { sessionExpiryInterval: 600 },
  username: "service",
  password: "service-password",
})
await client.subscribeAsync("space:example", { qos: 1 })

// EMQX publishes no JavaScript SDK for its REST API, so the publisher calls it over HTTP.
await fetch(`${emqx.url}/api/v5/publish`, {
  method: "POST",
  headers: {
    authorization: `Basic ${btoa("test-key:test-secret")}`,
    "content-type": "application/json",
  },
  body: JSON.stringify({ topic: "space:example", payload: "hello", qos: 1, retain: false }),
})

// Test control: move time instead of waiting for a session to expire.
await fetch(`${emqx.url}/__admin/clock`, { method: "POST", body: '{"advance": "600s"}' })

await client.endAsync()
await emqx.close() // closes every listener and drops every client
npx mockingbird-emqx serve --port 8850 --mqtt-port 1883 \
  --api-key test-key:test-secret --mqtt-user service:service-password \
  --jwt-secret test-jwt-secret --no-match deny

每个 createServer() 是它自己拥有自己的港口的经纪人,其中两个没有分享任何东西。 下 邦顿, mqtt节点 WebSocket 传输没有启动( Bun) ws 没有 createWebSocketStream,所以连接到 wsUrl 与库的浏览器传输 (单位:千美元)new MqttClient((c) => browserStreamBuilder(c, options), options) 从 mqtt/lib/connect/ws, (中文(简体) ), 或用途 connectStream(runtime) 从 ./server 用于无套接字连接。 在平原的节点上 mqtt.connect("ws://…/mqtt") 工作时.

MQTT 数据

MQTT 5.0 在TCP和WebSocket上运行 /mqtt (副议定书) mqtt,还有 mqtt-v3, (中文(简体) ), mqtt-v3.1.1, (中文(简体) ), mqtt-v5; 没有更新的升级被解答 400,正如 EM 所做的那样 fail_if_no_subprotocol) (中文(简体) ). 两种运输方式都达到相同的会话.

包装行为
连接/连接规格中的 Clean Start 和会话过期间隔 : clean: false 恢复存储会话( c)sessionPresent: true),一个干净的开始丢弃它. EMQ按发送的客户端间隔. CONNACK载有最大包尺寸1048576,Topic Alias 最大65535,接受最大订阅32,Wildcard 订阅可用 1,订阅识别符可用 1,以及此仿真器无法做到的: 最大QoS 1,保留可用 0,共享订阅可用 0. 空客户端 ID 被指定 16 个字符 .
认证EM-Q的链:内置数据库users),然后是JWT认证器(英语:jwt) (中文(简体) ). 没有配置任何连接, 如在新鲜的EMQX上。 错误的密码是 CONNACK 0x86; 用来验证但已过期的标志( 或 已过期) exp),目前无效(nbf),失败 verify_claims 或有缺陷 acl 实值 0x86;不验证或认证人不承认的证书是 0x87。 。 。 .
第二 CONNECT 有连接客户端 ID旧的连接得到DICONNECT 0x8E 会议结束;新的会议恢复会议,除非它要求有一个干净的开始.
子公司/分公司精确过滤器和 + 编号 : # 通配符,无本地,订阅标识符. 授予的QoS最多1分. 拒绝的过滤器是 SUBACK 0x87· ; $share/… 实值 0x9E。 。 。 .
PUBLISH / PUBACK 软件Qos 0和1. PUBACK为 0x00, (中文(简体) ), 0x10 或 0x87 被拒绝时( 信件被丢弃; 被拒绝的QoS 0 发布被悄悄地丢弃) 。 属性(内容类型,响应话题,关联数据,用户属性,有效载荷格式指标,消息过期间隔)被转发. 入门专题别名能用.
离线连接已去掉的会话会保留订阅并排队列信件(Qos 0 too, as mqtt.mqueue_store_qos0; 最多1 000起,最老的下降,因为 mqtt.max_mqueue_len) (中文(简体) ). 发送和未确认的信息在复刊时会遭到DUP的不满。 最多32个QoS 1信息正在飞行中(mqtt.max_inflight),如果客户端的"接收最大"更低.
会话到期Session Expiry Interval 连接结束后秒,在模拟时钟上. 0 (或缺席)以连接结束会话.
JWT 过期与 disconnectAfterExpire (EMQ) 连接的客户端被发送到 DICONNECT 0x87 当它的标志 exp 过关了 连接中断了 ACL否认一切.

JWT ACL. (英语). 标志 acl 索赔(可配置名称)先问:

  • 对象形式, {"pub": [...], "sub": [...], "all": [...]}: 允许列出的主题 其它的都被否认了.
  • 名单表, [{"permission": "allow" | "deny", "action": "pub" | "sub" | "all", "topic": "…", "qos"?: [0, 1], "retain"?: false}]: 第一个匹配规则决定;一个没有匹配规则的主题 归为 authorization.noMatch (单位:千美元)allow 默认, 如 EMQX 5; EMQX 6 更改了默认 改为 deny) (中文(简体) ).

ACL 主题为 MQTT 过滤器 ${clientid} 财务报告和审定财务报表 ${username} 扩大; eq <topic> 比较 从字面上说 请求的过滤器按文字匹配, 所以规则 a/+ 涵盖a 订阅 a/# (EMQX emqx_topic:match/2) (中文(简体) ). 一个超级用户来自 users 跳过 授权。 与 authorization.denyAction: "disconnect" 拒绝操作结束 连接到 DISCONNECT 0x87 换句话说.

模拟器的模型 经纪人做什么 一个话题,没有其他的: space:example 是一个 主题级别。 将应用程序的逻辑名称映射到主题上是客户端的工作.

路线

每条路线都需要 Authorization: Basic <api key>:<secret>与 apiKeys 清空任意一对 被接受; 丢失的页眉总是被拒绝.

路线行为
POST /api/v5/publish贾森 {topic, payload, qos?: 0|1|2, retain?, payload_encoding?: "plain"|"base64", properties?}。 。 。 . 200 {"id": "<32 hex>"} 当至少匹配一个会话( 离线的会话计数: 消息已排队); 202 {"reason_code": 16, "message": "no_matching_subscribers"} 那时没有人知道. 400 {"code": "BAD_REQUEST", "message"} 对于一个失败的人体 topic,非字符串 payload, (中文(简体) ), qos 超出范围、未知字段、无效的JSON); 400 {"reason_code": 144, "message": "topic_name_invalid"} 空题或带有通配符; 400 {"reason_code": 151, "message": "packet_too_large"} 超过 1 MB ; 415 当身体不是 application/json. QoS 2 接受并交付给 订阅的QoS.
DELETE /api/v5/clients/{clientid}踢出客户端: 一个连接的客户端获得 DICONNECT 0x98 行政行动、届会、订阅和排行被丢弃(离线会话也是如此). 204,或 404 {"code": "CLIENTID_NOT_FOUND", "message": "Client ID not found"}。 。 。 .
任何,无全权证书401 {"code": "AUTHORIZATION_HEADER_ERROR", "message": "Support authorization: basic/bearer "}; 错误的密钥或密钥是 401 {"code": "BAD_API_KEY_OR_SECRET", "message": "Check api_key/api_secret"}; 无记名符号是 401 BAD_TOKEN全部携带 WWW-Authenticate: Basic Realm="emqx-dashboard"。 。 。 .

管理员(超过标准合同)

路线效果
GET /__admin/clients每届会议: clientId, (中文(简体) ), username, (中文(简体) ), connected, (中文(简体) ), transport, (中文(简体) ), sessionExpiryInterval, (中文(简体) ), connectedAt, (中文(简体) ), disconnectedAt, (中文(简体) ), expiresAt和计数 subscriptions, (中文(简体) ), queued 财务报告和审定财务报表 inflight 留言.
GET /__admin/clients/:clientId一届会议,订阅日期 topics。 。 。 .
GET /__admin/subscriptions?clientId=订阅: topicFilter,准予 qos,选项.
GET /__admin/publishes{total, publishes}: 以元数据形式出版的上千种topic, (中文(简体) ), qos, (中文(简体) ), bytes, (中文(简体) ), source: "mqtt" | "http" | "admin", (中文(简体) ), clientId, (中文(简体) ), matched, (中文(简体) ), at) (中文(简体) ). 有效载荷从不保存.
POST /__admin/inject{topic, payload | payloadBase64, qos?: 0 | 1}: 向主题的订阅者发送生字节,绕过REST schema和每个ACL. 用它来给消费者一个有效载荷 它必须拒绝。 答复 {matched}。 。 。 .
POST /__admin/transport/cut{clientId?}:一个客户端或所有客户端的网络断电. 现场连接因没有DICONNECT而死亡,新的CONNECT被放弃,没有得到答复. 会话未受影响,按自己的时间安排过期.
POST /__admin/transport/restore{clientId?}:结束停产. GET /__admin/transport 列出切出的内容.
POST /__admin/clients/:clientId/disconnect{reasonCode?}: 发送 DICONNECT( 默认) 0x98)并收紧. 和卖家的踢球不同,会话会留下来.
GET 编号 : PUT /__admin/settings{apiKeys?, users?, jwt?: {secret, from?, aclClaimName?, verifyClaims?, secretBase64Encoded?, disconnectAfterExpire?} | null, authorization?: {noMatch?, denyAction?}} 呼叫的命名空间。 重置运行时间创建的值的返回 .
POST /__admin/clock标准 将时钟一并移走 : 会话经过间隔会被丢弃, 带有过期符的客户端被断开 .
POST /__admin/reset检查站标准 重置会降低每个连接和会话 。 恢复检查点会恢复会话、订阅和排队,并减少直播连接(检查点不能持有套接字).

错误预设( E)POST /__admin/faults {"preset": "<name>", "count"?: n}· ; GET /__admin/faults/presets: connect_bad_credentials (结束) 0x86, (中文(简体) ), connect_not_authorized (单位:千美元)0x87, (中文(简体) ), connect_server_unavailable (单位:千美元)0x88, (中文(简体) ), publish_unavailable (REST发布答案) 503 {"reason_code": 131, "message": "failed_to_dispatch"}, (中文(简体) ), api_unauthorized (每一次紧急呼叫) 答题 401) (中文(简体) ). CONNECT是故障操作 MqttConnect,所以任何原因代码都可以是 强制 : {"operationId": "MqttConnect", "effect": "connack", "params": {"reasonCode": 151}}。 。 。 .

命名空间

平行工人通过命名空间孤立自己. HTTP : (韩语) x-mockingbird-namespace页:1 /__admin/ns/<name> aPI 来源或 API 密钥上的前缀 (单位:千美元)PUT /__admin/credentials {"credentials": {"<api key>": "<namespace>"}}. MQTT: WebSocket (英语) 網址 ws://…/__admin/ns/<name>/mqtt,或CONNECT用户名所按的同一证书地图, 然后,它的客户身份。 未映射的客户端使用默认的名称空间 .

未核实

取自EMQX 5.8.6 来源或未打开,未观察到在经纪人身上:

  • 这个 message 计划文本 400 (EMQ) 打印其配置库的错误; 模拟器 指纹 {"kind": "validation_error", "path": "root.<field>", "reason": …}),基础差64 载荷和未知路径 404。 。 。 .
  • EM 强制整数 payload 以至其小数字符串;模拟者拒绝.
  • CONNACK接收最大值是EMQQ min(client's, 32);模拟器总是发出32.
  • 这个 is_superuser 符号索赔不读取.

故意不模拟

  • MQTT 3.1和3.1.1:这种CONNECT以协议的回码被拒绝.
  • QoS 2: CONNACK表示最大QoS 1,一个QoS 2的订阅获得QoS 1,一个QoS 2 发布是回答 DISCONNECT 0x9B.EMQX本身支持QoS 2.
  • 保留信件: CONNACK 表示保留可用 0, 保留的出版物被回答 分解系统 0x9A,以及 retain: true 记录显示 400。 。 。 .
  • 将信件(收录于CONNECT,从未出版),共享订阅,增强 认证( AUTH ), 留守超时( PINGREQ 已回答; 使用已死亡的运算切换) 连接、 消息过期、 和外出主题别名 .
  • 公用钥匙和JWKS代号、密码散列、以及核证人或授权人以外的 内置数据库和JWT.
  • 集群、仪表板及其登录标志、规则引擎、桥梁、计费、TLS和 听众配置 .

API 密码

导出仁爱说明
createRuntime函数服务合同的模拟者。 选项 : settings, (中文(简体) ), clock, (中文(简体) ), seed, (中文(简体) ), adminPrefix, (中文(简体) ), adminKey, (中文(简体) ), onLog, (中文(简体) ), sqlite添加 attach(transport, info?, namespace?) 为 MQTT 连接, webSocketPath(pathname), (中文(简体) ), endpoints,以及 stop()。 。 。 .
EmqxAPI类一个名字空间的经纪人: fetch(request) 用于rest API, broker 为MQTT, state, (中文(简体) ), reset()选项: sqlite, (中文(简体) ), now, (中文(简体) ), namespace, (中文(简体) ), settings, (中文(简体) ), connectFault。 。 。 .
EMQX_PRESETS对象每个命名的断层预设.
EMQX_NAMESPACE字符串服务名称, "emqx"。 。 。 .
MQTT_CONNECT_OPERATION字符串"MqttConnect",操作id一个错误规则用于CONNECT.
MQTT_WEBSOCKET_PATH字符串"/mqtt"。 。 。 .
MAX_PACKET_SIZE编号1048576,EMQX's mqtt.max_packet_size。 。 。 .
DEFAULT_SETTINGS, (中文(简体) ), DEFAULT_JWT_AUTHENTICATOR对象新鲜的EMQ:没有认证器, no_match = allow;和JWT验证器的默认值.
apiKeyCredential函数请求的 API 密钥( 如何将证书映射到命名空间 ) .
parseAcl, (中文(简体) ), checkAcl函数分析一个 acl 权利要求,并询问有关一个出版物或订阅者的情况(allow, (中文(简体) ), deny 或者说 nomatch) (中文(简体) ).
ReasonCode对象MQTT 5 名下理性码.
document, (中文(简体) ), operationIds, (中文(简体) ), supportedOperationIds数值REST合同及其操作代号.
createServer, (中文(简体) ), connectStream, (中文(简体) ), serveTarget, (中文(简体) ), DEFAULT_PORT, (中文(简体) ), DEFAULT_MQTT_PORT (单位:千美元)./server(中文(简体) )节点服务HTTP、WebSocket和TCP{url, mqttUrl, mqttPort, wsUrl, runtime, close()}; 选项添加 port, (中文(简体) ), mqttPort, (中文(简体) ), host, (中文(简体) ), sweepMs; 正在处理的 MQTT 流 serve CLI目标;港口8850和1883.

部分 嘲笑鸟。 。 。 .

版本与发布记录

@crvouga/mockingbird-service-emqx 共发布 19 个版本,首次发布于 2026/10/11;过去 12 个月发布了 19 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.10.0latest2026/11/11今天
0.9.82026/11/038 天前
0.9.72026/11/038 天前
0.9.62026/11/038 天前
0.9.52026/11/038 天前
0.9.42026/11/038 天前

关于 @crvouga/mockingbird-service-emqx 的常见问题

@crvouga/mockingbird-service-emqx 是什么?

状态模拟器 EMQQQT 5 MQTT 经纪人: MQTT 5 超越 TCP 和 WebSocket, 密码和 JWT 认证 JWT ACLs, 有离线QoS 1 队列的持续会话, REST v5 发布和客户端 Kick 端点.

如何安装 @crvouga/mockingbird-service-emqx?

在项目目录运行 npm install @crvouga/mockingbird-service-emqx,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 mockingbird-emqx,可以用 npx mockingbird-emqx 直接运行。

@crvouga/mockingbird-service-emqx 支持 TypeScript 吗?

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

@crvouga/mockingbird-service-emqx 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@crvouga/mockingbird-service-emqx 可以商用吗?

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

@crvouga/mockingbird-service-emqx 的下载量有多少?

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

@crvouga/mockingbird-service-emqx 还在维护吗?

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