@alemonjs/qq-bot 0.0.9 → 0.0.10

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.
Files changed (40) hide show
  1. package/dist/assets/index.css +476 -0
  2. package/dist/assets/index.js +11032 -0
  3. package/dist/index.html +15 -0
  4. package/lib/api.d.ts +971 -843
  5. package/lib/api.js +1172 -1156
  6. package/lib/client.d.ts +22 -22
  7. package/lib/client.js +201 -217
  8. package/lib/config.js +2 -2
  9. package/lib/desktop.d.ts +2 -2
  10. package/lib/desktop.js +60 -59
  11. package/lib/from.js +27 -34
  12. package/lib/index.d.ts +7 -7
  13. package/lib/index.js +406 -405
  14. package/lib/message/AT_MESSAGE_CREATE.d.ts +35 -35
  15. package/lib/message/C2C_MESSAGE_CREATE.d.ts +9 -9
  16. package/lib/message/CHANNEL_CREATE.d.ts +15 -15
  17. package/lib/message/CHANNEL_DELETE.d.ts +15 -15
  18. package/lib/message/CHANNEL_UPDATE.d.ts +15 -15
  19. package/lib/message/DIRECT_MESSAGE_CREATE.d.ts +29 -29
  20. package/lib/message/DIRECT_MESSAGE_DELETE.d.ts +17 -17
  21. package/lib/message/ERROR.d.ts +2 -2
  22. package/lib/message/GROUP_AT_MESSAGE_CREATE.d.ts +10 -10
  23. package/lib/message/GUILD_CREATE.d.ts +15 -15
  24. package/lib/message/GUILD_DELETE.d.ts +15 -15
  25. package/lib/message/GUILD_MEMBER_ADD.d.ts +14 -14
  26. package/lib/message/GUILD_MEMBER_REMOVE.d.ts +14 -14
  27. package/lib/message/GUILD_MEMBER_UPDATE.d.ts +14 -14
  28. package/lib/message/GUILD_UPDATE.d.ts +15 -15
  29. package/lib/message/INTERACTION_CREATE.d.ts +2 -2
  30. package/lib/message/MESSAGE_CREATE.d.ts +2 -2
  31. package/lib/message/MESSAGE_DELETE.d.ts +2 -2
  32. package/lib/message/MESSAGE_REACTION_ADD.d.ts +13 -13
  33. package/lib/message/MESSAGE_REACTION_REMOVE.d.ts +13 -13
  34. package/lib/message/PUBLIC_MESSAGE_DELETE.d.ts +15 -15
  35. package/lib/message/READY.d.ts +6 -6
  36. package/lib/message.d.ts +46 -46
  37. package/lib/send/index.js +230 -192
  38. package/lib/typing.d.ts +62 -54
  39. package/lib/webhook.js +46 -48
  40. package/package.json +1 -1
package/lib/client.d.ts CHANGED
@@ -1,26 +1,26 @@
1
- import { QQBotAPI } from './api.js';
2
- import { QQBotEventMap } from './message.js';
3
- import { Options } from './typing.js';
1
+ import { QQBotAPI } from './api.js'
2
+ import { QQBotEventMap } from './message.js'
3
+ import { Options } from './typing.js'
4
4
 
5
5
  declare class QQBotClient extends QQBotAPI {
6
- #private;
7
- /**
8
- * 设置配置
9
- * @param opstion
10
- */
11
- constructor(opstion: Options);
12
- /**
13
- * 注册事件处理程序
14
- * @param key 事件名称
15
- * @param val 事件处理函数
16
- */
17
- on<T extends keyof QQBotEventMap>(key: T, val: (event: QQBotEventMap[T]) => any): this;
18
- /**
19
- *
20
- * @param cfg
21
- * @param conversation
22
- */
23
- connect(): void;
6
+ #private
7
+ /**
8
+ * 设置配置
9
+ * @param opstion
10
+ */
11
+ constructor(opstion: Options)
12
+ /**
13
+ * 注册事件处理程序
14
+ * @param key 事件名称
15
+ * @param val 事件处理函数
16
+ */
17
+ on<T extends keyof QQBotEventMap>(key: T, val: (event: QQBotEventMap[T]) => any): this
18
+ /**
19
+ *
20
+ * @param cfg
21
+ * @param conversation
22
+ */
23
+ connect(): void
24
24
  }
