@zhin.js/adapter-wecom 4.0.3 → 4.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/wecom.js +2 -2
- package/adapters/wecom.ts +2 -2
- package/lib/endpoint.js +23 -25
- 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/lib/wecom-agent-deps.d.ts +2 -2
- package/lib/wecom-agent-deps.js +7 -7
- package/package.json +17 -16
- package/plugin.js +6 -3
- package/schema.json +41 -5
- package/src/endpoint.ts +24 -26
- package/src/index.ts +0 -1
- package/src/platform-permit.ts +4 -8
- package/src/protocol.ts +7 -7
- package/src/wecom-agent-deps.ts +8 -8
- /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-wecom
|
|
2
2
|
|
|
3
|
+
## 4.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
|
+
## 4.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
|
## 4.0.3
|
|
4
83
|
|
|
5
84
|
### Patch Changes
|
package/adapters/wecom.js
CHANGED
|
@@ -21,8 +21,8 @@ export default defineAdapter({
|
|
|
21
21
|
create(context) {
|
|
22
22
|
const config = resolveWecomConfig(context.config);
|
|
23
23
|
// 注册到插件运行时状态(wecom.endpoint list 的"运行中"数据源)
|
|
24
|
-
context.use(wecomRuntimeStateToken).endpoints.set(config.
|
|
25
|
-
|
|
24
|
+
context.use(wecomRuntimeStateToken).endpoints.set(config.id, {
|
|
25
|
+
id: config.id,
|
|
26
26
|
mode: 'webhook',
|
|
27
27
|
});
|
|
28
28
|
return new WecomEndpoint({
|
package/adapters/wecom.ts
CHANGED
|
@@ -26,8 +26,8 @@ export default defineAdapter<WecomAdapterConfig>({
|
|
|
26
26
|
create(context) {
|
|
27
27
|
const config = resolveWecomConfig(context.config);
|
|
28
28
|
// 注册到插件运行时状态(wecom.endpoint list 的"运行中"数据源)
|
|
29
|
-
context.use(wecomRuntimeStateToken).endpoints.set(config.
|
|
30
|
-
|
|
29
|
+
context.use(wecomRuntimeStateToken).endpoints.set(config.id, {
|
|
30
|
+
id: config.id,
|
|
31
31
|
mode: 'webhook',
|
|
32
32
|
});
|
|
33
33
|
return new WecomEndpoint({
|
package/lib/endpoint.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { formatCompact,
|
|
1
|
+
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
2
2
|
import { registerWecomAgentEndpoint } from './wecom-agent-deps.js';
|
|
3
3
|
import { buildMediaUploadForm, readOutboundImageMedia, resolveMediaBinary, } from './media-upload.js';
|
|
4
4
|
import { buildSendRequestBody, formatInboundContent, formatOutboundBody, resolveChatType, wecomInboundConversation, } from './protocol.js';
|
|
5
5
|
import { registerWecomWebhookRoutes } from './webhook.js';
|
|
6
|
-
const logger = getLogger('wecom');
|
|
7
6
|
/**
|
|
8
7
|
* 企业微信服务端 API 无 bot 群列表/群成员列表接口(客户群接口属「客户联系」
|
|
9
8
|
* 独立授权域,非 bot 社交面),好友/频道概念亦不存在;
|
|
10
9
|
* 因此本 endpoint 不暴露 EndpointManagement(Console 社交面 RPC 对该平台保持未接线)。
|
|
11
10
|
*/
|
|
12
11
|
export class WecomEndpoint {
|
|
12
|
+
#logger;
|
|
13
13
|
#options;
|
|
14
14
|
#fetch;
|
|
15
15
|
#routeReleases = [];
|
|
@@ -19,6 +19,7 @@ export class WecomEndpoint {
|
|
|
19
19
|
#started = false;
|
|
20
20
|
#unregisterAgent;
|
|
21
21
|
constructor(options) {
|
|
22
|
+
this.#logger = getAdapterLogger('wecom', options.config.id);
|
|
22
23
|
this.#options = options;
|
|
23
24
|
this.#fetch = options.fetch ?? globalThis.fetch;
|
|
24
25
|
}
|
|
@@ -35,17 +36,17 @@ export class WecomEndpoint {
|
|
|
35
36
|
this.#started = true;
|
|
36
37
|
try {
|
|
37
38
|
await this.#refreshAccessToken();
|
|
38
|
-
this.#unregisterAgent = registerWecomAgentEndpoint(this.#options.config.
|
|
39
|
+
this.#unregisterAgent = registerWecomAgentEndpoint(this.#options.config.id, this);
|
|
39
40
|
this.#routeReleases.push(...registerWecomWebhookRoutes(this.#options.http, this));
|
|
40
|
-
logger.debug(formatCompact({
|
|
41
|
-
endpoint: this.#options.config.
|
|
41
|
+
this.#logger.debug(formatCompact({
|
|
42
|
+
endpoint: this.#options.config.id,
|
|
42
43
|
op: 'webhook',
|
|
43
44
|
path: this.#options.config.webhookPath,
|
|
44
45
|
}));
|
|
45
46
|
}
|
|
46
47
|
catch (error) {
|
|
47
48
|
await this.stop();
|
|
48
|
-
logger.error('Failed to connect WeCom endpoint:', error);
|
|
49
|
+
this.#logger.error('Failed to connect WeCom endpoint:', error);
|
|
49
50
|
throw error;
|
|
50
51
|
}
|
|
51
52
|
}
|
|
@@ -62,7 +63,7 @@ export class WecomEndpoint {
|
|
|
62
63
|
this.#unregisterAgent?.();
|
|
63
64
|
this.#unregisterAgent = undefined;
|
|
64
65
|
this.#started = false;
|
|
65
|
-
logger.debug(formatCompact({ op: 'disconnect'
|
|
66
|
+
this.#logger.debug(formatCompact({ op: 'disconnect' }));
|
|
66
67
|
}
|
|
67
68
|
async send({ conversation, payload }) {
|
|
68
69
|
const materialized = await this.#materializeOutboundMedia(payload);
|
|
@@ -77,10 +78,7 @@ export class WecomEndpoint {
|
|
|
77
78
|
if (data.errcode !== 0) {
|
|
78
79
|
throw new Error(`Failed to send message: ${data.errmsg} (${data.errcode})`);
|
|
79
80
|
}
|
|
80
|
-
logger.debug(formatCompact({
|
|
81
|
-
op: 'send',
|
|
82
|
-
endpoint: this.#options.config.name,
|
|
83
|
-
to: `${conversation.kind}:${conversation.id}`,
|
|
81
|
+
this.#logger.debug(formatCompact({ op: 'send', to: `${conversation.kind}:${conversation.id}`,
|
|
84
82
|
}));
|
|
85
83
|
return data.msgid || `${Date.now()}`;
|
|
86
84
|
}
|
|
@@ -110,9 +108,9 @@ export class WecomEndpoint {
|
|
|
110
108
|
const data = seg.data ?? {};
|
|
111
109
|
const media = readOutboundImageMedia(data);
|
|
112
110
|
if (!media) {
|
|
113
|
-
logger.warn(formatCompact({
|
|
111
|
+
this.#logger.warn(formatCompact({
|
|
114
112
|
op: 'wecom_outbound_media_dropped',
|
|
115
|
-
endpoint: this.#options.config.
|
|
113
|
+
endpoint: this.#options.config.id,
|
|
116
114
|
type: 'image',
|
|
117
115
|
reason: 'missing_media_ref',
|
|
118
116
|
}));
|
|
@@ -126,9 +124,9 @@ export class WecomEndpoint {
|
|
|
126
124
|
return { type: 'image', data: { media_id: mediaId } };
|
|
127
125
|
}
|
|
128
126
|
catch (error) {
|
|
129
|
-
logger.warn(formatCompact({
|
|
127
|
+
this.#logger.warn(formatCompact({
|
|
130
128
|
op: 'wecom_media_upload_failed',
|
|
131
|
-
endpoint: this.#options.config.
|
|
129
|
+
endpoint: this.#options.config.id,
|
|
132
130
|
error: error instanceof Error ? error.message : String(error),
|
|
133
131
|
}));
|
|
134
132
|
const alt = typeof data.alt === 'string' && data.alt ? data.alt : '[image]';
|
|
@@ -159,17 +157,17 @@ export class WecomEndpoint {
|
|
|
159
157
|
conversation,
|
|
160
158
|
message: { conversation, id: msg.MsgId || `${msg.CreateTime}` },
|
|
161
159
|
content: formatInboundContent(msg),
|
|
162
|
-
sender: msg.FromUserName,
|
|
160
|
+
sender: { id: msg.FromUserName },
|
|
161
|
+
endpointId: this.#options.config.id,
|
|
163
162
|
metadata: Object.freeze({
|
|
164
163
|
msgType: msg.MsgType,
|
|
165
164
|
event: msg.Event,
|
|
166
165
|
chatType,
|
|
167
|
-
endpoint: this.#options.config.name,
|
|
168
166
|
toUserName: msg.ToUserName,
|
|
169
167
|
agentId: msg.AgentID,
|
|
170
168
|
}),
|
|
171
169
|
}).catch((err) => {
|
|
172
|
-
logger.warn(formatCompact({
|
|
170
|
+
this.#logger.warn(formatCompact({
|
|
173
171
|
op: 'wecom_gateway_receive_failed',
|
|
174
172
|
target: `${conversation.kind}:${conversation.id}`,
|
|
175
173
|
error: err instanceof Error ? err.message : String(err),
|
|
@@ -186,7 +184,7 @@ export class WecomEndpoint {
|
|
|
186
184
|
throw new Error(`Failed to get user info: ${data.errmsg}`);
|
|
187
185
|
}
|
|
188
186
|
catch (error) {
|
|
189
|
-
logger.error('Failed to get user info:', error);
|
|
187
|
+
this.#logger.error('Failed to get user info:', error);
|
|
190
188
|
return null;
|
|
191
189
|
}
|
|
192
190
|
}
|
|
@@ -200,7 +198,7 @@ export class WecomEndpoint {
|
|
|
200
198
|
throw new Error(`Failed to get department users: ${data.errmsg}`);
|
|
201
199
|
}
|
|
202
200
|
catch (error) {
|
|
203
|
-
logger.error('Failed to get department users:', error);
|
|
201
|
+
this.#logger.error('Failed to get department users:', error);
|
|
204
202
|
return [];
|
|
205
203
|
}
|
|
206
204
|
}
|
|
@@ -214,16 +212,16 @@ export class WecomEndpoint {
|
|
|
214
212
|
throw new Error(`Failed to get department list: ${data.errmsg}`);
|
|
215
213
|
}
|
|
216
214
|
catch (error) {
|
|
217
|
-
logger.error('Failed to get department list:', error);
|
|
215
|
+
this.#logger.error('Failed to get department list:', error);
|
|
218
216
|
return [];
|
|
219
217
|
}
|
|
220
218
|
}
|
|
221
219
|
async sendTextMessage(userId, content) {
|
|
222
220
|
try {
|
|
223
|
-
const
|
|
221
|
+
const endpointKey = String(this.#options.id);
|
|
224
222
|
await this.send({
|
|
225
223
|
conversation: {
|
|
226
|
-
endpoint: { id:
|
|
224
|
+
endpoint: { id: endpointKey, adapter: endpointKey.split('\0')[0] ?? endpointKey },
|
|
227
225
|
kind: resolveChatType(userId),
|
|
228
226
|
id: userId,
|
|
229
227
|
},
|
|
@@ -232,7 +230,7 @@ export class WecomEndpoint {
|
|
|
232
230
|
return true;
|
|
233
231
|
}
|
|
234
232
|
catch (error) {
|
|
235
|
-
logger.error('Failed to send text message:', error);
|
|
233
|
+
this.#logger.error('Failed to send text message:', error);
|
|
236
234
|
return false;
|
|
237
235
|
}
|
|
238
236
|
}
|
|
@@ -281,7 +279,7 @@ export class WecomEndpoint {
|
|
|
281
279
|
expires_in: data.expires_in ?? 7200,
|
|
282
280
|
timestamp: Date.now(),
|
|
283
281
|
};
|
|
284
|
-
logger.debug('Access token refreshed successfully');
|
|
282
|
+
this.#logger.debug('Access token refreshed successfully');
|
|
285
283
|
return;
|
|
286
284
|
}
|
|
287
285
|
throw new Error(`Failed to get access token: ${data.errmsg} (${data.errcode})`);
|
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { buildSendRequestBody, decryptMessage, extractEncryptFromXml, formatInboundContent, formatOutboundBody, getAesKey, normalizeEchostrParam, normalizeWebhookPath, parseXmlMessage, queryParam, readTextBody, resolveChatType, resolveWecomConfig, verifySignature, type AccessToken, type ResolvedWecomConfig, type WecomAdapterConfig, type WecomApiResponse, type WecomMessage, type WecomSendBody, type WecomWireSegment, } from './protocol.js';
|
|
2
2
|
export { getWecomAgentDeps, registerWecomAgentEndpoint, setWecomAgentDeps, type WecomAgentDeps, type WecomAgentEndpoint, } from './wecom-agent-deps.js';
|
|
3
|
-
export { checkWecomPlatformPermit, normalizeWecomSenderForPermit, platformPermit,
|
|
3
|
+
export { checkWecomPlatformPermit, normalizeWecomSenderForPermit, platformPermit, wecomGroupPermitResolver, } from './platform-permit.js';
|
|
4
4
|
export { WecomEndpoint, type WecomEndpointOptions, type WecomFetch, } from './endpoint.js';
|
|
5
5
|
export { buildMediaUploadForm, readOutboundImageMedia, resolveMediaBinary, type MediaBinary, type WecomMediaUploadResult, } from './media-upload.js';
|
|
6
6
|
export { registerWecomWebhookRoutes, handleWecomVerificationRequest, handleWecomWebhookRequest, type WecomWebhookHandler, } from './webhook.js';
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { buildSendRequestBody, decryptMessage, extractEncryptFromXml, formatInboundContent, formatOutboundBody, getAesKey, normalizeEchostrParam, normalizeWebhookPath, parseXmlMessage, queryParam, readTextBody, resolveChatType, resolveWecomConfig, verifySignature, } from './protocol.js';
|
|
2
2
|
export { getWecomAgentDeps, registerWecomAgentEndpoint, setWecomAgentDeps, } from './wecom-agent-deps.js';
|
|
3
|
-
export { checkWecomPlatformPermit, normalizeWecomSenderForPermit, platformPermit,
|
|
3
|
+
export { checkWecomPlatformPermit, normalizeWecomSenderForPermit, platformPermit, wecomGroupPermitResolver, } from './platform-permit.js';
|
|
4
4
|
export { WecomEndpoint, } from './endpoint.js';
|
|
5
5
|
export { buildMediaUploadForm, readOutboundImageMedia, resolveMediaBinary, } from './media-upload.js';
|
|
6
6
|
export { registerWecomWebhookRoutes, handleWecomVerificationRequest, handleWecomWebhookRequest, } from './webhook.js';
|
package/lib/platform-permit.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 企业微信 WeCom 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 wecomGroupPermitResolver(logicalPerm: string): string;
|
|
7
7
|
export declare function normalizeWecomSenderForPermit(input: {
|
|
@@ -11,5 +11,4 @@ export declare function normalizeWecomSenderForPermit(input: {
|
|
|
11
11
|
role?: string;
|
|
12
12
|
permissions?: string[];
|
|
13
13
|
};
|
|
14
|
-
export declare function checkWecomPlatformPermit(perm: string,
|
|
15
|
-
export declare function registerWecomPlatformPermitChecker(): () => void;
|
|
14
|
+
export declare function checkWecomPlatformPermit(perm: string, subject: PermissionSubject): boolean;
|
package/lib/platform-permit.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 企业微信 WeCom platform permit
|
|
3
|
-
*/
|
|
4
|
-
import { registerPlatformPermitChecker } from '@zhin.js/core';
|
|
5
1
|
const ADAPTER = 'wecom';
|
|
6
2
|
export function platformPermit(perm) {
|
|
7
3
|
return `platform(${ADAPTER},${perm})`;
|
|
@@ -22,10 +18,9 @@ export function normalizeWecomSenderForPermit(input) {
|
|
|
22
18
|
}
|
|
23
19
|
return { role: 'member', permissions: [] };
|
|
24
20
|
}
|
|
25
|
-
export function checkWecomPlatformPermit(perm,
|
|
26
|
-
const
|
|
27
|
-
const permissions = sender
|
|
28
|
-
const role = sender.role;
|
|
21
|
+
export function checkWecomPlatformPermit(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 checkWecomPlatformPermit(perm, message) {
|
|
|
36
31
|
return false;
|
|
37
32
|
}
|
|
38
33
|
}
|
|
39
|
-
export function registerWecomPlatformPermitChecker() {
|
|
40
|
-
return registerPlatformPermitChecker(ADAPTER, checkWecomPlatformPermit);
|
|
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 WecomAdapterConfig {
|
|
9
|
-
readonly
|
|
9
|
+
readonly id?: string;
|
|
10
10
|
readonly corpId?: string;
|
|
11
11
|
readonly agentSecret?: string;
|
|
12
12
|
readonly token?: string;
|
|
@@ -20,7 +20,7 @@ export interface WecomAdapterConfig {
|
|
|
20
20
|
}
|
|
21
21
|
export interface ResolvedWecomConfig {
|
|
22
22
|
readonly context: 'wecom';
|
|
23
|
-
readonly
|
|
23
|
+
readonly id: string;
|
|
24
24
|
readonly corpId: string;
|
|
25
25
|
readonly agentSecret: string;
|
|
26
26
|
readonly token: string;
|
|
@@ -91,7 +91,7 @@ export declare function resolveChatType(fromUserName: string): 'group' | 'privat
|
|
|
91
91
|
* 入站归一化 → ConversationRef:WeCom 无 guild/channel 容器概念,
|
|
92
92
|
* `@chatroom` 群会话 → kind 'group',其余(应用消息/单聊)→ kind 'private'。
|
|
93
93
|
*/
|
|
94
|
-
export declare function wecomInboundConversation(
|
|
94
|
+
export declare function wecomInboundConversation(endpointKey: string, msg: WecomMessage): ConversationRef;
|
|
95
95
|
/**
|
|
96
96
|
* Wire-encode an already-rendered outbound payload into WeCom message/send body parts.
|
|
97
97
|
*/
|
package/lib/protocol.js
CHANGED
|
@@ -14,13 +14,13 @@ export function resolveWecomConfig(config = {}) {
|
|
|
14
14
|
if (!corpId || !agentSecret || !token || !encodingAESKey) {
|
|
15
15
|
throw new TypeError('WeCom adapter requires corpId + agentSecret + token + encodingAESKey (plugins.<key> or endpoints with context: wecom)');
|
|
16
16
|
}
|
|
17
|
-
const
|
|
18
|
-
|| (typeof entry?.
|
|
17
|
+
const id = (typeof config.id === 'string' && config.id)
|
|
18
|
+
|| (typeof entry?.id === 'string' && entry.id)
|
|
19
19
|
|| process.env.WECOM_BOT_NAME
|
|
20
20
|
|| 'wecom-bot';
|
|
21
21
|
return {
|
|
22
22
|
context: 'wecom',
|
|
23
|
-
|
|
23
|
+
id,
|
|
24
24
|
corpId,
|
|
25
25
|
agentSecret,
|
|
26
26
|
token,
|
|
@@ -159,9 +159,9 @@ export function resolveChatType(fromUserName) {
|
|
|
159
159
|
* 入站归一化 → ConversationRef:WeCom 无 guild/channel 容器概念,
|
|
160
160
|
* `@chatroom` 群会话 → kind 'group',其余(应用消息/单聊)→ kind 'private'。
|
|
161
161
|
*/
|
|
162
|
-
export function wecomInboundConversation(
|
|
162
|
+
export function wecomInboundConversation(endpointKey, msg) {
|
|
163
163
|
return {
|
|
164
|
-
endpoint: { id:
|
|
164
|
+
endpoint: { id: endpointKey, adapter: endpointKey.split('\0')[0] ?? endpointKey },
|
|
165
165
|
kind: resolveChatType(msg.FromUserName),
|
|
166
166
|
id: msg.FromUserName,
|
|
167
167
|
};
|
|
@@ -9,9 +9,9 @@ export interface WecomAgentEndpoint {
|
|
|
9
9
|
sendTextMessage(userId: string, content: string): Promise<boolean>;
|
|
10
10
|
}
|
|
11
11
|
export interface WecomAgentDeps {
|
|
12
|
-
getEndpoint: (
|
|
12
|
+
getEndpoint: (endpointKey: string) => WecomAgentEndpoint;
|
|
13
13
|
}
|
|
14
|
-
export declare function registerWecomAgentEndpoint(
|
|
14
|
+
export declare function registerWecomAgentEndpoint(endpointKey: string, endpoint: WecomAgentEndpoint): () => void;
|
|
15
15
|
/** Optional override used by tests / transitional callers. Pass `null` to clear. */
|
|
16
16
|
export declare function setWecomAgentDeps(deps: WecomAgentDeps | null): void;
|
|
17
17
|
export declare function getWecomAgentDeps(): WecomAgentDeps;
|
package/lib/wecom-agent-deps.js
CHANGED
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
*/
|
|
5
5
|
const endpoints = new Map();
|
|
6
6
|
let override = null;
|
|
7
|
-
export function registerWecomAgentEndpoint(
|
|
8
|
-
endpoints.set(
|
|
7
|
+
export function registerWecomAgentEndpoint(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 getWecomAgentDeps() {
|
|
|
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-wecom",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.5",
|
|
4
4
|
"description": "Zhin.js WeCom (企业微信) adapter for Plugin Runtime (HTTP webhook)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -34,22 +34,23 @@
|
|
|
34
34
|
"directory": "plugins/adapters/wecom"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@zhin.js/adapter": "1.1.
|
|
38
|
-
"@zhin.js/command": "1.0.
|
|
39
|
-
"@zhin.js/core": "1.5.
|
|
40
|
-
"@zhin.js/host-http": "1.0.
|
|
41
|
-
"@zhin.js/im-contract": "1.0.
|
|
42
|
-
"@zhin.js/logger": "1.0.
|
|
43
|
-
"@zhin.js/plugin-runtime": "1.1.
|
|
37
|
+
"@zhin.js/adapter": "1.1.7",
|
|
38
|
+
"@zhin.js/command": "1.0.9",
|
|
39
|
+
"@zhin.js/core": "1.5.4",
|
|
40
|
+
"@zhin.js/host-http": "1.0.8",
|
|
41
|
+
"@zhin.js/im-contract": "1.0.3",
|
|
42
|
+
"@zhin.js/logger": "1.0.76",
|
|
43
|
+
"@zhin.js/plugin-runtime": "1.1.5"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"zod": "^4.0.0",
|
|
47
|
-
"@zhin.js/adapter": "1.1.
|
|
48
|
-
"@zhin.js/agent": "1.1.
|
|
49
|
-
"@zhin.js/core": "1.5.
|
|
50
|
-
"@zhin.js/host-http": "1.0.
|
|
51
|
-
"@zhin.js/
|
|
52
|
-
"zhin.js": "
|
|
47
|
+
"@zhin.js/adapter": "1.1.7",
|
|
48
|
+
"@zhin.js/agent": "1.1.5",
|
|
49
|
+
"@zhin.js/core": "1.5.4",
|
|
50
|
+
"@zhin.js/host-http": "1.0.8",
|
|
51
|
+
"@zhin.js/permission": "1.0.1",
|
|
52
|
+
"@zhin.js/plugin-runtime": "1.1.5",
|
|
53
|
+
"zhin.js": "6.0.4"
|
|
53
54
|
},
|
|
54
55
|
"peerDependenciesMeta": {
|
|
55
56
|
"zhin.js": {
|
|
@@ -67,8 +68,8 @@
|
|
|
67
68
|
"typescript": "^6.0.3",
|
|
68
69
|
"vitest": "^4.1.10",
|
|
69
70
|
"zod": "^4.4.3",
|
|
70
|
-
"@zhin.js/agent": "1.1.
|
|
71
|
-
"zhin.js": "6.0.
|
|
71
|
+
"@zhin.js/agent": "1.1.5",
|
|
72
|
+
"zhin.js": "6.0.4"
|
|
72
73
|
},
|
|
73
74
|
"files": [
|
|
74
75
|
"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 { checkWecomPlatformPermit } from "./lib/platform-permit.js";
|
|
5
6
|
import { wecomRuntimeStateToken } from "./lib/wecom-runtime-state.js";
|
|
6
7
|
export default definePlugin({
|
|
7
8
|
name: 'wecom',
|
|
@@ -9,8 +10,10 @@ export default definePlugin({
|
|
|
9
10
|
displayName: 'WeCom (企业微信) Adapter',
|
|
10
11
|
},
|
|
11
12
|
setup(context) {
|
|
12
|
-
// 运行中 endpoint 注册表(wecom.endpoint list 的"运行中"数据源)
|
|
13
13
|
context.resources.provide(wecomRuntimeStateToken, createEndpointRuntimeState());
|
|
14
|
-
|
|
14
|
+
if (context.resources.has(permissionHostToken)) {
|
|
15
|
+
const host = context.resources.use(permissionHostToken);
|
|
16
|
+
return host.registerPlatform('wecom', checkWecomPlatformPermit);
|
|
17
|
+
}
|
|
15
18
|
},
|
|
16
19
|
});
|
package/schema.json
CHANGED
|
@@ -11,16 +11,48 @@
|
|
|
11
11
|
"type": "string",
|
|
12
12
|
"default": "https://qyapi.weixin.qq.com"
|
|
13
13
|
},
|
|
14
|
+
"master": {
|
|
15
|
+
"type": [
|
|
16
|
+
"string",
|
|
17
|
+
"number"
|
|
18
|
+
],
|
|
19
|
+
"description": "框架 master(WeCom userid;AI/工具权限、endpoint 管理)。endpoints[i].master 可逐项覆盖"
|
|
20
|
+
},
|
|
21
|
+
"trusted": {
|
|
22
|
+
"type": "array",
|
|
23
|
+
"items": {
|
|
24
|
+
"type": [
|
|
25
|
+
"string",
|
|
26
|
+
"number"
|
|
27
|
+
],
|
|
28
|
+
"description": "Trusted WeCom userid"
|
|
29
|
+
},
|
|
30
|
+
"description": "框架 trusted 用户列表(弱于 master)。endpoints[i].trusted 可逐项追加"
|
|
31
|
+
},
|
|
14
32
|
"endpoints": {
|
|
15
33
|
"type": "array",
|
|
16
|
-
"description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(
|
|
34
|
+
"description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(id 必填,其余覆盖顶层)",
|
|
17
35
|
"items": {
|
|
18
36
|
"type": "object",
|
|
19
37
|
"additionalProperties": true,
|
|
20
38
|
"properties": {
|
|
21
|
-
"
|
|
22
|
-
"type":
|
|
23
|
-
|
|
39
|
+
"master": {
|
|
40
|
+
"type": [
|
|
41
|
+
"string",
|
|
42
|
+
"number"
|
|
43
|
+
],
|
|
44
|
+
"description": "本 endpoint 的框架 master(WeCom userid);覆盖顶层 master"
|
|
45
|
+
},
|
|
46
|
+
"trusted": {
|
|
47
|
+
"type": "array",
|
|
48
|
+
"items": {
|
|
49
|
+
"type": [
|
|
50
|
+
"string",
|
|
51
|
+
"number"
|
|
52
|
+
],
|
|
53
|
+
"description": "Trusted WeCom userid"
|
|
54
|
+
},
|
|
55
|
+
"description": "本 endpoint 的 trusted 列表"
|
|
24
56
|
},
|
|
25
57
|
"corpId": {
|
|
26
58
|
"type": "string",
|
|
@@ -37,10 +69,14 @@
|
|
|
37
69
|
"encodingAESKey": {
|
|
38
70
|
"type": "string",
|
|
39
71
|
"description": "WeCom encoding AES key"
|
|
72
|
+
},
|
|
73
|
+
"id": {
|
|
74
|
+
"type": "string",
|
|
75
|
+
"description": "WeCom bot name"
|
|
40
76
|
}
|
|
41
77
|
},
|
|
42
78
|
"required": [
|
|
43
|
-
"
|
|
79
|
+
"id",
|
|
44
80
|
"corpId",
|
|
45
81
|
"agentSecret",
|
|
46
82
|
"token",
|
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 { registerWecomAgentEndpoint } from './wecom-agent-deps.js';
|
|
10
10
|
import {
|
|
@@ -26,8 +26,6 @@ import {
|
|
|
26
26
|
} from './protocol.js';
|
|
27
27
|
import { registerWecomWebhookRoutes } from './webhook.js';
|
|
28
28
|
|
|
29
|
-
const logger = getLogger('wecom');
|
|
30
|
-
|
|
31
29
|
export type WecomFetch = (
|
|
32
30
|
url: string,
|
|
33
31
|
init?: {
|
|
@@ -56,6 +54,8 @@ export interface WecomEndpointOptions {
|
|
|
56
54
|
* 因此本 endpoint 不暴露 EndpointManagement(Console 社交面 RPC 对该平台保持未接线)。
|
|
57
55
|
*/
|
|
58
56
|
export class WecomEndpoint implements EndpointInstance {
|
|
57
|
+
readonly #logger!: ReturnType<typeof getAdapterLogger>;
|
|
58
|
+
|
|
59
59
|
readonly #options: WecomEndpointOptions;
|
|
60
60
|
readonly #fetch: WecomFetch;
|
|
61
61
|
#routeReleases: HttpRouteRegistration[] = [];
|
|
@@ -66,6 +66,7 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
66
66
|
#unregisterAgent?: () => void;
|
|
67
67
|
|
|
68
68
|
constructor(options: WecomEndpointOptions) {
|
|
69
|
+
this.#logger = getAdapterLogger('wecom', options.config.id);
|
|
69
70
|
this.#options = options;
|
|
70
71
|
this.#fetch = options.fetch ?? globalThis.fetch;
|
|
71
72
|
}
|
|
@@ -84,16 +85,16 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
84
85
|
this.#started = true;
|
|
85
86
|
try {
|
|
86
87
|
await this.#refreshAccessToken();
|
|
87
|
-
this.#unregisterAgent = registerWecomAgentEndpoint(this.#options.config.
|
|
88
|
+
this.#unregisterAgent = registerWecomAgentEndpoint(this.#options.config.id, this);
|
|
88
89
|
this.#routeReleases.push(...registerWecomWebhookRoutes(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 WeCom endpoint:', error);
|
|
97
|
+
this.#logger.error('Failed to connect WeCom endpoint:', error);
|
|
97
98
|
throw error;
|
|
98
99
|
}
|
|
99
100
|
}
|
|
@@ -112,7 +113,7 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
112
113
|
this.#unregisterAgent?.();
|
|
113
114
|
this.#unregisterAgent = undefined;
|
|
114
115
|
this.#started = false;
|
|
115
|
-
logger.debug(formatCompact({ op: 'disconnect'
|
|
116
|
+
this.#logger.debug(formatCompact({ op: 'disconnect' }));
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
|
|
@@ -131,10 +132,7 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
131
132
|
if (data.errcode !== 0) {
|
|
132
133
|
throw new Error(`Failed to send message: ${data.errmsg} (${data.errcode})`);
|
|
133
134
|
}
|
|
134
|
-
logger.debug(formatCompact({
|
|
135
|
-
op: 'send',
|
|
136
|
-
endpoint: this.#options.config.name,
|
|
137
|
-
to: `${conversation.kind}:${conversation.id}`,
|
|
135
|
+
this.#logger.debug(formatCompact({ op: 'send', to: `${conversation.kind}:${conversation.id}`,
|
|
138
136
|
}));
|
|
139
137
|
return (data.msgid as string) || `${Date.now()}`;
|
|
140
138
|
}
|
|
@@ -162,9 +160,9 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
162
160
|
const data = seg.data ?? {};
|
|
163
161
|
const media = readOutboundImageMedia(data);
|
|
164
162
|
if (!media) {
|
|
165
|
-
logger.warn(formatCompact({
|
|
163
|
+
this.#logger.warn(formatCompact({
|
|
166
164
|
op: 'wecom_outbound_media_dropped',
|
|
167
|
-
endpoint: this.#options.config.
|
|
165
|
+
endpoint: this.#options.config.id,
|
|
168
166
|
type: 'image',
|
|
169
167
|
reason: 'missing_media_ref',
|
|
170
168
|
}));
|
|
@@ -177,9 +175,9 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
177
175
|
const mediaId = await this.#uploadMedia('image', media);
|
|
178
176
|
return { type: 'image', data: { media_id: mediaId } };
|
|
179
177
|
} catch (error) {
|
|
180
|
-
logger.warn(formatCompact({
|
|
178
|
+
this.#logger.warn(formatCompact({
|
|
181
179
|
op: 'wecom_media_upload_failed',
|
|
182
|
-
endpoint: this.#options.config.
|
|
180
|
+
endpoint: this.#options.config.id,
|
|
183
181
|
error: error instanceof Error ? error.message : String(error),
|
|
184
182
|
}));
|
|
185
183
|
const alt = typeof data.alt === 'string' && data.alt ? data.alt : '[image]';
|
|
@@ -210,17 +208,17 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
210
208
|
conversation,
|
|
211
209
|
message: { conversation, id: msg.MsgId || `${msg.CreateTime}` },
|
|
212
210
|
content: formatInboundContent(msg),
|
|
213
|
-
sender: msg.FromUserName,
|
|
211
|
+
sender: { id: msg.FromUserName },
|
|
212
|
+
endpointId: this.#options.config.id,
|
|
214
213
|
metadata: Object.freeze({
|
|
215
214
|
msgType: msg.MsgType,
|
|
216
215
|
event: msg.Event,
|
|
217
216
|
chatType,
|
|
218
|
-
endpoint: this.#options.config.name,
|
|
219
217
|
toUserName: msg.ToUserName,
|
|
220
218
|
agentId: msg.AgentID,
|
|
221
219
|
}),
|
|
222
220
|
}).catch((err) => {
|
|
223
|
-
logger.warn(formatCompact({
|
|
221
|
+
this.#logger.warn(formatCompact({
|
|
224
222
|
op: 'wecom_gateway_receive_failed',
|
|
225
223
|
target: `${conversation.kind}:${conversation.id}`,
|
|
226
224
|
error: err instanceof Error ? err.message : String(err),
|
|
@@ -236,7 +234,7 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
236
234
|
if (data.errcode === 0) return data;
|
|
237
235
|
throw new Error(`Failed to get user info: ${data.errmsg}`);
|
|
238
236
|
} catch (error) {
|
|
239
|
-
logger.error('Failed to get user info:', error);
|
|
237
|
+
this.#logger.error('Failed to get user info:', error);
|
|
240
238
|
return null;
|
|
241
239
|
}
|
|
242
240
|
}
|
|
@@ -249,7 +247,7 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
249
247
|
if (data.errcode === 0) return (data.userlist as unknown[]) || [];
|
|
250
248
|
throw new Error(`Failed to get department users: ${data.errmsg}`);
|
|
251
249
|
} catch (error) {
|
|
252
|
-
logger.error('Failed to get department users:', error);
|
|
250
|
+
this.#logger.error('Failed to get department users:', error);
|
|
253
251
|
return [];
|
|
254
252
|
}
|
|
255
253
|
}
|
|
@@ -262,17 +260,17 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
262
260
|
if (data.errcode === 0) return (data.department as unknown[]) || [];
|
|
263
261
|
throw new Error(`Failed to get department list: ${data.errmsg}`);
|
|
264
262
|
} catch (error) {
|
|
265
|
-
logger.error('Failed to get department list:', error);
|
|
263
|
+
this.#logger.error('Failed to get department list:', error);
|
|
266
264
|
return [];
|
|
267
265
|
}
|
|
268
266
|
}
|
|
269
267
|
|
|
270
268
|
async sendTextMessage(userId: string, content: string): Promise<boolean> {
|
|
271
269
|
try {
|
|
272
|
-
const
|
|
270
|
+
const endpointKey = String(this.#options.id);
|
|
273
271
|
await this.send({
|
|
274
272
|
conversation: {
|
|
275
|
-
endpoint: { id:
|
|
273
|
+
endpoint: { id: endpointKey, adapter: endpointKey.split('\0')[0] ?? endpointKey },
|
|
276
274
|
kind: resolveChatType(userId),
|
|
277
275
|
id: userId,
|
|
278
276
|
},
|
|
@@ -280,7 +278,7 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
280
278
|
});
|
|
281
279
|
return true;
|
|
282
280
|
} catch (error) {
|
|
283
|
-
logger.error('Failed to send text message:', error);
|
|
281
|
+
this.#logger.error('Failed to send text message:', error);
|
|
284
282
|
return false;
|
|
285
283
|
}
|
|
286
284
|
}
|
|
@@ -343,7 +341,7 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
343
341
|
expires_in: data.expires_in ?? 7200,
|
|
344
342
|
timestamp: Date.now(),
|
|
345
343
|
};
|
|
346
|
-
logger.debug('Access token refreshed successfully');
|
|
344
|
+
this.#logger.debug('Access token refreshed successfully');
|
|
347
345
|
return;
|
|
348
346
|
}
|
|
349
347
|
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
|
* 企业微信 WeCom platform permit
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import type { PermissionSubject } from '@zhin.js/permission';
|
|
5
5
|
|
|
6
6
|
const ADAPTER = 'wecom';
|
|
7
7
|
|
|
@@ -31,10 +31,9 @@ export function normalizeWecomSenderForPermit(input: {
|
|
|
31
31
|
return { role: 'member', permissions: [] };
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
export function checkWecomPlatformPermit(perm: string,
|
|
35
|
-
const
|
|
36
|
-
const permissions = sender
|
|
37
|
-
const role = sender.role;
|
|
34
|
+
export function checkWecomPlatformPermit(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 checkWecomPlatformPermit(perm: string, message: Message<any>): b
|
|
|
47
46
|
}
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
export function registerWecomPlatformPermitChecker(): () => void {
|
|
51
|
-
return registerPlatformPermitChecker(ADAPTER, checkWecomPlatformPermit);
|
|
52
|
-
}
|
package/src/protocol.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { ConversationRef } from '@zhin.js/im-contract';
|
|
|
9
9
|
|
|
10
10
|
/** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
|
|
11
11
|
export interface WecomAdapterConfig {
|
|
12
|
-
readonly
|
|
12
|
+
readonly id?: string;
|
|
13
13
|
readonly corpId?: string;
|
|
14
14
|
readonly agentSecret?: string;
|
|
15
15
|
readonly token?: string;
|
|
@@ -24,7 +24,7 @@ export interface WecomAdapterConfig {
|
|
|
24
24
|
|
|
25
25
|
export interface ResolvedWecomConfig {
|
|
26
26
|
readonly context: 'wecom';
|
|
27
|
-
readonly
|
|
27
|
+
readonly id: string;
|
|
28
28
|
readonly corpId: string;
|
|
29
29
|
readonly agentSecret: string;
|
|
30
30
|
readonly token: string;
|
|
@@ -97,13 +97,13 @@ export function resolveWecomConfig(config: WecomAdapterConfig = {}): ResolvedWec
|
|
|
97
97
|
'WeCom adapter requires corpId + agentSecret + token + encodingAESKey (plugins.<key> or endpoints with context: wecom)',
|
|
98
98
|
);
|
|
99
99
|
}
|
|
100
|
-
const
|
|
101
|
-
|| (typeof entry?.
|
|
100
|
+
const id = (typeof config.id === 'string' && config.id)
|
|
101
|
+
|| (typeof entry?.id === 'string' && entry.id)
|
|
102
102
|
|| process.env.WECOM_BOT_NAME
|
|
103
103
|
|| 'wecom-bot';
|
|
104
104
|
return {
|
|
105
105
|
context: 'wecom',
|
|
106
|
-
|
|
106
|
+
id,
|
|
107
107
|
corpId,
|
|
108
108
|
agentSecret,
|
|
109
109
|
token,
|
|
@@ -260,9 +260,9 @@ export function resolveChatType(fromUserName: string): 'group' | 'private' {
|
|
|
260
260
|
* 入站归一化 → ConversationRef:WeCom 无 guild/channel 容器概念,
|
|
261
261
|
* `@chatroom` 群会话 → kind 'group',其余(应用消息/单聊)→ kind 'private'。
|
|
262
262
|
*/
|
|
263
|
-
export function wecomInboundConversation(
|
|
263
|
+
export function wecomInboundConversation(endpointKey: string, msg: WecomMessage): ConversationRef {
|
|
264
264
|
return {
|
|
265
|
-
endpoint: { id:
|
|
265
|
+
endpoint: { id: endpointKey, adapter: endpointKey.split('\0')[0] ?? endpointKey },
|
|
266
266
|
kind: resolveChatType(msg.FromUserName),
|
|
267
267
|
id: msg.FromUserName,
|
|
268
268
|
};
|
package/src/wecom-agent-deps.ts
CHANGED
|
@@ -11,20 +11,20 @@ export interface WecomAgentEndpoint {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export interface WecomAgentDeps {
|
|
14
|
-
getEndpoint: (
|
|
14
|
+
getEndpoint: (endpointKey: string) => WecomAgentEndpoint;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
const endpoints = new Map<string, WecomAgentEndpoint>();
|
|
18
18
|
let override: WecomAgentDeps | null = null;
|
|
19
19
|
|
|
20
20
|
export function registerWecomAgentEndpoint(
|
|
21
|
-
|
|
21
|
+
endpointKey: string,
|
|
22
22
|
endpoint: WecomAgentEndpoint,
|
|
23
23
|
): () => void {
|
|
24
|
-
endpoints.set(
|
|
24
|
+
endpoints.set(endpointKey, endpoint);
|
|
25
25
|
return () => {
|
|
26
|
-
if (endpoints.get(
|
|
27
|
-
endpoints.delete(
|
|
26
|
+
if (endpoints.get(endpointKey) === endpoint) {
|
|
27
|
+
endpoints.delete(endpointKey);
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
30
|
}
|
|
@@ -37,9 +37,9 @@ export function setWecomAgentDeps(deps: WecomAgentDeps | null): void {
|
|
|
37
37
|
export function getWecomAgentDeps(): WecomAgentDeps {
|
|
38
38
|
if (override) return override;
|
|
39
39
|
return {
|
|
40
|
-
getEndpoint(
|
|
41
|
-
const endpoint = endpoints.get(
|
|
42
|
-
if (!endpoint) throw new Error(`Endpoint ${
|
|
40
|
+
getEndpoint(endpointKey) {
|
|
41
|
+
const endpoint = endpoints.get(endpointKey);
|
|
42
|
+
if (!endpoint) throw new Error(`Endpoint ${endpointKey} 不存在`);
|
|
43
43
|
return endpoint;
|
|
44
44
|
},
|
|
45
45
|
};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|