(update: unknown)
| 105 | * Only `type === "emoji"` entries are considered; custom_emoji are ignored. |
| 106 | */ |
| 107 | export function decodeReaction(update: unknown): IncomingReaction[] { |
| 108 | const mr = (update as { message_reaction?: TgMessageReaction }) |
| 109 | .message_reaction; |
| 110 | if (!mr?.chat?.id || mr.message_id === undefined) return []; |
| 111 | const oldSet = emojiSet(mr.old_reaction); |
| 112 | const newSet = emojiSet(mr.new_reaction); |
| 113 | const chatId = mr.chat.id; |
| 114 | const message = { |
| 115 | chat: mr.chat as { id: number | string; type: string; is_forum?: boolean }, |
| 116 | message_id: mr.message_id, |
| 117 | message_thread_id: mr.message_thread_id, |
| 118 | }; |
| 119 | const ck = deriveConversationKey(message, mr.user?.id); |
| 120 | const conversationKey = conversationKeyOf(ck); |
| 121 | const replyTarget: ReplyTarget = { |
| 122 | chatId, |
| 123 | messageThreadId: mr.chat.is_forum ? mr.message_thread_id : undefined, |
| 124 | conversationKey, |
| 125 | }; |
| 126 | const user = mr.user |
| 127 | ? { |
| 128 | id: String(mr.user.id), |
| 129 | name: mr.user.first_name, |
| 130 | handle: mr.user.username, |
| 131 | } |
| 132 | : undefined; |
| 133 | const base = { |
| 134 | user, |
| 135 | conversationKey, |
| 136 | replyTarget, |
| 137 | messageId: String(mr.message_id), |
| 138 | // Update-capable ref (chatId + numeric messageId) so an onReaction handler |
| 139 | // can edit the reacted message in place via thread.update. |
| 140 | messageRef: { id: String(mr.message_id), chatId, messageId: mr.message_id }, |
| 141 | raw: update, |
| 142 | }; |
| 143 | const out: IncomingReaction[] = []; |
| 144 | for (const e of newSet) |
| 145 | if (!oldSet.has(e)) out.push({ ...base, rawEmoji: e, added: true }); |
| 146 | for (const e of oldSet) |
| 147 | if (!newSet.has(e)) out.push({ ...base, rawEmoji: e, added: false }); |
| 148 | return out; |
| 149 | } |
| 150 | |
| 151 | /** |
| 152 | * Decode a Telegram callback_query update (grammY or raw Bot API) into a |
no test coverage detected
searching dependent graphs…