@zhin.js/adapter-onebot11 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 +32 -0
- package/README.md +23 -4
- package/adapters/onebot11.js +0 -7
- package/adapters/onebot11.ts +0 -7
- package/agent/tools/set_title.ts +11 -8
- package/lib/client.d.ts +20 -0
- package/lib/client.js +30 -0
- package/lib/index.d.ts +4 -1
- package/lib/index.js +2 -1
- package/lib/onebot11-endpoint-commands.d.ts +1 -1
- package/lib/protocol.d.ts +3 -2
- package/lib/protocol.js +1 -1
- package/lib/side-event-dispatch.d.ts +2 -2
- package/lib/side-event-dispatch.js +3 -3
- package/lib/ws-endpoint.d.ts +5 -13
- package/lib/ws-endpoint.js +30 -41
- package/lib/ws-transport.d.ts +3 -3
- package/lib/ws-transport.js +2 -5
- package/lib/ws-types.d.ts +2 -1
- package/lib/wss-endpoint.d.ts +8 -11
- package/lib/wss-endpoint.js +63 -66
- package/package.json +17 -14
- package/src/client.ts +78 -0
- package/src/index.ts +15 -6
- package/src/protocol.ts +3 -2
- package/src/side-event-dispatch.ts +4 -4
- package/src/ws-endpoint.ts +38 -52
- package/src/ws-transport.ts +4 -5
- package/src/ws-types.ts +2 -1
- package/src/wss-endpoint.ts +70 -77
- package/lib/onebot11-agent-deps.d.ts +0 -15
- package/lib/onebot11-agent-deps.js +0 -30
- package/src/onebot11-agent-deps.ts +0 -49
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# @zhin.js/adapter-onebot11
|
|
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
|
+
- 4e8117c: Expose the published imhelper protocol Clients from every Endpoint, preserve native action responses, and route host-owned HTTP, WebSocket, and raw ingress through the Client APIs. Add the shared `ClientEndpoint` deep base so concrete transports inherit one open-gated Client event bridge, and move reverse WebSocket lifecycle and heartbeat cleanup onto the common lifecycle state machine.
|
|
16
|
+
- 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.
|
|
17
|
+
- 2ca9a52: Upgrade the protocol Clients to imhelper 1.0.7, keep receiver ownership exclusively in Endpoint through manual mode, expose structured protocol errors, and support canonical non-message Client events.
|
|
18
|
+
- Updated dependencies [e9c6a73]
|
|
19
|
+
- Updated dependencies [4e8117c]
|
|
20
|
+
- Updated dependencies [902fa35]
|
|
21
|
+
- Updated dependencies [54bfd6b]
|
|
22
|
+
- Updated dependencies [12025ee]
|
|
23
|
+
- Updated dependencies [09b14d6]
|
|
24
|
+
- Updated dependencies [1fc78bc]
|
|
25
|
+
- @zhin.js/agent@1.1.16
|
|
26
|
+
- @zhin.js/adapter@1.2.1
|
|
27
|
+
- @zhin.js/core@1.5.14
|
|
28
|
+
- @zhin.js/host-http@1.0.13
|
|
29
|
+
- @zhin.js/command@1.0.16
|
|
30
|
+
- @zhin.js/logger@1.0.77
|
|
31
|
+
- zhin.js@6.0.14
|
|
32
|
+
- @zhin.js/feature-kit@1.0.13
|
|
33
|
+
- @zhin.js/permission@1.0.4
|
|
34
|
+
|
|
3
35
|
## 7.0.0
|
|
4
36
|
|
|
5
37
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Zhin.js [OneBot 11](https://github.com/botuniverse/onebot-11) 适配器(Plugin
|
|
|
8
8
|
- 约定式 `defineAdapter` / `definePlugin`(无需 `usePlugin`)
|
|
9
9
|
- **正向 WebSocket**(`connection: ws`):应用连 OneBot 实现的 WS 服务器
|
|
10
10
|
- `access_token` 鉴权(Bearer + query)
|
|
11
|
-
- 入站经 `
|
|
11
|
+
- 入站经 `Endpoint.emit(...)`;出站 `send({ conversation, payload })`
|
|
12
12
|
|
|
13
13
|
## 安装
|
|
14
14
|
|
|
@@ -19,13 +19,23 @@ pnpm add @zhin.js/adapter-onebot11
|
|
|
19
19
|
## Plugin Runtime
|
|
20
20
|
|
|
21
21
|
- `@zhin.js/adapter` — 约定式 `adapters/onebot11.ts`(`defineAdapter`)
|
|
22
|
-
- `@zhin.js/core` — `
|
|
22
|
+
- `@zhin.js/core` — `Endpoint.emit(...)` 入站、`outboundMessageToken` 出站
|
|
23
23
|
- `zhin.js` — `plugin.ts`(`definePlugin`)
|
|
24
24
|
- 配置经插件 `schema.json` 落到 `plugins.<instanceKey>`
|
|
25
25
|
|
|
26
|
+
每个 Endpoint 的 `$client` 是 `@imhelper/onebot-v11` 的 `OneBotV11Client`。业务代码直接调用
|
|
27
|
+
`$client.call(action, params)` 和 Client 的公开平台能力;双工 WS 的 `echo` 响应由 Endpoint
|
|
28
|
+
先行分流,只有事件帧进入 Client 的 `ingest()` 和公开事件流。
|
|
29
|
+
|
|
26
30
|
入站:`gateway.receive({ conversation, message, content, sender, metadata })`(`conversation.kind` 为 `private`/`group`,`id` 为 uid/gid)
|
|
27
31
|
出站:`send({ conversation, payload })` → WS `send_private_msg` / `send_group_msg`(payload 已由 gateway/core 渲染;无 segment-mapper)
|
|
28
32
|
|
|
33
|
+
## 前置条件
|
|
34
|
+
|
|
35
|
+
1. 启动兼容 OneBot 11 的实现,并选定正向或反向 WebSocket。
|
|
36
|
+
2. 正向 WS 需 Zhin 可达实现端;反向 WS 需实现端可达 Zhin HTTP Host。
|
|
37
|
+
3. 两端配置相同的 `access_token`,生产环境不要开放无鉴权连接。
|
|
38
|
+
|
|
29
39
|
## 最小配置
|
|
30
40
|
|
|
31
41
|
```yaml
|
|
@@ -70,8 +80,8 @@ plugins:
|
|
|
70
80
|
|
|
71
81
|
## 迁移说明(Plugin Runtime)
|
|
72
82
|
|
|
73
|
-
- **notice / request / meta 侧事件**:经 `
|
|
74
|
-
- **群管工具暂未迁移**:旧 Adapter 经 `createSceneManagementTools` 注册踢人 / 禁言 / 群名片等成套 agent 工具;迁移后仅保留 `onebot11_set_title`,其余群管能力可通过
|
|
83
|
+
- **notice / request / meta 侧事件**:经 the unified `Endpoint.emit(...)` ingress 归一后分发到 `handlers`;消息仍走 `outboundMessageToken`。
|
|
84
|
+
- **群管工具暂未迁移**:旧 Adapter 经 `createSceneManagementTools` 注册踢人 / 禁言 / 群名片等成套 agent 工具;迁移后仅保留 `onebot11_set_title`,其余群管能力可通过 `$client.call()`(如 `set_group_kick`、`set_group_ban`)作为逃生舱调用。
|
|
75
85
|
- **平台权限门禁**:`plugin.ts` setup 已注册 `registerDefaultScenePlatformPermitChecker('onebot11')`,`scene_admin` / `scene_owner` 依据入站 metadata 中的 sender `role`(owner / admin)判定。
|
|
76
86
|
|
|
77
87
|
## 文档链接
|
|
@@ -79,6 +89,15 @@ plugins:
|
|
|
79
89
|
- [OneBot 11 标准](https://github.com/botuniverse/onebot-11)
|
|
80
90
|
- [适配器概览](https://zhin.js.org/essentials/adapters)
|
|
81
91
|
|
|
92
|
+
## 故障排查
|
|
93
|
+
|
|
94
|
+
| 现象 | 排查 |
|
|
95
|
+
| --- | --- |
|
|
96
|
+
| WS 无法建立 | 核对连接方向、URL、端口与实现端 WS 服务 |
|
|
97
|
+
| 401 或握手关闭 | 确认 Header/query token 与实现端一致 |
|
|
98
|
+
| 能收不能发 | 检查发送动作支持与账号风控状态 |
|
|
99
|
+
| notice/request 不出现 | 确认实现端上报对应 post type,并查看 Endpoint 请求/通知 |
|
|
100
|
+
|
|
82
101
|
## 许可证
|
|
83
102
|
|
|
84
103
|
MIT License
|
package/adapters/onebot11.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* Convention entry: discover `adapters/onebot11.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 { OneBot11WsEndpoint } from "../lib/ws-endpoint.js";
|
|
9
8
|
import { OneBot11WssEndpoint } from "../lib/wss-endpoint.js";
|
|
@@ -21,8 +20,6 @@ export default defineAdapter({
|
|
|
21
20
|
},
|
|
22
21
|
create(context) {
|
|
23
22
|
const config = resolveOneBot11Config(context.config);
|
|
24
|
-
const gateway = context.use(messageGatewayToken);
|
|
25
|
-
const sideEvents = context.use(sideEventGatewayToken);
|
|
26
23
|
// 注册到插件运行时状态(onebot11.endpoint list 的"运行中"数据源)
|
|
27
24
|
context.use(onebot11RuntimeStateToken).endpoints.set(config.id, {
|
|
28
25
|
id: config.id,
|
|
@@ -31,16 +28,12 @@ export default defineAdapter({
|
|
|
31
28
|
if (config.connection === 'wss') {
|
|
32
29
|
return new OneBot11WssEndpoint({
|
|
33
30
|
id: context.id,
|
|
34
|
-
gateway,
|
|
35
|
-
sideEvents,
|
|
36
31
|
http: context.use(httpHostToken),
|
|
37
32
|
config,
|
|
38
33
|
});
|
|
39
34
|
}
|
|
40
35
|
return new OneBot11WsEndpoint({
|
|
41
36
|
id: context.id,
|
|
42
|
-
gateway,
|
|
43
|
-
sideEvents,
|
|
44
37
|
config,
|
|
45
38
|
});
|
|
46
39
|
},
|
package/adapters/onebot11.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Convention entry: discover `adapters/onebot11.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 { OneBot11WsEndpoint } from '../src/ws-endpoint.js';
|
|
8
7
|
import { OneBot11WssEndpoint } from '../src/wss-endpoint.js';
|
|
@@ -34,8 +33,6 @@ export default defineAdapter<OneBot11AdapterConfig>({
|
|
|
34
33
|
},
|
|
35
34
|
create(context) {
|
|
36
35
|
const config = resolveOneBot11Config(context.config);
|
|
37
|
-
const gateway = context.use(messageGatewayToken);
|
|
38
|
-
const sideEvents = context.use(sideEventGatewayToken);
|
|
39
36
|
// 注册到插件运行时状态(onebot11.endpoint list 的"运行中"数据源)
|
|
40
37
|
context.use(onebot11RuntimeStateToken).endpoints.set(config.id, {
|
|
41
38
|
id: config.id,
|
|
@@ -44,16 +41,12 @@ export default defineAdapter<OneBot11AdapterConfig>({
|
|
|
44
41
|
if (config.connection === 'wss') {
|
|
45
42
|
return new OneBot11WssEndpoint({
|
|
46
43
|
id: context.id,
|
|
47
|
-
gateway,
|
|
48
|
-
sideEvents,
|
|
49
44
|
http: context.use(httpHostToken),
|
|
50
45
|
config,
|
|
51
46
|
});
|
|
52
47
|
}
|
|
53
48
|
return new OneBot11WsEndpoint({
|
|
54
49
|
id: context.id,
|
|
55
|
-
gateway,
|
|
56
|
-
sideEvents,
|
|
57
50
|
config,
|
|
58
51
|
});
|
|
59
52
|
},
|
package/agent/tools/set_title.ts
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
import { defineAgentTool } from '@zhin.js/agent/tools';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
|
|
4
|
-
export default defineAgentTool<{ endpoint_id: string; group_id: number; user_id: number; title: string }>({
|
|
3
|
+
export default defineAgentTool<{ group_id: number; user_id: number; title: string }>({
|
|
5
4
|
description: '设置 QQ 群成员的专属头衔。只有群主才能设置。',
|
|
6
5
|
inputSchema: z.object({
|
|
7
|
-
endpoint_id: z.string().describe('Endpoint 名称'),
|
|
8
6
|
group_id: z.number().describe('目标群号'),
|
|
9
7
|
user_id: z.number().describe('目标成员 QQ号'),
|
|
10
8
|
title: z.string().describe('头衔文字'),
|
|
11
9
|
}),
|
|
12
|
-
|
|
10
|
+
adapter: 'onebot11',
|
|
13
11
|
tags: ['onebot11'],
|
|
14
12
|
permissions: ['platform(onebot11,scene_owner)'],
|
|
15
|
-
async execute({
|
|
16
|
-
const
|
|
17
|
-
const
|
|
13
|
+
async execute({ group_id, user_id, title }: { group_id: number; user_id: number; title: string }, context) {
|
|
14
|
+
const client = context.$client;
|
|
15
|
+
const response = await client.call('set_group_special_title', {
|
|
16
|
+
group_id,
|
|
17
|
+
user_id,
|
|
18
|
+
special_title: title,
|
|
19
|
+
duration: -1,
|
|
20
|
+
});
|
|
21
|
+
const success = response.status === 'ok';
|
|
18
22
|
return { success, message: success ? `已将 ${user_id} 的头衔设为 "${title}"` : '设置失败' };
|
|
19
23
|
},
|
|
20
24
|
});
|
|
21
|
-
|
package/lib/client.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { OneBotV11Client, type OneBotV11Event as ImHelperOneBot11Event, type OneBotV11Response } from '@imhelper/onebot-v11';
|
|
2
|
+
import { type EventMap, type ImHelperEventMap } from 'imhelper';
|
|
3
|
+
import { type ClientEventPayloads } from 'zhin.js/adapter';
|
|
4
|
+
import type { ResolvedOneBot11Config } from './protocol.js';
|
|
5
|
+
export { OneBotV11Client as Onebot11Client } from '@imhelper/onebot-v11';
|
|
6
|
+
export type Onebot11ApiCall = (action: string, params?: Record<string, unknown>) => Promise<OneBotV11Response>;
|
|
7
|
+
type Onebot11ClientEvents = ImHelperEventMap<number, ImHelperOneBot11Event, EventMap<number>>;
|
|
8
|
+
export type Onebot11ClientEventMap = ClientEventPayloads<Onebot11ClientEvents>;
|
|
9
|
+
export declare function createOnebot11EndpointClient(config: ResolvedOneBot11Config, request: Onebot11ApiCall): OneBotV11Client;
|
|
10
|
+
export declare function callOnebot11Client<T = unknown>(client: OneBotV11Client, action: string, params?: Record<string, unknown>): Promise<T | undefined>;
|
|
11
|
+
export declare function forwardOnebot11ClientEvents(client: OneBotV11Client, receive: (name: string, payload: unknown) => void): () => void;
|
|
12
|
+
declare module '@zhin.js/feature-kit' {
|
|
13
|
+
interface AdapterClientRegistry {
|
|
14
|
+
readonly onebot11: {
|
|
15
|
+
readonly client: OneBotV11Client;
|
|
16
|
+
readonly events: Onebot11ClientEventMap;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export declare const onebot11Client: import("@zhin.js/adapter").EndpointClientToken<OneBotV11Client, ClientEventPayloads<Onebot11ClientEvents>>;
|
package/lib/client.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { OneBotV11Client, } from '@imhelper/onebot-v11';
|
|
2
|
+
import { EventFactory } from 'imhelper';
|
|
3
|
+
import { defineEndpointClient, forwardEndpointClientEvents, } from 'zhin.js/adapter';
|
|
4
|
+
export { OneBotV11Client as Onebot11Client } from '@imhelper/onebot-v11';
|
|
5
|
+
export function createOnebot11EndpointClient(config, request) {
|
|
6
|
+
return new OneBotV11Client({
|
|
7
|
+
baseUrl: config.connection === 'ws'
|
|
8
|
+
? config.url.replace(/^ws(s?):/, 'http$1:')
|
|
9
|
+
: 'http://localhost',
|
|
10
|
+
selfId: config.id,
|
|
11
|
+
accessToken: config.access_token,
|
|
12
|
+
receiveMode: 'manual',
|
|
13
|
+
call: request,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export async function callOnebot11Client(client, action, params) {
|
|
17
|
+
const response = await client.call(action, params);
|
|
18
|
+
if (response.status !== 'ok') {
|
|
19
|
+
throw new Error(`OneBot 11 API ${action}: retcode=${response.retcode}${response.message ? ` ${response.message}` : ''}`);
|
|
20
|
+
}
|
|
21
|
+
return response.data;
|
|
22
|
+
}
|
|
23
|
+
const onebot11ClientEventNames = Object.freeze([
|
|
24
|
+
...EventFactory.getSupportedEventTypes(),
|
|
25
|
+
'event',
|
|
26
|
+
]);
|
|
27
|
+
export function forwardOnebot11ClientEvents(client, receive) {
|
|
28
|
+
return forwardEndpointClientEvents(client, onebot11ClientEventNames, receive);
|
|
29
|
+
}
|
|
30
|
+
export const onebot11Client = defineEndpointClient('onebot11');
|
package/lib/index.d.ts
CHANGED
|
@@ -4,4 +4,7 @@ export { OneBot11WssEndpoint, type OneBot11WssEndpointOptions, } from './wss-end
|
|
|
4
4
|
export type { OneBot11WsSocket, OneBot11WsCreateOptions } from './ws-types.js';
|
|
5
5
|
export { callOneBot11WsAction, decodeWsPayload, handleOneBot11WsMessage, rejectAllPending, startOneBot11Heartbeat, } from './ws-transport.js';
|
|
6
6
|
export { verifyOneBotAccessToken } from './wss-auth.js';
|
|
7
|
-
export {
|
|
7
|
+
export { Onebot11Client, onebot11Client, type Onebot11ClientEventMap, } from './client.js';
|
|
8
|
+
export type { OneBotV11ActionUrlResolver, OneBotV11AdapterConfig as ImHelperOneBotV11AdapterConfig, OneBotV11Call, OneBotV11ClientConfig, OneBotV11Event as ImHelperOneBotV11Event, OneBotV11Response, } from '@imhelper/onebot-v11';
|
|
9
|
+
export { ProtocolError } from '@imhelper/onebot-v11';
|
|
10
|
+
export type { ProtocolErrorKind, ProtocolErrorOptions } from 'imhelper';
|
package/lib/index.js
CHANGED
|
@@ -3,4 +3,5 @@ export { OneBot11WsEndpoint, } from './ws-endpoint.js';
|
|
|
3
3
|
export { OneBot11WssEndpoint, } from './wss-endpoint.js';
|
|
4
4
|
export { callOneBot11WsAction, decodeWsPayload, handleOneBot11WsMessage, rejectAllPending, startOneBot11Heartbeat, } from './ws-transport.js';
|
|
5
5
|
export { verifyOneBotAccessToken } from './wss-auth.js';
|
|
6
|
-
export {
|
|
6
|
+
export { Onebot11Client, onebot11Client, } from './client.js';
|
|
7
|
+
export { ProtocolError } from '@imhelper/onebot-v11';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const onebot11EndpointCommands: import("@zhin.js/adapter").EndpointCommands<Readonly<import("@zhin.js/command").CommandDefinition<unknown, unknown, import("@zhin.js/command").CommandMessage>>>;
|
|
1
|
+
export declare const onebot11EndpointCommands: 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
|
@@ -82,9 +82,10 @@ export interface OneBot11ActionRequest {
|
|
|
82
82
|
echo?: string;
|
|
83
83
|
}
|
|
84
84
|
export interface OneBot11ActionResponse {
|
|
85
|
-
status:
|
|
85
|
+
status: 'ok' | 'failed';
|
|
86
86
|
retcode: number;
|
|
87
87
|
data?: unknown;
|
|
88
|
+
message?: string;
|
|
88
89
|
echo?: string;
|
|
89
90
|
}
|
|
90
91
|
export interface OneBot11WireSegment {
|
|
@@ -104,7 +105,7 @@ export declare function getChannelId(ev: OneBot11Event): string;
|
|
|
104
105
|
* OneBot 11 无 guild/temp 容器概念,不填 parent。
|
|
105
106
|
*/
|
|
106
107
|
export declare function onebot11InboundConversation(endpointKey: string, ev: OneBot11Event): ConversationRef;
|
|
107
|
-
/** Build inbound text for
|
|
108
|
+
/** Build inbound text for OutboundMessageService.receive */
|
|
108
109
|
export declare function formatInboundContent(ev: OneBot11Event): string;
|
|
109
110
|
export declare function senderDisplayName(ev: OneBot11Event): string;
|
|
110
111
|
/**
|
package/lib/protocol.js
CHANGED
|
@@ -83,7 +83,7 @@ export function onebot11InboundConversation(endpointKey, ev) {
|
|
|
83
83
|
id: getChannelId(ev),
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
|
-
/** Build inbound text for
|
|
86
|
+
/** Build inbound text for OutboundMessageService.receive */
|
|
87
87
|
export function formatInboundContent(ev) {
|
|
88
88
|
if (Array.isArray(ev.message)) {
|
|
89
89
|
return ev.message
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { EndpointEventEmitter } from 'zhin.js/adapter';
|
|
2
2
|
import { type getAdapterLogger } from '@zhin.js/logger';
|
|
3
3
|
import type { OneBot11Event } from './protocol.js';
|
|
4
4
|
export interface OneBot11SideEventCaller {
|
|
5
5
|
callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
6
6
|
}
|
|
7
|
-
export declare function receiveOneBot11SideEvent(
|
|
7
|
+
export declare function receiveOneBot11SideEvent(emit: EndpointEventEmitter, endpointKey: string, caller: OneBot11SideEventCaller, raw: OneBot11Event, logger: ReturnType<typeof getAdapterLogger>): void;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { receiveOneBotLikeSideEvent } from '@zhin.js/core';
|
|
2
2
|
import { formatCompact } from '@zhin.js/logger';
|
|
3
|
-
export function receiveOneBot11SideEvent(
|
|
4
|
-
if (!
|
|
3
|
+
export function receiveOneBot11SideEvent(emit, endpointKey, caller, raw, logger) {
|
|
4
|
+
if (!emit)
|
|
5
5
|
return;
|
|
6
6
|
const record = raw;
|
|
7
7
|
const postType = String(record.post_type ?? '');
|
|
8
8
|
const requestType = String(record.request_type ?? '');
|
|
9
9
|
const isRequest = postType === 'request' || postType.startsWith('request.');
|
|
10
10
|
const isFriend = requestType === 'friend' || postType.includes('friend');
|
|
11
|
-
void receiveOneBotLikeSideEvent(
|
|
11
|
+
void receiveOneBotLikeSideEvent(emit, {
|
|
12
12
|
adapter: 'onebot11',
|
|
13
13
|
endpointKey,
|
|
14
14
|
platform: 'onebot',
|
package/lib/ws-endpoint.d.ts
CHANGED
|
@@ -1,30 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { MessageGateway, SideEventGateway } from '@zhin.js/core/runtime';
|
|
1
|
+
import { ClientEndpoint, type EndpointControl, type EndpointManagement, type EndpointSendRequest } from 'zhin.js/adapter';
|
|
3
2
|
import type { CapabilityId } from 'zhin.js';
|
|
4
|
-
import { type
|
|
3
|
+
import { type OneBot11WsConfig } from './protocol.js';
|
|
5
4
|
import { type OneBot11WsCreateOptions, type OneBot11WsSocket } from './ws-types.js';
|
|
5
|
+
import { type Onebot11Client } from './client.js';
|
|
6
6
|
export interface OneBot11WsEndpointOptions {
|
|
7
7
|
readonly id: CapabilityId;
|
|
8
|
-
readonly gateway: MessageGateway;
|
|
9
|
-
readonly sideEvents?: SideEventGateway;
|
|
10
8
|
readonly config: OneBot11WsConfig;
|
|
11
9
|
readonly createWebSocket?: (url: string, options: OneBot11WsCreateOptions) => OneBot11WsSocket;
|
|
12
10
|
}
|
|
13
|
-
export declare class OneBot11WsEndpoint
|
|
11
|
+
export declare class OneBot11WsEndpoint extends ClientEndpoint<Onebot11Client> {
|
|
14
12
|
#private;
|
|
13
|
+
readonly client: Onebot11Client;
|
|
15
14
|
readonly management: EndpointManagement;
|
|
16
15
|
readonly control: EndpointControl;
|
|
17
16
|
readonly content: import("@zhin.js/adapter").EndpointContentPort;
|
|
18
17
|
constructor(options: OneBot11WsEndpointOptions);
|
|
19
18
|
start(): Promise<void>;
|
|
20
|
-
open(): void;
|
|
21
|
-
close(): void;
|
|
22
19
|
stop(): Promise<void>;
|
|
23
20
|
send({ conversation, payload }: EndpointSendRequest): Promise<string>;
|
|
24
21
|
recallMessage(messageId: string): Promise<void>;
|
|
25
|
-
/** Public API for agent tools / callers. */
|
|
26
|
-
callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
27
|
-
setTitle(groupId: number, userId: number, title: string, duration?: number): Promise<boolean>;
|
|
28
|
-
/** Test / internal: admit a parsed event when the endpoint is open. */
|
|
29
|
-
admit(ev: OneBot11Event): void;
|
|
30
22
|
}
|
package/lib/ws-endpoint.js
CHANGED
|
@@ -2,29 +2,37 @@
|
|
|
2
2
|
* OneBot11 WS client endpoint — outbound connect to OneBot implementation.
|
|
3
3
|
*/
|
|
4
4
|
import WebSocket from 'ws';
|
|
5
|
-
import { createRecallEndpointControl, createEndpointLifecycle, } from 'zhin.js/adapter';
|
|
5
|
+
import { ClientEndpoint, createRecallEndpointControl, createEndpointLifecycle, } from 'zhin.js/adapter';
|
|
6
6
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
7
7
|
import { createOneBot11EndpointManagement } from './endpoint-management.js';
|
|
8
|
-
import { registerOnebot11AgentEndpoint } from './onebot11-agent-deps.js';
|
|
9
8
|
import { buildSendAction, buildWsConnectOptions, formatInboundContent, formatInboundMetadata, formatOutboundSegments, isMessageEvent, onebot11InboundConversation, senderDisplayName, senderUserId, } from './protocol.js';
|
|
10
9
|
import { receiveOneBot11SideEvent } from './side-event-dispatch.js';
|
|
11
10
|
import { createOneBot11ContentPort } from './content-port.js';
|
|
12
11
|
import { callOneBot11WsAction, handleOneBot11WsMessage, rejectAllPending, } from './ws-transport.js';
|
|
13
|
-
|
|
12
|
+
import { callOnebot11Client, createOnebot11EndpointClient, forwardOnebot11ClientEvents } from './client.js';
|
|
13
|
+
export class OneBot11WsEndpoint extends ClientEndpoint {
|
|
14
|
+
client;
|
|
14
15
|
#logger;
|
|
15
16
|
#options;
|
|
16
|
-
management
|
|
17
|
+
management;
|
|
17
18
|
control = createRecallEndpointControl((id) => this.recallMessage(id));
|
|
18
|
-
content
|
|
19
|
+
content;
|
|
19
20
|
#lifecycle;
|
|
20
21
|
#ws;
|
|
21
22
|
#requestId = { value: 0 };
|
|
22
23
|
#pending = new Map();
|
|
23
|
-
#open = false;
|
|
24
|
-
#unregisterAgent;
|
|
25
24
|
constructor(options) {
|
|
25
|
+
super();
|
|
26
26
|
this.#logger = getAdapterLogger('onebot11', options.config.id);
|
|
27
27
|
this.#options = options;
|
|
28
|
+
this.client = createOnebot11EndpointClient(options.config, (action, params) => this.#callApi(action, params));
|
|
29
|
+
const callApi = (action, params) => callOnebot11Client(this.client, action, params);
|
|
30
|
+
this.management = createOneBot11EndpointManagement({ callApi });
|
|
31
|
+
this.content = createOneBot11ContentPort(callApi);
|
|
32
|
+
this.bindClientEvents((receive) => forwardOnebot11ClientEvents(this.client, receive), (name, payload) => {
|
|
33
|
+
if (name === 'event')
|
|
34
|
+
this.#admitRaw(payload);
|
|
35
|
+
}, (_name, error) => this.#warnPlatformEvent(error));
|
|
28
36
|
const { config } = options;
|
|
29
37
|
this.#lifecycle = createEndpointLifecycle({
|
|
30
38
|
name: config.id,
|
|
@@ -41,13 +49,11 @@ export class OneBot11WsEndpoint {
|
|
|
41
49
|
async start() {
|
|
42
50
|
if (this.#lifecycle.started)
|
|
43
51
|
return;
|
|
44
|
-
// agent 注册/反注册是适配器专有依赖,留在适配器侧(见 endpoint-lifecycle 迁移指引)
|
|
45
|
-
this.#unregisterAgent = registerOnebot11AgentEndpoint(this.#options.config.id, this);
|
|
46
52
|
try {
|
|
47
53
|
await this.#lifecycle.start((handle) => this.#connect(handle));
|
|
48
54
|
}
|
|
49
55
|
catch (err) {
|
|
50
|
-
// start
|
|
56
|
+
// start 失败必须清理现场(状态复位由基座保证)
|
|
51
57
|
if (this.#ws) {
|
|
52
58
|
try {
|
|
53
59
|
this.#ws.close();
|
|
@@ -57,30 +63,20 @@ export class OneBot11WsEndpoint {
|
|
|
57
63
|
}
|
|
58
64
|
this.#ws = undefined;
|
|
59
65
|
}
|
|
60
|
-
this.#unregisterAgent?.();
|
|
61
|
-
this.#unregisterAgent = undefined;
|
|
62
66
|
throw err;
|
|
63
67
|
}
|
|
64
68
|
}
|
|
65
|
-
open() {
|
|
66
|
-
this.#open = true;
|
|
67
|
-
}
|
|
68
|
-
close() {
|
|
69
|
-
this.#open = false;
|
|
70
|
-
}
|
|
71
69
|
async stop() {
|
|
72
|
-
this
|
|
70
|
+
this.close();
|
|
73
71
|
// 基座负责:清重连/心跳定时器、强关 ws、唤醒 stop-during-connect 竞态
|
|
74
72
|
await this.#lifecycle.stop();
|
|
75
|
-
this.#unregisterAgent?.();
|
|
76
|
-
this.#unregisterAgent = undefined;
|
|
77
73
|
rejectAllPending(this.#pending);
|
|
78
74
|
this.#ws = undefined;
|
|
79
75
|
}
|
|
80
76
|
async send({ conversation, payload }) {
|
|
81
77
|
const message = formatOutboundSegments(payload);
|
|
82
78
|
const { action, params } = buildSendAction(conversation, message);
|
|
83
|
-
const data = await this.
|
|
79
|
+
const data = await callOnebot11Client(this.client, action, params);
|
|
84
80
|
const messageId = data?.message_id != null ? String(data.message_id) : '';
|
|
85
81
|
this.#logger.debug(formatCompact({
|
|
86
82
|
op: 'onebot11_send',
|
|
@@ -93,33 +89,20 @@ export class OneBot11WsEndpoint {
|
|
|
93
89
|
async recallMessage(messageId) {
|
|
94
90
|
if (!messageId)
|
|
95
91
|
return;
|
|
96
|
-
await this.
|
|
92
|
+
await callOnebot11Client(this.client, 'delete_msg', { message_id: Number(messageId) });
|
|
97
93
|
}
|
|
98
|
-
|
|
99
|
-
callApi(action, params = {}) {
|
|
94
|
+
#callApi(action, params = {}) {
|
|
100
95
|
return callOneBot11WsAction(this.#ws, this.#pending, this.#requestId, action, params);
|
|
101
96
|
}
|
|
102
|
-
|
|
103
|
-
await this.callApi('set_group_special_title', {
|
|
104
|
-
group_id: groupId,
|
|
105
|
-
user_id: userId,
|
|
106
|
-
special_title: title,
|
|
107
|
-
duration,
|
|
108
|
-
});
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
|
-
/** Test / internal: admit a parsed event when the endpoint is open. */
|
|
112
|
-
admit(ev) {
|
|
113
|
-
if (!this.#open)
|
|
114
|
-
return;
|
|
97
|
+
#admitRaw(ev) {
|
|
115
98
|
if (!isMessageEvent(ev)) {
|
|
116
|
-
receiveOneBot11SideEvent(this
|
|
99
|
+
receiveOneBot11SideEvent((name, payload) => this.emit(name, payload), this.#options.config.id, { callApi: (action, params) => callOnebot11Client(this.client, action, params) }, ev, this.#logger);
|
|
117
100
|
return;
|
|
118
101
|
}
|
|
119
102
|
const conversation = onebot11InboundConversation(String(this.#options.id), ev);
|
|
120
103
|
const content = formatInboundContent(ev);
|
|
121
104
|
const inbound = formatInboundMetadata(ev, this.#options.config.id);
|
|
122
|
-
void this
|
|
105
|
+
void this.emit('message.receive', {
|
|
123
106
|
conversation,
|
|
124
107
|
message: { conversation, id: String(ev.message_id) },
|
|
125
108
|
content,
|
|
@@ -140,6 +123,12 @@ export class OneBot11WsEndpoint {
|
|
|
140
123
|
}));
|
|
141
124
|
});
|
|
142
125
|
}
|
|
126
|
+
#warnPlatformEvent(error) {
|
|
127
|
+
this.#logger.warn(formatCompact({
|
|
128
|
+
op: 'onebot11_platform_event_failed',
|
|
129
|
+
error: error instanceof Error ? error.message : String(error),
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
143
132
|
async #connect(handle) {
|
|
144
133
|
const { url, headers, safeUrl } = buildWsConnectOptions(this.#options.config);
|
|
145
134
|
const create = this.#options.createWebSocket
|
|
@@ -179,7 +168,7 @@ export class OneBot11WsEndpoint {
|
|
|
179
168
|
handleOneBot11WsMessage(data, {
|
|
180
169
|
endpointId: this.#options.config.id,
|
|
181
170
|
pending: this.#pending,
|
|
182
|
-
|
|
171
|
+
ingest: (ev) => this.client.ingest(ev),
|
|
183
172
|
});
|
|
184
173
|
});
|
|
185
174
|
ws.on('close', (code, reason) => {
|
package/lib/ws-transport.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { type OneBot11Event } from './protocol.js';
|
|
1
|
+
import { type OneBot11ActionResponse, type OneBot11Event } from './protocol.js';
|
|
2
2
|
import { type OneBot11PendingAction, type OneBot11WsSocket } from './ws-types.js';
|
|
3
3
|
export declare function decodeWsPayload(data: unknown): string;
|
|
4
4
|
export declare function handleOneBot11WsMessage(data: unknown, options: {
|
|
5
5
|
readonly endpointId: string;
|
|
6
6
|
readonly pending: Map<string, OneBot11PendingAction>;
|
|
7
|
-
readonly
|
|
7
|
+
readonly ingest: (ev: OneBot11Event) => void;
|
|
8
8
|
}): void;
|
|
9
9
|
export declare function callOneBot11WsAction(ws: OneBot11WsSocket | undefined, pending: Map<string, OneBot11PendingAction>, requestId: {
|
|
10
10
|
value: number;
|
|
11
|
-
}, action: string, params: Record<string, unknown>): Promise<
|
|
11
|
+
}, action: string, params: Record<string, unknown>): Promise<OneBot11ActionResponse>;
|
|
12
12
|
export declare function startOneBot11Heartbeat(ws: OneBot11WsSocket | undefined, intervalMs: number, existingTimer?: NodeJS.Timeout): NodeJS.Timeout;
|
|
13
13
|
export declare function rejectAllPending(pending: Map<string, OneBot11PendingAction>, message?: string): void;
|
package/lib/ws-transport.js
CHANGED
|
@@ -21,14 +21,11 @@ export function handleOneBot11WsMessage(data, options) {
|
|
|
21
21
|
if (pending) {
|
|
22
22
|
options.pending.delete(resp.echo);
|
|
23
23
|
clearTimeout(pending.timeout);
|
|
24
|
-
|
|
25
|
-
pending.resolve(resp.data);
|
|
26
|
-
else
|
|
27
|
-
pending.reject(new Error(`OneBot11 retcode=${resp.retcode}`));
|
|
24
|
+
pending.resolve(resp);
|
|
28
25
|
}
|
|
29
26
|
return;
|
|
30
27
|
}
|
|
31
|
-
options.
|
|
28
|
+
options.ingest(msg);
|
|
32
29
|
}
|
|
33
30
|
catch (error) {
|
|
34
31
|
logger.warn(formatCompact({
|
package/lib/ws-types.d.ts
CHANGED
|
@@ -11,7 +11,8 @@ export interface OneBot11WsCreateOptions {
|
|
|
11
11
|
}
|
|
12
12
|
export declare const WS_OPEN = 1;
|
|
13
13
|
export interface OneBot11PendingAction {
|
|
14
|
-
resolve: (value:
|
|
14
|
+
resolve: (value: OneBot11ActionResponse) => void;
|
|
15
15
|
reject: (err: Error) => void;
|
|
16
16
|
timeout: NodeJS.Timeout;
|
|
17
17
|
}
|
|
18
|
+
import type { OneBot11ActionResponse } from './protocol.js';
|
package/lib/wss-endpoint.d.ts
CHANGED
|
@@ -1,28 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* OneBot11 reverse WSS endpoint — accepts inbound WebSocket from OneBot implementation.
|
|
3
|
+
*/
|
|
4
|
+
import { ClientEndpoint, type EndpointControl, type EndpointManagement, type EndpointSendRequest } from 'zhin.js/adapter';
|
|
3
5
|
import type { HttpHost } from '@zhin.js/host-http';
|
|
4
6
|
import type { CapabilityId } from 'zhin.js';
|
|
5
|
-
import { type
|
|
7
|
+
import { type OneBot11WssConfig } from './protocol.js';
|
|
8
|
+
import { type Onebot11Client } from './client.js';
|
|
6
9
|
export interface OneBot11WssEndpointOptions {
|
|
7
10
|
readonly id: CapabilityId;
|
|
8
|
-
readonly gateway: MessageGateway;
|
|
9
|
-
readonly sideEvents?: SideEventGateway;
|
|
10
11
|
readonly http: HttpHost;
|
|
11
12
|
readonly config: OneBot11WssConfig;
|
|
12
13
|
}
|
|
13
|
-
export declare class OneBot11WssEndpoint
|
|
14
|
+
export declare class OneBot11WssEndpoint extends ClientEndpoint<Onebot11Client> {
|
|
14
15
|
#private;
|
|
16
|
+
readonly client: Onebot11Client;
|
|
15
17
|
readonly management: EndpointManagement;
|
|
16
18
|
readonly control: EndpointControl;
|
|
17
19
|
readonly content: import("@zhin.js/adapter").EndpointContentPort;
|
|
18
20
|
constructor(options: OneBot11WssEndpointOptions);
|
|
19
21
|
start(): Promise<void>;
|
|
20
|
-
open(): void;
|
|
21
|
-
close(): void;
|
|
22
22
|
stop(): Promise<void>;
|
|
23
23
|
send({ conversation, payload }: EndpointSendRequest): Promise<string>;
|
|
24
24
|
recallMessage(messageId: string): Promise<void>;
|
|
25
|
-
callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
26
|
-
setTitle(groupId: number, userId: number, title: string, duration?: number): Promise<boolean>;
|
|
27
|
-
admit(ev: OneBot11Event): void;
|
|
28
25
|
}
|