From 3c14ddd76a13fc7c064eb04712d14635baf2c9b3 Mon Sep 17 00:00:00 2001 From: yassinedorbozgithub Date: Sat, 19 Oct 2024 07:10:59 +0100 Subject: [PATCH] fix(api): enhance event typing --- api/src/chat/services/chat.service.ts | 8 +- api/src/eventemitter.d.ts | 155 +++++++++++++++----------- 2 files changed, 94 insertions(+), 69 deletions(-) diff --git a/api/src/chat/services/chat.service.ts b/api/src/chat/services/chat.service.ts index e7229ec1..9fd72510 100644 --- a/api/src/chat/services/chat.service.ts +++ b/api/src/chat/services/chat.service.ts @@ -17,7 +17,7 @@ import { WebsocketGateway } from '@/websocket/websocket.gateway'; import { MessageCreateDto } from '../dto/message.dto'; import { Conversation } from '../schemas/conversation.schema'; -import { Subscriber } from '../schemas/subscriber.schema'; +import { SubscriberDocument } from '../schemas/subscriber.schema'; import { OutgoingMessage } from '../schemas/types/message'; import { BotService } from './bot.service'; @@ -289,7 +289,8 @@ export class ChatService { * @param subscriber - The end user (subscriber) */ @OnEvent('hook:subscriber:postCreate') - onSubscriberCreate(subscriber: Subscriber) { + async onSubscriberCreate({ _id }: SubscriberDocument) { + const subscriber = await this.subscriberService.findOne(_id); this.websocketGateway.broadcastSubscriberNew(subscriber); } @@ -299,7 +300,8 @@ export class ChatService { * @param subscriber - The end user (subscriber) */ @OnEvent('hook:subscriber:postUpdate') - onSubscriberUpdate(subscriber: Subscriber) { + async onSubscriberUpdate({ _id }: SubscriberDocument) { + const subscriber = await this.subscriberService.findOne(_id); this.websocketGateway.broadcastSubscriberUpdate(subscriber); } } diff --git a/api/src/eventemitter.d.ts b/api/src/eventemitter.d.ts index ba286f44..7f56c6d5 100644 --- a/api/src/eventemitter.d.ts +++ b/api/src/eventemitter.d.ts @@ -1,11 +1,17 @@ import { type OnEventOptions } from '@nestjs/event-emitter/dist/interfaces'; -import type { Document, HydratedDocument, Query, TFilterQuery } from 'mongoose'; +import type { Listener, OnOptions } from 'eventemitter2'; +import type { + Document, + Query, + TFilterQuery, + THydratedDocument, +} from 'mongoose'; import { type Socket } from 'socket.io'; import { type BotStats } from '@/analytics/schemas/bot-stats.schema'; import { type Attachment } from '@/attachment/schemas/attachment.schema'; import type EventWrapper from '@/channel/lib/EventWrapper'; -import { BlockFull, type Block } from '@/chat/schemas/block.schema'; +import type { Block, BlockFull } from '@/chat/schemas/block.schema'; import { type Category } from '@/chat/schemas/category.schema'; import { type ContextVar } from '@/chat/schemas/context-var.schema'; import { type Conversation } from '@/chat/schemas/conversation.schema'; @@ -23,9 +29,9 @@ import type { } from '@/nlp/schemas/nlp-entity.schema'; import { type NlpSampleEntity } from '@/nlp/schemas/nlp-sample-entity.schema'; import { type NlpSample } from '@/nlp/schemas/nlp-sample.schema'; -import type { - NlpValue, +import { NlpValueDocument, + type NlpValue, } from '@/nlp/schemas/nlp-value.schema'; import { type Setting } from '@/setting/schemas/setting.schema'; import type { CheckboxSetting, TextSetting } from '@/setting/schemas/types'; @@ -181,10 +187,10 @@ declare module '@nestjs/event-emitter' { type EventNamespaces = keyof IHookEntityOperationMap; /* pre hooks */ - type TPreValidate = HydratedDocument; - type TPreCreate = HydratedDocument; + type TPreValidate = THydratedDocument; + type TPreCreate = THydratedDocument; type TPreUpdate = TFilterQuery & object; - type TPreDelete = Query< + type TPreDelete = Query< DeleteResult, Document, unknown, @@ -196,12 +202,12 @@ declare module '@nestjs/event-emitter' { | TPreValidate | TPreCreate | TPreUpdate - | TPreDelete; + | TPreDelete; /* post hooks */ - type TPostValidate = HydratedDocument; - type TPostCreate = HydratedDocument; - type TPostUpdate = HydratedDocument; + type TPostValidate = THydratedDocument; + type TPostCreate = THydratedDocument; + type TPostUpdate = THydratedDocument; type TPostDelete = DeleteResult; type TPostUnion = | TPostValidate @@ -209,16 +215,14 @@ declare module '@nestjs/event-emitter' { | TPostUpdate | TPostDelete; - /* union hooks */ - type TUnion = E extends keyof IHookOperationMap - ? IHookEntityOperationMap[E]['operations'][keyof IHookEntityOperationMap[E]['operations']] - : - | TPreUnion - | TPostUnion - | IHookEntityOperationMap[E]['operations'][keyof IHookEntityOperationMap[E]['operations']]; + type TCustomOperations = + IHookEntityOperationMap[E]['operations'][keyof IHookEntityOperationMap[E]['operations']]; - type THookSplitter = H extends `hook:${infer E}:${infer O}` - ? [E, O] + /* union hooks */ + type TUnion = E extends keyof IHookEntityOperationMap + ? E extends keyof IHookOperationMap + ? TCustomOperations + : TPreUnion | TPostUnion | TCustomOperations : never; /* Normalized hook */ @@ -235,58 +239,77 @@ declare module '@nestjs/event-emitter' { type TPreHook = TCompatibleHook; type TPostHook = TCompatibleHook; - type hookTypes = O extends keyof IHookOperationMap - ? '*' - : '*' | TPreHook | TPostHook; + type TNormalizedEvents = '*' | TPreHook | TPostHook; - type TNormalizedPreHook = O extends `${EHook.preValidate}` - ? TPreValidate - : O extends `${EHook.preCreate}` - ? TPreCreate - : O extends `${EHook.preUpdate}` - ? TPreUpdate - : O extends `${EHook.preDelete}` - ? TPreDelete - : never; - type TNormalizedPostHook = O extends `${EHook.postValidate}` - ? TPostValidate - : O extends `${EHook.postCreate}` - ? TPostCreate - : O extends `${EHook.postUpdate}` - ? TPostUpdate - : O extends `${EHook.postDelete}` - ? TPostDelete - : never; - type TNormalizedHook = TNormalizedPreHook & - TNormalizedPostHook; + type TNormalizedHooks< + E extends keyof IHookEntityOperationMap, + T = IHookEntityOperationMap[E]['schema'], + > = + | { + [EHook.preValidate]: TPreValidate; + } + | { + [EHook.preCreate]: TPreCreate; + } + | { + [EHook.preUpdate]: TPostUpdate; + } + | { + [EHook.preDelete]: TPreDelete; + } + | { + [EHook.postValidate]: TPostValidate; + } + | { + [EHook.postCreate]: TPostCreate; + } + | { + [EHook.postUpdate]: TPostUpdate; + } + | { + [EHook.postDelete]: TPostDelete; + }; + + type TNormalizedHook = Extract< + TNormalizedHooks, + { [key in O]: unknown } + >[O]; /* Extended hook */ - type TExtendedHook = IHookEntityOperationMap[E]['operations'][O]; + type TExtendedHook< + E extends keyof IHookEntityOperationMap, + O extends keyof IHookEntityOperationMap[E]['operations'], + > = IHookEntityOperationMap[E]['operations'][O]; - type EventValueOf< - G, - E = THookSplitter[0], - O = THookSplitter[1], - > = O extends '*' - ? TUnion - : O extends hookTypes - ? TNormalizedHook - : TExtendedHook; - - type IsHookEvent = G extends EventNamespaces - ? true - : G extends `hook:${infer N}:${string}` - ? N extends keyof IHookEntityOperationMap - ? true - : false - : false; - - type customEvent = G extends EventNamespaces - ? G extends `hook:${string}` - ? G - : `hook:${G}:${hookTypes | keyof IHookEntityOperationMap[G]['operations']}` + type EventValueOf = G extends `hook:${infer E}:${infer O}` + ? O extends '*' + ? TUnion + : E extends keyof IHookEntityOperationMap + ? O extends keyof IHookEntityOperationMap[E]['operations'] + ? TExtendedHook + : TNormalizedHook + : never : never; + type IsHookEvent = + G extends EventNamespaces + ? true + : G extends `hook:${infer N}:${string}` + ? N extends keyof IHookEntityOperationMap + ? true + : false + : false; + + type TCustomEvents = + keyof IHookEntityOperationMap[G]['operations'] & string; + + type customEvent = + G extends EventNamespaces + ? G extends `hook:${string}` + ? G + : `hook:${G}:${TNormalizedEvents | TCustomEvents}` + : never; + export interface ListenerFn { (value: EventValueOf, ...values: any[]): void; }