@amityco/ts-sdk 0.0.1-beta.30 → 0.0.1-beta.31
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/dist/@types/core/cache.d.ts +3 -0
- package/dist/@types/core/cache.d.ts.map +1 -1
- package/dist/@types/core/errors.d.ts +2 -1
- package/dist/@types/core/errors.d.ts.map +1 -1
- package/dist/@types/core/events.d.ts +2 -0
- package/dist/@types/core/events.d.ts.map +1 -1
- package/dist/@types/core/live.d.ts +8 -4
- package/dist/@types/core/live.d.ts.map +1 -1
- package/dist/@types/core/query.d.ts +1 -1
- package/dist/@types/core/query.d.ts.map +1 -1
- package/dist/@types/domains/channel.d.ts +1 -0
- package/dist/@types/domains/channel.d.ts.map +1 -1
- package/dist/@types/domains/message.d.ts +13 -6
- package/dist/@types/domains/message.d.ts.map +1 -1
- package/dist/@types/domains/post.d.ts +10 -3
- package/dist/@types/domains/post.d.ts.map +1 -1
- package/dist/@types/domains/user.d.ts +1 -0
- package/dist/@types/domains/user.d.ts.map +1 -1
- package/dist/@types/index.d.ts +2 -2
- package/dist/@types/index.d.ts.map +1 -1
- package/dist/cache/api/isInTombstone.d.ts +18 -0
- package/dist/cache/api/isInTombstone.d.ts.map +1 -0
- package/dist/cache/api/pushToTombstone.d.ts +17 -0
- package/dist/cache/api/pushToTombstone.d.ts.map +1 -0
- package/dist/cache/utils/index.d.ts +17 -0
- package/dist/cache/utils/index.d.ts.map +1 -1
- package/dist/channel/api/queryChannelMembers.d.ts +1 -1
- package/dist/channel/api/queryChannelMembers.d.ts.map +1 -1
- package/dist/channel/api/queryChannels.d.ts +1 -1
- package/dist/channel/api/queryChannels.d.ts.map +1 -1
- package/dist/channel/api/tests/queryChannelMembers.test.d.ts +2 -0
- package/dist/channel/api/tests/queryChannelMembers.test.d.ts.map +1 -0
- package/dist/channel/api/tests/queryChannels.test.d.ts +2 -0
- package/dist/channel/api/tests/queryChannels.test.d.ts.map +1 -0
- package/dist/channel/events/index.d.ts +2 -0
- package/dist/channel/events/index.d.ts.map +1 -1
- package/dist/channel/events/onChannelMemberBanned.d.ts +17 -0
- package/dist/channel/events/onChannelMemberBanned.d.ts.map +1 -0
- package/dist/channel/events/onChannelMemberUnbanned.d.ts +17 -0
- package/dist/channel/events/onChannelMemberUnbanned.d.ts.map +1 -0
- package/dist/channel/events/tests/onChannelMemberBanned.test.d.ts +2 -0
- package/dist/channel/events/tests/onChannelMemberBanned.test.d.ts.map +1 -0
- package/dist/channel/events/tests/onChannelMemberUnbanned.test.d.ts +2 -0
- package/dist/channel/events/tests/onChannelMemberUnbanned.test.d.ts.map +1 -0
- package/dist/channel/observers/liveChannelMembers.d.ts.map +1 -1
- package/dist/channel/observers/liveChannels.d.ts.map +1 -1
- package/dist/channel/{tests/utils → utils/tests}/prepareChannelPayload.test.d.ts +0 -0
- package/dist/channel/utils/tests/prepareChannelPayload.test.d.ts.map +1 -0
- package/dist/core/events.d.ts +3 -3
- package/dist/core/events.d.ts.map +1 -1
- package/dist/core/query/filtering.d.ts +11 -0
- package/dist/core/query/filtering.d.ts.map +1 -1
- package/dist/core/query/query.d.ts.map +1 -1
- package/dist/index.cjs.js +963 -507
- package/dist/index.esm.js +946 -499
- package/dist/index.umd.js +4 -4
- package/dist/message/api/createMessage.d.ts +4 -1
- package/dist/message/api/createMessage.d.ts.map +1 -1
- package/dist/message/api/deleteMessage.d.ts.map +1 -1
- package/dist/message/api/getMessage.d.ts +1 -1
- package/dist/message/api/getMessage.d.ts.map +1 -1
- package/dist/message/api/getMessages.d.ts.map +1 -1
- package/dist/message/api/queryMessages.d.ts.map +1 -1
- package/dist/message/api/tests/createMessage.test.d.ts +2 -0
- package/dist/message/api/tests/createMessage.test.d.ts.map +1 -0
- package/dist/message/api/updateMessage.d.ts.map +1 -1
- package/dist/message/events/index.d.ts +1 -0
- package/dist/message/events/index.d.ts.map +1 -1
- package/dist/message/events/onMessageFetched.d.ts +17 -0
- package/dist/message/events/onMessageFetched.d.ts.map +1 -0
- package/dist/message/observers/index.d.ts +2 -1
- package/dist/message/observers/index.d.ts.map +1 -1
- package/dist/message/observers/liveMessage.d.ts +18 -0
- package/dist/message/observers/liveMessage.d.ts.map +1 -0
- package/dist/message/observers/liveMessages.d.ts.map +1 -1
- package/dist/message/observers/observeMessage.d.ts.map +1 -1
- package/dist/message/tests/api/getMessage.test.d.ts +2 -0
- package/dist/message/tests/api/getMessage.test.d.ts.map +1 -0
- package/dist/message/tests/observers/liveMessage.test.d.ts +2 -0
- package/dist/message/tests/observers/liveMessage.test.d.ts.map +1 -0
- package/dist/message/{observers/tests → tests/observers}/liveMessages.test.d.ts +0 -0
- package/dist/message/tests/observers/liveMessages.test.d.ts.map +1 -0
- package/dist/post/api/deletePost.d.ts.map +1 -1
- package/dist/post/api/getPost.d.ts.map +1 -1
- package/dist/post/api/updatePost.d.ts +6 -1
- package/dist/post/api/updatePost.d.ts.map +1 -1
- package/dist/user/api/getUser.d.ts +1 -1
- package/dist/user/api/getUser.d.ts.map +1 -1
- package/dist/user/api/getUsers.d.ts.map +1 -1
- package/dist/user/api/queryUsers.d.ts.map +1 -1
- package/dist/user/api/updateUser.d.ts.map +1 -1
- package/dist/user/events/index.d.ts +1 -0
- package/dist/user/events/index.d.ts.map +1 -1
- package/dist/user/events/onUserFetched.d.ts +17 -0
- package/dist/user/events/onUserFetched.d.ts.map +1 -0
- package/dist/user/observers/index.d.ts +1 -0
- package/dist/user/observers/index.d.ts.map +1 -1
- package/dist/user/observers/liveUser.d.ts +18 -0
- package/dist/user/observers/liveUser.d.ts.map +1 -0
- package/dist/user/observers/observeUser.d.ts.map +1 -1
- package/dist/user/tests/api/getUser.test.d.ts +2 -0
- package/dist/user/tests/api/getUser.test.d.ts.map +1 -0
- package/dist/user/tests/observers/liveUser.test.d.ts +2 -0
- package/dist/user/tests/observers/liveUser.test.d.ts.map +1 -0
- package/dist/utils/constants.d.ts +3 -0
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/tests/dummy/channel.d.ts +15 -0
- package/dist/utils/tests/dummy/channel.d.ts.map +1 -1
- package/dist/utils/tests/dummy/message.d.ts +12 -1
- package/dist/utils/tests/dummy/message.d.ts.map +1 -1
- package/dist/utils/tests/dummy/user.d.ts +10 -0
- package/dist/utils/tests/dummy/user.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/@types/core/cache.ts +4 -0
- package/src/@types/core/errors.ts +1 -0
- package/src/@types/core/events.ts +2 -0
- package/src/@types/core/live.ts +10 -4
- package/src/@types/core/query.ts +1 -1
- package/src/@types/domains/channel.ts +6 -0
- package/src/@types/domains/message.ts +13 -10
- package/src/@types/domains/post.ts +10 -3
- package/src/@types/domains/user.ts +8 -0
- package/src/@types/index.ts +2 -2
- package/src/cache/api/index.ts +2 -1
- package/src/cache/api/isInTombstone.ts +41 -0
- package/src/cache/api/pushToTombstone.ts +33 -0
- package/src/cache/utils/index.ts +22 -0
- package/src/channel/api/queryChannelMembers.ts +53 -5
- package/src/channel/api/queryChannels.ts +31 -4
- package/src/channel/api/tests/queryChannelMembers.test.ts +115 -0
- package/src/channel/api/tests/queryChannels.test.ts +101 -0
- package/src/channel/events/index.ts +5 -0
- package/src/channel/events/onChannelMemberBanned.ts +36 -0
- package/src/channel/events/onChannelMemberUnbanned.ts +36 -0
- package/src/channel/events/tests/onChannelMemberBanned.test.ts +58 -0
- package/src/channel/events/tests/onChannelMemberUnbanned.test.ts +58 -0
- package/src/channel/observers/liveChannelMembers.ts +28 -4
- package/src/channel/observers/liveChannels.ts +7 -1
- package/src/channel/observers/tests/liveChannelMembers.test.ts +53 -11
- package/src/channel/observers/tests/liveChannels.test.ts +50 -20
- package/src/channel/{tests/utils → utils/tests}/prepareChannelPayload.test.ts +1 -1
- package/src/core/events.ts +1 -0
- package/src/core/query/filtering.ts +49 -0
- package/src/core/query/query.ts +9 -6
- package/src/core/tests/query/query.test.ts +12 -2
- package/src/message/api/createMessage.ts +15 -9
- package/src/message/api/deleteMessage.ts +2 -1
- package/src/message/api/getMessage.ts +32 -4
- package/src/message/api/getMessages.ts +6 -1
- package/src/message/api/queryMessages.ts +3 -0
- package/src/message/api/tests/createMessage.test.ts +76 -0
- package/src/message/api/updateMessage.ts +2 -0
- package/src/message/events/index.ts +1 -0
- package/src/message/events/onMessageFetched.ts +30 -0
- package/src/message/observers/index.ts +2 -1
- package/src/message/observers/liveMessage.ts +100 -0
- package/src/message/observers/liveMessages.ts +3 -1
- package/src/message/observers/observeMessage.ts +4 -0
- package/src/message/tests/api/getMessage.test.ts +96 -0
- package/src/message/tests/observers/liveMessage.test.ts +248 -0
- package/src/message/{observers/tests → tests/observers}/liveMessages.test.ts +29 -3
- package/src/post/api/deletePost.ts +4 -3
- package/src/post/api/getPost.ts +8 -4
- package/src/post/api/updatePost.ts +6 -1
- package/src/user/api/getUser.ts +34 -6
- package/src/user/api/getUsers.ts +3 -0
- package/src/user/api/queryUsers.ts +3 -0
- package/src/user/api/updateUser.ts +3 -0
- package/src/user/events/index.ts +1 -0
- package/src/user/events/onUserFetched.ts +19 -0
- package/src/user/observers/index.ts +1 -0
- package/src/user/observers/liveUser.ts +89 -0
- package/src/user/observers/observeUser.ts +2 -0
- package/src/user/tests/api/getUser.test.ts +112 -0
- package/src/user/tests/observers/liveUser.test.ts +224 -0
- package/src/utils/constants.ts +5 -0
- package/src/utils/tests/dummy/channel.ts +43 -0
- package/src/utils/tests/dummy/message.ts +16 -2
- package/src/utils/tests/dummy/user.ts +11 -0
- package/dist/channel/tests/utils/prepareChannelPayload.test.d.ts.map +0 -1
- package/dist/message/observers/tests/liveMessages.test.d.ts.map +0 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { getActiveClient } from '~/client/api';
|
|
2
2
|
|
|
3
|
-
import { getCommunity } from '~/community/api';
|
|
4
|
-
import { dropFromCache, upsertInCache } from '~/cache/api';
|
|
5
3
|
import { fireEvent } from '~/core/events';
|
|
4
|
+
import { upsertInCache } from '~/cache/api';
|
|
5
|
+
import { getCommunity } from '~/community/api';
|
|
6
|
+
import { pushToTombstone } from '~/cache/api/pushToTombstone';
|
|
6
7
|
|
|
7
8
|
import { getPost } from './getPost';
|
|
8
9
|
|
|
@@ -53,7 +54,7 @@ export const deletePost = async (
|
|
|
53
54
|
|
|
54
55
|
if (permanent) {
|
|
55
56
|
setTimeout(() => {
|
|
56
|
-
|
|
57
|
+
pushToTombstone('post', postId);
|
|
57
58
|
}, 0);
|
|
58
59
|
} else {
|
|
59
60
|
upsertInCache(['post', 'get', postId], { isDeleted: true });
|
package/src/post/api/getPost.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { getActiveClient } from '~/client/api';
|
|
2
2
|
|
|
3
|
-
import { pullFromCache
|
|
3
|
+
import { pullFromCache } from '~/cache/api';
|
|
4
4
|
import { ingestInCache } from '~/cache/api/ingestInCache';
|
|
5
|
+
import { isInTombstone } from '~/cache/api/isInTombstone';
|
|
6
|
+
import { checkIfShouldGoesToTombstone } from '~/cache/utils';
|
|
7
|
+
import { pushToTombstone } from '~/cache/api/pushToTombstone';
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* ```js
|
|
@@ -21,6 +24,8 @@ export const getPost = async (postId: Amity.Post['postId']): Promise<Amity.Cache
|
|
|
21
24
|
const client = getActiveClient();
|
|
22
25
|
client.log('post/getPost', postId);
|
|
23
26
|
|
|
27
|
+
isInTombstone('post', postId);
|
|
28
|
+
|
|
24
29
|
let data: Amity.PostPayload;
|
|
25
30
|
|
|
26
31
|
try {
|
|
@@ -28,11 +33,10 @@ export const getPost = async (postId: Amity.Post['postId']): Promise<Amity.Cache
|
|
|
28
33
|
const response = await client.http.get<Amity.PostPayload>(
|
|
29
34
|
`/api/v3/posts/${encodeURIComponent(postId)}`,
|
|
30
35
|
);
|
|
31
|
-
|
|
32
36
|
data = response.data;
|
|
33
37
|
} catch (error) {
|
|
34
|
-
if ((error as Amity.ErrorResponse)?.code
|
|
35
|
-
|
|
38
|
+
if (checkIfShouldGoesToTombstone((error as Amity.ErrorResponse)?.code)) {
|
|
39
|
+
pushToTombstone('post', postId);
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
throw error;
|
|
@@ -22,7 +22,12 @@ import { fireEvent } from '~/core/events';
|
|
|
22
22
|
*/
|
|
23
23
|
export const updatePost = async (
|
|
24
24
|
postId: Amity.Post['postId'],
|
|
25
|
-
patch: Patch<Amity.Post, 'data' | 'metadata' | 'mentionees' | 'tags'
|
|
25
|
+
patch: Patch<Amity.Post, 'data' | 'metadata' | 'mentionees' | 'tags'> & {
|
|
26
|
+
attachments?: {
|
|
27
|
+
type: 'image' | 'file' | 'video';
|
|
28
|
+
fileId: Amity.File['fileId'];
|
|
29
|
+
}[];
|
|
30
|
+
},
|
|
26
31
|
): Promise<Amity.Cached<Amity.Post>> => {
|
|
27
32
|
const client = getActiveClient();
|
|
28
33
|
client.log('user/updatePost', patch);
|
package/src/user/api/getUser.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { getActiveClient } from '~/client/api';
|
|
2
2
|
|
|
3
|
-
import { pullFromCache } from '~/cache/api';
|
|
3
|
+
import { pullFromCache, dropFromCache } from '~/cache/api';
|
|
4
4
|
import { ingestInCache } from '~/cache/api/ingestInCache';
|
|
5
|
+
import { fireEvent } from '~/core/events';
|
|
6
|
+
|
|
7
|
+
import { isInTombstone } from '~/cache/api/isInTombstone';
|
|
8
|
+
import { checkIfShouldGoesToTombstone } from '~/cache/utils';
|
|
9
|
+
import { pushToTombstone } from '~/cache/api/pushToTombstone';
|
|
5
10
|
|
|
6
11
|
/**
|
|
7
12
|
* ```js
|
|
@@ -17,20 +22,43 @@ import { ingestInCache } from '~/cache/api/ingestInCache';
|
|
|
17
22
|
* @category User API
|
|
18
23
|
* @async
|
|
19
24
|
*/
|
|
20
|
-
export const getUser = async (
|
|
25
|
+
export const getUser = async (
|
|
26
|
+
userId: Amity.User['userId'],
|
|
27
|
+
isLive = false,
|
|
28
|
+
): Promise<Amity.Cached<Amity.User>> => {
|
|
21
29
|
const client = getActiveClient();
|
|
22
30
|
client.log('user/getUser', userId);
|
|
23
31
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
if (!isLive) {
|
|
33
|
+
console.log('getUser will be deprecated on 25th November 2022, please use liveUser instead.');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
isInTombstone('user', userId);
|
|
37
|
+
|
|
38
|
+
let data: Amity.UserPayload;
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
// API-FIX: endpoint should not be /list, parameters should be querystring.
|
|
42
|
+
const response = await client.http.get<Amity.UserPayload>(
|
|
43
|
+
`/api/v3/users/${encodeURIComponent(userId)}`,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
data = response.data;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
if (checkIfShouldGoesToTombstone((error as Amity.ErrorResponse)?.code)) {
|
|
49
|
+
pushToTombstone('user', userId);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
28
54
|
|
|
29
55
|
const cachedAt = client.cache && Date.now();
|
|
30
56
|
if (client.cache) ingestInCache(data, { cachedAt });
|
|
31
57
|
|
|
32
58
|
const { users } = data;
|
|
33
59
|
|
|
60
|
+
fireEvent('user.fetched', data);
|
|
61
|
+
|
|
34
62
|
return {
|
|
35
63
|
data: users.find(user => user.userId === userId)!,
|
|
36
64
|
cachedAt,
|
package/src/user/api/getUsers.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { getActiveClient } from '~/client/api';
|
|
|
2
2
|
|
|
3
3
|
import { pullFromCache } from '~/cache/api';
|
|
4
4
|
import { ingestInCache } from '~/cache/api/ingestInCache';
|
|
5
|
+
import { fireEvent } from '~/core/events';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* ```js
|
|
@@ -33,6 +34,8 @@ export const getUsers = async (
|
|
|
33
34
|
const cachedAt = client.cache && Date.now();
|
|
34
35
|
if (client.cache) ingestInCache(data, { cachedAt });
|
|
35
36
|
|
|
37
|
+
fireEvent('user.fetched', data);
|
|
38
|
+
|
|
36
39
|
return {
|
|
37
40
|
data: data.users,
|
|
38
41
|
cachedAt,
|
|
@@ -5,6 +5,7 @@ import { toPage, toToken } from '~/core/query';
|
|
|
5
5
|
import { pullFromCache, pushToCache } from '~/cache/api';
|
|
6
6
|
import { ingestInCache } from '~/cache/api/ingestInCache';
|
|
7
7
|
import { getResolver } from '~/core/model';
|
|
8
|
+
import { fireEvent } from '~/core/events';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* ```js
|
|
@@ -60,6 +61,8 @@ export const queryUsers = async (
|
|
|
60
61
|
pushToCache(cacheKey, { users: users.map(getResolver('user')), paging });
|
|
61
62
|
}
|
|
62
63
|
|
|
64
|
+
fireEvent('user.fetched', data);
|
|
65
|
+
|
|
63
66
|
const prevPage = toPage(paging.previous);
|
|
64
67
|
const nextPage = toPage(paging.next);
|
|
65
68
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getActiveClient } from '~/client/api';
|
|
2
2
|
|
|
3
|
+
import { fireEvent } from '~/core/events';
|
|
3
4
|
import { ingestInCache } from '~/cache/api/ingestInCache';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -45,6 +46,8 @@ export const updateUser = async (
|
|
|
45
46
|
|
|
46
47
|
const { users } = data;
|
|
47
48
|
|
|
49
|
+
fireEvent('user.updated', data);
|
|
50
|
+
|
|
48
51
|
return {
|
|
49
52
|
data: users.find(user => user.userId === userId)!,
|
|
50
53
|
cachedAt,
|
package/src/user/events/index.ts
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createUserEventSubscriber } from './utils';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ```js
|
|
5
|
+
* import { onUserFetched } from '@amityco/ts-sdk'
|
|
6
|
+
* const dispose = onUserFetched(user => {
|
|
7
|
+
* // ...
|
|
8
|
+
* })
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* Fired when a {@link Amity.User} has been fetched
|
|
12
|
+
*
|
|
13
|
+
* @param callback The function to call when the event was fired
|
|
14
|
+
* @returns an {@link Amity.Unsubscriber} function to stop listening
|
|
15
|
+
*
|
|
16
|
+
* @category User Events
|
|
17
|
+
*/
|
|
18
|
+
export const onUserFetched = (callback: Amity.Listener<Amity.User>) =>
|
|
19
|
+
createUserEventSubscriber('user.fetched', callback);
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { getActiveClient } from '~/client/api';
|
|
2
|
+
import { createQuery, runQuery } from '~/core/query';
|
|
3
|
+
|
|
4
|
+
import { LIVE_OBJECT_ENABLE_CACHE_MESSAGE } from '~/utils/constants';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
onUserFetched,
|
|
8
|
+
onUserDeleted,
|
|
9
|
+
onUserUpdated,
|
|
10
|
+
onUserFlagCleared,
|
|
11
|
+
onUserFlagged,
|
|
12
|
+
onUserUnflagged,
|
|
13
|
+
} from '../events';
|
|
14
|
+
import { getUser } from '../api';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* ```js
|
|
18
|
+
* import { liveUser } from '@amityco/ts-sdk'
|
|
19
|
+
*
|
|
20
|
+
* let users = []
|
|
21
|
+
* const unsub = liveUser(userId, response => merge(users, response.data))
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* Observe all mutation on a given {@link Amity.User}
|
|
25
|
+
*
|
|
26
|
+
* @param userId the ID of the user to observe
|
|
27
|
+
* @param callback the function to call when new data are available
|
|
28
|
+
* @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the users
|
|
29
|
+
*
|
|
30
|
+
* @category Message Live Object
|
|
31
|
+
*/
|
|
32
|
+
export const liveUser = (
|
|
33
|
+
userId: Amity.User['userId'],
|
|
34
|
+
callback: Amity.LiveObjectCallback<Amity.User>,
|
|
35
|
+
): Amity.Unsubscriber => {
|
|
36
|
+
const { log, cache } = getActiveClient();
|
|
37
|
+
let user: Amity.User;
|
|
38
|
+
|
|
39
|
+
if (!cache) {
|
|
40
|
+
console.log(LIVE_OBJECT_ENABLE_CACHE_MESSAGE);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const timestamp = Date.now();
|
|
44
|
+
log(`liveUser(tmpid: ${timestamp}) > listen`);
|
|
45
|
+
|
|
46
|
+
const disposers: Amity.Unsubscriber[] = [];
|
|
47
|
+
|
|
48
|
+
const dispatcher = (data: Amity.LiveObject<Amity.User>) => {
|
|
49
|
+
// we check updatedAt to see if the current snapshot is new so
|
|
50
|
+
// we won't send old data back, only fresh new data
|
|
51
|
+
if (user && data.data?.updatedAt === user?.updatedAt && data.origin !== 'server') return;
|
|
52
|
+
|
|
53
|
+
callback(data);
|
|
54
|
+
user = data.data;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const realtimeRouter = (user: Amity.User, action: Amity.UserActionType) => {
|
|
58
|
+
dispatcher({ loading: false, data: user, origin: 'event' });
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const onFetch = () => {
|
|
62
|
+
const query = createQuery(getUser, userId, true);
|
|
63
|
+
|
|
64
|
+
runQuery(query, ({ loading, data, error, origin }) => {
|
|
65
|
+
dispatcher({ loading, data, origin, error });
|
|
66
|
+
|
|
67
|
+
if (error) {
|
|
68
|
+
// Terminate observe functionality on error
|
|
69
|
+
disposers.forEach(fn => fn());
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
disposers.push(
|
|
75
|
+
onUserFetched(user => realtimeRouter(user, 'onFetch')),
|
|
76
|
+
onUserUpdated(user => realtimeRouter(user, 'onUpdate')),
|
|
77
|
+
onUserDeleted(user => realtimeRouter(user, 'onDelete')),
|
|
78
|
+
onUserFlagged(user => realtimeRouter(user, 'onFlagged')),
|
|
79
|
+
onUserUnflagged(user => realtimeRouter(user, 'onUnflagged')),
|
|
80
|
+
onUserFlagCleared(user => realtimeRouter(user, 'onFlagCleared')),
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
onFetch();
|
|
84
|
+
|
|
85
|
+
return () => {
|
|
86
|
+
log(`liveUser(tmpid: ${timestamp}) > dispose`);
|
|
87
|
+
disposers.forEach(fn => fn());
|
|
88
|
+
};
|
|
89
|
+
};
|
|
@@ -37,6 +37,8 @@ export const observeUser = <
|
|
|
37
37
|
const timestamp = Date.now();
|
|
38
38
|
log(`observeUser(tmpid: ${timestamp}) > listen`);
|
|
39
39
|
|
|
40
|
+
console.log('observeUser will be deprecated on 25th November 2022, please use liveUser instead.');
|
|
41
|
+
|
|
40
42
|
// wrapper function to make sure
|
|
41
43
|
const router = (result: Amity.Snapshot<Amity.User>, action: Events[number]) => {
|
|
42
44
|
// filter function
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { ASCApiError } from '~/core/errors';
|
|
2
|
+
import { disableCache, enableCache, pushToCache } from '~/cache/api';
|
|
3
|
+
import { client, user11 } from '~/utils/tests';
|
|
4
|
+
|
|
5
|
+
import { pushToTombstone } from '~/cache/api/pushToTombstone';
|
|
6
|
+
import { isInTombstone } from '~/cache/api/isInTombstone';
|
|
7
|
+
|
|
8
|
+
import { getUser } from '../../api/getUser';
|
|
9
|
+
|
|
10
|
+
const user = user11;
|
|
11
|
+
const getResolvedUserValue = () => ({
|
|
12
|
+
data: {
|
|
13
|
+
users: [user],
|
|
14
|
+
files: [],
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('getUser', () => {
|
|
19
|
+
test('should return user data', async () => {
|
|
20
|
+
client.http.get = jest.fn().mockResolvedValue(getResolvedUserValue());
|
|
21
|
+
|
|
22
|
+
const { data } = await getUser(user.userId);
|
|
23
|
+
|
|
24
|
+
expect(data).toStrictEqual(user);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('it should update cache after fetch from server', async () => {
|
|
28
|
+
enableCache();
|
|
29
|
+
client.http.get = jest.fn().mockResolvedValue(getResolvedUserValue());
|
|
30
|
+
await getUser(user.userId);
|
|
31
|
+
|
|
32
|
+
expect(getUser.locally(user.userId)).toBeDefined();
|
|
33
|
+
|
|
34
|
+
disableCache();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('should return an error', async () => {
|
|
38
|
+
client.http.get = jest.fn().mockRejectedValueOnce(new Error('error'));
|
|
39
|
+
|
|
40
|
+
await expect(getUser(user.userId)).rejects.toThrow('error');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('should return an error if user in cache but api throws not found', async () => {
|
|
44
|
+
enableCache();
|
|
45
|
+
pushToCache(['user', 'get', user.userId], user, { cachedAt: Date.now() });
|
|
46
|
+
|
|
47
|
+
client.http.get = jest
|
|
48
|
+
|
|
49
|
+
.fn()
|
|
50
|
+
.mockRejectedValueOnce(
|
|
51
|
+
new ASCApiError('not found!', Amity.ServerError.ITEM_NOT_FOUND, Amity.ErrorLevel.ERROR),
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
await expect(getUser(user.userId)).rejects.toThrow();
|
|
55
|
+
|
|
56
|
+
expect(getUser.locally(user.userId)).toBeUndefined();
|
|
57
|
+
disableCache();
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('getUser locally', () => {
|
|
62
|
+
test('should return data from cache', () => {
|
|
63
|
+
enableCache();
|
|
64
|
+
|
|
65
|
+
const cachedAt = Date.now();
|
|
66
|
+
|
|
67
|
+
pushToCache(['user', 'get', user.userId], user, { cachedAt });
|
|
68
|
+
|
|
69
|
+
const data = getUser.locally(user.userId);
|
|
70
|
+
|
|
71
|
+
expect(data).toBeDefined();
|
|
72
|
+
expect(data?.data).toEqual(user);
|
|
73
|
+
expect(data?.cachedAt).toEqual(cachedAt);
|
|
74
|
+
|
|
75
|
+
disableCache();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('should return undefined if user not in cache', () => {
|
|
79
|
+
expect(getUser.locally('non-existent-user')).toBeUndefined();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('should return undefined if cache not enabled', () => {
|
|
83
|
+
expect(getUser.locally(user.userId)).toBeUndefined();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('getUser tombostone', () => {
|
|
88
|
+
test('it should add user to tombostone if 404', async () => {
|
|
89
|
+
enableCache();
|
|
90
|
+
client.http.get = jest
|
|
91
|
+
.fn()
|
|
92
|
+
.mockRejectedValueOnce(
|
|
93
|
+
new ASCApiError('not found!', Amity.ServerError.ITEM_NOT_FOUND, Amity.ErrorLevel.ERROR),
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
await expect(getUser(user.userId)).rejects.toThrow();
|
|
97
|
+
expect(() => {
|
|
98
|
+
isInTombstone('user', user.userId);
|
|
99
|
+
}).toThrow();
|
|
100
|
+
|
|
101
|
+
disableCache();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('it should throw error if user not found in tombostone', async () => {
|
|
105
|
+
enableCache();
|
|
106
|
+
|
|
107
|
+
pushToTombstone('user', user.userId);
|
|
108
|
+
await expect(getUser(user.userId)).rejects.toThrow();
|
|
109
|
+
|
|
110
|
+
disableCache();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { ASCApiError } from '~/core/errors';
|
|
2
|
+
import { disableCache, enableCache } from '~/cache/api';
|
|
3
|
+
import { LIVE_OBJECT_ENABLE_CACHE_MESSAGE } from '~/utils/constants';
|
|
4
|
+
|
|
5
|
+
import { liveUser } from '../../observers/liveUser';
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
pause,
|
|
9
|
+
client,
|
|
10
|
+
connectClient,
|
|
11
|
+
disconnectClient,
|
|
12
|
+
userQueryResponse,
|
|
13
|
+
user11 as defaultUser,
|
|
14
|
+
} from '~/utils/tests';
|
|
15
|
+
|
|
16
|
+
const getSnapshot = () => {
|
|
17
|
+
return {
|
|
18
|
+
loading: true,
|
|
19
|
+
error: undefined as any,
|
|
20
|
+
data: undefined as undefined | Amity.User,
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
describe('liveUser', () => {
|
|
25
|
+
beforeAll(async () => {
|
|
26
|
+
await connectClient();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
afterAll(async () => {
|
|
30
|
+
await disconnectClient();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
beforeEach(async () => {
|
|
34
|
+
enableCache();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
afterEach(disableCache);
|
|
38
|
+
|
|
39
|
+
test('it should show user if cache not enabled', () => {
|
|
40
|
+
/*
|
|
41
|
+
* NOTE: at the time of writing this test cache is diabled by default, but
|
|
42
|
+
* there is a proposal to enable cache by default. So I'm disabling cache
|
|
43
|
+
* here to ensure cache is disabled
|
|
44
|
+
*/
|
|
45
|
+
disableCache();
|
|
46
|
+
|
|
47
|
+
const callback = jest.fn();
|
|
48
|
+
jest.spyOn(global.console, 'log');
|
|
49
|
+
client.http.get = jest.fn();
|
|
50
|
+
|
|
51
|
+
// call liveUser check if mocked console get's called with the correct
|
|
52
|
+
// user
|
|
53
|
+
client.use();
|
|
54
|
+
liveUser(defaultUser.userId, callback);
|
|
55
|
+
|
|
56
|
+
expect(console.log).toBeCalledWith(LIVE_OBJECT_ENABLE_CACHE_MESSAGE);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('it should return user live object', async () => {
|
|
60
|
+
const snapshot = getSnapshot();
|
|
61
|
+
|
|
62
|
+
// mock response of queryUsers and validate
|
|
63
|
+
const callback = jest.fn();
|
|
64
|
+
client.http.get = jest.fn().mockResolvedValue(userQueryResponse);
|
|
65
|
+
|
|
66
|
+
liveUser(defaultUser.userId, callback);
|
|
67
|
+
|
|
68
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
69
|
+
|
|
70
|
+
// check if cache data returned (should be empty)
|
|
71
|
+
expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
|
|
72
|
+
|
|
73
|
+
await pause();
|
|
74
|
+
|
|
75
|
+
expect(callback).toHaveBeenCalledTimes(2);
|
|
76
|
+
|
|
77
|
+
snapshot.loading = false;
|
|
78
|
+
snapshot.data = defaultUser;
|
|
79
|
+
|
|
80
|
+
expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('it should return error on api failure', async () => {
|
|
84
|
+
const snapshot = getSnapshot();
|
|
85
|
+
const error = new ASCApiError(
|
|
86
|
+
'server error!',
|
|
87
|
+
Amity.ServerError.ITEM_NOT_FOUND,
|
|
88
|
+
Amity.ErrorLevel.ERROR,
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// mock response of queryUsers and validate
|
|
92
|
+
const callback = jest.fn();
|
|
93
|
+
client.http.get = jest.fn().mockRejectedValue(error);
|
|
94
|
+
|
|
95
|
+
liveUser(defaultUser.userId, callback);
|
|
96
|
+
|
|
97
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
98
|
+
|
|
99
|
+
// check if cache data returned (should be empty)
|
|
100
|
+
expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
|
|
101
|
+
|
|
102
|
+
await pause();
|
|
103
|
+
|
|
104
|
+
expect(callback).toHaveBeenCalledTimes(2);
|
|
105
|
+
|
|
106
|
+
snapshot.error = error;
|
|
107
|
+
snapshot.loading = false;
|
|
108
|
+
expect(callback).toHaveBeenLastCalledWith(expect.objectContaining(snapshot));
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test('it should terminate updates on api failure', async () => {
|
|
112
|
+
const snapshot = getSnapshot();
|
|
113
|
+
const error = new ASCApiError(
|
|
114
|
+
'server error!',
|
|
115
|
+
Amity.ServerError.ITEM_NOT_FOUND,
|
|
116
|
+
Amity.ErrorLevel.ERROR,
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// mock response of queryUsers and validate
|
|
120
|
+
const callback = jest.fn();
|
|
121
|
+
client.http.get = jest.fn().mockRejectedValue(error);
|
|
122
|
+
|
|
123
|
+
liveUser(defaultUser.userId, callback);
|
|
124
|
+
|
|
125
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
126
|
+
|
|
127
|
+
// check if cache data returned (should be empty)
|
|
128
|
+
expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
|
|
129
|
+
|
|
130
|
+
await pause();
|
|
131
|
+
|
|
132
|
+
expect(callback).toHaveBeenCalledTimes(2);
|
|
133
|
+
|
|
134
|
+
snapshot.error = error;
|
|
135
|
+
snapshot.loading = false;
|
|
136
|
+
expect(callback).toHaveBeenLastCalledWith(expect.objectContaining(snapshot));
|
|
137
|
+
|
|
138
|
+
const updatedAt = new Date(defaultUser?.updatedAt ?? new Date());
|
|
139
|
+
updatedAt.setDate(updatedAt.getDate() + 7);
|
|
140
|
+
|
|
141
|
+
const updatedUser = {
|
|
142
|
+
...defaultUser,
|
|
143
|
+
updatedAt: updatedAt.toISOString(),
|
|
144
|
+
};
|
|
145
|
+
client.emitter.emit('user.updated', { users: [updatedUser], files: [] });
|
|
146
|
+
|
|
147
|
+
delete snapshot.error;
|
|
148
|
+
snapshot.loading = false;
|
|
149
|
+
snapshot.data = updatedUser;
|
|
150
|
+
expect(callback).not.toHaveBeenNthCalledWith(3, expect.objectContaining(snapshot));
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test('it should not return updates on obtain once!', async () => {
|
|
154
|
+
const snapshot = getSnapshot();
|
|
155
|
+
|
|
156
|
+
// mock response of queryUsers and validate
|
|
157
|
+
const callback = jest.fn();
|
|
158
|
+
client.http.get = jest.fn().mockResolvedValue(userQueryResponse);
|
|
159
|
+
|
|
160
|
+
const unsub = liveUser(defaultUser.userId, callback);
|
|
161
|
+
|
|
162
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
163
|
+
|
|
164
|
+
// check if cache data returned (should be empty)
|
|
165
|
+
expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
|
|
166
|
+
|
|
167
|
+
await pause();
|
|
168
|
+
|
|
169
|
+
expect(callback).toHaveBeenCalledTimes(2);
|
|
170
|
+
|
|
171
|
+
unsub();
|
|
172
|
+
|
|
173
|
+
const updatedAt = new Date(defaultUser?.updatedAt ?? new Date());
|
|
174
|
+
updatedAt.setDate(updatedAt.getDate() + 7);
|
|
175
|
+
|
|
176
|
+
const updatedUser = {
|
|
177
|
+
...defaultUser,
|
|
178
|
+
updatedAt: updatedAt.toISOString(),
|
|
179
|
+
};
|
|
180
|
+
client.emitter.emit('user.updated', { users: [updatedUser], files: [] });
|
|
181
|
+
|
|
182
|
+
delete snapshot.error;
|
|
183
|
+
snapshot.loading = false;
|
|
184
|
+
snapshot.data = updatedUser;
|
|
185
|
+
expect(callback).not.toHaveBeenNthCalledWith(3, expect.objectContaining(snapshot));
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const events: [string, keyof Amity.Events][] = [
|
|
189
|
+
['it should return updated user on onFetch', 'user.fetched'],
|
|
190
|
+
['it should return updated user on onUpdate', 'user.updated'],
|
|
191
|
+
['it should return updated user on onDelete', 'user.deleted'],
|
|
192
|
+
['it should return updated user on onFlagged', 'user.flagged'],
|
|
193
|
+
['it should return updated user on onUnflagged', 'user.unflagged'],
|
|
194
|
+
['it should return updated user on onFlagCleared', 'user.flagCleared'],
|
|
195
|
+
];
|
|
196
|
+
|
|
197
|
+
test.each(events)('%s', async (test, event) => {
|
|
198
|
+
const snapshot = getSnapshot();
|
|
199
|
+
|
|
200
|
+
// mock response of queryUsers and validate
|
|
201
|
+
const callback = jest.fn();
|
|
202
|
+
client.http.get = jest.fn().mockResolvedValue(userQueryResponse);
|
|
203
|
+
|
|
204
|
+
liveUser(defaultUser.userId, callback);
|
|
205
|
+
|
|
206
|
+
await pause();
|
|
207
|
+
|
|
208
|
+
expect(callback).toHaveBeenCalledTimes(2);
|
|
209
|
+
|
|
210
|
+
const updatedAt = new Date(defaultUser?.updatedAt ?? new Date());
|
|
211
|
+
updatedAt.setDate(updatedAt.getDate() + 7);
|
|
212
|
+
|
|
213
|
+
const updatedUser = {
|
|
214
|
+
...defaultUser,
|
|
215
|
+
updatedAt: updatedAt.toISOString(),
|
|
216
|
+
};
|
|
217
|
+
client.emitter.emit(event, { users: [updatedUser], files: [] });
|
|
218
|
+
|
|
219
|
+
delete snapshot.error;
|
|
220
|
+
snapshot.loading = false;
|
|
221
|
+
snapshot.data = updatedUser;
|
|
222
|
+
expect(callback).toHaveBeenNthCalledWith(3, expect.objectContaining(snapshot));
|
|
223
|
+
});
|
|
224
|
+
});
|
package/src/utils/constants.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
export const COLLECTION_DEFAULT_PAGINATION_LIMIT = 5;
|
|
2
2
|
export const COLLECTION_DEFAULT_CACHING_POLICY: Amity.QueryPolicy = 'cache_then_server';
|
|
3
3
|
export const ENABLE_CACHE_MESSAGE = 'For using Live Collection feature you need to enable Cache!';
|
|
4
|
+
export const LIVE_OBJECT_ENABLE_CACHE_MESSAGE =
|
|
5
|
+
'For using Live Object feature you need to enable Cache!';
|
|
6
|
+
export const UNSYNCED_OBJECT_CACHED_AT_MESSAGE =
|
|
7
|
+
'Observing unsynced object is not supported by Live Object.';
|
|
8
|
+
export const UNSYNCED_OBJECT_CACHED_AT_VALUE = -5;
|