@zhin.js/adapter-wecom 4.0.2 → 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 CHANGED
@@ -1,5 +1,100 @@
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
+
82
+ ## 4.0.3
83
+
84
+ ### Patch Changes
85
+
86
+ - Updated dependencies [afc0e66]
87
+ - Updated dependencies [2e41ad5]
88
+ - Updated dependencies [9f57124]
89
+ - @zhin.js/core@1.5.2
90
+ - @zhin.js/adapter@1.1.5
91
+ - @zhin.js/im-contract@1.0.1
92
+ - @zhin.js/plugin-runtime@1.1.3
93
+ - @zhin.js/command@1.0.7
94
+ - @zhin.js/host-http@1.0.6
95
+ - @zhin.js/agent@1.1.3
96
+ - zhin.js@6.0.2
97
+
3
98
  ## 4.0.2
4
99
 
5
100
  ### Patch Changes
package/README.md CHANGED
@@ -23,8 +23,8 @@ pnpm add @zhin.js/adapter-wecom
23
23
  - `@zhin.js/plugin-runtime` — `plugin.ts`(`definePlugin`)
24
24
  - 配置经插件 `schema.json` 落到 `plugins.<instanceKey>`
25
25
 
26
- 入站:`gateway.receive({ adapter, target: FromUserName, content: text, sender, metadata })`
27
- 出站:`send({ target, payload })` → 企业微信 `message/send` API
26
+ 入站:`gateway.receive({ conversation, message: { conversation, id: MsgId }, content: text, sender, metadata })`(`conversation` 为 `ConversationRef`,`@chatroom` → kind `group`,其余 → kind `private`)
27
+ 出站:`send({ conversation, payload })` → 企业微信 `message/send` API
28
28
 
29
29
  入站 `metadata.mentioned`:**未接线**。企业微信应用消息回调的 XML 事件不含 mentions/@ 字段,回调里的 `ToUserName` 是 CorpID(企业 ID)而非可比较的 bot 用户 id,配置中也没有 bot id/name 可作可靠判据,故无法可靠识别 @ 机器人。
