/* * Copyright © 2024 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file). */ import { type OnEventOptions } from '@nestjs/event-emitter/dist/interfaces'; 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 { type SubscriberUpdateDto } from '@/chat/dto/subscriber.dto'; 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'; import type { Label, LabelDocument } from '@/chat/schemas/label.schema'; import { type Message } from '@/chat/schemas/message.schema'; import { type Subscriber } from '@/chat/schemas/subscriber.schema'; import { type ContentType } from '@/cms/schemas/content-type.schema'; import { type Content } from '@/cms/schemas/content.schema'; import { type Menu } from '@/cms/schemas/menu.schema'; import { type Language } from '@/i18n/schemas/language.schema'; import { type Translation } from '@/i18n/schemas/translation.schema'; import type { NlpEntity, NlpEntityDocument, } 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 { NlpValueDocument, type NlpValue, } 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 '@nestjs/event-emitter'; /** * @description Module declaration that extends the NestJS EventEmitter with custom event types and methods. */ declare module '@nestjs/event-emitter' { export interface TDefinition { schema: S; operations: O; } export interface IHookExtensionsOperationMap {} export interface IHookSettingsGroupLabelOperationMap { chatbot_settings: TDefinition< object, { global_fallback: Setting; fallback_block: Setting; fallback_message: Setting; } >; contact: TDefinition< object, { contact_email_recipient: Setting; company_name: Setting; company_phone: Setting; company_email: Setting; company_address1: Setting; company_address2: Setting; company_city: Setting; company_zipcode: Setting; company_state: Setting; company_country: Setting; } >; nlp_settings: TDefinition< object, { provider: Setting; endpoint: Setting; token: Setting; threshold: Setting; } >; } /* custom hooks */ export interface IHookOperationMap extends IHookSettingsGroupLabelOperationMap, IHookExtensionsOperationMap { analytics: TDefinition< object, { block: BlockFull; passation: Subscriber; 'fallback-local': BlockFull; 'fallback-global': EventWrapper; } >; chatbot: TDefinition< object, { sent: unknown; received: unknown; message: unknown; delivery: unknown; read: unknown; typing: unknown; follow: unknown; echo: unknown; } >; websocket: TDefinition< object, { connection: Socket; } >; } /* hooks */ export interface IHookEntityOperationMap extends IHookOperationMap { stats: TDefinition; attachment: TDefinition; block: TDefinition; category: TDefinition; contextVar: TDefinition; conversation: TDefinition; label: TDefinition< Label, { create: LabelDocument; delete: Label | Label[] } >; message: TDefinition; subscriber: TDefinition; contentType: TDefinition; content: TDefinition; menu: TDefinition; language: TDefinition; translation: TDefinition; nlpEntity: TDefinition< NlpEntity, { create: NlpEntityDocument; update: NlpEntity; delete: NlpEntity | NlpEntity[]; } >; nlpSampleEntity: TDefinition; nlpSample: TDefinition; nlpValue: TDefinition< NlpValue, { create: NlpValueDocument; update: NlpValue; delete: NlpValue | NlpValue[]; } >; setting: TDefinition; invitation: TDefinition; model: TDefinition; permission: TDefinition; role: TDefinition; user: TDefinition; } /* entities hooks having schemas */ export type IHookEntities = keyof Omit< IHookEntityOperationMap, keyof IHookOperationMap >; /** * @description A constrained string type that allows specific string values while preserving type safety. */ export type ConstrainedString = string & Record; export type EventNamespaces = keyof IHookEntityOperationMap; /* pre hooks */ export type TPreValidate = THydratedDocument; export type TPreCreate = THydratedDocument; export type TPreUpdate = TFilterQuery & object; export type TPreDelete = Query< DeleteResult, Document, unknown, T, 'deleteOne', Record >; export type TPreUnion = | TPreValidate | TPreCreate | TPreUpdate | TPreDelete; /* post hooks */ export type TPostValidate = THydratedDocument; export type TPostCreate = THydratedDocument; export type TPostUpdate = THydratedDocument; export type TPostDelete = DeleteResult; export type TPostUnion = | TPostValidate | TPostCreate | TPostUpdate | TPostDelete; export type TCustomOperations = IHookEntityOperationMap[E]['operations'][keyof IHookEntityOperationMap[E]['operations']]; /* union hooks */ export type TUnion = E extends keyof IHookEntityOperationMap ? E extends keyof IHookOperationMap ? TCustomOperations : TPreUnion | TPostUnion | TCustomOperations : never; /* Normalized hook */ export enum EHookPrefix { pre = 'pre', post = 'post', } export type TCompatibleHook< P extends `${EHookPrefix}`, T = `${EHook}`, > = T extends `${P}${infer I}` ? `${P}${I}` : never; export type TPreHook = TCompatibleHook; export type TPostHook = TCompatibleHook; export type TNormalizedEvents = '*' | TPreHook | TPostHook; export 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; }; export type TNormalizedHook< E extends keyof IHookEntityOperationMap, O, > = Extract, { [key in O]: unknown }>[O]; /* Extended hook */ export type TExtendedHook< E extends keyof IHookEntityOperationMap, O extends keyof IHookEntityOperationMap[E]['operations'], > = IHookEntityOperationMap[E]['operations'][O]; export 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; export type IsHookEvent = G extends EventNamespaces ? true : G extends `hook:${infer N}:${string}` ? N extends keyof IHookEntityOperationMap ? true : false : false; export type TCustomEvents = keyof IHookEntityOperationMap[G]['operations'] & string; export type customEvent = G extends EventNamespaces ? G extends `hook:${string}` ? G : `hook:${G}:${TNormalizedEvents | TCustomEvents}` : never; export interface ListenerFn { (value: EventValueOf, ...values: any[]): void; } export class EventEmitter2 { emit( customEvent: customEvent, value: EventValueOf, ...values: any[] ): boolean; emitAsync( customEvent: customEvent, value: EventValueOf, ...values: any[] ): Promise; addListener( customEvent: customEvent, listener: ListenerFn, ): this | Listener; on( customEvent: customEvent, listener: ListenerFn, options?: boolean | OnOptions, ): this | Listener; once( customEvent: customEvent, listener: ListenerFn, options?: true | OnOptions, ): this | Listener; prependOnceListener< G extends EventNamespaces | ConstrainedString, H extends G, >( customEvent: customEvent, listener: ListenerFn, options?: boolean | OnOptions, ): this | Listener; many( customEvent: customEvent, timesToListen: number, listener: ListenerFn, options?: boolean | OnOptions, ): this | Listener; prependMany( customEvent: customEvent, timesToListen: number, listener: ListenerFn, options?: boolean | OnOptions, ): this | Listener; removeListener( customEvent: customEvent, listener: ListenerFn, ): this; off( customEvent: customEvent, listener: ListenerFn, ): this; } declare type OnEventMethodDecorator< G extends EventNamespaces | ConstrainedString, > = ( target: IsHookEvent extends true ? [T[K]] extends [(params: EventValueOf, ...rest: any[]) => any] ? T : never : T, propertyKey: K, ) => void; export declare function OnEvent< G extends EventNamespaces | ConstrainedString, H extends G, >( event: customEvent, options?: OnEventOptions | undefined, ): OnEventMethodDecorator; }