14 KiB
WebHooker
GitHub / Gitea webhook → Discord / Telegram 分发服务。通过 Cloudflare Workers 接收 webhook 事件,应用过滤器,将格式化消息路由到 Discord 频道/子区与 Telegram 群组/话题。各 forge 适配器位于 server/lib/providers/(目前支持 GitHub + Gitea;GitLab 等可后续扩展)。
功能特性
- 28 种事件格式化 — push、pull_request、issues、issue_comment、workflow_run、workflow_job、status、deployment、deployment_status、check_run、check_suite、ping、release、create、delete、star、fork、pull_request_review、pull_request_review_comment、commit_comment、member、label、milestone、discussion、discussion_comment、repository、code_scanning_alert、dependabot_alert(+ 通用回退,+
custom自定义 webhook) - 多平台 webhook — GitHub(
X-Hub-Signature-256)与 Gitea(X-Gitea-Signature)共用/webhook端点,自动识别来源平台 - 分组级 webhook 入口 — 每个分组可拥有独立的
POST /webhook/{groupId}URL + secret(Gitea、classic GitHub webhook,以及用X-WebHooker-Signature签名的任意自定义 JSON,可选的 timestamp+nonce 重放防护) - GitHub App 租户隔离 — 将分组绑定到 GitHub App 安装 ID,只有该组织/用户的事件才能进入该分组
- HMAC-SHA256 签名验证(Web Crypto API)
- 按事件类型、仓库、操作人、操作、分支、关键词过滤(支持
*/?通配符与/正则/) - 富消息:颜色编码、作者头像、字段、时间戳——渲染为 Discord embed 与 Telegram HTML
- 路由到 Discord 频道/子区与 Telegram 群组/话题(一条路由可多目标)
workflow_run/check_run进度原地编辑同一条消息(运行推进时更新),两个平台均支持- 分组级 Webhook 日志频道 —— 为分组指定一个 Discord 频道/子区或 Telegram 群组/话题,该分组路由每次分发 webhook 都会向其中发送摘要(每条「路由 × 目标」一行,✅/❌ 结果)
- GitHub OAuth 用户授权(评论、编辑评论、删除评论、合并、关闭、反应)
- Web 配置控制台(
/admin)— 通过 GitHub OAuth + 管理员白名单管理路由与分组、查看发送日志 - Discord Interactions Endpoint(Ed25519 验签)支持
/gh斜杠命令、消息右键菜单命令、PR 合并/关闭按钮与评论 modal - Telegram
/gh命令(login/logout/comment/merge/close),通过 Telegram webhook 接收,头像以链接预览卡片呈现 - Cloudflare KV 存储 token/状态/配置/会话 + D1 存储发送日志与平台账号绑定
- Cloudflare Queues 异步投递 —— 绑定
QUEUE时,已验签的 webhook 会入队到webhooker-delivery,由消费者分发,带指数退避重试(5s/30s/2m/10m)与死信队列(webhooker-delivery-dlq);超大负载暂存于 KV。未绑定则保持同步分发 - 优雅降级(Discord 不可用时仅 webhook 模式)
架构
GitHub Webhook → Cloudflare Worker (Nuxt 4 / Nitro)
├── POST /webhook → 验证 → 去重 → 入队 (Queue) → 分发 → Discord (REST) / Telegram (Bot API)
├── POST /discord/interactions → 验证 (Ed25519) → 处理命令/按钮/modal
├── POST /telegram/webhook → 验证 (secret token) → 处理 /gh 命令
├── GET /auth/github → OAuth 流程
├── GET /api/richheader → Telegram 头像链接预览卡片
├── POST /api/* → 用户操作(Bearer token 鉴权)
├── /admin → 路由、分组与发送日志 Web UI
└── GET /health → 健康检查
- Cloudflare Worker — HTTP 入口、签名验证、路由分发
- Interactions Endpoint — HTTPS 回调(无 Discord Gateway 连接、无 Durable Object);bot 保持离线,命令通过 API 注册
- KV — Token 存储(
token:{userId})、OAuth state(state:{hex})、路由配置(config:routes)、分组配置(config:groups)、管理员会话(session:{id})、投递去重(delivery:{provider}:{groupId}:{id})、投递状态(delivery-state:*)、消息更新追踪(msg:*) - D1 — 发送日志(
send_logs)、Discord↔GitHub 绑定(discord_links)、Telegram↔GitHub 绑定(telegram_links) - Queue — 绑定
QUEUE时异步投递:webhooker-delivery(指数退避重试)+ 死信队列webhooker-delivery-dlq;超大负载暂存于 KV(queue:payload:*)
快速开始
bun install # 包管理器为 bun(锁文件:bun.lock)
cp .env.example .dev.vars # 填写本地开发密钥
bun run build # 先构建生产产物(wrangler dev 运行的是构建产物)
bunx wrangler dev # 启动本地开发服务器
配置
密钥(本地用 .dev.vars,生产用 Worker Secrets)
| 变量 | 说明 |
|---|---|
GITHUB_WEBHOOK_SECRET |
GitHub webhook 密钥 |
GITEA_WEBHOOK_SECRET |
Gitea webhook 密钥(仅接收 Gitea webhook 时需要) |
GITHUB_APP_ID |
GitHub App ID(用于 App 安装流程解析安装所属账号) |
GITHUB_PRIVATE_KEY |
App 私钥(PKCS#8 PEM;用于 App 安装流程,可选) |
GITHUB_CLIENT_ID |
OAuth Client ID |
GITHUB_CLIENT_SECRET |
OAuth Client Secret |
DISCORD_TOKEN |
机器人 token |
DISCORD_PUBLIC_KEY |
Discord 应用的公钥(开发者门户获取)—— 交互功能必需 |
DISCORD_APPLICATION_ID |
Discord 应用 ID(可选;省略时通过 GET /oauth2/applications/@me 自动获取) |
TELEGRAM_TOKEN |
Telegram Bot Token(BotFather 获取)—— Telegram 路由必需 |
TELEGRAM_WEBHOOK_SECRET |
可选;POST /telegram/webhook 的验签密钥 |
TELEGRAM_RICH_HEADER_HOST |
可选;覆盖内置 GET /api/richheader 的 Telegram 头像卡片地址 |
BASE_URL |
公网地址(用于 OAuth 回调与 Telegram webhook 同步) |
ADMIN_USER_IDS |
允许访问 /admin 的 GitHub 用户 ID(或登录名),逗号分隔 |
ALLOW_SELF_SIGNUP |
设为 1 时,无权限的 GitHub 用户首次登录自动获得个人分组(默认关闭) |
AUDIT_RETENTION_DAYS |
定时清理时审计日志的保留天数(默认 90) |
NUXT_PUBLIC_DOCS_URL |
可选;落地页使用的文档站点 URL |
NUXT_PUBLIC_REPO_URL |
可选;落地页使用的 GitHub 仓库 URL |
NUXT_PUBLIC_LEGAL_CONTACT |
可选;/terms 与 /privacy 页面展示的联系方式 |
路由配置
路由存储在 KV(config:routes,JSON 格式)。没有默认路由——每条路由(包括目标)都必须显式定义,可通过 Web 控制台(/admin)或直接向 KV 存储 JSON 数组。一条路由可携带多个 targets,因此一个规则可以同时转发到多个频道:
[
{
"id": "all-push",
"name": "Push 事件",
"enabled": true,
"groupId": "default",
"filters": [{ "type": "event", "match": "push" }],
"stop": true,
"targets": [
{ "platform": "discord", "channelId": "频道ID" },
{ "platform": "telegram", "chatId": "-1001234567890" }
]
}
]
target.platform 选择推送目标:discord(默认)或 telegram。Discord 目标需 target.channelId(可选 threadId 指向子区);Telegram 目标需 target.chatId(可选 topicId 指向话题)。路由隶属于分组(KV config:groups),分组用于限定管理权限,并可限制哪些组织/用户的事件流入。完整模式见路由与目标与分组与访问控制指南。
Web 控制台(/admin)
内置的配置控制台让你在浏览器中管理路由与分组(新增 / 编辑 / 删除 / 开关 / 排序)、查看发送日志、管理组成员与邀请链接、阅读审计日志——无需操作 KV:
- 设置
ADMIN_USER_IDS为允许管理控制台的 GitHub 用户 ID(或登录名),例如ADMIN_USER_IDS=12345,RhenCloud。 - 访问
/admin并用 GitHub 登录。无任何权限的用户收到403——除非开启ALLOW_SELF_SIGNUP=1(自动获得个人分组)或通过分组邀请链接加入。 - 修改会立即写入 KV,webhook 管线随即生效。
在 /admin/logout 退出登录。每个分组都有带角色的 members(owner / admin / viewer);所有管理操作(登录、分组/路由/成员/邀请变更)都会写入 D1 audit_logs 表。
过滤器类型
所有过滤器均支持纯文本、*/? 通配符与 /正则/(不区分大小写);设置 exclude: true 可取反。模式语法与完整过滤器参考见过滤器教程。
API
健康检查
GET /health— 返回{"status": "ok"}
OAuth
GET /auth/github— 发起 GitHub OAuth 授权(重定向到 GitHub)GET /auth/github/callback— OAuth 回调(交换 code 为 token;管理员会话 / Discord 绑定 / Telegram 绑定)DELETE /auth/token/:userId— 撤销用户 token
操作接口(需要 Authorization: Bearer <token> 头)
POST /api/comment— 创建 issue 评论POST /api/merge— 合并 PRPOST /api/close— 关闭 PRPOST /api/react— 添加 issue 反应
管理接口(需要管理员 OAuth 会话)
GET /admin— 配置控制台页面GET /admin/login— 开始管理员登录(GitHub OAuth)GET /admin/logout— 退出登录GET /admin/invite?token=…— 接受分组邀请(浏览器页面)GET /admin/api/routes— 列出路由PUT /admin/api/routes— 替换路由(按分组 owner/admin 权限)GET /admin/api/groups— 列出分组 + 你的角色PUT /admin/api/groups— 替换分组(超管全量;owner 仅自己的组)GET /admin/api/groups/:groupId/routes— 列出某分组的路由PUT /admin/api/groups/:groupId/routes— 替换某分组的路由POST /admin/api/groups/:groupId/invites— 创建邀请链接(owner)GET /admin/api/groups/:groupId/invites— 列出待接受邀请(owner)DELETE /admin/api/invites/:token— 撤销邀请(owner)GET /admin/api/audit— 审计日志(按权限过滤)GET /admin/api/me— 当前会话 / 权限范围 / 角色GET /admin/api/logs— 发送日志(按权限过滤)GET /admin/api/logs/:id— 单条发送日志
配置教程
- GitHub App — 创建应用、订阅事件、配置 OAuth 与 Setup URL(租户隔离):见 GitHub App 配置
- Discord 机器人 — 创建机器人、以
applications.commandsscope 邀请(组合权限整数274877910016)、配置 Interactions Endpoint:见 Discord Bot 配置。bot 从不连接 Discord Gateway,因此显示为离线——消息推送不受影响(始终走 REST)。 - Telegram 机器人 — 用 @BotFather 创建机器人,设置
TELEGRAM_TOKEN(可选TELEGRAM_WEBHOOK_SECRET);webhook 由定时任务自动同步:见 Telegram 机器人配置 - 部署 — KV 命名空间、D1 数据库与迁移、可选 Queues、密钥、部署:见部署指南
Bot 指令(以本人身份评论 GitHub)
bot 通过定时任务(每 5 分钟)同步注册原生的斜杠命令与消息右键菜单命令:按服务器注册以获得即时可用性,并全局注册(24h 去重,约 1 小时传播)。执行 /gh login 后即可评论 issue/PR、编辑/删除自己的评论,并通过按钮合并/关闭 PR——所有回复均为临时消息(仅你可见),权限交由 GitHub 判定。
/gh login /gh logout
/gh comment add|edit|del link:<链接> (或右键通知 → 应用 → GitHub: 添加/编辑/删除评论)
完整参考见机器人命令指南。
开发命令
bun run dev # Nuxt 开发服务器(HMR)
bun run typecheck # 类型检查
bun run lint # ESLint
bun test # 单元测试
支持的事件
28 个事件格式化器(push、pull_request、issues、workflow_run、release 等)外加 custom webhook;不支持的事件回退到通用格式化器。带嵌入亮点的完整表格见支持的事件。
许可证
MIT