// Custom error class for Telegram API errors export class TelegramError extends Error { constructor( message: string, public readonly code?: number, public readonly description?: string ) { super(message); this.name = 'TelegramError'; } } // Telegram API 메시지 전송 export async function sendMessage( token: string, chatId: number, text: string, options?: { parse_mode?: 'HTML' | 'Markdown' | 'MarkdownV2'; reply_to_message_id?: number; disable_notification?: boolean; } ): Promise { try { const response = await fetch( `https://api.telegram.org/bot${token}/sendMessage`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ chat_id: chatId, text, parse_mode: options?.parse_mode || 'HTML', reply_to_message_id: options?.reply_to_message_id, disable_notification: options?.disable_notification, }), } ); if (!response.ok) { let description = ''; try { const errorData = await response.json() as { description?: string }; description = errorData.description || ''; } catch { // JSON 파싱 실패 시 무시 } throw new TelegramError( `Failed to send message: ${response.status}`, response.status, description ); } } catch (error) { if (error instanceof TelegramError) { throw error; } throw new TelegramError( 'Network error while sending message', undefined, error instanceof Error ? error.message : String(error) ); } } // Webhook 설정 (Secret Token 포함) export async function setWebhook( token: string, webhookUrl: string, secretToken: string ): Promise<{ ok: boolean; description?: string }> { const response = await fetch( `https://api.telegram.org/bot${token}/setWebhook`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url: webhookUrl, secret_token: secretToken, allowed_updates: ['message', 'callback_query'], drop_pending_updates: true, }), } ); return response.json(); } // Webhook 정보 조회 export async function getWebhookInfo( token: string ): Promise { const response = await fetch( `https://api.telegram.org/bot${token}/getWebhookInfo` ); return response.json(); } // Webhook 삭제 export async function deleteWebhook( token: string ): Promise<{ ok: boolean }> { const response = await fetch( `https://api.telegram.org/bot${token}/deleteWebhook`, { method: 'POST' } ); return response.json(); } // 인라인 키보드 타입 export interface InlineKeyboardButton { text: string; url?: string; callback_data?: string; web_app?: { url: string }; } // 인라인 키보드와 함께 메시지 전송 export async function sendMessageWithKeyboard( token: string, chatId: number, text: string, keyboard: InlineKeyboardButton[][], options?: { parse_mode?: 'HTML' | 'Markdown' | 'MarkdownV2'; } ): Promise { try { const response = await fetch( `https://api.telegram.org/bot${token}/sendMessage`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ chat_id: chatId, text, parse_mode: options?.parse_mode || 'HTML', reply_markup: { inline_keyboard: keyboard, }, }), } ); if (!response.ok) { let description = ''; try { const errorData = await response.json() as { description?: string }; description = errorData.description || ''; } catch { // JSON 파싱 실패 시 무시 } throw new TelegramError( `Failed to send message with keyboard: ${response.status}`, response.status, description ); } } catch (error) { if (error instanceof TelegramError) { throw error; } throw new TelegramError( 'Network error while sending message with keyboard', undefined, error instanceof Error ? error.message : String(error) ); } } // 타이핑 액션 전송 export async function sendChatAction( token: string, chatId: number, action: 'typing' | 'upload_photo' | 'upload_document' = 'typing' ): Promise { try { const response = await fetch( `https://api.telegram.org/bot${token}/sendChatAction`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ chat_id: chatId, action, }), } ); if (!response.ok) { let description = ''; try { const errorData = await response.json() as { description?: string }; description = errorData.description || ''; } catch { // JSON 파싱 실패 시 무시 } throw new TelegramError( `Failed to send chat action: ${response.status}`, response.status, description ); } } catch (error) { if (error instanceof TelegramError) { throw error; } throw new TelegramError( 'Network error while sending chat action', undefined, error instanceof Error ? error.message : String(error) ); } } // Callback Query 응답 (버튼 클릭 알림) export async function answerCallbackQuery( token: string, callbackQueryId: string, options?: { text?: string; show_alert?: boolean; } ): Promise { try { const response = await fetch( `https://api.telegram.org/bot${token}/answerCallbackQuery`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ callback_query_id: callbackQueryId, text: options?.text, show_alert: options?.show_alert, }), } ); if (!response.ok) { let description = ''; try { const errorData = await response.json() as { description?: string }; description = errorData.description || ''; } catch { // JSON 파싱 실패 시 무시 } throw new TelegramError( `Failed to answer callback query: ${response.status}`, response.status, description ); } } catch (error) { if (error instanceof TelegramError) { throw error; } throw new TelegramError( 'Network error while answering callback query', undefined, error instanceof Error ? error.message : String(error) ); } } // 메시지 수정 (인라인 키보드 제거/변경용) export async function editMessageText( token: string, chatId: number, messageId: number, text: string, options?: { parse_mode?: 'HTML' | 'Markdown' | 'MarkdownV2'; reply_markup?: { inline_keyboard: InlineKeyboardButton[][] }; } ): Promise { try { const response = await fetch( `https://api.telegram.org/bot${token}/editMessageText`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ chat_id: chatId, message_id: messageId, text, parse_mode: options?.parse_mode || 'HTML', reply_markup: options?.reply_markup, }), } ); if (!response.ok) { let description = ''; try { const errorData = await response.json() as { description?: string }; description = errorData.description || ''; } catch { // JSON 파싱 실패 시 무시 } throw new TelegramError( `Failed to edit message text: ${response.status}`, response.status, description ); } } catch (error) { if (error instanceof TelegramError) { throw error; } throw new TelegramError( 'Network error while editing message text', undefined, error instanceof Error ? error.message : String(error) ); } }