Creating Your First Command
The main input for any Discord bot is its commands. In Seyfert, you can easily create and manage commands. Seyfert will handle loading and executing all the commands you create within the commands
folder (as specified in the configuration).
To get started, let’s create the following file and use the ping
command as an example.
All commands must use the @Declare
decorator for their information and a class that extends Command
:
Before you can execute new commands, you need to register them with Discord. You can do this using the following code:
import { class Client<Ready extends boolean = boolean>
Client } from 'seyfert';
const const client: Client<boolean>
client = new new Client<boolean>(options?: ClientOptions): Client<boolean>
Client();
const client: Client<boolean>
client.Client<boolean>.start(options?: Omit<DeepPartial<StartOptions>, "httpConnection">, execute?: boolean): Promise<void>
start() .Promise<void>.then<void, never>(onfulfilled?: ((value: void) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<...>
Attaches callbacks for the resolution and/or rejection of the Promise.
then(() => const client: Client<boolean>
client.BaseClient.uploadCommands({ applicationId, cachePath }?: { applicationId?: string; cachePath?: string;}): Promise<void>
uploadCommands({ cachePath?: string
cachePath: './commands.json' }));
With this, you can run your bot and test the /ping
command on Discord. You should see your bot’s latency!
Using Options
Simple enough, right? However, commands don’t always respond the same way every time you execute them. Sometimes, we need to interpret what the user actually needs. This is where options
come into play.
Let’s configure this command so its response is invisible to other users (an ephemeral message).
To achieve this, we’ll use the @Options
decorator and create a hide
option of type boolean:
import { class Command
Command, function Declare(declare: CommandDeclareOptions): <T extends { new (...args: any[]): object;}>(target: T) => { new (...args: any[]): { name: string; nsfw: boolean | undefined; props: ExtraProps | undefined; contexts: InteractionContextType[]; integrationTypes: ApplicationIntegrationType[]; defaultMemberPermissions: bigint | undefined; botPermissions: bigint | undefined; description: string; type: ApplicationCommandType; guildId?: string[]; ignore?: IgnoreCommand; aliases?: string[]; handler?: EntryPointCommandHandlerType; };} & T
Declare, function Options(options: (new () => SubCommand)[] | OptionsRecord): <T extends { new (...args: any[]): object;}>(target: T) => { new (...args: any[]): { options: SubCommand[] | CommandOption[]; };} & T
Options, function createBooleanOption<R extends boolean, T extends SeyfertBooleanOption<R> = SeyfertBooleanOption<R>>(data: T): T & { readonly type: ApplicationCommandOptionType.Boolean;}
createBooleanOption, type class CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>interface CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
CommandContext} from 'seyfert';import { MessageFlags } from 'seyfert/lib/types';
const const options: { hide: { description: string; } & { readonly type: ApplicationCommandOptionType.Boolean; };}
options = { hide: { description: string;} & { readonly type: ApplicationCommandOptionType.Boolean;}
hide: createBooleanOption<boolean, { description: string;}>(data: { description: string;}): { description: string;} & { readonly type: ApplicationCommandOptionType.Boolean;}
createBooleanOption({ description: string
description: "Hide the command's response", }),};
@function Declare(declare: CommandDeclareOptions): <T extends { new (...args: any[]): object;}>(target: T) => { new (...args: any[]): { name: string; nsfw: boolean | undefined; props: ExtraProps | undefined; contexts: InteractionContextType[]; integrationTypes: ApplicationIntegrationType[]; defaultMemberPermissions: bigint | undefined; botPermissions: bigint | undefined; description: string; type: ApplicationCommandType; guildId?: string[]; ignore?: IgnoreCommand; aliases?: string[]; handler?: EntryPointCommandHandlerType; };} & T
Declare({ name: string
name: 'ping', description: string
description: 'Show latency with Discord'})@function Options(options: (new () => SubCommand)[] | OptionsRecord): <T extends { new (...args: any[]): object;}>(target: T) => { new (...args: any[]): { options: SubCommand[] | CommandOption[]; };} & T
Options(const options: { hide: { description: string; } & { readonly type: ApplicationCommandOptionType.Boolean; };}
options)export default class class PingCommand
PingCommand extends class Command
Command {
async PingCommand.run(ctx: CommandContext<typeof options>): Promise<void>
run(ctx: CommandContext<{ hide: { description: string; } & { readonly type: ApplicationCommandOptionType.Boolean; };}, never>
ctx: class CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>interface CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
CommandContext<typeof const options: { hide: { description: string; } & { readonly type: ApplicationCommandOptionType.Boolean; };}
options>) { const const flags: MessageFlags.Ephemeral | undefined
flags = ctx: CommandContext<{ hide: { description: string; } & { readonly type: ApplicationCommandOptionType.Boolean; };}, never>
ctx.CommandContext<{ hide: { description: string; } & { readonly type: ApplicationCommandOptionType.Boolean; }; }, never>.options: ContextOptions<{ hide: { description: string; } & { readonly type: ApplicationCommandOptionType.Boolean; };}>
options.hide?: boolean | undefined
hide ? MessageFlags.function (enum member) MessageFlags.Ephemeral = 64
This message is only visible to the user who invoked the Interaction
Ephemeral : var undefined
undefined;
// Average latency between existing connections const const ping: number
ping = ctx: CommandContext<{ hide: { description: string; } & { readonly type: ApplicationCommandOptionType.Boolean; };}, never>
ctx.CommandContext<{ hide: { description: string; } & { readonly type: ApplicationCommandOptionType.Boolean; }; }, never>.client: UsingClient
client.Client<true>.gateway: ShardManager
gateway.ShardManager.latency: number
latency;
await ctx: CommandContext<{ hide: { description: string; } & { readonly type: ApplicationCommandOptionType.Boolean; };}, never>
ctx.CommandContext<{ hide: { description: string; } & { readonly type: ApplicationCommandOptionType.Boolean; }; }, never>.write<false>(body: InteractionCreateBodyRequest, withResponse?: false | undefined): Promise<void | WebhookMessage>
write({ content?: string | undefined
The message contents (up to 2000 characters)
content: `The latency is \`${const ping: number
ping}\``, flags?: MessageFlags | undefined
Message flags combined as a bitfield
flags, }); }}
The CommandContext
is extended with a generic to infer the type of options and provide access to them.
More information about command options can be found here.
Your project structure should look like this:
Directorysrc
Directorycommands
- ping.ts
- index.ts
- package.json
- seyfert.config.mjs
- tsconfig.json