mirror of
https://github.com/d0zingcat/alert-message-center.git
synced 2026-05-13 23:16:48 +00:00
@@ -10,6 +10,7 @@
|
||||
### 修复
|
||||
- **WebSocket 初始化**: 修复了 `@larksuiteoapi/node-sdk` v1.56.0+ 中 WebSocket 初始化不正确的 `TypeError`。现在正确使用了 `WSClient` 类并修复了参数类型错误。
|
||||
- **事件处理**: 修正了 `im.chat.member.bot.added_v1` 事件的 Payload 解析逻辑。
|
||||
- **Hono 兼容性**: 修正了 `feishu-event.ts` 中 `lark.adaptDefault` 的错误用法。改为使用手动 Challenge 处理和 `eventDispatcher.invoke`,解决了与 Hono 请求/响应对象的兼容性问题引发的编译错误。
|
||||
- **群聊解绑**: 增加对 `im.chat.member.bot.deleted_v1` 事件的支持。当机器人被移除群聊时,自动清理 `known_group_chats` 和 `topic_group_chats` 关联,确保订阅关系自动解绑。
|
||||
|
||||
### 新增
|
||||
|
||||
@@ -5,32 +5,39 @@ import { eventDispatcher } from '../event-handler';
|
||||
const feishuEvent = new Hono();
|
||||
|
||||
// Helper to adapt Hono request to Lark SDK request
|
||||
const adaptRequest = async (c: any) => {
|
||||
const headers = c.req.raw.headers;
|
||||
// Convert Headers object to Record<string, string>
|
||||
const headerRecord: Record<string, string> = {};
|
||||
headers.forEach((value: string, key: string) => {
|
||||
headerRecord[key] = value;
|
||||
});
|
||||
|
||||
return {
|
||||
headers: headerRecord,
|
||||
body: await c.req.json(),
|
||||
};
|
||||
};
|
||||
|
||||
feishuEvent.post('/', async (c) => {
|
||||
try {
|
||||
const req = await adaptRequest(c);
|
||||
const headers = c.req.raw.headers;
|
||||
const headerRecord: Record<string, string> = {};
|
||||
headers.forEach((value, key) => {
|
||||
headerRecord[key] = value;
|
||||
});
|
||||
|
||||
// Use the official SDK to handle the request
|
||||
// It handles URL verification, encryption, and dispatching
|
||||
const res = await lark.adaptDefault('/api/feishu/event', req, eventDispatcher, {
|
||||
autoChallenge: true,
|
||||
encryptKey: process.env.FEISHU_ENCRYPT_KEY
|
||||
}) as any;
|
||||
const body = await c.req.json();
|
||||
const req = {
|
||||
headers: headerRecord,
|
||||
body,
|
||||
};
|
||||
|
||||
return c.json(res?.body || {});
|
||||
// Use the official SDK functions directly for Hono compatibility
|
||||
// 1. Handle URL verification (Challenge)
|
||||
const { isChallenge, challenge } = lark.generateChallenge(body, {
|
||||
encryptKey: process.env.FEISHU_ENCRYPT_KEY || ''
|
||||
});
|
||||
|
||||
if (isChallenge) {
|
||||
return c.json(challenge);
|
||||
}
|
||||
|
||||
// 2. Dispatch event
|
||||
// The dispatcher expects an object containing headers and body
|
||||
const result = await eventDispatcher.invoke({
|
||||
...req.body,
|
||||
headers: req.headers
|
||||
});
|
||||
|
||||
return c.json(result || {});
|
||||
} catch (e) {
|
||||
console.error('[Feishu Event] Error:', e);
|
||||
return c.json({ error: 'Internal Server Error' }, 500);
|
||||
|
||||
@@ -69,6 +69,23 @@ The database schema is defined in `apps/server/src/db/schema.ts`.
|
||||
- `name`: Group name.
|
||||
- `lastActiveAt`: Timestamp of last event from this group.
|
||||
- **Purpose**: Caches groups the bot has been added to, facilitating easy selection in the UI.
|
||||
7. **Alert Task** (`alert_tasks`)
|
||||
- `id`: UUID (Primary Key).
|
||||
- `topicSlug`: The slug of the target topic (or `NULL` for DM).
|
||||
- `senderId`: Foreign Key -> `users.id` (who triggered the webhook).
|
||||
- `status`: `pending`, `processing`, `completed`, or `failed`.
|
||||
- `recipientCount`: Total recipients (subscribers + groups).
|
||||
- `successCount`: Number of successful deliveries.
|
||||
- `payload`: Snapshot of the incoming webhook body (JSONB).
|
||||
- `error`: Last error message if failed.
|
||||
- **Purpose**: Tracks the lifecycle of a single alert ingestion events.
|
||||
|
||||
8. **Alert Log** (`alert_logs`)
|
||||
- `id`: UUID (Primary Key).
|
||||
- `taskId`: Foreign Key -> `alert_tasks.id`.
|
||||
- `userId`: Target user open_id (snapshot).
|
||||
- `status`: `sent` or `failed`.
|
||||
- **Purpose**: Granular tracking for each individual delivery within a task.
|
||||
|
||||
## 4. Key Workflows
|
||||
|
||||
@@ -157,6 +174,7 @@ The database schema is defined in `apps/server/src/db/schema.ts`.
|
||||
|
||||
### Feishu Event
|
||||
- `POST /api/feishu/event`: Endpoint for receiving Feishu events (Webhook mode).
|
||||
- **Note**: This endpoint uses **manual challenge handling** (`lark.generateChallenge`) and `eventDispatcher.invoke` instead of the SDK's `adaptDefault` to maintain compatibility with Hono's non-standard Node.js response object.
|
||||
|
||||
### Webhook
|
||||
- `POST /api/webhook/:token/topic/:slug`: Trigger an alert for a topic.
|
||||
|
||||
Reference in New Issue
Block a user