From 969398891ff62cf47285256241fb5d7b02ef7ee6 Mon Sep 17 00:00:00 2001 From: Aditya Alif Nugraha Date: Fri, 25 Jul 2025 14:33:03 +0200 Subject: [PATCH 1/6] feat: add get hook event list client --- src/client.ts | 16 +++++++++++ src/types.ts | 10 +++++++ test/unit/client.test.js | 62 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/src/client.ts b/src/client.ts index dc113230e..fe872cb60 100644 --- a/src/client.ts +++ b/src/client.ts @@ -106,6 +106,7 @@ import type { GetCampaignOptions, GetChannelTypeResponse, GetCommandResponse, + GetHookEventsResponse, GetImportResponse, GetMessageAPIResponse, GetMessageOptions, @@ -116,6 +117,7 @@ import type { GetThreadOptions, GetUnreadCountAPIResponse, GetUnreadCountBatchAPIResponse, + HookEvent, ListChannelResponse, ListCommandsResponse, ListImportsPaginationOptions, @@ -2164,6 +2166,20 @@ export class StreamChat { }); } + /** + * getHookEvents - Get available events for hooks (webhook, SQS, and SNS) + * + * @param {string[]} [products] Optional array of products to filter events by (e.g., ['chat', 'video', 'moderation']) + * @returns {Promise} Response containing available hook events + */ + async getHookEvents(products?: string[]) { + const params = products && products.length > 0 ? { product: products } : {}; + return await this.get( + this.baseURL + '/v1/hook/events', + params, + ); + } + _addChannelConfig({ cid, config }: ChannelResponse) { if (this._cacheEnabled()) { this.configs[cid] = config; diff --git a/src/types.ts b/src/types.ts index b57fc9de4..7114c723e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -576,6 +576,16 @@ export type GetRateLimitsResponse = APIResponse & { web?: RateLimitsMap; }; +export type HookEvent = { + name: string; + description: string; + products: string[]; +}; + +export type GetHookEventsResponse = APIResponse & { + events: HookEvent[]; +}; + export type GetReactionsAPIResponse = APIResponse & { reactions: ReactionResponse[]; }; diff --git a/test/unit/client.test.js b/test/unit/client.test.js index 3da8d42cc..217e89a86 100644 --- a/test/unit/client.test.js +++ b/test/unit/client.test.js @@ -1128,4 +1128,66 @@ describe('X-Stream-Client header', () => { expect(userAgent).toMatchInlineSnapshot(`"deprecated"`); }); + + describe('getHookEvents', () => { + let clientGetSpy; + + beforeEach(() => { + clientGetSpy = vi.spyOn(client, 'get').mockResolvedValue({}); + }); + + it('should call get with correct URL and no params when no products specified', async () => { + await client.getHookEvents(); + + expect(clientGetSpy).toHaveBeenCalledTimes(1); + expect(clientGetSpy).toHaveBeenCalledWith(`${client.baseURL}/v1/hook/events`, {}); + }); + + it('should call get with correct URL and empty params when empty products array specified', async () => { + await client.getHookEvents([]); + + expect(clientGetSpy).toHaveBeenCalledTimes(1); + expect(clientGetSpy).toHaveBeenCalledWith(`${client.baseURL}/v1/hook/events`, {}); + }); + + it('should call get with product params when products specified', async () => { + await client.getHookEvents(['chat', 'video']); + + expect(clientGetSpy).toHaveBeenCalledTimes(1); + expect(clientGetSpy).toHaveBeenCalledWith(`${client.baseURL}/v1/hook/events`, { + product: ['chat', 'video'], + }); + }); + + it('should call get with single product param', async () => { + await client.getHookEvents(['chat']); + + expect(clientGetSpy).toHaveBeenCalledTimes(1); + expect(clientGetSpy).toHaveBeenCalledWith(`${client.baseURL}/v1/hook/events`, { + product: ['chat'], + }); + }); + + it('should return the response from get', async () => { + const mockResponse = { + events: [ + { + name: 'message.new', + description: 'When a new message is added', + products: ['chat'], + }, + { + name: 'call.created', + description: 'The call was created', + products: ['video'], + }, + ], + }; + clientGetSpy.mockResolvedValue(mockResponse); + + const result = await client.getHookEvents(['chat', 'video']); + + expect(result).toEqual(mockResponse); + }); + }); }); From dc3b8fbf731f589ffa92c28479121413ea594720 Mon Sep 17 00:00:00 2001 From: Aditya Alif Nugraha Date: Fri, 25 Jul 2025 15:30:48 +0200 Subject: [PATCH 2/6] fix: query param --- src/client.ts | 2 +- test/unit/client.test.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/client.ts b/src/client.ts index fe872cb60..35c0e667b 100644 --- a/src/client.ts +++ b/src/client.ts @@ -2173,7 +2173,7 @@ export class StreamChat { * @returns {Promise} Response containing available hook events */ async getHookEvents(products?: string[]) { - const params = products && products.length > 0 ? { product: products } : {}; + const params = products && products.length > 0 ? { product: products.join(',') } : {}; return await this.get( this.baseURL + '/v1/hook/events', params, diff --git a/test/unit/client.test.js b/test/unit/client.test.js index 217e89a86..1e526bd1a 100644 --- a/test/unit/client.test.js +++ b/test/unit/client.test.js @@ -1155,7 +1155,7 @@ describe('X-Stream-Client header', () => { expect(clientGetSpy).toHaveBeenCalledTimes(1); expect(clientGetSpy).toHaveBeenCalledWith(`${client.baseURL}/v1/hook/events`, { - product: ['chat', 'video'], + product: 'chat,video', }); }); @@ -1164,7 +1164,7 @@ describe('X-Stream-Client header', () => { expect(clientGetSpy).toHaveBeenCalledTimes(1); expect(clientGetSpy).toHaveBeenCalledWith(`${client.baseURL}/v1/hook/events`, { - product: ['chat'], + product: 'chat', }); }); From 6ad0749769892add9e64e9f42b1912d38b61dfa7 Mon Sep 17 00:00:00 2001 From: Aditya Alif Nugraha Date: Fri, 25 Jul 2025 15:32:24 +0200 Subject: [PATCH 3/6] fix: query param --- src/client.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/client.ts b/src/client.ts index 35c0e667b..e9937cb71 100644 --- a/src/client.ts +++ b/src/client.ts @@ -2174,10 +2174,7 @@ export class StreamChat { */ async getHookEvents(products?: string[]) { const params = products && products.length > 0 ? { product: products.join(',') } : {}; - return await this.get( - this.baseURL + '/v1/hook/events', - params, - ); + return await this.get(this.baseURL + '/hook/events', params); } _addChannelConfig({ cid, config }: ChannelResponse) { From dd884b9df5f82bd805df313f7067876f0b0b90b1 Mon Sep 17 00:00:00 2001 From: Aditya Alif Nugraha Date: Tue, 29 Jul 2025 09:34:13 +0200 Subject: [PATCH 4/6] fix: add product enum --- src/client.ts | 5 +++-- src/types.ts | 9 ++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/client.ts b/src/client.ts index e9937cb71..8ba18e5c1 100644 --- a/src/client.ts +++ b/src/client.ts @@ -36,6 +36,7 @@ import type { APIErrorResponse, APIResponse, AppSettings, + Product, AppSettingsAPIResponse, BannedUsersFilters, BannedUsersPaginationOptions, @@ -2169,10 +2170,10 @@ export class StreamChat { /** * getHookEvents - Get available events for hooks (webhook, SQS, and SNS) * - * @param {string[]} [products] Optional array of products to filter events by (e.g., ['chat', 'video', 'moderation']) + * @param {Product[]} [products] Optional array of products to filter events by (e.g., [Product.Chat, Product.Video]) * @returns {Promise} Response containing available hook events */ - async getHookEvents(products?: string[]) { + async getHookEvents(products?: Product[]) { const params = products && products.length > 0 ? { product: products.join(',') } : {}; return await this.get(this.baseURL + '/hook/events', params); } diff --git a/src/types.ts b/src/types.ts index 7114c723e..c7ee95c14 100644 --- a/src/types.ts +++ b/src/types.ts @@ -576,10 +576,17 @@ export type GetRateLimitsResponse = APIResponse & { web?: RateLimitsMap; }; +export enum Product { + Chat = 'chat', + Video = 'video', + Moderation = 'moderation', + Feeds = 'feeds', +} + export type HookEvent = { name: string; description: string; - products: string[]; + products: Product[]; }; export type GetHookEventsResponse = APIResponse & { From 8ba24d8dfe94688242f6b3db124557feae45731d Mon Sep 17 00:00:00 2001 From: Aditya Alif Nugraha Date: Tue, 29 Jul 2025 09:43:05 +0200 Subject: [PATCH 5/6] fix: lint --- src/client.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/client.ts b/src/client.ts index 8ba18e5c1..39a285fe0 100644 --- a/src/client.ts +++ b/src/client.ts @@ -36,7 +36,6 @@ import type { APIErrorResponse, APIResponse, AppSettings, - Product, AppSettingsAPIResponse, BannedUsersFilters, BannedUsersPaginationOptions, @@ -118,7 +117,6 @@ import type { GetThreadOptions, GetUnreadCountAPIResponse, GetUnreadCountBatchAPIResponse, - HookEvent, ListChannelResponse, ListCommandsResponse, ListImportsPaginationOptions, @@ -151,6 +149,7 @@ import type { PollVote, PollVoteData, PollVotesAPIResponse, + Product, PushPreference, PushProvider, PushProviderConfig, From dc6fc3b0250ff6a389a5a23008a24e590ea92696 Mon Sep 17 00:00:00 2001 From: Aditya Alif Nugraha Date: Tue, 29 Jul 2025 09:46:13 +0200 Subject: [PATCH 6/6] fix: test --- test/unit/client.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unit/client.test.js b/test/unit/client.test.js index 1e526bd1a..483489732 100644 --- a/test/unit/client.test.js +++ b/test/unit/client.test.js @@ -1140,21 +1140,21 @@ describe('X-Stream-Client header', () => { await client.getHookEvents(); expect(clientGetSpy).toHaveBeenCalledTimes(1); - expect(clientGetSpy).toHaveBeenCalledWith(`${client.baseURL}/v1/hook/events`, {}); + expect(clientGetSpy).toHaveBeenCalledWith(`${client.baseURL}/hook/events`, {}); }); it('should call get with correct URL and empty params when empty products array specified', async () => { await client.getHookEvents([]); expect(clientGetSpy).toHaveBeenCalledTimes(1); - expect(clientGetSpy).toHaveBeenCalledWith(`${client.baseURL}/v1/hook/events`, {}); + expect(clientGetSpy).toHaveBeenCalledWith(`${client.baseURL}/hook/events`, {}); }); it('should call get with product params when products specified', async () => { await client.getHookEvents(['chat', 'video']); expect(clientGetSpy).toHaveBeenCalledTimes(1); - expect(clientGetSpy).toHaveBeenCalledWith(`${client.baseURL}/v1/hook/events`, { + expect(clientGetSpy).toHaveBeenCalledWith(`${client.baseURL}/hook/events`, { product: 'chat,video', }); }); @@ -1163,7 +1163,7 @@ describe('X-Stream-Client header', () => { await client.getHookEvents(['chat']); expect(clientGetSpy).toHaveBeenCalledTimes(1); - expect(clientGetSpy).toHaveBeenCalledWith(`${client.baseURL}/v1/hook/events`, { + expect(clientGetSpy).toHaveBeenCalledWith(`${client.baseURL}/hook/events`, { product: 'chat', }); });