import { extractCard } from '@chat-adapter/shared'; import { BaseFormatConverter, Root, AdapterPostableMessage, Logger, Adapter, ChatInstance, UserInfo, WebhookOptions, RawMessage, EmojiValue, FetchOptions, FetchResult, Message, ThreadInfo, ChannelInfo, FormattedContent, Attachment } from 'chat'; /** * Telegram MarkdownV2 format conversion. * * Renders markdown AST as Telegram MarkdownV2, which requires escaping * special characters outside of entities. This replaces the previous * approach of emitting standard markdown with legacy parse_mode "Markdown", * which was incompatible (standard markdown uses **bold** while Telegram * legacy uses *bold*) and caused "can't parse entities" errors. * * @see https://core.telegram.org/bots/api#markdownv2-style */ /** * How the adapter intends a message to be rendered. * * - `"MarkdownV2"` — the body was produced by the MarkdownV2 renderer and * must be parsed by Telegram with `parse_mode: "MarkdownV2"`. * - `"plain"` — the body ships verbatim with no markdown parsing (the Bot * API receives no `parse_mode` field). * * Internal type; the Bot API wire value is obtained via `toBotApiParseMode`. */ type TelegramParseMode = "MarkdownV2" | "plain"; /** * Escape text for use in normal MarkdownV2 context (outside entities). */ declare function escapeMarkdownV2(text: string): string; declare class TelegramFormatConverter extends BaseFormatConverter { fromAst(ast: Root): string; toAst(text: string): Root; renderPostable(message: AdapterPostableMessage): string; } /** * Telegram adapter types. */ /** * Telegram adapter configuration. */ interface TelegramAdapterConfig { /** Optional custom API base URL (defaults to https://api.telegram.org). Defaults to TELEGRAM_API_BASE_URL env var. */ apiBaseUrl?: string; /** Override the Telegram API base URL. Alias for apiBaseUrl — apiUrl takes precedence if both are set. Defaults to TELEGRAM_API_BASE_URL env var. */ apiUrl?: string; /** Telegram bot token from BotFather. Defaults to TELEGRAM_BOT_TOKEN env var. */ botToken?: string; /** Logger instance for error reporting. Defaults to ConsoleLogger. */ logger?: Logger; /** Optional long-polling configuration for getUpdates flow. */ longPolling?: TelegramLongPollingConfig; /** * Adapter runtime mode: * - auto: choose webhook vs polling based on webhook registration/runtime (default) * - webhook: webhook-only mode * - polling: polling-only mode */ mode?: TelegramAdapterMode; /** Optional webhook secret token checked against x-telegram-bot-api-secret-token. Defaults to TELEGRAM_WEBHOOK_SECRET_TOKEN env var. */ secretToken?: string; /** Override bot username (optional). Defaults to TELEGRAM_BOT_USERNAME env var. */ userName?: string; } type TelegramAdapterMode = "auto" | "webhook" | "polling"; /** * Telegram long-polling configuration. * @see https://core.telegram.org/bots/api#getupdates */ interface TelegramLongPollingConfig { /** Allowed update types passed to getUpdates. */ allowedUpdates?: string[]; /** * Delete webhook before polling starts. * Telegram requires this when switching from webhook mode to getUpdates. * @default true */ deleteWebhook?: boolean; /** Passed to deleteWebhook as drop_pending_updates when deleting webhook. */ dropPendingUpdates?: boolean; /** * Maximum number of updates per getUpdates call. * Telegram range: 1-100. * @default 100 */ limit?: number; /** Delay before retrying polling after errors. @default 1000 */ retryDelayMs?: number; /** Long-poll timeout in seconds for getUpdates. @default 30 */ timeout?: number; } /** * Telegram thread ID components. */ interface TelegramThreadId { /** Telegram chat ID. */ chatId: string; /** Optional forum topic ID for supergroup topics. */ messageThreadId?: number; } /** * Telegram user object. * @see https://core.telegram.org/bots/api#user */ interface TelegramUser { first_name: string; id: number; is_bot: boolean; language_code?: string; last_name?: string; username?: string; } /** * Telegram chat object. * @see https://core.telegram.org/bots/api#chat */ interface TelegramChat { first_name?: string; id: number; last_name?: string; title?: string; type: "private" | "group" | "supergroup" | "channel"; username?: string; } /** * Telegram message entity (mentions, links, commands, etc). * @see https://core.telegram.org/bots/api#messageentity */ interface TelegramMessageEntity { language?: string; length: number; offset: number; type: string; url?: string; user?: TelegramUser; } /** * Telegram file metadata. */ interface TelegramFile { file_id: string; file_path?: string; file_size?: number; file_unique_id?: string; } /** * Telegram photo size object. */ interface TelegramPhotoSize extends TelegramFile { height: number; width: number; } /** * Telegram message. * @see https://core.telegram.org/bots/api#message */ interface TelegramMessage { audio?: TelegramFile & { duration?: number; performer?: string; title?: string; mime_type?: string; file_name?: string; }; caption?: string; caption_entities?: TelegramMessageEntity[]; chat: TelegramChat; date: number; document?: TelegramFile & { file_name?: string; mime_type?: string; }; edit_date?: number; entities?: TelegramMessageEntity[]; from?: TelegramUser; message_id: number; message_thread_id?: number; photo?: TelegramPhotoSize[]; sender_chat?: TelegramChat; sticker?: TelegramFile & { emoji?: string; }; text?: string; video?: TelegramFile & { width?: number; height?: number; mime_type?: string; file_name?: string; }; video_note?: TelegramFile & { length?: number; duration?: number; }; voice?: TelegramFile & { duration?: number; mime_type?: string; }; } /** * Telegram inline keyboard button. * @see https://core.telegram.org/bots/api#inlinekeyboardbutton */ interface TelegramInlineKeyboardButton { callback_data?: string; text: string; url?: string; } /** * Telegram inline keyboard markup. * @see https://core.telegram.org/bots/api#inlinekeyboardmarkup */ interface TelegramInlineKeyboardMarkup { inline_keyboard: TelegramInlineKeyboardButton[][]; } /** * Telegram callback query (inline keyboard button click). * @see https://core.telegram.org/bots/api#callbackquery */ interface TelegramCallbackQuery { chat_instance: string; data?: string; from: TelegramUser; id: string; inline_message_id?: string; message?: TelegramMessage; } /** * Telegram reaction types. */ type TelegramReactionType = { emoji: string; type: "emoji"; } | { custom_emoji_id: string; type: "custom_emoji"; }; /** * Telegram message reaction update. * @see https://core.telegram.org/bots/api#messagereactionupdated */ interface TelegramMessageReactionUpdated { actor_chat?: TelegramChat; chat: TelegramChat; date: number; message_id: number; message_thread_id?: number; new_reaction: TelegramReactionType[]; old_reaction: TelegramReactionType[]; user?: TelegramUser; } /** * Telegram webhook update payload. * @see https://core.telegram.org/bots/api#update */ interface TelegramUpdate { callback_query?: TelegramCallbackQuery; channel_post?: TelegramMessage; edited_channel_post?: TelegramMessage; edited_message?: TelegramMessage; message?: TelegramMessage; message_reaction?: TelegramMessageReactionUpdated; update_id: number; } /** * Telegram API response envelope. */ interface TelegramApiResponse { description?: string; error_code?: number; ok: boolean; parameters?: { retry_after?: number; }; result?: TResult; } /** * Telegram webhook info response. * @see https://core.telegram.org/bots/api#getwebhookinfo */ interface TelegramWebhookInfo { allowed_updates?: string[]; has_custom_certificate: boolean; ip_address?: string; last_error_date?: number; last_error_message?: string; max_connections?: number; pending_update_count: number; url: string; } type TelegramRawMessage = TelegramMessage; interface TelegramMessageAuthor { fullName: string; isBot: boolean | "unknown"; isMe: boolean; userId: string; userName: string; } interface ResolvedTelegramLongPollingConfig { allowedUpdates?: string[]; deleteWebhook: boolean; dropPendingUpdates: boolean; limit: number; retryDelayMs: number; timeout: number; } type TelegramRuntimeMode = "webhook" | "polling"; /** * Convert Telegram message entities (inbound) to standard markdown. * * Telegram delivers formatting as separate entity objects alongside plain text. * This function reconstructs **standard** markdown (`**bold**`, `~~strike~~`, * etc.) so the result can be fed into the SDK's `parseMarkdown` — which is * the canonical AST producer. The outbound direction (AST → MarkdownV2) is * handled separately by `TelegramFormatConverter.fromAst`. * * Entities use UTF-16 offsets, which match JavaScript's native string indexing. */ declare function applyTelegramEntities(text: string, entities: TelegramMessageEntity[]): string; declare class TelegramAdapter implements Adapter { readonly name = "telegram"; readonly lockScope: "channel"; readonly persistThreadHistory = true; protected readonly botToken: string; protected readonly apiBaseUrl: string; protected readonly secretToken?: string; private warnedNoVerification; protected readonly logger: Logger; protected readonly formatConverter: TelegramFormatConverter; private readonly messageCache; protected chat: ChatInstance | null; protected _botUserId?: string; protected _userName: string; protected readonly hasExplicitUserName: boolean; protected readonly mode: TelegramAdapterMode; protected readonly longPolling?: TelegramLongPollingConfig; private _runtimeMode; private pollingAbortController; private pollingTask; private pollingActive; get botUserId(): string | undefined; get userName(): string; get isPolling(): boolean; get runtimeMode(): TelegramRuntimeMode; constructor(config?: TelegramAdapterConfig); initialize(chat: ChatInstance): Promise; getUser(userId: string): Promise; handleWebhook(request: Request, options?: WebhookOptions): Promise; startPolling(config?: TelegramLongPollingConfig): Promise; stopPolling(): Promise; resetWebhook(dropPendingUpdates?: boolean): Promise; protected resolveRuntimeMode(): Promise; protected fetchWebhookInfo(): Promise; protected isLikelyServerlessRuntime(): boolean; protected processUpdate(update: TelegramUpdate, options?: WebhookOptions): void; protected handleIncomingMessageUpdate(telegramMessage: TelegramMessage, options?: WebhookOptions): void; protected handleCallbackQuery(callbackQuery: TelegramCallbackQuery, options?: WebhookOptions): void; protected handleMessageReactionUpdate(reactionUpdate: TelegramMessageReactionUpdated, options?: WebhookOptions): void; postMessage(threadId: string, message: AdapterPostableMessage): Promise>; postChannelMessage(channelId: string, message: AdapterPostableMessage): Promise>; editMessage(threadId: string, messageId: string, message: AdapterPostableMessage): Promise>; deleteMessage(threadId: string, messageId: string): Promise; addReaction(threadId: string, messageId: string, emoji: EmojiValue | string): Promise; removeReaction(threadId: string, messageId: string, _emoji: EmojiValue | string): Promise; startTyping(threadId: string): Promise; fetchMessages(threadId: string, options?: FetchOptions): Promise>; fetchChannelMessages(channelId: string, options?: FetchOptions): Promise>; fetchMessage(_threadId: string, messageId: string): Promise | null>; fetchThread(threadId: string): Promise; fetchChannelInfo(channelId: string): Promise; channelIdFromThreadId(threadId: string): string; openDM(userId: string): Promise; isDM(threadId: string): boolean; encodeThreadId(platformData: TelegramThreadId): string; decodeThreadId(threadId: string): TelegramThreadId; parseMessage(raw: TelegramRawMessage): Message; renderFormatted(content: FormattedContent): string; protected parseTelegramMessage(raw: TelegramMessage, threadId: string): Message; protected extractAttachments(raw: TelegramMessage): Attachment[]; protected createAttachment(type: Attachment["type"], fileId: string, metadata?: { size?: number; width?: number; height?: number; name?: string; mimeType?: string; }): Attachment; rehydrateAttachment(attachment: Attachment): Attachment; protected downloadFile(fileId: string): Promise; protected sendDocument(thread: TelegramThreadId, file: { filename: string; data: Buffer | Blob | ArrayBuffer; mimeType?: string; }, text: string, replyMarkup?: TelegramInlineKeyboardMarkup, parseMode?: TelegramParseMode): Promise; protected sendAttachment(thread: TelegramThreadId, attachment: Attachment, text: string, replyMarkup?: TelegramInlineKeyboardMarkup, parseMode?: TelegramParseMode): Promise; protected toTelegramBuffer(data: Buffer | Blob | ArrayBuffer): Promise; protected paginateMessages(messages: Message[], options: FetchOptions): FetchResult; protected cacheMessage(message: Message): void; protected findCachedMessage(messageId: string): Message | undefined; protected deleteCachedMessage(messageId: string): void; protected compareMessages(a: Message, b: Message): number; protected messageSequence(messageId: string): number; protected resolveThreadId(value: string): TelegramThreadId; protected encodeMessageId(chatId: string, messageId: number): string; protected decodeCompositeMessageId(messageId: string, expectedChatId?: string): { chatId: string; messageId: number; compositeId: string; }; protected toAuthor(user: TelegramUser): TelegramMessageAuthor; protected toReactionActorAuthor(chat: TelegramChat): TelegramMessageAuthor; protected chatDisplayName(chat: TelegramChat): string | undefined; protected isBotMentioned(message: TelegramMessage, text: string): boolean; protected entityText(text: string, entity: TelegramMessageEntity): string; protected escapeRegex(input: string): string; protected normalizeUserName(value: unknown): string; protected resolveParseMode(message: AdapterPostableMessage, card: ReturnType): TelegramParseMode; protected toTelegramReaction(emoji: EmojiValue | string): TelegramReactionType; protected reactionKey(reaction: TelegramReactionType): string; protected reactionToEmojiValue(reaction: TelegramReactionType): EmojiValue; protected pollingLoop(config: ResolvedTelegramLongPollingConfig): Promise; protected resolvePollingConfig(override?: TelegramLongPollingConfig): ResolvedTelegramLongPollingConfig; protected clampInteger(value: number | undefined, fallback: number, min: number, max: number): number; protected isAbortError(error: unknown): boolean; protected sleep(delayMs: number): Promise; protected telegramFetch(method: string, payload?: Record | FormData, request?: { signal?: AbortSignal; }): Promise; protected throwTelegramApiError(method: string, status: number, data: TelegramApiResponse): never; } declare function createTelegramAdapter(config?: TelegramAdapterConfig): TelegramAdapter; export { TelegramAdapter, type TelegramAdapterConfig, type TelegramAdapterMode, type TelegramCallbackQuery, type TelegramChat, TelegramFormatConverter, type TelegramLongPollingConfig, type TelegramMessage, type TelegramMessageReactionUpdated, type TelegramRawMessage, type TelegramReactionType, type TelegramThreadId, type TelegramUpdate, type TelegramUser, type TelegramWebhookInfo, applyTelegramEntities, createTelegramAdapter, escapeMarkdownV2 };