@zhin.js/adapter-wecom 4.0.14 → 5.0.1
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 +36 -0
- package/README.md +1 -1
- package/adapters/wecom.js +1 -3
- package/adapters/wecom.ts +1 -3
- package/agent/tools/get_dept_users.ts +4 -6
- package/agent/tools/get_user.ts +4 -6
- package/agent/tools/list_departments.ts +4 -6
- package/agent/tools/send_text.ts +4 -6
- package/lib/client.d.ts +12 -0
- package/lib/client.js +2 -0
- package/lib/endpoint.d.ts +21 -10
- package/lib/endpoint.js +38 -12
- package/lib/index.d.ts +2 -2
- package/lib/index.js +2 -2
- package/lib/protocol.d.ts +1 -1
- package/lib/protocol.js +1 -1
- package/lib/side-event-dispatch.d.ts +2 -2
- package/lib/side-event-dispatch.js +4 -4
- package/lib/wecom-endpoint-commands.d.ts +1 -1
- package/package.json +15 -14
- package/src/client.ts +16 -0
- package/src/endpoint.ts +44 -16
- package/src/index.ts +3 -7
- package/src/protocol.ts +1 -1
- package/src/side-event-dispatch.ts +5 -5
- package/lib/wecom-agent-deps.d.ts +0 -17
- package/lib/wecom-agent-deps.js +0 -30
- package/src/wecom-agent-deps.ts +0 -46
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# @zhin.js/adapter-wecom
|
|
2
2
|
|
|
3
|
+
## 5.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 1fc78bc: Unify native platform Client access behind the literal `adapter` discriminant. Handlers infer both native events and Clients, while command, inbound/outbound middleware, and both Agent tool authoring surfaces expose the exact operation-scoped Client through a lazy `$client` getter. Definitions without `adapter` keep `$client` typed as `unknown`, and runtime dispatch rejects adapter mismatches before resolving the Client. Bundled platform tools now use this single path instead of model-provided endpoint ids and adapter-specific dependency wrappers. Every adapter registers one Client/EventMap contract, and protocol adapters including NapCat, Milky, OneBot and Satori now produce transport-independent Client objects rather than letting Endpoint instances impersonate Clients.
|
|
8
|
+
- Updated dependencies [e9c6a73]
|
|
9
|
+
- Updated dependencies [4e8117c]
|
|
10
|
+
- Updated dependencies [902fa35]
|
|
11
|
+
- Updated dependencies [54bfd6b]
|
|
12
|
+
- Updated dependencies [12025ee]
|
|
13
|
+
- Updated dependencies [09b14d6]
|
|
14
|
+
- Updated dependencies [1fc78bc]
|
|
15
|
+
- @zhin.js/agent@1.1.16
|
|
16
|
+
- @zhin.js/adapter@1.2.1
|
|
17
|
+
- @zhin.js/core@1.5.14
|
|
18
|
+
- @zhin.js/host-http@1.0.13
|
|
19
|
+
- @zhin.js/command@1.0.16
|
|
20
|
+
- @zhin.js/logger@1.0.77
|
|
21
|
+
- zhin.js@6.0.14
|
|
22
|
+
- @zhin.js/feature-kit@1.0.13
|
|
23
|
+
- @zhin.js/permission@1.0.4
|
|
24
|
+
|
|
25
|
+
## 5.0.0
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- f2c532f: Expose exact per-Endpoint message operations through one validated Adapter capability model, route Core control calls through declared active capabilities, and connect existing recall, edit, reaction, and typing implementations across platform adapters.
|
|
30
|
+
- Updated dependencies [b10d058]
|
|
31
|
+
- Updated dependencies [f2c532f]
|
|
32
|
+
- Updated dependencies [3dbf990]
|
|
33
|
+
- @zhin.js/host-http@1.0.12
|
|
34
|
+
- @zhin.js/adapter@1.2.0
|
|
35
|
+
- @zhin.js/core@1.5.13
|
|
36
|
+
- @zhin.js/agent@1.1.15
|
|
37
|
+
- zhin.js@6.0.13
|
|
38
|
+
|
|
3
39
|
## 4.0.14
|
|
4
40
|
|
|
5
41
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ pnpm add @zhin.js/adapter-wecom
|
|
|
18
18
|
## Plugin Runtime
|
|
19
19
|
|
|
20
20
|
- `@zhin.js/adapter` — 约定式 `adapters/wecom.ts`(`defineAdapter`)
|
|
21
|
-
- `@zhin.js/core` — `
|
|
21
|
+
- `@zhin.js/core` — `Endpoint.emit(...)` 入站、`outboundMessageToken` 出站
|
|
22
22
|
- `@zhin.js/host-http` — `httpHostToken` 注册 Webhook 路由(**非** legacy host-router/Koa)
|
|
23
23
|
- `zhin.js` — `plugin.ts`(`definePlugin`)
|
|
24
24
|
- 配置经插件 `schema.json` 落到 `plugins.<instanceKey>`
|
package/adapters/wecom.js
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* Implementation lives under `src/` (endpoint / webhook / protocol).
|
|
5
5
|
*/
|
|
6
6
|
import { defineAdapter } from 'zhin.js/adapter';
|
|
7
|
-
import { messageGatewayToken, sideEventGatewayToken } from '@zhin.js/core/runtime';
|
|
8
7
|
import { httpHostToken } from '@zhin.js/host-http';
|
|
9
8
|
import { WecomEndpoint } from "../lib/endpoint.js";
|
|
10
9
|
import { resolveWecomConfig, } from "../lib/protocol.js";
|
|
@@ -12,6 +11,7 @@ import { wecomRuntimeStateToken } from "../lib/wecom-runtime-state.js";
|
|
|
12
11
|
export { WecomEndpoint } from "../lib/endpoint.js";
|
|
13
12
|
export default defineAdapter({
|
|
14
13
|
capabilities: ['inbound', 'outbound'],
|
|
14
|
+
operations: ['recall'],
|
|
15
15
|
// image 段全部经 /cgi-bin/media/upload 物化为 media_id(url 下载后上传、
|
|
16
16
|
// base64/path 直接上传、file 引用直用 media_id);无卡片交互面,交互段降级纯文本。
|
|
17
17
|
segments: {
|
|
@@ -27,8 +27,6 @@ export default defineAdapter({
|
|
|
27
27
|
});
|
|
28
28
|
return new WecomEndpoint({
|
|
29
29
|
id: context.id,
|
|
30
|
-
gateway: context.use(messageGatewayToken),
|
|
31
|
-
sideEvents: context.use(sideEventGatewayToken),
|
|
32
30
|
http: context.use(httpHostToken),
|
|
33
31
|
config,
|
|
34
32
|
});
|
package/adapters/wecom.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* Implementation lives under `src/` (endpoint / webhook / protocol).
|
|
4
4
|
*/
|
|
5
5
|
import { defineAdapter } from 'zhin.js/adapter';
|
|
6
|
-
import { messageGatewayToken, sideEventGatewayToken } from '@zhin.js/core/runtime';
|
|
7
6
|
import { httpHostToken } from '@zhin.js/host-http';
|
|
8
7
|
import { WecomEndpoint } from '../src/endpoint.js';
|
|
9
8
|
import {
|
|
@@ -17,6 +16,7 @@ export type { WecomEndpointOptions, WecomFetch } from '../src/endpoint.js';
|
|
|
17
16
|
|
|
18
17
|
export default defineAdapter<WecomAdapterConfig>({
|
|
19
18
|
capabilities: ['inbound', 'outbound'],
|
|
19
|
+
operations: ['recall'],
|
|
20
20
|
// image 段全部经 /cgi-bin/media/upload 物化为 media_id(url 下载后上传、
|
|
21
21
|
// base64/path 直接上传、file 引用直用 media_id);无卡片交互面,交互段降级纯文本。
|
|
22
22
|
segments: {
|
|
@@ -32,8 +32,6 @@ export default defineAdapter<WecomAdapterConfig>({
|
|
|
32
32
|
});
|
|
33
33
|
return new WecomEndpoint({
|
|
34
34
|
id: context.id,
|
|
35
|
-
gateway: context.use(messageGatewayToken),
|
|
36
|
-
sideEvents: context.use(sideEventGatewayToken),
|
|
37
35
|
http: context.use(httpHostToken),
|
|
38
36
|
config,
|
|
39
37
|
});
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
|
|
4
|
-
export default defineAgentTool<{ endpoint_id: string; dept_id: string }>({
|
|
3
|
+
export default defineAgentTool<{ dept_id: string }>({
|
|
5
4
|
description: '获取企业微信部门用户列表',
|
|
6
5
|
inputSchema: z.object({
|
|
7
|
-
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
8
6
|
dept_id: z.string().describe('部门 ID'),
|
|
9
7
|
}),
|
|
10
|
-
|
|
8
|
+
adapter: 'wecom',
|
|
11
9
|
tags: ['wecom'],
|
|
12
|
-
async execute({
|
|
13
|
-
const endpoint =
|
|
10
|
+
async execute({ dept_id }: { dept_id: string }, context) {
|
|
11
|
+
const endpoint = context.$client;
|
|
14
12
|
const users = await endpoint.getDepartmentUsers(Number(dept_id));
|
|
15
13
|
return { users, count: users.length };
|
|
16
14
|
},
|
package/agent/tools/get_user.ts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
|
|
4
|
-
export default defineAgentTool<{ endpoint_id: string; user_id: string }>({
|
|
3
|
+
export default defineAgentTool<{ user_id: string }>({
|
|
5
4
|
description: '获取企业微信用户信息',
|
|
6
5
|
inputSchema: z.object({
|
|
7
|
-
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
8
6
|
user_id: z.string().describe('用户 ID'),
|
|
9
7
|
}),
|
|
10
|
-
|
|
8
|
+
adapter: 'wecom',
|
|
11
9
|
tags: ['wecom'],
|
|
12
|
-
async execute({
|
|
13
|
-
const endpoint =
|
|
10
|
+
async execute({ user_id }: { user_id: string }, context) {
|
|
11
|
+
const endpoint = context.$client;
|
|
14
12
|
return await endpoint.getUserInfo(user_id);
|
|
15
13
|
},
|
|
16
14
|
});
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
|
|
4
|
-
export default defineAgentTool<{ endpoint_id: string; dept_id?: string }>({
|
|
3
|
+
export default defineAgentTool<{ dept_id?: string }>({
|
|
5
4
|
description: '获取企业微信部门列表',
|
|
6
5
|
inputSchema: z.object({
|
|
7
|
-
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
8
6
|
dept_id: z.string().optional().describe('父部门 ID,默认 1(根部门)'),
|
|
9
7
|
}),
|
|
10
|
-
|
|
8
|
+
adapter: 'wecom',
|
|
11
9
|
tags: ['wecom'],
|
|
12
|
-
async execute({
|
|
13
|
-
const endpoint =
|
|
10
|
+
async execute({ dept_id }: { dept_id?: string }, context) {
|
|
11
|
+
const endpoint = context.$client;
|
|
14
12
|
const departments = await endpoint.getDepartmentList(Number(dept_id) || 1);
|
|
15
13
|
return { departments, count: departments.length };
|
|
16
14
|
},
|
package/agent/tools/send_text.ts
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
|
|
4
|
-
export default defineAgentTool<{ endpoint_id: string; user_id: string; content: string }>({
|
|
3
|
+
export default defineAgentTool<{ user_id: string; content: string }>({
|
|
5
4
|
description: '向指定企业微信用户发送文本消息',
|
|
6
5
|
inputSchema: z.object({
|
|
7
|
-
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
8
6
|
user_id: z.string().describe('用户 ID'),
|
|
9
7
|
content: z.string().describe('消息内容'),
|
|
10
8
|
}),
|
|
11
|
-
|
|
9
|
+
adapter: 'wecom',
|
|
12
10
|
tags: ['wecom'],
|
|
13
|
-
async execute({
|
|
14
|
-
const endpoint =
|
|
11
|
+
async execute({ user_id, content }: { user_id: string; content: string }, context) {
|
|
12
|
+
const endpoint = context.$client;
|
|
15
13
|
const success = await endpoint.sendTextMessage(user_id, content);
|
|
16
14
|
return { success, message: success ? '消息已发送' : '发送失败' };
|
|
17
15
|
},
|
package/lib/client.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { WecomClient } from './endpoint.js';
|
|
2
|
+
import type { WecomMessage } from './protocol.js';
|
|
3
|
+
export type WecomClientEventMap = Record<string, WecomMessage>;
|
|
4
|
+
declare module '@zhin.js/feature-kit' {
|
|
5
|
+
interface AdapterClientRegistry {
|
|
6
|
+
readonly wecom: {
|
|
7
|
+
readonly client: WecomClient;
|
|
8
|
+
readonly events: WecomClientEventMap;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export declare const wecomClient: import("@zhin.js/adapter").EndpointClientToken<WecomClient, WecomClientEventMap>;
|
package/lib/client.js
ADDED
package/lib/endpoint.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import { Endpoint } from 'zhin.js/adapter';
|
|
1
2
|
/**
|
|
2
3
|
* WecomEndpoint — lifecycle, outbound send, inbound admit, OpenAPI helpers for agent tools.
|
|
3
4
|
*/
|
|
4
|
-
import type
|
|
5
|
-
import type { MessageGateway, SideEventGateway } from '@zhin.js/core/runtime';
|
|
5
|
+
import { type EndpointControl, type EndpointSendRequest } from 'zhin.js/adapter';
|
|
6
6
|
import type { HttpHost } from '@zhin.js/host-http';
|
|
7
7
|
import type { CapabilityId } from 'zhin.js';
|
|
8
|
-
import { type ResolvedWecomConfig, type
|
|
8
|
+
import { type ResolvedWecomConfig, type WecomMessage } from './protocol.js';
|
|
9
9
|
export type WecomFetch = (url: string, init?: {
|
|
10
10
|
readonly method?: string;
|
|
11
11
|
readonly headers?: Record<string, string>;
|
|
@@ -18,19 +18,34 @@ export type WecomFetch = (url: string, init?: {
|
|
|
18
18
|
}>;
|
|
19
19
|
export interface WecomEndpointOptions {
|
|
20
20
|
readonly id: CapabilityId;
|
|
21
|
-
readonly gateway: MessageGateway;
|
|
22
|
-
readonly sideEvents?: SideEventGateway;
|
|
23
21
|
readonly http: HttpHost;
|
|
24
22
|
readonly config: ResolvedWecomConfig;
|
|
25
23
|
readonly fetch?: WecomFetch;
|
|
26
24
|
}
|
|
25
|
+
export interface WecomClientApi {
|
|
26
|
+
getUserInfo(userId: string): Promise<unknown>;
|
|
27
|
+
getDepartmentUsers(deptId: number): Promise<unknown[]>;
|
|
28
|
+
getDepartmentList(deptId?: number): Promise<unknown[]>;
|
|
29
|
+
sendTextMessage(userId: string, content: string): Promise<boolean>;
|
|
30
|
+
}
|
|
31
|
+
/** WeCom API surface exposed to plugin events without Endpoint lifecycle methods. */
|
|
32
|
+
export declare class WecomClient implements WecomClientApi {
|
|
33
|
+
readonly api: WecomClientApi;
|
|
34
|
+
constructor(api: WecomClientApi);
|
|
35
|
+
getUserInfo: (userId: string) => Promise<unknown>;
|
|
36
|
+
getDepartmentUsers: (deptId: number) => Promise<unknown[]>;
|
|
37
|
+
getDepartmentList: (deptId?: number) => Promise<unknown[]>;
|
|
38
|
+
sendTextMessage: (userId: string, content: string) => Promise<boolean>;
|
|
39
|
+
}
|
|
27
40
|
/**
|
|
28
41
|
* 企业微信服务端 API 无 bot 群列表/群成员列表接口(客户群接口属「客户联系」
|
|
29
42
|
* 独立授权域,非 bot 社交面),好友/频道概念亦不存在;
|
|
30
43
|
* 因此本 endpoint 不暴露 EndpointManagement(Console 社交面 RPC 对该平台保持未接线)。
|
|
31
44
|
*/
|
|
32
|
-
export declare class WecomEndpoint
|
|
45
|
+
export declare class WecomEndpoint extends Endpoint<WecomClient> {
|
|
33
46
|
#private;
|
|
47
|
+
readonly client: WecomClient;
|
|
48
|
+
readonly control: EndpointControl;
|
|
34
49
|
constructor(options: WecomEndpointOptions);
|
|
35
50
|
/** Used by webhook handler. */
|
|
36
51
|
get isOpen(): boolean;
|
|
@@ -43,8 +58,4 @@ export declare class WecomEndpoint implements EndpointInstance {
|
|
|
43
58
|
recallMessage(messageId: string): Promise<void>;
|
|
44
59
|
/** Test / internal: admit a parsed message when open (non-webhook path). */
|
|
45
60
|
admit(msg: WecomMessage): void;
|
|
46
|
-
getUserInfo(userId: string): Promise<WecomApiResponse | null>;
|
|
47
|
-
getDepartmentUsers(deptId: number): Promise<unknown[]>;
|
|
48
|
-
getDepartmentList(deptId?: number): Promise<unknown[]>;
|
|
49
|
-
sendTextMessage(userId: string, content: string): Promise<boolean>;
|
|
50
61
|
}
|
package/lib/endpoint.js
CHANGED
|
@@ -1,25 +1,47 @@
|
|
|
1
|
+
import { Endpoint } from 'zhin.js/adapter';
|
|
2
|
+
/**
|
|
3
|
+
* WecomEndpoint — lifecycle, outbound send, inbound admit, OpenAPI helpers for agent tools.
|
|
4
|
+
*/
|
|
5
|
+
import { createRecallEndpointControl, } from 'zhin.js/adapter';
|
|
1
6
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
2
|
-
import { registerWecomAgentEndpoint } from './wecom-agent-deps.js';
|
|
3
7
|
import { buildMediaUploadForm, readOutboundImageMedia, resolveMediaBinary, } from './media-upload.js';
|
|
4
8
|
import { buildSendRequestBody, formatInboundContent, formatOutboundBody, resolveChatType, wecomInboundConversation, } from './protocol.js';
|
|
5
9
|
import { registerWecomWebhookRoutes } from './webhook.js';
|
|
6
10
|
import { receiveWecomSideEvent } from './side-event-dispatch.js';
|
|
11
|
+
/** WeCom API surface exposed to plugin events without Endpoint lifecycle methods. */
|
|
12
|
+
export class WecomClient {
|
|
13
|
+
api;
|
|
14
|
+
constructor(api) {
|
|
15
|
+
this.api = api;
|
|
16
|
+
}
|
|
17
|
+
getUserInfo = (userId) => this.api.getUserInfo(userId);
|
|
18
|
+
getDepartmentUsers = (deptId) => this.api.getDepartmentUsers(deptId);
|
|
19
|
+
getDepartmentList = (deptId) => this.api.getDepartmentList(deptId);
|
|
20
|
+
sendTextMessage = (userId, content) => this.api.sendTextMessage(userId, content);
|
|
21
|
+
}
|
|
7
22
|
/**
|
|
8
23
|
* 企业微信服务端 API 无 bot 群列表/群成员列表接口(客户群接口属「客户联系」
|
|
9
24
|
* 独立授权域,非 bot 社交面),好友/频道概念亦不存在;
|
|
10
25
|
* 因此本 endpoint 不暴露 EndpointManagement(Console 社交面 RPC 对该平台保持未接线)。
|
|
11
26
|
*/
|
|
12
|
-
export class WecomEndpoint {
|
|
27
|
+
export class WecomEndpoint extends Endpoint {
|
|
28
|
+
client = new WecomClient({
|
|
29
|
+
getUserInfo: (userId) => this.#getUserInfo(userId),
|
|
30
|
+
getDepartmentUsers: (deptId) => this.#getDepartmentUsers(deptId),
|
|
31
|
+
getDepartmentList: (deptId) => this.#getDepartmentList(deptId),
|
|
32
|
+
sendTextMessage: (userId, content) => this.#sendTextMessage(userId, content),
|
|
33
|
+
});
|
|
13
34
|
#logger;
|
|
14
35
|
#options;
|
|
36
|
+
control = createRecallEndpointControl((id) => this.recallMessage(id));
|
|
15
37
|
#fetch;
|
|
16
38
|
#routeReleases = [];
|
|
17
39
|
#accessToken = { access_token: '', expires_in: 0, timestamp: 0 };
|
|
18
40
|
#refreshPromise = null;
|
|
19
41
|
#open = false;
|
|
20
42
|
#started = false;
|
|
21
|
-
#unregisterAgent;
|
|
22
43
|
constructor(options) {
|
|
44
|
+
super();
|
|
23
45
|
this.#logger = getAdapterLogger('wecom', options.config.id);
|
|
24
46
|
this.#options = options;
|
|
25
47
|
this.#fetch = options.fetch ?? globalThis.fetch;
|
|
@@ -37,7 +59,6 @@ export class WecomEndpoint {
|
|
|
37
59
|
this.#started = true;
|
|
38
60
|
try {
|
|
39
61
|
await this.#refreshAccessToken();
|
|
40
|
-
this.#unregisterAgent = registerWecomAgentEndpoint(this.#options.config.id, this);
|
|
41
62
|
this.#routeReleases.push(...registerWecomWebhookRoutes(this.#options.http, this));
|
|
42
63
|
this.#logger.debug(formatCompact({
|
|
43
64
|
endpoint: this.#options.config.id,
|
|
@@ -61,8 +82,6 @@ export class WecomEndpoint {
|
|
|
61
82
|
this.#open = false;
|
|
62
83
|
for (const release of this.#routeReleases.splice(0))
|
|
63
84
|
release();
|
|
64
|
-
this.#unregisterAgent?.();
|
|
65
|
-
this.#unregisterAgent = undefined;
|
|
66
85
|
this.#started = false;
|
|
67
86
|
this.#logger.debug(formatCompact({ op: 'disconnect' }));
|
|
68
87
|
}
|
|
@@ -152,12 +171,19 @@ export class WecomEndpoint {
|
|
|
152
171
|
admit(msg) {
|
|
153
172
|
if (!this.#open)
|
|
154
173
|
return;
|
|
155
|
-
|
|
174
|
+
void this.emitPlatform(msg.Event || msg.MsgType || 'event', msg).catch((error) => {
|
|
175
|
+
this.#logger.warn(formatCompact({
|
|
176
|
+
op: 'wecom_platform_event_failed',
|
|
177
|
+
event: msg.Event || msg.MsgType,
|
|
178
|
+
error: error instanceof Error ? error.message : String(error),
|
|
179
|
+
}));
|
|
180
|
+
});
|
|
181
|
+
if (receiveWecomSideEvent((name, payload) => this.emit(name, payload), String(this.#options.id), this.#options.config.id, msg, this.#logger)) {
|
|
156
182
|
return;
|
|
157
183
|
}
|
|
158
184
|
const chatType = resolveChatType(msg.FromUserName);
|
|
159
185
|
const conversation = wecomInboundConversation(String(this.#options.id), msg);
|
|
160
|
-
void this
|
|
186
|
+
void this.emit('message.receive', {
|
|
161
187
|
conversation,
|
|
162
188
|
message: { conversation, id: msg.MsgId || `${msg.CreateTime}` },
|
|
163
189
|
content: formatInboundContent(msg),
|
|
@@ -178,7 +204,7 @@ export class WecomEndpoint {
|
|
|
178
204
|
}));
|
|
179
205
|
});
|
|
180
206
|
}
|
|
181
|
-
async getUserInfo(userId) {
|
|
207
|
+
async #getUserInfo(userId) {
|
|
182
208
|
try {
|
|
183
209
|
const data = await this.#request('/cgi-bin/user/get', {
|
|
184
210
|
params: { userid: userId },
|
|
@@ -192,7 +218,7 @@ export class WecomEndpoint {
|
|
|
192
218
|
return null;
|
|
193
219
|
}
|
|
194
220
|
}
|
|
195
|
-
async getDepartmentUsers(deptId) {
|
|
221
|
+
async #getDepartmentUsers(deptId) {
|
|
196
222
|
try {
|
|
197
223
|
const data = await this.#request('/cgi-bin/user/simplelist', {
|
|
198
224
|
params: { department_id: deptId },
|
|
@@ -206,7 +232,7 @@ export class WecomEndpoint {
|
|
|
206
232
|
return [];
|
|
207
233
|
}
|
|
208
234
|
}
|
|
209
|
-
async getDepartmentList(deptId = 1) {
|
|
235
|
+
async #getDepartmentList(deptId = 1) {
|
|
210
236
|
try {
|
|
211
237
|
const data = await this.#request('/cgi-bin/department/list', {
|
|
212
238
|
params: { id: deptId },
|
|
@@ -220,7 +246,7 @@ export class WecomEndpoint {
|
|
|
220
246
|
return [];
|
|
221
247
|
}
|
|
222
248
|
}
|
|
223
|
-
async sendTextMessage(userId, content) {
|
|
249
|
+
async #sendTextMessage(userId, content) {
|
|
224
250
|
try {
|
|
225
251
|
const endpointKey = String(this.#options.id);
|
|
226
252
|
await this.send({
|
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
|
-
export {
|
|
2
|
+
export { wecomClient, type WecomClientEventMap } from './client.js';
|
|
3
3
|
export { checkWecomPlatformPermit, normalizeWecomSenderForPermit, platformPermit, wecomGroupPermitResolver, } from './platform-permit.js';
|
|
4
|
-
export { WecomEndpoint, type WecomEndpointOptions, type WecomFetch, } from './endpoint.js';
|
|
4
|
+
export { WecomClient, WecomEndpoint, type WecomClientApi, 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
|
-
export {
|
|
2
|
+
export { wecomClient } from './client.js';
|
|
3
3
|
export { checkWecomPlatformPermit, normalizeWecomSenderForPermit, platformPermit, wecomGroupPermitResolver, } from './platform-permit.js';
|
|
4
|
-
export { WecomEndpoint, } from './endpoint.js';
|
|
4
|
+
export { WecomClient, 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/protocol.d.ts
CHANGED
|
@@ -84,7 +84,7 @@ export declare function verifySignature(token: string, timestamp: string, nonce:
|
|
|
84
84
|
export declare function decryptMessage(encrypted: string, encodingAESKey: string, corpId: string): string | null;
|
|
85
85
|
export declare function extractEncryptFromXml(xml: string): string | null;
|
|
86
86
|
export declare function parseXmlMessage(xml: string): WecomMessage | null;
|
|
87
|
-
/** Build inbound text for
|
|
87
|
+
/** Build inbound text for OutboundMessageService.receive. */
|
|
88
88
|
export declare function formatInboundContent(msg: WecomMessage): string;
|
|
89
89
|
export declare function resolveChatType(fromUserName: string): 'group' | 'private';
|
|
90
90
|
/**
|
package/lib/protocol.js
CHANGED
|
@@ -128,7 +128,7 @@ export function parseXmlMessage(xml) {
|
|
|
128
128
|
return null;
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
|
-
/** Build inbound text for
|
|
131
|
+
/** Build inbound text for OutboundMessageService.receive. */
|
|
132
132
|
export function formatInboundContent(msg) {
|
|
133
133
|
switch (msg.MsgType) {
|
|
134
134
|
case 'text':
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { EndpointEventEmitter } from 'zhin.js/adapter';
|
|
2
2
|
import { type getAdapterLogger } from '@zhin.js/logger';
|
|
3
3
|
import { type WecomMessage } from './protocol.js';
|
|
4
|
-
export declare function receiveWecomSideEvent(
|
|
4
|
+
export declare function receiveWecomSideEvent(emit: EndpointEventEmitter, endpointKey: string, configId: string, msg: WecomMessage, logger: ReturnType<typeof getAdapterLogger>): boolean;
|
|
@@ -13,12 +13,12 @@ function mapWecomEventParts(eventName) {
|
|
|
13
13
|
return { scene_type: 'wecom', sub_type: eventName || 'unknown' };
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
export function receiveWecomSideEvent(
|
|
17
|
-
if (
|
|
16
|
+
export function receiveWecomSideEvent(emit, endpointKey, configId, msg, logger) {
|
|
17
|
+
if (msg.MsgType !== 'event')
|
|
18
18
|
return false;
|
|
19
19
|
const eventName = msg.Event ?? 'unknown';
|
|
20
20
|
if (eventName === 'enter_agent') {
|
|
21
|
-
void
|
|
21
|
+
void emit('system.receive', buildSystem(msg, {
|
|
22
22
|
$id: `wecom:enter_agent:${msg.FromUserName}:${msg.CreateTime ?? Date.now()}`,
|
|
23
23
|
$adapter: 'wecom',
|
|
24
24
|
$endpoint: configId,
|
|
@@ -41,7 +41,7 @@ export function receiveWecomSideEvent(sideEvents, endpointKey, configId, msg, lo
|
|
|
41
41
|
if (!parts)
|
|
42
42
|
return false;
|
|
43
43
|
const sceneType = resolveChatType(msg.FromUserName);
|
|
44
|
-
void
|
|
44
|
+
void emit('notice.receive', buildNotice(msg, {
|
|
45
45
|
$id: `wecom:${eventName}:${msg.FromUserName}:${msg.CreateTime ?? Date.now()}`,
|
|
46
46
|
$adapter: 'wecom',
|
|
47
47
|
$endpoint: configId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const wecomEndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage>>>;
|
|
1
|
+
export declare const wecomEndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage, string | undefined>>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-wecom",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.1",
|
|
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,22 @@
|
|
|
34
34
|
"directory": "plugins/adapters/wecom"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@zhin.js/adapter": "1.1
|
|
38
|
-
"@zhin.js/core": "1.5.
|
|
39
|
-
"@zhin.js/
|
|
37
|
+
"@zhin.js/adapter": "1.2.1",
|
|
38
|
+
"@zhin.js/core": "1.5.14",
|
|
39
|
+
"@zhin.js/feature-kit": "1.0.13",
|
|
40
|
+
"@zhin.js/host-http": "1.0.13",
|
|
40
41
|
"@zhin.js/im-contract": "1.0.4",
|
|
41
|
-
"@zhin.js/logger": "1.0.
|
|
42
|
+
"@zhin.js/logger": "1.0.77"
|
|
42
43
|
},
|
|
43
44
|
"peerDependencies": {
|
|
44
45
|
"zod": "^4.0.0",
|
|
45
|
-
"@zhin.js/adapter": "1.1
|
|
46
|
-
"@zhin.js/agent": "1.1.
|
|
47
|
-
"@zhin.js/command": "1.0.
|
|
48
|
-
"@zhin.js/core": "1.5.
|
|
49
|
-
"@zhin.js/host-http": "1.0.
|
|
50
|
-
"@zhin.js/permission": "1.0.
|
|
51
|
-
"zhin.js": "6.0.
|
|
46
|
+
"@zhin.js/adapter": "1.2.1",
|
|
47
|
+
"@zhin.js/agent": "1.1.16",
|
|
48
|
+
"@zhin.js/command": "1.0.16",
|
|
49
|
+
"@zhin.js/core": "1.5.14",
|
|
50
|
+
"@zhin.js/host-http": "1.0.13",
|
|
51
|
+
"@zhin.js/permission": "1.0.4",
|
|
52
|
+
"zhin.js": "6.0.14"
|
|
52
53
|
},
|
|
53
54
|
"peerDependenciesMeta": {
|
|
54
55
|
"@zhin.js/agent": {
|
|
@@ -69,8 +70,8 @@
|
|
|
69
70
|
"typescript": "^6.0.3",
|
|
70
71
|
"vitest": "^4.1.10",
|
|
71
72
|
"zod": "^4.4.3",
|
|
72
|
-
"@zhin.js/agent": "1.1.
|
|
73
|
-
"zhin.js": "6.0.
|
|
73
|
+
"@zhin.js/agent": "1.1.16",
|
|
74
|
+
"zhin.js": "6.0.14"
|
|
74
75
|
},
|
|
75
76
|
"files": [
|
|
76
77
|
"adapters",
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineEndpointClient } from 'zhin.js/adapter';
|
|
2
|
+
import type { WecomClient } from './endpoint.js';
|
|
3
|
+
import type { WecomMessage } from './protocol.js';
|
|
4
|
+
|
|
5
|
+
export type WecomClientEventMap = Record<string, WecomMessage>;
|
|
6
|
+
|
|
7
|
+
declare module '@zhin.js/feature-kit' {
|
|
8
|
+
interface AdapterClientRegistry {
|
|
9
|
+
readonly wecom: {
|
|
10
|
+
readonly client: WecomClient;
|
|
11
|
+
readonly events: WecomClientEventMap;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const wecomClient = defineEndpointClient<WecomClient, WecomClientEventMap>('wecom');
|
package/src/endpoint.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import { Endpoint } from 'zhin.js/adapter';
|
|
1
2
|
/**
|
|
2
3
|
* WecomEndpoint — lifecycle, outbound send, inbound admit, OpenAPI helpers for agent tools.
|
|
3
4
|
*/
|
|
4
|
-
import
|
|
5
|
-
|
|
5
|
+
import {
|
|
6
|
+
createRecallEndpointControl,
|
|
7
|
+
type EndpointControl,
|
|
8
|
+
type EndpointSendRequest,
|
|
9
|
+
} from 'zhin.js/adapter';
|
|
6
10
|
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
7
11
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
8
12
|
import type { CapabilityId } from 'zhin.js';
|
|
9
|
-
import { registerWecomAgentEndpoint } from './wecom-agent-deps.js';
|
|
10
13
|
import {
|
|
11
14
|
buildMediaUploadForm,
|
|
12
15
|
readOutboundImageMedia,
|
|
@@ -43,31 +46,52 @@ export type WecomFetch = (
|
|
|
43
46
|
|
|
44
47
|
export interface WecomEndpointOptions {
|
|
45
48
|
readonly id: CapabilityId;
|
|
46
|
-
readonly gateway: MessageGateway;
|
|
47
|
-
readonly sideEvents?: SideEventGateway;
|
|
48
49
|
readonly http: HttpHost;
|
|
49
50
|
readonly config: ResolvedWecomConfig;
|
|
50
51
|
readonly fetch?: WecomFetch;
|
|
51
52
|
}
|
|
52
53
|
|
|
54
|
+
export interface WecomClientApi {
|
|
55
|
+
getUserInfo(userId: string): Promise<unknown>;
|
|
56
|
+
getDepartmentUsers(deptId: number): Promise<unknown[]>;
|
|
57
|
+
getDepartmentList(deptId?: number): Promise<unknown[]>;
|
|
58
|
+
sendTextMessage(userId: string, content: string): Promise<boolean>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** WeCom API surface exposed to plugin events without Endpoint lifecycle methods. */
|
|
62
|
+
export class WecomClient implements WecomClientApi {
|
|
63
|
+
constructor(readonly api: WecomClientApi) {}
|
|
64
|
+
getUserInfo = (userId: string) => this.api.getUserInfo(userId);
|
|
65
|
+
getDepartmentUsers = (deptId: number) => this.api.getDepartmentUsers(deptId);
|
|
66
|
+
getDepartmentList = (deptId?: number) => this.api.getDepartmentList(deptId);
|
|
67
|
+
sendTextMessage = (userId: string, content: string) => this.api.sendTextMessage(userId, content);
|
|
68
|
+
}
|
|
69
|
+
|
|
53
70
|
/**
|
|
54
71
|
* 企业微信服务端 API 无 bot 群列表/群成员列表接口(客户群接口属「客户联系」
|
|
55
72
|
* 独立授权域,非 bot 社交面),好友/频道概念亦不存在;
|
|
56
73
|
* 因此本 endpoint 不暴露 EndpointManagement(Console 社交面 RPC 对该平台保持未接线)。
|
|
57
74
|
*/
|
|
58
|
-
export class WecomEndpoint
|
|
75
|
+
export class WecomEndpoint extends Endpoint<WecomClient> {
|
|
76
|
+
readonly client = new WecomClient({
|
|
77
|
+
getUserInfo: (userId) => this.#getUserInfo(userId),
|
|
78
|
+
getDepartmentUsers: (deptId) => this.#getDepartmentUsers(deptId),
|
|
79
|
+
getDepartmentList: (deptId) => this.#getDepartmentList(deptId),
|
|
80
|
+
sendTextMessage: (userId, content) => this.#sendTextMessage(userId, content),
|
|
81
|
+
});
|
|
59
82
|
readonly #logger!: ReturnType<typeof getAdapterLogger>;
|
|
60
83
|
|
|
61
84
|
readonly #options: WecomEndpointOptions;
|
|
85
|
+
readonly control: EndpointControl = createRecallEndpointControl((id) => this.recallMessage(id));
|
|
62
86
|
readonly #fetch: WecomFetch;
|
|
63
87
|
#routeReleases: HttpRouteRegistration[] = [];
|
|
64
88
|
#accessToken: AccessToken = { access_token: '', expires_in: 0, timestamp: 0 };
|
|
65
89
|
#refreshPromise: Promise<string> | null = null;
|
|
66
90
|
#open = false;
|
|
67
91
|
#started = false;
|
|
68
|
-
#unregisterAgent?: () => void;
|
|
69
92
|
|
|
70
93
|
constructor(options: WecomEndpointOptions) {
|
|
94
|
+
super();
|
|
71
95
|
this.#logger = getAdapterLogger('wecom', options.config.id);
|
|
72
96
|
this.#options = options;
|
|
73
97
|
this.#fetch = options.fetch ?? globalThis.fetch;
|
|
@@ -87,7 +111,6 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
87
111
|
this.#started = true;
|
|
88
112
|
try {
|
|
89
113
|
await this.#refreshAccessToken();
|
|
90
|
-
this.#unregisterAgent = registerWecomAgentEndpoint(this.#options.config.id, this);
|
|
91
114
|
this.#routeReleases.push(...registerWecomWebhookRoutes(this.#options.http, this));
|
|
92
115
|
this.#logger.debug(formatCompact({
|
|
93
116
|
endpoint: this.#options.config.id,
|
|
@@ -112,8 +135,6 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
112
135
|
async stop(): Promise<void> {
|
|
113
136
|
this.#open = false;
|
|
114
137
|
for (const release of this.#routeReleases.splice(0)) release();
|
|
115
|
-
this.#unregisterAgent?.();
|
|
116
|
-
this.#unregisterAgent = undefined;
|
|
117
138
|
this.#started = false;
|
|
118
139
|
this.#logger.debug(formatCompact({ op: 'disconnect' }));
|
|
119
140
|
}
|
|
@@ -204,8 +225,15 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
204
225
|
/** Test / internal: admit a parsed message when open (non-webhook path). */
|
|
205
226
|
admit(msg: WecomMessage): void {
|
|
206
227
|
if (!this.#open) return;
|
|
228
|
+
void this.emitPlatform(msg.Event || msg.MsgType || 'event', msg).catch((error) => {
|
|
229
|
+
this.#logger.warn(formatCompact({
|
|
230
|
+
op: 'wecom_platform_event_failed',
|
|
231
|
+
event: msg.Event || msg.MsgType,
|
|
232
|
+
error: error instanceof Error ? error.message : String(error),
|
|
233
|
+
}));
|
|
234
|
+
});
|
|
207
235
|
if (receiveWecomSideEvent(
|
|
208
|
-
this
|
|
236
|
+
(name, payload) => this.emit(name, payload),
|
|
209
237
|
String(this.#options.id),
|
|
210
238
|
this.#options.config.id,
|
|
211
239
|
msg,
|
|
@@ -215,7 +243,7 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
215
243
|
}
|
|
216
244
|
const chatType = resolveChatType(msg.FromUserName);
|
|
217
245
|
const conversation = wecomInboundConversation(String(this.#options.id), msg);
|
|
218
|
-
void this
|
|
246
|
+
void this.emit('message.receive', {
|
|
219
247
|
conversation,
|
|
220
248
|
message: { conversation, id: msg.MsgId || `${msg.CreateTime}` },
|
|
221
249
|
content: formatInboundContent(msg),
|
|
@@ -237,7 +265,7 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
237
265
|
});
|
|
238
266
|
}
|
|
239
267
|
|
|
240
|
-
async getUserInfo(userId: string): Promise<WecomApiResponse | null> {
|
|
268
|
+
async #getUserInfo(userId: string): Promise<WecomApiResponse | null> {
|
|
241
269
|
try {
|
|
242
270
|
const data = await this.#request('/cgi-bin/user/get', {
|
|
243
271
|
params: { userid: userId },
|
|
@@ -250,7 +278,7 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
250
278
|
}
|
|
251
279
|
}
|
|
252
280
|
|
|
253
|
-
async getDepartmentUsers(deptId: number): Promise<unknown[]> {
|
|
281
|
+
async #getDepartmentUsers(deptId: number): Promise<unknown[]> {
|
|
254
282
|
try {
|
|
255
283
|
const data = await this.#request('/cgi-bin/user/simplelist', {
|
|
256
284
|
params: { department_id: deptId },
|
|
@@ -263,7 +291,7 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
263
291
|
}
|
|
264
292
|
}
|
|
265
293
|
|
|
266
|
-
async getDepartmentList(deptId: number = 1): Promise<unknown[]> {
|
|
294
|
+
async #getDepartmentList(deptId: number = 1): Promise<unknown[]> {
|
|
267
295
|
try {
|
|
268
296
|
const data = await this.#request('/cgi-bin/department/list', {
|
|
269
297
|
params: { id: deptId },
|
|
@@ -276,7 +304,7 @@ export class WecomEndpoint implements EndpointInstance {
|
|
|
276
304
|
}
|
|
277
305
|
}
|
|
278
306
|
|
|
279
|
-
async sendTextMessage(userId: string, content: string): Promise<boolean> {
|
|
307
|
+
async #sendTextMessage(userId: string, content: string): Promise<boolean> {
|
|
280
308
|
try {
|
|
281
309
|
const endpointKey = String(this.#options.id);
|
|
282
310
|
await this.send({
|
package/src/index.ts
CHANGED
|
@@ -22,13 +22,7 @@ export {
|
|
|
22
22
|
type WecomWireSegment,
|
|
23
23
|
} from './protocol.js';
|
|
24
24
|
|
|
25
|
-
export {
|
|
26
|
-
getWecomAgentDeps,
|
|
27
|
-
registerWecomAgentEndpoint,
|
|
28
|
-
setWecomAgentDeps,
|
|
29
|
-
type WecomAgentDeps,
|
|
30
|
-
type WecomAgentEndpoint,
|
|
31
|
-
} from './wecom-agent-deps.js';
|
|
25
|
+
export { wecomClient, type WecomClientEventMap } from './client.js';
|
|
32
26
|
|
|
33
27
|
export {
|
|
34
28
|
checkWecomPlatformPermit,
|
|
@@ -38,7 +32,9 @@ export {
|
|
|
38
32
|
} from './platform-permit.js';
|
|
39
33
|
|
|
40
34
|
export {
|
|
35
|
+
WecomClient,
|
|
41
36
|
WecomEndpoint,
|
|
37
|
+
type WecomClientApi,
|
|
42
38
|
type WecomEndpointOptions,
|
|
43
39
|
type WecomFetch,
|
|
44
40
|
} from './endpoint.js';
|
package/src/protocol.ts
CHANGED
|
@@ -227,7 +227,7 @@ export function parseXmlMessage(xml: string): WecomMessage | null {
|
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
/** Build inbound text for
|
|
230
|
+
/** Build inbound text for OutboundMessageService.receive. */
|
|
231
231
|
export function formatInboundContent(msg: WecomMessage): string {
|
|
232
232
|
switch (msg.MsgType) {
|
|
233
233
|
case 'text':
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { buildNotice, buildSystem, senderFromId } from '@zhin.js/core';
|
|
2
|
-
import type {
|
|
2
|
+
import type { EndpointEventEmitter } from 'zhin.js/adapter';
|
|
3
3
|
import { formatCompact, type getAdapterLogger } from '@zhin.js/logger';
|
|
4
4
|
import { resolveChatType, type WecomMessage } from './protocol.js';
|
|
5
5
|
|
|
@@ -17,16 +17,16 @@ function mapWecomEventParts(eventName: string): { scene_type: string; sub_type:
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export function receiveWecomSideEvent(
|
|
20
|
-
|
|
20
|
+
emit: EndpointEventEmitter,
|
|
21
21
|
endpointKey: string,
|
|
22
22
|
configId: string,
|
|
23
23
|
msg: WecomMessage,
|
|
24
24
|
logger: ReturnType<typeof getAdapterLogger>,
|
|
25
25
|
): boolean {
|
|
26
|
-
if (
|
|
26
|
+
if (msg.MsgType !== 'event') return false;
|
|
27
27
|
const eventName = msg.Event ?? 'unknown';
|
|
28
28
|
if (eventName === 'enter_agent') {
|
|
29
|
-
void
|
|
29
|
+
void emit('system.receive', buildSystem(msg, {
|
|
30
30
|
$id: `wecom:enter_agent:${msg.FromUserName}:${msg.CreateTime ?? Date.now()}`,
|
|
31
31
|
$adapter: 'wecom' as never,
|
|
32
32
|
$endpoint: configId,
|
|
@@ -48,7 +48,7 @@ export function receiveWecomSideEvent(
|
|
|
48
48
|
const parts = mapWecomEventParts(eventName);
|
|
49
49
|
if (!parts) return false;
|
|
50
50
|
const sceneType = resolveChatType(msg.FromUserName);
|
|
51
|
-
void
|
|
51
|
+
void emit('notice.receive', buildNotice(msg, {
|
|
52
52
|
$id: `wecom:${eventName}:${msg.FromUserName}:${msg.CreateTime ?? Date.now()}`,
|
|
53
53
|
$adapter: 'wecom' as never,
|
|
54
54
|
$endpoint: configId,
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent tool deps for wecom (get_user / departments / send_text).
|
|
3
|
-
* Endpoints register themselves on start; tools look up by endpoint id.
|
|
4
|
-
*/
|
|
5
|
-
export interface WecomAgentEndpoint {
|
|
6
|
-
getUserInfo(userId: string): Promise<unknown>;
|
|
7
|
-
getDepartmentUsers(deptId: number): Promise<unknown[]>;
|
|
8
|
-
getDepartmentList(deptId?: number): Promise<unknown[]>;
|
|
9
|
-
sendTextMessage(userId: string, content: string): Promise<boolean>;
|
|
10
|
-
}
|
|
11
|
-
export interface WecomAgentDeps {
|
|
12
|
-
getEndpoint: (endpointKey: string) => WecomAgentEndpoint;
|
|
13
|
-
}
|
|
14
|
-
export declare function registerWecomAgentEndpoint(endpointKey: string, endpoint: WecomAgentEndpoint): () => void;
|
|
15
|
-
/** Optional override used by tests / transitional callers. Pass `null` to clear. */
|
|
16
|
-
export declare function setWecomAgentDeps(deps: WecomAgentDeps | null): void;
|
|
17
|
-
export declare function getWecomAgentDeps(): WecomAgentDeps;
|
package/lib/wecom-agent-deps.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent tool deps for wecom (get_user / departments / send_text).
|
|
3
|
-
* Endpoints register themselves on start; tools look up by endpoint id.
|
|
4
|
-
*/
|
|
5
|
-
const endpoints = new Map();
|
|
6
|
-
let override = null;
|
|
7
|
-
export function registerWecomAgentEndpoint(endpointKey, endpoint) {
|
|
8
|
-
endpoints.set(endpointKey, endpoint);
|
|
9
|
-
return () => {
|
|
10
|
-
if (endpoints.get(endpointKey) === endpoint) {
|
|
11
|
-
endpoints.delete(endpointKey);
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
/** Optional override used by tests / transitional callers. Pass `null` to clear. */
|
|
16
|
-
export function setWecomAgentDeps(deps) {
|
|
17
|
-
override = deps;
|
|
18
|
-
}
|
|
19
|
-
export function getWecomAgentDeps() {
|
|
20
|
-
if (override)
|
|
21
|
-
return override;
|
|
22
|
-
return {
|
|
23
|
-
getEndpoint(endpointKey) {
|
|
24
|
-
const endpoint = endpoints.get(endpointKey);
|
|
25
|
-
if (!endpoint)
|
|
26
|
-
throw new Error(`Endpoint ${endpointKey} 不存在`);
|
|
27
|
-
return endpoint;
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
}
|
package/src/wecom-agent-deps.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent tool deps for wecom (get_user / departments / send_text).
|
|
3
|
-
* Endpoints register themselves on start; tools look up by endpoint id.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export interface WecomAgentEndpoint {
|
|
7
|
-
getUserInfo(userId: string): Promise<unknown>;
|
|
8
|
-
getDepartmentUsers(deptId: number): Promise<unknown[]>;
|
|
9
|
-
getDepartmentList(deptId?: number): Promise<unknown[]>;
|
|
10
|
-
sendTextMessage(userId: string, content: string): Promise<boolean>;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface WecomAgentDeps {
|
|
14
|
-
getEndpoint: (endpointKey: string) => WecomAgentEndpoint;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const endpoints = new Map<string, WecomAgentEndpoint>();
|
|
18
|
-
let override: WecomAgentDeps | null = null;
|
|
19
|
-
|
|
20
|
-
export function registerWecomAgentEndpoint(
|
|
21
|
-
endpointKey: string,
|
|
22
|
-
endpoint: WecomAgentEndpoint,
|
|
23
|
-
): () => void {
|
|
24
|
-
endpoints.set(endpointKey, endpoint);
|
|
25
|
-
return () => {
|
|
26
|
-
if (endpoints.get(endpointKey) === endpoint) {
|
|
27
|
-
endpoints.delete(endpointKey);
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** Optional override used by tests / transitional callers. Pass `null` to clear. */
|
|
33
|
-
export function setWecomAgentDeps(deps: WecomAgentDeps | null): void {
|
|
34
|
-
override = deps;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function getWecomAgentDeps(): WecomAgentDeps {
|
|
38
|
-
if (override) return override;
|
|
39
|
-
return {
|
|
40
|
-
getEndpoint(endpointKey) {
|
|
41
|
-
const endpoint = endpoints.get(endpointKey);
|
|
42
|
-
if (!endpoint) throw new Error(`Endpoint ${endpointKey} 不存在`);
|
|
43
|
-
return endpoint;
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
}
|