@alemonjs/qq-bot 2.1.32 → 2.1.33
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/README.md +1946 -35
- package/lib/hook.d.ts +2 -1
- package/lib/index.websoket.js +2 -2
- package/lib/message/group/GROUP_JOIN_REQUEST.d.ts +23 -0
- package/lib/message/group/GROUP_JOIN_REQUEST.js +1 -0
- package/lib/register.js +248 -44
- package/lib/sdk/api.d.ts +58 -3
- package/lib/sdk/api.js +138 -3
- package/lib/sdk/instance.js +2 -0
- package/lib/sdk/intents.d.ts +1 -1
- package/lib/sdk/intents.js +2 -0
- package/lib/sdk/message.group.d.ts +2 -0
- package/lib/sdk/typing.d.ts +123 -1
- package/lib/sends.d.ts +6 -2
- package/lib/sends.js +131 -73
- package/lib/upload.d.ts +21 -0
- package/lib/upload.js +60 -0
- package/package.json +4 -4
package/lib/sends.js
CHANGED
|
@@ -1,11 +1,31 @@
|
|
|
1
1
|
import { readFileSync } from 'fs';
|
|
2
|
-
import { createResult, ResultCode } from 'alemonjs';
|
|
2
|
+
import { createResult, ResultCode, logger } from 'alemonjs';
|
|
3
3
|
import axios from 'axios';
|
|
4
4
|
import { dataEnumToText, markdownToText, buttonsToText } from './format.js';
|
|
5
5
|
import { getQQBotConfig } from './config.js';
|
|
6
6
|
|
|
7
7
|
const MAX_BUTTON_ROWS = 5;
|
|
8
8
|
const MAX_BUTTONS_PER_ROW = 5;
|
|
9
|
+
const BUTTON_STYLE_MAP = {
|
|
10
|
+
gray: 0,
|
|
11
|
+
blue: 1,
|
|
12
|
+
red: 3,
|
|
13
|
+
'blue-fill': 4
|
|
14
|
+
};
|
|
15
|
+
const resolveButtonStyle = (style) => {
|
|
16
|
+
if (typeof style === 'number') {
|
|
17
|
+
return style;
|
|
18
|
+
}
|
|
19
|
+
if (typeof style === 'string') {
|
|
20
|
+
if (BUTTON_STYLE_MAP[style] !== undefined) {
|
|
21
|
+
return BUTTON_STYLE_MAP[style];
|
|
22
|
+
}
|
|
23
|
+
if (style.trim() !== '' && !Number.isNaN(Number(style))) {
|
|
24
|
+
return Number(style);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return 0;
|
|
28
|
+
};
|
|
9
29
|
const createButtonsData = (rows, startId = 0) => {
|
|
10
30
|
let id = startId;
|
|
11
31
|
const clippedRows = rows.slice(0, MAX_BUTTON_ROWS);
|
|
@@ -18,25 +38,45 @@ const createButtonsData = (rows, startId = 0) => {
|
|
|
18
38
|
const typing = options?.type ?? 'command';
|
|
19
39
|
const typeMap = { command: 2, link: 0, call: 1 };
|
|
20
40
|
const rowData = options?.rawData ?? {};
|
|
41
|
+
const data = options?.data;
|
|
42
|
+
const modal = options?.modal ??
|
|
43
|
+
(typeof data === 'object' && data
|
|
44
|
+
? {
|
|
45
|
+
content: data.click,
|
|
46
|
+
confirmText: data.confirm,
|
|
47
|
+
cancelText: data.cancel
|
|
48
|
+
}
|
|
49
|
+
: undefined);
|
|
50
|
+
const action = {
|
|
51
|
+
type: typeMap[typing],
|
|
52
|
+
permission: {
|
|
53
|
+
type: typeof options.permission?.type === 'undefined' ? 2 : options?.permission?.type,
|
|
54
|
+
specify_user_ids: options?.permission?.userIds,
|
|
55
|
+
specify_role_ids: options?.permission?.roleIds
|
|
56
|
+
},
|
|
57
|
+
unsupport_tips: options?.toolTip ?? '',
|
|
58
|
+
data: typeof data === 'string' ? data : '',
|
|
59
|
+
at_bot_show_channel_list: options?.atBotShowChannelList ?? false,
|
|
60
|
+
enter: options?.autoEnter ?? false,
|
|
61
|
+
reply: options?.reply ?? false,
|
|
62
|
+
anchor: options?.anchor ?? 0,
|
|
63
|
+
click_limit: options?.clickLimit
|
|
64
|
+
};
|
|
65
|
+
if (modal) {
|
|
66
|
+
action.modal = {
|
|
67
|
+
content: modal.content ?? '是否确认操作?',
|
|
68
|
+
confirm_text: modal.confirmText ?? '是',
|
|
69
|
+
cancel_text: modal.cancelText ?? '否'
|
|
70
|
+
};
|
|
71
|
+
}
|
|
21
72
|
return {
|
|
22
73
|
id: String(id),
|
|
23
74
|
render_data: {
|
|
24
75
|
label: value,
|
|
25
76
|
visited_label: value,
|
|
26
|
-
style: options
|
|
27
|
-
},
|
|
28
|
-
action: {
|
|
29
|
-
type: typeMap[typing],
|
|
30
|
-
permission: {
|
|
31
|
-
type: typeof options.permission?.type === 'undefined' ? 2 : options?.permission?.type,
|
|
32
|
-
specify_user_ids: options?.permission?.userIds,
|
|
33
|
-
specify_role_ids: options?.permission?.roleIds
|
|
34
|
-
},
|
|
35
|
-
unsupport_tips: options?.toolTip ?? '',
|
|
36
|
-
data: options?.data ?? '',
|
|
37
|
-
at_bot_show_channel_list: false,
|
|
38
|
-
enter: options?.autoEnter ?? false
|
|
77
|
+
style: resolveButtonStyle(options?.style)
|
|
39
78
|
},
|
|
79
|
+
action,
|
|
40
80
|
...rowData
|
|
41
81
|
};
|
|
42
82
|
})
|
|
@@ -235,6 +275,7 @@ const buildMdAndButtonsParams = (val) => {
|
|
|
235
275
|
return null;
|
|
236
276
|
}
|
|
237
277
|
const params = {};
|
|
278
|
+
let keyboardExtra;
|
|
238
279
|
for (const item of items) {
|
|
239
280
|
if (item.type === 'ButtonTemplate') {
|
|
240
281
|
if (item?.value) {
|
|
@@ -242,6 +283,13 @@ const buildMdAndButtonsParams = (val) => {
|
|
|
242
283
|
}
|
|
243
284
|
}
|
|
244
285
|
else if (item.type === 'BT.group' && typeof item?.value !== 'string') {
|
|
286
|
+
const groupOptions = item?.options ?? {};
|
|
287
|
+
if (groupOptions.smallButton || groupOptions.rawData) {
|
|
288
|
+
keyboardExtra = {
|
|
289
|
+
smallButton: keyboardExtra?.smallButton || groupOptions.smallButton,
|
|
290
|
+
rawData: groupOptions.rawData
|
|
291
|
+
};
|
|
292
|
+
}
|
|
245
293
|
if (params['keyboard']?.content?.rows) {
|
|
246
294
|
const existingRows = params['keyboard'].content.rows;
|
|
247
295
|
const currentId = params['keyboard'].content.nextId ?? existingRows.length;
|
|
@@ -277,6 +325,14 @@ const buildMdAndButtonsParams = (val) => {
|
|
|
277
325
|
}
|
|
278
326
|
}
|
|
279
327
|
}
|
|
328
|
+
if (keyboardExtra && params['keyboard']?.content) {
|
|
329
|
+
if (keyboardExtra.smallButton) {
|
|
330
|
+
params['keyboard'].content.style = { font_size: 'small' };
|
|
331
|
+
}
|
|
332
|
+
if (keyboardExtra.rawData) {
|
|
333
|
+
Object.assign(params['keyboard'].content, keyboardExtra.rawData);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
280
336
|
if (params['keyboard']?.content?.nextId !== undefined) {
|
|
281
337
|
delete params['keyboard'].content.nextId;
|
|
282
338
|
}
|
|
@@ -301,50 +357,66 @@ const buildArkParams = (val) => {
|
|
|
301
357
|
}
|
|
302
358
|
return params;
|
|
303
359
|
};
|
|
360
|
+
const MEDIA_FILE_TYPE = {
|
|
361
|
+
Image: 1,
|
|
362
|
+
ImageFile: 1,
|
|
363
|
+
ImageURL: 1,
|
|
364
|
+
Video: 2,
|
|
365
|
+
Audio: 3,
|
|
366
|
+
Attachment: 4
|
|
367
|
+
};
|
|
368
|
+
const filterMedia = (val) => {
|
|
369
|
+
return val.filter(item => MEDIA_FILE_TYPE[item.type] !== undefined);
|
|
370
|
+
};
|
|
304
371
|
const filterImages = (val) => {
|
|
305
372
|
return val.filter(item => item.type === 'Image' || item.type === 'ImageFile' || item.type === 'ImageURL');
|
|
306
373
|
};
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
374
|
+
const resolveFileData = async (item) => {
|
|
375
|
+
if (item.type === 'ImageURL') {
|
|
376
|
+
return await axios.get(item.value, { responseType: 'arraybuffer' }).then(res => Buffer.from(res.data, 'binary').toString('base64'));
|
|
377
|
+
}
|
|
378
|
+
if (item.type === 'ImageFile') {
|
|
379
|
+
return readFileSync(item.value, 'base64');
|
|
380
|
+
}
|
|
381
|
+
const value = item.value;
|
|
382
|
+
if (typeof value === 'string') {
|
|
383
|
+
if (value.startsWith('https://') || value.startsWith('http://')) {
|
|
384
|
+
return await axios.get(value, { responseType: 'arraybuffer' }).then(res => Buffer.from(res.data, 'binary').toString('base64'));
|
|
314
385
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
fileData = await axios.get(item.value, { responseType: 'arraybuffer' }).then(res => Buffer.from(res.data, 'binary').toString('base64'));
|
|
318
|
-
}
|
|
319
|
-
else if (typeof item.value === 'string' && item.value.startsWith('file://')) {
|
|
320
|
-
const localFilePath = item.value.replace('file://', '');
|
|
321
|
-
fileData = readFileSync(localFilePath, 'base64');
|
|
322
|
-
}
|
|
323
|
-
else if (typeof item.value === 'string' && item.value.startsWith('base64://')) {
|
|
324
|
-
fileData = item.value.replace('base64://', '');
|
|
325
|
-
}
|
|
326
|
-
else if (Buffer.isBuffer(item.value)) {
|
|
327
|
-
fileData = item.value.toString('base64');
|
|
328
|
-
}
|
|
329
|
-
else if (typeof item.value === 'string' && item.value.startsWith('buffer://')) {
|
|
330
|
-
fileData = item.value.replace('buffer://', '');
|
|
331
|
-
}
|
|
332
|
-
else if (typeof item.value === 'string') {
|
|
333
|
-
fileData = item.value;
|
|
334
|
-
}
|
|
386
|
+
if (value.startsWith('buffer://')) {
|
|
387
|
+
return value.replace('buffer://', '');
|
|
335
388
|
}
|
|
336
|
-
|
|
337
|
-
|
|
389
|
+
if (value.startsWith('file://')) {
|
|
390
|
+
return readFileSync(value.replace('file://', ''), 'base64');
|
|
338
391
|
}
|
|
339
|
-
if (
|
|
340
|
-
|
|
392
|
+
if (value.startsWith('base64://')) {
|
|
393
|
+
return value.replace('base64://', '');
|
|
341
394
|
}
|
|
342
|
-
|
|
343
|
-
|
|
395
|
+
return value;
|
|
396
|
+
}
|
|
397
|
+
if (Buffer.isBuffer(value)) {
|
|
398
|
+
return value.toString('base64');
|
|
399
|
+
}
|
|
400
|
+
return undefined;
|
|
401
|
+
};
|
|
402
|
+
const resolveMediaUrl = async (media, uploadMedia) => {
|
|
403
|
+
for (const item of media) {
|
|
404
|
+
const fileData = await resolveFileData(item);
|
|
405
|
+
if (fileData) {
|
|
406
|
+
const fileInfo = await uploadMedia({ file_type: MEDIA_FILE_TYPE[item.type] ?? 1, file_data: fileData }).then(res => res?.file_info);
|
|
407
|
+
if (fileInfo) {
|
|
408
|
+
return fileInfo;
|
|
409
|
+
}
|
|
344
410
|
}
|
|
345
411
|
}
|
|
346
412
|
return undefined;
|
|
347
413
|
};
|
|
414
|
+
const stripMediaPlaceholders = (text) => text
|
|
415
|
+
.replace(/\[附件[^\]]*\]/g, '')
|
|
416
|
+
.replace(/\[音频\]/g, '')
|
|
417
|
+
.replace(/\[视频\]/g, '')
|
|
418
|
+
.replace(/\n{2,}/g, '\n')
|
|
419
|
+
.trim();
|
|
348
420
|
const flattenMdToText = (content, val) => {
|
|
349
421
|
const mdItems = val.filter(item => item.type === 'Markdown');
|
|
350
422
|
const btnItems = val.filter(item => item.type === 'BT.group');
|
|
@@ -364,32 +436,18 @@ const flattenMdToText = (content, val) => {
|
|
|
364
436
|
.join('\n')
|
|
365
437
|
.replace(/^[^\S\n\r]+|[^\S\n\r]+$/g, '');
|
|
366
438
|
};
|
|
367
|
-
const sendOpenApiMessage = async (content, val, baseParams, uploadMedia, sendMessage, label) => {
|
|
439
|
+
const sendOpenApiMessage = async (content, val, baseParams, uploadMedia, sendMessage, label, options) => {
|
|
368
440
|
const config = getQQBotConfig();
|
|
369
441
|
const mdToText = config.markdownToText === true;
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
const url = await resolveRichMediaUrl(images, uploadMedia);
|
|
374
|
-
if (!url) {
|
|
375
|
-
return [createResult(ResultCode.Fail, '图片上传失败', null)];
|
|
376
|
-
}
|
|
377
|
-
const imgContent = flattenMdToText(content, val);
|
|
378
|
-
const res = await sendMessage({
|
|
379
|
-
content: imgContent,
|
|
380
|
-
media: { file_info: url },
|
|
381
|
-
msg_type: 7,
|
|
382
|
-
...baseParams
|
|
383
|
-
});
|
|
384
|
-
return [createResult(ResultCode.Ok, label, { id: res.id })];
|
|
385
|
-
}
|
|
386
|
-
if (richMedia.length > 0) {
|
|
387
|
-
const fileInfo = await resolveRichMediaUrl(richMedia, uploadMedia);
|
|
442
|
+
const media = filterMedia(val);
|
|
443
|
+
if (media.length > 0) {
|
|
444
|
+
const fileInfo = await resolveMediaUrl(media, uploadMedia);
|
|
388
445
|
if (!fileInfo) {
|
|
389
|
-
return [createResult(ResultCode.Fail, '
|
|
446
|
+
return [createResult(ResultCode.Fail, '媒体上传失败', null)];
|
|
390
447
|
}
|
|
448
|
+
const mediaContent = stripMediaPlaceholders(flattenMdToText(content, val));
|
|
391
449
|
const res = await sendMessage({
|
|
392
|
-
content:
|
|
450
|
+
content: mediaContent,
|
|
393
451
|
media: { file_info: fileInfo },
|
|
394
452
|
msg_type: 7,
|
|
395
453
|
...baseParams
|
|
@@ -413,7 +471,7 @@ const sendOpenApiMessage = async (content, val, baseParams, uploadMedia, sendMes
|
|
|
413
471
|
if (mdParams.markdown?.content && content) {
|
|
414
472
|
mdParams.markdown.content = content + '\n' + mdParams.markdown.content;
|
|
415
473
|
}
|
|
416
|
-
const res = await sendMessage({ content, msg_type: 2, ...mdParams, ...baseParams });
|
|
474
|
+
const res = await sendMessage({ content, msg_type: 2, ...mdParams, ...baseParams, force_verify_image_resource: options?.forceVerifyImageResource });
|
|
417
475
|
return [createResult(ResultCode.Ok, label, { id: res.id })];
|
|
418
476
|
}
|
|
419
477
|
const arkParams = buildArkParams(val);
|
|
@@ -494,21 +552,21 @@ const sendGuildMessage = async (content, val, baseParams, sendMessage, label) =>
|
|
|
494
552
|
}
|
|
495
553
|
return [];
|
|
496
554
|
};
|
|
497
|
-
const GROUP_AT_MESSAGE_CREATE = async (client, event, val) => {
|
|
555
|
+
const GROUP_AT_MESSAGE_CREATE = async (client, event, val, options) => {
|
|
498
556
|
const baseParams = buildBaseParams(event._tag, event.MessageId, 'INTERACTION_CREATE_GROUP');
|
|
499
557
|
const content = extractContent(val, 'group');
|
|
500
558
|
try {
|
|
501
|
-
return await sendOpenApiMessage(content, val, baseParams, data => client.postRichMediaByGroup(event.ChannelId, data), data => client.groupOpenMessages(event.ChannelId, data), 'client.groupOpenMessages');
|
|
559
|
+
return await sendOpenApiMessage(content, val, baseParams, data => client.postRichMediaByGroup(event.ChannelId, data), data => client.groupOpenMessages(event.ChannelId, data), 'client.groupOpenMessages', options);
|
|
502
560
|
}
|
|
503
561
|
catch (err) {
|
|
504
562
|
return [createResult(ResultCode.Fail, err?.response?.data ?? err?.message ?? err, null)];
|
|
505
563
|
}
|
|
506
564
|
};
|
|
507
|
-
const C2C_MESSAGE_CREATE = async (client, event, val) => {
|
|
565
|
+
const C2C_MESSAGE_CREATE = async (client, event, val, options) => {
|
|
508
566
|
const baseParams = buildBaseParams(event._tag, event.MessageId, 'INTERACTION_CREATE_C2C');
|
|
509
567
|
const content = extractContent(val, 'group');
|
|
510
568
|
try {
|
|
511
|
-
return await sendOpenApiMessage(content, val, baseParams, data => client.postRichMediaByUser(event.UserId, data), data => client.usersOpenMessages(event.UserId, data), 'client.usersOpenMessages');
|
|
569
|
+
return await sendOpenApiMessage(content, val, baseParams, data => client.postRichMediaByUser(event.UserId, data), data => client.usersOpenMessages(event.UserId, data), 'client.usersOpenMessages', options);
|
|
512
570
|
}
|
|
513
571
|
catch (err) {
|
|
514
572
|
return [createResult(ResultCode.Fail, err?.response?.data ?? err?.message ?? err, null)];
|
package/lib/upload.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { QQBotAPI } from './sdk/api';
|
|
2
|
+
import { FileType } from './sdk/typing';
|
|
3
|
+
export declare const CHUNK_THRESHOLD = 10002432;
|
|
4
|
+
export declare const fileDataToBuffer: (fileData: any) => Buffer | null;
|
|
5
|
+
export declare const computeFileDigests: (filePath: string) => {
|
|
6
|
+
buffer: NonSharedBuffer;
|
|
7
|
+
md5: string;
|
|
8
|
+
sha1: string;
|
|
9
|
+
md5_10m: string;
|
|
10
|
+
};
|
|
11
|
+
export declare const chunkedUpload: (client: QQBotAPI, scope: "user" | "group", openId: string, file: string | Buffer, options: {
|
|
12
|
+
file_type: FileType;
|
|
13
|
+
file_name?: string;
|
|
14
|
+
srv_send_msg?: boolean;
|
|
15
|
+
}) => Promise<{
|
|
16
|
+
file_uuid: string;
|
|
17
|
+
file_info: string;
|
|
18
|
+
ttl: number;
|
|
19
|
+
id?: string;
|
|
20
|
+
raw_url?: string;
|
|
21
|
+
}>;
|
package/lib/upload.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
|
|
4
|
+
const CHUNK_THRESHOLD = 10002432;
|
|
5
|
+
const fileDataToBuffer = (fileData) => {
|
|
6
|
+
if (!fileData) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
if (Buffer.isBuffer(fileData)) {
|
|
10
|
+
return fileData;
|
|
11
|
+
}
|
|
12
|
+
if (typeof fileData === 'string') {
|
|
13
|
+
if (fileData.indexOf('base64://') === 0) {
|
|
14
|
+
return Buffer.from(fileData.replace('base64://', ''), 'base64');
|
|
15
|
+
}
|
|
16
|
+
return Buffer.from(fileData, 'base64');
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
};
|
|
20
|
+
const computeFileDigests = (filePath) => {
|
|
21
|
+
const buffer = readFileSync(filePath);
|
|
22
|
+
const md5 = createHash('md5').update(buffer).digest('hex');
|
|
23
|
+
const sha1 = createHash('sha1').update(buffer).digest('hex');
|
|
24
|
+
const md5_10m = createHash('md5').update(buffer.subarray(0, CHUNK_THRESHOLD)).digest('hex');
|
|
25
|
+
return { buffer, md5, sha1, md5_10m };
|
|
26
|
+
};
|
|
27
|
+
const chunkedUpload = async (client, scope, openId, file, options) => {
|
|
28
|
+
const buffer = typeof file === 'string' ? readFileSync(file) : file;
|
|
29
|
+
const md5 = createHash('md5').update(buffer).digest('hex');
|
|
30
|
+
const sha1 = createHash('sha1').update(buffer).digest('hex');
|
|
31
|
+
const md5_10m = createHash('md5').update(buffer.subarray(0, CHUNK_THRESHOLD)).digest('hex');
|
|
32
|
+
const file_name = options.file_name ?? (typeof file === 'string' ? (file.split(/[\\/]/).pop() ?? 'file') : 'file');
|
|
33
|
+
const prepareData = {
|
|
34
|
+
file_type: options.file_type,
|
|
35
|
+
file_name,
|
|
36
|
+
file_size: String(buffer.byteLength),
|
|
37
|
+
md5,
|
|
38
|
+
sha1,
|
|
39
|
+
md5_10m
|
|
40
|
+
};
|
|
41
|
+
const prepare = await (scope === 'user' ? client.usersUploadPrepare(openId, prepareData) : client.groupUploadPrepare(openId, prepareData));
|
|
42
|
+
const blockSize = Number(prepare.block_size);
|
|
43
|
+
for (const part of prepare.parts) {
|
|
44
|
+
const start = part.index * blockSize;
|
|
45
|
+
const chunk = Buffer.from(buffer.subarray(start, start + Number(part.block_size)));
|
|
46
|
+
const partMd5 = createHash('md5').update(chunk).digest('hex');
|
|
47
|
+
await client.uploadPartDirect(part.presigned_url, chunk);
|
|
48
|
+
const finishData = {
|
|
49
|
+
upload_id: prepare.upload_id,
|
|
50
|
+
part_index: part.index,
|
|
51
|
+
block_size: part.block_size,
|
|
52
|
+
md5: partMd5
|
|
53
|
+
};
|
|
54
|
+
await (scope === 'user' ? client.usersUploadPartFinish(openId, finishData) : client.groupUploadPartFinish(openId, finishData));
|
|
55
|
+
}
|
|
56
|
+
const merge = { file_type: options.file_type, upload_id: prepare.upload_id, file_name, srv_send_msg: options.srv_send_msg };
|
|
57
|
+
return scope === 'user' ? client.postRichMediaByUser(openId, merge) : client.postRichMediaByGroup(openId, merge);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export { CHUNK_THRESHOLD, chunkedUpload, computeFileDigests, fileDataToBuffer };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alemonjs/qq-bot",
|
|
3
|
-
"version": "2.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.1.33",
|
|
4
|
+
"description": "QQ官方平台",
|
|
5
5
|
"author": "lemonade",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"type": "module",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
}
|
|
56
56
|
],
|
|
57
57
|
"config-source": {
|
|
58
|
-
"readme": "https://
|
|
58
|
+
"readme": "https://raw.githubusercontent.com/lemonade-lab/alemonjs/main/packages/qq-bot/README.md",
|
|
59
59
|
"official": "https://bot.q.qq.com/wiki/develop/api-v2/",
|
|
60
60
|
"platform": "https://q.qq.com/"
|
|
61
61
|
},
|
|
@@ -94,5 +94,5 @@
|
|
|
94
94
|
"type": "git",
|
|
95
95
|
"url": "https://github.com/lemonade-lab/alemonjs.git"
|
|
96
96
|
},
|
|
97
|
-
"gitHead": "
|
|
97
|
+
"gitHead": "6c93b0455b8db78ffa1a83becc1c2de19ba544db"
|
|
98
98
|
}
|