@amityco/ts-sdk-react-native 7.1.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 (89) 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/commentRepository/events/utils.d.ts.map +1 -1
  43. package/dist/core/events.d.ts +3 -3
  44. package/dist/core/events.d.ts.map +1 -1
  45. package/dist/core/model/idResolvers.d.ts.map +1 -1
  46. package/dist/index.cjs.js +610 -58
  47. package/dist/index.esm.js +610 -58
  48. package/dist/index.umd.js +3 -3
  49. package/dist/marker/events/onChannelUnreadInfoUpdatedLocal.d.ts +12 -0
  50. package/dist/marker/events/onChannelUnreadInfoUpdatedLocal.d.ts.map +1 -0
  51. package/dist/messageRepository/events/onMessageCreated.d.ts.map +1 -1
  52. package/dist/messageRepository/observers/getMessage.d.ts.map +1 -1
  53. package/dist/messageRepository/utils/markReadMessage.d.ts.map +1 -1
  54. package/package.json +1 -1
  55. package/src/@types/core/events.ts +2 -1
  56. package/src/@types/core/model.ts +4 -0
  57. package/src/@types/core/readReceipt.ts +14 -1
  58. package/src/@types/domains/channel.ts +13 -0
  59. package/src/@types/domains/client.ts +3 -0
  60. package/src/channelRepository/api/markChannelsAsReadBySegment.ts +29 -0
  61. package/src/channelRepository/events/onChannelDeleted.ts +17 -4
  62. package/src/channelRepository/events/onChannelLeft.ts +11 -3
  63. package/src/{marker → channelRepository}/events/onChannelUnreadUpdatedLocal.ts +3 -3
  64. package/src/channelRepository/internalApi/getTotalChannelsUnread.ts +38 -0
  65. package/src/channelRepository/observers/getChannel.ts +3 -1
  66. package/src/channelRepository/observers/getChannels/ChannelLiveCollectionController.ts +6 -1
  67. package/src/channelRepository/observers/getTotalChannelsUnread.ts +129 -0
  68. package/src/channelRepository/observers/index.ts +1 -0
  69. package/src/channelRepository/utils/constructChannelDynamicValue.ts +12 -2
  70. package/src/channelRepository/utils/getLegacyChannelUnread.ts +5 -0
  71. package/src/channelRepository/utils/prepareChannelPayload.ts +68 -17
  72. package/src/client/api/createClient.ts +7 -1
  73. package/src/client/api/enableUnreadCount.ts +1 -0
  74. package/src/client/api/login.ts +5 -1
  75. package/src/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.ts +267 -0
  76. package/src/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.ts +21 -0
  77. package/src/client/utils/ReadReceiptSync/readReceiptSyncEngine.ts +74 -99
  78. package/src/client/utils/endpoints.ts +1 -0
  79. package/src/client/utils/setClientToken.ts +8 -0
  80. package/src/commentRepository/events/utils.ts +73 -0
  81. package/src/core/model/idResolvers.ts +2 -0
  82. package/src/fileRepository/api/uploadFile.ts +1 -1
  83. package/src/fileRepository/api/uploadImage.ts +1 -1
  84. package/src/fileRepository/api/uploadVideo.ts +1 -1
  85. package/src/marker/events/onChannelUnreadInfoUpdatedLocal.ts +29 -0
  86. package/src/messageRepository/events/onMessageCreated.ts +45 -1
  87. package/src/messageRepository/observers/getMessage.ts +0 -1
  88. package/src/messageRepository/utils/markReadMessage.ts +10 -3
  89. package/dist/marker/events/onChannelUnreadUpdatedLocal.d.ts.map +0 -1
