stream-chat 9.16.0 → 9.18.0

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.
package/src/client.ts CHANGED
@@ -1404,7 +1404,11 @@ export class StreamChat {
1404
1404
  * @param {UserResponse} user
1405
1405
  * @param {boolean} hardDelete
1406
1406
  */
1407
- _deleteUserMessageReference = (user: UserResponse, hardDelete = false) => {
1407
+ _deleteUserMessageReference = (
1408
+ user: UserResponse,
1409
+ hardDelete = false,
1410
+ deletedAt?: LocalMessage['deleted_at'],
1411
+ ) => {
1408
1412
  const refMap = this.state.userChannelReferences[user.id] || {};
1409
1413
 
1410
1414
  for (const channelID in refMap) {
@@ -1413,7 +1417,7 @@ export class StreamChat {
1413
1417
  const state = channel.state;
1414
1418
 
1415
1419
  /** deleted the messages from this user. */
1416
- state?.deleteUserMessages(user, hardDelete);
1420
+ state?.deleteUserMessages(user, hardDelete, deletedAt);
1417
1421
  }
1418
1422
  }
1419
1423
  };
@@ -1478,7 +1482,11 @@ export class StreamChat {
1478
1482
  event.user.deleted_at &&
1479
1483
  (event.mark_messages_deleted || event.hard_delete)
1480
1484
  ) {
1481
- this._deleteUserMessageReference(event.user, event.hard_delete);
1485
+ this._deleteUserMessageReference(
1486
+ event.user,
1487
+ event.hard_delete,
1488
+ event.user.deleted_at ? new Date(event.user.deleted_at) : null,
1489
+ );
1482
1490
  }
1483
1491
  };
1484
1492
 
@@ -1503,6 +1511,14 @@ export class StreamChat {
1503
1511
  this._handleUserEvent(event);
1504
1512
  }
1505
1513
 
1514
+ if (event.type === 'user.messages.deleted' && !event.cid && event.user) {
1515
+ this._deleteUserMessageReference(
1516
+ event.user,
1517
+ event.hard_delete,
1518
+ event.created_at ? new Date(event.created_at) : null,
1519
+ );
1520
+ }
1521
+
1506
1522
  if (event.type === 'health.check' && event.me) {
1507
1523
  client.user = event.me;
1508
1524
  client.state.updateUser(event.me);
package/src/events.ts CHANGED
@@ -45,6 +45,7 @@ export const EVENT_MAP = {
45
45
  'typing.stop': true,
46
46
  'user.banned': true,
47
47
  'user.deleted': true,
48
+ 'user.messages.deleted': true,
48
49
  'user.presence.changed': true,
49
50
  'user.unbanned': true,
50
51
  'user.unread_message_reminder': true,
package/src/moderation.ts CHANGED
@@ -7,11 +7,16 @@ import type {
7
7
  ModerationConfig,
8
8
  ModerationFlagOptions,
9
9
  ModerationMuteOptions,
10
+ ModerationRule,
11
+ ModerationRuleRequest,
10
12
  MuteUserResponse,
11
13
  Pager,
12
14
  QueryConfigsResponse,
13
15
  QueryModerationConfigsFilters,
14
16
  QueryModerationConfigsSort,
17
+ QueryModerationRulesFilters,
18
+ QueryModerationRulesResponse,
19
+ QueryModerationRulesSort,
15
20
  RequireAtLeastOne,
16
21
  ReviewQueueFilters,
17
22
  ReviewQueueItem,
@@ -20,6 +25,7 @@ import type {
20
25
  ReviewQueueSort,
21
26
  SubmitActionOptions,
22
27
  UpsertConfigResponse,
28
+ UpsertModerationRuleResponse,
23
29
  } from './types';
24
30
  import type { StreamChat } from './client';
25
31
  import { normalizeQuerySort } from './utils';
@@ -388,4 +394,60 @@ export class Moderation {
388
394
  flags,
389
395
  );
390
396
  }
397
+
398
+ /**
399
+ * Create or update a moderation rule
400
+ * @param {ModerationRuleRequest} rule Rule configuration to be upserted
401
+ * @returns
402
+ */
403
+ async upsertModerationRule(rule: ModerationRuleRequest) {
404
+ return await this.client.post<UpsertModerationRuleResponse>(
405
+ this.client.baseURL + '/api/v2/moderation/moderation_rule',
406
+ rule,
407
+ );
408
+ }
409
+
410
+ /**
411
+ * Query moderation rules
412
+ * @param {QueryModerationRulesFilters} filterConditions Filter conditions for querying moderation rules
413
+ * @param {QueryModerationRulesSort} sort Sort conditions for querying moderation rules
414
+ * @param {Pager} options Pagination options for querying moderation rules
415
+ * @returns
416
+ */
417
+ async queryModerationRules(
418
+ filterConditions: QueryModerationRulesFilters = {},
419
+ sort: QueryModerationRulesSort = [],
420
+ options: Pager = {},
421
+ ) {
422
+ return await this.client.post<QueryModerationRulesResponse>(
423
+ this.client.baseURL + '/api/v2/moderation/moderation_rules',
424
+ {
425
+ filter: filterConditions,
426
+ sort,
427
+ ...options,
428
+ },
429
+ );
430
+ }
431
+
432
+ /**
433
+ * Get a specific moderation rule by ID
434
+ * @param {string} id ID of the moderation rule to fetch
435
+ * @returns
436
+ */
437
+ async getModerationRule(id: string) {
438
+ return await this.client.get<{ rule: ModerationRule }>(
439
+ this.client.baseURL + '/api/v2/moderation/moderation_rule/' + id,
440
+ );
441
+ }
442
+
443
+ /**
444
+ * Delete a moderation rule by ID
445
+ * @param {string} id ID of the moderation rule to delete
446
+ * @returns
447
+ */
448
+ async deleteModerationRule(id: string) {
449
+ return await this.client.delete(
450
+ this.client.baseURL + '/api/v2/moderation/moderation_rule/' + id,
451
+ );
452
+ }
391
453
  }
@@ -0,0 +1,104 @@
1
+ import { StateStore } from '../store';
2
+ import type { ArrayOneOrMore, ArrayTwoOrMore, QueryFilter } from '../types';
3
+
4
+ type ElementType<T> = T extends (infer U)[] ? U : T;
5
+
6
+ // redeclared because QueryFilter does not account for the additional operators
7
+ export type ExtendedQueryFilter<T = string> = QueryFilter<T> & {
8
+ $autocomplete?: T extends string ? string : never;
9
+ $contains?: ElementType<T>;
10
+ $in?: ElementType<T>[];
11
+ $q?: T extends string ? string : never;
12
+ };
13
+
14
+ export type ExtendedQueryLogicalOperators<T> = {
15
+ $and?: ArrayOneOrMore<ExtendedQueryFilters<T>>;
16
+ $nor?: ArrayOneOrMore<ExtendedQueryFilters<T>>;
17
+ $or?: ArrayTwoOrMore<ExtendedQueryFilters<T>>;
18
+ };
19
+
20
+ export type ExtendedQueryFilters<T> = {
21
+ [K in keyof T]?: ExtendedQueryFilter<T[K]>;
22
+ } & ExtendedQueryLogicalOperators<T>;
23
+
24
+ export type FilterBuilderGenerators<
25
+ TFilters,
26
+ TContext extends Record<string, unknown> = {},
27
+ > = {
28
+ [K in string]: {
29
+ enabled: boolean;
30
+ generate: (context: TContext) => Partial<TFilters> | null;
31
+ };
32
+ };
33
+
34
+ export type FilterBuilderOptions<TFilters, TContext extends Record<string, unknown>> = {
35
+ initialFilterConfig?: FilterBuilderGenerators<TFilters, TContext>;
36
+ initialContext?: TContext;
37
+ };
38
+
39
+ export class FilterBuilder<TFilters, TContext extends Record<string, unknown> = {}> {
40
+ filterConfig: StateStore<FilterBuilderGenerators<TFilters, TContext>>;
41
+ context: StateStore<TContext>;
42
+
43
+ constructor(params?: FilterBuilderOptions<TFilters, TContext>) {
44
+ this.context = new StateStore(params?.initialContext ?? ({} as TContext));
45
+ this.filterConfig = new StateStore(
46
+ params?.initialFilterConfig ?? ({} as FilterBuilderGenerators<TFilters, TContext>),
47
+ );
48
+ }
49
+
50
+ updateFilterConfig(config: Partial<FilterBuilderGenerators<TFilters, TContext>>) {
51
+ this.filterConfig.partialNext(config);
52
+ }
53
+
54
+ enableFilter(filterKey: keyof FilterBuilderGenerators<TFilters, TContext>) {
55
+ const config = this.filterConfig.getLatestValue();
56
+ if (config[filterKey]) {
57
+ this.filterConfig.partialNext({
58
+ [filterKey]: {
59
+ ...config[filterKey],
60
+ enabled: true,
61
+ },
62
+ });
63
+ }
64
+ }
65
+
66
+ disableFilter(filterKey: keyof FilterBuilderGenerators<TFilters, TContext>) {
67
+ const config = this.filterConfig.getLatestValue();
68
+ if (config[filterKey]) {
69
+ this.filterConfig.partialNext({
70
+ [filterKey]: {
71
+ ...config[filterKey],
72
+ enabled: false,
73
+ },
74
+ });
75
+ }
76
+ }
77
+
78
+ updateContext(newContext: Partial<TContext>) {
79
+ this.context.partialNext(newContext);
80
+ }
81
+
82
+ buildFilters(params?: {
83
+ context?: Partial<TContext>;
84
+ baseFilters?: Partial<TFilters>;
85
+ }): Partial<TFilters> {
86
+ const filters: Partial<TFilters> = {
87
+ ...(params?.baseFilters ?? {}),
88
+ } as Partial<TFilters>;
89
+
90
+ const filterConfig = this.filterConfig.getLatestValue();
91
+ for (const key in filterConfig) {
92
+ const configItem = filterConfig[key];
93
+ if (!configItem?.enabled) continue;
94
+
95
+ const generated = configItem.generate({
96
+ ...this.context.getLatestValue(),
97
+ ...(params?.context ?? {}),
98
+ });
99
+ if (generated) Object.assign(filters, generated);
100
+ }
101
+
102
+ return filters;
103
+ }
104
+ }
@@ -1,2 +1,3 @@
1
1
  export * from './BasePaginator';
2
+ export * from './FilterBuilder';
2
3
  export * from './ReminderPaginator';
@@ -59,7 +59,7 @@ const DEFAULT_SEARCH_SOURCE_OPTIONS: Required<SearchSourceOptions> = {
59
59
 
60
60
  abstract class BaseSearchSourceBase<T> implements ISearchSource<T> {
61
61
  state: StateStore<SearchSourceState<T>>;
62
- protected pageSize: number;
62
+ pageSize: number;
63
63
  abstract readonly type: SearchSourceType;
64
64
 
65
65
  protected constructor(options?: SearchSourceOptions) {
@@ -1,27 +1,66 @@
1
1
  import { BaseSearchSource } from './BaseSearchSource';
2
+ import type { FilterBuilderOptions } from '../pagination';
3
+ import { FilterBuilder } from '../pagination';
2
4
  import type { Channel } from '../channel';
3
5
  import type { StreamChat } from '../client';
4
6
  import type { ChannelFilters, ChannelOptions, ChannelSort } from '../types';
5
7
  import type { SearchSourceOptions } from './types';
6
8
 
7
- export class ChannelSearchSource extends BaseSearchSource<Channel> {
9
+ type CustomContext = Record<string, unknown>;
10
+
11
+ export type ChannelSearchSourceFilterBuilderContext<
12
+ C extends CustomContext = CustomContext,
13
+ > = { searchQuery?: string } & C;
14
+
15
+ export class ChannelSearchSource<
16
+ TFilterContext extends CustomContext = CustomContext,
17
+ > extends BaseSearchSource<Channel> {
8
18
  readonly type = 'channels';
9
- private client: StreamChat;
19
+ client: StreamChat;
10
20
  filters: ChannelFilters | undefined;
11
21
  sort: ChannelSort | undefined;
12
22
  searchOptions: Omit<ChannelOptions, 'limit' | 'offset'> | undefined;
23
+ filterBuilder: FilterBuilder<
24
+ ChannelFilters,
25
+ ChannelSearchSourceFilterBuilderContext<TFilterContext>
26
+ >;
13
27
 
14
- constructor(client: StreamChat, options?: SearchSourceOptions) {
28
+ constructor(
29
+ client: StreamChat,
30
+ options?: SearchSourceOptions,
31
+ filterBuilderOptions: FilterBuilderOptions<
32
+ ChannelFilters,
33
+ ChannelSearchSourceFilterBuilderContext<TFilterContext>
34
+ > = {},
35
+ ) {
15
36
  super(options);
16
37
  this.client = client;
38
+ this.filterBuilder = new FilterBuilder<
39
+ ChannelFilters,
40
+ ChannelSearchSourceFilterBuilderContext<TFilterContext>
41
+ >({
42
+ ...filterBuilderOptions,
43
+ initialFilterConfig: {
44
+ name: {
45
+ enabled: true,
46
+ generate: ({ searchQuery }) =>
47
+ searchQuery ? { name: { $autocomplete: searchQuery } } : null,
48
+ },
49
+ ...filterBuilderOptions.initialFilterConfig,
50
+ },
51
+ });
17
52
  }
18
53
 
19
54
  protected async query(searchQuery: string) {
20
- const filters = {
21
- members: { $in: [this.client.userID] },
22
- name: { $autocomplete: searchQuery },
23
- ...this.filters,
24
- } as ChannelFilters;
55
+ const filters = this.filterBuilder.buildFilters({
56
+ baseFilters: {
57
+ ...(this.client.userID ? { members: { $in: [this.client.userID] } } : {}),
58
+ ...this.filters,
59
+ },
60
+ context: { searchQuery } as Partial<
61
+ ChannelSearchSourceFilterBuilderContext<TFilterContext>
62
+ >,
63
+ });
25
64
  const sort = this.sort ?? {};
26
65
  const options = { ...this.searchOptions, limit: this.pageSize, offset: this.offset };
27
66
  const items = await this.client.queryChannels(filters, sort, options);
@@ -10,46 +10,161 @@ import type {
10
10
  } from '../types';
11
11
  import type { StreamChat } from '../client';
12
12
  import type { SearchSourceOptions } from './types';
13
+ import { FilterBuilder, type FilterBuilderOptions } from '../pagination';
13
14
 
14
- export class MessageSearchSource extends BaseSearchSource<MessageResponse> {
15
+ type CustomContext = Record<string, unknown>;
16
+
17
+ // Built-in contexts per builder
18
+ type BuiltInContexts = {
19
+ messageSearchChannel: { searchQuery?: string };
20
+ messageSearch: { searchQuery?: string };
21
+ channelQuery: { cids?: string[] };
22
+ };
23
+
24
+ // Merge Built-in with user-provided Custom context
25
+ type MergeContext<
26
+ B extends Record<string, unknown>,
27
+ C extends CustomContext | undefined,
28
+ > = B & (C extends object ? C : {});
29
+
30
+ // User can provide custom context for each builder
31
+ type MessageSearchSourceContexts = Partial<{
32
+ messageSearchChannelContext: Record<string, unknown>;
33
+ messageSearchContext: Record<string, unknown>;
34
+ channelQueryContext: Record<string, unknown>;
35
+ }>;
36
+
37
+ export type MessageSearchSourceFilterBuilderOptions<
38
+ TContexts extends MessageSearchSourceContexts = {},
39
+ > = Partial<{
40
+ messageSearchChannel: FilterBuilderOptions<
41
+ ChannelFilters,
42
+ MergeContext<
43
+ BuiltInContexts['messageSearchChannel'],
44
+ TContexts['messageSearchChannelContext']
45
+ >
46
+ >;
47
+ messageSearch: FilterBuilderOptions<
48
+ MessageFilters,
49
+ MergeContext<BuiltInContexts['messageSearch'], TContexts['messageSearchContext']>
50
+ >;
51
+ channelQuery: FilterBuilderOptions<
52
+ ChannelFilters,
53
+ MergeContext<BuiltInContexts['channelQuery'], TContexts['channelQueryContext']>
54
+ >;
55
+ }>;
56
+
57
+ export class MessageSearchSource<
58
+ TContexts extends MessageSearchSourceContexts = {},
59
+ > extends BaseSearchSource<MessageResponse> {
15
60
  readonly type = 'messages';
16
61
  private client: StreamChat;
62
+
17
63
  messageSearchChannelFilters: ChannelFilters | undefined;
18
64
  messageSearchFilters: MessageFilters | undefined;
19
65
  messageSearchSort: SearchMessageSort | undefined;
66
+
20
67
  channelQueryFilters: ChannelFilters | undefined;
21
68
  channelQuerySort: ChannelSort | undefined;
22
69
  channelQueryOptions: Omit<ChannelOptions, 'limit' | 'offset'> | undefined;
23
70
 
24
- constructor(client: StreamChat, options?: SearchSourceOptions) {
71
+ messageSearchChannelFilterBuilder: FilterBuilder<
72
+ ChannelFilters,
73
+ MergeContext<
74
+ BuiltInContexts['messageSearchChannel'],
75
+ TContexts['messageSearchChannelContext']
76
+ >
77
+ >;
78
+ messageSearchFilterBuilder: FilterBuilder<
79
+ MessageFilters,
80
+ MergeContext<BuiltInContexts['messageSearch'], TContexts['messageSearchContext']>
81
+ >;
82
+ channelQueryFilterBuilder: FilterBuilder<
83
+ ChannelFilters,
84
+ MergeContext<BuiltInContexts['channelQuery'], TContexts['channelQueryContext']>
85
+ >;
86
+
87
+ constructor(
88
+ client: StreamChat,
89
+ options?: SearchSourceOptions,
90
+ filterBuilderOptions?: MessageSearchSourceFilterBuilderOptions<TContexts>,
91
+ ) {
25
92
  super(options);
26
93
  this.client = client;
94
+
95
+ this.messageSearchChannelFilterBuilder = new FilterBuilder<
96
+ ChannelFilters,
97
+ MergeContext<
98
+ BuiltInContexts['messageSearchChannel'],
99
+ TContexts['messageSearchChannelContext']
100
+ >
101
+ >(filterBuilderOptions?.messageSearchChannel);
102
+
103
+ this.messageSearchFilterBuilder = new FilterBuilder<
104
+ MessageFilters,
105
+ MergeContext<BuiltInContexts['messageSearch'], TContexts['messageSearchContext']>
106
+ >({
107
+ ...filterBuilderOptions?.messageSearch,
108
+ initialFilterConfig: {
109
+ text: {
110
+ enabled: true,
111
+ generate: ({ searchQuery }) => (searchQuery ? { text: searchQuery } : null),
112
+ },
113
+ ...filterBuilderOptions?.messageSearch?.initialFilterConfig,
114
+ },
115
+ });
116
+
117
+ this.channelQueryFilterBuilder = new FilterBuilder<
118
+ ChannelFilters,
119
+ MergeContext<BuiltInContexts['channelQuery'], TContexts['channelQueryContext']>
120
+ >({
121
+ ...filterBuilderOptions?.channelQuery,
122
+ initialFilterConfig: {
123
+ cid: {
124
+ enabled: true,
125
+ generate: ({ cids }) => (cids ? { cid: { $in: cids } } : null),
126
+ },
127
+ ...filterBuilderOptions?.channelQuery?.initialFilterConfig,
128
+ },
129
+ });
27
130
  }
28
131
 
29
132
  protected async query(searchQuery: string) {
30
- if (!this.client.userID) return { items: [] };
133
+ if (!this.client.userID || !searchQuery || this.next === null) return { items: [] };
31
134
 
32
- const channelFilters: ChannelFilters = {
33
- members: { $in: [this.client.userID] },
34
- ...this.messageSearchChannelFilters,
35
- } as ChannelFilters;
135
+ const channelFilters = this.messageSearchChannelFilterBuilder.buildFilters({
136
+ baseFilters: {
137
+ ...(this.client.userID ? { members: { $in: [this.client.userID] } } : {}),
138
+ ...this.messageSearchChannelFilters,
139
+ },
140
+ context: { searchQuery } as Partial<
141
+ MergeContext<
142
+ BuiltInContexts['messageSearchChannel'],
143
+ TContexts['messageSearchChannelContext']
144
+ >
145
+ >,
146
+ });
36
147
 
37
- const messageFilters: MessageFilters = {
38
- text: searchQuery,
39
- type: 'regular', // FIXME: type: 'reply' resp. do not filter by type and allow to jump to a message in a thread - missing support
40
- ...this.messageSearchFilters,
41
- } as MessageFilters;
148
+ const messageFilters: MessageFilters = this.messageSearchFilterBuilder.buildFilters({
149
+ baseFilters: {
150
+ type: 'regular',
151
+ ...this.messageSearchFilters,
152
+ },
153
+ context: { searchQuery } as Partial<
154
+ MergeContext<BuiltInContexts['messageSearch'], TContexts['messageSearchContext']>
155
+ >,
156
+ });
42
157
 
43
158
  const sort: SearchMessageSort = {
44
159
  created_at: -1,
45
160
  ...this.messageSearchSort,
46
161
  };
47
162
 
48
- const options = {
163
+ const options: SearchOptions = {
49
164
  limit: this.pageSize,
50
165
  next: this.next,
51
166
  sort,
52
- } as SearchOptions;
167
+ };
53
168
 
54
169
  const { next, results } = await this.client.search(
55
170
  channelFilters,
@@ -62,15 +177,18 @@ export class MessageSearchSource extends BaseSearchSource<MessageResponse> {
62
177
  items.reduce((acc, message) => {
63
178
  if (message.cid && !this.client.activeChannels[message.cid]) acc.add(message.cid);
64
179
  return acc;
65
- }, new Set<string>()), // keep the cids unique
180
+ }, new Set<string>()),
66
181
  );
67
- const allChannelsLoadedLocally = cids.length === 0;
68
- if (!allChannelsLoadedLocally) {
182
+
183
+ if (cids.length > 0) {
184
+ const channelQueryFilters = this.channelQueryFilterBuilder.buildFilters({
185
+ baseFilters: this.channelQueryFilters,
186
+ context: { cids } as Partial<
187
+ MergeContext<BuiltInContexts['channelQuery'], TContexts['channelQueryContext']>
188
+ >,
189
+ });
69
190
  await this.client.queryChannels(
70
- {
71
- cid: { $in: cids },
72
- ...this.channelQueryFilters,
73
- } as ChannelFilters,
191
+ channelQueryFilters,
74
192
  {
75
193
  last_message_at: -1,
76
194
  ...this.channelQuerySort,
@@ -1,28 +1,65 @@
1
1
  import { BaseSearchSource } from './BaseSearchSource';
2
+ import { FilterBuilder, type FilterBuilderOptions } from '../pagination';
2
3
  import type { StreamChat } from '../client';
3
4
  import type { UserFilters, UserOptions, UserResponse, UserSort } from '../types';
4
5
  import type { SearchSourceOptions } from './types';
5
6
 
6
- export class UserSearchSource extends BaseSearchSource<UserResponse> {
7
+ type CustomContext = Record<string, unknown>;
8
+
9
+ export type UserSearchSourceFilterBuilderContext<
10
+ C extends CustomContext = CustomContext,
11
+ > = { searchQuery?: string } & C;
12
+
13
+ export class UserSearchSource<
14
+ TFilterContext extends CustomContext = CustomContext,
15
+ > extends BaseSearchSource<UserResponse> {
7
16
  readonly type = 'users';
8
- private client: StreamChat;
17
+ client: StreamChat;
9
18
  filters: UserFilters | undefined;
10
19
  sort: UserSort | undefined;
11
20
  searchOptions: Omit<UserOptions, 'limit' | 'offset'> | undefined;
21
+ filterBuilder: FilterBuilder<
22
+ UserFilters,
23
+ UserSearchSourceFilterBuilderContext<TFilterContext>
24
+ >;
12
25
 
13
- constructor(client: StreamChat, options?: SearchSourceOptions) {
26
+ constructor(
27
+ client: StreamChat,
28
+ options?: SearchSourceOptions,
29
+ filterBuilderOptions: FilterBuilderOptions<
30
+ UserFilters,
31
+ UserSearchSourceFilterBuilderContext<TFilterContext>
32
+ > = {},
33
+ ) {
14
34
  super(options);
15
35
  this.client = client;
36
+ this.filterBuilder = new FilterBuilder<
37
+ UserFilters,
38
+ UserSearchSourceFilterBuilderContext<TFilterContext>
39
+ >({
40
+ initialFilterConfig: {
41
+ $or: {
42
+ enabled: true,
43
+ generate: ({ searchQuery }) =>
44
+ searchQuery
45
+ ? {
46
+ $or: [
47
+ { id: { $autocomplete: searchQuery } },
48
+ { name: { $autocomplete: searchQuery } },
49
+ ],
50
+ }
51
+ : null,
52
+ },
53
+ },
54
+ ...filterBuilderOptions,
55
+ });
16
56
  }
17
57
 
18
58
  protected async query(searchQuery: string) {
19
- const filters = {
20
- $or: [
21
- { id: { $autocomplete: searchQuery } },
22
- { name: { $autocomplete: searchQuery } },
23
- ],
24
- ...this.filters,
25
- } as UserFilters;
59
+ const filters = this.filterBuilder.buildFilters({
60
+ baseFilters: this.filters,
61
+ context: { searchQuery } as UserSearchSourceFilterBuilderContext<TFilterContext>,
62
+ });
26
63
  const sort = { id: 1, ...this.sort } as UserSort;
27
64
  const options = { ...this.searchOptions, limit: this.pageSize, offset: this.offset };
28
65
  const { users } = await this.client.queryUsers(filters, sort, options);
@@ -1,6 +1,6 @@
1
1
  export * from './BaseSearchSource';
2
2
  export * from './SearchController';
3
- export { UserSearchSource } from './UserSearchSource';
4
- export { ChannelSearchSource } from './ChannelSearchSource';
5
- export { MessageSearchSource } from './MessageSearchSource';
3
+ export * from './UserSearchSource';
4
+ export * from './ChannelSearchSource';
5
+ export * from './MessageSearchSource';
6
6
  export * from './types';