stream-chat 9.47.1 → 9.49.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.
@@ -4,7 +4,7 @@ import { CooldownTimer } from './CooldownTimer';
4
4
  import { MessageComposer } from './messageComposer';
5
5
  import { MessageReceiptsTracker } from './messageDelivery';
6
6
  import type { StreamChat } from './client';
7
- import type { AIState, APIResponse, AscDesc, BanUserOptions, ChannelAPIResponse, ChannelData, ChannelMemberAPIResponse, ChannelMemberResponse, ChannelQueryOptions, ChannelResponse, ChannelUpdateOptions, CreateDraftResponse, DeleteChannelAPIResponse, DraftMessagePayload, Event, EventAPIResponse, EventHandler, EventTypes, GetDraftResponse, GetMultipleMessagesAPIResponse, GetReactionsAPIResponse, GetRepliesAPIResponse, LiveLocationPayload, LocalMessage, MarkReadOptions, MarkUnreadOptions, MemberFilters, MemberSort, Message, MessageFilters, MessageOptions, MessagePaginationOptions, MessageResponse, MessageSetType, MuteChannelAPIResponse, NewMemberPayload, PartialUpdateChannel, PartialUpdateChannelAPIResponse, PartialUpdateMember, PartialUpdateMemberAPIResponse, PinnedMessagePaginationOptions, PinnedMessagesSort, PollVoteData, PushPreference, QueryChannelAPIResponse, QueryMembersOptions, Reaction, ReactionAPIResponse, SearchAPIResponse, SearchOptions, SendMessageAPIResponse, SendMessageOptions, SendReactionOptions, StaticLocationPayload, TruncateChannelAPIResponse, TruncateOptions, UnBanUserOptions, UpdateChannelAPIResponse, UpdateChannelOptions, UpdateLocationPayload, UserResponse } from './types';
7
+ import type { AIState, APIResponse, AscDesc, BanUserOptions, ChannelAPIResponse, ChannelData, ChannelMemberAPIResponse, ChannelMemberResponse, ChannelPushPreference, ChannelQueryOptions, ChannelResponse, ChannelUpdateOptions, CreateDraftResponse, DeleteChannelAPIResponse, DraftMessagePayload, Event, EventAPIResponse, EventHandler, EventTypes, GetDraftResponse, GetMultipleMessagesAPIResponse, GetReactionsAPIResponse, GetRepliesAPIResponse, LiveLocationPayload, LocalMessage, MarkReadOptions, MarkUnreadOptions, MemberFilters, MemberSort, Message, MessageFilters, MessageOptions, MessagePaginationOptions, MessageResponse, MessageSetType, MuteChannelAPIResponse, NewMemberPayload, PartialUpdateChannel, PartialUpdateChannelAPIResponse, PartialUpdateMember, PartialUpdateMemberAPIResponse, PinnedMessagePaginationOptions, PinnedMessagesSort, PollVoteData, QueryChannelAPIResponse, QueryMembersOptions, Reaction, ReactionAPIResponse, SearchAPIResponse, SearchOptions, SendMessageAPIResponse, SendMessageOptions, SendReactionOptions, StaticLocationPayload, TruncateChannelAPIResponse, TruncateOptions, UnBanUserOptions, UpdateChannelAPIResponse, UpdateChannelOptions, UpdateLocationPayload, UserResponse } from './types';
8
8
  import type { Role } from './permissions';
