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

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 (35) hide show
  1. package/dist/@types/domains/channel.d.ts +11 -0
  2. package/dist/@types/domains/channel.d.ts.map +1 -1
  3. package/dist/channel/api/queryChannelMembers.d.ts +1 -8
  4. package/dist/channel/api/queryChannelMembers.d.ts.map +1 -1
  5. package/dist/channel/observers/index.d.ts +1 -0
  6. package/dist/channel/observers/index.d.ts.map +1 -1
  7. package/dist/channel/observers/liveChannelMembers.d.ts +20 -0
  8. package/dist/channel/observers/liveChannelMembers.d.ts.map +1 -0
  9. package/dist/channel/observers/tests/liveChannelMembers.test.d.ts +2 -0
  10. package/dist/channel/observers/tests/liveChannelMembers.test.d.ts.map +1 -0
  11. package/dist/client/api/getToken.d.ts +1 -3
  12. package/dist/client/api/getToken.d.ts.map +1 -1
  13. package/dist/core/query/filtering.d.ts +1 -0
  14. package/dist/core/query/filtering.d.ts.map +1 -1
  15. package/dist/core/query/query.d.ts.map +1 -1
  16. package/dist/index.cjs.js +105 -2
  17. package/dist/index.esm.js +104 -3
  18. package/dist/index.umd.js +4 -4
  19. package/dist/utils/tests/dummy/channel.d.ts +29 -3
  20. package/dist/utils/tests/dummy/channel.d.ts.map +1 -1
  21. package/dist/utils/tests/utils.d.ts +1 -0
  22. package/dist/utils/tests/utils.d.ts.map +1 -1
  23. package/package.json +2 -2
  24. package/src/@types/domains/channel.ts +19 -0
  25. package/src/channel/api/queryChannelMembers.ts +3 -8
  26. package/src/channel/observers/index.ts +1 -0
  27. package/src/channel/observers/liveChannelMembers.ts +159 -0
  28. package/src/channel/observers/tests/liveChannelMembers.test.ts +165 -0
  29. package/src/channel/observers/tests/liveChannels.test.ts +17 -9
  30. package/src/client/api/isConnected.ts +1 -1
  31. package/src/core/query/filtering.ts +6 -0
  32. package/src/core/query/query.ts +2 -3
  33. package/src/core/tests/query/query.test.ts +93 -11
  34. package/src/utils/tests/dummy/channel.ts +57 -17
  35. package/src/utils/tests/utils.ts +10 -0
@@ -6,28 +6,54 @@ export declare const channel12: Amity.Channel;
6
6
  export declare const channel21: Amity.Channel;
7
7
  export declare const channelUser1: Amity.Membership<'channel'>;
8
8
  export declare const channelUser2: Amity.Membership<'channel'>;
9
+ export declare const channelUser3: Amity.Membership<'channel'>;
10
+ export declare const channelUser4: Amity.Membership<'channel'>;
9
11
  export declare const channelQueryResponse: {
10
12
  data: {
13
+ paging: {
14
+ previous: string;
15
+ next: string;
16
+ };
11
17
  channels: Amity.Channel<any>[];
12
18
  channelUsers: never[];
13
19
  files: never[];
14
20
  users: never[];
21
+ };
22
+ };
23
+ export declare const channelQueryResponsePage2: {
24
+ data: {
15
25
  paging: {
16
26
  previous: string;
17
27
  next: string;
18
28
  };
29
+ channels: Amity.Channel<any>[];
30
+ channelUsers: never[];
31
+ files: never[];
32
+ users: never[];
19
33
  };
20
34
  };
