@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.
Files changed (233) hide show
  1. package/dist/@types/core/cache.d.ts +3 -0
  2. package/dist/@types/core/cache.d.ts.map +1 -1
  3. package/dist/@types/core/errors.d.ts +2 -1
  4. package/dist/@types/core/errors.d.ts.map +1 -1
  5. package/dist/@types/core/events.d.ts +2 -0
  6. package/dist/@types/core/events.d.ts.map +1 -1
  7. package/dist/@types/core/live.d.ts +8 -4
  8. package/dist/@types/core/live.d.ts.map +1 -1
  9. package/dist/@types/core/query.d.ts +1 -1
  10. package/dist/@types/core/query.d.ts.map +1 -1
  11. package/dist/@types/domains/channel.d.ts +1 -0
  12. package/dist/@types/domains/channel.d.ts.map +1 -1
  13. package/dist/@types/domains/message.d.ts +13 -6
  14. package/dist/@types/domains/message.d.ts.map +1 -1
  15. package/dist/@types/domains/post.d.ts +10 -3
  16. package/dist/@types/domains/post.d.ts.map +1 -1
  17. package/dist/@types/domains/user.d.ts +1 -0
  18. package/dist/@types/domains/user.d.ts.map +1 -1
  19. package/dist/@types/index.d.ts +2 -2
  20. package/dist/@types/index.d.ts.map +1 -1
  21. package/dist/cache/api/backupCache.d.ts.map +1 -1
  22. package/dist/cache/api/isInTombstone.d.ts +18 -0
  23. package/dist/cache/api/isInTombstone.d.ts.map +1 -0
  24. package/dist/cache/api/pushToTombstone.d.ts +17 -0
  25. package/dist/cache/api/pushToTombstone.d.ts.map +1 -0
  26. package/dist/cache/api/tests/pushToCache.test.d.ts +2 -0
  27. package/dist/cache/api/tests/pushToCache.test.d.ts.map +1 -0
  28. package/dist/cache/utils/index.d.ts +17 -0
  29. package/dist/cache/utils/index.d.ts.map +1 -1
  30. package/dist/channel/api/addChannelMembers.d.ts.map +1 -1
  31. package/dist/channel/api/getChannel.d.ts.map +1 -1
  32. package/dist/channel/api/queryChannelMembers.d.ts +1 -1
  33. package/dist/channel/api/queryChannelMembers.d.ts.map +1 -1
  34. package/dist/channel/api/queryChannels.d.ts +1 -1
  35. package/dist/channel/api/queryChannels.d.ts.map +1 -1
  36. package/dist/channel/api/tests/addChannelMembers.test.d.ts +2 -0
  37. package/dist/channel/api/tests/addChannelMembers.test.d.ts.map +1 -0
  38. package/dist/channel/api/tests/getChannel.test.d.ts +2 -0
  39. package/dist/channel/api/tests/getChannel.test.d.ts.map +1 -0
  40. package/dist/channel/api/tests/queryChannelMembers.test.d.ts +2 -0
  41. package/dist/channel/api/tests/queryChannelMembers.test.d.ts.map +1 -0
  42. package/dist/channel/api/tests/queryChannels.test.d.ts +2 -0
  43. package/dist/channel/api/tests/queryChannels.test.d.ts.map +1 -0
  44. package/dist/channel/events/index.d.ts +2 -0
  45. package/dist/channel/events/index.d.ts.map +1 -1
  46. package/dist/channel/events/onChannelMemberAdded.d.ts.map +1 -1
  47. package/dist/channel/events/onChannelMemberBanned.d.ts +17 -0
  48. package/dist/channel/events/onChannelMemberBanned.d.ts.map +1 -0
  49. package/dist/channel/events/onChannelMemberUnbanned.d.ts +17 -0
  50. package/dist/channel/events/onChannelMemberUnbanned.d.ts.map +1 -0
  51. package/dist/channel/events/tests/onChannelMemberBanned.test.d.ts +2 -0
  52. package/dist/channel/events/tests/onChannelMemberBanned.test.d.ts.map +1 -0
  53. package/dist/channel/events/tests/onChannelMemberUnbanned.test.d.ts +2 -0
  54. package/dist/channel/events/tests/onChannelMemberUnbanned.test.d.ts.map +1 -0
  55. package/dist/channel/observers/liveChannelMembers.d.ts.map +1 -1
  56. package/dist/channel/observers/liveChannels.d.ts.map +1 -1
  57. package/dist/channel/{tests/utils → utils/tests}/prepareChannelPayload.test.d.ts +0 -0
  58. package/dist/channel/utils/tests/prepareChannelPayload.test.d.ts.map +1 -0
  59. package/dist/core/events.d.ts +3 -3
  60. package/dist/core/events.d.ts.map +1 -1
  61. package/dist/core/query/filtering.d.ts +11 -0
  62. package/dist/core/query/filtering.d.ts.map +1 -1
  63. package/dist/core/query/query.d.ts.map +1 -1
  64. package/dist/core/transports/http.d.ts +5 -0
  65. package/dist/core/transports/http.d.ts.map +1 -1
  66. package/dist/core/transports/test/http.test.d.ts +2 -0
  67. package/dist/core/transports/test/http.test.d.ts.map +1 -0
  68. package/dist/index.cjs.js +980 -534
  69. package/dist/index.esm.js +962 -526
  70. package/dist/index.umd.js +4 -4
  71. package/dist/message/api/createMessage.d.ts +4 -1
  72. package/dist/message/api/createMessage.d.ts.map +1 -1
  73. package/dist/message/api/deleteMessage.d.ts.map +1 -1
  74. package/dist/message/api/getMessage.d.ts +1 -1
  75. package/dist/message/api/getMessage.d.ts.map +1 -1
  76. package/dist/message/api/getMessages.d.ts.map +1 -1
  77. package/dist/message/api/queryMessages.d.ts.map +1 -1
  78. package/dist/message/api/tests/createMessage.test.d.ts +2 -0
  79. package/dist/message/api/tests/createMessage.test.d.ts.map +1 -0
  80. package/dist/message/api/tests/deleteMessage.test.d.ts +2 -0
  81. package/dist/message/api/tests/deleteMessage.test.d.ts.map +1 -0
  82. package/dist/message/api/tests/getMessage.test.d.ts +2 -0
  83. package/dist/message/api/tests/getMessage.test.d.ts.map +1 -0
  84. package/dist/message/api/tests/getMessages.test.d.ts +2 -0
  85. package/dist/message/api/tests/getMessages.test.d.ts.map +1 -0
  86. package/dist/message/api/tests/queryMessages.test.d.ts +2 -0
  87. package/dist/message/api/tests/queryMessages.test.d.ts.map +1 -0
  88. package/dist/message/api/tests/updateMessage.test.d.ts +2 -0
  89. package/dist/message/api/tests/updateMessage.test.d.ts.map +1 -0
  90. package/dist/message/api/updateMessage.d.ts.map +1 -1
  91. package/dist/message/events/index.d.ts +1 -0
  92. package/dist/message/events/index.d.ts.map +1 -1
  93. package/dist/message/events/onMessageFetched.d.ts +17 -0
  94. package/dist/message/events/onMessageFetched.d.ts.map +1 -0
  95. package/dist/message/observers/index.d.ts +2 -1
  96. package/dist/message/observers/index.d.ts.map +1 -1
  97. package/dist/message/observers/liveMessage.d.ts +18 -0
  98. package/dist/message/observers/liveMessage.d.ts.map +1 -0
  99. package/dist/message/observers/liveMessages.d.ts.map +1 -1
  100. package/dist/message/observers/observeMessage.d.ts.map +1 -1
  101. package/dist/message/tests/observers/liveMessage.test.d.ts +2 -0
  102. package/dist/message/tests/observers/liveMessage.test.d.ts.map +1 -0
  103. package/dist/message/{observers/tests → tests/observers}/liveMessages.test.d.ts +0 -0
  104. package/dist/message/tests/observers/liveMessages.test.d.ts.map +1 -0
  105. package/dist/post/api/deletePost.d.ts.map +1 -1
  106. package/dist/post/api/getPost.d.ts.map +1 -1
  107. package/dist/post/api/updatePost.d.ts +6 -1
  108. package/dist/post/api/updatePost.d.ts.map +1 -1
  109. package/dist/reaction/api/addReaction.d.ts.map +1 -1
  110. package/dist/reaction/api/removeReaction.d.ts.map +1 -1
  111. package/dist/reaction/api/tests/addReaction.test.d.ts +2 -0
  112. package/dist/reaction/api/tests/addReaction.test.d.ts.map +1 -0
  113. package/dist/reaction/api/tests/removeReaction.test.d.ts +2 -0
  114. package/dist/reaction/api/tests/removeReaction.test.d.ts.map +1 -0
  115. package/dist/user/api/getUser.d.ts +1 -1
  116. package/dist/user/api/getUser.d.ts.map +1 -1
  117. package/dist/user/api/getUsers.d.ts.map +1 -1
  118. package/dist/user/api/queryUsers.d.ts.map +1 -1
  119. package/dist/user/api/tests/queryUsers.test.d.ts +2 -0
  120. package/dist/user/api/tests/queryUsers.test.d.ts.map +1 -0
  121. package/dist/user/api/updateUser.d.ts.map +1 -1
  122. package/dist/user/events/index.d.ts +1 -0
  123. package/dist/user/events/index.d.ts.map +1 -1
  124. package/dist/user/events/onUserFetched.d.ts +17 -0
  125. package/dist/user/events/onUserFetched.d.ts.map +1 -0
  126. package/dist/user/observers/index.d.ts +1 -0
  127. package/dist/user/observers/index.d.ts.map +1 -1
  128. package/dist/user/observers/liveUser.d.ts +18 -0
  129. package/dist/user/observers/liveUser.d.ts.map +1 -0
  130. package/dist/user/observers/observeUser.d.ts.map +1 -1
  131. package/dist/user/tests/api/getUser.test.d.ts +2 -0
  132. package/dist/user/tests/api/getUser.test.d.ts.map +1 -0
  133. package/dist/user/tests/observers/liveUser.test.d.ts +2 -0
  134. package/dist/user/tests/observers/liveUser.test.d.ts.map +1 -0
  135. package/dist/utils/constants.d.ts +3 -0
  136. package/dist/utils/constants.d.ts.map +1 -1
  137. package/dist/utils/tests/dummy/channel.d.ts +15 -0
  138. package/dist/utils/tests/dummy/channel.d.ts.map +1 -1
  139. package/dist/utils/tests/dummy/message.d.ts +12 -1
  140. package/dist/utils/tests/dummy/message.d.ts.map +1 -1
  141. package/dist/utils/tests/dummy/post.d.ts +12 -1
  142. package/dist/utils/tests/dummy/post.d.ts.map +1 -1
  143. package/dist/utils/tests/dummy/user.d.ts +10 -0
  144. package/dist/utils/tests/dummy/user.d.ts.map +1 -1
  145. package/package.json +2 -1
  146. package/src/@types/core/cache.ts +4 -0
  147. package/src/@types/core/errors.ts +1 -0
  148. package/src/@types/core/events.ts +2 -0
  149. package/src/@types/core/live.ts +10 -4
  150. package/src/@types/core/query.ts +1 -1
  151. package/src/@types/domains/channel.ts +6 -0
  152. package/src/@types/domains/message.ts +13 -10
  153. package/src/@types/domains/post.ts +10 -3
  154. package/src/@types/domains/user.ts +8 -0
  155. package/src/@types/index.ts +2 -2
  156. package/src/cache/api/backupCache.ts +0 -1
  157. package/src/cache/api/index.ts +2 -1
  158. package/src/cache/api/isInTombstone.ts +41 -0
  159. package/src/cache/api/pushToTombstone.ts +33 -0
  160. package/src/cache/api/tests/pushToCache.test.ts +57 -0
  161. package/src/cache/utils/index.ts +22 -0
  162. package/src/channel/api/addChannelMembers.ts +9 -1
  163. package/src/channel/api/getChannel.ts +20 -5
  164. package/src/channel/api/queryChannelMembers.ts +53 -5
  165. package/src/channel/api/queryChannels.ts +31 -4
  166. package/src/channel/api/tests/addChannelMembers.test.ts +95 -0
  167. package/src/channel/api/tests/getChannel.test.ts +108 -0
  168. package/src/channel/api/tests/queryChannelMembers.test.ts +115 -0
  169. package/src/channel/api/tests/queryChannels.test.ts +121 -0
  170. package/src/channel/events/index.ts +5 -0
  171. package/src/channel/events/onChannelMemberAdded.ts +1 -1
  172. package/src/channel/events/onChannelMemberBanned.ts +36 -0
  173. package/src/channel/events/onChannelMemberUnbanned.ts +36 -0
  174. package/src/channel/events/tests/onChannelMemberBanned.test.ts +58 -0
  175. package/src/channel/events/tests/onChannelMemberUnbanned.test.ts +58 -0
  176. package/src/channel/observers/liveChannelMembers.ts +28 -4
  177. package/src/channel/observers/liveChannels.ts +7 -1
  178. package/src/channel/observers/tests/liveChannelMembers.test.ts +53 -11
  179. package/src/channel/observers/tests/liveChannels.test.ts +50 -21
  180. package/src/channel/{tests/utils → utils/tests}/prepareChannelPayload.test.ts +1 -1
  181. package/src/core/events.ts +2 -1
  182. package/src/core/query/filtering.ts +49 -0
  183. package/src/core/query/query.ts +9 -6
  184. package/src/core/tests/query/query.test.ts +12 -2
  185. package/src/core/transports/http.ts +3 -17
  186. package/src/core/transports/test/http.test.ts +83 -0
  187. package/src/message/api/createMessage.ts +15 -9
  188. package/src/message/api/deleteMessage.ts +4 -4
  189. package/src/message/api/getMessage.ts +32 -4
  190. package/src/message/api/getMessages.ts +6 -1
  191. package/src/message/api/queryMessages.ts +3 -0
  192. package/src/message/api/tests/createMessage.test.ts +99 -0
  193. package/src/message/api/tests/deleteMessage.test.ts +110 -0
  194. package/src/message/api/tests/getMessage.test.ts +121 -0
  195. package/src/message/api/tests/getMessages.test.ts +108 -0
  196. package/src/message/api/tests/queryMessages.test.ts +115 -0
  197. package/src/message/api/tests/updateMessage.test.ts +100 -0
  198. package/src/message/api/updateMessage.ts +2 -0
  199. package/src/message/events/index.ts +1 -0
  200. package/src/message/events/onMessageFetched.ts +30 -0
  201. package/src/message/observers/index.ts +2 -1
  202. package/src/message/observers/liveMessage.ts +100 -0
  203. package/src/message/observers/liveMessages.ts +3 -1
  204. package/src/message/observers/observeMessage.ts +4 -0
  205. package/src/message/tests/observers/liveMessage.test.ts +248 -0
  206. package/src/message/{observers/tests → tests/observers}/liveMessages.test.ts +29 -3
  207. package/src/post/api/deletePost.ts +4 -3
  208. package/src/post/api/getPost.ts +8 -4
  209. package/src/post/api/updatePost.ts +6 -1
  210. package/src/post/tests/api/queryPosts.test.ts +117 -18
  211. package/src/reaction/api/addReaction.ts +1 -4
  212. package/src/reaction/api/removeReaction.ts +1 -4
  213. package/src/reaction/api/tests/addReaction.test.ts +37 -0
  214. package/src/reaction/api/tests/removeReaction.test.ts +43 -0
  215. package/src/user/api/getUser.ts +32 -5
  216. package/src/user/api/getUsers.ts +3 -0
  217. package/src/user/api/queryUsers.ts +27 -5
  218. package/src/user/api/tests/queryUsers.test.ts +124 -0
  219. package/src/user/api/updateUser.ts +3 -0
  220. package/src/user/events/index.ts +1 -0
  221. package/src/user/events/onUserFetched.ts +19 -0
  222. package/src/user/observers/index.ts +1 -0
  223. package/src/user/observers/liveUser.ts +89 -0
  224. package/src/user/observers/observeUser.ts +2 -0
  225. package/src/user/tests/api/getUser.test.ts +112 -0
  226. package/src/user/tests/observers/liveUser.test.ts +224 -0
  227. package/src/utils/constants.ts +5 -0
  228. package/src/utils/tests/dummy/channel.ts +43 -0
  229. package/src/utils/tests/dummy/message.ts +16 -2
  230. package/src/utils/tests/dummy/post.ts +26 -3
  231. package/src/utils/tests/dummy/user.ts +11 -0
  232. package/dist/channel/tests/utils/prepareChannelPayload.test.d.ts.map +0 -1
  233. package/dist/message/observers/tests/liveMessages.test.d.ts.map +0 -1
