@amityco/ts-sdk 7.1.1-1d526d8.0 → 7.1.1-c8d4edca.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) 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 +9 -0
  8. package/dist/@types/domains/channel.d.ts.map +1 -1
  9. package/dist/@types/domains/client.d.ts +1 -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/onChannelUnreadUpdatedLocal.d.ts +12 -0
  14. package/dist/channelRepository/events/onChannelUnreadUpdatedLocal.d.ts.map +1 -0
  15. package/dist/channelRepository/observers/getChannel.d.ts.map +1 -1
  16. package/dist/channelRepository/observers/getChannels/ChannelLiveCollectionController.d.ts.map +1 -1
  17. package/dist/channelRepository/utils/constructChannelDynamicValue.d.ts.map +1 -1
  18. package/dist/channelRepository/utils/getLegacyChannelUnread.d.ts +2 -0
  19. package/dist/channelRepository/utils/getLegacyChannelUnread.d.ts.map +1 -0
  20. package/dist/channelRepository/utils/prepareChannelPayload.d.ts.map +1 -1
  21. package/dist/client/api/createClient.d.ts.map +1 -1
  22. package/dist/client/api/enableUnreadCount.d.ts.map +1 -1
  23. package/dist/client/api/login.d.ts.map +1 -1
  24. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.d.ts +33 -0
  25. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.d.ts.map +1 -0
  26. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.d.ts +3 -0
  27. package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.d.ts.map +1 -0
  28. package/dist/client/utils/ReadReceiptSync/readReceiptSyncEngine.d.ts +2 -4
  29. package/dist/client/utils/ReadReceiptSync/readReceiptSyncEngine.d.ts.map +1 -1
  30. package/dist/core/events.d.ts +3 -3
  31. package/dist/core/events.d.ts.map +1 -1
  32. package/dist/core/model/idResolvers.d.ts.map +1 -1
  33. package/dist/index.cjs.js +360 -40
  34. package/dist/index.esm.js +360 -40
  35. package/dist/index.umd.js +4 -4
  36. package/dist/marker/events/onChannelUnreadInfoUpdatedLocal.d.ts +12 -0
  37. package/dist/marker/events/onChannelUnreadInfoUpdatedLocal.d.ts.map +1 -0
  38. package/dist/messageRepository/utils/markReadMessage.d.ts.map +1 -1
  39. package/package.json +1 -1
  40. package/src/@types/core/events.ts +2 -1
  41. package/src/@types/core/model.ts +4 -0
  42. package/src/@types/core/readReceipt.ts +14 -1
  43. package/src/@types/domains/channel.ts +11 -0
  44. package/src/@types/domains/client.ts +2 -0
  45. package/src/channelRepository/api/markChannelsAsReadBySegment.ts +29 -0
  46. package/src/channelRepository/events/onChannelUnreadUpdatedLocal.ts +29 -0
  47. package/src/channelRepository/observers/getChannel.ts +3 -1
  48. package/src/channelRepository/observers/getChannels/ChannelLiveCollectionController.ts +6 -1
  49. package/src/channelRepository/utils/constructChannelDynamicValue.ts +12 -2
  50. package/src/channelRepository/utils/getLegacyChannelUnread.ts +5 -0
  51. package/src/channelRepository/utils/prepareChannelPayload.ts +57 -17
  52. package/src/client/api/createClient.ts +3 -0
  53. package/src/client/api/enableUnreadCount.ts +1 -0
  54. package/src/client/api/login.ts +5 -1
  55. package/src/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.ts +267 -0
  56. package/src/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.ts +21 -0
  57. package/src/client/utils/ReadReceiptSync/readReceiptSyncEngine.ts +72 -98
  58. package/src/core/model/idResolvers.ts +2 -0
  59. package/src/marker/events/onChannelUnreadInfoUpdatedLocal.ts +29 -0
  60. package/src/marker/events/onChannelUnreadUpdatedLocal.ts +1 -1
  61. package/src/messageRepository/utils/markReadMessage.ts +10 -3
