@amityco/ts-sdk 0.0.1-beta.28 → 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 (83) hide show
  1. package/dist/@types/core/payload.d.ts +3 -3
  2. package/dist/@types/core/payload.d.ts.map +1 -1
  3. package/dist/@types/domains/channel.d.ts +12 -0
  4. package/dist/@types/domains/channel.d.ts.map +1 -1
  5. package/dist/@types/domains/community.d.ts +24 -2
  6. package/dist/@types/domains/community.d.ts.map +1 -1
  7. package/dist/@types/domains/content.d.ts +2 -1
  8. package/dist/@types/domains/content.d.ts.map +1 -1
  9. package/dist/@types/index.d.ts +1 -1
  10. package/dist/@types/index.d.ts.map +1 -1
  11. package/dist/channel/api/queryChannels.d.ts +1 -10
  12. package/dist/channel/api/queryChannels.d.ts.map +1 -1
  13. package/dist/channel/observers/index.d.ts +1 -0
  14. package/dist/channel/observers/index.d.ts.map +1 -1
  15. package/dist/channel/observers/liveChannels.d.ts +20 -0
  16. package/dist/channel/observers/liveChannels.d.ts.map +1 -0
  17. package/dist/channel/observers/tests/liveChannels.test.d.ts +2 -0
  18. package/dist/channel/observers/tests/liveChannels.test.d.ts.map +1 -0
  19. package/dist/community/api/createCommunity.d.ts +1 -1
  20. package/dist/community/api/createCommunity.d.ts.map +1 -1
  21. package/dist/community/api/getCommunities.d.ts.map +1 -1
  22. package/dist/community/api/getCommunity.d.ts.map +1 -1
  23. package/dist/community/api/getRecommendedCommunities.d.ts.map +1 -1
  24. package/dist/community/api/getTopTrendingCommunities.d.ts.map +1 -1
  25. package/dist/community/api/queryCommunities.d.ts.map +1 -1
  26. package/dist/community/api/updateCommunity.d.ts +1 -1
  27. package/dist/community/api/updateCommunity.d.ts.map +1 -1
  28. package/dist/community/events/utils.d.ts.map +1 -1
  29. package/dist/community/utils/index.d.ts +2 -0
  30. package/dist/community/utils/index.d.ts.map +1 -0
  31. package/dist/community/utils/payload.d.ts +11 -0
  32. package/dist/community/utils/payload.d.ts.map +1 -0
  33. package/dist/follow/tests/observers/liveFollowers.test.d.ts +2 -0
  34. package/dist/follow/tests/observers/liveFollowers.test.d.ts.map +1 -0
  35. package/dist/follow/tests/observers/liveFollowings.test.d.ts +2 -0
  36. package/dist/follow/tests/observers/liveFollowings.test.d.ts.map +1 -0
  37. package/dist/index.cjs.js +201 -20
  38. package/dist/index.esm.js +198 -21
  39. package/dist/index.umd.js +4 -4
  40. package/dist/utils/tests/dummy/channel.d.ts +25 -2
  41. package/dist/utils/tests/dummy/channel.d.ts.map +1 -1
  42. package/dist/utils/tests/dummy/follow.d.ts +12 -0
  43. package/dist/utils/tests/dummy/follow.d.ts.map +1 -0
  44. package/dist/utils/tests/dummy/index.d.ts +1 -0
  45. package/dist/utils/tests/dummy/index.d.ts.map +1 -1
  46. package/dist/utils/tests/dummy/user.d.ts +3 -0
  47. package/dist/utils/tests/dummy/user.d.ts.map +1 -1
  48. package/dist/utils/tests/index.d.ts +1 -0
  49. package/dist/utils/tests/index.d.ts.map +1 -1
  50. package/dist/utils/tests/utils.d.ts +2 -0
  51. package/dist/utils/tests/utils.d.ts.map +1 -0
  52. package/package.json +1 -1
  53. package/src/@types/core/payload.ts +3 -3
  54. package/src/@types/domains/channel.ts +18 -0
  55. package/src/@types/domains/community.ts +27 -2
  56. package/src/@types/domains/content.ts +2 -1
  57. package/src/@types/index.ts +1 -1
  58. package/src/channel/api/queryChannels.ts +3 -10
  59. package/src/channel/observers/index.ts +1 -0
  60. package/src/channel/observers/liveChannels.ts +178 -0
  61. package/src/channel/observers/tests/liveChannels.test.ts +173 -0
  62. package/src/community/api/createCommunity.ts +9 -3
  63. package/src/community/api/getCommunities.ts +10 -3
  64. package/src/community/api/getCommunity.ts +5 -1
  65. package/src/community/api/getRecommendedCommunities.ts +5 -2
  66. package/src/community/api/getTopTrendingCommunities.ts +4 -1
  67. package/src/community/api/queryCommunities.ts +5 -2
  68. package/src/community/api/updateCommunity.ts +7 -3
  69. package/src/community/events/utils.ts +13 -7
  70. package/src/community/utils/index.ts +1 -0
  71. package/src/community/utils/payload.ts +44 -0
  72. package/src/core/model/identifyModel.ts +1 -1
  73. package/src/follow/observers/liveFollowers.ts +1 -1
  74. package/src/follow/observers/liveFollowings.ts +1 -1
  75. package/src/follow/tests/observers/liveFollowers.test.ts +240 -0
  76. package/src/follow/tests/observers/liveFollowings.test.ts +239 -0
  77. package/src/message/observers/tests/liveMessages.test.ts +202 -22
  78. package/src/utils/tests/dummy/channel.ts +48 -4
  79. package/src/utils/tests/dummy/follow.ts +60 -0
  80. package/src/utils/tests/dummy/index.ts +1 -0
  81. package/src/utils/tests/dummy/user.ts +15 -0
  82. package/src/utils/tests/index.ts +1 -0
  83. package/src/utils/tests/utils.ts +3 -0
