@amityco/ts-sdk 0.0.1-beta.27 → 0.0.1-beta.29

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 (232) hide show
  1. package/.eslintrc.json +1 -0
  2. package/dist/@types/core/payload.d.ts +15 -13
  3. package/dist/@types/core/payload.d.ts.map +1 -1
  4. package/dist/@types/domains/channel.d.ts +17 -1
  5. package/dist/@types/domains/channel.d.ts.map +1 -1
  6. package/dist/@types/domains/client.d.ts +13 -0
  7. package/dist/@types/domains/client.d.ts.map +1 -1
  8. package/dist/@types/domains/community.d.ts +24 -2
  9. package/dist/@types/domains/community.d.ts.map +1 -1
  10. package/dist/@types/domains/content.d.ts +27 -3
  11. package/dist/@types/domains/content.d.ts.map +1 -1
  12. package/dist/@types/domains/file.d.ts +36 -3
  13. package/dist/@types/domains/file.d.ts.map +1 -1
  14. package/dist/@types/domains/follow.d.ts +11 -0
  15. package/dist/@types/domains/follow.d.ts.map +1 -1
  16. package/dist/@types/domains/group.d.ts +1 -0
  17. package/dist/@types/domains/group.d.ts.map +1 -1
  18. package/dist/@types/domains/message.d.ts +13 -0
  19. package/dist/@types/domains/message.d.ts.map +1 -1
  20. package/dist/@types/global.d.ts +1 -0
  21. package/dist/@types/global.d.ts.map +1 -1
  22. package/dist/@types/index.d.ts +3 -3
  23. package/dist/@types/index.d.ts.map +1 -1
  24. package/dist/channel/api/addChannelMembers.d.ts.map +1 -1
  25. package/dist/channel/api/addChannelMembersRole.d.ts.map +1 -1
  26. package/dist/channel/api/banChannelMembers.d.ts.map +1 -1
  27. package/dist/channel/api/createChannel.d.ts.map +1 -1
  28. package/dist/channel/api/getChannel.d.ts.map +1 -1
  29. package/dist/channel/api/getChannels.d.ts.map +1 -1
  30. package/dist/channel/api/joinChannel.d.ts.map +1 -1
  31. package/dist/channel/api/leaveChannel.d.ts.map +1 -1
  32. package/dist/channel/api/queryChannelMembers.d.ts.map +1 -1
  33. package/dist/channel/api/queryChannels.d.ts +1 -10
  34. package/dist/channel/api/queryChannels.d.ts.map +1 -1
  35. package/dist/channel/api/removeChannelMembers.d.ts.map +1 -1
  36. package/dist/channel/api/removeChannelMembersRole.d.ts.map +1 -1
  37. package/dist/channel/api/unbanChannelMembers.d.ts.map +1 -1
  38. package/dist/channel/api/updateChannel.d.ts.map +1 -1
  39. package/dist/channel/events/index.d.ts +1 -0
  40. package/dist/channel/events/index.d.ts.map +1 -1
  41. package/dist/channel/events/onChannelCreated.d.ts.map +1 -1
  42. package/dist/channel/events/onChannelDeleted.d.ts.map +1 -1
  43. package/dist/channel/events/onChannelJoined.d.ts.map +1 -1
  44. package/dist/channel/events/onChannelLeft.d.ts.map +1 -1
  45. package/dist/channel/events/onChannelMemberAdded.d.ts.map +1 -1
  46. package/dist/channel/events/onChannelMemberRemoved.d.ts.map +1 -1
  47. package/dist/channel/events/onChannelUpdated.d.ts.map +1 -1
  48. package/dist/channel/observers/index.d.ts +2 -0
  49. package/dist/channel/observers/index.d.ts.map +1 -1
  50. package/dist/channel/observers/liveChannels.d.ts +20 -0
  51. package/dist/channel/observers/liveChannels.d.ts.map +1 -0
  52. package/dist/channel/observers/observeChannel.d.ts +1 -1
  53. package/dist/channel/observers/observeChannel.d.ts.map +1 -1
  54. package/dist/channel/observers/observeChannels.d.ts +17 -0
  55. package/dist/channel/observers/observeChannels.d.ts.map +1 -0
  56. package/dist/channel/observers/tests/liveChannels.test.d.ts +2 -0
  57. package/dist/channel/observers/tests/liveChannels.test.d.ts.map +1 -0
  58. package/dist/channel/tests/utils/prepareChannelPayload.test.d.ts +2 -0
  59. package/dist/channel/tests/utils/prepareChannelPayload.test.d.ts.map +1 -0
  60. package/dist/channel/utils/index.d.ts +2 -0
  61. package/dist/channel/utils/index.d.ts.map +1 -0
  62. package/dist/channel/utils/prepareChannelPayload.d.ts +3 -0
  63. package/dist/channel/utils/prepareChannelPayload.d.ts.map +1 -0
  64. package/dist/client/api/connectClient.d.ts +1 -8
  65. package/dist/client/api/connectClient.d.ts.map +1 -1
  66. package/dist/client/api/createClient.d.ts +8 -1
  67. package/dist/client/api/createClient.d.ts.map +1 -1
  68. package/dist/client/api/getFeedSettings.d.ts +16 -0
  69. package/dist/client/api/getFeedSettings.d.ts.map +1 -0
  70. package/dist/client/api/index.d.ts +1 -0
  71. package/dist/client/api/index.d.ts.map +1 -1
  72. package/dist/community/api/createCommunity.d.ts +1 -1
  73. package/dist/community/api/createCommunity.d.ts.map +1 -1
  74. package/dist/community/api/getCommunities.d.ts.map +1 -1
  75. package/dist/community/api/getCommunity.d.ts.map +1 -1
  76. package/dist/community/api/getRecommendedCommunities.d.ts.map +1 -1
  77. package/dist/community/api/getTopTrendingCommunities.d.ts.map +1 -1
  78. package/dist/community/api/queryCommunities.d.ts.map +1 -1
  79. package/dist/community/api/updateCommunity.d.ts +1 -1
  80. package/dist/community/api/updateCommunity.d.ts.map +1 -1
  81. package/dist/community/events/utils.d.ts.map +1 -1
  82. package/dist/community/utils/index.d.ts +2 -0
  83. package/dist/community/utils/index.d.ts.map +1 -0
  84. package/dist/community/utils/payload.d.ts +11 -0
  85. package/dist/community/utils/payload.d.ts.map +1 -0
  86. package/dist/core/events.d.ts +3 -3
  87. package/dist/core/events.d.ts.map +1 -1
  88. package/dist/core/query/query.d.ts +1 -1
  89. package/dist/core/tests/query/query/runQuery.test.d.ts +2 -0
  90. package/dist/core/tests/query/query/runQuery.test.d.ts.map +1 -0
  91. package/dist/file/api/createVideo.d.ts +2 -1
  92. package/dist/file/api/createVideo.d.ts.map +1 -1
  93. package/dist/follow/api/queryFollowers.d.ts +1 -5
  94. package/dist/follow/api/queryFollowers.d.ts.map +1 -1
  95. package/dist/follow/api/queryFollowings.d.ts +1 -5
  96. package/dist/follow/api/queryFollowings.d.ts.map +1 -1
  97. package/dist/follow/observers/index.d.ts +2 -0
  98. package/dist/follow/observers/index.d.ts.map +1 -1
  99. package/dist/follow/observers/liveFollowers.d.ts +20 -0
  100. package/dist/follow/observers/liveFollowers.d.ts.map +1 -0
  101. package/dist/follow/observers/liveFollowings.d.ts +20 -0
  102. package/dist/follow/observers/liveFollowings.d.ts.map +1 -0
  103. package/dist/follow/tests/observers/liveFollowers.test.d.ts +2 -0
  104. package/dist/follow/tests/observers/liveFollowers.test.d.ts.map +1 -0
  105. package/dist/follow/tests/observers/liveFollowings.test.d.ts +2 -0
  106. package/dist/follow/tests/observers/liveFollowings.test.d.ts.map +1 -0
  107. package/dist/index.cjs.js +751 -128
  108. package/dist/index.d.ts +1 -1
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.esm.js +737 -129
  111. package/dist/index.umd.js +4 -4
  112. package/dist/message/api/queryMessages.d.ts +1 -10
  113. package/dist/message/api/queryMessages.d.ts.map +1 -1
  114. package/dist/message/observers/index.d.ts +1 -0
  115. package/dist/message/observers/index.d.ts.map +1 -1
  116. package/dist/message/observers/liveMessages.d.ts +20 -0
  117. package/dist/message/observers/liveMessages.d.ts.map +1 -0
  118. package/dist/message/observers/observeMessages.d.ts +0 -1
  119. package/dist/message/observers/observeMessages.d.ts.map +1 -1
  120. package/dist/message/observers/tests/liveMessages.test.d.ts +2 -0
  121. package/dist/message/observers/tests/liveMessages.test.d.ts.map +1 -0
  122. package/dist/post/observers/livePosts.d.ts.map +1 -1
  123. package/dist/utils/constants.d.ts +1 -0
  124. package/dist/utils/constants.d.ts.map +1 -1
  125. package/dist/utils/tests/client.d.ts +5 -2
  126. package/dist/utils/tests/client.d.ts.map +1 -1
  127. package/dist/utils/tests/dummy/channel.d.ts +33 -0
  128. package/dist/utils/tests/dummy/channel.d.ts.map +1 -0
  129. package/dist/utils/tests/dummy/follow.d.ts +12 -0
  130. package/dist/utils/tests/dummy/follow.d.ts.map +1 -0
  131. package/dist/utils/tests/dummy/index.d.ts +11 -0
  132. package/dist/utils/tests/dummy/index.d.ts.map +1 -0
  133. package/dist/utils/tests/dummy/message.d.ts +8 -0
  134. package/dist/utils/tests/dummy/message.d.ts.map +1 -0
  135. package/dist/utils/tests/{dummy.d.ts → dummy/post.d.ts} +3 -2
  136. package/dist/utils/tests/dummy/post.d.ts.map +1 -0
  137. package/dist/utils/tests/dummy/user.d.ts +5 -0
  138. package/dist/utils/tests/dummy/user.d.ts.map +1 -0
  139. package/dist/utils/tests/index.d.ts +3 -2
  140. package/dist/utils/tests/index.d.ts.map +1 -1
  141. package/dist/utils/tests/utils.d.ts +2 -0
  142. package/dist/utils/tests/utils.d.ts.map +1 -0
  143. package/package.json +1 -1
  144. package/src/@types/core/payload.ts +19 -13
  145. package/src/@types/domains/channel.ts +34 -1
  146. package/src/@types/domains/client.ts +17 -0
  147. package/src/@types/domains/community.ts +27 -2
  148. package/src/@types/domains/content.ts +35 -3
  149. package/src/@types/domains/file.ts +42 -3
  150. package/src/@types/domains/follow.ts +28 -0
  151. package/src/@types/domains/group.ts +1 -0
  152. package/src/@types/domains/message.ts +20 -0
  153. package/src/@types/global.ts +2 -0
  154. package/src/@types/index.ts +4 -3
  155. package/src/channel/api/addChannelMembers.ts +6 -5
  156. package/src/channel/api/addChannelMembersRole.ts +5 -1
  157. package/src/channel/api/banChannelMembers.ts +7 -3
  158. package/src/channel/api/createChannel.ts +6 -2
  159. package/src/channel/api/getChannel.ts +5 -1
  160. package/src/channel/api/getChannels.ts +5 -1
  161. package/src/channel/api/joinChannel.ts +5 -1
  162. package/src/channel/api/leaveChannel.ts +5 -1
  163. package/src/channel/api/queryChannelMembers.ts +16 -12
  164. package/src/channel/api/queryChannels.ts +12 -14
  165. package/src/channel/api/removeChannelMembers.ts +6 -5
  166. package/src/channel/api/removeChannelMembersRole.ts +5 -1
  167. package/src/channel/api/unbanChannelMembers.ts +7 -3
  168. package/src/channel/api/updateChannel.ts +5 -1
  169. package/src/channel/events/index.ts +1 -0
  170. package/src/channel/events/onChannelCreated.ts +6 -2
  171. package/src/channel/events/onChannelDeleted.ts +6 -2
  172. package/src/channel/events/onChannelJoined.ts +6 -2
  173. package/src/channel/events/onChannelLeft.ts +6 -2
  174. package/src/channel/events/onChannelMemberAdded.ts +6 -2
  175. package/src/channel/events/onChannelMemberRemoved.ts +6 -2
  176. package/src/channel/events/onChannelUpdated.ts +6 -2
  177. package/src/channel/observers/index.ts +2 -0
  178. package/src/channel/observers/liveChannels.ts +178 -0
  179. package/src/channel/observers/observeChannel.ts +1 -11
  180. package/src/channel/observers/observeChannels.ts +59 -0
  181. package/src/channel/observers/tests/liveChannels.test.ts +173 -0
  182. package/src/channel/tests/utils/prepareChannelPayload.test.ts +120 -0
  183. package/src/channel/utils/index.ts +1 -0
  184. package/src/channel/utils/prepareChannelPayload.ts +31 -0
  185. package/src/client/api/connectClient.ts +4 -9
  186. package/src/client/api/createClient.ts +19 -4
  187. package/src/client/api/getFeedSettings.ts +29 -0
  188. package/src/client/api/index.ts +2 -0
  189. package/src/community/api/createCommunity.ts +9 -3
  190. package/src/community/api/getCommunities.ts +10 -3
  191. package/src/community/api/getCommunity.ts +5 -1
  192. package/src/community/api/getRecommendedCommunities.ts +5 -2
  193. package/src/community/api/getTopTrendingCommunities.ts +4 -1
  194. package/src/community/api/queryCommunities.ts +5 -2
  195. package/src/community/api/updateCommunity.ts +7 -3
  196. package/src/community/events/utils.ts +13 -7
  197. package/src/community/utils/index.ts +1 -0
  198. package/src/community/utils/payload.ts +44 -0
  199. package/src/core/events.ts +2 -1
  200. package/src/core/model/identifyModel.ts +1 -1
  201. package/src/core/query/query.ts +3 -3
  202. package/src/core/tests/query/query/runQuery.test.ts +182 -0
  203. package/src/file/api/createVideo.ts +6 -0
  204. package/src/follow/api/queryFollowers.ts +3 -5
  205. package/src/follow/api/queryFollowings.ts +3 -5
  206. package/src/follow/api/utils.ts +7 -3
  207. package/src/follow/observers/index.ts +3 -0
  208. package/src/follow/observers/liveFollowers.ts +149 -0
  209. package/src/follow/observers/liveFollowings.ts +149 -0
  210. package/src/follow/tests/observers/liveFollowers.test.ts +240 -0
  211. package/src/follow/tests/observers/liveFollowings.test.ts +239 -0
  212. package/src/index.ts +1 -1
  213. package/src/message/api/queryMessages.ts +3 -10
  214. package/src/message/observers/index.ts +1 -0
  215. package/src/message/observers/liveMessages.ts +141 -0
  216. package/src/message/observers/observeMessages.ts +0 -1
  217. package/src/message/observers/tests/liveMessages.test.ts +313 -0
  218. package/src/post/observers/livePosts.ts +2 -1
  219. package/src/post/tests/api/getPost.test.ts +3 -3
  220. package/src/post/tests/api/queryPosts.test.ts +4 -4
  221. package/src/utils/constants.ts +1 -0
  222. package/src/utils/tests/client.ts +31 -3
  223. package/src/utils/tests/dummy/channel.ts +96 -0
  224. package/src/utils/tests/dummy/follow.ts +60 -0
  225. package/src/utils/tests/dummy/index.ts +8 -0
  226. package/src/utils/tests/dummy/message.ts +21 -0
  227. package/src/utils/tests/dummy/post.ts +31 -0
  228. package/src/utils/tests/dummy/user.ts +26 -0
  229. package/src/utils/tests/index.ts +3 -2
  230. package/src/utils/tests/utils.ts +3 -0
  231. package/dist/utils/tests/dummy.d.ts.map +0 -1
  232. package/src/utils/tests/dummy.ts +0 -7
