export interface ChatMessage { id: string; userId: string; text: string; createdAt: string; clientId: string; /** True while the message is only local (not yet echoed by server). */ optimistic?: boolean; } /** Raw shape returned by the REST API (snake_case from Postgres). */ export interface RawApiMessage { id: string; user_id: string; text: string; created_at: string; client_id?: string; } export type ServerMessage = | { type: "message.new"; id: string; userId: string; text: string; createdAt: string; clientId: string } | { type: "typing"; userId: string; isTyping: boolean } | { type: "presence.update"; userId: string; status: "online" | "offline" } | { type: "error"; code: string; message: string }; export interface UnreadCount { channel_id: string; unread_count: number; } export function normalizeMessage(raw: RawApiMessage): ChatMessage { return { id: raw.id, userId: raw.user_id, text: raw.text, createdAt: raw.created_at, clientId: raw.client_id ?? "", }; }