whatsbotcord 1.0.0-beta.7 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["path","path","emojiSplitter","GraphemeSplitter","fs","path","qr","DisconnectReason","GraphemeSplitter","fs","WAMessageAddressingMode","path","path","Whatsbotcord"],"sources":["../src/helpers/Decorators.helper.ts","../src/Msg.types.ts","../src/Whatsapp.types.ts","../src/helpers/Msg.helper.ts","../src/libs/Delegate.ts","../src/libs/MiddlewareChain.ts","../src/helpers/Whatsapp.helper.ts","../src/core/whats_socket/internals/WhatsSocket.receiver.ts","../src/libs/BunPath.ts","../src/core/whats_socket/internals/WhatsSocket.senderqueue.ts","../src/helpers/Mimetypes.helper.ts","../src/helpers/Strings.helper.ts","../src/core/whats_socket/internals/WhatsSocket.sugarsenders.ts","../src/core/whats_socket/WhatsSocket.ts","../src/core/bot/internals/ChatContext.ts","../src/core/bot/internals/ChatContext.myself.status.ts","../src/core/bot/internals/CommandsSearcher.ts","../src/core/bot/bot.ts","../src/core/official_plugins/OneCommandPerUser_Plugin.ts","../src/Debugging.helper.ts","../src/helpers/CommandForJs.helper.ts","../src/core/whats_socket/mocks/WhatsSocket.mock.ts","../src/mocking_suite/ChatContext.mockingsuite.ts","../src/mocking_suite/MsgsMockFactory.ts","../src/mocking_suite/WhatsSocket.receiver.mockingsuite.ts","../src/mocking_suite/WhatsSocket.sugarsender.mockingsuite.ts","../src/mocking_suite/ChatMock.ts","../src/index.ts"],"sourcesContent":["/**\r\n * # Autobind Decorator\r\n *\r\n * Method decorator that ensures the decorated function is always invoked\r\n * with its original class instance as `this`.\r\n *\r\n * Throws an error if applied to anything other than an instance method.\r\n *\r\n * @example\r\n * ```typescript\r\n * class MyClass {\r\n * @autobind\r\n * myMethod() { console.log(this); }\r\n * }\r\n * ```\r\n */\r\nexport function autobind(target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor {\r\n const originalMethod = descriptor.value;\r\n\r\n // Validate that the decorator is applied to a function\r\n if (typeof originalMethod !== \"function\") {\r\n throw new Error(`@autobind can only be applied to methods, not: ${propertyKey}`);\r\n }\r\n\r\n // Validate that the method is not static\r\n const isStatic = target.constructor === Function;\r\n if (isStatic) {\r\n throw new Error(`@autobind cannot be applied to static methods: ${propertyKey}`);\r\n }\r\n\r\n // Validate that the decorator is not applied to getters or setters\r\n if (descriptor.get || descriptor.set) {\r\n throw new Error(`@autobind cannot be applied to getters or setters: ${propertyKey}`);\r\n }\r\n\r\n return {\r\n configurable: true,\r\n enumerable: descriptor.enumerable,\r\n get() {\r\n // Bind the original method to the instance\r\n const bound = originalMethod.bind(this);\r\n\r\n // Define the property on the instance to allow reassignment\r\n Object.defineProperty(this, propertyKey, {\r\n value: bound,\r\n configurable: true, // Allow redefinition\r\n writable: true, // Allow reassignment\r\n enumerable: descriptor.enumerable,\r\n });\r\n\r\n return bound;\r\n },\r\n set(newValue: any) {\r\n // Allow the property to be reassigned (e.g., for mocking)\r\n Object.defineProperty(this, propertyKey, {\r\n value: newValue,\r\n configurable: true,\r\n writable: true,\r\n enumerable: descriptor.enumerable,\r\n });\r\n },\r\n };\r\n}\r\n","/**\r\n * # Message Type\r\n *\r\n * Enumeration mapping the type of the message received.\r\n *\r\n * @example\r\n * ```typescript\r\n * const type = MsgType.Text;\r\n * ```\r\n */\r\nexport enum MsgType {\r\n Text = 1,\r\n Image,\r\n Sticker,\r\n Video,\r\n Audio,\r\n Contact,\r\n Poll,\r\n Ubication,\r\n Document,\r\n Unknown,\r\n}\r\n\r\n/**\r\n * # Sender Type\r\n *\r\n * Enumeration mapping the type of sender that sent the message.\r\n *\r\n * @example\r\n * ```typescript\r\n * const type = SenderType.Individual;\r\n * ```\r\n */\r\nexport enum SenderType {\r\n Group = 1,\r\n Individual,\r\n Unknown,\r\n}\r\n","/**\r\n * # WhatsApp Group Identifier\r\n *\r\n * Suffix identifier used by WhatsApp for group chats.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isGroup = chatId.endsWith(WhatsappGroupIdentifier);\r\n * ```\r\n */\r\nexport const WhatsappGroupIdentifier: string = \"@g.us\";\r\n\r\n/**\r\n * # WhatsApp Phone Number Identifier\r\n *\r\n * Suffix identifier used by WhatsApp for individual phone numbers.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isIndividual = chatId.endsWith(WhatsappPhoneNumberIdentifier);\r\n * ```\r\n */\r\nexport const WhatsappPhoneNumberIdentifier: string = \"@s.whatsapp.net\";\r\n\r\n/**\r\n * # WhatsApp LID Identifier\r\n *\r\n * Suffix identifier used by WhatsApp for LID-normalized IDs.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isLID = chatId.endsWith(WhatsappLIDIdentifier);\r\n * ```\r\n */\r\nexport const WhatsappLIDIdentifier: string = \"@lid\";\r\n","import { type WAMessage, type proto } from \"baileys\";\r\nimport { MsgType, SenderType } from \"../Msg.types.js\";\r\nimport { WhatsappGroupIdentifier, WhatsappLIDIdentifier, WhatsappPhoneNumberIdentifier } from \"../Whatsapp.types.js\";\r\nimport type { FoundQuotedMsg } from \"../core/bot/internals/CommandsSearcher.types.js\";\r\nimport type { WhatsappMessage } from \"../core/whats_socket/types.js\";\r\n\r\n/**\r\n * # Extract Full Message Text\r\n *\r\n * Extracts the textual content from a raw WhatsApp message.\r\n *\r\n * This function inspects a `WAMessage` object and returns the main text associated with it.\r\n * It supports multiple message types, including simple text, extended text, and media captions.\r\n * If the message has no text content, it returns `null`.\r\n *\r\n * @param rawMsg - The raw message object received from Baileys.\r\n * @returns The text content of the message, or `null` if none is found.\r\n *\r\n * @example\r\n * ```typescript\r\n * const text = MsgHelper_FullMsg_GetText(rawMsg);\r\n * if (text) {\r\n * console.log(\"Message text:\", text);\r\n * }\r\n * ```\r\n */\r\nexport function MsgHelper_FullMsg_GetText(rawMsg: WAMessage): string | null {\r\n if (!rawMsg.message) return null;\r\n return (\r\n rawMsg.message.conversation ??\r\n rawMsg.message.extendedTextMessage?.text ??\r\n rawMsg.message.imageMessage?.caption ??\r\n rawMsg.message.videoMessage?.caption ??\r\n null\r\n );\r\n}\r\n\r\n/**\r\n * # Extract Quoted Message Text\r\n *\r\n * Extracts the text from a quoted message if it includes one inside a WAMessage.\r\n *\r\n * @param rawMsg - The raw message containing the quote.\r\n * @returns The extracted quoted text or `null` if it doesn't exist.\r\n *\r\n * @example\r\n * ```typescript\r\n * const quotedText = MsgHelper_FullMsg_GetQuotedMsgText(rawMsg);\r\n * console.log(quotedText);\r\n * ```\r\n */\r\nexport function MsgHelper_FullMsg_GetQuotedMsgText(rawMsg: WhatsappMessage): string | null {\r\n if (\r\n !rawMsg.message ||\r\n !rawMsg.message.extendedTextMessage ||\r\n !rawMsg.message.extendedTextMessage.contextInfo ||\r\n !rawMsg.message.extendedTextMessage.contextInfo.quotedMessage\r\n )\r\n return null;\r\n const quotedMsg = rawMsg.message.extendedTextMessage.contextInfo.quotedMessage;\r\n const text = quotedMsg.conversation || quotedMsg.extendedTextMessage?.text || quotedMsg.imageMessage?.caption || null;\r\n return text;\r\n}\r\n\r\n/**\r\n * # Extract Text From Quoted Message Object\r\n *\r\n * Extracts text content directly from a quoted message prototype object.\r\n *\r\n * @param quotedMsgOnly - The proto message object representing the quote.\r\n * @returns The text representation of the quoted message.\r\n *\r\n * @example\r\n * ```typescript\r\n * const quotedProto = MsgHelper_FullMsg_GetQuotedMsg(rawMsg);\r\n * if (quotedProto) {\r\n * const text = MsgHelper_QuotedMsg_GetText(quotedProto);\r\n * }\r\n * ```\r\n */\r\nexport function MsgHelper_QuotedMsg_GetText(quotedMsgOnly: proto.IMessage): string | null {\r\n return quotedMsgOnly.extendedTextMessage?.text ?? null;\r\n}\r\n\r\n// export function MsgHelper_HasQuotedMsg(rawMsg: WAMessage): boolean {\r\n// return !!rawMsg.message?.extendedTextMessage?.contextInfo?.quotedMessage;\r\n// }\r\n\r\n/**\r\n * # Get Quoted Message Object\r\n *\r\n * Safely extracts the quoted message prototype object from a full WhatsApp message.\r\n *\r\n * @param rawMsg - The raw WhatsApp message that might contain a quote.\r\n * @returns The quoted message protocol object or `null` if not found.\r\n *\r\n * @example\r\n * ```typescript\r\n * const quotedProto = MsgHelper_FullMsg_GetQuotedMsg(rawMsg);\r\n * ```\r\n */\r\nexport function MsgHelper_FullMsg_GetQuotedMsg(rawMsg: WAMessage): proto.IMessage | null {\r\n return rawMsg.message?.extendedTextMessage?.contextInfo?.quotedMessage ?? null;\r\n}\r\n\r\n/**\r\n * # Extract Quoted Message Information\r\n *\r\n * Returns both the quoted message object itself and its determined message type.\r\n *\r\n * @param rawMsg - The full WhatsApp message object.\r\n * @returns An object containing the quoted message and its type, or `null`.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = MsgHelper_ExtractQuotedMsgInfo(rawMsg);\r\n * if (info) {\r\n * console.log(\"Quoted message type:\", info.type);\r\n * }\r\n * ```\r\n */\r\nexport function MsgHelper_ExtractQuotedMsgInfo(rawMsg: WAMessage): FoundQuotedMsg | null {\r\n const existsQuotedMsg: proto.IMessage | null = MsgHelper_FullMsg_GetQuotedMsg(rawMsg);\r\n let quotedMsgAsArgument: FoundQuotedMsg | null = null;\r\n if (existsQuotedMsg) {\r\n const quotedMsgType: MsgType = MsgHelper_ProtoMsg_GetMsgType(existsQuotedMsg);\r\n quotedMsgAsArgument = {\r\n msg: existsQuotedMsg,\r\n type: quotedMsgType,\r\n };\r\n }\r\n return quotedMsgAsArgument;\r\n}\r\n\r\n/**\r\n * # Get Message Type\r\n *\r\n * Determines the type of a WhatsApp message from a raw Baileys `WAMessage` object.\r\n *\r\n * This function inspects the `message` field of the raw message and returns\r\n * a `MsgType` representing its type. If empty or unrecognized, returns `MsgType.Unknown`.\r\n *\r\n * @param rawMsg - The raw message object received from Baileys.\r\n * @returns The detected message type (`MsgType` enum).\r\n *\r\n * @example\r\n * ```typescript\r\n * const msgType = MsgHelper_FullMsg_GetMsgType(rawMsg);\r\n * if (msgType === MsgType.Text) {\r\n * console.log(\"Received a text message.\");\r\n * }\r\n * ```\r\n */\r\nexport function MsgHelper_FullMsg_GetMsgType(rawMsg: WhatsappMessage): MsgType {\r\n if (!rawMsg.message) return MsgType.Unknown;\r\n const objMsg = rawMsg.message;\r\n return MsgHelper_ProtoMsg_GetMsgType(objMsg);\r\n}\r\n\r\n/**\r\n * # Get Sender Type\r\n *\r\n * Detects whether the sender chat of the message is a group or an individual.\r\n *\r\n * @param rawMsg - The received WhatsApp message object.\r\n * @returns A `SenderType` indicating if it comes from a Group or Individual.\r\n *\r\n * @example\r\n * ```typescript\r\n * const senderType = MsgHelper_FullMsg_GetSenderType(rawMsg);\r\n * if (senderType === SenderType.Group) {\r\n * console.log(\"Message is from a group chat.\");\r\n * }\r\n * ```\r\n */\r\nexport function MsgHelper_FullMsg_GetSenderType(rawMsg: WhatsappMessage): SenderType {\r\n const chatId: string = rawMsg.key.remoteJid || rawMsg.key.remoteJidAlt!;\r\n let senderType: SenderType = SenderType.Unknown;\r\n if (chatId && chatId.endsWith(WhatsappGroupIdentifier)) senderType = SenderType.Group;\r\n if (chatId && chatId.endsWith(WhatsappPhoneNumberIdentifier)) senderType = SenderType.Individual;\r\n if (chatId && chatId.endsWith(WhatsappLIDIdentifier)) senderType = SenderType.Individual;\r\n return senderType;\r\n}\r\n\r\n/**\r\n * # Parse Prototype Message Type\r\n *\r\n * Gets the type of the message from the pure protocol message object.\r\n *\r\n * @param generic - The `IMessage` object from Baileys representing message content.\r\n * @returns The determined type of the message as a `MsgType` enum.\r\n *\r\n * @example\r\n * ```typescript\r\n * const msgType = MsgHelper_ProtoMsg_GetMsgType(rawMsg.message);\r\n * ```\r\n */\r\nexport function MsgHelper_ProtoMsg_GetMsgType(generic: proto.IMessage): MsgType {\r\n if (generic.imageMessage) return MsgType.Image;\r\n if (generic.videoMessage) return MsgType.Video;\r\n if (generic.audioMessage) return MsgType.Audio;\r\n if (generic.stickerMessage) return MsgType.Sticker;\r\n if (generic.pollCreationMessageV3) return MsgType.Poll;\r\n if (generic.locationMessage) return MsgType.Ubication;\r\n if (generic.contactMessage) return MsgType.Contact;\r\n if (generic.contactsArrayMessage) return MsgType.Contact;\r\n if (generic.documentMessage) return MsgType.Document;\r\n if (typeof generic.conversation === \"string\" || typeof generic.extendedTextMessage === \"string\" || generic.conversation || generic.extendedTextMessage)\r\n return MsgType.Text;\r\n return MsgType.Unknown;\r\n}\r\n","/**\r\n * A simple delegate implementation inspired by C# delegates.\r\n * Useful for the Observer pattern and event-driven programming.\r\n *\r\n * @template functType - The function signature that the delegate can hold.\r\n */\r\n\r\n/**\r\n * # Delegate Consumer\r\n *\r\n * Represents a delegate consumer type that exposes all Delegate functionality\r\n * except the `CallAll` method. Useful for restricting access to certain operations.\r\n *\r\n * @template fnType - The function signature that the delegate consumes.\r\n *\r\n * @example\r\n * ```typescript\r\n * const myEvent: DelegateConsumer<() => void> = new Delegate();\r\n * ```\r\n */\r\nexport type DelegateConsumer<fnType extends (...args: any[]) => any> = Omit<Delegate<fnType>, \"CallAll\">;\r\n\r\n/**\r\n * # Delegate\r\n *\r\n * A simple delegate implementation inspired by C# delegates.\r\n * Useful for the Observer pattern and event-driven programming.\r\n *\r\n * @template functType - The function signature that the delegate can hold.\r\n *\r\n * @example\r\n * ```typescript\r\n * const onChange = new Delegate<(id: string) => void>();\r\n * onChange.Subscribe((id) => console.log(id));\r\n * onChange.CallAll(\"123\");\r\n * ```\r\n */\r\n\r\nexport default class Delegate<functType extends (...args: any[]) => any> {\r\n /** Internal storage for all subscribed functions. */\r\n private functions: functType[] = [];\r\n\r\n /**\r\n * The number of functions currently subscribed to this delegate.\r\n */\r\n public get Length(): number {\r\n return this.functions.length;\r\n }\r\n\r\n /**\r\n * Subscribes a new function to the delegate.\r\n *\r\n * @param funct - The function to add.\r\n */\r\n public Subscribe(funct: functType): void {\r\n this.functions.push(funct);\r\n }\r\n\r\n /**\r\n * Unsubscribes a previously added function from the delegate.\r\n *\r\n * @param funct - The function to remove.\r\n * @returns `true` if the function was found and removed, otherwise `false`.\r\n */\r\n public Unsubscribe(funct: functType): boolean {\r\n const foundFunctIndex = this.functions.findIndex((f) => f === funct);\r\n if (foundFunctIndex === -1) return false;\r\n this.functions.splice(foundFunctIndex, 1);\r\n return true;\r\n }\r\n\r\n /**\r\n * Calls all subscribed functions synchronously with the provided arguments.\r\n *\r\n * @param args - Arguments to pass to each subscribed function.\r\n */\r\n public CallAll(...args: Parameters<functType>): Array<ReturnType<functType>> {\r\n if (this.functions.length > 0) {\r\n const res: Array<ReturnType<functType>> = this.functions.map((f) => f(...args));\r\n return res;\r\n }\r\n return [];\r\n }\r\n\r\n /**\r\n * Calls all subscribed functions asynchronously with the provided arguments.\r\n * Each function is awaited sequentially.\r\n *\r\n * @param args - Arguments to pass to each subscribed function.\r\n * @returns A promise that resolves when all functions have been called.\r\n */\r\n public async CallAllAsync(...args: Parameters<functType>): Promise<Array<ReturnType<functType>>> {\r\n if (this.functions.length > 0) {\r\n const res: Array<ReturnType<functType>> = await Promise.all(this.functions.map((f) => f(...args)));\r\n return res;\r\n }\r\n return [];\r\n }\r\n\r\n /**\r\n * Removes all subscribed functions from this delegate.\r\n */\r\n public Clear(): void {\r\n this.functions = [];\r\n }\r\n}\r\n","/**\r\n * The signature for the function that passes control to the next middleware.\r\n */\r\nexport type NextFunction = () => Promise<void>;\r\n\r\n/**\r\n * The generic signature for a middleware function.\r\n * @template TArgs An array type representing the arguments (e.g., [string, number]).\r\n * @param context The `this` context from the original caller.\r\n * @param args The typed arguments passed to the chain.\r\n * @param next The function to call to proceed to the next middleware.\r\n */\r\nexport type MiddlewareFunction<TArgs extends any[]> = (...args: [...TArgs, NextFunction]) => void | Promise<void>;\r\n\r\n/**\r\n * Manages the execution of a series of strongly-typed middleware functions.\r\n * @template TArgs An array type representing the arguments the chain will handle.\r\n */\r\nexport class MiddlewareChain<TArgs extends any[] = any[]> {\r\n private readonly _middleware: Array<MiddlewareFunction<TArgs>>;\r\n\r\n /**\r\n * @param middleware An array of middleware functions to execute in order.\r\n */\r\n constructor(middleware: Array<MiddlewareFunction<TArgs>>) {\r\n this._middleware = middleware;\r\n }\r\n\r\n /**\r\n * Executes the middleware chain with strongly-typed arguments.\r\n * @param context The object to use as `this` within middleware functions.\r\n * @param args Arguments that match the generic type `TArgs`.\r\n * @returns A promise that resolves to `true` if the chain completes, or `false` otherwise.\r\n */\r\n public async run(...args: TArgs): Promise<boolean> {\r\n if (this._middleware.length === 0) {\r\n return true;\r\n }\r\n\r\n let isChainCompleted = false;\r\n\r\n const callNext = async (index: number): Promise<void> => {\r\n if (index >= this._middleware.length) {\r\n isChainCompleted = true;\r\n return;\r\n }\r\n\r\n const currentMiddleware = this._middleware[index]!;\r\n const next = () => callNext(index + 1);\r\n // The provided 'args' are now passed with their types intact.\r\n await Promise.resolve(currentMiddleware(...args, next));\r\n };\r\n\r\n await callNext(0);\r\n return isChainCompleted;\r\n }\r\n}\r\n","import type { WAMessage } from \"baileys\";\r\nimport { WhatsappLIDIdentifier, WhatsappPhoneNumberIdentifier } from \"../Whatsapp.types.js\";\r\n\r\n/**\r\n * # WhatsApp ID Type\r\n *\r\n * Enum representing WhatsApp identifier conventions.\r\n *\r\n * @example\r\n * ```typescript\r\n * const myType = WhatsappIdType.Modern;\r\n * ```\r\n */\r\nexport enum WhatsappIdType {\r\n /** Legacy group addressing mode (`pn`) */\r\n Legacy = \"pn\",\r\n /** Modern group addressing mode (`lid`) */\r\n Modern = \"lid\",\r\n}\r\n\r\n/**\r\n * # WhatsApp ID Information\r\n *\r\n * Structure detailing different formats of a WhatsApp ID.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info: WhatsappIDInfo = {\r\n * rawId: \"1234567890@s.whatsapp.net\",\r\n * asMentionFormatted: \"@1234567890\",\r\n * WhatsappIdType: WhatsappIdType.Legacy\r\n * };\r\n * ```\r\n */\r\nexport type WhatsappIDInfo = {\r\n /**\r\n * The original WhatsApp ID as assigned by WhatsApp.\r\n * This is the raw identifier you receive in messages, without any formatting.\r\n */\r\n rawId?: string;\r\n\r\n /**\r\n * The phone number formatted for mentions in messages.\r\n * This is the normalized WhatsApp ID prefixed with '@', ready to be used in quotes or mentions.\r\n *\r\n * Example:\r\n * ```ts\r\n * // If the rawId is '1234567890@s.whatsapp.net', asMentionFormatted will be '@1234567890'\r\n * ```\r\n *\r\n * Note: When sending a message through the socket, make sure to include the sender's full raw ID in the array if required.\r\n */\r\n asMentionFormatted?: string;\r\n\r\n /**\r\n * Indicates the type of WhatsApp ID received.\r\n * - \"lid\": The ID comes from a group message as a linked device identifier. Messages cannot be sent directly to a `@lid`.\r\n * - \"full\": The ID comes from a private chat and is a full WhatsApp ID (e.g., '1234567890@s.whatsapp.net'), which can be used to send messages directly.\r\n */\r\n WhatsappIdType?: WhatsappIdType;\r\n};\r\n\r\n/**\r\n * # Extract Phone Info From Sender Message\r\n *\r\n * Extracts detailed phone number information from a raw WhatsApp message.\r\n *\r\n * @param rawMsg - The raw WhatsApp message.\r\n * @returns An object containing the extracted WhatsApp ID details.\r\n * @throws {Error} If both participant and remoteJid are undefined.\r\n *\r\n * @example\r\n * ```typescript\r\n * const phoneInfo = WhatsappHelper_ExtractWhatsappInfoInfoFromSenderRawMsg(rawMsg);\r\n * console.log(\"Sender Mention string:\", phoneInfo.asMentionFormatted);\r\n * ```\r\n */\r\nexport function WhatsappHelper_ExtractWhatsappInfoInfoFromSenderRawMsg(rawMsg: WAMessage): WhatsappIDInfo {\r\n //Let's check if comes from private msg or group\r\n const id: string | null = rawMsg.key.participant || rawMsg.key.remoteJid || null;\r\n if (!id) {\r\n throw Error(\"This shouldn't happen, baileys library never gives both participant and remoteJid as undefined, only one of them\");\r\n }\r\n return WhatsappHelper_ExtractFromWhatsappID(id);\r\n}\r\n\r\n/**\r\n * # Extract Info From WhatsApp ID\r\n *\r\n * Parses a given raw WhatsApp ID string into an informational structure.\r\n *\r\n * @param whatsappIDStr - The raw string identifier (e.g. \"1234@s.whatsapp.net\").\r\n * @returns The assembled `WhatsappIDInfo` data structure.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = WhatsappHelper_ExtractFromWhatsappID(\"123@s.whatsapp.net\");\r\n * ```\r\n */\r\nexport function WhatsappHelper_ExtractFromWhatsappID(whatsappIDStr: string): WhatsappIDInfo {\r\n const idNumbersOnly = whatsappIDStr.split(\"@\").at(0)!;\r\n let whatsIdType: WhatsappIdType;\r\n if (WhatsappHelper_isLIDIdentifier(whatsappIDStr)) {\r\n whatsIdType = WhatsappIdType.Modern;\r\n } else if (WhatsappHelper_isFullWhatsappIdUser(whatsappIDStr)) {\r\n whatsIdType = WhatsappIdType.Legacy;\r\n } else {\r\n throw new Error(\"WhatsappHelper_ExtractWhatsappIdFromSender couldn't get rawMsgs type id. Got instead: \" + whatsappIDStr);\r\n }\r\n return {\r\n asMentionFormatted: `@${idNumbersOnly}`,\r\n rawId: whatsappIDStr,\r\n WhatsappIdType: whatsIdType,\r\n };\r\n}\r\n\r\n/**\r\n * # Extract WhatsApp Info From Mention\r\n *\r\n * Gets the WhatsApp identifier details out of a mention string if valid.\r\n *\r\n * @param mentionId - A localized mention string (e.g., \"@12345\").\r\n * @returns The `WhatsappIDInfo` or `null` if invalid.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = WhatsappHelper_ExtractWhatsappInfoFromMention(\"@12345\");\r\n * ```\r\n */\r\nexport function WhatsappHelper_ExtractWhatsappInfoFromMention(mentionId: string): WhatsappIDInfo | null {\r\n if (!WhatsappHelper_isMentionId(mentionId)) return null;\r\n const number = mentionId.slice(1);\r\n return {\r\n rawId: `${number}${WhatsappLIDIdentifier}`,\r\n asMentionFormatted: mentionId,\r\n WhatsappIdType: WhatsappIdType.Modern,\r\n };\r\n}\r\n\r\n/**\r\n * # Is LID Identifier\r\n *\r\n * Checks if a string acts as a modern Linked Device Identifier.\r\n *\r\n * @param whatsIdExpected - The raw ID string.\r\n * @returns True if it is a LID.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isLid = WhatsappHelper_isLIDIdentifier(\"1234@lid\");\r\n * ```\r\n */\r\nexport function WhatsappHelper_isLIDIdentifier(whatsIdExpected: string): boolean {\r\n const isLidRegex = new RegExp(`^\\\\d{11,16}${WhatsappLIDIdentifier}$`);\r\n return isLidRegex.test(whatsIdExpected);\r\n}\r\n\r\n/**\r\n * # Is Mention Identifier\r\n *\r\n * Checks if the given string is a valid mention ID for a WhatsApp user.\r\n *\r\n * @param numberStr - The mention formatted string to check.\r\n * @returns True if valid, false otherwise.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isValid = WhatsappHelper_isMentionId('@1234567890123');\r\n * ```\r\n */\r\nexport function WhatsappHelper_isMentionId(numberStr: string): boolean {\r\n const UserMentionedRegex = /^@\\d{11,16}$/;\r\n return UserMentionedRegex.test(numberStr);\r\n}\r\n\r\n/**\r\n * # Is Full WhatsApp User ID\r\n *\r\n * Checks if the given string is a valid full WhatsApp ID for an individual user.\r\n *\r\n * @param expectedWhatsappId - The string to check.\r\n * @returns True if the string is a standard individual user ID.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isValid = WhatsappHelper_isFullWhatsappIdUser('1234567890@s.whatsapp.net');\r\n * ```\r\n */\r\nexport function WhatsappHelper_isFullWhatsappIdUser(expectedWhatsappId: string): boolean {\r\n const UserCompleteWhatsappIdRegex = new RegExp(`^\\\\d{11,16}${WhatsappPhoneNumberIdentifier}$`);\r\n return UserCompleteWhatsappIdRegex.test(expectedWhatsappId);\r\n}\r\n","import type { GroupMetadata } from \"baileys\";\r\nimport { MsgHelper_FullMsg_GetText } from \"../../../helpers/Msg.helper.js\";\r\nimport { type WhatsappIDInfo, WhatsappHelper_ExtractFromWhatsappID, WhatsappIdType } from \"../../../helpers/Whatsapp.helper.js\";\r\nimport { type SenderType, MsgType } from \"../../../Msg.types.js\";\r\nimport type { IWhatsSocket } from \"../IWhatsSocket.js\";\r\nimport type { WhatsappMessage } from \"../types.js\";\r\nimport type { IWhatsSocket_Submodule_Receiver } from \"./IWhatsSocket.receiver.js\";\r\n\r\n/**\r\n * Callback type used to determine whether a received message satisfies a success condition.\r\n *\r\n * @param userId - The WhatsApp sender ID of the message (may be null for broadcasts).\r\n * @param chatId - The ID of the chat the message belongs to.\r\n * @param incomingRawMsg - The raw message object from Baileys.\r\n * @param incomingMsgType - The type of the message.\r\n * @param incomingSenderType - Whether the sender is a group member, self, etc.\r\n * @returns true if the message satisfies the success condition; false otherwise.\r\n */\r\ntype SuccessConditionCallback = (\r\n participantId_LID: string | null,\r\n participantId_PN: string | null,\r\n chatId: string,\r\n incomingRawMsg: WhatsappMessage,\r\n incomingMsgType: MsgType,\r\n incomingSenderType: SenderType\r\n) => boolean;\r\n\r\n/**\r\n * # Wait Options\r\n *\r\n * Options used to configure the wait message behavior in Receiver module.\r\n *\r\n * @example\r\n * ```typescript\r\n * const waitOpts: WhatsSocketReceiverWaitOptions = { timeoutSeconds: 10, cancelKeywords: [\"stop\"], ignoreSelfMessages: true };\r\n * ```\r\n */\r\nexport type WhatsSocketReceiverWaitOptions = {\r\n /** Maximum time (in seconds) to wait for a valid message before rejecting. */\r\n timeoutSeconds: number;\r\n\r\n /** Array of keywords that, if present in a message, will cancel the wait. */\r\n cancelKeywords: string[];\r\n\r\n /** Message sent back to the user if they send a message of the wrong type. */\r\n wrongTypeFeedbackMsg?: string;\r\n\r\n cancelFeedbackMsg?: string;\r\n\r\n /** Whether to ignore messages sent by the bot itself. Default: true */\r\n ignoreSelfMessages: boolean;\r\n};\r\n\r\n/**\r\n * # Receiver Error\r\n *\r\n * Represents an error that occurs during message reception waiting.\r\n *\r\n * @example\r\n * ```typescript\r\n * const err: WhatsSocketReceiverError = {\r\n * errorMessage: WhatsSocketReceiverMsgError.Timeout,\r\n * wasAbortedByUser: false,\r\n * chatId: \"123\",\r\n * participantId_LID: null,\r\n * participantId_PN: null\r\n * };\r\n * ```\r\n */\r\nexport type WhatsSocketReceiverError = {\r\n /** Human-readable error message. */\r\n errorMessage: WhatsSocketReceiverMsgError;\r\n\r\n /** Whether the wait was aborted because the user sent a cancel keyword. */\r\n wasAbortedByUser: boolean;\r\n\r\n /**\r\n * If this error msg comes from group, this will be the participant ID who\r\n * triggered this waiting msg.\r\n * Otherwise, if this comes from private chat, will be null\r\n */\r\n participantId_LID: string | null;\r\n\r\n participantId_PN: string | null;\r\n\r\n /**\r\n * Whatsapp chat ID where this msgError came from\r\n */\r\n chatId: string;\r\n};\r\n\r\n/**\r\n * # Receiver Error Reason\r\n *\r\n * Enumeration mapping the reason for the receiver failure.\r\n *\r\n * @example\r\n * ```typescript\r\n * const reason = WhatsSocketReceiverMsgError.Timeout;\r\n * ```\r\n */\r\nexport enum WhatsSocketReceiverMsgError {\r\n Timeout = \"User didn't responded in time\",\r\n UserCanceledWaiting = \"User has canceled the dialog\",\r\n}\r\n\r\n/**\r\n * # Is Receiver Error\r\n *\r\n * Checks if an object is a `WhatsSocketReceiverError`. This error comes from ChatContext if using \"Wait\" methods,\r\n * or directly from WhatsMsgReceiver Submodule.\r\n *\r\n * @param anything The thing to check.\r\n * @returns Whether `anything` is a `WhatsSocketReceiverError`.\r\n * @category Internal\r\n *\r\n * @example\r\n * ```typescript\r\n * if(WhatsSocketReceiverHelper_isReceiverError(error)) {\r\n * console.log(error.errorMessage);\r\n * }\r\n * ```\r\n */\r\nexport function WhatsSocketReceiverHelper_isReceiverError(anything: unknown): anything is WhatsSocketReceiverError {\r\n return (\r\n typeof anything === \"object\" &&\r\n anything !== null &&\r\n \"errorMessage\" in anything &&\r\n \"wasAbortedByUser\" in anything &&\r\n \"participantId_PN\" in anything &&\r\n \"participantId_PN\" in anything &&\r\n \"chatId\" in anything\r\n );\r\n}\r\n\r\n/**\r\n * # Receiver Submodule\r\n *\r\n * Submodule responsible for listening and waiting for messages through a WhatsSocket instance.\r\n *\r\n * @example\r\n * ```typescript\r\n * const receiver = new WhatsSocket_Submodule_Receiver(socket);\r\n * ```\r\n */\r\nexport class WhatsSocket_Submodule_Receiver implements IWhatsSocket_Submodule_Receiver {\r\n private _whatsSocket: IWhatsSocket;\r\n\r\n /**\r\n * @param socket - An instance of a WhatsSocket (must implement IWhatsSocket).\r\n */\r\n constructor(socket: IWhatsSocket) {\r\n this._whatsSocket = socket;\r\n //DO NOT use decorator @autobind for this class, tests start to fail due to that, here has to be done manually\r\n this.FetchGroupData = this.FetchGroupData.bind(this);\r\n this.WaitUntilNextRawMsgFromUserIDInGroup = this.WaitUntilNextRawMsgFromUserIDInGroup.bind(this);\r\n this.WaitUntilNextRawMsgFromUserIdInPrivateConversation = this.WaitUntilNextRawMsgFromUserIdInPrivateConversation.bind(this);\r\n this._waitNextMsg = this._waitNextMsg.bind(this);\r\n }\r\n\r\n /**\r\n * Internal helper that waits for the next message satisfying a success condition.\r\n * Cancel logic and MsgType checking validation is made here, do not do it on successConditionCallback\r\n *\r\n * @param successConditionCallback - Callback to determine if the message meets the success criteria.\r\n * @param chatIdToLookFor - Chat ID where the message should arrive.\r\n * @param expectedMsgType - Expected type of the message.\r\n * @param options - Configuration options for timeout, cancel keywords, etc.\r\n * @returns Promise that resolves with the WhatsappMessage that met the condition or rejects with an error.\r\n */\r\n private _waitNextMsg(\r\n successConditionCallback: SuccessConditionCallback,\r\n expectedMsgType: MsgType,\r\n options: WhatsSocketReceiverWaitOptions\r\n ): Promise<WhatsappMessage> {\r\n //Options default values\r\n const { cancelKeywords = [], ignoreSelfMessages = true, timeoutSeconds = 30, cancelFeedbackMsg, wrongTypeFeedbackMsg } = options;\r\n\r\n let cachedChatId: string = \"====default ID===== (this is error msg), check WhatsSocket.receiver.ts\";\r\n return new Promise((resolve: (WhatsappMessage: WhatsappMessage) => void, reject: (reason: WhatsSocketReceiverError) => void) => {\r\n let timer: NodeJS.Timeout;\r\n const resetTimeout = () => {\r\n if (timer) clearTimeout(timer);\r\n timer = setTimeout(() => {\r\n this._whatsSocket.onIncomingMsg.Unsubscribe(listener);\r\n reject({\r\n wasAbortedByUser: false,\r\n errorMessage: WhatsSocketReceiverMsgError.Timeout,\r\n chatId: cachedChatId,\r\n participantId_LID: null,\r\n participantId_PN: null,\r\n });\r\n }, timeoutSeconds * 1000);\r\n };\r\n\r\n const listener = (\r\n participantId_LID: string | null,\r\n participantId_PN: string | null,\r\n chatId: string,\r\n msg: WhatsappMessage,\r\n msgType: MsgType,\r\n senderType: SenderType\r\n ) => {\r\n // @deprecated_line: This is supposed to be validated on param 'successConditionCallback'\r\n // if (msg.key.remoteJid !== chatIdToLookFor) return;\r\n cachedChatId = chatId;\r\n if (ignoreSelfMessages) {\r\n if (msg.key.fromMe) return;\r\n }\r\n\r\n resetTimeout();\r\n\r\n //Priority #2: Check if it fits our conditions\r\n if (!successConditionCallback(participantId_LID, participantId_PN, chatId, msg, msgType, senderType)) return;\r\n\r\n if (msgType === MsgType.Text) {\r\n //Priority #1: Check if user is trying to cancel this command\r\n const expectedTxtMsgContent: string | null = MsgHelper_FullMsg_GetText(msg);\r\n if (expectedTxtMsgContent) {\r\n const wordsLowerCased = expectedTxtMsgContent.split(\" \").map((word) => word.toLowerCase());\r\n for (let i = 0; i < wordsLowerCased.length; i++) {\r\n const actualWord = wordsLowerCased[i]!;\r\n if (cancelKeywords.includes(actualWord)) {\r\n this._whatsSocket.onIncomingMsg.Unsubscribe(listener);\r\n clearTimeout(timer);\r\n if (cancelFeedbackMsg) {\r\n this._whatsSocket.Send.Text(chatId, cancelFeedbackMsg);\r\n }\r\n reject({\r\n wasAbortedByUser: true,\r\n errorMessage: WhatsSocketReceiverMsgError.UserCanceledWaiting,\r\n chatId: chatId,\r\n participantId_LID: participantId_LID,\r\n participantId_PN: participantId_PN,\r\n });\r\n return;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Priority #3: All good?, User not cancelling, or even text, let's verify if its the type expected\r\n if (msgType !== expectedMsgType) {\r\n if (wrongTypeFeedbackMsg) {\r\n this._whatsSocket.Send.Text(chatId, wrongTypeFeedbackMsg);\r\n }\r\n return;\r\n }\r\n\r\n this._whatsSocket.onIncomingMsg.Unsubscribe(listener);\r\n clearTimeout(timer);\r\n resolve(msg);\r\n return;\r\n };\r\n //Set initial timeout\r\n resetTimeout();\r\n\r\n // Start listening for msgs\r\n this._whatsSocket.onIncomingMsg.Subscribe(listener);\r\n });\r\n }\r\n\r\n public async WaitUntilNextRawMsgFromUserIDInGroup(\r\n userID_LID_ToWait: string | null,\r\n userID_PN_toWait: string | null,\r\n chatToWaitOnID: string,\r\n expectedMsgType: MsgType,\r\n options: WhatsSocketReceiverWaitOptions\r\n ): Promise<WhatsappMessage> {\r\n if (!userID_LID_ToWait && userID_PN_toWait) {\r\n throw new Error(\"WhatsSocket.receiver.WaitUntilRAwmsgFromUserIDInGroup(), you must provide at least one userID, either the LID or PN version\");\r\n }\r\n //@note: ChatId validation is already done on this._waitNextMsg method\r\n const conditionCallback: SuccessConditionCallback = (participantId_LIDComingFrom, participantId_PNComingFrom, actualChatID, _, _actualMsgType, ___) => {\r\n //#1 Comes from same group?\r\n if (actualChatID !== chatToWaitOnID) return false;\r\n //#2 Its from the expected participant? LID format\r\n if (userID_LID_ToWait) {\r\n if (participantId_LIDComingFrom !== userID_LID_ToWait) return false;\r\n }\r\n\r\n //#3 Its from expected participant? PN format\r\n if (userID_PN_toWait) {\r\n if (participantId_PNComingFrom !== userID_PN_toWait) return false;\r\n }\r\n\r\n return true;\r\n };\r\n return await this._waitNextMsg(conditionCallback, expectedMsgType, options);\r\n }\r\n\r\n public async WaitUntilNextRawMsgFromUserIdInPrivateConversation(\r\n chatIdPrivateUserToWait: string,\r\n expectedMsgType: MsgType,\r\n options: WhatsSocketReceiverWaitOptions\r\n ): Promise<WhatsappMessage> {\r\n const conditionCallback: SuccessConditionCallback = (\r\n _participantId_LIDComingFrom,\r\n _participantId_PNComingFrom,\r\n actualChatId,\r\n _rawMsg,\r\n _actualMsgType,\r\n _senderType\r\n ) => {\r\n if (chatIdPrivateUserToWait !== actualChatId) return false;\r\n return true;\r\n };\r\n return await this._waitNextMsg(conditionCallback, expectedMsgType, options);\r\n }\r\n\r\n public async FetchGroupData(chatId: string): Promise<GroupMetadataInfo | null> {\r\n let res: GroupMetadata;\r\n try {\r\n //In case its a bad chatId and comes from individual msg\r\n res = await this._whatsSocket.GetRawGroupMetadata(chatId);\r\n } catch {\r\n return null;\r\n }\r\n const participants: ParticipantInfo[] = res.participants.map((info): ParticipantInfo => {\r\n const foundId = info.id || info.lid;\r\n let foundWhatsInfo: WhatsappIDInfo | null = null;\r\n if (foundId) {\r\n foundWhatsInfo = WhatsappHelper_ExtractFromWhatsappID(foundId);\r\n }\r\n return {\r\n isAdmin: info.admin === \"superadmin\",\r\n asMentionFormatted: foundWhatsInfo?.asMentionFormatted,\r\n rawId: foundWhatsInfo?.rawId,\r\n WhatsappIdType: foundWhatsInfo?.WhatsappIdType,\r\n };\r\n });\r\n return {\r\n id: res.id,\r\n sendingMode: res.addressingMode === \"pn\" ? WhatsappIdType.Legacy : WhatsappIdType.Modern,\r\n ownerName: res.subjectOwner || res.owner || null,\r\n groupName: res.subject,\r\n groupDescription: res.desc || null,\r\n inviteCode: res.inviteCode || null,\r\n communityIdWhereItBelongs: res.isCommunity ? res.id : null,\r\n onlyAdminsCanChangeGroupSettings: res.restrict || null,\r\n onlyAdminsCanSendMsgs: res.announce || null,\r\n membersCanAddOtherMembers: res.memberAddMode || null,\r\n needsRequestApprovalToJoinIn: res.joinApprovalMode ?? null,\r\n isCommunityAnnounceChannel: res.isCommunityAnnounce || null,\r\n membersCount: res.participants.length || null,\r\n ephemeralDuration: res.ephemeralDuration || null,\r\n author: null,\r\n lastNameChangeDateTime: res.subjectTime || null,\r\n creationDate: res.creation || null,\r\n members: participants,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * # Participant Information\r\n *\r\n * Represents a participant in a WhatsApp group.\r\n *\r\n * @example\r\n * ```typescript\r\n * const pInfo: ParticipantInfo = { isAdmin: true, rawId: \"123\" };\r\n * ```\r\n */\r\nexport type ParticipantInfo = {\r\n /** Whether this participant is an admin */\r\n isAdmin: boolean;\r\n} & WhatsappIDInfo;\r\n\r\n/**\r\n * # Group Metadata\r\n *\r\n * Represents all relevant metadata for a WhatsApp group chat.\r\n *\r\n * @example\r\n * ```typescript\r\n * // const metadata: GroupMetadataInfo = await receiver.FetchGroupData(\"123@g.us\");\r\n * ```\r\n */\r\nexport type GroupMetadataInfo = {\r\n /** Group ID */\r\n id: string;\r\n /** Sending mode of the group */\r\n sendingMode: WhatsappIdType;\r\n /** Name of the group owner */\r\n ownerName: string | null;\r\n /** Display name of the group */\r\n groupName: string;\r\n /** Group description */\r\n groupDescription: string | null;\r\n /** ID of the parent community if the group belongs to one */\r\n communityIdWhereItBelongs: string | null;\r\n /** Whether only admins can change group settings */\r\n onlyAdminsCanChangeGroupSettings: boolean | null;\r\n /** Whether only admins can send messages */\r\n onlyAdminsCanSendMsgs: boolean | null;\r\n /** Whether members can add other members */\r\n membersCanAddOtherMembers: boolean | null;\r\n /** Whether joining requires approval */\r\n needsRequestApprovalToJoinIn: boolean | null;\r\n /** Whether the group is a community announce channel */\r\n isCommunityAnnounceChannel: boolean | null;\r\n /** Total number of participants */\r\n membersCount: number | null;\r\n /** Ephemeral message duration in seconds, if enabled */\r\n ephemeralDuration: number | null;\r\n /** Invite code for the group */\r\n inviteCode: string | null;\r\n /** Timestamp of the last group name change */\r\n lastNameChangeDateTime: number | null;\r\n /** The person who added the bot or changed a setting */\r\n author: string | null;\r\n /** Timestamp of group creation */\r\n creationDate: number | null;\r\n /** Array of group participants */\r\n members: ParticipantInfo[];\r\n};\r\n","import path from \"node:path\";\r\n\r\n/**\r\n * # Get Path\r\n *\r\n * Do not use this anymore, it's the same as using path.join.\r\n * @deprecated Do not use this anymore, it used to work as a compile/not-compile path management, but that doesn't have sense\r\n * in a library...\r\n */\r\nexport function GetPath(...filePathToAppendFromRoot: string[]): string {\r\n if (filePathToAppendFromRoot.length === 0) return \"\";\r\n return path.join(...filePathToAppendFromRoot);\r\n}\r\n","import type { AnyMessageContent, MiscMessageGenerationOptions } from \"baileys\";\r\nimport Delegate from \"../../../libs/Delegate.js\";\r\nimport type { IWhatsSocket } from \"../IWhatsSocket.js\";\r\nimport type { WhatsappMessage } from \"../types.js\";\r\n\r\n/**\r\n * # Socket Message Queue Item\r\n *\r\n * Represents an item in the sending queue.\r\n *\r\n * @example\r\n * ```typescript\r\n * const item: SocketMsgQueueItem = {\r\n * chatId: \"123\",\r\n * content: { text: \"hello\" },\r\n * resolve: () => {},\r\n * reject: () => {}\r\n * };\r\n * ```\r\n */\r\ntype SocketMsgQueueItem = {\r\n chatId: string;\r\n content: AnyMessageContent;\r\n misc?: MiscMessageGenerationOptions;\r\n resolve: (result: any) => void;\r\n reject: (reason: any) => void;\r\n};\r\n\r\nfunction Clone_MsgQueueItem(msgItem: SocketMsgQueueItem) {\r\n const toReturn = {\r\n chatId: msgItem.chatId,\r\n content: { ...msgItem.content },\r\n misc: { ...msgItem.misc },\r\n resolve: msgItem.resolve,\r\n reject: msgItem.reject,\r\n };\r\n return toReturn;\r\n}\r\n\r\n/**\r\n * # Sender Queue Submodule\r\n *\r\n * A subclass code of 'WhatsSocket' class that manages a queue of messages to be sent.\r\n * Helps to prevent overwhelming the WhatsApp socket with too many messages at once incoming from\r\n * multiple users or a funny user trying to spam the bot.\r\n *\r\n * @example\r\n * ```typescript\r\n * const queue = new WhatsSocketSenderQueue_SubModule(socket, 10, 500);\r\n * ```\r\n */\r\nexport default class WhatsSocketSenderQueue_SubModule {\r\n public onSentMessageInsideQueue: Delegate<(chatId: string, content: AnyMessageContent, misc?: MiscMessageGenerationOptions) => void> = new Delegate();\r\n /**\r\n * A getter that returns a deep copy of all elements currently in the queue as an array.\r\n * This is useful for debugging and logging purposes.\r\n * @returns A deep copy of all elements currently in the queue as an array.\r\n */\r\n public get ActualElementsInQueue() {\r\n return this.queue.map((queueItem) => {\r\n return Clone_MsgQueueItem(queueItem);\r\n });\r\n }\r\n\r\n private queue: SocketMsgQueueItem[] = [];\r\n private isProcessing: boolean = false;\r\n private whatsSocket: IWhatsSocket;\r\n private readonly minMillisecondsDelay: number;\r\n private readonly maxQueueLimit: number;\r\n\r\n private isStopped: boolean = false;\r\n\r\n constructor(socket: IWhatsSocket, maxQueueLimit: number = 3, minMilisecondsDelay: number = 1000) {\r\n this.whatsSocket = socket;\r\n this.minMillisecondsDelay = minMilisecondsDelay;\r\n this.maxQueueLimit = maxQueueLimit;\r\n }\r\n\r\n /**\r\n * Enqueues a message to be sent.\r\n * @throws Error if msg enqueue couldn't be send\r\n * @param chatId ChatJID of the user.\r\n * @param content The content of the message.\r\n * @param misc Miscellaneous options.\r\n */\r\n public Enqueue(chatId: string, content: AnyMessageContent, misc?: MiscMessageGenerationOptions): Promise<WhatsappMessage | null> {\r\n return new Promise((resolve, reject) => {\r\n if (this.queue.length >= this.maxQueueLimit) {\r\n console.log(`WhatsSocketSenderQueue: Queue limit of ${this.maxQueueLimit} reached. Ignoring extra img...`);\r\n resolve(null);\r\n return;\r\n }\r\n this.queue.push({ chatId, content, misc, resolve, reject });\r\n // Only start the processing loop if it's not already running.\r\n if (!this.isProcessing && !this.isStopped) {\r\n this.ProcessQueue();\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Stops the queue from processing any more messages. This method is non-blocking. Any messages that are already in the queue\r\n * will be processed and sent, but no new messages will be added to the queue. Note that this method will not stop the underlying\r\n * WhatsApp socket from receiving or sending messages. You will need to call IWhatsSocket.Shutdown() to stop the socket completely.\r\n * @returns A promise that resolves when the queue has stopped processing messages.\r\n */\r\n public async StopGracefully(): Promise<void> {\r\n this.isStopped = true;\r\n }\r\n\r\n /**\r\n * Resumes the processing of the queue after being stopped. This will start processing all messages in the queue again.\r\n * @returns A promise that resolves when the queue has resumed processing messages.\r\n */\r\n public async Continue(): Promise<void> {\r\n this.isStopped = false;\r\n return this.ProcessQueue();\r\n }\r\n\r\n /**\r\n * Processes all messages in the queue one by one, respecting the minimum delay\r\n * between messages specified in the constructor.\r\n * @private\r\n */\r\n private async ProcessQueue(): Promise<void> {\r\n this.isProcessing = true;\r\n while (this.queue.length > 0) {\r\n const item = this.queue.shift()!;\r\n try {\r\n const sentMsg: WhatsappMessage | null = await this.whatsSocket._SendRaw(item.chatId, item.content, item.misc);\r\n this.onSentMessageInsideQueue.CallAll(item.chatId, item.content, item.misc);\r\n this.whatsSocket.onSentMessage.CallAll(item.chatId, item.content, item.misc);\r\n item.resolve(sentMsg);\r\n } catch (error) {\r\n item.reject(error);\r\n }\r\n // Wait for the delay before processing the next message.\r\n await new Promise((resolve) => setTimeout(resolve, this.minMillisecondsDelay));\r\n }\r\n this.isProcessing = false;\r\n }\r\n}\r\n","import mime from \"mime\";\r\nimport path from \"node:path\";\r\n\r\n/**\r\n * Regex to check if a string is a **file extension only**.\r\n *\r\n * Examples that match:\r\n * - \".txt\"\r\n * - \".png\"\r\n *\r\n * Examples that do NOT match:\r\n * - \"png\" (missing leading \".\")\r\n * - \"file.png\" (this is a path, not an extension)\r\n */\r\n// const isExtension_regex = /^\\.[a-zA-Z0-9]{1,}$/;\r\n\r\n/**\r\n * Regex to check if a string is a valid **path** (relative or absolute).\r\n *\r\n * Examples that match:\r\n * - \"./relative/path/to/file.png\"\r\n * - \"../up/one/dir/file.txt\"\r\n * - \"/absolute/path/to/file.jpeg\"\r\n * - \"C:\\\\Windows\\\\path\\\\file.gif\"\r\n */\r\nconst isPath_regex = /^(?:(?:\\/|[a-zA-Z]:\\\\|\\\\)(?:[\\w-]+[\\\\/])*[\\w-]+(?:\\.[\\w]+)?|(?:\\.\\/|\\.\\.\\/)(?:[\\w-]+[\\\\/])*[\\w-]+(?:\\.[\\w]+)?)$/;\r\n\r\n/**\r\n * # Default Mimetype\r\n *\r\n * The default mimetype used when no match is found.\r\n *\r\n * @example\r\n * ```typescript\r\n * const type = DEFAULT_MIMETYPE; // \"application/octet-stream\"\r\n * ```\r\n */\r\nexport const DEFAULT_MIMETYPE = \"application/octet-stream\";\r\n\r\n/**\r\n * Extracts and resolves the **MIME type** from either:\r\n * - A file extension (can begin with a dot or not, e.g. `.txt`, `png`)\r\n * - A file path (relative or absolute, e.g. `./image.jpg`, `/usr/local/file.pdf`)\r\n *\r\n * @param filePathOrExtensionOnly - String containing a file extension or a file path.\r\n * @returns The resolved MIME type (e.g. `\"image/png\"`, `\"video/mp4\"`).\r\n * Returns `\"application/octet-stream\"` if no match is found, or if givenValue is not either .<filetype> or a path\r\n */\r\nfunction _extractExtensionFrom_Path_Or_FileExtension(filePathOrExtensionOnly: string): string {\r\n //Is path (./relative/path/to/file.png or /absolute/path/to/file.jpeg)\r\n if (filePathOrExtensionOnly.match(isPath_regex)) {\r\n const res: string | null = mime.getType(path.extname(filePathOrExtensionOnly));\r\n return res ?? DEFAULT_MIMETYPE;\r\n } else {\r\n //Is extension only (\".txt\", \".png\") or any other else\r\n const res: string | null = mime.getType(filePathOrExtensionOnly);\r\n return res ?? DEFAULT_MIMETYPE;\r\n }\r\n}\r\n\r\n/**\r\n * # Is Image\r\n *\r\n * Determines whether the given file path or extension refers to an **image**.\r\n *\r\n * @param filePathOrExtension - A string with either:\r\n * - An extension (can start with a dot or not, e.g. `.jpg`, `png`)\r\n * - A path (relative or absolute, e.g. `./pic.png`)\r\n *\r\n * @returns `true` if the file is an image type (`image/*`), otherwise `false`.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isImage = MimeTypeHelper_IsImage(\"file.png\"); // true\r\n * ```\r\n */\r\nexport function MimeTypeHelper_IsImage(filePathOrExtension: string): boolean {\r\n if (!filePathOrExtension || filePathOrExtension.trim() === \"\") return false;\r\n const res: string = _extractExtensionFrom_Path_Or_FileExtension(filePathOrExtension);\r\n return res.startsWith(\"image/\");\r\n}\r\n\r\n/**\r\n * # Is Video\r\n *\r\n * Determines whether the given file path or extension refers to a **video**.\r\n *\r\n * @param filePathOrExtension - A string with either:\r\n * - An extension (can start with a dot or not, e.g. `.jpg`, `png`)\r\n * - A path (relative or absolute, e.g. `/movies/video.avi`)\r\n *\r\n * @returns `true` if the file is a video type (`video/*`), otherwise `false`.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isVideo = MimeTypeHelper_IsVideo(\"file.mp4\"); // true\r\n * ```\r\n */\r\nexport function MimeTypeHelper_IsVideo(filePathOrExtension: string): boolean {\r\n if (!filePathOrExtension || filePathOrExtension.trim() === \"\") return false;\r\n const res: string = _extractExtensionFrom_Path_Or_FileExtension(filePathOrExtension);\r\n return res.startsWith(\"video/\");\r\n}\r\n\r\n/**\r\n * # Is Audio\r\n *\r\n * Determines whether the given file path or extension refers to an **audio**.\r\n *\r\n * @param filePathOrExtension - A string with either:\r\n * - An extension (can start with a dot or not, e.g. `.mp3`, `wav`)\r\n * - A path (relative or absolute, e.g. `./audio/song.mp3`)\r\n *\r\n * @returns `true` if the file is an audio type (`audio/*`), otherwise `false`.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isAudio = MimeTypeHelper_IsAudio(\"file.mp3\"); // true\r\n * ```\r\n */\r\nexport function MimeTypeHelper_IsAudio(filePathOrExtension: string): boolean {\r\n if (!filePathOrExtension || filePathOrExtension.trim() === \"\") return false;\r\n const res: string = _extractExtensionFrom_Path_Or_FileExtension(filePathOrExtension);\r\n return res.startsWith(\"audio/\");\r\n}\r\n\r\n/**\r\n * # Get Mimetype Of\r\n *\r\n * Retrieves the MIME type of a file or buffer with a given extension.\r\n *\r\n * Supports two overloads:\r\n * 1. `MimeTypeHelper_GetMimeTypeOf({ source: string })`\r\n * - `source`: The file path\r\n * 2. `MimeTypeHelper_GetMimeTypeOf({ source: Buffer; extensionType: string })`\r\n * - `source`: The buffer containing the file data\r\n * - `extensionType`: The file extension (e.g. `\"pdf\"`, `\"zip\"`) can start with a dot or not, e.g. `.jpg`, `png`\r\n *\r\n * Returns the determined MIME type as a string. If the MIME type cannot be\r\n * determined, it returns `\"application/octet-stream\"`.\r\n *\r\n * @param params Object containing either string source, or source Buffer + extension type string.\r\n * @returns The complete mimetype if found, otherwise, fallbacks to default \"application/octet-stream\"\r\n *\r\n * @note This is already being tested on WhatsSocket.sugarsenders.test.ts!, doesn't need a standaole suite test\r\n *\r\n * @example\r\n * ```typescript\r\n * const type = MimeTypeHelper_GetMimeTypeOf({ source: \"file.png\" }); // \"image/png\"\r\n * ```\r\n */\r\nexport function MimeTypeHelper_GetMimeTypeOf(params: { source: string } | { source: Buffer; extensionType: string }): string {\r\n //1. First overload\r\n if (typeof params.source === \"string\") {\r\n //Can return false if not found. Bad library API in my opinion tbh\r\n const toReturn: string = _extractExtensionFrom_Path_Or_FileExtension(params.source);\r\n return toReturn;\r\n }\r\n\r\n //2. Second overload\r\n if (\"extensionType\" in params) {\r\n //Can return false if not found. Bad library API in my opinion tbh\r\n const toReturn: string = _extractExtensionFrom_Path_Or_FileExtension(params.extensionType);\r\n return toReturn;\r\n }\r\n\r\n //Default\r\n return DEFAULT_MIMETYPE;\r\n}\r\n","/**\r\n * # Normalize Literal String\r\n *\r\n * Normalizes a literal string by trimming unnecessary whitespace.\r\n *\r\n * - Removes leading and trailing whitespace from the entire string.\r\n * - Splits the string into lines and trims each line individually.\r\n * - Preserves empty lines (they are kept as `\"\"`, not removed).\r\n * - Rejoins the lines with `\"\\n\"` so the line structure is preserved.\r\n *\r\n * @example\r\n * Str_NormalizeLiteralString(\" hello \")\r\n * // => \"hello\"\r\n *\r\n * @example\r\n * Str_NormalizeLiteralString(\" line1 \\n line2 \\n\\n \")\r\n * // => \"line1\\nline2\\n\"\r\n *\r\n * @param str The input string to normalize. If `null` or `undefined`, returns an empty string.\r\n * @returns The normalized string with consistent whitespace handling.\r\n */\r\nexport function Str_NormalizeLiteralString(str: string): string {\r\n if (!str) return \"\";\r\n return str\r\n .trim()\r\n .split(\"\\n\")\r\n .map((line) => line.trim() || line)\r\n .join(\"\\n\");\r\n}\r\n","import { type MiscMessageGenerationOptions, type WAMessage } from \"baileys\";\r\nimport emojiRegexFabric from \"emoji-regex\";\r\nimport GraphemeSplitter from \"grapheme-splitter\";\r\nimport fs from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { MimeTypeHelper_GetMimeTypeOf, MimeTypeHelper_IsAudio, MimeTypeHelper_IsImage, MimeTypeHelper_IsVideo } from \"../../../helpers/Mimetypes.helper.js\";\r\nimport { Str_NormalizeLiteralString } from \"../../../helpers/Strings.helper.js\";\r\nimport { GetPath } from \"../../../libs/BunPath.js\";\r\nimport type { IWhatsSocket } from \"../IWhatsSocket.js\";\r\nimport type {\r\n IWhatsSocket_Submodule_SugarSender,\r\n WhatsMsgAudioOptions,\r\n WhatsMsgDocumentOptions,\r\n WhatsMsgMediaOptions,\r\n WhatsMsgPollOptions,\r\n WhatsMsgSenderSendingOptions,\r\n WhatsMsgSenderSendingOptionsMINIMUM,\r\n WhatsMsgUbicationOptions,\r\n} from \"./IWhatsSocket.sugarsender.js\";\r\n\r\nconst emojiRegex = emojiRegexFabric();\r\nconst emojiSplitter = new GraphemeSplitter();\r\n\r\n/**\r\n * # Sugar Sender Submodule\r\n *\r\n * A utility class for sending various types of WhatsApp messages with simplified APIs.\r\n * This class acts as a wrapper around the core WhatsApp socket functionality,\r\n * providing methods to send text, images, videos, audio, stickers, documents,\r\n * polls, locations, and contacts with proper validation and formatting.\r\n *\r\n * @remarks\r\n * - All methods support optional sending configurations, such as bypassing the\r\n * safe queue system or mentioning users.\r\n * - Media-related methods validate file existence and MIME types before sending.\r\n * - The class leverages Baileys' `MiscMessageGenerationOptions` for additional\r\n * message customization.\r\n *\r\n * @example\r\n * ```typescript\r\n * const sender = new WhatsSocket_Submodule_SugarSender(socket);\r\n * await sender.Text(\"123@s.whatsapp.net\", \"Hello World!\");\r\n * ```\r\n */\r\nexport class WhatsSocket_Submodule_SugarSender implements IWhatsSocket_Submodule_SugarSender {\r\n /** Strong dependency, needs to be inejcted from constructor */\r\n private socket: IWhatsSocket;\r\n\r\n /**\r\n * Initializes the SugarSender with a WhatsApp socket instance.\r\n *\r\n * @param socket - The WhatsApp socket instance used for sending messages.\r\n */\r\n constructor(socket: IWhatsSocket) {\r\n this.socket = socket;\r\n }\r\n\r\n public async Text(chatId: string, text: string, options?: WhatsMsgSenderSendingOptions) {\r\n if (typeof text !== \"string\" || text.trim() === \"\") {\r\n throw new Error(\r\n \"SugarSender.Text() received a non string text or an empty string to send, check that. Received instead: \" + JSON.stringify(text, null, 2)\r\n );\r\n }\r\n text = (options?.normalizeMessageText ?? true) ? Str_NormalizeLiteralString(text) : text;\r\n //_getSendingMethod() returns a functions, it seems cursed I know, get used to it\r\n return await this._getSendingMethod(options)(chatId, { text, mentions: options?.mentionsIds }, options as MiscMessageGenerationOptions);\r\n }\r\n\r\n public async Image(chatId: string, imageOptions: WhatsMsgMediaOptions, options?: WhatsMsgSenderSendingOptions): Promise<WAMessage | null> {\r\n let imgBuffer: Buffer;\r\n let mimeType: string;\r\n let isGif: boolean = false;\r\n //1. First overload: {sourcePath: string, caption?:string}\r\n if (typeof imageOptions.source === \"string\") {\r\n //1.1 Check if its a valid img type at least\r\n if (!MimeTypeHelper_IsImage(imageOptions.source)) {\r\n throw new Error(\"WhatsSocketSugarSender.Image() can't send a non IMAGE FILE!. What you were trying to send: \" + imageOptions.source);\r\n }\r\n\r\n //1.2 If using custom formatExtension, check if its a valid custom img valid format\r\n if (\"formatExtension\" in imageOptions) {\r\n if (!MimeTypeHelper_IsImage(imageOptions.formatExtension)) {\r\n throw new Error(\r\n `WhatsSockerSugarSender.Image(), you are sending a valid file, but you are trying to send it with custom extension which is not a file type => '${imageOptions.formatExtension}'`\r\n );\r\n }\r\n }\r\n\r\n //1.3 Proceed checking if img file to send exists\r\n if (!fs.existsSync(GetPath(imageOptions.source)) || !imageOptions.source || imageOptions.source.trim() === \"\") {\r\n throw new Error(\r\n \"Bad arguments: WhatsSocketSugarSender tried to send an img with incorrect path!, check again your img path\" + \" ImgPath: \" + imageOptions.source\r\n );\r\n }\r\n\r\n //Let's continue\r\n imgBuffer = fs.readFileSync(imageOptions.source);\r\n\r\n //@ts-expect-error Can be usable with formatExtension as well\r\n mimeType = imageOptions.formatExtension\r\n ? //@ts-expect-error Can be usable with formatExtension as well\r\n MimeTypeHelper_GetMimeTypeOf({ source: imageOptions.formatExtension })\r\n : MimeTypeHelper_GetMimeTypeOf({ source: imageOptions.source });\r\n isGif = mimeType === \"image/gif\";\r\n }\r\n //2. Second overload: {sourcePath: Buffer, caption?:string, formatExtension: string}\r\n else if (\"formatExtension\" in imageOptions) {\r\n imgBuffer = imageOptions.source;\r\n mimeType = MimeTypeHelper_GetMimeTypeOf({ source: imageOptions.source, extensionType: imageOptions.formatExtension });\r\n isGif = mimeType === \"image/gif\";\r\n } else {\r\n throw new Error(\r\n \"SugarSender.Img() bad args!, expected source in buffer or string with formatExtension prop if buffer... got instead: \" +\r\n JSON.stringify(imageOptions, null, 2)\r\n );\r\n }\r\n //Common overload logic\r\n let captionToSend: string | undefined = imageOptions.caption;\r\n if (captionToSend) {\r\n if (options?.normalizeMessageText) {\r\n captionToSend = Str_NormalizeLiteralString(captionToSend);\r\n }\r\n }\r\n // WhatsApp requires GIFs to be sent as videos with gifPlayback enabled\r\n if (isGif) {\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n image: imgBuffer,\r\n caption: captionToSend,\r\n gifPlayback: true,\r\n mentions: options?.mentionsIds,\r\n // mimetype: mimeType | For some reason it breaks if it includes a mimeType along with it (why? 🤓?)\r\n },\r\n options as MiscMessageGenerationOptions\r\n );\r\n }\r\n\r\n //Ends\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n image: imgBuffer,\r\n caption: captionToSend,\r\n mentions: options?.mentionsIds,\r\n mimetype: mimeType,\r\n },\r\n options as MiscMessageGenerationOptions\r\n );\r\n }\r\n\r\n public async ReactEmojiToMsg(\r\n chatId: string,\r\n rawMsgToReactTo: WAMessage,\r\n emojiStr: string,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WAMessage | null> {\r\n if (typeof emojiStr !== \"string\") {\r\n throw new Error(\"WhatsSocketSugarSender.ReactEmojiToMsg() received an non string emoji\");\r\n }\r\n const emojisCount: number = emojiSplitter.countGraphemes(emojiStr);\r\n if (emojisCount !== 1) {\r\n throw new Error(\r\n \"WhatsSocketSugarSender.ReactEmojiToMsg() received (less than 1 or greater than 2) chars as emoji to send.... It must be a simple emoji string of 1-2 emoji char length. Received instead: \" +\r\n emojiStr\r\n );\r\n }\r\n\r\n if (!emojiStr.match(emojiRegex)) {\r\n throw new Error(\"WhatsSocketSugarSender.ReactEmojiToMsg() received a non emoji reaction. Received instead: \" + emojiStr);\r\n }\r\n\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n react: {\r\n text: emojiStr,\r\n key: rawMsgToReactTo.key,\r\n },\r\n mentions: options?.mentionsIds,\r\n },\r\n options as MiscMessageGenerationOptions\r\n );\r\n }\r\n\r\n public async Sticker(chatId: string, stickerUrlSource: string | Buffer, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WAMessage | null> {\r\n if (typeof stickerUrlSource === \"string\") {\r\n if (!stickerUrlSource.endsWith(\".webp\")) {\r\n throw new Error(\"WhatsSocketSugarSender.Sticker() received a non .webp sticker to send. Must be in .webp format first!\");\r\n }\r\n if (!fs.existsSync(stickerUrlSource)) {\r\n throw new Error(\"WhatsSocketSugarSender.Sticker() coudn't find stickerUrlSource or it's invalid...\" + \"Url: \" + stickerUrlSource);\r\n }\r\n }\r\n\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n sticker: Buffer.isBuffer(stickerUrlSource)\r\n ? stickerUrlSource\r\n : {\r\n url: stickerUrlSource,\r\n },\r\n mentions: options?.mentionsIds,\r\n },\r\n options as MiscMessageGenerationOptions\r\n );\r\n }\r\n\r\n public async Audio(chatId: string, audioParams: WhatsMsgAudioOptions, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WAMessage | null> {\r\n let buffer: Buffer;\r\n let mimeType: string;\r\n //1. First overload: {source: string, caption?:string}\r\n if (typeof audioParams.source === \"string\") {\r\n if (!MimeTypeHelper_IsAudio(audioParams.source)) {\r\n throw new Error(\r\n \"Bad arguments: WhatsSocketSugarSender.Audio() received a non audio file to send (checked from extension format). Expected .mp3, .wav, and others but gotten instead: \" +\r\n audioParams.source\r\n );\r\n }\r\n\r\n if (\"formatExtension\" in audioParams) {\r\n if (!MimeTypeHelper_IsAudio(audioParams.formatExtension)) {\r\n throw new Error(\"Bad arguments: WhatsSocketSugarSender.Audio() received a non audio custom extension. Received: \" + audioParams.formatExtension);\r\n }\r\n }\r\n\r\n if (!fs.existsSync(GetPath(audioParams.source))) {\r\n throw new Error(\r\n \"Bad arguments: WhatsSocketSugarSender tried to send an img with incorrect path!, check again your img path\" +\r\n \" AudioSourcePath: \" +\r\n audioParams.source\r\n );\r\n }\r\n buffer = fs.readFileSync(audioParams.source);\r\n //@ts-expect-error Can be usable with format extension as well\r\n mimeType = audioParams.formatExtension\r\n ? //@ts-expect-error Can be usable with format extension as well\r\n MimeTypeHelper_GetMimeTypeOf({ source: audioParams.formatExtension })\r\n : MimeTypeHelper_GetMimeTypeOf({ source: audioParams.source });\r\n } else if (\"formatExtension\" in audioParams) {\r\n if (!MimeTypeHelper_IsAudio(audioParams.formatExtension)) {\r\n throw new Error(\r\n \"Bad args => SugarSender.Audio() received buffer and a non-video custom extension type. Extension type received: \" + audioParams.formatExtension\r\n );\r\n }\r\n\r\n buffer = audioParams.source;\r\n\r\n mimeType = MimeTypeHelper_GetMimeTypeOf({ source: audioParams.source, extensionType: audioParams.formatExtension as string });\r\n } else {\r\n throw new Error(\"SugarSender.Audio bad args, expected audio source in buffer or stringpath format. Got Instead: \" + JSON.stringify(audioParams, null, 2));\r\n }\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n audio: buffer,\r\n mimetype: mimeType,\r\n mentions: options?.mentionsIds,\r\n },\r\n options as MiscMessageGenerationOptions\r\n );\r\n }\r\n\r\n public async Video(chatId: string, videoParams: WhatsMsgMediaOptions, options?: WhatsMsgSenderSendingOptions): Promise<WAMessage | null> {\r\n let buffer: Buffer;\r\n let mimeType: string;\r\n\r\n //1. First overload: {source:string, caption?:string}\r\n if (typeof videoParams.source === \"string\") {\r\n if (!MimeTypeHelper_IsVideo(videoParams.source)) {\r\n throw new Error(\"Bad args: WhatsSugarSender.Video() received a non video file to send (checked from extension). Gotten instead: \" + videoParams.source);\r\n }\r\n\r\n if (\"formatExtension\" in videoParams) {\r\n if (!MimeTypeHelper_IsVideo(videoParams.formatExtension as string)) {\r\n throw new Error(\r\n \"Bad args: WhatsSugarSender.Video() received a NON custom video file format .extension. Given instead: \" + videoParams.formatExtension\r\n );\r\n }\r\n }\r\n\r\n if (!fs.existsSync(GetPath(videoParams.source))) {\r\n throw new Error(\"SugarSender.Video expected a valid video path!, doesn't exist... Got instead: \" + videoParams.source);\r\n }\r\n\r\n buffer = fs.readFileSync(videoParams.source);\r\n //@ts-expect-error Can be usable with format extension as well\r\n mimeType = videoParams.formatExtension\r\n ? //@ts-expect-error Can be usable with format extension as well\r\n MimeTypeHelper_GetMimeTypeOf({ source: videoParams.formatExtension })\r\n : MimeTypeHelper_GetMimeTypeOf({ source: videoParams.source });\r\n //2. Second overload: {source:Buffer, caption?: string, formatExtension: string}\r\n } else if (\"formatExtension\" in videoParams) {\r\n if (!MimeTypeHelper_IsVideo(videoParams.formatExtension)) {\r\n throw new Error(\r\n \"Bad args => SugarSender.Video() received a buffer with a NON image formatExtension (for mimetypes). FormatExtension provided: \" +\r\n videoParams.formatExtension\r\n );\r\n }\r\n buffer = videoParams.source;\r\n mimeType = MimeTypeHelper_GetMimeTypeOf({ source: videoParams.source, extensionType: videoParams.formatExtension });\r\n } else {\r\n throw new Error(\"SugarSender.Video bad args, expected video source in buffer or stringpath format. Got Instead: \" + JSON.stringify(videoParams, null, 2));\r\n }\r\n\r\n //Common overload logic code\r\n let caption: string | undefined = videoParams.caption;\r\n if (caption) {\r\n if (options?.normalizeMessageText) {\r\n caption = Str_NormalizeLiteralString(caption);\r\n }\r\n }\r\n //Default\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n video: buffer,\r\n caption: caption ?? \"\",\r\n mimetype: mimeType,\r\n mentions: options?.mentionsIds,\r\n },\r\n options\r\n );\r\n }\r\n\r\n public async Document(chatId: string, docParams: WhatsMsgDocumentOptions, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WAMessage | null> {\r\n let buffer: Buffer;\r\n let mimeType: string;\r\n let fileNameToDisplay: string;\r\n\r\n //1. First overload {source:string, caption?:string}\r\n if (typeof docParams.source === \"string\") {\r\n if (!fs.existsSync(GetPath(docParams.source))) {\r\n throw new Error(`SugarSender.Document(), received path document '${docParams.source}' doesn't exist!. Check again...`);\r\n }\r\n buffer = fs.readFileSync(docParams.source);\r\n mimeType = MimeTypeHelper_GetMimeTypeOf({ source: docParams.source });\r\n if (\"fileNameToDisplay\" in docParams) {\r\n // fileNameToDisplay = docParams.fileNameToDisplay ?? path.basename(docParams.source); //Gets file name WITH extension\r\n fileNameToDisplay =\r\n !docParams.fileNameToDisplay || docParams.fileNameToDisplay.trim() === \"\" ? path.basename(docParams.source) : docParams.fileNameToDisplay;\r\n } else {\r\n fileNameToDisplay = path.basename(docParams.source); //Gets file name WITH extension\r\n }\r\n //2. Second overload {source:Buffer, caption?: string, formatExtension:string}\r\n } else if (\"formatExtension\" in docParams) {\r\n buffer = docParams.source;\r\n mimeType = MimeTypeHelper_GetMimeTypeOf({ source: docParams.source, extensionType: docParams.formatExtension });\r\n fileNameToDisplay = docParams.fileNameWithoutExtension + \".\" + docParams.formatExtension.toLowerCase().replace(\".\", \"\");\r\n } else {\r\n throw new Error(\r\n \"SugarSender.Document bad args, expected document source in buffer or stringpath format. Got Instead: \" + JSON.stringify(docParams, null, 2)\r\n );\r\n }\r\n\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n document: buffer,\r\n mimetype: mimeType,\r\n fileName: fileNameToDisplay,\r\n mentions: options?.mentionsIds,\r\n },\r\n options\r\n );\r\n }\r\n\r\n public async Poll(\r\n chatId: string,\r\n pollTitle: string,\r\n selections: string[],\r\n pollParams: WhatsMsgPollOptions,\r\n moreOptions?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WAMessage | null> {\r\n let title: string = pollTitle;\r\n let selects: string[] = selections;\r\n\r\n if (!(selections.length >= 1 && selections.length <= 12)) {\r\n throw new Error(\r\n \"WhatsSocketSugarSender.Poll() received less than 1 options or greather than 12, must be in range 1-12. Received: \" + selections.length + \" options...\"\r\n );\r\n }\r\n\r\n if (pollParams.normalizeTitleText) {\r\n title = Str_NormalizeLiteralString(title);\r\n }\r\n\r\n if (pollParams.normalizeOptionsText) {\r\n selects = selections.map((opt) => Str_NormalizeLiteralString(opt));\r\n }\r\n\r\n for (let i = 0; i < selects.length; i++) {\r\n const selectionTxt = selects[i]!;\r\n if (selectionTxt.trim() === \"\") {\r\n throw new Error(`Bad Args: SugarSender.Poll(): Option ${i + 1} is empty string!, you can't send non-text options...`);\r\n }\r\n }\r\n\r\n return await this._getSendingMethod(moreOptions)(\r\n chatId,\r\n {\r\n poll: {\r\n name: title,\r\n values: selects,\r\n //Whats API receives 0 as multiple answers and 1 for exclusive 1 answer to polls (Thats how it works ¯\\_(ツ)_/¯)\r\n // selectableCount: pollParams.withMultiSelect ? 0 : 1\r\n selectableCount: selections.length,\r\n },\r\n mentions: moreOptions?.mentionsIds,\r\n },\r\n moreOptions as MiscMessageGenerationOptions\r\n );\r\n\r\n //INFO: Uncomment this section until discover a way to fetch votes data from polls, only sending porpuses so far.\r\n //Baileys library doesn't have any documentation at all to achieve this, so ill wait. - 20/august/2025\r\n\r\n // if (msgSent) {\r\n // const sugarPollObjToReturn = new WhatsPoll(this.socket, {\r\n // pollOptions: selects,\r\n // pollRawMsg: msgSent,\r\n // titleHeader: title,\r\n // withMultiSelect: pollParams.withMultiSelect\r\n // });\r\n\r\n // return sugarPollObjToReturn;\r\n // } else {\r\n // return null;\r\n // }\r\n }\r\n\r\n public async Location(chatId: string, ubicationParams: WhatsMsgUbicationOptions, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WAMessage | null> {\r\n if (!areValidCoordinates(ubicationParams.degreesLatitude, ubicationParams.degreesLongitude)) {\r\n throw new Error(\r\n `WhatsSocketSugarSender.Ubication() => Invalid coordinates: (${ubicationParams.degreesLatitude}, ${ubicationParams.degreesLongitude}).Latitude must be between -90 and 90, longitude between -180 and 180.`\r\n );\r\n }\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n location: {\r\n degreesLatitude: ubicationParams.degreesLatitude,\r\n degreesLongitude: ubicationParams.degreesLongitude,\r\n name: ubicationParams.name,\r\n address: ubicationParams.addressText,\r\n },\r\n mentions: options?.mentionsIds,\r\n },\r\n options as MiscMessageGenerationOptions\r\n );\r\n }\r\n\r\n public async Contact(\r\n chatId: string,\r\n contacts: { name: string; phone: string } | Array<{ name: string; phone: string }>,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WAMessage | null> {\r\n const arr = Array.isArray(contacts) ? contacts : [contacts];\r\n\r\n const vCards = arr.map((c) => {\r\n if (!c.name || !c.phone) {\r\n throw new Error(\"Invalid contact: name and phone are required\");\r\n }\r\n return `BEGIN:VCARD\r\nVERSION:3.0\r\nFN:${c.name}\r\nTEL;type=CELL;type=VOICE;waid=${c.phone}:${c.phone}\r\nEND:VCARD`;\r\n });\r\n\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n contacts: {\r\n displayName: arr.length === 1 ? arr[0]!.name : `${arr.length} contacts`,\r\n contacts: vCards.map((vc) => ({ vcard: vc })),\r\n },\r\n mentions: options?.mentionsIds,\r\n },\r\n options as MiscMessageGenerationOptions\r\n );\r\n }\r\n\r\n /**\r\n * Selects the sending method based on the options provided.\r\n *\r\n * If `options` is not provided or `sendRawWithoutEnqueue` is false,\r\n * the safe queue system will be used to send the message.\r\n *\r\n * If `options.sendRawWithoutEnqueue` is true, the message will be\r\n * sent immediately without using the safe queue system.\r\n *\r\n * @param options - The sending options, or undefined to use the default behavior.\r\n * @returns The method to call to send the message.\r\n */\r\n private _getSendingMethod(options?: WhatsMsgSenderSendingOptionsMINIMUM) {\r\n if (!options) return this.socket._SendSafe;\r\n else if (options.sendRawWithoutEnqueue) {\r\n return this.socket._SendRaw;\r\n } else {\r\n return this.socket._SendSafe;\r\n }\r\n }\r\n}\r\n\r\nfunction areValidCoordinates(lat: number, lon: number): boolean {\r\n return typeof lat === \"number\" && typeof lon === \"number\" && lat >= -90 && lat <= 90 && lon >= -180 && lon <= 180;\r\n}\r\n\r\n//Buffer is only used to differentiate type params, still needed for intelissense!\r\n","import type { Boom } from \"@hapi/boom\";\r\nimport {\r\n type AnyMessageContent,\r\n type GroupMetadata,\r\n type MiscMessageGenerationOptions,\r\n type WAMessageUpdate,\r\n DisconnectReason,\r\n fetchLatestBaileysVersion,\r\n makeWASocket,\r\n useMultiFileAuthState,\r\n} from \"baileys\";\r\n\r\nimport moment from \"moment\";\r\nimport pino from \"pino\";\r\nimport encodeQr from \"qr\";\r\nimport { MsgHelper_FullMsg_GetMsgType, MsgHelper_FullMsg_GetSenderType } from \"../../helpers/Msg.helper.js\";\r\nimport { GetPath } from \"../../libs/BunPath.js\";\r\nimport Delegate from \"../../libs/Delegate.js\";\r\nimport type { MsgType } from \"../../Msg.types.js\";\r\nimport { SenderType } from \"../../Msg.types.js\";\r\nimport { WhatsappGroupIdentifier, WhatsappPhoneNumberIdentifier } from \"../../Whatsapp.types.js\";\r\nimport { WhatsSocket_Submodule_Receiver } from \"./internals/WhatsSocket.receiver.js\";\r\nimport WhatsSocketSenderQueue_SubModule from \"./internals/WhatsSocket.senderqueue.js\";\r\nimport { WhatsSocket_Submodule_SugarSender } from \"./internals/WhatsSocket.sugarsenders.js\";\r\nimport type { IWhatsSocket } from \"./IWhatsSocket.js\";\r\nimport type { WhatsappMessage, WhatsSocketLoggerMode } from \"./types.js\";\r\nimport type { IWhatsSocketServiceAdapter } from \"./WhatsSocket.types.js\";\r\n\r\n/**\r\n * # WhatsApp Socket Options\r\n *\r\n * Configuration options for the WhatsApp Socket behavior.\r\n *\r\n * @example\r\n * ```typescript\r\n * const options: WhatsSocketOptions = { loggerMode: \"silent\", maxReconnectionRetries: 3 };\r\n * ```\r\n */\r\nexport type WhatsSocketOptions = {\r\n /**\r\n * Determines the logging level of the WhatsSocket instance.\r\n * - \"debug\": full details for troubleshooting.\r\n * - \"silent\": minimal output (no logs).\r\n *\r\n * @default \"debug\"\r\n */\r\n loggerMode?: WhatsSocketLoggerMode;\r\n\r\n /**\r\n * Path to the folder where authentication credentials are stored.\r\n * Can be relative to the project root or the current working directory.\r\n *\r\n * @default \"./auth\"\r\n */\r\n credentialsFolder?: string;\r\n\r\n /**\r\n * Maximum number of reconnection attempts if the socket encounters errors.\r\n *\r\n * @default 5\r\n */\r\n maxReconnectionRetries?: number;\r\n\r\n /**\r\n * If true, the socket ignores messages sent by itself, so they won't trigger\r\n * the 'onIncomingMessage' event.\r\n *\r\n * @default true\r\n */\r\n ignoreSelfMessage?: boolean;\r\n\r\n /**\r\n * Maximum number of messages that can be queued for sending globally.\r\n * Useful for buffering pending messages if the bot receives many messages\r\n * in a short time.\r\n *\r\n * @default 20\r\n */\r\n senderQueueMaxLimit?: number;\r\n\r\n /**\r\n * Delay (in milliseconds) between sending queued messages.\r\n * Helps prevent spamming or flooding when sending many messages rapidly.\r\n *\r\n * @default 100\r\n */\r\n delayMilisecondsBetweenMsgs?: number;\r\n\r\n /**\r\n * Optionally provide a custom implementation of the WhatsApp socket API.\r\n * By default, Baileys is used.\r\n *\r\n * @note Primarily intended for testing. Use at your own risk if you override.\r\n */\r\n ownImplementationSocketAPIWhatsapp?: IWhatsSocketServiceAdapter;\r\n};\r\n\r\n/**\r\n * # WhatsApp Socket Core\r\n *\r\n * Class used to interact with the WhatsApp Web socket client (baileys).\r\n * Will start the socket and keep it connected until you call the Shutdown method.\r\n * Provides some events you can subscribe to, to get notified when different things happen.\r\n *\r\n * @example\r\n * ```typescript\r\n * const socket = new WhatsSocket({\r\n * credentialsFolder: \"./auth\",\r\n * loggerMode: \"silent\",\r\n * maxReconnectionRetries: 5,\r\n * ignoreSelfMessage: true\r\n * });\r\n *\r\n * socket.onIncomingMsg.Subscribe((senderId, chatId, rawMsg, msgType, senderType) => {\r\n * console.log(`Msg: ${msgType} | SenderId: ${senderId}`);\r\n * });\r\n *\r\n * socket.Start().then(() => {\r\n * console.log(\"WhatsSocket initialized successfully!\");\r\n * }).catch((error) => {\r\n * console.error(\"Error initializing WhatsSocket:\", error);\r\n * });\r\n * ```\r\n */\r\nexport default class WhatsSocket implements IWhatsSocket {\r\n //All documentation comes from \"IWhatsSocket\" interface, check it to see docs about this events\r\n public onIncomingMsg: Delegate<\r\n (senderId_LID: string | null, sender_PN: string | null, chatId: string, rawMsg: WhatsappMessage, msgType: MsgType, senderType: SenderType) => void\r\n > = new Delegate();\r\n\r\n public onUpdateMsg: Delegate<\r\n (senderId_LID: string | null, senderId_PN: string | null, chatId: string, rawMsgUpdate: WhatsappMessage, msgType: MsgType, senderType: SenderType) => void\r\n > = new Delegate();\r\n\r\n public onSentMessage: Delegate<(chatId: string, rawContentMsg: AnyMessageContent, optionalMisc?: MiscMessageGenerationOptions) => void> = new Delegate();\r\n public onRestart: Delegate<() => Promise<void>> = new Delegate();\r\n public onGroupEnter: Delegate<(groupInfo: GroupMetadata) => void> = new Delegate();\r\n public onGroupUpdate: Delegate<(groupInfo: Partial<GroupMetadata>) => void> = new Delegate();\r\n public onStartupAllGroupsIn: Delegate<(allGroupsIn: GroupMetadata[]) => void> = new Delegate();\r\n\r\n public get ownJID(): string {\r\n return this.Socket.user!.id;\r\n }\r\n\r\n //=== Subcomponents ===\r\n //They're initialized/instantiated in \"Start()\"\r\n public Socket!: IWhatsSocketServiceAdapter;\r\n private _senderQueue!: WhatsSocketSenderQueue_SubModule;\r\n /**\r\n * Sender module and sugar layer for sending all kinds of msgs.\r\n * Text, Images, Videos, Polls, etc...\r\n */\r\n public Send!: WhatsSocket_Submodule_SugarSender;\r\n\r\n /**\r\n * Receive internal module. To wait for someone msg's.\r\n */\r\n public Receive!: WhatsSocket_Submodule_Receiver;\r\n\r\n // === Normal Public Properties ===\r\n public ActualReconnectionRetries: number = 0;\r\n\r\n // === Configuration Properties ===\r\n private _loggerMode: WhatsSocketLoggerMode;\r\n private _credentialsFolder: string;\r\n private _ignoreSelfMessages: boolean;\r\n private _maxReconnectionRetries: number;\r\n private _senderQueueMaxLimit: number;\r\n private _milisecondsDelayBetweenSentMsgs: number;\r\n private _customSocketImplementation?: IWhatsSocketServiceAdapter;\r\n\r\n constructor(options?: WhatsSocketOptions) {\r\n this._loggerMode = options?.loggerMode ?? \"silent\";\r\n this._credentialsFolder = options?.credentialsFolder ?? \"./auth\";\r\n this._ignoreSelfMessages = options?.ignoreSelfMessage ?? true;\r\n this._senderQueueMaxLimit = options?.senderQueueMaxLimit ?? 20;\r\n this._milisecondsDelayBetweenSentMsgs = options?.delayMilisecondsBetweenMsgs ?? 100;\r\n this._customSocketImplementation = options?.ownImplementationSocketAPIWhatsapp;\r\n this._maxReconnectionRetries = options?.maxReconnectionRetries ?? 5;\r\n }\r\n private _isRestarting: boolean = false;\r\n\r\n /**\r\n * Initializes the WhatsSocket instance and start connecting to Whatsapp.\r\n * After this method is called, the socket will be listening for incoming messages and events all the time.\r\n * Can be canceled and shutdown by calling the `Shutdown` method.\r\n * @returns A promise that will be running in the background all the time until the socket is closed.\r\n */\r\n public async Start(): Promise<void> {\r\n this.ActualReconnectionRetries = 0;\r\n await this._initializeSelf();\r\n }\r\n\r\n /**\r\n * Restarts the socket by shutting down current one and then starting a new instance, effectively \"restarting\" the socket.\r\n * @returns A promise that will be running in the background all the time until the socket is closed.\r\n */\r\n public async Restart(): Promise<void> {\r\n this._isRestarting = true;\r\n await this.Shutdown();\r\n await this._initializeSelf();\r\n this._isRestarting = false;\r\n }\r\n\r\n private async _initializeSelf(): Promise<void> {\r\n await this.InitializeInternalSocket();\r\n this.ConfigureReconnection();\r\n this.ConfigureMessageIncoming();\r\n this.ConfigureMessagesUpdates();\r\n this.ConfigureGroupsEnter();\r\n this.ConfigureGroupsUpdates();\r\n\r\n //Thanks JavaScript ☠️\r\n this._SendSafe = this._SendSafe.bind(this);\r\n this._SendRaw = this._SendRaw.bind(this);\r\n this.GetRawGroupMetadata = this.GetRawGroupMetadata.bind(this);\r\n this.InitializeInternalSocket = this.InitializeInternalSocket.bind(this);\r\n this.Start = this.Start.bind(this);\r\n this.Shutdown = this.Shutdown.bind(this);\r\n this._initializeSelf = this._initializeSelf.bind(this);\r\n this.ConfigureReconnection = this.ConfigureReconnection.bind(this);\r\n this.ConfigureMessageIncoming = this.ConfigureMessageIncoming.bind(this);\r\n this.ConfigureGroupsEnter = this.ConfigureGroupsEnter.bind(this);\r\n this.ConfigureGroupsUpdates = this.ConfigureGroupsUpdates.bind(this);\r\n }\r\n\r\n private async InitializeInternalSocket() {\r\n const authInfoPath: string = GetPath(this._credentialsFolder);\r\n const { state, saveCreds } = await useMultiFileAuthState(authInfoPath);\r\n\r\n const { version } = await fetchLatestBaileysVersion(); //1. I've added this line\r\n if (this._customSocketImplementation) {\r\n this.Socket = this._customSocketImplementation;\r\n } else {\r\n const logger = pino({ level: this._loggerMode === \"recommended\" ? \"silent\" : this._loggerMode });\r\n this.Socket = await makeWASocket({\r\n version, //2. Then added \"version\" prop in Socket constructor\r\n auth: state,\r\n logger: logger,\r\n // browser: Browsers.windows(\"Chrome\"),\r\n // syncFullHistory: true,\r\n });\r\n }\r\n this.Socket.ev.on(\"creds.update\", saveCreds);\r\n\r\n //== Initializing internal sub-modules ==\r\n this._senderQueue = new WhatsSocketSenderQueue_SubModule(this, this._senderQueueMaxLimit, this._milisecondsDelayBetweenSentMsgs);\r\n this.Send = new WhatsSocket_Submodule_SugarSender(this);\r\n this.Receive = new WhatsSocket_Submodule_Receiver(this);\r\n }\r\n\r\n public async Shutdown() {\r\n await this.Socket.ws.close();\r\n }\r\n\r\n private ConfigureReconnection(): void {\r\n this.Socket.ev.on(\"connection.update\", async (update) => {\r\n const { connection, lastDisconnect, qr } = update;\r\n\r\n // Show QR code if needed\r\n if (qr) {\r\n console.log(\"[Whatsbotcord]: ⌛ Logging in. Scan this qr code to get started!\");\r\n console.log(encodeQr(qr, \"ascii\"));\r\n }\r\n\r\n // Successfully connected\r\n if (connection === \"open\") {\r\n this.ActualReconnectionRetries = 0; // reset retries\r\n try {\r\n if (this._loggerMode !== \"silent\") {\r\n console.log(\"[Whatsbotcord]: ✅ Connected to whatsapp servers\");\r\n }\r\n const groups = Object.values(await this.Socket.groupFetchAllParticipating());\r\n this.onStartupAllGroupsIn.CallAll(groups);\r\n if (this._loggerMode !== \"silent\") {\r\n console.log(\"[Whatsbotcord]: 💬 All groups metadata fetched successfully\");\r\n }\r\n } catch (err) {\r\n if (this._loggerMode !== \"silent\") {\r\n console.error(\"[Whatsbotcord]: ❌ ERROR: Couldn't fetch groups\", err);\r\n }\r\n }\r\n }\r\n\r\n // Connection closed\r\n if (connection === \"close\") {\r\n const error = lastDisconnect?.error as Boom | undefined;\r\n const statusCode = error?.output?.statusCode;\r\n\r\n // Only attempt to reconnect if not logged out\r\n const shouldReconnect = statusCode !== DisconnectReason.loggedOut;\r\n if (this._loggerMode !== \"silent\") {\r\n console.warn(\"[Whatsbotcord]: ❌ Socket closed\", statusCode ? `(code: ${statusCode})` : \"\");\r\n }\r\n\r\n if (!shouldReconnect) {\r\n if (this._loggerMode !== \"silent\") {\r\n console.error(\"[Whatsbotcord]: ❌ ERROR: Socket logged out. Not reconnecting.\");\r\n }\r\n await this.Shutdown();\r\n return;\r\n }\r\n\r\n // Increment retries immediately\r\n this.ActualReconnectionRetries++;\r\n\r\n // Check max retries\r\n if (this.ActualReconnectionRetries > this._maxReconnectionRetries) {\r\n if (this._loggerMode !== \"silent\") {\r\n console.error(`[Whatsbotcord]: ❌ ERROR: Max reconnection attempts reached (${this._maxReconnectionRetries}). Giving up.`);\r\n }\r\n await this.Shutdown();\r\n return;\r\n }\r\n\r\n // Prevent overlapping restarts\r\n if (this._isRestarting) return;\r\n\r\n this._isRestarting = true;\r\n if (this._loggerMode !== \"silent\") {\r\n console.log(`[Whatsbotcord]: ❌ INFO: Restarting socket (attempt ${this.ActualReconnectionRetries}/${this._maxReconnectionRetries})...`);\r\n }\r\n\r\n try {\r\n await this.Restart();\r\n this.onRestart.CallAll();\r\n if (this._loggerMode !== \"silent\") {\r\n console.log(\"[Whatsbotcord]: ❌ INFO: Socket restarted successfully!\");\r\n }\r\n } catch (err) {\r\n if (this._loggerMode !== \"silent\") {\r\n console.error(\"[Whatsbotcord]: ❌ ERROR: Socket restart failed\", err);\r\n }\r\n } finally {\r\n this._isRestarting = false;\r\n }\r\n }\r\n });\r\n }\r\n\r\n private ConfigureMessageIncoming(): void {\r\n this.Socket.ev.on(\"messages.upsert\", async (messageUpdate) => {\r\n if (!messageUpdate.messages) return;\r\n for (const msgAny of messageUpdate.messages) {\r\n const msg = msgAny as WhatsappMessage;\r\n if (this._ignoreSelfMessages) if (!msg.message || msg.key.fromMe) continue;\r\n const chatId = msg.key.remoteJid!;\r\n const senderId_LID: string | null = msg.key.participant ? (msg.key.participant.trim() !== \"\" ? msg.key.participant : null) : null;\r\n const senderId_PN: string | null = msg.key.participantAlt ? (msg.key.participantAlt.trim() !== \"\" ? msg.key.participantAlt : null) : null;\r\n let senderType: SenderType = SenderType.Unknown;\r\n if (chatId && chatId.endsWith(WhatsappGroupIdentifier)) senderType = SenderType.Group;\r\n if (chatId && chatId.endsWith(WhatsappPhoneNumberIdentifier)) senderType = SenderType.Individual;\r\n this.onIncomingMsg.CallAll(senderId_LID, senderId_PN, chatId, msg, MsgHelper_FullMsg_GetMsgType(msg), senderType);\r\n }\r\n });\r\n }\r\n\r\n private ConfigureMessagesUpdates(): void {\r\n this.Socket.ev.on(\"messages.update\", (msgsUpdates: WAMessageUpdate[]) => {\r\n if (!msgsUpdates || msgsUpdates.length === 0) return;\r\n for (const msgUpdateRaw of msgsUpdates) {\r\n const msgUpdate = msgUpdateRaw as WhatsappMessage;\r\n if (this._ignoreSelfMessages) if (msgUpdate.key.fromMe) return;\r\n\r\n const senderType: SenderType = MsgHelper_FullMsg_GetSenderType(msgUpdate);\r\n const chatId: string = msgUpdate.key.remoteJid!;\r\n const senderId_LID: string | null = msgUpdate.key.participant ? (msgUpdate.key.participant.trim() !== \"\" ? msgUpdate.key.participant : null) : null;\r\n const senderId_PN: string | null = msgUpdate.key.participantAlt ? (msgUpdate.key.participantAlt !== \"\" ? msgUpdate.key.participantAlt : null) : null;\r\n this.onUpdateMsg.CallAll(senderId_LID, senderId_PN, chatId, msgUpdate, MsgHelper_FullMsg_GetMsgType(msgUpdate), senderType);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Gets the metadata of a group chat by its chat ID. (e.g: \"23423423123@g.us\")\r\n * @param chatId The chat ID of the group you want to get metadata from.\r\n * @throws Will throw an error if the provided chatId is not a group chat ID\r\n * @returns A promise that resolves to the group metadata.\r\n */\r\n public async GetRawGroupMetadata(chatId: string): Promise<GroupMetadata> {\r\n if (!chatId.endsWith(WhatsappGroupIdentifier))\r\n throw new Error(\"Bad args => WhatsSocket.GetGroupMetadata() => Provided chatId is not a group chat ID. => \" + chatId);\r\n return await this.Socket.groupMetadata(chatId);\r\n }\r\n\r\n private ConfigureGroupsEnter(): void {\r\n this.Socket.ev.on(\"groups.upsert\", async (groupsUpserted: GroupMetadata[]) => {\r\n for (const group of groupsUpserted) {\r\n this.onGroupEnter.CallAll(group);\r\n if (this._loggerMode !== \"silent\") {\r\n console.info(`INFO: Joined to a new group ${group.subject} at ${moment().format(\"YYYY-MM-DD HH:mm:ss\")}`);\r\n }\r\n }\r\n });\r\n }\r\n\r\n private ConfigureGroupsUpdates(): void {\r\n this.Socket.ev.on(\"groups.update\", (args) => {\r\n if (args.length === 0) {\r\n if (this._loggerMode !== \"silent\") {\r\n console.log(\"INFO: No group updates received.\");\r\n }\r\n return;\r\n }\r\n for (let i = 0; i < args.length; i++) {\r\n const groupMetadata: Partial<GroupMetadata> | undefined = args[i];\r\n if (groupMetadata) {\r\n this.onGroupUpdate.CallAll(groupMetadata);\r\n }\r\n }\r\n });\r\n }\r\n\r\n public async _SendSafe(chatId_JID: string, content: AnyMessageContent, options?: MiscMessageGenerationOptions): Promise<WhatsappMessage | null> {\r\n return this._senderQueue.Enqueue(chatId_JID, content, options);\r\n }\r\n\r\n public async _SendRaw(chatId_JID: string, content: AnyMessageContent, options?: MiscMessageGenerationOptions): Promise<WhatsappMessage | null> {\r\n const toReturn = (await this.Socket.sendMessage(chatId_JID, content, options)) ?? null;\r\n return toReturn;\r\n }\r\n}\r\n","import { downloadMediaMessage } from \"baileys\";\r\nimport { autobind } from \"../../../helpers/Decorators.helper.js\";\r\nimport { MsgHelper_FullMsg_GetSenderType, MsgHelper_FullMsg_GetText } from \"../../../helpers/Msg.helper.js\";\r\nimport { MsgType, SenderType } from \"../../../Msg.types.js\";\r\nimport { WhatsappLIDIdentifier, WhatsappPhoneNumberIdentifier } from \"../../../Whatsapp.types.js\";\r\nimport type { IWhatsSocket_Submodule_Receiver } from \"../../whats_socket/internals/IWhatsSocket.receiver.js\";\r\nimport type {\r\n IWhatsSocket_Submodule_SugarSender,\r\n WhatsMsgPollOptions,\r\n WhatsMsgSenderSendingOptions,\r\n WhatsMsgSenderSendingOptionsMINIMUM,\r\n} from \"../../whats_socket/internals/IWhatsSocket.sugarsender.js\";\r\nimport {\r\n type GroupMetadataInfo,\r\n type WhatsSocketReceiverWaitOptions,\r\n WhatsSocketReceiverHelper_isReceiverError,\r\n} from \"../../whats_socket/internals/WhatsSocket.receiver.js\";\r\nimport type { WhatsappMessage } from \"../../whats_socket/types.js\";\r\nimport type {\r\n ChatContextContactRes,\r\n ChatContextUbication,\r\n IChatContext,\r\n IChatContext_CloneTargetedTo_FromIds_GROUP_Params,\r\n IChatContext_CloneTargetedTo_FromIds_Individual_Params,\r\n IChatContext_CloneTargetedTo_FromWhatsmsg_Params,\r\n IChatContext_WaitYesOrNoAnswer_Params,\r\n} from \"./IChatContext.js\";\r\n\r\n/**\r\n * # Chat Context Configuration\r\n *\r\n * Extra configuration properties for the Chat Context initializing.\r\n *\r\n * @example\r\n * ```typescript\r\n * const config: IChatContextConfig = { timeoutSeconds: 30 };\r\n * ```\r\n */\r\nexport type IChatContextConfig = WhatsSocketReceiverWaitOptions & {\r\n /**\r\n * Used primarly in mocking system\r\n */\r\n explicitSenderType?: SenderType;\r\n\r\n /**\r\n * Default keywords to be interpreted as an affirmative (\"yes\") response\r\n * in `WaitYesOrNoAnswer`. Case-insensitive.\r\n *\r\n * @default [\"yes\", \"y\", \"si\", \"s\", \"ok\", \"vale\", \"sí\"]\r\n */\r\n positiveAnswerOptions?: string[];\r\n\r\n /**\r\n * Default keywords to be interpreted as a negative (\"no\") response\r\n * in `WaitYesOrNoAnswer`. Case-insensitive.\r\n *\r\n * @default [\"no\", \"n\"]\r\n */\r\n negativeAnswerOptions?: string[];\r\n};\r\n\r\n/**\r\n * # Chat Context\r\n *\r\n * A sugar-layer abstraction for sending/receiving msgs bound to the actual chat.\r\n *\r\n * This class simplifies sending messages and reactions to a fixed chat\r\n * without needing to repeatedly provide the chat ID. It also provides\r\n * helpers for common bot patterns like reacting with checkmarks or crosses to the\r\n * initial message and other common high-level utilities.\r\n *\r\n * @example\r\n * ```typescript\r\n * await ctx.SendText(\"Hello\");\r\n * ```\r\n */\r\nexport class ChatContext implements IChatContext {\r\n /**\r\n * Low-level sender dependency responsible for dispatching\r\n * messages, reactions, edits, and other outbound events.\r\n *\r\n * This is an internal utility—use higher-level convenience\r\n * methods instead of calling this directly where possible.\r\n */\r\n private _internalSend: IWhatsSocket_Submodule_SugarSender;\r\n\r\n /**\r\n * Low-level receiver dependency responsible for listening\r\n * to incoming WhatsApp events (messages, status updates, etc).\r\n *\r\n * Exposed internally so that session features can react to\r\n * real-time events within the same chat context.\r\n */\r\n private _internalReceive: IWhatsSocket_Submodule_Receiver;\r\n\r\n public readonly FixedParticipantPN: string | null;\r\n\r\n public readonly FixedParticipantLID: string | null;\r\n\r\n public readonly FixedChatId: string;\r\n\r\n public InitialMsg: WhatsappMessage | null;\r\n\r\n public readonly FixedSenderType: SenderType;\r\n\r\n public Config: IChatContextConfig;\r\n\r\n /**\r\n * Creates a new chat session bound to a specific chat and initial message.\r\n *\r\n * @param participantID_LID - The ID of the participant that triggered this session,\r\n * or `null` if the origin cannot be determined.\r\n * @param fixedChatId - The WhatsApp chat JID this context is tied to.\r\n * @param initialMsg - The original message object that caused this context to spawn.\r\n * @param senderDependency - Internal sender utility for dispatching messages.\r\n * @param receiverDependency - Internal receiver utility for subscribing to events.\r\n * @param config - Context configuration controlling runtime behavior.\r\n *\r\n * @remarks\r\n * - All `Fixed*` properties are immutable once the context is created.\r\n * - The context is designed to encapsulate state and metadata for a\r\n * single session, preventing accidental leakage between chats.\r\n */\r\n constructor(\r\n participantID_LID: string | null,\r\n participantID_PN: string | null,\r\n fixedChatId: string,\r\n initialMsg: WhatsappMessage | null,\r\n senderDependency: IWhatsSocket_Submodule_SugarSender,\r\n receiverDependency: IWhatsSocket_Submodule_Receiver,\r\n config: IChatContextConfig\r\n ) {\r\n this.Config = config;\r\n this.FixedParticipantLID = participantID_LID;\r\n this.FixedParticipantPN = participantID_PN;\r\n this._internalSend = senderDependency;\r\n this._internalReceive = receiverDependency;\r\n this.FixedChatId = fixedChatId;\r\n this.InitialMsg = initialMsg;\r\n this.FixedSenderType = config.explicitSenderType ?? (this.InitialMsg !== null ? MsgHelper_FullMsg_GetSenderType(this.InitialMsg) : SenderType.Individual);\r\n\r\n this.WaitText = this.WaitText.bind(this);\r\n }\r\n\r\n @autobind\r\n public Clone(): IChatContext {\r\n return new ChatContext(\r\n this.FixedParticipantLID,\r\n this.FixedParticipantPN,\r\n this.FixedChatId,\r\n this.InitialMsg,\r\n this._internalSend,\r\n this._internalReceive,\r\n this.Config\r\n );\r\n }\r\n\r\n @autobind\r\n public CloneButTargetedToWithInitialMsg(params: IChatContext_CloneTargetedTo_FromWhatsmsg_Params): IChatContext {\r\n const keysData = params.initialMsg.key;\r\n\r\n let ID_PN: string | null = null;\r\n let ID_LID: string | null = null;\r\n\r\n //Neccesary due to how bailey.js library works. Check update to v7.0.0 on their official page to understand this\r\n if (keysData.participant) {\r\n if (keysData.participant.endsWith(WhatsappLIDIdentifier)) {\r\n ID_LID = keysData.participant;\r\n } else if (keysData.participant.endsWith(WhatsappPhoneNumberIdentifier)) {\r\n ID_PN = keysData.participant;\r\n }\r\n }\r\n\r\n if (keysData.participantAlt) {\r\n if (keysData.participantAlt.endsWith(WhatsappLIDIdentifier)) {\r\n ID_LID = keysData.participantAlt;\r\n } else if (keysData.participantAlt.endsWith(WhatsappPhoneNumberIdentifier)) {\r\n ID_PN = keysData.participantAlt;\r\n }\r\n }\r\n\r\n //prettier-ignore\r\n return new ChatContext(\r\n ID_LID,\r\n ID_PN,\r\n params.initialMsg.key.remoteJid!,\r\n params.initialMsg,\r\n this._internalSend,\r\n this._internalReceive,\r\n params?.newConfig ?? this.Config\r\n );\r\n }\r\n\r\n @autobind\r\n public CloneButTargetedToIndividualChat(params: IChatContext_CloneTargetedTo_FromIds_Individual_Params): IChatContext {\r\n const configCopy: IChatContextConfig = structuredClone(this.Config);\r\n //Case: For individual chats\r\n if (this.FixedSenderType === SenderType.Group) {\r\n configCopy.explicitSenderType = SenderType.Individual;\r\n }\r\n //prettier-ignore\r\n return new ChatContext(\r\n null,\r\n null,\r\n params.userChatId,\r\n this.InitialMsg,\r\n this._internalSend,\r\n this._internalReceive,\r\n {...configCopy, ...params.newConfig}\r\n );\r\n }\r\n\r\n @autobind\r\n public CloneButTargetedToGroupChat(params: IChatContext_CloneTargetedTo_FromIds_GROUP_Params): IChatContext {\r\n const configCopy: IChatContextConfig = structuredClone(this.Config);\r\n if (this.FixedSenderType === SenderType.Individual) {\r\n configCopy.explicitSenderType = SenderType.Group;\r\n }\r\n //prettier-ignore\r\n return new ChatContext(\r\n params.participant_LID ?? this.FixedParticipantLID,\r\n params.participant_PN ?? this.FixedParticipantPN,\r\n params.groupChatId,\r\n this.InitialMsg,\r\n this._internalSend,\r\n this._internalReceive,\r\n {...configCopy, ...params.newConfig}\r\n );\r\n }\r\n\r\n private async HandlePrimaryMsg(mainMsgPromise: Promise<WhatsappMessage | null>): Promise<WhatsappMessage | null> {\r\n const msg: WhatsappMessage | null = await mainMsgPromise;\r\n if (!msg) return null;\r\n if (!this.InitialMsg) {\r\n this.InitialMsg = msg;\r\n }\r\n return msg;\r\n }\r\n\r\n @autobind\r\n public SendText(text: string, options?: WhatsMsgSenderSendingOptions): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Text(this.FixedChatId, text, options));\r\n }\r\n\r\n @autobind\r\n public async SendImg(imagePath: string, options?: WhatsMsgSenderSendingOptions): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Image(this.FixedChatId, { source: imagePath, caption: undefined }, options));\r\n }\r\n\r\n @autobind\r\n public SendImgWithCaption(imagePath: string, caption: string, options?: WhatsMsgSenderSendingOptions): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Image(this.FixedChatId, { source: imagePath, caption }, options));\r\n }\r\n\r\n @autobind\r\n public SendImgFromBuffer(\r\n imagePath: Buffer | Buffer<ArrayBuffer>,\r\n extensionType: string,\r\n options?: WhatsMsgSenderSendingOptions\r\n ): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(\r\n this._internalSend.Image(this.FixedChatId, { source: imagePath, formatExtension: extensionType, caption: undefined }, options)\r\n );\r\n }\r\n\r\n @autobind\r\n public SendImgFromBufferWithCaption(\r\n imagePath: Buffer,\r\n extensionType: string,\r\n caption: string,\r\n options?: WhatsMsgSenderSendingOptions\r\n ): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Image(this.FixedChatId, { source: imagePath, formatExtension: extensionType, caption: caption }, options));\r\n }\r\n\r\n @autobind\r\n public SendReactEmojiTo(msgToReactTo: WhatsappMessage, emojiStr: string, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n return this._internalSend.ReactEmojiToMsg(this.FixedChatId, msgToReactTo, emojiStr, options);\r\n }\r\n\r\n @autobind\r\n public SendReactEmojiToInitialMsg(emojiStr: string, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n if (!this.InitialMsg) {\r\n throw ThrowBadFirstMsgError();\r\n }\r\n return this._internalSend.ReactEmojiToMsg(this.FixedChatId, this.InitialMsg, emojiStr, options);\r\n }\r\n\r\n @autobind\r\n public Ok(options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n if (!this.InitialMsg) {\r\n throw ThrowBadFirstMsgError();\r\n }\r\n return this._internalSend.ReactEmojiToMsg(this.FixedChatId, this.InitialMsg, \"✅\", options);\r\n }\r\n\r\n @autobind\r\n public Loading(options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n if (!this.InitialMsg) {\r\n throw ThrowBadFirstMsgError();\r\n }\r\n return this._internalSend.ReactEmojiToMsg(this.FixedChatId, this.InitialMsg, \"⌛\", options);\r\n }\r\n\r\n @autobind\r\n public Fail(options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n if (!this.InitialMsg) {\r\n throw ThrowBadFirstMsgError();\r\n }\r\n return this._internalSend.ReactEmojiToMsg(this.FixedChatId, this.InitialMsg, \"❌\", options);\r\n }\r\n\r\n @autobind\r\n public SendSticker(stickerUrlSource: string | Buffer, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Sticker(this.FixedChatId, stickerUrlSource, options));\r\n }\r\n\r\n @autobind\r\n public SendAudio(audioSource: string, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Audio(this.FixedChatId, { source: audioSource }, options));\r\n }\r\n\r\n @autobind\r\n public SendAudioFromBuffer(audioSource: Buffer, formatFile: string, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Audio(this.FixedChatId, { source: audioSource, formatExtension: formatFile }, options));\r\n }\r\n\r\n @autobind\r\n public SendVideo(videopath: string, options?: WhatsMsgSenderSendingOptions): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Video(this.FixedChatId, { source: videopath }, options));\r\n }\r\n\r\n @autobind\r\n public SendVideoWithCaption(videoPath: string, caption: string, options?: WhatsMsgSenderSendingOptions): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Video(this.FixedChatId, { source: videoPath, caption: caption }, options));\r\n }\r\n\r\n @autobind\r\n public SendVideoFromBuffer(videoBuffer: Buffer, formatFile: string, options?: WhatsMsgSenderSendingOptions): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Video(this.FixedChatId, { source: videoBuffer, formatExtension: formatFile }, options));\r\n }\r\n\r\n @autobind\r\n public SendVideoFromBufferWithCaption(\r\n videoBuffer: Buffer,\r\n caption: string,\r\n formatFile: string,\r\n options?: WhatsMsgSenderSendingOptions\r\n ): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Video(this.FixedChatId, { source: videoBuffer, formatExtension: formatFile, caption: caption }, options));\r\n }\r\n\r\n @autobind\r\n public SendPoll(\r\n pollTitle: string,\r\n selections: string[],\r\n pollParams: WhatsMsgPollOptions,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Poll(this.FixedChatId, pollTitle, selections, pollParams, options));\r\n }\r\n\r\n @autobind\r\n public SendUbication(degreesLatitude: number, degreesLongitude: number, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(\r\n this._internalSend.Location(this.FixedChatId, { degreesLatitude, degreesLongitude, addressText: undefined, name: undefined }, options)\r\n );\r\n }\r\n\r\n @autobind\r\n public SendUbicationWithDescription(\r\n degreesLatitude: number,\r\n degreesLongitude: number,\r\n ubicationName: string,\r\n moreInfoAddress: string,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(\r\n this._internalSend.Location(this.FixedChatId, { degreesLatitude, degreesLongitude, addressText: moreInfoAddress, name: ubicationName }, options)\r\n );\r\n }\r\n\r\n @autobind\r\n public SendContact(\r\n contacts: { name: string; phone: string } | Array<{ name: string; phone: string }>,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Contact(this.FixedChatId, contacts, options));\r\n }\r\n\r\n @autobind\r\n public SendDocument(docPath: string, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Document(this.FixedChatId, { source: docPath }, options));\r\n }\r\n\r\n @autobind\r\n public SendDocumentWithCustomName(\r\n docPath: string,\r\n fileNameToDisplay: string,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Document(this.FixedChatId, { source: docPath, fileNameToDisplay: fileNameToDisplay }, options));\r\n }\r\n\r\n @autobind\r\n public SendDocumentFromBuffer(\r\n docBuffer: Buffer,\r\n fileNameToDisplayWithoutExt: string,\r\n extensionFileTypeOnly: string,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WhatsappMessage | null> {\r\n //prettier-ignore\r\n return this.HandlePrimaryMsg(this._internalSend.Document(\r\n this.FixedChatId,\r\n { source: docBuffer, fileNameWithoutExtension: fileNameToDisplayWithoutExt, formatExtension: extensionFileTypeOnly },\r\n options\r\n ));\r\n }\r\n //============================ RECEIVING ==============================\r\n\r\n @autobind\r\n public async WaitMsg(expectedType: MsgType, localOptions?: Partial<IChatContextConfig>): Promise<WhatsappMessage | null> {\r\n switch (this.FixedSenderType) {\r\n case SenderType.Unknown:\r\n throw new Error(\r\n \"[FATAL ERROR] on ChatContext.WaitMsg: ChatContext Obj received a non valid WhatsappMessage as parameter (couldn't identify sender type)\"\r\n );\r\n case SenderType.Group:\r\n if (!this.FixedParticipantLID) {\r\n throw new Error(\r\n \"[FATAL ERROR]: This shouldn't happen at all. Couldn't find group participant from group msg!... Report this bug as a github issue please.\"\r\n );\r\n }\r\n try {\r\n return await this._internalReceive.WaitUntilNextRawMsgFromUserIDInGroup(\r\n this.FixedParticipantLID,\r\n this.FixedParticipantPN,\r\n this.FixedChatId,\r\n expectedType,\r\n {\r\n ...this.Config,\r\n ...localOptions,\r\n }\r\n );\r\n } catch (e) {\r\n if (WhatsSocketReceiverHelper_isReceiverError(e)) {\r\n if (!e.wasAbortedByUser) {\r\n return null;\r\n }\r\n }\r\n throw e;\r\n }\r\n case SenderType.Individual:\r\n try {\r\n return await this._internalReceive.WaitUntilNextRawMsgFromUserIdInPrivateConversation(this.FixedChatId, expectedType, {\r\n ...this.Config,\r\n ...localOptions,\r\n });\r\n } catch (e) {\r\n if (WhatsSocketReceiverHelper_isReceiverError(e)) {\r\n if (!e.wasAbortedByUser) {\r\n return null;\r\n }\r\n }\r\n throw e;\r\n }\r\n }\r\n }\r\n\r\n //@autbinded in constructor()\r\n public async WaitText(localOptions?: Partial<IChatContextConfig>): Promise<string | null> {\r\n const found: WhatsappMessage | null = await this.WaitMsg(MsgType.Text, localOptions);\r\n if (!found) return null;\r\n const extractedTxtToReturn: string | null = MsgHelper_FullMsg_GetText(found);\r\n return extractedTxtToReturn;\r\n }\r\n\r\n @autobind\r\n public async WaitYesOrNoAnswer(localOptions?: Partial<IChatContext_WaitYesOrNoAnswer_Params>): Promise<boolean | null> {\r\n const text: string | null = await this.WaitText(localOptions?.normalConfig);\r\n if (!text) {\r\n return null;\r\n }\r\n\r\n const textLower: string = text.toLowerCase();\r\n //prettier-ignore\r\n const positiveAnswers: string[] = localOptions?.waitYesOrNoOptions?.positiveAnswerOptions ?? this.Config.positiveAnswerOptions ?? [\"yes\", \"y\", \"si\", \"s\", \"ok\", \"vale\", \"sí\"];\r\n //prettier-ignore\r\n const negativeAnswers: string[] = localOptions?.waitYesOrNoOptions?.negativeAnswerOptions ?? this.Config.negativeAnswerOptions ?? [\"no\", \"n\"];\r\n\r\n if (positiveAnswers.includes(textLower)) {\r\n return true;\r\n }\r\n\r\n if (negativeAnswers.includes(textLower)) {\r\n return false;\r\n }\r\n\r\n return null;\r\n }\r\n\r\n @autobind\r\n public async WaitMultimedia(\r\n msgTypeToWaitFor: MsgType.Image | MsgType.Sticker | MsgType.Video | MsgType.Document | MsgType.Audio,\r\n localOptions?: Partial<IChatContextConfig>\r\n ): Promise<Buffer | null> {\r\n const found: WhatsappMessage | null = await this.WaitMsg(msgTypeToWaitFor, localOptions);\r\n if (!found) return null;\r\n const buffer = await downloadMediaMessage(found, \"buffer\", {});\r\n return buffer;\r\n }\r\n\r\n @autobind\r\n public async WaitUbication(localOptions?: Partial<IChatContextConfig>): Promise<ChatContextUbication | null> {\r\n const found: WhatsappMessage | null = await this.WaitMsg(MsgType.Ubication, localOptions);\r\n if (!found) return null;\r\n const res = found?.message?.locationMessage;\r\n if (!res) return null;\r\n return {\r\n degreesLatitude: res.degreesLatitude ?? -1,\r\n degreesLongitude: res.degreesLongitude ?? -1,\r\n thumbnailJpegBuffer: res.jpegThumbnail ?? null,\r\n isLive: res.isLive ?? false,\r\n };\r\n }\r\n\r\n @autobind\r\n public async WaitContact(localOptions?: Partial<IChatContextConfig>): Promise<ChatContextContactRes | ChatContextContactRes[] | null> {\r\n // Wait for a contact message\r\n const message = await this.WaitMsg(MsgType.Contact, localOptions);\r\n if (!message) return null;\r\n\r\n // Handle single contact message\r\n if (message.message?.contactMessage) {\r\n const contact = message.message.contactMessage;\r\n const number = contact.vcard?.match(/WAID=(\\d+)/i)?.[1] || \"\";\r\n return {\r\n name: contact.displayName || \"\",\r\n number,\r\n whatsappId_PN: number ? `${number}${WhatsappPhoneNumberIdentifier}` : \"\",\r\n };\r\n }\r\n\r\n // Handle multiple contacts message\r\n if (message.message?.contactsArrayMessage?.contacts) {\r\n return message.message.contactsArrayMessage.contacts.map((contact) => {\r\n const number = contact.vcard?.match(/WAID=(\\d+)/i)?.[1] || \"\";\r\n return {\r\n name: contact.displayName || \"\",\r\n number,\r\n whatsappId_PN: number ? `${number}${WhatsappPhoneNumberIdentifier}` : \"\",\r\n } satisfies ChatContextContactRes;\r\n });\r\n }\r\n\r\n return null;\r\n }\r\n\r\n @autobind\r\n public async FetchGroupData(): Promise<GroupMetadataInfo | null> {\r\n if (this.FixedSenderType === SenderType.Individual) {\r\n return null;\r\n }\r\n return await this._internalReceive.FetchGroupData(this.FixedChatId);\r\n }\r\n}\r\n\r\nfunction ThrowBadFirstMsgError(): Error {\r\n throw new Error(\r\n \"ChatContext Bad usage: You probably have created a new chatcontext fork without sending any messages nor providing an initial msg trigger!!\\n\" +\r\n \"You need to do one of these two options:\\n\" +\r\n \"1. Provide an explicit first message to this forked chatcontext on ctx.CloneButTargetedTo({initialMsg: <here>}). You can get one using raw api.Send.<anything>()\\n\" +\r\n \"2. If not provided, just send a msg (anything) to chat and automatically chatcontext will be treat it as the first msg\\n\" +\r\n \"Try again..\"\r\n );\r\n}\r\n","import type { MiscMessageGenerationOptions } from \"baileys\";\r\nimport type { IWhatsSocket } from \"../../whats_socket/IWhatsSocket.js\";\r\nimport type { WhatsappMessage } from \"../../whats_socket/types.js\";\r\n\r\ntype MyselfStatusTextParams = Omit<Omit<MiscMessageGenerationOptions, \"statusJidList\">, \"broadcast\">;\r\n\r\n/**\r\n * Submodule responsible for sending status updates (\"stories\")\r\n * through the WhatsApp socket.\r\n *\r\n * This is a lightweight abstraction around the socket API for the\r\n * `status@broadcast` JID, enabling text uploads visible only to\r\n * selected WhatsApp IDs.\r\n *\r\n * Typical usage (from inside a command):\r\n * ```ts\r\n * await api.Myself.Status.UploadText(\"Working on the bot 🚀\", [\r\n * \"123456789@s.whatsapp.net\",\r\n * \"987654321@s.whatsapp.net\",\r\n * ]);\r\n * ```\r\n */\r\nexport default class Myself_Submodule_Status {\r\n /**\r\n * Reserved WhatsApp ID for the \"status\" broadcast channel.\r\n * All status updates must be sent to this JID.\r\n *\r\n * @internal\r\n */\r\n private readonly IDStatusToSend: string = \"status@broadcast\";\r\n\r\n private _whatsSocket: IWhatsSocket;\r\n\r\n /**\r\n * Creates a new `Myself_Submodule_Status` tied to a given socket.\r\n *\r\n * @param chatContextOwner - The active WhatsApp socket instance\r\n * that will handle sending the status update.\r\n */\r\n public constructor(chatContextOwner: IWhatsSocket) {\r\n this._whatsSocket = chatContextOwner;\r\n }\r\n\r\n /**\r\n * Uploads a plain text status update, visible only to the provided\r\n * list of WhatsApp IDs.\r\n *\r\n * This method sends a message to the special `status@broadcast` JID\r\n * with additional metadata indicating which contacts should see it.\r\n *\r\n * @param txtToSendToStatus - The text content of the status.\r\n * @param whatsappIdsToShowStatus - List of WhatsApp user IDs allowed to view the status.\r\n * All ID's must be PN (PhoneNumber) old version. e.g [\"12345@s.whatsapp.net\", \"anotherID@s.whatsapp.net\"]\r\n *\r\n * @returns A `WhatsappMessage` object representing the sent status, or `null`\r\n * if the message failed to send safely.\r\n *\r\n * @example\r\n * ```ts\r\n * const status = new Myself_Submodule_Status(socket);\r\n * await status.UploadText(\"Bot is online ✅\", [\"12345@s.whatsapp.net\"]);\r\n * ```\r\n */\r\n public async UploadText(txtToSendToStatus: string, whatsappIdsToShowStatus: string[], options?: MyselfStatusTextParams): Promise<WhatsappMessage | null> {\r\n let optionsTosend: MiscMessageGenerationOptions;\r\n if (options) {\r\n optionsTosend = { ...options, statusJidList: whatsappIdsToShowStatus, broadcast: true };\r\n } else {\r\n optionsTosend = { statusJidList: whatsappIdsToShowStatus, broadcast: true };\r\n }\r\n\r\n return this._whatsSocket._SendSafe(\r\n this.IDStatusToSend,\r\n {\r\n text: txtToSendToStatus,\r\n },\r\n optionsTosend\r\n );\r\n }\r\n}\r\n","import type { ICommand } from \"./ICommand.js\";\r\n/**\r\n * # Command Type\r\n *\r\n * Different categories of commands supported by the searcher.\r\n * - `Normal`: explicit commands that match directly.\r\n * - `Tag`: commands triggered by a tag (metadata, alias, or secondary marker).\r\n *\r\n * @example\r\n * ```typescript\r\n * const type = CommandType.Normal;\r\n * ```\r\n */\r\nexport enum CommandType {\r\n Normal = \"Normal\",\r\n Tag = \"Tag\",\r\n}\r\n\r\n/**\r\n * # Command Entry\r\n *\r\n * Central registry and search helper type for commands.\r\n *\r\n * Commands are separated into two namespaces:\r\n * - **Normal commands**: Standard commands invoked by name.\r\n * - **Tag commands**: Commands bound to tags or metadata.\r\n *\r\n * A default command or tag may be defined. These act as a global fallback\r\n * when no specific match is found.\r\n *\r\n * @example\r\n * ```typescript\r\n * const entry: CommandEntry = { commandName: \"ping\", commandObj: pingCommand };\r\n * ```\r\n */\r\nexport type CommandEntry = {\r\n commandName: string;\r\n commandObj: ICommand;\r\n};\r\n\r\n/**\r\n * # Commands Searcher System\r\n *\r\n * Central registry and search mechanism for commands.\r\n * Resolves commands by name or alias and manages fallback commands.\r\n *\r\n * @example\r\n * ```typescript\r\n * const searcher = new CommandsSearcher();\r\n * searcher.Add(myCmd);\r\n * ```\r\n */\r\nexport default class CommandsSearcher {\r\n private _normalCommands: Map<string, ICommand> = new Map();\r\n private _tagCommands: Map<string, ICommand> = new Map();\r\n /**\r\n * Optional global fallback command.\r\n * Executed if no specific \"normal\" command is matched.\r\n */\r\n private _defaultCommand?: ICommand;\r\n\r\n /**\r\n * Optional global fallback tag command.\r\n * Executed if no specific \"tag\" command is matched.\r\n */\r\n private _defaultTag?: ICommand;\r\n\r\n /**\r\n * Provides access to the currently configured defaults.\r\n * - `Command`: fallback normal command\r\n * - `Tag`: fallback tag command\r\n */\r\n public get Defaults() {\r\n return {\r\n Command: this._defaultCommand,\r\n Tag: this._defaultTag,\r\n };\r\n }\r\n /**\r\n * Registers the global fallback normal command.\r\n * Used when no explicit normal command is found.\r\n */\r\n public SetDefaultCommand(commandDefault: ICommand): void {\r\n this._defaultCommand = commandDefault;\r\n }\r\n /**\r\n * Registers the global fallback tag command.\r\n * Used when no explicit tag command is found.\r\n */\r\n public SetDefaultTag(commandDefault: ICommand): void {\r\n this._defaultTag = commandDefault;\r\n }\r\n /**\r\n * Returns a list of all registered normal commands.\r\n * Each entry includes the command name and its implementation.\r\n */\r\n public get NormalCommands(): CommandEntry[] {\r\n const toReturn: CommandEntry[] = [];\r\n this._normalCommands.forEach((commandObj, commandName) => toReturn.push({ commandName, commandObj }));\r\n return toReturn;\r\n }\r\n /**\r\n * Returns a list of all registered tag commands.\r\n * Each entry includes the tag name and its implementation.\r\n */\r\n public get TagCommands(): CommandEntry[] {\r\n const toReturn: CommandEntry[] = [];\r\n this._tagCommands.forEach((commandObj, commandName) => toReturn.push({ commandName, commandObj }));\r\n return toReturn;\r\n }\r\n\r\n /**\r\n * Registers a new command, validating it and adding it to the appropriate\r\n * namespace (`Normal` or `Tag`).\r\n *\r\n * The method ensures that command names are valid (non-empty, single-word),\r\n * unique within their type, and that their aliases do not conflict with\r\n * other commands of the same type. All names and aliases are normalized to\r\n * lowercase for case-insensitive matching.\r\n *\r\n * @param commandToAdd The {@link ICommand} instance to register.\r\n * @param addCommandAsType The type of command, either `CommandType.Normal` (default) or `CommandType.Tag`.\r\n *\r\n * @example\r\n * // Add a simple normal command\r\n * searcher.Add({ name: 'help', run: ... });\r\n *\r\n * // Add a tag command with aliases\r\n * searcher.Add({ name: 'admin', aliases: ['mod'], run: ... }, CommandType.Tag);\r\n *\r\n * @example <caption>Error Scenarios</caption>\r\n * // Throws error for duplicate command name\r\n * searcher.Add({ name: 'help', run: ... }); // OK\r\n * searcher.Add({ name: 'help', run: ... }); // Throws Error\r\n *\r\n * // Throws error for alias conflict\r\n * searcher.Add({ name: 'kick', aliases: ['remove'], run: ... }); // OK\r\n * searcher.Add({ name: 'ban', aliases: ['remove'], run: ... }); // Throws Error\r\n *\r\n * // Throws error for invalid name\r\n * searcher.Add({ name: 'bad name', run: ... }); // Throws Error\r\n *\r\n * @throws {Error} If the command name is empty or contains spaces.\r\n * @throws {Error} If a command with the same name already exists for the given type.\r\n * @throws {Error} If an alias conflicts with an existing command's name or aliases of the same type.\r\n */\r\n public Add(commandToAdd: ICommand, addCommandAsType: CommandType = CommandType.Normal): void {\r\n if (!commandToAdd.name || commandToAdd.name.trim() === \"\") {\r\n throw new Error(\"You can't add a command without name!\");\r\n }\r\n if (commandToAdd.name.split(\" \").length > 1) {\r\n throw new Error(\r\n \"You can not add a command with spaces or vary words length!. E.g: !hola mundo, 'hola mundo' is not a valid name, must be one word only like 'holamundo' or 'hola_mundo'\"\r\n );\r\n }\r\n const commandNameLowercase = commandToAdd.name.toLowerCase();\r\n const mapToStoreInto: Map<string, ICommand> = addCommandAsType === CommandType.Normal ? this._normalCommands : this._tagCommands;\r\n\r\n // Check if a command with the same name already exists\r\n if (mapToStoreInto.has(commandNameLowercase)) {\r\n throw new Error(`Bad Args: CommandsSearcher => Command of type \"${CommandType[addCommandAsType]}\" with name '${commandNameLowercase}' already exists!`);\r\n }\r\n\r\n // Normalize metadata\r\n commandToAdd.name = commandNameLowercase;\r\n if (commandToAdd.aliases) {\r\n commandToAdd.aliases = commandToAdd.aliases.map((alias) => alias.toLowerCase());\r\n }\r\n\r\n // Check for alias conflicts\r\n if (commandToAdd.aliases?.length) {\r\n mapToStoreInto.forEach((com) => {\r\n if (!com.aliases?.length) return;\r\n\r\n for (const alias of commandToAdd.aliases!) {\r\n if (com.aliases!.includes(alias)) {\r\n throw new Error(\r\n `Bad Args: CommandsSearcher => Alias '${alias}' for command '${commandNameLowercase}' conflicts with existing command '${com.name}' of type \"${CommandType[addCommandAsType]}\".`\r\n );\r\n }\r\n }\r\n });\r\n }\r\n\r\n // Store the command\r\n mapToStoreInto.set(commandNameLowercase, commandToAdd);\r\n }\r\n\r\n /**\r\n * Checks whether a command exists in either namespace.\r\n *\r\n * @example\r\n * ```ts\r\n * searcher.Exists(\"ping\"); // true\r\n * searcher.Exists(\"unknown\"); // false\r\n * ```\r\n */\r\n public Exists(commandName: string) {\r\n return this.GetTypeOf(commandName) !== null;\r\n }\r\n\r\n /**\r\n * Determines the type of a command.\r\n *\r\n * @example\r\n * ```ts\r\n * searcher.GetTypeOf(\"ping\"); // CommandType.Normal\r\n * searcher.GetTypeOf(\"mod\"); // CommandType.Tag\r\n * searcher.GetTypeOf(\"ghost\"); // null\r\n * ```\r\n */\r\n public GetTypeOf(commandName: string): CommandType | null {\r\n const commandNameLowerCase: string = commandName.toLowerCase();\r\n\r\n if (this._normalCommands.has(commandNameLowerCase)) return CommandType.Normal;\r\n\r\n if (this._tagCommands.has(commandNameLowerCase)) return CommandType.Tag;\r\n\r\n return null;\r\n }\r\n\r\n /**\r\n * Retrieves a normal command.\r\n * Falls back to the default command if not found.\r\n *\r\n * @example\r\n * ```ts\r\n * searcher.GetCommand(\"ping\"); // returns ICommand for \"ping\"\r\n * searcher.GetCommand(\"unknown\"); // returns default command (if set) or null\r\n * ```\r\n */\r\n public GetCommand(commandName: string): ICommand | null {\r\n return this._normalCommands.get(commandName.toLowerCase()) ?? this._defaultCommand ?? null;\r\n }\r\n\r\n /**\r\n * Retrieves a tag command.\r\n * Falls back to the default tag command if not found.\r\n *\r\n * @example\r\n * ```ts\r\n * searcher.GetTag(\"mod\"); // returns ICommand for \"mod\"\r\n * searcher.GetTag(\"ghost\"); // returns default tag (if set) or null\r\n * ```\r\n */\r\n public GetTag(tagName: string): ICommand | null {\r\n return this._tagCommands.get(tagName.toLowerCase()) ?? this._defaultTag ?? null;\r\n }\r\n\r\n /**\r\n * Finds a command by one of its aliases.\r\n *\r\n * @example\r\n * ```ts\r\n * searcher.Add({\r\n * name: \"ban\",\r\n * aliases: [\"block\", \"remove\"],\r\n * execute: () => \"banned\"\r\n * });\r\n *\r\n * searcher.GetWhateverWithAlias(\"block\", CommandType.Normal);\r\n * // returns the \"ban\" command\r\n * ```\r\n */\r\n public GetWhateverWithAlias(possibleAlias: string, commandTypeToLookFor: CommandType): ICommand | null {\r\n const aliasLower = possibleAlias.toLowerCase();\r\n\r\n const findInMap = (map: Map<string, ICommand>) => {\r\n for (const [, commandObj] of map) {\r\n if (commandObj.aliases?.some((alias) => alias.toLowerCase() === aliasLower)) {\r\n return commandObj;\r\n }\r\n }\r\n return null;\r\n };\r\n\r\n return commandTypeToLookFor === CommandType.Normal ? findInMap(this._normalCommands) : findInMap(this._tagCommands);\r\n }\r\n}\r\n","import type { WAMessage } from \"baileys\";\nimport GraphemeSplitter from \"grapheme-splitter\";\nimport { autobind } from \"../../helpers/Decorators.helper.js\";\nimport { MsgHelper_ExtractQuotedMsgInfo, MsgHelper_FullMsg_GetText } from \"../../helpers/Msg.helper.js\";\nimport Delegate from \"../../libs/Delegate.js\";\nimport { MiddlewareChain } from \"../../libs/MiddlewareChain.js\";\nimport { type SenderType, MsgType } from \"../../Msg.types.js\";\nimport type { IWhatsSocket_Submodule_Receiver } from \"../whats_socket/internals/IWhatsSocket.receiver.js\";\nimport type { IWhatsSocket_Submodule_SugarSender } from \"../whats_socket/internals/IWhatsSocket.sugarsender.js\";\nimport { WhatsSocketReceiverHelper_isReceiverError } from \"../whats_socket/internals/WhatsSocket.receiver.js\";\nimport type { IWhatsSocket, IWhatsSocket_EventsOnly_Module } from \"../whats_socket/IWhatsSocket.js\";\nimport WhatsSocket, { type WhatsSocketOptions } from \"../whats_socket/WhatsSocket.js\";\nimport { type IChatContextConfig, ChatContext } from \"./internals/ChatContext.js\";\nimport Myself_Submodule_Status from \"./internals/ChatContext.myself.status.js\";\nimport CommandsSearcher, { CommandType } from \"./internals/CommandsSearcher.js\";\nimport type { CommandArgs, FoundQuotedMsg } from \"./internals/CommandsSearcher.types.js\";\nimport type { IChatContext } from \"./internals/IChatContext.js\";\nimport type { AdditionalAPI, ICommand } from \"./internals/ICommand.js\";\n\n//Little dependency to verify that \"defaulEmojiToSendOnCommandFailure\" is 1 emoji length!\nconst emojiSplitter = new GraphemeSplitter();\n\n/**\n * # Minimal Bot Information\n *\n * Defines the essential, public-facing components of a bot instance.\n *\n * This type is useful for scenarios where a full `Bot` instance is not\n * required, but access to its core configuration and command system is needed.\n * It serves as a minimal interface implemented by the main `Bot` class.\n *\n * @example\n * ```typescript\n * const minBot: BotMinimalInfo = { Settings, Commands };\n * ```\n */\nexport type BotMinimalInfo = {\n /**\n * The bot's current configuration settings.\n *\n * Provides access to all runtime options, such as command prefixes,\n * timeouts, and logging modes.\n */\n Settings: WhatsBotOptions;\n /**\n * The command management system for the bot.\n *\n * Allows for registering, searching, and managing all bot commands.\n */\n Commands: WhatsBotCommands;\n};\n\nexport type WhatsBotOptions = Omit<WhatsSocketOptions, \"ownImplementationSocketAPIWhatsapp\"> &\n Omit<Partial<IChatContextConfig>, \"ignoreSelfMessages\"> & {\n /**\n * Character(s) used to tag the bot in messages.\n *\n * Useful in group contexts where multiple bots or members exist;\n * allows users to explicitly \"mention\" the bot.\n *\n * @default '@'\n * @example\n * tagCharPrefix: ['@', '#'] // bot reacts to both \"@bot\" and \"#bot\"\n */\n tagPrefix?: string | string[];\n\n /**\n * Character(s) used to prefix commands.\n *\n * Common convention is `\"!\"`, but you can use any characters or multiple\n * prefixes to support different command styles.\n *\n * @default '!'\n * @example\n * commandPrefix: ['/'] // commands triggered with \"/help\"\n */\n commandPrefix?: string | string[];\n\n /**\n * # Custom Socket Implementation\n *\n * For advanced users and maintainers: replace the internal WhatsApp socket implementation.\n *\n * If provided, the bot will use this custom implementation instead of the\n * built-in `WhatsSocket`. Useful for testing, extending, or mocking.\n *\n * Warning: Use at your own risk. Incorrect implementations can break bot behavior.\n *\n * @example\n * ```typescript\n * const opts: WhatsBotOptions = { ownWhatsSocketImplementation_Internal: myMock };\n * ```\n */\n ownWhatsSocketImplementation_Internal?: IWhatsSocket;\n\n /**\n * # Custom Chat Context Hook\n *\n * For advanced users and maintainers: replaces the ChatContext that will be sent to all commands.\n *\n * Used primarily for testing.\n *\n * Warning: Use at your own risk. Incorrect implementations can break bot behavior.\n *\n * @example\n * ```typescript\n * const opts: WhatsBotOptions = { ownChatContextCreationHook_Internal: () => myCtx };\n * ```\n */\n ownChatContextCreationHook_Internal?: () => IChatContext | null;\n\n /**\n * Enables or disables the \"safe net\" around command execution.\n *\n * - When `true` (default): command errors are caught internally, logged,\n * and prevented from crashing the bot.\n * - When `false`: errors bubble up to the caller, allowing external handling\n * (useful for integration tests or advanced error pipelines).\n *\n * @default true\n * @remarks This setting is primarily for developers who want fine-grained\n * control over error handling.\n */\n enableCommandSafeNet?: boolean;\n\n /**\n * Default emoji reaction to send when a command fails unexpectedly.\n *\n * If set, the bot will react to the triggering message with this emoji\n * whenever a command throws or exits with an error.\n *\n * @default undefined (no reaction sent on command failure)\n * @example\n * defaultEmojiToSendReactionOnFailureCommand: \"⚠️\"\n */\n defaultEmojiToSendReactionOnFailureCommand?: string | null;\n\n /**\n * Send to chat a json representation of catched error when a\n * commands fails unexpectedly. Useful for debug in real time.\n */\n sendErrorToChatOnFailureCommand_debug?: boolean;\n };\n\n/**\n * # WhatsApp Bot Events\n *\n * Defines all events emitted by the Bot instance.\n *\n * This type aggregates events from the underlying WhatsApp socket\n * (`IWhatsSocket_EventsOnly_Module`) and adds bot-specific events\n * related to command processing and middleware execution.\n *\n * @example\n * ```typescript\n * bot.Events.onIncomingMsg.Subscribe((msg) => console.log(msg));\n * ```\n */\nexport type WhatsBotEvents = IWhatsSocket_EventsOnly_Module & {\n /**\n * Fires after the main middleware chain has finished executing.\n *\n * This event is triggered for every incoming message that passes through\n * the middleware pipeline.\n *\n * @param completedSuccessfully - `true` if the chain ran to completion\n * (all middleware called `next()`), `false` if a middleware broke the chain.\n */\n onMainMiddlewareEnd: Delegate<(completedSuccessfully: boolean) => void | Promise<void>>;\n\n /**\n * Fires after the \"on command found\" middleware chain has finished executing.\n *\n * This event only triggers if a valid command was found in the message.\n *\n * @param completedSuccessfully - `true` if the chain ran to completion,\n * `false` if a middleware broke the chain before command execution.\n */\n onFoundCommandMiddlewareEnd: Delegate<(completedSuccessfully: boolean) => void | Promise<void>>;\n\n /**\n * Fires when a message is identified as a command (e.g., starts with `!`),\n * but no matching command or alias is registered.\n *\n * Useful for providing \"did you mean?\" suggestions or a generic help message.\n *\n * @param ctx - The chat context of the incoming message.\n * @param commandNameThatCouldntBeFound - The name of the command the user tried to run.\n */\n onCommandNotFound: Delegate<(ctx: IChatContext, commandNameThatCouldntBeFound: string) => void | Promise<void>>;\n\n /**\n * Fires when a valid command is found in a message, but **before** it is executed.\n *\n * This serves as a pre-execution hook, ideal for logging, analytics, or\n * dynamic permission checks that shouldn't be part of the command's core logic.\n *\n * @param ctx - The chat context of the incoming message.\n * @param commandToRun - The command object that is about to be executed.\n */\n onCommandFound: Delegate<(ctx: IChatContext, commandToRun: ICommand) => void | Promise<void>>;\n\n /**\n * Fires **after** a command has been executed.\n *\n * This serves as a post-execution hook, useful for logging the outcome,\n * cleaning up resources, or performing follow-up actions.\n *\n * @param ctx - The chat context of the incoming message.\n * @param commandExecuted - The command object that was just run.\n * @param ranSuccessfully - `true` if the command's `run` method completed\n * without throwing an error, `false` otherwise.\n */\n onCommandFoundAfterItsExecution: Delegate<(ctx: IChatContext, commandExecuted: ICommand, ranSuccessfully: boolean) => void>;\n};\n\nexport type WhatsBotSender = IWhatsSocket_Submodule_SugarSender;\nexport type WhatsBotReceiver = IWhatsSocket_Submodule_Receiver;\nexport type WhatsBotCommands = CommandsSearcher;\n\nexport type WhatsbotcordMiddlewareFunct = (\n bot: Bot,\n senderId_LID: string | null,\n senderId_PN: string | null,\n chatId: string,\n rawMsg: WAMessage,\n msgType: MsgType,\n senderType: SenderType,\n next: () => Promise<void>\n) => Promise<void> | void;\n\nexport type WhatsbotcordMiddlewareFunct_OnFoundCommand = (\n bot: Bot,\n senderId_LID: string | null,\n senderId_PN: string | null,\n chatId: string,\n rawMsg: WAMessage,\n msgType: MsgType,\n senderType: SenderType,\n commandFound: ICommand,\n next: () => Promise<void>\n) => Promise<void> | void;\n\nexport type WhatsbotcordPlugin = {\n plugin: (bot: Bot) => void;\n};\n\n/**\n * # WhatsApp Bot\n *\n * Represents the main WhatsApp Bot instance.\n *\n * The `Bot` class orchestrates the WhatsApp socket connection and provides a\n * command-driven interaction system (similar to Discord bots).\n *\n * Typical usage involves registering and handling commands via the internal\n * `Command` prop.\n *\n * @example\n * ```typescript\n * const bot = new Bot();\n * await bot.Start();\n *\n * // Commands are usually registered in the command system\n * bot.Commands.Register(\"ping\", async (ctx) => ctx.Reply(\"pong\"));\n * ```\n */\nexport default class Bot implements BotMinimalInfo {\n public InternalSocket: IWhatsSocket;\n private _commandSearcher: CommandsSearcher;\n private _internalMiddleware: WhatsbotcordMiddlewareFunct[] = [];\n private _internalMiddleware_OnCommandFound: WhatsbotcordMiddlewareFunct_OnFoundCommand[] = [];\n\n /** Bot Specific Events */\n /**\n * Event triggered when the bot receives a message that looks like a command,\n * but no registered command or alias matches it.\n *\n * Example usage:\n * ```ts\n * bot.Events.onCommandNotFound.Subscribe((name) => {\n * console.log(`User tried unknown command: ${name}`);\n * });\n * ```\n */\n private _EVENT_onCommandNotFound: Delegate<(ctx: IChatContext, commandNameThatCouldntBeFound: string) => void> = new Delegate();\n\n private _EVENT_onCommandFound: Delegate<(ctx: IChatContext, commandToRun: ICommand) => void | Promise<void>> = new Delegate();\n\n private _EVENT_onAfterCommandExecution: Delegate<(ctx: IChatContext, commandExecuted: ICommand, ranSuccessfully: boolean) => void | Promise<void>> =\n new Delegate();\n\n /**\n * Event triggered **after the middleware chain finishes running**.\n *\n * - The argument is `true` if the chain executed successfully to the end.\n * - The argument is `false` if some middleware stopped the chain by not calling `next()`.\n *\n * Example usage:\n * ```ts\n * bot.Events.onMiddlewareEnd.Subscribe((success) => {\n * if (success) console.log(\"All middleware finished\");\n * else console.log(\"Middleware chain was interrupted early\");\n * });\n * ```\n */\n private _EVENT_onMainMiddlewareEnd: Delegate<(completedSuccessfully: boolean) => void | Promise<void>> = new Delegate();\n\n private _EVENT_OnFoundCommandMiddlewareEnd: Delegate<(completedSuccessfully: boolean) => void | Promise<void>> = new Delegate();\n /**\n * Current bot configuration settings.\n *\n * These settings are derived from the constructor options, with defaults applied\n * where values were not provided.\n *\n * ⚠️ Changing properties on this object **after the bot has started** can affect its actual functionality.\n *\n * Typical use cases:\n * - Reading the active command or tag prefix\n * - Inspecting runtime limits (timeouts, queue limits, etc.)\n *\n * Example:\n * ```ts\n * console.log(bot.Settings.commandPrefix); // [\"!\"]\n * ```\n */\n public Settings: WhatsBotOptions;\n\n /**\n * Gets the primary command prefix configured for the bot.\n *\n * If multiple prefixes are configured (e.g., `[\"!\", \"/\"]`), this method\n * returns the first one in the array. If no prefix is explicitly configured,\n * it returns the default `\"!\"`.\n *\n * This is an utility Get Function to avoid unnecesary logic in your code\n * due to the nature of `this.Settings.commandPrefix` type \"string | string[] | undefined\"\n * (Triple validation? ugh, use this method instead!)\n *\n * @returns {string} The primary command prefix.\n */\n public get Settings_GetCommandPrefix(): string {\n const defaultPrefix: string = \"!\";\n\n if (typeof this.Settings.commandPrefix === \"undefined\") {\n return defaultPrefix;\n }\n\n if (typeof this.Settings.commandPrefix === \"string\") {\n return this.Settings.commandPrefix;\n }\n\n //Is \"array\" then...\n if (this.Settings.commandPrefix.length > 0) {\n return this.Settings.commandPrefix.at(0)!;\n } else {\n return defaultPrefix;\n }\n }\n\n /**\n * Direct access to the underlying send messaging module.\n *\n * ⚠️ Normally you should not use this directly.\n * Use the bot’s command system to send replies and interact with users.\n *\n * This exists for advanced cases where you need to bypass the command\n * framework (e.g., sending raw messages to specific chats).\n */\n public get SendMsg(): WhatsBotSender {\n return this.InternalSocket.Send;\n }\n\n /**\n * Direct access to the underlying receive messaging module.\n *\n * ⚠️ Normally you should not use this directly.\n * The bot’s command system will handle incoming messages for you.\n *\n * This exists for advanced use cases like:\n * - Listening to non-command events (group joins, reactions, etc.).\n * - Building custom listeners outside of the command framework.\n */\n public get ReceiveMsg(): WhatsBotReceiver {\n return this.InternalSocket.Receive;\n }\n\n /** Exposes all bot-related events that consumers can subscribe to.\n *\n * These events are implemented using `Delegate`, which provides `Subscribe` and\n * `Unsubscribe` methods to attach or detach handlers.\n *\n * Example usage:\n * ```ts\n * bot.Events.onIncomingMsg.Subscribe((msg) => {\n * console.log(\"Raw incoming message:\", msg);\n * });\n *\n * bot.Events.onCommandNotFound.Subscribe((name) => {\n * console.warn(`Unknown command: ${name}`);\n * });\n *\n * bot.Events.onMiddlewareEnd.Subscribe((success) => {\n * console.log(success ? \"Middleware chain finished\" : \"Middleware interrupted\");\n * });\n * ```\n */\n public get Events(): WhatsBotEvents {\n return {\n onGroupEnter: this.InternalSocket.onGroupEnter,\n onGroupUpdate: this.InternalSocket.onGroupUpdate,\n onIncomingMsg: this.InternalSocket.onIncomingMsg,\n onRestart: this.InternalSocket.onRestart,\n onSentMessage: this.InternalSocket.onSentMessage,\n onStartupAllGroupsIn: this.InternalSocket.onStartupAllGroupsIn,\n onUpdateMsg: this.InternalSocket.onUpdateMsg,\n onCommandNotFound: this._EVENT_onCommandNotFound,\n onMainMiddlewareEnd: this._EVENT_onMainMiddlewareEnd,\n onCommandFound: this._EVENT_onCommandFound,\n onCommandFoundAfterItsExecution: this._EVENT_onAfterCommandExecution,\n onFoundCommandMiddlewareEnd: this._EVENT_OnFoundCommandMiddlewareEnd,\n };\n }\n\n public get Commands(): WhatsBotCommands {\n return this._commandSearcher;\n }\n\n /**\n * Creates a new `Bot` instance with customizable behavior.\n *\n * The constructor accepts a `WhatsBotOptions` object that allows overriding\n * runtime settings such as logging, message delays, command handling, and\n * socket implementation.\n *\n * @param options - Optional configuration for customizing bot behavior.\n *\n * Default values:\n * - `credentialsFolder`: `\"./auth\"`\n * Folder path where WhatsApp session credentials are stored and reused.\n *\n * - `delayMilisecondsBetweenMsgs`: `100`\n * Minimum delay (in ms) between consecutive outgoing messages.\n * Helps avoid spam detection and rate-limiting by WhatsApp.\n *\n * - `ignoreSelfMessage`: `true`\n * When enabled, the bot ignores messages sent by its own account.\n *\n * - `loggerMode`: `\"recommended\"`\n * Logging verbosity. `\"recommended\"` provides balanced visibility;\n * other modes may increase or decrease log detail.\n *\n * - `maxReconnectionRetries`: `5`\n * Number of reconnection attempts before giving up when the socket disconnects.\n *\n * - `senderQueueMaxLimit`: `20`\n * Maximum number of pending messages allowed in the send queue.\n * Prevents unbounded memory growth if the bot cannot send fast enough.\n *\n * - `commandPrefix`: `[\"!\"]`\n * One or more prefixes that trigger command execution.\n * Can be a string or string[]; strings are normalized into arrays.\n *\n * - `tagCharPrefix`: `[\"@\"]`\n * Characters used to denote mentions or tagging in commands.\n * Similar normalization rules as `commandPrefix`.\n *\n * - `cancelFeedbackMsg`:\n * `\"canceled ❌ (Default Message: Change me using Bot constructor params options)\"`\n * Feedback message shown when a user cancels an interactive flow.\n *\n * - `cancelKeywords`: `[\"cancel\", \"cancelar\", \"para\", \"stop\"]`\n * Keywords that trigger cancellation of interactive sessions.\n *\n * - `timeoutSeconds`: `30`\n * Default timeout for interactive flows (in seconds).\n *\n * - `wrongTypeFeedbackMsg`:\n * `\"wrong expected msg type ❌ (Default Message: Change me using Bot constructor params options)\"`\n * Feedback shown when the received message type doesn’t match expectations.\n *\n * - `ownWhatsSocketImplementation`: `undefined`\n * Allows injecting a custom `WhatsSocket` implementation. If omitted,\n * the built-in socket (`new WhatsSocket(Settings)`) is used.\n *\n * - `enableCommandSafeNet`: `true`\n * Enables a safeguard layer around command execution, preventing\n * crashes or unintended side effects from propagating.\n *\n * @remarks\n * - All defaults are applied when their corresponding `options` field\n * is `undefined` or invalid.\n * - `commandPrefix` and `tagCharPrefix` always normalize to arrays.\n * - For production bots, consider raising `delayMilisecondsBetweenMsgs`\n * slightly to avoid WhatsApp anti-spam systems.\n */\n constructor(options?: WhatsBotOptions) {\n this.Settings = BotUtils_GenerateOptions(options);\n\n //# Validations:\n // 1.Validate is only one emoji length on defaultEmojiToSend...\n if (this.Settings.defaultEmojiToSendReactionOnFailureCommand) {\n const emojisCount: number = emojiSplitter.countGraphemes(this.Settings.defaultEmojiToSendReactionOnFailureCommand);\n if (emojisCount !== 1) {\n throw new Error(\n \"WhatsbotCord BOT received in 'defaultEmojiToSendReactionOnFailureCommand' a non valid SINGLE emoji. Received instead: \" +\n this.Settings.defaultEmojiToSendReactionOnFailureCommand\n );\n }\n }\n\n this._commandSearcher = new CommandsSearcher();\n this.InternalSocket = this.Settings.ownWhatsSocketImplementation_Internal ?? new WhatsSocket(this.Settings);\n this.InternalSocket.onIncomingMsg.Subscribe(this.EVENT_OnMessageIncoming);\n }\n\n /**\n * Starts the bot by initializing the WhatsApp socket connection.\n *\n * This method must be called before the bot can process commands.\n *\n * Example:\n * ```ts\n * const bot = new Bot();\n * await bot.Start();\n * ```\n */\n @autobind\n public async Start(): Promise<void> {\n return this.InternalSocket.Start();\n }\n\n /**\n * Registers a middleware function or a plugin to intercept incoming messages.\n *\n * This method serves as the main entry point for extending bot functionality.\n * Middleware is executed in registration order **before** any command processing.\n *\n * ### Use as Middleware\n * Pass a function to inspect, modify, or block messages globally. Each\n * middleware receives a `next()` function. Call `next()` to pass control\n * to the next middleware. If `next()` is not called, the processing chain\n * stops, preventing subsequent middleware and commands from running.\n *\n * ### Use as a Plugin\n * Pass an object with a `plugin` method. Plugins are ideal for encapsulating\n * complex or reusable logic, such as registering multiple commands and listeners at once.\n *\n * @param usePluginOrMiddleware - The middleware function or plugin object to register.\n *\n * @example\n * // ----- Using `WhatsbotcordMiddlewareFunct` param -----\n *\n * // Middleware for logging all incoming messages\n * bot.Use(async (bot, senderId_LID, senderId_PN, chatId, rawMsg, msgType, senderType, next) => {\n * console.log(`New message in chat ${chatId}`);\n * await next(); // Continue to the next middleware\n * });\n *\n * @example\n * // Middleware to block a specific user\n * bot.Use((bot, senderId_LID, senderId_PN, chatId, rawMsg, msgType, senderType, next) => {\n * if (senderId_PN === \"user-to-block@s.whatsapp.net\") {\n * return; // Stop the chain by not calling next()\n * }\n * next();\n * });\n *\n * // ---- Using `WhatsbotcordPlugin` param -----\n * @example\n * // Plugin that registers multiple commands\n * const myPlugin: WhatsbotcordPlugin = {\n * plugin: (bot) => {\n * bot.Commands.Register(\"ping\", async (ctx) => ctx.Reply(\"pong\"));\n * bot.Commands.Register(\"help\", async (ctx) => ctx.Reply(\"Here is some help!\"));\n * }\n * };\n * bot.Use(myPlugin);\n */\n @autobind\n public Use(usePluginOrMiddleware: WhatsbotcordMiddlewareFunct | WhatsbotcordPlugin): void {\n if (typeof usePluginOrMiddleware === \"function\") {\n this._internalMiddleware.push(usePluginOrMiddleware);\n }\n if (typeof usePluginOrMiddleware === \"object\") {\n usePluginOrMiddleware.plugin(this);\n }\n }\n\n /**\n * Registers middleware that runs only when a valid command is found.\n *\n * This hook executes **after** a command has been identified but **before** the\n * command's `run` method is called. It's the ideal place for command-specific\n * logic like permission checks, cooldowns, or logging.\n *\n * Like general middleware, you must call `next()` to proceed. If `next()` is\n * not called, the command will not be executed.\n *\n * @param useMiddleware - The middleware function to execute. It receives all\n * standard message parameters, plus the `commandFound` object.\n * @see Use for general-purpose middleware that runs on all messages.\n *\n * @example\n * // Middleware to allow a command only for admins\n * bot.Use_OnCommandFound(async (bot, senderId_LID, senderId_PN, chatId, rawMsg, msgType, senderType, commandFound, next) => {\n * const admins = [\"admin1@s.whatsapp.net\", \"admin2@s.whatsapp.net\"];\n * if (commandFound.name === \"ban\" && (!senderId_PN || !admins.includes(senderId_PN))) {\n * // User is not an admin, block the command\n * await bot.SendMsg.Text(chatId, \"You don't have permission to use that command.\");\n * return;\n * }\n * // User has permission, proceed to execute the command\n * await next();\n * });\n */\n @autobind\n public Use_OnCommandFound(useMiddleware: WhatsbotcordMiddlewareFunct_OnFoundCommand): void {\n this._internalMiddleware_OnCommandFound.push(useMiddleware);\n }\n\n @autobind\n private async EVENT_OnMessageIncoming(\n senderId_LID: string | null,\n senderId_PN: string | null,\n chatId: string,\n rawMsg: WAMessage,\n msgType: MsgType,\n senderType: SenderType\n ): Promise<void> {\n // ======== Middleware chain section ========\n const mainMiddleware = new MiddlewareChain(this._internalMiddleware);\n const middlewareChainSuccess = await mainMiddleware.run(this, senderId_LID, senderId_PN, chatId, rawMsg, msgType, senderType);\n this.Events.onMainMiddlewareEnd.CallAll(middlewareChainSuccess);\n if (!middlewareChainSuccess) return;\n\n // ==== Main Logic =====\n if (msgType === MsgType.Text) {\n const txtFromMsg: string | null = MsgHelper_FullMsg_GetText(rawMsg);\n if (!txtFromMsg || txtFromMsg.length === 0) return;\n const txtFromMsgHealthy: string = txtFromMsg.trim();\n\n const rawArgs: string[] = txtFromMsg.slice(1).split(\" \");\n //If user only sent \"!\" instead of !command (if '!' is prefix for example)\n if (rawArgs.length === 0) {\n return;\n }\n const commandOrAliasNameLowerCased: string = rawArgs.at(0)!.toLowerCase();\n let commandArgs: string[] = rawArgs.length > 1 ? rawArgs.slice(1) : [];\n\n // === Check if command, then what type ===\n const prefix: string = txtFromMsgHealthy[0]!;\n let commandFound: ICommand | null = null;\n let commandTypeFound: CommandType | null = null;\n // 1. Check if its normal command\n if (typeof this.Settings.commandPrefix === \"string\" ? this.Settings.commandPrefix === prefix : this.Settings.commandPrefix?.includes(prefix)) {\n commandTypeFound = CommandType.Normal;\n commandFound = this.Commands.GetCommand(commandOrAliasNameLowerCased);\n if (this.Commands.Defaults.Command) {\n if (this.Commands.Defaults.Command === commandFound) {\n commandArgs = rawArgs.filter((word) => word !== \"\");\n }\n }\n // 2. Check if is tag command\n } else if (typeof this.Settings.tagPrefix === \"string\" ? this.Settings.tagPrefix === prefix : this.Settings.tagPrefix?.includes(prefix)) {\n commandTypeFound = CommandType.Tag;\n commandFound = this.Commands.GetTag(commandOrAliasNameLowerCased);\n if (this.Commands.Defaults.Tag) {\n if (this.Commands.Defaults.Tag === commandFound) {\n commandArgs = rawArgs.filter((word) => word !== \"\");\n }\n }\n }\n // 3. Found type of command but not with normal name? Try searching if its an alias\n if (!commandFound && commandTypeFound) {\n commandFound = this.Commands.GetWhateverWithAlias(commandOrAliasNameLowerCased, commandTypeFound);\n }\n\n //=========================================================\n let ARG1_ChatContext: IChatContext;\n const customChatContext: IChatContext | null = this.Settings.ownChatContextCreationHook_Internal!();\n if (customChatContext) {\n ARG1_ChatContext = customChatContext;\n } else {\n ARG1_ChatContext = new ChatContext(senderId_LID, senderId_PN, chatId, rawMsg, this.InternalSocket.Send, this.InternalSocket.Receive, {\n cancelKeywords: this.Settings.cancelKeywords!,\n timeoutSeconds: this.Settings.timeoutSeconds!,\n ignoreSelfMessages: this.Settings.ignoreSelfMessage!,\n wrongTypeFeedbackMsg: this.Settings.wrongTypeFeedbackMsg,\n cancelFeedbackMsg: this.Settings.cancelFeedbackMsg,\n });\n }\n //=========================================================\n\n // 4. Can't be found after all that? its not a valid command\n if (!commandFound) {\n await this.Events.onCommandNotFound.CallAllAsync(\n new ChatContext(senderId_LID, senderId_PN, chatId, rawMsg, this.InternalSocket.Send, this.InternalSocket.Receive, {\n cancelKeywords: this.Settings.cancelKeywords!,\n timeoutSeconds: this.Settings.timeoutSeconds!,\n ignoreSelfMessages: this.Settings.ignoreSelfMessage!,\n wrongTypeFeedbackMsg: this.Settings.wrongTypeFeedbackMsg,\n cancelFeedbackMsg: this.Settings.cancelFeedbackMsg,\n }),\n txtFromMsg\n );\n return;\n } else {\n if (this.Events.onCommandFound.Length > 0) {\n await this.Events.onCommandFound.CallAllAsync(\n new ChatContext(senderId_LID, senderId_PN, chatId, rawMsg, this.InternalSocket.Send, this.InternalSocket.Receive, {\n cancelKeywords: this.Settings.cancelKeywords!,\n timeoutSeconds: this.Settings.timeoutSeconds!,\n ignoreSelfMessages: this.Settings.ignoreSelfMessage!,\n wrongTypeFeedbackMsg: this.Settings.wrongTypeFeedbackMsg,\n cancelFeedbackMsg: this.Settings.cancelFeedbackMsg,\n }),\n commandFound\n );\n }\n\n //2nd Middleware\n const middlewareOnFound = new MiddlewareChain(this._internalMiddleware_OnCommandFound);\n const shouldContinueAgain = await middlewareOnFound.run(this, senderId_LID, senderId_PN, chatId, rawMsg, msgType, senderType, commandFound);\n await this.Events.onFoundCommandMiddlewareEnd.CallAllAsync(shouldContinueAgain);\n if (!shouldContinueAgain) {\n await this._EVENT_onAfterCommandExecution.CallAllAsync(ARG1_ChatContext, commandFound, false);\n return;\n }\n }\n\n const quotedMsgAsArgument: FoundQuotedMsg | null = MsgHelper_ExtractQuotedMsgInfo(rawMsg);\n\n //=========================================================\n const ARG2_AdditionalAPI: AdditionalAPI = {\n // @deprecated ones: InternalSockets already have them inside!\n // Receive: this._socket.Receive,\n // Send: this._socket.Send,\n InternalSocket: this.InternalSocket,\n Myself: {\n Status: new Myself_Submodule_Status(this.InternalSocket),\n Bot: this,\n },\n };\n const ARG3_AdditionalArgs: CommandArgs = {\n args: commandArgs,\n chatId: chatId,\n chatId_LID: rawMsg.key.remoteJidAlt,\n msgType: msgType,\n originalRawMsg: rawMsg,\n senderType: senderType,\n participantIdLID: senderId_LID,\n participantIdPN: senderId_PN,\n quotedMsgInfo: quotedMsgAsArgument,\n botInfo: this,\n };\n try {\n await commandFound.run(\n /** Chat Context */\n ARG1_ChatContext,\n /** RawAPI */\n ARG2_AdditionalAPI,\n /** Command basic arguments */\n ARG3_AdditionalArgs\n );\n } catch (e) {\n if (this.Settings.defaultEmojiToSendReactionOnFailureCommand) {\n await ARG1_ChatContext.SendReactEmojiToInitialMsg(this.Settings.defaultEmojiToSendReactionOnFailureCommand);\n }\n if (this.Settings.sendErrorToChatOnFailureCommand_debug) {\n await ARG1_ChatContext.SendText(JSON.stringify(e, null, 2), { normalizeMessageText: false });\n }\n if (WhatsSocketReceiverHelper_isReceiverError(e)) {\n if (e.wasAbortedByUser && this.Settings.loggerMode !== \"silent\") {\n console.log(`[Command Canceled]: Name ${commandOrAliasNameLowerCased}`);\n }\n } else {\n if (this.Settings.loggerMode !== \"silent\")\n console.log(\n `[COMMAND EXECUTION ERROR]: Error when trying to execute '${commandOrAliasNameLowerCased}'\\n\\n`,\n `Error Info: ${JSON.stringify(e, null, 2)}`\n );\n }\n\n if (!this.Settings.enableCommandSafeNet) {\n throw e;\n }\n }\n await this._EVENT_onAfterCommandExecution.CallAllAsync(ARG1_ChatContext, commandFound, false);\n }\n } //EVENT_...() Method\n}\n\nexport function BotUtils_GenerateOptions(options?: Partial<WhatsBotOptions>): WhatsBotOptions {\n return {\n credentialsFolder: options?.credentialsFolder ?? \"./auth\",\n delayMilisecondsBetweenMsgs: options?.delayMilisecondsBetweenMsgs ?? 100,\n ignoreSelfMessage: options?.ignoreSelfMessage ?? true,\n loggerMode: options?.loggerMode ?? \"recommended\",\n maxReconnectionRetries: options?.maxReconnectionRetries ?? 5,\n senderQueueMaxLimit: options?.senderQueueMaxLimit ?? 20,\n commandPrefix: typeof options?.commandPrefix === \"string\" ? [options.commandPrefix] : (options?.commandPrefix ?? [\"!\"]),\n tagPrefix: typeof options?.tagPrefix === \"string\" ? [options.tagPrefix] : (options?.tagPrefix ?? [\"@\"]),\n cancelFeedbackMsg: options?.cancelFeedbackMsg ?? \"canceled ❌ (Default Message: Change me using Bot constructor params options)\",\n cancelKeywords: options?.cancelKeywords ?? [\"cancel\", \"cancelar\", \"para\", \"stop\"],\n timeoutSeconds: options?.timeoutSeconds ?? 30,\n wrongTypeFeedbackMsg: options?.wrongTypeFeedbackMsg ?? \"wrong expected msg type ❌ (Default Message: Change me using Bot constructor params options)\",\n ownWhatsSocketImplementation_Internal: options?.ownWhatsSocketImplementation_Internal,\n enableCommandSafeNet: options?.enableCommandSafeNet ?? true,\n defaultEmojiToSendReactionOnFailureCommand: options?.defaultEmojiToSendReactionOnFailureCommand ?? null,\n sendErrorToChatOnFailureCommand_debug: options?.sendErrorToChatOnFailureCommand_debug ?? false,\n ownChatContextCreationHook_Internal: options?.ownChatContextCreationHook_Internal ?? (() => null),\n };\n}\n","import type Bot from \"../bot/bot.js\";\r\nimport type { WhatsbotcordPlugin } from \"../bot/bot.js\";\r\nimport type { ICommand } from \"../bot/internals/ICommand.js\";\r\n\r\n/**\r\n * Keeps track of a user executing a command.\r\n * One record per (chatId + participantId).\r\n *\r\n * `timer` is used to auto-expire the entry after a configured timeout.\r\n */\r\ntype ActiveUserLog = {\r\n chatId: string;\r\n command: ICommand;\r\n participantId_LID: string | null;\r\n timer: NodeJS.Timeout;\r\n};\r\n\r\nexport type OfficialPlugin_OneCommandPerUserAtATime_ContextInfo = { pushName?: string | null };\r\n/**\r\n * Configuration options for the \"OneCommandPerUserAtATime\" plugin.\r\n */\r\nexport type OfficialPlugin_OneCommandPerUserAtATime_Config = {\r\n /**\r\n * Number of seconds to keep a user locked before their command lock expires.\r\n * This prevents users from getting stuck if a command fails without cleanup.\r\n * @default 180 (3 minutes)\r\n */\r\n timeoutSecondsToForgetThem?: number;\r\n\r\n /**\r\n * Called when a user tries to execute a new command while one is still active.\r\n *\r\n * @param ctxInfo - Contextual info such as pushName of the sender.\r\n * @param executingCommand - The command that is already running.\r\n * @param newCommand - The new command being attempted.\r\n * @returns A string to send back to the user (e.g., \"Please wait until your current command finishes.\").\r\n */\r\n msgToSend: (ctxInfo: OfficialPlugin_OneCommandPerUserAtATime_ContextInfo, executingCommand: ICommand, newCommand: ICommand) => string;\r\n};\r\n\r\n/**\r\n * Plugin: Ensures that only **one command per user** can be active at a time.\r\n *\r\n * - If a user tries to run a command while another is still active, they get a configurable message and the new command is blocked.\r\n * - Active commands are automatically forgotten after a timeout to prevent permanent locks.\r\n * - The lock is cleared instantly when a command finishes execution.\r\n *\r\n * @param config - Timeout settings and message generator.\r\n * @returns A WhatsbotcordPlugin object to register with the bot.\r\n */\r\nexport default function OfficialPlugin_OneCommandPerUserAtATime(config: OfficialPlugin_OneCommandPerUserAtATime_Config): WhatsbotcordPlugin {\r\n const activeUsers: ActiveUserLog[] = [];\r\n const timeoutSeconds = config.timeoutSecondsToForgetThem ?? 180;\r\n\r\n return {\r\n plugin: (bot: Bot) => {\r\n // The middleware now handles the check BEFORE a command runs.\r\n bot.Use_OnCommandFound(async (bot, senderId_LID, _senderId_PN, chatId, rawMsg, _msgType, _senderType, commandFound, next) => {\r\n const existingLog = activeUsers.find((u) => u.chatId === chatId && u.participantId_LID === senderId_LID);\r\n\r\n // If a log exists, the user is busy. Block the new command.\r\n if (existingLog) {\r\n const message = config.msgToSend({ pushName: rawMsg.pushName }, existingLog.command, commandFound);\r\n await bot.SendMsg.Text(chatId, message, { quoted: rawMsg });\r\n return; // By not calling next(), we stop execution.\r\n }\r\n\r\n // User is not busy. Add a log and allow the command to run.\r\n const newLog: ActiveUserLog = {\r\n chatId,\r\n participantId_LID: senderId_LID,\r\n command: commandFound,\r\n timer: setTimeout(() => {\r\n // Failsafe: auto-remove the log after a timeout.\r\n const index = activeUsers.findIndex((u) => u === newLog);\r\n if (index !== -1) {\r\n activeUsers.splice(index, 1);\r\n }\r\n }, timeoutSeconds * 1000),\r\n };\r\n\r\n activeUsers.push(newLog);\r\n await next(); // Proceed to execute the command.\r\n });\r\n\r\n // The event is still the best place to handle cleanup AFTER a command runs.\r\n bot.Events.onCommandFoundAfterItsExecution.Subscribe((ctx, _executedCommand) => {\r\n const index = activeUsers.findIndex((u) => u.chatId === ctx.FixedChatId && u.participantId_LID === ctx.FixedParticipantLID);\r\n\r\n if (index !== -1) {\r\n const log = activeUsers[index]!;\r\n clearTimeout(log.timer); // Clear the failsafe timer.\r\n activeUsers.splice(index, 1); // Remove the user from the active list.\r\n }\r\n });\r\n },\r\n };\r\n}\r\n","import fs from \"node:fs\";\r\nimport type { WhatsappMessage } from \"./core/whats_socket/types.js\";\r\nimport { GetPath } from \"./libs/BunPath.js\";\r\n\r\n/**\r\n * # Store Message in History JSON\r\n *\r\n * Stores the incoming WhatsApp message into a local JSON file for debugging purposes.\r\n * If the file does not exist, it creates it.\r\n *\r\n * @param filePath - The path to the JSON file where history will be stored.\r\n * @param rawMsg - The raw WhatsApp message object to store.\r\n *\r\n * @example\r\n * ```typescript\r\n * Debug_StoreWhatsMsgHistoryInJson(\"./debug_history.json\", rawMsg);\r\n * ```\r\n */\r\nexport function Debug_StoreWhatsMsgHistoryInJson(filePath: string, rawMsg: WhatsappMessage) {\r\n let msgsStored: any[] = [];\r\n if (fs.existsSync(GetPath(filePath))) {\r\n const before = fs.readFileSync(GetPath(filePath), \"utf-8\");\r\n if (before.trim() === \"\") {\r\n msgsStored = [];\r\n } else {\r\n msgsStored = JSON.parse(before);\r\n }\r\n } else {\r\n //Creates the file if it doesn't exist\r\n fs.writeFileSync(GetPath(filePath), \"\", \"utf-8\");\r\n msgsStored = [];\r\n }\r\n msgsStored.push(rawMsg);\r\n const json = JSON.stringify(msgsStored, null, 2);\r\n fs.writeFileSync(GetPath(filePath), json, \"utf-8\");\r\n}\r\n","import type { CommandArgs } from \"../core/bot/internals/CommandsSearcher.types.js\";\r\nimport type { IChatContext } from \"../core/bot/internals/IChatContext.js\";\r\nimport type { AdditionalAPI, ICommand } from \"../core/bot/internals/ICommand.js\";\r\n\r\n/**\r\n * # Command Parameters\r\n *\r\n * Optional parameters to define additional properties for a newly created command, such as aliases.\r\n *\r\n * @example\r\n * ```typescript\r\n * const params: CommandParams = { aliases: [\"ping\", \"p\"] };\r\n * ```\r\n */\r\nexport type CommandParams = {\r\n aliases?: string[];\r\n};\r\n\r\n/**\r\n * # Create Command Helper\r\n *\r\n * A simple function to create commands primarily for JS developers.\r\n * Gives you intellisense when creating your commands without needing\r\n * manual typings inline.\r\n *\r\n * @param commandName - The main trigger string for the command.\r\n * @param run - The execution function where the logic is defined.\r\n * @param params - Optional parameters like aliases.\r\n * @returns A structured `ICommand` ready to be registered in the bot.\r\n *\r\n * @example\r\n * ```typescript\r\n * const pingCommand = CreateCommand(\"ping\", async (ctx) => {\r\n * await ctx.Reply(\"pong\");\r\n * });\r\n * ```\r\n */\r\nexport default function CreateCommand(\r\n commandName: string,\r\n run: (ctx: IChatContext, api: AdditionalAPI, args: CommandArgs) => Promise<void>,\r\n params?: CommandParams\r\n): ICommand {\r\n return {\r\n name: commandName,\r\n run: run,\r\n aliases: params?.aliases,\r\n };\r\n}\r\n","import {\r\n type AnyMessageContent,\r\n type GroupMetadata,\r\n type GroupParticipant,\r\n type MiscMessageGenerationOptions,\r\n type WAMessage,\r\n WAMessageAddressingMode,\r\n} from \"baileys\";\r\nimport { autobind } from \"../../../helpers/Decorators.helper.js\";\r\nimport { MsgHelper_FullMsg_GetMsgType, MsgHelper_FullMsg_GetSenderType } from \"../../../helpers/Msg.helper.js\";\r\nimport Delegate from \"../../../libs/Delegate.js\";\r\nimport type { MsgType, SenderType } from \"../../../Msg.types.js\";\r\nimport { WhatsappGroupIdentifier, WhatsappLIDIdentifier, WhatsappPhoneNumberIdentifier } from \"../../../Whatsapp.types.js\";\r\nimport type { IWhatsSocket_Submodule_Receiver } from \"../internals/IWhatsSocket.receiver.js\";\r\nimport type { IWhatsSocket_Submodule_SugarSender } from \"../internals/IWhatsSocket.sugarsender.js\";\r\nimport type { GroupMetadataInfo, ParticipantInfo } from \"../internals/WhatsSocket.receiver.js\";\r\nimport { WhatsSocket_Submodule_Receiver } from \"../internals/WhatsSocket.receiver.js\";\r\nimport { WhatsSocket_Submodule_SugarSender } from \"../internals/WhatsSocket.sugarsenders.js\";\r\nimport type { IWhatsSocket } from \"../IWhatsSocket.js\";\r\nimport type { WhatsappMessage } from \"../types.js\";\r\nimport type { WhatsSocketMockMsgSent } from \"./types.js\";\r\n\r\nexport type WhatsSocketMockOptions = {\r\n maxQueueLimit?: number;\r\n minimumMilisecondsDelayBetweenMsgs?: number;\r\n customReceiver?: IWhatsSocket_Submodule_Receiver;\r\n customSugarSender?: IWhatsSocket_Submodule_SugarSender;\r\n};\r\n\r\nexport type WhatsSocketMockSendingMsgOptions = {\r\n replaceTextWith?: string;\r\n replaceParticipantIdWith?: string;\r\n replaceChatIdWith?: string;\r\n customMsgType?: MsgType;\r\n changeSenderType?: SenderType;\r\n};\r\n\r\nexport default class WhatsSocketMock implements IWhatsSocket {\r\n // ==== Interface dependencies ====\r\n onRestart: Delegate<() => Promise<void>> = new Delegate();\r\n onSentMessage: Delegate<(chatId: string, rawContentMsg: AnyMessageContent, optionalMisc?: MiscMessageGenerationOptions) => void> = new Delegate();\r\n onIncomingMsg: Delegate<\r\n (participantId_LID: string | null, participantId_PN: string | null, chatId: string, rawMsg: WAMessage, type: MsgType, senderType: SenderType) => void\r\n > = new Delegate();\r\n onUpdateMsg: Delegate<\r\n (\r\n participantId_LID: string | null,\r\n participantId_PN: string | null,\r\n chatId: string,\r\n rawMsgUpdate: WAMessage,\r\n msgType: MsgType,\r\n senderType: SenderType\r\n ) => void\r\n > = new Delegate();\r\n onGroupEnter: Delegate<(groupInfo: GroupMetadata) => void> = new Delegate();\r\n onGroupUpdate: Delegate<(groupInfo: Partial<GroupMetadata>) => void> = new Delegate();\r\n onStartupAllGroupsIn: Delegate<(allGroupsIn: GroupMetadata[]) => void> = new Delegate();\r\n ownJID: string = \"ownIDMock\" + WhatsappPhoneNumberIdentifier;\r\n\r\n Send: IWhatsSocket_Submodule_SugarSender;\r\n Receive: IWhatsSocket_Submodule_Receiver;\r\n\r\n // private _senderQueue: WhatsSocketSenderQueue_SubModule;\r\n\r\n constructor(options?: WhatsSocketMockOptions) {\r\n // this._senderQueue = new WhatsSocketSenderQueue_SubModule(this, options?.maxQueueLimit ?? 10, options?.minimumMilisecondsDelayBetweenMsgs ?? 500);\r\n\r\n this.Send = options?.customSugarSender ?? new WhatsSocket_Submodule_SugarSender(this);\r\n this.Receive = options?.customReceiver ?? new WhatsSocket_Submodule_Receiver(this);\r\n\r\n //Thanks js, this is never needed on another languages... ☠️\r\n this._SendRaw = this._SendRaw.bind(this);\r\n this._SendSafe = this._SendSafe.bind(this);\r\n this.Start = this.Start.bind(this);\r\n this.Shutdown = this.Shutdown.bind(this);\r\n this.GetRawGroupMetadata = this.GetRawGroupMetadata.bind(this);\r\n this.ClearMock = this.ClearMock.bind(this);\r\n }\r\n\r\n public SentMessagesThroughQueue: WhatsSocketMockMsgSent[] = [];\r\n public SentMessagesThroughRaw: WhatsSocketMockMsgSent[] = [];\r\n\r\n public GroupsIDTriedToFetch: string[] = [];\r\n\r\n public IsOn: boolean = false;\r\n\r\n public async Start(): Promise<void> {\r\n this.IsOn = true;\r\n }\r\n public async Shutdown(): Promise<void> {\r\n this.IsOn = false;\r\n }\r\n public async _SendSafe(chatId_JID: string, content: AnyMessageContent, options?: MiscMessageGenerationOptions): Promise<WAMessage | null> {\r\n let chatIdToUse: string;\r\n if (!chatId_JID.endsWith(WhatsappGroupIdentifier)) {\r\n chatIdToUse = chatId_JID + WhatsappGroupIdentifier;\r\n } else {\r\n chatIdToUse = chatId_JID;\r\n }\r\n\r\n this.SentMessagesThroughQueue.push({\r\n chatId: chatIdToUse,\r\n content: content,\r\n miscOptions: options,\r\n });\r\n return {\r\n message: {\r\n conversation: \"Mock Minimum Object WAMessage from SendSafe\",\r\n },\r\n key: {\r\n fromMe: false,\r\n id: \"23423423234\" + WhatsappLIDIdentifier,\r\n remoteJid: \"falseid\" + WhatsappGroupIdentifier,\r\n },\r\n };\r\n }\r\n\r\n public async _SendRaw(chatId_JID: string, content: AnyMessageContent, options?: MiscMessageGenerationOptions): Promise<WAMessage | null> {\r\n let chatIdToUse: string;\r\n if (!chatId_JID.endsWith(WhatsappGroupIdentifier)) {\r\n chatIdToUse = chatId_JID + WhatsappGroupIdentifier;\r\n } else {\r\n chatIdToUse = chatId_JID;\r\n }\r\n this.SentMessagesThroughRaw.push({\r\n chatId: chatIdToUse,\r\n content,\r\n miscOptions: options,\r\n });\r\n return {\r\n message: {\r\n conversation: \"Mock Minimum Object WAMessage from SendRaw\",\r\n },\r\n key: {\r\n fromMe: false,\r\n id: \"23423423234\" + WhatsappLIDIdentifier,\r\n remoteJid: \"falseid\" + WhatsappGroupIdentifier,\r\n },\r\n };\r\n }\r\n\r\n private _groupMetadataMock?: GroupMetadata;\r\n\r\n @autobind\r\n public SetGroupMetadataMock(groupData: Partial<GroupMetadataInfo>) {\r\n let chatIdToUse: string | undefined;\r\n if (groupData.id) {\r\n if (!groupData.id.endsWith(WhatsappGroupIdentifier)) {\r\n chatIdToUse = groupData.id + WhatsappGroupIdentifier;\r\n } else {\r\n chatIdToUse = groupData.id;\r\n }\r\n }\r\n this._groupMetadataMock = {\r\n id: chatIdToUse ?? \"fakeIdGroup\" + WhatsappGroupIdentifier,\r\n addressingMode: groupData?.sendingMode === \"pn\" ? WAMessageAddressingMode.PN : WAMessageAddressingMode.LID,\r\n owner: groupData?.ownerName ?? undefined,\r\n subject: groupData?.groupName ?? \"GroupName\",\r\n desc: groupData?.groupDescription ?? undefined,\r\n linkedParent: groupData?.communityIdWhereItBelongs ?? undefined,\r\n restrict: groupData?.onlyAdminsCanChangeGroupSettings ?? undefined,\r\n announce: groupData?.onlyAdminsCanSendMsgs ?? undefined,\r\n memberAddMode: groupData?.membersCanAddOtherMembers ?? undefined,\r\n joinApprovalMode: groupData?.needsRequestApprovalToJoinIn ?? undefined,\r\n isCommunity: false, // not exposed in high-level\r\n isCommunityAnnounce: groupData?.isCommunityAnnounceChannel ?? undefined,\r\n size: groupData?.membersCount ?? undefined,\r\n ephemeralDuration: groupData?.ephemeralDuration ?? undefined,\r\n inviteCode: groupData?.inviteCode ?? undefined,\r\n subjectTime: groupData?.lastNameChangeDateTime ?? undefined,\r\n author: groupData?.author ?? undefined,\r\n creation: groupData?.creationDate ?? undefined,\r\n participants: groupData?.members ? groupData?.members.map(mapParticipant) : [],\r\n };\r\n }\r\n\r\n /**\r\n * Gets the metadata of a group chat by its chat ID. (e.g: \"23423423123@g.us\")\r\n * @param chatId The chat ID of the group you want to get metadata from.\r\n * @returns A promise that resolves to the group metadata.\r\n */\r\n @autobind\r\n public async GetRawGroupMetadata(chatId: string): Promise<GroupMetadata> {\r\n this.GroupsIDTriedToFetch.push(chatId);\r\n if (this._groupMetadataMock) {\r\n return this._groupMetadataMock;\r\n } else {\r\n return {\r\n id: chatId,\r\n subject: \"Mock Group\",\r\n creation: Date.now(),\r\n creator: \"Some User\",\r\n } as any;\r\n }\r\n }\r\n\r\n public ClearMock(): void {\r\n this.IsOn = false;\r\n this.GroupsIDTriedToFetch = [];\r\n this.SentMessagesThroughQueue = [];\r\n\r\n this.onRestart.Clear();\r\n this.onIncomingMsg.Clear();\r\n this.onGroupEnter.Clear();\r\n this.onGroupUpdate.Clear();\r\n this.onStartupAllGroupsIn.Clear();\r\n this.onUpdateMsg.Clear();\r\n this.SentMessagesThroughRaw = [];\r\n this.SentMessagesThroughQueue = [];\r\n }\r\n\r\n /**\r\n * Simulates the reception of a message from whatsapp asynchronously!\r\n * @param rawMsg The message to be sent.\r\n * @param options Optional options to modify the message before sending it.\r\n * Currently only supports replacing the text of the message.\r\n * @returns Resolves to void.\r\n */\r\n public async MockSendMsgAsync(rawMsg: WhatsappMessage, options?: WhatsSocketMockSendingMsgOptions): Promise<void> {\r\n const info = this._extractInfoFromWhatsMsg(rawMsg, options);\r\n await this.onIncomingMsg.CallAllAsync(\r\n info.rawMsg.key.participant ?? null,\r\n info.rawMsg.key.participantAlt ?? null,\r\n info.rawMsg.key.remoteJid!,\r\n info.rawMsg,\r\n options?.customMsgType ?? info.msgType,\r\n options?.changeSenderType ?? info.senderType\r\n );\r\n }\r\n\r\n /**\r\n * @deprecated Use 'MockSendMsgAsync()' instead from this object 'WhatsSocketMock'. Its more reliable and normally\r\n * all code logic related to mockSending is Promised-Based....\r\n *\r\n * Simulates the reception of a message from whatsapp synchronously!\r\n * @param rawMsg The message to be sent.\r\n * @param options Optional options to modify the message before sending it.\r\n * Currently only supports replacing the text of the message.\r\n * @returns Resolves to void.\r\n */\r\n public MockSendMsg(rawMsg: WhatsappMessage, options?: WhatsSocketMockSendingMsgOptions): void {\r\n const info = this._extractInfoFromWhatsMsg(rawMsg, options);\r\n this.onIncomingMsg.CallAll(\r\n info.rawMsg.key.participant ?? null,\r\n info.rawMsg.key.participantAlt ?? null,\r\n info.rawMsg.key.remoteJid!,\r\n info.rawMsg,\r\n options?.customMsgType ?? info.msgType,\r\n options?.changeSenderType ?? info.senderType\r\n );\r\n }\r\n\r\n private _extractInfoFromWhatsMsg(rawMsg: WhatsappMessage, options?: WhatsSocketMockSendingMsgOptions) {\r\n const msgType: MsgType = MsgHelper_FullMsg_GetMsgType(rawMsg);\r\n const senderType: SenderType = MsgHelper_FullMsg_GetSenderType(rawMsg);\r\n\r\n let msgToReturn: WhatsappMessage;\r\n if (options) {\r\n msgToReturn = structuredClone(rawMsg);\r\n if (!rawMsg.message) {\r\n msgToReturn.message = {};\r\n }\r\n //=== Options handling ====\r\n if (options?.replaceTextWith) {\r\n msgToReturn.message!.conversation = options.replaceTextWith;\r\n }\r\n\r\n if (options?.replaceParticipantIdWith) {\r\n msgToReturn.key.participant = options.replaceParticipantIdWith;\r\n }\r\n\r\n if (options?.replaceChatIdWith) {\r\n msgToReturn.key.remoteJid = options.replaceChatIdWith;\r\n }\r\n } else {\r\n msgToReturn = rawMsg;\r\n }\r\n\r\n return { rawMsg: msgToReturn, msgType, senderType };\r\n }\r\n}\r\n\r\nfunction mapParticipant(p: ParticipantInfo): GroupParticipant {\r\n return {\r\n id: p.rawId ?? \"defaultId\" + WhatsappLIDIdentifier, // from WhatsappIDInfo\r\n name: undefined,\r\n notify: undefined,\r\n status: undefined,\r\n verifiedName: undefined,\r\n imgUrl: undefined,\r\n lid: undefined,\r\n isAdmin: p.isAdmin,\r\n isSuperAdmin: p.isAdmin, // or undefined if you prefer\r\n admin: p.isAdmin ? \"admin\" : null,\r\n };\r\n}\r\n","import type { IChatContextConfig } from \"../core/bot/internals/ChatContext.js\";\r\nimport { ChatContext } from \"../core/bot/internals/ChatContext.js\";\r\nimport type { WhatsappMessage } from \"../core/whats_socket/types.js\";\r\nimport type { MsgType } from \"../Msg.types.js\";\r\n\r\n/**\r\n * Mocking suite for {@link ChatContext}.\r\n *\r\n * This subclass is designed for unit/integration testing where\r\n * you don't want to actually download media from WhatsApp servers.\r\n * Instead of using `downloadMediaMessage`, it returns a configurable\r\n * mock buffer whenever a multimedia message is awaited.\r\n *\r\n * Usage:\r\n * ```ts\r\n * const mockCtx = new ChatContext_MockingSuite();\r\n * mockCtx.SetWaitMultiMediaBufferReturn(Buffer.from(\"test\"));\r\n *\r\n * const buf = await mockCtx.WaitMultimedia(MsgType.Image);\r\n * // buf === Buffer.from(\"test\")\r\n * ```\r\n */\r\nexport default class ChatContext_MockingSuite extends ChatContext {\r\n /**\r\n * Internal buffer to be returned when {@link WaitMultimedia} is called.\r\n * Defaults to `\"mock_buffer\"`.\r\n */\r\n private readonly _defaultBufferToReturn: Buffer = Buffer.from(\"mock_buffer\");\r\n\r\n private _queuedBufferToReturn: Buffer[] = [];\r\n\r\n /**\r\n * Configure the buffer that will be returned in place of a real\r\n * downloaded multimedia message.\r\n *\r\n * @param anyBuffer - The buffer to return on next `WaitMultimedia` calls.\r\n */\r\n public EnqueueMediaBufferToReturn(anyBuffer: Buffer) {\r\n this._queuedBufferToReturn.push(anyBuffer);\r\n }\r\n\r\n /**\r\n * Reset mock state to defaults.\r\n * The mock buffer is reset to `\"mock_buffer\"`.\r\n */\r\n public ClearMocks() {\r\n this._queuedBufferToReturn = [];\r\n }\r\n\r\n /**\r\n * Override of {@link ChatContext.WaitMultimedia}.\r\n *\r\n * Instead of downloading media via baileys, this returns the mock buffer\r\n * set via {@link EnqueueMediaBufferToReturn}.\r\n *\r\n * @param msgTypeToWaitFor - Type of multimedia message to wait for.\r\n * @param localOptions - Optional filters overriding the global context config.\r\n * @returns The configured mock buffer, or `null` if no matching message was found.\r\n */\r\n public override async WaitMultimedia(\r\n msgTypeToWaitFor: MsgType.Image | MsgType.Sticker | MsgType.Video | MsgType.Document | MsgType.Audio,\r\n localOptions?: Partial<IChatContextConfig>\r\n ): Promise<Buffer | null> {\r\n const found: WhatsappMessage | null = await this.WaitMsg(msgTypeToWaitFor, localOptions);\r\n if (!found) return null;\r\n const buffertoReturn: Buffer = this._queuedBufferToReturn.length > 0 ? this._queuedBufferToReturn.shift()! : this._defaultBufferToReturn;\r\n return buffertoReturn;\r\n }\r\n}\r\n","import mime from \"mime\";\r\nimport path from \"path\";\r\nimport type { WhatsappMessage } from \"../core/whats_socket/types.js\";\r\n\r\n/**\r\n * Internal helper for building the minimal base structure of a mock\r\n * WhatsApp message object.\r\n *\r\n * This function provides a consistent \"skeleton\" message with common\r\n * fields prefilled (e.g., `key`, `timestamp`, `deviceListMetadata`),\r\n * which can then be extended with specific message types such as text,\r\n * images, or reactions.\r\n *\r\n * @param chatId - The unique identifier (JID) of the chat where the message belongs.\r\n * @param participantId - The JID of the participant who sends the message.\r\n * @param id - Unique identifier of the message (typically a UUID or hash).\r\n * @param timestamp - Unix timestamp in **seconds** when the message was created.\r\n * @param pushName - Display name of the sender, as it would appear in WhatsApp.\r\n * @returns A partially constructed {@link WhatsappMessage} with basic metadata.\r\n *\r\n * @internal\r\n */\r\nfunction _createBaseMsg(chatId: string, participantId: string | null | undefined, id?: string, timestamp?: number, pushName?: string): WhatsappMessage {\r\n return {\r\n key: {\r\n remoteJid: chatId,\r\n participant: participantId ?? undefined,\r\n fromMe: false,\r\n id: id,\r\n },\r\n messageTimestamp: timestamp ?? Date.now(),\r\n pushName: pushName ?? \"Mock user\",\r\n broadcast: false,\r\n message: {},\r\n deviceListMetadata: {\r\n senderKeyHash: \"qprrpV5KV38MkA==\",\r\n senderTimestamp: \"1355194316\",\r\n recipientKeyHash: \"4gj7dwAGWE3rWw==\",\r\n recipientTimestamp: \"1155394318\",\r\n },\r\n deviceListMetadataVersion: 2,\r\n //@ts-expect-error This is string, but ts thinks is other type for some reason\r\n messageSecret: \"j+pPQKnytgjeJuMsvrly26TrQQjTFgDauhu2Gy9XsUM=\",\r\n };\r\n}\r\n\r\n/**\r\n * Factory function to generate a mock **text message** object in the\r\n * shape expected from the WhatsApp WebSocket.\r\n *\r\n * This is useful for testing, simulations, or mocking incoming messages\r\n * without relying on actual network activity. It builds on top of\r\n * {@link _createBaseMsg} by injecting a `conversation` field that\r\n * contains the text.\r\n *\r\n * @example\r\n * ```ts\r\n * const mockMsg = MsgFactory_CreateText(\r\n * \"12345@s.whatsapp.net\", // chatId\r\n * \"1111@c.us\", // participantId\r\n * \"Hello world!\", // text\r\n * { customSenderWhatsUsername: \"Alice\" }\r\n * );\r\n * ```\r\n *\r\n * @param chatId - The chat JID where the message should appear.\r\n * @param participantId - The JID of the sender (e.g., phone number with domain).\r\n * @param textToIncludeInMsg - The text body of the message (goes into `conversation`).\r\n * @param options - Optional configuration.\r\n * @param options.customSenderWhatsUsername - Override the sender's display name.\r\n *\r\n * @returns A complete {@link WhatsappMessage} object that represents a\r\n * mock text message, including metadata and content.\r\n */\r\nexport function MsgFactory_Text(\r\n chatId: string,\r\n participantId: string | undefined | null,\r\n textToIncludeInMsg: string,\r\n options?: { pushName?: string }\r\n): WhatsappMessage {\r\n const timestamp = Math.floor(Date.now() / 1000);\r\n const pushName = options?.pushName ?? \"User Who Sends this msg (mock response)\";\r\n\r\n const message: WhatsappMessage = _createBaseMsg(chatId, participantId ?? null, \"5AD0EEC1D2649BF2A2EC614714B3ED11\", timestamp, pushName);\r\n message.message = {\r\n conversation: textToIncludeInMsg,\r\n };\r\n return message;\r\n}\r\n\r\n/**\r\n * Factory function to generate a mock **text message with a quoted reply**.\r\n *\r\n * Builds on {@link _createBaseMsg} and injects an `extendedTextMessage`\r\n * with `contextInfo` referencing another {@link WhatsappMessage}.\r\n *\r\n * @example\r\n * ```ts\r\n * const original = MsgFactory_Image(\"123@g.us\", \"111@s.whatsapp.net\", \"http://img.jpg\");\r\n * const reply = MsgFactory_TextWithQuote(\"123@g.us\", null, \"Nice pic!\", original);\r\n * ```\r\n *\r\n * @param chatId - Chat JID where the reply is sent.\r\n * @param participantId - JID of the sender of this reply.\r\n * @param text - The body of the reply message.\r\n * @param quoted - A previously generated {@link WhatsappMessage} that\r\n * will be referenced as the quoted content.\r\n * @param opts.pushName - Override the display name for the sender.\r\n *\r\n * @returns A {@link WhatsappMessage} simulating a text reply with a quoted message.\r\n */\r\nexport function MsgFactory_TextWithQuote(\r\n chatId: string,\r\n participantId: string | null | undefined,\r\n text: string,\r\n quoted: WhatsappMessage,\r\n opts?: { pushName?: string }\r\n): WhatsappMessage {\r\n const base = _createBaseMsg(chatId, participantId, \"success_id_message_id\", Date.now(), opts?.pushName);\r\n\r\n base.message = {\r\n extendedTextMessage: {\r\n text,\r\n contextInfo: {\r\n stanzaId: quoted.key.id,\r\n participant: quoted.key.participant ?? quoted.key.remoteJid,\r\n quotedMessage: quoted.message,\r\n },\r\n },\r\n };\r\n\r\n return base;\r\n}\r\n\r\n/**\r\n * Factory function to generate a mock **image message**.\r\n *\r\n * @example\r\n * ```ts\r\n * const imgMsg = MsgFactory_Image(\"123@g.us\", null, \"http://server/image.jpg\", {\r\n * caption: \"Check this out!\"\r\n * });\r\n * ```\r\n *\r\n * @param chatId - Chat JID where the image is sent.\r\n * @param participantId - JID of the sender.\r\n * @param url - URL or path to the image.\r\n * @param opts.caption - Optional text caption.\r\n * @param opts.pushName - Override display name of sender.\r\n *\r\n * @returns A {@link WhatsappMessage} with an `imageMessage` payload.\r\n */\r\nexport function MsgFactory_Image(\r\n chatId: string,\r\n participantId: string | null | undefined,\r\n url: string,\r\n opts?: { caption?: string; pushName?: string }\r\n): WhatsappMessage {\r\n const base = _createBaseMsg(chatId, participantId, \"success_id_message_id\", Date.now(), opts?.pushName);\r\n base.message = {\r\n imageMessage: {\r\n url,\r\n mimetype: mime.getExtension(path.extname(url)),\r\n caption: opts?.caption,\r\n },\r\n };\r\n return base;\r\n}\r\n\r\n/**\r\n * Factory function to generate a mock **video message**.\r\n *\r\n * @example\r\n * ```ts\r\n * const vidMsg = MsgFactory_Video(\"123@g.us\", \"111@s.whatsapp.net\", \"http://vid.mp4\", {\r\n * caption: \"Funny video\"\r\n * });\r\n * ```\r\n *\r\n * @param chatId - Chat JID where the video is sent.\r\n * @param participantId - JID of the sender.\r\n * @param url - URL or path to the video.\r\n * @param opts.caption - Optional text caption.\r\n * @param opts.pushName - Override sender display name.\r\n *\r\n * @returns A {@link WhatsappMessage} with a `videoMessage` payload.\r\n */\r\nexport function MsgFactory_Video(\r\n chatId: string,\r\n participantId: string | null | undefined,\r\n url: string,\r\n opts?: { caption?: string; pushName?: string }\r\n): WhatsappMessage {\r\n const base = _createBaseMsg(chatId, participantId, \"success_id_message_id\", Date.now(), opts?.pushName);\r\n base.message = {\r\n videoMessage: {\r\n url,\r\n mimetype: mime.getExtension(path.extname(url)),\r\n caption: opts?.caption,\r\n },\r\n };\r\n return base;\r\n}\r\n\r\n/**\r\n * Factory function to generate a mock **audio message**.\r\n *\r\n * @example\r\n * ```ts\r\n * const audioMsg = MsgFactory_Audio(\"123@g.us\", null, \"http://server/audio.ogg\");\r\n * ```\r\n *\r\n * @param chatId - Chat JID where the audio is sent.\r\n * @param participantId - JID of the sender.\r\n * @param url - URL or path to the audio file.\r\n * @param opts.pushName - Override sender display name.\r\n *\r\n * @returns A {@link WhatsappMessage} with an `audioMessage` payload.\r\n */\r\nexport function MsgFactory_Audio(chatId: string, participantId: string | null | undefined, url: string, opts?: { pushName?: string }): WhatsappMessage {\r\n const base = _createBaseMsg(chatId, participantId, \"success_id_message_id\", Date.now(), opts?.pushName);\r\n base.message = {\r\n audioMessage: {\r\n url,\r\n mimetype: mime.getExtension(path.extname(url)),\r\n },\r\n };\r\n return base;\r\n}\r\n\r\n/**\r\n * Factory function to generate a mock **sticker message**.\r\n *\r\n * @example\r\n * ```ts\r\n * const stickerMsg = MsgFactory_Sticker(\"123@g.us\", null, \"http://server/sticker.webp\");\r\n * ```\r\n *\r\n * @param chatId - Chat JID where the sticker is sent.\r\n * @param participantId - JID of the sender.\r\n * @param url - URL or path to the `.webp` sticker file.\r\n * @param opts.pushName - Override sender display name.\r\n *\r\n * @returns A {@link WhatsappMessage} with a `stickerMessage` payload.\r\n */\r\nexport function MsgFactory_Sticker(chatId: string, participantId: string | null | undefined, url: string, opts?: { pushName?: string }): WhatsappMessage {\r\n const base = _createBaseMsg(chatId, participantId, \"success_id_message_id\", Date.now(), opts?.pushName);\r\n base.message = {\r\n stickerMessage: {\r\n url,\r\n mimetype: \"image/webp\",\r\n },\r\n };\r\n return base;\r\n}\r\n\r\n/**\r\n * Factory function to generate a mock **document message**.\r\n *\r\n * @example\r\n * ```ts\r\n * const docMsg = MsgFactory_Document(\"123@g.us\", \"111@s.whatsapp.net\", \"http://server/file.pdf\", {\r\n * fileName: \"report.pdf\"\r\n * });\r\n * ```\r\n *\r\n * @param chatId - Chat JID where the document is sent.\r\n * @param participantId - JID of the sender.\r\n * @param url - URL or path to the document file.\r\n * @param opts.fileName - File name shown in WhatsApp.\r\n * @param opts.mimetype - MIME type of the document.\r\n * @param opts.pushName - Override sender display name.\r\n *\r\n * @returns A {@link WhatsappMessage} with a `documentMessage` payload.\r\n */\r\nexport function MsgFactory_Document(\r\n chatId: string,\r\n participantId: string | null | undefined,\r\n url: string,\r\n opts?: { fileName?: string; mimetype?: string; pushName?: string }\r\n): WhatsappMessage {\r\n const base = _createBaseMsg(chatId, participantId, \"success_id_message_id\", Date.now(), opts?.pushName);\r\n base.message = {\r\n documentMessage: {\r\n url,\r\n mimetype: opts?.mimetype ?? \"application/pdf\",\r\n fileName: opts?.fileName ?? \"mock.pdf\",\r\n },\r\n };\r\n return base;\r\n}\r\n/**\r\n * Factory function to generate a mock **location message**.\r\n *\r\n * @example\r\n * ```ts\r\n * const locMsg = MsgFactory_Location(\"123@g.us\", \"111@s.whatsapp.net\", 19.4326, -99.1332, {\r\n * name: \"CDMX\",\r\n * address: \"Zócalo\"\r\n * });\r\n * ```\r\n *\r\n * @param chatId - Chat JID where the location is sent.\r\n * @param participantId - JID of the sender.\r\n * @param lat - Latitude in degrees.\r\n * @param lng - Longitude in degrees.\r\n * @param opts.name - Location name label.\r\n * @param opts.address - Location address label.\r\n * @param opts.pushName - Override sender display name.\r\n *\r\n * @returns A {@link WhatsappMessage} with a `locationMessage` payload.\r\n */\r\nexport function MsgFactory_Location(\r\n chatId: string,\r\n participantId: string | null | undefined,\r\n lat: number,\r\n lng: number,\r\n opts?: { name?: string; address?: string; pushName?: string }\r\n): WhatsappMessage {\r\n const base = _createBaseMsg(chatId, participantId, \"success_id_message_id\", Date.now(), opts?.pushName);\r\n base.message = {\r\n locationMessage: {\r\n degreesLatitude: lat,\r\n degreesLongitude: lng,\r\n name: opts?.name,\r\n address: opts?.address,\r\n },\r\n };\r\n return base;\r\n}\r\n\r\n/**\r\n * Factory function to generate a mock **contact message**.\r\n * Automatically builds proper vCard strings from simple\r\n * contact objects.\r\n *\r\n * Supports either a single contact or an array of contacts.\r\n *\r\n * @param chatId - Chat JID where the contacts array is sent.\r\n * @param participantId - JID of the sender.\r\n * @param contacts - Either a single contact object or an array of contacts.\r\n * Each contact should have:\r\n * - `contactName`: e.g., \"Chris\"\r\n * - `phoneNumber`: e.g., \"5217389273\" (same as +52 1 738 9273)\r\n * @param opts.pushName - Optional sender display name override.\r\n *\r\n * @returns A {@link WhatsappMessage} with a `contactsArrayMessage` payload.\r\n */\r\nexport function MsgFactory_Contact(\r\n chatId: string,\r\n participantId: string | null | undefined,\r\n contacts: { name: string; phone: string } | Array<{ name: string; phone: string }>,\r\n opts?: { pushName?: string }\r\n): WhatsappMessage {\r\n const base = _createBaseMsg(chatId, participantId, \"success_id_message_id\", Date.now(), opts?.pushName);\r\n\r\n // Normalize to array\r\n if (Array.isArray(contacts)) {\r\n base.message = {\r\n contactsArrayMessage: {\r\n contacts: contacts.map((c) => {\r\n const vcard = [\"BEGIN:VCARD\", \"VERSION:3.0\", `FN:${c.name}`, `TEL;type=WAID=${c.phone}`, \"END:VCARD\"].join(\"\\n\");\r\n return { displayName: c.name, vcard };\r\n }),\r\n },\r\n };\r\n } else {\r\n const vcard = [\"BEGIN:VCARD\", \"VERSION:3.0\", `FN:${contacts.name}`, `TEL;type=WAID=${contacts.phone}`, \"END:VCARD\"].join(\"\\n\");\r\n base.message = {\r\n contactMessage: {\r\n displayName: contacts.name,\r\n vcard: vcard,\r\n },\r\n };\r\n }\r\n\r\n return base;\r\n}\r\n","import type { IChatContextConfig } from \"../core/bot/internals/ChatContext.js\";\r\nimport type { IWhatsSocket_Submodule_Receiver } from \"../core/whats_socket/internals/IWhatsSocket.receiver.js\";\r\nimport type { WhatsSocketReceiverError } from \"../core/whats_socket/internals/WhatsSocket.receiver.js\";\r\nimport {\r\n type GroupMetadataInfo,\r\n type WhatsSocketReceiverWaitOptions,\r\n WhatsSocketReceiverMsgError,\r\n} from \"../core/whats_socket/internals/WhatsSocket.receiver.js\";\r\nimport type { WhatsappMessage } from \"../core/whats_socket/types.js\";\r\nimport { MsgHelper_FullMsg_GetMsgType, MsgHelper_FullMsg_GetText } from \"../helpers/Msg.helper.js\";\r\nimport { WhatsappIdType } from \"../helpers/Whatsapp.helper.js\";\r\nimport { MsgType } from \"../Msg.types.js\";\r\nimport { WhatsappGroupIdentifier } from \"../Whatsapp.types.js\";\r\n\r\nexport type WhatsSocketReceiverWaitObject = {\r\n rawMsg: WhatsappMessage;\r\n milisecondsDelayToRespondMock?: number;\r\n};\r\n\r\nexport type WhatsSocketReceiverMsgWaited = {\r\n waitedMsgType: MsgType;\r\n chatId: string;\r\n partipantId_LID: string | null;\r\n participantId_PN: string | null;\r\n options?: Partial<IChatContextConfig>;\r\n};\r\n\r\nexport default class WhatsSocket_Submodule_Receiver_MockingSuite implements IWhatsSocket_Submodule_Receiver {\r\n /**\r\n * Pending msgs to send to command when executed.\r\n */\r\n private _queueWait: WhatsSocketReceiverWaitObject[] = [];\r\n\r\n /**\r\n * Config: Actual metadata to mock when executing command (Environment mock)\r\n */\r\n private _groupMetadataToSendMock: GroupMetadataInfo;\r\n public get GroupMetadataToSendMock(): GroupMetadataInfo | undefined {\r\n return this._groupMetadataToSendMock;\r\n }\r\n\r\n //=================================================== Spy External Methods ==================================================\r\n /**\r\n * All waited msgs from command after its execution\r\n */\r\n public Waited: WhatsSocketReceiverMsgWaited[] = [];\r\n //===========================================================================================================================\r\n\r\n public constructor() {\r\n this._groupMetadataToSendMock = GenerateDefaultGroupMetadata();\r\n }\r\n\r\n public SetGroupMetadataMock(mock: Partial<GroupMetadataInfo>) {\r\n this._groupMetadataToSendMock = GenerateDefaultGroupMetadata(mock);\r\n }\r\n public ResetGroupMetadata() {\r\n this._groupMetadataToSendMock = GenerateDefaultGroupMetadata();\r\n }\r\n\r\n public AddWaitMsg(toAdd: WhatsSocketReceiverWaitObject) {\r\n this._queueWait.push(toAdd);\r\n }\r\n\r\n public ClearMocks() {\r\n this._queueWait = [];\r\n this.Waited = [];\r\n this._groupMetadataToSendMock = GenerateDefaultGroupMetadata();\r\n }\r\n\r\n //_local Options is not used, just used in real commands, here is not necessary;\r\n public WaitMsg(\r\n userID_LID_ToWait: string | null,\r\n userID_PN_to_wait: string | null,\r\n chatId: string,\r\n expectedType: MsgType,\r\n _localOptions?: Partial<IChatContextConfig>\r\n ): Promise<WhatsappMessage> {\r\n return new Promise((resolve, reject) => {\r\n // Removed async from here\r\n if (this._queueWait.length === 0) {\r\n return reject(\r\n new Error(\"ChatContext is trying to wait a msg that will never arrives!... Use MockChat.EnqueueIncoming_****() to enqueue what to return!\")\r\n );\r\n }\r\n const actualWaitedObjInfo = this._queueWait.shift()!;\r\n const timeoutPromise = new Promise<never>((_, rejectTimeout) => {\r\n if (_localOptions?.timeoutSeconds) {\r\n setTimeout(() => {\r\n rejectTimeout({\r\n errorMessage: WhatsSocketReceiverMsgError.Timeout,\r\n wasAbortedByUser: false,\r\n chatId: chatId,\r\n participantId_LID: userID_LID_ToWait,\r\n participantId_PN: userID_PN_to_wait,\r\n } satisfies WhatsSocketReceiverError);\r\n }, _localOptions.timeoutSeconds * 1000);\r\n }\r\n });\r\n\r\n const messageProcessingPromise = (async () => {\r\n const actualMsg_msgType = MsgHelper_FullMsg_GetMsgType(actualWaitedObjInfo.rawMsg);\r\n\r\n if (actualWaitedObjInfo.milisecondsDelayToRespondMock) {\r\n await new Promise((resolveDelay) => setTimeout(resolveDelay, actualWaitedObjInfo.milisecondsDelayToRespondMock));\r\n }\r\n\r\n if (_localOptions?.cancelKeywords) {\r\n if (actualMsg_msgType === MsgType.Text) {\r\n const txt = MsgHelper_FullMsg_GetText(actualWaitedObjInfo.rawMsg);\r\n if (txt) {\r\n const wordsLowerCased = txt.split(\" \").map((word) => word.toLowerCase());\r\n for (const cancelWord of _localOptions.cancelKeywords) {\r\n if (wordsLowerCased.includes(cancelWord.toLowerCase())) {\r\n throw {\r\n errorMessage: WhatsSocketReceiverMsgError.UserCanceledWaiting,\r\n chatId: chatId,\r\n participantId_LID: userID_LID_ToWait,\r\n participantId_PN: userID_PN_to_wait,\r\n wasAbortedByUser: true,\r\n } satisfies WhatsSocketReceiverError;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (actualMsg_msgType !== expectedType) {\r\n throw new Error(\r\n `You have received a msg of type ${MsgType[actualMsg_msgType]} when you expected of type ${MsgType[expectedType]}!, check what are you sending from MockChat.EnqueueIncoming_****() msg!, try again...`\r\n );\r\n }\r\n\r\n this.Waited.push({\r\n options: _localOptions,\r\n chatId: chatId,\r\n partipantId_LID: userID_LID_ToWait,\r\n participantId_PN: userID_PN_to_wait,\r\n waitedMsgType: actualMsg_msgType,\r\n });\r\n\r\n return actualWaitedObjInfo.rawMsg;\r\n })();\r\n\r\n try {\r\n Promise.race([messageProcessingPromise, timeoutPromise]).then(resolve).catch(reject);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n }\r\n\r\n public WaitUntilNextRawMsgFromUserIDInGroup(\r\n userID_LID_ToWait: string | null,\r\n userID_PN_toWait: string | null,\r\n chatToWaitOnID: string,\r\n expectedMsgType: MsgType,\r\n options: WhatsSocketReceiverWaitOptions\r\n ): Promise<WhatsappMessage> {\r\n return this.WaitMsg(userID_LID_ToWait, userID_PN_toWait, chatToWaitOnID, expectedMsgType, options);\r\n }\r\n\r\n public WaitUntilNextRawMsgFromUserIdInPrivateConversation(\r\n userIdToWait: string,\r\n expectedMsgType: MsgType,\r\n options: WhatsSocketReceiverWaitOptions\r\n ): Promise<WhatsappMessage> {\r\n return this.WaitMsg(null, null, userIdToWait, expectedMsgType, options);\r\n }\r\n\r\n /**\r\n * Important note: chatId param Is ignored, if you want to set a custom mock group metadata, use SetGroupMetadataMock() of this class\r\n * @param _chatId Is ignored, if you want to set a custom mock group metadata, use SetGroupMetadataMock() of this class\r\n * @returns The mocked group metadata establish in this mock receiver\r\n */\r\n public async FetchGroupData(_chatId: string): Promise<GroupMetadataInfo | null> {\r\n if (_chatId) {\r\n return { ...this._groupMetadataToSendMock, id: _chatId };\r\n } else {\r\n return this._groupMetadataToSendMock;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Generates a default group metadata object for mocking purposes.\r\n *\r\n * - Provides sensible defaults for all {@link GroupMetadataInfo} fields.\r\n * - Allows overriding any field by passing a partial object.\r\n *\r\n * @param chatContextData - Partial group data to override defaults.\r\n * @returns A fully populated {@link GroupMetadataInfo}.\r\n */\r\nexport function GenerateDefaultGroupMetadata(chatContextData: Partial<GroupMetadataInfo> = {}): GroupMetadataInfo {\r\n const defaults: GroupMetadataInfo = {\r\n id: \"fakeChatId\" + WhatsappGroupIdentifier,\r\n sendingMode: WhatsappIdType.Modern,\r\n ownerName: \"John Doe\",\r\n groupName: \"DEFAULT_groupname\",\r\n groupDescription: \"A group for awesome team collaboration!\",\r\n communityIdWhereItBelongs: null,\r\n onlyAdminsCanChangeGroupSettings: true,\r\n onlyAdminsCanSendMsgs: false,\r\n membersCanAddOtherMembers: true,\r\n needsRequestApprovalToJoinIn: false,\r\n isCommunityAnnounceChannel: false,\r\n membersCount: 25,\r\n ephemeralDuration: 86400, // 24 hours in seconds\r\n inviteCode: \"abc123xyz\",\r\n lastNameChangeDateTime: 1694726400000, // Example timestamp (2023-09-15)\r\n author: \"mock_author\",\r\n creationDate: 1694640000000, // Example timestamp (2023-09-14)\r\n members: [\r\n {\r\n asMentionFormatted: \"@12345678901\",\r\n rawId: \"12345678901@s.whatsapp.net\",\r\n isAdmin: true,\r\n WhatsappIdType: WhatsappIdType.Modern,\r\n },\r\n {\r\n asMentionFormatted: \"@12345678902\",\r\n rawId: \"12345678902@s.whatsapp.net\",\r\n isAdmin: false,\r\n WhatsappIdType: WhatsappIdType.Modern,\r\n },\r\n {\r\n asMentionFormatted: \"@12345678903\",\r\n rawId: \"12345678903@s.whatsapp.net\",\r\n isAdmin: false,\r\n WhatsappIdType: WhatsappIdType.Modern,\r\n },\r\n ],\r\n };\r\n\r\n return {\r\n ...defaults,\r\n ...chatContextData,\r\n members: chatContextData.members ?? defaults.members,\r\n };\r\n}\r\n","import type { WAMessage } from \"baileys\";\r\nimport mime from \"mime\";\r\nimport path from \"node:path\";\r\nimport type {\r\n IWhatsSocket_Submodule_SugarSender,\r\n WhatsMsgAudioOptions,\r\n WhatsMsgDocumentOptions,\r\n WhatsMsgMediaOptions,\r\n WhatsMsgPollOptions,\r\n WhatsMsgSenderSendingOptions,\r\n WhatsMsgSenderSendingOptionsMINIMUM,\r\n WhatsMsgUbicationOptions,\r\n} from \"../core/whats_socket/internals/IWhatsSocket.sugarsender.js\";\r\nimport type { WhatsappMessage } from \"../core/whats_socket/types.js\";\r\nimport { autobind } from \"../helpers/Decorators.helper.js\";\r\nimport { WhatsappGroupIdentifier, WhatsappPhoneNumberIdentifier } from \"../Whatsapp.types.js\";\r\nimport {\r\n MsgFactory_Audio,\r\n MsgFactory_Contact,\r\n MsgFactory_Document,\r\n MsgFactory_Image,\r\n MsgFactory_Location,\r\n MsgFactory_Sticker,\r\n MsgFactory_Text,\r\n MsgFactory_Video,\r\n} from \"./MsgsMockFactory.js\";\r\n\r\n/**\r\n * A mocking implementation of `IWhatsSocket_Submodule_SugarSender` designed for unit testing.\r\n * This class simulates the behavior of sending various WhatsApp message types without interacting\r\n * with the actual WhatsApp socket. Instead, it stores sent message details in public arrays for\r\n * verification in tests (e.g., using `expect` assertions).\r\n *\r\n * @remarks\r\n * - All sending methods return a mock `WhatsappMessage` object simulating success.\r\n * - Chat IDs are normalized to ensure proper group/individual format.\r\n * - Use `ClearMocks()` to reset all stored message arrays between tests.\r\n * - This is not intended for production use; it's solely for testing the sugar sender logic.\r\n *\r\n * @example\r\n * ```ts\r\n * const mockSender = new WhatsSocket_Submodule_SugarSender_MockingSuite();\r\n * await mockSender.Text(\"1234567890\", \"Hello!\");\r\n * expect(mockSender.SentMessages_Texts).toHaveLength(1);\r\n * expect(mockSender.SentMessages_Texts[0].text).toBe(\"Hello!\");\r\n * ```\r\n */\r\nexport default class WhatsSocket_Submodule_SugarSender_MockingSuite implements IWhatsSocket_Submodule_SugarSender {\r\n private readonly PushNameUserMock = \"ChatMock User\";\r\n //=================================================== Spy External Methods ==================================================\r\n // Text\r\n /**\r\n * Array storing details of simulated text messages sent via `Text()`.\r\n */\r\n public SentMessages_Texts: Array<{\r\n chatId: string;\r\n text: string;\r\n options?: WhatsMsgSenderSendingOptions;\r\n }> = [];\r\n /**\r\n * Simulates sending a text message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param text - The message text to send.\r\n * @param options - Optional sending options (e.g., mentions, normalization).\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Texts` for test verification.\r\n * - Normalizes the chat ID using `NormalizeChatId`.\r\n *\r\n * @example\r\n * ```ts\r\n * await mockSender.Text(\"338839029383\" + WhatsappGroupIdentifier, \"Hello World!\", { normalizeMessageText: true });\r\n * expect(mockSender.SentMessages_Texts[0].text).toBe(\"Hello World!\");\r\n * expect(mockSender.SentMessages_Texts[0].options).toEqual({ normalizeMessageText: true });\r\n * ```\r\n */\r\n @autobind\r\n public async Text(chatId: string, text: string, options?: WhatsMsgSenderSendingOptions): Promise<WAMessage | null> {\r\n const chatIdNormalized = NormalizeChatId(chatId);\r\n this.SentMessages_Texts.push({ text: text, options: options, chatId: chatIdNormalized });\r\n return MsgFactory_Text(chatIdNormalized, null, text, { pushName: this.PushNameUserMock });\r\n }\r\n\r\n // Img\r\n /**\r\n * Array storing details of simulated image messages sent via `Image()`.\r\n */\r\n public SentMessages_Imgs: Array<{\r\n chatId: string;\r\n imageOptions: WhatsMsgMediaOptions;\r\n options?: WhatsMsgSenderSendingOptions;\r\n }> = [];\r\n /**\r\n * Simulates sending an image message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param imageOptions - Options for the image (e.g., source path/buffer, caption, format).\r\n * @param options - Optional sending options (e.g., mentions).\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Imgs` for test verification.\r\n * - Does not perform actual file I/O; assumes valid image options.\r\n *\r\n * @example\r\n * ```ts\r\n * const imageOpts = { source: \"./fake.png\", caption: \"Check this image!\" };\r\n * await mockSender.Image(\"1234567890\", imageOpts);\r\n * expect(mockSender.SentMessages_Imgs[0].imageOptions).toEqual(imageOpts);\r\n * ```\r\n */\r\n @autobind\r\n public async Image(chatId: string, imageOptions: WhatsMsgMediaOptions, options?: WhatsMsgSenderSendingOptions): Promise<WAMessage | null> {\r\n const chatIdNormalized = NormalizeChatId(chatId);\r\n this.SentMessages_Imgs.push({ chatId: chatIdNormalized, imageOptions, options });\r\n return MsgFactory_Image(chatIdNormalized, null, imageOptions.source.toString(), {\r\n caption: imageOptions.caption,\r\n pushName: this.PushNameUserMock,\r\n });\r\n }\r\n\r\n // === ReactEmojiToMsg ===\r\n /**\r\n * Array storing details of simulated emoji reactions sent via `ReactEmojiToMsg()`.\r\n */\r\n public SentMessages_ReactedEmojis: Array<{\r\n chatId: string;\r\n rawMsgReactedTo: WAMessage;\r\n emojiStr: string;\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM;\r\n }> = [];\r\n /**\r\n * Simulates reacting to a message with an emoji.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param rawMsgToReactTo - The original message to react to.\r\n * @param emojiStr - The emoji string (e.g., \"👍\").\r\n * @param options - Optional sending options.\r\n * @returns A mock `WhatsappMessage` simulating successful reaction.\r\n *\r\n * @remarks\r\n * - Stores the reaction details in `SentMessages_ReactedEmojis` for test verification.\r\n *\r\n * @example\r\n * ```ts\r\n * const mockMsg = { key: { id: \"msg123\" } } as WAMessage;\r\n * await mockSender.ReactEmojiToMsg(\"1234567890\", mockMsg, \"❤️\");\r\n * expect(mockSender.SentMessages_ReactedEmojis[0].emojiStr).toBe(\"❤️\");\r\n * ```\r\n */\r\n @autobind\r\n public async ReactEmojiToMsg(\r\n chatId: string,\r\n rawMsgToReactTo: WAMessage,\r\n emojiStr: string,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WAMessage | null> {\r\n const chatIdNormalized = NormalizeChatId(chatId);\r\n this.SentMessages_ReactedEmojis.push({ chatId: chatIdNormalized, emojiStr, rawMsgReactedTo: rawMsgToReactTo, options });\r\n return CreateSuccessWhatsMsg(null, chatIdNormalized);\r\n }\r\n\r\n // === Stickers ===\r\n /**\r\n * Array storing details of simulated sticker messages sent via `Sticker()`.\r\n */\r\n public SentMessages_Stickers: Array<{\r\n chatId: string;\r\n stickerUrlSource: string | Buffer;\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM;\r\n }> = [];\r\n /**\r\n * Simulates sending a sticker message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param stickerUrlSource - Source of the sticker (URL string or Buffer).\r\n * @param options - Optional sending options.\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Stickers` for test verification.\r\n * - Does not process or validate the sticker source.\r\n *\r\n * @example\r\n * ```ts\r\n * const stickerBuffer = Buffer.from(\"sticker-data\");\r\n * await mockSender.Sticker(\"1234567890\", stickerBuffer);\r\n * expect(mockSender.SentMessages_Stickers[0].stickerUrlSource).toBe(stickerBuffer);\r\n * ```\r\n */\r\n @autobind\r\n public async Sticker(chatId: string, stickerUrlSource: string | Buffer, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WAMessage | null> {\r\n const chatIdNormalized: string = NormalizeChatId(chatId);\r\n this.SentMessages_Stickers.push({ chatId: chatIdNormalized, stickerUrlSource, options });\r\n return MsgFactory_Sticker(chatIdNormalized, null, stickerUrlSource.toString(), {\r\n pushName: this.PushNameUserMock,\r\n });\r\n }\r\n\r\n // === Audio ===\r\n /**\r\n * Array storing details of simulated audio messages sent via `Audio()`.\r\n */\r\n public SentMessages_Audios: Array<{\r\n chatId: string;\r\n audioParams: WhatsMsgAudioOptions;\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM;\r\n }> = [];\r\n /**\r\n * Simulates sending an audio message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param audioParams - Options for the audio, including:\r\n * - `source`: The audio source, either a file path or a Buffer.\r\n * - `formatExtension`: The file extension of the audio (e.g., \".mp3\", \".ogg\").\r\n * @param options - Optional sending options (e.g., quoting a message).\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Audios` for test verification.\r\n * - Normalizes the chat ID using `NormalizeChatId`.\r\n * - Does not validate the audio content or extension; this is purely for testing.\r\n *\r\n * @example\r\n * ```ts\r\n * const audioOpts = { source: \"./voice.ogg\", formatExtension: \".ogg\" };\r\n * await mockSender.Audio(\"1234567890\", audioOpts);\r\n * expect(mockSender.SentMessages_Audios[0]!.audioParams.formatExtension).toBe(\".ogg\");\r\n * expect(mockSender.SentMessages_Audios[0]!.audioParams.source).toBe(\"./voice.ogg\");\r\n * ```\r\n */\r\n @autobind\r\n public async Audio(chatId: string, audioParams: WhatsMsgAudioOptions, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WAMessage | null> {\r\n const chatIdNormalized: string = NormalizeChatId(chatId);\r\n this.SentMessages_Audios.push({ audioParams, chatId: chatIdNormalized, options });\r\n return MsgFactory_Audio(chatIdNormalized, null, audioParams.source.toString(), {\r\n pushName: this.PushNameUserMock,\r\n });\r\n }\r\n\r\n // === Video ===\r\n /**\r\n * Array storing details of simulated video messages sent via `Video()`.\r\n */\r\n public SentMessages_Videos: Array<{\r\n chatId: string;\r\n videoParams: WhatsMsgMediaOptions;\r\n options?: WhatsMsgSenderSendingOptions;\r\n }> = [];\r\n /**\r\n * Simulates sending a video message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param videoParams - Options for the video (e.g., source, caption, format).\r\n * @param options - Optional sending options.\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Videos` for test verification.\r\n *\r\n * @example\r\n * ```ts\r\n * const videoOpts = { source: \"./clip.mp4\", caption: \"Watch this!\" };\r\n * await mockSender.Video(\"1234567890\", videoOpts);\r\n * expect(mockSender.SentMessages_Videos[0].videoParams.caption).toBe(\"Watch this!\");\r\n * ```\r\n */\r\n @autobind\r\n public async Video(chatId: string, videoParams: WhatsMsgMediaOptions, options?: WhatsMsgSenderSendingOptions): Promise<WAMessage | null> {\r\n const chatIdNormalized: string = NormalizeChatId(chatId);\r\n this.SentMessages_Videos.push({ chatId: chatIdNormalized, videoParams, options });\r\n return MsgFactory_Video(chatIdNormalized, null, videoParams.source.toString(), {\r\n caption: videoParams.caption,\r\n pushName: this.PushNameUserMock,\r\n });\r\n }\r\n\r\n /**\r\n * Array storing details of simulated document messages sent via `Document()`.\r\n */\r\n public SentMessages_Documents: Array<{\r\n chatId: string;\r\n docParams: WhatsMsgDocumentOptions;\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM;\r\n }> = [];\r\n /**\r\n *\r\n * Simulates sending a document message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param docParams - Options for the document (e.g., source path/buffer, filename).\r\n * @param options - Optional sending options.\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Documents` for test verification.\r\n *\r\n * @example\r\n * ```ts\r\n * const docOpts = { source: \"./report.pdf\", fileNameToDisplay: \"Report 2025\" };\r\n * await mockSender.Document(\"1234567890\", docOpts);\r\n * expect(mockSender.SentMessages_Documents[0].docParams.fileNameToDisplay).toBe(\"Report 2025\");\r\n * ```\r\n */\r\n @autobind\r\n public async Document(chatId: string, docParams: WhatsMsgDocumentOptions, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WAMessage | null> {\r\n const chatIdNormalized: string = NormalizeChatId(chatId);\r\n this.SentMessages_Documents.push({ chatId: chatIdNormalized, docParams, options });\r\n if (typeof docParams.source === \"string\") {\r\n return MsgFactory_Document(chatIdNormalized, null, docParams.source, {\r\n fileName: path.basename(docParams.source),\r\n mimetype: mime.getType(path.extname(docParams.source)) ?? undefined,\r\n pushName: this.PushNameUserMock,\r\n });\r\n } else {\r\n return MsgFactory_Document(chatIdNormalized, null, \"./file-buffer.mock\", {\r\n fileName: \"file-buffer.mock\",\r\n mimetype: undefined,\r\n pushName: this.PushNameUserMock,\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Array storing details of simulated poll messages sent via `Poll()`.\r\n */\r\n public SentMessages_Polls: Array<{\r\n chatId: string;\r\n pollTitle: string;\r\n selections: string[];\r\n pollParams: WhatsMsgPollOptions;\r\n moreOptions?: WhatsMsgSenderSendingOptionsMINIMUM;\r\n }> = [];\r\n\r\n /**\r\n * Simulates sending a poll message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param pollTitle - The poll question/title.\r\n * @param selections - Array of poll options (1-12 items).\r\n * @param pollParams - Poll-specific options (e.g., multi-select, normalization).\r\n * @param moreOptions - Additional sending options.\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Polls` for test verification.\r\n * - Does not validate selection count or normalization in this mock.\r\n *\r\n * @example\r\n * ```ts\r\n * await mockSender.Poll(\"1234567890\", \"Favorite color?\", [\"Red\", \"Blue\"], { withMultiSelect: false });\r\n * expect(mockSender.SentMessages_Polls[0].selections).toEqual([\"Red\", \"Blue\"]);\r\n * ```\r\n */\r\n @autobind\r\n public async Poll(\r\n chatId: string,\r\n pollTitle: string,\r\n selections: string[],\r\n pollParams: WhatsMsgPollOptions,\r\n moreOptions?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WAMessage | null> {\r\n const chatIdNormalized: string = NormalizeChatId(chatId);\r\n this.SentMessages_Polls.push({ chatId: chatIdNormalized, moreOptions, pollParams, pollTitle, selections });\r\n return CreateSuccessWhatsMsg(null, chatIdNormalized);\r\n }\r\n\r\n /**\r\n * Array storing details of simulated location messages sent via `Location()`.\r\n *\r\n * @type {Array<{ chatId: string; ubicationParams: WhatsMsgUbicationOptions; options?: WhatsMsgSenderSendingOptionsMINIMUM }>}\r\n */\r\n public SentMessages_Locations: Array<{\r\n chatId: string;\r\n ubicationParams: WhatsMsgUbicationOptions;\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM;\r\n }> = [];\r\n\r\n /**\r\n * Simulates sending a location message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param ubicationParams - Location parameters (e.g., latitude, longitude, name).\r\n * @param options - Optional sending options.\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Locations` for test verification.\r\n * - Does not validate coordinates in this mock.\r\n *\r\n * @example\r\n * ```ts\r\n * const locParams = { degreesLatitude: 40.7128, degreesLongitude: -74.0060, name: \"NYC\" };\r\n * await mockSender.Location(\"1234567890\", locParams);\r\n * expect(mockSender.SentMessages_Locations[0].ubicationParams.degreesLatitude).toBe(40.7128);\r\n * ```\r\n */\r\n @autobind\r\n public async Location(chatId: string, ubicationParams: WhatsMsgUbicationOptions, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WAMessage | null> {\r\n const chatIdNormalized: string = NormalizeChatId(chatId);\r\n this.SentMessages_Locations.push({ chatId: chatIdNormalized, ubicationParams, options });\r\n return MsgFactory_Location(chatIdNormalized, null, ubicationParams.degreesLatitude, ubicationParams.degreesLongitude, {\r\n address: ubicationParams.addressText,\r\n name: ubicationParams.name,\r\n pushName: this.PushNameUserMock,\r\n });\r\n }\r\n\r\n /**\r\n * Array storing details of simulated contact messages sent via `Contact()`.\r\n *\r\n * @type {Array<{ chatId: string; contacts: { name: string; phone: string } | Array<{ name: string; phone: string }>; options?: WhatsMsgSenderSendingOptionsMINIMUM }>}\r\n */\r\n public SentMessages_Contacts: Array<{\r\n chatId: string;\r\n contacts: { name: string; phone: string } | Array<{ name: string; phone: string }>;\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM;\r\n }> = [];\r\n /**\r\n * Simulates sending a contact (or contacts) message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param contacts - Single contact or array of contacts (name and phone required).\r\n * @param options - Optional sending options.\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Contacts` for test verification.\r\n * - Does not generate vCards or validate contacts in this mock.\r\n *\r\n * @example\r\n * ```ts\r\n * const contact = { name: \"John Doe\", phone: \"1234567890\" };\r\n * await mockSender.Contact(\"1234567890\", contact);\r\n * expect(mockSender.SentMessages_Contacts[0].contacts).toEqual(contact);\r\n * ```\r\n */\r\n @autobind\r\n public async Contact(\r\n chatId: string,\r\n contacts: { name: string; phone: string } | Array<{ name: string; phone: string }>,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WAMessage | null> {\r\n const chatIdNormalized: string = NormalizeChatId(chatId);\r\n this.SentMessages_Contacts.push({ chatId: chatIdNormalized, contacts, options });\r\n return MsgFactory_Contact(chatIdNormalized, null, contacts, {\r\n pushName: this.PushNameUserMock,\r\n });\r\n }\r\n //===========================================================================================================================\r\n /**\r\n * Clears all stored mock message arrays, resetting the mocking suite for new tests.\r\n *\r\n * @remarks\r\n * - Call this in `afterEach` hooks to prevent test pollution.\r\n *\r\n * @example\r\n * ```ts\r\n * afterEach(() => {\r\n * mockSender.ClearMocks();\r\n * });\r\n * ```\r\n */\r\n public ClearMocks(): void {\r\n this.SentMessages_Texts = [];\r\n this.SentMessages_Imgs = [];\r\n this.SentMessages_ReactedEmojis = [];\r\n this.SentMessages_Stickers = [];\r\n this.SentMessages_Audios = [];\r\n this.SentMessages_Videos = [];\r\n this.SentMessages_Documents = [];\r\n this.SentMessages_Polls = [];\r\n this.SentMessages_Locations = [];\r\n this.SentMessages_Contacts = [];\r\n }\r\n\r\n // =============== to add =====================\r\n}\r\n\r\n/**\r\n * Creates a mock `WhatsappMessage` simulating a successful message send.\r\n *\r\n * @param participantId - Optional participant ID for the message key.\r\n * @param chatId - The chat ID for the remote JID.\r\n * @returns A basic `WhatsappMessage` object with a mock key.\r\n *\r\n * @remarks\r\n * - Used internally by all mocking methods to return consistent success responses.\r\n * - TODO: Enhance to create type-specific mock messages.\r\n *\r\n * @internal\r\n */\r\nfunction CreateSuccessWhatsMsg(participantId: string | null, chatId: string): WhatsappMessage {\r\n const toReturn: WhatsappMessage = {\r\n key: {\r\n fromMe: false,\r\n id: \"success_id_message_id\",\r\n participant: participantId ?? undefined,\r\n remoteJid: chatId,\r\n },\r\n };\r\n return toReturn;\r\n}\r\n\r\nfunction NormalizeChatId(rawChatId: string): string {\r\n if (rawChatId.endsWith(WhatsappPhoneNumberIdentifier)) return rawChatId;\r\n if (rawChatId.endsWith(WhatsappGroupIdentifier)) {\r\n return rawChatId;\r\n } else {\r\n return rawChatId + WhatsappGroupIdentifier;\r\n }\r\n}\r\n","import mime from \"mime\";\r\nimport path from \"node:path\";\r\nimport { type WhatsBotOptions, BotUtils_GenerateOptions } from \"../core/bot/bot.js\";\r\nimport type { IChatContextConfig } from \"../core/bot/internals/ChatContext.js\";\r\nimport Myself_Submodule_Status from \"../core/bot/internals/ChatContext.myself.status.js\";\r\nimport CommandsSearcher, { CommandType } from \"../core/bot/internals/CommandsSearcher.js\";\r\nimport type { ICommand } from \"../core/bot/internals/ICommand.js\";\r\nimport type { GroupMetadataInfo } from \"../core/whats_socket/internals/WhatsSocket.receiver.js\";\r\nimport type { WhatsSocketMockMsgSent } from \"../core/whats_socket/mocks/types.js\";\r\nimport WhatsSocketMock from \"../core/whats_socket/mocks/WhatsSocket.mock.js\";\r\nimport type { WhatsappMessage } from \"../core/whats_socket/types.js\";\r\nimport { autobind } from \"../helpers/Decorators.helper.js\";\r\nimport { ChatContext, MsgType, SenderType } from \"../index.js\";\r\nimport { WhatsappGroupIdentifier, WhatsappLIDIdentifier, WhatsappPhoneNumberIdentifier } from \"../Whatsapp.types.js\";\r\nimport ChatContext_MockingSuite from \"./ChatContext.mockingsuite.js\";\r\nimport {\r\n MsgFactory_Audio,\r\n MsgFactory_Contact,\r\n MsgFactory_Document,\r\n MsgFactory_Image,\r\n MsgFactory_Location,\r\n MsgFactory_Sticker,\r\n MsgFactory_Text,\r\n MsgFactory_Video,\r\n} from \"./MsgsMockFactory.js\";\r\nimport type { WhatsSocketReceiverMsgWaited } from \"./WhatsSocket.receiver.mockingsuite.js\";\r\nimport WhatsSocket_Submodule_Receiver_MockingSuite from \"./WhatsSocket.receiver.mockingsuite.js\";\r\nimport WhatsSocket_Submodule_SugarSender_MockingSuite from \"./WhatsSocket.sugarsender.mockingsuite.js\";\r\n\r\n/**\r\n * Extends {@link WhatsBotOptions} with additional settings specific to the mocking suite.\r\n */\r\ntype AdditionalWhatsBotOptions = {\r\n /**\r\n * An array of commands to pre-register in the bot's command handler\r\n * when the mock environment is initialized. This is useful for testing\r\n * commands that might depend on or interact with other commands.\r\n *\r\n * @example\r\n * ```ts\r\n * const chat = new ChatMock(myCommand, {\r\n * botSettings: {\r\n * initialCommandsToAdd: [new AnotherCommand(), new HelperCommand()]\r\n * }\r\n * });\r\n * ```\r\n */\r\n initialCommandsToAdd: Array<{ command: ICommand; commandType: CommandType }>;\r\n};\r\n\r\n/**\r\n * Defines the configuration parameters for creating a `ChatMock` instance.\r\n *\r\n * This object allows for detailed customization of the simulated chat\r\n * environment, including sender details, bot settings, and message context.\r\n */\r\nexport type MockingChatParams = {\r\n /**\r\n * Overrides for the `ChatContext` configuration, such as timeouts and\r\n * feedback messages. `cancelKeywords` is handled separately.\r\n */\r\n chatContextConfig?: Omit<Partial<IChatContextConfig>, \"cancelKeywords\">;\r\n /**\r\n * Overrides for the bot's settings (`WhatsBotOptions`), allowing customization\r\n * of prefixes, logging, and other bot behaviors for the test. Also includes\r\n * mock-specific options via `AdditionalWhatsBotOptions`.\r\n */\r\n botSettings?: Omit<Partial<WhatsBotOptions>, \"cancelKeywords\"> & Partial<AdditionalWhatsBotOptions>;\r\n /**\r\n * The simulated chat ID. If not provided, a default is generated.\r\n * The suffix (`@g.us` or `@s.whatsapp.net`) is automatically handled based on `senderType`.\r\n */\r\n chatId?: string;\r\n /**\r\n * The LID (Legacy ID) of the simulated message sender.\r\n * If provided, the `senderType` will default to `Group`.\r\n */\r\n participantId_LID?: string | null;\r\n /**\r\n * The PN (Phone Number ID) of the simulated message sender.\r\n * If provided, the `senderType` will default to `Group`.\r\n */\r\n participantId_PN?: string | null;\r\n /**\r\n * An array of strings representing the arguments passed to the command,\r\n * as if they were typed by the user after the command name.\r\n */\r\n args?: string[];\r\n /**\r\n * The type of the initial (command-triggering) message.\r\n * @default MsgType.Text\r\n */\r\n msgType?: MsgType;\r\n /**\r\n * The type of chat context to simulate.\r\n * - `SenderType.Individual`: A private one-on-one chat.\r\n * - `SenderType.Group`: A group chat.\r\n * @default SenderType.Individual (unless a participantId is provided)\r\n */\r\n senderType?: SenderType;\r\n /**\r\n * A list of keywords that will trigger a cancellation error when the\r\n * command is waiting for a user response.\r\n */\r\n cancelKeywords?: string[];\r\n};\r\n\r\nexport type MockEnqueueParamsMinimal = { pushName?: string; delayMilisecondsToReponse?: number };\r\n\r\nexport type MockEnqueueParamsMultimediaMinimal = MockEnqueueParamsMinimal & { imgContentBufferMock?: Buffer | Buffer<ArrayBuffer> };\r\nexport type MockEnqueueParamsMultimedia = MockEnqueueParamsMultimediaMinimal & { caption?: string };\r\nexport type MockEnqueueParamsDocument = MockEnqueueParamsMultimediaMinimal & { mimeType?: string };\r\nexport type MockEnqueueParamsLocation = MockEnqueueParamsMinimal & { locationName?: string; addressDescription?: string };\r\n\r\n/**\r\n * MockingChat is a helper utility designed to simulate a full WhatsApp chat session\r\n * against a given {@link ICommand}.\r\n *\r\n * It provides:\r\n * - Mocked **receiver**, **sender**, and **socket** modules for message flow control.\r\n * - Facilities to enqueue fake user messages (`SimulateTextSending`).\r\n * - Accessors to inspect messages that were sent/queued by the command under test.\r\n * - A fully configured {@link ChatContext} spy object for realistic command execution.\r\n *\r\n * Usage:\r\n * ```ts\r\n * const mock = new MockingChat(myCommand, { customParticipantId: \"12345\" });\r\n * mock.SimulateTextSending(\"hello\");\r\n * await mock.StartChatSimulation();\r\n * ```\r\n */\r\nexport default class ChatMock {\r\n public readonly ParticipantId_LID: string | null;\r\n public readonly ParticipantId_PN: string | null;\r\n public readonly ChatId: string;\r\n\r\n private readonly _senderType: SenderType;\r\n private _constructorConfig?: MockingChatParams;\r\n private _chatContextMock: ChatContext_MockingSuite;\r\n private _command: ICommand;\r\n private _receiverMock: WhatsSocket_Submodule_Receiver_MockingSuite;\r\n private _sugarSenderMock: WhatsSocket_Submodule_SugarSender_MockingSuite;\r\n private _socketMock: WhatsSocketMock;\r\n\r\n /**\r\n * All messages \"waited\" (consumed) from the mocked receiver.\r\n * Useful to check what input the command attempted to consume.\r\n */\r\n public get WaitedFromCommand(): WhatsSocketReceiverMsgWaited[] {\r\n return this._receiverMock.Waited;\r\n }\r\n\r\n /**\r\n * All messages sent via the sugar-sender mock.\r\n * These are usually text responses triggered by the command logic.\r\n */\r\n public get SentFromCommand() {\r\n return {\r\n //From whatssocket_receiver\r\n Texts: this._sugarSenderMock.SentMessages_Texts,\r\n Images: this._sugarSenderMock.SentMessages_Imgs,\r\n ReactedEmojis: this._sugarSenderMock.SentMessages_ReactedEmojis,\r\n Stickers: this._sugarSenderMock.SentMessages_Stickers,\r\n Audios: this._sugarSenderMock.SentMessages_Audios,\r\n Videos: this._sugarSenderMock.SentMessages_Videos,\r\n Documents: this._sugarSenderMock.SentMessages_Documents,\r\n Polls: this._sugarSenderMock.SentMessages_Polls,\r\n Locations: this._sugarSenderMock.SentMessages_Locations,\r\n Contacts: this._sugarSenderMock.SentMessages_Contacts,\r\n };\r\n }\r\n\r\n /**\r\n * Messages that were sent **through the queue** using the mocked socket.\r\n * This simulates queued delivery (e.g., internal socket enqueuing).\r\n */\r\n public get SentFromCommandSocketQueue(): WhatsSocketMockMsgSent[] {\r\n return this._socketMock.SentMessagesThroughQueue;\r\n }\r\n\r\n /**\r\n * Messages that were sent **directly without queueing** using the mocked socket.\r\n * This simulates \"raw\" delivery. ()\r\n */\r\n public get SentFromCommandSocketWithoutQueue(): WhatsSocketMockMsgSent[] {\r\n return this._socketMock.SentMessagesThroughRaw;\r\n }\r\n\r\n /**\r\n * Creates a new mock chat simulation environment for a given command.\r\n *\r\n * @param commandToTest - The {@link ICommand} instance to test.\r\n * @param additionalOptions - Optional parameters that customize chat setup,\r\n * such as `customChatId`, `customParticipantId`, `args`, or `senderType`.\r\n *\r\n * Behavior:\r\n * - If `customParticipantId` is provided, a group chat ID is assumed unless overridden.\r\n * - Otherwise, defaults to a private one-to-one chat.\r\n * - Automatically ensures correct WhatsApp LID suffixes for IDs.\r\n */\r\n constructor(commandToTest: ICommand, additionalOptions?: MockingChatParams) {\r\n this._constructorConfig = additionalOptions;\r\n this._command = commandToTest;\r\n\r\n // const senderTypeToMock: SenderType = additionalOptions?.senderType ?? SenderType.Individual;\r\n const senderTypeToMock: SenderType = additionalOptions?.senderType ?? SenderType.Individual;\r\n this._senderType = senderTypeToMock;\r\n const { chatIdResolved, updatedSenderType: resolveChatIdFoundSenderType } = Constructor_ResolveChatID(additionalOptions?.chatId, this._senderType);\r\n this.ChatId = chatIdResolved;\r\n if (resolveChatIdFoundSenderType) this._senderType = resolveChatIdFoundSenderType;\r\n\r\n const {\r\n LID,\r\n PN,\r\n senderTypeUpdated: resolveParticipantsFoundSenderType,\r\n } = Constructor_ResolveParticipantIds(additionalOptions?.participantId_LID, additionalOptions?.participantId_PN, this._senderType);\r\n if (resolveParticipantsFoundSenderType) this._senderType = resolveParticipantsFoundSenderType;\r\n\r\n this.ParticipantId_LID = LID;\r\n this.ParticipantId_PN = PN;\r\n if (additionalOptions?.senderType) this._senderType = additionalOptions?.senderType;\r\n\r\n const chatContextConfig: IChatContextConfig = {\r\n cancelKeywords: this._constructorConfig?.cancelKeywords ?? [\"cancel\"],\r\n ignoreSelfMessages: this._constructorConfig?.chatContextConfig?.ignoreSelfMessages ?? true,\r\n timeoutSeconds: this._constructorConfig?.chatContextConfig?.timeoutSeconds ?? 15,\r\n cancelFeedbackMsg:\r\n this._constructorConfig?.chatContextConfig?.cancelFeedbackMsg ?? \"Default cancel message mocking, user has canceled this command with a cancel word\",\r\n wrongTypeFeedbackMsg:\r\n this._constructorConfig?.chatContextConfig?.wrongTypeFeedbackMsg ??\r\n \"Default wrong expected type message, user has sent a msg which doesn't correspond to expected WaitMsg from command...\",\r\n explicitSenderType: this._senderType,\r\n };\r\n this._receiverMock = new WhatsSocket_Submodule_Receiver_MockingSuite();\r\n this._sugarSenderMock = new WhatsSocket_Submodule_SugarSender_MockingSuite();\r\n this._socketMock = new WhatsSocketMock({ customReceiver: this._receiverMock, customSugarSender: this._sugarSenderMock });\r\n const chatContext = new ChatContext_MockingSuite(\r\n this.ParticipantId_LID,\r\n this.ParticipantId_PN,\r\n this.ChatId,\r\n MsgFactory_Text(this.ChatId, this.ParticipantId_LID, `!${this._command.name}`, { pushName: \"ChatMock User\" }),\r\n this._sugarSenderMock,\r\n this._receiverMock,\r\n chatContextConfig\r\n );\r\n this._chatContextMock = chatContext;\r\n }\r\n\r\n /**\r\n * Simulates the sending of a text message into the mocked chat.\r\n * This enqueues the message into the mocked receiver, making it\r\n * available for the command to \"consume\" during execution.\r\n *\r\n * @param textToEnqueue - The message content to simulate.\r\n * @param options - Allows overriding the sender pushName (WhatsApp display name).\r\n */\r\n @autobind\r\n public EnqueueIncoming_Text(textToEnqueue: string, options?: MockEnqueueParamsMinimal): void {\r\n const txtMsg: WhatsappMessage = MsgFactory_Text(this.ChatId, this.ParticipantId_LID, textToEnqueue, {\r\n pushName: options?.pushName,\r\n });\r\n this._receiverMock.AddWaitMsg({ rawMsg: txtMsg, milisecondsDelayToRespondMock: options?.delayMilisecondsToReponse });\r\n }\r\n\r\n /**\r\n * Simulates an incoming image message, enqueuing it for the command under test to consume.\r\n *\r\n * ### Overloads\r\n * This method provides two convenient overloads for simulating image messages:\r\n *\r\n * 1. **`EnqueueIncoming_Img(imgUrl: string, opts?: MockEnqueueParamsMultimedia)`**\r\n * - Simulates an image from a specific URL or file path.\r\n * - Use the `opts` parameter to add a `caption`, `pushName`, or mock the download buffer.\r\n *\r\n * 2. **`EnqueueIncoming_Img(opts?: MockEnqueueParamsMultimedia)`**\r\n * - Simulates a generic, default placeholder image (`./whatsbotcord-mock-img.png`).\r\n * - This is useful when the specific image content is not important for the test.\r\n * - Can be called with no arguments.\r\n *\r\n * ### Multimedia Mocking\r\n * The `bufferToReturnOn_WaitMultimedia` option allows you to specify a `Buffer` that `ctx.WaitMultimedia()`\r\n * will resolve with. This is essential for testing multimedia handling logic without performing\r\n * actual downloads.\r\n *\r\n * @example\r\n * ```ts\r\n * // Overload 1: Simulate an image from a URL with a caption.\r\n * mock.EnqueueIncoming_Img(\"http://example.com/image.jpg\", { caption: \"Look at this!\" });\r\n *\r\n * // Overload 2: Simulate a default image with a custom sender name.\r\n * mock.EnqueueIncoming_Img({ pushName: \"Another User\" });\r\n *\r\n * // Or just... to simulate a generic img coming from user.\r\n * mock.EnqueueIncoming_Img();\r\n * ```\r\n */\r\n public EnqueueIncoming_Img(opts?: MockEnqueueParamsMultimedia): void;\r\n public EnqueueIncoming_Img(imgUrl: string, opts?: MockEnqueueParamsMultimedia): void;\r\n @autobind\r\n public EnqueueIncoming_Img(imgUrl_or_Opts?: MockEnqueueParamsMultimedia | string, onlyOpts?: MockEnqueueParamsMultimedia): void {\r\n // 1st Overload: public EnqueueIncoming_Img(opts?:MockEnqueueParamsMultimedia): void;\r\n if ((typeof imgUrl_or_Opts === \"undefined\" && typeof onlyOpts === \"undefined\") || typeof imgUrl_or_Opts === \"object\") {\r\n const imgMsg: WhatsappMessage = MsgFactory_Image(this.ChatId, this.ParticipantId_LID, \"./whatsbotcord-mock-img.png\", {\r\n caption: imgUrl_or_Opts?.caption,\r\n pushName: imgUrl_or_Opts?.pushName,\r\n });\r\n if (imgUrl_or_Opts?.imgContentBufferMock) {\r\n this._chatContextMock.EnqueueMediaBufferToReturn(imgUrl_or_Opts.imgContentBufferMock);\r\n }\r\n this._receiverMock.AddWaitMsg({ rawMsg: imgMsg, milisecondsDelayToRespondMock: imgUrl_or_Opts?.delayMilisecondsToReponse });\r\n return;\r\n }\r\n\r\n // 2nd Overload: public EnqueueIncoming_Img(imgUrl: string, opts?: MockEnqueueParamsMultimedia): void ;\r\n if (typeof imgUrl_or_Opts === \"string\") {\r\n const imgMsg: WhatsappMessage = MsgFactory_Image(this.ChatId, this.ParticipantId_LID, imgUrl_or_Opts, {\r\n caption: onlyOpts?.caption,\r\n pushName: onlyOpts?.pushName,\r\n });\r\n if (onlyOpts?.imgContentBufferMock) {\r\n this._chatContextMock.EnqueueMediaBufferToReturn(onlyOpts.imgContentBufferMock);\r\n }\r\n this._receiverMock.AddWaitMsg({ rawMsg: imgMsg, milisecondsDelayToRespondMock: onlyOpts?.delayMilisecondsToReponse });\r\n return;\r\n }\r\n }\r\n\r\n /**\r\n * Simulates the sending of a sticker message into the mocked chat.\r\n * Enqueues the message into the mocked receiver for the command to\r\n * consume.\r\n *\r\n * If a `bufferToReturnOnWaitMultimedia` is set, that buffer will be\r\n * returned during multimedia waits instead of performing a real\r\n * download.\r\n *\r\n * @param urlSticker - URL of the sticker file (usually `.webp`).\r\n * @param opts - Optional parameters like pushName and a mock buffer.\r\n */\r\n @autobind\r\n public EnqueueIncoming_Sticker(urlSticker: string, opts?: MockEnqueueParamsMultimediaMinimal): void {\r\n const stickerMsg: WhatsappMessage = MsgFactory_Sticker(this.ChatId, this.ParticipantId_LID, urlSticker, {\r\n pushName: opts?.pushName,\r\n });\r\n if (opts?.imgContentBufferMock) {\r\n this._chatContextMock.EnqueueMediaBufferToReturn(opts.imgContentBufferMock);\r\n }\r\n this._receiverMock.AddWaitMsg({ rawMsg: stickerMsg, milisecondsDelayToRespondMock: opts?.delayMilisecondsToReponse });\r\n }\r\n\r\n /**\r\n * Simulates the sending of an audio message into the mocked chat.\r\n * The message is added to the mocked receiver queue.\r\n *\r\n * If a mock buffer is provided, it will be used when awaiting\r\n * multimedia content via {@link WaitMultimedia}.\r\n *\r\n * @param urlaudio - URL of the audio file to simulate.\r\n * @param opts - Optional pushName and buffer override.\r\n */\r\n @autobind\r\n public EnqueueIncoming_Audio(urlaudio: string, opts?: MockEnqueueParamsMultimediaMinimal): void {\r\n const audioMsg: WhatsappMessage = MsgFactory_Audio(this.ChatId, this.ParticipantId_LID, urlaudio, {\r\n pushName: opts?.pushName,\r\n });\r\n if (opts?.imgContentBufferMock) {\r\n this._chatContextMock.EnqueueMediaBufferToReturn(opts.imgContentBufferMock);\r\n }\r\n this._receiverMock.AddWaitMsg({ rawMsg: audioMsg, milisecondsDelayToRespondMock: opts?.delayMilisecondsToReponse });\r\n }\r\n\r\n /**\r\n * Simulates the sending of a video message into the mocked chat.\r\n * This includes optional captions and sender details.\r\n *\r\n * If a buffer override is specified, it will be used during multimedia\r\n * waits instead of fetching from the URL.\r\n *\r\n * @param urlVideo - URL of the video file to simulate.\r\n * @param opts - Optional parameters (caption, pushName, buffer).\r\n */\r\n @autobind\r\n public EnqueueIncoming_Video(urlVideo: string, opts?: MockEnqueueParamsMultimedia): void {\r\n const videoMsg: WhatsappMessage = MsgFactory_Video(this.ChatId, this.ParticipantId_LID, urlVideo, {\r\n caption: opts?.caption,\r\n pushName: opts?.pushName,\r\n });\r\n if (opts?.imgContentBufferMock) {\r\n this._chatContextMock.EnqueueMediaBufferToReturn(opts.imgContentBufferMock);\r\n }\r\n this._receiverMock.AddWaitMsg({ rawMsg: videoMsg, milisecondsDelayToRespondMock: opts?.delayMilisecondsToReponse });\r\n }\r\n\r\n /**\r\n * Simulates the sending of a document message into the mocked chat.\r\n * Enqueues the message with proper filename and mimetype resolution.\r\n *\r\n * A mock buffer can be attached to override multimedia waits for this\r\n * document.\r\n *\r\n * @param urlDocument - URL of the document to simulate.\r\n * @param fileName - Filename to associate with the document.\r\n * @param opts - Optional mimetype, pushName, and buffer override.\r\n */\r\n @autobind\r\n public EnqueueIncoming_Document(urlDocument: string, fileName: string, opts?: MockEnqueueParamsDocument): void {\r\n const documentMsg: WhatsappMessage = MsgFactory_Document(this.ChatId, this.ParticipantId_LID, urlDocument, {\r\n fileName: fileName,\r\n mimetype: opts?.mimeType ?? mime.getType(path.extname(fileName)) ?? \"application/pdf\",\r\n pushName: opts?.pushName,\r\n });\r\n if (opts?.imgContentBufferMock) {\r\n this._chatContextMock.EnqueueMediaBufferToReturn(opts.imgContentBufferMock);\r\n }\r\n this._receiverMock.AddWaitMsg({ rawMsg: documentMsg, milisecondsDelayToRespondMock: opts?.delayMilisecondsToReponse });\r\n }\r\n\r\n /**\r\n * Simulates the sending of a location message into the mocked chat.\r\n * The message includes geographic coordinates and optional descriptive\r\n * fields like name and address.\r\n *\r\n * @param latitude - Latitude of the location.\r\n * @param longitude - Longitude of the location.\r\n * @param opts - Optional location name, address description, and pushName.\r\n */\r\n @autobind\r\n public EnqueueIncoming_Location(latitude: number, longitude: number, opts?: MockEnqueueParamsLocation): void {\r\n const locationMsg: WhatsappMessage = MsgFactory_Location(this.ChatId, this.ParticipantId_LID, latitude, longitude, {\r\n pushName: opts?.pushName,\r\n address: opts?.addressDescription,\r\n name: opts?.locationName,\r\n });\r\n this._receiverMock.AddWaitMsg({ rawMsg: locationMsg, milisecondsDelayToRespondMock: opts?.delayMilisecondsToReponse });\r\n }\r\n\r\n /**\r\n * Simulates the contact(s) sending mdg into the mocked chat.\r\n * The messaged include all contact or contacts with all mocked\r\n * environment metadata included.\r\n *\r\n * @param contact_s - Contact or contacts array\r\n * @param opts - Optional config obj: Actually including only 'pushName' prop\r\n */\r\n @autobind\r\n public EnqueueIncoming_Contact(contact_s: { name: string; phone: string } | Array<{ name: string; phone: string }>, opts?: MockEnqueueParamsMinimal): void {\r\n const contactMsg = MsgFactory_Contact(this.ChatId, this.ParticipantId_LID, contact_s, {\r\n pushName: opts?.pushName,\r\n });\r\n this._receiverMock.AddWaitMsg({ rawMsg: contactMsg, milisecondsDelayToRespondMock: opts?.delayMilisecondsToReponse });\r\n }\r\n\r\n /**\r\n * Starts the simulation by executing the command under test with the mocked context\r\n * and sending all queued msgs with this class EnqueueIncoming*() methods.\r\n *\r\n * Use it to start your test with your command\r\n *\r\n * This method:\r\n * - Creates a fake invocation of the command (`!commandName`).\r\n * - Injects mocked sender/receiver/socket modules into the execution context.\r\n * - Runs the command's `run` method as if in a real bot environment.\r\n */\r\n @autobind\r\n public async StartChatSimulation(): Promise<void> {\r\n // const receiver: WhatsSocket_Submodule_Receiver = new WhatsSocket_Submodule_Receiver();\r\n //Need to conver\r\n const botCommandsSearcher = new CommandsSearcher();\r\n\r\n if (this._constructorConfig?.botSettings?.initialCommandsToAdd) {\r\n for (const entry of this._constructorConfig.botSettings.initialCommandsToAdd) {\r\n if (entry.commandType === CommandType.Normal) {\r\n botCommandsSearcher.Add(entry.command, CommandType.Normal);\r\n }\r\n if (entry.commandType === CommandType.Tag) {\r\n botCommandsSearcher.Add(entry.command, CommandType.Tag);\r\n }\r\n }\r\n }\r\n\r\n const botSettings = BotUtils_GenerateOptions({ ...this._constructorConfig?.botSettings, cancelKeywords: this._chatContextMock.Config.cancelKeywords });\r\n try {\r\n await this._command.run(\r\n this._chatContextMock,\r\n {\r\n InternalSocket: this._socketMock,\r\n Myself: {\r\n Status: new Myself_Submodule_Status(this._socketMock),\r\n Bot: {\r\n Commands: botCommandsSearcher,\r\n Settings: botSettings,\r\n },\r\n },\r\n },\r\n {\r\n args: this._constructorConfig?.args ?? [],\r\n botInfo: {\r\n Commands: botCommandsSearcher,\r\n Settings: botSettings,\r\n },\r\n chatId: this.ChatId,\r\n participantIdPN: this.ParticipantId_PN,\r\n participantIdLID: this.ParticipantId_LID,\r\n msgType: this._constructorConfig?.msgType ?? MsgType.Text,\r\n originalRawMsg: {} as any,\r\n quotedMsgInfo: {} as any,\r\n senderType: this._senderType,\r\n }\r\n );\r\n } catch (error) {\r\n if (error instanceof Error) {\r\n if (\r\n error.message === \"ChatContext is trying to wait a msg that will never arrives!... Use MockChat.EnqueueIncoming_****() to enqueue what to return!\"\r\n ) {\r\n if (this.SentFromCommand.Texts.length > 0) {\r\n const lastMessage = this.SentFromCommand.Texts.at(-1)!.text;\r\n throw new Error(\r\n \"\\n\\n\\n[Whatsbotcord | MockChat Test Error: Deadlock]\\n\\n\" +\r\n \"The command is waiting for a user reply, but the mock's incoming message queue is empty.\\n\\n\" +\r\n \"Last Message Sent by Command:\\n\" +\r\n `\"${lastMessage}\"\\n\\n` +\r\n \"How to Fix:\\n\" +\r\n \"Use MockChat.EnqueueIncoming_...() in your test setup to provide the message the command is waiting for.\\n\\n\\n\"\r\n );\r\n }\r\n }\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Overrides the group metadata used in this mocked chat environment.\r\n * This is useful for simulating different group states (e.g., id,\r\n * subject, participants) without relying on real WhatsApp server data.\r\n *\r\n * Behavior:\r\n * - Ensures the `id` field has the correct suffix depending on whether\r\n * the current sender type is group or individual.\r\n * - Updates the `ChatId` internally and applies the metadata to the\r\n * receiver and socket mocks.\r\n *\r\n * @param metadata - Partial group metadata to inject into the mock\r\n * environment. If `id` is provided, it will be normalized.\r\n */\r\n @autobind\r\n public SetGroupMetadataMock(metadata: Partial<GroupMetadataInfo>) {\r\n const actualSenderType = this._constructorConfig?.senderType ?? (this.ParticipantId_LID ? SenderType.Group : SenderType.Individual);\r\n if (metadata.id) {\r\n let newChatId: string;\r\n if (actualSenderType === SenderType.Group) {\r\n if (!metadata.id.endsWith(WhatsappGroupIdentifier)) {\r\n newChatId = metadata.id + WhatsappGroupIdentifier;\r\n } else {\r\n newChatId = metadata.id;\r\n }\r\n } else {\r\n if (!metadata.id.endsWith(WhatsappPhoneNumberIdentifier)) {\r\n newChatId = metadata.id + WhatsappPhoneNumberIdentifier;\r\n } else {\r\n newChatId = metadata.id;\r\n }\r\n }\r\n //@ts-expect-error just let this private access to exists.. hehehehehe\r\n this.ChatId = newChatId;\r\n }\r\n //@ts-expect-error just a little fix... jejeje\r\n this._chatContextMock[\"FixedChatId\"] = this.ChatId;\r\n this._receiverMock.SetGroupMetadataMock({ ...metadata, id: this.ChatId });\r\n //With mocksocket, do not modify it, its always group\r\n this._socketMock.SetGroupMetadataMock(metadata);\r\n }\r\n\r\n /**\r\n * Resets the entire mocking environment back to its initial state.\r\n * This clears:\r\n * - Receiver mock state\r\n * - Sugar sender mock state\r\n * - Socket mock state\r\n * - Chat context mock state\r\n *\r\n * Use this before or after each test to ensure isolation between cases.\r\n */\r\n @autobind\r\n public ClearMocks(): void {\r\n this._receiverMock.ClearMocks();\r\n this._sugarSenderMock.ClearMocks();\r\n this._socketMock.ClearMock();\r\n this._chatContextMock.ClearMocks();\r\n }\r\n\r\n /**\r\n * Configure the buffer that will be returned in place of a real\r\n * downloaded multimedia message when using \"ctx.WaitMultimedia(...)\".\r\n *\r\n * @param anyBuffer - The buffer to return on next `WaitMultimedia` calls.\r\n */\r\n @autobind\r\n public SetWaitMsgBufferToReturnMock(anyBuffer: Buffer) {\r\n this._chatContextMock.EnqueueMediaBufferToReturn(anyBuffer);\r\n }\r\n}\r\n\r\n//Constructor:\r\n/**\r\n * If SenderType.Group case\r\n * If SenderType.Individual case\r\n *\r\n * If provided ChatId:string\r\n * If provided ParticipantId_LID: string\r\n * If provided ParticipantId_PN: string\r\n */\r\n\r\nfunction Constructor_ResolveChatID(chatId?: string, senderType?: SenderType): { chatIdResolved: string; updatedSenderType?: SenderType } {\r\n //Default case if nothing provide, returns by default individual chat id (private chat);\r\n const defaultIndividualChatId = \"fakeUserChatPrivate\" + WhatsappGroupIdentifier;\r\n\r\n if (senderType) {\r\n if (senderType === SenderType.Group) {\r\n if (!chatId) {\r\n return { chatIdResolved: \"fakeChatId\" + WhatsappGroupIdentifier };\r\n }\r\n if (chatId.endsWith(WhatsappGroupIdentifier)) {\r\n return { chatIdResolved: chatId }; //Its correct already!\r\n } else {\r\n return { chatIdResolved: chatId + WhatsappGroupIdentifier }; //Let's fix it\r\n }\r\n }\r\n\r\n if (senderType === SenderType.Individual) {\r\n if (!chatId) {\r\n return { chatIdResolved: defaultIndividualChatId };\r\n }\r\n if (chatId.endsWith(WhatsappPhoneNumberIdentifier)) {\r\n return { chatIdResolved: chatId };\r\n } else {\r\n return { chatIdResolved: chatId + WhatsappPhoneNumberIdentifier };\r\n }\r\n }\r\n } else if (chatId) {\r\n if (chatId.endsWith(WhatsappGroupIdentifier)) {\r\n return { chatIdResolved: chatId, updatedSenderType: SenderType.Group }; //Its correct already!\r\n } else if (chatId.endsWith(WhatsappPhoneNumberIdentifier)) {\r\n return { chatIdResolved: chatId + WhatsappPhoneNumberIdentifier, updatedSenderType: SenderType.Individual }; //Let's fix it\r\n }\r\n }\r\n\r\n //If, for some reason, it reaches here, return default case again.\r\n return { chatIdResolved: defaultIndividualChatId };\r\n}\r\n\r\nfunction Constructor_ResolveParticipantIds(\r\n participantId_LID?: string | null,\r\n participantId_PN?: string | null,\r\n senderType?: SenderType\r\n): { LID: string | null; PN: string | null; senderTypeUpdated: SenderType | null } {\r\n const defaultLID: string = \"fakeParticipnatID\" + WhatsappLIDIdentifier;\r\n const defaultPN: string = \"fakeParticipantID\" + WhatsappPhoneNumberIdentifier;\r\n\r\n if (!participantId_LID && !participantId_PN && senderType === SenderType.Individual) {\r\n return { LID: null, PN: null, senderTypeUpdated: null };\r\n }\r\n\r\n let LID_ToReturn: string | null; // participant_LID => Could be (string | undefined | null)\r\n if (typeof participantId_LID === \"string\") {\r\n if (participantId_LID.endsWith(WhatsappLIDIdentifier)) {\r\n LID_ToReturn = participantId_LID; //Its ok, nothing to fix\r\n } else {\r\n LID_ToReturn = participantId_LID + WhatsappLIDIdentifier; //Let's fix it\r\n }\r\n } else if (participantId_LID === null) {\r\n LID_ToReturn = null;\r\n } else {\r\n //Is undefined\r\n LID_ToReturn = defaultLID;\r\n }\r\n\r\n let PN_ToReturn: string | null; // participant_PN => Could be (string | undefined | null)\r\n if (typeof participantId_PN === \"string\") {\r\n if (participantId_PN.endsWith(WhatsappPhoneNumberIdentifier)) {\r\n PN_ToReturn = participantId_PN; //Its ok, nothing to fix\r\n } else {\r\n PN_ToReturn = participantId_PN + WhatsappPhoneNumberIdentifier; //Let's fix it\r\n }\r\n } else if (participantId_PN === null) {\r\n PN_ToReturn = null;\r\n } else {\r\n //Is undefined then\r\n PN_ToReturn = defaultPN;\r\n }\r\n\r\n return { LID: LID_ToReturn, PN: PN_ToReturn, senderTypeUpdated: SenderType.Group };\r\n}\r\n\r\n// \"fakeChatIdGroup\" + WhatsappGroupIdentifier;\r\n// \"fakeUserChatPrivate\" + WhatsappIndividualIdentifier;\r\n","import Whatsbotcord from \"./core/bot/bot.js\";\r\nimport {\r\n MsgHelper_FullMsg_GetMsgType,\r\n MsgHelper_FullMsg_GetQuotedMsg,\r\n MsgHelper_FullMsg_GetQuotedMsgText,\r\n MsgHelper_FullMsg_GetSenderType,\r\n MsgHelper_FullMsg_GetText,\r\n MsgHelper_ProtoMsg_GetMsgType,\r\n MsgHelper_QuotedMsg_GetText,\r\n} from \"./helpers/Msg.helper.js\";\r\nimport {\r\n WhatsappHelper_ExtractFromWhatsappID,\r\n WhatsappHelper_ExtractWhatsappInfoFromMention,\r\n WhatsappHelper_ExtractWhatsappInfoInfoFromSenderRawMsg,\r\n WhatsappHelper_isFullWhatsappIdUser,\r\n WhatsappHelper_isLIDIdentifier,\r\n WhatsappHelper_isMentionId,\r\n} from \"./helpers/Whatsapp.helper.js\";\r\n\r\n// === Types deps exporting ===\r\nimport type { WhatsbotcordMiddlewareFunct } from \"./core/bot/bot.js\";\r\nimport type { IChatContextConfig } from \"./core/bot/internals/ChatContext.js\";\r\nimport type { CommandEntry } from \"./core/bot/internals/CommandsSearcher.js\";\r\nimport type { CommandArgs } from \"./core/bot/internals/CommandsSearcher.types.js\";\r\nimport type { IChatContext } from \"./core/bot/internals/IChatContext.js\";\r\nimport type { AdditionalAPI, ICommand } from \"./core/bot/internals/ICommand.js\";\r\nimport type {\r\n OfficialPlugin_OneCommandPerUserAtATime_Config,\r\n OfficialPlugin_OneCommandPerUserAtATime_ContextInfo,\r\n} from \"./core/official_plugins/OneCommandPerUser_Plugin.js\";\r\nimport type { IWhatsSocket_Submodule_Receiver } from \"./core/whats_socket/internals/IWhatsSocket.receiver.js\";\r\nimport type { IWhatsSocket_Submodule_SugarSender } from \"./core/whats_socket/internals/IWhatsSocket.sugarsender.js\";\r\nimport type { WhatsSocketReceiverError } from \"./core/whats_socket/internals/WhatsSocket.receiver.js\";\r\nimport type { IMsgServiceSocketMinimum, IWhatsSocket, IWhatsSocket_EventsOnly_Module } from \"./core/whats_socket/IWhatsSocket.js\";\r\nimport type { WhatsappMessage } from \"./core/whats_socket/types.js\";\r\nimport type { WhatsappIDInfo } from \"./helpers/Whatsapp.helper.js\";\r\nimport type {\r\n MockEnqueueParamsDocument,\r\n MockEnqueueParamsLocation,\r\n MockEnqueueParamsMinimal,\r\n MockEnqueueParamsMultimedia,\r\n MockEnqueueParamsMultimediaMinimal,\r\n MockingChatParams,\r\n} from \"./mocking_suite/ChatMock.js\";\r\nimport type { GroupMetadataInfo } from \"./core/whats_socket/internals/WhatsSocket.receiver.js\";\r\nexport type {\r\n AdditionalAPI,\r\n GroupMetadataInfo,\r\n IChatContextConfig as ChatContextConfig,\r\n CommandArgs,\r\n CommandEntry,\r\n IChatContext,\r\n ICommand,\r\n IMsgServiceSocketMinimum,\r\n IWhatsSocket,\r\n IWhatsSocket_EventsOnly_Module,\r\n IWhatsSocket_Submodule_Receiver,\r\n IWhatsSocket_Submodule_SugarSender,\r\n MockEnqueueParamsDocument,\r\n MockEnqueueParamsLocation,\r\n MockEnqueueParamsMinimal,\r\n MockEnqueueParamsMultimedia,\r\n MockEnqueueParamsMultimediaMinimal,\r\n MockingChatParams,\r\n OfficialPlugin_OneCommandPerUserAtATime_Config,\r\n OfficialPlugin_OneCommandPerUserAtATime_ContextInfo,\r\n WhatsappIDInfo,\r\n WhatsappMessage,\r\n WhatsbotcordMiddlewareFunct,\r\n WhatsSocketReceiverError,\r\n};\r\n\r\n// == Runtime deps exporting ==\r\nimport Bot from \"./core/bot/bot.js\";\r\nimport { ChatContext } from \"./core/bot/internals/ChatContext.js\";\r\nimport { CommandType } from \"./core/bot/internals/CommandsSearcher.js\";\r\nimport OfficialPlugin_OneCommandPerUserAtATime from \"./core/official_plugins/OneCommandPerUser_Plugin.js\";\r\nimport { WhatsSocketReceiverHelper_isReceiverError, WhatsSocketReceiverMsgError } from \"./core/whats_socket/internals/WhatsSocket.receiver.js\";\r\nimport WhatsSocket from \"./core/whats_socket/WhatsSocket.js\";\r\nimport { Debug_StoreWhatsMsgHistoryInJson } from \"./Debugging.helper.js\";\r\nimport CreateCommand from \"./helpers/CommandForJs.helper.js\";\r\nimport { WhatsappIdType } from \"./helpers/Whatsapp.helper.js\";\r\nimport Delegate from \"./libs/Delegate.js\";\r\nimport ChatMock from \"./mocking_suite/ChatMock.js\";\r\nimport { MsgType, SenderType } from \"./Msg.types.js\";\r\nimport { WhatsappGroupIdentifier, WhatsappLIDIdentifier, WhatsappPhoneNumberIdentifier } from \"./Whatsapp.types.js\";\r\nexport {\r\n ChatContext,\r\n ChatMock,\r\n CommandType,\r\n CreateCommand,\r\n Delegate,\r\n MsgType,\r\n OfficialPlugin_OneCommandPerUserAtATime,\r\n SenderType,\r\n WhatsappIdType,\r\n Bot as Whatsbotcord,\r\n WhatsSocket,\r\n WhatsSocketReceiverMsgError,\r\n};\r\n\r\n// === Helpers ===\r\n\r\n/**\r\n * # Whatsapp Identifiers Postfixes\r\n *\r\n * Object containing all common patterns identifiers from WhatsApp API and\r\n * WhatsApp messages. Keep this for reference in your logic.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isGroup = id.endsWith(Helpers.Whatsapp.IdentifiersPostfixes.Group_Suffix_ID);\r\n * ```\r\n * @deprecated Made for compatibility with versions prior 1.0.0. Import {Helpers} from \"whatsbotcord\", and use 'Helpers.Whatsapp.IdentifiersPostfixes' instead\r\n */\r\nexport const WhatsappIdentifiers = {\r\n /**\r\n * Identifier for group chats. Example: \"@g.us\"\r\n *\r\n * @note Just for reference\r\n */\r\n Group_Suffix_ID: WhatsappGroupIdentifier,\r\n /**\r\n * Identifer for local IDs. Example: \"@lid\"\r\n *\r\n * @note Just for reference\r\n */\r\n LID_Suffix_ID: WhatsappLIDIdentifier,\r\n /**\r\n * Identifier for individual user chats. Example: \"@s.whatsapp.net\"\r\n *\r\n * @note Just for reference\r\n */\r\n PhoneNumber_Suffix_ID: WhatsappPhoneNumberIdentifier,\r\n};\r\n\r\n/**\r\n * # WhatsApp Identifiers Helpers\r\n * Collection of helper functions for working with WhatsApp IDs and mentions.\r\n * Provides utilities to extract sender information, identify mentions,\r\n * and verify WhatsApp ID formats.\r\n *\r\n * @deprecated This exists only for compatibility with versions prior to 1.0.0.\r\n * Instead: import { Helpers } from \"whatsbotcord\" and use 'Helpers.Whatsapp'.\r\n */\r\nexport const WhatsappHelpers = {\r\n /**\r\n * ### Get Info From Sender Message\r\n * Extracts detailed ID information from a raw Baileys `WAMessage`.\r\n * It automatically determines if the ID is a LID or a standard PN.\r\n * @example\r\n * ```typescript\r\n * const info = WhatsappHelpers.GetWhatsInfoFromSenderMsg(rawMsg);\r\n * console.log(info.rawId); // \"1234567890@s.whatsapp.net\" or \"123456789012345@lid\"\r\n * ```\r\n */\r\n GetWhatsInfoFromSenderMsg: WhatsappHelper_ExtractWhatsappInfoInfoFromSenderRawMsg,\r\n\r\n /**\r\n * ### Get Info From WhatsApp ID\r\n * Parses a raw string ID (including the @ suffix) into a structured object.\r\n * @example\r\n * ```typescript\r\n * const info = WhatsappHelpers.GetWhatsInfoFromWhatsappID(\"5215551234567@s.whatsapp.net\");\r\n * console.log(info.asMentionFormatted); // \"@5215551234567\"\r\n * ```\r\n */\r\n GetWhatsInfoFromWhatsappID: WhatsappHelper_ExtractFromWhatsappID,\r\n\r\n /**\r\n * ### Get Info From Mention String\r\n * Converts a user-facing mention (starting with @) into a system-ready ID info object.\r\n * @example\r\n * ```typescript\r\n * const mention = WhatsappHelpers.GetWhatsInfoFromMentionStr(\"@5215551234567\");\r\n * if (mention) console.log(mention.rawId); // \"5215551234567@lid\"\r\n * ```\r\n */\r\n GetWhatsInfoFromMentionStr: WhatsappHelper_ExtractWhatsappInfoFromMention,\r\n\r\n /**\r\n * ### Is LID Identifier\r\n * Returns true if the ID follows the modern Linked Device Identifier format (`@lid`).\r\n * @example\r\n * ```typescript\r\n * const isLid = WhatsappHelpers.IsLIDId(\"123456789012345@lid\"); // true\r\n * ```\r\n */\r\n IsLIDId: WhatsappHelper_isLIDIdentifier,\r\n\r\n /**\r\n * ### Is Mention String\r\n * Checks if a string is a valid WhatsApp mention (starts with the `@` prefix).\r\n * @example\r\n * ```typescript\r\n * const isMention = WhatsappHelpers.IsMentionString(\"@5215558889900\"); // true\r\n * const isNotMention = WhatsappHelpers.IsMentionString(\"5215558889900\"); // false\r\n * ```\r\n */\r\n IsMentionString: WhatsappHelper_isMentionId,\r\n\r\n /**\r\n * ### Is PN ID\r\n * Checks if the ID is a standard Phone Number identifier (`@s.whatsapp.net`).\r\n * @example\r\n * ```typescript\r\n * const isLegacy = WhatsappHelpers.IsPNId(\"5211234567890@s.whatsapp.net\"); // true\r\n * ```\r\n */\r\n IsPNId: WhatsappHelper_isFullWhatsappIdUser,\r\n\r\n /**\r\n * ### Identifiers Postfixes\r\n * Access common WhatsApp ID suffixes (e.g., `@g.us`, `@s.whatsapp.net`, `@lid`).\r\n * @example\r\n * ```typescript\r\n * const isGroup = msg.key.remoteJid?.endsWith(WhatsappHelpers.IdentifiersPostfixes.Group_Suffix_ID);\r\n * ```\r\n */\r\n IdentifiersPostfixes: WhatsappIdentifiers,\r\n};\r\n\r\nexport const Helpers = {\r\n /**\r\n * # External Message Helpers\r\n *\r\n * Collection of helper functions for working with WhatsApp messages.\r\n * Provides convenience methods to extract text or determine message types\r\n * from raw WhatsappMessages.\r\n *\r\n * @example\r\n * ```typescript\r\n * const text = Helpers.Msg.FullMsg_GetText(rawMsg);\r\n * ```\r\n */\r\n Msg: {\r\n FullMsg_GetQuotedMsgText: MsgHelper_FullMsg_GetQuotedMsgText,\r\n FullMsg_GetMsgType: MsgHelper_FullMsg_GetMsgType,\r\n FullMsg_GetText: MsgHelper_FullMsg_GetText,\r\n FullMsg_GetQuotedMsgObj: MsgHelper_FullMsg_GetQuotedMsg,\r\n FullMsg_GetSenderType: MsgHelper_FullMsg_GetSenderType,\r\n QuotedMsg_GetText: MsgHelper_QuotedMsg_GetText,\r\n AnyMsg_GetMsgType: MsgHelper_ProtoMsg_GetMsgType,\r\n },\r\n /**\r\n * # WhatsApp Identifiers Helpers\r\n\r\n * Collection of helper functions for working with WhatsApp IDs and mentions.\r\n * Provides utilities to extract sender information, identify mentions,\r\n * and verify WhatsApp ID formats.\r\n\r\n * @example\r\n * ```typescript\r\n * const isPN = Helpers.Whatsapp.IsPNId(\"123@s.whatsapp.net\");\r\n * ```\r\n */\r\n Whatsapp: WhatsappHelpers,\r\n\r\n /**\r\n * # Debugging Utilities\r\n *\r\n * Useful collection of functions for debugging WhatsApp behavior locally.\r\n *\r\n * @example\r\n * ```typescript\r\n * Helpers.Debugging.StoreMsgInHistoryJson(rawMsg);\r\n * ```\r\n */\r\n Debugging: {\r\n StoreMsgInHistoryJson: Debug_StoreWhatsMsgHistoryInJson,\r\n },\r\n\r\n ChatContext_IsWaitError: WhatsSocketReceiverHelper_isReceiverError,\r\n};\r\n\r\n// === Main Default Export ===\r\nexport default Whatsbotcord;\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["path","path","emojiSplitter","GraphemeSplitter","fs","path","qr","DisconnectReason","GraphemeSplitter","fs","WAMessageAddressingMode","path","path","Whatsbotcord"],"sources":["../src/helpers/Decorators.helper.ts","../src/Msg.types.ts","../src/Whatsapp.types.ts","../src/helpers/Msg.helper.ts","../src/libs/Delegate.ts","../src/libs/MiddlewareChain.ts","../src/helpers/Whatsapp.helper.ts","../src/core/whats_socket/internals/WhatsSocket.receiver.ts","../src/libs/BunPath.ts","../src/core/whats_socket/internals/WhatsSocket.senderqueue.ts","../src/helpers/Mimetypes.helper.ts","../src/helpers/Strings.helper.ts","../src/core/whats_socket/internals/WhatsSocket.sugarsenders.ts","../src/core/whats_socket/WhatsSocket.ts","../src/core/bot/internals/ChatContext.ts","../src/core/bot/internals/ChatContext.myself.status.ts","../src/core/bot/internals/CommandsSearcher.ts","../src/core/bot/bot.ts","../src/core/official_plugins/OneCommandPerUser_Plugin.ts","../src/Debugging.helper.ts","../src/helpers/CommandForJs.helper.ts","../src/core/whats_socket/mocks/WhatsSocket.mock.ts","../src/mocking_suite/ChatContext.mockingsuite.ts","../src/mocking_suite/MsgsMockFactory.ts","../src/mocking_suite/WhatsSocket.receiver.mockingsuite.ts","../src/mocking_suite/WhatsSocket.sugarsender.mockingsuite.ts","../src/mocking_suite/ChatMock.ts","../src/index.ts"],"sourcesContent":["/**\r\n * # Autobind Decorator\r\n *\r\n * Method decorator that ensures the decorated function is always invoked\r\n * with its original class instance as `this`.\r\n *\r\n * Throws an error if applied to anything other than an instance method.\r\n *\r\n * @example\r\n * ```typescript\r\n * class MyClass {\r\n * @autobind\r\n * myMethod() { console.log(this); }\r\n * }\r\n * ```\r\n */\r\nexport function autobind(target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor {\r\n const originalMethod = descriptor.value;\r\n\r\n // Validate that the decorator is applied to a function\r\n if (typeof originalMethod !== \"function\") {\r\n throw new Error(`@autobind can only be applied to methods, not: ${propertyKey}`);\r\n }\r\n\r\n // Validate that the method is not static\r\n const isStatic = target.constructor === Function;\r\n if (isStatic) {\r\n throw new Error(`@autobind cannot be applied to static methods: ${propertyKey}`);\r\n }\r\n\r\n // Validate that the decorator is not applied to getters or setters\r\n if (descriptor.get || descriptor.set) {\r\n throw new Error(`@autobind cannot be applied to getters or setters: ${propertyKey}`);\r\n }\r\n\r\n return {\r\n configurable: true,\r\n enumerable: descriptor.enumerable,\r\n get() {\r\n // Bind the original method to the instance\r\n const bound = originalMethod.bind(this);\r\n\r\n // Define the property on the instance to allow reassignment\r\n Object.defineProperty(this, propertyKey, {\r\n value: bound,\r\n configurable: true, // Allow redefinition\r\n writable: true, // Allow reassignment\r\n enumerable: descriptor.enumerable,\r\n });\r\n\r\n return bound;\r\n },\r\n set(newValue: any) {\r\n // Allow the property to be reassigned (e.g., for mocking)\r\n Object.defineProperty(this, propertyKey, {\r\n value: newValue,\r\n configurable: true,\r\n writable: true,\r\n enumerable: descriptor.enumerable,\r\n });\r\n },\r\n };\r\n}\r\n","/**\r\n * # Message Type\r\n *\r\n * Enumeration mapping the type of the message received.\r\n *\r\n * @example\r\n * ```typescript\r\n * const type = MsgType.Text;\r\n * ```\r\n */\r\nexport enum MsgType {\r\n Text = 1,\r\n Image,\r\n Sticker,\r\n Video,\r\n Audio,\r\n Contact,\r\n Poll,\r\n Ubication,\r\n Document,\r\n Unknown,\r\n}\r\n\r\n/**\r\n * # Sender Type\r\n *\r\n * Enumeration mapping the type of sender that sent the message.\r\n *\r\n * @example\r\n * ```typescript\r\n * const type = SenderType.Individual;\r\n * ```\r\n */\r\nexport enum SenderType {\r\n Group = 1,\r\n Individual,\r\n Unknown,\r\n}\r\n","/**\r\n * # WhatsApp Group Identifier\r\n *\r\n * Suffix identifier used by WhatsApp for group chats.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isGroup = chatId.endsWith(WhatsappGroupIdentifier);\r\n * ```\r\n */\r\nexport const WhatsappGroupIdentifier: string = \"@g.us\";\r\n\r\n/**\r\n * # WhatsApp Phone Number Identifier\r\n *\r\n * Suffix identifier used by WhatsApp for individual phone numbers.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isIndividual = chatId.endsWith(WhatsappPhoneNumberIdentifier);\r\n * ```\r\n */\r\nexport const WhatsappPhoneNumberIdentifier: string = \"@s.whatsapp.net\";\r\n\r\n/**\r\n * # WhatsApp LID Identifier\r\n *\r\n * Suffix identifier used by WhatsApp for LID-normalized IDs.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isLID = chatId.endsWith(WhatsappLIDIdentifier);\r\n * ```\r\n */\r\nexport const WhatsappLIDIdentifier: string = \"@lid\";\r\n","import { type WAMessage, type proto } from \"baileys\";\r\nimport { MsgType, SenderType } from \"../Msg.types.js\";\r\nimport { WhatsappGroupIdentifier, WhatsappLIDIdentifier, WhatsappPhoneNumberIdentifier } from \"../Whatsapp.types.js\";\r\nimport type { FoundQuotedMsg } from \"../core/bot/internals/CommandsSearcher.types.js\";\r\nimport type { WhatsappMessage } from \"../core/whats_socket/types.js\";\r\n\r\n/**\r\n * # Extract Full Message Text\r\n *\r\n * Extracts the textual content from a raw WhatsApp message.\r\n *\r\n * This function inspects a `WAMessage` object and returns the main text associated with it.\r\n * It supports multiple message types, including simple text, extended text, and media captions.\r\n * If the message has no text content, it returns `null`.\r\n *\r\n * @param rawMsg - The raw message object received from Baileys.\r\n * @returns The text content of the message, or `null` if none is found.\r\n *\r\n * @example\r\n * ```typescript\r\n * const text = MsgHelper_FullMsg_GetText(rawMsg);\r\n * if (text) {\r\n * console.log(\"Message text:\", text);\r\n * }\r\n * ```\r\n */\r\nexport function MsgHelper_FullMsg_GetText(rawMsg: WAMessage): string | null {\r\n if (!rawMsg.message) return null;\r\n return (\r\n rawMsg.message.conversation ??\r\n rawMsg.message.extendedTextMessage?.text ??\r\n rawMsg.message.imageMessage?.caption ??\r\n rawMsg.message.videoMessage?.caption ??\r\n null\r\n );\r\n}\r\n\r\n/**\r\n * # Extract Quoted Message Text\r\n *\r\n * Extracts the text from a quoted message if it includes one inside a WAMessage.\r\n *\r\n * @param rawMsg - The raw message containing the quote.\r\n * @returns The extracted quoted text or `null` if it doesn't exist.\r\n *\r\n * @example\r\n * ```typescript\r\n * const quotedText = MsgHelper_FullMsg_GetQuotedMsgText(rawMsg);\r\n * console.log(quotedText);\r\n * ```\r\n */\r\nexport function MsgHelper_FullMsg_GetQuotedMsgText(rawMsg: WhatsappMessage): string | null {\r\n if (\r\n !rawMsg.message ||\r\n !rawMsg.message.extendedTextMessage ||\r\n !rawMsg.message.extendedTextMessage.contextInfo ||\r\n !rawMsg.message.extendedTextMessage.contextInfo.quotedMessage\r\n )\r\n return null;\r\n const quotedMsg = rawMsg.message.extendedTextMessage.contextInfo.quotedMessage;\r\n const text = quotedMsg.conversation || quotedMsg.extendedTextMessage?.text || quotedMsg.imageMessage?.caption || null;\r\n return text;\r\n}\r\n\r\n/**\r\n * # Extract Text From Quoted Message Object\r\n *\r\n * Extracts text content directly from a quoted message prototype object.\r\n *\r\n * @param quotedMsgOnly - The proto message object representing the quote.\r\n * @returns The text representation of the quoted message.\r\n *\r\n * @example\r\n * ```typescript\r\n * const quotedProto = MsgHelper_FullMsg_GetQuotedMsg(rawMsg);\r\n * if (quotedProto) {\r\n * const text = MsgHelper_QuotedMsg_GetText(quotedProto);\r\n * }\r\n * ```\r\n */\r\nexport function MsgHelper_QuotedMsg_GetText(quotedMsgOnly: proto.IMessage): string | null {\r\n return quotedMsgOnly.extendedTextMessage?.text ?? null;\r\n}\r\n\r\n// export function MsgHelper_HasQuotedMsg(rawMsg: WAMessage): boolean {\r\n// return !!rawMsg.message?.extendedTextMessage?.contextInfo?.quotedMessage;\r\n// }\r\n\r\n/**\r\n * # Get Quoted Message Object\r\n *\r\n * Safely extracts the quoted message prototype object from a full WhatsApp message.\r\n *\r\n * @param rawMsg - The raw WhatsApp message that might contain a quote.\r\n * @returns The quoted message protocol object or `null` if not found.\r\n *\r\n * @example\r\n * ```typescript\r\n * const quotedProto = MsgHelper_FullMsg_GetQuotedMsg(rawMsg);\r\n * ```\r\n */\r\nexport function MsgHelper_FullMsg_GetQuotedMsg(rawMsg: WAMessage): proto.IMessage | null {\r\n return rawMsg.message?.extendedTextMessage?.contextInfo?.quotedMessage ?? null;\r\n}\r\n\r\n/**\r\n * # Extract Quoted Message Information\r\n *\r\n * Returns both the quoted message object itself and its determined message type.\r\n *\r\n * @param rawMsg - The full WhatsApp message object.\r\n * @returns An object containing the quoted message and its type, or `null`.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = MsgHelper_ExtractQuotedMsgInfo(rawMsg);\r\n * if (info) {\r\n * console.log(\"Quoted message type:\", info.type);\r\n * }\r\n * ```\r\n */\r\nexport function MsgHelper_ExtractQuotedMsgInfo(rawMsg: WAMessage): FoundQuotedMsg | null {\r\n const existsQuotedMsg: proto.IMessage | null = MsgHelper_FullMsg_GetQuotedMsg(rawMsg);\r\n let quotedMsgAsArgument: FoundQuotedMsg | null = null;\r\n if (existsQuotedMsg) {\r\n const quotedMsgType: MsgType = MsgHelper_ProtoMsg_GetMsgType(existsQuotedMsg);\r\n quotedMsgAsArgument = {\r\n msg: existsQuotedMsg,\r\n type: quotedMsgType,\r\n };\r\n }\r\n return quotedMsgAsArgument;\r\n}\r\n\r\n/**\r\n * # Get Message Type\r\n *\r\n * Determines the type of a WhatsApp message from a raw Baileys `WAMessage` object.\r\n *\r\n * This function inspects the `message` field of the raw message and returns\r\n * a `MsgType` representing its type. If empty or unrecognized, returns `MsgType.Unknown`.\r\n *\r\n * @param rawMsg - The raw message object received from Baileys.\r\n * @returns The detected message type (`MsgType` enum).\r\n *\r\n * @example\r\n * ```typescript\r\n * const msgType = MsgHelper_FullMsg_GetMsgType(rawMsg);\r\n * if (msgType === MsgType.Text) {\r\n * console.log(\"Received a text message.\");\r\n * }\r\n * ```\r\n */\r\nexport function MsgHelper_FullMsg_GetMsgType(rawMsg: WhatsappMessage): MsgType {\r\n if (!rawMsg.message) return MsgType.Unknown;\r\n const objMsg = rawMsg.message;\r\n return MsgHelper_ProtoMsg_GetMsgType(objMsg);\r\n}\r\n\r\n/**\r\n * # Get Sender Type\r\n *\r\n * Detects whether the sender chat of the message is a group or an individual.\r\n *\r\n * @param rawMsg - The received WhatsApp message object.\r\n * @returns A `SenderType` indicating if it comes from a Group or Individual.\r\n *\r\n * @example\r\n * ```typescript\r\n * const senderType = MsgHelper_FullMsg_GetSenderType(rawMsg);\r\n * if (senderType === SenderType.Group) {\r\n * console.log(\"Message is from a group chat.\");\r\n * }\r\n * ```\r\n */\r\nexport function MsgHelper_FullMsg_GetSenderType(rawMsg: WhatsappMessage): SenderType {\r\n const chatId: string = rawMsg.key.remoteJid || rawMsg.key.remoteJidAlt!;\r\n let senderType: SenderType = SenderType.Unknown;\r\n if (chatId && chatId.endsWith(WhatsappGroupIdentifier)) senderType = SenderType.Group;\r\n if (chatId && chatId.endsWith(WhatsappPhoneNumberIdentifier)) senderType = SenderType.Individual;\r\n if (chatId && chatId.endsWith(WhatsappLIDIdentifier)) senderType = SenderType.Individual;\r\n return senderType;\r\n}\r\n\r\n/**\r\n * # Parse Prototype Message Type\r\n *\r\n * Gets the type of the message from the pure protocol message object.\r\n *\r\n * @param generic - The `IMessage` object from Baileys representing message content.\r\n * @returns The determined type of the message as a `MsgType` enum.\r\n *\r\n * @example\r\n * ```typescript\r\n * const msgType = MsgHelper_ProtoMsg_GetMsgType(rawMsg.message);\r\n * ```\r\n */\r\nexport function MsgHelper_ProtoMsg_GetMsgType(generic: proto.IMessage): MsgType {\r\n if (generic.imageMessage) return MsgType.Image;\r\n if (generic.videoMessage) return MsgType.Video;\r\n if (generic.audioMessage) return MsgType.Audio;\r\n if (generic.stickerMessage) return MsgType.Sticker;\r\n if (generic.pollCreationMessageV3) return MsgType.Poll;\r\n if (generic.locationMessage) return MsgType.Ubication;\r\n if (generic.contactMessage) return MsgType.Contact;\r\n if (generic.contactsArrayMessage) return MsgType.Contact;\r\n if (generic.documentMessage) return MsgType.Document;\r\n if (typeof generic.conversation === \"string\" || typeof generic.extendedTextMessage === \"string\" || generic.conversation || generic.extendedTextMessage)\r\n return MsgType.Text;\r\n return MsgType.Unknown;\r\n}\r\n","/**\r\n * A simple delegate implementation inspired by C# delegates.\r\n * Useful for the Observer pattern and event-driven programming.\r\n *\r\n * @template functType - The function signature that the delegate can hold.\r\n */\r\n\r\n/**\r\n * # Delegate Consumer\r\n *\r\n * Represents a delegate consumer type that exposes all Delegate functionality\r\n * except the `CallAll` method. Useful for restricting access to certain operations.\r\n *\r\n * @template fnType - The function signature that the delegate consumes.\r\n *\r\n * @example\r\n * ```typescript\r\n * const myEvent: DelegateConsumer<() => void> = new Delegate();\r\n * ```\r\n */\r\nexport type DelegateConsumer<fnType extends (...args: any[]) => any> = Omit<Delegate<fnType>, \"CallAll\">;\r\n\r\n/**\r\n * # Delegate\r\n *\r\n * A simple delegate implementation inspired by C# delegates.\r\n * Useful for the Observer pattern and event-driven programming.\r\n *\r\n * @template functType - The function signature that the delegate can hold.\r\n *\r\n * @example\r\n * ```typescript\r\n * const onChange = new Delegate<(id: string) => void>();\r\n * onChange.Subscribe((id) => console.log(id));\r\n * onChange.CallAll(\"123\");\r\n * ```\r\n */\r\n\r\nexport default class Delegate<functType extends (...args: any[]) => any> {\r\n /** Internal storage for all subscribed functions. */\r\n private functions: functType[] = [];\r\n\r\n /**\r\n * The number of functions currently subscribed to this delegate.\r\n */\r\n public get Length(): number {\r\n return this.functions.length;\r\n }\r\n\r\n /**\r\n * Subscribes a new function to the delegate.\r\n *\r\n * @param funct - The function to add.\r\n */\r\n public Subscribe(funct: functType): void {\r\n this.functions.push(funct);\r\n }\r\n\r\n /**\r\n * Unsubscribes a previously added function from the delegate.\r\n *\r\n * @param funct - The function to remove.\r\n * @returns `true` if the function was found and removed, otherwise `false`.\r\n */\r\n public Unsubscribe(funct: functType): boolean {\r\n const foundFunctIndex = this.functions.findIndex((f) => f === funct);\r\n if (foundFunctIndex === -1) return false;\r\n this.functions.splice(foundFunctIndex, 1);\r\n return true;\r\n }\r\n\r\n /**\r\n * Calls all subscribed functions synchronously with the provided arguments.\r\n *\r\n * @param args - Arguments to pass to each subscribed function.\r\n */\r\n public CallAll(...args: Parameters<functType>): Array<ReturnType<functType>> {\r\n if (this.functions.length > 0) {\r\n const res: Array<ReturnType<functType>> = this.functions.map((f) => f(...args));\r\n return res;\r\n }\r\n return [];\r\n }\r\n\r\n /**\r\n * Calls all subscribed functions asynchronously with the provided arguments.\r\n * Each function is awaited sequentially.\r\n *\r\n * @param args - Arguments to pass to each subscribed function.\r\n * @returns A promise that resolves when all functions have been called.\r\n */\r\n public async CallAllAsync(...args: Parameters<functType>): Promise<Array<ReturnType<functType>>> {\r\n if (this.functions.length > 0) {\r\n const res: Array<ReturnType<functType>> = await Promise.all(this.functions.map((f) => f(...args)));\r\n return res;\r\n }\r\n return [];\r\n }\r\n\r\n /**\r\n * Removes all subscribed functions from this delegate.\r\n */\r\n public Clear(): void {\r\n this.functions = [];\r\n }\r\n}\r\n","/**\r\n * The signature for the function that passes control to the next middleware.\r\n */\r\nexport type NextFunction = () => Promise<void>;\r\n\r\n/**\r\n * The generic signature for a middleware function.\r\n * @template TArgs An array type representing the arguments (e.g., [string, number]).\r\n * @param context The `this` context from the original caller.\r\n * @param args The typed arguments passed to the chain.\r\n * @param next The function to call to proceed to the next middleware.\r\n */\r\nexport type MiddlewareFunction<TArgs extends any[]> = (...args: [...TArgs, NextFunction]) => void | Promise<void>;\r\n\r\n/**\r\n * Manages the execution of a series of strongly-typed middleware functions.\r\n * @template TArgs An array type representing the arguments the chain will handle.\r\n */\r\nexport class MiddlewareChain<TArgs extends any[] = any[]> {\r\n private readonly _middleware: Array<MiddlewareFunction<TArgs>>;\r\n\r\n /**\r\n * @param middleware An array of middleware functions to execute in order.\r\n */\r\n constructor(middleware: Array<MiddlewareFunction<TArgs>>) {\r\n this._middleware = middleware;\r\n }\r\n\r\n /**\r\n * Executes the middleware chain with strongly-typed arguments.\r\n * @param context The object to use as `this` within middleware functions.\r\n * @param args Arguments that match the generic type `TArgs`.\r\n * @returns A promise that resolves to `true` if the chain completes, or `false` otherwise.\r\n */\r\n public async run(...args: TArgs): Promise<boolean> {\r\n if (this._middleware.length === 0) {\r\n return true;\r\n }\r\n\r\n let isChainCompleted = false;\r\n\r\n const callNext = async (index: number): Promise<void> => {\r\n if (index >= this._middleware.length) {\r\n isChainCompleted = true;\r\n return;\r\n }\r\n\r\n const currentMiddleware = this._middleware[index]!;\r\n const next = () => callNext(index + 1);\r\n // The provided 'args' are now passed with their types intact.\r\n await Promise.resolve(currentMiddleware(...args, next));\r\n };\r\n\r\n await callNext(0);\r\n return isChainCompleted;\r\n }\r\n}\r\n","import type { WAMessage } from \"baileys\";\r\nimport { WhatsappLIDIdentifier, WhatsappPhoneNumberIdentifier } from \"../Whatsapp.types.js\";\r\n\r\n/**\r\n * # WhatsApp ID Type\r\n *\r\n * Enum representing WhatsApp identifier conventions.\r\n *\r\n * @example\r\n * ```typescript\r\n * const myType = WhatsappIdType.Modern;\r\n * ```\r\n */\r\nexport enum WhatsappIdType {\r\n /** Legacy group addressing mode (`pn`) */\r\n Legacy = \"pn\",\r\n /** Modern group addressing mode (`lid`) */\r\n Modern = \"lid\",\r\n}\r\n\r\n/**\r\n * # WhatsApp ID Information\r\n *\r\n * Structure detailing different formats of a WhatsApp ID.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info: WhatsappIDInfo = {\r\n * rawId: \"1234567890@s.whatsapp.net\",\r\n * asMentionFormatted: \"@1234567890\",\r\n * WhatsappIdType: WhatsappIdType.Legacy\r\n * };\r\n * ```\r\n */\r\nexport type WhatsappIDInfo = {\r\n /**\r\n * The original WhatsApp ID as assigned by WhatsApp.\r\n * This is the raw identifier you receive in messages, without any formatting.\r\n */\r\n rawId?: string;\r\n\r\n /**\r\n * The phone number formatted for mentions in messages.\r\n * This is the normalized WhatsApp ID prefixed with '@', ready to be used in quotes or mentions.\r\n *\r\n * Example:\r\n * ```ts\r\n * // If the rawId is '1234567890@s.whatsapp.net', asMentionFormatted will be '@1234567890'\r\n * ```\r\n *\r\n * Note: When sending a message through the socket, make sure to include the sender's full raw ID in the array if required.\r\n */\r\n asMentionFormatted?: string;\r\n\r\n /**\r\n * Indicates the type of WhatsApp ID received.\r\n * - \"lid\": The ID comes from a group message as a linked device identifier. Messages cannot be sent directly to a `@lid`.\r\n * - \"full\": The ID comes from a private chat and is a full WhatsApp ID (e.g., '1234567890@s.whatsapp.net'), which can be used to send messages directly.\r\n */\r\n WhatsappIdType?: WhatsappIdType;\r\n};\r\n\r\n/**\r\n * # Extract Phone Info From Sender Message\r\n *\r\n * Extracts detailed phone number information from a raw WhatsApp message.\r\n *\r\n * @param rawMsg - The raw WhatsApp message.\r\n * @returns An object containing the extracted WhatsApp ID details.\r\n * @throws {Error} If both participant and remoteJid are undefined.\r\n *\r\n * @example\r\n * ```typescript\r\n * const phoneInfo = WhatsappHelper_ExtractWhatsappInfoInfoFromSenderRawMsg(rawMsg);\r\n * console.log(\"Sender Mention string:\", phoneInfo.asMentionFormatted);\r\n * ```\r\n */\r\nexport function WhatsappHelper_ExtractWhatsappInfoInfoFromSenderRawMsg(rawMsg: WAMessage): WhatsappIDInfo {\r\n //Let's check if comes from private msg or group\r\n const id: string | null = rawMsg.key.participant || rawMsg.key.remoteJid || null;\r\n if (!id) {\r\n throw Error(\"This shouldn't happen, baileys library never gives both participant and remoteJid as undefined, only one of them\");\r\n }\r\n return WhatsappHelper_ExtractFromWhatsappID(id);\r\n}\r\n\r\n/**\r\n * # Extract Info From WhatsApp ID\r\n *\r\n * Parses a given raw WhatsApp ID string into an informational structure.\r\n *\r\n * @param whatsappIDStr - The raw string identifier (e.g. \"1234@s.whatsapp.net\").\r\n * @returns The assembled `WhatsappIDInfo` data structure.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = WhatsappHelper_ExtractFromWhatsappID(\"123@s.whatsapp.net\");\r\n * ```\r\n */\r\nexport function WhatsappHelper_ExtractFromWhatsappID(whatsappIDStr: string): WhatsappIDInfo {\r\n const idNumbersOnly = whatsappIDStr.split(\"@\").at(0)!;\r\n let whatsIdType: WhatsappIdType;\r\n if (WhatsappHelper_isLIDIdentifier(whatsappIDStr)) {\r\n whatsIdType = WhatsappIdType.Modern;\r\n } else if (WhatsappHelper_isFullWhatsappIdUser(whatsappIDStr)) {\r\n whatsIdType = WhatsappIdType.Legacy;\r\n } else {\r\n throw new Error(\"WhatsappHelper_ExtractWhatsappIdFromSender couldn't get rawMsgs type id. Got instead: \" + whatsappIDStr);\r\n }\r\n return {\r\n asMentionFormatted: `@${idNumbersOnly}`,\r\n rawId: whatsappIDStr,\r\n WhatsappIdType: whatsIdType,\r\n };\r\n}\r\n\r\n/**\r\n * # Extract WhatsApp Info From Mention\r\n *\r\n * Gets the WhatsApp identifier details out of a mention string if valid.\r\n *\r\n * @param mentionId - A localized mention string (e.g., \"@12345\").\r\n * @returns The `WhatsappIDInfo` or `null` if invalid.\r\n *\r\n * @example\r\n * ```typescript\r\n * const info = WhatsappHelper_ExtractWhatsappInfoFromMention(\"@12345\");\r\n * ```\r\n */\r\nexport function WhatsappHelper_ExtractWhatsappInfoFromMention(mentionId: string): WhatsappIDInfo | null {\r\n if (!WhatsappHelper_isMentionId(mentionId)) return null;\r\n const number = mentionId.slice(1);\r\n return {\r\n rawId: `${number}${WhatsappLIDIdentifier}`,\r\n asMentionFormatted: mentionId,\r\n WhatsappIdType: WhatsappIdType.Modern,\r\n };\r\n}\r\n\r\n/**\r\n * # Is LID Identifier\r\n *\r\n * Checks if a string acts as a modern Linked Device Identifier.\r\n *\r\n * @param whatsIdExpected - The raw ID string.\r\n * @returns True if it is a LID.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isLid = WhatsappHelper_isLIDIdentifier(\"1234@lid\");\r\n * ```\r\n */\r\nexport function WhatsappHelper_isLIDIdentifier(whatsIdExpected: string): boolean {\r\n const isLidRegex = new RegExp(`^\\\\d{11,16}${WhatsappLIDIdentifier}$`);\r\n return isLidRegex.test(whatsIdExpected);\r\n}\r\n\r\n/**\r\n * # Is Mention Identifier\r\n *\r\n * Checks if the given string is a valid mention ID for a WhatsApp user.\r\n *\r\n * @param numberStr - The mention formatted string to check.\r\n * @returns True if valid, false otherwise.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isValid = WhatsappHelper_isMentionId('@1234567890123');\r\n * ```\r\n */\r\nexport function WhatsappHelper_isMentionId(numberStr: string): boolean {\r\n const UserMentionedRegex = /^@\\d{11,16}$/;\r\n return UserMentionedRegex.test(numberStr);\r\n}\r\n\r\n/**\r\n * # Is Full WhatsApp User ID\r\n *\r\n * Checks if the given string is a valid full WhatsApp ID for an individual user.\r\n *\r\n * @param expectedWhatsappId - The string to check.\r\n * @returns True if the string is a standard individual user ID.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isValid = WhatsappHelper_isFullWhatsappIdUser('1234567890@s.whatsapp.net');\r\n * ```\r\n */\r\nexport function WhatsappHelper_isFullWhatsappIdUser(expectedWhatsappId: string): boolean {\r\n const UserCompleteWhatsappIdRegex = new RegExp(`^\\\\d{11,16}${WhatsappPhoneNumberIdentifier}$`);\r\n return UserCompleteWhatsappIdRegex.test(expectedWhatsappId);\r\n}\r\n","import type { GroupMetadata } from \"baileys\";\r\nimport { MsgHelper_FullMsg_GetText } from \"../../../helpers/Msg.helper.js\";\r\nimport { type WhatsappIDInfo, WhatsappHelper_ExtractFromWhatsappID, WhatsappIdType } from \"../../../helpers/Whatsapp.helper.js\";\r\nimport { type SenderType, MsgType } from \"../../../Msg.types.js\";\r\nimport type { IWhatsSocket } from \"../IWhatsSocket.js\";\r\nimport type { WhatsappMessage } from \"../types.js\";\r\nimport type { IWhatsSocket_Submodule_Receiver } from \"./IWhatsSocket.receiver.js\";\r\n\r\n/**\r\n * Callback type used to determine whether a received message satisfies a success condition.\r\n *\r\n * @param userId - The WhatsApp sender ID of the message (may be null for broadcasts).\r\n * @param chatId - The ID of the chat the message belongs to.\r\n * @param incomingRawMsg - The raw message object from Baileys.\r\n * @param incomingMsgType - The type of the message.\r\n * @param incomingSenderType - Whether the sender is a group member, self, etc.\r\n * @returns true if the message satisfies the success condition; false otherwise.\r\n */\r\ntype SuccessConditionCallback = (\r\n participantId_LID: string | null,\r\n participantId_PN: string | null,\r\n chatId: string,\r\n incomingRawMsg: WhatsappMessage,\r\n incomingMsgType: MsgType,\r\n incomingSenderType: SenderType\r\n) => boolean;\r\n\r\n/**\r\n * # Wait Options\r\n *\r\n * Options used to configure the wait message behavior in Receiver module.\r\n *\r\n * @example\r\n * ```typescript\r\n * const waitOpts: WhatsSocketReceiverWaitOptions = { timeoutSeconds: 10, cancelKeywords: [\"stop\"], ignoreSelfMessages: true };\r\n * ```\r\n */\r\nexport type WhatsSocketReceiverWaitOptions = {\r\n /** Maximum time (in seconds) to wait for a valid message before rejecting. */\r\n timeoutSeconds: number;\r\n\r\n /** Array of keywords that, if present in a message, will cancel the wait. */\r\n cancelKeywords: string[];\r\n\r\n /** Message sent back to the user if they send a message of the wrong type. */\r\n wrongTypeFeedbackMsg?: string;\r\n\r\n cancelFeedbackMsg?: string;\r\n\r\n /** Whether to ignore messages sent by the bot itself. Default: true */\r\n ignoreSelfMessages: boolean;\r\n};\r\n\r\n/**\r\n * # Receiver Error\r\n *\r\n * Represents an error that occurs during message reception waiting.\r\n *\r\n * @example\r\n * ```typescript\r\n * const err: WhatsSocketReceiverError = {\r\n * errorMessage: WhatsSocketReceiverMsgError.Timeout,\r\n * wasAbortedByUser: false,\r\n * chatId: \"123\",\r\n * participantId_LID: null,\r\n * participantId_PN: null\r\n * };\r\n * ```\r\n */\r\nexport type WhatsSocketReceiverError = {\r\n /** Human-readable error message. */\r\n errorMessage: WhatsSocketReceiverMsgError;\r\n\r\n /** Whether the wait was aborted because the user sent a cancel keyword. */\r\n wasAbortedByUser: boolean;\r\n\r\n /**\r\n * If this error msg comes from group, this will be the participant ID who\r\n * triggered this waiting msg.\r\n * Otherwise, if this comes from private chat, will be null\r\n */\r\n participantId_LID: string | null;\r\n\r\n participantId_PN: string | null;\r\n\r\n /**\r\n * Whatsapp chat ID where this msgError came from\r\n */\r\n chatId: string;\r\n};\r\n\r\n/**\r\n * # Receiver Error Reason\r\n *\r\n * Enumeration mapping the reason for the receiver failure.\r\n *\r\n * @example\r\n * ```typescript\r\n * const reason = WhatsSocketReceiverMsgError.Timeout;\r\n * ```\r\n */\r\nexport enum WhatsSocketReceiverMsgError {\r\n Timeout = \"User didn't responded in time\",\r\n UserCanceledWaiting = \"User has canceled the dialog\",\r\n}\r\n\r\n/**\r\n * # Is Receiver Error\r\n *\r\n * Checks if an object is a `WhatsSocketReceiverError`. This error comes from ChatContext if using \"Wait\" methods,\r\n * or directly from WhatsMsgReceiver Submodule.\r\n *\r\n * @param anything The thing to check.\r\n * @returns Whether `anything` is a `WhatsSocketReceiverError`.\r\n * @category Internal\r\n *\r\n * @example\r\n * ```typescript\r\n * if(WhatsSocketReceiverHelper_isReceiverError(error)) {\r\n * console.log(error.errorMessage);\r\n * }\r\n * ```\r\n */\r\nexport function WhatsSocketReceiverHelper_isReceiverError(anything: unknown): anything is WhatsSocketReceiverError {\r\n return (\r\n typeof anything === \"object\" &&\r\n anything !== null &&\r\n \"errorMessage\" in anything &&\r\n \"wasAbortedByUser\" in anything &&\r\n \"participantId_PN\" in anything &&\r\n \"participantId_PN\" in anything &&\r\n \"chatId\" in anything\r\n );\r\n}\r\n\r\n/**\r\n * # Receiver Submodule\r\n *\r\n * Submodule responsible for listening and waiting for messages through a WhatsSocket instance.\r\n *\r\n * @example\r\n * ```typescript\r\n * const receiver = new WhatsSocket_Submodule_Receiver(socket);\r\n * ```\r\n */\r\nexport class WhatsSocket_Submodule_Receiver implements IWhatsSocket_Submodule_Receiver {\r\n private _whatsSocket: IWhatsSocket;\r\n\r\n /**\r\n * @param socket - An instance of a WhatsSocket (must implement IWhatsSocket).\r\n */\r\n constructor(socket: IWhatsSocket) {\r\n this._whatsSocket = socket;\r\n //DO NOT use decorator @autobind for this class, tests start to fail due to that, here has to be done manually\r\n this.FetchGroupData = this.FetchGroupData.bind(this);\r\n this.WaitUntilNextRawMsgFromUserIDInGroup = this.WaitUntilNextRawMsgFromUserIDInGroup.bind(this);\r\n this.WaitUntilNextRawMsgFromUserIdInPrivateConversation = this.WaitUntilNextRawMsgFromUserIdInPrivateConversation.bind(this);\r\n this._waitNextMsg = this._waitNextMsg.bind(this);\r\n }\r\n\r\n /**\r\n * Internal helper that waits for the next message satisfying a success condition.\r\n * Cancel logic and MsgType checking validation is made here, do not do it on successConditionCallback\r\n *\r\n * @param successConditionCallback - Callback to determine if the message meets the success criteria.\r\n * @param chatIdToLookFor - Chat ID where the message should arrive.\r\n * @param expectedMsgType - Expected type of the message.\r\n * @param options - Configuration options for timeout, cancel keywords, etc.\r\n * @returns Promise that resolves with the WhatsappMessage that met the condition or rejects with an error.\r\n */\r\n private _waitNextMsg(\r\n successConditionCallback: SuccessConditionCallback,\r\n expectedMsgType: MsgType,\r\n options: WhatsSocketReceiverWaitOptions\r\n ): Promise<WhatsappMessage> {\r\n //Options default values\r\n const { cancelKeywords = [], ignoreSelfMessages = true, timeoutSeconds = 30, cancelFeedbackMsg, wrongTypeFeedbackMsg } = options;\r\n\r\n let cachedChatId: string = \"====default ID===== (this is error msg), check WhatsSocket.receiver.ts\";\r\n return new Promise((resolve: (WhatsappMessage: WhatsappMessage) => void, reject: (reason: WhatsSocketReceiverError) => void) => {\r\n let timer: NodeJS.Timeout;\r\n const resetTimeout = () => {\r\n if (timer) clearTimeout(timer);\r\n timer = setTimeout(() => {\r\n this._whatsSocket.onIncomingMsg.Unsubscribe(listener);\r\n reject({\r\n wasAbortedByUser: false,\r\n errorMessage: WhatsSocketReceiverMsgError.Timeout,\r\n chatId: cachedChatId,\r\n participantId_LID: null,\r\n participantId_PN: null,\r\n });\r\n }, timeoutSeconds * 1000);\r\n };\r\n\r\n const listener = (\r\n participantId_LID: string | null,\r\n participantId_PN: string | null,\r\n chatId: string,\r\n msg: WhatsappMessage,\r\n msgType: MsgType,\r\n senderType: SenderType\r\n ) => {\r\n // @deprecated_line: This is supposed to be validated on param 'successConditionCallback'\r\n // if (msg.key.remoteJid !== chatIdToLookFor) return;\r\n cachedChatId = chatId;\r\n if (ignoreSelfMessages) {\r\n if (msg.key.fromMe) return;\r\n }\r\n\r\n resetTimeout();\r\n\r\n //Priority #2: Check if it fits our conditions\r\n if (!successConditionCallback(participantId_LID, participantId_PN, chatId, msg, msgType, senderType)) return;\r\n\r\n if (msgType === MsgType.Text) {\r\n //Priority #1: Check if user is trying to cancel this command\r\n const expectedTxtMsgContent: string | null = MsgHelper_FullMsg_GetText(msg);\r\n if (expectedTxtMsgContent) {\r\n const wordsLowerCased = expectedTxtMsgContent.split(\" \").map((word) => word.toLowerCase());\r\n for (let i = 0; i < wordsLowerCased.length; i++) {\r\n const actualWord = wordsLowerCased[i]!;\r\n if (cancelKeywords.includes(actualWord)) {\r\n this._whatsSocket.onIncomingMsg.Unsubscribe(listener);\r\n clearTimeout(timer);\r\n if (cancelFeedbackMsg) {\r\n this._whatsSocket.Send.Text(chatId, cancelFeedbackMsg);\r\n }\r\n reject({\r\n wasAbortedByUser: true,\r\n errorMessage: WhatsSocketReceiverMsgError.UserCanceledWaiting,\r\n chatId: chatId,\r\n participantId_LID: participantId_LID,\r\n participantId_PN: participantId_PN,\r\n });\r\n return;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Priority #3: All good?, User not cancelling, or even text, let's verify if its the type expected\r\n if (msgType !== expectedMsgType) {\r\n if (wrongTypeFeedbackMsg) {\r\n this._whatsSocket.Send.Text(chatId, wrongTypeFeedbackMsg);\r\n }\r\n return;\r\n }\r\n\r\n this._whatsSocket.onIncomingMsg.Unsubscribe(listener);\r\n clearTimeout(timer);\r\n resolve(msg);\r\n return;\r\n };\r\n //Set initial timeout\r\n resetTimeout();\r\n\r\n // Start listening for msgs\r\n this._whatsSocket.onIncomingMsg.Subscribe(listener);\r\n });\r\n }\r\n\r\n public async WaitUntilNextRawMsgFromUserIDInGroup(\r\n userID_LID_ToWait: string | null,\r\n userID_PN_toWait: string | null,\r\n chatToWaitOnID: string,\r\n expectedMsgType: MsgType,\r\n options: WhatsSocketReceiverWaitOptions\r\n ): Promise<WhatsappMessage> {\r\n if (!userID_LID_ToWait && userID_PN_toWait) {\r\n throw new Error(\"WhatsSocket.receiver.WaitUntilRAwmsgFromUserIDInGroup(), you must provide at least one userID, either the LID or PN version\");\r\n }\r\n //@note: ChatId validation is already done on this._waitNextMsg method\r\n const conditionCallback: SuccessConditionCallback = (participantId_LIDComingFrom, participantId_PNComingFrom, actualChatID, _, _actualMsgType, ___) => {\r\n //#1 Comes from same group?\r\n if (actualChatID !== chatToWaitOnID) return false;\r\n //#2 Its from the expected participant? LID format\r\n if (userID_LID_ToWait) {\r\n if (participantId_LIDComingFrom !== userID_LID_ToWait) return false;\r\n }\r\n\r\n //#3 Its from expected participant? PN format\r\n if (userID_PN_toWait) {\r\n if (participantId_PNComingFrom !== userID_PN_toWait) return false;\r\n }\r\n\r\n return true;\r\n };\r\n return await this._waitNextMsg(conditionCallback, expectedMsgType, options);\r\n }\r\n\r\n public async WaitUntilNextRawMsgFromUserIdInPrivateConversation(\r\n chatIdPrivateUserToWait: string,\r\n expectedMsgType: MsgType,\r\n options: WhatsSocketReceiverWaitOptions\r\n ): Promise<WhatsappMessage> {\r\n const conditionCallback: SuccessConditionCallback = (\r\n _participantId_LIDComingFrom,\r\n _participantId_PNComingFrom,\r\n actualChatId,\r\n _rawMsg,\r\n _actualMsgType,\r\n _senderType\r\n ) => {\r\n if (chatIdPrivateUserToWait !== actualChatId) return false;\r\n return true;\r\n };\r\n return await this._waitNextMsg(conditionCallback, expectedMsgType, options);\r\n }\r\n\r\n public async FetchGroupData(chatId: string): Promise<GroupMetadataInfo | null> {\r\n let res: GroupMetadata;\r\n try {\r\n //In case its a bad chatId and comes from individual msg\r\n res = await this._whatsSocket.GetRawGroupMetadata(chatId);\r\n } catch {\r\n return null;\r\n }\r\n const participants: ParticipantInfo[] = res.participants.map((info): ParticipantInfo => {\r\n const foundId = info.id || info.lid;\r\n let foundWhatsInfo: WhatsappIDInfo | null = null;\r\n if (foundId) {\r\n foundWhatsInfo = WhatsappHelper_ExtractFromWhatsappID(foundId);\r\n }\r\n return {\r\n isAdmin: info.admin === \"superadmin\",\r\n asMentionFormatted: foundWhatsInfo?.asMentionFormatted,\r\n rawId: foundWhatsInfo?.rawId,\r\n WhatsappIdType: foundWhatsInfo?.WhatsappIdType,\r\n };\r\n });\r\n return {\r\n id: res.id,\r\n sendingMode: res.addressingMode === \"pn\" ? WhatsappIdType.Legacy : WhatsappIdType.Modern,\r\n ownerName: res.subjectOwner || res.owner || null,\r\n groupName: res.subject,\r\n groupDescription: res.desc || null,\r\n inviteCode: res.inviteCode || null,\r\n communityIdWhereItBelongs: res.isCommunity ? res.id : null,\r\n onlyAdminsCanChangeGroupSettings: res.restrict || null,\r\n onlyAdminsCanSendMsgs: res.announce || null,\r\n membersCanAddOtherMembers: res.memberAddMode || null,\r\n needsRequestApprovalToJoinIn: res.joinApprovalMode ?? null,\r\n isCommunityAnnounceChannel: res.isCommunityAnnounce || null,\r\n membersCount: res.participants.length || null,\r\n ephemeralDuration: res.ephemeralDuration || null,\r\n author: null,\r\n lastNameChangeDateTime: res.subjectTime || null,\r\n creationDate: res.creation || null,\r\n members: participants,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * # Participant Information\r\n *\r\n * Represents a participant in a WhatsApp group.\r\n *\r\n * @example\r\n * ```typescript\r\n * const pInfo: ParticipantInfo = { isAdmin: true, rawId: \"123\" };\r\n * ```\r\n */\r\nexport type ParticipantInfo = {\r\n /** Whether this participant is an admin */\r\n isAdmin: boolean;\r\n} & WhatsappIDInfo;\r\n\r\n/**\r\n * # Group Metadata\r\n *\r\n * Represents all relevant metadata for a WhatsApp group chat.\r\n *\r\n * @example\r\n * ```typescript\r\n * // const metadata: GroupMetadataInfo = await receiver.FetchGroupData(\"123@g.us\");\r\n * ```\r\n */\r\nexport type GroupMetadataInfo = {\r\n /** Group ID */\r\n id: string;\r\n /** Sending mode of the group */\r\n sendingMode: WhatsappIdType;\r\n /** Name of the group owner */\r\n ownerName: string | null;\r\n /** Display name of the group */\r\n groupName: string;\r\n /** Group description */\r\n groupDescription: string | null;\r\n /** ID of the parent community if the group belongs to one */\r\n communityIdWhereItBelongs: string | null;\r\n /** Whether only admins can change group settings */\r\n onlyAdminsCanChangeGroupSettings: boolean | null;\r\n /** Whether only admins can send messages */\r\n onlyAdminsCanSendMsgs: boolean | null;\r\n /** Whether members can add other members */\r\n membersCanAddOtherMembers: boolean | null;\r\n /** Whether joining requires approval */\r\n needsRequestApprovalToJoinIn: boolean | null;\r\n /** Whether the group is a community announce channel */\r\n isCommunityAnnounceChannel: boolean | null;\r\n /** Total number of participants */\r\n membersCount: number | null;\r\n /** Ephemeral message duration in seconds, if enabled */\r\n ephemeralDuration: number | null;\r\n /** Invite code for the group */\r\n inviteCode: string | null;\r\n /** Timestamp of the last group name change */\r\n lastNameChangeDateTime: number | null;\r\n /** The person who added the bot or changed a setting */\r\n author: string | null;\r\n /** Timestamp of group creation */\r\n creationDate: number | null;\r\n /** Array of group participants */\r\n members: ParticipantInfo[];\r\n};\r\n","import path from \"node:path\";\r\n\r\n/**\r\n * # Get Path\r\n *\r\n * Do not use this anymore, it's the same as using path.join.\r\n * @deprecated Do not use this anymore, it used to work as a compile/not-compile path management, but that doesn't have sense\r\n * in a library...\r\n */\r\nexport function GetPath(...filePathToAppendFromRoot: string[]): string {\r\n if (filePathToAppendFromRoot.length === 0) return \"\";\r\n return path.join(...filePathToAppendFromRoot);\r\n}\r\n","import type { AnyMessageContent, MiscMessageGenerationOptions } from \"baileys\";\r\nimport Delegate from \"../../../libs/Delegate.js\";\r\nimport type { IWhatsSocket } from \"../IWhatsSocket.js\";\r\nimport type { WhatsappMessage } from \"../types.js\";\r\n\r\n/**\r\n * # Socket Message Queue Item\r\n *\r\n * Represents an item in the sending queue.\r\n *\r\n * @example\r\n * ```typescript\r\n * const item: SocketMsgQueueItem = {\r\n * chatId: \"123\",\r\n * content: { text: \"hello\" },\r\n * resolve: () => {},\r\n * reject: () => {}\r\n * };\r\n * ```\r\n */\r\ntype SocketMsgQueueItem = {\r\n chatId: string;\r\n content: AnyMessageContent;\r\n misc?: MiscMessageGenerationOptions;\r\n resolve: (result: any) => void;\r\n reject: (reason: any) => void;\r\n};\r\n\r\nfunction Clone_MsgQueueItem(msgItem: SocketMsgQueueItem) {\r\n const toReturn = {\r\n chatId: msgItem.chatId,\r\n content: { ...msgItem.content },\r\n misc: { ...msgItem.misc },\r\n resolve: msgItem.resolve,\r\n reject: msgItem.reject,\r\n };\r\n return toReturn;\r\n}\r\n\r\n/**\r\n * # Sender Queue Submodule\r\n *\r\n * A subclass code of 'WhatsSocket' class that manages a queue of messages to be sent.\r\n * Helps to prevent overwhelming the WhatsApp socket with too many messages at once incoming from\r\n * multiple users or a funny user trying to spam the bot.\r\n *\r\n * @example\r\n * ```typescript\r\n * const queue = new WhatsSocketSenderQueue_SubModule(socket, 10, 500);\r\n * ```\r\n */\r\nexport default class WhatsSocketSenderQueue_SubModule {\r\n public onSentMessageInsideQueue: Delegate<(chatId: string, content: AnyMessageContent, misc?: MiscMessageGenerationOptions) => void> = new Delegate();\r\n /**\r\n * A getter that returns a deep copy of all elements currently in the queue as an array.\r\n * This is useful for debugging and logging purposes.\r\n * @returns A deep copy of all elements currently in the queue as an array.\r\n */\r\n public get ActualElementsInQueue() {\r\n return this.queue.map((queueItem) => {\r\n return Clone_MsgQueueItem(queueItem);\r\n });\r\n }\r\n\r\n private queue: SocketMsgQueueItem[] = [];\r\n private isProcessing: boolean = false;\r\n private whatsSocket: IWhatsSocket;\r\n private readonly minMillisecondsDelay: number;\r\n private readonly maxQueueLimit: number;\r\n\r\n private isStopped: boolean = false;\r\n\r\n constructor(socket: IWhatsSocket, maxQueueLimit: number = 3, minMilisecondsDelay: number = 1000) {\r\n this.whatsSocket = socket;\r\n this.minMillisecondsDelay = minMilisecondsDelay;\r\n this.maxQueueLimit = maxQueueLimit;\r\n }\r\n\r\n /**\r\n * Enqueues a message to be sent.\r\n * @throws Error if msg enqueue couldn't be send\r\n * @param chatId ChatJID of the user.\r\n * @param content The content of the message.\r\n * @param misc Miscellaneous options.\r\n */\r\n public Enqueue(chatId: string, content: AnyMessageContent, misc?: MiscMessageGenerationOptions): Promise<WhatsappMessage | null> {\r\n return new Promise((resolve, reject) => {\r\n if (this.queue.length >= this.maxQueueLimit) {\r\n console.log(`WhatsSocketSenderQueue: Queue limit of ${this.maxQueueLimit} reached. Ignoring extra img...`);\r\n resolve(null);\r\n return;\r\n }\r\n this.queue.push({ chatId, content, misc, resolve, reject });\r\n // Only start the processing loop if it's not already running.\r\n if (!this.isProcessing && !this.isStopped) {\r\n this.ProcessQueue();\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Stops the queue from processing any more messages. This method is non-blocking. Any messages that are already in the queue\r\n * will be processed and sent, but no new messages will be added to the queue. Note that this method will not stop the underlying\r\n * WhatsApp socket from receiving or sending messages. You will need to call IWhatsSocket.Shutdown() to stop the socket completely.\r\n * @returns A promise that resolves when the queue has stopped processing messages.\r\n */\r\n public async StopGracefully(): Promise<void> {\r\n this.isStopped = true;\r\n }\r\n\r\n /**\r\n * Resumes the processing of the queue after being stopped. This will start processing all messages in the queue again.\r\n * @returns A promise that resolves when the queue has resumed processing messages.\r\n */\r\n public async Continue(): Promise<void> {\r\n this.isStopped = false;\r\n return this.ProcessQueue();\r\n }\r\n\r\n /**\r\n * Processes all messages in the queue one by one, respecting the minimum delay\r\n * between messages specified in the constructor.\r\n * @private\r\n */\r\n private async ProcessQueue(): Promise<void> {\r\n this.isProcessing = true;\r\n while (this.queue.length > 0) {\r\n const item = this.queue.shift()!;\r\n try {\r\n const sentMsg: WhatsappMessage | null = await this.whatsSocket._SendRaw(item.chatId, item.content, item.misc);\r\n this.onSentMessageInsideQueue.CallAll(item.chatId, item.content, item.misc);\r\n this.whatsSocket.onSentMessage.CallAll(item.chatId, item.content, item.misc);\r\n item.resolve(sentMsg);\r\n } catch (error) {\r\n item.reject(error);\r\n }\r\n // Wait for the delay before processing the next message.\r\n await new Promise((resolve) => setTimeout(resolve, this.minMillisecondsDelay));\r\n }\r\n this.isProcessing = false;\r\n }\r\n}\r\n","import mime from \"mime\";\r\nimport path from \"node:path\";\r\n\r\n/**\r\n * Regex to check if a string is a **file extension only**.\r\n *\r\n * Examples that match:\r\n * - \".txt\"\r\n * - \".png\"\r\n *\r\n * Examples that do NOT match:\r\n * - \"png\" (missing leading \".\")\r\n * - \"file.png\" (this is a path, not an extension)\r\n */\r\n// const isExtension_regex = /^\\.[a-zA-Z0-9]{1,}$/;\r\n\r\n/**\r\n * Regex to check if a string is a valid **path** (relative or absolute).\r\n *\r\n * Examples that match:\r\n * - \"./relative/path/to/file.png\"\r\n * - \"../up/one/dir/file.txt\"\r\n * - \"/absolute/path/to/file.jpeg\"\r\n * - \"C:\\\\Windows\\\\path\\\\file.gif\"\r\n */\r\nconst isPath_regex = /^(?:(?:\\/|[a-zA-Z]:\\\\|\\\\)(?:[\\w-]+[\\\\/])*[\\w-]+(?:\\.[\\w]+)?|(?:\\.\\/|\\.\\.\\/)(?:[\\w-]+[\\\\/])*[\\w-]+(?:\\.[\\w]+)?)$/;\r\n\r\n/**\r\n * # Default Mimetype\r\n *\r\n * The default mimetype used when no match is found.\r\n *\r\n * @example\r\n * ```typescript\r\n * const type = DEFAULT_MIMETYPE; // \"application/octet-stream\"\r\n * ```\r\n */\r\nexport const DEFAULT_MIMETYPE = \"application/octet-stream\";\r\n\r\n/**\r\n * Extracts and resolves the **MIME type** from either:\r\n * - A file extension (can begin with a dot or not, e.g. `.txt`, `png`)\r\n * - A file path (relative or absolute, e.g. `./image.jpg`, `/usr/local/file.pdf`)\r\n *\r\n * @param filePathOrExtensionOnly - String containing a file extension or a file path.\r\n * @returns The resolved MIME type (e.g. `\"image/png\"`, `\"video/mp4\"`).\r\n * Returns `\"application/octet-stream\"` if no match is found, or if givenValue is not either .<filetype> or a path\r\n */\r\nfunction _extractExtensionFrom_Path_Or_FileExtension(filePathOrExtensionOnly: string): string {\r\n //Is path (./relative/path/to/file.png or /absolute/path/to/file.jpeg)\r\n if (filePathOrExtensionOnly.match(isPath_regex)) {\r\n const res: string | null = mime.getType(path.extname(filePathOrExtensionOnly));\r\n return res ?? DEFAULT_MIMETYPE;\r\n } else {\r\n //Is extension only (\".txt\", \".png\") or any other else\r\n const res: string | null = mime.getType(filePathOrExtensionOnly);\r\n return res ?? DEFAULT_MIMETYPE;\r\n }\r\n}\r\n\r\n/**\r\n * # Is Image\r\n *\r\n * Determines whether the given file path or extension refers to an **image**.\r\n *\r\n * @param filePathOrExtension - A string with either:\r\n * - An extension (can start with a dot or not, e.g. `.jpg`, `png`)\r\n * - A path (relative or absolute, e.g. `./pic.png`)\r\n *\r\n * @returns `true` if the file is an image type (`image/*`), otherwise `false`.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isImage = MimeTypeHelper_IsImage(\"file.png\"); // true\r\n * ```\r\n */\r\nexport function MimeTypeHelper_IsImage(filePathOrExtension: string): boolean {\r\n if (!filePathOrExtension || filePathOrExtension.trim() === \"\") return false;\r\n const res: string = _extractExtensionFrom_Path_Or_FileExtension(filePathOrExtension);\r\n return res.startsWith(\"image/\");\r\n}\r\n\r\n/**\r\n * # Is Video\r\n *\r\n * Determines whether the given file path or extension refers to a **video**.\r\n *\r\n * @param filePathOrExtension - A string with either:\r\n * - An extension (can start with a dot or not, e.g. `.jpg`, `png`)\r\n * - A path (relative or absolute, e.g. `/movies/video.avi`)\r\n *\r\n * @returns `true` if the file is a video type (`video/*`), otherwise `false`.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isVideo = MimeTypeHelper_IsVideo(\"file.mp4\"); // true\r\n * ```\r\n */\r\nexport function MimeTypeHelper_IsVideo(filePathOrExtension: string): boolean {\r\n if (!filePathOrExtension || filePathOrExtension.trim() === \"\") return false;\r\n const res: string = _extractExtensionFrom_Path_Or_FileExtension(filePathOrExtension);\r\n return res.startsWith(\"video/\");\r\n}\r\n\r\n/**\r\n * # Is Audio\r\n *\r\n * Determines whether the given file path or extension refers to an **audio**.\r\n *\r\n * @param filePathOrExtension - A string with either:\r\n * - An extension (can start with a dot or not, e.g. `.mp3`, `wav`)\r\n * - A path (relative or absolute, e.g. `./audio/song.mp3`)\r\n *\r\n * @returns `true` if the file is an audio type (`audio/*`), otherwise `false`.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isAudio = MimeTypeHelper_IsAudio(\"file.mp3\"); // true\r\n * ```\r\n */\r\nexport function MimeTypeHelper_IsAudio(filePathOrExtension: string): boolean {\r\n if (!filePathOrExtension || filePathOrExtension.trim() === \"\") return false;\r\n const res: string = _extractExtensionFrom_Path_Or_FileExtension(filePathOrExtension);\r\n return res.startsWith(\"audio/\");\r\n}\r\n\r\n/**\r\n * # Get Mimetype Of\r\n *\r\n * Retrieves the MIME type of a file or buffer with a given extension.\r\n *\r\n * Supports two overloads:\r\n * 1. `MimeTypeHelper_GetMimeTypeOf({ source: string })`\r\n * - `source`: The file path\r\n * 2. `MimeTypeHelper_GetMimeTypeOf({ source: Buffer; extensionType: string })`\r\n * - `source`: The buffer containing the file data\r\n * - `extensionType`: The file extension (e.g. `\"pdf\"`, `\"zip\"`) can start with a dot or not, e.g. `.jpg`, `png`\r\n *\r\n * Returns the determined MIME type as a string. If the MIME type cannot be\r\n * determined, it returns `\"application/octet-stream\"`.\r\n *\r\n * @param params Object containing either string source, or source Buffer + extension type string.\r\n * @returns The complete mimetype if found, otherwise, fallbacks to default \"application/octet-stream\"\r\n *\r\n * @note This is already being tested on WhatsSocket.sugarsenders.test.ts!, doesn't need a standaole suite test\r\n *\r\n * @example\r\n * ```typescript\r\n * const type = MimeTypeHelper_GetMimeTypeOf({ source: \"file.png\" }); // \"image/png\"\r\n * ```\r\n */\r\nexport function MimeTypeHelper_GetMimeTypeOf(params: { source: string } | { source: Buffer; extensionType: string }): string {\r\n //1. First overload\r\n if (typeof params.source === \"string\") {\r\n //Can return false if not found. Bad library API in my opinion tbh\r\n const toReturn: string = _extractExtensionFrom_Path_Or_FileExtension(params.source);\r\n return toReturn;\r\n }\r\n\r\n //2. Second overload\r\n if (\"extensionType\" in params) {\r\n //Can return false if not found. Bad library API in my opinion tbh\r\n const toReturn: string = _extractExtensionFrom_Path_Or_FileExtension(params.extensionType);\r\n return toReturn;\r\n }\r\n\r\n //Default\r\n return DEFAULT_MIMETYPE;\r\n}\r\n","/**\r\n * # Normalize Literal String\r\n *\r\n * Normalizes a literal string by trimming unnecessary whitespace.\r\n *\r\n * - Removes leading and trailing whitespace from the entire string.\r\n * - Splits the string into lines and trims each line individually.\r\n * - Preserves empty lines (they are kept as `\"\"`, not removed).\r\n * - Rejoins the lines with `\"\\n\"` so the line structure is preserved.\r\n *\r\n * @example\r\n * Str_NormalizeLiteralString(\" hello \")\r\n * // => \"hello\"\r\n *\r\n * @example\r\n * Str_NormalizeLiteralString(\" line1 \\n line2 \\n\\n \")\r\n * // => \"line1\\nline2\\n\"\r\n *\r\n * @param str The input string to normalize. If `null` or `undefined`, returns an empty string.\r\n * @returns The normalized string with consistent whitespace handling.\r\n */\r\nexport function Str_NormalizeLiteralString(str: string): string {\r\n if (!str) return \"\";\r\n return str\r\n .trim()\r\n .split(\"\\n\")\r\n .map((line) => line.trim() || line)\r\n .join(\"\\n\");\r\n}\r\n","import { type MiscMessageGenerationOptions, type WAMessage } from \"baileys\";\r\nimport emojiRegexFabric from \"emoji-regex\";\r\nimport GraphemeSplitter from \"grapheme-splitter\";\r\nimport fs from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { MimeTypeHelper_GetMimeTypeOf, MimeTypeHelper_IsAudio, MimeTypeHelper_IsImage, MimeTypeHelper_IsVideo } from \"../../../helpers/Mimetypes.helper.js\";\r\nimport { Str_NormalizeLiteralString } from \"../../../helpers/Strings.helper.js\";\r\nimport { GetPath } from \"../../../libs/BunPath.js\";\r\nimport type { IWhatsSocket } from \"../IWhatsSocket.js\";\r\nimport type {\r\n IWhatsSocket_Submodule_SugarSender,\r\n WhatsMsgAudioOptions,\r\n WhatsMsgDocumentOptions,\r\n WhatsMsgMediaOptions,\r\n WhatsMsgPollOptions,\r\n WhatsMsgSenderSendingOptions,\r\n WhatsMsgSenderSendingOptionsMINIMUM,\r\n WhatsMsgUbicationOptions,\r\n} from \"./IWhatsSocket.sugarsender.js\";\r\n\r\nconst emojiRegex = emojiRegexFabric();\r\nconst emojiSplitter = new GraphemeSplitter();\r\n\r\n/**\r\n * # Sugar Sender Submodule\r\n *\r\n * A utility class for sending various types of WhatsApp messages with simplified APIs.\r\n * This class acts as a wrapper around the core WhatsApp socket functionality,\r\n * providing methods to send text, images, videos, audio, stickers, documents,\r\n * polls, locations, and contacts with proper validation and formatting.\r\n *\r\n * @remarks\r\n * - All methods support optional sending configurations, such as bypassing the\r\n * safe queue system or mentioning users.\r\n * - Media-related methods validate file existence and MIME types before sending.\r\n * - The class leverages Baileys' `MiscMessageGenerationOptions` for additional\r\n * message customization.\r\n *\r\n * @example\r\n * ```typescript\r\n * const sender = new WhatsSocket_Submodule_SugarSender(socket);\r\n * await sender.Text(\"123@s.whatsapp.net\", \"Hello World!\");\r\n * ```\r\n */\r\nexport class WhatsSocket_Submodule_SugarSender implements IWhatsSocket_Submodule_SugarSender {\r\n /** Strong dependency, needs to be inejcted from constructor */\r\n private socket: IWhatsSocket;\r\n\r\n /**\r\n * Initializes the SugarSender with a WhatsApp socket instance.\r\n *\r\n * @param socket - The WhatsApp socket instance used for sending messages.\r\n */\r\n constructor(socket: IWhatsSocket) {\r\n this.socket = socket;\r\n }\r\n\r\n public async Text(chatId: string, text: string, options?: WhatsMsgSenderSendingOptions) {\r\n if (typeof text !== \"string\" || text.trim() === \"\") {\r\n throw new Error(\r\n \"SugarSender.Text() received a non string text or an empty string to send, check that. Received instead: \" + JSON.stringify(text, null, 2)\r\n );\r\n }\r\n text = (options?.normalizeMessageText ?? true) ? Str_NormalizeLiteralString(text) : text;\r\n //_getSendingMethod() returns a functions, it seems cursed I know, get used to it\r\n return await this._getSendingMethod(options)(chatId, { text, mentions: options?.mentionsIds }, options as MiscMessageGenerationOptions);\r\n }\r\n\r\n public async Image(chatId: string, imageOptions: WhatsMsgMediaOptions, options?: WhatsMsgSenderSendingOptions): Promise<WAMessage | null> {\r\n let imgBuffer: Buffer;\r\n let mimeType: string;\r\n let isGif: boolean = false;\r\n //1. First overload: {sourcePath: string, caption?:string}\r\n if (typeof imageOptions.source === \"string\") {\r\n //1.1 Check if its a valid img type at least\r\n if (!MimeTypeHelper_IsImage(imageOptions.source)) {\r\n throw new Error(\"WhatsSocketSugarSender.Image() can't send a non IMAGE FILE!. What you were trying to send: \" + imageOptions.source);\r\n }\r\n\r\n //1.2 If using custom formatExtension, check if its a valid custom img valid format\r\n if (\"formatExtension\" in imageOptions) {\r\n if (!MimeTypeHelper_IsImage(imageOptions.formatExtension)) {\r\n throw new Error(\r\n `WhatsSockerSugarSender.Image(), you are sending a valid file, but you are trying to send it with custom extension which is not a file type => '${imageOptions.formatExtension}'`\r\n );\r\n }\r\n }\r\n\r\n //1.3 Proceed checking if img file to send exists\r\n if (!fs.existsSync(GetPath(imageOptions.source)) || !imageOptions.source || imageOptions.source.trim() === \"\") {\r\n throw new Error(\r\n \"Bad arguments: WhatsSocketSugarSender tried to send an img with incorrect path!, check again your img path\" + \" ImgPath: \" + imageOptions.source\r\n );\r\n }\r\n\r\n //Let's continue\r\n imgBuffer = fs.readFileSync(imageOptions.source);\r\n\r\n //@ts-expect-error Can be usable with formatExtension as well\r\n mimeType = imageOptions.formatExtension\r\n ? //@ts-expect-error Can be usable with formatExtension as well\r\n MimeTypeHelper_GetMimeTypeOf({ source: imageOptions.formatExtension })\r\n : MimeTypeHelper_GetMimeTypeOf({ source: imageOptions.source });\r\n isGif = mimeType === \"image/gif\";\r\n }\r\n //2. Second overload: {sourcePath: Buffer, caption?:string, formatExtension: string}\r\n else if (\"formatExtension\" in imageOptions) {\r\n imgBuffer = imageOptions.source;\r\n mimeType = MimeTypeHelper_GetMimeTypeOf({ source: imageOptions.source, extensionType: imageOptions.formatExtension });\r\n isGif = mimeType === \"image/gif\";\r\n } else {\r\n throw new Error(\r\n \"SugarSender.Img() bad args!, expected source in buffer or string with formatExtension prop if buffer... got instead: \" +\r\n JSON.stringify(imageOptions, null, 2)\r\n );\r\n }\r\n //Common overload logic\r\n let captionToSend: string | undefined = imageOptions.caption;\r\n if (captionToSend) {\r\n if (options?.normalizeMessageText) {\r\n captionToSend = Str_NormalizeLiteralString(captionToSend);\r\n }\r\n }\r\n // WhatsApp requires GIFs to be sent as videos with gifPlayback enabled\r\n if (isGif) {\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n image: imgBuffer,\r\n caption: captionToSend,\r\n gifPlayback: true,\r\n mentions: options?.mentionsIds,\r\n // mimetype: mimeType | For some reason it breaks if it includes a mimeType along with it (why? 🤓?)\r\n },\r\n options as MiscMessageGenerationOptions\r\n );\r\n }\r\n\r\n //Ends\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n image: imgBuffer,\r\n caption: captionToSend,\r\n mentions: options?.mentionsIds,\r\n mimetype: mimeType,\r\n },\r\n options as MiscMessageGenerationOptions\r\n );\r\n }\r\n\r\n public async ReactEmojiToMsg(\r\n chatId: string,\r\n rawMsgToReactTo: WAMessage,\r\n emojiStr: string,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WAMessage | null> {\r\n if (typeof emojiStr !== \"string\") {\r\n throw new Error(\"WhatsSocketSugarSender.ReactEmojiToMsg() received an non string emoji\");\r\n }\r\n const emojisCount: number = emojiSplitter.countGraphemes(emojiStr);\r\n if (emojisCount !== 1) {\r\n throw new Error(\r\n \"WhatsSocketSugarSender.ReactEmojiToMsg() received (less than 1 or greater than 2) chars as emoji to send.... It must be a simple emoji string of 1-2 emoji char length. Received instead: \" +\r\n emojiStr\r\n );\r\n }\r\n\r\n if (!emojiStr.match(emojiRegex)) {\r\n throw new Error(\"WhatsSocketSugarSender.ReactEmojiToMsg() received a non emoji reaction. Received instead: \" + emojiStr);\r\n }\r\n\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n react: {\r\n text: emojiStr,\r\n key: rawMsgToReactTo.key,\r\n },\r\n mentions: options?.mentionsIds,\r\n },\r\n options as MiscMessageGenerationOptions\r\n );\r\n }\r\n\r\n public async Sticker(chatId: string, stickerUrlSource: string | Buffer, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WAMessage | null> {\r\n if (typeof stickerUrlSource === \"string\") {\r\n if (!stickerUrlSource.endsWith(\".webp\")) {\r\n throw new Error(\"WhatsSocketSugarSender.Sticker() received a non .webp sticker to send. Must be in .webp format first!\");\r\n }\r\n if (!fs.existsSync(stickerUrlSource)) {\r\n throw new Error(\"WhatsSocketSugarSender.Sticker() coudn't find stickerUrlSource or it's invalid...\" + \"Url: \" + stickerUrlSource);\r\n }\r\n }\r\n\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n sticker: Buffer.isBuffer(stickerUrlSource)\r\n ? stickerUrlSource\r\n : {\r\n url: stickerUrlSource,\r\n },\r\n mentions: options?.mentionsIds,\r\n },\r\n options as MiscMessageGenerationOptions\r\n );\r\n }\r\n\r\n public async Audio(chatId: string, audioParams: WhatsMsgAudioOptions, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WAMessage | null> {\r\n let buffer: Buffer;\r\n let mimeType: string;\r\n //1. First overload: {source: string, caption?:string}\r\n if (typeof audioParams.source === \"string\") {\r\n if (!MimeTypeHelper_IsAudio(audioParams.source)) {\r\n throw new Error(\r\n \"Bad arguments: WhatsSocketSugarSender.Audio() received a non audio file to send (checked from extension format). Expected .mp3, .wav, and others but gotten instead: \" +\r\n audioParams.source\r\n );\r\n }\r\n\r\n if (\"formatExtension\" in audioParams) {\r\n if (!MimeTypeHelper_IsAudio(audioParams.formatExtension)) {\r\n throw new Error(\"Bad arguments: WhatsSocketSugarSender.Audio() received a non audio custom extension. Received: \" + audioParams.formatExtension);\r\n }\r\n }\r\n\r\n if (!fs.existsSync(GetPath(audioParams.source))) {\r\n throw new Error(\r\n \"Bad arguments: WhatsSocketSugarSender tried to send an img with incorrect path!, check again your img path\" +\r\n \" AudioSourcePath: \" +\r\n audioParams.source\r\n );\r\n }\r\n buffer = fs.readFileSync(audioParams.source);\r\n //@ts-expect-error Can be usable with format extension as well\r\n mimeType = audioParams.formatExtension\r\n ? //@ts-expect-error Can be usable with format extension as well\r\n MimeTypeHelper_GetMimeTypeOf({ source: audioParams.formatExtension })\r\n : MimeTypeHelper_GetMimeTypeOf({ source: audioParams.source });\r\n } else if (\"formatExtension\" in audioParams) {\r\n if (!MimeTypeHelper_IsAudio(audioParams.formatExtension)) {\r\n throw new Error(\r\n \"Bad args => SugarSender.Audio() received buffer and a non-video custom extension type. Extension type received: \" + audioParams.formatExtension\r\n );\r\n }\r\n\r\n buffer = audioParams.source;\r\n\r\n mimeType = MimeTypeHelper_GetMimeTypeOf({ source: audioParams.source, extensionType: audioParams.formatExtension as string });\r\n } else {\r\n throw new Error(\"SugarSender.Audio bad args, expected audio source in buffer or stringpath format. Got Instead: \" + JSON.stringify(audioParams, null, 2));\r\n }\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n audio: buffer,\r\n mimetype: mimeType,\r\n mentions: options?.mentionsIds,\r\n },\r\n options as MiscMessageGenerationOptions\r\n );\r\n }\r\n\r\n public async Video(chatId: string, videoParams: WhatsMsgMediaOptions, options?: WhatsMsgSenderSendingOptions): Promise<WAMessage | null> {\r\n let buffer: Buffer;\r\n let mimeType: string;\r\n\r\n //1. First overload: {source:string, caption?:string}\r\n if (typeof videoParams.source === \"string\") {\r\n if (!MimeTypeHelper_IsVideo(videoParams.source)) {\r\n throw new Error(\"Bad args: WhatsSugarSender.Video() received a non video file to send (checked from extension). Gotten instead: \" + videoParams.source);\r\n }\r\n\r\n if (\"formatExtension\" in videoParams) {\r\n if (!MimeTypeHelper_IsVideo(videoParams.formatExtension as string)) {\r\n throw new Error(\r\n \"Bad args: WhatsSugarSender.Video() received a NON custom video file format .extension. Given instead: \" + videoParams.formatExtension\r\n );\r\n }\r\n }\r\n\r\n if (!fs.existsSync(GetPath(videoParams.source))) {\r\n throw new Error(\"SugarSender.Video expected a valid video path!, doesn't exist... Got instead: \" + videoParams.source);\r\n }\r\n\r\n buffer = fs.readFileSync(videoParams.source);\r\n //@ts-expect-error Can be usable with format extension as well\r\n mimeType = videoParams.formatExtension\r\n ? //@ts-expect-error Can be usable with format extension as well\r\n MimeTypeHelper_GetMimeTypeOf({ source: videoParams.formatExtension })\r\n : MimeTypeHelper_GetMimeTypeOf({ source: videoParams.source });\r\n //2. Second overload: {source:Buffer, caption?: string, formatExtension: string}\r\n } else if (\"formatExtension\" in videoParams) {\r\n if (!MimeTypeHelper_IsVideo(videoParams.formatExtension)) {\r\n throw new Error(\r\n \"Bad args => SugarSender.Video() received a buffer with a NON image formatExtension (for mimetypes). FormatExtension provided: \" +\r\n videoParams.formatExtension\r\n );\r\n }\r\n buffer = videoParams.source;\r\n mimeType = MimeTypeHelper_GetMimeTypeOf({ source: videoParams.source, extensionType: videoParams.formatExtension });\r\n } else {\r\n throw new Error(\"SugarSender.Video bad args, expected video source in buffer or stringpath format. Got Instead: \" + JSON.stringify(videoParams, null, 2));\r\n }\r\n\r\n //Common overload logic code\r\n let caption: string | undefined = videoParams.caption;\r\n if (caption) {\r\n if (options?.normalizeMessageText) {\r\n caption = Str_NormalizeLiteralString(caption);\r\n }\r\n }\r\n //Default\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n video: buffer,\r\n caption: caption ?? \"\",\r\n mimetype: mimeType,\r\n mentions: options?.mentionsIds,\r\n },\r\n options\r\n );\r\n }\r\n\r\n public async Document(chatId: string, docParams: WhatsMsgDocumentOptions, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WAMessage | null> {\r\n let buffer: Buffer;\r\n let mimeType: string;\r\n let fileNameToDisplay: string;\r\n\r\n //1. First overload {source:string, caption?:string}\r\n if (typeof docParams.source === \"string\") {\r\n if (!fs.existsSync(GetPath(docParams.source))) {\r\n throw new Error(`SugarSender.Document(), received path document '${docParams.source}' doesn't exist!. Check again...`);\r\n }\r\n buffer = fs.readFileSync(docParams.source);\r\n mimeType = MimeTypeHelper_GetMimeTypeOf({ source: docParams.source });\r\n if (\"fileNameToDisplay\" in docParams) {\r\n // fileNameToDisplay = docParams.fileNameToDisplay ?? path.basename(docParams.source); //Gets file name WITH extension\r\n fileNameToDisplay =\r\n !docParams.fileNameToDisplay || docParams.fileNameToDisplay.trim() === \"\" ? path.basename(docParams.source) : docParams.fileNameToDisplay;\r\n } else {\r\n fileNameToDisplay = path.basename(docParams.source); //Gets file name WITH extension\r\n }\r\n //2. Second overload {source:Buffer, caption?: string, formatExtension:string}\r\n } else if (\"formatExtension\" in docParams) {\r\n buffer = docParams.source;\r\n mimeType = MimeTypeHelper_GetMimeTypeOf({ source: docParams.source, extensionType: docParams.formatExtension });\r\n fileNameToDisplay = docParams.fileNameWithoutExtension + \".\" + docParams.formatExtension.toLowerCase().replace(\".\", \"\");\r\n } else {\r\n throw new Error(\r\n \"SugarSender.Document bad args, expected document source in buffer or stringpath format. Got Instead: \" + JSON.stringify(docParams, null, 2)\r\n );\r\n }\r\n\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n document: buffer,\r\n mimetype: mimeType,\r\n fileName: fileNameToDisplay,\r\n mentions: options?.mentionsIds,\r\n },\r\n options\r\n );\r\n }\r\n\r\n public async Poll(\r\n chatId: string,\r\n pollTitle: string,\r\n selections: string[],\r\n pollParams: WhatsMsgPollOptions,\r\n moreOptions?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WAMessage | null> {\r\n let title: string = pollTitle;\r\n let selects: string[] = selections;\r\n\r\n if (!(selections.length >= 1 && selections.length <= 12)) {\r\n throw new Error(\r\n \"WhatsSocketSugarSender.Poll() received less than 1 options or greather than 12, must be in range 1-12. Received: \" + selections.length + \" options...\"\r\n );\r\n }\r\n\r\n if (pollParams.normalizeTitleText) {\r\n title = Str_NormalizeLiteralString(title);\r\n }\r\n\r\n if (pollParams.normalizeOptionsText) {\r\n selects = selections.map((opt) => Str_NormalizeLiteralString(opt));\r\n }\r\n\r\n for (let i = 0; i < selects.length; i++) {\r\n const selectionTxt = selects[i]!;\r\n if (selectionTxt.trim() === \"\") {\r\n throw new Error(`Bad Args: SugarSender.Poll(): Option ${i + 1} is empty string!, you can't send non-text options...`);\r\n }\r\n }\r\n\r\n return await this._getSendingMethod(moreOptions)(\r\n chatId,\r\n {\r\n poll: {\r\n name: title,\r\n values: selects,\r\n //Whats API receives 0 as multiple answers and 1 for exclusive 1 answer to polls (Thats how it works ¯\\_(ツ)_/¯)\r\n // selectableCount: pollParams.withMultiSelect ? 0 : 1\r\n selectableCount: selections.length,\r\n },\r\n mentions: moreOptions?.mentionsIds,\r\n },\r\n moreOptions as MiscMessageGenerationOptions\r\n );\r\n\r\n //INFO: Uncomment this section until discover a way to fetch votes data from polls, only sending porpuses so far.\r\n //Baileys library doesn't have any documentation at all to achieve this, so ill wait. - 20/august/2025\r\n\r\n // if (msgSent) {\r\n // const sugarPollObjToReturn = new WhatsPoll(this.socket, {\r\n // pollOptions: selects,\r\n // pollRawMsg: msgSent,\r\n // titleHeader: title,\r\n // withMultiSelect: pollParams.withMultiSelect\r\n // });\r\n\r\n // return sugarPollObjToReturn;\r\n // } else {\r\n // return null;\r\n // }\r\n }\r\n\r\n public async Location(chatId: string, ubicationParams: WhatsMsgUbicationOptions, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WAMessage | null> {\r\n if (!areValidCoordinates(ubicationParams.degreesLatitude, ubicationParams.degreesLongitude)) {\r\n throw new Error(\r\n `WhatsSocketSugarSender.Ubication() => Invalid coordinates: (${ubicationParams.degreesLatitude}, ${ubicationParams.degreesLongitude}).Latitude must be between -90 and 90, longitude between -180 and 180.`\r\n );\r\n }\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n location: {\r\n degreesLatitude: ubicationParams.degreesLatitude,\r\n degreesLongitude: ubicationParams.degreesLongitude,\r\n name: ubicationParams.name,\r\n address: ubicationParams.addressText,\r\n },\r\n mentions: options?.mentionsIds,\r\n },\r\n options as MiscMessageGenerationOptions\r\n );\r\n }\r\n\r\n public async Contact(\r\n chatId: string,\r\n contacts: { name: string; phone: string } | Array<{ name: string; phone: string }>,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WAMessage | null> {\r\n const arr = Array.isArray(contacts) ? contacts : [contacts];\r\n\r\n const vCards = arr.map((c) => {\r\n if (!c.name || !c.phone) {\r\n throw new Error(\"Invalid contact: name and phone are required\");\r\n }\r\n return `BEGIN:VCARD\r\nVERSION:3.0\r\nFN:${c.name}\r\nTEL;type=CELL;type=VOICE;waid=${c.phone}:${c.phone}\r\nEND:VCARD`;\r\n });\r\n\r\n return await this._getSendingMethod(options)(\r\n chatId,\r\n {\r\n contacts: {\r\n displayName: arr.length === 1 ? arr[0]!.name : `${arr.length} contacts`,\r\n contacts: vCards.map((vc) => ({ vcard: vc })),\r\n },\r\n mentions: options?.mentionsIds,\r\n },\r\n options as MiscMessageGenerationOptions\r\n );\r\n }\r\n\r\n /**\r\n * Selects the sending method based on the options provided.\r\n *\r\n * If `options` is not provided or `sendRawWithoutEnqueue` is false,\r\n * the safe queue system will be used to send the message.\r\n *\r\n * If `options.sendRawWithoutEnqueue` is true, the message will be\r\n * sent immediately without using the safe queue system.\r\n *\r\n * @param options - The sending options, or undefined to use the default behavior.\r\n * @returns The method to call to send the message.\r\n */\r\n private _getSendingMethod(options?: WhatsMsgSenderSendingOptionsMINIMUM) {\r\n if (!options) return this.socket._SendSafe;\r\n else if (options.sendRawWithoutEnqueue) {\r\n return this.socket._SendRaw;\r\n } else {\r\n return this.socket._SendSafe;\r\n }\r\n }\r\n}\r\n\r\nfunction areValidCoordinates(lat: number, lon: number): boolean {\r\n return typeof lat === \"number\" && typeof lon === \"number\" && lat >= -90 && lat <= 90 && lon >= -180 && lon <= 180;\r\n}\r\n\r\n//Buffer is only used to differentiate type params, still needed for intelissense!\r\n","import type { Boom } from \"@hapi/boom\";\r\nimport {\r\n type AnyMessageContent,\r\n type GroupMetadata,\r\n type MiscMessageGenerationOptions,\r\n type WAMessageUpdate,\r\n DisconnectReason,\r\n fetchLatestBaileysVersion,\r\n makeWASocket,\r\n useMultiFileAuthState,\r\n} from \"baileys\";\r\n\r\nimport moment from \"moment\";\r\nimport pino from \"pino\";\r\nimport encodeQr from \"qr\";\r\nimport { MsgHelper_FullMsg_GetMsgType, MsgHelper_FullMsg_GetSenderType } from \"../../helpers/Msg.helper.js\";\r\nimport { GetPath } from \"../../libs/BunPath.js\";\r\nimport Delegate from \"../../libs/Delegate.js\";\r\nimport type { MsgType } from \"../../Msg.types.js\";\r\nimport { SenderType } from \"../../Msg.types.js\";\r\nimport { WhatsappGroupIdentifier, WhatsappPhoneNumberIdentifier } from \"../../Whatsapp.types.js\";\r\nimport { WhatsSocket_Submodule_Receiver } from \"./internals/WhatsSocket.receiver.js\";\r\nimport WhatsSocketSenderQueue_SubModule from \"./internals/WhatsSocket.senderqueue.js\";\r\nimport { WhatsSocket_Submodule_SugarSender } from \"./internals/WhatsSocket.sugarsenders.js\";\r\nimport type { IWhatsSocket } from \"./IWhatsSocket.js\";\r\nimport type { WhatsappMessage, WhatsSocketLoggerMode } from \"./types.js\";\r\nimport type { IWhatsSocketServiceAdapter } from \"./WhatsSocket.types.js\";\r\n\r\n/**\r\n * # WhatsApp Socket Options\r\n *\r\n * Configuration options for the WhatsApp Socket behavior.\r\n *\r\n * @example\r\n * ```typescript\r\n * const options: WhatsSocketOptions = { loggerMode: \"silent\", maxReconnectionRetries: 3 };\r\n * ```\r\n */\r\nexport type WhatsSocketOptions = {\r\n /**\r\n * Determines the logging level of the WhatsSocket instance.\r\n * - \"debug\": full details for troubleshooting.\r\n * - \"silent\": minimal output (no logs).\r\n *\r\n * @default \"debug\"\r\n */\r\n loggerMode?: WhatsSocketLoggerMode;\r\n\r\n /**\r\n * Path to the folder where authentication credentials are stored.\r\n * Can be relative to the project root or the current working directory.\r\n *\r\n * @default \"./auth\"\r\n */\r\n credentialsFolder?: string;\r\n\r\n /**\r\n * Maximum number of reconnection attempts if the socket encounters errors.\r\n *\r\n * @default 5\r\n */\r\n maxReconnectionRetries?: number;\r\n\r\n /**\r\n * If true, the socket ignores messages sent by itself, so they won't trigger\r\n * the 'onIncomingMessage' event.\r\n *\r\n * @default true\r\n */\r\n ignoreSelfMessage?: boolean;\r\n\r\n /**\r\n * Maximum number of messages that can be queued for sending globally.\r\n * Useful for buffering pending messages if the bot receives many messages\r\n * in a short time.\r\n *\r\n * @default 20\r\n */\r\n senderQueueMaxLimit?: number;\r\n\r\n /**\r\n * Delay (in milliseconds) between sending queued messages.\r\n * Helps prevent spamming or flooding when sending many messages rapidly.\r\n *\r\n * @default 100\r\n */\r\n delayMilisecondsBetweenMsgs?: number;\r\n\r\n /**\r\n * Optionally provide a custom implementation of the WhatsApp socket API.\r\n * By default, Baileys is used.\r\n *\r\n * @note Primarily intended for testing. Use at your own risk if you override.\r\n */\r\n ownImplementationSocketAPIWhatsapp?: IWhatsSocketServiceAdapter;\r\n};\r\n\r\n/**\r\n * # WhatsApp Socket Core\r\n *\r\n * Class used to interact with the WhatsApp Web socket client (baileys).\r\n * Will start the socket and keep it connected until you call the Shutdown method.\r\n * Provides some events you can subscribe to, to get notified when different things happen.\r\n *\r\n * @example\r\n * ```typescript\r\n * const socket = new WhatsSocket({\r\n * credentialsFolder: \"./auth\",\r\n * loggerMode: \"silent\",\r\n * maxReconnectionRetries: 5,\r\n * ignoreSelfMessage: true\r\n * });\r\n *\r\n * socket.onIncomingMsg.Subscribe((senderId, chatId, rawMsg, msgType, senderType) => {\r\n * console.log(`Msg: ${msgType} | SenderId: ${senderId}`);\r\n * });\r\n *\r\n * socket.Start().then(() => {\r\n * console.log(\"WhatsSocket initialized successfully!\");\r\n * }).catch((error) => {\r\n * console.error(\"Error initializing WhatsSocket:\", error);\r\n * });\r\n * ```\r\n */\r\nexport default class WhatsSocket implements IWhatsSocket {\r\n //All documentation comes from \"IWhatsSocket\" interface, check it to see docs about this events\r\n public onIncomingMsg: Delegate<\r\n (senderId_LID: string | null, sender_PN: string | null, chatId: string, rawMsg: WhatsappMessage, msgType: MsgType, senderType: SenderType) => void\r\n > = new Delegate();\r\n\r\n public onUpdateMsg: Delegate<\r\n (senderId_LID: string | null, senderId_PN: string | null, chatId: string, rawMsgUpdate: WhatsappMessage, msgType: MsgType, senderType: SenderType) => void\r\n > = new Delegate();\r\n\r\n public onSentMessage: Delegate<(chatId: string, rawContentMsg: AnyMessageContent, optionalMisc?: MiscMessageGenerationOptions) => void> = new Delegate();\r\n public onRestart: Delegate<() => Promise<void>> = new Delegate();\r\n public onGroupEnter: Delegate<(groupInfo: GroupMetadata) => void> = new Delegate();\r\n public onGroupUpdate: Delegate<(groupInfo: Partial<GroupMetadata>) => void> = new Delegate();\r\n public onStartupAllGroupsIn: Delegate<(allGroupsIn: GroupMetadata[]) => void> = new Delegate();\r\n\r\n public get ownJID(): string {\r\n return this.Socket.user!.id;\r\n }\r\n\r\n //=== Subcomponents ===\r\n //They're initialized/instantiated in \"Start()\"\r\n public Socket!: IWhatsSocketServiceAdapter;\r\n private _senderQueue!: WhatsSocketSenderQueue_SubModule;\r\n /**\r\n * Sender module and sugar layer for sending all kinds of msgs.\r\n * Text, Images, Videos, Polls, etc...\r\n */\r\n public Send!: WhatsSocket_Submodule_SugarSender;\r\n\r\n /**\r\n * Receive internal module. To wait for someone msg's.\r\n */\r\n public Receive!: WhatsSocket_Submodule_Receiver;\r\n\r\n // === Normal Public Properties ===\r\n public ActualReconnectionRetries: number = 0;\r\n\r\n // === Configuration Properties ===\r\n private _loggerMode: WhatsSocketLoggerMode;\r\n private _credentialsFolder: string;\r\n private _ignoreSelfMessages: boolean;\r\n private _maxReconnectionRetries: number;\r\n private _senderQueueMaxLimit: number;\r\n private _milisecondsDelayBetweenSentMsgs: number;\r\n private _customSocketImplementation?: IWhatsSocketServiceAdapter;\r\n\r\n constructor(options?: WhatsSocketOptions) {\r\n this._loggerMode = options?.loggerMode ?? \"silent\";\r\n this._credentialsFolder = options?.credentialsFolder ?? \"./auth\";\r\n this._ignoreSelfMessages = options?.ignoreSelfMessage ?? true;\r\n this._senderQueueMaxLimit = options?.senderQueueMaxLimit ?? 20;\r\n this._milisecondsDelayBetweenSentMsgs = options?.delayMilisecondsBetweenMsgs ?? 100;\r\n this._customSocketImplementation = options?.ownImplementationSocketAPIWhatsapp;\r\n this._maxReconnectionRetries = options?.maxReconnectionRetries ?? 5;\r\n }\r\n private _isRestarting: boolean = false;\r\n\r\n /**\r\n * Initializes the WhatsSocket instance and start connecting to Whatsapp.\r\n * After this method is called, the socket will be listening for incoming messages and events all the time.\r\n * Can be canceled and shutdown by calling the `Shutdown` method.\r\n * @returns A promise that will be running in the background all the time until the socket is closed.\r\n */\r\n public async Start(): Promise<void> {\r\n this.ActualReconnectionRetries = 0;\r\n await this._initializeSelf();\r\n }\r\n\r\n /**\r\n * Restarts the socket by shutting down current one and then starting a new instance, effectively \"restarting\" the socket.\r\n * @returns A promise that will be running in the background all the time until the socket is closed.\r\n */\r\n public async Restart(): Promise<void> {\r\n this._isRestarting = true;\r\n await this.Shutdown();\r\n await this._initializeSelf();\r\n this._isRestarting = false;\r\n }\r\n\r\n private async _initializeSelf(): Promise<void> {\r\n await this.InitializeInternalSocket();\r\n this.ConfigureReconnection();\r\n this.ConfigureMessageIncoming();\r\n this.ConfigureMessagesUpdates();\r\n this.ConfigureGroupsEnter();\r\n this.ConfigureGroupsUpdates();\r\n\r\n //Thanks JavaScript ☠️\r\n this._SendSafe = this._SendSafe.bind(this);\r\n this._SendRaw = this._SendRaw.bind(this);\r\n this.GetRawGroupMetadata = this.GetRawGroupMetadata.bind(this);\r\n this.InitializeInternalSocket = this.InitializeInternalSocket.bind(this);\r\n this.Start = this.Start.bind(this);\r\n this.Shutdown = this.Shutdown.bind(this);\r\n this._initializeSelf = this._initializeSelf.bind(this);\r\n this.ConfigureReconnection = this.ConfigureReconnection.bind(this);\r\n this.ConfigureMessageIncoming = this.ConfigureMessageIncoming.bind(this);\r\n this.ConfigureGroupsEnter = this.ConfigureGroupsEnter.bind(this);\r\n this.ConfigureGroupsUpdates = this.ConfigureGroupsUpdates.bind(this);\r\n }\r\n\r\n private async InitializeInternalSocket() {\r\n const authInfoPath: string = GetPath(this._credentialsFolder);\r\n const { state, saveCreds } = await useMultiFileAuthState(authInfoPath);\r\n\r\n const { version } = await fetchLatestBaileysVersion(); //1. I've added this line\r\n if (this._customSocketImplementation) {\r\n this.Socket = this._customSocketImplementation;\r\n } else {\r\n const logger = pino({ level: this._loggerMode === \"recommended\" ? \"silent\" : this._loggerMode });\r\n this.Socket = await makeWASocket({\r\n version, //2. Then added \"version\" prop in Socket constructor\r\n auth: state,\r\n logger: logger,\r\n // browser: Browsers.windows(\"Chrome\"),\r\n // syncFullHistory: true,\r\n });\r\n }\r\n this.Socket.ev.on(\"creds.update\", saveCreds);\r\n\r\n //== Initializing internal sub-modules ==\r\n this._senderQueue = new WhatsSocketSenderQueue_SubModule(this, this._senderQueueMaxLimit, this._milisecondsDelayBetweenSentMsgs);\r\n this.Send = new WhatsSocket_Submodule_SugarSender(this);\r\n this.Receive = new WhatsSocket_Submodule_Receiver(this);\r\n }\r\n\r\n public async Shutdown() {\r\n await this.Socket.ws.close();\r\n }\r\n\r\n private ConfigureReconnection(): void {\r\n this.Socket.ev.on(\"connection.update\", async (update) => {\r\n const { connection, lastDisconnect, qr } = update;\r\n\r\n // Show QR code if needed\r\n if (qr) {\r\n console.log(\"[Whatsbotcord]: ⌛ Logging in. Scan this qr code to get started!\");\r\n console.log(encodeQr(qr, \"ascii\"));\r\n }\r\n\r\n // Successfully connected\r\n if (connection === \"open\") {\r\n this.ActualReconnectionRetries = 0; // reset retries\r\n try {\r\n if (this._loggerMode !== \"silent\") {\r\n console.log(\"[Whatsbotcord]: ✅ Connected to whatsapp servers\");\r\n }\r\n const groups = Object.values(await this.Socket.groupFetchAllParticipating());\r\n this.onStartupAllGroupsIn.CallAll(groups);\r\n if (this._loggerMode !== \"silent\") {\r\n console.log(\"[Whatsbotcord]: 💬 All groups metadata fetched successfully\");\r\n }\r\n } catch (err) {\r\n if (this._loggerMode !== \"silent\") {\r\n console.error(\"[Whatsbotcord]: ❌ ERROR: Couldn't fetch groups\", err);\r\n }\r\n }\r\n }\r\n\r\n // Connection closed\r\n if (connection === \"close\") {\r\n const error = lastDisconnect?.error as Boom | undefined;\r\n const statusCode = error?.output?.statusCode;\r\n\r\n // Only attempt to reconnect if not logged out\r\n const shouldReconnect = statusCode !== DisconnectReason.loggedOut;\r\n if (this._loggerMode !== \"silent\") {\r\n console.warn(\"[Whatsbotcord]: ❌ Socket closed\", statusCode ? `(code: ${statusCode})` : \"\");\r\n }\r\n\r\n if (!shouldReconnect) {\r\n if (this._loggerMode !== \"silent\") {\r\n console.error(\"[Whatsbotcord]: ❌ ERROR: Socket logged out. Not reconnecting.\");\r\n }\r\n await this.Shutdown();\r\n return;\r\n }\r\n\r\n // Increment retries immediately\r\n this.ActualReconnectionRetries++;\r\n\r\n // Check max retries\r\n if (this.ActualReconnectionRetries > this._maxReconnectionRetries) {\r\n if (this._loggerMode !== \"silent\") {\r\n console.error(`[Whatsbotcord]: ❌ ERROR: Max reconnection attempts reached (${this._maxReconnectionRetries}). Giving up.`);\r\n }\r\n await this.Shutdown();\r\n return;\r\n }\r\n\r\n // Prevent overlapping restarts\r\n if (this._isRestarting) return;\r\n\r\n this._isRestarting = true;\r\n if (this._loggerMode !== \"silent\") {\r\n console.log(`[Whatsbotcord]: ❌ INFO: Restarting socket (attempt ${this.ActualReconnectionRetries}/${this._maxReconnectionRetries})...`);\r\n }\r\n\r\n try {\r\n await this.Restart();\r\n this.onRestart.CallAll();\r\n if (this._loggerMode !== \"silent\") {\r\n console.log(\"[Whatsbotcord]: ❌ INFO: Socket restarted successfully!\");\r\n }\r\n } catch (err) {\r\n if (this._loggerMode !== \"silent\") {\r\n console.error(\"[Whatsbotcord]: ❌ ERROR: Socket restart failed\", err);\r\n }\r\n } finally {\r\n this._isRestarting = false;\r\n }\r\n }\r\n });\r\n }\r\n\r\n private ConfigureMessageIncoming(): void {\r\n this.Socket.ev.on(\"messages.upsert\", async (messageUpdate) => {\r\n if (!messageUpdate.messages) return;\r\n for (const msgAny of messageUpdate.messages) {\r\n const msg = msgAny as WhatsappMessage;\r\n if (this._ignoreSelfMessages) if (!msg.message || msg.key.fromMe) continue;\r\n const chatId = msg.key.remoteJid!;\r\n const senderId_LID: string | null = msg.key.participant ? (msg.key.participant.trim() !== \"\" ? msg.key.participant : null) : null;\r\n const senderId_PN: string | null = msg.key.participantAlt ? (msg.key.participantAlt.trim() !== \"\" ? msg.key.participantAlt : null) : null;\r\n let senderType: SenderType = SenderType.Unknown;\r\n if (chatId && chatId.endsWith(WhatsappGroupIdentifier)) senderType = SenderType.Group;\r\n if (chatId && chatId.endsWith(WhatsappPhoneNumberIdentifier)) senderType = SenderType.Individual;\r\n this.onIncomingMsg.CallAll(senderId_LID, senderId_PN, chatId, msg, MsgHelper_FullMsg_GetMsgType(msg), senderType);\r\n }\r\n });\r\n }\r\n\r\n private ConfigureMessagesUpdates(): void {\r\n this.Socket.ev.on(\"messages.update\", (msgsUpdates: WAMessageUpdate[]) => {\r\n if (!msgsUpdates || msgsUpdates.length === 0) return;\r\n for (const msgUpdateRaw of msgsUpdates) {\r\n const msgUpdate = msgUpdateRaw as WhatsappMessage;\r\n if (this._ignoreSelfMessages) if (msgUpdate.key.fromMe) return;\r\n\r\n const senderType: SenderType = MsgHelper_FullMsg_GetSenderType(msgUpdate);\r\n const chatId: string = msgUpdate.key.remoteJid!;\r\n const senderId_LID: string | null = msgUpdate.key.participant ? (msgUpdate.key.participant.trim() !== \"\" ? msgUpdate.key.participant : null) : null;\r\n const senderId_PN: string | null = msgUpdate.key.participantAlt ? (msgUpdate.key.participantAlt !== \"\" ? msgUpdate.key.participantAlt : null) : null;\r\n this.onUpdateMsg.CallAll(senderId_LID, senderId_PN, chatId, msgUpdate, MsgHelper_FullMsg_GetMsgType(msgUpdate), senderType);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Gets the metadata of a group chat by its chat ID. (e.g: \"23423423123@g.us\")\r\n * @param chatId The chat ID of the group you want to get metadata from.\r\n * @throws Will throw an error if the provided chatId is not a group chat ID\r\n * @returns A promise that resolves to the group metadata.\r\n */\r\n public async GetRawGroupMetadata(chatId: string): Promise<GroupMetadata> {\r\n if (!chatId.endsWith(WhatsappGroupIdentifier))\r\n throw new Error(\"Bad args => WhatsSocket.GetGroupMetadata() => Provided chatId is not a group chat ID. => \" + chatId);\r\n return await this.Socket.groupMetadata(chatId);\r\n }\r\n\r\n private ConfigureGroupsEnter(): void {\r\n this.Socket.ev.on(\"groups.upsert\", async (groupsUpserted: GroupMetadata[]) => {\r\n for (const group of groupsUpserted) {\r\n this.onGroupEnter.CallAll(group);\r\n if (this._loggerMode !== \"silent\") {\r\n console.info(`INFO: Joined to a new group ${group.subject} at ${moment().format(\"YYYY-MM-DD HH:mm:ss\")}`);\r\n }\r\n }\r\n });\r\n }\r\n\r\n private ConfigureGroupsUpdates(): void {\r\n this.Socket.ev.on(\"groups.update\", (args) => {\r\n if (args.length === 0) {\r\n if (this._loggerMode !== \"silent\") {\r\n console.log(\"INFO: No group updates received.\");\r\n }\r\n return;\r\n }\r\n for (let i = 0; i < args.length; i++) {\r\n const groupMetadata: Partial<GroupMetadata> | undefined = args[i];\r\n if (groupMetadata) {\r\n this.onGroupUpdate.CallAll(groupMetadata);\r\n }\r\n }\r\n });\r\n }\r\n\r\n public async _SendSafe(chatId_JID: string, content: AnyMessageContent, options?: MiscMessageGenerationOptions): Promise<WhatsappMessage | null> {\r\n return this._senderQueue.Enqueue(chatId_JID, content, options);\r\n }\r\n\r\n public async _SendRaw(chatId_JID: string, content: AnyMessageContent, options?: MiscMessageGenerationOptions): Promise<WhatsappMessage | null> {\r\n const toReturn = (await this.Socket.sendMessage(chatId_JID, content, options)) ?? null;\r\n return toReturn;\r\n }\r\n}\r\n","import { downloadMediaMessage } from \"baileys\";\r\nimport { autobind } from \"../../../helpers/Decorators.helper.js\";\r\nimport { MsgHelper_FullMsg_GetSenderType, MsgHelper_FullMsg_GetText } from \"../../../helpers/Msg.helper.js\";\r\nimport { MsgType, SenderType } from \"../../../Msg.types.js\";\r\nimport { WhatsappLIDIdentifier, WhatsappPhoneNumberIdentifier } from \"../../../Whatsapp.types.js\";\r\nimport type { IWhatsSocket_Submodule_Receiver } from \"../../whats_socket/internals/IWhatsSocket.receiver.js\";\r\nimport type {\r\n IWhatsSocket_Submodule_SugarSender,\r\n WhatsMsgPollOptions,\r\n WhatsMsgSenderSendingOptions,\r\n WhatsMsgSenderSendingOptionsMINIMUM,\r\n} from \"../../whats_socket/internals/IWhatsSocket.sugarsender.js\";\r\nimport {\r\n type GroupMetadataInfo,\r\n type WhatsSocketReceiverWaitOptions,\r\n WhatsSocketReceiverHelper_isReceiverError,\r\n} from \"../../whats_socket/internals/WhatsSocket.receiver.js\";\r\nimport type { WhatsappMessage } from \"../../whats_socket/types.js\";\r\nimport type {\r\n ChatContextContactRes,\r\n ChatContextUbication,\r\n IChatContext,\r\n IChatContext_CloneTargetedTo_FromIds_GROUP_Params,\r\n IChatContext_CloneTargetedTo_FromIds_Individual_Params,\r\n IChatContext_CloneTargetedTo_FromWhatsmsg_Params,\r\n IChatContext_WaitYesOrNoAnswer_Params,\r\n} from \"./IChatContext.js\";\r\n\r\n/**\r\n * # Chat Context Configuration\r\n *\r\n * Extra configuration properties for the Chat Context initializing.\r\n *\r\n * @example\r\n * ```typescript\r\n * const config: IChatContextConfig = { timeoutSeconds: 30 };\r\n * ```\r\n */\r\nexport type IChatContextConfig = WhatsSocketReceiverWaitOptions & {\r\n /**\r\n * Used primarly in mocking system\r\n */\r\n explicitSenderType?: SenderType;\r\n\r\n /**\r\n * Default keywords to be interpreted as an affirmative (\"yes\") response\r\n * in `WaitYesOrNoAnswer`. Case-insensitive.\r\n *\r\n * @default [\"yes\", \"y\", \"si\", \"s\", \"ok\", \"vale\", \"sí\"]\r\n */\r\n positiveAnswerOptions?: string[];\r\n\r\n /**\r\n * Default keywords to be interpreted as a negative (\"no\") response\r\n * in `WaitYesOrNoAnswer`. Case-insensitive.\r\n *\r\n * @default [\"no\", \"n\"]\r\n */\r\n negativeAnswerOptions?: string[];\r\n};\r\n\r\n/**\r\n * # Chat Context\r\n *\r\n * A sugar-layer abstraction for sending/receiving msgs bound to the actual chat.\r\n *\r\n * This class simplifies sending messages and reactions to a fixed chat\r\n * without needing to repeatedly provide the chat ID. It also provides\r\n * helpers for common bot patterns like reacting with checkmarks or crosses to the\r\n * initial message and other common high-level utilities.\r\n *\r\n * @example\r\n * ```typescript\r\n * await ctx.SendText(\"Hello\");\r\n * ```\r\n */\r\nexport class ChatContext implements IChatContext {\r\n /**\r\n * Low-level sender dependency responsible for dispatching\r\n * messages, reactions, edits, and other outbound events.\r\n *\r\n * This is an internal utility—use higher-level convenience\r\n * methods instead of calling this directly where possible.\r\n */\r\n private _internalSend: IWhatsSocket_Submodule_SugarSender;\r\n\r\n /**\r\n * Low-level receiver dependency responsible for listening\r\n * to incoming WhatsApp events (messages, status updates, etc).\r\n *\r\n * Exposed internally so that session features can react to\r\n * real-time events within the same chat context.\r\n */\r\n private _internalReceive: IWhatsSocket_Submodule_Receiver;\r\n\r\n public readonly FixedParticipantPN: string | null;\r\n\r\n public readonly FixedParticipantLID: string | null;\r\n\r\n public readonly FixedChatId: string;\r\n\r\n public InitialMsg: WhatsappMessage | null;\r\n\r\n public readonly FixedSenderType: SenderType;\r\n\r\n public Config: IChatContextConfig;\r\n\r\n /**\r\n * Creates a new chat session bound to a specific chat and initial message.\r\n *\r\n * @param participantID_LID - The ID of the participant that triggered this session,\r\n * or `null` if the origin cannot be determined.\r\n * @param fixedChatId - The WhatsApp chat JID this context is tied to.\r\n * @param initialMsg - The original message object that caused this context to spawn.\r\n * @param senderDependency - Internal sender utility for dispatching messages.\r\n * @param receiverDependency - Internal receiver utility for subscribing to events.\r\n * @param config - Context configuration controlling runtime behavior.\r\n *\r\n * @remarks\r\n * - All `Fixed*` properties are immutable once the context is created.\r\n * - The context is designed to encapsulate state and metadata for a\r\n * single session, preventing accidental leakage between chats.\r\n */\r\n constructor(\r\n participantID_LID: string | null,\r\n participantID_PN: string | null,\r\n fixedChatId: string,\r\n initialMsg: WhatsappMessage | null,\r\n senderDependency: IWhatsSocket_Submodule_SugarSender,\r\n receiverDependency: IWhatsSocket_Submodule_Receiver,\r\n config: IChatContextConfig\r\n ) {\r\n this.Config = config;\r\n this.FixedParticipantLID = participantID_LID;\r\n this.FixedParticipantPN = participantID_PN;\r\n this._internalSend = senderDependency;\r\n this._internalReceive = receiverDependency;\r\n this.FixedChatId = fixedChatId;\r\n this.InitialMsg = initialMsg;\r\n this.FixedSenderType = config.explicitSenderType ?? (this.InitialMsg !== null ? MsgHelper_FullMsg_GetSenderType(this.InitialMsg) : SenderType.Individual);\r\n\r\n this.WaitText = this.WaitText.bind(this);\r\n }\r\n\r\n @autobind\r\n public Clone(): IChatContext {\r\n return new ChatContext(\r\n this.FixedParticipantLID,\r\n this.FixedParticipantPN,\r\n this.FixedChatId,\r\n this.InitialMsg,\r\n this._internalSend,\r\n this._internalReceive,\r\n this.Config\r\n );\r\n }\r\n\r\n @autobind\r\n public CloneButTargetedToWithInitialMsg(params: IChatContext_CloneTargetedTo_FromWhatsmsg_Params): IChatContext {\r\n const keysData = params.initialMsg.key;\r\n\r\n let ID_PN: string | null = null;\r\n let ID_LID: string | null = null;\r\n\r\n //Neccesary due to how bailey.js library works. Check update to v7.0.0 on their official page to understand this\r\n if (keysData.participant) {\r\n if (keysData.participant.endsWith(WhatsappLIDIdentifier)) {\r\n ID_LID = keysData.participant;\r\n } else if (keysData.participant.endsWith(WhatsappPhoneNumberIdentifier)) {\r\n ID_PN = keysData.participant;\r\n }\r\n }\r\n\r\n if (keysData.participantAlt) {\r\n if (keysData.participantAlt.endsWith(WhatsappLIDIdentifier)) {\r\n ID_LID = keysData.participantAlt;\r\n } else if (keysData.participantAlt.endsWith(WhatsappPhoneNumberIdentifier)) {\r\n ID_PN = keysData.participantAlt;\r\n }\r\n }\r\n\r\n //prettier-ignore\r\n return new ChatContext(\r\n ID_LID,\r\n ID_PN,\r\n params.initialMsg.key.remoteJid!,\r\n params.initialMsg,\r\n this._internalSend,\r\n this._internalReceive,\r\n params?.newConfig ?? this.Config\r\n );\r\n }\r\n\r\n @autobind\r\n public CloneButTargetedToIndividualChat(params: IChatContext_CloneTargetedTo_FromIds_Individual_Params): IChatContext {\r\n const configCopy: IChatContextConfig = structuredClone(this.Config);\r\n //Case: For individual chats\r\n if (this.FixedSenderType === SenderType.Group) {\r\n configCopy.explicitSenderType = SenderType.Individual;\r\n }\r\n //prettier-ignore\r\n return new ChatContext(\r\n null,\r\n null,\r\n params.userChatId,\r\n this.InitialMsg,\r\n this._internalSend,\r\n this._internalReceive,\r\n {...configCopy, ...params.newConfig}\r\n );\r\n }\r\n\r\n @autobind\r\n public CloneButTargetedToGroupChat(params: IChatContext_CloneTargetedTo_FromIds_GROUP_Params): IChatContext {\r\n const configCopy: IChatContextConfig = structuredClone(this.Config);\r\n if (this.FixedSenderType === SenderType.Individual) {\r\n configCopy.explicitSenderType = SenderType.Group;\r\n }\r\n //prettier-ignore\r\n return new ChatContext(\r\n params.participant_LID ?? this.FixedParticipantLID,\r\n params.participant_PN ?? this.FixedParticipantPN,\r\n params.groupChatId,\r\n this.InitialMsg,\r\n this._internalSend,\r\n this._internalReceive,\r\n {...configCopy, ...params.newConfig}\r\n );\r\n }\r\n\r\n private async HandlePrimaryMsg(mainMsgPromise: Promise<WhatsappMessage | null>): Promise<WhatsappMessage | null> {\r\n const msg: WhatsappMessage | null = await mainMsgPromise;\r\n if (!msg) return null;\r\n if (!this.InitialMsg) {\r\n this.InitialMsg = msg;\r\n }\r\n return msg;\r\n }\r\n\r\n @autobind\r\n public SendText(text: string, options?: WhatsMsgSenderSendingOptions): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Text(this.FixedChatId, text, options));\r\n }\r\n\r\n @autobind\r\n public async SendImg(imagePath: string, options?: WhatsMsgSenderSendingOptions): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Image(this.FixedChatId, { source: imagePath, caption: undefined }, options));\r\n }\r\n\r\n @autobind\r\n public SendImgWithCaption(imagePath: string, caption: string, options?: WhatsMsgSenderSendingOptions): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Image(this.FixedChatId, { source: imagePath, caption }, options));\r\n }\r\n\r\n @autobind\r\n public SendImgFromBuffer(\r\n imagePath: Buffer | Buffer<ArrayBuffer>,\r\n extensionType: string,\r\n options?: WhatsMsgSenderSendingOptions\r\n ): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(\r\n this._internalSend.Image(this.FixedChatId, { source: imagePath, formatExtension: extensionType, caption: undefined }, options)\r\n );\r\n }\r\n\r\n @autobind\r\n public SendImgFromBufferWithCaption(\r\n imagePath: Buffer,\r\n extensionType: string,\r\n caption: string,\r\n options?: WhatsMsgSenderSendingOptions\r\n ): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Image(this.FixedChatId, { source: imagePath, formatExtension: extensionType, caption: caption }, options));\r\n }\r\n\r\n @autobind\r\n public SendReactEmojiTo(msgToReactTo: WhatsappMessage, emojiStr: string, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n return this._internalSend.ReactEmojiToMsg(this.FixedChatId, msgToReactTo, emojiStr, options);\r\n }\r\n\r\n @autobind\r\n public SendReactEmojiToInitialMsg(emojiStr: string, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n if (!this.InitialMsg) {\r\n throw ThrowBadFirstMsgError();\r\n }\r\n return this._internalSend.ReactEmojiToMsg(this.FixedChatId, this.InitialMsg, emojiStr, options);\r\n }\r\n\r\n @autobind\r\n public Ok(options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n if (!this.InitialMsg) {\r\n throw ThrowBadFirstMsgError();\r\n }\r\n return this._internalSend.ReactEmojiToMsg(this.FixedChatId, this.InitialMsg, \"✅\", options);\r\n }\r\n\r\n @autobind\r\n public Loading(options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n if (!this.InitialMsg) {\r\n throw ThrowBadFirstMsgError();\r\n }\r\n return this._internalSend.ReactEmojiToMsg(this.FixedChatId, this.InitialMsg, \"⌛\", options);\r\n }\r\n\r\n @autobind\r\n public Fail(options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n if (!this.InitialMsg) {\r\n throw ThrowBadFirstMsgError();\r\n }\r\n return this._internalSend.ReactEmojiToMsg(this.FixedChatId, this.InitialMsg, \"❌\", options);\r\n }\r\n\r\n @autobind\r\n public SendSticker(stickerUrlSource: string | Buffer, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Sticker(this.FixedChatId, stickerUrlSource, options));\r\n }\r\n\r\n @autobind\r\n public SendAudio(audioSource: string, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Audio(this.FixedChatId, { source: audioSource }, options));\r\n }\r\n\r\n @autobind\r\n public SendAudioFromBuffer(audioSource: Buffer, formatFile: string, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Audio(this.FixedChatId, { source: audioSource, formatExtension: formatFile }, options));\r\n }\r\n\r\n @autobind\r\n public SendVideo(videopath: string, options?: WhatsMsgSenderSendingOptions): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Video(this.FixedChatId, { source: videopath }, options));\r\n }\r\n\r\n @autobind\r\n public SendVideoWithCaption(videoPath: string, caption: string, options?: WhatsMsgSenderSendingOptions): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Video(this.FixedChatId, { source: videoPath, caption: caption }, options));\r\n }\r\n\r\n @autobind\r\n public SendVideoFromBuffer(videoBuffer: Buffer, formatFile: string, options?: WhatsMsgSenderSendingOptions): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Video(this.FixedChatId, { source: videoBuffer, formatExtension: formatFile }, options));\r\n }\r\n\r\n @autobind\r\n public SendVideoFromBufferWithCaption(\r\n videoBuffer: Buffer,\r\n caption: string,\r\n formatFile: string,\r\n options?: WhatsMsgSenderSendingOptions\r\n ): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Video(this.FixedChatId, { source: videoBuffer, formatExtension: formatFile, caption: caption }, options));\r\n }\r\n\r\n @autobind\r\n public SendPoll(\r\n pollTitle: string,\r\n selections: string[],\r\n pollParams: WhatsMsgPollOptions,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Poll(this.FixedChatId, pollTitle, selections, pollParams, options));\r\n }\r\n\r\n @autobind\r\n public SendUbication(degreesLatitude: number, degreesLongitude: number, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(\r\n this._internalSend.Location(this.FixedChatId, { degreesLatitude, degreesLongitude, addressText: undefined, name: undefined }, options)\r\n );\r\n }\r\n\r\n @autobind\r\n public SendUbicationWithDescription(\r\n degreesLatitude: number,\r\n degreesLongitude: number,\r\n ubicationName: string,\r\n moreInfoAddress: string,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(\r\n this._internalSend.Location(this.FixedChatId, { degreesLatitude, degreesLongitude, addressText: moreInfoAddress, name: ubicationName }, options)\r\n );\r\n }\r\n\r\n @autobind\r\n public SendContact(\r\n contacts: { name: string; phone: string } | Array<{ name: string; phone: string }>,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Contact(this.FixedChatId, contacts, options));\r\n }\r\n\r\n @autobind\r\n public SendDocument(docPath: string, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Document(this.FixedChatId, { source: docPath }, options));\r\n }\r\n\r\n @autobind\r\n public SendDocumentWithCustomName(\r\n docPath: string,\r\n fileNameToDisplay: string,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WhatsappMessage | null> {\r\n return this.HandlePrimaryMsg(this._internalSend.Document(this.FixedChatId, { source: docPath, fileNameToDisplay: fileNameToDisplay }, options));\r\n }\r\n\r\n @autobind\r\n public SendDocumentFromBuffer(\r\n docBuffer: Buffer,\r\n fileNameToDisplayWithoutExt: string,\r\n extensionFileTypeOnly: string,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WhatsappMessage | null> {\r\n //prettier-ignore\r\n return this.HandlePrimaryMsg(this._internalSend.Document(\r\n this.FixedChatId,\r\n { source: docBuffer, fileNameWithoutExtension: fileNameToDisplayWithoutExt, formatExtension: extensionFileTypeOnly },\r\n options\r\n ));\r\n }\r\n //============================ RECEIVING ==============================\r\n\r\n @autobind\r\n public async WaitMsg(expectedType: MsgType, localOptions?: Partial<IChatContextConfig>): Promise<WhatsappMessage | null> {\r\n switch (this.FixedSenderType) {\r\n case SenderType.Unknown:\r\n throw new Error(\r\n \"[FATAL ERROR] on ChatContext.WaitMsg: ChatContext Obj received a non valid WhatsappMessage as parameter (couldn't identify sender type)\"\r\n );\r\n case SenderType.Group:\r\n if (!this.FixedParticipantLID) {\r\n throw new Error(\r\n \"[FATAL ERROR]: This shouldn't happen at all. Couldn't find group participant from group msg!... Report this bug as a github issue please.\"\r\n );\r\n }\r\n try {\r\n return await this._internalReceive.WaitUntilNextRawMsgFromUserIDInGroup(\r\n this.FixedParticipantLID,\r\n this.FixedParticipantPN,\r\n this.FixedChatId,\r\n expectedType,\r\n {\r\n ...this.Config,\r\n ...localOptions,\r\n }\r\n );\r\n } catch (e) {\r\n if (WhatsSocketReceiverHelper_isReceiverError(e)) {\r\n if (!e.wasAbortedByUser) {\r\n return null;\r\n }\r\n }\r\n throw e;\r\n }\r\n case SenderType.Individual:\r\n try {\r\n return await this._internalReceive.WaitUntilNextRawMsgFromUserIdInPrivateConversation(this.FixedChatId, expectedType, {\r\n ...this.Config,\r\n ...localOptions,\r\n });\r\n } catch (e) {\r\n if (WhatsSocketReceiverHelper_isReceiverError(e)) {\r\n if (!e.wasAbortedByUser) {\r\n return null;\r\n }\r\n }\r\n throw e;\r\n }\r\n }\r\n }\r\n\r\n //@autbinded in constructor()\r\n public async WaitText(localOptions?: Partial<IChatContextConfig>): Promise<string | null> {\r\n const found: WhatsappMessage | null = await this.WaitMsg(MsgType.Text, localOptions);\r\n if (!found) return null;\r\n const extractedTxtToReturn: string | null = MsgHelper_FullMsg_GetText(found);\r\n return extractedTxtToReturn;\r\n }\r\n\r\n @autobind\r\n public async WaitYesOrNoAnswer(localOptions?: Partial<IChatContext_WaitYesOrNoAnswer_Params>): Promise<boolean | null> {\r\n const text: string | null = await this.WaitText(localOptions?.normalConfig);\r\n if (!text) {\r\n return null;\r\n }\r\n\r\n const textLower: string = text.toLowerCase();\r\n //prettier-ignore\r\n const positiveAnswers: string[] = localOptions?.waitYesOrNoOptions?.positiveAnswerOptions ?? this.Config.positiveAnswerOptions ?? [\"yes\", \"y\", \"si\", \"s\", \"ok\", \"vale\", \"sí\"];\r\n //prettier-ignore\r\n const negativeAnswers: string[] = localOptions?.waitYesOrNoOptions?.negativeAnswerOptions ?? this.Config.negativeAnswerOptions ?? [\"no\", \"n\"];\r\n\r\n if (positiveAnswers.includes(textLower)) {\r\n return true;\r\n }\r\n\r\n if (negativeAnswers.includes(textLower)) {\r\n return false;\r\n }\r\n\r\n return null;\r\n }\r\n\r\n @autobind\r\n public async WaitMultimedia(\r\n msgTypeToWaitFor: MsgType.Image | MsgType.Sticker | MsgType.Video | MsgType.Document | MsgType.Audio,\r\n localOptions?: Partial<IChatContextConfig>\r\n ): Promise<Buffer | null> {\r\n const found: WhatsappMessage | null = await this.WaitMsg(msgTypeToWaitFor, localOptions);\r\n if (!found) return null;\r\n const buffer = await downloadMediaMessage(found, \"buffer\", {});\r\n return buffer;\r\n }\r\n\r\n @autobind\r\n public async WaitUbication(localOptions?: Partial<IChatContextConfig>): Promise<ChatContextUbication | null> {\r\n const found: WhatsappMessage | null = await this.WaitMsg(MsgType.Ubication, localOptions);\r\n if (!found) return null;\r\n const res = found?.message?.locationMessage;\r\n if (!res) return null;\r\n return {\r\n degreesLatitude: res.degreesLatitude ?? -1,\r\n degreesLongitude: res.degreesLongitude ?? -1,\r\n thumbnailJpegBuffer: res.jpegThumbnail ?? null,\r\n isLive: res.isLive ?? false,\r\n };\r\n }\r\n\r\n @autobind\r\n public async WaitContact(localOptions?: Partial<IChatContextConfig>): Promise<ChatContextContactRes | ChatContextContactRes[] | null> {\r\n // Wait for a contact message\r\n const message = await this.WaitMsg(MsgType.Contact, localOptions);\r\n if (!message) return null;\r\n\r\n // Handle single contact message\r\n if (message.message?.contactMessage) {\r\n const contact = message.message.contactMessage;\r\n const number = contact.vcard?.match(/WAID=(\\d+)/i)?.[1] || \"\";\r\n return {\r\n name: contact.displayName || \"\",\r\n number,\r\n whatsappId_PN: number ? `${number}${WhatsappPhoneNumberIdentifier}` : \"\",\r\n };\r\n }\r\n\r\n // Handle multiple contacts message\r\n if (message.message?.contactsArrayMessage?.contacts) {\r\n return message.message.contactsArrayMessage.contacts.map((contact) => {\r\n const number = contact.vcard?.match(/WAID=(\\d+)/i)?.[1] || \"\";\r\n return {\r\n name: contact.displayName || \"\",\r\n number,\r\n whatsappId_PN: number ? `${number}${WhatsappPhoneNumberIdentifier}` : \"\",\r\n } satisfies ChatContextContactRes;\r\n });\r\n }\r\n\r\n return null;\r\n }\r\n\r\n @autobind\r\n public async FetchGroupData(): Promise<GroupMetadataInfo | null> {\r\n if (this.FixedSenderType === SenderType.Individual) {\r\n return null;\r\n }\r\n return await this._internalReceive.FetchGroupData(this.FixedChatId);\r\n }\r\n}\r\n\r\nfunction ThrowBadFirstMsgError(): Error {\r\n throw new Error(\r\n \"ChatContext Bad usage: You probably have created a new chatcontext fork without sending any messages nor providing an initial msg trigger!!\\n\" +\r\n \"You need to do one of these two options:\\n\" +\r\n \"1. Provide an explicit first message to this forked chatcontext on ctx.CloneButTargetedTo({initialMsg: <here>}). You can get one using raw api.Send.<anything>()\\n\" +\r\n \"2. If not provided, just send a msg (anything) to chat and automatically chatcontext will be treat it as the first msg\\n\" +\r\n \"Try again..\"\r\n );\r\n}\r\n","import type { MiscMessageGenerationOptions } from \"baileys\";\r\nimport type { IWhatsSocket } from \"../../whats_socket/IWhatsSocket.js\";\r\nimport type { WhatsappMessage } from \"../../whats_socket/types.js\";\r\n\r\ntype MyselfStatusTextParams = Omit<Omit<MiscMessageGenerationOptions, \"statusJidList\">, \"broadcast\">;\r\n\r\n/**\r\n * Submodule responsible for sending status updates (\"stories\")\r\n * through the WhatsApp socket.\r\n *\r\n * This is a lightweight abstraction around the socket API for the\r\n * `status@broadcast` JID, enabling text uploads visible only to\r\n * selected WhatsApp IDs.\r\n *\r\n * Typical usage (from inside a command):\r\n * ```ts\r\n * await api.Myself.Status.UploadText(\"Working on the bot 🚀\", [\r\n * \"123456789@s.whatsapp.net\",\r\n * \"987654321@s.whatsapp.net\",\r\n * ]);\r\n * ```\r\n */\r\nexport default class Myself_Submodule_Status {\r\n /**\r\n * Reserved WhatsApp ID for the \"status\" broadcast channel.\r\n * All status updates must be sent to this JID.\r\n *\r\n * @internal\r\n */\r\n private readonly IDStatusToSend: string = \"status@broadcast\";\r\n\r\n private _whatsSocket: IWhatsSocket;\r\n\r\n /**\r\n * Creates a new `Myself_Submodule_Status` tied to a given socket.\r\n *\r\n * @param chatContextOwner - The active WhatsApp socket instance\r\n * that will handle sending the status update.\r\n */\r\n public constructor(chatContextOwner: IWhatsSocket) {\r\n this._whatsSocket = chatContextOwner;\r\n }\r\n\r\n /**\r\n * Uploads a plain text status update, visible only to the provided\r\n * list of WhatsApp IDs.\r\n *\r\n * This method sends a message to the special `status@broadcast` JID\r\n * with additional metadata indicating which contacts should see it.\r\n *\r\n * @param txtToSendToStatus - The text content of the status.\r\n * @param whatsappIdsToShowStatus - List of WhatsApp user IDs allowed to view the status.\r\n * All ID's must be PN (PhoneNumber) old version. e.g [\"12345@s.whatsapp.net\", \"anotherID@s.whatsapp.net\"]\r\n *\r\n * @returns A `WhatsappMessage` object representing the sent status, or `null`\r\n * if the message failed to send safely.\r\n *\r\n * @example\r\n * ```ts\r\n * const status = new Myself_Submodule_Status(socket);\r\n * await status.UploadText(\"Bot is online ✅\", [\"12345@s.whatsapp.net\"]);\r\n * ```\r\n */\r\n public async UploadText(txtToSendToStatus: string, whatsappIdsToShowStatus: string[], options?: MyselfStatusTextParams): Promise<WhatsappMessage | null> {\r\n let optionsTosend: MiscMessageGenerationOptions;\r\n if (options) {\r\n optionsTosend = { ...options, statusJidList: whatsappIdsToShowStatus, broadcast: true };\r\n } else {\r\n optionsTosend = { statusJidList: whatsappIdsToShowStatus, broadcast: true };\r\n }\r\n\r\n return this._whatsSocket._SendSafe(\r\n this.IDStatusToSend,\r\n {\r\n text: txtToSendToStatus,\r\n },\r\n optionsTosend\r\n );\r\n }\r\n}\r\n","import type { ICommand } from \"./ICommand.js\";\r\n/**\r\n * # Command Type\r\n *\r\n * Different categories of commands supported by the searcher.\r\n * - `Normal`: explicit commands that match directly.\r\n * - `Tag`: commands triggered by a tag (metadata, alias, or secondary marker).\r\n *\r\n * @example\r\n * ```typescript\r\n * const type = CommandType.Normal;\r\n * ```\r\n */\r\nexport enum CommandType {\r\n Normal = \"Normal\",\r\n Tag = \"Tag\",\r\n}\r\n\r\n/**\r\n * # Command Entry\r\n *\r\n * Central registry and search helper type for commands.\r\n *\r\n * Commands are separated into two namespaces:\r\n * - **Normal commands**: Standard commands invoked by name.\r\n * - **Tag commands**: Commands bound to tags or metadata.\r\n *\r\n * A default command or tag may be defined. These act as a global fallback\r\n * when no specific match is found.\r\n *\r\n * @example\r\n * ```typescript\r\n * const entry: CommandEntry = { commandName: \"ping\", commandObj: pingCommand };\r\n * ```\r\n */\r\nexport type CommandEntry = {\r\n commandName: string;\r\n commandObj: ICommand;\r\n};\r\n\r\n/**\r\n * # Commands Searcher System\r\n *\r\n * Central registry and search mechanism for commands.\r\n * Resolves commands by name or alias and manages fallback commands.\r\n *\r\n * @example\r\n * ```typescript\r\n * const searcher = new CommandsSearcher();\r\n * searcher.Add(myCmd);\r\n * ```\r\n */\r\nexport default class CommandsSearcher {\r\n private _normalCommands: Map<string, ICommand> = new Map();\r\n private _tagCommands: Map<string, ICommand> = new Map();\r\n /**\r\n * Optional global fallback command.\r\n * Executed if no specific \"normal\" command is matched.\r\n */\r\n private _defaultCommand?: ICommand;\r\n\r\n /**\r\n * Optional global fallback tag command.\r\n * Executed if no specific \"tag\" command is matched.\r\n */\r\n private _defaultTag?: ICommand;\r\n\r\n /**\r\n * Provides access to the currently configured defaults.\r\n * - `Command`: fallback normal command\r\n * - `Tag`: fallback tag command\r\n */\r\n public get Defaults() {\r\n return {\r\n Command: this._defaultCommand,\r\n Tag: this._defaultTag,\r\n };\r\n }\r\n /**\r\n * Registers the global fallback normal command.\r\n * Used when no explicit normal command is found.\r\n */\r\n public SetDefaultCommand(commandDefault: ICommand): void {\r\n this._defaultCommand = commandDefault;\r\n }\r\n /**\r\n * Registers the global fallback tag command.\r\n * Used when no explicit tag command is found.\r\n */\r\n public SetDefaultTag(commandDefault: ICommand): void {\r\n this._defaultTag = commandDefault;\r\n }\r\n /**\r\n * Returns a list of all registered normal commands.\r\n * Each entry includes the command name and its implementation.\r\n */\r\n public get NormalCommands(): CommandEntry[] {\r\n const toReturn: CommandEntry[] = [];\r\n this._normalCommands.forEach((commandObj, commandName) => toReturn.push({ commandName, commandObj }));\r\n return toReturn;\r\n }\r\n /**\r\n * Returns a list of all registered tag commands.\r\n * Each entry includes the tag name and its implementation.\r\n */\r\n public get TagCommands(): CommandEntry[] {\r\n const toReturn: CommandEntry[] = [];\r\n this._tagCommands.forEach((commandObj, commandName) => toReturn.push({ commandName, commandObj }));\r\n return toReturn;\r\n }\r\n\r\n /**\r\n * Registers a new command, validating it and adding it to the appropriate\r\n * namespace (`Normal` or `Tag`).\r\n *\r\n * The method ensures that command names are valid (non-empty, single-word),\r\n * unique within their type, and that their aliases do not conflict with\r\n * other commands of the same type. All names and aliases are normalized to\r\n * lowercase for case-insensitive matching.\r\n *\r\n * @param commandToAdd The {@link ICommand} instance to register.\r\n * @param addCommandAsType The type of command, either `CommandType.Normal` (default) or `CommandType.Tag`.\r\n *\r\n * @example\r\n * // Add a simple normal command\r\n * searcher.Add({ name: 'help', run: ... });\r\n *\r\n * // Add a tag command with aliases\r\n * searcher.Add({ name: 'admin', aliases: ['mod'], run: ... }, CommandType.Tag);\r\n *\r\n * @example <caption>Error Scenarios</caption>\r\n * // Throws error for duplicate command name\r\n * searcher.Add({ name: 'help', run: ... }); // OK\r\n * searcher.Add({ name: 'help', run: ... }); // Throws Error\r\n *\r\n * // Throws error for alias conflict\r\n * searcher.Add({ name: 'kick', aliases: ['remove'], run: ... }); // OK\r\n * searcher.Add({ name: 'ban', aliases: ['remove'], run: ... }); // Throws Error\r\n *\r\n * // Throws error for invalid name\r\n * searcher.Add({ name: 'bad name', run: ... }); // Throws Error\r\n *\r\n * @throws {Error} If the command name is empty or contains spaces.\r\n * @throws {Error} If a command with the same name already exists for the given type.\r\n * @throws {Error} If an alias conflicts with an existing command's name or aliases of the same type.\r\n */\r\n public Add(commandToAdd: ICommand, addCommandAsType: CommandType = CommandType.Normal): void {\r\n if (!commandToAdd.name || commandToAdd.name.trim() === \"\") {\r\n throw new Error(\"You can't add a command without name!\");\r\n }\r\n if (commandToAdd.name.split(\" \").length > 1) {\r\n throw new Error(\r\n \"You can not add a command with spaces or vary words length!. E.g: !hola mundo, 'hola mundo' is not a valid name, must be one word only like 'holamundo' or 'hola_mundo'\"\r\n );\r\n }\r\n const commandNameLowercase = commandToAdd.name.toLowerCase();\r\n const mapToStoreInto: Map<string, ICommand> = addCommandAsType === CommandType.Normal ? this._normalCommands : this._tagCommands;\r\n\r\n // Check if a command with the same name already exists\r\n if (mapToStoreInto.has(commandNameLowercase)) {\r\n throw new Error(`Bad Args: CommandsSearcher => Command of type \"${CommandType[addCommandAsType]}\" with name '${commandNameLowercase}' already exists!`);\r\n }\r\n\r\n // Normalize metadata\r\n commandToAdd.name = commandNameLowercase;\r\n if (commandToAdd.aliases) {\r\n commandToAdd.aliases = commandToAdd.aliases.map((alias) => alias.toLowerCase());\r\n }\r\n\r\n // Check for alias conflicts\r\n if (commandToAdd.aliases?.length) {\r\n mapToStoreInto.forEach((com) => {\r\n if (!com.aliases?.length) return;\r\n\r\n for (const alias of commandToAdd.aliases!) {\r\n if (com.aliases!.includes(alias)) {\r\n throw new Error(\r\n `Bad Args: CommandsSearcher => Alias '${alias}' for command '${commandNameLowercase}' conflicts with existing command '${com.name}' of type \"${CommandType[addCommandAsType]}\".`\r\n );\r\n }\r\n }\r\n });\r\n }\r\n\r\n // Store the command\r\n mapToStoreInto.set(commandNameLowercase, commandToAdd);\r\n }\r\n\r\n /**\r\n * Checks whether a command exists in either namespace.\r\n *\r\n * @example\r\n * ```ts\r\n * searcher.Exists(\"ping\"); // true\r\n * searcher.Exists(\"unknown\"); // false\r\n * ```\r\n */\r\n public Exists(commandName: string) {\r\n return this.GetTypeOf(commandName) !== null;\r\n }\r\n\r\n /**\r\n * Determines the type of a command.\r\n *\r\n * @example\r\n * ```ts\r\n * searcher.GetTypeOf(\"ping\"); // CommandType.Normal\r\n * searcher.GetTypeOf(\"mod\"); // CommandType.Tag\r\n * searcher.GetTypeOf(\"ghost\"); // null\r\n * ```\r\n */\r\n public GetTypeOf(commandName: string): CommandType | null {\r\n const commandNameLowerCase: string = commandName.toLowerCase();\r\n\r\n if (this._normalCommands.has(commandNameLowerCase)) return CommandType.Normal;\r\n\r\n if (this._tagCommands.has(commandNameLowerCase)) return CommandType.Tag;\r\n\r\n return null;\r\n }\r\n\r\n /**\r\n * Retrieves a normal command.\r\n * Falls back to the default command if not found.\r\n *\r\n * @example\r\n * ```ts\r\n * searcher.GetCommand(\"ping\"); // returns ICommand for \"ping\"\r\n * searcher.GetCommand(\"unknown\"); // returns default command (if set) or null\r\n * ```\r\n */\r\n public GetCommand(commandName: string): ICommand | null {\r\n return this._normalCommands.get(commandName.toLowerCase()) ?? this._defaultCommand ?? null;\r\n }\r\n\r\n /**\r\n * Retrieves a tag command.\r\n * Falls back to the default tag command if not found.\r\n *\r\n * @example\r\n * ```ts\r\n * searcher.GetTag(\"mod\"); // returns ICommand for \"mod\"\r\n * searcher.GetTag(\"ghost\"); // returns default tag (if set) or null\r\n * ```\r\n */\r\n public GetTag(tagName: string): ICommand | null {\r\n return this._tagCommands.get(tagName.toLowerCase()) ?? this._defaultTag ?? null;\r\n }\r\n\r\n /**\r\n * Finds a command by one of its aliases.\r\n *\r\n * @example\r\n * ```ts\r\n * searcher.Add({\r\n * name: \"ban\",\r\n * aliases: [\"block\", \"remove\"],\r\n * execute: () => \"banned\"\r\n * });\r\n *\r\n * searcher.GetWhateverWithAlias(\"block\", CommandType.Normal);\r\n * // returns the \"ban\" command\r\n * ```\r\n */\r\n public GetWhateverWithAlias(possibleAlias: string, commandTypeToLookFor: CommandType): ICommand | null {\r\n const aliasLower = possibleAlias.toLowerCase();\r\n\r\n const findInMap = (map: Map<string, ICommand>) => {\r\n for (const [, commandObj] of map) {\r\n if (commandObj.aliases?.some((alias) => alias.toLowerCase() === aliasLower)) {\r\n return commandObj;\r\n }\r\n }\r\n return null;\r\n };\r\n\r\n return commandTypeToLookFor === CommandType.Normal ? findInMap(this._normalCommands) : findInMap(this._tagCommands);\r\n }\r\n}\r\n","import type { WAMessage } from \"baileys\";\nimport GraphemeSplitter from \"grapheme-splitter\";\nimport { autobind } from \"../../helpers/Decorators.helper.js\";\nimport { MsgHelper_ExtractQuotedMsgInfo, MsgHelper_FullMsg_GetText } from \"../../helpers/Msg.helper.js\";\nimport Delegate from \"../../libs/Delegate.js\";\nimport { MiddlewareChain } from \"../../libs/MiddlewareChain.js\";\nimport { type SenderType, MsgType } from \"../../Msg.types.js\";\nimport type { IWhatsSocket_Submodule_Receiver } from \"../whats_socket/internals/IWhatsSocket.receiver.js\";\nimport type { IWhatsSocket_Submodule_SugarSender } from \"../whats_socket/internals/IWhatsSocket.sugarsender.js\";\nimport { WhatsSocketReceiverHelper_isReceiverError } from \"../whats_socket/internals/WhatsSocket.receiver.js\";\nimport type { IWhatsSocket, IWhatsSocket_EventsOnly_Module } from \"../whats_socket/IWhatsSocket.js\";\nimport WhatsSocket, { type WhatsSocketOptions } from \"../whats_socket/WhatsSocket.js\";\nimport { type IChatContextConfig, ChatContext } from \"./internals/ChatContext.js\";\nimport Myself_Submodule_Status from \"./internals/ChatContext.myself.status.js\";\nimport CommandsSearcher, { CommandType } from \"./internals/CommandsSearcher.js\";\nimport type { CommandArgs, FoundQuotedMsg } from \"./internals/CommandsSearcher.types.js\";\nimport type { IChatContext } from \"./internals/IChatContext.js\";\nimport type { AdditionalAPI, ICommand } from \"./internals/ICommand.js\";\n\n//Little dependency to verify that \"defaulEmojiToSendOnCommandFailure\" is 1 emoji length!\nconst emojiSplitter = new GraphemeSplitter();\n\n/**\n * # Minimal Bot Information\n *\n * Defines the essential, public-facing components of a bot instance.\n *\n * This type is useful for scenarios where a full `Bot` instance is not\n * required, but access to its core configuration and command system is needed.\n * It serves as a minimal interface implemented by the main `Bot` class.\n *\n * @example\n * ```typescript\n * const minBot: BotMinimalInfo = { Settings, Commands };\n * ```\n */\nexport type BotMinimalInfo = {\n /**\n * The bot's current configuration settings.\n *\n * Provides access to all runtime options, such as command prefixes,\n * timeouts, and logging modes.\n */\n Settings: WhatsBotOptions;\n /**\n * The command management system for the bot.\n *\n * Allows for registering, searching, and managing all bot commands.\n */\n Commands: WhatsBotCommands;\n};\n\nexport type WhatsBotOptions = Omit<WhatsSocketOptions, \"ownImplementationSocketAPIWhatsapp\"> &\n Omit<Partial<IChatContextConfig>, \"ignoreSelfMessages\"> & {\n /**\n * Character(s) used to tag the bot in messages.\n *\n * Useful in group contexts where multiple bots or members exist;\n * allows users to explicitly \"mention\" the bot.\n *\n * @default '@'\n * @example\n * tagCharPrefix: ['@', '#'] // bot reacts to both \"@bot\" and \"#bot\"\n */\n tagPrefix?: string | string[];\n\n /**\n * Character(s) used to prefix commands.\n *\n * Common convention is `\"!\"`, but you can use any characters or multiple\n * prefixes to support different command styles.\n *\n * @default '!'\n * @example\n * commandPrefix: ['/'] // commands triggered with \"/help\"\n */\n commandPrefix?: string | string[];\n\n /**\n * # Custom Socket Implementation\n *\n * For advanced users and maintainers: replace the internal WhatsApp socket implementation.\n *\n * If provided, the bot will use this custom implementation instead of the\n * built-in `WhatsSocket`. Useful for testing, extending, or mocking.\n *\n * Warning: Use at your own risk. Incorrect implementations can break bot behavior.\n *\n * @example\n * ```typescript\n * const opts: WhatsBotOptions = { ownWhatsSocketImplementation_Internal: myMock };\n * ```\n */\n ownWhatsSocketImplementation_Internal?: IWhatsSocket;\n\n /**\n * # Custom Chat Context Hook\n *\n * For advanced users and maintainers: replaces the ChatContext that will be sent to all commands.\n *\n * Used primarily for testing.\n *\n * Warning: Use at your own risk. Incorrect implementations can break bot behavior.\n *\n * @example\n * ```typescript\n * const opts: WhatsBotOptions = { ownChatContextCreationHook_Internal: () => myCtx };\n * ```\n */\n ownChatContextCreationHook_Internal?: () => IChatContext | null;\n\n /**\n * Enables or disables the \"safe net\" around command execution.\n *\n * - When `true` (default): command errors are caught internally, logged,\n * and prevented from crashing the bot.\n * - When `false`: errors bubble up to the caller, allowing external handling\n * (useful for integration tests or advanced error pipelines).\n *\n * @default true\n * @remarks This setting is primarily for developers who want fine-grained\n * control over error handling.\n */\n enableCommandSafeNet?: boolean;\n\n /**\n * Default emoji reaction to send when a command fails unexpectedly.\n *\n * If set, the bot will react to the triggering message with this emoji\n * whenever a command throws or exits with an error.\n *\n * @default undefined (no reaction sent on command failure)\n * @example\n * defaultEmojiToSendReactionOnFailureCommand: \"⚠️\"\n */\n defaultEmojiToSendReactionOnFailureCommand?: string | null;\n\n /**\n * Send to chat a json representation of catched error when a\n * commands fails unexpectedly. Useful for debug in real time.\n */\n sendErrorToChatOnFailureCommand_debug?: boolean;\n };\n\n/**\n * # WhatsApp Bot Events\n *\n * Defines all events emitted by the Bot instance.\n *\n * This type aggregates events from the underlying WhatsApp socket\n * (`IWhatsSocket_EventsOnly_Module`) and adds bot-specific events\n * related to command processing and middleware execution.\n *\n * @example\n * ```typescript\n * bot.Events.onIncomingMsg.Subscribe((msg) => console.log(msg));\n * ```\n */\nexport type WhatsBotEvents = IWhatsSocket_EventsOnly_Module & {\n /**\n * Fires after the main middleware chain has finished executing.\n *\n * This event is triggered for every incoming message that passes through\n * the middleware pipeline.\n *\n * @param completedSuccessfully - `true` if the chain ran to completion\n * (all middleware called `next()`), `false` if a middleware broke the chain.\n */\n onMainMiddlewareEnd: Delegate<(completedSuccessfully: boolean) => void | Promise<void>>;\n\n /**\n * Fires after the \"on command found\" middleware chain has finished executing.\n *\n * This event only triggers if a valid command was found in the message.\n *\n * @param completedSuccessfully - `true` if the chain ran to completion,\n * `false` if a middleware broke the chain before command execution.\n */\n onFoundCommandMiddlewareEnd: Delegate<(completedSuccessfully: boolean) => void | Promise<void>>;\n\n /**\n * Fires when a message is identified as a command (e.g., starts with `!`),\n * but no matching command or alias is registered.\n *\n * Useful for providing \"did you mean?\" suggestions or a generic help message.\n *\n * @param ctx - The chat context of the incoming message.\n * @param commandNameThatCouldntBeFound - The name of the command the user tried to run.\n */\n onCommandNotFound: Delegate<(ctx: IChatContext, commandNameThatCouldntBeFound: string) => void | Promise<void>>;\n\n /**\n * Fires when a valid command is found in a message, but **before** it is executed.\n *\n * This serves as a pre-execution hook, ideal for logging, analytics, or\n * dynamic permission checks that shouldn't be part of the command's core logic.\n *\n * @param ctx - The chat context of the incoming message.\n * @param commandToRun - The command object that is about to be executed.\n */\n onCommandFound: Delegate<(ctx: IChatContext, commandToRun: ICommand) => void | Promise<void>>;\n\n /**\n * Fires **after** a command has been executed.\n *\n * This serves as a post-execution hook, useful for logging the outcome,\n * cleaning up resources, or performing follow-up actions.\n *\n * @param ctx - The chat context of the incoming message.\n * @param commandExecuted - The command object that was just run.\n * @param ranSuccessfully - `true` if the command's `run` method completed\n * without throwing an error, `false` otherwise.\n */\n onCommandFoundAfterItsExecution: Delegate<(ctx: IChatContext, commandExecuted: ICommand, ranSuccessfully: boolean) => void>;\n};\n\nexport type WhatsBotSender = IWhatsSocket_Submodule_SugarSender;\nexport type WhatsBotReceiver = IWhatsSocket_Submodule_Receiver;\nexport type WhatsBotCommands = CommandsSearcher;\n\nexport type WhatsbotcordMiddlewareFunct = (\n bot: Bot,\n senderId_LID: string | null,\n senderId_PN: string | null,\n chatId: string,\n rawMsg: WAMessage,\n msgType: MsgType,\n senderType: SenderType,\n next: () => Promise<void>\n) => Promise<void> | void;\n\nexport type WhatsbotcordMiddlewareFunct_OnFoundCommand = (\n bot: Bot,\n senderId_LID: string | null,\n senderId_PN: string | null,\n chatId: string,\n rawMsg: WAMessage,\n msgType: MsgType,\n senderType: SenderType,\n commandFound: ICommand,\n next: () => Promise<void>\n) => Promise<void> | void;\n\nexport type WhatsbotcordPlugin = {\n plugin: (bot: Bot) => void;\n};\n\n/**\n * # WhatsApp Bot\n *\n * Represents the main WhatsApp Bot instance.\n *\n * The `Bot` class orchestrates the WhatsApp socket connection and provides a\n * command-driven interaction system (similar to Discord bots).\n *\n * Typical usage involves registering and handling commands via the internal\n * `Command` prop.\n *\n * @example\n * ```typescript\n * const bot = new Bot();\n * await bot.Start();\n *\n * // Commands are usually registered in the command system\n * bot.Commands.Register(\"ping\", async (ctx) => ctx.Reply(\"pong\"));\n * ```\n */\nexport default class Bot implements BotMinimalInfo {\n public InternalSocket: IWhatsSocket;\n private _commandSearcher: CommandsSearcher;\n private _internalMiddleware: WhatsbotcordMiddlewareFunct[] = [];\n private _internalMiddleware_OnCommandFound: WhatsbotcordMiddlewareFunct_OnFoundCommand[] = [];\n\n /** Bot Specific Events */\n /**\n * Event triggered when the bot receives a message that looks like a command,\n * but no registered command or alias matches it.\n *\n * Example usage:\n * ```ts\n * bot.Events.onCommandNotFound.Subscribe((name) => {\n * console.log(`User tried unknown command: ${name}`);\n * });\n * ```\n */\n private _EVENT_onCommandNotFound: Delegate<(ctx: IChatContext, commandNameThatCouldntBeFound: string) => void> = new Delegate();\n\n private _EVENT_onCommandFound: Delegate<(ctx: IChatContext, commandToRun: ICommand) => void | Promise<void>> = new Delegate();\n\n private _EVENT_onAfterCommandExecution: Delegate<(ctx: IChatContext, commandExecuted: ICommand, ranSuccessfully: boolean) => void | Promise<void>> =\n new Delegate();\n\n /**\n * Event triggered **after the middleware chain finishes running**.\n *\n * - The argument is `true` if the chain executed successfully to the end.\n * - The argument is `false` if some middleware stopped the chain by not calling `next()`.\n *\n * Example usage:\n * ```ts\n * bot.Events.onMiddlewareEnd.Subscribe((success) => {\n * if (success) console.log(\"All middleware finished\");\n * else console.log(\"Middleware chain was interrupted early\");\n * });\n * ```\n */\n private _EVENT_onMainMiddlewareEnd: Delegate<(completedSuccessfully: boolean) => void | Promise<void>> = new Delegate();\n\n private _EVENT_OnFoundCommandMiddlewareEnd: Delegate<(completedSuccessfully: boolean) => void | Promise<void>> = new Delegate();\n /**\n * Current bot configuration settings.\n *\n * These settings are derived from the constructor options, with defaults applied\n * where values were not provided.\n *\n * ⚠️ Changing properties on this object **after the bot has started** can affect its actual functionality.\n *\n * Typical use cases:\n * - Reading the active command or tag prefix\n * - Inspecting runtime limits (timeouts, queue limits, etc.)\n *\n * Example:\n * ```ts\n * console.log(bot.Settings.commandPrefix); // [\"!\"]\n * ```\n */\n public Settings: WhatsBotOptions;\n\n /**\n * Gets the primary command prefix configured for the bot.\n *\n * If multiple prefixes are configured (e.g., `[\"!\", \"/\"]`), this method\n * returns the first one in the array. If no prefix is explicitly configured,\n * it returns the default `\"!\"`.\n *\n * This is an utility Get Function to avoid unnecesary logic in your code\n * due to the nature of `this.Settings.commandPrefix` type \"string | string[] | undefined\"\n * (Triple validation? ugh, use this method instead!)\n *\n * @returns {string} The primary command prefix.\n */\n public get Settings_GetCommandPrefix(): string {\n const defaultPrefix: string = \"!\";\n\n if (typeof this.Settings.commandPrefix === \"undefined\") {\n return defaultPrefix;\n }\n\n if (typeof this.Settings.commandPrefix === \"string\") {\n return this.Settings.commandPrefix;\n }\n\n //Is \"array\" then...\n if (this.Settings.commandPrefix.length > 0) {\n return this.Settings.commandPrefix.at(0)!;\n } else {\n return defaultPrefix;\n }\n }\n\n /**\n * Direct access to the underlying send messaging module.\n *\n * ⚠️ Normally you should not use this directly.\n * Use the bot’s command system to send replies and interact with users.\n *\n * This exists for advanced cases where you need to bypass the command\n * framework (e.g., sending raw messages to specific chats).\n */\n public get SendMsg(): WhatsBotSender {\n return this.InternalSocket.Send;\n }\n\n /**\n * Direct access to the underlying receive messaging module.\n *\n * ⚠️ Normally you should not use this directly.\n * The bot’s command system will handle incoming messages for you.\n *\n * This exists for advanced use cases like:\n * - Listening to non-command events (group joins, reactions, etc.).\n * - Building custom listeners outside of the command framework.\n */\n public get ReceiveMsg(): WhatsBotReceiver {\n return this.InternalSocket.Receive;\n }\n\n /** Exposes all bot-related events that consumers can subscribe to.\n *\n * These events are implemented using `Delegate`, which provides `Subscribe` and\n * `Unsubscribe` methods to attach or detach handlers.\n *\n * Example usage:\n * ```ts\n * bot.Events.onIncomingMsg.Subscribe((msg) => {\n * console.log(\"Raw incoming message:\", msg);\n * });\n *\n * bot.Events.onCommandNotFound.Subscribe((name) => {\n * console.warn(`Unknown command: ${name}`);\n * });\n *\n * bot.Events.onMiddlewareEnd.Subscribe((success) => {\n * console.log(success ? \"Middleware chain finished\" : \"Middleware interrupted\");\n * });\n * ```\n */\n public get Events(): WhatsBotEvents {\n return {\n onGroupEnter: this.InternalSocket.onGroupEnter,\n onGroupUpdate: this.InternalSocket.onGroupUpdate,\n onIncomingMsg: this.InternalSocket.onIncomingMsg,\n onRestart: this.InternalSocket.onRestart,\n onSentMessage: this.InternalSocket.onSentMessage,\n onStartupAllGroupsIn: this.InternalSocket.onStartupAllGroupsIn,\n onUpdateMsg: this.InternalSocket.onUpdateMsg,\n onCommandNotFound: this._EVENT_onCommandNotFound,\n onMainMiddlewareEnd: this._EVENT_onMainMiddlewareEnd,\n onCommandFound: this._EVENT_onCommandFound,\n onCommandFoundAfterItsExecution: this._EVENT_onAfterCommandExecution,\n onFoundCommandMiddlewareEnd: this._EVENT_OnFoundCommandMiddlewareEnd,\n };\n }\n\n public get Commands(): WhatsBotCommands {\n return this._commandSearcher;\n }\n\n /**\n * Creates a new `Bot` instance with customizable behavior.\n *\n * The constructor accepts a `WhatsBotOptions` object that allows overriding\n * runtime settings such as logging, message delays, command handling, and\n * socket implementation.\n *\n * @param options - Optional configuration for customizing bot behavior.\n *\n * Default values:\n * - `credentialsFolder`: `\"./auth\"`\n * Folder path where WhatsApp session credentials are stored and reused.\n *\n * - `delayMilisecondsBetweenMsgs`: `100`\n * Minimum delay (in ms) between consecutive outgoing messages.\n * Helps avoid spam detection and rate-limiting by WhatsApp.\n *\n * - `ignoreSelfMessage`: `true`\n * When enabled, the bot ignores messages sent by its own account.\n *\n * - `loggerMode`: `\"recommended\"`\n * Logging verbosity. `\"recommended\"` provides balanced visibility;\n * other modes may increase or decrease log detail.\n *\n * - `maxReconnectionRetries`: `5`\n * Number of reconnection attempts before giving up when the socket disconnects.\n *\n * - `senderQueueMaxLimit`: `20`\n * Maximum number of pending messages allowed in the send queue.\n * Prevents unbounded memory growth if the bot cannot send fast enough.\n *\n * - `commandPrefix`: `[\"!\"]`\n * One or more prefixes that trigger command execution.\n * Can be a string or string[]; strings are normalized into arrays.\n *\n * - `tagCharPrefix`: `[\"@\"]`\n * Characters used to denote mentions or tagging in commands.\n * Similar normalization rules as `commandPrefix`.\n *\n * - `cancelFeedbackMsg`:\n * `\"canceled ❌ (Default Message: Change me using Bot constructor params options)\"`\n * Feedback message shown when a user cancels an interactive flow.\n *\n * - `cancelKeywords`: `[\"cancel\", \"cancelar\", \"para\", \"stop\"]`\n * Keywords that trigger cancellation of interactive sessions.\n *\n * - `timeoutSeconds`: `30`\n * Default timeout for interactive flows (in seconds).\n *\n * - `wrongTypeFeedbackMsg`:\n * `\"wrong expected msg type ❌ (Default Message: Change me using Bot constructor params options)\"`\n * Feedback shown when the received message type doesn’t match expectations.\n *\n * - `ownWhatsSocketImplementation`: `undefined`\n * Allows injecting a custom `WhatsSocket` implementation. If omitted,\n * the built-in socket (`new WhatsSocket(Settings)`) is used.\n *\n * - `enableCommandSafeNet`: `true`\n * Enables a safeguard layer around command execution, preventing\n * crashes or unintended side effects from propagating.\n *\n * @remarks\n * - All defaults are applied when their corresponding `options` field\n * is `undefined` or invalid.\n * - `commandPrefix` and `tagCharPrefix` always normalize to arrays.\n * - For production bots, consider raising `delayMilisecondsBetweenMsgs`\n * slightly to avoid WhatsApp anti-spam systems.\n */\n constructor(options?: WhatsBotOptions) {\n this.Settings = BotUtils_GenerateOptions(options);\n\n //# Validations:\n // 1.Validate is only one emoji length on defaultEmojiToSend...\n if (this.Settings.defaultEmojiToSendReactionOnFailureCommand) {\n const emojisCount: number = emojiSplitter.countGraphemes(this.Settings.defaultEmojiToSendReactionOnFailureCommand);\n if (emojisCount !== 1) {\n throw new Error(\n \"WhatsbotCord BOT received in 'defaultEmojiToSendReactionOnFailureCommand' a non valid SINGLE emoji. Received instead: \" +\n this.Settings.defaultEmojiToSendReactionOnFailureCommand\n );\n }\n }\n\n this._commandSearcher = new CommandsSearcher();\n this.InternalSocket = this.Settings.ownWhatsSocketImplementation_Internal ?? new WhatsSocket(this.Settings);\n this.InternalSocket.onIncomingMsg.Subscribe(this.EVENT_OnMessageIncoming);\n }\n\n /**\n * Starts the bot by initializing the WhatsApp socket connection.\n *\n * This method must be called before the bot can process commands.\n *\n * Example:\n * ```ts\n * const bot = new Bot();\n * await bot.Start();\n * ```\n */\n @autobind\n public async Start(): Promise<void> {\n return this.InternalSocket.Start();\n }\n\n /**\n * Registers a middleware function or a plugin to intercept incoming messages.\n *\n * This method serves as the main entry point for extending bot functionality.\n * Middleware is executed in registration order **before** any command processing.\n *\n * ### Use as Middleware\n * Pass a function to inspect, modify, or block messages globally. Each\n * middleware receives a `next()` function. Call `next()` to pass control\n * to the next middleware. If `next()` is not called, the processing chain\n * stops, preventing subsequent middleware and commands from running.\n *\n * ### Use as a Plugin\n * Pass an object with a `plugin` method. Plugins are ideal for encapsulating\n * complex or reusable logic, such as registering multiple commands and listeners at once.\n *\n * @param usePluginOrMiddleware - The middleware function or plugin object to register.\n *\n * @example\n * // ----- Using `WhatsbotcordMiddlewareFunct` param -----\n *\n * // Middleware for logging all incoming messages\n * bot.Use(async (bot, senderId_LID, senderId_PN, chatId, rawMsg, msgType, senderType, next) => {\n * console.log(`New message in chat ${chatId}`);\n * await next(); // Continue to the next middleware\n * });\n *\n * @example\n * // Middleware to block a specific user\n * bot.Use((bot, senderId_LID, senderId_PN, chatId, rawMsg, msgType, senderType, next) => {\n * if (senderId_PN === \"user-to-block@s.whatsapp.net\") {\n * return; // Stop the chain by not calling next()\n * }\n * next();\n * });\n *\n * // ---- Using `WhatsbotcordPlugin` param -----\n * @example\n * // Plugin that registers multiple commands\n * const myPlugin: WhatsbotcordPlugin = {\n * plugin: (bot) => {\n * bot.Commands.Register(\"ping\", async (ctx) => ctx.Reply(\"pong\"));\n * bot.Commands.Register(\"help\", async (ctx) => ctx.Reply(\"Here is some help!\"));\n * }\n * };\n * bot.Use(myPlugin);\n */\n @autobind\n public Use(usePluginOrMiddleware: WhatsbotcordMiddlewareFunct | WhatsbotcordPlugin): void {\n if (typeof usePluginOrMiddleware === \"function\") {\n this._internalMiddleware.push(usePluginOrMiddleware);\n }\n if (typeof usePluginOrMiddleware === \"object\") {\n usePluginOrMiddleware.plugin(this);\n }\n }\n\n /**\n * Registers middleware that runs only when a valid command is found.\n *\n * This hook executes **after** a command has been identified but **before** the\n * command's `run` method is called. It's the ideal place for command-specific\n * logic like permission checks, cooldowns, or logging.\n *\n * Like general middleware, you must call `next()` to proceed. If `next()` is\n * not called, the command will not be executed.\n *\n * @param useMiddleware - The middleware function to execute. It receives all\n * standard message parameters, plus the `commandFound` object.\n * @see Use for general-purpose middleware that runs on all messages.\n *\n * @example\n * // Middleware to allow a command only for admins\n * bot.Use_OnCommandFound(async (bot, senderId_LID, senderId_PN, chatId, rawMsg, msgType, senderType, commandFound, next) => {\n * const admins = [\"admin1@s.whatsapp.net\", \"admin2@s.whatsapp.net\"];\n * if (commandFound.name === \"ban\" && (!senderId_PN || !admins.includes(senderId_PN))) {\n * // User is not an admin, block the command\n * await bot.SendMsg.Text(chatId, \"You don't have permission to use that command.\");\n * return;\n * }\n * // User has permission, proceed to execute the command\n * await next();\n * });\n */\n @autobind\n public Use_OnCommandFound(useMiddleware: WhatsbotcordMiddlewareFunct_OnFoundCommand): void {\n this._internalMiddleware_OnCommandFound.push(useMiddleware);\n }\n\n @autobind\n private async EVENT_OnMessageIncoming(\n senderId_LID: string | null,\n senderId_PN: string | null,\n chatId: string,\n rawMsg: WAMessage,\n msgType: MsgType,\n senderType: SenderType\n ): Promise<void> {\n // ======== Middleware chain section ========\n const mainMiddleware = new MiddlewareChain(this._internalMiddleware);\n const middlewareChainSuccess = await mainMiddleware.run(this, senderId_LID, senderId_PN, chatId, rawMsg, msgType, senderType);\n this.Events.onMainMiddlewareEnd.CallAll(middlewareChainSuccess);\n if (!middlewareChainSuccess) return;\n\n // ==== Main Logic =====\n if (msgType === MsgType.Text) {\n const txtFromMsg: string | null = MsgHelper_FullMsg_GetText(rawMsg);\n if (!txtFromMsg || txtFromMsg.length === 0) return;\n const txtFromMsgHealthy: string = txtFromMsg.trim();\n\n const rawArgs: string[] = txtFromMsg.slice(1).split(\" \");\n //If user only sent \"!\" instead of !command (if '!' is prefix for example)\n if (rawArgs.length === 0) {\n return;\n }\n const commandOrAliasNameLowerCased: string = rawArgs.at(0)!.toLowerCase();\n let commandArgs: string[] = rawArgs.length > 1 ? rawArgs.slice(1) : [];\n\n // === Check if command, then what type ===\n const prefix: string = txtFromMsgHealthy[0]!;\n let commandFound: ICommand | null = null;\n let commandTypeFound: CommandType | null = null;\n // 1. Check if its normal command\n if (typeof this.Settings.commandPrefix === \"string\" ? this.Settings.commandPrefix === prefix : this.Settings.commandPrefix?.includes(prefix)) {\n commandTypeFound = CommandType.Normal;\n commandFound = this.Commands.GetCommand(commandOrAliasNameLowerCased);\n if (this.Commands.Defaults.Command) {\n if (this.Commands.Defaults.Command === commandFound) {\n commandArgs = rawArgs.filter((word) => word !== \"\");\n }\n }\n // 2. Check if is tag command\n } else if (typeof this.Settings.tagPrefix === \"string\" ? this.Settings.tagPrefix === prefix : this.Settings.tagPrefix?.includes(prefix)) {\n commandTypeFound = CommandType.Tag;\n commandFound = this.Commands.GetTag(commandOrAliasNameLowerCased);\n if (this.Commands.Defaults.Tag) {\n if (this.Commands.Defaults.Tag === commandFound) {\n commandArgs = rawArgs.filter((word) => word !== \"\");\n }\n }\n }\n // 3. Found type of command but not with normal name? Try searching if its an alias\n if (!commandFound && commandTypeFound) {\n commandFound = this.Commands.GetWhateverWithAlias(commandOrAliasNameLowerCased, commandTypeFound);\n }\n\n //=========================================================\n let ARG1_ChatContext: IChatContext;\n const customChatContext: IChatContext | null = this.Settings.ownChatContextCreationHook_Internal!();\n if (customChatContext) {\n ARG1_ChatContext = customChatContext;\n } else {\n ARG1_ChatContext = new ChatContext(senderId_LID, senderId_PN, chatId, rawMsg, this.InternalSocket.Send, this.InternalSocket.Receive, {\n cancelKeywords: this.Settings.cancelKeywords!,\n timeoutSeconds: this.Settings.timeoutSeconds!,\n ignoreSelfMessages: this.Settings.ignoreSelfMessage!,\n wrongTypeFeedbackMsg: this.Settings.wrongTypeFeedbackMsg,\n cancelFeedbackMsg: this.Settings.cancelFeedbackMsg,\n });\n }\n //=========================================================\n\n // 4. Can't be found after all that? its not a valid command\n if (!commandFound) {\n await this.Events.onCommandNotFound.CallAllAsync(\n new ChatContext(senderId_LID, senderId_PN, chatId, rawMsg, this.InternalSocket.Send, this.InternalSocket.Receive, {\n cancelKeywords: this.Settings.cancelKeywords!,\n timeoutSeconds: this.Settings.timeoutSeconds!,\n ignoreSelfMessages: this.Settings.ignoreSelfMessage!,\n wrongTypeFeedbackMsg: this.Settings.wrongTypeFeedbackMsg,\n cancelFeedbackMsg: this.Settings.cancelFeedbackMsg,\n }),\n txtFromMsg\n );\n return;\n } else {\n if (this.Events.onCommandFound.Length > 0) {\n await this.Events.onCommandFound.CallAllAsync(\n new ChatContext(senderId_LID, senderId_PN, chatId, rawMsg, this.InternalSocket.Send, this.InternalSocket.Receive, {\n cancelKeywords: this.Settings.cancelKeywords!,\n timeoutSeconds: this.Settings.timeoutSeconds!,\n ignoreSelfMessages: this.Settings.ignoreSelfMessage!,\n wrongTypeFeedbackMsg: this.Settings.wrongTypeFeedbackMsg,\n cancelFeedbackMsg: this.Settings.cancelFeedbackMsg,\n }),\n commandFound\n );\n }\n\n //2nd Middleware\n const middlewareOnFound = new MiddlewareChain(this._internalMiddleware_OnCommandFound);\n const shouldContinueAgain = await middlewareOnFound.run(this, senderId_LID, senderId_PN, chatId, rawMsg, msgType, senderType, commandFound);\n await this.Events.onFoundCommandMiddlewareEnd.CallAllAsync(shouldContinueAgain);\n if (!shouldContinueAgain) {\n await this._EVENT_onAfterCommandExecution.CallAllAsync(ARG1_ChatContext, commandFound, false);\n return;\n }\n }\n\n const quotedMsgAsArgument: FoundQuotedMsg | null = MsgHelper_ExtractQuotedMsgInfo(rawMsg);\n\n //=========================================================\n const ARG2_AdditionalAPI: AdditionalAPI = {\n // @deprecated ones: InternalSockets already have them inside!\n // Receive: this._socket.Receive,\n // Send: this._socket.Send,\n InternalSocket: this.InternalSocket,\n Myself: {\n Status: new Myself_Submodule_Status(this.InternalSocket),\n Bot: this,\n },\n };\n const ARG3_AdditionalArgs: CommandArgs = {\n args: commandArgs,\n chatId: chatId,\n chatId_LID: rawMsg.key.remoteJidAlt,\n msgType: msgType,\n originalRawMsg: rawMsg,\n senderType: senderType,\n participantIdLID: senderId_LID,\n participantIdPN: senderId_PN,\n quotedMsgInfo: quotedMsgAsArgument,\n botInfo: this,\n };\n try {\n await commandFound.run(\n /** Chat Context */\n ARG1_ChatContext,\n /** RawAPI */\n ARG2_AdditionalAPI,\n /** Command basic arguments */\n ARG3_AdditionalArgs\n );\n } catch (e) {\n if (this.Settings.defaultEmojiToSendReactionOnFailureCommand) {\n await ARG1_ChatContext.SendReactEmojiToInitialMsg(this.Settings.defaultEmojiToSendReactionOnFailureCommand);\n }\n if (this.Settings.sendErrorToChatOnFailureCommand_debug) {\n await ARG1_ChatContext.SendText(JSON.stringify(e, null, 2), { normalizeMessageText: false });\n }\n if (WhatsSocketReceiverHelper_isReceiverError(e)) {\n if (e.wasAbortedByUser && this.Settings.loggerMode !== \"silent\") {\n console.log(`[Command Canceled]: Name ${commandOrAliasNameLowerCased}`);\n }\n } else {\n if (this.Settings.loggerMode !== \"silent\")\n console.log(\n `[COMMAND EXECUTION ERROR]: Error when trying to execute '${commandOrAliasNameLowerCased}'\\n\\n`,\n `Error Info: ${JSON.stringify(e, null, 2)}`\n );\n }\n\n if (!this.Settings.enableCommandSafeNet) {\n throw e;\n }\n }\n await this._EVENT_onAfterCommandExecution.CallAllAsync(ARG1_ChatContext, commandFound, false);\n }\n } //EVENT_...() Method\n}\n\nexport function BotUtils_GenerateOptions(options?: Partial<WhatsBotOptions>): WhatsBotOptions {\n return {\n credentialsFolder: options?.credentialsFolder ?? \"./auth\",\n delayMilisecondsBetweenMsgs: options?.delayMilisecondsBetweenMsgs ?? 100,\n ignoreSelfMessage: options?.ignoreSelfMessage ?? true,\n loggerMode: options?.loggerMode ?? \"recommended\",\n maxReconnectionRetries: options?.maxReconnectionRetries ?? 5,\n senderQueueMaxLimit: options?.senderQueueMaxLimit ?? 20,\n commandPrefix: typeof options?.commandPrefix === \"string\" ? [options.commandPrefix] : (options?.commandPrefix ?? [\"!\"]),\n tagPrefix: typeof options?.tagPrefix === \"string\" ? [options.tagPrefix] : (options?.tagPrefix ?? [\"@\"]),\n cancelFeedbackMsg: options?.cancelFeedbackMsg ?? \"canceled ❌ (Default Message: Change me using Bot constructor params options)\",\n cancelKeywords: options?.cancelKeywords ?? [\"cancel\", \"cancelar\", \"para\", \"stop\"],\n timeoutSeconds: options?.timeoutSeconds ?? 30,\n wrongTypeFeedbackMsg: options?.wrongTypeFeedbackMsg ?? \"wrong expected msg type ❌ (Default Message: Change me using Bot constructor params options)\",\n ownWhatsSocketImplementation_Internal: options?.ownWhatsSocketImplementation_Internal,\n enableCommandSafeNet: options?.enableCommandSafeNet ?? true,\n defaultEmojiToSendReactionOnFailureCommand: options?.defaultEmojiToSendReactionOnFailureCommand ?? null,\n sendErrorToChatOnFailureCommand_debug: options?.sendErrorToChatOnFailureCommand_debug ?? false,\n ownChatContextCreationHook_Internal: options?.ownChatContextCreationHook_Internal ?? (() => null),\n };\n}\n","import type Bot from \"../bot/bot.js\";\r\nimport type { WhatsbotcordPlugin } from \"../bot/bot.js\";\r\nimport type { ICommand } from \"../bot/internals/ICommand.js\";\r\n\r\n/**\r\n * Keeps track of a user executing a command.\r\n * One record per (chatId + participantId).\r\n *\r\n * `timer` is used to auto-expire the entry after a configured timeout.\r\n */\r\ntype ActiveUserLog = {\r\n chatId: string;\r\n command: ICommand;\r\n participantId_LID: string | null;\r\n timer: NodeJS.Timeout;\r\n};\r\n\r\nexport type OfficialPlugin_OneCommandPerUserAtATime_ContextInfo = { pushName?: string | null };\r\n/**\r\n * Configuration options for the \"OneCommandPerUserAtATime\" plugin.\r\n */\r\nexport type OfficialPlugin_OneCommandPerUserAtATime_Config = {\r\n /**\r\n * Number of seconds to keep a user locked before their command lock expires.\r\n * This prevents users from getting stuck if a command fails without cleanup.\r\n * @default 180 (3 minutes)\r\n */\r\n timeoutSecondsToForgetThem?: number;\r\n\r\n /**\r\n * Called when a user tries to execute a new command while one is still active.\r\n *\r\n * @param ctxInfo - Contextual info such as pushName of the sender.\r\n * @param executingCommand - The command that is already running.\r\n * @param newCommand - The new command being attempted.\r\n * @returns A string to send back to the user (e.g., \"Please wait until your current command finishes.\").\r\n */\r\n msgToSend: (ctxInfo: OfficialPlugin_OneCommandPerUserAtATime_ContextInfo, executingCommand: ICommand, newCommand: ICommand) => string;\r\n};\r\n\r\n/**\r\n * Plugin: Ensures that only **one command per user** can be active at a time.\r\n *\r\n * - If a user tries to run a command while another is still active, they get a configurable message and the new command is blocked.\r\n * - Active commands are automatically forgotten after a timeout to prevent permanent locks.\r\n * - The lock is cleared instantly when a command finishes execution.\r\n *\r\n * @param config - Timeout settings and message generator.\r\n * @returns A WhatsbotcordPlugin object to register with the bot.\r\n */\r\nexport default function OfficialPlugin_OneCommandPerUserAtATime(config: OfficialPlugin_OneCommandPerUserAtATime_Config): WhatsbotcordPlugin {\r\n const activeUsers: ActiveUserLog[] = [];\r\n const timeoutSeconds = config.timeoutSecondsToForgetThem ?? 180;\r\n\r\n return {\r\n plugin: (bot: Bot) => {\r\n // The middleware now handles the check BEFORE a command runs.\r\n bot.Use_OnCommandFound(async (bot, senderId_LID, _senderId_PN, chatId, rawMsg, _msgType, _senderType, commandFound, next) => {\r\n const existingLog = activeUsers.find((u) => u.chatId === chatId && u.participantId_LID === senderId_LID);\r\n\r\n // If a log exists, the user is busy. Block the new command.\r\n if (existingLog) {\r\n const message = config.msgToSend({ pushName: rawMsg.pushName }, existingLog.command, commandFound);\r\n await bot.SendMsg.Text(chatId, message, { quoted: rawMsg });\r\n return; // By not calling next(), we stop execution.\r\n }\r\n\r\n // User is not busy. Add a log and allow the command to run.\r\n const newLog: ActiveUserLog = {\r\n chatId,\r\n participantId_LID: senderId_LID,\r\n command: commandFound,\r\n timer: setTimeout(() => {\r\n // Failsafe: auto-remove the log after a timeout.\r\n const index = activeUsers.findIndex((u) => u === newLog);\r\n if (index !== -1) {\r\n activeUsers.splice(index, 1);\r\n }\r\n }, timeoutSeconds * 1000),\r\n };\r\n\r\n activeUsers.push(newLog);\r\n await next(); // Proceed to execute the command.\r\n });\r\n\r\n // The event is still the best place to handle cleanup AFTER a command runs.\r\n bot.Events.onCommandFoundAfterItsExecution.Subscribe((ctx, _executedCommand) => {\r\n const index = activeUsers.findIndex((u) => u.chatId === ctx.FixedChatId && u.participantId_LID === ctx.FixedParticipantLID);\r\n\r\n if (index !== -1) {\r\n const log = activeUsers[index]!;\r\n clearTimeout(log.timer); // Clear the failsafe timer.\r\n activeUsers.splice(index, 1); // Remove the user from the active list.\r\n }\r\n });\r\n },\r\n };\r\n}\r\n","import fs from \"node:fs\";\r\nimport type { WhatsappMessage } from \"./core/whats_socket/types.js\";\r\nimport { GetPath } from \"./libs/BunPath.js\";\r\n\r\n/**\r\n * # Store Message in History JSON\r\n *\r\n * Stores the incoming WhatsApp message into a local JSON file for debugging purposes.\r\n * If the file does not exist, it creates it.\r\n *\r\n * @param filePath - The path to the JSON file where history will be stored.\r\n * @param rawMsg - The raw WhatsApp message object to store.\r\n *\r\n * @example\r\n * ```typescript\r\n * Debug_StoreWhatsMsgHistoryInJson(\"./debug_history.json\", rawMsg);\r\n * ```\r\n */\r\nexport function Debug_StoreWhatsMsgHistoryInJson(filePath: string, rawMsg: WhatsappMessage) {\r\n let msgsStored: any[] = [];\r\n if (fs.existsSync(GetPath(filePath))) {\r\n const before = fs.readFileSync(GetPath(filePath), \"utf-8\");\r\n if (before.trim() === \"\") {\r\n msgsStored = [];\r\n } else {\r\n msgsStored = JSON.parse(before);\r\n }\r\n } else {\r\n //Creates the file if it doesn't exist\r\n fs.writeFileSync(GetPath(filePath), \"\", \"utf-8\");\r\n msgsStored = [];\r\n }\r\n msgsStored.push(rawMsg);\r\n const json = JSON.stringify(msgsStored, null, 2);\r\n fs.writeFileSync(GetPath(filePath), json, \"utf-8\");\r\n}\r\n","import type { CommandArgs } from \"../core/bot/internals/CommandsSearcher.types.js\";\r\nimport type { IChatContext } from \"../core/bot/internals/IChatContext.js\";\r\nimport type { AdditionalAPI, ICommand } from \"../core/bot/internals/ICommand.js\";\r\n\r\n/**\r\n * # Command Parameters\r\n *\r\n * Optional parameters to define additional properties for a newly created command, such as aliases.\r\n *\r\n * @example\r\n * ```typescript\r\n * const params: CommandParams = { aliases: [\"ping\", \"p\"] };\r\n * ```\r\n */\r\nexport type CommandParams = {\r\n aliases?: string[];\r\n};\r\n\r\n/**\r\n * # Create Command Helper\r\n *\r\n * A simple function to create commands primarily for JS developers.\r\n * Gives you intellisense when creating your commands without needing\r\n * manual typings inline.\r\n *\r\n * @param commandName - The main trigger string for the command.\r\n * @param run - The execution function where the logic is defined.\r\n * @param params - Optional parameters like aliases.\r\n * @returns A structured `ICommand` ready to be registered in the bot.\r\n *\r\n * @example\r\n * ```typescript\r\n * const pingCommand = CreateCommand(\"ping\", async (ctx) => {\r\n * await ctx.Reply(\"pong\");\r\n * });\r\n * ```\r\n */\r\nexport default function CreateCommand(\r\n commandName: string,\r\n run: (ctx: IChatContext, api: AdditionalAPI, args: CommandArgs) => Promise<void>,\r\n params?: CommandParams\r\n): ICommand {\r\n return {\r\n name: commandName,\r\n run: run,\r\n aliases: params?.aliases,\r\n };\r\n}\r\n","import {\r\n type AnyMessageContent,\r\n type GroupMetadata,\r\n type GroupParticipant,\r\n type MiscMessageGenerationOptions,\r\n type WAMessage,\r\n WAMessageAddressingMode,\r\n} from \"baileys\";\r\nimport { autobind } from \"../../../helpers/Decorators.helper.js\";\r\nimport { MsgHelper_FullMsg_GetMsgType, MsgHelper_FullMsg_GetSenderType } from \"../../../helpers/Msg.helper.js\";\r\nimport Delegate from \"../../../libs/Delegate.js\";\r\nimport type { MsgType, SenderType } from \"../../../Msg.types.js\";\r\nimport { WhatsappGroupIdentifier, WhatsappLIDIdentifier, WhatsappPhoneNumberIdentifier } from \"../../../Whatsapp.types.js\";\r\nimport type { IWhatsSocket_Submodule_Receiver } from \"../internals/IWhatsSocket.receiver.js\";\r\nimport type { IWhatsSocket_Submodule_SugarSender } from \"../internals/IWhatsSocket.sugarsender.js\";\r\nimport type { GroupMetadataInfo, ParticipantInfo } from \"../internals/WhatsSocket.receiver.js\";\r\nimport { WhatsSocket_Submodule_Receiver } from \"../internals/WhatsSocket.receiver.js\";\r\nimport { WhatsSocket_Submodule_SugarSender } from \"../internals/WhatsSocket.sugarsenders.js\";\r\nimport type { IWhatsSocket } from \"../IWhatsSocket.js\";\r\nimport type { WhatsappMessage } from \"../types.js\";\r\nimport type { WhatsSocketMockMsgSent } from \"./types.js\";\r\n\r\nexport type WhatsSocketMockOptions = {\r\n maxQueueLimit?: number;\r\n minimumMilisecondsDelayBetweenMsgs?: number;\r\n customReceiver?: IWhatsSocket_Submodule_Receiver;\r\n customSugarSender?: IWhatsSocket_Submodule_SugarSender;\r\n};\r\n\r\nexport type WhatsSocketMockSendingMsgOptions = {\r\n replaceTextWith?: string;\r\n replaceParticipantIdWith?: string;\r\n replaceChatIdWith?: string;\r\n customMsgType?: MsgType;\r\n changeSenderType?: SenderType;\r\n};\r\n\r\nexport default class WhatsSocketMock implements IWhatsSocket {\r\n // ==== Interface dependencies ====\r\n onRestart: Delegate<() => Promise<void>> = new Delegate();\r\n onSentMessage: Delegate<(chatId: string, rawContentMsg: AnyMessageContent, optionalMisc?: MiscMessageGenerationOptions) => void> = new Delegate();\r\n onIncomingMsg: Delegate<\r\n (participantId_LID: string | null, participantId_PN: string | null, chatId: string, rawMsg: WAMessage, type: MsgType, senderType: SenderType) => void\r\n > = new Delegate();\r\n onUpdateMsg: Delegate<\r\n (\r\n participantId_LID: string | null,\r\n participantId_PN: string | null,\r\n chatId: string,\r\n rawMsgUpdate: WAMessage,\r\n msgType: MsgType,\r\n senderType: SenderType\r\n ) => void\r\n > = new Delegate();\r\n onGroupEnter: Delegate<(groupInfo: GroupMetadata) => void> = new Delegate();\r\n onGroupUpdate: Delegate<(groupInfo: Partial<GroupMetadata>) => void> = new Delegate();\r\n onStartupAllGroupsIn: Delegate<(allGroupsIn: GroupMetadata[]) => void> = new Delegate();\r\n ownJID: string = \"ownIDMock\" + WhatsappPhoneNumberIdentifier;\r\n\r\n Send: IWhatsSocket_Submodule_SugarSender;\r\n Receive: IWhatsSocket_Submodule_Receiver;\r\n\r\n // private _senderQueue: WhatsSocketSenderQueue_SubModule;\r\n\r\n constructor(options?: WhatsSocketMockOptions) {\r\n // this._senderQueue = new WhatsSocketSenderQueue_SubModule(this, options?.maxQueueLimit ?? 10, options?.minimumMilisecondsDelayBetweenMsgs ?? 500);\r\n\r\n this.Send = options?.customSugarSender ?? new WhatsSocket_Submodule_SugarSender(this);\r\n this.Receive = options?.customReceiver ?? new WhatsSocket_Submodule_Receiver(this);\r\n\r\n //Thanks js, this is never needed on another languages... ☠️\r\n this._SendRaw = this._SendRaw.bind(this);\r\n this._SendSafe = this._SendSafe.bind(this);\r\n this.Start = this.Start.bind(this);\r\n this.Shutdown = this.Shutdown.bind(this);\r\n this.GetRawGroupMetadata = this.GetRawGroupMetadata.bind(this);\r\n this.ClearMock = this.ClearMock.bind(this);\r\n }\r\n\r\n public SentMessagesThroughQueue: WhatsSocketMockMsgSent[] = [];\r\n public SentMessagesThroughRaw: WhatsSocketMockMsgSent[] = [];\r\n\r\n public GroupsIDTriedToFetch: string[] = [];\r\n\r\n public IsOn: boolean = false;\r\n\r\n public async Start(): Promise<void> {\r\n this.IsOn = true;\r\n }\r\n public async Shutdown(): Promise<void> {\r\n this.IsOn = false;\r\n }\r\n public async _SendSafe(chatId_JID: string, content: AnyMessageContent, options?: MiscMessageGenerationOptions): Promise<WAMessage | null> {\r\n let chatIdToUse: string;\r\n if (!chatId_JID.endsWith(WhatsappGroupIdentifier)) {\r\n chatIdToUse = chatId_JID + WhatsappGroupIdentifier;\r\n } else {\r\n chatIdToUse = chatId_JID;\r\n }\r\n\r\n this.SentMessagesThroughQueue.push({\r\n chatId: chatIdToUse,\r\n content: content,\r\n miscOptions: options,\r\n });\r\n return {\r\n message: {\r\n conversation: \"Mock Minimum Object WAMessage from SendSafe\",\r\n },\r\n key: {\r\n fromMe: false,\r\n id: \"23423423234\" + WhatsappLIDIdentifier,\r\n remoteJid: \"falseid\" + WhatsappGroupIdentifier,\r\n },\r\n };\r\n }\r\n\r\n public async _SendRaw(chatId_JID: string, content: AnyMessageContent, options?: MiscMessageGenerationOptions): Promise<WAMessage | null> {\r\n let chatIdToUse: string;\r\n if (!chatId_JID.endsWith(WhatsappGroupIdentifier)) {\r\n chatIdToUse = chatId_JID + WhatsappGroupIdentifier;\r\n } else {\r\n chatIdToUse = chatId_JID;\r\n }\r\n this.SentMessagesThroughRaw.push({\r\n chatId: chatIdToUse,\r\n content,\r\n miscOptions: options,\r\n });\r\n return {\r\n message: {\r\n conversation: \"Mock Minimum Object WAMessage from SendRaw\",\r\n },\r\n key: {\r\n fromMe: false,\r\n id: \"23423423234\" + WhatsappLIDIdentifier,\r\n remoteJid: \"falseid\" + WhatsappGroupIdentifier,\r\n },\r\n };\r\n }\r\n\r\n private _groupMetadataMock?: GroupMetadata;\r\n\r\n @autobind\r\n public SetGroupMetadataMock(groupData: Partial<GroupMetadataInfo>) {\r\n let chatIdToUse: string | undefined;\r\n if (groupData.id) {\r\n if (!groupData.id.endsWith(WhatsappGroupIdentifier)) {\r\n chatIdToUse = groupData.id + WhatsappGroupIdentifier;\r\n } else {\r\n chatIdToUse = groupData.id;\r\n }\r\n }\r\n this._groupMetadataMock = {\r\n id: chatIdToUse ?? \"fakeIdGroup\" + WhatsappGroupIdentifier,\r\n addressingMode: groupData?.sendingMode === \"pn\" ? WAMessageAddressingMode.PN : WAMessageAddressingMode.LID,\r\n owner: groupData?.ownerName ?? undefined,\r\n subject: groupData?.groupName ?? \"GroupName\",\r\n desc: groupData?.groupDescription ?? undefined,\r\n linkedParent: groupData?.communityIdWhereItBelongs ?? undefined,\r\n restrict: groupData?.onlyAdminsCanChangeGroupSettings ?? undefined,\r\n announce: groupData?.onlyAdminsCanSendMsgs ?? undefined,\r\n memberAddMode: groupData?.membersCanAddOtherMembers ?? undefined,\r\n joinApprovalMode: groupData?.needsRequestApprovalToJoinIn ?? undefined,\r\n isCommunity: false, // not exposed in high-level\r\n isCommunityAnnounce: groupData?.isCommunityAnnounceChannel ?? undefined,\r\n size: groupData?.membersCount ?? undefined,\r\n ephemeralDuration: groupData?.ephemeralDuration ?? undefined,\r\n inviteCode: groupData?.inviteCode ?? undefined,\r\n subjectTime: groupData?.lastNameChangeDateTime ?? undefined,\r\n author: groupData?.author ?? undefined,\r\n creation: groupData?.creationDate ?? undefined,\r\n participants: groupData?.members ? groupData?.members.map(mapParticipant) : [],\r\n };\r\n }\r\n\r\n /**\r\n * Gets the metadata of a group chat by its chat ID. (e.g: \"23423423123@g.us\")\r\n * @param chatId The chat ID of the group you want to get metadata from.\r\n * @returns A promise that resolves to the group metadata.\r\n */\r\n @autobind\r\n public async GetRawGroupMetadata(chatId: string): Promise<GroupMetadata> {\r\n this.GroupsIDTriedToFetch.push(chatId);\r\n if (this._groupMetadataMock) {\r\n return this._groupMetadataMock;\r\n } else {\r\n return {\r\n id: chatId,\r\n subject: \"Mock Group\",\r\n creation: Date.now(),\r\n creator: \"Some User\",\r\n } as any;\r\n }\r\n }\r\n\r\n public ClearMock(): void {\r\n this.IsOn = false;\r\n this.GroupsIDTriedToFetch = [];\r\n this.SentMessagesThroughQueue = [];\r\n\r\n this.onRestart.Clear();\r\n this.onIncomingMsg.Clear();\r\n this.onGroupEnter.Clear();\r\n this.onGroupUpdate.Clear();\r\n this.onStartupAllGroupsIn.Clear();\r\n this.onUpdateMsg.Clear();\r\n this.SentMessagesThroughRaw = [];\r\n this.SentMessagesThroughQueue = [];\r\n }\r\n\r\n /**\r\n * Simulates the reception of a message from whatsapp asynchronously!\r\n * @param rawMsg The message to be sent.\r\n * @param options Optional options to modify the message before sending it.\r\n * Currently only supports replacing the text of the message.\r\n * @returns Resolves to void.\r\n */\r\n public async MockSendMsgAsync(rawMsg: WhatsappMessage, options?: WhatsSocketMockSendingMsgOptions): Promise<void> {\r\n const info = this._extractInfoFromWhatsMsg(rawMsg, options);\r\n await this.onIncomingMsg.CallAllAsync(\r\n info.rawMsg.key.participant ?? null,\r\n info.rawMsg.key.participantAlt ?? null,\r\n info.rawMsg.key.remoteJid!,\r\n info.rawMsg,\r\n options?.customMsgType ?? info.msgType,\r\n options?.changeSenderType ?? info.senderType\r\n );\r\n }\r\n\r\n /**\r\n * @deprecated Use 'MockSendMsgAsync()' instead from this object 'WhatsSocketMock'. Its more reliable and normally\r\n * all code logic related to mockSending is Promised-Based....\r\n *\r\n * Simulates the reception of a message from whatsapp synchronously!\r\n * @param rawMsg The message to be sent.\r\n * @param options Optional options to modify the message before sending it.\r\n * Currently only supports replacing the text of the message.\r\n * @returns Resolves to void.\r\n */\r\n public MockSendMsg(rawMsg: WhatsappMessage, options?: WhatsSocketMockSendingMsgOptions): void {\r\n const info = this._extractInfoFromWhatsMsg(rawMsg, options);\r\n this.onIncomingMsg.CallAll(\r\n info.rawMsg.key.participant ?? null,\r\n info.rawMsg.key.participantAlt ?? null,\r\n info.rawMsg.key.remoteJid!,\r\n info.rawMsg,\r\n options?.customMsgType ?? info.msgType,\r\n options?.changeSenderType ?? info.senderType\r\n );\r\n }\r\n\r\n private _extractInfoFromWhatsMsg(rawMsg: WhatsappMessage, options?: WhatsSocketMockSendingMsgOptions) {\r\n const msgType: MsgType = MsgHelper_FullMsg_GetMsgType(rawMsg);\r\n const senderType: SenderType = MsgHelper_FullMsg_GetSenderType(rawMsg);\r\n\r\n let msgToReturn: WhatsappMessage;\r\n if (options) {\r\n msgToReturn = structuredClone(rawMsg);\r\n if (!rawMsg.message) {\r\n msgToReturn.message = {};\r\n }\r\n //=== Options handling ====\r\n if (options?.replaceTextWith) {\r\n msgToReturn.message!.conversation = options.replaceTextWith;\r\n }\r\n\r\n if (options?.replaceParticipantIdWith) {\r\n msgToReturn.key.participant = options.replaceParticipantIdWith;\r\n }\r\n\r\n if (options?.replaceChatIdWith) {\r\n msgToReturn.key.remoteJid = options.replaceChatIdWith;\r\n }\r\n } else {\r\n msgToReturn = rawMsg;\r\n }\r\n\r\n return { rawMsg: msgToReturn, msgType, senderType };\r\n }\r\n}\r\n\r\nfunction mapParticipant(p: ParticipantInfo): GroupParticipant {\r\n return {\r\n id: p.rawId ?? \"defaultId\" + WhatsappLIDIdentifier, // from WhatsappIDInfo\r\n name: undefined,\r\n notify: undefined,\r\n status: undefined,\r\n verifiedName: undefined,\r\n imgUrl: undefined,\r\n lid: undefined,\r\n isAdmin: p.isAdmin,\r\n isSuperAdmin: p.isAdmin, // or undefined if you prefer\r\n admin: p.isAdmin ? \"admin\" : null,\r\n };\r\n}\r\n","import type { IChatContextConfig } from \"../core/bot/internals/ChatContext.js\";\r\nimport { ChatContext } from \"../core/bot/internals/ChatContext.js\";\r\nimport type { WhatsappMessage } from \"../core/whats_socket/types.js\";\r\nimport type { MsgType } from \"../Msg.types.js\";\r\n\r\n/**\r\n * Mocking suite for {@link ChatContext}.\r\n *\r\n * This subclass is designed for unit/integration testing where\r\n * you don't want to actually download media from WhatsApp servers.\r\n * Instead of using `downloadMediaMessage`, it returns a configurable\r\n * mock buffer whenever a multimedia message is awaited.\r\n *\r\n * Usage:\r\n * ```ts\r\n * const mockCtx = new ChatContext_MockingSuite();\r\n * mockCtx.SetWaitMultiMediaBufferReturn(Buffer.from(\"test\"));\r\n *\r\n * const buf = await mockCtx.WaitMultimedia(MsgType.Image);\r\n * // buf === Buffer.from(\"test\")\r\n * ```\r\n */\r\nexport default class ChatContext_MockingSuite extends ChatContext {\r\n /**\r\n * Internal buffer to be returned when {@link WaitMultimedia} is called.\r\n * Defaults to `\"mock_buffer\"`.\r\n */\r\n private readonly _defaultBufferToReturn: Buffer = Buffer.from(\"mock_buffer\");\r\n\r\n private _queuedBufferToReturn: Buffer[] = [];\r\n\r\n /**\r\n * Configure the buffer that will be returned in place of a real\r\n * downloaded multimedia message.\r\n *\r\n * @param anyBuffer - The buffer to return on next `WaitMultimedia` calls.\r\n */\r\n public EnqueueMediaBufferToReturn(anyBuffer: Buffer) {\r\n this._queuedBufferToReturn.push(anyBuffer);\r\n }\r\n\r\n /**\r\n * Reset mock state to defaults.\r\n * The mock buffer is reset to `\"mock_buffer\"`.\r\n */\r\n public ClearMocks() {\r\n this._queuedBufferToReturn = [];\r\n }\r\n\r\n /**\r\n * Override of {@link ChatContext.WaitMultimedia}.\r\n *\r\n * Instead of downloading media via baileys, this returns the mock buffer\r\n * set via {@link EnqueueMediaBufferToReturn}.\r\n *\r\n * @param msgTypeToWaitFor - Type of multimedia message to wait for.\r\n * @param localOptions - Optional filters overriding the global context config.\r\n * @returns The configured mock buffer, or `null` if no matching message was found.\r\n */\r\n public override async WaitMultimedia(\r\n msgTypeToWaitFor: MsgType.Image | MsgType.Sticker | MsgType.Video | MsgType.Document | MsgType.Audio,\r\n localOptions?: Partial<IChatContextConfig>\r\n ): Promise<Buffer | null> {\r\n const found: WhatsappMessage | null = await this.WaitMsg(msgTypeToWaitFor, localOptions);\r\n if (!found) return null;\r\n const buffertoReturn: Buffer = this._queuedBufferToReturn.length > 0 ? this._queuedBufferToReturn.shift()! : this._defaultBufferToReturn;\r\n return buffertoReturn;\r\n }\r\n}\r\n","import mime from \"mime\";\r\nimport path from \"path\";\r\nimport type { WhatsappMessage } from \"../core/whats_socket/types.js\";\r\n\r\n/**\r\n * Internal helper for building the minimal base structure of a mock\r\n * WhatsApp message object.\r\n *\r\n * This function provides a consistent \"skeleton\" message with common\r\n * fields prefilled (e.g., `key`, `timestamp`, `deviceListMetadata`),\r\n * which can then be extended with specific message types such as text,\r\n * images, or reactions.\r\n *\r\n * @param chatId - The unique identifier (JID) of the chat where the message belongs.\r\n * @param participantId - The JID of the participant who sends the message.\r\n * @param id - Unique identifier of the message (typically a UUID or hash).\r\n * @param timestamp - Unix timestamp in **seconds** when the message was created.\r\n * @param pushName - Display name of the sender, as it would appear in WhatsApp.\r\n * @returns A partially constructed {@link WhatsappMessage} with basic metadata.\r\n *\r\n * @internal\r\n */\r\nfunction _createBaseMsg(chatId: string, participantId: string | null | undefined, id?: string, timestamp?: number, pushName?: string): WhatsappMessage {\r\n return {\r\n key: {\r\n remoteJid: chatId,\r\n participant: participantId ?? undefined,\r\n fromMe: false,\r\n id: id,\r\n },\r\n messageTimestamp: timestamp ?? Date.now(),\r\n pushName: pushName ?? \"Mock user\",\r\n broadcast: false,\r\n message: {},\r\n deviceListMetadata: {\r\n senderKeyHash: \"qprrpV5KV38MkA==\",\r\n senderTimestamp: \"1355194316\",\r\n recipientKeyHash: \"4gj7dwAGWE3rWw==\",\r\n recipientTimestamp: \"1155394318\",\r\n },\r\n deviceListMetadataVersion: 2,\r\n //@ts-expect-error This is string, but ts thinks is other type for some reason\r\n messageSecret: \"j+pPQKnytgjeJuMsvrly26TrQQjTFgDauhu2Gy9XsUM=\",\r\n };\r\n}\r\n\r\n/**\r\n * Factory function to generate a mock **text message** object in the\r\n * shape expected from the WhatsApp WebSocket.\r\n *\r\n * This is useful for testing, simulations, or mocking incoming messages\r\n * without relying on actual network activity. It builds on top of\r\n * {@link _createBaseMsg} by injecting a `conversation` field that\r\n * contains the text.\r\n *\r\n * @example\r\n * ```ts\r\n * const mockMsg = MsgFactory_CreateText(\r\n * \"12345@s.whatsapp.net\", // chatId\r\n * \"1111@c.us\", // participantId\r\n * \"Hello world!\", // text\r\n * { customSenderWhatsUsername: \"Alice\" }\r\n * );\r\n * ```\r\n *\r\n * @param chatId - The chat JID where the message should appear.\r\n * @param participantId - The JID of the sender (e.g., phone number with domain).\r\n * @param textToIncludeInMsg - The text body of the message (goes into `conversation`).\r\n * @param options - Optional configuration.\r\n * @param options.customSenderWhatsUsername - Override the sender's display name.\r\n *\r\n * @returns A complete {@link WhatsappMessage} object that represents a\r\n * mock text message, including metadata and content.\r\n */\r\nexport function MsgFactory_Text(\r\n chatId: string,\r\n participantId: string | undefined | null,\r\n textToIncludeInMsg: string,\r\n options?: { pushName?: string }\r\n): WhatsappMessage {\r\n const timestamp = Math.floor(Date.now() / 1000);\r\n const pushName = options?.pushName ?? \"User Who Sends this msg (mock response)\";\r\n\r\n const message: WhatsappMessage = _createBaseMsg(chatId, participantId ?? null, \"5AD0EEC1D2649BF2A2EC614714B3ED11\", timestamp, pushName);\r\n message.message = {\r\n conversation: textToIncludeInMsg,\r\n };\r\n return message;\r\n}\r\n\r\n/**\r\n * Factory function to generate a mock **text message with a quoted reply**.\r\n *\r\n * Builds on {@link _createBaseMsg} and injects an `extendedTextMessage`\r\n * with `contextInfo` referencing another {@link WhatsappMessage}.\r\n *\r\n * @example\r\n * ```ts\r\n * const original = MsgFactory_Image(\"123@g.us\", \"111@s.whatsapp.net\", \"http://img.jpg\");\r\n * const reply = MsgFactory_TextWithQuote(\"123@g.us\", null, \"Nice pic!\", original);\r\n * ```\r\n *\r\n * @param chatId - Chat JID where the reply is sent.\r\n * @param participantId - JID of the sender of this reply.\r\n * @param text - The body of the reply message.\r\n * @param quoted - A previously generated {@link WhatsappMessage} that\r\n * will be referenced as the quoted content.\r\n * @param opts.pushName - Override the display name for the sender.\r\n *\r\n * @returns A {@link WhatsappMessage} simulating a text reply with a quoted message.\r\n */\r\nexport function MsgFactory_TextWithQuote(\r\n chatId: string,\r\n participantId: string | null | undefined,\r\n text: string,\r\n quoted: WhatsappMessage,\r\n opts?: { pushName?: string }\r\n): WhatsappMessage {\r\n const base = _createBaseMsg(chatId, participantId, \"success_id_message_id\", Date.now(), opts?.pushName);\r\n\r\n base.message = {\r\n extendedTextMessage: {\r\n text,\r\n contextInfo: {\r\n stanzaId: quoted.key.id,\r\n participant: quoted.key.participant ?? quoted.key.remoteJid,\r\n quotedMessage: quoted.message,\r\n },\r\n },\r\n };\r\n\r\n return base;\r\n}\r\n\r\n/**\r\n * Factory function to generate a mock **image message**.\r\n *\r\n * @example\r\n * ```ts\r\n * const imgMsg = MsgFactory_Image(\"123@g.us\", null, \"http://server/image.jpg\", {\r\n * caption: \"Check this out!\"\r\n * });\r\n * ```\r\n *\r\n * @param chatId - Chat JID where the image is sent.\r\n * @param participantId - JID of the sender.\r\n * @param url - URL or path to the image.\r\n * @param opts.caption - Optional text caption.\r\n * @param opts.pushName - Override display name of sender.\r\n *\r\n * @returns A {@link WhatsappMessage} with an `imageMessage` payload.\r\n */\r\nexport function MsgFactory_Image(\r\n chatId: string,\r\n participantId: string | null | undefined,\r\n url: string,\r\n opts?: { caption?: string; pushName?: string }\r\n): WhatsappMessage {\r\n const base = _createBaseMsg(chatId, participantId, \"success_id_message_id\", Date.now(), opts?.pushName);\r\n base.message = {\r\n imageMessage: {\r\n url,\r\n mimetype: mime.getExtension(path.extname(url)),\r\n caption: opts?.caption,\r\n },\r\n };\r\n return base;\r\n}\r\n\r\n/**\r\n * Factory function to generate a mock **video message**.\r\n *\r\n * @example\r\n * ```ts\r\n * const vidMsg = MsgFactory_Video(\"123@g.us\", \"111@s.whatsapp.net\", \"http://vid.mp4\", {\r\n * caption: \"Funny video\"\r\n * });\r\n * ```\r\n *\r\n * @param chatId - Chat JID where the video is sent.\r\n * @param participantId - JID of the sender.\r\n * @param url - URL or path to the video.\r\n * @param opts.caption - Optional text caption.\r\n * @param opts.pushName - Override sender display name.\r\n *\r\n * @returns A {@link WhatsappMessage} with a `videoMessage` payload.\r\n */\r\nexport function MsgFactory_Video(\r\n chatId: string,\r\n participantId: string | null | undefined,\r\n url: string,\r\n opts?: { caption?: string; pushName?: string }\r\n): WhatsappMessage {\r\n const base = _createBaseMsg(chatId, participantId, \"success_id_message_id\", Date.now(), opts?.pushName);\r\n base.message = {\r\n videoMessage: {\r\n url,\r\n mimetype: mime.getExtension(path.extname(url)),\r\n caption: opts?.caption,\r\n },\r\n };\r\n return base;\r\n}\r\n\r\n/**\r\n * Factory function to generate a mock **audio message**.\r\n *\r\n * @example\r\n * ```ts\r\n * const audioMsg = MsgFactory_Audio(\"123@g.us\", null, \"http://server/audio.ogg\");\r\n * ```\r\n *\r\n * @param chatId - Chat JID where the audio is sent.\r\n * @param participantId - JID of the sender.\r\n * @param url - URL or path to the audio file.\r\n * @param opts.pushName - Override sender display name.\r\n *\r\n * @returns A {@link WhatsappMessage} with an `audioMessage` payload.\r\n */\r\nexport function MsgFactory_Audio(chatId: string, participantId: string | null | undefined, url: string, opts?: { pushName?: string }): WhatsappMessage {\r\n const base = _createBaseMsg(chatId, participantId, \"success_id_message_id\", Date.now(), opts?.pushName);\r\n base.message = {\r\n audioMessage: {\r\n url,\r\n mimetype: mime.getExtension(path.extname(url)),\r\n },\r\n };\r\n return base;\r\n}\r\n\r\n/**\r\n * Factory function to generate a mock **sticker message**.\r\n *\r\n * @example\r\n * ```ts\r\n * const stickerMsg = MsgFactory_Sticker(\"123@g.us\", null, \"http://server/sticker.webp\");\r\n * ```\r\n *\r\n * @param chatId - Chat JID where the sticker is sent.\r\n * @param participantId - JID of the sender.\r\n * @param url - URL or path to the `.webp` sticker file.\r\n * @param opts.pushName - Override sender display name.\r\n *\r\n * @returns A {@link WhatsappMessage} with a `stickerMessage` payload.\r\n */\r\nexport function MsgFactory_Sticker(chatId: string, participantId: string | null | undefined, url: string, opts?: { pushName?: string }): WhatsappMessage {\r\n const base = _createBaseMsg(chatId, participantId, \"success_id_message_id\", Date.now(), opts?.pushName);\r\n base.message = {\r\n stickerMessage: {\r\n url,\r\n mimetype: \"image/webp\",\r\n },\r\n };\r\n return base;\r\n}\r\n\r\n/**\r\n * Factory function to generate a mock **document message**.\r\n *\r\n * @example\r\n * ```ts\r\n * const docMsg = MsgFactory_Document(\"123@g.us\", \"111@s.whatsapp.net\", \"http://server/file.pdf\", {\r\n * fileName: \"report.pdf\"\r\n * });\r\n * ```\r\n *\r\n * @param chatId - Chat JID where the document is sent.\r\n * @param participantId - JID of the sender.\r\n * @param url - URL or path to the document file.\r\n * @param opts.fileName - File name shown in WhatsApp.\r\n * @param opts.mimetype - MIME type of the document.\r\n * @param opts.pushName - Override sender display name.\r\n *\r\n * @returns A {@link WhatsappMessage} with a `documentMessage` payload.\r\n */\r\nexport function MsgFactory_Document(\r\n chatId: string,\r\n participantId: string | null | undefined,\r\n url: string,\r\n opts?: { fileName?: string; mimetype?: string; pushName?: string }\r\n): WhatsappMessage {\r\n const base = _createBaseMsg(chatId, participantId, \"success_id_message_id\", Date.now(), opts?.pushName);\r\n base.message = {\r\n documentMessage: {\r\n url,\r\n mimetype: opts?.mimetype ?? \"application/pdf\",\r\n fileName: opts?.fileName ?? \"mock.pdf\",\r\n },\r\n };\r\n return base;\r\n}\r\n/**\r\n * Factory function to generate a mock **location message**.\r\n *\r\n * @example\r\n * ```ts\r\n * const locMsg = MsgFactory_Location(\"123@g.us\", \"111@s.whatsapp.net\", 19.4326, -99.1332, {\r\n * name: \"CDMX\",\r\n * address: \"Zócalo\"\r\n * });\r\n * ```\r\n *\r\n * @param chatId - Chat JID where the location is sent.\r\n * @param participantId - JID of the sender.\r\n * @param lat - Latitude in degrees.\r\n * @param lng - Longitude in degrees.\r\n * @param opts.name - Location name label.\r\n * @param opts.address - Location address label.\r\n * @param opts.pushName - Override sender display name.\r\n *\r\n * @returns A {@link WhatsappMessage} with a `locationMessage` payload.\r\n */\r\nexport function MsgFactory_Location(\r\n chatId: string,\r\n participantId: string | null | undefined,\r\n lat: number,\r\n lng: number,\r\n opts?: { name?: string; address?: string; pushName?: string }\r\n): WhatsappMessage {\r\n const base = _createBaseMsg(chatId, participantId, \"success_id_message_id\", Date.now(), opts?.pushName);\r\n base.message = {\r\n locationMessage: {\r\n degreesLatitude: lat,\r\n degreesLongitude: lng,\r\n name: opts?.name,\r\n address: opts?.address,\r\n },\r\n };\r\n return base;\r\n}\r\n\r\n/**\r\n * Factory function to generate a mock **contact message**.\r\n * Automatically builds proper vCard strings from simple\r\n * contact objects.\r\n *\r\n * Supports either a single contact or an array of contacts.\r\n *\r\n * @param chatId - Chat JID where the contacts array is sent.\r\n * @param participantId - JID of the sender.\r\n * @param contacts - Either a single contact object or an array of contacts.\r\n * Each contact should have:\r\n * - `contactName`: e.g., \"Chris\"\r\n * - `phoneNumber`: e.g., \"5217389273\" (same as +52 1 738 9273)\r\n * @param opts.pushName - Optional sender display name override.\r\n *\r\n * @returns A {@link WhatsappMessage} with a `contactsArrayMessage` payload.\r\n */\r\nexport function MsgFactory_Contact(\r\n chatId: string,\r\n participantId: string | null | undefined,\r\n contacts: { name: string; phone: string } | Array<{ name: string; phone: string }>,\r\n opts?: { pushName?: string }\r\n): WhatsappMessage {\r\n const base = _createBaseMsg(chatId, participantId, \"success_id_message_id\", Date.now(), opts?.pushName);\r\n\r\n // Normalize to array\r\n if (Array.isArray(contacts)) {\r\n base.message = {\r\n contactsArrayMessage: {\r\n contacts: contacts.map((c) => {\r\n const vcard = [\"BEGIN:VCARD\", \"VERSION:3.0\", `FN:${c.name}`, `TEL;type=WAID=${c.phone}`, \"END:VCARD\"].join(\"\\n\");\r\n return { displayName: c.name, vcard };\r\n }),\r\n },\r\n };\r\n } else {\r\n const vcard = [\"BEGIN:VCARD\", \"VERSION:3.0\", `FN:${contacts.name}`, `TEL;type=WAID=${contacts.phone}`, \"END:VCARD\"].join(\"\\n\");\r\n base.message = {\r\n contactMessage: {\r\n displayName: contacts.name,\r\n vcard: vcard,\r\n },\r\n };\r\n }\r\n\r\n return base;\r\n}\r\n","import type { IChatContextConfig } from \"../core/bot/internals/ChatContext.js\";\r\nimport type { IWhatsSocket_Submodule_Receiver } from \"../core/whats_socket/internals/IWhatsSocket.receiver.js\";\r\nimport type { WhatsSocketReceiverError } from \"../core/whats_socket/internals/WhatsSocket.receiver.js\";\r\nimport {\r\n type GroupMetadataInfo,\r\n type WhatsSocketReceiverWaitOptions,\r\n WhatsSocketReceiverMsgError,\r\n} from \"../core/whats_socket/internals/WhatsSocket.receiver.js\";\r\nimport type { WhatsappMessage } from \"../core/whats_socket/types.js\";\r\nimport { MsgHelper_FullMsg_GetMsgType, MsgHelper_FullMsg_GetText } from \"../helpers/Msg.helper.js\";\r\nimport { WhatsappIdType } from \"../helpers/Whatsapp.helper.js\";\r\nimport { MsgType } from \"../Msg.types.js\";\r\nimport { WhatsappGroupIdentifier } from \"../Whatsapp.types.js\";\r\n\r\nexport type WhatsSocketReceiverWaitObject = {\r\n rawMsg: WhatsappMessage;\r\n milisecondsDelayToRespondMock?: number;\r\n};\r\n\r\nexport type WhatsSocketReceiverMsgWaited = {\r\n waitedMsgType: MsgType;\r\n chatId: string;\r\n partipantId_LID: string | null;\r\n participantId_PN: string | null;\r\n options?: Partial<IChatContextConfig>;\r\n};\r\n\r\nexport default class WhatsSocket_Submodule_Receiver_MockingSuite implements IWhatsSocket_Submodule_Receiver {\r\n /**\r\n * Pending msgs to send to command when executed.\r\n */\r\n private _queueWait: WhatsSocketReceiverWaitObject[] = [];\r\n\r\n /**\r\n * Config: Actual metadata to mock when executing command (Environment mock)\r\n */\r\n private _groupMetadataToSendMock: GroupMetadataInfo;\r\n public get GroupMetadataToSendMock(): GroupMetadataInfo | undefined {\r\n return this._groupMetadataToSendMock;\r\n }\r\n\r\n //=================================================== Spy External Methods ==================================================\r\n /**\r\n * All waited msgs from command after its execution\r\n */\r\n public Waited: WhatsSocketReceiverMsgWaited[] = [];\r\n //===========================================================================================================================\r\n\r\n public constructor() {\r\n this._groupMetadataToSendMock = GenerateDefaultGroupMetadata();\r\n }\r\n\r\n public SetGroupMetadataMock(mock: Partial<GroupMetadataInfo>) {\r\n this._groupMetadataToSendMock = GenerateDefaultGroupMetadata(mock);\r\n }\r\n public ResetGroupMetadata() {\r\n this._groupMetadataToSendMock = GenerateDefaultGroupMetadata();\r\n }\r\n\r\n public AddWaitMsg(toAdd: WhatsSocketReceiverWaitObject) {\r\n this._queueWait.push(toAdd);\r\n }\r\n\r\n public ClearMocks() {\r\n this._queueWait = [];\r\n this.Waited = [];\r\n this._groupMetadataToSendMock = GenerateDefaultGroupMetadata();\r\n }\r\n\r\n //_local Options is not used, just used in real commands, here is not necessary;\r\n public WaitMsg(\r\n userID_LID_ToWait: string | null,\r\n userID_PN_to_wait: string | null,\r\n chatId: string,\r\n expectedType: MsgType,\r\n _localOptions?: Partial<IChatContextConfig>\r\n ): Promise<WhatsappMessage> {\r\n return new Promise((resolve, reject) => {\r\n // Removed async from here\r\n if (this._queueWait.length === 0) {\r\n return reject(\r\n new Error(\"ChatContext is trying to wait a msg that will never arrives!... Use MockChat.EnqueueIncoming_****() to enqueue what to return!\")\r\n );\r\n }\r\n const actualWaitedObjInfo = this._queueWait.shift()!;\r\n const timeoutPromise = new Promise<never>((_, rejectTimeout) => {\r\n if (_localOptions?.timeoutSeconds) {\r\n setTimeout(() => {\r\n rejectTimeout({\r\n errorMessage: WhatsSocketReceiverMsgError.Timeout,\r\n wasAbortedByUser: false,\r\n chatId: chatId,\r\n participantId_LID: userID_LID_ToWait,\r\n participantId_PN: userID_PN_to_wait,\r\n } satisfies WhatsSocketReceiverError);\r\n }, _localOptions.timeoutSeconds * 1000);\r\n }\r\n });\r\n\r\n const messageProcessingPromise = (async () => {\r\n const actualMsg_msgType = MsgHelper_FullMsg_GetMsgType(actualWaitedObjInfo.rawMsg);\r\n\r\n if (actualWaitedObjInfo.milisecondsDelayToRespondMock) {\r\n await new Promise((resolveDelay) => setTimeout(resolveDelay, actualWaitedObjInfo.milisecondsDelayToRespondMock));\r\n }\r\n\r\n if (_localOptions?.cancelKeywords) {\r\n if (actualMsg_msgType === MsgType.Text) {\r\n const txt = MsgHelper_FullMsg_GetText(actualWaitedObjInfo.rawMsg);\r\n if (txt) {\r\n const wordsLowerCased = txt.split(\" \").map((word) => word.toLowerCase());\r\n for (const cancelWord of _localOptions.cancelKeywords) {\r\n if (wordsLowerCased.includes(cancelWord.toLowerCase())) {\r\n throw {\r\n errorMessage: WhatsSocketReceiverMsgError.UserCanceledWaiting,\r\n chatId: chatId,\r\n participantId_LID: userID_LID_ToWait,\r\n participantId_PN: userID_PN_to_wait,\r\n wasAbortedByUser: true,\r\n } satisfies WhatsSocketReceiverError;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (actualMsg_msgType !== expectedType) {\r\n throw new Error(\r\n `You have received a msg of type ${MsgType[actualMsg_msgType]} when you expected of type ${MsgType[expectedType]}!, check what are you sending from MockChat.EnqueueIncoming_****() msg!, try again...`\r\n );\r\n }\r\n\r\n this.Waited.push({\r\n options: _localOptions,\r\n chatId: chatId,\r\n partipantId_LID: userID_LID_ToWait,\r\n participantId_PN: userID_PN_to_wait,\r\n waitedMsgType: actualMsg_msgType,\r\n });\r\n\r\n return actualWaitedObjInfo.rawMsg;\r\n })();\r\n\r\n try {\r\n Promise.race([messageProcessingPromise, timeoutPromise]).then(resolve).catch(reject);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n }\r\n\r\n public WaitUntilNextRawMsgFromUserIDInGroup(\r\n userID_LID_ToWait: string | null,\r\n userID_PN_toWait: string | null,\r\n chatToWaitOnID: string,\r\n expectedMsgType: MsgType,\r\n options: WhatsSocketReceiverWaitOptions\r\n ): Promise<WhatsappMessage> {\r\n return this.WaitMsg(userID_LID_ToWait, userID_PN_toWait, chatToWaitOnID, expectedMsgType, options);\r\n }\r\n\r\n public WaitUntilNextRawMsgFromUserIdInPrivateConversation(\r\n userIdToWait: string,\r\n expectedMsgType: MsgType,\r\n options: WhatsSocketReceiverWaitOptions\r\n ): Promise<WhatsappMessage> {\r\n return this.WaitMsg(null, null, userIdToWait, expectedMsgType, options);\r\n }\r\n\r\n /**\r\n * Important note: chatId param Is ignored, if you want to set a custom mock group metadata, use SetGroupMetadataMock() of this class\r\n * @param _chatId Is ignored, if you want to set a custom mock group metadata, use SetGroupMetadataMock() of this class\r\n * @returns The mocked group metadata establish in this mock receiver\r\n */\r\n public async FetchGroupData(_chatId: string): Promise<GroupMetadataInfo | null> {\r\n if (_chatId) {\r\n return { ...this._groupMetadataToSendMock, id: _chatId };\r\n } else {\r\n return this._groupMetadataToSendMock;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Generates a default group metadata object for mocking purposes.\r\n *\r\n * - Provides sensible defaults for all {@link GroupMetadataInfo} fields.\r\n * - Allows overriding any field by passing a partial object.\r\n *\r\n * @param chatContextData - Partial group data to override defaults.\r\n * @returns A fully populated {@link GroupMetadataInfo}.\r\n */\r\nexport function GenerateDefaultGroupMetadata(chatContextData: Partial<GroupMetadataInfo> = {}): GroupMetadataInfo {\r\n const defaults: GroupMetadataInfo = {\r\n id: \"fakeChatId\" + WhatsappGroupIdentifier,\r\n sendingMode: WhatsappIdType.Modern,\r\n ownerName: \"John Doe\",\r\n groupName: \"DEFAULT_groupname\",\r\n groupDescription: \"A group for awesome team collaboration!\",\r\n communityIdWhereItBelongs: null,\r\n onlyAdminsCanChangeGroupSettings: true,\r\n onlyAdminsCanSendMsgs: false,\r\n membersCanAddOtherMembers: true,\r\n needsRequestApprovalToJoinIn: false,\r\n isCommunityAnnounceChannel: false,\r\n membersCount: 25,\r\n ephemeralDuration: 86400, // 24 hours in seconds\r\n inviteCode: \"abc123xyz\",\r\n lastNameChangeDateTime: 1694726400000, // Example timestamp (2023-09-15)\r\n author: \"mock_author\",\r\n creationDate: 1694640000000, // Example timestamp (2023-09-14)\r\n members: [\r\n {\r\n asMentionFormatted: \"@12345678901\",\r\n rawId: \"12345678901@s.whatsapp.net\",\r\n isAdmin: true,\r\n WhatsappIdType: WhatsappIdType.Modern,\r\n },\r\n {\r\n asMentionFormatted: \"@12345678902\",\r\n rawId: \"12345678902@s.whatsapp.net\",\r\n isAdmin: false,\r\n WhatsappIdType: WhatsappIdType.Modern,\r\n },\r\n {\r\n asMentionFormatted: \"@12345678903\",\r\n rawId: \"12345678903@s.whatsapp.net\",\r\n isAdmin: false,\r\n WhatsappIdType: WhatsappIdType.Modern,\r\n },\r\n ],\r\n };\r\n\r\n return {\r\n ...defaults,\r\n ...chatContextData,\r\n members: chatContextData.members ?? defaults.members,\r\n };\r\n}\r\n","import type { WAMessage } from \"baileys\";\r\nimport mime from \"mime\";\r\nimport path from \"node:path\";\r\nimport type {\r\n IWhatsSocket_Submodule_SugarSender,\r\n WhatsMsgAudioOptions,\r\n WhatsMsgDocumentOptions,\r\n WhatsMsgMediaOptions,\r\n WhatsMsgPollOptions,\r\n WhatsMsgSenderSendingOptions,\r\n WhatsMsgSenderSendingOptionsMINIMUM,\r\n WhatsMsgUbicationOptions,\r\n} from \"../core/whats_socket/internals/IWhatsSocket.sugarsender.js\";\r\nimport type { WhatsappMessage } from \"../core/whats_socket/types.js\";\r\nimport { autobind } from \"../helpers/Decorators.helper.js\";\r\nimport { WhatsappGroupIdentifier, WhatsappPhoneNumberIdentifier } from \"../Whatsapp.types.js\";\r\nimport {\r\n MsgFactory_Audio,\r\n MsgFactory_Contact,\r\n MsgFactory_Document,\r\n MsgFactory_Image,\r\n MsgFactory_Location,\r\n MsgFactory_Sticker,\r\n MsgFactory_Text,\r\n MsgFactory_Video,\r\n} from \"./MsgsMockFactory.js\";\r\n\r\n/**\r\n * A mocking implementation of `IWhatsSocket_Submodule_SugarSender` designed for unit testing.\r\n * This class simulates the behavior of sending various WhatsApp message types without interacting\r\n * with the actual WhatsApp socket. Instead, it stores sent message details in public arrays for\r\n * verification in tests (e.g., using `expect` assertions).\r\n *\r\n * @remarks\r\n * - All sending methods return a mock `WhatsappMessage` object simulating success.\r\n * - Chat IDs are normalized to ensure proper group/individual format.\r\n * - Use `ClearMocks()` to reset all stored message arrays between tests.\r\n * - This is not intended for production use; it's solely for testing the sugar sender logic.\r\n *\r\n * @example\r\n * ```ts\r\n * const mockSender = new WhatsSocket_Submodule_SugarSender_MockingSuite();\r\n * await mockSender.Text(\"1234567890\", \"Hello!\");\r\n * expect(mockSender.SentMessages_Texts).toHaveLength(1);\r\n * expect(mockSender.SentMessages_Texts[0].text).toBe(\"Hello!\");\r\n * ```\r\n */\r\nexport default class WhatsSocket_Submodule_SugarSender_MockingSuite implements IWhatsSocket_Submodule_SugarSender {\r\n private readonly PushNameUserMock = \"ChatMock User\";\r\n //=================================================== Spy External Methods ==================================================\r\n // Text\r\n /**\r\n * Array storing details of simulated text messages sent via `Text()`.\r\n */\r\n public SentMessages_Texts: Array<{\r\n chatId: string;\r\n text: string;\r\n options?: WhatsMsgSenderSendingOptions;\r\n }> = [];\r\n /**\r\n * Simulates sending a text message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param text - The message text to send.\r\n * @param options - Optional sending options (e.g., mentions, normalization).\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Texts` for test verification.\r\n * - Normalizes the chat ID using `NormalizeChatId`.\r\n *\r\n * @example\r\n * ```ts\r\n * await mockSender.Text(\"338839029383\" + WhatsappGroupIdentifier, \"Hello World!\", { normalizeMessageText: true });\r\n * expect(mockSender.SentMessages_Texts[0].text).toBe(\"Hello World!\");\r\n * expect(mockSender.SentMessages_Texts[0].options).toEqual({ normalizeMessageText: true });\r\n * ```\r\n */\r\n @autobind\r\n public async Text(chatId: string, text: string, options?: WhatsMsgSenderSendingOptions): Promise<WAMessage | null> {\r\n const chatIdNormalized = NormalizeChatId(chatId);\r\n this.SentMessages_Texts.push({ text: text, options: options, chatId: chatIdNormalized });\r\n return MsgFactory_Text(chatIdNormalized, null, text, { pushName: this.PushNameUserMock });\r\n }\r\n\r\n // Img\r\n /**\r\n * Array storing details of simulated image messages sent via `Image()`.\r\n */\r\n public SentMessages_Imgs: Array<{\r\n chatId: string;\r\n imageOptions: WhatsMsgMediaOptions;\r\n options?: WhatsMsgSenderSendingOptions;\r\n }> = [];\r\n /**\r\n * Simulates sending an image message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param imageOptions - Options for the image (e.g., source path/buffer, caption, format).\r\n * @param options - Optional sending options (e.g., mentions).\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Imgs` for test verification.\r\n * - Does not perform actual file I/O; assumes valid image options.\r\n *\r\n * @example\r\n * ```ts\r\n * const imageOpts = { source: \"./fake.png\", caption: \"Check this image!\" };\r\n * await mockSender.Image(\"1234567890\", imageOpts);\r\n * expect(mockSender.SentMessages_Imgs[0].imageOptions).toEqual(imageOpts);\r\n * ```\r\n */\r\n @autobind\r\n public async Image(chatId: string, imageOptions: WhatsMsgMediaOptions, options?: WhatsMsgSenderSendingOptions): Promise<WAMessage | null> {\r\n const chatIdNormalized = NormalizeChatId(chatId);\r\n this.SentMessages_Imgs.push({ chatId: chatIdNormalized, imageOptions, options });\r\n return MsgFactory_Image(chatIdNormalized, null, imageOptions.source.toString(), {\r\n caption: imageOptions.caption,\r\n pushName: this.PushNameUserMock,\r\n });\r\n }\r\n\r\n // === ReactEmojiToMsg ===\r\n /**\r\n * Array storing details of simulated emoji reactions sent via `ReactEmojiToMsg()`.\r\n */\r\n public SentMessages_ReactedEmojis: Array<{\r\n chatId: string;\r\n rawMsgReactedTo: WAMessage;\r\n emojiStr: string;\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM;\r\n }> = [];\r\n /**\r\n * Simulates reacting to a message with an emoji.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param rawMsgToReactTo - The original message to react to.\r\n * @param emojiStr - The emoji string (e.g., \"👍\").\r\n * @param options - Optional sending options.\r\n * @returns A mock `WhatsappMessage` simulating successful reaction.\r\n *\r\n * @remarks\r\n * - Stores the reaction details in `SentMessages_ReactedEmojis` for test verification.\r\n *\r\n * @example\r\n * ```ts\r\n * const mockMsg = { key: { id: \"msg123\" } } as WAMessage;\r\n * await mockSender.ReactEmojiToMsg(\"1234567890\", mockMsg, \"❤️\");\r\n * expect(mockSender.SentMessages_ReactedEmojis[0].emojiStr).toBe(\"❤️\");\r\n * ```\r\n */\r\n @autobind\r\n public async ReactEmojiToMsg(\r\n chatId: string,\r\n rawMsgToReactTo: WAMessage,\r\n emojiStr: string,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WAMessage | null> {\r\n const chatIdNormalized = NormalizeChatId(chatId);\r\n this.SentMessages_ReactedEmojis.push({ chatId: chatIdNormalized, emojiStr, rawMsgReactedTo: rawMsgToReactTo, options });\r\n return CreateSuccessWhatsMsg(null, chatIdNormalized);\r\n }\r\n\r\n // === Stickers ===\r\n /**\r\n * Array storing details of simulated sticker messages sent via `Sticker()`.\r\n */\r\n public SentMessages_Stickers: Array<{\r\n chatId: string;\r\n stickerUrlSource: string | Buffer;\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM;\r\n }> = [];\r\n /**\r\n * Simulates sending a sticker message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param stickerUrlSource - Source of the sticker (URL string or Buffer).\r\n * @param options - Optional sending options.\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Stickers` for test verification.\r\n * - Does not process or validate the sticker source.\r\n *\r\n * @example\r\n * ```ts\r\n * const stickerBuffer = Buffer.from(\"sticker-data\");\r\n * await mockSender.Sticker(\"1234567890\", stickerBuffer);\r\n * expect(mockSender.SentMessages_Stickers[0].stickerUrlSource).toBe(stickerBuffer);\r\n * ```\r\n */\r\n @autobind\r\n public async Sticker(chatId: string, stickerUrlSource: string | Buffer, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WAMessage | null> {\r\n const chatIdNormalized: string = NormalizeChatId(chatId);\r\n this.SentMessages_Stickers.push({ chatId: chatIdNormalized, stickerUrlSource, options });\r\n return MsgFactory_Sticker(chatIdNormalized, null, stickerUrlSource.toString(), {\r\n pushName: this.PushNameUserMock,\r\n });\r\n }\r\n\r\n // === Audio ===\r\n /**\r\n * Array storing details of simulated audio messages sent via `Audio()`.\r\n */\r\n public SentMessages_Audios: Array<{\r\n chatId: string;\r\n audioParams: WhatsMsgAudioOptions;\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM;\r\n }> = [];\r\n /**\r\n * Simulates sending an audio message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param audioParams - Options for the audio, including:\r\n * - `source`: The audio source, either a file path or a Buffer.\r\n * - `formatExtension`: The file extension of the audio (e.g., \".mp3\", \".ogg\").\r\n * @param options - Optional sending options (e.g., quoting a message).\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Audios` for test verification.\r\n * - Normalizes the chat ID using `NormalizeChatId`.\r\n * - Does not validate the audio content or extension; this is purely for testing.\r\n *\r\n * @example\r\n * ```ts\r\n * const audioOpts = { source: \"./voice.ogg\", formatExtension: \".ogg\" };\r\n * await mockSender.Audio(\"1234567890\", audioOpts);\r\n * expect(mockSender.SentMessages_Audios[0]!.audioParams.formatExtension).toBe(\".ogg\");\r\n * expect(mockSender.SentMessages_Audios[0]!.audioParams.source).toBe(\"./voice.ogg\");\r\n * ```\r\n */\r\n @autobind\r\n public async Audio(chatId: string, audioParams: WhatsMsgAudioOptions, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WAMessage | null> {\r\n const chatIdNormalized: string = NormalizeChatId(chatId);\r\n this.SentMessages_Audios.push({ audioParams, chatId: chatIdNormalized, options });\r\n return MsgFactory_Audio(chatIdNormalized, null, audioParams.source.toString(), {\r\n pushName: this.PushNameUserMock,\r\n });\r\n }\r\n\r\n // === Video ===\r\n /**\r\n * Array storing details of simulated video messages sent via `Video()`.\r\n */\r\n public SentMessages_Videos: Array<{\r\n chatId: string;\r\n videoParams: WhatsMsgMediaOptions;\r\n options?: WhatsMsgSenderSendingOptions;\r\n }> = [];\r\n /**\r\n * Simulates sending a video message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param videoParams - Options for the video (e.g., source, caption, format).\r\n * @param options - Optional sending options.\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Videos` for test verification.\r\n *\r\n * @example\r\n * ```ts\r\n * const videoOpts = { source: \"./clip.mp4\", caption: \"Watch this!\" };\r\n * await mockSender.Video(\"1234567890\", videoOpts);\r\n * expect(mockSender.SentMessages_Videos[0].videoParams.caption).toBe(\"Watch this!\");\r\n * ```\r\n */\r\n @autobind\r\n public async Video(chatId: string, videoParams: WhatsMsgMediaOptions, options?: WhatsMsgSenderSendingOptions): Promise<WAMessage | null> {\r\n const chatIdNormalized: string = NormalizeChatId(chatId);\r\n this.SentMessages_Videos.push({ chatId: chatIdNormalized, videoParams, options });\r\n return MsgFactory_Video(chatIdNormalized, null, videoParams.source.toString(), {\r\n caption: videoParams.caption,\r\n pushName: this.PushNameUserMock,\r\n });\r\n }\r\n\r\n /**\r\n * Array storing details of simulated document messages sent via `Document()`.\r\n */\r\n public SentMessages_Documents: Array<{\r\n chatId: string;\r\n docParams: WhatsMsgDocumentOptions;\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM;\r\n }> = [];\r\n /**\r\n *\r\n * Simulates sending a document message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param docParams - Options for the document (e.g., source path/buffer, filename).\r\n * @param options - Optional sending options.\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Documents` for test verification.\r\n *\r\n * @example\r\n * ```ts\r\n * const docOpts = { source: \"./report.pdf\", fileNameToDisplay: \"Report 2025\" };\r\n * await mockSender.Document(\"1234567890\", docOpts);\r\n * expect(mockSender.SentMessages_Documents[0].docParams.fileNameToDisplay).toBe(\"Report 2025\");\r\n * ```\r\n */\r\n @autobind\r\n public async Document(chatId: string, docParams: WhatsMsgDocumentOptions, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WAMessage | null> {\r\n const chatIdNormalized: string = NormalizeChatId(chatId);\r\n this.SentMessages_Documents.push({ chatId: chatIdNormalized, docParams, options });\r\n if (typeof docParams.source === \"string\") {\r\n return MsgFactory_Document(chatIdNormalized, null, docParams.source, {\r\n fileName: path.basename(docParams.source),\r\n mimetype: mime.getType(path.extname(docParams.source)) ?? undefined,\r\n pushName: this.PushNameUserMock,\r\n });\r\n } else {\r\n return MsgFactory_Document(chatIdNormalized, null, \"./file-buffer.mock\", {\r\n fileName: \"file-buffer.mock\",\r\n mimetype: undefined,\r\n pushName: this.PushNameUserMock,\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Array storing details of simulated poll messages sent via `Poll()`.\r\n */\r\n public SentMessages_Polls: Array<{\r\n chatId: string;\r\n pollTitle: string;\r\n selections: string[];\r\n pollParams: WhatsMsgPollOptions;\r\n moreOptions?: WhatsMsgSenderSendingOptionsMINIMUM;\r\n }> = [];\r\n\r\n /**\r\n * Simulates sending a poll message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param pollTitle - The poll question/title.\r\n * @param selections - Array of poll options (1-12 items).\r\n * @param pollParams - Poll-specific options (e.g., multi-select, normalization).\r\n * @param moreOptions - Additional sending options.\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Polls` for test verification.\r\n * - Does not validate selection count or normalization in this mock.\r\n *\r\n * @example\r\n * ```ts\r\n * await mockSender.Poll(\"1234567890\", \"Favorite color?\", [\"Red\", \"Blue\"], { withMultiSelect: false });\r\n * expect(mockSender.SentMessages_Polls[0].selections).toEqual([\"Red\", \"Blue\"]);\r\n * ```\r\n */\r\n @autobind\r\n public async Poll(\r\n chatId: string,\r\n pollTitle: string,\r\n selections: string[],\r\n pollParams: WhatsMsgPollOptions,\r\n moreOptions?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WAMessage | null> {\r\n const chatIdNormalized: string = NormalizeChatId(chatId);\r\n this.SentMessages_Polls.push({ chatId: chatIdNormalized, moreOptions, pollParams, pollTitle, selections });\r\n return CreateSuccessWhatsMsg(null, chatIdNormalized);\r\n }\r\n\r\n /**\r\n * Array storing details of simulated location messages sent via `Location()`.\r\n *\r\n * @type {Array<{ chatId: string; ubicationParams: WhatsMsgUbicationOptions; options?: WhatsMsgSenderSendingOptionsMINIMUM }>}\r\n */\r\n public SentMessages_Locations: Array<{\r\n chatId: string;\r\n ubicationParams: WhatsMsgUbicationOptions;\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM;\r\n }> = [];\r\n\r\n /**\r\n * Simulates sending a location message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param ubicationParams - Location parameters (e.g., latitude, longitude, name).\r\n * @param options - Optional sending options.\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Locations` for test verification.\r\n * - Does not validate coordinates in this mock.\r\n *\r\n * @example\r\n * ```ts\r\n * const locParams = { degreesLatitude: 40.7128, degreesLongitude: -74.0060, name: \"NYC\" };\r\n * await mockSender.Location(\"1234567890\", locParams);\r\n * expect(mockSender.SentMessages_Locations[0].ubicationParams.degreesLatitude).toBe(40.7128);\r\n * ```\r\n */\r\n @autobind\r\n public async Location(chatId: string, ubicationParams: WhatsMsgUbicationOptions, options?: WhatsMsgSenderSendingOptionsMINIMUM): Promise<WAMessage | null> {\r\n const chatIdNormalized: string = NormalizeChatId(chatId);\r\n this.SentMessages_Locations.push({ chatId: chatIdNormalized, ubicationParams, options });\r\n return MsgFactory_Location(chatIdNormalized, null, ubicationParams.degreesLatitude, ubicationParams.degreesLongitude, {\r\n address: ubicationParams.addressText,\r\n name: ubicationParams.name,\r\n pushName: this.PushNameUserMock,\r\n });\r\n }\r\n\r\n /**\r\n * Array storing details of simulated contact messages sent via `Contact()`.\r\n *\r\n * @type {Array<{ chatId: string; contacts: { name: string; phone: string } | Array<{ name: string; phone: string }>; options?: WhatsMsgSenderSendingOptionsMINIMUM }>}\r\n */\r\n public SentMessages_Contacts: Array<{\r\n chatId: string;\r\n contacts: { name: string; phone: string } | Array<{ name: string; phone: string }>;\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM;\r\n }> = [];\r\n /**\r\n * Simulates sending a contact (or contacts) message to a chat.\r\n *\r\n * @param chatId - The chat ID (individual or group).\r\n * @param contacts - Single contact or array of contacts (name and phone required).\r\n * @param options - Optional sending options.\r\n * @returns A mock `WhatsappMessage` simulating successful sending.\r\n *\r\n * @remarks\r\n * - Stores the sent details in `SentMessages_Contacts` for test verification.\r\n * - Does not generate vCards or validate contacts in this mock.\r\n *\r\n * @example\r\n * ```ts\r\n * const contact = { name: \"John Doe\", phone: \"1234567890\" };\r\n * await mockSender.Contact(\"1234567890\", contact);\r\n * expect(mockSender.SentMessages_Contacts[0].contacts).toEqual(contact);\r\n * ```\r\n */\r\n @autobind\r\n public async Contact(\r\n chatId: string,\r\n contacts: { name: string; phone: string } | Array<{ name: string; phone: string }>,\r\n options?: WhatsMsgSenderSendingOptionsMINIMUM\r\n ): Promise<WAMessage | null> {\r\n const chatIdNormalized: string = NormalizeChatId(chatId);\r\n this.SentMessages_Contacts.push({ chatId: chatIdNormalized, contacts, options });\r\n return MsgFactory_Contact(chatIdNormalized, null, contacts, {\r\n pushName: this.PushNameUserMock,\r\n });\r\n }\r\n //===========================================================================================================================\r\n /**\r\n * Clears all stored mock message arrays, resetting the mocking suite for new tests.\r\n *\r\n * @remarks\r\n * - Call this in `afterEach` hooks to prevent test pollution.\r\n *\r\n * @example\r\n * ```ts\r\n * afterEach(() => {\r\n * mockSender.ClearMocks();\r\n * });\r\n * ```\r\n */\r\n public ClearMocks(): void {\r\n this.SentMessages_Texts = [];\r\n this.SentMessages_Imgs = [];\r\n this.SentMessages_ReactedEmojis = [];\r\n this.SentMessages_Stickers = [];\r\n this.SentMessages_Audios = [];\r\n this.SentMessages_Videos = [];\r\n this.SentMessages_Documents = [];\r\n this.SentMessages_Polls = [];\r\n this.SentMessages_Locations = [];\r\n this.SentMessages_Contacts = [];\r\n }\r\n\r\n // =============== to add =====================\r\n}\r\n\r\n/**\r\n * Creates a mock `WhatsappMessage` simulating a successful message send.\r\n *\r\n * @param participantId - Optional participant ID for the message key.\r\n * @param chatId - The chat ID for the remote JID.\r\n * @returns A basic `WhatsappMessage` object with a mock key.\r\n *\r\n * @remarks\r\n * - Used internally by all mocking methods to return consistent success responses.\r\n * - TODO: Enhance to create type-specific mock messages.\r\n *\r\n * @internal\r\n */\r\nfunction CreateSuccessWhatsMsg(participantId: string | null, chatId: string): WhatsappMessage {\r\n const toReturn: WhatsappMessage = {\r\n key: {\r\n fromMe: false,\r\n id: \"success_id_message_id\",\r\n participant: participantId ?? undefined,\r\n remoteJid: chatId,\r\n },\r\n };\r\n return toReturn;\r\n}\r\n\r\nfunction NormalizeChatId(rawChatId: string): string {\r\n if (rawChatId.endsWith(WhatsappPhoneNumberIdentifier)) return rawChatId;\r\n if (rawChatId.endsWith(WhatsappGroupIdentifier)) {\r\n return rawChatId;\r\n } else {\r\n return rawChatId + WhatsappGroupIdentifier;\r\n }\r\n}\r\n","import mime from \"mime\";\r\nimport path from \"node:path\";\r\nimport { type WhatsBotOptions, BotUtils_GenerateOptions } from \"../core/bot/bot.js\";\r\nimport type { IChatContextConfig } from \"../core/bot/internals/ChatContext.js\";\r\nimport Myself_Submodule_Status from \"../core/bot/internals/ChatContext.myself.status.js\";\r\nimport CommandsSearcher, { CommandType } from \"../core/bot/internals/CommandsSearcher.js\";\r\nimport type { ICommand } from \"../core/bot/internals/ICommand.js\";\r\nimport type { GroupMetadataInfo } from \"../core/whats_socket/internals/WhatsSocket.receiver.js\";\r\nimport type { WhatsSocketMockMsgSent } from \"../core/whats_socket/mocks/types.js\";\r\nimport WhatsSocketMock from \"../core/whats_socket/mocks/WhatsSocket.mock.js\";\r\nimport type { WhatsappMessage } from \"../core/whats_socket/types.js\";\r\nimport { autobind } from \"../helpers/Decorators.helper.js\";\r\nimport { ChatContext, MsgType, SenderType } from \"../index.js\";\r\nimport { WhatsappGroupIdentifier, WhatsappLIDIdentifier, WhatsappPhoneNumberIdentifier } from \"../Whatsapp.types.js\";\r\nimport ChatContext_MockingSuite from \"./ChatContext.mockingsuite.js\";\r\nimport {\r\n MsgFactory_Audio,\r\n MsgFactory_Contact,\r\n MsgFactory_Document,\r\n MsgFactory_Image,\r\n MsgFactory_Location,\r\n MsgFactory_Sticker,\r\n MsgFactory_Text,\r\n MsgFactory_Video,\r\n} from \"./MsgsMockFactory.js\";\r\nimport type { WhatsSocketReceiverMsgWaited } from \"./WhatsSocket.receiver.mockingsuite.js\";\r\nimport WhatsSocket_Submodule_Receiver_MockingSuite from \"./WhatsSocket.receiver.mockingsuite.js\";\r\nimport WhatsSocket_Submodule_SugarSender_MockingSuite from \"./WhatsSocket.sugarsender.mockingsuite.js\";\r\n\r\n/**\r\n * Extends {@link WhatsBotOptions} with additional settings specific to the mocking suite.\r\n */\r\ntype AdditionalWhatsBotOptions = {\r\n /**\r\n * An array of commands to pre-register in the bot's command handler\r\n * when the mock environment is initialized. This is useful for testing\r\n * commands that might depend on or interact with other commands.\r\n *\r\n * @example\r\n * ```ts\r\n * const chat = new ChatMock(myCommand, {\r\n * botSettings: {\r\n * initialCommandsToAdd: [new AnotherCommand(), new HelperCommand()]\r\n * }\r\n * });\r\n * ```\r\n */\r\n initialCommandsToAdd: Array<{ command: ICommand; commandType: CommandType }>;\r\n};\r\n\r\n/**\r\n * Defines the configuration parameters for creating a `ChatMock` instance.\r\n *\r\n * This object allows for detailed customization of the simulated chat\r\n * environment, including sender details, bot settings, and message context.\r\n */\r\nexport type MockingChatParams = {\r\n /**\r\n * Overrides for the `ChatContext` configuration, such as timeouts and\r\n * feedback messages. `cancelKeywords` is handled separately.\r\n */\r\n chatContextConfig?: Omit<Partial<IChatContextConfig>, \"cancelKeywords\">;\r\n /**\r\n * Overrides for the bot's settings (`WhatsBotOptions`), allowing customization\r\n * of prefixes, logging, and other bot behaviors for the test. Also includes\r\n * mock-specific options via `AdditionalWhatsBotOptions`.\r\n */\r\n botSettings?: Omit<Partial<WhatsBotOptions>, \"cancelKeywords\"> & Partial<AdditionalWhatsBotOptions>;\r\n /**\r\n * The simulated chat ID. If not provided, a default is generated.\r\n * The suffix (`@g.us` or `@s.whatsapp.net`) is automatically handled based on `senderType`.\r\n */\r\n chatId?: string;\r\n /**\r\n * The LID (Legacy ID) of the simulated message sender.\r\n * If provided, the `senderType` will default to `Group`.\r\n */\r\n participantId_LID?: string | null;\r\n /**\r\n * The PN (Phone Number ID) of the simulated message sender.\r\n * If provided, the `senderType` will default to `Group`.\r\n */\r\n participantId_PN?: string | null;\r\n /**\r\n * An array of strings representing the arguments passed to the command,\r\n * as if they were typed by the user after the command name.\r\n */\r\n args?: string[];\r\n /**\r\n * The type of the initial (command-triggering) message.\r\n * @default MsgType.Text\r\n */\r\n msgType?: MsgType;\r\n /**\r\n * The type of chat context to simulate.\r\n * - `SenderType.Individual`: A private one-on-one chat.\r\n * - `SenderType.Group`: A group chat.\r\n * @default SenderType.Individual (unless a participantId is provided)\r\n */\r\n senderType?: SenderType;\r\n /**\r\n * A list of keywords that will trigger a cancellation error when the\r\n * command is waiting for a user response.\r\n */\r\n cancelKeywords?: string[];\r\n};\r\n\r\nexport type MockEnqueueParamsMinimal = { pushName?: string; delayMilisecondsToReponse?: number };\r\n\r\nexport type MockEnqueueParamsMultimediaMinimal = MockEnqueueParamsMinimal & { imgContentBufferMock?: Buffer | Buffer<ArrayBuffer> };\r\nexport type MockEnqueueParamsMultimedia = MockEnqueueParamsMultimediaMinimal & { caption?: string };\r\nexport type MockEnqueueParamsDocument = MockEnqueueParamsMultimediaMinimal & { mimeType?: string };\r\nexport type MockEnqueueParamsLocation = MockEnqueueParamsMinimal & { locationName?: string; addressDescription?: string };\r\n\r\n/**\r\n * MockingChat is a helper utility designed to simulate a full WhatsApp chat session\r\n * against a given {@link ICommand}.\r\n *\r\n * It provides:\r\n * - Mocked **receiver**, **sender**, and **socket** modules for message flow control.\r\n * - Facilities to enqueue fake user messages (`SimulateTextSending`).\r\n * - Accessors to inspect messages that were sent/queued by the command under test.\r\n * - A fully configured {@link ChatContext} spy object for realistic command execution.\r\n *\r\n * Usage:\r\n * ```ts\r\n * const mock = new MockingChat(myCommand, { customParticipantId: \"12345\" });\r\n * mock.SimulateTextSending(\"hello\");\r\n * await mock.StartChatSimulation();\r\n * ```\r\n */\r\nexport default class ChatMock {\r\n public readonly ParticipantId_LID: string | null;\r\n public readonly ParticipantId_PN: string | null;\r\n public readonly ChatId: string;\r\n\r\n private readonly _senderType: SenderType;\r\n private _constructorConfig?: MockingChatParams;\r\n private _chatContextMock: ChatContext_MockingSuite;\r\n private _command: ICommand;\r\n private _receiverMock: WhatsSocket_Submodule_Receiver_MockingSuite;\r\n private _sugarSenderMock: WhatsSocket_Submodule_SugarSender_MockingSuite;\r\n private _socketMock: WhatsSocketMock;\r\n\r\n /**\r\n * All messages \"waited\" (consumed) from the mocked receiver.\r\n * Useful to check what input the command attempted to consume.\r\n */\r\n public get WaitedFromCommand(): WhatsSocketReceiverMsgWaited[] {\r\n return this._receiverMock.Waited;\r\n }\r\n\r\n /**\r\n * All messages sent via the sugar-sender mock.\r\n * These are usually text responses triggered by the command logic.\r\n */\r\n public get SentFromCommand() {\r\n return {\r\n //From whatssocket_receiver\r\n Texts: this._sugarSenderMock.SentMessages_Texts,\r\n Images: this._sugarSenderMock.SentMessages_Imgs,\r\n ReactedEmojis: this._sugarSenderMock.SentMessages_ReactedEmojis,\r\n Stickers: this._sugarSenderMock.SentMessages_Stickers,\r\n Audios: this._sugarSenderMock.SentMessages_Audios,\r\n Videos: this._sugarSenderMock.SentMessages_Videos,\r\n Documents: this._sugarSenderMock.SentMessages_Documents,\r\n Polls: this._sugarSenderMock.SentMessages_Polls,\r\n Locations: this._sugarSenderMock.SentMessages_Locations,\r\n Contacts: this._sugarSenderMock.SentMessages_Contacts,\r\n };\r\n }\r\n\r\n /**\r\n * Messages that were sent **through the queue** using the mocked socket.\r\n * This simulates queued delivery (e.g., internal socket enqueuing).\r\n */\r\n public get SentFromCommandSocketQueue(): WhatsSocketMockMsgSent[] {\r\n return this._socketMock.SentMessagesThroughQueue;\r\n }\r\n\r\n /**\r\n * Messages that were sent **directly without queueing** using the mocked socket.\r\n * This simulates \"raw\" delivery. ()\r\n */\r\n public get SentFromCommandSocketWithoutQueue(): WhatsSocketMockMsgSent[] {\r\n return this._socketMock.SentMessagesThroughRaw;\r\n }\r\n\r\n /**\r\n * Creates a new mock chat simulation environment for a given command.\r\n *\r\n * @param commandToTest - The {@link ICommand} instance to test.\r\n * @param additionalOptions - Optional parameters that customize chat setup,\r\n * such as `customChatId`, `customParticipantId`, `args`, or `senderType`.\r\n *\r\n * Behavior:\r\n * - If `customParticipantId` is provided, a group chat ID is assumed unless overridden.\r\n * - Otherwise, defaults to a private one-to-one chat.\r\n * - Automatically ensures correct WhatsApp LID suffixes for IDs.\r\n */\r\n constructor(commandToTest: ICommand, additionalOptions?: MockingChatParams) {\r\n this._constructorConfig = additionalOptions;\r\n this._command = commandToTest;\r\n\r\n // const senderTypeToMock: SenderType = additionalOptions?.senderType ?? SenderType.Individual;\r\n const senderTypeToMock: SenderType = additionalOptions?.senderType ?? SenderType.Individual;\r\n this._senderType = senderTypeToMock;\r\n const { chatIdResolved, updatedSenderType: resolveChatIdFoundSenderType } = Constructor_ResolveChatID(additionalOptions?.chatId, this._senderType);\r\n this.ChatId = chatIdResolved;\r\n if (resolveChatIdFoundSenderType) this._senderType = resolveChatIdFoundSenderType;\r\n\r\n const {\r\n LID,\r\n PN,\r\n senderTypeUpdated: resolveParticipantsFoundSenderType,\r\n } = Constructor_ResolveParticipantIds(additionalOptions?.participantId_LID, additionalOptions?.participantId_PN, this._senderType);\r\n if (resolveParticipantsFoundSenderType) this._senderType = resolveParticipantsFoundSenderType;\r\n\r\n this.ParticipantId_LID = LID;\r\n this.ParticipantId_PN = PN;\r\n if (additionalOptions?.senderType) this._senderType = additionalOptions?.senderType;\r\n\r\n const chatContextConfig: IChatContextConfig = {\r\n cancelKeywords: this._constructorConfig?.cancelKeywords ?? [\"cancel\"],\r\n ignoreSelfMessages: this._constructorConfig?.chatContextConfig?.ignoreSelfMessages ?? true,\r\n timeoutSeconds: this._constructorConfig?.chatContextConfig?.timeoutSeconds ?? 15,\r\n cancelFeedbackMsg:\r\n this._constructorConfig?.chatContextConfig?.cancelFeedbackMsg ?? \"Default cancel message mocking, user has canceled this command with a cancel word\",\r\n wrongTypeFeedbackMsg:\r\n this._constructorConfig?.chatContextConfig?.wrongTypeFeedbackMsg ??\r\n \"Default wrong expected type message, user has sent a msg which doesn't correspond to expected WaitMsg from command...\",\r\n explicitSenderType: this._senderType,\r\n };\r\n this._receiverMock = new WhatsSocket_Submodule_Receiver_MockingSuite();\r\n this._sugarSenderMock = new WhatsSocket_Submodule_SugarSender_MockingSuite();\r\n this._socketMock = new WhatsSocketMock({ customReceiver: this._receiverMock, customSugarSender: this._sugarSenderMock });\r\n const chatContext = new ChatContext_MockingSuite(\r\n this.ParticipantId_LID,\r\n this.ParticipantId_PN,\r\n this.ChatId,\r\n MsgFactory_Text(this.ChatId, this.ParticipantId_LID, `!${this._command.name}`, { pushName: \"ChatMock User\" }),\r\n this._sugarSenderMock,\r\n this._receiverMock,\r\n chatContextConfig\r\n );\r\n this._chatContextMock = chatContext;\r\n }\r\n\r\n /**\r\n * Simulates the sending of a text message into the mocked chat.\r\n * This enqueues the message into the mocked receiver, making it\r\n * available for the command to \"consume\" during execution.\r\n *\r\n * @param textToEnqueue - The message content to simulate.\r\n * @param options - Allows overriding the sender pushName (WhatsApp display name).\r\n */\r\n @autobind\r\n public EnqueueIncoming_Text(textToEnqueue: string, options?: MockEnqueueParamsMinimal): void {\r\n const txtMsg: WhatsappMessage = MsgFactory_Text(this.ChatId, this.ParticipantId_LID, textToEnqueue, {\r\n pushName: options?.pushName,\r\n });\r\n this._receiverMock.AddWaitMsg({ rawMsg: txtMsg, milisecondsDelayToRespondMock: options?.delayMilisecondsToReponse });\r\n }\r\n\r\n /**\r\n * Simulates an incoming image message, enqueuing it for the command under test to consume.\r\n *\r\n * ### Overloads\r\n * This method provides two convenient overloads for simulating image messages:\r\n *\r\n * 1. **`EnqueueIncoming_Img(imgUrl: string, opts?: MockEnqueueParamsMultimedia)`**\r\n * - Simulates an image from a specific URL or file path.\r\n * - Use the `opts` parameter to add a `caption`, `pushName`, or mock the download buffer.\r\n *\r\n * 2. **`EnqueueIncoming_Img(opts?: MockEnqueueParamsMultimedia)`**\r\n * - Simulates a generic, default placeholder image (`./whatsbotcord-mock-img.png`).\r\n * - This is useful when the specific image content is not important for the test.\r\n * - Can be called with no arguments.\r\n *\r\n * ### Multimedia Mocking\r\n * The `bufferToReturnOn_WaitMultimedia` option allows you to specify a `Buffer` that `ctx.WaitMultimedia()`\r\n * will resolve with. This is essential for testing multimedia handling logic without performing\r\n * actual downloads.\r\n *\r\n * @example\r\n * ```ts\r\n * // Overload 1: Simulate an image from a URL with a caption.\r\n * mock.EnqueueIncoming_Img(\"http://example.com/image.jpg\", { caption: \"Look at this!\" });\r\n *\r\n * // Overload 2: Simulate a default image with a custom sender name.\r\n * mock.EnqueueIncoming_Img({ pushName: \"Another User\" });\r\n *\r\n * // Or just... to simulate a generic img coming from user.\r\n * mock.EnqueueIncoming_Img();\r\n * ```\r\n */\r\n public EnqueueIncoming_Img(opts?: MockEnqueueParamsMultimedia): void;\r\n public EnqueueIncoming_Img(imgUrl: string, opts?: MockEnqueueParamsMultimedia): void;\r\n @autobind\r\n public EnqueueIncoming_Img(imgUrl_or_Opts?: MockEnqueueParamsMultimedia | string, onlyOpts?: MockEnqueueParamsMultimedia): void {\r\n // 1st Overload: public EnqueueIncoming_Img(opts?:MockEnqueueParamsMultimedia): void;\r\n if ((typeof imgUrl_or_Opts === \"undefined\" && typeof onlyOpts === \"undefined\") || typeof imgUrl_or_Opts === \"object\") {\r\n const imgMsg: WhatsappMessage = MsgFactory_Image(this.ChatId, this.ParticipantId_LID, \"./whatsbotcord-mock-img.png\", {\r\n caption: imgUrl_or_Opts?.caption,\r\n pushName: imgUrl_or_Opts?.pushName,\r\n });\r\n if (imgUrl_or_Opts?.imgContentBufferMock) {\r\n this._chatContextMock.EnqueueMediaBufferToReturn(imgUrl_or_Opts.imgContentBufferMock);\r\n }\r\n this._receiverMock.AddWaitMsg({ rawMsg: imgMsg, milisecondsDelayToRespondMock: imgUrl_or_Opts?.delayMilisecondsToReponse });\r\n return;\r\n }\r\n\r\n // 2nd Overload: public EnqueueIncoming_Img(imgUrl: string, opts?: MockEnqueueParamsMultimedia): void ;\r\n if (typeof imgUrl_or_Opts === \"string\") {\r\n const imgMsg: WhatsappMessage = MsgFactory_Image(this.ChatId, this.ParticipantId_LID, imgUrl_or_Opts, {\r\n caption: onlyOpts?.caption,\r\n pushName: onlyOpts?.pushName,\r\n });\r\n if (onlyOpts?.imgContentBufferMock) {\r\n this._chatContextMock.EnqueueMediaBufferToReturn(onlyOpts.imgContentBufferMock);\r\n }\r\n this._receiverMock.AddWaitMsg({ rawMsg: imgMsg, milisecondsDelayToRespondMock: onlyOpts?.delayMilisecondsToReponse });\r\n return;\r\n }\r\n }\r\n\r\n /**\r\n * Simulates the sending of a sticker message into the mocked chat.\r\n * Enqueues the message into the mocked receiver for the command to\r\n * consume.\r\n *\r\n * If a `bufferToReturnOnWaitMultimedia` is set, that buffer will be\r\n * returned during multimedia waits instead of performing a real\r\n * download.\r\n *\r\n * @param urlSticker - URL of the sticker file (usually `.webp`).\r\n * @param opts - Optional parameters like pushName and a mock buffer.\r\n */\r\n @autobind\r\n public EnqueueIncoming_Sticker(urlSticker: string, opts?: MockEnqueueParamsMultimediaMinimal): void {\r\n const stickerMsg: WhatsappMessage = MsgFactory_Sticker(this.ChatId, this.ParticipantId_LID, urlSticker, {\r\n pushName: opts?.pushName,\r\n });\r\n if (opts?.imgContentBufferMock) {\r\n this._chatContextMock.EnqueueMediaBufferToReturn(opts.imgContentBufferMock);\r\n }\r\n this._receiverMock.AddWaitMsg({ rawMsg: stickerMsg, milisecondsDelayToRespondMock: opts?.delayMilisecondsToReponse });\r\n }\r\n\r\n /**\r\n * Simulates the sending of an audio message into the mocked chat.\r\n * The message is added to the mocked receiver queue.\r\n *\r\n * If a mock buffer is provided, it will be used when awaiting\r\n * multimedia content via {@link WaitMultimedia}.\r\n *\r\n * @param urlaudio - URL of the audio file to simulate.\r\n * @param opts - Optional pushName and buffer override.\r\n */\r\n @autobind\r\n public EnqueueIncoming_Audio(urlaudio: string, opts?: MockEnqueueParamsMultimediaMinimal): void {\r\n const audioMsg: WhatsappMessage = MsgFactory_Audio(this.ChatId, this.ParticipantId_LID, urlaudio, {\r\n pushName: opts?.pushName,\r\n });\r\n if (opts?.imgContentBufferMock) {\r\n this._chatContextMock.EnqueueMediaBufferToReturn(opts.imgContentBufferMock);\r\n }\r\n this._receiverMock.AddWaitMsg({ rawMsg: audioMsg, milisecondsDelayToRespondMock: opts?.delayMilisecondsToReponse });\r\n }\r\n\r\n /**\r\n * Simulates the sending of a video message into the mocked chat.\r\n * This includes optional captions and sender details.\r\n *\r\n * If a buffer override is specified, it will be used during multimedia\r\n * waits instead of fetching from the URL.\r\n *\r\n * @param urlVideo - URL of the video file to simulate.\r\n * @param opts - Optional parameters (caption, pushName, buffer).\r\n */\r\n @autobind\r\n public EnqueueIncoming_Video(urlVideo: string, opts?: MockEnqueueParamsMultimedia): void {\r\n const videoMsg: WhatsappMessage = MsgFactory_Video(this.ChatId, this.ParticipantId_LID, urlVideo, {\r\n caption: opts?.caption,\r\n pushName: opts?.pushName,\r\n });\r\n if (opts?.imgContentBufferMock) {\r\n this._chatContextMock.EnqueueMediaBufferToReturn(opts.imgContentBufferMock);\r\n }\r\n this._receiverMock.AddWaitMsg({ rawMsg: videoMsg, milisecondsDelayToRespondMock: opts?.delayMilisecondsToReponse });\r\n }\r\n\r\n /**\r\n * Simulates the sending of a document message into the mocked chat.\r\n * Enqueues the message with proper filename and mimetype resolution.\r\n *\r\n * A mock buffer can be attached to override multimedia waits for this\r\n * document.\r\n *\r\n * @param urlDocument - URL of the document to simulate.\r\n * @param fileName - Filename to associate with the document.\r\n * @param opts - Optional mimetype, pushName, and buffer override.\r\n */\r\n @autobind\r\n public EnqueueIncoming_Document(urlDocument: string, fileName: string, opts?: MockEnqueueParamsDocument): void {\r\n const documentMsg: WhatsappMessage = MsgFactory_Document(this.ChatId, this.ParticipantId_LID, urlDocument, {\r\n fileName: fileName,\r\n mimetype: opts?.mimeType ?? mime.getType(path.extname(fileName)) ?? \"application/pdf\",\r\n pushName: opts?.pushName,\r\n });\r\n if (opts?.imgContentBufferMock) {\r\n this._chatContextMock.EnqueueMediaBufferToReturn(opts.imgContentBufferMock);\r\n }\r\n this._receiverMock.AddWaitMsg({ rawMsg: documentMsg, milisecondsDelayToRespondMock: opts?.delayMilisecondsToReponse });\r\n }\r\n\r\n /**\r\n * Simulates the sending of a location message into the mocked chat.\r\n * The message includes geographic coordinates and optional descriptive\r\n * fields like name and address.\r\n *\r\n * @param latitude - Latitude of the location.\r\n * @param longitude - Longitude of the location.\r\n * @param opts - Optional location name, address description, and pushName.\r\n */\r\n @autobind\r\n public EnqueueIncoming_Location(latitude: number, longitude: number, opts?: MockEnqueueParamsLocation): void {\r\n const locationMsg: WhatsappMessage = MsgFactory_Location(this.ChatId, this.ParticipantId_LID, latitude, longitude, {\r\n pushName: opts?.pushName,\r\n address: opts?.addressDescription,\r\n name: opts?.locationName,\r\n });\r\n this._receiverMock.AddWaitMsg({ rawMsg: locationMsg, milisecondsDelayToRespondMock: opts?.delayMilisecondsToReponse });\r\n }\r\n\r\n /**\r\n * Simulates the contact(s) sending mdg into the mocked chat.\r\n * The messaged include all contact or contacts with all mocked\r\n * environment metadata included.\r\n *\r\n * @param contact_s - Contact or contacts array\r\n * @param opts - Optional config obj: Actually including only 'pushName' prop\r\n */\r\n @autobind\r\n public EnqueueIncoming_Contact(contact_s: { name: string; phone: string } | Array<{ name: string; phone: string }>, opts?: MockEnqueueParamsMinimal): void {\r\n const contactMsg = MsgFactory_Contact(this.ChatId, this.ParticipantId_LID, contact_s, {\r\n pushName: opts?.pushName,\r\n });\r\n this._receiverMock.AddWaitMsg({ rawMsg: contactMsg, milisecondsDelayToRespondMock: opts?.delayMilisecondsToReponse });\r\n }\r\n\r\n /**\r\n * Starts the simulation by executing the command under test with the mocked context\r\n * and sending all queued msgs with this class EnqueueIncoming*() methods.\r\n *\r\n * Use it to start your test with your command\r\n *\r\n * This method:\r\n * - Creates a fake invocation of the command (`!commandName`).\r\n * - Injects mocked sender/receiver/socket modules into the execution context.\r\n * - Runs the command's `run` method as if in a real bot environment.\r\n */\r\n @autobind\r\n public async StartChatSimulation(): Promise<void> {\r\n // const receiver: WhatsSocket_Submodule_Receiver = new WhatsSocket_Submodule_Receiver();\r\n //Need to conver\r\n const botCommandsSearcher = new CommandsSearcher();\r\n\r\n if (this._constructorConfig?.botSettings?.initialCommandsToAdd) {\r\n for (const entry of this._constructorConfig.botSettings.initialCommandsToAdd) {\r\n if (entry.commandType === CommandType.Normal) {\r\n botCommandsSearcher.Add(entry.command, CommandType.Normal);\r\n }\r\n if (entry.commandType === CommandType.Tag) {\r\n botCommandsSearcher.Add(entry.command, CommandType.Tag);\r\n }\r\n }\r\n }\r\n\r\n const botSettings = BotUtils_GenerateOptions({ ...this._constructorConfig?.botSettings, cancelKeywords: this._chatContextMock.Config.cancelKeywords });\r\n try {\r\n await this._command.run(\r\n this._chatContextMock,\r\n {\r\n InternalSocket: this._socketMock,\r\n Myself: {\r\n Status: new Myself_Submodule_Status(this._socketMock),\r\n Bot: {\r\n Commands: botCommandsSearcher,\r\n Settings: botSettings,\r\n },\r\n },\r\n },\r\n {\r\n args: this._constructorConfig?.args ?? [],\r\n botInfo: {\r\n Commands: botCommandsSearcher,\r\n Settings: botSettings,\r\n },\r\n chatId: this.ChatId,\r\n participantIdPN: this.ParticipantId_PN,\r\n participantIdLID: this.ParticipantId_LID,\r\n msgType: this._constructorConfig?.msgType ?? MsgType.Text,\r\n originalRawMsg: {} as any,\r\n quotedMsgInfo: {} as any,\r\n senderType: this._senderType,\r\n }\r\n );\r\n } catch (error) {\r\n if (error instanceof Error) {\r\n if (\r\n error.message === \"ChatContext is trying to wait a msg that will never arrives!... Use MockChat.EnqueueIncoming_****() to enqueue what to return!\"\r\n ) {\r\n if (this.SentFromCommand.Texts.length > 0) {\r\n const lastMessage = this.SentFromCommand.Texts.at(-1)!.text;\r\n throw new Error(\r\n \"\\n\\n\\n[Whatsbotcord | MockChat Test Error: Deadlock]\\n\\n\" +\r\n \"The command is waiting for a user reply, but the mock's incoming message queue is empty.\\n\\n\" +\r\n \"Last Message Sent by Command:\\n\" +\r\n `\"${lastMessage}\"\\n\\n` +\r\n \"How to Fix:\\n\" +\r\n \"Use MockChat.EnqueueIncoming_...() in your test setup to provide the message the command is waiting for.\\n\\n\\n\"\r\n );\r\n }\r\n }\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Overrides the group metadata used in this mocked chat environment.\r\n * This is useful for simulating different group states (e.g., id,\r\n * subject, participants) without relying on real WhatsApp server data.\r\n *\r\n * Behavior:\r\n * - Ensures the `id` field has the correct suffix depending on whether\r\n * the current sender type is group or individual.\r\n * - Updates the `ChatId` internally and applies the metadata to the\r\n * receiver and socket mocks.\r\n *\r\n * @param metadata - Partial group metadata to inject into the mock\r\n * environment. If `id` is provided, it will be normalized.\r\n */\r\n @autobind\r\n public SetGroupMetadataMock(metadata: Partial<GroupMetadataInfo>) {\r\n const actualSenderType = this._constructorConfig?.senderType ?? (this.ParticipantId_LID ? SenderType.Group : SenderType.Individual);\r\n if (metadata.id) {\r\n let newChatId: string;\r\n if (actualSenderType === SenderType.Group) {\r\n if (!metadata.id.endsWith(WhatsappGroupIdentifier)) {\r\n newChatId = metadata.id + WhatsappGroupIdentifier;\r\n } else {\r\n newChatId = metadata.id;\r\n }\r\n } else {\r\n if (!metadata.id.endsWith(WhatsappPhoneNumberIdentifier)) {\r\n newChatId = metadata.id + WhatsappPhoneNumberIdentifier;\r\n } else {\r\n newChatId = metadata.id;\r\n }\r\n }\r\n //@ts-expect-error just let this private access to exists.. hehehehehe\r\n this.ChatId = newChatId;\r\n }\r\n //@ts-expect-error just a little fix... jejeje\r\n this._chatContextMock[\"FixedChatId\"] = this.ChatId;\r\n this._receiverMock.SetGroupMetadataMock({ ...metadata, id: this.ChatId });\r\n //With mocksocket, do not modify it, its always group\r\n this._socketMock.SetGroupMetadataMock(metadata);\r\n }\r\n\r\n /**\r\n * Resets the entire mocking environment back to its initial state.\r\n * This clears:\r\n * - Receiver mock state\r\n * - Sugar sender mock state\r\n * - Socket mock state\r\n * - Chat context mock state\r\n *\r\n * Use this before or after each test to ensure isolation between cases.\r\n */\r\n @autobind\r\n public ClearMocks(): void {\r\n this._receiverMock.ClearMocks();\r\n this._sugarSenderMock.ClearMocks();\r\n this._socketMock.ClearMock();\r\n this._chatContextMock.ClearMocks();\r\n }\r\n\r\n /**\r\n * Configure the buffer that will be returned in place of a real\r\n * downloaded multimedia message when using \"ctx.WaitMultimedia(...)\".\r\n *\r\n * @param anyBuffer - The buffer to return on next `WaitMultimedia` calls.\r\n */\r\n @autobind\r\n public SetWaitMsgBufferToReturnMock(anyBuffer: Buffer) {\r\n this._chatContextMock.EnqueueMediaBufferToReturn(anyBuffer);\r\n }\r\n}\r\n\r\n//Constructor:\r\n/**\r\n * If SenderType.Group case\r\n * If SenderType.Individual case\r\n *\r\n * If provided ChatId:string\r\n * If provided ParticipantId_LID: string\r\n * If provided ParticipantId_PN: string\r\n */\r\n\r\nfunction Constructor_ResolveChatID(chatId?: string, senderType?: SenderType): { chatIdResolved: string; updatedSenderType?: SenderType } {\r\n //Default case if nothing provide, returns by default individual chat id (private chat);\r\n const defaultIndividualChatId = \"fakeUserChatPrivate\" + WhatsappGroupIdentifier;\r\n\r\n if (senderType) {\r\n if (senderType === SenderType.Group) {\r\n if (!chatId) {\r\n return { chatIdResolved: \"fakeChatId\" + WhatsappGroupIdentifier };\r\n }\r\n if (chatId.endsWith(WhatsappGroupIdentifier)) {\r\n return { chatIdResolved: chatId }; //Its correct already!\r\n } else {\r\n return { chatIdResolved: chatId + WhatsappGroupIdentifier }; //Let's fix it\r\n }\r\n }\r\n\r\n if (senderType === SenderType.Individual) {\r\n if (!chatId) {\r\n return { chatIdResolved: defaultIndividualChatId };\r\n }\r\n if (chatId.endsWith(WhatsappPhoneNumberIdentifier)) {\r\n return { chatIdResolved: chatId };\r\n } else {\r\n return { chatIdResolved: chatId + WhatsappPhoneNumberIdentifier };\r\n }\r\n }\r\n } else if (chatId) {\r\n if (chatId.endsWith(WhatsappGroupIdentifier)) {\r\n return { chatIdResolved: chatId, updatedSenderType: SenderType.Group }; //Its correct already!\r\n } else if (chatId.endsWith(WhatsappPhoneNumberIdentifier)) {\r\n return { chatIdResolved: chatId + WhatsappPhoneNumberIdentifier, updatedSenderType: SenderType.Individual }; //Let's fix it\r\n }\r\n }\r\n\r\n //If, for some reason, it reaches here, return default case again.\r\n return { chatIdResolved: defaultIndividualChatId };\r\n}\r\n\r\nfunction Constructor_ResolveParticipantIds(\r\n participantId_LID?: string | null,\r\n participantId_PN?: string | null,\r\n senderType?: SenderType\r\n): { LID: string | null; PN: string | null; senderTypeUpdated: SenderType | null } {\r\n const defaultLID: string = \"fakeParticipnatID\" + WhatsappLIDIdentifier;\r\n const defaultPN: string = \"fakeParticipantID\" + WhatsappPhoneNumberIdentifier;\r\n\r\n if (!participantId_LID && !participantId_PN && senderType === SenderType.Individual) {\r\n return { LID: null, PN: null, senderTypeUpdated: null };\r\n }\r\n\r\n let LID_ToReturn: string | null; // participant_LID => Could be (string | undefined | null)\r\n if (typeof participantId_LID === \"string\") {\r\n if (participantId_LID.endsWith(WhatsappLIDIdentifier)) {\r\n LID_ToReturn = participantId_LID; //Its ok, nothing to fix\r\n } else {\r\n LID_ToReturn = participantId_LID + WhatsappLIDIdentifier; //Let's fix it\r\n }\r\n } else if (participantId_LID === null) {\r\n LID_ToReturn = null;\r\n } else {\r\n //Is undefined\r\n LID_ToReturn = defaultLID;\r\n }\r\n\r\n let PN_ToReturn: string | null; // participant_PN => Could be (string | undefined | null)\r\n if (typeof participantId_PN === \"string\") {\r\n if (participantId_PN.endsWith(WhatsappPhoneNumberIdentifier)) {\r\n PN_ToReturn = participantId_PN; //Its ok, nothing to fix\r\n } else {\r\n PN_ToReturn = participantId_PN + WhatsappPhoneNumberIdentifier; //Let's fix it\r\n }\r\n } else if (participantId_PN === null) {\r\n PN_ToReturn = null;\r\n } else {\r\n //Is undefined then\r\n PN_ToReturn = defaultPN;\r\n }\r\n\r\n return { LID: LID_ToReturn, PN: PN_ToReturn, senderTypeUpdated: SenderType.Group };\r\n}\r\n\r\n// \"fakeChatIdGroup\" + WhatsappGroupIdentifier;\r\n// \"fakeUserChatPrivate\" + WhatsappIndividualIdentifier;\r\n","import Whatsbotcord from \"./core/bot/bot.js\";\r\nimport {\r\n MsgHelper_FullMsg_GetMsgType,\r\n MsgHelper_FullMsg_GetQuotedMsg,\r\n MsgHelper_FullMsg_GetQuotedMsgText,\r\n MsgHelper_FullMsg_GetSenderType,\r\n MsgHelper_FullMsg_GetText,\r\n MsgHelper_ProtoMsg_GetMsgType,\r\n MsgHelper_QuotedMsg_GetText,\r\n} from \"./helpers/Msg.helper.js\";\r\nimport {\r\n WhatsappHelper_ExtractFromWhatsappID,\r\n WhatsappHelper_ExtractWhatsappInfoFromMention,\r\n WhatsappHelper_ExtractWhatsappInfoInfoFromSenderRawMsg,\r\n WhatsappHelper_isFullWhatsappIdUser,\r\n WhatsappHelper_isLIDIdentifier,\r\n WhatsappHelper_isMentionId,\r\n} from \"./helpers/Whatsapp.helper.js\";\r\n\r\n// === Types deps exporting ===\r\nimport type { WhatsbotcordMiddlewareFunct, WhatsbotcordMiddlewareFunct_OnFoundCommand } from \"./core/bot/bot.js\";\r\nimport type { IChatContextConfig } from \"./core/bot/internals/ChatContext.js\";\r\nimport type { CommandEntry } from \"./core/bot/internals/CommandsSearcher.js\";\r\nimport type { CommandArgs } from \"./core/bot/internals/CommandsSearcher.types.js\";\r\nimport type { IChatContext } from \"./core/bot/internals/IChatContext.js\";\r\nimport type { AdditionalAPI, ICommand } from \"./core/bot/internals/ICommand.js\";\r\nimport type {\r\n OfficialPlugin_OneCommandPerUserAtATime_Config,\r\n OfficialPlugin_OneCommandPerUserAtATime_ContextInfo,\r\n} from \"./core/official_plugins/OneCommandPerUser_Plugin.js\";\r\nimport type { IWhatsSocket_Submodule_Receiver } from \"./core/whats_socket/internals/IWhatsSocket.receiver.js\";\r\nimport type { IWhatsSocket_Submodule_SugarSender } from \"./core/whats_socket/internals/IWhatsSocket.sugarsender.js\";\r\nimport type { GroupMetadataInfo, WhatsSocketReceiverError } from \"./core/whats_socket/internals/WhatsSocket.receiver.js\";\r\nimport type { IMsgServiceSocketMinimum, IWhatsSocket, IWhatsSocket_EventsOnly_Module } from \"./core/whats_socket/IWhatsSocket.js\";\r\nimport type { WhatsappMessage } from \"./core/whats_socket/types.js\";\r\nimport type { WhatsappIDInfo } from \"./helpers/Whatsapp.helper.js\";\r\nimport type {\r\n MockEnqueueParamsDocument,\r\n MockEnqueueParamsLocation,\r\n MockEnqueueParamsMinimal,\r\n MockEnqueueParamsMultimedia,\r\n MockEnqueueParamsMultimediaMinimal,\r\n MockingChatParams,\r\n} from \"./mocking_suite/ChatMock.js\";\r\nexport type {\r\n AdditionalAPI,\r\n IChatContextConfig as ChatContextConfig,\r\n CommandArgs,\r\n CommandEntry,\r\n GroupMetadataInfo,\r\n IChatContext,\r\n ICommand,\r\n IMsgServiceSocketMinimum,\r\n IWhatsSocket,\r\n IWhatsSocket_EventsOnly_Module,\r\n IWhatsSocket_Submodule_Receiver,\r\n IWhatsSocket_Submodule_SugarSender,\r\n WhatsbotcordMiddlewareFunct_OnFoundCommand as MiddlewareFunct_OnFoundCommand,\r\n MockEnqueueParamsDocument,\r\n MockEnqueueParamsLocation,\r\n MockEnqueueParamsMinimal,\r\n MockEnqueueParamsMultimedia,\r\n MockEnqueueParamsMultimediaMinimal,\r\n MockingChatParams,\r\n OfficialPlugin_OneCommandPerUserAtATime_Config,\r\n OfficialPlugin_OneCommandPerUserAtATime_ContextInfo,\r\n WhatsappIDInfo,\r\n WhatsappMessage,\r\n WhatsbotcordMiddlewareFunct,\r\n WhatsSocketReceiverError,\r\n};\r\n\r\n// == Runtime deps exporting ==\r\nimport Bot from \"./core/bot/bot.js\";\r\nimport { ChatContext } from \"./core/bot/internals/ChatContext.js\";\r\nimport { CommandType } from \"./core/bot/internals/CommandsSearcher.js\";\r\nimport OfficialPlugin_OneCommandPerUserAtATime from \"./core/official_plugins/OneCommandPerUser_Plugin.js\";\r\nimport { WhatsSocketReceiverHelper_isReceiverError, WhatsSocketReceiverMsgError } from \"./core/whats_socket/internals/WhatsSocket.receiver.js\";\r\nimport WhatsSocket from \"./core/whats_socket/WhatsSocket.js\";\r\nimport { Debug_StoreWhatsMsgHistoryInJson } from \"./Debugging.helper.js\";\r\nimport CreateCommand from \"./helpers/CommandForJs.helper.js\";\r\nimport { WhatsappIdType } from \"./helpers/Whatsapp.helper.js\";\r\nimport Delegate from \"./libs/Delegate.js\";\r\nimport ChatMock from \"./mocking_suite/ChatMock.js\";\r\nimport { MsgType, SenderType } from \"./Msg.types.js\";\r\nimport { WhatsappGroupIdentifier, WhatsappLIDIdentifier, WhatsappPhoneNumberIdentifier } from \"./Whatsapp.types.js\";\r\nexport {\r\n ChatContext,\r\n ChatMock,\r\n CommandType,\r\n CreateCommand,\r\n Delegate,\r\n MsgType,\r\n OfficialPlugin_OneCommandPerUserAtATime,\r\n SenderType,\r\n WhatsappIdType,\r\n Bot as Whatsbotcord,\r\n WhatsSocket,\r\n WhatsSocketReceiverMsgError,\r\n};\r\n\r\n// === Helpers ===\r\n\r\n/**\r\n * # Whatsapp Identifiers Postfixes\r\n *\r\n * Object containing all common patterns identifiers from WhatsApp API and\r\n * WhatsApp messages. Keep this for reference in your logic.\r\n *\r\n * @example\r\n * ```typescript\r\n * const isGroup = id.endsWith(Helpers.Whatsapp.IdentifiersPostfixes.Group_Suffix_ID);\r\n * ```\r\n * @deprecated Made for compatibility with versions prior 1.0.0. Import {Helpers} from \"whatsbotcord\", and use 'Helpers.Whatsapp.IdentifiersPostfixes' instead\r\n */\r\nexport const WhatsappIdentifiers = {\r\n /**\r\n * Identifier for group chats. Example: \"@g.us\"\r\n *\r\n * @note Just for reference\r\n */\r\n Group_Suffix_ID: WhatsappGroupIdentifier,\r\n /**\r\n * Identifer for local IDs. Example: \"@lid\"\r\n *\r\n * @note Just for reference\r\n */\r\n LID_Suffix_ID: WhatsappLIDIdentifier,\r\n /**\r\n * Identifier for individual user chats. Example: \"@s.whatsapp.net\"\r\n *\r\n * @note Just for reference\r\n */\r\n PhoneNumber_Suffix_ID: WhatsappPhoneNumberIdentifier,\r\n};\r\n\r\n/**\r\n * # WhatsApp Identifiers Helpers\r\n * Collection of helper functions for working with WhatsApp IDs and mentions.\r\n * Provides utilities to extract sender information, identify mentions,\r\n * and verify WhatsApp ID formats.\r\n *\r\n * @deprecated This exists only for compatibility with versions prior to 1.0.0.\r\n * Instead: import { Helpers } from \"whatsbotcord\" and use 'Helpers.Whatsapp'.\r\n */\r\nexport const WhatsappHelpers = {\r\n /**\r\n * ### Get Info From Sender Message\r\n * Extracts detailed ID information from a raw Baileys `WAMessage`.\r\n * It automatically determines if the ID is a LID or a standard PN.\r\n * @example\r\n * ```typescript\r\n * const info = WhatsappHelpers.GetWhatsInfoFromSenderMsg(rawMsg);\r\n * console.log(info.rawId); // \"1234567890@s.whatsapp.net\" or \"123456789012345@lid\"\r\n * ```\r\n */\r\n GetWhatsInfoFromSenderMsg: WhatsappHelper_ExtractWhatsappInfoInfoFromSenderRawMsg,\r\n\r\n /**\r\n * ### Get Info From WhatsApp ID\r\n * Parses a raw string ID (including the @ suffix) into a structured object.\r\n * @example\r\n * ```typescript\r\n * const info = WhatsappHelpers.GetWhatsInfoFromWhatsappID(\"5215551234567@s.whatsapp.net\");\r\n * console.log(info.asMentionFormatted); // \"@5215551234567\"\r\n * ```\r\n */\r\n GetWhatsInfoFromWhatsappID: WhatsappHelper_ExtractFromWhatsappID,\r\n\r\n /**\r\n * ### Get Info From Mention String\r\n * Converts a user-facing mention (starting with @) into a system-ready ID info object.\r\n * @example\r\n * ```typescript\r\n * const mention = WhatsappHelpers.GetWhatsInfoFromMentionStr(\"@5215551234567\");\r\n * if (mention) console.log(mention.rawId); // \"5215551234567@lid\"\r\n * ```\r\n */\r\n GetWhatsInfoFromMentionStr: WhatsappHelper_ExtractWhatsappInfoFromMention,\r\n\r\n /**\r\n * ### Is LID Identifier\r\n * Returns true if the ID follows the modern Linked Device Identifier format (`@lid`).\r\n * @example\r\n * ```typescript\r\n * const isLid = WhatsappHelpers.IsLIDId(\"123456789012345@lid\"); // true\r\n * ```\r\n */\r\n IsLIDId: WhatsappHelper_isLIDIdentifier,\r\n\r\n /**\r\n * ### Is Mention String\r\n * Checks if a string is a valid WhatsApp mention (starts with the `@` prefix).\r\n * @example\r\n * ```typescript\r\n * const isMention = WhatsappHelpers.IsMentionString(\"@5215558889900\"); // true\r\n * const isNotMention = WhatsappHelpers.IsMentionString(\"5215558889900\"); // false\r\n * ```\r\n */\r\n IsMentionString: WhatsappHelper_isMentionId,\r\n\r\n /**\r\n * ### Is PN ID\r\n * Checks if the ID is a standard Phone Number identifier (`@s.whatsapp.net`).\r\n * @example\r\n * ```typescript\r\n * const isLegacy = WhatsappHelpers.IsPNId(\"5211234567890@s.whatsapp.net\"); // true\r\n * ```\r\n */\r\n IsPNId: WhatsappHelper_isFullWhatsappIdUser,\r\n\r\n /**\r\n * ### Identifiers Postfixes\r\n * Access common WhatsApp ID suffixes (e.g., `@g.us`, `@s.whatsapp.net`, `@lid`).\r\n * @example\r\n * ```typescript\r\n * const isGroup = msg.key.remoteJid?.endsWith(WhatsappHelpers.IdentifiersPostfixes.Group_Suffix_ID);\r\n * ```\r\n */\r\n IdentifiersPostfixes: WhatsappIdentifiers,\r\n};\r\n\r\nexport const Helpers = {\r\n /**\r\n * # External Message Helpers\r\n *\r\n * Collection of helper functions for working with WhatsApp messages.\r\n * Provides convenience methods to extract text or determine message types\r\n * from raw WhatsappMessages.\r\n *\r\n * @example\r\n * ```typescript\r\n * const text = Helpers.Msg.FullMsg_GetText(rawMsg);\r\n * ```\r\n */\r\n Msg: {\r\n FullMsg_GetQuotedMsgText: MsgHelper_FullMsg_GetQuotedMsgText,\r\n FullMsg_GetMsgType: MsgHelper_FullMsg_GetMsgType,\r\n FullMsg_GetText: MsgHelper_FullMsg_GetText,\r\n FullMsg_GetQuotedMsgObj: MsgHelper_FullMsg_GetQuotedMsg,\r\n FullMsg_GetSenderType: MsgHelper_FullMsg_GetSenderType,\r\n QuotedMsg_GetText: MsgHelper_QuotedMsg_GetText,\r\n AnyMsg_GetMsgType: MsgHelper_ProtoMsg_GetMsgType,\r\n },\r\n /**\r\n * # WhatsApp Identifiers Helpers\r\n\r\n * Collection of helper functions for working with WhatsApp IDs and mentions.\r\n * Provides utilities to extract sender information, identify mentions,\r\n * and verify WhatsApp ID formats.\r\n\r\n * @example\r\n * ```typescript\r\n * const isPN = Helpers.Whatsapp.IsPNId(\"123@s.whatsapp.net\");\r\n * ```\r\n */\r\n Whatsapp: WhatsappHelpers,\r\n\r\n /**\r\n * # Debugging Utilities\r\n *\r\n * Useful collection of functions for debugging WhatsApp behavior locally.\r\n *\r\n * @example\r\n * ```typescript\r\n * Helpers.Debugging.StoreMsgInHistoryJson(rawMsg);\r\n * ```\r\n */\r\n Debugging: {\r\n StoreMsgInHistoryJson: Debug_StoreWhatsMsgHistoryInJson,\r\n },\r\n\r\n ChatContext_IsWaitError: WhatsSocketReceiverHelper_isReceiverError,\r\n};\r\n\r\n// === Main Default Export ===\r\nexport default Whatsbotcord;\r\n"],"mappings":"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"}