@@ -0,0 +1,21 @@
1
+ import { onSessionStateChange } from '~/client/events/onSessionStateChange';
2
+ import LegacyReadReceiptSyncEngine from '~/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine';
3
+
4
+ export default () => {
5
+ const readReceiptSyncEngine = LegacyReadReceiptSyncEngine.getInstance();
6
+ readReceiptSyncEngine.startSyncReadReceipt();
7
+
8
+ onSessionStateChange(state => {
9
+ if (state === Amity.SessionStates.ESTABLISHED) {
10
+ readReceiptSyncEngine.onSessionEstablished();
11
+ } else if (state === Amity.SessionStates.TOKEN_EXPIRED) {
12
+ readReceiptSyncEngine.onTokenExpired();
13
+ } else {
14
+ readReceiptSyncEngine.onSessionDestroyed();
15
+ }
16
+ });
17
+
18
+ return () => {
19
+ readReceiptSyncEngine.onSessionDestroyed();
20
+ };
21
+ };
@@ -1,8 +1,7 @@
1
1
  import { pullFromCache, pushToCache, queryCache } from '~/cache/api';
2
2
  import { getActiveClient } from '../../api/activeClient';
3
- import { markAsReadBySegment } from '~/subChannelRepository/api/markAsReadBySegment';
4
- import { reCalculateChannelUnreadInfo } from '~/marker/utils/reCalculateChannelUnreadInfo';
5
3
  import { fireEvent } from '~/core/events';
4
+ import { markChannelsAsReadBySegment } from '~/channelRepository/api/markChannelsAsReadBySegment';
6
5
 
