@amityco/ts-sdk 0.0.1-beta.30 → 0.0.1-beta.31

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 (181) hide show
  1. package/dist/@types/core/cache.d.ts +3 -0
  2. package/dist/@types/core/cache.d.ts.map +1 -1
  3. package/dist/@types/core/errors.d.ts +2 -1
  4. package/dist/@types/core/errors.d.ts.map +1 -1
  5. package/dist/@types/core/events.d.ts +2 -0
  6. package/dist/@types/core/events.d.ts.map +1 -1
  7. package/dist/@types/core/live.d.ts +8 -4
  8. package/dist/@types/core/live.d.ts.map +1 -1
  9. package/dist/@types/core/query.d.ts +1 -1
  10. package/dist/@types/core/query.d.ts.map +1 -1
  11. package/dist/@types/domains/channel.d.ts +1 -0
  12. package/dist/@types/domains/channel.d.ts.map +1 -1
  13. package/dist/@types/domains/message.d.ts +13 -6
  14. package/dist/@types/domains/message.d.ts.map +1 -1
  15. package/dist/@types/domains/post.d.ts +10 -3
  16. package/dist/@types/domains/post.d.ts.map +1 -1
  17. package/dist/@types/domains/user.d.ts +1 -0
  18. package/dist/@types/domains/user.d.ts.map +1 -1
  19. package/dist/@types/index.d.ts +2 -2
  20. package/dist/@types/index.d.ts.map +1 -1
  21. package/dist/cache/api/isInTombstone.d.ts +18 -0
  22. package/dist/cache/api/isInTombstone.d.ts.map +1 -0
  23. package/dist/cache/api/pushToTombstone.d.ts +17 -0
  24. package/dist/cache/api/pushToTombstone.d.ts.map +1 -0
  25. package/dist/cache/utils/index.d.ts +17 -0
  26. package/dist/cache/utils/index.d.ts.map +1 -1
  27. package/dist/channel/api/queryChannelMembers.d.ts +1 -1
  28. package/dist/channel/api/queryChannelMembers.d.ts.map +1 -1
  29. package/dist/channel/api/queryChannels.d.ts +1 -1
  30. package/dist/channel/api/queryChannels.d.ts.map +1 -1
  31. package/dist/channel/api/tests/queryChannelMembers.test.d.ts +2 -0
  32. package/dist/channel/api/tests/queryChannelMembers.test.d.ts.map +1 -0
  33. package/dist/channel/api/tests/queryChannels.test.d.ts +2 -0
  34. package/dist/channel/api/tests/queryChannels.test.d.ts.map +1 -0
  35. package/dist/channel/events/index.d.ts +2 -0
  36. package/dist/channel/events/index.d.ts.map +1 -1
  37. package/dist/channel/events/onChannelMemberBanned.d.ts +17 -0
  38. package/dist/channel/events/onChannelMemberBanned.d.ts.map +1 -0
  39. package/dist/channel/events/onChannelMemberUnbanned.d.ts +17 -0
  40. package/dist/channel/events/onChannelMemberUnbanned.d.ts.map +1 -0
  41. package/dist/channel/events/tests/onChannelMemberBanned.test.d.ts +2 -0
  42. package/dist/channel/events/tests/onChannelMemberBanned.test.d.ts.map +1 -0
  43. package/dist/channel/events/tests/onChannelMemberUnbanned.test.d.ts +2 -0
  44. package/dist/channel/events/tests/onChannelMemberUnbanned.test.d.ts.map +1 -0
  45. package/dist/channel/observers/liveChannelMembers.d.ts.map +1 -1
  46. package/dist/channel/observers/liveChannels.d.ts.map +1 -1
  47. package/dist/channel/{tests/utils → utils/tests}/prepareChannelPayload.test.d.ts +0 -0
  48. package/dist/channel/utils/tests/prepareChannelPayload.test.d.ts.map +1 -0
  49. package/dist/core/events.d.ts +3 -3
  50. package/dist/core/events.d.ts.map +1 -1
  51. package/dist/core/query/filtering.d.ts +11 -0
  52. package/dist/core/query/filtering.d.ts.map +1 -1
  53. package/dist/core/query/query.d.ts.map +1 -1
  54. package/dist/index.cjs.js +963 -507
  55. package/dist/index.esm.js +946 -499
  56. package/dist/index.umd.js +4 -4
  57. package/dist/message/api/createMessage.d.ts +4 -1
  58. package/dist/message/api/createMessage.d.ts.map +1 -1
  59. package/dist/message/api/deleteMessage.d.ts.map +1 -1
  60. package/dist/message/api/getMessage.d.ts +1 -1
  61. package/dist/message/api/getMessage.d.ts.map +1 -1
  62. package/dist/message/api/getMessages.d.ts.map +1 -1
  63. package/dist/message/api/queryMessages.d.ts.map +1 -1
  64. package/dist/message/api/tests/createMessage.test.d.ts +2 -0
  65. package/dist/message/api/tests/createMessage.test.d.ts.map +1 -0
  66. package/dist/message/api/updateMessage.d.ts.map +1 -1
  67. package/dist/message/events/index.d.ts +1 -0
  68. package/dist/message/events/index.d.ts.map +1 -1
  69. package/dist/message/events/onMessageFetched.d.ts +17 -0
  70. package/dist/message/events/onMessageFetched.d.ts.map +1 -0
  71. package/dist/message/observers/index.d.ts +2 -1
  72. package/dist/message/observers/index.d.ts.map +1 -1
  73. package/dist/message/observers/liveMessage.d.ts +18 -0
  74. package/dist/message/observers/liveMessage.d.ts.map +1 -0
  75. package/dist/message/observers/liveMessages.d.ts.map +1 -1
  76. package/dist/message/observers/observeMessage.d.ts.map +1 -1
  77. package/dist/message/tests/api/getMessage.test.d.ts +2 -0
  78. package/dist/message/tests/api/getMessage.test.d.ts.map +1 -0
  79. package/dist/message/tests/observers/liveMessage.test.d.ts +2 -0
  80. package/dist/message/tests/observers/liveMessage.test.d.ts.map +1 -0
  81. package/dist/message/{observers/tests → tests/observers}/liveMessages.test.d.ts +0 -0
  82. package/dist/message/tests/observers/liveMessages.test.d.ts.map +1 -0
  83. package/dist/post/api/deletePost.d.ts.map +1 -1
  84. package/dist/post/api/getPost.d.ts.map +1 -1
  85. package/dist/post/api/updatePost.d.ts +6 -1
  86. package/dist/post/api/updatePost.d.ts.map +1 -1
  87. package/dist/user/api/getUser.d.ts +1 -1
  88. package/dist/user/api/getUser.d.ts.map +1 -1
  89. package/dist/user/api/getUsers.d.ts.map +1 -1
  90. package/dist/user/api/queryUsers.d.ts.map +1 -1
  91. package/dist/user/api/updateUser.d.ts.map +1 -1
  92. package/dist/user/events/index.d.ts +1 -0
  93. package/dist/user/events/index.d.ts.map +1 -1
  94. package/dist/user/events/onUserFetched.d.ts +17 -0
  95. package/dist/user/events/onUserFetched.d.ts.map +1 -0
  96. package/dist/user/observers/index.d.ts +1 -0
  97. package/dist/user/observers/index.d.ts.map +1 -1
  98. package/dist/user/observers/liveUser.d.ts +18 -0
  99. package/dist/user/observers/liveUser.d.ts.map +1 -0
  100. package/dist/user/observers/observeUser.d.ts.map +1 -1
  101. package/dist/user/tests/api/getUser.test.d.ts +2 -0
  102. package/dist/user/tests/api/getUser.test.d.ts.map +1 -0
  103. package/dist/user/tests/observers/liveUser.test.d.ts +2 -0
  104. package/dist/user/tests/observers/liveUser.test.d.ts.map +1 -0
  105. package/dist/utils/constants.d.ts +3 -0
  106. package/dist/utils/constants.d.ts.map +1 -1
  107. package/dist/utils/tests/dummy/channel.d.ts +15 -0
  108. package/dist/utils/tests/dummy/channel.d.ts.map +1 -1
  109. package/dist/utils/tests/dummy/message.d.ts +12 -1
  110. package/dist/utils/tests/dummy/message.d.ts.map +1 -1
  111. package/dist/utils/tests/dummy/user.d.ts +10 -0
  112. package/dist/utils/tests/dummy/user.d.ts.map +1 -1
  113. package/package.json +1 -1
  114. package/src/@types/core/cache.ts +4 -0
  115. package/src/@types/core/errors.ts +1 -0
  116. package/src/@types/core/events.ts +2 -0
  117. package/src/@types/core/live.ts +10 -4
  118. package/src/@types/core/query.ts +1 -1
  119. package/src/@types/domains/channel.ts +6 -0
  120. package/src/@types/domains/message.ts +13 -10
  121. package/src/@types/domains/post.ts +10 -3
  122. package/src/@types/domains/user.ts +8 -0
  123. package/src/@types/index.ts +2 -2
  124. package/src/cache/api/index.ts +2 -1
  125. package/src/cache/api/isInTombstone.ts +41 -0
  126. package/src/cache/api/pushToTombstone.ts +33 -0
  127. package/src/cache/utils/index.ts +22 -0
  128. package/src/channel/api/queryChannelMembers.ts +53 -5
  129. package/src/channel/api/queryChannels.ts +31 -4
  130. package/src/channel/api/tests/queryChannelMembers.test.ts +115 -0
  131. package/src/channel/api/tests/queryChannels.test.ts +101 -0
  132. package/src/channel/events/index.ts +5 -0
  133. package/src/channel/events/onChannelMemberBanned.ts +36 -0
  134. package/src/channel/events/onChannelMemberUnbanned.ts +36 -0
  135. package/src/channel/events/tests/onChannelMemberBanned.test.ts +58 -0
  136. package/src/channel/events/tests/onChannelMemberUnbanned.test.ts +58 -0
  137. package/src/channel/observers/liveChannelMembers.ts +28 -4
  138. package/src/channel/observers/liveChannels.ts +7 -1
  139. package/src/channel/observers/tests/liveChannelMembers.test.ts +53 -11
  140. package/src/channel/observers/tests/liveChannels.test.ts +50 -20
  141. package/src/channel/{tests/utils → utils/tests}/prepareChannelPayload.test.ts +1 -1
  142. package/src/core/events.ts +1 -0
  143. package/src/core/query/filtering.ts +49 -0
  144. package/src/core/query/query.ts +9 -6
  145. package/src/core/tests/query/query.test.ts +12 -2
  146. package/src/message/api/createMessage.ts +15 -9
  147. package/src/message/api/deleteMessage.ts +2 -1
  148. package/src/message/api/getMessage.ts +32 -4
  149. package/src/message/api/getMessages.ts +6 -1
  150. package/src/message/api/queryMessages.ts +3 -0
  151. package/src/message/api/tests/createMessage.test.ts +76 -0
  152. package/src/message/api/updateMessage.ts +2 -0
  153. package/src/message/events/index.ts +1 -0
  154. package/src/message/events/onMessageFetched.ts +30 -0
  155. package/src/message/observers/index.ts +2 -1
  156. package/src/message/observers/liveMessage.ts +100 -0
  157. package/src/message/observers/liveMessages.ts +3 -1
  158. package/src/message/observers/observeMessage.ts +4 -0
  159. package/src/message/tests/api/getMessage.test.ts +96 -0
  160. package/src/message/tests/observers/liveMessage.test.ts +248 -0
  161. package/src/message/{observers/tests → tests/observers}/liveMessages.test.ts +29 -3
  162. package/src/post/api/deletePost.ts +4 -3
  163. package/src/post/api/getPost.ts +8 -4
  164. package/src/post/api/updatePost.ts +6 -1
  165. package/src/user/api/getUser.ts +34 -6
  166. package/src/user/api/getUsers.ts +3 -0
  167. package/src/user/api/queryUsers.ts +3 -0
  168. package/src/user/api/updateUser.ts +3 -0
  169. package/src/user/events/index.ts +1 -0
  170. package/src/user/events/onUserFetched.ts +19 -0
  171. package/src/user/observers/index.ts +1 -0
  172. package/src/user/observers/liveUser.ts +89 -0
  173. package/src/user/observers/observeUser.ts +2 -0
  174. package/src/user/tests/api/getUser.test.ts +112 -0
  175. package/src/user/tests/observers/liveUser.test.ts +224 -0
  176. package/src/utils/constants.ts +5 -0
  177. package/src/utils/tests/dummy/channel.ts +43 -0
  178. package/src/utils/tests/dummy/message.ts +16 -2
  179. package/src/utils/tests/dummy/user.ts +11 -0
  180. package/dist/channel/tests/utils/prepareChannelPayload.test.d.ts.map +0 -1
  181. package/dist/message/observers/tests/liveMessages.test.d.ts.map +0 -1
