stream-chat 8.14.4 → 8.15.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
@@ -96,6 +96,7 @@ import {
96
96
  GetMessageAPIResponse,
97
97
  GetRateLimitsResponse,
98
98
  GetUnreadCountAPIResponse,
99
+ GetUnreadCountBatchAPIResponse,
99
100
  ListChannelResponse,
100
101
  ListCommandsResponse,
101
102
  ListImportsPaginationOptions,
@@ -123,12 +124,10 @@ import {
123
124
  PushProviderListResponse,
124
125
  PushProviderUpsertResponse,
125
126
  QueryChannelsAPIResponse,
127
+ QuerySegmentsOptions,
126
128
  ReactionResponse,
127
129
  ReactivateUserOptions,
128
130
  ReactivateUsersOptions,
129
- Recipient,
130
- RecipientFilters,
131
- RecipientQueryOptions,
132
131
  ReservedMessageFields,
133
132
  ReviewFlagReportOptions,
134
133
  ReviewFlagReportResponse,
@@ -138,8 +137,7 @@ import {
138
137
  SearchPayload,
139
138
  Segment,
140
139
  SegmentData,
141
- SegmentFilters,
142
- SegmentQueryOptions,
140
+ SegmentType,
143
141
  SendFileAPIResponse,
144
142
  StreamChatOptions,
145
143
  SyncOptions,
@@ -159,6 +157,7 @@ import {
159
157
  UpdatedMessage,
160
158
  UpdateMessageAPIResponse,
161
159
  UpdateMessageOptions,
160
+ UpdateSegmentData,
162
161
  UserCustomEvent,
163
162
  UserFilters,
164
163
  UserOptions,
@@ -1688,10 +1687,28 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
1688
1687
  );
1689
1688
  }
1690
1689
 
1690
+ /**
1691
+ * getUnreadCount - Returns unread counts for a single user
1692
+ *
1693
+ * @param {string} [userID] User ID.
1694
+ *
1695
+ * @return {<GetUnreadCountAPIResponse>}
1696
+ */
1691
1697
  async getUnreadCount(userID?: string) {
1692
1698
  return await this.get<GetUnreadCountAPIResponse>(this.baseURL + '/unread', userID ? { user_id: userID } : {});
1693
1699
  }
1694
1700
 
1701
+ /**
1702
+ * getUnreadCountBatch - Returns unread counts for multiple users at once. Only works server side.
1703
+ *
1704
+ * @param {string[]} [userIDs] List of user IDs to fetch unread counts for.
1705
+ *
1706
+ * @return {<GetUnreadCountBatchAPIResponse>}
1707
+ */
1708
+ async getUnreadCountBatch(userIDs: string[]) {
1709
+ return await this.post<GetUnreadCountBatchAPIResponse>(this.baseURL + '/unread_batch', { user_ids: userIDs });
1710
+ }
1711
+
1695
1712
  /**
1696
1713
  * removeDevice - Removes the device with the given id. Clientside users can only delete their own devices
1697
1714
  *
@@ -2824,56 +2841,132 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
2824
2841
  }
2825
2842
 
2826
2843
  /**
2827
- * createSegment - Creates a Campaign Segment
2844
+ * createSegment - Creates a segment
2828
2845
  *
2846
+ * @private
2847
+ * @param {SegmentType} type Segment type
2848
+ * @param {string} id Segment ID (valid UUID)
2849
+ * @param {string} name Segment name (valid UUID)
2829
2850
  * @param {SegmentData} params Segment data
2830
2851
  *
2831
- * @return {Segment} The Created Segment
2852
+ * @return {Segment} The created Segment
2832
2853
  */
2833
- async createSegment(params: SegmentData) {
2834
- const { segment } = await this.post<{ segment: Segment }>(this.baseURL + `/segments`, { segment: params });
2854
+ private async createSegment(type: SegmentType, id: string, name: string, data?: SegmentData): Promise<Segment> {
2855
+ const body = {
2856
+ id,
2857
+ type,
2858
+ name,
2859
+ data,
2860
+ };
2861
+ const { segment } = await this.post<{ segment: Segment }>(this.baseURL + `/segments`, body);
2835
2862
  return segment;
2836
2863
  }
2837
2864
 
2838
2865
  /**
2839
- * querySegments - Query Campaign Segments
2866
+ * createUserSegment - Creates a user segment
2867
+ *
2868
+ * @param {string} id Segment ID (valid UUID)
2869
+ * @param {string} name Segment name
2870
+ * @param {SegmentData} data Segment data
2871
+ *
2872
+ * @return {Segment} The created Segment
2873
+ */
2874
+ async createUserSegment(id: string, name: string, data?: SegmentData): Promise<Segment> {
2875
+ return await this.createSegment('user', id, name, data);
2876
+ }
2877
+
2878
+ /**
2879
+ * createChannelSegment - Creates a channel segment
2880
+ *
2881
+ * @param {string} id Segment ID (valid UUID)
2882
+ * @param {string} name Segment name
2883
+ * @param {SegmentData} data Segment data
2884
+ *
2885
+ * @return {Segment} The created Segment
2886
+ */
2887
+ async createChannelSegment(id: string, name: string, data?: SegmentData): Promise<Segment> {
2888
+ return await this.createSegment('channel', id, name, data);
2889
+ }
2890
+
2891
+ /**
2892
+ * updateSegment - Update a segment
2893
+ *
2894
+ * @param {string} id Segment ID
2895
+ * @param {Partial<UpdateSegmentData>} data Data to update
2896
+ *
2897
+ * @return {Segment} Updated Segment
2898
+ */
2899
+ async updateSegment(id: string, data: Partial<UpdateSegmentData>) {
2900
+ const { segment } = await this.put<{ segment: Segment }>(this.baseURL + `/segments/${id}`, data);
2901
+ return segment;
2902
+ }
2903
+
2904
+ /**
2905
+ * addSegmentTargets - Add targets to a segment
2906
+ *
2907
+ * @param {string} id Segment ID
2908
+ * @param {string[]} targets Targets to add to the segment
2909
+ *
2910
+ * @return {APIResponse} API response
2911
+ */
2912
+ async addSegmentTargets(id: string, targets: string[]) {
2913
+ const body = { targets };
2914
+ return await this.post<APIResponse>(this.baseURL + `/segments/${id}/addtargets`, body);
2915
+ }
2916
+
2917
+ /**
2918
+ * deleteSegmentTargets - Delete targets from a segment
2919
+ *
2920
+ * @param {string} id Segment ID
2921
+ * @param {string[]} targets Targets to add to the segment
2840
2922
  *
2923
+ * @return {APIResponse} API response
2924
+ */
2925
+ async deleteSegmentTargets(id: string, targets: string[]) {
2926
+ const body = { targets };
2927
+ return await this.post<APIResponse>(this.baseURL + `/segments/${id}/deletetargets`, body);
2928
+ }
2929
+
2930
+ /**
2931
+ * querySegments - Query Segments
2932
+ *
2933
+ * @param {filter} filter MongoDB style filter conditions
2934
+ * @param {QuerySegmentsOptions} options Options for sorting/paginating the results
2841
2935
  *
2842
2936
  * @return {Segment[]} Segments
2843
2937
  */
2844
- async querySegments(filters: SegmentFilters, options: SegmentQueryOptions = {}) {
2938
+ async querySegments(filter: {}, options: QuerySegmentsOptions = {}) {
2845
2939
  return await this.get<{
2846
2940
  segments: Segment[];
2847
2941
  }>(this.baseURL + `/segments`, {
2848
2942
  payload: {
2849
- filter_conditions: filters,
2943
+ filter,
2850
2944
  ...options,
2851
2945
  },
2852
2946
  });
2853
2947
  }
2854
2948
 
2855
2949
  /**
2856
- * updateSegment - Update a Campaign Segment
2950
+ * deleteSegment - Delete a Campaign Segment
2857
2951
  *
2858
2952
  * @param {string} id Segment ID
2859
- * @param {Partial<SegmentData>} params Segment data
2860
2953
  *
2861
- * @return {Segment} Updated Segment
2954
+ * @return {Promise<APIResponse>} The Server Response
2862
2955
  */
2863
- async updateSegment(id: string, params: Partial<SegmentData>) {
2864
- const { segment } = await this.put<{ segment: Segment }>(this.baseURL + `/segments/${id}`, { segment: params });
2865
- return segment;
2956
+ async deleteSegment(id: string) {
2957
+ return await this.delete<APIResponse>(this.baseURL + `/segments/${id}`);
2866
2958
  }
2867
2959
 
2868
2960
  /**
2869
- * deleteSegment - Delete a Campaign Segment
2961
+ * segmentTargetExists - Check if a target exists in a segment
2870
2962
  *
2871
- * @param {string} id Segment ID
2963
+ * @param {string} segmentId Segment ID
2964
+ * @param {string} targetId Target ID
2872
2965
  *
2873
2966
  * @return {Promise<APIResponse>} The Server Response
2874
2967
  */
2875
- async deleteSegment(id: string) {
2876
- return this.delete<APIResponse>(this.baseURL + `/segments/${id}`);
2968
+ async segmentTargetExists(segmentId: string, targetId: string) {
2969
+ return await this.get<APIResponse>(this.baseURL + `/segments/${segmentId}/target/${targetId}`);
2877
2970
  }
2878
2971
 
2879
2972
  /**
@@ -2987,27 +3080,6 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
2987
3080
  return await this.post<APIResponse & TestCampaignResponse>(this.baseURL + `/campaigns/${id}/test`, { users });
2988
3081
  }
2989
3082
 
2990
- /**
2991
- * queryRecipients - Query Campaign Recipient Results
2992
- *
2993
- *
2994
- * @return {Recipient[]} Recipients
2995
- */
2996
- async queryRecipients(filters: RecipientFilters, options: RecipientQueryOptions = {}) {
2997
- return await this.get<{
2998
- campaigns: Record<string, Campaign>;
2999
- recipients: Recipient[];
3000
- segments: Record<string, Segment>;
3001
- channels?: Record<string, ChannelResponse<StreamChatGenerics>>;
3002
- users?: Record<string, UserResponse<StreamChatGenerics>>;
3003
- }>(this.baseURL + `/recipients`, {
3004
- payload: {
3005
- filter_conditions: filters,
3006
- ...options,
3007
- },
3008
- });
3009
- }
3010
-
3011
3083
  /**
3012
3084
  * enrichURL - Get OpenGraph data of the given link
3013
3085
  *
@@ -3052,16 +3124,16 @@ export class StreamChat<StreamChatGenerics extends ExtendableGenerics = DefaultG
3052
3124
  *
3053
3125
  * @return {TaskResponse} A task ID
3054
3126
  */
3055
- async deleteUsers(user_ids: string[], options: DeleteUserOptions) {
3056
- if (options?.user !== 'soft' && options?.user !== 'hard') {
3057
- throw new Error('Invalid delete user options. user must be one of [soft hard]');
3127
+ async deleteUsers(user_ids: string[], options: DeleteUserOptions = {}) {
3128
+ if (typeof options.user !== 'undefined' && !['soft', 'hard', 'pruning'].includes(options.user)) {
3129
+ throw new Error('Invalid delete user options. user must be one of [soft hard pruning]');
3058
3130
  }
3059
- if (options.messages !== undefined && options.messages !== 'soft' && options.messages !== 'hard') {
3060
- throw new Error('Invalid delete user options. messages must be one of [soft hard]');
3061
- }
3062
- if (options.conversations !== undefined && options.conversations !== 'soft' && options.conversations !== 'hard') {
3131
+ if (typeof options.conversations !== 'undefined' && !['soft', 'hard'].includes(options.conversations)) {
3063
3132
  throw new Error('Invalid delete user options. conversations must be one of [soft hard]');
3064
3133
  }
3134
+ if (typeof options.messages !== 'undefined' && !['soft', 'hard', 'pruning'].includes(options.messages)) {
3135
+ throw new Error('Invalid delete user options. messages must be one of [soft hard pruning]');
3136
+ }
3065
3137
  return await this.post<APIResponse & TaskResponse>(this.baseURL + `/users/delete`, {
3066
3138
  user_ids,
3067
3139
  ...options,
package/src/events.ts CHANGED
@@ -24,6 +24,7 @@ export const EVENT_MAP = {
24
24
  'notification.invite_rejected': true,
25
25
  'notification.invited': true,
26
26
  'notification.mark_read': true,
27
+ 'notification.mark_unread': true,
27
28
  'notification.message_new': true,
28
29
  'notification.mutes_updated': true,
29
30
  'notification.removed_from_channel': true,
package/src/types.ts CHANGED
@@ -114,6 +114,10 @@ export type AppSettingsAPIResponse<StreamChatGenerics extends ExtendableGenerics
114
114
  campaign_enabled?: boolean;
115
115
  cdn_expiration_seconds?: number;
116
116
  custom_action_handler_url?: string;
117
+ datadog_info?: {
118
+ api_key: string;
119
+ site: string;
120
+ };
117
121
  disable_auth_checks?: boolean;
118
122
  disable_permissions_checks?: boolean;
119
123
  enforce_unique_usernames?: 'no' | 'app' | 'team';
@@ -247,6 +251,7 @@ export type BannedUsersResponse<StreamChatGenerics extends ExtendableGenerics =
247
251
 
248
252
  export type BlockListResponse = BlockList & {
249
253
  created_at?: string;
254
+ type?: string;
250
255
  updated_at?: string;
251
256
  };
252
257
 
@@ -508,6 +513,10 @@ export type GetUnreadCountAPIResponse = APIResponse & {
508
513
  total_unread_count: number;
509
514
  };
510
515
 
516
+ export type GetUnreadCountBatchAPIResponse = APIResponse & {
517
+ counts_by_user: { [userId: string]: GetUnreadCountAPIResponse };
518
+ };
519
+
511
520
  export type ListChannelResponse<StreamChatGenerics extends ExtendableGenerics = DefaultGenerics> = APIResponse & {
512
521
  channel_types: Record<
513
522
  string,
@@ -558,6 +567,7 @@ export type MessageResponseBase<
558
567
  };
559
568
  latest_reactions?: ReactionResponse<StreamChatGenerics>[];
560
569
  mentioned_users?: UserResponse<StreamChatGenerics>[];
570
+ moderation_details?: ModerationDetailsResponse;
561
571
  own_reactions?: ReactionResponse<StreamChatGenerics>[] | null;
562
572
  pin_expires?: string | null;
563
573
  pinned_at?: string | null;
@@ -571,6 +581,18 @@ export type MessageResponseBase<
571
581
  updated_at?: string;
572
582
  };
573
583
 
584
+ export type ModerationDetailsResponse = {
585
+ action: 'MESSAGE_RESPONSE_ACTION_BOUNCE' | (string & {});
586
+ error_msg: string;
587
+ harms: ModerationHarmResponse[];
588
+ original_text: string;
589
+ };
590
+
591
+ export type ModerationHarmResponse = {
592
+ name: string;
593
+ phrase_list_ids: number[];
594
+ };
595
+
574
596
  export type MuteResponse<StreamChatGenerics extends ExtendableGenerics = DefaultGenerics> = {
575
597
  user: UserResponse<StreamChatGenerics>;
576
598
  created_at?: string;
@@ -1055,8 +1077,13 @@ export type Event<StreamChatGenerics extends ExtendableGenerics = DefaultGeneric
1055
1077
  cid?: string;
1056
1078
  clear_history?: boolean;
1057
1079
  connection_id?: string;
1080
+ // event creation timestamp, format Date ISO string
1058
1081
  created_at?: string;
1082
+ // id of the message that was marked as unread - all the following messages are considered unread. (notification.mark_unread)
1083
+ first_unread_message_id?: string;
1059
1084
  hard_delete?: boolean;
1085
+ // creation date of a message with last_read_message_id, formatted as Date ISO string
1086
+ last_read_at?: string;
1060
1087
  last_read_message_id?: string;
1061
1088
  mark_messages_deleted?: boolean;
1062
1089
  me?: OwnUserResponse<StreamChatGenerics>;
@@ -1072,9 +1099,14 @@ export type Event<StreamChatGenerics extends ExtendableGenerics = DefaultGeneric
1072
1099
  reaction?: ReactionResponse<StreamChatGenerics>;
1073
1100
  received_at?: string | Date;
1074
1101
  team?: string;
1102
+ // @deprecated number of all unread messages across all current user's unread channels, equals unread_count
1075
1103
  total_unread_count?: number;
1104
+ // number of all current user's channels with at least one unread message including the channel in this event
1076
1105
  unread_channels?: number;
1106
+ // number of all unread messages across all current user's unread channels
1077
1107
  unread_count?: number;
1108
+ // number of unread messages in the channel from this event (notification.mark_unread)
1109
+ unread_messages?: number;
1078
1110
  user?: UserResponse<StreamChatGenerics>;
1079
1111
  user_id?: string;
1080
1112
  watcher_count?: number;
@@ -2365,40 +2397,68 @@ export type DeleteChannelsResponse = {
2365
2397
  result: Record<string, string>;
2366
2398
  } & Partial<TaskResponse>;
2367
2399
 
2368
- export type DeleteType = 'soft' | 'hard';
2400
+ export type DeleteType = 'soft' | 'hard' | 'pruning';
2369
2401
 
2370
2402
  /*
2371
2403
  DeleteUserOptions specifies a collection of one or more `user_ids` to be deleted.
2372
2404
 
2373
- `user` soft|hard determines if the user needs to be hard- or soft-deleted, where hard-delete
2374
- implies that all related objects (messages, flags, etc) will be hard-deleted as well.
2375
- `conversations` soft|hard will delete any 1to1 channels that the user was a member of.
2376
- `messages` soft-hard will delete any messages that the user has sent.
2377
- `new_channel_owner_id` any channels owned by the hard-deleted user will be transferred to this user ID
2405
+ `user`:
2406
+ - soft: marks user as deleted and retains all user data
2407
+ - pruning: marks user as deleted and nullifies user information
2408
+ - hard: deletes user completely - this requires hard option for messages and conversation as well
2409
+ `conversations`:
2410
+ - soft: marks all conversation channels as deleted (same effect as Delete Channels with 'hard' option disabled)
2411
+ - hard: deletes channel and all its data completely including messages (same effect as Delete Channels with 'hard' option enabled)
2412
+ `messages`:
2413
+ - soft: marks all user messages as deleted without removing any related message data
2414
+ - pruning: marks all user messages as deleted, nullifies message information and removes some message data such as reactions and flags
2415
+ - hard: deletes messages completely with all related information
2416
+ `new_channel_owner_id`: any channels owned by the hard-deleted user will be transferred to this user ID
2378
2417
  */
2379
2418
  export type DeleteUserOptions = {
2380
- user: DeleteType;
2381
- conversations?: DeleteType;
2419
+ conversations?: Exclude<DeleteType, 'pruning'>;
2382
2420
  messages?: DeleteType;
2383
2421
  new_channel_owner_id?: string;
2422
+ user?: DeleteType;
2384
2423
  };
2385
2424
 
2425
+ export type SegmentType = 'channel' | 'user';
2426
+
2386
2427
  export type SegmentData = {
2387
2428
  description: string;
2388
2429
  filter: {};
2389
- name: string;
2390
- type: 'channel' | 'user';
2391
2430
  };
2392
2431
 
2393
2432
  export type Segment = {
2394
2433
  created_at: string;
2434
+ deleted_at: string;
2395
2435
  id: string;
2396
- in_use: boolean;
2436
+ locked: boolean;
2437
+ name: string;
2397
2438
  size: number;
2398
- status: 'computing' | 'ready';
2439
+ type: SegmentType;
2399
2440
  updated_at: string;
2400
2441
  } & SegmentData;
2401
2442
 
2443
+ export type UpdateSegmentData = {
2444
+ name: string;
2445
+ } & SegmentData;
2446
+
2447
+ export type SortParam = {
2448
+ field: string;
2449
+ direction?: AscDesc;
2450
+ };
2451
+
2452
+ export type Pager = {
2453
+ limit?: number;
2454
+ next?: string;
2455
+ prev?: string;
2456
+ };
2457
+
2458
+ export type QuerySegmentsOptions = {
2459
+ sort?: SortParam[];
2460
+ } & Pager;
2461
+
2402
2462
  export type CampaignSortField = {
2403
2463
  field: string;
2404
2464
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -2416,12 +2476,9 @@ export type CampaignQueryOptions = {
2416
2476
  };
2417
2477
 
2418
2478
  export type SegmentQueryOptions = CampaignQueryOptions;
2419
- export type RecipientQueryOptions = CampaignQueryOptions;
2420
2479
 
2421
2480
  // TODO: add better typing
2422
- export type SegmentFilters = {};
2423
2481
  export type CampaignFilters = {};
2424
- export type RecipientFilters = {};
2425
2482
 
2426
2483
  export type CampaignData = {
2427
2484
  attachments: Attachment[];
@@ -2462,20 +2519,7 @@ export type TestCampaignResponse = {
2462
2519
  results?: Record<string, string>;
2463
2520
  };
2464
2521
 
2465
- export type DeleteCampaignOptions = {
2466
- recipients?: boolean;
2467
- };
2468
-
2469
- export type Recipient = {
2470
- campaign_id: string;
2471
- channel_cid: string;
2472
- created_at: string;
2473
- status: 'pending' | 'sent' | 'failed';
2474
- updated_at: string;
2475
- details?: string;
2476
- message_id?: string;
2477
- receiver_id?: string;
2478
- };
2522
+ export type DeleteCampaignOptions = {};
2479
2523
 
2480
2524
  export type TaskStatus = {
2481
2525
  created_at: string;