@zhin.js/adapter-dingtalk 4.0.2 → 4.0.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.
Files changed (65) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +58 -345
  3. package/adapters/dingtalk.ts +26 -0
  4. package/agent/tools/add_chat_members.ts +2 -2
  5. package/agent/tools/create_chat.ts +2 -2
  6. package/agent/tools/dept_info.ts +2 -2
  7. package/agent/tools/get_dept_users.ts +2 -2
  8. package/agent/tools/get_user.ts +2 -2
  9. package/agent/tools/list_departments.ts +2 -2
  10. package/agent/tools/send_work_notice.ts +2 -2
  11. package/agent/tools/update_chat.ts +2 -2
  12. package/lib/dingtalk-agent-deps.d.ts +26 -0
  13. package/lib/dingtalk-agent-deps.js +30 -0
  14. package/lib/endpoint.d.ts +55 -0
  15. package/lib/endpoint.js +312 -0
  16. package/lib/index.d.ts +5 -0
  17. package/lib/index.js +5 -0
  18. package/lib/platform-permit.d.ts +15 -0
  19. package/lib/{src/platform-permit.js → platform-permit.js} +1 -2
  20. package/lib/protocol.d.ts +121 -0
  21. package/lib/protocol.js +221 -0
  22. package/lib/webhook.d.ts +13 -0
  23. package/lib/webhook.js +48 -0
  24. package/package.json +45 -23
  25. package/plugin.ts +12 -0
  26. package/schema.json +23 -0
  27. package/src/dingtalk-agent-deps.ts +49 -9
  28. package/src/endpoint.ts +263 -479
  29. package/src/index.ts +45 -59
  30. package/src/platform-permit.ts +1 -1
  31. package/src/protocol.ts +338 -0
  32. package/src/webhook.ts +76 -0
  33. package/lib/agent/tools/add_chat_members.js +0 -21
  34. package/lib/agent/tools/add_chat_members.js.map +0 -1
  35. package/lib/agent/tools/create_chat.js +0 -22
  36. package/lib/agent/tools/create_chat.js.map +0 -1
  37. package/lib/agent/tools/dept_info.js +0 -17
  38. package/lib/agent/tools/dept_info.js.map +0 -1
  39. package/lib/agent/tools/get_dept_users.js +0 -18
  40. package/lib/agent/tools/get_dept_users.js.map +0 -1
  41. package/lib/agent/tools/get_user.js +0 -17
  42. package/lib/agent/tools/get_user.js.map +0 -1
  43. package/lib/agent/tools/list_departments.js +0 -18
  44. package/lib/agent/tools/list_departments.js.map +0 -1
  45. package/lib/agent/tools/send_work_notice.js +0 -20
  46. package/lib/agent/tools/send_work_notice.js.map +0 -1
  47. package/lib/agent/tools/update_chat.js +0 -31
  48. package/lib/agent/tools/update_chat.js.map +0 -1
  49. package/lib/src/adapter.js +0 -40
  50. package/lib/src/adapter.js.map +0 -1
  51. package/lib/src/dingtalk-agent-deps.js +0 -10
  52. package/lib/src/dingtalk-agent-deps.js.map +0 -1
  53. package/lib/src/endpoint.js +0 -547
  54. package/lib/src/endpoint.js.map +0 -1
  55. package/lib/src/index.js +0 -43
  56. package/lib/src/index.js.map +0 -1
  57. package/lib/src/platform-permit.js.map +0 -1
  58. package/lib/src/segment-mapper.js +0 -2
  59. package/lib/src/segment-mapper.js.map +0 -1
  60. package/lib/src/types.js +0 -5
  61. package/lib/src/types.js.map +0 -1
  62. package/plugin.yml +0 -3
  63. package/src/adapter.ts +0 -46
  64. package/src/segment-mapper.ts +0 -1
  65. package/src/types.ts +0 -56
