Commit graph

136 commits

Author SHA1 Message Date
04fa52db52
chore(deps): remove @nuxt/kit override and update lockfile 2026-08-15 17:10:14 +08:00
github-actions[bot]
a1ee756d1d chore: auto-fix lint & formatting [skip ci] 2026-08-15 09:04:41 +00:00
1e9ba3c5dd
feat(observability): delivery metrics, admin metrics/delivery endpoints, admin API route wiring 2026-08-15 17:03:45 +08:00
2470bd786d
feat(config): valibot schemas, schema version, migrations, filter AST 2026-08-15 17:03:42 +08:00
eaec039ad4
refactor(core): message tracker abstraction and formatter plugin registry 2026-08-15 17:03:39 +08:00
486f38365f
feat(queue): async delivery via Cloudflare Queues with retry backoff and DLQ 2026-08-15 17:03:35 +08:00
737dd7af98
feat(reliability): idempotency store, custom webhook replay protection, correlation ids
Add LICENSE (MIT), an IdempotencyStore abstraction with a KV implementation and provider-scoped delivery keys, optional replay protection for custom webhooks (X-WebHooker-Timestamp + X-WebHooker-Nonce), and per-request correlation ids in webhook responses and logs.
2026-08-15 17:03:32 +08:00
github-actions[bot]
92ba2203a5 chore: auto-fix lint & formatting [skip ci] 2026-08-15 04:05:25 +00:00
7ebd9aa63f
fix: prevent race conditions with KV locks in dispatch and group provisioning 2026-08-15 12:04:37 +08:00
github-actions[bot]
17eefd3c8e chore: auto-fix lint & formatting [skip ci] 2026-08-14 01:01:12 +00:00
c982356e0c
fix(formatters): use raster PNG forge icons Discord renders
- GitHub footer icon now uses fluidicon.png instead of favicon.ico —
  Discord silently drops .ico embed footer icons (png/jpg/webp/gif only)
- Gitea instances use {origin}/assets/img/favicon.png (verified on
  codeberg.org and gitea.com); links are still derived from the repo URL
- tests + docs updated to the new icon URLs
2026-08-14 08:59:51 +08:00
github-actions[bot]
c58b800987 chore: auto-fix lint & formatting [skip ci] 2026-08-14 00:51:23 +00:00
3f6f7f17b5
feat(groups): host-based forge sources with optional display name
- forgeSources entries are now { host, type, name? }: the repository URL's
  hostname is matched case-insensitively against host (github.com for GitHub,
  distinct hosts for multiple Gitea instances); the footer label is the
  optional name, falling back to the host
- GroupEditor renders one row per source: host input + type select + optional
  display name (grid layout); hostname validation mirrors the server
- fix: apiFetch sends Content-Type: application/json — h3's readBody only
  parses JSON bodies with that header, so every PUT/POST from the refactored
  console arrived as a raw string and failed with 'groups must be an array'
- hardening: readJsonBody (admin + actions) JSON-parses string bodies so curl
  and older clients without the content-type header still work
- regression test: groups PUT without content-type + forgeSources round-trip
- docs: groups.md/message-format.md (en/zh), AGENTS.md, config.example.yaml
2026-08-14 08:49:48 +08:00
github-actions[bot]
17d10db845 chore: auto-fix lint & formatting [skip ci] 2026-08-14 00:10:56 +00:00
3dce114cec
feat(groups): optional forge source label in message footers
- Group.forgeLabel (default off, editable per group in the console) shows the
  source forge on every message the group's routes dispatch
