### Create a new Sapphire project Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/getting-started.mdx Initiate a new Sapphire project by running the `sapphire new` command. This command will guide you through project setup with interactive prompts. ```bash sapphire new ``` -------------------------------- ### Install @sapphire/ratelimits Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/utilities/ratelimits.mdx Install the package using npm, yarn, or pnpm. ```bash npm install @sapphire/ratelimits ``` -------------------------------- ### Install Sapphire CLI with Volta Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/getting-started.mdx If you use Volta for Node.js version management, you can install the Sapphire CLI using the `volta install` command. ```bash volta install @sapphire/cli ``` -------------------------------- ### Example: Generate a Message Command Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/generating-components.mdx This example demonstrates how to generate a new message command named 'HelloWorld' using the Sapphire CLI. ```bash sapphire generate messagecommand HelloWorld ``` -------------------------------- ### Install @sapphire/plugin-i18next Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/plugins/i18next/getting-started.mdx Install the plugin along with its dependencies using npm, yarn, or pnpm. ```bash npm install @sapphire/plugin-i18next @sapphire/framework discord.js@14.x ``` -------------------------------- ### Install Sapphire Logger Plugin Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/plugins/Logger/getting-started.mdx Install the logger plugin and framework using npm, yarn, or pnpm. ```bash npm install @sapphire/plugin-logger @sapphire/framework ``` -------------------------------- ### Install Sapphire CLI with npm/pnpm Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/getting-started.mdx Install the Sapphire CLI globally using npm or pnpm. This makes the `sapphire` command available system-wide. ```bash npm install -g @sapphire/cli ``` ```bash pnpm add -g @sapphire/cli ``` -------------------------------- ### Install Stopwatch Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/utilities/stopwatch.mdx Install the @sapphire/stopwatch package using npm, yarn, or pnpm. ```bash npm install @sapphire/stopwatch ``` -------------------------------- ### Install Sapphire Plugin API Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/plugins/API/getting-started.mdx Install the necessary packages for the Sapphire Plugin API using npm, yarn, or pnpm. ```bash npm install @sapphire/plugin-api @sapphire/framework discord.js@14.x discord-api-types@0.37.x ``` -------------------------------- ### Install Editable Commands Plugin Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/plugins/plugin-editable-commands.mdx Install the editable commands plugin and the framework. Use npm, yarn, or pnpm. ```bash npm install @sapphire/plugin-editable-commands @sapphire/framework ``` -------------------------------- ### Initialize Sapphire CLI Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/getting-started.mdx Run this command to start the initialization process for Sapphire CLI in your project. ```bash sapphire init ``` -------------------------------- ### Install Subcommands Plugin Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/plugins/Subcommands/getting-started.mdx Install the necessary packages for the Subcommands plugin using npm, yarn, or pnpm. ```bash npm install @sapphire/plugin-subcommands @sapphire/framework @sapphire/utilities discord.js@14.x ``` -------------------------------- ### Install Discord Utilities Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/utilities/Discord_Utilities/UsefulRegexes.mdx Install the @sapphire/discord-utilities package to use the provided regexes. ```bash npm install @sapphire/discord-utilities ``` -------------------------------- ### Install Sapphire Framework and Discord.js Source: https://github.com/sapphiredev/website/blob/main/docs/General/Welcome.mdx Install the core Sapphire framework and Discord.js v14.x. Ensure you have Node.js 18.x or newer. ```bash npm install @sapphire/framework discord.js@14.x ``` -------------------------------- ### Initialize Sapphire Client Source: https://github.com/sapphiredev/website/blob/main/docs/General/Welcome.mdx Basic setup for initializing a Sapphire client with guild and message intents. Replace 'your-token-goes-here' with your actual bot token. ```typescript import { SapphireClient } from '@sapphire/framework'; const client = new SapphireClient({ intents: ['GUILDS', 'GUILD_MESSAGES'] }); client.login('your-token-goes-here'); ``` -------------------------------- ### Declarative Options Setup Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/arguments/using-options.mdx Enable automatic parsing of all arguments starting with two hyphens. This simplifies option handling but may parse unintended arguments. ```typescript import { ApplyOptions } from '@sapphire/decorators'; import { Command, Args } from '@sapphire/framework'; import type { Message } from 'discord.js'; export class OptionsCommand extends Command { public constructor(context: Command.LoaderContext, options: Command.Options) { super(context, { ...options, options: true }); } public async messageRun(message: Message, args: Args) { const [size, format] = args.getOptions('size', 'format'); } ``` -------------------------------- ### Install Snowflake Package Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/utilities/snowflake.mdx Install the @sapphire/snowflake package using npm, yarn, or pnpm. ```bash npm install @sapphire/snowflake ``` -------------------------------- ### Configure project language Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/getting-started.mdx Choose between TypeScript (recommended) and JavaScript for your new Sapphire project during the `sapphire new` setup. ```bash sapphire new √ What's the name of your project? ... my-sapphire-bot ? Choose a language for your project » - Use arrow-keys. Return to submit. > TypeScript (Recommended) JavaScript ``` -------------------------------- ### Install Sapphire CLI with Yarn dlx Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/getting-started.mdx Use the `yarn dlx` command to execute the Sapphire CLI without a global installation. This is useful for environments where global packages are not preferred or available. ```bash yarn dlx @sapphire/cli ``` -------------------------------- ### Imperative Options Setup Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/arguments/using-options.mdx Define specific options to be parsed by the command. This prevents unexpected parsing of other arguments as options. ```typescript import { ApplyOptions } from '@sapphire/decorators'; import { Command, Args } from '@sapphire/framework'; import type { Message } from 'discord.js'; export class OptionsCommand extends Command { public constructor(context: Command.LoaderContext, options: Command.Options) { super(context, { ...options, options: ['size'] }); } public async messageRun(message: Message, args: Args) {} ``` -------------------------------- ### Manually Start API on Shard Ready Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/plugins/API/starting-on-single-cluster-or-shard.mdx In your `shardReady` listener, check if the shard ID is 0 and then call `this.container.server.connect()` to start the API on the primary shard. ```typescript import { Events, Listener } from '@sapphire/framework'; export class UserShardEvent extends Listener { public run(id: number, unavailableGuilds: Set | undefined) { if (id === 0) { this.container.server.connect(); } } } ``` -------------------------------- ### Configure config file format Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/getting-started.mdx Choose the format for your project's configuration file, supporting either JSON or YAML, during the `sapphire new` setup. ```bash sapphire new √ What's the name of your project? ... my-sapphire-bot √ Choose a language for your project » TypeScript (Recommended) √ Choose a template for your project » Default template (Recommended) ? What format do you want your config file to be in? » - Use arrow-keys. Return to submit. JSON > YAML ``` -------------------------------- ### Basic Refresh Route Setup Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/plugins/API/oauth2-refresh-token.mdx Initializes a new route for handling token refreshes. This serves as the basic structure for the refresh logic. ```typescript import { methods, Route } from '@sapphire/plugin-api'; export class RefreshRoute extends Route { public async run(request: Route.Request, response: Route.Response) { // implementation } } ``` -------------------------------- ### Configure package manager Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/getting-started.mdx Select your preferred package manager, either npm or Yarn, for your new Sapphire project during the `sapphire new` setup. ```bash sapphire new √ What's the name of your project? ... my-sapphire-bot √ Choose a language for your project » TypeScript (Recommended) √ Choose a template for your project » Default template (Recommended) √ What format do you want your config file to be in? » YAML ? What package manager do you want to use? » - Use arrow-keys. Return to submit. > Yarn (Recommended) npm ``` -------------------------------- ### Directly listen to raw WebSocket events Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/listeners/listening-to-events-emitted-by-other-emitters.mdx This example shows the equivalent of the previous snippets using the client's WebSocket instance directly. It captures raw packet data. ```typescript client.ws.on('GUILD_MEMBER_ADD', (data) => { // `data` here is the raw packet }); ``` -------------------------------- ### Registering a Chat Input Command Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/getting-started/updating-from-v2-to-v3.mdx This example demonstrates how to register a chat input command and define its interaction handler. It overrides the `registerApplicationCommands` method to define the command's structure and the `chatInputRun` method to handle user interactions. ```typescript import { Command } from '@sapphire/framework'; export class SlashCommand extends Command { public constructor(context: Command.LoaderContext, options: Command.Options) { super(context, { ...options, description: 'Says hello.' }); } public override registerApplicationCommands(registry: Command.Registry) { registry.registerChatInputCommand((builder) => builder // .setName(this.name) .setDescription(this.description) ); } public override chatInputRun(interaction: Command.ChatInputInteraction) { return interaction.reply({ content: `Hello World!` }); } } ``` -------------------------------- ### Example Discord Application Command Object Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/commands/application-commands/application-command-registry/registering-chat-input-commands.mdx This JSON object represents a typical Application Command Object managed by Discord. It includes essential fields like 'id', 'application_id', 'name', and 'description'. ```json { "id": "1223334444555554444", "application_id": "...", // ... "name": "foo", "description": "bar!" } ``` -------------------------------- ### Responding to a Slash Command Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/getting-started/creating-a-basic-app-command.mdx Implement `chatInputRun` to handle user interactions with a registered slash command. This example shows how to reply with a message, calculate round-trip and heartbeat ping, and edit the reply. ```typescript import { isMessageInstance } from '@sapphire/discord.js-utilities'; import { Command } from '@sapphire/framework'; import { MessageFlags } from 'discord.js'; export class PingCommand extends Command { public constructor(context: Command.LoaderContext, options: Command.Options) { super(context, { ...options }); } public override registerApplicationCommands(registry: Command.Registry) { registry.registerChatInputCommand((builder) => builder.setName('ping').setDescription('Ping bot to see if it is alive') ); } public override async chatInputRun(interaction: Command.ChatInputCommandInteraction) { const callbackResponse = await interaction.reply({ content: `Ping?`, withResponse: true, flags: MessageFlags.Ephemeral }); const msg = callbackResponse.resource?.message; if (msg && isMessageInstance(msg)) { const diff = msg.createdTimestamp - interaction.createdTimestamp; const ping = Math.round(this.container.client.ws.ping); return interaction.editReply(`Pong 🏓! (Round trip took: ${diff}ms. Heartbeat: ${ping}ms.)`); } return interaction.editReply('Failed to retrieve ping :('); } } ``` -------------------------------- ### Handling Button Presses with `parse` and `run` Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/interaction-handlers/what-are-they.mdx This example demonstrates how to use an Interaction Handler to process button clicks. The `parse` method fetches data from a database, and if successful, the `run` method replies with the project name. ```typescript import { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework'; import type { ButtonInteraction } from 'discord.js'; import type { Project } from '@prisma/client'; export class HowDoWeUseThemExample extends InteractionHandler { public constructor(ctx: InteractionHandler.LoaderContext, options: InteractionHandler.Options) { super(ctx, { ...options, interactionHandlerType: InteractionHandlerTypes.Button }); } public async run(interaction: ButtonInteraction, project: Project) { await interaction.reply({ content: `The first project in TypeScript is called: ${project.name}` }); } public async parse(interaction: ButtonInteraction) { if (interaction.customId !== 'awesome-typescript') return this.none(); const dataFromDatabase = await this.container.prisma.project.findFirst({ where: { projectLanguage: 'typescript' } }); return this.some(dataFromDatabase); } } ``` -------------------------------- ### Create a Global Banlist Precondition Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/preconditions/global-preconditions.mdx This example shows how to create a global precondition that checks if a server is banned. It uses `AllFlowsPrecondition` to apply to all command types and includes a `position` of 20. The precondition checks against a Prisma database for banned guilds and returns an error if the guild is found, otherwise it allows the command to proceed. It handles DM commands by allowing them to run. ```typescript import { AllFlowsPrecondition, Piece, Result } from '@sapphire/framework'; import type { ChatInputCommandInteraction, ContextMenuCommandInteraction, Message } from 'discord.js'; export class UserPrecondition extends AllFlowsPrecondition { #message = "Sorry but your server is banned from using this bot's commands. Contact the bot developer for more information."; public constructor(context: AllFlowsPrecondition.LoaderContext, options: AllFlowsPrecondition.Options) { super(context, { ...options, position: 20 }); } public override chatInputRun(interaction: ChatInputCommandInteraction) { return this.doBanlistCheck(interaction.guildId); } public override contextMenuRun(interaction: ContextMenuCommandInteraction) { return this.doBanlistCheck(interaction.guildId); } public override messageRun(message: Message) { return this.doBanlistCheck(message.guildId); } private async doBanlistCheck(guildId: string | null) { if (guildId === null) return this.ok(); const isInBannedGuild = await Result.fromAsync( this.container.prisma.bannedGuilds.findFirstOrThrow({ where: { snowflake: BigInt(guildId) } }) ); // SQL query failed, therefore no guild was found, therefore the guild is not banned. if (isInBannedGuild.isErr()) return this.ok(); // Guild was found, therefore it is banned. return this.error({ identifier: 'GuildInBanList', message: this.#message }); } } ``` -------------------------------- ### Registering Subcommand Groups and Subcommands Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/plugins/Subcommands/subcommand-groups.mdx This example demonstrates how to extend the `Subcommand` class to define a base command with subcommands and subcommand groups. It registers the chat input commands, including nested subcommands within a group, and maps them to specific class methods. ```typescript import { Subcommand } from '@sapphire/plugin-subcommands'; // Extend `Subcommand` instead of `Command` export class UserCommand extends Subcommand { public constructor(context: Subcommand.LoaderContext, options: Subcommand.Options) { super(context, { ...options, name: 'vip', subcommands: [ { name: 'list', chatInputRun: 'chatInputList' }, { name: 'action', type: 'group', entries: [ { name: 'add', chatInputRun: 'chatInputAdd' }, { name: 'remove', chatInputRun: 'chatInputRemove' } ] } ] }); } registerApplicationCommands(registry: Subcommand.Registry) { registry.registerChatInputCommand((builder) => builder .setName('vip') .setDescription('Vip command') // Needed even though base command isn't displayed to end user .addSubcommand((command) => command.setName('list').setDescription('List vips')) .addSubcommandGroup((group) => group .setName('action') .setDescription('action subcommand group') // Also needed even though the group isn't displayed to end user .addSubcommand((command) => command .setName('add') .setDescription('Add a vip') .addUserOption((option) => option.setName('user').setDescription('user to add to vip list').setRequired(true) ) ) .addSubcommand((command) => command .setName('remove') .setDescription('Remove a vip') .addUserOption((option) => option.setName('user').setDescription('user to remove from vip list').setRequired(true) ) ) ) ); } public async chatInputList(interaction: Subcommand.ChatInputCommandInteraction) {} public async chatInputAdd(interaction: Subcommand.ChatInputCommandInteraction) {} public async chatInputRemove(interaction: Subcommand.ChatInputCommandInteraction) {} } ``` -------------------------------- ### Registering a Chat Input Command with Options Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/commands/application-commands/application-command-registry/registering-chat-input-commands.mdx Register a Chat Input Command that accepts user input options. This example demonstrates adding a required 'user' option using `addUserOption`, which allows the command to take a user as an argument. ```typescript import { Command } from '@sapphire/framework'; export class SlashCommand extends Command { public constructor(context: Command.LoaderContext, options: Command.Options) { super(context, { ...options, description: 'Say hello to a user.' }); } public override registerApplicationCommands(registry: Command.Registry) { registry.registerChatInputCommand((builder) => builder // .setName(this.name) .setDescription(this.description) .addUserOption((option) => option // .setName('user') .setDescription('User to say hello to') .setRequired(true) ) ); } public override chatInputRun(interaction: Command.ChatInputCommandInteraction) { // ... } } ``` -------------------------------- ### Initialize Sapphire Client and Login Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/getting-started/getting-started-with-sapphire.mdx This snippet shows how to import `SapphireClient` and `GatewayIntentBits`, instantiate the client with necessary intents, and log in the bot using a token. It's recommended to use environment variables for your token. ```typescript import { SapphireClient } from '@sapphire/framework'; import { GatewayIntentBits } from 'discord.js'; const client = new SapphireClient({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages] }); client.login('your-token-goes-here'); ``` -------------------------------- ### View README for New Sapphire Bot Project (Bash) Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/getting-started.mdx After creating a project, view its README.md file using the 'cat' command in Bash to understand the next steps. ```bash cat my-sapphire-bot/README.md # TypeScript Sapphire Bot example This is a basic setup of a Discord bot using the [sapphire framework][sapphire] written in TypeScript ... ``` -------------------------------- ### Create a GET Route Handler Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/plugins/API/adding-routes.mdx Define a GET request handler by extending the `Route` class and implementing the `run` method. This handler will be invoked when a GET request matches the route defined by the filename. ```typescript import { Route } from '@sapphire/plugin-api'; export class UserRoute extends Route { public run(_request: Route.Request, response: Route.Response) { response.json({ message: 'Hello World' }); } } ``` -------------------------------- ### View README for New Sapphire Bot Project (PowerShell) Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/getting-started.mdx After creating a project, view its README.md file using the 'Get-Content' command in PowerShell to understand the next steps. ```powershell Get-Content .\my-sapphire-bot\README.md # TypeScript Sapphire Bot example This is a basic setup of a Discord bot using the [sapphire framework][sapphire] written in TypeScript ... ``` -------------------------------- ### View README for New Sapphire Bot Project (CMD) Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/getting-started.mdx After creating a project, view its README.md file using the 'type' command in CMD to understand the next steps. ```batch type my-sapphire-bot\README.md # TypeScript Sapphire Bot example This is a basic setup of a Discord bot using the [sapphire framework][sapphire] written in TypeScript ... ``` -------------------------------- ### Import the Virtual Pieces Load File Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/additional-information/registering-virtual-pieces.mdx Import the `_load` file from your entry point to register all virtual pieces within that directory. ```javascript require('./listeners/_load'); ``` ```typescript import './listeners/_load'; ``` ```javascript import './listeners/_load'; ``` -------------------------------- ### Button Interaction Handler Example Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/interaction-handlers/what-are-they.mdx This example demonstrates a button interaction handler. The `parse` method filters interactions based on `customId` and returns data to be used in the `run` method. The `run` method replies to the interaction with the processed data. ```typescript import { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework'; export class ParseExampleInteractionHandler extends InteractionHandler { public constructor(ctx) { super(ctx, { interactionHandlerType: InteractionHandlerTypes.Button }); } // We'll look a little later in this guide on how to type this method, but for now, we'll type it as any. public async run(interaction: ButtonInteraction, awesomenessLevel: any) { // The `awesomenessLevel` variable has what we returned in the `parse` method's // `this.some`! In this example, we just show it to the user await interaction.reply({ content: `Your awesomeness level is: **${awesomenessLevel}**` }); } public parse(interaction: ButtonInteraction) { // If the custom id does not start with `is-user-awesome`, we do not want this // handler to run. if (!interaction.customId.startsWith('is-user-awesome')) return this.none(); // Here we return a `Some` as said above, in this case passing 9001 to it // which we get back in the `run` method as the awesomneness level return this.some(9001); } } ``` -------------------------------- ### Select Config File Format (YAML) Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/getting-started.mdx Choose YAML as the format for your Sapphire CLI configuration file during initialization. ```bash sapphire init ? What format do you want your config file to be in? » - Use arrow-keys. Return to submit. JSON > YAML ``` -------------------------------- ### Configure package.json for Sapphire Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/getting-started/getting-started-with-sapphire.mdx Set the 'main' property in your package.json to specify the entry point of your bot. This is crucial for Sapphire to locate your bot's pieces. ```json { "name": "my-awesome-new-bot", "main": "src/index.js", "dependencies": { "@sapphire/framework": "latest", "discord.js": "14.x" }, "scripts": { "start": "node src/index.js" } } ``` -------------------------------- ### Initialize Sapphire CLI Project Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/getting-started.mdx Run this command to initialize the Sapphire CLI in your project. It will prompt you for configuration details like config file format, project language, and directory structures. ```bash sapphire init √ What format do you want your config file to be in? » YAML √ Choose the language used in your project » TypeScript √ Your base directory ... src √ Where do you store your commands? (do not include the base) ... commands √ Where do you store your listeners? (do not include the base) ... listeners √ Where do you store your arguments? (do not include the base) ... arguments √ Where do you store your preconditions? (do not include the base) ... preconditions ? Do you want to enable custom file templates? » ``` ```bash sapphire init √ What format do you want your config file to be in? » YAML √ Choose the language used in your project » TypeScript √ Your base directory ... src √ Where do you store your commands? (do not include the base) ... commands √ Where do you store your listeners? (do not include the base) ... listeners √ Where do you store your arguments? (do not include the base) ... arguments √ Where do you store your preconditions? (do not include the base) ... preconditions √ Do you want to enable custom file templates? ... no ``` -------------------------------- ### Create a New Sapphire Bot Project Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/getting-started.mdx Use the 'sapphire new' command to initiate a new bot project. Follow the prompts to configure project name, language, template, config format, package manager, and Git repository. ```bash sapphire new √ What's the name of your project? ... my-sapphire-bot √ Choose a language for your project » TypeScript (Recommended) √ Choose a template for your project » Default template (Recommended) √ What format do you want your config file to be in? » YAML √ What package manager do you want to use? » Yarn (Recommended) √ Do you want to use Yarn v3? ... yes √ Do you want to create a git repository for this project? ... yes ✔ Cloning the repository ✔ Setting up the project ✔ Initializing git repo ✔ Installing Yarn v3 ✔ Installing Yarn Typescript Plugin ✔ Installing dependencies using Yarn Done! ``` -------------------------------- ### WebSocket URL Regex Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/utilities/Discord_Utilities/UsefulRegexes.mdx Matches any URL that starts with 'ws://' or 'wss://'. Useful for validating WebSocket connections. ```regex ^wss?:\/\/ ``` -------------------------------- ### Configure project template Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/getting-started.mdx Select a project template, such as the default template, with Docker, with tsup, or with SWC, when creating a new Sapphire project. ```bash sapphire new √ What's the name of your project? ... my-sapphire-bot √ Choose a language for your project » TypeScript (Recommended) ? Choose a template for your project » - Use arrow-keys. Return to submit. > Default template (Recommended) with Docker with tsup with SWC ``` -------------------------------- ### HTTP URL Regex Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/utilities/Discord_Utilities/UsefulRegexes.mdx Matches any URL that starts with 'http://' or 'https://'. Useful for validating web links. ```regex ^https?:\/\/ ``` -------------------------------- ### Register Editable Commands Plugin (ESM) Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/plugins/plugin-editable-commands.mdx Register the editable commands plugin in your main or setup file using ESM. ```javascript import '@sapphire/plugin-editable-commands/register'; ``` -------------------------------- ### Basic Command Implementation Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/getting-started/creating-a-basic-command.mdx This code demonstrates a basic command structure in Sapphire, including initialization with options and handling message interactions. It defines a 'ping' command that responds with latency information. ```typescript import { Command } from '@sapphire/framework'; import type { Message } from 'discord.js'; export class PingCommand extends Command { public constructor(context: Command.LoaderContext, options: Command.Options) { super(context, { ...options, name: 'ping', aliases: ['pong'], description: 'ping pong' }); } public async messageRun(message: Message) { const msg = await message.channel.send('Ping?'); const content = `Pong from JavaScript! Bot Latency ${Math.round(this.container.client.ws.ping)}ms. API Latency ${ msg.createdTimestamp - message.createdTimestamp }ms.`; return msg.edit(content); } } ``` -------------------------------- ### Enable API Plugin Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/getting-started.mdx Choose whether to enable the API plugin during Sapphire CLI initialization. Enter 'y' to enable. ```bash sapphire init √ What format do you want your config file to be in? » YAML √ Choose the language used in your project » TypeScript √ Your base directory ... src √ Where do you store your commands? (do not include the base) ... commands √ Where do you store your listeners? (do not include the base) ... listeners √ Where do you store your arguments? (do not include the base) ... arguments √ Where do you store your preconditions? (do not include the base) » preconditions √ Where do you store your interaction-handlers? (do not include the base) » interaction-handlers ? Would you use the api plugin? » (y/N) ``` -------------------------------- ### Register Editable Commands Plugin (CommonJS) Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/plugins/plugin-editable-commands.mdx Register the editable commands plugin in your main or setup file using CommonJS. ```javascript require('@sapphire/plugin-editable-commands/register'); ``` -------------------------------- ### Disable Automatic API Connection Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/plugins/API/starting-on-single-cluster-or-shard.mdx Set `automaticallyConnect` to `false` in the `api` options within `ClientOptions` to prevent the API from starting on all shards. ```typescript import { SapphireClient } from '@sapphire/framework'; const client = new SapphireClient({ api: { automaticallyConnect: false } }); ``` -------------------------------- ### Basic Project Directory Structure Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/getting-started/getting-started-with-sapphire.mdx This illustrates a typical project directory structure for a Sapphire bot, including essential files and folders like `node_modules`, `package.json`, and the `src` directory containing `index.js`. ```bash ├── node_modules ├── package.json └── src └── index.js ``` -------------------------------- ### Module Augmentation for DetailedDescriptionCommandObject Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/commands/command-options.mdx Augment the DetailedDescriptionCommandObject interface to include custom properties like usage, examples, and extendedHelp for detailed command descriptions. ```typescript declare module '@sapphire/framework' { export interface DetailedDescriptionCommandObject { usage: string; examples: string[]; extendedHelp: string; } } ``` -------------------------------- ### Basic Command Structure with Arguments Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/arguments/using-arguments.mdx Sets up a basic command class that includes the necessary imports and constructor for handling arguments in message commands. ```typescript import { Command, Args } from '@sapphire/framework'; import type { Message } from 'discord.js'; export class EchoCommand extends Command { public constructor(context: Command.LoaderContext, options: Command.Options) { super(context, { ...options, aliases: ['parrot', 'copy'], description: 'Replies with the text you provide' }); } public async messageRun(message: Message, args: Args) { // ... } } ``` -------------------------------- ### Project Directory Structure (ESM) Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/listeners/creating-your-own-listeners.mdx Illustrates the expected directory structure for a Sapphire.js project using ESM, highlighting the 'listeners' subdirectory. ```bash ├── node_modules ├── package.json └── src ├── commands │ └── ping.mjs ├── index.mjs └── listeners └── ready.mjs ``` -------------------------------- ### Button Interaction Handler Example Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/interaction-handlers/buttons.mdx Handles button clicks by responding with an ephemeral message. Ensure the button's custom ID matches 'my-awesome-button'. ```typescript import { InteractionHandler, InteractionHandlerTypes } from '@sapphire/framework'; import { MessageFlags } from 'discord.js'; import type { ButtonInteraction } from 'discord.js'; export class ButtonHandler extends InteractionHandler { public constructor(ctx: InteractionHandler.LoaderContext, options: InteractionHandler.Options) { super(ctx, { ...options, interactionHandlerType: InteractionHandlerTypes.Button }); } public override parse(interaction: ButtonInteraction) { if (interaction.customId !== 'my-awesome-button') return this.none(); return this.some(); } public async run(interaction: ButtonInteraction) { await interaction.reply({ content: 'Hello from a button interaction handler!', // Let's make it so only the person who pressed the button can see this message! flags: MessageFlags.Ephemeral }); } } ``` -------------------------------- ### Project Directory Structure (TypeScript) Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/listeners/creating-your-own-listeners.mdx Illustrates the expected directory structure for a Sapphire.js project using TypeScript, highlighting the 'listeners' subdirectory. ```bash ├── node_modules ├── package.json └── src ├── commands │ └── ping.ts ├── index.ts └── listeners └── ready.ts ``` -------------------------------- ### Require Client Permissions for Commands Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/preconditions/handling-permissions.mdx Use `requiredClientPermissions` to ensure the bot has the necessary permissions to execute a command. This example adds the 'Ban Members' permission requirement for the bot. ```typescript import { Command } from '@sapphire/framework'; import { PermissionFlagsBits } from 'discord.js'; export class BanCommand extends Command { public constructor(context: Command.LoaderContext) { super(context, { // ... requiredUserPermissions: [PermissionFlagsBits.BanMembers], requiredClientPermissions: [PermissionFlagsBits.BanMembers] }); } } ``` -------------------------------- ### Limit Repeating Arguments with 'times' Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/arguments/using-arguments.mdx Use `args.repeat('member', { times: 5 })` to limit the number of repeating arguments parsed. This example limits to a maximum of 5 members. ```typescript import { Command, Args } from '@sapphire/framework'; import type { Message } from 'discord.js'; export class MathsCommand extends Command { public constructor(context: Command.LoaderContext, options: Command.Options) { super(context, { ...options, description: 'Adds two numbers' }); } public async messageRun(message: Message, args: Args) { const members = await args.repeat('member', { times: 5 }); // ... } } ``` -------------------------------- ### Project Directory Structure (CommonJS) Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/listeners/creating-your-own-listeners.mdx Illustrates the expected directory structure for a Sapphire.js project using CommonJS, highlighting the 'listeners' subdirectory. ```bash ├── node_modules ├── package.json └── src ├── commands │ └── ping.js ├── index.js └── listeners └── ready.js ``` -------------------------------- ### Define Translation Key-Value Pairs (Dutch) Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/plugins/i18next/getting-started.mdx Provide translations for the `en-US` language strings in the `nl-NL` language file. This example shows how to translate the same keys, including interpolation variables. ```json { "success": "Pong!", "success_with_args": "Pong! Het heeft {{latency}}ms geduurd om te reageren" } ``` -------------------------------- ### Create a Load File for Virtual Pieces Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/additional-information/registering-virtual-pieces.mdx A common practice is to create a `_load` file within directories containing virtual pieces. This file imports all pieces in that directory, simplifying the entry point import. ```javascript require('./ready'); ``` ```typescript import './ready'; ``` ```javascript import './ready'; ``` -------------------------------- ### Configure Sapphire Plugin API Options Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/plugins/API/getting-started.mdx Configure authentication, route prefix, origin, and listen options for the Sapphire Plugin API. ```javascript const { OAuth2Scopes } = require('discord.js'); { auth: { // The application/client ID of your bot // You can find this at https://discord.com/developers/applications id: '', // The client secret of your bot // You can find this at https://discord.com/developers/applications secret: '', // The name of the authentication cookie cookie: 'SAPPHIRE_AUTH', // The URL that users should be redirected to after a successful authentication redirect: '', // The scopes that should be given to the authentication scopes: [OAuth2Scopes.Identify], // Transformers to transform the raw data from Discord to a different structure. transformers: [] }, // The prefix for all routes, e.g. / or v1/ prefix: '', // The origin header to be set on every request at 'Access-Control-Allow-Origin. origin: '*', // Any options passed to the NodeJS "net" internal server.listen function // See https://nodejs.org/api/net.html#net_server_listen_options_callback listenOptions: { // The port the API will listen on port: 4000 } } ``` -------------------------------- ### Basic Stopwatch Usage Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/utilities/stopwatch.mdx Import and use the Stopwatch class to measure elapsed time. The stopwatch starts immediately upon instantiation and can be stopped to retrieve the elapsed time as a string. ```typescript // Import the Stopwatch class import { Stopwatch } from '@sapphire/stopwatch'; // Create a new Stopwatch (which also starts it immediately) const stopwatch = new Stopwatch(); // run other task here console.log(stopwatch.stop().toString()); // 200ms ``` -------------------------------- ### GET Buffer Data with @sapphire/fetch Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/utilities/fetch.mdx Fetch binary data, such as images, using FetchResultTypes.Buffer. This is useful for downloading files or processing image data directly. Import fetch and FetchResultTypes from the package. ```typescript import { fetch, FetchResultTypes } from '@sapphire/fetch'; // Fetch the data. No need to call `.buffer()` after making the request! const sapphireLogo = await fetch('https://github.com/sapphiredev.png', FetchResultTypes.Buffer); // sapphireLogo is the `Buffer` of the image console.log(sapphireLogo); ``` -------------------------------- ### Configure Declarative Flags Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/arguments/using-flags.mdx Set `flags` to `true` in command options to enable declarative flags. This treats all arguments starting with two hyphens as flags without validation against command options. ```typescript import { ApplyOptions } from '@sapphire/decorators'; import { Command, CommandOptions, Args } from '@sapphire/framework'; import type { Message } from 'discord.js'; export class FlagsCommand extends Command { public constructor(context: Command.LoaderContext, options: Command.Options) { super(context, { ...options, flags: true }); } public async messageRun(message: Message, args: Args) { const firstArgument = await args.pick('string'); const isRequestingVersion = args.getFlags('version', 'v'); const secondArgument = await args.pick('string'); } } ``` -------------------------------- ### Implementing the Listener 'run' Method Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/listeners/creating-your-own-listeners.mdx Implements the 'run' method for a Sapphire.js listener to execute logic when the 'ready' event is triggered. Logs the bot's username and ID upon successful login. ```typescript import { Listener } from '@sapphire/framework'; import type { Client } from 'discord.js'; export class ReadyListener extends Listener { public run(client: Client) { const { username, id } = client.user!; this.container.logger.info(`Successfully logged in as ${username} (${id})`); } } ``` -------------------------------- ### Require User Permissions for Commands Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/preconditions/handling-permissions.mdx Use `requiredUserPermissions` to restrict command usage to users with specific Discord permissions. This example ensures only users with 'Ban Members' permission can use the ban command. ```typescript import { Command } from '@sapphire/framework'; import { PermissionFlagsBits } from 'discord.js'; export class BanCommand extends Command { public constructor(context: Command.LoaderContext) { super(context, { // ... requiredUserPermissions: [PermissionFlagsBits.BanMembers] }); } } ``` -------------------------------- ### Configure new project name Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/CLI/getting-started.mdx During the `sapphire new` process, you will be prompted to enter a name for your project. This name will be used as the directory name for your new project. ```bash sapphire new ? What's the name of your project? » my-sapphire-bot ``` -------------------------------- ### Implement Precondition Logic for All Command Types Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/preconditions/creating-your-own-preconditions.mdx Implement `messageRun`, `chatInputRun`, and `contextMenuRun` to handle different command interaction types. Use `this.ok()` to allow execution and `this.error()` to deny it, optionally providing a reason. ```typescript import { Precondition } from '@sapphire/framework'; import type { CommandInteraction, ContextMenuCommandInteraction, Message } from 'discord.js'; import { Config } from '#config'; export class OwnerOnlyPrecondition extends Precondition { public override async messageRun(message: Message) { // for Message Commands return this.checkOwner(message.author.id); } public override async chatInputRun(interaction: CommandInteraction) { // for Slash Commands return this.checkOwner(interaction.user.id); } public override async contextMenuRun(interaction: ContextMenuCommandInteraction) { // for Context Menu Command return this.checkOwner(interaction.user.id); } private async checkOwner(userId: string) { return Config.bot.owners!.includes(userId) ? this.ok() : this.error({ message: 'Only the bot owner can use this command!' }); } } ``` -------------------------------- ### Use Custom Array Argument in Command Source: https://github.com/sapphiredev/website/blob/main/docs/Guide/arguments/creating-your-own-arguments.mdx Pick a parameter using your custom 'array' argument and pass specific options in the context. This example demonstrates how to use the custom argument within a command. ```typescript import { Args, Command } from '@sapphire/framework'; import type { Message } from 'discord.js'; export class ArrayCommand extends Command { public async messageRun(message: Message, args: Args) { const parameter = await args.pick('array', { array: ['yes', 'no'] }); return message.reply(`Your parameter ${parameter} is valid!`); } } ```