diff --git a/README.zh.md b/README.zh.md index 3b959c7..6b81c1d 100644 --- a/README.zh.md +++ b/README.zh.md @@ -54,7 +54,7 @@ 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 安装流程解析安装所属账号) | diff --git a/docs-plan.md b/docs-plan.md index e46cf8f..7f8391b 100644 --- a/docs-plan.md +++ b/docs-plan.md @@ -7,12 +7,12 @@ ## 一、现状总览 -| 文档 | 规模 | 状态 | -|---|---|---| -| `docs/`(VitePress,en+zh 镜像) | 11 页 ×2,约 75KB | 结构完整但存在事实错误、覆盖缺失、信息架构混乱 | -| `README.md` / `README.zh.md` | 363 行 | 与 docs 大量重复(secrets、GitHub App 设置、部署),已出现漂移 | -| `AGENTS.md` | 222 行 | 基本同步,个别过时 | -| `config.example.yaml` / `.env.example` | — | 良好,但 README/AGENTS 中 `DOCS_URL` 等变量名与代码不符(`.env.example` 正确) | +| 文档 | 规模 | 状态 | +| -------------------------------------- | ----------------- | ------------------------------------------------------------------------------ | +| `docs/`(VitePress,en+zh 镜像) | 11 页 ×2,约 75KB | 结构完整但存在事实错误、覆盖缺失、信息架构混乱 | +| `README.md` / `README.zh.md` | 363 行 | 与 docs 大量重复(secrets、GitHub App 设置、部署),已出现漂移 | +| `AGENTS.md` | 222 行 | 基本同步,个别过时 | +| `config.example.yaml` / `.env.example` | — | 良好,但 README/AGENTS 中 `DOCS_URL` 等变量名与代码不符(`.env.example` 正确) | --- @@ -108,14 +108,14 @@ ## 五、中英一致性(zh 滞后) -| 严重度 | 文件 | 差异 | -|---|---|---| -| 高 | guide/introduction.md | zh 技术栈仍是"Nux3 静态 SPA",en 已为"Nuxt 4 (Vue 3 + Tailwind CSS v3)" | -| 高 | guide/getting-started.md | zh 脚本表缺 `bun run build`、`bun test` 两行;`bun run dev` 描述不一致(wrangler vs Nuxt HMR) | -| 中 | api/overview.md | zh 漏"or manage a group"准入条件;漏"空过滤器仅 fallback 路由允许" | -| 低 | guide/configuration.md | 可选密钥表行序不同;keyword 示例 zh 多 `*release-*`;"manage everything" 译作"管理路由" | -| 低 | guide/filters.md | zh 一处"`/` 包裹"应为"`//` 包裹"(同文件其他处正确) | -| 低 | index.md | 2 处 feature 描述中文略精简(未列签名头部、未列 slash commands and buttons) | +| 严重度 | 文件 | 差异 | +| ------ | ------------------------ | ---------------------------------------------------------------------------------------------- | +| 高 | guide/introduction.md | zh 技术栈仍是"Nux3 静态 SPA",en 已为"Nuxt 4 (Vue 3 + Tailwind CSS v3)" | +| 高 | guide/getting-started.md | zh 脚本表缺 `bun run build`、`bun test` 两行;`bun run dev` 描述不一致(wrangler vs Nuxt HMR) | +| 中 | api/overview.md | zh 漏"or manage a group"准入条件;漏"空过滤器仅 fallback 路由允许" | +| 低 | guide/configuration.md | 可选密钥表行序不同;keyword 示例 zh 多 `*release-*`;"manage everything" 译作"管理路由" | +| 低 | guide/filters.md | zh 一处"`/` 包裹"应为"`//` 包裹"(同文件其他处正确) | +| 低 | index.md | 2 处 feature 描述中文略精简(未列签名头部、未列 slash commands and buttons) | 完全一致的文件对:guide/deployment.md、api/actions.md、api/oauth.md、events/supported.md、contributing.md。 diff --git a/docs/api/admin.md b/docs/api/admin.md index c5d5316..91164d6 100644 --- a/docs/api/admin.md +++ b/docs/api/admin.md @@ -7,7 +7,7 @@ The console itself is served at `/admin`; its tabs are deep-linkable via the URL ## Endpoints | Endpoint | Description | -|-------------------------------------------------|-------------------------------------------------------------------| +| ----------------------------------------------- | ----------------------------------------------------------------- | | `GET /admin` | Config console UI | | `GET /admin/login` | Start admin sign-in (GitHub OAuth) | | `GET /admin/logout` | Sign out and destroy the session | diff --git a/docs/api/overview.md b/docs/api/overview.md index 107f604..c5ded28 100644 --- a/docs/api/overview.md +++ b/docs/api/overview.md @@ -10,27 +10,27 @@ https://your-worker.workers.dev ## Endpoints -| Method | Path | Auth | Description | -|----------|---------------------------------|-------------------|--------------------------------------------------------------------| -| `GET` | `/health` | None | Health check | -| `POST` | `/webhook` | HMAC signature | GitHub / Gitea / custom webhook ingestion (provider auto-detected) | -| `POST` | `/webhook/:groupId` | Per-group secret | Per-group webhook ingress (only that group's routes fire) | -| `POST` | `/discord/interactions` | Ed25519 signature | Discord interactions (slash commands, buttons, modals) | -| `POST` | `/telegram/webhook` | Secret token | Telegram updates (bot `/gh` commands) | -| `GET` | `/api/richheader` | None | Open Graph page for the Telegram avatar link-preview card | -| `GET` | `/auth/github` | None | Start GitHub OAuth flow | -| `GET` | `/auth/github/callback` | None | OAuth callback | -| `GET` | `/auth/github/install` | Admin session | Post-install choice page: bind the installation to a group | -| `POST` | `/auth/github/install/bind` | Admin session | Provision the chosen installation binding | -| `DELETE` | `/auth/token/:userId` | Admin session | Revoke user token | -| `POST` | `/api/comment` | Bearer token | Create issue comment | -| `POST` | `/api/merge` | Bearer token | Merge pull request | -| `POST` | `/api/close` | Bearer token | Close pull request | -| `POST` | `/api/react` | Bearer token | Add reaction to issue | -| `GET` | `/admin` | Admin session | Config console UI | -| `GET` | `/admin/login` | None | Start admin sign-in (GitHub OAuth) | -| `GET` | `/admin/logout` | Admin session | Sign out and destroy the session | -| `GET` | `/admin/invite` | Admin session | Accept a group invite (browser page, `?token=…`) | +| Method | Path | Auth | Description | +| -------- | --------------------------- | ----------------- | ------------------------------------------------------------------ | +| `GET` | `/health` | None | Health check | +| `POST` | `/webhook` | HMAC signature | GitHub / Gitea / custom webhook ingestion (provider auto-detected) | +| `POST` | `/webhook/:groupId` | Per-group secret | Per-group webhook ingress (only that group's routes fire) | +| `POST` | `/discord/interactions` | Ed25519 signature | Discord interactions (slash commands, buttons, modals) | +| `POST` | `/telegram/webhook` | Secret token | Telegram updates (bot `/gh` commands) | +| `GET` | `/api/richheader` | None | Open Graph page for the Telegram avatar link-preview card | +| `GET` | `/auth/github` | None | Start GitHub OAuth flow | +| `GET` | `/auth/github/callback` | None | OAuth callback | +| `GET` | `/auth/github/install` | Admin session | Post-install choice page: bind the installation to a group | +| `POST` | `/auth/github/install/bind` | Admin session | Provision the chosen installation binding | +| `DELETE` | `/auth/token/:userId` | Admin session | Revoke user token | +| `POST` | `/api/comment` | Bearer token | Create issue comment | +| `POST` | `/api/merge` | Bearer token | Merge pull request | +| `POST` | `/api/close` | Bearer token | Close pull request | +| `POST` | `/api/react` | Bearer token | Add reaction to issue | +| `GET` | `/admin` | Admin session | Config console UI | +| `GET` | `/admin/login` | None | Start admin sign-in (GitHub OAuth) | +| `GET` | `/admin/logout` | Admin session | Sign out and destroy the session | +| `GET` | `/admin/invite` | Admin session | Accept a group invite (browser page, `?token=…`) | The `/admin/api/*` endpoints (routes, groups, members, invites, webhook secrets, send logs, audit log) are documented separately in the [Admin API](./admin). @@ -62,11 +62,11 @@ Accepts GitHub webhook payloads. Requires valid `X-Hub-Signature-256` header. **Headers:** -| Header | Required | Description | -|-------------------------|------------|----------------------------------------------------| -| `X-Hub-Signature-256` | Yes | HMAC-SHA256 signature | -| `X-GitHub-Event` | Yes | Event type name | -| `X-GitHub-Delivery` | No | Unique delivery ID (used for dedup when present) | +| Header | Required | Description | +| --------------------- | -------- | ------------------------------------------------ | +| `X-Hub-Signature-256` | Yes | HMAC-SHA256 signature | +| `X-GitHub-Event` | Yes | Event type name | +| `X-GitHub-Delivery` | No | Unique delivery ID (used for dedup when present) | **Request Body:** GitHub webhook JSON payload (max 1MB). @@ -82,11 +82,11 @@ When `X-GitHub-Delivery` is present and the same delivery was already processed **Error Responses:** -| Status | Body | Cause | -|----------|------------------------------------|------------------------------------------| -| `401` | `{"error": "Invalid signature"}` | Signature verification failed | -| `400` | `{"error": "Invalid event"}` | Missing event header or malformed body | -| `413` | `{"error": "Request too large"}` | Body exceeds 1MB limit | +| Status | Body | Cause | +| ------ | -------------------------------- | -------------------------------------- | +| `401` | `{"error": "Invalid signature"}` | Signature verification failed | +| `400` | `{"error": "Invalid event"}` | Missing event header or malformed body | +| `413` | `{"error": "Request too large"}` | Body exceeds 1MB limit | ### Per-Group Webhook (`POST /webhook/:groupId`) @@ -102,10 +102,10 @@ Any JSON payload signed with `X-WebHooker-Signature: sha256=` (HMAC-SHA256 The primary flow is the App's **Setup URL** — set it to `{BASE_URL}/auth/github/install`. After a user installs the App, the browser lands on: -| Method | Path | Description | -|----------|-------------------------------|--------------------------------------------------------------------------------------------------| -| `GET` | `/auth/github/install` | Choice page: bind the installation to a new group or an existing group the signed-in user owns | -| `POST` | `/auth/github/install/bind` | Provisions the binding (owner role re-checked) and redirects to `/admin?install=ok` | +| Method | Path | Description | +| ------ | --------------------------- | ---------------------------------------------------------------------------------------------- | +| `GET` | `/auth/github/install` | Choice page: bind the installation to a new group or an existing group the signed-in user owns | +| `POST` | `/auth/github/install/bind` | Provisions the binding (owner role re-checked) and redirects to `/admin?install=ok` | ## Error Format diff --git a/docs/events/supported.md b/docs/events/supported.md index 6f7001a..7e40db1 100644 --- a/docs/events/supported.md +++ b/docs/events/supported.md @@ -4,51 +4,51 @@ WebHooker supports 28 GitHub webhook event types, each with a dedicated formatte ## Events Table -| Event | Description | Embed Highlights | -|---------------------------------|----------------------------------|--------------------------------------------------------------------------------------------------------------------------| -| `push` | Code pushed to a branch | Commit list, branch, author, diff stats | -| `pull_request` | PR opened/closed/merged/edited | PR title, branch, diff stats, labels | -| `issues` | Issue opened/closed/edited | Issue title, labels, assignees | -| `issue_comment` | Comment on issue or PR | Comment body, issue reference | -| `workflow_run` | CI/CD workflow phase updated | Workflow status, conclusion, duration; phases update a single message in place | -| `workflow_job` | CI job phase updated | Job name, status, conclusion, workflow | -| `status` | Commit status updated | Commit status, context, state, commit link | -| `deployment` | Deployment created | Environment, ref, task | -| `deployment_status` | Deployment status updated | Environment, status, commit ref | -| `check_run` | Check run phase updated | Status, conclusion, details URL; phases update a single message in place | -| `check_suite` | Check suite completed | Suite conclusion, head branch, commit link | -| `ping` | Webhook confirmation | Webhook confirmation, event types subscribed | -| `release` | Release published/edited | Tag, body, assets, pre-release flag | -| `create` | Branch or tag created | Ref name, ref type | -| `delete` | Branch or tag deleted | Ref name, ref type | -| `star` | Repository starred/unstarred | Star count, action | -| `fork` | Repository forked | Source → target fork | -| `pull_request_review` | PR review submitted | Review state (approved/changes/commented), body | -| `pull_request_review_comment` | Inline code review comment | File path, line number, comment body | -| `commit_comment` | Comment on a commit | Commit SHA, comment body | -| `member` | Collaborator added/removed | Member login, action | -| `label` | Label created/edited/deleted | Label name, color, description | -| `milestone` | Milestone opened/closed | Progress bar, issue counts, due date | -| `discussion` | Discussion created/answered | Title, category, action | -| `discussion_comment` | Comment on discussion | Comment body, discussion reference | -| `repository` | Repo renamed/transferred | Old → new name, changes | -| `code_scanning_alert` | Code scanning alert | Severity, rule ID, file path | -| `dependabot_alert` | Dependabot alert | Severity, package, vulnerable range, fix version | -| `custom` | Signed custom JSON webhook | Arbitrary title/description/color/url/author/fields (see [Custom webhooks](../guide/ingress.md#custom-webhooks)) | +| Event | Description | Embed Highlights | +| ----------------------------- | ------------------------------ | ---------------------------------------------------------------------------------------------------------------- | +| `push` | Code pushed to a branch | Commit list, branch, author, diff stats | +| `pull_request` | PR opened/closed/merged/edited | PR title, branch, diff stats, labels | +| `issues` | Issue opened/closed/edited | Issue title, labels, assignees | +| `issue_comment` | Comment on issue or PR | Comment body, issue reference | +| `workflow_run` | CI/CD workflow phase updated | Workflow status, conclusion, duration; phases update a single message in place | +| `workflow_job` | CI job phase updated | Job name, status, conclusion, workflow | +| `status` | Commit status updated | Commit status, context, state, commit link | +| `deployment` | Deployment created | Environment, ref, task | +| `deployment_status` | Deployment status updated | Environment, status, commit ref | +| `check_run` | Check run phase updated | Status, conclusion, details URL; phases update a single message in place | +| `check_suite` | Check suite completed | Suite conclusion, head branch, commit link | +| `ping` | Webhook confirmation | Webhook confirmation, event types subscribed | +| `release` | Release published/edited | Tag, body, assets, pre-release flag | +| `create` | Branch or tag created | Ref name, ref type | +| `delete` | Branch or tag deleted | Ref name, ref type | +| `star` | Repository starred/unstarred | Star count, action | +| `fork` | Repository forked | Source → target fork | +| `pull_request_review` | PR review submitted | Review state (approved/changes/commented), body | +| `pull_request_review_comment` | Inline code review comment | File path, line number, comment body | +| `commit_comment` | Comment on a commit | Commit SHA, comment body | +| `member` | Collaborator added/removed | Member login, action | +| `label` | Label created/edited/deleted | Label name, color, description | +| `milestone` | Milestone opened/closed | Progress bar, issue counts, due date | +| `discussion` | Discussion created/answered | Title, category, action | +| `discussion_comment` | Comment on discussion | Comment body, discussion reference | +| `repository` | Repo renamed/transferred | Old → new name, changes | +| `code_scanning_alert` | Code scanning alert | Severity, rule ID, file path | +| `dependabot_alert` | Dependabot alert | Severity, package, vulnerable range, fix version | +| `custom` | Signed custom JSON webhook | Arbitrary title/description/color/url/author/fields (see [Custom webhooks](../guide/ingress.md#custom-webhooks)) | ## Color Coding Each event type uses a distinct color in the Discord embed (from `server/lib/formatters/colors.ts`): -| Color | Events | -|----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Green (`#2da44e`) | push, PR opened / ready for review, issue opened, workflow success, release published, check success, review approved, deployment success, member added, milestone closed, discussion answered | -| Red (`#f85149`) | PR closed, issue closed, workflow failure, release deleted, delete, check failure, review changes requested, deployment failure, member removed, code scanning / dependabot critical & high | -| Purple (`#8957e5`) | PR merged, label, discussion | -| Blue (`#1f6feb`) | PR (other actions), issue reopened, fork, milestone opened | -| Yellow (`#d29922`) | workflow (queued/running/other), release prerelease, star, check (other), deployment pending, code scanning / dependabot medium | -| Gray (`#6e7681`) | issue comment, commit comment, discussion comment | -| Gray (`#8b949e`) | review commented, repository, code scanning / dependabot low, default | +| Color | Events | +| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Green (`#2da44e`) | push, PR opened / ready for review, issue opened, workflow success, release published, check success, review approved, deployment success, member added, milestone closed, discussion answered | +| Red (`#f85149`) | PR closed, issue closed, workflow failure, release deleted, delete, check failure, review changes requested, deployment failure, member removed, code scanning / dependabot critical & high | +| Purple (`#8957e5`) | PR merged, label, discussion | +| Blue (`#1f6feb`) | PR (other actions), issue reopened, fork, milestone opened | +| Yellow (`#d29922`) | workflow (queued/running/other), release prerelease, star, check (other), deployment pending, code scanning / dependabot medium | +| Gray (`#6e7681`) | issue comment, commit comment, discussion comment | +| Gray (`#8b949e`) | review commented, repository, code scanning / dependabot low, default | ## Generic Fallback @@ -66,11 +66,11 @@ Any event type without a dedicated formatter falls through to the generic format See the [Filter Tutorial](../guide/filters) for a hands-on guide with worked examples. -| Filter | Works With | -|-------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `event` | All events | -| `repo` | All events | -| `actor` | All events | -| `action` | Events with `action` field in payload | -| `branch` | push, pull_request, pull_request_review, pull_request_review_comment, create, delete, workflow_run, workflow_job, check_suite, deployment, code_scanning_alert | -| `keyword` | All events (searches full payload body) | +| Filter | Works With | +| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `event` | All events | +| `repo` | All events | +| `actor` | All events | +| `action` | Events with `action` field in payload | +| `branch` | push, pull_request, pull_request_review, pull_request_review_comment, create, delete, workflow_run, workflow_job, check_suite, deployment, code_scanning_alert | +| `keyword` | All events (searches full payload body) | diff --git a/docs/guide/commands.md b/docs/guide/commands.md index 1aba8df..fe468f5 100644 --- a/docs/guide/commands.md +++ b/docs/guide/commands.md @@ -7,7 +7,7 @@ After [linking your GitHub account](#linking-your-account), you can act on GitHu You must link your GitHub account once before using any command: | Platform | Command | Effect | -|----------|-----------------------------------|------------------------------------------------------------------| +| -------- | --------------------------------- | ---------------------------------------------------------------- | | Discord | `/gh login` | Returns an ephemeral OAuth link to authorize your GitHub account | | Discord | `/gh logout` | Unlinks your GitHub account | | Telegram | `/gh login` (reply to a message) | Returns an OAuth link | @@ -44,7 +44,7 @@ Notifications for open PRs include **合并 / 关闭** (merge/close) buttons: ### Requirements | Item | How | -|--------------|----------------------------------------------------------------------------------------------------| +| ------------ | -------------------------------------------------------------------------------------------------- | | Public key | `DISCORD_PUBLIC_KEY` set + Interactions Endpoint URL configured | | Invite scope | Bot invited with `applications.commands` (see [Discord Bot Setup](./deployment#discord-bot-setup)) | | OAuth | `GITHUB_CLIENT_ID` / `GITHUB_CLIENT_SECRET` and `BASE_URL` configured | diff --git a/docs/guide/groups.md b/docs/guide/groups.md index d3ae455..91568d6 100644 --- a/docs/guide/groups.md +++ b/docs/guide/groups.md @@ -21,7 +21,7 @@ Routes belong to groups. Groups scope admin access and can restrict which events ``` | Field | Type | Required | Description | -|------------------|----------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ---------------- | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | Yes | Lowercase id (`a-z0-9`, `-`); referenced by each route's `groupId`. Editable: renaming a group re-points its routes, per-group webhook secret and pending invites | | `name` | string | Yes | Human-readable group name | | `members` | object[] | No | `{ login, role }` entries; role is `owner`, `admin`, or `viewer` | @@ -38,7 +38,7 @@ Routes belong to groups. Groups scope admin access and can restrict which events Every group member has one of three roles. Super admins (`ADMIN_USER_IDS`) always bypass them. | Role | View routes/logs | Edit routes | Manage members & invites | Edit group settings | -|----------|------------------|-------------|--------------------------|---------------------| +| -------- | ---------------- | ----------- | ------------------------ | ------------------- | | `owner` | ✓ | ✓ | ✓ | ✓ (except `owners`) | | `admin` | ✓ | ✓ | ✗ | ✗ | | `viewer` | ✓ (read-only) | ✗ | ✗ | ✗ | diff --git a/docs/guide/i18n.md b/docs/guide/i18n.md index 110eff5..3a8547f 100644 --- a/docs/guide/i18n.md +++ b/docs/guide/i18n.md @@ -13,7 +13,7 @@ Translation overrides are merged from KV under the key `i18n:` as a flat J ```jsonc // KV key: i18n:zh { - "events.push.title": "{repo}: 推送了 {count} 个提交到 {ref}" + "events.push.title": "{repo}: 推送了 {count} 个提交到 {ref}", } ``` diff --git a/docs/guide/ingress.md b/docs/guide/ingress.md index a64cb47..12da507 100644 --- a/docs/guide/ingress.md +++ b/docs/guide/ingress.md @@ -5,7 +5,7 @@ WebHooker ingests webhooks from multiple forges through the same `POST /webhook` endpoint; the provider is auto-detected from the request headers, so point every forge's webhook at `{BASE_URL}/webhook`. | Provider | Event header | Signature header | Signature format | Secret | -|----------|------------------|-----------------------|----------------------------|-------------------------| +| -------- | ---------------- | --------------------- | -------------------------- | ----------------------- | | GitHub | `X-GitHub-Event` | `X-Hub-Signature-256` | `sha256=` HMAC-SHA256 | `GITHUB_WEBHOOK_SECRET` | | Gitea | `X-Gitea-Event` | `X-Gitea-Signature` | plain hex HMAC-SHA256 | `GITEA_WEBHOOK_SECRET` | @@ -51,7 +51,7 @@ Payload schema: ``` | Field | Type | Description | -|---------------|----------|------------------------------------------------------------------------------------------------------------------| +| ------------- | -------- | ---------------------------------------------------------------------------------------------------------------- | | `title` | string | Message title (falls back to "Custom message") | | `description` | string | Optional message body | | `color` | string | Optional embed color: a word (`red`, `green`, `yellow`, `blue`, `purple`, `orange`, `cyan`, `gray`) or `#rrggbb` | diff --git a/docs/guide/logs.md b/docs/guide/logs.md index 4ead225..05ffa93 100644 --- a/docs/guide/logs.md +++ b/docs/guide/logs.md @@ -4,25 +4,25 @@ Every dispatch attempt is recorded in the D1 `send_logs` table and browsable in the console (**Logs** tab). Fields: -| Field | Meaning | -|--------------|-------------------------------------------------------------------------| -| `routeId` | Route that matched | -| `groupId` | Route's group | -| `event` | Event type (e.g. `push`, `pull_request`, `custom`) | -| `repo` | Repository full name (when present) | -| `target` | Target id the message was sent to | -| `platform` | `discord` or `telegram` | -| `ok` | Whether the send succeeded | -| `status` | HTTP status from the platform API (when applicable) | -| `error` | Error message (when failed) | -| `errorCode` | Stable error code (e.g. `NO_TARGET`, `NO_TOKEN`, `RATE_LIMITED`) | -| `attempts` | Send attempts including retries | -| `durationMs` | Time spent sending | -| `deliveryId` | Webhook delivery id (when provided) | -| `messageId` | Platform message id (used for in-place edits) | -| `actor` | Sender login | -| `action` | Event action (when present) | -| `detail` | Extra JSON details (when present) | +| Field | Meaning | +| ------------ | ---------------------------------------------------------------- | +| `routeId` | Route that matched | +| `groupId` | Route's group | +| `event` | Event type (e.g. `push`, `pull_request`, `custom`) | +| `repo` | Repository full name (when present) | +| `target` | Target id the message was sent to | +| `platform` | `discord` or `telegram` | +| `ok` | Whether the send succeeded | +| `status` | HTTP status from the platform API (when applicable) | +| `error` | Error message (when failed) | +| `errorCode` | Stable error code (e.g. `NO_TARGET`, `NO_TOKEN`, `RATE_LIMITED`) | +| `attempts` | Send attempts including retries | +| `durationMs` | Time spent sending | +| `deliveryId` | Webhook delivery id (when provided) | +| `messageId` | Platform message id (used for in-place edits) | +| `actor` | Sender login | +| `action` | Event action (when present) | +| `detail` | Extra JSON details (when present) | The console's **Logs** tab lists recent entries (filterable by group) and shows full details for a single entry. Entries are written best-effort — a failed insert never breaks dispatch. diff --git a/docs/guide/routes.md b/docs/guide/routes.md index 6f81d54..fef5d6c 100644 --- a/docs/guide/routes.md +++ b/docs/guide/routes.md @@ -32,7 +32,7 @@ There are **no default routes** — each route must define its own target. If no Each entry of `targets` is a push destination, so one route can forward to several channels at once (e.g. a Discord channel **and** a Telegram group). `target.platform` selects the platform: `discord` (default) or `telegram`. For **Discord**, `target.channelId` is required (a thread in `target.threadId` is optional). For **Telegram**, `target.chatId` (the group/supergroup chat id, e.g. `-1001234567890`) is required and `target.topicId` (the `message_thread_id` of a topic, equivalent of a Discord thread) is optional. There is no fallback to a default channel. | Field | Type | Required | Description | -|------------------|----------|----------|-------------------------------------------------------------------------------------------------| +| ---------------- | -------- | -------- | ----------------------------------------------------------------------------------------------- | | `groupId` | string | Yes | Id of the [group](./groups) this route belongs to | | `fallback` | boolean | No | When `true`, fires only if no non-fallback route matched the event; its own filters are ignored | | `stop` | boolean | No | When `true` and this route matches, no further routes are evaluated for this event | diff --git a/docs/guide/storage.md b/docs/guide/storage.md index 2f1f78a..ab135b2 100644 --- a/docs/guide/storage.md +++ b/docs/guide/storage.md @@ -3,7 +3,7 @@ ## KV Storage Layout | Key Pattern | Value | TTL | -|--------------------------------|-------------------------------------------------------------------------------|--------------------| +| ------------------------------ | ----------------------------------------------------------------------------- | ------------------ | | `config:routes` | JSON array of routes | Permanent | | `config:groups` | JSON array of groups | Permanent | | `session:{id}` | Admin session `{ userId, login }` | 7 days | @@ -26,7 +26,7 @@ The D1 database (`DB` binding, database `webhooker`) holds four tables: | Table | Purpose | -|------------------|------------------------------------------------------------------------------------------------| +| ---------------- | ---------------------------------------------------------------------------------------------- | | `send_logs` | One row per dispatch attempt (route id, event, target, ok/error, duration, error code, detail) | | `audit_logs` | One row per admin operation (login/logout, group/route/member/invite changes) | | `discord_links` | Maps `discord_user_id` → `github_user_id` for `/gh` Discord commands | diff --git a/docs/guide/tasks.md b/docs/guide/tasks.md index 3520eed..58d5519 100644 --- a/docs/guide/tasks.md +++ b/docs/guide/tasks.md @@ -3,7 +3,7 @@ WebHooker runs three maintenance tasks on the scheduled trigger (`*/5 * * * *`, every 5 minutes). They only run on the deployed worker (Cloudflare cron); local `wrangler dev` runs them when triggered via `wrangler dev --test-scheduled`. | Task | Purpose | -|-----------------|------------------------------------------------------------------------------------------------------------------| +| --------------- | ---------------------------------------------------------------------------------------------------------------- | | `discord-sync` | Registers the Discord slash/context-menu commands: per-guild (instant) and globally (24h dedup, ~1h propagation) | | `telegram-sync` | Calls `setWebhook` to `{BASE_URL}/telegram/webhook` (with `TELEGRAM_WEBHOOK_SECRET` as `secret_token` when set) | | `audit-prune` | Deletes `audit_logs` entries older than `AUDIT_RETENTION_DAYS` (default 90) | diff --git a/docs/zh/api/admin.md b/docs/zh/api/admin.md index 10b6202..a59a79a 100644 --- a/docs/zh/api/admin.md +++ b/docs/zh/api/admin.md @@ -6,29 +6,29 @@ ## 端点 -| 端点 | 说明 | -|-------------------------------------------------|-------------------------------------------------------------------| -| `GET /admin` | 配置控制台页面 | -| `GET /admin/login` | 开始管理员登录(GitHub OAuth) | -| `GET /admin/logout` | 退出登录并销毁会话 | -| `GET /admin/invite?token=…` | 接受分组邀请(浏览器页面) | -| `GET /admin/api/me` | 当前会话、权限范围、分组与角色 | -| `GET /admin/api/routes` | 列出路由(按权限过滤) | -| `PUT /admin/api/routes` | 替换路由(按分组 owner/admin) | -| `GET /admin/api/groups` | 列出分组 + 当前用户在各分组的角色 | -| `PUT /admin/api/groups` | 替换分组(超级管理员全部;owner 仅自己的) | -| `GET /admin/api/groups/:id/routes` | 列出某分组的路由 | -| `PUT /admin/api/groups/:id/routes` | 替换某分组的路由(owner/admin) | -| `PUT /admin/api/groups/:id/rename` | 重命名分组(owner);路由、webhook secret 与邀请自动跟随 | -| `GET /admin/api/groups/:id/invites` | 列出待处理的邀请(owner) | -| `POST /admin/api/groups/:id/invites` | 创建邀请链接(owner) | -| `DELETE /admin/api/invites/:token` | 撤销邀请(owner) | -| `GET /admin/api/groups/:id/webhook` | 分组 webhook 端点信息(owner) | -| `POST /admin/api/groups/:id/webhook/regenerate` | 生成/重新生成分组 webhook secret(owner) | -| `DELETE /admin/api/groups/:id/webhook` | 停用分组 webhook 入口(owner) | -| `GET /admin/api/logs` | 发送日志(按可访问的路由过滤) | -| `GET /admin/api/logs/:id` | 单条发送日志(按权限过滤) | -| `GET /admin/api/audit` | 审计日志(按可访问的分组过滤) | +| 端点 | 说明 | +| ----------------------------------------------- | -------------------------------------------------------- | +| `GET /admin` | 配置控制台页面 | +| `GET /admin/login` | 开始管理员登录(GitHub OAuth) | +| `GET /admin/logout` | 退出登录并销毁会话 | +| `GET /admin/invite?token=…` | 接受分组邀请(浏览器页面) | +| `GET /admin/api/me` | 当前会话、权限范围、分组与角色 | +| `GET /admin/api/routes` | 列出路由(按权限过滤) | +| `PUT /admin/api/routes` | 替换路由(按分组 owner/admin) | +| `GET /admin/api/groups` | 列出分组 + 当前用户在各分组的角色 | +| `PUT /admin/api/groups` | 替换分组(超级管理员全部;owner 仅自己的) | +| `GET /admin/api/groups/:id/routes` | 列出某分组的路由 | +| `PUT /admin/api/groups/:id/routes` | 替换某分组的路由(owner/admin) | +| `PUT /admin/api/groups/:id/rename` | 重命名分组(owner);路由、webhook secret 与邀请自动跟随 | +| `GET /admin/api/groups/:id/invites` | 列出待处理的邀请(owner) | +| `POST /admin/api/groups/:id/invites` | 创建邀请链接(owner) | +| `DELETE /admin/api/invites/:token` | 撤销邀请(owner) | +| `GET /admin/api/groups/:id/webhook` | 分组 webhook 端点信息(owner) | +| `POST /admin/api/groups/:id/webhook/regenerate` | 生成/重新生成分组 webhook secret(owner) | +| `DELETE /admin/api/groups/:id/webhook` | 停用分组 webhook 入口(owner) | +| `GET /admin/api/logs` | 发送日志(按可访问的路由过滤) | +| `GET /admin/api/logs/:id` | 单条发送日志(按权限过滤) | +| `GET /admin/api/audit` | 审计日志(按可访问的分组过滤) | ## 校验 diff --git a/docs/zh/api/overview.md b/docs/zh/api/overview.md index e381032..13f965c 100644 --- a/docs/zh/api/overview.md +++ b/docs/zh/api/overview.md @@ -10,27 +10,27 @@ https://your-worker.workers.dev ## 端点 -| 方法 | 路径 | 鉴权 | 说明 | -|------------|----------------------------------------------|----------------|--------------------------------------------------------| -| `GET` | `/health` | 无 | 健康检查 | -| `POST` | `/webhook` | HMAC 签名 | GitHub / Gitea / 自定义 webhook 接入(自动识别来源) | -| `POST` | `/webhook/:groupId` | 分组 secret | 分组级 webhook 入口(只触发该分组的路由) | -| `POST` | `/discord/interactions` | Ed25519 签名 | Discord 交互(斜杠命令、按钮、modal) | -| `POST` | `/telegram/webhook` | Secret token | Telegram 更新(bot `/gh` 命令) | -| `GET` | `/api/richheader` | 无 | 用于 Telegram 头像链接预览卡片的 Open Graph 页面 | -| `GET` | `/auth/github` | 无 | 启动 GitHub OAuth 流程 | -| `GET` | `/auth/github/callback` | 无 | OAuth 回调 | -| `GET` | `/auth/github/install` | 管理员会话 | 安装后选择页:将安装绑定到某个分组 | -| `POST` | `/auth/github/install/bind` | 管理员会话 | 执行选定的安装绑定 | -| `DELETE` | `/auth/token/:userId` | 管理员会话 | 撤销用户 Token | -| `POST` | `/api/comment` | Bearer Token | 创建议题评论 | -| `POST` | `/api/merge` | Bearer Token | 合并拉取请求 | -| `POST` | `/api/close` | Bearer Token | 关闭拉取请求 | -| `POST` | `/api/react` | Bearer Token | 添加议题反应 | -| `GET` | `/admin` | 管理员会话 | 配置控制台页面 | -| `GET` | `/admin/login` | 无 | 开始管理员登录(GitHub OAuth) | -| `GET` | `/admin/logout` | 管理员会话 | 退出登录并销毁会话 | -| `GET` | `/admin/invite` | 管理员会话 | 接受分组邀请(浏览器页面,`?token=…`) | +| 方法 | 路径 | 鉴权 | 说明 | +| -------- | --------------------------- | ------------ | ---------------------------------------------------- | +| `GET` | `/health` | 无 | 健康检查 | +| `POST` | `/webhook` | HMAC 签名 | GitHub / Gitea / 自定义 webhook 接入(自动识别来源) | +| `POST` | `/webhook/:groupId` | 分组 secret | 分组级 webhook 入口(只触发该分组的路由) | +| `POST` | `/discord/interactions` | Ed25519 签名 | Discord 交互(斜杠命令、按钮、modal) | +| `POST` | `/telegram/webhook` | Secret token | Telegram 更新(bot `/gh` 命令) | +| `GET` | `/api/richheader` | 无 | 用于 Telegram 头像链接预览卡片的 Open Graph 页面 | +| `GET` | `/auth/github` | 无 | 启动 GitHub OAuth 流程 | +| `GET` | `/auth/github/callback` | 无 | OAuth 回调 | +| `GET` | `/auth/github/install` | 管理员会话 | 安装后选择页:将安装绑定到某个分组 | +| `POST` | `/auth/github/install/bind` | 管理员会话 | 执行选定的安装绑定 | +| `DELETE` | `/auth/token/:userId` | 管理员会话 | 撤销用户 Token | +| `POST` | `/api/comment` | Bearer Token | 创建议题评论 | +| `POST` | `/api/merge` | Bearer Token | 合并拉取请求 | +| `POST` | `/api/close` | Bearer Token | 关闭拉取请求 | +| `POST` | `/api/react` | Bearer Token | 添加议题反应 | +| `GET` | `/admin` | 管理员会话 | 配置控制台页面 | +| `GET` | `/admin/login` | 无 | 开始管理员登录(GitHub OAuth) | +| `GET` | `/admin/logout` | 管理员会话 | 退出登录并销毁会话 | +| `GET` | `/admin/invite` | 管理员会话 | 接受分组邀请(浏览器页面,`?token=…`) | `/admin/api/*` 端点(路由、分组、成员、邀请、webhook 密钥、发送日志、审计日志)在 [Admin API](./admin) 中单独说明。 @@ -62,11 +62,11 @@ POST /webhook **请求头:** -| 头部 | 必需 | 说明 | -|-------------------------|--------|---------------------------------| -| `X-Hub-Signature-256` | 是 | HMAC-SHA256 签名 | -| `X-GitHub-Event` | 是 | 事件类型名称 | -| `X-GitHub-Delivery` | 否 | 唯一投递 ID(存在时用于去重) | +| 头部 | 必需 | 说明 | +| --------------------- | ---- | ----------------------------- | +| `X-Hub-Signature-256` | 是 | HMAC-SHA256 签名 | +| `X-GitHub-Event` | 是 | 事件类型名称 | +| `X-GitHub-Delivery` | 否 | 唯一投递 ID(存在时用于去重) | **请求体:** GitHub webhook JSON 载荷(最大 1MB)。 @@ -82,11 +82,11 @@ POST /webhook **错误响应:** -| 状态码 | 响应体 | 原因 | -|----------|------------------------------------|--------------------------------| -| `401` | `{"error": "Invalid signature"}` | 签名验证失败 | -| `400` | `{"error": "Invalid event"}` | 缺少事件头或格式错误的请求体 | -| `413` | `{"error": "Request too large"}` | 请求体超过 1MB 限制 | +| 状态码 | 响应体 | 原因 | +| ------ | -------------------------------- | ---------------------------- | +| `401` | `{"error": "Invalid signature"}` | 签名验证失败 | +| `400` | `{"error": "Invalid event"}` | 缺少事件头或格式错误的请求体 | +| `413` | `{"error": "Request too large"}` | 请求体超过 1MB 限制 | ### 分组级 Webhook(`POST /webhook/:groupId`) @@ -102,10 +102,10 @@ POST /webhook 主要流程是 App 的 **Setup URL** —— 将其设置为 `{BASE_URL}/auth/github/install`。用户安装 App 后浏览器会跳转到: -| 方法 | 路径 | 说明 | -|----------|-------------------------------|-----------------------------------------------------------------| -| `GET` | `/auth/github/install` | 选择页:将安装绑定到新分组或登录用户拥有 owner 权限的已有分组 | -| `POST` | `/auth/github/install/bind` | 执行绑定(再次校验 owner 角色)并跳转 `/admin?install=ok` | +| 方法 | 路径 | 说明 | +| ------ | --------------------------- | ------------------------------------------------------------- | +| `GET` | `/auth/github/install` | 选择页:将安装绑定到新分组或登录用户拥有 owner 权限的已有分组 | +| `POST` | `/auth/github/install/bind` | 执行绑定(再次校验 owner 角色)并跳转 `/admin?install=ok` | ## 错误格式 diff --git a/docs/zh/events/supported.md b/docs/zh/events/supported.md index f56e9e8..0f22953 100644 --- a/docs/zh/events/supported.md +++ b/docs/zh/events/supported.md @@ -4,51 +4,51 @@ WebHooker 支持 28 种 GitHub webhook 事件类型,每种都有专用的格 ## 事件表 -| 事件 | 说明 | 嵌入亮点 | -|---------------------------------|-----------------------------|------------------------------------------------------------------------------------------------------------------| -| `push` | 代码推送到分支 | 提交列表、分支、作者、差异统计 | -| `pull_request` | PR 打开/关闭/合并/编辑 | PR 标题、分支、差异统计、标签 | -| `issues` | 议题打开/关闭/编辑 | 议题标题、标签、指派人 | -| `issue_comment` | 议题或 PR 的评论 | 评论内容、议题引用 | -| `workflow_run` | CI/CD 工作流阶段更新 | 工作流状态、结论、耗时;各阶段原地更新同一条消息 | -| `workflow_job` | CI 作业阶段更新 | 作业名、状态、结论、工作流 | -| `status` | 提交状态更新 | 提交状态、上下文、状态值、提交链接 | -| `deployment` | 部署已创建 | 环境、引用、任务 | -| `deployment_status` | 部署状态更新 | 环境、状态、提交引用 | -| `check_run` | 检查运行阶段更新 | 状态、结论、详情 URL;各阶段原地更新同一条消息 | -| `check_suite` | 检查套件完成 | 套件结论、head 分支、提交链接 | -| `ping` | Webhook 确认 | Webhook 确认、已订阅的事件类型 | -| `release` | 发布创建/编辑 | 标签、内容、附件、预发布标记 | -| `create` | 分支或标签已创建 | 引用名称、引用类型 | -| `delete` | 分支或标签已删除 | 引用名称、引用类型 | -| `star` | 仓库加星/取消星标 | 星标数、操作 | -| `fork` | 仓库已复刻 | 源 → 目标复刻 | -| `pull_request_review` | PR 审查已提交 | 审查状态(已批准/需修改/已评论)、正文 | -| `pull_request_review_comment` | 行内代码审查评论 | 文件路径、行号、评论内容 | -| `commit_comment` | 提交的评论 | 提交 SHA、评论内容 | -| `member` | 协作者添加/移除 | 成员登录名、操作 | -| `label` | 标签创建/编辑/删除 | 标签名称、颜色、描述 | -| `milestone` | 里程碑打开/关闭 | 进度条、议题计数、截止日期 | -| `discussion` | 讨论创建/回答 | 标题、分类、操作 | -| `discussion_comment` | 讨论的评论 | 评论内容、讨论引用 | -| `repository` | 仓库重命名/转移 | 旧 → 新名称、变更 | -| `code_scanning_alert` | 代码扫描告警 | 严重程度、规则 ID、文件路径 | -| `dependabot_alert` | Dependabot 告警 | 严重程度、包、受影响版本、修复版本 | -| `custom` | 签名的自定义 JSON webhook | 任意 title/description/color/url/author/fields(见[自定义 webhook](../guide/ingress.md#自定义-webhook)) | +| 事件 | 说明 | 嵌入亮点 | +| ----------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------- | +| `push` | 代码推送到分支 | 提交列表、分支、作者、差异统计 | +| `pull_request` | PR 打开/关闭/合并/编辑 | PR 标题、分支、差异统计、标签 | +| `issues` | 议题打开/关闭/编辑 | 议题标题、标签、指派人 | +| `issue_comment` | 议题或 PR 的评论 | 评论内容、议题引用 | +| `workflow_run` | CI/CD 工作流阶段更新 | 工作流状态、结论、耗时;各阶段原地更新同一条消息 | +| `workflow_job` | CI 作业阶段更新 | 作业名、状态、结论、工作流 | +| `status` | 提交状态更新 | 提交状态、上下文、状态值、提交链接 | +| `deployment` | 部署已创建 | 环境、引用、任务 | +| `deployment_status` | 部署状态更新 | 环境、状态、提交引用 | +| `check_run` | 检查运行阶段更新 | 状态、结论、详情 URL;各阶段原地更新同一条消息 | +| `check_suite` | 检查套件完成 | 套件结论、head 分支、提交链接 | +| `ping` | Webhook 确认 | Webhook 确认、已订阅的事件类型 | +| `release` | 发布创建/编辑 | 标签、内容、附件、预发布标记 | +| `create` | 分支或标签已创建 | 引用名称、引用类型 | +| `delete` | 分支或标签已删除 | 引用名称、引用类型 | +| `star` | 仓库加星/取消星标 | 星标数、操作 | +| `fork` | 仓库已复刻 | 源 → 目标复刻 | +| `pull_request_review` | PR 审查已提交 | 审查状态(已批准/需修改/已评论)、正文 | +| `pull_request_review_comment` | 行内代码审查评论 | 文件路径、行号、评论内容 | +| `commit_comment` | 提交的评论 | 提交 SHA、评论内容 | +| `member` | 协作者添加/移除 | 成员登录名、操作 | +| `label` | 标签创建/编辑/删除 | 标签名称、颜色、描述 | +| `milestone` | 里程碑打开/关闭 | 进度条、议题计数、截止日期 | +| `discussion` | 讨论创建/回答 | 标题、分类、操作 | +| `discussion_comment` | 讨论的评论 | 评论内容、讨论引用 | +| `repository` | 仓库重命名/转移 | 旧 → 新名称、变更 | +| `code_scanning_alert` | 代码扫描告警 | 严重程度、规则 ID、文件路径 | +| `dependabot_alert` | Dependabot 告警 | 严重程度、包、受影响版本、修复版本 | +| `custom` | 签名的自定义 JSON webhook | 任意 title/description/color/url/author/fields(见[自定义 webhook](../guide/ingress.md#自定义-webhook)) | ## 颜色编码 每种事件类型在 Discord 嵌入中使用不同的颜色(来自 `server/lib/formatters/colors.ts`): -| 颜色 | 事件 | -|--------------------|-----------------------------------------------------------------------------------------------------------------------------------| -| 绿色 (`#2da44e`) | push、PR 打开/可审查、issue 打开、工作流成功、发布已发布、检查成功、审查已批准、部署成功、成员添加、里程碑关闭、讨论已回答 | -| 红色 (`#f85149`) | PR 关闭、issue 关闭、工作流失败、发布已删除、delete、检查失败、审查请求修改、部署失败、成员移除、代码扫描/Dependabot 严重与高危 | -| 紫色 (`#8957e5`) | PR 合并、label、discussion | -| 蓝色 (`#1f6feb`) | PR(其他操作)、issue 重新打开、fork、里程碑打开 | -| 黄色 (`#d29922`) | 工作流(排队/运行中/其他)、预发布 release、star、检查(其他)、部署待定、代码扫描/Dependabot 中危 | -| 灰色 (`#6e7681`) | issue 评论、commit 评论、讨论评论 | -| 灰色 (`#8b949e`) | 审查评论、repository、代码扫描/Dependabot 低危、默认 | +| 颜色 | 事件 | +| ---------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| 绿色 (`#2da44e`) | push、PR 打开/可审查、issue 打开、工作流成功、发布已发布、检查成功、审查已批准、部署成功、成员添加、里程碑关闭、讨论已回答 | +| 红色 (`#f85149`) | PR 关闭、issue 关闭、工作流失败、发布已删除、delete、检查失败、审查请求修改、部署失败、成员移除、代码扫描/Dependabot 严重与高危 | +| 紫色 (`#8957e5`) | PR 合并、label、discussion | +| 蓝色 (`#1f6feb`) | PR(其他操作)、issue 重新打开、fork、里程碑打开 | +| 黄色 (`#d29922`) | 工作流(排队/运行中/其他)、预发布 release、star、检查(其他)、部署待定、代码扫描/Dependabot 中危 | +| 灰色 (`#6e7681`) | issue 评论、commit 评论、讨论评论 | +| 灰色 (`#8b949e`) | 审查评论、repository、代码扫描/Dependabot 低危、默认 | ## 通用回退 @@ -66,11 +66,11 @@ WebHooker 支持 28 种 GitHub webhook 事件类型,每种都有专用的格 实操指南见[过滤器教程](../guide/filters),包含完整示例。 -| 过滤器 | 适用事件 | -|-------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `event` | 所有事件 | -| `repo` | 所有事件 | -| `actor` | 所有事件 | -| `action` | 载荷中包含 `action` 字段的事件 | -| `branch` | push、pull_request、pull_request_review、pull_request_review_comment、create、delete、workflow_run、workflow_job、check_suite、deployment、code_scanning_alert | -| `keyword` | 所有事件(搜索完整载荷正文) | +| 过滤器 | 适用事件 | +| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `event` | 所有事件 | +| `repo` | 所有事件 | +| `actor` | 所有事件 | +| `action` | 载荷中包含 `action` 字段的事件 | +| `branch` | push、pull_request、pull_request_review、pull_request_review_comment、create、delete、workflow_run、workflow_job、check_suite、deployment、code_scanning_alert | +| `keyword` | 所有事件(搜索完整载荷正文) | diff --git a/docs/zh/guide/commands.md b/docs/zh/guide/commands.md index 98f0998..2d34ad5 100644 --- a/docs/zh/guide/commands.md +++ b/docs/zh/guide/commands.md @@ -6,12 +6,12 @@ 使用任何命令前,需先绑定一次 GitHub 账号: -| 平台 | 命令 | 效果 | -|----------|----------------------------------|-------------------------------------------------------------| -| Discord | `/gh login` | 返回一条仅你可见的 OAuth 链接,用于授权 GitHub 账号 | -| Discord | `/gh logout` | 解除绑定 | -| Telegram | `/gh login`(引用一条消息) | 返回 OAuth 链接 | -| Telegram | `/gh logout`(引用一条消息) | 解除绑定 | +| 平台 | 命令 | 效果 | +| -------- | ---------------------------- | --------------------------------------------------- | +| Discord | `/gh login` | 返回一条仅你可见的 OAuth 链接,用于授权 GitHub 账号 | +| Discord | `/gh logout` | 解除绑定 | +| Telegram | `/gh login`(引用一条消息) | 返回 OAuth 链接 | +| Telegram | `/gh logout`(引用一条消息) | 解除绑定 | 链接保存在服务端(KV),并在 D1 中映射到你的 Discord/Telegram 用户 ID。 @@ -43,12 +43,12 @@ Discord 命令为**斜杠命令**与**消息右键菜单命令**,由定时任 ### 前置条件 -| 项目 | 如何满足 | -|--------------|-----------------------------------------------------------------------------------------------------| -| 公钥 | 设置 `DISCORD_PUBLIC_KEY` 并配置 Interactions Endpoint URL | -| 邀请 scope | 机器人以 `applications.commands` scope 邀请(见 [Discord Bot 设置](./deployment#discord-bot-设置)) | -| OAuth | 配置 `GITHUB_CLIENT_ID` / `GITHUB_CLIENT_SECRET` 与 `BASE_URL` | -| 绑定账号 | 每位用户先执行 `/gh login` | +| 项目 | 如何满足 | +| ---------- | --------------------------------------------------------------------------------------------------- | +| 公钥 | 设置 `DISCORD_PUBLIC_KEY` 并配置 Interactions Endpoint URL | +| 邀请 scope | 机器人以 `applications.commands` scope 邀请(见 [Discord Bot 设置](./deployment#discord-bot-设置)) | +| OAuth | 配置 `GITHUB_CLIENT_ID` / `GITHUB_CLIENT_SECRET` 与 `BASE_URL` | +| 绑定账号 | 每位用户先执行 `/gh login` | ## Telegram diff --git a/docs/zh/guide/getting-started.md b/docs/zh/guide/getting-started.md index a39b646..d415127 100644 --- a/docs/zh/guide/getting-started.md +++ b/docs/zh/guide/getting-started.md @@ -63,7 +63,7 @@ curl http://localhost:8787/health ## 可用脚本 | 脚本 | 说明 | -|------------------------|--------------------------------------| +| ---------------------- | ------------------------------------ | | `bun run dev` | 启动 Nuxt 开发服务器 (HMR) | | `bun run build` | 生产构建(cloudflare_module preset) | | `bun run deploy` | 部署到 Cloudflare | diff --git a/docs/zh/guide/groups.md b/docs/zh/guide/groups.md index a320439..14a573d 100644 --- a/docs/zh/guide/groups.md +++ b/docs/zh/guide/groups.md @@ -21,7 +21,7 @@ ``` | 字段 | 类型 | 必需 | 说明 | -|------------------|----------|------|--------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ---------------- | -------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `id` | string | 是 | 小写 id(`a-z0-9`、`-`);被每条路由的 `groupId` 引用。可编辑:重命名分组会同步其路由、分组 webhook secret 与待处理邀请 | | `name` | string | 是 | 人类可读的分组名 | | `members` | object[] | 否 | `{ login, role }` 条目;角色为 `owner`、`admin` 或 `viewer` | @@ -38,7 +38,7 @@ 每个分组成员拥有三种角色之一。超级管理员(`ADMIN_USER_IDS`)始终绕过这些限制。 | 角色 | 查看路由/日志 | 编辑路由 | 管理成员与邀请 | 编辑分组设置 | -|----------|---------------|----------|----------------|------------------| +| -------- | ------------- | -------- | -------------- | ---------------- | | `owner` | ✓ | ✓ | ✓ | ✓(除 `owners`) | | `admin` | ✓ | ✓ | ✗ | ✗ | | `viewer` | ✓(只读) | ✗ | ✗ | ✗ | diff --git a/docs/zh/guide/i18n.md b/docs/zh/guide/i18n.md index 083aa97..e7172db 100644 --- a/docs/zh/guide/i18n.md +++ b/docs/zh/guide/i18n.md @@ -13,7 +13,7 @@ ```jsonc // KV 键:i18n:zh { - "events.push.title": "{repo}: 推送了 {count} 个提交到 {ref}" + "events.push.title": "{repo}: 推送了 {count} 个提交到 {ref}", } ``` diff --git a/docs/zh/guide/ingress.md b/docs/zh/guide/ingress.md index ffb1509..78b6c5a 100644 --- a/docs/zh/guide/ingress.md +++ b/docs/zh/guide/ingress.md @@ -5,7 +5,7 @@ WebHooker 通过同一个 `POST /webhook` 端点接收多个 forge 的 webhook,按请求头自动识别来源;只需把各 forge 的 webhook 指向 `{BASE_URL}/webhook` 即可。 | 提供方 | 事件请求头 | 签名请求头 | 签名格式 | 密钥 | -|--------|------------------|-----------------------|----------------------------|-------------------------| +| ------ | ---------------- | --------------------- | -------------------------- | ----------------------- | | GitHub | `X-GitHub-Event` | `X-Hub-Signature-256` | `sha256=` HMAC-SHA256 | `GITHUB_WEBHOOK_SECRET` | | Gitea | `X-Gitea-Event` | `X-Gitea-Signature` | 纯 hex HMAC-SHA256 | `GITEA_WEBHOOK_SECRET` | @@ -51,7 +51,7 @@ Gitea 载荷会被归一化为与 GitHub 事件相同的内部结构,因此路 ``` | 字段 | 类型 | 说明 | -|---------------|----------|----------------------------------------------------------------------------------------------------------| +| ------------- | -------- | -------------------------------------------------------------------------------------------------------- | | `title` | string | 消息标题(缺省时为 "Custom message") | | `description` | string | 可选消息正文 | | `color` | string | 可选嵌入颜色:颜色词(`red`、`green`、`yellow`、`blue`、`purple`、`orange`、`cyan`、`gray`)或 `#rrggbb` | diff --git a/docs/zh/guide/logs.md b/docs/zh/guide/logs.md index b7b7880..e19ed79 100644 --- a/docs/zh/guide/logs.md +++ b/docs/zh/guide/logs.md @@ -4,25 +4,25 @@ 每次分发尝试都会记录到 D1 `send_logs` 表,并可在控制台(**日志**标签页)查看。字段: -| 字段 | 含义 | -|--------------|-------------------------------------------------------------| -| `routeId` | 匹配的路由 | -| `groupId` | 路由所属分组 | -| `event` | 事件类型(如 `push`、`pull_request`、`custom`) | -| `repo` | 仓库全名(存在时) | -| `target` | 消息发送到的目标 id | -| `platform` | `discord` 或 `telegram` | -| `ok` | 发送是否成功 | -| `status` | 平台 API 的 HTTP 状态码(适用时) | -| `error` | 失败时的错误信息 | -| `errorCode` | 稳定错误码(如 `NO_TARGET`、`NO_TOKEN`、`RATE_LIMITED`) | -| `attempts` | 含重试在内的发送次数 | -| `durationMs` | 发送耗时 | -| `deliveryId` | Webhook 投递 id(提供时) | -| `messageId` | 平台消息 id(用于原地编辑) | -| `actor` | 发送者登录名 | -| `action` | 事件动作(存在时) | -| `detail` | 附加 JSON 详情(存在时) | +| 字段 | 含义 | +| ------------ | -------------------------------------------------------- | +| `routeId` | 匹配的路由 | +| `groupId` | 路由所属分组 | +| `event` | 事件类型(如 `push`、`pull_request`、`custom`) | +| `repo` | 仓库全名(存在时) | +| `target` | 消息发送到的目标 id | +| `platform` | `discord` 或 `telegram` | +| `ok` | 发送是否成功 | +| `status` | 平台 API 的 HTTP 状态码(适用时) | +| `error` | 失败时的错误信息 | +| `errorCode` | 稳定错误码(如 `NO_TARGET`、`NO_TOKEN`、`RATE_LIMITED`) | +| `attempts` | 含重试在内的发送次数 | +| `durationMs` | 发送耗时 | +| `deliveryId` | Webhook 投递 id(提供时) | +| `messageId` | 平台消息 id(用于原地编辑) | +| `actor` | 发送者登录名 | +| `action` | 事件动作(存在时) | +| `detail` | 附加 JSON 详情(存在时) | 控制台的**日志**标签页列出最近记录(可按分组过滤),并可查看单条完整详情。写入为尽力而为——插入失败不会中断分发。 diff --git a/docs/zh/guide/routes.md b/docs/zh/guide/routes.md index ae811b8..64bc4f0 100644 --- a/docs/zh/guide/routes.md +++ b/docs/zh/guide/routes.md @@ -31,12 +31,12 @@ `targets` 的每一项都是一个推送目标,因此一条路由可同时转发到多个频道(例如一个 Discord 频道**和**一个 Telegram 群组)。`target.platform` 选择平台:`discord`(默认)或 `telegram`。**Discord** 目标要求 `target.channelId`(可选 `target.threadId` 指定子区);**Telegram** 目标要求 `target.chatId`(群组/超级群组 id,如 `-1001234567890`),可选 `target.topicId`(话题的 `message_thread_id`,相当于 Discord 子区)。没有默认频道回退。 -| 字段 | 类型 | 必需 | 说明 | -|------------------|----------|------|-----------------------------------------------------------------------------| -| `groupId` | string | 是 | 路由所属[分组](./groups)的 id | -| `fallback` | boolean | 否 | 为 `true` 时仅在没有其他非 fallback 路由匹配时才触发;其自身过滤器被忽略 | -| `stop` | boolean | 否 | 为 `true` 且该路由匹配时,不再评估后续路由 | -| `discordRoleIds` | string[] | 否 | 路由触发时要提醒的 Discord 身份组 id;仅对 Discord 目标生效 | +| 字段 | 类型 | 必需 | 说明 | +| ---------------- | -------- | ---- | ------------------------------------------------------------------------ | +| `groupId` | string | 是 | 路由所属[分组](./groups)的 id | +| `fallback` | boolean | 否 | 为 `true` 时仅在没有其他非 fallback 路由匹配时才触发;其自身过滤器被忽略 | +| `stop` | boolean | 否 | 为 `true` 且该路由匹配时,不再评估后续路由 | +| `discordRoleIds` | string[] | 否 | 路由触发时要提醒的 Discord 身份组 id;仅对 Discord 目标生效 | ## Discord 身份组提醒 diff --git a/docs/zh/guide/storage.md b/docs/zh/guide/storage.md index 04cc32a..eddfee5 100644 --- a/docs/zh/guide/storage.md +++ b/docs/zh/guide/storage.md @@ -2,34 +2,34 @@ ## KV 存储布局 -| 键模式 | 值 | TTL | -|---------------------------------|--------------------------------------------------------------------------------|--------------------| -| `config:routes` | 路由 JSON 数组 | 永久 | -| `config:groups` | 分组 JSON 数组 | 永久 | -| `session:{id}` | 管理员会话 `{ userId, login }` | 7 天 | -| `token:{userId}` | `{ userId, accessToken, expiresAt, refreshToken? }` | 0.9 × Token 有效期 | -| `token-reverse:{sha256}` | 用于按 Token 反查的用户 id | 0.9 × Token 有效期 | -| `state:{hex}` | `{ redirectTo, expiresAt, discordUserId?, telegramUserId?, telegramChatId? }` | 600 秒 | -| `invite:{token}` | `{ groupId, role, expiresAt, createdBy, note? }` | 7 天 | -| `invite:group:{id}` | 每组的 Token 索引(保证邀请列表一致性) | 永久 | -| `delivery:{id}` | Webhook 投递 id(去重标记) | 300 秒 | -| `delivery:{groupId}:{id}` | 分组级 webhook 入口的租户级投递去重 | 300 秒 | -| `tenant:{groupId}` | 分组 webhook secret(64 位 hex,控制台生成) | 永久 | -| `msg:{routeId}:{key}:{target}` | 原地更新用消息 id 追踪(如 `workflow_run` / `check_run`) | 7 天 | -| `cmd:guild:{id}` | 已注册命令的服务器 id(去重) | 永久 | -| `cmd:registered:global` | 全局命令注册标记(去重) | 1 天 | -| `config:discord-app-id` | 缓存的 Discord 应用 id | 永久 | -| `i18n:{lang}` | 叠加在英文之上的翻译覆盖 | 永久 | +| 键模式 | 值 | TTL | +| ------------------------------ | ----------------------------------------------------------------------------- | ------------------ | +| `config:routes` | 路由 JSON 数组 | 永久 | +| `config:groups` | 分组 JSON 数组 | 永久 | +| `session:{id}` | 管理员会话 `{ userId, login }` | 7 天 | +| `token:{userId}` | `{ userId, accessToken, expiresAt, refreshToken? }` | 0.9 × Token 有效期 | +| `token-reverse:{sha256}` | 用于按 Token 反查的用户 id | 0.9 × Token 有效期 | +| `state:{hex}` | `{ redirectTo, expiresAt, discordUserId?, telegramUserId?, telegramChatId? }` | 600 秒 | +| `invite:{token}` | `{ groupId, role, expiresAt, createdBy, note? }` | 7 天 | +| `invite:group:{id}` | 每组的 Token 索引(保证邀请列表一致性) | 永久 | +| `delivery:{id}` | Webhook 投递 id(去重标记) | 300 秒 | +| `delivery:{groupId}:{id}` | 分组级 webhook 入口的租户级投递去重 | 300 秒 | +| `tenant:{groupId}` | 分组 webhook secret(64 位 hex,控制台生成) | 永久 | +| `msg:{routeId}:{key}:{target}` | 原地更新用消息 id 追踪(如 `workflow_run` / `check_run`) | 7 天 | +| `cmd:guild:{id}` | 已注册命令的服务器 id(去重) | 永久 | +| `cmd:registered:global` | 全局命令注册标记(去重) | 1 天 | +| `config:discord-app-id` | 缓存的 Discord 应用 id | 永久 | +| `i18n:{lang}` | 叠加在英文之上的翻译覆盖 | 永久 | ## D1 存储布局 D1 数据库(`DB` 绑定,数据库 `webhooker`)包含四张表: -| 表 | 用途 | -|-------------------|--------------------------------------------------------------------------------------------------| -| `send_logs` | 每次分发尝试一行(路由 id、事件、目标、ok/error、耗时、错误码、详情) | -| `audit_logs` | 每次管理员操作一行(登录/登出、分组/路由/成员/邀请变更) | -| `discord_links` | 映射 `discord_user_id` → `github_user_id`,供 `/gh` Discord 命令使用 | -| `telegram_links` | 映射 `telegram_user_id` → `github_user_id`,供 `/gh` Telegram 命令使用 | +| 表 | 用途 | +| ---------------- | ---------------------------------------------------------------------- | +| `send_logs` | 每次分发尝试一行(路由 id、事件、目标、ok/error、耗时、错误码、详情) | +| `audit_logs` | 每次管理员操作一行(登录/登出、分组/路由/成员/邀请变更) | +| `discord_links` | 映射 `discord_user_id` → `github_user_id`,供 `/gh` Discord 命令使用 | +| `telegram_links` | 映射 `telegram_user_id` → `github_user_id`,供 `/gh` Telegram 命令使用 | `audit_logs` 由定时任务在 `AUDIT_RETENTION_DAYS`(默认 90)后自动清理。行字段说明见[日志](./logs)。 diff --git a/docs/zh/guide/tasks.md b/docs/zh/guide/tasks.md index 5e41e96..bdd139e 100644 --- a/docs/zh/guide/tasks.md +++ b/docs/zh/guide/tasks.md @@ -3,7 +3,7 @@ WebHooker 通过定时触发器(`*/5 * * * *`,每 5 分钟)运行三个维护任务。它们只在部署后的 Worker 上运行(Cloudflare cron);本地 `wrangler dev` 可用 `wrangler dev --test-scheduled` 触发。 | 任务 | 用途 | -|-----------------|---------------------------------------------------------------------------------------------------------------------| +| --------------- | ------------------------------------------------------------------------------------------------------------------- | | `discord-sync` | 注册 Discord 斜杠/右键菜单命令:按服务器即时注册,并全局注册(24h 去重,约 1 小时传播) | | `telegram-sync` | 调用 `setWebhook` 指向 `{BASE_URL}/telegram/webhook`(设置了 `TELEGRAM_WEBHOOK_SECRET` 时作为 `secret_token` 传入) | | `audit-prune` | 删除早于 `AUDIT_RETENTION_DAYS`(默认 90)天的 `audit_logs` 记录 | diff --git a/server/lib/web/admin.ts b/server/lib/web/admin.ts index 4ba2316..67b29b0 100644 --- a/server/lib/web/admin.ts +++ b/server/lib/web/admin.ts @@ -284,9 +284,7 @@ export function validateGroups( if ( g.providers !== undefined && (!Array.isArray(g.providers) || - !g.providers.every( - (p) => typeof p === "string" && ["github", "gitea"].includes(p), - )) + !g.providers.every((p) => typeof p === "string" && ["github", "gitea"].includes(p))) ) { return { ok: false,