export interface WsRequest { type: 'request'; request_id: string; action: WsAction; params?: WsRequestParams; } export type WsAction = | 'room.list' | 'room.get' | 'room.create' | 'room.update' | 'room.delete' | 'category.list' | 'category.create' | 'category.update' | 'category.delete' | 'message.list' | 'message.create' | 'message.update' | 'message.revoke' | 'message.get' | 'member.list' | 'member.add' | 'member.remove' | 'member.leave' | 'member.set_read_seq' | 'member.update_role' | 'pin.list' | 'pin.add' | 'pin.remove' | 'thread.list' | 'thread.create' | 'thread.messages' | 'reaction.add' | 'reaction.remove' | 'reaction.get' | 'message.search' | 'message.edit_history' | 'ai.list' | 'ai.upsert' | 'ai.delete' | 'notification.list' | 'notification.mark_read' | 'notification.mark_all_read' | 'notification.archive' | 'mention.list' | 'mention.read_all' | 'room.subscribe' | 'room.unsubscribe' | 'project.subscribe' | 'project.unsubscribe' | 'reaction.list_batch'; export interface WsRequestParams { project_name?: string; room_id?: string; message_id?: string; user_id?: string; category_id?: string; thread_id?: string; model_id?: string; notification_id?: string; emoji?: string; only_public?: boolean; only_unread?: boolean; limit?: number; offset?: number; before_seq?: number; after_seq?: number; room_name?: string; room_public?: boolean; room_category?: string; content?: string; content_type?: string; in_reply_to?: string; parent_seq?: number; role?: string; last_read_seq?: number; name?: string; position?: number; model?: string; model_version?: string; history_limit?: number; system_prompt?: string; temperature?: number; max_tokens?: number; use_exact?: boolean; think?: boolean; stream?: boolean; min_score?: number; query?: string; message_ids?: string[]; } export interface WsResponse { type: 'response'; request_id: string; action: string; data?: WsResponseData; error?: WsErrorInfo | null; } export interface WsErrorInfo { code: number; error: string; message: string; } /** 响应数据类型 */ export type WsResponseData = | boolean | number | RoomResponse | RoomResponse[] | RoomCategoryResponse | RoomCategoryResponse[] | RoomMessageResponse | RoomMessageListResponse | RoomMemberResponse | RoomMemberResponse[] | PinResponseData | PinResponseData[] | RoomThreadResponse | RoomThreadResponse[] | ReactionListData | ReactionListData[] | SearchResultData | MessageEditHistoryResponse | AiConfigData | AiConfigData[] | NotificationListData | MentionListData | SubscribeData | UserInfo[]; export interface WsEvent { type: 'event'; event: string; room_id?: string | null; project_id?: string | null; data?: unknown; error?: string | null; } /** Maps backend event string to typed event. Only room-relevant events are typed. */ export type WsEventPayload = | { type: 'room_message'; data: RoomMessagePayload } | { type: 'project_event'; data: ProjectEventPayload } | { type: 'ai_stream_chunk'; data: AiStreamChunkPayload } | { type: 'room_reaction_updated'; data: RoomReactionUpdatedPayload } | { type: 'message_edited'; data: MessageEditedPayload } | { type: 'message_revoked'; data: MessageRevokedPayload } | { type: 'message_pinned'; data: MessagePinnedPayload } | { type: 'message_unpinned'; data: MessageUnpinnedPayload } | { type: string; data: unknown }; // catch-all for unknown events export interface RoomMessagePayload { id: string; room_id: string; sender_type: string; sender_id?: string; thread_id?: string; content: string; content_type: string; send_at: string; seq: number; display_name?: string; /** Present when this event carries reaction updates for the message */ reactions?: ReactionItem[]; } export interface ProjectEventPayload { event_type: string; project_id: string; room_id?: string; category_id?: string; message_id?: string; seq?: number; timestamp: string; } export interface AiStreamChunkPayload { message_id: string; room_id: string; content: string; done: boolean; error?: string; } export interface RoomResponse { id: string; project: string; room_name: string; public: boolean; category?: string; created_by: string; created_at: string; last_msg_at: string; unread_count: number; } export interface RoomCategoryResponse { id: string; project: string; name: string; position: number; created_by: string; created_at: string; } export interface RoomMessageResponse { id: string; seq: number; room: string; sender_type: string; sender_id?: string; display_name?: string; thread?: string; in_reply_to?: string; content: string; content_type: string; edited_at?: string; send_at: string; revoked?: string; revoked_by?: string; } export interface RoomMessageListResponse { messages: RoomMessageResponse[]; total: number; } export interface RoomMemberResponse { room: string; user: string; user_info?: UserInfo; role: string; first_msg_in?: string; joined_at?: string; last_read_seq?: number; do_not_disturb: boolean; dnd_start_hour?: number; dnd_end_hour?: number; } export interface UserInfo { uid: string; username: string; avatar_url?: string; } export interface PinResponseData { room: string; message: string; pinned_by: string; pinned_at: string; message_data?: RoomMessageResponse; } export interface RoomThreadResponse { id: string; room: string; parent: number; created_by: string; participants: unknown; last_message_at: string; last_message_preview?: string; created_at: string; updated_at: string; } export interface ReactionItem { emoji: string; count: number; reacted_by_me: boolean; users: string[]; } export interface ReactionListData { message_id: string; reactions: ReactionItem[]; } export interface RoomReactionUpdatedPayload { message_id: string; reactions: ReactionItem[]; } export interface MessageEditedPayload { message_id: string; room_id: string; edited_at: string; } export interface MessageRevokedPayload { message_id: string; room_id: string; revoked_at: string; revoked_by: string; } export interface MessagePinnedPayload { message_id: string; room_id: string; pinned_by: string; pinned_at: string; } export interface MessageUnpinnedPayload { message_id: string; room_id: string; } export interface SearchResultData { messages: RoomMessageResponse[]; total: number; } export interface EditHistoryEntry { old_content: string; new_content: string; edited_at: string; } export interface MessageEditHistoryResponse { message_id: string; history: EditHistoryEntry[]; total_edits: number; } export interface AiConfigData { room: string; model: string; version?: string; call_count: number; last_call_at?: string; history_limit?: number; system_prompt?: string; temperature?: number; max_tokens?: number; use_exact: boolean; think: boolean; stream: boolean; min_score?: number; created_at: string; updated_at: string; } export interface NotificationData { id: string; room?: string; project?: string; user_id?: string; user_info?: UserInfo; notification_type: string; title: string; content?: string; related_message_id?: string; related_user_id?: string; related_room_id?: string; is_read: boolean; is_archived: boolean; created_at: string; read_at?: string; expires_at?: string; } export interface NotificationListData { notifications: NotificationData[]; total: number; unread_count: number; } export interface MentionListData { mentions: MentionData[]; } export interface MentionData { message_id: string; mentioned_by: string; mentioned_by_name: string; content_preview: string; room_id: string; room_name: string; created_at: string; } export interface SubscribeData { room_id?: string; project_id?: string; } export type WsInMessage = WsResponse | WsEvent | WsErrorMessage; export interface WsErrorMessage { type: 'error'; error: string; message?: string; }