@antzsoft/chat-core 1.0.0 → 1.0.3

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.
package/dist/index.d.ts CHANGED
@@ -25,9 +25,12 @@ interface UploadableFile {
25
25
  }
26
26
  interface User {
27
27
  id: string;
28
+ externalId?: string;
28
29
  tenantId: string;
29
30
  email: string;
30
31
  username: string;
32
+ firstName?: string;
33
+ lastName?: string;
31
34
  displayName: string;
32
35
  avatarUrl?: string;
33
36
  phone?: string;
@@ -54,7 +57,9 @@ interface RegisterData {
54
57
  email: string;
55
58
  password: string;
56
59
  username: string;
57
- displayName: string;
60
+ firstName: string;
61
+ lastName: string;
62
+ displayName?: string;
58
63
  phone?: string;
59
64
  tenantId?: string;
60
65
  }
@@ -135,9 +140,14 @@ interface Participant {
135
140
  isActive?: boolean;
136
141
  user?: User;
137
142
  }
143
+ interface MessageConfig {
144
+ editWindowSeconds?: number;
145
+ deleteWindowSeconds?: number;
146
+ }
138
147
  interface ConversationSettings {
139
148
  onlyAdminsCanMessage?: boolean;
140
149
  onlyAdminsCanAddMembers?: boolean;
150
+ messageConfig?: MessageConfig;
141
151
  }
142
152
  interface Conversation {
143
153
  id: string;
@@ -163,6 +173,38 @@ interface Conversation {
163
173
  isEncryptionEnabled?: boolean;
164
174
  encryptionKey?: string;
165
175
  }
176
+ interface ConversationUnreadCount {
177
+ conversationId: string;
178
+ unreadCount: number;
179
+ }
180
+ interface UnreadSummary {
181
+ /** Total unread messages across all conversations */
182
+ totalUnread: number;
183
+ /** Per-conversation breakdown — only includes conversations with unread > 0 */
184
+ byConversation: ConversationUnreadCount[];
185
+ }
186
+ interface ConversationListParams {
187
+ page?: number;
188
+ limit?: number;
189
+ /** Filter by conversation type */
190
+ type?: ConversationType;
191
+ /** Only pinned (true) or unpinned (false) conversations */
192
+ isPinned?: boolean;
193
+ /** Only muted (true) or unmuted (false) conversations */
194
+ isMuted?: boolean;
195
+ /** Only conversations with unread messages */
196
+ hasUnread?: boolean;
197
+ /** Search by group name / description (text index) */
198
+ search?: string;
199
+ /** Filter by current user's role in the conversation */
200
+ role?: ParticipantRole;
201
+ /** Filter by whether the last message has attachments */
202
+ hasAttachments?: boolean;
203
+ /** Filter by last message attachment type */
204
+ attachmentType?: FileType;
205
+ /** Filter by notification setting */
206
+ notificationsEnabled?: boolean;
207
+ }
166
208
  interface PaginationMeta {
167
209
  total: number;
168
210
  page: number;
@@ -243,6 +285,10 @@ interface MessageDeletedEvent {
243
285
  messageId: string;
244
286
  conversationId: string;
245
287
  }
288
+ interface MessageDeletedForMeEvent {
289
+ messageId: string;
290
+ conversationId: string;
291
+ }
246
292
  interface ReactionUpdatedEvent {
247
293
  messageId: string;
248
294
  conversationId: string;
@@ -313,6 +359,37 @@ interface SendMessagePayload {
313
359
  encryptedContent?: EncryptedContent;
314
360
  isEncrypted?: boolean;
315
361
  }
362
+ interface QuietHours {
363
+ enabled: boolean;
364
+ /** HH:MM — e.g. "22:00" */
365
+ start: string;
366
+ /** HH:MM — e.g. "08:00" */
367
+ end: string;
368
+ /** IANA timezone — e.g. "Asia/Kolkata" */
369
+ timezone: string;
370
+ }
371
+ /**
372
+ * User notification preferences stored in chat_user_prefs.
373
+ * All fields are optional on update — only send what changed.
374
+ * Any future preference field is added here and to the server schema;
375
+ * no new collections or API endpoints needed.
376
+ */
377
+ interface UserPreferences {
378
+ /** Master switch — false disables all push notifications */
379
+ notificationsEnabled?: boolean;
380
+ /** Play sound with notifications */
381
+ soundEnabled?: boolean;
382
+ /** Show message text in notification body (false = show "New message" only) */
383
+ messagePreview?: boolean;
384
+ /** Notify when @mentioned in a group */
385
+ notifyOnMention?: boolean;
386
+ /** Notify when someone reacts to your message */
387
+ notifyOnReaction?: boolean;
388
+ /** Notify when added to a group */
389
+ notifyOnGroupInvite?: boolean;
390
+ /** Quiet hours window — no push delivered during this period */
391
+ quietHours?: QuietHours;
392
+ }
316
393
 
317
394
  interface FileSizeLimits {
318
395
  image?: number;
@@ -376,11 +453,38 @@ interface AntzChatConfig {
376
453
  * Not needed for builtin mode (chat server issues its own JWTs).
377
454
  */
378
455
  userId?: string;
456
+ /**
457
+ * Profile picture for non-builtin modes.
458
+ * Server fetches/decodes, hashes for dedup, uploads to chat storage on first use.
459
+ * Only sent once at init — not re-sent on every request.
460
+ * Client never needs to compute hashes; the server owns all dedup logic.
461
+ */
462
+ avatar?: {
463
+ /** Full URL the server can fetch (preferred — Antz/external/wso2 clients know their own file URLs) */
464
+ url?: string;
465
+ /** Raw base64 string (with or without data:... prefix) as fallback */
466
+ base64?: string;
467
+ };
379
468
  /** Required for multi-tenant backends. Sent as X-Tenant-ID header. */
380
469
  tenantId?: string;
381
470
  /** Must match server ENCRYPTION_MODE env var. Default: 'none' */
382
471
  encryptionMode?: 'none' | 'server';
383
472
  upload?: UploadConfig;
473
+ /**
474
+ * Number of messages fetched per page when loading chat history.
475
+ * Default: 40
476
+ */
477
+ messagePageSize?: number;
478
+ /**
479
+ * Number of starred messages fetched per page.
480
+ * Default: 30
481
+ */
482
+ starredMessagePageSize?: number;
483
+ /**
484
+ * Number of search results fetched per request.
485
+ * Default: 50
486
+ */
487
+ searchPageSize?: number;
384
488
  /**
385
489
  * Platform-specific binary upload implementation.
386
490
  * Required — each SDK (web, RN) provides its own.
@@ -402,10 +506,16 @@ interface ResolvedFileSizeLimits {
402
506
  interface ResolvedConfig {
403
507
  apiUrl: string;
404
508
  socketUrl: string;
509
+ socketOrigin: string;
510
+ socketPath: string;
405
511
  authToken?: string;
406
512
  authProvider?: () => Promise<string>;
407
513
  userId?: string;
408
514
  tenantId?: string;
515
+ avatar?: {
516
+ url?: string;
517
+ base64?: string;
518
+ };
409
519
  encryptionMode: 'none' | 'server';
410
520
  upload: {
411
521
  maxFileSizeMB: ResolvedFileSizeLimits;
@@ -416,6 +526,9 @@ interface ResolvedConfig {
416
526
  };
417
527
  platformUploadFn: PlatformUploadFn;
418
528
  persistStorage: PersistStorage;
529
+ messagePageSize: number;
530
+ starredMessagePageSize: number;
531
+ searchPageSize: number;
419
532
  }
420
533
  declare function resolveConfig(config: AntzChatConfig): ResolvedConfig;
421
534
 
@@ -426,6 +539,15 @@ declare const authApi: {
426
539
  logout(refreshToken?: string): Promise<void>;
427
540
  logoutAll(): Promise<void>;
428
541
  getMe(): Promise<User>;
542
+ uploadAvatar(file: File | Blob, mimeType?: string): Promise<{
543
+ avatarUrl: string;
544
+ }>;
545
+ syncAvatar(source: {
546
+ url?: string;
547
+ base64?: string;
548
+ }): Promise<{
549
+ avatarUrl: string;
550
+ }>;
429
551
  };
430
552
 
431
553
  interface ListMessagesParams {
@@ -452,6 +574,7 @@ declare const messagesApi: {
452
574
  send(conversationId: string, payload: SendData): Promise<Message>;
453
575
  update(messageId: string, text: string): Promise<Message>;
454
576
  delete(messageId: string): Promise<void>;
577
+ deleteForMe(messageId: string): Promise<void>;
455
578
  addReaction(messageId: string, emoji: string): Promise<Message>;
456
579
  removeReaction(messageId: string, emoji: string): Promise<Message>;
457
580
  star(messageId: string): Promise<void>;
@@ -462,6 +585,10 @@ declare const messagesApi: {
462
585
  conversationId?: string;
463
586
  }): Promise<PaginatedResponse<Message>>;
464
587
  search(params: SearchParams): Promise<PaginatedResponse<Message>>;
588
+ getLastRead(conversationId: string): Promise<{
589
+ lastReadMessageId: string | null;
590
+ lastReadAt: string | null;
591
+ }>;
465
592
  markAsRead(conversationId: string, messageId?: string): Promise<void>;
466
593
  pin(messageId: string): Promise<Message>;
467
594
  unpin(messageId: string): Promise<Message>;
@@ -484,10 +611,7 @@ interface UpdateConversationData {
484
611
  icon?: string;
485
612
  }
486
613
  declare const conversationsApi: {
487
- list(params?: {
488
- page?: number;
489
- limit?: number;
490
- }): Promise<PaginatedResponse<Conversation>>;
614
+ list(params?: ConversationListParams): Promise<PaginatedResponse<Conversation>>;
491
615
  get(conversationId: string): Promise<Conversation>;
492
616
  createGroup(payload: CreateGroupData): Promise<Conversation>;
493
617
  createDirect(payload: CreateDirectData): Promise<Conversation>;
@@ -502,7 +626,18 @@ declare const conversationsApi: {
502
626
  unpin(conversationId: string): Promise<void>;
503
627
  leave(conversationId: string): Promise<void>;
504
628
  getMembers(conversationId: string): Promise<User[]>;
505
- searchUsers(query: string): Promise<User[]>;
629
+ /**
630
+ * Get unread message count for a single conversation.
631
+ * Use this after app foreground or socket reconnect to refresh a specific count.
632
+ */
633
+ getUnreadCount(conversationId: string): Promise<ConversationUnreadCount>;
634
+ /**
635
+ * Get total unread count across all conversations + per-conversation breakdown.
636
+ * Use on app cold start, foreground resume, or after socket reconnect.
637
+ * The socket keeps counts live while connected — this is the source of truth
638
+ * when the socket was down.
639
+ */
640
+ getUnreadSummary(): Promise<UnreadSummary>;
506
641
  };
507
642
 
508
643
  declare const storageApi: {
@@ -590,6 +725,30 @@ declare const devicesApi: {
590
725
  remove(deviceId: string): Promise<void>;
591
726
  };
592
727
 
728
+ declare const usersApi: {
729
+ list(params?: {
730
+ query?: string;
731
+ page?: number;
732
+ limit?: number;
733
+ }): Promise<PaginatedResponse<User>>;
734
+ getById(userId: string): Promise<User>;
735
+ getLastSeen(userId: string): Promise<{
736
+ lastSeenAt: string | null;
737
+ }>;
738
+ /**
739
+ * Update notification preferences for the current user.
740
+ * Partial update — only send fields you want to change.
741
+ * A prefs record is automatically created with defaults when a device
742
+ * token is first registered, so this never fails with "not found".
743
+ */
744
+ updatePreferences(prefs: UserPreferences): Promise<User>;
745
+ /**
746
+ * Fetch current notification preferences for the current user.
747
+ * Returns null if no prefs record exists yet (all defaults apply).
748
+ */
749
+ getPreferences(): Promise<UserPreferences | null>;
750
+ };
751
+
593
752
  type TokenStore = {
594
753
  getAccessToken: () => string | null | undefined;
595
754
  getRefreshToken: () => string | null | undefined;
@@ -610,7 +769,16 @@ declare function getSocketStatus(): SocketStatus;
610
769
  declare function onSocketStatus(listener: StatusListener): () => void;
611
770
  declare function connectSocket(config: ResolvedConfig, getToken: () => string | null | undefined): Promise<Socket>;
612
771
  declare function disconnectSocket(): void;
613
- declare function reconnectSocket(token: string): void;
772
+ declare function reconnectSocket(token: string, userId?: string, tenantId?: string): void;
773
+ /**
774
+ * Updates the socket auth token from the stored getToken function and reconnects.
775
+ * Called by SocketProvider on connect_error to handle expired-token scenarios:
776
+ * 1. Token expired while disconnected → server rejects the reconnect handshake
777
+ * 2. authProvider returns a fresh token → we update socket auth and retry
778
+ *
779
+ * Returns true if the token was updated, false if no token source is available.
780
+ */
781
+ declare function refreshSocketAuth(): boolean;
614
782
 
615
783
  declare const socketEmit: {
616
784
  joinRoom(conversationId: string): void;
@@ -618,6 +786,7 @@ declare const socketEmit: {
618
786
  sendMessage(payload: SendMessagePayload): Promise<unknown>;
619
787
  updateMessage(messageId: string, text: string): Promise<unknown>;
620
788
  deleteMessage(messageId: string): Promise<unknown>;
789
+ deleteMessageForMe(messageId: string): Promise<unknown>;
621
790
  addReaction(messageId: string, emoji: string): Promise<unknown>;
622
791
  removeReaction(messageId: string, emoji: string): Promise<unknown>;
623
792
  pinMessage(messageId: string): Promise<unknown>;
@@ -718,6 +887,10 @@ interface TypingUser {
718
887
  displayName: string;
719
888
  avatarUrl?: string;
720
889
  }
890
+ interface LastReadEntry {
891
+ messageId: string;
892
+ readAt: string;
893
+ }
721
894
  interface ChatState {
722
895
  activeConversationId: string | null;
723
896
  pendingTarget: {
@@ -726,6 +899,10 @@ interface ChatState {
726
899
  } | null;
727
900
  typingUsers: Record<string, TypingUser[]>;
728
901
  onlineUsers: string[];
902
+ /** keyed by conversationId — current user's last read pointer per conversation */
903
+ lastRead: Record<string, LastReadEntry>;
904
+ /** keyed by userId — last seen timestamp for each user */
905
+ lastSeen: Record<string, string>;
729
906
  replyingTo: Message | null;
730
907
  editingMessage: Message | null;
731
908
  isSidebarOpen: boolean;
@@ -741,6 +918,8 @@ interface ChatState {
741
918
  setUserOnline: (userId: string) => void;
742
919
  setUserOffline: (userId: string) => void;
743
920
  setOnlineUsers: (userIds: string[]) => void;
921
+ setLastRead: (conversationId: string, messageId: string, readAt: string) => void;
922
+ setLastSeen: (userId: string, lastSeenAt: string) => void;
744
923
  setReplyingTo: (message: Message | null) => void;
745
924
  setEditingMessage: (message: Message | null) => void;
746
925
  toggleSidebar: () => void;
@@ -773,6 +952,15 @@ declare class AntzChatClient {
773
952
  logout(refreshToken?: string): Promise<void>;
774
953
  logoutAll(): Promise<void>;
775
954
  getMe(): Promise<User>;
955
+ uploadAvatar(file: File | Blob, mimeType?: string): Promise<{
956
+ avatarUrl: string;
957
+ }>;
958
+ syncAvatar(source: {
959
+ url?: string;
960
+ base64?: string;
961
+ }): Promise<{
962
+ avatarUrl: string;
963
+ }>;
776
964
  };
777
965
  readonly messages: {
778
966
  list(conversationId: string, params?: ListMessagesParams): Promise<CursorPaginatedResponse<Message>>;
@@ -780,6 +968,7 @@ declare class AntzChatClient {
780
968
  send(conversationId: string, payload: SendData): Promise<Message>;
781
969
  update(messageId: string, text: string): Promise<Message>;
782
970
  delete(messageId: string): Promise<void>;
971
+ deleteForMe(messageId: string): Promise<void>;
783
972
  addReaction(messageId: string, emoji: string): Promise<Message>;
784
973
  removeReaction(messageId: string, emoji: string): Promise<Message>;
785
974
  star(messageId: string): Promise<void>;
@@ -790,16 +979,17 @@ declare class AntzChatClient {
790
979
  conversationId?: string;
791
980
  }): Promise<PaginatedResponse<Message>>;
792
981
  search(params: SearchParams): Promise<PaginatedResponse<Message>>;
982
+ getLastRead(conversationId: string): Promise<{
983
+ lastReadMessageId: string | null;
984
+ lastReadAt: string | null;
985
+ }>;
793
986
  markAsRead(conversationId: string, messageId?: string): Promise<void>;
794
987
  pin(messageId: string): Promise<Message>;
795
988
  unpin(messageId: string): Promise<Message>;
796
989
  getPinned(conversationId: string): Promise<Message[]>;
797
990
  };
798
991
  readonly conversations: {
799
- list(params?: {
800
- page?: number;
801
- limit?: number;
802
- }): Promise<PaginatedResponse<Conversation>>;
992
+ list(params?: ConversationListParams): Promise<PaginatedResponse<Conversation>>;
803
993
  get(conversationId: string): Promise<Conversation>;
804
994
  createGroup(payload: CreateGroupData): Promise<Conversation>;
805
995
  createDirect(payload: CreateDirectData): Promise<Conversation>;
@@ -814,7 +1004,8 @@ declare class AntzChatClient {
814
1004
  unpin(conversationId: string): Promise<void>;
815
1005
  leave(conversationId: string): Promise<void>;
816
1006
  getMembers(conversationId: string): Promise<User[]>;
817
- searchUsers(query: string): Promise<User[]>;
1007
+ getUnreadCount(conversationId: string): Promise<ConversationUnreadCount>;
1008
+ getUnreadSummary(): Promise<UnreadSummary>;
818
1009
  };
819
1010
  readonly storage: {
820
1011
  requestPresignedUrl(payload: PresignedUrlRequest): Promise<PresignedUrlResponse>;
@@ -842,6 +1033,19 @@ declare class AntzChatClient {
842
1033
  limit?: number;
843
1034
  }): Promise<PaginatedResponse<FileResponse>>;
844
1035
  };
1036
+ readonly users: {
1037
+ list(params?: {
1038
+ query?: string;
1039
+ page?: number;
1040
+ limit?: number;
1041
+ }): Promise<PaginatedResponse<User>>;
1042
+ getById(userId: string): Promise<User>;
1043
+ getLastSeen(userId: string): Promise<{
1044
+ lastSeenAt: string | null;
1045
+ }>;
1046
+ updatePreferences(prefs: UserPreferences): Promise<User>;
1047
+ getPreferences(): Promise<UserPreferences | null>;
1048
+ };
845
1049
  readonly socket: ClientSocketHandle;
846
1050
  constructor(rawConfig: AntzChatConfig);
847
1051
  connect(): Promise<void>;
@@ -849,4 +1053,4 @@ declare class AntzChatClient {
849
1053
  uploadFiles(files: UploadableFile[], conversationId?: string): Promise<BatchUploadResult>;
850
1054
  }
851
1055
 
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 };
1056
+ export { AntzChatClient, type AntzChatConfig, type Attachment, type AuthResponse, type AuthTokens, type BatchUploadResult, type Conversation, type ConversationListParams, type ConversationUnreadCount, type CreateDirectData, type CreateGroupData, type CursorPaginatedResponse, type EncryptedContent, type EncryptionKeyInfo, type EncryptionMode, type FileResponse, type FileSizeLimits, type FileType, type LastReadEntry, type ListMessagesParams, type LoginCredentials, type Message, type MessageAckEvent, type MessageContent, type MessageDeletedEvent, type MessageDeletedForMeEvent, 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 QuietHours, 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 UnreadSummary, type UpdateConversationData, type UploadConfig, type UploadProgress, type UploadableFile, type User, type UserPreferences, type UserStatusEvent, type WebPushDeviceToken, authApi, connectSocket, conversationsApi, createAuthStore, devicesApi, disconnectSocket, getApiClient, getAuthStore, getSocket, getSocketStatus, initApiClient, initAuthStore, messagesApi, normalizeConversation, onSocketStatus, reconnectSocket, refreshSocketAuth, resetAuthStore, resolveConfig, setApiClientInstance, socketEmit, storageApi, tryGetSocket, uploadBatch, useChatStore, usersApi };