@yaoyuanchao/dingtalk 1.3.2 → 1.3.4
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/package.json +1 -1
- package/src/api.ts +12 -4
- package/src/channel.ts +14 -2
- package/src/monitor.ts +30 -6
package/package.json
CHANGED
package/src/api.ts
CHANGED
|
@@ -93,12 +93,16 @@ export async function getDingTalkAccessToken(clientId: string, clientSecret: str
|
|
|
93
93
|
export async function sendViaSessionWebhook(
|
|
94
94
|
sessionWebhook: string,
|
|
95
95
|
text: string,
|
|
96
|
-
): Promise<{ ok: boolean }> {
|
|
96
|
+
): Promise<{ ok: boolean; errcode?: number; errmsg?: string }> {
|
|
97
97
|
const res = await jsonPost(sessionWebhook, {
|
|
98
98
|
msgtype: "text",
|
|
99
99
|
text: { content: text },
|
|
100
100
|
});
|
|
101
|
-
|
|
101
|
+
const ok = res?.errcode === 0 || !res?.errcode;
|
|
102
|
+
if (!ok) {
|
|
103
|
+
console.warn(`[dingtalk] SessionWebhook text error: errcode=${res?.errcode}, errmsg=${res?.errmsg}`);
|
|
104
|
+
}
|
|
105
|
+
return { ok, errcode: res?.errcode, errmsg: res?.errmsg };
|
|
102
106
|
}
|
|
103
107
|
|
|
104
108
|
/** Send markdown via sessionWebhook */
|
|
@@ -106,12 +110,16 @@ export async function sendMarkdownViaSessionWebhook(
|
|
|
106
110
|
sessionWebhook: string,
|
|
107
111
|
title: string,
|
|
108
112
|
text: string,
|
|
109
|
-
): Promise<{ ok: boolean }> {
|
|
113
|
+
): Promise<{ ok: boolean; errcode?: number; errmsg?: string }> {
|
|
110
114
|
const res = await jsonPost(sessionWebhook, {
|
|
111
115
|
msgtype: "markdown",
|
|
112
116
|
markdown: { title, text },
|
|
113
117
|
});
|
|
114
|
-
|
|
118
|
+
const ok = res?.errcode === 0 || !res?.errcode;
|
|
119
|
+
if (!ok) {
|
|
120
|
+
console.warn(`[dingtalk] SessionWebhook markdown error: errcode=${res?.errcode}, errmsg=${res?.errmsg}`);
|
|
121
|
+
}
|
|
122
|
+
return { ok, errcode: res?.errcode, errmsg: res?.errmsg };
|
|
115
123
|
}
|
|
116
124
|
|
|
117
125
|
/** Send image via sessionWebhook using markdown format */
|
package/src/channel.ts
CHANGED
|
@@ -4,6 +4,18 @@ import { startDingTalkMonitor } from './monitor.js';
|
|
|
4
4
|
import { sendDingTalkRestMessage } from './api.js';
|
|
5
5
|
import { probeDingTalk } from './probe.js';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Parse outbound `to` address, stripping optional channel prefix.
|
|
9
|
+
* Handles both "dm:id" and "dingtalk:dm:id" formats.
|
|
10
|
+
*/
|
|
11
|
+
function parseOutboundTo(to: string): { type: string; id: string } {
|
|
12
|
+
const parts = to.split(':');
|
|
13
|
+
if (parts[0] === 'dingtalk' && parts.length > 2) {
|
|
14
|
+
parts.shift();
|
|
15
|
+
}
|
|
16
|
+
return { type: parts[0], id: parts.slice(1).join(':') };
|
|
17
|
+
}
|
|
18
|
+
|
|
7
19
|
export const dingtalkPlugin = {
|
|
8
20
|
id: 'dingtalk',
|
|
9
21
|
|
|
@@ -166,7 +178,7 @@ export const dingtalkPlugin = {
|
|
|
166
178
|
|
|
167
179
|
async sendText({ to, text, accountId, cfg }) {
|
|
168
180
|
const account = resolveDingTalkAccount({ cfg, accountId });
|
|
169
|
-
const
|
|
181
|
+
const { type, id } = parseOutboundTo(to);
|
|
170
182
|
|
|
171
183
|
if (type === 'dm') {
|
|
172
184
|
await sendDingTalkRestMessage({
|
|
@@ -204,7 +216,7 @@ export const dingtalkPlugin = {
|
|
|
204
216
|
}
|
|
205
217
|
|
|
206
218
|
const account = resolveDingTalkAccount({ cfg, accountId });
|
|
207
|
-
const
|
|
219
|
+
const { type, id } = parseOutboundTo(to);
|
|
208
220
|
|
|
209
221
|
// Build text message with image URL as markdown image
|
|
210
222
|
const imageMarkdown = ``;
|
package/src/monitor.ts
CHANGED
|
@@ -52,6 +52,11 @@ export async function startDingTalkMonitor(ctx: DingTalkMonitorContext): Promise
|
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
client.registerCallbackListener(TOPIC_ROBOT, async (downstream: any) => {
|
|
55
|
+
// Immediately ACK to prevent DingTalk from retrying (60s timeout)
|
|
56
|
+
try {
|
|
57
|
+
client.socketResponse(downstream.headers.messageId, { status: 'SUCCESS' });
|
|
58
|
+
} catch (_) { /* best-effort ACK */ }
|
|
59
|
+
|
|
55
60
|
try {
|
|
56
61
|
const data: DingTalkRobotMessage = typeof downstream.data === "string"
|
|
57
62
|
? JSON.parse(downstream.data) : downstream.data;
|
|
@@ -577,10 +582,13 @@ async function processInboundMessage(
|
|
|
577
582
|
cfg: actualCfg,
|
|
578
583
|
dispatcherOptions: {
|
|
579
584
|
deliver: async (payload: any) => {
|
|
585
|
+
log?.info?.("[dingtalk] Deliver payload keys: " + Object.keys(payload || {}).join(',') + " text?=" + (typeof payload?.text) + " markdown?=" + (typeof payload?.markdown));
|
|
580
586
|
const textToSend = resolveDeliverText(payload, log);
|
|
581
587
|
if (textToSend) {
|
|
582
588
|
await deliverReply(replyTarget, textToSend, log);
|
|
583
589
|
setStatus?.({ lastOutboundAt: Date.now() });
|
|
590
|
+
} else {
|
|
591
|
+
log?.info?.("[dingtalk] Deliver: no text resolved from payload");
|
|
584
592
|
}
|
|
585
593
|
},
|
|
586
594
|
onError: (err: any) => {
|
|
@@ -680,8 +688,12 @@ async function dispatchWithFullPipeline(params: {
|
|
|
680
688
|
responsePrefix: '',
|
|
681
689
|
deliver: async (payload: any) => {
|
|
682
690
|
try {
|
|
691
|
+
log?.info?.("[dingtalk] Pipeline deliver payload keys: " + Object.keys(payload || {}).join(',') + " text?=" + (typeof payload?.text) + " markdown?=" + (typeof payload?.markdown));
|
|
683
692
|
const textToSend = resolveDeliverText(payload, log);
|
|
684
|
-
if (!textToSend)
|
|
693
|
+
if (!textToSend) {
|
|
694
|
+
log?.info?.("[dingtalk] Pipeline deliver: no text resolved from payload");
|
|
695
|
+
return { ok: true };
|
|
696
|
+
}
|
|
685
697
|
await deliverReply(replyTarget, textToSend, log);
|
|
686
698
|
setStatus?.({ lastOutboundAt: Date.now() });
|
|
687
699
|
return { ok: true };
|
|
@@ -709,7 +721,15 @@ async function dispatchWithFullPipeline(params: {
|
|
|
709
721
|
* We merge them into the text as markdown image syntax so DingTalk can render them.
|
|
710
722
|
*/
|
|
711
723
|
function resolveDeliverText(payload: any, log?: any): string | undefined {
|
|
712
|
-
|
|
724
|
+
// payload.markdown may be a boolean flag (not the actual text), so check type
|
|
725
|
+
let text = (typeof payload.markdown === 'string' && payload.markdown) || payload.text;
|
|
726
|
+
|
|
727
|
+
// Guard: ensure text is a string (platform might send unexpected types)
|
|
728
|
+
if (text != null && typeof text !== 'string') {
|
|
729
|
+
log?.info?.("[dingtalk] Deliver payload has non-string text type=" + typeof text + ", payload keys=" + Object.keys(payload).join(','));
|
|
730
|
+
text = String(text);
|
|
731
|
+
}
|
|
732
|
+
|
|
713
733
|
const mediaUrl = payload.mediaUrl || payload.media || payload.imageUrl || payload.image;
|
|
714
734
|
|
|
715
735
|
if (mediaUrl && typeof mediaUrl === 'string' && mediaUrl.startsWith('http')) {
|
|
@@ -762,13 +782,17 @@ async function deliverReply(target: any, text: string, log?: any): Promise<void>
|
|
|
762
782
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
763
783
|
try {
|
|
764
784
|
log?.info?.("[dingtalk] Using sessionWebhook (attempt " + attempt + "/" + maxRetries + "), format=" + messageFormat);
|
|
765
|
-
log?.info?.("[dingtalk] Sending text: " + chunk.substring(0, 200));
|
|
785
|
+
log?.info?.("[dingtalk] Sending text (" + chunk.length + " chars): " + chunk.substring(0, 200));
|
|
786
|
+
let sendResult: { ok: boolean; errcode?: number; errmsg?: string };
|
|
766
787
|
if (isMarkdown) {
|
|
767
|
-
await sendMarkdownViaSessionWebhook(target.sessionWebhook, "Reply", chunk);
|
|
788
|
+
sendResult = await sendMarkdownViaSessionWebhook(target.sessionWebhook, "Reply", chunk);
|
|
768
789
|
} else {
|
|
769
|
-
await sendViaSessionWebhook(target.sessionWebhook, chunk);
|
|
790
|
+
sendResult = await sendViaSessionWebhook(target.sessionWebhook, chunk);
|
|
791
|
+
}
|
|
792
|
+
if (!sendResult.ok) {
|
|
793
|
+
throw new Error(`SessionWebhook rejected: errcode=${sendResult.errcode}, errmsg=${sendResult.errmsg}`);
|
|
770
794
|
}
|
|
771
|
-
log?.info?.("[dingtalk] SessionWebhook send OK");
|
|
795
|
+
log?.info?.("[dingtalk] SessionWebhook send OK (errcode=" + (sendResult.errcode ?? 0) + ")");
|
|
772
796
|
webhookSuccess = true;
|
|
773
797
|
break;
|
|
774
798
|
} catch (err) {
|