{"version":3,"file":"alternate-message-modifier.mjs","names":[],"sources":["../../src/mixins/alternate-message-modifier.ts"],"sourcesContent":["import type { ClientMixin } from \"./base-mixin\";\nimport type { ChatClient } from \"~/client/client\";\nimport type { PrivmsgMessage } from \"~/message/twitch-types/privmsg\";\nimport { canSpamFast } from \"./ratelimiters/utils\";\nimport { applyReplacements } from \"~/utils/apply-function-replacements\";\n\nexport const invisibleSuffix = \" \\u{34F}\";\n\ninterface LastMessage {\n  content: string;\n  action: boolean;\n}\n\nexport class AlternateMessageModifier implements ClientMixin {\n  private readonly client: ChatClient;\n  private readonly lastMessages: Record<string, LastMessage> = {};\n\n  public constructor(client: ChatClient) {\n    this.client = client;\n  }\n\n  public appendInvisibleCharacter(\n    channelName: string,\n    messageText: string,\n    action: boolean,\n  ): string {\n    const lastMessage: LastMessage | undefined = this.lastMessages[channelName];\n\n    return lastMessage?.content === messageText && lastMessage.action === action\n      ? messageText + invisibleSuffix\n      : messageText;\n  }\n\n  public applyToClient(client: ChatClient): void {\n    type GenericReplacementFunction = (\n      oldFunction: (channelName: string, message: string) => Promise<void>,\n      channelName: string,\n      message: string,\n    ) => Promise<void>;\n\n    const genericReplacement =\n      (action: boolean): GenericReplacementFunction =>\n      async <A extends unknown[]>(\n        oldFunction: (\n          channelName: string,\n          message: string,\n          ...args: A\n        ) => Promise<void>,\n        channelName: string,\n        message: string,\n        ...args: A\n      ): Promise<void> => {\n        const { fastSpam } = canSpamFast(\n          channelName,\n          client.configuration.username,\n          client.userStateTracker,\n        );\n\n        if (fastSpam) {\n          await oldFunction(channelName, message, ...args);\n          return;\n        }\n\n        const newMessage = this.appendInvisibleCharacter(\n          channelName,\n          message,\n          action,\n        );\n        await oldFunction(channelName, newMessage, ...args);\n\n        if (!this.client.joinedChannels.has(channelName)) {\n          // in this case we won't get our own message back via the\n          // onPrivmsg handler, so this will have to do. (Save the sent\n          // message)\n          this.lastMessages[channelName] = {\n            content: newMessage,\n            action,\n          };\n        }\n      };\n\n    applyReplacements(this, client, {\n      say: genericReplacement(false),\n      me: genericReplacement(true),\n    });\n\n    client.on(\"PRIVMSG\", this.onPrivmsgMessage.bind(this));\n  }\n\n  private onPrivmsgMessage(message: PrivmsgMessage): void {\n    // msg must be from us (the logged in user)\n    if (!(message.sender.login === this.client.configuration.username)) {\n      return;\n    }\n\n    this.lastMessages[message.channel.login] = {\n      content: message.content,\n      action: message.isAction,\n    };\n  }\n}\n"],"mappings":";;;AAMA,MAAa,kBAAkB;AAO/B,IAAa,2BAAb,MAA6D;CAC3D;CACA,eAA6D,EAAE;CAE/D,YAAmB,QAAoB;AACrC,OAAK,SAAS;;CAGhB,yBACE,aACA,aACA,QACQ;EACR,MAAM,cAAuC,KAAK,aAAa;AAE/D,SAAO,aAAa,YAAY,eAAe,YAAY,WAAW,SAClE,cAAA,OACA;;CAGN,cAAqB,QAA0B;EAO7C,MAAM,sBACH,WACD,OACE,aAKA,aACA,SACA,GAAG,SACe;GAClB,MAAM,EAAE,aAAa,YACnB,aACA,OAAO,cAAc,UACrB,OAAO,iBACR;AAED,OAAI,UAAU;AACZ,UAAM,YAAY,aAAa,SAAS,GAAG,KAAK;AAChD;;GAGF,MAAM,aAAa,KAAK,yBACtB,aACA,SACA,OACD;AACD,SAAM,YAAY,aAAa,YAAY,GAAG,KAAK;AAEnD,OAAI,CAAC,KAAK,OAAO,eAAe,IAAI,YAAY,CAI9C,MAAK,aAAa,eAAe;IAC/B,SAAS;IACT;IACD;;AAIP,oBAAkB,MAAM,QAAQ;GAC9B,KAAK,mBAAmB,MAAM;GAC9B,IAAI,mBAAmB,KAAK;GAC7B,CAAC;AAEF,SAAO,GAAG,WAAW,KAAK,iBAAiB,KAAK,KAAK,CAAC;;CAGxD,iBAAyB,SAA+B;AAEtD,MAAI,EAAE,QAAQ,OAAO,UAAU,KAAK,OAAO,cAAc,UACvD;AAGF,OAAK,aAAa,QAAQ,QAAQ,SAAS;GACzC,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GACjB"}