Spraxium logoSpraxium

Definição e opções

Defina o schema de slash commands com o decorator @SlashCommand e opções tipadas. Entenda cada tipo de opção, restrição, choice e flag de configuração disponível na camada de definição do comando.

A classe de definição do comando

Uma definição de slash command é uma classe decorada com @SlashCommand que descreve o que o Discord deve mostrar no seletor de comandos. A classe em si não contém lógica de execução. A função dela é guardar metadados que o SlashRegistrar lê no boot para montar o payload JSON enviado para a API REST do Discord. As opções são declaradas como decorators de método em um método build(), e os subcomandos são declarados em métodos nomeados. A mesma classe pode ser importada por handlers, autocomplete handlers e testes sem puxar dependências de serviço.

O decorator @SlashCommand aceita um objeto SlashCommandConfig com as propriedades abaixo. Todo comando precisa informar pelo menos name e description. O restante controla permissões padrão, disponibilidade em DM, marcação NSFW, registro específico por guild e localização.

commands/ban.command.ts
import { SlashCommand, SlashOption } from '@spraxium/common';
import { PermissionFlagsBits } from 'discord.js';

@SlashCommand({
  name: 'ban',
  description: 'Ban a member from the server.',
  defaultMemberPermissions: PermissionFlagsBits.BanMembers,
})
export class BanCommand {
  @SlashOption.User('target', {
    description: 'The member to ban',
    required: true,
  })
  @SlashOption.String('reason', {
    description: 'Reason for the ban',
    required: false,
    maxLength: 512,
  })
  @SlashOption.Integer('days', {
    description: 'Number of days of messages to delete',
    required: false,
    min: 0,
    max: 7,
  })
  build() {}
}

Tipos de opção

O Spraxium oferece nove decorators de tipo de opção dentro do namespace SlashOption, um para cada tipo de opção de application command do Discord. Cada decorator é aplicado ao método build() da classe de comando, ou a um método decorado com @SlashSubcommand quando a opção pertence a um subcomando. Você empilha as opções no mesmo método, e a ordem dos decorators define a ordem de exibição no cliente do Discord, com o decorator mais alto aparecendo por último no seletor.

Todo decorator de opção recebe dois argumentos posicionais: o name da opção, usado no registro com o Discord e no matching de @SlashOpt, e um objeto config. Esse objeto estende SlashBaseOptionConfig com campos específicos de cada tipo.

Configuração base das opções

Os nove tipos de opção compartilham uma interface de configuração em comum. O campo description é a única propriedade obrigatória. O restante tem defaults sensatos, então você só precisa informar o que realmente importa para o seu caso.

PropriedadeTipoPadrãoDescrição
descriptionstring(obrigatório)

Descrição mostrada ao usuário no seletor de opções do Discord. Aceita de 1 a 100 caracteres.

requiredbooleanfalse

Define se o usuário precisa obrigatoriamente informar um valor. Quando está em false, o handler recebe null se a opção for omitida.

i18nSlashI18nKeysundefined

Chaves de localização para o nome e a descrição da opção, resolvidas pelo módulo de i18n.

Restrições de opções string

O decorator @SlashOption.String suporta quatro propriedades extras além da configuração base. Elas refletem diretamente as restrições que a API do Discord oferece para opções string e permitem controlar comprimento do texto, choices fixos e autocomplete.

commands/echo.command.ts
import { SlashCommand, SlashOption } from '@spraxium/common';

@SlashCommand({
  name: 'echo',
  description: 'Repeat a message back to the channel.',
})
export class EchoCommand {
  @SlashOption.String('message', {
    description: 'Text to echo',
    required: true,
    minLength: 1,
    maxLength: 2000,
  })
  build() {}
}
PropriedadeTipoDescrição
minLengthnumberComprimento mínimo aceito para o texto informado.
maxLengthnumberComprimento máximo aceito para o texto informado.
choicesLista de choicesConjunto fixo de valores exibido como dropdown.
autocompletebooleanAtiva sugestões dinâmicas à medida que o usuário digita.

Quando minLength ou maxLength está definido, o Discord valida o tamanho do texto no cliente antes de enviar a interação. Quando choices é informado, o usuário escolhe um valor em um dropdown em vez de digitar livremente. Quando autocomplete está em true, o Discord chama seu autocomplete handler enquanto o usuário digita, o que permite montar sugestões em tempo real a partir do seu código.

choices e autocomplete são mutuamente exclusivos

O Discord não permite combinar choices estáticos e autocomplete na mesma opção. Quando autocomplete está ativo, os choices estáticos são ignorados e apenas o autocomplete handler é consultado. Use choices para listas pequenas e fechadas, e autocomplete quando os valores forem dinâmicos, grandes ou dependerem de dados externos.

Restrições de opções numéricas

Tanto @SlashOption.Integer quanto @SlashOption.Number suportam as propriedades min e max, que definem a faixa de valores aceita. O Discord aplica essas restrições no cliente, então o handler já recebe um valor dentro do intervalo esperado, ou null quando a opção não é obrigatória e foi omitida. A variante Integer também suporta choices e autocomplete, enquanto a variante Number suporta apenas autocomplete.

import { SlashCommand, SlashOption } from '@spraxium/common';