@@ -0,0 +1,178 @@
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 { onChannelCreated, onChannelDeleted, onChannelUpdated } from '../events';
15
+ import { queryChannels } from '../api';
16
+
17
+ import {
18
+ COLLECTION_DEFAULT_CACHING_POLICY,
19
+ COLLECTION_DEFAULT_PAGINATION_LIMIT,
20
+ ENABLE_CACHE_MESSAGE,
21
+ } from '~/utils/constants';
22
+
23
+ /**
24
+ * ```js
25
+ * import { liveChannels } from '@amityco/ts-sdk'
26
+ *
27
+ * let channels = []
28
+ * const unsub = liveChannels({
29
+ * displayName: Amity.Channel['displayName'],
30
+ * }, response => merge(channels, response.data))
31
+ * ```
32
+ *
33
+ * Observe all mutations on a list of {@link Amity.Channel}s
34
+ *
35
+ * @param params for querying channels
36
+ * @param callback the function to call when new data are available
37
+ * @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the channels
38
+ *
39
+ * @category Channel Live Collection
40
+ */
41
+ export const liveChannels = (
42
+ params: Amity.ChannelLiveCollection,
43
+ callback: Amity.LiveCollectionCallback<Amity.Channel>,
44
+ config?: Amity.LiveCollectionConfig,
45
+ ) => {
46
+ const { log, cache } = getActiveClient();
47
+
48
+ if (!cache) {
49
+ console.log(ENABLE_CACHE_MESSAGE);
50
+ }
51
+
52
+ const timestamp = Date.now();
53
+ log(`liveChannels(tmpid: ${timestamp}) > listen`);
54
+
55
+ const { limit: queryLimit, ...queryParams } = params;
56
+
57
+ const limit = queryLimit ?? COLLECTION_DEFAULT_PAGINATION_LIMIT;
58
+ const { policy = COLLECTION_DEFAULT_CACHING_POLICY } = config ?? {};
59
+
60
+ const disposers: Amity.Unsubscriber[] = [];
61
+ const cacheKey = ['channel', 'collection', {}];
62
+
63
+ const responder = (data: Amity.ChannelLiveCollectionCache) => {
64
+ let channels: Amity.Channel[] =
65
+ data.data
66
+ .map(channelId => pullFromCache<Amity.Channel>(['channel', 'get', channelId])!)
67
+ .filter(Boolean)
68
+ .map(({ data }) => data) ?? [];
69
+
70
+ channels = filterByPropEquality(channels, 'isDeleted', params.isDeleted);
71
+ channels = filterByPropEquality(channels, 'displayName', params.displayName);
72
+
73
+ if (params.types) {
74
+ channels = channels.filter(c => params.types?.includes(c.type));
75
+ }
76
+
77
+ if (params.tags) {
78
+ channels = channels.filter(c => c.tags?.some(t => params.tags?.includes(t)));
79
+ }
80
+
81
+ if (params.excludeTags) {
82
+ channels = channels.filter(c => !c.tags?.some(t => params.excludeTags?.includes(t)));
83
+ }
84
+
85
+ const sortBy = params.sortBy || 'lastCreated';
86
+
87
+ if (sortBy === 'lastCreated' || sortBy === 'firstCreated') {
88
+ channels = channels.sort(sortBy === 'lastCreated' ? sortByLastCreated : sortByFirstCreated);
89
+ }
90
+
91
+ /*
92
+ * The server returns channels with empty | null displayName's first before
93
+ * returning sorted list of channels with displayNames
94
+ *
95
+ * This section needs to be updated as displayNames can be null as well
96
+ */
97
+ if (sortBy === 'displayName') {
98
+ channels = channels
99
+ // this needs to be aligned with the backend data type
100
+ .map(c => (c.displayName ? c : { ...c, displayName: '' }))
101
+ // @ts-ignore
102
+ .sort(sortByDisplayName);
103
+ }
104
+
105
+ callback({
106
+ onNextPage: onFetch,
107
+ data: channels,
108
+ hasNextPage: !!data.params?.page,
109
+ loading: data.loading,
110
+ error: data.error,
111
+ });
112
+ };
113
+
114
+ const realtimeRouter = (channel: Amity.Channel, action: Amity.ChannelActionType) => {
115
+ const collection = pullFromCache<Amity.ChannelLiveCollectionCache>(cacheKey)?.data;
116
+ if (!collection) return;
117
+
118
+ if (action === 'onCreate') {
119
+ collection.data = [...new Set([channel.channelId, ...collection.data])];
120
+ /*
121
+ * if the filter isDeleted is set, only collection item must be updated and not
122
+ * the collection
123
+ */
124
+ } else if (action === 'onDelete' && !params.isDeleted) {
125
+ collection.data = collection.data.filter(c => c !== channel.channelId);
126
+ }
127
+
128
+ pushToCache(cacheKey, collection);
129
+ responder(collection);
130
+ };
131
+
132
+ const onFetch = () => {
133
+ const collection = pullFromCache<Amity.ChannelLiveCollectionCache>(cacheKey)?.data;
134
+
135
+ const channels = collection?.data ?? [];
136
+
137
+ if (channels.length > 0 && !collection?.params.page) return;
138
+
139
+ const query = createQuery(queryChannels, {
140
+ ...queryParams,
141
+ page: collection?.params.page ?? { limit },
142
+ });
143
+
144
+ runQuery(
145
+ query,
146
+ ({ data: result, error, loading, nextPage: page }) => {
147
+ const data = {
148
+ loading,
149
+ error,
150
+ params: { page },
151
+ data: channels,
152
+ };
153
+
154
+ if (result) {
155
+ data.data = [...new Set([...channels, ...result.map(getResolver('channel'))])];
156
+ }
157
+
158
+ pushToCache(cacheKey, data);
159
+
160
+ responder(data);
161
+ },
162
+ queryOptions(policy),
163
+ );
164
+ };
165
+
166
+ disposers.push(
167
+ onChannelCreated(channel => realtimeRouter(channel, 'onCreate')),
168
+ onChannelDeleted(channel => realtimeRouter(channel, 'onDelete')),
169
+ onChannelUpdated(channel => realtimeRouter(channel, 'onUpdate')),
170
+ );
171
+
172
+ onFetch();
173
+
174
+ return () => {
175
+ log(`liveChannels(tmpid: ${timestamp}) > dispose`);
176
+ disposers.forEach(fn => fn());
177
+ };
178
+ };
@@ -29,17 +29,7 @@ import {
29
29
  *
30
30
  * @category Channel Observer
31
31
  */
32
- export const observeChannel = <
33
- Events extends [
34
- 'onFetch',
35
- 'onUpdate',
36
- 'onDelete',
37
- 'onJoin',
38
- 'onLeft',
39
- 'onMemberAdded',
40
- 'onMemberRemoved',
41
- ],
42
- >(
32
+ export const observeChannel = <Events extends [Exclude<Amity.ChannelActionType, 'onCreate'>]>(
43
33
  channelId: string,
44
34
  callback: Amity.ObjectListener<Amity.Snapshot<Amity.Channel>, Events>,
45
35
  ): Amity.Unsubscriber => {
@@ -0,0 +1,59 @@
1
+ import { getActiveClient } from '~/client/api';
2
+
3
+ import {
4
+ onChannelCreated,
5
+ onChannelUpdated,
6
+ onChannelDeleted,
7
+ onChannelJoined,
8
+ onChannelLeft,
9
+ onChannelMemberAdded,
10
+ onChannelMemberRemoved,
11
+ } from '../events';
12
+
13
+ /**
14
+ * ```js
15
+ * import { observeChannels } from '@amityco/ts-sdk'
16
+ *
17
+ * let channels = []
18
+ * const unsub = observeChannels(channel => merge(channels, channel))
19
+ * ```
20
+ *
21
+ * Observe all mutations on a list of {@link Amity.Channel} for a current user
22
+ *
23
+ * @param callback the function to call when new data are available
24
+ * @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the channels
25
+ *
26
+ * @category Channel Observer
27
+ */
28
+ export const observeChannels = (
29
+ callback: Amity.ObjectListener<Amity.Channel, [Exclude<Amity.ChannelActionType, 'onFetch'>]>,
30
+ ): Amity.Unsubscriber => {
31
+ const { log } = getActiveClient();
32
+
33
+ const timestamp = Date.now();
34
+ log(`observeChannels(tmpid: ${timestamp}) > listen`);
35
+
36
+ const disposers: Amity.Unsubscriber[] = [];
37
+
38
+ const router = (channel: Amity.Channel, action: Exclude<Amity.ChannelActionType, 'onFetch'>) => {
39
+ if (callback instanceof Function) return callback(channel);
40
+
41
+ callback.onEvent?.(action, channel);
42
+ callback[action]?.(channel);
43
+ };
44
+
45
+ disposers.push(
46
+ onChannelCreated(data => router(data, 'onCreate')),
47
+ onChannelUpdated(data => router(data, 'onUpdate')),
48
+ onChannelDeleted(data => router(data, 'onDelete')),
49
+ onChannelJoined(data => router(data, 'onJoin')),
50
+ onChannelLeft(data => router(data, 'onLeft')),
51
+ onChannelMemberAdded(data => router(data, 'onMemberAdded')),
52
+ onChannelMemberRemoved(data => router(data, 'onMemberRemoved')),
53
+ );
54
+
55
+ return () => {
56
+ log(`observeChannels(tmpid: ${timestamp}) > dispose`);
57
+ disposers.forEach(fn => fn());
58
+ };
59
+ };
@@ -0,0 +1,173 @@
1
+ import { disableCache, enableCache } from '~/cache/api';
2
+
3
+ import { liveChannels } from '../liveChannels';
4
+ import { queryChannels } from '~/channel/api';
5
+
6
+ import {
7
+ client,
8
+ connectClient,
9
+ disconnectClient,
10
+ channel11,
11
+ channel12,
12
+ channelUser1,
13
+ channelQueryResponse,
14
+ channelQueryResponsePage2,
15
+ } from '~/utils/tests';
16
+
17
+ const getSnapshot = () => {
18
+ return {
19
+ data: [] as Amity.Channel[],
20
+ loading: true,
21
+ error: undefined as any,
22
+ };
23
+ };
24
+
25
+ describe('liveChannels', () => {
26
+ beforeAll(async () => {
27
+ await connectClient();
28
+ });
29
+
30
+ afterAll(async () => {
31
+ await disconnectClient();
32
+ });
33
+
34
+ beforeEach(enableCache);
35
+
36
+ afterEach(disableCache);
37
+
38
+ test('it should return channel collection', async () => {
39
+ // mock response of queryChannels and validate
40
+ const callback = jest.fn();
41
+ client.http.get = jest.fn().mockResolvedValue(channelQueryResponse);
42
+
43
+ liveChannels({}, callback);
44
+
45
+ expect(callback).toHaveBeenCalledTimes(1);
46
+
47
+ const snapshot = getSnapshot();
48
+
49
+ // check if cache data returned (should be empty)
50
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
51
+
52
+ await expect(queryChannels()).resolves.toBeTruthy();
53
+
54
+ expect(callback).toHaveBeenCalledTimes(2);
55
+
56
+ snapshot.data = channelQueryResponse.data.channels;
57
+ snapshot.loading = false;
58
+
59
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
60
+ });
61
+
62
+ // table for channel filters
63
+ const filters: [string, Amity.ChannelLiveCollection][] = [
64
+ ['deleted', { isDeleted: false }],
65
+ ['tagged', { tags: ['tag2'] }],
66
+ ['out excluded tags', { excludeTags: ['tag1'] }],
67
+ ];
68
+
69
+ test.each(filters)('it should filter %s channels', async (filter, params) => {
70
+ const callback = jest.fn();
71
+ client.http.get = jest.fn().mockResolvedValue(channelQueryResponse);
72
+
73
+ liveChannels(params, callback);
74
+
75
+ expect(callback).toHaveBeenCalledTimes(1);
76
+
77
+ const snapshot = getSnapshot();
78
+ // check if cache data returned (should be empty)
79
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
80
+
81
+ await expect(queryChannels()).resolves.toBeTruthy();
82
+
83
+ expect(callback).toHaveBeenCalledTimes(2);
84
+
85
+ snapshot.loading = false;
86
+ snapshot.data = [channelQueryResponse.data.channels[0]];
87
+
88
+ expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
89
+ });
90
+
91
+ test('it should return method to fetch next page', async () => {
92
+ const callback = jest.fn();
93
+ client.http.get = jest
94
+ .fn()
95
+ .mockResolvedValue(channelQueryResponse)
96
+ .mockResolvedValueOnce(channelQueryResponsePage2);
97
+
98
+ liveChannels({}, callback);
99
+
100
+ expect(callback).toHaveBeenCalled();
101
+
102
+ await expect(queryChannels()).resolves.toBeTruthy();
103
+
104
+ expect(callback.mock.lastCall).toHaveLength(1);
105
+
106
+ const { onNextPage, hasNextPage } = callback.mock.lastCall[0];
107
+
108
+ expect(hasNextPage).toBe(true);
109
+ expect(onNextPage).toBeTruthy();
110
+
111
+ onNextPage();
112
+
113
+ await expect(queryChannels()).resolves.toBeTruthy();
114
+
115
+ // 4 -> becuase 1 local & server call each per call (2)
116
+ expect(callback).toHaveBeenCalledTimes(4);
117
+
118
+ const snapshot = getSnapshot();
119
+ snapshot.loading = false;
120
+ snapshot.data = [
121
+ ...channelQueryResponsePage2.data.channels,
122
+ ...channelQueryResponse.data.channels,
123
+ ];
124
+
125
+ expect(callback).toHaveBeenNthCalledWith(4, expect.objectContaining(snapshot));
126
+ });
127
+
128
+ const events: [string, keyof Amity.Events, Amity.Channel][] = [
129
+ [
130
+ 'it should add new channel to collection onCreate',
131
+ 'v3.channel.didCreate',
132
+ { ...channel11, channelId: 'new-channel-id' },
133
+ ],
134
+ ['it should edit channel in collection onUpdate', 'v3.channel.didUpdate', channel11],
135
+ ['it should remove channel from collection onDelete', 'v3.channel.didDelete', channel11],
136
+ ];
137
+
138
+ test.each(events)('%s', async (test, event, channel) => {
139
+ const snapshot = getSnapshot();
140
+
141
+ const callback = jest.fn();
142
+ client.http.get = jest.fn().mockResolvedValue(channelQueryResponse);
143
+
144
+ liveChannels({}, callback);
145
+
146
+ await expect(queryChannels()).resolves.toBeTruthy();
147
+ expect(callback).toHaveBeenCalledTimes(2);
148
+
149
+ client.emitter.emit(event, {
150
+ channels: [channel],
151
+ channelUsers: [channelUser1],
152
+ users: [],
153
+ files: [],
154
+ });
155
+
156
+ snapshot.loading = false;
157
+ // get data based on event
158
+ switch (event) {
159
+ case 'v3.channel.didCreate':
160
+ snapshot.data = [channel, channel11, channel12];
161
+ break;
162
+
163
+ case 'v3.channel.didUpdate':
164
+ snapshot.data = channelQueryResponse.data.channels;
165
+ break;
166
+
167
+ default:
168
+ snapshot.data = [channel12];
169
+ }
170
+
171
+ expect(callback).toHaveBeenNthCalledWith(3, expect.objectContaining(snapshot));
172
+ });
173
+ });
@@ -0,0 +1,120 @@
1
+ import {
2
+ connectClient,
3
+ disconnectClient,
4
+ channel11,
5
+ channel12,
6
+ channelRaw1,
7
+ channelRaw2,
8
+ channelUser1,
9
+ channelUser2,
10
+ } from '~/utils/tests';
11
+
12
+ import { prepareChannelPayload } from '../../utils';
13
+
14
+ beforeAll(async () => {
15
+ await connectClient();
16
+ });
17
+
18
+ afterAll(async () => {
19
+ await disconnectClient();
20
+ });
21
+
22
+ const responseSchema = {
23
+ channels: [],
24
+ channelUsers: [],
25
+ files: [],
26
+ users: [],
27
+ };
28
+
29
+ const tests = [
30
+ {
31
+ id: 1,
32
+ desc: 'hasMention: false, unreadCount: 0, if channelUsers is empty',
33
+ before: {
34
+ ...responseSchema,
35
+ channels: [channelRaw1],
36
+ },
37
+ after: {
38
+ ...responseSchema,
39
+ channels: [channel11],
40
+ },
41
+ },
42
+ {
43
+ id: 2,
44
+ desc: 'hasMention: false, if channelUser.readToSegment >= channelUser.lastMentionedSegment',
45
+ before: {
46
+ ...responseSchema,
47
+ channels: [channelRaw1],
48
+ channelUsers: [channelUser1],
49
+ },
50
+ after: {
51
+ ...responseSchema,
52
+ channels: [channel11],
53
+ channelUsers: [channelUser1],
54
+ },
55
+ },
56
+ {
57
+ id: 3,
58
+ desc: 'unreadCount: 0, if channelUser.readToSegment = channel.messageCount',
59
+ before: {
60
+ ...responseSchema,
61
+ channels: [channelRaw1],
62
+ channelUsers: [channelUser1],
63
+ },
64
+ after: {
65
+ ...responseSchema,
66
+ channels: [channel11],
67
+ channelUsers: [channelUser1],
68
+ },
69
+ },
70
+ {
71
+ id: 4,
72
+ desc: 'hasMention: true, if channelUser.readToSegment < channelUser.lastMentionedSegment',
73
+ before: {
74
+ ...responseSchema,
75
+ channels: [channelRaw2],
76
+ channelUsers: [channelUser2],
77
+ },
78
+ after: {
79
+ ...responseSchema,
80
+ channels: [channel12],
81
+ channelUsers: [channelUser2],
82
+ },
83
+ },
84
+ {
85
+ id: 5,
86
+ desc: 'unreadCount: > 0, if channelUser.readToSegment < channel.messageCount',
87
+ before: {
88
+ ...responseSchema,
89
+ channels: [channelRaw2],
90
+ channelUsers: [channelUser2],
91
+ },
92
+ after: {
93
+ ...responseSchema,
94
+ channels: [channel12],
95
+ channelUsers: [channelUser2],
96
+ },
97
+ },
98
+ {
99
+ id: 4,
100
+ desc: 'hasMention: true, unreadCount: > 0, if 4 / 5 ',
101
+ before: {
102
+ ...responseSchema,
103
+ channels: [channelRaw2],
104
+ channelUsers: [channelUser2],
105
+ },
106
+ after: {
107
+ ...responseSchema,
108
+ channels: [channel12],
109
+ channelUsers: [channelUser2],
110
+ },
111
+ },
112
+ ];
113
+
114
+ describe('channel/utils/prepareChannelPayload', () => {
115
+ tests.forEach(({ id, desc, before, after }) => {
116
+ test(`${id} - ${desc}`, () => {
117
+ expect(prepareChannelPayload(before)).toEqual(after);
118
+ });
119
+ });
120
+ });
@@ -0,0 +1 @@
1
+ export * from './prepareChannelPayload';
@@ -0,0 +1,31 @@
1
+ import { getActiveClient } from '~/client/api';
2
+
3
+ /** @hidden */
4
+ export const prepareChannelPayload = (
5
+ payload: Amity.ChannelPayload,
6
+ ): Amity.ChannelPayload<any, Amity.Channel> => {
7
+ const client = getActiveClient();
8
+
9
+ const channels: Amity.Channel[] = payload.channels.map(channel => {
10
+ const channelUser = payload.channelUsers.find(
11
+ channelUser =>
12
+ channelUser.userId === client.userId && channel.channelId === channelUser.channelId,
13
+ )!;
14
+
15
+ const hasMention = channelUser
16
+ ? channelUser.readToSegment < channelUser.lastMentionedSegment
17
+ : false;
18
+ const unreadCount =
19
+ channelUser && channelUser.membership === 'member' && channel.messageCount
20
+ ? Math.max(0, channel.messageCount - channelUser.readToSegment)
21
+ : 0;
22
+
23
+ return {
24
+ ...channel,
25
+ hasMention,
26
+ unreadCount,
27
+ };
28
+ });
29
+
30
+ return { ...payload, channels };
31
+ };
@@ -3,14 +3,14 @@
3
3
  import { disconnectClient } from '~/client/api/disconnectClient';
4
4
  import { getDeviceId } from '~/core/device';
5
5
  import { proxyWebsocketEvents } from '~/core/events';
6
+ import { getNetworkTopic, subscribeTopic } from '~/core/subscription';
7
+ import { onUserDeleted } from '~/user/events/onUserDeleted';
6
8
 
7
9
  import { getActiveClient } from './activeClient';
8
10
  import { setActiveUser } from './activeUser';
9
11
 
10
12
  import { getToken } from './getToken';
11
13
  import { onClientBanned } from '../events';
12
- import { getNetworkTopic, subscribeTopic } from '~/core/subscription';
13
- import { onUserDeleted } from '~/user/events/onUserDeleted';
14
14
 
15
15
  /**
16
16
  * ```js
@@ -33,13 +33,8 @@ import { onUserDeleted } from '~/user/events/onUserDeleted';
33
33
  * @async
34
34
  */
35
35
  export const connectClient = async (
36
- params: {
37
- userId: Amity.User['userId'];
38
- displayName?: Amity.User['displayName'];
39
- authToken?: string;
40
- deviceId?: Amity.Device['deviceId'];
41
- },
42
- config?: { disableRTE: boolean },
36
+ params: Amity.ConnectClientParams,
37
+ config?: Amity.ConnectClientConfig,
43
38
  ): Promise<boolean> => {
44
39
  const client = getActiveClient();
45
40
  client.log('client/api/connectClient', { apiKey: client.apiKey, ...params });
@@ -12,6 +12,9 @@ import {
12
12
  import { createEventEmitter } from '~/core/events';
13
13
 
14
14
  import { getActiveClient, setActiveClient } from './activeClient';
15
+ import { getFeedSettings } from './getFeedSettings';
16
+
17
+ const DEFAULT_DEBUG_SESSION = 'amity';
15
18
 
16
19
  /**
17
20
  * ```js
@@ -23,6 +26,7 @@ import { getActiveClient, setActiveClient } from './activeClient';
23
26
  *
24
27
  * @param apiKey for the {@link Amity.Client} instance
25
28
  * @param apiRegion endpoint to connect to
29
+ * @param apiEndpoint custom endpoint in case you don't want to use a preset endpoint
26
30
  * @param debugSession session's identifier for the client's logger instance
27
31
  * @returns A {@link Amity.Client} instance
28
32
  *
@@ -31,7 +35,13 @@ import { getActiveClient, setActiveClient } from './activeClient';
31
35
  export const createClient = (
32
36
  apiKey: string,
33
37
  apiRegion: typeof API_REGIONS[keyof typeof API_REGIONS] = API_REGIONS.SG,
34
- debugSession = 'amity',
38
+ {
39
+ debugSession = DEFAULT_DEBUG_SESSION,
40
+ apiEndpoint,
41
+ }: {
42
+ debugSession?: string;
43
+ apiEndpoint?: { http?: string; mqtt?: string };
44
+ } = {},
35
45
  ): Amity.Client => {
36
46
  const log = createLogger(debugSession);
37
47
 
@@ -40,9 +50,12 @@ export const createClient = (
40
50
  apiRegion,
41
51
  });
42
52
 
43
- const http = createHttpTransport(computeUrl('http', apiRegion));
44
- const ws = createWebsocketTransport(computeUrl('http', apiRegion));
45
- const mqtt = createMqttTransport(computeUrl('mqtt', apiRegion));
53
+ const httpEndpoint = apiEndpoint?.http ?? computeUrl('http', apiRegion);
54
+ const mqttEndpoint = apiEndpoint?.mqtt ?? computeUrl('mqtt', apiRegion);
55
+
56
+ const http = createHttpTransport(httpEndpoint);
57
+ const ws = createWebsocketTransport(httpEndpoint);
58
+ const mqtt = createMqttTransport(mqttEndpoint);
46
59
 
47
60
  const emitter = createEventEmitter();
48
61
 
@@ -56,6 +69,8 @@ export const createClient = (
56
69
  mqtt,
57
70
  emitter,
58
71
  use: () => setActiveClient(client),
72
+
73
+ getFeedSettings,
59
74
  };
60
75
 
61
76
  try {
@@ -0,0 +1,29 @@
1
+ import { getActiveClient } from './activeClient';
2
+
3
+ /**
4
+ * ```js
5
+ * import { getFeedSettings } from '@amityco/ts-sdk'
6
+ * const feedSettings = await getFeedSettings()
7
+ * const postFeedSetting = feedSettings.post
8
+ * ```
9
+ *
10
+ * Fetches a {@link Amity.FeedSettings} object
11
+ *
12
+ * @returns A Promise of {@link Amity.FeedSettings} object
13
+ *
14
+ * @category Client API
15
+ * @async
16
+ */
17
+ export const getFeedSettings = async (): Promise<Amity.FeedSettings> => {
18
+ const client = getActiveClient();
19
+
20
+ const { data } = await client.http.get<Amity.FeedSettingPayload>(
21
+ `/api/v3/network-settings/feed-setting`,
22
+ );
23
+
24
+ return Object.fromEntries(
25
+ data.feedSettings.map(({ feedType, contentSettings }) => {
26
+ return [feedType, contentSettings];
27
+ }),
28
+ );
29
+ };