import type { Attachment, ChannelSummary, Conversation, CreateChannelInput, Membership, Message, MessageEvent, Person, SendOpts, Unsubscribe, } from './types'; /** * The one seam of this SDK. Hosts implement this; the SDK renders it. * * Lifted from lynkeduppro-crm's MessengerData/ThreadData, which already survived * two implementations (live data-door + mock) — the minimum real evidence that a * seam is genuine rather than imagined. * * Optional methods degrade gracefully: the UI hides the reaction picker when * `react` is absent, and the attach button when `upload` is absent. That is how one * component set serves both a full CRM messenger and a stripped-down widget with no * `mode` prop. */ export interface MessagingAdapter { listConversations(): Promise; openThread(p: { participantIds: string[]; membership?: Membership; subject?: string }): Promise<{ threadId: string }>; history(threadId: string): Promise; send(threadId: string, content: string, opts?: SendOpts): Promise; /** Returns an unsubscribe fn. Implementations MUST be idempotent on repeat unsubscribe. */ subscribe(threadId: string, cb: (e: MessageEvent) => void): Unsubscribe; sendTyping(threadId: string): void; markRead(threadId: string, messageId: string): Promise; /** * The current user's actor id, or null if not yet known. * * MUST NOT be inferred from message history. The CRM's bug was exactly that: * scanning for a sent message meant every message read as not-yours until you * had spoken. Adapters derive this from auth/session. */ currentActorId(): string | null; /** Absent => the UI hides reactions entirely. */ react?(threadId: string, messageId: string, emoji: string): Promise; /** Absent => the UI hides attachments. Storage/auth/limits are the host's concern. */ upload?(file: File): Promise; /** Absent => treated as always connected (e.g. a pure-REST adapter). */ isConnected?(): boolean; /** A thread's members (id + display name), for @mention autocomplete + highlighting. * Absent => the composer offers no autocomplete (you can still type @text). */ listMembers?(threadId: string): Promise; /** The people you can start a conversation with (org directory). Drives the "New message" * people picker. Absent => the UI hides DM/group creation (you can still open channels). */ directory?(): Promise; // ── Channels (optional capability) ────────────────────────────── // A channel is just a third membership beyond dm/group: a discoverable, joinable room. // Implement all four to enable the channels UI; absent => the UI hides channels entirely. /** Discoverable channels in the caller's scope, each flagged `joined`. */ browseChannels?(): Promise; /** Create a channel; the creator joins as admin. Returns the new thread id. */ createChannel?(input: CreateChannelInput): Promise<{ threadId: string }>; /** Join a (public) channel by id. */ joinChannel?(threadId: string): Promise; /** Leave a channel by id. */ leaveChannel?(threadId: string): Promise; }