项目地址:https://github.com/noblesnowfield/unicall
文档站:https://noblesnowfield.github.io/unicall-doc/
npm 包:
@noblesnowfield/unicall
带有快速本地调试启动的测试页面

导航
- [为什么做 Unicall](#为什么做 Unicall)
- [Unicall 是什么](#Unicall 是什么)
- 核心设计
- 快速开始
- [Provider 支持](#Provider 支持)
- 中间件能力
- 浏览器接入与安全边界
- 适合哪些场景
- 后续计划
为什么做 Unicall
很多项目都会遇到"通知"这个需求:服务异常要发消息,部署完成要提醒,定时任务失败要报警,业务事件要推送到微信、邮箱或 Webhook。
一开始这通常很简单:
ts
await fetch('https://example.com/webhook', {
method: 'POST',
body: JSON.stringify({ text: '任务完成' })
});
但随着项目变复杂,问题也会变多:
- 不同通知渠道有不同格式。
- 有些渠道支持 Markdown,有些只支持纯文本。
- 邮件要支持 HTML 和附件。
- Webhook、Pushplus、WxPusher、SMTP 的配置方式各不相同。
- 失败后要重试,超时要中断,重复消息要去重。
- 前端不能暴露服务端密钥。
所以我做了 Unicall。
Unicall 是什么
Unicall 是一个面向 Node.js / TypeScript 的轻量通知运行时 SDK。
它的目标不是简单封装某一个 Webhook,而是提供一个统一的通知运行时:
text
Message -> Runtime -> Middleware -> Provider -> Target
你可以用一条 Provider URL 描述通知目标,例如:
text
webhook://127.0.0.1:4317/mock/webhook?scheme=http&method=POST
pushplus://PUSHPLUS_TOKEN?template=markdown
smtp://user:pass@smtp.example.com:465
wxpusher://APP_TOKEN?uid=USER_UID
然后通过统一 API 发送消息。
核心设计
Unicall 的核心设计有三个关键词。
1. URL-driven
通知目标用 URL 表达,适合配置化管理,也方便在本地、测试、生产环境之间切换。
2. Provider-based
每个通知渠道都是独立 Provider。Runtime 不硬编码任何具体渠道逻辑,新增渠道时只需要实现统一接口。
3. Middleware-first
发送流程天然经过中间件,可以组合:
- retry
- timeout
- logging
- metrics
- dedupe
- rate limit
这让通知能力更像一个小型运行时,而不是一堆零散的工具函数。
快速开始
安装:
bash
npm install @noblesnowfield/unicall
发送一条 Webhook 通知:
ts
import { createDefaultProviderRegistry, notify } from '@noblesnowfield/unicall';
const results = await notify(
'webhook://127.0.0.1:4317/mock/webhook?scheme=http&method=POST',
{
title: 'Unicall test',
text: 'Hello from Unicall.'
},
{
registry: createDefaultProviderRegistry()
}
);
console.log(results[0]?.success);
如果需要复用多个目标,可以使用 NotificationRuntime:
ts
import {
NotificationRuntime,
createDefaultProviderRegistry,
retryMiddleware,
timeoutMiddleware
} from '@noblesnowfield/unicall';
const runtime = new NotificationRuntime({
registry: createDefaultProviderRegistry(),
middleware: [
timeoutMiddleware({ timeoutMs: 5000 }),
retryMiddleware({ retries: 2 })
]
});
runtime.add([
'webhook://127.0.0.1:4317/mock/webhook?scheme=http&method=POST',
'pushplus://PUSHPLUS_TOKEN?template=markdown'
]);
await runtime.send({
title: '部署完成',
markdown: '## Unicall\n\n生产环境部署完成。'
});
Provider 支持
当前已经支持:
| Provider | 协议 | 适合场景 |
|---|---|---|
| Webhook | webhook:// |
自有服务、本地 mock、后端代理 |
| Email / SMTP | smtp://、mailto:// |
HTML 邮件、附件、运维通知 |
| 喵提醒 | miaotixing:// |
个人轻量文本提醒 |
| Pushplus | pushplus:// |
微信消息、Markdown / HTML 推送 |
| WxPusher | wxpusher:// |
微信公众号应用推送 |
Provider 文档可以看这里:
https://noblesnowfield.github.io/unicall-doc/providers/webhook
中间件能力
Unicall 把中间件作为一等能力,而不是事后补丁。
例如:超时 + 重试。
ts
const runtime = new NotificationRuntime({
registry: createDefaultProviderRegistry(),
middleware: [
timeoutMiddleware({ timeoutMs: 3000 }),
retryMiddleware({ retries: 3 })
]
});
这类能力在通知场景里很实用:
- 第三方服务偶发失败,可以重试。
- 某个渠道响应太慢,可以超时。
- 重复事件可以去重。
- 高频通知可以限流。
- 发送结果可以接入 metrics。
浏览器接入与安全边界
Unicall 也提供浏览器构建:
ts
import { NotificationRuntime } from '@noblesnowfield/unicall/browser';
也可以使用 <script>:
html
<script src="./dist/unicall.global.js"></script>
<script>
const runtime = new Unicall.NotificationRuntime();
</script>
但需要特别注意:不要在浏览器代码里暴露服务端密钥。
例如这些都不应该放在前端:
- SMTP 密码
- Pushplus token
- WxPusher app token
- 企业微信 webhook key
- 飞书 / 钉钉 secret
更推荐的生产链路是:
text
Browser -> 你的后端 /api/notify -> Unicall Runtime -> Provider
适合哪些场景
Unicall 比较适合:
- Node.js 项目通知聚合
- 定时任务失败告警
- 部署完成提醒
- 业务事件推送
- 内部系统 Webhook 转发
- 邮件 + 微信类通知统一封装
- 需要 retry / timeout / dedupe 的通知场景
如果只是一个一次性的 fetch(webhook),可能不需要它。
但如果你开始同时接入多个通知渠道,并且希望配置、消息模型、错误处理和中间件统一,Unicall 会更合适。
后续计划
后续我希望继续完善:
- 更多国内常用通知 Provider
- 更完整的 Provider URL 文档
- 更丰富的模板示例
- 浏览器端安全接入示例
- 更完善的 CI 发布和自动化验证
Unicall 目前已经发布到 npm:
bash
npm install @noblesnowfield/unicall
完整文档:
https://noblesnowfield.github.io/unicall-doc/
如果你也在项目里维护过一堆零散的通知脚本,Unicall 想解决的正是这个问题:用统一的运行时,把通知能力变成可以组合、可以测试、可以长期维护的基础设施。