stream-chat 9.20.2 → 9.21.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.
@@ -6,6 +6,8 @@ type ChannelReadStatus = Record<string, {
6
6
  user: UserResponse;
7
7
  first_unread_message_id?: string;
8
8
  last_read_message_id?: string;
9
+ last_delivered_at?: Date;
10
+ last_delivered_message_id?: string;
9
11
  }>;
10
12
  /**
11
13
  * ChannelState - A container class for the channel state.
@@ -7,7 +7,7 @@ import { TokenManager } from './token_manager';
7
7
  import { WSConnectionFallback } from './connection_fallback';
8
8
  import { Campaign } from './campaign';
9
9
  import { Segment } from './segment';
10
- 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, CreateReminderOptions, CustomPermissionOptions, DeactivateUsersOptions, DeleteCommandResponse, DeleteUserOptions, Device, DeviceIdentifier, DraftFilters, DraftSort, EndpointName, Event, EventHandler, ExportChannelOptions, ExportChannelRequest, ExportChannelResponse, ExportChannelStatusResponse, ExportUsersRequest, ExportUsersResponse, FlagMessageResponse, FlagReportsFilters, FlagReportsPaginationOptions, FlagReportsResponse, FlagsFilters, FlagsPaginationOptions, FlagsResponse, FlagUserResponse, GetBlockedUsersAPIResponse, GetCampaignOptions, GetChannelTypeResponse, GetCommandResponse, GetHookEventsResponse, GetImportResponse, GetMessageOptions, GetPollAPIResponse, GetRateLimitsResponse, GetThreadAPIResponse, GetThreadOptions, GetUnreadCountAPIResponse, GetUnreadCountBatchAPIResponse, ListChannelResponse, ListCommandsResponse, ListImportsPaginationOptions, ListImportsResponse, LocalMessage, Logger, MarkChannelsReadOptions, MessageFilters, MessageFlagsFilters, MessageFlagsPaginationOptions, MessageFlagsResponse, MessageResponse, Mute, MuteUserOptions, MuteUserResponse, OGAttachment, OwnUserResponse, Pager, PartialMessageUpdate, PartialPollUpdate, PartialThreadUpdate, PartialUserUpdate, PermissionAPIResponse, PermissionsAPIResponse, PollAnswersAPIResponse, PollData, PollOptionData, PollSort, PollVote, PollVoteData, PollVotesAPIResponse, Product, PushPreference, PushProvider, PushProviderConfig, PushProviderID, PushProviderListResponse, PushProviderUpsertResponse, QueryDraftsResponse, QueryMessageHistoryFilters, QueryMessageHistoryOptions, QueryMessageHistoryResponse, QueryMessageHistorySort, QueryPollsFilters, QueryPollsOptions, QueryPollsResponse, QueryReactionsAPIResponse, QueryReactionsOptions, QueryRemindersOptions, QueryRemindersResponse, QuerySegmentsOptions, QuerySegmentTargetsFilter, QueryThreadsOptions, QueryVotesFilters, QueryVotesOptions, ReactionFilters, ReactionResponse, ReactionSort, ReactivateUserOptions, ReactivateUsersOptions, ReminderAPIResponse, ReviewFlagReportOptions, ReviewFlagReportResponse, SdkIdentifier, SearchAPIResponse, SearchOptions, SegmentData, SegmentResponse, SegmentTargetsResponse, SegmentType, SendFileAPIResponse, SharedLocationResponse, SortParam, StreamChatOptions, SyncOptions, SyncResponse, TaskResponse, TaskStatus, TestPushDataInput, TestSNSDataInput, TestSQSDataInput, TokenOrProvider, TranslateResponse, UnBanUserOptions, UpdateChannelTypeRequest, UpdateChannelTypeResponse, UpdateCommandOptions, UpdateCommandResponse, UpdateLocationPayload, UpdateMessageAPIResponse, UpdateMessageOptions, UpdatePollAPIResponse, UpdateReminderOptions, UpdateSegmentData, UpsertPushPreferencesResponse, UserCustomEvent, UserFilters, UserOptions, UserResponse, UserSort, VoteSort } from './types';
10
+ 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, CreateReminderOptions, CustomPermissionOptions, DeactivateUsersOptions, DeleteCommandResponse, DeleteUserOptions, Device, DeviceIdentifier, DraftFilters, DraftSort, EndpointName, Event, EventAPIResponse, EventHandler, ExportChannelOptions, ExportChannelRequest, ExportChannelResponse, ExportChannelStatusResponse, ExportUsersRequest, ExportUsersResponse, FlagMessageResponse, FlagReportsFilters, FlagReportsPaginationOptions, FlagReportsResponse, FlagsFilters, FlagsPaginationOptions, FlagsResponse, FlagUserResponse, GetBlockedUsersAPIResponse, GetCampaignOptions, GetChannelTypeResponse, GetCommandResponse, GetHookEventsResponse, GetImportResponse, GetMessageOptions, GetPollAPIResponse, GetRateLimitsResponse, GetThreadAPIResponse, GetThreadOptions, GetUnreadCountAPIResponse, GetUnreadCountBatchAPIResponse, ListChannelResponse, ListCommandsResponse, ListImportsPaginationOptions, ListImportsResponse, 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, Product, PushPreference, PushProvider, PushProviderConfig, PushProviderID, PushProviderListResponse, PushProviderUpsertResponse, QueryDraftsResponse, QueryMessageHistoryFilters, QueryMessageHistoryOptions, QueryMessageHistoryResponse, QueryMessageHistorySort, QueryPollsFilters, QueryPollsOptions, QueryPollsResponse, QueryReactionsAPIResponse, QueryReactionsOptions, QueryRemindersOptions, QueryRemindersResponse, QuerySegmentsOptions, QuerySegmentTargetsFilter, QueryThreadsOptions, QueryVotesFilters, QueryVotesOptions, ReactionFilters, ReactionResponse, ReactionSort, ReactivateUserOptions, ReactivateUsersOptions, ReminderAPIResponse, ReviewFlagReportOptions, ReviewFlagReportResponse, SdkIdentifier, SearchAPIResponse, SearchOptions, SegmentData, SegmentResponse, SegmentTargetsResponse, SegmentType, SendFileAPIResponse, SharedLocationResponse, SortParam, StreamChatOptions, SyncOptions, SyncResponse, TaskResponse, TaskStatus, TestPushDataInput, TestSNSDataInput, TestSQSDataInput, TokenOrProvider, TranslateResponse, UnBanUserOptions, UpdateChannelTypeRequest, UpdateChannelTypeResponse, UpdateCommandOptions, UpdateCommandResponse, UpdateLocationPayload, UpdateMessageAPIResponse, UpdateMessageOptions, UpdatePollAPIResponse, UpdateReminderOptions, UpdateSegmentData, UpsertPushPreferencesResponse, UserCustomEvent, UserFilters, UserOptions, UserResponse, UserSort, VoteSort } from './types';
11
11
  import { ErrorFromResponse } from './types';
12
12
  import { InsightMetrics } from './insights';
13
13
  import { Thread } from './thread';
@@ -1970,5 +1970,12 @@ export declare class StreamChat {
1970
1970
  * @return {Promise<APIResponse>} The server response
1971
1971
  */
