stream-chat 9.38.0 → 9.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12755,6 +12755,29 @@ var _ReminderManager = class _ReminderManager extends WithSubscriptions {
12755
12755
  _ReminderManager.isReminderWsEventPayload = (event) => !!event.reminder && (event.type.startsWith("reminder.") || event.type === "notification.reminder_due");
12756
12756
  var ReminderManager = _ReminderManager;
12757
12757
 
12758
+ // src/offline-support/util.ts
12759
+ var isLocalUrl = (value) => !!value && !value.startsWith("http");
12760
+ var isAttachmentReplayable = (attachment) => {
12761
+ if (!attachment || typeof attachment !== "object") {
12762
+ return true;
12763
+ }
12764
+ return !isLocalUrl(attachment.asset_url) && !isLocalUrl(attachment.image_url);
12765
+ };
12766
+ var isMessageUpdateReplayable = (message) => !message.attachments?.some((attachment) => !isAttachmentReplayable(attachment));
12767
+ var getPendingTaskChannelData = (cid) => {
12768
+ if (!cid) {
12769
+ return {};
12770
+ }
12771
+ const separatorIndex = cid.indexOf(":");
12772
+ if (separatorIndex <= 0 || separatorIndex === cid.length - 1) {
12773
+ return {};
12774
+ }
12775
+ return {
12776
+ channelId: cid.slice(separatorIndex + 1),
12777
+ channelType: cid.slice(0, separatorIndex)
12778
+ };
12779
+ };
12780
+
12758
12781
  // src/client.ts
12759
12782
  function isString2(x) {
12760
12783
  return typeof x === "string" || x instanceof String;
@@ -14847,6 +14870,30 @@ var StreamChat = class _StreamChat {
14847
14870
  * @return {{ message: LocalMessage | MessageResponse }} Response that includes the message
14848
14871
  */
14849
14872
  async updateMessage(message, partialUserOrUserId, options) {
14873
+ if (!message.id) {
14874
+ throw Error("Please specify the message.id when calling updateMessage");
14875
+ }
14876
+ const messageId = message.id;
14877
+ try {
14878
+ if (this.offlineDb) {
14879
+ return await this.offlineDb.queueTask({
14880
+ task: {
14881
+ ...getPendingTaskChannelData(message.cid),
14882
+ messageId,
14883
+ payload: [message, partialUserOrUserId, options],
14884
+ type: "update-message"
14885
+ }
14886
+ });
14887
+ }
14888
+ } catch (error) {
14889
+ this.logger("error", `offlineDb:updateMessage`, {
14890
+ tags: ["channel", "offlineDb"],
14891
+ error
14892
+ });
14893
+ }
14894
+ return await this._updateMessage(message, partialUserOrUserId, options);
14895
+ }
14896
+ async _updateMessage(message, partialUserOrUserId, options) {
14850
14897
  if (!message.id) {
14851
14898
  throw Error("Please specify the message.id when calling updateMessage");
14852
14899
  }
@@ -15124,7 +15171,7 @@ var StreamChat = class _StreamChat {
15124
15171
  if (this.userAgent) {
15125
15172
  return this.userAgent;
15126
15173
  }
15127
- const version = "9.38.0";
15174
+ const version = "9.40.0";
15128
15175
  const clientBundle = "browser-cjs";
15129
15176
  let userAgentString = "";
15130
15177
  if (this.sdkIdentifier) {
@@ -16399,6 +16446,60 @@ var StreamChat = class _StreamChat {
16399
16446
  }
16400
16447
  );
16401
16448
  }
16449
+ /**
16450
+ * setRetentionPolicy - Creates or updates a retention policy for the app.
16451
+ * Server-side only.
16452
+ *
16453
+ * @param {string} policy The policy type ('old-messages' or 'inactive-channels')
16454
+ * @param {number} maxAgeHours Max age in hours (24-43800)
16455
+ * @returns {Promise<SetRetentionPolicyResponse>}
16456
+ */
16457
+ async setRetentionPolicy(policy, maxAgeHours) {
16458
+ this.validateServerSideAuth();
16459
+ return await this.post(
16460
+ this.baseURL + "/retention_policy",
16461
+ { policy, max_age_hours: maxAgeHours }
16462
+ );
16463
+ }
16464
+ /**
16465
+ * deleteRetentionPolicy - Deletes a retention policy for the app.
16466
+ * Server-side only.
16467
+ *
16468
+ * @param {string} policy The policy type ('old-messages' or 'inactive-channels')
16469
+ * @returns {Promise<DeleteRetentionPolicyResponse>}
16470
+ */
16471
+ async deleteRetentionPolicy(policy) {
16472
+ this.validateServerSideAuth();
16473
+ return await this.post(
16474
+ this.baseURL + "/retention_policy/delete",
16475
+ { policy }
16476
+ );
16477
+ }
16478
+ /**
16479
+ * getRetentionPolicy - Returns all retention policies configured for the app.
16480
+ * Server-side only.
16481
+ *
16482
+ * @returns {Promise<GetRetentionPolicyResponse>}
16483
+ */
16484
+ async getRetentionPolicy() {
16485
+ this.validateServerSideAuth();
16486
+ return await this.get(this.baseURL + "/retention_policy");
16487
+ }
16488
+ /**
16489
+ * getRetentionPolicyRuns - Returns filtered and sorted retention cleanup run history.
16490
+ * Supports filter_conditions on 'policy' and 'date' fields.
16491
+ * Server-side only.
16492
+ *
16493
+ * @param {GetRetentionPolicyRunsOptions} options Filter, sort, and pagination options
16494
+ * @returns {Promise<GetRetentionPolicyRunsResponse>}
16495
+ */
16496
+ async getRetentionPolicyRuns(options = {}) {
16497
+ this.validateServerSideAuth();
16498
+ return await this.post(
16499
+ this.baseURL + "/retention_policy/runs",
16500
+ options
16501
+ );
16502
+ }
16402
16503
  };
16403
16504
 
16404
16505
  // src/events.ts
@@ -17226,7 +17327,7 @@ var AbstractOfflineDB = class {
17226
17327
  return await attemptTaskExecution();
17227
17328
  } catch (e) {
17228
17329
  if (!this.shouldSkipQueueingTask(e)) {
17229
- await this.addPendingTask(task);
17330
+ await this.handleAddPendingTask({ task });
17230
17331
  }
17231
17332
  throw e;
17232
17333
  }
@@ -17239,19 +17340,92 @@ var AbstractOfflineDB = class {
17239
17340
  * @param error
17240
17341
  */
17241
17342
  this.shouldSkipQueueingTask = (error) => error?.response?.data?.code === 4 || error?.response?.data?.code === 17;
17343
+ this.mergeFailedMessageUpdateIntoPendingSendMessage = ({
17344
+ editedMessage,
17345
+ pendingMessage
17346
+ }) => {
17347
+ const normalizedEditedMessageSource = {
17348
+ ...editedMessage
17349
+ };
17350
+ if (editedMessage.status === "failed") {
17351
+ delete normalizedEditedMessageSource.message_text_updated_at;
17352
+ }
17353
+ const normalizedEditedMessage = localMessageToNewMessagePayload(
17354
+ normalizedEditedMessageSource
17355
+ );
17356
+ const pendingMessageStatus = pendingMessage.status;
17357
+ return {
17358
+ ...pendingMessage,
17359
+ ...normalizedEditedMessage,
17360
+ ...typeof pendingMessageStatus !== "undefined" ? { status: pendingMessageStatus } : {}
17361
+ };
17362
+ };
17363
+ this.isPendingSendMessageTask = (task) => task.type === "send-message";
17364
+ this.handleOfflineFailedUpdateMessagePendingTask = async (task) => {
17365
+ const [message] = task.payload;
17366
+ if (!message.id) {
17367
+ return;
17368
+ }
17369
+ const pendingTasks = await this.getPendingTasks({ messageId: message.id });
17370
+ const pendingSendMessageTask = pendingTasks.find(this.isPendingSendMessageTask);
17371
+ if (!pendingSendMessageTask) {
17372
+ return;
17373
+ }
17374
+ const updatedPendingSendMessage = this.mergeFailedMessageUpdateIntoPendingSendMessage(
17375
+ {
17376
+ editedMessage: message,
17377
+ pendingMessage: pendingSendMessageTask.payload[0]
17378
+ }
17379
+ );
17380
+ const updatedPendingTask = {
17381
+ ...pendingSendMessageTask,
17382
+ payload: [updatedPendingSendMessage, pendingSendMessageTask.payload[1]]
17383
+ };
17384
+ if (pendingSendMessageTask.id) {
17385
+ await this.updatePendingTask({
17386
+ id: pendingSendMessageTask.id,
17387
+ task: updatedPendingTask
17388
+ });
17389
+ return;
17390
+ }
17391
+ await this.addPendingTask({
17392
+ ...updatedPendingTask,
17393
+ id: void 0
17394
+ });
17395
+ };
17396
+ /**
17397
+ * Central ingress for persisting pending tasks. It either stores the task as-is
17398
+ * or rewrites an existing pending `send-message` task for offline edits of failed messages.
17399
+ */
17400
+ this.handleAddPendingTask = async ({ task }) => {
17401
+ if (task.type === "update-message" && !isMessageUpdateReplayable(task.payload[0])) {
17402
+ return;
17403
+ }
17404
+ if (task.type === "update-message" && !this.client.wsConnection?.isHealthy && task.payload[0].status === "failed") {
17405
+ await this.handleOfflineFailedUpdateMessagePendingTask(task);
17406
+ return;
17407
+ }
17408
+ await this.addPendingTask(task);
17409
+ };
17242
17410
  /**
17243
17411
  * Executes a task from the list of supported pending tasks. Currently supported pending tasks
17244
17412
  * are:
17413
+ * - Updating a message
17245
17414
  * - Deleting a message
17246
17415
  * - Sending a reaction
17247
17416
  * - Removing a reaction
17248
17417
  * - Sending a message
17418
+ * - Creating a draft
17419
+ * - Deleting a draft
17249
17420
  * It will throw if we try to execute a pending task that is not supported.
17250
17421
  * @param task - The task we want to execute
17251
17422
  * @param isPendingTask - a control value telling us if it's an actual pending task being executed
17252
17423
  * or delayed execution
17253
17424
  */
17254
17425
  this.executeTask = async ({ task }, isPendingTask = false) => {
17426
+ if (task.type === "update-message") {
17427
+ return await this.client._updateMessage(...task.payload);
17428
+ }
17255
17429
  if (task.type === "delete-message") {
17256
17430
  return await this.client._deleteMessage(...task.payload);
17257
17431
  }