chore: apps/site/ > site/

This commit is contained in:
Skillz4Killz
2023-02-20 21:20:54 +00:00
parent 5f6a111492
commit 8536fc7150
110 changed files with 4 additions and 4 deletions

View File

@@ -0,0 +1,4 @@
{
"label": "Command Handler",
"position": 9
}

View File

@@ -0,0 +1,92 @@
---
sidebar_position: 2
---
# Command Manager
Currently, you probably have something like this in your code:
```js
const Discord = require("discordeno.js");
// Ideally you should move to an `.env` file
const config = require("./config.json");
const bot = Discord.createBot({
events: {
messageCreate(client, message) {
if (message.content === "!ping") {
client.helpers.sendMessage(message.channelId, { content: "pong" });
}
},
},
intents: Discord.Intents.Guilds | Discord.Intents.GuildMessages,
token: config.token,
});
const client = Discord.enableCachePlugin(bot, {});
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.

View File

@@ -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 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.

View File

@@ -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).
:::

View File

@@ -0,0 +1,4 @@
{
"label": "Event Handler",
"position": 8
}

View File

@@ -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<options>.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 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.

View File

@@ -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.
- 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.
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.
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).
:::

View File

@@ -0,0 +1,75 @@
---
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 as it's 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 = client.messages.forge(payload);
if (message.author.bot) 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 = client.interactions.forge(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 = client.users.forge(payload.user);
if (payload.shardId + 1 === client.gateway.maxShards) {
// All Shards are ready
console.log(`Successfully connected to the gateway as ${client.user.tag}`);
}
};
```

View File

@@ -0,0 +1,4 @@
{
"label": "Structures",
"position": 7
}

View File

