dsh-messager 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +169 -45
- package/README.md +145 -146
- package/cordis.patch.yml +13 -0
- package/lib/channels/dingtalk.d.ts +38 -0
- package/lib/channels/dingtalk.d.ts.map +1 -0
- package/lib/channels/dingtalk.js +60 -0
- package/lib/channels/dingtalk.js.map +1 -0
- package/lib/channels/discord.d.ts +28 -0
- package/lib/channels/discord.d.ts.map +1 -0
- package/lib/channels/discord.js +44 -0
- package/lib/channels/discord.js.map +1 -0
- package/lib/channels/telegram.d.ts +31 -0
- package/lib/channels/telegram.d.ts.map +1 -0
- package/lib/channels/telegram.js +52 -0
- package/lib/channels/telegram.js.map +1 -0
- package/lib/channels/wecom.d.ts +34 -0
- package/lib/channels/wecom.d.ts.map +1 -0
- package/lib/channels/wecom.js +53 -0
- package/lib/channels/wecom.js.map +1 -0
- package/lib/client.js +391 -54
- package/lib/client.js.map +1 -1
- package/lib/config.d.ts +46 -0
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +27 -0
- package/lib/config.js.map +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +33 -2
- package/lib/index.js.map +1 -1
- package/lib/notify.d.ts +1 -1
- package/lib/notify.d.ts.map +1 -1
- package/lib/notify.js +10 -6
- package/lib/notify.js.map +1 -1
- package/lib/types/client/card-controller.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +48 -2
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/settings-form.d.ts.map +1 -1
- package/lib/types/config.d.ts +46 -0
- package/lib/types/config.d.ts.map +1 -1
- package/package.json +28 -5
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram 通道(Bot API):sendMessage(HTML parse_mode),host 端投递。
|
|
3
|
+
*
|
|
4
|
+
* 端点 = https://api.telegram.org/bot<token>/sendMessage(token 即凭证,走 URL 路径)。
|
|
5
|
+
* 成功判定:HTTP 2xx 且响应 ok === true。
|
|
6
|
+
* HTML parse_mode 必须转义 & < > " ',否则非法标签会导致 API 400。
|
|
7
|
+
* 限制守卫:text ≤ 4096 字符。
|
|
8
|
+
*/
|
|
9
|
+
export const TELEGRAM_API_BASE = 'https://api.telegram.org';
|
|
10
|
+
/** HTML 转义(纯函数):& < > " '。 */
|
|
11
|
+
export function escapeHtml(text) {
|
|
12
|
+
return text
|
|
13
|
+
.replaceAll('&', '&')
|
|
14
|
+
.replaceAll('<', '<')
|
|
15
|
+
.replaceAll('>', '>')
|
|
16
|
+
.replaceAll('"', '"')
|
|
17
|
+
.replaceAll("'", ''');
|
|
18
|
+
}
|
|
19
|
+
/** 构建 sendMessage 载荷(纯函数;text ≤ 4096 兜底)。 */
|
|
20
|
+
export function buildTelegramPayload(payload, chatId) {
|
|
21
|
+
const lines = [`<b>${escapeHtml(payload.title)}</b>`];
|
|
22
|
+
if (payload.body !== '')
|
|
23
|
+
lines.push(escapeHtml(payload.body));
|
|
24
|
+
lines.push(`<a href="${escapeHtml(payload.url)}">打开 DSH</a>`);
|
|
25
|
+
return {
|
|
26
|
+
chat_id: chatId,
|
|
27
|
+
text: lines.join('\n').slice(0, 4096),
|
|
28
|
+
parse_mode: 'HTML',
|
|
29
|
+
link_preview_options: { is_disabled: true },
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function createTelegramChannel(options) {
|
|
33
|
+
return {
|
|
34
|
+
id: 'telegram',
|
|
35
|
+
async send(payload) {
|
|
36
|
+
const endpoint = `${TELEGRAM_API_BASE}/bot${options.botToken}/sendMessage`;
|
|
37
|
+
const response = await fetch(endpoint, {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
headers: { 'content-type': 'application/json' },
|
|
40
|
+
body: JSON.stringify(buildTelegramPayload(payload, options.chatId)),
|
|
41
|
+
signal: AbortSignal.timeout(options.timeoutMs),
|
|
42
|
+
});
|
|
43
|
+
if (!response.ok)
|
|
44
|
+
throw new Error(`telegram API responded ${response.status}`);
|
|
45
|
+
const result = (await response.json().catch(() => undefined));
|
|
46
|
+
if (result !== undefined && result.ok !== true) {
|
|
47
|
+
throw new Error(`telegram rejected: ${result.description ?? 'unknown error'}`);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=telegram.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.js","sourceRoot":"","sources":["../../src/channels/telegram.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,MAAM,CAAC,MAAM,iBAAiB,GAAG,0BAA0B,CAAA;AAE3D,8BAA8B;AAC9B,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,IAAI;SACR,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;SACxB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC;SACzB,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;AAC7B,CAAC;AAUD,6CAA6C;AAC7C,MAAM,UAAU,oBAAoB,CAAC,OAA4B,EAAE,MAAc;IAC/E,MAAM,KAAK,GAAG,CAAC,MAAM,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IACrD,IAAI,OAAO,CAAC,IAAI,KAAK,EAAE;QAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IAC7D,KAAK,CAAC,IAAI,CAAC,YAAY,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;IAC7D,OAAO;QACL,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;QACrC,UAAU,EAAE,MAAM;QAClB,oBAAoB,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE;KAC5C,CAAA;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAA+B;IACnE,OAAO;QACL,EAAE,EAAE,UAAU;QACd,KAAK,CAAC,IAAI,CAAC,OAA4B;YACrC,MAAM,QAAQ,GAAG,GAAG,iBAAiB,OAAO,OAAO,CAAC,QAAQ,cAAc,CAAA;YAC1E,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;gBACrC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;gBACnE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC;aAC/C,CAAC,CAAA;YACF,IAAI,CAAC,QAAQ,CAAC,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;YAC9E,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAuD,CAAA;YACnH,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;gBAC/C,MAAM,IAAI,KAAK,CAAC,sBAAsB,MAAM,CAAC,WAAW,IAAI,eAAe,EAAE,CAAC,CAAA;YAChF,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 企业微信群机器人通道(webhook):POST markdown 消息,host 端投递。
|
|
3
|
+
*
|
|
4
|
+
* 消息:msgtype=markdown,content 为「加粗标题 + 正文 + 打开链接」。
|
|
5
|
+
* 可选加签(机器人「安全设置-加签」):
|
|
6
|
+
* string_to_sign = `${timestamp}\n${secret}`
|
|
7
|
+
* sign = base64(HmacSHA256(string_to_sign, key=secret)) // 无需 URL 编码
|
|
8
|
+
* 追加为查询参数 ×tamp=<ts>&sign=<sign>(与钉钉不同:钉钉需要 urlEncode)。
|
|
9
|
+
* 成功判定:HTTP 2xx 且响应 errcode === 0。
|
|
10
|
+
*/
|
|
11
|
+
import type { NotifyChannel, NotificationPayload } from '../notify.js';
|
|
12
|
+
export interface WecomChannelOptions {
|
|
13
|
+
webhookUrl: string;
|
|
14
|
+
/** 加签密钥(机器人「安全设置-加签」),配置后按企业微信规范签名。 */
|
|
15
|
+
secret?: string;
|
|
16
|
+
timeoutMs: number;
|
|
17
|
+
}
|
|
18
|
+
/** 企业微信 markdown 消息载荷。 */
|
|
19
|
+
export interface WecomMarkdownPayload {
|
|
20
|
+
msgtype: 'markdown';
|
|
21
|
+
markdown: {
|
|
22
|
+
content: string;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** 构建企业微信 markdown 消息(纯函数;content 限 4000 字符兜底)。 */
|
|
26
|
+
export declare function buildWecomPayload(payload: NotificationPayload): WecomMarkdownPayload;
|
|
27
|
+
/**
|
|
28
|
+
* 企业微信加签:
|
|
29
|
+
* sign = base64(HmacSHA256(key=secret, msg=`${timestamp}\n${secret}`)),无 URL 编码。
|
|
30
|
+
* @returns 追加了 timestamp/sign 查询参数的完整 URL。
|
|
31
|
+
*/
|
|
32
|
+
export declare function signWecomUrl(webhookUrl: string, secret: string, timestamp: string): string;
|
|
33
|
+
export declare function createWecomChannel(options: WecomChannelOptions): NotifyChannel;
|
|
34
|
+
//# sourceMappingURL=wecom.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wecom.d.ts","sourceRoot":"","sources":["../../src/channels/wecom.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAEtE,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAA;IAClB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,0BAA0B;AAC1B,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,UAAU,CAAA;IACnB,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAC9B;AAED,mDAAmD;AACnD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,mBAAmB,GAAG,oBAAoB,CAKpF;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAK1F;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,aAAa,CAoB9E"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 企业微信群机器人通道(webhook):POST markdown 消息,host 端投递。
|
|
3
|
+
*
|
|
4
|
+
* 消息:msgtype=markdown,content 为「加粗标题 + 正文 + 打开链接」。
|
|
5
|
+
* 可选加签(机器人「安全设置-加签」):
|
|
6
|
+
* string_to_sign = `${timestamp}\n${secret}`
|
|
7
|
+
* sign = base64(HmacSHA256(string_to_sign, key=secret)) // 无需 URL 编码
|
|
8
|
+
* 追加为查询参数 ×tamp=<ts>&sign=<sign>(与钉钉不同:钉钉需要 urlEncode)。
|
|
9
|
+
* 成功判定:HTTP 2xx 且响应 errcode === 0。
|
|
10
|
+
*/
|
|
11
|
+
import { createHmac } from 'node:crypto';
|
|
12
|
+
/** 构建企业微信 markdown 消息(纯函数;content 限 4000 字符兜底)。 */
|
|
13
|
+
export function buildWecomPayload(payload) {
|
|
14
|
+
const lines = [`**${payload.title}**`];
|
|
15
|
+
if (payload.body !== '')
|
|
16
|
+
lines.push(payload.body);
|
|
17
|
+
lines.push(`[打开 DSH](${payload.url})`);
|
|
18
|
+
return { msgtype: 'markdown', markdown: { content: lines.join('\n').slice(0, 4000) } };
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 企业微信加签:
|
|
22
|
+
* sign = base64(HmacSHA256(key=secret, msg=`${timestamp}\n${secret}`)),无 URL 编码。
|
|
23
|
+
* @returns 追加了 timestamp/sign 查询参数的完整 URL。
|
|
24
|
+
*/
|
|
25
|
+
export function signWecomUrl(webhookUrl, secret, timestamp) {
|
|
26
|
+
const stringToSign = `${timestamp}\n${secret}`;
|
|
27
|
+
const sign = createHmac('sha256', secret).update(stringToSign).digest('base64');
|
|
28
|
+
const separator = webhookUrl.includes('?') ? '&' : '?';
|
|
29
|
+
return `${webhookUrl}${separator}timestamp=${timestamp}&sign=${sign}`;
|
|
30
|
+
}
|
|
31
|
+
export function createWecomChannel(options) {
|
|
32
|
+
return {
|
|
33
|
+
id: 'wecom',
|
|
34
|
+
async send(payload) {
|
|
35
|
+
const url = options.secret === undefined
|
|
36
|
+
? options.webhookUrl
|
|
37
|
+
: signWecomUrl(options.webhookUrl, options.secret, String(Math.floor(Date.now() / 1000)));
|
|
38
|
+
const response = await fetch(url, {
|
|
39
|
+
method: 'POST',
|
|
40
|
+
headers: { 'content-type': 'application/json' },
|
|
41
|
+
body: JSON.stringify(buildWecomPayload(payload)),
|
|
42
|
+
signal: AbortSignal.timeout(options.timeoutMs),
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok)
|
|
45
|
+
throw new Error(`wecom webhook responded ${response.status}`);
|
|
46
|
+
const result = (await response.json().catch(() => undefined));
|
|
47
|
+
if (result !== undefined && result.errcode !== 0) {
|
|
48
|
+
throw new Error(`wecom webhook rejected: errcode=${String(result.errcode)} errmsg=${String(result.errmsg)}`);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=wecom.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wecom.js","sourceRoot":"","sources":["../../src/channels/wecom.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAgBxC,mDAAmD;AACnD,MAAM,UAAU,iBAAiB,CAAC,OAA4B;IAC5D,MAAM,KAAK,GAAG,CAAC,KAAK,OAAO,CAAC,KAAK,IAAI,CAAC,CAAA;IACtC,IAAI,OAAO,CAAC,IAAI,KAAK,EAAE;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IACjD,KAAK,CAAC,IAAI,CAAC,YAAY,OAAO,CAAC,GAAG,GAAG,CAAC,CAAA;IACtC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAA;AACxF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,UAAkB,EAAE,MAAc,EAAE,SAAiB;IAChF,MAAM,YAAY,GAAG,GAAG,SAAS,KAAK,MAAM,EAAE,CAAA;IAC9C,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC/E,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAA;IACtD,OAAO,GAAG,UAAU,GAAG,SAAS,aAAa,SAAS,SAAS,IAAI,EAAE,CAAA;AACvE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAA4B;IAC7D,OAAO;QACL,EAAE,EAAE,OAAO;QACX,KAAK,CAAC,IAAI,CAAC,OAA4B;YACrC,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,KAAK,SAAS;gBACtC,CAAC,CAAC,OAAO,CAAC,UAAU;gBACpB,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;YAC3F,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAChC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;gBAChD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC;aAC/C,CAAC,CAAA;YACF,IAAI,CAAC,QAAQ,CAAC,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;YAC/E,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAsD,CAAA;YAClH,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;gBACjD,MAAM,IAAI,KAAK,CAAC,mCAAmC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;YAC9G,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
|