From 89543ab3710551e109bb091397e3f0b697476c21 Mon Sep 17 00:00:00 2001 From: devlikepro Date: Mon, 31 Aug 2026 17:05:33 +0700 Subject: [PATCH] chore: EventWildUnmask support wildcard - group.* --- src/utils/events.test.ts | 49 +++++++++++++++++++++++++++++++++++----- src/utils/events.ts | 16 +++++++++---- 2 files changed, 55 insertions(+), 10 deletions(-) diff --git a/src/utils/events.test.ts b/src/utils/events.test.ts index 95d5b8f5..ef37d18b 100644 --- a/src/utils/events.test.ts +++ b/src/utils/events.test.ts @@ -3,10 +3,19 @@ import { EventWildUnmask } from './events'; enum TestEvents { MESSAGE = 'message', MESSAGE_ANY = 'message.any', + MESSAGE_ACK = 'message.ack', + GROUP_JOIN = 'group.join', + GROUP_V2_JOIN = 'group.v2.join', STATE_CHANGE = 'state.change', } -const WILD = [TestEvents.MESSAGE, TestEvents.MESSAGE_ANY]; +const WILD = [ + TestEvents.MESSAGE, + TestEvents.MESSAGE_ANY, + TestEvents.MESSAGE_ACK, + TestEvents.GROUP_JOIN, + TestEvents.GROUP_V2_JOIN, +]; describe('EventWildUnmask', () => { const unmask = new EventWildUnmask(TestEvents, WILD); @@ -19,7 +28,7 @@ describe('EventWildUnmask', () => { 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.events).toEqual(WILD); expect(result.unknown).toEqual([]); }); @@ -28,22 +37,50 @@ describe('EventWildUnmask', () => { expect(unmask.unmask(['state.change']).events).toEqual(['state.change']); }); + it('should expand prefix wildcards', () => { + const result = unmask.unmask(['message.*']); + expect(result.events).toEqual(['message.any', 'message.ack']); + expect(result.unknown).toEqual([]); + }); + + it('should expand group.* including nested events', () => { + const result = unmask.unmask(['group.*']); + expect(result.events).toEqual(['group.join', 'group.v2.join']); + expect(result.unknown).toEqual([]); + }); + + it('should not include internal events in prefix wildcards', () => { + const result = unmask.unmask(['state.*']); + expect(result.events).toEqual([]); + expect(result.unknown).toEqual(['state.*']); + }); + + it('should report prefix wildcards with no matches as unknown', () => { + const result = unmask.unmask(['nope.*']); + expect(result.events).toEqual([]); + expect(result.unknown).toEqual(['nope.*']); + }); + 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']); + it('should combine *, prefixes, known and unknown events', () => { + const result = unmask.unmask(['message.*', 'state.change', 'nope', 'nope']); + expect(result.events).toEqual([ + 'message.any', + 'message.ack', + '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.events).toEqual(Object.values(TestEvents)); expect(result.unknown).toEqual([]); }); diff --git a/src/utils/events.ts b/src/utils/events.ts index e5ba7092..9960c4ed 100644 --- a/src/utils/events.ts +++ b/src/utils/events.ts @@ -15,12 +15,20 @@ export class EventWildUnmask { unmask(events: string[]): { events: string[]; unknown: string[] } { const rightEvents = []; const unknown = []; - if (events.includes('*')) { - rightEvents.push(...this.all); - } - for (const event of events) { if (event === '*') { + rightEvents.push(...this.all); + continue; + } + // Prefix wildcard - 'message.*' matches everything starting with 'message.' + if (event.includes('*')) { + const prefix = event.split('*')[0]; + const matched = this.all.filter((known) => known.startsWith(prefix)); + if (matched.length === 0) { + unknown.push(event); + continue; + } + rightEvents.push(...matched); continue; } if (!this.events.includes(event)) {