{"version":3,"file":"slack.mjs","names":[],"sources":["../../src/publishers/slack.ts"],"sourcesContent":["import type { Announcement, Publisher, ReleaseNotesLogger } from \"../shared/types\"\n\nconst SLACK_HEADER_LIMIT = 150\nconst SLACK_SECTION_LIMIT = 3000\nconst SLACK_FALLBACK_LIMIT = 4000\nconst TRUNCATION_SUFFIX = \"\\n\\n[...truncated...]\"\n\nfunction clamp(text: string, maxLength: number) {\n  if (text.length <= maxLength) return text\n  return `${text.slice(0, maxLength - TRUNCATION_SUFFIX.length)}${TRUNCATION_SUFFIX}`\n}\n\nfunction buildFallbackText(announcement: Announcement) {\n  return clamp(\n    `${announcement.title}\\n\\n${formatSlackMrkdwn(announcement.description)}`,\n    SLACK_FALLBACK_LIMIT,\n  )\n}\n\nfunction formatInlineMarkdown(text: string) {\n  return text.replaceAll(/\\*\\*([^*]+)\\*\\*/g, \"*$1*\")\n}\n\nfunction formatSlackMrkdwn(markdown: string) {\n  return markdown\n    .split(\"\\n\")\n    .map((line) => {\n      const heading = line.match(/^#{1,6}\\s+(.+)$/)\n      if (heading?.[1]) return `*${formatInlineMarkdown(heading[1].trim())}*`\n\n      const bullet = line.match(/^(\\s*)[-*]\\s+(.+)$/)\n      if (bullet?.[2]) return `${bullet[1] ?? \"\"}• ${formatInlineMarkdown(bullet[2])}`\n\n      return formatInlineMarkdown(line)\n    })\n    .join(\"\\n\")\n}\n\nfunction buildSlackPayload({\n  announcement,\n  branchName,\n  version,\n}: {\n  announcement: Announcement\n  branchName: string\n  version: string\n}) {\n  return {\n    text: buildFallbackText(announcement),\n    blocks: [\n      {\n        type: \"header\",\n        text: {\n          type: \"plain_text\",\n          text: clamp(announcement.title, SLACK_HEADER_LIMIT),\n          emoji: true,\n        },\n      },\n      {\n        type: \"section\",\n        text: {\n          type: \"mrkdwn\",\n          text: clamp(formatSlackMrkdwn(announcement.description), SLACK_SECTION_LIMIT),\n        },\n      },\n      {\n        type: \"context\",\n        elements: [\n          {\n            type: \"mrkdwn\",\n            text: `*Version:* ${version}  *Branch:* ${branchName}`,\n          },\n        ],\n      },\n    ],\n  }\n}\n\nexport async function publishSlackAnnouncement({\n  webhookUrl,\n  announcement,\n  branchName,\n  version,\n  dryRun,\n  logger,\n  fetchImpl = fetch,\n}: {\n  webhookUrl: string\n  announcement: Announcement\n  branchName: string\n  version: string\n  dryRun: boolean\n  logger: ReleaseNotesLogger\n  fetchImpl?: typeof fetch\n}) {\n  if (!(announcement.title.trim() && announcement.description.trim())) {\n    logger.log(\"Skipping Slack release message because the AI output was empty\")\n    return { sent: false as const, reason: \"empty-output\" as const }\n  }\n\n  const payload = buildSlackPayload({ announcement, branchName, version })\n\n  if (dryRun) {\n    logger.log(`Dry run enabled; would send Slack release message: ${JSON.stringify(payload)}`)\n    return { sent: false as const, reason: \"dry-run\" as const }\n  }\n\n  const response = await fetchImpl(webhookUrl, {\n    method: \"POST\",\n    headers: {\n      \"content-type\": \"application/json\",\n    },\n    body: JSON.stringify(payload),\n  })\n\n  if (!response.ok) {\n    const body = await response.text()\n    throw new Error(`Slack webhook failed: ${response.status} ${body}`)\n  }\n\n  logger.log(\"Sent Slack release message\")\n  return { sent: true as const }\n}\n\nexport function createSlackPublisher({\n  webhookUrl,\n  fetchImpl,\n}: {\n  webhookUrl: string\n  fetchImpl?: typeof fetch\n}): Publisher {\n  return {\n    name: \"slack\",\n    publish(input) {\n      return publishSlackAnnouncement({\n        webhookUrl,\n        announcement: input.announcement,\n        branchName: input.branchName,\n        version: input.version,\n        dryRun: input.dryRun,\n        logger: input.logger,\n        fetchImpl,\n      })\n    },\n  }\n}\n"],"mappings":";AAEA,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAC5B,MAAM,uBAAuB;AAC7B,MAAM,oBAAoB;AAE1B,SAAS,MAAM,MAAc,WAAmB;CAC9C,IAAI,KAAK,UAAU,WAAW,OAAO;CACrC,OAAO,GAAG,KAAK,MAAM,GAAG,YAAY,EAAwB,IAAI;AAClE;AAEA,SAAS,kBAAkB,cAA4B;CACrD,OAAO,MACL,GAAG,aAAa,MAAM,MAAM,kBAAkB,aAAa,WAAW,KACtE,oBACF;AACF;AAEA,SAAS,qBAAqB,MAAc;CAC1C,OAAO,KAAK,WAAW,oBAAoB,MAAM;AACnD;AAEA,SAAS,kBAAkB,UAAkB;CAC3C,OAAO,SACJ,MAAM,IAAI,CAAC,CACX,KAAK,SAAS;EACb,MAAM,UAAU,KAAK,MAAM,iBAAiB;EAC5C,IAAI,UAAU,IAAI,OAAO,IAAI,qBAAqB,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE;EAErE,MAAM,SAAS,KAAK,MAAM,oBAAoB;EAC9C,IAAI,SAAS,IAAI,OAAO,GAAG,OAAO,MAAM,GAAG,IAAI,qBAAqB,OAAO,EAAE;EAE7E,OAAO,qBAAqB,IAAI;CAClC,CAAC,CAAC,CACD,KAAK,IAAI;AACd;AAEA,SAAS,kBAAkB,EACzB,cACA,YACA,WAKC;CACD,OAAO;EACL,MAAM,kBAAkB,YAAY;EACpC,QAAQ;GACN;IACE,MAAM;IACN,MAAM;KACJ,MAAM;KACN,MAAM,MAAM,aAAa,OAAO,kBAAkB;KAClD,OAAO;IACT;GACF;GACA;IACE,MAAM;IACN,MAAM;KACJ,MAAM;KACN,MAAM,MAAM,kBAAkB,aAAa,WAAW,GAAG,mBAAmB;IAC9E;GACF;GACA;IACE,MAAM;IACN,UAAU,CACR;KACE,MAAM;KACN,MAAM,cAAc,QAAQ,cAAc;IAC5C,CACF;GACF;EACF;CACF;AACF;AAEA,eAAsB,yBAAyB,EAC7C,YACA,cACA,YACA,SACA,QACA,QACA,YAAY,SASX;CACD,IAAI,EAAE,aAAa,MAAM,KAAK,KAAK,aAAa,YAAY,KAAK,IAAI;EACnE,OAAO,IAAI,gEAAgE;EAC3E,OAAO;GAAE,MAAM;GAAgB,QAAQ;EAAwB;CACjE;CAEA,MAAM,UAAU,kBAAkB;EAAE;EAAc;EAAY;CAAQ,CAAC;CAEvE,IAAI,QAAQ;EACV,OAAO,IAAI,sDAAsD,KAAK,UAAU,OAAO,GAAG;EAC1F,OAAO;GAAE,MAAM;GAAgB,QAAQ;EAAmB;CAC5D;CAEA,MAAM,WAAW,MAAM,UAAU,YAAY;EAC3C,QAAQ;EACR,SAAS,EACP,gBAAgB,mBAClB;EACA,MAAM,KAAK,UAAU,OAAO;CAC9B,CAAC;CAED,IAAI,CAAC,SAAS,IAAI;EAChB,MAAM,OAAO,MAAM,SAAS,KAAK;EACjC,MAAM,IAAI,MAAM,yBAAyB,SAAS,OAAO,GAAG,MAAM;CACpE;CAEA,OAAO,IAAI,4BAA4B;CACvC,OAAO,EAAE,MAAM,KAAc;AAC/B;AAEA,SAAgB,qBAAqB,EACnC,YACA,aAIY;CACZ,OAAO;EACL,MAAM;EACN,QAAQ,OAAO;GACb,OAAO,yBAAyB;IAC9B;IACA,cAAc,MAAM;IACpB,YAAY,MAAM;IAClB,SAAS,MAAM;IACf,QAAQ,MAAM;IACd,QAAQ,MAAM;IACd;GACF,CAAC;EACH;CACF;AACF"}