@SlashCommand({ name: 'roll', description: 'Roll a dice.' })
export class RollCommand {
  @SlashOption.Integer('sides', {
    description: 'Number of sides on the dice',
    required: true,
    choices: [
      { name: '6-sided', value: 6 },
      { name: '12-sided', value: 12 },
      { name: '20-sided', value: 20 },
    ],
  })
  build() {}
}

Filtragem por tipo de canal

O decorator @SlashOption.Channel aceita um array channelTypes que restringe quais tipos de canal o usuário pode selecionar. Os valores correspondem aos membros do enum ChannelType do Discord. Quando o array é informado, o cliente do Discord só mostra no seletor os canais compatíveis com os tipos especificados.

commands/setup.command.ts
import { SlashCommand, SlashOption } from '@spraxium/common';
import { ChannelType } from 'discord.js';

@SlashCommand({
  name: 'setup',
  description: 'Configure the bot for this server.',
})
export class SetupCommand {
  @SlashOption.Channel('log-channel', {
    description: 'Channel for bot logs',
    required: true,
    channelTypes: [ChannelType.GuildText, ChannelType.GuildAnnouncement],
  })
  @SlashOption.Channel('voice-channel', {
    description: 'Default voice channel',
    required: false,
    channelTypes: [ChannelType.GuildVoice, ChannelType.GuildStageVoice],
  })
  build() {}
}
ChannelTypeValor numéricoDescrição
GuildText0Canal de texto padrão dentro de uma guild.
GuildVoice2Canal de voz dentro de uma guild.
GuildCategory4Categoria que agrupa outros canais.
GuildAnnouncement5Canal de anúncios dentro de uma guild.
AnnouncementThread10Thread criada dentro de um canal de anúncios.
PublicThread11Thread pública aberta para todos os membros do canal.
PrivateThread12Thread privada visível apenas para membros convidados.
GuildStageVoice13Canal de palco para eventos de áudio moderados.
GuildForum15Canal de fórum em que cada postagem cria uma thread.
GuildMedia16Canal de mídia para publicações com foco em conteúdo visual.

Localização com chaves de i18n

Tanto o decorator @SlashCommand quanto cada @SlashOption aceitam uma propriedade opcional i18n do tipo SlashI18nKeys. Esse objeto contém duas chaves string, name e description, que o módulo de i18n resolve para textos localizados durante o registro do comando. As localizações resolvidas são enviadas ao Discord no payload do comando, então o usuário enxerga nomes e descrições no idioma configurado no cliente dele.

commands/locale.command.ts
import { SlashCommand, SlashOption } from '@spraxium/common';

@SlashCommand({
  name: 'locale',
  description: 'Change your preferred language.',
  i18n: {
    name: 'commands.locale.name',
    description: 'commands.locale.description',
  },
})
export class LocaleCommand {
  @SlashOption.String('language', {
    description: 'The language to use.',
    required: true,
    i18n: {
      name: 'commands.locale.options.language.name',
      description: 'commands.locale.options.language.description',
    },
    choices: [
      { name: 'English (US)', value: 'en-US' },
      { name: 'Português (Brasil)', value: 'pt-BR' },
    ],
  })
  build() {}
}

As chaves de i18n seguem o mesmo padrão de resolução usado no restante do framework. Elas apontam para entradas nos arquivos JSON de locale e suportam todos os idiomas aceitos pelo Discord. Se um usuário com o cliente em português do Brasil abrir o seletor de comandos, ele verá automaticamente o nome e a descrição traduzidos do comando e das opções.

Checklist de design para definições de comando

Mantenha a definição livre de lógica de negócio

A classe do comando deve conter apenas decorators de metadados e um método build() vazio, ou métodos nomeados de subcomando. Não importe serviços, repositórios nem dependências de runtime para um arquivo de definição. Isso permite reutilizar a classe em handlers, autocomplete handlers e testes sem criar cadeias de dependência desnecessárias.

Use o tipo de opção mais específico disponível

Prefira @SlashOption.User em vez de @SlashOption.String para IDs de usuário, @SlashOption.Channel em vez de @SlashOption.String para referências de canal e @SlashOption.Integer em vez de @SlashOption.Number para números inteiros. Tipos específicos dão uma UI melhor no Discord, como seletores de usuário e dropdowns de canal, e ainda entregam objetos já resolvidos no handler.

Restrinja canais com channelTypes

Quando um comando espera um tipo específico de canal, sempre informe o array channelTypes. Isso evita que o usuário selecione um canal inválido, e o próprio cliente do Discord bloqueia a escolha antes de a interação chegar ao bot.

Prefira choices em conjuntos pequenos

Arrays estáticos de choices aparecem como dropdown e não exigem código de handler adicional. Use-os quando o conjunto de valores válidos for pequeno e fixo, normalmente abaixo de 25 entradas. Use autocomplete quando os valores forem dinâmicos, vierem do banco ou excederem esse limite.

Defina permissões já na definição do comando

Use defaultMemberPermissions para indicar o mínimo de permissões exigido para o comando aparecer no seletor. Isso funciona como um filtro de UI do Discord. Combine com @UseGuards no handler para ter a validação do lado do servidor, que não pode ser burlada.