@amityco/ts-sdk 0.0.1-beta.37 → 0.0.1-beta.39

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 (251) hide show
  1. package/.eslintrc.json +3 -5
  2. package/dist/@types/core/events.d.ts +1 -0
  3. package/dist/@types/core/events.d.ts.map +1 -1
  4. package/dist/@types/core/model.d.ts +2 -0
  5. package/dist/@types/core/model.d.ts.map +1 -1
  6. package/dist/@types/domains/category.d.ts +7 -0
  7. package/dist/@types/domains/category.d.ts.map +1 -1
  8. package/dist/@types/domains/channel.d.ts +2 -2
  9. package/dist/@types/domains/channel.d.ts.map +1 -1
  10. package/dist/@types/domains/community.d.ts +12 -0
  11. package/dist/@types/domains/community.d.ts.map +1 -1
  12. package/dist/@types/domains/feed.d.ts +1 -2
  13. package/dist/@types/domains/feed.d.ts.map +1 -1
  14. package/dist/@types/domains/message.d.ts +1 -1
  15. package/dist/@types/domains/message.d.ts.map +1 -1
  16. package/dist/@types/domains/post.d.ts +1 -1
  17. package/dist/@types/domains/post.d.ts.map +1 -1
  18. package/dist/@types/domains/user.d.ts +8 -0
  19. package/dist/@types/domains/user.d.ts.map +1 -1
  20. package/dist/@types/global.d.ts +5 -0
  21. package/dist/@types/global.d.ts.map +1 -1
  22. package/dist/category/api/queryCategories.d.ts +1 -5
  23. package/dist/category/api/queryCategories.d.ts.map +1 -1
  24. package/dist/category/observers/index.d.ts +2 -0
  25. package/dist/category/observers/index.d.ts.map +1 -0
  26. package/dist/category/observers/liveCategories.d.ts +18 -0
  27. package/dist/category/observers/liveCategories.d.ts.map +1 -0
  28. package/dist/category/observers/tests/liveCategories.test.d.ts +2 -0
  29. package/dist/category/observers/tests/liveCategories.test.d.ts.map +1 -0
  30. package/dist/channel/api/tests/getChannels.test.d.ts +2 -0
  31. package/dist/channel/api/tests/getChannels.test.d.ts.map +1 -0
  32. package/dist/channel/api/tests/leaveChannel.test.d.ts +2 -0
  33. package/dist/channel/api/tests/leaveChannel.test.d.ts.map +1 -0
  34. package/dist/channel/observers/liveChannel.d.ts.map +1 -1
  35. package/dist/channel/observers/liveChannels.d.ts.map +1 -1
  36. package/dist/client/api/accessTokenExpiryWatcher.d.ts +4 -1
  37. package/dist/client/api/accessTokenExpiryWatcher.d.ts.map +1 -1
  38. package/dist/client/api/connectClient.d.ts.map +1 -1
  39. package/dist/client/api/getToken.d.ts +3 -1
  40. package/dist/client/api/getToken.d.ts.map +1 -1
  41. package/dist/client/utils/setClientToken.d.ts +3 -3
  42. package/dist/comment/api/deleteComment.d.ts.map +1 -1
  43. package/dist/comment/api/getComment.d.ts.map +1 -1
  44. package/dist/comment/observers/index.d.ts +1 -0
  45. package/dist/comment/observers/index.d.ts.map +1 -1
  46. package/dist/comment/observers/liveComment.d.ts +21 -0
  47. package/dist/comment/observers/liveComment.d.ts.map +1 -0
  48. package/dist/comment/observers/tests/liveComment.test.d.ts +2 -0
  49. package/dist/comment/observers/tests/liveComment.test.d.ts.map +1 -0
  50. package/dist/community/api/queryCommunities.d.ts +1 -10
  51. package/dist/community/api/queryCommunities.d.ts.map +1 -1
  52. package/dist/community/events/index.d.ts +1 -0
  53. package/dist/community/events/index.d.ts.map +1 -1
  54. package/dist/community/events/onCommunityUserChanged.d.ts +17 -0
  55. package/dist/community/events/onCommunityUserChanged.d.ts.map +1 -0
  56. package/dist/community/events/utils.d.ts +1 -0
  57. package/dist/community/events/utils.d.ts.map +1 -1
  58. package/dist/community/observers/index.d.ts +1 -0
  59. package/dist/community/observers/index.d.ts.map +1 -1
  60. package/dist/community/observers/liveCommunities.d.ts +20 -0
  61. package/dist/community/observers/liveCommunities.d.ts.map +1 -0
  62. package/dist/community/observers/tests/liveCommunities.test.d.ts +2 -0
  63. package/dist/community/observers/tests/liveCommunities.test.d.ts.map +1 -0
  64. package/dist/core/events.d.ts +3 -3
  65. package/dist/core/events.d.ts.map +1 -1
  66. package/dist/core/model/idResolvers.d.ts.map +1 -1
  67. package/dist/core/model/identifyModel.d.ts.map +1 -1
  68. package/dist/core/model/index.d.ts.map +1 -1
  69. package/dist/core/query/filtering.d.ts +10 -0
  70. package/dist/core/query/filtering.d.ts.map +1 -1
  71. package/dist/core/query/paging.d.ts +2 -2
  72. package/dist/core/query/paging.d.ts.map +1 -1
  73. package/dist/core/query/sorting.d.ts +6 -0
  74. package/dist/core/query/sorting.d.ts.map +1 -1
  75. package/dist/core/query/tests/paging.test.d.ts +2 -0
  76. package/dist/core/query/tests/paging.test.d.ts.map +1 -0
  77. package/dist/core/transports/http.d.ts +0 -5
  78. package/dist/core/transports/http.d.ts.map +1 -1
  79. package/dist/file/api/test/createImage.test.d.ts +2 -0
  80. package/dist/file/api/test/createImage.test.d.ts.map +1 -0
  81. package/dist/file/api/test/createVideo.test.d.ts +2 -0
  82. package/dist/file/api/test/createVideo.test.d.ts.map +1 -0
  83. package/dist/index.cjs.js +607 -252
  84. package/dist/index.d.ts +1 -0
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.esm.js +599 -251
  87. package/dist/index.umd.js +4 -4
  88. package/dist/message/api/queryMessages.d.ts +2 -2
  89. package/dist/message/api/queryMessages.d.ts.map +1 -1
  90. package/dist/message/observers/liveMessage.d.ts.map +1 -1
  91. package/dist/post/observers/index.d.ts +1 -0
  92. package/dist/post/observers/index.d.ts.map +1 -1
  93. package/dist/post/observers/livePost.d.ts +21 -0
  94. package/dist/post/observers/livePost.d.ts.map +1 -0
  95. package/dist/post/observers/livePosts.d.ts +2 -2
  96. package/dist/post/observers/livePosts.d.ts.map +1 -1
  97. package/dist/post/observers/tests/livePost.test.d.ts +2 -0
  98. package/dist/post/observers/tests/livePost.test.d.ts.map +1 -0
  99. package/dist/report/api/createReport.d.ts.map +1 -1
  100. package/dist/report/api/deleteReport.d.ts.map +1 -1
  101. package/dist/report/api/tests/createReport.test.d.ts +2 -0
  102. package/dist/report/api/tests/createReport.test.d.ts.map +1 -0
  103. package/dist/report/api/tests/deleteReport.test.d.ts +2 -0
  104. package/dist/report/api/tests/deleteReport.test.d.ts.map +1 -0
  105. package/dist/subChannel/api/tests/deleteSubChannel.test.d.ts +2 -0
  106. package/dist/subChannel/api/tests/deleteSubChannel.test.d.ts.map +1 -0
  107. package/dist/subChannel/api/tests/getSubChannel.test.d.ts +2 -0
  108. package/dist/subChannel/api/tests/getSubChannel.test.d.ts.map +1 -0
  109. package/dist/subChannel/api/tests/getSubChannels.test.d.ts +2 -0
  110. package/dist/subChannel/api/tests/getSubChannels.test.d.ts.map +1 -0
  111. package/dist/subChannel/api/tests/updateSubChannel.test.d.ts +2 -0
  112. package/dist/subChannel/api/tests/updateSubChannel.test.d.ts.map +1 -0
  113. package/dist/subChannel/observers/liveSubChannel.d.ts.map +1 -1
  114. package/dist/user/api/queryUsers.d.ts +1 -6
  115. package/dist/user/api/queryUsers.d.ts.map +1 -1
  116. package/dist/user/api/tests/updateUser.test.d.ts +2 -0
  117. package/dist/user/api/tests/updateUser.test.d.ts.map +1 -0
  118. package/dist/user/observers/index.d.ts +1 -0
  119. package/dist/user/observers/index.d.ts.map +1 -1
  120. package/dist/user/observers/liveUser.d.ts.map +1 -1
  121. package/dist/user/observers/liveUsers.d.ts +18 -0
  122. package/dist/user/observers/liveUsers.d.ts.map +1 -0
  123. package/dist/user/observers/tests/liveUsers.test.d.ts +2 -0
  124. package/dist/user/observers/tests/liveUsers.test.d.ts.map +1 -0
  125. package/dist/utils/liveObject.d.ts +2 -0
  126. package/dist/utils/liveObject.d.ts.map +1 -0
  127. package/dist/utils/tests/dummy/category.d.ts +64 -0
  128. package/dist/utils/tests/dummy/category.d.ts.map +1 -0
  129. package/dist/utils/tests/dummy/channel.d.ts +50 -0
  130. package/dist/utils/tests/dummy/channel.d.ts.map +1 -1
  131. package/dist/utils/tests/dummy/community.d.ts +132 -0
  132. package/dist/utils/tests/dummy/community.d.ts.map +1 -1
  133. package/dist/utils/tests/dummy/feed.d.ts +21 -0
  134. package/dist/utils/tests/dummy/feed.d.ts.map +1 -0
  135. package/dist/utils/tests/dummy/file.d.ts +3 -0
  136. package/dist/utils/tests/dummy/file.d.ts.map +1 -1
  137. package/dist/utils/tests/dummy/index.d.ts +2 -0
  138. package/dist/utils/tests/dummy/index.d.ts.map +1 -1
  139. package/dist/utils/tests/dummy/post.d.ts +11 -0
  140. package/dist/utils/tests/dummy/post.d.ts.map +1 -1
  141. package/dist/utils/tests/dummy/subChannel.d.ts +0 -20
  142. package/dist/utils/tests/dummy/subChannel.d.ts.map +1 -1
  143. package/dist/utils/tests/dummy/user.d.ts +81 -0
  144. package/dist/utils/tests/dummy/user.d.ts.map +1 -1
  145. package/dist/utils/tests/liveObject.test.d.ts +2 -0
  146. package/dist/utils/tests/liveObject.test.d.ts.map +1 -0
  147. package/package.json +4 -4
  148. package/src/@types/core/events.ts +1 -0
  149. package/src/@types/core/model.ts +4 -0
  150. package/src/@types/domains/category.ts +13 -0
  151. package/src/@types/domains/channel.ts +2 -2
  152. package/src/@types/domains/community.ts +25 -0
  153. package/src/@types/domains/feed.ts +1 -3
  154. package/src/@types/domains/message.ts +4 -1
  155. package/src/@types/domains/post.ts +1 -1
  156. package/src/@types/domains/user.ts +14 -0
  157. package/src/@types/global.ts +5 -0
  158. package/src/cache/api/tests/ingestInCache.test.ts +2 -0
  159. package/src/category/api/queryCategories.ts +3 -5
  160. package/src/category/observers/index.ts +1 -0
  161. package/src/category/observers/liveCategories.ts +141 -0
  162. package/src/category/observers/tests/liveCategories.test.ts +147 -0
  163. package/src/channel/api/tests/createChannel.test.ts +30 -6
  164. package/src/channel/api/tests/getChannel.test.ts +3 -1
  165. package/src/channel/api/tests/getChannels.test.ts +97 -0
  166. package/src/channel/api/tests/joinChannel.test.ts +62 -3
  167. package/src/channel/api/tests/leaveChannel.test.ts +90 -0
  168. package/src/channel/api/tests/queryChannels.test.ts +38 -1
  169. package/src/channel/observers/liveChannel.ts +8 -80
  170. package/src/channel/observers/liveChannels.ts +29 -24
  171. package/src/client/api/accessTokenExpiryWatcher.ts +7 -5
  172. package/src/client/api/connectClient.ts +0 -2
  173. package/src/client/api/tests/accessTokenExpiryWatcher.test.ts +8 -5
  174. package/src/comment/api/deleteComment.ts +5 -5
  175. package/src/comment/api/getComment.ts +8 -3
  176. package/src/comment/observers/index.ts +1 -0
  177. package/src/comment/observers/liveComment.ts +43 -0
  178. package/src/comment/observers/tests/liveComment.test.ts +95 -0
  179. package/src/community/api/queryCommunities.ts +3 -10
  180. package/src/community/api/test/addCommunityMember.test.ts +14 -2
  181. package/src/community/api/test/joinCommunity.test.ts +14 -2
  182. package/src/community/api/test/leaveCommunity.test.ts +11 -1
  183. package/src/community/api/test/removeCommunityMembers.test.ts +11 -1
  184. package/src/community/events/index.ts +1 -0
  185. package/src/community/events/onCommunityUserChanged.ts +20 -0
  186. package/src/community/events/test/onCommunityJoined.test.ts +1 -1
  187. package/src/community/events/test/onCommunityUserAdded.test.ts +1 -1
  188. package/src/community/events/test/onCommunityUserBanned.test.ts +1 -1
  189. package/src/community/events/test/onCommunityUserUnbaned.test.ts +1 -1
  190. package/src/community/events/test/utils.test.ts +52 -3
  191. package/src/community/events/utils.ts +49 -0
  192. package/src/community/observers/index.ts +1 -0
  193. package/src/community/observers/liveCommunities.ts +188 -0
  194. package/src/community/observers/tests/liveCommunities.test.ts +284 -0
  195. package/src/core/model/idResolvers.ts +2 -0
  196. package/src/core/model/identifyModel.ts +1 -0
  197. package/src/core/model/index.ts +2 -0
  198. package/src/core/query/filtering.ts +33 -3
  199. package/src/core/query/paging.ts +5 -4
  200. package/src/core/query/sorting.ts +8 -0
  201. package/src/core/query/tests/paging.test.ts +66 -0
  202. package/src/core/transports/http.ts +17 -13
  203. package/src/core/transports/test/http.test.ts +49 -60
  204. package/src/file/api/createFile.ts +1 -1
  205. package/src/file/api/createImage.ts +1 -1
  206. package/src/file/api/createVideo.ts +1 -1
  207. package/src/file/api/test/createImage.test.ts +69 -0
  208. package/src/file/api/test/createVideo.test.ts +81 -0
  209. package/src/index.ts +1 -0
  210. package/src/message/api/queryMessages.ts +7 -7
  211. package/src/message/api/tests/queryMessages.test.ts +6 -6
  212. package/src/message/observers/liveMessage.ts +11 -83
  213. package/src/message/tests/observers/liveMessage.test.ts +1 -143
  214. package/src/message/tests/observers/liveMessages.test.ts +4 -4
  215. package/src/post/observers/index.ts +1 -0
  216. package/src/post/observers/livePost.ts +47 -0
  217. package/src/post/observers/livePosts.ts +14 -22
  218. package/src/post/observers/tests/livePost.test.ts +97 -0
  219. package/src/post/observers/tests/livePosts.test.ts +65 -8
  220. package/src/report/api/createReport.ts +1 -6
  221. package/src/report/api/deleteReport.ts +2 -6
  222. package/src/report/api/tests/createReport.test.ts +93 -0
  223. package/src/report/api/tests/deleteReport.test.ts +93 -0
  224. package/src/stream/api/tests/createStream.test.ts +3 -11
  225. package/src/stream/api/tests/deleteStream.test.ts +5 -3
  226. package/src/subChannel/api/tests/createSubChannel.test.ts +21 -14
  227. package/src/subChannel/api/tests/deleteSubChannel.test.ts +112 -0
  228. package/src/subChannel/api/tests/getSubChannel.test.ts +97 -0
  229. package/src/subChannel/api/tests/getSubChannels.test.ts +97 -0
  230. package/src/subChannel/api/tests/updateSubChannel.test.ts +86 -0
  231. package/src/subChannel/observers/liveSubChannel.ts +6 -56
  232. package/src/subChannel/observers/tests/liveSubChannel.test.ts +0 -82
  233. package/src/user/api/queryUsers.ts +1 -6
  234. package/src/user/api/tests/updateUser.test.ts +60 -0
  235. package/src/user/observers/index.ts +1 -0
  236. package/src/user/observers/liveUser.ts +9 -61
  237. package/src/user/observers/liveUsers.ts +162 -0
  238. package/src/user/observers/tests/liveUsers.test.ts +202 -0
  239. package/src/user/tests/observers/liveUser.test.ts +1 -154
  240. package/src/utils/liveObject.ts +86 -0
  241. package/src/utils/tests/dummy/category.ts +57 -0
  242. package/src/utils/tests/dummy/channel.ts +52 -1
  243. package/src/utils/tests/dummy/community.ts +94 -0
  244. package/src/utils/tests/dummy/feed.ts +13 -0
  245. package/src/utils/tests/dummy/file.ts +32 -0
  246. package/src/utils/tests/dummy/index.ts +3 -0
  247. package/src/utils/tests/dummy/post.ts +62 -47
  248. package/src/utils/tests/dummy/stream.ts +73 -73
  249. package/src/utils/tests/dummy/subChannel.ts +0 -22
  250. package/src/utils/tests/dummy/user.ts +57 -0
  251. package/src/utils/tests/liveObject.test.ts +172 -0
