stream-chat 9.49.0 → 9.50.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.
@@ -590,6 +590,12 @@ function isOwnUserBaseProperty(property) {
590
590
  };
591
591
  return ownUserBaseProperties[property];
592
592
  }
593
+ var channelHasReadEvents = (channel) => {
594
+ const ownCapabilities = channel?.data?.own_capabilities;
595
+ return !(Array.isArray(ownCapabilities) && !ownCapabilities.includes("read-events"));
596
+ };
597
+ var channelTracksReadLocally = (channel) => !channelHasReadEvents(channel) && !!channel?.getClient().options.isLocalUnreadCountEnabled;
598
+ var userHasReadReceipts = (client) => client.user?.privacy_settings?.read_receipts?.enabled ?? true;
593
599
  function addFileToFormData(uri, name, contentType) {
594
600
  const data = new import_form_data.default();
595
601
  if (isReadableStream(uri) || isBuffer(uri) || isFileWebAPI(uri) || isBlobWebAPI(uri)) {
@@ -8751,6 +8757,7 @@ var MessageDeliveryReporter = class _MessageDeliveryReporter {
8751
8757
  * @param options
8752
8758
  */
8753
8759
  this.markRead = async (collection, options) => {
8760
+ if (!userHasReadReceipts(this.client)) return null;
8754
8761
  let result = null;
8755
8762
  if (isChannel(collection)) {
8756
8763
  result = await collection.markAsReadRequest(options);
@@ -10095,6 +10102,33 @@ var Channel = class {
10095
10102
  ...data
10096
10103
  });
10097
10104
  }
10105
+ /**
10106
+ * markReadLocally - Resets this user's unread count locally, without any backend call. Intended for
10107
+ * channels that have read events disabled (e.g. livestreams) when the client is created with the
10108
+ * `isLocalUnreadCountEnabled` option. Dispatches a dedicated, client-only `message.read_locally` event
10109
+ * that runs through the same `_handleChannelEvent` read logic as a real `message.read` (minus the
10110
+ * delivery-report network sync), so the read-state update lives in one place. When offline support
10111
+ * is enabled, the offline DB persists the reset for read-events-disabled channels, so the local
10112
+ * count stays consistent across app restarts.
10113
+ *
10114
+ * @return {Event | undefined} The dispatched `message.read_locally` event, or `undefined` if there is no connected user.
10115
+ */
10116
+ markReadLocally() {
10117
+ const client = this.getClient();
10118
+ if (!client.userID) return;
10119
+ const event = {
10120
+ channel_id: this.id,
10121
+ channel_type: this.type,
10122
+ cid: this.cid,
10123
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
10124
+ last_read_message_id: this.lastMessage()?.id,
10125
+ team: this.data?.team,
10126
+ type: "message.read_locally",
10127
+ user: client.user
10128
+ };
10129
+ client.dispatchEvent(event);
10130
+ return event;
10131
+ }
10098
10132
  /**
10099
10133
  * clean - Cleans the channel state and fires stop typing if needed
10100
10134
  */
@@ -10250,7 +10284,7 @@ var Channel = class {
10250
10284
  if (message.user?.id === this.getClient().userID) return false;
10251
10285
  if (message.user?.id && this.getClient().userMuteStatus(message.user.id))
10252
10286
  return false;
10253
- if (Array.isArray(this.data?.own_capabilities) && !this.data?.own_capabilities.includes("read-events")) {
10287
+ if (!this.getClient().options.isLocalUnreadCountEnabled && !channelHasReadEvents(this)) {
10254
10288
  return false;
10255
10289
  }
10256
10290
  if (this.getClient()._muteStatus(this.cid).muted) return false;
@@ -10661,6 +10695,11 @@ var Channel = class {
10661
10695
  delete channelState.typing[event.user.id];
10662
10696
  }
10663
10697
  break;
10698
+ // `message.read_locally` is the client-only event dispatched by `markReadLocally()` when read
10699
+ // events are disabled (e.g. livestreams with `isLocalUnreadCountEnabled`). It reuses the exact
10700
+ // `message.read` state logic so the read-state update lives in one place — only the
10701
+ // delivery-report network sync below is skipped for it.
10702
+ case "message.read_locally":
10664
10703
  case "message.read":
10665
10704
  if (event.user?.id && event.created_at) {
10666
10705
  const previousReadState = channelState.read[event.user.id];
@@ -10681,7 +10720,9 @@ var Channel = class {
10681
10720
  const isOwnEvent = event.user?.id === client.user?.id;
10682
10721
  if (isOwnEvent) {
10683
10722
  channelState.unreadCount = 0;
10684
- client.syncDeliveredCandidates([this]);
10723
+ if (event.type === "message.read") {
10724
+ client.syncDeliveredCandidates([this]);
10725
+ }
10685
10726
  }
10686
10727
  }
10687
10728
  break;
@@ -14801,7 +14842,7 @@ var StreamChat = class _StreamChat {
14801
14842
  return this.userAgent;
14802
14843
  }
14803
14844
  if (!this.cachedUserAgent) {
14804
- const version = "9.49.0";
14845
+ const version = "9.50.0";
14805
14846
  const { name: sdkName, version: sdkVersion } = this.sdkIdentifier ?? {};
14806
14847
  const { name: appName, version: appVersion } = this.appIdentifier ?? {};
14807
14848
  const { os, model: deviceModel } = this.deviceIdentifier ?? {};
@@ -14859,6 +14900,7 @@ var StreamChat = class _StreamChat {
14859
14900
  warmUp: false,
14860
14901
  recoverStateOnReconnect: true,
14861
14902
  disableCache: false,
14903
+ isLocalUnreadCountEnabled: false,
14862
14904
  wsUrlParams: new URLSearchParams({}),
14863
14905
  ...inputOptions
14864
14906
  };
@@ -18212,6 +18254,7 @@ var EVENT_MAP = {
18212
18254
  "ai_indicator.stop": true,
18213
18255
  "ai_indicator.clear": true,
18214
18256
  // local events
18257
+ "message.read_locally": true,
18215
18258
  "channels.queried": true,
18216
18259
  "offline_reactions.queried": true,
18217
18260
  "connection.changed": true,
@@ -18595,7 +18638,8 @@ var AbstractOfflineDB = class {
18595
18638
  if (cid && client.user && client.user.id !== user?.id) {
18596
18639
  const userId = client.user.id;
18597
18640
  const channel = client.activeChannels[cid];
18598
- if (channel) {
18641
+ const tracksReadLocally = channelTracksReadLocally(channel);
18642
+ if (channel && (channelHasReadEvents(channel) || tracksReadLocally)) {
18599
18643
  const ownReads = channel.state.read[userId];
18600
18644
  const unreadCount = channel.countUnread();
18601
18645
  const upsertReadsQueries = await this.upsertReads({
@@ -18603,8 +18647,8 @@ var AbstractOfflineDB = class {
18603
18647
  execute: false,
18604
18648
  reads: [
18605
18649
  {
18606
- last_read: ownReads.last_read.toISOString(),
18607
- last_read_message_id: ownReads.last_read_message_id,
18650
+ last_read: (ownReads?.last_read ?? /* @__PURE__ */ new Date(0)).toISOString(),
18651
+ last_read_message_id: ownReads?.last_read_message_id,
18608
18652
  unread_messages: unreadCount,
18609
18653
  user: client.user
18610
18654
  }
@@ -18803,27 +18847,30 @@ var AbstractOfflineDB = class {
18803
18847
  truncated_at,
18804
18848
  execute: false
18805
18849
  });
18850
+ let finalQueries = [...truncateQueries];
18806
18851
  const userId = ownUser.id;
18807
18852
  const activeChannel = this.client.activeChannels[cid];
18808
- const ownReads = activeChannel.state.read[userId];
18809
- let unreadCount = 0;
18810
- if (truncated_at) {
18811
- const truncatedAt = new Date(truncated_at);
18812
- unreadCount = activeChannel.countUnread(truncatedAt);
18853
+ const tracksReadLocally = channelTracksReadLocally(activeChannel);
18854
+ if (activeChannel && (channelHasReadEvents(activeChannel) || tracksReadLocally)) {
18855
+ const ownReads = activeChannel.state.read[userId];
18856
+ let unreadCount = 0;
18857
+ if (truncated_at) {
18858
+ unreadCount = activeChannel.countUnread(new Date(truncated_at));
18859
+ }
18860
+ const upsertReadQueries = await this.upsertReads({
18861
+ cid,
18862
+ execute: false,
18863
+ reads: [
18864
+ {
18865
+ last_read: (ownReads?.last_read ?? /* @__PURE__ */ new Date(0)).toString(),
18866
+ last_read_message_id: ownReads?.last_read_message_id,
18867
+ unread_messages: unreadCount,
18868
+ user: ownUser
18869
+ }
18870
+ ]
18871
+ });
18872
+ finalQueries = [...finalQueries, ...upsertReadQueries];
18813
18873
  }
18814
- const upsertReadQueries = await this.upsertReads({
18815
- cid,
18816
- execute: false,
18817
- reads: [
18818
- {
18819
- last_read: ownReads.last_read.toString(),
18820
- last_read_message_id: ownReads.last_read_message_id,
18821
- unread_messages: unreadCount,
18822
- user: ownUser
18823
- }
18824
- ]
18825
- });
18826
- const finalQueries = [...truncateQueries, ...upsertReadQueries];
18827
18874
  if (execute) {
18828
18875
  await this.executeSqlBatch(finalQueries);
18829
18876
  }
@@ -18924,6 +18971,13 @@ var AbstractOfflineDB = class {
18924
18971
  if (type === "message.read" || type === "notification.mark_read") {
18925
18972
  return this.handleRead({ event, unreadMessages: 0, execute });
18926
18973
  }
18974
+ if (type === "message.read_locally") {
18975
+ const localChannel = event.cid ? this.client.activeChannels[event.cid] : void 0;
18976
+ if (channelTracksReadLocally(localChannel)) {
18977
+ return this.handleRead({ event, unreadMessages: 0, execute });
18978
+ }
18979
+ return [];
18980
+ }
18927
18981
  if (type === "notification.mark_unread") {
18928
18982
  return this.handleRead({ event, execute });
18929
18983
  }