@antzsoft/chat-core 1.1.2 → 1.1.4

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
@@ -681,7 +681,7 @@ declare const conversationsApi: {
681
681
  unmute(conversationId: string): Promise<void>;
682
682
  pin(conversationId: string): Promise<void>;
683
683
  unpin(conversationId: string): Promise<void>;
684
- leave(conversationId: string): Promise<void>;
684
+ leave(conversationId: string, andDelete?: boolean): Promise<void>;
685
685
  getMembers(conversationId: string, filter?: "deleted" | "all"): Promise<Participant[]>;
686
686
  /**
687
687
  * Get unread message count for a single conversation.
@@ -701,6 +701,7 @@ declare const conversationsApi: {
701
701
  * Server copies storageKey into conversation.iconMeta and deletes the chat_files record.
702
702
  */
703
703
  uploadIcon(conversationId: string, fileId: string): Promise<Conversation>;
704
+ removeIcon(conversationId: string): Promise<Conversation>;
704
705
  };
705
706
 
706
707
  declare const storageApi: {
@@ -791,6 +792,30 @@ declare const devicesApi: {
791
792
  remove(deviceId: string): Promise<void>;
792
793
  };
793
794
 
795
+ /**
796
+ * Fields for updating the current user's profile.
797
+ *
798
+ * Works in both builtin and non-builtin (external/SSO/WSO2) modes.
799
+ *
800
+ * In non-builtin modes, firstName/lastName/email/displayName/phone are also
801
+ * synced from the upstream user-service (on socket connect if stale, and every
802
+ * 2 hours via cron). Calling updateProfile() is the way to push an immediate
803
+ * update to the chat server without waiting for the next sync cycle — useful
804
+ * when the host app knows a profile change just happened in the identity provider.
805
+ *
806
+ * Uniqueness constraints: email and phone must each be unique within the tenant.
807
+ * A 409 is returned if another user already holds the same email or phone.
808
+ *
809
+ * username and status are intentionally excluded — username is a system
810
+ * identifier and status is lifecycle-managed by user-service.
811
+ */
812
+ interface UpdateProfilePayload {
813
+ firstName?: string;
814
+ lastName?: string;
815
+ email?: string;
816
+ displayName?: string;
817
+ phone?: string;
818
+ }
794
819
  declare const usersApi: {
795
820
  list(params?: {
796
821
  query?: string;
@@ -801,6 +826,13 @@ declare const usersApi: {
801
826
  getLastSeen(userId: string): Promise<{
802
827
  lastSeenAt: string | null;
803
828
  }>;
829
+ /**
830
+ * Update basic profile fields for the current user.
831
+ * Works in both builtin and non-builtin modes. Use this to push an immediate
832
+ * profile update to the chat server when the host app knows a change just
833
+ * happened — without waiting for the next 2-hour sync cycle.
834
+ */
835
+ updateProfile(payload: UpdateProfilePayload): Promise<User>;
804
836
  /**
805
837
  * Update notification preferences for the current user.
806
838
  * Partial update — only send fields you want to change.
@@ -1075,11 +1107,12 @@ declare class AntzChatClient {
1075
1107
  unmute(conversationId: string): Promise<void>;
1076
1108
  pin(conversationId: string): Promise<void>;
1077
1109
  unpin(conversationId: string): Promise<void>;
1078
- leave(conversationId: string): Promise<void>;
1110
+ leave(conversationId: string, andDelete?: boolean): Promise<void>;
1079
1111
  getMembers(conversationId: string, filter?: "deleted" | "all"): Promise<Participant[]>;
1080
1112
  getUnreadCount(conversationId: string): Promise<ConversationUnreadCount>;
1081
1113
  getUnreadSummary(): Promise<UnreadSummary>;
1082
1114
  uploadIcon(conversationId: string, fileId: string): Promise<Conversation>;
1115
+ removeIcon(conversationId: string): Promise<Conversation>;
1083
1116
  };
1084
1117
  readonly storage: {
1085
1118
  requestPresignedUrl(payload: PresignedUrlRequest): Promise<PresignedUrlResponse>;
@@ -1117,6 +1150,7 @@ declare class AntzChatClient {
1117
1150
  getLastSeen(userId: string): Promise<{
1118
1151
  lastSeenAt: string | null;
1119
1152
  }>;
1153
+ updateProfile(payload: UpdateProfilePayload): Promise<User>;
1120
1154
  updatePreferences(prefs: UserPreferences): Promise<User>;
1121
1155
  getPreferences(): Promise<UserPreferences | null>;
1122
1156
  };
@@ -1128,4 +1162,4 @@ declare class AntzChatClient {
1128
1162
  uploadIcon(conversationId: string, file: UploadableFile): Promise<Conversation>;
1129
1163
  }
1130
1164
 
1131
- export { AntzChatClient, type AntzChatConfig, type AppConfig, type Attachment, type AuthResponse, type AuthTokens, type BatchUploadResult, type CompressedFile, type CompressionAlgorithm, type CompressionConfig, type Conversation, type ConversationListParams, type ConversationUnreadCount, type CreateDirectData, type CreateGroupData, type CursorPaginatedResponse, 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 PlatformCompressFn, type PlatformUploadFn, type PresignedUrlRequest, type PresignedUrlResponse, type QuietHours, type ReactionUpdatedEvent, type ReadReceiptEvent, type RegisterData, type RegisterDeviceTokenPayload, type ReplyAttachmentSnapshot, type ResolvedCompressionConfig, 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, appConfigApi, authApi, connectSocket, conversationsApi, createAuthStore, devicesApi, disconnectSocket, getApiClient, getAuthStore, getCompressionStrategy, getSocket, getSocketStatus, initApiClient, initAuthStore, messagesApi, normalizeConversation, onSocketStatus, reconnectSocket, refreshSocketAuth, resetAuthStore, resolveConfig, setApiClientInstance, setTransitSession, socketEmit, storageApi, tryGetSocket, uploadBatch, useChatStore, usersApi };
1165
+ export { AntzChatClient, type AntzChatConfig, type AppConfig, type Attachment, type AuthResponse, type AuthTokens, type BatchUploadResult, type CompressedFile, type CompressionAlgorithm, type CompressionConfig, type Conversation, type ConversationListParams, type ConversationUnreadCount, type CreateDirectData, type CreateGroupData, type CursorPaginatedResponse, 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 PlatformCompressFn, type PlatformUploadFn, type PresignedUrlRequest, type PresignedUrlResponse, type QuietHours, type ReactionUpdatedEvent, type ReadReceiptEvent, type RegisterData, type RegisterDeviceTokenPayload, type ReplyAttachmentSnapshot, type ResolvedCompressionConfig, 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 UpdateProfilePayload, type UploadConfig, type UploadProgress, type UploadableFile, type User, type UserPreferences, type UserStatusEvent, type WebPushDeviceToken, appConfigApi, authApi, connectSocket, conversationsApi, createAuthStore, devicesApi, disconnectSocket, getApiClient, getAuthStore, getCompressionStrategy, getSocket, getSocketStatus, initApiClient, initAuthStore, messagesApi, normalizeConversation, onSocketStatus, reconnectSocket, refreshSocketAuth, resetAuthStore, resolveConfig, setApiClientInstance, setTransitSession, socketEmit, storageApi, tryGetSocket, uploadBatch, useChatStore, usersApi };
package/dist/index.d.ts CHANGED
@@ -681,7 +681,7 @@ declare const conversationsApi: {
681
681
  unmute(conversationId: string): Promise<void>;
682
682
  pin(conversationId: string): Promise<void>;
683
683
  unpin(conversationId: string): Promise<void>;
684
- leave(conversationId: string): Promise<void>;
684
+ leave(conversationId: string, andDelete?: boolean): Promise<void>;
685
685
  getMembers(conversationId: string, filter?: "deleted" | "all"): Promise<Participant[]>;
686
686
  /**
687
687
  * Get unread message count for a single conversation.
@@ -701,6 +701,7 @@ declare const conversationsApi: {
701
701
  * Server copies storageKey into conversation.iconMeta and deletes the chat_files record.
702
702
  */
703
703
  uploadIcon(conversationId: string, fileId: string): Promise<Conversation>;
704
+ removeIcon(conversationId: string): Promise<Conversation>;
704
705
  };
705
706
 
706
707
  declare const storageApi: {
@@ -791,6 +792,30 @@ declare const devicesApi: {
791
792
  remove(deviceId: string): Promise<void>;
792
793
  };
793
794
 
795
+ /**
796
+ * Fields for updating the current user's profile.
797
+ *
798
+ * Works in both builtin and non-builtin (external/SSO/WSO2) modes.
799
+ *
800
+ * In non-builtin modes, firstName/lastName/email/displayName/phone are also
801
+ * synced from the upstream user-service (on socket connect if stale, and every
802
+ * 2 hours via cron). Calling updateProfile() is the way to push an immediate
803
+ * update to the chat server without waiting for the next sync cycle — useful
804
+ * when the host app knows a profile change just happened in the identity provider.
805
+ *
806
+ * Uniqueness constraints: email and phone must each be unique within the tenant.
807
+ * A 409 is returned if another user already holds the same email or phone.
808
+ *
809
+ * username and status are intentionally excluded — username is a system
810
+ * identifier and status is lifecycle-managed by user-service.
811
+ */
812
+ interface UpdateProfilePayload {
813
+ firstName?: string;
814
+ lastName?: string;
815
+ email?: string;
816
+ displayName?: string;
817
+ phone?: string;
818
+ }
794
819
  declare const usersApi: {
795
820
  list(params?: {
796
821
  query?: string;
@@ -801,6 +826,13 @@ declare const usersApi: {
801
826
  getLastSeen(userId: string): Promise<{
802
827
  lastSeenAt: string | null;
803
828
  }>;
829
+ /**
830
+ * Update basic profile fields for the current user.
831
+ * Works in both builtin and non-builtin modes. Use this to push an immediate
832
+ * profile update to the chat server when the host app knows a change just
833
+ * happened — without waiting for the next 2-hour sync cycle.
834
+ */
835
+ updateProfile(payload: UpdateProfilePayload): Promise<User>;
804
836
  /**
805
837
  * Update notification preferences for the current user.
806
838
  * Partial update — only send fields you want to change.
@@ -1075,11 +1107,12 @@ declare class AntzChatClient {
1075
1107
  unmute(conversationId: string): Promise<void>;
1076
1108
  pin(conversationId: string): Promise<void>;
1077
1109
  unpin(conversationId: string): Promise<void>;
1078
- leave(conversationId: string): Promise<void>;
1110
+ leave(conversationId: string, andDelete?: boolean): Promise<void>;
1079
1111
  getMembers(conversationId: string, filter?: "deleted" | "all"): Promise<Participant[]>;
1080
1112
  getUnreadCount(conversationId: string): Promise<ConversationUnreadCount>;
1081
1113
  getUnreadSummary(): Promise<UnreadSummary>;
1082
1114
  uploadIcon(conversationId: string, fileId: string): Promise<Conversation>;
1115
+ removeIcon(conversationId: string): Promise<Conversation>;
1083
1116
  };
1084
1117
  readonly storage: {
1085
1118
  requestPresignedUrl(payload: PresignedUrlRequest): Promise<PresignedUrlResponse>;
@@ -1117,6 +1150,7 @@ declare class AntzChatClient {
1117
1150
  getLastSeen(userId: string): Promise<{
1118
1151
  lastSeenAt: string | null;
1119
1152
  }>;
1153
+ updateProfile(payload: UpdateProfilePayload): Promise<User>;
1120
1154
  updatePreferences(prefs: UserPreferences): Promise<User>;
1121
1155
  getPreferences(): Promise<UserPreferences | null>;
1122
1156
  };
@@ -1128,4 +1162,4 @@ declare class AntzChatClient {
1128
1162
  uploadIcon(conversationId: string, file: UploadableFile): Promise<Conversation>;
1129
1163
  }
1130
1164
 
1131
- export { AntzChatClient, type AntzChatConfig, type AppConfig, type Attachment, type AuthResponse, type AuthTokens, type BatchUploadResult, type CompressedFile, type CompressionAlgorithm, type CompressionConfig, type Conversation, type ConversationListParams, type ConversationUnreadCount, type CreateDirectData, type CreateGroupData, type CursorPaginatedResponse, 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 PlatformCompressFn, type PlatformUploadFn, type PresignedUrlRequest, type PresignedUrlResponse, type QuietHours, type ReactionUpdatedEvent, type ReadReceiptEvent, type RegisterData, type RegisterDeviceTokenPayload, type ReplyAttachmentSnapshot, type ResolvedCompressionConfig, 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, appConfigApi, authApi, connectSocket, conversationsApi, createAuthStore, devicesApi, disconnectSocket, getApiClient, getAuthStore, getCompressionStrategy, getSocket, getSocketStatus, initApiClient, initAuthStore, messagesApi, normalizeConversation, onSocketStatus, reconnectSocket, refreshSocketAuth, resetAuthStore, resolveConfig, setApiClientInstance, setTransitSession, socketEmit, storageApi, tryGetSocket, uploadBatch, useChatStore, usersApi };
1165
+ export { AntzChatClient, type AntzChatConfig, type AppConfig, type Attachment, type AuthResponse, type AuthTokens, type BatchUploadResult, type CompressedFile, type CompressionAlgorithm, type CompressionConfig, type Conversation, type ConversationListParams, type ConversationUnreadCount, type CreateDirectData, type CreateGroupData, type CursorPaginatedResponse, 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 PlatformCompressFn, type PlatformUploadFn, type PresignedUrlRequest, type PresignedUrlResponse, type QuietHours, type ReactionUpdatedEvent, type ReadReceiptEvent, type RegisterData, type RegisterDeviceTokenPayload, type ReplyAttachmentSnapshot, type ResolvedCompressionConfig, 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 UpdateProfilePayload, type UploadConfig, type UploadProgress, type UploadableFile, type User, type UserPreferences, type UserStatusEvent, type WebPushDeviceToken, appConfigApi, authApi, connectSocket, conversationsApi, createAuthStore, devicesApi, disconnectSocket, getApiClient, getAuthStore, getCompressionStrategy, getSocket, getSocketStatus, initApiClient, initAuthStore, messagesApi, normalizeConversation, onSocketStatus, reconnectSocket, refreshSocketAuth, resetAuthStore, resolveConfig, setApiClientInstance, setTransitSession, socketEmit, storageApi, tryGetSocket, uploadBatch, useChatStore, usersApi };
package/dist/index.js CHANGED
@@ -177,45 +177,61 @@ function b64ToBuf(b64) {
177
177
  }
178
178
 
179
179
  // src/crypto/session.ts
180
- var _session = null;
181
- var _readyResolve = null;
182
- var _readyPromise = null;
183
- var _transitConfigured = null;
180
+ var _KEY = /* @__PURE__ */ Symbol.for("__antz_chat_transit__");
181
+ function getState() {
182
+ const g = globalThis;
183
+ if (!g[_KEY]) {
184
+ g[_KEY] = {
185
+ session: null,
186
+ sessionEverEstablished: false,
187
+ readyResolve: null,
188
+ readyPromise: null,
189
+ transitConfigured: null
190
+ };
191
+ }
192
+ return g[_KEY];
193
+ }
184
194
  function configureTransit(enabled) {
185
- _transitConfigured = enabled;
195
+ const s = getState();
196
+ s.transitConfigured = enabled;
186
197
  if (!enabled) {
187
- _readyResolve?.();
188
- _readyResolve = null;
198
+ s.readyResolve?.();
199
+ s.readyResolve = null;
189
200
  }
190
201
  }
191
202
  function waitForTransitReady() {
192
- if (!_transitConfigured) return Promise.resolve();
193
- if (_session) return Promise.resolve();
194
- if (!_readyPromise) {
195
- _readyPromise = new Promise((resolve) => {
196
- _readyResolve = resolve;
203
+ const s = getState();
204
+ if (!s.transitConfigured) return Promise.resolve();
205
+ if (s.session) return Promise.resolve();
206
+ if (s.sessionEverEstablished) return Promise.resolve();
207
+ if (!s.readyPromise) {
208
+ s.readyPromise = new Promise((resolve) => {
209
+ s.readyResolve = resolve;
197
210
  });
198
211
  }
199
- return _readyPromise;
212
+ return s.readyPromise;
200
213
  }
201
214
  function setTransitSession(session) {
202
- _session = session;
203
- _readyResolve?.();
204
- _readyResolve = null;
215
+ const s = getState();
216
+ s.session = session;
217
+ s.sessionEverEstablished = true;
218
+ s.readyResolve?.();
219
+ s.readyResolve = null;
205
220
  }
206
221
  function clearTransitSession() {
207
- _session = null;
208
- _readyPromise = null;
209
- _readyResolve = null;
222
+ const s = getState();
223
+ s.session = null;
224
+ s.readyPromise = null;
225
+ s.readyResolve = null;
210
226
  }
211
227
  function isTransitEnabled() {
212
- return _session?.enabled === true;
228
+ return getState().session?.enabled === true;
213
229
  }
214
230
  function getSessionKey() {
215
- return _session?.sessionKey ?? null;
231
+ return getState().session?.sessionKey ?? null;
216
232
  }
217
233
  function getSessionId() {
218
- return _session?.sessionId ?? null;
234
+ return getState().session?.sessionId ?? null;
219
235
  }
220
236
 
221
237
  // src/api/client.ts
@@ -575,8 +591,9 @@ var conversationsApi = {
575
591
  async unpin(conversationId) {
576
592
  await getApiClient().delete(`/conversations/${conversationId}/pin`);
577
593
  },
578
- async leave(conversationId) {
579
- await getApiClient().delete(`/conversations/${conversationId}/leave`);
594
+ async leave(conversationId, andDelete) {
595
+ const url = andDelete ? `/conversations/${conversationId}/leave?delete=true` : `/conversations/${conversationId}/leave`;
596
+ await getApiClient().delete(url);
580
597
  },
581
598
  async getMembers(conversationId, filter) {
582
599
  const { data } = await getApiClient().get(
@@ -616,6 +633,12 @@ var conversationsApi = {
616
633
  { fileId }
617
634
  );
618
635
  return normalizeConversation(data);
636
+ },
637
+ async removeIcon(conversationId) {
638
+ const { data } = await getApiClient().delete(
639
+ `/conversations/${conversationId}/icon`
640
+ );
641
+ return normalizeConversation(data);
619
642
  }
620
643
  };
621
644
 
@@ -744,6 +767,16 @@ var usersApi = {
744
767
  const { data } = await getApiClient().get(`/users/${userId}`);
745
768
  return { lastSeenAt: data.lastSeenAt ?? null };
746
769
  },
770
+ /**
771
+ * Update basic profile fields for the current user.
772
+ * Works in both builtin and non-builtin modes. Use this to push an immediate
773
+ * profile update to the chat server when the host app knows a change just
774
+ * happened — without waiting for the next 2-hour sync cycle.
775
+ */
776
+ async updateProfile(payload) {
777
+ const { data } = await getApiClient().put("/users/me", payload);
778
+ return data;
779
+ },
747
780
  /**
748
781
  * Update notification preferences for the current user.
749
782
  * Partial update — only send fields you want to change.
@@ -1095,6 +1128,41 @@ function refreshSocketAuth() {
1095
1128
  // src/socket/emitters.ts
1096
1129
  var ACK_TIMEOUT = 5e3;
1097
1130
  var RECONNECT_WAIT_TIMEOUT = 15e3;
1131
+ var QUEUE_MAX_SIZE = 100;
1132
+ var QUEUE_ENTRY_TTL = 3e4;
1133
+ var sendQueues = /* @__PURE__ */ new Map();
1134
+ var sendQueueRunning = /* @__PURE__ */ new Map();
1135
+ async function drainSendQueue(conversationId) {
1136
+ if (sendQueueRunning.get(conversationId)) return;
1137
+ sendQueueRunning.set(conversationId, true);
1138
+ const queue = sendQueues.get(conversationId);
1139
+ while (queue.length > 0) {
1140
+ const entry = queue.shift();
1141
+ if (Date.now() - entry.enqueuedAt > QUEUE_ENTRY_TTL) {
1142
+ entry.reject(new Error("[AntzChat] Message dropped: queued too long"));
1143
+ continue;
1144
+ }
1145
+ try {
1146
+ entry.resolve(await entry.run());
1147
+ } catch (e) {
1148
+ entry.reject(e);
1149
+ }
1150
+ }
1151
+ sendQueues.delete(conversationId);
1152
+ sendQueueRunning.delete(conversationId);
1153
+ }
1154
+ function queueSendMessage(payload) {
1155
+ const conversationId = payload.conversationId;
1156
+ if (!sendQueues.has(conversationId)) sendQueues.set(conversationId, []);
1157
+ const queue = sendQueues.get(conversationId);
1158
+ if (queue.length >= QUEUE_MAX_SIZE) {
1159
+ return Promise.reject(new Error("[AntzChat] Send queue full: too many messages in flight"));
1160
+ }
1161
+ return new Promise((resolve, reject) => {
1162
+ queue.push({ run: () => withAck("send_message", payload), resolve, reject, enqueuedAt: Date.now() });
1163
+ drainSendQueue(conversationId);
1164
+ });
1165
+ }
1098
1166
  function waitForReconnect() {
1099
1167
  return new Promise((resolve, reject) => {
1100
1168
  const timer = setTimeout(() => {
@@ -1142,7 +1210,7 @@ var socketEmit = {
1142
1210
  fireAndForget("leave_room", { conversationId });
1143
1211
  },
1144
1212
  sendMessage(payload) {
1145
- return withAck("send_message", payload);
1213
+ return queueSendMessage(payload);
1146
1214
  },
1147
1215
  updateMessage(messageId, text) {
1148
1216
  return withAck("update_message", { messageId, text });