@@ -1,4 +1,3 @@
1
- import { ASCApiError } from '~/core/errors';
2
1
  import { disableCache, enableCache } from '~/cache/api';
3
2
  import {
4
3
  pause,
@@ -30,27 +29,6 @@ describe('liveSubChannel', () => {
30
29
 
31
30
  afterEach(disableCache);
32
31
 
33
- test('should get sub channel', async () => {
34
- const callback = jest.fn();
35
- client.http.get = jest.fn().mockResolvedValue(response);
36
-
37
- liveSubChannel(rawSubChannel.messageFeedId, callback);
38
- await pause();
39
-
40
- expect(callback).toHaveBeenCalledTimes(2);
41
- expect(callback).toHaveBeenNthCalledWith(
42
- 1,
43
- expect.objectContaining({ data: undefined, loading: true }),
44
- );
45
- expect(callback).toHaveBeenNthCalledWith(
46
- 2,
47
- expect.objectContaining({
48
- data: convertFromRaw(rawSubChannel),
49
- loading: false,
50
- }),
51
- );
52
- });
53
-
54
32
  const events: [string, keyof Amity.Events][] = [
55
33
  ['should get update on message-feed.updated event', 'message-feed.updated'],
56
34
  ['should get update on message-feed.deleted event', 'message-feed.deleted'],
@@ -149,64 +127,4 @@ describe('liveSubChannel', () => {
149
127
  );
150
128
  });
151
129
  });
152
-
153
- test('should not get update on api failure', async () => {
154
- const error = new ASCApiError(
155
- 'server error!',
156
- Amity.ServerError.ITEM_NOT_FOUND,
157
- Amity.ErrorLevel.ERROR,
158
- );
159
- const update = {
160
- ...rawSubChannel,
161
- name: 'new name',
162
- updatedAt: getFutureDate(rawSubChannel.updatedAt),
163
- };
164
- const callback = jest.fn();
165
- client.http.get = jest.fn().mockRejectedValue(error);
166
-
167
- liveSubChannel(subChannel.subChannelId, callback);
168
- await pause();
169
- client.emitter.emit('message-feed.updated', { messageFeeds: [update] });
170
- await pause();
171
-
172
- expect(callback).toHaveBeenCalledTimes(2);
173
- expect(callback).toHaveBeenNthCalledWith(
174
- 2,
175
- expect.objectContaining({
176
- data: undefined,
177
- error,
178
- loading: false,
179
- }),
180
- );
181
- });
182
-
183
- test('should not call callback if liveMessage is disposed', async () => {
184
- const update = {
185
- ...rawSubChannel,
186
- name: 'new name',
187
- updatedAt: getFutureDate(rawSubChannel.updatedAt),
188
- };
189
- const callback = jest.fn();
190
- client.http.get = jest.fn().mockResolvedValue(response);
191
-
192
- const dispose = liveSubChannel(subChannel.subChannelId, callback);
193
- await pause();
194
- dispose();
195
- client.emitter.emit('message-feed.updated', { messageFeeds: [update] });
196
- await pause();
197
-
198
- expect(callback).toHaveBeenCalledTimes(2);
199
- });
200
-
201
- test('should not call callback if data is the same', async () => {
202
- const callback = jest.fn();
203
- client.http.get = jest.fn().mockResolvedValue(response);
204
-
205
- liveSubChannel(subChannel.subChannelId, callback);
206
- await pause();
207
- client.emitter.emit('message-feed.updated', { messageFeeds: response.data.messageFeeds });
208
- await pause();
209
-
210
- expect(callback).toHaveBeenCalledTimes(2);
211
- });
212
130
  });