25
25
 
26
- export { QQBotClient };
26
+ export { QQBotClient }
package/lib/client.js CHANGED
@@ -1,228 +1,212 @@
1
- import { QQBotAPI } from './api.js';
2
- import bodyParser from 'koa-bodyparser';
3
- import Router from 'koa-router';
4
- import { WebhookAPI } from './webhook.js';
5
- import Koa from 'koa';
6
- import { config } from './config.js';
7
- import { v4 } from 'uuid';
8
- import { WebSocketServer, WebSocket } from 'ws';
1
+ import { QQBotAPI } from './api.js'
2
+ import bodyParser from 'koa-bodyparser'
3
+ import Router from 'koa-router'
4
+ import { WebhookAPI } from './webhook.js'
5
+ import Koa from 'koa'
6
+ import { config } from './config.js'
7
+ import { v4 } from 'uuid'
8
+ import { WebSocketServer, WebSocket } from 'ws'
9
9
 
10
10
  class QQBotClient extends QQBotAPI {
11
- #events = {};
12
- #app = null;
13
- #count = 0;
14
- #client = [];
15
- #ws = null;
16
- /**
17
- * 设置配置
18
- * @param opstion
19
- */
20
- constructor(opstion) {
21
- super();
22
- if (opstion.secret)
23
- config.set('secret', opstion.secret);
24
- if (opstion.app_id)
25
- config.set('app_id', opstion.app_id);
26
- if (opstion.token)
27
- config.set('token', opstion.token);
28
- if (opstion.port)
29
- config.set('port', opstion.port);
30
- if (opstion.ws)
31
- config.set('ws', opstion.ws);
11
+ #events = {}
12
+ #app = null
13
+ #count = 0
14
+ #client = []
15
+ #ws = null
16
+ /**
17
+ * 设置配置
18
+ * @param opstion
19
+ */
20
+ constructor(opstion) {
21
+ super()
22
+ if (opstion.secret) config.set('secret', opstion.secret)
23
+ if (opstion.app_id) config.set('app_id', opstion.app_id)
24
+ if (opstion.token) config.set('token', opstion.token)
25
+ if (opstion.port) config.set('port', opstion.port)
26
+ if (opstion.ws) config.set('ws', opstion.ws)
27
+ }
28
+ /**
29
+ * 注册事件处理程序
30
+ * @param key 事件名称
31
+ * @param val 事件处理函数
32
+ */
33
+ on(key, val) {
34
+ if (!this.#events[key]) {
35
+ this.#events[key] = []
32
36
  }
33
- /**
34
- * 注册事件处理程序
35
- * @param key 事件名称
36
- * @param val 事件处理函数
37
- */
38
- on(key, val) {
39
- if (!this.#events[key]) {
40
- this.#events[key] = [];
41
- }
42
- this.#events[key].push(val);
43
- return this;
44
- }
45
- /**
46
- * 定时鉴权
47
- * @param cfg
48
- * @returns
49
- */
50
- async #setTimeoutBotConfig() {
51
- const callBack = async () => {
52
- const app_id = config.get('app_id');
53
- if (!app_id)
54
- return;
55
- const secret = config.get('secret');
56
- if (!secret)
57
- return;
58
- // 发送请求
59
- const data = await this.getAuthentication(app_id, secret).then(res => res.data);
60
- config.set('access_token', data.access_token);
61
- console.info('refresh', data.expires_in, 's');
62
- setTimeout(callBack, data.expires_in * 1000);
63
- };
64
- await callBack();
37
+ this.#events[key].push(val)
38
+ return this
39
+ }
40
+ /**
41
+ * 定时鉴权
42
+ * @param cfg
43
+ * @returns
44
+ */
45
+ async #setTimeoutBotConfig() {
46
+ const callBack = async () => {
47
+ const app_id = config.get('app_id')
48
+ if (!app_id) return
49
+ const secret = config.get('secret')
50
+ if (!secret) return
51
+ // 发送请求
52
+ const data = await this.getAuthentication(app_id, secret).then(res => res.data)
53
+ config.set('access_token', data.access_token)
54
+ console.info('refresh', data.expires_in, 's')
55
+ setTimeout(callBack, data.expires_in * 1000)
65
56
  }
66
- /**
67
- *
68
- * @param cfg
69
- * @param conversation
70
- */
71
- connect() {
72
- try {
73
- const ws = config.get('ws');
74
- if (!ws) {
75
- this.#setTimeoutBotConfig();
76
- this.#app = new Koa();
77
- this.#app.use(bodyParser());
78
- const router = new Router();
79
- const port = config.get('port');
80
- const secret = config.get('secret');
81
- const route = config.get('route') ?? '/webhook';
82
- const cfg = {
83
- secret: secret ?? '',
84
- port: port ? Number(port) : 17157
85
- };
86
- const ntqqWebhook = new WebhookAPI({
87
- secret: cfg.secret
88
- });
89
- this.#app.use(async (ctx, next) => {
90
- let rawData = '';
91
- ctx.req.on('data', chunk => (rawData += chunk));
92
- ctx.req.on('end', () => (ctx.request.rawBody = rawData));
93
- await next();
94
- });
95
- // 启动服务
96
- router.post(route, async (ctx) => {
97
- const sign = ctx.req.headers['x-signature-ed25519'];
98
- const timestamp = ctx.req.headers['x-signature-timestamp'];
99
- const rawBody = ctx.request.rawBody;
100
- const isValid = ntqqWebhook.validSign(timestamp, rawBody, String(sign));
101
- if (!isValid) {
102
- ctx.status = 400;
103
- ctx.body = { msg: 'invalid signature' };
104
- return;
105
- }
106
- const body = ctx.request.body;
107
- if (body.op == 13) {
108
- ctx.status = 200;
109
- ctx.body = {
110
- // 返回明文 token
111
- plain_token: body.d.plain_token,
112
- // 生成签名
113
- signature: ntqqWebhook.getSign(body.d.event_ts, body.d.plain_token)
114
- };
115
- }
116
- else if (body.op == 0) {
117
- ctx.status = 204;
118
- // 根据事件类型,处理事件
119
- for (const event of this.#events[body.t] || []) {
120
- event(body.d);
121
- }
122
- const access_token = config.get('access_token');
123
- // 也可以分法到客户端。 发送失败需要处理 或清理调
124
- for (const client of this.#client) {
125
- try {
126
- if (access_token)
127
- body['access_token'] = access_token;
128
- client.ws.send(JSON.stringify(body));
129
- }
130
- catch (e) {
131
- this.#error(e);
132
- }
133
- }
134
- }
135
- });
136
- this.#app.use(router.routes());
137
- this.#app.use(router.allowedMethods());
138
- // 启动服务
139
- const server = this.#app.listen(cfg.port, () => {
140
- console.log('Server running at http://localhost:' + cfg.port + route);
141
- });
142
- // 创建 WebSocketServer 并监听同一个端口
143
- const wss = new WebSocketServer({ server: server });
144
- console.log('Server running at wss://localhost:' + cfg.port + '/');
145
- // 处理客户端连接
146
- wss.on('connection', ws => {
147
- const clientId = v4();
148
- ws['clientId'] = clientId;
149
- console.log(clientId, 'connection');
150
- this.#client.push({ id: clientId, ws });
151
- // 处理消息事件
152
- ws.on('message', (message) => {
153
- // 拿到消息
154
- try {
155
- const body = JSON.parse(message.toString());
156
- for (const event of this.#events[body.t] || []) {
157
- event(body.d);
158
- }
159
- }
160
- catch (e) {
161
- this.#error(e);
162
- }
163
- });
164
- // 处理关闭事件
165
- ws.on('close', () => {
166
- console.log(`${clientId} disconnected`);
167
- this.#client = this.#client.filter(client => client.id !== clientId);
168
- });
169
- });
57
+ await callBack()
58
+ }
59
+ /**
60
+ *
61
+ * @param cfg
62
+ * @param conversation
63
+ */
64
+ connect() {
65
+ try {
66
+ const ws = config.get('ws')
67
+ if (!ws) {
68
+ this.#setTimeoutBotConfig()
69
+ this.#app = new Koa()
70
+ this.#app.use(bodyParser())
71
+ const router = new Router()
72
+ const port = config.get('port')
73
+ const secret = config.get('secret')
74
+ const route = config.get('route') ?? '/webhook'
75
+ const cfg = {
76
+ secret: secret ?? '',
77
+ port: port ? Number(port) : 17157
78
+ }
79
+ const ntqqWebhook = new WebhookAPI({
80
+ secret: cfg.secret
81
+ })
82
+ this.#app.use(async (ctx, next) => {
83
+ let rawData = ''
84
+ ctx.req.on('data', chunk => (rawData += chunk))
85
+ ctx.req.on('end', () => (ctx.request.rawBody = rawData))
86
+ await next()
87
+ })
88
+ // 启动服务
89
+ router.post(route, async ctx => {
90
+ const sign = ctx.req.headers['x-signature-ed25519']
91
+ const timestamp = ctx.req.headers['x-signature-timestamp']
92
+ const rawBody = ctx.request.rawBody
93
+ const isValid = ntqqWebhook.validSign(timestamp, rawBody, String(sign))
94
+ if (!isValid) {
95
+ ctx.status = 400
96
+ ctx.body = { msg: 'invalid signature' }
97
+ return
98
+ }
99
+ const body = ctx.request.body
100
+ if (body.op == 13) {
101
+ ctx.status = 200
102
+ ctx.body = {
103
+ // 返回明文 token
104
+ plain_token: body.d.plain_token,
105
+ // 生成签名
106
+ signature: ntqqWebhook.getSign(body.d.event_ts, body.d.plain_token)
170
107
  }
171
- else {
172
- const reconnect = () => {
173
- // 使用了ws服务器
174
- this.#ws = new WebSocket(ws);
175
- this.#ws.on('open', () => {
176
- this.#count = 0;
177
- console.log('ws connected');
178
- });
179
- this.#ws.on('message', data => {
180
- try {
181
- // 拿到消息
182
- const body = JSON.parse(data.toString());
183
- const access_token = body['access_token'];
184
- if (access_token)
185
- config.set('access_token', access_token);
186
- for (const event of this.#events[body.t] || []) {
187
- event(body.d);
188
- }
189
- }
190
- catch (e) {
191
- this.#error(e);
192
- }
193
- });
194
- this.#ws.on('close', () => {
195
- console.log('ws closed');
196
- // 重连5次,超过5次不再重连
197
- if (this.#count > 5)
198
- return;
199
- // 1.3s 后重连
200
- setTimeout(() => {
201
- reconnect();
202
- }, 1300);
203
- });
204
- this.#ws.on('error', e => {
205
- this.#error(e);
206
- });
207
- };
208
- reconnect();
108
+ } else if (body.op == 0) {
109
+ ctx.status = 204
110
+ // 根据事件类型,处理事件
111
+ for (const event of this.#events[body.t] || []) {
112
+ event(body.d)
209
113
  }
210
- }
211
- catch (e) {
212
- this.#error(e);
213
- }
214
- }
215
- /**
216
- *
217
- * @param error
218
- */
219
- #error(error) {
220
- if (this.#events['ERROR']) {
221
- for (const event of this.#events['ERROR'] || []) {
222
- event(error);
114
+ const access_token = config.get('access_token')
115
+ // 也可以分法到客户端。 发送失败需要处理 或清理调
116
+ for (const client of this.#client) {
117
+ try {
118
+ if (access_token) body['access_token'] = access_token
119
+ client.ws.send(JSON.stringify(body))
120
+ } catch (e) {
121
+ this.#error(e)
122
+ }
123
+ }
124
+ }
125
+ })
126
+ this.#app.use(router.routes())
127
+ this.#app.use(router.allowedMethods())
128
+ // 启动服务
129
+ const server = this.#app.listen(cfg.port, () => {
130
+ console.log('Server running at http://localhost:' + cfg.port + route)
131
+ })
132
+ // 创建 WebSocketServer 并监听同一个端口
133
+ const wss = new WebSocketServer({ server: server })
134
+ console.log('Server running at wss://localhost:' + cfg.port + '/')
135
+ // 处理客户端连接
136
+ wss.on('connection', ws => {
137
+ const clientId = v4()
138
+ ws['clientId'] = clientId
139
+ console.log(clientId, 'connection')
140
+ this.#client.push({ id: clientId, ws })
141
+ // 处理消息事件
142
+ ws.on('message', message => {
143
+ // 拿到消息
144
+ try {
145
+ const body = JSON.parse(message.toString())
146
+ for (const event of this.#events[body.t] || []) {
147
+ event(body.d)
148
+ }
149
+ } catch (e) {
150
+ this.#error(e)
223
151
  }
152
+ })
153
+ // 处理关闭事件
154
+ ws.on('close', () => {
155
+ console.log(`${clientId} disconnected`)
156
+ this.#client = this.#client.filter(client => client.id !== clientId)
157
+ })
158
+ })
159
+ } else {
160
+ const reconnect = () => {
161
+ // 使用了ws服务器
162
+ this.#ws = new WebSocket(ws)
163
+ this.#ws.on('open', () => {
164
+ this.#count = 0
165
+ console.log('ws connected')
166
+ })
167
+ this.#ws.on('message', data => {
168
+ try {
169
+ // 拿到消息
170
+ const body = JSON.parse(data.toString())
171
+ const access_token = body['access_token']
172
+ if (access_token) config.set('access_token', access_token)
173
+ for (const event of this.#events[body.t] || []) {
174
+ event(body.d)
175
+ }
176
+ } catch (e) {
177
+ this.#error(e)
178
+ }
179
+ })
180
+ this.#ws.on('close', () => {
181
+ console.log('ws closed')
182
+ // 重连5次,超过5次不再重连
183
+ if (this.#count > 5) return
184
+ // 1.3s 后重连
185
+ setTimeout(() => {
186
+ reconnect()
187
+ }, 1300)
188
+ })
189
+ this.#ws.on('error', e => {
190
+ this.#error(e)
191
+ })
224
192
  }
