@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
@@ -6,6 +6,7 @@ import {
6
6
  channelUser1,
7
7
  channelUser4,
8
8
  channelUserQueryResponse,
9
+ channelUserQueryResponsePage3,
9
10
  channelUserQueryResponsePage2,
10
11
  channel11,
11
12
  pause,
@@ -57,24 +58,34 @@ describe('liveChannelMembers', () => {
57
58
  const filters: [string, Amity.ChannelMembersLiveCollection, Amity.Membership<'channel'>[]][] = [
58
59
  [
59
60
  'roles',
60
- { channelId, roles: channelUserQueryResponse.data.channelUsers[1].roles },
61
- [channelUserQueryResponse.data.channelUsers[1]],
61
+ { channelId, roles: channelUserQueryResponsePage3.data.channelUsers[0].roles },
62
+ [channelUserQueryResponsePage3.data.channelUsers[0]],
62
63
  ],
63
64
  [
64
65
  'searched term',
65
66
  { channelId, search: 'use' },
66
- [channelUserQueryResponse.data.channelUsers[1]],
67
+ [channelUserQueryResponsePage3.data.channelUsers[0]],
67
68
  ],
68
69
  [
69
- 'memberships',
70
+ 'member',
70
71
  { channelId, memberships: ['member'] },
71
- [channelUserQueryResponse.data.channelUsers[0]],
72
+ [channelUserQueryResponsePage3.data.channelUsers[0]],
73
+ ],
74
+ [
75
+ 'muted members',
76
+ { channelId, memberships: ['muted'] },
77
+ [channelUserQueryResponsePage3.data.channelUsers[1]],
78
+ ],
79
+ [
80
+ 'banned members',
81
+ { channelId, memberships: ['banned'] },
82
+ [channelUserQueryResponsePage3.data.channelUsers[1]],
72
83
  ],
73
84
  ];
74
85
 
75
86
  test.each(filters)('it should filter channelUsers by %s', async (filter, params, expected) => {
76
87
  const callback = jest.fn();
77
- client.http.get = jest.fn().mockResolvedValue(channelUserQueryResponse);
88
+ client.http.get = jest.fn().mockResolvedValue(channelUserQueryResponsePage3);
78
89
 
79
90
  liveChannelMembers(params, callback);
80
91
  await pause();
@@ -131,6 +142,16 @@ describe('liveChannelMembers', () => {
131
142
  'v3.channel.didRemoveUsers',
132
143
  channelUser1,
133
144
  ],
145
+ [
146
+ 'it should update channel memeber membership on onChannelMemberBanned',
147
+ 'v3.channel.didBan',
148
+ { ...channelUser1, membership: 'banned', isBanned: true },
149
+ ],
150
+ [
151
+ 'it should update channel memeber membership on onChannelMemberUnbanned',
152
+ 'v3.channel.didUnban',
153
+ { ...channelUser1, membership: 'none', isBanned: false },
154
+ ],
134
155
  ];
135
156
 
136
157
  test.each(events)('%s', async (test, event, channelUser) => {
@@ -153,11 +174,32 @@ describe('liveChannelMembers', () => {
153
174
 
154
175
  snapshot.loading = false;
155
176
  // get data based on event
156
- if (event === 'v3.channel.didAddUsers') {
157
- snapshot.data = [channelUser, ...payload.channelUsers];
158
- } else {
159
- const deletePayload = payload.channelUsers.filter(u => u.userId !== channelUser.userId);
160
- snapshot.data = deletePayload;
177
+ switch (event) {
178
+ case 'v3.channel.didAddUsers':
179
+ snapshot.data = [channelUser, ...payload.channelUsers];
180
+ break;
181
+
182
+ case 'v3.channel.didBan': {
183
+ const bannedUserIdx = payload.channelUsers.findIndex(u => u.userId === channelUser.userId);
184
+ payload.channelUsers[bannedUserIdx] = channelUser;
185
+
186
+ snapshot.data = payload.channelUsers;
187
+ break;
188
+ }
189
+
190
+ case 'v3.channel.didUnban': {
191
+ const unbannedUserIdx = payload.channelUsers.findIndex(
192
+ u => u.userId === channelUser.userId,
193
+ );
194
+ payload.channelUsers[unbannedUserIdx] = channelUser;
195
+
196
+ snapshot.data = payload.channelUsers;
197
+ break;
198
+ }
199
+
200
+ default:
201
+ // delete payload
202
+ snapshot.data = payload.channelUsers.filter(u => u.userId !== channelUser.userId);
161
203
  }
162
204
 
163
205
  expect(callback).toHaveBeenNthCalledWith(3, expect.objectContaining(snapshot));
@@ -1,11 +1,12 @@
1
- import { disableCache, enableCache } from '~/cache/api';
1
+ import { disableCache, enableCache, pushToCache } from '~/cache/api';
2
+ import { getResolver } from '~/core/model';
2
3
 
3
4
  import { liveChannels } from '../liveChannels';
4
- import { queryChannels } from '~/channel/api';
5
5
  import { prepareChannelPayload } from '../../utils/prepareChannelPayload';
6
6
 
7
7
  import {
8
8
  client,
9
+ pause,
9
10
  connectClient,
10
11
  disconnectClient,
11
12
  channel11,
@@ -49,7 +50,7 @@ describe('liveChannels', () => {
49
50
  // check if cache data returned (should be empty)
50
51
  expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
51
52
 
52
- await expect(queryChannels()).resolves.toBeTruthy();
53
+ await pause();
53
54
 
54
55
  expect(callback).toHaveBeenCalledTimes(2);
55
56
 
@@ -63,33 +64,61 @@ describe('liveChannels', () => {
63
64
  });
64
65
 
65
66
  // table for channel filters
66
- const filters: [string, Amity.ChannelLiveCollection][] = [
67
+ const filters: [string, Amity.ChannelLiveCollection, number?][] = [
67
68
  ['deleted', { isDeleted: false }],
68
69
  ['tagged', { tags: ['tag2'] }],
69
70
  ['out excluded tags', { excludeTags: ['tag1'] }],
71
+ ['member', { membership: 'member' }],
72
+ ['not member', { membership: 'notMember' }, 1],
73
+ ['all membership', { membership: 'all' }],
70
74
  ];
71
75
 
72
- test.each(filters)('it should filter %s channels', async (filter, params) => {
73
- const callback = jest.fn();
74
- client.http.get = jest.fn().mockResolvedValue(channelQueryResponse);
76
+ test.each(filters)(
77
+ 'it should filter by %s channels',
78
+ async (filter, params, expectedChannelIdx = 0) => {
79
+ const callback = jest.fn();
80
+ client.http.get = jest.fn().mockResolvedValue(channelQueryResponse);
75
81
 
76
- liveChannels(params, callback);
82
+ const payload = prepareChannelPayload(channelQueryResponse.data);
83
+ let snapshotData = [payload.channels[expectedChannelIdx]];
77
84
 
78
- expect(callback).toHaveBeenCalledTimes(1);
85
+ // add channel users to cache for testing membership filter
86
+ if (params.membership) {
87
+ pushToCache(
88
+ [
89
+ 'channelUsers',
90
+ 'get',
91
+ getResolver('channelUsers')({
92
+ channelId: channelQueryResponse.data.channels[0].channelId,
93
+ userId: channelUser1.userId,
94
+ }),
95
+ ],
96
+ channelUser1,
97
+ );
79
98
 
80
- const snapshot = getSnapshot();
81
- // check if cache data returned (should be empty)
82
- expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
99
+ if (params.membership === 'all') {
100
+ snapshotData = payload.channels;
101
+ }
102
+ }
83
103
 
84
- await expect(queryChannels()).resolves.toBeTruthy();
104
+ liveChannels(params, callback);
85
105
 
86
- expect(callback).toHaveBeenCalledTimes(2);
106
+ expect(callback).toHaveBeenCalledTimes(1);
87
107
 
88
- snapshot.loading = false;
89
- snapshot.data = [channelQueryResponse.data.channels[0]];
108
+ const snapshot = getSnapshot();
109
+ // check if cache data returned (should be empty)
110
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
90
111
 
91
- expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
92
- });
112
+ await pause();
113
+
114
+ expect(callback).toHaveBeenCalledTimes(2);
115
+
116
+ snapshot.loading = false;
117
+ snapshot.data = snapshotData;
118
+
119
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
120
+ },
121
+ );
93
122
 
94
123
  test('it should return method to fetch next page', async () => {
95
124
  const callback = jest.fn();
@@ -102,7 +131,7 @@ describe('liveChannels', () => {
102
131
 
103
132
  expect(callback).toHaveBeenCalled();
104
133
 
105
- await expect(queryChannels()).resolves.toBeTruthy();
134
+ await pause();
106
135
 
107
136
  expect(callback.mock.lastCall).toHaveLength(1);
108
137
 
@@ -113,7 +142,7 @@ describe('liveChannels', () => {
113
142
 
114
143
  onNextPage();
115
144
 
116
- await expect(queryChannels()).resolves.toBeTruthy();
145
+ await pause();
117
146
 
118
147
  // 4 -> becuase 1 local & server call each per call (2)
119
148
  expect(callback).toHaveBeenCalledTimes(4);
@@ -146,7 +175,7 @@ describe('liveChannels', () => {
146
175
 
147
176
  liveChannels({}, callback);
148
177
 
149
- await expect(queryChannels()).resolves.toBeTruthy();
178
+ await pause();
150
179
  expect(callback).toHaveBeenCalledTimes(2);
151
180
 
152
181
  client.emitter.emit(event, {
@@ -9,7 +9,7 @@ import {
9
9
  channelUser2,
10
10
  } from '~/utils/tests';
11
11
 
12
- import { prepareChannelPayload } from '../../utils';
12
+ import { prepareChannelPayload } from '../prepareChannelPayload';
13
13
 
14
14
  beforeAll(async () => {
15
15
  await connectClient();
@@ -23,6 +23,7 @@ const WS_EVENTS = [
23
23
  'v3.channel.didBan',
24
24
  'v3.channel.didUnban',
25
25
 
26
+ 'v3.message.didFetch',
26
27
  'v3.message.didCreate',
27
28
  'v3.message.didUpdate',
28
29
  'v3.message.didDelete',
@@ -116,7 +117,7 @@ export const createEventSubscriber = <T extends keyof Amity.Events>(
116
117
  export const createMqttMessageSubscriber = <T extends keyof Amity.Events>(
117
118
  client: Amity.Client,
118
119
  namespace: string,
119
- event: string,
120
+ event: T,
120
121
  fn: (params: Record<string, unknown>) => void,
121
122
  ): Amity.Unsubscriber => {
122
123
  return createEventSubscriber(client, namespace, 'message', ([topic, message]) => {
@@ -1,3 +1,5 @@
1
+ import { getResolver } from '~/core/model';
2
+ import { pullFromCache } from '~/cache/api';
1
3
  // Note:
2
4
  // this file should contain a suite of filtering utilities to help the
3
5
  // local version of the query functions.
@@ -23,3 +25,50 @@ export const filterByPropInclusion = <T = Record<string, unknown>>(
23
25
  key: keyof T,
24
26
  value: any[] | undefined,
25
27
  ) => (value !== undefined ? collection.filter(item => value.includes(item[key])) : collection);
28
+
29
+ /**
30
+ * Filter a channel collection by membership of the userId
31
+ *
32
+ * @param collection the channel collection to filter
33
+ * @param membership the membership to be filtered by
34
+ * @param userId user id to be filtered by
35
+ * @returns a filtered collection with items only matching the criteria
36
+ *
37
+ * @hidden
38
+ */
39
+ export const filterByChannelMembership = (
40
+ collection: Amity.Channel[],
41
+ membership: Amity.ChannelLiveCollection['membership'],
42
+ userId: Amity.Membership<'channel'>['userId'],
43
+ ): Amity.Channel[] => {
44
+ if (membership === 'all') {
45
+ return collection;
46
+ }
47
+
48
+ return collection.filter(c => {
49
+ // get resolver for the channel by user
50
+ const channelUserCacheKey = getResolver('channelUsers')({
51
+ channelId: c.channelId,
52
+ userId,
53
+ });
54
+
55
+ const channelUser = pullFromCache<Amity.Membership<'channel'>>([
56
+ 'channelUsers',
57
+ 'get',
58
+ channelUserCacheKey,
59
+ ])?.data;
60
+
61
+ // if channel user is defined for user, user is a member
62
+ if (membership === 'member' && channelUser) {
63
+ return true;
64
+ }
65
+
66
+ // if channel user by user id not found, user is not a member of that
67
+ // channel
68
+ if (membership === 'notMember' && !channelUser) {
69
+ return true;
70
+ }
71
+
72
+ return false;
73
+ });
74
+ };
@@ -2,6 +2,8 @@
2
2
  import { isPaged } from './paging';
3
3
  import { identifyModelKey } from '~/core/model';
4
4
 
5
+ import { CACHE_LIFESPAN } from '~/cache/utils';
6
+
5
7
  /**
6
8
  * Type guard to check and cast that a given async function is has the ".locally" property
7
9
  *
@@ -71,7 +73,7 @@ export const isLocal = (model?: any): model is Amity.Local => {
71
73
  *
72
74
  * @hidden
73
75
  */
74
- export const isFresh = (model?: Amity.Cachable, lifeSpan = 0) => {
76
+ export const isFresh = (model?: Amity.Cachable, lifeSpan = CACHE_LIFESPAN) => {
75
77
  return Date.now() - (model?.cachedAt ?? 0) <= lifeSpan;
76
78
  };
77
79
 
@@ -111,12 +113,11 @@ export const createQuery = <Args extends any[], Returned extends any>(
111
113
  */
112
114
  export const queryOptions = (
113
115
  policy: Amity.QueryPolicy,
114
- lifeSpan: number = 2 * 60 * 1000, // 2mn
116
+ lifeSpan: number = CACHE_LIFESPAN, // 1mn
115
117
  ): Amity.QueryOptions => {
116
118
  if (policy === 'cache_only') return { lifeSpan: Infinity };
117
- if (policy === 'server_only') return { lifeSpan: 0 };
118
119
 
119
- return { lifeSpan };
120
+ return { lifeSpan: lifeSpan < CACHE_LIFESPAN ? CACHE_LIFESPAN : lifeSpan };
120
121
  };
121
122
 
122
123
  /**
@@ -168,8 +169,10 @@ export const runQuery = <Args extends any[], Returned extends any>(
168
169
  ) => {
169
170
  let local: Returned | undefined;
170
171
 
172
+ const { lifeSpan } = queryOptions('cache_then_server', options.lifeSpan);
173
+
171
174
  // offline first
172
- if (isOffline(func) && options.lifeSpan !== 0) {
175
+ if (isOffline(func)) {
173
176
  try {
174
177
  local = isMutator(func) ? func.optimistically(...args) : func.locally(...args);
175
178
  } catch (error) {
@@ -182,7 +185,7 @@ export const runQuery = <Args extends any[], Returned extends any>(
182
185
  );
183
186
  }
184
187
 
185
- const shouldAbort = isCachable(local) && isFresh(local, options.lifeSpan);
188
+ const shouldAbort = isCachable(local) && isFresh(local, lifeSpan);
186
189
 
187
190
  callback?.(
188
191
  createSnapshot<Returned>(local, {
@@ -7,6 +7,7 @@ import {
7
7
  isFresh,
8
8
  queryOptions,
9
9
  } from '~/core/query';
10
+ import { CACHE_LIFESPAN } from '~/cache/utils';
10
11
 
11
12
  describe('Core/Query', () => {
12
13
  type isFetcherMockType = jest.Mock<any, any> & {
@@ -90,8 +91,17 @@ describe('Core/Query', () => {
90
91
  });
91
92
 
92
93
  describe('queryOptions', () => {
93
- test('should return lifespan 0 if server only', () => {
94
- expect(queryOptions('server_only').lifeSpan).toBe(0);
94
+ test('should return minimum lifeSpan', () => {
95
+ expect(queryOptions('cache_then_server').lifeSpan).toBe(CACHE_LIFESPAN);
96
+ });
97
+
98
+ test('should return minimum lifeSpan if provided lifeSpan is less than cache lifeSpan', () => {
99
+ expect(queryOptions('cache_then_server', 0).lifeSpan).toBe(CACHE_LIFESPAN);
100
+ });
101
+
102
+ test('should return provided lifeSpan if provided lifeSpan is more than cache lifeSpan', () => {
103
+ const value = CACHE_LIFESPAN * 2;
104
+ expect(queryOptions('cache_then_server', value).lifeSpan).toBe(value);
95
105
  });
96
106
 
97
107
  test('should return lifespan Infinity if cache only', () => {
@@ -1,4 +1,5 @@
1
1
  import axios from 'axios';
2
+ import qs from 'qs';
2
3
  import HttpAgent, { HttpsAgent } from 'agentkeepalive';
3
4
 
4
5
  import { unwrapPayload } from './utils';
@@ -7,23 +8,8 @@ import { unwrapPayload } from './utils';
7
8
  * Axios param serializer (for querystring)
8
9
  * @hidden
9
10
  */
10
- const stringify = (params: Record<string, unknown>, prefix?: string): string => {
11
- return Object.entries(params)
12
- .filter(([, value]) => value !== undefined)
13
- .map(([name, value]) => {
14
- const key = prefix ? `${prefix}[${name}]` : name;
15
-
16
- if (Array.isArray(value)) {
17
- return value.map(item => `${key}[]=${item}`).join('&');
18
- }
19
- if (typeof value !== 'object') {
20
- return `${key}=${value}`;
21
- }
22
-
23
- // @ts-ignore
24
- return stringify(value, prefix ?? name);
25
- })
26
- .join('&');
11
+ export const stringify = (params: Record<string, unknown>): string => {
12
+ return qs.stringify(params, { arrayFormat: 'brackets' });
27
13
  };
28
14
 
29
15
  /**
@@ -0,0 +1,83 @@
1
+ import { createHttpTransport, stringify } from '../http';
2
+
3
+ describe('core/transports', () => {
4
+ describe('stringify', () => {
5
+ test('should serializer simple string', () => {
6
+ const params = { a: 'c' };
7
+ const url = stringify(params);
8
+ expect(url).toBe('a=c');
9
+ });
10
+
11
+ test('should serializer empty string', () => {
12
+ const params = { a: '' };
13
+ const url = stringify(params);
14
+ expect(url).toBe('a=');
15
+ });
16
+
17
+ test('should serializer special character', () => {
18
+ const params = { a: '✓', b: 'ø' };
19
+ const url = stringify(params);
20
+ expect(url).toBe('a=%E2%9C%93&b=%C3%B8');
21
+ });
22
+
23
+ test('should serializer boolean', () => {
24
+ const params = { a: true, b: false };
25
+ const url = stringify(params);
26
+ expect(url).toBe('a=true&b=false');
27
+ });
28
+
29
+ test('should serializer null ', () => {
30
+ const params = { a: null };
31
+ const url = stringify(params);
32
+ expect(url).toBe('a=');
33
+ });
34
+
35
+ test('should serializer undefined', () => {
36
+ const params = { a: undefined };
37
+ const url = stringify(params);
38
+ expect(url).toBe('');
39
+ });
40
+
41
+ test('should serializer NaN', () => {
42
+ const params = { a: NaN };
43
+ const url = stringify(params);
44
+ expect(url).toBe('a=NaN');
45
+ });
46
+
47
+ test('should serializer simple array', () => {
48
+ const params = { a: ['b', 'c', 'd'] };
49
+ const url = stringify(params);
50
+ expect(url).toBe('a%5B%5D=b&a%5B%5D=c&a%5B%5D=d');
51
+ });
52
+
53
+ test('should serializer complex array', () => {
54
+ const params = { a: ['b', { c: 'd' }] };
55
+ const url = stringify(params);
56
+ expect(url).toBe('a%5B%5D=b&a%5B%5D%5Bc%5D=d');
57
+ });
58
+
59
+ test('should serializer nested object', () => {
60
+ const params = { a: { b: 'c' } };
61
+ const url = stringify(params);
62
+ expect(url).toBe('a%5Bb%5D=c');
63
+ });
64
+
65
+ test('should serializer deep nested object', () => {
66
+ const params = { a: { b: { c: { d: { e: { f: { g: { h: { i: 'j' } } } } } } } } };
67
+ const url = stringify(params);
68
+ expect(url).toBe('a%5Bb%5D%5Bc%5D%5Bd%5D%5Be%5D%5Bf%5D%5Bg%5D%5Bh%5D%5Bi%5D=j');
69
+ });
70
+
71
+ test('should serializer empty object', () => {
72
+ const params = { a: { b: [] } };
73
+ const url = stringify(params);
74
+ expect(url).toBe('');
75
+ });
76
+ });
77
+
78
+ describe('createHttpTransport', () => {
79
+ test('should create axios instance with out error', () => {
80
+ expect(createHttpTransport('/')).not.toThrow();
81
+ });
82
+ });
83
+ });
@@ -1,9 +1,9 @@
1
+ import { uuid } from '~/core/uuid';
2
+ import { fireEvent } from '~/core/events';
1
3
  import { getActiveClient } from '~/client/api';
2
-
3
- import { upsertInCache, pullFromCache, pushToCache } from '~/cache/api';
4
4
  import { ingestInCache } from '~/cache/api/ingestInCache';
5
- import { fireEvent } from '~/core/events';
6
- import { uuid } from '~/core/uuid';
5
+ import { UNSYNCED_OBJECT_CACHED_AT_VALUE } from '~/utils/constants';
6
+ import { upsertInCache, pullFromCache, pushToCache } from '~/cache/api';
7
7
 
8
8
  /**
9
9
  * ```js
@@ -25,8 +25,11 @@ import { uuid } from '~/core/uuid';
25
25
  export const createMessage = async <T extends Amity.MessageContentType>(
26
26
  bundle: Pick<
27
27
  Amity.Message<T>,
28
- 'channelId' | 'parentId' | 'type' | 'data' | 'tags' | 'metadata' | 'mentionees'
29
- >,
28
+ 'channelId' | 'parentId' | 'type' | 'tags' | 'metadata' | 'mentionees'
29
+ > & {
30
+ data?: Amity.Message<T>['data'];
31
+ fileId?: Amity.Message<T>['fileId'];
32
+ },
30
33
  ): Promise<Amity.Cached<Amity.Message>> => {
31
34
  const client = getActiveClient();
32
35
 
@@ -36,10 +39,11 @@ export const createMessage = async <T extends Amity.MessageContentType>(
36
39
 
37
40
  const cachedAt = client.cache && Date.now();
38
41
  if (client.cache) ingestInCache(data, { cachedAt });
39
- // no need for event, fired by server
40
42
 
41
43
  const { messages } = data;
42
44
 
45
+ fireEvent('v3.message.didCreate', { messages });
46
+
43
47
  return {
44
48
  data: messages[0],
45
49
  cachedAt,
@@ -102,11 +106,13 @@ createMessage.optimistically = (
102
106
  ...bundleWithMessageId,
103
107
  } as Amity.Message;
104
108
 
105
- pushToCache(['message', 'get', message.messageId], message, { cachedAt: -1 });
109
+ const cachedAt = UNSYNCED_OBJECT_CACHED_AT_VALUE;
110
+
111
+ pushToCache(['message', 'get', message.messageId], message, { cachedAt });
106
112
  fireEvent('v3.message.didCreate', { messages: [message] });
107
113
 
108
114
  return {
115
+ cachedAt,
109
116
  data: message,
110
- cachedAt: -1,
111
117
  };
112
118
  };
@@ -1,10 +1,9 @@
1
1
  import { getActiveClient } from '~/client/api';
2
-
3
- import { getMessage } from './getMessage';
4
-
5
2
  import { pullFromCache, upsertInCache } from '~/cache/api';
6
3
  import { fireEvent } from '~/core/events';
7
4
 
5
+ import { getMessage } from './getMessage';
6
+
8
7
  /**
9
8
  * ```js
10
9
  * import { deleteMessage } from '@amityco/ts-sdk'
@@ -31,7 +30,8 @@ export const deleteMessage = async (
31
30
  );
32
31
 
33
32
  const deleted = await getMessage(messageId);
34
- // no need for event, fired by server
33
+
34
+ fireEvent('v3.message.didDelete', { messages: [deleted.data] });
35
35
 
36
36
  return deleted.data;
37
37
  };
@@ -1,8 +1,13 @@
1
1
  import { getActiveClient } from '~/client/api';
2
2
 
3
+ import { fireEvent } from '~/core/events';
3
4
  import { pullFromCache } from '~/cache/api';
4
5
  import { ingestInCache } from '~/cache/api/ingestInCache';
5
6
 
7
+ import { isInTombstone } from '~/cache/api/isInTombstone';
8
+ import { checkIfShouldGoesToTombstone } from '~/cache/utils';
9
+ import { pushToTombstone } from '~/cache/api/pushToTombstone';
10
+
6
11
  /**
7
12
  * ```js
8
13
  * import { getMessage } from '@amityco/ts-sdk'
@@ -19,20 +24,43 @@ import { ingestInCache } from '~/cache/api/ingestInCache';
19
24
  */
20
25
  export const getMessage = async (
21
26
  messageId: Amity.Message['messageId'],
27
+ isLive = false,
22
28
  ): Promise<Amity.Cached<Amity.Message>> => {
23
29
  const client = getActiveClient();
24
30
  client.log('message/getMessage', messageId);
25
31
 
26
- // API-FIX: endpoint should not be /list, parameters should be querystring.
27
- const { data } = await client.http.get<Amity.MessagePayload>(
28
- `/api/v3/messages/${encodeURIComponent(messageId)}`,
29
- );
32
+ if (!isLive) {
33
+ console.log(
34
+ 'getMessage will be deprecated on 15th November 2022, please use liveMessage instead.',
35
+ );
36
+ }
37
+
38
+ isInTombstone('message', messageId);
39
+
40
+ let data: Amity.MessagePayload;
41
+
42
+ try {
43
+ // API-FIX: endpoint should not be /list, parameters should be querystring.
44
+ const response = await client.http.get<Amity.MessagePayload>(
45
+ `/api/v3/messages/${encodeURIComponent(messageId)}`,
46
+ );
47
+
48
+ data = response.data;
49
+ } catch (error) {
50
+ if (checkIfShouldGoesToTombstone((error as Amity.ErrorResponse)?.code)) {
51
+ pushToTombstone('message', messageId);
52
+ }
53
+
54
+ throw error;
55
+ }
30
56
 
31
57
  const cachedAt = client.cache && Date.now();
32
58
  if (client.cache) ingestInCache(data, { cachedAt });
33
59
 
34
60
  const { messages } = data;
35
61
 
62
+ fireEvent('v3.message.didFetch', { messages });
63
+
36
64
  return {
37
65
  data: messages.find(message => message.messageId === messageId)!,
38
66
  cachedAt,
@@ -1,5 +1,6 @@
1
1
  import { getActiveClient } from '~/client/api';
2
2
 
3
+ import { fireEvent } from '~/core/events';
3
4
  import { pullFromCache } from '~/cache/api';
4
5
  import { ingestInCache } from '~/cache/api/ingestInCache';
5
6
 
@@ -31,8 +32,12 @@ export const getMessages = async (
31
32
  const cachedAt = client.cache && Date.now();
32
33
  if (client.cache) ingestInCache(data, { cachedAt });
33
34
 
35
+ const { messages } = data;
36
+
37
+ fireEvent('v3.message.didFetch', { messages });
38
+
34
39
  return {
35
- data: data.messages,
40
+ data: messages,
36
41
  cachedAt,
37
42
  };
38
43
  };