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.
@@ -621,6 +621,12 @@ function isOwnUserBaseProperty(property) {
621
621
  };
622
622
  return ownUserBaseProperties[property];
623
623
  }
624
+ var channelHasReadEvents = (channel) => {
625
+ const ownCapabilities = channel?.data?.own_capabilities;
626
+ return !(Array.isArray(ownCapabilities) && !ownCapabilities.includes("read-events"));
627
+ };
628
+ var channelTracksReadLocally = (channel) => !channelHasReadEvents(channel) && !!channel?.getClient().options.isLocalUnreadCountEnabled;
629
+ var userHasReadReceipts = (client) => client.user?.privacy_settings?.read_receipts?.enabled ?? true;
624
630
  function addFileToFormData(uri, name, contentType) {
625
631
  const data = new import_form_data.default();
626
632
  if (isReadableStream(uri) || isBuffer(uri) || isFileWebAPI(uri) || isBlobWebAPI(uri)) {
@@ -8782,6 +8788,7 @@ var MessageDeliveryReporter = class _MessageDeliveryReporter {
8782
8788
  * @param options
8783
8789
  */
8784
8790
  this.markRead = async (collection, options) => {
8791
+ if (!userHasReadReceipts(this.client)) return null;
8785
8792
  let result = null;
8786
8793
  if (isChannel(collection)) {
8787
8794
  result = await collection.markAsReadRequest(options);
@@ -10126,6 +10133,33 @@ var Channel = class {
10126
10133
  ...data
10127
10134
  });
10128
10135
  }
10136
+ /**
10137
+ * markReadLocally - Resets this user's unread count locally, without any backend call. Intended for
10138
+ * channels that have read events disabled (e.g. livestreams) when the client is created with the
10139
+ * `isLocalUnreadCountEnabled` option. Dispatches a dedicated, client-only `message.read_locally` event
10140
+ * that runs through the same `_handleChannelEvent` read logic as a real `message.read` (minus the
10141
+ * delivery-report network sync), so the read-state update lives in one place. When offline support
10142
+ * is enabled, the offline DB persists the reset for read-events-disabled channels, so the local
10143
+ * count stays consistent across app restarts.
10144
+ *
10145
+ * @return {Event | undefined} The dispatched `message.read_locally` event, or `undefined` if there is no connected user.
10146
+ */
10147
+ markReadLocally() {
10148
+ const client = this.getClient();
10149
+ if (!client.userID) return;
10150
+ const event = {
10151
+ channel_id: this.id,
10152
+ channel_type: this.type,
10153
+ cid: this.cid,
10154
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
10155
+ last_read_message_id: this.lastMessage()?.id,
10156
+ team: this.data?.team,
10157
+ type: "message.read_locally",
10158
+ user: client.user
10159
+ };
10160
+ client.dispatchEvent(event);
10161
+ return event;
10162
+ }
10129
10163
  /**
10130
10164
  * clean - Cleans the channel state and fires stop typing if needed
10131
10165
  */
@@ -10281,7 +10315,7 @@ var Channel = class {
10281
10315
  if (message.user?.id === this.getClient().userID) return false;
10282
10316
  if (message.user?.id && this.getClient().userMuteStatus(message.user.id))
10283
10317
  return false;
10284
- if (Array.isArray(this.data?.own_capabilities) && !this.data?.own_capabilities.includes("read-events")) {
10318
+ if (!this.getClient().options.isLocalUnreadCountEnabled && !channelHasReadEvents(this)) {
10285
10319
  return false;
10286
10320
  }
10287
10321
  if (this.getClient()._muteStatus(this.cid).muted) return false;
@@ -10692,6 +10726,11 @@ var Channel = class {
10692
10726
  delete channelState.typing[event.user.id];
10693
10727
  }
10694
10728
  break;
10729
+ // `message.read_locally` is the client-only event dispatched by `markReadLocally()` when read
10730
+ // events are disabled (e.g. livestreams with `isLocalUnreadCountEnabled`). It reuses the exact
10731
+ // `message.read` state logic so the read-state update lives in one place — only the
10732
+ // delivery-report network sync below is skipped for it.
10733
+ case "message.read_locally":
10695
10734
  case "message.read":
10696
10735
  if (event.user?.id && event.created_at) {
10697
10736
  const previousReadState = channelState.read[event.user.id];
@@ -10712,7 +10751,9 @@ var Channel = class {
10712
10751
  const isOwnEvent = event.user?.id === client.user?.id;
10713
10752
  if (isOwnEvent) {
10714
10753
  channelState.unreadCount = 0;
10715
- client.syncDeliveredCandidates([this]);
10754
+ if (event.type === "message.read") {
10755
+ client.syncDeliveredCandidates([this]);
10756
+ }
10716
10757
  }
10717
10758
  }
10718
10759
  break;
@@ -14832,7 +14873,7 @@ var StreamChat = class _StreamChat {
14832
14873
  return this.userAgent;
14833
14874
  }
14834
14875
  if (!this.cachedUserAgent) {
14835
- const version = "9.49.0";
14876
+ const version = "9.50.0";
14836
14877
  const { name: sdkName, version: sdkVersion } = this.sdkIdentifier ?? {};
14837
14878
  const { name: appName, version: appVersion } = this.appIdentifier ?? {};
14838
14879
  const { os, model: deviceModel } = this.deviceIdentifier ?? {};
@@ -14890,6 +14931,7 @@ var StreamChat = class _StreamChat {
14890
14931
  warmUp: false,
14891
14932
  recoverStateOnReconnect: true,
14892
14933
  disableCache: false,
14934
+ isLocalUnreadCountEnabled: false,
14893
14935
  wsUrlParams: new URLSearchParams({}),
14894
14936
  ...inputOptions
14895
14937
  };
@@ -18243,6 +18285,7 @@ var EVENT_MAP = {
18243
18285
  "ai_indicator.stop": true,
18244
18286
  "ai_indicator.clear": true,
18245
18287
  // local events
18288
+ "message.read_locally": true,
18246
18289
  "channels.queried": true,
18247
18290
  "offline_reactions.queried": true,
18248
18291
  "connection.changed": true,
@@ -18626,7 +18669,8 @@ var AbstractOfflineDB = class {
18626
18669
  if (cid && client.user && client.user.id !== user?.id) {
18627
18670
  const userId = client.user.id;
18628
18671
  const channel = client.activeChannels[cid];
18629
- if (channel) {
18672
+ const tracksReadLocally = channelTracksReadLocally(channel);
18673
+ if (channel && (channelHasReadEvents(channel) || tracksReadLocally)) {
18630
18674
  const ownReads = channel.state.read[userId];
18631
18675
  const unreadCount = channel.countUnread();
18632
18676
  const upsertReadsQueries = await this.upsertReads({
@@ -18634,8 +18678,8 @@ var AbstractOfflineDB = class {
18634
18678
  execute: false,
18635
18679
  reads: [
18636
18680
  {
18637
- last_read: ownReads.last_read.toISOString(),
18638
- last_read_message_id: ownReads.last_read_message_id,
18681
+ last_read: (ownReads?.last_read ?? /* @__PURE__ */ new Date(0)).toISOString(),
18682
+ last_read_message_id: ownReads?.last_read_message_id,
18639
18683
  unread_messages: unreadCount,
18640
18684
  user: client.user
18641
18685
  }
@@ -18834,27 +18878,30 @@ var AbstractOfflineDB = class {
18834
18878
  truncated_at,
18835
18879
  execute: false
18836
18880
  });
18881
+ let finalQueries = [...truncateQueries];
18837
18882
  const userId = ownUser.id;
18838
18883
  const activeChannel = this.client.activeChannels[cid];
18839
- const ownReads = activeChannel.state.read[userId];
18840
- let unreadCount = 0;
18841
- if (truncated_at) {
18842
- const truncatedAt = new Date(truncated_at);
18843
- unreadCount = activeChannel.countUnread(truncatedAt);
18884
+ const tracksReadLocally = channelTracksReadLocally(activeChannel);
18885
+ if (activeChannel && (channelHasReadEvents(activeChannel) || tracksReadLocally)) {
18886
+ const ownReads = activeChannel.state.read[userId];
18887
+ let unreadCount = 0;
18888
+ if (truncated_at) {
18889
+ unreadCount = activeChannel.countUnread(new Date(truncated_at));
18890
+ }
18891
+ const upsertReadQueries = await this.upsertReads({
18892
+ cid,
18893
+ execute: false,
18894
+ reads: [
18895
+ {
18896
+ last_read: (ownReads?.last_read ?? /* @__PURE__ */ new Date(0)).toString(),
18897
+ last_read_message_id: ownReads?.last_read_message_id,
18898
+ unread_messages: unreadCount,
18899
+ user: ownUser
18900
+ }
18901
+ ]
18902
+ });
18903
+ finalQueries = [...finalQueries, ...upsertReadQueries];
18844
18904
  }
18845
- const upsertReadQueries = await this.upsertReads({
18846
- cid,
18847
- execute: false,
18848
- reads: [
18849
- {
18850
- last_read: ownReads.last_read.toString(),
18851
- last_read_message_id: ownReads.last_read_message_id,
18852
- unread_messages: unreadCount,
18853
- user: ownUser
18854
- }
18855
- ]
18856
- });
18857
- const finalQueries = [...truncateQueries, ...upsertReadQueries];
18858
18905
  if (execute) {
18859
18906
  await this.executeSqlBatch(finalQueries);
18860
18907
  }
@@ -18955,6 +19002,13 @@ var AbstractOfflineDB = class {
18955
19002
  if (type === "message.read" || type === "notification.mark_read") {
18956
19003
  return this.handleRead({ event, unreadMessages: 0, execute });
18957
19004
  }
19005
+ if (type === "message.read_locally") {
19006
+ const localChannel = event.cid ? this.client.activeChannels[event.cid] : void 0;
19007
+ if (channelTracksReadLocally(localChannel)) {
19008
+ return this.handleRead({ event, unreadMessages: 0, execute });
19009
+ }
19010
+ return [];
19011
+ }
18958
19012
  if (type === "notification.mark_unread") {
18959
19013
  return this.handleRead({ event, execute });
18960
19014
  }