export interface InlineKeyboardButton { text: string; callback_data?: string; callbackData?: string; url?: string; web_app?: { url?: string }; webAppUrl?: string; } export interface InlineKeyboardMarkup { inline_keyboard?: InlineKeyboardButton[][]; reply_markup?: { inline_keyboard?: InlineKeyboardButton[][]; }; kind?: 'inline'; rows?: InlineKeyboardButton[][]; } function normalizeButton(button: InlineKeyboardButton): InlineKeyboardButton { return { text: button.text, callback_data: button.callback_data ?? button.callbackData, url: button.url, web_app: button.web_app ?? (button.webAppUrl ? { url: button.webAppUrl } : undefined) }; } export function parseInlineKeyboardMarkup(source: unknown): InlineKeyboardButton[][] { if (!source) return []; let raw: InlineKeyboardMarkup | null = null; if (typeof source === 'string') { try { raw = JSON.parse(source) as InlineKeyboardMarkup; } catch { return []; } } else if (typeof source === 'object') { raw = source as InlineKeyboardMarkup; } if (!raw) return []; const nested = raw.reply_markup?.inline_keyboard; if (Array.isArray(nested) && nested.length) { return nested .filter((row) => Array.isArray(row)) .map((row) => row.map(normalizeButton).filter((button) => Boolean(button.text?.trim()))); } if (Array.isArray(raw.inline_keyboard) && raw.inline_keyboard.length) { return raw.inline_keyboard .filter((row) => Array.isArray(row)) .map((row) => row.map(normalizeButton).filter((button) => Boolean(button.text?.trim()))); } if (raw.kind === 'inline' && Array.isArray(raw.rows)) { return raw.rows .filter((row) => Array.isArray(row)) .map((row) => row.map(normalizeButton).filter((button) => Boolean(button.text?.trim()))); } return []; } export function serializeInlineKeyboardMarkup(rows: InlineKeyboardButton[][]): string | null { if (!rows.length) return null; return JSON.stringify({ inline_keyboard: rows.map((row) => row.map(normalizeButton)) }); } export function extractMessageReplyMarkup(message: { replyMarkupJson?: string | null; replyMarkup?: unknown; telegramReplyMarkup?: unknown; reply_markup?: unknown; }): InlineKeyboardButton[][] { if (message.replyMarkupJson) { const parsed = parseInlineKeyboardMarkup(message.replyMarkupJson); if (parsed.length) return parsed; } if (message.telegramReplyMarkup) { const parsed = parseInlineKeyboardMarkup(message.telegramReplyMarkup); if (parsed.length) return parsed; } if (message.replyMarkup) { const parsed = parseInlineKeyboardMarkup(message.replyMarkup); if (parsed.length) return parsed; } if (message.reply_markup) { const parsed = parseInlineKeyboardMarkup(message.reply_markup); if (parsed.length) return parsed; } return []; }