@alemonjs/qq-bot 2.1.31 → 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/lib/register.js CHANGED
@@ -1,15 +1,20 @@
1
- import { cbpPlatform, FormatEvent, ResultCode, createResult } from 'alemonjs';
1
+ import { cbpPlatform, FormatEvent, createResult, ResultCode, logger } from 'alemonjs';
2
+ import { createHash } from 'node:crypto';
3
+ import { stat, readFile } from 'node:fs/promises';
4
+ import { basename } from 'node:path';
5
+ import { chunkedUpload } from './upload.js';
2
6
  import { GROUP_AT_MESSAGE_CREATE, C2C_MESSAGE_CREATE, DIRECT_MESSAGE_CREATE, AT_MESSAGE_CREATE, MESSAGE_CREATE } from './sends.js';
3
7
  import { getQQBotConfig, platform, getMaster, getIdentity } from './config.js';
4
8
 
5
- const register = (client) => {
9
+ const register = (client, options) => {
10
+ const MAX_MEDIA_SIZE = 100 * 1024 * 1024;
6
11
  const config = getQQBotConfig();
7
- const botId = String(config?.app_id ?? '');
12
+ const botId = String(options?.botId ?? config?.app_id ?? '');
8
13
  const port = process.env?.port || config?.port || 17117;
9
14
  const url = `ws://127.0.0.1:${port}`;
10
- const cbp = cbpPlatform(url);
15
+ const cbp = options?.cbp ?? cbpPlatform(url);
11
16
  const createUserAvatarURL = (authorId) => {
12
- return `https://q.qlogo.cn/qqapp/${config.app_id}/${authorId}/640`;
17
+ return `https://q.qlogo.cn/qqapp/${botId}/${authorId}/640`;
13
18
  };
14
19
  const getGroupMessageMeta = (event) => {
15
20
  const author = event?.author;
@@ -39,6 +44,122 @@ const register = (client) => {
39
44
  auditTime
40
45
  };
41
46
  };
47
+ const getMediaItems = (attachments) => {
48
+ return (attachments || []).flatMap(attachment => {
49
+ if (!attachment?.url) {
50
+ return [];
51
+ }
52
+ const mimeType = attachment.content_type || '';
53
+ const Type = mimeType.startsWith('image/')
54
+ ? 'image'
55
+ : mimeType.startsWith('audio/')
56
+ ? 'audio'
57
+ : mimeType.startsWith('video/')
58
+ ? 'video'
59
+ : 'file';
60
+ return [
61
+ {
62
+ Type,
63
+ Url: attachment.url,
64
+ ...(attachment.filename && { FileName: attachment.filename }),
65
+ ...(typeof attachment.size === 'number' && { FileSize: attachment.size }),
66
+ ...(mimeType && { MimeType: mimeType })
67
+ }
68
+ ];
69
+ });
70
+ };
71
+ const normalizeTarget = (target) => {
72
+ if (!target?.targetId || !target.scope) {
73
+ return undefined;
74
+ }
75
+ return target;
76
+ };
77
+ const validateTargetBot = (target) => {
78
+ return !target.BotId || target.BotId === botId;
79
+ };
80
+ const mediaCache = new Map();
81
+ const mediaType = (type) => (type === 'image' ? 1 : type === 'video' ? 2 : type === 'audio' ? 3 : 4);
82
+ const prepareMedia = async (target, params) => {
83
+ const sources = [params?.url, params?.data, params?.filePath, params?.fileId].filter(value => value !== undefined && value !== '').length;
84
+ if (sources !== 1) {
85
+ throw new Error('Provide exactly one media source: url, data, filePath, or fileId');
86
+ }
87
+ if (params.fileId) {
88
+ return { fileId: String(params.fileId), reused: true };
89
+ }
90
+ let data = params.data;
91
+ let buffer;
92
+ let filePath;
93
+ let fileSize;
94
+ let hashes;
95
+ let name = params.name;
96
+ let hashSource = String(params.url || '');
97
+ if (params.filePath) {
98
+ const metadata = await stat(String(params.filePath));
99
+ if (!metadata.isFile()) {
100
+ throw new Error('media filePath must point to a regular file');
101
+ }
102
+ if (metadata.size > MAX_MEDIA_SIZE) {
103
+ throw new Error('QQ media files must not exceed 100 MiB');
104
+ }
105
+ filePath = String(params.filePath);
106
+ fileSize = metadata.size;
107
+ hashes = await client.getMediaFileHashes(filePath);
108
+ hashSource = hashes.sha256;
109
+ name ||= basename(filePath);
110
+ if (fileSize < 5 * 1024 * 1024) {
111
+ buffer = await readFile(filePath);
112
+ data = `base64://${buffer.toString('base64')}`;
113
+ }
114
+ }
115
+ else if (data) {
116
+ hashSource = data;
117
+ const value = data.replace(/^base64:\/\//, '');
118
+ buffer = Buffer.from(value, 'base64');
119
+ if (buffer.length > MAX_MEDIA_SIZE) {
120
+ throw new Error('QQ media files must not exceed 100 MiB');
121
+ }
122
+ }
123
+ const key = [botId, target.scope, target.targetId, params.type, createHash('sha256').update(hashSource).digest('hex')].join(':');
124
+ const cached = mediaCache.get(key);
125
+ if (cached && (!cached.expiresAt || cached.expiresAt > Date.now())) {
126
+ return { fileId: cached.fileId, expiresAt: cached.expiresAt, reused: true };
127
+ }
128
+ return { key, url: params.url, data, buffer, filePath, fileSize, hashes, name, reused: false };
129
+ };
130
+ const uploadMedia = async (target, params) => {
131
+ if (!validateTargetBot(target)) {
132
+ throw new Error(`BotId ${target.BotId} is not active`);
133
+ }
134
+ if (target.scope !== 'group' && target.scope !== 'c2c') {
135
+ throw new Error('QQ media upload only supports group and c2c targets');
136
+ }
137
+ const prepared = await prepareMedia(target, params);
138
+ if (prepared.fileId) {
139
+ return prepared;
140
+ }
141
+ const fileType = mediaType(params.type);
142
+ const value = prepared.filePath && prepared.fileSize && prepared.fileSize >= 5 * 1024 * 1024
143
+ ? await client.postChunkedRichMedia({
144
+ scope: target.scope,
145
+ targetId: target.targetId,
146
+ fileType,
147
+ filePath: prepared.filePath,
148
+ size: prepared.fileSize,
149
+ hashes: prepared.hashes,
150
+ name: prepared.name
151
+ })
152
+ : prepared.buffer && prepared.buffer.length >= 5 * 1024 * 1024
153
+ ? await client.postChunkedRichMedia({ scope: target.scope, targetId: target.targetId, fileType, data: prepared.buffer, name: prepared.name })
154
+ : target.scope === 'group'
155
+ ? await client.postRichMediaByGroup(target.targetId, { file_type: fileType, url: prepared.url, file_data: prepared.data, srv_send_msg: false })
156
+ : await client.postRichMediaByUser(target.targetId, { file_type: fileType, url: prepared.url, file_data: prepared.data, srv_send_msg: false });
157
+ const expiresAt = value.ttl ? Date.now() + value.ttl * 1000 : undefined;
158
+ if (prepared.key) {
159
+ mediaCache.set(prepared.key, { fileId: value.file_info, expiresAt });
160
+ }
161
+ return { fileId: value.file_info, expiresAt, reused: false };
162
+ };
42
163
  const createUserMeta = (UserId, extra = {}) => {
43
164
  const [IsMaster, UserKey] = getIdentity(UserId);
44
165
  return {
@@ -85,6 +206,7 @@ const register = (client) => {
85
206
  })
86
207
  .addMessage({ MessageId: meta.messageId })
87
208
  .addText({ MessageText: msg?.trim() })
209
+ .addMedia({ MessageMedia: getMediaItems(event.attachments) })
88
210
  .addOpen({ OpenId: meta.openId })
89
211
  .add({ tag: 'GROUP_MESSAGE_CREATE' }).value);
90
212
  });
@@ -108,6 +230,24 @@ const register = (client) => {
108
230
  .addUser({ UserId: UserId, UserKey, UserName: event?.username ?? '', UserAvatar: createUserAvatarURL(UserId), IsMaster: isMaster, IsBot: false })
109
231
  .add({ tag: 'GROUP_MEMBER_REMOVE' }).value);
110
232
  });
