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

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 (179) 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/domains/category.d.ts +7 -0
  5. package/dist/@types/domains/category.d.ts.map +1 -1
  6. package/dist/@types/domains/community.d.ts +12 -0
  7. package/dist/@types/domains/community.d.ts.map +1 -1
  8. package/dist/@types/global.d.ts +5 -0
  9. package/dist/@types/global.d.ts.map +1 -1
  10. package/dist/category/api/queryCategories.d.ts +1 -5
  11. package/dist/category/api/queryCategories.d.ts.map +1 -1
  12. package/dist/category/observers/index.d.ts +2 -0
  13. package/dist/category/observers/index.d.ts.map +1 -0
  14. package/dist/category/observers/liveCategories.d.ts +18 -0
  15. package/dist/category/observers/liveCategories.d.ts.map +1 -0
  16. package/dist/category/observers/tests/liveCategories.test.d.ts +2 -0
  17. package/dist/category/observers/tests/liveCategories.test.d.ts.map +1 -0
  18. package/dist/channel/api/tests/getChannels.test.d.ts +2 -0
  19. package/dist/channel/api/tests/getChannels.test.d.ts.map +1 -0
  20. package/dist/channel/api/tests/leaveChannel.test.d.ts +2 -0
  21. package/dist/channel/api/tests/leaveChannel.test.d.ts.map +1 -0
  22. package/dist/channel/observers/liveChannel.d.ts.map +1 -1
  23. package/dist/client/api/accessTokenExpiryWatcher.d.ts +4 -1
  24. package/dist/client/api/accessTokenExpiryWatcher.d.ts.map +1 -1
  25. package/dist/client/api/getToken.d.ts +3 -1
  26. package/dist/client/api/getToken.d.ts.map +1 -1
  27. package/dist/client/utils/setClientToken.d.ts +3 -3
  28. package/dist/comment/api/deleteComment.d.ts.map +1 -1
  29. package/dist/comment/api/getComment.d.ts.map +1 -1
  30. package/dist/comment/observers/index.d.ts +1 -0
  31. package/dist/comment/observers/index.d.ts.map +1 -1
  32. package/dist/comment/observers/liveComment.d.ts +21 -0
  33. package/dist/comment/observers/liveComment.d.ts.map +1 -0
  34. package/dist/comment/observers/tests/liveComment.test.d.ts +2 -0
  35. package/dist/comment/observers/tests/liveComment.test.d.ts.map +1 -0
  36. package/dist/community/api/queryCommunities.d.ts +1 -10
  37. package/dist/community/api/queryCommunities.d.ts.map +1 -1
  38. package/dist/community/events/index.d.ts +1 -0
  39. package/dist/community/events/index.d.ts.map +1 -1
  40. package/dist/community/events/onCommunityUserChanged.d.ts +17 -0
  41. package/dist/community/events/onCommunityUserChanged.d.ts.map +1 -0
  42. package/dist/community/events/utils.d.ts +1 -0
  43. package/dist/community/events/utils.d.ts.map +1 -1
  44. package/dist/community/observers/index.d.ts +1 -0
  45. package/dist/community/observers/index.d.ts.map +1 -1
  46. package/dist/community/observers/liveCommunities.d.ts +20 -0
  47. package/dist/community/observers/liveCommunities.d.ts.map +1 -0
  48. package/dist/community/observers/tests/liveCommunities.test.d.ts +2 -0
  49. package/dist/community/observers/tests/liveCommunities.test.d.ts.map +1 -0
  50. package/dist/core/events.d.ts +3 -3
  51. package/dist/core/events.d.ts.map +1 -1
  52. package/dist/core/query/sorting.d.ts +6 -0
  53. package/dist/core/query/sorting.d.ts.map +1 -1
  54. package/dist/core/transports/http.d.ts +0 -5
  55. package/dist/core/transports/http.d.ts.map +1 -1
  56. package/dist/file/api/test/createImage.test.d.ts +2 -0
  57. package/dist/file/api/test/createImage.test.d.ts.map +1 -0
  58. package/dist/file/api/test/createVideo.test.d.ts +2 -0
  59. package/dist/file/api/test/createVideo.test.d.ts.map +1 -0
  60. package/dist/index.cjs.js +441 -195
  61. package/dist/index.d.ts +1 -0
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.esm.js +436 -195
  64. package/dist/index.umd.js +4 -4
  65. package/dist/message/observers/liveMessage.d.ts.map +1 -1
  66. package/dist/post/observers/index.d.ts +1 -0
  67. package/dist/post/observers/index.d.ts.map +1 -1
  68. package/dist/post/observers/livePost.d.ts +21 -0
  69. package/dist/post/observers/livePost.d.ts.map +1 -0
  70. package/dist/post/observers/tests/livePost.test.d.ts +2 -0
  71. package/dist/post/observers/tests/livePost.test.d.ts.map +1 -0
  72. package/dist/subChannel/api/tests/deleteSubChannel.test.d.ts +2 -0
  73. package/dist/subChannel/api/tests/deleteSubChannel.test.d.ts.map +1 -0
  74. package/dist/subChannel/api/tests/getSubChannel.test.d.ts +2 -0
  75. package/dist/subChannel/api/tests/getSubChannel.test.d.ts.map +1 -0
  76. package/dist/subChannel/api/tests/getSubChannels.test.d.ts +2 -0
  77. package/dist/subChannel/api/tests/getSubChannels.test.d.ts.map +1 -0
  78. package/dist/subChannel/api/tests/updateSubChannel.test.d.ts +2 -0
  79. package/dist/subChannel/api/tests/updateSubChannel.test.d.ts.map +1 -0
  80. package/dist/subChannel/observers/liveSubChannel.d.ts.map +1 -1
  81. package/dist/user/api/tests/updateUser.test.d.ts +2 -0
  82. package/dist/user/api/tests/updateUser.test.d.ts.map +1 -0
  83. package/dist/user/observers/liveUser.d.ts.map +1 -1
  84. package/dist/utils/liveObject.d.ts +2 -0
  85. package/dist/utils/liveObject.d.ts.map +1 -0
  86. package/dist/utils/tests/dummy/category.d.ts +64 -0
  87. package/dist/utils/tests/dummy/category.d.ts.map +1 -0
  88. package/dist/utils/tests/dummy/channel.d.ts +50 -0
  89. package/dist/utils/tests/dummy/channel.d.ts.map +1 -1
  90. package/dist/utils/tests/dummy/community.d.ts +132 -0
  91. package/dist/utils/tests/dummy/community.d.ts.map +1 -1
  92. package/dist/utils/tests/dummy/file.d.ts +3 -0
  93. package/dist/utils/tests/dummy/file.d.ts.map +1 -1
  94. package/dist/utils/tests/dummy/index.d.ts +1 -0
  95. package/dist/utils/tests/dummy/index.d.ts.map +1 -1
  96. package/dist/utils/tests/dummy/post.d.ts +2 -0
  97. package/dist/utils/tests/dummy/post.d.ts.map +1 -1
  98. package/dist/utils/tests/dummy/subChannel.d.ts +0 -20
  99. package/dist/utils/tests/dummy/subChannel.d.ts.map +1 -1
  100. package/dist/utils/tests/dummy/user.d.ts +18 -0
  101. package/dist/utils/tests/dummy/user.d.ts.map +1 -1
  102. package/dist/utils/tests/liveObject.test.d.ts +2 -0
  103. package/dist/utils/tests/liveObject.test.d.ts.map +1 -0
  104. package/package.json +4 -4
  105. package/src/@types/core/events.ts +1 -0
  106. package/src/@types/domains/category.ts +13 -0
  107. package/src/@types/domains/community.ts +25 -0
  108. package/src/@types/global.ts +5 -0
  109. package/src/category/api/queryCategories.ts +3 -5
  110. package/src/category/observers/index.ts +1 -0
  111. package/src/category/observers/liveCategories.ts +141 -0
  112. package/src/category/observers/tests/liveCategories.test.ts +147 -0
  113. package/src/channel/api/tests/createChannel.test.ts +30 -6
  114. package/src/channel/api/tests/getChannel.test.ts +3 -1
  115. package/src/channel/api/tests/getChannels.test.ts +97 -0
  116. package/src/channel/api/tests/joinChannel.test.ts +62 -3
  117. package/src/channel/api/tests/leaveChannel.test.ts +90 -0
  118. package/src/channel/api/tests/queryChannels.test.ts +38 -1
  119. package/src/channel/observers/liveChannel.ts +8 -80
  120. package/src/client/api/accessTokenExpiryWatcher.ts +7 -5
  121. package/src/client/api/tests/accessTokenExpiryWatcher.test.ts +8 -5
  122. package/src/comment/api/deleteComment.ts +5 -5
  123. package/src/comment/api/getComment.ts +8 -3
  124. package/src/comment/observers/index.ts +1 -0
  125. package/src/comment/observers/liveComment.ts +43 -0
  126. package/src/comment/observers/tests/liveComment.test.ts +95 -0
  127. package/src/community/api/queryCommunities.ts +3 -10
  128. package/src/community/api/test/addCommunityMember.test.ts +14 -2
  129. package/src/community/api/test/joinCommunity.test.ts +14 -2
  130. package/src/community/api/test/leaveCommunity.test.ts +11 -1
  131. package/src/community/api/test/removeCommunityMembers.test.ts +11 -1
  132. package/src/community/events/index.ts +1 -0
  133. package/src/community/events/onCommunityUserChanged.ts +20 -0
  134. package/src/community/events/test/onCommunityJoined.test.ts +1 -1
  135. package/src/community/events/test/onCommunityUserAdded.test.ts +1 -1
  136. package/src/community/events/test/onCommunityUserBanned.test.ts +1 -1
  137. package/src/community/events/test/onCommunityUserUnbaned.test.ts +1 -1
  138. package/src/community/events/test/utils.test.ts +52 -3
  139. package/src/community/events/utils.ts +49 -0
  140. package/src/community/observers/index.ts +1 -0
  141. package/src/community/observers/liveCommunities.ts +188 -0
  142. package/src/community/observers/tests/liveCommunities.test.ts +284 -0
  143. package/src/core/query/sorting.ts +8 -0
  144. package/src/core/transports/http.ts +17 -13
  145. package/src/core/transports/test/http.test.ts +49 -60
  146. package/src/file/api/createFile.ts +1 -1
  147. package/src/file/api/createImage.ts +1 -1
  148. package/src/file/api/createVideo.ts +1 -1
  149. package/src/file/api/test/createImage.test.ts +69 -0
  150. package/src/file/api/test/createVideo.test.ts +81 -0
  151. package/src/index.ts +1 -0
  152. package/src/message/observers/liveMessage.ts +11 -83
  153. package/src/message/tests/observers/liveMessage.test.ts +1 -143
  154. package/src/post/observers/index.ts +1 -0
  155. package/src/post/observers/livePost.ts +47 -0
  156. package/src/post/observers/tests/livePost.test.ts +97 -0
  157. package/src/stream/api/tests/createStream.test.ts +3 -11
  158. package/src/stream/api/tests/deleteStream.test.ts +5 -3
  159. package/src/subChannel/api/tests/createSubChannel.test.ts +21 -14
  160. package/src/subChannel/api/tests/deleteSubChannel.test.ts +112 -0
  161. package/src/subChannel/api/tests/getSubChannel.test.ts +97 -0
  162. package/src/subChannel/api/tests/getSubChannels.test.ts +97 -0
  163. package/src/subChannel/api/tests/updateSubChannel.test.ts +86 -0
  164. package/src/subChannel/observers/liveSubChannel.ts +6 -56
  165. package/src/subChannel/observers/tests/liveSubChannel.test.ts +0 -82
  166. package/src/user/api/tests/updateUser.test.ts +60 -0
  167. package/src/user/observers/liveUser.ts +9 -61
  168. package/src/user/tests/observers/liveUser.test.ts +1 -154
  169. package/src/utils/liveObject.ts +86 -0
  170. package/src/utils/tests/dummy/category.ts +57 -0
  171. package/src/utils/tests/dummy/channel.ts +51 -1
  172. package/src/utils/tests/dummy/community.ts +94 -0
  173. package/src/utils/tests/dummy/file.ts +32 -0
  174. package/src/utils/tests/dummy/index.ts +1 -0
  175. package/src/utils/tests/dummy/post.ts +56 -45
  176. package/src/utils/tests/dummy/stream.ts +73 -73
  177. package/src/utils/tests/dummy/subChannel.ts +0 -22
  178. package/src/utils/tests/dummy/user.ts +21 -0
  179. 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
  });
