From 26c1e01a5f6c0df3f43037898d6f4240b02b0940 Mon Sep 17 00:00:00 2001
From: March 7th <71698422+aiko-chan-ai@users.noreply.github.com>
Date: Mon, 28 Mar 2022 20:46:18 +0700
Subject: [PATCH] Update New Method
---
 DOCUMENT.md                               | 21 +++++++++++--
 package.json                              |  3 +-
 src/managers/ApplicationCommandManager.js |  1 +
 src/structures/ApplicationCommand.js      |  4 +--
 src/structures/Channel.js                 | 36 +++++++++++++++++++++
 src/structures/Message.js                 | 38 +++++++++++++++++++++++
 typings/index.d.ts                        |  3 ++
 7 files changed, 100 insertions(+), 6 deletions(-)
diff --git a/DOCUMENT.md b/DOCUMENT.md
index 4338079..b40de00 100644
--- a/DOCUMENT.md
+++ b/DOCUMENT.md
@@ -209,6 +209,7 @@ Update soon ~
 Code
 
 ```js
+const RPC = require('discord-rpc-contructor');
 // Bot ID
 RPC.getRpcImages('817229550684471297').then(console.log);
 ```
@@ -252,6 +253,7 @@ await message.selectMenu(options) // If message has 1 menu
 Slash Command (v1)
 
 ```js
+// v1
 const botID = '12345678987654321'
 const user = await client.users.fetch(botID);
 const application = await user.applications.fetch();
@@ -265,13 +267,15 @@ messageID: Message.id,
 await command.sendSlashCommand(Message, ['option1', 'option2']);
 // Eg: Slash /add role:123456789 user:987654321
 // value: ['123456789', '987654321']
-// Channel.sendSlashCommand(botID, commandName, options): Comming soon !
+// v2
+await Channel.sendSlash(botID, commandName, ['option1', 'option2']);
 ```
 
 
-Message Context Command (v1)
+Message Context Command
 
 ```js
+// v1
 const botID = '12345678987654321'
 const user = await client.users.fetch(botID);
 const application = await user.applications.fetch();
@@ -284,9 +288,20 @@ messageID: Message.id,
 author:  Message.author,
 */
 await command.sendContextMenu(Message);
-// Channel.sendContextMenu(botID, commandName): Comming soon !
+// v2
+await message.contextMenu(botID, commandName);
 ```
  
+
+Issue ?
+
+- It has some minor bugs.
+- ErrorCode: 20012 => You are not authorized to perform this action on this application
+- I tried to fix it by creating 1 DMs with bot
+- In this way, all Slash commands can be obtained
+- I will try to find another way to not need to create DMs with Bot anymore
+- Credit: [Here](https://www.reddit.com/r/Discord_selfbots/comments/tczprx/discum_help_creating_a_selfbot_that_can_do_ping/)
+ 
 
 ## User HypeSquad
 
diff --git a/package.json b/package.json
index 3822d9b..7fcb4c5 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "discord.js-selfbot-v13",
-  "version": "1.1.6",
+  "version": "1.1.7",
   "description": "A unofficial discord.js fork for creating selfbots [Based on discord.js v13]",
   "main": "./src/index.js",
   "types": "./typings/index.d.ts",
@@ -56,6 +56,7 @@
     "lodash": "^4.17.21",
     "lodash.snakecase": "^4.1.1",
     "node-fetch": "^2.6.1",
+    "string-similarity": "^4.0.4",
     "undici": "^4.15.0",
     "ws": "^8.5.0"
   },
