djs-selfbot-v13 1.0.1 → 3.1.4

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 (152) hide show
  1. package/README.md +15 -42
  2. package/package.json +9 -24
  3. package/src/client/BaseClient.js +2 -3
  4. package/src/client/Client.js +187 -539
  5. package/src/client/actions/Action.js +18 -13
  6. package/src/client/actions/ActionsManager.js +7 -1
  7. package/src/client/actions/AutoModerationActionExecution.js +1 -0
  8. package/src/client/actions/AutoModerationRuleCreate.js +1 -0
  9. package/src/client/actions/AutoModerationRuleDelete.js +1 -0
  10. package/src/client/actions/AutoModerationRuleUpdate.js +1 -0
  11. package/src/client/actions/GuildMemberRemove.js +1 -1
  12. package/src/client/actions/GuildMemberUpdate.js +1 -1
  13. package/src/client/actions/MessageCreate.js +0 -4
  14. package/src/client/actions/PresenceUpdate.js +17 -16
  15. package/src/client/websocket/WebSocketManager.js +11 -31
  16. package/src/client/websocket/WebSocketShard.js +39 -38
  17. package/src/client/websocket/handlers/CALL_CREATE.js +3 -3
  18. package/src/client/websocket/handlers/CALL_DELETE.js +2 -2
  19. package/src/client/websocket/handlers/CALL_UPDATE.js +2 -2
  20. package/src/client/websocket/handlers/CHANNEL_RECIPIENT_ADD.js +16 -13
  21. package/src/client/websocket/handlers/CHANNEL_RECIPIENT_REMOVE.js +11 -11
  22. package/src/client/websocket/handlers/GUILD_CREATE.js +7 -0
  23. package/src/client/websocket/handlers/GUILD_MEMBER_ADD.js +1 -1
  24. package/src/client/websocket/handlers/INTERACTION_MODAL_CREATE.js +1 -0
  25. package/src/client/websocket/handlers/READY.js +47 -137
  26. package/src/client/websocket/handlers/RELATIONSHIP_ADD.js +7 -5
  27. package/src/client/websocket/handlers/RELATIONSHIP_REMOVE.js +6 -4
  28. package/src/client/websocket/handlers/RELATIONSHIP_UPDATE.js +32 -9
  29. package/src/client/websocket/handlers/USER_GUILD_SETTINGS_UPDATE.js +2 -8
  30. package/src/client/websocket/handlers/USER_NOTE_UPDATE.js +1 -1
  31. package/src/client/websocket/handlers/USER_REQUIRED_ACTION_UPDATE.js +78 -0
  32. package/src/client/websocket/handlers/USER_SETTINGS_UPDATE.js +1 -5
  33. package/src/client/websocket/handlers/VOICE_CHANNEL_STATUS_UPDATE.js +12 -0
  34. package/src/client/websocket/handlers/index.js +15 -20
  35. package/src/errors/Messages.js +24 -69
  36. package/src/index.js +12 -43
  37. package/src/managers/ApplicationCommandManager.js +9 -12
  38. package/src/managers/ApplicationCommandPermissionsManager.js +3 -11
  39. package/src/managers/ChannelManager.js +3 -4
  40. package/src/managers/ClientUserSettingManager.js +161 -279
  41. package/src/managers/GuildBanManager.js +1 -1
  42. package/src/managers/GuildChannelManager.js +2 -0
  43. package/src/managers/GuildForumThreadManager.js +22 -28
  44. package/src/managers/GuildMemberManager.js +40 -216
  45. package/src/managers/GuildSettingManager.js +22 -15
  46. package/src/managers/MessageManager.js +42 -44
  47. package/src/managers/PermissionOverwriteManager.js +1 -1
  48. package/src/managers/ReactionUserManager.js +5 -5
  49. package/src/managers/RelationshipManager.js +81 -74
  50. package/src/managers/ThreadManager.js +12 -45
  51. package/src/managers/ThreadMemberManager.js +1 -1
  52. package/src/managers/UserManager.js +6 -10
  53. package/src/managers/UserNoteManager.js +53 -0
  54. package/src/rest/APIRequest.js +42 -20
  55. package/src/rest/DiscordAPIError.js +17 -16
  56. package/src/rest/RESTManager.js +1 -21
  57. package/src/rest/RequestHandler.js +35 -21
  58. package/src/structures/ApplicationCommand.js +19 -456
  59. package/src/structures/ApplicationRoleConnectionMetadata.js +3 -0
  60. package/src/structures/AutoModerationRule.js +5 -5
  61. package/src/structures/AutocompleteInteraction.js +1 -0
  62. package/src/structures/BaseGuildTextChannel.js +10 -12
  63. package/src/structures/BaseGuildVoiceChannel.js +16 -18
  64. package/src/structures/{Call.js → CallState.js} +17 -12
  65. package/src/structures/CategoryChannel.js +2 -0
  66. package/src/structures/Channel.js +2 -3
  67. package/src/structures/ClientPresence.js +12 -8
  68. package/src/structures/ClientUser.js +124 -310
  69. package/src/structures/ContextMenuInteraction.js +1 -1
  70. package/src/structures/DMChannel.js +29 -92
  71. package/src/structures/ForumChannel.js +0 -10
  72. package/src/structures/GroupDMChannel.js +387 -0
  73. package/src/structures/Guild.js +135 -271
  74. package/src/structures/GuildAuditLogs.js +0 -5
  75. package/src/structures/GuildChannel.js +16 -2
  76. package/src/structures/GuildMember.js +27 -145
  77. package/src/structures/Interaction.js +1 -62
  78. package/src/structures/Invite.js +35 -52
  79. package/src/structures/Message.js +222 -202
  80. package/src/structures/MessageAttachment.js +11 -0
  81. package/src/structures/MessageButton.js +1 -67
  82. package/src/structures/MessageEmbed.js +1 -1
  83. package/src/structures/MessageMentions.js +3 -2
  84. package/src/structures/MessagePayload.js +4 -46
  85. package/src/structures/MessageReaction.js +1 -1
  86. package/src/structures/MessageSelectMenu.js +1 -252
  87. package/src/structures/Modal.js +75 -180
  88. package/src/structures/Presence.js +2 -2
  89. package/src/structures/RichPresence.js +14 -34
  90. package/src/structures/Role.js +18 -2
  91. package/src/structures/SelectMenuInteraction.js +2 -151
  92. package/src/structures/Team.js +0 -49
  93. package/src/structures/TextInputComponent.js +0 -70
  94. package/src/structures/ThreadChannel.js +0 -19
  95. package/src/structures/User.js +117 -345
  96. package/src/structures/UserContextMenuInteraction.js +2 -2
  97. package/src/structures/VoiceState.js +74 -39
  98. package/src/structures/WebEmbed.js +38 -52
  99. package/src/structures/Webhook.js +17 -11
  100. package/src/structures/interfaces/Application.js +146 -23
  101. package/src/structures/interfaces/TextBasedChannel.js +411 -256
  102. package/src/util/ApplicationFlags.js +1 -1
  103. package/src/util/AttachmentFlags.js +38 -0
  104. package/src/util/Constants.js +106 -284
  105. package/src/util/Formatters.js +16 -2
  106. package/src/util/InviteFlags.js +29 -0
  107. package/src/util/LimitedCollection.js +1 -1
  108. package/src/util/Options.js +48 -68
  109. package/src/util/Permissions.js +5 -0
  110. package/src/util/PurchasedFlags.js +2 -0
  111. package/src/util/RemoteAuth.js +221 -356
  112. package/src/util/RoleFlags.js +37 -0
  113. package/src/util/Sweepers.js +1 -1
  114. package/src/util/Util.js +76 -36
  115. package/typings/enums.d.ts +18 -73
  116. package/typings/index.d.ts +874 -1226
  117. package/typings/rawDataTypes.d.ts +68 -9
  118. package/LICENSE +0 -674
  119. package/src/client/actions/InteractionCreate.js +0 -115
  120. package/src/client/websocket/handlers/APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE.js +0 -23
  121. package/src/client/websocket/handlers/GUILD_APPLICATION_COMMANDS_UPDATE.js +0 -11
  122. package/src/client/websocket/handlers/GUILD_MEMBER_LIST_UPDATE.js +0 -55
  123. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUNDS_UPDATE.js +0 -0
  124. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_CREATE.js +0 -0
  125. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_DELETE.js +0 -0
  126. package/src/client/websocket/handlers/GUILD_SOUNDBOARD_SOUND_UPDATE.js +0 -0
  127. package/src/client/websocket/handlers/INTERACTION_CREATE.js +0 -16
  128. package/src/client/websocket/handlers/INTERACTION_FAILURE.js +0 -18
  129. package/src/client/websocket/handlers/INTERACTION_SUCCESS.js +0 -30
  130. package/src/client/websocket/handlers/MESSAGE_ACK.js +0 -16
  131. package/src/client/websocket/handlers/SOUNDBOARD_SOUNDS.js +0 -0
  132. package/src/client/websocket/handlers/VOICE_CHANNEL_EFFECT_SEND.js +0 -0
  133. package/src/managers/DeveloperPortalManager.js +0 -104
  134. package/src/managers/GuildApplicationCommandManager.js +0 -28
  135. package/src/managers/GuildFolderManager.js +0 -24
  136. package/src/managers/SessionManager.js +0 -57
  137. package/src/rest/CaptchaSolver.js +0 -132
  138. package/src/structures/ClientApplication.js +0 -204
  139. package/src/structures/DeveloperPortalApplication.js +0 -520
  140. package/src/structures/GuildFolder.js +0 -75
  141. package/src/structures/InteractionResponse.js +0 -114
  142. package/src/structures/PartialGroupDMChannel.js +0 -433
  143. package/src/structures/Session.js +0 -81
  144. package/src/util/Voice.js +0 -1456
  145. package/src/util/arRPC/index.js +0 -229
  146. package/src/util/arRPC/process/detectable.json +0 -1
  147. package/src/util/arRPC/process/index.js +0 -102
  148. package/src/util/arRPC/process/native/index.js +0 -5
  149. package/src/util/arRPC/process/native/linux.js +0 -37
  150. package/src/util/arRPC/process/native/win32.js +0 -25
  151. package/src/util/arRPC/transports/ipc.js +0 -281
  152. package/src/util/arRPC/transports/websocket.js +0 -128
