@zhin.js/adapter-onebot12 1.1.18 → 1.1.20
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 +43 -0
- package/README.md +24 -5
- package/adapters/onebot12/index.js +3 -32
- package/adapters/onebot12/index.ts +2 -38
- package/commands/onebot12/endpoint/definition.js +2 -2
- package/commands/onebot12/endpoint/definition.ts +2 -2
- package/lib/adapter.d.ts +21 -0
- package/lib/adapter.js +34 -0
- package/lib/client.d.ts +9 -11
- package/lib/client.js +23 -13
- package/lib/console-spec.js +2 -0
- package/lib/console.d.ts +1 -1
- package/lib/console.js +2 -5
- package/lib/content-port.d.ts +2 -2
- package/lib/content-port.js +1 -1
- package/lib/endpoint-management.d.ts +5 -5
- package/lib/endpoint-management.js +17 -17
- package/lib/identity.d.ts +4 -0
- package/lib/identity.js +53 -0
- package/lib/index.d.ts +3 -2
- package/lib/index.js +2 -1
- package/lib/protocol.d.ts +32 -4
- package/lib/protocol.js +54 -53
- package/lib/response.d.ts +5 -0
- package/lib/response.js +17 -0
- package/lib/side-event-dispatch.d.ts +8 -1
- package/lib/side-event-dispatch.js +2 -1
- package/lib/webhook.d.ts +5 -11
- package/lib/webhook.js +72 -37
- package/lib/ws-endpoint.d.ts +5 -11
- package/lib/ws-endpoint.js +79 -45
- package/lib/ws-transport.d.ts +18 -10
- package/lib/ws-transport.js +26 -45
- package/lib/ws-types.d.ts +0 -6
- package/lib/wss-endpoint.d.ts +5 -11
- package/lib/wss-endpoint.js +82 -48
- package/package.json +15 -15
- package/plugin.js +0 -4
- package/schema.json +15 -3
- package/src/adapter.ts +36 -0
- package/src/client.ts +26 -29
- package/src/console-spec.ts +2 -0
- package/src/console.ts +2 -5
- package/src/content-port.ts +3 -3
- package/src/endpoint-management.ts +25 -24
- package/src/identity.ts +52 -0
- package/src/index.ts +4 -1
- package/src/protocol.ts +71 -62
- package/src/response.ts +19 -0
- package/src/side-event-dispatch.ts +9 -7
- package/src/webhook.ts +70 -55
- package/src/ws-endpoint.ts +75 -63
- package/src/ws-transport.ts +37 -73
- package/src/ws-types.ts +0 -7
- package/src/wss-endpoint.ts +80 -66
- package/lib/onebot12-runtime-state.d.ts +0 -1
- package/lib/onebot12-runtime-state.js +0 -6
- package/src/onebot12-runtime-state.ts +0 -7
package/src/wss-endpoint.ts
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
* OneBot12 reverse WSS endpoint — accepts inbound WebSocket from OneBot implementation.
|
|
3
3
|
*/
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
createEndpointSpecification, endpointSpec,
|
|
6
|
+
type Endpoint, type EndpointSpecification,
|
|
6
7
|
createEndpointLifecycle,
|
|
7
8
|
createRecallEndpointControl,
|
|
8
9
|
type EndpointLifecycle,
|
|
9
10
|
type EndpointControl,
|
|
10
11
|
type EndpointManagement,
|
|
11
12
|
type EndpointSendRequest,
|
|
13
|
+
type PendingRpcRequest,
|
|
12
14
|
} from 'zhin.js/adapter';
|
|
13
15
|
import type { HttpHost, WsConnection } from '@zhin.js/host-http';
|
|
14
16
|
import { formatCompact, getAdapterLogger } from '@zhin.js/logger';
|
|
@@ -16,6 +18,7 @@ import type { CapabilityId } from 'zhin.js';
|
|
|
16
18
|
import { createOneBot12EndpointManagement } from './endpoint-management.js';
|
|
17
19
|
import {
|
|
18
20
|
buildSendMessageParams,
|
|
21
|
+
matchesOneBot12Self,
|
|
19
22
|
formatInboundContent,
|
|
20
23
|
formatOutboundSegments,
|
|
21
24
|
isBotMentioned,
|
|
@@ -29,59 +32,70 @@ import {
|
|
|
29
32
|
} from './protocol.js';
|
|
30
33
|
import { receiveOneBot12SideEvent } from './side-event-dispatch.js';
|
|
31
34
|
import { createOneBot12ContentPort } from './content-port.js';
|
|
32
|
-
import { callOnebot12Client,
|
|
35
|
+
import { callOnebot12Client, readOnebot12Response, onebot12ClientOptions, forwardOnebot12ClientEvents, Onebot12Client } from './client.js';
|
|
33
36
|
import { verifyOneBotAccessToken } from './wss-auth.js';
|
|
34
|
-
import { type
|
|
35
|
-
import {
|
|
36
|
-
callOneBot12WsAction,
|
|
37
|
-
handleOneBot12WsMessage,
|
|
38
|
-
rejectAllPending,
|
|
39
|
-
} from './ws-transport.js';
|
|
37
|
+
import { type OneBot12WsSocket } from './ws-types.js';
|
|
38
|
+
import { createOneBot12Rpc, type OneBot12Rpc } from './ws-transport.js';
|
|
40
39
|
|
|
41
40
|
export interface OneBot12WssEndpointOptions {
|
|
41
|
+
readonly signal?: AbortSignal;
|
|
42
42
|
readonly id: CapabilityId;
|
|
43
43
|
readonly http: HttpHost;
|
|
44
44
|
readonly config: OneBot12WssConfig;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
export class OneBot12WssEndpoint extends
|
|
48
|
-
readonly
|
|
47
|
+
export class OneBot12WssEndpoint extends Onebot12Client implements Endpoint {
|
|
48
|
+
readonly [endpointSpec]: EndpointSpecification;
|
|
49
|
+
#open = false;
|
|
49
50
|
readonly #logger!: ReturnType<typeof getAdapterLogger>;
|
|
50
51
|
|
|
51
52
|
readonly #options: OneBot12WssEndpointOptions;
|
|
52
|
-
readonly management: EndpointManagement;
|
|
53
|
-
readonly control: EndpointControl = createRecallEndpointControl((id) => this
|
|
54
|
-
readonly content;
|
|
53
|
+
readonly #management: EndpointManagement;
|
|
54
|
+
readonly #control: EndpointControl = createRecallEndpointControl((id, signal?: AbortSignal) => this.#recallMessage(id, signal));
|
|
55
|
+
readonly #content;
|
|
56
|
+
readonly #releaseClientEvents: () => void;
|
|
55
57
|
#ws?: OneBot12WsSocket;
|
|
56
58
|
#wsRelease?: () => void;
|
|
57
59
|
readonly #connectionLifecycle: EndpointLifecycle;
|
|
58
60
|
#connectionTask = Promise.resolve();
|
|
59
|
-
#
|
|
60
|
-
#pending = new Map<string, OneBot12PendingAction>();
|
|
61
|
+
readonly #rpc: OneBot12Rpc;
|
|
61
62
|
#started = false;
|
|
62
63
|
|
|
63
64
|
constructor(options: OneBot12WssEndpointOptions) {
|
|
64
|
-
|
|
65
|
+
const rpc = createOneBot12Rpc({ endpointId: options.config.id, signal: options.signal,
|
|
66
|
+
self: { platform: options.config.platform, user_id: options.config.userId },
|
|
67
|
+
socket: () => this.#connectionLifecycle.state === 'closed' ? undefined : this.#ws,
|
|
68
|
+
});
|
|
69
|
+
super(onebot12ClientOptions(options.config, (action, params) => rpc.call({ action, params })));
|
|
70
|
+
this.#rpc = rpc;
|
|
65
71
|
this.#logger = getAdapterLogger('onebot12', options.config.id);
|
|
66
72
|
this.#options = options;
|
|
67
73
|
this.#connectionLifecycle = createEndpointLifecycle({
|
|
68
74
|
name: `${options.config.id}:inbound`,
|
|
69
75
|
reconnect: false,
|
|
70
76
|
});
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
this
|
|
74
|
-
|
|
75
|
-
this
|
|
76
|
-
|
|
77
|
-
(
|
|
77
|
+
const callApi = (request: PendingRpcRequest) => this.#rpc.call(request).then(readOnebot12Response);
|
|
78
|
+
this.#management = createOneBot12EndpointManagement({ callApi });
|
|
79
|
+
this.#content = createOneBot12ContentPort(callApi);
|
|
80
|
+
const readTransportState = () => this.#connectionLifecycle.state;
|
|
81
|
+
this[endpointSpec] = createEndpointSpecification(this, {
|
|
82
|
+
name: options.config.id,
|
|
83
|
+
start: () => this.#start(), open: () => { this.#open = true; },
|
|
84
|
+
close: () => { this.#open = false; }, stop: () => this.#stop(),
|
|
85
|
+
send: request => this.#send(request),
|
|
86
|
+
get transportState() { return readTransportState(); },
|
|
87
|
+
management: this.#management, control: this.#control, content: this.#content,
|
|
88
|
+
});
|
|
89
|
+
this.#releaseClientEvents = forwardOnebot12ClientEvents(this, (name, payload) => {
|
|
90
|
+
void this[endpointSpec].events.run(() => {
|
|
91
|
+
if (!this.#open && !this.#started) return;
|
|
92
|
+
void this[endpointSpec].events.platform(name, payload).catch(error => this.#warnPlatformEvent(error));
|
|
78
93
|
if (name === 'event') this.#admitRaw(payload as OneBot12Event);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
);
|
|
94
|
+
}).catch(error => this.#warnPlatformEvent(error));
|
|
95
|
+
});
|
|
82
96
|
}
|
|
83
97
|
|
|
84
|
-
async start(): Promise<void> {
|
|
98
|
+
async #start(): Promise<void> {
|
|
85
99
|
if (this.#started) return;
|
|
86
100
|
if (!this.#options.config.access_token) {
|
|
87
101
|
// wss 模式未配 access_token 时任何连接都会被放行(verifyOneBotAccessToken 直接 return true)
|
|
@@ -113,55 +127,59 @@ export class OneBot12WssEndpoint extends ClientEndpoint<Onebot12Client> {
|
|
|
113
127
|
}));
|
|
114
128
|
}
|
|
115
129
|
|
|
116
|
-
async stop(): Promise<void> {
|
|
117
|
-
this
|
|
130
|
+
async #stop(): Promise<void> {
|
|
131
|
+
this.#open = false;
|
|
118
132
|
this.#wsRelease?.();
|
|
119
133
|
this.#wsRelease = undefined;
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
134
|
+
try {
|
|
135
|
+
await this.#connectionTask;
|
|
136
|
+
await this.#connectionLifecycle.stop();
|
|
137
|
+
} finally {
|
|
138
|
+
this.#rpc.dispose();
|
|
139
|
+
this.#releaseClientEvents();
|
|
140
|
+
this.#ws = undefined;
|
|
141
|
+
this.#started = false;
|
|
142
|
+
}
|
|
125
143
|
}
|
|
126
144
|
|
|
127
|
-
async send({ conversation, payload }: EndpointSendRequest): Promise<string> {
|
|
128
|
-
const materialized = await uploadOneBot12MediaSegments(
|
|
129
|
-
payload,
|
|
130
|
-
(action, params) =>
|
|
131
|
-
|
|
132
|
-
this.#logger.warn(formatCompact({
|
|
133
|
-
|
|
134
|
-
endpoint: this.#options.config.id,
|
|
135
|
-
error: error instanceof Error ? error.message : String(error),
|
|
136
|
-
}));
|
|
145
|
+
async #send({ conversation, payload, signal }: EndpointSendRequest): Promise<string> {
|
|
146
|
+
const materialized = await uploadOneBot12MediaSegments({
|
|
147
|
+
payload, signal,
|
|
148
|
+
callAction: (action, params) => this.#rpc.call({ action, params, signal }).then(readOnebot12Response),
|
|
149
|
+
onUploadFailed: error => {
|
|
150
|
+
this.#logger.warn(formatCompact({ op: 'onebot12_upload_failed', endpoint: this.#options.config.id,
|
|
151
|
+
error: error instanceof Error ? error.message : String(error) }));
|
|
137
152
|
},
|
|
138
|
-
);
|
|
153
|
+
});
|
|
139
154
|
const message = formatOutboundSegments(materialized);
|
|
140
155
|
const params = buildSendMessageParams(conversation, message);
|
|
141
|
-
const data =
|
|
156
|
+
const data = readOnebot12Response<{ message_id?: string }>(await this.#rpc.call({ action: 'send_message', params, signal }));
|
|
142
157
|
return data?.message_id ?? '';
|
|
143
158
|
}
|
|
144
159
|
|
|
145
|
-
async recallMessage(messageId: string): Promise<void> {
|
|
160
|
+
async #recallMessage(messageId: string, signal?: AbortSignal): Promise<void> {
|
|
146
161
|
if (!messageId) return;
|
|
147
|
-
await
|
|
162
|
+
await this.#rpc.call({ action: 'delete_message', params: { message_id: messageId }, signal }).then(readOnebot12Response);
|
|
148
163
|
}
|
|
149
164
|
|
|
150
165
|
#admitRaw(ev: OneBot12Event): void {
|
|
166
|
+
if (!matchesOneBot12Self(this.#options.config, ev)) return;
|
|
167
|
+
this[endpointSpec].reportSelfUserId(ev.self.user_id);
|
|
151
168
|
if (!isMessageEvent(ev)) {
|
|
152
|
-
receiveOneBot12SideEvent(
|
|
153
|
-
(name, payload) => this.emit(name, payload),
|
|
154
|
-
this.#options.config.id,
|
|
155
|
-
{ callApi: (action, params) => callOnebot12Client(this
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
);
|
|
169
|
+
receiveOneBot12SideEvent(ev, {
|
|
170
|
+
emit: (name, payload) => this[endpointSpec].events.emit(name, payload),
|
|
171
|
+
endpointKey: this.#options.config.id,
|
|
172
|
+
caller: { callApi: (action, params) => callOnebot12Client({ client: this, action, params }) },
|
|
173
|
+
logger: this.#logger,
|
|
174
|
+
});
|
|
159
175
|
return;
|
|
160
176
|
}
|
|
161
|
-
const conversation = onebot12InboundConversation(String(this.#options.id), ev);
|
|
177
|
+
const conversation = { ...onebot12InboundConversation(String(this.#options.id), ev), endpoint: this[endpointSpec].identity };
|
|
162
178
|
const nickname = senderNickname(ev);
|
|
163
179
|
const mentioned = isBotMentioned(ev);
|
|
164
|
-
void this.
|
|
180
|
+
void this[endpointSpec].events.message({
|
|
181
|
+
event: ev,
|
|
182
|
+
...(typeof ev.time === 'number' ? { platformSentAt: ev.time * 1000 } : {}),
|
|
165
183
|
conversation,
|
|
166
184
|
message: { conversation, id: ev.message_id },
|
|
167
185
|
content: formatInboundContent(ev),
|
|
@@ -201,7 +219,7 @@ export class OneBot12WssEndpoint extends ClientEndpoint<Onebot12Client> {
|
|
|
201
219
|
}
|
|
202
220
|
const socket = connection.socket as unknown as OneBot12WsSocket;
|
|
203
221
|
await this.#connectionLifecycle.stop();
|
|
204
|
-
|
|
222
|
+
this.#rpc.disconnect('连接已替换');
|
|
205
223
|
await this.#connectionLifecycle.start(async (lifecycleHandle) => {
|
|
206
224
|
this.#ws = socket;
|
|
207
225
|
lifecycleHandle.onForceClose(() => {
|
|
@@ -218,18 +236,14 @@ export class OneBot12WssEndpoint extends ClientEndpoint<Onebot12Client> {
|
|
|
218
236
|
socket.on('message', (data) => {
|
|
219
237
|
if (this.#ws !== socket) return;
|
|
220
238
|
this.#connectionLifecycle.notifyHeartbeatAck();
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
pending: this.#pending,
|
|
224
|
-
ingest: (event) => this.client.ingest(
|
|
225
|
-
event as Parameters<Onebot12Client['ingest']>[0],
|
|
226
|
-
),
|
|
239
|
+
this.#rpc.receive(data, event => {
|
|
240
|
+
if (matchesOneBot12Self(this.#options.config, event)) this.ingest(event as Parameters<Onebot12Client['ingest']>[0]);
|
|
227
241
|
});
|
|
228
242
|
});
|
|
229
243
|
socket.on('close', () => {
|
|
230
244
|
if (this.#ws === socket) {
|
|
231
245
|
this.#ws = undefined;
|
|
232
|
-
|
|
246
|
+
this.#rpc.disconnect();
|
|
233
247
|
}
|
|
234
248
|
lifecycleHandle.notifyClosed(new Error('OneBot12 reverse WebSocket closed'));
|
|
235
249
|
});
|
|
@@ -242,7 +256,7 @@ export class OneBot12WssEndpoint extends ClientEndpoint<Onebot12Client> {
|
|
|
242
256
|
}
|
|
243
257
|
|
|
244
258
|
#callAction(action: string, params: Record<string, unknown>) {
|
|
245
|
-
return
|
|
259
|
+
return this.#rpc.call({ action, params });
|
|
246
260
|
}
|
|
247
261
|
|
|
248
262
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const onebot12RuntimeStateToken: import("zhin.js").Token<import("@zhin.js/adapter").EndpointRuntimeState>;
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OneBot12 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
|
|
3
|
-
* 由 plugin.ts setup() provide,adapter create 与 `onebot12 endpoint` 命令共享(同一 owner generation)。
|
|
4
|
-
*/
|
|
5
|
-
import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
|
|
6
|
-
export const onebot12RuntimeStateToken = defineEndpointRuntimeStateToken('onebot12');
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OneBot12 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
|
|
3
|
-
* 由 plugin.ts setup() provide,adapter create 与 `onebot12 endpoint` 命令共享(同一 owner generation)。
|
|
4
|
-
*/
|
|
5
|
-
import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
|
|
6
|
-
|
|
7
|
-
export const onebot12RuntimeStateToken = defineEndpointRuntimeStateToken('onebot12');
|