@zhin.js/adapter-onebot11 6.0.3 → 6.0.5
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 +79 -0
- package/adapters/onebot11.js +2 -2
- package/adapters/onebot11.ts +2 -2
- package/lib/onebot11-agent-deps.d.ts +2 -2
- package/lib/onebot11-agent-deps.js +7 -7
- package/lib/protocol.d.ts +15 -6
- package/lib/protocol.js +21 -19
- package/lib/ws-endpoint.js +26 -17
- package/lib/ws-transport.d.ts +1 -1
- package/lib/ws-transport.js +1 -1
- package/lib/wss-endpoint.js +23 -14
- package/package.json +16 -15
- package/plugin.js +5 -4
- package/schema.json +41 -5
- package/src/onebot11-agent-deps.ts +8 -8
- package/src/protocol.ts +33 -23
- package/src/ws-endpoint.ts +27 -17
- package/src/ws-transport.ts +2 -2
- package/src/wss-endpoint.ts +24 -14
- /package/commands/endpoint/add/{[name].js → [id].js} +0 -0
- /package/commands/endpoint/add/{[name].ts → [id].ts} +0 -0
- /package/commands/endpoint/remove/{[name].js → [id].js} +0 -0
- /package/commands/endpoint/remove/{[name].ts → [id].ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,84 @@
|
|
|
1
1
|
# @zhin.js/adapter-onebot11
|
|
2
2
|
|
|
3
|
+
## 6.0.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 51015d6: refactor(adapters): migrate platform-permit to PermissionSubject
|
|
8
|
+
|
|
9
|
+
All adapter platform-permit checkers now accept PermissionSubject
|
|
10
|
+
(duck-typed from Message/CommandSession) instead of Message directly.
|
|
11
|
+
registerPlatformPermitChecker is replaced by host.registerPlatform in
|
|
12
|
+
the adapter plugin setup. activity-feedback service updated for new
|
|
13
|
+
PermissionHost integration.
|
|
14
|
+
|
|
15
|
+
- Updated dependencies [6f9c366]
|
|
16
|
+
- Updated dependencies [373a56b]
|
|
17
|
+
- Updated dependencies [0de46a8]
|
|
18
|
+
- Updated dependencies [c106ecc]
|
|
19
|
+
- Updated dependencies [ca92e03]
|
|
20
|
+
- Updated dependencies [b0f37ae]
|
|
21
|
+
- Updated dependencies [ba08a2f]
|
|
22
|
+
- Updated dependencies [b08f7fe]
|
|
23
|
+
- Updated dependencies [daffd4c]
|
|
24
|
+
- Updated dependencies [36c7400]
|
|
25
|
+
- Updated dependencies [a9fa72e]
|
|
26
|
+
- Updated dependencies [c8de3ef]
|
|
27
|
+
- Updated dependencies [60f0fc8]
|
|
28
|
+
- Updated dependencies [574c990]
|
|
29
|
+
- Updated dependencies [d096f16]
|
|
30
|
+
- Updated dependencies [3f29623]
|
|
31
|
+
- Updated dependencies [2916852]
|
|
32
|
+
- Updated dependencies [d047869]
|
|
33
|
+
- Updated dependencies [162fa34]
|
|
34
|
+
- Updated dependencies [e62561e]
|
|
35
|
+
- Updated dependencies [3eeeb46]
|
|
36
|
+
- Updated dependencies [85d0f82]
|
|
37
|
+
- Updated dependencies [61bfc1c]
|
|
38
|
+
- Updated dependencies [04bad47]
|
|
39
|
+
- Updated dependencies [e40b048]
|
|
40
|
+
- Updated dependencies [5a5b1bb]
|
|
41
|
+
- Updated dependencies [f1708c3]
|
|
42
|
+
- Updated dependencies [d254a81]
|
|
43
|
+
- Updated dependencies [7123c47]
|
|
44
|
+
- Updated dependencies [05befc1]
|
|
45
|
+
- Updated dependencies [0663b6a]
|
|
46
|
+
- Updated dependencies [f28f9b3]
|
|
47
|
+
- Updated dependencies [9f340f7]
|
|
48
|
+
- Updated dependencies [e53444f]
|
|
49
|
+
- Updated dependencies [5eedd26]
|
|
50
|
+
- Updated dependencies [92b0dd7]
|
|
51
|
+
- Updated dependencies [f919b6f]
|
|
52
|
+
- Updated dependencies [098e411]
|
|
53
|
+
- Updated dependencies [e1b7c01]
|
|
54
|
+
- Updated dependencies [9b94f87]
|
|
55
|
+
- Updated dependencies [a7df753]
|
|
56
|
+
- @zhin.js/agent@1.1.5
|
|
57
|
+
- @zhin.js/host-http@1.0.8
|
|
58
|
+
- @zhin.js/permission@1.0.1
|
|
59
|
+
- @zhin.js/im-contract@1.0.3
|
|
60
|
+
- @zhin.js/adapter@1.1.7
|
|
61
|
+
- @zhin.js/plugin-runtime@1.1.5
|
|
62
|
+
- @zhin.js/command@1.0.9
|
|
63
|
+
- @zhin.js/core@1.5.4
|
|
64
|
+
- zhin.js@6.0.4
|
|
65
|
+
|
|
66
|
+
## 6.0.4
|
|
67
|
+
|
|
68
|
+
### Patch Changes
|
|
69
|
+
|
|
70
|
+
- f8c7a54: fix: im
|
|
71
|
+
- Updated dependencies [f8c7a54]
|
|
72
|
+
- @zhin.js/logger@1.0.76
|
|
73
|
+
- @zhin.js/host-http@1.0.7
|
|
74
|
+
- @zhin.js/adapter@1.1.6
|
|
75
|
+
- @zhin.js/agent@1.1.4
|
|
76
|
+
- @zhin.js/command@1.0.8
|
|
77
|
+
- @zhin.js/core@1.5.3
|
|
78
|
+
- @zhin.js/im-contract@1.0.2
|
|
79
|
+
- @zhin.js/plugin-runtime@1.1.4
|
|
80
|
+
- zhin.js@6.0.3
|
|
81
|
+
|
|
3
82
|
## 6.0.3
|
|
4
83
|
|
|
5
84
|
### Patch Changes
|
package/adapters/onebot11.js
CHANGED
|
@@ -22,8 +22,8 @@ export default defineAdapter({
|
|
|
22
22
|
const config = resolveOneBot11Config(context.config);
|
|
23
23
|
const gateway = context.use(messageGatewayToken);
|
|
24
24
|
// 注册到插件运行时状态(onebot11.endpoint list 的"运行中"数据源)
|
|
25
|
-
context.use(onebot11RuntimeStateToken).endpoints.set(config.
|
|
26
|
-
|
|
25
|
+
context.use(onebot11RuntimeStateToken).endpoints.set(config.id, {
|
|
26
|
+
id: config.id,
|
|
27
27
|
mode: config.connection,
|
|
28
28
|
});
|
|
29
29
|
if (config.connection === 'wss') {
|
package/adapters/onebot11.ts
CHANGED
|
@@ -29,8 +29,8 @@ export default defineAdapter<OneBot11AdapterConfig>({
|
|
|
29
29
|
const config = resolveOneBot11Config(context.config);
|
|
30
30
|
const gateway = context.use(messageGatewayToken);
|
|
31
31
|
// 注册到插件运行时状态(onebot11.endpoint list 的"运行中"数据源)
|
|
32
|
-
context.use(onebot11RuntimeStateToken).endpoints.set(config.
|
|
33
|
-
|
|
32
|
+
context.use(onebot11RuntimeStateToken).endpoints.set(config.id, {
|
|
33
|
+
id: config.id,
|
|
34
34
|
mode: config.connection,
|
|
35
35
|
});
|
|
36
36
|
if (config.connection === 'wss') {
|
|
@@ -7,9 +7,9 @@ export interface Onebot11AgentEndpoint {
|
|
|
7
7
|
callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
8
8
|
}
|
|
9
9
|
export interface Onebot11AgentDeps {
|
|
10
|
-
getEndpoint: (
|
|
10
|
+
getEndpoint: (endpointKey: string) => Onebot11AgentEndpoint;
|
|
11
11
|
}
|
|
12
|
-
export declare function registerOnebot11AgentEndpoint(
|
|
12
|
+
export declare function registerOnebot11AgentEndpoint(endpointKey: string, endpoint: Onebot11AgentEndpoint): () => void;
|
|
13
13
|
/** Optional override used by tests / transitional callers. */
|
|
14
14
|
export declare function setOnebot11AgentDeps(deps: Onebot11AgentDeps): void;
|
|
15
15
|
export declare function getOnebot11AgentDeps(): Onebot11AgentDeps;
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
*/
|
|
5
5
|
const endpoints = new Map();
|
|
6
6
|
let override = null;
|
|
7
|
-
export function registerOnebot11AgentEndpoint(
|
|
8
|
-
endpoints.set(
|
|
7
|
+
export function registerOnebot11AgentEndpoint(endpointKey, endpoint) {
|
|
8
|
+
endpoints.set(endpointKey, endpoint);
|
|
9
9
|
return () => {
|
|
10
|
-
if (endpoints.get(
|
|
11
|
-
endpoints.delete(
|
|
10
|
+
if (endpoints.get(endpointKey) === endpoint) {
|
|
11
|
+
endpoints.delete(endpointKey);
|
|
12
12
|
}
|
|
13
13
|
};
|
|
14
14
|
}
|
|
@@ -20,10 +20,10 @@ export function getOnebot11AgentDeps() {
|
|
|
20
20
|
if (override)
|
|
21
21
|
return override;
|
|
22
22
|
return {
|
|
23
|
-
getEndpoint(
|
|
24
|
-
const registered = endpoints.get(
|
|
23
|
+
getEndpoint(endpointKey) {
|
|
24
|
+
const registered = endpoints.get(endpointKey);
|
|
25
25
|
if (!registered)
|
|
26
|
-
throw new Error(`Endpoint ${
|
|
26
|
+
throw new Error(`Endpoint ${endpointKey} 不存在`);
|
|
27
27
|
return registered;
|
|
28
28
|
},
|
|
29
29
|
};
|
package/lib/protocol.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export interface OneBot11LegacyEndpointRow {
|
|
|
11
11
|
readonly connection?: 'ws' | 'wss';
|
|
12
12
|
/** Legacy alias: `type: 'ws' | 'ws_reverse'` */
|
|
13
13
|
readonly type?: string;
|
|
14
|
-
readonly
|
|
14
|
+
readonly id?: string;
|
|
15
15
|
readonly access_token?: string;
|
|
16
16
|
readonly url?: string;
|
|
17
17
|
readonly path?: string;
|
|
@@ -21,7 +21,7 @@ export interface OneBot11LegacyEndpointRow {
|
|
|
21
21
|
/** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
|
|
22
22
|
export interface OneBot11AdapterConfig {
|
|
23
23
|
readonly connection?: 'ws' | 'wss';
|
|
24
|
-
readonly
|
|
24
|
+
readonly id?: string;
|
|
25
25
|
readonly access_token?: string;
|
|
26
26
|
readonly url?: string;
|
|
27
27
|
readonly path?: string;
|
|
@@ -32,7 +32,7 @@ export interface OneBot11AdapterConfig {
|
|
|
32
32
|
}
|
|
33
33
|
export interface OneBot11ConfigBase {
|
|
34
34
|
readonly context: 'onebot11';
|
|
35
|
-
readonly
|
|
35
|
+
readonly id: string;
|
|
36
36
|
readonly access_token?: string;
|
|
37
37
|
}
|
|
38
38
|
/** 正向 WebSocket:应用连 OneBot 实现的 WS 服务器 */
|
|
@@ -103,7 +103,7 @@ export declare function getChannelId(ev: OneBot11Event): string;
|
|
|
103
103
|
* 其余(private 及带 group_id 的非 private 事件按群处理)→ kind 'private'。
|
|
104
104
|
* OneBot 11 无 guild/temp 容器概念,不填 parent。
|
|
105
105
|
*/
|
|
106
|
-
export declare function onebot11InboundConversation(
|
|
106
|
+
export declare function onebot11InboundConversation(endpointKey: string, ev: OneBot11Event): ConversationRef;
|
|
107
107
|
/** Build inbound text for MessageGateway.receive */
|
|
108
108
|
export declare function formatInboundContent(ev: OneBot11Event): string;
|
|
109
109
|
export declare function senderDisplayName(ev: OneBot11Event): string;
|
|
@@ -124,8 +124,17 @@ export declare function isOneBot11BotMentioned(input: {
|
|
|
124
124
|
readonly selfId: string | undefined;
|
|
125
125
|
readonly message?: readonly OneBot11Segment[];
|
|
126
126
|
}): boolean;
|
|
127
|
-
/**
|
|
128
|
-
export
|
|
127
|
+
/** Inbound fields extracted from an event for gateway.receive (ws / wss 两个 endpoint 共用). */
|
|
128
|
+
export interface OneBot11InboundFields {
|
|
129
|
+
readonly metadata: Readonly<Record<string, unknown>>;
|
|
130
|
+
readonly endpointId: string;
|
|
131
|
+
readonly mentioned: boolean;
|
|
132
|
+
readonly replyTo: {
|
|
133
|
+
readonly id: string;
|
|
134
|
+
} | undefined;
|
|
135
|
+
}
|
|
136
|
+
/** 构造 gateway.receive 的 metadata 与提升字段(ws / wss 两个 endpoint 共用)。 */
|
|
137
|
+
export declare function formatInboundMetadata(ev: OneBot11Event, endpoint: string): OneBot11InboundFields;
|
|
129
138
|
/**
|
|
130
139
|
* canonical MediaRef → OneBot `file` 参数:url 直传、base64 → `base64://`、
|
|
131
140
|
* 本地路径 → `file://`(路径在 OneBot 实现侧解析)、kind=file 不透明引用原样透传。
|
package/lib/protocol.js
CHANGED
|
@@ -18,8 +18,8 @@ function normalizeConnection(connection, legacyType) {
|
|
|
18
18
|
export function resolveOneBot11Config(config = {}) {
|
|
19
19
|
const entry = config.endpoints?.find((item) => item.context === 'onebot11');
|
|
20
20
|
const connection = normalizeConnection(config.connection ?? entry?.connection, entry?.type);
|
|
21
|
-
const
|
|
22
|
-
|| (typeof entry?.
|
|
21
|
+
const id = (typeof config.id === 'string' && config.id)
|
|
22
|
+
|| (typeof entry?.id === 'string' && entry.id)
|
|
23
23
|
|| process.env.ONEBOT11_BOT_NAME
|
|
24
24
|
|| 'onebot11-bot';
|
|
25
25
|
const access_token = config.access_token ?? entry?.access_token;
|
|
@@ -31,7 +31,7 @@ export function resolveOneBot11Config(config = {}) {
|
|
|
31
31
|
return {
|
|
32
32
|
context: 'onebot11',
|
|
33
33
|
connection: 'ws',
|
|
34
|
-
|
|
34
|
+
id,
|
|
35
35
|
access_token,
|
|
36
36
|
url,
|
|
37
37
|
reconnect_interval: config.reconnect_interval ?? entry?.reconnect_interval ?? 5000,
|
|
@@ -46,7 +46,7 @@ export function resolveOneBot11Config(config = {}) {
|
|
|
46
46
|
return {
|
|
47
47
|
context: 'onebot11',
|
|
48
48
|
connection: 'wss',
|
|
49
|
-
|
|
49
|
+
id,
|
|
50
50
|
access_token,
|
|
51
51
|
path,
|
|
52
52
|
heartbeat_interval: config.heartbeat_interval ?? entry?.heartbeat_interval ?? 30_000,
|
|
@@ -73,12 +73,12 @@ export function getChannelId(ev) {
|
|
|
73
73
|
* 其余(private 及带 group_id 的非 private 事件按群处理)→ kind 'private'。
|
|
74
74
|
* OneBot 11 无 guild/temp 容器概念,不填 parent。
|
|
75
75
|
*/
|
|
76
|
-
export function onebot11InboundConversation(
|
|
76
|
+
export function onebot11InboundConversation(endpointKey, ev) {
|
|
77
77
|
const kind = ev.message_type === 'group' || (ev.group_id != null && ev.message_type !== 'private')
|
|
78
78
|
? 'group'
|
|
79
79
|
: 'private';
|
|
80
80
|
return {
|
|
81
|
-
endpoint: { id:
|
|
81
|
+
endpoint: { id: endpointKey, adapter: endpointKey.split('\0')[0] ?? endpointKey },
|
|
82
82
|
kind,
|
|
83
83
|
id: getChannelId(ev),
|
|
84
84
|
};
|
|
@@ -144,24 +144,26 @@ export function isOneBot11BotMentioned(input) {
|
|
|
144
144
|
return qq !== 'all' && qq === input.selfId;
|
|
145
145
|
});
|
|
146
146
|
}
|
|
147
|
-
/** 构造 gateway.receive 的 metadata
|
|
147
|
+
/** 构造 gateway.receive 的 metadata 与提升字段(ws / wss 两个 endpoint 共用)。 */
|
|
148
148
|
export function formatInboundMetadata(ev, endpoint) {
|
|
149
149
|
const selfId = ev.self_id != null ? String(ev.self_id) : undefined;
|
|
150
150
|
const nickname = senderNickname(ev);
|
|
151
151
|
const quoteId = extractQuoteId(ev);
|
|
152
152
|
const mentioned = isOneBot11BotMentioned({ selfId, message: ev.message });
|
|
153
|
-
return
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
153
|
+
return {
|
|
154
|
+
metadata: Object.freeze({
|
|
155
|
+
message_type: ev.message_type,
|
|
156
|
+
user_id: ev.user_id != null ? String(ev.user_id) : undefined,
|
|
157
|
+
group_id: ev.group_id != null ? String(ev.group_id) : undefined,
|
|
158
|
+
time: ev.time,
|
|
159
|
+
self_id: selfId,
|
|
160
|
+
role: ev.sender?.role,
|
|
161
|
+
...(nickname ? { nickname } : {}),
|
|
162
|
+
}),
|
|
163
|
+
endpointId: endpoint,
|
|
164
|
+
mentioned,
|
|
165
|
+
replyTo: quoteId ? { id: quoteId } : undefined,
|
|
166
|
+
};
|
|
165
167
|
}
|
|
166
168
|
/**
|
|
167
169
|
* canonical MediaRef → OneBot `file` 参数:url 直传、base64 → `base64://`、
|
package/lib/ws-endpoint.js
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import WebSocket from 'ws';
|
|
5
5
|
import { createEndpointLifecycle, } from '@zhin.js/adapter';
|
|
6
|
-
import { formatCompact,
|
|
6
|
+
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
7
7
|
import { createOneBot11EndpointManagement } from './endpoint-management.js';
|
|
8
8
|
import { registerOnebot11AgentEndpoint } from './onebot11-agent-deps.js';
|
|
9
|
-
import { buildSendAction, buildWsConnectOptions, formatInboundContent, formatInboundMetadata, formatOutboundSegments, isMessageEvent, onebot11InboundConversation, senderUserId, } from './protocol.js';
|
|
9
|
+
import { buildSendAction, buildWsConnectOptions, formatInboundContent, formatInboundMetadata, formatOutboundSegments, isMessageEvent, onebot11InboundConversation, senderDisplayName, senderUserId, } from './protocol.js';
|
|
10
10
|
import { callOneBot11WsAction, handleOneBot11WsMessage, rejectAllPending, } from './ws-transport.js';
|
|
11
|
-
const logger = getLogger('onebot11');
|
|
12
11
|
export class OneBot11WsEndpoint {
|
|
12
|
+
#logger;
|
|
13
13
|
#options;
|
|
14
14
|
management = createOneBot11EndpointManagement(this);
|
|
15
15
|
#lifecycle;
|
|
@@ -19,10 +19,11 @@ export class OneBot11WsEndpoint {
|
|
|
19
19
|
#open = false;
|
|
20
20
|
#unregisterAgent;
|
|
21
21
|
constructor(options) {
|
|
22
|
+
this.#logger = getAdapterLogger('onebot11', options.config.id);
|
|
22
23
|
this.#options = options;
|
|
23
24
|
const { config } = options;
|
|
24
25
|
this.#lifecycle = createEndpointLifecycle({
|
|
25
|
-
name: config.
|
|
26
|
+
name: config.id,
|
|
26
27
|
reconnect: {
|
|
27
28
|
initialIntervalMs: config.reconnect_interval,
|
|
28
29
|
// 固定间隔(multiplier 1、无抖动),对齐旧 reconnect_interval 语义
|
|
@@ -37,7 +38,7 @@ export class OneBot11WsEndpoint {
|
|
|
37
38
|
if (this.#lifecycle.started)
|
|
38
39
|
return;
|
|
39
40
|
// agent 注册/反注册是适配器专有依赖,留在适配器侧(见 endpoint-lifecycle 迁移指引)
|
|
40
|
-
this.#unregisterAgent = registerOnebot11AgentEndpoint(this.#options.config.
|
|
41
|
+
this.#unregisterAgent = registerOnebot11AgentEndpoint(this.#options.config.id, this);
|
|
41
42
|
try {
|
|
42
43
|
await this.#lifecycle.start((handle) => this.#connect(handle));
|
|
43
44
|
}
|
|
@@ -77,9 +78,9 @@ export class OneBot11WsEndpoint {
|
|
|
77
78
|
const { action, params } = buildSendAction(conversation, message);
|
|
78
79
|
const data = await this.callApi(action, params);
|
|
79
80
|
const messageId = data?.message_id != null ? String(data.message_id) : '';
|
|
80
|
-
logger.debug(formatCompact({
|
|
81
|
+
this.#logger.debug(formatCompact({
|
|
81
82
|
op: 'onebot11_send',
|
|
82
|
-
endpoint: this.#options.config.
|
|
83
|
+
endpoint: this.#options.config.id,
|
|
83
84
|
target: `${conversation.kind}:${conversation.id}`,
|
|
84
85
|
messageId,
|
|
85
86
|
}));
|
|
@@ -109,14 +110,22 @@ export class OneBot11WsEndpoint {
|
|
|
109
110
|
return;
|
|
110
111
|
const conversation = onebot11InboundConversation(String(this.#options.id), ev);
|
|
111
112
|
const content = formatInboundContent(ev);
|
|
113
|
+
const inbound = formatInboundMetadata(ev, this.#options.config.id);
|
|
112
114
|
void this.#options.gateway.receive({
|
|
113
115
|
conversation,
|
|
114
116
|
message: { conversation, id: String(ev.message_id) },
|
|
115
117
|
content,
|
|
116
|
-
sender:
|
|
117
|
-
|
|
118
|
+
sender: {
|
|
119
|
+
id: senderUserId(ev),
|
|
120
|
+
name: senderDisplayName(ev) || undefined,
|
|
121
|
+
...(ev.sender?.role ? { roles: [ev.sender.role] } : {}),
|
|
122
|
+
},
|
|
123
|
+
endpointId: inbound.endpointId,
|
|
124
|
+
...(inbound.mentioned ? { mentioned: true } : {}),
|
|
125
|
+
...(inbound.replyTo ? { replyTo: inbound.replyTo } : {}),
|
|
126
|
+
metadata: inbound.metadata,
|
|
118
127
|
}).catch((err) => {
|
|
119
|
-
logger.warn(formatCompact({
|
|
128
|
+
this.#logger.warn(formatCompact({
|
|
120
129
|
op: 'onebot11_gateway_receive_failed',
|
|
121
130
|
target: `${conversation.kind}:${conversation.id}`,
|
|
122
131
|
error: err instanceof Error ? err.message : String(err),
|
|
@@ -144,14 +153,14 @@ export class OneBot11WsEndpoint {
|
|
|
144
153
|
return;
|
|
145
154
|
settled = true;
|
|
146
155
|
if (!this.#options.config.access_token) {
|
|
147
|
-
logger.warn(formatCompact({
|
|
148
|
-
endpoint: this.#options.config.
|
|
156
|
+
this.#logger.warn(formatCompact({
|
|
157
|
+
endpoint: this.#options.config.id,
|
|
149
158
|
ok: false,
|
|
150
159
|
error: 'missing access_token',
|
|
151
160
|
}));
|
|
152
161
|
}
|
|
153
|
-
logger.debug(formatCompact({
|
|
154
|
-
endpoint: this.#options.config.
|
|
162
|
+
this.#logger.debug(formatCompact({
|
|
163
|
+
endpoint: this.#options.config.id,
|
|
155
164
|
mode: 'ws',
|
|
156
165
|
url: safeUrl,
|
|
157
166
|
}));
|
|
@@ -160,7 +169,7 @@ export class OneBot11WsEndpoint {
|
|
|
160
169
|
});
|
|
161
170
|
ws.on('message', (data) => {
|
|
162
171
|
handleOneBot11WsMessage(data, {
|
|
163
|
-
|
|
172
|
+
endpointId: this.#options.config.id,
|
|
164
173
|
pending: this.#pending,
|
|
165
174
|
admit: (ev) => this.admit(ev),
|
|
166
175
|
});
|
|
@@ -187,9 +196,9 @@ export class OneBot11WsEndpoint {
|
|
|
187
196
|
});
|
|
188
197
|
ws.on('error', (err) => {
|
|
189
198
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
190
|
-
logger.warn(formatCompact({
|
|
199
|
+
this.#logger.warn(formatCompact({
|
|
191
200
|
op: 'ws_error',
|
|
192
|
-
endpoint: this.#options.config.
|
|
201
|
+
endpoint: this.#options.config.id,
|
|
193
202
|
ok: false,
|
|
194
203
|
error: error.message,
|
|
195
204
|
}));
|
package/lib/ws-transport.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { 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
|
-
readonly
|
|
5
|
+
readonly endpointId: string;
|
|
6
6
|
readonly pending: Map<string, OneBot11PendingAction>;
|
|
7
7
|
readonly admit: (ev: OneBot11Event) => void;
|
|
8
8
|
}): void;
|
package/lib/ws-transport.js
CHANGED
|
@@ -33,7 +33,7 @@ export function handleOneBot11WsMessage(data, options) {
|
|
|
33
33
|
catch (error) {
|
|
34
34
|
logger.warn(formatCompact({
|
|
35
35
|
op: 'onebot11_parse_failed',
|
|
36
|
-
endpoint: options.
|
|
36
|
+
endpoint: options.endpointId,
|
|
37
37
|
error: error instanceof Error ? error.message : String(error),
|
|
38
38
|
}));
|
|
39
39
|
}
|
package/lib/wss-endpoint.js
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
* OneBot11 reverse WSS endpoint — accepts inbound WebSocket from OneBot implementation.
|
|
3
3
|
*/
|
|
4
4
|
import { clearInterval } from 'node:timers';
|
|
5
|
-
import { formatCompact,
|
|
5
|
+
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
6
6
|
import { createOneBot11EndpointManagement } from './endpoint-management.js';
|
|
7
7
|
import { registerOnebot11AgentEndpoint } from './onebot11-agent-deps.js';
|
|
8
|
-
import { buildSendAction, formatInboundContent, formatInboundMetadata, formatOutboundSegments, isMessageEvent, onebot11InboundConversation, senderUserId, } from './protocol.js';
|
|
8
|
+
import { buildSendAction, formatInboundContent, formatInboundMetadata, formatOutboundSegments, isMessageEvent, onebot11InboundConversation, senderDisplayName, senderUserId, } from './protocol.js';
|
|
9
9
|
import { verifyOneBotAccessToken } from './wss-auth.js';
|
|
10
10
|
import { callOneBot11WsAction, handleOneBot11WsMessage, rejectAllPending, startOneBot11Heartbeat, } from './ws-transport.js';
|
|
11
|
-
const logger = getLogger('onebot11');
|
|
12
11
|
export class OneBot11WssEndpoint {
|
|
12
|
+
#logger;
|
|
13
13
|
#options;
|
|
14
14
|
management = createOneBot11EndpointManagement(this);
|
|
15
15
|
#ws;
|
|
@@ -21,6 +21,7 @@ export class OneBot11WssEndpoint {
|
|
|
21
21
|
#started = false;
|
|
22
22
|
#unregisterAgent;
|
|
23
23
|
constructor(options) {
|
|
24
|
+
this.#logger = getAdapterLogger('onebot11', options.config.id);
|
|
24
25
|
this.#options = options;
|
|
25
26
|
}
|
|
26
27
|
async start() {
|
|
@@ -29,21 +30,21 @@ export class OneBot11WssEndpoint {
|
|
|
29
30
|
this.#started = true;
|
|
30
31
|
if (!this.#options.config.access_token) {
|
|
31
32
|
// wss 模式未配 access_token 时任何连接都会被放行(verifyOneBotAccessToken 直接 return true)
|
|
32
|
-
logger.warn(formatCompact({
|
|
33
|
-
endpoint: this.#options.config.
|
|
33
|
+
this.#logger.warn(formatCompact({
|
|
34
|
+
endpoint: this.#options.config.id,
|
|
34
35
|
mode: 'wss',
|
|
35
36
|
ok: false,
|
|
36
37
|
error: 'missing access_token',
|
|
37
38
|
}));
|
|
38
39
|
}
|
|
39
|
-
this.#unregisterAgent = registerOnebot11AgentEndpoint(this.#options.config.
|
|
40
|
+
this.#unregisterAgent = registerOnebot11AgentEndpoint(this.#options.config.id, this);
|
|
40
41
|
const handle = this.#options.http.ws(this.#options.config.path);
|
|
41
42
|
this.#wsRelease = handle.onConnection((connection) => {
|
|
42
43
|
this.#acceptConnection(connection);
|
|
43
44
|
});
|
|
44
|
-
logger.info(formatCompact({
|
|
45
|
+
this.#logger.info(formatCompact({
|
|
45
46
|
op: 'listen',
|
|
46
|
-
endpoint: this.#options.config.
|
|
47
|
+
endpoint: this.#options.config.id,
|
|
47
48
|
mode: 'wss',
|
|
48
49
|
path: this.#options.config.path,
|
|
49
50
|
}));
|
|
@@ -103,14 +104,22 @@ export class OneBot11WssEndpoint {
|
|
|
103
104
|
if (!this.#open || !isMessageEvent(ev))
|
|
104
105
|
return;
|
|
105
106
|
const conversation = onebot11InboundConversation(String(this.#options.id), ev);
|
|
107
|
+
const inbound = formatInboundMetadata(ev, this.#options.config.id);
|
|
106
108
|
void this.#options.gateway.receive({
|
|
107
109
|
conversation,
|
|
108
110
|
message: { conversation, id: String(ev.message_id) },
|
|
109
111
|
content: formatInboundContent(ev),
|
|
110
|
-
sender:
|
|
111
|
-
|
|
112
|
+
sender: {
|
|
113
|
+
id: senderUserId(ev),
|
|
114
|
+
name: senderDisplayName(ev) || undefined,
|
|
115
|
+
...(ev.sender?.role ? { roles: [ev.sender.role] } : {}),
|
|
116
|
+
},
|
|
117
|
+
endpointId: inbound.endpointId,
|
|
118
|
+
...(inbound.mentioned ? { mentioned: true } : {}),
|
|
119
|
+
...(inbound.replyTo ? { replyTo: inbound.replyTo } : {}),
|
|
120
|
+
metadata: inbound.metadata,
|
|
112
121
|
}).catch((err) => {
|
|
113
|
-
logger.warn(formatCompact({
|
|
122
|
+
this.#logger.warn(formatCompact({
|
|
114
123
|
op: 'onebot11_gateway_receive_failed',
|
|
115
124
|
target: `${conversation.kind}:${conversation.id}`,
|
|
116
125
|
error: err instanceof Error ? err.message : String(err),
|
|
@@ -135,7 +144,7 @@ export class OneBot11WssEndpoint {
|
|
|
135
144
|
this.#heartbeatTimer = startOneBot11Heartbeat(this.#ws, this.#options.config.heartbeat_interval, this.#heartbeatTimer);
|
|
136
145
|
socket.on('message', (data) => {
|
|
137
146
|
handleOneBot11WsMessage(data, {
|
|
138
|
-
|
|
147
|
+
endpointId: this.#options.config.id,
|
|
139
148
|
pending: this.#pending,
|
|
140
149
|
admit: (ev) => this.admit(ev),
|
|
141
150
|
});
|
|
@@ -149,8 +158,8 @@ export class OneBot11WssEndpoint {
|
|
|
149
158
|
}
|
|
150
159
|
}
|
|
151
160
|
});
|
|
152
|
-
logger.debug(formatCompact({
|
|
153
|
-
endpoint: this.#options.config.
|
|
161
|
+
this.#logger.debug(formatCompact({
|
|
162
|
+
endpoint: this.#options.config.id,
|
|
154
163
|
mode: 'wss',
|
|
155
164
|
peer: connection.request.socket.remoteAddress,
|
|
156
165
|
}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-onebot11",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.5",
|
|
4
4
|
"description": "Zhin.js OneBot 11 adapter for Plugin Runtime (WebSocket client)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -41,13 +41,14 @@
|
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"ws": "^8.21.1",
|
|
44
|
-
"@zhin.js/adapter": "1.1.
|
|
45
|
-
"@zhin.js/command": "1.0.
|
|
46
|
-
"@zhin.js/core": "1.5.
|
|
47
|
-
"@zhin.js/host-http": "1.0.
|
|
48
|
-
"@zhin.js/im-contract": "1.0.
|
|
49
|
-
"@zhin.js/logger": "1.0.
|
|
50
|
-
"@zhin.js/
|
|
44
|
+
"@zhin.js/adapter": "1.1.7",
|
|
45
|
+
"@zhin.js/command": "1.0.9",
|
|
46
|
+
"@zhin.js/core": "1.5.4",
|
|
47
|
+
"@zhin.js/host-http": "1.0.8",
|
|
48
|
+
"@zhin.js/im-contract": "1.0.3",
|
|
49
|
+
"@zhin.js/logger": "1.0.76",
|
|
50
|
+
"@zhin.js/permission": "1.0.1",
|
|
51
|
+
"@zhin.js/plugin-runtime": "1.1.5"
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|
|
53
54
|
"@types/node": "^26.1.2",
|
|
@@ -55,16 +56,16 @@
|
|
|
55
56
|
"typescript": "^6.0.3",
|
|
56
57
|
"vitest": "^4.1.10",
|
|
57
58
|
"zod": "^4.4.3",
|
|
58
|
-
"@zhin.js/agent": "1.1.
|
|
59
|
-
"@zhin.js/host-http": "1.0.
|
|
59
|
+
"@zhin.js/agent": "1.1.5",
|
|
60
|
+
"@zhin.js/host-http": "1.0.8"
|
|
60
61
|
},
|
|
61
62
|
"peerDependencies": {
|
|
62
63
|
"zod": "^4.0.0",
|
|
63
|
-
"@zhin.js/adapter": "1.1.
|
|
64
|
-
"@zhin.js/agent": "1.1.
|
|
65
|
-
"@zhin.js/core": "1.5.
|
|
66
|
-
"@zhin.js/plugin-runtime": "1.1.
|
|
67
|
-
"zhin.js": "6.0.
|
|
64
|
+
"@zhin.js/adapter": "1.1.7",
|
|
65
|
+
"@zhin.js/agent": "1.1.5",
|
|
66
|
+
"@zhin.js/core": "1.5.4",
|
|
67
|
+
"@zhin.js/plugin-runtime": "1.1.5",
|
|
68
|
+
"zhin.js": "6.0.4"
|
|
68
69
|
},
|
|
69
70
|
"peerDependenciesMeta": {
|
|
70
71
|
"zhin.js": {
|
package/plugin.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
2
|
import { createEndpointRuntimeState } from '@zhin.js/adapter';
|
|
3
3
|
import { definePlugin } from '@zhin.js/plugin-runtime';
|
|
4
|
-
import {
|
|
4
|
+
import { permissionHostToken, createSceneRolePlatformChecker } from '@zhin.js/permission';
|
|
5
5
|
import { onebot11RuntimeStateToken } from "./lib/onebot11-runtime-state.js";
|
|
6
6
|
export default definePlugin({
|
|
7
7
|
name: 'onebot11',
|
|
@@ -9,9 +9,10 @@ export default definePlugin({
|
|
|
9
9
|
displayName: 'OneBot 11 Adapter',
|
|
10
10
|
},
|
|
11
11
|
setup(context) {
|
|
12
|
-
// 运行中 endpoint 注册表(onebot11.endpoint list 的"运行中"数据源)
|
|
13
12
|
context.resources.provide(onebot11RuntimeStateToken, createEndpointRuntimeState());
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
if (context.resources.has(permissionHostToken)) {
|
|
14
|
+
const host = context.resources.use(permissionHostToken);
|
|
15
|
+
return host.registerPlatform('onebot11', createSceneRolePlatformChecker());
|
|
16
|
+
}
|
|
16
17
|
},
|
|
17
18
|
});
|
package/schema.json
CHANGED
|
@@ -20,16 +20,48 @@
|
|
|
20
20
|
"type": "number",
|
|
21
21
|
"default": 30000
|
|
22
22
|
},
|
|
23
|
+
"master": {
|
|
24
|
+
"type": [
|
|
25
|
+
"string",
|
|
26
|
+
"number"
|
|
27
|
+
],
|
|
28
|
+
"description": "框架 master(platform user id;AI/工具权限、endpoint 管理)。endpoints[i].master 可逐项覆盖"
|
|
29
|
+
},
|
|
30
|
+
"trusted": {
|
|
31
|
+
"type": "array",
|
|
32
|
+
"items": {
|
|
33
|
+
"type": [
|
|
34
|
+
"string",
|
|
35
|
+
"number"
|
|
36
|
+
],
|
|
37
|
+
"description": "Trusted platform user id"
|
|
38
|
+
},
|
|
39
|
+
"description": "框架 trusted 用户列表(弱于 master)。endpoints[i].trusted 可逐项追加"
|
|
40
|
+
},
|
|
23
41
|
"endpoints": {
|
|
24
42
|
"type": "array",
|
|
25
|
-
"description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(
|
|
43
|
+
"description": "多账号:一个插件实例挂多个 endpoint。每项与顶层字段同构(id 必填,其余覆盖顶层)",
|
|
26
44
|
"items": {
|
|
27
45
|
"type": "object",
|
|
28
46
|
"additionalProperties": true,
|
|
29
47
|
"properties": {
|
|
30
|
-
"
|
|
31
|
-
"type":
|
|
32
|
-
|
|
48
|
+
"master": {
|
|
49
|
+
"type": [
|
|
50
|
+
"string",
|
|
51
|
+
"number"
|
|
52
|
+
],
|
|
53
|
+
"description": "本 endpoint 的框架 master(platform user id);覆盖顶层 master"
|
|
54
|
+
},
|
|
55
|
+
"trusted": {
|
|
56
|
+
"type": "array",
|
|
57
|
+
"items": {
|
|
58
|
+
"type": [
|
|
59
|
+
"string",
|
|
60
|
+
"number"
|
|
61
|
+
],
|
|
62
|
+
"description": "Trusted platform user id"
|
|
63
|
+
},
|
|
64
|
+
"description": "本 endpoint 的 trusted 列表"
|
|
33
65
|
},
|
|
34
66
|
"url": {
|
|
35
67
|
"type": "string",
|
|
@@ -42,10 +74,14 @@
|
|
|
42
74
|
"access_token": {
|
|
43
75
|
"type": "string",
|
|
44
76
|
"description": "OneBot access token"
|
|
77
|
+
},
|
|
78
|
+
"id": {
|
|
79
|
+
"type": "string",
|
|
80
|
+
"description": "OneBot11 bot name"
|
|
45
81
|
}
|
|
46
82
|
},
|
|
47
83
|
"required": [
|
|
48
|
-
"
|
|
84
|
+
"id"
|
|
49
85
|
]
|
|
50
86
|
}
|
|
51
87
|
},
|
|
@@ -14,20 +14,20 @@ export interface Onebot11AgentEndpoint {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export interface Onebot11AgentDeps {
|
|
17
|
-
getEndpoint: (
|
|
17
|
+
getEndpoint: (endpointKey: string) => Onebot11AgentEndpoint;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
const endpoints = new Map<string, Onebot11AgentEndpoint>();
|
|
21
21
|
let override: Onebot11AgentDeps | null = null;
|
|
22
22
|
|
|
23
23
|
export function registerOnebot11AgentEndpoint(
|
|
24
|
-
|
|
24
|
+
endpointKey: string,
|
|
25
25
|
endpoint: Onebot11AgentEndpoint,
|
|
26
26
|
): () => void {
|
|
27
|
-
endpoints.set(
|
|
27
|
+
endpoints.set(endpointKey, endpoint);
|
|
28
28
|
return () => {
|
|
29
|
-
if (endpoints.get(
|
|
30
|
-
endpoints.delete(
|
|
29
|
+
if (endpoints.get(endpointKey) === endpoint) {
|
|
30
|
+
endpoints.delete(endpointKey);
|
|
31
31
|
}
|
|
32
32
|
};
|
|
33
33
|
}
|
|
@@ -40,9 +40,9 @@ export function setOnebot11AgentDeps(deps: Onebot11AgentDeps): void {
|
|
|
40
40
|
export function getOnebot11AgentDeps(): Onebot11AgentDeps {
|
|
41
41
|
if (override) return override;
|
|
42
42
|
return {
|
|
43
|
-
getEndpoint(
|
|
44
|
-
const registered = endpoints.get(
|
|
45
|
-
if (!registered) throw new Error(`Endpoint ${
|
|
43
|
+
getEndpoint(endpointKey: string): Onebot11AgentEndpoint {
|
|
44
|
+
const registered = endpoints.get(endpointKey);
|
|
45
|
+
if (!registered) throw new Error(`Endpoint ${endpointKey} 不存在`);
|
|
46
46
|
return registered;
|
|
47
47
|
},
|
|
48
48
|
};
|
package/src/protocol.ts
CHANGED
|
@@ -15,7 +15,7 @@ export interface OneBot11LegacyEndpointRow {
|
|
|
15
15
|
readonly connection?: 'ws' | 'wss';
|
|
16
16
|
/** Legacy alias: `type: 'ws' | 'ws_reverse'` */
|
|
17
17
|
readonly type?: string;
|
|
18
|
-
readonly
|
|
18
|
+
readonly id?: string;
|
|
19
19
|
readonly access_token?: string;
|
|
20
20
|
readonly url?: string;
|
|
21
21
|
readonly path?: string;
|
|
@@ -26,7 +26,7 @@ export interface OneBot11LegacyEndpointRow {
|
|
|
26
26
|
/** Plugin Runtime owner config (`plugins.<instanceKey>` / schema.json). */
|
|
27
27
|
export interface OneBot11AdapterConfig {
|
|
28
28
|
readonly connection?: 'ws' | 'wss';
|
|
29
|
-
readonly
|
|
29
|
+
readonly id?: string;
|
|
30
30
|
readonly access_token?: string;
|
|
31
31
|
readonly url?: string;
|
|
32
32
|
readonly path?: string;
|
|
@@ -38,7 +38,7 @@ export interface OneBot11AdapterConfig {
|
|
|
38
38
|
|
|
39
39
|
export interface OneBot11ConfigBase {
|
|
40
40
|
readonly context: 'onebot11';
|
|
41
|
-
readonly
|
|
41
|
+
readonly id: string;
|
|
42
42
|
readonly access_token?: string;
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -123,8 +123,8 @@ export function resolveOneBot11Config(config: OneBot11AdapterConfig = {}): Resol
|
|
|
123
123
|
config.connection ?? entry?.connection,
|
|
124
124
|
entry?.type,
|
|
125
125
|
);
|
|
126
|
-
const
|
|
127
|
-
|| (typeof entry?.
|
|
126
|
+
const id = (typeof config.id === 'string' && config.id)
|
|
127
|
+
|| (typeof entry?.id === 'string' && entry.id)
|
|
128
128
|
|| process.env.ONEBOT11_BOT_NAME
|
|
129
129
|
|| 'onebot11-bot';
|
|
130
130
|
const access_token = config.access_token ?? entry?.access_token;
|
|
@@ -139,7 +139,7 @@ export function resolveOneBot11Config(config: OneBot11AdapterConfig = {}): Resol
|
|
|
139
139
|
return {
|
|
140
140
|
context: 'onebot11',
|
|
141
141
|
connection: 'ws',
|
|
142
|
-
|
|
142
|
+
id,
|
|
143
143
|
access_token,
|
|
144
144
|
url,
|
|
145
145
|
reconnect_interval: config.reconnect_interval ?? entry?.reconnect_interval ?? 5000,
|
|
@@ -155,7 +155,7 @@ export function resolveOneBot11Config(config: OneBot11AdapterConfig = {}): Resol
|
|
|
155
155
|
return {
|
|
156
156
|
context: 'onebot11',
|
|
157
157
|
connection: 'wss',
|
|
158
|
-
|
|
158
|
+
id,
|
|
159
159
|
access_token,
|
|
160
160
|
path,
|
|
161
161
|
heartbeat_interval: config.heartbeat_interval ?? entry?.heartbeat_interval ?? 30_000,
|
|
@@ -185,12 +185,12 @@ export function getChannelId(ev: OneBot11Event): string {
|
|
|
185
185
|
* 其余(private 及带 group_id 的非 private 事件按群处理)→ kind 'private'。
|
|
186
186
|
* OneBot 11 无 guild/temp 容器概念,不填 parent。
|
|
187
187
|
*/
|
|
188
|
-
export function onebot11InboundConversation(
|
|
188
|
+
export function onebot11InboundConversation(endpointKey: string, ev: OneBot11Event): ConversationRef {
|
|
189
189
|
const kind = ev.message_type === 'group' || (ev.group_id != null && ev.message_type !== 'private')
|
|
190
190
|
? 'group' as const
|
|
191
191
|
: 'private' as const;
|
|
192
192
|
return {
|
|
193
|
-
endpoint: { id:
|
|
193
|
+
endpoint: { id: endpointKey, adapter: endpointKey.split('\0')[0] ?? endpointKey },
|
|
194
194
|
kind,
|
|
195
195
|
id: getChannelId(ev),
|
|
196
196
|
};
|
|
@@ -259,27 +259,37 @@ export function isOneBot11BotMentioned(input: {
|
|
|
259
259
|
});
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
-
/**
|
|
262
|
+
/** Inbound fields extracted from an event for gateway.receive (ws / wss 两个 endpoint 共用). */
|
|
263
|
+
export interface OneBot11InboundFields {
|
|
264
|
+
readonly metadata: Readonly<Record<string, unknown>>;
|
|
265
|
+
readonly endpointId: string;
|
|
266
|
+
readonly mentioned: boolean;
|
|
267
|
+
readonly replyTo: { readonly id: string } | undefined;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/** 构造 gateway.receive 的 metadata 与提升字段(ws / wss 两个 endpoint 共用)。 */
|
|
263
271
|
export function formatInboundMetadata(
|
|
264
272
|
ev: OneBot11Event,
|
|
265
273
|
endpoint: string,
|
|
266
|
-
):
|
|
274
|
+
): OneBot11InboundFields {
|
|
267
275
|
const selfId = ev.self_id != null ? String(ev.self_id) : undefined;
|
|
268
276
|
const nickname = senderNickname(ev);
|
|
269
277
|
const quoteId = extractQuoteId(ev);
|
|
270
278
|
const mentioned = isOneBot11BotMentioned({ selfId, message: ev.message });
|
|
271
|
-
return
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
279
|
+
return {
|
|
280
|
+
metadata: Object.freeze({
|
|
281
|
+
message_type: ev.message_type,
|
|
282
|
+
user_id: ev.user_id != null ? String(ev.user_id) : undefined,
|
|
283
|
+
group_id: ev.group_id != null ? String(ev.group_id) : undefined,
|
|
284
|
+
time: ev.time,
|
|
285
|
+
self_id: selfId,
|
|
286
|
+
role: ev.sender?.role,
|
|
287
|
+
...(nickname ? { nickname } : {}),
|
|
288
|
+
}),
|
|
289
|
+
endpointId: endpoint,
|
|
290
|
+
mentioned,
|
|
291
|
+
replyTo: quoteId ? { id: quoteId } : undefined,
|
|
292
|
+
};
|
|
283
293
|
}
|
|
284
294
|
|
|
285
295
|
/**
|
package/src/ws-endpoint.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
type EndpointSendRequest,
|
|
12
12
|
} from '@zhin.js/adapter';
|
|
13
13
|
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
14
|
-
import { formatCompact,
|
|
14
|
+
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
15
15
|
import type { CapabilityId } from '@zhin.js/plugin-runtime';
|
|
16
16
|
import { createOneBot11EndpointManagement } from './endpoint-management.js';
|
|
17
17
|
import { registerOnebot11AgentEndpoint } from './onebot11-agent-deps.js';
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
formatOutboundSegments,
|
|
24
24
|
isMessageEvent,
|
|
25
25
|
onebot11InboundConversation,
|
|
26
|
+
senderDisplayName,
|
|
26
27
|
senderUserId,
|
|
27
28
|
type OneBot11Event,
|
|
28
29
|
type OneBot11WsConfig,
|
|
@@ -38,8 +39,6 @@ import {
|
|
|
38
39
|
type OneBot11WsSocket,
|
|
39
40
|
} from './ws-types.js';
|
|
40
41
|
|
|
41
|
-
const logger = getLogger('onebot11');
|
|
42
|
-
|
|
43
42
|
export interface OneBot11WsEndpointOptions {
|
|
44
43
|
readonly id: CapabilityId;
|
|
45
44
|
readonly gateway: MessageGateway;
|
|
@@ -51,6 +50,8 @@ export interface OneBot11WsEndpointOptions {
|
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
export class OneBot11WsEndpoint implements EndpointInstance {
|
|
53
|
+
readonly #logger!: ReturnType<typeof getAdapterLogger>;
|
|
54
|
+
|
|
54
55
|
readonly #options: OneBot11WsEndpointOptions;
|
|
55
56
|
readonly management: EndpointManagement = createOneBot11EndpointManagement(this);
|
|
56
57
|
readonly #lifecycle: EndpointLifecycle;
|
|
@@ -61,10 +62,11 @@ export class OneBot11WsEndpoint implements EndpointInstance {
|
|
|
61
62
|
#unregisterAgent?: () => void;
|
|
62
63
|
|
|
63
64
|
constructor(options: OneBot11WsEndpointOptions) {
|
|
65
|
+
this.#logger = getAdapterLogger('onebot11', options.config.id);
|
|
64
66
|
this.#options = options;
|
|
65
67
|
const { config } = options;
|
|
66
68
|
this.#lifecycle = createEndpointLifecycle({
|
|
67
|
-
name: config.
|
|
69
|
+
name: config.id,
|
|
68
70
|
reconnect: {
|
|
69
71
|
initialIntervalMs: config.reconnect_interval,
|
|
70
72
|
// 固定间隔(multiplier 1、无抖动),对齐旧 reconnect_interval 语义
|
|
@@ -79,7 +81,7 @@ export class OneBot11WsEndpoint implements EndpointInstance {
|
|
|
79
81
|
async start(): Promise<void> {
|
|
80
82
|
if (this.#lifecycle.started) return;
|
|
81
83
|
// agent 注册/反注册是适配器专有依赖,留在适配器侧(见 endpoint-lifecycle 迁移指引)
|
|
82
|
-
this.#unregisterAgent = registerOnebot11AgentEndpoint(this.#options.config.
|
|
84
|
+
this.#unregisterAgent = registerOnebot11AgentEndpoint(this.#options.config.id, this);
|
|
83
85
|
try {
|
|
84
86
|
await this.#lifecycle.start((handle) => this.#connect(handle));
|
|
85
87
|
} catch (err) {
|
|
@@ -121,9 +123,9 @@ export class OneBot11WsEndpoint implements EndpointInstance {
|
|
|
121
123
|
const { action, params } = buildSendAction(conversation, message);
|
|
122
124
|
const data = await this.callApi(action, params) as { message_id?: number | string } | undefined;
|
|
123
125
|
const messageId = data?.message_id != null ? String(data.message_id) : '';
|
|
124
|
-
logger.debug(formatCompact({
|
|
126
|
+
this.#logger.debug(formatCompact({
|
|
125
127
|
op: 'onebot11_send',
|
|
126
|
-
endpoint: this.#options.config.
|
|
128
|
+
endpoint: this.#options.config.id,
|
|
127
129
|
target: `${conversation.kind}:${conversation.id}`,
|
|
128
130
|
messageId,
|
|
129
131
|
}));
|
|
@@ -160,14 +162,22 @@ export class OneBot11WsEndpoint implements EndpointInstance {
|
|
|
160
162
|
if (!this.#open || !isMessageEvent(ev)) return;
|
|
161
163
|
const conversation = onebot11InboundConversation(String(this.#options.id), ev);
|
|
162
164
|
const content = formatInboundContent(ev);
|
|
165
|
+
const inbound = formatInboundMetadata(ev, this.#options.config.id);
|
|
163
166
|
void this.#options.gateway.receive({
|
|
164
167
|
conversation,
|
|
165
168
|
message: { conversation, id: String(ev.message_id) },
|
|
166
169
|
content,
|
|
167
|
-
sender:
|
|
168
|
-
|
|
170
|
+
sender: {
|
|
171
|
+
id: senderUserId(ev),
|
|
172
|
+
name: senderDisplayName(ev) || undefined,
|
|
173
|
+
...(ev.sender?.role ? { roles: [ev.sender.role] } : {}),
|
|
174
|
+
},
|
|
175
|
+
endpointId: inbound.endpointId,
|
|
176
|
+
...(inbound.mentioned ? { mentioned: true } : {}),
|
|
177
|
+
...(inbound.replyTo ? { replyTo: inbound.replyTo } : {}),
|
|
178
|
+
metadata: inbound.metadata,
|
|
169
179
|
}).catch((err) => {
|
|
170
|
-
logger.warn(formatCompact({
|
|
180
|
+
this.#logger.warn(formatCompact({
|
|
171
181
|
op: 'onebot11_gateway_receive_failed',
|
|
172
182
|
target: `${conversation.kind}:${conversation.id}`,
|
|
173
183
|
error: err instanceof Error ? err.message : String(err),
|
|
@@ -197,14 +207,14 @@ export class OneBot11WsEndpoint implements EndpointInstance {
|
|
|
197
207
|
if (settled) return;
|
|
198
208
|
settled = true;
|
|
199
209
|
if (!this.#options.config.access_token) {
|
|
200
|
-
logger.warn(formatCompact({
|
|
201
|
-
endpoint: this.#options.config.
|
|
210
|
+
this.#logger.warn(formatCompact({
|
|
211
|
+
endpoint: this.#options.config.id,
|
|
202
212
|
ok: false,
|
|
203
213
|
error: 'missing access_token',
|
|
204
214
|
}));
|
|
205
215
|
}
|
|
206
|
-
logger.debug(formatCompact({
|
|
207
|
-
endpoint: this.#options.config.
|
|
216
|
+
this.#logger.debug(formatCompact({
|
|
217
|
+
endpoint: this.#options.config.id,
|
|
208
218
|
mode: 'ws',
|
|
209
219
|
url: safeUrl,
|
|
210
220
|
}));
|
|
@@ -214,7 +224,7 @@ export class OneBot11WsEndpoint implements EndpointInstance {
|
|
|
214
224
|
|
|
215
225
|
ws.on('message', (data) => {
|
|
216
226
|
handleOneBot11WsMessage(data, {
|
|
217
|
-
|
|
227
|
+
endpointId: this.#options.config.id,
|
|
218
228
|
pending: this.#pending,
|
|
219
229
|
admit: (ev) => this.admit(ev),
|
|
220
230
|
});
|
|
@@ -243,9 +253,9 @@ export class OneBot11WsEndpoint implements EndpointInstance {
|
|
|
243
253
|
|
|
244
254
|
ws.on('error', (err) => {
|
|
245
255
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
246
|
-
logger.warn(formatCompact({
|
|
256
|
+
this.#logger.warn(formatCompact({
|
|
247
257
|
op: 'ws_error',
|
|
248
|
-
endpoint: this.#options.config.
|
|
258
|
+
endpoint: this.#options.config.id,
|
|
249
259
|
ok: false,
|
|
250
260
|
error: error.message,
|
|
251
261
|
}));
|
package/src/ws-transport.ts
CHANGED
|
@@ -23,7 +23,7 @@ export function decodeWsPayload(data: unknown): string {
|
|
|
23
23
|
export function handleOneBot11WsMessage(
|
|
24
24
|
data: unknown,
|
|
25
25
|
options: {
|
|
26
|
-
readonly
|
|
26
|
+
readonly endpointId: string;
|
|
27
27
|
readonly pending: Map<string, OneBot11PendingAction>;
|
|
28
28
|
readonly admit: (ev: OneBot11Event) => void;
|
|
29
29
|
},
|
|
@@ -46,7 +46,7 @@ export function handleOneBot11WsMessage(
|
|
|
46
46
|
} catch (error) {
|
|
47
47
|
logger.warn(formatCompact({
|
|
48
48
|
op: 'onebot11_parse_failed',
|
|
49
|
-
endpoint: options.
|
|
49
|
+
endpoint: options.endpointId,
|
|
50
50
|
error: error instanceof Error ? error.message : String(error),
|
|
51
51
|
}));
|
|
52
52
|
}
|
package/src/wss-endpoint.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { clearInterval } from 'node:timers';
|
|
|
5
5
|
import type { EndpointInstance, EndpointManagement, EndpointSendRequest } from '@zhin.js/adapter';
|
|
6
6
|
import type { MessageGateway } from '@zhin.js/core/runtime';
|
|
7
7
|
import type { HttpHost, WsConnection } from '@zhin.js/host-http';
|
|
8
|
-
import { formatCompact,
|
|
8
|
+
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
9
9
|
import type { CapabilityId } from '@zhin.js/plugin-runtime';
|
|
10
10
|
import { createOneBot11EndpointManagement } from './endpoint-management.js';
|
|
11
11
|
import { registerOnebot11AgentEndpoint } from './onebot11-agent-deps.js';
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
formatOutboundSegments,
|
|
17
17
|
isMessageEvent,
|
|
18
18
|
onebot11InboundConversation,
|
|
19
|
+
senderDisplayName,
|
|
19
20
|
senderUserId,
|
|
20
21
|
type OneBot11Event,
|
|
21
22
|
type OneBot11WssConfig,
|
|
@@ -33,8 +34,6 @@ import {
|
|
|
33
34
|
type OneBot11WsSocket,
|
|
34
35
|
} from './ws-types.js';
|
|
35
36
|
|
|
36
|
-
const logger = getLogger('onebot11');
|
|
37
|
-
|
|
38
37
|
export interface OneBot11WssEndpointOptions {
|
|
39
38
|
readonly id: CapabilityId;
|
|
40
39
|
readonly gateway: MessageGateway;
|
|
@@ -43,6 +42,8 @@ export interface OneBot11WssEndpointOptions {
|
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
export class OneBot11WssEndpoint implements EndpointInstance {
|
|
45
|
+
readonly #logger!: ReturnType<typeof getAdapterLogger>;
|
|
46
|
+
|
|
46
47
|
readonly #options: OneBot11WssEndpointOptions;
|
|
47
48
|
readonly management: EndpointManagement = createOneBot11EndpointManagement(this);
|
|
48
49
|
#ws?: OneBot11WsSocket;
|
|
@@ -55,6 +56,7 @@ export class OneBot11WssEndpoint implements EndpointInstance {
|
|
|
55
56
|
#unregisterAgent?: () => void;
|
|
56
57
|
|
|
57
58
|
constructor(options: OneBot11WssEndpointOptions) {
|
|
59
|
+
this.#logger = getAdapterLogger('onebot11', options.config.id);
|
|
58
60
|
this.#options = options;
|
|
59
61
|
}
|
|
60
62
|
|
|
@@ -63,24 +65,24 @@ export class OneBot11WssEndpoint implements EndpointInstance {
|
|
|
63
65
|
this.#started = true;
|
|
64
66
|
if (!this.#options.config.access_token) {
|
|
65
67
|
// wss 模式未配 access_token 时任何连接都会被放行(verifyOneBotAccessToken 直接 return true)
|
|
66
|
-
logger.warn(formatCompact({
|
|
67
|
-
endpoint: this.#options.config.
|
|
68
|
+
this.#logger.warn(formatCompact({
|
|
69
|
+
endpoint: this.#options.config.id,
|
|
68
70
|
mode: 'wss',
|
|
69
71
|
ok: false,
|
|
70
72
|
error: 'missing access_token',
|
|
71
73
|
}));
|
|
72
74
|
}
|
|
73
75
|
this.#unregisterAgent = registerOnebot11AgentEndpoint(
|
|
74
|
-
this.#options.config.
|
|
76
|
+
this.#options.config.id,
|
|
75
77
|
this as unknown as OneBot11WsEndpoint,
|
|
76
78
|
);
|
|
77
79
|
const handle = this.#options.http.ws(this.#options.config.path);
|
|
78
80
|
this.#wsRelease = handle.onConnection((connection) => {
|
|
79
81
|
this.#acceptConnection(connection);
|
|
80
82
|
});
|
|
81
|
-
logger.info(formatCompact({
|
|
83
|
+
this.#logger.info(formatCompact({
|
|
82
84
|
op: 'listen',
|
|
83
|
-
endpoint: this.#options.config.
|
|
85
|
+
endpoint: this.#options.config.id,
|
|
84
86
|
mode: 'wss',
|
|
85
87
|
path: this.#options.config.path,
|
|
86
88
|
}));
|
|
@@ -145,14 +147,22 @@ export class OneBot11WssEndpoint implements EndpointInstance {
|
|
|
145
147
|
admit(ev: OneBot11Event): void {
|
|
146
148
|
if (!this.#open || !isMessageEvent(ev)) return;
|
|
147
149
|
const conversation = onebot11InboundConversation(String(this.#options.id), ev);
|
|
150
|
+
const inbound = formatInboundMetadata(ev, this.#options.config.id);
|
|
148
151
|
void this.#options.gateway.receive({
|
|
149
152
|
conversation,
|
|
150
153
|
message: { conversation, id: String(ev.message_id) },
|
|
151
154
|
content: formatInboundContent(ev),
|
|
152
|
-
sender:
|
|
153
|
-
|
|
155
|
+
sender: {
|
|
156
|
+
id: senderUserId(ev),
|
|
157
|
+
name: senderDisplayName(ev) || undefined,
|
|
158
|
+
...(ev.sender?.role ? { roles: [ev.sender.role] } : {}),
|
|
159
|
+
},
|
|
160
|
+
endpointId: inbound.endpointId,
|
|
161
|
+
...(inbound.mentioned ? { mentioned: true } : {}),
|
|
162
|
+
...(inbound.replyTo ? { replyTo: inbound.replyTo } : {}),
|
|
163
|
+
metadata: inbound.metadata,
|
|
154
164
|
}).catch((err) => {
|
|
155
|
-
logger.warn(formatCompact({
|
|
165
|
+
this.#logger.warn(formatCompact({
|
|
156
166
|
op: 'onebot11_gateway_receive_failed',
|
|
157
167
|
target: `${conversation.kind}:${conversation.id}`,
|
|
158
168
|
error: err instanceof Error ? err.message : String(err),
|
|
@@ -181,7 +191,7 @@ export class OneBot11WssEndpoint implements EndpointInstance {
|
|
|
181
191
|
);
|
|
182
192
|
socket.on('message', (data) => {
|
|
183
193
|
handleOneBot11WsMessage(data, {
|
|
184
|
-
|
|
194
|
+
endpointId: this.#options.config.id,
|
|
185
195
|
pending: this.#pending,
|
|
186
196
|
admit: (ev) => this.admit(ev),
|
|
187
197
|
});
|
|
@@ -195,8 +205,8 @@ export class OneBot11WssEndpoint implements EndpointInstance {
|
|
|
195
205
|
}
|
|
196
206
|
}
|
|
197
207
|
});
|
|
198
|
-
logger.debug(formatCompact({
|
|
199
|
-
endpoint: this.#options.config.
|
|
208
|
+
this.#logger.debug(formatCompact({
|
|
209
|
+
endpoint: this.#options.config.id,
|
|
200
210
|
mode: 'wss',
|
|
201
211
|
peer: connection.request.socket.remoteAddress,
|
|
202
212
|
}));
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|