@zhin.js/adapter-wecom 0.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/src/index.ts ADDED
@@ -0,0 +1,134 @@
1
+ /**
2
+ * 企业微信适配器入口:类型扩展、导出、注册
3
+ */
4
+ import { usePlugin, type Plugin, type ToolFeature } from 'zhin.js';
5
+ import type { Router } from '@zhin.js/host-router/router';
6
+ import { WecomAdapter } from './adapter.js';
7
+ import {
8
+ registerWecomPlatformPermitChecker,
9
+ platformPermit,
10
+ } from './platform-permit.js';
11
+
12
+ declare module 'zhin.js' {
13
+ namespace Plugin {
14
+ interface Contexts {
15
+ router: import('@zhin.js/host-router').Router;
16
+ }
17
+ }
18
+ interface Adapters {
19
+ wecom: WecomAdapter;
20
+ }
21
+ }
22
+
23
+ export * from './types.js';
24
+ export { WecomEndpoint } from './endpoint.js';
25
+ export { WecomAdapter } from './adapter.js';
26
+
27
+ const plugin = usePlugin();
28
+ const { provide, useContext } = plugin;
29
+
30
+ useContext('router', (router: Router) => {
31
+ provide({
32
+ name: 'wecom',
33
+ description: 'WeCom (企业微信) Endpoint Adapter',
34
+ mounted: async (p: Plugin) => {
35
+ const adapter = new WecomAdapter(p, router);
36
+ await adapter.start();
37
+ return adapter;
38
+ },
39
+ dispose: async (adapter: WecomAdapter) => {
40
+ await adapter.stop();
41
+ },
42
+ });
43
+ });
44
+
45
+ useContext('tool', 'wecom', (toolService: ToolFeature, wecom: WecomAdapter) => {
46
+ const disposers: (() => void)[] = [];
47
+ disposers.push(registerWecomPlatformPermitChecker());
48
+
49
+ disposers.push(toolService.addTool({
50
+ name: 'wecom_get_user',
51
+ description: '获取企业微信用户信息',
52
+ parameters: {
53
+ type: 'object',
54
+ properties: {
55
+ endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
56
+ user_id: { type: 'string', description: '用户 ID' },
57
+ },
58
+ required: ['endpoint_id', 'user_id'],
59
+ },
60
+ platforms: ['wecom'],
61
+ tags: ['wecom'],
62
+ execute: async (args: Record<string, any>) => {
63
+ const endpoint = wecom.endpoints.get(args.endpoint_id);
64
+ if (!endpoint) throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
65
+ return await endpoint.getUserInfo(args.user_id);
66
+ },
67
+ }, plugin.name));
68
+
69
+ disposers.push(toolService.addTool({
70
+ name: 'wecom_get_dept_users',
71
+ description: '获取企业微信部门用户列表',
72
+ parameters: {
73
+ type: 'object',
74
+ properties: {
75
+ endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
76
+ dept_id: { type: 'string', description: '部门 ID' },
77
+ },
78
+ required: ['endpoint_id', 'dept_id'],
79
+ },
80
+ platforms: ['wecom'],
81
+ tags: ['wecom'],
82
+ execute: async (args: Record<string, any>) => {
83
+ const endpoint = wecom.endpoints.get(args.endpoint_id);
84
+ if (!endpoint) throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
85
+ const users = await endpoint.getDepartmentUsers(Number(args.dept_id));
86
+ return { users, count: users.length };
87
+ },
88
+ }, plugin.name));
89
+
90
+ disposers.push(toolService.addTool({
91
+ name: 'wecom_list_departments',
92
+ description: '获取企业微信部门列表',
93
+ parameters: {
94
+ type: 'object',
95
+ properties: {
96
+ endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
97
+ dept_id: { type: 'string', description: '父部门 ID,默认 1(跟部门)' },
98
+ },
99
+ required: ['endpoint_id'],
100
+ },
101
+ platforms: ['wecom'],
102
+ tags: ['wecom'],
103
+ execute: async (args: Record<string, any>) => {
104
+ const endpoint = wecom.endpoints.get(args.endpoint_id);
105
+ if (!endpoint) throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
106
+ const departments = await endpoint.getDepartmentList(Number(args.dept_id) || 1);
107
+ return { departments, count: departments.length };
108
+ },
109
+ }, plugin.name));
110
+
111
+ disposers.push(toolService.addTool({
112
+ name: 'wecom_send_text',
113
+ description: '向指定企业微信用户发送文本消息',
114
+ parameters: {
115
+ type: 'object',
116
+ properties: {
117
+ endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
118
+ user_id: { type: 'string', description: '用户 ID' },
119
+ content: { type: 'string', description: '消息内容' },
120
+ },
121
+ required: ['endpoint_id', 'user_id', 'content'],
122
+ },
123
+ platforms: ['wecom'],
124
+ tags: ['wecom'],
125
+ execute: async (args: Record<string, any>) => {
126
+ const endpoint = wecom.endpoints.get(args.endpoint_id);
127
+ if (!endpoint) throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
128
+ const success = await endpoint.sendTextMessage(args.user_id, args.content);
129
+ return { success, message: success ? '消息已发送' : '发送失败' };
130
+ },
131
+ }, plugin.name));
132
+
133
+ return () => disposers.forEach(d => d());
134
+ });
@@ -0,0 +1,53 @@
1
+ /**
2
+ * 企业微信 WeCom platform permit
3
+ */
4
+ import type { Message } from 'zhin.js';
5
+ import { registerPlatformPermitChecker } from 'zhin.js';
6
+
7
+ const ADAPTER = 'wecom';
8
+
9
+ export function platformPermit(perm: string): string {
10
+ return `platform(${ADAPTER},${perm})`;
11
+ }
12
+
13
+ const FACTORY_PERM_MAP: Record<string, string> = {
14
+ group_admin: 'chat_admin',
15
+ group_owner: 'chat_owner',
16
+ };
17
+
18
+ export function wecomGroupPermitResolver(logicalPerm: string): string {
19
+ return platformPermit(FACTORY_PERM_MAP[logicalPerm] ?? logicalPerm);
20
+ }
21
+
22
+ export function normalizeWecomSenderForPermit(input: {
23
+ isOwner?: boolean;
24
+ isAdmin?: boolean;
25
+ }): { role?: string; permissions?: string[] } {
26
+ if (input.isOwner) {
27
+ return { role: 'owner', permissions: ['chat_owner', 'chat_admin'] };
28
+ }
29
+ if (input.isAdmin) {
30
+ return { role: 'admin', permissions: ['chat_admin'] };
31
+ }
32
+ return { role: 'member', permissions: [] };
33
+ }
34
+
35
+ export function checkWecomPlatformPermit(perm: string, message: Message<any>): boolean {
36
+ const sender = message.$sender as { role?: string; permissions?: string[] };
37
+ const permissions = sender.permissions ?? [];
38
+ const role = sender.role;
39
+ const has = (t: string) => permissions.includes(t);
40
+
41
+ switch (perm) {
42
+ case 'chat_owner':
43
+ return role === 'owner' || has('chat_owner');
44
+ case 'chat_admin':
45
+ return role === 'owner' || role === 'admin' || has('chat_admin') || has('chat_owner');
46
+ default:
47
+ return false;
48
+ }
49
+ }
50
+
51
+ export function registerWecomPlatformPermitChecker(): () => void {
52
+ return registerPlatformPermitChecker(ADAPTER, checkWecomPlatformPermit);
53
+ }
package/src/types.ts ADDED
@@ -0,0 +1,51 @@
1
+ /**
2
+ * 企业微信适配器类型定义
3
+ */
4
+
5
+ export interface WecomEndpointConfig {
6
+ context: 'wecom'
7
+ name: string
8
+ corpId: string
9
+ agentSecret: string // 应用 Secret
10
+ token: string // 用于签名验证
11
+ encodingAESKey: string // 用于消息加解密
12
+ webhookPath?: string // 默认 '/wecom/callback'
13
+ apiBaseUrl?: string // 默认 'https://qyapi.weixin.qq.com'
14
+ }
15
+
16
+ export interface WecomMessage {
17
+ ToUserName: string
18
+ FromUserName: string
19
+ CreateTime: number
20
+ MsgType: 'text' | 'image' | 'voice' | 'video' | 'shortvideo' | 'location' | 'link' | 'event'
21
+ Content?: string
22
+ MsgId?: string
23
+ PicUrl?: string
24
+ MediaId?: string
25
+ ThumbMediaId?: string
26
+ Format?: string
27
+ Recognition?: string
28
+ Location_X?: string
29
+ Location_Y?: string
30
+ Scale?: string
31
+ Label?: string
32
+ Title?: string
33
+ Description?: string
34
+ Url?: string
35
+ Event?: string
36
+ EventKey?: string
37
+ AgentID?: string
38
+ [key: string]: unknown
39
+ }
40
+
41
+ export interface AccessToken {
42
+ access_token: string
43
+ expires_in: number
44
+ timestamp: number
45
+ }
46
+
47
+ export interface WecomApiResponse {
48
+ errcode: number
49
+ errmsg?: string
50
+ [key: string]: unknown
51
+ }