@amityco/ts-sdk 7.1.0 → 7.1.1-c8d4edca.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.
Files changed (62) hide show
  1. package/.env +26 -26
  2. package/dist/@types/core/events.d.ts +2 -1
  3. package/dist/@types/core/events.d.ts.map +1 -1
  4. package/dist/@types/core/model.d.ts +2 -0
  5. package/dist/@types/core/model.d.ts.map +1 -1
  6. package/dist/@types/core/readReceipt.d.ts +12 -1
  7. package/dist/@types/core/readReceipt.d.ts.map +1 -1
  8. package/dist/@types/domains/channel.d.ts +9 -0
  9. package/dist/@types/domains/channel.d.ts.map +1 -1
  10. package/dist/@types/domains/client.d.ts +1 -0
  11. package/dist/@types/domains/client.d.ts.map +1 -1
  12. package/dist/channelRepository/api/markChannelsAsReadBySegment.d.ts +16 -0
  13. package/dist/channelRepository/api/markChannelsAsReadBySegment.d.ts.map +1 -0
  14. package/dist/channelRepository/events/onChannelUnreadUpdatedLocal.d.ts +12 -0
  15. package/dist/channelRepository/events/onChannelUnreadUpdatedLocal.d.ts.map +1 -0
  16. package/dist/channelRepository/observers/getChannel.d.ts.map +1 -1
  17. package/dist/channelRepository/observers/getChannels/ChannelLiveCollectionController.d.ts.map +1 -1
  18. package/dist/channelRepository/utils/constructChannelDynamicValue.d.ts.map +1 -1
  19. package/dist/channelRepository/utils/getLegacyChannelUnread.d.ts +2 -0
  20. package/dist/channelRepository/utils/getLegacyChannelUnread.d.ts.map +1 -0
  21. package/dist/channelRepository/utils/prepareChannelPayload.d.ts.map +1 -1
  22. package/dist/client/api/createClient.d.ts.map +1 -1
  23. package/dist/client/api/enableUnreadCount.d.ts.map +1 -1
  24. package/dist/client/api/login.d.ts.map +1 -1
  25. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.d.ts +33 -0
  26. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.d.ts.map +1 -0
  27. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.d.ts +3 -0
  28. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.d.ts.map +1 -0
  29. package/dist/client/utils/ReadReceiptSync/readReceiptSyncEngine.d.ts +2 -4
  30. package/dist/client/utils/ReadReceiptSync/readReceiptSyncEngine.d.ts.map +1 -1
  31. package/dist/core/events.d.ts +3 -3
  32. package/dist/core/events.d.ts.map +1 -1
  33. package/dist/core/model/idResolvers.d.ts.map +1 -1
  34. package/dist/index.cjs.js +361 -41
  35. package/dist/index.esm.js +361 -41
  36. package/dist/index.umd.js +4 -4
  37. package/dist/marker/events/onChannelUnreadInfoUpdatedLocal.d.ts +12 -0
  38. package/dist/marker/events/onChannelUnreadInfoUpdatedLocal.d.ts.map +1 -0
  39. package/dist/messageRepository/utils/markReadMessage.d.ts.map +1 -1
  40. package/package.json +1 -1
  41. package/src/@types/core/events.ts +2 -1
  42. package/src/@types/core/model.ts +4 -0
  43. package/src/@types/core/readReceipt.ts +14 -1
  44. package/src/@types/domains/channel.ts +11 -0
  45. package/src/@types/domains/client.ts +2 -0
  46. package/src/channelRepository/api/markChannelsAsReadBySegment.ts +29 -0
  47. package/src/channelRepository/events/onChannelUnreadUpdatedLocal.ts +29 -0
  48. package/src/channelRepository/observers/getChannel.ts +3 -1
  49. package/src/channelRepository/observers/getChannels/ChannelLiveCollectionController.ts +6 -1
  50. package/src/channelRepository/utils/constructChannelDynamicValue.ts +12 -2
  51. package/src/channelRepository/utils/getLegacyChannelUnread.ts +5 -0
  52. package/src/channelRepository/utils/prepareChannelPayload.ts +57 -17
  53. package/src/client/api/createClient.ts +3 -0
  54. package/src/client/api/enableUnreadCount.ts +1 -0
  55. package/src/client/api/login.ts +5 -1
  56. package/src/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.ts +267 -0
  57. package/src/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.ts +21 -0
  58. package/src/client/utils/ReadReceiptSync/readReceiptSyncEngine.ts +72 -98
  59. package/src/core/model/idResolvers.ts +2 -0
  60. package/src/marker/events/onChannelUnreadInfoUpdatedLocal.ts +29 -0
  61. package/src/marker/events/onChannelUnreadUpdatedLocal.ts +1 -1
  62. package/src/messageRepository/utils/markReadMessage.ts +10 -3
package/dist/index.cjs.js CHANGED
@@ -516,6 +516,7 @@ const idResolvers = {
516
516
  messagePreviewSubChannel: ({ subChannelId }) => `${subChannelId}`,
517
517
  channelUnreadInfo: ({ channelId }) => channelId,
518
518
  subChannelUnreadInfo: ({ subChannelId }) => subChannelId,
519
+ channelUnread: ({ channelId }) => channelId,
519
520
  channelMarker: ({ entityId, userId }) => `${entityId}#${userId}`,
520
521
  subChannelMarker: ({ entityId, feedId, userId }) => `${entityId}#${feedId}#${userId}`,
521
522
  messageMarker: ({ feedId, contentId, creatorId }) => `${feedId}#${contentId}#${creatorId}`,
@@ -1609,13 +1610,13 @@ class NetworkActivitiesWatcher {
1609
1610
  this._listener.clear();
1610
1611
  }
1611
1612
  }
