From e52ba1efae45b089e2ceb671c0b7bcbb9ea7a517 Mon Sep 17 00:00:00 2001 From: Igor Savin Date: Thu, 23 May 2024 16:19:18 +0300 Subject: [PATCH] Support passing optional metadata to the domain emitter --- .../lib/events/DomainEventEmitter.spec.ts | 27 ++++++++++++++++--- .../core/lib/events/DomainEventEmitter.ts | 16 ++++++----- packages/core/lib/events/eventTypes.ts | 25 ++++++++++++----- .../core/lib/events/fakes/FakeListener.ts | 8 +++++- 4 files changed, 60 insertions(+), 16 deletions(-) diff --git a/packages/core/lib/events/DomainEventEmitter.spec.ts b/packages/core/lib/events/DomainEventEmitter.spec.ts index b1fe7398..8b854995 100644 --- a/packages/core/lib/events/DomainEventEmitter.spec.ts +++ b/packages/core/lib/events/DomainEventEmitter.spec.ts @@ -7,10 +7,10 @@ import { afterAll, beforeAll, expect } from 'vitest' import type { Dependencies } from '../../test/testContext' import { registerDependencies, TestEvents } from '../../test/testContext' -import type { CommonEventDefinitionSchemaType } from './eventTypes' +import type { CommonEventDefinitionConsumerSchemaType } from './eventTypes' import { FakeListener } from './fakes/FakeListener' -const createdEventPayload: CommonEventDefinitionSchemaType = { +const createdEventPayload: CommonEventDefinitionConsumerSchemaType = { payload: { message: 'msg', }, @@ -25,7 +25,7 @@ const createdEventPayload: CommonEventDefinitionSchemaType = { +const updatedEventPayload: CommonEventDefinitionConsumerSchemaType = { ...createdEventPayload, type: 'entity.updated', } @@ -75,6 +75,27 @@ describe('AutopilotEventEmitter', () => { expect(fakeListener.receivedEvents[0]).toMatchObject(expectedCreatedPayload) }) + it('emits event to anyListener with metadata', async () => { + const { eventEmitter } = diContainer.cradle + const fakeListener = new FakeListener(diContainer.cradle.eventRegistry.supportedEvents) + eventEmitter.onAny(fakeListener) + + await eventEmitter.emit(TestEvents.created, createdEventPayload, { + correlationId: 'dummy', + }) + + await waitAndRetry(() => { + return fakeListener.receivedEvents.length > 0 + }) + + expect(fakeListener.receivedEvents).toHaveLength(1) + expect(fakeListener.receivedEvents[0]).toMatchObject(expectedCreatedPayload) + expect(fakeListener.receivedMetadata).toHaveLength(1) + expect(fakeListener.receivedMetadata[0]).toMatchObject({ + correlationId: 'dummy', + }) + }) + it('emits event to singleListener', async () => { const { eventEmitter } = diContainer.cradle const fakeListener = new FakeListener(diContainer.cradle.eventRegistry.supportedEvents) diff --git a/packages/core/lib/events/DomainEventEmitter.ts b/packages/core/lib/events/DomainEventEmitter.ts index 31cd1872..053b2a98 100644 --- a/packages/core/lib/events/DomainEventEmitter.ts +++ b/packages/core/lib/events/DomainEventEmitter.ts @@ -1,13 +1,16 @@ import { InternalError } from '@lokalise/node-core' +import type { MessageMetadataType } from '../messages/baseMessageSchemas' + import type { EventRegistry } from './EventRegistry' import type { EventHandler, AnyEventHandler, SingleEventHandler, CommonEventDefinition, - CommonEventDefinitionSchemaType, + CommonEventDefinitionConsumerSchemaType, EventTypeNames, + CommonEventDefinitionPublisherSchemaType, } from './eventTypes' export class DomainEventEmitter { @@ -15,7 +18,7 @@ export class DomainEventEmitter private readonly eventHandlerMap: Record< string, - EventHandler>[] + EventHandler>[] > = {} private readonly anyHandlers: AnyEventHandler[] = [] @@ -25,9 +28,10 @@ export class DomainEventEmitter public async emit( supportedEvent: SupportedEvent, - data: Omit, 'type'>, + data: Omit, 'type'>, + metadata?: Partial, ) { - const eventTypeName = supportedEvent.consumerSchema.shape.type.value + const eventTypeName = supportedEvent.publisherSchema.shape.type.value if (!this.eventRegistry.isSupportedEvent(eventTypeName)) { throw new InternalError({ @@ -52,12 +56,12 @@ export class DomainEventEmitter if (eventHandlers) { for (const handler of eventHandlers) { - await handler.handleEvent(validatedEvent) + await handler.handleEvent(validatedEvent, metadata) } } for (const handler of this.anyHandlers) { - await handler.handleEvent(validatedEvent) + await handler.handleEvent(validatedEvent, metadata) } } diff --git a/packages/core/lib/events/eventTypes.ts b/packages/core/lib/events/eventTypes.ts index 5723fb45..21356d1d 100644 --- a/packages/core/lib/events/eventTypes.ts +++ b/packages/core/lib/events/eventTypes.ts @@ -1,10 +1,12 @@ import type { ZodObject, ZodTypeAny } from 'zod' import type z from 'zod' +import type { MessageMetadataType } from '../messages/baseMessageSchemas' + import type { CONSUMER_BASE_EVENT_SCHEMA, PUBLISHER_BASE_EVENT_SCHEMA } from './baseEventSchemas' export type EventTypeNames = - CommonEventDefinitionSchemaType['type'] + CommonEventDefinitionConsumerSchemaType['type'] export type CommonEventDefinition = { consumerSchema: ZodObject< @@ -16,19 +18,27 @@ export type CommonEventDefinition = { schemaVersion?: string } -export type CommonEventDefinitionSchemaType = z.infer< +export type CommonEventDefinitionConsumerSchemaType = z.infer< T['consumerSchema'] > +export type CommonEventDefinitionPublisherSchemaType = z.infer< + T['publisherSchema'] +> + export type EventHandler< EventDefinitionSchema extends - CommonEventDefinitionSchemaType = CommonEventDefinitionSchemaType, + CommonEventDefinitionConsumerSchemaType = CommonEventDefinitionConsumerSchemaType, + MetadataDefinitionSchema extends Partial = Partial, > = { - handleEvent(event: EventDefinitionSchema): void | Promise + handleEvent( + event: EventDefinitionSchema, + metadata?: MetadataDefinitionSchema, + ): void | Promise } export type AnyEventHandler = EventHandler< - CommonEventDefinitionSchemaType + CommonEventDefinitionConsumerSchemaType > export type SingleEventHandler< @@ -39,4 +49,7 @@ export type SingleEventHandler< type EventFromArrayByTypeName< EventDefinition extends CommonEventDefinition[], EventTypeName extends EventTypeNames, -> = Extract, { type: EventTypeName }> +> = Extract< + CommonEventDefinitionConsumerSchemaType, + { type: EventTypeName } +> diff --git a/packages/core/lib/events/fakes/FakeListener.ts b/packages/core/lib/events/fakes/FakeListener.ts index d6547860..b19bf87f 100644 --- a/packages/core/lib/events/fakes/FakeListener.ts +++ b/packages/core/lib/events/fakes/FakeListener.ts @@ -1,15 +1,21 @@ +import type { MessageMetadataType } from '../../messages/baseMessageSchemas' import type { AnyEventHandler, CommonEventDefinition } from '../eventTypes' export class FakeListener implements AnyEventHandler { public receivedEvents: SupportedEvents[number]['consumerSchema']['_output'][] = [] + public receivedMetadata: MessageMetadataType[] = [] constructor(_supportedEvents: SupportedEvents) { this.receivedEvents = [] } - handleEvent(event: SupportedEvents[number]['consumerSchema']['_output']): void | Promise { + handleEvent( + event: SupportedEvents[number]['consumerSchema']['_output'], + metadata: MessageMetadataType, + ): void | Promise { this.receivedEvents.push(event) + this.receivedMetadata.push(metadata) } }