@huo15/dingtalk-connector-pro 1.0.4 → 1.0.7

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.
Files changed (142) hide show
  1. package/README.en.md +106 -384
  2. package/README.md +14 -18
  3. package/dist/index.js +17 -0
  4. package/dist/openclaw.plugin.json +498 -0
  5. package/dist/package.json +91 -0
  6. package/dist/src/channel.js +415 -0
  7. package/dist/src/config/accounts.js +182 -0
  8. package/dist/src/config/schema.js +135 -0
  9. package/dist/src/core/connection.js +561 -0
  10. package/dist/src/core/message-handler.js +1422 -0
  11. package/dist/src/core/provider.js +59 -0
  12. package/dist/src/core/state.js +49 -0
  13. package/dist/src/directory.js +53 -0
  14. package/dist/src/docs.js +209 -0
  15. package/dist/src/gateway-methods.js +360 -0
  16. package/dist/src/onboarding.js +337 -0
  17. package/dist/src/policy.js +15 -0
  18. package/dist/src/probe.js +144 -0
  19. package/dist/src/reply-dispatcher.js +435 -0
  20. package/dist/src/runtime.js +26 -0
  21. package/dist/src/sdk/helpers.js +237 -0
  22. package/dist/src/sdk/types.js +13 -0
  23. package/dist/src/secret-input.js +13 -0
  24. package/dist/src/services/media/audio.js +40 -0
  25. package/dist/src/services/media/chunk-upload.js +211 -0
  26. package/dist/src/services/media/common.js +120 -0
  27. package/dist/src/services/media/file.js +54 -0
  28. package/dist/src/services/media/image.js +59 -0
  29. package/dist/src/services/media/index.js +9 -0
  30. package/dist/src/services/media/video.js +133 -0
  31. package/dist/src/services/media.js +889 -0
  32. package/dist/src/services/messaging/card.js +234 -0
  33. package/dist/src/services/messaging/index.js +8 -0
  34. package/dist/src/services/messaging/send.js +85 -0
  35. package/dist/src/services/messaging.js +680 -0
  36. package/dist/src/targets.js +38 -0
  37. package/dist/src/types/index.js +1 -0
  38. package/dist/src/utils/agent.js +55 -0
  39. package/dist/src/utils/async.js +40 -0
  40. package/dist/src/utils/constants.js +24 -0
  41. package/dist/src/utils/http-client.js +33 -0
  42. package/dist/src/utils/index.js +7 -0
  43. package/dist/src/utils/logger.js +76 -0
  44. package/dist/src/utils/session.js +95 -0
  45. package/dist/src/utils/token.js +71 -0
  46. package/dist/src/utils/utils-legacy.js +393 -0
  47. package/index.ts +3 -3
  48. package/openclaw.plugin.json +1 -1
  49. package/package.json +16 -5
  50. package/src/channel.js +415 -0
  51. package/src/channel.ts +12 -12
  52. package/src/config/accounts.js +182 -0
  53. package/src/config/accounts.ts +2 -2
  54. package/src/config/schema.js +135 -0
  55. package/src/config/schema.ts +2 -2
  56. package/src/core/connection.js +561 -0
  57. package/src/core/connection.ts +2 -2
  58. package/src/core/message-handler.js +1422 -0
  59. package/src/core/message-handler.ts +12 -12
  60. package/src/core/provider.js +59 -0
  61. package/src/core/provider.ts +4 -4
  62. package/src/core/state.js +49 -0
  63. package/src/directory.js +53 -0
  64. package/src/directory.ts +2 -2
  65. package/src/docs.js +209 -0
  66. package/src/docs.ts +3 -3
  67. package/src/gateway-methods.js +360 -0
  68. package/src/gateway-methods.ts +5 -5
  69. package/src/onboarding.js +337 -0
  70. package/src/onboarding.ts +4 -4
  71. package/src/policy.js +15 -0
  72. package/src/policy.ts +1 -1
  73. package/src/probe.js +144 -0
  74. package/src/probe.ts +2 -2
  75. package/src/reply-dispatcher.js +435 -0
  76. package/src/reply-dispatcher.ts +9 -9
  77. package/src/runtime.js +26 -0
  78. package/src/sdk/helpers.js +237 -0
  79. package/src/sdk/helpers.ts +1 -1
  80. package/src/sdk/types.js +13 -0
  81. package/src/secret-input.js +13 -0
  82. package/src/secret-input.ts +1 -1
  83. package/src/services/media/audio.js +40 -0
  84. package/src/services/media/audio.ts +2 -2
  85. package/src/services/media/chunk-upload.js +211 -0
  86. package/src/services/media/chunk-upload.ts +2 -2
  87. package/src/services/media/common.js +120 -0
  88. package/src/services/media/common.ts +3 -3
  89. package/src/services/media/file.js +54 -0
  90. package/src/services/media/file.ts +2 -2
  91. package/src/services/media/image.js +59 -0
  92. package/src/services/media/image.ts +2 -2
  93. package/src/services/media/index.js +9 -0
  94. package/src/services/media/index.ts +6 -6
  95. package/src/services/media/video.js +133 -0
  96. package/src/services/media/video.ts +2 -2
  97. package/src/services/media.js +889 -0
  98. package/src/services/media.ts +12 -12
  99. package/src/services/messaging/card.js +234 -0
  100. package/src/services/messaging/card.ts +3 -3
  101. package/src/services/messaging/index.js +8 -0
  102. package/src/services/messaging/index.ts +3 -3
  103. package/src/services/messaging/send.js +85 -0
  104. package/src/services/messaging/send.ts +3 -3
  105. package/src/services/messaging.js +680 -0
  106. package/src/services/messaging.ts +8 -8
  107. package/src/targets.js +38 -0
  108. package/src/targets.ts +1 -1
  109. package/src/types/index.js +1 -0
  110. package/src/types/index.ts +1 -1
  111. package/src/utils/agent.js +55 -0
  112. package/src/utils/async.js +40 -0
  113. package/src/utils/constants.js +24 -0
  114. package/src/utils/http-client.js +33 -0
  115. package/src/utils/http-client.ts +1 -1
  116. package/src/utils/index.js +7 -0
  117. package/src/utils/index.ts +4 -4
  118. package/src/utils/logger.js +76 -0
  119. package/src/utils/session.js +95 -0
  120. package/src/utils/session.ts +1 -1
  121. package/src/utils/token.js +71 -0
  122. package/src/utils/token.ts +2 -2
  123. package/src/utils/utils-legacy.js +393 -0
  124. package/src/utils/utils-legacy.ts +8 -8
  125. package/CHANGELOG.md +0 -485
  126. package/SKILL.md +0 -40
  127. package/_meta.json +0 -4
  128. package/docs/AGENT_ROUTING.md +0 -335
  129. package/docs/DEAP_AGENT_GUIDE.en.md +0 -115
  130. package/docs/DEAP_AGENT_GUIDE.md +0 -115
  131. package/docs/images/dingtalk.svg +0 -1
  132. package/docs/images/image-1.png +0 -0
  133. package/docs/images/image-2.png +0 -0
  134. package/docs/images/image-3.png +0 -0
  135. package/docs/images/image-4.png +0 -0
  136. package/docs/images/image-5.png +0 -0
  137. package/docs/images/image-6.png +0 -0
  138. package/docs/images/image-7.png +0 -0
  139. package/install-beta.sh +0 -438
  140. package/install-npm.sh +0 -167
  141. package/src/hooks/init.ts +0 -16
  142. package/tsconfig.json +0 -20
