@amityco/ts-sdk 7.1.1-1d526d8.0 → 7.1.1-279cf96.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 (87) hide show
  1. package/dist/@types/core/events.d.ts +2 -1
  2. package/dist/@types/core/events.d.ts.map +1 -1
  3. package/dist/@types/core/model.d.ts +2 -0
  4. package/dist/@types/core/model.d.ts.map +1 -1
  5. package/dist/@types/core/readReceipt.d.ts +12 -1
  6. package/dist/@types/core/readReceipt.d.ts.map +1 -1
  7. package/dist/@types/domains/channel.d.ts +10 -0
  8. package/dist/@types/domains/channel.d.ts.map +1 -1
  9. package/dist/@types/domains/client.d.ts +2 -0
  10. package/dist/@types/domains/client.d.ts.map +1 -1
  11. package/dist/channelRepository/api/markChannelsAsReadBySegment.d.ts +16 -0
  12. package/dist/channelRepository/api/markChannelsAsReadBySegment.d.ts.map +1 -0
  13. package/dist/channelRepository/events/onChannelDeleted.d.ts.map +1 -1
  14. package/dist/channelRepository/events/onChannelLeft.d.ts.map +1 -1
  15. package/dist/{marker → channelRepository}/events/onChannelUnreadUpdatedLocal.d.ts +2 -2
  16. package/dist/channelRepository/events/onChannelUnreadUpdatedLocal.d.ts.map +1 -0
  17. package/dist/channelRepository/internalApi/getTotalChannelsUnread.d.ts +11 -0
  18. package/dist/channelRepository/internalApi/getTotalChannelsUnread.d.ts.map +1 -0
  19. package/dist/channelRepository/observers/getChannel.d.ts.map +1 -1
  20. package/dist/channelRepository/observers/getChannels/ChannelLiveCollectionController.d.ts.map +1 -1
  21. package/dist/channelRepository/observers/getTotalChannelsUnread.d.ts +20 -0
  22. package/dist/channelRepository/observers/getTotalChannelsUnread.d.ts.map +1 -0
  23. package/dist/channelRepository/observers/index.d.ts +1 -0
  24. package/dist/channelRepository/observers/index.d.ts.map +1 -1
  25. package/dist/channelRepository/utils/constructChannelDynamicValue.d.ts.map +1 -1
  26. package/dist/channelRepository/utils/getLegacyChannelUnread.d.ts +2 -0
  27. package/dist/channelRepository/utils/getLegacyChannelUnread.d.ts.map +1 -0
  28. package/dist/channelRepository/utils/prepareChannelPayload.d.ts.map +1 -1
  29. package/dist/client/api/createClient.d.ts +1 -0
  30. package/dist/client/api/createClient.d.ts.map +1 -1
  31. package/dist/client/api/enableUnreadCount.d.ts.map +1 -1
  32. package/dist/client/api/login.d.ts.map +1 -1
  33. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.d.ts +33 -0
  34. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.d.ts.map +1 -0
  35. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.d.ts +3 -0
  36. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.d.ts.map +1 -0
  37. package/dist/client/utils/ReadReceiptSync/readReceiptSyncEngine.d.ts +2 -4
  38. package/dist/client/utils/ReadReceiptSync/readReceiptSyncEngine.d.ts.map +1 -1
  39. package/dist/client/utils/endpoints.d.ts +1 -0
  40. package/dist/client/utils/endpoints.d.ts.map +1 -1
  41. package/dist/client/utils/setClientToken.d.ts.map +1 -1
  42. package/dist/core/events.d.ts +3 -3
  43. package/dist/core/events.d.ts.map +1 -1
  44. package/dist/core/model/idResolvers.d.ts.map +1 -1
  45. package/dist/index.cjs.js +551 -55
  46. package/dist/index.esm.js +551 -55
  47. package/dist/index.umd.js +4 -4
  48. package/dist/marker/events/onChannelUnreadInfoUpdatedLocal.d.ts +12 -0
  49. package/dist/marker/events/onChannelUnreadInfoUpdatedLocal.d.ts.map +1 -0
  50. package/dist/messageRepository/events/onMessageCreated.d.ts.map +1 -1
  51. package/dist/messageRepository/observers/getMessage.d.ts.map +1 -1
  52. package/dist/messageRepository/utils/markReadMessage.d.ts.map +1 -1
  53. package/package.json +1 -1
  54. package/src/@types/core/events.ts +2 -1
  55. package/src/@types/core/model.ts +4 -0
  56. package/src/@types/core/readReceipt.ts +14 -1
  57. package/src/@types/domains/channel.ts +13 -0
  58. package/src/@types/domains/client.ts +3 -0
  59. package/src/channelRepository/api/markChannelsAsReadBySegment.ts +29 -0
  60. package/src/channelRepository/events/onChannelDeleted.ts +17 -4
  61. package/src/channelRepository/events/onChannelLeft.ts +11 -3
  62. package/src/{marker → channelRepository}/events/onChannelUnreadUpdatedLocal.ts +3 -3
  63. package/src/channelRepository/internalApi/getTotalChannelsUnread.ts +38 -0
  64. package/src/channelRepository/observers/getChannel.ts +3 -1
  65. package/src/channelRepository/observers/getChannels/ChannelLiveCollectionController.ts +6 -1
  66. package/src/channelRepository/observers/getTotalChannelsUnread.ts +129 -0
  67. package/src/channelRepository/observers/index.ts +1 -0
  68. package/src/channelRepository/utils/constructChannelDynamicValue.ts +12 -2
  69. package/src/channelRepository/utils/getLegacyChannelUnread.ts +5 -0
  70. package/src/channelRepository/utils/prepareChannelPayload.ts +66 -17
  71. package/src/client/api/createClient.ts +7 -1
  72. package/src/client/api/enableUnreadCount.ts +1 -0
  73. package/src/client/api/login.ts +5 -1
  74. package/src/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.ts +267 -0
  75. package/src/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.ts +21 -0
  76. package/src/client/utils/ReadReceiptSync/readReceiptSyncEngine.ts +74 -99
  77. package/src/client/utils/endpoints.ts +1 -0
  78. package/src/client/utils/setClientToken.ts +8 -0
  79. package/src/core/model/idResolvers.ts +2 -0
  80. package/src/fileRepository/api/uploadFile.ts +1 -1
  81. package/src/fileRepository/api/uploadImage.ts +1 -1
  82. package/src/fileRepository/api/uploadVideo.ts +1 -1
  83. package/src/marker/events/onChannelUnreadInfoUpdatedLocal.ts +29 -0
  84. package/src/messageRepository/events/onMessageCreated.ts +45 -1
  85. package/src/messageRepository/observers/getMessage.ts +0 -1
  86. package/src/messageRepository/utils/markReadMessage.ts +10 -3
  87. package/dist/marker/events/onChannelUnreadUpdatedLocal.d.ts.map +0 -1
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}`,
@@ -1561,6 +1562,7 @@ const API_REGIONS = {
1561
1562
  };
1562
1563
  const URLS = {
1563
1564
  http: 'https://apix.{region}.amity.co',
1565
+ upload: 'https://upload.{region}.amity.co',
1564
1566
  mqtt: 'wss://sse.{region}.amity.co:443/mqtt',
1565
1567
  };
1566
1568
  function computeUrl(type, region) {
@@ -1609,13 +1611,13 @@ class NetworkActivitiesWatcher {
1609
1611
  this._listener.clear();
1610
1612
  }
1611
1613
  }
1612
- let instance$5;
1614
+ let instance$6;
1613
1615
  var NetworkActivitiesWatcher$1 = {
1614
1616
  getInstance: () => {
1615
- if (!instance$5) {
1616
- instance$5 = new NetworkActivitiesWatcher();
1617
+ if (!instance$6) {
1618
+ instance$6 = new NetworkActivitiesWatcher();
1617
1619
  }
1618
- return instance$5;
1620
+ return instance$6;
1619
1621
  },
1620
1622
  };
1621
1623
 
@@ -5148,13 +5150,13 @@ class AnalyticsEngine {
5148
5150
  this._eventCapturer.resetAllBuckets();
5149
5151
  }
5150
5152
  }
5151
- let instance$4;
5153
+ let instance$5;
5152
5154
  var AnalyticsEngine$1 = {
5153
5155
  getInstance: () => {
5154
- if (!instance$4) {
5155
- instance$4 = new AnalyticsEngine();
5156
+ if (!instance$5) {
5157
+ instance$5 = new AnalyticsEngine();
5156
5158
  }
5157
- return instance$4;
5159
+ return instance$5;
5158
5160
  },
5159
5161
  };
5160
5162
 
@@ -5580,6 +5582,223 @@ const getMessageReadCount = (message, marker) => {
5580
5582
  getCachedMarker$2(message)) !== null && _a !== void 0 ? _a : { readCount: 0, deliveredCount: 0 };
5581
5583
  }; // and if not found in cache use default value `0`
5582
5584
 
5585
+ /**
5586
+ *
5587
+ * Mark subChannel as read by readToSegment
5588
+ *
5589
+ * @param subChannelIds the IDs of the {@link Amity.SubChannel} to update
5590
+ * @param readToSegment the segment to mark as read
5591
+ * @returns a success boolean if the {@link Amity.SubChannel} was updated
5592
+ *
5593
+ * @category Channel API
5594
+ * @async
5595
+ */
5596
+ const markChannelsAsReadBySegment = async (readings) => {
5597
+ const client = getActiveClient();
5598
+ try {
5599
+ await client.http.post('api/v3/channels/seen', { channels: readings });
5600
+ return true;
5601
+ }
5602
+ catch (e) {
5603
+ return false;
5604
+ }
5605
+ };
5606
+
5607
+ class MessageReadReceiptSyncEngine {
5608
+ constructor() {
5609
+ this.isActive = true;
5610
+ this.MAX_RETRY = 3;
5611
+ this.JOB_QUEUE_SIZE = 120;
5612
+ this.jobQueue = [];
5613
+ // Interval for message read receipt sync in seconds
5614
+ this.RECEIPT_SYNC_INTERVAL = 1;
5615
+ this.client = getActiveClient();
5616
+ // Get remaining unsync read receipts from cache
5617
+ this.getUnsyncJobs();
5618
+ }
5619
+ // Call this when client call client.login
5620
+ startSyncReadReceipt() {
5621
+ // Start timer when start receipt sync
5622
+ this.timer = setInterval(() => {
5623
+ this.syncReadReceipts();
5624
+ }, this.RECEIPT_SYNC_INTERVAL * 1000);
5625
+ }
5626
+ // Read receipt observer handling
5627
+ syncReadReceipts() {
5628
+ if (this.jobQueue.length === 0 || this.isActive === false)
5629
+ return;
5630
+ const readReceipts = this.getReadReceipts();
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
+ if (typeof (channelUnread === null || channelUnread === void 0 ? void 0 : channelUnread.readToSegment) === 'number' &&
5733
+ channelUnread &&
5734
+ segment > channelUnread.readToSegment) {
5735
+ channelUnread.readToSegment = segment;
5736
+ channelUnread.unreadCount = Math.max(channelUnread.lastSegment - segment, 0);
5737
+ pushToCache(cacheKey, channelUnread);
5738
+ fireEvent('local.channelUnread.updated', channelUnread);
5739
+ }
5740
+ // Step 2: Enqueue the read receipt
5741
+ this.enqueueReadReceipt(channelId, segment);
5742
+ }
5743
+ enqueueReadReceipt(channelId, segment) {
5744
+ var _a;
5745
+ const readReceipt = (_a = pullFromCache(['readReceipt', channelId])) === null || _a === void 0 ? void 0 : _a.data;
5746
+ // Create new read receipt if it's not exists and add the job to queue
5747
+ if (!readReceipt) {
5748
+ const readReceiptChannel = {
5749
+ channelId,
5750
+ latestSegment: segment,
5751
+ latestSyncSegment: 0,
5752
+ };
5753
+ pushToCache(['readReceipt', channelId], readReceiptChannel);
5754
+ }
5755
+ else if (readReceipt.latestSegment < segment) {
5756
+ // Update latestSegment in read receipt cache
5757
+ pushToCache(['readReceipt', channelId], Object.assign(Object.assign({}, readReceipt), { latestSegment: segment }));
5758
+ }
5759
+ else if (readReceipt.latestSyncSegment >= segment) {
5760
+ // Skip the job when lastSyncSegment > = segment
5761
+ return;
5762
+ }
5763
+ let syncJob = this.getSyncJob(channelId);
5764
+ if (syncJob === null || syncJob.syncState === "syncing" /* Amity.ReadReceiptSyncState.SYNCING */) {
5765
+ syncJob = {
5766
+ channelId,
5767
+ segment,
5768
+ syncState: "create" /* Amity.ReadReceiptSyncState.CREATED */,
5769
+ retryCount: 0,
5770
+ };
5771
+ this.enqueueJob(syncJob);
5772
+ }
5773
+ else if (syncJob.segment < segment) {
5774
+ syncJob.segment = segment;
5775
+ }
5776
+ }
5777
+ getSyncJob(channelId) {
5778
+ const { jobQueue } = this;
5779
+ const targetJob = jobQueue.find(job => job.channelId === channelId);
5780
+ return targetJob || null;
5781
+ }
5782
+ enqueueJob(syncJob) {
5783
+ if (this.jobQueue.length < this.JOB_QUEUE_SIZE) {
5784
+ this.jobQueue.push(syncJob);
5785
+ }
5786
+ else {
5787
+ // Remove oldest job when queue reach maximum capacity
5788
+ this.jobQueue.shift();
5789
+ this.jobQueue.push(syncJob);
5790
+ }
5791
+ }
5792
+ }
5793
+ let instance$4 = null;
5794
+ var ReadReceiptSyncEngine = {
5795
+ getInstance: () => {
5796
+ if (!instance$4)
5797
+ instance$4 = new MessageReadReceiptSyncEngine();
5798
+ return instance$4;
5799
+ },
5800
+ };
5801
+
5583
5802
  /**
5584
5803
  *
5585
5804
  * Mark subChannel as read by readToSegment
@@ -5628,7 +5847,7 @@ const reCalculateChannelUnreadInfo = (channelId) => {
5628
5847
  return channelUnreadInfo;
5629
5848
  };
5630
5849
 
5631
- class MessageReadReceiptSyncEngine {
5850
+ class LegacyMessageReadReceiptSyncEngine {
5632
5851
  constructor() {
5633
5852
  this.isActive = true;
5634
5853
  this.MAX_RETRY = 3;
@@ -5659,7 +5878,7 @@ class MessageReadReceiptSyncEngine {
5659
5878
  getUnsyncJobs() {
5660
5879
  var _a;
5661
5880
  // Get all read receipts that has latestSyncSegment < latestSegment
5662
- const readReceipts = (_a = queryCache(['readReceipt'])) === null || _a === void 0 ? void 0 : _a.filter(({ data }) => {
5881
+ const readReceipts = (_a = queryCache(['legacyReadReceipt'])) === null || _a === void 0 ? void 0 : _a.filter(({ data }) => {
5663
5882
  return data.latestSyncSegment < data.latestSegment;
5664
5883
  });
5665
5884
  // Enqueue unsync read receipts to the job queue
@@ -5678,7 +5897,7 @@ class MessageReadReceiptSyncEngine {
5678
5897
  return;
5679
5898
  // Get readReceipt from cache by subChannelId
5680
5899
  const readReceipt = (_a = pullFromCache([
5681
- 'readReceipt',
5900
+ 'legacyReadReceipt',
5682
5901
  syncJob.subChannelId,
5683
5902
  ])) === null || _a === void 0 ? void 0 : _a.data;
5684
5903
  if (!readReceipt)
@@ -5701,10 +5920,10 @@ class MessageReadReceiptSyncEngine {
5701
5920
  if (response) {
5702
5921
  this.removeSynedReceipt(syncJob.subChannelId, syncJob.segment);
5703
5922
  const readReceiptCache = (_a = pullFromCache([
5704
- 'readReceipt',
5923
+ 'legacyReadReceipt',
5705
5924
  subChannelId,
5706
5925
  ])) === null || _a === void 0 ? void 0 : _a.data;
5707
- pushToCache(['readReceipt', subChannelId], Object.assign(Object.assign({}, readReceiptCache), { latestSyncSegment: segment }));
5926
+ pushToCache(['legacyReadReceipt', subChannelId], Object.assign(Object.assign({}, readReceiptCache), { latestSyncSegment: segment }));
5708
5927
  }
5709
5928
  else if (!response) {
5710
5929
  if (newSyncJob.retryCount > this.MAX_RETRY) {
@@ -5771,7 +5990,7 @@ class MessageReadReceiptSyncEngine {
5771
5990
  subChannelUnreadInfo.readToSegment = segment;
5772
5991
  subChannelUnreadInfo.unreadCount = Math.max(subChannelUnreadInfo.lastSegment - segment, 0);
5773
5992
  const channelUnreadInfo = reCalculateChannelUnreadInfo(subChannelUnreadInfo.channelId);
5774
- fireEvent('local.channelUnread.updated', channelUnreadInfo);
5993
+ fireEvent('local.channelUnreadInfo.updated', channelUnreadInfo);
5775
5994
  pushToCache(cacheKey, subChannelUnreadInfo);
5776
5995
  fireEvent('local.subChannelUnread.updated', subChannelUnreadInfo);
5777
5996
  }
@@ -5780,7 +5999,10 @@ class MessageReadReceiptSyncEngine {
5780
5999
  }
5781
6000
  enqueueReadReceipt(subChannelId, segment) {
5782
6001
  var _a;
5783
- const readReceipt = (_a = pullFromCache(['readReceipt', subChannelId])) === null || _a === void 0 ? void 0 : _a.data;
6002
+ const readReceipt = (_a = pullFromCache([
6003
+ 'legacyReadReceipt',
6004
+ subChannelId,
6005
+ ])) === null || _a === void 0 ? void 0 : _a.data;
5784
6006
  // Create new read receipt if it's not exists and add job to queue
5785
6007
  if (!readReceipt) {
5786
6008
  const readReceiptSubChannel = {
@@ -5788,10 +6010,10 @@ class MessageReadReceiptSyncEngine {
5788
6010
  latestSegment: segment,
5789
6011
  latestSyncSegment: 0,
5790
6012
  };
5791
- pushToCache(['readReceipt', subChannelId], readReceiptSubChannel);
6013
+ pushToCache(['legacyReadReceipt', subChannelId], readReceiptSubChannel);
5792
6014
  }
5793
6015
  else if (readReceipt.latestSegment < segment) {
5794
- pushToCache(['readReceipt', subChannelId], Object.assign(Object.assign({}, readReceipt), { latestSegment: segment }));
6016
+ pushToCache(['legacyReadReceipt', subChannelId], Object.assign(Object.assign({}, readReceipt), { latestSegment: segment }));
5795
6017
  }
5796
6018
  else if (readReceipt.latestSyncSegment >= segment) {
5797
6019
  // Skip the job when lastSyncSegment > = segment
@@ -5834,18 +6056,24 @@ class MessageReadReceiptSyncEngine {
5834
6056
  }
5835
6057
  }
5836
6058
  let instance$3 = null;
5837
- var ReadReceiptSyncEngine = {
6059
+ var LegacyReadReceiptSyncEngine = {
5838
6060
  getInstance: () => {
5839
6061
  if (!instance$3)
5840
- instance$3 = new MessageReadReceiptSyncEngine();
6062
+ instance$3 = new LegacyMessageReadReceiptSyncEngine();
5841
6063
  return instance$3;
5842
6064
  },
5843
6065
  };
5844
6066
 
5845
6067
  const markReadMessage = (message) => {
5846
- const { subChannelId, channelSegment } = message;
5847
- const markReadReceiptEngine = ReadReceiptSyncEngine.getInstance();
5848
- markReadReceiptEngine.markRead(subChannelId, channelSegment);
6068
+ const client = getActiveClient();
6069
+ if (client.useLegacyUnreadCount) {
6070
+ const markReadReceiptEngine = ReadReceiptSyncEngine.getInstance();
6071
+ markReadReceiptEngine.markRead(message.channelId, message.channelSegment);
6072
+ }
6073
+ else {
6074
+ const markReadReceiptEngine = LegacyReadReceiptSyncEngine.getInstance();
6075
+ markReadReceiptEngine.markRead(message.subChannelId, message.channelSegment);
6076
+ }
5849
6077
  };
5850
6078
 
5851
6079
  const messageLinkedObject = (message) => {
@@ -6833,6 +7061,31 @@ const preUpdateChannelCache = (rawPayload, options = { isMessagePreviewUpdated:
6833
7061
  channels: rawPayload.channels.map(channel => convertFromRaw(channel, { isMessagePreviewUpdated: options.isMessagePreviewUpdated })),
6834
7062
  });
6835
7063
  };
7064
+ const updateChannelUnread = ({ currentUserId, channels, channelUsers, }) => {
7065
+ for (let i = 0; i < channels.length; i += 1) {
7066
+ const cacheKey = ['channelUnread', 'get', channels[i].channelId];
7067
+ const channelUser = channelUsers.find(channelUser => channelUser.channelId === channels[i].channelId && channelUser.userId === currentUserId);
7068
+ let unreadCount = 0;
7069
+ let readToSegment = null;
7070
+ let lastMentionedSegment = null;
7071
+ let isMentioned = false;
7072
+ if (channelUser) {
7073
+ readToSegment = channelUser.readToSegment;
7074
+ lastMentionedSegment = channelUser.lastMentionedSegment;
7075
+ unreadCount = Math.max(channels[i].messageCount - readToSegment, 0);
7076
+ isMentioned = lastMentionedSegment > readToSegment;
7077
+ }
7078
+ pushToCache(cacheKey, {
7079
+ channelId: channels[i].channelId,
7080
+ lastSegment: channels[i].messageCount,
7081
+ readToSegment,
7082
+ lastMentionedSegment,
7083
+ unreadCount,
7084
+ isMentioned,
7085
+ isDeleted: channels[i].isDeleted,
7086
+ });
7087
+ }
7088
+ };
6836
7089
  const prepareChannelPayload = async (rawPayload, options = { isMessagePreviewUpdated: true }) => {
6837
7090
  const client = getActiveClient();
6838
7091
  const networkPreviewSetting = await client.getMessagePreviewSetting(false);
@@ -6842,23 +7095,34 @@ const prepareChannelPayload = async (rawPayload, options = { isMessagePreviewUpd
6842
7095
  rawPayload.messagePreviews.length > 0) {
6843
7096
  updateChannelMessagePreviewCache(rawPayload);
6844
7097
  }
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)
7098
+ if (client.useLegacyUnreadCount) {
7099
+ updateChannelUnread({
7100
+ channels: rawPayload.channels,
7101
+ channelUsers: rawPayload.channelUsers,
7102
+ currentUserId: client.userId,
7103
+ });
7104
+ }
7105
+ else {
7106
+ const markerIds = rawPayload.channels
7107
+ // filter channel by type. Only conversation, community and broadcast type are included.
7108
+ .filter(isUnreadCountSupport)
7109
+ .map(({ channelInternalId }) => channelInternalId);
7110
+ if (markerIds.length > 0) {
7111
+ // since the get markers method requires a channel cache to function with the reducer.
7112
+ preUpdateChannelCache(rawPayload, {
7113
+ isMessagePreviewUpdated: options.isMessagePreviewUpdated,
7114
+ });
7115
+ try {
7116
+ await getChannelMarkers(markerIds);
7117
+ }
7118
+ catch (e) {
7119
+ // empty block (from the spec, allow marker fetch to fail without having to do anything)
7120
+ }
6857
7121
  }
6858
7122
  }
6859
- // attach marker to channel
7123
+ // convert raw channel to internal channel
6860
7124
  const channels = rawPayload.channels.map(payload => convertFromRaw(payload, { isMessagePreviewUpdated: options.isMessagePreviewUpdated }));
6861
- // user marker to channel users
7125
+ // convert raw channel user to membership (add user object)
6862
7126
  const channelUsers = rawPayload.channelUsers.map(channelUser => {
6863
7127
  return convertRawMembershipToMembership(channelUser);
6864
7128
  });
@@ -6985,15 +7249,28 @@ const getSubChannelsUnreadCount = (channel, marker) => {
6985
7249
  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
7250
  };
6987
7251
 
7252
+ const getLegacyChannelUnread = (channelId) => {
7253
+ var _a;
7254
+ return (_a = pullFromCache(['channelUnread', 'get', channelId])) === null || _a === void 0 ? void 0 : _a.data;
7255
+ };
7256
+
6988
7257
  const constructChannelDynamicValue = (channel) => {
7258
+ const client = getActiveClient();
6989
7259
  const rest = __rest(channel, ["messageCount"]);
6990
7260
  return shallowClone(rest, {
6991
- get isMentioned() {
6992
- return getChannelIsMentioned(rest);
7261
+ get unreadCount() {
7262
+ var _a, _b;
7263
+ return (_b = (_a = getLegacyChannelUnread(rest.channelId)) === null || _a === void 0 ? void 0 : _a.unreadCount) !== null && _b !== void 0 ? _b : 0;
6993
7264
  },
6994
7265
  get subChannelsUnreadCount() {
6995
7266
  return getSubChannelsUnreadCount(rest);
6996
7267
  },
7268
+ get isMentioned() {
7269
+ var _a, _b;
7270
+ if (client.useLegacyUnreadCount)
7271
+ return (_b = (_a = getLegacyChannelUnread(rest.channelId)) === null || _a === void 0 ? void 0 : _a.isMentioned) !== null && _b !== void 0 ? _b : false;
7272
+ return getChannelIsMentioned(rest);
7273
+ },
6997
7274
  });
6998
7275
  };
6999
7276
 
@@ -7606,6 +7883,12 @@ const setClientToken = async (params) => {
7606
7883
  isGlobalBanned: false,
7607
7884
  isUserDeleted: false,
7608
7885
  };
7886
+ client.upload.defaults.headers.common.Authorization = `Bearer ${accessToken}`;
7887
+ client.upload.defaults.metadata = {
7888
+ tokenExpiry: expiresAt,
7889
+ isGlobalBanned: false,
7890
+ isUserDeleted: false,
7891
+ };
7609
7892
  // manually setup the token for ws transport
7610
7893
  if (client.ws)
7611
7894
  client.ws.io.opts.query = { token: accessToken };
@@ -7650,12 +7933,21 @@ const onChannelDeleted = (callback) => {
7650
7933
  const client = getActiveClient();
7651
7934
  const filter = async (payload) => {
7652
7935
  const data = await prepareChannelPayload(payload);
7653
- if (client.isUnreadCountEnabled && client.getMarkerSyncConsistentMode()) {
7654
- data.channels.forEach(channel => {
7936
+ const isConsistentMode = client.getMarkerSyncConsistentMode() && client.isUnreadCountEnabled;
7937
+ const isLegacyUnreadCount = client.useLegacyUnreadCount;
7938
+ data.channels.forEach(channel => {
7939
+ if (isConsistentMode) {
7655
7940
  addFlagIsDeletedSubChannelUnreadByChannelId(channel.channelId);
7656
7941
  deleteChannelUnreadByChannelId(channel.channelId);
7657
- });
7658
- }
7942
+ }
7943
+ else if (isLegacyUnreadCount) {
7944
+ const cacheKey = ['channelUnread', 'get', channel.channelId];
7945
+ const cache = pullFromCache(cacheKey);
7946
+ if (cache) {
7947
+ pushToCache(cacheKey, Object.assign(Object.assign({}, cache), { isDeleted: true }));
7948
+ }
7949
+ }
7950
+ });
7659
7951
  ingestInCache(data);
7660
7952
  callbacks$b.forEach(cb => cb(data.channels[0]));
7661
7953
  };
@@ -7769,6 +8061,25 @@ var readReceiptSyncEngineOnLoginHandler = () => {
7769
8061
  };
7770
8062
  };
7771
8063
 
8064
+ var legacyReadReceiptSyncEngineOnLoginHandler = () => {
8065
+ const readReceiptSyncEngine = LegacyReadReceiptSyncEngine.getInstance();
8066
+ readReceiptSyncEngine.startSyncReadReceipt();
8067
+ onSessionStateChange(state => {
8068
+ if (state === "established" /* Amity.SessionStates.ESTABLISHED */) {
8069
+ readReceiptSyncEngine.onSessionEstablished();
8070
+ }
8071
+ else if (state === "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */) {
8072
+ readReceiptSyncEngine.onTokenExpired();
8073
+ }
8074
+ else {
8075
+ readReceiptSyncEngine.onSessionDestroyed();
8076
+ }
8077
+ });
8078
+ return () => {
8079
+ readReceiptSyncEngine.onSessionDestroyed();
8080
+ };
8081
+ };
8082
+
7772
8083
  const onOnline = (callback) => {
7773
8084
  if (typeof window !== 'undefined' && window.addEventListener) {
7774
8085
  window.addEventListener('online', callback);
@@ -8335,10 +8646,17 @@ const onChannelLeft = (callback) => {
8335
8646
  const preparedPayload = await prepareChannelPayload(payload, {
8336
8647
  isMessagePreviewUpdated: isLeftByMe,
8337
8648
  });
8338
- if (client.isUnreadCountEnabled && client.getMarkerSyncConsistentMode() && isLeftByMe) {
8649
+ const isConsistentMode = client.getMarkerSyncConsistentMode() && client.isUnreadCountEnabled;
8650
+ const isLegacyUnreadCount = client.useLegacyUnreadCount;
8651
+ if (isLeftByMe) {
8339
8652
  preparedPayload.channels.forEach(channel => {
8340
- addFlagIsDeletedSubChannelUnreadByChannelId(channel.channelId);
8341
- deleteChannelUnreadByChannelId(channel.channelId);
8653
+ if (isConsistentMode) {
8654
+ addFlagIsDeletedSubChannelUnreadByChannelId(channel.channelId);
8655
+ deleteChannelUnreadByChannelId(channel.channelId);
8656
+ }
8657
+ else if (isLegacyUnreadCount) {
8658
+ dropFromCache(['channelUnread', 'get', channel.channelId]);
8659
+ }
8342
8660
  });
8343
8661
  }
8344
8662
  const { channels, channelUsers } = preparedPayload;
@@ -8606,6 +8924,34 @@ const onMessageCreatedMqtt = (callback) => {
8606
8924
  reCalculateChannelUnreadInfo(message.channelId);
8607
8925
  });
8608
8926
  }
8927
+ if (client.useLegacyUnreadCount) {
8928
+ rawPayload.messages.forEach(message => {
8929
+ var _a, _b;
8930
+ const channelUnread = (_a = pullFromCache([
8931
+ 'channelUnread',
8932
+ 'get',
8933
+ message.channelId,
8934
+ ])) === null || _a === void 0 ? void 0 : _a.data;
8935
+ if (!channelUnread ||
8936
+ channelUnread.lastSegment >= message.segment ||
8937
+ typeof channelUnread.readToSegment !== 'number' ||
8938
+ typeof channelUnread.lastMentionSegment !== 'number')
8939
+ return;
8940
+ const lastSegment = message.segment;
8941
+ const isMentionedInMessage = (_b = message.mentionedUsers) === null || _b === void 0 ? void 0 : _b.some(mention => {
8942
+ return (mention.type === 'channel' ||
8943
+ (mention.type === 'user' &&
8944
+ client.userId &&
8945
+ mention.userPublicIds.includes(client.userId)));
8946
+ });
8947
+ const lastMentionSegment = isMentionedInMessage
8948
+ ? message.segment
8949
+ : channelUnread.lastMentionSegment;
8950
+ const updatedChannelUnread = Object.assign(Object.assign({}, channelUnread), { lastSegment, unreadCount: Math.max(lastSegment - channelUnread.readToSegment, 0), lastMentionSegment, isMentioned: !(channelUnread.readToSegment >= lastMentionSegment) });
8951
+ pushToCache(['channelUnread', 'get', message.channelId], updatedChannelUnread);
8952
+ fireEvent('local.channelUnread.updated', updatedChannelUnread);
8953
+ });
8954
+ }
8609
8955
  // Update in cache
8610
8956
  ingestInCache(payload);
8611
8957
  payload.messages.forEach(message => {
@@ -8781,6 +9127,7 @@ const enableUnreadCount = () => {
8781
9127
  if (client.isUnreadCountEnabled)
8782
9128
  return false;
8783
9129
  client.isUnreadCountEnabled = true;
9130
+ client.useLegacyUnreadCount = false;
8784
9131
  client.emitter.emit('unreadCountEnabled', true);
8785
9132
  return true;
8786
9133
  };
@@ -9096,7 +9443,12 @@ const login = async (params, sessionHandler, config) => {
9096
9443
  // NOTE: This is a temporary solution to handle the channel marker when the user is forced to leave
9097
9444
  // the channel because currently backend can't handle this, so every time a user is banned from
9098
9445
  // 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());
9446
+ onChannelDeleted(removeChannelMarkerCache), onChannelMemberBanned(removeChannelMarkerCache), markReadEngineOnLoginHandler(), analyticsEngineOnLoginHandler(), objectResolverEngineOnLoginHandler());
9447
+ if (client.useLegacyUnreadCount) {
9448
+ subscriptions.push(readReceiptSyncEngineOnLoginHandler());
9449
+ }
9450
+ else
9451
+ subscriptions.push(legacyReadReceiptSyncEngineOnLoginHandler());
9100
9452
  const markerSyncUnsubscriber = await startMarkerSync();
9101
9453
  subscriptions.push(markerSyncUnsubscriber);
9102
9454
  }
@@ -9254,15 +9606,17 @@ const DEFAULT_DEBUG_SESSION = 'amity';
9254
9606
  * @category Client API
9255
9607
  * */
9256
9608
  const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAULT_DEBUG_SESSION, apiEndpoint, prefixDeviceIdKey, rteEnabled = true, } = {}) => {
9257
- var _a, _b;
9609
+ var _a, _b, _c;
9258
9610
  const log = createLogger(debugSession);
9259
9611
  log('client/api/createClient', {
9260
9612
  apiKey: apiKey.replace(/.{5}$/g, 'xxxxx'),
9261
9613
  apiRegion,
9262
9614
  });
9263
9615
  const httpEndpoint = (_a = apiEndpoint === null || apiEndpoint === void 0 ? void 0 : apiEndpoint.http) !== null && _a !== void 0 ? _a : computeUrl('http', apiRegion);
9264
- const mqttEndpoint = (_b = apiEndpoint === null || apiEndpoint === void 0 ? void 0 : apiEndpoint.mqtt) !== null && _b !== void 0 ? _b : computeUrl('mqtt', apiRegion);
9616
+ const uploadEndpoint = (_b = apiEndpoint === null || apiEndpoint === void 0 ? void 0 : apiEndpoint.upload) !== null && _b !== void 0 ? _b : computeUrl('upload', apiRegion);
9617
+ const mqttEndpoint = (_c = apiEndpoint === null || apiEndpoint === void 0 ? void 0 : apiEndpoint.mqtt) !== null && _c !== void 0 ? _c : computeUrl('mqtt', apiRegion);
9265
9618
  const http = createHttpTransport(httpEndpoint);
9619
+ const upload = createHttpTransport(uploadEndpoint);
9266
9620
  let ws;
9267
9621
  let mqtt;
9268
9622
  if (rteEnabled) {
@@ -9277,6 +9631,8 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
9277
9631
  const sessionState = "notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */;
9278
9632
  const sessionHandler = undefined;
9279
9633
  const isUnreadCountEnabled = false;
9634
+ // Legacy unread count is true by default
9635
+ const useLegacyUnreadCount = true;
9280
9636
  const client = {
9281
9637
  version: `${VERSION}`,
9282
9638
  apiKey,
@@ -9291,6 +9647,7 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
9291
9647
  http,
9292
9648
  ws,
9293
9649
  mqtt,
9650
+ upload,
9294
9651
  emitter,
9295
9652
  /*
9296
9653
  * Session Components
@@ -9306,6 +9663,7 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
9306
9663
  getMessagePreviewSetting,
9307
9664
  use: () => setActiveClient(client),
9308
9665
  isUnreadCountEnabled,
9666
+ useLegacyUnreadCount,
9309
9667
  getMarkerSyncConsistentMode,
9310
9668
  /**
9311
9669
  * Prefix for the deviceId key in the local storage or async storage.
@@ -9319,7 +9677,7 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
9319
9677
  return activeClient;
9320
9678
  setActiveClient(client);
9321
9679
  }
9322
- catch (_c) {
9680
+ catch (_d) {
9323
9681
  setActiveClient(client);
9324
9682
  }
9325
9683
  return client;
@@ -12108,7 +12466,7 @@ const uploadFile = async (formData, onProgress) => {
12108
12466
  const headers = 'getHeaders' in formData
12109
12467
  ? formData.getHeaders()
12110
12468
  : { 'content-type': 'multipart/form-data' };
12111
- const { data } = await client.http.post('/api/v4/files', formData, {
12469
+ const { data } = await client.upload.post('/api/v4/files', formData, {
12112
12470
  headers,
12113
12471
  onUploadProgress({ loaded, total = 100 }) {
12114
12472
  onProgress && onProgress(Math.round((loaded * 100) / total));
@@ -12198,7 +12556,7 @@ const uploadVideo = async (formData, feedType, onProgress) => {
12198
12556
  const headers = 'getHeaders' in formData
12199
12557
  ? formData.getHeaders()
12200
12558
  : { 'content-type': 'multipart/form-data' };
12201
- const { data } = await client.http.post('/api/v4/videos', formData, {
12559
+ const { data } = await client.upload.post('/api/v4/videos', formData, {
12202
12560
  headers,
12203
12561
  onUploadProgress({ loaded, total = 100 }) {
12204
12562
  onProgress && onProgress(Math.round((loaded * 100) / total));
@@ -12246,7 +12604,7 @@ const uploadImage = async (formData, onProgress) => {
12246
12604
  const headers = 'getHeaders' in formData
12247
12605
  ? formData.getHeaders()
12248
12606
  : { 'content-type': 'multipart/form-data' };
12249
- const { data } = await client.http.post('/api/v4/images', formData, {
12607
+ const { data } = await client.upload.post('/api/v4/images', formData, {
12250
12608
  headers,
12251
12609
  onUploadProgress({ loaded, total = 100 }) {
12252
12610
  onProgress && onProgress(Math.round((loaded * 100) / total));
@@ -16439,19 +16797,37 @@ var index$f = /*#__PURE__*/Object.freeze({
16439
16797
  /**
16440
16798
  * Internal used only
16441
16799
  *
16442
- * Fired when an {@link Amity.userMessageFeedMarkers} has been resolved by Object Rsesolver
16800
+ * Fired when an {@link Amity.channelUnreadInfo} has been updated.
16443
16801
  *
16444
16802
  * @param callback The function to call when the event was fired
16445
16803
  * @returns an {@link Amity.Unsubscriber} function to stop listening
16446
16804
  *
16447
- * @category MessageMarker Events
16805
+ * @category ChannelMarker Events
16806
+ */
16807
+ const onChannelUnreadInfoUpdatedLocal = (callback) => {
16808
+ const client = getActiveClient();
16809
+ const filter = (payload) => {
16810
+ callback(payload);
16811
+ };
16812
+ return createEventSubscriber(client, 'channelMarker/onChannelUnreadInfoUpdatedLocal', 'local.channelUnreadInfo.updated', filter);
16813
+ };
16814
+
16815
+ /**
16816
+ * Internal used only
16817
+ *
16818
+ * Fired when an {@link Amity.ChannelUnread} has been updated.
16819
+ *
16820
+ * @param callback The function to call when the event was fired
16821
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
16822
+ *
16823
+ * @category Channel Events
16448
16824
  */
16449
16825
  const onChannelUnreadUpdatedLocal = (callback) => {
16450
16826
  const client = getActiveClient();
16451
16827
  const filter = (payload) => {
16452
16828
  callback(payload);
16453
16829
  };
16454
- return createEventSubscriber(client, 'channelMarker/onChannelUnreadUpdatedLocal', 'local.channelUnread.updated', filter);
16830
+ return createEventSubscriber(client, 'channel/onChannelUnreadUpdatedLocal', 'local.channelUnread.updated', filter);
16455
16831
  };
16456
16832
 
16457
16833
  /* begin_public_function
@@ -16653,6 +17029,7 @@ const getChannel = (channelId, callback) => {
16653
17029
  return onSubChannelUpdated(updateMessagePreview);
16654
17030
  }, 'channelId', 'channel'),
16655
17031
  convertEventPayload(onSubChannelCreated, 'channelId', 'channel'),
17032
+ convertEventPayload(onChannelUnreadInfoUpdatedLocal, 'channelId', 'channel'),
16656
17033
  convertEventPayload(onChannelUnreadUpdatedLocal, 'channelId', 'channel'),
16657
17034
  ], {
16658
17035
  forceDispatch: true,
@@ -17166,6 +17543,10 @@ class ChannelLiveCollectionController extends LiveCollectionController {
17166
17543
  },
17167
17544
  action: "OnResolveUnread" /* Amity.ChannelActionType.OnResolveUnread */,
17168
17545
  },
17546
+ {
17547
+ fn: convertEventPayload(onChannelUnreadInfoUpdatedLocal, 'channelId', 'channel'),
17548
+ action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
17549
+ },
17169
17550
  {
17170
17551
  fn: convertEventPayload(onChannelUnreadUpdatedLocal, 'channelId', 'channel'),
17171
17552
  action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
@@ -17231,6 +17612,120 @@ const getChannels = (params, callback, config) => {
17231
17612
  };
17232
17613
  /* end_public_function */
17233
17614
 
17615
+ /**
17616
+ *
17617
+ * Calculate user unread from {@link Amity.ChannelUnread} objects
17618
+ *
17619
+ * @returns the {@link Amity.UserUnread} objects
17620
+ *
17621
+ * @category Channel API
17622
+ * @async
17623
+ */
17624
+ const getTotalChannelsUnread$1 = () => {
17625
+ var _a;
17626
+ const client = getActiveClient();
17627
+ client.log('channel/getTotalChannelsUnread.locally');
17628
+ const cachedChannelsUnread = ((_a = queryCache(['channelUnread', 'get'])) === null || _a === void 0 ? void 0 : _a.filter(({ data }) => {
17629
+ return !data.isDeleted;
17630
+ })) || [];
17631
+ const totalChannelsUnread = (cachedChannelsUnread === null || cachedChannelsUnread === void 0 ? void 0 : cachedChannelsUnread.reduce((acc, { data }) => {
17632
+ acc.unreadCount += data.unreadCount;
17633
+ acc.isMentioned = acc.isMentioned || data.isMentioned;
17634
+ return acc;
17635
+ }, { unreadCount: 0, isMentioned: false })) || { unreadCount: 0, isMentioned: false };
17636
+ const cachedAt = client.cache && Date.now();
17637
+ return {
17638
+ data: totalChannelsUnread,
17639
+ cachedAt,
17640
+ };
17641
+ };
17642
+
17643
+ /* begin_public_function
17644
+ id: totalChannelsUnread.get
17645
+ */
17646
+ /**
17647
+ * ```js
17648
+ * import { ChannelRepository } from '@amityco/ts-sdk';
17649
+ *
17650
+ * let totalChannelsUnread;
17651
+ *
17652
+ * const unsubscribe = ChannelRepository.getTotalChannelsUnread(response => {
17653
+ * unread = response.data;
17654
+ * });
17655
+ * ```
17656
+ *
17657
+ * Observe all mutation on a given {@link Amity.UserUnread}
17658
+ *
17659
+ * @returns An {@link Amity.UserUnread} function to run when willing to stop observing the message
17660
+ *
17661
+ * @category User Unread Live Object
17662
+ *
17663
+ */
17664
+ const getTotalChannelsUnread = (callback) => {
17665
+ const { _id: userId } = getActiveUser();
17666
+ if (!userId)
17667
+ throw new ASCError('The _id has not been defined in ActiveUser', 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
17668
+ const { log, cache } = getActiveClient();
17669
+ if (!cache) {
17670
+ console.log('For using Live Object feature you need to enable Cache!');
17671
+ }
17672
+ const timestamp = Date.now();
17673
+ log(`liveTotalChannelsUnread(tmpid: ${timestamp}) > listen`);
17674
+ const disposers = [];
17675
+ let isUnsyncedModel = false; // for messages
17676
+ let model;
17677
+ const dispatcher = (data) => {
17678
+ const { data: userUnread } = data;
17679
+ const callbackModel = userUnread
17680
+ ? {
17681
+ unreadCount: userUnread.unreadCount,
17682
+ isMentioned: userUnread.isMentioned,
17683
+ }
17684
+ : undefined;
17685
+ model = callbackModel ? convertGetterPropsToStatic(callbackModel) : callbackModel;
17686
+ callback({
17687
+ data: callbackModel
17688
+ ? Object.assign(Object.assign({}, callbackModel), { isMentioned: callbackModel.isMentioned }) : callbackModel,
17689
+ loading: data.loading,
17690
+ error: data.error,
17691
+ });
17692
+ };
17693
+ const realtimeRouter = (userUnread) => {
17694
+ if (isEqual(model, userUnread))
17695
+ return;
17696
+ dispatcher({
17697
+ loading: false,
17698
+ data: userUnread,
17699
+ });
17700
+ };
17701
+ const onFetch = () => {
17702
+ const query = createQuery(async () => getTotalChannelsUnread$1());
17703
+ runQuery(query, ({ error, data, loading, origin, cachedAt }) => {
17704
+ if (cachedAt === UNSYNCED_OBJECT_CACHED_AT_VALUE) {
17705
+ dispatcher({
17706
+ data,
17707
+ origin,
17708
+ loading: false,
17709
+ error: new ASCApiError(UNSYNCED_OBJECT_CACHED_AT_MESSAGE, 800800 /* Amity.ClientError.DISALOOW_UNSYNCED_OBJECT */, "error" /* Amity.ErrorLevel.ERROR */),
17710
+ });
17711
+ isUnsyncedModel = true;
17712
+ disposers.forEach(fn => fn());
17713
+ }
17714
+ else if (!isUnsyncedModel) {
17715
+ dispatcher({ loading, data, origin, error });
17716
+ }
17717
+ if (error) {
17718
+ disposers.forEach(fn => fn());
17719
+ }
17720
+ });
17721
+ };
17722
+ disposers.push(onChannelUnreadUpdatedLocal(realtimeRouter));
17723
+ onFetch();
17724
+ return () => {
17725
+ disposers.forEach(fn => fn());
17726
+ };
17727
+ };
17728
+
17234
17729
  /* begin_public_function
17235
17730
  id: channel.member.add
17236
17731
  */
@@ -17834,6 +18329,7 @@ var index$c = /*#__PURE__*/Object.freeze({
17834
18329
  onChannelMemberRoleRemoved: onChannelMemberRoleRemoved,
17835
18330
  getChannel: getChannel,
17836
18331
  getChannels: getChannels,
18332
+ getTotalChannelsUnread: getTotalChannelsUnread,
17837
18333
  MARKER_INCLUDED_CHANNEL_TYPE: MARKER_INCLUDED_CHANNEL_TYPE,
17838
18334
  isUnreadCountSupport: isUnreadCountSupport,
17839
18335
  convertFromRaw: convertFromRaw,