@amityco/ts-sdk 0.0.1-beta.25 → 0.0.1-beta.28

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 (295) hide show
  1. package/.eslintrc.json +5 -1
  2. package/dist/@types/core/events.d.ts +7 -7
  3. package/dist/@types/core/events.d.ts.map +1 -1
  4. package/dist/@types/core/live.d.ts +23 -0
  5. package/dist/@types/core/live.d.ts.map +1 -0
  6. package/dist/@types/core/paging.d.ts +1 -1
  7. package/dist/@types/core/paging.d.ts.map +1 -1
  8. package/dist/@types/core/payload.d.ts +15 -15
  9. package/dist/@types/core/payload.d.ts.map +1 -1
  10. package/dist/@types/domains/channel.d.ts +5 -1
  11. package/dist/@types/domains/channel.d.ts.map +1 -1
  12. package/dist/@types/domains/client.d.ts +13 -0
  13. package/dist/@types/domains/client.d.ts.map +1 -1
  14. package/dist/@types/domains/comment.d.ts +14 -0
  15. package/dist/@types/domains/comment.d.ts.map +1 -1
  16. package/dist/@types/domains/content.d.ts +26 -3
  17. package/dist/@types/domains/content.d.ts.map +1 -1
  18. package/dist/@types/domains/file.d.ts +36 -3
  19. package/dist/@types/domains/file.d.ts.map +1 -1
  20. package/dist/@types/domains/follow.d.ts +13 -1
  21. package/dist/@types/domains/follow.d.ts.map +1 -1
  22. package/dist/@types/domains/group.d.ts +1 -0
  23. package/dist/@types/domains/group.d.ts.map +1 -1
  24. package/dist/@types/domains/message.d.ts +13 -0
  25. package/dist/@types/domains/message.d.ts.map +1 -1
  26. package/dist/@types/domains/post.d.ts +17 -0
  27. package/dist/@types/domains/post.d.ts.map +1 -1
  28. package/dist/@types/domains/reaction.d.ts +10 -0
  29. package/dist/@types/domains/reaction.d.ts.map +1 -1
  30. package/dist/@types/global.d.ts +1 -0
  31. package/dist/@types/global.d.ts.map +1 -1
  32. package/dist/@types/index.d.ts +3 -2
  33. package/dist/@types/index.d.ts.map +1 -1
  34. package/dist/cache/api/ingestInCache.d.ts +1 -1
  35. package/dist/cache/api/ingestInCache.d.ts.map +1 -1
  36. package/dist/cache/api/mergeInCache.d.ts +1 -1
  37. package/dist/cache/api/mergeInCache.d.ts.map +1 -1
  38. package/dist/category/api/queryCategories.d.ts +3 -3
  39. package/dist/category/api/queryCategories.d.ts.map +1 -1
  40. package/dist/channel/api/addChannelMembers.d.ts.map +1 -1
  41. package/dist/channel/api/addChannelMembersRole.d.ts.map +1 -1
  42. package/dist/channel/api/banChannelMembers.d.ts +16 -0
  43. package/dist/channel/api/banChannelMembers.d.ts.map +1 -0
  44. package/dist/channel/api/createChannel.d.ts.map +1 -1
  45. package/dist/channel/api/getChannel.d.ts.map +1 -1
  46. package/dist/channel/api/getChannels.d.ts.map +1 -1
  47. package/dist/channel/api/index.d.ts +2 -0
  48. package/dist/channel/api/index.d.ts.map +1 -1
  49. package/dist/channel/api/joinChannel.d.ts.map +1 -1
  50. package/dist/channel/api/leaveChannel.d.ts.map +1 -1
  51. package/dist/channel/api/queryChannelMembers.d.ts.map +1 -1
  52. package/dist/channel/api/queryChannels.d.ts +6 -6
  53. package/dist/channel/api/queryChannels.d.ts.map +1 -1
  54. package/dist/channel/api/removeChannelMembers.d.ts.map +1 -1
  55. package/dist/channel/api/removeChannelMembersRole.d.ts.map +1 -1
  56. package/dist/channel/api/unbanChannelMembers.d.ts +16 -0
  57. package/dist/channel/api/unbanChannelMembers.d.ts.map +1 -0
  58. package/dist/channel/api/updateChannel.d.ts.map +1 -1
  59. package/dist/channel/events/index.d.ts +1 -0
  60. package/dist/channel/events/index.d.ts.map +1 -1
  61. package/dist/channel/events/onChannelCreated.d.ts.map +1 -1
  62. package/dist/channel/events/onChannelDeleted.d.ts.map +1 -1
  63. package/dist/channel/events/onChannelJoined.d.ts.map +1 -1
  64. package/dist/channel/events/onChannelLeft.d.ts.map +1 -1
  65. package/dist/channel/events/onChannelMemberAdded.d.ts.map +1 -1
  66. package/dist/channel/events/onChannelMemberRemoved.d.ts.map +1 -1
  67. package/dist/channel/events/onChannelUpdated.d.ts.map +1 -1
  68. package/dist/channel/observers/index.d.ts +1 -0
  69. package/dist/channel/observers/index.d.ts.map +1 -1
  70. package/dist/channel/observers/observeChannel.d.ts +1 -1
  71. package/dist/channel/observers/observeChannel.d.ts.map +1 -1
  72. package/dist/channel/observers/observeChannels.d.ts +17 -0
  73. package/dist/channel/observers/observeChannels.d.ts.map +1 -0
  74. package/dist/channel/tests/utils/prepareChannelPayload.test.d.ts +2 -0
  75. package/dist/channel/tests/utils/prepareChannelPayload.test.d.ts.map +1 -0
  76. package/dist/channel/utils/index.d.ts +2 -0
  77. package/dist/channel/utils/index.d.ts.map +1 -0
  78. package/dist/channel/utils/prepareChannelPayload.d.ts +3 -0
  79. package/dist/channel/utils/prepareChannelPayload.d.ts.map +1 -0
  80. package/dist/client/api/connectClient.d.ts +1 -8
  81. package/dist/client/api/connectClient.d.ts.map +1 -1
  82. package/dist/client/api/createClient.d.ts +8 -1
  83. package/dist/client/api/createClient.d.ts.map +1 -1
  84. package/dist/client/api/getFeedSettings.d.ts +16 -0
  85. package/dist/client/api/getFeedSettings.d.ts.map +1 -0
  86. package/dist/client/api/index.d.ts +1 -0
  87. package/dist/client/api/index.d.ts.map +1 -1
  88. package/dist/comment/api/queryComments.d.ts +1 -9
  89. package/dist/comment/api/queryComments.d.ts.map +1 -1
  90. package/dist/comment/observers/index.d.ts +1 -0
  91. package/dist/comment/observers/index.d.ts.map +1 -1
  92. package/dist/comment/observers/liveComments.d.ts +22 -0
  93. package/dist/comment/observers/liveComments.d.ts.map +1 -0
  94. package/dist/comment/observers/observeComments.d.ts.map +1 -1
  95. package/dist/community/api/getRecommendedCommunities.d.ts +1 -1
  96. package/dist/community/api/getRecommendedCommunities.d.ts.map +1 -1
  97. package/dist/community/api/getTopTrendingCommunities.d.ts +1 -1
  98. package/dist/community/api/getTopTrendingCommunities.d.ts.map +1 -1
  99. package/dist/community/api/queryCommunities.d.ts +7 -7
  100. package/dist/community/api/queryCommunities.d.ts.map +1 -1
  101. package/dist/core/debug.d.ts +1 -1
  102. package/dist/core/debug.d.ts.map +1 -1
  103. package/dist/core/events.d.ts +3 -3
  104. package/dist/core/events.d.ts.map +1 -1
  105. package/dist/core/query/paging.d.ts +2 -2
  106. package/dist/core/query/paging.d.ts.map +1 -1
  107. package/dist/core/query/query.d.ts +2 -2
  108. package/dist/core/query/query.d.ts.map +1 -1
  109. package/dist/core/tests/query/filtering.test.d.ts +2 -0
  110. package/dist/core/tests/query/filtering.test.d.ts.map +1 -0
  111. package/dist/core/tests/query/query/runQuery.test.d.ts +2 -0
  112. package/dist/core/tests/query/query/runQuery.test.d.ts.map +1 -0
  113. package/dist/core/tests/query/query.test.d.ts +2 -0
  114. package/dist/core/tests/query/query.test.d.ts.map +1 -0
  115. package/dist/core/transports/ws.d.ts +1 -1
  116. package/dist/core/transports/ws.d.ts.map +1 -1
  117. package/dist/external/api/createUserToken.d.ts +1 -1
  118. package/dist/external/api/createUserToken.d.ts.map +1 -1
  119. package/dist/feed/api/queryGlobalFeed.d.ts +4 -4
  120. package/dist/feed/api/queryGlobalFeed.d.ts.map +1 -1
  121. package/dist/file/api/createVideo.d.ts +2 -1
  122. package/dist/file/api/createVideo.d.ts.map +1 -1
  123. package/dist/follow/api/follow.d.ts.map +1 -1
  124. package/dist/follow/api/getFollowInfo.d.ts.map +1 -1
  125. package/dist/follow/api/queryFollowers.d.ts +2 -6
  126. package/dist/follow/api/queryFollowers.d.ts.map +1 -1
  127. package/dist/follow/api/queryFollowings.d.ts +2 -6
  128. package/dist/follow/api/queryFollowings.d.ts.map +1 -1
  129. package/dist/follow/api/utils.d.ts +4 -4
  130. package/dist/follow/api/utils.d.ts.map +1 -1
  131. package/dist/follow/events/utils.d.ts.map +1 -1
  132. package/dist/follow/observers/index.d.ts +2 -0
  133. package/dist/follow/observers/index.d.ts.map +1 -1
  134. package/dist/follow/observers/liveFollowers.d.ts +20 -0
  135. package/dist/follow/observers/liveFollowers.d.ts.map +1 -0
  136. package/dist/follow/observers/liveFollowings.d.ts +20 -0
  137. package/dist/follow/observers/liveFollowings.d.ts.map +1 -0
  138. package/dist/index.cjs.js +18706 -17726
  139. package/dist/index.d.ts +2 -1
  140. package/dist/index.d.ts.map +1 -1
  141. package/dist/index.esm.js +18688 -17727
  142. package/dist/index.umd.js +4 -19
  143. package/dist/message/api/queryMessages.d.ts +1 -10
  144. package/dist/message/api/queryMessages.d.ts.map +1 -1
  145. package/dist/message/observers/index.d.ts +1 -0
  146. package/dist/message/observers/index.d.ts.map +1 -1
  147. package/dist/message/observers/liveMessages.d.ts +20 -0
  148. package/dist/message/observers/liveMessages.d.ts.map +1 -0
  149. package/dist/message/observers/observeMessages.d.ts +0 -1
  150. package/dist/message/observers/observeMessages.d.ts.map +1 -1
  151. package/dist/message/observers/tests/liveMessages.test.d.ts +2 -0
  152. package/dist/message/observers/tests/liveMessages.test.d.ts.map +1 -0
  153. package/dist/post/api/queryPosts.d.ts +1 -12
  154. package/dist/post/api/queryPosts.d.ts.map +1 -1
  155. package/dist/post/observers/index.d.ts +1 -0
  156. package/dist/post/observers/index.d.ts.map +1 -1
  157. package/dist/post/observers/livePosts.d.ts +22 -0
  158. package/dist/post/observers/livePosts.d.ts.map +1 -0
  159. package/dist/post/observers/observePosts.d.ts.map +1 -1
  160. package/dist/post/tests/api/getPost.test.d.ts +2 -0
  161. package/dist/post/tests/api/getPost.test.d.ts.map +1 -0
  162. package/dist/post/tests/api/queryPosts.test.d.ts +2 -0
  163. package/dist/post/tests/api/queryPosts.test.d.ts.map +1 -0
  164. package/dist/reaction/api/queryReactions.d.ts +1 -6
  165. package/dist/reaction/api/queryReactions.d.ts.map +1 -1
  166. package/dist/reaction/events/index.d.ts +3 -0
  167. package/dist/reaction/events/index.d.ts.map +1 -1
  168. package/dist/reaction/events/onReactorAdded.d.ts +19 -0
  169. package/dist/reaction/events/onReactorAdded.d.ts.map +1 -0
  170. package/dist/reaction/events/onReactorRemoved.d.ts +19 -0
  171. package/dist/reaction/events/onReactorRemoved.d.ts.map +1 -0
  172. package/dist/reaction/observers/index.d.ts +2 -0
  173. package/dist/reaction/observers/index.d.ts.map +1 -0
  174. package/dist/reaction/observers/liveReactions.d.ts +22 -0
  175. package/dist/reaction/observers/liveReactions.d.ts.map +1 -0
  176. package/dist/role/api/queryRoles.d.ts +4 -4
  177. package/dist/role/api/queryRoles.d.ts.map +1 -1
  178. package/dist/stream/api/queryStreams.d.ts +6 -6
  179. package/dist/stream/api/queryStreams.d.ts.map +1 -1
  180. package/dist/utils/constants.d.ts +4 -0
  181. package/dist/utils/constants.d.ts.map +1 -0
  182. package/dist/utils/tests/client.d.ts +6 -0
  183. package/dist/utils/tests/client.d.ts.map +1 -0
  184. package/dist/utils/tests/dummy/channel.d.ts +10 -0
  185. package/dist/utils/tests/dummy/channel.d.ts.map +1 -0
  186. package/dist/utils/tests/dummy/index.d.ts +10 -0
  187. package/dist/utils/tests/dummy/index.d.ts.map +1 -0
  188. package/dist/utils/tests/dummy/message.d.ts +8 -0
  189. package/dist/utils/tests/dummy/message.d.ts.map +1 -0
  190. package/dist/utils/tests/dummy/post.d.ts +9 -0
  191. package/dist/utils/tests/dummy/post.d.ts.map +1 -0
  192. package/dist/utils/tests/dummy/user.d.ts +2 -0
  193. package/dist/utils/tests/dummy/user.d.ts.map +1 -0
  194. package/dist/utils/tests/index.d.ts +3 -0
  195. package/dist/utils/tests/index.d.ts.map +1 -0
  196. package/jest.config.ts +15 -0
  197. package/package.json +21 -16
  198. package/src/@types/core/events.ts +7 -7
  199. package/src/@types/core/live.ts +28 -0
  200. package/src/@types/core/paging.ts +1 -1
  201. package/src/@types/core/payload.ts +21 -16
  202. package/src/@types/domains/channel.ts +16 -1
  203. package/src/@types/domains/client.ts +17 -0
  204. package/src/@types/domains/comment.ts +31 -0
  205. package/src/@types/domains/content.ts +34 -3
  206. package/src/@types/domains/file.ts +42 -3
  207. package/src/@types/domains/follow.ts +31 -1
  208. package/src/@types/domains/group.ts +1 -0
  209. package/src/@types/domains/message.ts +20 -0
  210. package/src/@types/domains/post.ts +37 -0
  211. package/src/@types/domains/reaction.ts +17 -0
  212. package/src/@types/global.ts +2 -0
  213. package/src/@types/index.ts +4 -2
  214. package/src/channel/api/addChannelMembers.ts +6 -5
  215. package/src/channel/api/addChannelMembersRole.ts +5 -1
  216. package/src/channel/api/banChannelMembers.ts +45 -0
  217. package/src/channel/api/createChannel.ts +6 -2
  218. package/src/channel/api/getChannel.ts +5 -1
  219. package/src/channel/api/getChannels.ts +5 -1
  220. package/src/channel/api/index.ts +3 -0
  221. package/src/channel/api/joinChannel.ts +5 -1
  222. package/src/channel/api/leaveChannel.ts +5 -1
  223. package/src/channel/api/queryChannelMembers.ts +16 -12
  224. package/src/channel/api/queryChannels.ts +9 -4
  225. package/src/channel/api/removeChannelMembers.ts +6 -5
  226. package/src/channel/api/removeChannelMembersRole.ts +5 -1
  227. package/src/channel/api/unbanChannelMembers.ts +45 -0
  228. package/src/channel/api/updateChannel.ts +5 -1
  229. package/src/channel/events/index.ts +1 -0
  230. package/src/channel/events/onChannelCreated.ts +6 -2
  231. package/src/channel/events/onChannelDeleted.ts +6 -2
  232. package/src/channel/events/onChannelJoined.ts +6 -2
  233. package/src/channel/events/onChannelLeft.ts +6 -2
  234. package/src/channel/events/onChannelMemberAdded.ts +6 -2
  235. package/src/channel/events/onChannelMemberRemoved.ts +6 -2
  236. package/src/channel/events/onChannelUpdated.ts +6 -2
  237. package/src/channel/observers/index.ts +1 -0
  238. package/src/channel/observers/observeChannel.ts +1 -11
  239. package/src/channel/observers/observeChannels.ts +59 -0
  240. package/src/channel/tests/utils/prepareChannelPayload.test.ts +120 -0
  241. package/src/channel/utils/index.ts +1 -0
  242. package/src/channel/utils/prepareChannelPayload.ts +31 -0
  243. package/src/client/api/connectClient.ts +4 -9
  244. package/src/client/api/createClient.ts +19 -4
  245. package/src/client/api/getFeedSettings.ts +29 -0
  246. package/src/client/api/index.ts +2 -0
  247. package/src/comment/api/queryComments.ts +3 -9
  248. package/src/comment/observers/index.ts +1 -0
  249. package/src/comment/observers/liveComments.ts +172 -0
  250. package/src/comment/observers/observeComments.ts +1 -11
  251. package/src/core/events.ts +2 -1
  252. package/src/core/query/query.ts +16 -3
  253. package/src/core/tests/query/filtering.test.ts +11 -0
  254. package/src/core/tests/query/query/runQuery.test.ts +182 -0
  255. package/src/core/tests/query/query.test.ts +19 -0
  256. package/src/file/api/createVideo.ts +6 -0
  257. package/src/follow/api/acceptFollower.ts +1 -1
  258. package/src/follow/api/declineFollower.ts +1 -1
  259. package/src/follow/api/follow.ts +1 -4
  260. package/src/follow/api/getFollowInfo.ts +8 -5
  261. package/src/follow/api/queryFollowers.ts +5 -6
  262. package/src/follow/api/queryFollowings.ts +5 -6
  263. package/src/follow/api/unfollow.ts +1 -1
  264. package/src/follow/api/utils.ts +17 -13
  265. package/src/follow/events/utils.ts +9 -6
  266. package/src/follow/observers/index.ts +3 -0
  267. package/src/follow/observers/liveFollowers.ts +149 -0
  268. package/src/follow/observers/liveFollowings.ts +149 -0
  269. package/src/index.ts +2 -1
  270. package/src/message/api/queryMessages.ts +3 -10
  271. package/src/message/observers/index.ts +1 -0
  272. package/src/message/observers/liveMessages.ts +141 -0
  273. package/src/message/observers/observeMessages.ts +0 -1
  274. package/src/message/observers/tests/liveMessages.test.ts +133 -0
  275. package/src/post/api/queryPosts.ts +3 -12
  276. package/src/post/observers/index.ts +1 -0
  277. package/src/post/observers/livePosts.ts +171 -0
  278. package/src/post/observers/observePosts.ts +1 -13
  279. package/src/post/tests/api/getPost.test.ts +88 -0
  280. package/src/post/tests/api/queryPosts.test.ts +23 -0
  281. package/src/reaction/api/queryReactions.ts +14 -14
  282. package/src/reaction/events/index.ts +4 -0
  283. package/src/reaction/events/onReactorAdded.ts +80 -0
  284. package/src/reaction/events/onReactorRemoved.ts +85 -0
  285. package/src/reaction/observers/index.ts +1 -0
  286. package/src/reaction/observers/liveReactions.ts +142 -0
  287. package/src/utils/constants.ts +3 -0
  288. package/src/utils/tests/client.ts +33 -0
  289. package/src/utils/tests/dummy/channel.ts +52 -0
  290. package/src/utils/tests/dummy/index.ts +7 -0
  291. package/src/utils/tests/dummy/message.ts +21 -0
  292. package/src/utils/tests/dummy/post.ts +31 -0
  293. package/src/utils/tests/dummy/user.ts +11 -0
  294. package/src/utils/tests/index.ts +2 -0
  295. package/tsconfig.json +23 -22
