@amityco/ts-sdk-react-native 7.0.3-d7a9877.0 → 7.2.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 (96) 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 +10 -0
  9. package/dist/@types/domains/channel.d.ts.map +1 -1
  10. package/dist/@types/domains/client.d.ts +2 -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/onChannelDeleted.d.ts.map +1 -1
  15. package/dist/channelRepository/events/onChannelLeft.d.ts.map +1 -1
  16. package/dist/{marker → channelRepository}/events/onChannelUnreadUpdatedLocal.d.ts +2 -2
  17. package/dist/channelRepository/events/onChannelUnreadUpdatedLocal.d.ts.map +1 -0
  18. package/dist/channelRepository/internalApi/getTotalChannelsUnread.d.ts +11 -0
  19. package/dist/channelRepository/internalApi/getTotalChannelsUnread.d.ts.map +1 -0
  20. package/dist/channelRepository/observers/getChannel.d.ts.map +1 -1
  21. package/dist/channelRepository/observers/getChannels/ChannelLiveCollectionController.d.ts.map +1 -1
  22. package/dist/channelRepository/observers/getTotalChannelsUnread.d.ts +20 -0
  23. package/dist/channelRepository/observers/getTotalChannelsUnread.d.ts.map +1 -0
  24. package/dist/channelRepository/observers/index.d.ts +1 -0
  25. package/dist/channelRepository/observers/index.d.ts.map +1 -1
  26. package/dist/channelRepository/utils/constructChannelDynamicValue.d.ts.map +1 -1
  27. package/dist/channelRepository/utils/getLegacyChannelUnread.d.ts +2 -0
  28. package/dist/channelRepository/utils/getLegacyChannelUnread.d.ts.map +1 -0
  29. package/dist/channelRepository/utils/prepareChannelPayload.d.ts.map +1 -1
  30. package/dist/client/api/createClient.d.ts +1 -0
  31. package/dist/client/api/createClient.d.ts.map +1 -1
  32. package/dist/client/api/enableUnreadCount.d.ts.map +1 -1
  33. package/dist/client/api/login.d.ts.map +1 -1
  34. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.d.ts +33 -0
  35. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.d.ts.map +1 -0
  36. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.d.ts +3 -0
  37. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.d.ts.map +1 -0
  38. package/dist/client/utils/ReadReceiptSync/readReceiptSyncEngine.d.ts +2 -4
  39. package/dist/client/utils/ReadReceiptSync/readReceiptSyncEngine.d.ts.map +1 -1
  40. package/dist/client/utils/endpoints.d.ts +1 -0
  41. package/dist/client/utils/endpoints.d.ts.map +1 -1
  42. package/dist/client/utils/setClientToken.d.ts.map +1 -1
  43. package/dist/commentRepository/events/utils.d.ts.map +1 -1
  44. package/dist/core/events.d.ts +3 -3
  45. package/dist/core/events.d.ts.map +1 -1
  46. package/dist/core/model/idResolvers.d.ts.map +1 -1
  47. package/dist/index.cjs.js +617 -59
  48. package/dist/index.esm.js +617 -59
  49. package/dist/index.umd.js +3 -3
  50. package/dist/marker/events/onChannelUnreadInfoUpdatedLocal.d.ts +12 -0
  51. package/dist/marker/events/onChannelUnreadInfoUpdatedLocal.d.ts.map +1 -0
  52. package/dist/messageRepository/events/onMessageCreated.d.ts.map +1 -1
  53. package/dist/messageRepository/observers/getMessage.d.ts.map +1 -1
  54. package/dist/messageRepository/utils/markReadMessage.d.ts.map +1 -1
  55. package/dist/reactionRepository/api/addReaction.d.ts.map +1 -1
  56. package/dist/reactionRepository/api/removeReaction.d.ts.map +1 -1
  57. package/dist/reactionRepository/observers/getReactions/ReactionPaginationController.d.ts.map +1 -1
  58. package/package.json +1 -1
  59. package/src/@types/core/events.ts +2 -1
  60. package/src/@types/core/model.ts +4 -0
  61. package/src/@types/core/readReceipt.ts +14 -1
  62. package/src/@types/domains/channel.ts +13 -0
  63. package/src/@types/domains/client.ts +3 -0
  64. package/src/channelRepository/api/markChannelsAsReadBySegment.ts +29 -0
  65. package/src/channelRepository/events/onChannelDeleted.ts +17 -4
  66. package/src/channelRepository/events/onChannelLeft.ts +11 -3
  67. package/src/{marker → channelRepository}/events/onChannelUnreadUpdatedLocal.ts +3 -3
  68. package/src/channelRepository/internalApi/getTotalChannelsUnread.ts +38 -0
  69. package/src/channelRepository/observers/getChannel.ts +3 -1
  70. package/src/channelRepository/observers/getChannels/ChannelLiveCollectionController.ts +6 -1
  71. package/src/channelRepository/observers/getTotalChannelsUnread.ts +129 -0
  72. package/src/channelRepository/observers/index.ts +1 -0
  73. package/src/channelRepository/utils/constructChannelDynamicValue.ts +12 -2
  74. package/src/channelRepository/utils/getLegacyChannelUnread.ts +5 -0
  75. package/src/channelRepository/utils/prepareChannelPayload.ts +68 -17
  76. package/src/client/api/createClient.ts +7 -1
  77. package/src/client/api/enableUnreadCount.ts +1 -0
  78. package/src/client/api/login.ts +5 -1
  79. package/src/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.ts +267 -0
  80. package/src/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.ts +21 -0
  81. package/src/client/utils/ReadReceiptSync/readReceiptSyncEngine.ts +74 -99
  82. package/src/client/utils/endpoints.ts +1 -0
  83. package/src/client/utils/setClientToken.ts +8 -0
  84. package/src/commentRepository/events/utils.ts +73 -0
  85. package/src/core/model/idResolvers.ts +2 -0
  86. package/src/fileRepository/api/uploadFile.ts +1 -1
  87. package/src/fileRepository/api/uploadImage.ts +1 -1
  88. package/src/fileRepository/api/uploadVideo.ts +1 -1
  89. package/src/marker/events/onChannelUnreadInfoUpdatedLocal.ts +29 -0
  90. package/src/messageRepository/events/onMessageCreated.ts +45 -1
  91. package/src/messageRepository/observers/getMessage.ts +0 -1
  92. package/src/messageRepository/utils/markReadMessage.ts +10 -3
  93. package/src/reactionRepository/api/addReaction.ts +8 -0
  94. package/src/reactionRepository/api/removeReaction.ts +8 -0
  95. package/src/reactionRepository/observers/getReactions/ReactionPaginationController.ts +8 -0
  96. package/dist/marker/events/onChannelUnreadUpdatedLocal.d.ts.map +0 -1