9
9
  /**
10
10
  * Channel - The Channel class manages it's own state.
@@ -40,7 +40,7 @@ export declare class Channel {
40
40
  lastTypingEvent: Date | null;
41
41
  isTyping: boolean;
42
42
  disconnected: boolean;
43
- push_preferences?: PushPreference;
43
+ push_preferences?: ChannelPushPreference;
44
44
  readonly messageComposer: MessageComposer;
45
45
  readonly messageReceiptsTracker: MessageReceiptsTracker;
46
46
  readonly cooldownTimer: CooldownTimer;
@@ -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, AddUserGroupMembersOptions, AddUserGroupMembersResponse, 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, CreateRoleAPIResponse, CreateUserGroupOptions, CreateUserGroupResponse, CustomPermissionOptions, DeactivateUsersOptions, DeleteCommandResponse, DeleteMessageOptions, DeleteUserGroupOptions, 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, GetUserGroupOptions, GetUserGroupResponse, ListChannelResponse, ListCommandsResponse, ListImportsPaginationOptions, ListImportsResponse, ListPredefinedFiltersOptions, ListPredefinedFiltersResponse, ListRolesAPIResponse, 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, QueryUserGroupsOptions, QueryUserGroupsResponse, QueryVotesFilters, QueryVotesOptions, ReactionFilters, ReactionResponse, ReactionSort, ReactivateUserOptions, ReactivateUsersOptions, ReminderAPIResponse, RemoveUserGroupMembersOptions, RemoveUserGroupMembersResponse, ReviewFlagReportOptions, ReviewFlagReportResponse, SdkIdentifier, SearchAPIResponse, SearchOptions, SearchRolesAPIResponse, SearchRolesOptions, SearchUserGroupsOptions, SearchUserGroupsResponse, 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, UpdateUserGroupOptions, UpdateUserGroupResponse, UpdateUsersAPIResponse, UpsertPushPreferencesResponse, UserCustomEvent, UserFilters, UserOptions, UserResponse, UserSort, VoteSort } from './types';
11
+ import type { ActiveLiveLocationsAPIResponse, AddUserGroupMembersOptions, AddUserGroupMembersResponse, APIErrorResponse, APIResponse, AppIdentifier, 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, CreateRoleAPIResponse, CreateUserGroupOptions, CreateUserGroupResponse, CustomPermissionOptions, DeactivateUsersOptions, DeleteCommandResponse, DeleteMessageOptions, DeleteUserGroupOptions, 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, GetUserGroupOptions, GetUserGroupResponse, ListChannelResponse, ListCommandsResponse, ListImportsPaginationOptions, ListImportsResponse, ListPredefinedFiltersOptions, ListPredefinedFiltersResponse, ListRolesAPIResponse, 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, QueryUserGroupsOptions, QueryUserGroupsResponse, QueryVotesFilters, QueryVotesOptions, ReactionFilters, ReactionResponse, ReactionSort, ReactivateUserOptions, ReactivateUsersOptions, ReminderAPIResponse, RemoveUserGroupMembersOptions, RemoveUserGroupMembersResponse, ReviewFlagReportOptions, ReviewFlagReportResponse, SdkIdentifier, SearchAPIResponse, SearchOptions, SearchRolesAPIResponse, SearchRolesOptions, SearchUserGroupsOptions, SearchUserGroupsResponse, 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, UpdateUserGroupOptions, UpdateUserGroupResponse, 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';
@@ -111,6 +111,8 @@ export declare class StreamChat {
111
111
  defaultWSTimeout: number;
112
112
  sdkIdentifier?: SdkIdentifier;
113
113
  deviceIdentifier?: DeviceIdentifier;
114
+ appIdentifier?: AppIdentifier;
115
+ private cachedUserAgent?;
114
116
  readonly messageComposerCache: FixedSizeQueueCache<string, MessageComposer>;
115
117
  private nextRequestAbortController;
116
118
  /**
@@ -1319,7 +1321,7 @@ export declare class StreamChat {
1319
1321
  * @returns {GetThreadAPIResponse} Returns the updated thread.
1320
1322
  */
1321
1323
  partialUpdateThread(messageId: string, partialThreadObject: PartialThreadUpdate): Promise<GetThreadAPIResponse>;
