stream-chat 9.44.0 → 9.44.2

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.
@@ -1,4 +1,4 @@
1
- import type { StreamChat } from './client';
1
+ import type { QueryChannelsResponseWithChannels, StreamChat } from './client';
2
2
  import type { ChannelFilters, ChannelOptions, ChannelSort, ChannelStateOptions, Event } from './types';
3
3
  import type { ValueOrPatch } from './store';
4
4
  import { StateStore } from './store';
@@ -10,6 +10,8 @@ export type ChannelManagerPagination = {
10
10
  isLoading: boolean;
11
11
  isLoadingNext: boolean;
12
12
  options: ChannelOptions;
13
+ responseFilters?: ChannelFilters;
14
+ responseSort?: ChannelSort;
13
15
  sort: ChannelSort;
14
16
  };
15
17
  export type ChannelManagerState = {
@@ -64,7 +66,8 @@ export type ChannelManagerOptions = {
64
66
  */
65
67
  lockChannelOrder?: boolean;
66
68
  };
67
- export type QueryChannelsRequestType = (...params: Parameters<StreamChat['queryChannels']>) => Promise<Channel[]>;
69
+ export type QueryChannelsRequestOutput = Channel[] | QueryChannelsResponseWithChannels;
70
+ export type QueryChannelsRequestType = (filters: ChannelFilters, sort?: ChannelSort, options?: ChannelOptions, stateOptions?: ChannelStateOptions) => Promise<QueryChannelsRequestOutput>;
68
71
  export declare const DEFAULT_CHANNEL_MANAGER_OPTIONS: {
69
72
  abortInFlightQuery: boolean;
70
73
  allowNotLoadedChannelPromotionForEvent: {
@@ -8,7 +8,7 @@ import { WSConnectionFallback } from './connection_fallback';
8
8
  import { Campaign } from './campaign';
9
9
  import { ChannelBatchUpdater } from './channel_batch_updater';
10
10
  import { Segment } from './segment';
11
- import type { ActiveLiveLocationsAPIResponse, APIErrorResponse, APIResponse, AppSettings, AppSettingsAPIResponse, BannedUsersFilters, BannedUsersPaginationOptions, BannedUsersResponse, BannedUsersSort, BanUserOptions, BaseDeviceFields, BlockList, BlockListResponse, BlockUserAPIResponse, CampaignData, CampaignFilters, CampaignQueryOptions, CampaignResponse, CampaignSort, CastVoteAPIResponse, ChannelAPIResponse, ChannelData, ChannelFilters, ChannelMute, ChannelOptions, ChannelResponse, ChannelSort, ChannelStateOptions, CheckPushResponse, CheckSNSResponse, CheckSQSResponse, Configs, ConnectAPIResponse, CreateChannelOptions, CreateChannelResponse, CreateCommandOptions, CreateCommandResponse, CreateImportOptions, CreateImportResponse, CreateImportURLResponse, CreatePollAPIResponse, CreatePollData, CreatePollOptionAPIResponse, CreatePredefinedFilterOptions, CreateReminderOptions, CustomPermissionOptions, DeactivateUsersOptions, DeleteCommandResponse, DeleteMessageOptions, DeleteUserOptions, Device, DeviceIdentifier, DraftFilters, DraftSort, EndpointName, Event, EventAPIResponse, EventHandler, ExportChannelOptions, ExportChannelRequest, ExportChannelResponse, ExportChannelStatusResponse, ExportUsersRequest, ExportUsersResponse, FlagMessageResponse, FlagReportsFilters, FlagReportsPaginationOptions, FlagReportsResponse, FlagsFilters, FlagsPaginationOptions, FlagsResponse, FlagUserResponse, FutureChannelBansResponse, GetBlockedUsersAPIResponse, GetCampaignOptions, GetChannelTypeResponse, GetCommandResponse, GetHookEventsResponse, GetImportResponse, GetMessageOptions, GetPollAPIResponse, GetRateLimitsResponse, GetRetentionPolicyResponse, GetRetentionPolicyRunsOptions, GetRetentionPolicyRunsResponse, GetThreadAPIResponse, GetThreadOptions, GetUnreadCountAPIResponse, GetUnreadCountBatchAPIResponse, ListChannelResponse, ListCommandsResponse, ListImportsPaginationOptions, ListImportsResponse, ListPredefinedFiltersOptions, ListPredefinedFiltersResponse, LocalMessage, Logger, MarkChannelsReadOptions, MarkDeliveredOptions, MessageFilters, MessageFlagsFilters, MessageFlagsPaginationOptions, MessageFlagsResponse, MessageResponse, Mute, MuteUserOptions, MuteUserResponse, OGAttachment, OwnUserResponse, Pager, PartialMessageUpdate, PartialPollUpdate, PartialThreadUpdate, PartialUserUpdate, PermissionAPIResponse, PermissionsAPIResponse, PollAnswersAPIResponse, PollData, PollOptionData, PollSort, PollVote, PollVoteData, PollVotesAPIResponse, PredefinedFilterResponse, Product, PushPreference, PushProvider, PushProviderConfig, PushProviderID, PushProviderListResponse, PushProviderUpsertResponse, QueryDraftsResponse, QueryFutureChannelBansOptions, QueryMessageHistoryFilters, QueryMessageHistoryOptions, QueryMessageHistoryResponse, QueryMessageHistorySort, QueryPollsFilters, QueryPollsOptions, QueryPollsResponse, QueryReactionsAPIResponse, QueryReactionsOptions, QueryRemindersOptions, QueryRemindersResponse, QuerySegmentsOptions, QuerySegmentTargetsFilter, QueryTeamUsageStatsOptions, QueryTeamUsageStatsResponse, QueryThreadsOptions, QueryVotesFilters, QueryVotesOptions, ReactionFilters, ReactionResponse, ReactionSort, ReactivateUserOptions, ReactivateUsersOptions, ReminderAPIResponse, ReviewFlagReportOptions, ReviewFlagReportResponse, SdkIdentifier, SearchAPIResponse, SearchOptions, SegmentData, SegmentResponse, SegmentTargetsResponse, SegmentType, SendFileAPIResponse, SetRetentionPolicyResponse, SharedLocationResponse, SortParam, StreamChatOptions, SyncOptions, SyncResponse, TaskResponse, TaskStatus, TestPushDataInput, TestSNSDataInput, TestSQSDataInput, TokenOrProvider, TranslateResponse, UnBanUserOptions, UpdateChannelsBatchOptions, UpdateChannelTypeRequest, UpdateChannelTypeResponse, UpdateCommandOptions, UpdateCommandResponse, UpdateLocationPayload, UpdateMessageAPIResponse, UpdateMessageOptions, UpdatePollAPIResponse, UpdatePredefinedFilterOptions, UpdateReminderOptions, UpdateSegmentData, UpdateUsersAPIResponse, UpsertPushPreferencesResponse, UserCustomEvent, UserFilters, UserOptions, UserResponse, UserSort, VoteSort } from './types';
11
+ import type { ActiveLiveLocationsAPIResponse, APIErrorResponse, APIResponse, AppSettings, AppSettingsAPIResponse, BannedUsersFilters, BannedUsersPaginationOptions, BannedUsersResponse, BannedUsersSort, BanUserOptions, BaseDeviceFields, BlockList, BlockListResponse, BlockUserAPIResponse, CampaignData, CampaignFilters, CampaignQueryOptions, CampaignResponse, CampaignSort, CastVoteAPIResponse, ChannelAPIResponse, ChannelData, ChannelFilters, ChannelMute, ChannelOptions, ChannelResponse, ChannelSort, ChannelStateOptions, CheckPushResponse, CheckSNSResponse, CheckSQSResponse, Configs, ConnectAPIResponse, CreateChannelOptions, CreateChannelResponse, CreateCommandOptions, CreateCommandResponse, CreateImportOptions, CreateImportResponse, CreateImportURLResponse, CreatePollAPIResponse, CreatePollData, CreatePollOptionAPIResponse, CreatePredefinedFilterOptions, CreateReminderOptions, CustomPermissionOptions, DeactivateUsersOptions, DeleteCommandResponse, DeleteMessageOptions, DeleteUserOptions, Device, DeviceIdentifier, DraftFilters, DraftSort, EndpointName, Event, EventAPIResponse, EventHandler, ExportChannelOptions, ExportChannelRequest, ExportChannelResponse, ExportChannelStatusResponse, ExportUsersRequest, ExportUsersResponse, FlagMessageResponse, FlagReportsFilters, FlagReportsPaginationOptions, FlagReportsResponse, FlagsFilters, FlagsPaginationOptions, FlagsResponse, FlagUserResponse, FutureChannelBansResponse, GetBlockedUsersAPIResponse, GetCampaignOptions, GetChannelTypeResponse, GetCommandResponse, GetHookEventsResponse, GetImportResponse, GetMessageOptions, GetPollAPIResponse, GetRateLimitsResponse, GetRetentionPolicyResponse, GetRetentionPolicyRunsOptions, GetRetentionPolicyRunsResponse, GetThreadAPIResponse, GetThreadOptions, GetUnreadCountAPIResponse, GetUnreadCountBatchAPIResponse, ListChannelResponse, ListCommandsResponse, ListImportsPaginationOptions, ListImportsResponse, ListPredefinedFiltersOptions, ListPredefinedFiltersResponse, LocalMessage, Logger, MarkChannelsReadOptions, MarkDeliveredOptions, MessageFilters, MessageFlagsFilters, MessageFlagsPaginationOptions, MessageFlagsResponse, MessageResponse, Mute, MuteUserOptions, MuteUserResponse, OGAttachment, OwnUserResponse, Pager, PartialMessageUpdate, PartialPollUpdate, PartialThreadUpdate, PartialUserUpdate, PermissionAPIResponse, PermissionsAPIResponse, PollAnswersAPIResponse, PollData, PollOptionData, PollSort, PollVote, PollVoteData, PollVotesAPIResponse, PredefinedFilterResponse, Product, PushPreference, PushProvider, PushProviderConfig, PushProviderID, PushProviderListResponse, PushProviderUpsertResponse, QueryChannelsAPIResponse, QueryDraftsResponse, QueryFutureChannelBansOptions, QueryMessageHistoryFilters, QueryMessageHistoryOptions, QueryMessageHistoryResponse, QueryMessageHistorySort, QueryPollsFilters, QueryPollsOptions, QueryPollsResponse, QueryReactionsAPIResponse, QueryReactionsOptions, QueryRemindersOptions, QueryRemindersResponse, QuerySegmentsOptions, QuerySegmentTargetsFilter, QueryTeamUsageStatsOptions, QueryTeamUsageStatsResponse, QueryThreadsOptions, QueryVotesFilters, QueryVotesOptions, ReactionFilters, ReactionResponse, ReactionSort, ReactivateUserOptions, ReactivateUsersOptions, ReminderAPIResponse, ReviewFlagReportOptions, ReviewFlagReportResponse, SdkIdentifier, SearchAPIResponse, SearchOptions, SegmentData, SegmentResponse, SegmentTargetsResponse, SegmentType, SendFileAPIResponse, SetRetentionPolicyResponse, SharedLocationResponse, SortParam, StreamChatOptions, SyncOptions, SyncResponse, TaskResponse, TaskStatus, TestPushDataInput, TestSNSDataInput, TestSQSDataInput, TokenOrProvider, TranslateResponse, UnBanUserOptions, UpdateChannelsBatchOptions, UpdateChannelTypeRequest, UpdateChannelTypeResponse, UpdateCommandOptions, UpdateCommandResponse, UpdateLocationPayload, UpdateMessageAPIResponse, UpdateMessageOptions, UpdatePollAPIResponse, UpdatePredefinedFilterOptions, UpdateReminderOptions, UpdateSegmentData, UpdateUsersAPIResponse, UpsertPushPreferencesResponse, UserCustomEvent, UserFilters, UserOptions, UserResponse, UserSort, VoteSort } from './types';
12
12
  import { ErrorFromResponse } from './types';
13
13
  import { InsightMetrics } from './insights';
14
14
  import { Thread } from './thread';
@@ -24,6 +24,9 @@ import { StateStore } from './store';
24
24
  import type { MessageComposer } from './messageComposer';
25
25
  import type { AbstractOfflineDB } from './offline-support';
26
26
  type MessageComposerTearDownFunction = () => void;
27
+ export type QueryChannelsResponseWithChannels = Omit<QueryChannelsAPIResponse, 'channels'> & {
28
+ channels: Channel[];
29
+ };
27
30
  type MessageComposerSetupFunction = ({ composer, }: {
28
31
  composer: MessageComposer;
29
32
  }) => void | MessageComposerTearDownFunction;
@@ -513,7 +516,29 @@ export declare class StreamChat {
513
516
  */
514
517
  queryMessageFlags(filterConditions?: MessageFlagsFilters, options?: MessageFlagsPaginationOptions): Promise<MessageFlagsResponse>;
515
518
  /**
516
- * queryChannelsRequest - Queries channels and returns the raw response
519
+ * queryChannelsRequestWithResponse - Queries channels and returns the full API response
520
+ * including top-level metadata such as `predefined_filter`.
521
+ *
522
+ * This exists as a compatibility bridge, as changing `queryChannelsRequest()` to return
523
+ * `QueryChannelsAPIResponse` would be a breaking change because it currently returns
524
+ * only the channel list. In the next major release, the request/response APIs should
525
+ * be consolidated so callers can access the full response through the primary API.
526
+ *
527
+ * @param {ChannelFilters} filterConditions object MongoDB style filters. Can be empty object when using predefined_filter in options.
528
+ * @param {ChannelSort} [sort] Sort options, for instance {created_at: -1}.
529
+ * When using multiple fields, make sure you use array of objects to guarantee field order, for instance [{last_updated: -1}, {created_at: 1}]
530
+ * @param {ChannelOptions} [options] Options object. Can include predefined_filter, filter_values, and sort_values for using predefined filters.
531
+ *
532
+ * @return {Promise<QueryChannelsAPIResponse>} full search channels response
533
+ */
534
+ queryChannelsRequestWithResponse(filterConditions: ChannelFilters, sort?: ChannelSort, options?: ChannelOptions): Promise<QueryChannelsAPIResponse>;
535
+ /**
536
+ * queryChannelsRequest - Queries channels and returns the raw channel response list.
537
+ *
538
+ * This preserves the historical return shape for backwards compatibility. Use
539
+ * `queryChannelsRequestWithResponse()` when response level metadata such as
540
+ * `predefined_filter` is needed. In the next major release these APIs should be
541
+ * consolidated into a single full-response API.
517
542
  *
518
543
  * @param {ChannelFilters} filterConditions object MongoDB style filters. Can be empty object when using predefined_filter in options.
519
544
  * @param {ChannelSort} [sort] Sort options, for instance {created_at: -1}.
@@ -533,10 +558,14 @@ export declare class StreamChat {
533
558
  * @param {ChannelStateOptions} [stateOptions] State options object. These options will only be used for state management and won't be sent in the request.
534
559
  * - stateOptions.skipInitialization - Skips the initialization of the state for the channels matching the ids in the list.
535
560
  * - stateOptions.skipHydration - Skips returning the channels as instances of the Channel class and rather returns the raw query response.
561
+ * - stateOptions.withResponse - Returns the full query response with hydrated channels. This is a compatibility bridge for internal callers that need response-level metadata while the default return value remains `Channel[]`.
536
562
  *
537
563
  * @return {Promise<Array<Channel>>} search channels response
538
564
  */
539
- queryChannels(filterConditions: ChannelFilters, sort?: ChannelSort, options?: ChannelOptions, stateOptions?: ChannelStateOptions): Promise<Channel[]>;
565
+ queryChannels(filterConditions: ChannelFilters, sort: ChannelSort, options: ChannelOptions, stateOptions: ChannelStateOptions & {
566
+ withResponse: true;
567
+ }): Promise<QueryChannelsResponseWithChannels>;
568
+ queryChannels(filterConditions?: ChannelFilters, sort?: ChannelSort, options?: ChannelOptions, stateOptions?: ChannelStateOptions): Promise<Channel[]>;
540
569
  /**
541
570
  * queryReactions - Query reactions
542
571
  *
@@ -1,4 +1,4 @@
1
- import type { AppSettingsAPIResponse, ChannelAPIResponse, ChannelFilters, ChannelMemberResponse, ChannelResponse, ChannelSort, DraftResponse, LocalMessage, MessageResponse, PollResponse, ReactionFilters, ReactionResponse, ReactionSort, ReadResponse } from '../types';
1
+ import type { AppSettingsAPIResponse, ChannelAPIResponse, ChannelFilters, ChannelMemberResponse, ChannelOptions, ChannelResponse, ChannelSort, DraftResponse, LocalMessage, MessageResponse, PollResponse, ReactionFilters, ReactionResponse, ReactionSort, ReadResponse } from '../types';
2
2
  import type { Channel } from '../channel';
3
3
  import type { StreamChat } from '../client';
4
4
  export type PrepareBatchDBQueries = [string] | [string, Array<unknown> | Array<Array<unknown>>];
@@ -21,6 +21,8 @@ export type DBUpsertCidsForQueryType = {
21
21
  cids: string[];
22
22
  /** Optional filters for the channels. */
23
23
  filters?: ChannelFilters;
24
+ /** Optional full query options for the channels. */
25
+ options?: ChannelOptions;
24
26
  /** Whether to immediately execute the operation. */
25
27
  execute?: boolean;
26
28
  /** Optional sorting applied to the channels. */
@@ -145,6 +147,8 @@ export type DBGetChannelsForQueryType = {
145
147
  userId: string;
146
148
  /** Optional filters for channels. */
147
149
  filters?: ChannelFilters;
150
+ /** Optional full query options for channels. */
151
+ options?: ChannelOptions;
148
152
  /** Optional sorting for the channels. */
149
153
  sort?: ChannelSort;
150
154
  };
@@ -949,6 +949,15 @@ export type ChannelStateOptions = {
949
949
  offlineMode?: boolean;
950
950
  skipInitialization?: string[];
951
951
  skipHydration?: boolean;
952
+ /**
953
+ * Returns the full query response with hydrated channels from `queryChannels()`.
954
+ *
955
+ * This is a compatibility bridge for internal callers that need response level
956
+ * metadata such as `predefined_filter`. The default `queryChannels()` return value
957
+ * remains `Channel[]` to avoid a breaking change. This should be folded into a
958
+ * single full response API in the next major release.
959
+ */
960
+ withResponse?: boolean;
952
961
  };
953
962
  export type CreateChannelOptions = {
954
963
  automod?: ChannelConfigAutomod;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stream-chat",
3
- "version": "9.44.0",
3
+ "version": "9.44.2",
4
4
  "description": "JS SDK for the Stream Chat API",
5
5
  "homepage": "https://getstream.io/chat/",
6
6
  "author": {
@@ -1,10 +1,11 @@
1
- import type { StreamChat } from './client';
1
+ import type { QueryChannelsResponseWithChannels, StreamChat } from './client';
2
2
  import type {
3
3
  ChannelFilters,
4
4
  ChannelOptions,
5
5
  ChannelSort,
6
6
  ChannelStateOptions,
7
7
  Event,
8
+ QueryChannelsAPIResponse,
8
9
  } from './types';
9
10
  import type { ValueOrPatch } from './store';
10
11
  import { isPatch, StateStore } from './store';
@@ -34,6 +35,8 @@ export type ChannelManagerPagination = {
34
35
  isLoading: boolean;
35
36
  isLoadingNext: boolean;
36
37
  options: ChannelOptions;
38
+ responseFilters?: ChannelFilters;
39
+ responseSort?: ChannelSort;
37
40
  sort: ChannelSort;
38
41
  };
39
42
 
@@ -133,9 +136,14 @@ export type ChannelManagerOptions = {
133
136
  lockChannelOrder?: boolean;
134
137
  };
135
138
 
139
+ export type QueryChannelsRequestOutput = Channel[] | QueryChannelsResponseWithChannels;
140
+
136
141
  export type QueryChannelsRequestType = (
137
- ...params: Parameters<StreamChat['queryChannels']>
138
- ) => Promise<Channel[]>;
142
+ filters: ChannelFilters,
143
+ sort?: ChannelSort,
144
+ options?: ChannelOptions,
145
+ stateOptions?: ChannelStateOptions,
146
+ ) => Promise<QueryChannelsRequestOutput>;
139
147
 
140
148
  export const DEFAULT_CHANNEL_MANAGER_OPTIONS = {
141
149
  abortInFlightQuery: false,
@@ -152,6 +160,54 @@ export const DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS = {
152
160
  offset: 0,
153
161
  };
154
162
 
163
+ const mapPredefinedFilterSortToChannelSort = (
164
+ sort: NonNullable<QueryChannelsAPIResponse['predefined_filter']>['sort'],
165
+ ): ChannelSort =>
166
+ (sort ?? []).map(({ direction = 1, field }) => ({
167
+ [field]: direction,
168
+ })) as ChannelSort;
169
+
170
+ const getResponsePaginationParams = ({
171
+ queryChannelsResponse,
172
+ sort,
173
+ }: {
174
+ queryChannelsResponse?: Pick<QueryChannelsAPIResponse, 'predefined_filter'>;
175
+ sort: ChannelSort;
176
+ }): Pick<ChannelManagerPagination, 'responseFilters' | 'responseSort'> => {
177
+ const predefinedFilter = queryChannelsResponse?.predefined_filter;
178
+
179
+ if (!predefinedFilter) {
180
+ return {};
181
+ }
182
+
183
+ return {
184
+ responseFilters: predefinedFilter.filter as ChannelFilters,
185
+ responseSort:
186
+ predefinedFilter.sort !== undefined
187
+ ? mapPredefinedFilterSortToChannelSort(predefinedFilter.sort)
188
+ : sort,
189
+ };
190
+ };
191
+
192
+ const getResponseFiltersAndSort = (
193
+ pagination: ChannelManagerPagination,
194
+ ): Pick<ChannelManagerPagination, 'filters' | 'sort'> => ({
195
+ filters: pagination.responseFilters ?? pagination.filters,
196
+ sort: pagination.responseSort ?? pagination.sort,
197
+ });
198
+
199
+ const omitResponsePaginationParams = (pagination: ChannelManagerPagination) => {
200
+ const paginationWithoutResponseParams = { ...pagination };
201
+ delete paginationWithoutResponseParams.responseFilters;
202
+ delete paginationWithoutResponseParams.responseSort;
203
+
204
+ return paginationWithoutResponseParams;
205
+ };
206
+
207
+ const isQueryChannelsResponseWithChannels = (
208
+ response: QueryChannelsRequestOutput,
209
+ ): response is QueryChannelsResponseWithChannels => !Array.isArray(response);
210
+
155
211
  /**
156
212
  * A class that manages a list of channels and changes it based on configuration and WS events. The
157
213
  * list of channels is reactive as well as the pagination and it can be subscribed to for state updates.
@@ -231,13 +287,14 @@ export class ChannelManager extends WithSubscriptions {
231
287
  });
232
288
  const {
233
289
  channels,
234
- pagination: { filters, sort },
290
+ pagination: { filters, options, sort },
235
291
  } = this.state.getLatestValue();
236
292
  this.client.offlineDb?.executeQuerySafely(
237
293
  (db) =>
238
294
  db.upsertCidsForQuery({
239
295
  cids: channels.map((channel) => channel.cid),
240
296
  filters,
297
+ options,
241
298
  sort,
242
299
  }),
243
300
  { method: 'upsertCidsForQuery' },
@@ -278,23 +335,39 @@ export class ChannelManager extends WithSubscriptions {
278
335
  ...options,
279
336
  };
280
337
  try {
281
- const channels = await this.queryChannelsRequest(
338
+ const queryChannelsResponse = await this.queryChannelsRequest(
282
339
  filters,
283
340
  sort,
284
341
  options,
285
- stateOptions,
342
+ { ...stateOptions, withResponse: true },
286
343
  );
344
+ const channels = isQueryChannelsResponseWithChannels(queryChannelsResponse)
345
+ ? queryChannelsResponse.channels
346
+ : queryChannelsResponse;
287
347
  const newOffset = offset + (channels?.length ?? 0);
288
348
  const newOptions = { ...options, offset: newOffset };
289
349
  const { pagination } = this.state.getLatestValue();
350
+ const responsePaginationParams = getResponsePaginationParams({
351
+ queryChannelsResponse: isQueryChannelsResponseWithChannels(queryChannelsResponse)
352
+ ? queryChannelsResponse
353
+ : undefined,
354
+ sort,
355
+ });
356
+ const paginationWithoutResponseParams = omitResponsePaginationParams(pagination);
290
357
 
291
358
  this.state.partialNext({
292
359
  channels,
293
360
  pagination: {
294
- ...pagination,
361
+ // Drop response derived filter/sort from the previous query before applying
362
+ // the current response. Non predefined queries do not return this metadata,
363
+ // so keeping the old values would make later WS mutations use stale
364
+ // predefined filter semantics. Also the predefined_filter might change, producing
365
+ // a different combination as well so we always need to first clean up.
366
+ ...paginationWithoutResponseParams,
295
367
  hasNext: (channels?.length ?? 0) >= (limit ?? 1),
296
368
  isLoading: false,
297
369
  options: newOptions,
370
+ ...responsePaginationParams,
298
371
  },
299
372
  initialized: true,
300
373
  error: undefined,
@@ -304,6 +377,7 @@ export class ChannelManager extends WithSubscriptions {
304
377
  db.upsertCidsForQuery({
305
378
  cids: channels.map((channel) => channel.cid),
306
379
  filters: pagination.filters,
380
+ options,
307
381
  sort: pagination.sort,
308
382
  }),
309
383
  { method: 'upsertCidsForQuery' },
@@ -366,7 +440,7 @@ export class ChannelManager extends WithSubscriptions {
366
440
  this.state.next((currentState) => ({
367
441
  ...currentState,
368
442
  pagination: {
369
- ...currentState.pagination,
443
+ ...omitResponsePaginationParams(currentState.pagination),
370
444
  isLoading: true,
371
445
  isLoadingNext: false,
372
446
  filters,
@@ -381,6 +455,7 @@ export class ChannelManager extends WithSubscriptions {
381
455
  const channelsFromDB = await this.client.offlineDb.getChannelsForQuery({
382
456
  userId: this.client.user.id,
383
457
  filters,
458
+ options,
384
459
  sort,
385
460
  });
386
461
 
@@ -431,12 +506,15 @@ export class ChannelManager extends WithSubscriptions {
431
506
  this.state.partialNext({
432
507
  pagination: { ...pagination, isLoading: false, isLoadingNext: true },
433
508
  });
434
- const nextChannels = await this.queryChannelsRequest(
509
+ const queryChannelsResponse = await this.queryChannelsRequest(
435
510
  filters,
436
511
  sort,
437
512
  options,
438
513
  this.stateOptions,
439
514
  );
515
+ const nextChannels = isQueryChannelsResponseWithChannels(queryChannelsResponse)
516
+ ? queryChannelsResponse.channels
517
+ : queryChannelsResponse;
440
518
  const { channels } = this.state.getLatestValue();
441
519
  const newOffset = offset + (nextChannels?.length ?? 0);
442
520
  const newOptions = { ...options, offset: newOffset };
@@ -495,7 +573,7 @@ export class ChannelManager extends WithSubscriptions {
495
573
  return;
496
574
  }
497
575
 
498
- const { sort } = pagination ?? {};
576
+ const { sort } = getResponseFiltersAndSort(pagination);
499
577
 
500
578
  this.setChannels(
501
579
  promoteChannel({
@@ -532,7 +610,7 @@ export class ChannelManager extends WithSubscriptions {
532
610
  if (!channels) {
533
611
  return;
534
612
  }
535
- const { filters, sort } = pagination ?? {};
613
+ const { filters, sort } = getResponseFiltersAndSort(pagination);
536
614
 
537
615
  const channelType = event.channel_type;
538
616
  const channelId = event.channel_id;
@@ -591,7 +669,7 @@ export class ChannelManager extends WithSubscriptions {
591
669
  });
592
670
 
593
671
  const { channels, pagination } = this.state.getLatestValue();
594
- const { filters, sort } = pagination ?? {};
672
+ const { filters, sort } = getResponseFiltersAndSort(pagination);
595
673
 
596
674
  const considerArchivedChannels = shouldConsiderArchivedChannels(filters);
597
675
  const isTargetChannelArchived = isChannelArchived(channel);
@@ -628,7 +706,7 @@ export class ChannelManager extends WithSubscriptions {
628
706
  });
629
707
 
630
708
  const { channels, pagination } = this.state.getLatestValue();
631
- const { sort, filters } = pagination ?? {};
709
+ const { filters, sort } = getResponseFiltersAndSort(pagination);
632
710
 
633
711
  const considerArchivedChannels = shouldConsiderArchivedChannels(filters);
634
712
  const isTargetChannelArchived = isChannelArchived(channel);
@@ -655,7 +733,7 @@ export class ChannelManager extends WithSubscriptions {
655
733
 
656
734
  private memberUpdatedHandler = (event: Event) => {
657
735
  const { pagination, channels } = this.state.getLatestValue();
658
- const { filters, sort } = pagination;
736
+ const { filters, sort } = getResponseFiltersAndSort(pagination);
659
737
  if (
660
738
  !event.member?.user ||
661
739
  event.member.user.id !== this.client.userID ||
package/src/client.ts CHANGED
@@ -281,6 +281,13 @@ function isString(x: unknown): x is string {
281
281
 
282
282
  type MessageComposerTearDownFunction = () => void;
283
283
 
284
+ export type QueryChannelsResponseWithChannels = Omit<
285
+ QueryChannelsAPIResponse,
286
+ 'channels'
287
+ > & {
288
+ channels: Channel[];
289
+ };
290
+
284
291
  type MessageComposerSetupFunction = ({
285
292
  composer,
286
293
  }: {
@@ -1888,20 +1895,26 @@ export class StreamChat {
1888
1895
  }
1889
1896
 
1890
1897
  /**
1891
- * queryChannelsRequest - Queries channels and returns the raw response
1898
+ * queryChannelsRequestWithResponse - Queries channels and returns the full API response
1899
+ * including top-level metadata such as `predefined_filter`.
1900
+ *
1901
+ * This exists as a compatibility bridge, as changing `queryChannelsRequest()` to return
1902
+ * `QueryChannelsAPIResponse` would be a breaking change because it currently returns
1903
+ * only the channel list. In the next major release, the request/response APIs should
1904
+ * be consolidated so callers can access the full response through the primary API.
1892
1905
  *
1893
1906
  * @param {ChannelFilters} filterConditions object MongoDB style filters. Can be empty object when using predefined_filter in options.
1894
1907
  * @param {ChannelSort} [sort] Sort options, for instance {created_at: -1}.
1895
1908
  * When using multiple fields, make sure you use array of objects to guarantee field order, for instance [{last_updated: -1}, {created_at: 1}]
1896
1909
  * @param {ChannelOptions} [options] Options object. Can include predefined_filter, filter_values, and sort_values for using predefined filters.
1897
1910
  *
1898
- * @return {Promise<Array<ChannelAPIResponse>>} search channels response
1911
+ * @return {Promise<QueryChannelsAPIResponse>} full search channels response
1899
1912
  */
1900
- async queryChannelsRequest(
1913
+ async queryChannelsRequestWithResponse(
1901
1914
  filterConditions: ChannelFilters,
1902
1915
  sort: ChannelSort = [],
1903
1916
  options: ChannelOptions = {},
1904
- ) {
1917
+ ): Promise<QueryChannelsAPIResponse> {
1905
1918
  const defaultOptions: ChannelOptions = {
1906
1919
  state: true,
1907
1920
  watch: true,
@@ -1934,9 +1947,33 @@ export class StreamChat {
1934
1947
  ...restOptions,
1935
1948
  };
1936
1949
 
1937
- const data = await this.post<QueryChannelsAPIResponse>(
1938
- this.baseURL + '/channels',
1939
- payload,
1950
+ return await this.post<QueryChannelsAPIResponse>(this.baseURL + '/channels', payload);
1951
+ }
1952
+
1953
+ /**
1954
+ * queryChannelsRequest - Queries channels and returns the raw channel response list.
1955
+ *
1956
+ * This preserves the historical return shape for backwards compatibility. Use
1957
+ * `queryChannelsRequestWithResponse()` when response level metadata such as
1958
+ * `predefined_filter` is needed. In the next major release these APIs should be
1959
+ * consolidated into a single full-response API.
1960
+ *
1961
+ * @param {ChannelFilters} filterConditions object MongoDB style filters. Can be empty object when using predefined_filter in options.
1962
+ * @param {ChannelSort} [sort] Sort options, for instance {created_at: -1}.
1963
+ * When using multiple fields, make sure you use array of objects to guarantee field order, for instance [{last_updated: -1}, {created_at: 1}]
1964
+ * @param {ChannelOptions} [options] Options object. Can include predefined_filter, filter_values, and sort_values for using predefined filters.
1965
+ *
1966
+ * @return {Promise<Array<ChannelAPIResponse>>} search channels response
1967
+ */
1968
+ async queryChannelsRequest(
1969
+ filterConditions: ChannelFilters,
1970
+ sort: ChannelSort = [],
1971
+ options: ChannelOptions = {},
1972
+ ) {
1973
+ const data = await this.queryChannelsRequestWithResponse(
1974
+ filterConditions,
1975
+ sort,
1976
+ options,
1940
1977
  );
1941
1978
 
1942
1979
  // FIXME: In the next major release, return the full QueryChannelsAPIResponse
@@ -1955,16 +1992,34 @@ export class StreamChat {
1955
1992
  * @param {ChannelStateOptions} [stateOptions] State options object. These options will only be used for state management and won't be sent in the request.
1956
1993
  * - stateOptions.skipInitialization - Skips the initialization of the state for the channels matching the ids in the list.
1957
1994
  * - stateOptions.skipHydration - Skips returning the channels as instances of the Channel class and rather returns the raw query response.
1995
+ * - stateOptions.withResponse - Returns the full query response with hydrated channels. This is a compatibility bridge for internal callers that need response-level metadata while the default return value remains `Channel[]`.
1958
1996
  *
1959
1997
  * @return {Promise<Array<Channel>>} search channels response
1960
1998
  */
1999
+ async queryChannels(
2000
+ filterConditions: ChannelFilters,
2001
+ sort: ChannelSort,
2002
+ options: ChannelOptions,
2003
+ stateOptions: ChannelStateOptions & { withResponse: true },
2004
+ ): Promise<QueryChannelsResponseWithChannels>;
2005
+ async queryChannels(
2006
+ filterConditions?: ChannelFilters,
2007
+ sort?: ChannelSort,
2008
+ options?: ChannelOptions,
2009
+ stateOptions?: ChannelStateOptions,
2010
+ ): Promise<Channel[]>;
1961
2011
  async queryChannels(
1962
2012
  filterConditions: ChannelFilters,
1963
2013
  sort: ChannelSort = [],
1964
2014
  options: ChannelOptions = {},
1965
2015
  stateOptions: ChannelStateOptions = {},
1966
- ) {
1967
- const channels = await this.queryChannelsRequest(filterConditions, sort, options);
2016
+ ): Promise<Channel[] | QueryChannelsResponseWithChannels> {
2017
+ const queryChannelsResponse = await this.queryChannelsRequestWithResponse(
2018
+ filterConditions,
2019
+ sort,
2020
+ options,
2021
+ );
2022
+ const channels = queryChannelsResponse.channels;
1968
2023
 
1969
2024
  this.dispatchEvent({
1970
2025
  type: 'channels.queried',
@@ -1980,7 +2035,16 @@ export class StreamChat {
1980
2035
  });
1981
2036
  }
1982
2037
 
1983
- return this.hydrateActiveChannels(channels, stateOptions, options);
2038
+ const hydratedChannels = this.hydrateActiveChannels(channels, stateOptions, options);
2039
+
2040
+ if (stateOptions.withResponse) {
2041
+ return {
2042
+ ...queryChannelsResponse,
2043
+ channels: hydratedChannels,
2044
+ };
2045
+ }
2046
+
2047
+ return hydratedChannels;
1984
2048
  }
1985
2049
 
1986
2050
  /**
@@ -3,6 +3,7 @@ import type {
3
3
  ChannelAPIResponse,
4
4
  ChannelFilters,
5
5
  ChannelMemberResponse,
6
+ ChannelOptions,
6
7
  ChannelResponse,
7
8
  ChannelSort,
8
9
  DraftResponse,
@@ -41,6 +42,8 @@ export type DBUpsertCidsForQueryType = {
41
42
  cids: string[];
42
43
  /** Optional filters for the channels. */
43
44
  filters?: ChannelFilters;
45
+ /** Optional full query options for the channels. */
46
+ options?: ChannelOptions;
44
47
  /** Whether to immediately execute the operation. */
45
48
  execute?: boolean;
46
49
  /** Optional sorting applied to the channels. */
@@ -177,6 +180,8 @@ export type DBGetChannelsForQueryType = {
177
180
  userId: string;
178
181
  /** Optional filters for channels. */
179
182
  filters?: ChannelFilters;
183
+ /** Optional full query options for channels. */
184
+ options?: ChannelOptions;
180
185
  /** Optional sorting for the channels. */
181
186
  sort?: ChannelSort;
182
187
  };
package/src/types.ts CHANGED
@@ -1111,6 +1111,15 @@ export type ChannelStateOptions = {
1111
1111
  offlineMode?: boolean;
1112
1112
  skipInitialization?: string[];
1113
1113
  skipHydration?: boolean;
1114
+ /**
1115
+ * Returns the full query response with hydrated channels from `queryChannels()`.
1116
+ *
1117
+ * This is a compatibility bridge for internal callers that need response level
1118
+ * metadata such as `predefined_filter`. The default `queryChannels()` return value
1119
+ * remains `Channel[]` to avoid a breaking change. This should be folded into a
1120
+ * single full response API in the next major release.
1121
+ */
1122
+ withResponse?: boolean;
1114
1123
  };
1115
1124
 
1116
1125
  export type CreateChannelOptions = {