@zhin.js/adapter-dingtalk 6.0.3 → 6.0.5
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 +79 -0
- package/adapters/dingtalk.js +2 -2
- package/adapters/dingtalk.ts +2 -2
- package/lib/dingtalk-agent-deps.d.ts +2 -2
- package/lib/dingtalk-agent-deps.js +7 -7
- package/lib/endpoint.js +28 -23
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/platform-permit.d.ts +2 -3
- package/lib/platform-permit.js +3 -11
- package/lib/protocol.d.ts +3 -3
- package/lib/protocol.js +5 -5
- package/package.json +17 -16
- package/plugin.js +6 -3
- package/schema.json +41 -5
- package/src/dingtalk-agent-deps.ts +8 -8
- package/src/endpoint.ts +29 -24
- package/src/index.ts +0 -1
- package/src/platform-permit.ts +4 -8
- package/src/protocol.ts +7 -7
- /package/commands/endpoint/add/{[name].js → [id].js} +0 -0
- /package/commands/endpoint/add/{[name].ts → [id].ts} +0 -0
- /package/commands/endpoint/remove/{[name].js → [id].js} +0 -0
- /package/commands/endpoint/remove/{[name].ts → [id].ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,84 @@
|
|
|
1
1
|
# @zhin.js/adapter-dingtalk
|
|
2
2
|
|
|
3
|
+
## 6.0.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 51015d6: refactor(adapters): migrate platform-permit to PermissionSubject
|
|
8
|
+
|
|
9
|
+
All adapter platform-permit checkers now accept PermissionSubject
|
|
10
|
+
(duck-typed from Message/CommandSession) instead of Message directly.
|
|
11
|
+
registerPlatformPermitChecker is replaced by host.registerPlatform in
|
|
12
|
+
the adapter plugin setup. activity-feedback service updated for new
|
|
13
|
+
PermissionHost integration.
|
|
14
|
+
|
|
15
|
+
- Updated dependencies [6f9c366]
|
|
16
|
+
- Updated dependencies [373a56b]
|
|
17
|
+
- Updated dependencies [0de46a8]
|
|
18
|
+
- Updated dependencies [c106ecc]
|
|
19
|
+
- Updated dependencies [ca92e03]
|
|
20
|
+
- Updated dependencies [b0f37ae]
|
|
21
|
+
- Updated dependencies [ba08a2f]
|
|
22
|
+
- Updated dependencies [b08f7fe]
|
|
23
|
+
- Updated dependencies [daffd4c]
|
|
24
|
+
- Updated dependencies [36c7400]
|
|
25
|
+
- Updated dependencies [a9fa72e]
|
|
26
|
+
- Updated dependencies [c8de3ef]
|
|
27
|
+
- Updated dependencies [60f0fc8]
|
|
28
|
+
- Updated dependencies [574c990]
|
|
29
|
+
- Updated dependencies [d096f16]
|
|
30
|
+
- Updated dependencies [3f29623]
|
|
31
|
+
- Updated dependencies [2916852]
|
|
32
|
+
- Updated dependencies [d047869]
|
|
33
|
+
- Updated dependencies [162fa34]
|
|
34
|
+
- Updated dependencies [e62561e]
|
|
35
|
+
- Updated dependencies [3eeeb46]
|
|
36
|
+
- Updated dependencies [85d0f82]
|
|
37
|
+
- Updated dependencies [61bfc1c]
|
|
38
|
+
- Updated dependencies [04bad47]
|
|
39
|
+
- Updated dependencies [e40b048]
|
|
40
|
+
- Updated dependencies [5a5b1bb]
|
|
41
|
+
- Updated dependencies [f1708c3]
|
|
42
|
+
- Updated dependencies [d254a81]
|
|
43
|
+
- Updated dependencies [7123c47]
|
|
44
|
+
- Updated dependencies [05befc1]
|
|
45
|
+
- Updated dependencies [0663b6a]
|
|
46
|
+
- Updated dependencies [f28f9b3]
|
|
47
|
+
- Updated dependencies [9f340f7]
|
|
48
|
+
- Updated dependencies [e53444f]
|
|
49
|
+
- Updated dependencies [5eedd26]
|
|
50
|
+
- Updated dependencies [92b0dd7]
|
|
51
|
+
- Updated dependencies [f919b6f]
|
|
52
|
+
- Updated dependencies [098e411]
|
|
53
|
+
- Updated dependencies [e1b7c01]
|
|
54
|
+
- Updated dependencies [9b94f87]
|
|
55
|
+
- Updated dependencies [a7df753]
|
|
56
|
+
- @zhin.js/agent@1.1.5
|
|
57
|
+
- @zhin.js/host-http@1.0.8
|
|
58
|
+
- @zhin.js/permission@1.0.1
|
|
59
|
+
- @zhin.js/im-contract@1.0.3
|
|
60
|
+
- @zhin.js/adapter@1.1.7
|
|
61
|
+
- @zhin.js/plugin-runtime@1.1.5
|
|
62
|
+
- @zhin.js/command@1.0.9
|
|
63
|
+
- @zhin.js/core@1.5.4
|
|
64
|
+
- zhin.js@6.0.4
|
|
65
|
+
|
|
66
|
+
## 6.0.4
|
|
67
|
+
|
|
68
|
+
### Patch Changes
|
|
69
|
+
|
|
70
|
+
- f8c7a54: fix: im
|
|
71
|
+
- Updated dependencies [f8c7a54]
|
|
72
|
+
- @zhin.js/logger@1.0.76
|
|
73
|
+
- @zhin.js/host-http@1.0.7
|
|
74
|
+
- @zhin.js/adapter@1.1.6
|
|
75
|
+
- @zhin.js/agent@1.1.4
|
|
76
|
+
- @zhin.js/command@1.0.8
|
|
77
|
+
- @zhin.js/core@1.5.3
|
|
78
|
+
- @zhin.js/im-contract@1.0.2
|
|
79
|
+
- @zhin.js/plugin-runtime@1.1.4
|
|
80
|
+
- zhin.js@6.0.3
|
|
81
|
+
|
|
3
82
|
## 6.0.3
|
|
4
83
|
|
|
5
84
|
### Patch Changes
|
package/adapters/dingtalk.js
CHANGED
|
@@ -19,8 +19,8 @@ export default defineAdapter({
|
|
|
19
19
|
create(context) {
|
|
20
20
|
const config = resolveDingTalkConfig(context.config);
|
|
21
21
|
// 注册到插件运行时状态(dingtalk.endpoint list 的"运行中"数据源)
|
|
22
|
-
context.use(dingtalkRuntimeStateToken).endpoints.set(config.
|
|
23
|
-
|
|
22
|
+
context.use(dingtalkRuntimeStateToken).endpoints.set(config.id, {
|
|
23
|
+
id: config.id,
|
|
24
24
|
mode: 'webhook',
|
|
25
25
|
});
|
|
26
26
|
return new DingTalkEndpoint({
|
package/adapters/dingtalk.ts
CHANGED
|
@@ -24,8 +24,8 @@ export default defineAdapter<DingTalkAdapterConfig>({
|
|
|
24
24
|
create(context) {
|
|
25
25
|
const config = resolveDingTalkConfig(context.config);
|
|
26
26
|
// 注册到插件运行时状态(dingtalk.endpoint list 的"运行中"数据源)
|
|
27
|
-
context.use(dingtalkRuntimeStateToken).endpoints.set(config.
|
|
28
|
-
|
|
27
|
+
context.use(dingtalkRuntimeStateToken).endpoints.set(config.id, {
|
|
28
|
+
id: config.id,
|
|
29
29
|
mode: 'webhook',
|
|
30
30
|
});
|
|
31
31
|
return new DingTalkEndpoint({
|
|
@@ -18,9 +18,9 @@ export interface DingtalkAgentEndpoint {
|
|
|
18
18
|
}): Promise<boolean>;
|
|
19
19
|
}
|
|
20
20
|
export interface DingtalkAgentDeps {
|
|
21
|
-
getEndpoint: (
|
|
21
|
+
getEndpoint: (endpointKey: string) => DingtalkAgentEndpoint;
|
|
22
22
|
}
|
|
23
|
-
export declare function registerDingtalkAgentEndpoint(
|
|
23
|
+
export declare function registerDingtalkAgentEndpoint(endpointKey: string, endpoint: DingtalkAgentEndpoint): () => void;
|
|
24
24
|
/** Optional override used by tests / transitional callers. Pass `null` to clear. */
|
|
25
25
|
export declare function setDingtalkAgentDeps(deps: DingtalkAgentDeps | null): void;
|
|
26
26
|
export declare function getDingtalkAgentDeps(): DingtalkAgentDeps;
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
*/
|
|
5
5
|
const endpoints = new Map();
|
|
6
6
|
let override = null;
|
|
7
|
-
export function registerDingtalkAgentEndpoint(
|
|
8
|
-
endpoints.set(
|
|
7
|
+
export function registerDingtalkAgentEndpoint(endpointKey, endpoint) {
|
|
8
|
+
endpoints.set(endpointKey, endpoint);
|
|
9
9
|
return () => {
|
|
10
|
-
if (endpoints.get(
|
|
11
|
-
endpoints.delete(
|
|
10
|
+
if (endpoints.get(endpointKey) === endpoint) {
|
|
11
|
+
endpoints.delete(endpointKey);
|
|
12
12
|
}
|
|
13
13
|
};
|
|
14
14
|
}
|
|
@@ -20,10 +20,10 @@ export function getDingtalkAgentDeps() {
|
|
|
20
20
|
if (override)
|
|
21
21
|
return override;
|
|
22
22
|
return {
|
|
23
|
-
getEndpoint(
|
|
24
|
-
const endpoint = endpoints.get(
|
|
23
|
+
getEndpoint(endpointKey) {
|
|
24
|
+
const endpoint = endpoints.get(endpointKey);
|
|
25
25
|
if (!endpoint)
|
|
26
|
-
throw new Error(`Endpoint ${
|
|
26
|
+
throw new Error(`Endpoint ${endpointKey} 不存在`);
|
|
27
27
|
return endpoint;
|
|
28
28
|
},
|
|
29
29
|
};
|
package/lib/endpoint.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { formatCompact,
|
|
1
|
+
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
2
2
|
import { registerDingtalkAgentEndpoint } from './dingtalk-agent-deps.js';
|
|
3
3
|
import { normalizeDingtalkSenderForPermit } from './platform-permit.js';
|
|
4
4
|
import { dingtalkInboundConversation, formatInboundContent, formatOutboundBody, generateMessageId, isDingtalkBotMentioned, resolveChatType, resolveSender, } from './protocol.js';
|
|
5
5
|
import { registerDingTalkWebhookRoutes } from './webhook.js';
|
|
6
|
-
const logger = getLogger('dingtalk');
|
|
7
6
|
/**
|
|
8
7
|
* 钉钉机器人(webhook/stream 模式)无常规群列表 API——机器人不持有
|
|
9
8
|
* 「我所在的群」枚举面,仅能收发消息;
|
|
10
9
|
* 因此本 endpoint 不暴露 EndpointManagement(Console 社交面 RPC 对该平台保持未接线)。
|
|
11
10
|
*/
|
|
12
11
|
export class DingTalkEndpoint {
|
|
12
|
+
#logger;
|
|
13
13
|
#options;
|
|
14
14
|
#fetch;
|
|
15
15
|
#routeReleases = [];
|
|
@@ -20,6 +20,7 @@ export class DingTalkEndpoint {
|
|
|
20
20
|
#started = false;
|
|
21
21
|
#unregisterAgent;
|
|
22
22
|
constructor(options) {
|
|
23
|
+
this.#logger = getAdapterLogger('dingtalk', options.config.id);
|
|
23
24
|
this.#options = options;
|
|
24
25
|
this.#fetch = options.fetch ?? globalThis.fetch;
|
|
25
26
|
}
|
|
@@ -36,17 +37,17 @@ export class DingTalkEndpoint {
|
|
|
36
37
|
this.#started = true;
|
|
37
38
|
try {
|
|
38
39
|
await this.#refreshAccessToken();
|
|
39
|
-
this.#unregisterAgent = registerDingtalkAgentEndpoint(this.#options.config.
|
|
40
|
+
this.#unregisterAgent = registerDingtalkAgentEndpoint(this.#options.config.id, this);
|
|
40
41
|
this.#routeReleases.push(...registerDingTalkWebhookRoutes(this.#options.http, this));
|
|
41
|
-
logger.debug(formatCompact({
|
|
42
|
-
endpoint: this.#options.config.
|
|
42
|
+
this.#logger.debug(formatCompact({
|
|
43
|
+
endpoint: this.#options.config.id,
|
|
43
44
|
op: 'webhook',
|
|
44
45
|
path: this.#options.config.webhookPath,
|
|
45
46
|
}));
|
|
46
47
|
}
|
|
47
48
|
catch (error) {
|
|
48
49
|
await this.stop();
|
|
49
|
-
logger.error('Failed to connect DingTalk endpoint:', error);
|
|
50
|
+
this.#logger.error('Failed to connect DingTalk endpoint:', error);
|
|
50
51
|
throw error;
|
|
51
52
|
}
|
|
52
53
|
}
|
|
@@ -64,7 +65,7 @@ export class DingTalkEndpoint {
|
|
|
64
65
|
this.#unregisterAgent?.();
|
|
65
66
|
this.#unregisterAgent = undefined;
|
|
66
67
|
this.#started = false;
|
|
67
|
-
logger.debug(formatCompact({ op: 'disconnect'
|
|
68
|
+
this.#logger.debug(formatCompact({ op: 'disconnect' }));
|
|
68
69
|
}
|
|
69
70
|
async send({ conversation, payload }) {
|
|
70
71
|
const content = formatOutboundBody(payload);
|
|
@@ -79,9 +80,9 @@ export class DingTalkEndpoint {
|
|
|
79
80
|
if (data.errcode !== 0) {
|
|
80
81
|
throw new Error(`Failed to send message via session webhook: ${data.errmsg}`);
|
|
81
82
|
}
|
|
82
|
-
logger.debug(formatCompact({
|
|
83
|
+
this.#logger.debug(formatCompact({
|
|
83
84
|
op: 'send',
|
|
84
|
-
endpoint: this.#options.config.
|
|
85
|
+
endpoint: this.#options.config.id,
|
|
85
86
|
via: 'sessionWebhook',
|
|
86
87
|
to: conversation.id,
|
|
87
88
|
}));
|
|
@@ -100,7 +101,7 @@ export class DingTalkEndpoint {
|
|
|
100
101
|
if (data.errcode !== 0) {
|
|
101
102
|
throw new Error(`Failed to send message: ${data.errmsg}`);
|
|
102
103
|
}
|
|
103
|
-
logger.debug(formatCompact({ op: 'send',
|
|
104
|
+
this.#logger.debug(formatCompact({ op: 'send', to: conversation.id }));
|
|
104
105
|
return data.msgId || `${Date.now()}`;
|
|
105
106
|
}
|
|
106
107
|
/** Test / internal: admit a parsed event when open (non-webhook path). */
|
|
@@ -117,19 +118,23 @@ export class DingTalkEndpoint {
|
|
|
117
118
|
conversation,
|
|
118
119
|
message: { conversation, id: generateMessageId(event) },
|
|
119
120
|
content: formatInboundContent(event),
|
|
120
|
-
sender:
|
|
121
|
+
sender: {
|
|
122
|
+
id: resolveSender(event),
|
|
123
|
+
name: event.senderNick || undefined,
|
|
124
|
+
...(permit.role ? { roles: [permit.role] } : {}),
|
|
125
|
+
},
|
|
126
|
+
endpointId: this.#options.config.id,
|
|
127
|
+
...(isDingtalkBotMentioned(event, this.#options.config.robotCode) ? { mentioned: true } : {}),
|
|
121
128
|
metadata: Object.freeze({
|
|
122
129
|
msgtype: event.msgtype,
|
|
123
130
|
chatType,
|
|
124
|
-
endpoint: this.#options.config.name,
|
|
125
131
|
senderNick: event.senderNick,
|
|
126
132
|
role: permit.role,
|
|
127
133
|
permissions: permit.permissions,
|
|
128
134
|
conversationType: event.conversationType,
|
|
129
|
-
...(isDingtalkBotMentioned(event, this.#options.config.robotCode) ? { mentioned: true } : {}),
|
|
130
135
|
}),
|
|
131
136
|
}).catch((err) => {
|
|
132
|
-
logger.warn(formatCompact({
|
|
137
|
+
this.#logger.warn(formatCompact({
|
|
133
138
|
op: 'dingtalk_gateway_receive_failed',
|
|
134
139
|
conversationId: conversation.id,
|
|
135
140
|
error: err instanceof Error ? err.message : String(err),
|
|
@@ -147,7 +152,7 @@ export class DingTalkEndpoint {
|
|
|
147
152
|
throw new Error(`Failed to get user info: ${data.errmsg}`);
|
|
148
153
|
}
|
|
149
154
|
catch (error) {
|
|
150
|
-
logger.error('Failed to get user info:', error);
|
|
155
|
+
this.#logger.error('Failed to get user info:', error);
|
|
151
156
|
return null;
|
|
152
157
|
}
|
|
153
158
|
}
|
|
@@ -164,7 +169,7 @@ export class DingTalkEndpoint {
|
|
|
164
169
|
throw new Error(`Failed to get department users: ${data.errmsg}`);
|
|
165
170
|
}
|
|
166
171
|
catch (error) {
|
|
167
|
-
logger.error('Failed to get department users:', error);
|
|
172
|
+
this.#logger.error('Failed to get department users:', error);
|
|
168
173
|
return [];
|
|
169
174
|
}
|
|
170
175
|
}
|
|
@@ -183,7 +188,7 @@ export class DingTalkEndpoint {
|
|
|
183
188
|
throw new Error(`Failed to send work notice: ${data.errmsg}`);
|
|
184
189
|
}
|
|
185
190
|
catch (error) {
|
|
186
|
-
logger.error('Failed to send work notice:', error);
|
|
191
|
+
this.#logger.error('Failed to send work notice:', error);
|
|
187
192
|
return false;
|
|
188
193
|
}
|
|
189
194
|
}
|
|
@@ -198,7 +203,7 @@ export class DingTalkEndpoint {
|
|
|
198
203
|
throw new Error(`Failed to get department list: ${data.errmsg}`);
|
|
199
204
|
}
|
|
200
205
|
catch (error) {
|
|
201
|
-
logger.error('Failed to get department list:', error);
|
|
206
|
+
this.#logger.error('Failed to get department list:', error);
|
|
202
207
|
return [];
|
|
203
208
|
}
|
|
204
209
|
}
|
|
@@ -213,7 +218,7 @@ export class DingTalkEndpoint {
|
|
|
213
218
|
throw new Error(`Failed to get department info: ${data.errmsg}`);
|
|
214
219
|
}
|
|
215
220
|
catch (error) {
|
|
216
|
-
logger.error('Failed to get department info:', error);
|
|
221
|
+
this.#logger.error('Failed to get department info:', error);
|
|
217
222
|
return null;
|
|
218
223
|
}
|
|
219
224
|
}
|
|
@@ -228,7 +233,7 @@ export class DingTalkEndpoint {
|
|
|
228
233
|
throw new Error(`Failed to create chat: ${data.errmsg}`);
|
|
229
234
|
}
|
|
230
235
|
catch (error) {
|
|
231
|
-
logger.error('Failed to create chat:', error);
|
|
236
|
+
this.#logger.error('Failed to create chat:', error);
|
|
232
237
|
return null;
|
|
233
238
|
}
|
|
234
239
|
}
|
|
@@ -243,7 +248,7 @@ export class DingTalkEndpoint {
|
|
|
243
248
|
throw new Error(`Failed to get chat info: ${data.errmsg}`);
|
|
244
249
|
}
|
|
245
250
|
catch (error) {
|
|
246
|
-
logger.error('Failed to get chat info:', error);
|
|
251
|
+
this.#logger.error('Failed to get chat info:', error);
|
|
247
252
|
return null;
|
|
248
253
|
}
|
|
249
254
|
}
|
|
@@ -258,7 +263,7 @@ export class DingTalkEndpoint {
|
|
|
258
263
|
throw new Error(`Failed to update chat: ${data.errmsg}`);
|
|
259
264
|
}
|
|
260
265
|
catch (error) {
|
|
261
|
-
logger.error('Failed to update chat:', error);
|
|
266
|
+
this.#logger.error('Failed to update chat:', error);
|
|
262
267
|
return false;
|
|
263
268
|
}
|
|
264
269
|
}
|
|
@@ -308,7 +313,7 @@ export class DingTalkEndpoint {
|
|
|
308
313
|
expires_in: data.expires_in ?? 7200,
|
|
309
314
|
timestamp: Date.now(),
|
|
310
315
|
};
|
|
311
|
-
logger.debug('Access token refreshed successfully');
|
|
316
|
+
this.#logger.debug('Access token refreshed successfully');
|
|
312
317
|
return;
|
|
313
318
|
}
|
|
314
319
|
throw new Error(`Failed to get access token: ${data.errmsg} (${data.errcode})`);
|
package/lib/index.d.ts
CHANGED
|
@@ -2,4 +2,4 @@ export { dingtalkInboundConversation, formatInboundContent, formatOutboundBody,
|
|
|
2
2
|
export { DingTalkEndpoint, type DingTalkEndpointOptions, type DingTalkFetch, } from './endpoint.js';
|
|
3
3
|
export { registerDingTalkWebhookRoutes, handleDingTalkWebhookRequest, type DingTalkWebhookHandler, } from './webhook.js';
|
|
4
4
|
export { getDingtalkAgentDeps, registerDingtalkAgentEndpoint, setDingtalkAgentDeps, type DingtalkAgentDeps, type DingtalkAgentEndpoint, } from './dingtalk-agent-deps.js';
|
|
5
|
-
export { checkDingtalkPlatformPermit, dingtalkGroupPermitResolver, normalizeDingtalkSenderForPermit, platformPermit,
|
|
5
|
+
export { checkDingtalkPlatformPermit, dingtalkGroupPermitResolver, normalizeDingtalkSenderForPermit, platformPermit, } from './platform-permit.js';
|
package/lib/index.js
CHANGED
|
@@ -2,4 +2,4 @@ export { dingtalkInboundConversation, formatInboundContent, formatOutboundBody,
|
|
|
2
2
|
export { DingTalkEndpoint, } from './endpoint.js';
|
|
3
3
|
export { registerDingTalkWebhookRoutes, handleDingTalkWebhookRequest, } from './webhook.js';
|
|
4
4
|
export { getDingtalkAgentDeps, registerDingtalkAgentEndpoint, setDingtalkAgentDeps, } from './dingtalk-agent-deps.js';
|
|
5
|
-
export { checkDingtalkPlatformPermit, dingtalkGroupPermitResolver, normalizeDingtalkSenderForPermit, platformPermit,
|
|
5
|
+
export { checkDingtalkPlatformPermit, dingtalkGroupPermitResolver, normalizeDingtalkSenderForPermit, platformPermit, } from './platform-permit.js';
|
package/lib/platform-permit.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 钉钉 DingTalk platform permit
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import type { PermissionSubject } from '@zhin.js/permission';
|
|
5
5
|
export declare function platformPermit(perm: string): string;
|
|
6
6
|
export declare function dingtalkGroupPermitResolver(logicalPerm: string): string;
|
|
7
7
|
export declare function normalizeDingtalkSenderForPermit(input: {
|
|
@@ -11,5 +11,4 @@ export declare function normalizeDingtalkSenderForPermit(input: {
|
|
|
11
11
|
role?: string;
|
|
12
12
|
permissions?: string[];
|
|
13
13
|
};
|
|
14
|
-
export declare function checkDingtalkPlatformPermit(perm: string,
|
|
15
|
-
export declare function registerDingtalkPlatformPermitChecker(): () => void;
|
|
14
|
+
export declare function checkDingtalkPlatformPermit(perm: string, subject: PermissionSubject): boolean;
|
package/lib/platform-permit.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 钉钉 DingTalk platform permit
|
|
3
|
-
*/
|
|
4
|
-
import { registerPlatformPermitChecker } from '@zhin.js/core';
|
|
5
1
|
const ADAPTER = 'dingtalk';
|
|
6
2
|
export function platformPermit(perm) {
|
|
7
3
|
return `platform(${ADAPTER},${perm})`;
|
|
@@ -22,10 +18,9 @@ export function normalizeDingtalkSenderForPermit(input) {
|
|
|
22
18
|
}
|
|
23
19
|
return { role: 'member', permissions: [] };
|
|
24
20
|
}
|
|
25
|
-
export function checkDingtalkPlatformPermit(perm,
|
|
26
|
-
const
|
|
27
|
-
const permissions = sender
|
|
28
|
-
const role = sender.role;
|
|
21
|
+
export function checkDingtalkPlatformPermit(perm, subject) {
|
|
22
|
+
const role = subject.sender?.role?.[0];
|
|
23
|
+
const permissions = subject.sender?.permissions ?? [];
|
|
29
24
|
const has = (t) => permissions.includes(t);
|
|
30
25
|
switch (perm) {
|
|
31
26
|
case 'chat_owner':
|
|
@@ -36,6 +31,3 @@ export function checkDingtalkPlatformPermit(perm, message) {
|
|
|
36
31
|
return false;
|
|
37
32
|
}
|
|
38
33
|
}
|
|
39
|
-
export function registerDingtalkPlatformPermitChecker() {
|
|
40
|
-
return registerPlatformPermitChecker(ADAPTER, checkDingtalkPlatformPermit);
|
|
41
|
-
}
|
package/lib/protocol.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { IncomingMessage } from 'node:http';
|
|
|
6
6
|
import type { ConversationRef } from '@zhin.js/im-contract';
|
|
7
7
|
/** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
|
|
8
8
|
export interface DingTalkAdapterConfig {
|
|
9
|
-
readonly
|
|
9
|
+
readonly id?: string;
|
|
10
10
|
readonly appKey?: string;
|
|
11
11
|
readonly appSecret?: string;
|
|
12
12
|
readonly webhookPath?: string;
|
|
@@ -19,7 +19,7 @@ export interface DingTalkAdapterConfig {
|
|
|
19
19
|
}
|
|
20
20
|
export interface ResolvedDingTalkConfig {
|
|
21
21
|
readonly context: 'dingtalk';
|
|
22
|
-
readonly
|
|
22
|
+
readonly id: string;
|
|
23
23
|
readonly appKey: string;
|
|
24
24
|
readonly appSecret: string;
|
|
25
25
|
readonly webhookPath: string;
|
|
@@ -110,7 +110,7 @@ export declare function resolveChatType(conversationType?: string): 'group' | 'p
|
|
|
110
110
|
* 其余为单聊(kind 'private');会话原生 id 取 conversationId,缺省回退 senderId。
|
|
111
111
|
* 钉钉无 guild/频道容器概念,不产生 parent。
|
|
112
112
|
*/
|
|
113
|
-
export declare function dingtalkInboundConversation(
|
|
113
|
+
export declare function dingtalkInboundConversation(endpointKey: string, msg: DingTalkMessage): ConversationRef;
|
|
114
114
|
export declare function resolveSender(msg: DingTalkMessage): string;
|
|
115
115
|
export declare function generateMessageId(msg: DingTalkMessage): string;
|
|
116
116
|
/** Build inbound text for MessageGateway.receive. */
|
package/lib/protocol.js
CHANGED
|
@@ -29,8 +29,8 @@ export function resolveDingTalkConfig(config = {}) {
|
|
|
29
29
|
if (!appKey || !appSecret) {
|
|
30
30
|
throw new TypeError('DingTalk adapter requires appKey + appSecret (plugins.<key> or endpoints with context: dingtalk)');
|
|
31
31
|
}
|
|
32
|
-
const
|
|
33
|
-
|| (typeof entry?.
|
|
32
|
+
const id = (typeof config.id === 'string' && config.id)
|
|
33
|
+
|| (typeof entry?.id === 'string' && entry.id)
|
|
34
34
|
|| process.env.DINGTALK_BOT_NAME
|
|
35
35
|
|| 'dingtalk-bot';
|
|
36
36
|
const webhookPath = normalizeWebhookPath(config.webhookPath ?? entry?.webhookPath ?? '/dingtalk/webhook');
|
|
@@ -38,7 +38,7 @@ export function resolveDingTalkConfig(config = {}) {
|
|
|
38
38
|
const robotCode = config.robotCode ?? entry?.robotCode;
|
|
39
39
|
return {
|
|
40
40
|
context: 'dingtalk',
|
|
41
|
-
|
|
41
|
+
id,
|
|
42
42
|
appKey,
|
|
43
43
|
appSecret,
|
|
44
44
|
webhookPath,
|
|
@@ -58,9 +58,9 @@ export function resolveChatType(conversationType) {
|
|
|
58
58
|
* 其余为单聊(kind 'private');会话原生 id 取 conversationId,缺省回退 senderId。
|
|
59
59
|
* 钉钉无 guild/频道容器概念,不产生 parent。
|
|
60
60
|
*/
|
|
61
|
-
export function dingtalkInboundConversation(
|
|
61
|
+
export function dingtalkInboundConversation(endpointKey, msg) {
|
|
62
62
|
return {
|
|
63
|
-
endpoint: { id:
|
|
63
|
+
endpoint: { id: endpointKey, adapter: endpointKey.split('\0')[0] ?? endpointKey },
|
|
64
64
|
kind: resolveChatType(msg.conversationType),
|
|
65
65
|
id: msg.conversationId || msg.senderId || 'unknown',
|
|
66
66
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-dingtalk",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.5",
|
|
4
4
|
"description": "Zhin.js DingTalk (钉钉) adapter for Plugin Runtime (HTTP webhook)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -33,22 +33,23 @@
|
|
|
33
33
|
"directory": "plugins/adapters/dingtalk"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@zhin.js/adapter": "1.1.
|
|
37
|
-
"@zhin.js/command": "1.0.
|
|
38
|
-
"@zhin.js/core": "1.5.
|
|
39
|
-
"@zhin.js/host-http": "1.0.
|
|
40
|
-
"@zhin.js/im-contract": "1.0.
|
|
41
|
-
"@zhin.js/logger": "1.0.
|
|
42
|
-
"@zhin.js/plugin-runtime": "1.1.
|
|
36
|
+
"@zhin.js/adapter": "1.1.7",
|
|
37
|
+
"@zhin.js/command": "1.0.9",
|
|
38
|
+
"@zhin.js/core": "1.5.4",
|
|
39
|
+
"@zhin.js/host-http": "1.0.8",
|
|
40
|
+
"@zhin.js/im-contract": "1.0.3",
|
|
41
|
+
"@zhin.js/logger": "1.0.76",
|
|
42
|
+
"@zhin.js/plugin-runtime": "1.1.5"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"zod": "^4.0.0",
|
|
46
|
-
"@zhin.js/adapter": "1.1.
|
|
47
|
-
"@zhin.js/agent": "1.1.
|
|
48
|
-
"@zhin.js/core": "1.5.
|
|
49
|
-
"@zhin.js/host-http": "1.0.
|
|
50
|
-
"@zhin.js/
|
|
51
|
-
"zhin.js": "
|
|
46
|
+
"@zhin.js/adapter": "1.1.7",
|
|
47
|
+
"@zhin.js/agent": "1.1.5",
|
|
48
|
+
"@zhin.js/core": "1.5.4",
|
|
49
|
+
"@zhin.js/host-http": "1.0.8",
|
|
50
|
+
"@zhin.js/permission": "1.0.1",
|
|
51
|
+
"@zhin.js/plugin-runtime": "1.1.5",
|
|
52
|
+
"zhin.js": "6.0.4"
|
|
52
53
|
},
|
|
53
54
|
"peerDependenciesMeta": {
|
|
54
55
|
"zhin.js": {
|
|
@@ -66,8 +67,8 @@
|
|
|
66
67
|
"typescript": "^6.0.3",
|
|
67
68
|
"vitest": "^4.1.10",
|
|
68
69
|
"zod": "^4.4.3",
|
|
69
|
-
"@zhin.js/agent": "1.1.
|
|
70
|
-
"zhin.js": "6.0.
|
|
70
|
+
"@zhin.js/agent": "1.1.5",
|
|
71
|
+
"zhin.js": "6.0.4"
|
|
71
72
|
},
|
|
72
73
|
"files": [
|
|
73
74
|
"adapters",
|
package/plugin.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { createEndpointRuntimeState } from '@zhin.js/adapter';
|
|
3
3
|
import { definePlugin } from '@zhin.js/plugin-runtime';
|
|
4
|
-
import {
|
|
4
|
+
import { permissionHostToken } from '@zhin.js/permission';
|
|
5
|
+
import { checkDingtalkPlatformPermit } from "./lib/platform-permit.js";
|
|
5
6
|
import { dingtalkRuntimeStateToken } from "./lib/dingtalk-runtime-state.js";
|
|
6
7
|
export default definePlugin({
|
|
7
8
|
name: 'dingtalk',
|
|
@@ -9,8 +10,10 @@ export default definePlugin({
|
|
|
9
10
|
displayName: 'DingTalk (钉钉) Adapter',
|
|
10
11
|
},
|
|
11
12
|
setup(context) {
|
|
12
|
-
// 运行中 endpoint 注册表(dingtalk.endpoint list 的"运行中"数据源)
|
|
13
13
|
context.resources.provide(dingtalkRuntimeStateToken, createEndpointRuntimeState());
|
|
14
|
-
|
|
14
|
+
if (context.resources.has(permissionHostToken)) {
|
|
15
|
+
const host = context.resources.use(permissionHostToken);
|
|
16
|
+
return host.registerPlatform('dingtalk', checkDingtalkPlatformPermit);
|
|
17
|
+
}
|
|
15
18
|
},
|
|
16
19
|
});
|
package/schema.json
CHANGED
|
@@ -7,16 +7,48 @@
|
|
|
7
7
|
"type": "string",
|
|
8
8
|
"default": "https://oapi.dingtalk.com"
|
|
9
9
|
},
|
|
10
|
+
"master": {
|
|
11
|
+
"type": [
|
|
12
|
+
"string",
|
|
13
|
+
"number"
|
|
14
|
+
],
|
|
15
|
+
"description": "框架 master(DingTalk userid;AI/工具权限、endpoint 管理)。endpoints[i].master 可逐项覆盖"
|
|
16
|
+
},
|
|
17
|
+
"trusted": {
|
|
18
|
+
"type": "array",
|
|
19
|
+
"items": {
|
|
20
|
+
"type": [
|
|
21
|
+
"string",
|
|
22
|
+
"number"
|
|
23
|
+
],
|
|
24
|
+
"description": "Trusted DingTalk userid"
|
|
25
|
+
},
|
|
26
|
+
"description": "框架 trusted 用户列表(弱于 master)。endpoints[i].trusted 可逐项追加"
|
|
27
|
+
},
|
|
10
28
|
"endpoints": {
|
|
11
29
|
"type": "array",
|
|
12
|
-
"description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(
|
|
30
|
+
"description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(id 必填,其余覆盖顶层)",
|
|
13
31
|
"items": {
|
|
14
32
|
"type": "object",
|
|
15
33
|
"additionalProperties": true,
|
|
16
34
|
"properties": {
|
|
17
|
-
"
|
|
18
|
-
"type":
|
|
19
|
-
|
|
35
|
+
"master": {
|
|
36
|
+
"type": [
|
|
37
|
+
"string",
|
|
38
|
+
"number"
|
|
39
|
+
],
|
|
40
|
+
"description": "本 endpoint 的框架 master(DingTalk userid);覆盖顶层 master"
|
|
41
|
+
},
|
|
42
|
+
"trusted": {
|
|
43
|
+
"type": "array",
|
|
44
|
+
"items": {
|
|
45
|
+
"type": [
|
|
46
|
+
"string",
|
|
47
|
+
"number"
|
|
48
|
+
],
|
|
49
|
+
"description": "Trusted DingTalk userid"
|
|
50
|
+
},
|
|
51
|
+
"description": "本 endpoint 的 trusted 列表"
|
|
20
52
|
},
|
|
21
53
|
"appKey": {
|
|
22
54
|
"type": "string",
|
|
@@ -33,10 +65,14 @@
|
|
|
33
65
|
"robotCode": {
|
|
34
66
|
"type": "string",
|
|
35
67
|
"description": "Dingtalk robot code"
|
|
68
|
+
},
|
|
69
|
+
"id": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"description": "Dingtalk bot name"
|
|
36
72
|
}
|
|
37
73
|
},
|
|
38
74
|
"required": [
|
|
39
|
-
"
|
|
75
|
+
"id",
|
|
40
76
|
"appKey",
|
|
41
77
|
"appSecret",
|
|
42
78
|
"webhookPath",
|
|
@@ -23,20 +23,20 @@ export interface DingtalkAgentEndpoint {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export interface DingtalkAgentDeps {
|
|
26
|
-
getEndpoint: (
|
|
26
|
+
getEndpoint: (endpointKey: string) => DingtalkAgentEndpoint;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
const endpoints = new Map<string, DingtalkAgentEndpoint>();
|
|
30
30
|
let override: DingtalkAgentDeps | null = null;
|
|
31
31
|
|
|
32
32
|
export function registerDingtalkAgentEndpoint(
|
|
33
|
-
|
|
33
|
+
endpointKey: string,
|
|
34
34
|
endpoint: DingtalkAgentEndpoint,
|
|
35
35
|
): () => void {
|
|
36
|
-
endpoints.set(
|
|
36
|
+
endpoints.set(endpointKey, endpoint);
|
|
37
37
|
return () => {
|
|
38
|
-
if (endpoints.get(
|
|
39
|
-
endpoints.delete(
|
|
38
|
+
if (endpoints.get(endpointKey) === endpoint) {
|
|
39
|
+
endpoints.delete(endpointKey);
|
|
40
40
|
}
|
|
41
41
|
};
|
|
42
42
|
}
|
|
@@ -49,9 +49,9 @@ export function setDingtalkAgentDeps(deps: DingtalkAgentDeps | null): void {
|
|
|
49
49
|
export function getDingtalkAgentDeps(): DingtalkAgentDeps {
|
|
50
50
|
if (override) return override;
|
|
51
51
|
return {
|
|
52
|
-
getEndpoint(
|
|
53
|
-
const endpoint = endpoints.get(
|
|
54
|
-
if (!endpoint) throw new Error(`Endpoint ${
|
|
52
|
+
getEndpoint(endpointKey) {
|
|
53
|
+
const endpoint = endpoints.get(endpointKey);
|
|
54
|
+
if (!endpoint) throw new Error(`Endpoint ${endpointKey} 不存在`);
|
|
55
55
|
return endpoint;
|
|
56
56
|
},
|
|
57
57
|
};
|
package/src/endpoint.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import type { EndpointInstance, EndpointSendRequest } from '@zhin.js/adapter';
|
|
5
5
|
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
6
6
|
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
7
|
-
import { formatCompact,
|
|
7
|
+
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
8
8
|
import type { CapabilityId } from '@zhin.js/plugin-runtime';
|
|
9
9
|
import { registerDingtalkAgentEndpoint } from './dingtalk-agent-deps.js';
|
|
10
10
|
import { normalizeDingtalkSenderForPermit } from './platform-permit.js';
|
|
@@ -25,8 +25,6 @@ import {
|
|
|
25
25
|
} from './protocol.js';
|
|
26
26
|
import { registerDingTalkWebhookRoutes } from './webhook.js';
|
|
27
27
|
|
|
28
|
-
const logger = getLogger('dingtalk');
|
|
29
|
-
|
|
30
28
|
export type DingTalkFetch = (
|
|
31
29
|
url: string,
|
|
32
30
|
init?: {
|
|
@@ -55,6 +53,8 @@ export interface DingTalkEndpointOptions {
|
|
|
55
53
|
* 因此本 endpoint 不暴露 EndpointManagement(Console 社交面 RPC 对该平台保持未接线)。
|
|
56
54
|
*/
|
|
57
55
|
export class DingTalkEndpoint implements EndpointInstance {
|
|
56
|
+
readonly #logger!: ReturnType<typeof getAdapterLogger>;
|
|
57
|
+
|
|
58
58
|
readonly #options: DingTalkEndpointOptions;
|
|
59
59
|
readonly #fetch: DingTalkFetch;
|
|
60
60
|
#routeReleases: HttpRouteRegistration[] = [];
|
|
@@ -66,6 +66,7 @@ export class DingTalkEndpoint implements EndpointInstance {
|
|
|
66
66
|
#unregisterAgent?: () => void;
|
|
67
67
|
|
|
68
68
|
constructor(options: DingTalkEndpointOptions) {
|
|
69
|
+
this.#logger = getAdapterLogger('dingtalk', options.config.id);
|
|
69
70
|
this.#options = options;
|
|
70
71
|
this.#fetch = options.fetch ?? globalThis.fetch;
|
|
71
72
|
}
|
|
@@ -84,16 +85,16 @@ export class DingTalkEndpoint implements EndpointInstance {
|
|
|
84
85
|
this.#started = true;
|
|
85
86
|
try {
|
|
86
87
|
await this.#refreshAccessToken();
|
|
87
|
-
this.#unregisterAgent = registerDingtalkAgentEndpoint(this.#options.config.
|
|
88
|
+
this.#unregisterAgent = registerDingtalkAgentEndpoint(this.#options.config.id, this);
|
|
88
89
|
this.#routeReleases.push(...registerDingTalkWebhookRoutes(this.#options.http, this));
|
|
89
|
-
logger.debug(formatCompact({
|
|
90
|
-
endpoint: this.#options.config.
|
|
90
|
+
this.#logger.debug(formatCompact({
|
|
91
|
+
endpoint: this.#options.config.id,
|
|
91
92
|
op: 'webhook',
|
|
92
93
|
path: this.#options.config.webhookPath,
|
|
93
94
|
}));
|
|
94
95
|
} catch (error) {
|
|
95
96
|
await this.stop();
|
|
96
|
-
logger.error('Failed to connect DingTalk endpoint:', error);
|
|
97
|
+
this.#logger.error('Failed to connect DingTalk endpoint:', error);
|
|
97
98
|
throw error;
|
|
98
99
|
}
|
|
99
100
|
}
|
|
@@ -113,7 +114,7 @@ export class DingTalkEndpoint implements EndpointInstance {
|
|
|
113
114
|
this.#unregisterAgent?.();
|
|
114
115
|
this.#unregisterAgent = undefined;
|
|
115
116
|
this.#started = false;
|
|
116
|
-
logger.debug(formatCompact({ op: 'disconnect'
|
|
117
|
+
this.#logger.debug(formatCompact({ op: 'disconnect' }));
|
|
117
118
|
}
|
|
118
119
|
|
|
119
120
|
async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
|
|
@@ -129,9 +130,9 @@ export class DingTalkEndpoint implements EndpointInstance {
|
|
|
129
130
|
if (data.errcode !== 0) {
|
|
130
131
|
throw new Error(`Failed to send message via session webhook: ${data.errmsg}`);
|
|
131
132
|
}
|
|
132
|
-
logger.debug(formatCompact({
|
|
133
|
+
this.#logger.debug(formatCompact({
|
|
133
134
|
op: 'send',
|
|
134
|
-
endpoint: this.#options.config.
|
|
135
|
+
endpoint: this.#options.config.id,
|
|
135
136
|
via: 'sessionWebhook',
|
|
136
137
|
to: conversation.id,
|
|
137
138
|
}));
|
|
@@ -151,7 +152,7 @@ export class DingTalkEndpoint implements EndpointInstance {
|
|
|
151
152
|
if (data.errcode !== 0) {
|
|
152
153
|
throw new Error(`Failed to send message: ${data.errmsg}`);
|
|
153
154
|
}
|
|
154
|
-
logger.debug(formatCompact({ op: 'send',
|
|
155
|
+
this.#logger.debug(formatCompact({ op: 'send', to: conversation.id }));
|
|
155
156
|
return (data.msgId as string) || `${Date.now()}`;
|
|
156
157
|
}
|
|
157
158
|
|
|
@@ -168,19 +169,23 @@ export class DingTalkEndpoint implements EndpointInstance {
|
|
|
168
169
|
conversation,
|
|
169
170
|
message: { conversation, id: generateMessageId(event) },
|
|
170
171
|
content: formatInboundContent(event),
|
|
171
|
-
sender:
|
|
172
|
+
sender: {
|
|
173
|
+
id: resolveSender(event),
|
|
174
|
+
name: event.senderNick || undefined,
|
|
175
|
+
...(permit.role ? { roles: [permit.role] } : {}),
|
|
176
|
+
},
|
|
177
|
+
endpointId: this.#options.config.id,
|
|
178
|
+
...(isDingtalkBotMentioned(event, this.#options.config.robotCode) ? { mentioned: true } : {}),
|
|
172
179
|
metadata: Object.freeze({
|
|
173
180
|
msgtype: event.msgtype,
|
|
174
181
|
chatType,
|
|
175
|
-
endpoint: this.#options.config.name,
|
|
176
182
|
senderNick: event.senderNick,
|
|
177
183
|
role: permit.role,
|
|
178
184
|
permissions: permit.permissions,
|
|
179
185
|
conversationType: event.conversationType,
|
|
180
|
-
...(isDingtalkBotMentioned(event, this.#options.config.robotCode) ? { mentioned: true } : {}),
|
|
181
186
|
}),
|
|
182
187
|
}).catch((err) => {
|
|
183
|
-
logger.warn(formatCompact({
|
|
188
|
+
this.#logger.warn(formatCompact({
|
|
184
189
|
op: 'dingtalk_gateway_receive_failed',
|
|
185
190
|
conversationId: conversation.id,
|
|
186
191
|
error: err instanceof Error ? err.message : String(err),
|
|
@@ -197,7 +202,7 @@ export class DingTalkEndpoint implements EndpointInstance {
|
|
|
197
202
|
if (data.errcode === 0) return data.result;
|
|
198
203
|
throw new Error(`Failed to get user info: ${data.errmsg}`);
|
|
199
204
|
} catch (error) {
|
|
200
|
-
logger.error('Failed to get user info:', error);
|
|
205
|
+
this.#logger.error('Failed to get user info:', error);
|
|
201
206
|
return null;
|
|
202
207
|
}
|
|
203
208
|
}
|
|
@@ -214,7 +219,7 @@ export class DingTalkEndpoint implements EndpointInstance {
|
|
|
214
219
|
}
|
|
215
220
|
throw new Error(`Failed to get department users: ${data.errmsg}`);
|
|
216
221
|
} catch (error) {
|
|
217
|
-
logger.error('Failed to get department users:', error);
|
|
222
|
+
this.#logger.error('Failed to get department users:', error);
|
|
218
223
|
return [];
|
|
219
224
|
}
|
|
220
225
|
}
|
|
@@ -232,7 +237,7 @@ export class DingTalkEndpoint implements EndpointInstance {
|
|
|
232
237
|
if (data.errcode === 0) return true;
|
|
233
238
|
throw new Error(`Failed to send work notice: ${data.errmsg}`);
|
|
234
239
|
} catch (error) {
|
|
235
|
-
logger.error('Failed to send work notice:', error);
|
|
240
|
+
this.#logger.error('Failed to send work notice:', error);
|
|
236
241
|
return false;
|
|
237
242
|
}
|
|
238
243
|
}
|
|
@@ -246,7 +251,7 @@ export class DingTalkEndpoint implements EndpointInstance {
|
|
|
246
251
|
if (data.errcode === 0) return (data.result as unknown[]) || [];
|
|
247
252
|
throw new Error(`Failed to get department list: ${data.errmsg}`);
|
|
248
253
|
} catch (error) {
|
|
249
|
-
logger.error('Failed to get department list:', error);
|
|
254
|
+
this.#logger.error('Failed to get department list:', error);
|
|
250
255
|
return [];
|
|
251
256
|
}
|
|
252
257
|
}
|
|
@@ -260,7 +265,7 @@ export class DingTalkEndpoint implements EndpointInstance {
|
|
|
260
265
|
if (data.errcode === 0) return data.result;
|
|
261
266
|
throw new Error(`Failed to get department info: ${data.errmsg}`);
|
|
262
267
|
} catch (error) {
|
|
263
|
-
logger.error('Failed to get department info:', error);
|
|
268
|
+
this.#logger.error('Failed to get department info:', error);
|
|
264
269
|
return null;
|
|
265
270
|
}
|
|
266
271
|
}
|
|
@@ -278,7 +283,7 @@ export class DingTalkEndpoint implements EndpointInstance {
|
|
|
278
283
|
if (data.errcode === 0) return (data.chatid as string) || null;
|
|
279
284
|
throw new Error(`Failed to create chat: ${data.errmsg}`);
|
|
280
285
|
} catch (error) {
|
|
281
|
-
logger.error('Failed to create chat:', error);
|
|
286
|
+
this.#logger.error('Failed to create chat:', error);
|
|
282
287
|
return null;
|
|
283
288
|
}
|
|
284
289
|
}
|
|
@@ -292,7 +297,7 @@ export class DingTalkEndpoint implements EndpointInstance {
|
|
|
292
297
|
if (data.errcode === 0) return data.chat_info;
|
|
293
298
|
throw new Error(`Failed to get chat info: ${data.errmsg}`);
|
|
294
299
|
} catch (error) {
|
|
295
|
-
logger.error('Failed to get chat info:', error);
|
|
300
|
+
this.#logger.error('Failed to get chat info:', error);
|
|
296
301
|
return null;
|
|
297
302
|
}
|
|
298
303
|
}
|
|
@@ -314,7 +319,7 @@ export class DingTalkEndpoint implements EndpointInstance {
|
|
|
314
319
|
if (data.errcode === 0) return true;
|
|
315
320
|
throw new Error(`Failed to update chat: ${data.errmsg}`);
|
|
316
321
|
} catch (error) {
|
|
317
|
-
logger.error('Failed to update chat:', error);
|
|
322
|
+
this.#logger.error('Failed to update chat:', error);
|
|
318
323
|
return false;
|
|
319
324
|
}
|
|
320
325
|
}
|
|
@@ -378,7 +383,7 @@ export class DingTalkEndpoint implements EndpointInstance {
|
|
|
378
383
|
expires_in: data.expires_in ?? 7200,
|
|
379
384
|
timestamp: Date.now(),
|
|
380
385
|
};
|
|
381
|
-
logger.debug('Access token refreshed successfully');
|
|
386
|
+
this.#logger.debug('Access token refreshed successfully');
|
|
382
387
|
return;
|
|
383
388
|
}
|
|
384
389
|
throw new Error(`Failed to get access token: ${data.errmsg} (${data.errcode})`);
|
package/src/index.ts
CHANGED
package/src/platform-permit.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 钉钉 DingTalk platform permit
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import type { PermissionSubject } from '@zhin.js/permission';
|
|
5
5
|
|
|
6
6
|
const ADAPTER = 'dingtalk';
|
|
7
7
|
|
|
@@ -31,10 +31,9 @@ export function normalizeDingtalkSenderForPermit(input: {
|
|
|
31
31
|
return { role: 'member', permissions: [] };
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
export function checkDingtalkPlatformPermit(perm: string,
|
|
35
|
-
const
|
|
36
|
-
const permissions = sender
|
|
37
|
-
const role = sender.role;
|
|
34
|
+
export function checkDingtalkPlatformPermit(perm: string, subject: PermissionSubject): boolean {
|
|
35
|
+
const role = subject.sender?.role?.[0];
|
|
36
|
+
const permissions = subject.sender?.permissions ?? [];
|
|
38
37
|
const has = (t: string) => permissions.includes(t);
|
|
39
38
|
|
|
40
39
|
switch (perm) {
|
|
@@ -47,6 +46,3 @@ export function checkDingtalkPlatformPermit(perm: string, message: Message<any>)
|
|
|
47
46
|
}
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
export function registerDingtalkPlatformPermitChecker(): () => void {
|
|
51
|
-
return registerPlatformPermitChecker(ADAPTER, checkDingtalkPlatformPermit);
|
|
52
|
-
}
|
package/src/protocol.ts
CHANGED
|
@@ -14,7 +14,7 @@ const logger = getLogger('dingtalk');
|
|
|
14
14
|
|
|
15
15
|
/** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
|
|
16
16
|
export interface DingTalkAdapterConfig {
|
|
17
|
-
readonly
|
|
17
|
+
readonly id?: string;
|
|
18
18
|
readonly appKey?: string;
|
|
19
19
|
readonly appSecret?: string;
|
|
20
20
|
readonly webhookPath?: string;
|
|
@@ -28,7 +28,7 @@ export interface DingTalkAdapterConfig {
|
|
|
28
28
|
|
|
29
29
|
export interface ResolvedDingTalkConfig {
|
|
30
30
|
readonly context: 'dingtalk';
|
|
31
|
-
readonly
|
|
31
|
+
readonly id: string;
|
|
32
32
|
readonly appKey: string;
|
|
33
33
|
readonly appSecret: string;
|
|
34
34
|
readonly webhookPath: string;
|
|
@@ -124,8 +124,8 @@ export function resolveDingTalkConfig(config: DingTalkAdapterConfig = {}): Resol
|
|
|
124
124
|
'DingTalk adapter requires appKey + appSecret (plugins.<key> or endpoints with context: dingtalk)',
|
|
125
125
|
);
|
|
126
126
|
}
|
|
127
|
-
const
|
|
128
|
-
|| (typeof entry?.
|
|
127
|
+
const id = (typeof config.id === 'string' && config.id)
|
|
128
|
+
|| (typeof entry?.id === 'string' && entry.id)
|
|
129
129
|
|| process.env.DINGTALK_BOT_NAME
|
|
130
130
|
|| 'dingtalk-bot';
|
|
131
131
|
const webhookPath = normalizeWebhookPath(
|
|
@@ -137,7 +137,7 @@ export function resolveDingTalkConfig(config: DingTalkAdapterConfig = {}): Resol
|
|
|
137
137
|
const robotCode = config.robotCode ?? entry?.robotCode;
|
|
138
138
|
return {
|
|
139
139
|
context: 'dingtalk',
|
|
140
|
-
|
|
140
|
+
id,
|
|
141
141
|
appKey,
|
|
142
142
|
appSecret,
|
|
143
143
|
webhookPath,
|
|
@@ -160,9 +160,9 @@ export function resolveChatType(conversationType?: string): 'group' | 'private'
|
|
|
160
160
|
* 其余为单聊(kind 'private');会话原生 id 取 conversationId,缺省回退 senderId。
|
|
161
161
|
* 钉钉无 guild/频道容器概念,不产生 parent。
|
|
162
162
|
*/
|
|
163
|
-
export function dingtalkInboundConversation(
|
|
163
|
+
export function dingtalkInboundConversation(endpointKey: string, msg: DingTalkMessage): ConversationRef {
|
|
164
164
|
return {
|
|
165
|
-
endpoint: { id:
|
|
165
|
+
endpoint: { id: endpointKey, adapter: endpointKey.split('\0')[0] ?? endpointKey },
|
|
166
166
|
kind: resolveChatType(msg.conversationType),
|
|
167
167
|
id: msg.conversationId || msg.senderId || 'unknown',
|
|
168
168
|
};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|