feat(ws-client): add TypingStart/TypingStop protocol types and client handlers
ws-protocol.ts: TypingStartPayload/TypingStopPayload interfaces, WsEventPayload union types. room-ws-client.ts: onTypingStart/onTypingStop callbacks, sendTyping() method, event dispatch for typing.start/typing_start. editor/types.ts: special_here/special_channel MentionType + description field on MentionItem.
This commit is contained in:
parent
5776af18ca
commit
59640c6f44
@ -2,13 +2,14 @@
|
||||
* Core types for the IM editor (mentions, files, emojis).
|
||||
*/
|
||||
|
||||
export type MentionType = 'user' | 'channel' | 'ai' | 'command';
|
||||
export type MentionType = 'user' | 'channel' | 'ai' | 'command' | 'special_here' | 'special_channel';
|
||||
|
||||
export interface MentionItem {
|
||||
id: string;
|
||||
label: string;
|
||||
type: MentionType;
|
||||
avatar?: string;
|
||||
description?: string; // shown under label in suggestion dropdown
|
||||
}
|
||||
|
||||
export interface FileData {
|
||||
|
||||
@ -78,6 +78,8 @@ export interface RoomWsCallbacks {
|
||||
onMessagePinned?: (payload: import('./ws-protocol').MessagePinnedPayload) => void;
|
||||
onMessageUnpinned?: (payload: import('./ws-protocol').MessageUnpinnedPayload) => void;
|
||||
onUserPresence?: (payload: UserPresencePayload) => void;
|
||||
onTypingStart?: (payload: import('./ws-protocol').TypingStartPayload) => void;
|
||||
onTypingStop?: (payload: import('./ws-protocol').TypingStopPayload) => void;
|
||||
onStatusChange?: (status: RoomWsStatus) => void;
|
||||
onError?: (error: Error) => void;
|
||||
/** Called each time the client sends a heartbeat ping */
|
||||
@ -961,6 +963,14 @@ export class RoomWsClient {
|
||||
return url;
|
||||
}
|
||||
|
||||
/** Send a typing_start / typing_stop event directly via WebSocket push (no response needed). */
|
||||
sendTyping(roomId: string, action: 'start' | 'stop'): void {
|
||||
if (this.ws && this.status === 'open') {
|
||||
const event = { type: 'event', event: `typing_${action}`, room_id: roomId };
|
||||
this.ws.send(JSON.stringify(event));
|
||||
}
|
||||
}
|
||||
|
||||
private handleMessage(rawText: string): void {
|
||||
// Handle raw JSON pong before full parsing — resets heartbeat
|
||||
if (rawText.trim() === '{"type":"pong"}') {
|
||||
@ -1033,6 +1043,22 @@ export class RoomWsClient {
|
||||
status: ((event.data as { status?: string })?.status ?? 'offline') as 'online' | 'away' | 'dnd' | 'offline',
|
||||
});
|
||||
break;
|
||||
case 'typing.start':
|
||||
case 'typing_start':
|
||||
this.callbacks.onTypingStart?.({
|
||||
room_id: event.room_id ?? '',
|
||||
user_id: (event.data as { user_id?: string })?.user_id ?? '',
|
||||
username: (event.data as { username?: string })?.username ?? '',
|
||||
avatar_url: (event.data as { avatar_url?: string })?.avatar_url,
|
||||
});
|
||||
break;
|
||||
case 'typing.stop':
|
||||
case 'typing_stop':
|
||||
this.callbacks.onTypingStop?.({
|
||||
room_id: event.room_id ?? '',
|
||||
user_id: (event.data as { user_id?: string })?.user_id ?? '',
|
||||
});
|
||||
break;
|
||||
default:
|
||||
// Unknown event type - ignore silently
|
||||
break;
|
||||
|
||||
@ -133,7 +133,20 @@ export type WsResponseData =
|
||||
| NotificationListData
|
||||
| MentionListData
|
||||
| SubscribeData
|
||||
| UserInfo[];
|
||||
| UserInfo[]
|
||||
| null;
|
||||
|
||||
export interface TypingStartPayload {
|
||||
room_id: string;
|
||||
user_id: string;
|
||||
username: string;
|
||||
avatar_url?: string;
|
||||
}
|
||||
|
||||
export interface TypingStopPayload {
|
||||
room_id: string;
|
||||
user_id: string;
|
||||
}
|
||||
|
||||
export interface WsEvent {
|
||||
type: 'event';
|
||||
@ -155,6 +168,8 @@ export type WsEventPayload =
|
||||
| { type: 'message_pinned'; data: MessagePinnedPayload }
|
||||
| { type: 'message_unpinned'; data: MessageUnpinnedPayload }
|
||||
| { type: 'user_presence'; data: UserPresencePayload }
|
||||
| { type: 'typing_start'; data: TypingStartPayload }
|
||||
| { type: 'typing_stop'; data: TypingStopPayload }
|
||||
| { type: string; data: unknown }; // catch-all for unknown events
|
||||
|
||||
export interface RoomMessagePayload {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user