@@ -1,10 +1,33 @@
1
1
  export declare const channelRaw1: Amity.ChannelRaw;
2
2
  export declare const channelRaw2: Amity.ChannelRaw;
3
+ export declare const channelRaw3: Amity.ChannelRaw;
3
4
  export declare const channel11: Amity.Channel;
4
5
  export declare const channel12: Amity.Channel;
6
+ export declare const channel21: Amity.Channel;
5
7
  export declare const channelUser1: Amity.Membership<'channel'>;
6
8
  export declare const channelUser2: Amity.Membership<'channel'>;
7
- export declare const channels: {
8
- page1: string[];
9
+ export declare const channelQueryResponse: {
10
+ data: {
11
+ channels: Amity.Channel<any>[];
12
+ channelUsers: never[];
13
+ files: never[];
14
+ users: never[];
15
+ paging: {
16
+ previous: string;
17
+ next: string;
18
+ };
19
+ };
20
+ };
21
+ export declare const channelQueryResponsePage2: {
22
+ data: {
23
+ channels: Amity.Channel<any>[];
24
+ channelUsers: never[];
25
+ files: never[];
26
+ users: never[];
27
+ paging: {
28
+ previous: string;
29
+ next: string;
30
+ };
31
+ };
9
32
  };
10
33
  //# sourceMappingURL=channel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../../../src/utils/tests/dummy/channel.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,UAK/B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,UAK/B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,OAI7B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,OAI7B,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS,CAYpD,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS,CAKpD,CAAC;AAEF,eAAO,MAAM,QAAQ;;CAEpB,CAAC"}
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../../../src/utils/tests/dummy/channel.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,UAK/B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,UAK/B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,UAK/B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,OAO7B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,OAO7B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,OAO7B,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS,CAYpD,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS,CAKpD,CAAC;AAEF,eAAO,MAAM,oBAAoB;;;;;;;;;;;CAWhC,CAAC;AAEF,eAAO,MAAM,yBAAyB;;;;;;;;;;;CAWrC,CAAC"}
@@ -0,0 +1,12 @@
1
+ export declare const follow11: Amity.FollowStatus;
2
+ export declare const follow12: Amity.FollowStatus;
3
+ export declare const follow13: Amity.FollowStatus;
4
+ export declare const follow21: Amity.FollowStatus;
5
+ export declare const follow22: Amity.FollowStatus;
6
+ export declare const follow23: Amity.FollowStatus;
7
+ export declare const follows: {
8
+ userId: string;
9
+ page1: Amity.FollowStatus[];
10
+ page2: Amity.FollowStatus[];
11
+ };
12
+ //# sourceMappingURL=follow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"follow.d.ts","sourceRoot":"","sources":["../../../../src/utils/tests/dummy/follow.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,YAK5B,CAAC;AAGF,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,YAK5B,CAAC;AAGF,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,YAK5B,CAAC;AAGF,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,YAK5B,CAAC;AAGF,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,YAK5B,CAAC;AAGF,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,YAK5B,CAAC;AAEF,eAAO,MAAM,OAAO;;;;CAInB,CAAC"}
@@ -5,6 +5,7 @@ export declare const rolesAndPermissions: {
5
5
  };
6
6
  export * from './user';
7
7
  export * from './post';
8
+ export * from './follow';
8
9
  export * from './channel';
9
10
  export * from './message';
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/utils/tests/dummy/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI,QAA2B,CAAC;AAC7C,eAAO,MAAM,mBAAmB;;;CAAiC,CAAC;AAElE,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/utils/tests/dummy/index.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI,QAA2B,CAAC;AAC7C,eAAO,MAAM,mBAAmB;;;CAAiC,CAAC;AAElE,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC"}
@@ -1,2 +1,5 @@
1
1
  export declare const user11: Amity.User;
2
+ export declare const user12: Amity.User;
3
+ export declare const user13: Amity.User;
4
+ export declare const user14: Amity.User;
2
5
  //# sourceMappingURL=user.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../../../src/utils/tests/dummy/user.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,IAQ1B,CAAC"}
1
+ {"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../../../src/utils/tests/dummy/user.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,IAQ1B,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,IAG1B,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,IAG1B,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,IAG1B,CAAC"}
@@ -1,3 +1,4 @@
1
+ export * from './utils';
1
2
  export * from './dummy';
2
3
  export * from './client';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/tests/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/tests/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const encodeJson: (value: Record<string, any>) => string;
2
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/utils/tests/utils.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,UAAU,UAAW,OAAO,MAAM,EAAE,GAAG,CAAC,WAAkC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amityco/ts-sdk",
3
- "version": "0.0.1-beta.28",
3
+ "version": "0.0.1-beta.29",
4
4
  "license": "CC-BY-ND-4.0",
5
5
  "author": "amity.co <developers@amity.co> (https://amity.co)",
6
6
  "description": "Amity Social Cloud Typescript SDK",
@@ -65,7 +65,7 @@ declare global {
65
65
  };
66
66
 
67
67
  type CommunityPayload = {
68
- communities: Amity.Community[];
68
+ communities: Amity.RawCommunity[];
69
69
  communityUsers?: Amity.Membership<'community'>[];
70
70
  categories?: Amity.Category[];
71
71
  feeds?: Amity.Feed[];
@@ -79,7 +79,7 @@ declare global {
79
79
  };
80
80
 
81
81
  type CommunityMembershipPayload = {
82
- communities: Amity.Community[];
82
+ communities: Amity.RawCommunity[];
83
83
  communityUsers: Amity.Membership<'community'>[];
84
84
  categories?: Amity.Category[];
85
85
  feeds?: Amity.Feed[];
@@ -90,7 +90,7 @@ declare global {
90
90
  type PostPayload<T extends Amity.PostContentType = any> = {
91
91
  posts: Amity.Post<T>[];
92
92
  postChildren?: Amity.Post[];
93
- communities?: Amity.Community[];
93
+ communities?: Amity.RawCommunity[];
94
94
  communityUsers?: Amity.Membership<'community'>[];
95
95
  categories?: Amity.Category[];
96
96
  comments?: Amity.Comment[];
@@ -46,5 +46,23 @@ declare global {
46
46
  Amity.SoftDelete;
47
47
 
48
48
  type ChannelRaw<T extends ChannelType = any> = Omit<Channel<T>, 'unreadCount' | 'hasMention'>;
49
+
50
+ type QueryChannels = {
51
+ displayName?: string;
52
+ membership?: 'all' | 'member' | 'notMember';
53
+ sortBy?: 'displayName' | 'firstCreated' | 'lastCreated';
54
+ types?: Amity.ChannelType[];
55
+ isDeleted?: Amity.Channel['isDeleted'];
56
+ tags?: Amity.Taggable['tags'];
57
+ excludeTags?: Amity.Taggable['tags'];
58
+ page?: Amity.Page;
59
+ };
60
+
61
+ type ChannelLiveCollection = Amity.LiveCollectionParams<Omit<QueryChannels, 'page'>>;
62
+
63
+ type ChannelLiveCollectionCache = Amity.LiveCollectionCache<
64
+ Amity.Channel['channelId'],
65
+ Pick<QueryChannels, 'page'>
66
+ >;
49
67
  }
50
68
  }
@@ -1,8 +1,29 @@
1
- export {};
1
+ export const CommunityPostSettings = Object.freeze({
2
+ ONLY_ADMIN_CAN_POST: 'ONLY_ADMIN_CAN_POST',
3
+ ADMIN_REVIEW_POST_REQUIRED: 'ADMIN_REVIEW_POST_REQUIRED',
4
+ ANYONE_CAN_POST: 'ANYONE_CAN_POST',
5
+ });
6
+
7
+ export const CommunityPostSettingMaps = Object.freeze({
8
+ ONLY_ADMIN_CAN_POST: {
9
+ needApprovalOnPostCreation: false,
10
+ onlyAdminCanPost: true,
11
+ },
12
+ ADMIN_REVIEW_POST_REQUIRED: {
13
+ needApprovalOnPostCreation: true,
14
+ onlyAdminCanPost: false,
15
+ },
16
+ ANYONE_CAN_POST: {
17
+ needApprovalOnPostCreation: false,
18
+ onlyAdminCanPost: false,
19
+ },
20
+ });
21
+
22
+ export const DefaultCommunityPostSetting = 'ONLY_ADMIN_CAN_POST';
2
23
 
3
24
  declare global {
4
25
  namespace Amity {
5
- type Community = {
26
+ type RawCommunity = {
6
27
  communityId: string;
7
28
 
8
29
  displayName: string;
@@ -30,5 +51,9 @@ declare global {
30
51
  Amity.Timestamps &
31
52
  Amity.SoftDelete &
32
53
  Amity.Subscribable;
54
+
55
+ type Community = Omit<Amity.RawCommunity, 'onlyAdminCanPost' | 'needApprovalOnPostCreation'> & {
56
+ postSetting?: ValueOf<typeof CommunityPostSettings>;
57
+ };
33
58
  }
34
59
  }
@@ -1,8 +1,9 @@
1
1
  export const ContentFeedType = Object.freeze({
2
2
  STORY: 'story',
3
- CHIP: 'clip',
3
+ CLIP: 'clip',
4
4
  CHAT: 'chat',
5
5
  POST: 'post',
6
+ MESSAGE: 'message',
6
7
  });
7
8
 
8
9
  declare global {
@@ -23,7 +23,6 @@ import './domains/group';
23
23
  import './domains/channel';
24
24
  import './domains/message';
25
25
 
26
- import './domains/community';
27
26
  import './domains/category';
28
27
  import './domains/post';
29
28
  import './domains/comment';
@@ -34,5 +33,6 @@ import './domains/mention';
34
33
 
35
34
  import './domains/poll';
36
35
 
36
+ export * from './domains/community';
37
37
  export * from './domains/content';
38
38
  export * from './domains/file';
@@ -22,16 +22,9 @@ import { prepareChannelPayload } from '../utils';
22
22
  * @category Channel API
23
23
  * @async
24
24
  */
25
- export const queryChannels = async (query?: {
26
- displayName?: string;
27
- membership?: 'all' | 'member' | 'notMember';
28
- sortBy?: 'displayName' | 'firstCreated' | 'lastCreated';
29
- types?: Amity.ChannelType;
30
- isDeleted?: Amity.Channel['isDeleted'];
31
- tags?: Amity.Taggable['tags'];
32
- excludeTags?: Amity.Taggable['tags'];
33
- page?: Amity.Page;
34
- }): Promise<Amity.Cached<Amity.Paged<Amity.Channel>>> => {
25
+ export const queryChannels = async (
26
+ query?: Amity.QueryChannels,
27
+ ): Promise<Amity.Cached<Amity.Paged<Amity.Channel>>> => {
35
28
  const client = getActiveClient();
36
29
  client.log('channel/queryChannels', query);
37
30
 
@@ -1,2 +1,3 @@
1
1
  export * from './observeChannel';
2
2
  export * from './observeChannels';
3
+ export * from './liveChannels';
@@ -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
+ };
@@ -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
+ });
@@ -3,6 +3,8 @@ import { getActiveClient } from '~/client/api';
3
3
  import { ingestInCache } from '~/cache/api/ingestInCache';
4
4
  import { fireEvent } from '~/core/events';
5
5
 
6
+ import { packCommunityPayload, unpackCommunityPayload } from '../utils';
7
+
6
8
  /**
7
9
  * ```js
8
10
  * import { createCommunity } from '@amityco/ts-sdk'
@@ -25,8 +27,7 @@ export const createCommunity = async (
25
27
  | 'description'
26
28
  | 'isPublic'
27
29
  | 'isOfficial'
28
- | 'onlyAdminCanPost'
29
- | 'needApprovalOnPostCreation'
30
+ | 'postSetting'
30
31
  | 'tags'
31
32
  | 'metadata'
32
33
  > & {
@@ -38,7 +39,12 @@ export const createCommunity = async (
38
39
  const client = getActiveClient();
39
40
  client.log('user/createCommunity', bundle);
40
41
 
41
- const { data } = await client.http.post<Amity.CommunityPayload>('/api/v3/communities/', bundle);
42
+ const { data: payload } = await client.http.post<Amity.CommunityPayload>(
43
+ '/api/v3/communities/',
44
+ packCommunityPayload(bundle),
45
+ );
46
+
47
+ const data = unpackCommunityPayload(payload);
42
48
 
43
49
  const cachedAt = client.cache && Date.now();
44
50
  if (client.cache) ingestInCache(data, { cachedAt });
@@ -3,6 +3,8 @@ import { getActiveClient } from '~/client/api';
3
3
  import { pullFromCache } from '~/cache/api';
4
4
  import { ingestInCache } from '~/cache/api/ingestInCache';
5
5
 
6
+ import { unpackCommunityPayload } from '../utils';
7
+
6
8
  /**
7
9
  * ```js
8
10
  * import { getCommunities } from '@amityco/ts-sdk'
@@ -24,9 +26,14 @@ export const getCommunities = async (
24
26
  client.log('community/getCommunities', communityIds);
25
27
 
26
28
  // API-FIX: endpoint should not be /list, parameters should be querystring.
27
- const { data } = await client.http.get<Amity.CommunityPayload>(`/api/v3/communities/list`, {
28
- params: { communityIds },
29
- });
29
+ const { data: payload } = await client.http.get<Amity.CommunityPayload>(
30
+ `/api/v3/communities/list`,
31
+ {
32
+ params: { communityIds },
33
+ },
34
+ );
35
+
36
+ const data = unpackCommunityPayload(payload);
30
37
 
31
38
  const cachedAt = client.cache && Date.now();
32
39
  if (client.cache) ingestInCache(data, { cachedAt });