1612
- let instance$5;
1613
+ let instance$6;
1613
1614
  var NetworkActivitiesWatcher$1 = {
1614
1615
  getInstance: () => {
1615
- if (!instance$5) {
1616
- instance$5 = new NetworkActivitiesWatcher();
1616
+ if (!instance$6) {
1617
+ instance$6 = new NetworkActivitiesWatcher();
1617
1618
  }
1618
- return instance$5;
1619
+ return instance$6;
1619
1620
  },
1620
1621
  };
1621
1622
 
@@ -5148,13 +5149,13 @@ class AnalyticsEngine {
5148
5149
  this._eventCapturer.resetAllBuckets();
5149
5150
  }
5150
5151
  }
5151
- let instance$4;
5152
+ let instance$5;
5152
5153
  var AnalyticsEngine$1 = {
5153
5154
  getInstance: () => {
5154
- if (!instance$4) {
5155
- instance$4 = new AnalyticsEngine();
5155
+ if (!instance$5) {
5156
+ instance$5 = new AnalyticsEngine();
5156
5157
  }
5157
- return instance$4;
5158
+ return instance$5;
5158
5159
  },
5159
5160
  };
5160
5161
 
@@ -5580,6 +5581,223 @@ const getMessageReadCount = (message, marker) => {
5580
5581
  getCachedMarker$2(message)) !== null && _a !== void 0 ? _a : { readCount: 0, deliveredCount: 0 };
5581
5582
  }; // and if not found in cache use default value `0`
5582
5583
 