@@ -2,12 +2,18 @@ export {};
2
2
 
3
3
  declare global {
4
4
  namespace Amity {
5
- type LiveCollection<T extends any> = {
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>>;
@@ -33,7 +33,7 @@ declare global {
33
33
  args: Args;
34
34
  };
35
35
 
36
- type QueryPolicy = 'server_only' | 'cache_only' | 'cache_then_server' | 'no_fetch';
36
+ type QueryPolicy = 'cache_only' | 'cache_then_server' | 'no_fetch';
37
37
 
38
38
  type QueryOptions = {
39
39
  lifeSpan: number;
@@ -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 = 'text' | 'file' | 'image' | 'video' | 'audio' | 'custom';
12
+ type MessageContentType = ValueOf<typeof MessageContentType>;
6
13
 
7
- type MessageContent<T extends Amity.MessageContentType = any> = T extends
8
- | 'file'
9
- | 'image'
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 = 'text' | 'image' | 'file' | 'video' | 'liveStream' | 'poll';
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?: string;
56
+ dataType?: Exclude<Amity.PostContentType, 'text'>;
50
57
  isDeleted?: Amity.Post['isDeleted'];
51
58
  hasFlag?: boolean;
52
59
  feedType?: 'reviewing' | 'published';
@@ -2,6 +2,14 @@ export {};
2
2
 
3
3
  declare global {
4
4
  namespace Amity {
5
+ type UserActionType =
6
+ | 'onFetch'
7
+ | 'onUpdate'
8
+ | 'onDelete'
9
+ | 'onFlagged'
10
+ | 'onUnflagged'
11
+ | 'onFlagCleared';
12
+
5
13
  type User = {
6
14
  _id: string;
7
15
  userId: string;
@@ -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';
@@ -1,4 +1,3 @@
1
- /* eslint-disable @typescript-eslint/no-unused-vars */
2
1
  import AsyncStorage from '@react-native-async-storage/async-storage';
3
2
 
4
3
  import { getActiveClient } from '~/client/api/activeClient';
@@ -18,6 +18,7 @@ export * from './upsertInCache';
18
18
  export * from './dropFromCache';
19
19
 
20
20
  /*
21
- * ingestInCache and syncInCache are not exported ;
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
+ });
@@ -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
- fireEvent('v3.channel.didAddUsers', data);
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
- // API-FIX: endpoint should not be /list, parameters should be querystring.
29
- const { data: payload } = await client.http.get<Amity.ChannelPayload>(
30
- `/api/v3/channels/${encodeURIComponent(channelId)}`,
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
- const data = prepareChannelPayload(payload);
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, channelId, ...params } = query ?? {};
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 = (query: Parameters<typeof queryChannelMembers>[0]) => {
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
- // TODO
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 = (query: Parameters<typeof queryChannels>[0]) => {
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
- // TODO
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
+ });