mirror of
https://github.com/discordeno/discordeno.git
synced 2026-06-04 18:00:08 +00:00
BREAKING: node migration + major improvements and style changes (#2783)
* Setup turborepo (#2610) * chore: BREAKING move to monorepo structure * chore: setup turborepo * setup more eslint and tsconfig (#2612) * fix packages setting lcoation * add dist to ignore * style * fix: .vscode set prettier and remove deno configs (#2611) * fix: rewrite to process.env * chore: add node types * style: run eslint --fix * fix: tests import ext * chore: fix formatter * chore: add build script * chore: remove site from turborepo * chore: move to seperate packages * chore: seperate util * chore: rename to index * fix: utils * chore: bump typescript * fix: in process of fixing rest * fix: logger * style * chore: fix turbo script * fix: types * fix: types * fix: shard * fix: gateway * fixing: bot * fix: at least it can run now * chore: fix turbo script * chore: move plugins * chore: add type and utils export * chore: working bot type and cache plugin * Add git hooks (#2618) * CI: Setup ci (#2669) * ci: fix test * ci: fix typo * fix: turbo script * fixes: yarn and linter errors in embeds pkg * chore: fix yarn gitignore * Node migration - devcontainer (#2672) * ✨ - feat: devcontainer -> node * 👷♂ - ci: devcontainer - add tabnine, prettier * fix: ignore .env and debug.ts * fix: couple of linter errors * fix: linter error * fix: gateway linter errors * style: update style * style: fix bot style * fix: type * ci: move all old workflow * chore: close #2619 * chore: close #2671 * test: add mocha * chore: add typescript plugin * test: add mocha * test: add test to utils * test/ci: update ci and coverage * chore: change script naming * ci: update include test * test: add coverage * ci: fix cache * ci: fix ci and codecov * Discordeno Documentation (#2673) * Add git hooks * Add documentation generatation * Change Documentation Engine * Add documentation * Remove autogenerated docs * combine lint staged action into one * style: fix Co-authored-by: H01001000 <heiheiho000@gmail.com> * chore: new package client * test: add rest test * ci: enable codecov * fix: type * test: add test to all packages * ci: add release to gh per commit * fix: ci syntax * fix: package version * fix: publish script * fix: remove private from gateway * ci: add filter for changes * fix: ci syntex * ci: try fix path filter * ci: try fix path filter * test: add test * ci: fix string and boolean * fix: package and ci * chore: fix turbo type cache * ci: also publish to npm * ci: change to public * fix: not publish to npm * fix: dependencies * chore: fix fmt script * fix: better rest typecheck Closes #2621 * fix: run yarn install * feat: add transformers to rest * feat: add helpers to rest * test: move bot utils test * reverse change to release.yml * chore: add clean build * refactor: discordeno * chore: add import type * chore: remove bot * fix: change deps from bot to dd * chore: update yarn lock * test: temp remove test from logger * refactor: remove transformers in helpers/channel * type: close #2622 * ci(fix): explicitly define coverage file * refactor: remove transformers in helpers/emoji * type: fix discord guild type * feat: DiscordEditAutomoderationRule type * fix: remove unused type * feat: DiscordCreateGuildEmoji DiscordModifyGuildEmoji & DiscordModifyCHannel types * feat: DiscordCreateChannel DiscordBuDeleteMessages DiscordCreateMessage DiscordEditMessage * feat: DiscordCreateScheduledEvent EditScheduledEvent DiscordCreateInvite * fix: types for guild stuff for rest * feat: thread discord types for rest * feat: channel rest types * feat: member rest types * feat: more discord rest types * fix: type errors * fix: docs bot param name should be rest * type: fix type error * ci(fix): codecov * chore(client) :add export transformer * fix: verifySignature * test: fix types * test: add test prevent #2683 #2678 * fix: export transformer twice * ci: reuse cache * test: add test:unit-noTextCoverage * feat: add transform and constant package * fix: half fix #2683 #2688 * fix: #2688 fix all transformer.spec.ts * fix: transformer name * ci: update style * fix: dependencies * fix: naming * fix: yarn lock * fix: remove validations from helpers. Closes #2700 * fix: rest routes as a constants pkg * fix: esm import with .js * test: add exception case * feat: adding transformer * chore: change script name * chore: add path fixing to coverage file * fix: camelize tuple bug * fix: reverse transformers * fix: transformers folder to camel * fix: transformers as an object * fix: linter error * ci: run test with deno close #2701 * fix: test depends on build * fix: deno import node:crypto * fix: rest improvements * fix: channel type * fix: export user * chore: move to unit dir * test: moving bench * fix: remove transformers from rest package * fix: move toggle transformers to bot pkg * fix: move out gw helpers to gw package * test: add rest e2e test * fix: syntex * ci: add discord token * fix: ci not passing secret * test: add role test * ci: fix secret inherit * fix: role helpers transformer * test: increase timeout to 10s * fix: member helpers transformer * test: add member test * fix: name and type * fix: guild ban * test: fix test * fix: test add await * test: skip some test * test: increase timeout * chore: add transformer to import map * fix: test * test: add why-is-node-still-running * test: add debug hook * ci: add timeout incase any async running * test: try fix * test: turn on rest debug * fix: if undefined * test: reduce timeout * fix: queue not running after some request * fix: increase remaining after request without ratelimit header * fix: partial webhook * fix: fetch hooks not working if debug defined later * fix: nickname null to undefined * test: finish adding webhook test * refactor(test): move rest to utils * fix: add await * fix: sticker * feat: add message embed component transformer * fix: test not done * fix: arg type to bigString * fix: sendMessage * fix: add allowedMentions, interactionResponse * test: add emoji e2e test * test: add guild e2e test * refactor(test): remove extra rest call * fix: create emoji BINARY_TYPE_INVALID_DATA_URI * fix: create guild rate limit * fix: automode rule helpers and test * fix: test run in only * test: add some queue bucket test * test: remove empty test * refactor(test): use new guild * test: use new guild for other test * fix: guild not defind * reactor(test): remove duplicated creat channel * test: increase timeout to 30s * test: add thread test * fix: more transformers * fix: gateway helpers use transformers * fix: types belong in types pkg * fix: helpers use transformers * BREAKING: v19 rewrite to node + major improvements (#2703) * fix: move all to old folder * fix: cleanup types * fix: more cleanup * fix: more base cleanup * fix: token dotenv * fix: add base transformer * fix: partial error handling * fix: handle 429 rate limit * test(rest): fix unit test * fix(script): transform extension * test: fix error and buffer * feat: camelizer util * fix: cleanup * fix: rate limit queues and headers processing * fix: rest exports * fix: no more transformers * fix: queue header null bug * fix: add gateway package base * fix: lint error * fix: add prettier file * fix: prettier is default fmtr * fix: fmt shard file * fix: fmt * fix: types issue * fix: remove unused consts * fix: all import issues * fix: import error * fix: import ending with .js * fix: remove transformers package * Fix eslint (#2710) * fix: typing of button component label to be optional (#2708) * feat: add guild_connections to role tags and toggles (#2706) Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> * Add lint checks and autofixing workflow (#2702) * Add lint checks and autofixing workflow * Update lint.yml * Fix: use yarn instead npm * fix: add ts to eslint_extensions * fix: update dir * fix: lint.yml format Co-authored-by: Jonathan Ho <heiheiho000@gmail.com> * fix: unused deps * ci: fix e2e test not running * chore: run yarn install * test: this should run test * feat: getCHannel * feat: createEMji helper * feat: collection class in util package * fix: gateway bugs * why on earth is this needed change * fix: cleanup docs on collection * Emoji rest methods (node-migration-clean) (#2713) * feat: all emoji rest methods * Fix code style issues with ESLint Co-authored-by: Lint Action <lint-action@samuelmeuli.com> * fix: stuff * fix: bot types * fix: remove logs * fix: camelize all gateway payloads * fix: remove todos * fix: start deris * fix: lint/ts errors except shard file * thats 1 way to fix type errors * yes (#2714) Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> * feat: rest channel helpers * Update release.yml * Update release.yml * ci: add build filter * ci: fail fast false * fix: complete webhook related helpers * fix: follow announcement helper * add forum helper * add stage helpers * add thread related helpers * alphabetize * cleanup webhook routes * automod helpers * scheduled events * integrations helpers * invite stuff incomplete * dm channel and avatar url * chore: move ts-node into package * fix: importing esm * fix: tris message helpers * test(rest): add simplifyUrl test * test(rest): add checkRateLimits test * test(rest): add processRateLimitedPaths test * test(rest): fix missing beforeEach * test(utils): enable old test * interaction helpers * perf(utils): optimize snake to camel case conversion (#2717) * perf(utils): optimize snake to camel case conversion * fmt * wont change much but still faster * actually this was a stupid idea * shh * Fix(client): Fix typings. (#2716) Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> * test: fix rest and utils test (#2723) * test(utils): fix cant import collection * test(rest): await expect * fix(utils): deno compactability * test(utils): typing * fix(utils): add return type * Add rest helpers for templates (#2727) * Add rest helpers for templates * Fix code style issues with ESLint Co-authored-by: Lint Action <lint-action@samuelmeuli.com> * fix: remove frozenAt * fix: cleanup templates * ci: release to npm (#2725) * ci: release to npm * Update release.yml * 🐛 - fix: types - slashcommands - add nsfw prop (#2731) * feat(rest helpers): Add template and member helpers. (#2728) * feat(rest helpers): Add template and member helpers. * format code * feat(rest): add template routes * fix(rest): routes and runMethod * fix(rest): try to fix most of type Co-authored-by: H01001000 <heiheiho000@gmail.com> Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> * ci: fix release (#2732) * fix: rest type errors * fix: v19 begin * fix: yarn lock * chore: fix deps and script (#2733) * fix: bug camelizer deleting letters * fix: falsy token check * fix: add frozenat check for queue * fix: max stack trace error do to infinite loop * fix: type error * test(rest): fix missing import (#2734) Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> * fix: file paths for imports * fix: lastShardId should default to 0 * fix: use isomorphic ws * test(rest): fix "TypeError: [Function] is not a thenable" (#2736) * test(utils): add utils tests (#2737) * test(utils): add urltobase64 test * test(utils): add token test * test(utils): fix missing import buffer * test(utils): add casting test * test(utils): add casting test * test(utils): fix use correct function * chore: make eslint error if missing .js extension (#2735) * chore: eslint error if missing .js extension * chore * lint: fix missing .js error Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> * fix: readme runtime list (#2739) * Bot pkg (#2740) * fix: bot pkg test * Fix code style issues with ESLint * Update Guild.ts * Update Guild.ts * Fix code style issues with ESLint Co-authored-by: Lint Action <lint-action@samuelmeuli.com> Co-authored-by: Jonathan Ho <heiheiho000@gmail.com> * Update tsdoc.json (#2741) Updates tsdoc.json to reflect the current packages. * Interaction types - remove member,channel,role from value type (#2743) https://discord.com/channels/785384884197392384/1067265182776176690/1068189883073572924 * Add missing types (#2742) * Revert "fix: use isomorphic ws" (#2744) This reverts commitad306b0d0a. * fix: interaction requests that sent without full url * fix: lint issues * fix: remote gateway test file * fix: interaction response bug with body being invalid (#2746) * fix: readme runtime list * Fix code style issues with ESLint * node 18 * fix: websocket import type * fix: body for interaction requests --------- Co-authored-by: Lint Action <lint-action@samuelmeuli.com> * fix: interaction followup type (#2747) * fix: readme runtime list * Fix code style issues with ESLint * node 18 * fix: websocket import type * fix: body for interaction requests * fix: perma fix for type error in ci * fix: followupmessage option type --------- Co-authored-by: Lint Action <lint-action@samuelmeuli.com> * fix: e2e exit bug (#2748) * fix: readme runtime list * Fix code style issues with ESLint * node 18 * fix: websocket import type * fix: body for interaction requests * fix: perma fix for type error in ci * fix: followupmessage option type * fix: e2e tests exit bug * fix: color console logger --------- Co-authored-by: Lint Action <lint-action@samuelmeuli.com> * fix: rest sending attachments files (#2749) * fix: readme runtime list * Fix code style issues with ESLint * node 18 * fix: websocket import type * fix: body for interaction requests * fix: perma fix for type error in ci * fix: followupmessage option type * fix: e2e tests exit bug * fix: color console logger * fix: image file sending * Fix code style issues with ESLint --------- Co-authored-by: Lint Action <lint-action@samuelmeuli.com> * fix: guild and role methods (#2751) * fix: readme runtime list * Fix code style issues with ESLint * node 18 * fix: websocket import type * fix: body for interaction requests * fix: perma fix for type error in ci * fix: followupmessage option type * fix: e2e tests exit bug * fix: color console logger * fix: image file sending * Fix code style issues with ESLint * guild and role methods * Fix code style issues with ESLint --------- Co-authored-by: Lint Action <lint-action@samuelmeuli.com> * ci: add bot package (#2752) * ci: add bot package * ci: fix test * e2e test stuff (#2754) * fix: readme runtime list * Fix code style issues with ESLint * node 18 * fix: websocket import type * fix: body for interaction requests * fix: perma fix for type error in ci * fix: followupmessage option type * fix: e2e tests exit bug * fix: color console logger * fix: image file sending * Fix code style issues with ESLint * guild and role methods * Fix code style issues with ESLint * fix: dont send heartbeat if socket is not open * fix: remove logs * fox: remove more logs * fix some bugs in role tests * Switch to after hook style * hoti's speed snaker * auto convert objects for discord * Fix code style issues with ESLint * fix: remove dup imports * fix: i hate linters * speeder --------- Co-authored-by: Lint Action <lint-action@samuelmeuli.com> * fix: delete guilds test (#2758) * fix: readme runtime list * Fix code style issues with ESLint * node 18 * fix: websocket import type * fix: body for interaction requests * fix: perma fix for type error in ci * fix: followupmessage option type * fix: e2e tests exit bug * fix: color console logger * fix: image file sending * Fix code style issues with ESLint * guild and role methods * Fix code style issues with ESLint * fix: dont send heartbeat if socket is not open * fix: remove logs * fox: remove more logs * fix some bugs in role tests * Switch to after hook style * hoti's speed snaker * auto convert objects for discord * Fix code style issues with ESLint * fix: remove dup imports * fix: i hate linters * speeder * fix: tests delete guilds * Fix code style issues with ESLint --------- Co-authored-by: Lint Action <lint-action@samuelmeuli.com> * chore: fix deps (#2757) * ci/test: fix bot pkg e2e test (#2759) * chore: fix script and update import map (#2761) * chore: fix version script * chore: update import map * chore: fix ws import map * chore: fix deno import map * test: fix * fix: more rest e2e tests (#2763) * fix: readme runtime list * Fix code style issues with ESLint * node 18 * fix: websocket import type * fix: body for interaction requests * fix: perma fix for type error in ci * fix: followupmessage option type * fix: e2e tests exit bug * fix: color console logger * fix: image file sending * Fix code style issues with ESLint * guild and role methods * Fix code style issues with ESLint * fix: dont send heartbeat if socket is not open * fix: remove logs * fox: remove more logs * fix some bugs in role tests * Switch to after hook style * hoti's speed snaker * auto convert objects for discord * Fix code style issues with ESLint * fix: remove dup imports * fix: i hate linters * speeder * fix: tests delete guilds * Fix code style issues with ESLint * fix: easier to provide custom intents in bot * fix: shutdown bot after test * fix: add getGuild * fix: multiple guild delete attempts * fix: add emoji e2e tests * fix: remaining old e2e rest tests * Fix code style issues with ESLint --------- Co-authored-by: Lint Action <lint-action@samuelmeuli.com> * test: add gateway integration test (#2756) * test: add gateway integration test * test(gateway): fix connection test * test(gateway): add heartbeat test * ci: add integration test * fix: add uWebSockets.js * ci: add timeout * test(utils): remove old test * Revert "test(utils): remove old test" This reverts commit04fb6dd4b5. * test(gateway): fix uws server * test(gateway): fix type * chore: update codecov flag * test(gateway): remove dev code --------- Co-authored-by: Skillz4Killz <23035000+Skillz4Killz@users.noreply.github.com> * Update release.yml (#2768) * fix: bot logger (#2769) * fix: readme runtime list * Fix code style issues with ESLint * node 18 * fix: websocket import type * fix: body for interaction requests * fix: perma fix for type error in ci * fix: followupmessage option type * fix: e2e tests exit bug * fix: color console logger * fix: image file sending * Fix code style issues with ESLint * guild and role methods * Fix code style issues with ESLint * fix: dont send heartbeat if socket is not open * fix: remove logs * fox: remove more logs * fix some bugs in role tests * Switch to after hook style * hoti's speed snaker * auto convert objects for discord * Fix code style issues with ESLint * fix: remove dup imports * fix: i hate linters * speeder * fix: tests delete guilds * Fix code style issues with ESLint * fix: easier to provide custom intents in bot * fix: shutdown bot after test * fix: add getGuild * fix: multiple guild delete attempts * fix: add emoji e2e tests * fix: remaining old e2e rest tests * Fix code style issues with ESLint * fix: add bot.logger * fix: make logger name capital --------- Co-authored-by: Lint Action <lint-action@samuelmeuli.com> * chore: update readme (#2772) * chore: add coverage per pkg * chore: add npm version * chore: add test status * chore: fix ci * chore: fix ci * ci: fix ci needs * chore: add only push event * style: remove import logger * 📚 - docs: fix README package links (#2773) * test(all): add test importing index (#2774) * test(all): add test importing index * chore: remove old benchmark dir * chore: disable coverage status fail * test(client): add import test with try catch * test(rest): fix narrow import scope * test(utils): add test (#2764) * test(utils): remove old test * test(utils): add color test * test(utils): fix import mocha * test(utils): fix test type error * test(utils): remove dev code * fix(utils): bucket not export all function * test(utils): add some test for bucket * fix(utils): close #2775 * test(utils): add test for permissions.ts * test(utils): fix missing mocha import * fix(utils): better fix for #2775 * feat: addReaction & addReactions * feat: connectToVoice * fix: linters issues * fix: remove aliases and add createGuildFromTemplate * feat: deleteMessages * fix: reaction related helpers * mfa level * voie states editing * image urls * fix: typos * get message typeguards * fix: more helpers * fix: remaining helpers * fix: add logs to gateway manager * fix: rest resolve sends status and body * fix: lots of errors * fix: client errors * fix: remove old pkg * snaker * fix: broken util import for image url * fix: cleanup shard and circular deps * fix: remove ThreadChannel from GuildChannel * fix: generate interaction usage * fix: more bugs * fix: use node:events to import * fix(rest): add interface RestRequestRejection (#2782) * fix: remove invalid todo * fix: timeout bug --------- Co-authored-by: Skillz <skillz@discord.gg/ddeno> Co-authored-by: Jonathan Ho <heiheiho000@gmail.com> Co-authored-by: deepsarda <92147339+deepsarda@users.noreply.github.com> Co-authored-by: Awesome Stickz <awesome@stickz.dev> Co-authored-by: Lint Action <lint-action@samuelmeuli.com> Co-authored-by: Lars_und_so <46791248+Larsundso@users.noreply.github.com> Co-authored-by: ITOH <to@itoh.at> Co-authored-by: Yaikava <83710104+Yaikava@users.noreply.github.com> Co-authored-by: Andreas Fink <mail@afink.dev> --------- Co-authored-by: Jonathan Ho <48591478+H01001000@users.noreply.github.com> Co-authored-by: H01001000 <heiheiho000@gmail.com> Co-authored-by: deepsarda <92147339+deepsarda@users.noreply.github.com> Co-authored-by: Yaikava <83710104+Yaikava@users.noreply.github.com> Co-authored-by: Skillz <skillz@discord.gg/ddeno> Co-authored-by: Awesome Stickz <awesome@stickz.dev> Co-authored-by: Lint Action <lint-action@samuelmeuli.com> Co-authored-by: Lars_und_so <46791248+Larsundso@users.noreply.github.com> Co-authored-by: ITOH <to@itoh.at> Co-authored-by: Andreas Fink <mail@afink.dev>
This commit is contained in:
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"label": "Command Handler",
|
||||
"position": 9
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
---
|
||||
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.
|
||||
@@ -1,61 +0,0 @@
|
||||
---
|
||||
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.
|
||||
@@ -1,22 +0,0 @@
|
||||
---
|
||||
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).
|
||||
|
||||
:::
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"label": "Event Handler",
|
||||
"position": 8
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
---
|
||||
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.
|
||||
@@ -1,29 +0,0 @@
|
||||
---
|
||||
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).
|
||||
|
||||
:::
|
||||
@@ -1,75 +0,0 @@
|
||||
---
|
||||
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}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"label": "Structures",
|
||||
"position": 7
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
---
|
||||
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.
|
||||
@@ -1,223 +0,0 @@
|
||||
---
|
||||
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.
|
||||
|
||||

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

|
||||
|
||||
- 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.
|
||||
@@ -1,100 +0,0 @@
|
||||
---
|
||||
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.
|
||||
@@ -1,106 +0,0 @@
|
||||
---
|
||||
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
|
||||
@@ -1,30 +0,0 @@
|
||||
---
|
||||
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.
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"label": "Nodejs",
|
||||
"position": 3
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
---
|
||||
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.
|
||||
@@ -1,203 +0,0 @@
|
||||
---
|
||||
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.
|
||||
|
||||
:::
|
||||
@@ -1,48 +0,0 @@
|
||||
---
|
||||
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.
|
||||
@@ -1,46 +0,0 @@
|
||||
---
|
||||
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
|
||||
```
|
||||
@@ -1,30 +0,0 @@
|
||||
---
|
||||
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
|
||||
```
|
||||
@@ -1,64 +0,0 @@
|
||||
---
|
||||
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.
|
||||
Reference in New Issue
Block a user