30
30
 
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.name, {
25
- name: config.name,
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.name, {
30
- name: config.name,
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.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * WecomEndpoint — lifecycle, outbound send, inbound admit, OpenAPI helpers for agent tools.
3
3
  */
4
- import type { EndpointInstance } from '@zhin.js/adapter';
4
+ import type { EndpointInstance, EndpointSendRequest } from '@zhin.js/adapter';
5
5
  import type { MessageGateway } from '@zhin.js/core/runtime';
6
6
  import type { HttpHost } from '@zhin.js/host-http';
7
7
  import type { CapabilityId } from '@zhin.js/plugin-runtime';
@@ -38,10 +38,7 @@ export declare class WecomEndpoint implements EndpointInstance {
38
38
  open(): void;
39
39
  close(): void;
40
40
  stop(): Promise<void>;
41
- send({ target, payload }: {
42
- readonly target: string;
43
- readonly payload: unknown;
44
- }): Promise<string>;
41
+ send({ conversation, payload }: EndpointSendRequest): Promise<string>;
45
42
  recallMessage(messageId: string): Promise<void>;
46
43
  /** Test / internal: admit a parsed message when open (non-webhook path). */
47
44
  admit(msg: WecomMessage): void;
package/lib/endpoint.js CHANGED
@@ -1,15 +1,15 @@
1
- import { formatCompact, getLogger } from '@zhin.js/logger';
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
- import { buildSendRequestBody, formatInboundContent, formatOutboundBody, resolveChatType, } from './protocol.js';
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.name, this);
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.name,
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,12 +63,12 @@ export class WecomEndpoint {
62
63
  this.#unregisterAgent?.();
63
64
  this.#unregisterAgent = undefined;
64
65
  this.#started = false;
65
- logger.debug(formatCompact({ op: 'disconnect', endpoint: this.#options.config.name }));
66
+ this.#logger.debug(formatCompact({ op: 'disconnect' }));
66
67
  }
67
- async send({ target, payload }) {
68
+ async send({ conversation, payload }) {
68
69
  const materialized = await this.#materializeOutboundMedia(payload);
69
70
  const content = formatOutboundBody(materialized);
70
- const body = buildSendRequestBody(target, content,
71
+ const body = buildSendRequestBody(conversation.id, content,
71
72
  // Legacy field: historically written into agentid (preserved for cutover).
72
73
  this.#options.config.agentSecret);
73
74
  const data = await this.#request('/cgi-bin/message/send', {
@@ -77,7 +78,8 @@ 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({ op: 'send', endpoint: this.#options.config.name, to: target }));
81
+ this.#logger.debug(formatCompact({ op: 'send', to: `${conversation.kind}:${conversation.id}`,
82
+ }));
81
83
  return data.msgid || `${Date.now()}`;
82
84
  }
83
85
  async recallMessage(messageId) {
@@ -106,9 +108,9 @@ export class WecomEndpoint {
106
108
  const data = seg.data ?? {};
107
109
  const media = readOutboundImageMedia(data);
108
110
  if (!media) {
109
- logger.warn(formatCompact({
111
+ this.#logger.warn(formatCompact({
110
112
  op: 'wecom_outbound_media_dropped',
111
- endpoint: this.#options.config.name,
113
+ endpoint: this.#options.config.id,
112
114
  type: 'image',
113
115
  reason: 'missing_media_ref',
114
116
  }));
@@ -122,9 +124,9 @@ export class WecomEndpoint {
122
124
  return { type: 'image', data: { media_id: mediaId } };
123
125
  }
124
126
  catch (error) {
125
- logger.warn(formatCompact({
127
+ this.#logger.warn(formatCompact({
126
128
  op: 'wecom_media_upload_failed',
127
- endpoint: this.#options.config.name,
129
+ endpoint: this.#options.config.id,
128
130
  error: error instanceof Error ? error.message : String(error),
129
131
  }));
130
132
  const alt = typeof data.alt === 'string' && data.alt ? data.alt : '[image]';
@@ -150,24 +152,24 @@ export class WecomEndpoint {
150
152
  if (!this.#open)
151
153
  return;
152
154
  const chatType = resolveChatType(msg.FromUserName);
155
+ const conversation = wecomInboundConversation(String(this.#options.id), msg);
153
156
  void this.#options.gateway.receive({
154
- adapter: this.#options.id,
155
- target: msg.FromUserName,
157
+ conversation,
158
+ message: { conversation, id: msg.MsgId || `${msg.CreateTime}` },
156
159
  content: formatInboundContent(msg),
157
- sender: msg.FromUserName,
158
- id: msg.MsgId || `${msg.CreateTime}`,
160
+ sender: { id: msg.FromUserName },
161
+ endpointId: this.#options.config.id,
159
162
  metadata: Object.freeze({
160
163
  msgType: msg.MsgType,
161
164
  event: msg.Event,
162
165
  chatType,
163
- endpoint: this.#options.config.name,
164
166
  toUserName: msg.ToUserName,
165
167
  agentId: msg.AgentID,
166
168
  }),
167
169
  }).catch((err) => {
168
- logger.warn(formatCompact({
170
+ this.#logger.warn(formatCompact({
169
171
  op: 'wecom_gateway_receive_failed',
170
- target: msg.FromUserName,
172
+ target: `${conversation.kind}:${conversation.id}`,
171
173
  error: err instanceof Error ? err.message : String(err),
172
174
  }));
173
175
  });
@@ -182,7 +184,7 @@ export class WecomEndpoint {
182
184
  throw new Error(`Failed to get user info: ${data.errmsg}`);
183
185
  }
184
186
  catch (error) {
185
- logger.error('Failed to get user info:', error);
187
+ this.#logger.error('Failed to get user info:', error);
186
188
  return null;
187
189
  }
188
190
  }
@@ -196,7 +198,7 @@ export class WecomEndpoint {
196
198
  throw new Error(`Failed to get department users: ${data.errmsg}`);
197
199
  }
198
200
  catch (error) {
199
- logger.error('Failed to get department users:', error);
201
+ this.#logger.error('Failed to get department users:', error);
200
202
  return [];
201
203
  }
202
204
  }
@@ -210,17 +212,25 @@ export class WecomEndpoint {
210
212
  throw new Error(`Failed to get department list: ${data.errmsg}`);
211
213
  }
212
214
  catch (error) {
213
- logger.error('Failed to get department list:', error);
215
+ this.#logger.error('Failed to get department list:', error);
214
216
  return [];
215
217
  }
216
218
  }
217
219
  async sendTextMessage(userId, content) {
218
220
  try {
219
- await this.send({ target: userId, payload: content });
221
+ const endpointKey = String(this.#options.id);
222
+ await this.send({
223
+ conversation: {
224
+ endpoint: { id: endpointKey, adapter: endpointKey.split('\0')[0] ?? endpointKey },
225
+ kind: resolveChatType(userId),
226
+ id: userId,
227
+ },
228
+ payload: content,
229
+ });
220
230
  return true;
221
231
  }
222
232
  catch (error) {
223
- logger.error('Failed to send text message:', error);
233
+ this.#logger.error('Failed to send text message:', error);
224
234
  return false;
225
235
  }
226
236
  }
@@ -269,7 +279,7 @@ export class WecomEndpoint {
269
279
  expires_in: data.expires_in ?? 7200,
270
280
  timestamp: Date.now(),
271
281
  };
272
- logger.debug('Access token refreshed successfully');
282
+ this.#logger.debug('Access token refreshed successfully');
273
283
  return;
274
284
  }
275
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, registerWecomPlatformPermitChecker, wecomGroupPermitResolver, } from './platform-permit.js';
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, registerWecomPlatformPermitChecker, wecomGroupPermitResolver, } from './platform-permit.js';
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';
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * 企业微信 WeCom platform permit
3
3
  */
4
- import { type Message } from '@zhin.js/core';
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, message: Message<any>): boolean;
15
- export declare function registerWecomPlatformPermitChecker(): () => void;
14
+ export declare function checkWecomPlatformPermit(perm: string, subject: PermissionSubject): boolean;
@@ -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, message) {
26
- const sender = message.$sender;
27
- const permissions = sender.permissions ?? [];
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
@@ -3,9 +3,10 @@
3
3
  * Canonicalization is owned by gateway/core before endpoint.send.
4
4
  */
5
5
  import type { IncomingMessage } from 'node:http';
6
+ import type { ConversationRef } from '@zhin.js/im-contract';
6
7
  /** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
7
8
  export interface WecomAdapterConfig {
8
- readonly name?: string;
9
+ readonly id?: string;
9
10
  readonly corpId?: string;
10
11
  readonly agentSecret?: string;
11
12
  readonly token?: string;
@@ -19,7 +20,7 @@ export interface WecomAdapterConfig {
19
20
  }
20
21
  export interface ResolvedWecomConfig {
21
22
  readonly context: 'wecom';
22
- readonly name: string;
23
+ readonly id: string;
23
24
  readonly corpId: string;
24
25
  readonly agentSecret: string;
25
26
  readonly token: string;
@@ -86,6 +87,11 @@ export declare function parseXmlMessage(xml: string): WecomMessage | null;
86
87
  /** Build inbound text for MessageGateway.receive. */
87
88
  export declare function formatInboundContent(msg: WecomMessage): string;
88
89
  export declare function resolveChatType(fromUserName: string): 'group' | 'private';
90
+ /**
91
+ * 入站归一化 → ConversationRef:WeCom 无 guild/channel 容器概念,
92
+ * `@chatroom` 群会话 → kind 'group',其余(应用消息/单聊)→ kind 'private'。
93
+ */
94
+ export declare function wecomInboundConversation(endpointKey: string, msg: WecomMessage): ConversationRef;
89
95
  /**
90
96
  * Wire-encode an already-rendered outbound payload into WeCom message/send body parts.
91
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 name = (typeof config.name === 'string' && config.name)
18
- || (typeof entry?.name === 'string' && entry.name)
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
- name,
23
+ id,
24
24
  corpId,
25
25
  agentSecret,
26
26
  token,
@@ -155,6 +155,17 @@ export function formatInboundContent(msg) {
155
155
  export function resolveChatType(fromUserName) {
156
156
  return fromUserName.endsWith('@chatroom') ? 'group' : 'private';
157
157
  }
158
+ /**
159
+ * 入站归一化 → ConversationRef:WeCom 无 guild/channel 容器概念,
160
+ * `@chatroom` 群会话 → kind 'group',其余(应用消息/单聊)→ kind 'private'。
161
+ */
162
+ export function wecomInboundConversation(endpointKey, msg) {
163
+ return {
164
+ endpoint: { id: endpointKey, adapter: endpointKey.split('\0')[0] ?? endpointKey },
165
+ kind: resolveChatType(msg.FromUserName),
166
+ id: msg.FromUserName,
167
+ };
168
+ }
158
169
  /**
159
170
  * Wire-encode an already-rendered outbound payload into WeCom message/send body parts.
160
171
  */
@@ -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: (endpointId: string) => WecomAgentEndpoint;
12
+ getEndpoint: (endpointKey: string) => WecomAgentEndpoint;
13
13
  }
14
- export declare function registerWecomAgentEndpoint(endpointId: string, endpoint: WecomAgentEndpoint): () => void;
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;
@@ -4,11 +4,11 @@
4
4
  */
5
5
  const endpoints = new Map();
6
6
  let override = null;
7
- export function registerWecomAgentEndpoint(endpointId, endpoint) {
8
- endpoints.set(endpointId, endpoint);
7
+ export function registerWecomAgentEndpoint(endpointKey, endpoint) {
8
+ endpoints.set(endpointKey, endpoint);
9
9
  return () => {
10
- if (endpoints.get(endpointId) === endpoint) {
11
- endpoints.delete(endpointId);
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(endpointId) {
24
- const endpoint = endpoints.get(endpointId);
23
+ getEndpoint(endpointKey) {
24
+ const endpoint = endpoints.get(endpointKey);
25
25
  if (!endpoint)
26
- throw new Error(`Endpoint ${endpointId} 不存在`);
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.2",
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,21 +34,23 @@
34
34
  "directory": "plugins/adapters/wecom"
35
35
  },
36
36
  "dependencies": {
37
- "@zhin.js/adapter": "1.1.4",
38
- "@zhin.js/command": "1.0.6",
39
- "@zhin.js/core": "1.5.1",
40
- "@zhin.js/host-http": "1.0.5",
41
- "@zhin.js/logger": "1.0.75",
42
- "@zhin.js/plugin-runtime": "1.1.2"
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"
43
44
  },
44
45
  "peerDependencies": {
45
46
  "zod": "^4.0.0",
46
- "@zhin.js/adapter": "1.1.4",
47
- "@zhin.js/agent": "1.1.2",
48
- "@zhin.js/core": "1.5.1",
49
- "@zhin.js/host-http": "1.0.5",
50
- "@zhin.js/plugin-runtime": "1.1.2",
51
- "zhin.js": "6.0.1"
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"
52
54
  },
53
55
  "peerDependenciesMeta": {
54
56
  "zhin.js": {
@@ -66,8 +68,8 @@
66
68
  "typescript": "^6.0.3",
67
69
  "vitest": "^4.1.10",
68
70
  "zod": "^4.4.3",
69
- "@zhin.js/agent": "1.1.2",
70
- "zhin.js": "6.0.1"
71
+ "@zhin.js/agent": "1.1.5",
72
+ "zhin.js": "6.0.4"
71
73
  },
72
74
  "files": [
73
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 { registerWecomPlatformPermitChecker } from "./lib/platform-permit.js";
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
- return registerWecomPlatformPermitChecker();
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。每项与顶层字段同构(name 必填,其余覆盖顶层)",
34
+ "description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(id 必填,其余覆盖顶层)",
17
35
  "items": {
18
36
  "type": "object",
19
37
  "additionalProperties": true,
20
38
  "properties": {
21
- "name": {
22
- "type": "string",
23
- "description": "WeCom bot name"
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
- "name",
79
+ "id",
44
80
  "corpId",
45
81
  "agentSecret",
46
82
  "token",
package/src/endpoint.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * WecomEndpoint — lifecycle, outbound send, inbound admit, OpenAPI helpers for agent tools.
3
3
  */
4
- import type { EndpointInstance } from '@zhin.js/adapter';
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, getLogger } from '@zhin.js/logger';
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 {
@@ -18,6 +18,7 @@ import {
18
18
  formatInboundContent,
19
19
  formatOutboundBody,
20
20
  resolveChatType,
21
+ wecomInboundConversation,
21
22
  type AccessToken,
22
23
  type ResolvedWecomConfig,
23
24
  type WecomApiResponse,
@@ -25,8 +26,6 @@ import {
25
26
  } from './protocol.js';
26
27
  import { registerWecomWebhookRoutes } from './webhook.js';
27
28
 
28
- const logger = getLogger('wecom');
29
-
30
29
  export type WecomFetch = (
31
30
  url: string,
32
31
  init?: {
@@ -55,6 +54,8 @@ export interface WecomEndpointOptions {
55
54
  * 因此本 endpoint 不暴露 EndpointManagement(Console 社交面 RPC 对该平台保持未接线)。
56
55
  */
57
56
  export class WecomEndpoint implements EndpointInstance {
57
+ readonly #logger!: ReturnType<typeof getAdapterLogger>;
58
+
58
59
  readonly #options: WecomEndpointOptions;
59
60
  readonly #fetch: WecomFetch;
60
61
  #routeReleases: HttpRouteRegistration[] = [];
@@ -65,6 +66,7 @@ export class WecomEndpoint implements EndpointInstance {
65
66
  #unregisterAgent?: () => void;
66
67
 
67
68
  constructor(options: WecomEndpointOptions) {
69
+ this.#logger = getAdapterLogger('wecom', options.config.id);
68
70
  this.#options = options;
69
71
  this.#fetch = options.fetch ?? globalThis.fetch;
70
72
  }
@@ -83,16 +85,16 @@ export class WecomEndpoint implements EndpointInstance {
83
85
  this.#started = true;
84
86
  try {
85
87
  await this.#refreshAccessToken();
86
- this.#unregisterAgent = registerWecomAgentEndpoint(this.#options.config.name, this);
88
+ this.#unregisterAgent = registerWecomAgentEndpoint(this.#options.config.id, this);
87
89
  this.#routeReleases.push(...registerWecomWebhookRoutes(this.#options.http, this));
88
- logger.debug(formatCompact({
89
- endpoint: this.#options.config.name,
90
+ this.#logger.debug(formatCompact({
91
+ endpoint: this.#options.config.id,
90
92
  op: 'webhook',
91
93
  path: this.#options.config.webhookPath,
92
94
  }));
93
95
  } catch (error) {
94
96
  await this.stop();
95
- logger.error('Failed to connect WeCom endpoint:', error);
97
+ this.#logger.error('Failed to connect WeCom endpoint:', error);
96
98
  throw error;
97
99
  }
98
100
  }
@@ -111,14 +113,14 @@ export class WecomEndpoint implements EndpointInstance {
111
113
  this.#unregisterAgent?.();
112
114
  this.#unregisterAgent = undefined;
113
115
  this.#started = false;
114
- logger.debug(formatCompact({ op: 'disconnect', endpoint: this.#options.config.name }));
116
+ this.#logger.debug(formatCompact({ op: 'disconnect' }));
115
117
  }
116
118
 
117
- async send({ target, payload }: { readonly target: string; readonly payload: unknown }): Promise<string> {
119
+ async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
118
120
  const materialized = await this.#materializeOutboundMedia(payload);
119
121
  const content = formatOutboundBody(materialized);
120
122
  const body = buildSendRequestBody(
121
- target,
123
+ conversation.id,
122
124
  content,
123
125
  // Legacy field: historically written into agentid (preserved for cutover).
124
126
  this.#options.config.agentSecret,
@@ -130,7 +132,8 @@ export class WecomEndpoint implements EndpointInstance {
130
132
  if (data.errcode !== 0) {
131
133
  throw new Error(`Failed to send message: ${data.errmsg} (${data.errcode})`);
132
134
  }
133
- logger.debug(formatCompact({ op: 'send', endpoint: this.#options.config.name, to: target }));
135
+ this.#logger.debug(formatCompact({ op: 'send', to: `${conversation.kind}:${conversation.id}`,
136
+ }));
134
137
  return (data.msgid as string) || `${Date.now()}`;
135
138
  }
136
139
 
@@ -157,9 +160,9 @@ export class WecomEndpoint implements EndpointInstance {
157
160
  const data = seg.data ?? {};
158
161
  const media = readOutboundImageMedia(data);
159
162
  if (!media) {
160
- logger.warn(formatCompact({
163
+ this.#logger.warn(formatCompact({
161
164
  op: 'wecom_outbound_media_dropped',
162
- endpoint: this.#options.config.name,
165
+ endpoint: this.#options.config.id,
163
166
  type: 'image',
164
167
  reason: 'missing_media_ref',
165
168
  }));
@@ -172,9 +175,9 @@ export class WecomEndpoint implements EndpointInstance {
172
175
  const mediaId = await this.#uploadMedia('image', media);
173
176
  return { type: 'image', data: { media_id: mediaId } };
174
177
  } catch (error) {
175
- logger.warn(formatCompact({
178
+ this.#logger.warn(formatCompact({
176
179
  op: 'wecom_media_upload_failed',
177
- endpoint: this.#options.config.name,
180
+ endpoint: this.#options.config.id,
178
181
  error: error instanceof Error ? error.message : String(error),
179
182
  }));
180
183
  const alt = typeof data.alt === 'string' && data.alt ? data.alt : '[image]';
@@ -200,24 +203,24 @@ export class WecomEndpoint implements EndpointInstance {
200
203
  admit(msg: WecomMessage): void {
201
204
  if (!this.#open) return;
202
205
  const chatType = resolveChatType(msg.FromUserName);
206
+ const conversation = wecomInboundConversation(String(this.#options.id), msg);
203
207
  void this.#options.gateway.receive({
204
- adapter: this.#options.id,
205
- target: msg.FromUserName,
208
+ conversation,
209
+ message: { conversation, id: msg.MsgId || `${msg.CreateTime}` },
206
210
  content: formatInboundContent(msg),
207
- sender: msg.FromUserName,
208
- id: msg.MsgId || `${msg.CreateTime}`,
211
+ sender: { id: msg.FromUserName },
212
+ endpointId: this.#options.config.id,
209
213
  metadata: Object.freeze({
210
214
  msgType: msg.MsgType,
211
215
  event: msg.Event,
212
216
  chatType,
213
- endpoint: this.#options.config.name,
214
217
  toUserName: msg.ToUserName,
215
218
  agentId: msg.AgentID,
216
219
  }),
217
220
  }).catch((err) => {
218
- logger.warn(formatCompact({
221
+ this.#logger.warn(formatCompact({
219
222
  op: 'wecom_gateway_receive_failed',
220
- target: msg.FromUserName,
223
+ target: `${conversation.kind}:${conversation.id}`,
221
224
  error: err instanceof Error ? err.message : String(err),
222
225
  }));
223
226
  });
@@ -231,7 +234,7 @@ export class WecomEndpoint implements EndpointInstance {
231
234
  if (data.errcode === 0) return data;
232
235
  throw new Error(`Failed to get user info: ${data.errmsg}`);
233
236
  } catch (error) {
234
- logger.error('Failed to get user info:', error);
237
+ this.#logger.error('Failed to get user info:', error);
235
238
  return null;
236
239
  }
237
240
  }
@@ -244,7 +247,7 @@ export class WecomEndpoint implements EndpointInstance {
244
247
  if (data.errcode === 0) return (data.userlist as unknown[]) || [];
245
248
  throw new Error(`Failed to get department users: ${data.errmsg}`);
246
249
  } catch (error) {
247
- logger.error('Failed to get department users:', error);
250
+ this.#logger.error('Failed to get department users:', error);
248
251
  return [];
249
252
  }
250
253
  }
@@ -257,17 +260,25 @@ export class WecomEndpoint implements EndpointInstance {
257
260
  if (data.errcode === 0) return (data.department as unknown[]) || [];
258
261
  throw new Error(`Failed to get department list: ${data.errmsg}`);
259
262
  } catch (error) {
260
- logger.error('Failed to get department list:', error);
263
+ this.#logger.error('Failed to get department list:', error);
261
264
  return [];
262
265
  }
263
266
  }
264
267
 
265
268
  async sendTextMessage(userId: string, content: string): Promise<boolean> {
266
269
  try {
267
- await this.send({ target: userId, payload: content });
270
+ const endpointKey = String(this.#options.id);
271
+ await this.send({
272
+ conversation: {
273
+ endpoint: { id: endpointKey, adapter: endpointKey.split('\0')[0] ?? endpointKey },
274
+ kind: resolveChatType(userId),
275
+ id: userId,
276
+ },
277
+ payload: content,
278
+ });
268
279
  return true;
269
280
  } catch (error) {
270
- logger.error('Failed to send text message:', error);
281
+ this.#logger.error('Failed to send text message:', error);
271
282
  return false;
272
283
  }
273
284
  }
@@ -330,7 +341,7 @@ export class WecomEndpoint implements EndpointInstance {
330
341
  expires_in: data.expires_in ?? 7200,
331
342
  timestamp: Date.now(),
332
343
  };
333
- logger.debug('Access token refreshed successfully');
344
+ this.#logger.debug('Access token refreshed successfully');
334
345
  return;
335
346
  }
336
347
  throw new Error(`Failed to get access token: ${data.errmsg} (${data.errcode})`);
package/src/index.ts CHANGED
@@ -34,7 +34,6 @@ export {
34
34
  checkWecomPlatformPermit,
35
35
  normalizeWecomSenderForPermit,
36
36
  platformPermit,
37
- registerWecomPlatformPermitChecker,
38
37
  wecomGroupPermitResolver,
39
38
  } from './platform-permit.js';
40
39
 
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * 企业微信 WeCom platform permit
3
3
  */
4
- import { registerPlatformPermitChecker, type Message } from '@zhin.js/core';
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, message: Message<any>): boolean {
35
- const sender = message.$sender as { role?: string; permissions?: string[] };
36
- const permissions = sender.permissions ?? [];
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
@@ -5,10 +5,11 @@
5
5
 
6
6
  import { createHash, createDecipheriv, timingSafeEqual } from 'node:crypto';
7
7
  import type { IncomingMessage } from 'node:http';
8
+ import type { ConversationRef } from '@zhin.js/im-contract';
8
9
 
9
10
  /** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
10
11
  export interface WecomAdapterConfig {
11
- readonly name?: string;
12
+ readonly id?: string;
12
13
  readonly corpId?: string;
13
14
  readonly agentSecret?: string;
14
15
  readonly token?: string;
@@ -23,7 +24,7 @@ export interface WecomAdapterConfig {
23
24
 
24
25
  export interface ResolvedWecomConfig {
25
26
  readonly context: 'wecom';
26
- readonly name: string;
27
+ readonly id: string;
27
28
  readonly corpId: string;
28
29
  readonly agentSecret: string;
29
30
  readonly token: string;
@@ -96,13 +97,13 @@ export function resolveWecomConfig(config: WecomAdapterConfig = {}): ResolvedWec
96
97
  'WeCom adapter requires corpId + agentSecret + token + encodingAESKey (plugins.<key> or endpoints with context: wecom)',
97
98
  );
98
99
  }
99
- const name = (typeof config.name === 'string' && config.name)
100
- || (typeof entry?.name === 'string' && entry.name)
100
+ const id = (typeof config.id === 'string' && config.id)
101
+ || (typeof entry?.id === 'string' && entry.id)
101
102
  || process.env.WECOM_BOT_NAME
102
103
  || 'wecom-bot';
103
104
  return {
104
105
  context: 'wecom',
105
- name,
106
+ id,
106
107
  corpId,
107
108
  agentSecret,
108
109
  token,
@@ -255,6 +256,18 @@ export function resolveChatType(fromUserName: string): 'group' | 'private' {
255
256
  return fromUserName.endsWith('@chatroom') ? 'group' : 'private';
256
257
  }
257
258
 
259
+ /**
260
+ * 入站归一化 → ConversationRef:WeCom 无 guild/channel 容器概念,
261
+ * `@chatroom` 群会话 → kind 'group',其余(应用消息/单聊)→ kind 'private'。
262
+ */
263
+ export function wecomInboundConversation(endpointKey: string, msg: WecomMessage): ConversationRef {
264
+ return {
265
+ endpoint: { id: endpointKey, adapter: endpointKey.split('\0')[0] ?? endpointKey },
266
+ kind: resolveChatType(msg.FromUserName),
267
+ id: msg.FromUserName,
268
+ };
269
+ }
270
+
258
271
  /**
259
272
  * Wire-encode an already-rendered outbound payload into WeCom message/send body parts.
260
273
  */
@@ -11,20 +11,20 @@ export interface WecomAgentEndpoint {
11
11
  }
12
12
 
13
13
  export interface WecomAgentDeps {
14
- getEndpoint: (endpointId: string) => WecomAgentEndpoint;
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
- endpointId: string,
21
+ endpointKey: string,
22
22
  endpoint: WecomAgentEndpoint,
23
23
  ): () => void {
24
- endpoints.set(endpointId, endpoint);
24
+ endpoints.set(endpointKey, endpoint);
25
25
  return () => {
26
- if (endpoints.get(endpointId) === endpoint) {
27
- endpoints.delete(endpointId);
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(endpointId) {
41
- const endpoint = endpoints.get(endpointId);
42
- if (!endpoint) throw new Error(`Endpoint ${endpointId} 不存在`);
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
  };