(raw: unknown)
| 157 | * - A bare callback query object: `{ id, data, from, message }` |
| 158 | */ |
| 159 | export function decodeInteraction(raw: unknown): InteractionEvent | undefined { |
| 160 | if (!raw || typeof raw !== "object") return undefined; |
| 161 | |
| 162 | const obj = raw as Record<string, unknown>; |
| 163 | |
| 164 | // Unwrap grammY update wrapper if present. |
| 165 | const cq = (obj.callback_query ?? obj) as Record<string, unknown>; |
| 166 | if (!cq || typeof cq !== "object") return undefined; |
| 167 | |
| 168 | // Must have callback data. |
| 169 | if (!cq.data || typeof cq.data !== "string") return undefined; |
| 170 | |
| 171 | const message = cq.message as |
| 172 | | { |
| 173 | message_id: number; |
| 174 | message_thread_id?: number; |
| 175 | chat: { id: number | string; type: string; is_forum?: boolean }; |
| 176 | reply_to_message?: { message_id: number }; |
| 177 | } |
| 178 | | undefined; |
| 179 | |
| 180 | if (!message) return undefined; |
| 181 | |
| 182 | const from = cq.from as |
| 183 | | { id: number; first_name?: string; last_name?: string; username?: string } |
| 184 | | undefined; |
| 185 | |
| 186 | // A callback_query's `message` is the BOT's message, so its `from` is the |
| 187 | // bot. Derive the key from the CLICKING user's id (cq.from) so non-forum |
| 188 | // group keys match the ingress key produced by the listener. |
| 189 | const ck = deriveConversationKey(message, from?.id); |
| 190 | const conversationKey = conversationKeyOf(ck); |
| 191 | |
| 192 | const replyTarget: ReplyTarget = { |
| 193 | chatId: message.chat.id, |
| 194 | // Only attach a forum thread id in forum supergroups. In non-forum chats |
| 195 | // message_thread_id is the reply-thread id and Telegram rejects sends that |
| 196 | // attach it ("message thread not found"). |
| 197 | messageThreadId: message.chat?.is_forum |
| 198 | ? message.message_thread_id |
| 199 | : undefined, |
| 200 | conversationKey, |
| 201 | }; |
| 202 | |
| 203 | const messageRef: TelegramMessageRef = { |
| 204 | id: `${message.chat.id}:${message.message_id}`, |
| 205 | chatId: message.chat.id, |
| 206 | messageId: message.message_id, |
| 207 | }; |
| 208 | |
| 209 | const user = from ? toPlatformUser(from) : undefined; |
| 210 | |
| 211 | return { |
| 212 | id: cq.data as string, |
| 213 | conversationKey, |
| 214 | replyTarget, |
| 215 | messageRef, |
| 216 | user, |
no test coverage detected
searching dependent graphs…