package/dist/index.cjs.js CHANGED
@@ -123,8 +123,8 @@ const PostContentType = Object.freeze({
123
123
 
124
124
  function getVersion() {
125
125
  try {
126
- // the string ''v7.0.2-cjs'' should be replaced by actual value by @rollup/plugin-replace
127
- return 'v7.0.2-cjs';
126
+ // the string ''v7.2.0-cjs'' should be replaced by actual value by @rollup/plugin-replace
127
+ return 'v7.2.0-cjs';
128
128
  }
129
129
  catch (error) {
130
130
  return '__dev__';
@@ -537,6 +537,7 @@ const idResolvers = {
537
537
  messagePreviewSubChannel: ({ subChannelId }) => `${subChannelId}`,
538
538
  channelUnreadInfo: ({ channelId }) => channelId,
539
539
  subChannelUnreadInfo: ({ subChannelId }) => subChannelId,
540
+ channelUnread: ({ channelId }) => channelId,
540
541
  channelMarker: ({ entityId, userId }) => `${entityId}#${userId}`,
541
542
  subChannelMarker: ({ entityId, feedId, userId }) => `${entityId}#${feedId}#${userId}`,
542
543
  messageMarker: ({ feedId, contentId, creatorId }) => `${feedId}#${contentId}#${creatorId}`,
@@ -1594,6 +1595,7 @@ const API_REGIONS = {
1594
1595
  };
1595
1596
  const URLS = {
1596
1597
  http: 'https://apix.{region}.amity.co',
1598
+ upload: 'https://upload.{region}.amity.co',
1597
1599
  mqtt: 'wss://sse.{region}.amity.co:443/mqtt',
1598
1600
  };
1599
1601
  function computeUrl(type, region) {
@@ -1642,13 +1644,13 @@ class NetworkActivitiesWatcher {
1642
1644
  this._listener.clear();
1643
1645
  }
1644
1646
  }
1645
- let instance$5;
1647
+ let instance$6;
1646
1648
  var NetworkActivitiesWatcher$1 = {
1647
1649
  getInstance: () => {
1648
- if (!instance$5) {
1649
- instance$5 = new NetworkActivitiesWatcher();
1650
+ if (!instance$6) {
1651
+ instance$6 = new NetworkActivitiesWatcher();
1650
1652
  }
1651
- return instance$5;
1653
+ return instance$6;
1652
1654
  },
1653
1655
  };
1654
1656
 
@@ -5224,13 +5226,13 @@ class AnalyticsEngine {
5224
5226
  this._eventCapturer.resetAllBuckets();
5225
5227
  }
5226
5228
  }
5227
- let instance$4;
5229
+ let instance$5;
5228
5230
  var AnalyticsEngine$1 = {
5229
5231
  getInstance: () => {
5230
- if (!instance$4) {
5231
- instance$4 = new AnalyticsEngine();
5232
+ if (!instance$5) {
5233
+ instance$5 = new AnalyticsEngine();
5232
5234
  }
5233
- return instance$4;
5235
+ return instance$5;
5234
5236
  },
5235
5237
  };
5236
5238
 
@@ -5656,6 +5658,223 @@ const getMessageReadCount = (message, marker) => {
5656
5658
  getCachedMarker$2(message)) !== null && _a !== void 0 ? _a : { readCount: 0, deliveredCount: 0 };
5657
5659
  }; // and if not found in cache use default value `0`
5658
5660
 
5661
+ /**
5662
+ *
5663
+ * Mark subChannel as read by readToSegment
5664
+ *
5665
+ * @param subChannelIds the IDs of the {@link Amity.SubChannel} to update
5666
+ * @param readToSegment the segment to mark as read
5667
+ * @returns a success boolean if the {@link Amity.SubChannel} was updated
5668
+ *
5669
+ * @category Channel API
5670
+ * @async
5671
+ */
5672
+ const markChannelsAsReadBySegment = async (readings) => {
5673
+ const client = getActiveClient();
5674
+ try {
5675
+ await client.http.post('api/v3/channels/seen', { channels: readings });
5676
+ return true;
5677
+ }
5678
+ catch (e) {
5679
+ return false;
5680
+ }
5681
+ };
5682
+
5683
+ class MessageReadReceiptSyncEngine {
5684
+ constructor() {
5685
+ this.isActive = true;
5686
+ this.MAX_RETRY = 3;
5687
+ this.JOB_QUEUE_SIZE = 120;
5688
+ this.jobQueue = [];
5689
+ // Interval for message read receipt sync in seconds
5690
+ this.RECEIPT_SYNC_INTERVAL = 1;
5691
+ this.client = getActiveClient();
5692
+ // Get remaining unsync read receipts from cache
5693
+ this.getUnsyncJobs();
5694
+ }
5695
+ // Call this when client call client.login
5696
+ startSyncReadReceipt() {
5697
+ // Start timer when start receipt sync
5698
+ this.timer = setInterval(() => {
5699
+ this.syncReadReceipts();
5700
+ }, this.RECEIPT_SYNC_INTERVAL * 1000);
5701
+ }
5702
+ // Read receipt observer handling
5703
+ syncReadReceipts() {
5704
+ if (this.jobQueue.length === 0 || this.isActive === false)
5705
+ return;
5706
+ const readReceipts = this.getReadReceipts();
5707
+ if (readReceipts) {
5708
+ this.markReadApi(readReceipts);
5709
+ }
5710
+ }
5711
+ getUnsyncJobs() {
5712
+ var _a;
5713
+ // Get all read receipts that has latestSyncSegment < latestSegment
5714
+ const readReceipts = (_a = queryCache(['readReceipt'])) === null || _a === void 0 ? void 0 : _a.filter(({ data }) => {
5715
+ return data.latestSyncSegment < data.latestSegment;
5716
+ });
5717
+ // Enqueue unsync read receipts to the job queue
5718
+ readReceipts === null || readReceipts === void 0 ? void 0 : readReceipts.forEach(({ data: readReceipt }) => {
5719
+ this.enqueueReadReceipt(readReceipt.channelId, readReceipt.latestSegment);
5720
+ });
5721
+ }
5722
+ getReadReceipts() {
5723
+ // get all read receipts from queue, now the queue is empty
5724
+ const syncJob = this.jobQueue.splice(0, this.jobQueue.length);
5725
+ if (syncJob.length === 0)
5726
+ return;
5727
+ return syncJob.filter(job => {
5728
+ var _a;
5729
+ const readReceipt = (_a = pullFromCache(['readReceipt', job.channelId])) === null || _a === void 0 ? void 0 : _a.data;
5730
+ if (!readReceipt)
5731
+ return false;
5732
+ if (readReceipt.latestSegment > readReceipt.latestSyncSegment)
5733
+ return true;
5734
+ return false;
5735
+ });
5736
+ }
5737
+ async markReadApi(syncJobs) {
5738
+ var _a;
5739
+ // constuct payload
5740
+ // example: [{ channelId: 'channelId', readToSegment: 2 }]
5741
+ const syncJobsPayload = syncJobs.map(job => {
5742
+ return {
5743
+ channelId: job.channelId,
5744
+ readToSegment: job.segment,
5745
+ };
5746
+ });
5747
+ const response = await markChannelsAsReadBySegment(syncJobsPayload);
5748
+ if (response) {
5749
+ for (let i = 0; i < syncJobs.length; i += 1) {
5750
+ // update lastestSyncSegment in read receipt cache
5751
+ const cacheKey = ['readReceipt', syncJobs[i].channelId];
5752
+ const readReceiptCache = (_a = pullFromCache(cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
5753
+ pushToCache(cacheKey, Object.assign(Object.assign({}, readReceiptCache), { latestSyncSegment: syncJobs[i].segment }));
5754
+ }
5755
+ }
5756
+ else {
5757
+ for (let i = 0; i < syncJobs.length; i += 1) {
5758
+ // push them back to queue if the syncing is failed and retry count is less than max retry
5759
+ if (syncJobs[i].retryCount >= this.MAX_RETRY)
5760
+ return;
5761
+ const updatedJob = Object.assign(Object.assign({}, syncJobs[i]), { syncState: "create" /* Amity.ReadReceiptSyncState.CREATED */, retryCount: syncJobs[i].retryCount + 1 });
5762
+ this.enqueueJob(updatedJob);
5763
+ }
5764
+ }
5765
+ }
5766
+ startObservingReadReceiptQueue() {
5767
+ if (this.client.useLegacyUnreadCount) {
5768
+ this.isActive = true;
5769
+ this.startSyncReadReceipt();
5770
+ }
5771
+ }
5772
+ stopObservingReadReceiptQueue() {
5773
+ this.isActive = false;
5774
+ this.jobQueue.map(job => {
5775
+ if (job.syncState === "syncing" /* Amity.ReadReceiptSyncState.SYNCING */) {
5776
+ return Object.assign(Object.assign({}, job), { syncState: "create" /* Amity.ReadReceiptSyncState.CREATED */ });
5777
+ }
5778
+ return job;
5779
+ });
5780
+ if (this.timer)
5781
+ clearInterval(this.timer);
5782
+ }
5783
+ // Session Management
5784
+ onSessionEstablished() {
5785
+ this.startObservingReadReceiptQueue();
5786
+ }
5787
+ onSessionDestroyed() {
5788
+ this.stopObservingReadReceiptQueue();
5789
+ this.jobQueue = [];
5790
+ }
5791
+ onTokenExpired() {
5792
+ this.stopObservingReadReceiptQueue();
5793
+ }
5794
+ // Network Connection Management
5795
+ onNetworkOffline() {
5796
+ // Stop observing to the read receipt queue.
5797
+ this.stopObservingReadReceiptQueue();
5798
+ }
5799
+ onNetworkOnline() {
5800
+ // Resume observing to the read receipt queue.
5801
+ this.startObservingReadReceiptQueue();
5802
+ }
5803
+ markRead(channelId, segment) {
5804
+ var _a;
5805
+ // Step 1: Optimistic update of channelUnread.readToSegment to message.segment and update unreadCount value
5806
+ const cacheKey = ['channelUnread', 'get', channelId];
5807
+ const channelUnread = (_a = pullFromCache(cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
5808
+ if (typeof (channelUnread === null || channelUnread === void 0 ? void 0 : channelUnread.readToSegment) === 'number' &&
5809
+ channelUnread &&
5810
+ segment > channelUnread.readToSegment) {
5811
+ channelUnread.readToSegment = segment;
5812
+ channelUnread.unreadCount = Math.max(channelUnread.lastSegment - segment, 0);
5813
+ pushToCache(cacheKey, channelUnread);
5814
+ fireEvent('local.channelUnread.updated', channelUnread);
5815
+ }
5816
+ // Step 2: Enqueue the read receipt
5817
+ this.enqueueReadReceipt(channelId, segment);
5818
+ }
5819
+ enqueueReadReceipt(channelId, segment) {
5820
+ var _a;
5821
+ const readReceipt = (_a = pullFromCache(['readReceipt', channelId])) === null || _a === void 0 ? void 0 : _a.data;
5822
+ // Create new read receipt if it's not exists and add the job to queue
5823
+ if (!readReceipt) {
5824
+ const readReceiptChannel = {
5825
+ channelId,
5826
+ latestSegment: segment,
5827
+ latestSyncSegment: 0,
5828
+ };
5829
+ pushToCache(['readReceipt', channelId], readReceiptChannel);
5830
+ }
5831
+ else if (readReceipt.latestSegment < segment) {
5832
+ // Update latestSegment in read receipt cache
5833
+ pushToCache(['readReceipt', channelId], Object.assign(Object.assign({}, readReceipt), { latestSegment: segment }));
5834
+ }
5835
+ else if (readReceipt.latestSyncSegment >= segment) {
5836
+ // Skip the job when lastSyncSegment > = segment
5837
+ return;
5838
+ }
5839
+ let syncJob = this.getSyncJob(channelId);
5840
+ if (syncJob === null || syncJob.syncState === "syncing" /* Amity.ReadReceiptSyncState.SYNCING */) {
5841
+ syncJob = {
5842
+ channelId,
5843
+ segment,
5844
+ syncState: "create" /* Amity.ReadReceiptSyncState.CREATED */,
5845
+ retryCount: 0,
5846
+ };
5847
+ this.enqueueJob(syncJob);
5848
+ }
5849
+ else if (syncJob.segment < segment) {
5850
+ syncJob.segment = segment;
5851
+ }
5852
+ }
5853
+ getSyncJob(channelId) {
5854
+ const { jobQueue } = this;
5855
+ const targetJob = jobQueue.find(job => job.channelId === channelId);
5856
+ return targetJob || null;
5857
+ }
5858
+ enqueueJob(syncJob) {
5859
+ if (this.jobQueue.length < this.JOB_QUEUE_SIZE) {
5860
+ this.jobQueue.push(syncJob);
5861
+ }
5862
+ else {
5863
+ // Remove oldest job when queue reach maximum capacity
5864
+ this.jobQueue.shift();
5865
+ this.jobQueue.push(syncJob);
5866
+ }
5867
+ }
5868
+ }
5869
+ let instance$4 = null;
5870
+ var ReadReceiptSyncEngine = {
5871
+ getInstance: () => {
5872
+ if (!instance$4)
5873
+ instance$4 = new MessageReadReceiptSyncEngine();
5874
+ return instance$4;
5875
+ },
5876
+ };
5877
+
5659
5878
  /**
5660
5879
  *
5661
5880
  * Mark subChannel as read by readToSegment
@@ -5704,7 +5923,7 @@ const reCalculateChannelUnreadInfo = (channelId) => {
5704
5923
  return channelUnreadInfo;
5705
5924
  };
5706
5925
 
5707
- class MessageReadReceiptSyncEngine {
5926
+ class LegacyMessageReadReceiptSyncEngine {
5708
5927
  constructor() {
5709
5928
  this.isActive = true;
5710
5929
  this.MAX_RETRY = 3;
@@ -5735,7 +5954,7 @@ class MessageReadReceiptSyncEngine {
5735
5954
  getUnsyncJobs() {
5736
5955
  var _a;
5737
5956
  // Get all read receipts that has latestSyncSegment < latestSegment
5738
- const readReceipts = (_a = queryCache(['readReceipt'])) === null || _a === void 0 ? void 0 : _a.filter(({ data }) => {
5957
+ const readReceipts = (_a = queryCache(['legacyReadReceipt'])) === null || _a === void 0 ? void 0 : _a.filter(({ data }) => {
5739
5958
  return data.latestSyncSegment < data.latestSegment;
5740
5959
  });
5741
5960
  // Enqueue unsync read receipts to the job queue
@@ -5754,7 +5973,7 @@ class MessageReadReceiptSyncEngine {
5754
5973
  return;
5755
5974
  // Get readReceipt from cache by subChannelId
5756
5975
  const readReceipt = (_a = pullFromCache([
5757
- 'readReceipt',
5976
+ 'legacyReadReceipt',
5758
5977
  syncJob.subChannelId,
5759
5978
  ])) === null || _a === void 0 ? void 0 : _a.data;
5760
5979
  if (!readReceipt)
@@ -5777,10 +5996,10 @@ class MessageReadReceiptSyncEngine {
5777
5996
  if (response) {
5778
5997
  this.removeSynedReceipt(syncJob.subChannelId, syncJob.segment);
5779
5998
  const readReceiptCache = (_a = pullFromCache([
5780
- 'readReceipt',
5999
+ 'legacyReadReceipt',
5781
6000
  subChannelId,
5782
6001
  ])) === null || _a === void 0 ? void 0 : _a.data;
5783
- pushToCache(['readReceipt', subChannelId], Object.assign(Object.assign({}, readReceiptCache), { latestSyncSegment: segment }));
6002
+ pushToCache(['legacyReadReceipt', subChannelId], Object.assign(Object.assign({}, readReceiptCache), { latestSyncSegment: segment }));
5784
6003
  }
5785
6004
  else if (!response) {
5786
6005
  if (newSyncJob.retryCount > this.MAX_RETRY) {
@@ -5847,7 +6066,7 @@ class MessageReadReceiptSyncEngine {
5847
6066
  subChannelUnreadInfo.readToSegment = segment;
5848
6067
  subChannelUnreadInfo.unreadCount = Math.max(subChannelUnreadInfo.lastSegment - segment, 0);
5849
6068
  const channelUnreadInfo = reCalculateChannelUnreadInfo(subChannelUnreadInfo.channelId);
5850
- fireEvent('local.channelUnread.updated', channelUnreadInfo);
6069
+ fireEvent('local.channelUnreadInfo.updated', channelUnreadInfo);
5851
6070
  pushToCache(cacheKey, subChannelUnreadInfo);
5852
6071
  fireEvent('local.subChannelUnread.updated', subChannelUnreadInfo);
5853
6072
  }
@@ -5856,7 +6075,10 @@ class MessageReadReceiptSyncEngine {
5856
6075
  }
5857
6076
  enqueueReadReceipt(subChannelId, segment) {
5858
6077
  var _a;
5859
- const readReceipt = (_a = pullFromCache(['readReceipt', subChannelId])) === null || _a === void 0 ? void 0 : _a.data;
6078
+ const readReceipt = (_a = pullFromCache([
6079
+ 'legacyReadReceipt',
6080
+ subChannelId,
6081
+ ])) === null || _a === void 0 ? void 0 : _a.data;
5860
6082
  // Create new read receipt if it's not exists and add job to queue
5861
6083
  if (!readReceipt) {
5862
6084
  const readReceiptSubChannel = {
@@ -5864,10 +6086,10 @@ class MessageReadReceiptSyncEngine {
5864
6086
  latestSegment: segment,
5865
6087
  latestSyncSegment: 0,
5866
6088
  };
5867
- pushToCache(['readReceipt', subChannelId], readReceiptSubChannel);
6089
+ pushToCache(['legacyReadReceipt', subChannelId], readReceiptSubChannel);
5868
6090
  }
5869
6091
  else if (readReceipt.latestSegment < segment) {
5870
- pushToCache(['readReceipt', subChannelId], Object.assign(Object.assign({}, readReceipt), { latestSegment: segment }));
6092
+ pushToCache(['legacyReadReceipt', subChannelId], Object.assign(Object.assign({}, readReceipt), { latestSegment: segment }));
5871
6093
  }
5872
6094
  else if (readReceipt.latestSyncSegment >= segment) {
5873
6095
  // Skip the job when lastSyncSegment > = segment
@@ -5910,18 +6132,24 @@ class MessageReadReceiptSyncEngine {
5910
6132
  }
5911
6133
  }
5912
6134
  let instance$3 = null;
5913
- var ReadReceiptSyncEngine = {
6135
+ var LegacyReadReceiptSyncEngine = {
5914
6136
  getInstance: () => {
5915
6137
  if (!instance$3)
5916
- instance$3 = new MessageReadReceiptSyncEngine();
6138
+ instance$3 = new LegacyMessageReadReceiptSyncEngine();
5917
6139
  return instance$3;
5918
6140
  },
5919
6141
  };
5920
6142
 
5921
6143
  const markReadMessage = (message) => {
5922
- const { subChannelId, channelSegment } = message;
5923
- const markReadReceiptEngine = ReadReceiptSyncEngine.getInstance();
5924
- markReadReceiptEngine.markRead(subChannelId, channelSegment);
6144
+ const client = getActiveClient();
6145
+ if (client.useLegacyUnreadCount) {
6146
+ const markReadReceiptEngine = ReadReceiptSyncEngine.getInstance();
6147
+ markReadReceiptEngine.markRead(message.channelId, message.channelSegment);
6148
+ }
6149
+ else {
6150
+ const markReadReceiptEngine = LegacyReadReceiptSyncEngine.getInstance();
6151
+ markReadReceiptEngine.markRead(message.subChannelId, message.channelSegment);
6152
+ }
5925
6153
  };
5926
6154
 
5927
6155
  const messageLinkedObject = (message) => {
@@ -6909,6 +7137,32 @@ const preUpdateChannelCache = (rawPayload, options = { isMessagePreviewUpdated:
6909
7137
  channels: rawPayload.channels.map(channel => convertFromRaw(channel, { isMessagePreviewUpdated: options.isMessagePreviewUpdated })),
6910
7138
  });
6911
7139
  };
7140
+ const updateChannelUnread = ({ currentUserId, channels, channelUsers, }) => {
7141
+ for (let i = 0; i < channels.length; i += 1) {
7142
+ const cacheKey = ['channelUnread', 'get', channels[i].channelId];
7143
+ const channelUser = channelUsers.find(channelUser => channelUser.channelId === channels[i].channelId && channelUser.userId === currentUserId);
7144
+ let unreadCount = 0;
7145
+ let readToSegment = null;
7146
+ let lastMentionedSegment = null;
7147
+ let isMentioned = false;
7148
+ if (channelUser) {
7149
+ readToSegment = channelUser.readToSegment;
7150
+ lastMentionedSegment = channelUser.lastMentionedSegment;
7151
+ unreadCount = Math.max(channels[i].messageCount - readToSegment, 0);
7152
+ isMentioned = lastMentionedSegment > readToSegment;
7153
+ }
7154
+ const cacheChannelUnread = {
7155
+ channelId: channels[i].channelId,
7156
+ lastSegment: channels[i].messageCount,
7157
+ readToSegment,
7158
+ lastMentionedSegment,
7159
+ unreadCount,
7160
+ isMentioned,
7161
+ isDeleted: channels[i].isDeleted || false,
7162
+ };
7163
+ pushToCache(cacheKey, cacheChannelUnread);
7164
+ }
7165
+ };
6912
7166
  const prepareChannelPayload = async (rawPayload, options = { isMessagePreviewUpdated: true }) => {
6913
7167
  const client = getActiveClient();
6914
7168
  const networkPreviewSetting = await client.getMessagePreviewSetting(false);
@@ -6918,23 +7172,34 @@ const prepareChannelPayload = async (rawPayload, options = { isMessagePreviewUpd
6918
7172
  rawPayload.messagePreviews.length > 0) {
6919
7173
  updateChannelMessagePreviewCache(rawPayload);
6920
7174
  }
6921
- const markerIds = rawPayload.channels
6922
- // filter channel by type. Only conversation, community and broadcast type are included.
6923
- .filter(isUnreadCountSupport)
6924
- .map(({ channelInternalId }) => channelInternalId);
6925
- if (markerIds.length > 0) {
6926
- // since the get markers method requires a channel cache to function with the reducer.
6927
- preUpdateChannelCache(rawPayload, { isMessagePreviewUpdated: options.isMessagePreviewUpdated });
6928
- try {
6929
- await getChannelMarkers(markerIds);
6930
- }
6931
- catch (e) {
6932
- // empty block (from the spec, allow marker fetch to fail without having to do anything)
7175
+ if (client.useLegacyUnreadCount) {
7176
+ updateChannelUnread({
7177
+ channels: rawPayload.channels,
7178
+ channelUsers: rawPayload.channelUsers,
7179
+ currentUserId: client.userId,
7180
+ });
7181
+ }
7182
+ else {
7183
+ const markerIds = rawPayload.channels
7184
+ // filter channel by type. Only conversation, community and broadcast type are included.
7185
+ .filter(isUnreadCountSupport)
7186
+ .map(({ channelInternalId }) => channelInternalId);
7187
+ if (markerIds.length > 0) {
7188
+ // since the get markers method requires a channel cache to function with the reducer.
7189
+ preUpdateChannelCache(rawPayload, {
7190
+ isMessagePreviewUpdated: options.isMessagePreviewUpdated,
7191
+ });
7192
+ try {
7193
+ await getChannelMarkers(markerIds);
7194
+ }
7195
+ catch (e) {
7196
+ // empty block (from the spec, allow marker fetch to fail without having to do anything)
7197
+ }
6933
7198
  }
6934
7199
  }
6935
- // attach marker to channel
7200
+ // convert raw channel to internal channel
6936
7201
  const channels = rawPayload.channels.map(payload => convertFromRaw(payload, { isMessagePreviewUpdated: options.isMessagePreviewUpdated }));
6937
- // user marker to channel users
7202
+ // convert raw channel user to membership (add user object)
6938
7203
  const channelUsers = rawPayload.channelUsers.map(channelUser => {
6939
7204
  return convertRawMembershipToMembership(channelUser);
6940
7205
  });
@@ -7061,15 +7326,28 @@ const getSubChannelsUnreadCount = (channel, marker) => {
7061
7326
  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;
7062
7327
  };
7063
7328
 
7329
+ const getLegacyChannelUnread = (channelId) => {
7330
+ var _a;
7331
+ return (_a = pullFromCache(['channelUnread', 'get', channelId])) === null || _a === void 0 ? void 0 : _a.data;
7332
+ };
7333
+
7064
7334
  const constructChannelDynamicValue = (channel) => {
7335
+ const client = getActiveClient();
7065
7336
  const rest = __rest(channel, ["messageCount"]);
7066
7337
  return shallowClone(rest, {
7067
- get isMentioned() {
7068
- return getChannelIsMentioned(rest);
7338
+ get unreadCount() {
7339
+ var _a, _b;
7340
+ return (_b = (_a = getLegacyChannelUnread(rest.channelId)) === null || _a === void 0 ? void 0 : _a.unreadCount) !== null && _b !== void 0 ? _b : 0;
7069
7341
  },
7070
7342
  get subChannelsUnreadCount() {
7071
7343
  return getSubChannelsUnreadCount(rest);
7072
7344
  },
7345
+ get isMentioned() {
7346
+ var _a, _b;
7347
+ if (client.useLegacyUnreadCount)
7348
+ return (_b = (_a = getLegacyChannelUnread(rest.channelId)) === null || _a === void 0 ? void 0 : _a.isMentioned) !== null && _b !== void 0 ? _b : false;
7349
+ return getChannelIsMentioned(rest);
7350
+ },
7073
7351
  });
7074
7352
  };
7075
7353
 
@@ -7682,6 +7960,12 @@ const setClientToken = async (params) => {
7682
7960
  isGlobalBanned: false,
7683
7961
  isUserDeleted: false,
7684
7962
  };
7963
+ client.upload.defaults.headers.common.Authorization = `Bearer ${accessToken}`;
7964
+ client.upload.defaults.metadata = {
7965
+ tokenExpiry: expiresAt,
7966
+ isGlobalBanned: false,
7967
+ isUserDeleted: false,
7968
+ };
7685
7969
  // manually setup the token for ws transport
7686
7970
  if (client.ws)
7687
7971
  client.ws.io.opts.query = { token: accessToken };
@@ -7726,12 +8010,21 @@ const onChannelDeleted = (callback) => {
7726
8010
  const client = getActiveClient();
7727
8011
  const filter = async (payload) => {
7728
8012
  const data = await prepareChannelPayload(payload);
7729
- if (client.isUnreadCountEnabled && client.getMarkerSyncConsistentMode()) {
7730
- data.channels.forEach(channel => {
8013
+ const isConsistentMode = client.getMarkerSyncConsistentMode() && client.isUnreadCountEnabled;
8014
+ const isLegacyUnreadCount = client.useLegacyUnreadCount;
8015
+ data.channels.forEach(channel => {
8016
+ if (isConsistentMode) {
7731
8017
  addFlagIsDeletedSubChannelUnreadByChannelId(channel.channelId);
7732
8018
  deleteChannelUnreadByChannelId(channel.channelId);
7733
- });
7734
- }
8019
+ }
8020
+ else if (isLegacyUnreadCount) {
8021
+ const cacheKey = ['channelUnread', 'get', channel.channelId];
8022
+ const cache = pullFromCache(cacheKey);
8023
+ if (cache) {
8024
+ pushToCache(cacheKey, Object.assign(Object.assign({}, cache), { isDeleted: true }));
8025
+ }
8026
+ }
8027
+ });
7735
8028
  ingestInCache(data);
7736
8029
  callbacks$b.forEach(cb => cb(data.channels[0]));
7737
8030
  };
@@ -7845,6 +8138,25 @@ var readReceiptSyncEngineOnLoginHandler = () => {
7845
8138
  };
7846
8139
  };
7847
8140
 
8141
+ var legacyReadReceiptSyncEngineOnLoginHandler = () => {
8142
+ const readReceiptSyncEngine = LegacyReadReceiptSyncEngine.getInstance();
8143
+ readReceiptSyncEngine.startSyncReadReceipt();
8144
+ onSessionStateChange(state => {
8145
+ if (state === "established" /* Amity.SessionStates.ESTABLISHED */) {
8146
+ readReceiptSyncEngine.onSessionEstablished();
8147
+ }
8148
+ else if (state === "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */) {
8149
+ readReceiptSyncEngine.onTokenExpired();
8150
+ }
8151
+ else {
8152
+ readReceiptSyncEngine.onSessionDestroyed();
8153
+ }
8154
+ });
8155
+ return () => {
8156
+ readReceiptSyncEngine.onSessionDestroyed();
8157
+ };
8158
+ };
8159
+
7848
8160
  const onOnline = (callback) => {
7849
8161
  if (typeof window !== 'undefined' && window.addEventListener) {
7850
8162
  window.addEventListener('online', callback);
@@ -8441,10 +8753,17 @@ const onChannelLeft = (callback) => {
8441
8753
  const preparedPayload = await prepareChannelPayload(payload, {
8442
8754
  isMessagePreviewUpdated: isLeftByMe,
8443
8755
  });
8444
- if (client.isUnreadCountEnabled && client.getMarkerSyncConsistentMode() && isLeftByMe) {
8756
+ const isConsistentMode = client.getMarkerSyncConsistentMode() && client.isUnreadCountEnabled;
8757
+ const isLegacyUnreadCount = client.useLegacyUnreadCount;
8758
+ if (isLeftByMe) {
8445
8759
  preparedPayload.channels.forEach(channel => {
8446
- addFlagIsDeletedSubChannelUnreadByChannelId(channel.channelId);
8447
- deleteChannelUnreadByChannelId(channel.channelId);
8760
+ if (isConsistentMode) {
8761
+ addFlagIsDeletedSubChannelUnreadByChannelId(channel.channelId);
8762
+ deleteChannelUnreadByChannelId(channel.channelId);
8763
+ }
8764
+ else if (isLegacyUnreadCount) {
8765
+ dropFromCache(['channelUnread', 'get', channel.channelId]);
8766
+ }
8448
8767
  });
8449
8768
  }
8450
8769
  const { channels, channelUsers } = preparedPayload;
@@ -8712,6 +9031,34 @@ const onMessageCreatedMqtt = (callback) => {
8712
9031
  reCalculateChannelUnreadInfo(message.channelId);
8713
9032
  });
8714
9033
  }
9034
+ if (client.useLegacyUnreadCount) {
9035
+ rawPayload.messages.forEach(message => {
9036
+ var _a, _b;
9037
+ const channelUnread = (_a = pullFromCache([
9038
+ 'channelUnread',
9039
+ 'get',
9040
+ message.channelId,
9041
+ ])) === null || _a === void 0 ? void 0 : _a.data;
9042
+ if (!channelUnread ||
9043
+ channelUnread.lastSegment >= message.segment ||
9044
+ typeof channelUnread.readToSegment !== 'number' ||
9045
+ typeof channelUnread.lastMentionedSegment !== 'number')
9046
+ return;
9047
+ const lastSegment = message.segment;
9048
+ const isMentionedInMessage = (_b = message.mentionedUsers) === null || _b === void 0 ? void 0 : _b.some(mention => {
9049
+ return (mention.type === 'channel' ||
9050
+ (mention.type === 'user' &&
9051
+ client.userId &&
9052
+ mention.userPublicIds.includes(client.userId)));
9053
+ });
9054
+ const lastMentionedSegment = isMentionedInMessage
9055
+ ? message.segment
9056
+ : channelUnread.lastMentionedSegment;
9057
+ const updatedChannelUnread = Object.assign(Object.assign({}, channelUnread), { lastSegment, unreadCount: Math.max(lastSegment - channelUnread.readToSegment, 0), lastMentionedSegment, isMentioned: !(channelUnread.readToSegment >= lastMentionedSegment) });
9058
+ pushToCache(['channelUnread', 'get', message.channelId], updatedChannelUnread);
9059
+ fireEvent('local.channelUnread.updated', updatedChannelUnread);
9060
+ });
9061
+ }
8715
9062
  // Update in cache
8716
9063
  ingestInCache(payload);
8717
9064
  payload.messages.forEach(message => {
@@ -8887,6 +9234,7 @@ const enableUnreadCount = () => {
8887
9234
  if (client.isUnreadCountEnabled)
8888
9235
  return false;
8889
9236
  client.isUnreadCountEnabled = true;
9237
+ client.useLegacyUnreadCount = false;
8890
9238
  client.emitter.emit('unreadCountEnabled', true);
8891
9239
  return true;
8892
9240
  };
@@ -9202,7 +9550,12 @@ const login = async (params, sessionHandler, config) => {
9202
9550
  // NOTE: This is a temporary solution to handle the channel marker when the user is forced to leave
9203
9551
  // the channel because currently backend can't handle this, so every time a user is banned from
9204
9552
  // a channel or the channel is deleted the channel's unread count will not be reset to zero
9205
- onChannelDeleted(removeChannelMarkerCache), onChannelMemberBanned(removeChannelMarkerCache), markReadEngineOnLoginHandler(), analyticsEngineOnLoginHandler(), readReceiptSyncEngineOnLoginHandler(), objectResolverEngineOnLoginHandler());
9553
+ onChannelDeleted(removeChannelMarkerCache), onChannelMemberBanned(removeChannelMarkerCache), markReadEngineOnLoginHandler(), analyticsEngineOnLoginHandler(), objectResolverEngineOnLoginHandler());
9554
+ if (client.useLegacyUnreadCount) {
9555
+ subscriptions.push(readReceiptSyncEngineOnLoginHandler());
9556
+ }
9557
+ else
9558
+ subscriptions.push(legacyReadReceiptSyncEngineOnLoginHandler());
9206
9559
  const markerSyncUnsubscriber = await startMarkerSync();
9207
9560
  subscriptions.push(markerSyncUnsubscriber);
9208
9561
  }
@@ -9380,15 +9733,17 @@ const DEFAULT_DEBUG_SESSION = 'amity';
9380
9733
  * @category Client API
9381
9734
  * */
9382
9735
  const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAULT_DEBUG_SESSION, apiEndpoint, prefixDeviceIdKey, rteEnabled = true, } = {}) => {
9383
- var _a, _b;
9736
+ var _a, _b, _c;
9384
9737
  const log = createLogger(debugSession);
9385
9738
  log('client/api/createClient', {
9386
9739
  apiKey: apiKey.replace(/.{5}$/g, 'xxxxx'),
9387
9740
  apiRegion,
9388
9741
  });
9389
9742
  const httpEndpoint = (_a = apiEndpoint === null || apiEndpoint === void 0 ? void 0 : apiEndpoint.http) !== null && _a !== void 0 ? _a : computeUrl('http', apiRegion);
9390
- const mqttEndpoint = (_b = apiEndpoint === null || apiEndpoint === void 0 ? void 0 : apiEndpoint.mqtt) !== null && _b !== void 0 ? _b : computeUrl('mqtt', apiRegion);
9743
+ const uploadEndpoint = (_b = apiEndpoint === null || apiEndpoint === void 0 ? void 0 : apiEndpoint.upload) !== null && _b !== void 0 ? _b : computeUrl('upload', apiRegion);
9744
+ const mqttEndpoint = (_c = apiEndpoint === null || apiEndpoint === void 0 ? void 0 : apiEndpoint.mqtt) !== null && _c !== void 0 ? _c : computeUrl('mqtt', apiRegion);
9391
9745
  const http = createHttpTransport(httpEndpoint);
9746
+ const upload = createHttpTransport(uploadEndpoint);
9392
9747
  let ws;
9393
9748
  let mqtt;
9394
9749
  if (rteEnabled) {
@@ -9403,6 +9758,8 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
9403
9758
  const sessionState = "notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */;
9404
9759
  const sessionHandler = undefined;
9405
9760
  const isUnreadCountEnabled = false;
9761
+ // Legacy unread count is true by default
9762
+ const useLegacyUnreadCount = true;
9406
9763
  const client = {
9407
9764
  version: `${VERSION}`,
9408
9765
  apiKey,
@@ -9417,6 +9774,7 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
9417
9774
  http,
9418
9775
  ws,
9419
9776
  mqtt,
9777
+ upload,
9420
9778
  emitter,
9421
9779
  /*
9422
9780
  * Session Components
@@ -9433,6 +9791,7 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
9433
9791
  onRTEConnectionStateChange,
9434
9792
  use: () => setActiveClient(client),
9435
9793
  isUnreadCountEnabled,
9794
+ useLegacyUnreadCount,
9436
9795
  getMarkerSyncConsistentMode,
9437
9796
  /**
9438
9797
  * Prefix for the deviceId key in the local storage or async storage.
@@ -9446,7 +9805,7 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
9446
9805
  return activeClient;
9447
9806
  setActiveClient(client);
9448
9807
  }
9449
- catch (_c) {
9808
+ catch (_d) {
9450
9809
  setActiveClient(client);
9451
9810
  }
9452
9811
  return client;
@@ -12275,7 +12634,7 @@ const uploadFile = async (formData, onProgress) => {
12275
12634
  const headers = 'getHeaders' in formData
12276
12635
  ? formData.getHeaders()
12277
12636
  : { 'content-type': 'multipart/form-data' };
12278
- const { data } = await client.http.post('/api/v4/files', formData, {
12637
+ const { data } = await client.upload.post('/api/v4/files', formData, {
12279
12638
  headers,
12280
12639
  onUploadProgress({ loaded, total = 100 }) {
12281
12640
  onProgress && onProgress(Math.round((loaded * 100) / total));
@@ -12365,7 +12724,7 @@ const uploadVideo = async (formData, feedType, onProgress) => {
12365
12724
  const headers = 'getHeaders' in formData
12366
12725
  ? formData.getHeaders()
12367
12726
  : { 'content-type': 'multipart/form-data' };
12368
- const { data } = await client.http.post('/api/v4/videos', formData, {
12727
+ const { data } = await client.upload.post('/api/v4/videos', formData, {
12369
12728
  headers,
12370
12729
  onUploadProgress({ loaded, total = 100 }) {
12371
12730
  onProgress && onProgress(Math.round((loaded * 100) / total));
@@ -12413,7 +12772,7 @@ const uploadImage = async (formData, onProgress) => {
12413
12772
  const headers = 'getHeaders' in formData
12414
12773
  ? formData.getHeaders()
12415
12774
  : { 'content-type': 'multipart/form-data' };
12416
- const { data } = await client.http.post('/api/v4/images', formData, {
12775
+ const { data } = await client.upload.post('/api/v4/images', formData, {
12417
12776
  headers,
12418
12777
  onUploadProgress({ loaded, total = 100 }) {
12419
12778
  onProgress && onProgress(Math.round((loaded * 100) / total));
@@ -12907,6 +13266,8 @@ const addReaction = async (referenceType, referenceId, reactionName) => {
12907
13266
  referenceType,
12908
13267
  reactionName,
12909
13268
  });
13269
+ if (!['post', 'comment', 'story', 'message'].includes(referenceType))
13270
+ throw new ASCApiError('The reference type is not valid. It should be one of post, comment, story, or message', 400000 /* Amity.ServerError.BAD_REQUEST */, "error" /* Amity.ErrorLevel.ERROR */);
12910
13271
  const { data } = await client.http.post('/api/v2/reactions', {
12911
13272
  referenceId,
12912
13273
  referenceType,
@@ -13026,6 +13387,8 @@ const removeReaction = async (referenceType, referenceId, reactionName) => {
13026
13387
  referenceType,
13027
13388
  reactionName,
13028
13389
  });
13390
+ if (!['post', 'comment', 'story', 'message'].includes(referenceType))
13391
+ throw new ASCApiError('The reference type is not valid. It should be one of post, comment, story, or message', 400000 /* Amity.ServerError.BAD_REQUEST */, "error" /* Amity.ErrorLevel.ERROR */);
13029
13392
  const { data } = await client.http.delete(`/api/v2/reactions`, {
13030
13393
  data: {
13031
13394
  referenceId,
@@ -13494,6 +13857,29 @@ const createCommentEventSubscriber = (event, callback) => {
13494
13857
  }
13495
13858
  }
13496
13859
  }
13860
+ }
13861
+ if (['comment.deleted'].includes(event)) {
13862
+ // NOTE: skip deleting comment to parent comment children if it's the same user since we use the local event to update instead.
13863
+ if (event === 'comment.deleted' && comment.data.userId === client.userId)
13864
+ return;
13865
+ if (comments[0].parentId) {
13866
+ const parentComment = pullFromCache([
13867
+ 'comment',
13868
+ 'get',
13869
+ comments[0].parentId,
13870
+ ]);
13871
+ if (parentComment === null || parentComment === void 0 ? void 0 : parentComment.data) {
13872
+ // Remove deleted comment in parent childComment if still exists
13873
+ if (parentComment.data.children.includes(comments[0].commentId)) {
13874
+ const newParentComment = Object.assign(Object.assign({}, parentComment.data), { childrenNumber: parentComment.data.childrenNumber - 1, children: [
13875
+ ...new Set([
13876
+ ...parentComment.data.children.filter(id => id !== comments[0].commentId),
13877
+ ]),
13878
+ ] });
13879
+ pushToCache(['comment', 'get', comments[0].parentId], newParentComment);
13880
+ }
13881
+ }
13882
+ }
13497
13883
  const queries = (_a = queryCache(['comment', 'query'])) === null || _a === void 0 ? void 0 : _a.filter(({ key }) => { var _a; return ((_a = key[2]) === null || _a === void 0 ? void 0 : _a.referenceId) === comment.data.referenceId; });
13498
13884
  queries === null || queries === void 0 ? void 0 : queries.map(({ key, data }) => upsertInCache(key, data, { cachedAt: -1 }));
13499
13885
  }
@@ -13506,7 +13892,7 @@ const createCommentEventSubscriber = (event, callback) => {
13506
13892
  const createLocalCommentEventSubscriber = (event, callback) => {
13507
13893
  const client = getActiveClient();
13508
13894
  const filter = (payload) => {
13509
- var _a;
13895
+ var _a, _b;
13510
13896
  if (!client.cache) {
13511
13897
  // TODO: here we are missing specific properties here!
13512
13898
  callback(LinkedObject.comment(payload.comments[0]));
@@ -13549,6 +13935,38 @@ const createLocalCommentEventSubscriber = (event, callback) => {
13549
13935
  const queries = (_a = queryCache(['comment', 'query'])) === null || _a === void 0 ? void 0 : _a.filter(({ key }) => { var _a; return ((_a = key[2]) === null || _a === void 0 ? void 0 : _a.referenceId) === comment.data.referenceId; });
13550
13936
  queries === null || queries === void 0 ? void 0 : queries.map(({ key, data }) => upsertInCache(key, data, { cachedAt: -1 }));
13551
13937
  }
13938
+ if (['local.comment.deleted'].includes(event)) {
13939
+ if (comments[0].parentId) {
13940
+ const parentComment = pullFromCache([
13941
+ 'comment',
13942
+ 'get',
13943
+ comments[0].parentId,
13944
+ ]);
13945
+ if (parentComment === null || parentComment === void 0 ? void 0 : parentComment.data) {
13946
+ // Remove deleted comment in parent childComment if still exists
13947
+ if (parentComment.data.children.includes(comments[0].commentId)) {
13948
+ const newParentComment = Object.assign(Object.assign({}, parentComment.data), { childrenNumber: parentComment.data.childrenNumber - 1, children: [
13949
+ ...new Set([
13950
+ ...parentComment.data.children.filter(id => id !== comments[0].commentId),
13951
+ ]),
13952
+ ] });
13953
+ pushToCache(['comment', 'get', comments[0].parentId], newParentComment);
13954
+ setTimeout(() => {
13955
+ // NOTE: This is workaround solution for emitting event not work properly.
13956
+ fireEvent('comment.updated', {
13957
+ comments: [newParentComment],
13958
+ commentChildren: [],
13959
+ files: [],
13960
+ users: [],
13961
+ communityUsers: [],
13962
+ });
13963
+ }, 200);
13964
+ }
13965
+ }
13966
+ }
13967
+ const queries = (_b = queryCache(['comment', 'query'])) === null || _b === void 0 ? void 0 : _b.filter(({ key }) => { var _a; return ((_a = key[2]) === null || _a === void 0 ? void 0 : _a.referenceId) === comment.data.referenceId; });
13968
+ queries === null || queries === void 0 ? void 0 : queries.map(({ key, data }) => upsertInCache(key, data, { cachedAt: -1 }));
13969
+ }
13552
13970
  callback(LinkedObject.comment(comment.data));
13553
13971
  }
13554
13972
  }
@@ -13951,6 +14369,8 @@ class ReactionPaginationController extends PaginationController {
13951
14369
  const client = getActiveClient();
13952
14370
  client.log('reaction/queryReactions', queryParams);
13953
14371
  const path = '/api/v3/reactions';
14372
+ if (!['post', 'comment', 'story', 'message'].includes(params.referenceType))
14373
+ throw new ASCApiError('The reference type is not valid. It should be one of post, comment, story, or message', 400000 /* Amity.ServerError.BAD_REQUEST */, "error" /* Amity.ErrorLevel.ERROR */);
13954
14374
  const { data: queryResponse } = await this.http.get(path, {
13955
14375
  params: Object.assign(Object.assign({}, params), { referenceVersion: REFERENCE_API_V5, // Need to put this param to make it can query reaction for message in sub-channel
13956
14376
  options }),
@@ -16600,19 +17020,37 @@ var index$f = /*#__PURE__*/Object.freeze({
16600
17020
  /**
16601
17021
  * Internal used only
16602
17022
  *
16603
- * Fired when an {@link Amity.userMessageFeedMarkers} has been resolved by Object Rsesolver
17023
+ * Fired when an {@link Amity.channelUnreadInfo} has been updated.
16604
17024
  *
16605
17025
  * @param callback The function to call when the event was fired
16606
17026
  * @returns an {@link Amity.Unsubscriber} function to stop listening
16607
17027
  *
16608
- * @category MessageMarker Events
17028
+ * @category ChannelMarker Events
17029
+ */
17030
+ const onChannelUnreadInfoUpdatedLocal = (callback) => {
17031
+ const client = getActiveClient();
17032
+ const filter = (payload) => {
17033
+ callback(payload);
17034
+ };
17035
+ return createEventSubscriber(client, 'channelMarker/onChannelUnreadInfoUpdatedLocal', 'local.channelUnreadInfo.updated', filter);
17036
+ };
17037
+
17038
+ /**
17039
+ * Internal used only
17040
+ *
17041
+ * Fired when an {@link Amity.ChannelUnread} has been updated.
17042
+ *
17043
+ * @param callback The function to call when the event was fired
17044
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
17045
+ *
17046
+ * @category Channel Events
16609
17047
  */
16610
17048
  const onChannelUnreadUpdatedLocal = (callback) => {
16611
17049
  const client = getActiveClient();
16612
17050
  const filter = (payload) => {
16613
17051
  callback(payload);
16614
17052
  };
16615
- return createEventSubscriber(client, 'channelMarker/onChannelUnreadUpdatedLocal', 'local.channelUnread.updated', filter);
17053
+ return createEventSubscriber(client, 'channel/onChannelUnreadUpdatedLocal', 'local.channelUnread.updated', filter);
16616
17054
  };
16617
17055
 
16618
17056
  /* begin_public_function
@@ -16814,6 +17252,7 @@ const getChannel = (channelId, callback) => {
16814
17252
  return onSubChannelUpdated(updateMessagePreview);
16815
17253
  }, 'channelId', 'channel'),
16816
17254
  convertEventPayload(onSubChannelCreated, 'channelId', 'channel'),
17255
+ convertEventPayload(onChannelUnreadInfoUpdatedLocal, 'channelId', 'channel'),
16817
17256
  convertEventPayload(onChannelUnreadUpdatedLocal, 'channelId', 'channel'),
16818
17257
  ], {
16819
17258
  forceDispatch: true,
@@ -17327,6 +17766,10 @@ class ChannelLiveCollectionController extends LiveCollectionController {
17327
17766
  },
17328
17767
  action: "OnResolveUnread" /* Amity.ChannelActionType.OnResolveUnread */,
17329
17768
  },
17769
+ {
17770
+ fn: convertEventPayload(onChannelUnreadInfoUpdatedLocal, 'channelId', 'channel'),
17771
+ action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
17772
+ },
17330
17773
  {
17331
17774
  fn: convertEventPayload(onChannelUnreadUpdatedLocal, 'channelId', 'channel'),
17332
17775
  action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
@@ -17392,6 +17835,120 @@ const getChannels = (params, callback, config) => {
17392
17835
  };
17393
17836
  /* end_public_function */
17394
17837
 
17838
+ /**
17839
+ *
17840
+ * Calculate user unread from {@link Amity.ChannelUnread} objects
17841
+ *
17842
+ * @returns the {@link Amity.UserUnread} objects
17843
+ *
17844
+ * @category Channel API
17845
+ * @async
17846
+ */
17847
+ const getTotalChannelsUnread$1 = () => {
17848
+ var _a;
17849
+ const client = getActiveClient();
17850
+ client.log('channel/getTotalChannelsUnread.locally');
17851
+ const cachedChannelsUnread = ((_a = queryCache(['channelUnread', 'get'])) === null || _a === void 0 ? void 0 : _a.filter(({ data }) => {
17852
+ return !data.isDeleted;
17853
+ })) || [];
17854
+ const totalChannelsUnread = (cachedChannelsUnread === null || cachedChannelsUnread === void 0 ? void 0 : cachedChannelsUnread.reduce((acc, { data }) => {
17855
+ acc.unreadCount += data.unreadCount;
17856
+ acc.isMentioned = acc.isMentioned || data.isMentioned;
17857
+ return acc;
17858
+ }, { unreadCount: 0, isMentioned: false })) || { unreadCount: 0, isMentioned: false };
17859
+ const cachedAt = client.cache && Date.now();
17860
+ return {
17861
+ data: totalChannelsUnread,
17862
+ cachedAt,
17863
+ };
17864
+ };
17865
+
17866
+ /* begin_public_function
17867
+ id: totalChannelsUnread.get
17868
+ */
17869
+ /**
17870
+ * ```js
17871
+ * import { ChannelRepository } from '@amityco/ts-sdk';
17872
+ *
17873
+ * let totalChannelsUnread;
17874
+ *
17875
+ * const unsubscribe = ChannelRepository.getTotalChannelsUnread(response => {
17876
+ * unread = response.data;
17877
+ * });
17878
+ * ```
17879
+ *
17880
+ * Observe all mutation on a given {@link Amity.UserUnread}
17881
+ *
17882
+ * @returns An {@link Amity.UserUnread} function to run when willing to stop observing the message
17883
+ *
17884
+ * @category User Unread Live Object
17885
+ *
17886
+ */
17887
+ const getTotalChannelsUnread = (callback) => {
17888
+ const { _id: userId } = getActiveUser();
17889
+ if (!userId)
17890
+ throw new ASCError('The _id has not been defined in ActiveUser', 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
17891
+ const { log, cache } = getActiveClient();
17892
+ if (!cache) {
17893
+ console.log('For using Live Object feature you need to enable Cache!');
17894
+ }
17895
+ const timestamp = Date.now();
17896
+ log(`liveTotalChannelsUnread(tmpid: ${timestamp}) > listen`);
17897
+ const disposers = [];
17898
+ let isUnsyncedModel = false; // for messages
17899
+ let model;
17900
+ const dispatcher = (data) => {
17901
+ const { data: userUnread } = data;
17902
+ const callbackModel = userUnread
17903
+ ? {
17904
+ unreadCount: userUnread.unreadCount,
17905
+ isMentioned: userUnread.isMentioned,
17906
+ }
17907
+ : undefined;
17908
+ model = callbackModel ? convertGetterPropsToStatic(callbackModel) : callbackModel;
17909
+ callback({
17910
+ data: callbackModel
17911
+ ? Object.assign(Object.assign({}, callbackModel), { isMentioned: callbackModel.isMentioned }) : callbackModel,
17912
+ loading: data.loading,
17913
+ error: data.error,
17914
+ });
17915
+ };
17916
+ const realtimeRouter = (userUnread) => {
17917
+ if (isEqual(model, userUnread))
17918
+ return;
17919
+ dispatcher({
17920
+ loading: false,
17921
+ data: userUnread,
17922
+ });
17923
+ };
17924
+ const onFetch = () => {
17925
+ const query = createQuery(async () => getTotalChannelsUnread$1());
17926
+ runQuery(query, ({ error, data, loading, origin, cachedAt }) => {
17927
+ if (cachedAt === UNSYNCED_OBJECT_CACHED_AT_VALUE) {
17928
+ dispatcher({
17929
+ data,
17930
+ origin,
17931
+ loading: false,
17932
+ error: new ASCApiError(UNSYNCED_OBJECT_CACHED_AT_MESSAGE, 800800 /* Amity.ClientError.DISALOOW_UNSYNCED_OBJECT */, "error" /* Amity.ErrorLevel.ERROR */),
17933
+ });
17934
+ isUnsyncedModel = true;
17935
+ disposers.forEach(fn => fn());
17936
+ }
17937
+ else if (!isUnsyncedModel) {
17938
+ dispatcher({ loading, data, origin, error });
17939
+ }
17940
+ if (error) {
17941
+ disposers.forEach(fn => fn());
17942
+ }
17943
+ });
17944
+ };
17945
+ disposers.push(onChannelUnreadUpdatedLocal(realtimeRouter));
17946
+ onFetch();
17947
+ return () => {
17948
+ disposers.forEach(fn => fn());
17949
+ };
17950
+ };
17951
+
17395
17952
  /* begin_public_function
17396
17953
  id: channel.member.add
17397
17954
  */
@@ -17995,6 +18552,7 @@ var index$c = /*#__PURE__*/Object.freeze({
17995
18552
  onChannelMemberRoleRemoved: onChannelMemberRoleRemoved,
17996
18553
  getChannel: getChannel,
17997
18554
  getChannels: getChannels,
18555
+ getTotalChannelsUnread: getTotalChannelsUnread,
17998
18556
  MARKER_INCLUDED_CHANNEL_TYPE: MARKER_INCLUDED_CHANNEL_TYPE,
17999
18557
  isUnreadCountSupport: isUnreadCountSupport,
18000
18558
  convertFromRaw: convertFromRaw,
@@ -23937,7 +24495,7 @@ var index$3 = /*#__PURE__*/Object.freeze({
23937
24495
  getPoll: getPoll
23938
24496
  });
23939
24497
 
23940
- 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-----";
24498
+ 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-----";
23941
24499
  /*
23942
24500
  * The crypto algorithm used for importing key and signing string
23943
24501
  */