@amityco/ts-sdk 0.0.1-beta.30 → 0.0.1-beta.32
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/backupCache.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/api/tests/pushToCache.test.d.ts +2 -0
- package/dist/cache/api/tests/pushToCache.test.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/addChannelMembers.d.ts.map +1 -1
- package/dist/channel/api/getChannel.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/addChannelMembers.test.d.ts +2 -0
- package/dist/channel/api/tests/addChannelMembers.test.d.ts.map +1 -0
- package/dist/channel/api/tests/getChannel.test.d.ts +2 -0
- package/dist/channel/api/tests/getChannel.test.d.ts.map +1 -0
- 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/onChannelMemberAdded.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/core/transports/http.d.ts +5 -0
- package/dist/core/transports/http.d.ts.map +1 -1
- package/dist/core/transports/test/http.test.d.ts +2 -0
- package/dist/core/transports/test/http.test.d.ts.map +1 -0
- package/dist/index.cjs.js +980 -534
- package/dist/index.esm.js +962 -526
- 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/tests/deleteMessage.test.d.ts +2 -0
- package/dist/message/api/tests/deleteMessage.test.d.ts.map +1 -0
- package/dist/message/api/tests/getMessage.test.d.ts +2 -0
- package/dist/message/api/tests/getMessage.test.d.ts.map +1 -0
- package/dist/message/api/tests/getMessages.test.d.ts +2 -0
- package/dist/message/api/tests/getMessages.test.d.ts.map +1 -0
- package/dist/message/api/tests/queryMessages.test.d.ts +2 -0
- package/dist/message/api/tests/queryMessages.test.d.ts.map +1 -0
- package/dist/message/api/tests/updateMessage.test.d.ts +2 -0
- package/dist/message/api/tests/updateMessage.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/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/reaction/api/addReaction.d.ts.map +1 -1
- package/dist/reaction/api/removeReaction.d.ts.map +1 -1
- package/dist/reaction/api/tests/addReaction.test.d.ts +2 -0
- package/dist/reaction/api/tests/addReaction.test.d.ts.map +1 -0
- package/dist/reaction/api/tests/removeReaction.test.d.ts +2 -0
- package/dist/reaction/api/tests/removeReaction.test.d.ts.map +1 -0
- 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/tests/queryUsers.test.d.ts +2 -0
- package/dist/user/api/tests/queryUsers.test.d.ts.map +1 -0
- 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/post.d.ts +12 -1
- package/dist/utils/tests/dummy/post.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 +2 -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/backupCache.ts +0 -1
- 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/api/tests/pushToCache.test.ts +57 -0
- package/src/cache/utils/index.ts +22 -0
- package/src/channel/api/addChannelMembers.ts +9 -1
- package/src/channel/api/getChannel.ts +20 -5
- package/src/channel/api/queryChannelMembers.ts +53 -5
- package/src/channel/api/queryChannels.ts +31 -4
- package/src/channel/api/tests/addChannelMembers.test.ts +95 -0
- package/src/channel/api/tests/getChannel.test.ts +108 -0
- package/src/channel/api/tests/queryChannelMembers.test.ts +115 -0
- package/src/channel/api/tests/queryChannels.test.ts +121 -0
- package/src/channel/events/index.ts +5 -0
- package/src/channel/events/onChannelMemberAdded.ts +1 -1
- 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 -21
- package/src/channel/{tests/utils → utils/tests}/prepareChannelPayload.test.ts +1 -1
- package/src/core/events.ts +2 -1
- 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/core/transports/http.ts +3 -17
- package/src/core/transports/test/http.test.ts +83 -0
- package/src/message/api/createMessage.ts +15 -9
- package/src/message/api/deleteMessage.ts +4 -4
- 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 +99 -0
- package/src/message/api/tests/deleteMessage.test.ts +110 -0
- package/src/message/api/tests/getMessage.test.ts +121 -0
- package/src/message/api/tests/getMessages.test.ts +108 -0
- package/src/message/api/tests/queryMessages.test.ts +115 -0
- package/src/message/api/tests/updateMessage.test.ts +100 -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/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/post/tests/api/queryPosts.test.ts +117 -18
- package/src/reaction/api/addReaction.ts +1 -4
- package/src/reaction/api/removeReaction.ts +1 -4
- package/src/reaction/api/tests/addReaction.test.ts +37 -0
- package/src/reaction/api/tests/removeReaction.test.ts +43 -0
- package/src/user/api/getUser.ts +32 -5
- package/src/user/api/getUsers.ts +3 -0
- package/src/user/api/queryUsers.ts +27 -5
- package/src/user/api/tests/queryUsers.test.ts +124 -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/post.ts +26 -3
- 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
package/src/@types/core/live.ts
CHANGED
|
@@ -2,12 +2,18 @@ export {};
|
|
|
2
2
|
|
|
3
3
|
declare global {
|
|
4
4
|
namespace Amity {
|
|
5
|
-
type
|
|
6
|
-
data: T
|
|
7
|
-
onNextPage: () => void;
|
|
8
|
-
hasNextPage: boolean;
|
|
5
|
+
type LiveObject<T extends any> = {
|
|
6
|
+
data: T;
|
|
9
7
|
error?: any;
|
|
10
8
|
loading: boolean;
|
|
9
|
+
origin?: 'local' | 'server' | 'event';
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type LiveObjectCallback<T extends any> = Amity.Listener<LiveObject<T>>;
|
|
13
|
+
|
|
14
|
+
type LiveCollection<T extends any> = LiveObject<T[]> & {
|
|
15
|
+
onNextPage: () => void;
|
|
16
|
+
hasNextPage: boolean;
|
|
11
17
|
};
|
|
12
18
|
|
|
13
19
|
type LiveCollectionCallback<T extends any> = Amity.Listener<LiveCollection<T>>;
|
package/src/@types/core/query.ts
CHANGED
|
@@ -4,6 +4,12 @@ declare global {
|
|
|
4
4
|
namespace Amity {
|
|
5
5
|
type ChannelType = 'broadcast' | 'conversation' | 'community' | 'live';
|
|
6
6
|
|
|
7
|
+
type ChannelMemberActionType =
|
|
8
|
+
| 'onMemberAdded'
|
|
9
|
+
| 'onMemberRemoved'
|
|
10
|
+
| 'onChannelMemberBanned'
|
|
11
|
+
| 'onChannelMemberUnbanned';
|
|
12
|
+
|
|
7
13
|
type ChannelActionType =
|
|
8
14
|
| 'onFetch'
|
|
9
15
|
| 'onCreate'
|
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export const MessageContentType = Object.freeze({
|
|
2
|
+
TEXT: 'text',
|
|
3
|
+
IMAGE: 'image',
|
|
4
|
+
FILE: 'file',
|
|
5
|
+
VIDEO: 'video',
|
|
6
|
+
AUDIO: 'audio',
|
|
7
|
+
CUSTOM: 'custom',
|
|
8
|
+
});
|
|
2
9
|
|
|
3
10
|
declare global {
|
|
4
11
|
namespace Amity {
|
|
5
|
-
type MessageContentType =
|
|
12
|
+
type MessageContentType = ValueOf<typeof MessageContentType>;
|
|
6
13
|
|
|
7
|
-
type MessageContent<T extends Amity.MessageContentType = any> =
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
| 'video'
|
|
11
|
-
| 'audio'
|
|
12
|
-
? { fileId: string }
|
|
13
|
-
: unknown;
|
|
14
|
+
type MessageContent<T extends Amity.MessageContentType = any> = {
|
|
15
|
+
fileId: T extends 'file' | 'image' | 'video' | 'audio' ? string : null;
|
|
16
|
+
};
|
|
14
17
|
|
|
15
|
-
type MessageActionType = 'onCreate' | 'onUpdate' | 'onDelete';
|
|
18
|
+
type MessageActionType = 'onCreate' | 'onUpdate' | 'onDelete' | 'onFetch';
|
|
16
19
|
|
|
17
20
|
type Message<T extends Amity.MessageContentType = any> = {
|
|
18
21
|
messageId: string;
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export const PostContentType = Object.freeze({
|
|
2
|
+
TEXT: 'text',
|
|
3
|
+
IMAGE: 'image',
|
|
4
|
+
FILE: 'file',
|
|
5
|
+
VIDEO: 'video',
|
|
6
|
+
LIVESTREAM: 'liveStream',
|
|
7
|
+
POLL: 'poll',
|
|
8
|
+
});
|
|
2
9
|
|
|
3
10
|
declare global {
|
|
4
11
|
namespace Amity {
|
|
5
12
|
// bad hack until we get proper feed objects in backend
|
|
6
13
|
type PostTargetType = Amity.FeedType | 'content';
|
|
7
14
|
|
|
8
|
-
type PostContentType =
|
|
15
|
+
type PostContentType = ValueOf<typeof PostContentType>;
|
|
9
16
|
|
|
10
17
|
type PostActionType =
|
|
11
18
|
| 'onFetch'
|
|
@@ -46,7 +53,7 @@ declare global {
|
|
|
46
53
|
targetId: string;
|
|
47
54
|
targetType: Amity.Post['targetType'];
|
|
48
55
|
sortBy?: 'lastCreated' | 'firstCreated' | 'lastUpdated' | 'firstUpdated';
|
|
49
|
-
dataType?:
|
|
56
|
+
dataType?: Exclude<Amity.PostContentType, 'text'>;
|
|
50
57
|
isDeleted?: Amity.Post['isDeleted'];
|
|
51
58
|
hasFlag?: boolean;
|
|
52
59
|
feedType?: 'reviewing' | 'published';
|
package/src/@types/index.ts
CHANGED
|
@@ -21,10 +21,8 @@ import './domains/reaction';
|
|
|
21
21
|
|
|
22
22
|
import './domains/group';
|
|
23
23
|
import './domains/channel';
|
|
24
|
-
import './domains/message';
|
|
25
24
|
|
|
26
25
|
import './domains/category';
|
|
27
|
-
import './domains/post';
|
|
28
26
|
import './domains/comment';
|
|
29
27
|
|
|
30
28
|
import './domains/stream';
|
|
@@ -36,3 +34,5 @@ import './domains/poll';
|
|
|
36
34
|
export * from './domains/community';
|
|
37
35
|
export * from './domains/content';
|
|
38
36
|
export * from './domains/file';
|
|
37
|
+
export * from './domains/message';
|
|
38
|
+
export * from './domains/post';
|
package/src/cache/api/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ export * from './upsertInCache';
|
|
|
18
18
|
export * from './dropFromCache';
|
|
19
19
|
|
|
20
20
|
/*
|
|
21
|
-
* ingestInCache and syncInCache
|
|
21
|
+
* ingestInCache and syncInCache and isInTombstone
|
|
22
|
+
* and pushToTombstone are not exported ;
|
|
22
23
|
* we don't want it as part of the sdk's public api.
|
|
23
24
|
*/
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { getActiveClient } from '~/client/api/activeClient';
|
|
2
|
+
|
|
3
|
+
import { ASCApiError } from '~/core/errors';
|
|
4
|
+
import { pullFromCache } from '~/cache/api';
|
|
5
|
+
import { isFresh, queryOptions } from '~/core/query';
|
|
6
|
+
import { CACHE_KEY_TOMBSTONE, CACHE_LIFESPAN_TOMBSTONE } from '~/cache/utils';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ```js
|
|
10
|
+
* import { isInTombstone } from '@amityco/ts-sdk'
|
|
11
|
+
* const user = isInTombstone(["message", "messageId"])
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Checks if the {@link Amity.TombstoneCacheOptions} exists
|
|
15
|
+
* in cache and it's not expired means it's in tombstone
|
|
16
|
+
* and we throw an Error
|
|
17
|
+
*
|
|
18
|
+
* @param model the model to check
|
|
19
|
+
* @param modelId the object id to check
|
|
20
|
+
* @returns the matching cache entry, or undefined.
|
|
21
|
+
*
|
|
22
|
+
* @category Cache API
|
|
23
|
+
*/
|
|
24
|
+
export const isInTombstone = (model: Amity.Domain, modelId: string) => {
|
|
25
|
+
const { log, cache } = getActiveClient();
|
|
26
|
+
const key = [model, CACHE_KEY_TOMBSTONE, modelId];
|
|
27
|
+
|
|
28
|
+
if (!cache) return;
|
|
29
|
+
log('cache/api/isInTombstone', key);
|
|
30
|
+
|
|
31
|
+
const isInTombstone = pullFromCache<Amity.TombstoneCacheOptions>(key);
|
|
32
|
+
const { lifeSpan } = queryOptions('cache_then_server', CACHE_LIFESPAN_TOMBSTONE);
|
|
33
|
+
|
|
34
|
+
if (isInTombstone && isFresh(isInTombstone.data, lifeSpan)) {
|
|
35
|
+
throw new ASCApiError(
|
|
36
|
+
'Item not found!',
|
|
37
|
+
Amity.ServerError.ITEM_NOT_FOUND,
|
|
38
|
+
Amity.ErrorLevel.ERROR,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { getActiveClient } from '~/client/api/activeClient';
|
|
2
|
+
|
|
3
|
+
import { dropFromCache, pushToCache } from '~/cache/api';
|
|
4
|
+
|
|
5
|
+
import { CACHE_KEY_GET, CACHE_KEY_TOMBSTONE } from '~/cache/utils';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* ```js
|
|
9
|
+
* import { pushToTombstone } from '@amityco/ts-sdk'
|
|
10
|
+
* pushToTombstone(["message", "messageId"], { cachedAt: Date.now() })
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Removes an existing {@link Amity.CacheEntry} from the {@link Amity.Client}'s
|
|
14
|
+
* {@link Amity.Cache} from a given {@link Amity.CacheKey}
|
|
15
|
+
*
|
|
16
|
+
* @param model the model to remove and push to Tombstone
|
|
17
|
+
* @param modelId the related model id
|
|
18
|
+
*
|
|
19
|
+
* @category Cache API
|
|
20
|
+
* @hidden
|
|
21
|
+
*/
|
|
22
|
+
export const pushToTombstone = (model: Amity.Domain, modelId: string) => {
|
|
23
|
+
const { log, cache } = getActiveClient();
|
|
24
|
+
|
|
25
|
+
const cacheKey = [model, CACHE_KEY_TOMBSTONE, modelId];
|
|
26
|
+
const data: Pick<Amity.CacheOptions, 'cachedAt'> = { cachedAt: Date.now() };
|
|
27
|
+
|
|
28
|
+
if (!cache) return;
|
|
29
|
+
log('cache/api/pushToTombstone', { cacheKey, data });
|
|
30
|
+
|
|
31
|
+
dropFromCache([model, CACHE_KEY_GET, modelId], true);
|
|
32
|
+
pushToCache(cacheKey, data);
|
|
33
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { getActiveClient } from '~/client/api';
|
|
2
|
+
import { connectClient, disconnectClient, user11 } from '~/utils/tests';
|
|
3
|
+
|
|
4
|
+
import { pushToCache, enableCache, disableCache, pullFromCache } from '..';
|
|
5
|
+
import { encodeKey } from '../../utils';
|
|
6
|
+
|
|
7
|
+
describe('pushToCache', () => {
|
|
8
|
+
beforeAll(connectClient);
|
|
9
|
+
afterAll(disconnectClient);
|
|
10
|
+
|
|
11
|
+
describe('- cache enabled', () => {
|
|
12
|
+
beforeEach(enableCache);
|
|
13
|
+
afterEach(disableCache);
|
|
14
|
+
|
|
15
|
+
const cacheKey = ['user', 'get', user11.userId];
|
|
16
|
+
|
|
17
|
+
test('it should return true if data added to cache', () => {
|
|
18
|
+
const recieved = pushToCache(cacheKey, user11);
|
|
19
|
+
|
|
20
|
+
expect(recieved).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('it should add data to cache', () => {
|
|
24
|
+
const returned = pushToCache(cacheKey, user11);
|
|
25
|
+
const recieved = pullFromCache(cacheKey)?.data;
|
|
26
|
+
|
|
27
|
+
expect(returned).toBe(true);
|
|
28
|
+
expect(recieved).toBe(user11);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('it should persist data offline', () => {
|
|
32
|
+
const { cache } = getActiveClient();
|
|
33
|
+
const encodedKey = encodeKey(cacheKey);
|
|
34
|
+
const options = { offline: true, cachedAt: Date.now() };
|
|
35
|
+
|
|
36
|
+
const addedUser = pushToCache(cacheKey, user11, options);
|
|
37
|
+
|
|
38
|
+
const expected = {
|
|
39
|
+
key: cacheKey,
|
|
40
|
+
data: user11,
|
|
41
|
+
...options,
|
|
42
|
+
};
|
|
43
|
+
const recieved = cache?.data[encodedKey];
|
|
44
|
+
|
|
45
|
+
expect(addedUser).toBe(true);
|
|
46
|
+
expect(recieved).toStrictEqual(expected);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('- no cache', () => {
|
|
51
|
+
test('it should return false if no cache', () => {
|
|
52
|
+
const recieved = pushToCache(['model', 'key', 'modleId'], {});
|
|
53
|
+
|
|
54
|
+
expect(recieved).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
});
|
package/src/cache/utils/index.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
// cache constants
|
|
2
|
+
export const CACHE_KEY_GET = 'get';
|
|
3
|
+
export const CACHE_KEY_QUERY = 'query';
|
|
4
|
+
export const CACHE_KEY_TOMBSTONE = 'dead';
|
|
5
|
+
export const CACHE_KEY_COLLECTION = 'collection';
|
|
6
|
+
|
|
7
|
+
export const CACHE_LIFESPAN = 1 * 60 * 1000; // 1 minute
|
|
8
|
+
export const CACHE_LIFESPAN_TOMBSTONE = 3 * 60 * 1000; // 3 minutes
|
|
9
|
+
|
|
1
10
|
/**
|
|
2
11
|
* Shallow-clones an object and sort its keys
|
|
3
12
|
*
|
|
@@ -72,3 +81,16 @@ export const partialMatch = (predicate: any, candidate: any): boolean => {
|
|
|
72
81
|
*/
|
|
73
82
|
export const isCached = <T extends unknown>(obj?: any): obj is Amity.Cached<T> =>
|
|
74
83
|
['data', 'cachedAt'].every(prop => obj?.hasOwnProperty(prop));
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* checks if passed error code is included in
|
|
87
|
+
* Tombstone errors list
|
|
88
|
+
*
|
|
89
|
+
* @param errorCode as {@link Amity.ServerError}
|
|
90
|
+
* @returns success boolean if the given errorCode
|
|
91
|
+
* is included in Tombstone errors list
|
|
92
|
+
*
|
|
93
|
+
* @category Cache
|
|
94
|
+
*/
|
|
95
|
+
export const checkIfShouldGoesToTombstone = (errorCode: Amity.ServerError): boolean =>
|
|
96
|
+
[Amity.ServerError.ITEM_NOT_FOUND, Amity.ServerError.FORBIDDEN].includes(errorCode);
|
|
@@ -36,7 +36,15 @@ export const addChannelMembers = async (
|
|
|
36
36
|
|
|
37
37
|
if (client.cache) ingestInCache(data);
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
/*
|
|
40
|
+
* should fire event for each user that was added
|
|
41
|
+
*/
|
|
42
|
+
userIds.forEach(id =>
|
|
43
|
+
fireEvent('v3.channel.didAddUsers', {
|
|
44
|
+
...data,
|
|
45
|
+
channelUsers: data.channelUsers.filter(u => u.userId === id),
|
|
46
|
+
}),
|
|
47
|
+
);
|
|
40
48
|
|
|
41
49
|
const { channelUsers } = data;
|
|
42
50
|
return !!channelUsers.find(
|
|
@@ -3,6 +3,10 @@ import { getActiveClient } from '~/client/api';
|
|
|
3
3
|
import { pullFromCache } from '~/cache/api';
|
|
4
4
|
import { ingestInCache } from '~/cache/api/ingestInCache';
|
|
5
5
|
|
|
6
|
+
import { isInTombstone } from '~/cache/api/isInTombstone';
|
|
7
|
+
import { checkIfShouldGoesToTombstone } from '~/cache/utils';
|
|
8
|
+
import { pushToTombstone } from '~/cache/api/pushToTombstone';
|
|
9
|
+
|
|
6
10
|
import { prepareChannelPayload } from '../utils';
|
|
7
11
|
|
|
8
12
|
/**
|
|
@@ -25,12 +29,23 @@ export const getChannel = async (
|
|
|
25
29
|
const client = getActiveClient();
|
|
26
30
|
client.log('channel/getChannel', channelId);
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
isInTombstone('channel', channelId);
|
|
33
|
+
|
|
34
|
+
let data: Amity.ChannelPayload<any, Amity.Channel>;
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const { data: payload } = await client.http.get<Amity.ChannelPayload>(
|
|
38
|
+
`/api/v3/channels/${encodeURIComponent(channelId)}`,
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
data = prepareChannelPayload(payload);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
if (checkIfShouldGoesToTombstone((error as Amity.ErrorResponse)?.code)) {
|
|
44
|
+
pushToTombstone('channel', channelId);
|
|
45
|
+
}
|
|
32
46
|
|
|
33
|
-
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
34
49
|
|
|
35
50
|
const cachedAt = client.cache && Date.now();
|
|
36
51
|
if (client.cache) ingestInCache(data, { cachedAt });
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { getActiveClient } from '~/client/api';
|
|
2
2
|
|
|
3
3
|
import { toPage, toToken } from '~/core/query';
|
|
4
|
+
import { getResolver } from '~/core/model';
|
|
5
|
+
|
|
6
|
+
import { pullFromCache, pushToCache } from '~/cache/api';
|
|
4
7
|
import { ingestInCache } from '~/cache/api/ingestInCache';
|
|
5
8
|
|
|
6
9
|
import { prepareChannelPayload } from '../utils';
|
|
@@ -25,11 +28,11 @@ export const queryChannelMembers = async (
|
|
|
25
28
|
const client = getActiveClient();
|
|
26
29
|
client.log('channel/queryChannelMembers', query);
|
|
27
30
|
|
|
28
|
-
const { page
|
|
31
|
+
const { page = { limit: 10 }, ...params } = query ?? {};
|
|
29
32
|
|
|
30
33
|
const { data: queryPayload } = await client.http.get<
|
|
31
34
|
Amity.ChannelMembershipPayload & Amity.Pagination
|
|
32
|
-
>(`/api/v4/channels/${encodeURIComponent(channelId)}/users`, {
|
|
35
|
+
>(`/api/v4/channels/${encodeURIComponent(params.channelId)}/users`, {
|
|
33
36
|
params: {
|
|
34
37
|
...params,
|
|
35
38
|
options: {
|
|
@@ -47,6 +50,19 @@ export const queryChannelMembers = async (
|
|
|
47
50
|
const cachedAt = client.cache && Date.now();
|
|
48
51
|
if (client.cache) {
|
|
49
52
|
ingestInCache(data as Amity.ChannelMembershipPayload);
|
|
53
|
+
|
|
54
|
+
const cacheKey = [
|
|
55
|
+
'channelUsers',
|
|
56
|
+
'query',
|
|
57
|
+
{ ...params, options: { ...page } } as Amity.Serializable,
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
pushToCache(cacheKey, {
|
|
61
|
+
channelUsers: channelUsers.map(({ channelId, userId }) =>
|
|
62
|
+
getResolver('channelUsers')({ channelId, userId }),
|
|
63
|
+
),
|
|
64
|
+
paging,
|
|
65
|
+
});
|
|
50
66
|
}
|
|
51
67
|
|
|
52
68
|
const nextPage = toPage(paging.next);
|
|
@@ -68,9 +84,41 @@ export const queryChannelMembers = async (
|
|
|
68
84
|
*
|
|
69
85
|
* @category Post API
|
|
70
86
|
*/
|
|
71
|
-
queryChannelMembers.locally = (
|
|
87
|
+
queryChannelMembers.locally = (
|
|
88
|
+
query: Parameters<typeof queryChannelMembers>[0],
|
|
89
|
+
): Amity.Cached<Amity.Paged<Amity.Membership<'channel'>>> | undefined => {
|
|
72
90
|
const client = getActiveClient();
|
|
73
|
-
client.log('channel/queryChannelMembers', query);
|
|
91
|
+
client.log('channel/queryChannelMembers.locally', query);
|
|
92
|
+
|
|
93
|
+
if (!client.cache) return;
|
|
94
|
+
|
|
95
|
+
const { page = { limit: 10 }, ...params } = query;
|
|
96
|
+
|
|
97
|
+
const cacheKey = [
|
|
98
|
+
'channelUsers',
|
|
99
|
+
'query',
|
|
100
|
+
{ ...params, options: { ...page } } as Amity.Serializable,
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
const { data, cachedAt } =
|
|
104
|
+
pullFromCache<
|
|
105
|
+
{
|
|
106
|
+
channelUsers: Pick<Amity.Membership<'channel'>, 'channelId' | 'userId'>[];
|
|
107
|
+
} & Amity.Pagination
|
|
108
|
+
>(cacheKey) ?? {};
|
|
109
|
+
|
|
110
|
+
if (!data?.channelUsers.length) return;
|
|
111
|
+
|
|
112
|
+
const channelUsers: Amity.Membership<'channel'>[] = data.channelUsers
|
|
113
|
+
// ck -> cacheKey, abbrevated to avoid confusion from the above cache key
|
|
114
|
+
.map(ck => pullFromCache<Amity.Membership<'channel'>>(['channelUsers', 'get', ck])!)
|
|
115
|
+
.filter(Boolean)
|
|
116
|
+
.map(({ data }) => data);
|
|
117
|
+
|
|
118
|
+
const prevPage = toPage(data?.paging.previous);
|
|
119
|
+
const nextPage = toPage(data?.paging.next);
|
|
74
120
|
|
|
75
|
-
|
|
121
|
+
return channelUsers.length === data?.channelUsers?.length
|
|
122
|
+
? { data: channelUsers, cachedAt, prevPage, nextPage }
|
|
123
|
+
: undefined;
|
|
76
124
|
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { getActiveClient } from '~/client/api';
|
|
2
2
|
|
|
3
3
|
import { toPage, toToken } from '~/core/query';
|
|
4
|
-
import { pushToCache } from '~/cache/api';
|
|
5
|
-
import { ingestInCache } from '~/cache/api/ingestInCache';
|
|
6
4
|
import { getResolver } from '~/core/model';
|
|
7
5
|
|
|
6
|
+
import { pushToCache, pullFromCache } from '~/cache/api';
|
|
7
|
+
import { ingestInCache } from '~/cache/api/ingestInCache';
|
|
8
|
+
|
|
8
9
|
import { prepareChannelPayload } from '../utils';
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -86,9 +87,35 @@ export const queryChannels = async (
|
|
|
86
87
|
*
|
|
87
88
|
* @category Channel API
|
|
88
89
|
*/
|
|
89
|
-
queryChannels.locally = (
|
|
90
|
+
queryChannels.locally = (
|
|
91
|
+
query?: Parameters<typeof queryChannels>[0],
|
|
92
|
+
): Amity.Cached<Amity.Paged<Amity.Channel>> | undefined => {
|
|
90
93
|
const client = getActiveClient();
|
|
91
94
|
client.log('channel/queryChannels.locally', query);
|
|
92
95
|
|
|
93
|
-
|
|
96
|
+
const { page = { limit: 10 }, ...params } = query ?? {};
|
|
97
|
+
|
|
98
|
+
const cacheKey = ['channel', 'query', { ...params, options: { ...page } } as Amity.Serializable];
|
|
99
|
+
|
|
100
|
+
const { data, cachedAt } =
|
|
101
|
+
pullFromCache<
|
|
102
|
+
{
|
|
103
|
+
channels: Pick<Amity.Channel, 'channelId'>[];
|
|
104
|
+
} & Amity.Pagination
|
|
105
|
+
>(cacheKey) ?? {};
|
|
106
|
+
|
|
107
|
+
if (!data?.channels.length) return;
|
|
108
|
+
|
|
109
|
+
const channels: Amity.Channel[] = data.channels
|
|
110
|
+
// ck -> cacheKey, abbrevated to avoid confusion from the above cache key
|
|
111
|
+
.map(ck => pullFromCache<Amity.Channel>(['channel', 'get', ck])!)
|
|
112
|
+
.filter(Boolean)
|
|
113
|
+
.map(({ data }) => data);
|
|
114
|
+
|
|
115
|
+
const prevPage = toPage(data?.paging.previous);
|
|
116
|
+
const nextPage = toPage(data?.paging.next);
|
|
117
|
+
|
|
118
|
+
return channels.length === data?.channels?.length
|
|
119
|
+
? { data: channels, cachedAt, prevPage, nextPage }
|
|
120
|
+
: undefined;
|
|
94
121
|
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { getResolver } from '~/core/model';
|
|
2
|
+
import { pullFromCache, enableCache, disableCache } from '~/cache/api';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
client,
|
|
6
|
+
pause,
|
|
7
|
+
channelUserQueryResponse,
|
|
8
|
+
channelUser1,
|
|
9
|
+
channelUser3,
|
|
10
|
+
channel11,
|
|
11
|
+
} from '~/utils/tests';
|
|
12
|
+
|
|
13
|
+
import { onChannelMemberAdded } from '~/channel/events';
|
|
14
|
+
import { addChannelMembers } from '../addChannelMembers';
|
|
15
|
+
|
|
16
|
+
describe('addChannelMembers', () => {
|
|
17
|
+
const { channelId } = channelUserQueryResponse.data.channels[0];
|
|
18
|
+
const { userId } = channelUser1;
|
|
19
|
+
|
|
20
|
+
test('it should add channel members in channel', async () => {
|
|
21
|
+
client.http.post = jest.fn().mockResolvedValueOnce(channelUserQueryResponse);
|
|
22
|
+
|
|
23
|
+
const recieved = await addChannelMembers(channelId, [userId]);
|
|
24
|
+
|
|
25
|
+
expect(recieved).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('it should update cache with channel members', async () => {
|
|
29
|
+
enableCache();
|
|
30
|
+
|
|
31
|
+
client.http.post = jest.fn().mockResolvedValueOnce(channelUserQueryResponse);
|
|
32
|
+
|
|
33
|
+
const channelUserCacheKey = getResolver('channelUsers')({
|
|
34
|
+
channelId,
|
|
35
|
+
userId,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const recieved = await addChannelMembers(channelId, [userId]);
|
|
39
|
+
const channelUser = pullFromCache<Amity.Membership<'channel'>>([
|
|
40
|
+
'channelUsers',
|
|
41
|
+
'get',
|
|
42
|
+
channelUserCacheKey,
|
|
43
|
+
])?.data;
|
|
44
|
+
|
|
45
|
+
expect(recieved).toBe(true);
|
|
46
|
+
expect(channelUser).toBeDefined();
|
|
47
|
+
expect(channelUser).toBe(channelUser1);
|
|
48
|
+
|
|
49
|
+
disableCache();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('it should fire event when new members added', async () => {
|
|
53
|
+
expect.assertions(1);
|
|
54
|
+
|
|
55
|
+
client.http.post = jest.fn().mockResolvedValueOnce(channelUserQueryResponse);
|
|
56
|
+
let dispose;
|
|
57
|
+
|
|
58
|
+
const callback = new Promise(resolve => {
|
|
59
|
+
dispose = onChannelMemberAdded(resolve);
|
|
60
|
+
}).finally(dispose);
|
|
61
|
+
|
|
62
|
+
await addChannelMembers(channelId, [userId]);
|
|
63
|
+
|
|
64
|
+
return expect(callback).resolves.not.toThrow();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('it should fire event with all new members', async () => {
|
|
68
|
+
client.http.post = jest.fn().mockResolvedValueOnce(channelUserQueryResponse);
|
|
69
|
+
|
|
70
|
+
const callback = jest.fn();
|
|
71
|
+
const { userId: userId2 } = channelUser3;
|
|
72
|
+
const unsub = onChannelMemberAdded(callback);
|
|
73
|
+
|
|
74
|
+
const recieved = await addChannelMembers(channelId, [userId, userId2]);
|
|
75
|
+
|
|
76
|
+
expect(recieved).toBe(true);
|
|
77
|
+
|
|
78
|
+
await pause();
|
|
79
|
+
|
|
80
|
+
/*
|
|
81
|
+
* Assertion below is required to check if the event handler is called with the right
|
|
82
|
+
* params. It's not enough to check if the handler does not throw
|
|
83
|
+
*/
|
|
84
|
+
expect(callback).toHaveBeenNthCalledWith(1, { ...channel11 }, { ...channelUser1 });
|
|
85
|
+
expect(callback).toHaveBeenNthCalledWith(2, { ...channel11 }, { ...channelUser3 });
|
|
86
|
+
|
|
87
|
+
unsub();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('it should return an error', async () => {
|
|
91
|
+
client.http.post = jest.fn().mockRejectedValueOnce(new Error('error'));
|
|
92
|
+
|
|
93
|
+
await expect(addChannelMembers('channelId', [])).rejects.toThrow('error');
|
|
94
|
+
});
|
|
95
|
+
});
|