@@ -8,9 +8,9 @@ import * as path from 'path';
8
8
  // form-data 是 CJS 模块,静态 import 可确保 jiti/ESM 环境下 CJS 互操作行为稳定,
9
9
  // 避免动态 import 时 .default 偶发为 undefined 导致 "Cannot read properties of undefined (reading 'registry')"
10
10
  import FormData from 'form-data';
11
- import type { DingtalkConfig } from '../types/index.ts';
12
- import { DINGTALK_OAPI, getOapiAccessToken } from '../utils/index.ts';
13
- import { dingtalkHttp, dingtalkOapiHttp } from '../utils/http-client.ts';
11
+ import type { DingtalkConfig } from '../types/index.js';
12
+ import { DINGTALK_OAPI, getOapiAccessToken } from '../utils/index.js';
13
+ import { dingtalkHttp, dingtalkOapiHttp } from '../utils/http-client.js';
14
14
 
15
15
 
16
16
  /** 文本文件扩展名 */
@@ -716,7 +716,7 @@ async function sendVideoMessage(
716
716
  metadata?: { duration: number; width: number; height: number },
717
717
  ): Promise<void> {
718
718
  try {
719
- const token = await (await import('../utils/index.ts')).getAccessToken(config);
719
+ const token = await (await import('../utils/index.js')).getAccessToken(config);
720
720
 
721
721
  // 钉钉视频消息格式(sessionWebhook 模式)
722
722
  const videoMessage = {
@@ -759,8 +759,8 @@ export async function sendVideoProactive(
759
759
  log?: any,
760
760
  ): Promise<void> {
761
761
  try {
762
- const token = await (await import('../utils/index.ts')).getAccessToken(config);
763
- const { DINGTALK_API } = await import('../utils/index.ts');
762
+ const token = await (await import('../utils/index.js')).getAccessToken(config);
763
+ const { DINGTALK_API } = await import('../utils/index.js');
764
764
 
765
765
  // 钉钉普通消息 API 的视频消息格式
766
766
  const msgParam = {
@@ -819,7 +819,7 @@ async function sendAudioMessage(
819
819
  durationMs?: number,
820
820
  ): Promise<void> {
821
821
  try {
822
- const token = await (await import('../utils/index.ts')).getAccessToken(config);
822
+ const token = await (await import('../utils/index.js')).getAccessToken(config);
823
823
 
824
824
  // 钉钉语音消息格式
825
825
  const actualDuration = (durationMs && durationMs > 0) ? durationMs.toString() : '60000';
@@ -862,8 +862,8 @@ export async function sendAudioProactive(
862
862
  durationMs?: number,
863
863
  ): Promise<void> {
864
864
  try {
865
- const token = await (await import('../utils/index.ts')).getAccessToken(config);
866
- const { DINGTALK_API } = await import('../utils/index.ts');
865
+ const token = await (await import('../utils/index.js')).getAccessToken(config);
866
+ const { DINGTALK_API } = await import('../utils/index.js');
867
867
 
868
868
  // 钉钉普通消息 API 的音频消息格式
869
869
  const actualDuration = (durationMs && durationMs > 0) ? durationMs.toString() : '60000';
@@ -915,7 +915,7 @@ async function sendFileMessage(
915
915
  log?: any,
916
916
  ): Promise<void> {
917
917
  try {
918
- const token = await (await import('../utils/index.ts')).getAccessToken(config);
918
+ const token = await (await import('../utils/index.js')).getAccessToken(config);
919
919
 
920
920
  const fileMessage = {
921
921
  msgtype: 'file',
@@ -956,8 +956,8 @@ export async function sendFileProactive(
956
956
  log?: any,
957
957
  ): Promise<void> {
958
958
  try {
959
- const token = await (await import('../utils/index.ts')).getAccessToken(config);
960
- const { DINGTALK_API } = await import('../utils/index.ts');
959
+ const token = await (await import('../utils/index.js')).getAccessToken(config);
960
+ const { DINGTALK_API } = await import('../utils/index.js');
961
961
 
962
962
  // 钉钉普通消息 API 的文件消息格式
963
963
  const msgParam = {
@@ -0,0 +1,234 @@
1
+ /**
2
+ * AI Card 流式响应模块
3
+ * 支持 AI Card 创建、流式更新、完成
4
+ */
5
+ import { DINGTALK_API, getAccessToken } from "../../utils/token.js";
6
+ import { dingtalkHttp } from "../../utils/http-client.js";
7
+ // ============ 常量 ============
8
+ const AI_CARD_TEMPLATE_ID = "02fcf2f4-5e02-4a85-b672-46d1f715543e.schema";
9
+ /** AI Card 状态 */
10
+ const AICardStatus = {
11
+ PROCESSING: "1",
12
+ INPUTING: "2",
13
+ FINISHED: "3",
14
+ EXECUTING: "4",
15
+ FAILED: "5",
16
+ };
17
+ // ============ Markdown 格式修正 ============
18
+ /**
19
+ * 确保 Markdown 表格前有空行,否则钉钉无法正确渲染表格
20
+ */
21
+ function ensureTableBlankLines(text) {
22
+ const lines = text.split("\n");
23
+ const result = [];
24
+ const tableDividerRegex = /^\s*\|?\s*:?-+:?\s*(\|?\s*:?-+:?\s*)+\|?\s*$/;
25
+ const tableRowRegex = /^\s*\|?.*\|.*\|?\s*$/;
26
+ const isDivider = (line) => line &&
27
+ typeof line === "string" &&
28
+ line.includes("|") &&
29
+ tableDividerRegex.test(line);
30
+ for (let i = 0; i < lines.length; i++) {
31
+ const currentLine = lines[i];
32
+ const nextLine = lines[i + 1] ?? "";
33
+ if (tableRowRegex.test(currentLine) &&
34
+ isDivider(nextLine) &&
35
+ i > 0 &&
36
+ lines[i - 1].trim() !== "" &&
37
+ !tableRowRegex.test(lines[i - 1])) {
38
+ result.push("");
39
+ }
40
+ result.push(currentLine);
41
+ }
42
+ return result.join("\n");
43
+ }
44
+ // ============ AI Card 相关 ============
45
+ /**
46
+ * 构建卡片投放请求体
47
+ */
48
+ export function buildDeliverBody(cardInstanceId, target, robotCode) {
49
+ const base = { outTrackId: cardInstanceId, userIdType: 1 };
50
+ if (target.type === "group") {
51
+ return {
52
+ ...base,
53
+ openSpaceId: `dtv1.card//IM_GROUP.${target.openConversationId}`,
54
+ imGroupOpenDeliverModel: {
55
+ robotCode,
56
+ },
57
+ };
58
+ }
59
+ return {
60
+ ...base,
61
+ openSpaceId: `dtv1.card//IM_ROBOT.${target.userId}`,
62
+ imRobotOpenDeliverModel: {
63
+ spaceType: 'IM_ROBOT',
64
+ robotCode,
65
+ extension: {
66
+ dynamicSummary: 'true',
67
+ },
68
+ },
69
+ };
70
+ }
71
+ /**
72
+ * 通用 AI Card 创建函数
73
+ */
74
+ export async function createAICardForTarget(config, target, log) {
75
+ const targetDesc = target.type === "group"
76
+ ? `群聊 ${target.openConversationId}`
77
+ : `用户 ${target.userId}`;
78
+ try {
79
+ const token = await getAccessToken(config);
80
+ const cardInstanceId = `card_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
81
+ log?.info?.(`[DingTalk][AICard] 开始创建卡片:${targetDesc}, outTrackId=${cardInstanceId}`);
82
+ // 1. 创建卡片实例
83
+ const createBody = {
84
+ cardTemplateId: AI_CARD_TEMPLATE_ID,
85
+ outTrackId: cardInstanceId,
86
+ cardData: {
87
+ cardParamMap: {
88
+ config: JSON.stringify({ autoLayout: true }),
89
+ }
90
+ },
91
+ callbackType: "STREAM",
92
+ imGroupOpenSpaceModel: { supportForward: true },
93
+ imRobotOpenSpaceModel: { supportForward: true },
94
+ };
95
+ const createResp = await dingtalkHttp.post(`${DINGTALK_API}/v1.0/card/instances`, createBody, {
96
+ headers: {
97
+ "x-acs-dingtalk-access-token": token,
98
+ "Content-Type": "application/json",
99
+ },
100
+ });
101
+ // 2. 投放卡片
102
+ const deliverBody = buildDeliverBody(cardInstanceId, target, String(config.clientId ?? ""));
103
+ const deliverResp = await dingtalkHttp.post(`${DINGTALK_API}/v1.0/card/instances/deliver`, deliverBody, {
104
+ headers: {
105
+ "x-acs-dingtalk-access-token": token,
106
+ "Content-Type": "application/json",
107
+ },
108
+ });
109
+ // 记录 token 过期时间(钉钉 token 有效期 2 小时)
110
+ const tokenExpireTime = Date.now() + 2 * 60 * 60 * 1000;
111
+ return { cardInstanceId, accessToken: token, tokenExpireTime, inputingStarted: false };
112
+ }
113
+ catch (err) {
114
+ log?.error?.(`[DingTalk][AICard] 创建卡片失败 (${targetDesc}): ${err.message}`);
115
+ if (err.response) {
116
+ log?.error?.(`[DingTalk][AICard] 错误响应:status=${err.response.status}`);
117
+ }
118
+ return null;
119
+ }
120
+ }
121
+ /**
122
+ * 确保 Token 有效(自动刷新过期的 Token)
123
+ */
124
+ async function ensureValidToken(card, config) {
125
+ // 如果 token 即将过期(提前 5 分钟刷新)
126
+ if (Date.now() > card.tokenExpireTime - 5 * 60 * 1000) {
127
+ const newToken = await getAccessToken(config);
128
+ card.accessToken = newToken;
129
+ card.tokenExpireTime = Date.now() + 2 * 60 * 60 * 1000;
130
+ }
131
+ return card.accessToken;
132
+ }
133
+ /**
134
+ * 流式更新 AI Card 内容
135
+ */
136
+ export async function streamAICard(card, content, finished = false, config, log) {
137
+ // 确保 token 有效
138
+ if (config) {
139
+ await ensureValidToken(card, config);
140
+ }
141
+ if (!card.inputingStarted) {
142
+ const statusBody = {
143
+ outTrackId: card.cardInstanceId,
144
+ cardData: {
145
+ cardParamMap: {
146
+ flowStatus: AICardStatus.INPUTING,
147
+ msgContent: content,
148
+ staticMsgContent: "",
149
+ sys_full_json_obj: JSON.stringify({
150
+ order: ["msgContent"],
151
+ }),
152
+ config: JSON.stringify({ autoLayout: true }),
153
+ },
154
+ },
155
+ };
156
+ try {
157
+ const statusResp = await dingtalkHttp.put(`${DINGTALK_API}/v1.0/card/instances`, statusBody, {
158
+ headers: {
159
+ "x-acs-dingtalk-access-token": card.accessToken,
160
+ "Content-Type": "application/json",
161
+ },
162
+ });
163
+ log?.info?.(`[DingTalk][AICard] INPUTING 响应:status=${statusResp.status}`);
164
+ }
165
+ catch (err) {
166
+ log?.error?.(`[DingTalk][AICard] INPUTING 切换失败:${err.message}`);
167
+ throw err;
168
+ }
169
+ card.inputingStarted = true;
170
+ }
171
+ const fixedContent = ensureTableBlankLines(content);
172
+ const body = {
173
+ outTrackId: card.cardInstanceId,
174
+ guid: `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
175
+ key: "msgContent",
176
+ content: fixedContent,
177
+ isFull: true,
178
+ isFinalize: finished,
179
+ isError: false,
180
+ };
181
+ log?.info?.(`[DingTalk][AICard] PUT /v1.0/card/streaming contentLen=${content.length} isFinalize=${finished}`);
182
+ try {
183
+ const streamResp = await dingtalkHttp.put(`${DINGTALK_API}/v1.0/card/streaming`, body, {
184
+ headers: {
185
+ "x-acs-dingtalk-access-token": card.accessToken,
186
+ "Content-Type": "application/json",
187
+ },
188
+ });
189
+ log?.info?.(`[DingTalk][AICard] streaming 响应:status=${streamResp.status}`);
190
+ }
191
+ catch (err) {
192
+ log?.error?.(`[DingTalk][AICard] streaming 更新失败:${err.message}`);
193
+ throw err;
194
+ }
195
+ }
196
+ /**
197
+ * 完成 AI Card
198
+ */
199
+ export async function finishAICard(card, content, config, log) {
200
+ // 确保 token 有效
201
+ if (config) {
202
+ await ensureValidToken(card, config);
203
+ }
204
+ const fixedContent = ensureTableBlankLines(content);
205
+ log?.info?.(`[DingTalk][AICard] 开始 finish,最终内容长度=${fixedContent.length}`);
206
+ await streamAICard(card, fixedContent, true, log);
207
+ const body = {
208
+ outTrackId: card.cardInstanceId,
209
+ cardData: {
210
+ cardParamMap: {
211
+ flowStatus: AICardStatus.FINISHED,
212
+ msgContent: fixedContent,
213
+ staticMsgContent: "",
214
+ sys_full_json_obj: JSON.stringify({
215
+ order: ["msgContent"],
216
+ }),
217
+ config: JSON.stringify({ autoLayout: true }),
218
+ },
219
+ },
220
+ cardUpdateOptions: { updateCardDataByKey: true },
221
+ };
222
+ try {
223
+ const finishResp = await dingtalkHttp.put(`${DINGTALK_API}/v1.0/card/instances`, body, {
224
+ headers: {
225
+ "x-acs-dingtalk-access-token": card.accessToken,
226
+ "Content-Type": "application/json",
227
+ },
228
+ });
229
+ log?.info?.(`[DingTalk][AICard] FINISHED 响应:status=${finishResp.status}`);
230
+ }
231
+ catch (err) {
232
+ log?.error?.(`[DingTalk][AICard] FINISHED 更新失败:${err.message}`);
233
+ }
234
+ }
@@ -3,9 +3,9 @@
3
3
  * 支持 AI Card 创建、流式更新、完成
4
4
  */
5
5
 
6
- import type { DingtalkConfig } from "../../types/index.ts";
7
- import { DINGTALK_API, getAccessToken } from "../../utils/token.ts";
8
- import { dingtalkHttp } from "../../utils/http-client.ts";
6
+ import type { DingtalkConfig } from "../../types/index.js";
7
+ import { DINGTALK_API, getAccessToken } from "../../utils/token.js";
8
+ import { dingtalkHttp } from "../../utils/http-client.js";
9
9
 
10
10
  // ============ 常量 ============
11
11
 
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 消息发送模块统一导出
3
+ */
4
+ export * from './send.js';
5
+ export * from './card.js';
6
+ // 兼容旧实现(`src/services/messaging.ts`)中仍被外部调用的 API。
7
+ // 注意:这里只显式导出函数,避免与 `send.ts/card.ts` 的类型/常量命名冲突。
8
+ export { sendMessage, sendProactive, sendToUser, sendToGroup, sendTextToDingTalk, sendMediaToDingTalk, } from '../messaging.js';
@@ -2,8 +2,8 @@
2
2
  * 消息发送模块统一导出
3
3
  */
4
4
 
5
- export * from './send.ts';
6
- export * from './card.ts';
5
+ export * from './send.js';
6
+ export * from './card.js';
7
7
 
8
8
  // 兼容旧实现(`src/services/messaging.ts`)中仍被外部调用的 API。
9
9
  // 注意:这里只显式导出函数,避免与 `send.ts/card.ts` 的类型/常量命名冲突。
@@ -14,4 +14,4 @@ export {
14
14
  sendToGroup,
15
15
  sendTextToDingTalk,
16
16
  sendMediaToDingTalk,
17
- } from '../messaging.ts';
17
+ } from '../messaging.js';
@@ -0,0 +1,85 @@
1
+ /**
2
+ * 消息发送基础模块
3
+ * 支持 Markdown、文本、链接等消息类型
4
+ */
5
+ import { getAccessToken } from '../../utils/token.js';
6
+ import { dingtalkHttp } from '../../utils/http-client.js';
7
+ /**
8
+ * 发送 Markdown 消息
9
+ */
10
+ export async function sendMarkdownMessage(config, sessionWebhook, title, markdown, options = {}) {
11
+ const token = await getAccessToken(config);
12
+ let text = markdown;
13
+ if (options.atUserId)
14
+ text = `${text} @${options.atUserId}`;
15
+ const body = {
16
+ msgtype: 'markdown',
17
+ markdown: {
18
+ title,
19
+ text: text,
20
+ },
21
+ };
22
+ if (options.atUserId) {
23
+ body.at = {
24
+ userIds: [options.atUserId],
25
+ isAtAll: false,
26
+ };
27
+ }
28
+ const resp = await dingtalkHttp.post(sessionWebhook, body, {
29
+ headers: {
30
+ 'x-acs-dingtalk-access-token': token,
31
+ 'Content-Type': 'application/json',
32
+ },
33
+ });
34
+ return resp.data;
35
+ }
36
+ /**
37
+ * 发送文本消息
38
+ */
39
+ export async function sendTextMessage(config, sessionWebhook, content, options = {}) {
40
+ const token = await getAccessToken(config);
41
+ let text = content;
42
+ if (options.atUserId)
43
+ text = `${text} @${options.atUserId}`;
44
+ const body = {
45
+ msgtype: 'text',
46
+ text: {
47
+ content: text,
48
+ },
49
+ };
50
+ if (options.atUserId) {
51
+ body.at = {
52
+ userIds: [options.atUserId],
53
+ isAtAll: false,
54
+ };
55
+ }
56
+ const resp = await dingtalkHttp.post(sessionWebhook, body, {
57
+ headers: {
58
+ 'x-acs-dingtalk-access-token': token,
59
+ 'Content-Type': 'application/json',
60
+ },
61
+ });
62
+ return resp.data;
63
+ }
64
+ /**
65
+ * 发送链接消息
66
+ */
67
+ export async function sendLinkMessage(config, sessionWebhook, params) {
68
+ const token = await getAccessToken(config);
69
+ const body = {
70
+ msgtype: 'link',
71
+ link: {
72
+ title: params.title,
73
+ text: params.text,
74
+ picUrl: params.picUrl,
75
+ messageUrl: params.messageUrl,
76
+ },
77
+ };
78
+ const resp = await dingtalkHttp.post(sessionWebhook, body, {
79
+ headers: {
80
+ 'x-acs-dingtalk-access-token': token,
81
+ 'Content-Type': 'application/json',
82
+ },
83
+ });
84
+ return resp.data;
85
+ }
@@ -3,9 +3,9 @@
3
3
  * 支持 Markdown、文本、链接等消息类型
4
4
  */
5
5
 
6
- import type { DingtalkConfig } from '../../types/index.ts';
7
- import { DINGTALK_API, getAccessToken } from '../../utils/token.ts';
8
- import { dingtalkHttp } from '../../utils/http-client.ts';
6
+ import type { DingtalkConfig } from '../../types/index.js';
7
+ import { DINGTALK_API, getAccessToken } from '../../utils/token.js';
8
+ import { dingtalkHttp } from '../../utils/http-client.js';
9
9
 
10
10
  /** 消息类型枚举 */
11
11
  export type DingTalkMsgType = 'text' | 'markdown' | 'link' | 'actionCard' | 'image';