@@ -0,0 +1,55 @@
---
sidebar_position: 5
---
# Create Collectors
Some of your commands or features are sometimes based on user interactions. E.g. if a user presses a button and you want
to know whether it was pressed. This is actually done by listening to the `interactionCreate` event.
But sometimes you need to access locale variables or don't want to "hardcode" the part.
That's why it's sometimes recommended to create collectors.
Collectors are listeners that listen to a specific event. In addition, you can provide a filter, so you only receive
certain interactions.
## Use a Collector
:::note Template The template code is used below. You must have the EventManager part to use the collector feature. :::
We have a pre-made class for collectors which you can find
[here](https://github.com/meister03/discordeno.js/blob/master/Util/Collectors.js).
```js
const Discord = require("discordeno.js");
const filter = (m) => m.data?.customId === "warn_modal" && m.user.id === interaction.user.id;
const listener = client.eventListener; // When the eventListener property is named different
const collector = new Discord.Collector("interactionCreate", {
client: client,
timeout: 60000,
filter,
max: 20,
listener,
});
collector.on("collect", (m) => {
const interaction = client.interactions.forge(m);
// Stop Collector
// collector.stop();
});
// Fires on a timeout, when the collector has reached the max amount of interactions or when it has been closed
collector.on("end", (collected) => {
// Map of Collected Interactions
console.log(collected);
});
```
As you can see, this opens up many possibilities. You can listen to any event and get the interaction you need.
### Collector Options
`filter`: Function, just fire the event if the filter returns true. `timeout`: Number, the time in milliseconds until
the collector times out. `max`: Number, the max amount of interactions the collector can collect. `listener`: Function,
the listener that will be fired when the collector collects an interaction. Just required when client property is named
differently.

View File

@@ -0,0 +1,223 @@
---
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/meister03/discordeno.js/tree/master/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/meister03/discordeno.js/tree/master/Structures/Component.js).
### Button
```js
const Discord = require("discordeno.js");
const message = client.messages.forge(rawMessage);
const button = new Discord.Component()
.setType("BUTTON")
.setStyle("LINK")
.setLabel("Click me!")
.setUrl("https://google.com")
.toJSON();
// Button with raw types
const button2 = new Discord.Component()
.setType(2)
.setStyle(4)
.setLabel("DO NOT CLICK")
.setCustomId("12345")
.toJSON();
const actionRow = new Discord.Component()
.setType("ACTION_ROW")
.setComponents(button, button2)
.toJSON();
// Message to send
const messageOptions = { content: "hello", components: [actionRow] };
// await client.helpers.sendMessage(channelId, messageOptions); // Do it the raw way
message.channel.send(messageOptions); // Do it with the structure
```
As you can see, for simplicity you can use strings instead of numbers (types), which are hard to remember.
### Select Menu
```js
const Discord = require("discordeno.js");
const message = client.messages.forge(rawMessage);
const selectMenu = new Discord.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 Discord.Component()
.setType("ACTION_ROW")
.setComponents(selectMenu)
.toJSON();
const messageOptions = { content: "hello", components: [actionRow] };
// await client.helpers.sendMessage(channelId, messageOptions); // Do it the raw way
message.channel.send(messageOptions); // Do it with the structure
```
### Text Input
```js
const Discord = require("discordeno.js");
const interaction = client.messages.forge(rawInteraction);
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();
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.

View File

@@ -0,0 +1,100 @@
---
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
class Channel {
constructor(client, data) {
this.client = client;
this.id = data.id;
this.name = data.name;
}
async send(options) {
return await this.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 and you want to utilize the djs-like wrapper, you'll likely choose to
continue using special structures. Therefore we have ready-made structures for the wrapper `Discordeno.js`.
- [Guild](https://github.com/meister03/discordeno.js/tree/master/Structures/Guild.js)
- [Channel](https://github.com/meister03/discordeno.js/tree/master/Structures/Channel.js)
- [Role](https://github.com/meister03/discordeno.js/tree/master/Structures/Role.js)
- [Member](https://github.com/meister03/discordeno.js/tree/master/Structures/Member.js)
- [User](https://github.com/meister03/discordeno.js/tree/master/Structures/User.js)
- [Message](https://github.com/meister03/discordeno.js/tree/master/Structures/Message.js)
- [Interaction](https://github.com/meister03/discordeno.js/tree/master/Structures/Interaction.js)
- [Emoji](https://github.com/meister03/discordeno.js/tree/master/Structures/Emoji.js)
- [Webhook](https://github.com/meister03/discordeno.js/tree/master/Structures/Webhook.js)
- [Embed](https://github.com/meister03/discordeno.js/tree/master/Structures/Embed.js)
- [Component](https://github.com/meister03/discordeno.js/tree/master/Structures/Component.js)
- [Collection](https://github.com/meister03/discordeno.js/tree/master/Structures/Collection.js)
We recommend that you check the wrappers [Readme](https://github.com/meister03/discordeno.js#discordclient) in order to
construct the client for following the Guide
**Using the Structures:**
```js
const Discord = require("discordeno.js");
const client = new Discord.Client(clientOptions, cacheOptions); //See the Readme above
Discord.startBot(client);
const guild = client.guilds.forge(guildData);
const channel = guild.channels.forge(channelData);
const role = guild.roles.forge(roleData);
const member = guild.members.forge(memberData);
const user = guild.users.forge(userData);
const message = guild.messages.forge(messageData);
const interaction = guild.interactions.forge(interactionData);
const emoji = guild.emojis.forge(emojiData);
const webhook = new Discord.Webhook(client, webhookData);
const embed = new Discord.Embed(embedData); // embedData is optional
const component = new Discord.Component(componentData); // componentData is optional
const collection = new Discord.Collection();
```
Some popular methods have been added to the structures so that you can use them without having to come up with your own.
In order to use the Structures from the Wrapper, you need to invoke the `.forge` method with the raw discord data,
whereas it will construct the structure for you.
Next we're going to give a better insight into how create [`Embeds`](embeds) and [`Components`](components) with the
wrappers structures.

View File

@@ -0,0 +1,106 @@
---
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.
[Here is how the Embed Structure looks like](https://github.com/meister03/discordeno.js/blob/master/Structures/Embed.js)
### Using the Embed Structure:
```js
const Discord = require("discordeno.js");
const channel = client.channels.forge(channelData);
const showCaseEmbed = new Discord.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

View File

@@ -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.

View File

@@ -0,0 +1,4 @@
{
"label": "Nodejs",
"position": 3
}

View File

@@ -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.

View File

@@ -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.
:::

View File

@@ -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 that is too large to migrate to a slightly different language.
This guide will help you make your first Discord bot using Node.js or even migrate your bot from another library.
Moreover this guide will utilize two different options. One option to use the Discordeno package without any frameworks
and one, which uses the wrapper called `Discordeno.js`, which aims to achieve a djs-like interface.
:::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.

View File

@@ -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
```

View File

@@ -0,0 +1,30 @@
---
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. When you want to go along with the wrapper named `Discordeno.js`, then install it
too. Go to your terminal and run the following command:
```cli
$ npm install discordeno
```

View File

@@ -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 adding 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: Discord.Intents.Guilds | Discord.Intents.GuildMessages,
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.