feat(api): unhance event types

This commit is contained in:
yassinedorbozgithub 2024-10-09 08:26:39 +01:00
parent 11ef7735ed
commit 7ba818b788

View File

@ -1,33 +1,41 @@
import { OnEventOptions } from '@nestjs/event-emitter/dist/interfaces'; import { type OnEventOptions } from '@nestjs/event-emitter/dist/interfaces';
import { Socket } from 'socket.io'; import type { TFilterQuery, HydratedDocument, Query, Document } from 'mongoose';
import { type Socket } from 'socket.io';
import { BotStats } from '@/analytics/schemas/bot-stats.schema'; import { type BotStats } from '@/analytics/schemas/bot-stats.schema';
import { Attachment } from '@/attachment/schemas/attachment.schema'; import { type Attachment } from '@/attachment/schemas/attachment.schema';
import { Block, BlockFull } from '@/chat/schemas/block.schema'; import type EventWrapper from '@/channel/lib/EventWrapper';
import { Category } from '@/chat/schemas/category.schema'; import { type Block, BlockFull } from '@/chat/schemas/block.schema';
import { ContextVar } from '@/chat/schemas/context-var.schema'; import { type Category } from '@/chat/schemas/category.schema';
import { Conversation } from '@/chat/schemas/conversation.schema'; import { type ContextVar } from '@/chat/schemas/context-var.schema';
import { Label } from '@/chat/schemas/label.schema'; import { type Conversation } from '@/chat/schemas/conversation.schema';
import { Message } from '@/chat/schemas/message.schema'; import { LabelDocument, type Label } from '@/chat/schemas/label.schema';
import { Subscriber } from '@/chat/schemas/subscriber.schema'; import { type Message } from '@/chat/schemas/message.schema';
import { ContentType } from '@/cms/schemas/content-type.schema'; import { type Subscriber } from '@/chat/schemas/subscriber.schema';
import { Content } from '@/cms/schemas/content.schema'; import { type ContentType } from '@/cms/schemas/content-type.schema';
import { Menu } from '@/cms/schemas/menu.schema'; import { type Content } from '@/cms/schemas/content.schema';
import { Language } from '@/i18n/schemas/language.schema'; import { type Menu } from '@/cms/schemas/menu.schema';
import { Translation } from '@/i18n/schemas/translation.schema'; import { type Language } from '@/i18n/schemas/language.schema';
import { NlpEntity } from '@/nlp/schemas/nlp-entity.schema'; import { type Translation } from '@/i18n/schemas/translation.schema';
import { NlpSampleEntity } from '@/nlp/schemas/nlp-sample-entity.schema'; import type {
import { NlpSample } from '@/nlp/schemas/nlp-sample.schema'; NlpEntity,
import { NlpValue } from '@/nlp/schemas/nlp-value.schema'; NlpEntityDocument,
import { Setting } from '@/setting/schemas/setting.schema'; } from '@/nlp/schemas/nlp-entity.schema';
import { Invitation } from '@/user/schemas/invitation.schema'; import { type NlpSampleEntity } from '@/nlp/schemas/nlp-sample-entity.schema';
import { Model } from '@/user/schemas/model.schema'; import { type NlpSample } from '@/nlp/schemas/nlp-sample.schema';
import { Permission } from '@/user/schemas/permission.schema'; import {
import { Role } from '@/user/schemas/role.schema'; NlpValueDocument,
import { User } from '@/user/schemas/user.schema'; type NlpValue,
import { EHook } from '@/utils/generics/base-repository'; } from '@/nlp/schemas/nlp-value.schema';
import { type Setting } from '@/setting/schemas/setting.schema';
import { type Invitation } from '@/user/schemas/invitation.schema';
import { type Model } from '@/user/schemas/model.schema';
import { type Permission } from '@/user/schemas/permission.schema';
import { type Role } from '@/user/schemas/role.schema';
import { type User } from '@/user/schemas/user.schema';
import { EHook, type DeleteResult } from '@/utils/generics/base-repository';
import { SubscriberUpdateDto } from './chat/dto/subscriber.dto'; import { type SubscriberUpdateDto } from './chat/dto/subscriber.dto';
import '@nestjs/event-emitter'; import '@nestjs/event-emitter';
@ -39,21 +47,72 @@ declare module '@nestjs/event-emitter' {
schema: S; schema: S;
operations: O; operations: O;
} }
interface IHookOperationMap {
interface IHookExtensionsOperationMap {
messenger_settings: TDefinition<
object,
{
get_started_button: unknown;
access_token: unknown;
composer_input_disabled: unknown;
greeting_text: unknown;
}
>;
}
interface IHookSettingsGroupLabelOperationMap {
chatbot_settings: TDefinition<
object,
{
global_fallback: unknown;
fallback_block: unknown;
fallback_message: unknown;
}
>;
contact: TDefinition<
object,
{
contact_email_recipient: unknown;
company_name: unknown;
company_phone: unknown;
company_email: unknown;
company_address1: unknown;
company_address2: unknown;
company_city: unknown;
company_zipcode: unknown;
company_state: unknown;
company_country: unknown;
}
>;
nlp_settings: TDefinition<
object,
{
provider: unknown;
endpoint: unknown;
token: unknown;
threshold: number;
}
>;
}
/* custom hooks */
interface IHookOperationMap
extends IHookSettingsGroupLabelOperationMap,
IHookExtensionsOperationMap {
analytics: TDefinition< analytics: TDefinition<
object, object,
{ {
block: BlockFull; block: BlockFull;
passation: Subscriber; passation: Subscriber;
'fallback-local': BlockFull; 'fallback-local': BlockFull;
'fallback-global': any; 'fallback-global': EventWrapper<any, any>;
} }
>; >;
chatbot: TDefinition< chatbot: TDefinition<
object, object,
{ {
sent: unknown; sent: string;
received: unknown; received: number;
message: unknown; message: unknown;
delivery: unknown; delivery: unknown;
read: unknown; read: unknown;
@ -62,7 +121,6 @@ declare module '@nestjs/event-emitter' {
echo: unknown; echo: unknown;
} }
>; >;
nlp: TDefinition<object, { settings: unknown }>;
websocket: TDefinition< websocket: TDefinition<
object, object,
{ {
@ -70,6 +128,8 @@ declare module '@nestjs/event-emitter' {
} }
>; >;
} }
/* entities hooks */
interface IHookEntityOperationMap extends IHookOperationMap { interface IHookEntityOperationMap extends IHookOperationMap {
stats: TDefinition<BotStats, { entry: string }>; stats: TDefinition<BotStats, { entry: string }>;
attachment: TDefinition<Attachment>; attachment: TDefinition<Attachment>;
@ -79,28 +139,32 @@ declare module '@nestjs/event-emitter' {
conversation: TDefinition<Conversation, { end: unknown; close: unknown }>; conversation: TDefinition<Conversation, { end: unknown; close: unknown }>;
label: TDefinition< label: TDefinition<
Label, Label,
{ create: THydratedDocument<Label>; delete: Label[] } { create: LabelDocument; delete: Label | Label[] }
>; >;
message: TDefinition<Message>; message: TDefinition<Message>;
subscriber: TDefinition<Subscriber, { assign: SubscriberUpdateDto }>; subscriber: TDefinition<Subscriber, { assign: SubscriberUpdateDto }>;
contentType: TDefinition<ContentType>; contentType: TDefinition<ContentType>;
content: TDefinition<Content>; content: TDefinition<Content>;
menu: TDefinition<Menu>; menu: TDefinition<Menu>;
language: TDefinition<Language, { delete: unknown }>; language: TDefinition<Language, { delete: Language | Language[] }>;
translation: TDefinition<Translation>; translation: TDefinition<Translation>;
nlpEntity: TDefinition< nlpEntity: TDefinition<
NlpEntity, NlpEntity,
{ {
create: NlpEntity; create: NlpEntityDocument;
update: NlpEntity; update: NlpEntity;
delete: NlpEntity; delete: NlpEntity | NlpEntity[];
} }
>; >;
nlpSampleEntity: TDefinition<NlpSampleEntity>; nlpSampleEntity: TDefinition<NlpSampleEntity>;
nlpSample: TDefinition<NlpSample>; nlpSample: TDefinition<NlpSample>;
nlpValue: TDefinition< nlpValue: TDefinition<
NlpValue, NlpValue,
{ create: NlpValue; update: NlpValue; delete: unknown } {
create: NlpValueDocument;
update: NlpValue;
delete: NlpValue | NlpValue[];
}
>; >;
setting: TDefinition<Setting>; setting: TDefinition<Setting>;
invitation: TDefinition<Invitation>; invitation: TDefinition<Invitation>;
@ -114,39 +178,100 @@ declare module '@nestjs/event-emitter' {
* @description A constrained string type that allows specific string values while preserving type safety. * @description A constrained string type that allows specific string values while preserving type safety.
*/ */
type ConstrainedString = string & Record<never, never>; type ConstrainedString = string & Record<never, never>;
type EventNamespaces = keyof IHookEntityOperationMap;
/* pre hooks */
type TPreValidate<T> = HydratedDocument<T>;
type TPreCreate<T> = HydratedDocument<T>;
type TPreUpdate<T> = TFilterQuery<T> & object;
type TPreDelete = Query<
DeleteResult,
Document<T>,
unknown,
T,
'deleteOne',
Record<string, never>
>;
type TPreUnion<T> =
| TPreValidate<T>
| TPreCreate<T>
| TPreUpdate<T>
| TPreDelete;
/* post hooks */
type TPostValidate<T> = HydratedDocument<T>;
type TPostCreate<T> = HydratedDocument<T>;
type TPostUpdate<T> = HydratedDocument<T>;
type TPostDelete = DeleteResult;
type TPostUnion<T> =
| TPostValidate<T>
| TPostCreate<T>
| TPostUpdate<T>
| TPostDelete;
/* union hooks */
type TUnion<G, E> = E extends keyof IHookOperationMap
? IHookEntityOperationMap[E]['operations'][keyof IHookEntityOperationMap[E]['operations']]
:
| TPreUnion<G>
| TPostUnion<G>
| IHookEntityOperationMap[E]['operations'][keyof IHookEntityOperationMap[E]['operations']];
type THookSplitter<H> = H extends `hook:${infer E}:${infer O}`
? [E, O]
: never;
/* Normalized hook */
enum EHookPrefix {
pre = 'pre',
post = 'post',
}
type TCompatibleHook< type TCompatibleHook<
P extends 'pre' | 'post', P extends `${EHookPrefix}`,
T = `${EHook}`, T = `${EHook}`,
> = T extends `${P}${infer I}` ? `${P}${I}` : never; > = T extends `${P}${infer I}` ? `${P}${I}` : never;
type TPreHook = TCompatibleHook<'pre'>; type TPreHook = TCompatibleHook<EHookPrefix.pre>;
type TPostHook = TCompatibleHook<'post'>; type TPostHook = TCompatibleHook<EHookPrefix.post>;
type hookTypes = '*' | TPreHook | TPostHook; type hookTypes<O = never> = O extends keyof IHookOperationMap
? '*'
: '*' | TPreHook | TPostHook;
/* hooks values */ type TNormalizedPreHook<E, O> = O extends `${EHook.preValidate}`
type TPostValidate<T> = THydratedDocument<T>; ? TPreValidate<IHookEntityOperationMap[E]['schema']>
type TPostCreate<T> = THydratedDocument<T>; : O extends `${EHook.preCreate}`
type TPostUpdate<T> = THydratedDocument<T>; ? TPreCreate<IHookEntityOperationMap[E]['schema']>
type TPostDelete = { : O extends `${EHook.preUpdate}`
acknowledged: boolean; ? TPreUpdate<IHookEntityOperationMap[E]['schema']>
deletedCount: number; : O extends `${EHook.preDelete}`
}; ? TPreDelete
type TPost<T> = TPostValidate<T> & : never;
TPostCreate<T> & type TNormalizedPostHook<E, O> = O extends `${EHook.postValidate}`
TPostUpdate<T> & ? TPostValidate<IHookEntityOperationMap[E]['schema']>
TPostDelete; : O extends `${EHook.postCreate}`
? TPostCreate<IHookEntityOperationMap[E]['schema']>
: O extends `${EHook.postUpdate}`
? TPostUpdate<IHookEntityOperationMap[E]['schema']>
: O extends `${EHook.postDelete}`
? TPostDelete
: never;
type TNormalizedHook<E, O> = TNormalizedPreHook<E, O> &
TNormalizedPostHook<E, O>;
type EventNamespaces = keyof IHookEntityOperationMap; /* Extended hook */
type TExtendedHook<E, O> = IHookEntityOperationMap[E]['operations'][O];
type EventValueOf<G> = G extends EventNamespaces type EventValueOf<
? IHookEntityOperationMap[G] G,
: G extends `hook:${infer N}:${hookTypes}` E = THookSplitter<G>[0],
? IHookEntityOperationMap[N]['schema'] O = THookSplitter<G>[1],
: G extends `hook:${infer N}:${infer O}` > = O extends '*'
? IHookEntityOperationMap[N]['operations'][O] ? TUnion<G, E>
: any; : O extends hookTypes
? TNormalizedHook<E, O>
: TExtendedHook<E, O>;
type IsHookEvent<G extends EventNamespaces> = G extends EventNamespaces type IsHookEvent<G extends EventNamespaces> = G extends EventNamespaces
? true ? true
@ -159,7 +284,7 @@ declare module '@nestjs/event-emitter' {
type customEvent<G extends EventNamespaces> = G extends EventNamespaces type customEvent<G extends EventNamespaces> = G extends EventNamespaces
? G extends `hook:${string}` ? G extends `hook:${string}`
? G ? G
: `hook:${G}:${hookTypes | keyof IHookEntityOperationMap[G]['operations']}` : `hook:${G}:${hookTypes<G> | keyof IHookEntityOperationMap[G]['operations']}`
: never; : never;
export interface ListenerFn<G extends EventNamespaces | ConstrainedString> { export interface ListenerFn<G extends EventNamespaces | ConstrainedString> {
@ -167,63 +292,66 @@ declare module '@nestjs/event-emitter' {
} }
export class EventEmitter2 { export class EventEmitter2 {
emit<G extends EventNamespaces | ConstrainedString>( emit<G extends EventNamespaces | ConstrainedString, H extends G>(
customEvent: customEvent<G>, customEvent: customEvent<G>,
value: EventValueOf<G>, value: EventValueOf<H>,
...values: any[] ...values: any[]
): boolean; ): boolean;
emitAsync<G extends EventNamespaces | ConstrainedString>( emitAsync<G extends EventNamespaces | ConstrainedString, H extends G>(
customEvent: customEvent<G>, customEvent: customEvent<G>,
value: EventValueOf<G>, value: EventValueOf<H>,
...values: any[] ...values: any[]
): Promise<any[]>; ): Promise<any[]>;
addListener<G extends EventNamespaces | ConstrainedString>( addListener<G extends EventNamespaces | ConstrainedString, H extends G>(
customEvent: customEvent<G>, customEvent: customEvent<G>,
listener: ListenerFn<G>, listener: ListenerFn<H>,
): this | Listener; ): this | Listener;
on<G extends EventNamespaces | ConstrainedString>( on<G extends EventNamespaces | ConstrainedString, H extends G>(
customEvent: customEvent<G>, customEvent: customEvent<G>,
listener: ListenerFn<G>, listener: ListenerFn<H>,
options?: boolean | OnOptions, options?: boolean | OnOptions,
): this | Listener; ): this | Listener;
once<G extends EventNamespaces | ConstrainedString>( once<G extends EventNamespaces | ConstrainedString, H extends G>(
customEvent: customEvent<G>, customEvent: customEvent<G>,
listener: ListenerFn<G>, listener: ListenerFn<H>,
options?: true | OnOptions, options?: true | OnOptions,
): this | Listener; ): this | Listener;
prependOnceListener<G extends EventNamespaces | ConstrainedString>( prependOnceListener<
G extends EventNamespaces | ConstrainedString,
H extends G,
>(
customEvent: customEvent<G>, customEvent: customEvent<G>,
listener: ListenerFn<G>, listener: ListenerFn<H>,
options?: boolean | OnOptions, options?: boolean | OnOptions,
): this | Listener; ): this | Listener;
many<G extends EventNamespaces | ConstrainedString>( many<G extends EventNamespaces | ConstrainedString, H extends G>(
customEvent: customEvent<G>, customEvent: customEvent<G>,
timesToListen: number, timesToListen: number,
listener: ListenerFn<G>, listener: ListenerFn<H>,
options?: boolean | OnOptions, options?: boolean | OnOptions,
): this | Listener; ): this | Listener;
prependMany<G extends EventNamespaces | ConstrainedString>( prependMany<G extends EventNamespaces | ConstrainedString, H extends G>(
customEvent: customEvent<G>, customEvent: customEvent<G>,
timesToListen: number, timesToListen: number,
listener: ListenerFn<G>, listener: ListenerFn<H>,
options?: boolean | OnOptions, options?: boolean | OnOptions,
): this | Listener; ): this | Listener;
removeListener<G extends EventNamespaces | ConstrainedString>( removeListener<G extends EventNamespaces | ConstrainedString, H extends G>(
customEvent: customEvent<G>, customEvent: customEvent<G>,
listener: ListenerFn<G>, listener: ListenerFn<H>,
): this; ): this;
off<G extends EventNamespaces | ConstrainedString>( off<G extends EventNamespaces | ConstrainedString, H extends G>(
customEvent: customEvent<G>, customEvent: customEvent<G>,
listener: ListenerFn<G>, listener: ListenerFn<H>,
): this; ): this;
} }
@ -240,8 +368,9 @@ declare module '@nestjs/event-emitter' {
export declare function OnEvent< export declare function OnEvent<
G extends EventNamespaces | ConstrainedString, G extends EventNamespaces | ConstrainedString,
H extends G,
>( >(
event: customEvent<G>, event: customEvent<G>,
options?: OnEventOptions | undefined, options?: OnEventOptions | undefined,
): OnEventMethodDecorator<G>; ): OnEventMethodDecorator<H>;
} }