7
6
  export class MessageReadReceiptSyncEngine {
8
7
  private client: Amity.Client;
@@ -38,9 +37,10 @@ export class MessageReadReceiptSyncEngine {
38
37
  syncReadReceipts(): void {
39
38
  if (this.jobQueue.length === 0 || this.isActive === false) return;
40
39
 
41
- const readReceipt = this.getReadReceipt();
42
- if (readReceipt) {
43
- this.markReadApi(readReceipt);
40
+ const readReceipts = this.getReadReceipts();
41
+ console.log('[New 🌟 readReceipts] Sync read receipts', readReceipts);
42
+ if (readReceipts) {
43
+ this.markReadApi(readReceipts);
44
44
  }
45
45
  }
46
46
 
@@ -52,79 +52,64 @@ export class MessageReadReceiptSyncEngine {
52
52
 
53
53
  // Enqueue unsync read receipts to the job queue
54
54
  readReceipts?.forEach(({ data: readReceipt }) => {
55
- this.enqueueReadReceipt(readReceipt.subChannelId, readReceipt.latestSegment);
55
+ this.enqueueReadReceipt(readReceipt.channelId, readReceipt.latestSegment);
56
56
  });
57
57
  }
58
58
 
59
- private getReadReceipt(): Amity.ReadReceiptSyncJob | undefined {
60
- // Get first read receipt in queue
61
- const syncJob = this.jobQueue[0];
59
+ private getReadReceipts(): Amity.ReadReceiptSyncJob[] | undefined {
60
+ // get all read receipts from queue, now the queue is empty
61
+ const syncJob = this.jobQueue.splice(0, this.jobQueue.length);
62
+ if (syncJob.length === 0) return;
62
63
 
63
- if (!syncJob) return;
64
- // Skip when it's syncing
65
- if (syncJob.syncState === Amity.ReadReceiptSyncState.SYNCING) return;
66
-
67
- // Get readReceipt from cache by subChannelId
68
- const readReceipt = pullFromCache<Amity.ReadReceipt>([
69
- 'readReceipt',
70
- syncJob.subChannelId,
71
- ])?.data;
72
-
73
- if (!readReceipt) return;
74
-
75
- if (readReceipt?.latestSegment > readReceipt?.latestSyncSegment) {
76
- syncJob.segment = readReceipt.latestSegment;
77
- return syncJob;
78
- }
79
- // Clear all synced job in job queue
80
- this.removeSynedReceipt(readReceipt.subChannelId, readReceipt.latestSegment);
81
-
82
- // Recursion getReadReceipt() until get unsync read receipt or job queue is empty
83
- return this.getReadReceipt();
64
+ return syncJob.filter(job => {
65
+ const readReceipt = pullFromCache<Amity.ReadReceipt>(['readReceipt', job.channelId])?.data;
66
+ if (!readReceipt) return false;
67
+ if (readReceipt.latestSegment > readReceipt.latestSyncSegment) return true;
68
+ return false;
69
+ });
84
70
  }
85
71
 
86
- private async markReadApi(syncJob: Amity.ReadReceiptSyncJob): Promise<void> {
87
- const newSyncJob = syncJob;
88
- newSyncJob.syncState = Amity.ReadReceiptSyncState.SYNCING;
89
-
90
- const { subChannelId, segment } = newSyncJob;
72
+ private async markReadApi(syncJobs: Amity.ReadReceiptSyncJob[]): Promise<void> {
73
+ // constuct payload
74
+ // example: [{ channelId: 'channelId', readToSegment: 2 }]
75
+ const syncJobsPayload = syncJobs.map(job => {
76
+ return {
77
+ channelId: job.channelId,
78
+ readToSegment: job.segment,
79
+ };
80
+ });
91
81
 
92
- const response = await markAsReadBySegment({ subChannelId, readToSegment: segment });
82
+ const response = await markChannelsAsReadBySegment(syncJobsPayload);
93
83
 
94
84
  if (response) {
95
- this.removeSynedReceipt(syncJob.subChannelId, syncJob.segment);
96
-
97
- const readReceiptCache = pullFromCache<Amity.ReadReceipt>([
98
- 'readReceipt',
99
- subChannelId,
100
- ])?.data;
101
-
102
- pushToCache(['readReceipt', subChannelId], {
103
- ...readReceiptCache,
104
- latestSyncSegment: segment,
105
- });
106
- } else if (!response) {
107
- if (newSyncJob.retryCount > this.MAX_RETRY) {
108
- this.removeJobFromQueue(newSyncJob);
109
- } else {
110
- newSyncJob.retryCount += 1;
111
- newSyncJob.syncState = Amity.ReadReceiptSyncState.CREATED;
85
+ for (let i = 0; i < syncJobs.length; i += 1) {
86
+ // update lastestSyncSegment in read receipt cache
87
+ const cacheKey = ['readReceipt', syncJobs[i].channelId];
88
+ const readReceiptCache = pullFromCache<Amity.ReadReceipt>(cacheKey)?.data;
89
+
90
+ pushToCache(cacheKey, {
91
+ ...readReceiptCache,
92
+ latestSyncSegment: syncJobs[i].segment,
93
+ });
112
94
  }
113
- }
114
- }
95
+ } else {
96
+ for (let i = 0; i < syncJobs.length; i += 1) {
97
+ // push them back to queue if the syncing is failed and retry count is less than max retry
98
+ if (syncJobs[i].retryCount >= this.MAX_RETRY) return;
115
99
 
116
- private removeSynedReceipt(subChannelId: string, segment: number) {
117
- const syncJobs = this.jobQueue;
100
+ const updatedJob = {
101
+ ...syncJobs[i],
102
+ syncState: Amity.ReadReceiptSyncState.CREATED,
103
+ retryCount: syncJobs[i].retryCount + 1,
104
+ };
118
105
 
119
- syncJobs.forEach(job => {
120
- if (job.subChannelId === subChannelId && job.segment <= segment) {
121
- this.removeJobFromQueue(job);
106
+ this.enqueueJob(updatedJob);
122
107
  }
123
- });
108
+ }
124
109
  }
125
110
 
126
111
  private startObservingReadReceiptQueue(): void {
127
- if (this.client.isUnreadCountEnabled) {
112
+ if (this.client.useLegacyUnreadCount) {
128
113
  this.isActive = true;
129
114
  this.startSyncReadReceipt();
130
115
  }
@@ -133,8 +118,7 @@ export class MessageReadReceiptSyncEngine {
133
118
  private stopObservingReadReceiptQueue(): void {
134
119
  this.isActive = false;
135
120
 
136
- const syncJobs = this.jobQueue;
137
- syncJobs.map(job => {
121
+ this.jobQueue.map(job => {
138
122
  if (job.syncState === Amity.ReadReceiptSyncState.SYNCING) {
139
123
  return { ...job, syncState: Amity.ReadReceiptSyncState.CREATED };
140
124
  }
@@ -170,50 +154,49 @@ export class MessageReadReceiptSyncEngine {
170
154
  this.startObservingReadReceiptQueue();
171
155
  }
172
156
 
173
- markRead(subChannelId: string, segment: number): void {
174
- // Step 1: Optimistic update of subChannelUnreadInfo.readToSegment to message.segment
175
- const cacheKey = ['subChannelUnreadInfo', 'get', subChannelId];
176
- const subChannelUnreadInfo = pullFromCache<Amity.SubChannelUnreadInfo>(cacheKey)?.data;
157
+ markRead(channelId: string, segment: number): void {
158
+ // Step 1: Optimistic update of channelUnread.readToSegment to message.segment and update unreadCount value
159
+ const cacheKey = ['channelUnread', 'get', channelId];
160
+ const channelUnread = pullFromCache<Amity.ChannelUnread>(cacheKey)?.data;
177
161
 
178
- if (subChannelUnreadInfo && segment > subChannelUnreadInfo.readToSegment) {
179
- subChannelUnreadInfo.readToSegment = segment;
180
- subChannelUnreadInfo.unreadCount = Math.max(subChannelUnreadInfo.lastSegment - segment, 0);
162
+ console.log('[New 🌟] Mark read => channel unread', channelUnread);
181
163
 
182
- const channelUnreadInfo = reCalculateChannelUnreadInfo(subChannelUnreadInfo.channelId);
183
- fireEvent('local.channelUnread.updated', channelUnreadInfo);
164
+ if (channelUnread && segment > channelUnread.readToSegment) {
165
+ channelUnread.readToSegment = segment;
166
+ channelUnread.unreadCount = Math.max(channelUnread.lastSegment - segment, 0);
184
167
 
185
- pushToCache(cacheKey, subChannelUnreadInfo);
186
- fireEvent('local.subChannelUnread.updated', subChannelUnreadInfo);
168
+ pushToCache(cacheKey, channelUnread);
169
+ fireEvent('local.channelUnread.updated', channelUnread);
187
170
  }
188
171
 
189
172
  // Step 2: Enqueue the read receipt
190
- this.enqueueReadReceipt(subChannelId, segment);
173
+ this.enqueueReadReceipt(channelId, segment);
191
174
  }
192
175
 
193
- private enqueueReadReceipt(subChannelId: string, segment: number): void {
194
- const readReceipt = pullFromCache<Amity.ReadReceipt>(['readReceipt', subChannelId])?.data;
176
+ private enqueueReadReceipt(channelId: string, segment: number): void {
177
+ const readReceipt = pullFromCache<Amity.ReadReceipt>(['readReceipt', channelId])?.data;
195
178
 
196
- // Create new read receipt if it's not exists and add job to queue
179
+ // Create new read receipt if it's not exists and add the job to queue
197
180
  if (!readReceipt) {
198
- const readReceiptSubChannel: Amity.ReadReceipt = {
199
- subChannelId,
181
+ const readReceiptChannel: Amity.ReadReceipt = {
182
+ channelId,
200
183
  latestSegment: segment,
201
184
  latestSyncSegment: 0,
202
185
  };
203
-
204
- pushToCache(['readReceipt', subChannelId], readReceiptSubChannel);
186
+ pushToCache(['readReceipt', channelId], readReceiptChannel);
205
187
  } else if (readReceipt.latestSegment < segment) {
206
- pushToCache(['readReceipt', subChannelId], { ...readReceipt, latestSegment: segment });
188
+ // Update latestSegment in read receipt cache
189
+ pushToCache(['readReceipt', channelId], { ...readReceipt, latestSegment: segment });
207
190
  } else if (readReceipt.latestSyncSegment >= segment) {
208
191
  // Skip the job when lastSyncSegment > = segment
209
192
  return;
210
193
  }
211
194
 
212
- let syncJob: Amity.ReadReceiptSyncJob | null = this.getSyncJob(subChannelId);
195
+ let syncJob: Amity.ReadReceiptSyncJob | null = this.getSyncJob(channelId);
213
196
 
214
197
  if (syncJob === null || syncJob.syncState === Amity.ReadReceiptSyncState.SYNCING) {
215
198
  syncJob = {
216
- subChannelId,
199
+ channelId,
217
200
  segment,
218
201
  syncState: Amity.ReadReceiptSyncState.CREATED,
219
202
  retryCount: 0,
@@ -225,11 +208,9 @@ export class MessageReadReceiptSyncEngine {
225
208
  }
226
209
  }
227
210
 
228
- private getSyncJob(subChannelId: string): Amity.ReadReceiptSyncJob | null {
229
- const syncJobs = this.jobQueue;
230
-
231
- const targetJob = syncJobs.find(job => job.subChannelId === subChannelId);
232
-
211
+ private getSyncJob(channelId: string): Amity.ReadReceiptSyncJob | null {
212
+ const { jobQueue } = this;
213
+ const targetJob = jobQueue.find(job => job.channelId === channelId);
233
214
  return targetJob || null;
234
215
  }
235
216
 
@@ -242,13 +223,6 @@ export class MessageReadReceiptSyncEngine {
242
223
  this.jobQueue.push(syncJob);
243
224
  }
244
225
  }
245
-
246
- private removeJobFromQueue(item: Amity.ReadReceiptSyncJob) {
247
- const index = this.jobQueue.indexOf(item);
248
- if (index > -1) {
249
- this.jobQueue.splice(index, 1);
250
- }
251
- }
252
226
  }
253
227
 
254
228
  let instance: MessageReadReceiptSyncEngine | null = null;
@@ -26,6 +26,8 @@ const idResolvers: Resolvers = {
26
26
  channelUnreadInfo: ({ channelId }) => channelId,
27
27
  subChannelUnreadInfo: ({ subChannelId }) => subChannelId,
28
28
 
29
+ channelUnread: ({ channelId }) => channelId,
30
+
29
31
  channelMarker: ({ entityId, userId }) => `${entityId}#${userId}`,
30
32
  subChannelMarker: ({ entityId, feedId, userId }) => `${entityId}#${feedId}#${userId}`,
31
33
  messageMarker: ({ feedId, contentId, creatorId }) => `${feedId}#${contentId}#${creatorId}`,
@@ -0,0 +1,29 @@
1
+ import { getActiveClient } from '~/client/api/activeClient';
2
+ import { createEventSubscriber } from '~/core/events';
3
+
4
+ /**
5
+ * Internal used only
6
+ *
7
+ * Fired when an {@link Amity.userMessageFeedMarkers} has been resolved by Object Rsesolver
8
+ *
9
+ * @param callback The function to call when the event was fired
10
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
11
+ *
12
+ * @category MessageMarker Events
13
+ */
14
+ export const onChannelUnreadInfoUpdatedLocal = (
15
+ callback: Amity.Listener<Amity.Events['local.channelUnreadInfo.updated']>,
16
+ ): Amity.Unsubscriber => {
17
+ const client = getActiveClient();
18
+
19
+ const filter = (payload: Amity.Events['local.channelUnreadInfo.updated']) => {
20
+ callback(payload);
21
+ };
22
+
23
+ return createEventSubscriber(
24
+ client,
25
+ 'channelMarker/onChannelUnreadInfoUpdatedLocal',
26
+ 'local.channelUnreadInfo.updated',
27
+ filter,
28
+ );
29
+ };
@@ -22,7 +22,7 @@ export const onChannelUnreadUpdatedLocal = (
22
22
 
23
23
  return createEventSubscriber(
24
24
  client,
25
- 'channelMarker/onChannelUnreadUpdatedLocal',
25
+ 'channel/onChannelUnreadUpdatedLocal',
26
26
  'local.channelUnread.updated',
27
27
  filter,
28
28
  );
@@ -1,8 +1,15 @@
1
+ import { getActiveClient } from '~/client/api/activeClient';
1
2
  import ReadReceiptSyncEngine from '~/client/utils/ReadReceiptSync/readReceiptSyncEngine';
3
+ import LegacyReadReceiptSyncEngine from '~/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine';
2
4
 
3
5
  export const markReadMessage = (message: Amity.InternalMessage) => {
4
- const { subChannelId, channelSegment } = message;
5
- const markReadReceiptEngine = ReadReceiptSyncEngine.getInstance();
6
+ const client = getActiveClient();
6
7
 
7
- markReadReceiptEngine.markRead(subChannelId, channelSegment);
8
+ if (client.useLegacyUnreadCount) {
9
+ const markReadReceiptEngine = ReadReceiptSyncEngine.getInstance();
10
+ markReadReceiptEngine.markRead(message.channelId, message.channelSegment);
11
+ } else {
12
+ const markReadReceiptEngine = LegacyReadReceiptSyncEngine.getInstance();
13
+ markReadReceiptEngine.markRead(message.subChannelId, message.channelSegment);
14
+ }
8
15
  };