233
+ client.on('GROUP_JOIN_REQUEST', event => {
234
+ const UserId = event.member_openid ?? '';
235
+ const [isMaster, UserKey] = getMaster(UserId);
236
+ cbp.send(FormatEvent.create('notice.create')
237
+ .addPlatform({ Platform: platform, value: event, BotId: botId })
238
+ .addGuild({ GuildId: event.group_openid ?? '', SpaceId: `GROUP:${event.group_openid ?? ''}` })
239
+ .addChannel({ ChannelId: event.group_openid ?? '' })
240
+ .addUser({
241
+ UserId: UserId,
242
+ UserKey,
243
+ UserName: event?.username ?? '',
244
+ UserAvatar: createUserAvatarURL(UserId),
245
+ IsMaster: isMaster,
246
+ IsBot: event.bot ?? false
247
+ })
248
+ .addMessage({ MessageId: `group_join_request_${event.group_openid}_${event.join_request_id}` })
249
+ .add({ tag: 'GROUP_JOIN_REQUEST' }).value);
250
+ });
111
251
  client.on('GROUP_AT_MESSAGE_CREATE', event => {
112
252
  if (event?.author?.bot) {
113
253
  return;
@@ -128,6 +268,7 @@ const register = (client) => {
128
268
  })
129
269
  .addMessage({ MessageId: meta.messageId })
130
270
  .addText({ MessageText: msg?.trim() })
271
+ .addMedia({ MessageMedia: getMediaItems(event.attachments) })
131
272
  .addOpen({ OpenId: meta.openId })
132
273
  .add({ tag: 'GROUP_AT_MESSAGE_CREATE' }).value);
133
274
  });
@@ -147,6 +288,7 @@ const register = (client) => {
147
288
  })
148
289
  .addMessage({ MessageId: event.id })
149
290
  .addText({ MessageText: event.content?.trim() })
291
+ .addMedia({ MessageMedia: getMediaItems(event.attachments) })
150
292
  .addOpen({ OpenId: `C2C:${event.author.user_openid}` })
151
293
  .add({ tag: 'C2C_MESSAGE_CREATE' }).value);
152
294
  });
@@ -170,6 +312,7 @@ const register = (client) => {
170
312
  })
171
313
  .addMessage({ MessageId: event.id })
172
314
  .addText({ MessageText: msg?.trim() })
315
+ .addMedia({ MessageMedia: getMediaItems(event.attachments) })
173
316
  .addOpen({ OpenId: `DIRECT:${event.guild_id}` })
174
317
  .add({ tag: 'DIRECT_MESSAGE_CREATE' }).value);
175
318
  });
@@ -195,6 +338,7 @@ const register = (client) => {
195
338
  })
196
339
  .addMessage({ MessageId: event.id })
197
340
  .addText({ MessageText: msg?.trim() })
341
+ .addMedia({ MessageMedia: getMediaItems(event.attachments) })
198
342
  .addOpen({ OpenId: `DIRECT:${event.guild_id}` })
199
343
  .add({ tag: 'AT_MESSAGE_CREATE' }).value);
200
344
  });
@@ -238,10 +382,17 @@ const register = (client) => {
238
382
  })
239
383
  .addMessage({ MessageId: event.id })
240
384
  .addText({ MessageText: msg?.trim() })
385
+ .addMedia({ MessageMedia: getMediaItems(event.attachments) })
241
386
  .addOpen({ OpenId: `DIRECT:${event.guild_id}` })
242
387
  .add({ tag: 'MESSAGE_CREATE' }).value);
243
388
  });
