@zhin.js/adapter-onebot12 5.0.1 → 5.0.4
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 +55 -0
- package/README.md +3 -3
- package/adapters/onebot12.js +2 -2
- package/adapters/onebot12.ts +2 -2
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/protocol.d.ts +13 -12
- package/lib/protocol.js +41 -43
- package/lib/webhook.d.ts +2 -5
- package/lib/webhook.js +18 -17
- package/lib/ws-endpoint.d.ts +2 -5
- package/lib/ws-endpoint.js +28 -26
- package/lib/wss-endpoint.d.ts +2 -5
- package/lib/wss-endpoint.js +25 -24
- package/package.json +13 -12
- package/schema.json +41 -5
- package/src/index.ts +1 -3
- package/src/protocol.ts +43 -51
- package/src/webhook.ts +19 -18
- package/src/ws-endpoint.ts +30 -27
- package/src/wss-endpoint.ts +27 -26
- /package/commands/endpoint/add/{[name:string].js → [id].js} +0 -0
- /package/commands/endpoint/add/{[name:string].ts → [id].ts} +0 -0
- /package/commands/endpoint/remove/{[name:string].js → [id].js} +0 -0
- /package/commands/endpoint/remove/{[name:string].ts → [id].ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,60 @@
|
|
|
1
1
|
# @zhin.js/adapter-onebot12
|
|
2
2
|
|
|
3
|
+
## 5.0.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [0de46a8]
|
|
8
|
+
- Updated dependencies [c106ecc]
|
|
9
|
+
- Updated dependencies [ca92e03]
|
|
10
|
+
- Updated dependencies [b0f37ae]
|
|
11
|
+
- Updated dependencies [ba08a2f]
|
|
12
|
+
- Updated dependencies [daffd4c]
|
|
13
|
+
- Updated dependencies [36c7400]
|
|
14
|
+
- Updated dependencies [162fa34]
|
|
15
|
+
- Updated dependencies [e40b048]
|
|
16
|
+
- Updated dependencies [f1708c3]
|
|
17
|
+
- Updated dependencies [e53444f]
|
|
18
|
+
- Updated dependencies [92b0dd7]
|
|
19
|
+
- Updated dependencies [a7df753]
|
|
20
|
+
- @zhin.js/host-http@1.0.8
|
|
21
|
+
- @zhin.js/im-contract@1.0.3
|
|
22
|
+
- @zhin.js/adapter@1.1.7
|
|
23
|
+
- @zhin.js/plugin-runtime@1.1.5
|
|
24
|
+
- @zhin.js/command@1.0.9
|
|
25
|
+
- @zhin.js/core@1.5.4
|
|
26
|
+
- zhin.js@6.0.4
|
|
27
|
+
|
|
28
|
+
## 5.0.3
|
|
29
|
+
|
|
30
|
+
### Patch Changes
|
|
31
|
+
|
|
32
|
+
- f8c7a54: fix: im
|
|
33
|
+
- Updated dependencies [f8c7a54]
|
|
34
|
+
- @zhin.js/logger@1.0.76
|
|
35
|
+
- @zhin.js/host-http@1.0.7
|
|
36
|
+
- @zhin.js/adapter@1.1.6
|
|
37
|
+
- @zhin.js/command@1.0.8
|
|
38
|
+
- @zhin.js/core@1.5.3
|
|
39
|
+
- @zhin.js/im-contract@1.0.2
|
|
40
|
+
- @zhin.js/plugin-runtime@1.1.4
|
|
41
|
+
- zhin.js@6.0.3
|
|
42
|
+
|
|
43
|
+
## 5.0.2
|
|
44
|
+
|
|
45
|
+
### Patch Changes
|
|
46
|
+
|
|
47
|
+
- Updated dependencies [afc0e66]
|
|
48
|
+
- Updated dependencies [2e41ad5]
|
|
49
|
+
- Updated dependencies [9f57124]
|
|
50
|
+
- @zhin.js/core@1.5.2
|
|
51
|
+
- @zhin.js/adapter@1.1.5
|
|
52
|
+
- @zhin.js/im-contract@1.0.1
|
|
53
|
+
- @zhin.js/plugin-runtime@1.1.3
|
|
54
|
+
- @zhin.js/command@1.0.7
|
|
55
|
+
- @zhin.js/host-http@1.0.6
|
|
56
|
+
- zhin.js@6.0.2
|
|
57
|
+
|
|
3
58
|
## 5.0.1
|
|
4
59
|
|
|
5
60
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Zhin.js [OneBot 12](https://12.onebot.dev/) 适配器(Plugin Runtime)。默
|
|
|
8
8
|
- 约定式 `defineAdapter` / `definePlugin`(无需 `usePlugin`)
|
|
9
9
|
- **正向 WebSocket**(`connection: ws`):应用连 OneBot 实现的 WS 服务器
|
|
10
10
|
- `access_token` 鉴权(Bearer + query)
|
|
11
|
-
- 入站经 `messageGatewayToken`;出站 `send({
|
|
11
|
+
- 入站经 `messageGatewayToken`;出站 `send({ conversation, payload })`
|
|
12
12
|
|
|
13
13
|
## 安装
|
|
14
14
|
|
|
@@ -23,8 +23,8 @@ pnpm add @zhin.js/adapter-onebot12
|
|
|
23
23
|
- `@zhin.js/plugin-runtime` — `plugin.ts`(`definePlugin`)
|
|
24
24
|
- 配置经插件 `schema.json` 落到 `plugins.<instanceKey>`
|
|
25
25
|
|
|
26
|
-
入站:`gateway.receive({
|
|
27
|
-
出站:`send({
|
|
26
|
+
入站:`gateway.receive({ conversation: ConversationRef, message: { conversation, id }, content, sender, metadata })`
|
|
27
|
+
出站:`send({ conversation, payload })` → WS `send_message`(payload 已由 gateway/core 渲染;无 segment-mapper)
|
|
28
28
|
|
|
29
29
|
## 最小配置
|
|
30
30
|
|
package/adapters/onebot12.js
CHANGED
|
@@ -25,8 +25,8 @@ export default defineAdapter({
|
|
|
25
25
|
const config = resolveOneBot12Config(context.config);
|
|
26
26
|
const gateway = context.use(messageGatewayToken);
|
|
27
27
|
// 注册到插件运行时状态(onebot12.endpoint list 的"运行中"数据源)
|
|
28
|
-
context.use(onebot12RuntimeStateToken).endpoints.set(config.
|
|
29
|
-
|
|
28
|
+
context.use(onebot12RuntimeStateToken).endpoints.set(config.id, {
|
|
29
|
+
id: config.id,
|
|
30
30
|
mode: config.connection,
|
|
31
31
|
});
|
|
32
32
|
if (config.connection === 'webhook') {
|
package/adapters/onebot12.ts
CHANGED
|
@@ -33,8 +33,8 @@ export default defineAdapter<OneBot12AdapterConfig>({
|
|
|
33
33
|
const config = resolveOneBot12Config(context.config);
|
|
34
34
|
const gateway = context.use(messageGatewayToken);
|
|
35
35
|
// 注册到插件运行时状态(onebot12.endpoint list 的"运行中"数据源)
|
|
36
|
-
context.use(onebot12RuntimeStateToken).endpoints.set(config.
|
|
37
|
-
|
|
36
|
+
context.use(onebot12RuntimeStateToken).endpoints.set(config.id, {
|
|
37
|
+
id: config.id,
|
|
38
38
|
mode: config.connection,
|
|
39
39
|
});
|
|
40
40
|
if (config.connection === 'webhook') {
|
package/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { buildSendMessageParams, buildWsConnectOptions, callOneBot12Action, formatInboundContent,
|
|
1
|
+
export { buildSendMessageParams, buildWsConnectOptions, callOneBot12Action, formatInboundContent, formatOutboundSegments, getChannelId, isBotMentioned, isMessageEvent, mediaRefToOneBot12Fields, mediaRefToOneBot12UploadParams, onebot12InboundConversation, resolveOneBot12Config, senderNickname, senderUserId, uploadOneBot12MediaSegments, type OneBot12ActionRequest, type OneBot12ActionResponse, type OneBot12AdapterConfig, type OneBot12CallAction, type OneBot12ConfigBase, type OneBot12EndpointConfig, type OneBot12Event, type OneBot12HttpOptions, type OneBot12Segment, type OneBot12Self, type OneBot12WebhookConfig, type OneBot12WireSegment, type OneBot12WsConfig, type OneBot12WssConfig, type ResolvedOneBot12Config, } from './protocol.js';
|
|
2
2
|
export { OneBot12WebhookEndpoint, type OneBot12WebhookEndpointOptions, } from './webhook.js';
|
|
3
3
|
export { OneBot12WsEndpoint, type OneBot12WsEndpointOptions, } from './ws-endpoint.js';
|
|
4
4
|
export { OneBot12WssEndpoint, type OneBot12WssEndpointOptions, } from './wss-endpoint.js';
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { buildSendMessageParams, buildWsConnectOptions, callOneBot12Action, formatInboundContent,
|
|
1
|
+
export { buildSendMessageParams, buildWsConnectOptions, callOneBot12Action, formatInboundContent, formatOutboundSegments, getChannelId, isBotMentioned, isMessageEvent, mediaRefToOneBot12Fields, mediaRefToOneBot12UploadParams, onebot12InboundConversation, resolveOneBot12Config, senderNickname, senderUserId, uploadOneBot12MediaSegments, } from './protocol.js';
|
|
2
2
|
export { OneBot12WebhookEndpoint, } from './webhook.js';
|
|
3
3
|
export { OneBot12WsEndpoint, } from './ws-endpoint.js';
|
|
4
4
|
export { OneBot12WssEndpoint, } from './wss-endpoint.js';
|
package/lib/protocol.d.ts
CHANGED
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
* Spec: https://12.onebot.dev/
|
|
5
5
|
*/
|
|
6
6
|
import { type MediaRef } from '@zhin.js/core';
|
|
7
|
+
import type { ConversationRef } from '@zhin.js/im-contract';
|
|
7
8
|
/** Transitional legacy endpoint row (`endpoints[]` with `context: onebot12`). */
|
|
8
9
|
export interface OneBot12LegacyEndpointRow {
|
|
9
10
|
readonly context?: string;
|
|
10
11
|
readonly connection?: 'ws' | 'webhook' | 'wss';
|
|
11
|
-
readonly
|
|
12
|
+
readonly id?: string;
|
|
12
13
|
readonly access_token?: string;
|
|
13
14
|
readonly url?: string;
|
|
14
15
|
readonly path?: string;
|
|
@@ -19,7 +20,7 @@ export interface OneBot12LegacyEndpointRow {
|
|
|
19
20
|
/** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
|
|
20
21
|
export interface OneBot12AdapterConfig {
|
|
21
22
|
readonly connection?: 'ws' | 'webhook' | 'wss';
|
|
22
|
-
readonly
|
|
23
|
+
readonly id?: string;
|
|
23
24
|
readonly access_token?: string;
|
|
24
25
|
readonly url?: string;
|
|
25
26
|
readonly path?: string;
|
|
@@ -31,7 +32,7 @@ export interface OneBot12AdapterConfig {
|
|
|
31
32
|
}
|
|
32
33
|
export interface OneBot12ConfigBase {
|
|
33
34
|
readonly context: 'onebot12';
|
|
34
|
-
readonly
|
|
35
|
+
readonly id: string;
|
|
35
36
|
readonly access_token?: string;
|
|
36
37
|
}
|
|
37
38
|
/** 正向 WebSocket:应用连 OneBot 实现的 WS 服务器 */
|
|
@@ -100,11 +101,6 @@ export interface OneBot12WireSegment {
|
|
|
100
101
|
readonly type: string;
|
|
101
102
|
readonly data?: Record<string, unknown>;
|
|
102
103
|
}
|
|
103
|
-
export interface ParsedSendTarget {
|
|
104
|
-
readonly detail_type: 'private' | 'group' | 'channel';
|
|
105
|
-
readonly id: string;
|
|
106
|
-
readonly guild_id?: string;
|
|
107
|
-
}
|
|
108
104
|
export declare function resolveOneBot12Config(config?: OneBot12AdapterConfig): ResolvedOneBot12Config;
|
|
109
105
|
/** 判断是否为消息事件(type=message) */
|
|
110
106
|
export declare function isMessageEvent(ev: OneBot12Event): ev is OneBot12Event & {
|
|
@@ -114,10 +110,11 @@ export declare function isMessageEvent(ev: OneBot12Event): ev is OneBot12Event &
|
|
|
114
110
|
/** 从事件得到场景 id:私聊 user_id,群 group_id,频道 channel_id 或 guild_id:channel_id */
|
|
115
111
|
export declare function getChannelId(ev: OneBot12Event): string;
|
|
116
112
|
/**
|
|
117
|
-
*
|
|
113
|
+
* 入站归一化 → ConversationRef:`detail_type` 直映射 kind;channel 的 guild 容器
|
|
114
|
+
* 进 `parent`(kind 'channel');私聊临时会话(private 事件携带 group_id)映射为
|
|
115
|
+
* group 容器内的 private 会话。
|
|
118
116
|
*/
|
|
119
|
-
export declare function
|
|
120
|
-
export declare function parseSendTarget(target: string): ParsedSendTarget;
|
|
117
|
+
export declare function onebot12InboundConversation(endpointKey: string, ev: OneBot12Event): ConversationRef;
|
|
121
118
|
/** Build inbound text for MessageGateway.receive */
|
|
122
119
|
export declare function formatInboundContent(ev: OneBot12Event): string;
|
|
123
120
|
/**
|
|
@@ -158,7 +155,11 @@ export declare function mediaRefToOneBot12UploadParams(segmentType: string, data
|
|
|
158
155
|
* 上传失败保留原段(降级扩展字段透传)并回调 onUploadFailed。
|
|
159
156
|
*/
|
|
160
157
|
export declare function uploadOneBot12MediaSegments(payload: unknown, callAction: OneBot12CallAction, onUploadFailed?: (error: unknown) => void): Promise<unknown>;
|
|
161
|
-
|
|
158
|
+
/**
|
|
159
|
+
* 结构化会话 → OB12 `send_message` 动作参数:kind 直映射 detail_type;
|
|
160
|
+
* channel 的 guild 容器取自 `conversation.parent`(kind 'channel')。
|
|
161
|
+
*/
|
|
162
|
+
export declare function buildSendMessageParams(conversation: ConversationRef, message: OneBot12Segment[]): Record<string, unknown>;
|
|
162
163
|
/**
|
|
163
164
|
* 向 OneBot 实现发送动作请求(HTTP POST),返回动作响应。
|
|
164
165
|
* 供 webhook 出站与纯协议测试使用;WS 路径走 WebSocket echo 请求。
|
package/lib/protocol.js
CHANGED
|
@@ -11,8 +11,8 @@ export function resolveOneBot12Config(config = {}) {
|
|
|
11
11
|
const connection = config.connection
|
|
12
12
|
?? entry?.connection
|
|
13
13
|
?? 'ws';
|
|
14
|
-
const
|
|
15
|
-
|| (typeof entry?.
|
|
14
|
+
const id = (typeof config.id === 'string' && config.id)
|
|
15
|
+
|| (typeof entry?.id === 'string' && entry.id)
|
|
16
16
|
|| process.env.ONEBOT12_BOT_NAME
|
|
17
17
|
|| 'onebot12-bot';
|
|
18
18
|
const access_token = config.access_token ?? entry?.access_token;
|
|
@@ -24,7 +24,7 @@ export function resolveOneBot12Config(config = {}) {
|
|
|
24
24
|
return {
|
|
25
25
|
context: 'onebot12',
|
|
26
26
|
connection: 'ws',
|
|
27
|
-
|
|
27
|
+
id,
|
|
28
28
|
access_token,
|
|
29
29
|
url,
|
|
30
30
|
reconnect_interval: config.reconnect_interval ?? entry?.reconnect_interval ?? 5000,
|
|
@@ -39,7 +39,7 @@ export function resolveOneBot12Config(config = {}) {
|
|
|
39
39
|
return {
|
|
40
40
|
context: 'onebot12',
|
|
41
41
|
connection: 'webhook',
|
|
42
|
-
|
|
42
|
+
id,
|
|
43
43
|
access_token,
|
|
44
44
|
path,
|
|
45
45
|
api_url: config.api_url ?? entry?.api_url,
|
|
@@ -53,7 +53,7 @@ export function resolveOneBot12Config(config = {}) {
|
|
|
53
53
|
return {
|
|
54
54
|
context: 'onebot12',
|
|
55
55
|
connection: 'wss',
|
|
56
|
-
|
|
56
|
+
id,
|
|
57
57
|
access_token,
|
|
58
58
|
path,
|
|
59
59
|
heartbeat_interval: config.heartbeat_interval ?? entry?.heartbeat_interval ?? 30_000,
|
|
@@ -77,36 +77,31 @@ export function getChannelId(ev) {
|
|
|
77
77
|
return ev.user_id ?? ev.group_id ?? '';
|
|
78
78
|
}
|
|
79
79
|
/**
|
|
80
|
-
*
|
|
80
|
+
* 入站归一化 → ConversationRef:`detail_type` 直映射 kind;channel 的 guild 容器
|
|
81
|
+
* 进 `parent`(kind 'channel');私聊临时会话(private 事件携带 group_id)映射为
|
|
82
|
+
* group 容器内的 private 会话。
|
|
81
83
|
*/
|
|
82
|
-
export function
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
: '
|
|
86
|
-
return `${detail}:${getChannelId(ev)}`;
|
|
87
|
-
}
|
|
88
|
-
export function parseSendTarget(target) {
|
|
89
|
-
const sep = target.indexOf(':');
|
|
90
|
-
if (sep <= 0) {
|
|
91
|
-
return { detail_type: 'private', id: target };
|
|
92
|
-
}
|
|
93
|
-
const head = target.slice(0, sep);
|
|
94
|
-
const rest = target.slice(sep + 1);
|
|
95
|
-
if (head === 'private' || head === 'group') {
|
|
96
|
-
return { detail_type: head, id: rest };
|
|
97
|
-
}
|
|
98
|
-
if (head === 'channel') {
|
|
99
|
-
const guildSep = rest.indexOf(':');
|
|
100
|
-
if (guildSep > 0) {
|
|
101
|
-
return {
|
|
102
|
-
detail_type: 'channel',
|
|
103
|
-
guild_id: rest.slice(0, guildSep),
|
|
104
|
-
id: rest.slice(guildSep + 1),
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
return { detail_type: 'channel', id: rest };
|
|
84
|
+
export function onebot12InboundConversation(endpointKey, ev) {
|
|
85
|
+
const endpoint = { id: endpointKey, adapter: endpointKey.split('\0')[0] ?? endpointKey };
|
|
86
|
+
if (ev.detail_type === 'group' && ev.group_id) {
|
|
87
|
+
return { endpoint, kind: 'group', id: ev.group_id };
|
|
108
88
|
}
|
|
109
|
-
|
|
89
|
+
if (ev.detail_type === 'channel' && ev.channel_id) {
|
|
90
|
+
return {
|
|
91
|
+
endpoint,
|
|
92
|
+
kind: 'channel',
|
|
93
|
+
id: ev.channel_id,
|
|
94
|
+
...(ev.guild_id ? { parent: { kind: 'channel', id: ev.guild_id } } : {}),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
endpoint,
|
|
99
|
+
kind: 'private',
|
|
100
|
+
id: ev.user_id ?? ev.group_id ?? '',
|
|
101
|
+
...(ev.detail_type === 'private' && ev.group_id
|
|
102
|
+
? { parent: { kind: 'group', id: ev.group_id } }
|
|
103
|
+
: {}),
|
|
104
|
+
};
|
|
110
105
|
}
|
|
111
106
|
/** Build inbound text for MessageGateway.receive */
|
|
112
107
|
export function formatInboundContent(ev) {
|
|
@@ -347,22 +342,25 @@ export async function uploadOneBot12MediaSegments(payload, callAction, onUploadF
|
|
|
347
342
|
}
|
|
348
343
|
return uploadOneMediaSegment(payload, callAction, onUploadFailed);
|
|
349
344
|
}
|
|
350
|
-
|
|
351
|
-
|
|
345
|
+
/**
|
|
346
|
+
* 结构化会话 → OB12 `send_message` 动作参数:kind 直映射 detail_type;
|
|
347
|
+
* channel 的 guild 容器取自 `conversation.parent`(kind 'channel')。
|
|
348
|
+
*/
|
|
349
|
+
export function buildSendMessageParams(conversation, message) {
|
|
352
350
|
const params = {
|
|
353
351
|
message,
|
|
354
|
-
detail_type:
|
|
352
|
+
detail_type: conversation.kind,
|
|
355
353
|
};
|
|
356
|
-
if (
|
|
357
|
-
params.user_id =
|
|
354
|
+
if (conversation.kind === 'private') {
|
|
355
|
+
params.user_id = conversation.id;
|
|
358
356
|
}
|
|
359
|
-
else if (
|
|
360
|
-
params.group_id =
|
|
357
|
+
else if (conversation.kind === 'group') {
|
|
358
|
+
params.group_id = conversation.id;
|
|
361
359
|
}
|
|
362
360
|
else {
|
|
363
|
-
params.channel_id =
|
|
364
|
-
if (
|
|
365
|
-
params.guild_id =
|
|
361
|
+
params.channel_id = conversation.id;
|
|
362
|
+
if (conversation.parent?.kind === 'channel')
|
|
363
|
+
params.guild_id = conversation.parent.id;
|
|
366
364
|
}
|
|
367
365
|
return params;
|
|
368
366
|
}
|
package/lib/webhook.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EndpointInstance, EndpointManagement } from '@zhin.js/adapter';
|
|
1
|
+
import type { EndpointInstance, EndpointManagement, EndpointSendRequest } from '@zhin.js/adapter';
|
|
2
2
|
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
3
3
|
import type { HttpHost } from '@zhin.js/host-http';
|
|
4
4
|
import type { CapabilityId } from '@zhin.js/plugin-runtime';
|
|
@@ -18,10 +18,7 @@ export declare class OneBot12WebhookEndpoint implements EndpointInstance {
|
|
|
18
18
|
open(): void;
|
|
19
19
|
close(): void;
|
|
20
20
|
stop(): Promise<void>;
|
|
21
|
-
send({
|
|
22
|
-
readonly target: string;
|
|
23
|
-
readonly payload: unknown;
|
|
24
|
-
}): Promise<string>;
|
|
21
|
+
send({ conversation, payload }: EndpointSendRequest): Promise<string>;
|
|
25
22
|
/** Public API for management surface / callers;webhook 模式走 api_url。 */
|
|
26
23
|
callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
27
24
|
admit(ev: OneBot12Event): void;
|
package/lib/webhook.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
2
2
|
import { createOneBot12EndpointManagement } from './endpoint-management.js';
|
|
3
|
-
import { buildSendMessageParams, callOneBot12Action, formatInboundContent,
|
|
3
|
+
import { buildSendMessageParams, callOneBot12Action, formatInboundContent, formatOutboundSegments, isBotMentioned, isMessageEvent, onebot12InboundConversation, senderNickname, senderUserId, uploadOneBot12MediaSegments, } from './protocol.js';
|
|
4
4
|
import { verifyOneBotAccessToken } from './wss-auth.js';
|
|
5
5
|
const logger = getLogger('onebot12');
|
|
6
6
|
export class OneBot12WebhookEndpoint {
|
|
@@ -21,7 +21,7 @@ export class OneBot12WebhookEndpoint {
|
|
|
21
21
|
if (!this.#options.config.access_token) {
|
|
22
22
|
// webhook 模式未配 access_token 时任何 POST 都会被放行(verifyOneBotAccessToken 直接 return true)
|
|
23
23
|
logger.warn(formatCompact({
|
|
24
|
-
endpoint: this.#options.config.
|
|
24
|
+
endpoint: this.#options.config.id,
|
|
25
25
|
mode: 'webhook',
|
|
26
26
|
ok: false,
|
|
27
27
|
error: 'missing access_token',
|
|
@@ -30,7 +30,7 @@ export class OneBot12WebhookEndpoint {
|
|
|
30
30
|
this.#setupRoutes();
|
|
31
31
|
logger.info(formatCompact({
|
|
32
32
|
op: 'listen',
|
|
33
|
-
endpoint: this.#options.config.
|
|
33
|
+
endpoint: this.#options.config.id,
|
|
34
34
|
mode: 'webhook',
|
|
35
35
|
path: this.#options.config.path,
|
|
36
36
|
}));
|
|
@@ -46,24 +46,25 @@ export class OneBot12WebhookEndpoint {
|
|
|
46
46
|
for (const release of this.#routeReleases.splice(0))
|
|
47
47
|
release();
|
|
48
48
|
this.#started = false;
|
|
49
|
-
logger.debug(formatCompact({ op: 'disconnect', endpoint: this.#options.config.
|
|
49
|
+
logger.debug(formatCompact({ op: 'disconnect', endpoint: this.#options.config.id }));
|
|
50
50
|
}
|
|
51
|
-
async send({
|
|
51
|
+
async send({ conversation, payload }) {
|
|
52
52
|
const materialized = await uploadOneBot12MediaSegments(payload, (action, params) => this.callApi(action, params), (error) => {
|
|
53
53
|
logger.warn(formatCompact({
|
|
54
54
|
op: 'onebot12_upload_failed',
|
|
55
|
-
endpoint: this.#options.config.
|
|
55
|
+
endpoint: this.#options.config.id,
|
|
56
56
|
error: error instanceof Error ? error.message : String(error),
|
|
57
57
|
}));
|
|
58
58
|
});
|
|
59
59
|
const message = formatOutboundSegments(materialized);
|
|
60
|
-
const params = buildSendMessageParams(
|
|
60
|
+
const params = buildSendMessageParams(conversation, message);
|
|
61
61
|
const data = await this.callApi('send_message', params);
|
|
62
62
|
const messageId = data?.message_id ?? '';
|
|
63
63
|
logger.debug(formatCompact({
|
|
64
64
|
op: 'onebot12_send',
|
|
65
|
-
endpoint: this.#options.config.
|
|
66
|
-
|
|
65
|
+
endpoint: this.#options.config.id,
|
|
66
|
+
kind: conversation.kind,
|
|
67
|
+
conversationId: conversation.id,
|
|
67
68
|
messageId,
|
|
68
69
|
}));
|
|
69
70
|
return messageId;
|
|
@@ -80,31 +81,31 @@ export class OneBot12WebhookEndpoint {
|
|
|
80
81
|
admit(ev) {
|
|
81
82
|
if (!this.#open || !isMessageEvent(ev))
|
|
82
83
|
return;
|
|
83
|
-
const
|
|
84
|
+
const conversation = onebot12InboundConversation(String(this.#options.id), ev);
|
|
84
85
|
const content = formatInboundContent(ev);
|
|
85
86
|
const nickname = senderNickname(ev);
|
|
86
87
|
const mentioned = isBotMentioned(ev);
|
|
87
88
|
void this.#options.gateway.receive({
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
conversation,
|
|
90
|
+
message: { conversation, id: ev.message_id },
|
|
90
91
|
content,
|
|
91
|
-
sender: senderUserId(ev),
|
|
92
|
-
|
|
92
|
+
sender: { id: senderUserId(ev), ...(nickname ? { name: nickname } : {}) },
|
|
93
|
+
endpointId: this.#options.config.id,
|
|
94
|
+
...(mentioned ? { mentioned: true } : {}),
|
|
93
95
|
metadata: Object.freeze({
|
|
94
96
|
detail_type: ev.detail_type,
|
|
95
97
|
user_id: ev.user_id,
|
|
96
98
|
group_id: ev.group_id,
|
|
97
99
|
channel_id: ev.channel_id,
|
|
98
100
|
guild_id: ev.guild_id,
|
|
99
|
-
endpoint: this.#options.config.name,
|
|
100
101
|
time: ev.time,
|
|
101
102
|
...(nickname ? { nickname } : {}),
|
|
102
|
-
...(mentioned ? { mentioned: true } : {}),
|
|
103
103
|
}),
|
|
104
104
|
}).catch((err) => {
|
|
105
105
|
logger.warn(formatCompact({
|
|
106
106
|
op: 'onebot12_gateway_receive_failed',
|
|
107
|
-
|
|
107
|
+
kind: conversation.kind,
|
|
108
|
+
conversationId: conversation.id,
|
|
108
109
|
error: err instanceof Error ? err.message : String(err),
|
|
109
110
|
}));
|
|
110
111
|
});
|
package/lib/ws-endpoint.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type EndpointInstance, type EndpointManagement } from '@zhin.js/adapter';
|
|
1
|
+
import { type EndpointInstance, type EndpointManagement, type EndpointSendRequest } from '@zhin.js/adapter';
|
|
2
2
|
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
3
3
|
import type { CapabilityId } from '@zhin.js/plugin-runtime';
|
|
4
4
|
import { type OneBot12Event, type OneBot12WsConfig } from './protocol.js';
|
|
@@ -17,10 +17,7 @@ export declare class OneBot12WsEndpoint implements EndpointInstance {
|
|
|
17
17
|
open(): void;
|
|
18
18
|
close(): void;
|
|
19
19
|
stop(): Promise<void>;
|
|
20
|
-
send({
|
|
21
|
-
readonly target: string;
|
|
22
|
-
readonly payload: unknown;
|
|
23
|
-
}): Promise<string>;
|
|
20
|
+
send({ conversation, payload }: EndpointSendRequest): Promise<string>;
|
|
24
21
|
recallMessage(messageId: string): Promise<void>;
|
|
25
22
|
/** Public API for management surface / callers. */
|
|
26
23
|
callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
|
package/lib/ws-endpoint.js
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
import WebSocket from 'ws';
|
|
5
5
|
import { clearTimeout } from 'node:timers';
|
|
6
6
|
import { createEndpointLifecycle, } from '@zhin.js/adapter';
|
|
7
|
-
import { formatCompact,
|
|
7
|
+
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
8
8
|
import { createOneBot12EndpointManagement } from './endpoint-management.js';
|
|
9
|
-
import { buildSendMessageParams, buildWsConnectOptions, formatInboundContent,
|
|
9
|
+
import { buildSendMessageParams, buildWsConnectOptions, formatInboundContent, formatOutboundSegments, isBotMentioned, isMessageEvent, onebot12InboundConversation, senderNickname, senderUserId, uploadOneBot12MediaSegments, } from './protocol.js';
|
|
10
10
|
import { WS_OPEN, } from './ws-types.js';
|
|
11
|
-
const logger = getLogger('onebot12');
|
|
12
11
|
export class OneBot12WsEndpoint {
|
|
12
|
+
#logger;
|
|
13
13
|
#options;
|
|
14
14
|
management = createOneBot12EndpointManagement(this);
|
|
15
15
|
#lifecycle;
|
|
@@ -18,10 +18,11 @@ export class OneBot12WsEndpoint {
|
|
|
18
18
|
#pending = new Map();
|
|
19
19
|
#open = false;
|
|
20
20
|
constructor(options) {
|
|
21
|
+
this.#logger = getAdapterLogger('onebot12', options.config.id);
|
|
21
22
|
this.#options = options;
|
|
22
23
|
const { config } = options;
|
|
23
24
|
this.#lifecycle = createEndpointLifecycle({
|
|
24
|
-
name: config.
|
|
25
|
+
name: config.id,
|
|
25
26
|
reconnect: {
|
|
26
27
|
initialIntervalMs: config.reconnect_interval,
|
|
27
28
|
// 固定间隔(multiplier 1、无抖动),对齐旧 reconnect_interval 语义
|
|
@@ -69,22 +70,23 @@ export class OneBot12WsEndpoint {
|
|
|
69
70
|
this.#pending.clear();
|
|
70
71
|
this.#ws = undefined;
|
|
71
72
|
}
|
|
72
|
-
async send({
|
|
73
|
+
async send({ conversation, payload }) {
|
|
73
74
|
const materialized = await uploadOneBot12MediaSegments(payload, (action, params) => this.callApi(action, params), (error) => {
|
|
74
|
-
logger.warn(formatCompact({
|
|
75
|
+
this.#logger.warn(formatCompact({
|
|
75
76
|
op: 'onebot12_upload_failed',
|
|
76
|
-
endpoint: this.#options.config.
|
|
77
|
+
endpoint: this.#options.config.id,
|
|
77
78
|
error: error instanceof Error ? error.message : String(error),
|
|
78
79
|
}));
|
|
79
80
|
});
|
|
80
81
|
const message = formatOutboundSegments(materialized);
|
|
81
|
-
const params = buildSendMessageParams(
|
|
82
|
+
const params = buildSendMessageParams(conversation, message);
|
|
82
83
|
const data = await this.#callAction('send_message', params);
|
|
83
84
|
const messageId = data?.message_id ?? '';
|
|
84
|
-
logger.debug(formatCompact({
|
|
85
|
+
this.#logger.debug(formatCompact({
|
|
85
86
|
op: 'onebot12_send',
|
|
86
|
-
endpoint: this.#options.config.
|
|
87
|
-
|
|
87
|
+
endpoint: this.#options.config.id,
|
|
88
|
+
kind: conversation.kind,
|
|
89
|
+
conversationId: conversation.id,
|
|
88
90
|
messageId,
|
|
89
91
|
}));
|
|
90
92
|
return messageId;
|
|
@@ -102,31 +104,31 @@ export class OneBot12WsEndpoint {
|
|
|
102
104
|
admit(ev) {
|
|
103
105
|
if (!this.#open || !isMessageEvent(ev))
|
|
104
106
|
return;
|
|
105
|
-
const
|
|
107
|
+
const conversation = onebot12InboundConversation(String(this.#options.id), ev);
|
|
106
108
|
const content = formatInboundContent(ev);
|
|
107
109
|
const nickname = senderNickname(ev);
|
|
108
110
|
const mentioned = isBotMentioned(ev);
|
|
109
111
|
void this.#options.gateway.receive({
|
|
110
|
-
|
|
111
|
-
|
|
112
|
+
conversation,
|
|
113
|
+
message: { conversation, id: ev.message_id },
|
|
112
114
|
content,
|
|
113
|
-
sender: senderUserId(ev),
|
|
114
|
-
|
|
115
|
+
sender: { id: senderUserId(ev), name: senderNickname(ev) },
|
|
116
|
+
endpointId: this.#options.config.id,
|
|
117
|
+
...(mentioned ? { mentioned: true } : {}),
|
|
115
118
|
metadata: Object.freeze({
|
|
116
119
|
detail_type: ev.detail_type,
|
|
117
120
|
user_id: ev.user_id,
|
|
118
121
|
group_id: ev.group_id,
|
|
119
122
|
channel_id: ev.channel_id,
|
|
120
123
|
guild_id: ev.guild_id,
|
|
121
|
-
endpoint: this.#options.config.name,
|
|
122
124
|
time: ev.time,
|
|
123
125
|
...(nickname ? { nickname } : {}),
|
|
124
|
-
...(mentioned ? { mentioned: true } : {}),
|
|
125
126
|
}),
|
|
126
127
|
}).catch((err) => {
|
|
127
|
-
logger.warn(formatCompact({
|
|
128
|
+
this.#logger.warn(formatCompact({
|
|
128
129
|
op: 'onebot12_gateway_receive_failed',
|
|
129
|
-
|
|
130
|
+
kind: conversation.kind,
|
|
131
|
+
conversationId: conversation.id,
|
|
130
132
|
error: err instanceof Error ? err.message : String(err),
|
|
131
133
|
}));
|
|
132
134
|
});
|
|
@@ -151,8 +153,8 @@ export class OneBot12WsEndpoint {
|
|
|
151
153
|
if (settled)
|
|
152
154
|
return;
|
|
153
155
|
settled = true;
|
|
154
|
-
logger.debug(formatCompact({
|
|
155
|
-
endpoint: this.#options.config.
|
|
156
|
+
this.#logger.debug(formatCompact({
|
|
157
|
+
endpoint: this.#options.config.id,
|
|
156
158
|
mode: 'ws',
|
|
157
159
|
url: safeUrl,
|
|
158
160
|
}));
|
|
@@ -181,9 +183,9 @@ export class OneBot12WsEndpoint {
|
|
|
181
183
|
});
|
|
182
184
|
ws.on('error', (err) => {
|
|
183
185
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
184
|
-
logger.warn(formatCompact({
|
|
186
|
+
this.#logger.warn(formatCompact({
|
|
185
187
|
op: 'ws_error',
|
|
186
|
-
endpoint: this.#options.config.
|
|
188
|
+
endpoint: this.#options.config.id,
|
|
187
189
|
ok: false,
|
|
188
190
|
error: error.message,
|
|
189
191
|
}));
|
|
@@ -220,9 +222,9 @@ export class OneBot12WsEndpoint {
|
|
|
220
222
|
this.admit(msg);
|
|
221
223
|
}
|
|
222
224
|
catch (error) {
|
|
223
|
-
logger.warn(formatCompact({
|
|
225
|
+
this.#logger.warn(formatCompact({
|
|
224
226
|
op: 'onebot12_parse_failed',
|
|
225
|
-
endpoint: this.#options.config.
|
|
227
|
+
endpoint: this.#options.config.id,
|
|
226
228
|
error: error instanceof Error ? error.message : String(error),
|
|
227
229
|
}));
|
|
228
230
|
}
|
package/lib/wss-endpoint.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EndpointInstance, EndpointManagement } from '@zhin.js/adapter';
|
|
1
|
+
import type { EndpointInstance, EndpointManagement, EndpointSendRequest } from '@zhin.js/adapter';
|
|
2
2
|
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
3
3
|
import type { HttpHost } from '@zhin.js/host-http';
|
|
4
4
|
import type { CapabilityId } from '@zhin.js/plugin-runtime';
|
|
@@ -17,10 +17,7 @@ export declare class OneBot12WssEndpoint implements EndpointInstance {
|
|
|
17
17
|
open(): void;
|
|
18
18
|
close(): void;
|
|
19
19
|
stop(): Promise<void>;
|
|
20
|
-
send({
|
|
21
|
-
readonly target: string;
|
|
22
|
-
readonly payload: unknown;
|
|
23
|
-
}): Promise<string>;
|
|
20
|
+
send({ conversation, payload }: EndpointSendRequest): Promise<string>;
|
|
24
21
|
recallMessage(messageId: string): Promise<void>;
|
|
25
22
|
/** Public API for management surface / callers. */
|
|
26
23
|
callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
|