193
+ reconnect()
194
+ }
195
+ } catch (e) {
196
+ this.#error(e)
197
+ }
198
+ }
199
+ /**
200
+ *
201
+ * @param error
202
+ */
203
+ #error(error) {
204
+ if (this.#events['ERROR']) {
205
+ for (const event of this.#events['ERROR'] || []) {
206
+ event(error)
207
+ }
225
208
  }
209
+ }
226
210
  }
227
211
 
228
- export { QQBotClient };
212
+ export { QQBotClient }
package/lib/config.js CHANGED
@@ -1,3 +1,3 @@
1
- const config = new Map();
1
+ const config = new Map()
2
2
 
3
- export { config };
3
+ export { config }
package/lib/desktop.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- declare const activate: (context: any) => void;
1
+ declare const activate: (context: any) => void
2
2
 
3
- export { activate };
3
+ export { activate }
package/lib/desktop.js CHANGED
@@ -1,65 +1,66 @@
1
- import { readFileSync } from 'fs';
2
- import { dirname, join } from 'path';
3
- import { fileURLToPath } from 'url';
4
- import { getConfig, getConfigValue } from 'alemonjs';
1
+ import { readFileSync } from 'fs'
2
+ import { dirname, join } from 'path'
3
+ import { fileURLToPath } from 'url'
4
+ import { getConfig, getConfigValue } from 'alemonjs'
5
5
 