@@ -21,10 +21,8 @@ import './domains/reaction';
21
21
 
22
22
  import './domains/group';
23
23
  import './domains/channel';
24
- import './domains/message';
25
24
 
26
25
  import './domains/category';
27
- import './domains/post';
28
26
  import './domains/comment';
29
27
 
30
28
  import './domains/stream';
@@ -36,3 +34,5 @@ import './domains/poll';
36
34
  export * from './domains/community';
37
35
  export * from './domains/content';
38
36
  export * from './domains/file';
37
+ export * from './domains/message';
38
+ export * from './domains/post';
@@ -18,6 +18,7 @@ export * from './upsertInCache';
18
18
  export * from './dropFromCache';
19
19
 
20
20
  /*
21
- * ingestInCache and syncInCache are not exported ;
21
+ * ingestInCache and syncInCache and isInTombstone
22
+ * and pushToTombstone are not exported ;
22
23
  * we don't want it as part of the sdk's public api.
23
24
  */
@@ -0,0 +1,41 @@
1
+ import { getActiveClient } from '~/client/api/activeClient';
2
+
3
+ import { ASCApiError } from '~/core/errors';
4
+ import { pullFromCache } from '~/cache/api';
5
+ import { isFresh, queryOptions } from '~/core/query';
6
+ import { CACHE_KEY_TOMBSTONE, CACHE_LIFESPAN_TOMBSTONE } from '~/cache/utils';
7
+
8
+ /**
9
+ * ```js
10
+ * import { isInTombstone } from '@amityco/ts-sdk'
11
+ * const user = isInTombstone(["message", "messageId"])
12
+ * ```
13
+ *
14
+ * Checks if the {@link Amity.TombstoneCacheOptions} exists
15
+ * in cache and it's not expired means it's in tombstone
16
+ * and we throw an Error
17
+ *
18
+ * @param model the model to check
19
+ * @param modelId the object id to check
20
+ * @returns the matching cache entry, or undefined.
21
+ *
22
+ * @category Cache API
23
+ */
24
+ export const isInTombstone = (model: Amity.Domain, modelId: string) => {
25
+ const { log, cache } = getActiveClient();
26
+ const key = [model, CACHE_KEY_TOMBSTONE, modelId];
27
+
28
+ if (!cache) return;
29
+ log('cache/api/isInTombstone', key);
30
+
31
+ const isInTombstone = pullFromCache<Amity.TombstoneCacheOptions>(key);
32
+ const { lifeSpan } = queryOptions('cache_then_server', CACHE_LIFESPAN_TOMBSTONE);
33
+
34
+ if (isInTombstone && isFresh(isInTombstone.data, lifeSpan)) {
35
+ throw new ASCApiError(
36
+ 'Item not found!',
37
+ Amity.ServerError.ITEM_NOT_FOUND,
38
+ Amity.ErrorLevel.ERROR,
39
+ );
40
+ }
41
+ };
@@ -0,0 +1,33 @@
1
+ import { getActiveClient } from '~/client/api/activeClient';
2
+
3
+ import { dropFromCache, pushToCache } from '~/cache/api';
4
+
5
+ import { CACHE_KEY_GET, CACHE_KEY_TOMBSTONE } from '~/cache/utils';
6
+
7
+ /**
8
+ * ```js
9
+ * import { pushToTombstone } from '@amityco/ts-sdk'
10
+ * pushToTombstone(["message", "messageId"], { cachedAt: Date.now() })
11
+ * ```
12
+ *
13
+ * Removes an existing {@link Amity.CacheEntry} from the {@link Amity.Client}'s
14
+ * {@link Amity.Cache} from a given {@link Amity.CacheKey}
15
+ *
16
+ * @param model the model to remove and push to Tombstone
17
+ * @param modelId the related model id
18
+ *
19
+ * @category Cache API
20
+ * @hidden
21
+ */
22
+ export const pushToTombstone = (model: Amity.Domain, modelId: string) => {
23
+ const { log, cache } = getActiveClient();
24
+
25
+ const cacheKey = [model, CACHE_KEY_TOMBSTONE, modelId];
26
+ const data: Pick<Amity.CacheOptions, 'cachedAt'> = { cachedAt: Date.now() };
27
+
28
+ if (!cache) return;
29
+ log('cache/api/pushToTombstone', { cacheKey, data });
30
+
31
+ dropFromCache([model, CACHE_KEY_GET, modelId], true);
32
+ pushToCache(cacheKey, data);
33
+ };
@@ -1,3 +1,12 @@
1
+ // cache constants
2
+ export const CACHE_KEY_GET = 'get';
3
+ export const CACHE_KEY_QUERY = 'query';
4
+ export const CACHE_KEY_TOMBSTONE = 'dead';
5
+ export const CACHE_KEY_COLLECTION = 'collection';
6
+
7
+ export const CACHE_LIFESPAN = 1 * 60 * 1000; // 1 minute
8
+ export const CACHE_LIFESPAN_TOMBSTONE = 3 * 60 * 1000; // 3 minutes
9
+
1
10
  /**
2
11
  * Shallow-clones an object and sort its keys
3
12
  *
@@ -72,3 +81,16 @@ export const partialMatch = (predicate: any, candidate: any): boolean => {
72
81
  */