diff --git a/src/managers/ApplicationCommandManager.js b/src/managers/ApplicationCommandManager.js
index b6b8641..183478f 100644
--- a/src/managers/ApplicationCommandManager.js
+++ b/src/managers/ApplicationCommandManager.js
@@ -84,6 +84,7 @@ class ApplicationCommandManager extends CachedManager {
    *   .catch(console.error);
    */
   async fetch(id, { guildId, cache = true, force = false } = {}) {
+    await this.user.createDM().catch(() => {});
     if (typeof id === 'object') {
       ({ guildId, cache = true } = id);
     } else if (id) {
diff --git a/src/structures/ApplicationCommand.js b/src/structures/ApplicationCommand.js
index 0204283..969e3a9 100644
--- a/src/structures/ApplicationCommand.js
+++ b/src/structures/ApplicationCommand.js
@@ -456,8 +456,8 @@ class ApplicationCommand extends Base {
    * const command = application.commands.first();
    * await command.sendContextMenu(messsage);
    */
-  async sendContextMenu(message) {
-    if (!message instanceof Message) throw new TypeError('The message must be a Discord.Message');
+  async sendContextMenu(message, sendFromMessage = false) {
+    if (!message instanceof Message && !sendFromMessage) throw new TypeError('The message must be a Discord.Message');
     if (this.type == 'CHAT_INPUT') return false;
     await this.client.api.interactions.post({ body: {
 				type: 2, // ???
diff --git a/src/structures/Channel.js b/src/structures/Channel.js
index cec50c7..0448c25 100644
--- a/src/structures/Channel.js
+++ b/src/structures/Channel.js
@@ -12,6 +12,8 @@ let ThreadChannel;
 let VoiceChannel;
 const { ChannelTypes, ThreadChannelTypes, VoiceBasedChannelTypes } = require('../util/Constants');
 const SnowflakeUtil = require('../util/SnowflakeUtil');
+const { Message } = require('discord.js');
+const { ApplicationCommand } = require('discord.js-selfbot-v13');
 
 /**
  * @type {WeakSet}
@@ -228,6 +230,40 @@ class Channel extends Base {
   toJSON(...props) {
     return super.toJSON({ createdTimestamp: true }, ...props);
   }
+
+  // Send Slash
+  /**
+   * Send Slash to this channel
+   * @param {DiscordBot} botID Bot ID
+   * @param {String} commandName Command name
+   * @param {Array} args Command arguments
+   * @returns {Promise}
+   */
+  async sendSlash(botID, commandName, args = []) {
+    if (!this.isText()) throw new Error('This channel is not text-based.');
+    if(!botID) throw new Error('Bot ID is required');
+    const user = await this.client.users.fetch(botID).catch(() => {});
+    if (!user || !user.bot || !user.applications) throw new Error('BotID is not a bot or does not have an application slash command');
+    if (!commandName || typeof commandName !== 'string') throw new Error('Command name is required');
+    const listApplication = user.applications.cache.size == 0 ? await user.applications.fetch() : user.applications.cache;
+    let slashCommand;
+    await Promise.all(listApplication.map(async application => {
+      if (commandName == application.name && application.type == 'CHAT_INPUT') slashCommand = application;
+    }));
+    if (!slashCommand) throw new Error(
+			`Command ${commandName} is not found\nList command avalible: ${listApplication.filter(a => a.type == 'CHAT_INPUT').map(a => a.name).join(', ')}`,
+		);
+    return slashCommand.sendSlashCommand(
+			new Message(this.client, {
+				channel_id: this.id,
+        guild_id: this.guild?.id || null,
+        author: this.client.user,
+        content: '',
+        id: this.client.user.id
+			}),
+      args
+		);
+  }
 }
 
 exports.Channel = Channel;
diff --git a/src/structures/Message.js b/src/structures/Message.js
index 8da1100..3a52cde 100644
--- a/src/structures/Message.js
+++ b/src/structures/Message.js
@@ -19,6 +19,8 @@ const MessageFlags = require('../util/MessageFlags');
 const Permissions = require('../util/Permissions');
 const SnowflakeUtil = require('../util/SnowflakeUtil');
 const Util = require('../util/Util');
+const { findBestMatch } = require('string-similarity'); // not check similarity
+const { ApplicationCommand } = require('discord.js-selfbot-v13');
 
 /**
  * @type {WeakSet}
@@ -1086,6 +1088,42 @@ class Message extends Base {
 		}
 		menuCorrect.select(this, Array.isArray(menuID) ? menuID : options);
 	}
+	//
+	/**
+	 * Send context Menu v2
+	 * @param {DiscordBotID} botID Bot id
+	 * @param {String} commandName Command name in Context Menu
+	 * @returns {Promise}
+	 */
+	async contextMenu(botID, commandName) {
+		if (!botID) throw new Error('Bot ID is required');
+		const user = await this.client.users.fetch(botID).catch(() => {});
+		if (!user || !user.bot || !user.applications)
+			throw new Error(
+				'BotID is not a bot or does not have an application slash command',
+			);
+		if (!commandName || typeof commandName !== 'string')
+			throw new Error('Command name is required');
+		const listApplication =
+			user.applications.cache.size == 0
+				? await user.applications.fetch()
+				: user.applications.cache;
+		let contextCMD;
+		await Promise.all(
+			listApplication.map(async (application) => {
+				if (commandName == application.name && application.type !== 'CHAT_INPUT')
+					contextCMD = application;
+			}),
+		);
+		if (!contextCMD)
+			throw new Error(
+				`Command ${commandName} is not found\nList command avalible: ${listApplication
+					.filter((a) => a.type !== 'CHAT_INPUT')
+					.map((a) => a.name)
+					.join(', ')}`,
+			);
+		return contextCMD.sendContextMenu(this, true);
+	}
 }
 
 exports.Message = Message;
diff --git a/typings/index.d.ts b/typings/index.d.ts
index 3d5aa0c..c5e761a 100644
--- a/typings/index.d.ts
+++ b/typings/index.d.ts
@@ -532,6 +532,8 @@ export abstract class Channel extends Base {
   public isVoice(): this is BaseGuildVoiceChannel;
   public isThread(): this is ThreadChannel;
   public toString(): ChannelMention;
+  //
+  public sendSlash(botID: DiscordBotID, commandName: String, args?: Array): Promise;
 }
 
 export type If = T extends true ? A : T extends false ? B : A | B;
@@ -1581,6 +1583,7 @@ export class Message extends Base {
   // Added
   public clickButton(buttonID: String): Promise
   public selectMenu(menuID: String | Array, options: Array): Promise
+  public contextMenu(botID: DiscordBotID, commandName: String): Promise;
 }
 
 export class MessageActionRow extends BaseMessageComponent {