export type TelegramTarget = { chatId: string; messageThreadId?: number; }; export function stripTelegramInternalPrefixes(to: string): string { let trimmed = to.trim(); let strippedTelegramPrefix = false; while (true) { const next = (() => { if (/^(telegram|tg):/i.test(trimmed)) { strippedTelegramPrefix = true; return trimmed.replace(/^(telegram|tg):/i, "").trim(); } // Legacy internal form: `telegram:group:` (still emitted by session keys). if (strippedTelegramPrefix && /^group:/i.test(trimmed)) { return trimmed.replace(/^group:/i, "").trim(); } return trimmed; })(); if (next === trimmed) return trimmed; trimmed = next; } } /** * Parse a Telegram delivery target into chatId and optional topic/thread ID. * * Supported formats: * - `chatId` (plain chat ID, t.me link, @username, or internal prefixes like `telegram:...`) * - `chatId:topicId` (numeric topic/thread ID) * - `chatId:topic:topicId` (explicit topic marker; preferred) */ export function parseTelegramTarget(to: string): TelegramTarget { const normalized = stripTelegramInternalPrefixes(to); const topicMatch = /^(.+?):topic:(\d+)$/.exec(normalized); if (topicMatch) { return { chatId: topicMatch[1], messageThreadId: Number.parseInt(topicMatch[2], 10), }; } const colonMatch = /^(.+):(\d+)$/.exec(normalized); if (colonMatch) { return { chatId: colonMatch[1], messageThreadId: Number.parseInt(colonMatch[2], 10), }; } return { chatId: normalized }; }