### Run Project Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/getting-started.mdx Start your Discordx bot after setup and token configuration. ```bash npm run start ``` -------------------------------- ### Quick Example: Music Playback Setup Source: https://github.com/discordx-ts/discordx/blob/main/packages/music/README.md Demonstrates how to initialize QueueNode, create a TrackQueue for a guild, join a voice channel, and add a track for playback. ```typescript // Create a queue node const queueNode = new QueueNode(client); // Create a track queue for guild const trackQueue = new TrackQueue({ client: client, guildId: guildId, queueNode: queueNode, }); // Join voice channel queue.join({ channelId: channelId, guildId: guildId, }); // Add and play track queue.addTrack({ url: "VIDEO_URL", }); ``` -------------------------------- ### Install @discordx/music Source: https://github.com/discordx-ts/discordx/blob/main/packages/music/README.md Install the library using npm or yarn. Ensure Node.js v16.6.0+ and discord.js and @discordjs/voice are installed prior. ```bash npm install @discordx/music yarn add @discordx/music ``` -------------------------------- ### Install Discordx and Discord.js Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/getting-started.mdx Install the necessary Discordx and discord.js packages using npm or yarn. ```bash npm install discordx discord.js ``` -------------------------------- ### Initialize and Start Discord.ts Client Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/basics/client.md Use the discordx Client to manage operations with Discord's API. Ensure correct intents are provided for receiving necessary data. This snippet shows the basic setup for starting the bot and initializing application commands. ```typescript const client = new Client({ intents: [ IntentsBitField.Flags.Guilds, IntentsBitField.Flags.GuildMessages, IntentsBitField.Flags.GuildMembers, ], silent: false, }); client.on(Events.ClientReady, async () => { console.log(">> Bot started"); // to create/update/delete discord application commands await client.initApplicationCommands(); }); client.login(BOT_TOKEN); ``` -------------------------------- ### Install discordx Source: https://github.com/discordx-ts/discordx/blob/main/packages/discordx/README.md Install discordx using npm or yarn. Node.js version 16.6.0 or newer is required. ```bash npm install discordx yarn add discordx ``` -------------------------------- ### Install YTDL Player Plugin Source: https://github.com/discordx-ts/discordx/blob/main/packages/plugin-ytdl-player/README.md Use npm to install the YTDL player plugin for discordx bots. ```bash npm install @discordx/plugin-ytdl-player ``` -------------------------------- ### Build Project Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/getting-started.mdx Build your Discordx project after setup. ```bash npm run build ``` -------------------------------- ### Install @discordx/utilities Source: https://github.com/discordx-ts/discordx/blob/main/packages/utilities/README.md Install the @discordx/utilities package using npm or yarn. Node.js version 16.6.0 or newer is required. ```bash npm install @discordx/utilities yarn add @discordx/utilities ``` -------------------------------- ### Install @discordx/importer Source: https://github.com/discordx-ts/discordx/blob/main/packages/importer/README.md Install the package using npm or yarn. Node.js version 16.6.0 or newer is required. ```bash npm install @discordx/importer yarn add @discordx/importer ``` -------------------------------- ### Install discordx Source: https://github.com/discordx-ts/discordx/blob/main/packages/create-discordx/README.md Use this command to create a new discordx application. It is inspired by create-next-app. ```bash npx create-discordx ``` -------------------------------- ### Install @discordx/lava-player Source: https://github.com/discordx-ts/discordx/blob/main/packages/lava-player/README.md Install the library using npm or yarn. Ensure Node.js version 16.6.0 or newer is used. Lavalink must also be running. ```bash npm install @discordx/lava-player yarn add @discordx/lava-player ``` -------------------------------- ### Install @discordx/pagination Source: https://github.com/discordx-ts/discordx/blob/main/packages/pagination/README.md Install the @discordx/pagination package using npm or yarn. Node.js version 16.6.0 or newer is required. ```bash npm install @discordx/pagination ``` ```bash yarn add @discordx/pagination ``` -------------------------------- ### Install Lava Player Plugin Source: https://github.com/discordx-ts/discordx/blob/main/packages/plugin-lava-player/README.md Install the plugin using npm. This command adds the necessary package to your project. ```bash npm install @discordx/plugin-lava-player ``` -------------------------------- ### Install TypeScript Dev Dependencies Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/getting-started.mdx Install TypeScript as a development dependency. ```bash npm install --save-dev typescript ``` -------------------------------- ### Install @discordx/internal Source: https://github.com/discordx-ts/discordx/blob/main/packages/internal/README.md Install the @discordx/internal package using npm or yarn. Node.js version 16.6.0 or newer is required. ```bash npm install @discordx/internal yarn add @discordx/internal ``` -------------------------------- ### Install @discordx/lava-queue Source: https://github.com/discordx-ts/discordx/blob/main/packages/lava-queue/README.md Install the @discordx/lava-queue package using npm or yarn. Requires Node.js version 16.6.0 or newer. ```bash npm install @discordx/lava-queue ``` ```bash yarn add @discordx/lava-queue ``` -------------------------------- ### Install @discordx/di with npm or yarn Source: https://github.com/discordx-ts/discordx/blob/main/packages/di/README.md Use npm or yarn to install the @discordx/di package. Ensure you have Node.js version 16.6.0 or newer. ```bash npm install @discordx/di ``` ```bash yarn add @discordx/di ``` -------------------------------- ### Install tsx for Debugging Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/basics/debugging.md Install tsx as a development dependency to enable TypeScript execution during debugging. ```bash npm install --save-dev tsx ``` -------------------------------- ### Add ShardBot Start Method Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/basics/sharding.md Adds a static start method to the ShardBot class and calls it. This sets up the entry point for the sharding process. ```typescript export class ShardBot { static start(): void {} } ShardBot.start(); ``` -------------------------------- ### Initialize Client with TSyringe DI Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/basics/dependency-injection.md Initialize the discord.js client with TSyringe DI configured. This example shows setting the engine and client options before login. ```typescript import { Events, IntentsBitField } from "discord.js"; import { Client, DIService, tsyringeDependencyRegistryEngine } from "discordx"; async function start() { DIService.engine = tsyringeDependencyRegistryEngine; const client = new Client({ botId: "test", intents: [ IntentsBitField.Flags.Guilds, IntentsBitField.Flags.GuildMessages, ], silent: false, }); await client.login("YOUR_TOKEN"); } start(); ``` -------------------------------- ### Create Embed Pagination with @discordx/pagination Source: https://context7.com/discordx-ts/discordx/llms.txt Demonstrates how to create a basic embed pagination component using the @discordx/pagination package. Ensure @discordx/pagination is installed. ```typescript import { Pagination, PaginationResolver } from "@discordx/pagination"; import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, type CommandInteraction, type MessageActionRowComponentBuilder, } from "discord.js"; import { Discord, Slash } from "discordx"; @Discord() class PaginationExample { @Slash({ description: "Show paginated content", name: "pages" }) async showPages(interaction: CommandInteraction): Promise { const pages = Array.from({ length: 10 }, (_, i) => ({ embeds: [ new EmbedBuilder() .setTitle(`Page ${i + 1}`) .setDescription(`This is page ${i + 1} of 10`) .setColor(0x00ff00), ], })); const pagination = new Pagination(interaction, pages, { time: 60_000, // 60 second timeout onTimeout: () => interaction.deleteReply().catch(() => {}), }); await pagination.send(); } @Slash({ description: "Dynamic pagination", name: "dynamic-pages" }) async dynamicPages(interaction: CommandInteraction): Promise { const resolver = new PaginationResolver((page, paginator) => { // Dynamically generate page content if (page === 5) { paginator.setPages(Array.from({ length: 20 }, (_, i) => ({ content: `Extended page ${i + 1}`, }))); return { content: "Pagination extended to 20 pages!" }; } return { embeds: [ new EmbedBuilder() .setTitle(`Dynamic Page ${page + 1}`) .setDescription(`Generated on request`), ], }; }, 10); const pagination = new Pagination(interaction, resolver, { buttons: { previous: { emoji: { name: "arrow_left" } }, next: { emoji: { name: "arrow_right" } }, exit: { style: ButtonStyle.Danger }, }, }); await pagination.send(); } } ``` -------------------------------- ### Initialize Discord client and application commands Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/decorators/command/slash.md Configure your Discord client to initialize application commands and execute interactions. This setup is required for commands to function. ```typescript import { Client } from "discordx"; async function start() { const client = new Client({ botId: "test", intents: [ IntentsBitField.Flags.Guilds, IntentsBitField.Flags.GuildMessages, ], }); client.once(Events.ClientReady, async () => { await client.initApplicationCommands(); }); client.on(Events.InteractionCreate, (interaction) => { client.executeInteraction(interaction); }); await client.login("YOUR_TOKEN"); } start(); ``` -------------------------------- ### Import Glob Paths (Combined Modules) Source: https://github.com/discordx-ts/discordx/blob/main/packages/importer/README.md This example demonstrates how to handle module imports dynamically based on whether the environment is CommonJS or ESNext, making libraries more compatible. ```typescript import { dirname, importx, isESM } from "@discordx/importer"; const folder = isESM() ? dirname(import.meta.url) : __dirname; importx(`${folder}/commands/**.js`).then(() => console.log("All files imported"), ); ``` -------------------------------- ### Format Date and Time with Discordx Utilities Source: https://github.com/discordx-ts/discordx/blob/main/packages/utilities/README.md Demonstrates using TimeFormat.StaticRelativeTime for relative time strings and TimeFormat.LongDate with dayjs for specific date formatting. Ensure @discordx/utilities is installed. ```typescript import { dayjs, TimeFormat } from "@discordx/utilities"; const message = `I will be there in ${TimeFormat.StaticRelativeTime("31/12/2025", false)}`; const message = `I will be there by ${TimeFormat.LongDate( dayjs({ day: 31, month: 12, year: 2025, }), false, )}`; ``` -------------------------------- ### Play Music Track Source: https://github.com/discordx-ts/discordx/blob/main/packages/lava-player/README.md Load a track using a search query (e.g., YouTube search) and start playback. Handles cases where no track is found. ```typescript const res = await this.node.rest.loadTracks(`ytsearch:${song}`); if (res.loadType !== LoadType.SEARCH || !res.data[0]) { await interaction.followUp("No track found"); return; } const track = res.data[0]; await player.update({ track, }); await interaction.followUp(`playing ${track.info.title}`); ``` -------------------------------- ### Get All Discord Classes with DIService Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/basics/dependency-injection.md Use DIService.allServices() to construct and retrieve all @Discord classes. This method initializes all classes in the DI container and is not suitable for lazy-loading. ```typescript import { DIService } from "discordx"; function getAllDiscordClasses(): Set { return DIService.allServices(); } ``` -------------------------------- ### Access Guard Data in SimpleCommand Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/decorators/general/guard.md This example illustrates how to access the guard data object within a simple command handler, which can be populated by guards. ```typescript @Discord() class Example { @SimpleCommand({ name: "my-cmd" }) async myCmd(command: SimpleCommandMessage, client: Client, guardData: any) { command.message.reply("Hello :wave_tone1:"); } } ``` -------------------------------- ### Import Glob Paths (ESNext) Source: https://github.com/discordx-ts/discordx/blob/main/packages/importer/README.md Import modules using glob paths in an ESNext environment. Note that __dirname is not available in ESNext, so import.meta.url must be used to get the directory name. ```typescript import { dirname, importx } from "@discordx/importer"; const __dirname = dirname(import.meta.url); importx(`${__dirname}/commands/**.js`).then(() => console.log("All files imported"), ); ``` -------------------------------- ### Dependency Injection with TSyringe in Discordx Source: https://context7.com/discordx-ts/discordx/llms.txt Integrates TSyringe for dependency injection within a Discord bot using discordx. Requires TSyringe and discordx to be installed. ```typescript import { Events, IntentsBitField, type CommandInteraction } from "discord.js"; import { Client, DIService, Discord, Slash, tsyringeDependencyRegistryEngine } from "discordx"; import { container, injectable, singleton } from "tsyringe"; // Database service @singleton() class DatabaseService { private connection: string = "connected"; query(sql: string): string { return `Executed: ${sql} on ${this.connection}`; } } // Discord class with dependency injection @Discord() @injectable() class DatabaseCommands { constructor(private database: DatabaseService) { console.log("DatabaseCommands instantiated with injected database service"); } @Slash({ description: "Query database", name: "db-query" }) async dbQuery(interaction: CommandInteraction): Promise { const result = this.database.query("SELECT * FROM users"); await interaction.reply(result); } } // Application setup async function start() { // Configure DI before importing Discord classes DIService.engine = tsyringeDependencyRegistryEngine.setInjector(container); const client = new Client({ intents: [IntentsBitField.Flags.Guilds], silent: false, }); client.once(Events.ClientReady, async () => { await client.initApplicationCommands(); console.log("Bot ready with DI!"); }); client.on(Events.InteractionCreate, (interaction) => { client.executeInteraction(interaction); }); await client.login(process.env.BOT_TOKEN!); } start(); ``` -------------------------------- ### Create Prefix Commands with @SimpleCommand Source: https://context7.com/discordx-ts/discordx/llms.txt Use the `@SimpleCommand` decorator to define traditional prefix-based commands. This example shows a basic ping command and a command that repeats user input. ```typescript import { Events, IntentsBitField, type Message } from "discord.js"; import { Client, Discord, SimpleCommand, SimpleCommandMessage, SimpleCommandOption } from "discordx"; @Discord() class PrefixCommands { @SimpleCommand({ aliases: ["p"], name: "ping" }) async ping(command: SimpleCommandMessage): Promise { await command.message.reply("Pong!"); } @SimpleCommand({ name: "say", description: "Repeat your message" }) async say( @SimpleCommandOption({ name: "text", type: "STRING" }) text: string, command: SimpleCommandMessage ): Promise { await command.message.reply(text || "You didn't say anything!"); } @SimpleCommand({ prefix: ["?", "!"], name: "help" }) async help(command: SimpleCommandMessage): Promise { await command.message.reply("Available commands: ping, say, help"); } } // Client setup for simple commands const client = new Client({ intents: [ IntentsBitField.Flags.Guilds, IntentsBitField.Flags.GuildMessages, IntentsBitField.Flags.MessageContent, // Required for message content ], simpleCommand: { prefix: "!", }, }); client.on(Events.MessageCreate, (message) => { client.executeCommand(message); }); ``` -------------------------------- ### File Importing with @discordx/importer Source: https://context7.com/discordx-ts/discordx/llms.txt Utilizes the @discordx/importer package for cross-platform glob-based file importing in both CommonJS and ESM environments. Ensure @discordx/importer is installed. ```typescript import { dirname, importx, isESM, resolve } from "@discordx/importer"; // Check module system console.log(`Running in ${isESM() ? "ESM" : "CommonJS"} mode`); // Import files using glob patterns async function loadCommands() { // ESM: use dirname helper since __dirname is not available const baseDir = isESM() ? dirname(import.meta.url) : __dirname; // Import all command files await importx(`${baseDir}/commands/**/*.{js,ts}`); // Or use relative paths from project root await importx("./src/events/**/*.js"); console.log("All files imported successfully"); } // Resolve paths without importing async function listCommandFiles() { const files = await resolve("./src/commands/**/*.ts"); console.log("Found command files:", files); } loadCommands(); ``` -------------------------------- ### Import Using Relative Path Source: https://github.com/discordx-ts/discordx/blob/main/packages/importer/README.md Import modules using a relative path starting from the root folder. This simplifies path definitions by avoiding the need for __dirname. ```typescript import { importx } from "@discordx/importer"; // relative path start from root folder importx("./tests/commands/**.js").then(() => console.log("All files imported")); ``` -------------------------------- ### Basic Reaction Handler with @Reaction Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/decorators/general/reaction.md Use the @Reaction decorator to create a handler for a specific emoji. This example shows how to pin a message when a '📌' reaction is added. ```typescript import { MessageReaction, User } from "discord.js"; import { Discord, Reaction } from "discordx"; @Discord() class Example { @Reaction({ emoji: "📌" }) async pin(reaction: MessageReaction, user: User): Promise { await reaction.message.pin(); } } ``` -------------------------------- ### Create a Slash Command with @Slash Source: https://github.com/discordx-ts/discordx/blob/main/packages/discordx/README.md Use the @Slash decorator to define slash commands for your Discord bot. This example shows how to create a 'hello' command that takes a message as an option. ```typescript import { ApplicationCommandOptionType, CommandInteraction, } from "discord.js"; import { Discord, Slash, SlashOption } from "discordx"; @Discord() class Example { @Slash({ description: "say hello", name: "hello" }) hello( @SlashOption({ description: "enter your greeting", name: "message", required: true, type: ApplicationCommandOptionType.String, }) message: string, interaction: CommandInteraction, ): void { interaction.reply(`:wave: from ${interaction.user}: ${message}`); } } ``` -------------------------------- ### Typing Event Payloads with ArgsOf Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/basics/args-of.md Use ArgsOf to type event parameters by passing the event name as a string. This example shows how to type parameters for MessageCreate and ChannelUpdate events. ```typescript import { ArgsOf, Discord, On } from "@typeit/discord"; import { Message } from "discord.js"; @Discord() class Example { @On({ event: "messageCreate" }) onMessage( // The type of message is Message [message]: ArgsOf<"messageCreate">, ) { // ... } @On({ event: "channelUpdate" }) onMessage( // The type of channel1 and channel2 is TextChannel [channel1, channel2]: ArgsOf<"channelUpdate">, ) { // ... } } ``` -------------------------------- ### Initialize discordx Client Source: https://context7.com/discordx-ts/discordx/llms.txt Sets up the discordx Client, including intents, event listeners for ready and interaction events, and command initialization. Ensure BOT_TOKEN is set in your environment variables. ```typescript import { dirname, importx } from "@discordx/importer"; import { Events, IntentsBitField } from "discord.js"; import { Client } from "discordx"; async function start() { const client = new Client({ intents: [ IntentsBitField.Flags.Guilds, IntentsBitField.Flags.GuildMessages, IntentsBitField.Flags.GuildMembers, ], silent: false, // Optional: restrict commands to specific guilds during development // botGuilds: process.env.DEV ? ["GUILD_ID"] : undefined, }); client.once(Events.ClientReady, async () => { // Register slash commands with Discord await client.initApplicationCommands(); console.log(">>> Bot started"); }); client.on(Events.InteractionCreate, (interaction) => { client.executeInteraction(interaction); }); // Import all command files using glob pattern await importx(`${dirname(import.meta.url)}/commands/**/*.{js,ts}`); if (!process.env.BOT_TOKEN) { throw Error("Could not find BOT_TOKEN in your environment"); } await client.login(process.env.BOT_TOKEN); } start(); ``` -------------------------------- ### Get All Discord Classes with TypeDi Tokens Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/basics/dependency-injection.md Fetch all Discord classes using typeDi tokens by getting all instances associated with TypeDiDependencyRegistryEngine.token. ```typescript import { DIService } from "discordx"; function getAllDiscordClasses(): Set { return Container.getMany(TypeDiDependencyRegistryEngine.token); } ``` -------------------------------- ### Get Guild Player Instance Source: https://github.com/discordx-ts/discordx/blob/main/packages/lava-player/README.md Retrieve an existing player instance for a specific guild using its ID. ```typescript const player = node.players.get("guild id"); ``` -------------------------------- ### Get All Discord Classes with Tsyringe Tokens Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/basics/dependency-injection.md Retrieve all Discord classes using tsyrnge tokens by resolving all instances associated with TsyringeDependencyRegistryEngine.token. ```typescript import { DIService } from "discordx"; function getAllDiscordClasses(): Set { return container.resolveAll(TsyringeDependencyRegistryEngine.token); } ``` -------------------------------- ### Get declared application commands Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/decorators/command/slash.md Retrieve a list of all application commands declared in your application using decorators like @Slash and @ContextMenu. ```typescript const applicationCommands = client.applicationCommands; ``` -------------------------------- ### Setting Up Global Guards Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/decorators/general/guard.md Configure global guards when initializing the Discordx client. These guards are executed before any @Discord class guards. ```typescript import { NotBot } from "@discordx/utilities"; import { Client } from "discordx"; // Use the client provided by discordx, not discord.js. async function start() { const client = new Client({ botId: "test", silent: false, guards: [NotBot], }); await client.login("YOUR_TOKEN"); } start(); ``` -------------------------------- ### Initialize Lava Link Node Source: https://github.com/discordx-ts/discordx/blob/main/packages/lava-player/README.md Set up a new Node instance for Lavalink connection. Configure host, port, password, and event handlers for voice state and server updates. Requires a running Lavalink instance and a Discord client. ```typescript const nodeInstance = new Node({ host: { address: process.env.LAVA_HOST ?? "localhost", connectionOptions: { sessionId: "discordx" }, port: process.env.LAVA_PORT ? Number(process.env.LAVA_PORT) : 2333, }, // your Lavalink password password: process.env.LAVA_PASSWORD ?? "youshallnotpass", send(guildId, packet) { const guild = client.guilds.cache.get(guildId); if (guild) { guild.shard.send(packet); } }, userId: client.user?.id ?? "", // the user id of your bot }); nodeInstance.connection.ws.on("message", (data) => { const raw = JSON.parse(data.toString()) as OpResponse; console.log("ws>>", raw); }); nodeInstance.on("error", (e) => { console.log(e); }); client.ws.on( GatewayDispatchEvents.VoiceStateUpdate, (data: VoiceStateUpdate) => { void nodeInstance.voiceStateUpdate(data); }, ); client.ws.on( GatewayDispatchEvents.VoiceServerUpdate, (data: VoiceServerUpdate) => { void nodeInstance.voiceServerUpdate(data); }, ); ``` -------------------------------- ### Execute Simple Commands with Client Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/decorators/command/simple-command.md Configure the Discord.js client to use a prefix for simple commands and manually execute them when a message is created. Ensure necessary intents are enabled. ```typescript import { Client, IntentsBitField } from "discordx"; import { Events } from "discord.js"; async function start() { const client = new Client({ botId: "test", simpleCommand: { prefix: "!", // define your prefix here }, intents: [ IntentsBitField.Flags.Guilds, IntentsBitField.Flags.GuildMessages, ], }); client.on(Events.MessageCreate, (message) => { client.executeCommand(message); }); await client.login("YOUR_TOKEN"); } start(); ``` -------------------------------- ### VSCode launch.json Configuration Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/basics/debugging.md Configure the .vscode/launch.json file to set up the Node.js debugger for your bot. Ensure the 'args' path points to your main TypeScript file. ```json { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Debug bot", "protocol": "inspector", "args": ["${workspaceRoot}/PATH_TO_YOUR_MAIN.ts"], "cwd": "${workspaceRoot}", "runtimeArgs": ["--import", "tsx"], "internalConsoleOptions": "neverOpen" } ] } ``` -------------------------------- ### Set Bot Token (Windows) Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/getting-started.mdx Set the BOT_TOKEN environment variable on Windows using either cmd or PowerShell. ```bash // cmd set BOT_TOKEN=REPLACE_THIS_WITH_YOUR_BOT_TOKEN ``` ```powershell $ENV:BOT_TOKEN="REPLACE_THIS_WITH_YOUR_BOT_TOKEN" ``` -------------------------------- ### Configure Guild-specific commands during development Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/decorators/command/slash.md To speed up development, use the `botGuilds` option to limit application command propagation to a specific test server. ```typescript const client = new Client({ botId: "test", intents: [IntentsBitField.Flags.Guilds, IntentsBitField.Flags.GuildMessages], botGuilds: process.DEV ? ["GUILD_ID"] : undefined, }); ``` -------------------------------- ### Transformer for Slash Option Parameters Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/decorators/command/slash-option.md Implement a transformer function to process and transform option inputs before they are passed to the command handler. This example uses a DocumentTransformer. ```typescript class Document { constructor( public input: string, public interaction: ChatInputCommandInteraction ) { /* empty constructor */ } async save(): Promise { /* your logic to save input into database */ await this.interaction.followUp( `${this.interaction.user} saved \ `${this.input}\ ` into database` ); } } function DocumentTransformer( input: string, interaction: ChatInputCommandInteraction ): Document { return new Document(input, interaction); } @Discord() export class Example { @Slash({ description: "Save input into database", name: "save-input" }) async withTransformer( @SlashOption( { description: "input", name: "input", required: true, type: ApplicationCommandOptionType.String, }, DocumentTransformer ) doc: Document, interaction: ChatInputCommandInteraction ): Promise { await interaction.deferReply(); doc.save(); } } ``` -------------------------------- ### Configure Custom DI Engine Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/basics/dependency-injection.md Integrate a custom DI engine with discordx by assigning your implementation of IDependencyRegistryEngine to DIService.engine. ```typescript import { DIService } from "discordx"; import { Container } from "typedi"; import { myCustomEngine } from "./MyCustomEngine.js"; DIService.engine = myCustomEngine; ``` -------------------------------- ### Set Bot Token (Linux) Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/getting-started.mdx Set the BOT_TOKEN environment variable on Linux. ```bash export BOT_TOKEN=REPLACE_THIS_WITH_YOUR_BOT_TOKEN ``` -------------------------------- ### Implement Bot Guard with @Guard Source: https://context7.com/discordx-ts/discordx/llms.txt Use the `@Guard` decorator with a `GuardFunction` to create middleware that runs before command handlers. This example prevents bots from triggering message handlers. ```typescript import { type CommandInteraction, type Message } from "discord.js"; import { ArgsOf, Client, Discord, Guard, GuardFunction, On, Slash } from "discordx"; // Guard function to check if user is not a bot const NotBot: GuardFunction> = async ( [message], client, next ) => { if (!message.author.bot) { await next(); } }; // Guard function with parameters function RequireRole(roleId: string): GuardFunction { return async (interaction, client, next) => { const member = interaction.member; if (member && "roles" in member && member.roles.cache.has(roleId)) { await next(); } else { await interaction.reply({ content: "Permission denied.", ephemeral: true }); } }; } @Discord() @Guard(NotBot) // Apply to all handlers in class class GuardedCommands { @On({ event: "messageCreate" }) async onMessage([message]: ArgsOf<"messageCreate">): Promise { // This only runs if NotBot guard passes console.log(`Message from human: ${message.content}`); } @Slash({ description: "Admin only command" }) @Guard(RequireRole("ADMIN_ROLE_ID")) async adminCommand(interaction: CommandInteraction): Promise { await interaction.reply("Admin command executed!"); } } ``` -------------------------------- ### Import LavaLyrics Plugin Source: https://github.com/discordx-ts/discordx/blob/main/packages/plugin-lava-player/README.md Import the LavaLyrics extension for the Lava Player plugin. This enables additional features like the `/music lyrics` command. Requires LavaLyrics and LavaSrc plugins. ```typescript import "@discordx/plugin-lava-player/lavalyrics"; ``` -------------------------------- ### Create and Show a Modal Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/decorators/gui/modal-component.md Use this to create a modal with text input fields and present it to the user. Ensure the modal has a unique custom ID. ```typescript import { CommandInteraction, ModalBuilder, TextInputBuilder, TextInputStyle, } from "discord.js"; import { Discord, Slash, ModalComponent } from "discordx"; class LabelBuilder { private label: string; private textInputComponent: TextInputBuilder; setLabel(label: string): this { this.label = label; return this; } setTextInputComponent(textInputComponent: TextInputBuilder): this { this.textInputComponent = textInputComponent; return this; } build() { return { label: this.label, textInputComponent: this.textInputComponent, }; } } @Discord() class Example { @Slash({ description: "modal" }) modal(interaction: CommandInteraction): void { // Create the modal const modal = new ModalBuilder() .setTitle("My Awesome Form") .setCustomId("AwesomeForm"); // Create text input fields const tvShowInputComponent = new LabelBuilder() .setLabel("Favorite TV show") .setTextInputComponent( new TextInputBuilder() .setCustomId("tvField") .setStyle(TextInputStyle.Short) .setRequired(true), ) .build(); const haikuInputComponent = new LabelBuilder() .setLabel("Write down your favorite haiku") .setTextInputComponent( new TextInputBuilder() .setCustomId("haikuField") .setStyle(TextInputStyle.Paragraph) .setRequired(true), ) .build(); // Add action rows to form modal.addLabelComponents(tvShowInputComponent.textInputComponent, haikuInputComponent.textInputComponent); // Present the modal to the user interaction.showModal(modal); } @ModalComponent() async AwesomeForm(interaction: ModalSubmitInteraction): Promise { const [favTVShow, favHaiku] = ["tvField", "haikuField"].map((id) => interaction.fields.getTextInputValue(id), ); await interaction.reply( `Favorite TV Show: ${favTVShow}, Favorite haiku: ${favHaiku}`, ); return; } } ``` -------------------------------- ### Import Lava Player Plugin Source: https://github.com/discordx-ts/discordx/blob/main/packages/plugin-lava-player/README.md Import the main plugin to enable its functionality in your Discord bot. Ensure this import is placed correctly in your bot's entry file. ```typescript import "@discordx/plugin-lava-player"; ``` -------------------------------- ### Slash Command with Autocomplete Options Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/decorators/command/slash-option.md Demonstrates a slash command with three options, each featuring different autocomplete implementations. Includes handling for both autocomplete interactions and regular command execution. Note the difference in 'this' context between normal functions and arrow functions for autocomplete. ```typescript import { Discord, Slash, SlashOption, } from "discordx"; import { AutocompleteInteraction, CommandInteraction, } from "discord.js"; @Discord() class Example { myCustomText = "Hello discordx"; @Slash({ description: "autocomplete", }) autocomplete( @SlashOption({ autocomplete: true, description: "option-a", name: "option-a", required: true, type: ApplicationCommandOptionType.String, }) searchText: string, @SlashOption({ autocomplete: function ( this: Example, interaction: AutocompleteInteraction ) { // The normal function has this (keyword), therefore class reference is available console.log(this.myCustomText); // resolver for option b interaction.respond([ { name: "option c", value: "d" }, { name: "option d", value: "c" }, ]); }, description: "option-b", name: "option-b", required: true, type: ApplicationCommandOptionType.String, }) searchText2: string, @SlashOption({ autocomplete: (interaction: AutocompleteInteraction) => { // This is not available for the arrow function, so there is no class reference interaction.respond([ { name: "option e", value: "e" }, { name: "option f", value: "f" }, ]); }, description: "option-c", name: "option-c", required: true, type: ApplicationCommandOptionType.String, }) searchText3: string, interaction: CommandInteraction | AutocompleteInteraction ): void { // If autocomplete is not handled above, it will be passed to handler (see option-a definition) if (interaction.isAutocomplete()) { const focusedOption = interaction.options.getFocused(true); // resolver for option a if (focusedOption.name === "option-a") { interaction.respond([ { name: "option a", value: "a" }, { name: "option b", value: "b" }, ]); } } else { interaction.reply(`${searchText}-${searchText2}-${searchText3}`); } } } ``` -------------------------------- ### Restrict Commands to Guilds with @Guild Source: https://context7.com/discordx-ts/discordx/llms.txt The `@Guild` decorator limits the availability of commands to specific Discord servers. This example demonstrates applying it at the class level and overriding it for individual commands. ```typescript import { type CommandInteraction } from "discord.js"; import { Discord, Guild, Slash } from "discordx"; @Discord() @Guild("123456789012345678", "987654321098765432") // Apply to all commands in class class GuildCommands { @Slash({ description: "Server-specific command" }) serverOnly(interaction: CommandInteraction): void { interaction.reply("This command only works in specific servers!"); } @Slash({ description: "Another guild command" }) @Guild("111111111111111111") // Override class-level guilds specificGuild(interaction: CommandInteraction): void { interaction.reply("This only works in one specific server!"); } } // Dynamic guild resolver in client configuration const client = new Client({ intents: [IntentsBitField.Flags.Guilds], botGuilds: [(client) => client.guilds.cache.map((guild) => guild.id)], }); ``` -------------------------------- ### Enable Tokenization with TypeDI Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/basics/dependency-injection.md To enable tokenization with TypeDI, call `setUseTokenization(true)` on the `typeDiDependencyRegistryEngine` during Discordx initialization. The injector is set separately. ```typescript import { DIService } from "discordx"; import { typeDiDependencyRegistryEngine } from "discordx"; import { container } from "typedi"; DIService.engine = typeDiDependencyRegistryEngine .setUseTokenization(true) .setInjector(container); ``` -------------------------------- ### Fetch application commands from Discord Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/decorators/command/slash.md Retrieve application commands directly from Discord. If no guild ID is provided, it fetches global commands. ```typescript client.once(Events.ClientReady, async () => { // ... const applicationCommands = await client.fetchApplicationCommands(); }); ``` -------------------------------- ### Using object or enum for choices Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/decorators/command/slash-choice.md Define choices using objects or enums for better organization and reusability. This example shows how to map enum values to display names and actual values for autocompletion. ```typescript enum TextChoices { // WhatDiscordShows = value Hello = "Hello", "Good Bye" = "Good Bye", } @Discord() class Example { @Slash({ description: "hello" }) hello( @SlashChoice( { name: TextChoices[TextChoices.Hello], value: TextChoices.Hello, }, { name: TextChoices[TextChoices["Good Bye"]], value: TextChoices["Good Bye"], }, ) @SlashChoice({ name: "How are you", value: "hay" }) @SlashOption({ description: "text", name: "text", required: true, type: ApplicationCommandOptionType.String, }) text: string, interaction: CommandInteraction, ) { interaction.reply(text); } } ``` -------------------------------- ### Configure TSyringe DI Engine Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/basics/dependency-injection.md Set the TSyringe DI engine for discordx. Ensure the container reference is set from your side due to how shared containers work. ```typescript import { DIService, tsyringeDependencyRegistryEngine } from "discordx"; import { container } from "tsyringe"; DIService.engine = tsyringeDependencyRegistryEngine.setInjector(container); // set the container ``` -------------------------------- ### Apply NotBot Guard to Slash Command Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/decorators/general/guard.md This example demonstrates how to apply the 'NotBot' guard to a slash command using the @Guard decorator. The guardData object passed from the guard is accessible within the command handler. ```typescript import { CommandInteraction } from "discord.js"; import { Client, Discord, Guard, Slash } from "discordx"; import { NotBot } from "./NotBot"; @Discord() class Example { @Slash({ description: "hello" }) @Guard(NotBot) async hello( interaction: CommandInteraction, client: Client, guardData: { message: string }, ) { console.log(guardData.message); // > the NotBot guard passed } } ``` -------------------------------- ### Example Usage of @Bot Decorator Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/decorators/general/bot.md Use the @Bot decorator to specify which bots can run the commands or events defined within the decorated class. Ensure bot IDs are correctly defined and clients are logged in after building the application metadata. ```typescript @Discord() @Bot("alex", "zoe") // Define which bot can run the following commands or events class Example { @SimpleCommand() hello(command: SimpleCommandMessage) { command.message.reply(`👋 ${message.member}`); } } const alex = new Client({ botId: "alex", // define botId }); const zoe = new Client({ botId: "zoe", // define botId }); // We will now build our application to load all the commands/events for both bots. MetadataStorage.instance.build().then(() => { // Now that the app is ready, we can login to both bots alex.login("alex token"); zoe.login("zoe token"); }); ``` -------------------------------- ### Enable Tokenization with TSyringe Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/basics/dependency-injection.md To enable tokenization with TSyringe, call `setUseTokenization(true)` and `setCashingSingletonFactory(instanceCachingFactory)` on the `tsyringeDependencyRegistryEngine` during Discordx initialization. ```typescript import { container, instanceCachingFactory } from "tsyringe"; import { DIService } from "discordx"; import { tsyringeDependencyRegistryEngine } from "discordx"; DIService.engine = tsyringeDependencyRegistryEngine .setUseTokenization(true) .setCashingSingletonFactory(instanceCachingFactory) .setInjector(container); ``` -------------------------------- ### Import YTDL Player Plugin Source: https://github.com/discordx-ts/discordx/blob/main/packages/plugin-ytdl-player/README.md Import the YTDL player plugin to enable its functionality in your discordx bot. Ensure this import is placed at the top of your main bot file. ```typescript import "@discordx/plugin-ytdl-player"; ``` -------------------------------- ### Configure TypeDi DI Engine Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/basics/dependency-injection.md Configure TypeDi for discordx by setting both the service and the injector. This enables TypeDi's dependency injection capabilities. ```typescript import { DIService, typeDiDependencyRegistryEngine } from "discordx"; import { Container, Service } from "typedi"; DIService.engine = typeDiDependencyRegistryEngine .setService(Service) .setInjector(Container); ``` -------------------------------- ### Create Basic Slash Commands Source: https://context7.com/discordx-ts/discordx/llms.txt Defines slash commands using the @Discord and @Slash decorators. @Discord marks a class as command container, while @Slash defines individual commands with options. ```typescript import { ApplicationCommandOptionType, type CommandInteraction } from "discord.js"; import { Discord, Slash, SlashOption } from "discordx"; @Discord() class Commands { @Slash({ description: "Say hello to a user", name: "hello" }) async hello( @SlashOption({ description: "User to greet", name: "user", required: true, type: ApplicationCommandOptionType.User, }) user: User, interaction: CommandInteraction ): Promise { await interaction.reply(`Hello, ${user}!`); } @Slash({ description: "Add two numbers", name: "add" }) async add( @SlashOption({ description: "First number", name: "x", required: true, type: ApplicationCommandOptionType.Number, }) x: number, @SlashOption({ description: "Second number", name: "y", required: true, type: ApplicationCommandOptionType.Number, }) y: number, interaction: CommandInteraction ): Promise { await interaction.reply(`Result: ${x + y}`); } } ``` -------------------------------- ### Create Context Menu Commands with @ContextMenu Source: https://context7.com/discordx-ts/discordx/llms.txt Use the @ContextMenu decorator to create right-click context menu options for users and messages. Specify the command type as User or Message. ```typescript import { ApplicationCommandType, type MessageContextMenuCommandInteraction, type UserContextMenuCommandInteraction, } from "discord.js"; import { ContextMenu, Discord } from "discordx"; @Discord() class ContextMenuExample { @ContextMenu({ name: "Get User Info", type: ApplicationCommandType.User, }) async getUserInfo(interaction: UserContextMenuCommandInteraction): Promise { const user = interaction.targetUser; await interaction.reply({ content: `User: ${user.tag}\nID: ${user.id}\nCreated: ${user.createdAt.toDateString()}`, ephemeral: true, }); } @ContextMenu({ name: "Report Message", type: ApplicationCommandType.Message, }) async reportMessage(interaction: MessageContextMenuCommandInteraction): Promise { const message = interaction.targetMessage; await interaction.reply({ content: `Message reported.\nContent: "${message.content}"\nAuthor: ${message.author.tag}`, ephemeral: true, }); } } ``` -------------------------------- ### Enable Direct Messages with Partial Configuration Source: https://github.com/discordx-ts/discordx/blob/main/docs/docs/discordx/basics/client.md To receive direct messages, you must enable the DirectMessages intent and configure partials for channels and messages. This allows your bot to respond to DMs. ```typescript import { IntentsBitField, Partials } from "discord.js"; const client = new Client({ botId: "test", // partial configuration required to enable direct messages partials: [Partials.Channel, Partials.Message], intents: [ IntentsBitField.Flags.Guilds, IntentsBitField.Flags.GuildMessages, IntentsBitField.Flags.DirectMessages, ], // ... }); ```