1322
- getUserAgent(): string;
1324
+ getUserAgent: () => string;
1323
1325
  /**
1324
1326
  * @deprecated use sdkIdentifier instead
1325
1327
  * @param userAgent
@@ -6,6 +6,8 @@ export interface CustomCommandData {
6
6
  }
7
7
  export interface CustomEventData {
8
8
  }
9
+ export interface CustomEventTypes {
10
+ }
9
11
  export interface CustomMemberData {
10
12
  }
11
13
  export interface CustomMessageData {
@@ -32,6 +32,6 @@ export * from './uploadManager';
32
32
  export * from './channel_manager';
33
33
  export * from './offline-support';
34
34
  export * from './LiveLocationManager';
35
- export type { CustomAttachmentData, CustomChannelData, CustomCommandData, CustomEventData, CustomMemberData, CustomMessageComposerData, CustomMessageData, CustomPollOptionData, CustomPollData, CustomReactionData, CustomUserData, CustomThreadData, } from './custom_types';
35
+ export type { CustomAttachmentData, CustomChannelData, CustomCommandData, CustomEventData, CustomEventTypes, CustomMemberData, CustomMessageComposerData, CustomMessageData, CustomPollOptionData, CustomPollData, CustomReactionData, CustomUserData, CustomThreadData, } from './custom_types';
36
36
  export { isOwnUser, chatCodes, logChatPromiseExecution, localMessageToNewMessagePayload, formatMessage, promoteChannel, } from './utils';
37
37
  export { FixedSizeQueueCache } from './utils/FixedSizeQueueCache';
@@ -49,6 +49,7 @@ export type ThreadUserReadState = {
49
49
  unreadMessageCount: number;
50
50
  user: UserResponse;
51
51
  lastReadMessageId?: string;
52
+ firstUnreadMessageId?: string;
52
53
  };
53
54
  export type ThreadReadState = Record<string, ThreadUserReadState | undefined>;
54
55
  export declare const THREAD_RESPONSE_RESERVED_KEYS: Record<keyof ThreadResponse, true>;
@@ -74,6 +75,7 @@ export declare class Thread extends WithSubscriptions {
74
75
  private subscribeMarkActiveThreadRead;
75
76
  private subscribeReloadActiveStaleThread;
76
77
  private subscribeMarkThreadStale;
78
+ private subscribeRepliesUnread;
77
79
  private subscribeNewReplies;
78
80
  private subscribeRepliesRead;
79
81
  private subscribeMessageDeleted;
@@ -3,7 +3,7 @@ import type { Channel } from './channel';
3
3
  import type { AxiosRequestConfig, AxiosResponse } from 'axios';
4
4
  import type { StableWSConnection } from './connection';
5
5
  import type { Role } from './permissions';
6
- import type { CustomAttachmentData, CustomChannelData, CustomCommandData, CustomEventData, CustomMemberData, CustomMessageData, CustomPollData, CustomPollOptionData, CustomReactionData, CustomThreadData, CustomUserData } from './custom_types';
6
+ import type { CustomAttachmentData, CustomChannelData, CustomCommandData, CustomEventData, CustomEventTypes, CustomMemberData, CustomMessageData, CustomPollData, CustomPollOptionData, CustomReactionData, CustomThreadData, CustomUserData } from './custom_types';
7
7
  import type { NotificationManager } from './notifications';
8
8
  import type { RESERVED_UPDATED_MESSAGE_FIELDS } from './constants';
9
9
  /**
@@ -314,7 +314,7 @@ export type ChannelAPIResponse = {
314
314
  hidden?: boolean;
315
315
  membership?: ChannelMemberResponse | null;
316
316
  pending_messages?: PendingMessageResponse[];
317
- push_preferences?: PushPreference;
317
+ push_preferences?: ChannelPushPreference;
318
318
  read?: ReadResponse[];
319
319
  threads?: ThreadResponse[];
320
320
  watcher_count?: number;
@@ -571,21 +571,51 @@ export type GetUnreadCountAPIResponse = APIResponse & {
571
571
  total_unread_threads_count: number;
572
572
  total_unread_count_by_team?: Record<string, number>;
573
573
  };
574
- export type ChatLevelPushPreference = 'all' | 'none' | 'mentions' | (string & {});
574
+ export type ChatLevelPushPreference = 'all' | 'mentions' | 'direct_mentions' | 'all_mentions' | 'none' | 'default' | (string & {});
575
+ export type CallLevelPushPreference = 'all' | 'none' | 'default' | (string & {});
576
+ /** Granular all/none toggle used by the chat sub-preferences. */
577
+ export type PushPreferenceLevel = 'all' | 'none' | (string & {});
578
+ /** Per-mention-type chat push preferences (matches OpenAPI `ChatPreferencesInput`). */
579
+ export type ChatPreferences = {
580
+ channel_mentions?: PushPreferenceLevel;
581
+ default_preference?: PushPreferenceLevel;
582
+ direct_mentions?: PushPreferenceLevel;
583
+ group_mentions?: PushPreferenceLevel;
584
+ here_mentions?: PushPreferenceLevel;
585
+ role_mentions?: PushPreferenceLevel;
586
+ thread_replies?: PushPreferenceLevel;
587
+ };
588
+ /**
589
+ * Input accepted by {@link StreamChat.setPushPreferences} (matches OpenAPI `PushPreferenceInput`).
590
+ *
591
+ * Set `channel_cid` to scope the preference to a single channel; leave it empty to
592
+ * set the user-level default. `user_id` is required for server-side auth and
593
+ * defaults to the connected user for client-side auth.
594
+ */
575
595
  export type PushPreference = {
576
- callLevel?: 'all' | 'none' | (string & {});
577
- chatLevel?: ChatLevelPushPreference;
578
- disabledUntil?: string;
579
- removeDisable?: boolean;
596
+ call_level?: CallLevelPushPreference;
597
+ channel_cid?: string;
598
+ chat_level?: ChatLevelPushPreference;
599
+ chat_preferences?: ChatPreferences;
600
+ disabled_until?: string;
601
+ remove_disable?: boolean;
602
+ user_id?: string;
603
+ };
604
+ /** Per-user push preferences returned by the API (matches OpenAPI `PushPreferencesResponse`). */
605
+ export type PushPreferencesResponse = {
606
+ call_level?: CallLevelPushPreference;
607
+ chat_level?: ChatLevelPushPreference;
608
+ chat_preferences?: ChatPreferences;
609
+ disabled_until?: string;
580
610
  };