21
- export declare const channelQueryResponsePage2: {
35
+ export declare const channelUserQueryResponse: {
22
36
  data: {
37
+ paging: {
38
+ previous: string;
39
+ next: string;
40
+ };
23
41
  channels: Amity.Channel<any>[];
24
- channelUsers: never[];
25
- files: never[];
42
+ channelUsers: Amity.Membership<"channel">[];
26
43
  users: never[];
44
+ files: never[];
45
+ };
46
+ };
47
+ export declare const channelUserQueryResponsePage2: {
48
+ data: {
27
49
  paging: {
28
50
  previous: string;
29
51
  next: string;
30
52
  };
53
+ channels: Amity.Channel<any>[];
54
+ channelUsers: Amity.Membership<"channel">[];
55
+ users: never[];
56
+ files: never[];
31
57
  };
32
58
  };
33
59
  //# 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,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"}
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../../../src/utils/tests/dummy/channel.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,UAO/B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,UAO/B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,UAK/B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,OAK7B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,OAI7B,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,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS,CAapD,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS,CAGpD,CAAC;AAEF,eAAO,MAAM,oBAAoB;;;;;;;;;;;CAQhC,CAAC;AAEF,eAAO,MAAM,yBAAyB;;;;;;;;;;;CAQrC,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;;;;;;;;;CAQpC,CAAC;AAEF,eAAO,MAAM,6BAA6B;;;;;;;;;;;CAQzC,CAAC"}
@@ -1,2 +1,3 @@
1
1
  export declare const encodeJson: (value: Record<string, any>) => string;
2
+ export declare const pause: (ms?: number) => Promise<unknown>;
2
3
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +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"}
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;AAOxF,eAAO,MAAM,KAAK,mCAGd,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amityco/ts-sdk",
3
- "version": "0.0.1-beta.29",
3
+ "version": "0.0.1-beta.30",
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",
@@ -54,7 +54,7 @@
54
54
  "dependencies": {
55
55
  "@react-native-async-storage/async-storage": "^1.17.7",
56
56
  "agentkeepalive": "^4.2.1",
57
- "axios": "0.21.1",
57
+ "axios": "^0.27.2",
58
58
  "debug": "^4.3.4",
59
59
  "js-base64": "^3.7.2",
60
60
  "mitt": "^3.0.0",
@@ -35,6 +35,7 @@ declare global {
35
35
 
36
36
  memberCount?: number;
37
37
  messageCount?: number;
38
+ moderatorMemberCount?: number;
38
39
 
39
40
  lastActivity?: Amity.timestamp;
40
41
 
@@ -64,5 +65,23 @@ declare global {
64
65
  Amity.Channel['channelId'],
65
66
  Pick<QueryChannels, 'page'>
66
67
  >;
68
+
69
+ type QueryChannelMembers = {
70
+ channelId: Amity.Channel['channelId'];
71
+ memberships?: Array<Exclude<Amity.Membership<'channel'>['membership'], 'none'> | 'muted'>;
72
+ roles?: string[];
73
+ sortBy?: 'firstCreated' | 'lastCreated';
74
+ search?: string;
75
+ page?: Amity.Page;
76
+ };
77
+
78
+ type ChannelMembersLiveCollection = Amity.LiveCollectionParams<
79
+ Omit<QueryChannelMembers, 'page'>
80
+ >;
81
+
82
+ type ChannelMembersLiveCollectionCache = Amity.LiveCollectionCache<
83
+ Amity.Membership<'channel'>['userId'],
84
+ Pick<QueryChannelMembers, 'page'>
85
+ >;
67
86
  }
68
87
  }
@@ -19,14 +19,9 @@ import { prepareChannelPayload } from '../utils';
19
19
  * @category Channel API
20
20
  * @async
21
21
  * */
22
- export const queryChannelMembers = async (query: {
23
- channelId: string;
24
- memberships?: ('muted' | 'banned' | 'member')[];
25
- roles?: string[];
26
- sortBy?: 'firstCreated' | 'lastCreated';
27
- search?: string;
28
- page?: Amity.Page;
29
- }): Promise<Amity.Cached<Amity.Paged<Amity.Membership<'channel'>>>> => {
22
+ export const queryChannelMembers = async (
23
+ query: Amity.QueryChannelMembers,
24
+ ): Promise<Amity.Cached<Amity.Paged<Amity.Membership<'channel'>>>> => {
30
25
  const client = getActiveClient();
31
26
  client.log('channel/queryChannelMembers', query);
32
27
 
@@ -1,3 +1,4 @@
1
1
  export * from './observeChannel';
2
2
  export * from './observeChannels';
3
3
  export * from './liveChannels';
4
+ export * from './liveChannelMembers';
@@ -0,0 +1,159 @@
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
+ sortByFirstCreated,
12
+ filterByPropInclusion,
13
+ } from '~/core/query';
14
+ import {
15
+ COLLECTION_DEFAULT_CACHING_POLICY,
16
+ COLLECTION_DEFAULT_PAGINATION_LIMIT,
17
+ ENABLE_CACHE_MESSAGE,
18
+ } from '~/utils/constants';
19
+ import { onChannelMemberAdded, onChannelMemberRemoved } from '../events';
20
+ import { queryChannelMembers } from '../api';
21
+
22
+ /**
23
+ * ```js
24
+ * import { liveChannelMembers } from '@amityco/ts-sdk'
25
+ *
26
+ * let channelMembers = []
27
+ * const unsub = liveChannelMembers({
28
+ * channelId: Amity.Channel['channelId'],
29
+ * }, response => merge(channelMembers, response.data))
30
+ * ```
31
+ *
32
+ * Observe all mutations on a list of {@link Amity.ChannelUser}s
33
+ *
34
+ * @param params for querying channel users
35
+ * @param callback the function to call when new data are available
36
+ * @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the channel users
37
+ *
38
+ * @category Channel Live Collection
39
+ */
40
+ export const liveChannelMembers = (
41
+ params: Amity.ChannelMembersLiveCollection,
42
+ callback: Amity.LiveCollectionCallback<Amity.Membership<'channel'>>,
43
+ config?: Amity.LiveCollectionConfig,
44
+ ) => {
45
+ const { log, cache } = getActiveClient();
46
+
47
+ if (!cache) {
48
+ console.log(ENABLE_CACHE_MESSAGE);
49
+ }
50
+
51
+ const timestamp = Date.now();
52
+ log(`liveChannelMembers(tmpid: ${timestamp}) > listen`);
53
+
54
+ const { limit: queryLimit, ...queryParams } = params;
55
+
56
+ const limit = queryLimit ?? COLLECTION_DEFAULT_PAGINATION_LIMIT;
57
+ const { policy = COLLECTION_DEFAULT_CACHING_POLICY } = config ?? {};
58
+
59
+ const disposers: Amity.Unsubscriber[] = [];
60
+ const cacheKey = ['channelUsers', 'collection', { channelId: params.channelId }];
61
+
62
+ const responder = (data: Amity.ChannelMembersLiveCollectionCache) => {
63
+ let channelMembers: Amity.Membership<'channel'>[] =
64
+ data.data
65
+ .map(id => pullFromCache<Amity.Membership<'channel'>>(['channelUsers', 'get', id])!)
66
+ .filter(Boolean)
67
+ .map(({ data }) => data) ?? [];
68
+
69
+ channelMembers = filterByPropEquality(channelMembers, 'roles', params.roles);
70
+ channelMembers = filterByPropInclusion(channelMembers, 'membership', params.memberships);
71
+
72
+ if (params.search) {
73
+ const containsMatcher = new RegExp(params.search);
74
+ channelMembers = channelMembers.filter(m => m.userId.match(containsMatcher));
75
+ }
76
+
77
+ // sort, 'lastCreated' is the default sort order
78
+ const sortBy = params.sortBy ? params.sortBy : 'lastCreated';
79
+ channelMembers = channelMembers.sort(
80
+ sortBy === 'lastCreated' ? sortByLastCreated : sortByFirstCreated,
81
+ );
82
+
83
+ callback({
84
+ onNextPage: onFetch,
85
+ data: channelMembers,
86
+ hasNextPage: !!data.params?.page,
87
+ loading: data.loading,
88
+ error: data.error,
89
+ });
90
+ };
91
+
92
+ const realtimeRouter = (
93
+ channelMember: Amity.Membership<'channel'>,
94
+ action: 'onMemberAdded' | 'onMemberRemoved',
95
+ ) => {
96
+ const collection = pullFromCache<Amity.ChannelMembersLiveCollectionCache>(cacheKey)?.data;
97
+ if (!collection) return;
98
+
99
+ const channelMemberCacheId = getResolver('channelUsers')({
100
+ channelId: params.channelId,
101
+ userId: channelMember.userId,
102
+ });
103
+
104
+ if (action === 'onMemberAdded') {
105
+ collection.data = [...new Set([channelMemberCacheId, ...collection.data])];
106
+ } else {
107
+ collection.data = collection.data.filter(m => m !== channelMemberCacheId);
108
+ }
109
+
110
+ pushToCache(cacheKey, collection);
111
+ responder(collection);
112
+ };
113
+
114
+ const onFetch = () => {
115
+ const collection = pullFromCache<Amity.ChannelMembersLiveCollectionCache>(cacheKey)?.data;
116
+
117
+ const channelMembers = collection?.data ?? [];
118
+
119
+ if (channelMembers.length > 0 && !collection?.params.page) return;
120
+
121
+ const query = createQuery(queryChannelMembers, {
122
+ ...queryParams,
123
+ page: collection?.params.page ?? { limit },
124
+ });
125
+
126
+ runQuery(
127
+ query,
128
+ ({ data: result, error, loading, nextPage: page }) => {
129
+ const data = {
130
+ loading,
131
+ error,
132
+ params: { page },
133
+ data: channelMembers,
134
+ };
135
+
136
+ if (result) {
137
+ data.data = [...new Set([...channelMembers, ...result.map(getResolver('channelUsers'))])];
138
+ }
139
+
140
+ pushToCache(cacheKey, data);
141
+
142
+ responder(data);
143
+ },
144
+ queryOptions(policy),
145
+ );
146
+ };
147
+
148
+ disposers.push(
149
+ onChannelMemberAdded((_, member) => realtimeRouter(member, 'onMemberAdded')),
150
+ onChannelMemberRemoved((_, member) => realtimeRouter(member, 'onMemberRemoved')),
151
+ );
152
+
153
+ onFetch();
154
+
155
+ return () => {
156
+ log(`liveChannelMembers(tmpid: ${timestamp}) > dispose`);
157
+ disposers.forEach(fn => fn());
158
+ };
159
+ };
@@ -0,0 +1,165 @@
1
+ import { disableCache, enableCache } from '~/cache/api';
2
+ import {
3
+ client,
4
+ connectClient,
5
+ disconnectClient,
6
+ channelUser1,
7
+ channelUser4,
8
+ channelUserQueryResponse,
9
+ channelUserQueryResponsePage2,
10
+ channel11,
11
+ pause,
12
+ } from '~/utils/tests';
13
+ import { liveChannelMembers } from '../liveChannelMembers';
14
+ import { prepareChannelPayload } from '../../utils';
15
+
16
+ const getSnapshot = () => {
17
+ return {
18
+ data: [] as Amity.Membership<'channel'>[],
19
+ loading: true,
20
+ error: undefined as any,
21
+ };
22
+ };
23
+
24
+ describe('liveChannelMembers', () => {
25
+ beforeAll(async () => {
26
+ await connectClient();
27
+ });
28
+
29
+ afterAll(async () => {
30
+ await disconnectClient();
31
+ });
32
+
33
+ beforeEach(enableCache);
34
+
35
+ afterEach(disableCache);
36
+
37
+ const { channelId } = channel11;
38
+
39
+ test('it should return channel members collection', async () => {
40
+ // mock response of queryChannels and validate
41
+ const callback = jest.fn();
42
+ client.http.get = jest.fn().mockResolvedValue(channelUserQueryResponse);
43
+
44
+ liveChannelMembers({ channelId }, callback);
45
+ await pause();
46
+
47
+ // check if cache data returned (should be empty)
48
+ expect(callback).toHaveBeenNthCalledWith(1, expect.objectContaining(getSnapshot()));
49
+
50
+ const snapshot = getSnapshot();
51
+ snapshot.data = channelUserQueryResponse.data.channelUsers;
52
+ snapshot.loading = false;
53
+
54
+ expect(callback).toHaveBeenNthCalledWith(2, expect.objectContaining(snapshot));
55
+ });
56
+
57
+ const filters: [string, Amity.ChannelMembersLiveCollection, Amity.Membership<'channel'>[]][] = [
58
+ [
59
+ 'roles',
60
+ { channelId, roles: channelUserQueryResponse.data.channelUsers[1].roles },
61
+ [channelUserQueryResponse.data.channelUsers[1]],
62
+ ],
63
+ [
64
+ 'searched term',
65
+ { channelId, search: 'use' },
66
+ [channelUserQueryResponse.data.channelUsers[1]],
67
+ ],
68
+ [
69
+ 'memberships',
70
+ { channelId, memberships: ['member'] },
71
+ [channelUserQueryResponse.data.channelUsers[0]],
72
+ ],
73
+ ];
74
+
75
+ test.each(filters)('it should filter channelUsers by %s', async (filter, params, expected) => {
76
+ const callback = jest.fn();
77
+ client.http.get = jest.fn().mockResolvedValue(channelUserQueryResponse);
78
+
79
+ liveChannelMembers(params, callback);
80
+ await pause();
81
+
82
+ const snapshot = getSnapshot();
83
+ // check if cache data returned (should be empty)
84
+ expect(callback).toHaveBeenNthCalledWith(1, expect.objectContaining(snapshot));
85
+
86
+ snapshot.loading = false;
87
+ snapshot.data = expected;
88
+
89
+ expect(callback).toHaveBeenNthCalledWith(2, expect.objectContaining(snapshot));
90
+ });
91
+
92
+ test('it should return method to fetch next page', async () => {
93
+ const callback = jest.fn();
94
+ client.http.get = jest
95
+ .fn()
96
+ .mockResolvedValue(channelUserQueryResponse)
97
+ .mockResolvedValueOnce(channelUserQueryResponsePage2);
98
+
99
+ liveChannelMembers({ channelId }, callback);
100
+ await pause();
101
+
102
+ expect(callback).toHaveBeenCalled();
103
+ expect(callback.mock.lastCall).toHaveLength(1);
104
+
105
+ const { onNextPage, hasNextPage } = callback.mock.lastCall[0];
106
+
107
+ expect(hasNextPage).toBe(true);
108
+ expect(onNextPage).toBeTruthy();
109
+
110
+ onNextPage();
111
+ await pause();
112
+
113
+ const payload = prepareChannelPayload(channelUserQueryResponse.data);
114
+ const payload2 = prepareChannelPayload(channelUserQueryResponsePage2.data);
115
+
116
+ const snapshot = getSnapshot();
117
+ snapshot.loading = false;
118
+ snapshot.data = [...payload2.channelUsers, ...payload.channelUsers];
119
+
120
+ expect(callback).toHaveBeenNthCalledWith(4, expect.objectContaining(snapshot));
121
+ });
122
+
123
+ const events: [string, keyof Amity.Events, Amity.Membership<'channel'>][] = [
124
+ [
125
+ 'it should add new member to collection onMemberAdded',
126
+ 'v3.channel.didAddUsers',
127
+ channelUser4,
128
+ ],
129
+ [
130
+ 'it should remove channel memeber from collection onMemberRemoved',
131
+ 'v3.channel.didRemoveUsers',
132
+ channelUser1,
133
+ ],
134
+ ];
135
+
136
+ test.each(events)('%s', async (test, event, channelUser) => {
137
+ const snapshot = getSnapshot();
138
+
139
+ const callback = jest.fn();
140
+ client.http.get = jest.fn().mockResolvedValue(channelUserQueryResponse);
141
+
142
+ liveChannelMembers({ channelId }, callback);
143
+ await pause();
144
+
145
+ client.emitter.emit(event, {
146
+ channels: [channel11],
147
+ channelUsers: [channelUser],
148
+ users: [],
149
+ files: [],
150
+ });
151
+
152
+ const payload = prepareChannelPayload(channelUserQueryResponse.data);
153
+
154
+ snapshot.loading = false;
155
+ // get data based on event
156
+ if (event === 'v3.channel.didAddUsers') {
157
+ snapshot.data = [channelUser, ...payload.channelUsers];
158
+ } else {
159
+ const deletePayload = payload.channelUsers.filter(u => u.userId !== channelUser.userId);
160
+ snapshot.data = deletePayload;
161
+ }
162
+
163
+ expect(callback).toHaveBeenNthCalledWith(3, expect.objectContaining(snapshot));
164
+ });
165
+ });
@@ -2,13 +2,13 @@ import { disableCache, enableCache } from '~/cache/api';
2
2
 
3
3
  import { liveChannels } from '../liveChannels';
4
4
  import { queryChannels } from '~/channel/api';
5
+ import { prepareChannelPayload } from '../../utils/prepareChannelPayload';
5
6
 
6
7
  import {
7
8
  client,
8
9
  connectClient,
9
10
  disconnectClient,
10
11
  channel11,
11
- channel12,
12
12
  channelUser1,
13
13
  channelQueryResponse,
14
14
  channelQueryResponsePage2,
@@ -53,7 +53,10 @@ describe('liveChannels', () => {
53
53
 
54
54
  expect(callback).toHaveBeenCalledTimes(2);
55
55
 
56
- snapshot.data = channelQueryResponse.data.channels;
56
+ // cause we apply prepareChannelPayload on channel raw data from server
57
+ const payload = prepareChannelPayload(channelQueryResponse.data);
58
+
59
+ snapshot.data = payload.channels;
57
60
  snapshot.loading = false;
58
61
 
59
62
  expect(callback).toHaveBeenCalledWith(expect.objectContaining(snapshot));
@@ -115,12 +118,12 @@ describe('liveChannels', () => {
115
118
  // 4 -> becuase 1 local & server call each per call (2)
116
119
  expect(callback).toHaveBeenCalledTimes(4);
117
120
 
121
+ const payload = prepareChannelPayload(channelQueryResponse.data);
122
+ const payload2 = prepareChannelPayload(channelQueryResponsePage2.data);
123
+
118
124
  const snapshot = getSnapshot();
119
125
  snapshot.loading = false;
120
- snapshot.data = [
121
- ...channelQueryResponsePage2.data.channels,
122
- ...channelQueryResponse.data.channels,
123
- ];
126
+ snapshot.data = [...payload2.channels, ...payload.channels];
124
127
 
125
128
  expect(callback).toHaveBeenNthCalledWith(4, expect.objectContaining(snapshot));
126
129
  });
@@ -153,19 +156,24 @@ describe('liveChannels', () => {
153
156
  files: [],
154
157
  });
155
158
 
159
+ const payload = prepareChannelPayload(channelQueryResponse.data);
160
+ const deletePayload = payload.channels.filter(
161
+ channel => channel.channelId !== channel11.channelId,
162
+ );
163
+
156
164
  snapshot.loading = false;
157
165
  // get data based on event
158
166
  switch (event) {
159
167
  case 'v3.channel.didCreate':
160
- snapshot.data = [channel, channel11, channel12];
168
+ snapshot.data = [channel, ...payload.channels];
161
169
  break;
162
170
 
163
171
  case 'v3.channel.didUpdate':
164
- snapshot.data = channelQueryResponse.data.channels;
172
+ snapshot.data = payload.channels;
165
173
  break;
166
174
 
167
175
  default:
168
- snapshot.data = [channel12];
176
+ snapshot.data = deletePayload;
169
177
  }
170
178
 
171
179
  expect(callback).toHaveBeenNthCalledWith(3, expect.objectContaining(snapshot));
@@ -18,7 +18,7 @@ export const isConnected = (): boolean => {
18
18
 
19
19
  return !!(
20
20
  client.userId &&
21
- client.http.defaults.headers.common?.Authorization?.length &&
21
+ String(client.http.defaults.headers.common?.Authorization)?.length &&
22
22
  client.ws.connected
23
23
  );
24
24
  };
@@ -17,3 +17,9 @@ export const filterByPropEquality = <T = Record<string, unknown>>(
17
17
  key: keyof T,
18
18
  value: any,
19
19
  ) => (value !== undefined ? collection.filter(item => item[key] === value) : collection);
20
+
21
+ export const filterByPropInclusion = <T = Record<string, unknown>>(
22
+ collection: T[],
23
+ key: keyof T,
24
+ value: any[] | undefined,
25
+ ) => (value !== undefined ? collection.filter(item => value.includes(item[key])) : collection);
@@ -129,18 +129,17 @@ export const queryOptions = (
129
129
  *
130
130
  * @hidden
131
131
  */
132
- const isEmpty = (local: any) => {
132
+ const isEmpty = (local: unknown) => {
133
133
  // if it's supposed to be a single object, it'd be undefined
134
134
  if (!local) return true;
135
135
 
136
136
  // it's a paged query, the 1st cell of the array would be empty
137
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
138
137
  if (isPaged(local) && isEmpty(local.data)) {
139
138
  return true;
140
139
  }
141
140
 
142
141
  // if it's a item collection, it'd have no keys
143
- if (!Object.keys(local).length) return true;
142
+ if (typeof local === 'object' && !Object.keys(local).length) return true;
144
143
 
145
144
  return false;
146
145
  };