@amityco/ts-sdk 0.0.1-beta.36 → 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 (279) hide show
  1. package/.eslintrc.json +3 -5
  2. package/dist/@types/core/errors.d.ts +1 -0
  3. package/dist/@types/core/errors.d.ts.map +1 -1
  4. package/dist/@types/core/events.d.ts +5 -0
  5. package/dist/@types/core/events.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/client.d.ts +21 -1
  9. package/dist/@types/domains/client.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/global.d.ts +12 -0
  13. package/dist/@types/global.d.ts.map +1 -1
  14. package/dist/category/api/queryCategories.d.ts +1 -5
  15. package/dist/category/api/queryCategories.d.ts.map +1 -1
  16. package/dist/category/observers/index.d.ts +2 -0
  17. package/dist/category/observers/index.d.ts.map +1 -0
  18. package/dist/category/observers/liveCategories.d.ts +18 -0
  19. package/dist/category/observers/liveCategories.d.ts.map +1 -0
  20. package/dist/category/observers/tests/liveCategories.test.d.ts +2 -0
  21. package/dist/category/observers/tests/liveCategories.test.d.ts.map +1 -0
  22. package/dist/channel/api/tests/getChannels.test.d.ts +2 -0
  23. package/dist/channel/api/tests/getChannels.test.d.ts.map +1 -0
  24. package/dist/channel/api/tests/leaveChannel.test.d.ts +2 -0
  25. package/dist/channel/api/tests/leaveChannel.test.d.ts.map +1 -0
  26. package/dist/channel/observers/liveChannel.d.ts.map +1 -1
  27. package/dist/client/api/accessTokenExpiryWatcher.d.ts +7 -0
  28. package/dist/client/api/accessTokenExpiryWatcher.d.ts.map +1 -0
  29. package/dist/client/api/activeUser.d.ts +1 -1
  30. package/dist/client/api/activeUser.d.ts.map +1 -1
  31. package/dist/client/api/connectClient.d.ts +1 -1
  32. package/dist/client/api/connectClient.d.ts.map +1 -1
  33. package/dist/client/api/createClient.d.ts +1 -1
  34. package/dist/client/api/createClient.d.ts.map +1 -1
  35. package/dist/client/api/disconnectClient.d.ts +0 -1
  36. package/dist/client/api/disconnectClient.d.ts.map +1 -1
  37. package/dist/client/api/getToken.d.ts +7 -5
  38. package/dist/client/api/getToken.d.ts.map +1 -1
  39. package/dist/client/api/index.d.ts +1 -0
  40. package/dist/client/api/index.d.ts.map +1 -1
  41. package/dist/client/api/renewal.d.ts +2 -0
  42. package/dist/client/api/renewal.d.ts.map +1 -0
  43. package/dist/client/api/setSessionState.d.ts +12 -0
  44. package/dist/client/api/setSessionState.d.ts.map +1 -0
  45. package/dist/client/api/terminateClient.d.ts +9 -0
  46. package/dist/client/api/terminateClient.d.ts.map +1 -0
  47. package/dist/client/api/tests/accessTokenExpiryWatcher.test.d.ts +2 -0
  48. package/dist/client/api/tests/accessTokenExpiryWatcher.test.d.ts.map +1 -0
  49. package/dist/client/api/tests/connectClient.test.d.ts +2 -0
  50. package/dist/client/api/tests/connectClient.test.d.ts.map +1 -0
  51. package/dist/client/api/tests/disconnectClient.test.d.ts +2 -0
  52. package/dist/client/api/tests/disconnectClient.test.d.ts.map +1 -0
  53. package/dist/client/api/tests/getToken.test.d.ts +2 -0
  54. package/dist/client/api/tests/getToken.test.d.ts.map +1 -0
  55. package/dist/client/api/tests/renewal.test.d.ts +2 -0
  56. package/dist/client/api/tests/renewal.test.d.ts.map +1 -0
  57. package/dist/client/api/tests/setSessionState.test.d.ts +2 -0
  58. package/dist/client/api/tests/setSessionState.test.d.ts.map +1 -0
  59. package/dist/client/api/tests/terminateClient.test.d.ts +2 -0
  60. package/dist/client/api/tests/terminateClient.test.d.ts.map +1 -0
  61. package/dist/client/events/index.d.ts +1 -0
  62. package/dist/client/events/index.d.ts.map +1 -1
  63. package/dist/client/events/onClientBanned.d.ts +1 -1
  64. package/dist/client/events/onClientBanned.d.ts.map +1 -1
  65. package/dist/client/events/onSessionStateChange.d.ts +17 -0
  66. package/dist/client/events/onSessionStateChange.d.ts.map +1 -0
  67. package/dist/client/events/onTokenExpired.d.ts +17 -0
  68. package/dist/client/events/onTokenExpired.d.ts.map +1 -0
  69. package/dist/client/events/onTokenTerminated.d.ts +11 -0
  70. package/dist/client/events/onTokenTerminated.d.ts.map +1 -0
  71. package/dist/client/events/tests/onSessionStateChange.test.d.ts +2 -0
  72. package/dist/client/events/tests/onSessionStateChange.test.d.ts.map +1 -0
  73. package/dist/client/events/tests/onTokenTerminated.test.d.ts +2 -0
  74. package/dist/client/events/tests/onTokenTerminated.test.d.ts.map +1 -0
  75. package/dist/client/utils/setClientToken.d.ts +19 -0
  76. package/dist/client/utils/setClientToken.d.ts.map +1 -0
  77. package/dist/comment/api/deleteComment.d.ts.map +1 -1
  78. package/dist/comment/api/getComment.d.ts.map +1 -1
  79. package/dist/comment/events/tests/onCommentDeleted.test.d.ts +2 -0
  80. package/dist/comment/events/tests/onCommentDeleted.test.d.ts.map +1 -0
  81. package/dist/comment/observers/index.d.ts +1 -0
  82. package/dist/comment/observers/index.d.ts.map +1 -1
  83. package/dist/comment/observers/liveComment.d.ts +21 -0
  84. package/dist/comment/observers/liveComment.d.ts.map +1 -0
  85. package/dist/comment/observers/tests/liveComment.test.d.ts +2 -0
  86. package/dist/comment/observers/tests/liveComment.test.d.ts.map +1 -0
  87. package/dist/community/api/queryCommunities.d.ts +1 -10
  88. package/dist/community/api/queryCommunities.d.ts.map +1 -1
  89. package/dist/community/events/index.d.ts +1 -0
  90. package/dist/community/events/index.d.ts.map +1 -1
  91. package/dist/community/events/onCommunityUserChanged.d.ts +17 -0
  92. package/dist/community/events/onCommunityUserChanged.d.ts.map +1 -0
  93. package/dist/community/events/utils.d.ts +1 -0
  94. package/dist/community/events/utils.d.ts.map +1 -1
  95. package/dist/community/observers/index.d.ts +1 -0
  96. package/dist/community/observers/index.d.ts.map +1 -1
  97. package/dist/community/observers/liveCommunities.d.ts +20 -0
  98. package/dist/community/observers/liveCommunities.d.ts.map +1 -0
  99. package/dist/community/observers/tests/liveCommunities.test.d.ts +2 -0
  100. package/dist/community/observers/tests/liveCommunities.test.d.ts.map +1 -0
  101. package/dist/core/events.d.ts +3 -3
  102. package/dist/core/events.d.ts.map +1 -1
  103. package/dist/core/query/sorting.d.ts +6 -0
  104. package/dist/core/query/sorting.d.ts.map +1 -1
  105. package/dist/core/subscription.d.ts.map +1 -1
  106. package/dist/core/transports/http.d.ts +0 -5
  107. package/dist/core/transports/http.d.ts.map +1 -1
  108. package/dist/file/api/test/createImage.test.d.ts +2 -0
  109. package/dist/file/api/test/createImage.test.d.ts.map +1 -0
  110. package/dist/file/api/test/createVideo.test.d.ts +2 -0
  111. package/dist/file/api/test/createVideo.test.d.ts.map +1 -0
  112. package/dist/index.cjs.js +944 -332
  113. package/dist/index.d.ts +1 -0
  114. package/dist/index.d.ts.map +1 -1
  115. package/dist/index.esm.js +937 -332
  116. package/dist/index.umd.js +4 -4
  117. package/dist/message/observers/liveMessage.d.ts.map +1 -1
  118. package/dist/post/observers/index.d.ts +1 -0
  119. package/dist/post/observers/index.d.ts.map +1 -1
  120. package/dist/post/observers/livePost.d.ts +21 -0
  121. package/dist/post/observers/livePost.d.ts.map +1 -0
  122. package/dist/post/observers/tests/livePost.test.d.ts +2 -0
  123. package/dist/post/observers/tests/livePost.test.d.ts.map +1 -0
  124. package/dist/stream/api/tests/createStream.test.d.ts +2 -0
  125. package/dist/stream/api/tests/createStream.test.d.ts.map +1 -0
  126. package/dist/stream/api/tests/deleteStream.test.d.ts +2 -0
  127. package/dist/stream/api/tests/deleteStream.test.d.ts.map +1 -0
  128. package/dist/stream/api/tests/getStream.test.d.ts +2 -0
  129. package/dist/stream/api/tests/getStream.test.d.ts.map +1 -0
  130. package/dist/subChannel/api/tests/createSubChannel.test.d.ts +2 -0
  131. package/dist/subChannel/api/tests/createSubChannel.test.d.ts.map +1 -0
  132. package/dist/subChannel/api/tests/deleteSubChannel.test.d.ts +2 -0
  133. package/dist/subChannel/api/tests/deleteSubChannel.test.d.ts.map +1 -0
  134. package/dist/subChannel/api/tests/getSubChannel.test.d.ts +2 -0
  135. package/dist/subChannel/api/tests/getSubChannel.test.d.ts.map +1 -0
  136. package/dist/subChannel/api/tests/getSubChannels.test.d.ts +2 -0
  137. package/dist/subChannel/api/tests/getSubChannels.test.d.ts.map +1 -0
  138. package/dist/subChannel/api/tests/updateSubChannel.test.d.ts +2 -0
  139. package/dist/subChannel/api/tests/updateSubChannel.test.d.ts.map +1 -0
  140. package/dist/subChannel/observers/liveSubChannel.d.ts.map +1 -1
  141. package/dist/user/api/tests/updateUser.test.d.ts +2 -0
  142. package/dist/user/api/tests/updateUser.test.d.ts.map +1 -0
  143. package/dist/user/observers/liveUser.d.ts.map +1 -1
  144. package/dist/utils/constants.d.ts +2 -0
  145. package/dist/utils/constants.d.ts.map +1 -1
  146. package/dist/utils/liveObject.d.ts +2 -0
  147. package/dist/utils/liveObject.d.ts.map +1 -0
  148. package/dist/utils/tests/client.d.ts.map +1 -1
  149. package/dist/utils/tests/dummy/category.d.ts +64 -0
  150. package/dist/utils/tests/dummy/category.d.ts.map +1 -0
  151. package/dist/utils/tests/dummy/channel.d.ts +50 -0
  152. package/dist/utils/tests/dummy/channel.d.ts.map +1 -1
  153. package/dist/utils/tests/dummy/community.d.ts +132 -0
  154. package/dist/utils/tests/dummy/community.d.ts.map +1 -1
  155. package/dist/utils/tests/dummy/file.d.ts +3 -0
  156. package/dist/utils/tests/dummy/file.d.ts.map +1 -1
  157. package/dist/utils/tests/dummy/index.d.ts +3 -0
  158. package/dist/utils/tests/dummy/index.d.ts.map +1 -1
  159. package/dist/utils/tests/dummy/post.d.ts +2 -0
  160. package/dist/utils/tests/dummy/post.d.ts.map +1 -1
  161. package/dist/utils/tests/dummy/stream.d.ts +83 -0
  162. package/dist/utils/tests/dummy/stream.d.ts.map +1 -0
  163. package/dist/utils/tests/dummy/token.d.ts +11 -0
  164. package/dist/utils/tests/dummy/token.d.ts.map +1 -0
  165. package/dist/utils/tests/dummy/user.d.ts +18 -0
  166. package/dist/utils/tests/dummy/user.d.ts.map +1 -1
  167. package/dist/utils/tests/liveObject.test.d.ts +2 -0
  168. package/dist/utils/tests/liveObject.test.d.ts.map +1 -0
  169. package/package.json +4 -4
  170. package/src/@types/core/errors.ts +1 -0
  171. package/src/@types/core/events.ts +7 -0
  172. package/src/@types/domains/category.ts +13 -0
  173. package/src/@types/domains/client.ts +45 -1
  174. package/src/@types/domains/community.ts +25 -0
  175. package/src/@types/global.ts +19 -0
  176. package/src/category/api/queryCategories.ts +3 -5
  177. package/src/category/observers/index.ts +1 -0
  178. package/src/category/observers/liveCategories.ts +141 -0
  179. package/src/category/observers/tests/liveCategories.test.ts +147 -0
  180. package/src/channel/api/tests/createChannel.test.ts +30 -6
  181. package/src/channel/api/tests/getChannel.test.ts +3 -1
  182. package/src/channel/api/tests/getChannels.test.ts +97 -0
  183. package/src/channel/api/tests/joinChannel.test.ts +62 -3
  184. package/src/channel/api/tests/leaveChannel.test.ts +90 -0
  185. package/src/channel/api/tests/queryChannels.test.ts +38 -1
  186. package/src/channel/observers/liveChannel.ts +8 -80
  187. package/src/client/api/accessTokenExpiryWatcher.ts +85 -0
  188. package/src/client/api/activeUser.ts +1 -1
  189. package/src/client/api/connectClient.ts +105 -24
  190. package/src/client/api/createClient.ts +9 -1
  191. package/src/client/api/disconnectClient.ts +26 -2
  192. package/src/client/api/getToken.ts +6 -6
  193. package/src/client/api/index.ts +2 -0
  194. package/src/client/api/renewal.ts +74 -0
  195. package/src/client/api/setSessionState.ts +75 -0
  196. package/src/client/api/terminateClient.ts +20 -0
  197. package/src/client/api/tests/accessTokenExpiryWatcher.test.ts +132 -0
  198. package/src/client/api/tests/connectClient.test.ts +84 -0
  199. package/src/client/api/tests/createClient.test.ts +8 -0
  200. package/src/client/api/tests/disconnectClient.test.ts +78 -0
  201. package/src/client/api/tests/getToken.test.ts +36 -0
  202. package/src/client/api/tests/renewal.test.ts +67 -0
  203. package/src/client/api/tests/setSessionState.test.ts +62 -0
  204. package/src/client/api/tests/terminateClient.test.ts +29 -0
  205. package/src/client/events/index.ts +2 -0
  206. package/src/client/events/onClientBanned.ts +12 -5
  207. package/src/client/events/onSessionStateChange.ts +31 -0
  208. package/src/client/events/onTokenExpired.ts +26 -0
  209. package/src/client/events/onTokenTerminated.ts +20 -0
  210. package/src/client/events/tests/onSessionStateChange.test.ts +37 -0
  211. package/src/client/events/tests/onTokenTerminated.test.ts +37 -0
  212. package/src/client/tests/connectClient.test.ts +6 -1
  213. package/src/client/utils/setClientToken.ts +39 -0
  214. package/src/comment/api/deleteComment.ts +5 -5
  215. package/src/comment/api/getComment.ts +8 -3
  216. package/src/comment/events/tests/onCommentDeleted.test.ts +27 -0
  217. package/src/comment/observers/index.ts +1 -0
  218. package/src/comment/observers/liveComment.ts +43 -0
  219. package/src/comment/observers/tests/liveComment.test.ts +95 -0
  220. package/src/community/api/queryCommunities.ts +3 -10
  221. package/src/community/api/test/addCommunityMember.test.ts +14 -2
  222. package/src/community/api/test/joinCommunity.test.ts +14 -2
  223. package/src/community/api/test/leaveCommunity.test.ts +11 -1
  224. package/src/community/api/test/removeCommunityMembers.test.ts +11 -1
  225. package/src/community/events/index.ts +1 -0
  226. package/src/community/events/onCommunityUserChanged.ts +20 -0
  227. package/src/community/events/test/onCommunityJoined.test.ts +1 -1
  228. package/src/community/events/test/onCommunityUserAdded.test.ts +1 -1
  229. package/src/community/events/test/onCommunityUserBanned.test.ts +1 -1
  230. package/src/community/events/test/onCommunityUserUnbaned.test.ts +1 -1
  231. package/src/community/events/test/utils.test.ts +52 -3
  232. package/src/community/events/utils.ts +49 -0
  233. package/src/community/observers/index.ts +1 -0
  234. package/src/community/observers/liveCommunities.ts +188 -0
  235. package/src/community/observers/tests/liveCommunities.test.ts +284 -0
  236. package/src/core/events.ts +5 -3
  237. package/src/core/query/sorting.ts +8 -0
  238. package/src/core/subscription.ts +3 -1
  239. package/src/core/transports/http.ts +52 -13
  240. package/src/core/transports/mqtt.ts +1 -1
  241. package/src/core/transports/test/http.test.ts +49 -60
  242. package/src/external/api/createUserToken.ts +2 -2
  243. package/src/file/api/createFile.ts +1 -1
  244. package/src/file/api/createImage.ts +1 -1
  245. package/src/file/api/createVideo.ts +1 -1
  246. package/src/file/api/test/createImage.test.ts +69 -0
  247. package/src/file/api/test/createVideo.test.ts +81 -0
  248. package/src/index.ts +1 -0
  249. package/src/message/observers/liveMessage.ts +11 -83
  250. package/src/message/tests/observers/liveMessage.test.ts +1 -143
  251. package/src/post/observers/index.ts +1 -0
  252. package/src/post/observers/livePost.ts +47 -0
  253. package/src/post/observers/tests/livePost.test.ts +97 -0
  254. package/src/stream/api/tests/createStream.test.ts +22 -0
  255. package/src/stream/api/tests/deleteStream.test.ts +50 -0
  256. package/src/stream/api/tests/getStream.test.ts +23 -0
  257. package/src/subChannel/api/tests/createSubChannel.test.ts +110 -0
  258. package/src/subChannel/api/tests/deleteSubChannel.test.ts +112 -0
  259. package/src/subChannel/api/tests/getSubChannel.test.ts +97 -0
  260. package/src/subChannel/api/tests/getSubChannels.test.ts +97 -0
  261. package/src/subChannel/api/tests/updateSubChannel.test.ts +86 -0
  262. package/src/subChannel/observers/liveSubChannel.ts +6 -56
  263. package/src/subChannel/observers/tests/liveSubChannel.test.ts +0 -82
  264. package/src/user/api/tests/updateUser.test.ts +60 -0
  265. package/src/user/observers/liveUser.ts +9 -61
  266. package/src/user/tests/observers/liveUser.test.ts +1 -154
  267. package/src/utils/constants.ts +2 -0
  268. package/src/utils/liveObject.ts +86 -0
  269. package/src/utils/tests/client.ts +18 -2
  270. package/src/utils/tests/dummy/category.ts +57 -0
  271. package/src/utils/tests/dummy/channel.ts +51 -1
  272. package/src/utils/tests/dummy/community.ts +94 -0
  273. package/src/utils/tests/dummy/file.ts +32 -0
  274. package/src/utils/tests/dummy/index.ts +4 -0
  275. package/src/utils/tests/dummy/post.ts +56 -45
  276. package/src/utils/tests/dummy/stream.ts +86 -0
  277. package/src/utils/tests/dummy/token.ts +12 -0
  278. package/src/utils/tests/dummy/user.ts +21 -0
  279. package/src/utils/tests/liveObject.test.ts +172 -0
