Date: 2026-03-17 Author: Sisyphus AI Agent Status: Draft for Review
Add WebSocket long-connection support for Feishu bot integration, enabling internal network deployment without requiring public domain or internet-facing endpoints. The system will support both existing webhook mode and new WebSocket mode, allowing users to choose their preferred connection method.
Feishu Cloud → Public Domain → NAT/Firewall → Internal Server
└→ POST /api/feishu/webhook/:appId
Limitations:
Feishu Cloud ←──────── WebSocket (wss://open.feishu.cn) ──────── Internal Server
↑
Feishu Cloud → Webhook (optional backup) → Internal Server
Advantages:
┌─────────────────────────────────────────────────────────────┐
│ Feishu Open Platform │
│ (WebSocket Event Subscription) │
└───────────────────────┬─────────────────────────────────────┘
│
┌─────────────┴─────────────┐
│ │
┌─────▼──────┐ ┌──────▼─────┐
│ Bot A │ │ Bot B │
│ ws://.../A │ │ ws://.../B │
└─────┬──────┘ └──────┬─────┘
│ │
┌─────▼──────────────────────────▼──────┐
│ AuraK Server │
│ ┌──────────────────────────────────┐ │
│ │ FeishuModule │ │
│ │ ┌────────────────────────────┐ │ │
│ │ │ FeishuWsManager │ │ │
│ │ │ - per-bot connections │ │ │
│ │ │ - auto-reconnect │ │ │
│ │ │ - message routing │ │ │
│ │ └────────────────────────────┘ │ │
│ │ ┌────────────────────────────┐ │ │
│ │ │ FeishuService │ │ │
│ │ │ - existing logic │ │ │
│ │ │ - new ws connect/disconnect│ │ │
│ │ └────────────────────────────┘ │ │
│ │ ┌────────────────────────────┐ │ │
│ │ │ FeishuController │ │ │
│ │ │ - webhook endpoints │ │ │
│ │ │ - ws management APIs │ │ │
│ │ └────────────────────────────┘ │ │
│ └──────────────────────────────────┘ │
└──────────────────────────────────────────┘
Purpose: Manage WebSocket connections for each bot
Responsibilities:
Location: server/src/feishu/feishu-ws.manager.ts
Key Methods:
class FeishuWsManager {
// Start WebSocket connection for a bot
async connect(bot: FeishuBot): Promise<void>
// Stop WebSocket connection for a bot
async disconnect(botId: string): Promise<void>
// Get connection status
getStatus(botId: string): ConnectionStatus
// Get all active connections
getAllConnections(): Map<string, ConnectionStatus>
}
enum ConnectionState {
DISCONNECTED = 'disconnected',
CONNECTING = 'connecting',
CONNECTED = 'connected',
ERROR = 'error'
}
interface ConnectionStatus {
botId: string
state: ConnectionState
connectedAt?: Date
lastHeartbeat?: Date
error?: string
}
New Methods:
class FeishuService {
// Start WebSocket connection for a bot
async startWsConnection(botId: string): Promise<void>
// Stop WebSocket connection for a bot
async stopWsConnection(botId: string): Promise<void>
// Get connection status
async getWsStatus(botId: string): Promise<ConnectionStatus>
// List all connection statuses
async getAllWsStatuses(): Promise<ConnectionStatus[]>
}
New Endpoints:
// POST /feishu/bots/:id/ws/connect - Start WebSocket connection
// POST /feishu/bots/:id/ws/disconnect - Stop WebSocket connection
// GET /feishu/bots/:id/ws/status - Get connection status
// GET /feishu/ws/status - Get all connection statuses
Modified Endpoints:
New Fields:
@Entity('feishu_bots')
export class FeishuBot {
// ... existing fields ...
@Column({ default: false })
useWebSocket: boolean
@Column({ nullable: true })
wsConnectionState: string
}
Package: @larksuiteoapi/node-sdk
Installation:
cd server && yarn add @larksuiteoapi/node-sdk
Configuration:
import { EventDispatcher, Conf } from '@larksuiteoapi/node-sdk'
const client = new EventDispatcher({
appId: bot.appId,
appSecret: bot.appSecret,
verificationToken: bot.verificationToken,
}, {
logger: console
})
Flow for WebSocket Mode:
Feishu Cloud ──WebSocket──> FeishuWsManager.on('message')
│
▼
Parse event type
│
┌───────────────┼───────────────┐
│ │ │
im.message. im.message. other
receive_v1 p2p_msg_received
│ │
▼ ▼
FeishuService.processChatMessage()
│
▼
Send response via
FeishuService.sendTextMessage()
Feishu Open Platform:
Users need to configure in Feishu developer console:
im.message.receive_v11. User triggers connect API
│
▼
2. FeishuController.connect(botId)
│
▼
3. FeishuService.startWsConnection(botId)
│
▼
4. FeishuWsManager.connect(bot)
│
▼
5. SDK establishes WebSocket to open.feishu.cn
│
▼
6. Connection established, events flow:
│
├─> on('message') ──> _processEvent() ──> _handleMessage()
│ │
│ ▼
│ FeishuService.processChatMessage()
│ │
│ ▼
│ FeishuService.sendTextMessage() (via SDK)
│
├─> on('error') ──> log error ──> trigger reconnect
│
└─> on('close') ──> trigger auto-reconnect
| Error Type | Handling |
|---|---|
| Network timeout | Retry with exponential backoff (max 5 attempts) |
| Invalid credentials | Mark bot as error state, notify user |
| Token expired | Refresh token, reconnect |
| Feishu server error | Wait 30s, retry |
Initial delay: 1 second
Max delay: 60 seconds
Backoff multiplier: 2x
Max attempts: 5
Reset on successful connection
POST /api/feishu/bots/:id/ws/connect
Response 200:
{
"success": true,
"botId": "bot_xxx",
"status": "connecting"
}
Response 400:
{
"success": false,
"error": "Bot not found or disabled"
}
POST /api/feishu/bots/:id/ws/disconnect
Response 200:
{
"success": true,
"botId": "bot_xxx",
"status": "disconnected"
}
GET /api/feishu/bots/:id/ws/status
Response 200:
{
"botId": "bot_xxx",
"state": "connected",
"connectedAt": "2026-03-17T10:00:00Z",
"lastHeartbeat": "2026-03-17T10:05:00Z"
}
GET /api/feishu/ws/status
Response 200:
{
"connections": [
{
"botId": "bot_xxx",
"state": "connected",
"connectedAt": "2026-03-17T10:00:00Z"
},
{
"botId": "bot_yyy",
"state": "disconnected"
}
]
}
yarn add @larksuiteoapi/node-sdkPOST /api/feishu/bots/:id/ws/connect to activateopen.feishu.cn via WebSocketserver/src/feishu/feishu-ws.manager.ts - WebSocket connection managerserver/src/feishu/dto/ws-status.dto.ts - WebSocket status DTOsserver/src/feishu/feishu.service.ts - Add WS methodsserver/src/feishu/feishu.controller.ts - Add WS endpointsserver/src/feishu/entities/feishu-bot.entity.ts - Add WS fieldsserver/src/feishu/feishu.module.ts - Register new manager@larksuiteoapi/node-sdk