@zhin.js/adapter-lark 7.0.0 → 7.0.2
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 +30 -0
- package/README.md +11 -2
- package/adapters/lark.js +0 -3
- package/adapters/lark.ts +0 -3
- package/agent/tools/add_members.ts +4 -6
- package/agent/tools/create_chat.ts +4 -6
- package/agent/tools/dissolve_chat.ts +4 -6
- package/agent/tools/get_user.ts +4 -6
- package/agent/tools/remove_managers.ts +4 -6
- package/agent/tools/set_managers.ts +4 -6
- package/agent/tools/update_chat.ts +4 -6
- package/agent/tools/upload_file.ts +4 -8
- package/lib/client.d.ts +12 -0
- package/lib/client.js +2 -0
- package/lib/endpoint.d.ts +40 -5
- package/lib/endpoint.js +46 -7
- package/lib/index.d.ts +2 -2
- package/lib/index.js +2 -2
- package/lib/lark-endpoint-commands.d.ts +1 -1
- package/lib/protocol.d.ts +1 -1
- package/lib/protocol.js +1 -1
- package/lib/webhook.d.ts +1 -0
- package/lib/webhook.js +6 -0
- package/package.json +15 -14
- package/src/client.ts +16 -0
- package/src/endpoint.ts +62 -11
- package/src/index.ts +3 -7
- package/src/protocol.ts +1 -1
- package/src/webhook.ts +8 -0
- package/lib/lark-agent-deps.d.ts +0 -27
- package/lib/lark-agent-deps.js +0 -30
- package/src/lark-agent-deps.ts +0 -62
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @zhin.js/adapter-lark
|
|
2
2
|
|
|
3
|
+
## 7.0.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [736fa04]
|
|
8
|
+
- @zhin.js/agent@1.1.17
|
|
9
|
+
- zhin.js@6.0.14
|
|
10
|
+
|
|
11
|
+
## 7.0.1
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 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.
|
|
16
|
+
- Updated dependencies [e9c6a73]
|
|
17
|
+
- Updated dependencies [4e8117c]
|
|
18
|
+
- Updated dependencies [902fa35]
|
|
19
|
+
- Updated dependencies [54bfd6b]
|
|
20
|
+
- Updated dependencies [12025ee]
|
|
21
|
+
- Updated dependencies [09b14d6]
|
|
22
|
+
- Updated dependencies [1fc78bc]
|
|
23
|
+
- @zhin.js/agent@1.1.16
|
|
24
|
+
- @zhin.js/adapter@1.2.1
|
|
25
|
+
- @zhin.js/core@1.5.14
|
|
26
|
+
- @zhin.js/host-http@1.0.13
|
|
27
|
+
- @zhin.js/command@1.0.16
|
|
28
|
+
- @zhin.js/logger@1.0.77
|
|
29
|
+
- zhin.js@6.0.14
|
|
30
|
+
- @zhin.js/feature-kit@1.0.13
|
|
31
|
+
- @zhin.js/permission@1.0.4
|
|
32
|
+
|
|
3
33
|
## 7.0.0
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ pnpm add @zhin.js/adapter-lark
|
|
|
20
20
|
## Plugin Runtime
|
|
21
21
|
|
|
22
22
|
- `@zhin.js/adapter` — 约定式 `adapters/lark.ts`(`defineAdapter`)
|
|
23
|
-
- `@zhin.js/core` — `
|
|
23
|
+
- `@zhin.js/core` — `Endpoint.emit(...)` 入站、`outboundMessageToken` 出站
|
|
24
24
|
- `@zhin.js/host-http` — `httpHostToken` 注册 Webhook 路由(**非** legacy host-router/Koa)
|
|
25
25
|
- `zhin.js` — `plugin.ts`(`definePlugin`)
|
|
26
26
|
- 配置经插件 `schema.json` 落到 `plugins.<instanceKey>`
|
|
@@ -79,7 +79,7 @@ plugins:
|
|
|
79
79
|
|
|
80
80
|
## Agent 工具
|
|
81
81
|
|
|
82
|
-
`agent/` 目录保留(get_user
|
|
82
|
+
`agent/` 目录保留(get_user、群聊、管理员、上传文件等)。工具声明 `adapter: 'lark'` 后,通过惰性的 `context.$client` 自动取得当前操作的 `LarkClient`;无需把 Endpoint id 暴露给模型。
|
|
83
83
|
|
|
84
84
|
## 平台权限(platform permit)
|
|
85
85
|
|
|
@@ -91,3 +91,12 @@ plugins:
|
|
|
91
91
|
pnpm --filter @zhin.js/adapter-lark build
|
|
92
92
|
pnpm --filter @zhin.js/adapter-lark test
|
|
93
93
|
```
|
|
94
|
+
|
|
95
|
+
## 故障排查
|
|
96
|
+
|
|
97
|
+
| 现象 | 排查 |
|
|
98
|
+
| --- | --- |
|
|
99
|
+
| URL 验证失败 | 检查公网 HTTPS、`webhookPath`、verification token 与 encrypt key |
|
|
100
|
+
| Tenant Token 获取失败 | 检查 `appId`、`appSecret` 与应用版本是否已发布 |
|
|
101
|
+
| 群里 @机器人不触发 AI | 当前无法可靠判定 bot open_id;使用显式 AI 前缀 |
|
|
102
|
+
| 能收不能发 | 检查机器人消息权限、可见范围与应用是否已加入群聊 |
|
package/adapters/lark.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* Convention entry: discover `adapters/lark.ts` → defineAdapter.
|
|
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 { LarkEndpoint } from "../lib/endpoint.js";
|
|
9
8
|
import { resolveLarkConfig, } from "../lib/protocol.js";
|
|
@@ -30,8 +29,6 @@ export default defineAdapter({
|
|
|
30
29
|
});
|
|
31
30
|
return new LarkEndpoint({
|
|
32
31
|
id: context.id,
|
|
33
|
-
gateway: context.use(messageGatewayToken),
|
|
34
|
-
sideEvents: context.use(sideEventGatewayToken),
|
|
35
32
|
http: context.use(httpHostToken),
|
|
36
33
|
config,
|
|
37
34
|
});
|
package/adapters/lark.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Convention entry: discover `adapters/lark.ts` → defineAdapter.
|
|
3
3
|
*/
|
|
4
4
|
import { defineAdapter } from 'zhin.js/adapter';
|
|
5
|
-
import { messageGatewayToken, sideEventGatewayToken } from '@zhin.js/core/runtime';
|
|
6
5
|
import { httpHostToken } from '@zhin.js/host-http';
|
|
7
6
|
import { LarkEndpoint } from '../src/endpoint.js';
|
|
8
7
|
import {
|
|
@@ -35,8 +34,6 @@ export default defineAdapter<LarkAdapterConfig>({
|
|
|
35
34
|
});
|
|
36
35
|
return new LarkEndpoint({
|
|
37
36
|
id: context.id,
|
|
38
|
-
gateway: context.use(messageGatewayToken),
|
|
39
|
-
sideEvents: context.use(sideEventGatewayToken),
|
|
40
37
|
http: context.use(httpHostToken),
|
|
41
38
|
config,
|
|
42
39
|
});
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { getLarkAgentDeps } from '../../src/lark-agent-deps.js';
|
|
4
3
|
import { platformPermit } from '../../src/platform-permit.js';
|
|
5
4
|
|
|
6
|
-
export default defineAgentTool<{
|
|
5
|
+
export default defineAgentTool<{ chat_id: string; user_ids: string }>({
|
|
7
6
|
description: '添加飞书群成员',
|
|
8
7
|
inputSchema: z.object({
|
|
9
|
-
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
10
8
|
chat_id: z.string().describe('群聊 ID'),
|
|
11
9
|
user_ids: z.string().describe('用户 open_id 列表,逗号分隔'),
|
|
12
10
|
}),
|
|
13
|
-
|
|
11
|
+
adapter: 'lark',
|
|
14
12
|
tags: ['lark'],
|
|
15
13
|
permissions: [platformPermit('chat_admin')],
|
|
16
|
-
async execute({
|
|
17
|
-
const endpoint =
|
|
14
|
+
async execute({ chat_id, user_ids }: { chat_id: string; user_ids: string }, context) {
|
|
15
|
+
const endpoint = context.$client;
|
|
18
16
|
const success = await endpoint.addChatMembers(chat_id, user_ids.split(','));
|
|
19
17
|
return { success, message: success ? '成员添加成功' : '添加失败' };
|
|
20
18
|
},
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
|
|
4
|
-
export default defineAgentTool<{ endpoint_id: string; name: string; members: string; owner?: string }>({
|
|
3
|
+
export default defineAgentTool<{ name: string; members: string; owner?: string }>({
|
|
5
4
|
description: '创建飞书群聊',
|
|
6
5
|
inputSchema: z.object({
|
|
7
|
-
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
8
6
|
name: z.string().describe('群名'),
|
|
9
7
|
members: z.string().describe('成员 open_id 列表,逗号分隔'),
|
|
10
8
|
owner: z.string().optional().describe('群主 open_id(可选)'),
|
|
11
9
|
}),
|
|
12
|
-
|
|
10
|
+
adapter: 'lark',
|
|
13
11
|
tags: ['lark'],
|
|
14
|
-
async execute({
|
|
15
|
-
const endpoint =
|
|
12
|
+
async execute({ name, members, owner }: { name: string; members: string; owner?: string }, context) {
|
|
13
|
+
const endpoint = context.$client;
|
|
16
14
|
const chatId = await endpoint.createChat(name, members.split(','), owner);
|
|
17
15
|
return { success: !!chatId, chat_id: chatId, message: chatId ? `群聊创建成功: ${chatId}` : '创建失败' };
|
|
18
16
|
},
|
|
@@ -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; chat_id: string }>({
|
|
3
|
+
export default defineAgentTool<{ chat_id: string }>({
|
|
5
4
|
description: '解散飞书群聊(需要群主权限)',
|
|
6
5
|
inputSchema: z.object({
|
|
7
|
-
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
8
6
|
chat_id: z.string().describe('群聊 ID'),
|
|
9
7
|
}),
|
|
10
|
-
|
|
8
|
+
adapter: 'lark',
|
|
11
9
|
tags: ['lark'],
|
|
12
|
-
async execute({
|
|
13
|
-
const endpoint =
|
|
10
|
+
async execute({ chat_id }: { chat_id: string }, context) {
|
|
11
|
+
const endpoint = context.$client;
|
|
14
12
|
const success = await endpoint.dissolveChat(chat_id);
|
|
15
13
|
return { success, message: success ? '群聊已解散' : '解散失败' };
|
|
16
14
|
},
|
package/agent/tools/get_user.ts
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { getLarkAgentDeps } from '../../src/lark-agent-deps.js';
|
|
4
3
|
|
|
5
|
-
export default defineAgentTool<{
|
|
4
|
+
export default defineAgentTool<{ user_id: string }>({
|
|
6
5
|
description: '获取飞书用户信息',
|
|
7
6
|
inputSchema: z.object({
|
|
8
|
-
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
9
7
|
user_id: z.string().describe('用户 ID (open_id)'),
|
|
10
8
|
}),
|
|
11
|
-
|
|
9
|
+
adapter: 'lark',
|
|
12
10
|
tags: ['lark'],
|
|
13
|
-
async execute({
|
|
14
|
-
const endpoint =
|
|
11
|
+
async execute({ user_id }: { user_id: string }, context) {
|
|
12
|
+
const endpoint = context.$client;
|
|
15
13
|
return await endpoint.getUserInfo(user_id);
|
|
16
14
|
},
|
|
17
15
|
});
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { getLarkAgentDeps } from '../../src/lark-agent-deps.js';
|
|
4
3
|
import { platformPermit } from '../../src/platform-permit.js';
|
|
5
4
|
|
|
6
|
-
export default defineAgentTool<{
|
|
5
|
+
export default defineAgentTool<{ chat_id: string; user_ids: string }>({
|
|
7
6
|
description: '移除飞书群管理员',
|
|
8
7
|
inputSchema: z.object({
|
|
9
|
-
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
10
8
|
chat_id: z.string().describe('群聊 ID'),
|
|
11
9
|
user_ids: z.string().describe('用户 open_id 列表,逗号分隔'),
|
|
12
10
|
}),
|
|
13
|
-
|
|
11
|
+
adapter: 'lark',
|
|
14
12
|
tags: ['lark'],
|
|
15
13
|
permissions: [platformPermit('manage_managers')],
|
|
16
|
-
async execute({
|
|
17
|
-
const endpoint =
|
|
14
|
+
async execute({ chat_id, user_ids }: { chat_id: string; user_ids: string }, context) {
|
|
15
|
+
const endpoint = context.$client;
|
|
18
16
|
const success = await endpoint.removeChatManagers(chat_id, user_ids.split(','));
|
|
19
17
|
return { success, message: success ? '管理员移除成功' : '移除失败' };
|
|
20
18
|
},
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { getLarkAgentDeps } from '../../src/lark-agent-deps.js';
|
|
4
3
|
import { platformPermit } from '../../src/platform-permit.js';
|
|
5
4
|
|
|
6
|
-
export default defineAgentTool<{
|
|
5
|
+
export default defineAgentTool<{ chat_id: string; user_ids: string }>({
|
|
7
6
|
description: '设置飞书群管理员',
|
|
8
7
|
inputSchema: z.object({
|
|
9
|
-
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
10
8
|
chat_id: z.string().describe('群聊 ID'),
|
|
11
9
|
user_ids: z.string().describe('用户 open_id 列表,逗号分隔'),
|
|
12
10
|
}),
|
|
13
|
-
|
|
11
|
+
adapter: 'lark',
|
|
14
12
|
tags: ['lark'],
|
|
15
13
|
permissions: [platformPermit('manage_managers')],
|
|
16
|
-
async execute({
|
|
17
|
-
const endpoint =
|
|
14
|
+
async execute({ chat_id, user_ids }: { chat_id: string; user_ids: string }, context) {
|
|
15
|
+
const endpoint = context.$client;
|
|
18
16
|
const success = await endpoint.setChatManagers(chat_id, user_ids.split(','));
|
|
19
17
|
return { success, message: success ? '管理员设置成功' : '设置失败' };
|
|
20
18
|
},
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { getLarkAgentDeps } from '../../src/lark-agent-deps.js';
|
|
4
3
|
import { platformPermit } from '../../src/platform-permit.js';
|
|
5
4
|
|
|
6
|
-
export default defineAgentTool<{
|
|
5
|
+
export default defineAgentTool<{ chat_id: string; name?: string; description?: string }>({
|
|
7
6
|
description: '更新飞书群聊信息(群名、描述)',
|
|
8
7
|
inputSchema: z.object({
|
|
9
|
-
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
10
8
|
chat_id: z.string().describe('群聊 ID'),
|
|
11
9
|
name: z.string().optional().describe('新群名(可选)'),
|
|
12
10
|
description: z.string().optional().describe('新描述(可选)'),
|
|
13
11
|
}),
|
|
14
|
-
|
|
12
|
+
adapter: 'lark',
|
|
15
13
|
tags: ['lark'],
|
|
16
14
|
permissions: [platformPermit('chat_admin')],
|
|
17
|
-
async execute({
|
|
18
|
-
const endpoint =
|
|
15
|
+
async execute({ chat_id, name, description }: { chat_id: string; name?: string; description?: string }, context) {
|
|
16
|
+
const endpoint = context.$client;
|
|
19
17
|
const success = await endpoint.updateChatInfo(chat_id, { name, description });
|
|
20
18
|
return { success, message: success ? '群信息更新成功' : '更新失败' };
|
|
21
19
|
},
|
|
@@ -1,26 +1,22 @@
|
|
|
1
1
|
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { getLarkAgentDeps } from '../../src/lark-agent-deps.js';
|
|
4
3
|
|
|
5
4
|
export default defineAgentTool<{
|
|
6
|
-
endpoint_id: string;
|
|
7
5
|
file_path: string;
|
|
8
6
|
file_type: 'image' | 'file' | 'video' | 'audio';
|
|
9
7
|
}>({
|
|
10
8
|
description: '上传文件到飞书(image/file/video/audio)',
|
|
11
9
|
inputSchema: z.object({
|
|
12
|
-
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
13
10
|
file_path: z.string().describe('本地文件路径'),
|
|
14
11
|
file_type: z.enum(['image', 'file', 'video', 'audio']).default('file').describe('飞书文件类型'),
|
|
15
12
|
}),
|
|
16
|
-
|
|
13
|
+
adapter: 'lark',
|
|
17
14
|
tags: ['lark'],
|
|
18
|
-
async execute({
|
|
19
|
-
endpoint_id: string;
|
|
15
|
+
async execute({ file_path, file_type }: {
|
|
20
16
|
file_path: string;
|
|
21
17
|
file_type: 'image' | 'file' | 'video' | 'audio';
|
|
22
|
-
}) {
|
|
23
|
-
const endpoint =
|
|
18
|
+
}, context) {
|
|
19
|
+
const endpoint = context.$client;
|
|
24
20
|
const result = await endpoint.uploadFile(file_path, file_type);
|
|
25
21
|
return { success: true, file_key: result, message: `文件已上传,file_key: ${result}` };
|
|
26
22
|
},
|
package/lib/client.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { LarkClient } from './endpoint.js';
|
|
2
|
+
import type { LarkEventBody } from './protocol.js';
|
|
3
|
+
export type LarkClientEventMap = Record<string, LarkEventBody>;
|
|
4
|
+
declare module '@zhin.js/feature-kit' {
|
|
5
|
+
interface AdapterClientRegistry {
|
|
6
|
+
readonly lark: {
|
|
7
|
+
readonly client: LarkClient;
|
|
8
|
+
readonly events: LarkClientEventMap;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export declare const larkClient: import("@zhin.js/adapter").EndpointClientToken<LarkClient, LarkClientEventMap>;
|
package/lib/client.js
ADDED
package/lib/endpoint.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type
|
|
1
|
+
import { Endpoint } from 'zhin.js/adapter';
|
|
2
|
+
import { type EndpointControl, type EndpointManagement, type EndpointSendRequest } from 'zhin.js/adapter';
|
|
3
3
|
import type { HttpHost } from '@zhin.js/host-http';
|
|
4
4
|
import type { CapabilityId } from 'zhin.js';
|
|
5
5
|
import { resolveMediaBinary } from './media-upload.js';
|
|
@@ -17,14 +17,48 @@ export type LarkFetch = (url: string, init?: {
|
|
|
17
17
|
}>;
|
|
18
18
|
export interface LarkEndpointOptions {
|
|
19
19
|
readonly id: CapabilityId;
|
|
20
|
-
readonly gateway: MessageGateway;
|
|
21
|
-
readonly sideEvents?: SideEventGateway;
|
|
22
20
|
readonly http: HttpHost;
|
|
23
21
|
readonly config: ResolvedLarkConfig;
|
|
24
22
|
readonly fetch?: LarkFetch;
|
|
25
23
|
}
|
|
26
|
-
export
|
|
24
|
+
export interface LarkClientApi {
|
|
25
|
+
getUserInfo(userId: string, userIdType?: 'open_id' | 'user_id' | 'union_id'): Promise<unknown>;
|
|
26
|
+
getChatInfo(chatId: string): Promise<unknown>;
|
|
27
|
+
uploadFile(filePath: string, fileType?: 'image' | 'file' | 'video' | 'audio'): Promise<string | null>;
|
|
28
|
+
createChat(name: string, userIds: string[], ownerId?: string): Promise<string | null>;
|
|
29
|
+
updateChatInfo(chatId: string, options: {
|
|
30
|
+
name?: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
}): Promise<boolean>;
|
|
33
|
+
addChatMembers(chatId: string, userIds: string[]): Promise<boolean>;
|
|
34
|
+
removeChatMembers(chatId: string, userIds: string[]): Promise<boolean>;
|
|
35
|
+
getChatMembers(chatId: string): Promise<unknown[]>;
|
|
36
|
+
dissolveChat(chatId: string): Promise<boolean>;
|
|
37
|
+
setChatManagers(chatId: string, userIds: string[]): Promise<boolean>;
|
|
38
|
+
removeChatManagers(chatId: string, userIds: string[]): Promise<boolean>;
|
|
39
|
+
}
|
|
40
|
+
/** Feishu/Lark OpenAPI client surface carried by every Endpoint event. */
|
|
41
|
+
export declare class LarkClient implements LarkClientApi {
|
|
42
|
+
readonly api: LarkClientApi;
|
|
43
|
+
constructor(api: LarkClientApi);
|
|
44
|
+
getUserInfo: (id: string, type?: "open_id" | "user_id" | "union_id") => Promise<unknown>;
|
|
45
|
+
getChatInfo: (id: string) => Promise<unknown>;
|
|
46
|
+
uploadFile: (path: string, type?: "image" | "file" | "video" | "audio") => Promise<string | null>;
|
|
47
|
+
createChat: (name: string, users: string[], owner?: string) => Promise<string | null>;
|
|
48
|
+
updateChatInfo: (id: string, options: {
|
|
49
|
+
name?: string;
|
|
50
|
+
description?: string;
|
|
51
|
+
}) => Promise<boolean>;
|
|
52
|
+
addChatMembers: (id: string, users: string[]) => Promise<boolean>;
|
|
53
|
+
removeChatMembers: (id: string, users: string[]) => Promise<boolean>;
|
|
54
|
+
getChatMembers: (id: string) => Promise<unknown[]>;
|
|
55
|
+
dissolveChat: (id: string) => Promise<boolean>;
|
|
56
|
+
setChatManagers: (id: string, users: string[]) => Promise<boolean>;
|
|
57
|
+
removeChatManagers: (id: string, users: string[]) => Promise<boolean>;
|
|
58
|
+
}
|
|
59
|
+
export declare class LarkEndpoint extends Endpoint<LarkClient> {
|
|
27
60
|
#private;
|
|
61
|
+
readonly client: LarkClient;
|
|
28
62
|
/**
|
|
29
63
|
* Console 社交面语义端口。Lark OpenAPI 仅接读取类列表能力:
|
|
30
64
|
* - listGroups:GET /im/v1/chats(bot 所在群列表,分页归一为 {group_id: chat_id, name})
|
|
@@ -48,6 +82,7 @@ export declare class LarkEndpoint implements EndpointInstance {
|
|
|
48
82
|
uploadImage(media: Parameters<typeof resolveMediaBinary>[0]): Promise<string | null>;
|
|
49
83
|
/** Test / internal: admit a parsed message when open (non-webhook path). */
|
|
50
84
|
admit(msg: LarkMessage): void;
|
|
85
|
+
admitPlatform(name: string, event: unknown): void;
|
|
51
86
|
getUserInfo(userId: string, userIdType?: 'open_id' | 'user_id' | 'union_id'): Promise<unknown>;
|
|
52
87
|
getChatInfo(chatId: string): Promise<unknown>;
|
|
53
88
|
uploadFile(filePath: string, fileType?: 'image' | 'file' | 'video' | 'audio'): Promise<string | null>;
|
package/lib/endpoint.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Endpoint } from 'zhin.js/adapter';
|
|
1
2
|
/**
|
|
2
3
|
* LarkEndpoint — lifecycle, outbound, admit, OpenAPI helpers for agent tools.
|
|
3
4
|
*/
|
|
@@ -5,13 +6,43 @@ import { readFile } from 'node:fs/promises';
|
|
|
5
6
|
import { basename } from 'node:path';
|
|
6
7
|
import { createRecallEndpointControl, } from 'zhin.js/adapter';
|
|
7
8
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
8
|
-
import { registerLarkAgentEndpoint } from './lark-agent-deps.js';
|
|
9
9
|
import { buildImageUploadForm, readOutboundImageMedia, resolveMediaBinary, } from './media-upload.js';
|
|
10
10
|
import { formatInboundContent, formatOutboundBody, generateMessageId, larkInboundConversation, resolveChatType, resolveSender, } from './protocol.js';
|
|
11
11
|
import { registerLarkWebhookRoutes } from './webhook.js';
|
|
12
12
|
/** 出站 HTTP 调用统一 30s 超时。 */
|
|
13
13
|
const OUTBOUND_TIMEOUT_MS = 30_000;
|
|
14
|
-
|
|
14
|
+
/** Feishu/Lark OpenAPI client surface carried by every Endpoint event. */
|
|
15
|
+
export class LarkClient {
|
|
16
|
+
api;
|
|
17
|
+
constructor(api) {
|
|
18
|
+
this.api = api;
|
|
19
|
+
}
|
|
20
|
+
getUserInfo = (id, type) => this.api.getUserInfo(id, type);
|
|
21
|
+
getChatInfo = (id) => this.api.getChatInfo(id);
|
|
22
|
+
uploadFile = (path, type) => this.api.uploadFile(path, type);
|
|
23
|
+
createChat = (name, users, owner) => this.api.createChat(name, users, owner);
|
|
24
|
+
updateChatInfo = (id, options) => this.api.updateChatInfo(id, options);
|
|
25
|
+
addChatMembers = (id, users) => this.api.addChatMembers(id, users);
|
|
26
|
+
removeChatMembers = (id, users) => this.api.removeChatMembers(id, users);
|
|
27
|
+
getChatMembers = (id) => this.api.getChatMembers(id);
|
|
28
|
+
dissolveChat = (id) => this.api.dissolveChat(id);
|
|
29
|
+
setChatManagers = (id, users) => this.api.setChatManagers(id, users);
|
|
30
|
+
removeChatManagers = (id, users) => this.api.removeChatManagers(id, users);
|
|
31
|
+
}
|
|
32
|
+
export class LarkEndpoint extends Endpoint {
|
|
33
|
+
client = new LarkClient({
|
|
34
|
+
getUserInfo: (id, type) => this.getUserInfo(id, type),
|
|
35
|
+
getChatInfo: (id) => this.getChatInfo(id),
|
|
36
|
+
uploadFile: (path, type) => this.uploadFile(path, type),
|
|
37
|
+
createChat: (name, users, owner) => this.createChat(name, users, owner),
|
|
38
|
+
updateChatInfo: (id, options) => this.updateChatInfo(id, options),
|
|
39
|
+
addChatMembers: (id, users) => this.addChatMembers(id, users),
|
|
40
|
+
removeChatMembers: (id, users) => this.removeChatMembers(id, users),
|
|
41
|
+
getChatMembers: (id) => this.getChatMembers(id),
|
|
42
|
+
dissolveChat: (id) => this.dissolveChat(id),
|
|
43
|
+
setChatManagers: (id, users) => this.setChatManagers(id, users),
|
|
44
|
+
removeChatManagers: (id, users) => this.removeChatManagers(id, users),
|
|
45
|
+
});
|
|
15
46
|
#logger;
|
|
16
47
|
#options;
|
|
17
48
|
#fetch;
|
|
@@ -45,8 +76,8 @@ export class LarkEndpoint {
|
|
|
45
76
|
#refreshPromise = null;
|
|
46
77
|
#open = false;
|
|
47
78
|
#started = false;
|
|
48
|
-
#unregisterAgent;
|
|
49
79
|
constructor(options) {
|
|
80
|
+
super();
|
|
50
81
|
this.#logger = getAdapterLogger('lark', options.config.id);
|
|
51
82
|
this.#options = options;
|
|
52
83
|
this.#fetch = options.fetch ?? globalThis.fetch;
|
|
@@ -73,7 +104,6 @@ export class LarkEndpoint {
|
|
|
73
104
|
}));
|
|
74
105
|
}
|
|
75
106
|
await this.#refreshAccessToken();
|
|
76
|
-
this.#unregisterAgent = registerLarkAgentEndpoint(this.#options.config.id, this);
|
|
77
107
|
this.#routeReleases.push(...registerLarkWebhookRoutes(this.#options.http, this));
|
|
78
108
|
this.#logger.debug(formatCompact({
|
|
79
109
|
endpoint: this.#options.config.id,
|
|
@@ -97,8 +127,6 @@ export class LarkEndpoint {
|
|
|
97
127
|
this.#open = false;
|
|
98
128
|
for (const release of this.#routeReleases.splice(0))
|
|
99
129
|
release();
|
|
100
|
-
this.#unregisterAgent?.();
|
|
101
|
-
this.#unregisterAgent = undefined;
|
|
102
130
|
this.#started = false;
|
|
103
131
|
this.#logger.debug(formatCompact({ op: 'disconnect' }));
|
|
104
132
|
}
|
|
@@ -186,7 +214,7 @@ export class LarkEndpoint {
|
|
|
186
214
|
if (!this.#open)
|
|
187
215
|
return;
|
|
188
216
|
const conversation = larkInboundConversation(String(this.#options.id), msg);
|
|
189
|
-
void this
|
|
217
|
+
void this.emit('message.receive', {
|
|
190
218
|
conversation,
|
|
191
219
|
message: { conversation, id: generateMessageId(msg) },
|
|
192
220
|
content: formatInboundContent(msg),
|
|
@@ -204,6 +232,17 @@ export class LarkEndpoint {
|
|
|
204
232
|
}));
|
|
205
233
|
});
|
|
206
234
|
}
|
|
235
|
+
admitPlatform(name, event) {
|
|
236
|
+
if (!this.#open)
|
|
237
|
+
return;
|
|
238
|
+
void this.emitPlatform(name, event).catch((error) => {
|
|
239
|
+
this.#logger.warn(formatCompact({
|
|
240
|
+
op: 'lark_platform_event_failed',
|
|
241
|
+
event: name,
|
|
242
|
+
error: error instanceof Error ? error.message : String(error),
|
|
243
|
+
}));
|
|
244
|
+
});
|
|
245
|
+
}
|
|
207
246
|
async getUserInfo(userId, userIdType = 'open_id') {
|
|
208
247
|
try {
|
|
209
248
|
const data = await this.#request(`/contact/v3/users/${userId}`, {
|
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { formatInboundContent, formatOutboundBody, generateMessageId, headerValue, larkInboundConversation, normalizeWebhookPath, readTextBody, resolveChatType, resolveLarkConfig, resolveSender, verifySignature, type AccessToken, type LarkAdapterConfig, type LarkApiResponse, type LarkEventBody, type LarkMessage, type LarkSendBody, type LarkWireSegment, type ResolvedLarkConfig, } from './protocol.js';
|
|
2
|
-
export {
|
|
2
|
+
export { larkClient, type LarkClientEventMap } from './client.js';
|
|
3
3
|
export { checkLarkPlatformPermit, larkGroupPermitResolver, normalizeLarkSenderForPermit, platformPermit, } from './platform-permit.js';
|
|
4
|
-
export { LarkEndpoint, type LarkEndpointOptions, type LarkFetch, } from './endpoint.js';
|
|
4
|
+
export { LarkClient, LarkEndpoint, type LarkClientApi, type LarkEndpointOptions, type LarkFetch, } from './endpoint.js';
|
|
5
5
|
export { buildImageUploadForm, readOutboundImageMedia, resolveMediaBinary, type MediaBinary, } from './media-upload.js';
|
|
6
6
|
export { registerLarkWebhookRoutes, handleLarkWebhookRequest, type LarkWebhookHandler, } from './webhook.js';
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { formatInboundContent, formatOutboundBody, generateMessageId, headerValue, larkInboundConversation, normalizeWebhookPath, readTextBody, resolveChatType, resolveLarkConfig, resolveSender, verifySignature, } from './protocol.js';
|
|
2
|
-
export {
|
|
2
|
+
export { larkClient } from './client.js';
|
|
3
3
|
export { checkLarkPlatformPermit, larkGroupPermitResolver, normalizeLarkSenderForPermit, platformPermit, } from './platform-permit.js';
|
|
4
|
-
export { LarkEndpoint, } from './endpoint.js';
|
|
4
|
+
export { LarkClient, LarkEndpoint, } from './endpoint.js';
|
|
5
5
|
export { buildImageUploadForm, readOutboundImageMedia, resolveMediaBinary, } from './media-upload.js';
|
|
6
6
|
export { registerLarkWebhookRoutes, handleLarkWebhookRequest, } from './webhook.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const larkEndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage>>>;
|
|
1
|
+
export declare const larkEndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage, string | undefined>>>;
|
package/lib/protocol.d.ts
CHANGED
|
@@ -105,7 +105,7 @@ export declare function resolveChatType(chatId?: string, chatType?: string): 'gr
|
|
|
105
105
|
export declare function larkInboundConversation(endpointKey: string, msg: LarkMessage): ConversationRef;
|
|
106
106
|
export declare function resolveSender(msg: LarkMessage): string;
|
|
107
107
|
export declare function generateMessageId(msg: LarkMessage): string;
|
|
108
|
-
/** Build inbound text for
|
|
108
|
+
/** Build inbound text for OutboundMessageService.receive. */
|
|
109
109
|
export declare function formatInboundContent(msg: LarkMessage): string;
|
|
110
110
|
/** 验签时间戳时效窗口(防重放)。 */
|
|
111
111
|
export declare const LARK_SIGNATURE_MAX_AGE_MS: number;
|
package/lib/protocol.js
CHANGED
|
@@ -69,7 +69,7 @@ export function resolveSender(msg) {
|
|
|
69
69
|
export function generateMessageId(msg) {
|
|
70
70
|
return msg.message_id || `${msg.create_time ?? Date.now()}`;
|
|
71
71
|
}
|
|
72
|
-
/** Build inbound text for
|
|
72
|
+
/** Build inbound text for OutboundMessageService.receive. */
|
|
73
73
|
export function formatInboundContent(msg) {
|
|
74
74
|
if (!msg.content || !msg.message_type)
|
|
75
75
|
return '';
|
package/lib/webhook.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { type LarkMessage, type ResolvedLarkConfig } from './protocol.js';
|
|
|
7
7
|
export interface LarkWebhookHandler {
|
|
8
8
|
readonly config: ResolvedLarkConfig;
|
|
9
9
|
readonly isOpen: boolean;
|
|
10
|
+
admitPlatform(name: string, event: unknown): void;
|
|
10
11
|
admit(msg: LarkMessage): void;
|
|
11
12
|
}
|
|
12
13
|
export declare function registerLarkWebhookRoutes(http: HttpHost, handler: LarkWebhookHandler): HttpRouteRegistration[];
|
package/lib/webhook.js
CHANGED
|
@@ -44,6 +44,12 @@ export async function handleLarkWebhookRequest(request, response, handler) {
|
|
|
44
44
|
response.end(JSON.stringify({ code: 0, msg: 'success' }));
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
|
+
if (handler.isOpen) {
|
|
48
|
+
const eventName = event.type === 'event_callback'
|
|
49
|
+
? String(event.event?.type ?? event.type)
|
|
50
|
+
: String(event.type ?? 'event');
|
|
51
|
+
handler.admitPlatform(eventName, event);
|
|
52
|
+
}
|
|
47
53
|
if (event.type === 'url_verification') {
|
|
48
54
|
response.writeHead(200, { 'Content-Type': 'application/json' });
|
|
49
55
|
response.end(JSON.stringify({ challenge: event.challenge }));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-lark",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.2",
|
|
4
4
|
"description": "Zhin.js Lark/Feishu (飞书) 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/lark"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@zhin.js/adapter": "1.2.
|
|
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.2.
|
|
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.17",
|
|
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.17",
|
|
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 { LarkClient } from './endpoint.js';
|
|
3
|
+
import type { LarkEventBody } from './protocol.js';
|
|
4
|
+
|
|
5
|
+
export type LarkClientEventMap = Record<string, LarkEventBody>;
|
|
6
|
+
|
|
7
|
+
declare module '@zhin.js/feature-kit' {
|
|
8
|
+
interface AdapterClientRegistry {
|
|
9
|
+
readonly lark: {
|
|
10
|
+
readonly client: LarkClient;
|
|
11
|
+
readonly events: LarkClientEventMap;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const larkClient = defineEndpointClient<LarkClient, LarkClientEventMap>('lark');
|
package/src/endpoint.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Endpoint } from 'zhin.js/adapter';
|
|
1
2
|
/**
|
|
2
3
|
* LarkEndpoint — lifecycle, outbound, admit, OpenAPI helpers for agent tools.
|
|
3
4
|
*/
|
|
@@ -7,15 +8,12 @@ import {
|
|
|
7
8
|
createRecallEndpointControl,
|
|
8
9
|
type EndpointControl,
|
|
9
10
|
type EndpointGroup,
|
|
10
|
-
type EndpointInstance,
|
|
11
11
|
type EndpointManagement,
|
|
12
12
|
type EndpointSendRequest,
|
|
13
13
|
} from 'zhin.js/adapter';
|
|
14
|
-
import type { MessageGateway, SideEventGateway } from '@zhin.js/core/runtime';
|
|
15
14
|
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
16
15
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
17
16
|
import type { CapabilityId } from 'zhin.js';
|
|
18
|
-
import { registerLarkAgentEndpoint } from './lark-agent-deps.js';
|
|
19
17
|
import {
|
|
20
18
|
buildImageUploadForm,
|
|
21
19
|
readOutboundImageMedia,
|
|
@@ -55,14 +53,59 @@ export type LarkFetch = (
|
|
|
55
53
|
|
|
56
54
|
export interface LarkEndpointOptions {
|
|
57
55
|
readonly id: CapabilityId;
|
|
58
|
-
readonly gateway: MessageGateway;
|
|
59
|
-
readonly sideEvents?: SideEventGateway;
|
|
60
56
|
readonly http: HttpHost;
|
|
61
57
|
readonly config: ResolvedLarkConfig;
|
|
62
58
|
readonly fetch?: LarkFetch;
|
|
63
59
|
}
|
|
64
60
|
|
|
65
|
-
export
|
|
61
|
+
export interface LarkClientApi {
|
|
62
|
+
getUserInfo(userId: string, userIdType?: 'open_id' | 'user_id' | 'union_id'): Promise<unknown>;
|
|
63
|
+
getChatInfo(chatId: string): Promise<unknown>;
|
|
64
|
+
uploadFile(filePath: string, fileType?: 'image' | 'file' | 'video' | 'audio'): Promise<string | null>;
|
|
65
|
+
createChat(name: string, userIds: string[], ownerId?: string): Promise<string | null>;
|
|
66
|
+
updateChatInfo(chatId: string, options: { name?: string; description?: string }): Promise<boolean>;
|
|
67
|
+
addChatMembers(chatId: string, userIds: string[]): Promise<boolean>;
|
|
68
|
+
removeChatMembers(chatId: string, userIds: string[]): Promise<boolean>;
|
|
69
|
+
getChatMembers(chatId: string): Promise<unknown[]>;
|
|
70
|
+
dissolveChat(chatId: string): Promise<boolean>;
|
|
71
|
+
setChatManagers(chatId: string, userIds: string[]): Promise<boolean>;
|
|
72
|
+
removeChatManagers(chatId: string, userIds: string[]): Promise<boolean>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Feishu/Lark OpenAPI client surface carried by every Endpoint event. */
|
|
76
|
+
export class LarkClient implements LarkClientApi {
|
|
77
|
+
constructor(readonly api: LarkClientApi) {}
|
|
78
|
+
getUserInfo = (id: string, type?: 'open_id' | 'user_id' | 'union_id') =>
|
|
79
|
+
this.api.getUserInfo(id, type);
|
|
80
|
+
getChatInfo = (id: string) => this.api.getChatInfo(id);
|
|
81
|
+
uploadFile = (path: string, type?: 'image' | 'file' | 'video' | 'audio') =>
|
|
82
|
+
this.api.uploadFile(path, type);
|
|
83
|
+
createChat = (name: string, users: string[], owner?: string) =>
|
|
84
|
+
this.api.createChat(name, users, owner);
|
|
85
|
+
updateChatInfo = (id: string, options: { name?: string; description?: string }) =>
|
|
86
|
+
this.api.updateChatInfo(id, options);
|
|
87
|
+
addChatMembers = (id: string, users: string[]) => this.api.addChatMembers(id, users);
|
|
88
|
+
removeChatMembers = (id: string, users: string[]) => this.api.removeChatMembers(id, users);
|
|
89
|
+
getChatMembers = (id: string) => this.api.getChatMembers(id);
|
|
90
|
+
dissolveChat = (id: string) => this.api.dissolveChat(id);
|
|
91
|
+
setChatManagers = (id: string, users: string[]) => this.api.setChatManagers(id, users);
|
|
92
|
+
removeChatManagers = (id: string, users: string[]) => this.api.removeChatManagers(id, users);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export class LarkEndpoint extends Endpoint<LarkClient> {
|
|
96
|
+
readonly client = new LarkClient({
|
|
97
|
+
getUserInfo: (id, type) => this.getUserInfo(id, type),
|
|
98
|
+
getChatInfo: (id) => this.getChatInfo(id),
|
|
99
|
+
uploadFile: (path, type) => this.uploadFile(path, type),
|
|
100
|
+
createChat: (name, users, owner) => this.createChat(name, users, owner),
|
|
101
|
+
updateChatInfo: (id, options) => this.updateChatInfo(id, options),
|
|
102
|
+
addChatMembers: (id, users) => this.addChatMembers(id, users),
|
|
103
|
+
removeChatMembers: (id, users) => this.removeChatMembers(id, users),
|
|
104
|
+
getChatMembers: (id) => this.getChatMembers(id),
|
|
105
|
+
dissolveChat: (id) => this.dissolveChat(id),
|
|
106
|
+
setChatManagers: (id, users) => this.setChatManagers(id, users),
|
|
107
|
+
removeChatManagers: (id, users) => this.removeChatManagers(id, users),
|
|
108
|
+
});
|
|
66
109
|
readonly #logger!: ReturnType<typeof getAdapterLogger>;
|
|
67
110
|
|
|
68
111
|
readonly #options: LarkEndpointOptions;
|
|
@@ -99,9 +142,9 @@ export class LarkEndpoint implements EndpointInstance {
|
|
|
99
142
|
#refreshPromise: Promise<string> | null = null;
|
|
100
143
|
#open = false;
|
|
101
144
|
#started = false;
|
|
102
|
-
#unregisterAgent?: () => void;
|
|
103
145
|
|
|
104
146
|
constructor(options: LarkEndpointOptions) {
|
|
147
|
+
super();
|
|
105
148
|
this.#logger = getAdapterLogger('lark', options.config.id);
|
|
106
149
|
this.#options = options;
|
|
107
150
|
this.#fetch = options.fetch ?? globalThis.fetch;
|
|
@@ -130,7 +173,6 @@ export class LarkEndpoint implements EndpointInstance {
|
|
|
130
173
|
}));
|
|
131
174
|
}
|
|
132
175
|
await this.#refreshAccessToken();
|
|
133
|
-
this.#unregisterAgent = registerLarkAgentEndpoint(this.#options.config.id, this);
|
|
134
176
|
this.#routeReleases.push(...registerLarkWebhookRoutes(this.#options.http, this));
|
|
135
177
|
this.#logger.debug(formatCompact({
|
|
136
178
|
endpoint: this.#options.config.id,
|
|
@@ -155,8 +197,6 @@ export class LarkEndpoint implements EndpointInstance {
|
|
|
155
197
|
async stop(): Promise<void> {
|
|
156
198
|
this.#open = false;
|
|
157
199
|
for (const release of this.#routeReleases.splice(0)) release();
|
|
158
|
-
this.#unregisterAgent?.();
|
|
159
|
-
this.#unregisterAgent = undefined;
|
|
160
200
|
this.#started = false;
|
|
161
201
|
this.#logger.debug(formatCompact({ op: 'disconnect' }));
|
|
162
202
|
}
|
|
@@ -242,7 +282,7 @@ export class LarkEndpoint implements EndpointInstance {
|
|
|
242
282
|
admit(msg: LarkMessage): void {
|
|
243
283
|
if (!this.#open) return;
|
|
244
284
|
const conversation = larkInboundConversation(String(this.#options.id), msg);
|
|
245
|
-
void this
|
|
285
|
+
void this.emit('message.receive', {
|
|
246
286
|
conversation,
|
|
247
287
|
message: { conversation, id: generateMessageId(msg) },
|
|
248
288
|
content: formatInboundContent(msg),
|
|
@@ -261,6 +301,17 @@ export class LarkEndpoint implements EndpointInstance {
|
|
|
261
301
|
});
|
|
262
302
|
}
|
|
263
303
|
|
|
304
|
+
admitPlatform(name: string, event: unknown): void {
|
|
305
|
+
if (!this.#open) return;
|
|
306
|
+
void this.emitPlatform(name, event).catch((error) => {
|
|
307
|
+
this.#logger.warn(formatCompact({
|
|
308
|
+
op: 'lark_platform_event_failed',
|
|
309
|
+
event: name,
|
|
310
|
+
error: error instanceof Error ? error.message : String(error),
|
|
311
|
+
}));
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
264
315
|
async getUserInfo(
|
|
265
316
|
userId: string,
|
|
266
317
|
userIdType: 'open_id' | 'user_id' | 'union_id' = 'open_id',
|
package/src/index.ts
CHANGED
|
@@ -20,13 +20,7 @@ export {
|
|
|
20
20
|
type ResolvedLarkConfig,
|
|
21
21
|
} from './protocol.js';
|
|
22
22
|
|
|
23
|
-
export {
|
|
24
|
-
getLarkAgentDeps,
|
|
25
|
-
registerLarkAgentEndpoint,
|
|
26
|
-
setLarkAgentDeps,
|
|
27
|
-
type LarkAgentDeps,
|
|
28
|
-
type LarkAgentEndpoint,
|
|
29
|
-
} from './lark-agent-deps.js';
|
|
23
|
+
export { larkClient, type LarkClientEventMap } from './client.js';
|
|
30
24
|
|
|
31
25
|
export {
|
|
32
26
|
checkLarkPlatformPermit,
|
|
@@ -36,7 +30,9 @@ export {
|
|
|
36
30
|
} from './platform-permit.js';
|
|
37
31
|
|
|
38
32
|
export {
|
|
33
|
+
LarkClient,
|
|
39
34
|
LarkEndpoint,
|
|
35
|
+
type LarkClientApi,
|
|
40
36
|
type LarkEndpointOptions,
|
|
41
37
|
type LarkFetch,
|
|
42
38
|
} from './endpoint.js';
|
package/src/protocol.ts
CHANGED
|
@@ -182,7 +182,7 @@ export function generateMessageId(msg: LarkMessage): string {
|
|
|
182
182
|
return msg.message_id || `${msg.create_time ?? Date.now()}`;
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
/** Build inbound text for
|
|
185
|
+
/** Build inbound text for OutboundMessageService.receive. */
|
|
186
186
|
export function formatInboundContent(msg: LarkMessage): string {
|
|
187
187
|
if (!msg.content || !msg.message_type) return '';
|
|
188
188
|
try {
|
package/src/webhook.ts
CHANGED
|
@@ -19,6 +19,7 @@ const logger = getLogger('lark');
|
|
|
19
19
|
export interface LarkWebhookHandler {
|
|
20
20
|
readonly config: ResolvedLarkConfig;
|
|
21
21
|
readonly isOpen: boolean;
|
|
22
|
+
admitPlatform(name: string, event: unknown): void;
|
|
22
23
|
admit(msg: LarkMessage): void;
|
|
23
24
|
}
|
|
24
25
|
|
|
@@ -78,6 +79,13 @@ export async function handleLarkWebhookRequest(
|
|
|
78
79
|
return;
|
|
79
80
|
}
|
|
80
81
|
|
|
82
|
+
if (handler.isOpen) {
|
|
83
|
+
const eventName = event.type === 'event_callback'
|
|
84
|
+
? String(event.event?.type ?? event.type)
|
|
85
|
+
: String(event.type ?? 'event');
|
|
86
|
+
handler.admitPlatform(eventName, event);
|
|
87
|
+
}
|
|
88
|
+
|
|
81
89
|
if (event.type === 'url_verification') {
|
|
82
90
|
response.writeHead(200, { 'Content-Type': 'application/json' });
|
|
83
91
|
response.end(JSON.stringify({ challenge: event.challenge }));
|
package/lib/lark-agent-deps.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent tool deps for lark (user / chat / managers / upload).
|
|
3
|
-
* Endpoints register themselves on start; tools look up by endpoint id.
|
|
4
|
-
*/
|
|
5
|
-
export interface LarkAgentEndpoint {
|
|
6
|
-
getUserInfo(userId: string, userIdType?: 'open_id' | 'user_id' | 'union_id'): Promise<unknown>;
|
|
7
|
-
getChatInfo(chatId: string): Promise<unknown>;
|
|
8
|
-
uploadFile(filePath: string, fileType?: 'image' | 'file' | 'video' | 'audio'): Promise<string | null>;
|
|
9
|
-
createChat(name: string, userIds: string[], ownerId?: string): Promise<string | null>;
|
|
10
|
-
updateChatInfo(chatId: string, options: {
|
|
11
|
-
name?: string;
|
|
12
|
-
description?: string;
|
|
13
|
-
}): Promise<boolean>;
|
|
14
|
-
addChatMembers(chatId: string, userIds: string[]): Promise<boolean>;
|
|
15
|
-
removeChatMembers(chatId: string, userIds: string[]): Promise<boolean>;
|
|
16
|
-
getChatMembers(chatId: string): Promise<unknown[]>;
|
|
17
|
-
dissolveChat(chatId: string): Promise<boolean>;
|
|
18
|
-
setChatManagers(chatId: string, userIds: string[]): Promise<boolean>;
|
|
19
|
-
removeChatManagers(chatId: string, userIds: string[]): Promise<boolean>;
|
|
20
|
-
}
|
|
21
|
-
export interface LarkAgentDeps {
|
|
22
|
-
getEndpoint: (endpointKey: string) => LarkAgentEndpoint;
|
|
23
|
-
}
|
|
24
|
-
export declare function registerLarkAgentEndpoint(endpointKey: string, endpoint: LarkAgentEndpoint): () => void;
|
|
25
|
-
/** Optional override used by tests / transitional callers. Pass `null` to clear. */
|
|
26
|
-
export declare function setLarkAgentDeps(deps: LarkAgentDeps | null): void;
|
|
27
|
-
export declare function getLarkAgentDeps(): LarkAgentDeps;
|
package/lib/lark-agent-deps.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent tool deps for lark (user / chat / managers / upload).
|
|
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 registerLarkAgentEndpoint(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 setLarkAgentDeps(deps) {
|
|
17
|
-
override = deps;
|
|
18
|
-
}
|
|
19
|
-
export function getLarkAgentDeps() {
|
|
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/lark-agent-deps.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent tool deps for lark (user / chat / managers / upload).
|
|
3
|
-
* Endpoints register themselves on start; tools look up by endpoint id.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export interface LarkAgentEndpoint {
|
|
7
|
-
getUserInfo(
|
|
8
|
-
userId: string,
|
|
9
|
-
userIdType?: 'open_id' | 'user_id' | 'union_id',
|
|
10
|
-
): Promise<unknown>;
|
|
11
|
-
getChatInfo(chatId: string): Promise<unknown>;
|
|
12
|
-
uploadFile(
|
|
13
|
-
filePath: string,
|
|
14
|
-
fileType?: 'image' | 'file' | 'video' | 'audio',
|
|
15
|
-
): Promise<string | null>;
|
|
16
|
-
createChat(name: string, userIds: string[], ownerId?: string): Promise<string | null>;
|
|
17
|
-
updateChatInfo(
|
|
18
|
-
chatId: string,
|
|
19
|
-
options: { name?: string; description?: string },
|
|
20
|
-
): Promise<boolean>;
|
|
21
|
-
addChatMembers(chatId: string, userIds: string[]): Promise<boolean>;
|
|
22
|
-
removeChatMembers(chatId: string, userIds: string[]): Promise<boolean>;
|
|
23
|
-
getChatMembers(chatId: string): Promise<unknown[]>;
|
|
24
|
-
dissolveChat(chatId: string): Promise<boolean>;
|
|
25
|
-
setChatManagers(chatId: string, userIds: string[]): Promise<boolean>;
|
|
26
|
-
removeChatManagers(chatId: string, userIds: string[]): Promise<boolean>;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface LarkAgentDeps {
|
|
30
|
-
getEndpoint: (endpointKey: string) => LarkAgentEndpoint;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const endpoints = new Map<string, LarkAgentEndpoint>();
|
|
34
|
-
let override: LarkAgentDeps | null = null;
|
|
35
|
-
|
|
36
|
-
export function registerLarkAgentEndpoint(
|
|
37
|
-
endpointKey: string,
|
|
38
|
-
endpoint: LarkAgentEndpoint,
|
|
39
|
-
): () => void {
|
|
40
|
-
endpoints.set(endpointKey, endpoint);
|
|
41
|
-
return () => {
|
|
42
|
-
if (endpoints.get(endpointKey) === endpoint) {
|
|
43
|
-
endpoints.delete(endpointKey);
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** Optional override used by tests / transitional callers. Pass `null` to clear. */
|
|
49
|
-
export function setLarkAgentDeps(deps: LarkAgentDeps | null): void {
|
|
50
|
-
override = deps;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function getLarkAgentDeps(): LarkAgentDeps {
|
|
54
|
-
if (override) return override;
|
|
55
|
-
return {
|
|
56
|
-
getEndpoint(endpointKey) {
|
|
57
|
-
const endpoint = endpoints.get(endpointKey);
|
|
58
|
-
if (!endpoint) throw new Error(`Endpoint ${endpointKey} 不存在`);
|
|
59
|
-
return endpoint;
|
|
60
|
-
},
|
|
61
|
-
};
|
|
62
|
-
}
|