@@ -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,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
  };
@@ -1,6 +1,4 @@
1
- import { ASCApiError } from '~/core/errors';
2
1
  import { disableCache, enableCache } from '~/cache/api';
3
- import { LIVE_OBJECT_ENABLE_CACHE_MESSAGE } from '~/utils/constants';
4
2
  import {
5
3
  client,
6
4
  connectClient,
@@ -29,161 +27,10 @@ describe('liveUser', () => {
29
27
  await disconnectClient();
30
28
  });
31
29
 
32
- beforeEach(async () => {
33
- enableCache();
34
- });
30
+ beforeEach(enableCache);
35
31
 
36
32
  afterEach(disableCache);
37
33
 
38
- test('it should show user if cache not enabled', () => {
39
- /*
40
- * NOTE: at the time of writing this test cache is diabled by default, but
41
- * there is a proposal to enable cache by default. So I'm disabling cache
42
- * here to ensure cache is disabled
43
- */
44
- disableCache();
45
-
46
- const callback = jest.fn();
47
- jest.spyOn(global.console, 'log');
48
- client.http.get = jest.fn();
49
-
50
- // call liveUser check if mocked console get's called with the correct
51
- // user
52
- client.use();
53
- liveUser(defaultUser.userId, callback);
54
-
55
- expect(console.log).toBeCalledWith(LIVE_OBJECT_ENABLE_CACHE_MESSAGE);
56
- });
57
-
58
- test('it should return user live object', async () => {
59
- const snapshot = getSnapshot();
60
-
61
- // mock response of queryUsers and validate
62
- const callback = jest.fn();
63
- client.http.get = jest.fn().mockResolvedValue(userQueryResponse);
64
-
65
- liveUser(defaultUser.userId, callback);
66
-
67
- expect(callback).toHaveBeenCalledTimes(1);
68
-
69
- // check if cache data returned (should be empty)
70
- expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
71
-
72
- await pause();
73
-
74
- expect(callback).toHaveBeenCalledTimes(2);
75
-
76
- snapshot.loading = false;
77
- snapshot.data = defaultUser;
78
-
79
- expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
80
- });
81
-
82
- test('it should return error on api failure', async () => {
83
- const snapshot = getSnapshot();
84
- const error = new ASCApiError(
85
- 'server error!',
86
- Amity.ServerError.ITEM_NOT_FOUND,
87
- Amity.ErrorLevel.ERROR,
88
- );
89
-
90
- // mock response of queryUsers and validate
91
- const callback = jest.fn();
92
- client.http.get = jest.fn().mockRejectedValue(error);
93
-
94
- liveUser(defaultUser.userId, callback);
95
-
96
- expect(callback).toHaveBeenCalledTimes(1);
97
-
98
- // check if cache data returned (should be empty)
99
- expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
100
-
101
- await pause();
102
-
103
- expect(callback).toHaveBeenCalledTimes(2);
104
-
105
- snapshot.error = error;
106
- snapshot.loading = false;
107
- expect(callback).toHaveBeenLastCalledWith(expect.objectContaining(snapshot));
108
- });
109
-
110
- test('it should terminate updates on api failure', async () => {
111
- const snapshot = getSnapshot();
112
- const error = new ASCApiError(
113
- 'server error!',
114
- Amity.ServerError.ITEM_NOT_FOUND,
115
- Amity.ErrorLevel.ERROR,
116
- );
117
-
118
- // mock response of queryUsers and validate
119
- const callback = jest.fn();
120
- client.http.get = jest.fn().mockRejectedValue(error);
121
-
122
- liveUser(defaultUser.userId, callback);
123
-
124
- expect(callback).toHaveBeenCalledTimes(1);
125
-
126
- // check if cache data returned (should be empty)
127
- expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
128
-
129
- await pause();
130
-
131
- expect(callback).toHaveBeenCalledTimes(2);
132
-
133
- snapshot.error = error;
134
- snapshot.loading = false;
135
- expect(callback).toHaveBeenLastCalledWith(expect.objectContaining(snapshot));
136
-
137
- const updatedAt = new Date(defaultUser?.updatedAt ?? new Date());
138
- updatedAt.setDate(updatedAt.getDate() + 7);
139
-
140
- const updatedUser = {
141
- ...defaultUser,
142
- updatedAt: updatedAt.toISOString(),
143
- };
144
- client.emitter.emit('user.updated', { users: [updatedUser], files: [] });
145
-
146
- delete snapshot.error;
147
- snapshot.loading = false;
148
- snapshot.data = updatedUser;
149
- expect(callback).not.toHaveBeenNthCalledWith(3, expect.objectContaining(snapshot));
150
- });
151
-
152
- test('it should not return updates on obtain once!', async () => {
153
- const snapshot = getSnapshot();
154
-
155
- // mock response of queryUsers and validate
156
- const callback = jest.fn();
157
- client.http.get = jest.fn().mockResolvedValue(userQueryResponse);
158
-
159
- const unsub = liveUser(defaultUser.userId, callback);
160
-
161
- expect(callback).toHaveBeenCalledTimes(1);
162
-
163
- // check if cache data returned (should be empty)
164
- expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
165
-
166
- await pause();
167
-
168
- expect(callback).toHaveBeenCalledTimes(2);
169
-
170
- unsub();
171
-
172
- const updatedAt = new Date(defaultUser?.updatedAt ?? new Date());
173
- updatedAt.setDate(updatedAt.getDate() + 7);
174
-
175
- const updatedUser = {
176
- ...defaultUser,
177
- updatedAt: updatedAt.toISOString(),
178
- };
179
- client.emitter.emit('user.updated', { users: [updatedUser], files: [] });
180
-
181
- delete snapshot.error;
182
- snapshot.loading = false;
183
- snapshot.data = updatedUser;
184
- expect(callback).not.toHaveBeenNthCalledWith(3, expect.objectContaining(snapshot));
185
- });
186
-
187
34
  const events: [string, keyof Amity.Events][] = [
188
35
  ['it should return updated user on onFetch', 'user.fetched'],
189
36
  ['it should return updated user on onUpdate', 'user.updated'],
@@ -0,0 +1,86 @@
1
+ import { getActiveClient } from '~/client/api';
2
+ import {
3
+ LIVE_OBJECT_ENABLE_CACHE_MESSAGE,
4
+ UNSYNCED_OBJECT_CACHED_AT_MESSAGE,
5
+ UNSYNCED_OBJECT_CACHED_AT_VALUE,
6
+ } from '~/utils/constants';
7
+ import { hasUpdates } from '~/core/model';
8
+ import { createQuery, runQuery } from '~/core/query';
9
+ import { ASCApiError } from '~/core/errors';
10
+
11
+ export const liveObject = <
12
+ T extends Exclude<Amity.Model[Amity.Domain], Amity.Reaction | Amity.FollowCount>,
13
+ K extends keyof T,
14
+ >(
15
+ id: T[K],
16
+ callback: Amity.LiveObjectCallback<T>,
17
+ key: K,
18
+ fetcher: (id: T[K]) => Promise<Amity.Cached<T>>,
19
+ eventHandlers: Array<(callback: Amity.Listener<T>) => Amity.Unsubscriber>,
20
+ ): Amity.Unsubscriber => {
21
+ const { cache } = getActiveClient();
22
+
23
+ if (!cache) {
24
+ console.log(LIVE_OBJECT_ENABLE_CACHE_MESSAGE);
25
+ }
26
+
27
+ let model: T;
28
+ let isUnsyncedModel = false; // for messages
29
+ const disposers: Amity.Unsubscriber[] = [];
30
+
31
+ const dispatcher = (data: Amity.LiveObject<T>) => {
32
+ model = data.data;
33
+ callback(data);
34
+ };
35
+
36
+ const realtimeRouter = (eventModel: T) => {
37
+ if (id !== eventModel[key]) {
38
+ return;
39
+ }
40
+
41
+ if (model && !hasUpdates(model, eventModel)) {
42
+ return;
43
+ }
44
+
45
+ dispatcher({ loading: false, data: eventModel, origin: 'event' });
46
+ };
47
+
48
+ const onFetch = () => {
49
+ // @ts-ignore
50
+ const query = createQuery(fetcher, id, true);
51
+
52
+ runQuery(query, ({ error, data, loading, origin, cachedAt }) => {
53
+ if (cachedAt === UNSYNCED_OBJECT_CACHED_AT_VALUE) {
54
+ dispatcher({
55
+ // @ts-ignore
56
+ data,
57
+ origin,
58
+ loading: false,
59
+ error: new ASCApiError(
60
+ UNSYNCED_OBJECT_CACHED_AT_MESSAGE,
61
+ Amity.ClientError.DISALOOW_UNSYNCED_OBJECT,
62
+ Amity.ErrorLevel.ERROR,
63
+ ),
64
+ });
65
+
66
+ isUnsyncedModel = true;
67
+ disposers.forEach(fn => fn());
68
+ } else if (!isUnsyncedModel) {
69
+ // @ts-ignore
70
+ dispatcher({ loading, data, origin, error });
71
+ }
72
+
73
+ if (error) {
74
+ disposers.forEach(fn => fn());
75
+ }
76
+ });
77
+ };
78
+
79
+ disposers.push(...eventHandlers.map(fn => fn(realtimeRouter)));
80
+
81
+ onFetch();
82
+
83
+ return () => {
84
+ disposers.forEach(fn => fn());
85
+ };
86
+ };
@@ -0,0 +1,57 @@
1
+ export const category11 = {
2
+ name: 'a-hello',
3
+ updatedAt: '2022-11-25T04:19:34.446Z',
4
+ createdAt: '2022-11-25T04:19:34.446Z',
5
+ isDeleted: false,
6
+ categoryId: '2ddea5ad242d0a2bd5dc5be8ae9fc8c2',
7
+ };
8
+
9
+ export const category12 = {
10
+ name: 'b-testing-category',
11
+ updatedAt: '2022-11-25T03:56:06.238Z',
12
+ createdAt: '2022-11-25T03:56:06.238Z',
13
+ isDeleted: false,
14
+ categoryId: '88d175da65cbfeb39b81e722b322430e',
15
+ };
16
+
17
+ export const category13 = {
18
+ name: 'c-deleted-category',
19
+ updatedAt: '2022-11-25T03:56:06.238Z',
20
+ createdAt: '2022-11-25T03:56:06.238Z',
21
+ isDeleted: true,
22
+ categoryId: '88d175da65cbfeb39b81e722b322430d',
23
+ };
24
+
25
+ export const category21 = {
26
+ name: 'a-0asd',
27
+ updatedAt: '2022-11-25T04:18:59.180Z',
28
+ createdAt: '2022-11-25T04:18:59.180Z',
29
+ isDeleted: false,
30
+ categoryId: '10051d82a1f371c6be3a8f4a4654b8a1',
31
+ };
32
+
33
+ export const category22 = {
34
+ name: 'b-A Category',
35
+ updatedAt: '2022-11-25T03:56:29.037Z',
36
+ createdAt: '2022-11-25T03:56:29.037Z',
37
+ isDeleted: false,
38
+ categoryId: '639942c6b2f121bed3901cf4a4c296e7',
39
+ };
40
+
41
+ export const categoryQueryResponse = {
42
+ data: {
43
+ categories: [category11, category12, category13],
44
+ paging: {
45
+ next: 'eyJza2lwIjoxMCwibGltaXQiOjEwfQ==',
46
+ },
47
+ },
48
+ };
49
+
50
+ export const categoryQueryResponsePage2 = {
51
+ data: {
52
+ categories: [category21, category22],
53
+ paging: {
54
+ next: 'eyJza2lwIjoxMCwibGltaXQiOjEwfQ==',
55
+ },
56
+ },
57
+ };
@@ -54,7 +54,13 @@ export const mockPage = {
54
54
  },
55
55
  };
56
56
 
57
- export const channelRaw1: Amity.ChannelRaw = generateRawChannel();
57
+ export const channelRaw1: Amity.ChannelRaw = generateRawChannel({ type: 'community' });
58
+
59
+ export const channelRawLive1: Amity.ChannelRaw = generateRawChannel({ type: 'live' });
60
+
61
+ export const channelRawConversation1: Amity.ChannelRaw = generateRawChannel({
62
+ type: 'conversation',
63
+ });
58
64
 
59
65
  export const channelRaw2: Amity.ChannelRaw = generateRawChannel({
60
66
  channelId: 'channelId12',
@@ -132,6 +138,16 @@ export const channelQueryResponse = {
132
138
  },
133
139
  };
134
140
 
141
+ export const getChannelsResponse = {
142
+ data: {
143
+ channels: [channelRaw1, channelRaw2, channelRaw3],
144
+ channelUsers: [],
145
+ files: [],
146
+ users: [],
147
+ ...mockPage,
148
+ },
149
+ };
150
+
135
151
  export const channelQueryResponsePage2 = {
136
152
  data: {
137
153
  channels: [channelRaw3],
@@ -142,6 +158,26 @@ export const channelQueryResponsePage2 = {
142
158
  },
143
159
  };
144
160
 
161
+ export const channelTagQueryResponse = {
162
+ data: {
163
+ channels: [channelRaw2],
164
+ channelUsers: [],
165
+ files: [],
166
+ users: [],
167
+ ...mockPage,
168
+ },
169
+ };
170
+
171
+ export const channelExcludeTagQueryResponse = {
172
+ data: {
173
+ channels: [channelRaw1, channelRaw3],
174
+ channelUsers: [],
175
+ files: [],
176
+ users: [],
177
+ ...mockPage,
178
+ },
179
+ };
180
+
145
181
  export const channelUserQueryResponse = {
146
182
  data: {
147
183
  channels: [channelRaw1],
@@ -191,3 +227,17 @@ export const channelPayload = {
191
227
  users: [user14, user11],
192
228
  files: [file11],
193
229
  };
230
+
231
+ export const liveChannelPayload = {
232
+ channels: [channelRawLive1],
233
+ channelUsers: [rawChannelUserWithRole, rawMutedChannelUser],
234
+ users: [user14, user11],
235
+ files: [file11],
236
+ };
237
+
238
+ export const conversationChannelPayload = {
239
+ channels: [channelRawConversation1],
240
+ channelUsers: [rawChannelUserWithRole, rawMutedChannelUser],
241
+ users: [user14, user11],
242
+ files: [file11],
243
+ };