From 3ac685d6ba7d35cf84832422d6d6333ba54a51a6 Mon Sep 17 00:00:00 2001 From: Avraj Date: Tue, 26 Aug 2025 11:53:49 +0300 Subject: [PATCH] docs: add tabs setup for js support --- .../02-setup-commandkit.mdx | 41 ++- .../02-commands/01-chat-input-commands.mdx | 48 ++- .../02-command-options-autocomplete.mdx | 183 +++++++---- .../02-commands/03-context-menu-commands.mdx | 157 ++++++--- .../guide/02-commands/04-message-commands.mdx | 195 +++++++++--- .../guide/02-commands/05-command-metadata.mdx | 199 +++++++++--- .../guide/02-commands/06-after-function.mdx | 139 +++++--- .../docs/guide/02-commands/08-middlewares.mdx | 299 ++++++++++++++---- .../guide/03-events/01-discordjs-events.mdx | 247 +++++++++++---- .../guide/04-jsx-components/01-using-jsx.mdx | 134 +++++--- .../01-setup-commandkit-manually.mdx | 167 +++++++--- 11 files changed, 1349 insertions(+), 460 deletions(-) diff --git a/apps/website/docs/guide/01-getting-started/02-setup-commandkit.mdx b/apps/website/docs/guide/01-getting-started/02-setup-commandkit.mdx index e5289cda..c55bd35a 100644 --- a/apps/website/docs/guide/01-getting-started/02-setup-commandkit.mdx +++ b/apps/website/docs/guide/01-getting-started/02-setup-commandkit.mdx @@ -3,6 +3,9 @@ title: Setup CommandKit description: Setup a new CommandKit project using the create-commandkit CLI --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + :::info - CommandKit requires at least [Node.js](https://nodejs.org/) v24 @@ -52,18 +55,38 @@ The `src/app.ts` file is the main entry point for your application. This file default exports the discord.js client instance which CommandKit loads at runtime. -```ts title="src/app.ts" -import { Client } from 'discord.js'; + + + ```ts title="src/app.ts" + import { Client } from 'discord.js'; -const client = new Client({ - intents: ['Guilds', 'GuildMessages', 'MessageContent'], -}); + const client = new Client({ + intents: ['Guilds', 'GuildMessages', 'MessageContent'], + }); -// Optional: Setting up the token manually -client.token = process.env.MY_BOT_TOKEN; + // Optional: Setting up the token manually + client.token = process.env.MY_BOT_TOKEN; -export default client; -``` + export default client; + ``` + + + + ```js title="src/app.js" + import { Client } from 'discord.js'; + + const client = new Client({ + intents: ['Guilds', 'GuildMessages', 'MessageContent'], + }); + + // Optional: Setting up the token manually + client.token = process.env.MY_BOT_TOKEN; + + export default client; + ``` + + + Notice how there's no `client.login()` in this file. This is because CommandKit will automatically handle the login process for you when diff --git a/apps/website/docs/guide/02-commands/01-chat-input-commands.mdx b/apps/website/docs/guide/02-commands/01-chat-input-commands.mdx index 7f4bb3ae..e601d1bc 100644 --- a/apps/website/docs/guide/02-commands/01-chat-input-commands.mdx +++ b/apps/website/docs/guide/02-commands/01-chat-input-commands.mdx @@ -2,6 +2,9 @@ title: Chat Input Commands --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + Chat input commands, more commonly known as 'Slash Commands', are a way for users on Discord to perform actions using your bot. @@ -14,18 +17,43 @@ To create a new chat input command, create a new file in the will create a basic ping command which will respond with "Pong!" when executed. -```ts title="src/app/commands/ping.ts" -import type { CommandData, ChatInputCommand } from 'commandkit'; + + + ```ts title="src/app/commands/ping.ts" + import type { CommandData, ChatInputCommand } from 'commandkit'; + + export const command: CommandData = { + name: 'ping', + description: 'Replies with Pong!', + }; + + export const chatInput: ChatInputCommand = async (ctx) => { + await ctx.interaction.reply('Pong!'); + }; + ``` + + + + ```js title="src/app/commands/ping.js" + /** + * @typedef {import('commandkit').CommandData} CommandData + * @typedef {import('commandkit').ChatInputCommand} ChatInputCommand + */ + + /** @type {CommandData} */ + export const command = { + name: 'ping', + description: 'Replies with Pong!', + }; -export const command: CommandData = { - name: 'ping', - description: 'Replies with Pong!', -}; + /** @type {ChatInputCommand} */ + export const chatInput = async (ctx) => { + await ctx.interaction.reply('Pong!'); + }; + ``` -export const chatInput: ChatInputCommand = async (ctx) => { - await ctx.interaction.reply('Pong!'); -}; -``` + + ## Exports explained diff --git a/apps/website/docs/guide/02-commands/02-command-options-autocomplete.mdx b/apps/website/docs/guide/02-commands/02-command-options-autocomplete.mdx index 259f1689..364e70ee 100644 --- a/apps/website/docs/guide/02-commands/02-command-options-autocomplete.mdx +++ b/apps/website/docs/guide/02-commands/02-command-options-autocomplete.mdx @@ -2,6 +2,9 @@ title: Options Autocomplete --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + :::warning This feature is only available for @@ -24,61 +27,131 @@ and managing your own `interactionCreate` event listener. To begin, export the `autocomplete` function from the command where you have an option with `autocomplete` set to `true`. -```ts title="src/app/commands/pet.ts" -import type { CommandData, AutocompleteCommand } from 'commandkit'; -import { ApplicationCommandOptionType } from 'discord.js'; - -export const command: CommandData = { - name: 'pet', - description: 'Check in one of your pets.', - options: [ - { - name: 'name', - description: 'The name of your pet', - type: ApplicationCommandOptionType.String, - autocomplete: true, - required: true, - }, - ], -}; - -const pets = Array.from({ length: 20 }, (_, i) => ({ - name: `Pet ${i + 1}`, // e.g. Pet 1, Pet 2, Pet 3, etc. - value: `petId_${i}`, -})); - -export const autocomplete: AutocompleteCommand = async ({ interaction }) => { - try { - // Get the input value of your autocomplete option - const input = interaction.options.getString('name', false); - if (!input) { - interaction.respond(pets); - return; - } - - const filteredPets = pets.filter((pet) => - pet.name.toLowerCase().includes(input.toLowerCase()), - ); - - // Respond with what you think the user may trying to find - interaction.respond(filteredPets); - } catch (error) { - console.error('Autocomplete error', error); - } -}; - -export const chatInput: ChatInputCommand = async ({ interaction }) => { - const chosenPetId = interaction.options.getString('name', true); - const chosenPet = pets.find((pet) => pet.value === chosenPetId); - - if (!chosenPet) { - interaction.reply('Pet not found.'); - return; - } - - interaction.reply(`You chose ${chosenPet.name}`); -}; -``` + + + ```ts title="src/app/commands/pet.ts" + import type { CommandData, AutocompleteCommand, ChatInputCommand } from 'commandkit'; + import { ApplicationCommandOptionType } from 'discord.js'; + + export const command: CommandData = { + name: 'pet', + description: 'Check in one of your pets.', + options: [ + { + name: 'name', + description: 'The name of your pet', + type: ApplicationCommandOptionType.String, + autocomplete: true, + required: true, + }, + ], + }; + + const pets = Array.from({ length: 20 }, (_, i) => ({ + name: `Pet ${i + 1}`, // e.g. Pet 1, Pet 2, Pet 3, etc. + value: `petId_${i}`, + })); + + export const autocomplete: AutocompleteCommand = async ({ interaction }) => { + try { + // Get the input value of your autocomplete option + const input = interaction.options.getString('name', false); + if (!input) { + interaction.respond(pets); + return; + } + + const filteredPets = pets.filter((pet) => + pet.name.toLowerCase().includes(input.toLowerCase()), + ); + + // Respond with what you think the user may trying to find + interaction.respond(filteredPets); + } catch (error) { + console.error('Autocomplete error', error); + } + }; + + export const chatInput: ChatInputCommand = async ({ interaction }) => { + const chosenPetId = interaction.options.getString('name', true); + const chosenPet = pets.find((pet) => pet.value === chosenPetId); + + if (!chosenPet) { + interaction.reply('Pet not found.'); + return; + } + + interaction.reply(`You chose ${chosenPet.name}`); + }; + ``` + + + + ```js title="src/app/commands/pet.js" + /** + * @typedef {import('commandkit').CommandData} CommandData + * @typedef {import('commandkit').AutocompleteCommand} AutocompleteCommand + * @typedef {import('commandkit').ChatInputCommand} ChatInputCommand + */ + import { ApplicationCommandOptionType } from 'discord.js'; + + /** @type {CommandData} */ + export const command = { + name: 'pet', + description: 'Check in one of your pets.', + options: [ + { + name: 'name', + description: 'The name of your pet', + type: ApplicationCommandOptionType.String, + autocomplete: true, + required: true, + }, + ], + }; + + const pets = Array.from({ length: 20 }, (_, i) => ({ + name: `Pet ${i + 1}`, // e.g. Pet 1, Pet 2, Pet 3, etc. + value: `petId_${i}`, + })); + + /** @type {AutocompleteCommand} */ + export const autocomplete = async ({ interaction }) => { + try { + // Get the input value of your autocomplete option + const input = interaction.options.getString('name', false); + if (!input) { + interaction.respond(pets); + return; + } + + const filteredPets = pets.filter((pet) => + pet.name.toLowerCase().includes(input.toLowerCase()), + ); + + // Respond with what you think the user may trying to find + interaction.respond(filteredPets); + } catch (error) { + console.error('Autocomplete error', error); + } + }; + + /** @type {ChatInputCommand} */ + export const chatInput = async ({ interaction }) => { + const chosenPetId = interaction.options.getString('name', true); + const chosenPet = pets.find((pet) => pet.value === chosenPetId); + + if (!chosenPet) { + interaction.reply('Pet not found.'); + return; + } + + interaction.reply(`You chose ${chosenPet.name}`); + }; + ``` + + + :::warning diff --git a/apps/website/docs/guide/02-commands/03-context-menu-commands.mdx b/apps/website/docs/guide/02-commands/03-context-menu-commands.mdx index 9194aad0..6b86396f 100644 --- a/apps/website/docs/guide/02-commands/03-context-menu-commands.mdx +++ b/apps/website/docs/guide/02-commands/03-context-menu-commands.mdx @@ -2,6 +2,9 @@ title: Context Menu Commands --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + Context menu commands allows users on Discord to run commands by either referencing a message or a user. Context menu commands can be grouped to either 'Message' or 'User' context menu commands. @@ -19,28 +22,61 @@ understanding the nature of these context menu commands easier. ## Message context menu command -```ts title="src/app/commands/report-message.ts" -import type { CommandData, MessageContextMenuCommand } from 'commandkit'; -import { MessageFlags } from 'discord.js'; - -export const command: CommandData = { - name: 'report-message', - description: 'Report a message to moderators.', -}; - -export const messageContextMenu: MessageContextMenuCommand = async ({ - interaction, -}) => { - const content = interaction.targetMessage.content; - - // you could add your message reporting logic here - - await interaction.reply({ - content: `You have reported the following message: ${content}`, - flags: MessageFlags.Ephemeral, - }); -}; -``` + + + ```ts title="src/app/commands/report-message.ts" + import type { CommandData, MessageContextMenuCommand } from 'commandkit'; + import { MessageFlags } from 'discord.js'; + + export const command: CommandData = { + name: 'report-message', + description: 'Report a message to moderators.', + }; + + export const messageContextMenu: MessageContextMenuCommand = async ({ + interaction, + }) => { + const content = interaction.targetMessage.content; + + // you could add your message reporting logic here + + await interaction.reply({ + content: `You have reported the following message: ${content}`, + flags: MessageFlags.Ephemeral, + }); + }; + ``` + + + + ```js title="src/app/commands/report-message.js" + /** + * @typedef {import('commandkit').CommandData} CommandData + * @typedef {import('commandkit').MessageContextMenuCommand} MessageContextMenuCommand + */ + import { MessageFlags } from 'discord.js'; + + /** @type {CommandData} */ + export const command = { + name: 'report-message', + description: 'Report a message to moderators.', + }; + + /** @type {MessageContextMenuCommand} */ + export const messageContextMenu = async ({ interaction }) => { + const content = interaction.targetMessage.content; + + // you could add your message reporting logic here + + await interaction.reply({ + content: `You have reported the following message: ${content}`, + flags: MessageFlags.Ephemeral, + }); + }; + ``` + + + By just exporting the `messageContextMenu` function from your command file, CommandKit will properly update your command type before @@ -53,25 +89,58 @@ handlers. The logic for registering and handling user context menu commands is very similar to message context menu commands. -```ts title="src/app/commands/report-user.ts" -import type { CommandData, UserContextMenuCommand } from 'commandkit'; -import { MessageFlags } from 'discord.js'; - -export const command: CommandData = { - name: 'report-user', - description: 'Report a user to moderators.', -}; - -export const userContextMenu: UserContextMenuCommand = async ({ - interaction, -}) => { - const userId = interaction.targetUser.id; - - // you could add your user reporting logic here - - await interaction.reply({ - content: `You have reported a user with the ID: ${userId}`, - flags: MessageFlags.Ephemeral, - }); -}; -``` + + + ```ts title="src/app/commands/report-user.ts" + import type { CommandData, UserContextMenuCommand } from 'commandkit'; + import { MessageFlags } from 'discord.js'; + + export const command: CommandData = { + name: 'report-user', + description: 'Report a user to moderators.', + }; + + export const userContextMenu: UserContextMenuCommand = async ({ + interaction, + }) => { + const userId = interaction.targetUser.id; + + // you could add your user reporting logic here + + await interaction.reply({ + content: `You have reported a user with the ID: ${userId}`, + flags: MessageFlags.Ephemeral, + }); + }; + ``` + + + + ```js title="src/app/commands/report-user.js" + /** + * @typedef {import('commandkit').CommandData} CommandData + * @typedef {import('commandkit').UserContextMenuCommand} UserContextMenuCommand + */ + import { MessageFlags } from 'discord.js'; + + /** @type {CommandData} */ + export const command = { + name: 'report-user', + description: 'Report a user to moderators.', + }; + + /** @type {UserContextMenuCommand} */ + export const userContextMenu = async ({ interaction }) => { + const userId = interaction.targetUser.id; + + // you could add your user reporting logic here + + await interaction.reply({ + content: `You have reported a user with the ID: ${userId}`, + flags: MessageFlags.Ephemeral, + }); + }; + ``` + + + diff --git a/apps/website/docs/guide/02-commands/04-message-commands.mdx b/apps/website/docs/guide/02-commands/04-message-commands.mdx index b3c6b233..3a47f9c6 100644 --- a/apps/website/docs/guide/02-commands/04-message-commands.mdx +++ b/apps/website/docs/guide/02-commands/04-message-commands.mdx @@ -2,6 +2,9 @@ title: Message Commands --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + Message commands, which are generally considered 'Legacy', are a way to run commands on Discord bots using regular messages. Before the introduction of @@ -25,17 +28,41 @@ Message commands, like all the other command types, live in your message command, just export the `message` function from your command file. -```ts title="src/app/commands/ping.ts" -import type { CommandData, MessageCommand } from 'commandkit'; - -export const command: CommandData = { - name: 'ping', -}; - -export const message: MessageCommand = async (ctx) => { - await ctx.message.reply('Pong!'); -}; -``` + + + ```ts title="src/app/commands/ping.ts" + import type { CommandData, MessageCommand } from 'commandkit'; + + export const command: CommandData = { + name: 'ping', + }; + + export const message: MessageCommand = async (ctx) => { + await ctx.message.reply('Pong!'); + }; + ``` + + + + ```js title="src/app/commands/ping.js" + /** + * @typedef {import('commandkit').CommandData} CommandData + * @typedef {import('commandkit').MessageCommand} MessageCommand + */ + + /** @type {CommandData} */ + export const command = { + name: 'ping', + }; + + /** @type {MessageCommand} */ + export const message = async (ctx) => { + await ctx.message.reply('Pong!'); + }; + ``` + + + ## Message command options (arguments) @@ -45,17 +72,41 @@ idea of message command options will be different compared to getting parsed data, you'll essentially be dealing with string 'arguments'. -```ts title="src/app/commands/ping.ts" {8} -import type { CommandData, MessageCommand } from 'commandkit'; - -export const command: CommandData = { - name: 'ping', -}; - -export const message: MessageCommand = async (ctx) => { - const args = ctx.args(); // string[] -}; -``` + + + ```ts title="src/app/commands/ping.ts" {8} + import type { CommandData, MessageCommand } from 'commandkit'; + + export const command: CommandData = { + name: 'ping', + }; + + export const message: MessageCommand = async (ctx) => { + const args = ctx.args(); // string[] + }; + ``` + + + + ```js title="src/app/commands/ping.js" {13} + /** + * @typedef {import('commandkit').CommandData} CommandData + * @typedef {import('commandkit').MessageCommand} MessageCommand + */ + + /** @type {CommandData} */ + export const command = { + name: 'ping', + }; + + /** @type {MessageCommand} */ + export const message = async (ctx) => { + const args = ctx.args(); // string[] + }; + ``` + + + With the above command as an example, if a user on Discord runs `!ping john jack jane`, the value of `args` will equal @@ -66,13 +117,28 @@ With the above command as an example, if a user on Discord runs The simplest way to set a custom prefix is using the `setPrefixResolver` method on the `commandkit` instance: -```ts title="src/app.ts" -import { commandkit } from 'commandkit'; + + + ```ts title="src/app.ts" + import { commandkit } from 'commandkit'; -commandkit.setPrefixResolver(async (message) => { - return '?'; -}); -``` + commandkit.setPrefixResolver(async (message) => { + return '?'; + }); + ``` + + + + ```js title="src/app.js" + import { commandkit } from 'commandkit'; + + commandkit.setPrefixResolver(async (message) => { + return '?'; + }); + ``` + + + This sets a global prefix of `?` for all message commands. Your bot will now respond to commands like `?help` or `?ping`. @@ -82,7 +148,7 @@ will now respond to commands like `?help` or `?ping`. You can return an array of strings to support multiple prefixes simultaneously: -```ts +```js return ['?', '!', '>']; ``` @@ -93,27 +159,56 @@ return ['?', '!', '>']; For a more dynamic approach, you might want different prefixes for different guilds. Here's how to implement that: -```ts title="src/app.ts" -import { commandkit } from 'commandkit'; -import { database } from '../database'; // This is a mock database - -commandkit.setPrefixResolver(async (message) => { - if (!message.guildId) { - return '!'; // Fallback to '!' if command is used in a DM - } - - const guildSettings = await database.findUnique({ - where: { - guildId: message.guildId, - }, - select: { - prefix: true, - }, - }); - - return guildSettings?.prefix ?? '!'; // Fallback to '!' if no prefix is found -}); -``` + + + ```ts title="src/app.ts" + import { commandkit } from 'commandkit'; + import { database } from '../database'; // This is a mock database + + commandkit.setPrefixResolver(async (message) => { + if (!message.guildId) { + return '!'; // Fallback to '!' if command is used in a DM + } + + const guildSettings = await database.findUnique({ + where: { + guildId: message.guildId, + }, + select: { + prefix: true, + }, + }); + + return guildSettings?.prefix ?? '!'; // Fallback to '!' if no prefix is found + }); + ``` + + + + ```js title="src/app.js" + import { commandkit } from 'commandkit'; + import { database } from '../database'; // This is a mock database + + commandkit.setPrefixResolver(async (message) => { + if (!message.guildId) { + return '!'; // Fallback to '!' if command is used in a DM + } + + const guildSettings = await database.findUnique({ + where: { + guildId: message.guildId, + }, + select: { + prefix: true, + }, + }); + + return guildSettings?.prefix ?? '!'; // Fallback to '!' if no prefix is found + }); + ``` + + + :::warning diff --git a/apps/website/docs/guide/02-commands/05-command-metadata.mdx b/apps/website/docs/guide/02-commands/05-command-metadata.mdx index b941c5db..5caa02f8 100644 --- a/apps/website/docs/guide/02-commands/05-command-metadata.mdx +++ b/apps/website/docs/guide/02-commands/05-command-metadata.mdx @@ -2,23 +2,51 @@ title: Command Metadata --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + Command metadata is a way to add additional information to your commands that CommandKit will handle. To get started, you can export a `metadata` object from your command: -```ts title="src/app/commands/ping.ts" {8-10} -import type { CommandData, CommandMetadata } from 'commandkit'; - -export const command: CommandData = { - name: 'ping', - description: 'Replies with Pong!', -}; - -export const metadata: CommandMetadata = { - // Add your metadata here -}; -``` + + + ```ts title="src/app/commands/ping.ts" {8-10} + import type { CommandData, CommandMetadata } from 'commandkit'; + + export const command: CommandData = { + name: 'ping', + description: 'Replies with Pong!', + }; + + export const metadata: CommandMetadata = { + // Add your metadata here + }; + ``` + + + + ```js title="src/app/commands/ping.js" {13-15} + /** + * @typedef {import('commandkit').CommandData} CommandData + * @typedef {import('commandkit').CommandMetadata} CommandMetadata + */ + + /** @type {CommandData} */ + export const command = { + name: 'ping', + description: 'Replies with Pong!', + }; + + /** @type {CommandMetadata} */ + export const metadata = { + // Add your metadata here + }; + ``` + + + ## Metadata properties @@ -27,12 +55,25 @@ export const metadata: CommandMetadata = { This is a string, or array of user permission strings that will be required by the person executing the command. -```ts title="src/app/commands/ping.ts" -export const metadata: CommandMetadata = { - // If the user does not have the Administrator permission, CommandKit will let them know - userPermissions: 'Administrator', -}; -``` + + + ```ts title="src/app/commands/ping.ts" + export const metadata: CommandMetadata = { + // If the user does not have the Administrator permission, CommandKit will let them know + userPermissions: 'Administrator', + }; + ``` + + + ```js title="src/app/commands/ping.js" + /** @type {CommandMetadata} */ + export const metadata = { + // If the user does not have the Administrator permission, CommandKit will let them know + userPermissions: 'Administrator', + }; + ``` + + ### `botPermissions` @@ -41,23 +82,48 @@ required by your bot to execute the command. This is useful for commands where your bot needs to have certain permissions in a guild e.g. moderation commands. -```ts title="src/app/commands/ping.ts" -export const metadata: CommandMetadata = { - // If the bot does not have these permissions, CommandKit will let them know - botPermissions: ['KickMembers', 'BanMembers'], -}; -``` + + + ```ts title="src/app/commands/ping.ts" + export const metadata: CommandMetadata = { + // If the bot does not have these permissions, CommandKit will let them know + botPermissions: ['KickMembers', 'BanMembers'], + }; + ``` + + + ```js title="src/app/commands/ping.js" + /** @type {CommandMetadata} */ + export const metadata = { + // If the bot does not have these permissions, CommandKit will let them know + botPermissions: ['KickMembers', 'BanMembers'], + }; + ``` + + ### `guilds` This is an array of guild IDs that the command will be registered in, or be available to be executed (message commands). -```ts title="src/app/commands/ping.ts" -export const metadata: CommandMetadata = { - guilds: ['1234567890', '1234567891'], -}; -``` + + + ```ts title="src/app/commands/ping.ts" + export const metadata: CommandMetadata = { + guilds: ['1234567890', '1234567891'], + }; + ``` + + + ```js title="src/app/commands/ping.js" + /** @type {CommandMetadata} */ + export const metadata = { + guilds: ['1234567890', '1234567891'], + }; + ``` + + ### `aliases` @@ -70,11 +136,23 @@ This only works for [message commands](./04-message-commands.mdx). ::: -```ts title="src/app/commands/ping.ts" -export const metadata: CommandMetadata = { - aliases: ['p', 'pong'], -}; -``` + + + ```ts title="src/app/commands/ping.ts" + export const metadata: CommandMetadata = { + aliases: ['p', 'pong'], + }; + ``` + + + ```js title="src/app/commands/ping.js" + /** @type {CommandMetadata} */ + export const metadata = { + aliases: ['p', 'pong'], + }; + ``` + + ## Generated metadata @@ -82,17 +160,42 @@ If you'd like to generate metadata dynamically, you can export a `generateMetadata` function from your command file that should return a `CommandMetadata` object. -```ts title="src/app/commands/ping.ts" -import type { CommandMetadataFunction } from 'commandkit'; - -export const generateMetadata: CommandMetadataFunction = async () => { - // Dynamically determine the metadata for the command - - return { - userPermissions: 'Administrator', - botPermissions: ['KickMembers', 'BanMembers'], - guilds: ['1234567890', '1234567891'], - aliases: ['p', 'pong'], - }; -}; -``` + + + ```ts title="src/app/commands/ping.ts" + import type { CommandMetadataFunction } from 'commandkit'; + + export const generateMetadata: CommandMetadataFunction = async () => { + // Dynamically determine the metadata for the command + + return { + userPermissions: 'Administrator', + botPermissions: ['KickMembers', 'BanMembers'], + guilds: ['1234567890', '1234567891'], + aliases: ['p', 'pong'], + }; + }; + ``` + + + + ```js title="src/app/commands/ping.js" + /** + * @typedef {import('commandkit').CommandMetadataFunction} CommandMetadataFunction + */ + + /** @type {CommandMetadataFunction} */ + export const generateMetadata = async () => { + // Dynamically determine the metadata for the command + + return { + userPermissions: 'Administrator', + botPermissions: ['KickMembers', 'BanMembers'], + guilds: ['1234567890', '1234567891'], + aliases: ['p', 'pong'], + }; + }; + ``` + + + diff --git a/apps/website/docs/guide/02-commands/06-after-function.mdx b/apps/website/docs/guide/02-commands/06-after-function.mdx index 210a872d..7cbff4da 100644 --- a/apps/website/docs/guide/02-commands/06-after-function.mdx +++ b/apps/website/docs/guide/02-commands/06-after-function.mdx @@ -2,6 +2,9 @@ title: after Function --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + :::warning UNSTABLE The `after()` function is currently marked as unstable and may change @@ -16,28 +19,60 @@ cleanup tasks. ## Usage -```ts title="src/app/commands/ping.ts" -import { - type CommandData, - type ChatInputCommand, - unstable_after as after, -} from 'commandkit'; - -export const command: CommandData = {}; - -export const chatInput: ChatInputCommand = async (ctx) => { - after(() => { - // This code will be executed after the command has been executed - // Perform any cleanup here - console.log('Command has been executed'); - }); - - await ctx.interaction.reply({ - content: 'Hello World', - ephemeral: true, - }); -}; -``` + + + ```ts title="src/app/commands/ping.ts" + import { + type CommandData, + type ChatInputCommand, + unstable_after as after, + } from 'commandkit'; + + export const command: CommandData = {}; + + export const chatInput: ChatInputCommand = async (ctx) => { + after(() => { + // This code will be executed after the command has been executed + // Perform any cleanup here + console.log('Command has been executed'); + }); + + await ctx.interaction.reply({ + content: 'Hello World', + ephemeral: true, + }); + }; + ``` + + + + ```js title="src/app/commands/ping.js" + /** + * @typedef {import('commandkit').CommandData} CommandData + * @typedef {import('commandkit').ChatInputCommand} ChatInputCommand + */ + import { unstable_after as after } from 'commandkit'; + + /** @type {CommandData} */ + export const command = {}; + + /** @type {ChatInputCommand} */ + export const chatInput = async (ctx) => { + after(() => { + // This code will be executed after the command has been executed + // Perform any cleanup here + console.log('Command has been executed'); + }); + + await ctx.interaction.reply({ + content: 'Hello World', + ephemeral: true, + }); + }; + ``` + + + :::info @@ -51,19 +86,47 @@ the command execution was successful or not. You can cancel the after function by calling the `cancelAfter` function with the ID of the after function. -```ts title="src/app/commands/ping.ts" -import { - unstable_after as after, - unstable_cancelAfter as cancelAfter, -} from 'commandkit'; - -export const chatInput: ChatInputCommand = async (ctx) => { - const id = after(() => { - console.log('This will run after the command has finished executing.'); - }); - - if (something) { - cancelAfter(id); - } -}; -``` + + + ```ts title="src/app/commands/ping.ts" + import { + unstable_after as after, + unstable_cancelAfter as cancelAfter, + } from 'commandkit'; + + export const chatInput: ChatInputCommand = async (ctx) => { + const id = after(() => { + console.log('This will run after the command has finished executing.'); + }); + + if (something) { + cancelAfter(id); + } + }; + ``` + + + + ```js title="src/app/commands/ping.js" + /** + * @typedef {import('commandkit').ChatInputCommand} ChatInputCommand + */ + import { + unstable_after as after, + unstable_cancelAfter as cancelAfter, + } from 'commandkit'; + + /** @type {ChatInputCommand} */ + export const chatInput = async (ctx) => { + const id = after(() => { + console.log('This will run after the command has finished executing.'); + }); + + if (something) { + cancelAfter(id); + } + }; + ``` + + + diff --git a/apps/website/docs/guide/02-commands/08-middlewares.mdx b/apps/website/docs/guide/02-commands/08-middlewares.mdx index c67bbe3a..0a7f8d33 100644 --- a/apps/website/docs/guide/02-commands/08-middlewares.mdx +++ b/apps/website/docs/guide/02-commands/08-middlewares.mdx @@ -2,6 +2,9 @@ title: Middlewares --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + Middlewares in CommandKit allow you to execute code before and after command execution. This is incredibly powerful for implementing features like logging, authentication, permission checks, or any other @@ -16,41 +19,101 @@ All middleware files follow the same export pattern. You can export `beforeExecute` and `afterExecute` functions that will run at their respective times during command execution. -```ts title="src/app/commands/+middleware.ts" -import { MiddlewareContext } from 'commandkit'; + + + ```ts title="src/app/commands/+middleware.ts" + import { MiddlewareContext } from 'commandkit'; + + export function beforeExecute(ctx: MiddlewareContext) { + // This function will be executed before the command is executed + console.log(`User ${ctx.interaction.user.id} is about to execute a command`); + } -export function beforeExecute(ctx: MiddlewareContext) { - // This function will be executed before the command is executed - console.log(`User ${ctx.interaction.user.id} is about to execute a command`); -} + export function afterExecute(ctx: MiddlewareContext) { + // This function will be executed after the command is executed + console.log( + `Command execution completed for user ${ctx.interaction.user.id}`, + ); + } + ``` + + + + ```js title="src/app/commands/+middleware.js" + /** + * @typedef {import('commandkit').MiddlewareContext} MiddlewareContext + */ + + /** + * Executed before command execution + * @param {MiddlewareContext} ctx - The middleware context + */ + export function beforeExecute(ctx) { + // This function will be executed before the command is executed + console.log(`User ${ctx.interaction.user.id} is about to execute a command`); + } -export function afterExecute(ctx: MiddlewareContext) { - // This function will be executed after the command is executed - console.log( - `Command execution completed for user ${ctx.interaction.user.id}`, - ); -} -``` + /** + * Executed after command execution + * @param {MiddlewareContext} ctx - The middleware context + */ + export function afterExecute(ctx) { + // This function will be executed after the command is executed + console.log( + `Command execution completed for user ${ctx.interaction.user.id}`, + ); + } + ``` + + + ## Stop command execution You can stop a command from running by calling `stopMiddlewares()` in the `beforeExecute` function. -```ts title="src/app/commands/+middleware.ts" -import type { MiddlewareContext } from 'commandkit'; + + + ```ts title="src/app/commands/+middleware.ts" + import type { MiddlewareContext } from 'commandkit'; -export function beforeExecute(ctx: MiddlewareContext) { - if (ctx.interaction.user.id !== '1234567890') { - // Conditionally stop command execution - console.log(`${ctx.commandName} will not be executed!`); - stopMiddlewares(); - } + export function beforeExecute(ctx: MiddlewareContext) { + if (ctx.interaction.user.id !== '1234567890') { + // Conditionally stop command execution + console.log(`${ctx.commandName} will not be executed!`); + stopMiddlewares(); + } - // Continue with command execution - console.log(`${ctx.commandName} will be executed!`); -} -``` + // Continue with command execution + console.log(`${ctx.commandName} will be executed!`); + } + ``` + + + + ```js title="src/app/commands/+middleware.js" + /** + * @typedef {import('commandkit').MiddlewareContext} MiddlewareContext + */ + + /** + * @param {MiddlewareContext} ctx - The middleware context + */ + export function beforeExecute(ctx) { + if (ctx.interaction.user.id !== '1234567890') { + // Conditionally stop command execution + console.log(`${ctx.commandName} will not be executed!`); + stopMiddlewares(); + } + + // Continue with command execution + console.log(`${ctx.commandName} will be executed!`); + } + ``` + + + :::tip @@ -72,26 +135,59 @@ If you still want to use `stopMiddlewares()` in a try/catch block, you can use the `isErrorType` function to check if the error is an instance of the `CommandKitErrorCodes.StopMiddlewares` error. -```ts title="src/app/commands/+middleware.ts" -import type { MiddlewareContext } from 'commandkit'; - -export function beforeExecute(ctx: MiddlewareContext) { - try { - // code that may throw an error - - stopMiddlewares(); // conditionally stop the middleware chain - } catch (error) { - if (isErrorType(error, CommandKitErrorCodes.StopMiddlewares)) { - // if stopMiddlewares() is called in the try block, throw it so CommandKit can stop the middleware chain - throw error; + + + ```ts title="src/app/commands/+middleware.ts" + import type { MiddlewareContext } from 'commandkit'; + + export function beforeExecute(ctx: MiddlewareContext) { + try { + // code that may throw an error + + stopMiddlewares(); // conditionally stop the middleware chain + } catch (error) { + if (isErrorType(error, CommandKitErrorCodes.StopMiddlewares)) { + // if stopMiddlewares() is called in the try block, throw it so CommandKit can stop the middleware chain + throw error; + } + + // this means that the code threw the error, and stopMiddlewares() was not called + // the rest of the middlewares will be executed as normal + console.error(error); + } + } + ``` + + + + ```js title="src/app/commands/+middleware.js" + /** + * @typedef {import('commandkit').MiddlewareContext} MiddlewareContext + */ + + /** + * @param {MiddlewareContext} ctx - The middleware context + */ + export function beforeExecute(ctx) { + try { + // code that may throw an error + + stopMiddlewares(); // conditionally stop the middleware chain + } catch (error) { + if (isErrorType(error, CommandKitErrorCodes.StopMiddlewares)) { + // if stopMiddlewares() is called in the try block, throw it so CommandKit can stop the middleware chain + throw error; + } + + // this means that the code threw the error, and stopMiddlewares() was not called + // the rest of the middlewares will be executed as normal + console.error(error); + } } + ``` - // this means that the code threw the error, and stopMiddlewares() was not called - // the rest of the middlewares will be executed as normal - console.error(error); - } -} -``` + + ::: @@ -103,16 +199,39 @@ Create a `+middleware.ts` file in any commands directory to apply middleware to all commands within that directory and its subdirectories. -```ts title="src/app/commands/(Moderation)/+middleware.ts" -import type { MiddlewareContext } from 'commandkit'; + + + ```ts title="src/app/commands/(Moderation)/+middleware.ts" + import type { MiddlewareContext } from 'commandkit'; + + export function beforeExecute(ctx: MiddlewareContext) { + // This middleware will run before any moderation command + if (!ctx.interaction.member.permissions.has('KickMembers')) { + throw new Error('You need moderation permissions to use this command'); + } + } + ``` + + + + ```js title="src/app/commands/(Moderation)/+middleware.js" + /** + * @typedef {import('commandkit').MiddlewareContext} MiddlewareContext + */ + + /** + * @param {MiddlewareContext} ctx - The middleware context + */ + export function beforeExecute(ctx) { + // This middleware will run before any moderation command + if (!ctx.interaction.member.permissions.has('KickMembers')) { + throw new Error('You need moderation permissions to use this command'); + } + } + ``` -export function beforeExecute(ctx: MiddlewareContext) { - // This middleware will run before any moderation command - if (!ctx.interaction.member.permissions.has('KickMembers')) { - throw new Error('You need moderation permissions to use this command'); - } -} -``` + + ### Command-specific middleware @@ -120,30 +239,74 @@ For command-specific middleware, create a file named `+.middleware.ts` where `` matches your command file name. -```ts title="src/app/commands/+ban.middleware.ts" -import type { MiddlewareContext } from 'commandkit'; + + + ```ts title="src/app/commands/+ban.middleware.ts" + import type { MiddlewareContext } from 'commandkit'; -export function beforeExecute(ctx: MiddlewareContext) { - // This middleware only runs before the ban command - console.log('Ban command is about to be executed'); -} -``` + export function beforeExecute(ctx: MiddlewareContext) { + // This middleware only runs before the ban command + console.log('Ban command is about to be executed'); + } + ``` + + + + ```js title="src/app/commands/+ban.middleware.js" + /** + * @typedef {import('commandkit').MiddlewareContext} MiddlewareContext + */ + + /** + * @param {MiddlewareContext} ctx - The middleware context + */ + export function beforeExecute(ctx) { + // This middleware only runs before the ban command + console.log('Ban command is about to be executed'); + } + ``` + + + ### Global middleware Create a `+global-middleware.ts` file in your commands directory to apply middleware to every command in your entire Discord bot. -```ts title="src/app/commands/+global-middleware.ts" -import type { MiddlewareContext } from 'commandkit'; + + + ```ts title="src/app/commands/+global-middleware.ts" + import type { MiddlewareContext } from 'commandkit'; + + export function beforeExecute(ctx: MiddlewareContext) { + // This middleware runs before ANY command in your bot + console.log( + `Command executed by ${ctx.interaction.user.tag} in ${ctx.interaction.guild?.name || 'DMs'}`, + ); + } + ``` + + + + ```js title="src/app/commands/+global-middleware.js" + /** + * @typedef {import('commandkit').MiddlewareContext} MiddlewareContext + */ + + /** + * @param {MiddlewareContext} ctx - The middleware context + */ + export function beforeExecute(ctx) { + // This middleware runs before ANY command in your bot + console.log( + `Command executed by ${ctx.interaction.user.tag} in ${ctx.interaction.guild?.name || 'DMs'}`, + ); + } + ``` -export function beforeExecute(ctx: MiddlewareContext) { - // This middleware runs before ANY command in your bot - console.log( - `Command executed by ${ctx.interaction.user.tag} in ${ctx.interaction.guild?.name || 'DMs'}`, - ); -} -``` + + :::tip diff --git a/apps/website/docs/guide/03-events/01-discordjs-events.mdx b/apps/website/docs/guide/03-events/01-discordjs-events.mdx index 5fa1f86b..304faea6 100644 --- a/apps/website/docs/guide/03-events/01-discordjs-events.mdx +++ b/apps/website/docs/guide/03-events/01-discordjs-events.mdx @@ -2,6 +2,9 @@ title: Discord.js Events --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + Events allow your Discord bot to react to various actions happening on Discord, such as when users send messages, join guilds, or when your bot comes online. @@ -52,15 +55,35 @@ To create an event handler, create a folder inside the `src/app/events` directory which should match the event name from Discord.js. This example will use the `"clientReady"` event. -```ts title="src/app/events/clientReady/log.ts" -import type { EventHandler } from 'commandkit'; + + + ```ts title="src/app/events/clientReady/log.ts" + import type { EventHandler } from 'commandkit'; -const handler: EventHandler<'clientReady'> = (client) => { - console.log(`🤖 ${client.user.displayName} is online!`); -}; + const handler: EventHandler<'clientReady'> = (client) => { + console.log(`🤖 ${client.user.displayName} is online!`); + }; -export default handler; -``` + export default handler; + ``` + + + + ```js title="src/app/events/clientReady/log.js" + /** + * @typedef {import('commandkit').EventHandler<'clientReady'>} ClientReadyHandler + */ + + /** @type {ClientReadyHandler} */ + const handler = (client) => { + console.log(`🤖 ${client.user.displayName} is online!`); + }; + + export default handler; + ``` + + + That's it! CommandKit will automatically detect this file and register it as one of the handler functions for the `"clientReady"` event. @@ -87,34 +110,78 @@ definition. You may want to have some events to only get called once. For this, you can export a variable called `once` from your event function file. -```ts title="src/app/events/clientReady/log.ts" -import type { EventHandler } from 'commandkit'; + + + ```ts title="src/app/events/clientReady/log.ts" + import type { EventHandler } from 'commandkit'; -export const once = true; + export const once = true; -const handler: EventHandler<'clientReady'> = (client) => { - console.log(`🤖 ${client.user.displayName} is online!`); -}; + const handler: EventHandler<'clientReady'> = (client) => { + console.log(`🤖 ${client.user.displayName} is online!`); + }; -export default handler; -``` + export default handler; + ``` + + + + ```js title="src/app/events/clientReady/log.js" + /** + * @typedef {import('commandkit').EventHandler<'clientReady'>} ClientReadyHandler + */ + + export const once = true; + + /** @type {ClientReadyHandler} */ + const handler = (client) => { + console.log(`🤖 ${client.user.displayName} is online!`); + }; + + export default handler; + ``` + + + ## Events with multiple parameter Some Discord.js events have multiple parameters, such as the `"messageUpdate"` event. -```ts title="src/app/events/messageUpdate/log-message-update.ts" -import type { EventHandler } from 'commandkit'; + + + ```ts title="src/app/events/messageUpdate/log-message-update.ts" + import type { EventHandler } from 'commandkit'; -const handler: EventHandler<'messageUpdate'> = (oldMessage, newMessage) => { - console.log( - `Message from ${oldMessage.author?.username} updated: ${oldMessage.content} -> ${newMessage.content}`, - ); -}; + const handler: EventHandler<'messageUpdate'> = (oldMessage, newMessage) => { + console.log( + `Message from ${oldMessage.author?.username} updated: ${oldMessage.content} -> ${newMessage.content}`, + ); + }; -export default handler; -``` + export default handler; + ``` + + + + ```js title="src/app/events/messageUpdate/log-message-update.js" + /** + * @typedef {import('commandkit').EventHandler<'messageUpdate'>} MessageUpdateHandler + */ + + /** @type {MessageUpdateHandler} */ + const handler = (oldMessage, newMessage) => { + console.log( + `Message from ${oldMessage.author?.username} updated: ${oldMessage.content} -> ${newMessage.content}`, + ); + }; + + export default handler; + ``` + + + ## Additional parameters @@ -125,19 +192,39 @@ and [`CommandKit`](../../api-reference/commandkit/classes/command-kit.mdx) instance. -```ts title="src/app/events/messageCreate/log.ts" -import type { EventHandler } from 'commandkit'; + + + ```ts title="src/app/events/messageCreate/log.ts" + import type { EventHandler } from 'commandkit'; -const handler: EventHandler<'messageCreate'> = ( - message, - client, - commandkit, -) => { - console.log(`Message from ${message.author.username}: ${message.content}`); -}; + const handler: EventHandler<'messageCreate'> = ( + message, + client, + commandkit, + ) => { + console.log(`Message from ${message.author.username}: ${message.content}`); + }; -export default handler; -``` + export default handler; + ``` + + + + ```js title="src/app/events/messageCreate/log.js" + /** + * @typedef {import('commandkit').EventHandler<'messageCreate'>} MessageCreateHandler + */ + + /** @type {MessageCreateHandler} */ + const handler = (message, client, commandkit) => { + console.log(`Message from ${message.author.username}: ${message.content}`); + }; + + export default handler; + ``` + + + ## Multiple handlers for the same event @@ -149,29 +236,73 @@ is called. For example, you might want to do several things when a message is created: -```ts title="src/app/events/messageCreate/give-xp.ts" -import type { EventHandler } from 'commandkit'; - -const handler: EventHandler<'messageCreate'> = (message) => { - // Don't give XP to bots - if (message.author.bot) return; - - // Give XP to the user - console.log(`Giving XP to ${message.author.username}`); -}; - -export default handler; -``` - -```ts title="src/app/events/messageCreate/log-message.ts" -import type { EventHandler } from 'commandkit'; - -const handler: EventHandler<'messageCreate'> = (message) => { - console.log(`Message from ${message.author.username}: ${message.content}`); -}; - -export default handler; -``` + + + ```ts title="src/app/events/messageCreate/give-xp.ts" + import type { EventHandler } from 'commandkit'; + + const handler: EventHandler<'messageCreate'> = (message) => { + // Don't give XP to bots + if (message.author.bot) return; + + // Give XP to the user + console.log(`Giving XP to ${message.author.username}`); + }; + + export default handler; + ``` + + + + ```js title="src/app/events/messageCreate/give-xp.js" + /** + * @typedef {import('commandkit').EventHandler<'messageCreate'>} MessageCreateHandler + */ + + /** @type {MessageCreateHandler} */ + const handler = (message) => { + // Don't give XP to bots + if (message.author.bot) return; + + // Give XP to the user + console.log(`Giving XP to ${message.author.username}`); + }; + + export default handler; + ``` + + + + + + + ```ts title="src/app/events/messageCreate/log-message.ts" + import type { EventHandler } from 'commandkit'; + + const handler: EventHandler<'messageCreate'> = (message) => { + console.log(`Message from ${message.author.username}: ${message.content}`); + }; + + export default handler; + ``` + + + + ```js title="src/app/events/messageCreate/log-message.js" + /** + * @typedef {import('commandkit').EventHandler<'messageCreate'>} MessageCreateHandler + */ + + /** @type {MessageCreateHandler} */ + const handler = (message) => { + console.log(`Message from ${message.author.username}: ${message.content}`); + }; + + export default handler; + ``` + + + Both handler functions will be called whenever a message is sent in Discord. diff --git a/apps/website/docs/guide/04-jsx-components/01-using-jsx.mdx b/apps/website/docs/guide/04-jsx-components/01-using-jsx.mdx index 5b832d94..9d6661b7 100644 --- a/apps/website/docs/guide/04-jsx-components/01-using-jsx.mdx +++ b/apps/website/docs/guide/04-jsx-components/01-using-jsx.mdx @@ -2,6 +2,9 @@ title: Using JSX --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + CommandKit provides first-class JSX support for both TypeScript and JavaScript projects. This allows you to write Discord message components using a familiar and intuitive syntax if you're already @@ -11,16 +14,30 @@ familiar with React. CommandKit automatically configures JSX support in your project. If you are doing a manual setup, ensure you have the following in your -`tsconfig.json` or `jsconfig.json`: +configuration: -```json -{ - "compilerOptions": { - "jsx": "react-jsx", - "jsxImportSource": "commandkit" - } -} -``` + + + ```json title="tsconfig.json" + { + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "commandkit" + } + } + ``` + + + ```json title="jsconfig.json" + { + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "commandkit" + } + } + ``` + + ## Available components @@ -39,38 +56,83 @@ builders: ## Example usage -```tsx -import { Container, TextDisplay, ActionRow, Button } from 'commandkit'; -import { ButtonStyle } from 'discord.js'; + + + ```tsx title="example.tsx" + import { Container, TextDisplay, ActionRow, Button } from 'commandkit'; + import { ButtonStyle } from 'discord.js'; + + const message = ( + + Welcome to our server! + + + + + ); + + interaction.reply({ + components: [message], + }); + ``` + + + + ```jsx title="example.jsx" + import { Container, TextDisplay, ActionRow, Button } from 'commandkit'; + import { ButtonStyle } from 'discord.js'; + + const message = ( + + Welcome to our server! + + + + + ); -const message = ( - - Welcome to our server! - - - - -); + interaction.reply({ + components: [message], + }); + ``` -interaction.reply({ - components: [message], -}); -``` + + ## JSX fragments CommandKit fully supports JSX fragments for grouping multiple elements without adding extra nodes: -```tsx -const elements = ( - <> - First message - Second message - -); - -interaction.reply({ - components: elements, -}); -``` + + + ```tsx title="fragments.tsx" + const elements = ( + <> + First message + Second message + + ); + + interaction.reply({ + components: elements, + }); + ``` + + + + ```jsx title="fragments.jsx" + const elements = ( + <> + First message + Second message + + ); + + interaction.reply({ + components: elements, + }); + ``` + + + diff --git a/apps/website/docs/guide/08-advanced/01-setup-commandkit-manually.mdx b/apps/website/docs/guide/08-advanced/01-setup-commandkit-manually.mdx index 2a86920b..49f4c7b4 100644 --- a/apps/website/docs/guide/08-advanced/01-setup-commandkit-manually.mdx +++ b/apps/website/docs/guide/08-advanced/01-setup-commandkit-manually.mdx @@ -29,32 +29,64 @@ npm install commandkit@next ## Configuration file -To get started, create a file called `commandkit.config.ts` at the -root of your project. This file is used to configure CommandKit and -optionally its plugins. +To get started, create a configuration file at the root of your +project. This file is used to configure CommandKit and optionally its +plugins. -```ts title="commandkit.config.ts" -import { defineConfig } from 'commandkit'; + + + ```ts title="commandkit.config.ts" + import { defineConfig } from 'commandkit'; -export default defineConfig({}); -``` + export default defineConfig({}); + ``` + + + + ```js title="commandkit.config.js" + import { defineConfig } from 'commandkit'; + + export default defineConfig({}); + ``` + + + ## Entrypoint file -Then, create a folder called `src`, followed by a file called `app.ts` -inside it. The file should look like this: +Then, create a folder called `src`, followed by an app file inside it. +The file should look like this: -```ts title="src/app.ts" -import { Client } from 'discord.js'; + + + ```ts title="src/app.ts" + import { Client } from 'discord.js'; -const client = new Client({ - intents: ['Guilds'], -}); + const client = new Client({ + intents: ['Guilds'], + }); -client.token = '...'; // Optional: Manually set a bot token + client.token = '...'; // Optional: Manually set a bot token -export default client; -``` + export default client; + ``` + + + + ```js title="src/app.js" + import { Client } from 'discord.js'; + + const client = new Client({ + intents: ['Guilds'], + }); + + client.token = '...'; // Optional: Manually set a bot token + + export default client; + ``` + + + With the current entrypoint file created, it's important to understand that: @@ -71,26 +103,57 @@ that: ## Adding commands To add a command, create a folder inside the `src/app` directory -called `commands` and create your command file (e.g. `ping.ts`). This -example will use a simple ping/pong command which will register as a -chat input (slash) and message command. - -```ts title="src/app/commands/ping.ts" -import type { ChatInputCommand, CommandData, MessageCommand } from 'commandkit'; - -export const command: CommandData = { - name: 'ping', - description: 'Pong!', -}; - -export const chatInput: ChatInputCommand = async ({ interaction }) => { - await interaction.reply('Pong!'); -}; - -export const message: MessageCommand = async ({ message }) => { - await message.reply('Pong!'); -}; -``` +called `commands` and create your command file. This example will use +a simple ping/pong command which will register as a chat input (slash) +and message command. + + + + ```ts title="src/app/commands/ping.ts" + import type { ChatInputCommand, CommandData, MessageCommand } from 'commandkit'; + + export const command: CommandData = { + name: 'ping', + description: 'Pong!', + }; + + export const chatInput: ChatInputCommand = async ({ interaction }) => { + await interaction.reply('Pong!'); + }; + + export const message: MessageCommand = async ({ message }) => { + await message.reply('Pong!'); + }; + ``` + + + + ```js title="src/app/commands/ping.js" + /** + * @typedef {import('commandkit').ChatInputCommand} ChatInputCommand + * @typedef {import('commandkit').CommandData} CommandData + * @typedef {import('commandkit').MessageCommand} MessageCommand + */ + + /** @type {CommandData} */ + export const command = { + name: 'ping', + description: 'Pong!', + }; + + /** @type {ChatInputCommand} */ + export const chatInput = async ({ interaction }) => { + await interaction.reply('Pong!'); + }; + + /** @type {MessageCommand} */ + export const message = async ({ message }) => { + await message.reply('Pong!'); + }; + ``` + + + This command will reply with "Pong!" when the user runs the `/ping` slash command, or sends `!ping` in the chat. @@ -117,13 +180,29 @@ respective event is emitted by discord.js. Following the `clientReady` event example mentioned above, you may want to log when your bot comes online. The function for that will look like so: -```ts title="src/app/events/clientReady/log.ts" -import type { Client } from 'discord.js'; - -export default function (client: Client) { - console.log(`Logged in as ${client.user.username}!`); -} -``` + + + ```ts title="src/app/events/clientReady/log.ts" + import type { Client } from 'discord.js'; + + export default function (client: Client) { + console.log(`Logged in as ${client.user.username}!`); + } + ``` + + + + ```js title="src/app/events/clientReady/log.js" + /** + * Event handler for when the bot is ready + * @param {import('discord.js').Client} client - The Discord client instance + */ + export default function (client) { + console.log(`Logged in as ${client.user.username}!`); + } + ``` + + :::tip