diff --git a/src/api/websocket.gateway.core.ts b/src/api/websocket.gateway.core.ts index 70df2e14..53da6284 100644 --- a/src/api/websocket.gateway.core.ts +++ b/src/api/websocket.gateway.core.ts @@ -97,7 +97,7 @@ export class WebsocketGatewayCore } this.logger.debug(`New client connected: ${request.url} - ${socket.id}`); - const events: WAHAEvents[] = params.events; + const events = params.events as WAHAEvents[]; this.logger.debug( `Client connected to session: '${session}', events: ${events}, ${socket.id}`, ); @@ -131,8 +131,13 @@ export class WebsocketGatewayCore const paramsEvents = query.getAll('events'); const eventsRaw = paramsEvents.length > 0 ? paramsEvents : ['*']; const eventsList = eventsRaw.flatMap((value) => value.split(',')); - const events = this.eventUnmask.unmask(eventsList); - return { session, events }; + const result = this.eventUnmask.unmask(eventsList); + if (result.unknown.length > 0) { + this.logger.warn( + `Ignoring unknown websocket events: ${result.unknown.join(', ')}`, + ); + } + return { session, events: result.events }; } handleDisconnect(socket: WebSocket): any { diff --git a/src/modules/waha-webhook/WebhookPlugin.ts b/src/modules/waha-webhook/WebhookPlugin.ts index 576d599a..4b37db54 100644 --- a/src/modules/waha-webhook/WebhookPlugin.ts +++ b/src/modules/waha-webhook/WebhookPlugin.ts @@ -34,7 +34,13 @@ export class WebhookPlugin extends SessionPlugin { } private getSuitableEvents(events: WAHAEvents[] | string[]): WAHAEvents[] { - return this.eventUnmask.unmask(events); + const result = this.eventUnmask.unmask(events); + if (result.unknown.length > 0) { + this.logger.warn( + `Ignoring unknown webhook events: ${result.unknown.join(', ')}`, + ); + } + return result.events as WAHAEvents[]; } private configure(webhook: WebhookConfig) { diff --git a/src/utils/events.test.ts b/src/utils/events.test.ts new file mode 100644 index 00000000..95d5b8f5 --- /dev/null +++ b/src/utils/events.test.ts @@ -0,0 +1,55 @@ +import { EventWildUnmask } from './events'; + +enum TestEvents { + MESSAGE = 'message', + MESSAGE_ANY = 'message.any', + STATE_CHANGE = 'state.change', +} + +const WILD = [TestEvents.MESSAGE, TestEvents.MESSAGE_ANY]; + +describe('EventWildUnmask', () => { + const unmask = new EventWildUnmask(TestEvents, WILD); + + it('should keep known events and remove duplicates', () => { + const result = unmask.unmask(['message', 'message.any', 'message']); + expect(result.events).toEqual(['message', 'message.any']); + expect(result.unknown).toEqual([]); + }); + + it('should expand * to the wild list without reporting it as unknown', () => { + const result = unmask.unmask(['*']); + expect(result.events).toEqual(['message', 'message.any']); + expect(result.unknown).toEqual([]); + }); + + it('should not include internal events in * but allow them explicitly', () => { + expect(unmask.unmask(['*']).events).not.toContain('state.change'); + expect(unmask.unmask(['state.change']).events).toEqual(['state.change']); + }); + + it('should return unknown events without failing', () => { + const result = unmask.unmask(['message', 'nope', 'invalid']); + expect(result.events).toEqual(['message']); + expect(result.unknown).toEqual(['nope', 'invalid']); + }); + + it('should combine *, known and unknown events', () => { + const result = unmask.unmask(['*', 'state.change', 'nope', 'nope']); + expect(result.events).toEqual(['message', 'message.any', 'state.change']); + expect(result.unknown).toEqual(['nope']); + }); + + it('should expand * to all events when no wild list is given', () => { + const all = new EventWildUnmask(TestEvents); + const result = all.unmask(['*']); + expect(result.events).toEqual(['message', 'message.any', 'state.change']); + expect(result.unknown).toEqual([]); + }); + + it('should return empty lists for empty input', () => { + const result = unmask.unmask([]); + expect(result.events).toEqual([]); + expect(result.unknown).toEqual([]); + }); +}); diff --git a/src/utils/events.ts b/src/utils/events.ts index 8bfefbde..e5ba7092 100644 --- a/src/utils/events.ts +++ b/src/utils/events.ts @@ -12,20 +12,27 @@ export class EventWildUnmask { this.all = all ? Object.values(all) : this.events; } - unmask(events: string[]) { + unmask(events: string[]): { events: string[]; unknown: string[] } { const rightEvents = []; + const unknown = []; if (events.includes('*')) { rightEvents.push(...this.all); } - // Get only known events, log and ignore others for (const event of events) { + if (event === '*') { + continue; + } if (!this.events.includes(event)) { + unknown.push(event); continue; } rightEvents.push(event); } - // return unique values - return [...new Set(rightEvents)]; + // unique values, the caller decides what to do with unknown ones + return { + events: [...new Set(rightEvents)], + unknown: [...new Set(unknown)], + }; } }