@antzsoft/chat-core 1.0.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,852 @@
1
+ import { AxiosInstance } from 'axios';
2
+ import { Socket } from 'socket.io-client';
3
+ import * as zustand_middleware from 'zustand/middleware';
4
+ import * as zustand from 'zustand';
5
+
6
+ type EncryptionMode = 'none' | 'server' | 'e2ee';
7
+ type FileType = 'image' | 'video' | 'audio' | 'document';
8
+ type ConversationType = 'direct' | 'group';
9
+ type MessageStatus = 'sent' | 'delivered' | 'read' | 'failed' | 'deleted';
10
+ type DeliveryStatus = 'sending' | 'sent' | 'delivered' | 'read' | 'failed';
11
+ type UserStatus = 'online' | 'offline' | 'away';
12
+ type ParticipantRole = 'admin' | 'member';
13
+ /**
14
+ * Platform-agnostic file descriptor.
15
+ * - Web: built from a browser File object ({ uri: URL.createObjectURL(f), name: f.name, type: f.type, size: f.size })
16
+ * - React Native: built from document/image picker result ({ uri: result.uri, name: result.name, type: result.mimeType, size: result.size })
17
+ */
18
+ interface UploadableFile {
19
+ /** Local URI — blob URL on web, file:// URI on RN */
20
+ uri: string;
21
+ name: string;
22
+ /** MIME type, e.g. "image/jpeg" */
23
+ type: string;
24
+ size: number;
25
+ }
26
+ interface User {
27
+ id: string;
28
+ tenantId: string;
29
+ email: string;
30
+ username: string;
31
+ displayName: string;
32
+ avatarUrl?: string;
33
+ phone?: string;
34
+ status: UserStatus;
35
+ lastSeenAt?: string;
36
+ createdAt: string;
37
+ updatedAt: string;
38
+ }
39
+ interface AuthTokens {
40
+ accessToken: string;
41
+ refreshToken: string;
42
+ tokenType: string;
43
+ expiresIn: number;
44
+ }
45
+ interface AuthResponse {
46
+ user: User;
47
+ tokens: AuthTokens;
48
+ }
49
+ interface LoginCredentials {
50
+ email: string;
51
+ password: string;
52
+ }
53
+ interface RegisterData {
54
+ email: string;
55
+ password: string;
56
+ username: string;
57
+ displayName: string;
58
+ phone?: string;
59
+ tenantId?: string;
60
+ }
61
+ interface Attachment {
62
+ id: string;
63
+ type: FileType;
64
+ url: string;
65
+ thumbnailUrl?: string;
66
+ filename: string;
67
+ mimeType: string;
68
+ size: number;
69
+ dimensions?: {
70
+ width: number;
71
+ height: number;
72
+ };
73
+ duration?: number;
74
+ isUploading?: boolean;
75
+ uploadProgress?: number;
76
+ }
77
+ interface EncryptedContent {
78
+ ciphertext: string;
79
+ iv: string;
80
+ tag: string;
81
+ algorithm: 'aes-256-gcm';
82
+ }
83
+ interface EncryptionKeyInfo {
84
+ key: string;
85
+ enabled: boolean;
86
+ mode: EncryptionMode;
87
+ }
88
+ interface MessageReaction {
89
+ emoji: string;
90
+ userIds: string[];
91
+ count: number;
92
+ }
93
+ interface MessageContent {
94
+ text?: string;
95
+ type: 'text' | 'attachment' | 'system';
96
+ attachments?: Attachment[];
97
+ }
98
+ interface MessageReplyReference {
99
+ messageId?: string;
100
+ contentPreview?: string;
101
+ senderName?: string;
102
+ id?: string;
103
+ content?: MessageContent;
104
+ sender?: Pick<User, 'displayName' | 'avatarUrl'>;
105
+ }
106
+ interface Message {
107
+ id: string;
108
+ tenantId: string;
109
+ conversationId: string;
110
+ senderId: string;
111
+ content: MessageContent;
112
+ replyTo?: MessageReplyReference;
113
+ reactions: MessageReaction[];
114
+ status: MessageStatus;
115
+ deliveryStatus?: DeliveryStatus;
116
+ isEdited: boolean;
117
+ editedAt?: string;
118
+ isStarred?: boolean;
119
+ isPinned?: boolean;
120
+ pinnedBy?: string;
121
+ pinnedAt?: string;
122
+ uploadProgress?: number;
123
+ sentAt: string;
124
+ createdAt: string;
125
+ sender?: User;
126
+ readBy?: string[];
127
+ isEncrypted?: boolean;
128
+ encryptionMode?: EncryptionMode;
129
+ encryptedContent?: EncryptedContent;
130
+ }
131
+ interface Participant {
132
+ userId: string;
133
+ role: ParticipantRole;
134
+ joinedAt: string;
135
+ isActive?: boolean;
136
+ user?: User;
137
+ }
138
+ interface ConversationSettings {
139
+ onlyAdminsCanMessage?: boolean;
140
+ onlyAdminsCanAddMembers?: boolean;
141
+ }
142
+ interface Conversation {
143
+ id: string;
144
+ tenantId: string;
145
+ conversationType: ConversationType;
146
+ name?: string;
147
+ description?: string;
148
+ icon?: string;
149
+ iconUrl?: string;
150
+ participants: Participant[];
151
+ participantCount?: number;
152
+ settings?: ConversationSettings;
153
+ lastMessage?: Message;
154
+ createdBy?: string;
155
+ isActive: boolean;
156
+ createdAt: string;
157
+ updatedAt: string;
158
+ unreadCount?: number;
159
+ isPinned?: boolean;
160
+ isMuted?: boolean;
161
+ mutedUntil?: string;
162
+ encryptionMode?: EncryptionMode;
163
+ isEncryptionEnabled?: boolean;
164
+ encryptionKey?: string;
165
+ }
166
+ interface PaginationMeta {
167
+ total: number;
168
+ page: number;
169
+ limit: number;
170
+ totalPages: number;
171
+ hasNextPage: boolean;
172
+ hasPrevPage: boolean;
173
+ }
174
+ interface PaginatedResponse<T> {
175
+ data: T[];
176
+ meta: PaginationMeta;
177
+ }
178
+ interface CursorPaginationMeta {
179
+ hasMore: boolean;
180
+ nextCursor?: string;
181
+ prevCursor?: string;
182
+ }
183
+ interface CursorPaginatedResponse<T> {
184
+ data: T[];
185
+ meta: CursorPaginationMeta;
186
+ }
187
+ interface PresignedUrlRequest {
188
+ filename: string;
189
+ mimeType: string;
190
+ size: number;
191
+ conversationId?: string;
192
+ folder?: string;
193
+ }
194
+ interface PresignedUrlResponse {
195
+ fileId: string;
196
+ uploadUrl: string;
197
+ method: 'PUT' | 'POST';
198
+ headers: Record<string, string>;
199
+ fields?: Record<string, string>;
200
+ expiresAt: string;
201
+ maxSize: number;
202
+ allowedMimeType: string;
203
+ }
204
+ interface FileResponse {
205
+ id: string;
206
+ filename: string;
207
+ originalFilename: string;
208
+ mimeType: string;
209
+ size: number;
210
+ url: string;
211
+ thumbnailUrl?: string;
212
+ type: FileType;
213
+ uploadedAt?: string;
214
+ confirmedAt?: string;
215
+ }
216
+ interface UploadProgress {
217
+ fileId: string;
218
+ filename: string;
219
+ progress: number;
220
+ status: 'pending' | 'uploading' | 'confirming' | 'done' | 'error';
221
+ error?: string;
222
+ }
223
+ interface BatchUploadResult {
224
+ successful: FileResponse[];
225
+ failed: Array<{
226
+ filename: string;
227
+ error: string;
228
+ }>;
229
+ }
230
+ interface NewMessageEvent {
231
+ tempId?: string;
232
+ senderName?: string;
233
+ senderAvatarUrl?: string;
234
+ message: Message;
235
+ }
236
+ interface MessageUpdatedEvent {
237
+ messageId: string;
238
+ conversationId: string;
239
+ text: string;
240
+ editedAt: string;
241
+ }
242
+ interface MessageDeletedEvent {
243
+ messageId: string;
244
+ conversationId: string;
245
+ }
246
+ interface ReactionUpdatedEvent {
247
+ messageId: string;
248
+ conversationId: string;
249
+ reactions: MessageReaction[];
250
+ }
251
+ interface TypingIndicatorEvent {
252
+ conversationId: string;
253
+ userId: string;
254
+ username: string;
255
+ displayName: string;
256
+ avatarUrl?: string;
257
+ isTyping: boolean;
258
+ }
259
+ interface UserStatusEvent {
260
+ userId: string;
261
+ status: UserStatus;
262
+ lastSeenAt?: string;
263
+ }
264
+ interface ReadReceiptEvent {
265
+ conversationId: string;
266
+ messageId: string;
267
+ userId: string;
268
+ readAt: string;
269
+ updatedMessageIds?: string[];
270
+ fullyReadMessageIds?: string[];
271
+ }
272
+ interface MessageAckEvent {
273
+ tempId: string;
274
+ messageId: string;
275
+ status: MessageStatus;
276
+ }
277
+ interface MessageDeliveredEvent {
278
+ messageId: string;
279
+ conversationId: string;
280
+ deliveredAt: string;
281
+ }
282
+ interface MessagesDeliveredEvent {
283
+ conversationId: string;
284
+ messageIds: string[];
285
+ deliveredTo: string;
286
+ deliveredAt: string;
287
+ }
288
+ interface SendMessageAttachment {
289
+ fileId: string;
290
+ type: FileType;
291
+ url: string;
292
+ thumbnailUrl?: string;
293
+ filename: string;
294
+ mimeType: string;
295
+ size: number;
296
+ }
297
+ interface OptimisticAttachment extends SendMessageAttachment {
298
+ id: string;
299
+ url: string;
300
+ thumbnailUrl?: string;
301
+ filename: string;
302
+ mimeType: string;
303
+ size: number;
304
+ isUploading?: boolean;
305
+ uploadProgress?: number;
306
+ }
307
+ interface SendMessagePayload {
308
+ conversationId: string;
309
+ text?: string;
310
+ attachments?: SendMessageAttachment[];
311
+ replyTo?: string;
312
+ tempId: string;
313
+ encryptedContent?: EncryptedContent;
314
+ isEncrypted?: boolean;
315
+ }
316
+
317
+ interface FileSizeLimits {
318
+ image?: number;
319
+ video?: number;
320
+ audio?: number;
321
+ document?: number;
322
+ default?: number;
323
+ }
324
+ /**
325
+ * Platform-provided function that performs the actual binary upload to a presigned URL.
326
+ * - Web implementation: XMLHttpRequest with progress events
327
+ * - RN implementation: fetch with FormData or direct body
328
+ *
329
+ * The core calls this — it never does the upload itself.
330
+ */
331
+ type PlatformUploadFn = (presigned: PresignedUrlResponse, file: UploadableFile, onProgress?: (pct: number) => void) => Promise<void>;
332
+ /**
333
+ * Platform-provided persistent key-value storage for auth token persistence.
334
+ * - Web: localStorage adapter
335
+ * - RN: AsyncStorage adapter
336
+ */
337
+ interface PersistStorage {
338
+ getItem(key: string): string | null | Promise<string | null>;
339
+ setItem(key: string, value: string): void | Promise<void>;
340
+ removeItem(key: string): void | Promise<void>;
341
+ }
342
+ interface UploadConfig {
343
+ /**
344
+ * Per-type file size limits in MB. Can also pass a single number for all types.
345
+ * Defaults: image 5MB, video 25MB, audio 10MB, document 10MB.
346
+ */
347
+ maxFileSizeMB?: number | FileSizeLimits;
348
+ /** Max files per message. Default: 10 */
349
+ maxFilesPerMessage?: number;
350
+ /** Which attachment types users can send. Default: all */
351
+ allowedTypes?: Array<FileType>;
352
+ /** Called when a file fails validation or upload */
353
+ onUploadError?: (file: UploadableFile, error: Error) => void;
354
+ /** Called with 0–100 aggregate progress during a batch upload */
355
+ onProgress?: (progress: number) => void;
356
+ }
357
+ interface AntzChatConfig {
358
+ /** REST API base URL — e.g. "https://api.yourapp.com/api/v1" */
359
+ apiUrl: string;
360
+ /**
361
+ * WebSocket server URL. Defaults to apiUrl with /api/vN path stripped.
362
+ * SDK connects to {socketUrl}/chat
363
+ */
364
+ socketUrl?: string;
365
+ /** Static JWT. Use this OR authProvider, not both. */
366
+ authToken?: string;
367
+ /**
368
+ * Dynamic token getter — called before requests and on socket reconnect.
369
+ * Preferred when the host app manages its own auth lifecycle.
370
+ */
371
+ authProvider?: () => Promise<string>;
372
+ /**
373
+ * External user ID — required for non-builtin modes (antz / external / wso2).
374
+ * Sent as x-user-id header on every request so the chat server can forward it
375
+ * to the user-service for token validation.
376
+ * Not needed for builtin mode (chat server issues its own JWTs).
377
+ */
378
+ userId?: string;
379
+ /** Required for multi-tenant backends. Sent as X-Tenant-ID header. */
380
+ tenantId?: string;
381
+ /** Must match server ENCRYPTION_MODE env var. Default: 'none' */
382
+ encryptionMode?: 'none' | 'server';
383
+ upload?: UploadConfig;
384
+ /**
385
+ * Platform-specific binary upload implementation.
386
+ * Required — each SDK (web, RN) provides its own.
387
+ */
388
+ platformUploadFn: PlatformUploadFn;
389
+ /**
390
+ * Platform-specific persistent storage for auth tokens.
391
+ * Required — each SDK provides its own (localStorage / AsyncStorage).
392
+ */
393
+ persistStorage: PersistStorage;
394
+ }
395
+ interface ResolvedFileSizeLimits {
396
+ image: number;
397
+ video: number;
398
+ audio: number;
399
+ document: number;
400
+ default: number;
401
+ }
402
+ interface ResolvedConfig {
403
+ apiUrl: string;
404
+ socketUrl: string;
405
+ authToken?: string;
406
+ authProvider?: () => Promise<string>;
407
+ userId?: string;
408
+ tenantId?: string;
409
+ encryptionMode: 'none' | 'server';
410
+ upload: {
411
+ maxFileSizeMB: ResolvedFileSizeLimits;
412
+ maxFilesPerMessage: number;
413
+ allowedTypes: FileType[];
414
+ onUploadError?: (file: UploadableFile, error: Error) => void;
415
+ onProgress?: (progress: number) => void;
416
+ };
417
+ platformUploadFn: PlatformUploadFn;
418
+ persistStorage: PersistStorage;
419
+ }
420
+ declare function resolveConfig(config: AntzChatConfig): ResolvedConfig;
421
+
422
+ declare const authApi: {
423
+ login(credentials: LoginCredentials): Promise<AuthResponse>;
424
+ register(payload: RegisterData): Promise<AuthResponse>;
425
+ refresh(refreshToken: string): Promise<AuthTokens>;
426
+ logout(refreshToken?: string): Promise<void>;
427
+ logoutAll(): Promise<void>;
428
+ getMe(): Promise<User>;
429
+ };
430
+
431
+ interface ListMessagesParams {
432
+ cursor?: string;
433
+ limit?: number;
434
+ direction?: 'before' | 'after';
435
+ }
436
+ interface SearchParams {
437
+ query: string;
438
+ conversationId?: string;
439
+ page?: number;
440
+ limit?: number;
441
+ }
442
+ interface SendData {
443
+ text?: string;
444
+ attachments?: SendMessagePayload['attachments'];
445
+ replyTo?: string;
446
+ tempId?: string;
447
+ isEncrypted?: boolean;
448
+ }
449
+ declare const messagesApi: {
450
+ list(conversationId: string, params?: ListMessagesParams): Promise<CursorPaginatedResponse<Message>>;
451
+ get(messageId: string): Promise<Message>;
452
+ send(conversationId: string, payload: SendData): Promise<Message>;
453
+ update(messageId: string, text: string): Promise<Message>;
454
+ delete(messageId: string): Promise<void>;
455
+ addReaction(messageId: string, emoji: string): Promise<Message>;
456
+ removeReaction(messageId: string, emoji: string): Promise<Message>;
457
+ star(messageId: string): Promise<void>;
458
+ unstar(messageId: string): Promise<void>;
459
+ getStarred(params?: {
460
+ page?: number;
461
+ limit?: number;
462
+ conversationId?: string;
463
+ }): Promise<PaginatedResponse<Message>>;
464
+ search(params: SearchParams): Promise<PaginatedResponse<Message>>;
465
+ markAsRead(conversationId: string, messageId?: string): Promise<void>;
466
+ pin(messageId: string): Promise<Message>;
467
+ unpin(messageId: string): Promise<Message>;
468
+ getPinned(conversationId: string): Promise<Message[]>;
469
+ };
470
+
471
+ declare function normalizeConversation(conv: any): Conversation;
472
+ interface CreateGroupData {
473
+ name: string;
474
+ description?: string;
475
+ icon?: string;
476
+ participantIds: string[];
477
+ }
478
+ interface CreateDirectData {
479
+ userId: string;
480
+ }
481
+ interface UpdateConversationData {
482
+ name?: string;
483
+ description?: string;
484
+ icon?: string;
485
+ }
486
+ declare const conversationsApi: {
487
+ list(params?: {
488
+ page?: number;
489
+ limit?: number;
490
+ }): Promise<PaginatedResponse<Conversation>>;
491
+ get(conversationId: string): Promise<Conversation>;
492
+ createGroup(payload: CreateGroupData): Promise<Conversation>;
493
+ createDirect(payload: CreateDirectData): Promise<Conversation>;
494
+ update(conversationId: string, payload: UpdateConversationData): Promise<Conversation>;
495
+ delete(conversationId: string): Promise<void>;
496
+ addParticipants(conversationId: string, userIds: string[]): Promise<Conversation>;
497
+ removeParticipant(conversationId: string, userId: string): Promise<Conversation>;
498
+ updateParticipantRole(conversationId: string, userId: string, role: "admin" | "member"): Promise<Conversation>;
499
+ mute(conversationId: string, mutedUntil?: string): Promise<void>;
500
+ unmute(conversationId: string): Promise<void>;
501
+ pin(conversationId: string): Promise<void>;
502
+ unpin(conversationId: string): Promise<void>;
503
+ leave(conversationId: string): Promise<void>;
504
+ getMembers(conversationId: string): Promise<User[]>;
505
+ searchUsers(query: string): Promise<User[]>;
506
+ };
507
+
508
+ declare const storageApi: {
509
+ requestPresignedUrl(payload: PresignedUrlRequest): Promise<PresignedUrlResponse>;
510
+ requestPresignedUrlBatch(files: PresignedUrlRequest[]): Promise<{
511
+ urls: PresignedUrlResponse[];
512
+ errors: Array<{
513
+ filename: string;
514
+ error: string;
515
+ }>;
516
+ }>;
517
+ confirmUpload(fileId: string): Promise<FileResponse>;
518
+ getFile(fileId: string): Promise<FileResponse>;
519
+ getFileUrl(fileId: string, expiresIn?: number): Promise<{
520
+ url: string;
521
+ expiresAt: string;
522
+ }>;
523
+ deleteFile(fileId: string): Promise<void>;
524
+ getConversationFiles(conversationId: string, params?: {
525
+ page?: number;
526
+ limit?: number;
527
+ type?: FileType;
528
+ }): Promise<PaginatedResponse<FileResponse>>;
529
+ getMyFiles(params?: {
530
+ page?: number;
531
+ limit?: number;
532
+ }): Promise<PaginatedResponse<FileResponse>>;
533
+ };
534
+ /**
535
+ * High-level batch upload.
536
+ * The actual binary transfer is delegated to platformUploadFn so this
537
+ * function is platform-agnostic (works on web and React Native).
538
+ */
539
+ declare function uploadBatch(files: UploadableFile[], platformUploadFn: PlatformUploadFn, conversationId?: string, onProgress?: (pct: number) => void): Promise<BatchUploadResult>;
540
+
541
+ /** Shared fields for every device registration. */
542
+ interface DeviceTokenBase {
543
+ /**
544
+ * Client-generated stable UUID for this device.
545
+ * Store this in localStorage / SecureStore / Keychain and reuse it on every
546
+ * app start so the same record is updated rather than duplicated.
547
+ */
548
+ deviceId: string;
549
+ platform: 'ios' | 'android' | 'web';
550
+ provider: 'expo' | 'fcm' | 'apns' | 'web-push';
551
+ userAgent?: string;
552
+ }
553
+ /** Mobile push registration (expo | fcm | apns). */
554
+ interface MobileDeviceToken extends DeviceTokenBase {
555
+ provider: 'expo' | 'fcm' | 'apns';
556
+ /** FCM registration token / APNs device token / Expo push token. */
557
+ token: string;
558
+ endpoint?: never;
559
+ p256dh?: never;
560
+ auth?: never;
561
+ }
562
+ /** Web push (VAPID) registration. */
563
+ interface WebPushDeviceToken extends DeviceTokenBase {
564
+ provider: 'web-push';
565
+ /** PushSubscription.endpoint */
566
+ endpoint: string;
567
+ /** base64url-encoded PushSubscription key 'p256dh' */
568
+ p256dh: string;
569
+ /** base64url-encoded PushSubscription key 'auth' */
570
+ auth: string;
571
+ token?: never;
572
+ }
573
+ type RegisterDeviceTokenPayload = MobileDeviceToken | WebPushDeviceToken;
574
+ declare const devicesApi: {
575
+ /**
576
+ * Register or update a device push token with the chat server.
577
+ *
578
+ * Upserts by `deviceId` — calling this multiple times with the same deviceId
579
+ * simply refreshes the token value (tokens can rotate silently on some platforms).
580
+ *
581
+ * The SDK never calls this automatically. The parent app or the `tokenProvider`
582
+ * option in `pushNotifications` config is responsible for calling it after
583
+ * obtaining the token from the OS / browser.
584
+ */
585
+ register(payload: RegisterDeviceTokenPayload): Promise<void>;
586
+ /**
587
+ * Remove a device token from the chat server.
588
+ * Call this on logout so the user stops receiving push notifications on this device.
589
+ */
590
+ remove(deviceId: string): Promise<void>;
591
+ };
592
+
593
+ type TokenStore = {
594
+ getAccessToken: () => string | null | undefined;
595
+ getRefreshToken: () => string | null | undefined;
596
+ setTokens: (tokens: AuthTokens) => void;
597
+ clearTokens: () => void;
598
+ };
599
+ declare function initApiClient(config: ResolvedConfig, tokenStore: TokenStore): AxiosInstance;
600
+ declare function setApiClientInstance(instance: AxiosInstance): void;
601
+ declare function getApiClient(): AxiosInstance;
602
+
603
+ type SocketStatus = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';
604
+ type StatusListener = (status: SocketStatus) => void;
605
+ declare function getSocket(): Socket;
606
+ /** Returns the socket if connected, null otherwise. Use this for fire-and-forget
607
+ * operations (markRead, typing) that should silently no-op when not yet connected. */
608
+ declare function tryGetSocket(): Socket | null;
609
+ declare function getSocketStatus(): SocketStatus;
610
+ declare function onSocketStatus(listener: StatusListener): () => void;
611
+ declare function connectSocket(config: ResolvedConfig, getToken: () => string | null | undefined): Promise<Socket>;
612
+ declare function disconnectSocket(): void;
613
+ declare function reconnectSocket(token: string): void;
614
+
615
+ declare const socketEmit: {
616
+ joinRoom(conversationId: string): void;
617
+ leaveRoom(conversationId: string): void;
618
+ sendMessage(payload: SendMessagePayload): Promise<unknown>;
619
+ updateMessage(messageId: string, text: string): Promise<unknown>;
620
+ deleteMessage(messageId: string): Promise<unknown>;
621
+ addReaction(messageId: string, emoji: string): Promise<unknown>;
622
+ removeReaction(messageId: string, emoji: string): Promise<unknown>;
623
+ pinMessage(messageId: string): Promise<unknown>;
624
+ unpinMessage(messageId: string): Promise<unknown>;
625
+ typing(conversationId: string, isTyping: boolean): void;
626
+ markRead(conversationId: string, messageId?: string): void;
627
+ getOnlineUsers(userIds: string[]): Promise<string[]>;
628
+ getTypingUsers(conversationId: string): Promise<unknown>;
629
+ };
630
+
631
+ interface AuthState {
632
+ user: User | null;
633
+ tokens: AuthTokens | null;
634
+ isAuthenticated: boolean;
635
+ isLoading: boolean;
636
+ isHydrated: boolean;
637
+ setAuth: (user: User, tokens: AuthTokens) => void;
638
+ setTokens: (tokens: AuthTokens) => void;
639
+ setUser: (user: User) => void;
640
+ logout: () => void;
641
+ setLoading: (loading: boolean) => void;
642
+ setHydrated: (hydrated: boolean) => void;
643
+ }
644
+ /**
645
+ * Creates a platform-specific auth store.
646
+ * Call once during SDK init with the platform's PersistStorage adapter.
647
+ * - Web: pass a localStorage adapter
648
+ * - RN: pass an AsyncStorage adapter
649
+ */
650
+ declare function createAuthStore(storage: PersistStorage): {
651
+ useAuthStore: zustand.UseBoundStore<Omit<zustand.StoreApi<AuthState>, "persist"> & {
652
+ persist: {
653
+ setOptions: (options: Partial<zustand_middleware.PersistOptions<AuthState, AuthState>>) => void;
654
+ clearStorage: () => void;
655
+ rehydrate: () => Promise<void> | void;
656
+ hasHydrated: () => boolean;
657
+ onHydrate: (fn: (state: AuthState) => void) => () => void;
658
+ onFinishHydration: (fn: (state: AuthState) => void) => () => void;
659
+ getOptions: () => Partial<zustand_middleware.PersistOptions<AuthState, AuthState>>;
660
+ };
661
+ }>;
662
+ authTokenStore: {
663
+ getAccessToken: () => string | undefined;
664
+ getRefreshToken: () => string | undefined;
665
+ setTokens: (tokens: AuthTokens) => void;
666
+ clearTokens: () => void;
667
+ };
668
+ };
669
+ /**
670
+ * Initialize the auth store singleton.
671
+ * Idempotent — subsequent calls with the same storage return the existing instance.
672
+ * This ensures tokens persisted in localStorage/AsyncStorage survive re-renders
673
+ * and React StrictMode double-invocations.
674
+ */
675
+ declare function initAuthStore(storage: PersistStorage): {
676
+ useAuthStore: zustand.UseBoundStore<Omit<zustand.StoreApi<AuthState>, "persist"> & {
677
+ persist: {
678
+ setOptions: (options: Partial<zustand_middleware.PersistOptions<AuthState, AuthState>>) => void;
679
+ clearStorage: () => void;
680
+ rehydrate: () => Promise<void> | void;
681
+ hasHydrated: () => boolean;
682
+ onHydrate: (fn: (state: AuthState) => void) => () => void;
683
+ onFinishHydration: (fn: (state: AuthState) => void) => () => void;
684
+ getOptions: () => Partial<zustand_middleware.PersistOptions<AuthState, AuthState>>;
685
+ };
686
+ }>;
687
+ authTokenStore: {
688
+ getAccessToken: () => string | undefined;
689
+ getRefreshToken: () => string | undefined;
690
+ setTokens: (tokens: AuthTokens) => void;
691
+ clearTokens: () => void;
692
+ };
693
+ };
694
+ declare function getAuthStore(): {
695
+ useAuthStore: zustand.UseBoundStore<Omit<zustand.StoreApi<AuthState>, "persist"> & {
696
+ persist: {
697
+ setOptions: (options: Partial<zustand_middleware.PersistOptions<AuthState, AuthState>>) => void;
698
+ clearStorage: () => void;
699
+ rehydrate: () => Promise<void> | void;
700
+ hasHydrated: () => boolean;
701
+ onHydrate: (fn: (state: AuthState) => void) => () => void;
702
+ onFinishHydration: (fn: (state: AuthState) => void) => () => void;
703
+ getOptions: () => Partial<zustand_middleware.PersistOptions<AuthState, AuthState>>;
704
+ };
705
+ }>;
706
+ authTokenStore: {
707
+ getAccessToken: () => string | undefined;
708
+ getRefreshToken: () => string | undefined;
709
+ setTokens: (tokens: AuthTokens) => void;
710
+ clearTokens: () => void;
711
+ };
712
+ };
713
+ /** Reset the singleton — only for tests / SDK teardown. */
714
+ declare function resetAuthStore(): void;
715
+
716
+ interface TypingUser {
717
+ userId: string;
718
+ displayName: string;
719
+ avatarUrl?: string;
720
+ }
721
+ interface ChatState {
722
+ activeConversationId: string | null;
723
+ pendingTarget: {
724
+ conversationId: string;
725
+ messageId: string;
726
+ } | null;
727
+ typingUsers: Record<string, TypingUser[]>;
728
+ onlineUsers: string[];
729
+ replyingTo: Message | null;
730
+ editingMessage: Message | null;
731
+ isSidebarOpen: boolean;
732
+ isGroupInfoOpen: boolean;
733
+ isStarredPanelOpen: boolean;
734
+ setActiveConversation: (id: string | null) => void;
735
+ setPendingTarget: (target: {
736
+ conversationId: string;
737
+ messageId: string;
738
+ } | null) => void;
739
+ addTypingUser: (conversationId: string, user: TypingUser) => void;
740
+ removeTypingUser: (conversationId: string, userId: string) => void;
741
+ setUserOnline: (userId: string) => void;
742
+ setUserOffline: (userId: string) => void;
743
+ setOnlineUsers: (userIds: string[]) => void;
744
+ setReplyingTo: (message: Message | null) => void;
745
+ setEditingMessage: (message: Message | null) => void;
746
+ toggleSidebar: () => void;
747
+ setSidebarOpen: (open: boolean) => void;
748
+ toggleGroupInfo: () => void;
749
+ setGroupInfoOpen: (open: boolean) => void;
750
+ toggleStarredPanel: () => void;
751
+ setStarredPanelOpen: (open: boolean) => void;
752
+ }
753
+ declare const useChatStore: zustand.UseBoundStore<zustand.StoreApi<ChatState>>;
754
+
755
+ interface ClientSocketHandle {
756
+ emit: typeof socketEmit;
757
+ on(event: string, handler: (...args: unknown[]) => void): void;
758
+ off(event: string, handler: (...args: unknown[]) => void): void;
759
+ }
760
+ /**
761
+ * Headless client for non-React consumers or direct programmatic use.
762
+ * Usage:
763
+ * const client = new AntzChatClient({ apiUrl, authToken, platformUploadFn, persistStorage })
764
+ * await client.connect()
765
+ */
766
+ declare class AntzChatClient {
767
+ private _config;
768
+ private _authStore;
769
+ readonly auth: {
770
+ login(credentials: LoginCredentials): Promise<AuthResponse>;
771
+ register(payload: RegisterData): Promise<AuthResponse>;
772
+ refresh(refreshToken: string): Promise<AuthTokens>;
773
+ logout(refreshToken?: string): Promise<void>;
774
+ logoutAll(): Promise<void>;
775
+ getMe(): Promise<User>;
776
+ };
777
+ readonly messages: {
778
+ list(conversationId: string, params?: ListMessagesParams): Promise<CursorPaginatedResponse<Message>>;
779
+ get(messageId: string): Promise<Message>;
780
+ send(conversationId: string, payload: SendData): Promise<Message>;
781
+ update(messageId: string, text: string): Promise<Message>;
782
+ delete(messageId: string): Promise<void>;
783
+ addReaction(messageId: string, emoji: string): Promise<Message>;
784
+ removeReaction(messageId: string, emoji: string): Promise<Message>;
785
+ star(messageId: string): Promise<void>;
786
+ unstar(messageId: string): Promise<void>;
787
+ getStarred(params?: {
788
+ page?: number;
789
+ limit?: number;
790
+ conversationId?: string;
791
+ }): Promise<PaginatedResponse<Message>>;
792
+ search(params: SearchParams): Promise<PaginatedResponse<Message>>;
793
+ markAsRead(conversationId: string, messageId?: string): Promise<void>;
794
+ pin(messageId: string): Promise<Message>;
795
+ unpin(messageId: string): Promise<Message>;
796
+ getPinned(conversationId: string): Promise<Message[]>;
797
+ };
798
+ readonly conversations: {
799
+ list(params?: {
800
+ page?: number;
801
+ limit?: number;
802
+ }): Promise<PaginatedResponse<Conversation>>;
803
+ get(conversationId: string): Promise<Conversation>;
804
+ createGroup(payload: CreateGroupData): Promise<Conversation>;
805
+ createDirect(payload: CreateDirectData): Promise<Conversation>;
806
+ update(conversationId: string, payload: UpdateConversationData): Promise<Conversation>;
807
+ delete(conversationId: string): Promise<void>;
808
+ addParticipants(conversationId: string, userIds: string[]): Promise<Conversation>;
809
+ removeParticipant(conversationId: string, userId: string): Promise<Conversation>;
810
+ updateParticipantRole(conversationId: string, userId: string, role: "admin" | "member"): Promise<Conversation>;
811
+ mute(conversationId: string, mutedUntil?: string): Promise<void>;
812
+ unmute(conversationId: string): Promise<void>;
813
+ pin(conversationId: string): Promise<void>;
814
+ unpin(conversationId: string): Promise<void>;
815
+ leave(conversationId: string): Promise<void>;
816
+ getMembers(conversationId: string): Promise<User[]>;
817
+ searchUsers(query: string): Promise<User[]>;
818
+ };
819
+ readonly storage: {
820
+ requestPresignedUrl(payload: PresignedUrlRequest): Promise<PresignedUrlResponse>;
821
+ requestPresignedUrlBatch(files: PresignedUrlRequest[]): Promise<{
822
+ urls: PresignedUrlResponse[];
823
+ errors: Array<{
824
+ filename: string;
825
+ error: string;
826
+ }>;
827
+ }>;
828
+ confirmUpload(fileId: string): Promise<FileResponse>;
829
+ getFile(fileId: string): Promise<FileResponse>;
830
+ getFileUrl(fileId: string, expiresIn?: number): Promise<{
831
+ url: string;
832
+ expiresAt: string;
833
+ }>;
834
+ deleteFile(fileId: string): Promise<void>;
835
+ getConversationFiles(conversationId: string, params?: {
836
+ page?: number;
837
+ limit?: number;
838
+ type?: FileType;
839
+ }): Promise<PaginatedResponse<FileResponse>>;
840
+ getMyFiles(params?: {
841
+ page?: number;
842
+ limit?: number;
843
+ }): Promise<PaginatedResponse<FileResponse>>;
844
+ };
845
+ readonly socket: ClientSocketHandle;
846
+ constructor(rawConfig: AntzChatConfig);
847
+ connect(): Promise<void>;
848
+ disconnect(): void;
849
+ uploadFiles(files: UploadableFile[], conversationId?: string): Promise<BatchUploadResult>;
850
+ }
851
+
852
+ export { AntzChatClient, type AntzChatConfig, type Attachment, type AuthResponse, type AuthTokens, type BatchUploadResult, type Conversation, type CreateDirectData, type CreateGroupData, type CursorPaginatedResponse, type EncryptedContent, type EncryptionKeyInfo, type EncryptionMode, type FileResponse, type FileSizeLimits, type FileType, type ListMessagesParams, type LoginCredentials, type Message, type MessageAckEvent, type MessageContent, type MessageDeletedEvent, type MessageDeliveredEvent, type MessageReaction, type MessageReplyReference, type MessageUpdatedEvent, type MessagesDeliveredEvent, type MobileDeviceToken, type NewMessageEvent, type OptimisticAttachment, type PaginatedResponse, type Participant, type PersistStorage, type PlatformUploadFn, type PresignedUrlRequest, type PresignedUrlResponse, type ReactionUpdatedEvent, type ReadReceiptEvent, type RegisterData, type RegisterDeviceTokenPayload, type ResolvedConfig, type ResolvedFileSizeLimits, type SearchParams, type SendData, type SendMessageAttachment, type SendMessagePayload, type SocketStatus, type StatusListener, type TokenStore, type TypingIndicatorEvent, type UpdateConversationData, type UploadConfig, type UploadProgress, type UploadableFile, type User, type UserStatusEvent, type WebPushDeviceToken, authApi, connectSocket, conversationsApi, createAuthStore, devicesApi, disconnectSocket, getApiClient, getAuthStore, getSocket, getSocketStatus, initApiClient, initAuthStore, messagesApi, normalizeConversation, onSocketStatus, reconnectSocket, resetAuthStore, resolveConfig, setApiClientInstance, socketEmit, storageApi, tryGetSocket, uploadBatch, useChatStore };