@antzsoft/chat-core 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -28,6 +28,8 @@ interface User {
28
28
  tenantId: string;
29
29
  email: string;
30
30
  username: string;
31
+ firstName?: string;
32
+ lastName?: string;
31
33
  displayName: string;
32
34
  avatarUrl?: string;
33
35
  phone?: string;
@@ -54,7 +56,9 @@ interface RegisterData {
54
56
  email: string;
55
57
  password: string;
56
58
  username: string;
57
- displayName: string;
59
+ firstName: string;
60
+ lastName: string;
61
+ displayName?: string;
58
62
  phone?: string;
59
63
  tenantId?: string;
60
64
  }
@@ -135,9 +139,14 @@ interface Participant {
135
139
  isActive?: boolean;
136
140
  user?: User;
137
141
  }
142
+ interface MessageConfig {
143
+ editWindowSeconds?: number;
144
+ deleteWindowSeconds?: number;
145
+ }
138
146
  interface ConversationSettings {
139
147
  onlyAdminsCanMessage?: boolean;
140
148
  onlyAdminsCanAddMembers?: boolean;
149
+ messageConfig?: MessageConfig;
141
150
  }
142
151
  interface Conversation {
143
152
  id: string;
@@ -243,6 +252,10 @@ interface MessageDeletedEvent {
243
252
  messageId: string;
244
253
  conversationId: string;
245
254
  }
255
+ interface MessageDeletedForMeEvent {
256
+ messageId: string;
257
+ conversationId: string;
258
+ }
246
259
  interface ReactionUpdatedEvent {
247
260
  messageId: string;
248
261
  conversationId: string;
@@ -376,6 +389,18 @@ interface AntzChatConfig {
376
389
  * Not needed for builtin mode (chat server issues its own JWTs).
377
390
  */
378
391
  userId?: string;
392
+ /**
393
+ * Profile picture for non-builtin modes.
394
+ * Server fetches/decodes, hashes for dedup, uploads to chat storage on first use.
395
+ * Only sent once at init — not re-sent on every request.
396
+ * Client never needs to compute hashes; the server owns all dedup logic.
397
+ */
398
+ avatar?: {
399
+ /** Full URL the server can fetch (preferred — Antz/external/wso2 clients know their own file URLs) */
400
+ url?: string;
401
+ /** Raw base64 string (with or without data:... prefix) as fallback */
402
+ base64?: string;
403
+ };
379
404
  /** Required for multi-tenant backends. Sent as X-Tenant-ID header. */
380
405
  tenantId?: string;
381
406
  /** Must match server ENCRYPTION_MODE env var. Default: 'none' */
@@ -402,10 +427,16 @@ interface ResolvedFileSizeLimits {
402
427
  interface ResolvedConfig {
403
428
  apiUrl: string;
404
429
  socketUrl: string;
430
+ socketOrigin: string;
431
+ socketPath: string;
405
432
  authToken?: string;
406
433
  authProvider?: () => Promise<string>;
407
434
  userId?: string;
408
435
  tenantId?: string;
436
+ avatar?: {
437
+ url?: string;
438
+ base64?: string;
439
+ };
409
440
  encryptionMode: 'none' | 'server';
410
441
  upload: {
411
442
  maxFileSizeMB: ResolvedFileSizeLimits;
@@ -426,6 +457,15 @@ declare const authApi: {
426
457
  logout(refreshToken?: string): Promise<void>;
427
458
  logoutAll(): Promise<void>;
428
459
  getMe(): Promise<User>;
460
+ uploadAvatar(file: File | Blob, mimeType?: string): Promise<{
461
+ avatarUrl: string;
462
+ }>;
463
+ syncAvatar(source: {
464
+ url?: string;
465
+ base64?: string;
466
+ }): Promise<{
467
+ avatarUrl: string;
468
+ }>;
429
469
  };
430
470
 
431
471
  interface ListMessagesParams {
@@ -452,6 +492,7 @@ declare const messagesApi: {
452
492
  send(conversationId: string, payload: SendData): Promise<Message>;
453
493
  update(messageId: string, text: string): Promise<Message>;
454
494
  delete(messageId: string): Promise<void>;
495
+ deleteForMe(messageId: string): Promise<void>;
455
496
  addReaction(messageId: string, emoji: string): Promise<Message>;
456
497
  removeReaction(messageId: string, emoji: string): Promise<Message>;
457
498
  star(messageId: string): Promise<void>;
@@ -608,9 +649,18 @@ declare function getSocket(): Socket;
608
649
  declare function tryGetSocket(): Socket | null;
609
650
  declare function getSocketStatus(): SocketStatus;
610
651
  declare function onSocketStatus(listener: StatusListener): () => void;
611
- declare function connectSocket(config: ResolvedConfig, getToken: () => string | null | undefined): Promise<Socket>;
652
+ declare function connectSocket(config: ResolvedConfig, getToken: () => string | null | undefined, userId?: string, tenantId?: string): Promise<Socket>;
612
653
  declare function disconnectSocket(): void;
613
- declare function reconnectSocket(token: string): void;
654
+ declare function reconnectSocket(token: string, userId?: string, tenantId?: string): void;
655
+ /**
656
+ * Updates the socket auth token from the stored getToken function and reconnects.
657
+ * Called by SocketProvider on connect_error to handle expired-token scenarios:
658
+ * 1. Token expired while disconnected → server rejects the reconnect handshake
659
+ * 2. authProvider returns a fresh token → we update socket auth and retry
660
+ *
661
+ * Returns true if the token was updated, false if no token source is available.
662
+ */
663
+ declare function refreshSocketAuth(): boolean;
614
664
 
615
665
  declare const socketEmit: {
616
666
  joinRoom(conversationId: string): void;
@@ -618,6 +668,7 @@ declare const socketEmit: {
618
668
  sendMessage(payload: SendMessagePayload): Promise<unknown>;
619
669
  updateMessage(messageId: string, text: string): Promise<unknown>;
620
670
  deleteMessage(messageId: string): Promise<unknown>;
671
+ deleteMessageForMe(messageId: string): Promise<unknown>;
621
672
  addReaction(messageId: string, emoji: string): Promise<unknown>;
622
673
  removeReaction(messageId: string, emoji: string): Promise<unknown>;
623
674
  pinMessage(messageId: string): Promise<unknown>;
@@ -773,6 +824,15 @@ declare class AntzChatClient {
773
824
  logout(refreshToken?: string): Promise<void>;
774
825
  logoutAll(): Promise<void>;
775
826
  getMe(): Promise<User>;
827
+ uploadAvatar(file: File | Blob, mimeType?: string): Promise<{
828
+ avatarUrl: string;
829
+ }>;
830
+ syncAvatar(source: {
831
+ url?: string;
832
+ base64?: string;
833
+ }): Promise<{
834
+ avatarUrl: string;
835
+ }>;
776
836
  };
777
837
  readonly messages: {
778
838
  list(conversationId: string, params?: ListMessagesParams): Promise<CursorPaginatedResponse<Message>>;
@@ -780,6 +840,7 @@ declare class AntzChatClient {
780
840
  send(conversationId: string, payload: SendData): Promise<Message>;
781
841
  update(messageId: string, text: string): Promise<Message>;
782
842
  delete(messageId: string): Promise<void>;
843
+ deleteForMe(messageId: string): Promise<void>;
783
844
  addReaction(messageId: string, emoji: string): Promise<Message>;
784
845
  removeReaction(messageId: string, emoji: string): Promise<Message>;
785
846
  star(messageId: string): Promise<void>;
@@ -849,4 +910,4 @@ declare class AntzChatClient {
849
910
  uploadFiles(files: UploadableFile[], conversationId?: string): Promise<BatchUploadResult>;
850
911
  }
851
912
 
852
- export { AntzChatClient, type AntzChatConfig, type Attachment, type AuthResponse, type AuthTokens, type BatchUploadResult, type Conversation, type CreateDirectData, type CreateGroupData, type CursorPaginatedResponse, type EncryptedContent, type EncryptionKeyInfo, type EncryptionMode, type FileResponse, type FileSizeLimits, type FileType, type ListMessagesParams, type LoginCredentials, type Message, type MessageAckEvent, type MessageContent, type MessageDeletedEvent, type MessageDeliveredEvent, type MessageReaction, type MessageReplyReference, type MessageUpdatedEvent, type MessagesDeliveredEvent, type MobileDeviceToken, type NewMessageEvent, type OptimisticAttachment, type PaginatedResponse, type Participant, type PersistStorage, type PlatformUploadFn, type PresignedUrlRequest, type PresignedUrlResponse, type ReactionUpdatedEvent, type ReadReceiptEvent, type RegisterData, type RegisterDeviceTokenPayload, type ResolvedConfig, type ResolvedFileSizeLimits, type SearchParams, type SendData, type SendMessageAttachment, type SendMessagePayload, type SocketStatus, type StatusListener, type TokenStore, type TypingIndicatorEvent, type UpdateConversationData, type UploadConfig, type UploadProgress, type UploadableFile, type User, type UserStatusEvent, type WebPushDeviceToken, authApi, connectSocket, conversationsApi, createAuthStore, devicesApi, disconnectSocket, getApiClient, getAuthStore, getSocket, getSocketStatus, initApiClient, initAuthStore, messagesApi, normalizeConversation, onSocketStatus, reconnectSocket, resetAuthStore, resolveConfig, setApiClientInstance, socketEmit, storageApi, tryGetSocket, uploadBatch, useChatStore };
913
+ export { AntzChatClient, type AntzChatConfig, type Attachment, type AuthResponse, type AuthTokens, type BatchUploadResult, type Conversation, type CreateDirectData, type CreateGroupData, type CursorPaginatedResponse, type EncryptedContent, type EncryptionKeyInfo, type EncryptionMode, type FileResponse, type FileSizeLimits, type FileType, type ListMessagesParams, type LoginCredentials, type Message, type MessageAckEvent, type MessageContent, type MessageDeletedEvent, type 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 ReactionUpdatedEvent, type ReadReceiptEvent, type RegisterData, type RegisterDeviceTokenPayload, type ResolvedConfig, type ResolvedFileSizeLimits, type SearchParams, type SendData, type SendMessageAttachment, type SendMessagePayload, type SocketStatus, type StatusListener, type TokenStore, type TypingIndicatorEvent, type UpdateConversationData, type UploadConfig, type UploadProgress, type UploadableFile, type User, type UserStatusEvent, type WebPushDeviceToken, authApi, connectSocket, conversationsApi, createAuthStore, devicesApi, disconnectSocket, getApiClient, getAuthStore, getSocket, getSocketStatus, initApiClient, initAuthStore, messagesApi, normalizeConversation, onSocketStatus, reconnectSocket, refreshSocketAuth, resetAuthStore, resolveConfig, setApiClientInstance, socketEmit, storageApi, tryGetSocket, uploadBatch, useChatStore };
package/dist/index.d.ts CHANGED
@@ -28,6 +28,8 @@ interface User {
28
28
  tenantId: string;
29
29
  email: string;
30
30
  username: string;
31
+ firstName?: string;
32
+ lastName?: string;
31
33
  displayName: string;
32
34
  avatarUrl?: string;
33
35
  phone?: string;
@@ -54,7 +56,9 @@ interface RegisterData {
54
56
  email: string;
55
57
  password: string;
56
58
  username: string;
57
- displayName: string;
59
+ firstName: string;
60
+ lastName: string;
61
+ displayName?: string;
58
62
  phone?: string;
59
63
  tenantId?: string;
60
64
  }
@@ -135,9 +139,14 @@ interface Participant {
135
139
  isActive?: boolean;
136
140
  user?: User;
137
141
  }
142
+ interface MessageConfig {
143
+ editWindowSeconds?: number;
144
+ deleteWindowSeconds?: number;
145
+ }
138
146
  interface ConversationSettings {
139
147
  onlyAdminsCanMessage?: boolean;
140
148
  onlyAdminsCanAddMembers?: boolean;
149
+ messageConfig?: MessageConfig;
141
150
  }
142
151
  interface Conversation {
143
152
  id: string;
@@ -243,6 +252,10 @@ interface MessageDeletedEvent {
243
252
  messageId: string;
244
253
  conversationId: string;
245
254
  }
255
+ interface MessageDeletedForMeEvent {
256
+ messageId: string;
257
+ conversationId: string;
258
+ }
246
259
  interface ReactionUpdatedEvent {
247
260
  messageId: string;
248
261
  conversationId: string;
@@ -376,6 +389,18 @@ interface AntzChatConfig {
376
389
  * Not needed for builtin mode (chat server issues its own JWTs).
377
390
  */
378
391
  userId?: string;
392
+ /**
393
+ * Profile picture for non-builtin modes.
394
+ * Server fetches/decodes, hashes for dedup, uploads to chat storage on first use.
395
+ * Only sent once at init — not re-sent on every request.
396
+ * Client never needs to compute hashes; the server owns all dedup logic.
397
+ */
398
+ avatar?: {
399
+ /** Full URL the server can fetch (preferred — Antz/external/wso2 clients know their own file URLs) */
400
+ url?: string;
401
+ /** Raw base64 string (with or without data:... prefix) as fallback */
402
+ base64?: string;
403
+ };
379
404
  /** Required for multi-tenant backends. Sent as X-Tenant-ID header. */
380
405
  tenantId?: string;
381
406
  /** Must match server ENCRYPTION_MODE env var. Default: 'none' */
@@ -402,10 +427,16 @@ interface ResolvedFileSizeLimits {
402
427
  interface ResolvedConfig {
403
428
  apiUrl: string;
404
429
  socketUrl: string;
430
+ socketOrigin: string;
431
+ socketPath: string;
405
432
  authToken?: string;
406
433
  authProvider?: () => Promise<string>;
407
434
  userId?: string;
408
435
  tenantId?: string;
436
+ avatar?: {
437
+ url?: string;
438
+ base64?: string;
439
+ };
409
440
  encryptionMode: 'none' | 'server';
410
441
  upload: {
411
442
  maxFileSizeMB: ResolvedFileSizeLimits;
@@ -426,6 +457,15 @@ declare const authApi: {
426
457
  logout(refreshToken?: string): Promise<void>;
427
458
  logoutAll(): Promise<void>;
428
459
  getMe(): Promise<User>;
460
+ uploadAvatar(file: File | Blob, mimeType?: string): Promise<{
461
+ avatarUrl: string;
462
+ }>;
463
+ syncAvatar(source: {
464
+ url?: string;
465
+ base64?: string;
466
+ }): Promise<{
467
+ avatarUrl: string;
468
+ }>;
429
469
  };
430
470
 
431
471
  interface ListMessagesParams {
@@ -452,6 +492,7 @@ declare const messagesApi: {
452
492
  send(conversationId: string, payload: SendData): Promise<Message>;
453
493
  update(messageId: string, text: string): Promise<Message>;
454
494
  delete(messageId: string): Promise<void>;
495
+ deleteForMe(messageId: string): Promise<void>;
455
496
  addReaction(messageId: string, emoji: string): Promise<Message>;
456
497
  removeReaction(messageId: string, emoji: string): Promise<Message>;
457
498
  star(messageId: string): Promise<void>;
@@ -608,9 +649,18 @@ declare function getSocket(): Socket;
608
649
  declare function tryGetSocket(): Socket | null;
609
650
  declare function getSocketStatus(): SocketStatus;
610
651
  declare function onSocketStatus(listener: StatusListener): () => void;
611
- declare function connectSocket(config: ResolvedConfig, getToken: () => string | null | undefined): Promise<Socket>;
652
+ declare function connectSocket(config: ResolvedConfig, getToken: () => string | null | undefined, userId?: string, tenantId?: string): Promise<Socket>;
612
653
  declare function disconnectSocket(): void;
613
- declare function reconnectSocket(token: string): void;
654
+ declare function reconnectSocket(token: string, userId?: string, tenantId?: string): void;
655
+ /**
656
+ * Updates the socket auth token from the stored getToken function and reconnects.
657
+ * Called by SocketProvider on connect_error to handle expired-token scenarios:
658
+ * 1. Token expired while disconnected → server rejects the reconnect handshake
659
+ * 2. authProvider returns a fresh token → we update socket auth and retry
660
+ *
661
+ * Returns true if the token was updated, false if no token source is available.
662
+ */
663
+ declare function refreshSocketAuth(): boolean;
614
664
 
615
665
  declare const socketEmit: {
616
666
  joinRoom(conversationId: string): void;
@@ -618,6 +668,7 @@ declare const socketEmit: {
618
668
  sendMessage(payload: SendMessagePayload): Promise<unknown>;
619
669
  updateMessage(messageId: string, text: string): Promise<unknown>;
620
670
  deleteMessage(messageId: string): Promise<unknown>;
671
+ deleteMessageForMe(messageId: string): Promise<unknown>;
621
672
  addReaction(messageId: string, emoji: string): Promise<unknown>;
622
673
  removeReaction(messageId: string, emoji: string): Promise<unknown>;
623
674
  pinMessage(messageId: string): Promise<unknown>;
@@ -773,6 +824,15 @@ declare class AntzChatClient {
773
824
  logout(refreshToken?: string): Promise<void>;
774
825
  logoutAll(): Promise<void>;
775
826
  getMe(): Promise<User>;
827
+ uploadAvatar(file: File | Blob, mimeType?: string): Promise<{
828
+ avatarUrl: string;
829
+ }>;
830
+ syncAvatar(source: {
831
+ url?: string;
832
+ base64?: string;
833
+ }): Promise<{
834
+ avatarUrl: string;
835
+ }>;
776
836
  };
777
837
  readonly messages: {
778
838
  list(conversationId: string, params?: ListMessagesParams): Promise<CursorPaginatedResponse<Message>>;
@@ -780,6 +840,7 @@ declare class AntzChatClient {
780
840
  send(conversationId: string, payload: SendData): Promise<Message>;
781
841
  update(messageId: string, text: string): Promise<Message>;
782
842
  delete(messageId: string): Promise<void>;
843
+ deleteForMe(messageId: string): Promise<void>;
783
844
  addReaction(messageId: string, emoji: string): Promise<Message>;
784
845
  removeReaction(messageId: string, emoji: string): Promise<Message>;
785
846
  star(messageId: string): Promise<void>;
@@ -849,4 +910,4 @@ declare class AntzChatClient {
849
910
  uploadFiles(files: UploadableFile[], conversationId?: string): Promise<BatchUploadResult>;
850
911
  }
851
912
 
852
- export { AntzChatClient, type AntzChatConfig, type Attachment, type AuthResponse, type AuthTokens, type BatchUploadResult, type Conversation, type CreateDirectData, type CreateGroupData, type CursorPaginatedResponse, type EncryptedContent, type EncryptionKeyInfo, type EncryptionMode, type FileResponse, type FileSizeLimits, type FileType, type ListMessagesParams, type LoginCredentials, type Message, type MessageAckEvent, type MessageContent, type MessageDeletedEvent, type MessageDeliveredEvent, type MessageReaction, type MessageReplyReference, type MessageUpdatedEvent, type MessagesDeliveredEvent, type MobileDeviceToken, type NewMessageEvent, type OptimisticAttachment, type PaginatedResponse, type Participant, type PersistStorage, type PlatformUploadFn, type PresignedUrlRequest, type PresignedUrlResponse, type ReactionUpdatedEvent, type ReadReceiptEvent, type RegisterData, type RegisterDeviceTokenPayload, type ResolvedConfig, type ResolvedFileSizeLimits, type SearchParams, type SendData, type SendMessageAttachment, type SendMessagePayload, type SocketStatus, type StatusListener, type TokenStore, type TypingIndicatorEvent, type UpdateConversationData, type UploadConfig, type UploadProgress, type UploadableFile, type User, type UserStatusEvent, type WebPushDeviceToken, authApi, connectSocket, conversationsApi, createAuthStore, devicesApi, disconnectSocket, getApiClient, getAuthStore, getSocket, getSocketStatus, initApiClient, initAuthStore, messagesApi, normalizeConversation, onSocketStatus, reconnectSocket, resetAuthStore, resolveConfig, setApiClientInstance, socketEmit, storageApi, tryGetSocket, uploadBatch, useChatStore };
913
+ export { AntzChatClient, type AntzChatConfig, type Attachment, type AuthResponse, type AuthTokens, type BatchUploadResult, type Conversation, type CreateDirectData, type CreateGroupData, type CursorPaginatedResponse, type EncryptedContent, type EncryptionKeyInfo, type EncryptionMode, type FileResponse, type FileSizeLimits, type FileType, type ListMessagesParams, type LoginCredentials, type Message, type MessageAckEvent, type MessageContent, type MessageDeletedEvent, type 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 ReactionUpdatedEvent, type ReadReceiptEvent, type RegisterData, type RegisterDeviceTokenPayload, type ResolvedConfig, type ResolvedFileSizeLimits, type SearchParams, type SendData, type SendMessageAttachment, type SendMessagePayload, type SocketStatus, type StatusListener, type TokenStore, type TypingIndicatorEvent, type UpdateConversationData, type UploadConfig, type UploadProgress, type UploadableFile, type User, type UserStatusEvent, type WebPushDeviceToken, authApi, connectSocket, conversationsApi, createAuthStore, devicesApi, disconnectSocket, getApiClient, getAuthStore, getSocket, getSocketStatus, initApiClient, initAuthStore, messagesApi, normalizeConversation, onSocketStatus, reconnectSocket, refreshSocketAuth, resetAuthStore, resolveConfig, setApiClientInstance, socketEmit, storageApi, tryGetSocket, uploadBatch, useChatStore };
package/dist/index.js CHANGED
@@ -1,6 +1,15 @@
1
1
  // src/config/types.ts
2
2
  function resolveConfig(config) {
3
3
  const socketUrl = config.socketUrl ?? config.apiUrl.replace(/\/api\/v\d+\/?$/, "").replace(/\/$/, "");
4
+ let socketOrigin = socketUrl;
5
+ let socketPath = "/socket.io";
6
+ try {
7
+ const parsed = new URL(socketUrl);
8
+ socketOrigin = parsed.origin;
9
+ const pathname = parsed.pathname.replace(/\/$/, "");
10
+ if (pathname && pathname !== "/") socketPath = `${pathname}/socket.io`;
11
+ } catch {
12
+ }
4
13
  const raw = config.upload?.maxFileSizeMB;
5
14
  let limits;
6
15
  if (typeof raw === "number") {
@@ -18,10 +27,13 @@ function resolveConfig(config) {
18
27
  return {
19
28
  apiUrl: config.apiUrl.replace(/\/$/, ""),
20
29
  socketUrl,
30
+ socketOrigin,
31
+ socketPath,
21
32
  authToken: config.authToken,
22
33
  authProvider: config.authProvider,
23
34
  userId: config.userId,
24
35
  tenantId: config.tenantId,
36
+ avatar: config.avatar,
25
37
  encryptionMode: config.encryptionMode ?? "none",
26
38
  upload: {
27
39
  maxFileSizeMB: limits,
@@ -39,9 +51,11 @@ function resolveConfig(config) {
39
51
  import axios from "axios";
40
52
  var _tokenStore = null;
41
53
  var _config = null;
54
+ var _avatarSent = false;
42
55
  function initApiClient(config, tokenStore) {
43
56
  _config = config;
44
57
  _tokenStore = tokenStore;
58
+ _avatarSent = false;
45
59
  const client = axios.create({
46
60
  baseURL: config.apiUrl,
47
61
  headers: { "Content-Type": "application/json" }
@@ -51,6 +65,11 @@ function initApiClient(config, tokenStore) {
51
65
  if (token) req.headers["Authorization"] = `Bearer ${token}`;
52
66
  if (_config?.userId) req.headers["x-user-id"] = _config.userId;
53
67
  if (_config?.tenantId) req.headers["X-Tenant-ID"] = _config.tenantId;
68
+ if (token && !_avatarSent && _config?.avatar) {
69
+ if (_config.avatar.base64) req.headers["x-avatar-base64"] = _config.avatar.base64;
70
+ else if (_config.avatar.url) req.headers["x-avatar-url"] = _config.avatar.url;
71
+ _avatarSent = true;
72
+ }
54
73
  return req;
55
74
  });
56
75
  let isRefreshing = false;
@@ -135,6 +154,23 @@ var authApi = {
135
154
  async getMe() {
136
155
  const { data } = await getApiClient().get("/users/me");
137
156
  return data;
157
+ },
158
+ // Upload a new avatar file (builtin mode — multipart)
159
+ async uploadAvatar(file, mimeType) {
160
+ const form = new FormData();
161
+ form.append("avatar", file instanceof File ? file : new File([file], "avatar.jpg", { type: mimeType ?? "image/jpeg" }));
162
+ const { data } = await getApiClient().put("/users/me/avatar", form, {
163
+ headers: { "Content-Type": "multipart/form-data" }
164
+ });
165
+ return data;
166
+ },
167
+ // Sync avatar from URL or base64 (non-builtin modes — or post-init update)
168
+ async syncAvatar(source) {
169
+ const headers = {};
170
+ if (source.base64) headers["x-avatar-base64"] = source.base64;
171
+ else if (source.url) headers["x-avatar-url"] = source.url;
172
+ const { data } = await getApiClient().post("/users/me/avatar/sync", {}, { headers });
173
+ return data;
138
174
  }
139
175
  };
140
176
 
@@ -165,6 +201,9 @@ var messagesApi = {
165
201
  async delete(messageId) {
166
202
  await getApiClient().delete(`/messages/${messageId}`);
167
203
  },
204
+ async deleteForMe(messageId) {
205
+ await getApiClient().delete(`/messages/${messageId}/for-me`);
206
+ },
168
207
  async addReaction(messageId, emoji) {
169
208
  const { data } = await getApiClient().post(`/messages/${messageId}/reactions`, { emoji });
170
209
  return data;
@@ -213,6 +252,7 @@ function normalizeParticipant(p) {
213
252
  userId: p.userId,
214
253
  role: p.role,
215
254
  joinedAt: p.joinedAt,
255
+ isActive: p.isActive,
216
256
  user: hasUserDetails ? {
217
257
  id: p.userId,
218
258
  tenantId: "",
@@ -239,7 +279,7 @@ function normalizeLastMessage(lastMsg) {
239
279
  text: lastMsg.contentPreview
240
280
  },
241
281
  reactions: [],
242
- status: "sent",
282
+ status: lastMsg.status ?? "sent",
243
283
  isEdited: false,
244
284
  sentAt: lastMsg.sentAt ?? "",
245
285
  createdAt: lastMsg.sentAt ?? ""
@@ -428,6 +468,9 @@ import { io } from "socket.io-client";
428
468
  var _socket = null;
429
469
  var _status = "disconnected";
430
470
  var _statusListeners = /* @__PURE__ */ new Set();
471
+ var _getToken = null;
472
+ var _userId;
473
+ var _tenantId;
431
474
  function setStatus(s) {
432
475
  _status = s;
433
476
  _statusListeners.forEach((l) => l(s));
@@ -446,11 +489,24 @@ function onSocketStatus(listener) {
446
489
  _statusListeners.add(listener);
447
490
  return () => _statusListeners.delete(listener);
448
491
  }
449
- async function connectSocket(config, getToken) {
492
+ async function connectSocket(config, getToken, userId, tenantId) {
450
493
  if (_socket?.connected) return _socket;
494
+ _getToken = getToken;
495
+ _userId = userId;
496
+ _tenantId = tenantId;
451
497
  const token = getToken();
452
- _socket = io(`${config.socketUrl}/chat`, {
453
- auth: { token: token ? `Bearer ${token}` : "" },
498
+ _socket = io(`${config.socketOrigin}/chat`, {
499
+ auth: {
500
+ token: token ? `Bearer ${token}` : "",
501
+ ...userId && { userId },
502
+ ...tenantId && { tenantId },
503
+ ...config.avatar?.url && { avatarUrl: config.avatar.url },
504
+ ...config.avatar?.base64 && { avatarBase64: config.avatar.base64 }
505
+ },
506
+ // path must match SOCKET_IO_PATH on the server (default '/socket.io').
507
+ // Set socketPath in SDK config when the server is behind a reverse proxy
508
+ // that adds a path prefix (e.g. '/chat-api/socket.io' for UAT).
509
+ path: config.socketPath,
454
510
  transports: ["websocket", "polling"],
455
511
  reconnection: true,
456
512
  reconnectionAttempts: 10,
@@ -472,13 +528,31 @@ function disconnectSocket() {
472
528
  _socket = null;
473
529
  setStatus("disconnected");
474
530
  }
531
+ _getToken = null;
532
+ _userId = void 0;
533
+ _tenantId = void 0;
475
534
  }
476
- function reconnectSocket(token) {
535
+ function reconnectSocket(token, userId, tenantId) {
477
536
  if (_socket) {
478
- _socket.auth = { token: `Bearer ${token}` };
537
+ _socket.auth = {
538
+ token: `Bearer ${token}`,
539
+ ...userId && { userId },
540
+ ...tenantId && { tenantId }
541
+ };
479
542
  _socket.connect();
480
543
  }
481
544
  }
545
+ function refreshSocketAuth() {
546
+ if (!_socket || !_getToken) return false;
547
+ const fresh = _getToken();
548
+ if (!fresh) return false;
549
+ _socket.auth = {
550
+ token: `Bearer ${fresh}`,
551
+ ..._userId && { userId: _userId },
552
+ ..._tenantId && { tenantId: _tenantId }
553
+ };
554
+ return true;
555
+ }
482
556
 
483
557
  // src/socket/emitters.ts
484
558
  var ACK_TIMEOUT = 5e3;
@@ -514,6 +588,9 @@ var socketEmit = {
514
588
  deleteMessage(messageId) {
515
589
  return withAck("delete_message", { messageId });
516
590
  },
591
+ deleteMessageForMe(messageId) {
592
+ return withAck("delete_message_for_me", { messageId });
593
+ },
517
594
  addReaction(messageId, emoji) {
518
595
  return withAck("add_reaction", { messageId, emoji });
519
596
  },
@@ -738,6 +815,7 @@ export {
738
815
  normalizeConversation,
739
816
  onSocketStatus,
740
817
  reconnectSocket,
818
+ refreshSocketAuth,
741
819
  resetAuthStore,
742
820
  resolveConfig,
743
821
  setApiClientInstance,