@zhin.js/adapter-onebot12 0.0.0

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.
@@ -0,0 +1,130 @@
1
+ /**
2
+ * OneBot 12 HTTP Webhook Bot:OneBot 实现 POST 事件到应用 path,可选 api_url 用于发消息
3
+ */
4
+ import { EventEmitter } from 'events';
5
+ import { Bot, Message, SendOptions, segment } from 'zhin.js';
6
+ import type { Router, RouterContext } from '@zhin.js/http';
7
+ import { callOneBot12Action } from './api.js';
8
+ import type { OneBot12WebhookConfig, OneBot12Event } from './types.js';
9
+ import type { OneBot12Adapter } from './adapter.js';
10
+ import { formatOneBot12MessagePayload, isMessageEvent, contentToOb12Segments } from './utils.js';
11
+
12
+ export class OneBot12WebhookBot extends EventEmitter implements Bot<OneBot12WebhookConfig, OneBot12Event> {
13
+ $connected: boolean = true;
14
+
15
+ get logger() {
16
+ return this.adapter.plugin.logger;
17
+ }
18
+
19
+ constructor(
20
+ public adapter: OneBot12Adapter,
21
+ public router: Router,
22
+ public $config: OneBot12WebhookConfig,
23
+ ) {
24
+ super();
25
+ }
26
+
27
+ get $id() {
28
+ return this.$config.name;
29
+ }
30
+
31
+ private httpOptions() {
32
+ const url = this.$config.api_url?.replace(/\/$/, '') ?? '';
33
+ return { url: url || '', access_token: this.$config.access_token };
34
+ }
35
+
36
+ async $connect(): Promise<void> {
37
+ const path = this.$config.path.startsWith('/') ? this.$config.path : `/${this.$config.path}`;
38
+ this.router.post(path, async (ctx: RouterContext) => {
39
+ const body = ctx.request.body as OneBot12Event | undefined;
40
+ if (!body || typeof body !== 'object' || !body.id || body.time == null || !body.type) {
41
+ ctx.status = 400;
42
+ ctx.body = { message: 'Invalid OneBot12 event' };
43
+ return;
44
+ }
45
+ const token = this.$config.access_token;
46
+ const auth = ctx.headers['authorization'];
47
+ if (token && auth !== `Bearer ${token}`) {
48
+ ctx.status = 401;
49
+ ctx.body = { message: 'Unauthorized' };
50
+ return;
51
+ }
52
+ this.handleEvent(body);
53
+ ctx.status = 204;
54
+ ctx.body = undefined;
55
+ });
56
+ this.logger.info(`OneBot12 Webhook 注册路径: ${path}`);
57
+ }
58
+
59
+ async $disconnect(): Promise<void> {
60
+ this.$connected = false;
61
+ }
62
+
63
+ private handleEvent(ev: OneBot12Event): void {
64
+ if (ev.type === 'message' && isMessageEvent(ev)) {
65
+ const message = this.$formatMessage(ev);
66
+ this.adapter.emit('message.receive', message);
67
+ this.logger.debug(`${this.$config.name} recv ${message.$channel.type}(${message.$channel.id}):${segment.raw(message.$content)}`);
68
+ }
69
+ }
70
+
71
+ $formatMessage(ev: OneBot12Event): Message<OneBot12Event> {
72
+ if (!isMessageEvent(ev)) {
73
+ return Message.from(ev, {
74
+ $id: '',
75
+ $adapter: 'onebot12',
76
+ $bot: this.$config.name,
77
+ $channel: { id: '', type: 'private' },
78
+ $sender: { id: '', name: '' },
79
+ $content: [],
80
+ $raw: '',
81
+ $timestamp: ev.time ?? 0,
82
+ $recall: async () => {},
83
+ $reply: async () => '',
84
+ });
85
+ }
86
+ const payload = formatOneBot12MessagePayload(
87
+ ev,
88
+ this.$config.name,
89
+ (id) => this.$recallMessage(id),
90
+ (channel, content, _quote) =>
91
+ this.adapter.sendMessage({
92
+ ...channel,
93
+ context: 'onebot12',
94
+ bot: this.$config.name,
95
+ content: content as import('zhin.js').SendContent,
96
+ }),
97
+ );
98
+ return Message.from(ev, payload);
99
+ }
100
+
101
+ async $sendMessage(options: SendOptions): Promise<string> {
102
+ const apiUrl = this.$config.api_url;
103
+ if (!apiUrl) {
104
+ throw new Error('OneBot12 Webhook 发消息需要配置 api_url(OneBot 实现的 HTTP 端点)');
105
+ }
106
+ const message = contentToOb12Segments(options.content);
107
+ const params: Record<string, unknown> = { message };
108
+ if (options.type === 'private') {
109
+ params.detail_type = 'private';
110
+ params.user_id = options.id;
111
+ } else if (options.type === 'group') {
112
+ params.detail_type = 'group';
113
+ params.group_id = options.id;
114
+ } else {
115
+ const [guildId, channelId] = options.id.includes(':') ? options.id.split(':') : [undefined, options.id];
116
+ params.detail_type = 'channel';
117
+ params.channel_id = channelId ?? options.id;
118
+ if (guildId) params.guild_id = guildId;
119
+ }
120
+ const data = await callOneBot12Action(this.httpOptions(), 'send_message', params);
121
+ const out = (data as { message_id?: string })?.message_id ?? '';
122
+ return out;
123
+ }
124
+
125
+ async $recallMessage(id: string): Promise<void> {
126
+ const apiUrl = this.$config.api_url;
127
+ if (!apiUrl) throw new Error('OneBot12 Webhook 撤回需要配置 api_url');
128
+ await callOneBot12Action(this.httpOptions(), 'delete_message', { message_id: id });
129
+ }
130
+ }
package/src/bot-ws.ts ADDED
@@ -0,0 +1,191 @@
1
+ /**
2
+ * OneBot 12 正向 WebSocket Bot:应用连 OneBot 实现的 WS,收事件、发动作
3
+ */
4
+ import WebSocket from 'ws';
5
+ import { EventEmitter } from 'events';
6
+ import { clearInterval, clearTimeout } from 'node:timers';
7
+ import { Bot, Message, SendOptions, segment } from 'zhin.js';
8
+ import type { OneBot12WsConfig, OneBot12Event, OneBot12ActionRequest, OneBot12ActionResponse } from './types.js';
9
+ import type { OneBot12Adapter } from './adapter.js';
10
+ import { formatOneBot12MessagePayload, isMessageEvent, contentToOb12Segments } from './utils.js';
11
+
12
+ export class OneBot12WsClient extends EventEmitter implements Bot<OneBot12WsConfig, OneBot12Event> {
13
+ $connected: boolean;
14
+ private ws?: WebSocket;
15
+ private reconnectTimer?: NodeJS.Timeout;
16
+ private heartbeatTimer?: NodeJS.Timeout;
17
+ private requestId = 0;
18
+ private pendingRequests = new Map<string, { resolve: (value: unknown) => void; reject: (err: Error) => void; timeout: NodeJS.Timeout }>();
19
+
20
+ get logger() {
21
+ return this.adapter.plugin.logger;
22
+ }
23
+
24
+ constructor(public adapter: OneBot12Adapter, public $config: OneBot12WsConfig) {
25
+ super();
26
+ this.$connected = false;
27
+ }
28
+
29
+ get $id() {
30
+ return this.$config.name;
31
+ }
32
+
33
+ private startHeartbeat(): void {
34
+ const interval = this.$config.heartbeat_interval ?? 30000;
35
+ this.heartbeatTimer = setInterval(() => {
36
+ this.callAction('get_status', {}).catch(() => {});
37
+ }, interval);
38
+ }
39
+
40
+ private scheduleReconnect(): void {
41
+ if (this.reconnectTimer) return;
42
+ const delay = this.$config.reconnect_interval ?? 5000;
43
+ this.reconnectTimer = setTimeout(() => {
44
+ this.reconnectTimer = undefined;
45
+ this.$connect().catch((err) => this.logger.warn('OneBot12 重连失败', err));
46
+ }, delay);
47
+ }
48
+
49
+ private callAction(action: string, params: Record<string, unknown>): Promise<OneBot12ActionResponse['data']> {
50
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
51
+ return Promise.reject(new Error('WebSocket 未连接'));
52
+ }
53
+ const echo = `ob12_${++this.requestId}`;
54
+ const req: OneBot12ActionRequest = { action, params, echo };
55
+ return new Promise((resolve, reject) => {
56
+ const timeout = setTimeout(() => {
57
+ this.pendingRequests.delete(echo);
58
+ reject(new Error(`OneBot12 动作超时: ${action}`));
59
+ }, 30000);
60
+ this.pendingRequests.set(echo, {
61
+ resolve: (data: unknown) => resolve(data as OneBot12ActionResponse['data']),
62
+ reject,
63
+ timeout,
64
+ });
65
+ this.ws!.send(JSON.stringify(req));
66
+ });
67
+ }
68
+
69
+ async $connect(): Promise<void> {
70
+ return new Promise((resolve, reject) => {
71
+ const headers: Record<string, string> = {};
72
+ if (this.$config.access_token) headers['Authorization'] = `Bearer ${this.$config.access_token}`;
73
+ this.ws = new WebSocket(this.$config.url, { headers });
74
+
75
+ this.ws.on('open', () => {
76
+ this.$connected = true;
77
+ this.startHeartbeat();
78
+ resolve();
79
+ });
80
+
81
+ this.ws.on('message', (data) => {
82
+ try {
83
+ const msg = JSON.parse(data.toString()) as OneBot12Event | OneBot12ActionResponse;
84
+ if ('echo' in msg && typeof (msg as OneBot12ActionResponse).echo === 'string') {
85
+ const resp = msg as OneBot12ActionResponse;
86
+ const pending = this.pendingRequests.get(resp.echo!);
87
+ if (pending) {
88
+ this.pendingRequests.delete(resp.echo!);
89
+ clearTimeout(pending.timeout);
90
+ if (resp.status === 'ok') pending.resolve(resp.data);
91
+ else pending.reject(new Error(`OneBot12 retcode=${resp.retcode}: ${resp.message}`));
92
+ }
93
+ return;
94
+ }
95
+ const ev = msg as OneBot12Event;
96
+ if (ev.type === 'message' && isMessageEvent(ev)) {
97
+ const message = this.$formatMessage(ev);
98
+ this.adapter.emit('message.receive', message);
99
+ this.logger.debug(`${this.$config.name} recv ${message.$channel.type}(${message.$channel.id}):${segment.raw(message.$content)}`);
100
+ }
101
+ } catch (error) {
102
+ this.emit('error', error);
103
+ }
104
+ });
105
+
106
+ this.ws.on('close', (code, reason) => {
107
+ this.$connected = false;
108
+ reject(new Error(`OneBot12 WS 关闭: ${code} ${reason.toString()}`));
109
+ this.scheduleReconnect();
110
+ });
111
+
112
+ this.ws.on('error', (err) => reject(err));
113
+ });
114
+ }
115
+
116
+ async $disconnect(): Promise<void> {
117
+ if (this.reconnectTimer) {
118
+ clearTimeout(this.reconnectTimer);
119
+ this.reconnectTimer = undefined;
120
+ }
121
+ if (this.heartbeatTimer) {
122
+ clearInterval(this.heartbeatTimer);
123
+ this.heartbeatTimer = undefined;
124
+ }
125
+ for (const [, p] of this.pendingRequests) {
126
+ clearTimeout(p.timeout);
127
+ p.reject(new Error('连接已关闭'));
128
+ }
129
+ this.pendingRequests.clear();
130
+ if (this.ws) {
131
+ this.ws.close();
132
+ this.ws = undefined;
133
+ }
134
+ this.$connected = false;
135
+ }
136
+
137
+ $formatMessage(ev: OneBot12Event): Message<OneBot12Event> {
138
+ if (!isMessageEvent(ev)) {
139
+ return Message.from(ev, {
140
+ $id: '',
141
+ $adapter: 'onebot12',
142
+ $bot: this.$config.name,
143
+ $channel: { id: '', type: 'private' },
144
+ $sender: { id: '', name: '' },
145
+ $content: [],
146
+ $raw: '',
147
+ $timestamp: ev.time ?? 0,
148
+ $recall: async () => {},
149
+ $reply: async () => '',
150
+ });
151
+ }
152
+ const payload = formatOneBot12MessagePayload(
153
+ ev,
154
+ this.$config.name,
155
+ (id) => this.$recallMessage(id),
156
+ (channel, content, _quote) =>
157
+ this.adapter.sendMessage({
158
+ ...channel,
159
+ context: 'onebot12',
160
+ bot: this.$config.name,
161
+ content: content as import('zhin.js').SendContent,
162
+ }),
163
+ );
164
+ return Message.from(ev, payload);
165
+ }
166
+
167
+ async $sendMessage(options: SendOptions): Promise<string> {
168
+ const message = contentToOb12Segments(options.content);
169
+ const params: Record<string, unknown> = { message };
170
+ if (options.type === 'private') {
171
+ params.detail_type = 'private';
172
+ params.user_id = options.id;
173
+ } else if (options.type === 'group') {
174
+ params.detail_type = 'group';
175
+ params.group_id = options.id;
176
+ } else {
177
+ const [guildId, channelId] = options.id.includes(':') ? options.id.split(':') : [undefined, options.id];
178
+ params.detail_type = 'channel';
179
+ params.channel_id = channelId ?? options.id;
180
+ if (guildId) params.guild_id = guildId;
181
+ }
182
+ const data = await this.callAction('send_message', params) as { message_id?: string } | undefined;
183
+ const msgId = data?.message_id ?? '';
184
+ this.logger.debug(`${this.$config.name} send ${options.type}(${options.id}):${segment.raw(options.content)}`);
185
+ return msgId;
186
+ }
187
+
188
+ async $recallMessage(id: string): Promise<void> {
189
+ await this.callAction('delete_message', { message_id: id });
190
+ }
191
+ }
package/src/bot-wss.ts ADDED
@@ -0,0 +1,188 @@
1
+ /**
2
+ * OneBot 12 反向 WebSocket Bot:应用开 WS 服务端,OneBot 实现连上来
3
+ */
4
+ import WebSocket, { WebSocketServer } from 'ws';
5
+ import { EventEmitter } from 'events';
6
+ import { clearInterval, clearTimeout } from 'node:timers';
7
+ import { IncomingMessage } from 'http';
8
+ import { Bot, Message, SendOptions, segment } from 'zhin.js';
9
+ import type { Router } from '@zhin.js/http';
10
+ import type { OneBot12WssConfig, OneBot12Event, OneBot12ActionRequest, OneBot12ActionResponse } from './types.js';
11
+ import type { OneBot12Adapter } from './adapter.js';
12
+ import { formatOneBot12MessagePayload, isMessageEvent, contentToOb12Segments } from './utils.js';
13
+
14
+ export class OneBot12WssServer extends EventEmitter implements Bot<OneBot12WssConfig, OneBot12Event> {
15
+ $connected: boolean = false;
16
+ #wss?: WebSocketServer;
17
+ #client?: WebSocket;
18
+ private heartbeatTimer?: NodeJS.Timeout;
19
+ private requestId = 0;
20
+ private pendingRequests = new Map<string, { resolve: (value: unknown) => void; reject: (err: Error) => void; timeout: NodeJS.Timeout }>();
21
+
22
+ get logger() {
23
+ return this.adapter.plugin.logger;
24
+ }
25
+
26
+ constructor(
27
+ public adapter: OneBot12Adapter,
28
+ public router: Router,
29
+ public $config: OneBot12WssConfig,
30
+ ) {
31
+ super();
32
+ }
33
+
34
+ get $id() {
35
+ return this.$config.name;
36
+ }
37
+
38
+ private getClient(): WebSocket | undefined {
39
+ return this.#client && this.#client.readyState === WebSocket.OPEN ? this.#client : undefined;
40
+ }
41
+
42
+ private callAction(action: string, params: Record<string, unknown>): Promise<OneBot12ActionResponse['data']> {
43
+ const client = this.getClient();
44
+ if (!client) return Promise.reject(new Error('反向 WebSocket 未连接'));
45
+ const echo = `ob12wss_${++this.requestId}`;
46
+ const req: OneBot12ActionRequest = { action, params, echo };
47
+ return new Promise((resolve, reject) => {
48
+ const timeout = setTimeout(() => {
49
+ this.pendingRequests.delete(echo);
50
+ reject(new Error(`OneBot12 动作超时: ${action}`));
51
+ }, 30000);
52
+ this.pendingRequests.set(echo, {
53
+ resolve: (data: unknown) => resolve(data as OneBot12ActionResponse['data']),
54
+ reject,
55
+ timeout,
56
+ });
57
+ client.send(JSON.stringify(req));
58
+ });
59
+ }
60
+
61
+ async $connect(): Promise<void> {
62
+ const path = this.$config.path.startsWith('/') ? this.$config.path : `/${this.$config.path}`;
63
+ this.#wss = this.router.ws(path, {
64
+ verifyClient: (info: { req: IncomingMessage }) => {
65
+ const auth = info.req.headers['authorization'];
66
+ if (this.$config.access_token && auth !== `Bearer ${this.$config.access_token}`) {
67
+ this.logger.error('OneBot12 反向 WS 鉴权失败');
68
+ return false;
69
+ }
70
+ return true;
71
+ },
72
+ });
73
+
74
+ this.#wss.on('connection', (ws: WebSocket) => {
75
+ if (this.#client && this.#client.readyState === WebSocket.OPEN) {
76
+ this.#client.close();
77
+ }
78
+ this.#client = ws;
79
+ this.$connected = true;
80
+ this.logger.info(`OneBot12 反向 WS 已连接: ${this.$config.name}`);
81
+
82
+ ws.on('message', (data) => {
83
+ try {
84
+ const msg = JSON.parse(data.toString()) as OneBot12Event | OneBot12ActionResponse;
85
+ if ('echo' in msg && typeof (msg as OneBot12ActionResponse).echo === 'string') {
86
+ const resp = msg as OneBot12ActionResponse;
87
+ const pending = this.pendingRequests.get(resp.echo!);
88
+ if (pending) {
89
+ this.pendingRequests.delete(resp.echo!);
90
+ clearTimeout(pending.timeout);
91
+ if (resp.status === 'ok') pending.resolve(resp.data);
92
+ else pending.reject(new Error(`OneBot12 retcode=${resp.retcode}: ${resp.message}`));
93
+ }
94
+ return;
95
+ }
96
+ const ev = msg as OneBot12Event;
97
+ if (ev.type === 'message' && isMessageEvent(ev)) {
98
+ const message = this.$formatMessage(ev);
99
+ this.adapter.emit('message.receive', message);
100
+ this.logger.debug(`${this.$config.name} recv ${message.$channel.type}(${message.$channel.id}):${segment.raw(message.$content)}`);
101
+ }
102
+ } catch (error) {
103
+ this.emit('error', error);
104
+ }
105
+ });
106
+
107
+ ws.on('close', () => {
108
+ this.$connected = false;
109
+ this.#client = undefined;
110
+ this.logger.warn('OneBot12 反向 WS 断开');
111
+ });
112
+
113
+ ws.on('error', (err) => this.logger.error('OneBot12 反向 WS 错误', err));
114
+ });
115
+ }
116
+
117
+ async $disconnect(): Promise<void> {
118
+ if (this.heartbeatTimer) {
119
+ clearInterval(this.heartbeatTimer);
120
+ this.heartbeatTimer = undefined;
121
+ }
122
+ for (const [, p] of this.pendingRequests) {
123
+ clearTimeout(p.timeout);
124
+ p.reject(new Error('连接已关闭'));
125
+ }
126
+ this.pendingRequests.clear();
127
+ if (this.#client) {
128
+ this.#client.close();
129
+ this.#client = undefined;
130
+ }
131
+ this.#wss?.close();
132
+ this.#wss = undefined;
133
+ this.$connected = false;
134
+ }
135
+
136
+ $formatMessage(ev: OneBot12Event): Message<OneBot12Event> {
137
+ if (!isMessageEvent(ev)) {
138
+ return Message.from(ev, {
139
+ $id: '',
140
+ $adapter: 'onebot12',
141
+ $bot: this.$config.name,
142
+ $channel: { id: '', type: 'private' },
143
+ $sender: { id: '', name: '' },
144
+ $content: [],
145
+ $raw: '',
146
+ $timestamp: ev.time ?? 0,
147
+ $recall: async () => {},
148
+ $reply: async () => '',
149
+ });
150
+ }
151
+ const payload = formatOneBot12MessagePayload(
152
+ ev,
153
+ this.$config.name,
154
+ (id) => this.$recallMessage(id),
155
+ (channel, content, _quote) =>
156
+ this.adapter.sendMessage({
157
+ ...channel,
158
+ context: 'onebot12',
159
+ bot: this.$config.name,
160
+ content: content as import('zhin.js').SendContent,
161
+ }),
162
+ );
163
+ return Message.from(ev, payload);
164
+ }
165
+
166
+ async $sendMessage(options: SendOptions): Promise<string> {
167
+ const message = contentToOb12Segments(options.content);
168
+ const params: Record<string, unknown> = { message };
169
+ if (options.type === 'private') {
170
+ params.detail_type = 'private';
171
+ params.user_id = options.id;
172
+ } else if (options.type === 'group') {
173
+ params.detail_type = 'group';
174
+ params.group_id = options.id;
175
+ } else {
176
+ const [guildId, channelId] = options.id.includes(':') ? options.id.split(':') : [undefined, options.id];
177
+ params.detail_type = 'channel';
178
+ params.channel_id = channelId ?? options.id;
179
+ if (guildId) params.guild_id = guildId;
180
+ }
181
+ const data = await this.callAction('send_message', params) as { message_id?: string } | undefined;
182
+ return data?.message_id ?? '';
183
+ }
184
+
185
+ async $recallMessage(id: string): Promise<void> {
186
+ await this.callAction('delete_message', { message_id: id });
187
+ }
188
+ }
package/src/index.ts ADDED
@@ -0,0 +1,40 @@
1
+ /**
2
+ * OneBot 12 适配器入口:单一适配器,支持正向 WS / Webhook / 反向 WS
3
+ * 协议文档 https://12.onebot.dev/
4
+ */
5
+ import { usePlugin, type Plugin, type Context } from 'zhin.js';
6
+ import type { Router } from '@zhin.js/http';
7
+ import { OneBot12Adapter } from './adapter.js';
8
+
9
+ export * from './types.js';
10
+ export { callOneBot12Action } from './api.js';
11
+ export * from './utils.js';
12
+ export { OneBot12WsClient } from './bot-ws.js';
13
+ export { OneBot12WebhookBot } from './bot-webhook.js';
14
+ export { OneBot12WssServer } from './bot-wss.js';
15
+ export { OneBot12Adapter, type OneBot12Bot } from './adapter.js';
16
+
17
+ declare module 'zhin.js' {
18
+ namespace Plugin {
19
+ interface Contexts {
20
+ router: import('@zhin.js/http').Router;
21
+ }
22
+ }
23
+ interface Adapters {
24
+ onebot12: OneBot12Adapter;
25
+ }
26
+ }
27
+
28
+ const { provide } = usePlugin();
29
+ provide({
30
+ name: 'onebot12',
31
+ description: 'OneBot 12 协议适配器(正向 WS / Webhook / 反向 WS)',
32
+ mounted: async (p: Plugin) => {
33
+ const adapter = new OneBot12Adapter(p);
34
+ await adapter.start();
35
+ return adapter;
36
+ },
37
+ dispose: async (adapter: OneBot12Adapter) => {
38
+ await adapter.stop();
39
+ },
40
+ } as unknown as Context<'onebot12'>);
package/src/types.ts ADDED
@@ -0,0 +1,86 @@
1
+ /**
2
+ * OneBot 12 适配器类型(参考 https://12.onebot.dev/ )
3
+ */
4
+
5
+ /** 配置公共字段;单一适配器 context 均为 'onebot12',连接方式由 connection 区分 */
6
+ export interface OneBot12ConfigBase {
7
+ context: 'onebot12';
8
+ name: string;
9
+ /** 访问令牌,鉴权用 */
10
+ access_token?: string;
11
+ }
12
+
13
+ /** 正向 WebSocket:应用连 OneBot 实现的 WS 服务器 */
14
+ export interface OneBot12WsConfig extends OneBot12ConfigBase {
15
+ connection: 'ws';
16
+ /** OneBot 实现提供的 WebSocket 地址,如 ws://127.0.0.1:6700 */
17
+ url: string;
18
+ reconnect_interval?: number;
19
+ heartbeat_interval?: number;
20
+ }
21
+
22
+ /** HTTP Webhook:OneBot 实现 POST 事件到应用提供的 path */
23
+ export interface OneBot12WebhookConfig extends OneBot12ConfigBase {
24
+ connection: 'webhook';
25
+ /** 应用接收事件的 POST 路径 */
26
+ path: string;
27
+ /** 可选:OneBot 实现的 HTTP 端点,用于发消息等动作(实现 POST 事件到我们,我们 POST 动作到该 url) */
28
+ api_url?: string;
29
+ }
30
+
31
+ /** 反向 WebSocket:应用开 WS 服务端,OneBot 实现连上来 */
32
+ export interface OneBot12WssConfig extends OneBot12ConfigBase {
33
+ connection: 'wss';
34
+ /** 应用侧 WS 路径 */
35
+ path: string;
36
+ heartbeat_interval?: number;
37
+ }
38
+
39
+ export type OneBot12BotConfig = OneBot12WsConfig | OneBot12WebhookConfig | OneBot12WssConfig;
40
+
41
+ /** 机器人自身标识(事件与动作中的 self) */
42
+ export interface OneBot12Self {
43
+ platform: string;
44
+ user_id: string;
45
+ }
46
+
47
+ /** 事件(实现推送给应用) */
48
+ export interface OneBot12Event {
49
+ id: string;
50
+ time: number;
51
+ type: 'meta' | 'message' | 'notice' | 'request';
52
+ detail_type: string;
53
+ sub_type: string;
54
+ self?: OneBot12Self;
55
+ message_id?: string;
56
+ message?: OneBot12Segment[];
57
+ alt_message?: string;
58
+ user_id?: string;
59
+ group_id?: string;
60
+ channel_id?: string;
61
+ guild_id?: string;
62
+ [key: string]: unknown;
63
+ }
64
+
65
+ /** 消息段 */
66
+ export interface OneBot12Segment {
67
+ type: string;
68
+ data?: Record<string, unknown>;
69
+ }
70
+
71
+ /** 动作请求(应用发给实现) */
72
+ export interface OneBot12ActionRequest {
73
+ action: string;
74
+ params: Record<string, unknown>;
75
+ echo?: string;
76
+ self?: OneBot12Self;
77
+ }
78
+
79
+ /** 动作响应(实现返回给应用) */
80
+ export interface OneBot12ActionResponse {
81
+ status: 'ok' | 'failed';
82
+ retcode: number;
83
+ data?: unknown;
84
+ message: string;
85
+ echo?: string;
86
+ }