@zhin.js/adapter-onebot12 6.0.0 → 6.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 +31 -0
- package/README.md +21 -2
- package/adapters/onebot12.js +0 -9
- package/adapters/onebot12.ts +0 -9
- package/lib/client.d.ts +20 -0
- package/lib/client.js +33 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +2 -0
- package/lib/onebot12-endpoint-commands.d.ts +1 -1
- package/lib/protocol.d.ts +2 -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/webhook.d.ts +5 -11
- package/lib/webhook.js +34 -50
- package/lib/ws-endpoint.d.ts +5 -12
- package/lib/ws-endpoint.js +30 -30
- package/lib/wss-endpoint.d.ts +8 -11
- package/lib/wss-endpoint.js +58 -66
- package/package.json +14 -11
- package/src/client.ts +81 -0
- package/src/index.ts +16 -0
- package/src/protocol.ts +2 -2
- package/src/side-event-dispatch.ts +4 -4
- package/src/webhook.ts +42 -54
- package/src/ws-endpoint.ts +37 -36
- package/src/wss-endpoint.ts +66 -69
package/lib/ws-endpoint.js
CHANGED
|
@@ -3,27 +3,37 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import WebSocket from 'ws';
|
|
5
5
|
import { clearTimeout } from 'node:timers';
|
|
6
|
-
import { createRecallEndpointControl, createEndpointLifecycle, } from 'zhin.js/adapter';
|
|
6
|
+
import { ClientEndpoint, createRecallEndpointControl, createEndpointLifecycle, } from 'zhin.js/adapter';
|
|
7
7
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
8
8
|
import { createOneBot12EndpointManagement } from './endpoint-management.js';
|
|
9
9
|
import { buildSendMessageParams, buildWsConnectOptions, formatInboundContent, formatOutboundSegments, isBotMentioned, isMessageEvent, onebot12InboundConversation, senderNickname, senderUserId, uploadOneBot12MediaSegments, } from './protocol.js';
|
|
10
10
|
import { receiveOneBot12SideEvent } from './side-event-dispatch.js';
|
|
11
11
|
import { createOneBot12ContentPort } from './content-port.js';
|
|
12
|
+
import { callOnebot12Client, createOnebot12EndpointClient, forwardOnebot12ClientEvents } from './client.js';
|
|
12
13
|
import { WS_OPEN, } from './ws-types.js';
|
|
13
|
-
export class OneBot12WsEndpoint {
|
|
14
|
+
export class OneBot12WsEndpoint extends ClientEndpoint {
|
|
15
|
+
client;
|
|
14
16
|
#logger;
|
|
15
17
|
#options;
|
|
16
|
-
management
|
|
18
|
+
management;
|
|
17
19
|
control = createRecallEndpointControl((id) => this.recallMessage(id));
|
|
18
|
-
content
|
|
20
|
+
content;
|
|
19
21
|
#lifecycle;
|
|
20
22
|
#ws;
|
|
21
23
|
#requestId = 0;
|
|
22
24
|
#pending = new Map();
|
|
23
|
-
#open = false;
|
|
24
25
|
constructor(options) {
|
|
26
|
+
super();
|
|
25
27
|
this.#logger = getAdapterLogger('onebot12', options.config.id);
|
|
26
28
|
this.#options = options;
|
|
29
|
+
this.client = createOnebot12EndpointClient(options.config, (action, params) => this.#callAction(action, params ?? {}));
|
|
30
|
+
const callApi = (action, params) => callOnebot12Client(this.client, action, params);
|
|
31
|
+
this.management = createOneBot12EndpointManagement({ callApi });
|
|
32
|
+
this.content = createOneBot12ContentPort(callApi);
|
|
33
|
+
this.bindClientEvents((receive) => forwardOnebot12ClientEvents(this.client, receive), (name, payload) => {
|
|
34
|
+
if (name === 'event')
|
|
35
|
+
this.#admitRaw(payload);
|
|
36
|
+
}, (_name, error) => this.#warnPlatformEvent(error));
|
|
27
37
|
const { config } = options;
|
|
28
38
|
this.#lifecycle = createEndpointLifecycle({
|
|
29
39
|
name: config.id,
|
|
@@ -57,14 +67,8 @@ export class OneBot12WsEndpoint {
|
|
|
57
67
|
throw err;
|
|
58
68
|
}
|
|
59
69
|
}
|
|
60
|
-
open() {
|
|
61
|
-
this.#open = true;
|
|
62
|
-
}
|
|
63
|
-
close() {
|
|
64
|
-
this.#open = false;
|
|
65
|
-
}
|
|
66
70
|
async stop() {
|
|
67
|
-
this
|
|
71
|
+
this.close();
|
|
68
72
|
// 基座负责:清重连/心跳定时器、强关 ws、唤醒 stop-during-connect 竞态
|
|
69
73
|
await this.#lifecycle.stop();
|
|
70
74
|
for (const [, pending] of this.#pending) {
|
|
@@ -75,7 +79,7 @@ export class OneBot12WsEndpoint {
|
|
|
75
79
|
this.#ws = undefined;
|
|
76
80
|
}
|
|
77
81
|
async send({ conversation, payload }) {
|
|
78
|
-
const materialized = await uploadOneBot12MediaSegments(payload, (action, params) => this.
|
|
82
|
+
const materialized = await uploadOneBot12MediaSegments(payload, (action, params) => callOnebot12Client(this.client, action, params), (error) => {
|
|
79
83
|
this.#logger.warn(formatCompact({
|
|
80
84
|
op: 'onebot12_upload_failed',
|
|
81
85
|
endpoint: this.#options.config.id,
|
|
@@ -84,7 +88,7 @@ export class OneBot12WsEndpoint {
|
|
|
84
88
|
});
|
|
85
89
|
const message = formatOutboundSegments(materialized);
|
|
86
90
|
const params = buildSendMessageParams(conversation, message);
|
|
87
|
-
const data = await this
|
|
91
|
+
const data = await callOnebot12Client(this.client, 'send_message', params);
|
|
88
92
|
const messageId = data?.message_id ?? '';
|
|
89
93
|
this.#logger.debug(formatCompact({
|
|
90
94
|
op: 'onebot12_send',
|
|
@@ -98,25 +102,18 @@ export class OneBot12WsEndpoint {
|
|
|
98
102
|
async recallMessage(messageId) {
|
|
99
103
|
if (!messageId)
|
|
100
104
|
return;
|
|
101
|
-
await this
|
|
102
|
-
}
|
|
103
|
-
/** Public API for management surface / callers. */
|
|
104
|
-
callApi(action, params = {}) {
|
|
105
|
-
return this.#callAction(action, params);
|
|
105
|
+
await callOnebot12Client(this.client, 'delete_message', { message_id: messageId });
|
|
106
106
|
}
|
|
107
|
-
|
|
108
|
-
admit(ev) {
|
|
109
|
-
if (!this.#open)
|
|
110
|
-
return;
|
|
107
|
+
#admitRaw(ev) {
|
|
111
108
|
if (!isMessageEvent(ev)) {
|
|
112
|
-
receiveOneBot12SideEvent(this
|
|
109
|
+
receiveOneBot12SideEvent((name, payload) => this.emit(name, payload), this.#options.config.id, { callApi: (action, params) => callOnebot12Client(this.client, action, params) }, ev, this.#logger);
|
|
113
110
|
return;
|
|
114
111
|
}
|
|
115
112
|
const conversation = onebot12InboundConversation(String(this.#options.id), ev);
|
|
116
113
|
const content = formatInboundContent(ev);
|
|
117
114
|
const nickname = senderNickname(ev);
|
|
118
115
|
const mentioned = isBotMentioned(ev);
|
|
119
|
-
void this
|
|
116
|
+
void this.emit('message.receive', {
|
|
120
117
|
conversation,
|
|
121
118
|
message: { conversation, id: ev.message_id },
|
|
122
119
|
content,
|
|
@@ -141,6 +138,12 @@ export class OneBot12WsEndpoint {
|
|
|
141
138
|
}));
|
|
142
139
|
});
|
|
143
140
|
}
|
|
141
|
+
#warnPlatformEvent(error) {
|
|
142
|
+
this.#logger.warn(formatCompact({
|
|
143
|
+
op: 'onebot12_platform_event_failed',
|
|
144
|
+
error: error instanceof Error ? error.message : String(error),
|
|
145
|
+
}));
|
|
146
|
+
}
|
|
144
147
|
async #connect(handle) {
|
|
145
148
|
const { url, headers, safeUrl } = buildWsConnectOptions(this.#options.config);
|
|
146
149
|
const create = this.#options.createWebSocket
|
|
@@ -220,14 +223,11 @@ export class OneBot12WsEndpoint {
|
|
|
220
223
|
if (pending) {
|
|
221
224
|
this.#pending.delete(resp.echo);
|
|
222
225
|
clearTimeout(pending.timeout);
|
|
223
|
-
|
|
224
|
-
pending.resolve(resp.data);
|
|
225
|
-
else
|
|
226
|
-
pending.reject(new Error(`OneBot12 retcode=${resp.retcode}: ${resp.message}`));
|
|
226
|
+
pending.resolve(resp);
|
|
227
227
|
}
|
|
228
228
|
return;
|
|
229
229
|
}
|
|
230
|
-
this.
|
|
230
|
+
this.client.ingest(msg);
|
|
231
231
|
}
|
|
232
232
|
catch (error) {
|
|
233
233
|
this.#logger.warn(formatCompact({
|
package/lib/wss-endpoint.d.ts
CHANGED
|
@@ -1,28 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* OneBot12 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 OneBot12WssConfig } from './protocol.js';
|
|
8
|
+
import { type Onebot12Client } from './client.js';
|
|
6
9
|
export interface OneBot12WssEndpointOptions {
|
|
7
10
|
readonly id: CapabilityId;
|
|
8
|
-
readonly gateway: MessageGateway;
|
|
9
|
-
readonly sideEvents?: SideEventGateway;
|
|
10
11
|
readonly http: HttpHost;
|
|
11
12
|
readonly config: OneBot12WssConfig;
|
|
12
13
|
}
|
|
13
|
-
export declare class OneBot12WssEndpoint
|
|
14
|
+
export declare class OneBot12WssEndpoint extends ClientEndpoint<Onebot12Client> {
|
|
14
15
|
#private;
|
|
16
|
+
readonly client: Onebot12Client;
|
|
15
17
|
readonly management: EndpointManagement;
|
|
16
18
|
readonly control: EndpointControl;
|
|
17
19
|
readonly content: import("@zhin.js/adapter").EndpointContentPort;
|
|
18
20
|
constructor(options: OneBot12WssEndpointOptions);
|
|
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
|
-
/** Public API for management surface / callers. */
|
|
26
|
-
callApi(action: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
27
|
-
admit(ev: OneBot12Event): void;
|
|
28
25
|
}
|
package/lib/wss-endpoint.js
CHANGED
|
@@ -1,36 +1,46 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* OneBot12 reverse WSS endpoint — accepts inbound WebSocket from OneBot implementation.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
import { createRecallEndpointControl, } from 'zhin.js/adapter';
|
|
4
|
+
import { ClientEndpoint, createEndpointLifecycle, createRecallEndpointControl, } from 'zhin.js/adapter';
|
|
6
5
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
7
6
|
import { createOneBot12EndpointManagement } from './endpoint-management.js';
|
|
8
7
|
import { buildSendMessageParams, formatInboundContent, formatOutboundSegments, isBotMentioned, isMessageEvent, onebot12InboundConversation, senderNickname, senderUserId, uploadOneBot12MediaSegments, } from './protocol.js';
|
|
9
8
|
import { receiveOneBot12SideEvent } from './side-event-dispatch.js';
|
|
10
9
|
import { createOneBot12ContentPort } from './content-port.js';
|
|
10
|
+
import { callOnebot12Client, createOnebot12EndpointClient, forwardOnebot12ClientEvents } from './client.js';
|
|
11
11
|
import { verifyOneBotAccessToken } from './wss-auth.js';
|
|
12
12
|
import { WS_OPEN } from './ws-types.js';
|
|
13
|
-
export class OneBot12WssEndpoint {
|
|
13
|
+
export class OneBot12WssEndpoint 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
|
#ws;
|
|
20
21
|
#wsRelease;
|
|
21
|
-
#
|
|
22
|
+
#lifecycle;
|
|
22
23
|
#requestId = 0;
|
|
23
24
|
#pending = new Map();
|
|
24
|
-
#open = false;
|
|
25
|
-
#started = false;
|
|
26
25
|
constructor(options) {
|
|
26
|
+
super();
|
|
27
27
|
this.#logger = getAdapterLogger('onebot12', options.config.id);
|
|
28
28
|
this.#options = options;
|
|
29
|
+
this.#lifecycle = createEndpointLifecycle({
|
|
30
|
+
name: options.config.id,
|
|
31
|
+
reconnect: false,
|
|
32
|
+
heartbeat: { intervalMs: options.config.heartbeat_interval },
|
|
33
|
+
});
|
|
34
|
+
this.client = createOnebot12EndpointClient(options.config, (action, params) => this.#callAction(action, params ?? {}));
|
|
35
|
+
const callApi = (action, params) => callOnebot12Client(this.client, action, params);
|
|
36
|
+
this.management = createOneBot12EndpointManagement({ callApi });
|
|
37
|
+
this.content = createOneBot12ContentPort(callApi);
|
|
38
|
+
this.bindClientEvents((receive) => forwardOnebot12ClientEvents(this.client, receive), (name, payload) => {
|
|
39
|
+
if (name === 'event')
|
|
40
|
+
this.#admitRaw(payload);
|
|
41
|
+
}, (_name, error) => this.#warnPlatformEvent(error));
|
|
29
42
|
}
|
|
30
43
|
async start() {
|
|
31
|
-
if (this.#started)
|
|
32
|
-
return;
|
|
33
|
-
this.#started = true;
|
|
34
44
|
if (!this.#options.config.access_token) {
|
|
35
45
|
// wss 模式未配 access_token 时任何连接都会被放行(verifyOneBotAccessToken 直接 return true)
|
|
36
46
|
this.#logger.warn(formatCompact({
|
|
@@ -40,9 +50,22 @@ export class OneBot12WssEndpoint {
|
|
|
40
50
|
error: 'missing access_token',
|
|
41
51
|
}));
|
|
42
52
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
this.#
|
|
53
|
+
await this.#lifecycle.start(async (lifecycleHandle) => {
|
|
54
|
+
const handle = this.#options.http.ws(this.#options.config.path);
|
|
55
|
+
this.#wsRelease = handle.onConnection((connection) => {
|
|
56
|
+
this.#acceptConnection(connection);
|
|
57
|
+
});
|
|
58
|
+
lifecycleHandle.onForceClose(() => {
|
|
59
|
+
this.#wsRelease?.();
|
|
60
|
+
this.#wsRelease = undefined;
|
|
61
|
+
try {
|
|
62
|
+
this.#ws?.close();
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
/* ignore */
|
|
66
|
+
}
|
|
67
|
+
this.#ws = undefined;
|
|
68
|
+
});
|
|
46
69
|
});
|
|
47
70
|
this.#logger.info(formatCompact({
|
|
48
71
|
op: 'listen',
|
|
@@ -51,38 +74,17 @@ export class OneBot12WssEndpoint {
|
|
|
51
74
|
path: this.#options.config.path,
|
|
52
75
|
}));
|
|
53
76
|
}
|
|
54
|
-
open() {
|
|
55
|
-
this.#open = true;
|
|
56
|
-
}
|
|
57
|
-
close() {
|
|
58
|
-
this.#open = false;
|
|
59
|
-
}
|
|
60
77
|
async stop() {
|
|
61
|
-
this
|
|
62
|
-
this.#
|
|
63
|
-
this.#wsRelease = undefined;
|
|
64
|
-
if (this.#heartbeatTimer) {
|
|
65
|
-
clearInterval(this.#heartbeatTimer);
|
|
66
|
-
this.#heartbeatTimer = undefined;
|
|
67
|
-
}
|
|
78
|
+
this.close();
|
|
79
|
+
await this.#lifecycle.stop();
|
|
68
80
|
for (const [, pending] of this.#pending) {
|
|
69
81
|
clearTimeout(pending.timeout);
|
|
70
82
|
pending.reject(new Error('连接已关闭'));
|
|
71
83
|
}
|
|
72
84
|
this.#pending.clear();
|
|
73
|
-
if (this.#ws) {
|
|
74
|
-
try {
|
|
75
|
-
this.#ws.close();
|
|
76
|
-
}
|
|
77
|
-
catch {
|
|
78
|
-
/* ignore */
|
|
79
|
-
}
|
|
80
|
-
this.#ws = undefined;
|
|
81
|
-
}
|
|
82
|
-
this.#started = false;
|
|
83
85
|
}
|
|
84
86
|
async send({ conversation, payload }) {
|
|
85
|
-
const materialized = await uploadOneBot12MediaSegments(payload, (action, params) => this.
|
|
87
|
+
const materialized = await uploadOneBot12MediaSegments(payload, (action, params) => callOnebot12Client(this.client, action, params), (error) => {
|
|
86
88
|
this.#logger.warn(formatCompact({
|
|
87
89
|
op: 'onebot12_upload_failed',
|
|
88
90
|
endpoint: this.#options.config.id,
|
|
@@ -91,29 +93,23 @@ export class OneBot12WssEndpoint {
|
|
|
91
93
|
});
|
|
92
94
|
const message = formatOutboundSegments(materialized);
|
|
93
95
|
const params = buildSendMessageParams(conversation, message);
|
|
94
|
-
const data = await this
|
|
96
|
+
const data = await callOnebot12Client(this.client, 'send_message', params);
|
|
95
97
|
return data?.message_id ?? '';
|
|
96
98
|
}
|
|
97
99
|
async recallMessage(messageId) {
|
|
98
100
|
if (!messageId)
|
|
99
101
|
return;
|
|
100
|
-
await this
|
|
102
|
+
await callOnebot12Client(this.client, 'delete_message', { message_id: messageId });
|
|
101
103
|
}
|
|
102
|
-
|
|
103
|
-
callApi(action, params = {}) {
|
|
104
|
-
return this.#callAction(action, params);
|
|
105
|
-
}
|
|
106
|
-
admit(ev) {
|
|
107
|
-
if (!this.#open)
|
|
108
|
-
return;
|
|
104
|
+
#admitRaw(ev) {
|
|
109
105
|
if (!isMessageEvent(ev)) {
|
|
110
|
-
receiveOneBot12SideEvent(this
|
|
106
|
+
receiveOneBot12SideEvent((name, payload) => this.emit(name, payload), this.#options.config.id, { callApi: (action, params) => callOnebot12Client(this.client, action, params) }, ev, this.#logger);
|
|
111
107
|
return;
|
|
112
108
|
}
|
|
113
109
|
const conversation = onebot12InboundConversation(String(this.#options.id), ev);
|
|
114
110
|
const nickname = senderNickname(ev);
|
|
115
111
|
const mentioned = isBotMentioned(ev);
|
|
116
|
-
void this
|
|
112
|
+
void this.emit('message.receive', {
|
|
117
113
|
conversation,
|
|
118
114
|
message: { conversation, id: ev.message_id },
|
|
119
115
|
content: formatInboundContent(ev),
|
|
@@ -138,6 +134,12 @@ export class OneBot12WssEndpoint {
|
|
|
138
134
|
}));
|
|
139
135
|
});
|
|
140
136
|
}
|
|
137
|
+
#warnPlatformEvent(error) {
|
|
138
|
+
this.#logger.warn(formatCompact({
|
|
139
|
+
op: 'onebot12_platform_event_failed',
|
|
140
|
+
error: error instanceof Error ? error.message : String(error),
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
141
143
|
#acceptConnection(connection) {
|
|
142
144
|
if (!verifyOneBotAccessToken(this.#options.config.access_token, connection.request)) {
|
|
143
145
|
connection.socket.close(4003, 'Unauthorized');
|
|
@@ -153,17 +155,17 @@ export class OneBot12WssEndpoint {
|
|
|
153
155
|
}
|
|
154
156
|
}
|
|
155
157
|
this.#ws = socket;
|
|
156
|
-
this.#startHeartbeat()
|
|
158
|
+
this.#lifecycle.startHeartbeat(() => {
|
|
159
|
+
this.#callAction('get_status', {}).catch(() => { });
|
|
160
|
+
});
|
|
157
161
|
socket.on('message', (data) => {
|
|
162
|
+
this.#lifecycle.notifyHeartbeatAck();
|
|
158
163
|
this.#onMessage(data);
|
|
159
164
|
});
|
|
160
165
|
socket.on('close', () => {
|
|
161
166
|
if (this.#ws === socket) {
|
|
162
167
|
this.#ws = undefined;
|
|
163
|
-
|
|
164
|
-
clearInterval(this.#heartbeatTimer);
|
|
165
|
-
this.#heartbeatTimer = undefined;
|
|
166
|
-
}
|
|
168
|
+
this.#lifecycle.stopHeartbeat();
|
|
167
169
|
}
|
|
168
170
|
});
|
|
169
171
|
this.#logger.debug(formatCompact({
|
|
@@ -188,14 +190,11 @@ export class OneBot12WssEndpoint {
|
|
|
188
190
|
if (pending) {
|
|
189
191
|
this.#pending.delete(resp.echo);
|
|
190
192
|
clearTimeout(pending.timeout);
|
|
191
|
-
|
|
192
|
-
pending.resolve(resp.data);
|
|
193
|
-
else
|
|
194
|
-
pending.reject(new Error(`OneBot12 retcode=${resp.retcode}: ${resp.message}`));
|
|
193
|
+
pending.resolve(resp);
|
|
195
194
|
}
|
|
196
195
|
return;
|
|
197
196
|
}
|
|
198
|
-
this.
|
|
197
|
+
this.client.ingest(msg);
|
|
199
198
|
}
|
|
200
199
|
catch (error) {
|
|
201
200
|
this.#logger.warn(formatCompact({
|
|
@@ -220,11 +219,4 @@ export class OneBot12WssEndpoint {
|
|
|
220
219
|
this.#ws.send(JSON.stringify(req));
|
|
221
220
|
});
|
|
222
221
|
}
|
|
223
|
-
#startHeartbeat() {
|
|
224
|
-
if (this.#heartbeatTimer)
|
|
225
|
-
clearInterval(this.#heartbeatTimer);
|
|
226
|
-
this.#heartbeatTimer = setInterval(() => {
|
|
227
|
-
this.#callAction('get_status', {}).catch(() => { });
|
|
228
|
-
}, this.#options.config.heartbeat_interval);
|
|
229
|
-
}
|
|
230
222
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-onebot12",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.2",
|
|
4
4
|
"description": "Zhin.js OneBot 12 adapter for Plugin Runtime (WebSocket client)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -39,26 +39,29 @@
|
|
|
39
39
|
"directory": "plugins/adapters/onebot12"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
+
"@imhelper/onebot-v12": "1.0.7",
|
|
43
|
+
"imhelper": "1.0.7",
|
|
42
44
|
"ws": "^8.21.1",
|
|
43
|
-
"@zhin.js/adapter": "1.2.
|
|
44
|
-
"@zhin.js/core": "1.5.
|
|
45
|
-
"@zhin.js/
|
|
45
|
+
"@zhin.js/adapter": "1.2.1",
|
|
46
|
+
"@zhin.js/core": "1.5.15",
|
|
47
|
+
"@zhin.js/feature-kit": "1.0.13",
|
|
48
|
+
"@zhin.js/host-http": "1.0.14",
|
|
46
49
|
"@zhin.js/im-contract": "1.0.4",
|
|
47
|
-
"@zhin.js/logger": "1.0.
|
|
50
|
+
"@zhin.js/logger": "1.0.77"
|
|
48
51
|
},
|
|
49
52
|
"devDependencies": {
|
|
50
53
|
"@types/node": "^26.1.2",
|
|
51
54
|
"@types/ws": "^8.18.1",
|
|
52
55
|
"typescript": "^6.0.3",
|
|
53
56
|
"vitest": "^4.1.10",
|
|
54
|
-
"@zhin.js/host-http": "1.0.
|
|
55
|
-
"zhin.js": "6.0.
|
|
57
|
+
"@zhin.js/host-http": "1.0.14",
|
|
58
|
+
"zhin.js": "6.0.15"
|
|
56
59
|
},
|
|
57
60
|
"peerDependencies": {
|
|
58
|
-
"@zhin.js/adapter": "1.2.
|
|
59
|
-
"@zhin.js/command": "1.0.
|
|
60
|
-
"@zhin.js/core": "1.5.
|
|
61
|
-
"zhin.js": "6.0.
|
|
61
|
+
"@zhin.js/adapter": "1.2.1",
|
|
62
|
+
"@zhin.js/command": "1.0.16",
|
|
63
|
+
"@zhin.js/core": "1.5.15",
|
|
64
|
+
"zhin.js": "6.0.15"
|
|
62
65
|
},
|
|
63
66
|
"peerDependenciesMeta": {
|
|
64
67
|
"@zhin.js/command": {
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OneBotV12Client,
|
|
3
|
+
type OneBotV12Event as ImHelperOneBot12Event,
|
|
4
|
+
type OneBotV12Response,
|
|
5
|
+
} from '@imhelper/onebot-v12';
|
|
6
|
+
import { EventFactory, type EventMap, type ImHelperEventMap } from 'imhelper';
|
|
7
|
+
import {
|
|
8
|
+
defineEndpointClient,
|
|
9
|
+
forwardEndpointClientEvents,
|
|
10
|
+
type ClientEventPayloads,
|
|
11
|
+
} from 'zhin.js/adapter';
|
|
12
|
+
import type { ResolvedOneBot12Config } from './protocol.js';
|
|
13
|
+
|
|
14
|
+
export { OneBotV12Client as Onebot12Client } from '@imhelper/onebot-v12';
|
|
15
|
+
|
|
16
|
+
export type Onebot12ApiCall = (
|
|
17
|
+
action: string,
|
|
18
|
+
params?: Record<string, unknown>,
|
|
19
|
+
) => Promise<OneBotV12Response>;
|
|
20
|
+
|
|
21
|
+
type Onebot12ClientEvents = ImHelperEventMap<
|
|
22
|
+
string,
|
|
23
|
+
ImHelperOneBot12Event,
|
|
24
|
+
EventMap<string>
|
|
25
|
+
>;
|
|
26
|
+
export type Onebot12ClientEventMap = ClientEventPayloads<Onebot12ClientEvents>;
|
|
27
|
+
|
|
28
|
+
export function createOnebot12EndpointClient(
|
|
29
|
+
config: ResolvedOneBot12Config,
|
|
30
|
+
request: Onebot12ApiCall,
|
|
31
|
+
): OneBotV12Client {
|
|
32
|
+
const baseUrl = config.connection === 'ws'
|
|
33
|
+
? config.url.replace(/^ws(s?):/, 'http$1:')
|
|
34
|
+
: config.connection === 'webhook' && config.api_url
|
|
35
|
+
? config.api_url
|
|
36
|
+
: 'http://localhost';
|
|
37
|
+
return new OneBotV12Client({
|
|
38
|
+
baseUrl,
|
|
39
|
+
selfId: config.id,
|
|
40
|
+
accessToken: config.access_token,
|
|
41
|
+
receiveMode: 'manual',
|
|
42
|
+
call: request,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function callOnebot12Client<T = unknown>(
|
|
47
|
+
client: OneBotV12Client,
|
|
48
|
+
action: string,
|
|
49
|
+
params?: Record<string, unknown>,
|
|
50
|
+
): Promise<T | undefined> {
|
|
51
|
+
const response: OneBotV12Response<T> = await client.call<T>(action, params);
|
|
52
|
+
if (response.status !== 'ok') {
|
|
53
|
+
throw new Error(
|
|
54
|
+
`OneBot 12 API ${action}: retcode=${response.retcode}${response.message ? ` ${response.message}` : ''}`,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return response.data;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const onebot12ClientEventNames = Object.freeze([
|
|
61
|
+
...EventFactory.getSupportedEventTypes<string>(),
|
|
62
|
+
'event',
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
export function forwardOnebot12ClientEvents(
|
|
66
|
+
client: OneBotV12Client,
|
|
67
|
+
receive: (name: string, payload: unknown) => void,
|
|
68
|
+
): () => void {
|
|
69
|
+
return forwardEndpointClientEvents(client, onebot12ClientEventNames, receive);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
declare module '@zhin.js/feature-kit' {
|
|
73
|
+
interface AdapterClientRegistry {
|
|
74
|
+
readonly onebot12: {
|
|
75
|
+
readonly client: OneBotV12Client;
|
|
76
|
+
readonly events: Onebot12ClientEventMap;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const onebot12Client = defineEndpointClient<OneBotV12Client, Onebot12ClientEventMap>('onebot12');
|
package/src/index.ts
CHANGED
|
@@ -49,3 +49,19 @@ export {
|
|
|
49
49
|
export type { OneBot12WsSocket, OneBot12WsCreateOptions } from './ws-types.js';
|
|
50
50
|
|
|
51
51
|
export { verifyOneBotAccessToken } from './wss-auth.js';
|
|
52
|
+
export {
|
|
53
|
+
Onebot12Client,
|
|
54
|
+
onebot12Client,
|
|
55
|
+
type Onebot12ClientEventMap,
|
|
56
|
+
} from './client.js';
|
|
57
|
+
|
|
58
|
+
export type {
|
|
59
|
+
OneBotV12ActionUrlResolver,
|
|
60
|
+
OneBotV12AdapterConfig as ImHelperOneBotV12AdapterConfig,
|
|
61
|
+
OneBotV12Call,
|
|
62
|
+
OneBotV12ClientConfig,
|
|
63
|
+
OneBotV12Event as ImHelperOneBotV12Event,
|
|
64
|
+
OneBotV12Response,
|
|
65
|
+
} from '@imhelper/onebot-v12';
|
|
66
|
+
export { ProtocolError } from '@imhelper/onebot-v12';
|
|
67
|
+
export type { ProtocolErrorKind, ProtocolErrorOptions } from 'imhelper';
|
package/src/protocol.ts
CHANGED
|
@@ -78,7 +78,7 @@ export interface OneBot12Event {
|
|
|
78
78
|
type: 'meta' | 'message' | 'notice' | 'request';
|
|
79
79
|
detail_type: string;
|
|
80
80
|
sub_type: string;
|
|
81
|
-
self
|
|
81
|
+
self: OneBot12Self;
|
|
82
82
|
message_id?: string;
|
|
83
83
|
message?: OneBot12Segment[];
|
|
84
84
|
alt_message?: string;
|
|
@@ -226,7 +226,7 @@ export function onebot12InboundConversation(endpointKey: string, ev: OneBot12Eve
|
|
|
226
226
|
};
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
-
/** Build inbound text for
|
|
229
|
+
/** Build inbound text for OutboundMessageService.receive */
|
|
230
230
|
export function formatInboundContent(ev: OneBot12Event): string {
|
|
231
231
|
if (Array.isArray(ev.message)) {
|
|
232
232
|
return ev.message
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { receiveOneBotLikeSideEvent } from '@zhin.js/core';
|
|
2
|
-
import type {
|
|
2
|
+
import type { EndpointEventEmitter } from 'zhin.js/adapter';
|
|
3
3
|
import { formatCompact, type getAdapterLogger } from '@zhin.js/logger';
|
|
4
4
|
import type { OneBot12Event } from './protocol.js';
|
|
5
5
|
|
|
@@ -8,19 +8,19 @@ export interface OneBot12SideEventCaller {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export function receiveOneBot12SideEvent(
|
|
11
|
-
|
|
11
|
+
emit: EndpointEventEmitter,
|
|
12
12
|
endpointKey: string,
|
|
13
13
|
caller: OneBot12SideEventCaller,
|
|
14
14
|
raw: OneBot12Event,
|
|
15
15
|
logger: ReturnType<typeof getAdapterLogger>,
|
|
16
16
|
): void {
|
|
17
|
-
if (!
|
|
17
|
+
if (!emit) return;
|
|
18
18
|
const record = raw as Record<string, unknown>;
|
|
19
19
|
const eventType = String(record.type ?? record.post_type ?? '');
|
|
20
20
|
const detailType = String(record.detail_type ?? '');
|
|
21
21
|
const isRequest = eventType === 'request' || eventType.startsWith('request.');
|
|
22
22
|
const isFriend = detailType.includes('friend') || String(record.request_type ?? '') === 'friend';
|
|
23
|
-
void receiveOneBotLikeSideEvent(
|
|
23
|
+
void receiveOneBotLikeSideEvent(emit, {
|
|
24
24
|
adapter: 'onebot12',
|
|
25
25
|
endpointKey,
|
|
26
26
|
platform: 'onebot',
|