feat(feishu): add Feishu inbound webhook, /gh commands and card actions

- add feishu_links D1 table and link store helpers
- implement X-Lark-Signature verification, url_verification, /gh login|logout|comment|merge|close and card.action.trigger Merge/Close
- render interactive cards with clickable title link, inline links and callback buttons (no whole-card card_link)
- bind Feishu account in OAuth callback
- document event subscription and required scopes
This commit is contained in:
RhenCloud 2026-08-27 00:04:49 +08:00
parent 3437ac5513
commit 4b99f6d33d
No known key found for this signature in database
GPG key ID: A574A617378C4E0B
38 changed files with 2449 additions and 1412 deletions

View file

@ -234,10 +234,10 @@ function validateTarget(
target: Record<string, unknown>,
): { ok: true; target: Route["targets"][number] } | { ok: false; error: string } {
const platform = target.platform === undefined ? "discord" : target.platform;
if (platform !== "discord" && platform !== "telegram") {
return { ok: false, error: `${label}.platform must be "discord" or "telegram"` };
if (platform !== "discord" && platform !== "telegram" && platform !== "feishu") {
return { ok: false, error: `${label}.platform must be "discord", "telegram" or "feishu"` };
}
if (platform === "telegram") {
if (platform === "telegram" || platform === "feishu") {
if (typeof target.chatId !== "string" || target.chatId.trim().length === 0)
return { ok: false, error: `${label}.chatId is required` };
if (target.topicId !== undefined && typeof target.topicId !== "string") {
@ -254,9 +254,9 @@ function validateTarget(
ok: true,
target: {
platform,
channelId: platform === "telegram" ? undefined : (target.channelId as string),
threadId: platform === "telegram" ? undefined : ((target.threadId as string) ?? undefined),
chatId: platform === "telegram" ? (target.chatId as string) : undefined,
channelId: platform === "discord" ? (target.channelId as string) : undefined,
threadId: platform === "discord" ? ((target.threadId as string) ?? undefined) : undefined,
chatId: platform === "telegram" || platform === "feishu" ? (target.chatId as string) : undefined,
topicId: platform === "telegram" ? ((target.topicId as string) ?? undefined) : undefined,
},
};