feishu-bot-notify
Version:
基于 tsdown 打包的飞书机器人通知工具
198 lines (193 loc) • 5.56 kB
JavaScript
//#region rolldown:runtime
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
key = keys[i];
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: ((k) => from[k]).bind(null, key),
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
value: mod,
enumerable: true
}) : target, mod));
//#endregion
let ofetch = require("ofetch");
ofetch = __toESM(ofetch);
//#region src/card.ts
const DEFAULT_TITLE = "组件更新啦!!!";
const DEFAULT_BUTTON_TEXT = "去看看";
/**
* 构造飞书交互式卡片
*/
function buildComponentUpdateCard(options) {
const { componentName, version, changes, buttonUrl, title, buttonText } = options;
const markdownUpdates = formatChanges(changes);
return {
schema: "2.0",
config: {
update_multi: true,
style: { text_size: { normal_v2: {
default: "normal",
pc: "normal",
mobile: "heading"
} } }
},
header: {
title: {
tag: "plain_text",
content: title ?? DEFAULT_TITLE
},
template: "blue",
icon: {
tag: "standard_icon",
token: "speaker_filled"
},
padding: "12px 12px 12px 12px"
},
body: {
direction: "vertical",
padding: "12px 12px 12px 12px",
elements: [
{
tag: "hr",
margin: "0px 0px 0px 0px"
},
buildMetaColumn(componentName, version),
{
tag: "div",
text: {
tag: "lark_md",
content: `**📝更新说明:**\n${markdownUpdates}`,
text_size: "normal_v2",
text_align: "left",
text_color: "default",
lines: 5
},
margin: "0px 0px 0px 0px"
},
{
tag: "hr",
margin: "0px 0px 0px 0px"
},
{
tag: "button",
text: {
tag: "plain_text",
content: buttonText ?? DEFAULT_BUTTON_TEXT
},
type: "primary_filled",
width: "default",
size: "medium",
behaviors: [{
type: "open_url",
default_url: buttonUrl
}],
margin: "0px 0px 0px 0px",
element_id: "go_component_url"
}
]
}
};
}
function buildMetaColumn(componentName, version) {
return {
tag: "column_set",
columns: [{
tag: "column",
width: "weighted",
elements: [{
tag: "markdown",
content: `**📦组件名称:**${componentName}`,
text_align: "left",
text_size: "normal_v2"
}],
vertical_align: "top",
weight: 1
}, {
tag: "column",
width: "weighted",
elements: [{
tag: "markdown",
content: `**💥版本:** ${version}`,
text_align: "left",
text_size: "normal_v2"
}],
vertical_align: "top",
weight: 1
}]
};
}
function formatChanges(changes) {
if (!Array.isArray(changes)) return changes;
if (!changes.length) return "- 暂无更新内容";
return changes.map((item) => item.startsWith("-") ? item : `- ${item}`).join("\n");
}
//#endregion
//#region src/sender.ts
const client = ofetch.ofetch.create({
headers: { "Content-Type": "application/json" },
retry: 0
});
/**
* 负责向飞书 webhook 推送交互式卡片,默认使用 ofetch 并保留详细错误信息
*/
async function sendCardToWebhook(options) {
const { webhookUrl, card, timeoutMs } = options;
const payload = {
msg_type: "interactive",
card
};
try {
const { status, _data } = await client.raw(webhookUrl, {
method: "POST",
body: payload,
timeout: timeoutMs
});
if (status < 200 || status >= 300) throw new Error(`飞书接口返回 HTTP ${status}`);
if (!_data || typeof _data.code !== "number") throw new Error("飞书接口返回内容为空或结构异常");
if (_data.code !== 0) throw new Error(`飞书接口响应异常:${JSON.stringify(_data)}`);
return _data;
} catch (error) {
if (error instanceof ofetch.FetchError) {
var _error$cause;
if (error.status === 408 || ((_error$cause = error.cause) === null || _error$cause === void 0 ? void 0 : _error$cause.name) === "AbortError") throw new Error("请求飞书接口超时");
if (typeof error.status === "number" && error.status >= 400) {
const bodyText = typeof error.data === "string" ? error.data : JSON.stringify(error.data ?? {});
throw new Error(`飞书接口返回 HTTP ${error.status}:${bodyText}`);
}
}
throw error instanceof Error ? error : /* @__PURE__ */ new Error("请求飞书接口失败");
}
}
//#endregion
//#region src/index.ts
/**
* 基于组件更新信息构建卡片并推送至飞书机器人
*/
async function sendComponentUpdateNotification(options) {
const { webhookUrl, timeoutMs,...cardOptions } = options;
const card = buildComponentUpdateCard(cardOptions);
return sendCardToWebhook({
webhookUrl,
card,
timeoutMs
});
}
/**
* 仅构建飞书交互式卡片,便于在外部服务中复用
*/
function createComponentUpdateCard(options) {
return buildComponentUpdateCard(options);
}
//#endregion
exports.createComponentUpdateCard = createComponentUpdateCard;
exports.sendComponentUpdateNotification = sendComponentUpdateNotification;