@jeik/dingtalk-connector 0.8.27 → 0.8.29
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/CHANGELOG.md +48 -0
- package/README.en.md +40 -82
- package/README.md +50 -93
- package/dist/background-work-DkaSDqWk.mjs +53 -0
- package/dist/card-content-cache-C7-XHhHw.mjs +2 -0
- package/dist/{card-content-cache-CYUzCaQJ.mjs → card-content-cache-DT_OYThh.mjs} +15 -1
- package/dist/chunk-upload-BKM1y4Ba.mjs +2 -0
- package/dist/{chunk-upload-BBQgGtcZ.mjs → chunk-upload-CIU5G_ay.mjs} +1 -1
- package/dist/{common-DE0gd0Jg.mjs → common-BfIYs1yC.mjs} +3 -3
- package/dist/{common-B_A78n8u.mjs → common-C0Oaf0z-.mjs} +1 -1
- package/dist/connection-obtrPkj4.mjs +641 -0
- package/dist/entry-bundled.mjs +1 -1
- package/dist/{gateway-methods--aKsyMs-.mjs → gateway-methods-BdcpfxEZ.mjs} +1 -1
- package/dist/gateway-methods-DQ6TwOAr.mjs +2 -0
- package/dist/index.mjs +2 -2
- package/dist/{logger-mZ9OSbmD.mjs → logger-CnBTcwyq.mjs} +16 -2
- package/dist/logger-D8H2IcYz.mjs +2 -0
- package/dist/{media-BqpUGCni.mjs → media-DDtX37T2.mjs} +1 -1
- package/dist/{media-DnQB2BrL.mjs → media-g8tJtpfU.mjs} +29 -20
- package/dist/{message-handler-DQZiKx3i.mjs → message-handler-BrO2i7tg.mjs} +251 -139
- package/dist/{messaging-WleKf54h.mjs → messaging-CK0Wz3Ze.mjs} +23 -21
- package/dist/{runtime-DzZo6Gvk.mjs → runtime-DbqGRyhI.mjs} +6 -5
- package/dist/{utils-Bjh4r_qS.mjs → utils-Bwz2Fls_.mjs} +1 -1
- package/docs/RELEASE_NOTES_V0.8.28.md +56 -0
- package/docs/RELEASE_NOTES_V0.8.29.md +57 -0
- package/openclaw.plugin.json +9 -5
- package/package.json +2 -2
- package/src/config/schema.ts +2 -1
- package/src/core/connection.ts +504 -220
- package/src/core/message-handler.ts +197 -102
- package/src/reply-dispatcher.ts +244 -93
- package/src/services/media.ts +60 -27
- package/src/services/messaging/card-content-cache.ts +11 -6
- package/src/services/messaging/card.ts +2 -0
- package/src/services/messaging.ts +52 -38
- package/src/utils/background-work.ts +65 -0
- package/src/utils/logger.ts +23 -2
- package/dist/card-content-cache-Dwd8HICP.mjs +0 -2
- package/dist/chunk-upload-DaLXXZH3.mjs +0 -2
- package/dist/connection-fc6B4z4G.mjs +0 -423
- package/dist/gateway-methods-BQd4E0Sk.mjs +0 -2
- package/dist/logger-BmJkQkm1.mjs +0 -2
- /package/dist/{game-xiyou-CAT0ilSj.mjs → game-xiyou-uwsv23AC.mjs} +0 -0
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
//#region src/utils/logger.ts
|
|
2
2
|
/**
|
|
3
3
|
* 日志工具模块
|
|
4
|
-
*
|
|
4
|
+
* 根据配置里的 debug 控制日志输出(无需环境变量)
|
|
5
5
|
*/
|
|
6
|
+
/** 任一账号/连接开启过 debug 后为 true;默认静默 */
|
|
7
|
+
let pluginDebugEnabled = false;
|
|
8
|
+
/**
|
|
9
|
+
* 设置插件全局 debug(由配置 `debug: true` 驱动)
|
|
10
|
+
* 仅在 true 时打开;避免多账号中未开 debug 的账号把开关关掉。
|
|
11
|
+
*/
|
|
12
|
+
function setDingtalkDebug(enabled) {
|
|
13
|
+
if (enabled) pluginDebugEnabled = true;
|
|
14
|
+
}
|
|
15
|
+
/** 是否输出图片/引用/队列等详细诊断日志 */
|
|
16
|
+
function isDingtalkDebug() {
|
|
17
|
+
return pluginDebugEnabled;
|
|
18
|
+
}
|
|
6
19
|
/**
|
|
7
20
|
* 创建日志记录器
|
|
8
21
|
* @param debug - 是否启用 debug 模式
|
|
@@ -10,6 +23,7 @@
|
|
|
10
23
|
* @returns 日志记录器对象
|
|
11
24
|
*/
|
|
12
25
|
function createLogger(debug = false, prefix = "") {
|
|
26
|
+
if (debug) setDingtalkDebug(true);
|
|
13
27
|
return {
|
|
14
28
|
/**
|
|
15
29
|
* 打印 info 级别日志
|
|
@@ -55,4 +69,4 @@ function createLoggerFromConfig(config, prefix = "") {
|
|
|
55
69
|
return createLogger(!!config?.debug, prefix);
|
|
56
70
|
}
|
|
57
71
|
//#endregion
|
|
58
|
-
export { createLoggerFromConfig as n, createLogger as t };
|
|
72
|
+
export { setDingtalkDebug as i, createLoggerFromConfig as n, isDingtalkDebug as r, createLogger as t };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as toLocalPath, d as processLocalImages, f as processRawMediaPaths, h as sendFileProactive, o as hasResidualLocalMdImagesOutsideCode, p as processVideoMarkers } from "./media-
|
|
1
|
+
import { _ as toLocalPath, d as processLocalImages, f as processRawMediaPaths, h as sendFileProactive, o as hasResidualLocalMdImagesOutsideCode, p as processVideoMarkers } from "./media-g8tJtpfU.mjs";
|
|
2
2
|
export { hasResidualLocalMdImagesOutsideCode, processLocalImages, processRawMediaPaths, processVideoMarkers, sendFileProactive, toLocalPath };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { r as isDingtalkDebug } from "./logger-CnBTcwyq.mjs";
|
|
1
2
|
import { n as dingtalkOapiHttp, t as dingtalkHttp } from "./http-client-DFWZgO1n.mjs";
|
|
2
3
|
import { n as DINGTALK_OAPI } from "./utils-CIfI_3Jh.mjs";
|
|
3
4
|
import { createRequire } from "node:module";
|
|
@@ -76,9 +77,8 @@ function toLocalPath(raw) {
|
|
|
76
77
|
return filePath;
|
|
77
78
|
}
|
|
78
79
|
/**
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* 决策路径(匹配/exists/上传成败/残留)务必 always-on,方便查灰图。
|
|
80
|
+
* 本地图诊断日志。
|
|
81
|
+
* 默认静默:无图/空扫描不再刷屏。仅在上传/失败/灰图风险,或 debug: true 时输出。
|
|
82
82
|
*/
|
|
83
83
|
function logLocalImage(log, step, detail, verbose = false) {
|
|
84
84
|
const line = detail ? `[DingTalk][LocalImage] ${step} | ${detail}` : `[DingTalk][LocalImage] ${step}`;
|
|
@@ -88,6 +88,12 @@ function logLocalImage(log, step, detail, verbose = false) {
|
|
|
88
88
|
} catch {}
|
|
89
89
|
return;
|
|
90
90
|
}
|
|
91
|
+
if (!(isDingtalkDebug() || /失败|灰图|残留|上传成功|上传失败|下载成功|下载失败|重试|remote|Remote/i.test(`${step} ${detail || ""}`))) {
|
|
92
|
+
try {
|
|
93
|
+
log?.debug?.(line);
|
|
94
|
+
} catch {}
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
91
97
|
console.log(line);
|
|
92
98
|
}
|
|
93
99
|
/** 钉钉 mediaId 形态(oapi 返回常带 @) */
|
|
@@ -117,7 +123,7 @@ function logMediaIdTrace(stage, content, extra, force = false) {
|
|
|
117
123
|
const residualLocal = mdTargets.filter((t) => isLocalImageRef(t));
|
|
118
124
|
const httpCount = (text.match(/https?:\/\//gi) || []).length;
|
|
119
125
|
const suspiciousBare = /type=image|sampleImage|photoURL/i.test(`${stage} ${extra || ""}`) ? [] : bareIds;
|
|
120
|
-
if (!(force || suspiciousBare.length > 0 || residualLocal.length > 0
|
|
126
|
+
if (!(force || isDingtalkDebug() || suspiciousBare.length > 0 || residualLocal.length > 0)) return;
|
|
121
127
|
const preview = text.replace(/\n/g, "\\n").slice(0, 200);
|
|
122
128
|
console.log(`[DingTalk][MediaIdTrace] ${stage} | len=${text.length} mediaIdCount=${ids.length}` + (ids.length ? ` ids=[${ids.slice(0, 4).join(",")}]` : "") + ` BARE_ids=${suspiciousBare.length ? suspiciousBare.join(",") : "无"} mdImgs=[${mdImgs.length ? mdImgs.join(" || ") : "-"}] httpCount=${httpCount}` + (residualLocal.length ? ` residualLocal=${residualLocal.length}:${residualLocal.slice(0, 3).map((p) => p.slice(0, 80)).join("|")}` : " residualLocal=0") + (extra ? ` ${extra}` : "") + ` preview="${preview}"`);
|
|
123
129
|
}
|
|
@@ -277,7 +283,7 @@ async function downloadRemoteUrlToTemp(url) {
|
|
|
277
283
|
}
|
|
278
284
|
const tmp = path.join(os.tmpdir(), `dingtalk-md-remote-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}`);
|
|
279
285
|
fs.writeFileSync(tmp, buf);
|
|
280
|
-
console.log(`[DingTalk][MediaIdTrace] 远程图下载成功 | bytes=${buf.length} tmp=${tmp}`);
|
|
286
|
+
if (isDingtalkDebug()) console.log(`[DingTalk][MediaIdTrace] 远程图下载成功 | bytes=${buf.length} tmp=${tmp}`);
|
|
281
287
|
return tmp;
|
|
282
288
|
} catch (e) {
|
|
283
289
|
console.warn(`[DingTalk][MediaIdTrace] 远程图下载异常 | ${e?.message || e}`);
|
|
@@ -312,27 +318,29 @@ function replaceOutsideImageTargets(content, original, replacement) {
|
|
|
312
318
|
* - 本地:正文重复的本地路径换成 down.dingtalk.com 可点链接(仍同一条消息)
|
|
313
319
|
* - **不再拆第二条 text 消息**
|
|
314
320
|
*
|
|
315
|
-
*
|
|
316
|
-
* -
|
|
321
|
+
* 日志约定(默认静默;配置 debug: true 全量):
|
|
322
|
+
* - 有图上传/失败/灰图残留才 console;无图路径不刷屏
|
|
317
323
|
*/
|
|
318
324
|
async function processImagesForOutbound(content, oapiToken, log) {
|
|
319
325
|
logLocalImage(log, "processImagesForOutbound 开始", `contentLen=${content?.length ?? 0} hasToken=${!!oapiToken}`);
|
|
320
326
|
if (!oapiToken) {
|
|
321
|
-
|
|
322
|
-
|
|
327
|
+
if (/!\[[^\]]*\]\([^)]+\)/.test(content || "")) {
|
|
328
|
+
logLocalImage(log, "processImagesForOutbound 跳过", "无 oapiToken(本地路径无法上传→必灰图)");
|
|
329
|
+
logMediaIdTrace("processImagesForOutbound:skip-no-token", content);
|
|
330
|
+
}
|
|
323
331
|
return {
|
|
324
332
|
text: content || "",
|
|
325
333
|
followUpUrls: []
|
|
326
334
|
};
|
|
327
335
|
}
|
|
328
336
|
if (!content || typeof content !== "string") {
|
|
329
|
-
logLocalImage(log, "processImagesForOutbound 跳过", "content 为空");
|
|
337
|
+
logLocalImage(log, "processImagesForOutbound 跳过", "content 为空", true);
|
|
330
338
|
return {
|
|
331
339
|
text: content || "",
|
|
332
340
|
followUpUrls: []
|
|
333
341
|
};
|
|
334
342
|
}
|
|
335
|
-
logMediaIdTrace("processImagesForOutbound:in", content
|
|
343
|
+
logMediaIdTrace("processImagesForOutbound:in", content);
|
|
336
344
|
const codeRanges = getMarkdownCodeRanges(content);
|
|
337
345
|
if (codeRanges.length > 0) logLocalImage(log, "processImagesForOutbound 代码区域", `count=${codeRanges.length}(围栏/行内 code 内的图路径将跳过)`);
|
|
338
346
|
const mdMatches = [...content.matchAll(LOCAL_IMAGE_RE)];
|
|
@@ -435,9 +443,10 @@ async function processImagesForOutbound(content, oapiToken, log) {
|
|
|
435
443
|
if (m.index !== void 0 && isIndexInCodeRange(m.index, getMarkdownCodeRanges(result))) return false;
|
|
436
444
|
return isLocalImageRef((m[2] || "").trim());
|
|
437
445
|
}).map((m) => (m[2] || "").trim());
|
|
438
|
-
logLocalImage(log, "processImagesForOutbound 完成", `uploads=${uploadCount} localTried=${localTried} remoteTried=${remoteTried} skippedCode=${skippedCode} skippedOther=${skippedOther} outLen=${result.length}` + (residual.length ? ` ⚠️residualLocal=${residual.length}:${residual.slice(0, 3).join("|")}` : " residualLocal=0"));
|
|
446
|
+
if (uploadCount > 0 || localTried > 0 || remoteTried > 0 || residual.length > 0) logLocalImage(log, residual.length ? "processImagesForOutbound 完成(有残留)" : "processImagesForOutbound 上传成功", `uploads=${uploadCount} localTried=${localTried} remoteTried=${remoteTried} skippedCode=${skippedCode} skippedOther=${skippedOther} outLen=${result.length}` + (residual.length ? ` ⚠️residualLocal=${residual.length}:${residual.slice(0, 3).join("|")}` : " residualLocal=0"));
|
|
447
|
+
else logLocalImage(log, "processImagesForOutbound 完成", `uploads=0 outLen=${result.length}`, true);
|
|
439
448
|
if (residual.length) logLocalImage(log, "processImagesForOutbound ⚠️仍有代码块外本地路径未替换(钉钉必灰图)", residual.join(" | "));
|
|
440
|
-
logMediaIdTrace("processImagesForOutbound:out", result
|
|
449
|
+
logMediaIdTrace("processImagesForOutbound:out", result);
|
|
441
450
|
return {
|
|
442
451
|
text: result,
|
|
443
452
|
followUpUrls: []
|
|
@@ -658,7 +667,7 @@ async function extractAudioDuration(filePath, log) {
|
|
|
658
667
|
*/
|
|
659
668
|
async function sendVideoMessage(config, sessionWebhook, fileName, mediaId, log, metadata) {
|
|
660
669
|
try {
|
|
661
|
-
const token = await (await import("./utils-
|
|
670
|
+
const token = await (await import("./utils-Bwz2Fls_.mjs")).getAccessToken(config);
|
|
662
671
|
const videoMessage = {
|
|
663
672
|
msgtype: "video",
|
|
664
673
|
video: {
|
|
@@ -686,8 +695,8 @@ async function sendVideoMessage(config, sessionWebhook, fileName, mediaId, log,
|
|
|
686
695
|
*/
|
|
687
696
|
async function sendVideoProactive(config, target, videoMediaId, picMediaId, metadata, log) {
|
|
688
697
|
try {
|
|
689
|
-
const token = await (await import("./utils-
|
|
690
|
-
const { DINGTALK_API } = await import("./utils-
|
|
698
|
+
const token = await (await import("./utils-Bwz2Fls_.mjs")).getAccessToken(config);
|
|
699
|
+
const { DINGTALK_API } = await import("./utils-Bwz2Fls_.mjs");
|
|
691
700
|
const msgParam = {
|
|
692
701
|
duration: metadata?.duration.toString() || "60000",
|
|
693
702
|
videoMediaId,
|
|
@@ -732,8 +741,8 @@ async function sendVideoProactive(config, target, videoMediaId, picMediaId, meta
|
|
|
732
741
|
*/
|
|
733
742
|
async function sendAudioProactive(config, target, fileName, mediaId, log, durationMs) {
|
|
734
743
|
try {
|
|
735
|
-
const token = await (await import("./utils-
|
|
736
|
-
const { DINGTALK_API } = await import("./utils-
|
|
744
|
+
const token = await (await import("./utils-Bwz2Fls_.mjs")).getAccessToken(config);
|
|
745
|
+
const { DINGTALK_API } = await import("./utils-Bwz2Fls_.mjs");
|
|
737
746
|
const msgParam = {
|
|
738
747
|
mediaId,
|
|
739
748
|
duration: durationMs && durationMs > 0 ? durationMs.toString() : "60000"
|
|
@@ -770,8 +779,8 @@ async function sendAudioProactive(config, target, fileName, mediaId, log, durati
|
|
|
770
779
|
*/
|
|
771
780
|
async function sendFileProactive(config, target, fileInfo, mediaId, log) {
|
|
772
781
|
try {
|
|
773
|
-
const token = await (await import("./utils-
|
|
774
|
-
const { DINGTALK_API } = await import("./utils-
|
|
782
|
+
const token = await (await import("./utils-Bwz2Fls_.mjs")).getAccessToken(config);
|
|
783
|
+
const { DINGTALK_API } = await import("./utils-Bwz2Fls_.mjs");
|
|
775
784
|
const resolvedFileName = fileInfo.fileName || path.basename(fileInfo.path);
|
|
776
785
|
const msgParam = {
|
|
777
786
|
mediaId,
|