mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-15 11:03:30 +01:00
feat(guide): port legacy guide (#10938)
* feat: initial attempt at porting legacy guide * feat: completion of legacy guide backport * chore: lockfile shenanigans * fix: handle svgs * fix: replace svg with mermaid integration * chore: format * chore: remove unnecssary bullet * chore: cleanup code highlights * chore: explicit return * chore: move display components after interactive components in sidebar * chore: voice * top link should be installation * add docs link to sidebar * feat: subguide-based accent styles * chore: don't list faq twice * chore: mention display components in interactive components * fix: remove unoccs/order rule from guide * chore: redirect to legacy guide instead of /guide root * refactor: use `<kbd>` * refactor: more kbd use * Update apps/guide/content/docs/legacy/app-creation/handling-events.mdx Co-authored-by: Naiyar <137700126+imnaiyar@users.noreply.github.com> * chore: fix typos Co-authored-by: Qjuh <76154676+Qjuh@users.noreply.github.com> * chore: fix typos * chore: fix links regarding secret stores across coding platforms * chore: fix typo * chore: link node method directly Co-authored-by: Qjuh <76154676+Qjuh@users.noreply.github.com> * chore: typos Co-authored-by: Vlad Frangu <me@vladfrangu.dev> * chore: typo Co-authored-by: Vlad Frangu <me@vladfrangu.dev> * fix: prevent v14 changes from being listed twice * chore: prefer relative links * chore: missed link conversion * chore: missed link conversion * chore: fix link * chore: remove legacy code highlight markers * chore: rephrase and extend contributing guidelines * feat(setup): suggest cli flag over dotenv package * chore: move introduction in sidebar better navigation experience if the 'next page' in intro refers to getting started vs. updating/faq * fix: replace outdated link * fix: update voice dependencies * chore: update node install instructions * fix: list in missing access callout * chore: match bun env file format * chore: restore ffmpeg disclaimer * fix: lockfile conflict * chore: action row typo Co-authored-by: Vlad Frangu <me@vladfrangu.dev> * chore: no longer use at-next for pino --------- Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> Co-authored-by: Qjuh <76154676+Qjuh@users.noreply.github.com> Co-authored-by: Naiyar <137700126+imnaiyar@users.noreply.github.com> Co-authored-by: Vlad Frangu <me@vladfrangu.dev>
This commit is contained in:
219
apps/guide/content/docs/legacy/additional-info/async-await.mdx
Normal file
219
apps/guide/content/docs/legacy/additional-info/async-await.mdx
Normal file
@@ -0,0 +1,219 @@
|
||||
---
|
||||
title: Understanding async/await
|
||||
---
|
||||
|
||||
If you aren't very familiar with ECMAScript 2017, you may not know about async/await. It's a useful way to handle Promises in a hoisted manner. It's also slightly faster and increases overall readability.
|
||||
|
||||
## How do Promises work?
|
||||
|
||||
Before we can get into async/await, you should know what Promises are and how they work because async/await is just a way to handle Promises. If you know what Promises are and how to deal with them, you can skip this part.
|
||||
|
||||
Promises are a way to handle asynchronous tasks in JavaScript; they are the newer alternative to callbacks. A Promise has many similarities to a progress bar; they represent an unfinished and ongoing process. An excellent example of this is a request to a server (e.g., discord.js sends requests to Discord's API).
|
||||
|
||||
A Promise can have three states; pending, resolved, and rejected.
|
||||
|
||||
- The **pending** state means that the Promise still is ongoing and neither resolved nor rejected.
|
||||
- The **resolved** state means that the Promise is done and executed without any errors.
|
||||
- The **rejected** state means that the Promise encountered an error and could not execute correctly.
|
||||
|
||||
One important thing to know is that a Promise can only have one state simultaneously; it can never be pending and resolved, rejected and resolved, or pending and rejected. You may be asking, "How would that look in code?". Here is a small example:
|
||||
|
||||
<Callout>
|
||||
This example uses ES6 code. If you do not know what that is, you should read up on that [here](./es6-syntax).
|
||||
</Callout>
|
||||
|
||||
```js
|
||||
function deleteMessages(amount) {
|
||||
// [!code word:Promise]
|
||||
return new Promise((resolve, reject) => {
|
||||
if (amount > 10) return reject(new Error("You can't delete more than 10 Messages at a time."));
|
||||
setTimeout(() => resolve('Deleted 10 messages.'), 2_000);
|
||||
});
|
||||
}
|
||||
|
||||
deleteMessages(5)
|
||||
// [!code word:then]
|
||||
.then((value) => {
|
||||
// `deleteMessages` is complete and has not encountered any errors
|
||||
// the resolved value will be the string "Deleted 10 messages"
|
||||
})
|
||||
// [!code word:catch]
|
||||
.catch((error) => {
|
||||
// `deleteMessages` encountered an error
|
||||
// the error will be an Error Object
|
||||
});
|
||||
```
|
||||
|
||||
In this scenario, the `deleteMessages` function returns a Promise. The `.then()` method will trigger if the Promise resolves, and the `.catch()` method if the Promise rejects. In the `deleteMessages` function, the Promise is resolved after 2 seconds with the string "Deleted 10 messages.", so the `.catch()` method will never be executed. You can also pass the `.catch()` function as the second parameter of `.then()`.
|
||||
|
||||
## How to implement async/await
|
||||
|
||||
### Theory
|
||||
|
||||
The following information is essential to know before working with async/await. You can only use the `await` keyword inside a function declared as `async` (you put the `async` keyword before the `function` keyword or before the parameters when using a callback function).
|
||||
|
||||
A simple example would be:
|
||||
|
||||
```js
|
||||
// [!code word:async]
|
||||
async function declaredAsAsync() {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```js
|
||||
// [!code word:async]
|
||||
const declaredAsAsync = async () => {
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
You can use that as well if you use the arrow function as an event listener.
|
||||
|
||||
```js
|
||||
client.on('event', async (first, last) => {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
An important thing to know is that a function declared as `async` will always return a Promise. In addition to this, if you return something, the Promise will resolve with that value, and if you throw an error, it will reject the Promise with that error.
|
||||
|
||||
### Execution with discord.js code
|
||||
|
||||
Now that you know how Promises work and what they are used for, let's look at an example that handles multiple Promises. Let's say you want to react with letters (regional indicators) in a specific order. For this example, here's a basic template for a discord.js bot with some ES6 adjustments.
|
||||
|
||||
```js title="promise-example.js" lineNumbers
|
||||
const { Client, Events, GatewayIntentBits } = require('discord.js');
|
||||
|
||||
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
|
||||
|
||||
client.once(Events.ClientReady, () => {
|
||||
console.log('I am ready!');
|
||||
});
|
||||
|
||||
client.on(Events.InteractionCreate, (interaction) => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
|
||||
if (interaction.commandName === 'react') {
|
||||
// ...
|
||||
}
|
||||
});
|
||||
|
||||
client.login('your-token-goes-here');
|
||||
```
|
||||
|
||||
If you don't know how Node.js asynchronous execution works, you would probably try something like this:
|
||||
|
||||
```js title="promise-example.js" lineNumbers=9
|
||||
client.on(Events.InteractionCreate, (interaction) => {
|
||||
// ...
|
||||
// [!code focus:7]
|
||||
if (commandName === 'react') {
|
||||
const response = interaction.reply({ content: 'Reacting!', withResponse: true }); // [!code ++:5]
|
||||
const { message } = response.resource;
|
||||
message.react('🇦');
|
||||
message.react('🇧');
|
||||
message.react('🇨');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
But since all of these methods are started at the same time, it would just be a race to which server request finished first, so there would be no guarantee that it would react at all (if the message isn't fetched) or in the order you wanted it to. In order to make sure it reacts after the message is sent and in order (a, b, c), you'd need to use the `.then()` callback from the Promises that these methods return. The code would look like this:
|
||||
|
||||
```js title="promise-example.js" lineNumbers=9
|
||||
client.on(Events.InteractionCreate, (interaction) => {
|
||||
// ...
|
||||
if (commandName === 'react') {
|
||||
interaction.reply({ content: 'Reacting!', withResponse: true }).then((response) => {
|
||||
const { message } = response.resource;
|
||||
message.react('🇦'); // [!code --:3]
|
||||
message.react('🇧');
|
||||
message.react('🇨');
|
||||
message // [!code ++:7]
|
||||
.react('🇦')
|
||||
.then(() => message.react('🇧'))
|
||||
.then(() => message.react('🇨'))
|
||||
.catch((error) => {
|
||||
// handle failure of any Promise rejection inside here
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
In this piece of code, the Promises are [chain resolved](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then#Chaining) with each other, and if one of the Promises gets rejected, the function passed to `.catch()` gets called. Here's the same code but with async/await:
|
||||
|
||||
```js title="promise-example.js" lineNumbers=9
|
||||
client.on(Events.InteractionCreate, async (interaction) => {
|
||||
// ...
|
||||
if (commandName === 'react') {
|
||||
const response = await interaction.reply({ content: 'Reacting!', withResponse: true });
|
||||
const { message } = response.resource;
|
||||
message.react('🇦'); // [!code --:3]
|
||||
message.react('🇧');
|
||||
message.react('🇨');
|
||||
await message.react('🇦'); // [!code ++:3]
|
||||
await message.react('🇧');
|
||||
await message.react('🇨');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
It's mostly the same code, but how would you catch Promise rejections now since `.catch()` isn't there anymore? That is also a useful feature with async/await; the error will be thrown if you await it so that you can wrap the awaited Promises inside a try/catch, and you're good to go.
|
||||
|
||||
```js title="promise-example.js" lineNumbers=9
|
||||
client.on(Events.InteractionCreate, async (interaction) => {
|
||||
if (commandName === 'react') {
|
||||
// [!code ++]
|
||||
try {
|
||||
const response = await interaction.reply({ content: 'Reacting!', withResponse: true });
|
||||
const { message } = response.resource;
|
||||
await message.react('🇦');
|
||||
await message.react('🇧');
|
||||
await message.react('🇨');
|
||||
// [!code ++:3]
|
||||
} catch (error) {
|
||||
// handle failure of any Promise rejection inside here
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
This code looks clean and is also easy to read.
|
||||
|
||||
So you may be asking, "How would I get the value the Promise resolved with?".
|
||||
|
||||
Let's look at an example where you want to delete a sent reply.
|
||||
|
||||
```js title="promise-example.js"
|
||||
client.on(Events.InteractionCreate, (interaction) => {
|
||||
// ...
|
||||
if (commandName === 'delete') {
|
||||
interaction
|
||||
.reply({ content: 'This message will be deleted.', withResponse: true })
|
||||
.then((response) => setTimeout(() => response.resource.message.delete(), 10_000)) // [!code word:response]
|
||||
.catch((error) => {
|
||||
// handle error
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
The return value of a `.reply()` with the `withResponse` option set to `true` is a promise which resolves with `InteractionCallbackResponse`, but how would the same code with async/await look?
|
||||
|
||||
```js title="promise-example.js"
|
||||
client.on(Events.InteractionCreate, async (interaction) => {
|
||||
if (commandName === 'delete') {
|
||||
try {
|
||||
const response = await interaction.reply({ content: 'This message will be deleted.', withResponse: true }); // [!code word:response]
|
||||
setTimeout(() => response.resource.message.delete(), 10_000);
|
||||
} catch (error) {
|
||||
// handle error
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
With async/await, you can assign the awaited function to a variable representing the returned value. Now you know how you use async/await.
|
||||
@@ -0,0 +1,674 @@
|
||||
---
|
||||
title: Updating to v14
|
||||
---
|
||||
|
||||
## Before you start
|
||||
|
||||
Make sure you're using the latest LTS version of Node. To check your Node version, use `node -v` in your terminal or command prompt, and if it's not high enough, update it! There are many resources online to help you with this step based on your host system.
|
||||
|
||||
### Various packages are now included in v14
|
||||
|
||||
If you previously had `@discordjs/builders`, `@discordjs/formatters`, `@discordjs/rest`, or `discord-api-types` manually installed, it's _highly_ recommended that you uninstall the packages to avoid package version conflicts.
|
||||
|
||||
```sh tab="npm"
|
||||
npm uninstall @discordjs/builders @discordjs/formatters @discordjs/rest discord-api-types
|
||||
```
|
||||
|
||||
```sh tab="yarn"
|
||||
yarn remove @discordjs/builders @discordjs/formatters @discordjs/rest discord-api-types
|
||||
```
|
||||
|
||||
```sh tab="pnpm"
|
||||
pnpm remove @discordjs/builders @discordjs/formatters @discordjs/rest discord-api-types
|
||||
```
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
### API version
|
||||
|
||||
discord.js v14 makes the switch to Discord API v10!
|
||||
|
||||
### Common Breakages
|
||||
|
||||
### Enum Values
|
||||
|
||||
Any areas that used to accept a `string` or `number` type for an enum parameter will now only accept exclusively `number`s.
|
||||
|
||||
In addition, the old enums exported by discord.js v13 and lower are replaced with new enums from [discord-api-types](https://discord-api-types.dev/api/discord-api-types-v10).
|
||||
|
||||
#### New enum differences
|
||||
|
||||
Most of the difference between enums from discord.js and discord-api-types can be summarized as so:
|
||||
|
||||
1. Enums are singular, i.e., `ApplicationCommandOptionTypes` -> `ApplicationCommandOptionType`
|
||||
2. Enums that are prefixed with `Message` no longer have the `Message` prefix, i.e., `MessageButtonStyles` -> `ButtonStyle`
|
||||
3. Enum values are `PascalCase` rather than `SCREAMING_SNAKE_CASE`, i.e., `.CHAT_INPUT` -> `.ChatInput`
|
||||
|
||||
<Callout>
|
||||
You might be inclined to use raw `number`s (most commonly referred to as [magic numbers](<https://en.wikipedia.org/wiki/Magic_number_(programming)>)) instead of enum values. This is highly discouraged. Enums provide more readability and are more resistant to changes in the API. Magic numbers can obscure the meaning of your code in many ways, check out this [blog post](https://blog.webdevsimplified.com/2020-02/magic-numbers/) if you want more context on as to why they shouldn't be used.
|
||||
</Callout>
|
||||
|
||||
#### Common enum breakages
|
||||
|
||||
Areas like `Client` initialization, JSON slash commands and JSON message components will likely need to be modified to accommodate these changes:
|
||||
|
||||
##### Common Client Initialization Changes
|
||||
|
||||
```js
|
||||
const { Client, Intents } = require('discord.js'); // [!code --]
|
||||
const { Client, GatewayIntentBits, Partials } = require('discord.js'); // [!code ++]
|
||||
|
||||
const client = new Client({ intents: [Intents.FLAGS.GUILDS], partials: ['CHANNEL'] }); // [!code --]
|
||||
const client = new Client({ intents: [GatewayIntentBits.Guilds], partials: [Partials.Channel] }); // [!code ++]
|
||||
```
|
||||
|
||||
##### Common Application Command Data changes
|
||||
|
||||
```js
|
||||
const { ApplicationCommandType, ApplicationCommandOptionType } = require('discord.js'); // [!code ++]
|
||||
|
||||
const command = {
|
||||
name: 'ping',
|
||||
type: 'CHAT_INPUT', // [!code --]
|
||||
type: ApplicationCommandType.ChatInput, // [!code ++]
|
||||
options: [
|
||||
{
|
||||
name: 'option',
|
||||
description: 'A sample option',
|
||||
type: 'STRING', // [!code --]
|
||||
type: ApplicationCommandOptionType.String, // [!code ++]
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
##### Common Button Data changes
|
||||
|
||||
```js
|
||||
const { ButtonStyle } = require('discord.js'); // [!code ++]
|
||||
|
||||
const button = {
|
||||
label: 'test',
|
||||
style: 'PRIMARY', // [!code --]
|
||||
style: ButtonStyle.Primary, // [!code ++]
|
||||
customId: '1234',
|
||||
};
|
||||
```
|
||||
|
||||
### Removal of method-based type guards
|
||||
|
||||
#### Channels
|
||||
|
||||
Some channel type guard methods that narrowed to one channel type have been removed. Instead compare the `type` property against a [ChannelType](https://discord-api-types.dev/api/discord-api-types-v10/enum/ChannelType) enum member to narrow channels.
|
||||
|
||||
```js
|
||||
const { ChannelType } = require('discord.js'); // [!code ++]
|
||||
|
||||
channel.isText(); // [!code --]
|
||||
channel.type === ChannelType.GuildText; // [!code ++]
|
||||
|
||||
channel.isVoice(); // [!code --]
|
||||
channel.type === ChannelType.GuildVoice; // [!code ++]
|
||||
|
||||
channel.isDM(); // [!code --]
|
||||
channel.type === ChannelType.DM; // [!code ++]
|
||||
```
|
||||
|
||||
### Builders
|
||||
|
||||
Builders are no longer returned by the API like they were previously. For example you send the API an `EmbedBuilder` but you receive an `Embed` of the same data from the API. This may affect how your code handles received structures such as components. Refer to [message component changes section](#messagecomponent) for more details.
|
||||
|
||||
Added `disableValidators()` and `enableValidators()` as top-level exports which disable or enable validation (enabled by default).
|
||||
|
||||
### Consolidation of `create()` & `edit()` parameters
|
||||
|
||||
Various `create()` and `edit()` methods on managers and objects have had their parameters consolidated. The changes are below:
|
||||
|
||||
- `Guild#edit()` now takes `reason` in the `data` parameter
|
||||
- `GuildChannel#edit()` now takes `reason` in the `data` parameter
|
||||
- `GuildEmoji#edit()` now takes `reason` in the `data` parameter
|
||||
- `Role#edit()` now takes `reason` in the `data` parameter
|
||||
- `Sticker#edit()` now takes `reason` in the `data` parameter
|
||||
- `ThreadChannel#edit()` now takes `reason` in the `data` parameter
|
||||
- `GuildChannelManager#create()` now takes `name` in the `options` parameter
|
||||
- `GuildChannelManager#createWebhook()` (and other text-based channels) now takes `channel` and `name` in the `options` parameter
|
||||
- `GuildChannelManager#edit()` now takes `reason` as a part of `data`
|
||||
- `GuildEmojiManager#edit()` now takes `reason` as a part of `data`
|
||||
- `GuildManager#create()` now takes `name` as a part of `options`
|
||||
- `GuildMemberManager#edit()` now takes `reason` as a part of `data`
|
||||
- `GuildMember#edit()` now takes `reason` as a part of `data`
|
||||
- `GuildStickerManager#edit()` now takes `reason` as a part of `data`
|
||||
- `RoleManager#edit()` now takes `reason` as a part of `options`
|
||||
- `Webhook#edit()` now takes `reason` as a part of `options`
|
||||
- `GuildEmojiManager#create()` now takes `attachment` and `name` as a part of `options`
|
||||
- `GuildStickerManager#create()` now takes `file`, `name`, and `tags` as a part of `options`
|
||||
|
||||
### Activity
|
||||
|
||||
The following properties have been removed as they are not documented by Discord:
|
||||
|
||||
- `Activity#id`
|
||||
- `Activity#platform`
|
||||
- `Activity#sessionId`
|
||||
- `Activity#syncId`
|
||||
|
||||
### Application
|
||||
|
||||
`Application#fetchAssets()` has been removed as it is no longer supported by the API.
|
||||
|
||||
### BitField
|
||||
|
||||
- BitField constituents now have a `BitField` suffix to avoid naming conflicts with the enum names:
|
||||
|
||||
```js
|
||||
new Permissions(); // [!code --]
|
||||
new PermissionsBitField(); // [!code ++]
|
||||
|
||||
new MessageFlags(); // [!code --]
|
||||
new MessageFlagsBitField(); // [!code ++]
|
||||
|
||||
new ThreadMemberFlags(); // [!code --]
|
||||
new ThreadMemberFlagsBitField(); // [!code ++]
|
||||
|
||||
new UserFlags(); // [!code --]
|
||||
new UserFlagsBitField(); // [!code ++]
|
||||
|
||||
new SystemChannelFlags(); // [!code --]
|
||||
new SystemChannelFlagsBitField(); // [!code ++]
|
||||
|
||||
new ApplicationFlags(); // [!code --]
|
||||
new ApplicationFlagsBitField(); // [!code ++]
|
||||
|
||||
new Intents(); // [!code --]
|
||||
new IntentsBitField(); // [!code ++]
|
||||
|
||||
new ActivityFlags(); // [!code --]
|
||||
new ActivityFlagsBitField(); // [!code ++]
|
||||
```
|
||||
|
||||
- `#FLAGS` has been renamed to `#Flags`
|
||||
|
||||
### CDN
|
||||
|
||||
The methods that return CDN URLs have changed. Here is an example on a User:
|
||||
|
||||
```js
|
||||
const url = user.displayAvatarURL({ dynamic: true, format: 'png', size: 1_024 }); // [!code --]
|
||||
const url = user.displayAvatarURL({ extension: 'png', size: 1_024 }); // [!code ++]
|
||||
```
|
||||
|
||||
Dynamic URLs use `ImageURLOptions` and static URLs use `BaseImageURLOptions`. Since dynamic URLs are returned by default, this option has been renamed to `forceStatic` which forces the return of a static URL. Additionally, `format` has been renamed to `extension`.
|
||||
|
||||
### CategoryChannel
|
||||
|
||||
`CategoryChannel#children` is no longer a `Collection` of channels the category contains. It is now a manager (`CategoryChannelChildManager`). This also means `CategoryChannel#createChannel()` has been moved to the `CategoryChannelChildManager`.
|
||||
|
||||
### Channel
|
||||
|
||||
The following type guards have been removed:
|
||||
|
||||
- `Channel#isText()`
|
||||
- `Channel#isVoice()`
|
||||
- `Channel#isDirectory()`
|
||||
- `Channel#isDM()`
|
||||
- `Channel#isGroupDM()`
|
||||
- `Channel#isCategory()`
|
||||
- `Channel#isNews()`
|
||||
|
||||
Refer to [this section](#channels) for more context.
|
||||
|
||||
The base channel class is now `BaseChannel`.
|
||||
|
||||
### Client
|
||||
|
||||
The `restWsBridgeTimeout` client option has been removed.
|
||||
|
||||
### CommandInteractionOptionResolver
|
||||
|
||||
`CommandInteractionOptionResolver#getMember()` no longer has a parameter for `required`. See [this pull request](https://github.com/discordjs/discord.js/pull/7188) for more information.
|
||||
|
||||
### Constants
|
||||
|
||||
- Many constant objects and key arrays are now top-level exports for example:
|
||||
|
||||
```js
|
||||
const { Constants } = require('discord.js'); // [!code --]
|
||||
const { Colors } = Constants; // [!code --]
|
||||
const { Colors } = require('discord.js'); // [!code ++]
|
||||
```
|
||||
|
||||
- The refactored constants structures have `PascalCase` member names as opposed to `SCREAMING_SNAKE_CASE` member names.
|
||||
|
||||
- Many of the exported constants structures have been replaced and renamed:
|
||||
|
||||
```js
|
||||
Opcodes; // [!code --]
|
||||
GatewayOpcodes; // [!code ++]
|
||||
|
||||
WSEvents; // [!code --]
|
||||
GatewayDispatchEvents; // [!code ++]
|
||||
|
||||
WSCodes; // [!code --]
|
||||
GatewayCloseCodes; // [!code ++]
|
||||
|
||||
InviteScopes; // [!code --]
|
||||
OAuth2Scopes; // [!code ++]
|
||||
```
|
||||
|
||||
### Events
|
||||
|
||||
The `message` and `interaction` events are now removed. Use `messageCreate` and `interactionCreate` instead.
|
||||
|
||||
`applicationCommandCreate`, `applicationCommandDelete` and `applicationCommandUpdate` have all been removed. See [this pull request](https://github.com/discordjs/discord.js/pull/6492) for more information.
|
||||
|
||||
The `threadMembersUpdate` event now emits the users who were added, the users who were removed, and the thread respectively.
|
||||
|
||||
### GuildBanManager
|
||||
|
||||
Developers should utilise `deleteMessageSeconds` instead of `days` and `deleteMessageDays`:
|
||||
|
||||
```js
|
||||
<GuildBanManager>.create('123456789', {
|
||||
days: 3 // [!code --]
|
||||
deleteMessageDays: 3 // [!code --]
|
||||
deleteMessageSeconds: 3 * 24 * 60 * 60 // [!code ++]
|
||||
});
|
||||
```
|
||||
|
||||
`deleteMessageDays` (introduced with version 14) and `days` are both deprecated and will be removed in the future.
|
||||
|
||||
### Guild
|
||||
|
||||
`Guild#setRolePositions()` and `Guild#setChannelPositions()` have been removed. Use `RoleManager#setPositions()` and `GuildChannelManager#setPositions()` instead respectively.
|
||||
|
||||
`Guild#maximumPresences` no longer has a default value of 25,000.
|
||||
|
||||
`Guild#me` has been moved to `GuildMemberManager#me`. See [this pull request](https://github.com/discordjs/discord.js/pull/7669) for more information.
|
||||
|
||||
### GuildAuditLogs & GuildAuditLogsEntry
|
||||
|
||||
`GuildAuditLogs.build()` has been removed as it has been deemed defunct. There is no alternative.
|
||||
|
||||
The following properties & methods have been moved to the `GuildAuditLogsEntry` class:
|
||||
|
||||
- `GuildAuditLogs.Targets`
|
||||
- `GuildAuditLogs.actionType()`
|
||||
- `GuildAuditLogs.targetType()`
|
||||
|
||||
### GuildMember
|
||||
|
||||
`GuildMember#pending` is now nullable to account for partial guild members. See [this issue](https://github.com/discordjs/discord.js/issues/6546) for more information.
|
||||
|
||||
### IntegrationApplication
|
||||
|
||||
`IntegrationApplication#summary` has been removed as it is no longer supported by the API.
|
||||
|
||||
### Interaction
|
||||
|
||||
Whenever an interaction is replied to and one fetches the reply, it could possibly give an `APIMessage` if the guild was not cached. However, interaction replies now always return an `InteractionCallbackResponse` with `withResponse` set to `true`.
|
||||
|
||||
The base interaction class is now `BaseInteraction`.
|
||||
|
||||
### Invite
|
||||
|
||||
`Invite#inviter` is now a getter and resolves structures from the cache.
|
||||
|
||||
### MessageAttachment
|
||||
|
||||
`MessageAttachment` has now been renamed to `AttachmentBuilder`. // [!code --]
|
||||
|
||||
```js
|
||||
new MessageAttachment(buffer, 'image.png'); // [!code --]
|
||||
new AttachmentBuilder(buffer, { name: 'image.png' }); // [!code ++]
|
||||
```
|
||||
|
||||
### MessageComponent
|
||||
|
||||
- MessageComponents have been renamed as well. They no longer have the `Message` prefix, and now have a `Builder` suffix:
|
||||
|
||||
```js
|
||||
const button = new MessageButton(); // [!code --]
|
||||
const button = new ButtonBuilder(); // [!code ++]
|
||||
|
||||
const selectMenu = new MessageSelectMenu(); // [!code --]
|
||||
const selectMenu = new StringSelectMenuBuilder(); // [!code ++]
|
||||
|
||||
const actionRow = new MessageActionRow(); // [!code --]
|
||||
const actionRow = new ActionRowBuilder(); // [!code ++]
|
||||
|
||||
const textInput = new TextInputComponent(); // [!code --]
|
||||
const textInput = new TextInputBuilder(); // [!code ++]
|
||||
```
|
||||
|
||||
- Components received from the API are no longer directly mutable. If you wish to mutate a component from the API, use `ComponentBuilder#from`. For example, if you want to make a button mutable:
|
||||
|
||||
```js
|
||||
const editedButton = receivedButton // [!code --]
|
||||
.setDisabled(true); // [!code --]
|
||||
const { ButtonBuilder } = require('discord.js'); // [!code ++]
|
||||
const editedButton = ButtonBuilder.from(receivedButton) // [!code ++]
|
||||
.setDisabled(true); // [!code ++]
|
||||
```
|
||||
|
||||
### MessageManager
|
||||
|
||||
`MessageManager#fetch()`'s second parameter has been removed. The `BaseFetchOptions` the second parameter once was is now merged into the first parameter.
|
||||
|
||||
```js
|
||||
messageManager.fetch('1234567890', { cache: false, force: true }); // [!code --]
|
||||
messageManager.fetch({ message: '1234567890', cache: false, force: true }); // [!code ++]
|
||||
```
|
||||
|
||||
### MessageSelectMenu
|
||||
|
||||
- `MessageSelectMenu` has been renamed to `StringSelectMenuBuilder`
|
||||
- `StringSelectMenuBuilder#addOption()` has been removed. Use `StringSelectMenuBuilder#addOptions()` instead.
|
||||
|
||||
### MessageEmbed
|
||||
|
||||
- `MessageEmbed` has now been renamed to `EmbedBuilder`.
|
||||
- `EmbedBuilder#setAuthor()` now accepts a sole `EmbedAuthorOptions` object.
|
||||
- `EmbedBuilder#setFooter()` now accepts a sole `EmbedFooterOptions` object.
|
||||
- `EmbedBuilder#addField()` has been removed. Use `EmbedBuilder#addFields()` instead.
|
||||
|
||||
```js
|
||||
new MessageEmbed().addField('Inline field title', 'Some value here', true); // [!code --]
|
||||
new EmbedBuilder().addFields([ // [!code ++]
|
||||
{ name: 'one', value: 'one', inline: true }, // [!code ++]
|
||||
{ name: 'two', value: 'two', inline: true }, // [!code ++]
|
||||
+]);
|
||||
```
|
||||
|
||||
### Modal
|
||||
|
||||
- `Modal` has been renamed as well and now has a `Builder` suffix:
|
||||
|
||||
```js
|
||||
const modal = new Modal(); // [!code --]
|
||||
const modal = new ModalBuilder(); // [!code ++]
|
||||
```
|
||||
|
||||
### PartialTypes
|
||||
|
||||
The `PartialTypes` string array has been removed. Use the `Partials` enum instead.
|
||||
|
||||
In addition to this, there is now a new partial: `Partials.ThreadMember`.
|
||||
|
||||
### Permissions
|
||||
|
||||
Thread permissions `USE_PUBLIC_THREADS` and `USE_PRIVATE_THREADS` have been removed as they are deprecated in the API. Use `CREATE_PUBLIC_THREADS` and `CREATE_PRIVATE_THREADS` respectively.
|
||||
|
||||
`ManageEmojisAndStickers` has been deprecated due to API changes. Its replacement is `ManageGuildExpressions`. See [this pull request](https://github.com/discord/discord-api-docs/pull/6017) for more information.
|
||||
|
||||
### PermissionOverwritesManager
|
||||
|
||||
Overwrites are now keyed by the `PascalCase` permission key rather than the `SCREAMING_SNAKE_CASE` permission key.
|
||||
|
||||
### REST Events
|
||||
|
||||
#### apiRequest
|
||||
|
||||
This REST event has been removed as discord.js now uses [Undici](https://github.com/nodejs/undici) as the underlying request handler. You must now use a [Diagnostics Channel](https://undici.nodejs.org/#/docs/api/DiagnosticsChannel). Here is a simple example:
|
||||
|
||||
```js
|
||||
import diagnosticsChannel from 'node:diagnostics_channel';
|
||||
|
||||
diagnosticsChannel.channel('undici:request:create').subscribe((data) => {
|
||||
// If you use TypeScript, `data` may be casted as
|
||||
// `DiagnosticsChannel.RequestCreateMessage`
|
||||
// from Undici to receive type definitions.
|
||||
const { request } = data;
|
||||
console.log(request.method); // Log the method
|
||||
console.log(request.path); // Log the path
|
||||
console.log(request.headers); // Log the headers
|
||||
console.log(request); // Or just log everything!
|
||||
});
|
||||
```
|
||||
|
||||
You can find further examples at the [Undici Diagnostics Channel documentation](https://undici.nodejs.org/#/docs/api/DiagnosticsChannel).
|
||||
|
||||
#### apiResponse
|
||||
|
||||
This REST event has been renamed to `response` and moved to `Client#rest`:
|
||||
|
||||
```js
|
||||
client.on('apiResponse', ...); // [!code --]
|
||||
client.rest.on('response', ...); // [!code ++]
|
||||
```
|
||||
|
||||
#### invalidRequestWarning
|
||||
|
||||
This REST event has been moved to `Client#rest`:
|
||||
|
||||
```js
|
||||
client.on('invalidRequestWarning', ...); // [!code --]
|
||||
client.rest.on('invalidRequestWarning', ...); // [!code ++]
|
||||
```
|
||||
|
||||
#### rateLimit
|
||||
|
||||
This REST event has been renamed to `rateLimited` and moved to `Client#rest`:
|
||||
|
||||
```js
|
||||
client.on('rateLimit', ...); // [!code --]
|
||||
client.rest.on('rateLimited', ...); // [!code ++]
|
||||
```
|
||||
|
||||
### RoleManager
|
||||
|
||||
`Role.comparePositions()` has been removed. Use `RoleManager#comparePositions()` instead.
|
||||
|
||||
### Sticker
|
||||
|
||||
`Sticker#tags` is now a nullable string (`string | null`). Previously, it was a nullable array of strings (`string[] | null`). See [this pull request](https://github.com/discordjs/discord.js/pull/8010) for more information.
|
||||
|
||||
### ThreadChannel
|
||||
|
||||
The `MAX` helper used in `ThreadAutoArchiveDuration` has been removed. Discord has since allowed any guild to use any auto archive time which makes this helper redundant.
|
||||
|
||||
### ThreadMemberManager
|
||||
|
||||
`ThreadMemberManager#fetch()`'s second parameter has been removed. The `BaseFetchOptions` the second parameter once was is now merged into the first parameter. In addition, the boolean helper to specify `cache` has been removed.
|
||||
|
||||
Usage is now as follows:
|
||||
|
||||
```js
|
||||
// The second parameter is merged into the first parameter.
|
||||
threadMemberManager.fetch('1234567890', { cache: false, force: true }); // [!code --]
|
||||
threadMemberManager.fetch({ member: '1234567890', cache: false, force: true }); // [!code ++]
|
||||
|
||||
// The lone boolean has been removed. One must be explicit here.
|
||||
threadMemberManager.fetch(false); // [!code --]
|
||||
threadMemberManager.fetch({ cache: false }); // [!code ++]
|
||||
```
|
||||
|
||||
### Util
|
||||
|
||||
`Util.removeMentions()` has been removed. To control mentions, you should use `allowedMentions` on `BaseMessageOptions` instead.
|
||||
|
||||
`Util.splitMessage()` has been removed. This utility method is something the developer themselves should do.
|
||||
|
||||
`Util.resolveAutoArchiveMaxLimit()` has been removed. Discord has since allowed any guild to use any auto archive time which makes this method redundant.
|
||||
|
||||
Other functions in `Util` have been moved to top-level exports so you can directly import them from `discord.js`.
|
||||
|
||||
```js
|
||||
import { Util } from 'discord.js'; // [!code --]
|
||||
Util.escapeMarkdown(message); // [!code --]
|
||||
import { escapeMarkdown } from 'discord.js'; // [!code ++]
|
||||
escapeMarkdown(message); // [!code ++]
|
||||
```
|
||||
|
||||
### `.deleted` Field(s) have been removed
|
||||
|
||||
You can no longer use the `deleted` property to check if a structure was deleted. See [this issue](https://github.com/discordjs/discord.js/issues/7091) for more information.
|
||||
|
||||
### VoiceChannel
|
||||
|
||||
`VoiceChannel#editable` has been removed. You should use `GuildChannel#manageable` instead.
|
||||
|
||||
### VoiceRegion
|
||||
|
||||
`VoiceRegion#vip` has been removed as it is no longer part of the API.
|
||||
|
||||
### Webhook
|
||||
|
||||
`Webhook#fetchMessage()`'s second parameter no longer allows a boolean to be passed. The `cache` option in `WebhookFetchMessageOptions` should be used instead.
|
||||
|
||||
## Features
|
||||
|
||||
### ApplicationCommand
|
||||
|
||||
NFSW commands are supported.
|
||||
|
||||
### Attachment
|
||||
|
||||
Added support for voice message metadata fields.
|
||||
|
||||
### AutocompleteInteraction
|
||||
|
||||
`AutocompleteInteraction#commandGuildId` has been added which is the id of the guild the invoked application command is registered to.
|
||||
|
||||
### BaseChannel
|
||||
|
||||
Added support for `BaseChannel#flags`.
|
||||
|
||||
Store channels have been removed as they are no longer part of the API.
|
||||
|
||||
`BaseChannel#url` has been added which is a link to a channel, just like in the client.
|
||||
|
||||
Additionally, new typeguards have been added:
|
||||
|
||||
- `BaseChannel#isDMBased()`
|
||||
- `BaseChannel#isTextBased()`
|
||||
- `BaseChannel#isVoiceBased()`
|
||||
|
||||
### BaseInteraction
|
||||
|
||||
Added `BaseInteraction#isRepliable()` to check whether a given interaction can be replied to.
|
||||
|
||||
### ClientApplication
|
||||
|
||||
Added support for role connection metadata.
|
||||
|
||||
### Collection
|
||||
|
||||
- Added `Collection#merge()` and `Collection#combineEntries()`.
|
||||
- New type: `ReadonlyCollection` which indicates an immutable `Collection`.
|
||||
|
||||
### Collector
|
||||
|
||||
A new `ignore` event has been added which is emitted whenever an element is not collected by the collector.
|
||||
|
||||
Component collector options now use the `ComponentType` enum values:
|
||||
|
||||
```js
|
||||
const { ComponentType } = require('discord.js'); // [!code ++]
|
||||
|
||||
const collector = interaction.channel.createMessageComponentCollector({
|
||||
filter: collectorFilter,
|
||||
componentType: 'BUTTON', // [!code --]
|
||||
componentType: ComponentType.Button, // [!code ++]
|
||||
time: 20_000,
|
||||
});
|
||||
```
|
||||
|
||||
### CommandInteraction
|
||||
|
||||
`CommandInteraction#commandGuildId` has been added which is the id of the guild the invoked application command is registered to.
|
||||
|
||||
### CommandInteractionOptionResolver
|
||||
|
||||
`CommandInteractionOptionResolver#getChannel()` now has a third parameter which narrows the channel type.
|
||||
|
||||
### Events
|
||||
|
||||
Added support for `guildAuditLogEntryCreate` event.
|
||||
|
||||
### ForumChannel
|
||||
|
||||
Added support for forum channels.
|
||||
|
||||
Added support for `ForumChannel#defaultForumLayout`.
|
||||
|
||||
### Guild
|
||||
|
||||
Added `Guild#setMFALevel()` which sets the guild's MFA level.
|
||||
|
||||
Added `Guild#maxVideoChannelUsers` which indicates the maximum number of video channel users.
|
||||
|
||||
Added `Guild#maxStageVideoChannelUsers` which indicates the maximum number of video channel users for stage channels.
|
||||
|
||||
Added `Guild#disableInvites()` which disables the guild's invites.
|
||||
|
||||
Added support for the `after` parameter in `Guild#fetchAuditLogs()`.
|
||||
|
||||
### GuildChannelManager
|
||||
|
||||
`videoQualityMode` may be used whilst creating a channel to initially set the camera video quality mode.
|
||||
|
||||
### GuildEmojiManager
|
||||
|
||||
Added `GuildEmojiManager#delete()` and `GuildEmojiManager#edit()` for managing existing guild emojis.
|
||||
|
||||
### GuildForumThreadManager
|
||||
|
||||
Added `GuildForumThreadManager` as manager for threads in forum channels.
|
||||
|
||||
### GuildMember
|
||||
|
||||
Added support for `GuildMember#flags`.
|
||||
|
||||
### GuildMembersChunk
|
||||
|
||||
This object now supports the `GuildMembersChunk#notFound` property.
|
||||
|
||||
### GuildMemberManager
|
||||
|
||||
Added `GuildMemberManager#fetchMe()` to fetch the client user in the guild.
|
||||
|
||||
Added `GuildMemberManager#addRole()` and `GuildMemberManager#removeRole()`. These methods allow a single addition or removal of a role respectively to a guild member, even if uncached.
|
||||
|
||||
### GuildTextThreadManager
|
||||
|
||||
Added `GuildTextThreadManager` as manager for threads in text channels and announcement channels.
|
||||
|
||||
### Message
|
||||
|
||||
`Message#position` has been added as an approximate position in a thread.
|
||||
|
||||
Added support for role subscription data.
|
||||
|
||||
### MessageReaction
|
||||
|
||||
Added `MessageReaction#react()` to make the client user react with the reaction the class belongs to.
|
||||
|
||||
### Role
|
||||
|
||||
Added support for role subscriptions.
|
||||
|
||||
Added support for `Role#tags#guildConnections`.
|
||||
|
||||
### StageChannel
|
||||
|
||||
Stage channels now allow messages to be sent in them, much like voice channels.
|
||||
|
||||
### Sticker
|
||||
|
||||
Added support for GIF stickers.
|
||||
|
||||
### ThreadMemberManager
|
||||
|
||||
The new `withMember` options returns the associated guild member with the thread member.
|
||||
|
||||
When fetching multiple thread members alongside `withMember`, paginated results will be returned. The `after` and `limit` option are supported in this scenario.
|
||||
|
||||
### Webhook
|
||||
|
||||
Added `Webhook#applicationId`.
|
||||
|
||||
Added the `threadName` property in `Webhook#send()` options which allows a webhook to create a post in a forum channel.
|
||||
|
||||
### WebSocketManager
|
||||
|
||||
discord.js uses `@discordjs/ws` internally
|
||||
107
apps/guide/content/docs/legacy/additional-info/collections.mdx
Normal file
107
apps/guide/content/docs/legacy/additional-info/collections.mdx
Normal file
@@ -0,0 +1,107 @@
|
||||
---
|
||||
title: Collections
|
||||
---
|
||||
|
||||
discord.js comes with a utility class known as `Collection`.
|
||||
It extends JavaScript's native `Map` class, so it has all the `Map` features and more!
|
||||
|
||||
<Callout type="warn">
|
||||
If you're not familiar with `Map`, read [MDN's page on
|
||||
it](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) before continuing. You
|
||||
should be familiar with `Array`
|
||||
[methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) as well. We will
|
||||
also use some ES6 features, so read up [here](./es6-syntax) if you do not know what they are.
|
||||
</Callout>
|
||||
|
||||
A `Map` allows for an association between unique keys and their values.
|
||||
For example, how can you transform every value or filter the entries in a `Map` easily?
|
||||
This is the point of the `Collection` class!
|
||||
|
||||
## Array-like Methods
|
||||
|
||||
Many of the methods on `Collection` correspond to their namesake in `Array`. One of them is `find`:
|
||||
|
||||
```js
|
||||
// Assume we have an array of users and a collection of the same users.
|
||||
array.find((u) => u.discriminator === '1000'); // [!code word:find]
|
||||
collection.find((u) => u.discriminator === '1000');
|
||||
```
|
||||
|
||||
The interface of the callback function is very similar between the two.
|
||||
For arrays, callbacks usually pass the parameters `(value, index, array)`, where `value` is the value iterated to,
|
||||
`index` is the current index, and `array` is the array. For collections, you would have `(value, key, collection)`.
|
||||
Here, `value` is the same, but `key` is the key of the value, and `collection` is the collection itself instead.
|
||||
|
||||
Methods that follow this philosophy of staying close to the `Array` interface are as follows:
|
||||
|
||||
- `find`
|
||||
- `filter` - Note that this returns a `Collection` rather than an `Array`.
|
||||
- `map` - Yet this returns an `Array` of values instead of a `Collection`!
|
||||
- `every`
|
||||
- `some`
|
||||
- `reduce`
|
||||
- `concat`
|
||||
- `sort`
|
||||
|
||||
## Converting to Array
|
||||
|
||||
Since `Collection` extends `Map`, it is an [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols), and can be converted to an `Array` through either `Array.from()` or spread syntax (`...collection`).
|
||||
|
||||
```js
|
||||
// For values.
|
||||
Array.from(collection.values());
|
||||
[...collection.values()];
|
||||
|
||||
// For keys.
|
||||
Array.from(collection.keys());
|
||||
[...collection.keys()];
|
||||
|
||||
// For [key, value] pairs.
|
||||
Array.from(collection);
|
||||
[...collection];
|
||||
```
|
||||
|
||||
<Callout>
|
||||
Many people convert Collections to Arrays way too much!
|
||||
|
||||
This can lead to unnecessary and confusing code. Before you use `Array.from()` or similar, ask yourself if whatever you are trying to do can't be done with the given `Map` or `Collection` methods or with a for-of loop. Not being familiar with a new data structure should not mean you default to transforming it into the other.
|
||||
|
||||
There is usually a reason, why a `Map` or `Collection` is used. Most structures in Discord can be identified with an `id`, which lends itself well to `key -> value` associations like in `Map`s.
|
||||
|
||||
</Callout>
|
||||
|
||||
## Extra Utilities
|
||||
|
||||
Some methods are not from `Array` and are instead entirely new to standard JavaScript.
|
||||
|
||||
```js
|
||||
// A random value.
|
||||
collection.random();
|
||||
|
||||
// The first value.
|
||||
collection.first();
|
||||
|
||||
// The first 5 values.
|
||||
collection.first(5);
|
||||
|
||||
// Similar to `first`, but from the end.
|
||||
collection.last();
|
||||
collection.last(2);
|
||||
|
||||
// Removes anything that meets the condition from the collection.
|
||||
// Sort of like `filter`, but in-place.
|
||||
collection.sweep((user) => user.username === 'Bob');
|
||||
```
|
||||
|
||||
A more complicated method is `partition`, which splits a single Collection into two new Collections based on the provided function.
|
||||
You can think of it as two `filter`s, but done at the same time (and because of that much more performant):
|
||||
|
||||
```js
|
||||
// `bots` is a Collection of users where their `bot` property was true.
|
||||
// `humans` is a Collection where the property was false instead!
|
||||
const [bots, humans] = collection.partition((u) => u.bot); // [!code word:partition]
|
||||
|
||||
// Both return true.
|
||||
bots.every((b) => b.bot);
|
||||
humans.every((h) => !h.bot); // note the "not" ! operator
|
||||
```
|
||||
243
apps/guide/content/docs/legacy/additional-info/es6-syntax.mdx
Normal file
243
apps/guide/content/docs/legacy/additional-info/es6-syntax.mdx
Normal file
@@ -0,0 +1,243 @@
|
||||
---
|
||||
title: ES6 Syntax
|
||||
---
|
||||
|
||||
If you've used JavaScript for only a (relatively) small amount of time or don't have much experience with it, you might not be aware of what ES6 is and what beneficial features it includes. Since this is a guide primarily for Discord bots, we'll be using some discord.js code as an example of what you might have versus what you could do to benefit from ES6.
|
||||
|
||||
Here's the startup code we'll be using:
|
||||
|
||||
```js title="index.js" lineNumbers
|
||||
const { Client, Events, GatewayIntentBits } = require('discord.js'); // [!code word:const]
|
||||
const config = require('./config.json');
|
||||
|
||||
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
|
||||
|
||||
// [!code word:=>]
|
||||
client.once(Events.ClientReady, () => {
|
||||
console.log('Ready!');
|
||||
});
|
||||
|
||||
client.on(Events.InteractionCreate, (interaction) => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
|
||||
const { commandName } = interaction;
|
||||
|
||||
if (commandName === 'ping') {
|
||||
interaction.reply('Pong.');
|
||||
} else if (commandName === 'beep') {
|
||||
interaction.reply('Boop.');
|
||||
} else if (commandName === 'server') {
|
||||
interaction.reply('Guild name: ' + interaction.guild.name + '\nTotal members: ' + interaction.guild.memberCount);
|
||||
} else if (commandName === 'user-info') {
|
||||
interaction.reply('Your username: ' + interaction.user.username + '\nYour ID: ' + interaction.user.id);
|
||||
}
|
||||
});
|
||||
|
||||
client.login(config.token);
|
||||
```
|
||||
|
||||
If you haven't noticed, this piece of code is already using a bit of ES6 here! The `const` keyword and arrow function declaration (`() => ...`) is ES6 syntax, and we recommend using it whenever possible.
|
||||
|
||||
As for the code above, there are a few places where things can be done better. Let's look at them.
|
||||
|
||||
## Template literals
|
||||
|
||||
If you check the code above, it's currently doing things like `'Guild name: ' + interaction.guild.name` and `'Your username: ' + interaction.user.username`, which is perfectly valid. It is a bit hard to read, though, and it's not too fun to constantly type out. Fortunately, there's a better alternative.
|
||||
|
||||
```js title="index.js" lineNumbers=19
|
||||
} else if (commandName === 'server') {
|
||||
interaction.reply('Guild name: ' + interaction.guild.name + '\nTotal members: ' + interaction.guild.memberCount); // [!code --]
|
||||
interaction.reply(`Guild name: ${interaction.guild.name}\nTotal members: ${interaction.guild.memberCount}`); // [!code ++]
|
||||
}
|
||||
else if (commandName === 'user-info') {
|
||||
interaction.reply('Your username: ' + interaction.user.username + '\nYour ID: ' + interaction.user.id); // [!code --]
|
||||
interaction.reply(`Your username: ${interaction.user.username}\nYour ID: ${interaction.user.id}`); // [!code ++]
|
||||
}
|
||||
```
|
||||
|
||||
Easier to read and write! The best of both worlds.
|
||||
|
||||
### Template literals vs string concatenation
|
||||
|
||||
If you've used other programming languages, you might be familiar with the term "string interpolation". Template literals would be JavaScript's implementation of string interpolation. If you're familiar with the heredoc syntax, it's very much like that; it allows for string interpolation, as well as multiline strings.
|
||||
|
||||
The example below won't go too much into detail about it, but if you're interested in reading more, you can [read about them on MDN](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Template_literals).
|
||||
|
||||
```js
|
||||
const username = 'Sanctuary';
|
||||
const password = 'pleasedonthackme';
|
||||
|
||||
function letsPretendThisDoesSomething() {
|
||||
return 'Yay for sample data.';
|
||||
}
|
||||
|
||||
console.log('Your username is: **' + username + '**.'); // [!code --:2]
|
||||
console.log('Your password is: **' + password + '**.');
|
||||
console.log(`Your username is: **${username}**.`); // [!code ++:2]
|
||||
console.log(`Your password is: **${password}**.`);
|
||||
|
||||
console.log('1 + 1 = ' + (1 + 1)); // [!code --]
|
||||
console.log(`1 + 1 = ${1 + 1}`); // [!code ++]
|
||||
|
||||
console.log("And here's a function call: " + letsPretendThisDoesSomething()); // [!code --]
|
||||
console.log(`And here's a function call: ${letsPretendThisDoesSomething()}`); // [!code ++]
|
||||
|
||||
console.log('Putting strings on new lines\n' + 'can be a bit painful\n' + 'with string concatenation.'); // [!code --]
|
||||
// [!code ++:5]
|
||||
console.log(`
|
||||
Putting strings on new lines
|
||||
is a breeze
|
||||
with template literals!
|
||||
`);
|
||||
```
|
||||
|
||||
<Callout>
|
||||
As you will notice, template literals will also render the white space inside them, including the indentation! There
|
||||
are ways around this, which we will discuss in another section.
|
||||
</Callout>
|
||||
|
||||
You can see how it makes things easier and more readable. In some cases, it can even make your code shorter! This one is something you'll want to take advantage of as much as possible.
|
||||
|
||||
## Arrow functions
|
||||
|
||||
Arrow functions are shorthand for regular functions, with the addition that they use a lexical `this` context inside of their own. If you don't know what the `this` keyword is referring to, don't worry about it; you'll learn more about it as you advance.
|
||||
|
||||
Here are some examples of ways you can benefit from arrow functions over regular functions:
|
||||
|
||||
```js
|
||||
// [!code --:3]
|
||||
client.once(Events.ClientReady, function () {
|
||||
console.log('Ready!');
|
||||
});
|
||||
client.once(Events.ClientReady, () => console.log('Ready!')); // [!code ++]
|
||||
|
||||
// [!code --:3]
|
||||
client.on(Events.TypingStart, function (typing) {
|
||||
console.log(typing.user.tag + ' started typing in #' + typing.channel.name);
|
||||
});
|
||||
client.on(Events.TypingStart, (typing) => console.log(`${typing.user.tag} started typing in #${typing.channel.name}`)); // [!code ++]
|
||||
|
||||
// [!code --:3]
|
||||
client.on(Events.MessageCreate, function (message) {
|
||||
console.log(message.author.tag + ' sent: ' + message.content);
|
||||
});
|
||||
client.on(Events.MessageCreate, (message) => console.log(`${message.author.tag} sent: ${message.content}`)); // [!code ++]
|
||||
|
||||
// [!code --:3]
|
||||
var doubleAge = function (age) {
|
||||
return 'Your age doubled is: ' + age * 2;
|
||||
};
|
||||
const doubleAge = (age) => `Your age doubled is: ${age * 2}`; // [!code ++]
|
||||
|
||||
// [!code --:4]
|
||||
var collectorFilter = function (m) {
|
||||
return m.content === 'I agree' && !m.author.bot;
|
||||
};
|
||||
var collector = message.createMessageCollector({ filter: collectorFilter, time: 15_000 });
|
||||
const collectorFilter = (m) => m.content === 'I agree' && !m.author.bot; // [!code ++:2]
|
||||
const collector = message.createMessageCollector({ filter: collectorFilter, time: 15_000 });
|
||||
```
|
||||
|
||||
There are a few important things you should note here:
|
||||
|
||||
- The parentheses around function parameters are optional when you have only one parameter but are required otherwise. If you feel like this will confuse you, it may be a good idea to use parentheses.
|
||||
- You can cleanly put what you need on a single line without curly braces.
|
||||
- Omitting curly braces will make arrow functions use **implicit return**, but only if you have a single-line expression. The `doubleAge` and `filter` variables are a good example of this.
|
||||
- Unlike the `function someFunc() { ... }` declaration, arrow functions cannot be used to create functions with such syntax. You can create a variable and give it an anonymous arrow function as the value, though (as seen with the `doubleAge` and `filter` variables).
|
||||
|
||||
We won't be covering the lexical `this` scope with arrow functions in here, but you can Google around if you're still curious. Again, if you aren't sure what `this` is or when you need it, reading about lexical `this` first may only confuse you.
|
||||
|
||||
## Destructuring
|
||||
|
||||
Destructuring is an easy way to extract items from an object or array. If you've never seen the syntax for it before, it can be a bit confusing, but it's straightforward to understand once explained!
|
||||
|
||||
### Object destructuring
|
||||
|
||||
Here's a common example where object destructuring would come in handy:
|
||||
|
||||
```js
|
||||
const config = require('./config.json');
|
||||
const prefix = config.prefix;
|
||||
const token = config.token;
|
||||
```
|
||||
|
||||
This code is a bit verbose and not the most fun to write out each time. Object destructuring simplifies this, making it easier to both read and write. Take a look:
|
||||
|
||||
```js
|
||||
const config = require('./config.json'); // [!code --:3]
|
||||
const prefix = config.prefix;
|
||||
const token = config.token;
|
||||
const { prefix, token } = require('./config.json'); // [!code ++]
|
||||
```
|
||||
|
||||
Object destructuring takes those properties from the object and stores them in variables. If the property doesn't exist, it'll still create a variable but with the value of `undefined`. So instead of using `config.token` in your `client.login()` method, you'd simply use `token`. And since destructuring creates a variable for each item, you don't even need that `const prefix = config.prefix` line. Pretty cool!
|
||||
|
||||
Additionally, you could do this for your commands:
|
||||
|
||||
```js
|
||||
client.on(Events.InteractionCreate, (interaction) => {
|
||||
const { commandName } = interaction;
|
||||
|
||||
if (commandName === 'ping') {
|
||||
// ping command here...
|
||||
} else if (commandName === 'beep') {
|
||||
// beep command here...
|
||||
}
|
||||
// other commands here...
|
||||
});
|
||||
```
|
||||
|
||||
The code is shorter and looks cleaner, but it shouldn't be necessary if you follow along with the [command handler](../app-creation/handling-commands) part of the guide.
|
||||
|
||||
You can also rename variables when destructuring, if necessary. A good example is when you're extracting a property with a name already being used or conflicts with a reserved keyword. The syntax is as follows:
|
||||
|
||||
```js
|
||||
// `default` is a reserved keyword
|
||||
const { default: defaultValue } = someObject;
|
||||
|
||||
console.log(defaultValue);
|
||||
// 'Some default value here'
|
||||
```
|
||||
|
||||
### Array destructuring
|
||||
|
||||
Array destructuring syntax is very similar to object destructuring, except that you use brackets instead of curly braces. In addition, since you're using it on an array, you destructure the items in the same order the array is. Without array destructuring, this is how you'd extract items from an array:
|
||||
|
||||
```js
|
||||
// assuming we're in a `profile` command and have an `args` variable
|
||||
const name = args[0];
|
||||
const age = args[1];
|
||||
const location = args[2];
|
||||
```
|
||||
|
||||
Like the first example with object destructuring, this is a bit verbose and not fun to write out. Array destructuring eases this pain.
|
||||
|
||||
```js
|
||||
const name = args[0]; // [!code --:3]
|
||||
const age = args[1];
|
||||
const location = args[2];
|
||||
const [name, age, location] = args; // [!code ++]
|
||||
```
|
||||
|
||||
A single line of code that makes things much cleaner! In some cases, you may not even need all the array's items (e.g., when using `string.match(regex)`). Array destructuring still allows you to operate in the same sense.
|
||||
|
||||
```js
|
||||
const [, username, id] = message.content.match(someRegex);
|
||||
```
|
||||
|
||||
In this snippet, we use a comma without providing a name for the item in the array we don't need. You can also give it a placeholder name (`_match` or similar) if you prefer, of course; it's entirely preference at that point.
|
||||
|
||||
<Callout>
|
||||
The underscore `_` prefix is a convention for unused variables. Some lint rules will error or warn if you define
|
||||
identifiers without using them in your code but ignore identifiers starting with `_`.
|
||||
</Callout>
|
||||
|
||||
## var, let, and const
|
||||
|
||||
Since there are many, many articles out there that can explain this part more in-depth, we'll only be giving you a TL;DR and an article link if you choose to read more about it.
|
||||
|
||||
1. The `var` keyword is what was (and can still be) used in JavaScript before `let` and `const` came to surface. There are many issues with `var`, though, such as it being function-scoped, hoisting related issues, and allowing redeclaration.
|
||||
2. The `let` keyword is essentially the new `var`; it addresses many of the issues `var` has, but its most significant factor would be that it's block-scoped and disallows redeclaration (_not_ reassignment).
|
||||
3. The `const` keyword is for giving variables a constant value that is unable to be reassigned. `const`, like `let`, is also block-scoped.
|
||||
|
||||
The general rule of thumb recommended by this guide is to use `const` wherever possible, `let` otherwise, and avoid using `var`. Here's a [helpful article](https://madhatted.com/2016/1/25/let-it-be) if you want to read more about this subject.
|
||||
BIN
apps/guide/content/docs/legacy/additional-info/images/search.png
Normal file
BIN
apps/guide/content/docs/legacy/additional-info/images/search.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.6 KiB |
BIN
apps/guide/content/docs/legacy/additional-info/images/send.png
Normal file
BIN
apps/guide/content/docs/legacy/additional-info/images/send.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
3
apps/guide/content/docs/legacy/additional-info/meta.json
Normal file
3
apps/guide/content/docs/legacy/additional-info/meta.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"pages": ["async-await", "collections", "es6-syntax", "notation", "rest-api"]
|
||||
}
|
||||
61
apps/guide/content/docs/legacy/additional-info/notation.mdx
Normal file
61
apps/guide/content/docs/legacy/additional-info/notation.mdx
Normal file
@@ -0,0 +1,61 @@
|
||||
---
|
||||
title: Understanding Notation
|
||||
---
|
||||
|
||||
Throughout the discord.js docs and when asking for help on the official server, you will run into many different kinds of notations. To help you understand the texts that you read, we will be going over some standard notations.
|
||||
|
||||
<Callout>
|
||||
Always keep in mind that notation is not always rigorous. There will be typos, misunderstandings, or contexts that
|
||||
will cause notation to differ from the usual meanings.
|
||||
</Callout>
|
||||
|
||||
## Classes
|
||||
|
||||
Some common notations refer to a class or the properties, methods, or events of a class. There are many variations on these notations, and they are very flexible depending on the person, so use your best judgment when reading them.
|
||||
|
||||
The notation `<Class>` means an instance of the `Class` class. For example, a snippet like `<BaseInteraction>.reply('Hello')` is asking you to replace `<BaseInteraction>` with some value that is an instance of `BaseInteraction`, e.g. `interaction.reply('Hello')`. It could also just be a placeholder, e.g., `<id>` would mean a placeholder for some ID.
|
||||
|
||||
The notation `Class#foo` can refer to the `foo` property, method, or event of the `Class` class. Which one the writer meant needs to be determined from context. For example:
|
||||
|
||||
- `BaseInteraction#user` means that you should refer to the `user` property on a `BaseInteraction`.
|
||||
- `TextChannel#send` means that you should refer to the `send` method on a `TextChannel`.
|
||||
- `Client#interactionCreate` means that you should refer to the `interactionCreate` event on a `Client`.
|
||||
|
||||
<Callout>
|
||||
Remember that this notation is not valid JavaScript; it is a shorthand to refer to a specific piece of code.
|
||||
</Callout>
|
||||
|
||||
Sometimes, the notation is extended, which can help you determine which one the writer meant. For example, `TextChannel#send(options)` is definitely a method of `TextChannel`, since it uses function notation. `Client#event:messageCreate` is an event since it says it is an event.
|
||||
|
||||
The vital thing to take away from this notation is that the `#` symbol signifies that the property, method, or event can only be accessed through an instance of the class. Unfortunately, many abuse this notation, e.g., `<Message>#send` or `Util#resolveColor`. `<Message>` is already an instance, so this makes no sense, and `resolveColor` is a static method–you should write it as `Util.resolveColor`. Always refer back to the docs if you are confused.
|
||||
|
||||
As an example, the documentation's search feature uses this notation.
|
||||
|
||||

|
||||
|
||||
Notice the use of the `.` operator for the static method, `Role.comparePositions` and the `#` notation for the method, `Role#comparePositionsTo`.
|
||||
|
||||
## Types
|
||||
|
||||
In the discord.js docs, there are type signatures everywhere, such as in properties, parameters, or return values. If you do not come from a statically typed language, you may not know what specific notations mean.
|
||||
|
||||
The symbol `*` means any type. For example, methods that return `*` mean that they can return anything, and a parameter of type `*` can be anything.
|
||||
|
||||
The symbol `?` means that the type is nullable. You can see it before or after the type (e.g. `?T` or `T?`). This symbol means that the value can be of the type `T` or `null`. An example is `GuildMember#nickname`; its type is `?string` since a member may or may not have a nickname.
|
||||
|
||||
The expression `T[]` means an array of `T`. You can sometimes see multiple brackets `[]`, indicating that the array is multi-dimensional, e.g., `string[][]`.
|
||||
|
||||
The expression `...T` signifies a rest parameter of type `T`. This means that the function can take any amount of arguments, and all those arguments must be of the type `T`.
|
||||
|
||||
The operator `|`, which can read as "or", creates a union type, e.g. `A|B|C`. Simply, it means the value can be of any one of the types given.
|
||||
|
||||
The angle brackets `<>` are used for generic types or parameterized types, signifying a type that uses another type(s). The notation looks like `A<B>` where `A` is the type and `B` is a type parameter. If this is hard to follow, it is enough to keep in mind that whenever you see `A<B>`, you can think of an `A` containing `B`. Examples:
|
||||
|
||||
- `Array<String>` means an array of strings.
|
||||
- `Promise<User>` means a `Promise` that contains a `User`.
|
||||
- `Array<Promise<User|GuildMember>>` would be an array of `Promise`s, each containing a `User` or a `GuildMember`.
|
||||
- `Collection<Snowflake, User>` would be a `Collection`, containing key-value pairs where the keys are `Snowflake`s, and the values are `User`s.
|
||||
|
||||

|
||||
|
||||
In this piece of the docs, you can see two type signatures, `string`, `MessagePayload`, or `MessageOptions`, and `Promise<(Message|Array<Message>)>`. The meaning of the word "or" here is the same as `|`.
|
||||
176
apps/guide/content/docs/legacy/additional-info/rest-api.mdx
Normal file
176
apps/guide/content/docs/legacy/additional-info/rest-api.mdx
Normal file
@@ -0,0 +1,176 @@
|
||||
---
|
||||
title: REST APIs
|
||||
---
|
||||
|
||||
REST APIs are extremely popular on the web and allow you to freely grab a site's data if it has an available API over an HTTP connection.
|
||||
|
||||
## Making HTTP requests with Node
|
||||
|
||||
In these examples, we will be using [undici](https://www.npmjs.com/package/undici), an excellent library for making HTTP requests.
|
||||
|
||||
To install undici, run the following command:
|
||||
|
||||
```sh tab="npm"
|
||||
npm i install undici
|
||||
```
|
||||
|
||||
```sh tab="yarn"
|
||||
yarn add undici
|
||||
```
|
||||
|
||||
```sh tab="pnpm"
|
||||
pnpm add undici
|
||||
```
|
||||
|
||||
## Skeleton code
|
||||
|
||||
To start off, you will be using the following skeleton code. Since both the commands you will be adding in this section require an interaction with external APIs, you will defer the reply, so your application responds with a "thinking..." state. You can then edit the reply once you got the data you need:
|
||||
|
||||
```js title="rest-examples.js" lineNumbers
|
||||
const { Client, EmbedBuilder, Events, GatewayIntentBits } = require('discord.js');
|
||||
|
||||
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
|
||||
|
||||
client.once(Events.ClientReady, (readyClient) => {
|
||||
console.log(`Ready! Logged in as ${readyClient.user.tag}`);
|
||||
});
|
||||
|
||||
client.on(Events.InteractionCreate, async (interaction) => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
|
||||
const { commandName } = interaction;
|
||||
await interaction.deferReply();
|
||||
// ...
|
||||
});
|
||||
|
||||
client.login('your-token-goes-here');
|
||||
```
|
||||
|
||||
<Callout>
|
||||
We're taking advantage of [destructuring](./es6-syntax#destructuring) in this tutorial to maintain readability.
|
||||
</Callout>
|
||||
|
||||
## Using undici
|
||||
|
||||
Undici is a Promise-based HTTP/1.1 client, written from scratch for Node.js. If you aren't already familiar with Promises, you should read up on them [here](./async-await).
|
||||
|
||||
In this tutorial, you will be making a bot with two API-based commands using the [random.cat](https://aws.random.cat) and [Urban Dictionary](https://www.urbandictionary.com) APIs.
|
||||
|
||||
On top of your file, import the library function you will be using:
|
||||
|
||||
```js
|
||||
const { request } = require('undici');
|
||||
```
|
||||
|
||||
### Random Cat
|
||||
|
||||
<Callout title="No more cats :(" type="error">
|
||||
Unfortunately, the `aws.random.cat` API doesn't work anymore. We will keep the example as-is until we find a better
|
||||
showcase!
|
||||
</Callout>
|
||||
|
||||
Random cat's API is available at [https://aws.random.cat/meow](https://aws.random.cat/meow) and returns a [JSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON) response. To actually fetch data from the API, you're going to do the following:
|
||||
|
||||
```js
|
||||
const catResult = await request('https://aws.random.cat/meow');
|
||||
const { file } = await catResult.body.json();
|
||||
```
|
||||
|
||||
If you just add this code, it will seem like nothing happens. What you do not see, is that you are launching a request to the random.cat server, which responds some JSON data. The helper function parses the response data to a JavaScript object you can work with. The object will have a `file` property with the value of a link to a random cat image.
|
||||
|
||||
Next, you will implement this approach into an application command:
|
||||
|
||||
```js
|
||||
client.on(Events.InteractionCreate, async (interaction) => {
|
||||
// ...
|
||||
if (commandName === 'cat') {
|
||||
const catResult = await request('https://aws.random.cat/meow');
|
||||
const { file } = await catResult.body.json();
|
||||
interaction.editReply({ files: [file] });
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
So, here's what's happening in this code:
|
||||
|
||||
1. Your application sends a `GET` request to random.cat.
|
||||
2. random.cat sees the request and gets a random file url from their database.
|
||||
3. random.cat then sends that file's URL as a JSON object in a stringified form that contains a link to the image.
|
||||
4. undici receives the response and you parse the body to a JSON object.
|
||||
5. Your application then attaches the image and sends it in Discord.
|
||||
|
||||
### Urban Dictionary
|
||||
|
||||
Urban Dictionary's API is available at [https://api.urbandictionary.com/v0/define](https://api.urbandictionary.com/v0/define), accepts a `term` parameter, and returns a JSON response.
|
||||
|
||||
The following code will fetch data from this api:
|
||||
|
||||
```js
|
||||
// ...
|
||||
client.on(Events.InteractionCreate, async (interaction) => {
|
||||
// ...
|
||||
if (commandName === 'urban') {
|
||||
const term = interaction.options.getString('term');
|
||||
const query = new URLSearchParams({ term }); // [!code word:URLSearchParams]
|
||||
|
||||
const dictResult = await request(`https://api.urbandictionary.com/v0/define?${query}`);
|
||||
const { list } = await dictResult.body.json();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Here, you are using JavaScript's native [URLSearchParams class](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) to create a [query string](https://en.wikipedia.org/wiki/Query_string) for the URL so that the Urban Dictionary server can parse it and know what you want to look up.
|
||||
|
||||
If you were to do `/urban hello world`, then the URL would become https://api.urbandictionary.com/v0/define?term=hello%20world since the string `"hello world"` is encoded.
|
||||
|
||||
You can get the respective properties from the returned JSON. If you were to view it in your browser, it usually looks like a bunch of mumbo jumbo. If it doesn't, great! If it does, then you should get a JSON formatter/viewer. If you're using Chrome, [JSON Formatter](https://chrome.google.com/webstore/detail/json-formatter/bcjindcccaagfpapjjmafapmmgkkhgoa) is one of the more popular extensions. If you're not using Chrome, search for "JSON formatter/viewer <your browser>" and get one.
|
||||
|
||||
Now, if you look at the JSON, you can see that it has a `list` property, which is an array of objects containing various definitions for the term (maximum 10). Something you always want to do when making API-based commands is to handle the case when no results are available. So, if you throw a random term in there (e.g. `njaksdcas`) and then look at the response the `list` array should be empty. Now you are ready to start writing!
|
||||
|
||||
As explained above, you'll want to check if the API returned any answers for your query, and send back the definition if that's the case:
|
||||
|
||||
```js
|
||||
if (commandName === 'urban') {
|
||||
// ...
|
||||
if (!list.length) {
|
||||
return interaction.editReply(`No results found for **${term}**.`);
|
||||
}
|
||||
|
||||
interaction.editReply(`**${term}**: ${list[0].definition}`);
|
||||
}
|
||||
```
|
||||
|
||||
Here, you are only getting the first object from the array of objects called `list` and grabbing its `definition` property.
|
||||
|
||||
If you've followed the tutorial, you should have something like this:
|
||||
|
||||
Now, you can make it an [embed](../popular-topics/embeds) for easier formatting.
|
||||
|
||||
You can define the following helper function at the top of your file. In the code below, you can use this function to truncate the returned data and make sure the embed doesn't error, because field values exceed 1024 characters.
|
||||
|
||||
```js
|
||||
const trim = (str, max) => (str.length > max ? `${str.slice(0, max - 3)}...` : str);
|
||||
```
|
||||
|
||||
And here is how you can build the embed from the API data:
|
||||
|
||||
```js
|
||||
const [answer] = list;
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setColor(0xefff00)
|
||||
.setTitle(answer.word)
|
||||
.setURL(answer.permalink)
|
||||
.addFields(
|
||||
{ name: 'Definition', value: trim(answer.definition, 1_024) },
|
||||
{ name: 'Example', value: trim(answer.example, 1_024) },
|
||||
{ name: 'Rating', value: `${answer.thumbs_up} thumbs up. ${answer.thumbs_down} thumbs down.` },
|
||||
);
|
||||
|
||||
interaction.editReply({ embeds: [embed] });
|
||||
```
|
||||
|
||||
<Callout>
|
||||
Check out display components for a newer approach to message formatting! You can read the [display
|
||||
components](../popular-topics/display-components) section of this guide to learn more about using them!
|
||||
</Callout>
|
||||
Reference in New Issue
Block a user