@@ -0,0 +1,55 @@
1
+ /**
2
+ * DingTalkEndpoint — lifecycle, outbound, admit, OpenAPI helpers for agent tools.
3
+ */
4
+ import type { EndpointInstance } from '@zhin.js/adapter';
5
+ import type { MessageGateway } from '@zhin.js/core/runtime';
6
+ import type { HttpHost } from '@zhin.js/host-http';
7
+ import type { CapabilityId } from '@zhin.js/plugin-runtime';
8
+ import { type DingTalkEvent, type DingTalkMessage, type ResolvedDingTalkConfig } from './protocol.js';
9
+ export type DingTalkFetch = (url: string, init?: {
10
+ readonly method?: string;
11
+ readonly headers?: Record<string, string>;
12
+ readonly body?: string;
13
+ }) => Promise<{
14
+ readonly ok: boolean;
15
+ readonly status: number;
16
+ text(): Promise<string>;
17
+ json(): Promise<unknown>;
18
+ }>;
19
+ export interface DingTalkEndpointOptions {
20
+ readonly id: CapabilityId;
21
+ readonly gateway: MessageGateway;
22
+ readonly http: HttpHost;
23
+ readonly config: ResolvedDingTalkConfig;
24
+ readonly fetch?: DingTalkFetch;
25
+ }
26
+ export declare class DingTalkEndpoint implements EndpointInstance {
27
+ #private;
28
+ constructor(options: DingTalkEndpointOptions);
29
+ /** Used by webhook handler. */
30
+ get isOpen(): boolean;
31
+ get config(): ResolvedDingTalkConfig;
32
+ start(): Promise<void>;
33
+ open(): void;
34
+ close(): void;
35
+ stop(): Promise<void>;
36
+ send({ target, payload }: {
37
+ readonly target: string;
38
+ readonly payload: unknown;
39
+ }): Promise<string>;
40
+ /** Test / internal: admit a parsed event when open (non-webhook path). */
41
+ admit(event: DingTalkEvent | DingTalkMessage): void;
42
+ getUserInfo(userId: string): Promise<unknown>;
43
+ getDepartmentUsers(deptId: number): Promise<unknown[]>;
44
+ sendWorkNotice(userIdList: string[], content: unknown): Promise<boolean>;
45
+ getDepartmentList(deptId?: number): Promise<unknown[]>;
46
+ getDepartmentInfo(deptId: number): Promise<unknown>;
47
+ createChat(name: string, ownerUserId: string, userIdList: string[]): Promise<string | null>;
48
+ getChatInfo(chatId: string): Promise<unknown>;
49
+ updateChat(chatId: string, options: {
50
+ name?: string;
51
+ owner?: string;
52
+ add_useridlist?: string[];
53
+ del_useridlist?: string[];
54
+ }): Promise<boolean>;
55
+ }
@@ -0,0 +1,312 @@
1
+ import { formatCompact, getLogger } from '@zhin.js/logger';
2
+ import { registerDingtalkAgentEndpoint } from './dingtalk-agent-deps.js';
3
+ import { normalizeDingtalkSenderForPermit } from './platform-permit.js';
4
+ import { formatInboundContent, formatOutboundBody, generateMessageId, isDingtalkBotMentioned, resolveChatType, resolveSender, resolveTarget, } from './protocol.js';
5
+ import { registerDingTalkWebhookRoutes } from './webhook.js';
6
+ const logger = getLogger('dingtalk');
7
+ export class DingTalkEndpoint {
8
+ #options;
9
+ #fetch;
10
+ #routeReleases = [];
11
+ #accessToken = { token: '', expires_in: 0, timestamp: 0 };
12
+ #refreshPromise = null;
13
+ #sessionWebhooks = new Map();
14
+ #open = false;
15
+ #started = false;
16
+ #unregisterAgent;
17
+ constructor(options) {
18
+ this.#options = options;
19
+ this.#fetch = options.fetch ?? globalThis.fetch;
20
+ }
21
+ /** Used by webhook handler. */
22
+ get isOpen() {
23
+ return this.#open;
24
+ }
25
+ get config() {
26
+ return this.#options.config;
27
+ }
28
+ async start() {
29
+ if (this.#started)
30
+ return;
31
+ this.#started = true;
32
+ try {
33
+ await this.#refreshAccessToken();
34
+ this.#unregisterAgent = registerDingtalkAgentEndpoint(this.#options.config.name, this);
35
+ this.#routeReleases.push(...registerDingTalkWebhookRoutes(this.#options.http, this));
36
+ logger.debug(formatCompact({
37
+ endpoint: this.#options.config.name,
38
+ op: 'webhook',
39
+ path: this.#options.config.webhookPath,
40
+ }));
41
+ }
42
+ catch (error) {
43
+ await this.stop();
44
+ logger.error('Failed to connect DingTalk endpoint:', error);
45
+ throw error;
46
+ }
47
+ }
48
+ open() {
49
+ this.#open = true;
50
+ }
51
+ close() {
52
+ this.#open = false;
53
+ }
54
+ async stop() {
55
+ this.#open = false;
56
+ this.#sessionWebhooks.clear();
57
+ for (const release of this.#routeReleases.splice(0))
58
+ release();
59
+ this.#unregisterAgent?.();
60
+ this.#unregisterAgent = undefined;
61
+ this.#started = false;
62
+ logger.debug(formatCompact({ op: 'disconnect', endpoint: this.#options.config.name }));
63
+ }
64
+ async send({ target, payload }) {
65
+ const content = formatOutboundBody(payload);
66
+ const sessionWebhook = this.#sessionWebhooks.get(target);
67
+ if (sessionWebhook) {
68
+ const response = await this.#fetch(sessionWebhook, {
69
+ method: 'POST',
70
+ headers: { 'Content-Type': 'application/json; charset=utf-8' },
71
+ body: JSON.stringify(content),
72
+ });
73
+ const data = await response.json();
74
+ if (data.errcode !== 0) {
75
+ throw new Error(`Failed to send message via session webhook: ${data.errmsg}`);
76
+ }
77
+ logger.debug(formatCompact({
78
+ op: 'send',
79
+ endpoint: this.#options.config.name,
80
+ via: 'sessionWebhook',
81
+ to: target,
82
+ }));
83
+ return data.msgId || `${Date.now()}`;
84
+ }
85
+ const body = {
86
+ ...content,
87
+ ...(this.#options.config.robotCode
88
+ ? { robotCode: this.#options.config.robotCode }
89
+ : {}),
90
+ };
91
+ const data = await this.#request('/robot/send', {
92
+ method: 'POST',
93
+ body: body,
94
+ });
95
+ if (data.errcode !== 0) {
96
+ throw new Error(`Failed to send message: ${data.errmsg}`);
97
+ }
98
+ logger.debug(formatCompact({ op: 'send', endpoint: this.#options.config.name, to: target }));
99
+ return data.msgId || `${Date.now()}`;
100
+ }
101
+ /** Test / internal: admit a parsed event when open (non-webhook path). */
102
+ admit(event) {
103
+ if (!this.#open)
104
+ return;
105
+ if (event.sessionWebhook && event.conversationId) {
106
+ this.#sessionWebhooks.set(event.conversationId, event.sessionWebhook);
107
+ }
108
+ const target = resolveTarget(event);
109
+ const chatType = resolveChatType(event.conversationType);
110
+ const permit = normalizeDingtalkSenderForPermit({ isAdmin: event.isAdmin === true });
111
+ void this.#options.gateway.receive({
112
+ adapter: this.#options.id,
113
+ target,
114
+ content: formatInboundContent(event),
115
+ sender: resolveSender(event),
116
+ id: generateMessageId(event),
117
+ metadata: Object.freeze({
118
+ msgtype: event.msgtype,
119
+ chatType,
120
+ endpoint: this.#options.config.name,
121
+ senderNick: event.senderNick,
122
+ role: permit.role,
123
+ permissions: permit.permissions,
124
+ conversationType: event.conversationType,
125
+ ...(isDingtalkBotMentioned(event, this.#options.config.robotCode) ? { mentioned: true } : {}),
126
+ }),
127
+ }).catch((err) => {
128
+ logger.warn(formatCompact({
129
+ op: 'dingtalk_gateway_receive_failed',
130
+ target,
131
+ error: err instanceof Error ? err.message : String(err),
132
+ }));
133
+ });
134
+ }
135
+ async getUserInfo(userId) {
136
+ try {
137
+ const data = await this.#request('/topapi/v2/user/get', {
138
+ method: 'POST',
139
+ body: { userid: userId },
140
+ });
141
+ if (data.errcode === 0)
142
+ return data.result;
143
+ throw new Error(`Failed to get user info: ${data.errmsg}`);
144
+ }
145
+ catch (error) {
146
+ logger.error('Failed to get user info:', error);
147
+ return null;
148
+ }
149
+ }
150
+ async getDepartmentUsers(deptId) {
151
+ try {
152
+ const data = await this.#request('/topapi/user/listid', {
153
+ method: 'POST',
154
+ body: { dept_id: deptId },
155
+ });
156
+ if (data.errcode === 0) {
157
+ const result = data.result;
158
+ return result?.userid_list || [];
159
+ }
160
+ throw new Error(`Failed to get department users: ${data.errmsg}`);
161
+ }
162
+ catch (error) {
163
+ logger.error('Failed to get department users:', error);
164
+ return [];
165
+ }
166
+ }
167
+ async sendWorkNotice(userIdList, content) {
168
+ try {
169
+ const data = await this.#request('/topapi/message/corpconversation/asyncsend_v2', {
170
+ method: 'POST',
171
+ body: {
172
+ agent_id: this.#options.config.robotCode,
173
+ userid_list: userIdList.join(','),
174
+ msg: content,
175
+ },
176
+ });
177
+ if (data.errcode === 0)
178
+ return true;
179
+ throw new Error(`Failed to send work notice: ${data.errmsg}`);
180
+ }
181
+ catch (error) {
182
+ logger.error('Failed to send work notice:', error);
183
+ return false;
184
+ }
185
+ }
186
+ async getDepartmentList(deptId = 1) {
187
+ try {
188
+ const data = await this.#request('/topapi/v2/department/listsub', {
189
+ method: 'POST',
190
+ body: { dept_id: deptId },
191
+ });
192
+ if (data.errcode === 0)
193
+ return data.result || [];
194
+ throw new Error(`Failed to get department list: ${data.errmsg}`);
195
+ }
196
+ catch (error) {
197
+ logger.error('Failed to get department list:', error);
198
+ return [];
199
+ }
200
+ }
201
+ async getDepartmentInfo(deptId) {
202
+ try {
203
+ const data = await this.#request('/topapi/v2/department/get', {
204
+ method: 'POST',
205
+ body: { dept_id: deptId },
206
+ });
207
+ if (data.errcode === 0)
208
+ return data.result;
209
+ throw new Error(`Failed to get department info: ${data.errmsg}`);
210
+ }
211
+ catch (error) {
212
+ logger.error('Failed to get department info:', error);
213
+ return null;
214
+ }
215
+ }
216
+ async createChat(name, ownerUserId, userIdList) {
217
+ try {
218
+ const data = await this.#request('/topapi/chat/create', {
219
+ method: 'POST',
220
+ body: { name, owner: ownerUserId, useridlist: userIdList },
221
+ });
222
+ if (data.errcode === 0)
223
+ return data.chatid || null;
224
+ throw new Error(`Failed to create chat: ${data.errmsg}`);
225
+ }
226
+ catch (error) {
227
+ logger.error('Failed to create chat:', error);
228
+ return null;
229
+ }
230
+ }
231
+ async getChatInfo(chatId) {
232
+ try {
233
+ const data = await this.#request('/topapi/chat/get', {
234
+ method: 'POST',
235
+ body: { chatid: chatId },
236
+ });
237
+ if (data.errcode === 0)
238
+ return data.chat_info;
239
+ throw new Error(`Failed to get chat info: ${data.errmsg}`);
240
+ }
241
+ catch (error) {
242
+ logger.error('Failed to get chat info:', error);
243
+ return null;
244
+ }
245
+ }
246
+ async updateChat(chatId, options) {
247
+ try {
248
+ const data = await this.#request('/topapi/chat/update', {
249
+ method: 'POST',
250
+ body: { chatid: chatId, ...options },
251
+ });
252
+ if (data.errcode === 0)
253
+ return true;
254
+ throw new Error(`Failed to update chat: ${data.errmsg}`);
255
+ }
256
+ catch (error) {
257
+ logger.error('Failed to update chat:', error);
258
+ return false;
259
+ }
260
+ }
261
+ async #request(path, options = {}) {
262
+ await this.#ensureAccessToken();
263
+ const { method = 'GET', params = {}, body } = options;
264
+ const urlParams = new URLSearchParams({
265
+ ...Object.fromEntries(Object.entries(params).map(([key, value]) => [key, String(value)])),
266
+ access_token: this.#accessToken.token,
267
+ });
268
+ const url = `${this.#options.config.apiBaseUrl}${path}?${urlParams.toString()}`;
269
+ const response = await this.#fetch(url, {
270
+ method,
271
+ headers: { 'Content-Type': 'application/json; charset=utf-8' },
272
+ body: body && method === 'POST' ? JSON.stringify(body) : undefined,
273
+ });
274
+ if (!response.ok) {
275
+ const text = await response.text().catch(() => '');
276
+ throw new Error(`DingTalk API error ${response.status}: ${text}`);
277
+ }
278
+ return await response.json();
279
+ }
280
+ async #ensureAccessToken() {
281
+ const now = Date.now();
282
+ if (this.#accessToken.token
283
+ && now < this.#accessToken.timestamp + (this.#accessToken.expires_in - 300) * 1000) {
284
+ return;
285
+ }
286
+ if (this.#refreshPromise) {
287
+ await this.#refreshPromise;
288
+ return;
289
+ }
290
+ this.#refreshPromise = this.#refreshAccessToken()
291
+ .then(() => this.#accessToken.token)
292
+ .finally(() => { this.#refreshPromise = null; });
293
+ await this.#refreshPromise;
294
+ }
295
+ async #refreshAccessToken() {
296
+ const { appKey, appSecret, apiBaseUrl } = this.#options.config;
297
+ const params = new URLSearchParams({ appkey: appKey, appsecret: appSecret });
298
+ const url = `${apiBaseUrl}/gettoken?${params.toString()}`;
299
+ const response = await this.#fetch(url);
300
+ const data = await response.json();
301
+ if (data.errcode === 0 && data.access_token) {
302
+ this.#accessToken = {
303
+ token: data.access_token,
304
+ expires_in: data.expires_in ?? 7200,
305
+ timestamp: Date.now(),
306
+ };
307
+ logger.debug('Access token refreshed successfully');
308
+ return;
309
+ }
310
+ throw new Error(`Failed to get access token: ${data.errmsg} (${data.errcode})`);
311
+ }
312
+ }
package/lib/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ export { formatInboundContent, formatOutboundBody, generateMessageId, headerValue, normalizeWebhookPath, readTextBody, resolveChatType, resolveDingTalkConfig, resolveSender, resolveTarget, verifySignature, type AccessToken, type DingTalkAdapterConfig, type DingTalkApiResponse, type DingTalkEvent, type DingTalkMessage, type DingTalkSendBody, type DingTalkWireSegment, type ResolvedDingTalkConfig, } from './protocol.js';
2
+ export { DingTalkEndpoint, type DingTalkEndpointOptions, type DingTalkFetch, } from './endpoint.js';
3
+ export { registerDingTalkWebhookRoutes, handleDingTalkWebhookRequest, type DingTalkWebhookHandler, } from './webhook.js';
4
+ export { getDingtalkAgentDeps, registerDingtalkAgentEndpoint, setDingtalkAgentDeps, type DingtalkAgentDeps, type DingtalkAgentEndpoint, } from './dingtalk-agent-deps.js';
5
+ export { checkDingtalkPlatformPermit, dingtalkGroupPermitResolver, normalizeDingtalkSenderForPermit, platformPermit, registerDingtalkPlatformPermitChecker, } from './platform-permit.js';
package/lib/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { formatInboundContent, formatOutboundBody, generateMessageId, headerValue, normalizeWebhookPath, readTextBody, resolveChatType, resolveDingTalkConfig, resolveSender, resolveTarget, verifySignature, } from './protocol.js';
2
+ export { DingTalkEndpoint, } from './endpoint.js';
3
+ export { registerDingTalkWebhookRoutes, handleDingTalkWebhookRequest, } from './webhook.js';
4
+ export { getDingtalkAgentDeps, registerDingtalkAgentEndpoint, setDingtalkAgentDeps, } from './dingtalk-agent-deps.js';
5
+ export { checkDingtalkPlatformPermit, dingtalkGroupPermitResolver, normalizeDingtalkSenderForPermit, platformPermit, registerDingtalkPlatformPermitChecker, } from './platform-permit.js';
@@ -0,0 +1,15 @@
1
+ /**
2
+ * 钉钉 DingTalk platform permit
3
+ */
4
+ import { type Message } from '@zhin.js/core';
5
+ export declare function platformPermit(perm: string): string;
6
+ export declare function dingtalkGroupPermitResolver(logicalPerm: string): string;
7
+ export declare function normalizeDingtalkSenderForPermit(input: {
8
+ isOwner?: boolean;
9
+ isAdmin?: boolean;
10
+ }): {
11
+ role?: string;
12
+ permissions?: string[];
13
+ };
14
+ export declare function checkDingtalkPlatformPermit(perm: string, message: Message<any>): boolean;
15
+ export declare function registerDingtalkPlatformPermitChecker(): () => void;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * 钉钉 DingTalk platform permit
3
3
  */