5584
+ /**
5585
+ *
5586
+ * Mark subChannel as read by readToSegment
5587
+ *
5588
+ * @param subChannelIds the IDs of the {@link Amity.SubChannel} to update
5589
+ * @param readToSegment the segment to mark as read
5590
+ * @returns a success boolean if the {@link Amity.SubChannel} was updated
5591
+ *
5592
+ * @category Channel API
5593
+ * @async
5594
+ */
5595
+ const markChannelsAsReadBySegment = async (readings) => {
5596
+ const client = getActiveClient();
5597
+ try {
5598
+ await client.http.post('api/v3/channels/seen', { channels: readings });
5599
+ return true;
5600
+ }
5601
+ catch (e) {
5602
+ return false;
5603
+ }
5604
+ };
5605
+
5606
+ class MessageReadReceiptSyncEngine {
5607
+ constructor() {
5608
+ this.isActive = true;
5609
+ this.MAX_RETRY = 3;
5610
+ this.JOB_QUEUE_SIZE = 120;
5611
+ this.jobQueue = [];
5612
+ // Interval for message read receipt sync in seconds
5613
+ this.RECEIPT_SYNC_INTERVAL = 1;
5614
+ this.client = getActiveClient();
5615
+ // Get remaining unsync read receipts from cache
5616
+ this.getUnsyncJobs();
5617
+ }
5618
+ // Call this when client call client.login
5619
+ startSyncReadReceipt() {
5620
+ // Start timer when start receipt sync
5621
+ this.timer = setInterval(() => {
5622
+ this.syncReadReceipts();
5623
+ }, this.RECEIPT_SYNC_INTERVAL * 1000);
5624
+ }
5625
+ // Read receipt observer handling
5626
+ syncReadReceipts() {
5627
+ if (this.jobQueue.length === 0 || this.isActive === false)
5628
+ return;
5629
+ const readReceipts = this.getReadReceipts();
5630
+ console.log('[New 🌟 readReceipts] Sync read receipts', readReceipts);
5631
+ if (readReceipts) {
5632
+ this.markReadApi(readReceipts);
5633
+ }
5634
+ }
5635
+ getUnsyncJobs() {
5636
+ var _a;
5637
+ // Get all read receipts that has latestSyncSegment < latestSegment
5638
+ const readReceipts = (_a = queryCache(['readReceipt'])) === null || _a === void 0 ? void 0 : _a.filter(({ data }) => {
5639
+ return data.latestSyncSegment < data.latestSegment;
5640
+ });
5641
+ // Enqueue unsync read receipts to the job queue
5642
+ readReceipts === null || readReceipts === void 0 ? void 0 : readReceipts.forEach(({ data: readReceipt }) => {
5643
+ this.enqueueReadReceipt(readReceipt.channelId, readReceipt.latestSegment);
5644
+ });
5645
+ }
5646
+ getReadReceipts() {
5647
+ // get all read receipts from queue, now the queue is empty
5648
+ const syncJob = this.jobQueue.splice(0, this.jobQueue.length);
5649
+ if (syncJob.length === 0)
5650
+ return;
5651
+ return syncJob.filter(job => {
5652
+ var _a;
5653
+ const readReceipt = (_a = pullFromCache(['readReceipt', job.channelId])) === null || _a === void 0 ? void 0 : _a.data;
5654
+ if (!readReceipt)
5655
+ return false;
5656
+ if (readReceipt.latestSegment > readReceipt.latestSyncSegment)
5657
+ return true;
5658
+ return false;
5659
+ });
5660
+ }
5661
+ async markReadApi(syncJobs) {
5662
+ var _a;
5663
+ // constuct payload
5664
+ // example: [{ channelId: 'channelId', readToSegment: 2 }]
5665
+ const syncJobsPayload = syncJobs.map(job => {
5666
+ return {
5667
+ channelId: job.channelId,
5668
+ readToSegment: job.segment,
5669
+ };
5670
+ });
5671
+ const response = await markChannelsAsReadBySegment(syncJobsPayload);
5672
+ if (response) {
5673
+ for (let i = 0; i < syncJobs.length; i += 1) {
5674
+ // update lastestSyncSegment in read receipt cache
5675
+ const cacheKey = ['readReceipt', syncJobs[i].channelId];
5676
+ const readReceiptCache = (_a = pullFromCache(cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
5677
+ pushToCache(cacheKey, Object.assign(Object.assign({}, readReceiptCache), { latestSyncSegment: syncJobs[i].segment }));
5678
+ }
5679
+ }
5680
+ else {
5681
+ for (let i = 0; i < syncJobs.length; i += 1) {
5682
+ // push them back to queue if the syncing is failed and retry count is less than max retry
5683
+ if (syncJobs[i].retryCount >= this.MAX_RETRY)
5684
+ return;
5685
+ const updatedJob = Object.assign(Object.assign({}, syncJobs[i]), { syncState: "create" /* Amity.ReadReceiptSyncState.CREATED */, retryCount: syncJobs[i].retryCount + 1 });
5686
+ this.enqueueJob(updatedJob);
5687
+ }
5688
+ }
5689
+ }
5690
+ startObservingReadReceiptQueue() {
5691
+ if (this.client.useLegacyUnreadCount) {
5692
+ this.isActive = true;
5693
+ this.startSyncReadReceipt();
5694
+ }
5695
+ }
5696
+ stopObservingReadReceiptQueue() {
5697
+ this.isActive = false;
5698
+ this.jobQueue.map(job => {
5699
+ if (job.syncState === "syncing" /* Amity.ReadReceiptSyncState.SYNCING */) {
5700
+ return Object.assign(Object.assign({}, job), { syncState: "create" /* Amity.ReadReceiptSyncState.CREATED */ });
5701
+ }
5702
+ return job;
5703
+ });
5704
+ if (this.timer)
5705
+ clearInterval(this.timer);
5706
+ }
5707
+ // Session Management
5708
+ onSessionEstablished() {
5709
+ this.startObservingReadReceiptQueue();
5710
+ }
5711
+ onSessionDestroyed() {
5712
+ this.stopObservingReadReceiptQueue();
5713
+ this.jobQueue = [];
5714
+ }
5715
+ onTokenExpired() {
5716
+ this.stopObservingReadReceiptQueue();
5717
+ }
5718
+ // Network Connection Management
5719
+ onNetworkOffline() {
5720
+ // Stop observing to the read receipt queue.
5721
+ this.stopObservingReadReceiptQueue();
5722
+ }
5723
+ onNetworkOnline() {
5724
+ // Resume observing to the read receipt queue.
5725
+ this.startObservingReadReceiptQueue();
5726
+ }
5727
+ markRead(channelId, segment) {
5728
+ var _a;
5729
+ // Step 1: Optimistic update of channelUnread.readToSegment to message.segment and update unreadCount value
5730
+ const cacheKey = ['channelUnread', 'get', channelId];
5731
+ const channelUnread = (_a = pullFromCache(cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
5732
+ console.log('[New 🌟] Mark read => channel unread', channelUnread);
5733
+ if (channelUnread && segment > channelUnread.readToSegment) {
5734
+ channelUnread.readToSegment = segment;
5735
+ channelUnread.unreadCount = Math.max(channelUnread.lastSegment - segment, 0);
5736
+ pushToCache(cacheKey, channelUnread);
5737
+ fireEvent('local.channelUnread.updated', channelUnread);
5738
+ }
5739
+ // Step 2: Enqueue the read receipt
5740
+ this.enqueueReadReceipt(channelId, segment);
5741
+ }
5742
+ enqueueReadReceipt(channelId, segment) {
5743
+ var _a;
5744
+ const readReceipt = (_a = pullFromCache(['readReceipt', channelId])) === null || _a === void 0 ? void 0 : _a.data;
5745
+ // Create new read receipt if it's not exists and add the job to queue
5746
+ if (!readReceipt) {
5747
+ const readReceiptChannel = {
5748
+ channelId,
5749
+ latestSegment: segment,
5750
+ latestSyncSegment: 0,
5751
+ };
5752
+ pushToCache(['readReceipt', channelId], readReceiptChannel);
5753
+ }
5754
+ else if (readReceipt.latestSegment < segment) {
5755
+ // Update latestSegment in read receipt cache
5756
+ pushToCache(['readReceipt', channelId], Object.assign(Object.assign({}, readReceipt), { latestSegment: segment }));
5757
+ }
5758
+ else if (readReceipt.latestSyncSegment >= segment) {
5759
+ // Skip the job when lastSyncSegment > = segment
5760
+ return;
5761
+ }
5762
+ let syncJob = this.getSyncJob(channelId);
5763
+ if (syncJob === null || syncJob.syncState === "syncing" /* Amity.ReadReceiptSyncState.SYNCING */) {
5764
+ syncJob = {
5765
+ channelId,
5766
+ segment,
5767
+ syncState: "create" /* Amity.ReadReceiptSyncState.CREATED */,
5768
+ retryCount: 0,
5769
+ };
5770
+ this.enqueueJob(syncJob);
5771
+ }
5772
+ else if (syncJob.segment < segment) {
5773
+ syncJob.segment = segment;
5774
+ }
5775
+ }
5776
+ getSyncJob(channelId) {
5777
+ const { jobQueue } = this;
5778
+ const targetJob = jobQueue.find(job => job.channelId === channelId);
5779
+ return targetJob || null;
5780
+ }
5781
+ enqueueJob(syncJob) {
5782
+ if (this.jobQueue.length < this.JOB_QUEUE_SIZE) {
5783
+ this.jobQueue.push(syncJob);
5784
+ }
5785
+ else {
5786
+ // Remove oldest job when queue reach maximum capacity
5787
+ this.jobQueue.shift();
5788
+ this.jobQueue.push(syncJob);
5789
+ }
5790
+ }
5791
+ }
5792
+ let instance$4 = null;
5793
+ var ReadReceiptSyncEngine = {
5794
+ getInstance: () => {
5795
+ if (!instance$4)
5796
+ instance$4 = new MessageReadReceiptSyncEngine();
5797
+ return instance$4;
5798
+ },
5799
+ };
5800
+
5583
5801
  /**
5584
5802
  *
5585
5803
  * Mark subChannel as read by readToSegment
@@ -5628,7 +5846,7 @@ const reCalculateChannelUnreadInfo = (channelId) => {
5628
5846
  return channelUnreadInfo;
5629
5847
  };
5630
5848
 
5631
- class MessageReadReceiptSyncEngine {
5849
+ class LegacyMessageReadReceiptSyncEngine {
5632
5850
  constructor() {
5633
5851
  this.isActive = true;
5634
5852
  this.MAX_RETRY = 3;
@@ -5659,7 +5877,7 @@ class MessageReadReceiptSyncEngine {
5659
5877
  getUnsyncJobs() {
5660
5878
  var _a;
5661
5879
  // Get all read receipts that has latestSyncSegment < latestSegment
5662
- const readReceipts = (_a = queryCache(['readReceipt'])) === null || _a === void 0 ? void 0 : _a.filter(({ data }) => {
5880
+ const readReceipts = (_a = queryCache(['legacyReadReceipt'])) === null || _a === void 0 ? void 0 : _a.filter(({ data }) => {
5663
5881
  return data.latestSyncSegment < data.latestSegment;
5664
5882
  });
5665
5883
  // Enqueue unsync read receipts to the job queue
@@ -5678,7 +5896,7 @@ class MessageReadReceiptSyncEngine {
5678
5896
  return;
5679
5897
  // Get readReceipt from cache by subChannelId
5680
5898
  const readReceipt = (_a = pullFromCache([
5681
- 'readReceipt',
5899
+ 'legacyReadReceipt',
5682
5900
  syncJob.subChannelId,
5683
5901
  ])) === null || _a === void 0 ? void 0 : _a.data;
5684
5902
  if (!readReceipt)
@@ -5701,10 +5919,10 @@ class MessageReadReceiptSyncEngine {
5701
5919
  if (response) {
5702
5920
  this.removeSynedReceipt(syncJob.subChannelId, syncJob.segment);
5703
5921
  const readReceiptCache = (_a = pullFromCache([
5704
- 'readReceipt',
5922
+ 'legacyReadReceipt',
5705
5923
  subChannelId,
5706
5924
  ])) === null || _a === void 0 ? void 0 : _a.data;
5707
- pushToCache(['readReceipt', subChannelId], Object.assign(Object.assign({}, readReceiptCache), { latestSyncSegment: segment }));
5925
+ pushToCache(['legacyReadReceipt', subChannelId], Object.assign(Object.assign({}, readReceiptCache), { latestSyncSegment: segment }));
5708
5926
  }
5709
5927
  else if (!response) {
5710
5928
  if (newSyncJob.retryCount > this.MAX_RETRY) {
@@ -5771,7 +5989,7 @@ class MessageReadReceiptSyncEngine {
5771
5989
  subChannelUnreadInfo.readToSegment = segment;
5772
5990
  subChannelUnreadInfo.unreadCount = Math.max(subChannelUnreadInfo.lastSegment - segment, 0);
5773
5991
  const channelUnreadInfo = reCalculateChannelUnreadInfo(subChannelUnreadInfo.channelId);
5774
- fireEvent('local.channelUnread.updated', channelUnreadInfo);
5992
+ fireEvent('local.channelUnreadInfo.updated', channelUnreadInfo);
5775
5993
  pushToCache(cacheKey, subChannelUnreadInfo);
5776
5994
  fireEvent('local.subChannelUnread.updated', subChannelUnreadInfo);
5777
5995
  }
@@ -5780,7 +5998,10 @@ class MessageReadReceiptSyncEngine {
5780
5998
  }
5781
5999
  enqueueReadReceipt(subChannelId, segment) {
5782
6000
  var _a;
5783
- const readReceipt = (_a = pullFromCache(['readReceipt', subChannelId])) === null || _a === void 0 ? void 0 : _a.data;
6001
+ const readReceipt = (_a = pullFromCache([
6002
+ 'legacyReadReceipt',
6003
+ subChannelId,
6004
+ ])) === null || _a === void 0 ? void 0 : _a.data;
5784
6005
  // Create new read receipt if it's not exists and add job to queue
5785
6006
  if (!readReceipt) {
5786
6007
  const readReceiptSubChannel = {
@@ -5788,10 +6009,10 @@ class MessageReadReceiptSyncEngine {
5788
6009
  latestSegment: segment,
5789
6010
  latestSyncSegment: 0,
5790
6011
  };
5791
- pushToCache(['readReceipt', subChannelId], readReceiptSubChannel);
6012
+ pushToCache(['legacyReadReceipt', subChannelId], readReceiptSubChannel);
5792
6013
  }
5793
6014
  else if (readReceipt.latestSegment < segment) {
5794
- pushToCache(['readReceipt', subChannelId], Object.assign(Object.assign({}, readReceipt), { latestSegment: segment }));
6015
+ pushToCache(['legacyReadReceipt', subChannelId], Object.assign(Object.assign({}, readReceipt), { latestSegment: segment }));
5795
6016
  }
5796
6017
  else if (readReceipt.latestSyncSegment >= segment) {
5797
6018
  // Skip the job when lastSyncSegment > = segment
@@ -5834,18 +6055,24 @@ class MessageReadReceiptSyncEngine {
5834
6055
  }
5835
6056
  }
5836
6057
  let instance$3 = null;
5837
- var ReadReceiptSyncEngine = {
6058
+ var LegacyReadReceiptSyncEngine = {
5838
6059
  getInstance: () => {
5839
6060
  if (!instance$3)
5840
- instance$3 = new MessageReadReceiptSyncEngine();
6061
+ instance$3 = new LegacyMessageReadReceiptSyncEngine();
5841
6062
  return instance$3;
5842
6063
  },
5843
6064
  };
5844
6065
 
5845
6066
  const markReadMessage = (message) => {
5846
- const { subChannelId, channelSegment } = message;
5847
- const markReadReceiptEngine = ReadReceiptSyncEngine.getInstance();
5848
- markReadReceiptEngine.markRead(subChannelId, channelSegment);
6067
+ const client = getActiveClient();
6068
+ if (client.useLegacyUnreadCount) {
6069
+ const markReadReceiptEngine = ReadReceiptSyncEngine.getInstance();
6070
+ markReadReceiptEngine.markRead(message.channelId, message.channelSegment);
6071
+ }
6072
+ else {
6073
+ const markReadReceiptEngine = LegacyReadReceiptSyncEngine.getInstance();
6074
+ markReadReceiptEngine.markRead(message.subChannelId, message.channelSegment);
6075
+ }
5849
6076
  };
5850
6077
 
5851
6078
  const messageLinkedObject = (message) => {
@@ -6833,6 +7060,24 @@ const preUpdateChannelCache = (rawPayload, options = { isMessagePreviewUpdated:
6833
7060
  channels: rawPayload.channels.map(channel => convertFromRaw(channel, { isMessagePreviewUpdated: options.isMessagePreviewUpdated })),
6834
7061
  });
6835
7062
  };
7063
+ const updateChannelUnread = ({ currentUserId, channels, channelUsers, }) => {
7064
+ for (let i = 0; i < channels.length; i += 1) {
7065
+ const cacheKey = ['channelUnread', 'get', channels[i].channelId];
7066
+ const { readToSegment, lastMentionedSegment } = channelUsers.find(channelUser => channelUser.channelId === channels[i].channelId && channelUser.userId === currentUserId) || {
7067
+ readToSegment: 0,
7068
+ lastMentionedSegment: 0,
7069
+ };
7070
+ pushToCache(cacheKey, {
7071
+ channelId: channels[i].channelId,
7072
+ lastSegment: channels[i].messageCount,
7073
+ readToSegment,
7074
+ lastMentionedSegment,
7075
+ unreadCount: channels[i].messageCount - readToSegment,
7076
+ isMentioned: lastMentionedSegment > readToSegment,
7077
+ isDeleted: channels[i].isDeleted,
7078
+ });
7079
+ }
7080
+ };
6836
7081
  const prepareChannelPayload = async (rawPayload, options = { isMessagePreviewUpdated: true }) => {
6837
7082
  const client = getActiveClient();
6838
7083
  const networkPreviewSetting = await client.getMessagePreviewSetting(false);
@@ -6842,23 +7087,34 @@ const prepareChannelPayload = async (rawPayload, options = { isMessagePreviewUpd
6842
7087
  rawPayload.messagePreviews.length > 0) {
6843
7088
  updateChannelMessagePreviewCache(rawPayload);
6844
7089
  }
6845
- const markerIds = rawPayload.channels
6846
- // filter channel by type. Only conversation, community and broadcast type are included.
6847
- .filter(isUnreadCountSupport)
6848
- .map(({ channelInternalId }) => channelInternalId);
6849
- if (markerIds.length > 0) {
6850
- // since the get markers method requires a channel cache to function with the reducer.
6851
- preUpdateChannelCache(rawPayload, { isMessagePreviewUpdated: options.isMessagePreviewUpdated });
6852
- try {
6853
- await getChannelMarkers(markerIds);
6854
- }
6855
- catch (e) {
6856
- // empty block (from the spec, allow marker fetch to fail without having to do anything)
7090
+ if (client.useLegacyUnreadCount) {
7091
+ updateChannelUnread({
7092
+ channels: rawPayload.channels,
7093
+ channelUsers: rawPayload.channelUsers,
7094
+ currentUserId: client.userId,
7095
+ });
7096
+ }
7097
+ else {
7098
+ const markerIds = rawPayload.channels
7099
+ // filter channel by type. Only conversation, community and broadcast type are included.
7100
+ .filter(isUnreadCountSupport)
7101
+ .map(({ channelInternalId }) => channelInternalId);
7102
+ if (markerIds.length > 0) {
7103
+ // since the get markers method requires a channel cache to function with the reducer.
7104
+ preUpdateChannelCache(rawPayload, {
7105
+ isMessagePreviewUpdated: options.isMessagePreviewUpdated,
7106
+ });
7107
+ try {
7108
+ await getChannelMarkers(markerIds);
7109
+ }
7110
+ catch (e) {
7111
+ // empty block (from the spec, allow marker fetch to fail without having to do anything)
7112
+ }
6857
7113
  }
6858
7114
  }
6859
- // attach marker to channel
7115
+ // convert raw channel to internal channel
6860
7116
  const channels = rawPayload.channels.map(payload => convertFromRaw(payload, { isMessagePreviewUpdated: options.isMessagePreviewUpdated }));
6861
- // user marker to channel users
7117
+ // convert raw channel user to membership (add user object)
6862
7118
  const channelUsers = rawPayload.channelUsers.map(channelUser => {
6863
7119
  return convertRawMembershipToMembership(channelUser);
6864
7120
  });
@@ -6985,15 +7241,28 @@ const getSubChannelsUnreadCount = (channel, marker) => {
6985
7241
  return (_e = (_c = marker === null || marker === void 0 ? void 0 : marker.unreadCount) !== null && _c !== void 0 ? _c : (_d = getCachedMarker(channel.channelInternalId)) === null || _d === void 0 ? void 0 : _d.unreadCount) !== null && _e !== void 0 ? _e : 0;
6986
7242
  };
6987
7243
 
7244
+ const getLegacyChannelUnread = (channelId) => {
7245
+ var _a;
7246
+ return (_a = pullFromCache(['channelUnread', 'get', channelId])) === null || _a === void 0 ? void 0 : _a.data;
7247
+ };
7248
+
6988
7249
  const constructChannelDynamicValue = (channel) => {
7250
+ const client = getActiveClient();
6989
7251
  const rest = __rest(channel, ["messageCount"]);
6990
7252
  return shallowClone(rest, {
6991
- get isMentioned() {
6992
- return getChannelIsMentioned(rest);
7253
+ get unreadCount() {
7254
+ var _a, _b;
7255
+ return (_b = (_a = getLegacyChannelUnread(rest.channelId)) === null || _a === void 0 ? void 0 : _a.unreadCount) !== null && _b !== void 0 ? _b : 0;
6993
7256
  },
6994
7257
  get subChannelsUnreadCount() {
6995
7258
  return getSubChannelsUnreadCount(rest);
6996
7259
  },
7260
+ get isMentioned() {
7261
+ var _a, _b;
7262
+ if (client.useLegacyUnreadCount)
7263
+ return (_b = (_a = getLegacyChannelUnread(rest.channelId)) === null || _a === void 0 ? void 0 : _a.isMentioned) !== null && _b !== void 0 ? _b : false;
7264
+ return getChannelIsMentioned(rest);
7265
+ },
6997
7266
  });
6998
7267
  };
6999
7268
 
@@ -7769,6 +8038,25 @@ var readReceiptSyncEngineOnLoginHandler = () => {
7769
8038
  };
7770
8039
  };
7771
8040
 
8041
+ var legacyReadReceiptSyncEngineOnLoginHandler = () => {
8042
+ const readReceiptSyncEngine = LegacyReadReceiptSyncEngine.getInstance();
8043
+ readReceiptSyncEngine.startSyncReadReceipt();
8044
+ onSessionStateChange(state => {
8045
+ if (state === "established" /* Amity.SessionStates.ESTABLISHED */) {
8046
+ readReceiptSyncEngine.onSessionEstablished();
8047
+ }
8048
+ else if (state === "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */) {
8049
+ readReceiptSyncEngine.onTokenExpired();
8050
+ }
8051
+ else {
8052
+ readReceiptSyncEngine.onSessionDestroyed();
8053
+ }
8054
+ });
8055
+ return () => {
8056
+ readReceiptSyncEngine.onSessionDestroyed();
8057
+ };
8058
+ };
8059
+
7772
8060
  const onOnline = (callback) => {
7773
8061
  if (typeof window !== 'undefined' && window.addEventListener) {
7774
8062
  window.addEventListener('online', callback);
@@ -8781,6 +9069,7 @@ const enableUnreadCount = () => {
8781
9069
  if (client.isUnreadCountEnabled)
8782
9070
  return false;
8783
9071
  client.isUnreadCountEnabled = true;
9072
+ client.useLegacyUnreadCount = false;
8784
9073
  client.emitter.emit('unreadCountEnabled', true);
8785
9074
  return true;
8786
9075
  };
@@ -9096,7 +9385,12 @@ const login = async (params, sessionHandler, config) => {
9096
9385
  // NOTE: This is a temporary solution to handle the channel marker when the user is forced to leave
9097
9386
  // the channel because currently backend can't handle this, so every time a user is banned from
9098
9387
  // a channel or the channel is deleted the channel's unread count will not be reset to zero
9099
- onChannelDeleted(removeChannelMarkerCache), onChannelMemberBanned(removeChannelMarkerCache), markReadEngineOnLoginHandler(), analyticsEngineOnLoginHandler(), readReceiptSyncEngineOnLoginHandler(), objectResolverEngineOnLoginHandler());
9388
+ onChannelDeleted(removeChannelMarkerCache), onChannelMemberBanned(removeChannelMarkerCache), markReadEngineOnLoginHandler(), analyticsEngineOnLoginHandler(), objectResolverEngineOnLoginHandler());
9389
+ if (client.useLegacyUnreadCount) {
9390
+ subscriptions.push(readReceiptSyncEngineOnLoginHandler());
9391
+ }
9392
+ else
9393
+ subscriptions.push(legacyReadReceiptSyncEngineOnLoginHandler());
9100
9394
  const markerSyncUnsubscriber = await startMarkerSync();
9101
9395
  subscriptions.push(markerSyncUnsubscriber);
9102
9396
  }
