128 lines · 5.0 KB
import { htmlToText as coreHtmlToText } from "../../core/html-to-text.ts";
import type { DeliveryResult, MailAdapter, OwnerRef, ParsedMail } from "../../core/types.ts";
import { sendDocument, sendMessage, TelegramApiError, type TelegramFile } from "./telegram-rest.ts";

// Telegram's hard cap per sendMessage call. Anything longer gets sent as a
// message.txt attachment instead, same shape as Discord's inline-body cap.
const TELEGRAM_MESSAGE_CAP = 4096;
const INLINE_BODY_CAP = 3500;
// Telegram's own limit for bot-uploaded documents.
const TELEGRAM_FILE_CAP = 50 * 1024 * 1024;

const MAX_HTML_LENGTH = 256 * 1024;
const SPARSE_TEXT_THRESHOLD = 200;
const SUBSTANTIAL_HTML_THRESHOLD = 1500;

function htmlToText(html: string): string {
  return coreHtmlToText(html, {
    // Sent as plain text (no parse_mode), so nothing needs escaping -- unlike
    // Discord, there's no markdown for attacker-controlled mail to abuse.
    escape: (text) => text,
    // Link previews are disabled per-message via the API instead of by
    // obscuring the URL's syntax, so it can just be printed plainly.
    formatLink: (url) => `(${url})`,
  });
}

function truncateAtLineBoundary(text: string, maxLength: number): string {
  const lines = text.split("\n");
  let result = "";
  for (const line of lines) {
    const candidate = result ? `${result}\n${line}` : line;
    if (candidate.length > maxLength) {
      break;
    }
    result = candidate;
  }
  return result || text.slice(0, maxLength);
}

export function createTelegramAdapter(botToken: string): MailAdapter {