@antzsoft/chat-core 1.0.4 → 1.0.6

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/README.md CHANGED
@@ -614,6 +614,13 @@ class AntzChatClient {
614
614
  * to the configured platformUploadFn, and confirms each upload with the server.
615
615
  */
616
616
  uploadFiles(files: UploadableFile[], conversationId?: string): Promise<BatchUploadResult>;
617
+
618
+ /**
619
+ * Upload or replace the group icon (admin only).
620
+ * Internally calls uploadFiles() to upload the file, then sets the icon on the conversation.
621
+ * Same presigned URL pipeline as message attachments — platformUploadFn is handled automatically.
622
+ */
623
+ uploadIcon(conversationId: string, file: UploadableFile): Promise<Conversation>;
617
624
  }
618
625
  ```
619
626
 
@@ -773,6 +780,56 @@ await messagesApi.send('conv-abc', {
773
780
  const results = await messagesApi.search({ query: 'deployment', conversationId: 'conv-abc' });
774
781
  ```
775
782
 
783
+ #### Jump to first unread message
784
+
785
+ Use `direction: 'after'` with the user's `lastReadMessageId` as the cursor to fetch only the unread messages. This powers a scroll-to-first-unread experience with an "↑ Unread messages" divider.
786
+
787
+ ```typescript
788
+ import { messagesApi, useChatStore } from '@antzsoft/chat-core';
789
+
790
+ // 1. Get the last-read pointer and seed the store
791
+ const { lastReadMessageId, lastReadAt } = await messagesApi.getLastRead(conversationId);
792
+
793
+ if (lastReadMessageId && lastReadAt) {
794
+ useChatStore.getState().setLastRead(conversationId, lastReadMessageId, lastReadAt);
795
+
796
+ // 2. Fetch all messages AFTER the last-read message — these are unread
797
+ const { data: unreadMessages, meta } = await messagesApi.list(conversationId, {
798
+ cursor: lastReadMessageId,
799
+ direction: 'after',
800
+ limit: 50,
801
+ });
802
+
803
+ // unreadMessages[0] is the first unread — scroll the list to this item
804
+ // meta.hasMore = true means there are more than 50 unread messages
805
+ if (unreadMessages.length > 0) {
806
+ scrollToMessage(unreadMessages[0].id);
807
+ }
808
+ } else {
809
+ // No prior read state — load latest messages normally
810
+ const { data: messages } = await messagesApi.list(conversationId, { limit: 30 });
811
+ }
812
+ ```
813
+
814
+ Render the divider in your message list by checking `useChatStore.lastRead[conversationId]`:
815
+
816
+ ```typescript
817
+ const lastRead = useChatStore((s) => s.lastRead[conversationId]);
818
+
819
+ function MessageRow({ message, prevMessage }) {
820
+ // Insert divider between the last-read message and the next one
821
+ const isFirstUnread = lastRead && prevMessage?.id === lastRead.messageId;
822
+ return (
823
+ <>
824
+ {isFirstUnread && <UnreadDivider />}
825
+ <MessageBubble message={message} />
826
+ </>
827
+ );
828
+ }
829
+ ```
830
+
831
+ After the user reads the messages, call `socketEmit.markRead(conversationId)` (see [Read Receipts](#chat-store-usechatstore)) to update the server and broadcast the receipt to other participants.
832
+
776
833
  ---
777
834
 
778
835
  ### Conversations API (`conversationsApi`)
@@ -788,7 +845,7 @@ import { conversationsApi } from '@antzsoft/chat-core';
788
845
  | `createGroup` | `(data: CreateGroupData) => Promise<Conversation>` | Create a group conversation. |
789
846
  | `createDirect` | `(data: CreateDirectData) => Promise<Conversation>` | Start or retrieve a direct conversation with another user. |
790
847
  | `update` | `(conversationId: string, data: UpdateConversationData) => Promise<Conversation>` | Update group name or description. |
791
- | `uploadIcon` | `(conversationId: string, file: File \| { uri: string; name: string; type: string }) => Promise<Conversation>` | Upload or replace the group icon (admin only). Deletes previous icon from storage. Returns conversation with fresh `iconUrl`. |
848
+ | `uploadIcon` | `(conversationId: string, fileId: string) => Promise<Conversation>` | Set the group icon from an already-uploaded file (admin only). Call `client.uploadFiles()` first to get the `fileId`, then pass it here. Server copies `storageKey` into `conversation.iconMeta`, deletes the `chat_files` record, and returns the conversation with a fresh `iconUrl`. |
792
849
  | `delete` | `(conversationId: string) => Promise<void>` | Delete a conversation (admin only). |
793
850
  | `addParticipants` | `(conversationId: string, userIds: string[]) => Promise<Conversation>` | Add one or more participants. |
794
851
  | `removeParticipant` | `(conversationId: string, userId: string) => Promise<Conversation>` | Remove a participant. |
@@ -883,6 +940,37 @@ const group = await conversationsApi.createGroup({
883
940
  // Start a DM
884
941
  const dm = await conversationsApi.createDirect({ userId: 'user-b' });
885
942
 
943
+ // ── Group icon ────────────────────────────────────────────────────────────────
944
+ // Upload or replace the group icon (admin only).
945
+ // Uses the SAME presigned URL pipeline as message attachments — platformUploadFn
946
+ // is handled automatically from config, you never pass it explicitly.
947
+ // Always call AFTER createGroup — the group must exist first.
948
+
949
+ // Using AntzChatClient (headless) — one call, same as client.uploadFiles()
950
+ const updated = await client.uploadIcon(group.id, {
951
+ uri: 'blob:http://...', // URL.createObjectURL(file) on web, file URI on RN
952
+ name: 'icon.jpg',
953
+ type: 'image/jpeg',
954
+ size: file.size,
955
+ });
956
+ console.log(updated.iconUrl); // fresh signed URL, regenerated on every response
957
+
958
+ // What client.uploadIcon() does internally (same as attachment upload):
959
+ // 1. uploadFiles([file], conversationId)
960
+ // → POST /storage/presigned-url (creates temp chat_files record)
961
+ // → platformUploadFn uploads binary directly to S3/Azure/local
962
+ // → POST /storage/confirm/:fileId (marks chat_files active)
963
+ // 2. conversationsApi.uploadIcon(conversationId, fileId)
964
+ // → PUT /conversations/:id/icon { fileId }
965
+ // Server: validateAdmin() → copy storageKey into conversation.iconMeta
966
+ // → delete chat_files record (it was only a transport vehicle)
967
+ // → return conversation with fresh iconUrl
968
+
969
+ // iconUrl behaviour:
970
+ // - Never stored in DB — regenerated fresh from iconMeta.storageKey on every response
971
+ // - Previous icon deleted from storage automatically on replace
972
+ // - Non-admins get 403 Forbidden
973
+
886
974
  // Add members
887
975
  await conversationsApi.addParticipants(group.id, ['user-d', 'user-e']);
888
976
 
@@ -1644,7 +1732,7 @@ The socket listeners for `read_receipt`, `user_online`, and `user_offline` are w
1644
1732
 
1645
1733
  #### Seeding state on initial load
1646
1734
 
1647
- The store starts empty. On first render, fetch the initial values from the API and seed the store:
1735
+ The store starts empty. On first render, fetch the initial values from the API and seed the store. Once seeded, `lastReadMessageId` can also be used as a cursor to [jump to the first unread message](#jump-to-first-unread-message) using `messagesApi.list()` with `direction: 'after'`.
1648
1736
 
1649
1737
  ```typescript
1650
1738
  import { messagesApi, usersApi, useChatStore, type LastReadEntry } from '@antzsoft/chat-core';
package/dist/index.cjs CHANGED
@@ -516,22 +516,14 @@ var conversationsApi = {
516
516
  return data;
517
517
  },
518
518
  /**
519
- * Upload or replace the group icon (admin only).
520
- * Accepts a File (web) or { uri, name, type } object (React Native).
521
- * The server stores the image in its own storage, deletes the previous icon,
522
- * and returns a fresh signed iconUrl on every subsequent response.
519
+ * Set the group icon from an already-uploaded file (admin only).
520
+ * The fileId comes from uploadBatch() / client.uploadFiles() same as attachments.
521
+ * Server copies storageKey into conversation.iconMeta and deletes the chat_files record.
523
522
  */
524
- async uploadIcon(conversationId, file) {
525
- const formData = new FormData();
526
- if (file instanceof File) {
527
- formData.append("icon", file);
528
- } else {
529
- formData.append("icon", { uri: file.uri, name: file.name, type: file.type });
530
- }
523
+ async uploadIcon(conversationId, fileId) {
531
524
  const { data } = await getApiClient().put(
532
525
  `/conversations/${conversationId}/icon`,
533
- formData,
534
- { headers: { "Content-Type": "multipart/form-data" } }
526
+ { fileId }
535
527
  );
536
528
  return normalizeConversation(data);
537
529
  }
@@ -992,6 +984,12 @@ var AntzChatClient = class {
992
984
  uploadFiles(files, conversationId) {
993
985
  return uploadBatch(files, this._config.platformUploadFn, conversationId, this._config.upload.onProgress);
994
986
  }
987
+ async uploadIcon(conversationId, file) {
988
+ const result = await this.uploadFiles([file], conversationId);
989
+ const fileId = result.successful[0]?.id;
990
+ if (!fileId) throw new Error("Icon upload failed");
991
+ return conversationsApi.uploadIcon(conversationId, fileId);
992
+ }
995
993
  };
996
994
  // Annotate the CommonJS export names for ESM import in node:
997
995
  0 && (module.exports = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/stores/chat.store.ts","../src/index.ts","../src/config/types.ts","../src/api/client.ts","../src/api/auth.ts","../src/api/messages.ts","../src/api/conversations.ts","../src/api/storage.ts","../src/api/devices.ts","../src/api/users.ts","../src/socket/socket.ts","../src/socket/emitters.ts","../src/stores/auth.store.ts","../src/client-facade.ts"],"sourcesContent":["import { create } from 'zustand';\nimport type { Message } from '../types/index.js';\n\ninterface TypingUser {\n userId: string;\n displayName: string;\n avatarUrl?: string;\n}\n\nexport interface LastReadEntry {\n messageId: string;\n readAt: string;\n}\n\ninterface ChatState {\n activeConversationId: string | null;\n pendingTarget: { conversationId: string; messageId: string } | null;\n typingUsers: Record<string, TypingUser[]>;\n onlineUsers: string[];\n /** keyed by conversationId — current user's last read pointer per conversation */\n lastRead: Record<string, LastReadEntry>;\n /** keyed by userId — last seen timestamp for each user */\n lastSeen: Record<string, string>;\n replyingTo: Message | null;\n editingMessage: Message | null;\n isSidebarOpen: boolean;\n isGroupInfoOpen: boolean;\n isStarredPanelOpen: boolean;\n\n setActiveConversation: (id: string | null) => void;\n setPendingTarget: (target: { conversationId: string; messageId: string } | null) => void;\n addTypingUser: (conversationId: string, user: TypingUser) => void;\n removeTypingUser: (conversationId: string, userId: string) => void;\n setUserOnline: (userId: string) => void;\n setUserOffline: (userId: string) => void;\n setOnlineUsers: (userIds: string[]) => void;\n setLastRead: (conversationId: string, messageId: string, readAt: string) => void;\n setLastSeen: (userId: string, lastSeenAt: string) => void;\n setReplyingTo: (message: Message | null) => void;\n setEditingMessage: (message: Message | null) => void;\n toggleSidebar: () => void;\n setSidebarOpen: (open: boolean) => void;\n toggleGroupInfo: () => void;\n setGroupInfoOpen: (open: boolean) => void;\n toggleStarredPanel: () => void;\n setStarredPanelOpen: (open: boolean) => void;\n}\n\nexport const useChatStore = create<ChatState>((set) => ({\n activeConversationId: null,\n pendingTarget: null,\n typingUsers: {},\n onlineUsers: [],\n lastRead: {},\n lastSeen: {},\n replyingTo: null,\n editingMessage: null,\n isSidebarOpen: true,\n isGroupInfoOpen: false,\n isStarredPanelOpen: false,\n\n setActiveConversation: (id) =>\n set({ activeConversationId: id, replyingTo: null, editingMessage: null }),\n\n setPendingTarget: (target) => set({ pendingTarget: target }),\n\n addTypingUser: (conversationId, user) =>\n set((state) => {\n const existing = state.typingUsers[conversationId] ?? [];\n const deduped = existing.filter((u) => u.userId !== user.userId);\n return { typingUsers: { ...state.typingUsers, [conversationId]: [...deduped, user] } };\n }),\n\n removeTypingUser: (conversationId, userId) =>\n set((state) => ({\n typingUsers: {\n ...state.typingUsers,\n [conversationId]: (state.typingUsers[conversationId] ?? []).filter(\n (u) => u.userId !== userId,\n ),\n },\n })),\n\n setUserOnline: (userId) =>\n set((state) => ({\n onlineUsers: state.onlineUsers.includes(userId)\n ? state.onlineUsers\n : [...state.onlineUsers, userId],\n })),\n\n setUserOffline: (userId) =>\n set((state) => ({ onlineUsers: state.onlineUsers.filter((id) => id !== userId) })),\n\n setOnlineUsers: (userIds) => set({ onlineUsers: userIds }),\n\n setLastRead: (conversationId, messageId, readAt) =>\n set((state) => ({\n lastRead: { ...state.lastRead, [conversationId]: { messageId, readAt } },\n })),\n\n setLastSeen: (userId, lastSeenAt) =>\n set((state) => ({\n lastSeen: { ...state.lastSeen, [userId]: lastSeenAt },\n })),\n\n setReplyingTo: (message) => set({ replyingTo: message, editingMessage: null }),\n\n setEditingMessage: (message) => set({ editingMessage: message, replyingTo: null }),\n\n toggleSidebar: () => set((state) => ({ isSidebarOpen: !state.isSidebarOpen })),\n setSidebarOpen: (open) => set({ isSidebarOpen: open }),\n\n toggleGroupInfo: () => set((state) => ({ isGroupInfoOpen: !state.isGroupInfoOpen })),\n setGroupInfoOpen: (open) => set({ isGroupInfoOpen: open }),\n\n toggleStarredPanel: () => set((state) => ({ isStarredPanelOpen: !state.isStarredPanelOpen })),\n setStarredPanelOpen: (open) => set({ isStarredPanelOpen: open }),\n}));\n","// Config\nexport type {\n AntzChatConfig,\n ResolvedConfig,\n UploadConfig,\n FileSizeLimits,\n ResolvedFileSizeLimits,\n PlatformUploadFn,\n PersistStorage,\n} from './config/types.js';\nexport { resolveConfig } from './config/types.js';\n\n// Types\nexport type {\n UploadableFile,\n User,\n AuthTokens,\n AuthResponse,\n LoginCredentials,\n RegisterData,\n Message,\n MessageContent,\n MessageReplyReference,\n MessageReaction,\n Conversation,\n ConversationListParams,\n ConversationUnreadCount,\n UnreadSummary,\n Participant,\n Attachment,\n EncryptedContent,\n EncryptionKeyInfo,\n EncryptionMode,\n FileType,\n FileResponse,\n PresignedUrlRequest,\n PresignedUrlResponse,\n BatchUploadResult,\n UploadProgress,\n PaginatedResponse,\n CursorPaginatedResponse,\n SendMessagePayload,\n SendMessageAttachment,\n OptimisticAttachment,\n NewMessageEvent,\n MessageUpdatedEvent,\n MessageDeletedEvent,\n MessageDeletedForMeEvent,\n ReactionUpdatedEvent,\n TypingIndicatorEvent,\n UserStatusEvent,\n ReadReceiptEvent,\n MessageAckEvent,\n MessageDeliveredEvent,\n MessagesDeliveredEvent,\n} from './types/index.js';\n\n// API\nexport { authApi, messagesApi, conversationsApi, storageApi, uploadBatch, normalizeConversation, devicesApi, usersApi } from './api/index.js';\nexport type { RegisterDeviceTokenPayload, MobileDeviceToken, WebPushDeviceToken } from './api/index.js';\nexport type { CreateGroupData, CreateDirectData, UpdateConversationData, ListMessagesParams, SearchParams, SendData } from './api/index.js';\nexport type { UserPreferences, QuietHours } from './types/index.js';\nexport { initApiClient, setApiClientInstance, getApiClient } from './api/client.js';\nexport type { TokenStore } from './api/client.js';\n\n// Socket\nexport { connectSocket, disconnectSocket, reconnectSocket, refreshSocketAuth, getSocket, tryGetSocket, getSocketStatus, onSocketStatus } from './socket/socket.js';\nexport type { SocketStatus, StatusListener } from './socket/socket.js';\nexport { socketEmit } from './socket/emitters.js';\n\n// Stores\nexport { initAuthStore, getAuthStore, createAuthStore, resetAuthStore } from './stores/auth.store.js';\nexport { useChatStore } from './stores/chat.store.js';\nexport type { LastReadEntry } from './stores/chat.store.js';\n\n// Headless client\nexport { AntzChatClient } from './client-facade.js';\n","import type { FileType, UploadableFile, PresignedUrlResponse } from '../types/index.js';\n\nexport interface FileSizeLimits {\n image?: number;\n video?: number;\n audio?: number;\n document?: number;\n default?: number;\n}\n\n/**\n * Platform-provided function that performs the actual binary upload to a presigned URL.\n * - Web implementation: XMLHttpRequest with progress events\n * - RN implementation: fetch with FormData or direct body\n *\n * The core calls this — it never does the upload itself.\n */\nexport type PlatformUploadFn = (\n presigned: PresignedUrlResponse,\n file: UploadableFile,\n onProgress?: (pct: number) => void,\n) => Promise<void>;\n\n/**\n * Platform-provided persistent key-value storage for auth token persistence.\n * - Web: localStorage adapter\n * - RN: AsyncStorage adapter\n */\nexport interface PersistStorage {\n getItem(key: string): string | null | Promise<string | null>;\n setItem(key: string, value: string): void | Promise<void>;\n removeItem(key: string): void | Promise<void>;\n}\n\nexport interface UploadConfig {\n /**\n * Per-type file size limits in MB. Can also pass a single number for all types.\n * Defaults: image 5MB, video 25MB, audio 10MB, document 10MB.\n */\n maxFileSizeMB?: number | FileSizeLimits;\n\n /** Max files per message. Default: 10 */\n maxFilesPerMessage?: number;\n\n /** Which attachment types users can send. Default: all */\n allowedTypes?: Array<FileType>;\n\n /** Called when a file fails validation or upload */\n onUploadError?: (file: UploadableFile, error: Error) => void;\n\n /** Called with 0–100 aggregate progress during a batch upload */\n onProgress?: (progress: number) => void;\n}\n\nexport interface AntzChatConfig {\n /** REST API base URL — e.g. \"https://api.yourapp.com/api/v1\" */\n apiUrl: string;\n\n /**\n * WebSocket server URL. Defaults to apiUrl with /api/vN path stripped.\n * SDK connects to {socketUrl}/chat\n */\n socketUrl?: string;\n\n /** Static JWT. Use this OR authProvider, not both. */\n authToken?: string;\n\n /**\n * Dynamic token getter — called before requests and on socket reconnect.\n * Preferred when the host app manages its own auth lifecycle.\n */\n authProvider?: () => Promise<string>;\n\n /**\n * External user ID — required for non-builtin modes (antz / external / wso2).\n * Sent as x-user-id header on every request so the chat server can forward it\n * to the user-service for token validation.\n * Not needed for builtin mode (chat server issues its own JWTs).\n */\n userId?: string;\n\n /**\n * Profile picture for non-builtin modes.\n * Server fetches/decodes, hashes for dedup, uploads to chat storage on first use.\n * Only sent once at init — not re-sent on every request.\n * Client never needs to compute hashes; the server owns all dedup logic.\n */\n avatar?: {\n /** Full URL the server can fetch (preferred — Antz/external/wso2 clients know their own file URLs) */\n url?: string;\n /** Raw base64 string (with or without data:... prefix) as fallback */\n base64?: string;\n };\n\n /** Required for multi-tenant backends. Sent as X-Tenant-ID header. */\n tenantId?: string;\n\n /** Must match server ENCRYPTION_MODE env var. Default: 'none' */\n encryptionMode?: 'none' | 'server';\n\n upload?: UploadConfig;\n\n /**\n * Number of messages fetched per page when loading chat history.\n * Default: 40\n */\n messagePageSize?: number;\n\n /**\n * Number of starred messages fetched per page.\n * Default: 30\n */\n starredMessagePageSize?: number;\n\n /**\n * Number of search results fetched per request.\n * Default: 50\n */\n searchPageSize?: number;\n\n /**\n * Platform-specific binary upload implementation.\n * Required — each SDK (web, RN) provides its own.\n */\n platformUploadFn: PlatformUploadFn;\n\n /**\n * Platform-specific persistent storage for auth tokens.\n * Required — each SDK provides its own (localStorage / AsyncStorage).\n */\n persistStorage: PersistStorage;\n}\n\n// ─── Resolved (all defaults filled) ─────────────────────────────────────────\n\nexport interface ResolvedFileSizeLimits {\n image: number;\n video: number;\n audio: number;\n document: number;\n default: number;\n}\n\nexport interface ResolvedConfig {\n apiUrl: string;\n socketUrl: string;\n socketOrigin: string;\n socketPath: string;\n authToken?: string;\n authProvider?: () => Promise<string>;\n userId?: string;\n tenantId?: string;\n avatar?: { url?: string; base64?: string };\n encryptionMode: 'none' | 'server';\n upload: {\n maxFileSizeMB: ResolvedFileSizeLimits;\n maxFilesPerMessage: number;\n allowedTypes: FileType[];\n onUploadError?: (file: UploadableFile, error: Error) => void;\n onProgress?: (progress: number) => void;\n };\n platformUploadFn: PlatformUploadFn;\n persistStorage: PersistStorage;\n messagePageSize: number;\n starredMessagePageSize: number;\n searchPageSize: number;\n}\n\nexport function resolveConfig(config: AntzChatConfig): ResolvedConfig {\n const socketUrl =\n config.socketUrl ??\n config.apiUrl.replace(/\\/api\\/v\\d+\\/?$/, '').replace(/\\/$/, '');\n\n // Auto-derive Socket.IO engine path from the socketUrl pathname.\n // If the server is behind a reverse proxy with a path prefix (e.g. /chat-api),\n // that prefix is already embedded in socketUrl. We append /socket.io to it.\n // Examples:\n // socketUrl = https://host/chat-api → socketPath = /chat-api/socket.io\n // socketUrl = https://host → socketPath = /socket.io\n // No env var or manual config needed — SERVER_URL on the server and apiUrl\n // on the client carry the same prefix, so both sides derive the same path.\n // Derive Socket.IO engine path and origin separately.\n // Socket.IO uses the URL passed to io() as the namespace origin — anything\n // in the pathname of that URL becomes part of the namespace, not the engine path.\n // So we must pass only the bare origin (https://host) to io(), and use the\n // path option for the engine mount point.\n //\n // socketUrl = https://host/chat-api\n // → socketOrigin = https://host (passed to io())\n // → socketPath = /chat-api/socket.io (engine path option)\n // → namespace = /chat (hardcoded in connectSocket)\n //\n // socketUrl = https://host\n // → socketOrigin = https://host\n // → socketPath = /socket.io\n let socketOrigin = socketUrl;\n let socketPath = '/socket.io';\n try {\n const parsed = new URL(socketUrl);\n socketOrigin = parsed.origin; // strips pathname, search, hash\n const pathname = parsed.pathname.replace(/\\/$/, '');\n if (pathname && pathname !== '/') socketPath = `${pathname}/socket.io`;\n } catch {\n // invalid URL — fall back to defaults\n }\n\n const raw = config.upload?.maxFileSizeMB;\n let limits: ResolvedFileSizeLimits;\n\n if (typeof raw === 'number') {\n limits = { image: raw, video: raw, audio: raw, document: raw, default: raw };\n } else {\n const fallback = raw?.default ?? 25;\n limits = {\n image: raw?.image ?? 5,\n video: raw?.video ?? 25,\n audio: raw?.audio ?? 10,\n document: raw?.document ?? 10,\n default: fallback,\n };\n }\n\n return {\n apiUrl: config.apiUrl.replace(/\\/$/, ''),\n socketUrl,\n socketOrigin,\n socketPath,\n authToken: config.authToken,\n authProvider: config.authProvider,\n userId: config.userId,\n tenantId: config.tenantId,\n avatar: config.avatar,\n encryptionMode: config.encryptionMode ?? 'none',\n upload: {\n maxFileSizeMB: limits,\n maxFilesPerMessage: config.upload?.maxFilesPerMessage ?? 10,\n allowedTypes: config.upload?.allowedTypes ?? ['image', 'video', 'audio', 'document'],\n onUploadError: config.upload?.onUploadError,\n onProgress: config.upload?.onProgress,\n },\n platformUploadFn: config.platformUploadFn,\n persistStorage: config.persistStorage,\n messagePageSize: config.messagePageSize ?? 40,\n starredMessagePageSize: config.starredMessagePageSize ?? 30,\n searchPageSize: config.searchPageSize ?? 50,\n };\n}\n","import axios, {\n AxiosInstance,\n InternalAxiosRequestConfig,\n} from 'axios';\nimport type { ResolvedConfig } from '../config/types.js';\nimport type { AuthTokens } from '../types/index.js';\n\nexport type TokenStore = {\n getAccessToken: () => string | null | undefined;\n getRefreshToken: () => string | null | undefined;\n setTokens: (tokens: AuthTokens) => void;\n clearTokens: () => void;\n};\n\nlet _tokenStore: TokenStore | null = null;\nlet _config: ResolvedConfig | null = null;\n// Avatar headers are sent only on the first authenticated request after init.\n// The server hashes on receive and deduplicates — subsequent requests don't need them.\nlet _avatarSent = false;\n\nexport function initApiClient(config: ResolvedConfig, tokenStore: TokenStore): AxiosInstance {\n _config = config;\n _tokenStore = tokenStore;\n _avatarSent = false; // reset on re-init (new session / authToken change)\n\n const client = axios.create({\n baseURL: config.apiUrl,\n headers: { 'Content-Type': 'application/json' },\n });\n\n client.interceptors.request.use((req: InternalAxiosRequestConfig) => {\n const token = _tokenStore?.getAccessToken();\n if (token) req.headers['Authorization'] = `Bearer ${token}`;\n if (_config?.userId) req.headers['x-user-id'] = _config.userId;\n if (_config?.tenantId) req.headers['X-Tenant-ID'] = _config.tenantId;\n // Send avatar on the first request only — server hashes and deduplicates\n if (token && !_avatarSent && _config?.avatar) {\n if (_config.avatar.base64) req.headers['x-avatar-base64'] = _config.avatar.base64;\n else if (_config.avatar.url) req.headers['x-avatar-url'] = _config.avatar.url;\n _avatarSent = true;\n }\n return req;\n });\n\n let isRefreshing = false;\n let refreshQueue: Array<(token: string) => void> = [];\n\n client.interceptors.response.use(\n (response) => {\n if (\n response.data &&\n typeof response.data === 'object' &&\n 'success' in response.data &&\n 'data' in response.data\n ) {\n response.data = response.data.data;\n }\n return response;\n },\n async (error) => {\n const original = error.config as InternalAxiosRequestConfig & { _retry?: boolean };\n\n if (error.response?.status === 401 && !original._retry) {\n const refreshToken = _tokenStore?.getRefreshToken();\n if (!refreshToken) {\n _tokenStore?.clearTokens();\n return Promise.reject(error);\n }\n\n if (isRefreshing) {\n return new Promise((resolve) => {\n refreshQueue.push((newToken) => {\n original.headers['Authorization'] = `Bearer ${newToken}`;\n resolve(client(original));\n });\n });\n }\n\n original._retry = true;\n isRefreshing = true;\n\n try {\n const { data } = await axios.post<{ data: AuthTokens }>(\n `${_config!.apiUrl}/auth/refresh`,\n { refreshToken },\n );\n const tokens: AuthTokens = (data as any).data ?? data;\n _tokenStore?.setTokens(tokens);\n refreshQueue.forEach((cb) => cb(tokens.accessToken));\n refreshQueue = [];\n original.headers['Authorization'] = `Bearer ${tokens.accessToken}`;\n return client(original);\n } catch {\n _tokenStore?.clearTokens();\n return Promise.reject(error);\n } finally {\n isRefreshing = false;\n }\n }\n\n return Promise.reject(error);\n },\n );\n\n return client;\n}\n\nlet _instance: AxiosInstance | null = null;\n\nexport function setApiClientInstance(instance: AxiosInstance) {\n _instance = instance;\n}\n\nexport function getApiClient(): AxiosInstance {\n if (!_instance) throw new Error('[AntzChat] API client not initialized. Call initApiClient first.');\n return _instance;\n}\n","import type { AuthResponse, AuthTokens, LoginCredentials, RegisterData, User } from '../types/index.js';\nimport { getApiClient } from './client.js';\n\nexport const authApi = {\n async login(credentials: LoginCredentials): Promise<AuthResponse> {\n const { data } = await getApiClient().post<AuthResponse>('/auth/login', credentials);\n return data;\n },\n\n async register(payload: RegisterData): Promise<AuthResponse> {\n const { data } = await getApiClient().post<AuthResponse>('/auth/register', payload);\n return data;\n },\n\n async refresh(refreshToken: string): Promise<AuthTokens> {\n const { data } = await getApiClient().post<AuthTokens>('/auth/refresh', { refreshToken });\n return data;\n },\n\n async logout(refreshToken?: string): Promise<void> {\n await getApiClient().post('/auth/logout', refreshToken ? { refreshToken } : {});\n },\n\n async logoutAll(): Promise<void> {\n await getApiClient().post('/auth/logout-all');\n },\n\n async getMe(): Promise<User> {\n const { data } = await getApiClient().get<User>('/users/me');\n return data;\n },\n\n // Upload a new avatar file (builtin mode — multipart)\n async uploadAvatar(file: File | Blob, mimeType?: string): Promise<{ avatarUrl: string }> {\n const form = new FormData();\n form.append('avatar', file instanceof File ? file : new File([file], 'avatar.jpg', { type: mimeType ?? 'image/jpeg' }));\n const { data } = await getApiClient().put<{ avatarUrl: string }>('/users/me/avatar', form, {\n headers: { 'Content-Type': 'multipart/form-data' },\n });\n return data;\n },\n\n // Sync avatar from URL or base64 (non-builtin modes — or post-init update)\n async syncAvatar(source: { url?: string; base64?: string }): Promise<{ avatarUrl: string }> {\n const headers: Record<string, string> = {};\n if (source.base64) headers['x-avatar-base64'] = source.base64;\n else if (source.url) headers['x-avatar-url'] = source.url;\n const { data } = await getApiClient().post<{ avatarUrl: string }>('/users/me/avatar/sync', {}, { headers });\n return data;\n },\n};\n","import type {\n Message,\n CursorPaginatedResponse,\n PaginatedResponse,\n SendMessagePayload,\n} from '../types/index.js';\nimport { getApiClient } from './client.js';\n\nexport interface ListMessagesParams {\n cursor?: string;\n limit?: number;\n direction?: 'before' | 'after';\n}\n\nexport interface SearchParams {\n query: string;\n conversationId?: string;\n page?: number;\n limit?: number;\n}\n\nexport interface SendData {\n text?: string;\n attachments?: SendMessagePayload['attachments'];\n replyTo?: string;\n tempId?: string;\n isEncrypted?: boolean;\n}\n\nexport const messagesApi = {\n async list(conversationId: string, params: ListMessagesParams = {}): Promise<CursorPaginatedResponse<Message>> {\n const { cursor, direction, ...rest } = params;\n const serverParams: Record<string, unknown> = { ...rest };\n if (cursor) {\n serverParams[direction === 'after' ? 'after' : 'before'] = cursor;\n }\n const { data } = await getApiClient().get<CursorPaginatedResponse<Message>>(\n `/conversations/${conversationId}/messages`,\n { params: serverParams },\n );\n return data;\n },\n\n async get(messageId: string): Promise<Message> {\n const { data } = await getApiClient().get<Message>(`/messages/${messageId}`);\n return data;\n },\n\n async send(conversationId: string, payload: SendData): Promise<Message> {\n const { data } = await getApiClient().post<Message>(\n `/conversations/${conversationId}/messages`,\n payload,\n );\n return data;\n },\n\n async update(messageId: string, text: string): Promise<Message> {\n const { data } = await getApiClient().put<Message>(`/messages/${messageId}`, { text });\n return data;\n },\n\n async delete(messageId: string): Promise<void> {\n await getApiClient().delete(`/messages/${messageId}`);\n },\n\n async deleteForMe(messageId: string): Promise<void> {\n await getApiClient().delete(`/messages/${messageId}/for-me`);\n },\n\n async addReaction(messageId: string, emoji: string): Promise<Message> {\n const { data } = await getApiClient().post<Message>(`/messages/${messageId}/reactions`, { emoji });\n return data;\n },\n\n async removeReaction(messageId: string, emoji: string): Promise<Message> {\n const { data } = await getApiClient().delete<Message>(\n `/messages/${messageId}/reactions/${encodeURIComponent(emoji)}`,\n );\n return data;\n },\n\n async star(messageId: string): Promise<void> {\n await getApiClient().post(`/messages/${messageId}/star`);\n },\n\n async unstar(messageId: string): Promise<void> {\n await getApiClient().delete(`/messages/${messageId}/star`);\n },\n\n async getStarred(params: { page?: number; limit?: number; conversationId?: string } = {}): Promise<PaginatedResponse<Message>> {\n const { data } = await getApiClient().get<PaginatedResponse<Message>>('/messages/starred', { params });\n return data;\n },\n\n async search(params: SearchParams): Promise<PaginatedResponse<Message>> {\n const { data } = await getApiClient().get<PaginatedResponse<Message>>('/messages/search', { params });\n return data;\n },\n\n async getLastRead(conversationId: string): Promise<{ lastReadMessageId: string | null; lastReadAt: string | null }> {\n const { data } = await getApiClient().get<{ lastReadMessageId: string | null; lastReadAt: string | null }>(\n `/conversations/${conversationId}/read-receipt`,\n );\n return data;\n },\n\n async markAsRead(conversationId: string, messageId?: string): Promise<void> {\n await getApiClient().post(`/conversations/${conversationId}/read`, messageId ? { messageId } : {});\n },\n\n async pin(messageId: string): Promise<Message> {\n const { data } = await getApiClient().post<Message>(`/messages/${messageId}/pin`);\n return data;\n },\n\n async unpin(messageId: string): Promise<Message> {\n const { data } = await getApiClient().delete<Message>(`/messages/${messageId}/pin`);\n return data;\n },\n\n async getPinned(conversationId: string): Promise<Message[]> {\n const { data } = await getApiClient().get<Message[]>(`/conversations/${conversationId}/pinned-messages`);\n return data;\n },\n};\n","import type { Conversation, ConversationListParams, ConversationUnreadCount, Message, MessageStatus, Participant, PaginatedResponse, UnreadSummary, User } from '../types/index.js';\nimport { getApiClient } from './client.js';\n\nfunction normalizeParticipant(p: any): Participant {\n const hasUserDetails = p.displayName || p.username || p.avatarUrl;\n return {\n userId: p.userId,\n role: p.role,\n joinedAt: p.joinedAt,\n isActive: p.isActive,\n user: hasUserDetails\n ? {\n id: p.userId,\n tenantId: '',\n email: '',\n username: p.username ?? '',\n displayName: p.displayName ?? p.username ?? '',\n avatarUrl: p.avatarUrl,\n status: 'offline' as const,\n createdAt: p.joinedAt ?? '',\n updatedAt: p.joinedAt ?? '',\n }\n : (p.user as User | undefined),\n };\n}\n\nfunction normalizeLastMessage(lastMsg: any): Message | undefined {\n if (!lastMsg) return undefined;\n if (lastMsg.content !== undefined) return lastMsg as Message;\n return {\n id: lastMsg.messageId ?? '',\n tenantId: '',\n conversationId: '',\n senderId: '',\n content: {\n type: lastMsg.hasAttachments ? 'attachment' : 'text',\n text: lastMsg.contentPreview,\n },\n reactions: [],\n status: (lastMsg.status ?? 'sent') as MessageStatus,\n isEdited: false,\n sentAt: lastMsg.sentAt ?? '',\n createdAt: lastMsg.sentAt ?? '',\n };\n}\n\nexport function normalizeConversation(conv: any): Conversation {\n return {\n ...conv,\n id: conv.id ?? conv.conversationId,\n participants: (conv.participants ?? []).map(normalizeParticipant),\n lastMessage: normalizeLastMessage(conv.lastMessage),\n };\n}\n\nexport interface CreateGroupData {\n name: string;\n description?: string;\n participantIds: string[];\n}\n\nexport interface CreateDirectData {\n userId: string;\n}\n\nexport interface UpdateConversationData {\n name?: string;\n description?: string;\n}\n\nexport const conversationsApi = {\n async list(params: ConversationListParams = {}): Promise<PaginatedResponse<Conversation>> {\n const { data } = await getApiClient().get<PaginatedResponse<Conversation>>('/conversations', { params });\n return { ...data, data: data.data.map(normalizeConversation) };\n },\n\n async get(conversationId: string): Promise<Conversation> {\n const { data } = await getApiClient().get<Conversation>(`/conversations/${conversationId}`);\n return normalizeConversation(data);\n },\n\n async createGroup(payload: CreateGroupData): Promise<Conversation> {\n const { data } = await getApiClient().post<Conversation>('/conversations', payload);\n return normalizeConversation(data);\n },\n\n async createDirect(payload: CreateDirectData): Promise<Conversation> {\n const { data } = await getApiClient().post<Conversation>('/conversations/direct', payload);\n return normalizeConversation(data);\n },\n\n async update(conversationId: string, payload: UpdateConversationData): Promise<Conversation> {\n const { data } = await getApiClient().put<Conversation>(`/conversations/${conversationId}`, payload);\n return normalizeConversation(data);\n },\n\n async delete(conversationId: string): Promise<void> {\n await getApiClient().delete(`/conversations/${conversationId}`);\n },\n\n async addParticipants(conversationId: string, userIds: string[]): Promise<Conversation> {\n const { data } = await getApiClient().post<Conversation>(\n `/conversations/${conversationId}/participants`,\n { userIds },\n );\n return normalizeConversation(data);\n },\n\n async removeParticipant(conversationId: string, userId: string): Promise<Conversation> {\n const { data } = await getApiClient().delete<Conversation>(\n `/conversations/${conversationId}/participants/${userId}`,\n );\n return normalizeConversation(data);\n },\n\n async updateParticipantRole(conversationId: string, userId: string, role: 'admin' | 'member'): Promise<Conversation> {\n const { data } = await getApiClient().put<Conversation>(\n `/conversations/${conversationId}/participants/${userId}/role`,\n { role },\n );\n return normalizeConversation(data);\n },\n\n async mute(conversationId: string, mutedUntil?: string): Promise<void> {\n await getApiClient().post(`/conversations/${conversationId}/mute`, mutedUntil ? { mutedUntil } : {});\n },\n\n async unmute(conversationId: string): Promise<void> {\n await getApiClient().delete(`/conversations/${conversationId}/mute`);\n },\n\n async pin(conversationId: string): Promise<void> {\n await getApiClient().post(`/conversations/${conversationId}/pin`);\n },\n\n async unpin(conversationId: string): Promise<void> {\n await getApiClient().delete(`/conversations/${conversationId}/pin`);\n },\n\n async leave(conversationId: string): Promise<void> {\n await getApiClient().delete(`/conversations/${conversationId}/leave`);\n },\n\n async getMembers(conversationId: string): Promise<User[]> {\n const { data } = await getApiClient().get<User[]>(`/conversations/${conversationId}/participants`);\n return data;\n },\n\n /**\n * Get unread message count for a single conversation.\n * Use this after app foreground or socket reconnect to refresh a specific count.\n */\n async getUnreadCount(conversationId: string): Promise<ConversationUnreadCount> {\n const { data } = await getApiClient().get<ConversationUnreadCount>(\n `/conversations/${conversationId}/unread`,\n );\n return data;\n },\n\n /**\n * Get total unread count across all conversations + per-conversation breakdown.\n * Use on app cold start, foreground resume, or after socket reconnect.\n * The socket keeps counts live while connected — this is the source of truth\n * when the socket was down.\n */\n async getUnreadSummary(): Promise<UnreadSummary> {\n const { data } = await getApiClient().get<UnreadSummary>('/conversations/unread');\n return data;\n },\n\n /**\n * Upload or replace the group icon (admin only).\n * Accepts a File (web) or { uri, name, type } object (React Native).\n * The server stores the image in its own storage, deletes the previous icon,\n * and returns a fresh signed iconUrl on every subsequent response.\n */\n async uploadIcon(conversationId: string, file: File | { uri: string; name: string; type: string }): Promise<Conversation> {\n const formData = new FormData();\n if (file instanceof File) {\n formData.append('icon', file);\n } else {\n formData.append('icon', { uri: file.uri, name: file.name, type: file.type } as any);\n }\n const { data } = await getApiClient().put<Conversation>(\n `/conversations/${conversationId}/icon`,\n formData,\n { headers: { 'Content-Type': 'multipart/form-data' } },\n );\n return normalizeConversation(data);\n },\n\n};\n","import type {\n BatchUploadResult,\n FileResponse,\n PaginatedResponse,\n PresignedUrlRequest,\n PresignedUrlResponse,\n FileType,\n UploadableFile,\n} from '../types/index.js';\nimport type { PlatformUploadFn } from '../config/types.js';\nimport { getApiClient } from './client.js';\n\nexport const storageApi = {\n async requestPresignedUrl(payload: PresignedUrlRequest): Promise<PresignedUrlResponse> {\n const { data } = await getApiClient().post<PresignedUrlResponse>('/storage/presigned-url', payload);\n return data;\n },\n\n async requestPresignedUrlBatch(files: PresignedUrlRequest[]): Promise<{\n urls: PresignedUrlResponse[];\n errors: Array<{ filename: string; error: string }>;\n }> {\n const { data } = await getApiClient().post('/storage/presigned-url/batch', { files });\n return data;\n },\n\n async confirmUpload(fileId: string): Promise<FileResponse> {\n const { data } = await getApiClient().post<FileResponse>(`/storage/confirm/${fileId}`);\n return data;\n },\n\n async getFile(fileId: string): Promise<FileResponse> {\n const { data } = await getApiClient().get<FileResponse>(`/storage/files/${fileId}`);\n return data;\n },\n\n async getFileUrl(fileId: string, expiresIn?: number): Promise<{ url: string; expiresAt: string }> {\n const { data } = await getApiClient().get(`/storage/files/${fileId}/url`, {\n params: expiresIn ? { expiresIn } : {},\n });\n return data;\n },\n\n async deleteFile(fileId: string): Promise<void> {\n await getApiClient().delete(`/storage/files/${fileId}`);\n },\n\n async getConversationFiles(\n conversationId: string,\n params: { page?: number; limit?: number; type?: FileType } = {},\n ): Promise<PaginatedResponse<FileResponse>> {\n const { data } = await getApiClient().get(\n `/storage/conversations/${conversationId}/files`,\n { params },\n );\n return data;\n },\n\n async getMyFiles(params: { page?: number; limit?: number } = {}): Promise<PaginatedResponse<FileResponse>> {\n const { data } = await getApiClient().get('/storage/my-files', { params });\n return data;\n },\n};\n\n/**\n * High-level batch upload.\n * The actual binary transfer is delegated to platformUploadFn so this\n * function is platform-agnostic (works on web and React Native).\n */\nexport async function uploadBatch(\n files: UploadableFile[],\n platformUploadFn: PlatformUploadFn,\n conversationId?: string,\n onProgress?: (pct: number) => void,\n): Promise<BatchUploadResult> {\n const requests: PresignedUrlRequest[] = files.map((f) => ({\n filename: f.name,\n mimeType: f.type,\n size: f.size,\n conversationId,\n }));\n\n const { urls, errors: requestErrors } = await storageApi.requestPresignedUrlBatch(requests);\n\n const progressMap: Record<number, number> = {};\n const reportProgress = () => {\n if (!onProgress) return;\n const vals = Object.values(progressMap);\n const avg = vals.reduce((s, v) => s + v, 0) / Math.max(vals.length, 1);\n onProgress(Math.round(avg));\n };\n\n const successful: FileResponse[] = [];\n const failed: Array<{ filename: string; error: string }> = [...requestErrors];\n\n await Promise.all(\n urls.map(async (presigned, idx) => {\n const file = files[idx];\n progressMap[idx] = 0;\n try {\n await platformUploadFn(presigned, file, (pct) => {\n progressMap[idx] = Math.round(pct * 0.9);\n reportProgress();\n });\n\n const result = await storageApi.confirmUpload(presigned.fileId);\n progressMap[idx] = 100;\n reportProgress();\n successful.push(result);\n } catch (err) {\n failed.push({ filename: file.name, error: (err as Error).message });\n }\n }),\n );\n\n return { successful, failed };\n}\n","import { getApiClient } from './client.js';\n\n// ─── Types ─────────────────────────────────────────────────────────────────\n\n/** Shared fields for every device registration. */\ninterface DeviceTokenBase {\n /**\n * Client-generated stable UUID for this device.\n * Store this in localStorage / SecureStore / Keychain and reuse it on every\n * app start so the same record is updated rather than duplicated.\n */\n deviceId: string;\n platform: 'ios' | 'android' | 'web';\n provider: 'expo' | 'fcm' | 'apns' | 'web-push';\n userAgent?: string;\n}\n\n/** Mobile push registration (expo | fcm | apns). */\nexport interface MobileDeviceToken extends DeviceTokenBase {\n provider: 'expo' | 'fcm' | 'apns';\n /** FCM registration token / APNs device token / Expo push token. */\n token: string;\n endpoint?: never;\n p256dh?: never;\n auth?: never;\n}\n\n/** Web push (VAPID) registration. */\nexport interface WebPushDeviceToken extends DeviceTokenBase {\n provider: 'web-push';\n /** PushSubscription.endpoint */\n endpoint: string;\n /** base64url-encoded PushSubscription key 'p256dh' */\n p256dh: string;\n /** base64url-encoded PushSubscription key 'auth' */\n auth: string;\n token?: never;\n}\n\nexport type RegisterDeviceTokenPayload = MobileDeviceToken | WebPushDeviceToken;\n\n// ─── API ───────────────────────────────────────────────────────────────────\n\nexport const devicesApi = {\n /**\n * Register or update a device push token with the chat server.\n *\n * Upserts by `deviceId` — calling this multiple times with the same deviceId\n * simply refreshes the token value (tokens can rotate silently on some platforms).\n *\n * The SDK never calls this automatically. The parent app or the `tokenProvider`\n * option in `pushNotifications` config is responsible for calling it after\n * obtaining the token from the OS / browser.\n */\n async register(payload: RegisterDeviceTokenPayload): Promise<void> {\n await getApiClient().post('/users/me/devices', payload);\n },\n\n /**\n * Remove a device token from the chat server.\n * Call this on logout so the user stops receiving push notifications on this device.\n */\n async remove(deviceId: string): Promise<void> {\n await getApiClient().delete(`/users/me/devices/${deviceId}`);\n },\n};\n","import type { PaginatedResponse, User, UserPreferences } from '../types/index.js';\nimport { getApiClient } from './client.js';\n\nexport const usersApi = {\n async list(params: { query?: string; page?: number; limit?: number } = {}): Promise<PaginatedResponse<User>> {\n const { data } = await getApiClient().get<PaginatedResponse<User>>('/users', { params });\n return data;\n },\n\n async getById(userId: string): Promise<User> {\n const { data } = await getApiClient().get<User>(`/users/${userId}`);\n return data;\n },\n\n async getLastSeen(userId: string): Promise<{ lastSeenAt: string | null }> {\n const { data } = await getApiClient().get<User>(`/users/${userId}`);\n return { lastSeenAt: data.lastSeenAt ?? null };\n },\n\n /**\n * Update notification preferences for the current user.\n * Partial update — only send fields you want to change.\n * A prefs record is automatically created with defaults when a device\n * token is first registered, so this never fails with \"not found\".\n */\n async updatePreferences(prefs: UserPreferences): Promise<User> {\n const { data } = await getApiClient().put<User>('/users/me/preferences', prefs);\n return data;\n },\n\n /**\n * Fetch current notification preferences for the current user.\n * Returns null if no prefs record exists yet (all defaults apply).\n */\n async getPreferences(): Promise<UserPreferences | null> {\n try {\n const { data } = await getApiClient().get<UserPreferences>('/users/me/preferences');\n return data;\n } catch {\n return null;\n }\n },\n};\n","import { io, Socket } from 'socket.io-client';\nimport type { ResolvedConfig } from '../config/types.js';\nimport type { ReadReceiptEvent, UserStatusEvent } from '../types/index.js';\n\nexport type SocketStatus = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';\nexport type StatusListener = (status: SocketStatus) => void;\n\nlet _socket: Socket | null = null;\nlet _status: SocketStatus = 'disconnected';\nconst _statusListeners = new Set<StatusListener>();\n\n// Stored so SocketProvider can call refreshAndReconnect() without re-passing config\nlet _getToken: (() => string | null | undefined) | null = null;\nlet _userId: string | undefined;\nlet _tenantId: string | undefined;\n\nfunction setStatus(s: SocketStatus) {\n _status = s;\n _statusListeners.forEach(l => l(s));\n}\n\nexport function getSocket(): Socket {\n if (!_socket) throw new Error('[AntzChat] Socket not initialized. Call connectSocket first.');\n return _socket;\n}\n\n/** Returns the socket if connected, null otherwise. Use this for fire-and-forget\n * operations (markRead, typing) that should silently no-op when not yet connected. */\nexport function tryGetSocket(): Socket | null {\n return _socket?.connected ? _socket : null;\n}\n\nexport function getSocketStatus(): SocketStatus {\n return _status;\n}\n\nexport function onSocketStatus(listener: StatusListener): () => void {\n _statusListeners.add(listener);\n return () => _statusListeners.delete(listener);\n}\n\nexport async function connectSocket(\n config: ResolvedConfig,\n getToken: () => string | null | undefined,\n): Promise<Socket> {\n // Also guard against overwriting a socket that's mid-handshake (connected=false, disconnected=false).\n // Without this, SocketProvider mounting while AntzChatClient.connect() is still handshaking\n // creates a second io() instance, orphans the first socket's listeners, and drops the connection.\n if (_socket && !_socket.disconnected) return _socket;\n\n // Persist so refreshAndReconnect can update auth without re-passing these\n _getToken = getToken;\n _userId = config.userId;\n _tenantId = config.tenantId;\n\n const token = getToken();\n\n // Pass only the origin to io() — Socket.IO treats the URL pathname as the\n // namespace, so /chat-api in socketUrl would become /chat-api/chat namespace\n // instead of /chat. The engine path prefix is handled by the path option.\n _socket = io(`${config.socketOrigin}/chat`, {\n auth: {\n token: token ? `Bearer ${token}` : '',\n ...(config.userId && { userId: config.userId }),\n ...(config.tenantId && { tenantId: config.tenantId }),\n ...(config.avatar?.url && { avatarUrl: config.avatar.url }),\n ...(config.avatar?.base64 && { avatarBase64: config.avatar.base64 }),\n },\n // path must match SOCKET_IO_PATH on the server (default '/socket.io').\n // Set socketPath in SDK config when the server is behind a reverse proxy\n // that adds a path prefix (e.g. '/chat-api/socket.io' for UAT).\n path: config.socketPath,\n transports: ['websocket', 'polling'],\n reconnection: true,\n reconnectionAttempts: 10,\n reconnectionDelay: 1000,\n reconnectionDelayMax: 5000,\n autoConnect: true,\n });\n\n setStatus('connecting');\n\n _socket.on('connect', () => setStatus('connected'));\n _socket.on('disconnect', () => setStatus('disconnected'));\n _socket.on('connect_error', (err) => {\n console.error('[AntzChat] Socket connect_error:', err?.message, (err as any)?.data);\n setStatus('error');\n });\n _socket.on('reconnecting', () => setStatus('reconnecting'));\n _socket.on('reconnect', () => setStatus('connected'));\n\n // Lazily import store to avoid circular dependency at module load time\n _socket.on('read_receipt', (event: ReadReceiptEvent) => {\n import('../stores/chat.store.js').then(({ useChatStore }) => {\n useChatStore.getState().setLastRead(event.conversationId, event.messageId, event.readAt);\n });\n });\n\n _socket.on('user_online', (event: UserStatusEvent) => {\n import('../stores/chat.store.js').then(({ useChatStore }) => {\n const store = useChatStore.getState();\n store.setUserOnline(event.userId);\n });\n });\n\n _socket.on('user_offline', (event: UserStatusEvent) => {\n import('../stores/chat.store.js').then(({ useChatStore }) => {\n const store = useChatStore.getState();\n store.setUserOffline(event.userId);\n if (event.lastSeenAt) store.setLastSeen(event.userId, event.lastSeenAt);\n });\n });\n\n return _socket;\n}\n\nexport function disconnectSocket() {\n if (_socket) {\n _socket.disconnect();\n _socket = null;\n setStatus('disconnected');\n }\n _getToken = null;\n _userId = undefined;\n _tenantId = undefined;\n}\n\nexport function reconnectSocket(token: string, userId?: string, tenantId?: string) {\n if (_socket) {\n _socket.auth = {\n token: `Bearer ${token}`,\n ...(userId && { userId }),\n ...(tenantId && { tenantId }),\n };\n _socket.connect();\n }\n}\n\n/**\n * Updates the socket auth token from the stored getToken function and reconnects.\n * Called by SocketProvider on connect_error to handle expired-token scenarios:\n * 1. Token expired while disconnected → server rejects the reconnect handshake\n * 2. authProvider returns a fresh token → we update socket auth and retry\n *\n * Returns true if the token was updated, false if no token source is available.\n */\nexport function refreshSocketAuth(): boolean {\n if (!_socket || !_getToken) return false;\n const fresh = _getToken();\n if (!fresh) return false;\n _socket.auth = {\n token: `Bearer ${fresh}`,\n ...(_userId && { userId: _userId }),\n ...(_tenantId && { tenantId: _tenantId }),\n };\n return true;\n}\n","import type { SendMessagePayload } from '../types/index.js';\nimport { getSocket, tryGetSocket } from './socket.js';\n\nconst ACK_TIMEOUT = 5000;\n\n// withAck: for operations that need a response (send message, reactions, etc.)\n// Returns a rejected promise if socket not connected — callers should handle this.\nfunction withAck<T>(event: string, payload: unknown): Promise<T> {\n const socket = tryGetSocket();\n if (!socket) return Promise.reject(new Error(`[AntzChat] Socket not connected (event: ${event})`));\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`Socket ack timeout: ${event}`)), ACK_TIMEOUT);\n socket.emit(event, payload, (response: T) => {\n clearTimeout(timer);\n resolve(response);\n });\n });\n}\n\n// fireAndForget: for operations where missing a send is acceptable\n// (mark read, typing indicators) — silently no-ops when not connected.\nfunction fireAndForget(event: string, payload: unknown): void {\n const socket = tryGetSocket();\n if (!socket) return;\n socket.emit(event, payload);\n}\n\nexport const socketEmit = {\n joinRoom(conversationId: string) {\n fireAndForget('join_room', { conversationId });\n },\n\n leaveRoom(conversationId: string) {\n fireAndForget('leave_room', { conversationId });\n },\n\n sendMessage(payload: SendMessagePayload): Promise<unknown> {\n return withAck('send_message', payload);\n },\n\n updateMessage(messageId: string, text: string): Promise<unknown> {\n return withAck('update_message', { messageId, text });\n },\n\n deleteMessage(messageId: string): Promise<unknown> {\n return withAck('delete_message', { messageId });\n },\n\n deleteMessageForMe(messageId: string): Promise<unknown> {\n return withAck('delete_message_for_me', { messageId });\n },\n\n addReaction(messageId: string, emoji: string): Promise<unknown> {\n return withAck('add_reaction', { messageId, emoji });\n },\n\n removeReaction(messageId: string, emoji: string): Promise<unknown> {\n return withAck('remove_reaction', { messageId, emoji });\n },\n\n pinMessage(messageId: string): Promise<unknown> {\n return withAck('pin_message', { messageId });\n },\n\n unpinMessage(messageId: string): Promise<unknown> {\n return withAck('unpin_message', { messageId });\n },\n\n // markRead and typing are best-effort — silently dropped if socket not ready\n typing(conversationId: string, isTyping: boolean) {\n fireAndForget('typing', { conversationId, isTyping });\n },\n\n markRead(conversationId: string, messageId?: string) {\n fireAndForget('mark_read', { conversationId, ...(messageId ? { messageId } : {}) });\n },\n\n getOnlineUsers(userIds: string[]): Promise<string[]> {\n const socket = tryGetSocket();\n if (!socket) return Promise.resolve([]);\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error('get_online_users timeout')), ACK_TIMEOUT);\n socket.emit('get_online_users', { userIds }, (response: unknown) => {\n clearTimeout(timer);\n if (response && typeof response === 'object' && 'onlineStatus' in (response as object)) {\n const status = (response as { onlineStatus: Record<string, boolean> }).onlineStatus;\n resolve(Object.entries(status).filter(([, v]) => v).map(([k]) => k));\n } else if (Array.isArray(response)) {\n resolve(response as string[]);\n } else {\n resolve([]);\n }\n });\n });\n },\n\n getTypingUsers(conversationId: string): Promise<unknown> {\n return withAck('get_typing_users', { conversationId });\n },\n};\n","import { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\nimport type { AuthTokens, User } from '../types/index.js';\nimport type { PersistStorage } from '../config/types.js';\n\ninterface AuthState {\n user: User | null;\n tokens: AuthTokens | null;\n isAuthenticated: boolean;\n isLoading: boolean;\n isHydrated: boolean;\n\n setAuth: (user: User, tokens: AuthTokens) => void;\n setTokens: (tokens: AuthTokens) => void;\n setUser: (user: User) => void;\n logout: () => void;\n setLoading: (loading: boolean) => void;\n setHydrated: (hydrated: boolean) => void;\n}\n\n/**\n * Creates a platform-specific auth store.\n * Call once during SDK init with the platform's PersistStorage adapter.\n * - Web: pass a localStorage adapter\n * - RN: pass an AsyncStorage adapter\n */\nexport function createAuthStore(storage: PersistStorage) {\n if (!storage) throw new Error('[AntzChat] createAuthStore requires a valid PersistStorage — received undefined. Make sure the SDK config is fully resolved before initializing the store.');\n // Use a ref object so the onRehydrateStorage closure can call store.setState\n // without hitting a temporal dead zone. On web, localStorage is synchronous\n // and onRehydrateStorage fires during create() before `store` is assigned.\n const ref: { store: any } = { store: null };\n\n const store = create<AuthState>()(\n persist(\n (set) => ({\n user: null,\n tokens: null,\n isAuthenticated: false,\n isLoading: false,\n isHydrated: false,\n\n setAuth: (user, tokens) =>\n set({ user, tokens, isAuthenticated: true, isLoading: false }),\n\n setTokens: (tokens) => set({ tokens }),\n\n setUser: (user) => set({ user }),\n\n logout: () =>\n set({ user: null, tokens: null, isAuthenticated: false, isLoading: false }),\n\n setLoading: (isLoading) => set({ isLoading }),\n\n setHydrated: (isHydrated) => set({ isHydrated }),\n }),\n {\n name: 'antz-chat-auth',\n storage: {\n getItem: (name) => {\n const result = storage.getItem(name);\n if (result instanceof Promise) {\n return result.then((str) => (str ? JSON.parse(str) : null));\n }\n return result ? JSON.parse(result) : null;\n },\n setItem: (name, value) => {\n storage.setItem(name, JSON.stringify(value));\n },\n removeItem: (name) => storage.removeItem(name),\n },\n partialize: (state) => ({\n user: state.user,\n tokens: state.tokens,\n isAuthenticated: state.isAuthenticated,\n }) as AuthState,\n onRehydrateStorage: () => (state, error) => {\n if (error) {\n console.warn('[AntzChat] Auth store rehydration failed:', error);\n }\n // Access via ref — safe even when called synchronously during create()\n ref.store?.setState({ isHydrated: true });\n },\n },\n ),\n );\n\n // Assign ref immediately after create() completes\n ref.store = store;\n\n // If already hydrated synchronously (web/localStorage rehydrated during create),\n // set the flag now since the closure above may have called ref.store when it was null.\n if (!store.getState().isHydrated) {\n // Fallback: async storage (RN) — force hydrated after 3s max\n const hydrationTimeout = setTimeout(() => {\n if (!store.getState().isHydrated) {\n store.setState({ isHydrated: true });\n }\n }, 3000);\n\n // Clean up if it resolves naturally before timeout\n const unsub = store.subscribe((s) => {\n if (s.isHydrated) {\n clearTimeout(hydrationTimeout);\n unsub();\n }\n });\n }\n\n const tokenStore = {\n getAccessToken: () => store.getState().tokens?.accessToken,\n getRefreshToken: () => store.getState().tokens?.refreshToken,\n setTokens: (tokens: AuthTokens) => store.getState().setTokens(tokens),\n clearTokens: () => store.getState().logout(),\n };\n\n return { useAuthStore: store, authTokenStore: tokenStore };\n}\n\n// ─── Singleton instances (set during SDK init) ────────────────────────────────\n// Each SDK (web / RN) calls createAuthStore once and exports these.\n// Direct import of these will throw until initAuthStore is called.\n\nlet _authStore: ReturnType<typeof createAuthStore> | null = null;\n\n/**\n * Initialize the auth store singleton.\n * Idempotent — subsequent calls with the same storage return the existing instance.\n * This ensures tokens persisted in localStorage/AsyncStorage survive re-renders\n * and React StrictMode double-invocations.\n */\nexport function initAuthStore(storage: PersistStorage) {\n if (!_authStore) {\n _authStore = createAuthStore(storage);\n }\n return _authStore;\n}\n\nexport function getAuthStore() {\n if (!_authStore) throw new Error('[AntzChat] Auth store not initialized. Call initAuthStore first.');\n return _authStore;\n}\n\n/** Reset the singleton — only for tests / SDK teardown. */\nexport function resetAuthStore() {\n _authStore = null;\n}\n","import type { AntzChatConfig, PlatformUploadFn } from './config/types.js';\nimport { resolveConfig } from './config/types.js';\nimport { initApiClient, setApiClientInstance } from './api/client.js';\nimport { initAuthStore } from './stores/auth.store.js';\nimport { authApi } from './api/auth.js';\nimport { messagesApi } from './api/messages.js';\nimport { conversationsApi } from './api/conversations.js';\nimport { storageApi, uploadBatch } from './api/storage.js';\nimport { usersApi } from './api/users.js';\nimport { connectSocket, disconnectSocket, getSocket } from './socket/socket.js';\nimport { socketEmit } from './socket/emitters.js';\nimport type { UploadableFile } from './types/index.js';\n\ninterface ClientSocketHandle {\n emit: typeof socketEmit;\n on(event: string, handler: (...args: unknown[]) => void): void;\n off(event: string, handler: (...args: unknown[]) => void): void;\n}\n\n/**\n * Headless client for non-React consumers or direct programmatic use.\n * Usage:\n * const client = new AntzChatClient({ apiUrl, authToken, platformUploadFn, persistStorage })\n * await client.connect()\n */\nexport class AntzChatClient {\n private _config;\n private _authStore;\n\n readonly auth = authApi;\n readonly messages = messagesApi;\n readonly conversations = conversationsApi;\n readonly storage = storageApi;\n readonly users = usersApi;\n readonly socket: ClientSocketHandle = {\n emit: socketEmit,\n on: (event, handler) => getSocket().on(event, handler as (...args: any[]) => void),\n off: (event, handler) => getSocket().off(event, handler as (...args: any[]) => void),\n };\n\n constructor(rawConfig: AntzChatConfig) {\n this._config = resolveConfig(rawConfig);\n this._authStore = initAuthStore(rawConfig.persistStorage);\n\n if (rawConfig.authToken) {\n this._authStore.authTokenStore.setTokens({\n accessToken: rawConfig.authToken,\n refreshToken: '',\n tokenType: 'Bearer',\n expiresIn: 0,\n });\n }\n\n const instance = initApiClient(this._config, this._authStore.authTokenStore);\n setApiClientInstance(instance);\n }\n\n async connect(): Promise<void> {\n await connectSocket(this._config, () => this._authStore.authTokenStore.getAccessToken());\n }\n\n disconnect(): void {\n disconnectSocket();\n }\n\n uploadFiles(files: UploadableFile[], conversationId?: string) {\n return uploadBatch(files, this._config.platformUploadFn, conversationId, this._config.upload.onProgress);\n }\n}\n"],"mappings":"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","names":["axios","useChatStore","import_zustand"]}
1
+ {"version":3,"sources":["../src/stores/chat.store.ts","../src/index.ts","../src/config/types.ts","../src/api/client.ts","../src/api/auth.ts","../src/api/messages.ts","../src/api/conversations.ts","../src/api/storage.ts","../src/api/devices.ts","../src/api/users.ts","../src/socket/socket.ts","../src/socket/emitters.ts","../src/stores/auth.store.ts","../src/client-facade.ts"],"sourcesContent":["import { create } from 'zustand';\nimport type { Message } from '../types/index.js';\n\ninterface TypingUser {\n userId: string;\n displayName: string;\n avatarUrl?: string;\n}\n\nexport interface LastReadEntry {\n messageId: string;\n readAt: string;\n}\n\ninterface ChatState {\n activeConversationId: string | null;\n pendingTarget: { conversationId: string; messageId: string } | null;\n typingUsers: Record<string, TypingUser[]>;\n onlineUsers: string[];\n /** keyed by conversationId — current user's last read pointer per conversation */\n lastRead: Record<string, LastReadEntry>;\n /** keyed by userId — last seen timestamp for each user */\n lastSeen: Record<string, string>;\n replyingTo: Message | null;\n editingMessage: Message | null;\n isSidebarOpen: boolean;\n isGroupInfoOpen: boolean;\n isStarredPanelOpen: boolean;\n\n setActiveConversation: (id: string | null) => void;\n setPendingTarget: (target: { conversationId: string; messageId: string } | null) => void;\n addTypingUser: (conversationId: string, user: TypingUser) => void;\n removeTypingUser: (conversationId: string, userId: string) => void;\n setUserOnline: (userId: string) => void;\n setUserOffline: (userId: string) => void;\n setOnlineUsers: (userIds: string[]) => void;\n setLastRead: (conversationId: string, messageId: string, readAt: string) => void;\n setLastSeen: (userId: string, lastSeenAt: string) => void;\n setReplyingTo: (message: Message | null) => void;\n setEditingMessage: (message: Message | null) => void;\n toggleSidebar: () => void;\n setSidebarOpen: (open: boolean) => void;\n toggleGroupInfo: () => void;\n setGroupInfoOpen: (open: boolean) => void;\n toggleStarredPanel: () => void;\n setStarredPanelOpen: (open: boolean) => void;\n}\n\nexport const useChatStore = create<ChatState>((set) => ({\n activeConversationId: null,\n pendingTarget: null,\n typingUsers: {},\n onlineUsers: [],\n lastRead: {},\n lastSeen: {},\n replyingTo: null,\n editingMessage: null,\n isSidebarOpen: true,\n isGroupInfoOpen: false,\n isStarredPanelOpen: false,\n\n setActiveConversation: (id) =>\n set({ activeConversationId: id, replyingTo: null, editingMessage: null }),\n\n setPendingTarget: (target) => set({ pendingTarget: target }),\n\n addTypingUser: (conversationId, user) =>\n set((state) => {\n const existing = state.typingUsers[conversationId] ?? [];\n const deduped = existing.filter((u) => u.userId !== user.userId);\n return { typingUsers: { ...state.typingUsers, [conversationId]: [...deduped, user] } };\n }),\n\n removeTypingUser: (conversationId, userId) =>\n set((state) => ({\n typingUsers: {\n ...state.typingUsers,\n [conversationId]: (state.typingUsers[conversationId] ?? []).filter(\n (u) => u.userId !== userId,\n ),\n },\n })),\n\n setUserOnline: (userId) =>\n set((state) => ({\n onlineUsers: state.onlineUsers.includes(userId)\n ? state.onlineUsers\n : [...state.onlineUsers, userId],\n })),\n\n setUserOffline: (userId) =>\n set((state) => ({ onlineUsers: state.onlineUsers.filter((id) => id !== userId) })),\n\n setOnlineUsers: (userIds) => set({ onlineUsers: userIds }),\n\n setLastRead: (conversationId, messageId, readAt) =>\n set((state) => ({\n lastRead: { ...state.lastRead, [conversationId]: { messageId, readAt } },\n })),\n\n setLastSeen: (userId, lastSeenAt) =>\n set((state) => ({\n lastSeen: { ...state.lastSeen, [userId]: lastSeenAt },\n })),\n\n setReplyingTo: (message) => set({ replyingTo: message, editingMessage: null }),\n\n setEditingMessage: (message) => set({ editingMessage: message, replyingTo: null }),\n\n toggleSidebar: () => set((state) => ({ isSidebarOpen: !state.isSidebarOpen })),\n setSidebarOpen: (open) => set({ isSidebarOpen: open }),\n\n toggleGroupInfo: () => set((state) => ({ isGroupInfoOpen: !state.isGroupInfoOpen })),\n setGroupInfoOpen: (open) => set({ isGroupInfoOpen: open }),\n\n toggleStarredPanel: () => set((state) => ({ isStarredPanelOpen: !state.isStarredPanelOpen })),\n setStarredPanelOpen: (open) => set({ isStarredPanelOpen: open }),\n}));\n","// Config\nexport type {\n AntzChatConfig,\n ResolvedConfig,\n UploadConfig,\n FileSizeLimits,\n ResolvedFileSizeLimits,\n PlatformUploadFn,\n PersistStorage,\n} from './config/types.js';\nexport { resolveConfig } from './config/types.js';\n\n// Types\nexport type {\n UploadableFile,\n User,\n AuthTokens,\n AuthResponse,\n LoginCredentials,\n RegisterData,\n Message,\n MessageContent,\n MessageReplyReference,\n MessageReaction,\n Conversation,\n ConversationListParams,\n ConversationUnreadCount,\n UnreadSummary,\n Participant,\n Attachment,\n EncryptedContent,\n EncryptionKeyInfo,\n EncryptionMode,\n FileType,\n FileResponse,\n PresignedUrlRequest,\n PresignedUrlResponse,\n BatchUploadResult,\n UploadProgress,\n PaginatedResponse,\n CursorPaginatedResponse,\n SendMessagePayload,\n SendMessageAttachment,\n OptimisticAttachment,\n NewMessageEvent,\n MessageUpdatedEvent,\n MessageDeletedEvent,\n MessageDeletedForMeEvent,\n ReactionUpdatedEvent,\n TypingIndicatorEvent,\n UserStatusEvent,\n ReadReceiptEvent,\n MessageAckEvent,\n MessageDeliveredEvent,\n MessagesDeliveredEvent,\n} from './types/index.js';\n\n// API\nexport { authApi, messagesApi, conversationsApi, storageApi, uploadBatch, normalizeConversation, devicesApi, usersApi } from './api/index.js';\nexport type { RegisterDeviceTokenPayload, MobileDeviceToken, WebPushDeviceToken } from './api/index.js';\nexport type { CreateGroupData, CreateDirectData, UpdateConversationData, ListMessagesParams, SearchParams, SendData } from './api/index.js';\nexport type { UserPreferences, QuietHours } from './types/index.js';\nexport { initApiClient, setApiClientInstance, getApiClient } from './api/client.js';\nexport type { TokenStore } from './api/client.js';\n\n// Socket\nexport { connectSocket, disconnectSocket, reconnectSocket, refreshSocketAuth, getSocket, tryGetSocket, getSocketStatus, onSocketStatus } from './socket/socket.js';\nexport type { SocketStatus, StatusListener } from './socket/socket.js';\nexport { socketEmit } from './socket/emitters.js';\n\n// Stores\nexport { initAuthStore, getAuthStore, createAuthStore, resetAuthStore } from './stores/auth.store.js';\nexport { useChatStore } from './stores/chat.store.js';\nexport type { LastReadEntry } from './stores/chat.store.js';\n\n// Headless client\nexport { AntzChatClient } from './client-facade.js';\n","import type { FileType, UploadableFile, PresignedUrlResponse } from '../types/index.js';\n\nexport interface FileSizeLimits {\n image?: number;\n video?: number;\n audio?: number;\n document?: number;\n default?: number;\n}\n\n/**\n * Platform-provided function that performs the actual binary upload to a presigned URL.\n * - Web implementation: XMLHttpRequest with progress events\n * - RN implementation: fetch with FormData or direct body\n *\n * The core calls this — it never does the upload itself.\n */\nexport type PlatformUploadFn = (\n presigned: PresignedUrlResponse,\n file: UploadableFile,\n onProgress?: (pct: number) => void,\n) => Promise<void>;\n\n/**\n * Platform-provided persistent key-value storage for auth token persistence.\n * - Web: localStorage adapter\n * - RN: AsyncStorage adapter\n */\nexport interface PersistStorage {\n getItem(key: string): string | null | Promise<string | null>;\n setItem(key: string, value: string): void | Promise<void>;\n removeItem(key: string): void | Promise<void>;\n}\n\nexport interface UploadConfig {\n /**\n * Per-type file size limits in MB. Can also pass a single number for all types.\n * Defaults: image 5MB, video 25MB, audio 10MB, document 10MB.\n */\n maxFileSizeMB?: number | FileSizeLimits;\n\n /** Max files per message. Default: 10 */\n maxFilesPerMessage?: number;\n\n /** Which attachment types users can send. Default: all */\n allowedTypes?: Array<FileType>;\n\n /** Called when a file fails validation or upload */\n onUploadError?: (file: UploadableFile, error: Error) => void;\n\n /** Called with 0–100 aggregate progress during a batch upload */\n onProgress?: (progress: number) => void;\n}\n\nexport interface AntzChatConfig {\n /** REST API base URL — e.g. \"https://api.yourapp.com/api/v1\" */\n apiUrl: string;\n\n /**\n * WebSocket server URL. Defaults to apiUrl with /api/vN path stripped.\n * SDK connects to {socketUrl}/chat\n */\n socketUrl?: string;\n\n /** Static JWT. Use this OR authProvider, not both. */\n authToken?: string;\n\n /**\n * Dynamic token getter — called before requests and on socket reconnect.\n * Preferred when the host app manages its own auth lifecycle.\n */\n authProvider?: () => Promise<string>;\n\n /**\n * External user ID — required for non-builtin modes (antz / external / wso2).\n * Sent as x-user-id header on every request so the chat server can forward it\n * to the user-service for token validation.\n * Not needed for builtin mode (chat server issues its own JWTs).\n */\n userId?: string;\n\n /**\n * Profile picture for non-builtin modes.\n * Server fetches/decodes, hashes for dedup, uploads to chat storage on first use.\n * Only sent once at init — not re-sent on every request.\n * Client never needs to compute hashes; the server owns all dedup logic.\n */\n avatar?: {\n /** Full URL the server can fetch (preferred — Antz/external/wso2 clients know their own file URLs) */\n url?: string;\n /** Raw base64 string (with or without data:... prefix) as fallback */\n base64?: string;\n };\n\n /** Required for multi-tenant backends. Sent as X-Tenant-ID header. */\n tenantId?: string;\n\n /** Must match server ENCRYPTION_MODE env var. Default: 'none' */\n encryptionMode?: 'none' | 'server';\n\n upload?: UploadConfig;\n\n /**\n * Number of messages fetched per page when loading chat history.\n * Default: 40\n */\n messagePageSize?: number;\n\n /**\n * Number of starred messages fetched per page.\n * Default: 30\n */\n starredMessagePageSize?: number;\n\n /**\n * Number of search results fetched per request.\n * Default: 50\n */\n searchPageSize?: number;\n\n /**\n * Platform-specific binary upload implementation.\n * Required — each SDK (web, RN) provides its own.\n */\n platformUploadFn: PlatformUploadFn;\n\n /**\n * Platform-specific persistent storage for auth tokens.\n * Required — each SDK provides its own (localStorage / AsyncStorage).\n */\n persistStorage: PersistStorage;\n}\n\n// ─── Resolved (all defaults filled) ─────────────────────────────────────────\n\nexport interface ResolvedFileSizeLimits {\n image: number;\n video: number;\n audio: number;\n document: number;\n default: number;\n}\n\nexport interface ResolvedConfig {\n apiUrl: string;\n socketUrl: string;\n socketOrigin: string;\n socketPath: string;\n authToken?: string;\n authProvider?: () => Promise<string>;\n userId?: string;\n tenantId?: string;\n avatar?: { url?: string; base64?: string };\n encryptionMode: 'none' | 'server';\n upload: {\n maxFileSizeMB: ResolvedFileSizeLimits;\n maxFilesPerMessage: number;\n allowedTypes: FileType[];\n onUploadError?: (file: UploadableFile, error: Error) => void;\n onProgress?: (progress: number) => void;\n };\n platformUploadFn: PlatformUploadFn;\n persistStorage: PersistStorage;\n messagePageSize: number;\n starredMessagePageSize: number;\n searchPageSize: number;\n}\n\nexport function resolveConfig(config: AntzChatConfig): ResolvedConfig {\n const socketUrl =\n config.socketUrl ??\n config.apiUrl.replace(/\\/api\\/v\\d+\\/?$/, '').replace(/\\/$/, '');\n\n // Auto-derive Socket.IO engine path from the socketUrl pathname.\n // If the server is behind a reverse proxy with a path prefix (e.g. /chat-api),\n // that prefix is already embedded in socketUrl. We append /socket.io to it.\n // Examples:\n // socketUrl = https://host/chat-api → socketPath = /chat-api/socket.io\n // socketUrl = https://host → socketPath = /socket.io\n // No env var or manual config needed — SERVER_URL on the server and apiUrl\n // on the client carry the same prefix, so both sides derive the same path.\n // Derive Socket.IO engine path and origin separately.\n // Socket.IO uses the URL passed to io() as the namespace origin — anything\n // in the pathname of that URL becomes part of the namespace, not the engine path.\n // So we must pass only the bare origin (https://host) to io(), and use the\n // path option for the engine mount point.\n //\n // socketUrl = https://host/chat-api\n // → socketOrigin = https://host (passed to io())\n // → socketPath = /chat-api/socket.io (engine path option)\n // → namespace = /chat (hardcoded in connectSocket)\n //\n // socketUrl = https://host\n // → socketOrigin = https://host\n // → socketPath = /socket.io\n let socketOrigin = socketUrl;\n let socketPath = '/socket.io';\n try {\n const parsed = new URL(socketUrl);\n socketOrigin = parsed.origin; // strips pathname, search, hash\n const pathname = parsed.pathname.replace(/\\/$/, '');\n if (pathname && pathname !== '/') socketPath = `${pathname}/socket.io`;\n } catch {\n // invalid URL — fall back to defaults\n }\n\n const raw = config.upload?.maxFileSizeMB;\n let limits: ResolvedFileSizeLimits;\n\n if (typeof raw === 'number') {\n limits = { image: raw, video: raw, audio: raw, document: raw, default: raw };\n } else {\n const fallback = raw?.default ?? 25;\n limits = {\n image: raw?.image ?? 5,\n video: raw?.video ?? 25,\n audio: raw?.audio ?? 10,\n document: raw?.document ?? 10,\n default: fallback,\n };\n }\n\n return {\n apiUrl: config.apiUrl.replace(/\\/$/, ''),\n socketUrl,\n socketOrigin,\n socketPath,\n authToken: config.authToken,\n authProvider: config.authProvider,\n userId: config.userId,\n tenantId: config.tenantId,\n avatar: config.avatar,\n encryptionMode: config.encryptionMode ?? 'none',\n upload: {\n maxFileSizeMB: limits,\n maxFilesPerMessage: config.upload?.maxFilesPerMessage ?? 10,\n allowedTypes: config.upload?.allowedTypes ?? ['image', 'video', 'audio', 'document'],\n onUploadError: config.upload?.onUploadError,\n onProgress: config.upload?.onProgress,\n },\n platformUploadFn: config.platformUploadFn,\n persistStorage: config.persistStorage,\n messagePageSize: config.messagePageSize ?? 40,\n starredMessagePageSize: config.starredMessagePageSize ?? 30,\n searchPageSize: config.searchPageSize ?? 50,\n };\n}\n","import axios, {\n AxiosInstance,\n InternalAxiosRequestConfig,\n} from 'axios';\nimport type { ResolvedConfig } from '../config/types.js';\nimport type { AuthTokens } from '../types/index.js';\n\nexport type TokenStore = {\n getAccessToken: () => string | null | undefined;\n getRefreshToken: () => string | null | undefined;\n setTokens: (tokens: AuthTokens) => void;\n clearTokens: () => void;\n};\n\nlet _tokenStore: TokenStore | null = null;\nlet _config: ResolvedConfig | null = null;\n// Avatar headers are sent only on the first authenticated request after init.\n// The server hashes on receive and deduplicates — subsequent requests don't need them.\nlet _avatarSent = false;\n\nexport function initApiClient(config: ResolvedConfig, tokenStore: TokenStore): AxiosInstance {\n _config = config;\n _tokenStore = tokenStore;\n _avatarSent = false; // reset on re-init (new session / authToken change)\n\n const client = axios.create({\n baseURL: config.apiUrl,\n headers: { 'Content-Type': 'application/json' },\n });\n\n client.interceptors.request.use((req: InternalAxiosRequestConfig) => {\n const token = _tokenStore?.getAccessToken();\n if (token) req.headers['Authorization'] = `Bearer ${token}`;\n if (_config?.userId) req.headers['x-user-id'] = _config.userId;\n if (_config?.tenantId) req.headers['X-Tenant-ID'] = _config.tenantId;\n // Send avatar on the first request only — server hashes and deduplicates\n if (token && !_avatarSent && _config?.avatar) {\n if (_config.avatar.base64) req.headers['x-avatar-base64'] = _config.avatar.base64;\n else if (_config.avatar.url) req.headers['x-avatar-url'] = _config.avatar.url;\n _avatarSent = true;\n }\n return req;\n });\n\n let isRefreshing = false;\n let refreshQueue: Array<(token: string) => void> = [];\n\n client.interceptors.response.use(\n (response) => {\n if (\n response.data &&\n typeof response.data === 'object' &&\n 'success' in response.data &&\n 'data' in response.data\n ) {\n response.data = response.data.data;\n }\n return response;\n },\n async (error) => {\n const original = error.config as InternalAxiosRequestConfig & { _retry?: boolean };\n\n if (error.response?.status === 401 && !original._retry) {\n const refreshToken = _tokenStore?.getRefreshToken();\n if (!refreshToken) {\n _tokenStore?.clearTokens();\n return Promise.reject(error);\n }\n\n if (isRefreshing) {\n return new Promise((resolve) => {\n refreshQueue.push((newToken) => {\n original.headers['Authorization'] = `Bearer ${newToken}`;\n resolve(client(original));\n });\n });\n }\n\n original._retry = true;\n isRefreshing = true;\n\n try {\n const { data } = await axios.post<{ data: AuthTokens }>(\n `${_config!.apiUrl}/auth/refresh`,\n { refreshToken },\n );\n const tokens: AuthTokens = (data as any).data ?? data;\n _tokenStore?.setTokens(tokens);\n refreshQueue.forEach((cb) => cb(tokens.accessToken));\n refreshQueue = [];\n original.headers['Authorization'] = `Bearer ${tokens.accessToken}`;\n return client(original);\n } catch {\n _tokenStore?.clearTokens();\n return Promise.reject(error);\n } finally {\n isRefreshing = false;\n }\n }\n\n return Promise.reject(error);\n },\n );\n\n return client;\n}\n\nlet _instance: AxiosInstance | null = null;\n\nexport function setApiClientInstance(instance: AxiosInstance) {\n _instance = instance;\n}\n\nexport function getApiClient(): AxiosInstance {\n if (!_instance) throw new Error('[AntzChat] API client not initialized. Call initApiClient first.');\n return _instance;\n}\n","import type { AuthResponse, AuthTokens, LoginCredentials, RegisterData, User } from '../types/index.js';\nimport { getApiClient } from './client.js';\n\nexport const authApi = {\n async login(credentials: LoginCredentials): Promise<AuthResponse> {\n const { data } = await getApiClient().post<AuthResponse>('/auth/login', credentials);\n return data;\n },\n\n async register(payload: RegisterData): Promise<AuthResponse> {\n const { data } = await getApiClient().post<AuthResponse>('/auth/register', payload);\n return data;\n },\n\n async refresh(refreshToken: string): Promise<AuthTokens> {\n const { data } = await getApiClient().post<AuthTokens>('/auth/refresh', { refreshToken });\n return data;\n },\n\n async logout(refreshToken?: string): Promise<void> {\n await getApiClient().post('/auth/logout', refreshToken ? { refreshToken } : {});\n },\n\n async logoutAll(): Promise<void> {\n await getApiClient().post('/auth/logout-all');\n },\n\n async getMe(): Promise<User> {\n const { data } = await getApiClient().get<User>('/users/me');\n return data;\n },\n\n // Upload a new avatar file (builtin mode — multipart)\n async uploadAvatar(file: File | Blob, mimeType?: string): Promise<{ avatarUrl: string }> {\n const form = new FormData();\n form.append('avatar', file instanceof File ? file : new File([file], 'avatar.jpg', { type: mimeType ?? 'image/jpeg' }));\n const { data } = await getApiClient().put<{ avatarUrl: string }>('/users/me/avatar', form, {\n headers: { 'Content-Type': 'multipart/form-data' },\n });\n return data;\n },\n\n // Sync avatar from URL or base64 (non-builtin modes — or post-init update)\n async syncAvatar(source: { url?: string; base64?: string }): Promise<{ avatarUrl: string }> {\n const headers: Record<string, string> = {};\n if (source.base64) headers['x-avatar-base64'] = source.base64;\n else if (source.url) headers['x-avatar-url'] = source.url;\n const { data } = await getApiClient().post<{ avatarUrl: string }>('/users/me/avatar/sync', {}, { headers });\n return data;\n },\n};\n","import type {\n Message,\n CursorPaginatedResponse,\n PaginatedResponse,\n SendMessagePayload,\n} from '../types/index.js';\nimport { getApiClient } from './client.js';\n\nexport interface ListMessagesParams {\n cursor?: string;\n limit?: number;\n direction?: 'before' | 'after';\n}\n\nexport interface SearchParams {\n query: string;\n conversationId?: string;\n page?: number;\n limit?: number;\n}\n\nexport interface SendData {\n text?: string;\n attachments?: SendMessagePayload['attachments'];\n replyTo?: string;\n tempId?: string;\n isEncrypted?: boolean;\n}\n\nexport const messagesApi = {\n async list(conversationId: string, params: ListMessagesParams = {}): Promise<CursorPaginatedResponse<Message>> {\n const { cursor, direction, ...rest } = params;\n const serverParams: Record<string, unknown> = { ...rest };\n if (cursor) {\n serverParams[direction === 'after' ? 'after' : 'before'] = cursor;\n }\n const { data } = await getApiClient().get<CursorPaginatedResponse<Message>>(\n `/conversations/${conversationId}/messages`,\n { params: serverParams },\n );\n return data;\n },\n\n async get(messageId: string): Promise<Message> {\n const { data } = await getApiClient().get<Message>(`/messages/${messageId}`);\n return data;\n },\n\n async send(conversationId: string, payload: SendData): Promise<Message> {\n const { data } = await getApiClient().post<Message>(\n `/conversations/${conversationId}/messages`,\n payload,\n );\n return data;\n },\n\n async update(messageId: string, text: string): Promise<Message> {\n const { data } = await getApiClient().put<Message>(`/messages/${messageId}`, { text });\n return data;\n },\n\n async delete(messageId: string): Promise<void> {\n await getApiClient().delete(`/messages/${messageId}`);\n },\n\n async deleteForMe(messageId: string): Promise<void> {\n await getApiClient().delete(`/messages/${messageId}/for-me`);\n },\n\n async addReaction(messageId: string, emoji: string): Promise<Message> {\n const { data } = await getApiClient().post<Message>(`/messages/${messageId}/reactions`, { emoji });\n return data;\n },\n\n async removeReaction(messageId: string, emoji: string): Promise<Message> {\n const { data } = await getApiClient().delete<Message>(\n `/messages/${messageId}/reactions/${encodeURIComponent(emoji)}`,\n );\n return data;\n },\n\n async star(messageId: string): Promise<void> {\n await getApiClient().post(`/messages/${messageId}/star`);\n },\n\n async unstar(messageId: string): Promise<void> {\n await getApiClient().delete(`/messages/${messageId}/star`);\n },\n\n async getStarred(params: { page?: number; limit?: number; conversationId?: string } = {}): Promise<PaginatedResponse<Message>> {\n const { data } = await getApiClient().get<PaginatedResponse<Message>>('/messages/starred', { params });\n return data;\n },\n\n async search(params: SearchParams): Promise<PaginatedResponse<Message>> {\n const { data } = await getApiClient().get<PaginatedResponse<Message>>('/messages/search', { params });\n return data;\n },\n\n async getLastRead(conversationId: string): Promise<{ lastReadMessageId: string | null; lastReadAt: string | null }> {\n const { data } = await getApiClient().get<{ lastReadMessageId: string | null; lastReadAt: string | null }>(\n `/conversations/${conversationId}/read-receipt`,\n );\n return data;\n },\n\n async markAsRead(conversationId: string, messageId?: string): Promise<void> {\n await getApiClient().post(`/conversations/${conversationId}/read`, messageId ? { messageId } : {});\n },\n\n async pin(messageId: string): Promise<Message> {\n const { data } = await getApiClient().post<Message>(`/messages/${messageId}/pin`);\n return data;\n },\n\n async unpin(messageId: string): Promise<Message> {\n const { data } = await getApiClient().delete<Message>(`/messages/${messageId}/pin`);\n return data;\n },\n\n async getPinned(conversationId: string): Promise<Message[]> {\n const { data } = await getApiClient().get<Message[]>(`/conversations/${conversationId}/pinned-messages`);\n return data;\n },\n};\n","import type { Conversation, ConversationListParams, ConversationUnreadCount, Message, MessageStatus, Participant, PaginatedResponse, UnreadSummary, User } from '../types/index.js';\nimport { getApiClient } from './client.js';\n\nfunction normalizeParticipant(p: any): Participant {\n const hasUserDetails = p.displayName || p.username || p.avatarUrl;\n return {\n userId: p.userId,\n role: p.role,\n joinedAt: p.joinedAt,\n isActive: p.isActive,\n user: hasUserDetails\n ? {\n id: p.userId,\n tenantId: '',\n email: '',\n username: p.username ?? '',\n displayName: p.displayName ?? p.username ?? '',\n avatarUrl: p.avatarUrl,\n status: 'offline' as const,\n createdAt: p.joinedAt ?? '',\n updatedAt: p.joinedAt ?? '',\n }\n : (p.user as User | undefined),\n };\n}\n\nfunction normalizeLastMessage(lastMsg: any): Message | undefined {\n if (!lastMsg) return undefined;\n if (lastMsg.content !== undefined) return lastMsg as Message;\n return {\n id: lastMsg.messageId ?? '',\n tenantId: '',\n conversationId: '',\n senderId: '',\n content: {\n type: lastMsg.hasAttachments ? 'attachment' : 'text',\n text: lastMsg.contentPreview,\n },\n reactions: [],\n status: (lastMsg.status ?? 'sent') as MessageStatus,\n isEdited: false,\n sentAt: lastMsg.sentAt ?? '',\n createdAt: lastMsg.sentAt ?? '',\n };\n}\n\nexport function normalizeConversation(conv: any): Conversation {\n return {\n ...conv,\n id: conv.id ?? conv.conversationId,\n participants: (conv.participants ?? []).map(normalizeParticipant),\n lastMessage: normalizeLastMessage(conv.lastMessage),\n };\n}\n\nexport interface CreateGroupData {\n name: string;\n description?: string;\n participantIds: string[];\n}\n\nexport interface CreateDirectData {\n userId: string;\n}\n\nexport interface UpdateConversationData {\n name?: string;\n description?: string;\n}\n\nexport const conversationsApi = {\n async list(params: ConversationListParams = {}): Promise<PaginatedResponse<Conversation>> {\n const { data } = await getApiClient().get<PaginatedResponse<Conversation>>('/conversations', { params });\n return { ...data, data: data.data.map(normalizeConversation) };\n },\n\n async get(conversationId: string): Promise<Conversation> {\n const { data } = await getApiClient().get<Conversation>(`/conversations/${conversationId}`);\n return normalizeConversation(data);\n },\n\n async createGroup(payload: CreateGroupData): Promise<Conversation> {\n const { data } = await getApiClient().post<Conversation>('/conversations', payload);\n return normalizeConversation(data);\n },\n\n async createDirect(payload: CreateDirectData): Promise<Conversation> {\n const { data } = await getApiClient().post<Conversation>('/conversations/direct', payload);\n return normalizeConversation(data);\n },\n\n async update(conversationId: string, payload: UpdateConversationData): Promise<Conversation> {\n const { data } = await getApiClient().put<Conversation>(`/conversations/${conversationId}`, payload);\n return normalizeConversation(data);\n },\n\n async delete(conversationId: string): Promise<void> {\n await getApiClient().delete(`/conversations/${conversationId}`);\n },\n\n async addParticipants(conversationId: string, userIds: string[]): Promise<Conversation> {\n const { data } = await getApiClient().post<Conversation>(\n `/conversations/${conversationId}/participants`,\n { userIds },\n );\n return normalizeConversation(data);\n },\n\n async removeParticipant(conversationId: string, userId: string): Promise<Conversation> {\n const { data } = await getApiClient().delete<Conversation>(\n `/conversations/${conversationId}/participants/${userId}`,\n );\n return normalizeConversation(data);\n },\n\n async updateParticipantRole(conversationId: string, userId: string, role: 'admin' | 'member'): Promise<Conversation> {\n const { data } = await getApiClient().put<Conversation>(\n `/conversations/${conversationId}/participants/${userId}/role`,\n { role },\n );\n return normalizeConversation(data);\n },\n\n async mute(conversationId: string, mutedUntil?: string): Promise<void> {\n await getApiClient().post(`/conversations/${conversationId}/mute`, mutedUntil ? { mutedUntil } : {});\n },\n\n async unmute(conversationId: string): Promise<void> {\n await getApiClient().delete(`/conversations/${conversationId}/mute`);\n },\n\n async pin(conversationId: string): Promise<void> {\n await getApiClient().post(`/conversations/${conversationId}/pin`);\n },\n\n async unpin(conversationId: string): Promise<void> {\n await getApiClient().delete(`/conversations/${conversationId}/pin`);\n },\n\n async leave(conversationId: string): Promise<void> {\n await getApiClient().delete(`/conversations/${conversationId}/leave`);\n },\n\n async getMembers(conversationId: string): Promise<User[]> {\n const { data } = await getApiClient().get<User[]>(`/conversations/${conversationId}/participants`);\n return data;\n },\n\n /**\n * Get unread message count for a single conversation.\n * Use this after app foreground or socket reconnect to refresh a specific count.\n */\n async getUnreadCount(conversationId: string): Promise<ConversationUnreadCount> {\n const { data } = await getApiClient().get<ConversationUnreadCount>(\n `/conversations/${conversationId}/unread`,\n );\n return data;\n },\n\n /**\n * Get total unread count across all conversations + per-conversation breakdown.\n * Use on app cold start, foreground resume, or after socket reconnect.\n * The socket keeps counts live while connected — this is the source of truth\n * when the socket was down.\n */\n async getUnreadSummary(): Promise<UnreadSummary> {\n const { data } = await getApiClient().get<UnreadSummary>('/conversations/unread');\n return data;\n },\n\n /**\n * Set the group icon from an already-uploaded file (admin only).\n * The fileId comes from uploadBatch() / client.uploadFiles() — same as attachments.\n * Server copies storageKey into conversation.iconMeta and deletes the chat_files record.\n */\n async uploadIcon(conversationId: string, fileId: string): Promise<Conversation> {\n const { data } = await getApiClient().put<Conversation>(\n `/conversations/${conversationId}/icon`,\n { fileId },\n );\n return normalizeConversation(data);\n },\n\n};\n","import type {\n BatchUploadResult,\n FileResponse,\n PaginatedResponse,\n PresignedUrlRequest,\n PresignedUrlResponse,\n FileType,\n UploadableFile,\n} from '../types/index.js';\nimport type { PlatformUploadFn } from '../config/types.js';\nimport { getApiClient } from './client.js';\n\nexport const storageApi = {\n async requestPresignedUrl(payload: PresignedUrlRequest): Promise<PresignedUrlResponse> {\n const { data } = await getApiClient().post<PresignedUrlResponse>('/storage/presigned-url', payload);\n return data;\n },\n\n async requestPresignedUrlBatch(files: PresignedUrlRequest[]): Promise<{\n urls: PresignedUrlResponse[];\n errors: Array<{ filename: string; error: string }>;\n }> {\n const { data } = await getApiClient().post('/storage/presigned-url/batch', { files });\n return data;\n },\n\n async confirmUpload(fileId: string): Promise<FileResponse> {\n const { data } = await getApiClient().post<FileResponse>(`/storage/confirm/${fileId}`);\n return data;\n },\n\n async getFile(fileId: string): Promise<FileResponse> {\n const { data } = await getApiClient().get<FileResponse>(`/storage/files/${fileId}`);\n return data;\n },\n\n async getFileUrl(fileId: string, expiresIn?: number): Promise<{ url: string; expiresAt: string }> {\n const { data } = await getApiClient().get(`/storage/files/${fileId}/url`, {\n params: expiresIn ? { expiresIn } : {},\n });\n return data;\n },\n\n async deleteFile(fileId: string): Promise<void> {\n await getApiClient().delete(`/storage/files/${fileId}`);\n },\n\n async getConversationFiles(\n conversationId: string,\n params: { page?: number; limit?: number; type?: FileType } = {},\n ): Promise<PaginatedResponse<FileResponse>> {\n const { data } = await getApiClient().get(\n `/storage/conversations/${conversationId}/files`,\n { params },\n );\n return data;\n },\n\n async getMyFiles(params: { page?: number; limit?: number } = {}): Promise<PaginatedResponse<FileResponse>> {\n const { data } = await getApiClient().get('/storage/my-files', { params });\n return data;\n },\n};\n\n/**\n * High-level batch upload.\n * The actual binary transfer is delegated to platformUploadFn so this\n * function is platform-agnostic (works on web and React Native).\n */\nexport async function uploadBatch(\n files: UploadableFile[],\n platformUploadFn: PlatformUploadFn,\n conversationId?: string,\n onProgress?: (pct: number) => void,\n): Promise<BatchUploadResult> {\n const requests: PresignedUrlRequest[] = files.map((f) => ({\n filename: f.name,\n mimeType: f.type,\n size: f.size,\n conversationId,\n }));\n\n const { urls, errors: requestErrors } = await storageApi.requestPresignedUrlBatch(requests);\n\n const progressMap: Record<number, number> = {};\n const reportProgress = () => {\n if (!onProgress) return;\n const vals = Object.values(progressMap);\n const avg = vals.reduce((s, v) => s + v, 0) / Math.max(vals.length, 1);\n onProgress(Math.round(avg));\n };\n\n const successful: FileResponse[] = [];\n const failed: Array<{ filename: string; error: string }> = [...requestErrors];\n\n await Promise.all(\n urls.map(async (presigned, idx) => {\n const file = files[idx];\n progressMap[idx] = 0;\n try {\n await platformUploadFn(presigned, file, (pct) => {\n progressMap[idx] = Math.round(pct * 0.9);\n reportProgress();\n });\n\n const result = await storageApi.confirmUpload(presigned.fileId);\n progressMap[idx] = 100;\n reportProgress();\n successful.push(result);\n } catch (err) {\n failed.push({ filename: file.name, error: (err as Error).message });\n }\n }),\n );\n\n return { successful, failed };\n}\n","import { getApiClient } from './client.js';\n\n// ─── Types ─────────────────────────────────────────────────────────────────\n\n/** Shared fields for every device registration. */\ninterface DeviceTokenBase {\n /**\n * Client-generated stable UUID for this device.\n * Store this in localStorage / SecureStore / Keychain and reuse it on every\n * app start so the same record is updated rather than duplicated.\n */\n deviceId: string;\n platform: 'ios' | 'android' | 'web';\n provider: 'expo' | 'fcm' | 'apns' | 'web-push';\n userAgent?: string;\n}\n\n/** Mobile push registration (expo | fcm | apns). */\nexport interface MobileDeviceToken extends DeviceTokenBase {\n provider: 'expo' | 'fcm' | 'apns';\n /** FCM registration token / APNs device token / Expo push token. */\n token: string;\n endpoint?: never;\n p256dh?: never;\n auth?: never;\n}\n\n/** Web push (VAPID) registration. */\nexport interface WebPushDeviceToken extends DeviceTokenBase {\n provider: 'web-push';\n /** PushSubscription.endpoint */\n endpoint: string;\n /** base64url-encoded PushSubscription key 'p256dh' */\n p256dh: string;\n /** base64url-encoded PushSubscription key 'auth' */\n auth: string;\n token?: never;\n}\n\nexport type RegisterDeviceTokenPayload = MobileDeviceToken | WebPushDeviceToken;\n\n// ─── API ───────────────────────────────────────────────────────────────────\n\nexport const devicesApi = {\n /**\n * Register or update a device push token with the chat server.\n *\n * Upserts by `deviceId` — calling this multiple times with the same deviceId\n * simply refreshes the token value (tokens can rotate silently on some platforms).\n *\n * The SDK never calls this automatically. The parent app or the `tokenProvider`\n * option in `pushNotifications` config is responsible for calling it after\n * obtaining the token from the OS / browser.\n */\n async register(payload: RegisterDeviceTokenPayload): Promise<void> {\n await getApiClient().post('/users/me/devices', payload);\n },\n\n /**\n * Remove a device token from the chat server.\n * Call this on logout so the user stops receiving push notifications on this device.\n */\n async remove(deviceId: string): Promise<void> {\n await getApiClient().delete(`/users/me/devices/${deviceId}`);\n },\n};\n","import type { PaginatedResponse, User, UserPreferences } from '../types/index.js';\nimport { getApiClient } from './client.js';\n\nexport const usersApi = {\n async list(params: { query?: string; page?: number; limit?: number } = {}): Promise<PaginatedResponse<User>> {\n const { data } = await getApiClient().get<PaginatedResponse<User>>('/users', { params });\n return data;\n },\n\n async getById(userId: string): Promise<User> {\n const { data } = await getApiClient().get<User>(`/users/${userId}`);\n return data;\n },\n\n async getLastSeen(userId: string): Promise<{ lastSeenAt: string | null }> {\n const { data } = await getApiClient().get<User>(`/users/${userId}`);\n return { lastSeenAt: data.lastSeenAt ?? null };\n },\n\n /**\n * Update notification preferences for the current user.\n * Partial update — only send fields you want to change.\n * A prefs record is automatically created with defaults when a device\n * token is first registered, so this never fails with \"not found\".\n */\n async updatePreferences(prefs: UserPreferences): Promise<User> {\n const { data } = await getApiClient().put<User>('/users/me/preferences', prefs);\n return data;\n },\n\n /**\n * Fetch current notification preferences for the current user.\n * Returns null if no prefs record exists yet (all defaults apply).\n */\n async getPreferences(): Promise<UserPreferences | null> {\n try {\n const { data } = await getApiClient().get<UserPreferences>('/users/me/preferences');\n return data;\n } catch {\n return null;\n }\n },\n};\n","import { io, Socket } from 'socket.io-client';\nimport type { ResolvedConfig } from '../config/types.js';\nimport type { ReadReceiptEvent, UserStatusEvent } from '../types/index.js';\n\nexport type SocketStatus = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';\nexport type StatusListener = (status: SocketStatus) => void;\n\nlet _socket: Socket | null = null;\nlet _status: SocketStatus = 'disconnected';\nconst _statusListeners = new Set<StatusListener>();\n\n// Stored so SocketProvider can call refreshAndReconnect() without re-passing config\nlet _getToken: (() => string | null | undefined) | null = null;\nlet _userId: string | undefined;\nlet _tenantId: string | undefined;\n\nfunction setStatus(s: SocketStatus) {\n _status = s;\n _statusListeners.forEach(l => l(s));\n}\n\nexport function getSocket(): Socket {\n if (!_socket) throw new Error('[AntzChat] Socket not initialized. Call connectSocket first.');\n return _socket;\n}\n\n/** Returns the socket if connected, null otherwise. Use this for fire-and-forget\n * operations (markRead, typing) that should silently no-op when not yet connected. */\nexport function tryGetSocket(): Socket | null {\n return _socket?.connected ? _socket : null;\n}\n\nexport function getSocketStatus(): SocketStatus {\n return _status;\n}\n\nexport function onSocketStatus(listener: StatusListener): () => void {\n _statusListeners.add(listener);\n return () => _statusListeners.delete(listener);\n}\n\nexport async function connectSocket(\n config: ResolvedConfig,\n getToken: () => string | null | undefined,\n): Promise<Socket> {\n // Also guard against overwriting a socket that's mid-handshake (connected=false, disconnected=false).\n // Without this, SocketProvider mounting while AntzChatClient.connect() is still handshaking\n // creates a second io() instance, orphans the first socket's listeners, and drops the connection.\n if (_socket && !_socket.disconnected) return _socket;\n\n // Persist so refreshAndReconnect can update auth without re-passing these\n _getToken = getToken;\n _userId = config.userId;\n _tenantId = config.tenantId;\n\n const token = getToken();\n\n // Pass only the origin to io() — Socket.IO treats the URL pathname as the\n // namespace, so /chat-api in socketUrl would become /chat-api/chat namespace\n // instead of /chat. The engine path prefix is handled by the path option.\n _socket = io(`${config.socketOrigin}/chat`, {\n auth: {\n token: token ? `Bearer ${token}` : '',\n ...(config.userId && { userId: config.userId }),\n ...(config.tenantId && { tenantId: config.tenantId }),\n ...(config.avatar?.url && { avatarUrl: config.avatar.url }),\n ...(config.avatar?.base64 && { avatarBase64: config.avatar.base64 }),\n },\n // path must match SOCKET_IO_PATH on the server (default '/socket.io').\n // Set socketPath in SDK config when the server is behind a reverse proxy\n // that adds a path prefix (e.g. '/chat-api/socket.io' for UAT).\n path: config.socketPath,\n transports: ['websocket', 'polling'],\n reconnection: true,\n reconnectionAttempts: 10,\n reconnectionDelay: 1000,\n reconnectionDelayMax: 5000,\n autoConnect: true,\n });\n\n setStatus('connecting');\n\n _socket.on('connect', () => setStatus('connected'));\n _socket.on('disconnect', () => setStatus('disconnected'));\n _socket.on('connect_error', (err) => {\n console.error('[AntzChat] Socket connect_error:', err?.message, (err as any)?.data);\n setStatus('error');\n });\n _socket.on('reconnecting', () => setStatus('reconnecting'));\n _socket.on('reconnect', () => setStatus('connected'));\n\n // Lazily import store to avoid circular dependency at module load time\n _socket.on('read_receipt', (event: ReadReceiptEvent) => {\n import('../stores/chat.store.js').then(({ useChatStore }) => {\n useChatStore.getState().setLastRead(event.conversationId, event.messageId, event.readAt);\n });\n });\n\n _socket.on('user_online', (event: UserStatusEvent) => {\n import('../stores/chat.store.js').then(({ useChatStore }) => {\n const store = useChatStore.getState();\n store.setUserOnline(event.userId);\n });\n });\n\n _socket.on('user_offline', (event: UserStatusEvent) => {\n import('../stores/chat.store.js').then(({ useChatStore }) => {\n const store = useChatStore.getState();\n store.setUserOffline(event.userId);\n if (event.lastSeenAt) store.setLastSeen(event.userId, event.lastSeenAt);\n });\n });\n\n return _socket;\n}\n\nexport function disconnectSocket() {\n if (_socket) {\n _socket.disconnect();\n _socket = null;\n setStatus('disconnected');\n }\n _getToken = null;\n _userId = undefined;\n _tenantId = undefined;\n}\n\nexport function reconnectSocket(token: string, userId?: string, tenantId?: string) {\n if (_socket) {\n _socket.auth = {\n token: `Bearer ${token}`,\n ...(userId && { userId }),\n ...(tenantId && { tenantId }),\n };\n _socket.connect();\n }\n}\n\n/**\n * Updates the socket auth token from the stored getToken function and reconnects.\n * Called by SocketProvider on connect_error to handle expired-token scenarios:\n * 1. Token expired while disconnected → server rejects the reconnect handshake\n * 2. authProvider returns a fresh token → we update socket auth and retry\n *\n * Returns true if the token was updated, false if no token source is available.\n */\nexport function refreshSocketAuth(): boolean {\n if (!_socket || !_getToken) return false;\n const fresh = _getToken();\n if (!fresh) return false;\n _socket.auth = {\n token: `Bearer ${fresh}`,\n ...(_userId && { userId: _userId }),\n ...(_tenantId && { tenantId: _tenantId }),\n };\n return true;\n}\n","import type { SendMessagePayload } from '../types/index.js';\nimport { getSocket, tryGetSocket } from './socket.js';\n\nconst ACK_TIMEOUT = 5000;\n\n// withAck: for operations that need a response (send message, reactions, etc.)\n// Returns a rejected promise if socket not connected — callers should handle this.\nfunction withAck<T>(event: string, payload: unknown): Promise<T> {\n const socket = tryGetSocket();\n if (!socket) return Promise.reject(new Error(`[AntzChat] Socket not connected (event: ${event})`));\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`Socket ack timeout: ${event}`)), ACK_TIMEOUT);\n socket.emit(event, payload, (response: T) => {\n clearTimeout(timer);\n resolve(response);\n });\n });\n}\n\n// fireAndForget: for operations where missing a send is acceptable\n// (mark read, typing indicators) — silently no-ops when not connected.\nfunction fireAndForget(event: string, payload: unknown): void {\n const socket = tryGetSocket();\n if (!socket) return;\n socket.emit(event, payload);\n}\n\nexport const socketEmit = {\n joinRoom(conversationId: string) {\n fireAndForget('join_room', { conversationId });\n },\n\n leaveRoom(conversationId: string) {\n fireAndForget('leave_room', { conversationId });\n },\n\n sendMessage(payload: SendMessagePayload): Promise<unknown> {\n return withAck('send_message', payload);\n },\n\n updateMessage(messageId: string, text: string): Promise<unknown> {\n return withAck('update_message', { messageId, text });\n },\n\n deleteMessage(messageId: string): Promise<unknown> {\n return withAck('delete_message', { messageId });\n },\n\n deleteMessageForMe(messageId: string): Promise<unknown> {\n return withAck('delete_message_for_me', { messageId });\n },\n\n addReaction(messageId: string, emoji: string): Promise<unknown> {\n return withAck('add_reaction', { messageId, emoji });\n },\n\n removeReaction(messageId: string, emoji: string): Promise<unknown> {\n return withAck('remove_reaction', { messageId, emoji });\n },\n\n pinMessage(messageId: string): Promise<unknown> {\n return withAck('pin_message', { messageId });\n },\n\n unpinMessage(messageId: string): Promise<unknown> {\n return withAck('unpin_message', { messageId });\n },\n\n // markRead and typing are best-effort — silently dropped if socket not ready\n typing(conversationId: string, isTyping: boolean) {\n fireAndForget('typing', { conversationId, isTyping });\n },\n\n markRead(conversationId: string, messageId?: string) {\n fireAndForget('mark_read', { conversationId, ...(messageId ? { messageId } : {}) });\n },\n\n getOnlineUsers(userIds: string[]): Promise<string[]> {\n const socket = tryGetSocket();\n if (!socket) return Promise.resolve([]);\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error('get_online_users timeout')), ACK_TIMEOUT);\n socket.emit('get_online_users', { userIds }, (response: unknown) => {\n clearTimeout(timer);\n if (response && typeof response === 'object' && 'onlineStatus' in (response as object)) {\n const status = (response as { onlineStatus: Record<string, boolean> }).onlineStatus;\n resolve(Object.entries(status).filter(([, v]) => v).map(([k]) => k));\n } else if (Array.isArray(response)) {\n resolve(response as string[]);\n } else {\n resolve([]);\n }\n });\n });\n },\n\n getTypingUsers(conversationId: string): Promise<unknown> {\n return withAck('get_typing_users', { conversationId });\n },\n};\n","import { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\nimport type { AuthTokens, User } from '../types/index.js';\nimport type { PersistStorage } from '../config/types.js';\n\ninterface AuthState {\n user: User | null;\n tokens: AuthTokens | null;\n isAuthenticated: boolean;\n isLoading: boolean;\n isHydrated: boolean;\n\n setAuth: (user: User, tokens: AuthTokens) => void;\n setTokens: (tokens: AuthTokens) => void;\n setUser: (user: User) => void;\n logout: () => void;\n setLoading: (loading: boolean) => void;\n setHydrated: (hydrated: boolean) => void;\n}\n\n/**\n * Creates a platform-specific auth store.\n * Call once during SDK init with the platform's PersistStorage adapter.\n * - Web: pass a localStorage adapter\n * - RN: pass an AsyncStorage adapter\n */\nexport function createAuthStore(storage: PersistStorage) {\n if (!storage) throw new Error('[AntzChat] createAuthStore requires a valid PersistStorage — received undefined. Make sure the SDK config is fully resolved before initializing the store.');\n // Use a ref object so the onRehydrateStorage closure can call store.setState\n // without hitting a temporal dead zone. On web, localStorage is synchronous\n // and onRehydrateStorage fires during create() before `store` is assigned.\n const ref: { store: any } = { store: null };\n\n const store = create<AuthState>()(\n persist(\n (set) => ({\n user: null,\n tokens: null,\n isAuthenticated: false,\n isLoading: false,\n isHydrated: false,\n\n setAuth: (user, tokens) =>\n set({ user, tokens, isAuthenticated: true, isLoading: false }),\n\n setTokens: (tokens) => set({ tokens }),\n\n setUser: (user) => set({ user }),\n\n logout: () =>\n set({ user: null, tokens: null, isAuthenticated: false, isLoading: false }),\n\n setLoading: (isLoading) => set({ isLoading }),\n\n setHydrated: (isHydrated) => set({ isHydrated }),\n }),\n {\n name: 'antz-chat-auth',\n storage: {\n getItem: (name) => {\n const result = storage.getItem(name);\n if (result instanceof Promise) {\n return result.then((str) => (str ? JSON.parse(str) : null));\n }\n return result ? JSON.parse(result) : null;\n },\n setItem: (name, value) => {\n storage.setItem(name, JSON.stringify(value));\n },\n removeItem: (name) => storage.removeItem(name),\n },\n partialize: (state) => ({\n user: state.user,\n tokens: state.tokens,\n isAuthenticated: state.isAuthenticated,\n }) as AuthState,\n onRehydrateStorage: () => (state, error) => {\n if (error) {\n console.warn('[AntzChat] Auth store rehydration failed:', error);\n }\n // Access via ref — safe even when called synchronously during create()\n ref.store?.setState({ isHydrated: true });\n },\n },\n ),\n );\n\n // Assign ref immediately after create() completes\n ref.store = store;\n\n // If already hydrated synchronously (web/localStorage rehydrated during create),\n // set the flag now since the closure above may have called ref.store when it was null.\n if (!store.getState().isHydrated) {\n // Fallback: async storage (RN) — force hydrated after 3s max\n const hydrationTimeout = setTimeout(() => {\n if (!store.getState().isHydrated) {\n store.setState({ isHydrated: true });\n }\n }, 3000);\n\n // Clean up if it resolves naturally before timeout\n const unsub = store.subscribe((s) => {\n if (s.isHydrated) {\n clearTimeout(hydrationTimeout);\n unsub();\n }\n });\n }\n\n const tokenStore = {\n getAccessToken: () => store.getState().tokens?.accessToken,\n getRefreshToken: () => store.getState().tokens?.refreshToken,\n setTokens: (tokens: AuthTokens) => store.getState().setTokens(tokens),\n clearTokens: () => store.getState().logout(),\n };\n\n return { useAuthStore: store, authTokenStore: tokenStore };\n}\n\n// ─── Singleton instances (set during SDK init) ────────────────────────────────\n// Each SDK (web / RN) calls createAuthStore once and exports these.\n// Direct import of these will throw until initAuthStore is called.\n\nlet _authStore: ReturnType<typeof createAuthStore> | null = null;\n\n/**\n * Initialize the auth store singleton.\n * Idempotent — subsequent calls with the same storage return the existing instance.\n * This ensures tokens persisted in localStorage/AsyncStorage survive re-renders\n * and React StrictMode double-invocations.\n */\nexport function initAuthStore(storage: PersistStorage) {\n if (!_authStore) {\n _authStore = createAuthStore(storage);\n }\n return _authStore;\n}\n\nexport function getAuthStore() {\n if (!_authStore) throw new Error('[AntzChat] Auth store not initialized. Call initAuthStore first.');\n return _authStore;\n}\n\n/** Reset the singleton — only for tests / SDK teardown. */\nexport function resetAuthStore() {\n _authStore = null;\n}\n","import type { AntzChatConfig, PlatformUploadFn } from './config/types.js';\nimport { resolveConfig } from './config/types.js';\nimport { initApiClient, setApiClientInstance } from './api/client.js';\nimport { initAuthStore } from './stores/auth.store.js';\nimport { authApi } from './api/auth.js';\nimport { messagesApi } from './api/messages.js';\nimport { conversationsApi } from './api/conversations.js';\nimport { storageApi, uploadBatch } from './api/storage.js';\nimport { usersApi } from './api/users.js';\nimport { connectSocket, disconnectSocket, getSocket } from './socket/socket.js';\nimport { socketEmit } from './socket/emitters.js';\nimport type { UploadableFile } from './types/index.js';\n\ninterface ClientSocketHandle {\n emit: typeof socketEmit;\n on(event: string, handler: (...args: unknown[]) => void): void;\n off(event: string, handler: (...args: unknown[]) => void): void;\n}\n\n/**\n * Headless client for non-React consumers or direct programmatic use.\n * Usage:\n * const client = new AntzChatClient({ apiUrl, authToken, platformUploadFn, persistStorage })\n * await client.connect()\n */\nexport class AntzChatClient {\n private _config;\n private _authStore;\n\n readonly auth = authApi;\n readonly messages = messagesApi;\n readonly conversations = conversationsApi;\n readonly storage = storageApi;\n readonly users = usersApi;\n readonly socket: ClientSocketHandle = {\n emit: socketEmit,\n on: (event, handler) => getSocket().on(event, handler as (...args: any[]) => void),\n off: (event, handler) => getSocket().off(event, handler as (...args: any[]) => void),\n };\n\n constructor(rawConfig: AntzChatConfig) {\n this._config = resolveConfig(rawConfig);\n this._authStore = initAuthStore(rawConfig.persistStorage);\n\n if (rawConfig.authToken) {\n this._authStore.authTokenStore.setTokens({\n accessToken: rawConfig.authToken,\n refreshToken: '',\n tokenType: 'Bearer',\n expiresIn: 0,\n });\n }\n\n const instance = initApiClient(this._config, this._authStore.authTokenStore);\n setApiClientInstance(instance);\n }\n\n async connect(): Promise<void> {\n await connectSocket(this._config, () => this._authStore.authTokenStore.getAccessToken());\n }\n\n disconnect(): void {\n disconnectSocket();\n }\n\n uploadFiles(files: UploadableFile[], conversationId?: string) {\n return uploadBatch(files, this._config.platformUploadFn, conversationId, this._config.upload.onProgress);\n }\n\n async uploadIcon(conversationId: string, file: UploadableFile) {\n const result = await this.uploadFiles([file], conversationId);\n const fileId = result.successful[0]?.id;\n if (!fileId) throw new Error('Icon upload failed');\n return conversationsApi.uploadIcon(conversationId, fileId);\n }\n}\n"],"mappings":"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","names":["axios","useChatStore","import_zustand"]}
package/dist/index.d.cts CHANGED
@@ -636,16 +636,11 @@ declare const conversationsApi: {
636
636
  */
637
637
  getUnreadSummary(): Promise<UnreadSummary>;
638
638
  /**
639
- * Upload or replace the group icon (admin only).
640
- * Accepts a File (web) or { uri, name, type } object (React Native).
641
- * The server stores the image in its own storage, deletes the previous icon,
642
- * and returns a fresh signed iconUrl on every subsequent response.
639
+ * Set the group icon from an already-uploaded file (admin only).
640
+ * The fileId comes from uploadBatch() / client.uploadFiles() same as attachments.
641
+ * Server copies storageKey into conversation.iconMeta and deletes the chat_files record.
643
642
  */
644
- uploadIcon(conversationId: string, file: File | {
645
- uri: string;
646
- name: string;
647
- type: string;
648
- }): Promise<Conversation>;
643
+ uploadIcon(conversationId: string, fileId: string): Promise<Conversation>;
649
644
  };
650
645
 
651
646
  declare const storageApi: {
@@ -1014,11 +1009,7 @@ declare class AntzChatClient {
1014
1009
  getMembers(conversationId: string): Promise<User[]>;
1015
1010
  getUnreadCount(conversationId: string): Promise<ConversationUnreadCount>;
1016
1011
  getUnreadSummary(): Promise<UnreadSummary>;
1017
- uploadIcon(conversationId: string, file: File | {
1018
- uri: string;
1019
- name: string;
1020
- type: string;
1021
- }): Promise<Conversation>;
1012
+ uploadIcon(conversationId: string, fileId: string): Promise<Conversation>;
1022
1013
  };
1023
1014
  readonly storage: {
1024
1015
  requestPresignedUrl(payload: PresignedUrlRequest): Promise<PresignedUrlResponse>;
@@ -1064,6 +1055,7 @@ declare class AntzChatClient {
1064
1055
  connect(): Promise<void>;
1065
1056
  disconnect(): void;
1066
1057
  uploadFiles(files: UploadableFile[], conversationId?: string): Promise<BatchUploadResult>;
1058
+ uploadIcon(conversationId: string, file: UploadableFile): Promise<Conversation>;
1067
1059
  }
1068
1060
 
1069
1061
  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 };