@amityco/ts-sdk 7.1.0 → 7.1.1-c8d4edca.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env +26 -26
- package/dist/@types/core/events.d.ts +2 -1
- package/dist/@types/core/events.d.ts.map +1 -1
- package/dist/@types/core/model.d.ts +2 -0
- package/dist/@types/core/model.d.ts.map +1 -1
- package/dist/@types/core/readReceipt.d.ts +12 -1
- package/dist/@types/core/readReceipt.d.ts.map +1 -1
- package/dist/@types/domains/channel.d.ts +9 -0
- package/dist/@types/domains/channel.d.ts.map +1 -1
- package/dist/@types/domains/client.d.ts +1 -0
- package/dist/@types/domains/client.d.ts.map +1 -1
- package/dist/channelRepository/api/markChannelsAsReadBySegment.d.ts +16 -0
- package/dist/channelRepository/api/markChannelsAsReadBySegment.d.ts.map +1 -0
- package/dist/channelRepository/events/onChannelUnreadUpdatedLocal.d.ts +12 -0
- package/dist/channelRepository/events/onChannelUnreadUpdatedLocal.d.ts.map +1 -0
- package/dist/channelRepository/observers/getChannel.d.ts.map +1 -1
- package/dist/channelRepository/observers/getChannels/ChannelLiveCollectionController.d.ts.map +1 -1
- package/dist/channelRepository/utils/constructChannelDynamicValue.d.ts.map +1 -1
- package/dist/channelRepository/utils/getLegacyChannelUnread.d.ts +2 -0
- package/dist/channelRepository/utils/getLegacyChannelUnread.d.ts.map +1 -0
- package/dist/channelRepository/utils/prepareChannelPayload.d.ts.map +1 -1
- package/dist/client/api/createClient.d.ts.map +1 -1
- package/dist/client/api/enableUnreadCount.d.ts.map +1 -1
- package/dist/client/api/login.d.ts.map +1 -1
- package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.d.ts +33 -0
- package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.d.ts.map +1 -0
- package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.d.ts +3 -0
- package/dist/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.d.ts.map +1 -0
- package/dist/client/utils/ReadReceiptSync/readReceiptSyncEngine.d.ts +2 -4
- package/dist/client/utils/ReadReceiptSync/readReceiptSyncEngine.d.ts.map +1 -1
- package/dist/core/events.d.ts +3 -3
- package/dist/core/events.d.ts.map +1 -1
- package/dist/core/model/idResolvers.d.ts.map +1 -1
- package/dist/index.cjs.js +361 -41
- package/dist/index.esm.js +361 -41
- package/dist/index.umd.js +4 -4
- package/dist/marker/events/onChannelUnreadInfoUpdatedLocal.d.ts +12 -0
- package/dist/marker/events/onChannelUnreadInfoUpdatedLocal.d.ts.map +1 -0
- package/dist/messageRepository/utils/markReadMessage.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/@types/core/events.ts +2 -1
- package/src/@types/core/model.ts +4 -0
- package/src/@types/core/readReceipt.ts +14 -1
- package/src/@types/domains/channel.ts +11 -0
- package/src/@types/domains/client.ts +2 -0
- package/src/channelRepository/api/markChannelsAsReadBySegment.ts +29 -0
- package/src/channelRepository/events/onChannelUnreadUpdatedLocal.ts +29 -0
- package/src/channelRepository/observers/getChannel.ts +3 -1
- package/src/channelRepository/observers/getChannels/ChannelLiveCollectionController.ts +6 -1
- package/src/channelRepository/utils/constructChannelDynamicValue.ts +12 -2
- package/src/channelRepository/utils/getLegacyChannelUnread.ts +5 -0
- package/src/channelRepository/utils/prepareChannelPayload.ts +57 -17
- package/src/client/api/createClient.ts +3 -0
- package/src/client/api/enableUnreadCount.ts +1 -0
- package/src/client/api/login.ts +5 -1
- package/src/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngine.ts +267 -0
- package/src/client/utils/ReadReceiptSync/legacyReadReceiptSyncEngineOnLoginHandler.ts +21 -0
- package/src/client/utils/ReadReceiptSync/readReceiptSyncEngine.ts +72 -98
- package/src/core/model/idResolvers.ts +2 -0
- package/src/marker/events/onChannelUnreadInfoUpdatedLocal.ts +29 -0
- package/src/marker/events/onChannelUnreadUpdatedLocal.ts +1 -1
- 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
|
|
42
|
-
|
|
43
|
-
|
|
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.
|
|
55
|
+
this.enqueueReadReceipt(readReceipt.channelId, readReceipt.latestSegment);
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
private
|
|
60
|
-
//
|
|
61
|
-
const syncJob = this.jobQueue
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
|
82
|
+
const response = await markChannelsAsReadBySegment(syncJobsPayload);
|
|
93
83
|
|
|
94
84
|
if (response) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
|
|
117
|
-
|
|
100
|
+
const updatedJob = {
|
|
101
|
+
...syncJobs[i],
|
|
102
|
+
syncState: Amity.ReadReceiptSyncState.CREATED,
|
|
103
|
+
retryCount: syncJobs[i].retryCount + 1,
|
|
104
|
+
};
|
|
118
105
|
|
|
119
|
-
|
|
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.
|
|
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
|
-
|
|
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(
|
|
174
|
-
// Step 1: Optimistic update of
|
|
175
|
-
const cacheKey = ['
|
|
176
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
183
|
-
|
|
164
|
+
if (channelUnread && segment > channelUnread.readToSegment) {
|
|
165
|
+
channelUnread.readToSegment = segment;
|
|
166
|
+
channelUnread.unreadCount = Math.max(channelUnread.lastSegment - segment, 0);
|
|
184
167
|
|
|
185
|
-
pushToCache(cacheKey,
|
|
186
|
-
fireEvent('local.
|
|
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(
|
|
173
|
+
this.enqueueReadReceipt(channelId, segment);
|
|
191
174
|
}
|
|
192
175
|
|
|
193
|
-
private enqueueReadReceipt(
|
|
194
|
-
const readReceipt = pullFromCache<Amity.ReadReceipt>(['readReceipt',
|
|
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
|
|
199
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
229
|
-
const
|
|
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
|
+
};
|
|
@@ -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
|
|
5
|
-
const markReadReceiptEngine = ReadReceiptSyncEngine.getInstance();
|
|
6
|
+
const client = getActiveClient();
|
|
6
7
|
|
|
7
|
-
|
|
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
|
};
|