From 5ea11dbaef4683ad0b2e58716190973180965294 Mon Sep 17 00:00:00 2001 From: Jimmy Pettersson <953852+JimmyPettersson85@users.noreply.github.com> Date: Thu, 25 Jan 2024 14:57:08 +0100 Subject: [PATCH 1/5] feat: add batch unread endpoint (#1212) Co-authored-by: Vishal Narkhede --- src/client.ts | 19 +++++++++++++++++++ src/types.ts | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/src/client.ts b/src/client.ts index 5b464b984..4426ec5ed 100644 --- a/src/client.ts +++ b/src/client.ts @@ -96,6 +96,7 @@ import { GetMessageAPIResponse, GetRateLimitsResponse, GetUnreadCountAPIResponse, + GetUnreadCountBatchAPIResponse, ListChannelResponse, ListCommandsResponse, ListImportsPaginationOptions, @@ -1688,10 +1689,28 @@ export class StreamChat} + */ async getUnreadCount(userID?: string) { return await this.get(this.baseURL + '/unread', userID ? { user_id: userID } : {}); } + /** + * getUnreadCountBatch - Returns unread counts for multiple users at once. Only works server side. + * + * @param {string[]} [userIDs] List of user IDs to fetch unread counts for. + * + * @return {} + */ + async getUnreadCountBatch(userIDs: string[]) { + return await this.post(this.baseURL + '/unread_batch', { user_ids: userIDs }); + } + /** * removeDevice - Removes the device with the given id. Clientside users can only delete their own devices * diff --git a/src/types.ts b/src/types.ts index 422ad9be9..cbf451b77 100644 --- a/src/types.ts +++ b/src/types.ts @@ -513,6 +513,10 @@ export type GetUnreadCountAPIResponse = APIResponse & { total_unread_count: number; }; +export type GetUnreadCountBatchAPIResponse = APIResponse & { + counts_by_user: { [userId: string]: GetUnreadCountAPIResponse }; +}; + export type ListChannelResponse = APIResponse & { channel_types: Record< string, From d2bf603673400bdcb57b75989825eb3cb638eee9 Mon Sep 17 00:00:00 2001 From: Yassine Ennebati <4570448+yaziine@users.noreply.github.com> Date: Tue, 30 Jan 2024 13:35:17 +0400 Subject: [PATCH 2/5] feat: segments API v2 (#1205) --- src/client.ts | 139 ++++++++++++++++++++++++++++++++++---------------- src/types.ts | 47 +++++++++-------- 2 files changed, 122 insertions(+), 64 deletions(-) diff --git a/src/client.ts b/src/client.ts index 4426ec5ed..690100192 100644 --- a/src/client.ts +++ b/src/client.ts @@ -124,12 +124,10 @@ import { PushProviderListResponse, PushProviderUpsertResponse, QueryChannelsAPIResponse, + QuerySegmentsOptions, ReactionResponse, ReactivateUserOptions, ReactivateUsersOptions, - Recipient, - RecipientFilters, - RecipientQueryOptions, ReservedMessageFields, ReviewFlagReportOptions, ReviewFlagReportResponse, @@ -139,8 +137,7 @@ import { SearchPayload, Segment, SegmentData, - SegmentFilters, - SegmentQueryOptions, + SegmentType, SendFileAPIResponse, StreamChatOptions, SyncOptions, @@ -160,6 +157,7 @@ import { UpdatedMessage, UpdateMessageAPIResponse, UpdateMessageOptions, + UpdateSegmentData, UserCustomEvent, UserFilters, UserOptions, @@ -2843,56 +2841,132 @@ export class StreamChat(this.baseURL + `/segments`, { segment: params }); + private async createSegment(type: SegmentType, id: string, name: string, data?: SegmentData): Promise { + const body = { + id, + type, + name, + data, + }; + const { segment } = await this.post<{ segment: Segment }>(this.baseURL + `/segments`, body); return segment; } /** - * querySegments - Query Campaign Segments + * createUserSegment - Creates a user segment + * + * @param {string} id Segment ID (valid UUID) + * @param {string} name Segment name + * @param {SegmentData} data Segment data + * + * @return {Segment} The created Segment + */ + async createUserSegment(id: string, name: string, data?: SegmentData): Promise { + return await this.createSegment('user', id, name, data); + } + + /** + * createChannelSegment - Creates a channel segment + * + * @param {string} id Segment ID (valid UUID) + * @param {string} name Segment name + * @param {SegmentData} data Segment data + * + * @return {Segment} The created Segment + */ + async createChannelSegment(id: string, name: string, data?: SegmentData): Promise { + return await this.createSegment('channel', id, name, data); + } + + /** + * updateSegment - Update a segment + * + * @param {string} id Segment ID + * @param {Partial} data Data to update + * + * @return {Segment} Updated Segment + */ + async updateSegment(id: string, data: Partial) { + const { segment } = await this.put<{ segment: Segment }>(this.baseURL + `/segments/${id}`, data); + return segment; + } + + /** + * addSegmentTargets - Add targets to a segment + * + * @param {string} id Segment ID + * @param {string[]} targets Targets to add to the segment + * + * @return {APIResponse} API response + */ + async addSegmentTargets(id: string, targets: string[]) { + const body = { targets }; + return await this.post(this.baseURL + `/segments/${id}/addtargets`, body); + } + + /** + * deleteSegmentTargets - Delete targets from a segment * + * @param {string} id Segment ID + * @param {string[]} targets Targets to add to the segment + * + * @return {APIResponse} API response + */ + async deleteSegmentTargets(id: string, targets: string[]) { + const body = { targets }; + return await this.post(this.baseURL + `/segments/${id}/deletetargets`, body); + } + + /** + * querySegments - Query Segments + * + * @param {filter} filter MongoDB style filter conditions + * @param {QuerySegmentsOptions} options Options for sorting/paginating the results * * @return {Segment[]} Segments */ - async querySegments(filters: SegmentFilters, options: SegmentQueryOptions = {}) { + async querySegments(filter: {}, options: QuerySegmentsOptions = {}) { return await this.get<{ segments: Segment[]; }>(this.baseURL + `/segments`, { payload: { - filter_conditions: filters, + filter, ...options, }, }); } /** - * updateSegment - Update a Campaign Segment + * deleteSegment - Delete a Campaign Segment * * @param {string} id Segment ID - * @param {Partial} params Segment data * - * @return {Segment} Updated Segment + * @return {Promise} The Server Response */ - async updateSegment(id: string, params: Partial) { - const { segment } = await this.put<{ segment: Segment }>(this.baseURL + `/segments/${id}`, { segment: params }); - return segment; + async deleteSegment(id: string) { + return await this.delete(this.baseURL + `/segments/${id}`); } /** - * deleteSegment - Delete a Campaign Segment + * segmentTargetExists - Check if a target exists in a segment * - * @param {string} id Segment ID + * @param {string} segmentId Segment ID + * @param {string} targetId Target ID * * @return {Promise} The Server Response */ - async deleteSegment(id: string) { - return this.delete(this.baseURL + `/segments/${id}`); + async segmentTargetExists(segmentId: string, targetId: string) { + return await this.get(this.baseURL + `/segments/${segmentId}/target/${targetId}`); } /** @@ -3006,27 +3080,6 @@ export class StreamChat(this.baseURL + `/campaigns/${id}/test`, { users }); } - /** - * queryRecipients - Query Campaign Recipient Results - * - * - * @return {Recipient[]} Recipients - */ - async queryRecipients(filters: RecipientFilters, options: RecipientQueryOptions = {}) { - return await this.get<{ - campaigns: Record; - recipients: Recipient[]; - segments: Record; - channels?: Record>; - users?: Record>; - }>(this.baseURL + `/recipients`, { - payload: { - filter_conditions: filters, - ...options, - }, - }); - } - /** * enrichURL - Get OpenGraph data of the given link * diff --git a/src/types.ts b/src/types.ts index cbf451b77..da3c418a9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -2409,22 +2409,43 @@ export type DeleteUserOptions = { user?: DeleteType; }; +export type SegmentType = 'channel' | 'user'; + export type SegmentData = { description: string; filter: {}; - name: string; - type: 'channel' | 'user'; }; export type Segment = { created_at: string; + deleted_at: string; id: string; - in_use: boolean; + locked: boolean; + name: string; size: number; - status: 'computing' | 'ready'; + type: SegmentType; updated_at: string; } & SegmentData; +export type UpdateSegmentData = { + name: string; +} & SegmentData; + +export type SortParam = { + field: string; + direction?: AscDesc; +}; + +export type Pager = { + limit?: number; + next?: string; + prev?: string; +}; + +export type QuerySegmentsOptions = { + sort?: SortParam[]; +} & Pager; + export type CampaignSortField = { field: string; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -2442,12 +2463,9 @@ export type CampaignQueryOptions = { }; export type SegmentQueryOptions = CampaignQueryOptions; -export type RecipientQueryOptions = CampaignQueryOptions; // TODO: add better typing -export type SegmentFilters = {}; export type CampaignFilters = {}; -export type RecipientFilters = {}; export type CampaignData = { attachments: Attachment[]; @@ -2488,20 +2506,7 @@ export type TestCampaignResponse = { results?: Record; }; -export type DeleteCampaignOptions = { - recipients?: boolean; -}; - -export type Recipient = { - campaign_id: string; - channel_cid: string; - created_at: string; - status: 'pending' | 'sent' | 'failed'; - updated_at: string; - details?: string; - message_id?: string; - receiver_id?: string; -}; +export type DeleteCampaignOptions = {}; export type TaskStatus = { created_at: string; From 2a13b053c7006fd64f7187160ca5ea22e486d3a5 Mon Sep 17 00:00:00 2001 From: Matvei Andrienko Date: Wed, 31 Jan 2024 11:16:40 +0100 Subject: [PATCH 3/5] feat: add moderation types (#1213) --- src/types.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/types.ts b/src/types.ts index da3c418a9..531e21b66 100644 --- a/src/types.ts +++ b/src/types.ts @@ -567,6 +567,7 @@ export type MessageResponseBase< }; latest_reactions?: ReactionResponse[]; mentioned_users?: UserResponse[]; + moderation_details?: ModerationDetailsResponse; own_reactions?: ReactionResponse[] | null; pin_expires?: string | null; pinned_at?: string | null; @@ -580,6 +581,18 @@ export type MessageResponseBase< updated_at?: string; }; +export type ModerationDetailsResponse = { + action: 'MESSAGE_RESPONSE_ACTION_BOUNCE' | (string & {}); + error_msg: string; + harms: ModerationHarmResponse[]; + original_text: string; +}; + +export type ModerationHarmResponse = { + name: string; + phrase_list_ids: number[]; +}; + export type MuteResponse = { user: UserResponse; created_at?: string; From 9cedf6ff14e9cc039722371ada3b7e0a5a2fab05 Mon Sep 17 00:00:00 2001 From: MartinCupela <32706194+MartinCupela@users.noreply.github.com> Date: Thu, 1 Feb 2024 16:07:18 +0100 Subject: [PATCH 4/5] fix: prevent channel unread count reset to 0 when sending message and on new own or thread messages (#1210) --- src/channel.ts | 32 +++++++++++++++----------------- test/unit/channel.js | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 19 deletions(-) diff --git a/src/channel.ts b/src/channel.ts index 2812c2fff..605ea3e73 100644 --- a/src/channel.ts +++ b/src/channel.ts @@ -170,18 +170,10 @@ export class Channel>} The Server Response */ async sendMessage(message: Message, options?: SendMessageOptions) { - const sendMessageResponse = await this.getClient().post>( - this._channelURL() + '/message', - { - message, - ...options, - }, - ); - - // Reset unreadCount to 0. - this.state.unreadCount = 0; - - return sendMessageResponse; + return await this.getClient().post>(this._channelURL() + '/message', { + message, + ...options, + }); } sendFile( @@ -1289,6 +1281,12 @@ export class Channel Date: Thu, 1 Feb 2024 16:19:38 +0100 Subject: [PATCH 5/5] chore: release v8.15.0 (#1218) --- CHANGELOG.md | 16 ++++++++++++++++ package.json | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b7ba5c10..a54d5032f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [8.15.0](https://github.com/GetStream/stream-chat-js/compare/v8.14.5...v8.15.0) (2024-02-01) + + +### Features + +* add batch unread endpoint ([#1212](https://github.com/GetStream/stream-chat-js/issues/1212)) ([5ea11db](https://github.com/GetStream/stream-chat-js/commit/5ea11dbaef4683ad0b2e58716190973180965294)) +* add moderation types ([#1213](https://github.com/GetStream/stream-chat-js/issues/1213)) ([2a13b05](https://github.com/GetStream/stream-chat-js/commit/2a13b053c7006fd64f7187160ca5ea22e486d3a5)) +* handle notification.mark_unread ([#1208](https://github.com/GetStream/stream-chat-js/issues/1208)) ([4d73838](https://github.com/GetStream/stream-chat-js/commit/4d73838c7e9aa174b1367d334a011d579b67573f)) +* segments API v2 ([#1205](https://github.com/GetStream/stream-chat-js/issues/1205)) ([d2bf603](https://github.com/GetStream/stream-chat-js/commit/d2bf603673400bdcb57b75989825eb3cb638eee9)) + + +### Bug Fixes + +* missing types for datadog_info and blocklist type ([33f09b9](https://github.com/GetStream/stream-chat-js/commit/33f09b9fdfb9388312a6e715eba6fff0e5c956f6)) +* prevent channel unread count reset to 0 when sending message and on new own or thread messages ([#1210](https://github.com/GetStream/stream-chat-js/issues/1210)) ([9cedf6f](https://github.com/GetStream/stream-chat-js/commit/9cedf6ff14e9cc039722371ada3b7e0a5a2fab05)) + ### [8.14.5](https://github.com/GetStream/stream-chat-js/compare/v8.14.4...v8.14.5) (2024-01-09) diff --git a/package.json b/package.json index 191028b53..885e9b739 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stream-chat", - "version": "8.14.5", + "version": "8.15.0", "description": "JS SDK for the Stream Chat API", "author": "GetStream", "homepage": "https://getstream.io/chat/",