- Discord embed footer: forge name next to the repo + the site's favicon as
  icon_url (Gitea instance's own favicon from its origin)
- Telegram footer: hyperlinked site name (GitHub or Gitea hostname); custom
  webhooks render a plain 'Custom' label
- forgeInfo() derives branding from event.provider + repository.html_url;
  dispatch attaches it to the NeutralMessage like mentionRoleIds
- validateGroups accepts forgeLabel booleans; GroupEditor gains the toggle
- tests: forgeInfo unit, discord/telegram footer render, dispatch on/off
- docs: groups.md + message-format.md (en/zh), config.example.yaml, AGENTS.md
- fix: wrangler.jsonc compatibility_date was an incomplete '2026-'
2026-08-14 08:10:04 +08:00
a5324fb0ea
fix(formatters): localize PR buttons, cap oversized content, dedupe status logic
- PR merge/close button labels now follow the group language (actions.merge/close)
  instead of hardcoded Chinese
- clamp content to Discord embed limits (title 256, description 4096, field value
  1024, 25 fields) in formatters plus a render-layer safety net; Telegram gets a
  tag-safe 4096-char cap (capHtml closes dangling tags)
- raise commit subject truncation from 72 to 200 chars (MAX_COMMIT_SUBJECT)
- extract workflowStatus/workflowRunStatus/statusColorKey helpers shared by
  check_run/check_suite/workflow_run/workflow_job
- dedupe deployment ref/sha fields via addDeploymentRefFields
- commit_comment without a commit id uses title_plain (no dangling ???????)
- tag pushes now report 'Tag created'; zh push title includes the {ref}
- sender profile link derives from the repo's forge origin instead of github.com
- group webhook log emoji injected via emojiPrefix, removed from locale files
- dispatchEvent accepts preloaded groups (single KV read per webhook)
- webhook 401 logs distinguish 'secret not configured' from 'invalid signature'
2026-08-14 07:41:19 +08:00
e59b10f739
refactor(admin): unify webui fetch/copy/format helpers; fix audit tab load and delete-group count
- apiFetch + shared needLogin (any 401 shows the login card) replaces six
  duplicated fetch/401/error-handling blocks in the admin composables
- useCopy composable: clipboard + execCommand fallback with timed reset,
  used by MembersPanel and WebhookPanel
- utils/format.ts (fmtTime/splitList/parseMatch) removes inline duplicates
  across SendLogs, AuditLog, RouteEditor and GroupEditor
- fix: load the audit log when the audit tab becomes active (client-side
  navigation never remounted the page, leaving the list empty on first visit)
- fix: fetch the real route count for a group before confirming deletion
  instead of reusing the currently open group's route list
2026-08-14 07:18:55 +08:00
c438fe96dc
Merge branch 'main' of https://github.com/ReCloudStudio/WebHooker 2026-08-14 06:52:17 +08:00
44f534e71d
fix(docs): standalone tsconfig for vitepress config loading 2026-08-14 06:52:05 +08:00
github-actions[bot]
811f8646e0 chore: auto-fix lint & formatting [skip ci] 2026-08-13 22:46:35 +00:00
6f1a334150
merge: resolve conflicts with origin/main (auto-fix formatting) 2026-08-14 06:45:15 +08:00
a9e50fba50
docs: restructure into core-concept pages and split admin API 2026-08-14 06:41:08 +08:00
db49e1f01c
docs: fix factual errors, fill coverage gaps and align zh mirror 2026-08-14 06:17:13 +08:00
github-actions[bot]
df51b71121 chore: auto-fix lint & formatting [skip ci] 2026-08-13 12:37:09 +00:00
41ad1a036b
chore: migrate package manager from npm to bun 2026-08-13 20:34:52 +08:00
cf65111e4e
fix(formatters): dedupe push count line, link workflow run name to actions 2026-08-13 19:37:20 +08:00
dfb65ef70d
fix: link only the repo head in message titles, keep the subject plain 2026-08-13 19:18:55 +08:00
84d8a5384d
fix(push): render git push branch deletions as a delete message 2026-08-13 19:01:01 +08:00
cc3ccadc24
feat(filters): unified glob (*/?) and //-regex matching for all filter types 2026-08-13 18:44:13 +08:00
ebae2dc94f
Merge branch 'main' of https://github.com/ReCloudStudio/WebHooker 2026-08-13 18:16:55 +08:00
2106aad3b8
fix: read raw request + body via h3 context for discord/telegram webhooks 2026-08-13 18:13:55 +08:00
dependabot[bot]
07965f1630 chore(deps): bump undici and wrangler
Bumps [undici](https://github.com/nodejs/undici) to 7.29.0 and updates ancestor dependency [wrangler](https://github.com/cloudflare/workers-sdk/tree/HEAD/packages/wrangler). These dependencies need to be updated together.


Updates `undici` from 7.28.0 to 7.29.0
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v7.28.0...v7.29.0)

Updates `wrangler` from 4.118.0 to 4.122.0
- [Release notes](https://github.com/cloudflare/workers-sdk/releases)
- [Commits](https://github.com/cloudflare/workers-sdk/commits/wrangler@4.122.0/packages/wrangler)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 7.29.0
  dependency-type: indirect
- dependency-name: wrangler
  dependency-version: 4.122.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-13 18:02:59 +08:00
dependabot[bot]
ce34068b36 chore(deps): bump js-yaml from 4.3.0 to 4.3.1
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 4.3.0 to 4.3.1.
- [Changelog](https://github.com/nodeca/js-yaml/blob/4.3.1/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.3.0...4.3.1)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.3.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-13 18:02:10 +08:00
b139712a91
feat: migrate to Nuxt 4 (Nitro) and Tailwind CSS v3 2026-08-13 17:43:33 +08:00
f4959eebf8
feat(groups): allow renaming a group id
Add PUT /admin/api/groups/:id/rename (owner role) which re-points the group's routes, migrates the per-group webhook secret (tenant:{id}) and pending invites, and records an audit entry. The group editor's id field is now editable and the console renames first, then persists remaining edits under the new id.
2026-08-13 09:58:02 +08:00
39bb639883
feat(install): post-install setup flow with group bind choice
The GitHub App Setup URL now lands on /auth/github/install, which renders a choice page: bind the installation to a new inst-{id} group or to an existing group the signed-in user owns (owner role re-checked on POST /auth/github/install/bind). Adds an App-JWT helper (getInstallationAccount) to name the auto-created group, audit entries, a console toast, and keeps the installation.created webhook fallback.
2026-08-13 09:39:02 +08:00
b600f02027
feat: per-group webhook ingress, custom webhooks, GitHub App tenant isolation
Add POST /webhook/{groupId} with per-group secrets (KV tenant:{groupId}), a custom provider (X-WebHooker-Signature HMAC, arbitrary JSON -> custom events through the route pipeline), and GitHub App installation isolation (Group.installationId) with automatic provisioning on installation.created (inst-{id} groups or binding matching owners groups). Includes WebhookPanel admin UI, custom route template, docs and 157 passing tests.
2026-08-13 09:24:50 +08:00
0b078d938b
feat(groups): per-group webhook log channel (logTarget)
Add an optional Discord channel/thread or Telegram chat/topic (Group.logTarget) that receives a summary message per webhook the group's routes dispatched: event/action, repo, delivery id and per route×target OK/FAIL lines with green/red embed color. Validated by the admin API and editable in the group editor; docs and example config updated.
2026-08-13 08:36:46 +08:00
b35c2c2f90
feat(check_run): edit messages in place as the run progresses, like workflow_run
formatCheckRun now sets a stable updateKey (check_run:{repo}:{id}) so queued → in_progress → completed phases update the original message via KV msg:* tracking instead of posting new ones. Adds tests and syncs README/docs.
2026-08-13 06:47:30 +08:00
bf76b9342f
style(formatters): render branch/commit/tag refs as inline code with hyperlinks
Unify all branch, commit hash and tag references across formatters to the push commit style (inline code + link). Adds commitLink/branchLink/tagLink helpers in formatters/helpers.ts, links branches to /tree/, tags to /releases/tag/, and PR head branches to the fork repo. Drops the backticks from the en/zh locale templates around {ref}/{sha} since the formatters now inject pre-linked values.
2026-08-13 06:37:45 +08:00
github-actions[bot]
3029b3468f chore: auto-fix lint & formatting [skip ci] 2026-08-11 16:52:11 +00:00
13ba1e019e
merge: resolve docs conflict with origin/main (auto-fix)
Merged the remote lint/formatting fix; kept the group-level lang row in the zh group schema table.
2026-08-12 00:50:28 +08:00
7e45b0a09c
feat(groups): configure message language per group instead of per route
Route.lang is removed; Group.lang now drives the message language for
every route in the group (default en, custom via KV i18n:<lang>).
dispatch.ts loads translations per group and falls back to en for
groups without a lang. Admin UI: GroupEditor gains the language field,
RouteEditor/RouteCard drop theirs; docs and config example updated.
2026-08-12 00:43:47 +08:00
github-actions[bot]
89b43b8b28 chore: auto-fix lint & formatting [skip ci] 2026-08-11 16:06:06 +00:00
c73b642504
feat(admin): deep-linkable console URLs, stop collapsing unknown paths to /admin
The root catch-all page ([...slug].vue) redirected every unknown URL to
/admin, and the worker fell back to the SPA for any path — so no matter
what page was opened, the URL ended up at baseurl/admin.

- Extract the console into ConsolePage.vue; the active tab now mirrors
  the URL path: /admin (groups), /admin/groups, /admin/logs, /admin/audit
  (tab switches use router.replace; unknown slugs render 404)
- admin.vue and admin/[slug].vue become thin wrappers
- Delete the root [...slug].vue catch-all redirect
- server.ts: notFound serves ASSETS (SPA + _nuxt chunks) only for
  /admin-prefixed paths; every other unknown URL returns a JSON 404
2026-08-12 00:05:20 +08:00
a0e15975df
fix(invites): list invites via per-group KV index instead of kv.list
Cloudflare KV's list operation is eventually consistent and can lag
behind a fresh write, so pending invites were invisible right after
creation (GET /admin/api/groups/:id/invites returned {invites: []}).
Keep a per-group token index (invite:group:{id}) updated on create,
revoke, accept and expiry; the members panel also inserts the freshly
created invite into the list immediately and copies the absolute link.
2026-08-11 23:53:58 +08:00
ce9f6147f1
docs: document roles, invites, audit log and self-signup
- configuration.md (en/zh): ALLOW_SELF_SIGNUP, AUDIT_RETENTION_DAYS,
  member schema, role table, invite/self-signup sections, invite KV key,
  audit_logs D1 table, new admin endpoints
- deployment.md (en/zh): migration list through 0005
- README (en/zh) and AGENTS.md: access model, invites, audit log
- config.example.yaml: members example; .env.example: new variables
- .gitignore: ignore local saas-roadmap.md
2026-08-11 23:38:50 +08:00
11b74aa82a
feat(admin-ui): members panel, invite links, audit tab and role-aware console
- New MembersPanel: role switching, add/remove members, invite-link
  generation with copy/revoke, pending invite list
- New Audit tab (AuditLog.vue) with group filter
- Role-aware UI: viewer hides route/group edit actions (RouteCard readonly),
  owner-only controls, role badge + member count on group cards
- GroupEditor: members managed via panel, owners field super-admin only
- en/zh i18n and CSS for the new panels
2026-08-11 23:38:33 +08:00
252f6f181a
test: cover member roles, invite lifecycle and audit log 2026-08-11 23:37:34 +08:00
9b8533cabc
feat(admin): role-based group members (owner/admin/viewer), invites and audit log
- Group model: members[] with roles owner/admin/viewer; legacy adminIds
  resolve to owners (backward compatible); last-owner and self-demotion
  guards
- Unified permission middleware (src/web/auth.ts): requireAnyAccess,
  requireGroup(Role), bearerAuthMiddleware replace per-route loadScope
- Single-use 7-day invite links (invite:{token}); accept via /admin/invite
  or the OAuth callback; self-signup personal group via ALLOW_SELF_SIGNUP
- D1 audit_logs (migration 0005): login/logout, group/route/member/invite
  changes; GET /admin/api/audit; scheduled prune after AUDIT_RETENTION_DAYS
- Env: ALLOW_SELF_SIGNUP, AUDIT_RETENTION_DAYS
2026-08-11 23:37:19 +08:00