Discordeno.js guide (#2313)

* Update Template and Add Discordeno.js notes in favour of depreciating Discord Structures

* Add package.json

* deno fmt

Co-authored-by: meister03 <meisterpi@gmail.com>
Co-authored-by: LTS20050703 <87189679+lts20050703@users.noreply.github.com>
Co-authored-by: LTS20050703 <lts20050703@gmail.com>
This commit is contained in:
meister03
2022-08-23 10:31:14 -04:00
committed by GitHub
co-authored by meister03 LTS20050703 LTS20050703
parent b5105cbc32
commit 405e4a7533
39 changed files with 260 additions and 693 deletions
@@ -1,4 +1,4 @@
{
"label": "Command Handler",
"position": 7
"position": 9
}
@@ -7,11 +7,11 @@ sidebar_position: 2
Currently, you probably have something like this in your code:
```js
const Discord = require("discordeno");
const Discord = require("discordeno.js");
// Ideally you should move to an `.env` file
const config = require("./config.json");
const client = Discord.createBot({
const bot = Discord.createBot({
events: {
messageCreate(client, message) {
if (message.content === "!ping") {
@@ -19,9 +19,10 @@ const client = Discord.createBot({
}
},
},
intents: ["Guilds", "GuildMessages"],
intents: Discord.Intents.Guilds | Discord.Intents.GuildMessages,
token: config.token,
});
const client = Discord.enableCachePlugin(bot, {});
Discord.startBot(client);
```
@@ -1,4 +1,4 @@
{
"label": "Event Handler",
"position": 6
"position": 8
}
@@ -27,9 +27,9 @@ This file should be called `messageCreate.js`.
const Message = require("./structures/Message");
module.exports = async (client, payload) => {
const message = new Message(client, payload);
const message = client.messages.forge(payload);
if (message.isBot) return;
if (message.author.bot) return;
if (message.content === "!ping") return await message.reply("pong");
};
```
@@ -42,7 +42,7 @@ This file should be called `interactionCreate.js`.
const Interaction = require("./structures/Interaction");
module.exports = async (client, payload) => {
const interaction = new Interaction(client, payload);
const interaction = client.interactions.forge(payload);
if (interaction.data.name === "ping") return await interaction.reply({ content: "pong" });
};
@@ -65,7 +65,7 @@ In order to fire the "real event" a small code snippet has to be added to the `r
const User = require("../Structures/User");
module.exports = async (client, payload) => {
client.user = new User(client, payload.user);
client.user = client.users.forge(payload.user);
if (payload.shardId + 1 === client.gateway.maxShards) {
// All Shards are ready
+1 -1
View File
@@ -1,4 +1,4 @@
{
"label": "Structures",
"position": 5
"position": 7
}
+55
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.
+21 -17
View File
@@ -19,7 +19,7 @@ just using raw data because they still execute methods, which takes more time to
:::
We already have a Template for `Components`, which can be found
[here](https://github.com/discordeno/discordeno/tree/main/template/nodejs/structures/Component.js).
[here](https://github.com/meister03/discordeno.js/tree/master/Structures/Component.js).
## Different Components:
@@ -102,12 +102,15 @@ This code will obviously not work because it's a missing a lot required of data.
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).
[here](https://github.com/meister03/discordeno.js/tree/master/Structures/Component.js).
### Button
```js
const button = new Component()
const Discord = require("discordeno.js");
const message = client.messages.forge(rawMessage);
const button = new Discord.Component()
.setType("BUTTON")
.setStyle("LINK")
.setLabel("Click me!")
@@ -115,14 +118,14 @@ const button = new Component()
.toJSON();
// Button with raw types
const button2 = new Component()
const button2 = new Discord.Component()
.setType(2)
.setStyle(4)
.setLabel("DO NOT CLICK")
.setCustomId("12345")
.toJSON();
const actionRow = new Component()
const actionRow = new Discord.Component()
.setType("ACTION_ROW")
.setComponents(button, button2)
.toJSON();
@@ -130,7 +133,8 @@ const actionRow = new Component()
// Message to send
const messageOptions = { content: "hello", components: [actionRow] };
await client.helpers.sendMessage(channelId, messageOptions); // You can also use the Message Structure
// 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.
@@ -138,7 +142,10 @@ As you can see, for simplicity you can use strings instead of numbers (types), w
### Select Menu
```js
const selectMenu = new Component()
const Discord = require("discordeno.js");
const message = client.messages.forge(rawMessage);
const selectMenu = new Discord.Component()
.setType("SELECT_MENU")
.setCustomId("12345")
.setOptions([
@@ -162,19 +169,23 @@ const selectMenu = new Component()
.setPlaceholder("Select an option")
.toJSON();
const actionRow = new Component()
const actionRow = new Discord.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
// 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")
@@ -199,7 +210,7 @@ const textInput2 = new Component()
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({
interaction.popupModal({
customId: "ban_modal",
title: "Ban User",
components: [actionRow, actionRow2],
@@ -210,10 +221,3 @@ new Interaction(client, interaction).popupModal({
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.
:::
+35 -14
View File
@@ -52,28 +52,49 @@ 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:
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/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)
- [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 clone the whole template repo, since some structures are based on other files.
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 Guild = require("./structures/Guild"); // Path to your structure
const guild = new Guild(client, data); // DiscordenoClient and DiscordenoPayloadData
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.
Of course, you can add your own methods and customize the structures to fit your needs.
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
template structures.
wrappers structures.
+4 -5
View File
@@ -57,16 +57,15 @@ 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)
[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 Embed = require("./structures/Embed"); // Path to structure
const Channel = require("./structures/Channel"); // Path to structure
const Discord = require("discordeno.js");
const channel = new Channel(client, data);
const showCaseEmbed = new Embed()
const channel = client.channels.forge(channelData);
const showCaseEmbed = new Discord.Embed()
.setColor(0x00AE86)
.setTitle("A Random Title")
.setURL("https://github.com/discordeno")
+3
View File
@@ -13,6 +13,9 @@ different language.
This guide will help you making your first Discord Bot using Node.js or even migrating your Bot from a other 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
+2 -1
View File
@@ -22,7 +22,8 @@ In order to keep track of the dependencies, you need to initialize NPM, which ge
$ npm init --yes
```
Then you need to install Discordeno. Go to your terminal and run the following command:
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
+1 -1
View File
@@ -53,7 +53,7 @@ const client = Discord.createBot({
}
},
},
intents: ["Guilds"],
intents: Discord.Intents.Guilds | Discord.Intents.GuildMessages,
token: config.token,
});
@@ -1,17 +0,0 @@
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;
+9 -9
View File
@@ -5,26 +5,26 @@ const resolveFolder = (folderName) => path.resolve(__dirname, ".", folderName);
const EventEmitter = require("events");
class EventManager extends EventEmitter {
constructor(client) {
constructor() {
super();
this.cache = new Map();
this._events = {};
this.allEvents = {};
}
load(options = {}) {
const eventsFolder = resolveFolder("../events");
let i = 0;
fs.readdirSync(eventsFolder).map(async (file) => {
if (!file.endsWith(".js")) return;
i++;
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);
};
*/
this.allEvents[`${eventName}`] = (...args) => {
this.emit(eventName, ...args);
return event(...args);
};
});
return this._events;
}
-13
View File
@@ -1,13 +0,0 @@
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;
-29
View File
@@ -1,29 +0,0 @@
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;
@@ -1,5 +1,6 @@
const Discord = require("discordeno.js");
const BaseCommand = require("../../../Structures/BaseCommand.js");
const Embed = require("../../../Structures/Embed.js");
class evalcommand extends BaseCommand {
static name = "eval";
static description = "danger !!!";
@@ -40,7 +41,7 @@ class evalcommand extends BaseCommand {
}, 1)
: outputOfEval;
const embed = new Embed()
const embed = new Discord.Embed()
.addField({ name: "Input", value: "```js\n" + inputOfEval + "```" })
.addField({ name: "Output", value: "```json\n" + `${outputOfEval}`.slice(0, 1000) + "```" });
this.reply({ embeds: [embed] });
@@ -1,5 +1,4 @@
const BaseCommand = require("../../../Structures/BaseCommand.js");
const Embed = require("../../../Structures/Embed.js");
class reloadcommand extends BaseCommand {
static name = "reload";
static description = "Reloads a Command";
@@ -1,5 +1,5 @@
const BaseCommand = require("../../../Structures/BaseCommand.js");
const Embed = require("../../../Structures/Embed.js");
const Discord = require("discordeno.js");
class pingcommand extends BaseCommand {
static name = "ping";
static description = "See if the bot latency is okay";
@@ -14,7 +14,7 @@ class pingcommand extends BaseCommand {
//Assign properties to the response
const ping = msg.timestamp - this.message.timestamp;
const embed = new Embed()
const embed = new Discord.Embed()
.setTitle(`The Bots ping is ${ping} ms`)
.toJSON();
//Edit Message with the Embed
@@ -1,5 +1,5 @@
const BaseCommand = require("../../../Structures/BaseCommand.js");
const Component = require("../../../Structures/Component.js");
const Discord = require("discordeno.js");
class bancommand extends BaseCommand {
static name = "ban";
@@ -16,7 +16,7 @@ class bancommand extends BaseCommand {
// Because no permission system has not been added
if (!this.client.config.owners.includes(String(this.user.id))) return;
const textinput = new Component()
const textinput = new Discord.Component()
.setType("TEXT_INPUT")
.setStyle("SHORT")
.setCustomId("t1")
@@ -27,12 +27,12 @@ class bancommand extends BaseCommand {
.setMinLength(1)
.setValue(this.args[0])
.toJSON();
const textinput2 = new Component().setType("TEXT_INPUT").setStyle("PARAGRAPH").setCustomId("t2")
const textinput2 = new Discord.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();
const actionrow = new Discord.Component().setType(1).setComponents(textinput).toJSON();
const actionrow2 = new Discord.Component().setType(1).setComponents(textinput2).toJSON();
this.interaction.popupModal({ customId: "ban_modal", title: "Ban User", components: [actionrow, actionrow2] });
}
@@ -0,0 +1,81 @@
const BaseCommand = require("../../../Structures/BaseCommand.js");
const { Interaction, Collector, ComponentOptions, Embed, Component } = require("discordeno.js");
class warncommand extends BaseCommand {
static name = "warn";
static description = "Warn a user from the server";
static usage = "";
static category = "Moderation";
static slash = { name: "warn", category: "mod" };
constructor(data) {
super(data);
}
async execute() {
//Show Case Modal
if (!this.interaction) return this.reply("You currently can just use this command as slash command.");
if (!this.interaction.member.permissions.has("KICK_MEMBERS")) {
return this.reply("You need the permission `KICK_MEMBERS` to use this command.");
}
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 Warning").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: "warn_modal", title: "Warn User", components: [actionrow, actionrow2] });
const filter = (m) => m.data?.customId === "warn_modal";
const collector = new Collector("interactionCreate", { client: this.client, timeout: 60000, filter });
collector.on("collect", (m) => {
const options = new ComponentOptions(m.data.components);
const i = new Interaction(this.client, m);
collector.stop();
const memberId = options.get("t1").value;
const reason = options.get("t2").value;
const embed = new Embed()
.setTitle("Warned User:")
.setDescription(`User ID: <@${memberId}> \n Reason: ${reason}`)
.setColor(0x00ff00)
.toJSON();
const warnMessage = new Embed()
.setTitle("Warning:")
.setDescription(`You have been warned in **${this.guild.name}** for ${"`" + reason + "`"}`)
.toJSON();
this.guild.members.fetch(memberId).then((m) => {
m.send({ embeds: [warnMessage] }).then(() => {
i.reply({ embeds: [embed] });
}).catch((e) => {
console.log(e);
i.reply({ content: `Could not warn user ${"<@" + m.id + ">"} | They likely do not have their DMs open.` });
});
}).catch((e) => {
const embed = new Embed()
.setTitle("Member not found")
.setDescription(`The member with the ID of ${"`" + memberId + "`"} has not been found in this Server.`)
.setColor(0xff0000)
.toJSON();
i.reply({ embeds: [embed] });
});
});
}
}
module.exports = warncommand;
+2 -2
View File
@@ -4,8 +4,8 @@ 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.message = data.message;
this.interaction = 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;
-29
View File
@@ -1,29 +0,0 @@
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;
+4 -11
View File
@@ -1,5 +1,3 @@
const Message = require("./Message");
class Responses {
constructor(data) {
this.manager = data.manager;
@@ -13,12 +11,8 @@ class Responses {
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;
return {};
}
if (this.message) {
if (this.replied) return this.followUp(content);
@@ -26,7 +20,7 @@ class Responses {
const msg = await this.message.channel.send(content);
//Assign properties to the response
const response = new Message(this.client, msg);
const response = this.client.messages.forge(msg);
this.replied = true;
return response;
}
@@ -35,12 +29,11 @@ class Responses {
async followUp(content) {
if (this.interaction) {
const reply = await this.interaction.followUp(content);
const response = new Message(this.client, reply);
return response;
return {};
}
if (this.message) {
const msg = await this.message.channel.send(content);
const response = new Message(this.client, msg);
const response = this.client.messages.forge(msg);
return response;
}
}
-171
View File
@@ -1,171 +0,0 @@
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;
@@ -1,16 +0,0 @@
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;
-99
View File
@@ -1,99 +0,0 @@
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;
-18
View File
@@ -1,18 +0,0 @@
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;
-116
View File
@@ -1,116 +0,0 @@
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;
-16
View File
@@ -1,16 +0,0 @@
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;
-50
View File
@@ -1,50 +0,0 @@
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;
@@ -1,9 +0,0 @@
/// On work
class Permissions {
constructor(client, data = {}, options = {}) {
this.client = client;
}
has(bit) {
}
}
-12
View File
@@ -1,12 +0,0 @@
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;
-13
View File
@@ -1,13 +0,0 @@
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;
@@ -1,3 +1,4 @@
module.exports = async (client, interaction) => {
interaction = client.interactions.forge(interaction);
client.commands.isInteraction(interaction);
};
+1
View File
@@ -1,3 +1,4 @@
module.exports = async (client, message) => {
message = client.messages.forge(message);
client.commands.isCommand(message);
};
+1 -2
View File
@@ -1,7 +1,6 @@
const User = require("../Structures/User");
module.exports = async (client, payload) => {
client.user = new User(client, payload.user);
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);
+4 -3
View File
@@ -1,4 +1,4 @@
const Discord = require("discordeno");
const Discord = require("discordeno.js");
// Ideally you should switch this to .env but for a template a config json is enough
const config = require("../config.json");
@@ -7,11 +7,12 @@ const EventManager = require("./Managers/EventManager.js");
// looping through all events and registering them
const events = new EventManager({});
const client = Discord.createBot({
const baseBot = Discord.createBot({
events: events.load({}),
intents: ["Guilds", "GuildMessages"],
intents: Discord.Intents.Guilds | Discord.Intents.GuildMessages | Discord.Intents.MessageContent,
token: config.token,
});
const client = Discord.enableCachePlugin(baseBot, {});
client.config = config;
+15
View File
@@ -0,0 +1,15 @@
{
"name": "nodejs-template",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"discordeno.js": "github:meister03/discordeno.js"
}
}