6
6
  // 当前目录
7
- const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ const __dirname = dirname(fileURLToPath(import.meta.url))
8
8
  // 被激活的时候。
9
9
  const activate = context => {
10
- // 创建一个 webview。
11
- const webView = context.createSidebarWebView(context);
12
- // 当命令被触发的时候。
13
- context.onCommand('open.qq-bot', () => {
14
- const dir = join(__dirname, '../', 'dist', 'index.html');
15
- const scriptReg = /<script.*?src="(.+?)".*?>/;
16
- const styleReg = /<link.*?href="(.+?)".*?>/;
17
- // 创建 webview 路径
18
- const styleUri = context.createExtensionDir(join(__dirname, '../', 'dist', 'assets', 'index.css'));
19
- const scriptUri = context.createExtensionDir(join(__dirname, '../', 'dist', 'assets', 'index.js'));
20
- // 确保路径存在
21
- const html = readFileSync(dir, 'utf-8')
22
- .replace(scriptReg, `<script type="module" crossorigin src="${scriptUri}"></script>`)
23
- .replace(styleReg, `<link rel="stylesheet" crossorigin href="${styleUri}">`);
24
- // 立即渲染 webview
25
- webView.loadWebView(html);
26
- });
27
- // 监听 webview 的消息。
28
- webView.onMessage(data => {
29
- try {
30
- if (data.type === 'qq-bot.form.save') {
31
- const qqBot = data.data;
32
- const config = getConfig();
33
- const value = config.value ?? {};
34
- value['qq-bot'] = {
35
- app_id: qqBot.app_id ?? '',
36
- token: qqBot.token ?? '',
37
- secret: qqBot.secret ?? '',
38
- // master_key 12121,1313,1313,13 转为数组
39
- master_key: qqBot.master_key.split(','),
40
- route: qqBot.route ?? '/webhook',
41
- port: qqBot.port ?? 17157,
42
- ws: qqBot.ws != '' && qqBot.ws ? qqBot.ws : null,
43
- sandbox: qqBot.sandbox ?? false
44
- };
45
- config.saveValue(value);
46
- context.notification('QQ Bot 配置保存成功~');
47
- }
48
- else if (data.type === 'qq-bot.init') {
49
- let config = getConfigValue();
50
- if (!config)
51
- config = {};
52
- // 发送消息
53
- webView.postMessage({
54
- type: 'qq-bot.init',
55
- data: config.qq_bot ?? {}
56
- });
57
- }
10
+ // 创建一个 webview。
11
+ const webView = context.createSidebarWebView(context)
12
+ // 当命令被触发的时候。
13
+ context.onCommand('open.qq-bot', () => {
14
+ const dir = join(__dirname, '../', 'dist', 'index.html')
15
+ const scriptReg = /<script.*?src="(.+?)".*?>/
16
+ const styleReg = /<link.*?href="(.+?)".*?>/
17
+ // 创建 webview 路径
18
+ const styleUri = context.createExtensionDir(
19
+ join(__dirname, '../', 'dist', 'assets', 'index.css')
20
+ )
21
+ const scriptUri = context.createExtensionDir(
22
+ join(__dirname, '../', 'dist', 'assets', 'index.js')
23
+ )
24
+ // 确保路径存在
25
+ const html = readFileSync(dir, 'utf-8')
26
+ .replace(scriptReg, `<script type="module" crossorigin src="${scriptUri}"></script>`)
27
+ .replace(styleReg, `<link rel="stylesheet" crossorigin href="${styleUri}">`)
28
+ // 立即渲染 webview
29
+ webView.loadWebView(html)
30
+ })
31
+ // 监听 webview 的消息。
32
+ webView.onMessage(data => {
33
+ try {
34
+ if (data.type === 'qq-bot.form.save') {
35
+ const qqBot = data.data
36
+ const config = getConfig()
37
+ const value = config.value ?? {}
38
+ value['qq-bot'] = {
39
+ app_id: qqBot.app_id ?? '',
40
+ token: qqBot.token ?? '',
41
+ secret: qqBot.secret ?? '',
42
+ // master_key 12121,1313,1313,13 转为数组
43
+ master_key: qqBot.master_key.split(','),
44
+ route: qqBot.route ?? '/webhook',
45
+ port: qqBot.port ?? 17157,
46
+ ws: qqBot.ws != '' && qqBot.ws ? qqBot.ws : null,
47
+ sandbox: qqBot.sandbox ?? false
58
48
  }
59
- catch (e) {
60
- console.error(e);
61
- }
62
- });
63
- };
49
+ config.saveValue(value)
50
+ context.notification('QQ Bot 配置保存成功~')
51
+ } else if (data.type === 'qq-bot.init') {
52
+ let config = getConfigValue()
53
+ if (!config) config = {}
54
+ // 发送消息
55
+ webView.postMessage({
56
+ type: 'qq-bot.init',
57
+ data: config.qq_bot ?? {}
58
+ })
59
+ }
60
+ } catch (e) {
61
+ console.error(e)
62
+ }
63
+ })
64
+ }
64
65
 
65
- export { activate };
66
+ export { activate }