122 lines · 4.6 KB
import { htmlToText as coreHtmlToText } from "../../core/html-to-text.ts";
import type { DeliveryResult, MailAdapter, OwnerRef, ParsedMail } from "../../core/types.ts";
import { postMessage, uploadFile, SlackApiError, type SlackFile } from "./slack-rest.ts";

// Conservative caps, not Slack's actual platform maximums -- chosen the
// same way Discord's and Telegram's adapters picked theirs: a point past
// which a message stops being a quick DM to skim and should be an
// attachment instead.
const INLINE_BODY_CAP = 3500;
const SLACK_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, {
    // mrkdwn has its own small set of special characters (*_~`), but
    // escaping them would mangle legitimate-looking formatting in
    // forwarded mail worse than just leaving it plain -- same tradeoff
    // Telegram's plain-text send makes, just for a different syntax.
    escape: (text) => text,
    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 createSlackAdapter(botToken: string): MailAdapter {