@yaoyuanchao/dingtalk 1.3.1 → 1.3.3
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 +4 -3
- package/src/monitor.ts +46 -8
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
|
@@ -206,10 +206,11 @@ export const dingtalkPlugin = {
|
|
|
206
206
|
const account = resolveDingTalkAccount({ cfg, accountId });
|
|
207
207
|
const [type, id] = to.split(':');
|
|
208
208
|
|
|
209
|
-
// Build text message with image URL
|
|
209
|
+
// Build text message with image URL as markdown image
|
|
210
|
+
const imageMarkdown = ``;
|
|
210
211
|
const textMessage = text
|
|
211
|
-
? `${text}\n\n
|
|
212
|
-
:
|
|
212
|
+
? `${text}\n\n${imageMarkdown}`
|
|
213
|
+
: imageMarkdown;
|
|
213
214
|
|
|
214
215
|
if (type === 'dm') {
|
|
215
216
|
await sendDingTalkRestMessage({
|
package/src/monitor.ts
CHANGED
|
@@ -577,9 +577,13 @@ async function processInboundMessage(
|
|
|
577
577
|
cfg: actualCfg,
|
|
578
578
|
dispatcherOptions: {
|
|
579
579
|
deliver: async (payload: any) => {
|
|
580
|
-
|
|
581
|
-
|
|
580
|
+
log?.info?.("[dingtalk] Deliver payload keys: " + Object.keys(payload || {}).join(',') + " text?=" + (typeof payload?.text) + " markdown?=" + (typeof payload?.markdown));
|
|
581
|
+
const textToSend = resolveDeliverText(payload, log);
|
|
582
|
+
if (textToSend) {
|
|
583
|
+
await deliverReply(replyTarget, textToSend, log);
|
|
582
584
|
setStatus?.({ lastOutboundAt: Date.now() });
|
|
585
|
+
} else {
|
|
586
|
+
log?.info?.("[dingtalk] Deliver: no text resolved from payload");
|
|
583
587
|
}
|
|
584
588
|
},
|
|
585
589
|
onError: (err: any) => {
|
|
@@ -679,8 +683,12 @@ async function dispatchWithFullPipeline(params: {
|
|
|
679
683
|
responsePrefix: '',
|
|
680
684
|
deliver: async (payload: any) => {
|
|
681
685
|
try {
|
|
682
|
-
|
|
683
|
-
|
|
686
|
+
log?.info?.("[dingtalk] Pipeline deliver payload keys: " + Object.keys(payload || {}).join(',') + " text?=" + (typeof payload?.text) + " markdown?=" + (typeof payload?.markdown));
|
|
687
|
+
const textToSend = resolveDeliverText(payload, log);
|
|
688
|
+
if (!textToSend) {
|
|
689
|
+
log?.info?.("[dingtalk] Pipeline deliver: no text resolved from payload");
|
|
690
|
+
return { ok: true };
|
|
691
|
+
}
|
|
684
692
|
await deliverReply(replyTarget, textToSend, log);
|
|
685
693
|
setStatus?.({ lastOutboundAt: Date.now() });
|
|
686
694
|
return { ok: true };
|
|
@@ -702,6 +710,32 @@ async function dispatchWithFullPipeline(params: {
|
|
|
702
710
|
rt.channel?.activity?.record?.('dingtalk', account.accountId, 'message');
|
|
703
711
|
}
|
|
704
712
|
|
|
713
|
+
/**
|
|
714
|
+
* Extract text + media URL from a deliver payload.
|
|
715
|
+
* The Clawdbot platform may send media URLs in separate fields (e.g. from the `message` tool).
|
|
716
|
+
* We merge them into the text as markdown image syntax so DingTalk can render them.
|
|
717
|
+
*/
|
|
718
|
+
function resolveDeliverText(payload: any, log?: any): string | undefined {
|
|
719
|
+
// payload.markdown may be a boolean flag (not the actual text), so check type
|
|
720
|
+
let text = (typeof payload.markdown === 'string' && payload.markdown) || payload.text;
|
|
721
|
+
|
|
722
|
+
// Guard: ensure text is a string (platform might send unexpected types)
|
|
723
|
+
if (text != null && typeof text !== 'string') {
|
|
724
|
+
log?.info?.("[dingtalk] Deliver payload has non-string text type=" + typeof text + ", payload keys=" + Object.keys(payload).join(','));
|
|
725
|
+
text = String(text);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
const mediaUrl = payload.mediaUrl || payload.media || payload.imageUrl || payload.image;
|
|
729
|
+
|
|
730
|
+
if (mediaUrl && typeof mediaUrl === 'string' && mediaUrl.startsWith('http')) {
|
|
731
|
+
log?.info?.("[dingtalk] Deliver payload includes media URL: " + mediaUrl);
|
|
732
|
+
const imageMarkdown = ``;
|
|
733
|
+
text = text ? `${text}\n\n${imageMarkdown}` : imageMarkdown;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
return text || undefined;
|
|
737
|
+
}
|
|
738
|
+
|
|
705
739
|
async function deliverReply(target: any, text: string, log?: any): Promise<void> {
|
|
706
740
|
const now = Date.now();
|
|
707
741
|
const chunkLimit = 2000;
|
|
@@ -743,13 +777,17 @@ async function deliverReply(target: any, text: string, log?: any): Promise<void>
|
|
|
743
777
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
744
778
|
try {
|
|
745
779
|
log?.info?.("[dingtalk] Using sessionWebhook (attempt " + attempt + "/" + maxRetries + "), format=" + messageFormat);
|
|
746
|
-
log?.info?.("[dingtalk] Sending text: " + chunk.substring(0, 200));
|
|
780
|
+
log?.info?.("[dingtalk] Sending text (" + chunk.length + " chars): " + chunk.substring(0, 200));
|
|
781
|
+
let sendResult: { ok: boolean; errcode?: number; errmsg?: string };
|
|
747
782
|
if (isMarkdown) {
|
|
748
|
-
await sendMarkdownViaSessionWebhook(target.sessionWebhook, "Reply", chunk);
|
|
783
|
+
sendResult = await sendMarkdownViaSessionWebhook(target.sessionWebhook, "Reply", chunk);
|
|
749
784
|
} else {
|
|
750
|
-
await sendViaSessionWebhook(target.sessionWebhook, chunk);
|
|
785
|
+
sendResult = await sendViaSessionWebhook(target.sessionWebhook, chunk);
|
|
786
|
+
}
|
|
787
|
+
if (!sendResult.ok) {
|
|
788
|
+
throw new Error(`SessionWebhook rejected: errcode=${sendResult.errcode}, errmsg=${sendResult.errmsg}`);
|
|
751
789
|
}
|
|
752
|
-
log?.info?.("[dingtalk] SessionWebhook send OK");
|
|
790
|
+
log?.info?.("[dingtalk] SessionWebhook send OK (errcode=" + (sendResult.errcode ?? 0) + ")");
|
|
753
791
|
webhookSuccess = true;
|
|
754
792
|
break;
|
|
755
793
|
} catch (err) {
|