import type { ChatMessage } from "../game/chat.js"; export interface ChatSendArgs { channelId: string; body: string; } export interface ChatSendOutcome { ok: boolean; reason?: string; } export interface ChatActions { sendMessage(args: ChatSendArgs): Promise; } /** * Backend seam for remote text chat, mirroring PresenceTransport: the use* * members are called as React hooks by consumers, so a mounted transport must * never change identity — remount the subtree to switch backends. useMessages * returns undefined while the subscription is loading and the channel's recent * history once live. */ export interface ChatTransport { useMessages(channelId: string | "skip"): readonly ChatMessage[] | undefined; useActions(): ChatActions; } /** * Callback seam for backends that cannot host React hooks (e.g. the ws * client): subscribe delivers the channel's recent history on every change; * send resolves with the host's verdict. @jgengine/react's chatTransportFromSync * lifts a ChatSync into a ChatTransport. */ export interface ChatSync { subscribe(channelId: string, onChange: (messages: readonly ChatMessage[]) => void): () => void; send(channelId: string, body: string): Promise; } export declare function createLocalChatTransport(options?: { userId?: string; historyLimit?: number; now?: () => number; }): { transport: ChatTransport; sync: ChatSync; actions: ChatActions; };