@@ -0,0 +1,141 @@
1
+ /* eslint-disable no-use-before-define */
2
+ import { getResolver } from '~/core/model';
3
+ import { getActiveClient } from '~/client/api';
4
+ import { pushToCache, pullFromCache } from '~/cache/api';
5
+ import { createQuery, runQuery, queryOptions, filterByPropEquality } from '~/core/query';
6
+
7
+ import {
8
+ COLLECTION_DEFAULT_CACHING_POLICY,
9
+ COLLECTION_DEFAULT_PAGINATION_LIMIT,
10
+ ENABLE_CACHE_MESSAGE,
11
+ } from '~/utils/constants';
12
+
13
+ import { onMessageCreated, onMessageDeleted, onMessageUpdated } from '../events';
14
+ import { queryMessages } from '../api';
15
+
16
+ /**
17
+ * ```js
18
+ * import { liveMessages } from '@amityco/ts-sdk'
19
+ *
20
+ * let messages = []
21
+ * const unsub = liveMessages({
22
+ * channelId: Amity.Channel['channelId'];
23
+ * }, response => merge(messages, response.data))
24
+ * ```
25
+ *
26
+ * Observe all mutations on a list of {@link Amity.Message} for a given target object
27
+ *
28
+ * @param params for querying memssages from a channel
29
+ * @param callback the function to call when new data are available
30
+ * @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the messages
31
+ *
32
+ * @category Messages Live Collection
33
+ */
34
+ export const liveMessages = (
35
+ params: Amity.MessagesLiveCollection,
36
+ callback: Amity.LiveCollectionCallback<Amity.Message>,
37
+ config?: Amity.LiveCollectionConfig,
38
+ ): Amity.Unsubscriber => {
39
+ const { log, cache } = getActiveClient();
40
+
41
+ if (!cache) {
42
+ console.log(ENABLE_CACHE_MESSAGE);
43
+ }
44
+
45
+ const timestamp = Date.now();
46
+ log(`liveMessages(tmpid: ${timestamp}) > listen`);
47
+
48
+ const { limit: queryLimit, ...queryParams } = params;
49
+
50
+ const limit = queryLimit ?? COLLECTION_DEFAULT_PAGINATION_LIMIT;
51
+ const { policy = COLLECTION_DEFAULT_CACHING_POLICY } = config ?? {};
52
+
53
+ const disposers: Amity.Unsubscriber[] = [];
54
+ const cacheKey = ['message', 'collection', { channelId: params.channelId }];
55
+
56
+ const responder = (data: Amity.MessageLiveCollectionCache) => {
57
+ let messages: Amity.Message[] =
58
+ data.data
59
+ .map(messageId => pullFromCache<Amity.Message>(['message', 'get', messageId])!)
60
+ .filter(Boolean)
61
+ .map(({ data }) => data) ?? [];
62
+
63
+ /*
64
+ * for cases when message is deleted via RTE, this flag is used to get
65
+ * items fro cache that are deleted | !deleted
66
+ */
67
+ messages = filterByPropEquality(messages, 'isDeleted', params.isDeleted);
68
+
69
+ callback({
70
+ onNextPage: onFetch,
71
+ data: messages,
72
+ hasNextPage: !!data.params?.page,
73
+ loading: data.loading,
74
+ error: data.error,
75
+ });
76
+ };
77
+
78
+ const realtimeRouter = (message: Amity.Message, action: Amity.MessageActionType) => {
79
+ const collection = pullFromCache<Amity.MessageLiveCollectionCache>(cacheKey)?.data;
80
+
81
+ if (params.channelId !== message.channelId || !collection) return;
82
+
83
+ if (action === 'onCreate') {
84
+ collection.data = [...new Set([message.messageId, ...collection.data])];
85
+ } else if (['onDelete'].includes(action)) {
86
+ collection.data = collection.data.filter(m => m !== message.messageId);
87
+ }
88
+
89
+ pushToCache(cacheKey, collection);
90
+
91
+ responder(collection);
92
+ };
93
+
94
+ const onFetch = () => {
95
+ const collection = pullFromCache<Amity.MessageLiveCollectionCache>(cacheKey)?.data;
96
+
97
+ const messages = collection?.data ?? [];
98
+
99
+ if (messages.length > 0 && !collection?.params?.page) return;
100
+
101
+ const query = createQuery(queryMessages, {
102
+ ...queryParams,
103
+ page: collection?.params?.page ?? { limit },
104
+ });
105
+
106
+ runQuery(
107
+ query,
108
+ ({ data: result, error, loading, prevPage: page }) => {
109
+ const data = {
110
+ loading,
111
+ error,
112
+ params: { page },
113
+ data: messages,
114
+ };
115
+
116
+ if (result) {
117
+ data.data = [...new Set([...messages, ...result.map(getResolver('message'))])];
118
+ }
119
+
120
+ pushToCache(cacheKey, data);
121
+
122
+ responder(data);
123
+ },
124
+ queryOptions(policy),
125
+ );
126
+ };
127
+
128
+ disposers.push(
129
+ onMessageCreated(message => realtimeRouter(message, 'onCreate')),
130
+ onMessageDeleted(message => realtimeRouter(message, 'onDelete')),
131
+
132
+ onMessageUpdated(message => realtimeRouter(message, 'onUpdate')),
133
+ );
134
+
135
+ onFetch();
136
+
137
+ return () => {
138
+ log(`liveMessages(tmpid: ${timestamp}) > dispose`);
139
+ disposers.forEach(fn => fn());
140
+ };
141
+ };
@@ -12,7 +12,6 @@ import { onMessageCreated, onMessageUpdated, onMessageDeleted } from '../events'
12
12
  *