73
82
  export const isCached = <T extends unknown>(obj?: any): obj is Amity.Cached<T> =>
74
83
  ['data', 'cachedAt'].every(prop => obj?.hasOwnProperty(prop));
84
+
85
+ /**
86
+ * checks if passed error code is included in
87
+ * Tombstone errors list
88
+ *
89
+ * @param errorCode as {@link Amity.ServerError}
90
+ * @returns success boolean if the given errorCode
91
+ * is included in Tombstone errors list
92
+ *
93
+ * @category Cache
94
+ */
95
+ export const checkIfShouldGoesToTombstone = (errorCode: Amity.ServerError): boolean =>
96
+ [Amity.ServerError.ITEM_NOT_FOUND, Amity.ServerError.FORBIDDEN].includes(errorCode);
@@ -1,6 +1,9 @@
1
1
  import { getActiveClient } from '~/client/api';
2
2
 
3
3
  import { toPage, toToken } from '~/core/query';
4
+ import { getResolver } from '~/core/model';
5
+
6
+ import { pullFromCache, pushToCache } from '~/cache/api';
4
7
  import { ingestInCache } from '~/cache/api/ingestInCache';
5
8
 
6
9
  import { prepareChannelPayload } from '../utils';
@@ -25,11 +28,11 @@ export const queryChannelMembers = async (
25
28
  const client = getActiveClient();
26
29
  client.log('channel/queryChannelMembers', query);
27
30
 
28
- const { page, channelId, ...params } = query ?? {};
31
+ const { page = { limit: 10 }, ...params } = query ?? {};
29
32
 
30
33
  const { data: queryPayload } = await client.http.get<
31
34
  Amity.ChannelMembershipPayload & Amity.Pagination
32
- >(`/api/v4/channels/${encodeURIComponent(channelId)}/users`, {
35
+ >(`/api/v4/channels/${encodeURIComponent(params.channelId)}/users`, {
33
36
  params: {
34
37
  ...params,
35
38
  options: {
@@ -47,6 +50,19 @@ export const queryChannelMembers = async (
47
50
  const cachedAt = client.cache && Date.now();
48
51
  if (client.cache) {
49
52
  ingestInCache(data as Amity.ChannelMembershipPayload);
53
+
54
+ const cacheKey = [
55
+ 'channelUsers',
56
+ 'query',
57
+ { ...params, options: { ...page } } as Amity.Serializable,
58
+ ];
59
+
60
+ pushToCache(cacheKey, {
61
+ channelUsers: channelUsers.map(({ channelId, userId }) =>
62
+ getResolver('channelUsers')({ channelId, userId }),
63
+ ),
64
+ paging,
65
+ });
50
66
  }
51
67
 
52
68
  const nextPage = toPage(paging.next);
@@ -68,9 +84,41 @@ export const queryChannelMembers = async (
68
84
  *
69
85
  * @category Post API
70
86
  */
71
- queryChannelMembers.locally = (query: Parameters<typeof queryChannelMembers>[0]) => {
87
+ queryChannelMembers.locally = (
88
+ query: Parameters<typeof queryChannelMembers>[0],
89
+ ): Amity.Cached<Amity.Paged<Amity.Membership<'channel'>>> | undefined => {
72
90
  const client = getActiveClient();
73
- client.log('channel/queryChannelMembers', query);
91
+ client.log('channel/queryChannelMembers.locally', query);
92
+
93
+ if (!client.cache) return;
94
+
95
+ const { page = { limit: 10 }, ...params } = query;
96
+
97
+ const cacheKey = [
98
+ 'channelUsers',
99
+ 'query',
100
+ { ...params, options: { ...page } } as Amity.Serializable,
101
+ ];
102
+
103
+ const { data, cachedAt } =
104
+ pullFromCache<
105
+ {
106
+ channelUsers: Pick<Amity.Membership<'channel'>, 'channelId' | 'userId'>[];
107
+ } & Amity.Pagination
108
+ >(cacheKey) ?? {};
109
+
110
+ if (!data?.channelUsers.length) return;
111
+
112
+ const channelUsers: Amity.Membership<'channel'>[] = data.channelUsers
113
+ // ck -> cacheKey, abbrevated to avoid confusion from the above cache key
114
+ .map(ck => pullFromCache<Amity.Membership<'channel'>>(['channelUsers', 'get', ck])!)
115
+ .filter(Boolean)
116
+ .map(({ data }) => data);
117
+
118
+ const prevPage = toPage(data?.paging.previous);
119
+ const nextPage = toPage(data?.paging.next);
74
120
 
75
- // TODO
121
+ return channelUsers.length === data?.channelUsers?.length
122
+ ? { data: channelUsers, cachedAt, prevPage, nextPage }
123
+ : undefined;
76
124
  };
@@ -1,10 +1,11 @@
1
1
  import { getActiveClient } from '~/client/api';
2
2
 
3
3
  import { toPage, toToken } from '~/core/query';
4
- import { pushToCache } from '~/cache/api';
5
- import { ingestInCache } from '~/cache/api/ingestInCache';
6
4
  import { getResolver } from '~/core/model';
7
5
 
6
+ import { pushToCache, pullFromCache } from '~/cache/api';
7
+ import { ingestInCache } from '~/cache/api/ingestInCache';
8
+
8
9
  import { prepareChannelPayload } from '../utils';
9
10
 
10
11
  /**
@@ -86,9 +87,35 @@ export const queryChannels = async (
86
87
  *
87
88
  * @category Channel API
88
89
  */
89
- queryChannels.locally = (query: Parameters<typeof queryChannels>[0]) => {
90
+ queryChannels.locally = (
91
+ query?: Parameters<typeof queryChannels>[0],
92
+ ): Amity.Cached<Amity.Paged<Amity.Channel>> | undefined => {
90
93
  const client = getActiveClient();
91
94
  client.log('channel/queryChannels.locally', query);
92
95
 
93
- // TODO
96
+ const { page = { limit: 10 }, ...params } = query ?? {};
97
+
98
+ const cacheKey = ['channel', 'query', { ...params, options: { ...page } } as Amity.Serializable];
99
+
100
+ const { data, cachedAt } =
101
+ pullFromCache<
102
+ {
103
+ channels: Pick<Amity.Channel, 'channelId'>[];
104
+ } & Amity.Pagination
105
+ >(cacheKey) ?? {};
106
+
107
+ if (!data?.channels.length) return;
108
+
109
+ const channels: Amity.Channel[] = data.channels
110
+ // ck -> cacheKey, abbrevated to avoid confusion from the above cache key
111
+ .map(ck => pullFromCache<Amity.Channel>(['channel', 'get', ck])!)
112
+ .filter(Boolean)
113
+ .map(({ data }) => data);
114
+
115
+ const prevPage = toPage(data?.paging.previous);
116
+ const nextPage = toPage(data?.paging.next);
117
+
118
+ return channels.length === data?.channels?.length
119
+ ? { data: channels, cachedAt, prevPage, nextPage }
120
+ : undefined;
94
121
  };
@@ -0,0 +1,115 @@
1
+ import { getResolver } from '~/core/model';
2
+
3
+ import { disableCache, enableCache, pushToCache } from '~/cache/api';
4
+ import { ingestInCache } from '~/cache/api/ingestInCache';
5
+
6
+ import { prepareChannelPayload } from '~/channel/utils';
7
+ import { client, channelUserQueryResponse } from '~/utils/tests';
8
+
9
+ import { queryChannelMembers } from '../queryChannelMembers';
10
+
11
+ describe('queryChannelMembers', () => {
12
+ const { channelId } = channelUserQueryResponse.data.channels[0];
13
+
14
+ test('it should return channel members', async () => {
15
+ const expected = channelUserQueryResponse.data.channelUsers;
16
+ client.http.get = jest.fn().mockResolvedValue(channelUserQueryResponse);
17
+
18
+ const { data } = await queryChannelMembers({ channelId });
19
+
20
+ expect(data).toEqual(expected);
21
+ });
22
+
23
+ test('it should throw error', async () => {
24
+ client.http.get = jest.fn().mockRejectedValueOnce(new Error('error'));
25
+
26
+ await expect(queryChannelMembers({ channelId })).rejects.toThrow('error');
27
+ });
28
+
29
+ test('it should update cache upon fetching data from server', async () => {
30
+ enableCache();
31
+ client.http.get = jest.fn().mockResolvedValue(channelUserQueryResponse);
32
+
33
+ const { data: got } = await queryChannelMembers({ channelId });
34
+ const { data } = queryChannelMembers.locally({ channelId })!;
35
+
36
+ expect(data).toBeDefined();
37
+ expect(got).toEqual(data);
38
+
39
+ disableCache();
40
+ });
41
+ });
42
+
43
+ describe('queryChannelMembers.locally', () => {
44
+ const { channelId } = channelUserQueryResponse.data.channels[0];
45
+ const cacheKey = [
46
+ 'channelUsers',
47
+ 'query',
48
+ { channelId, options: { limit: 10, after: undefined } },
49
+ ];
50
+
51
+ test('it should fetch query locally if present in cache', () => {
52
+ enableCache();
53
+
54
+ const { paging, ...payload } = channelUserQueryResponse.data;
55
+ const data = prepareChannelPayload(payload);
56
+ const { channelUsers } = data;
57
+
58
+ ingestInCache(data as Amity.ChannelMembershipPayload);
59
+
60
+ pushToCache(cacheKey, {
61
+ channelUsers: channelUsers.map(({ channelId, userId }) =>
62
+ getResolver('channelUsers')({ channelId, userId }),
63
+ ),
64
+ paging,
65
+ });
66
+
67
+ const { data: got } = queryChannelMembers.locally({ channelId })!;
68
+
69
+ expect(got).toBeDefined();
70
+ expect(got).toEqual(channelUsers);
71
+
72
+ disableCache();
73
+ });
74
+
75
+ test('it should return undefined if only partial data in cache', () => {
76
+ enableCache();
77
+
78
+ const { paging, ...payload } = channelUserQueryResponse.data;
79
+ const data = prepareChannelPayload(payload);
80
+ const { channelUsers } = data;
81
+
82
+ // ingest incomplete data
83
+ ingestInCache({
84
+ ...data,
85
+ channelUsers: [data.channelUsers[0]],
86
+ } as Amity.ChannelMembershipPayload);
87
+
88
+ pushToCache(cacheKey, {
89
+ channelUsers: channelUsers.map(({ channelId, userId }) =>
90
+ getResolver('channelUsers')({ channelId, userId }),
91
+ ),
92
+ paging,
93
+ });
94
+
95
+ const got = queryChannelMembers.locally({ channelId })!;
96
+
97
+ expect(got).toBeUndefined();
98
+
99
+ disableCache();
100
+ });
101
+
102
+ test('it should return undefined if data not in cache', () => {
103
+ enableCache();
104
+
105
+ const got = queryChannelMembers.locally({ channelId });
106
+
107
+ expect(got).toBeUndefined();
108
+
109
+ disableCache();
110
+ });
111
+
112
+ test('it should return undefined if cache disabled', () => {
113
+ expect(queryChannelMembers.locally({ channelId })).toBeUndefined();
114
+ });
115
+ });
@@ -0,0 +1,101 @@
1
+ import { getResolver } from '~/core/model';
2
+
3
+ import { disableCache, enableCache, pushToCache } from '~/cache/api';
4
+ import { ingestInCache } from '~/cache/api/ingestInCache';
5
+
6
+ import { prepareChannelPayload } from '~/channel/utils';
7
+ import { client, channelQueryResponse } from '~/utils/tests';
8
+
9
+ import { queryChannels } from '../queryChannels';
10
+
11
+ describe('queryChannels', () => {
12
+ test('it should return channels', async () => {
13
+ const expected = prepareChannelPayload(channelQueryResponse.data).channels;
14
+ client.http.get = jest.fn().mockResolvedValue(channelQueryResponse);
15
+
16
+ const { data } = await queryChannels();
17
+
18
+ expect(data).toEqual(expected);
19
+ });
20
+
21
+ test('it should throw error', async () => {
22
+ client.http.get = jest.fn().mockRejectedValueOnce(new Error('error'));
23
+
24
+ await expect(queryChannels()).rejects.toThrow('error');
25
+ });
26
+
27
+ test('it should update cache upon fetching data from server', async () => {
28
+ enableCache();
29
+ client.http.get = jest.fn().mockResolvedValue(channelQueryResponse);
30
+
31
+ const { data: got } = await queryChannels();
32
+ const { data } = queryChannels.locally()!;
33
+
34
+ expect(data).toBeDefined();
35
+ expect(got).toEqual(data);
36
+
37
+ disableCache();
38
+ });
39
+ });
40
+
41
+ describe('queryChannels.locally', () => {
42
+ const cacheKey = ['channel', 'query', { options: { limit: 10, after: undefined } }];
43
+
44
+ test('it should fetch query locally if present in cache', () => {
45
+ enableCache();
46
+
47
+ const { paging, ...payload } = channelQueryResponse.data;
48
+ const data = prepareChannelPayload(payload);
49
+ const { channels } = data;
50
+
51
+ ingestInCache(data as Amity.ChannelMembershipPayload);
52
+
53
+ pushToCache(cacheKey, { channels: channels.map(getResolver('channel')), paging });
54
+
55
+ const { data: got } = queryChannels.locally()!;
56
+
57
+ expect(got).toBeDefined();
58
+ expect(got).toEqual(channels);
59
+
60
+ disableCache();
61
+ });
62
+
63
+ test('it should return undefined if only partial data in cache', () => {
64
+ enableCache();
65
+
66
+ const { paging, ...payload } = channelQueryResponse.data;
67
+ const data = prepareChannelPayload(payload);
68
+ const { channels } = data;
69
+
70
+ // ingest incomplete data
71
+ ingestInCache({
72
+ ...data,
73
+ channels: [data.channels[0]],
74
+ } as Amity.ChannelPayload);
75
+
76
+ pushToCache(cacheKey, {
77
+ channels: channels.map(getResolver('channel')),
78
+ paging,
79
+ });
80
+
81
+ const got = queryChannels.locally()!;
82
+
83
+ expect(got).toBeUndefined();
84
+
85
+ disableCache();
86
+ });
87
+
88
+ test('it should return undefined if data not in cache', () => {
89
+ enableCache();
90
+
91
+ const got = queryChannels.locally();
92
+
93
+ expect(got).toBeUndefined();
94
+
95
+ disableCache();
96
+ });
97
+
98
+ test('it should return undefined if cache disabled', () => {
99
+ expect(queryChannels.locally()).toBeUndefined();
100
+ });
101
+ });
@@ -1,7 +1,12 @@
1
1
  export * from './onChannelCreated';
2
2
  export * from './onChannelUpdated';
3
3
  export * from './onChannelDeleted';
4
+
4
5
  export * from './onChannelJoined';
5
6
  export * from './onChannelLeft';
7
+
6
8
  export * from './onChannelMemberAdded';
7
9
  export * from './onChannelMemberRemoved';
10
+
11
+ export * from './onChannelMemberBanned';
12
+ export * from './onChannelMemberUnbanned';
@@ -0,0 +1,36 @@
1
+ import { getActiveClient } from '~/client/api';
2
+ import { createEventSubscriber } from '~/core/events';
3
+
4
+ import { ingestInCache } from '~/cache/api/ingestInCache';
5
+
6
+ import { prepareChannelPayload } from '../utils';
7
+
8
+ /**
9
+ * ```js
10
+ * import { onChannelMemberBanned } from '@amityco/ts-sdk'
11
+ * const dispose = onChannelMemberBanned((channel, member) => {
12
+ * // ...
13
+ * })
14
+ * ```
15
+ *
16
+ * Fired when any {@link Amity.User} has been banned from any {@link Amity.Channel}
17
+ *
18
+ * @param callback The function to call when the event was fired
19
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
20
+ *
21
+ * @category Channel Events
22
+ */
23
+ export const onChannelMemberBanned = (
24
+ callback: (channel: Amity.Channel, member: Amity.Membership<'channel'>) => void,
25
+ ) => {
26
+ const client = getActiveClient();
27
+
28
+ const filter = (payload: Amity.ChannelMembershipPayload) => {
29
+ const data = prepareChannelPayload(payload);
30
+
31
+ ingestInCache(data);
32
+ callback(data.channels[0], data.channelUsers.find(cu => cu.membership === 'banned')!);
33
+ };
34
+
35
+ return createEventSubscriber(client, 'onChannelMemberBanned', 'v3.channel.didBan', filter);
36
+ };
@@ -0,0 +1,36 @@
1
+ import { getActiveClient } from '~/client/api';
2
+ import { createEventSubscriber } from '~/core/events';
3
+
4
+ import { ingestInCache } from '~/cache/api/ingestInCache';
5
+
6
+ import { prepareChannelPayload } from '../utils';
7
+
8
+ /**
9
+ * ```js
10
+ * import { onChannelMemberUnbanned } from '@amityco/ts-sdk'
11
+ * const dispose = onChannelMemberUnbanned((channel, member) => {
12
+ * // ...
13
+ * })
14
+ * ```
15
+ *
16
+ * Fired when any {@link Amity.User} has been unbanned from any {@link Amity.Channel}
17
+ *
18
+ * @param callback The function to call when the event was fired
19
+ * @returns an {@link Amity.Unsubscriber} function to stop listening
20
+ *
21
+ * @category Channel Events
22
+ */
23
+ export const onChannelMemberUnbanned = (
24
+ callback: (channel: Amity.Channel, member: Amity.Membership<'channel'>) => void,
25
+ ) => {
26
+ const client = getActiveClient();
27
+
28
+ const filter = (payload: Amity.ChannelMembershipPayload) => {
29
+ const data = prepareChannelPayload(payload);
30
+
31
+ ingestInCache(data);
32
+ callback(data.channels[0], data.channelUsers.find(cu => cu.membership === 'none')!);
33
+ };
34
+
35
+ return createEventSubscriber(client, 'onChannelMemberBanned', 'v3.channel.didUnban', filter);
36
+ };
@@ -0,0 +1,58 @@
1
+ import { disableCache, enableCache } from '~/cache/api';
2
+
3
+ import {
4
+ client,
5
+ connectClient,
6
+ disconnectClient,
7
+ channel11,
8
+ channelUser1,
9
+ channelUser5,
10
+ } from '~/utils/tests';
11
+
12
+ import { onChannelMemberBanned } from '../onChannelMemberBanned';
13
+
14
+ describe('onChannelMemberBanned event', () => {
15
+ beforeAll(async () => {
16
+ await connectClient();
17
+ });
18
+
19
+ afterAll(async () => {
20
+ await disconnectClient();
21
+ });
22
+
23
+ beforeEach(async () => {
24
+ enableCache();
25
+ });
26
+
27
+ afterEach(disableCache);
28
+
29
+ const channelPayload: Amity.ChannelMembershipPayload = {
30
+ channelUsers: [channelUser1, channelUser5],
31
+ channels: [channel11],
32
+ files: [],
33
+ users: [],
34
+ };
35
+
36
+ test('it should call callback with channel and banned member', () => {
37
+ const callback = jest.fn();
38
+
39
+ const unsub = onChannelMemberBanned(callback);
40
+ client.emitter.emit('v3.channel.didBan', channelPayload);
41
+
42
+ unsub();
43
+
44
+ expect(callback).toHaveBeenCalled();
45
+ expect(callback).toHaveBeenCalledWith(channel11, channelUser5);
46
+ });
47
+
48
+ test('it should return an unsubscriber', () => {
49
+ const callback = jest.fn();
50
+
51
+ const unsub = onChannelMemberBanned(callback);
52
+ unsub();
53
+
54
+ client.emitter.emit('v3.channel.didBan', channelPayload);
55
+
56
+ expect(callback).not.toHaveBeenCalled();
57
+ });
58
+ });