@@ -23,12 +23,7 @@ import { fireEvent } from '~/core/events';
23
23
  * @async
24
24
  */
25
25
  export const queryUsers = async (
26
- query: {
27
- displayName?: Amity.User['displayName'];
28
- filter?: 'all' | 'flagged';
29
- sortBy?: 'displayName' | 'firstCreated' | 'lastCreated';
30
- page?: Amity.Page;
31
- } = {},
26
+ query: Amity.QueryUsers = {},
32
27
  ): Promise<Amity.Cached<Amity.Paged<Amity.User>>> => {
33
28
  const client = getActiveClient();
34
29
  client.log('user/queryUsers', query);
@@ -0,0 +1,60 @@
1
+ import { disableCache, enableCache, pushToCache, pullFromCache } from '~/cache/api';
2
+
3
+ import { client, userUpdateResponse } from '~/utils/tests';
4
+
5
+ import { updateUser } from '../updateUser';
6
+ import { onUserUpdated } from '../../events/onUserUpdated';
7
+
8
+ describe('updateUser', () => {
9
+ const displayName = 'updated-display-name';
10
+ const userId = 'test-user';
11
+ const avatarCustomUrl = 'updated-avatarUrl';
12
+
13
+ // integration_test_id: a1a8260f-3314-41ba-9f5f-3a96dd52453d
14
+ test('it should return updated user on success', async () => {
15
+ const { users: expected } = userUpdateResponse.data;
16
+ client.http.put = jest.fn().mockResolvedValue(userUpdateResponse);
17
+
18
+ const { data: received } = await updateUser(userId, { displayName, avatarCustomUrl });
19
+
20
+ expect(received).toStrictEqual(expected[0]);
21
+ });
22
+
23
+ // integration_test_id: 67cb7ad8-28a9-4950-a86c-35497bb5212c
24
+ test('it should return 400301 when updating another user', async () => {
25
+ client.http.put = jest.fn().mockRejectedValueOnce(new Error('400301'));
26
+
27
+ await expect(
28
+ updateUser('different-user', { displayName: 'updated-display-name' }),
29
+ ).rejects.toThrow('400301');
30
+ });
31
+
32
+ test('it should update cache with updated user', async () => {
33
+ enableCache();
34
+
35
+ const expected = userUpdateResponse.data.users[0];
36
+ pushToCache(['user', 'get', userId], { ...expected, displayName: 'old-displayName' });
37
+
38
+ client.http.put = jest.fn().mockResolvedValue(userUpdateResponse);
39
+ await updateUser(userId, { displayName, avatarCustomUrl });
40
+
41
+ const received = pullFromCache(['user', 'get', userId])?.data;
42
+
43
+ expect(received).toStrictEqual(expected);
44
+ disableCache();
45
+ });
46
+
47
+ test('it should fire event for updated user', async () => {
48
+ let dispose;
49
+ const { users: expected } = userUpdateResponse.data;
50
+ client.http.put = jest.fn().mockResolvedValue(userUpdateResponse);
51
+
52
+ const callbackPromise = new Promise(resolve => {
53
+ dispose = onUserUpdated(resolve);
54
+ }).finally(dispose);
55
+
56
+ await updateUser(userId, { displayName, avatarCustomUrl });
57
+
58
+ await expect(callbackPromise).resolves.toEqual(expect.objectContaining(expected[0]));
59
+ });
60
+ });
@@ -1,2 +1,3 @@
1
1
  export { liveUser } from './liveUser';
2
+ export { liveUsers } from './liveUsers';
2
3
  export { observeUser } from './observeUser';
@@ -1,9 +1,4 @@
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 { hasUpdates } from '~/core/model';
1
+ import { liveObject } from '~/utils/liveObject';
7
2
  import {
8
3
  onUserDeleted,
9
4
  onUserUpdated,
@@ -37,59 +32,12 @@ export const liveUser = (
37
32
  userId: Amity.User['userId'],
38
33
  callback: Amity.LiveObjectCallback<Amity.User>,
39
34
  ): Amity.Unsubscriber => {
40
- const { log, cache } = getActiveClient();
41
- const timestamp = Date.now();
42
- log(`liveUser(tmpid: ${timestamp}) > listen`);
43
-
44
- if (!cache) {
45
- console.log(LIVE_OBJECT_ENABLE_CACHE_MESSAGE);
46
- }
47
-
48
- let user: Amity.User;
49
- const disposers: Amity.Unsubscriber[] = [];
50
-
51
- const dispatcher = (data: Amity.LiveObject<Amity.User>) => {
52
- user = data.data;
53
- callback(data);
54
- };
55
-
56
- const realtimeRouter = (eventUser: Amity.User) => {
57
- if (userId !== eventUser.userId) {
58
- return;
59
- }
60
-
61
- if (user && !hasUpdates(user, eventUser)) {
62
- return;
63
- }
64
-
65
- dispatcher({ loading: false, data: eventUser, origin: 'event' });
66
- };
67
-
68
- const onFetch = () => {
69
- const query = createQuery(getUser, userId, true);
70
-
71
- runQuery(query, ({ loading, data, error, origin }) => {
72
- dispatcher({ loading, data, origin, error });
73
-
74
- if (error) {
75
- disposers.forEach(fn => fn());
76
- }
77
- });
78
- };
79
-
80
- disposers.push(
81
- onUserFetched(realtimeRouter),
82
- onUserUpdated(realtimeRouter),
83
- onUserDeleted(realtimeRouter),
84
- onUserFlagged(realtimeRouter),
85
- onUserUnflagged(realtimeRouter),
86
- onUserFlagCleared(realtimeRouter),
87
- );
88
-
89
- onFetch();
90
-
91
- return () => {
92
- log(`liveUser(tmpid: ${timestamp}) > dispose`);
93
- disposers.forEach(fn => fn());
94
- };
35
+ return liveObject(userId, callback, 'userId', getUser, [
36
+ onUserFetched,
37
+ onUserUpdated,
38
+ onUserDeleted,
39
+ onUserFlagged,
40
+ onUserUnflagged,
41
+ onUserFlagCleared,
42
+ ]);
95
43
  };
@@ -0,0 +1,162 @@
1
+ /* eslint-disable no-use-before-define */
2
+ import { getResolver } from '~/core/model';
3
+ import { pullFromCache, pushToCache } from '~/cache/api';
4
+ import { getActiveClient } from '~/client/api';
5
+
6
+ import {
7
+ createQuery,
8
+ runQuery,
9
+ queryOptions,
10
+ filterByPropEquality,
11
+ sortByLastCreated,
12
+ sortByDisplayName,
13
+ sortByFirstCreated,
14
+ } from '~/core/query';
15
+
16
+ import {
17
+ COLLECTION_DEFAULT_CACHING_POLICY,
18
+ COLLECTION_DEFAULT_PAGINATION_LIMIT,
19
+ ENABLE_CACHE_MESSAGE,
20
+ } from '~/utils/constants';
21
+
22
+ import { queryUsers } from '../api';
23
+ import {
24
+ onUserFlagged,
25
+ onUserUpdated,
26
+ onUserUnflagged,
27
+ onUserFlagCleared,
28
+ onUserDeleted,
29
+ } from '../events';
30
+
31
+ /**
32
+ * ```js
33
+ * import { liveUsers } from '@amityco/ts-sdk'
34
+ *
35
+ * let users = []
36
+ * const unsub = liveUsers({}, response => merge(users, response.data))
37
+ * ```
38
+ *
39
+ * Observe all mutations on a list of {@link Amity.User}s
40
+ *
41
+ * @param params for querying users
42
+ * @param callback the function to call when new data are available
43
+ * @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the users
44
+ *
45
+ * @category Category Live Collection
46
+ */
47
+ export const liveUsers = (
48
+ params: Amity.UserLiveCollection,
49
+ callback: Amity.LiveCollectionCallback<Amity.User>,
50
+ config?: Amity.LiveCollectionConfig,
51
+ ) => {
52
+ const { log, cache } = getActiveClient();
53
+
54
+ if (!cache) {
55
+ console.log(ENABLE_CACHE_MESSAGE);
56
+ }
57
+
58
+ const timestamp = Date.now();
59
+ log(`liveUsers(tmpid: ${timestamp}) > listen`);
60
+
61
+ const { limit: queryLimit, ...queryParams } = params;
62
+
63
+ const limit = queryLimit ?? COLLECTION_DEFAULT_PAGINATION_LIMIT;
64
+ const { policy = COLLECTION_DEFAULT_CACHING_POLICY } = config ?? {};
65
+
66
+ const disposers: Amity.Unsubscriber[] = [];
67
+ const cacheKey = ['user', 'collection', {}];
68
+
69
+ const responder = (data: Amity.UserLiveCollectionCache) => {
70
+ let users: Amity.User[] =
71
+ data.data
72
+ .map(userId => pullFromCache<Amity.User>(['user', 'get', userId])!)
73
+ .filter(Boolean)
74
+ .map(({ data }) => data) ?? [];
75
+
76
+ users = filterByPropEquality(users, 'displayName', params.displayName);
77
+
78
+ switch (params.sortBy) {
79
+ case 'firstCreated':
80
+ users = users.sort(sortByFirstCreated);
81
+ break;
82
+
83
+ case 'lastCreated':
84
+ users = users.sort(sortByLastCreated);
85
+ break;
86
+
87
+ default:
88
+ users = users
89
+ // this needs to be aligned with the backend data type
90
+ .map(u => (u.displayName ? u : { ...u, displayName: '' }))
91
+ // @ts-ignore
92
+ .sort(sortByDisplayName);
93
+ }
94
+
95
+ callback({
96
+ onNextPage: onFetch,
97
+ data: users,
98
+ hasNextPage: !!data.params?.page,
99
+ loading: data.loading,
100
+ error: data.error,
101
+ });
102
+ };
103
+
104
+ const realtimeRouter = (_: Amity.UserActionType) => (user: Amity.User) => {
105
+ const collection = pullFromCache<Amity.CommunityLiveCollectionCache>(cacheKey)?.data;
106
+ if (!collection) return;
107
+
108
+ collection.data = [...new Set([user.userId, ...collection.data])];
109
+
110
+ pushToCache(cacheKey, collection);
111
+ responder(collection);
112
+ };
113
+
114
+ const onFetch = () => {
115
+ const collection = pullFromCache<Amity.UserLiveCollectionCache>(cacheKey)?.data;
116
+
117
+ const users = collection?.data ?? [];
118
+
119
+ if (users.length > 0 && !collection?.params.page) return;
120
+
121
+ const query = createQuery(queryUsers, {
122
+ ...queryParams,
123
+ page: collection?.params.page ?? { limit },
124
+ });
125
+
126
+ runQuery(
127
+ query,
128
+ ({ data: result, error, loading, nextPage: page }) => {
129
+ const data = {
130
+ loading,
131
+ error,
132
+ params: { page },
133
+ data: users,
134
+ };
135
+
136
+ if (result) {
137
+ data.data = [...new Set([...users, ...result.map(getResolver('user'))])];
138
+ }
139
+
140
+ pushToCache(cacheKey, data);
141
+
142
+ responder(data);
143
+ },
144
+ queryOptions(policy),
145
+ );
146
+ };
147
+
148
+ disposers.push(
149
+ onUserUpdated(realtimeRouter('onUpdate')),
150
+ onUserDeleted(realtimeRouter('onDelete')),
151
+ onUserFlagged(realtimeRouter('onFlagged')),
152
+ onUserUnflagged(realtimeRouter('onUnflagged')),
153
+ onUserFlagCleared(realtimeRouter('onFlagCleared')),
154
+ );
155
+
156
+ onFetch();
157
+
158
+ return () => {
159
+ log(`liveUsers(tmpid: ${timestamp}) > dispose`);
160
+ disposers.forEach(fn => fn());
161
+ };
162
+ };
@@ -0,0 +1,202 @@
1
+ import { disableCache, enableCache } from '~/cache/api';
2
+ import {
3
+ client,
4
+ connectClient,
5
+ disconnectClient,
6
+ pause,
7
+ user11,
8
+ user12,
9
+ user21,
10
+ userQueryResponse,
11
+ userQueryResponsePage2,
12
+ } from '~/utils/tests';
13
+
14
+ import { liveUsers } from '../liveUsers';
15
+
16
+ const getSnapshot = (params?: Record<string, any>) => {
17
+ return {
18
+ data: [] as Amity.User[],
19
+ loading: true,
20
+ error: undefined as any,
21
+ ...params,
22
+ };
23
+ };
24
+
25
+ const { paging, ...payload } = userQueryResponse.data;
26
+ const { paging: paging2, ...payload2 } = userQueryResponsePage2.data;
27
+
28
+ describe('liveUsers', () => {
29
+ beforeAll(connectClient);
30
+ afterAll(disconnectClient);
31
+
32
+ beforeEach(enableCache);
33
+
34
+ afterEach(disableCache);
35
+
36
+ const params = { sortBy: 'lastCreated' } as Amity.UserLiveCollection;
37
+
38
+ test('it should return users collection', async () => {
39
+ const callback = jest.fn();
40
+ client.http.get = jest.fn().mockResolvedValue(userQueryResponse);
41
+
42
+ liveUsers(params, callback);
43
+ await pause();
44
+
45
+ expect(callback).toHaveBeenCalledTimes(2);
46
+ expect(callback).toHaveBeenNthCalledWith(1, expect.objectContaining(getSnapshot()));
47
+ expect(callback).toHaveBeenNthCalledWith(
48
+ 2,
49
+ expect.objectContaining(
50
+ getSnapshot({
51
+ data: payload.users,
52
+ loading: false,
53
+ }),
54
+ ),
55
+ );
56
+ });
57
+
58
+ test('it should return data from cache', async () => {
59
+ const callback = jest.fn();
60
+ client.http.get = jest.fn().mockResolvedValue(userQueryResponse);
61
+
62
+ liveUsers(params, () => undefined);
63
+ await pause();
64
+ liveUsers(params, callback);
65
+ await pause();
66
+
67
+ expect(callback).toHaveBeenCalledTimes(2);
68
+ expect(callback).toHaveBeenNthCalledWith(
69
+ 1,
70
+ expect.objectContaining(
71
+ getSnapshot({
72
+ data: payload.users,
73
+ }),
74
+ ),
75
+ );
76
+ expect(callback).toHaveBeenNthCalledWith(
77
+ 2,
78
+ expect.objectContaining(
79
+ getSnapshot({
80
+ data: payload.users,
81
+ loading: false,
82
+ }),
83
+ ),
84
+ );
85
+ });
86
+
87
+ test('it should return method to fetch next page', async () => {
88
+ const callback = jest.fn();
89
+ client.http.get = jest
90
+ .fn()
91
+ .mockResolvedValue(userQueryResponse)
92
+ .mockResolvedValueOnce(userQueryResponsePage2);
93
+
94
+ liveUsers(params, callback);
95
+ await pause();
96
+
97
+ expect(callback).toHaveBeenCalled();
98
+ expect(callback.mock.lastCall).toHaveLength(1);
99
+
100
+ const { onNextPage, hasNextPage } = callback.mock.lastCall[0];
101
+
102
+ expect(hasNextPage).toBe(true);
103
+ expect(onNextPage).toBeTruthy();
104
+
105
+ onNextPage();
106
+ await pause();
107
+
108
+ // 4 -> because 1 local & server call each per call (2)
109
+ expect(callback).toHaveBeenCalledTimes(4);
110
+ expect(callback).toHaveBeenNthCalledWith(
111
+ 4,
112
+ expect.objectContaining(
113
+ getSnapshot({
114
+ loading: false,
115
+ data: [...payload2.users, ...payload.users],
116
+ }),
117
+ ),
118
+ );
119
+ });
120
+
121
+ describe('events', () => {
122
+ const updatedUser = { ...user11, displayName: 'updated-user' };
123
+ const flaggedUser = { ...user11, flagCount: 1 };
124
+ const unflaggedUser = { ...user11, flagCount: 1 };
125
+ const flagClearedUser = { ...user11, flagCount: 0 };
126
+
127
+ const cases: [string, keyof Amity.Events, Amity.UserPayload, Amity.User[]][] = [
128
+ [
129
+ 'it should update user in collection onUpdate',
130
+ 'user.updated',
131
+ { users: [updatedUser], files: [] },
132
+ [updatedUser, user12],
133
+ ],
134
+ [
135
+ 'it should update user in collection onUpdate',
136
+ 'user.flagged',
137
+ { users: [flaggedUser], files: [] },
138
+ [flaggedUser, user12],
139
+ ],
140
+ [
141
+ 'it should update user in collection onUpdate',
142
+ 'user.unflagged',
143
+ { users: [unflaggedUser], files: [] },
144
+ [unflaggedUser, user12],
145
+ ],
146
+ [
147
+ 'it should update user in collection onUpdate',
148
+ 'user.flagCleared',
149
+ { users: [flagClearedUser], files: [] },
150
+ [flagClearedUser, user12],
151
+ ],
152
+ ];
153
+
154
+ test.each(cases)('%s', async (test, event, user, expected) => {
155
+ const callback = jest.fn();
156
+ client.http.get = jest.fn().mockResolvedValue(userQueryResponse);
157
+
158
+ liveUsers(params, callback);
159
+ await pause();
160
+
161
+ client.emitter.emit(event, user);
162
+ await pause();
163
+
164
+ expect(callback).toHaveBeenNthCalledWith(
165
+ 3,
166
+ expect.objectContaining(
167
+ getSnapshot({
168
+ data: expected,
169
+ loading: false,
170
+ }),
171
+ ),
172
+ );
173
+ });
174
+ });
175
+
176
+ const filters: [string, Amity.UserLiveCollection, Amity.User[]][] = [
177
+ ['displayName', { displayName: 'displayName' }, [user21]],
178
+ ];
179
+
180
+ test.each(filters)('it should filter by %s communities', async (filter, params, expected) => {
181
+ const callback = jest.fn();
182
+ client.http.get = jest.fn().mockResolvedValue(userQueryResponsePage2);
183
+
184
+ liveUsers(params, callback);
185
+
186
+ expect(callback).toHaveBeenCalledTimes(1);
187
+ // check if cache data returned (should be empty)
188
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining(getSnapshot()));
189
+
190
+ await pause();
191
+
192
+ expect(callback).toHaveBeenCalledTimes(2);
193
+ expect(callback).toHaveBeenCalledWith(
194
+ expect.objectContaining(
195
+ getSnapshot({
196
+ loading: false,
197
+ data: expected,
198
+ }),
199
+ ),
200
+ );
201
+ });
202
+ });