4
- import { registerPlatformPermitChecker } from 'zhin.js';
4
+ import { registerPlatformPermitChecker } from '@zhin.js/core';
5
5
  const ADAPTER = 'dingtalk';
6
6
  export function platformPermit(perm) {
7
7
  return `platform(${ADAPTER},${perm})`;
@@ -39,4 +39,3 @@ export function checkDingtalkPlatformPermit(perm, message) {
39
39
  export function registerDingtalkPlatformPermitChecker() {
40
40
  return registerPlatformPermitChecker(ADAPTER, checkDingtalkPlatformPermit);
41
41
  }
42
- //# sourceMappingURL=platform-permit.js.map
@@ -0,0 +1,121 @@
1
+ /**
2
+ * DingTalk protocol helpers — no legacy Adapter/Endpoint / segment-mapper.
3
+ * Canonicalization is owned by gateway/core before endpoint.send.
4
+ */
5
+ import type { IncomingMessage } from 'node:http';
6
+ /** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
7
+ export interface DingTalkAdapterConfig {
8
+ readonly name?: string;
9
+ readonly appKey?: string;
10
+ readonly appSecret?: string;
11
+ readonly webhookPath?: string;
12
+ readonly robotCode?: string;
13
+ readonly apiBaseUrl?: string;
14
+ /** Transitional: legacy root `endpoints[]` with `context: dingtalk`. */
15
+ readonly endpoints?: ReadonlyArray<Partial<ResolvedDingTalkConfig> & {
16
+ readonly context?: string;
17
+ }>;
18
+ }
19
+ export interface ResolvedDingTalkConfig {
20
+ readonly context: 'dingtalk';
21
+ readonly name: string;
22
+ readonly appKey: string;
23
+ readonly appSecret: string;
24
+ readonly webhookPath: string;
25
+ readonly robotCode?: string;
26
+ readonly apiBaseUrl: string;
27
+ }
28
+ export interface DingTalkMessage {
29
+ readonly msgtype?: string;
30
+ readonly text?: {
31
+ readonly content?: string;
32
+ };
33
+ readonly msgId?: string;
34
+ readonly createAt?: number;
35
+ readonly conversationType?: string;
36
+ readonly conversationId?: string;
37
+ readonly senderId?: string;
38
+ readonly senderNick?: string;
39
+ readonly senderCorpId?: string;
40
+ readonly sessionWebhook?: string;
41
+ readonly chatbotCorpId?: string;
42
+ readonly chatbotUserId?: string;
43
+ readonly isAdmin?: boolean;
44
+ readonly senderStaffId?: string;
45
+ readonly atUsers?: ReadonlyArray<{
46
+ readonly dingtalkId?: string;
47
+ readonly staffId?: string;
48
+ }>;
49
+ readonly content?: Record<string, unknown>;
50
+ }
51
+ export interface DingTalkEvent extends DingTalkMessage {
52
+ readonly [key: string]: unknown;
53
+ }
54
+ /**
55
+ * 钉钉回调消息 @ 机器人判定:机器人被 @ 时回调带 `isInAtList: true`;
56
+ * 部分回调形态的 `atUserIds` / `atUsers[].dingtalkId` 会包含机器人 robotCode(来自配置)。
57
+ * 两者都不满足则不标注。
58
+ */
59
+ export declare function isDingtalkBotMentioned(event: DingTalkMessage, robotCode?: string): boolean;
60
+ export interface AccessToken {
61
+ token: string;
62
+ expires_in: number;
63
+ timestamp: number;
64
+ }
65
+ export interface DingTalkApiResponse {
66
+ readonly errcode: number;
67
+ readonly errmsg?: string;
68
+ readonly access_token?: string;
69
+ readonly expires_in?: number;
70
+ readonly msgId?: string;
71
+ readonly chatid?: string;
72
+ readonly result?: unknown;
73
+ readonly chat_info?: unknown;
74
+ readonly [key: string]: unknown;
75
+ }
76
+ export interface DingTalkWireSegment {
77
+ readonly type: string;
78
+ readonly data?: Record<string, unknown>;
79
+ }
80
+ export interface DingTalkSendBody {
81
+ readonly msgtype: string;
82
+ readonly text?: {
83
+ readonly content: string;
84
+ };
85
+ readonly picture?: {
86
+ readonly picURL: string;
87
+ };
88
+ readonly markdown?: {
89
+ readonly title: string;
90
+ readonly text: string;
91
+ };
92
+ readonly link?: {
93
+ readonly title: string;
94
+ readonly text: string;
95
+ readonly messageUrl?: string;
96
+ readonly picUrl?: string;
97
+ };
98
+ readonly at?: {
99
+ readonly atUserIds: string[];
100
+ readonly isAtAll: boolean;
101
+ };
102
+ readonly robotCode?: string;
103
+ }
104
+ export declare function resolveDingTalkConfig(config?: DingTalkAdapterConfig): ResolvedDingTalkConfig;
105
+ export declare function normalizeWebhookPath(path: string): string;
106
+ export declare function resolveChatType(conversationType?: string): 'group' | 'private';
107
+ export declare function resolveTarget(msg: DingTalkMessage): string;
108
+ export declare function resolveSender(msg: DingTalkMessage): string;
109
+ export declare function generateMessageId(msg: DingTalkMessage): string;
110
+ /** Build inbound text for MessageGateway.receive. */
111
+ export declare function formatInboundContent(msg: DingTalkMessage): string;
112
+ export declare function verifySignature(appSecret: string, timestamp: string, sign: string): boolean;
113
+ /**
114
+ * Wire-encode an already-rendered outbound payload into DingTalk robot body.
115
+ * Segment canonicalization is intentionally not done here.
116
+ */
117
+ export declare function formatOutboundBody(payload: unknown): DingTalkSendBody;
118
+ export declare function headerValue(headers: IncomingMessage['headers'], name: string): string;
119
+ export declare function readTextBody(request: IncomingMessage, options?: {
120
+ readonly limit?: number;
121
+ }): Promise<string>;