@anakin824/prdg-chat-ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,671 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+ import * as _tanstack_react_query from '@tanstack/react-query';
4
+ import { QueryClient } from '@tanstack/react-query';
5
+ import * as _tanstack_query_core from '@tanstack/query-core';
6
+
7
+ type ChatTheme = {
8
+ primary?: string;
9
+ bubbleSent?: string;
10
+ bubbleReceived?: string;
11
+ textOnSent?: string;
12
+ textOnReceived?: string;
13
+ fontFamily?: string;
14
+ radius?: string;
15
+ surface?: string;
16
+ border?: string;
17
+ /** Input / icon button fill (e.g. rgba) */
18
+ mutedFill?: string;
19
+ /** Optional shadow for the message composer bar */
20
+ composerShadow?: string;
21
+ };
22
+ /** e.g. order-linked chat — pass as ChatPanel / StandaloneChatPage `entityContext` */
23
+ type EntityConversationContext = {
24
+ entity_ref: string;
25
+ entity_uuid: string;
26
+ title?: string;
27
+ members?: string[];
28
+ };
29
+ type Conversation = {
30
+ id: string;
31
+ kind: string;
32
+ title?: string | null;
33
+ updated_at: string;
34
+ /** Defaults true when omitted (older payloads). */
35
+ list_in_inbox?: boolean;
36
+ entity_ref?: string | null;
37
+ entity_uuid?: string | null;
38
+ /** Truncated body of the most recent non-deleted message (≤80 chars). */
39
+ last_message_preview?: string | null;
40
+ /** ISO timestamp of the most recent message (may differ from updated_at). */
41
+ last_message_at?: string | null;
42
+ /** For direct conversations: the other participant's display name. */
43
+ peer_display_name?: string | null;
44
+ };
45
+ type MessageAttachment = {
46
+ id: string;
47
+ storage_key: string;
48
+ mime_type: string;
49
+ byte_size: number;
50
+ width?: number | null;
51
+ height?: number | null;
52
+ duration_seconds?: number | null;
53
+ thumbnail_storage_key?: string | null;
54
+ };
55
+ type Message = {
56
+ id: string;
57
+ conversation_id: string;
58
+ sender_id: string;
59
+ body?: string | null;
60
+ created_at: string;
61
+ edited_at?: string | null;
62
+ deleted_at?: string | null;
63
+ attachments?: MessageAttachment[];
64
+ mentioned_user_ids?: string[];
65
+ /** Client-only — not present on server messages. Tracks optimistic send state. */
66
+ _status?: "sending" | "failed";
67
+ };
68
+ /** Server → browser over WebSocket (JSON). Pushed by a Conduitly consumer into NATS subjects. */
69
+ type WSServerEvent = {
70
+ type: "message.new";
71
+ data: Message;
72
+ } | {
73
+ type: "message.edited";
74
+ data: Message;
75
+ } | {
76
+ type: "message.deleted";
77
+ data: {
78
+ id: string;
79
+ conversation_id: string;
80
+ deleted_at: string;
81
+ };
82
+ } | {
83
+ type: "typing.start";
84
+ data: {
85
+ user_id: string;
86
+ conversation_id: string;
87
+ };
88
+ } | {
89
+ type: "typing.stop";
90
+ data: {
91
+ user_id: string;
92
+ conversation_id: string;
93
+ };
94
+ } | {
95
+ type: "read";
96
+ data: {
97
+ user_id: string;
98
+ conversation_id: string;
99
+ message_id: string;
100
+ };
101
+ } | {
102
+ type: "conversation.updated";
103
+ data: Conversation;
104
+ } | {
105
+ type: "conversation.member_added";
106
+ data: {
107
+ conversation_id: string;
108
+ added_user_ids: string[];
109
+ actor_user_id: string;
110
+ };
111
+ } | {
112
+ type: "conversation.member_removed";
113
+ data: {
114
+ conversation_id: string;
115
+ removed_user_id: string;
116
+ actor_user_id: string;
117
+ };
118
+ };
119
+ type ChatConfig = {
120
+ apiUrl: string;
121
+ token: string;
122
+ userId: string;
123
+ tenantId: string;
124
+ /** Polling when WS down (ms). 0 = off */
125
+ pollIntervalMs?: number;
126
+ /**
127
+ * When true, standalone layout shows the Calls tab and voice/video actions in the chat header.
128
+ * Default false; enable when your host integrates calling.
129
+ */
130
+ callEnabled?: boolean;
131
+ };
132
+
133
+ type ChatProviderProps = {
134
+ apiUrl: string;
135
+ /** Current bearer token (HDS JWT in integrated mode, prdg-chat JWT in standalone). */
136
+ token: string;
137
+ /** prdg-chat user UUID — identifies the current user for own-message display, mentions, etc. */
138
+ userId: string;
139
+ /** Internal prdg-chat tenant UUID (JWT / API). */
140
+ tenantId: string;
141
+ /**
142
+ * Conduitly `tenant_id` for NATS (`chat.{conduitly_tenant_id}.user.*`). Set via `conduitly_tenant_id` in dev.json or `NEXT_PUBLIC_CONDUITLY_TENANT_ID`; do not rely on internal prdg-chat tenant UUID.
143
+ */
144
+ conduitlyTenantId?: string;
145
+ theme?: ChatTheme;
146
+ pollIntervalMs?: number;
147
+ onUnreadChange?: (n: number) => void;
148
+ /**
149
+ * Called when a request returns 401 (token expired). Should refresh the token and return
150
+ * the new string, or return null if refresh is not possible (user will be logged out by host).
151
+ * ChatProvider also uses the returned token for all subsequent requests without remounting.
152
+ */
153
+ onTokenRefresh?: () => Promise<string | null>;
154
+ /**
155
+ * When true, standalone UI shows Calls tab and audio/video header buttons. Default false.
156
+ */
157
+ callEnabled?: boolean;
158
+ /**
159
+ * NATS WebSocket URL(s) for `nats.ws`: a single `ws://`/`wss://` URL or comma-separated list.
160
+ * Broker-style `nats://host:port` entries are converted to `ws://` for the browser.
161
+ * When set, the client subscribes to chat subjects and turns off REST polling while connected.
162
+ */
163
+ natsWsUrl?: string;
164
+ /** Optional NATS auth token (when the server uses token authentication). */
165
+ natsToken?: string;
166
+ children: ReactNode;
167
+ };
168
+ declare function ChatProvider({ apiUrl, token, userId, tenantId, conduitlyTenantId, theme, pollIntervalMs, onUnreadChange: _onUnreadChange, onTokenRefresh, callEnabled, natsWsUrl, natsToken, children, }: ChatProviderProps): react.JSX.Element;
169
+
170
+ type ListConversationsRes = {
171
+ items: Conversation[];
172
+ next_cursor: string;
173
+ };
174
+ type ListMessagesRes = {
175
+ items: Message[];
176
+ next_cursor: string;
177
+ };
178
+ type AppUser = {
179
+ id: string;
180
+ tenant_id: string;
181
+ display_name: string;
182
+ email?: string | null;
183
+ ext_user_id?: string | null;
184
+ };
185
+ type PresignPutRes = {
186
+ upload_url: string;
187
+ key: string;
188
+ bucket: string;
189
+ expires_in: number;
190
+ };
191
+ type PresignGetRes = {
192
+ url: string;
193
+ expires_in: number;
194
+ };
195
+ declare class ChatAPI {
196
+ private baseUrl;
197
+ private getToken;
198
+ /**
199
+ * Called when a request returns 401. Should refresh the token and return the new one,
200
+ * or return null if refresh is impossible. ChatAPI retries the failed request once with
201
+ * the returned token. The provider also updates its token ref for future requests.
202
+ */
203
+ private onAuthError?;
204
+ constructor(baseUrl: string, getToken: () => string | null,
205
+ /**
206
+ * Called when a request returns 401. Should refresh the token and return the new one,
207
+ * or return null if refresh is impossible. ChatAPI retries the failed request once with
208
+ * the returned token. The provider also updates its token ref for future requests.
209
+ */
210
+ onAuthError?: (() => Promise<string | null>) | undefined);
211
+ private headers;
212
+ private json;
213
+ listConversations(cursor?: string, limit?: number): Promise<ListConversationsRes>;
214
+ listMessages(conversationId: string, cursor?: string, limit?: number): Promise<ListMessagesRes>;
215
+ findOrCreateDirect(peerUserId: string): Promise<Conversation>;
216
+ createGroup(title: string, members: string[]): Promise<Conversation>;
217
+ findOrCreateEntity(input: {
218
+ title: string;
219
+ entity_ref: string;
220
+ entity_uuid: string;
221
+ members?: string[];
222
+ }): Promise<Conversation>;
223
+ listConversationMembers(conversationId: string): Promise<AppUser[]>;
224
+ listContacts(q?: string, limit?: number): Promise<AppUser[]>;
225
+ sendMessage(conversationId: string, body: {
226
+ body?: string | null;
227
+ client_id?: string | null;
228
+ reply_to_message_id?: string | null;
229
+ mentioned_user_ids?: string[];
230
+ attachments?: Array<{
231
+ storage_key: string;
232
+ mime_type: string;
233
+ byte_size: number;
234
+ original_filename?: string | null;
235
+ width?: number | null;
236
+ height?: number | null;
237
+ duration_seconds?: number | null;
238
+ thumbnail_storage_key?: string | null;
239
+ }>;
240
+ }): Promise<Message>;
241
+ presignPut(filename: string, contentType: string): Promise<PresignPutRes>;
242
+ presignGet(key: string): Promise<PresignGetRes>;
243
+ }
244
+
245
+ type ChatContextValue = {
246
+ api: ChatAPI;
247
+ config: ChatConfig;
248
+ /** Resolved theme tokens (defaults merged) */
249
+ theme: ChatTheme;
250
+ queryClient: QueryClient;
251
+ /** prdg-chat user UUID for the current session — used to identify own messages, mentions, etc. */
252
+ userId: string;
253
+ /** Internal prdg-chat tenant UUID (API scope). */
254
+ tenantId: string;
255
+ /**
256
+ * Conduitly tenant id for NATS subjects (`chat.{natsTenantId}.user.*`) — matches `tenant.slug` / Conduitly `tenant_id` in events.
257
+ */
258
+ natsTenantId: string;
259
+ wsConnected: boolean;
260
+ sendTyping: (conversationId: string) => void;
261
+ sendTypingStop: (conversationId: string) => void;
262
+ sendRead: (conversationId: string, messageId: string) => void;
263
+ /**
264
+ * Per-conversation map of user IDs currently typing.
265
+ * Key: conversationId. Value: array of user IDs (never includes the current user).
266
+ */
267
+ typingByConversation: Record<string, string[]>;
268
+ };
269
+ declare function useChat(): ChatContextValue;
270
+
271
+ type ChatPanelProps = {
272
+ conversationId?: string;
273
+ peerUserId?: string;
274
+ entityContext?: EntityConversationContext;
275
+ showNewChat?: boolean;
276
+ onConversationChange?: (conversationId: string | null) => void;
277
+ };
278
+ declare function useChatPanelController({ conversationId: initialId, peerUserId, entityContext, showNewChat, onConversationChange, }: ChatPanelProps): {
279
+ selectedId: string | null;
280
+ setSelected: (id: string | null) => void;
281
+ newChatOpen: boolean;
282
+ setNewChatOpen: react.Dispatch<react.SetStateAction<boolean>>;
283
+ refreshFromServer: () => void;
284
+ convItems: Conversation[];
285
+ messages: Message[];
286
+ loadMsg: boolean;
287
+ fetchOlderMessages: () => Promise<void>;
288
+ isFetchingOlder: boolean;
289
+ hasMoreMessages: boolean;
290
+ typingNames: string[];
291
+ showNewChat: boolean;
292
+ membersForSelected: AppUser[];
293
+ };
294
+
295
+ declare function ChatPanel(props: ChatPanelProps): react.JSX.Element;
296
+
297
+ type ChatWidgetProps = ChatPanelProps & {
298
+ position?: "bottom-right" | "bottom-left";
299
+ defaultOpen?: boolean;
300
+ };
301
+ declare function ChatWidget({ position, defaultOpen, conversationId, peerUserId, showNewChat, onConversationChange, }: ChatWidgetProps): react.JSX.Element;
302
+
303
+ type StandaloneChatPageProps = ChatPanelProps;
304
+ declare function StandaloneChatPage(props: ChatPanelProps): react.JSX.Element;
305
+
306
+ type Props$5 = {
307
+ messages: Message[];
308
+ /** Override default thread container (e.g. full-height flex child) */
309
+ threadClassName?: string;
310
+ fetchOlderMessages?: () => void;
311
+ isFetchingOlder?: boolean;
312
+ hasMoreMessages?: boolean;
313
+ };
314
+ declare function MessageThread({ messages, threadClassName, fetchOlderMessages, isFetchingOlder, hasMoreMessages, }: Props$5): react.JSX.Element;
315
+
316
+ type Props$4 = {
317
+ conversationId: string;
318
+ };
319
+ declare function MessageInput({ conversationId }: Props$4): react.JSX.Element;
320
+
321
+ type Props$3 = {
322
+ items: Conversation[];
323
+ selectedId: string | null;
324
+ onSelect: (id: string) => void;
325
+ };
326
+ declare function ConversationList({ items, selectedId, onSelect }: Props$3): react.JSX.Element;
327
+
328
+ type Props$2 = {
329
+ message: Message;
330
+ compact?: boolean;
331
+ /** Fade-in animation for messages that arrive from other senders via NATS. */
332
+ animateIn?: boolean;
333
+ };
334
+ declare function MessageBubble({ message, compact, animateIn }: Props$2): react.JSX.Element;
335
+
336
+ type ChatConversationViewProps = {
337
+ /** Active conversation — wire `useChatPanelController({ conversationId })` or entity resolution first. */
338
+ conversationId: string;
339
+ /** Optional block above the scrollable thread (order title, breadcrumbs, etc.). */
340
+ header?: ReactNode;
341
+ className?: string;
342
+ threadAreaClassName?: string;
343
+ /** Passed to `MessageThread` (default: `chatStyles.threadFlex`). */
344
+ threadClassName?: string;
345
+ inputAreaClassName?: string;
346
+ /** @default true */
347
+ showTyping?: boolean;
348
+ loadingFallback?: ReactNode;
349
+ };
350
+ /**
351
+ * Self-contained thread + typing + composer for a single conversation (e.g. entity / order chat).
352
+ * Compose your own layout, or use `StandaloneChatPage` for the full inbox + thread experience.
353
+ */
354
+ declare function ChatConversationView({ conversationId, header, className, threadAreaClassName, threadClassName, inputAreaClassName, showTyping, loadingFallback, }: ChatConversationViewProps): react.JSX.Element;
355
+
356
+ type SidebarTab = "recent" | "groups" | "calls";
357
+ type ChatInboxSidebarProps = {
358
+ q: string;
359
+ setQ: (q: string) => void;
360
+ tab: SidebarTab;
361
+ setTab: (t: SidebarTab) => void;
362
+ tabDefs: [SidebarTab, string][];
363
+ filtered: Conversation[];
364
+ activeRows: Conversation[];
365
+ restRows: Conversation[];
366
+ selectedId: string | null;
367
+ onSelectConversation: (id: string) => void;
368
+ onRefresh: () => void;
369
+ showNewChat: boolean;
370
+ onNewChat: () => void;
371
+ };
372
+ /**
373
+ * Full inbox sidebar (search, tabs, conversation rows, FAB). Styles use `standalone-chat.module.css`.
374
+ * Pair with `ChatMainColumn` or your own main area; or use `StandaloneChatPage` for the full layout.
375
+ */
376
+ declare function ChatInboxSidebar({ q, setQ, tab, setTab, tabDefs, filtered, activeRows, restRows, selectedId, onSelectConversation, onRefresh, showNewChat, onNewChat, }: ChatInboxSidebarProps): react.JSX.Element;
377
+
378
+ type ChatMainColumnProps = {
379
+ selectedId: string | null;
380
+ headerTitle: string;
381
+ headerStatus: string;
382
+ messages: Message[];
383
+ loadMsg: boolean;
384
+ fetchOlderMessages?: () => void;
385
+ isFetchingOlder?: boolean;
386
+ hasMoreMessages?: boolean;
387
+ typingNames: string[];
388
+ /** When nothing is selected */
389
+ emptyMessage?: string;
390
+ threadClassName?: string;
391
+ };
392
+ /**
393
+ * Main chat column: header, scrollable thread, typing line, composer. Use with `ChatInboxSidebar` or a custom picker.
394
+ * For a **single** conversation (entity / order), prefer `ChatConversationView` instead.
395
+ */
396
+ declare function ChatMainColumn({ selectedId, headerTitle, headerStatus, messages, loadMsg, fetchOlderMessages, isFetchingOlder, hasMoreMessages, typingNames, emptyMessage, threadClassName, }: ChatMainColumnProps): react.JSX.Element;
397
+
398
+ /** Primary display name for a conversation in the list. */
399
+ declare function convDisplayName(c: Conversation): string;
400
+ /** For header / controller use (title, not the peer name). */
401
+ declare function convLabel(c: Conversation): string;
402
+ declare function formatConvTime(iso: string): string;
403
+ declare function initials(name: string): string;
404
+
405
+ type Props$1 = {
406
+ open: boolean;
407
+ onClose: () => void;
408
+ /** Called after a conversation is created or opened. */
409
+ onConversationReady: (conversationId: string) => void;
410
+ };
411
+ declare function NewChatModal({ open, onClose, onConversationReady }: Props$1): react.JSX.Element | null;
412
+
413
+ type Props = {
414
+ /** Display names of users currently typing (already resolved from member list). */
415
+ names: string[];
416
+ };
417
+ declare function TypingIndicator({ names }: Props): react.JSX.Element | null;
418
+
419
+ /** Stable React Query keys for chat — use with invalidateQueries / host integrations. */
420
+ declare const chatKeys: {
421
+ all: readonly ["chat"];
422
+ conversations: () => readonly ["chat", "conversations"];
423
+ messages: (conversationId: string | null) => readonly ["chat", "messages", string | null];
424
+ members: (conversationId: string) => readonly ["chat", "members", string];
425
+ contacts: (q: string) => readonly ["chat", "contacts", string];
426
+ };
427
+
428
+ declare function useConversations(): _tanstack_react_query.UseQueryResult<ListConversationsRes, Error>;
429
+
430
+ type MessagePage = {
431
+ items: Message[];
432
+ next_cursor: string;
433
+ };
434
+ /**
435
+ * REST is authoritative; merge in any client-only rows (WS-delivered before fetch,
436
+ * or optimistic local-* ids) and dedupe by message id. Newest-first order.
437
+ */
438
+ declare function mergeMessagePages(server: MessagePage, prev: MessagePage | undefined): MessagePage;
439
+
440
+ /** First page size for `GET /conversations/:id/messages` (newest first). Older pages use `next_cursor`. */
441
+ declare const INITIAL_MESSAGE_PAGE_SIZE = 30;
442
+ declare function useMessages(conversationId: string | null): {
443
+ fetchOlderMessages: () => Promise<void>;
444
+ isFetchingOlder: boolean;
445
+ hasMoreMessages: boolean;
446
+ data: MessagePage;
447
+ error: Error;
448
+ isError: true;
449
+ isPending: false;
450
+ isLoading: false;
451
+ isLoadingError: false;
452
+ isRefetchError: true;
453
+ isSuccess: false;
454
+ isPlaceholderData: false;
455
+ status: "error";
456
+ dataUpdatedAt: number;
457
+ errorUpdatedAt: number;
458
+ failureCount: number;
459
+ failureReason: Error | null;
460
+ errorUpdateCount: number;
461
+ isFetched: boolean;
462
+ isFetchedAfterMount: boolean;
463
+ isFetching: boolean;
464
+ isInitialLoading: boolean;
465
+ isPaused: boolean;
466
+ isRefetching: boolean;
467
+ isStale: boolean;
468
+ isEnabled: boolean;
469
+ refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<MessagePage, Error>>;
470
+ fetchStatus: _tanstack_query_core.FetchStatus;
471
+ promise: Promise<MessagePage>;
472
+ } | {
473
+ fetchOlderMessages: () => Promise<void>;
474
+ isFetchingOlder: boolean;
475
+ hasMoreMessages: boolean;
476
+ data: MessagePage;
477
+ error: null;
478
+ isError: false;
479
+ isPending: false;
480
+ isLoading: false;
481
+ isLoadingError: false;
482
+ isRefetchError: false;
483
+ isSuccess: true;
484
+ isPlaceholderData: false;
485
+ status: "success";
486
+ dataUpdatedAt: number;
487
+ errorUpdatedAt: number;
488
+ failureCount: number;
489
+ failureReason: Error | null;
490
+ errorUpdateCount: number;
491
+ isFetched: boolean;
492
+ isFetchedAfterMount: boolean;
493
+ isFetching: boolean;
494
+ isInitialLoading: boolean;
495
+ isPaused: boolean;
496
+ isRefetching: boolean;
497
+ isStale: boolean;
498
+ isEnabled: boolean;
499
+ refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<MessagePage, Error>>;
500
+ fetchStatus: _tanstack_query_core.FetchStatus;
501
+ promise: Promise<MessagePage>;
502
+ } | {
503
+ fetchOlderMessages: () => Promise<void>;
504
+ isFetchingOlder: boolean;
505
+ hasMoreMessages: boolean;
506
+ data: undefined;
507
+ error: Error;
508
+ isError: true;
509
+ isPending: false;
510
+ isLoading: false;
511
+ isLoadingError: true;
512
+ isRefetchError: false;
513
+ isSuccess: false;
514
+ isPlaceholderData: false;
515
+ status: "error";
516
+ dataUpdatedAt: number;
517
+ errorUpdatedAt: number;
518
+ failureCount: number;
519
+ failureReason: Error | null;
520
+ errorUpdateCount: number;
521
+ isFetched: boolean;
522
+ isFetchedAfterMount: boolean;
523
+ isFetching: boolean;
524
+ isInitialLoading: boolean;
525
+ isPaused: boolean;
526
+ isRefetching: boolean;
527
+ isStale: boolean;
528
+ isEnabled: boolean;
529
+ refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<MessagePage, Error>>;
530
+ fetchStatus: _tanstack_query_core.FetchStatus;
531
+ promise: Promise<MessagePage>;
532
+ } | {
533
+ fetchOlderMessages: () => Promise<void>;
534
+ isFetchingOlder: boolean;
535
+ hasMoreMessages: boolean;
536
+ data: undefined;
537
+ error: null;
538
+ isError: false;
539
+ isPending: true;
540
+ isLoading: true;
541
+ isLoadingError: false;
542
+ isRefetchError: false;
543
+ isSuccess: false;
544
+ isPlaceholderData: false;
545
+ status: "pending";
546
+ dataUpdatedAt: number;
547
+ errorUpdatedAt: number;
548
+ failureCount: number;
549
+ failureReason: Error | null;
550
+ errorUpdateCount: number;
551
+ isFetched: boolean;
552
+ isFetchedAfterMount: boolean;
553
+ isFetching: boolean;
554
+ isInitialLoading: boolean;
555
+ isPaused: boolean;
556
+ isRefetching: boolean;
557
+ isStale: boolean;
558
+ isEnabled: boolean;
559
+ refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<MessagePage, Error>>;
560
+ fetchStatus: _tanstack_query_core.FetchStatus;
561
+ promise: Promise<MessagePage>;
562
+ } | {
563
+ fetchOlderMessages: () => Promise<void>;
564
+ isFetchingOlder: boolean;
565
+ hasMoreMessages: boolean;
566
+ data: undefined;
567
+ error: null;
568
+ isError: false;
569
+ isPending: true;
570
+ isLoadingError: false;
571
+ isRefetchError: false;
572
+ isSuccess: false;
573
+ isPlaceholderData: false;
574
+ status: "pending";
575
+ dataUpdatedAt: number;
576
+ errorUpdatedAt: number;
577
+ failureCount: number;
578
+ failureReason: Error | null;
579
+ errorUpdateCount: number;
580
+ isFetched: boolean;
581
+ isFetchedAfterMount: boolean;
582
+ isFetching: boolean;
583
+ isLoading: boolean;
584
+ isInitialLoading: boolean;
585
+ isPaused: boolean;
586
+ isRefetching: boolean;
587
+ isStale: boolean;
588
+ isEnabled: boolean;
589
+ refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<MessagePage, Error>>;
590
+ fetchStatus: _tanstack_query_core.FetchStatus;
591
+ promise: Promise<MessagePage>;
592
+ } | {
593
+ fetchOlderMessages: () => Promise<void>;
594
+ isFetchingOlder: boolean;
595
+ hasMoreMessages: boolean;
596
+ data: MessagePage;
597
+ isError: false;
598
+ error: null;
599
+ isPending: false;
600
+ isLoading: false;
601
+ isLoadingError: false;
602
+ isRefetchError: false;
603
+ isSuccess: true;
604
+ isPlaceholderData: true;
605
+ status: "success";
606
+ dataUpdatedAt: number;
607
+ errorUpdatedAt: number;
608
+ failureCount: number;
609
+ failureReason: Error | null;
610
+ errorUpdateCount: number;
611
+ isFetched: boolean;
612
+ isFetchedAfterMount: boolean;
613
+ isFetching: boolean;
614
+ isInitialLoading: boolean;
615
+ isPaused: boolean;
616
+ isRefetching: boolean;
617
+ isStale: boolean;
618
+ isEnabled: boolean;
619
+ refetch: (options?: _tanstack_query_core.RefetchOptions) => Promise<_tanstack_query_core.QueryObserverResult<MessagePage, Error>>;
620
+ fetchStatus: _tanstack_query_core.FetchStatus;
621
+ promise: Promise<MessagePage>;
622
+ };
623
+
624
+ /** Orchestrated mutations + cache invalidation for host UIs and internal widgets. */
625
+ declare function useChatActions(): {
626
+ api: ChatAPI;
627
+ openOrCreateDirect: (peerUserId: string) => Promise<Conversation>;
628
+ createGroup: (title: string, members: string[]) => Promise<Conversation>;
629
+ findOrCreateEntity: (input: {
630
+ title: string;
631
+ entity_ref: string;
632
+ entity_uuid: string;
633
+ members?: string[];
634
+ }) => Promise<Conversation>;
635
+ invalidateConversations: () => Promise<void>;
636
+ invalidateMessages: (conversationId: string) => Promise<void>;
637
+ invalidateMembers: (conversationId: string) => Promise<void>;
638
+ invalidateAllChat: () => Promise<void>;
639
+ };
640
+
641
+ declare function useConversationMembers(conversationId: string | null): _tanstack_react_query.UseQueryResult<AppUser[], Error>;
642
+
643
+ type UploadedPart = {
644
+ storage_key: string;
645
+ mime_type: string;
646
+ byte_size: number;
647
+ original_filename?: string;
648
+ width?: number;
649
+ height?: number;
650
+ duration_seconds?: number;
651
+ thumbnail_storage_key?: string;
652
+ };
653
+ declare function useUpload(): {
654
+ uploadFile: (file: File, meta?: Partial<UploadedPart>) => Promise<UploadedPart>;
655
+ };
656
+
657
+ declare function usePresignedUrl(storageKey: string | undefined | null): {
658
+ url: string | null;
659
+ error: Error | null;
660
+ };
661
+
662
+ declare function useVoiceRecorder(): {
663
+ recording: boolean;
664
+ start: () => Promise<void>;
665
+ stop: () => Promise<{
666
+ blob: Blob;
667
+ mimeType: string;
668
+ } | null>;
669
+ };
670
+
671
+ export { type AppUser, ChatAPI, MessageInput as ChatComposer, type ChatConfig, type ChatContextValue, ChatConversationView, type ChatConversationViewProps, ChatInboxSidebar, type ChatInboxSidebarProps, ChatMainColumn, type ChatMainColumnProps, ChatPanel, type ChatPanelProps, ChatProvider, type ChatProviderProps, type ChatTheme, ChatWidget, type ChatWidgetProps, type Conversation, ConversationList, type EntityConversationContext as EntityContext, INITIAL_MESSAGE_PAGE_SIZE, type Message, type MessageAttachment, MessageBubble, MessageInput, type MessagePage, MessageThread, NewChatModal, type SidebarTab, StandaloneChatPage, type StandaloneChatPageProps, TypingIndicator, type WSServerEvent, chatKeys, convDisplayName, convLabel, formatConvTime, initials, mergeMessagePages, useChat, useChatActions, useChatPanelController, useConversationMembers, useConversations, useMessages, usePresignedUrl, useUpload, useVoiceRecorder };