import { AthenaChatModule, AthenaChatWsServerEvent } from '@xylex-group/athena'; import { StoreApi, UseBoundStore } from 'zustand'; import { AthenaChatPendingAttachment, AthenaChatUploadedFile, AthenaChatUser, AthenaChatViewMember, AthenaChatViewMessage, AthenaChatViewRoom } from './types.js'; /** How many messages a single history page requests. */ export declare const ATHENA_CHAT_PAGE_SIZE = 50; /** How long a peer stays in the typing list without a refresh. */ export declare const ATHENA_CHAT_TYPING_TTL_MS = 6000; export interface AthenaChatSendOptions { attachments?: readonly AthenaChatUploadedFile[]; replyToId?: string | null; } export interface AthenaChatStoreConfig { /** Athena chat module, e.g. `client.chat`. */ chat: AthenaChatModule; /** Signed-in user id; used for "is own message" and read cursors. */ currentUserId: string; /** * Uploads a file and returns its Athena file id. * * Optional: when absent the composer hides its attachment controls, because * the chat gateway only accepts ids for files that already exist. */ uploadFile?: (file: File) => Promise; } export interface AthenaChatState { addReaction: (messageId: string, emoji: string) => Promise; /** Loads the room list and opens the most recent room. */ bootstrap: () => Promise; /** * Whether the host app supplied an upload implementation. * * The composer hides attachment controls when this is `false` rather than * offering an action that cannot succeed. */ canUploadFiles: boolean; clearComposer: () => void; createRoom: (input: { kind?: "channel" | "group"; memberUserIds?: readonly string[]; title?: string | null; }) => Promise; currentUserId: string; deleteMessage: (messageId: string) => Promise; draft: string; editingId: string | null; editMessage: (messageId: string, text: string) => Promise; error: string | null; /** True while an older page is being fetched. */ hasMore: boolean; /** Applies a realtime frame from `client.chat.realtime`. */ ingestRealtimeEvent: (event: AthenaChatWsServerEvent) => void; isLoading: boolean; isLoadingMore: boolean; isSending: boolean; isUploading: boolean; lightboxFileId: string | null; loadOlderMessages: () => Promise; markRead: () => Promise; members: AthenaChatViewMember[]; messages: AthenaChatViewMessage[]; openRoom: (roomId: string) => Promise; /** Recovers only messages after the last applied room sequence. */ recoverRoom: (roomId: string) => Promise; pendingAttachments: AthenaChatPendingAttachment[]; removePendingAttachment: (fileId: string) => void; removeReaction: (messageId: string, emoji: string) => Promise; retryMessage: (messageId: string) => Promise; replyTo: AthenaChatViewMessage | null; roomId: string | null; rooms: AthenaChatViewRoom[]; /** Bumped whenever this client posts, so the view can force-scroll down. */ selfMessageToken: number; sendMessage: (text: string, options?: AthenaChatSendOptions) => Promise; setDraft: (draft: string) => void; setEditingId: (messageId: string | null) => void; setError: (error: string | null) => void; setLightboxFileId: (fileId: string | null) => void; setReplyTo: (message: AthenaChatViewMessage | null) => void; setTypingUsers: (roomId: string, userIds: readonly string[]) => void; /** Peers currently typing in the open room. */ typingUserIds: string[]; uploadFiles: (files: readonly File[]) => Promise; upsertUsers: (users: readonly AthenaChatUser[]) => void; users: Record; } export type AthenaChatStore = UseBoundStore>; export declare function latestConfirmedMessageSeq(messages: readonly AthenaChatViewMessage[]): number; /** * Creates a chat store bound to one Athena chat module. * * A factory rather than a module-level singleton so several independent chat * surfaces (or several test cases) can coexist without sharing state. */ export declare function createAthenaChatStore(config: AthenaChatStoreConfig): AthenaChatStore;