Spaces:
Running
Running
| import type { ChannelOutboundAdapter } from "../types.js"; | |
| import { markdownToTelegramHtmlChunks } from "../../../telegram/format.js"; | |
| import { sendMessageTelegram } from "../../../telegram/send.js"; | |
| function parseReplyToMessageId(replyToId?: string | null) { | |
| if (!replyToId) { | |
| return undefined; | |
| } | |
| const parsed = Number.parseInt(replyToId, 10); | |
| return Number.isFinite(parsed) ? parsed : undefined; | |
| } | |
| function parseThreadId(threadId?: string | number | null) { | |
| if (threadId == null) { | |
| return undefined; | |
| } | |
| if (typeof threadId === "number") { | |
| return Number.isFinite(threadId) ? Math.trunc(threadId) : undefined; | |
| } | |
| const trimmed = threadId.trim(); | |
| if (!trimmed) { | |
| return undefined; | |
| } | |
| const parsed = Number.parseInt(trimmed, 10); | |
| return Number.isFinite(parsed) ? parsed : undefined; | |
| } | |
| export const telegramOutbound: ChannelOutboundAdapter = { | |
| deliveryMode: "direct", | |
| chunker: markdownToTelegramHtmlChunks, | |
| chunkerMode: "markdown", | |
| textChunkLimit: 4000, | |
| sendText: async ({ to, text, accountId, deps, replyToId, threadId }) => { | |
| const send = deps?.sendTelegram ?? sendMessageTelegram; | |
| const replyToMessageId = parseReplyToMessageId(replyToId); | |
| const messageThreadId = parseThreadId(threadId); | |
| const result = await send(to, text, { | |
| verbose: false, | |
| textMode: "html", | |
| messageThreadId, | |
| replyToMessageId, | |
| accountId: accountId ?? undefined, | |
| }); | |
| return { channel: "telegram", ...result }; | |
| }, | |
| sendMedia: async ({ to, text, mediaUrl, accountId, deps, replyToId, threadId }) => { | |
| const send = deps?.sendTelegram ?? sendMessageTelegram; | |
| const replyToMessageId = parseReplyToMessageId(replyToId); | |
| const messageThreadId = parseThreadId(threadId); | |
| const result = await send(to, text, { | |
| verbose: false, | |
| mediaUrl, | |
| textMode: "html", | |
| messageThreadId, | |
| replyToMessageId, | |
| accountId: accountId ?? undefined, | |
| }); | |
| return { channel: "telegram", ...result }; | |
| }, | |
| sendPayload: async ({ to, payload, accountId, deps, replyToId, threadId }) => { | |
| const send = deps?.sendTelegram ?? sendMessageTelegram; | |
| const replyToMessageId = parseReplyToMessageId(replyToId); | |
| const messageThreadId = parseThreadId(threadId); | |
| const telegramData = payload.channelData?.telegram as | |
| | { buttons?: Array<Array<{ text: string; callback_data: string }>>; quoteText?: string } | |
| | undefined; | |
| const quoteText = | |
| typeof telegramData?.quoteText === "string" ? telegramData.quoteText : undefined; | |
| const text = payload.text ?? ""; | |
| const mediaUrls = payload.mediaUrls?.length | |
| ? payload.mediaUrls | |
| : payload.mediaUrl | |
| ? [payload.mediaUrl] | |
| : []; | |
| const baseOpts = { | |
| verbose: false, | |
| textMode: "html" as const, | |
| messageThreadId, | |
| replyToMessageId, | |
| quoteText, | |
| accountId: accountId ?? undefined, | |
| }; | |
| if (mediaUrls.length === 0) { | |
| const result = await send(to, text, { | |
| ...baseOpts, | |
| buttons: telegramData?.buttons, | |
| }); | |
| return { channel: "telegram", ...result }; | |
| } | |
| // Telegram allows reply_markup on media; attach buttons only to first send. | |
| let finalResult: Awaited<ReturnType<typeof send>> | undefined; | |
| for (let i = 0; i < mediaUrls.length; i += 1) { | |
| const mediaUrl = mediaUrls[i]; | |
| const isFirst = i === 0; | |
| finalResult = await send(to, isFirst ? text : "", { | |
| ...baseOpts, | |
| mediaUrl, | |
| ...(isFirst ? { buttons: telegramData?.buttons } : {}), | |
| }); | |
| } | |
| return { channel: "telegram", ...(finalResult ?? { messageId: "unknown", chatId: to }) }; | |
| }, | |
| }; | |