@@ -9277,6 +9571,8 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
9277
9571
  const sessionState = "notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */;
9278
9572
  const sessionHandler = undefined;
9279
9573
  const isUnreadCountEnabled = false;
9574
+ // Legacy unread count is true by default
9575
+ const useLegacyUnreadCount = true;
9280
9576
  const client = {
9281
9577
  version: `${VERSION}`,
9282
9578
  apiKey,
@@ -9306,6 +9602,7 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
9306
9602
  getMessagePreviewSetting,
9307
9603
  use: () => setActiveClient(client),
9308
9604
  isUnreadCountEnabled,
9605
+ useLegacyUnreadCount,
9309
9606
  getMarkerSyncConsistentMode,
9310
9607
  /**
9311
9608
  * Prefix for the deviceId key in the local storage or async storage.
@@ -16436,6 +16733,24 @@ var index$f = /*#__PURE__*/Object.freeze({
16436
16733
  stopMessageReceiptSync: stopMessageReceiptSync
16437
16734
  });
16438
16735
 
16736
+ /**
16737
+ * Internal used only
16738
+ *
16739
+ * Fired when an {@link Amity.userMessageFeedMarkers} has been resolved by Object Rsesolver
16740
+ *
16741
+ * @param callback The function to call when the event was fired
16742
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
16743
+ *
16744
+ * @category MessageMarker Events
16745
+ */
16746
+ const onChannelUnreadInfoUpdatedLocal = (callback) => {
16747
+ const client = getActiveClient();
16748
+ const filter = (payload) => {
16749
+ callback(payload);
16750
+ };
16751
+ return createEventSubscriber(client, 'channelMarker/onChannelUnreadInfoUpdatedLocal', 'local.channelUnreadInfo.updated', filter);
16752
+ };
16753
+
16439
16754
  /**
16440
16755
  * Internal used only
16441
16756
  *
@@ -16451,7 +16766,7 @@ const onChannelUnreadUpdatedLocal = (callback) => {
16451
16766
  const filter = (payload) => {
16452
16767
  callback(payload);
16453
16768
  };
16454
- return createEventSubscriber(client, 'channelMarker/onChannelUnreadUpdatedLocal', 'local.channelUnread.updated', filter);
16769
+ return createEventSubscriber(client, 'channel/onChannelUnreadUpdatedLocal', 'local.channelUnread.updated', filter);
16455
16770
  };
16456
16771
 
16457
16772
  /* begin_public_function
@@ -16653,6 +16968,7 @@ const getChannel = (channelId, callback) => {
16653
16968
  return onSubChannelUpdated(updateMessagePreview);
16654
16969
  }, 'channelId', 'channel'),
16655
16970
  convertEventPayload(onSubChannelCreated, 'channelId', 'channel'),
16971
+ convertEventPayload(onChannelUnreadInfoUpdatedLocal, 'channelId', 'channel'),
16656
16972
  convertEventPayload(onChannelUnreadUpdatedLocal, 'channelId', 'channel'),
16657
16973
  ], {
16658
16974
  forceDispatch: true,
@@ -17166,6 +17482,10 @@ class ChannelLiveCollectionController extends LiveCollectionController {
17166
17482
  },
17167
17483
  action: "OnResolveUnread" /* Amity.ChannelActionType.OnResolveUnread */,
17168
17484
  },