611
+ /** Per-channel push preferences returned by the API (matches OpenAPI `ChannelPushPreferencesResponse`). */
581
612
  export type ChannelPushPreference = {
582
- chatLevel?: ChatLevelPushPreference;
583
- disabledUntil?: string;
584
- removeDisable?: boolean;
613
+ chat_level?: ChatLevelPushPreference;
614
+ disabled_until?: string;
585
615
  };
586
616
  export type UpsertPushPreferencesResponse = APIResponse & {
587
- userChannelPreferences: Record<string, Record<string, ChannelPushPreference>>;
588
- userPreferences: Record<string, PushPreference>;
617
+ user_channel_preferences: Record<string, Record<string, ChannelPushPreference>>;
618
+ user_preferences: Record<string, PushPreferencesResponse>;
589
619
  };
590
620
  export type GetUnreadCountBatchAPIResponse = APIResponse & {
591
621
  counts_by_user: {
@@ -731,7 +761,7 @@ export type OwnUserBase = {
731
761
  unread_threads: number;
732
762
  invisible?: boolean;
733
763
  privacy_settings?: PrivacySettings;
734
- push_preferences?: PushPreference;
764
+ push_preferences?: PushPreferencesResponse;
735
765
  roles?: string[];
736
766
  total_unread_count_by_team?: Record<string, number> | null;
737
767
  };
@@ -1473,12 +1503,13 @@ export type Event = CustomEventData & {
1473
1503
  watcher_count?: number;
1474
1504
  channel_last_message_at?: string;
1475
1505
  app?: Record<string, unknown>;
1506
+ thread_id?: string;
1476
1507
  };
1477
1508
  export type UserCustomEvent = CustomEventData & {
1478
1509
  type: string;
1479
1510
  };
1480
1511
  export type EventHandler = (event: Event) => void;
1481
- export type EventTypes = 'all' | keyof typeof EVENT_MAP;
1512
+ export type EventTypes = 'all' | keyof typeof EVENT_MAP | keyof CustomEventTypes;
1482
1513
  /**
1483
1514
  * Filter Types
1484
1515
  */
@@ -3358,6 +3389,16 @@ export type DeviceIdentifier = {
3358
3389
  os: string;
3359
3390
  model?: string;
3360
3391
  };
3392
+ /**
3393
+ * An identifier containing information about the downstream application integrating
3394
+ * stream-chat, if available. `name` is reported as `app` and `version` as `app_version`
3395
+ * in the user agent. Distinct from the SDK ({@link SdkIdentifier}) and device
3396
+ * ({@link DeviceIdentifier}) identifiers.
3397
+ */
3398
+ export type AppIdentifier = {
3399
+ name: string;
3400
+ version?: string;
3401
+ };
3361
3402
  export type DraftResponse = {
3362
3403
  channel_cid: string;
3363
3404
  created_at: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stream-chat",
3
- "version": "9.47.1",
3
+ "version": "9.49.0",
4
4
  "description": "JS SDK for the Stream Chat API",
5
5
  "homepage": "https://getstream.io/chat/",
6
6
  "author": {
package/src/channel.ts CHANGED
@@ -21,6 +21,7 @@ import type {
21
21
  ChannelFilters,
22
22
  ChannelMemberAPIResponse,
23
23
  ChannelMemberResponse,
24
+ ChannelPushPreference,
24
25
  ChannelQueryOptions,
25
26
  ChannelResponse,
26
27
  ChannelUpdateOptions,
@@ -56,7 +57,6 @@ import type {
56
57
  PinnedMessagePaginationOptions,
57
58
  PinnedMessagesSort,
58
59
  PollVoteData,
59
- PushPreference,
60
60
  QueryChannelAPIResponse,
61
61
  QueryMembersOptions,
62
62
  Reaction,
@@ -112,7 +112,7 @@ export class Channel {
112
112
  lastTypingEvent: Date | null;
113
113
  isTyping: boolean;
114
114
  disconnected: boolean;
115
- push_preferences?: PushPreference;
115
+ push_preferences?: ChannelPushPreference;
116
116
  public readonly messageComposer: MessageComposer;
117
117
  public readonly messageReceiptsTracker: MessageReceiptsTracker;
118
118
  public readonly cooldownTimer: CooldownTimer;
package/src/client.ts CHANGED
@@ -46,6 +46,7 @@ import type {
46
46
  AddUserGroupMembersResponse,
47
47
  APIErrorResponse,
48
48
  APIResponse,
49
+ AppIdentifier,
49
50
  AppSettings,
50
51
  AppSettingsAPIResponse,
51
52
  BannedUsersFilters,
@@ -394,6 +395,8 @@ export class StreamChat {
394
395
  defaultWSTimeout: number;
395
396
  sdkIdentifier?: SdkIdentifier;
396
397
  deviceIdentifier?: DeviceIdentifier;
398
+ appIdentifier?: AppIdentifier;
399
+ private cachedUserAgent?: string;
397
400
  readonly messageComposerCache: FixedSizeQueueCache<string, MessageComposer>;
398
401
  private nextRequestAbortController: AbortController | null = null;
399
402
  /**
@@ -1641,6 +1644,19 @@ export class StreamChat {
1641
1644
  });
1642
1645
  }
1643
1646
 
1647
+ // Current user removed from a channel: evict it like channel.deleted so
1648
+ // recoverState won't re-watch it and no further events reach it (#2599).
1649
+ // Type-agnostic. We skip deleteAllChannelReference (unlike deletion) since
1650
+ // the channel still exists for its remaining members.
1651
+ if (event.type === 'notification.removed_from_channel' && event.cid) {
1652
+ const { cid } = event;
1653
+ this.activeChannels[cid]?._disconnect();
1654
+
1655
+ postListenerCallbacks.push(() => {
1656
+ delete this.activeChannels[cid];
1657
+ });
1658
+ }
1659
+
1644
1660
  return postListenerCallbacks;
1645
1661
  }
1646
1662
 
@@ -3709,40 +3725,42 @@ export class StreamChat {
3709
3725
  );
3710
3726
  }
3711
3727
 
3712
- getUserAgent() {
3728
+ getUserAgent = (): string => {
3729
+ // An explicit override (deprecated `setUserAgent`) always wins and is never cached.
3713
3730
  if (this.userAgent) {
3714
3731
  return this.userAgent;
3715
3732
  }
3716
3733
 
3717
- const version = process.env.PKG_VERSION;
3718
- const clientBundle = process.env.CLIENT_BUNDLE;
3719
-
3720
- let userAgentString = '';
3721
- if (this.sdkIdentifier) {
3722
- userAgentString = `stream-chat-${this.sdkIdentifier.name}-v${this.sdkIdentifier.version}-llc-v${version}`;
3723
- } else {
3724
- userAgentString = `stream-chat-js-v${version}-${this.node ? 'node' : 'browser'}`;
3734
+ // Computed once, then memoized for the client's lifetime - inputs read on
3735
+ // the first call (sdk/device identifiers, build-time env) are not re-read.
3736
+ if (!this.cachedUserAgent) {
3737
+ const version = process.env.PKG_VERSION;
3738
+ const { name: sdkName, version: sdkVersion } = this.sdkIdentifier ?? {};
3739
+ const { name: appName, version: appVersion } = this.appIdentifier ?? {};
3740
+ const { os, model: deviceModel } = this.deviceIdentifier ?? {};
3741
+
3742
+ const head = sdkName
3743
+ ? `stream-chat-${sdkName}-v${sdkVersion}-llc-v${version}`
3744
+ : `stream-chat-js-v${version}-${this.node ? 'node' : 'browser'}`;
3745
+
3746
+ this.cachedUserAgent = [
3747
+ head,
3748
+ // reports the host app, the device OS, the device model, and the picked
3749
+ // exports bundle, each only when a value is present
3750
+ ...Object.entries({
3751
+ app: appName,
3752
+ app_version: appVersion,
3753
+ os,
3754
+ device_model: deviceModel,
3755
+ client_bundle: process.env.CLIENT_BUNDLE,
3756
+ })
3757
+ .filter(([, value]) => value && value.length > 0)
3758
+ .map(([key, value]) => `${key}=${value}`),
3759
+ ].join('|');
3725
3760
  }
3726
3761
 
3727
- const { os, model } = this.deviceIdentifier ?? {};
3728
-
3729
- return (
3730
- [
3731
- // reports the device OS, if provided
3732
- ['os', os],
3733
- // reports the device model, if provided
3734
- ['device_model', model],
3735
- // reports which bundle is being picked from the exports
3736
- ['client_bundle', clientBundle],
3737
- ] as const
3738
- ).reduce(
3739
- (withArguments, [key, value]) =>
3740
- value && value.length > 0
3741
- ? withArguments.concat(`|${key}=${value}`)
3742
- : withArguments,
3743
- userAgentString,
3744
- );
3745
- }
3762
+ return this.cachedUserAgent;
3763
+ };
3746
3764
 
3747
3765
  /**
3748
3766
  * @deprecated use sdkIdentifier instead
@@ -2,6 +2,7 @@ export interface CustomAttachmentData {}
2
2
  export interface CustomChannelData {}
3
3
  export interface CustomCommandData {}
4
4
  export interface CustomEventData {}
5
+ export interface CustomEventTypes {}
5
6
  export interface CustomMemberData {}
6
7
  export interface CustomMessageData {}
7
8
  export interface CustomPollOptionData {}
package/src/index.ts CHANGED
@@ -43,6 +43,7 @@ export type {
43
43
  CustomChannelData,
44
44
  CustomCommandData,
45
45
  CustomEventData,
46
+ CustomEventTypes,
46
47
  CustomMemberData,
47
48
  CustomMessageComposerData,
48
49
  CustomMessageData,
package/src/thread.ts CHANGED
@@ -63,6 +63,7 @@ export type ThreadUserReadState = {
63
63
  unreadMessageCount: number;
64
64
  user: UserResponse;
65
65
  lastReadMessageId?: string;
66
+ firstUnreadMessageId?: string;
66
67
  };
67
68
 
68
69
  export type ThreadReadState = Record<string, ThreadUserReadState | undefined>;
@@ -272,6 +273,7 @@ export class Thread extends WithSubscriptions {
272
273
  this.addUnsubscribeFunction(this.subscribeMarkThreadStale());
273
274
  this.addUnsubscribeFunction(this.subscribeNewReplies());
274
275
  this.addUnsubscribeFunction(this.subscribeRepliesRead());
276
+ this.addUnsubscribeFunction(this.subscribeRepliesUnread());
275
277
  this.addUnsubscribeFunction(this.subscribeMessageDeleted());
276
278
  this.addUnsubscribeFunction(this.subscribeMessageUpdated());
277
279
  };
@@ -330,6 +332,33 @@ export class Thread extends WithSubscriptions {
330
332
  this.state.partialNext({ isStateStale: true });
331
333
  }).unsubscribe;
332
334
 
335
+ private subscribeRepliesUnread = () =>
336
+ this.client.on('notification.mark_unread', (event) => {
337
+ if (!event.user || !event.created_at || !event.thread_id) return;
338
+ if (event.thread_id !== this.id) return;
339
+
340
+ const userId = event.user.id;
341
+ const createdAt = event.created_at;
342
+ const user = event.user;
343
+
344
+ this.state.next((current) => ({
345
+ ...current,
346
+ read: {
347
+ ...current.read,
348
+ [userId]: {
349
+ ...current.read[userId],
350
+ lastReadAt:
351
+ typeof event.last_read_at !== 'undefined'
352
+ ? new Date(event.last_read_at)
353
+ : new Date(createdAt),
354
+ user,
355
+ firstUnreadMessageId: event.first_unread_message_id,
356
+ unreadMessageCount: event.unread_messages ?? 0,
357
+ },
358
+ },
359
+ }));
360
+ }).unsubscribe;
361
+
333
362
  private subscribeNewReplies = () =>
334
363
  this.client.on('message.new', (event) => {
335
364
  if (!this.client.userID || event.message?.parent_id !== this.id) {
@@ -117,6 +117,7 @@ export class ThreadManager extends WithSubscriptions {
117
117
  const unsubscribeFunctions = [
118
118
  'health.check',
119
119
  'notification.mark_read',
120
+ 'notification.mark_unread',
120
121
  'notification.thread_message_new',
121
122
  'notification.channel_deleted',
122
123
  ].map(
package/src/types.ts CHANGED
@@ -8,6 +8,7 @@ import type {
8
8
  CustomChannelData,
9
9
  CustomCommandData,
10
10
  CustomEventData,
11
+ CustomEventTypes,
11
12
  CustomMemberData,
12
13
  CustomMessageData,
13
14
  CustomPollData,
@@ -379,7 +380,7 @@ export type ChannelAPIResponse = {
379
380
  hidden?: boolean;
380
381
  membership?: ChannelMemberResponse | null;
381
382
  pending_messages?: PendingMessageResponse[];
382
- push_preferences?: PushPreference;
383
+ push_preferences?: ChannelPushPreference;
383
384
  read?: ReadResponse[];
384
385
  threads?: ThreadResponse[];
385
386
  watcher_count?: number;
@@ -684,25 +685,67 @@ export type GetUnreadCountAPIResponse = APIResponse & {
684
685
  total_unread_count_by_team?: Record<string, number>;
685
686
  };
686
687
 
687
- export type ChatLevelPushPreference = 'all' | 'none' | 'mentions' | (string & {});
688
+ export type ChatLevelPushPreference =
689
+ | 'all'
690
+ | 'mentions' // deprecated by the API in favor of 'direct_mentions'
691
+ | 'direct_mentions'
692
+ | 'all_mentions'
693
+ | 'none'
694
+ | 'default'
695
+ | (string & {});
696
+
697
+ export type CallLevelPushPreference = 'all' | 'none' | 'default' | (string & {});
688
698
 
699
+ /** Granular all/none toggle used by the chat sub-preferences. */
700
+ export type PushPreferenceLevel = 'all' | 'none' | (string & {});
701
+
702
+ /** Per-mention-type chat push preferences (matches OpenAPI `ChatPreferencesInput`). */
703
+ export type ChatPreferences = {
704
+ channel_mentions?: PushPreferenceLevel;
705
+ default_preference?: PushPreferenceLevel;
706
+ direct_mentions?: PushPreferenceLevel;
707
+ group_mentions?: PushPreferenceLevel;
708
+ here_mentions?: PushPreferenceLevel;
709
+ role_mentions?: PushPreferenceLevel;
710
+ thread_replies?: PushPreferenceLevel;
711
+ };
712
+
713
+ /**
714
+ * Input accepted by {@link StreamChat.setPushPreferences} (matches OpenAPI `PushPreferenceInput`).
715
+ *
716
+ * Set `channel_cid` to scope the preference to a single channel; leave it empty to
717
+ * set the user-level default. `user_id` is required for server-side auth and
718
+ * defaults to the connected user for client-side auth.
719
+ */
689
720
  export type PushPreference = {
690
- callLevel?: 'all' | 'none' | (string & {});
691
- chatLevel?: ChatLevelPushPreference;
692
- disabledUntil?: string; // snooze till this time
693
- removeDisable?: boolean; // Temporary flag for resetting disabledUntil
721
+ call_level?: CallLevelPushPreference;
722
+ channel_cid?: string;
723
+ chat_level?: ChatLevelPushPreference;
724
+ chat_preferences?: ChatPreferences;
725
+ disabled_until?: string; // snooze until this time
726
+ remove_disable?: boolean; // stop snoozing (clears disabled_until)
727
+ user_id?: string;
728
+ };
729
+
730
+ /** Per-user push preferences returned by the API (matches OpenAPI `PushPreferencesResponse`). */
731
+ export type PushPreferencesResponse = {
732
+ call_level?: CallLevelPushPreference;
733
+ chat_level?: ChatLevelPushPreference;
734
+ chat_preferences?: ChatPreferences;
735
+ disabled_until?: string;
694
736
  };
695
737
 
738
+ /** Per-channel push preferences returned by the API (matches OpenAPI `ChannelPushPreferencesResponse`). */
696
739
  export type ChannelPushPreference = {
697
- chatLevel?: ChatLevelPushPreference; // "all", "none", "mentions", or other custom strings
698
- disabledUntil?: string;
699
- removeDisable?: boolean; // Temporary flag for resetting disabledUntil
740
+ chat_level?: ChatLevelPushPreference; // "all", "mentions", "direct_mentions", "all_mentions", "none", "default" or other custom strings
741
+ disabled_until?: string;
700
742
  };
701
743
 
702
744
  export type UpsertPushPreferencesResponse = APIResponse & {
703
- // Mapping of user IDs to their push preferences
704
- userChannelPreferences: Record<string, Record<string, ChannelPushPreference>>;
705
- userPreferences: Record<string, PushPreference>; // Mapping of user -> channel id -> push preferences
745
+ // Mapping of user id -> channel cid -> channel push preferences
746
+ user_channel_preferences: Record<string, Record<string, ChannelPushPreference>>;
747
+ // Mapping of user id -> user push preferences
748
+ user_preferences: Record<string, PushPreferencesResponse>;
706
749
  };
707
750
 
708
751
  export type GetUnreadCountBatchAPIResponse = APIResponse & {
@@ -861,7 +904,7 @@ export type OwnUserBase = {
861
904
  unread_threads: number;
862
905
  invisible?: boolean;
863
906
  privacy_settings?: PrivacySettings;
864
- push_preferences?: PushPreference;
907
+ push_preferences?: PushPreferencesResponse;
865
908
  roles?: string[];
866
909
  total_unread_count_by_team?: Record<string, number> | null;
867
910
  };
@@ -1694,6 +1737,7 @@ export type Event = CustomEventData & {
1694
1737
  watcher_count?: number;
1695
1738
  channel_last_message_at?: string;
1696
1739
  app?: Record<string, unknown>; // TODO: further specify type
1740
+ thread_id?: string;
1697
1741
  };
1698
1742
 
1699
1743
  export type UserCustomEvent = CustomEventData & {
@@ -1702,7 +1746,7 @@ export type UserCustomEvent = CustomEventData & {
1702
1746
 
1703
1747
  export type EventHandler = (event: Event) => void;
1704
1748
 
1705
- export type EventTypes = 'all' | keyof typeof EVENT_MAP;
1749
+ export type EventTypes = 'all' | keyof typeof EVENT_MAP | keyof CustomEventTypes;
1706
1750
 
1707
1751
  /**
1708
1752
  * Filter Types
@@ -4493,6 +4537,14 @@ export type SdkIdentifier = {
4493
4537
  */
4494
4538
  export type DeviceIdentifier = { os: string; model?: string };
4495
4539
 
4540
+ /**
4541
+ * An identifier containing information about the downstream application integrating
4542
+ * stream-chat, if available. `name` is reported as `app` and `version` as `app_version`
4543
+ * in the user agent. Distinct from the SDK ({@link SdkIdentifier}) and device
4544
+ * ({@link DeviceIdentifier}) identifiers.
4545
+ */
4546
+ export type AppIdentifier = { name: string; version?: string };
4547
+
4496
4548
  export type DraftResponse = {
4497
4549
  channel_cid: string;
4498
4550
  created_at: string;