Decorators
Referência seca. A explicação de como usar está em Eventos e Comandos.
import {
NescordModule, NescordHandler,
On, Once, SlashCommand, UseNescordGuards,
Ctx, Options, Opt, Rest,
InjectConcordClient,
NescordService, NescordCommandRegistry, NescordExplorer,
type EventContext, type SlashCommandContext, type CommandContext,
} from 'nescord';
Módulo
NescordModule.forRoot(options?)
@Module({
imports: [
NescordModule.forRoot({
token: process.env.CONCORD_TOKEN,
baseUrl: process.env.CONCORD_URL,
presence: '',
commands: { prefix: '/', ignoreBots: true },
}),
],
providers: [MeuHandler],
})
export class AppModule {}
Aceita tudo que o ClientOptions do concord.js aceita, mais:
| Opção | Padrão | O que é |
|---|---|---|
token | process.env.CONCORD_TOKEN | Token de sessão |
commands | ver abaixo | Despacho de comandos por mensagem |
client | — | Reaproveita um Client já criado (teste, bot dentro de app maior) |
autoLogin | true | false quando o bootstrap é manual |
logger | — | Logger do concord.js |
O módulo registra o Client, o explorer e o despachante. O login acontece em
onApplicationBootstrap, depois de ligar os handlers — assim nenhum evento se perde entre o
ready e o bind.
NescordModule.forRootAsync(options)
NescordModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
token: config.getOrThrow('CONCORD_TOKEN'),
baseUrl: config.get('CONCORD_URL'),
}),
});
Também aceita useClass / useExisting com uma NescordOptionsFactory:
@Injectable()
export class NescordConfig implements NescordOptionsFactory {
createNescordOptions(): NescordModuleOptions {
return { token: process.env.CONCORD_TOKEN };
}
}
NescordCommandOptions
| Campo | Padrão | O que é |
|---|---|---|
prefix | '/' | Prefixo dos comandos de texto |
allowMention | true | Também aceita @meubot comando |
ignoreBots | true | Ignora mensagens de bot (evita laço) |
caseInsensitive | true | Nome do comando sem distinção de caixa |
unknownCommandReply | null | Resposta a comando inexistente. null cala a boca |
interactionInbox | desligado | { enabled, intervalMs? } — fonte REST por polling |
Decorators de método
@On(event)
Liga o método a um evento do Client. Pode repetir no mesmo método.
@On('messageCreate')
onMessage(@Ctx() [message]: EventContext<'messageCreate'>) {}
@Once(event)
Igual, mas desliga depois da primeira vez.
@Once('ready')
onReady(@Ctx() [client]: EventContext<'ready'>) {}
@SlashCommand(meta)
Comando de texto despachado de messageCreate.
| Campo | Padrão | O que é |
|---|---|---|
name | — | Obrigatório |
description | — | Obrigatório. Aparece no /help |
aliases | — | Apelidos |
options | — | SlashCommandOptionMeta[] |
permissions | — | Bits exigidos de quem chamou |
serverOnly | true | Recusa em DM |
ownerOnly | false | Só o dono do servidor |
cooldown | 0 | Segundos entre chamadas por pessoa |
SlashCommandOptionMeta:
| Campo | Padrão | O que é |
|---|---|---|
name | — | Obrigatório |
description | — | Obrigatório |
type | 'string' | string, integer, number, boolean, user, channel, rest |
required | false | |
choices | — | Valores aceitos |
rest engole o resto da linha, então só pode ser a última opção.
@UseNescordGuards(...guards)
Vale em método e em classe.
@Injectable()
export class SoDeDia implements NescordGuard {
canActivate(ctx: CommandContext): boolean {
return new Date().getHours() >= 8;
}
}
@UseNescordGuards(SoDeDia)
@SlashCommand({ name: 'barulho', description: 'Toca algo alto' })
async barulho(@Ctx() [ctx]: SlashCommandContext) {}
Decorators de parâmetro
| Decorator | Injeta |
|---|---|
@Ctx() | A tupla do contexto: [args…] do evento, ou [ctx] do comando |
@Options() | Todas as opções convertidas, como objeto |
@Opt(name) | Uma opção pelo nome |
@Rest() | A linha crua depois do nome do comando |
@SlashCommand({
name: 'mover',
description: 'Move alguém para outro canal de voz',
options: [
{ name: 'quem', description: 'A pessoa', type: 'user', required: true },
{ name: 'para', description: 'O canal', type: 'channel', required: true },
],
})
async mover(
@Ctx() [ctx]: SlashCommandContext,
@Opt('quem') quem: User,
@Opt('para') para: Channel,
) {}
Decorator de classe
@NescordHandler()
Marca a classe como alvo do explorer. É opcional: um @Injectable() registrado em providers já é
varrido.
Injeção
@InjectConcordClient()
@Injectable()
export class MeuHandler {
constructor(@InjectConcordClient() private readonly client: Client) {}
}
Equivale a @Inject(NESCORD_CLIENT).
Serviços injetáveis
NescordService
@Injectable()
export class Admin {
constructor(private readonly nescord: NescordService) {}
async reconectar() {
await this.nescord.destroy();
await this.nescord.login();
}
}
Expõe client, commands, login(token?) e destroy().
NescordCommandRegistry
registry.commands; // ReadonlyMap<string, SlashCommandMeta>
registry.get('play');
await registry.publish(); // anuncia à aplicação e, com installToken, à instalação
publish() manda a lista para PUT /api/applications/@me/commands quando o cliente usa token de
bot — é o que o seletor do chat mostra ao digitar / — e para POST /api/bots/commands quando há
installToken. O nescord chama isso sozinho ao subir. Nunca falha: Concord sem a rota só gera
um aviso no log.
NescordExplorer
explorer.handlers;
// [{ event: 'messageCreate', once: false, provider: 'PingHandler', method: 'onMessage' }, …]
O que ficou ligado. Serve para teste e para o log de inicialização. Um handler que estoura é
capturado e vira evento error do Client — nunca derruba o processo.
Contexto
export type Context<T extends readonly unknown[]> = T;
export type EventContext<K extends ClientEventName> = Context<ClientEvents[K]>;
export type SlashCommandContext = Context<[CommandContext]>;
CommandContext está detalhado em Comandos.
Tokens de injeção
| Símbolo | O que é |
|---|---|
NESCORD_OPTIONS | As opções do módulo |
NESCORD_CLIENT | O Client |
NESCORD_HANDLER | Metadado de handler, lido pelo explorer |
NESCORD_COMMAND | Metadado de comando |
NESCORD_GUARDS | Metadado de guards |
Os três últimos são detalhe interno: só o explorer os lê.