package/dist/index.esm.js CHANGED
@@ -89,8 +89,8 @@ const PostContentType = Object.freeze({
89
89
 
90
90
  function getVersion() {
91
91
  try {
92
- // the string ''v7.1.0-esm'' should be replaced by actual value by @rollup/plugin-replace
93
- return 'v7.1.0-esm';
92
+ // the string ''v7.2.0-esm'' should be replaced by actual value by @rollup/plugin-replace
93
+ return 'v7.2.0-esm';
94
94
  }
95
95
  catch (error) {
96
96
  return '__dev__';
@@ -503,6 +503,7 @@ const idResolvers = {
503
503
  messagePreviewSubChannel: ({ subChannelId }) => `${subChannelId}`,
504
504
  channelUnreadInfo: ({ channelId }) => channelId,
505
505
  subChannelUnreadInfo: ({ subChannelId }) => subChannelId,
506
+ channelUnread: ({ channelId }) => channelId,
506
507
  channelMarker: ({ entityId, userId }) => `${entityId}#${userId}`,
507
508
  subChannelMarker: ({ entityId, feedId, userId }) => `${entityId}#${feedId}#${userId}`,
508
509
  messageMarker: ({ feedId, contentId, creatorId }) => `${feedId}#${contentId}#${creatorId}`,
@@ -1560,6 +1561,7 @@ const API_REGIONS = {
1560
1561
  };
1561
1562
  const URLS = {
1562
1563
  http: 'https://apix.{region}.amity.co',
1564
+ upload: 'https://upload.{region}.amity.co',
1563
1565
  mqtt: 'wss://sse.{region}.amity.co:443/mqtt',
1564
1566
  };
1565
1567
  function computeUrl(type, region) {
@@ -1608,13 +1610,13 @@ class NetworkActivitiesWatcher {
1608
1610
  this._listener.clear();
1609
1611
  }
1610
1612
  }
1611
- let instance$5;
1613
+ let instance$6;
1612
1614
  var NetworkActivitiesWatcher$1 = {
1613
1615
  getInstance: () => {
1614
- if (!instance$5) {
1615
- instance$5 = new NetworkActivitiesWatcher();
1616
+ if (!instance$6) {
1617
+ instance$6 = new NetworkActivitiesWatcher();
1616
1618
  }
1617
- return instance$5;
1619
+ return instance$6;
1618
1620
  },
1619
1621
  };
1620
1622
 
@@ -21297,13 +21299,13 @@ class AnalyticsEngine {
21297
21299
  this._eventCapturer.resetAllBuckets();
21298
21300
  }
21299
21301
  }
21300
- let instance$4;
21302
+ let instance$5;
21301
21303
  var AnalyticsEngine$1 = {
21302
21304
  getInstance: () => {
21303
- if (!instance$4) {
21304
- instance$4 = new AnalyticsEngine();
21305
+ if (!instance$5) {
21306
+ instance$5 = new AnalyticsEngine();
21305
21307
  }
21306
- return instance$4;
21308
+ return instance$5;
21307
21309
  },
21308
21310
  };
21309
21311
 
@@ -21729,6 +21731,223 @@ const getMessageReadCount = (message, marker) => {
21729
21731
  getCachedMarker$2(message)) !== null && _a !== void 0 ? _a : { readCount: 0, deliveredCount: 0 };
21730
21732
  }; // and if not found in cache use default value `0`
21731
21733
 
21734
+ /**
21735
+ *
21736
+ * Mark subChannel as read by readToSegment
21737
+ *
21738
+ * @param subChannelIds the IDs of the {@link Amity.SubChannel} to update
21739
+ * @param readToSegment the segment to mark as read
21740
+ * @returns a success boolean if the {@link Amity.SubChannel} was updated
21741
+ *
21742
+ * @category Channel API
21743
+ * @async
21744
+ */
21745
+ const markChannelsAsReadBySegment = async (readings) => {
21746
+ const client = getActiveClient();
21747
+ try {
21748
+ await client.http.post('api/v3/channels/seen', { channels: readings });
21749
+ return true;
21750
+ }
21751
+ catch (e) {
21752
+ return false;
21753
+ }
21754
+ };
21755
+
21756
+ class MessageReadReceiptSyncEngine {
21757
+ constructor() {
21758
+ this.isActive = true;
21759
+ this.MAX_RETRY = 3;
21760
+ this.JOB_QUEUE_SIZE = 120;
21761
+ this.jobQueue = [];
21762
+ // Interval for message read receipt sync in seconds
21763
+ this.RECEIPT_SYNC_INTERVAL = 1;
21764
+ this.client = getActiveClient();
21765
+ // Get remaining unsync read receipts from cache
21766
+ this.getUnsyncJobs();
21767
+ }
21768
+ // Call this when client call client.login
21769
+ startSyncReadReceipt() {
21770
+ // Start timer when start receipt sync
21771
+ this.timer = setInterval(() => {
21772
+ this.syncReadReceipts();
21773
+ }, this.RECEIPT_SYNC_INTERVAL * 1000);
21774
+ }
21775
+ // Read receipt observer handling
21776
+ syncReadReceipts() {
21777
+ if (this.jobQueue.length === 0 || this.isActive === false)
21778
+ return;
21779
+ const readReceipts = this.getReadReceipts();
21780
+ if (readReceipts) {
21781
+ this.markReadApi(readReceipts);
21782
+ }
21783
+ }
21784
+ getUnsyncJobs() {
21785
+ var _a;
21786
+ // Get all read receipts that has latestSyncSegment < latestSegment
21787
+ const readReceipts = (_a = queryCache(['readReceipt'])) === null || _a === void 0 ? void 0 : _a.filter(({ data }) => {
21788
+ return data.latestSyncSegment < data.latestSegment;
21789
+ });
21790
+ // Enqueue unsync read receipts to the job queue
21791
+ readReceipts === null || readReceipts === void 0 ? void 0 : readReceipts.forEach(({ data: readReceipt }) => {
21792
+ this.enqueueReadReceipt(readReceipt.channelId, readReceipt.latestSegment);
21793
+ });
21794
+ }
21795
+ getReadReceipts() {
21796
+ // get all read receipts from queue, now the queue is empty
21797
+ const syncJob = this.jobQueue.splice(0, this.jobQueue.length);
21798
+ if (syncJob.length === 0)
21799
+ return;
21800
+ return syncJob.filter(job => {
21801
+ var _a;
21802
+ const readReceipt = (_a = pullFromCache(['readReceipt', job.channelId])) === null || _a === void 0 ? void 0 : _a.data;
21803
+ if (!readReceipt)
21804
+ return false;
21805
+ if (readReceipt.latestSegment > readReceipt.latestSyncSegment)
21806
+ return true;
21807
+ return false;
21808
+ });
21809
+ }
21810
+ async markReadApi(syncJobs) {
21811
+ var _a;
21812
+ // constuct payload
21813
+ // example: [{ channelId: 'channelId', readToSegment: 2 }]
21814
+ const syncJobsPayload = syncJobs.map(job => {
21815
+ return {
21816
+ channelId: job.channelId,
21817
+ readToSegment: job.segment,
21818
+ };
21819
+ });
21820
+ const response = await markChannelsAsReadBySegment(syncJobsPayload);
21821
+ if (response) {
21822
+ for (let i = 0; i < syncJobs.length; i += 1) {
21823
+ // update lastestSyncSegment in read receipt cache
21824
+ const cacheKey = ['readReceipt', syncJobs[i].channelId];
21825
+ const readReceiptCache = (_a = pullFromCache(cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
21826
+ pushToCache(cacheKey, Object.assign(Object.assign({}, readReceiptCache), { latestSyncSegment: syncJobs[i].segment }));
21827
+ }
21828
+ }
21829
+ else {
21830
+ for (let i = 0; i < syncJobs.length; i += 1) {
21831
+ // push them back to queue if the syncing is failed and retry count is less than max retry
21832
+ if (syncJobs[i].retryCount >= this.MAX_RETRY)
21833
+ return;
21834
+ const updatedJob = Object.assign(Object.assign({}, syncJobs[i]), { syncState: "create" /* Amity.ReadReceiptSyncState.CREATED */, retryCount: syncJobs[i].retryCount + 1 });
21835
+ this.enqueueJob(updatedJob);
21836
+ }
21837
+ }
21838
+ }
21839
+ startObservingReadReceiptQueue() {
21840
+ if (this.client.useLegacyUnreadCount) {
21841
+ this.isActive = true;
21842
+ this.startSyncReadReceipt();
21843
+ }
21844
+ }
21845
+ stopObservingReadReceiptQueue() {
21846
+ this.isActive = false;
21847
+ this.jobQueue.map(job => {
21848
+ if (job.syncState === "syncing" /* Amity.ReadReceiptSyncState.SYNCING */) {
21849
+ return Object.assign(Object.assign({}, job), { syncState: "create" /* Amity.ReadReceiptSyncState.CREATED */ });
21850
+ }
21851
+ return job;
21852
+ });
21853
+ if (this.timer)
21854
+ clearInterval(this.timer);
21855
+ }
21856
+ // Session Management
21857
+ onSessionEstablished() {
21858
+ this.startObservingReadReceiptQueue();
21859
+ }
21860
+ onSessionDestroyed() {
21861
+ this.stopObservingReadReceiptQueue();
21862
+ this.jobQueue = [];
21863
+ }
21864
+ onTokenExpired() {
21865
+ this.stopObservingReadReceiptQueue();
21866
+ }
21867
+ // Network Connection Management
21868
+ onNetworkOffline() {
21869
+ // Stop observing to the read receipt queue.
21870
+ this.stopObservingReadReceiptQueue();
21871
+ }
21872
+ onNetworkOnline() {
21873
+ // Resume observing to the read receipt queue.
21874
+ this.startObservingReadReceiptQueue();
21875
+ }
21876
+ markRead(channelId, segment) {
21877
+ var _a;
21878
+ // Step 1: Optimistic update of channelUnread.readToSegment to message.segment and update unreadCount value
21879
+ const cacheKey = ['channelUnread', 'get', channelId];
21880
+ const channelUnread = (_a = pullFromCache(cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
21881
+ if (typeof (channelUnread === null || channelUnread === void 0 ? void 0 : channelUnread.readToSegment) === 'number' &&
21882
+ channelUnread &&
21883
+ segment > channelUnread.readToSegment) {
21884
+ channelUnread.readToSegment = segment;
21885
+ channelUnread.unreadCount = Math.max(channelUnread.lastSegment - segment, 0);
21886
+ pushToCache(cacheKey, channelUnread);
21887
+ fireEvent('local.channelUnread.updated', channelUnread);
21888
+ }
21889
+ // Step 2: Enqueue the read receipt
21890
+ this.enqueueReadReceipt(channelId, segment);
21891
+ }
21892
+ enqueueReadReceipt(channelId, segment) {
21893
+ var _a;
21894
+ const readReceipt = (_a = pullFromCache(['readReceipt', channelId])) === null || _a === void 0 ? void 0 : _a.data;
21895
+ // Create new read receipt if it's not exists and add the job to queue
21896
+ if (!readReceipt) {
21897
+ const readReceiptChannel = {
21898
+ channelId,
21899
+ latestSegment: segment,
21900
+ latestSyncSegment: 0,
21901
+ };
21902
+ pushToCache(['readReceipt', channelId], readReceiptChannel);
21903
+ }
21904
+ else if (readReceipt.latestSegment < segment) {
21905
+ // Update latestSegment in read receipt cache
21906
+ pushToCache(['readReceipt', channelId], Object.assign(Object.assign({}, readReceipt), { latestSegment: segment }));
21907
+ }
21908
+ else if (readReceipt.latestSyncSegment >= segment) {
21909
+ // Skip the job when lastSyncSegment > = segment
21910
+ return;
21911
+ }
21912
+ let syncJob = this.getSyncJob(channelId);
21913
+ if (syncJob === null || syncJob.syncState === "syncing" /* Amity.ReadReceiptSyncState.SYNCING */) {
21914
+ syncJob = {
21915
+ channelId,
21916
+ segment,
21917
+ syncState: "create" /* Amity.ReadReceiptSyncState.CREATED */,
21918
+ retryCount: 0,
21919
+ };
21920
+ this.enqueueJob(syncJob);
21921
+ }
21922
+ else if (syncJob.segment < segment) {
21923
+ syncJob.segment = segment;
21924
+ }
21925
+ }
21926
+ getSyncJob(channelId) {
21927
+ const { jobQueue } = this;
21928
+ const targetJob = jobQueue.find(job => job.channelId === channelId);
21929
+ return targetJob || null;
21930
+ }
21931
+ enqueueJob(syncJob) {
21932
+ if (this.jobQueue.length < this.JOB_QUEUE_SIZE) {
21933
+ this.jobQueue.push(syncJob);
21934
+ }
21935
+ else {
21936
+ // Remove oldest job when queue reach maximum capacity
21937
+ this.jobQueue.shift();
21938
+ this.jobQueue.push(syncJob);
21939
+ }
21940
+ }
21941
+ }
21942
+ let instance$4 = null;
21943
+ var ReadReceiptSyncEngine = {
21944
+ getInstance: () => {
21945
+ if (!instance$4)
21946
+ instance$4 = new MessageReadReceiptSyncEngine();
21947
+ return instance$4;
21948
+ },
21949
+ };
21950
+
21732
21951
  /**
21733
21952
  *
21734
21953
  * Mark subChannel as read by readToSegment
@@ -21777,7 +21996,7 @@ const reCalculateChannelUnreadInfo = (channelId) => {
21777
21996
  return channelUnreadInfo;
21778
21997
  };
21779
21998
 
21780
- class MessageReadReceiptSyncEngine {
21999
+ class LegacyMessageReadReceiptSyncEngine {
21781
22000
  constructor() {
21782
22001
  this.isActive = true;
21783
22002
  this.MAX_RETRY = 3;
@@ -21808,7 +22027,7 @@ class MessageReadReceiptSyncEngine {
21808
22027
  getUnsyncJobs() {
21809
22028
  var _a;
21810
22029
  // Get all read receipts that has latestSyncSegment < latestSegment
21811
- const readReceipts = (_a = queryCache(['readReceipt'])) === null || _a === void 0 ? void 0 : _a.filter(({ data }) => {
22030
+ const readReceipts = (_a = queryCache(['legacyReadReceipt'])) === null || _a === void 0 ? void 0 : _a.filter(({ data }) => {
21812
22031
  return data.latestSyncSegment < data.latestSegment;
21813
22032
  });
21814
22033
  // Enqueue unsync read receipts to the job queue
@@ -21827,7 +22046,7 @@ class MessageReadReceiptSyncEngine {
21827
22046
  return;
21828
22047
  // Get readReceipt from cache by subChannelId
21829
22048
  const readReceipt = (_a = pullFromCache([
21830
- 'readReceipt',
22049
+ 'legacyReadReceipt',
21831
22050
  syncJob.subChannelId,
21832
22051
  ])) === null || _a === void 0 ? void 0 : _a.data;
21833
22052
  if (!readReceipt)
@@ -21850,10 +22069,10 @@ class MessageReadReceiptSyncEngine {
21850
22069
  if (response) {
21851
22070
  this.removeSynedReceipt(syncJob.subChannelId, syncJob.segment);
21852
22071
  const readReceiptCache = (_a = pullFromCache([
21853
- 'readReceipt',
22072
+ 'legacyReadReceipt',
21854
22073
  subChannelId,
21855
22074
  ])) === null || _a === void 0 ? void 0 : _a.data;
21856
- pushToCache(['readReceipt', subChannelId], Object.assign(Object.assign({}, readReceiptCache), { latestSyncSegment: segment }));
22075
+ pushToCache(['legacyReadReceipt', subChannelId], Object.assign(Object.assign({}, readReceiptCache), { latestSyncSegment: segment }));
21857
22076
  }
21858
22077
  else if (!response) {
21859
22078
  if (newSyncJob.retryCount > this.MAX_RETRY) {
@@ -21920,7 +22139,7 @@ class MessageReadReceiptSyncEngine {
21920
22139
  subChannelUnreadInfo.readToSegment = segment;
21921
22140
  subChannelUnreadInfo.unreadCount = Math.max(subChannelUnreadInfo.lastSegment - segment, 0);
21922
22141
  const channelUnreadInfo = reCalculateChannelUnreadInfo(subChannelUnreadInfo.channelId);
21923
- fireEvent('local.channelUnread.updated', channelUnreadInfo);
22142
+ fireEvent('local.channelUnreadInfo.updated', channelUnreadInfo);
21924
22143
  pushToCache(cacheKey, subChannelUnreadInfo);
21925
22144
  fireEvent('local.subChannelUnread.updated', subChannelUnreadInfo);
21926
22145
  }
@@ -21929,7 +22148,10 @@ class MessageReadReceiptSyncEngine {
21929
22148
  }
21930
22149
  enqueueReadReceipt(subChannelId, segment) {
21931
22150
  var _a;
21932
- const readReceipt = (_a = pullFromCache(['readReceipt', subChannelId])) === null || _a === void 0 ? void 0 : _a.data;
22151
+ const readReceipt = (_a = pullFromCache([
22152
+ 'legacyReadReceipt',
22153
+ subChannelId,
22154
+ ])) === null || _a === void 0 ? void 0 : _a.data;
21933
22155
  // Create new read receipt if it's not exists and add job to queue
21934
22156
  if (!readReceipt) {
21935
22157
  const readReceiptSubChannel = {
@@ -21937,10 +22159,10 @@ class MessageReadReceiptSyncEngine {
21937
22159
  latestSegment: segment,
21938
22160
  latestSyncSegment: 0,
21939
22161
  };
21940
- pushToCache(['readReceipt', subChannelId], readReceiptSubChannel);
22162
+ pushToCache(['legacyReadReceipt', subChannelId], readReceiptSubChannel);
21941
22163
  }
21942
22164
  else if (readReceipt.latestSegment < segment) {
21943
- pushToCache(['readReceipt', subChannelId], Object.assign(Object.assign({}, readReceipt), { latestSegment: segment }));
22165
+ pushToCache(['legacyReadReceipt', subChannelId], Object.assign(Object.assign({}, readReceipt), { latestSegment: segment }));
21944
22166
  }
21945
22167
  else if (readReceipt.latestSyncSegment >= segment) {
21946
22168
  // Skip the job when lastSyncSegment > = segment
@@ -21983,18 +22205,24 @@ class MessageReadReceiptSyncEngine {
21983
22205
  }
21984
22206
  }
21985
22207
  let instance$3 = null;
21986
- var ReadReceiptSyncEngine = {
22208
+ var LegacyReadReceiptSyncEngine = {
21987
22209
  getInstance: () => {
21988
22210
  if (!instance$3)
21989
- instance$3 = new MessageReadReceiptSyncEngine();
22211
+ instance$3 = new LegacyMessageReadReceiptSyncEngine();
21990
22212
  return instance$3;
21991
22213
  },
21992
22214
  };
21993
22215
 
21994
22216
  const markReadMessage = (message) => {
21995
- const { subChannelId, channelSegment } = message;
21996
- const markReadReceiptEngine = ReadReceiptSyncEngine.getInstance();
21997
- markReadReceiptEngine.markRead(subChannelId, channelSegment);
22217
+ const client = getActiveClient();
22218
+ if (client.useLegacyUnreadCount) {
22219
+ const markReadReceiptEngine = ReadReceiptSyncEngine.getInstance();
22220
+ markReadReceiptEngine.markRead(message.channelId, message.channelSegment);
22221
+ }
22222
+ else {
22223
+ const markReadReceiptEngine = LegacyReadReceiptSyncEngine.getInstance();
22224
+ markReadReceiptEngine.markRead(message.subChannelId, message.channelSegment);
22225
+ }
21998
22226
  };
21999
22227
 
22000
22228
  const messageLinkedObject = (message) => {
@@ -22982,6 +23210,32 @@ const preUpdateChannelCache = (rawPayload, options = { isMessagePreviewUpdated:
22982
23210
  channels: rawPayload.channels.map(channel => convertFromRaw(channel, { isMessagePreviewUpdated: options.isMessagePreviewUpdated })),
22983
23211
  });
22984
23212
  };
23213
+ const updateChannelUnread = ({ currentUserId, channels, channelUsers, }) => {
23214
+ for (let i = 0; i < channels.length; i += 1) {
23215
+ const cacheKey = ['channelUnread', 'get', channels[i].channelId];
23216
+ const channelUser = channelUsers.find(channelUser => channelUser.channelId === channels[i].channelId && channelUser.userId === currentUserId);
23217
+ let unreadCount = 0;
23218
+ let readToSegment = null;
23219
+ let lastMentionedSegment = null;
23220
+ let isMentioned = false;
23221
+ if (channelUser) {
23222
+ readToSegment = channelUser.readToSegment;
23223
+ lastMentionedSegment = channelUser.lastMentionedSegment;
23224
+ unreadCount = Math.max(channels[i].messageCount - readToSegment, 0);
23225
+ isMentioned = lastMentionedSegment > readToSegment;
23226
+ }
23227
+ const cacheChannelUnread = {
23228
+ channelId: channels[i].channelId,
23229
+ lastSegment: channels[i].messageCount,
23230
+ readToSegment,
23231
+ lastMentionedSegment,
23232
+ unreadCount,
23233
+ isMentioned,
23234
+ isDeleted: channels[i].isDeleted || false,
23235
+ };
23236
+ pushToCache(cacheKey, cacheChannelUnread);
23237
+ }
23238
+ };
22985
23239
  const prepareChannelPayload = async (rawPayload, options = { isMessagePreviewUpdated: true }) => {
22986
23240
  const client = getActiveClient();
22987
23241
  const networkPreviewSetting = await client.getMessagePreviewSetting(false);
@@ -22991,23 +23245,34 @@ const prepareChannelPayload = async (rawPayload, options = { isMessagePreviewUpd
22991
23245
  rawPayload.messagePreviews.length > 0) {
22992
23246
  updateChannelMessagePreviewCache(rawPayload);
22993
23247
  }
22994
- const markerIds = rawPayload.channels
22995
- // filter channel by type. Only conversation, community and broadcast type are included.
22996
- .filter(isUnreadCountSupport)
22997
- .map(({ channelInternalId }) => channelInternalId);
22998
- if (markerIds.length > 0) {
22999
- // since the get markers method requires a channel cache to function with the reducer.
23000
- preUpdateChannelCache(rawPayload, { isMessagePreviewUpdated: options.isMessagePreviewUpdated });
23001
- try {
23002
- await getChannelMarkers(markerIds);
23003
- }
23004
- catch (e) {
23005
- // empty block (from the spec, allow marker fetch to fail without having to do anything)
23248
+ if (client.useLegacyUnreadCount) {
23249
+ updateChannelUnread({
23250
+ channels: rawPayload.channels,
23251
+ channelUsers: rawPayload.channelUsers,
23252
+ currentUserId: client.userId,
23253
+ });
23254
+ }
23255
+ else {
23256
+ const markerIds = rawPayload.channels
23257
+ // filter channel by type. Only conversation, community and broadcast type are included.
23258
+ .filter(isUnreadCountSupport)
23259
+ .map(({ channelInternalId }) => channelInternalId);
23260
+ if (markerIds.length > 0) {
23261
+ // since the get markers method requires a channel cache to function with the reducer.
23262
+ preUpdateChannelCache(rawPayload, {
23263
+ isMessagePreviewUpdated: options.isMessagePreviewUpdated,
23264
+ });
23265
+ try {
23266
+ await getChannelMarkers(markerIds);
23267
+ }
23268
+ catch (e) {
23269
+ // empty block (from the spec, allow marker fetch to fail without having to do anything)
23270
+ }
23006
23271
  }
23007
23272
  }
23008
- // attach marker to channel
23273
+ // convert raw channel to internal channel
23009
23274
  const channels = rawPayload.channels.map(payload => convertFromRaw(payload, { isMessagePreviewUpdated: options.isMessagePreviewUpdated }));
23010
- // user marker to channel users
23275
+ // convert raw channel user to membership (add user object)
23011
23276
  const channelUsers = rawPayload.channelUsers.map(channelUser => {
23012
23277
  return convertRawMembershipToMembership(channelUser);
23013
23278
  });
@@ -23134,15 +23399,28 @@ const getSubChannelsUnreadCount = (channel, marker) => {
23134
23399
  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;
23135
23400
  };
23136
23401
 
23402
+ const getLegacyChannelUnread = (channelId) => {
23403
+ var _a;
23404
+ return (_a = pullFromCache(['channelUnread', 'get', channelId])) === null || _a === void 0 ? void 0 : _a.data;
23405
+ };
23406
+
23137
23407
  const constructChannelDynamicValue = (channel) => {
23408
+ const client = getActiveClient();
23138
23409
  const rest = __rest(channel, ["messageCount"]);
23139
23410
  return shallowClone(rest, {
23140
- get isMentioned() {
23141
- return getChannelIsMentioned(rest);
23411
+ get unreadCount() {
23412
+ var _a, _b;
23413
+ return (_b = (_a = getLegacyChannelUnread(rest.channelId)) === null || _a === void 0 ? void 0 : _a.unreadCount) !== null && _b !== void 0 ? _b : 0;
23142
23414
  },
23143
23415
  get subChannelsUnreadCount() {
23144
23416
  return getSubChannelsUnreadCount(rest);
23145
23417
  },
23418
+ get isMentioned() {
23419
+ var _a, _b;
23420
+ if (client.useLegacyUnreadCount)
23421
+ return (_b = (_a = getLegacyChannelUnread(rest.channelId)) === null || _a === void 0 ? void 0 : _a.isMentioned) !== null && _b !== void 0 ? _b : false;
23422
+ return getChannelIsMentioned(rest);
23423
+ },
23146
23424
  });
23147
23425
  };
23148
23426
 
@@ -23755,6 +24033,12 @@ const setClientToken = async (params) => {
23755
24033
  isGlobalBanned: false,
23756
24034
  isUserDeleted: false,
23757
24035
  };
24036
+ client.upload.defaults.headers.common.Authorization = `Bearer ${accessToken}`;
24037
+ client.upload.defaults.metadata = {
24038
+ tokenExpiry: expiresAt,
24039
+ isGlobalBanned: false,
24040
+ isUserDeleted: false,
24041
+ };
23758
24042
  // manually setup the token for ws transport
23759
24043
  if (client.ws)
23760
24044
  client.ws.io.opts.query = { token: accessToken };
@@ -23799,12 +24083,21 @@ const onChannelDeleted = (callback) => {
23799
24083
  const client = getActiveClient();
23800
24084
  const filter = async (payload) => {
23801
24085
  const data = await prepareChannelPayload(payload);
23802
- if (client.isUnreadCountEnabled && client.getMarkerSyncConsistentMode()) {
23803
- data.channels.forEach(channel => {
24086
+ const isConsistentMode = client.getMarkerSyncConsistentMode() && client.isUnreadCountEnabled;
24087
+ const isLegacyUnreadCount = client.useLegacyUnreadCount;
24088
+ data.channels.forEach(channel => {
24089
+ if (isConsistentMode) {
23804
24090
  addFlagIsDeletedSubChannelUnreadByChannelId(channel.channelId);
23805
24091
  deleteChannelUnreadByChannelId(channel.channelId);
23806
- });
23807
- }
24092
+ }
24093
+ else if (isLegacyUnreadCount) {
24094
+ const cacheKey = ['channelUnread', 'get', channel.channelId];
24095
+ const cache = pullFromCache(cacheKey);
24096
+ if (cache) {
24097
+ pushToCache(cacheKey, Object.assign(Object.assign({}, cache), { isDeleted: true }));
24098
+ }
24099
+ }
24100
+ });
23808
24101
  ingestInCache(data);
23809
24102
  callbacks$b.forEach(cb => cb(data.channels[0]));
23810
24103
  };
@@ -23918,6 +24211,25 @@ var readReceiptSyncEngineOnLoginHandler = () => {
23918
24211
  };
23919
24212
  };
23920
24213
 
24214
+ var legacyReadReceiptSyncEngineOnLoginHandler = () => {
24215
+ const readReceiptSyncEngine = LegacyReadReceiptSyncEngine.getInstance();
24216
+ readReceiptSyncEngine.startSyncReadReceipt();
24217
+ onSessionStateChange(state => {
24218
+ if (state === "established" /* Amity.SessionStates.ESTABLISHED */) {
24219
+ readReceiptSyncEngine.onSessionEstablished();
24220
+ }
24221
+ else if (state === "tokenExpired" /* Amity.SessionStates.TOKEN_EXPIRED */) {
24222
+ readReceiptSyncEngine.onTokenExpired();
24223
+ }
24224
+ else {
24225
+ readReceiptSyncEngine.onSessionDestroyed();
24226
+ }
24227
+ });
24228
+ return () => {
24229
+ readReceiptSyncEngine.onSessionDestroyed();
24230
+ };
24231
+ };
24232
+
23921
24233
  const onOnline = (callback) => {
23922
24234
  if (typeof window !== 'undefined' && window.addEventListener) {
23923
24235
  window.addEventListener('online', callback);
@@ -24514,10 +24826,17 @@ const onChannelLeft = (callback) => {
24514
24826
  const preparedPayload = await prepareChannelPayload(payload, {
24515
24827
  isMessagePreviewUpdated: isLeftByMe,
24516
24828
  });
24517
- if (client.isUnreadCountEnabled && client.getMarkerSyncConsistentMode() && isLeftByMe) {
24829
+ const isConsistentMode = client.getMarkerSyncConsistentMode() && client.isUnreadCountEnabled;
24830
+ const isLegacyUnreadCount = client.useLegacyUnreadCount;
24831
+ if (isLeftByMe) {
24518
24832
  preparedPayload.channels.forEach(channel => {
24519
- addFlagIsDeletedSubChannelUnreadByChannelId(channel.channelId);
24520
- deleteChannelUnreadByChannelId(channel.channelId);
24833
+ if (isConsistentMode) {
24834
+ addFlagIsDeletedSubChannelUnreadByChannelId(channel.channelId);
24835
+ deleteChannelUnreadByChannelId(channel.channelId);
24836
+ }
24837
+ else if (isLegacyUnreadCount) {
24838
+ dropFromCache(['channelUnread', 'get', channel.channelId]);
24839
+ }
24521
24840
  });
24522
24841
  }
24523
24842
  const { channels, channelUsers } = preparedPayload;
@@ -24785,6 +25104,34 @@ const onMessageCreatedMqtt = (callback) => {
24785
25104
  reCalculateChannelUnreadInfo(message.channelId);
24786
25105
  });
24787
25106
  }
25107
+ if (client.useLegacyUnreadCount) {
25108
+ rawPayload.messages.forEach(message => {
25109
+ var _a, _b;
25110
+ const channelUnread = (_a = pullFromCache([
25111
+ 'channelUnread',
25112
+ 'get',
25113
+ message.channelId,
25114
+ ])) === null || _a === void 0 ? void 0 : _a.data;
25115
+ if (!channelUnread ||
25116
+ channelUnread.lastSegment >= message.segment ||
25117
+ typeof channelUnread.readToSegment !== 'number' ||
25118
+ typeof channelUnread.lastMentionedSegment !== 'number')
25119
+ return;
25120
+ const lastSegment = message.segment;
25121
+ const isMentionedInMessage = (_b = message.mentionedUsers) === null || _b === void 0 ? void 0 : _b.some(mention => {
25122
+ return (mention.type === 'channel' ||
25123
+ (mention.type === 'user' &&
25124
+ client.userId &&
25125
+ mention.userPublicIds.includes(client.userId)));
25126
+ });
25127
+ const lastMentionedSegment = isMentionedInMessage
25128
+ ? message.segment
25129
+ : channelUnread.lastMentionedSegment;
25130
+ const updatedChannelUnread = Object.assign(Object.assign({}, channelUnread), { lastSegment, unreadCount: Math.max(lastSegment - channelUnread.readToSegment, 0), lastMentionedSegment, isMentioned: !(channelUnread.readToSegment >= lastMentionedSegment) });
25131
+ pushToCache(['channelUnread', 'get', message.channelId], updatedChannelUnread);
25132
+ fireEvent('local.channelUnread.updated', updatedChannelUnread);
25133
+ });
25134
+ }
24788
25135
  // Update in cache
24789
25136
  ingestInCache(payload);
24790
25137
  payload.messages.forEach(message => {
@@ -24960,6 +25307,7 @@ const enableUnreadCount = () => {
24960
25307
  if (client.isUnreadCountEnabled)
24961
25308
  return false;
24962
25309
  client.isUnreadCountEnabled = true;
25310
+ client.useLegacyUnreadCount = false;
24963
25311
  client.emitter.emit('unreadCountEnabled', true);
24964
25312
  return true;
24965
25313
  };
@@ -25275,7 +25623,12 @@ const login = async (params, sessionHandler, config) => {
25275
25623
  // NOTE: This is a temporary solution to handle the channel marker when the user is forced to leave
25276
25624
  // the channel because currently backend can't handle this, so every time a user is banned from
25277
25625
  // a channel or the channel is deleted the channel's unread count will not be reset to zero
25278
- onChannelDeleted(removeChannelMarkerCache), onChannelMemberBanned(removeChannelMarkerCache), markReadEngineOnLoginHandler(), analyticsEngineOnLoginHandler(), readReceiptSyncEngineOnLoginHandler(), objectResolverEngineOnLoginHandler());
25626
+ onChannelDeleted(removeChannelMarkerCache), onChannelMemberBanned(removeChannelMarkerCache), markReadEngineOnLoginHandler(), analyticsEngineOnLoginHandler(), objectResolverEngineOnLoginHandler());
25627
+ if (client.useLegacyUnreadCount) {
25628
+ subscriptions.push(readReceiptSyncEngineOnLoginHandler());
25629
+ }
25630
+ else
25631
+ subscriptions.push(legacyReadReceiptSyncEngineOnLoginHandler());
25279
25632
  const markerSyncUnsubscriber = await startMarkerSync();
25280
25633
  subscriptions.push(markerSyncUnsubscriber);
25281
25634
  }
@@ -25453,15 +25806,17 @@ const DEFAULT_DEBUG_SESSION = 'amity';
25453
25806
  * @category Client API
25454
25807
  * */
25455
25808
  const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAULT_DEBUG_SESSION, apiEndpoint, prefixDeviceIdKey, rteEnabled = true, } = {}) => {
25456
- var _a, _b;
25809
+ var _a, _b, _c;
25457
25810
  const log = createLogger(debugSession);
25458
25811
  log('client/api/createClient', {
25459
25812
  apiKey: apiKey.replace(/.{5}$/g, 'xxxxx'),
25460
25813
  apiRegion,
25461
25814
  });
25462
25815
  const httpEndpoint = (_a = apiEndpoint === null || apiEndpoint === void 0 ? void 0 : apiEndpoint.http) !== null && _a !== void 0 ? _a : computeUrl('http', apiRegion);
25463
- const mqttEndpoint = (_b = apiEndpoint === null || apiEndpoint === void 0 ? void 0 : apiEndpoint.mqtt) !== null && _b !== void 0 ? _b : computeUrl('mqtt', apiRegion);
25816
+ const uploadEndpoint = (_b = apiEndpoint === null || apiEndpoint === void 0 ? void 0 : apiEndpoint.upload) !== null && _b !== void 0 ? _b : computeUrl('upload', apiRegion);
25817
+ const mqttEndpoint = (_c = apiEndpoint === null || apiEndpoint === void 0 ? void 0 : apiEndpoint.mqtt) !== null && _c !== void 0 ? _c : computeUrl('mqtt', apiRegion);
25464
25818
  const http = createHttpTransport(httpEndpoint);
25819
+ const upload = createHttpTransport(uploadEndpoint);
25465
25820
  let ws;
25466
25821
  let mqtt;
25467
25822
  if (rteEnabled) {
@@ -25476,6 +25831,8 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
25476
25831
  const sessionState = "notLoggedIn" /* Amity.SessionStates.NOT_LOGGED_IN */;
25477
25832
  const sessionHandler = undefined;
25478
25833
  const isUnreadCountEnabled = false;
25834
+ // Legacy unread count is true by default
25835
+ const useLegacyUnreadCount = true;
25479
25836
  const client = {
25480
25837
  version: `${VERSION}`,
25481
25838
  apiKey,
@@ -25490,6 +25847,7 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
25490
25847
  http,
25491
25848
  ws,
25492
25849
  mqtt,
25850
+ upload,
25493
25851
  emitter,
25494
25852
  /*
25495
25853
  * Session Components
@@ -25506,6 +25864,7 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
25506
25864
  onRTEConnectionStateChange,
25507
25865
  use: () => setActiveClient(client),
25508
25866
  isUnreadCountEnabled,
25867
+ useLegacyUnreadCount,
25509
25868
  getMarkerSyncConsistentMode,
25510
25869
  /**
25511
25870
  * Prefix for the deviceId key in the local storage or async storage.
@@ -25519,7 +25878,7 @@ const createClient = (apiKey, apiRegion = API_REGIONS.SG, { debugSession = DEFAU
25519
25878
  return activeClient;
25520
25879
  setActiveClient(client);
25521
25880
  }
25522
- catch (_c) {
25881
+ catch (_d) {
25523
25882
  setActiveClient(client);
25524
25883
  }
25525
25884
  return client;
@@ -28348,7 +28707,7 @@ const uploadFile = async (formData, onProgress) => {
28348
28707
  const headers = 'getHeaders' in formData
28349
28708
  ? formData.getHeaders()
28350
28709
  : { 'content-type': 'multipart/form-data' };
28351
- const { data } = await client.http.post('/api/v4/files', formData, {
28710
+ const { data } = await client.upload.post('/api/v4/files', formData, {
28352
28711
  headers,
28353
28712
  onUploadProgress({ loaded, total = 100 }) {
28354
28713
  onProgress && onProgress(Math.round((loaded * 100) / total));
@@ -28438,7 +28797,7 @@ const uploadVideo = async (formData, feedType, onProgress) => {
28438
28797
  const headers = 'getHeaders' in formData
28439
28798
  ? formData.getHeaders()
28440
28799
  : { 'content-type': 'multipart/form-data' };
28441
- const { data } = await client.http.post('/api/v4/videos', formData, {
28800
+ const { data } = await client.upload.post('/api/v4/videos', formData, {
28442
28801
  headers,
28443
28802
  onUploadProgress({ loaded, total = 100 }) {
28444
28803
  onProgress && onProgress(Math.round((loaded * 100) / total));
@@ -28486,7 +28845,7 @@ const uploadImage = async (formData, onProgress) => {
28486
28845
  const headers = 'getHeaders' in formData
28487
28846
  ? formData.getHeaders()
28488
28847
  : { 'content-type': 'multipart/form-data' };
28489
- const { data } = await client.http.post('/api/v4/images', formData, {
28848
+ const { data } = await client.upload.post('/api/v4/images', formData, {
28490
28849
  headers,
28491
28850
  onUploadProgress({ loaded, total = 100 }) {
28492
28851
  onProgress && onProgress(Math.round((loaded * 100) / total));
@@ -29571,6 +29930,29 @@ const createCommentEventSubscriber = (event, callback) => {
29571
29930
  }
29572
29931
  }
29573
29932
  }
29933
+ }
29934
+ if (['comment.deleted'].includes(event)) {
29935
+ // NOTE: skip deleting comment to parent comment children if it's the same user since we use the local event to update instead.
29936
+ if (event === 'comment.deleted' && comment.data.userId === client.userId)
29937
+ return;
29938
+ if (comments[0].parentId) {
29939
+ const parentComment = pullFromCache([
29940
+ 'comment',
29941
+ 'get',
29942
+ comments[0].parentId,
29943
+ ]);
29944
+ if (parentComment === null || parentComment === void 0 ? void 0 : parentComment.data) {
29945
+ // Remove deleted comment in parent childComment if still exists
29946
+ if (parentComment.data.children.includes(comments[0].commentId)) {
29947
+ const newParentComment = Object.assign(Object.assign({}, parentComment.data), { childrenNumber: parentComment.data.childrenNumber - 1, children: [
29948
+ ...new Set([
29949
+ ...parentComment.data.children.filter(id => id !== comments[0].commentId),
29950
+ ]),
29951
+ ] });
29952
+ pushToCache(['comment', 'get', comments[0].parentId], newParentComment);
29953
+ }
29954
+ }
29955
+ }
29574
29956
  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; });
29575
29957
  queries === null || queries === void 0 ? void 0 : queries.map(({ key, data }) => upsertInCache(key, data, { cachedAt: -1 }));
29576
29958
  }
@@ -29583,7 +29965,7 @@ const createCommentEventSubscriber = (event, callback) => {
29583
29965
  const createLocalCommentEventSubscriber = (event, callback) => {
29584
29966
  const client = getActiveClient();
29585
29967
  const filter = (payload) => {
29586
- var _a;
29968
+ var _a, _b;
29587
29969
  if (!client.cache) {
29588
29970
  // TODO: here we are missing specific properties here!
29589
29971
  callback(LinkedObject.comment(payload.comments[0]));
@@ -29626,6 +30008,38 @@ const createLocalCommentEventSubscriber = (event, callback) => {
29626
30008
  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; });
29627
30009
  queries === null || queries === void 0 ? void 0 : queries.map(({ key, data }) => upsertInCache(key, data, { cachedAt: -1 }));
29628
30010
  }
30011
+ if (['local.comment.deleted'].includes(event)) {
30012
+ if (comments[0].parentId) {
30013
+ const parentComment = pullFromCache([
30014
+ 'comment',
30015
+ 'get',
30016
+ comments[0].parentId,
30017
+ ]);
30018
+ if (parentComment === null || parentComment === void 0 ? void 0 : parentComment.data) {
30019
+ // Remove deleted comment in parent childComment if still exists
30020
+ if (parentComment.data.children.includes(comments[0].commentId)) {
30021
+ const newParentComment = Object.assign(Object.assign({}, parentComment.data), { childrenNumber: parentComment.data.childrenNumber - 1, children: [
30022
+ ...new Set([
30023
+ ...parentComment.data.children.filter(id => id !== comments[0].commentId),
30024
+ ]),
30025
+ ] });
30026
+ pushToCache(['comment', 'get', comments[0].parentId], newParentComment);
30027
+ setTimeout(() => {
30028
+ // NOTE: This is workaround solution for emitting event not work properly.
30029
+ fireEvent('comment.updated', {
30030
+ comments: [newParentComment],
30031
+ commentChildren: [],
30032
+ files: [],
30033
+ users: [],
30034
+ communityUsers: [],
30035
+ });
30036
+ }, 200);
30037
+ }
30038
+ }
30039
+ }
30040
+ 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; });
30041
+ queries === null || queries === void 0 ? void 0 : queries.map(({ key, data }) => upsertInCache(key, data, { cachedAt: -1 }));
30042
+ }
29629
30043
  callback(LinkedObject.comment(comment.data));
29630
30044
  }
29631
30045
  }
@@ -32679,19 +33093,37 @@ var index$f = /*#__PURE__*/Object.freeze({
32679
33093
  /**
32680
33094
  * Internal used only
32681
33095
  *
32682
- * Fired when an {@link Amity.userMessageFeedMarkers} has been resolved by Object Rsesolver
33096
+ * Fired when an {@link Amity.channelUnreadInfo} has been updated.
32683
33097
  *
32684
33098
  * @param callback The function to call when the event was fired
32685
33099
  * @returns an {@link Amity.Unsubscriber} function to stop listening
32686
33100
  *
32687
- * @category MessageMarker Events
33101
+ * @category ChannelMarker Events
33102
+ */
33103
+ const onChannelUnreadInfoUpdatedLocal = (callback) => {
33104
+ const client = getActiveClient();
33105
+ const filter = (payload) => {
33106
+ callback(payload);
33107
+ };
33108
+ return createEventSubscriber(client, 'channelMarker/onChannelUnreadInfoUpdatedLocal', 'local.channelUnreadInfo.updated', filter);
33109
+ };
33110
+
33111
+ /**
33112
+ * Internal used only
33113
+ *
33114
+ * Fired when an {@link Amity.ChannelUnread} has been updated.
33115
+ *
33116
+ * @param callback The function to call when the event was fired
33117
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
33118
+ *
33119
+ * @category Channel Events
32688
33120
  */
32689
33121
  const onChannelUnreadUpdatedLocal = (callback) => {
32690
33122
  const client = getActiveClient();
32691
33123
  const filter = (payload) => {
32692
33124
  callback(payload);
32693
33125
  };
32694
- return createEventSubscriber(client, 'channelMarker/onChannelUnreadUpdatedLocal', 'local.channelUnread.updated', filter);
33126
+ return createEventSubscriber(client, 'channel/onChannelUnreadUpdatedLocal', 'local.channelUnread.updated', filter);
32695
33127
  };
32696
33128
 
32697
33129
  /* begin_public_function
@@ -32893,6 +33325,7 @@ const getChannel = (channelId, callback) => {
32893
33325
  return onSubChannelUpdated(updateMessagePreview);
32894
33326
  }, 'channelId', 'channel'),
32895
33327
  convertEventPayload(onSubChannelCreated, 'channelId', 'channel'),
33328
+ convertEventPayload(onChannelUnreadInfoUpdatedLocal, 'channelId', 'channel'),
32896
33329
  convertEventPayload(onChannelUnreadUpdatedLocal, 'channelId', 'channel'),
32897
33330
  ], {
32898
33331
  forceDispatch: true,
@@ -33406,6 +33839,10 @@ class ChannelLiveCollectionController extends LiveCollectionController {
33406
33839
  },
33407
33840
  action: "OnResolveUnread" /* Amity.ChannelActionType.OnResolveUnread */,
33408
33841
  },
33842
+ {
33843
+ fn: convertEventPayload(onChannelUnreadInfoUpdatedLocal, 'channelId', 'channel'),
33844
+ action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
33845
+ },
33409
33846
  {
33410
33847
  fn: convertEventPayload(onChannelUnreadUpdatedLocal, 'channelId', 'channel'),
33411
33848
  action: "onUpdate" /* Amity.ChannelActionType.OnUpdate */,
@@ -33471,6 +33908,120 @@ const getChannels = (params, callback, config) => {
33471
33908
  };
33472
33909
  /* end_public_function */
33473
33910
 
33911
+ /**
33912
+ *
33913
+ * Calculate user unread from {@link Amity.ChannelUnread} objects
33914
+ *
33915
+ * @returns the {@link Amity.UserUnread} objects
33916
+ *
33917
+ * @category Channel API
33918
+ * @async
33919
+ */
33920
+ const getTotalChannelsUnread$1 = () => {
33921
+ var _a;
33922
+ const client = getActiveClient();
33923
+ client.log('channel/getTotalChannelsUnread.locally');
33924
+ const cachedChannelsUnread = ((_a = queryCache(['channelUnread', 'get'])) === null || _a === void 0 ? void 0 : _a.filter(({ data }) => {
33925
+ return !data.isDeleted;
33926
+ })) || [];
33927
+ const totalChannelsUnread = (cachedChannelsUnread === null || cachedChannelsUnread === void 0 ? void 0 : cachedChannelsUnread.reduce((acc, { data }) => {
33928
+ acc.unreadCount += data.unreadCount;
33929
+ acc.isMentioned = acc.isMentioned || data.isMentioned;
33930
+ return acc;
33931
+ }, { unreadCount: 0, isMentioned: false })) || { unreadCount: 0, isMentioned: false };
33932
+ const cachedAt = client.cache && Date.now();
33933
+ return {
33934
+ data: totalChannelsUnread,
33935
+ cachedAt,
33936
+ };
33937
+ };
33938
+
33939
+ /* begin_public_function
33940
+ id: totalChannelsUnread.get
33941
+ */
33942
+ /**
33943
+ * ```js
33944
+ * import { ChannelRepository } from '@amityco/ts-sdk';
33945
+ *
33946
+ * let totalChannelsUnread;
33947
+ *
33948
+ * const unsubscribe = ChannelRepository.getTotalChannelsUnread(response => {
33949
+ * unread = response.data;
33950
+ * });
33951
+ * ```
33952
+ *
33953
+ * Observe all mutation on a given {@link Amity.UserUnread}
33954
+ *
33955
+ * @returns An {@link Amity.UserUnread} function to run when willing to stop observing the message
33956
+ *
33957
+ * @category User Unread Live Object
33958
+ *
33959
+ */
33960
+ const getTotalChannelsUnread = (callback) => {
33961
+ const { _id: userId } = getActiveUser();
33962
+ if (!userId)
33963
+ throw new ASCError('The _id has not been defined in ActiveUser', 800000 /* Amity.ClientError.UNKNOWN_ERROR */, "error" /* Amity.ErrorLevel.ERROR */);
33964
+ const { log, cache } = getActiveClient();
33965
+ if (!cache) {
33966
+ console.log('For using Live Object feature you need to enable Cache!');
33967
+ }
33968
+ const timestamp = Date.now();
33969
+ log(`liveTotalChannelsUnread(tmpid: ${timestamp}) > listen`);
33970
+ const disposers = [];
33971
+ let isUnsyncedModel = false; // for messages
33972
+ let model;
33973
+ const dispatcher = (data) => {
33974
+ const { data: userUnread } = data;
33975
+ const callbackModel = userUnread
33976
+ ? {
33977
+ unreadCount: userUnread.unreadCount,
33978
+ isMentioned: userUnread.isMentioned,
33979
+ }
33980
+ : undefined;
33981
+ model = callbackModel ? convertGetterPropsToStatic(callbackModel) : callbackModel;
33982
+ callback({
33983
+ data: callbackModel
33984
+ ? Object.assign(Object.assign({}, callbackModel), { isMentioned: callbackModel.isMentioned }) : callbackModel,
33985
+ loading: data.loading,
33986
+ error: data.error,
33987
+ });
33988
+ };
33989
+ const realtimeRouter = (userUnread) => {
33990
+ if (isEqual(model, userUnread))
33991
+ return;
33992
+ dispatcher({
33993
+ loading: false,
33994
+ data: userUnread,
33995
+ });
33996
+ };
33997
+ const onFetch = () => {
33998
+ const query = createQuery(async () => getTotalChannelsUnread$1());
33999
+ runQuery(query, ({ error, data, loading, origin, cachedAt }) => {
34000
+ if (cachedAt === UNSYNCED_OBJECT_CACHED_AT_VALUE) {
34001
+ dispatcher({
34002
+ data,
34003
+ origin,
34004
+ loading: false,
34005
+ error: new ASCApiError(UNSYNCED_OBJECT_CACHED_AT_MESSAGE, 800800 /* Amity.ClientError.DISALOOW_UNSYNCED_OBJECT */, "error" /* Amity.ErrorLevel.ERROR */),
34006
+ });
34007
+ isUnsyncedModel = true;
34008
+ disposers.forEach(fn => fn());
34009
+ }
34010
+ else if (!isUnsyncedModel) {
34011
+ dispatcher({ loading, data, origin, error });
34012
+ }
34013
+ if (error) {
34014
+ disposers.forEach(fn => fn());
34015
+ }
34016
+ });
34017
+ };
34018
+ disposers.push(onChannelUnreadUpdatedLocal(realtimeRouter));
34019
+ onFetch();
34020
+ return () => {
34021
+ disposers.forEach(fn => fn());
34022
+ };
34023
+ };
34024
+
33474
34025
  /* begin_public_function
33475
34026
  id: channel.member.add
33476
34027
  */
@@ -34074,6 +34625,7 @@ var index$c = /*#__PURE__*/Object.freeze({
34074
34625
  onChannelMemberRoleRemoved: onChannelMemberRoleRemoved,
34075
34626
  getChannel: getChannel,
34076
34627
  getChannels: getChannels,
34628
+ getTotalChannelsUnread: getTotalChannelsUnread,
34077
34629
  MARKER_INCLUDED_CHANNEL_TYPE: MARKER_INCLUDED_CHANNEL_TYPE,
34078
34630
  isUnreadCountSupport: isUnreadCountSupport,
34079
34631
  convertFromRaw: convertFromRaw,