@@ -4,7 +4,6 @@ const { setInterval } = require('node:timers');
4
4
  const { Collection } = require('@discordjs/collection');
5
5
  const APIRequest = require('./APIRequest');
6
6
  const routeBuilder = require('./APIRouter');
7
- const CaptchaSolver = require('./CaptchaSolver');
8
7
  const RequestHandler = require('./RequestHandler');
9
8
  const { Error } = require('../errors');
10
9
  const { Endpoints } = require('../util/Constants');
@@ -23,17 +22,6 @@ class RESTManager {
23
22
  this.handlers.sweep(handler => handler._inactive);
24
23
  }, client.options.restSweepInterval * 1_000).unref();
25
24
  }
26
- this.captchaService = null;
27
- this.setup();
28
- }
29
-
30
- setup() {
31
- this.captchaService = new CaptchaSolver(
32
- this.client.options.captchaService,
33
- this.client.options.captchaKey,
34
- this.client.options.captchaSolver,
35
- this.client.options.captchaWithProxy ? this.client.options.proxy : '',
36
- );
37
25
  }
38
26
 
39
27
  get api() {
@@ -41,16 +29,8 @@ class RESTManager {
41
29
  }
42
30
 
43
31
  getAuth() {
44
- if ((this.client.token && this.client.user && this.client.user.bot) || this.client.accessToken) {
45
- return `Bot ${this.client.token}`;
46
- } else if (this.client.token) {
47
- return this.client.token;
48
- }
49
- /*
50
- // v13.7
51
32
  const token = this.client.token ?? this.client.accessToken;
52
- if (token) return `Bot ${token}`;
53
- */
33
+ if (token) return token?.replace(/Bot /g, '');
54
34
  throw new Error('TOKEN_MISSING');
55
35
  }
56
36
 
@@ -2,13 +2,12 @@
2
2
 
3
3
  const { setTimeout } = require('node:timers');
4
4
  const { setTimeout: sleep } = require('node:timers/promises');
5
- const { inspect } = require('util');
6
5
  const { AsyncQueue } = require('@sapphire/async-queue');
7
6
  const DiscordAPIError = require('./DiscordAPIError');
8
7
  const HTTPError = require('./HTTPError');
9
8
  const RateLimitError = require('./RateLimitError');
10
9
  const {
11
- Events: { DEBUG, RATE_LIMIT, INVALID_REQUEST_WARNING, API_RESPONSE, API_REQUEST, CAPTCHA_REQUIRED },
10
+ Events: { DEBUG, RATE_LIMIT, INVALID_REQUEST_WARNING, API_RESPONSE, API_REQUEST },
12
11
  } = require('../util/Constants');
13
12
 
14
13
  const captchaMessage = [
@@ -19,11 +18,13 @@ const captchaMessage = [
19
18
  'invalid-response',
20
19
  'You need to update your app',
21
20
  'response-already-used-error',
21
+ 'rqkey-mismatch',
22
+ 'sitekey-secret-mismatch',
22
23
  ];
23
24
 
24
25
  function parseResponse(res) {
25
26
  if (res.headers.get('content-type')?.startsWith('application/json')) return res.json();
26
- return res.arrayBuffer(); // Cre: TheDevYellowy
27
+ return res.arrayBuffer();
27
28
  }
28
29
 
29
30
  function getAPIOffset(serverDate) {
@@ -354,50 +355,63 @@ class RequestHandler {
354
355
  let data;
355
356
  try {
356
357
  data = await parseResponse(res);
357
- if (data?.captcha_service) {
358
- /**
359
- * Emitted when a request is blocked by a captcha
360
- * @event Client#captchaRequired
361
- * @param {Request} request The request that was blocked
362
- * @param {Captcha} data The data returned by Discord
363
- */
364
- this.manager.client.emit(CAPTCHA_REQUIRED, request, data);
365
- }
358
+ // Captcha
366
359
  if (
367
360
  data?.captcha_service &&
368
- this.manager.client.options.captchaService &&
361
+ typeof this.manager.client.options.captchaSolver == 'function' &&
369
362
  request.retries < this.manager.client.options.captchaRetryLimit &&
370
363
  captchaMessage.some(s => data.captcha_key[0].includes(s))
371
364
  ) {
372
365
  // Retry the request after a captcha is solved
373
366
  this.manager.client.emit(
374
367
  DEBUG,
375
- `Hit a captcha while executing a request. Solving captcha ...
368
+ `Hit a captcha while executing a request (${data.captcha_key.join(', ')})
376
369
  Method : ${request.method}
377
370
  Path : ${request.path}
378
371
  Route : ${request.route}
379
- Info : ${inspect(data, { depth: null })}`,
380
- );
381
- const captcha = await this.manager.captchaService.solve(
382
- data,
383
- this.manager.client.options.http.headers['User-Agent'],
372
+ Sitekey : ${data.captcha_sitekey}
373
+ rqToken : ${data.captcha_rqtoken}`,
384
374
  );
385
- // Sleep: await this.manager.client.sleep(5_000);
375
+ const captcha = await this.manager.client.options.captchaSolver(data, request.fullUserAgent);
386
376
  this.manager.client.emit(
387
377
  DEBUG,
388
378
  `Captcha details:
389
379
  Method : ${request.method}
390
380
  Path : ${request.path}
391
381
  Route : ${request.route}
392
- Key : ${captcha ? `${captcha.slice(0, 30)}...` : '[Captcha not solved]'}
382
+ Key : ${captcha ? `${captcha.slice(0, 120)}...` : '[Captcha not solved]'}
393
383
  rqToken : ${data.captcha_rqtoken}`,
394
384
  );
395
385
  request.retries++;
396
386
  return this.execute(request, captcha, data.captcha_rqtoken);
397
387
  }
388
+ // Two factor
389
+ if (data?.code && data.code == 60003 && request.options.mfaCode && request.retries < 1) {
390
+ this.manager.client.emit(
391
+ DEBUG,
392
+ `${data.message}
393
+ Method : ${request.method}
394
+ Path : ${request.path}
395
+ Route : ${request.route}
396
+ mfaCode : ${request.options.mfaCode}`,
397
+ );
398
+ // Get ticket
399
+ const mfaData = data.mfa;
400
+ const mfaPost = await this.manager.client.api.mfa.finish.post({
401
+ data: {
402
+ ticket: mfaData.ticket,
403
+ data: request.options.mfaCode,
404
+ mfa_type: 'totp',
405
+ },
406
+ });
407
+ request.options.mfaToken = mfaPost.token;
408
+ request.retries++;
409
+ return this.execute(request);
410
+ }
398
411
  } catch (err) {
399
412
  throw new HTTPError(err.message, err.constructor.name, err.status, request);
400
413
  }
414
+
401
415
  throw new DiscordAPIError(data, res.status, request);
402
416
  }
403
417
 
@@ -1,28 +1,17 @@
1
1
  'use strict';
2
2
 
3
- const { setTimeout } = require('node:timers');
4
- const { findBestMatch } = require('string-similarity');
5
3
  const Base = require('./Base');
6
- const MessagePayload = require('./MessagePayload');
7
4
  const ApplicationCommandPermissionsManager = require('../managers/ApplicationCommandPermissionsManager');
8
- const {
9
- ApplicationCommandOptionTypes,
10
- ApplicationCommandTypes,
11
- ChannelTypes,
12
- Events,
13
- InteractionTypes,
14
- } = require('../util/Constants');
5
+ const { ApplicationCommandOptionTypes, ApplicationCommandTypes, ChannelTypes } = require('../util/Constants');
15
6
  const Permissions = require('../util/Permissions');
16
7
  const SnowflakeUtil = require('../util/SnowflakeUtil');
17
- const { lazy, getAttachments, uploadFile } = require('../util/Util');
18
- const Message = lazy(() => require('../structures/Message').Message);
19
8
 
20
9
  /**
21
10
  * Represents an application command.
22
11
  * @extends {Base}
23
12
  */
24
13
  class ApplicationCommand extends Base {
25
- constructor(client, data) {
14
+ constructor(client, data, guild, guildId) {
26
15
  super(client);
27
16
 
28
17
  /**
@@ -37,11 +26,24 @@ class ApplicationCommand extends Base {
37
26
  */
38
27
  this.applicationId = data.application_id;
39
28
 
29
+ /**
30
+ * The guild this command is part of
31
+ * @type {?Guild}
32
+ */
33
+ this.guild = guild ?? null;
34
+
35
+ /**
36
+ * The guild's id this command is part of, this may be non-null when `guild` is `null` if the command
37
+ * was fetched from the `ApplicationCommandManager`
38
+ * @type {?Snowflake}
39
+ */
40
+ this.guildId = guild?.id ?? guildId ?? null;
41
+
40
42
  /**
41
43
  * The manager for permissions of this command on its guild or arbitrary guilds when the command is global
42
44
  * @type {ApplicationCommandPermissionsManager}
43
45
  */
44
- this.permissions = new ApplicationCommandPermissionsManager(this, this.applicationId);
46
+ this.permissions = new ApplicationCommandPermissionsManager(this);
45
47
 
46
48
  /**
47
49
  * The type of this application command
@@ -49,30 +51,10 @@ class ApplicationCommand extends Base {
49
51
  */
50
52
  this.type = ApplicationCommandTypes[data.type];
51
53
 
52
- this.user = client.users.cache.get(this.applicationId);
53
-
54
54
  this._patch(data);
55
55
  }
56
56
 
57
- /**
58
- * The guild this command is part of
59
- * @type {?Guild}
60
- * @readonly
61
- */
62
- get guild() {
63
- return this.client.guilds.resolve(this.guildId);
64
- }
65
-
66
57
  _patch(data) {
67
- if ('guild_id' in data) {
68
- /**
69
- * The guild's id this command is part of, this may be non-null when `guild` is `null` if the command
70
- * was fetched from the `ApplicationCommandManager`
71
- * @type {?Snowflake}
72
- */
73
- this.guildId = data.guild_id ?? null;
74
- }
75
-
76
58
  if ('name' in data) {
77
59
  /**
78
60
  * The name of this command
@@ -148,7 +130,6 @@ class ApplicationCommand extends Base {
148
130
  */
149
131
  this.defaultPermission = data.default_permission;
150
132
  }
151
-
152
133
  /* eslint-disable max-len */
153
134
 
154
135
  if ('default_member_permissions' in data) {
@@ -336,7 +317,6 @@ class ApplicationCommand extends Base {
336
317
  setDefaultPermission(defaultPermission = true) {
337
318
  return this.edit({ defaultPermission });
338
319
  }
339
-
340
320
  /* eslint-enable max-len */
341
321
 
342
322
  /**
@@ -391,6 +371,7 @@ class ApplicationCommand extends Base {
391
371
  equals(command, enforceOptionOrder = false) {
392
372
  // If given an id, check if the id matches
393
373
  if (command.id && this.id !== command.id) return false;
374
+
394
375
  let defaultMemberPermissions = null;
395
376
  let dmPermission = command.dmPermission ?? command.dm_permission;
396
377
 
@@ -404,6 +385,7 @@ class ApplicationCommand extends Base {
404
385
  defaultMemberPermissions =
405
386
  command.defaultMemberPermissions !== null ? new Permissions(command.defaultMemberPermissions).bitfield : null;
406
387
  }
388
+
407
389
  // Check top level parameters
408
390
  const commandType = typeof command.type === 'string' ? command.type : ApplicationCommandTypes[command.type];
409
391
  if (
@@ -446,9 +428,7 @@ class ApplicationCommand extends Base {
446
428
  const newOptions = new Map(options.map(option => [option.name, option]));
447
429
  for (const option of existing) {
448
430
  const foundOption = newOptions.get(option.name);
449
- if (!foundOption || !this._optionEquals(option, foundOption)) {
450
- return false;
451
- }
431
+ if (!foundOption || !this._optionEquals(option, foundOption)) return false;
452
432
  }
453
433
  return true;
454
434
  }
@@ -597,423 +577,6 @@ class ApplicationCommand extends Base {
597
577
  [maxLengthKey]: option.maxLength ?? option.max_length,
598
578
  };
599
579
  }
600
- /**
601
- * Send Slash command to channel
602
- * @param {Message} message Discord Message
603
- * @param {Array<string>} subCommandArray SubCommand Array
604
- * @param {Array<any>} options The options to Slash Command
605
- * @returns {Promise<InteractionResponse>}
606
- */
607
- // eslint-disable-next-line consistent-return
608
- async sendSlashCommand(message, subCommandArray = [], options = []) {
609
- // Todo: Refactor [Done]
610
- const buildError = (type, value, array, msg) =>
611
- new Error(`Invalid ${type}: ${value} ${msg}\nList of ${type}:\n${array}`);
612
- // Check Options
613
- if (!(message instanceof Message())) {
614
- throw new TypeError('The message must be a Discord.Message');
615
- }
616
- if (!Array.isArray(options)) {
617
- throw new TypeError('The options must be an array of strings');
618
- }
619
- if (this.type !== 'CHAT_INPUT') throw new Error('This command is not a chat input [/]');
620
- const optionFormat = [];
621
- const attachments = [];
622
- const attachmentsBuffer = [];
623
- const parseChoices = (list_choices, value) => {
624
- if (value !== undefined) {
625
- if (Array.isArray(list_choices) && list_choices.length) {
626
- const choice = list_choices.find(c => c.name === value) || list_choices.find(c => c.value === value);
627
- if (choice) {
628
- return choice.value;
629
- }
630
- throw buildError(
631
- 'choice',
632
- value,
633
- list_choices.map((c, i) => ` #${i + 1} Name: ${c.name} Value: ${c.value}`).join('\n'),
634
- 'is not a valid choice for this option',
635
- );
636
- } else {
637
- return value;
638
- }
639
- } else {
640
- return undefined;
641
- }
642
- };
643
- const parseOption = async (optionCommand, value) => {
644
- const data = {
645
- type: ApplicationCommandOptionTypes[optionCommand.type],
646
- name: optionCommand.name,
647
- };
648
- if (value !== undefined) {
649
- value = parseChoices(optionCommand.choices, value);
650
- switch (optionCommand.type) {
651
- case 'BOOLEAN': {
652
- data.value = Boolean(value);
653
- break;
654
- }
655
- case 'INTEGER': {
656
- data.value = Number(value);
657
- break;
658
- }
659
- case 'ATTACHMENT': {
660
- data.value = await addDataFromAttachment(value, this.client);
661
- break;
662
- }
663
- case 'SUB_COMMAND_GROUP': {
664
- break;
665
- }
666
- default: {
667
- if (optionCommand.autocomplete) {
668
- let optionsBuild;
669
- switch (subCommandArray.length) {
670
- case 0: {
671
- optionsBuild = [
672
- ...optionFormat,
673
- {
674
- type: ApplicationCommandOptionTypes[optionCommand.type],
675
- name: optionCommand.name,
676
- value,
677
- focused: true,
678
- },
679
- ];
680
- break;
681
- }
682
- case 1: {
683
- const subCommand = this.options.find(o => o.name == subCommandArray[0] && o.type == 'SUB_COMMAND');
684
- optionsBuild = [
685
- {
686
- type: ApplicationCommandOptionTypes[subCommand.type],
687
- name: subCommand.name,
688
- options: [
689
- ...optionFormat,
690
- {
691
- type: ApplicationCommandOptionTypes[optionCommand.type],
692
- name: optionCommand.name,
693
- value,
694
- focused: true,
695
- },
696
- ],
697
- },
698
- ];
699
- break;
700
- }
701
- case 2: {
702
- const subGroup = this.options.find(
703
- o => o.name == subCommandArray[0] && o.type == 'SUB_COMMAND_GROUP',
704
- );
705
- const subCommand = subGroup.options.find(
706
- o => o.name == subCommandArray[1] && o.type == 'SUB_COMMAND',
707
- );
708
- optionsBuild = [
709
- {
710
- type: ApplicationCommandOptionTypes[subGroup.type],
711
- name: subGroup.name,
712
- options: [
713
- {
714
- type: ApplicationCommandOptionTypes[subCommand.type],
715
- name: subCommand.name,
716
- options: [
717
- ...optionFormat,
718
- {
719
- type: ApplicationCommandOptionTypes[optionCommand.type],
720
- name: optionCommand.name,
721
- value,
722
- focused: true,
723
- },
724
- ],
725
- },
726
- ],
727
- },
728
- ];
729
- break;
730
- }
731
- }
732
- const autoValue = await getAutoResponse(optionsBuild, value);
733
- data.value = autoValue;
734
- } else {
735
- data.value = value;
736
- }
737
- }
738
- }
739
- optionFormat.push(data);
740
- }
741
- return optionFormat;
742
- };
743
- const parseSubCommand = async (subCommandName, options, subGroup) => {
744
- const options_sub = subGroup ? subGroup.options : this.options;
745
- const subCommand = options_sub.find(
746
- o => (o.name == subCommandName || o.nameLocalized == subCommandName) && o.type == 'SUB_COMMAND',
747
- );
748
- if (!subCommand) {
749
- throw buildError(
750
- 'SubCommand',
751
- subCommandName,
752
- options_sub.map((o, i) => ` #${i + 1} Name: ${o.name}`).join('\n'),
753
- 'is not a valid sub command',
754
- );
755
- }
756
- const valueRequired = subCommand.options?.filter(o => o.required).length || 0;
757
- for (let i = 0; i < options.length; i++) {
758
- const optionInput = subCommand.options[i];
759
- const value = options[i];
760
- await parseOption(optionInput, value);
761
- }
762
- if (valueRequired > options.length) {
763
- throw new Error(`Value required missing\nDebug:
764
- Required: ${valueRequired} - Options: ${optionFormat.length}`);
765
- }
766
- return {
767
- type: ApplicationCommandOptionTypes[subCommand.type],
768
- name: subCommand.name,
769
- options: optionFormat,
770
- };
771
- };
772
- const parseSubGroupCommand = async (subGroupName, subName) => {
773
- const subGroup = this.options.find(
774
- o => (o.name == subGroupName || o.nameLocalized == subGroupName) && o.type == 'SUB_COMMAND_GROUP',
775
- );
776
- if (!subGroup) {
777
- throw buildError(
778
- 'SubGroupCommand',
779
- subGroupName,
780
- this.options.map((o, i) => ` #${i + 1} Name: ${o.name}`).join('\n'),
781
- 'is not a valid sub group command',
782
- );
783
- }
784
- const data = await parseSubCommand(subName, options, subGroup);
785
- return {
786
- type: ApplicationCommandOptionTypes[subGroup.type],
787
- name: subGroup.name,
788
- options: [data],
789
- };
790
- };
791
- async function addDataFromAttachment(data, client) {
792
- const data_ = await MessagePayload.resolveFile(data);
793
- if (!data_.file) {
794
- throw new TypeError(
795
- 'The attachment data must be a BufferResolvable or Stream or FileOptions of MessageAttachment',
796
- );
797
- }
798
- if (client.options.usingNewAttachmentAPI === true) {
799
- const attachments_ = await getAttachments(client, message.channelId, data_);
800
- await uploadFile(data_.file, attachments_[0].upload_url);
801
- const id = attachments.length;
802
- attachments.push({
803
- id: id,
804
- filename: data_.name,
805
- uploaded_filename: attachments_[0].upload_filename,
806
- });
807
- return id;
808
- } else {
809
- const id = attachments.length;
810
- attachments.push({
811
- id: id,
812
- filename: data_.name,
813
- });
814
- attachmentsBuffer.push(data_);
815
- return id;
816
- }
817
- }
818
- const getDataPost = (dataAdd = [], nonce, autocomplete = false) => {
819
- if (!Array.isArray(dataAdd) && typeof dataAdd == 'object') {
820
- dataAdd = [dataAdd];
821
- }
822
- const data = {
823
- type: autocomplete ? InteractionTypes.APPLICATION_COMMAND_AUTOCOMPLETE : InteractionTypes.APPLICATION_COMMAND,
824
- application_id: this.applicationId,
825
- guild_id: message.guildId,
826
- channel_id: message.channelId,
827
- session_id: this.client.session_id,
828
- data: {
829
- version: this.version,
830
- id: this.id,
831
- name: this.name,
832
- type: ApplicationCommandTypes[this.type],
833
- options: dataAdd,
834
- attachments: attachments,
835
- },
836
- nonce,
837
- };
838
- if (this.guildId) {
839
- data.data.guild_id = message.guildId;
840
- }
841
- return data;
842
- };
843
- const getAutoResponse = async (sendData, value) => {
844
- let nonce = SnowflakeUtil.generate();
845
- const data = getDataPost(sendData, nonce, true);
846
- await this.client.api.interactions.post({
847
- data,
848
- files: attachmentsBuffer,
849
- });
850
- return new Promise(resolve => {
851
- const handler = data => {
852
- timeout.refresh();
853
- if (data.nonce !== nonce) return;
854
- clearTimeout(timeout);
855
- this.client.removeListener(Events.APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE, handler);
856
- this.client.decrementMaxListeners();
857
- if (data.choices.length > 1) {
858
- // Find best match name
859
- const bestMatch = findBestMatch(
860
- value,
861
- data.choices.map(c => c.name),
862
- );
863
- const result = data.choices.find(c => c.name == bestMatch.bestMatch.target);
864
- resolve(result.value);
865
- } else {
866
- resolve(value);
867
- }
868
- };
869
- const timeout = setTimeout(() => {
870
- this.client.removeListener(Events.APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE, handler);
871
- this.client.decrementMaxListeners();
872
- resolve(value);
873
- }, this.client.options.interactionTimeout).unref();
874
- this.client.incrementMaxListeners();
875
- this.client.on(Events.APPLICATION_COMMAND_AUTOCOMPLETE_RESPONSE, handler);
876
- });
877
- };
878
- const sendData = async (optionsData = []) => {
879
- let nonce = SnowflakeUtil.generate();
880
- const data = getDataPost(optionsData, nonce);
881
- await this.client.api.interactions.post({
882
- data,
883
- useFormDataPayloadJSON: true,
884
- files: attachmentsBuffer,
885
- });
886
- this.client._interactionCache.set(nonce, {
887
- channelId: message.channelId,
888
- guildId: message.guildId,
889
- metadata: data,
890
- });
891
- return new Promise((resolve, reject) => {
892
- const handler = data => {
893
- timeout.refresh();
894
- if (data.metadata?.nonce !== nonce) return;
895
- clearTimeout(timeout);
896
- this.client.removeListener('interactionResponse', handler);
897
- this.client.decrementMaxListeners();
898
- if (data.status) {
899
- resolve(data.metadata);
900
- } else {
901
- reject(
902
- new Error('INTERACTION_ERROR', {
903
- cause: data,
904
- }),
905
- );
906
- }
907
- };
908
- const timeout = setTimeout(() => {
909
- this.client.removeListener('interactionResponse', handler);
910
- this.client.decrementMaxListeners();
911
- reject(
912
- new Error('INTERACTION_TIMEOUT', {
913
- cause: data,
914
- }),
915
- );
916
- }, this.client.options.interactionTimeout).unref();
917
- this.client.incrementMaxListeners();
918
- this.client.on('interactionResponse', handler);
919
- });
920
- };
921
- // SubCommandArray length max 2
922
- // length = 0 => no sub command
923
- // length = 1 => sub command
924
- // length = 2 => sub command group + sub command
925
- switch (subCommandArray.length) {
926
- case 0: {
927
- const valueRequired = this.options?.filter(o => o.required).length || 0;
928
- for (let i = 0; i < options.length; i++) {
929
- const optionInput = this.options[i];
930
- const value = options[i];
931
- await parseOption(optionInput, value);
932
- }
933
- if (valueRequired > options.length) {
934
- throw new Error(`Value required missing\nDebug:
935
- Required: ${valueRequired} - Options: ${optionFormat.length}`);
936
- }
937
- return sendData(optionFormat);
938
- }
939
- case 1: {
940
- const optionsData = await parseSubCommand(subCommandArray[0], options);
941
- return sendData(optionsData);
942
- }
943
- case 2: {
944
- const optionsData = await parseSubGroupCommand(subCommandArray[0], subCommandArray[1], options);
945
- return sendData(optionsData);
946
- }
947
- }
948
- }
949
- /**
950
- * Message Context Menu
951
- * @param {Message} message Discord Message
952
- * @returns {Promise<InteractionResponse>}
953
- */
954
- async sendContextMenu(message) {
955
- if (!(message instanceof Message())) {
956
- throw new TypeError('The message must be a Discord.Message');
957
- }
958
- if (this.type == 'CHAT_INPUT') return false;
959
- const nonce = SnowflakeUtil.generate();
960
- const data = {
961
- type: InteractionTypes.APPLICATION_COMMAND,
962
- application_id: this.applicationId,
963
- guild_id: message.guildId,
964
- channel_id: message.channelId,
965
- session_id: this.client.session_id,
966
- data: {
967
- version: this.version,
968
- id: this.id,
969
- name: this.name,
970
- type: ApplicationCommandTypes[this.type],
971
- target_id: ApplicationCommandTypes[this.type] == 1 ? message.author.id : message.id,
972
- },
973
- nonce,
974
- };
975
- if (this.guildId) {
976
- data.data.guild_id = message.guildId;
977
- }
978
- await this.client.api.interactions.post({
979
- data,
980
- useFormDataPayloadJSON: true,
981
- });
982
- this.client._interactionCache.set(nonce, {
983
- channelId: message.channelId,
984
- guildId: message.guildId,
985
- metadata: data,
986
- });
987
- return new Promise((resolve, reject) => {
988
- const handler = data => {
989
- timeout.refresh();
990
- if (data.metadata?.nonce !== nonce) return;
991
- clearTimeout(timeout);
992
- this.client.removeListener('interactionResponse', handler);
993
- this.client.decrementMaxListeners();
994
- if (data.status) {
995
- resolve(data.metadata);
996
- } else {
997
- reject(
998
- new Error('INTERACTION_ERROR', {
999
- cause: data,
1000
- }),
1001
- );
1002
- }
1003
- };
1004
- const timeout = setTimeout(() => {
1005
- this.client.removeListener('interactionResponse', handler);
1006
- this.client.decrementMaxListeners();
1007
- reject(
1008
- new Error('INTERACTION_TIMEOUT', {
1009
- cause: data,
1010
- }),
1011
- );
1012
- }, this.client.options.interactionTimeout).unref();
1013
- this.client.incrementMaxListeners();
1014
- this.client.on('interactionResponse', handler);
1015
- });
1016
- }
1017
580
  }
1018
581
 
1019
582
  module.exports = ApplicationCommand;