@@ -0,0 +1,188 @@
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
+ import {
6
+ createQuery,
7
+ runQuery,
8
+ queryOptions,
9
+ filterByPropEquality,
10
+ sortByLastCreated,
11
+ sortByDisplayName,
12
+ sortByFirstCreated,
13
+ } from '~/core/query';
14
+ import {
15
+ COLLECTION_DEFAULT_CACHING_POLICY,
16
+ COLLECTION_DEFAULT_PAGINATION_LIMIT,
17
+ ENABLE_CACHE_MESSAGE,
18
+ } from '~/utils/constants';
19
+ import {
20
+ onCommunityCreated,
21
+ onCommunityDeleted,
22
+ onCommunityUpdated,
23
+ onCommunityJoined,
24
+ onCommunityLeft,
25
+ onCommunityUserChanged,
26
+ } from '../events';
27
+ import { queryCommunities } from '../api';
28
+
29
+ /**
30
+ * ```js
31
+ * import { liveCommunities } from '@amityco/ts-sdk'
32
+ *
33
+ * let communities = []
34
+ * const unsub = liveCommunities({
35
+ * displayName: Amity.Community['displayName'],
36
+ * }, response => merge(communities, response.data))
37
+ * ```
38
+ *
39
+ * Observe all mutations on a list of {@link Amity.Community}s
40
+ *
41
+ * @param params for querying communities
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 communities
44
+ *
45
+ * @category Community Live Collection
46
+ */
47
+ export const liveCommunities = (
48
+ params: Amity.CommunityLiveCollection,
49
+ callback: Amity.LiveCollectionCallback<Amity.Community>,
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(`liveCommunities(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 = ['community', 'collection', {}];
68
+
69
+ const responder = (data: Amity.CommunityLiveCollectionCache) => {
70
+ let communities: Amity.Community[] =
71
+ data.data
72
+ .map(communityId => pullFromCache<Amity.Community>(['community', 'get', communityId])!)
73
+ .filter(Boolean)
74
+ .map(({ data }) => data) ?? [];
75
+
76
+ communities = filterByPropEquality(communities, 'isDeleted', params.isDeleted);
77
+ communities = filterByPropEquality(communities, 'displayName', params.displayName);
78
+
79
+ if (params.categoryId) {
80
+ communities = communities.filter(c => c.categoryIds?.includes(params.categoryId!));
81
+ }
82
+
83
+ if (params.tags) {
84
+ communities = communities.filter(c => c.tags?.some(t => params.tags?.includes(t)));
85
+ }
86
+
87
+ if (params.membership === 'member') {
88
+ communities = filterByPropEquality(communities, 'isJoined', true);
89
+ }
90
+
91
+ if (params.membership === 'notMember') {
92
+ communities = filterByPropEquality(communities, 'isJoined', false);
93
+ }
94
+
95
+ const sortBy = params.sortBy || 'lastCreated';
96
+
97
+ if (sortBy === 'lastCreated' || sortBy === 'firstCreated') {
98
+ communities = communities.sort(
99
+ sortBy === 'lastCreated' ? sortByLastCreated : sortByFirstCreated,
100
+ );
101
+ }
102
+
103
+ /*
104
+ * The server returns communities with empty | null displayName's first before
105
+ * returning sorted list of communities with displayNames
106
+ *
107
+ * This section needs to be updated as displayNames can be null as well
108
+ */
109
+ if (sortBy === 'displayName') {
110
+ communities = communities
111
+ // this needs to be aligned with the backend data type
112
+ .map(c => (c.displayName ? c : { ...c, displayName: '' }))
113
+ // @ts-ignore
114
+ .sort(sortByDisplayName);
115
+ }
116
+
117
+ callback({
118
+ onNextPage: onFetch,
119
+ data: communities,
120
+ hasNextPage: !!data.params?.page,
121
+ loading: data.loading,
122
+ error: data.error,
123
+ });
124
+ };
125
+
126
+ const realtimeRouter = (_: Amity.CommunityActionType) => (community: Amity.Community) => {
127
+ const collection = pullFromCache<Amity.CommunityLiveCollectionCache>(cacheKey)?.data;
128
+ if (!collection) return;
129
+
130
+ /*
131
+ * Simply update collection and let responder decide what to do with data
132
+ */
133
+ collection.data = [...new Set([community.communityId, ...collection.data])];
134
+
135
+ pushToCache(cacheKey, collection);
136
+ responder(collection);
137
+ };
138
+
139
+ const onFetch = () => {
140
+ const collection = pullFromCache<Amity.CommunityLiveCollectionCache>(cacheKey)?.data;
141
+
142
+ const communities = collection?.data ?? [];
143
+
144
+ if (communities.length > 0 && !collection?.params.page) return;
145
+
146
+ const query = createQuery(queryCommunities, {
147
+ ...queryParams,
148
+ page: collection?.params.page ?? { limit },
149
+ });
150
+
151
+ runQuery(
152
+ query,
153
+ ({ data: result, error, loading, nextPage: page }) => {
154
+ const data = {
155
+ loading,
156
+ error,
157
+ params: { page },
158
+ data: communities,
159
+ };
160
+
161
+ if (result) {
162
+ data.data = [...new Set([...communities, ...result.map(getResolver('community'))])];
163
+ }
164
+
165
+ pushToCache(cacheKey, data);
166
+
167
+ responder(data);
168
+ },
169
+ queryOptions(policy),
170
+ );
171
+ };
172
+
173
+ disposers.push(
174
+ onCommunityCreated(realtimeRouter('onCreate')),
175
+ onCommunityDeleted(realtimeRouter('onDelete')),
176
+ onCommunityUpdated(realtimeRouter('onUpdate')),
177
+ onCommunityJoined(realtimeRouter('onJoin')),
178
+ onCommunityLeft(realtimeRouter('onLeft')),
179
+ onCommunityUserChanged(realtimeRouter('onMemberCountChanged')),
180
+ );
181
+
182
+ onFetch();
183
+
184
+ return () => {
185
+ log(`liveCommunities(tmpid: ${timestamp}) > dispose`);
186
+ disposers.forEach(fn => fn());
187
+ };
188
+ };
@@ -0,0 +1,284 @@
1
+ import { disableCache, enableCache } from '~/cache/api';
2
+ import {
3
+ communityQueryResponse,
4
+ communityQueryResponsePage2,
5
+ client,
6
+ connectClient,
7
+ disconnectClient,
8
+ pause,
9
+ communityUser11,
10
+ } from '~/utils/tests';
11
+
12
+ import { liveCommunities } from '../liveCommunities';
13
+
14
+ import { unpackCommunityPayload } from '../../utils';
15
+
16
+ const getSnapshot = (params?: Record<string, any>) => {
17
+ return {
18
+ data: [] as Amity.Community[],
19
+ loading: true,
20
+ error: undefined as any,
21
+ ...params,
22
+ };
23
+ };
24
+
25
+ const { paging, ...payload } = communityQueryResponse.data;
26
+ const { paging: paging2, ...payload2 } = communityQueryResponsePage2.data;
27
+
28
+ const community1 = unpackCommunityPayload(payload).communities[0];
29
+ const community2 = unpackCommunityPayload(payload).communities[1];
30
+
31
+ describe('liveCommunities', () => {
32
+ beforeAll(connectClient);
33
+ afterAll(disconnectClient);
34
+
35
+ beforeEach(enableCache);
36
+
37
+ afterEach(disableCache);
38
+
39
+ test('it should return community collection', async () => {
40
+ const callback = jest.fn();
41
+ client.http.get = jest.fn().mockResolvedValue(communityQueryResponse);
42
+
43
+ liveCommunities({}, callback);
44
+ await pause();
45
+
46
+ expect(callback).toHaveBeenCalledTimes(2);
47
+ expect(callback).toHaveBeenNthCalledWith(1, expect.objectContaining(getSnapshot()));
48
+ expect(callback).toHaveBeenNthCalledWith(
49
+ 2,
50
+ expect.objectContaining(
51
+ getSnapshot({
52
+ data: unpackCommunityPayload(payload).communities,
53
+ loading: false,
54
+ }),
55
+ ),
56
+ );
57
+ });
58
+
59
+ test('it should return data from cache', async () => {
60
+ const callback = jest.fn();
61
+ client.http.get = jest.fn().mockResolvedValue(communityQueryResponse);
62
+
63
+ liveCommunities({}, () => undefined);
64
+ await pause();
65
+ liveCommunities({}, callback);
66
+ await pause();
67
+
68
+ expect(callback).toHaveBeenCalledTimes(2);
69
+ expect(callback).toHaveBeenNthCalledWith(
70
+ 1,
71
+ expect.objectContaining(
72
+ getSnapshot({
73
+ data: unpackCommunityPayload(payload).communities,
74
+ }),
75
+ ),
76
+ );
77
+ expect(callback).toHaveBeenNthCalledWith(
78
+ 2,
79
+ expect.objectContaining(
80
+ getSnapshot({
81
+ data: unpackCommunityPayload(payload).communities,
82
+ loading: false,
83
+ }),
84
+ ),
85
+ );
86
+ });
87
+
88
+ const filters: [string, Amity.CommunityLiveCollection, Amity.Community[]][] = [
89
+ ['deleted', { isDeleted: true }, [community1]],
90
+ ['categoryId', { categoryId: 'test-category-id' }, [community1]],
91
+ ['displayName', { displayName: 'community 1' }, [community1]],
92
+ ['tagged', { tags: ['test-community-tag'] }, [community1]],
93
+ ['member', { membership: 'member' }, [community1]],
94
+ ['not member', { membership: 'notMember' }, [community2]],
95
+ ['all membership', { membership: 'all' }, [community1, community2]],
96
+ ];
97
+
98
+ test.each(filters)('it should filter by %s communities', async (filter, params, expected) => {
99
+ const callback = jest.fn();
100
+ client.http.get = jest.fn().mockResolvedValue(communityQueryResponse);
101
+
102
+ liveCommunities(params, callback);
103
+
104
+ expect(callback).toHaveBeenCalledTimes(1);
105
+ // check if cache data returned (should be empty)
106
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining(getSnapshot()));
107
+
108
+ await pause();
109
+
110
+ expect(callback).toHaveBeenCalledTimes(2);
111
+ expect(callback).toHaveBeenCalledWith(
112
+ expect.objectContaining(
113
+ getSnapshot({
114
+ loading: false,
115
+ data: expected,
116
+ }),
117
+ ),
118
+ );
119
+ });
120
+
121
+ test('it should return method to fetch next page', async () => {
122
+ const callback = jest.fn();
123
+ client.http.get = jest
124
+ .fn()
125
+ .mockResolvedValue(communityQueryResponse)
126
+ .mockResolvedValueOnce(communityQueryResponsePage2);
127
+
128
+ liveCommunities({}, callback);
129
+ await pause();
130
+
131
+ expect(callback).toHaveBeenCalled();
132
+ expect(callback.mock.lastCall).toHaveLength(1);
133
+
134
+ const { onNextPage, hasNextPage } = callback.mock.lastCall[0];
135
+
136
+ expect(hasNextPage).toBe(true);
137
+ expect(onNextPage).toBeTruthy();
138
+
139
+ onNextPage();
140
+ await pause();
141
+
142
+ // 4 -> because 1 local & server call each per call (2)
143
+ expect(callback).toHaveBeenCalledTimes(4);
144
+ expect(callback).toHaveBeenNthCalledWith(
145
+ 4,
146
+ expect.objectContaining(
147
+ getSnapshot({
148
+ loading: false,
149
+ data: unpackCommunityPayload(payload).communities,
150
+ }),
151
+ ),
152
+ );
153
+ });
154
+
155
+ describe('events', () => {
156
+ const newCommunityPayload = {
157
+ ...communityQueryResponse.data.communities[0],
158
+ communityId: 'new-community',
159
+ isDeleted: false,
160
+ };
161
+ const newCommunity = unpackCommunityPayload({ communities: [newCommunityPayload] })
162
+ .communities[0];
163
+
164
+ const communityPayload = {
165
+ communities: [communityQueryResponse.data.communities[0]],
166
+ communityUsers: [communityUser11],
167
+ };
168
+
169
+ const cases: [string, keyof Amity.Events, Amity.CommunityPayload, Amity.Community[]][] = [
170
+ [
171
+ 'it should add new community to collection onCreate',
172
+ 'community.created',
173
+ { communities: [newCommunityPayload] },
174
+ [newCommunity, community2],
175
+ ],
176
+ [
177
+ 'it should update community in collection onUpdate',
178
+ 'community.updated',
179
+ { communities: [{ ...newCommunityPayload, communityId: community1.communityId }] },
180
+ [{ ...newCommunity, communityId: community1.communityId }, community2],
181
+ ],
182
+ [
183
+ 'it should remove community from collection onDelete',
184
+ 'community.deleted',
185
+ communityPayload,
186
+ [community2],
187
+ ],
188
+ ];
189
+
190
+ test.each(cases)('%s', async (test, event, communityPayload, expected) => {
191
+ const callback = jest.fn();
192
+ client.http.get = jest.fn().mockResolvedValue(communityQueryResponse);
193
+
194
+ liveCommunities({ isDeleted: false }, callback);
195
+ await pause();
196
+
197
+ client.emitter.emit(event, communityPayload);
198
+ await pause();
199
+
200
+ expect(callback).toHaveBeenNthCalledWith(
201
+ 3,
202
+ expect.objectContaining(
203
+ getSnapshot({
204
+ data: expected,
205
+ loading: false,
206
+ }),
207
+ ),
208
+ );
209
+ });
210
+
211
+ const joinCommunityPayload = {
212
+ ...communityQueryResponse.data.communities[0],
213
+ communityId: 'joining-community',
214
+ isDeleted: false,
215
+ };
216
+ const joinedCommunity = unpackCommunityPayload({ communities: [joinCommunityPayload] })
217
+ .communities[0];
218
+
219
+ const joiningUser: Amity.MembershipRaw<'community'> = {
220
+ ...communityUser11,
221
+ userId: 'test',
222
+ communityId: 'joining-community',
223
+ communityMembership: 'member',
224
+ };
225
+
226
+ const memberEvents: [
227
+ string,
228
+ Amity.CommunityLiveCollection,
229
+ keyof Amity.Events,
230
+ Amity.CommunityPayload,
231
+ Amity.Community[],
232
+ ][] = [
233
+ [
234
+ 'it should add new community to collection onJoin',
235
+ { membership: 'member' },
236
+ 'community.joined',
237
+ { communities: [joinCommunityPayload], communityUsers: [joiningUser] },
238
+ [joinedCommunity, community1],
239
+ ],
240
+ [
241
+ 'it should not add new member to community collection onJoin if membership:not member',
242
+ { membership: 'notMember' },
243
+ 'community.joined',
244
+ { communities: [joinCommunityPayload], communityUsers: [joiningUser] },
245
+ [],
246
+ ],
247
+ [
248
+ 'it should update community in collection onLeft',
249
+ { membership: 'member' },
250
+ 'community.left',
251
+ { ...communityPayload, communities: [{ ...community1, isJoined: false }] },
252
+ [],
253
+ ],
254
+ [
255
+ 'it should add new community in collection onLeft and if membership:not member',
256
+ { membership: 'notMember' },
257
+ 'community.left',
258
+ { ...communityPayload, communities: [{ ...community1, isJoined: false }] },
259
+ [{ ...community1, isJoined: false }],
260
+ ],
261
+ ];
262
+
263
+ test.each(memberEvents)('%s', async (test, params, event, communityPayload, expected) => {
264
+ const callback = jest.fn();
265
+ client.http.get = jest.fn().mockResolvedValue(communityQueryResponsePage2);
266
+
267
+ liveCommunities(params, callback);
268
+ await pause();
269
+
270
+ client.emitter.emit(event, communityPayload);
271
+ await pause();
272
+
273
+ expect(callback).toHaveBeenNthCalledWith(
274
+ 3,
275
+ expect.objectContaining(
276
+ getSnapshot({
277
+ data: expected,
278
+ loading: false,
279
+ }),
280
+ ),
281
+ );
282
+ });
283
+ });
284
+ });
@@ -12,6 +12,9 @@ const WS_EVENTS = [
12
12
  'connect_error',
13
13
  'reconnect_error',
14
14
  'reconnect_failed',
15
+ 'sessionStateChange',
16
+ // for internal use by accessTokenExpiryWatcher
17
+ 'tokenExpired',
15
18
  ] as const;
16
19
 
17
20
  const MQTT_EVENTS = [
@@ -22,6 +25,8 @@ const MQTT_EVENTS = [
22
25
  'close',
23
26
  'end',
24
27
  'reconnect',
28
+
29
+ 'user.didGlobalBan',
25
30
  ] as const;
26
31
 
27
32
  /** @hidden */
@@ -42,7 +47,6 @@ export const createEventEmitter = () => {
42
47
  export const proxyWebsocketEvents = (ws: Amity.Client['ws'], emitter: Amity.Client['emitter']) => {
43
48
  WS_EVENTS.forEach(event => {
44
49
  ws.on(event, (param: Amity.Events[typeof event]) => {
45
- console.log('ws', event, param);
46
50
  emitter.emit(event, param);
47
51
  });
48
52
  });
@@ -54,7 +58,6 @@ export const proxyMqttEvents = (
54
58
  ) => {
55
59
  MQTT_EVENTS.forEach(event => {
56
60
  mqttClient.on(event, (...params: any[]) => {
57
- console.log('mqtt', event, params);
58
61
  emitter.emit(event, params.length === 1 ? params[0] : params);
59
62
  });
60
63
  });
@@ -62,7 +65,6 @@ export const proxyMqttEvents = (
62
65
  // @ts-ignore
63
66
  mqttClient.on('message', (topic: string, payload: Buffer) => {
64
67
  const message = JSON.parse(payload.toString());
65
- console.log('mqtt message', message);
66
68
  emitter.emit(message.eventType, message.data);
67
69
  });
68
70
  };
@@ -15,6 +15,14 @@ export const sortByDisplayName: SortingFunc<{ displayName: string }> = (
15
15
  return a < b ? -1 : 1;
16
16
  };
17
17
 
18
+ /**
19
+ * Alphabetic sorting of objects having a name
20
+ */
21
+ export const sortByName: SortingFunc<{ name: string }> = ({ name: a }, { name: b }) => {
22
+ if (a === b) return 0;
23
+ return a < b ? -1 : 1;
24
+ };
25
+
18
26
  /**
19
27
  * Sorting a collection by their apparition order (oldest first)
20
28
  */
@@ -127,7 +127,9 @@ export function subscribeTopic(
127
127
  topic: string,
128
128
  callback?: Amity.Listener<ASCError | void>,
129
129
  ): Amity.Unsubscriber {
130
- const { mqtt, emitter, accessToken } = getActiveClient();
130
+ const { mqtt, emitter, token } = getActiveClient();
131
+ const accessToken = token?.accessToken ?? '';
132
+
131
133
  const user = getActiveUser();
132
134
 
133
135
  if (mqttAccessToken !== accessToken || mqttUserId !== user._id) {
@@ -1,16 +1,10 @@
1
1
  import axios from 'axios';
2
- import qs from 'qs';
3
2
  import HttpAgent, { HttpsAgent } from 'agentkeepalive';
4
3
 
5
- import { unwrapPayload } from './utils';
4
+ import { ASCError } from '~/core/errors';
6
5
 
7
- /**
8
- * Axios param serializer (for querystring)
9
- * @hidden
10
- */
11
- export const stringify = (params: Record<string, unknown>): string => {
12
- return qs.stringify(params, { arrayFormat: 'brackets' });
13
- };
6
+ import { fireEvent } from '../events';
7
+ import { unwrapPayload } from './utils';
14
8
 
15
9
  /**
16
10
  * Creates a pre-configured axios instance
@@ -33,17 +27,62 @@ export const createHttpTransport = (endpoint: string) => {
33
27
  baseURL: endpoint,
34
28
  httpAgent: new HttpAgent(options),
35
29
  httpsAgent: new HttpsAgent(options),
36
- paramsSerializer: stringify,
30
+ /*
31
+ * If paramSerializer is required, use the serialize option to stringify
32
+ * params. The encode option will pass complex params as string only whereas
33
+ * the serialize option will pass params in the format Record<string, any>
34
+ *
35
+ * For more details:
36
+ * https://github.com/axios/axios#request-config
37
+ */
38
+ });
39
+
40
+ instance.interceptors.request.use(config => {
41
+ // check global.ts for the extension of AxiosRequestConfig
42
+ const tokenExpiry = config.metadata?.tokenExpiry;
43
+
44
+ if (tokenExpiry) {
45
+ if (Date.now() >= Date.parse(tokenExpiry)) {
46
+ return {
47
+ ...config,
48
+ cancelToken: new axios.CancelToken(cancel => cancel('Token Expired')),
49
+ };
50
+ }
51
+ }
52
+
53
+ return config;
37
54
  });
38
55
 
39
56
  instance.interceptors.response.use(
40
57
  response => response,
41
58
  error => {
42
59
  const { response } = error;
43
- // eslint-disable-next-line no-console
44
- console.error(response?.data ?? error);
45
60
 
46
- if (response) unwrapPayload(response.data);
61
+ // handle unauthorized request
62
+ if (response.data.code === Amity.ServerError.UNAUTHORIZED) {
63
+ fireEvent('tokenTerminated', Amity.SessionStates.TERMINATED);
64
+ }
65
+
66
+ // handle request cancellation
67
+ if (axios.isCancel(error)) {
68
+ fireEvent('tokenExpired', Amity.SessionStates.TOKEN_EXPIRED);
69
+
70
+ throw new ASCError(
71
+ 'Token expired',
72
+ Amity.ClientError.TOKEN_EXPIRED,
73
+ Amity.ErrorLevel.FATAL,
74
+ );
75
+ }
76
+
77
+ // if it's an error with status in the response payload,
78
+ // then it's an expected error.
79
+ if (response?.data?.status) {
80
+ unwrapPayload(response?.data);
81
+ }
82
+ // unexpected error.
83
+ else {
84
+ throw new Error(response?.data ?? error);
85
+ }
47
86
  },
48
87
  );
49
88
 
@@ -21,7 +21,7 @@ export function getMqttOptions(params: {
21
21
  }): IClientOptions {
22
22
  return {
23
23
  clean: false, // keep subscriptions
24
- clientId: `mqttjs_ + ${Math.random().toString(16).substr(2, 8)}`,
24
+ clientId: `mqttjs_ + ${Math.random().toString(16).substring(2, 10)}`,
25
25
  protocolId: 'MQTT',
26
26
  protocolVersion: 4,
27
27
  reconnectPeriod: 0, // disable auto reconnect