stream-chat 9.49.0 → 9.50.1

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.
@@ -406,6 +406,12 @@ function isOwnUserBaseProperty(property) {
406
406
  };
407
407
  return ownUserBaseProperties[property];
408
408
  }
409
+ var channelHasReadEvents = (channel) => {
410
+ const ownCapabilities = channel?.data?.own_capabilities;
411
+ return !(Array.isArray(ownCapabilities) && !ownCapabilities.includes("read-events"));
412
+ };
413
+ var channelTracksReadLocally = (channel) => !channelHasReadEvents(channel) && !!channel?.getClient().options.isLocalUnreadCountEnabled;
414
+ var userHasReadReceipts = (client) => client.user?.privacy_settings?.read_receipts?.enabled ?? true;
409
415
  function addFileToFormData(uri, name, contentType) {
410
416
  const data = new FormData();
411
417
  if (isReadableStream(uri) || isBuffer(uri) || isFileWebAPI(uri) || isBlobWebAPI(uri)) {
@@ -8567,6 +8573,7 @@ var MessageDeliveryReporter = class _MessageDeliveryReporter {
8567
8573
  * @param options
8568
8574
  */
8569
8575
  this.markRead = async (collection, options) => {
8576
+ if (!userHasReadReceipts(this.client)) return null;
8570
8577
  let result = null;
8571
8578
  if (isChannel(collection)) {
8572
8579
  result = await collection.markAsReadRequest(options);
@@ -9911,6 +9918,33 @@ var Channel = class {
9911
9918
  ...data
9912
9919
  });
9913
9920
  }
9921
+ /**
9922
+ * markReadLocally - Resets this user's unread count locally, without any backend call. Intended for
9923
+ * channels that have read events disabled (e.g. livestreams) when the client is created with the
9924
+ * `isLocalUnreadCountEnabled` option. Dispatches a dedicated, client-only `message.read_locally` event
9925
+ * that runs through the same `_handleChannelEvent` read logic as a real `message.read` (minus the
9926
+ * delivery-report network sync), so the read-state update lives in one place. When offline support
9927
+ * is enabled, the offline DB persists the reset for read-events-disabled channels, so the local
9928
+ * count stays consistent across app restarts.
9929
+ *
9930
+ * @return {Event | undefined} The dispatched `message.read_locally` event, or `undefined` if there is no connected user.
9931
+ */
9932
+ markReadLocally() {
9933
+ const client = this.getClient();
9934
+ if (!client.userID) return;
9935
+ const event = {
9936
+ channel_id: this.id,
9937
+ channel_type: this.type,
9938
+ cid: this.cid,
9939
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
9940
+ last_read_message_id: this.lastMessage()?.id,
9941
+ team: this.data?.team,
9942
+ type: "message.read_locally",
9943
+ user: client.user
9944
+ };
9945
+ client.dispatchEvent(event);
9946
+ return event;
9947
+ }
9914
9948
  /**
9915
9949
  * clean - Cleans the channel state and fires stop typing if needed
9916
9950
  */
@@ -10066,7 +10100,7 @@ var Channel = class {
10066
10100
  if (message.user?.id === this.getClient().userID) return false;
10067
10101
  if (message.user?.id && this.getClient().userMuteStatus(message.user.id))
10068
10102
  return false;
10069
- if (Array.isArray(this.data?.own_capabilities) && !this.data?.own_capabilities.includes("read-events")) {
10103
+ if (!this.getClient().options.isLocalUnreadCountEnabled && !channelHasReadEvents(this)) {
10070
10104
  return false;
10071
10105
  }
10072
10106
  if (this.getClient()._muteStatus(this.cid).muted) return false;
@@ -10477,6 +10511,11 @@ var Channel = class {
10477
10511
  delete channelState.typing[event.user.id];
10478
10512
  }
10479
10513
  break;
10514
+ // `message.read_locally` is the client-only event dispatched by `markReadLocally()` when read
10515
+ // events are disabled (e.g. livestreams with `isLocalUnreadCountEnabled`). It reuses the exact
10516
+ // `message.read` state logic so the read-state update lives in one place — only the
10517
+ // delivery-report network sync below is skipped for it.
10518
+ case "message.read_locally":
10480
10519
  case "message.read":
10481
10520
  if (event.user?.id && event.created_at) {
10482
10521
  const previousReadState = channelState.read[event.user.id];
@@ -10497,7 +10536,9 @@ var Channel = class {
10497
10536
  const isOwnEvent = event.user?.id === client.user?.id;
10498
10537
  if (isOwnEvent) {
10499
10538
  channelState.unreadCount = 0;
10500
- client.syncDeliveredCandidates([this]);
10539
+ if (event.type === "message.read") {
10540
+ client.syncDeliveredCandidates([this]);
10541
+ }
10501
10542
  }
10502
10543
  }
10503
10544
  break;
@@ -12382,6 +12423,7 @@ var DEFAULT_CONNECTION_RECOVERY_THROTTLE_DURATION = 1e3;
12382
12423
  var MAX_QUERY_THREADS_LIMIT = 25;
12383
12424
  var THREAD_MANAGER_INITIAL_STATE = {
12384
12425
  active: false,
12426
+ wasActivatedAtLeastOnce: false,
12385
12427
  isThreadOrderStale: false,
12386
12428
  threads: [],
12387
12429
  unreadThreadCount: 0,
@@ -12404,7 +12446,7 @@ var ThreadManager = class extends WithSubscriptions {
12404
12446
  this.state.next(THREAD_MANAGER_INITIAL_STATE);
12405
12447
  };
12406
12448
  this.activate = () => {
12407
- this.state.partialNext({ active: true });
12449
+ this.state.partialNext({ active: true, wasActivatedAtLeastOnce: true });
12408
12450
  };
12409
12451
  this.deactivate = () => {
12410
12452
  this.state.partialNext({ active: false });
@@ -12484,8 +12526,8 @@ var ThreadManager = class extends WithSubscriptions {
12484
12526
  }).unsubscribe;
12485
12527
  const throttledHandleConnectionRecovered = throttle(
12486
12528
  () => {
12487
- const { lastConnectionDropAt } = this.state.getLatestValue();
12488
- if (!lastConnectionDropAt) return;
12529
+ const { lastConnectionDropAt, wasActivatedAtLeastOnce } = this.state.getLatestValue();
12530
+ if (!lastConnectionDropAt || !wasActivatedAtLeastOnce) return;
12489
12531
  this.reload({ force: true });
12490
12532
  },
12491
12533
  DEFAULT_CONNECTION_RECOVERY_THROTTLE_DURATION,
@@ -14617,7 +14659,7 @@ var StreamChat = class _StreamChat {
14617
14659
  return this.userAgent;
14618
14660
  }
14619
14661
  if (!this.cachedUserAgent) {
14620
- const version = "9.49.0";
14662
+ const version = "9.50.1";
14621
14663
  const { name: sdkName, version: sdkVersion } = this.sdkIdentifier ?? {};
14622
14664
  const { name: appName, version: appVersion } = this.appIdentifier ?? {};
14623
14665
  const { os, model: deviceModel } = this.deviceIdentifier ?? {};
@@ -14675,6 +14717,7 @@ var StreamChat = class _StreamChat {
14675
14717
  warmUp: false,
14676
14718
  recoverStateOnReconnect: true,
14677
14719
  disableCache: false,
14720
+ isLocalUnreadCountEnabled: false,
14678
14721
  wsUrlParams: new URLSearchParams({}),
14679
14722
  ...inputOptions
14680
14723
  };
@@ -18028,6 +18071,7 @@ var EVENT_MAP = {
18028
18071
  "ai_indicator.stop": true,
18029
18072
  "ai_indicator.clear": true,
18030
18073
  // local events
18074
+ "message.read_locally": true,
18031
18075
  "channels.queried": true,
18032
18076
  "offline_reactions.queried": true,
18033
18077
  "connection.changed": true,
@@ -18411,7 +18455,8 @@ var AbstractOfflineDB = class {
18411
18455
  if (cid && client.user && client.user.id !== user?.id) {
18412
18456
  const userId = client.user.id;
18413
18457
  const channel = client.activeChannels[cid];
18414
- if (channel) {
18458
+ const tracksReadLocally = channelTracksReadLocally(channel);
18459
+ if (channel && (channelHasReadEvents(channel) || tracksReadLocally)) {
18415
18460
  const ownReads = channel.state.read[userId];
18416
18461
  const unreadCount = channel.countUnread();
18417
18462
  const upsertReadsQueries = await this.upsertReads({
@@ -18419,8 +18464,8 @@ var AbstractOfflineDB = class {
18419
18464
  execute: false,
18420
18465
  reads: [
18421
18466
  {
18422
- last_read: ownReads.last_read.toISOString(),
18423
- last_read_message_id: ownReads.last_read_message_id,
18467
+ last_read: (ownReads?.last_read ?? /* @__PURE__ */ new Date(0)).toISOString(),
18468
+ last_read_message_id: ownReads?.last_read_message_id,
18424
18469
  unread_messages: unreadCount,
18425
18470
  user: client.user
18426
18471
  }
@@ -18619,27 +18664,30 @@ var AbstractOfflineDB = class {
18619
18664
  truncated_at,
18620
18665
  execute: false
18621
18666
  });
18667
+ let finalQueries = [...truncateQueries];
18622
18668
  const userId = ownUser.id;
18623
18669
  const activeChannel = this.client.activeChannels[cid];
18624
- const ownReads = activeChannel.state.read[userId];
18625
- let unreadCount = 0;
18626
- if (truncated_at) {
18627
- const truncatedAt = new Date(truncated_at);
18628
- unreadCount = activeChannel.countUnread(truncatedAt);
18670
+ const tracksReadLocally = channelTracksReadLocally(activeChannel);
18671
+ if (activeChannel && (channelHasReadEvents(activeChannel) || tracksReadLocally)) {
18672
+ const ownReads = activeChannel.state.read[userId];
18673
+ let unreadCount = 0;
18674
+ if (truncated_at) {
18675
+ unreadCount = activeChannel.countUnread(new Date(truncated_at));
18676
+ }
18677
+ const upsertReadQueries = await this.upsertReads({
18678
+ cid,
18679
+ execute: false,
18680
+ reads: [
18681
+ {
18682
+ last_read: (ownReads?.last_read ?? /* @__PURE__ */ new Date(0)).toString(),
18683
+ last_read_message_id: ownReads?.last_read_message_id,
18684
+ unread_messages: unreadCount,
18685
+ user: ownUser
18686
+ }
18687
+ ]
18688
+ });
18689
+ finalQueries = [...finalQueries, ...upsertReadQueries];
18629
18690
  }
18630
- const upsertReadQueries = await this.upsertReads({
18631
- cid,
18632
- execute: false,
18633
- reads: [
18634
- {
18635
- last_read: ownReads.last_read.toString(),
18636
- last_read_message_id: ownReads.last_read_message_id,
18637
- unread_messages: unreadCount,
18638
- user: ownUser
18639
- }
18640
- ]
18641
- });
18642
- const finalQueries = [...truncateQueries, ...upsertReadQueries];
18643
18691
  if (execute) {
18644
18692
  await this.executeSqlBatch(finalQueries);
18645
18693
  }
@@ -18740,6 +18788,13 @@ var AbstractOfflineDB = class {
18740
18788
  if (type === "message.read" || type === "notification.mark_read") {
18741
18789
  return this.handleRead({ event, unreadMessages: 0, execute });
18742
18790
  }
18791
+ if (type === "message.read_locally") {
18792
+ const localChannel = event.cid ? this.client.activeChannels[event.cid] : void 0;
18793
+ if (channelTracksReadLocally(localChannel)) {
18794
+ return this.handleRead({ event, unreadMessages: 0, execute });
18795
+ }
18796
+ return [];
18797
+ }
18743
18798
  if (type === "notification.mark_unread") {
18744
18799
  return this.handleRead({ event, execute });
18745
18800
  }