13
13
  * Observe all mutations on a list of {@link Amity.Message} for a given {@link Amity.Channel} object
14
14
  *
15
- * @param client the client to observe the message with
16
15
  * @param channelId the ID of the channel where to observe the messages
17
16
  * @param callback the function to call when new data are available
18
17
  * @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the messages
@@ -0,0 +1,133 @@
1
+ import { disableCache, enableCache, pushToCache } from '~/cache/api';
2
+ import { ENABLE_CACHE_MESSAGE } from '~/utils/constants';
3
+
4
+ import { liveMessages } from '../liveMessages';
5
+
6
+ import { client, messages } from '~/utils/tests';
7
+ import { queryMessages } from '~/message/api';
8
+
9
+ describe('liveMessages', () => {
10
+ beforeEach(enableCache);
11
+ afterEach(disableCache);
12
+
13
+ test('it should show message if cache not enabled', () => {
14
+ /*
15
+ * NOTE: at the time of writing this test cache is diabled by default, but
16
+ * there is a proposal to enable cache by default. So I'm disabling cache
17
+ * here to ensure cache is disabled
18
+ */
19
+ disableCache();
20
+
21
+ const callback = jest.fn();
22
+ jest.spyOn(global.console, 'log');
23
+ client.http.get = jest.fn();
24
+
25
+ // call liveMessages check if mocked console get's called with the correct
26
+ // message
27
+ client.use();
28
+ liveMessages({ channelId: messages.channelId }, callback);
29
+
30
+ expect(console.log).toBeCalledWith(ENABLE_CACHE_MESSAGE);
31
+ });
32
+
33
+ test('it should return message collection', async () => {
34
+ const returnValue = [{ messageId: messages.page1[0] }];
35
+
36
+ // mock response of queryMessages and validate
37
+ const callback = jest.fn();
38
+ client.http.get = jest.fn().mockResolvedValue({
39
+ data: {
40
+ messages: returnValue,
41
+ paging: {},
42
+ },
43
+ });
44
+
45
+ liveMessages({ channelId: messages.channelId }, callback);
46
+
47
+ expect(callback).toHaveBeenCalledTimes(1);
48
+
49
+ // check if cache data returned (should be empty)
50
+ expect(callback).toHaveBeenCalledWith(
51
+ expect.objectContaining({
52
+ data: [],
53
+ error: undefined,
54
+ loading: true,
55
+ }),
56
+ );
57
+
58
+ await expect(queryMessages({ channelId: messages.channelId })).resolves.toBeTruthy();
59
+
60
+ expect(callback).toHaveBeenCalledTimes(2);
61
+
62
+ expect(callback).toHaveBeenCalledWith(
63
+ expect.objectContaining({
64
+ data: returnValue,
65
+ error: undefined,
66
+ loading: false,
67
+ }),
68
+ );
69
+ });
70
+
71
+ test('it should filter deleted messages based on param', async () => {
72
+ // mock response of queryMessages with a deleted message
73
+ const returnValue = [
74
+ { messageId: messages.page1[0], isDeleted: true },
75
+ { messageId: messages.page1[1], isDeleted: false },
76
+ ];
77
+
78
+ // mock response of queryMessages and validate
79
+ const callback = jest.fn();
80
+ client.http.get = jest.fn().mockResolvedValue({
81
+ data: {
82
+ messages: returnValue,
83
+ paging: {},
84
+ },
85
+ });
86
+
87
+ liveMessages({ channelId: messages.channelId, isDeleted: false }, callback);
88
+
89
+ expect(callback).toHaveBeenCalledTimes(1);
90
+
91
+ // check if cache data returned (should be empty)
92
+ expect(callback).toHaveBeenCalledWith(
93
+ expect.objectContaining({
94
+ data: [],
95
+ error: undefined,
96
+ loading: true,
97
+ }),
98
+ );
99
+
100
+ await expect(queryMessages({ channelId: messages.channelId })).resolves.toBeTruthy();
101
+
102
+ expect(callback).toHaveBeenCalledTimes(2);
103
+
104
+ expect(callback).toHaveBeenCalledWith(
105
+ expect.objectContaining({
106
+ data: [returnValue[1]],
107
+ error: undefined,
108
+ loading: false,
109
+ }),
110
+ );
111
+ });
112
+
113
+ test('it should return method to fetch next page', async () => {
114
+ // mock nextPage()
115
+ });
116
+
117
+ test('it should add new message to collection onCreate', () => {
118
+ // new message should be added to top of collection
119
+ });
120
+
121
+ test('it should update message in collection onUpdate', () => {
122
+ // updated message should be reflected in collection
123
+ });
124
+
125
+ test('it should delete message from collection onDelete', () => {
126
+ // should remove message from collection on delete
127
+ });
128
+
129
+ test('it should get messages from cache if present', () => {
130
+ // push message with Id in collection response to cache
131
+ // get request to get that messageId should not be called
132
+ });
133
+ });
@@ -20,18 +20,9 @@ import { getResolver } from '~/core/model';
20
20
  * @category Post API
