From cf747d5a63397f512f8721ed8b7dfeabb9668b65 Mon Sep 17 00:00:00 2001 From: ITOH Date: Mon, 14 Feb 2022 20:00:58 +0100 Subject: [PATCH 01/14] feat!: update to api version 10 (#2063) * testing stuff * feat: update to api version 10 * broken url import * do changes * delete test file --- rest/createRequestBody.ts | 1 + rest/rest_manager.ts | 3 ++- transformers/application.ts | 3 --- types/applications/application.ts | 2 -- types/messages/editMessage.ts | 2 +- util/constants.ts | 4 ++-- 6 files changed, 6 insertions(+), 9 deletions(-) diff --git a/rest/createRequestBody.ts b/rest/createRequestBody.ts index ea2681a99..5f64438a0 100644 --- a/rest/createRequestBody.ts +++ b/rest/createRequestBody.ts @@ -18,6 +18,7 @@ export function createRequestBody(rest: RestManager, queuedRequest: { request: R // IF A REASON IS PROVIDED ENCODE IT IN HEADERS if (queuedRequest.payload.body?.reason) { headers["X-Audit-Log-Reason"] = encodeURIComponent(queuedRequest.payload.body.reason as string); + queuedRequest.payload.body.reason = undefined; } // IF A FILE/ATTACHMENT IS PRESENT WE NEED SPECIAL HANDLING diff --git a/rest/rest_manager.ts b/rest/rest_manager.ts index 1fb0b52d9..05cfc151c 100644 --- a/rest/rest_manager.ts +++ b/rest/rest_manager.ts @@ -10,9 +10,10 @@ import { RestPayload, RestRateLimitedPath, RestRequest } from "./rest.ts"; import { runMethod } from "./runMethod.ts"; import { simplifyUrl } from "./simplifyUrl.ts"; import { baseEndpoints } from "../util/constants.ts"; +import { API_VERSION } from "../util/constants.ts"; export function createRestManager(options: CreateRestManagerOptions) { - const version = options.version || "9"; + const version = options.version || API_VERSION; if (options.customUrl) { baseEndpoints.BASE_URL = `${options.customUrl}/v${version}`; diff --git a/transformers/application.ts b/transformers/application.ts index d691a1e59..2efa784a8 100644 --- a/transformers/application.ts +++ b/transformers/application.ts @@ -14,7 +14,6 @@ export function transformApplication(bot: Bot, payload: SnakeCasedPropertiesDeep botRequireCodeGrant: payload.bot_require_code_grant, termsOfServiceUrl: payload.terms_of_service_url, privacyPolicyUrl: payload.privacy_policy_url, - summary: payload.summary, verifyKey: payload.verify_key, primarySkuId: payload.primary_sku_id, slug: payload.slug, @@ -51,8 +50,6 @@ export interface DiscordenoApplication { privacyPolicyUrl?: string; /** Partial user object containing info on the owner of the application */ owner?: Partial; - /** If this application is a game sold on Discord, this field will be the summary field for the store page of its primary sku */ - summary: string; /** The hex encoded key for verification in interactions and the GameSDK's GetTicket */ verifyKey: string; /** If the application belongs to a team, this will be a list of the members of that team */ diff --git a/types/applications/application.ts b/types/applications/application.ts index 76618c632..ec0dd235b 100644 --- a/types/applications/application.ts +++ b/types/applications/application.ts @@ -24,8 +24,6 @@ export interface Application { privacyPolicyUrl?: string; /** Partial user object containing info on the owner of the application */ owner?: Partial; - /** If this application is a game sold on Discord, this field will be the summary field for the store page of its primary sku */ - summary: string; /** The hex encoded key for verification in interactions and the GameSDK's GetTicket */ verifyKey: string; /** If the application belongs to a team, this will be a list of the members of that team */ diff --git a/types/messages/editMessage.ts b/types/messages/editMessage.ts index 20d93adf0..c802537af 100644 --- a/types/messages/editMessage.ts +++ b/types/messages/editMessage.ts @@ -23,7 +23,7 @@ export interface EditMessage { users?: bigint[]; }) | null; - /** Attached files to keep */ + /** When specified (adding new attachments), attachments which are not provided in this list will be removed. */ attachments?: Attachment[]; /** The components you would like to have sent in this message */ components?: MessageComponents; diff --git a/util/constants.ts b/util/constants.ts index 379bd023a..5e036c9f6 100644 --- a/util/constants.ts +++ b/util/constants.ts @@ -2,10 +2,10 @@ export const BASE_URL = "https://discord.com/api"; /** https://discord.com/developers/docs/reference#api-versioning-api-versions */ -export const API_VERSION = 9; +export const API_VERSION = 10; /** https://discord.com/developers/docs/topics/gateway#gateways-gateway-versions */ -export const GATEWAY_VERSION = 9; +export const GATEWAY_VERSION = 10; // TODO: update this version /** https://github.com/discordeno/discordeno/releases */ From b7b2120a6fb2033f218d0e15d1e7be10e9d0adc9 Mon Sep 17 00:00:00 2001 From: meister03 <69507874+meister03@users.noreply.github.com> Date: Tue, 15 Feb 2022 14:54:05 +0100 Subject: [PATCH 02/14] docs(site, template): add Nodejs Bot Guide (#1998) * Inital Docs * Finish Design * Finish Design * Add FILE Structure' * Add Not Ready Template * Update Template * Add Command Manager and first Command ping * Add Command Manager and first Command ping * Add Embeds Guide & EventManager * INITIAL FINISH: GUIDE * FIX TYPOS, LTS's Review, sidebar_position * Update site/docs/nodejs/getting-started.md Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> * Fixed Position? Add some comments on template, add changes in review * Add Interaction Handling, Modals * format files * Update site/docs/nodejs/getting-started.md 1 Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> * Update site/docs/nodejs/CommandHandler/command-manager.md Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> * Fix Review things * itoh's suggestions The guide looks very very veery good overall I like it. This commit adds my personal style of writing. Please review it :pray:. PS: I hope these are not too many changes .-. * deno fmt Co-authored-by: meister03 Co-authored-by: ITOH Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> --- .../nodejs/CommandHandler/_category_.json | 4 + .../nodejs/CommandHandler/command-manager.md | 91 ++++++++ .../nodejs/CommandHandler/create-command.md | 61 +++++ .../nodejs/CommandHandler/getting-started.md | 22 ++ site/docs/nodejs/EventHandler/_category_.json | 4 + .../docs/nodejs/EventHandler/event-manager.md | 119 ++++++++++ .../nodejs/EventHandler/getting-started.md | 29 +++ site/docs/nodejs/EventHandler/handle-event.md | 74 ++++++ site/docs/nodejs/Structures/_category_.json | 4 + site/docs/nodejs/Structures/components.md | 219 ++++++++++++++++++ .../nodejs/Structures/create-structure.md | 79 +++++++ site/docs/nodejs/Structures/embeds.md | 107 +++++++++ .../docs/nodejs/Structures/getting-started.md | 30 +++ site/docs/nodejs/_category_.json | 4 + site/docs/nodejs/create-application.md | 29 +++ site/docs/nodejs/design.md | 203 ++++++++++++++++ site/docs/nodejs/getting-started.md | 48 ++++ site/docs/nodejs/initial-setup.md | 46 ++++ site/docs/nodejs/installion.md | 29 +++ site/docs/nodejs/slash-command.md | 64 +++++ template/nodejs/Managers/ChannelManager.js | 17 ++ template/nodejs/Managers/CommandManager.js | 136 +++++++++++ template/nodejs/Managers/EventManager.js | 32 +++ template/nodejs/Managers/MemberManager.js | 13 ++ template/nodejs/Managers/RoleManager.js | 29 +++ .../nodejs/Plugins/Developer/commands/eval.js | 49 ++++ .../Plugins/Developer/commands/reload.js | 19 ++ template/nodejs/Plugins/Developer/index.js | 0 .../nodejs/Plugins/General/commands/ping.js | 24 ++ template/nodejs/Plugins/General/index.js | 0 .../nodejs/Plugins/Moderation/commands/ban.js | 40 ++++ template/nodejs/Plugins/Moderation/index.js | 0 template/nodejs/Structures/BaseCommand.js | 17 ++ template/nodejs/Structures/Channel.js | 29 +++ template/nodejs/Structures/CommandResponse.js | 57 +++++ template/nodejs/Structures/Component.js | 171 ++++++++++++++ template/nodejs/Structures/DestructObject.js | 16 ++ template/nodejs/Structures/Embed.js | 99 ++++++++ template/nodejs/Structures/Guild.js | 18 ++ template/nodejs/Structures/Interaction.js | 116 ++++++++++ template/nodejs/Structures/Member.js | 16 ++ template/nodejs/Structures/Message.js | 50 ++++ template/nodejs/Structures/Permissions.js | 9 + template/nodejs/Structures/Role.js | 12 + template/nodejs/Structures/User.js | 13 ++ template/nodejs/events/interactionCreate.js | 3 + template/nodejs/events/messageCreate.js | 3 + template/nodejs/events/ready.js | 9 + template/nodejs/index.js | 29 +++ 49 files changed, 2292 insertions(+) create mode 100644 site/docs/nodejs/CommandHandler/_category_.json create mode 100644 site/docs/nodejs/CommandHandler/command-manager.md create mode 100644 site/docs/nodejs/CommandHandler/create-command.md create mode 100644 site/docs/nodejs/CommandHandler/getting-started.md create mode 100644 site/docs/nodejs/EventHandler/_category_.json create mode 100644 site/docs/nodejs/EventHandler/event-manager.md create mode 100644 site/docs/nodejs/EventHandler/getting-started.md create mode 100644 site/docs/nodejs/EventHandler/handle-event.md create mode 100644 site/docs/nodejs/Structures/_category_.json create mode 100644 site/docs/nodejs/Structures/components.md create mode 100644 site/docs/nodejs/Structures/create-structure.md create mode 100644 site/docs/nodejs/Structures/embeds.md create mode 100644 site/docs/nodejs/Structures/getting-started.md create mode 100644 site/docs/nodejs/_category_.json create mode 100644 site/docs/nodejs/create-application.md create mode 100644 site/docs/nodejs/design.md create mode 100644 site/docs/nodejs/getting-started.md create mode 100644 site/docs/nodejs/initial-setup.md create mode 100644 site/docs/nodejs/installion.md create mode 100644 site/docs/nodejs/slash-command.md create mode 100644 template/nodejs/Managers/ChannelManager.js create mode 100644 template/nodejs/Managers/CommandManager.js create mode 100644 template/nodejs/Managers/EventManager.js create mode 100644 template/nodejs/Managers/MemberManager.js create mode 100644 template/nodejs/Managers/RoleManager.js create mode 100644 template/nodejs/Plugins/Developer/commands/eval.js create mode 100644 template/nodejs/Plugins/Developer/commands/reload.js create mode 100644 template/nodejs/Plugins/Developer/index.js create mode 100644 template/nodejs/Plugins/General/commands/ping.js create mode 100644 template/nodejs/Plugins/General/index.js create mode 100644 template/nodejs/Plugins/Moderation/commands/ban.js create mode 100644 template/nodejs/Plugins/Moderation/index.js create mode 100644 template/nodejs/Structures/BaseCommand.js create mode 100644 template/nodejs/Structures/Channel.js create mode 100644 template/nodejs/Structures/CommandResponse.js create mode 100644 template/nodejs/Structures/Component.js create mode 100644 template/nodejs/Structures/DestructObject.js create mode 100644 template/nodejs/Structures/Embed.js create mode 100644 template/nodejs/Structures/Guild.js create mode 100644 template/nodejs/Structures/Interaction.js create mode 100644 template/nodejs/Structures/Member.js create mode 100644 template/nodejs/Structures/Message.js create mode 100644 template/nodejs/Structures/Permissions.js create mode 100644 template/nodejs/Structures/Role.js create mode 100644 template/nodejs/Structures/User.js create mode 100644 template/nodejs/events/interactionCreate.js create mode 100644 template/nodejs/events/messageCreate.js create mode 100644 template/nodejs/events/ready.js create mode 100644 template/nodejs/index.js diff --git a/site/docs/nodejs/CommandHandler/_category_.json b/site/docs/nodejs/CommandHandler/_category_.json new file mode 100644 index 000000000..384da5c64 --- /dev/null +++ b/site/docs/nodejs/CommandHandler/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Command Handler", + "position": 7 +} diff --git a/site/docs/nodejs/CommandHandler/command-manager.md b/site/docs/nodejs/CommandHandler/command-manager.md new file mode 100644 index 000000000..700d6be5e --- /dev/null +++ b/site/docs/nodejs/CommandHandler/command-manager.md @@ -0,0 +1,91 @@ +--- +sidebar_position: 2 +--- + +# Command Manager + +Currently, you probably have something like this in your code: + +```js +const Discord = require("discordeno"); +// Ideally you should move to an `.env` file +const config = require("./config.json"); + +const client = Discord.createBot({ + events: { + messageCreate(client, message) { + if (message.content === "!ping") { + client.helpers.sendMessage(message.channelId, { content: "pong" }); + } + }, + }, + intents: ["Guilds", "GuildMessages"], + token: config.token, +}); + +Discord.startBot(client); +``` + +Of course, if you add more and more commands and as your code base grows, you can lose track very quickly. + +To avoid this, it is recommended to store the commands in separate folders divided into different categories. + +[Previously, we introduced you to our plugin structure, which has a lot of advantages.](../design.md) + +```root +├Plugins/ +├── General/ +│ ├── commands/ +│ │ ├── ping.js +│ │ └── ... +├── Developer/ +│ ├── commands/ +│ │ ├── eval.js +│ │ └── ... +└── ... +``` + +**Get [this file](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Managers/CommandManager.js) from +the [nodejs template](https://github.com/discordeno/discordeno/tree/main/template)** + +```js +const CommandManager = require("./template/Managers/CommandManager.js"); +const manager = new CommandManager({}); +manager.load({ plugin: true }); // Load the commands +client.commands = manager; + +client.commands.cache.get("ping"); // Get the `ping` command +``` + +The Manager will automatically iterate through all files in the folder and then load them into the cache property, which +is mapped on the command name. + +**Take a look at [Create Command](./create-command.md) to learn how to create a command.** + +## Handle Command + +The manager also contains a handler for executing the command when a message is received. + +:::important + +Currently checks for permissions, cooldowns, and rate limits are not covered, but these will be added soon. + +::: + +### Message Create Event: + +```js +module.exports = async (client, message) => { + client.commands.isCommand(message); +}; +``` + +### Interaction Create Event: + +```js +module.exports = async (client, interaction) => { + client.commands.isInteraction(interaction); +}; +``` + +You can also customize the `isCommand` function to your use case. diff --git a/site/docs/nodejs/CommandHandler/create-command.md b/site/docs/nodejs/CommandHandler/create-command.md new file mode 100644 index 000000000..672d265ba --- /dev/null +++ b/site/docs/nodejs/CommandHandler/create-command.md @@ -0,0 +1,61 @@ +--- +sidebar_position: 3 +--- + +# Create Command + +One of the most important features we wanted in our template, was that you can use the same code for handling +`slash commands` and `message based commands`. + +This can be done by saving the static class in the command cache, creating a constructor and passing the desired data. +Moreover the `BaseCommand` is extended with the `Response Command` class, so you can take advantage of functions such as +`.reply()` + +**Copy the [`BaseCommand`](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Structures/BaseCommand.js) +& +[`CommandResponses`](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Structures/CommandResponses.js) +code from the template** + +### Creating a Ping Command: + +```js +const BaseCommand = require("../../../Structures/BaseCommand.js"); +const Embed = require("../../../Structures/Embed.js"); + +class pingCommand extends BaseCommand { + static name = "ping"; + static description = "See if the bot latency is okay"; + static usage = ""; + static category = "General"; + static slash = { name: "ping", category: "info" }; + + constructor(data) { + super(data); + } + + async execute() { + const msg = await this.reply({content: `Pinging...`}); + // Assign properties to the response + const ping = msg.timestamp - this.message.timestamp; + + const embed = new Embed() + .setTitle(`The Bots ping is ${ping} ms`) + .toJSON(); + + // Edit Message with the Embed + return await msg.edit({embeds: [embed] }); + }); + } +} + +module.exports = pingCommand; +``` + +- The `BaseCommand` is extended with the `CommandResponses` class. +- The ping command class is been extended with the `BaseCommand` class. +- Some static properties are assigned to the ping command class, in order to access it in the cache, such as `name`, + `description`, `usage`, `category` and `slash`... +- The `execute()` function will be called, when the command has been run by the user. +- The constructor allows to access data, such as `this.message`, `this.args`, `this.client`... + +You can customize the `CommandManager` file, in order to pass arguments in the `execute()` function. diff --git a/site/docs/nodejs/CommandHandler/getting-started.md b/site/docs/nodejs/CommandHandler/getting-started.md new file mode 100644 index 000000000..622175240 --- /dev/null +++ b/site/docs/nodejs/CommandHandler/getting-started.md @@ -0,0 +1,22 @@ +--- +sidebar_position: 1 +--- + +# Getting Started with the Command Manager + +One of the most important characteristics of bots is that they have commands that can be used to interact with the bot. + +Hard coding your commands in an event function is not the best code practice and should be strictly prevented. + +In the following we will show you how to create a command manager, which is compatible with Discordeno's Client. + +- Load Commands +- Handle Commands +- Reload Commands + +:::info template + +You can also copy the +[`CommandManager` from the template repo](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Managers/CommandManager.js). + +::: diff --git a/site/docs/nodejs/EventHandler/_category_.json b/site/docs/nodejs/EventHandler/_category_.json new file mode 100644 index 000000000..32da17a11 --- /dev/null +++ b/site/docs/nodejs/EventHandler/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Event Handler", + "position": 6 +} diff --git a/site/docs/nodejs/EventHandler/event-manager.md b/site/docs/nodejs/EventHandler/event-manager.md new file mode 100644 index 000000000..1740f07d8 --- /dev/null +++ b/site/docs/nodejs/EventHandler/event-manager.md @@ -0,0 +1,119 @@ +--- +sidebar_position: 2 +--- + +# Create Event Manager + +In order to process certain events, you must provide the Discordeno client with functions for these events. + +```js +const Discord = require("discordeno"); +const config = require("./config.json"); + +const client = Discord.createBot({ + events: { + ready(client, payload) { + console.log(`Successfully connected Shard ${payload.shardId} to the gateway`); + }, + + async messageCreate(client, message) { + if (message.content === "!ping") { + await client.helpers.sendMessage(message.channelId, { content: "pong" }); + } + + console.log(`Received message: ${message.content || message.embeds}`); + }, + }, + intents: ["Guilds", "GuildMessages"], + token: config.token, +}); + +Discord.startBot(client); +``` + +As you listen to more and more events, the functions code grows along with them, so you can quickly lose track. + +To avoid this, we recommend storing the event functions divided into files in a separate folder. + +## Create Event Folder + +Create a folder called `events` in your project folder. + +:::info note + +The event files have to be named using camelCase so that they can be understood by the client. e.g `message` -> +`messageCreate.js`. You can check the typings see how the events are called. + +::: + +Ready Event: + +```js +module.exports = (client, payload) => { + if (payload.shardId + 1 === client.gateway.maxShards) { + // All Shards are ready + console.log(`Successfully connected to the gateway as ${payload.user.username}#${payload.user.discriminator}`); + } +}; +``` + +## Load your Events + +```js +const fs = require("fs"); +const path = require("path"); + +const resolveFolder = (folderName) => path.resolve(__dirname, ".", folderName); + +class EventManager { + constructor(client) { + this.cache = new Map(); + this._events = {}; + } + + load(options = {}) { + const eventsFolder = resolveFolder("../events"); + fs.readdirSync(eventsFolder).map(async (file) => { + if (!file.endsWith(".js")) return; + + const fileName = path.join(eventsFolder, file); + const event = require(fileName); + const eventName = file.split(".")[0]; + + this._events[`${eventName}`] = event; + }); + + return this._events; + } +} + +module.exports = EventManager; +``` + +The code above, which can also be found in the +[template repo](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Managers/EventManager.js) will loop +through all the files in the `events` folder and load the functions into the `_events` object. + +In order to let the client know which events should be processed, you need to pass the functions in the +`createBot.events` object. + +```js +const Discord = require("discordeno"); +const config = require("./config.json"); + +const EventManager = require("./Managers/EventManager.js"); +const events = new EventManager({}); + +const client = Discord.createBot({ + events: events.load({}), + intents: ["Guilds", "GuildMessages"], + token: config.token, +}); + +Discord.startBot(client); +``` + +Moreover, you can customize the `EventManager` and add more functionality to it and make it exactly fit your your needs +or even emit events, by extending it. + +Of course you wonder what you can do with all of this now. We will explain this further on the next page. diff --git a/site/docs/nodejs/EventHandler/getting-started.md b/site/docs/nodejs/EventHandler/getting-started.md new file mode 100644 index 000000000..ef6d0e8c4 --- /dev/null +++ b/site/docs/nodejs/EventHandler/getting-started.md @@ -0,0 +1,29 @@ +--- +sidebar_position: 1 +--- + +# Getting Started with the Event Handler + +An event handler is essential to process the data, which Discord sends to you. + +With a good implementation, you will have a nice code structure and thus have a good overview in long term. + +Since the `EventEmitter` class is commonly used you probably already know it from other libraries. + +Discordeno decided against it as it comes with several downsides which are mentioned below. + +Performance plays a more important role than handling, however this event management system can be easily implemented +since it only needs a few changes in your code. + +- It's easy to create memory leaks, when you add too many listeners or go carelessly with it. +- Many fragmented parts of event code complicate maintenance. +- ErrorHandling is difficult and debugging is harder when many listeners are open for the same events. + +In the following we will show you, how to create an event manager, which is compatible with Discordeno's Client. + +:::info template + +You can also copy the +[`EventManager` from the template repo](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Managers/EventManager.js). + +::: diff --git a/site/docs/nodejs/EventHandler/handle-event.md b/site/docs/nodejs/EventHandler/handle-event.md new file mode 100644 index 000000000..2ebe9632b --- /dev/null +++ b/site/docs/nodejs/EventHandler/handle-event.md @@ -0,0 +1,74 @@ +--- +sidebar_position: 3 +--- + +# Handle Events + +When an event is fired, Discordeno sends two important things: the `client` instance and the `payload`. + +As mentioned in the `Structure` section the `payload` object, does not contain any functions, its a plain json object. + +In order to take use of our nice built structures, we need to transform the payload into a structure. + +:::info + +The Structures can be found [here](https://github.com/discordeno/discordeno/tree/main/template/nodejs/Structures) + +::: + +Sometimes it's important to listen to events, in order to get informed of changes and updating the cache based on it. + +### Message Event + +This file should be called `messageCreate.js`. + +```js +const Message = require("./structures/Message"); + +module.exports = async (client, payload) => { + const message = new Message(client, payload); + + if (message.isBot) return; + if (message.content === "!ping") return await message.reply("pong"); +}; +``` + +### Interaction Event + +This file should be called `interactionCreate.js`. + +```js +const Interaction = require("./structures/Interaction"); + +module.exports = async (client, payload) => { + const interaction = new Interaction(client, payload); + + if (interaction.data.name === "ping") return await interaction.reply({ content: "pong" }); +}; +``` + +### Ready Event + +This file should be called `ready.js`. + +:::tip + +There is a small difference with the `ready` Event. The Event is fired `shard` wise, in other words it fires every time +a `shard` becomes ready. + +::: + +In order to fire the "real event" a small code snippet has to be added to the `ready` Event. + +```js +const User = require("../Structures/User"); + +module.exports = async (client, payload) => { + client.user = new User(client, payload.user); + + if (payload.shardId + 1 === client.gateway.maxShards) { + // All Shards are ready + console.log(`Successfully connected to the gateway as ${client.user.tag}`); + } +}; +``` diff --git a/site/docs/nodejs/Structures/_category_.json b/site/docs/nodejs/Structures/_category_.json new file mode 100644 index 000000000..8bfdb91d2 --- /dev/null +++ b/site/docs/nodejs/Structures/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Structures", + "position": 5 +} diff --git a/site/docs/nodejs/Structures/components.md b/site/docs/nodejs/Structures/components.md new file mode 100644 index 000000000..68651a284 --- /dev/null +++ b/site/docs/nodejs/Structures/components.md @@ -0,0 +1,219 @@ +--- +sidebar_position: 4 +--- + +# Create Components + +Since Discord has decided to make message content accessible only to privileged bots, components will play an +increasingly important role in the future. Discord has released some components already and many more will follow. Of +course, this opens up completely new possibilities. On the one hand, it improves the user experience and on the other +hand, the interactions can be easily handled by the developer. + +To take advantage of this, we'll go into more detail on how to use them. + +:::note Runtime Overhead + +Constructor classes are nice to use and make your code look better, but they incur a slight runtime overhead compared to +just using raw data because they still execute methods, which takes more time to process. + +::: + +We already have a Template for `Components`, which can be found +[here](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Component.js). + +## Different Components: + +There are many different components, which you can quickly read about here: + +### Action Row (`type: 1`): + +This is a top level component, which contains a limited amount of other components. It can be described as container. + +An Action Row ... + +- can not include an action row +- can maximal have 5 Buttons +- can have 1 SelectMenu +- can have 1 Text Input (only available in modal responses) + +### Button (`type: 2`): + +Buttons are interactive components, are bound to a message and they sent an interaction payload, when a user clicks on +it. + +![Different Button Styles](https://i.imgur.com/jUE2Kp0.png) + +- Needs a customId, except the Link Button +- An Action Row can have maximal 5 Buttons + +There are different styles of buttons, which can be used: + +- `1` - PRIMARY - blurple - customId required +- `2` - DEFAULT - grey - customId required +- `3` - SUCCESS - green - customId required +- `4` - DANGER - red - customId required +- `5` - LINK - grey - url required + +### Select Menu (`type: 3`): + +Select Menus are a simple drop-down with selectable options. They accept a set of allowed selects, which sends an +interaction payload, when a user selects sth. from the menu. + +![Select Menu](https://i.imgur.com/42Hwiuw.png) + +- You can specify a range of allowed selects (`minValue` and `maxValue`) +- Every Select Item can have an `emoji` and has a `value`, in order to identify the selected item +- A default Select Item can be set +- An Action Row can have maximal 1 Select Menu + +### Text Input (`type: 4`): + +Text Inputs are interactive components, which can just be sent with a modal response. + +- You can specify a range of text length (`minLength` and `maxLength`) +- You can add a placeholder, a pre-filled value and specify whether the text input is required +- An Action Row can have maximal 1 Text Input + +## Send Components + +As mentioned above there are different types of components. This requires to define a type, so that Discord knows, which +component you want to use. + +```js +class ActionRow { + constructor(options = {}) { + this.type = 1; + } + + setComponents(...components) { + this.components = components; + return this; + } +} +``` + +```js +const button = new Button(); +const button2 = new Button(); +const actionRow = new ActionRow().setComponents(button, button2); +``` + +This code will obviously not work because it's a missing a lot required of data. The other reason is that we can't send +a class to Discord, we need sth. to transform it to a json object. + +We have a pre-made class for components which you can find +[here](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Component.js). + +### Button + +```js +const button = new Component() + .setType("BUTTON") + .setStyle("LINK") + .setLabel("Click me!") + .setUrl("https://google.com") + .toJSON(); + +// Button with raw types +const button2 = new Component() + .setType(2) + .setStyle(4) + .setLabel("DO NOT CLICK") + .setCustomId("12345") + .toJSON(); + +const actionRow = new Component() + .setType("ACTION_ROW") + .setComponents(button, button2) + .toJSON(); + +// Message to send +const messageOptions = { content: "hello", components: [actionRow] }; + +await client.helpers.sendMessage(channelId, messageOptions); // You can also use the Message Structure +``` + +As you can see, for simplicity you can use strings instead of numbers (types), which are hard to remember. + +### Select Menu + +```js +const selectMenu = new Component() + .setType("SELECT_MENU") + .setCustomId("12345") + .setOptions([ + { + label: "Option 1", + value: "1", + description: `This is option 1`, + }, + { + label: "Option 2", + value: "2", + description: `This is option 2`, + }, + { + label: "Default Option", + value: "3", + description: `Default option...`, + default: true, + }, + ]) + .setPlaceholder("Select an option") + .toJSON(); + +const actionRow = new Component() + .setType("ACTION_ROW") + .setComponents(selectMenu) + .toJSON(); + +const messageOptions = { content: "hello", components: [actionRow] }; + +client.helpers.sendMessage(channelId, messageOptions); // You can also use the Message Structure +``` + +### Text Input + +```js +const textInput = new Component() + .setType("TEXT_INPUT") + .setStyle("SHORT") + .setCustomId("t1") + .setLabel("User ID") + .setPlaceholder("User ID") + .setRequired(true) + .setMaxLength(20) + .setMinLength(1) + .toJSON(); + +const textInput2 = new Component() + .setType("TEXT_INPUT") + .setStyle("PARAGRAPH") + .setCustomId("t2") + .setLabel("Reason") + .setPlaceholder("Reason for Ban") + .setRequired(false) + .setMaxLength(300) + .toJSON(); + +const actionRow = new Component().setType("ACTION_ROW").setComponents(textInput).toJSON(); +const actionRow2 = new Component().setType("ACTION_ROW").setComponents(textInput2).toJSON(); + +new Interaction(client, interaction).popupModal({ + customId: "ban_modal", + title: "Ban User", + components: [actionRow, actionRow2], +}); +``` + +### Receive Interactions + +When a user clicks a button or selects an option from a Select Menu, Discord sends an `interactionCreate` event, which +contains the information necessary to process it. + +:::note Collecting + +An `InteractionCollector` can also be used to handle prompts, which requires some tweaks, but will be added soon in the +guide and the template repo. + +::: diff --git a/site/docs/nodejs/Structures/create-structure.md b/site/docs/nodejs/Structures/create-structure.md new file mode 100644 index 000000000..d7b7808c2 --- /dev/null +++ b/site/docs/nodejs/Structures/create-structure.md @@ -0,0 +1,79 @@ +--- +sidebar_position: 2 +--- + +# Create Structure + +Structures are often used to transform data and add methods to existing objects. To make it easier to work with them. + +Imagine you have a channel object to which you want to send a message. + +```js +const data = { + id: 806947972004839444n, + name: "spam-and-bots", +}; +``` + +The recommended way would be: + +```js +await client.helpers.sendMessage(data.id, { content: "hello" }); +``` + +However, you probably want to use something shorter, such as the following: + +```js +const Channel { + constructor(client, data) { + this.client = client; + this.id = data.id; + this.name = data.name; + } + + async send(options) { + return await client.helpers.sendMessage(this.id, options); + } +} +``` + +Now you can use the `.send()` method on the channel object without using such a long code: + +```js +const channel = new Channel(client, data); +await channel.send({ content: "hello" }); +``` + +Moreover, you can modify the `.send()` method to better suit your use case e.g not send the message if the channel is +blacklisted. + +This naturally opens a lot of opportunities and makes coding a lot easier. Because you decide what you want to do with +the data, how the methods are named and how you want to process the request. + +## Using Template Structures: + +When you are migrating from another library, you'll likely choose to continue using special structures. Therefore why we +have ready-made structures in our template repo: + +- [Guild](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Guild.js) +- [Channel](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Channel.js) +- [Role](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Role.js) +- [Member](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Member.js) +- [User](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/User.js) +- [Message](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Message.js) +- [Interaction](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Interaction.js) + +We recommend that you clone the whole template repo, since some structures are based on other files. + +**Using the Structures:** + +```js +const Guild = require("./structures/Guild"); // Path to your structure +const guild = new Guild(client, data); // DiscordenoClient and DiscordenoPayloadData +``` + +Some popular methods have been added to the structures so that you can use them without having to come up with your own. +Of course, you can add your own methods and customize the structures to fit your needs. + +Next we're going to give a better insight into how create [`Embeds`](embeds) and [`Components`](components) with the +template structures. diff --git a/site/docs/nodejs/Structures/embeds.md b/site/docs/nodejs/Structures/embeds.md new file mode 100644 index 000000000..48015d54e --- /dev/null +++ b/site/docs/nodejs/Structures/embeds.md @@ -0,0 +1,107 @@ +--- +sidebar_position: 3 +--- + +# Create Embeds + +Embeds are widely used by bots in order to display messages in a fancy way. + +Unfortunately, the Discord API does not accept funky classes such as `new MessageEmbed().setTitle("hello")`, instead it +takes a json object, e.g. `{ title: "hello" }`. Therefore, we need to create an embed Structure that converts the +user-supplied data into the format which Discord uses. + +:::note Runtime Overhead + +Constructor classes are nice to use and make your code look better, but they incur a slight runtime overhead compared to +just using raw data because they still execute methods, which takes more time to process. + +::: + +```js +class Embed() { + constructor() {} + + setTitle(title) { + this.title = title; + } +} +``` + +Now we have created a class which we can use to create embeds. But we can't just send this to Discord. + +So we need an additional method which will convert the data from the class to the correct format. + +```js +class Embed(){ + constructor() {} + + setTitle(title) { + this.title = title; + } + + toJSON() { + return { + title: this.title + } + } +} +``` + +Wow, now you can create a embed and send it to Discord. + +```js +const Channel = require("./structures/Channel"); // Path to structure + +const channel = new Channel(client, data); +await channel.send({ embeds: [embed] }); +``` + +You probably want more methods which you can use to create embeds. +[We also have a Template for this](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Embed.js) + +### Using the Embed Structure: + +```js +const Embed = require("./structures/Embed"); // Path to structure +const Channel = require("./structures/Channel"); // Path to structure + +const channel = new Channel(client, data); +const showCaseEmbed = new Embed() + .setColor(0x00AE86) + .setTitle("A Random Title") + .setURL("https://github.com/discordeno") + .setAuthor({ + name: "Author name", + iconUrl: "https://raw.githubusercontent.com/discordeno/discordeno/main/site/static/img/logo.png", + url: "https://github.com/discordeno", + }) + .setDescription("A Random Description") + .setThumbnail("https://raw.githubusercontent.com/discordeno/discordeno/main/site/static/img/logo.png") + .addFields( + { name: "Field 1 Name", value: "Normal Field Value" }, + { name: "\u200B", value: "\u200B" }, + { name: "Field 2 Name", value: "Inline Field Value", inline: true }, + { name: "Field 3 Name", value: "Inline Field Value", inline: true }, + ) + .addField({ name: "Field 4", value: "Field Value" }) + .setImage("https://raw.githubusercontent.com/discordeno/discordeno/main/site/static/img/logo.png") + .setTimestamp() + .setFooter({ + text: "A Footer Text", + iconUrl: "https://raw.githubusercontent.com/discordeno/discordeno/main/site/static/img/logo.png", + }) + .toJSON(); + +await channel.send({ embeds: [showCaseEmbed] }); +``` + +### Embed Limits: + +- Title: 256 characters +- Description: 4096 characters +- Field Name: 256 characters +- Field Value: 1024 characters +- Footer Text: 2048 characters +- Author Name: 256 characters +- 10 Embeds per message +- In total over all 10 Embeds not more than 6000 characters diff --git a/site/docs/nodejs/Structures/getting-started.md b/site/docs/nodejs/Structures/getting-started.md new file mode 100644 index 000000000..1898e757b --- /dev/null +++ b/site/docs/nodejs/Structures/getting-started.md @@ -0,0 +1,30 @@ +--- +sidebar_position: 1 +--- + +# Getting Started with Structures + +As previously mentioned, Discordeno was built with as few classes as possible, this is in favor of performance. + +For example, you cannot execute functions on objects. + +```diff +- message.channel.send({content: "hello"}) ++ client.helpers.sendMessage(message.channel.id, {content: "hello"}) +``` + +This seems to be more complicated at first, but has many advantages: + +- You get full control over the actions +- Errors are easier to debug +- A validation by classes does not have to take place + +One of the disadvantages is that you have to change a lot in your code. + +Of course, we recommend that you try out the upper way, but we will introduce structures in this guide because they are +used by many users who eventually want to migrate. + +For example, if you want to get correctly formatted objects, structures are obviously beneficial, because they support +the readability of the code by their ease of use + +In the following, we will introduce how to create your own structures and how to use the ones available in the template. diff --git a/site/docs/nodejs/_category_.json b/site/docs/nodejs/_category_.json new file mode 100644 index 000000000..b45c7e9ac --- /dev/null +++ b/site/docs/nodejs/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Nodejs", + "position": 3 +} diff --git a/site/docs/nodejs/create-application.md b/site/docs/nodejs/create-application.md new file mode 100644 index 000000000..b7197a8ba --- /dev/null +++ b/site/docs/nodejs/create-application.md @@ -0,0 +1,29 @@ +--- +sidebar_position: 3 +--- + +# Create Application + +1. Go to the [Developer Portal](https://discord.com/developers/applications) and create a new application. +2. Navigate to the Section `Bot` and confirm with "Yes, do it!" +3. Now copy your token and save it under a safe environment. + +:::caution Token Security + +Keep your token safe, because it is like a password that grants access to your bot, which then can be used for mass +DMing, mass banning or any other kind of malicious activity. + +::: + +## Add your Bot to your Server + +In order to use your Bot, it should be in a server where you can interact with it. + +1. Go to the [Developer Portal](https://discord.com/developers/applications) and click on your previously created bot. +2. Click on `OAuth2` and there go to the `URL Generator`. +3. Select the `bot` and the `applications.commands` scope. +4. Scroll down and select the `Administrator` permission. +5. Copy the generated URL and open it in your browser. +6. Select your Server and click the invite button. + +The bot should now have been added to your server and show as an offline user. diff --git a/site/docs/nodejs/design.md b/site/docs/nodejs/design.md new file mode 100644 index 000000000..580e70c7b --- /dev/null +++ b/site/docs/nodejs/design.md @@ -0,0 +1,203 @@ +--- +sidebar_position: 6 +--- + +# Design + +In order to ensure long-term scalability and maintainability, the code structure is of enormous importance. In the +following, we show how such a code structure could look like. + +The essential parts are a `CommandHandler/CommandManager`, `EventHandler/EventManager`, lots of `Structures` in order to +code faster and `Plugins`, where your different features will be, such as `Commands`, `DB Stuff`... + +## Code Structure + +We recommend following structure for your code: + +```root +├index.js +├─Structures/ +├─Managers/ +├─events/ +├─Plugins/ +├── General/ +│ ├── commands/ +│ │ ├── ping.js +│ │ └── ... +├── Developer/ +│ ├── commands/ +│ │ ├── eval.js +│ │ └── ... +├─Util/ +└── ... +``` + +The following explains why this structure is suitable. If you want to follow this guide further, you should create these +folders. + +In the `Managers` folder the Managers will be added e.g. `CommandManager.js`, `EventManager.js`. Generally codes, which +manage the system. + +While in the `Structures` folder mainly classes are added like `BaseCommand.js`, `CommandResponse.js`, `Embed.js`, +`Components.js`, which make it easier to add methods to objects. + +The `events` folder will contain the event handlers such as `messageCreate.js`, `debug.js` + +Your many useful features and categories end up in the `Plugins` folder, where they should be categorically divided into +many folders. + +The `Util` folder contains functions or classes that help you convert certain things, such as timestamps, into a +human-readable format. + +## CommandHandler & BaseCommand + +The `CommandHandler` is the main class of the bot, which will handle all the commands and the events received from +Discord. + +The `BaseCommand` is the base class of all commands, which will be extended with the`CommandResponse` class. + +### Steps showed in the following Guide + +- Loading commands from different plugins +- Deploying slash commands +- Handling `messageCreate` & `interactionCreate` events +- Command rate limit handling +- Handle `Interaction` & `Message` commands with the same code +- Validating user provided arguments +- Correct permission and error handling +- Hot reloading commands +- Creating message and interaction collectors + +## EventHandler + +You probably realized that Discordeno does not use an `EventEmitter` to fire the events, but your own event function is +fired. + +There are ways to adapt to an `EventEmitter`, but we decided against it for the following reasons: + +- It's easy to create memory leaks, when you add too many listeners or go carelessly with it. +- Many fragmented parts of event code complicate maintenance. +- ErrorHandling is difficult and debugging is harder when many listeners are open for the same events. + +## Structures + +Structures are essential to abstract larger parts of code in smaller ready-made methods and to modify them if necessary. + +Example: + +```js +class Command { + static name = "ping"; + static aliases = ["pong"]; + static botPermission = ["SEND_EMBED_LINKS"]; + + run(message, args) { + // do something + } +} +``` + +It would be annoying adding everytime the `botPermission` property to the class Command, when the Permission is used +from every Command, then it is unnecessary to add it, when you can extend the class. + +It would be annoying to add the `botPermission` property to the command class every time the same permissions are used +by each command. Extending the class makes this extra step obsolete. + +```js +class BaseCommand { + constructor(client) { + this.client = client; + this.basePermission = ["SEND_EMBED_LINKS"]; + } +} + +class Command extends BaseCommand { + static name = "ping"; + static aliases = ["pong"]; + + constructor(data) { + super(data); + } + + run(message, args) { + // do something + } +} +``` + +## Plugins + +The plugins folder helps you categorize your code into many parts to give some structure. + +Of course, this has many advantages, you have a much clearer code, you can debug problems much easier. + +This also opens possibilities for open source contributions, since not all parts of the code have to be published in +order to add new plugins, since they are "independent". + +There will be the main `Plugins` folder, which by default contains a `General` folder for all your base commands. The +`Plugins` folder will also contain all your other plugins. + +## Error Handling + +One of the most important things is how to handle errors. This is done to provide a user-friendly experience and to find +errors faster. + +You should catch errors and log them in your logger so you can fix them later. There are several open source `Sentry`'s +that give you a good overview of the latest errors through a website. + +Sometimes errors have a positive effect on maintainability and scalability. + +In addition, handling errors caused by users is very important to increase transparency. If they don't know why the +error happened, then they'll be very surprised with what they did wrong and might even remove your bot from their +server. + +## Caching + +Normally libraries cache all the info they get, which can of course be helpful at the beginning to discover all +functionalities but later it turns out to be a resource-consuming method. Therefore, this way should be avoided. + +Discordeno allows `Custom Caching` and even `Custom Property Caching` which gives you fine-grained control over the +caching of data. Normally you only need 20% of the data received by Discord, which makes caching unnecessary in most +cases. + +There are also some `Filter` and `Sweeper` methods which help you to empty unused cache values. + +## Cross Communication & Scaling + +If you are running many different processes, such as a Welcomer API, communication is of central importance in order to +send or receive data, with which you can then perform certain actions. + +Cross communication can be easily done with sockets or a TCP client. + +This brings up this Structure: + +```js +Bridge (Heart) +- Machine 1 + - Cluster [0-9] +- Machine 2 + - Cluster [10-18] +- Machine 3 -> Welcomer Api +- Machine 4 -> Dashboard +``` + +It's important to use something fast to have a proper "real time" communication. + +Discordeno already offers many internal options for scaling bots, no matter what size. + +As you scale, you will likely separate many parts of your bot and put them in separate processes, such as a +`RestManager`, a `Gateway Manager` etc. + +This of course opens up a lot of possibilities: + +- Zero downtime updates +- Global cache +- Synced rate limits + +[Check the Github Readme for more information](https://github.com/discordeno/discordeno#features) + +:::tip congratulations + +You just learned how to design a scalable bot, let's get into implementing it with the next pages. + +::: diff --git a/site/docs/nodejs/getting-started.md b/site/docs/nodejs/getting-started.md new file mode 100644 index 000000000..22a0548d2 --- /dev/null +++ b/site/docs/nodejs/getting-started.md @@ -0,0 +1,48 @@ +--- +sidebar_position: 1 +--- + +# Getting Started + +If you are reading this, you probably want to create a Discord bot with Discordeno or migrate from popular libraries +like Discord.js. + +If this is going to be your first time making a bot, you should use Deno instead of Node.js. Although in some cases Deno +might not be suitable for you, because of missing packages or a code base which too large to migrate to a slightly +different language. + +This guide will help you making your first Discord Bot using Node.js or even migrating your Bot from a other Library. + +:::important Disclaimer + +Some features are not documented yet. If you want to know more about them, kindly ask for help in the +[Discord Server](https://discord.gg/ddeno). + +::: + +## Why should I switch? + +Discordeno was built with the purpose of being scalable, flexible and easy to use. + +Libraries like `Discord.js` and `Eris` often have excessive caching behavior that can only be changed slightly without +breaking the entire library. There is a lack of customization and many nested classes, which makes it almost impossible +to edit the code without having unwanted side effects. Moreover scalability is only possible on a limited extend. + +Discordeno has been kept plain and simple, which opens up a lot of opportunities for customization such as +`custom-caching (custom-property-caching)`, [`Standalone Rest`](../big-bot-guide/rest.md), +[`Gateway`](../big-bot-guide/gateway.md), [`Cache`](../big-bot-guide/cache.md) and more. Check the detailed advantages +[here](https://github.com/discordeno/discordeno#features). + +This guide will also help you making your code more scalable and easier to maintain with bringing you closer to the +Discord API. + +# Before you start + +Before you start digging in this guide, you should have a solid understanding of `javascript`. If you are not familiar +with it, then you should take a look at some popular resources. + +- [W3Schools Course](https://www.w3schools.com/js/DEFAULT.asp) +- [Mozilla Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript) +- [JavaScript.Info](https://javascript.info) + +A basic understanding is of great importance in order to solve problems skillfully. diff --git a/site/docs/nodejs/initial-setup.md b/site/docs/nodejs/initial-setup.md new file mode 100644 index 000000000..04ab56456 --- /dev/null +++ b/site/docs/nodejs/initial-setup.md @@ -0,0 +1,46 @@ +--- +sidebar_position: 4 +--- + +# Initial Setup + +## Config File + +Ideally, you should save your configs in an `.env` file. Out of simplicity for this guide, we are saving it in a +`config.json` file. + +Create a file named `config.json` in your project folder and insert the following content: + +```json +{ + "token": "YOUR_TOKEN_HERE", + "prefix": "!" +} +``` + +## Edit the main file + +Open the `index.js` file which you have created earlier and then insert the following content: + +```js +const Discord = require("discordeno"); +const config = require("./config.json"); + +const client = Discord.createBot({ + events: { + ready(client, payload) { + console.log(`Successfully connected Shard ${payload.shardId} to the gateway`); + }, + }, + intents: ["Guilds", "GuildMessages"], + token: config.token, +}); + +Discord.startBot(client); +``` + +Now you can start your bot by running the following command in your terminal: + +```cli +$ node index.js +``` diff --git a/site/docs/nodejs/installion.md b/site/docs/nodejs/installion.md new file mode 100644 index 000000000..8a991dec5 --- /dev/null +++ b/site/docs/nodejs/installion.md @@ -0,0 +1,29 @@ +--- +sidebar_position: 2 +--- + +# Installing Node.js and Discordeno + +To use the Discordeno library you first need to install Node.js and then Discordeno from NPM. + +Go to [nodejs.org](https://nodejs.org/en/) and download the latest version of Node.js. Open the downloaded file and +follow the instructions of the installer to install Node.js. + +## Create a Folder + +Open your file manager and create a new folder (e.g.: `discordbot`) in your desired directory. Then open the code editor +of your choice and create a new file (e.g.: `index.js`) in the folder you just have created. + +### Initalize NPM & Install Discordeno + +In order to keep track of the dependencies, you need to initialize NPM, which generates a `package.json` file. + +```cli +$ npm init --yes +``` + +Then you need to install Discordeno. Go to your terminal and run the following command: + +```cli +$ npm install discordeno +``` diff --git a/site/docs/nodejs/slash-command.md b/site/docs/nodejs/slash-command.md new file mode 100644 index 000000000..a0d096e8c --- /dev/null +++ b/site/docs/nodejs/slash-command.md @@ -0,0 +1,64 @@ +--- +sidebar_position: 5 +--- + +# Slash Commands + +Since Discord has decided to make message content accessible only to privileged bots, message commands will play a +subordinate role in the future. Discord users will be more used to slash commands. That's why it's essential that every +bot offers them. + +In the following we will show you how to create slash commands: + +## Deploying Slash Commands + +There is a difference between global and guild commands. Global commands take a while to appear in all guilds. Guild +commands show up directly. + +For this reason, we will now show how to create guild commands, in order to test them immediately. + +```js +const guildId = BigInt("YOUR_GUILD_ID"); +const command = { + name: "ping", + description: "Retrieves the Bot latency", + options: [], +}; + +client.helpers.createApplicationCommand(command, guildId); +``` + +This is just very simple example, you can also add sub commands, select options and much more. + +## Handling Slash Commands + +Discord sends a WebSocket Event, when a user runs a slash command. You can listen to this event by add the +`interactionCreate` function in the client. + +```js +const Discord = require("discordeno"); +const config = require("./config.json"); + +const client = Discord.createBot({ + events: { + ready(client, payload) { + console.log(`Successfully connected Shard ${payload.shardId} to the gateway`); + }, + async interactionCreate(client, interaction) { + if (interaction.data?.name === "ping") { + return await client.helpers.sendInteractionResponse(interaction.id, interaction.token, { + type: Discord.InteractionResponseTypes.ChannelMessageWithSource, + data: { content: "🏓 Pong!" }, + }); + } + }, + }, + intents: ["Guilds"], + token: config.token, +}); + +Discord.startBot(client); +``` + +The handling may see complicated in the beginning, but as mentioned before, we will introduce structures to make it +easier. diff --git a/template/nodejs/Managers/ChannelManager.js b/template/nodejs/Managers/ChannelManager.js new file mode 100644 index 000000000..6258d73f9 --- /dev/null +++ b/template/nodejs/Managers/ChannelManager.js @@ -0,0 +1,17 @@ +const Channel = require("../Structures/Channel"); +class Channels { + constructor(client, data = {}, options = {}) { + this.client = client; + + if (options.guild) this.guild = options.guild; + } + + async create(options = {}, reason) { + return new Channel(this.client, options).create(options, reason); + } + + forge(data = {}) { + return new Channel(this.client, data); + } +} +module.exports = Channels; diff --git a/template/nodejs/Managers/CommandManager.js b/template/nodejs/Managers/CommandManager.js new file mode 100644 index 000000000..344a09524 --- /dev/null +++ b/template/nodejs/Managers/CommandManager.js @@ -0,0 +1,136 @@ +const resolveFolder = (folderName) => path.resolve(__dirname, ".", folderName); +const fs = require("fs"); +const path = require("path"); + +class CommandManager { + constructor(client) { + this.client = client; + this.cache = new Map(); + this.aliases = new Map(); + } + load(options = {}) { + const commandFolderPath = options.path || "../Plugins"; + const commandFolder = resolveFolder(commandFolderPath); + if (options.category === undefined) options.category = true; + if (options.plugins === undefined) options.plugins = true; + //PluginMode will iterate through all SubFolders + fs.readdirSync(commandFolder).map(async (dir) => { + if (dir.endsWith(".txt")) return; + if (!options.category && dir.endsWith(".js")) { + const commandPath = path.join(commandFolder, dir); + this.loadCommand(commandPath); + } else { + fs.readdirSync(path.join(commandFolder, dir)).map((cmd) => { + if (cmd.endsWith(".js") && !options.plugins) { + const commandPath = path.join(commandFolder, dir, cmd); + this.loadCommand(commandPath); + } else if (commandFolderPath === "../Plugins") { + if (cmd !== "commands") return; + fs.readdirSync(path.join(commandFolder, dir, cmd)).map((cmdfile) => { + if (!cmdfile.endsWith(".js")) return; + const commandPath = path.join(commandFolder, dir, cmd, cmdfile); + this.loadCommand(commandPath); + }); + } + }); + } + }); + } + + loadCommand(commandPath) { + const pull = require(path.join(commandPath)); + if (pull.name) { + pull.path = commandPath; + this.cache.set(pull.name, pull); + } + if (pull.aliases) { + pull.aliases.map((p) => this.aliases.set(p, pull)); + } + return pull; + } + + reloadCommand(commandName) { + const command = this.cache.get(commandName); + if (!command) return; + const commandPath = path.join(command.path); + delete require.cache[require.resolve(commandPath)]; + return this.loadCommand(commandPath); + } + + isCommand(message) { + if (message.isBot) return false; + const prefix = "!"; + const escapeRegex = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + const prefixRegex = new RegExp(`^(<@!?${this.client.id}>|${escapeRegex(prefix)})\\s*`); + if (!prefixRegex.test(message.content)) return false; + + const [, matchedPrefix] = message.content.match(prefixRegex); + const args = message.content.slice(matchedPrefix.length).trim().split(/ +/); + + this.onMessage(message, prefix, args); + return true; + } + + isInteraction(interaction) { + if (interaction.type !== 2) return; + this.onInteraction(interaction); + } + + async onMessage(message, guild, args) { + const commandName = args.shift().toLowerCase(); + const command = this.cache.get(commandName); //|| this.cache.find(cmd => cmd.aliases && cmd.aliases.includes(commandName)); + if (!command && message.content.includes(this.client.id)) { + //Handle, when Command has not been found + const options = { content: "I did not found the Command!" }; + this.client.helpers.sendMessage(message.channelId, options); + } + if (!command) return; + + const messagecommand = new command({ + manager: this, + message: message, + client: this.client, + args: args, + settings: {}, + commandName: command.name, + }); + messagecommand.execute()?.catch?.((error) => { + console.log(error); + // Call Function on CommandResponse.js, handle the error + return messagecommand.onError(error ?? "custom"); + }); + } + + async onInteraction(interaction) { + const command = this.cache.get(interaction.data.name); + if (!command) return; + + const args = []; + //Map all Values and Args + interaction.data.options.map((o) => { + if (o.name) args.push(o.name); + if (o.options) { + o.options.map((o2) => { + if (o2.value) return args.push(o2.value); + if (o2.name) args.push(o2.name); + if (o2.options) o2.options.map((v) => args.push(v.value)); + }); + } + }); + + const messagecommand = new command({ + manager: this, + interaction: interaction, + client: this.client, + args: args, + settings: {}, + commandName: command.name, + }); + messagecommand.execute()?.catch?.((error) => { + console.log(error); + // Call Function on CommandResponse.js, handle the error + return messagecommand.onError(error ?? "custom"); + }); + } +} +module.exports = CommandManager; diff --git a/template/nodejs/Managers/EventManager.js b/template/nodejs/Managers/EventManager.js new file mode 100644 index 000000000..5d90bb0c2 --- /dev/null +++ b/template/nodejs/Managers/EventManager.js @@ -0,0 +1,32 @@ +const fs = require("fs"); +const path = require("path"); +const resolveFolder = (folderName) => path.resolve(__dirname, ".", folderName); + +const EventEmitter = require("events"); + +class EventManager extends EventEmitter { + constructor(client) { + super(); + this.cache = new Map(); + this._events = {}; + } + + load(options = {}) { + const eventsFolder = resolveFolder("../events"); + fs.readdirSync(eventsFolder).map(async (file) => { + if (!file.endsWith(".js")) return; + const fileName = path.join(eventsFolder, file); + const event = require(fileName); + const eventName = file.split(".")[0]; + this._events[`${eventName}`] = event; + /* When the event should be emitted on client.events.on(eventName, (...args) => {...}) + this._events[`${eventName}`] = function(...args) { + this.emit(eventName, ...args); + return event(...args); + }; + */ + }); + return this._events; + } +} +module.exports = EventManager; diff --git a/template/nodejs/Managers/MemberManager.js b/template/nodejs/Managers/MemberManager.js new file mode 100644 index 000000000..ce719cc48 --- /dev/null +++ b/template/nodejs/Managers/MemberManager.js @@ -0,0 +1,13 @@ +const Member = require("../Structures/Member"); +class Members { + constructor(client, data = {}, options = {}) { + this.client = client; + + if (options.guild) this.guild = options.guild; + } + + forge(data = {}) { + return new Member(this.client, data, { guild: this.guild }); + } +} +module.exports = Members; diff --git a/template/nodejs/Managers/RoleManager.js b/template/nodejs/Managers/RoleManager.js new file mode 100644 index 000000000..64997d1f9 --- /dev/null +++ b/template/nodejs/Managers/RoleManager.js @@ -0,0 +1,29 @@ +const Role = require("../Structures/Role"); +class Roles { + constructor(client, data = {}, options = {}) { + this.client = client; + if (options.member) this.member = options.member; + if (options.guild) this.guild = options.guild; + } + + async create(options = {}, reason) { + return new Role(this.client, options).create(options, reason); + } + + forge(data = {}) { + return new Roles(this.client, data); + } + + async add(options = {}, reason) { + const guildId = (this.guild ? this.guild.id : options.guildId); + const memberId = (this.member ? this.member.id : options.memberId); + return this.client.helpers.addRole(guildId, memberId, options.roleId, reason); + } + + async remove(options = {}, reason) { + const guildId = (this.guild ? this.guild.id : options.guildId); + const memberId = (this.member ? this.member.id : options.memberId); + return this.client.helpers.removeRole(guildId, memberId, options.roleId, reason); + } +} +module.exports = Roles; diff --git a/template/nodejs/Plugins/Developer/commands/eval.js b/template/nodejs/Plugins/Developer/commands/eval.js new file mode 100644 index 000000000..8544b879e --- /dev/null +++ b/template/nodejs/Plugins/Developer/commands/eval.js @@ -0,0 +1,49 @@ +const BaseCommand = require("../../../Structures/BaseCommand.js"); +const Embed = require("../../../Structures/Embed.js"); +class evalcommand extends BaseCommand { + static name = "eval"; + static description = "danger !!!"; + static category = "Developer"; + static slash = { name: "eval", category: "dev" }; + constructor(data) { + super(data); + } + async execute() { + if (!this.client.config.owners.includes(String(this.user.id))) return; + if (!(this.args.length > 0)) return this.reply({ content: "**You must provide something to eval!**" }); + + let inputOfEval = this.args.join(" "); + let outputOfEval; + let typeOfEval; + + try { + if (this.args.includes("await")) { + outputOfEval = await eval("(async () => {" + inputOfEval + "})()"); + } else { + outputOfEval = await eval(inputOfEval); + } + } catch (e) { + outputOfEval = e.message; + typeOfEval = e.name; + } + + var seen = []; + outputOfEval = typeof outputOfEval === "object" + ? JSON.stringify(outputOfEval, (_, value) => { + if (value == `Bot ${this.client.config.token}`) return `BOT_TOKEN`; + if (typeof value === "bigint") value = value.toString(); + if (typeof value === "object" && value !== null) { + if (seen.indexOf(value) !== -1) return; + else seen.push(value); + } + return value; + }, 1) + : outputOfEval; + + const embed = new Embed() + .addField({ name: "Input", value: "```js\n" + inputOfEval + "```" }) + .addField({ name: "Output", value: "```json\n" + `${outputOfEval}`.slice(0, 1000) + "```" }); + this.reply({ embeds: [embed] }); + } +} +module.exports = evalcommand; diff --git a/template/nodejs/Plugins/Developer/commands/reload.js b/template/nodejs/Plugins/Developer/commands/reload.js new file mode 100644 index 000000000..4e01117a7 --- /dev/null +++ b/template/nodejs/Plugins/Developer/commands/reload.js @@ -0,0 +1,19 @@ +const BaseCommand = require("../../../Structures/BaseCommand.js"); +const Embed = require("../../../Structures/Embed.js"); +class reloadcommand extends BaseCommand { + static name = "reload"; + static description = "Reloads a Command"; + static category = "Developer"; + static slash = { name: "reload", category: "dev" }; + constructor(data) { + super(data); + } + async execute() { + if (!this.client.config.owners.includes(String(this.user.id))) return; + if (!this.args[0]) return this.reply({ content: "**You must provide a command to reload!**" }); + const op = this.client.commands.reloadCommand(this.args[0]); + if (!op) return this.reply({ content: "**That command doesn't exist!**" }); + return this.reply({ content: "**Reloaded Command: `" + this.args[0] + "`**" }); + } +} +module.exports = reloadcommand; diff --git a/template/nodejs/Plugins/Developer/index.js b/template/nodejs/Plugins/Developer/index.js new file mode 100644 index 000000000..e69de29bb diff --git a/template/nodejs/Plugins/General/commands/ping.js b/template/nodejs/Plugins/General/commands/ping.js new file mode 100644 index 000000000..7a3666833 --- /dev/null +++ b/template/nodejs/Plugins/General/commands/ping.js @@ -0,0 +1,24 @@ +const BaseCommand = require("../../../Structures/BaseCommand.js"); +const Embed = require("../../../Structures/Embed.js"); +class pingcommand extends BaseCommand { + static name = "ping"; + static description = "See if the bot latency is okay"; + static usage = ""; + static category = "General"; + static slash = { name: "ping", category: "info" }; + constructor(data) { + super(data); + } + async execute() { + const msg = await this.reply({ content: `Pinging...` }); + //Assign properties to the response + const ping = msg.timestamp - this.message.timestamp; + + const embed = new Embed() + .setTitle(`The Bots ping is ${ping} ms`) + .toJSON(); + //Edit Message with the Embed + return msg.edit({ embeds: [embed] }); + } +} +module.exports = pingcommand; diff --git a/template/nodejs/Plugins/General/index.js b/template/nodejs/Plugins/General/index.js new file mode 100644 index 000000000..e69de29bb diff --git a/template/nodejs/Plugins/Moderation/commands/ban.js b/template/nodejs/Plugins/Moderation/commands/ban.js new file mode 100644 index 000000000..5d6a7d5f2 --- /dev/null +++ b/template/nodejs/Plugins/Moderation/commands/ban.js @@ -0,0 +1,40 @@ +const BaseCommand = require("../../../Structures/BaseCommand.js"); +const Component = require("../../../Structures/Component.js"); + +class bancommand extends BaseCommand { + static name = "ban"; + static description = "Ban a user from the server"; + static usage = ""; + static category = "Moderation"; + static slash = { name: "ban", category: "mod" }; + constructor(data) { + super(data); + } + async execute() { + //Show Case Modal + + // Because no permission system has not been added + if (!this.client.config.owners.includes(String(this.user.id))) return; + + const textinput = new Component() + .setType("TEXT_INPUT") + .setStyle("SHORT") + .setCustomId("t1") + .setLabel("User ID") + .setPlaceholder("User ID") + .setRequired(true) + .setMaxLength(20) + .setMinLength(1) + .setValue(this.args[0]) + .toJSON(); + const textinput2 = new Component().setType("TEXT_INPUT").setStyle("PARAGRAPH").setCustomId("t2") + .setLabel("Reason").setPlaceholder("Reason for Ban").setRequired(false) + .setMaxLength(300).toJSON(); + + const actionrow = new Component().setType(1).setComponents(textinput).toJSON(); + const actionrow2 = new Component().setType(1).setComponents(textinput2).toJSON(); + + this.interaction.popupModal({ customId: "ban_modal", title: "Ban User", components: [actionrow, actionrow2] }); + } +} +module.exports = bancommand; diff --git a/template/nodejs/Plugins/Moderation/index.js b/template/nodejs/Plugins/Moderation/index.js new file mode 100644 index 000000000..e69de29bb diff --git a/template/nodejs/Structures/BaseCommand.js b/template/nodejs/Structures/BaseCommand.js new file mode 100644 index 000000000..146f2d78f --- /dev/null +++ b/template/nodejs/Structures/BaseCommand.js @@ -0,0 +1,17 @@ +const UtilCommand = require("./CommandResponse.js"); +const Message = require("./Message.js"); +const Interaction = require("./Interaction.js"); +class BaseCommand extends UtilCommand { + constructor(data) { + super(data); + this.message = data.message && new Message(data.client, data.message); + this.interaction = data.interaction && new Interaction(data.client, data.interaction); + this.user = this.message ? this.message.author : this.interaction.user; + this.guild = this.message ? this.message.guild : this.interaction.guild; + this.member = this.message ? this.message.member : this.interaction.member; + this.channel = this.message ? this.message.channel : this.interaction.channel; + this.client = data.client; + this.settings = data.settings ?? {}; + } +} +module.exports = BaseCommand; diff --git a/template/nodejs/Structures/Channel.js b/template/nodejs/Structures/Channel.js new file mode 100644 index 000000000..0e18fd002 --- /dev/null +++ b/template/nodejs/Structures/Channel.js @@ -0,0 +1,29 @@ +const DestructObject = require("./DestructObject"); +const Guild = require("./Guild"); + +class Channel extends DestructObject { + constructor(client, channel = {}, options = {}) { + super(channel); + if (options.guild) this.guild = options.guild; + else if (channel.guildId) this.guild = new Guild(client, { id: channel.guildId }); + + this.client = client; + } + + async create(options = {}, reason) { + return this.client.helpers.createChannel(this.guildId, options, reason); + } + + async edit(options = {}, reason) { + return this.client.helpers.editChannel(this.id, options, reason); + } + + async delete(reason) { + return this.client.helpers.deleteChannel(this.id, reason); + } + + async send(options = {}) { + return this.client.helpers.sendMessage(this.id, options); + } +} +module.exports = Channel; diff --git a/template/nodejs/Structures/CommandResponse.js b/template/nodejs/Structures/CommandResponse.js new file mode 100644 index 000000000..9c5b17c8f --- /dev/null +++ b/template/nodejs/Structures/CommandResponse.js @@ -0,0 +1,57 @@ +const Message = require("./Message"); + +class Responses { + constructor(data) { + this.manager = data.manager; + this.args = this._validateArguments(data.args); + this.replied = false; + } + + async reply(content) { + // When just a string is passed, we assume it's the content -> transform to correct formatted payload + if (typeof content === "string") content = { content }; + if (this.interaction) { + if (this.replied) return this.followUp(content); + const reply = await this.interaction.reply(content); + + //Assign properties to the response + const response = new Message(this.client, reply); + + this.replied = true; + return response; + } + if (this.message) { + if (this.replied) return this.followUp(content); + + const msg = await this.message.channel.send(content); + + //Assign properties to the response + const response = new Message(this.client, msg); + this.replied = true; + return response; + } + } + + async followUp(content) { + if (this.interaction) { + const reply = await this.interaction.followUp(content); + const response = new Message(this.client, reply); + return response; + } + if (this.message) { + const msg = await this.message.channel.send(content); + const response = new Message(this.client, msg); + return response; + } + } + + onError(error) { + return this.reply({ content: `A unknown Error happend: \n> ${error}` }); + } + + _validateArguments(args) { + this.args = args; + return args; + } +} +module.exports = Responses; diff --git a/template/nodejs/Structures/Component.js b/template/nodejs/Structures/Component.js new file mode 100644 index 000000000..31dcfc9d1 --- /dev/null +++ b/template/nodejs/Structures/Component.js @@ -0,0 +1,171 @@ +const Constants = { + PRIMARY: 1, + SECONDARY: 2, + SUCCESS: 3, + DANGER: 4, + LINK: 5, + SHORT: 1, + PARAGRAPH: 2, + + ACTION_ROW: 1, + BUTTON: 2, + SELECT_MENU: 3, + TEXT_INPUT: 4, +}; +class Component { + constructor(options = {}) { + this.type = options.type; + this.custom_id = options.custom_id ?? options.customId; + this.disabled = options.disabled; + this.style = options.style; + this.label = options.label; + this.emoji = options.emoji; + this.url = options.url; + + //Select Menu + this.options = options.options; + this.placeholder = options.placeholder; + this.min_values = options.min_values ?? options.minValues; + this.max_values = options.max_values ?? options.maxValues; + + //Action Row + this.components = options.components; + + //Modal + this.value = options.value; + this.min_length = options.min_length ?? options.minLength; + this.max_length = options.max_length ?? options.maxLength; + this.required = options.required; + } + + setType(type) { + if (typeof type === "string") { + this.type = Constants[type.toUpperCase()]; + if (!this.type) throw new Error(`Invalid Component Type: ${type}`); + } else this.type = type; + return this; + } + + setCustomId(custom_id) { + if (!this.url) this.custom_id = custom_id; + return this; + } + + setDisabled(disabled) { + this.disabled = disabled; + return this; + } + + setRequired(required) { + this.required = required; + return this; + } + + setStyle(style) { + if (!this.url) { + if (typeof style === "string") { + this.style = Constants[style.toUpperCase()]; + if (!this.style) throw new Error(`Invalid Button Style Type: ${type}`); + } else this.style = style; + } + return this; + } + + setLabel(label) { + this.label = label; + return this; + } + + setEmoji(emoji) { + this.emoji = emoji; + return this; + } + + setUrl(url) { + this.url = url; + this.style = 5; + this.custom_id = undefined; + return this; + } + + setOptions(options) { + this.options = options; + return this; + } + + setValue(value) { + this.value = value; + return this; + } + + setPlaceholder(placeholder) { + this.placeholder = placeholder; + return this; + } + + setMinValues(min_values) { + this.min_values = min_values; + return this; + } + + setMaxValues(max_values) { + this.max_values = max_values; + return this; + } + + setMinLength(min_values) { + this.min_length = min_values; + return this; + } + + setMaxLength(max_values) { + this.max_length = max_values; + return this; + } + + setComponents(...components) { + this.components = components; + return this; + } + + toJSON() { + if (!this.type) throw new Error("Component must have a type"); + const json = { + type: this.type, + }; + if (this.type === 1) { + json.components = this.components; + } + + if (this.type === 2) { + json.customId = this.custom_id; + json.style = this.style; + json.label = this.label; + json.emoji = this.emoji; + json.url = this.url; + json.disabled = this.disabled; + } + + if (this.type === 3) { + json.customId = this.custom_id; + json.options = this.options; + json.placeholder = this.placeholder; + json.minValues = this.min_values; + json.maxValues = this.max_values; + json.disabled = this.disabled; + } + + if (this.type === 4) { + json.customId = this.custom_id; + json.style = this.style; + json.label = this.label; + json.minLength = this.min_length; + json.maxLength = this.max_length; + json.required = this.required; + json.value = this.value; + json.placeholder = this.placeholder; + } + return json; + } +} +module.exports = Component; diff --git a/template/nodejs/Structures/DestructObject.js b/template/nodejs/Structures/DestructObject.js new file mode 100644 index 000000000..2f0dff7b0 --- /dev/null +++ b/template/nodejs/Structures/DestructObject.js @@ -0,0 +1,16 @@ +class DestructObject { + constructor(message = {}) { + this.destructObject(message); + } + destructObject(message) { + for (let [key, value] of Object.entries(message)) { + this[key] = value; + } + return this; + } + + toJSON() { + return { ...this }; + } +} +module.exports = DestructObject; diff --git a/template/nodejs/Structures/Embed.js b/template/nodejs/Structures/Embed.js new file mode 100644 index 000000000..cb7e88ba0 --- /dev/null +++ b/template/nodejs/Structures/Embed.js @@ -0,0 +1,99 @@ +class Embed { + constructor(options = {}) { + this.title = options.title; + this.description = options.description; + this.fields = options.fields; + this.thumbnail = options.thumbnail; + this.image = options.image; + this.author = options.author; + this.color = options.color; + this.timestamp = options.timestamp; + this.footer = options.footer; + this.url = options.url; + this.fields = options.fields ?? []; + } + setTitle(title) { + this.title = title; + return this; + } + + setDescription(description) { + this.description = description; + return this; + } + + setThumbnail(thumbnail) { + this.thumbnail = thumbnail; + return this; + } + + setImage(image) { + this.image = image; + return this; + } + + setAuthor(author) { + if (typeof author !== "object") throw new Error("Author must be an object"); + this.author = author; + return this; + } + + setColor(color) { + this.color = color; + return this; + } + + setTimestamp(timestamp) { + this.timestamp = timestamp ?? Date.now(); + return this; + } + + setFooter(footer) { + if (typeof footer !== "object") throw new Error("Footer must be an object"); + this.footer = footer; + return this; + } + + setURL(url) { + this.url = url; + return this; + } + + addField(field) { + this.fields.push(field); + return this; + } + + addFields(...fields) { + fields.map((x) => this.addField(x)); + return this; + } + + toJSON() { + return { + title: this.title, + type: "rich", + description: this.description, + color: this.color, + timestamp: this.timestamp ? new Date(this.timestamp).toISOString() : null, + thumbnail: this.thumbnail, + image: this.image, + fields: this.fields, + url: this.url, + author: this.author + ? { + name: this.author.name, + url: this.author.url, + iconUrl: this.author.icon_url || this.author.iconUrl, + } + : null, + footer: this.footer + ? { + text: this.footer.text, + iconUrl: this.footer.icon_url || this.footer.iconUrl, + } + : null, + }; + } +} +module.exports = Embed; diff --git a/template/nodejs/Structures/Guild.js b/template/nodejs/Structures/Guild.js new file mode 100644 index 000000000..fe3a19d1f --- /dev/null +++ b/template/nodejs/Structures/Guild.js @@ -0,0 +1,18 @@ +const DestructObject = require("./DestructObject"); + +const RoleManager = require("../Managers/RoleManager"); +const MemberManager = require("../Managers/MemberManager"); +const ChannelManager = require("../Managers/ChannelManager"); + +class Guild extends DestructObject { + constructor(client, guild = {}) { + super(guild); + this.client = client; + + //Managers: + this.roles = new RoleManager(client, {}, { guild: this }); + this.members = new MemberManager(client, {}, { guild: this }); + this.channels = new ChannelManager(client, {}, { guild: this }); + } +} +module.exports = Guild; diff --git a/template/nodejs/Structures/Interaction.js b/template/nodejs/Structures/Interaction.js new file mode 100644 index 000000000..a21b8123f --- /dev/null +++ b/template/nodejs/Structures/Interaction.js @@ -0,0 +1,116 @@ +const DestructObject = require("./DestructObject"); +const Guild = require("./Guild"); +const Channel = require("./Channel"); +const Constants = { + DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE: 5, + CHANNEL_MESSAGE_WITH_SOURCE: 4, + DEFERRED_UPDATE_MESSAGE: 6, + UPDATE_MESSAGE: 7, + APPLICATION_COMMAND_AUTOCOMPLETE_RESULT: 8, + MODAL: 9, + FLAGS: { EPHEMERAL: 64 }, + INTERACTION_TYPES: { + CHAT_INPUT: 1, + APPLICATION_COMMAND: 2, + CONTEXT_MENU: 2, + MESSAGE_COMPONENT: 3, + APPLICATION_COMMAND_AUTOCOMPLETE: 4, + }, +}; +class Interaction extends DestructObject { + constructor(client, interaction = {}) { + super(interaction); + this.raw = interaction; + this.client = client; + + this.guild = new Guild(client, { id: this.guild_id || this.guildId }); + this.channel = new Channel(client, { id: this.channel_id || this.channelId }, { + internal: true, + guild: this.guild, + }); + } + + isCommand() { + return this.type === Constants.INTERACTION_TYPES.APPLICATION_COMMAND; + } + + // @todo check Context Menu type and Component Type + isChatInputCommand() { + return this.type === Constants.INTERACTION_TYPES.CHAT_INPUT; + } + isContextMenuCommand() { + return this.isCommand(); + } + isAutoComplete() { + return this.type === Constants.INTERACTION_TYPES.APPLICATION_COMMAND_AUTOCOMPLETE; + } + isMessageComponent() { + return this.type === Constants.INTERACTION_TYPES.MESSAGE_COMPONENT; + } + isSelectMenu() { + return this.type === Constants.INTERACTION_TYPES.MESSAGE_COMPONENT; + } + isButton() { + return this.type === Constants.INTERACTION_TYPES.MESSAGE_COMPONENT; + } + + async deferReply(options = {}) { + if (this.deferred || this.replied) throw new Error("Interaction has been already replied"); + const Payload = { data: {}, type: Constants.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE }; + options.type = 5; + if (this.ephemeral) options.private = true; + this.ephemeral = options.ephemeral || false; + this.deferred = true; + return this.client.helpers.sendInteractionResponse(this.id, this.token, options); + } + + async deferUpdate(options = {}) { + if (this.deferred || this.replied) throw new Error("Interaction has been already replied"); + this.deferred = true; + const Payload = { data: options, type: Constants.DEFERRED_UPDATE_MESSAGE }; + return this.client.helpers.sendInteractionResponse(this.id, this.token, Payload); + } + + async reply(options = {}) { + if (this.deferred || this.replied) throw new Error("Interaction has been already replied"); + this.ephemeral = options.ephemeral || false; + if (this.ephemeral) options.private = true; + this.replied = true; + const Payload = { data: options, type: Constants.CHANNEL_MESSAGE_WITH_SOURCE }; + return this.client.helpers.sendInteractionResponse(this.id, this.token, Payload); + } + + async popupModal(options = {}) { + if (this.deferred || this.replied) throw new Error("Interaction has been already replied"); + const Payload = { data: options, type: Constants.MODAL }; + this.replied = true; + return this.client.helpers.sendInteractionResponse(this.id, this.token, Payload); + } + + async editReply(options = {}) { + if (!this.deferred && !this.replied) throw new Error("Interaction has not been replied"); + this.replied = true; + const messageId = this.messageId ? this.messageId : options.messageId; + return this.client.helpers.editInteractionResponse(this.token, options); + } + + async deleteReply(options = {}) { + if (this.ephemeral) throw new Error("Ephemeral messages cannot be deleted"); + const messageId = this.messageId ? this.messageId : options.messageId; + return this.client.helpers.deleteInteractionResponse(this.token, messageId); + } + + async followUp(options = {}) { + if (!this.replied || !this.deferred) throw new Error("Interaction has not been replied"); + const Payload = { data: options, type: Constants.CHANNEL_MESSAGE_WITH_SOURCE }; + return this.client.helpers.sendInteractionResponse(this.id, this.token, Payload); + } + + async update(options = {}) { + if (this.deferred || this.replied) throw new Error("Interaction has been already replied"); + const Payload = { data: options, type: Constants.UPDATE_MESSAGE }; + this.replied = true; + return this.client.helpers.sendInteractionResponse(this.id, this.token, Payload); + } +} +module.exports = Interaction; diff --git a/template/nodejs/Structures/Member.js b/template/nodejs/Structures/Member.js new file mode 100644 index 000000000..2aab97af5 --- /dev/null +++ b/template/nodejs/Structures/Member.js @@ -0,0 +1,16 @@ +const DestructObject = require("./DestructObject"); +const Guild = require("./Guild"); +const RoleManager = require("../Managers/RoleManager"); + +class Member extends DestructObject { + constructor(client, member = {}, options = {}) { + super(member); + this.client = client; + + if (options.guild) this.guild = options.guild; + else if (member.guildId) this.guild = new Guild(client, { id: member.guildId }); + + this.roles = new RoleManager(client, {}, { guild: this.guild, member: this }); + } +} +module.exports = Member; diff --git a/template/nodejs/Structures/Message.js b/template/nodejs/Structures/Message.js new file mode 100644 index 000000000..39d46fb63 --- /dev/null +++ b/template/nodejs/Structures/Message.js @@ -0,0 +1,50 @@ +const DestructObject = require("./DestructObject"); + +const Channel = require("./Channel"); +const Guild = require("./Guild"); +const Member = require("./Member"); +const User = require("./User"); + +class Message extends DestructObject { + constructor(client, message = {}) { + super(message); + this.client = client; + this.guild = new Guild(client, { id: this.guild_id || this.guildId }); + this.channel = new Channel(client, { id: this.channel_id || this.channelId }, { guild: this.guild }); + this.member = new Member(client, message.member, { guild: this.guild }); + this.author = new User(client, { + id: this.author_id || this.authorId, + username: this.tag?.split("#")[0], + discriminator: this.tag?.split("#")[1], + bot: this.isBot, + }); + } + + async edit(options) { + return this.client.helpers.editMessage(this.channel.id, this.id, options); + } + + async reply(options = {}) { + if (!options.messageReference) { + options.messageReference = { messageId: this.id, channelId: this.channel.id, guildId: this.guild.id }; + } + return this.client.helpers.sendMessage(this.channel.id, options); + } + + async delete(options = {}) { + return this.client.helpers.deleteMessage(this.channel.id, this.id, options.reason, options.delayMilliseconds); + } + + async react(emoji) { + return this.client.helpers.addReaction(this.channel.id, this.id, emoji); + } + + async pin() { + return this.client.helpers.pinMessage(this.channel.id, this.id); + } + + async unpin() { + return this.client.helpers.unpinMessage(this.channel.id, this.id); + } +} +module.exports = Message; diff --git a/template/nodejs/Structures/Permissions.js b/template/nodejs/Structures/Permissions.js new file mode 100644 index 000000000..1ed537b37 --- /dev/null +++ b/template/nodejs/Structures/Permissions.js @@ -0,0 +1,9 @@ +/// On work +class Permissions { + constructor(client, data = {}, options = {}) { + this.client = client; + } + + has(bit) { + } +} diff --git a/template/nodejs/Structures/Role.js b/template/nodejs/Structures/Role.js new file mode 100644 index 000000000..8e92ad114 --- /dev/null +++ b/template/nodejs/Structures/Role.js @@ -0,0 +1,12 @@ +const DestructObject = require("./DestructObject"); +const Guild = require("./Guild"); + +class Role extends DestructObject { + constructor(client, role = {}, options = {}) { + super(role); + if (options.guild) this.guild = options.guild; + else if (role.guildId) this.guild = new Guild(client, { id: role.guildId }); + this.client = client; + } +} +module.exports = Role; diff --git a/template/nodejs/Structures/User.js b/template/nodejs/Structures/User.js new file mode 100644 index 000000000..7626a3dfa --- /dev/null +++ b/template/nodejs/Structures/User.js @@ -0,0 +1,13 @@ +const DestructObject = require("./DestructObject"); + +class User extends DestructObject { + constructor(client, user = {}) { + super(user); + this.client = client; + } + + get tag() { + return `#${this.username}#${this.discriminator}`; + } +} +module.exports = User; diff --git a/template/nodejs/events/interactionCreate.js b/template/nodejs/events/interactionCreate.js new file mode 100644 index 000000000..ff76be71e --- /dev/null +++ b/template/nodejs/events/interactionCreate.js @@ -0,0 +1,3 @@ +module.exports = async (client, interaction) => { + client.commands.isInteraction(interaction); +}; diff --git a/template/nodejs/events/messageCreate.js b/template/nodejs/events/messageCreate.js new file mode 100644 index 000000000..3b18d1977 --- /dev/null +++ b/template/nodejs/events/messageCreate.js @@ -0,0 +1,3 @@ +module.exports = async (client, message) => { + client.commands.isCommand(message); +}; diff --git a/template/nodejs/events/ready.js b/template/nodejs/events/ready.js new file mode 100644 index 000000000..5e6fa6aab --- /dev/null +++ b/template/nodejs/events/ready.js @@ -0,0 +1,9 @@ +const User = require("../Structures/User"); +module.exports = async (client, payload) => { + client.user = new User(client, payload.user); + + if (payload.shardId + 1 === client.gateway.maxShards) { + //All Shards are ready + console.log("Successfully connected to the gateway as " + client.user.tag); + } +}; diff --git a/template/nodejs/index.js b/template/nodejs/index.js new file mode 100644 index 000000000..10c3d81df --- /dev/null +++ b/template/nodejs/index.js @@ -0,0 +1,29 @@ +const Discord = require("discordeno"); + +// Ideally you should switch this to .env but for a template a config json is enough +const config = require("../config.json"); + +const EventManager = require("./Managers/EventManager.js"); +// looping through all events and registering them +const events = new EventManager({}); + +const client = Discord.createBot({ + events: events.load({}), + intents: ["Guilds", "GuildMessages"], + token: config.token, +}); + +client.config = config; + +// looping through all commands and registering them in .cache of the class +const CommandManager = require("./Managers/CommandManager.js"); +client.commands = new CommandManager(client); +client.commands.load({}); + +// Starts your Bot +Discord.startBot(client); + +/* +* You should handle all errors and fix the issues in your codes... +* process.on('unhandledRejection', (reason, p) => {console.log(reason, p)}) +*/ From 7204665e77d8001f2fe5386475e716df6399cbe8 Mon Sep 17 00:00:00 2001 From: ITOH Date: Tue, 15 Feb 2022 21:06:06 +0100 Subject: [PATCH 03/14] fix(plugins): await old function return (#2065) * fix(plugins): await old function return * Update plugins/permissions/src/channels/stage.ts lol Co-authored-by: TriForMine Co-authored-by: TriForMine --- .../permissions/src/channels/deleteChannel.ts | 4 ++-- .../src/channels/deleteChannelOverwrite.ts | 4 ++-- .../permissions/src/channels/editChannel.ts | 4 ++-- .../src/channels/editChannelOverwrite.ts | 4 ++-- .../permissions/src/channels/followChannel.ts | 4 ++-- .../src/channels/getChannelWebhooks.ts | 4 ++-- plugins/permissions/src/channels/stage.ts | 12 +++++------ .../permissions/src/channels/swapChannels.ts | 4 ++-- .../src/channels/threads/addToThread.ts | 2 +- .../channels/threads/getArchivedThreads.ts | 2 +- .../src/channels/threads/getThreadMembers.ts | 4 ++-- .../src/channels/threads/joinThread.ts | 4 ++-- .../src/channels/threads/leaveThread.ts | 4 ++-- .../channels/threads/removeThreadMember.ts | 2 +- .../permissions/src/connectToVoiceChannels.ts | 2 +- plugins/permissions/src/discovery.ts | 16 +++++++-------- plugins/permissions/src/editMember.ts | 2 +- plugins/permissions/src/emojis.ts | 12 +++++------ plugins/permissions/src/guilds/createGuild.ts | 4 ++-- plugins/permissions/src/guilds/deleteGuild.ts | 4 ++-- plugins/permissions/src/guilds/editGuild.ts | 4 ++-- plugins/permissions/src/guilds/events.ts | 8 ++++---- .../permissions/src/guilds/getAuditLogs.ts | 4 ++-- plugins/permissions/src/guilds/getBan.ts | 4 ++-- plugins/permissions/src/guilds/getBans.ts | 4 ++-- .../permissions/src/guilds/getPruneCount.ts | 4 ++-- .../permissions/src/guilds/getVanityUrl.ts | 4 ++-- .../permissions/src/guilds/welcomeScreen.ts | 8 ++++---- plugins/permissions/src/guilds/widget.ts | 4 ++-- plugins/permissions/src/integrations.ts | 8 ++++---- .../permissions/src/interactions/commands.ts | 8 ++++---- .../src/interactions/editFollowupMessage.ts | 4 ++-- plugins/permissions/src/invites.ts | 12 +++++------ plugins/permissions/src/members/ban.ts | 8 ++++---- plugins/permissions/src/members/editBot.ts | 4 ++-- plugins/permissions/src/members/editMember.ts | 4 ++-- plugins/permissions/src/members/kickMember.ts | 4 ++-- .../permissions/src/members/pruneMembers.ts | 4 ++-- plugins/permissions/src/messages/create.ts | 4 ++-- plugins/permissions/src/messages/delete.ts | 8 ++++---- plugins/permissions/src/messages/get.ts | 8 ++++---- plugins/permissions/src/messages/pin.ts | 8 ++++---- plugins/permissions/src/messages/reactions.ts | 20 +++++++++---------- plugins/permissions/src/misc/mod.ts | 4 ++-- plugins/permissions/src/roles/add.ts | 4 ++-- plugins/permissions/src/roles/create.ts | 4 ++-- plugins/permissions/src/roles/delete.ts | 4 ++-- plugins/permissions/src/roles/edit.ts | 4 ++-- plugins/permissions/src/roles/remove.ts | 4 ++-- .../permissions/src/webhooks/createWebhook.ts | 4 ++-- .../permissions/src/webhooks/deleteWebhook.ts | 4 ++-- .../permissions/src/webhooks/editWebhook.ts | 4 ++-- plugins/permissions/src/webhooks/message.ts | 4 ++-- .../permissions/src/webhooks/sendWebhook.ts | 4 ++-- r.ts | 16 +++++++++++++++ 55 files changed, 161 insertions(+), 145 deletions(-) create mode 100644 r.ts diff --git a/plugins/permissions/src/channels/deleteChannel.ts b/plugins/permissions/src/channels/deleteChannel.ts index cdc0ff571..10677f27e 100644 --- a/plugins/permissions/src/channels/deleteChannel.ts +++ b/plugins/permissions/src/channels/deleteChannel.ts @@ -4,7 +4,7 @@ import { requireBotGuildPermissions } from "../permissions.ts"; export default function deleteChannel(bot: BotWithCache) { const deleteChannelOld = bot.helpers.deleteChannel; - bot.helpers.deleteChannel = function (channelId, reason) { + bot.helpers.deleteChannel = async function (channelId, reason) { const channel = bot.channels.get(channelId); if (channel?.guildId) { @@ -32,6 +32,6 @@ export default function deleteChannel(bot: BotWithCache) { ); } - return deleteChannelOld(channelId, reason); + return await deleteChannelOld(channelId, reason); }; } diff --git a/plugins/permissions/src/channels/deleteChannelOverwrite.ts b/plugins/permissions/src/channels/deleteChannelOverwrite.ts index 58801e8c3..6c57ce019 100644 --- a/plugins/permissions/src/channels/deleteChannelOverwrite.ts +++ b/plugins/permissions/src/channels/deleteChannelOverwrite.ts @@ -4,13 +4,13 @@ import { requireBotChannelPermissions } from "../permissions.ts"; export default function deleteChannelOverwrite(bot: BotWithCache) { const deleteChannelOverwriteOld = bot.helpers.deleteChannelOverwrite; - bot.helpers.deleteChannelOverwrite = function (channelId, overwriteId) { + bot.helpers.deleteChannelOverwrite = async function (channelId, overwriteId) { const channel = bot.channels.get(channelId); if (channel?.guildId) { requireBotChannelPermissions(bot, channelId, ["MANAGE_ROLES"]); } - return deleteChannelOverwriteOld(channelId, overwriteId); + return await deleteChannelOverwriteOld(channelId, overwriteId); }; } diff --git a/plugins/permissions/src/channels/editChannel.ts b/plugins/permissions/src/channels/editChannel.ts index 41d83a19d..fb96828ee 100644 --- a/plugins/permissions/src/channels/editChannel.ts +++ b/plugins/permissions/src/channels/editChannel.ts @@ -5,7 +5,7 @@ import { requireBotChannelPermissions } from "../permissions.ts"; export default function editChannel(bot: BotWithCache) { const editChannelOld = bot.helpers.editChannel; - bot.helpers.editChannel = function (channelId, options, reason) { + bot.helpers.editChannel = async function (channelId, options, reason) { const channel = bot.channels.get(channelId); if (channel?.guildId) { @@ -118,6 +118,6 @@ export default function editChannel(bot: BotWithCache) { } } - return editChannelOld(channelId, options, reason); + return await editChannelOld(channelId, options, reason); }; } diff --git a/plugins/permissions/src/channels/editChannelOverwrite.ts b/plugins/permissions/src/channels/editChannelOverwrite.ts index 287b5e8ba..b6e721eb9 100644 --- a/plugins/permissions/src/channels/editChannelOverwrite.ts +++ b/plugins/permissions/src/channels/editChannelOverwrite.ts @@ -4,12 +4,12 @@ import { requireBotChannelPermissions } from "../permissions.ts"; export default function editChannelOverwrite(bot: BotWithCache) { const editChannelOverwriteOld = bot.helpers.editChannelOverwrite; - bot.helpers.editChannelOverwrite = function (channelId, overwriteId, options) { + bot.helpers.editChannelOverwrite = async function (channelId, overwriteId, options) { const channel = bot.channels.get(channelId); if (channel?.guildId) { requireBotChannelPermissions(bot, channelId, ["MANAGE_ROLES"]); } - return editChannelOverwriteOld(channelId, overwriteId, options); + return await editChannelOverwriteOld(channelId, overwriteId, options); }; } diff --git a/plugins/permissions/src/channels/followChannel.ts b/plugins/permissions/src/channels/followChannel.ts index b5bf0fd7c..9505ea78f 100644 --- a/plugins/permissions/src/channels/followChannel.ts +++ b/plugins/permissions/src/channels/followChannel.ts @@ -4,12 +4,12 @@ import { requireBotChannelPermissions } from "../permissions.ts"; export default function followChannel(bot: BotWithCache) { const followChannelOld = bot.helpers.followChannel; - bot.helpers.followChannel = function (sourceChannelId, targetChannelId) { + bot.helpers.followChannel = async function (sourceChannelId, targetChannelId) { const channel = bot.channels.get(targetChannelId); if (channel?.guildId) { requireBotChannelPermissions(bot, channel, ["MANAGE_WEBHOOKS"]); } - return followChannelOld(sourceChannelId, targetChannelId); + return await followChannelOld(sourceChannelId, targetChannelId); }; } diff --git a/plugins/permissions/src/channels/getChannelWebhooks.ts b/plugins/permissions/src/channels/getChannelWebhooks.ts index 6f4e672ee..15b911ea5 100644 --- a/plugins/permissions/src/channels/getChannelWebhooks.ts +++ b/plugins/permissions/src/channels/getChannelWebhooks.ts @@ -4,12 +4,12 @@ import { requireBotChannelPermissions } from "../permissions.ts"; export default function getChannelWebhooks(bot: BotWithCache) { const getChannelWebhooksOld = bot.helpers.getChannelWebhooks; - bot.helpers.getChannelWebhooks = function (channelId) { + bot.helpers.getChannelWebhooks = async function (channelId) { const channel = bot.channels.get(channelId); if (channel?.guildId) { requireBotChannelPermissions(bot, channelId, ["MANAGE_WEBHOOKS"]); } - return getChannelWebhooksOld(channelId); + return await getChannelWebhooksOld(channelId); }; } diff --git a/plugins/permissions/src/channels/stage.ts b/plugins/permissions/src/channels/stage.ts index 9d8f2bba6..06f86de31 100644 --- a/plugins/permissions/src/channels/stage.ts +++ b/plugins/permissions/src/channels/stage.ts @@ -4,7 +4,7 @@ import { requireBotChannelPermissions } from "../permissions.ts"; export function createStageInstance(bot: BotWithCache) { const createStageInstanceOld = bot.helpers.createStageInstance; - bot.helpers.createStageInstance = function (channelId, topic, privacyLevel) { + bot.helpers.createStageInstance = async function (channelId, topic, privacyLevel) { if (!bot.utils.validateLength(topic, { max: 120, min: 1 })) { throw new Error( "The topic length for creating a stage instance must be between 1-120.", @@ -17,35 +17,35 @@ export function createStageInstance(bot: BotWithCache) { "MOVE_MEMBERS", ]); - return createStageInstanceOld(channelId, topic, privacyLevel); + return await createStageInstanceOld(channelId, topic, privacyLevel); }; } export function deleteStageInstance(bot: BotWithCache) { const deleteStageInstanceOld = bot.helpers.deleteStageInstance; - bot.helpers.deleteStageInstance = function (channelId) { + bot.helpers.deleteStageInstance = async function (channelId) { requireBotChannelPermissions(bot, channelId, [ "MANAGE_CHANNELS", "MUTE_MEMBERS", "MOVE_MEMBERS", ]); - return deleteStageInstanceOld(channelId); + return await deleteStageInstanceOld(channelId); }; } export function updateStageInstance(bot: BotWithCache) { const updateStageInstanceOld = bot.helpers.updateStageInstance; - bot.helpers.updateStageInstance = function (channelId, data) { + bot.helpers.updateStageInstance = async function (channelId, data) { requireBotChannelPermissions(bot, channelId, [ "MANAGE_CHANNELS", "MUTE_MEMBERS", "MOVE_MEMBERS", ]); - return updateStageInstanceOld(channelId, data); + return await updateStageInstanceOld(channelId, data); }; } diff --git a/plugins/permissions/src/channels/swapChannels.ts b/plugins/permissions/src/channels/swapChannels.ts index 0dea16998..61680d46b 100644 --- a/plugins/permissions/src/channels/swapChannels.ts +++ b/plugins/permissions/src/channels/swapChannels.ts @@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts"; export default function swapChannels(bot: BotWithCache) { const swapChannelsOld = bot.helpers.swapChannels; - bot.helpers.swapChannels = function (guildId, channelPositions) { + bot.helpers.swapChannels = async function (guildId, channelPositions) { requireBotGuildPermissions(bot, guildId, ["MANAGE_CHANNELS"]); - return swapChannelsOld(guildId, channelPositions); + return await swapChannelsOld(guildId, channelPositions); }; } diff --git a/plugins/permissions/src/channels/threads/addToThread.ts b/plugins/permissions/src/channels/threads/addToThread.ts index c052477e1..000d20d63 100644 --- a/plugins/permissions/src/channels/threads/addToThread.ts +++ b/plugins/permissions/src/channels/threads/addToThread.ts @@ -21,6 +21,6 @@ export default function addToThread(bot: BotWithCache) { await requireBotChannelPermissions(bot, channel, ["SEND_MESSAGES"]); } - return addToThreadOld(threadId, userId); + return await addToThreadOld(threadId, userId); }; } diff --git a/plugins/permissions/src/channels/threads/getArchivedThreads.ts b/plugins/permissions/src/channels/threads/getArchivedThreads.ts index 92e9db3e0..48ce2aa25 100644 --- a/plugins/permissions/src/channels/threads/getArchivedThreads.ts +++ b/plugins/permissions/src/channels/threads/getArchivedThreads.ts @@ -15,6 +15,6 @@ export default function getArchivedThreads(bot: BotWithCache) { ); } - return getArchivedThreadsOld(channelId, options); + return await getArchivedThreadsOld(channelId, options); }; } diff --git a/plugins/permissions/src/channels/threads/getThreadMembers.ts b/plugins/permissions/src/channels/threads/getThreadMembers.ts index 0d2881895..3a5ff6096 100644 --- a/plugins/permissions/src/channels/threads/getThreadMembers.ts +++ b/plugins/permissions/src/channels/threads/getThreadMembers.ts @@ -3,7 +3,7 @@ import { BotWithCache, GatewayIntents } from "../../../deps.ts"; export default function getThreadMembers(bot: BotWithCache) { const getThreadMembersOld = bot.helpers.getThreadMembers; - bot.helpers.getThreadMembers = function (threadId) { + bot.helpers.getThreadMembers = async function (threadId) { const hasIntent = bot.intents & GatewayIntents.GuildMembers; if (!hasIntent) { throw new Error( @@ -11,6 +11,6 @@ export default function getThreadMembers(bot: BotWithCache) { ); } - return getThreadMembersOld(threadId); + return await getThreadMembersOld(threadId); }; } diff --git a/plugins/permissions/src/channels/threads/joinThread.ts b/plugins/permissions/src/channels/threads/joinThread.ts index 521bf9f7d..c50a06d7e 100644 --- a/plugins/permissions/src/channels/threads/joinThread.ts +++ b/plugins/permissions/src/channels/threads/joinThread.ts @@ -3,13 +3,13 @@ import { BotWithCache } from "../../../deps.ts"; export default function joinThread(bot: BotWithCache) { const joinThreadOld = bot.helpers.joinThread; - bot.helpers.joinThread = function (threadId) { + bot.helpers.joinThread = async function (threadId) { const channel = bot.channels.get(threadId); if (channel && !channel.archived) { throw new Error("You can not join an archived channel."); } - return joinThreadOld(threadId); + return await joinThreadOld(threadId); }; } diff --git a/plugins/permissions/src/channels/threads/leaveThread.ts b/plugins/permissions/src/channels/threads/leaveThread.ts index 24cd71599..3ff3d455a 100644 --- a/plugins/permissions/src/channels/threads/leaveThread.ts +++ b/plugins/permissions/src/channels/threads/leaveThread.ts @@ -3,13 +3,13 @@ import { BotWithCache } from "../../../deps.ts"; export default function leaveThread(bot: BotWithCache) { const leaveThreadOld = bot.helpers.leaveThread; - bot.helpers.leaveThread = function (threadId) { + bot.helpers.leaveThread = async function (threadId) { const channel = bot.channels.get(threadId); if (channel && !channel.archived) { throw new Error("You can not leave an archived channel."); } - return leaveThreadOld(threadId); + return await leaveThreadOld(threadId); }; } diff --git a/plugins/permissions/src/channels/threads/removeThreadMember.ts b/plugins/permissions/src/channels/threads/removeThreadMember.ts index 14e935934..fabd893ec 100644 --- a/plugins/permissions/src/channels/threads/removeThreadMember.ts +++ b/plugins/permissions/src/channels/threads/removeThreadMember.ts @@ -28,6 +28,6 @@ export default function removeThreadMember(bot: BotWithCache) { } } - return removeThreadMemberOld(threadId, userId); + return await removeThreadMemberOld(threadId, userId); }; } diff --git a/plugins/permissions/src/connectToVoiceChannels.ts b/plugins/permissions/src/connectToVoiceChannels.ts index 7f9fbe016..26f40fd5e 100644 --- a/plugins/permissions/src/connectToVoiceChannels.ts +++ b/plugins/permissions/src/connectToVoiceChannels.ts @@ -40,6 +40,6 @@ export default function connectToVoiceChannel(bot: BotWithCache) { await requireBotChannelPermissions(bot, channel, permsNeeded); - return connectToVoiceChannelOld(guildId, channelId, options); + return await connectToVoiceChannelOld(guildId, channelId, options); }; } diff --git a/plugins/permissions/src/discovery.ts b/plugins/permissions/src/discovery.ts index caec07517..9ae3fe6ab 100644 --- a/plugins/permissions/src/discovery.ts +++ b/plugins/permissions/src/discovery.ts @@ -4,40 +4,40 @@ import { requireBotGuildPermissions } from "./permissions.ts"; export function addDiscoverySubcategory(bot: BotWithCache) { const addDiscoverySubcategoryOld = bot.helpers.addDiscoverySubcategory; - bot.helpers.addDiscoverySubcategory = function (guildId, categoryId) { + bot.helpers.addDiscoverySubcategory = async function (guildId, categoryId) { requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]); - return addDiscoverySubcategoryOld(guildId, categoryId); + return await addDiscoverySubcategoryOld(guildId, categoryId); }; } export function removeDiscoverySubcategory(bot: BotWithCache) { const removeDiscoverySubcategoryOld = bot.helpers.removeDiscoverySubcategory; - bot.helpers.removeDiscoverySubcategory = function (guildId, categoryId) { + bot.helpers.removeDiscoverySubcategory = async function (guildId, categoryId) { requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]); - return removeDiscoverySubcategoryOld(guildId, categoryId); + return await removeDiscoverySubcategoryOld(guildId, categoryId); }; } export function getDiscovery(bot: BotWithCache) { const getDiscoveryOld = bot.helpers.getDiscovery; - bot.helpers.getDiscovery = function (guildId) { + bot.helpers.getDiscovery = async function (guildId) { requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]); - return getDiscoveryOld(guildId); + return await getDiscoveryOld(guildId); }; } export function editDiscovery(bot: BotWithCache) { const editDiscoveryOld = bot.helpers.editDiscovery; - bot.helpers.editDiscovery = function (guildId, data) { + bot.helpers.editDiscovery = async function (guildId, data) { requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]); - return editDiscoveryOld(guildId, data); + return await editDiscoveryOld(guildId, data); }; } diff --git a/plugins/permissions/src/editMember.ts b/plugins/permissions/src/editMember.ts index c54b8d8fc..984b5bcdd 100644 --- a/plugins/permissions/src/editMember.ts +++ b/plugins/permissions/src/editMember.ts @@ -59,6 +59,6 @@ export default function editMember(bot: BotWithCache) { ...requiredPerms, ]); - return editMemberOld(guildId, memberId, options); + return await editMemberOld(guildId, memberId, options); }; } diff --git a/plugins/permissions/src/emojis.ts b/plugins/permissions/src/emojis.ts index e34f4880f..47d624790 100644 --- a/plugins/permissions/src/emojis.ts +++ b/plugins/permissions/src/emojis.ts @@ -4,30 +4,30 @@ import { requireBotGuildPermissions } from "./permissions.ts"; export function createEmoji(bot: BotWithCache) { const createEmojiOld = bot.helpers.createEmoji; - bot.helpers.createEmoji = function (guildId, id) { + bot.helpers.createEmoji = async function (guildId, id) { requireBotGuildPermissions(bot, guildId, ["MANAGE_EMOJIS"]); - return createEmojiOld(guildId, id); + return await createEmojiOld(guildId, id); }; } export function deleteEmoji(bot: BotWithCache) { const deleteEmojiOld = bot.helpers.deleteEmoji; - bot.helpers.deleteEmoji = function (guildId, id) { + bot.helpers.deleteEmoji = async function (guildId, id) { requireBotGuildPermissions(bot, guildId, ["MANAGE_EMOJIS"]); - return deleteEmojiOld(guildId, id); + return await deleteEmojiOld(guildId, id); }; } export function editEmoji(bot: BotWithCache) { const editEmojiOld = bot.helpers.editEmoji; - bot.helpers.editEmoji = function (guildId, id, options) { + bot.helpers.editEmoji = async function (guildId, id, options) { requireBotGuildPermissions(bot, guildId, ["MANAGE_EMOJIS"]); - return editEmojiOld(guildId, id, options); + return await editEmojiOld(guildId, id, options); }; } diff --git a/plugins/permissions/src/guilds/createGuild.ts b/plugins/permissions/src/guilds/createGuild.ts index a70a2c701..8524a0022 100644 --- a/plugins/permissions/src/guilds/createGuild.ts +++ b/plugins/permissions/src/guilds/createGuild.ts @@ -3,7 +3,7 @@ import { BotWithCache } from "../../deps.ts"; export default function createGuild(bot: BotWithCache) { const createGuildOld = bot.helpers.createGuild; - bot.helpers.createGuild = function (options) { + bot.helpers.createGuild = async function (options) { if (bot.guilds.size > 10) { throw new Error( "A bot can not create a guild if it is already in 10 guilds.", @@ -17,6 +17,6 @@ export default function createGuild(bot: BotWithCache) { throw new Error("The guild name must be between 2 and 100 characters."); } - return createGuildOld(options); + return await createGuildOld(options); }; } diff --git a/plugins/permissions/src/guilds/deleteGuild.ts b/plugins/permissions/src/guilds/deleteGuild.ts index a56a8abd9..41cfda5e2 100644 --- a/plugins/permissions/src/guilds/deleteGuild.ts +++ b/plugins/permissions/src/guilds/deleteGuild.ts @@ -3,12 +3,12 @@ import { BotWithCache } from "../../deps.ts"; export default function deleteGuild(bot: BotWithCache) { const deleteGuildOld = bot.helpers.deleteGuild; - bot.helpers.deleteGuild = function (guildId) { + bot.helpers.deleteGuild = async function (guildId) { const guild = bot.guilds.get(guildId); if (guild && guild.ownerId !== bot.id) { throw new Error("A bot can only delete a guild it owns."); } - return deleteGuildOld(guildId); + return await deleteGuildOld(guildId); }; } diff --git a/plugins/permissions/src/guilds/editGuild.ts b/plugins/permissions/src/guilds/editGuild.ts index da4cc419e..c485749f4 100644 --- a/plugins/permissions/src/guilds/editGuild.ts +++ b/plugins/permissions/src/guilds/editGuild.ts @@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts"; export default function editGuild(bot: BotWithCache) { const editGuildOld = bot.helpers.editGuild; - bot.helpers.editGuild = function (guildId, options, shardId) { + bot.helpers.editGuild = async function (guildId, options, shardId) { requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]); - return editGuildOld(guildId, options, shardId); + return await editGuildOld(guildId, options, shardId); }; } diff --git a/plugins/permissions/src/guilds/events.ts b/plugins/permissions/src/guilds/events.ts index f4a39cc63..eff9817c9 100644 --- a/plugins/permissions/src/guilds/events.ts +++ b/plugins/permissions/src/guilds/events.ts @@ -4,7 +4,7 @@ import { requireBotChannelPermissions, requireBotGuildPermissions } from "../per export function createScheduledEvent(bot: BotWithCache) { const createScheduledEventOld = bot.helpers.createScheduledEvent; - bot.helpers.createScheduledEvent = function (guildId, options) { + bot.helpers.createScheduledEvent = async function (guildId, options) { if (options.entityType === ScheduledEventEntityType.StageInstance) { if (!options.channelId) { throw new Error( @@ -64,14 +64,14 @@ export function createScheduledEvent(bot: BotWithCache) { "MANAGE_EVENTS", ]); - return createScheduledEventOld(guildId, options); + return await createScheduledEventOld(guildId, options); }; } export function editScheduledEvent(bot: BotWithCache) { const editScheduledEventOld = bot.helpers.editScheduledEvent; - bot.helpers.editScheduledEvent = function (guildId, eventId, options) { + bot.helpers.editScheduledEvent = async function (guildId, eventId, options) { if (options.entityType === ScheduledEventEntityType.StageInstance) { if (!options.channelId) { throw new Error( @@ -131,7 +131,7 @@ export function editScheduledEvent(bot: BotWithCache) { "MANAGE_EVENTS", ]); - return editScheduledEventOld(guildId, eventId, options); + return await editScheduledEventOld(guildId, eventId, options); }; } diff --git a/plugins/permissions/src/guilds/getAuditLogs.ts b/plugins/permissions/src/guilds/getAuditLogs.ts index 528080520..219398ba4 100644 --- a/plugins/permissions/src/guilds/getAuditLogs.ts +++ b/plugins/permissions/src/guilds/getAuditLogs.ts @@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts"; export default function getAuditLogs(bot: BotWithCache) { const getAuditLogsOld = bot.helpers.getAuditLogs; - bot.helpers.getAuditLogs = function (guildId, options) { + bot.helpers.getAuditLogs = async function (guildId, options) { requireBotGuildPermissions(bot, guildId, ["VIEW_AUDIT_LOG"]); - return getAuditLogsOld(guildId, options); + return await getAuditLogsOld(guildId, options); }; } diff --git a/plugins/permissions/src/guilds/getBan.ts b/plugins/permissions/src/guilds/getBan.ts index 3e745d165..49736ac12 100644 --- a/plugins/permissions/src/guilds/getBan.ts +++ b/plugins/permissions/src/guilds/getBan.ts @@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts"; export default function getBan(bot: BotWithCache) { const getBanOld = bot.helpers.getBan; - bot.helpers.getBan = function (guildId, memberId) { + bot.helpers.getBan = async function (guildId, memberId) { requireBotGuildPermissions(bot, guildId, ["BAN_MEMBERS"]); - return getBanOld(guildId, memberId); + return await getBanOld(guildId, memberId); }; } diff --git a/plugins/permissions/src/guilds/getBans.ts b/plugins/permissions/src/guilds/getBans.ts index b5a9ceec6..f59c62ee4 100644 --- a/plugins/permissions/src/guilds/getBans.ts +++ b/plugins/permissions/src/guilds/getBans.ts @@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts"; export default function getBans(bot: BotWithCache) { const getBansOld = bot.helpers.getBans; - bot.helpers.getBans = function (guildId) { + bot.helpers.getBans = async function (guildId) { requireBotGuildPermissions(bot, guildId, ["BAN_MEMBERS"]); - return getBansOld(guildId); + return await getBansOld(guildId); }; } diff --git a/plugins/permissions/src/guilds/getPruneCount.ts b/plugins/permissions/src/guilds/getPruneCount.ts index 521d43f75..2669b57c4 100644 --- a/plugins/permissions/src/guilds/getPruneCount.ts +++ b/plugins/permissions/src/guilds/getPruneCount.ts @@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts"; export default function getPruneCount(bot: BotWithCache) { const getPruneCountOld = bot.helpers.getPruneCount; - bot.helpers.getPruneCount = function (guildId, options) { + bot.helpers.getPruneCount = async function (guildId, options) { requireBotGuildPermissions(bot, guildId, ["KICK_MEMBERS"]); - return getPruneCountOld(guildId, options); + return await getPruneCountOld(guildId, options); }; } diff --git a/plugins/permissions/src/guilds/getVanityUrl.ts b/plugins/permissions/src/guilds/getVanityUrl.ts index acc31ce9e..a957f8ca2 100644 --- a/plugins/permissions/src/guilds/getVanityUrl.ts +++ b/plugins/permissions/src/guilds/getVanityUrl.ts @@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts"; export default function getVanityUrl(bot: BotWithCache) { const getVanityUrlOld = bot.helpers.getVanityUrl; - bot.helpers.getVanityUrl = function (guildId) { + bot.helpers.getVanityUrl = async function (guildId) { requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]); - return getVanityUrlOld(guildId); + return await getVanityUrlOld(guildId); }; } diff --git a/plugins/permissions/src/guilds/welcomeScreen.ts b/plugins/permissions/src/guilds/welcomeScreen.ts index 7da106632..e8ae7a073 100644 --- a/plugins/permissions/src/guilds/welcomeScreen.ts +++ b/plugins/permissions/src/guilds/welcomeScreen.ts @@ -4,23 +4,23 @@ import { requireBotGuildPermissions } from "../permissions.ts"; export function getWelcomeScreen(bot: BotWithCache) { const getWelcomeScreenOld = bot.helpers.getWelcomeScreen; - bot.helpers.getWelcomeScreen = function (guildId) { + bot.helpers.getWelcomeScreen = async function (guildId) { const guild = bot.guilds.get(guildId); if (!guild?.welcomeScreen) { requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]); } - return getWelcomeScreenOld(guildId); + return await getWelcomeScreenOld(guildId); }; } export function editWelcomeScreen(bot: BotWithCache) { const editWelcomeScreenOld = bot.helpers.editWelcomeScreen; - bot.helpers.editWelcomeScreen = function (guildId, options) { + bot.helpers.editWelcomeScreen = async function (guildId, options) { requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]); - return editWelcomeScreenOld(guildId, options); + return await editWelcomeScreenOld(guildId, options); }; } diff --git a/plugins/permissions/src/guilds/widget.ts b/plugins/permissions/src/guilds/widget.ts index 5b95c1666..68ba9f72d 100644 --- a/plugins/permissions/src/guilds/widget.ts +++ b/plugins/permissions/src/guilds/widget.ts @@ -4,10 +4,10 @@ import { requireBotGuildPermissions } from "../permissions.ts"; export function editWidget(bot: BotWithCache) { const editWidgetOld = bot.helpers.editWidget; - bot.helpers.editWidget = function (guildId, enabled, channelId) { + bot.helpers.editWidget = async function (guildId, enabled, channelId) { requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]); - return editWidgetOld(guildId, enabled, channelId); + return await editWidgetOld(guildId, enabled, channelId); }; } diff --git a/plugins/permissions/src/integrations.ts b/plugins/permissions/src/integrations.ts index b340dbe18..c7fc1876f 100644 --- a/plugins/permissions/src/integrations.ts +++ b/plugins/permissions/src/integrations.ts @@ -4,20 +4,20 @@ import { requireBotGuildPermissions } from "./permissions.ts"; export function deleteIntegration(bot: BotWithCache) { const deleteIntegrationOld = bot.helpers.deleteIntegration; - bot.helpers.deleteIntegration = function (guildId, id) { + bot.helpers.deleteIntegration = async function (guildId, id) { requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]); - return deleteIntegrationOld(guildId, id); + return await deleteIntegrationOld(guildId, id); }; } export function getIntegrations(bot: BotWithCache) { const getIntegrationsOld = bot.helpers.getIntegrations; - bot.helpers.getIntegrations = function (guildId) { + bot.helpers.getIntegrations = async function (guildId) { requireBotGuildPermissions(bot, guildId, ["MANAGE_GUILD"]); - return getIntegrationsOld(guildId); + return await getIntegrationsOld(guildId); }; } diff --git a/plugins/permissions/src/interactions/commands.ts b/plugins/permissions/src/interactions/commands.ts index e8a2ff7fe..5c369e26c 100644 --- a/plugins/permissions/src/interactions/commands.ts +++ b/plugins/permissions/src/interactions/commands.ts @@ -76,7 +76,7 @@ export function validateApplicationCommandOptions( export function createApplicationCommand(bot: BotWithCache) { const createApplicationCommandOld = bot.helpers.createApplicationCommand; - bot.helpers.createApplicationCommand = function (options, guildId) { + bot.helpers.createApplicationCommand = async function (options, guildId) { const isChatInput = !options.type || options.type === ApplicationCommandTypes.ChatInput; @@ -135,14 +135,14 @@ export function createApplicationCommand(bot: BotWithCache) { options.options = validateApplicationCommandOptions(bot, options.options); } - return createApplicationCommandOld(options, guildId); + return await createApplicationCommandOld(options, guildId); }; } export function editInteractionResponse(bot: BotWithCache) { const editInteractionResponseOld = bot.helpers.editInteractionResponse; - bot.helpers.editInteractionResponse = function (token, options) { + bot.helpers.editInteractionResponse = async function (token, options) { if (options.content && options.content.length > 2000) { throw Error(bot.constants.Errors.MESSAGE_MAX_LENGTH); } @@ -191,7 +191,7 @@ export function editInteractionResponse(bot: BotWithCache) { } } - return editInteractionResponseOld(token, options); + return await editInteractionResponseOld(token, options); }; } diff --git a/plugins/permissions/src/interactions/editFollowupMessage.ts b/plugins/permissions/src/interactions/editFollowupMessage.ts index d9abb9a94..0917417d8 100644 --- a/plugins/permissions/src/interactions/editFollowupMessage.ts +++ b/plugins/permissions/src/interactions/editFollowupMessage.ts @@ -3,7 +3,7 @@ import { AllowedMentionsTypes, BotWithCache } from "../../deps.ts"; export default function editFollowupMessage(bot: BotWithCache) { const editFollowupMessageOld = bot.helpers.editFollowupMessage; - bot.helpers.editFollowupMessage = function ( + bot.helpers.editFollowupMessage = async function ( token, messageId, options, @@ -56,6 +56,6 @@ export default function editFollowupMessage(bot: BotWithCache) { } } - return editFollowupMessageOld(token, messageId, options); + return await editFollowupMessageOld(token, messageId, options); }; } diff --git a/plugins/permissions/src/invites.ts b/plugins/permissions/src/invites.ts index 32a1dd47b..a10b02a6c 100644 --- a/plugins/permissions/src/invites.ts +++ b/plugins/permissions/src/invites.ts @@ -4,7 +4,7 @@ import { requireBotChannelPermissions } from "./permissions.ts"; export function createInvite(bot: BotWithCache) { const createInviteOld = bot.helpers.createInvite; - bot.helpers.createInvite = function (channelId, options = {}) { + bot.helpers.createInvite = async function (channelId, options = {}) { if (options.maxAge && (options.maxAge < 0 || options.maxAge > 604800)) { throw new Error( "The max age for an invite must be between 0 and 604800.", @@ -16,27 +16,27 @@ export function createInvite(bot: BotWithCache) { requireBotChannelPermissions(bot, channelId, ["CREATE_INSTANT_INVITE"]); - return createInviteOld(channelId, options); + return await createInviteOld(channelId, options); }; } export function getChannelInvites(bot: BotWithCache) { const getChannelInvitesOld = bot.helpers.getChannelInvites; - bot.helpers.getChannelInvites = function (channelId) { + bot.helpers.getChannelInvites = async function (channelId) { requireBotChannelPermissions(bot, channelId, ["MANAGE_CHANNELS"]); - return getChannelInvitesOld(channelId); + return await getChannelInvitesOld(channelId); }; } export function getInvites(bot: BotWithCache) { const getInvitesOld = bot.helpers.getInvites; - bot.helpers.getInvites = function (guildId) { + bot.helpers.getInvites = async function (guildId) { requireBotChannelPermissions(bot, guildId, ["MANAGE_GUILD"]); - return getInvitesOld(guildId); + return await getInvitesOld(guildId); }; } diff --git a/plugins/permissions/src/members/ban.ts b/plugins/permissions/src/members/ban.ts index b1c6d729e..31031c59c 100644 --- a/plugins/permissions/src/members/ban.ts +++ b/plugins/permissions/src/members/ban.ts @@ -4,20 +4,20 @@ import { requireBotGuildPermissions } from "../permissions.ts"; export function banMember(bot: BotWithCache) { const banMemberOld = bot.helpers.banMember; - bot.helpers.banMember = function (guildId, id, options) { + bot.helpers.banMember = async function (guildId, id, options) { requireBotGuildPermissions(bot, guildId, ["BAN_MEMBERS"]); - return banMemberOld(guildId, id, options); + return await banMemberOld(guildId, id, options); }; } export function unbanMember(bot: BotWithCache) { const unbanMemberOld = bot.helpers.unbanMember; - bot.helpers.unbanMember = function (guildId, id) { + bot.helpers.unbanMember = async function (guildId, id) { requireBotGuildPermissions(bot, guildId, ["BAN_MEMBERS"]); - return unbanMemberOld(guildId, id); + return await unbanMemberOld(guildId, id); }; } diff --git a/plugins/permissions/src/members/editBot.ts b/plugins/permissions/src/members/editBot.ts index 0d246add5..cd7e94706 100644 --- a/plugins/permissions/src/members/editBot.ts +++ b/plugins/permissions/src/members/editBot.ts @@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts"; export default function editBotNickname(bot: BotWithCache) { const editBotNicknameOld = bot.helpers.editBotNickname; - bot.helpers.editBotNickname = function (guildId, options) { + bot.helpers.editBotNickname = async function (guildId, options) { requireBotGuildPermissions(bot, guildId, ["CHANGE_NICKNAME"]); - return editBotNicknameOld(guildId, options); + return await editBotNicknameOld(guildId, options); }; } diff --git a/plugins/permissions/src/members/editMember.ts b/plugins/permissions/src/members/editMember.ts index 8c4f069bc..1b16b9740 100644 --- a/plugins/permissions/src/members/editMember.ts +++ b/plugins/permissions/src/members/editMember.ts @@ -4,7 +4,7 @@ import { requireBotGuildPermissions } from "../permissions.ts"; export default function editMember(bot: BotWithCache) { const editMemberOld = bot.helpers.editMember; - bot.helpers.editMember = function (guildId, memberId, options) { + bot.helpers.editMember = async function (guildId, memberId, options) { const requiredPerms: PermissionStrings[] = []; if (options.roles) requiredPerms.push("MANAGE_ROLES"); // NULL IS ALLOWED @@ -17,6 +17,6 @@ export default function editMember(bot: BotWithCache) { requireBotGuildPermissions(bot, guildId, requiredPerms); } - return editMemberOld(guildId, memberId, options); + return await editMemberOld(guildId, memberId, options); }; } diff --git a/plugins/permissions/src/members/kickMember.ts b/plugins/permissions/src/members/kickMember.ts index 71a3fd8a5..a804cdc5e 100644 --- a/plugins/permissions/src/members/kickMember.ts +++ b/plugins/permissions/src/members/kickMember.ts @@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts"; export default function kickMember(bot: BotWithCache) { const editMemberOld = bot.helpers.kickMember; - bot.helpers.kickMember = function (guildId, memberId, reason) { + bot.helpers.kickMember = async function (guildId, memberId, reason) { requireBotGuildPermissions(bot, guildId, ["KICK_MEMBERS"]); - return editMemberOld(guildId, memberId, reason); + return await editMemberOld(guildId, memberId, reason); }; } diff --git a/plugins/permissions/src/members/pruneMembers.ts b/plugins/permissions/src/members/pruneMembers.ts index 55aad7138..870c41559 100644 --- a/plugins/permissions/src/members/pruneMembers.ts +++ b/plugins/permissions/src/members/pruneMembers.ts @@ -4,9 +4,9 @@ import { requireBotGuildPermissions } from "../permissions.ts"; export default function pruneMembers(bot: BotWithCache) { const pruneMembersOld = bot.helpers.pruneMembers; - bot.helpers.pruneMembers = function (guildId, options) { + bot.helpers.pruneMembers = async function (guildId, options) { requireBotGuildPermissions(bot, guildId, ["KICK_MEMBERS"]); - return pruneMembersOld(guildId, options); + return await pruneMembersOld(guildId, options); }; } diff --git a/plugins/permissions/src/messages/create.ts b/plugins/permissions/src/messages/create.ts index 70b2021fa..f26ca6a54 100644 --- a/plugins/permissions/src/messages/create.ts +++ b/plugins/permissions/src/messages/create.ts @@ -5,7 +5,7 @@ import { requireBotChannelPermissions } from "../permissions.ts"; export function sendMessage(bot: BotWithCache) { const sendMessageOld = bot.helpers.sendMessage; - bot.helpers.sendMessage = function ( + bot.helpers.sendMessage = async function ( channelId, content, ) { @@ -90,7 +90,7 @@ export function sendMessage(bot: BotWithCache) { } } - return sendMessageOld(channelId, content); + return await sendMessageOld(channelId, content); }; } diff --git a/plugins/permissions/src/messages/delete.ts b/plugins/permissions/src/messages/delete.ts index cfe53a431..57c9ec1e2 100644 --- a/plugins/permissions/src/messages/delete.ts +++ b/plugins/permissions/src/messages/delete.ts @@ -4,7 +4,7 @@ import { requireBotChannelPermissions } from "../permissions.ts"; export function deleteMessage(bot: BotWithCache) { const deleteMessageOld = bot.helpers.deleteMessage; - bot.helpers.deleteMessage = function ( + bot.helpers.deleteMessage = async function ( channelId, messageId, reason, @@ -27,14 +27,14 @@ export function deleteMessage(bot: BotWithCache) { ); } - return deleteMessageOld(channelId, messageId, reason, milliseconds); + return await deleteMessageOld(channelId, messageId, reason, milliseconds); }; } export function deleteMessages(bot: BotWithCache) { const deleteMessagesOld = bot.helpers.deleteMessages; - bot.helpers.deleteMessages = function ( + bot.helpers.deleteMessages = async function ( channelId, ids, reason, @@ -70,7 +70,7 @@ export function deleteMessages(bot: BotWithCache) { "MANAGE_MESSAGES", ]); - return deleteMessagesOld(channelId, ids, reason); + return await deleteMessagesOld(channelId, ids, reason); }; } diff --git a/plugins/permissions/src/messages/get.ts b/plugins/permissions/src/messages/get.ts index 6add29acc..129f446a0 100644 --- a/plugins/permissions/src/messages/get.ts +++ b/plugins/permissions/src/messages/get.ts @@ -4,7 +4,7 @@ import { requireBotChannelPermissions } from "../permissions.ts"; export function getMessage(bot: BotWithCache) { const getMessageOld = bot.helpers.getMessage; - bot.helpers.getMessage = function ( + bot.helpers.getMessage = async function ( channelId, messageId, ) { @@ -15,14 +15,14 @@ export function getMessage(bot: BotWithCache) { ]); } - return getMessageOld(channelId, messageId); + return await getMessageOld(channelId, messageId); }; } export function getMessages(bot: BotWithCache) { const getMessagesOld = bot.helpers.getMessages; - bot.helpers.getMessages = function ( + bot.helpers.getMessages = async function ( channelId, options, ) { @@ -34,7 +34,7 @@ export function getMessages(bot: BotWithCache) { ]); } - return getMessagesOld(channelId, options); + return await getMessagesOld(channelId, options); }; } diff --git a/plugins/permissions/src/messages/pin.ts b/plugins/permissions/src/messages/pin.ts index 6b7d04402..9be081529 100644 --- a/plugins/permissions/src/messages/pin.ts +++ b/plugins/permissions/src/messages/pin.ts @@ -4,7 +4,7 @@ import { requireBotChannelPermissions } from "../permissions.ts"; export function pinMessage(bot: BotWithCache) { const pinMessageOld = bot.helpers.pinMessage; - bot.helpers.pinMessage = function ( + bot.helpers.pinMessage = async function ( channelId, messageId, ) { @@ -12,14 +12,14 @@ export function pinMessage(bot: BotWithCache) { "MANAGE_MESSAGES", ]); - return pinMessageOld(channelId, messageId); + return await pinMessageOld(channelId, messageId); }; } export function unpinMessage(bot: BotWithCache) { const unpinMessageOld = bot.helpers.unpinMessage; - bot.helpers.unpinMessage = function ( + bot.helpers.unpinMessage = async function ( channelId, messageId, ) { @@ -27,7 +27,7 @@ export function unpinMessage(bot: BotWithCache) { "MANAGE_MESSAGES", ]); - return unpinMessageOld(channelId, messageId); + return await unpinMessageOld(channelId, messageId); }; } diff --git a/plugins/permissions/src/messages/reactions.ts b/plugins/permissions/src/messages/reactions.ts index 7ec78dd99..f510b8a87 100644 --- a/plugins/permissions/src/messages/reactions.ts +++ b/plugins/permissions/src/messages/reactions.ts @@ -4,20 +4,20 @@ import { requireBotChannelPermissions } from "../permissions.ts"; export function addReaction(bot: BotWithCache) { const addReactionOld = bot.helpers.addReaction; - bot.helpers.addReaction = function (channelId, messageId, reaction) { + bot.helpers.addReaction = async function (channelId, messageId, reaction) { requireBotChannelPermissions(bot, channelId, [ "READ_MESSAGE_HISTORY", "ADD_REACTIONS", ]); - return addReactionOld(channelId, messageId, reaction); + return await addReactionOld(channelId, messageId, reaction); }; } export function addReactions(bot: BotWithCache) { const addReactionsOld = bot.helpers.addReactions; - bot.helpers.addReactions = function ( + bot.helpers.addReactions = async function ( channelId, messageId, reactions, @@ -28,14 +28,14 @@ export function addReactions(bot: BotWithCache) { "ADD_REACTIONS", ]); - return addReactionsOld(channelId, messageId, reactions, ordered); + return await addReactionsOld(channelId, messageId, reactions, ordered); }; } export function removeReaction(bot: BotWithCache) { const removeReactionOld = bot.helpers.removeReaction; - bot.helpers.removeReaction = function ( + bot.helpers.removeReaction = async function ( channelId, messageId, reactions, @@ -48,14 +48,14 @@ export function removeReaction(bot: BotWithCache) { ]); } - return removeReactionOld(channelId, messageId, reactions, options); + return await removeReactionOld(channelId, messageId, reactions, options); }; } export function removeAllReactions(bot: BotWithCache) { const removeAllReactionsOld = bot.helpers.removeAllReactions; - bot.helpers.removeAllReactions = function ( + bot.helpers.removeAllReactions = async function ( channelId, messageId, ) { @@ -63,14 +63,14 @@ export function removeAllReactions(bot: BotWithCache) { "MANAGE_MESSAGES", ]); - return removeAllReactionsOld(channelId, messageId); + return await removeAllReactionsOld(channelId, messageId); }; } export function removeReactionEmoji(bot: BotWithCache) { const removeReactionEmojiOld = bot.helpers.removeReactionEmoji; - bot.helpers.removeReactionEmoji = function ( + bot.helpers.removeReactionEmoji = async function ( channelId, messageId, reaction, @@ -79,7 +79,7 @@ export function removeReactionEmoji(bot: BotWithCache) { "MANAGE_MESSAGES", ]); - return removeReactionEmojiOld(channelId, messageId, reaction); + return await removeReactionEmojiOld(channelId, messageId, reaction); }; } diff --git a/plugins/permissions/src/misc/mod.ts b/plugins/permissions/src/misc/mod.ts index 68a31f3dc..c6d7a4b41 100644 --- a/plugins/permissions/src/misc/mod.ts +++ b/plugins/permissions/src/misc/mod.ts @@ -3,7 +3,7 @@ import { BotWithCache } from "../../deps.ts"; export function editBotProfile(bot: BotWithCache) { const editBotProfileOld = bot.helpers.editBotProfile; - bot.helpers.editBotProfile = function ( + bot.helpers.editBotProfile = async function ( options, ) { // Nothing was edited @@ -36,7 +36,7 @@ export function editBotProfile(bot: BotWithCache) { } } - return editBotProfileOld(options); + return await editBotProfileOld(options); }; } diff --git a/plugins/permissions/src/roles/add.ts b/plugins/permissions/src/roles/add.ts index e0f16572e..2fb55848f 100644 --- a/plugins/permissions/src/roles/add.ts +++ b/plugins/permissions/src/roles/add.ts @@ -5,7 +5,7 @@ import { highestRole, requireBotGuildPermissions } from "../permissions.ts"; export default function addRole(bot: BotWithCache) { const addRoleOld = bot.helpers.addRole; - bot.helpers.addRole = function ( + bot.helpers.addRole = async function ( guildId, memberId, roleId, @@ -27,6 +27,6 @@ export default function addRole(bot: BotWithCache) { requireBotGuildPermissions(bot, guild, ["MANAGE_ROLES"]); } - return addRoleOld(guildId, memberId, roleId, reason); + return await addRoleOld(guildId, memberId, roleId, reason); }; } diff --git a/plugins/permissions/src/roles/create.ts b/plugins/permissions/src/roles/create.ts index e66fcf257..19fefc83f 100644 --- a/plugins/permissions/src/roles/create.ts +++ b/plugins/permissions/src/roles/create.ts @@ -4,13 +4,13 @@ import { requireBotGuildPermissions } from "../permissions.ts"; export default function createRole(bot: BotWithCache) { const createRoleOld = bot.helpers.createRole; - bot.helpers.createRole = function ( + bot.helpers.createRole = async function ( guildId, options, reason, ) { requireBotGuildPermissions(bot, guildId, ["MANAGE_ROLES"]); - return createRoleOld(guildId, options, reason); + return await createRoleOld(guildId, options, reason); }; } diff --git a/plugins/permissions/src/roles/delete.ts b/plugins/permissions/src/roles/delete.ts index 896d33bef..16a6eda21 100644 --- a/plugins/permissions/src/roles/delete.ts +++ b/plugins/permissions/src/roles/delete.ts @@ -4,12 +4,12 @@ import { requireBotGuildPermissions } from "../permissions.ts"; export default function deleteRole(bot: BotWithCache) { const deleteRoleOld = bot.helpers.deleteRole; - bot.helpers.deleteRole = function ( + bot.helpers.deleteRole = async function ( guildId, id, ) { requireBotGuildPermissions(bot, guildId, ["MANAGE_ROLES"]); - return deleteRoleOld(guildId, id); + return await deleteRoleOld(guildId, id); }; } diff --git a/plugins/permissions/src/roles/edit.ts b/plugins/permissions/src/roles/edit.ts index ab4034b08..ff14a4d4a 100644 --- a/plugins/permissions/src/roles/edit.ts +++ b/plugins/permissions/src/roles/edit.ts @@ -5,7 +5,7 @@ import { highestRole, requireBotGuildPermissions } from "../permissions.ts"; export default function editRole(bot: BotWithCache) { const editRoleOld = bot.helpers.editRole; - bot.helpers.editRole = function ( + bot.helpers.editRole = async function ( guildId, id, options, @@ -26,6 +26,6 @@ export default function editRole(bot: BotWithCache) { requireBotGuildPermissions(bot, guild, ["MANAGE_ROLES"]); } - return editRoleOld(guildId, id, options); + return await editRoleOld(guildId, id, options); }; } diff --git a/plugins/permissions/src/roles/remove.ts b/plugins/permissions/src/roles/remove.ts index d85a6af80..215397f47 100644 --- a/plugins/permissions/src/roles/remove.ts +++ b/plugins/permissions/src/roles/remove.ts @@ -5,7 +5,7 @@ import { highestRole, requireBotGuildPermissions } from "../permissions.ts"; export default function removeRole(bot: BotWithCache) { const removeRoleOld = bot.helpers.removeRole; - bot.helpers.removeRole = function ( + bot.helpers.removeRole = async function ( guildId, memberId, roleId, @@ -27,6 +27,6 @@ export default function removeRole(bot: BotWithCache) { requireBotGuildPermissions(bot, guild, ["MANAGE_ROLES"]); } - return removeRoleOld(guildId, memberId, roleId, reason); + return await removeRoleOld(guildId, memberId, roleId, reason); }; } diff --git a/plugins/permissions/src/webhooks/createWebhook.ts b/plugins/permissions/src/webhooks/createWebhook.ts index 95a107791..214cde9f0 100644 --- a/plugins/permissions/src/webhooks/createWebhook.ts +++ b/plugins/permissions/src/webhooks/createWebhook.ts @@ -4,7 +4,7 @@ import { requireBotChannelPermissions } from "../permissions.ts"; export default function createWebhook(bot: BotWithCache) { const createWebhookOld = bot.helpers.createWebhook; - bot.helpers.createWebhook = function (channelId, options) { + bot.helpers.createWebhook = async function (channelId, options) { requireBotChannelPermissions(bot, channelId, ["MANAGE_WEBHOOKS"]); if ( @@ -17,6 +17,6 @@ export default function createWebhook(bot: BotWithCache) { ); } - return createWebhookOld(channelId, options); + return await createWebhookOld(channelId, options); }; } diff --git a/plugins/permissions/src/webhooks/deleteWebhook.ts b/plugins/permissions/src/webhooks/deleteWebhook.ts index 1ba0cf19b..96313b30f 100644 --- a/plugins/permissions/src/webhooks/deleteWebhook.ts +++ b/plugins/permissions/src/webhooks/deleteWebhook.ts @@ -4,9 +4,9 @@ import { requireBotChannelPermissions } from "../permissions.ts"; export default function deleteWebhook(bot: BotWithCache) { const deleteWebhookOld = bot.helpers.deleteWebhook; - bot.helpers.deleteWebhook = function (channelId, options) { + bot.helpers.deleteWebhook = async function (channelId, options) { requireBotChannelPermissions(bot, channelId, ["MANAGE_WEBHOOKS"]); - return deleteWebhookOld(channelId, options); + return await deleteWebhookOld(channelId, options); }; } diff --git a/plugins/permissions/src/webhooks/editWebhook.ts b/plugins/permissions/src/webhooks/editWebhook.ts index 75c055aee..38a2b5990 100644 --- a/plugins/permissions/src/webhooks/editWebhook.ts +++ b/plugins/permissions/src/webhooks/editWebhook.ts @@ -4,7 +4,7 @@ import { requireBotChannelPermissions } from "../permissions.ts"; export default function editWebhook(bot: BotWithCache) { const editWebhookOld = bot.helpers.editWebhook; - bot.helpers.editWebhook = function (channelId, webhookId, options) { + bot.helpers.editWebhook = async function (channelId, webhookId, options) { requireBotChannelPermissions(bot, channelId, ["MANAGE_WEBHOOKS"]); if (options.name) { if ( @@ -18,6 +18,6 @@ export default function editWebhook(bot: BotWithCache) { } } - return editWebhookOld(channelId, webhookId, options); + return await editWebhookOld(channelId, webhookId, options); }; } diff --git a/plugins/permissions/src/webhooks/message.ts b/plugins/permissions/src/webhooks/message.ts index 0eb975942..a3167736f 100644 --- a/plugins/permissions/src/webhooks/message.ts +++ b/plugins/permissions/src/webhooks/message.ts @@ -4,7 +4,7 @@ import { validateComponents } from "../components.ts"; export function editWebhookMessage(bot: BotWithCache) { const editWebhookMessageOld = bot.helpers.editWebhookMessage; - bot.helpers.editWebhookMessage = function ( + bot.helpers.editWebhookMessage = async function ( webhookId, webhookToken, options, @@ -62,7 +62,7 @@ export function editWebhookMessage(bot: BotWithCache) { if (options.components) validateComponents(bot, options.components); - return editWebhookMessageOld(webhookId, webhookToken, options); + return await editWebhookMessageOld(webhookId, webhookToken, options); }; } diff --git a/plugins/permissions/src/webhooks/sendWebhook.ts b/plugins/permissions/src/webhooks/sendWebhook.ts index 4078f521c..9ab776cb2 100644 --- a/plugins/permissions/src/webhooks/sendWebhook.ts +++ b/plugins/permissions/src/webhooks/sendWebhook.ts @@ -4,7 +4,7 @@ import { validateComponents } from "../components.ts"; export default function sendWebhook(bot: BotWithCache) { const sendWebhookOld = bot.helpers.sendWebhook; - bot.helpers.sendWebhook = function (webhookId, webhookToken, options) { + bot.helpers.sendWebhook = async function (webhookId, webhookToken, options) { if ( options.content && !bot.utils.validateLength(options.content, { max: 2000 }) @@ -62,6 +62,6 @@ export default function sendWebhook(bot: BotWithCache) { ); } - return sendWebhookOld(webhookId, webhookToken, options); + return await sendWebhookOld(webhookId, webhookToken, options); }; } diff --git a/r.ts b/r.ts new file mode 100644 index 000000000..555961739 --- /dev/null +++ b/r.ts @@ -0,0 +1,16 @@ +import { createBot } from "./bot.ts"; + +const bot = createBot({ + token: "", + botId: 1n, + events: {}, + intents: [], +}); + +await bot.helpers.deleteWebhookMessage( + 943082834103500820n, + "LgGfOmEpEh13BP-u31TCUADsr0cE0LCn5ZTQM-RL1toQf0YUJBV5gd8tdpK0gC8c3J7Z", + 943083038240301056n, +); + +// https://discord.com/api/webhooks/943082834103500820/LgGfOmEpEh13BP-u31TCUADsr0cE0LCn5ZTQM-RL1toQf0YUJBV5gd8tdpK0gC8c3J7Z From 72294936e0eae18e93f8340124a2eea4e12988d2 Mon Sep 17 00:00:00 2001 From: ITOH Date: Wed, 16 Feb 2022 18:28:11 +0100 Subject: [PATCH 04/14] Delete r.ts --- r.ts | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 r.ts diff --git a/r.ts b/r.ts deleted file mode 100644 index 555961739..000000000 --- a/r.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { createBot } from "./bot.ts"; - -const bot = createBot({ - token: "", - botId: 1n, - events: {}, - intents: [], -}); - -await bot.helpers.deleteWebhookMessage( - 943082834103500820n, - "LgGfOmEpEh13BP-u31TCUADsr0cE0LCn5ZTQM-RL1toQf0YUJBV5gd8tdpK0gC8c3J7Z", - 943083038240301056n, -); - -// https://discord.com/api/webhooks/943082834103500820/LgGfOmEpEh13BP-u31TCUADsr0cE0LCn5ZTQM-RL1toQf0YUJBV5gd8tdpK0gC8c3J7Z From 51ce4803afc0c529db497ae37c44e299a2a8cb38 Mon Sep 17 00:00:00 2001 From: LTS20050703 <87189679+lts20050703@users.noreply.github.com> Date: Sat, 19 Feb 2022 20:49:29 +0700 Subject: [PATCH 05/14] docs(types): add link for `InputTextComponent` (#2061) --- types/messages/components/inputTextComponent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/messages/components/inputTextComponent.ts b/types/messages/components/inputTextComponent.ts index 08168c236..af6821c31 100644 --- a/types/messages/components/inputTextComponent.ts +++ b/types/messages/components/inputTextComponent.ts @@ -1,7 +1,7 @@ import { MessageComponentTypes } from "./messageComponentTypes.ts"; import { TextStyles } from "./textStyles.ts"; -// TODO: docs link +/** https://discord.com/developers/docs/interactions/message-components#text-inputs-text-input-structure */ export interface InputTextComponent { /** InputText Component is of type 3 */ type: MessageComponentTypes.InputText; From 9a4a2909f51b099748a9856ea156abfa67c7f437 Mon Sep 17 00:00:00 2001 From: LTS20050703 <87189679+lts20050703@users.noreply.github.com> Date: Sat, 19 Feb 2022 21:27:30 +0700 Subject: [PATCH 06/14] docs(types): update `MessageComponentTypes` variant description (#2060) --- types/messages/components/messageComponentTypes.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/types/messages/components/messageComponentTypes.ts b/types/messages/components/messageComponentTypes.ts index d1f04df1b..7bc2e6357 100644 --- a/types/messages/components/messageComponentTypes.ts +++ b/types/messages/components/messageComponentTypes.ts @@ -1,11 +1,11 @@ /** https://discord.com/developers/docs/interactions/message-components#component-types */ export enum MessageComponentTypes { - /** A row of components at the bottom of a message */ + /** A container for other components */ ActionRow = 1, - /** A button! */ + /** A button object */ Button = 2, - /** A select menu. */ + /** A select menu for picking from choices */ SelectMenu = 3, - /** An Input Text. */ + /** A text input object */ InputText = 4, } From 120fae0840bcfcf5f4e87fd0c2099120cc0a3fb6 Mon Sep 17 00:00:00 2001 From: LTS20050703 <87189679+lts20050703@users.noreply.github.com> Date: Sat, 19 Feb 2022 21:27:49 +0700 Subject: [PATCH 07/14] fix(types): `ScheduledEvent#creator_id` is nullable (#2059) --- types/guilds/scheduledEvents.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/guilds/scheduledEvents.ts b/types/guilds/scheduledEvents.ts index b807266ae..b2e3e0f89 100644 --- a/types/guilds/scheduledEvents.ts +++ b/types/guilds/scheduledEvents.ts @@ -8,7 +8,7 @@ export interface ScheduledEvent { /** the channel id in which the scheduled event will be hosted if specified */ channelId: string | null; /** the id of the user that created the scheduled event */ - creatorId?: string; + creatorId?: string | null; /** the name of the scheduled event */ name: string; /** the description of the scheduled event */ From 1f485eea0b53fb3e7ef5c431a62490261a910b59 Mon Sep 17 00:00:00 2001 From: LTS20050703 <87189679+lts20050703@users.noreply.github.com> Date: Sat, 19 Feb 2022 21:28:05 +0700 Subject: [PATCH 08/14] fix(types): `ThreadMetadata#create_timestamp` is optional and nullable & `locked` is not optional (#2057) --- types/channels/threads/threadMetadata.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/channels/threads/threadMetadata.ts b/types/channels/threads/threadMetadata.ts index 209d0862d..594c38626 100644 --- a/types/channels/threads/threadMetadata.ts +++ b/types/channels/threads/threadMetadata.ts @@ -7,9 +7,9 @@ export interface ThreadMetadata { /** Timestamp when the thread's archive status was last changed, used for calculating recent activity */ archiveTimestamp: string; /** When a thread is locked, only users with `MANAGE_THREADS` can unarchive it */ - locked?: boolean; + locked: boolean; /** whether non-moderators can add other non-moderators to a thread; only available on private threads */ invitable?: boolean; /** Timestamp when the thread was created; only populated for threads created after 2022-01-09 */ - createTimestamp: string; + createTimestamp?: string | null; } From 0cb2baaea2c37b5b4eb36ab641ca775c841e97d9 Mon Sep 17 00:00:00 2001 From: LTS20050703 <87189679+lts20050703@users.noreply.github.com> Date: Sat, 19 Feb 2022 21:28:19 +0700 Subject: [PATCH 09/14] fix(types): `invitable` & `createTimestamp` are in `ThreadMetadata` and not in `Channel` (#2056) --- transformers/channel.ts | 6 ++++-- types/channels/channel.ts | 4 ---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/transformers/channel.ts b/transformers/channel.ts index a1f4979aa..d3287d334 100644 --- a/transformers/channel.ts +++ b/transformers/channel.ts @@ -71,8 +71,10 @@ export function transformChannel( botIsMember: Boolean(payload.channel.member), archived: payload.channel.thread_metadata?.archived, locked: payload.channel.thread_metadata?.locked, - invitable: payload.channel.invitable, - createTimestamp: payload.channel.create_timestamp ? Date.parse(payload.channel.create_timestamp) : undefined, + invitable: payload.channel.thread_metadata?.invitable, + createTimestamp: payload.channel.thread_metadata?.create_timestamp + ? Date.parse(payload.channel.thread_metadata.create_timestamp) + : undefined, }; } diff --git a/types/channels/channel.ts b/types/channels/channel.ts index 01636fea5..8e4fac1e5 100644 --- a/types/channels/channel.ts +++ b/types/channels/channel.ts @@ -58,8 +58,4 @@ export interface Channel { defaultAutoArchiveDuration?: number; /** computed permissions for the invoking user in the channel, including overwrites, only included when part of the resolved data received on a application command interaction */ permissions?: string; - /** whether non-moderators can add other non-moderators to a thread; only available on private threads */ - invitable?: boolean; - /** timestamp when the thread was created; only populated for threads created after 2022-01-09 */ - createTimestamp?: string; } From 79e260892b9e74c778ddc508af7e0c2cc4ddfee0 Mon Sep 17 00:00:00 2001 From: LTS20050703 <87189679+lts20050703@users.noreply.github.com> Date: Sat, 19 Feb 2022 21:28:31 +0700 Subject: [PATCH 10/14] docs(types): Clarify documentation on the `CREATE_PUBLIC_THREADS` permission (#2055) --- types/permissions/bitwisePermissionFlags.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/permissions/bitwisePermissionFlags.ts b/types/permissions/bitwisePermissionFlags.ts index b63d57906..8c2d1d024 100644 --- a/types/permissions/bitwisePermissionFlags.ts +++ b/types/permissions/bitwisePermissionFlags.ts @@ -70,7 +70,7 @@ export enum BitwisePermissionFlags { MANAGE_EVENTS = 0x0000000200000000, /** Allows for deleting and archiving threads, and viewing all private threads */ MANAGE_THREADS = 0x0000000400000000, - /** Allows for creating threads */ + /** Allows for creating public and announcement threads */ CREATE_PUBLIC_THREADS = 0x0000000800000000, /** Allows for creating private threads */ CREATE_PRIVATE_THREADS = 0x0000001000000000, From bea86bb47be02bd82ec7fe1e6af78fa1135badc8 Mon Sep 17 00:00:00 2001 From: LTS20050703 <87189679+lts20050703@users.noreply.github.com> Date: Sat, 19 Feb 2022 21:29:12 +0700 Subject: [PATCH 11/14] fix(helpers): when creating/modifying a channel `permission_overwrites` can omit the `allow` and `deny` (#2053) Clarify that permission_overwrites can omit allow and deny keys when creating/modifying channel/channel ovewrites --- helpers/channels/createChannel.ts | 10 +++++----- helpers/channels/editChannel.ts | 13 ++++++------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/helpers/channels/createChannel.ts b/helpers/channels/createChannel.ts index 58ff87760..5992c30ff 100644 --- a/helpers/channels/createChannel.ts +++ b/helpers/channels/createChannel.ts @@ -22,11 +22,11 @@ export async function createChannel(bot: Bot, guildId: bigint, options?: CreateG position: options.position, parent_id: options.parentId?.toString(), nsfw: options.nsfw, - permission_overwrites: options?.permissionOverwrites?.map((perm) => ({ - id: perm.id.toString(), - type: perm.type, - allow: perm.allow ? bot.utils.calculateBits(perm.allow) : "0", - deny: perm.deny ? bot.utils.calculateBits(perm.deny) : "0", + permission_overwrites: options?.permissionOverwrites?.map((overwrite) => ({ + id: overwrite.id.toString(), + type: overwrite.type, + allow: overwrite.allow ? bot.utils.calculateBits(overwrite.allow) : null, + deny: overwrite.deny ? bot.utils.calculateBits(overwrite.deny) : null, })), type: options?.type || ChannelTypes.GuildText, reason, diff --git a/helpers/channels/editChannel.ts b/helpers/channels/editChannel.ts index 8e67ec0b2..9c6455795 100644 --- a/helpers/channels/editChannel.ts +++ b/helpers/channels/editChannel.ts @@ -46,13 +46,12 @@ export async function editChannel(bot: Bot, channelId: bigint, options: ModifyCh locked: options.locked, invitable: options.invitable, permission_overwrites: options.permissionOverwrites - ? options.permissionOverwrites?.map((overwrite) => { - return { - ...overwrite, - allow: overwrite.allow ? bot.utils.calculateBits(overwrite.allow) : "0", - deny: overwrite.deny ? bot.utils.calculateBits(overwrite.deny) : "0", - }; - }) + ? options.permissionOverwrites?.map((overwrite) => ({ + id: overwrite.id.toString(), + type: overwrite.type, + allow: overwrite.allow ? bot.utils.calculateBits(overwrite.allow) : null, + deny: overwrite.deny ? bot.utils.calculateBits(overwrite.deny) : null, + })) : undefined, reason, }); From 3cf0e11beb27c68161de47475cb72b9ebe3bc4e4 Mon Sep 17 00:00:00 2001 From: LTS20050703 <87189679+lts20050703@users.noreply.github.com> Date: Sat, 19 Feb 2022 21:29:19 +0700 Subject: [PATCH 12/14] fix(types): interaction transformer not transforming components (#2052) --- transformers/interaction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transformers/interaction.ts b/transformers/interaction.ts index 8b2c98173..3446883b0 100644 --- a/transformers/interaction.ts +++ b/transformers/interaction.ts @@ -42,7 +42,7 @@ export function transformInteraction(bot: Bot, payload: SnakeCasedPropertiesDeep ? { componentType: payload.data.component_type, customId: payload.data.custom_id, - components: payload.data.components, + components: payload.data.components?.map((component) => bot.transformers.component(bot, component)), values: payload.data.values, id: payload.data.id ? bot.transformers.snowflake(payload.data.id) : undefined, name: payload.data.name, From 004533ac0b0da1fd237d750d89846bde28fd6af2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 19 Feb 2022 15:38:00 +0100 Subject: [PATCH 13/14] build(site): deps bump follow-redirects from 1.14.7 to 1.14.8 (#2064) Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.7 to 1.14.8. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.7...v1.14.8) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- site/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/site/package-lock.json b/site/package-lock.json index d6769ba57..a83ac8b13 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -6140,9 +6140,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==", + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", "funding": [ { "type": "individual", @@ -17396,9 +17396,9 @@ } }, "follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==" + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==" }, "fork-ts-checker-webpack-plugin": { "version": "6.5.0", From 0245bcc7a9b403198cb0157ac1a921d541add1ee Mon Sep 17 00:00:00 2001 From: LTS20050703 <87189679+lts20050703@users.noreply.github.com> Date: Sun, 20 Feb 2022 03:37:13 +0700 Subject: [PATCH 14/14] docs(types): add `attachment` to `InteractionData` (#2062) * document attachment application command type * update jsdoc comments Co-authored-by: ITOH Co-authored-by: ITOH --- .../commands/applicationCommandInteractionData.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/types/interactions/commands/applicationCommandInteractionData.ts b/types/interactions/commands/applicationCommandInteractionData.ts index 6f8d2f768..a7a755039 100644 --- a/types/interactions/commands/applicationCommandInteractionData.ts +++ b/types/interactions/commands/applicationCommandInteractionData.ts @@ -1,6 +1,7 @@ import { Channel, Message, MessageComponents, MessageComponentTypes, Role, User } from "../../mod.ts"; import { InteractionGuildMember } from "../interactionGuildMember.ts"; import { InteractionDataOption } from "./applicationCommandInteractionDataOption.ts"; +import { Attachment } from "../../messages/attachment.ts"; export interface InteractionData { /** The type of component */ @@ -15,7 +16,7 @@ export interface InteractionData { id: string; /** The name of the invoked command */ name: string; - /** Converted users + roles + channels */ + /** Converted users + roles + channels + attachments */ resolved?: { /** The Ids and Message objects */ messages?: Record; @@ -27,6 +28,8 @@ export interface InteractionData { roles?: Record; /** The Ids and partial Channel objects */ channels?: Record>; + /** The ids and attachment objects */ + attachments: Record; }; /** The params + values from the user */ options?: InteractionDataOption[];