1972
1972
  deleteImage(url: string): Promise<APIResponse>;
1973
+ /**
1974
+ * Send the mark delivered event for this user, only works if the `delivery_receipts` setting is enabled
1975
+ *
1976
+ * @param {MarkDeliveredOptions} data
1977
+ * @return {Promise<EventAPIResponse | void>} Description
1978
+ */
1979
+ markChannelsDelivered(data?: MarkDeliveredOptions): Promise<EventAPIResponse | undefined>;
1973
1980
  }
1974
1981
  export {};
@@ -21,6 +21,7 @@ export declare const EVENT_MAP: {
21
21
  'message.undeleted': boolean;
22
22
  'notification.added_to_channel': boolean;
23
23
  'notification.channel_deleted': boolean;
24
+ 'message.delivered': boolean;
24
25
  'notification.channel_mutes_updated': boolean;
25
26
  'notification.channel_truncated': boolean;
26
27
  'notification.invite_accepted': boolean;
@@ -692,6 +692,8 @@ export type ReadResponse = {
692
692
  user: UserResponse;
693
693
  last_read_message_id?: string;
694
694
  unread_messages?: number;
695
+ last_delivered_at?: string;
696
+ last_delivered_message_id?: string;
695
697
  };
696
698
  export type SearchAPIResponse = APIResponse & {
697
699
  results: {
@@ -783,6 +785,9 @@ export type PrivacySettings = {
783
785
  typing_indicators?: {
784
786
  enabled?: boolean;
785
787
  };
788
+ delivery_receipts?: {
789
+ enabled?: boolean;
790
+ };
786
791
  };
787
792
  export type PushNotificationSettings = {
788
793
  disabled?: boolean;
@@ -972,6 +977,7 @@ export type UpdateChannelTypeRequest = Partial<{
972
977
  typing_events?: boolean;
973
978
  uploads?: boolean;
974
979
  url_enrichment?: boolean;
980
+ count_messages?: boolean;
975
981
  };
976
982
  export type UpdateChannelTypeResponse = {
977
983
  automod: Automod;
@@ -1007,6 +1013,7 @@ export type UpdateChannelTypeResponse = {
1007
1013
  blocklists?: BlockListOptions[];
1008
1014
  partition_size?: number;
1009
1015
  partition_ttl?: string;
1016
+ count_messages?: boolean;
1010
1017
  };
1011
1018
  export type GetChannelTypeResponse = {
1012
1019
  automod: Automod;
@@ -1042,6 +1049,7 @@ export type GetChannelTypeResponse = {
1042
1049
  blocklists?: BlockListOptions[];
1043
1050
  partition_size?: number;
1044
1051
  partition_ttl?: string;
1052
+ count_messages?: boolean;
1045
1053
  };
1046
1054
  export type UpdateChannelOptions = Partial<{
1047
1055
  accept_invite: boolean;
@@ -1080,6 +1088,16 @@ export type MarkUnreadOptions = {
1080
1088
  user?: UserResponse;
1081
1089
  user_id?: string;
1082
1090
  };
1091
+ export type DeliveredMessageConfirmation = {
1092
+ cid: string;
1093
+ id: string;
1094
+ parent_id?: string;
1095
+ };
1096
+ export type MarkDeliveredOptions = {
1097
+ latest_delivered_messages: DeliveredMessageConfirmation[];
1098
+ user?: UserResponse;
1099
+ user_id?: string;
1100
+ };
1083
1101
  export type MuteUserOptions = {
1084
1102
  client_id?: string;
1085
1103
  connection_id?: string;
@@ -1263,6 +1281,8 @@ export type Event = CustomEventData & {
1263
1281
  draft?: DraftResponse;
1264
1282
  first_unread_message_id?: string;
1265
1283
  hard_delete?: boolean;
1284
+ last_delivered_at?: string;
1285
+ last_delivered_message_id?: string;
1266
1286
  last_read_at?: string;
1267
1287
  last_read_message_id?: string;
1268
1288
  live_location?: SharedLocationResponse;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stream-chat",
3
- "version": "9.20.2",
3
+ "version": "9.21.0",
4
4
  "description": "JS SDK for the Stream Chat API",
5
5
  "homepage": "https://getstream.io/chat/",
6
6
  "author": {
@@ -12,20 +12,20 @@
12
12
  "url": "https://github.com/GetStream/stream-chat-js.git"
13
13
  },
14
14
  "types": "./dist/types/index.d.ts",
15
- "main": "./dist/esm/index.js",
15
+ "main": "./dist/esm/index.mjs",
16
16
  "exports": {
17
17
  ".": {
18
18
  "types": "./dist/types/index.d.ts",
19
19
  "browser": {
20
- "import": "./dist/esm/index.js",
21
- "require": "./dist/cjs/index.browser.cjs"
20
+ "import": "./dist/esm/index.mjs",
21
+ "require": "./dist/cjs/index.browser.js"
22
22
  },
23
23
  "react-native": {
24
- "import": "./dist/esm/index.js",
25
- "require": "./dist/cjs/index.browser.cjs"
24
+ "import": "./dist/esm/index.mjs",
25
+ "require": "./dist/cjs/index.browser.js"
26
26
  },
27
- "node": "./dist/cjs/index.node.cjs",
28
- "default": "./dist/esm/index.js"
27
+ "node": "./dist/cjs/index.node.js",
28
+ "default": "./dist/esm/index.mjs"
29
29
  }
30
30
  },
31
31
  "browser": {
@@ -51,7 +51,7 @@
51
51
  "dependencies": {
52
52
  "@types/jsonwebtoken": "^9.0.8",
53
53
  "@types/ws": "^8.5.14",
54
- "axios": "^1.6.0",
54
+ "axios": "^1.12.2",
55
55
  "base64-js": "^1.5.1",
56
56
  "form-data": "^4.0.4",
57
57
  "isomorphic-ws": "^5.0.0",
package/src/channel.ts CHANGED
@@ -2272,6 +2272,10 @@ export class Channel {
2272
2272
  if (state.read) {
2273
2273
  for (const read of state.read) {
2274
2274
  this.state.read[read.user.id] = {
2275
+ last_delivered_at: read.last_delivered_at
2276
+ ? new Date(read.last_delivered_at)
2277
+ : undefined,
2278
+ last_delivered_message_id: read.last_delivered_message_id,
2275
2279
  last_read: new Date(read.last_read),
2276
2280
  last_read_message_id: read.last_read_message_id,
2277
2281
  unread_messages: read.unread_messages ?? 0,
@@ -26,6 +26,8 @@ type ChannelReadStatus = Record<
26
26
  user: UserResponse;
27
27
  first_unread_message_id?: string;
28
28
  last_read_message_id?: string;
29
+ last_delivered_at?: Date;
30
+ last_delivered_message_id?: string;
29
31
  }
30
32
  >;
31
33
 
package/src/client.ts CHANGED
@@ -87,6 +87,7 @@ import type {
87
87
  DraftSort,
88
88
  EndpointName,
89
89
  Event,
90
+ EventAPIResponse,
90
91
  EventHandler,
91
92
  ExportChannelOptions,
92
93
  ExportChannelRequest,
@@ -124,6 +125,7 @@ import type {
124
125
  LocalMessage,
125
126
  Logger,
126
127
  MarkChannelsReadOptions,
128
+ MarkDeliveredOptions,
127
129
  MessageFilters,
128
130
  MessageFlagsFilters,
129
131
  MessageFlagsPaginationOptions,
@@ -4697,4 +4699,21 @@ export class StreamChat {
4697
4699
  deleteImage(url: string) {
4698
4700
  return this.delete<APIResponse>(`${this.baseURL}/uploads/image`, { url });
4699
4701
  }
4702
+
4703
+ /**
4704
+ * Send the mark delivered event for this user, only works if the `delivery_receipts` setting is enabled
4705
+ *
4706
+ * @param {MarkDeliveredOptions} data
4707
+ * @return {Promise<EventAPIResponse | void>} Description
4708
+ */
4709
+ async markChannelsDelivered(data?: MarkDeliveredOptions) {
4710
+ const deliveryReceiptsEnabled =
4711
+ this.user?.privacy_settings?.delivery_receipts?.enabled;
4712
+ if (!deliveryReceiptsEnabled) return;
4713
+
4714
+ return await this.post<EventAPIResponse>(
4715
+ this.baseURL + '/channels/delivered',
4716
+ data ?? {},
4717
+ );
4718
+ }
4700
4719
  }
package/src/events.ts CHANGED
@@ -21,6 +21,7 @@ export const EVENT_MAP = {
21
21
  'message.undeleted': true,
22
22
  'notification.added_to_channel': true,
23
23
  'notification.channel_deleted': true,
24
+ 'message.delivered': true,
24
25
  'notification.channel_mutes_updated': true,
25
26
  'notification.channel_truncated': true,
26
27
  'notification.invite_accepted': true,
@@ -812,12 +812,9 @@ export class MessageComposer extends WithSubscriptions {
812
812
 
813
813
  this.initState({ composition: draft });
814
814
  } catch (error) {
815
- this.client.notifications.add({
816
- message: 'Failed to get the draft',
817
- origin: {
818
- emitter: 'MessageComposer',
819
- context: { composer: this },
820
- },
815
+ this.client.logger('error', `messageComposer:getDraft`, {
816
+ tags: ['channel', 'messageComposer'],
817
+ error,
821
818
  });
822
819
  }
823
820
  };
@@ -203,13 +203,19 @@ export class TextComposer {
203
203
  selection?: TextSelection;
204
204
  }) => {
205
205
  if (!this.enabled) return;
206
-
206
+ /**
207
+ * Windows inserts \r\n; macOS inserts \n.
208
+ * The caret can fall inside a CRLF pair during repeated pastes on Windows.
209
+ * That corrupts newline alignment (a\nb\na\nba\nb\n\n).
210
+ * Normalize the text to prevent it.
211
+ */
212
+ const normalizedText = text.replace(/\r\n/g, '\n');
207
213
  const finalSelection: TextSelection = selection ?? this.selection;
208
214
  const { maxLengthOnEdit } = this.composer.config.text ?? {};
209
215
  const currentText = this.text;
210
216
  const textBeforeTrim = [
211
217
  currentText.slice(0, finalSelection.start),
212
- text,
218
+ normalizedText,
213
219
  currentText.slice(finalSelection.end),
214
220
  ].join('');
215
221
 
@@ -217,7 +223,7 @@ export class TextComposer {
217
223
  0,
218
224
  typeof maxLengthOnEdit === 'number' ? maxLengthOnEdit : textBeforeTrim.length,
219
225
  );
220
- const expectedCursorPosition = finalSelection.start + text.length;
226
+ const expectedCursorPosition = finalSelection.start + normalizedText.length;
221
227
  const cursorPosition = Math.min(expectedCursorPosition, finalText.length);
222
228
 
223
229
  await this.handleChange({
package/src/types.ts CHANGED
@@ -817,6 +817,8 @@ export type ReadResponse = {
817
817
  user: UserResponse;
818
818
  last_read_message_id?: string;
819
819
  unread_messages?: number;
820
+ last_delivered_at?: string;
821
+ last_delivered_message_id?: string;
820
822
  };
821
823
 
822
824
  export type SearchAPIResponse = APIResponse & {
@@ -919,6 +921,9 @@ export type PrivacySettings = {
919
921
  typing_indicators?: {
920
922
  enabled?: boolean;
921
923
  };
924
+ delivery_receipts?: {
925
+ enabled?: boolean;
926
+ };
922
927
  };
923
928
 
924
929
  export type PushNotificationSettings = {
@@ -1135,6 +1140,7 @@ export type UpdateChannelTypeRequest =
1135
1140
  typing_events?: boolean;
1136
1141
  uploads?: boolean;
1137
1142
  url_enrichment?: boolean;
1143
+ count_messages?: boolean;
1138
1144
  };
1139
1145
 
1140
1146
  export type UpdateChannelTypeResponse = {
@@ -1171,6 +1177,7 @@ export type UpdateChannelTypeResponse = {
1171
1177
  blocklists?: BlockListOptions[];
1172
1178
  partition_size?: number;
1173
1179
  partition_ttl?: string;
1180
+ count_messages?: boolean;
1174
1181
  };
1175
1182
 
1176
1183
  export type GetChannelTypeResponse = {
@@ -1207,6 +1214,7 @@ export type GetChannelTypeResponse = {
1207
1214
  blocklists?: BlockListOptions[];
1208
1215
  partition_size?: number;
1209
1216
  partition_ttl?: string;
1217
+ count_messages?: boolean;
1210
1218
  };
1211
1219
 
1212
1220
  export type UpdateChannelOptions = Partial<{
@@ -1250,6 +1258,18 @@ export type MarkUnreadOptions = {
1250
1258
  user_id?: string;
1251
1259
  };
1252
1260
 
1261
+ export type DeliveredMessageConfirmation = {
1262
+ cid: string;
1263
+ id: string;
1264
+ parent_id?: string; // todo: should we include parent_id if thread delivery receipts are not yet supported?
1265
+ };
1266
+
1267
+ export type MarkDeliveredOptions = {
1268
+ latest_delivered_messages: DeliveredMessageConfirmation[];
1269
+ user?: UserResponse;
1270
+ user_id?: string;
1271
+ };
1272
+
1253
1273
  export type MuteUserOptions = {
1254
1274
  client_id?: string;
1255
1275
  connection_id?: string;
@@ -1460,6 +1480,8 @@ export type Event = CustomEventData & {
1460
1480
  // id of the message that was marked as unread - all the following messages are considered unread. (notification.mark_unread)
1461
1481
  first_unread_message_id?: string;
1462
1482
  hard_delete?: boolean;
1483
+ last_delivered_at?: string;
1484
+ last_delivered_message_id?: string;
1463
1485
  // creation date of a message with last_read_message_id, formatted as Date ISO string
1464
1486
  last_read_at?: string;
1465
1487
  last_read_message_id?: string;
@@ -2373,7 +2395,7 @@ export type ChannelConfigFields = {
2373
2395
  replies?: boolean;
2374
2396
  search?: boolean;
2375
2397
  shared_locations?: boolean;
2376
- count_messages?: boolean; // Feature flag for message count
2398
+ count_messages?: boolean;
2377
2399
  typing_events?: boolean;
2378
2400
  uploads?: boolean;
2379
2401
  url_enrichment?: boolean;