21
21
  * @async
22
22
  */
23
- export const queryPosts = async (query: {
24
- targetId: string;
25
- targetType: Amity.Post['targetType'];
26
- sortBy?: 'lastCreated' | 'firstCreated' | 'lastUpdated' | 'firstUpdated';
27
- dataType?: string;
28
- isDeleted?: Amity.Post['isDeleted'];
29
- hasFlag?: boolean;
30
- feedType?: 'reviewing' | 'published';
31
- tags?: Amity.Taggable['tags'];
32
- matchingOnlyParentPost?: boolean;
33
- page?: Amity.PageRaw;
34
- }): Promise<Amity.Cached<Amity.Paged<Amity.Post, Amity.PageRaw>>> => {
23
+ export const queryPosts = async (
24
+ query: Amity.QueryPosts,
25
+ ): Promise<Amity.Cached<Amity.Paged<Amity.Post, Amity.PageRaw>>> => {
35
26
  const client = getActiveClient();
36
27
  client.log('post/queryPosts', query);
37
28
 
@@ -1,2 +1,3 @@
1
1
  export * from './observePosts';
2
2
  export * from './observePost';
3
+ export * from './livePosts';
@@ -0,0 +1,171 @@
1
+ /* eslint-disable no-use-before-define */
2
+ import { getResolver } from '~/core/model';
3
+ import { getActiveClient } from '~/client/api';
4
+ import { pushToCache, pullFromCache } from '~/cache/api';
5
+ import {
6
+ createQuery,
7
+ runQuery,
8
+ queryOptions,
9
+ filterByPropEquality,
10
+ sortByFirstCreated,
11
+ sortByLastCreated,
12
+ } from '~/core/query';
13
+
14
+ import {
15
+ COLLECTION_DEFAULT_CACHING_POLICY,
16
+ COLLECTION_DEFAULT_PAGINATION_LIMIT,
17
+ ENABLE_CACHE_MESSAGE,
18
+ } from '~/utils/constants';
19
+
20
+ import {
21
+ onPostCreated,
22
+ onPostUpdated,
23
+ onPostDeleted,
24
+ onPostApproved,
25
+ onPostDeclined,
26
+ onPostFlagged,
27
+ onPostUnflagged,
28
+ onPostReactionAdded,
29
+ onPostReactionRemoved,
30
+ } from '../events';
31
+ import { queryPosts } from '../api';
32
+
33
+ /**
34
+ * ```js
35
+ * import { livePosts } from '@amityco/ts-sdk'
36
+ *
37
+ * let posts = []
38
+ * const unsub = livePosts({
39
+ * targetType: Amity.PostTargetType,
40
+ * targetId: Amity.Post['targetId'],
41
+ * }, response => merge(posts, response.data))
42
+ * ```
43
+ *
44
+ * Observe all mutations on a list of {@link Amity.Post} for a given target object
45
+ *
46
+ * @param targetType the type of the target
47
+ * @param targetId the ID of the target
48
+ * @param callback the function to call when new data are available
49
+ * @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the messages
50
+ *
51
+ * @category Posts Live Collection
52
+ */
53
+ export const livePosts = (
54
+ params: Amity.PostLiveCollection,
55
+ callback: Amity.LiveCollectionCallback<Amity.Post>,
56
+ config?: Amity.LiveCollectionConfig,
57
+ ): Amity.Unsubscriber => {
58
+ const { log, cache } = getActiveClient();
59
+
60
+ if (!cache) {
61
+ console.log(ENABLE_CACHE_MESSAGE);
62
+ }
63
+
64
+ const timestamp = Date.now();
65
+ log(`livePosts(tmpid: ${timestamp}) > listen`);
66
+
67
+ const { limit: queryLimit, ...queryParams } = params;
68
+
69
+ const limit = queryLimit ?? COLLECTION_DEFAULT_PAGINATION_LIMIT;
70
+ const { policy = COLLECTION_DEFAULT_CACHING_POLICY } = config ?? {};
71
+
72
+ const disposers: Amity.Unsubscriber[] = [];
73
+ const cacheKey = [
74
+ 'post',
75
+ 'collection',
76
+ { targetId: params.targetId, targetType: params.targetType },
77
+ ];
78
+
79
+ const responder = (data: Amity.PostLiveCollectionCache) => {
80
+ let posts: Amity.Post[] =
81
+ data.data
82
+ .map(postId => pullFromCache<Amity.Post>(['post', 'get', postId])!)
83
+ .filter(Boolean)
84
+ .map(({ data }) => data) ?? [];
85
+
86
+ posts = filterByPropEquality(posts, 'isDeleted', params.isDeleted);
87
+
88
+ const sortBy = params.sortBy ? params.sortBy : 'lastCreated';
89
+
90
+ posts = posts.sort(sortBy === 'lastCreated' ? sortByLastCreated : sortByFirstCreated);
91
+
92
+ callback({
93
+ onNextPage: onFetch,
94
+ data: posts,
95
+ hasNextPage: !!data.params?.page,
96
+ loading: data.loading,
97
+ error: data.error,
98
+ });
99
+ };
100
+
101
+ const realtimeRouter = (post: Amity.Post, action: Amity.PostActionType) => {
102
+ const collection = pullFromCache<Amity.PostLiveCollectionCache>(cacheKey)?.data;
103
+
104
+ if (params.targetId !== post.targetId || params.targetType !== post.targetType || !collection)
105
+ return;
106
+
107
+ if (action === 'onCreate') {
108
+ collection.data = [...new Set([post.postId, ...collection.data])];
109
+ } else if (['onDelete', 'onDeclined'].includes(action)) {
110
+ collection.data = collection.data.filter(p => p !== post.postId);
111
+ }
112
+
113
+ pushToCache(cacheKey, collection);
114
+
115
+ responder(collection);
116
+ };
117
+
118
+ const onFetch = () => {
119
+ const collection = pullFromCache<Amity.PostLiveCollectionCache>(cacheKey)?.data;
120
+
121
+ const posts = collection?.data ?? [];
122
+
123
+ if (posts.length > 0 && !collection?.params?.page) return;
124
+
125
+ const query = createQuery(queryPosts, {
126
+ ...queryParams,
127
+ page: collection?.params?.page ?? { limit },
128
+ });
129
+
130
+ runQuery(
131
+ query,
132
+ ({ data: result, error, loading, nextPage: page }) => {
133
+ const data = {
134
+ loading,
135
+ error,
136
+ params: { page },
137
+ data: posts,
138
+ };
139
+
140
+ if (result) {
141
+ data.data = [...new Set([...posts, ...result.map(getResolver('post'))])];
142
+ }
143
+
144
+ pushToCache(cacheKey, data);
145
+
146
+ responder(data);
147
+ },
148
+ queryOptions(policy),
149
+ );
150
+ };
151
+
152
+ disposers.push(
153
+ onPostCreated(post => realtimeRouter(post, 'onCreate')),
154
+ onPostApproved(post => realtimeRouter(post, 'onApproved')),
155
+ onPostDeclined(post => realtimeRouter(post, 'onDeclined')),
156
+ onPostDeleted(post => realtimeRouter(post, 'onDelete')),
157
+
158
+ onPostUpdated(post => realtimeRouter(post, 'onUpdate')),
159
+ onPostFlagged(post => realtimeRouter(post, 'onFlagged')),
160
+ onPostUnflagged(post => realtimeRouter(post, 'onUnflagged')),
161
+ onPostReactionAdded(post => realtimeRouter(post, 'onReactionAdded')),
162
+ onPostReactionRemoved(post => realtimeRouter(post, 'onReactionRemoved')),
163
+ );
164
+
165
+ onFetch();
166
+
167
+ return () => {
168
+ log(`livePosts(tmpid: ${timestamp}) > dispose`);
169
+ disposers.forEach(fn => fn());
170
+ };
171
+ };
@@ -59,19 +59,7 @@ export const observePosts = (
59
59
 
60
60
  const disposers: Amity.Unsubscriber[] = [];
61
61
 
62
- const router = (
63
- post: Amity.Post,
64
- action:
65
- | 'onCreate'
66
- | 'onUpdate'
67
- | 'onDelete'
68
- | 'onApproved'
69
- | 'onDeclined'
70
- | 'onFlagged'
71
- | 'onUnflagged'
72
- | 'onReactionAdded'
73
- | 'onReactionRemoved',
74
- ) => {
62
+ const router = (post: Amity.Post, action: Exclude<Amity.PostActionType, 'onFetch'>) => {
75
63
  if (params.targetId !== post.targetId || params.targetType !== post.targetType) return;
76
64
 
77
65
  if (callback instanceof Function) return callback(post);
@@ -0,0 +1,88 @@
1
+ import { ASCApiError } from '~/core/errors';
2
+ import { client, posts } from '~/utils/tests';
3
+ import { pushToCache, enableCache, disableCache } from '~/cache/api';
4
+
5
+ import { getPost } from '~/post/api';
6
+
7
+ describe('post/api', () => {
8
+ const post = { postId: posts.page1[0] };
9
+ const post2 = { postId: posts.page1[1] };
10
+
11
+ describe('getPost.locally', () => {
12
+ test('should return undefined if cache is turned off', () => {
13
+ expect(getPost.locally(post.postId)).toBeUndefined();
14
+ });
15
+
16
+ test('should return undefined if post not in cache', () => {
17
+ enableCache();
18
+
19
+ const cachedAt = Date.now();
20
+
21
+ pushToCache(['post', 'get', post.postId], post, { cachedAt });
22
+
23
+ expect(getPost.locally(post2.postId)).toBeUndefined();
24
+
25
+ disableCache();
26
+ });
27
+
28
+ test('should return post if post in cache', () => {
29
+ enableCache();
30
+
31
+ const cachedAt = Date.now();
32
+
33
+ pushToCache(['post', 'get', post.postId], post, { cachedAt });
34
+
35
+ const data = getPost.locally(post.postId);
36
+
37
+ expect(data).toBeDefined();
38
+ expect(data?.data).toEqual(post);
39
+ expect(data?.cachedAt).toEqual(cachedAt);
40
+
41
+ disableCache();
42
+ });
43
+ });
44
+
45
+ describe('getPost', () => {
46
+ test('should return a post', async () => {
47
+ client.http.get = jest.fn().mockReturnValueOnce({ data: { posts: [post] } });
48
+
49
+ const data = await getPost(post.postId);
50
+
51
+ expect(data).toBeDefined();
52
+ expect(data?.data).toEqual(post);
53
+ });
54
+
55
+ test('should put post into the cache after fetch', async () => {
56
+ enableCache();
57
+ client.http.get = jest.fn().mockReturnValueOnce({ data: { posts: [post] } });
58
+
59
+ await getPost(post.postId);
60
+
61
+ expect(getPost.locally(post.postId)?.data).toEqual(post);
62
+
63
+ disableCache();
64
+ });
65
+
66
+ test('should return an error', async () => {
67
+ client.http.get = jest.fn().mockRejectedValueOnce(new Error('error'));
68
+
69
+ await expect(getPost(post.postId)).rejects.toThrow('error');
70
+ });
71
+
72
+ test('should return an error if post in cache but api throws not found', async () => {
73
+ enableCache();
74
+ pushToCache(['post', 'get', post.postId], post, { cachedAt: Date.now() });
75
+
76
+ client.http.get = jest
77
+ .fn()
78
+ .mockRejectedValueOnce(
79
+ new ASCApiError('not found!', Amity.ServerError.ITEM_NOT_FOUND, Amity.ErrorLevel.ERROR),
80
+ );
81
+
82
+ await expect(getPost(post.postId)).rejects.toThrow();
83
+
84
+ expect(getPost.locally(post.postId)).toBeUndefined();
85
+ disableCache();
86
+ });
87
+ });
88
+ });
@@ -0,0 +1,23 @@
1
+ import { queryPosts } from '~/post/api';
2
+ import { client, posts } from '~/utils/tests';
3
+
4
+ describe('post/api', () => {
5
+ test('should return a post query', async () => {
6
+ const returnValue = [{ postId: posts.page1[0] }];
7
+
8
+ client.http.get = jest.fn().mockResolvedValue({
9
+ data: {
10
+ posts: returnValue,
11
+ paging: {},
12
+ },
13
+ });
14
+
15
+ const data = await queryPosts({
16
+ targetId: posts.targetId,
17
+ targetType: posts.targetType,
18
+ });
19
+
20
+ expect(data).toBeDefined();
21
+ expect(data?.data).toEqual(returnValue);
22
+ });
23
+ });
@@ -1,6 +1,7 @@
1
1
  import { getActiveClient } from '~/client/api/activeClient';
2
2
 
3
- import { toToken, toPage } from '~/core/query';
3
+ import { toToken, toPageRaw } from '~/core/query';
4
+ import { ingestInCache } from '~/cache/api/ingestInCache';
4
5
 
5
6
  /**
6
7
  * ```js
@@ -19,34 +20,33 @@ import { toToken, toPage } from '~/core/query';
19
20
  * @reaction Reaction API
20
21
  * @async
21
22
  * */
22
- export const queryReactions = async (query: {
23
- referenceId: Amity.Reaction['referenceId'];
24
- referenceType: Amity.Reaction['referenceType'];
25
- reactionName?: Amity.Reaction['reactionName'];
26
- page?: Amity.Page;
27
- }): Promise<Amity.Paged<Amity.ReactionQuery, Amity.Page>> => {
23
+ export const queryReactions = async (
24
+ query: Amity.QueryReactions,
25
+ ): Promise<Amity.Paged<Amity.ReactionQuery, Amity.Page<string>>> => {
28
26
  const client = getActiveClient();
29
27
  client.log('reaction/queryReactions', query);
30
28
 
31
29
  const { page = { limit: 10 }, ...params } = query ?? {};
32
30
 
33
- const { data } = await client.http.get<{ results: Amity.ReactionPayload } & Amity.Pagination>(
34
- `/api/v2/reactions`,
31
+ const { data } = await client.http.get<Amity.ReactionPayload & Amity.Pagination>(
32
+ `/api/v3/reactions`,
35
33
  {
36
34
  params: {
37
35
  ...params,
38
36
  options: {
39
- token: toToken(page, 'skiplimit'),
37
+ token: toToken(page, 'afterbeforeraw'),
40
38
  },
41
39
  },
42
40
  },
43
41
  );
44
42
 
45
- const { paging, results } = data;
46
- const { reactions } = results;
43
+ const { paging, ...payload } = data;
44
+ const { reactions } = payload;
47
45
 
48
- const nextPage = toPage(paging.next);
49
- const prevPage = toPage(paging.previous);
46
+ ingestInCache({ ...payload, reactions: reactions[0].reactors });
47
+
48
+ const nextPage = toPageRaw(paging.next);
49
+ const prevPage = toPageRaw(paging.previous);
50
50
 
51
51
  return { data: reactions, prevPage, nextPage };
52
52
  };
@@ -1 +1,5 @@
1
+ export * from './onReactionAdded';
1
2
  export * from './onReactionRemoved';
3
+
4
+ export * from './onReactorAdded';
5
+ export * from './onReactorRemoved';