Spaces:
Paused
Paused
| import type { ChannelAccountSnapshot, ChannelStatusIssue } from "../types.js"; | |
| import { appendMatchMetadata, asString, isRecord } from "./shared.js"; | |
| type TelegramAccountStatus = { | |
| accountId?: unknown; | |
| enabled?: unknown; | |
| configured?: unknown; | |
| allowUnmentionedGroups?: unknown; | |
| audit?: unknown; | |
| }; | |
| type TelegramGroupMembershipAuditSummary = { | |
| unresolvedGroups?: number; | |
| hasWildcardUnmentionedGroups?: boolean; | |
| groups?: Array<{ | |
| chatId: string; | |
| ok?: boolean; | |
| status?: string | null; | |
| error?: string | null; | |
| matchKey?: string; | |
| matchSource?: string; | |
| }>; | |
| }; | |
| function readTelegramAccountStatus(value: ChannelAccountSnapshot): TelegramAccountStatus | null { | |
| if (!isRecord(value)) { | |
| return null; | |
| } | |
| return { | |
| accountId: value.accountId, | |
| enabled: value.enabled, | |
| configured: value.configured, | |
| allowUnmentionedGroups: value.allowUnmentionedGroups, | |
| audit: value.audit, | |
| }; | |
| } | |
| function readTelegramGroupMembershipAuditSummary( | |
| value: unknown, | |
| ): TelegramGroupMembershipAuditSummary { | |
| if (!isRecord(value)) { | |
| return {}; | |
| } | |
| const unresolvedGroups = | |
| typeof value.unresolvedGroups === "number" && Number.isFinite(value.unresolvedGroups) | |
| ? value.unresolvedGroups | |
| : undefined; | |
| const hasWildcardUnmentionedGroups = | |
| typeof value.hasWildcardUnmentionedGroups === "boolean" | |
| ? value.hasWildcardUnmentionedGroups | |
| : undefined; | |
| const groupsRaw = value.groups; | |
| const groups = Array.isArray(groupsRaw) | |
| ? (groupsRaw | |
| .map((entry) => { | |
| if (!isRecord(entry)) { | |
| return null; | |
| } | |
| const chatId = asString(entry.chatId); | |
| if (!chatId) { | |
| return null; | |
| } | |
| const ok = typeof entry.ok === "boolean" ? entry.ok : undefined; | |
| const status = asString(entry.status) ?? null; | |
| const error = asString(entry.error) ?? null; | |
| const matchKey = asString(entry.matchKey) ?? undefined; | |
| const matchSource = asString(entry.matchSource) ?? undefined; | |
| return { chatId, ok, status, error, matchKey, matchSource }; | |
| }) | |
| .filter(Boolean) as TelegramGroupMembershipAuditSummary["groups"]) | |
| : undefined; | |
| return { unresolvedGroups, hasWildcardUnmentionedGroups, groups }; | |
| } | |
| export function collectTelegramStatusIssues( | |
| accounts: ChannelAccountSnapshot[], | |
| ): ChannelStatusIssue[] { | |
| const issues: ChannelStatusIssue[] = []; | |
| for (const entry of accounts) { | |
| const account = readTelegramAccountStatus(entry); | |
| if (!account) { | |
| continue; | |
| } | |
| const accountId = asString(account.accountId) ?? "default"; | |
| const enabled = account.enabled !== false; | |
| const configured = account.configured === true; | |
| if (!enabled || !configured) { | |
| continue; | |
| } | |
| if (account.allowUnmentionedGroups === true) { | |
| issues.push({ | |
| channel: "telegram", | |
| accountId, | |
| kind: "config", | |
| message: | |
| "Config allows unmentioned group messages (requireMention=false). Telegram Bot API privacy mode will block most group messages unless disabled.", | |
| fix: "In BotFather run /setprivacy → Disable for this bot (then restart the gateway).", | |
| }); | |
| } | |
| const audit = readTelegramGroupMembershipAuditSummary(account.audit); | |
| if (audit.hasWildcardUnmentionedGroups === true) { | |
| issues.push({ | |
| channel: "telegram", | |
| accountId, | |
| kind: "config", | |
| message: | |
| 'Telegram groups config uses "*" with requireMention=false; membership probing is not possible without explicit group IDs.', | |
| fix: "Add explicit numeric group ids under channels.telegram.groups (or per-account groups) to enable probing.", | |
| }); | |
| } | |
| if (audit.unresolvedGroups && audit.unresolvedGroups > 0) { | |
| issues.push({ | |
| channel: "telegram", | |
| accountId, | |
| kind: "config", | |
| message: `Some configured Telegram groups are not numeric IDs (unresolvedGroups=${audit.unresolvedGroups}). Membership probe can only check numeric group IDs.`, | |
| fix: "Use numeric chat IDs (e.g. -100...) as keys in channels.telegram.groups for requireMention=false groups.", | |
| }); | |
| } | |
| for (const group of audit.groups ?? []) { | |
| if (group.ok === true) { | |
| continue; | |
| } | |
| const status = group.status ? ` status=${group.status}` : ""; | |
| const err = group.error ? `: ${group.error}` : ""; | |
| const baseMessage = `Group ${group.chatId} not reachable by bot.${status}${err}`; | |
| issues.push({ | |
| channel: "telegram", | |
| accountId, | |
| kind: "runtime", | |
| message: appendMatchMetadata(baseMessage, { | |
| matchKey: group.matchKey, | |
| matchSource: group.matchSource, | |
| }), | |
| fix: "Invite the bot to the group, then DM the bot once (/start) and restart the gateway.", | |
| }); | |
| } | |
| } | |
| return issues; | |
| } | |