244
- client.on('INTERACTION_CREATE', event => {
389
+ client.on('INTERACTION_CREATE', async (event) => {
390
+ try {
391
+ await client.interactionResponse('group', event.id, 0);
392
+ }
393
+ catch (err) {
394
+ createResult(ResultCode.Fail, 'interactionResponse failed', err?.response?.data ?? err?.message ?? err);
395
+ }
245
396
  if (event.scene === 'group') {
246
397
  const UserAvatar = createUserAvatarURL(event.group_member_openid);
247
398
  const UserId = event.group_member_openid;
@@ -258,8 +409,13 @@ const register = (client) => {
258
409
  IsMaster: isMaster,
259
410
  IsBot: false
260
411
  })
261
- .addMessage({ MessageId: `INTERACTION_CREATE:${event.id}` })
412
+ .addMessage({ MessageId: event.id })
262
413
  .addText({ MessageText: MessageText })
414
+ .addInteraction({
415
+ InteractionId: event.id,
416
+ InteractionData: JSON.stringify(event.data.resolved),
417
+ Target: { scope: 'group', targetId: event.group_openid, BotId: botId }
418
+ })
263
419
  .addOpen({ OpenId: `C2C:${event.group_member_openid}` })
264
420
  .add({ tag: 'INTERACTION_CREATE_GROUP' }).value;
265
421
  cbp.send(e);
@@ -280,6 +436,11 @@ const register = (client) => {
280
436
  })
281
437
  .addMessage({ MessageId: event.id })
282
438
  .addText({ MessageText: MessageText })
439
+ .addInteraction({
440
+ InteractionId: event.id,
441
+ InteractionData: JSON.stringify(event.data.resolved),
442
+ Target: { scope: 'c2c', targetId: event.user_openid, BotId: botId }
443
+ })
283
444
  .addOpen({ OpenId: `C2C:${event.user_openid}` })
284
445
  .add({ tag: 'INTERACTION_CREATE_C2C' }).value;
285
446
  cbp.send(e);
@@ -296,6 +457,11 @@ const register = (client) => {
296
457
  .addUser({ UserId: event.data.resolved.user_id, UserKey, UserAvatar: UserAvatar, IsMaster: isMaster, IsBot: false })
297
458
  .addMessage({ MessageId: event.data.resolved.message_id })
298
459
  .addText({ MessageText: MessageText })
460
+ .addInteraction({
461
+ InteractionId: event.id,
462
+ InteractionData: JSON.stringify(event.data.resolved),
463
+ Target: { scope: 'channel', targetId: event.channel_id, BotId: botId }
464
+ })
299
465
  .addOpen({ OpenId: `DIRECT:${event.guild_id}` })
300
466
  .add({ tag: 'INTERACTION_CREATE_GUILD' }).value;
301
467
  cbp.send(e);
@@ -483,6 +649,24 @@ const register = (client) => {
483
649
  const api = {
484
650
  active: {
485
651
  send: {
652
+ target: async (target, val, replyId) => {
653
+ if (!validateTargetBot(target)) {
654
+ return [createResult(ResultCode.FailParams, `BotId ${target.BotId} is not active`, null)];
655
+ }
656
+ if (target.scope === 'group') {
657
+ return GROUP_AT_MESSAGE_CREATE(client, { ChannelId: target.targetId, MessageId: replyId }, val);
658
+ }
659
+ if (target.scope === 'c2c') {
660
+ return C2C_MESSAGE_CREATE(client, { UserId: target.targetId, MessageId: replyId }, val);
661
+ }
662
+ if (target.scope === 'channel') {
663
+ return AT_MESSAGE_CREATE(client, { ChannelId: target.targetId, MessageId: replyId }, val);
664
+ }
665
+ if (target.scope === 'direct') {
666
+ return DIRECT_MESSAGE_CREATE(client, { UserId: target.targetId, MessageId: replyId }, val);
667
+ }
668
+ return [createResult(ResultCode.FailParams, `Unsupported target scope: ${target.scope}`, null)];
669
+ },
486
670
  channel: async (SpaceId, val) => {
487
671
  if (/^GUILD:/.test(SpaceId)) {
488
672
  const id = SpaceId.replace('GUILD:', '');
@@ -522,19 +706,19 @@ const register = (client) => {
522
706
  }
523
707
  },
524
708
  use: {
525
- send: async (event, val) => {
709
+ send: async (event, val, options) => {
526
710
  if (!val || val.length <= 0) {
527
711
  return [];
528
712
  }
529
713
  const tag = event._tag;
530
714
  if (tag === 'GROUP_AT_MESSAGE_CREATE') {
531
- return await GROUP_AT_MESSAGE_CREATE(client, event, val);
715
+ return await GROUP_AT_MESSAGE_CREATE(client, event, val, options);
532
716
  }
533
717
  if (tag === 'GROUP_MESSAGE_CREATE') {
534
- return await GROUP_AT_MESSAGE_CREATE(client, event, val);
718
+ return await GROUP_AT_MESSAGE_CREATE(client, event, val, options);
535
719
  }
536
720
  if (tag === 'C2C_MESSAGE_CREATE') {
537
- return await C2C_MESSAGE_CREATE(client, event, val);
721
+ return await C2C_MESSAGE_CREATE(client, event, val, options);
538
722
  }
539
723
  if (tag === 'DIRECT_MESSAGE_CREATE') {
540
724
  return await DIRECT_MESSAGE_CREATE(client, event, val);
@@ -546,10 +730,10 @@ const register = (client) => {
546
730
  return await MESSAGE_CREATE(client, event, val);
547
731
  }
548
732
  if (tag === 'INTERACTION_CREATE_GROUP') {
549
- return await GROUP_AT_MESSAGE_CREATE(client, event, val);
733
+ return await GROUP_AT_MESSAGE_CREATE(client, event, val, options);
550
734
  }
551
735
  if (tag === 'INTERACTION_CREATE_C2C') {
552
- return await C2C_MESSAGE_CREATE(client, event, val);
736
+ return await C2C_MESSAGE_CREATE(client, event, val, options);
553
737
  }
554
738
  if (tag === 'INTERACTION_CREATE_GUILD') {
555
739
  return await AT_MESSAGE_CREATE(client, event, val);
@@ -581,6 +765,12 @@ const register = (client) => {
581
765
  }
582
766
  };
583
767
  const onactions = async (data, consume) => {
768
+ const event = data.payload.event ?? {};
769
+ const getGroupOpenId = () => data.payload.ChannelId ?? data.payload.params?.groupOpenId ?? data.payload.GuildId ?? event.ChannelId ?? event.GuildId ?? '';
770
+ const getMemberOpenId = () => data.payload.params?.memberOpenId ?? data.payload.UserId ?? event.UserId ?? '';
771
+ const getGuildId = () => data.payload.GuildId ?? event.GuildId ?? '';
772
+ const getUserId = () => data.payload.UserId ?? event.UserId ?? '';
773
+ const getChannelId = () => data.payload.ChannelId ?? event.ChannelId ?? '';
584
774
  try {
585
775
  if (data.action === 'me.info') {
586
776
  const res = await client.usersMe();
@@ -599,7 +789,8 @@ const register = (client) => {
599
789
  else if (data.action === 'message.send') {
600
790
  const event = data.payload.event;
601
791
  const paramFormat = data.payload.params.format;
602
- const res = await api.use.send(event, paramFormat);
792
+ const options = data.payload.params?.forceVerifyImageResource !== undefined ? { forceVerifyImageResource: data.payload.params.forceVerifyImageResource } : undefined;
793
+ const res = await api.use.send(event, paramFormat, options);
603
794
  consume(res);
604
795
  }
605
796
  else if (data.action === 'mention.get') {
@@ -619,53 +810,96 @@ const register = (client) => {
619
810
  const res = await api.active.send.user(userId, paramFormat);
620
811
  consume(res);
621
812
  }
813
+ else if (data.action === 'message.send.target') {
814
+ const target = normalizeTarget(data.payload.target);
815
+ if (!target) {
816
+ consume([createResult(ResultCode.FailParams, 'message.send.target 缺少 target', null)]);
817
+ return;
818
+ }
819
+ const res = await api.active.send.target(target, data.payload.params?.format || [], data.payload.params?.replyId);
820
+ consume(res);
821
+ }
622
822
  else if (data.action === 'message.delete') {
623
- const channelId = data.payload.ChannelId;
624
823
  const messageId = data.payload.MessageId;
824
+ const params = data.payload.params ?? {};
825
+ const target = normalizeTarget(data.payload.target);
826
+ if (target && !validateTargetBot(target)) {
827
+ consume([createResult(ResultCode.FailParams, `BotId ${target.BotId} is not active`, null)]);
828
+ return;
829
+ }
830
+ const scope = target?.scope ?? params.scope ?? params.messageType;
831
+ const request = scope === 'group'
832
+ ? client.grouMessageDelte(String(target?.targetId ?? params.groupId ?? data.payload.GroupId ?? data.payload.ChannelId), messageId)
833
+ : scope === 'user' || scope === 'c2c'
834
+ ? client.userMessageDelete(String(target?.targetId ?? params.userId ?? data.payload.UserId), messageId)
835
+ : scope === 'direct'
836
+ ? client.dmsMessageDelete(String(target?.targetId ?? params.guildId ?? data.payload.GuildId ?? data.payload.ChannelId), messageId)
837
+ : client.channelsMessagesDelete(target?.targetId ?? data.payload.ChannelId, messageId);
838
+ const res = await request.then(r => createResult(ResultCode.Ok, data.action, r)).catch(err => createResult(ResultCode.Fail, data.action, err));
839
+ consume([res]);
840
+ }
841
+ else if (data.action === 'interaction.ack') {
842
+ const params = data.payload.params ?? {};
843
+ const interactionId = String(params.interactionId ?? data.payload.InteractionId ?? '');
844
+ const mode = data.payload.target?.scope === 'channel' || data.payload.target?.scope === 'direct' || params.mode === 'guild' ? 'guild' : 'group';
845
+ if (!interactionId) {
846
+ consume([createResult(ResultCode.Fail, 'interaction.ack 缺少 InteractionId', null)]);
847
+ return;
848
+ }
625
849
  const res = await client
626
- .channelsMessagesDelete(channelId, messageId)
850
+ .interactionResponse(mode, interactionId, params.code)
627
851
  .then(r => createResult(ResultCode.Ok, data.action, r))
628
852
  .catch(err => createResult(ResultCode.Fail, data.action, err));
629
853
  consume([res]);
854
+ consume([res]);
630
855
  }
631
856
  else if (data.action === 'message.pin') {
632
857
  const res = await client
633
- .channelsPinsPut(data.payload.ChannelId, data.payload.MessageId)
858
+ .channelsPinsPut(getChannelId(), data.payload.MessageId)
634
859
  .then(r => createResult(ResultCode.Ok, data.action, r))
635
860
  .catch(err => createResult(ResultCode.Fail, data.action, err));
636
861
  consume([res]);
637
862
  }
638
863
  else if (data.action === 'message.unpin') {
639
864
  const res = await client
640
- .channelsPinsDelete(data.payload.ChannelId, data.payload.MessageId)
865
+ .channelsPinsDelete(getChannelId(), data.payload.MessageId)
641
866
  .then(r => createResult(ResultCode.Ok, data.action, r))
642
867
  .catch(err => createResult(ResultCode.Fail, data.action, err));
643
868
  consume([res]);
644
869
  }
645
870
  else if (data.action === 'reaction.add') {
646
871
  const res = await client
647
- .channelsMessagesReactionsPut(data.payload.ChannelId, data.payload.MessageId, 1, data.payload.EmojiId)
872
+ .channelsMessagesReactionsPut(getChannelId(), data.payload.MessageId, 1, data.payload.EmojiId)
648
873
  .then(r => createResult(ResultCode.Ok, data.action, r))
649
874
  .catch(err => createResult(ResultCode.Fail, data.action, err));
650
875
  consume([res]);
651
876
  }
652
877
  else if (data.action === 'reaction.remove') {
653
878
  const res = await client
654
- .channelsMessagesReactionsDelete(data.payload.ChannelId, data.payload.MessageId, 1, data.payload.EmojiId)
879
+ .channelsMessagesReactionsDelete(getChannelId(), data.payload.MessageId, 1, data.payload.EmojiId)
655
880
  .then(r => createResult(ResultCode.Ok, data.action, r))
656
881
  .catch(err => createResult(ResultCode.Fail, data.action, err));
657
882
  consume([res]);
658
883
  }
659
884
  else if (data.action === 'message.get') {
660
885
  const res = await client
661
- .channelsMessagesById(data.payload.ChannelId, data.payload.MessageId)
886
+ .channelsMessagesById(getChannelId(), data.payload.MessageId)
662
887
  .then(r => createResult(ResultCode.Ok, data.action, r))
663
888
  .catch(err => createResult(ResultCode.Fail, data.action, err));
664
889
  consume([res]);
665
890
  }
891
+ else if (data.action === 'interaction.response') {
892
+ const interactionId = data.payload.interaction_id;
893
+ const code = data.payload.code ?? 0;
894
+ const res = await client
895
+ .interactionResponse('group', interactionId, code)
896
+ .then(r => createResult(ResultCode.Ok, data.action, r))
897
+ .catch(err => createResult(ResultCode.Fail, data.action, err?.response?.data ?? err?.message ?? err));
898
+ consume([res]);
899
+ }
666
900
  else if (data.action === 'member.info') {
667
- const guildId = data.payload.params?.guildId ?? data.payload.GuildId;
668
- const userId = data.payload.params?.userId ?? data.payload.UserId;
901
+ const guildId = data.payload.params?.guildId ?? getGuildId();
902
+ const userId = data.payload.params?.userId ?? getUserId();
669
903
  const res = await client
670
904
  .guildsMembersMessage(guildId, userId)
671
905
  .then(r => createResult(ResultCode.Ok, data.action, r))
@@ -673,7 +907,7 @@ const register = (client) => {
673
907
  consume([res]);
674
908
  }
675
909
  else if (data.action === 'member.list') {
676
- const guildId = data.payload.GuildId;
910
+ const guildId = getGuildId();
677
911
  const after = data.payload.params?.After ?? '0';
678
912
  const limit = data.payload.params?.Limit ?? 100;
679
913
  const res = await client
@@ -684,14 +918,14 @@ const register = (client) => {
684
918
  }
685
919
  else if (data.action === 'member.kick') {
686
920
  const res = await client
687
- .guildsMembersDelete(data.payload.GuildId, data.payload.UserId)
921
+ .guildsMembersDelete(getGuildId(), getUserId())
688
922
  .then(r => createResult(ResultCode.Ok, data.action, r))
689
923
  .catch(err => createResult(ResultCode.Fail, data.action, err));
690
924
  consume([res]);
691
925
  }
692
926
  else if (data.action === 'member.ban') {
693
- const guildId = data.payload.GuildId;
694
- const userId = data.payload.UserId;
927
+ const guildId = getGuildId();
928
+ const userId = getUserId();
695
929
  const duration = data.payload.params?.duration ?? 0;
696
930
  const mute_seconds = String(duration > 0 ? duration : 604800);
697
931
  const res = await client
@@ -702,14 +936,14 @@ const register = (client) => {
702
936
  }
703
937
  else if (data.action === 'member.unban') {
704
938
  const res = await client
705
- .guildsMemberMute(data.payload.GuildId, data.payload.UserId, { mute_seconds: '0' })
939
+ .guildsMemberMute(getGuildId(), getUserId(), { mute_seconds: '0' })
706
940
  .then(r => createResult(ResultCode.Ok, data.action, r))
707
941
  .catch(err => createResult(ResultCode.Fail, data.action, err));
708
942
  consume([res]);
709
943
  }
710
944
  else if (data.action === 'member.mute') {
711
- const guildId = data.payload.GuildId;
712
- const userId = data.payload.UserId;
945
+ const guildId = getGuildId();
946
+ const userId = getUserId();
713
947
  const duration = data.payload.params?.duration ?? 0;
714
948
  const mute_seconds = String(duration);
715
949
  const res = await client
@@ -720,7 +954,7 @@ const register = (client) => {
720
954
  }
721
955
  else if (data.action === 'guild.info') {
722
956
  const res = await client
723
- .guilds(data.payload.GuildId)
957
+ .guilds(getGuildId())
724
958
  .then(r => createResult(ResultCode.Ok, data.action, r))
725
959
  .catch(err => createResult(ResultCode.Fail, data.action, err));
726
960
  consume([res]);
@@ -733,7 +967,7 @@ const register = (client) => {
733
967
  consume([res]);
734
968
  }
735
969
  else if (data.action === 'guild.mute') {
736
- const guildId = data.payload.GuildId;
970
+ const guildId = getGuildId();
737
971
  const duration = data.payload.params?.duration ?? 0;
738
972
  const mute_seconds = String(duration);
739
973
  const res = await client
@@ -742,22 +976,135 @@ const register = (client) => {
742
976
  .catch(err => createResult(ResultCode.Fail, data.action, err));
743
977
  consume([res]);
744
978
  }
979
+ else if (data.action === 'group.info') {
980
+ const res = await client
981
+ .groupsInfo(getGroupOpenId())
982
+ .then(r => createResult(ResultCode.Ok, data.action, r))
983
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
984
+ consume([res]);
985
+ }
986
+ else if (data.action === 'group.botState') {
987
+ const res = await client
988
+ .groupsBotState(getGroupOpenId())
989
+ .then(r => createResult(ResultCode.Ok, data.action, r))
990
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
991
+ consume([res]);
992
+ }
993
+ else if (data.action === 'group.member.info') {
994
+ const res = await client
995
+ .groupsMembersMessage(getGroupOpenId(), getMemberOpenId())
996
+ .then(r => createResult(ResultCode.Ok, data.action, r))
997
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
998
+ consume([res]);
999
+ }
1000
+ else if (data.action === 'group.joinRequest.list') {
1001
+ const params = data.payload.params ?? {};
1002
+ const res = await client
1003
+ .groupsJoinRequestList(getGroupOpenId(), { cursor: params.cursor, limit: params.limit })
1004
+ .then(r => createResult(ResultCode.Ok, data.action, r))
1005
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
1006
+ consume([res]);
1007
+ }
1008
+ else if (data.action === 'group.joinRequest.approve') {
1009
+ const params = data.payload.params ?? {};
1010
+ const res = await client
1011
+ .groupsApprovalJoinRequest(getGroupOpenId(), getMemberOpenId(), {
1012
+ op: params.op,
1013
+ join_request_id: params.joinRequestId,
1014
+ reject_reason: params.rejectReason,
1015
+ add_to_member_blacklist: params.addToMemberBlacklist
1016
+ })
1017
+ .then(r => createResult(ResultCode.Ok, data.action, r))
1018
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
1019
+ consume([res]);
1020
+ }
1021
+ else if (data.action === 'group.mute.setting') {
1022
+ const res = await client
1023
+ .groupsRestrictChatSetting(getGroupOpenId())
1024
+ .then(r => createResult(ResultCode.Ok, data.action, r))
1025
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
1026
+ consume([res]);
1027
+ }
1028
+ else if (data.action === 'group.mute.set') {
1029
+ const res = await client
1030
+ .groupsRestrictChatSettingPost(getGroupOpenId(), { members: data.payload.params?.members })
1031
+ .then(r => createResult(ResultCode.Ok, data.action, r))
1032
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
1033
+ consume([res]);
1034
+ }
1035
+ else if (data.action === 'group.strategy.list') {
1036
+ const params = data.payload.params ?? {};
1037
+ const res = await client
1038
+ .groupsJoinApprovalStrategies({ cursor: params.cursor, limit: params.limit })
1039
+ .then(r => createResult(ResultCode.Ok, data.action, r))
1040
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
1041
+ consume([res]);
1042
+ }
1043
+ else if (data.action === 'group.strategy.create') {
1044
+ const params = data.payload.params ?? {};
1045
+ const res = await client
1046
+ .groupsJoinApprovalStrategyCreate({
1047
+ group_openids: params.groupOpenIds,
1048
+ group_ids: params.groupIds,
1049
+ is_enable: params.isEnable,
1050
+ expire_at: params.expireAt,
1051
+ remark: params.remark
1052
+ })
1053
+ .then(r => createResult(ResultCode.Ok, data.action, r))
1054
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
1055
+ consume([res]);
1056
+ }
1057
+ else if (data.action === 'group.strategy.update') {
1058
+ const params = data.payload.params ?? {};
1059
+ const res = await client
1060
+ .groupsJoinApprovalStrategyPatch(data.payload.StrategyId, {
1061
+ is_enable: params.isEnable,
1062
+ expire_at: params.expireAt,
1063
+ group_action: params.groupAction,
1064
+ remark: params.remark
1065
+ })
1066
+ .then(r => createResult(ResultCode.Ok, data.action, r))
1067
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
1068
+ consume([res]);
1069
+ }
1070
+ else if (data.action === 'group.strategy.delete') {
1071
+ const res = await client
1072
+ .groupsJoinApprovalStrategyDelete(data.payload.StrategyId)
1073
+ .then(r => createResult(ResultCode.Ok, data.action, r))
1074
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
1075
+ consume([res]);
1076
+ }
1077
+ else if (data.action === 'group.strategy.execute') {
1078
+ const res = await client
1079
+ .groupsJoinApprovalStrategyExecute(data.payload.StrategyId)
1080
+ .then(r => createResult(ResultCode.Ok, data.action, r))
1081
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
1082
+ consume([res]);
1083
+ }
1084
+ else if (data.action === 'group.strategy.whitelist') {
1085
+ const params = data.payload.params ?? {};
1086
+ const res = await client
1087
+ .groupsJoinApprovalStrategyWhitelistUsers(data.payload.StrategyId, { op: params.op, whitelist_users: params.whitelistUsers })
1088
+ .then(r => createResult(ResultCode.Ok, data.action, r))
1089
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
1090
+ consume([res]);
1091
+ }
745
1092
  else if (data.action === 'channel.info') {
746
1093
  const res = await client
747
- .channels(data.payload.ChannelId)
1094
+ .channels(getChannelId())
748
1095
  .then(r => createResult(ResultCode.Ok, data.action, r))
749
1096
  .catch(err => createResult(ResultCode.Fail, data.action, err));
750
1097
  consume([res]);
751
1098
  }
752
1099
  else if (data.action === 'channel.list') {
753
1100
  const res = await client
754
- .guildsChannels(data.payload.GuildId)
1101
+ .guildsChannels(getGuildId())
755
1102
  .then(r => createResult(ResultCode.Ok, data.action, r))
756
1103
  .catch(err => createResult(ResultCode.Fail, data.action, err));
757
1104
  consume([res]);
758
1105
  }
759
1106
  else if (data.action === 'channel.create') {
760
- const guildId = data.payload.GuildId;
1107
+ const guildId = getGuildId();
761
1108
  const params = data.payload.params;
762
1109
  const res = await client
763
1110
  .guildsChannelsCreate(guildId, { name: params.name, type: params.type ? Number(params.type) : 0, position: 0, parent_id: params.parentId ?? '' })
@@ -766,7 +1113,7 @@ const register = (client) => {
766
1113
  consume([res]);
767
1114
  }
768
1115
  else if (data.action === 'channel.update') {
769
- const channelId = data.payload.ChannelId;
1116
+ const channelId = getChannelId();
770
1117
  const params = data.payload.params;
771
1118
  const res = await client
772
1119
  .guildsChannelsUpdate(channelId, { name: params.name ?? '', position: params.position ?? 0 })
@@ -776,14 +1123,14 @@ const register = (client) => {
776
1123
  }
777
1124
  else if (data.action === 'channel.delete') {
778
1125
  const res = await client
779
- .guildsChannelsdelete(data.payload.ChannelId, {})
1126
+ .guildsChannelsdelete(getChannelId(), {})
780
1127
  .then(r => createResult(ResultCode.Ok, data.action, r))
781
1128
  .catch(err => createResult(ResultCode.Fail, data.action, err));
782
1129
  consume([res]);
783
1130
  }
784
1131
  else if (data.action === 'role.list') {
785
1132
  const res = await client
786
- .guildsRoles(data.payload.GuildId)
1133
+ .guildsRoles(getGuildId())
787
1134
  .then(r => createResult(ResultCode.Ok, data.action, r))
788
1135
  .catch(err => createResult(ResultCode.Fail, data.action, err));
789
1136
  consume([res]);
@@ -791,7 +1138,7 @@ const register = (client) => {
791
1138
  else if (data.action === 'role.create') {
792
1139
  const params = data.payload.params;
793
1140
  const res = await client
794
- .guildsRolesPost(data.payload.GuildId, { name: params.name, color: params.color })
1141
+ .guildsRolesPost(getGuildId(), { name: params.name, color: params.color })
795
1142
  .then(r => createResult(ResultCode.Ok, data.action, r))
796
1143
  .catch(err => createResult(ResultCode.Fail, data.action, err));
797
1144
  consume([res]);
@@ -799,35 +1146,35 @@ const register = (client) => {
799
1146
  else if (data.action === 'role.update') {
800
1147
  const params = data.payload.params;
801
1148
  const res = await client
802
- .guildsRolesPatch(data.payload.GuildId, data.payload.RoleId, { name: params.name, color: params.color })
1149
+ .guildsRolesPatch(getGuildId(), data.payload.RoleId, { name: params.name, color: params.color })
803
1150
  .then(r => createResult(ResultCode.Ok, data.action, r))
804
1151
  .catch(err => createResult(ResultCode.Fail, data.action, err));
805
1152
  consume([res]);
806
1153
  }
807
1154
  else if (data.action === 'role.delete') {
808
1155
  const res = await client
809
- .guildsRolesDelete(data.payload.GuildId, data.payload.RoleId)
1156
+ .guildsRolesDelete(getGuildId(), data.payload.RoleId)
810
1157
  .then(r => createResult(ResultCode.Ok, data.action, r))
811
1158
  .catch(err => createResult(ResultCode.Fail, data.action, err));
812
1159
  consume([res]);
813
1160
  }
814
1161
  else if (data.action === 'role.assign') {
815
1162
  const res = await client
816
- .guildsRolesMembersPut(data.payload.GuildId, '', data.payload.UserId, data.payload.RoleId)
1163
+ .guildsRolesMembersPut(getGuildId(), '', getUserId(), data.payload.RoleId)
817
1164
  .then(r => createResult(ResultCode.Ok, data.action, r))
818
1165
  .catch(err => createResult(ResultCode.Fail, data.action, err));
819
1166
  consume([res]);
820
1167
  }
821
1168
  else if (data.action === 'role.remove') {
822
1169
  const res = await client
823
- .guildsRolesMembersDelete(data.payload.GuildId, '', data.payload.UserId, data.payload.RoleId)
1170
+ .guildsRolesMembersDelete(getGuildId(), '', getUserId(), data.payload.RoleId)
824
1171
  .then(r => createResult(ResultCode.Ok, data.action, r))
825
1172
  .catch(err => createResult(ResultCode.Fail, data.action, err));
826
1173
  consume([res]);
827
1174
  }
828
1175
  else if (data.action === 'file.send.channel') {
829
1176
  const res = await client
830
- .postRichMediaByGroup(data.payload.ChannelId, {
1177
+ .postRichMediaByGroup(getGroupOpenId(), {
831
1178
  file_type: data.payload.params?.file_type ?? 1,
832
1179
  url: data.payload.params?.url,
833
1180
  file_data: data.payload.params?.file_data,
@@ -839,7 +1186,7 @@ const register = (client) => {
839
1186
  }
840
1187
  else if (data.action === 'file.send.user') {
841
1188
  const res = await client
842
- .postRichMediaByUser(data.payload.UserId, {
1189
+ .postRichMediaByUser(getUserId(), {
843
1190
  file_type: data.payload.params?.file_type ?? 1,
844
1191
  url: data.payload.params?.url,
845
1192
  file_data: data.payload.params?.file_data,
@@ -860,7 +1207,7 @@ const register = (client) => {
860
1207
  consume([createResult(ResultCode.Warn, 'media.send.channel not directly supported, use message.send with format', null)]);
861
1208
  }
862
1209
  else if (data.action === 'media.send.user') {
863
- const userId = data.payload.UserId;
1210
+ const userId = getUserId();
864
1211
  const params = data.payload.params;
865
1212
  const fileType = params?.type === 'image' ? 1 : params?.type === 'video' ? 2 : params?.type === 'audio' ? 3 : 4;
866
1213
  const res = await client
@@ -870,11 +1217,116 @@ const register = (client) => {
870
1217
  consume([res]);
871
1218
  }
872
1219
  else if (data.action === 'media.upload') {
873
- consume([createResult(ResultCode.Warn, 'media.upload not supported, use media.send.user or media.send.channel', null)]);
1220
+ const target = normalizeTarget(data.payload.target);
1221
+ if (!target) {
1222
+ consume([createResult(ResultCode.Warn, 'QQ media.upload requires target', null)]);
1223
+ return;
1224
+ }
1225
+ const res = await uploadMedia(target, data.payload.params || {})
1226
+ .then(value => createResult(ResultCode.Ok, data.action, value))
1227
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
1228
+ consume([res]);
1229
+ }
1230
+ else if (data.action === 'media.send') {
1231
+ const target = normalizeTarget(data.payload.target);
1232
+ if (!target) {
1233
+ consume([createResult(ResultCode.FailParams, 'media.send 缺少 target', null)]);
1234
+ return;
1235
+ }
1236
+ if (!validateTargetBot(target)) {
1237
+ consume([createResult(ResultCode.FailParams, `BotId ${target.BotId} is not active`, null)]);
1238
+ return;
1239
+ }
1240
+ const params = data.payload.params || {};
1241
+ if (params.fileId) {
1242
+ const send = target.scope === 'group'
1243
+ ? client.groupOpenMessages(target.targetId, { msg_type: 7, content: params.content || '', media: { file_info: params.fileId } })
1244
+ : target.scope === 'c2c'
1245
+ ? client.usersOpenMessages(target.targetId, { msg_type: 7, content: params.content || '', media: { file_info: params.fileId } })
1246
+ : null;
1247
+ if (!send) {
1248
+ consume([createResult(ResultCode.Warn, 'QQ media.send only supports group and c2c targets', null)]);
1249
+ return;
1250
+ }
1251
+ const res = await send
1252
+ .then(value => createResult(ResultCode.Ok, data.action, { id: value.id }))
1253
+ .catch(err => createResult(ResultCode.Fail, data.action, err));
1254
+ consume([res]);
1255
+ return;
1256
+ }
1257
+ const upload = await uploadMedia(target, params)
1258
+ .then(value => value.fileId)
1259
+ .catch(error => {
1260
+ consume([createResult(ResultCode.Fail, data.action, error)]);
1261
+ return null;
1262
+ });
1263
+ if (!upload) {
1264
+ return;
1265
+ }
1266
+ await onactions({ action: 'media.send', payload: { target, params: { ...params, fileId: upload, url: undefined, data: undefined, filePath: undefined } } }, consume);
1267
+ }
1268
+ else if (data.action === 'connection.status') {
1269
+ const status = client.getConnectionStatus();
1270
+ consume([
1271
+ createResult(ResultCode.Ok, data.action, {
1272
+ Platform: platform,
1273
+ state: status.state,
1274
+ bots: [{ BotId: botId, ...status }]
1275
+ })
1276
+ ]);
1277
+ }
1278
+ else if (data.action === 'media.upload.prepare') {
1279
+ const userId = getUserId();
1280
+ const groupId = getGroupOpenId();
1281
+ const res = await (userId ? client.usersUploadPrepare(userId, data.payload.params) : client.groupUploadPrepare(groupId, data.payload.params))
1282
+ .then(r => createResult(ResultCode.Ok, data.action, r))
1283
+ .catch(err => createResult(ResultCode.Fail, data.action, err?.response?.data ?? err?.message ?? err));
1284
+ consume([res]);
1285
+ }
1286
+ else if (data.action === 'media.upload.part.finish') {
1287
+ const userId = getUserId();
1288
+ const groupId = getGroupOpenId();
1289
+ const res = await (userId ? client.usersUploadPartFinish(userId, data.payload.params) : client.groupUploadPartFinish(groupId, data.payload.params))
1290
+ .then(r => createResult(ResultCode.Ok, data.action, r))
1291
+ .catch(err => createResult(ResultCode.Fail, data.action, err?.response?.data ?? err?.message ?? err));
1292
+ consume([res]);
1293
+ }
1294
+ else if (data.action === 'media.upload.chunked') {
1295
+ const userId = getUserId();
1296
+ const groupId = getGroupOpenId();
1297
+ const params = data.payload.params ?? {};
1298
+ const res = await chunkedUpload(client, userId ? 'user' : 'group', userId || groupId, params.file ?? params.file_path, {
1299
+ file_type: params.file_type ?? 1,
1300
+ file_name: params.file_name,
1301
+ srv_send_msg: params.srv_send_msg
1302
+ })
1303
+ .then(r => createResult(ResultCode.Ok, data.action, r))
1304
+ .catch(err => createResult(ResultCode.Fail, data.action, err?.response?.data ?? err?.message ?? err));
1305
+ consume([res]);
1306
+ }
1307
+ else if (data.action === 'stream.message.send') {
1308
+ const res = await client
1309
+ .streamMessages(getUserId(), data.payload.params ?? {})
1310
+ .then(r => createResult(ResultCode.Ok, data.action, r))
1311
+ .catch(err => createResult(ResultCode.Fail, data.action, err?.response?.data ?? err?.message ?? err));
1312
+ consume([res]);
1313
+ }
1314
+ else if (data.action === 'message.input.notify') {
1315
+ const params = data.payload.params ?? {};
1316
+ const res = await client
1317
+ .usersOpenMessages(getUserId(), {
1318
+ msg_type: 6,
1319
+ input_notify: { input_type: params.input_type ?? 1, input_second: params.input_second ?? 60 },
1320
+ msg_seq: params.msg_seq,
1321
+ msg_id: params.msg_id
1322
+ })
1323
+ .then(r => createResult(ResultCode.Ok, data.action, r))
1324
+ .catch(err => createResult(ResultCode.Fail, data.action, err?.response?.data ?? err?.message ?? err));
1325
+ consume([res]);
874
1326
  }
875
1327
  else if (data.action === 'permission.get') {
876
1328
  const res = await client
877
- .channelsPermissions(data.payload.ChannelId, data.payload.UserId)
1329
+ .channelsPermissions(getChannelId(), getUserId())
878
1330
  .then(r => createResult(ResultCode.Ok, data.action, r))
879
1331
  .catch(err => createResult(ResultCode.Fail, data.action, err));
880
1332
  consume([res]);
@@ -882,20 +1334,20 @@ const register = (client) => {
882
1334
  else if (data.action === 'permission.set') {
883
1335
  const params = data.payload.params;
884
1336
  const res = await client
885
- .channelsPermissionsPut(data.payload.ChannelId, data.payload.UserId, params?.allow ?? '0', params?.deny ?? '0')
1337
+ .channelsPermissionsPut(getChannelId(), getUserId(), params?.allow ?? '0', params?.deny ?? '0')
886
1338
  .then(r => createResult(ResultCode.Ok, data.action, r))
887
1339
  .catch(err => createResult(ResultCode.Fail, data.action, err));
888
1340
  consume([res]);
889
1341
  }
890
1342
  else if (data.action === 'reaction.list') {
891
1343
  const res = await client
892
- .channelsMessagesReactionsUsers(data.payload.ChannelId, data.payload.MessageId, 1, data.payload.EmojiId, { limit: data.payload.params?.limit ?? 20 })
1344
+ .channelsMessagesReactionsUsers(getChannelId(), data.payload.MessageId, 1, data.payload.EmojiId, { limit: data.payload.params?.limit ?? 20 })
893
1345
  .then(r => createResult(ResultCode.Ok, data.action, r))
894
1346
  .catch(err => createResult(ResultCode.Fail, data.action, err));
895
1347
  consume([res]);
896
1348
  }
897
1349
  else if (data.action === 'channel.announce') {
898
- const guildId = data.payload.GuildId;
1350
+ const guildId = getGuildId();
899
1351
  const params = data.payload.params;
900
1352
  if (params?.remove) {
901
1353
  const res = await client
@@ -920,7 +1372,6 @@ const register = (client) => {
920
1372
  consume([createResult(ResultCode.Fail, '请求失败', error)]);
921
1373
  }
922
1374
  };
923
- cbp.onactions((data, consume) => void onactions(data, consume));
924
1375
  const onapis = async (data, consume) => {
925
1376
  const key = data.payload?.key;
926
1377
  const params = data.payload?.params;
@@ -947,7 +1398,11 @@ const register = (client) => {
947
1398
  consume([createResult(ResultCode.Fail, '请求失败', error)]);
948
1399
  }
949
1400
  };
950
- cbp.onapis((data, consume) => void onapis(data, consume));
1401
+ if (options?.bindActions !== false) {
1402
+ cbp.onactions((data, consume) => void onactions(data, consume));
1403
+ cbp.onapis((data, consume) => void onapis(data, consume));
1404
+ }
1405
+ return { onAction: onactions, onApi: onapis };
951
1406
  };
952
1407
 
953
1408
  export { register };