17485
+ {
17486
+ fn: convertEventPayload(onChannelUnreadInfoUpdatedLocal, 'channelId', 'channel'),
17487
+ action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
17488
+ },
17169
17489
  {
17170
17490
  fn: convertEventPayload(onChannelUnreadUpdatedLocal, 'channelId', 'channel'),
17171
17491
  action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
@@ -23781,7 +24101,7 @@ var index$3 = /*#__PURE__*/Object.freeze({
23781
24101
  getPoll: getPoll
23782
24102
  });
23783
24103
 
23784
- const privateKey = "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDHo80SecH7FuF2\nhFYnb+l26/VN8UMLXAQFLnxciNTEwkGVFMpdezlH8rU2HtUJL4RETogbAOLVY0XM\njs6sPn8G1nALmh9qeDpUtVqFOVtBHxEZ910TLOtQiunjqJKO5nWdqZ71EC3OFluR\niGQkO84BiIFbv37ub7xl3S8XarbtKoLcyVpkDHi+1wx1pgCAn6gtBUgckPL5NR8j\nLseabl3HAXQfhTCKo4tmOFM2Dxwl1IUMmIJrJg/aIU/U0tj/1Eoo7mG0JcNWX19l\nW3EecCbi0ncCJOrkUdwlBrcjaMayaX/ubEwyUeTGiLdyc4L3GRLHjyK8xgVNXRMH\nbZWJ2a5NAgMBAAECggEASxuE+35zTFO/XydKgmvIGcWL9FbgMlXb7Vcf0nBoG945\nbiz0NVc2paraIhJXc608xbYF3qLmtAE1MVBI0ORyRdBHNxY024l/6H6SH60Ed+uI\nM4ysp5ourY6Vj+DLwpdRiI9YDjqYAQDIUmhNxJP7XPhOMoZI6st+xZQBM34ic/bv\nAMSJm9OZphSp3+qXVkFZztr2mxD2EZSJJLYxi8BCdgM2qhazalbcJ6zDKHCZWVWm\n8RRxDGldyMb/237JxETzP40tAlzOZDmBAbUgEnurDJ93RVDIE3rbZUshwgeQd18a\nem096mWgvB1AIKYgsTAR3pw+V19YWAjq/glP6fz8wQKBgQD/oQq+ukKF0PRgBeM5\ngeTjSwsdGppQLmf5ndujvoiz/TpdjDEPu6R8kigQr1rG2t4K/yfdZoI8RdmJD1al\n3Q7N9hofooSy4rj6E3txzWZCHJjHad2cnCp/O26HiReGAl7wTcfTmNdiFHhZQzm5\nJBkvWAiwuvQMNfEbnXxw6/vIDwKBgQDH7fX8gsc77JLvAWgp1MaQN/sbqVb6JeT1\nFQfR8E/WFCSmzQBtNzd5KgYuCeelwr/8DyYytvN2BzCYZXp73gI1jF3YlW5jVn74\nOY6TwQ095digwo6Z0yuxopdIOApKgAkL9PRKgNrqAf3NAyMua6lOGifzjDojC3KU\nfylQmxMn4wKBgHp2B9O/H0dEBw5JQ8W0+JX6yWQz7mEjGiR2/1W+XXb8hQ1zr709\nw1r6Gb+EghRpnZ3fBpYGGbYOMFx8wKHM+N6qW3F0ReX8v2juFGE8aRSa5oYBrWzt\nU16Idjbv8hj84cZ1PJmdyvDtpYn9rpWHOZl4rxEbPvbqkIsOMyNVqdT5AoGAOSge\nmwIIU2le2FVeohbibXiToWTYKMuMmURZ5/r72AgKMmWJKbAPe+Q3wBG01/7FRBpQ\noU8Ma0HC8s6QJbliiEyIx9JwrJWd1vkdecBHONrtA4ibm/5zD2WcOllLF+FitLhi\n3qnX6+6F0IaFGFBPJrTzlv0P4dTz/OAdv52V7GECgYEA2TttOKBAqWllgOaZOkql\nLVMJVmgR7s6tLi1+cEP8ZcapV9aRbRzTAKXm4f8AEhtlG9F9kCOvHYCYGi6JaiWJ\nZkHjeex3T+eE6Di6y5Bm/Ift5jtVhJ4jCVwHOKTMej79NPUFTJfv8hCo29haBDv6\nRXFrv+T21KCcw8k3sJeJWWQ=\n-----END PRIVATE KEY-----";
24104
+ const privateKey = "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDAARz+hmBgi8pJ\nQb8LeY41gtHhk+ACMwRfhsn7GqpqRQNG2qU0755mzZuVDUqjQMGSo8THJB7O+OJs\nflbZRkFXlFoFOVNw1UpNOgwEQZ6wB9oRwzepTJAfF1sVhm/o/ixvXh1zDFNDy6yZ\npXyiiJHUVxqyjllZhxnwdvjoVtDs6hW6awG09bB9nh/TTejlUKXoAgzqVwu/1QMu\nUVViET495elEe19aUarEy+oL2iKeXCEvqda/pWNBdbieFyJvvZ08HN8dPuT88wq2\njZLEAth1vrwQ2IAa4ktaLcBQdLJgIkrbDvAiVZ8lQAjS/bq5vXQikTGvoPlC5bbn\nvuOM/3eLAgMBAAECggEAVZ+peHAghq2QVj71nX5lxsNCKaCyYwixSJBpfouTt7Rz\nE6PpzMOXFi1W1o+I22jDakuSM2SOQKqI/u0QefB0r0O/KVk5NrZHXk0mkrdYtxOp\nUgaGyf8UvmjB+8VqHrNKyZdk9qtmbnNj01kTTcAtmE4H39zPR7eR/8Rul94vaZbs\nwCnKJS3mLT3JxyGug6lxanveKkjG+CKC1nJQYWaxCJxaFSzbwXQPvDhB+TvrIbee\npd5v4EAyEJohpr+T9oDGGJkb/KARBZCtwLyB976PKJwwBA8MRVL1i5QwawuMiMq5\nUtnOnbGKtCeFzaLbNU0Qi8bqyims84EQxC6DOu1fkQKBgQDdvsoBsEhsOXV7hlIJ\naEd0eSJZVkdqimxH8uGoMM2FeNaOrcB6yBXqTSP0R3OIyf8eaY6yjRvP30ZNXcll\n/gD3O1Mu6YmWQdt1W2WA6pKOsUuPXasf0pdOF7IiFZKlSabz5YHXFqwVuqm8loaj\nsXel3YWqPVdHiankE7tz+3ssnQKBgQDdqi4TNdD1MdEpihx19jr0QjUiXW3939FK\nqp30HESPEGDGQzXdmJgif9HhZb+cJSuWaHEbjgBrYahvgCF+y6LbEpOD+D/dmT+s\nDEAQaR84sah6dokwPjV8fjBSrcVFjCS+doxv0d3p/9OUEeyUhFrY03nxtIEYkLIE\n/Zvn37b4RwKBgQCLENVFe9XfsaVhQ5r9dV2iyTlmh7qgMZG5CbTFs12hQGhm8McO\n+Z7s41YSJCFr/yq1WwP4LJDtrBw99vyQr1zRsG35tNLp3gGRNzGQSQyC2uQFVHw2\np+7mNewsfhUK/gbrXNsyFnDz6635rPlhfbII3sWuP2wWXFqkxE9CbMwR7QKBgQC6\nawDMzxmo2/iYArrkyevSuEuPVxvFwpF1RgAI6C0QVCnPE38dmdN4UB7mfHekje4W\nVEercMURidPp0cxZolCYBQtilUjAyL0vqC3In1/Ogjq6oy3FEMxSop1pKxMY5j+Q\nnoqFD+6deLUrddeNH7J3X4LSr4dSbX4JjG+tlgt+yQKBgQCuwTL4hA6KqeInQ0Ta\n9VQX5Qr8hFlqJz1gpymi/k63tW/Ob8yedbg3WWNWyShwRMFYyY9S81ITFWM95uL6\nvF3x9rmRjwElJw9PMwVu6dmf/CO0Z1wzXSp2VVD12gbrUD/0/d7MUoJ9LgC8X8f/\nn0txLHYGHbx+nf95+JUg6lV3hg==\n-----END PRIVATE KEY-----";
23785
24105
  /*
23786
24106
  * The crypto algorithm used for importing key and signing string
23787
24107
  */