Comandos, cartões e botões
Além de mensagens de texto, um bot pode:
- ter comandos com "/": quem digita
/no app vê a lista dos comandos dos bots do canal, com descrição e campos para preencher; - mandar cartões: título, texto, campos lado a lado, imagens e uma borda colorida;
- pôr botões nas mensagens, que avisam o bot quando alguém clica;
- responder só para a pessoa que usou o comando (a resposta não fica no canal).
Funciona no app do computador, na web e no Android.
Comandos
O bot cadastra a lista inteira de comandos de uma vez, normalmente ao conectar:
ts
await client.setCommands([
{
name: 'dado',
description: 'Rola um dado',
options: [{ name: 'lados', description: 'Quantos lados', type: 'integer', min_value: 2, max_value: 100 }],
},
{ name: 'ping', description: 'Responde pong' },
]);Os comandos aparecem em todos os canais que o bot vê, em todos os servidores dele. Cadastrar de novo troca a lista inteira.
| campo | |
|---|---|
name | 1 a 32 letras minúsculas, números, _ ou -. |
description | 1 a 100 caracteres. |
options | Até 25 campos (abaixo). Os obrigatórios vêm antes dos opcionais. |
Cada opção:
| campo | |
|---|---|
name, description | Como no comando. |
type | string, integer, number, boolean, user (alguém do servidor), channel (um canal de texto) ou role (um cargo). |
required | Se precisa ser preenchida. |
choices | Até 25 { name, value }: o app mostra uma lista em vez de um campo livre. Para string, integer e number. |
min_value, max_value | Limites para integer e number. |
O servidor confere o que a pessoa preencheu antes de avisar o bot: tipo, obrigatórios, limites e escolhas. Um bot pode ter até 100 comandos.
Quando alguém usa um comando
O bot recebe o evento INTERACTION_CREATE, e só ele recebe. Na biblioteca, é o evento interaction:
ts
client.on('interaction', async (i) => {
if (i.command === 'dado') {
const lados = i.option<number>('lados') ?? 6;
await i.reply(`🎲 ${1 + Math.floor(Math.random() * lados)}`);
}
});i.type | 'command' ou 'button'. |
i.command | O nome do comando. |
i.option(nome) | O valor de uma opção; undefined se ficou vazia. user, channel e role chegam como ids. |
i.user, i.member | Quem usou, e como membro do servidor. |
i.channelId, i.guildId | Onde. |
i.reply(...) | Responde com uma mensagem. |
i.update(...) | Só em cliques: muda a mensagem do botão. |
O app mostra "Bot está pensando…" até a resposta chegar, e "não respondeu" depois de 15 segundos sem nada. O bot tem até 15 minutos para responder, e pode responder mais de uma vez (as respostas seguintes são mensagens novas). A resposta aparece no canal com "Fulano usou /dado" em cima.
Se o bot estiver offline, o app avisa quem tentou usar o comando, e nada é enviado.
Resposta só para a pessoa
ts
await i.reply({ content: 'Você não tem permissão para isso.', ephemeral: true });Só quem usou o comando vê, com "Só você vê esta mensagem · Dispensar". Ela não fica guardada: some ao recarregar o app. Não leva botões.
Cartões
ts
await client.send(channelId, {
cards: [
{
author: { name: 'Previsão do tempo' },
title: 'São Paulo',
url: 'https://exemplo.com/sp',
description: 'Nublado, com **chuva** à tarde.',
color: 0xa594f9,
fields: [
{ name: 'Máxima', value: '27 °C', inline: true },
{ name: 'Mínima', value: '18 °C', inline: true },
],
thumbnail: { url: 'https://exemplo.com/nuvem.png' },
footer: { text: 'Atualizado' },
timestamp: Date.now(),
},
],
});| campo | limite | |
|---|---|---|
title | 256 | Em negrito; vira link se houver url. |
description | 4096 | Markdown, como uma mensagem. |
url | Link do título (http(s)). | |
color | A cor da borda, 0xRRGGBB. | |
author | nome 256 | { name, url?, icon_url? }, uma linha pequena em cima. |
fields | 25 campos; nome 256, valor 1024 | { name, value, inline? }. Os inline ficam lado a lado. |
image | { url }: imagem grande embaixo. | |
thumbnail | { url }: imagem pequena ao lado do texto. | |
footer | 2048 | { text, icon_url? }. |
timestamp | Em ms; aparece no rodapé. |
Até 5 cartões por mensagem, com até 6000 caracteres somando todos. Um cartão precisa de pelo menos título, texto, campo, imagem ou autor.
As imagens vão por links http(s) (ou por imagens enviadas ao Zynko, /api/media/...). O servidor busca as imagens pelas pessoas, como faz com as prévias de links, então os sites não ficam sabendo quem viu. Só bots mandam cartões e botões; as mensagens de pessoas não levam.
Botões
ts
await client.send(channelId, {
content: 'Votação: pizza ou hambúrguer?',
components: [
[
{ style: 'primary', emoji: '🍕', label: 'Pizza', custom_id: 'voto:pizza' },
{ style: 'secondary', emoji: '🍔', label: 'Hambúrguer', custom_id: 'voto:burger' },
{ style: 'link', label: 'Cardápio', url: 'https://exemplo.com/cardapio' },
],
],
});components são fileiras de botões: até 5 fileiras com até 5 botões cada.
| campo | |
|---|---|
style | primary (lilás), secondary (cinza), success (verde), danger (vermelho) ou link. |
label | Até 80 caracteres. Precisa de label ou emoji. |
emoji | Um emoji antes do texto. |
custom_id | Até 100 caracteres, diferente em cada botão. Volta para o bot no clique. Todos menos link. |
url | Só no link: abre o endereço, sem avisar o bot. |
disabled | Aparece apagado e não clica. |
Um clique chega como uma interação do tipo button:
ts
client.on('interaction', async (i) => {
if (i.type !== 'button') return;
if (i.customId?.startsWith('voto:')) {
votos.set(i.user.id, i.customId.slice(5));
await i.update({ content: `Votação: pizza ou hambúrguer? (${votos.size} votos)` });
}
});i.update(...) muda o texto, os cartões ou os botões da mensagem que foi clicada (o que você mandar; o resto fica). Para tirar os botões, mande components: []. Também dá para responder com i.reply(...), como num comando.
Editar depois
O bot edita as próprias mensagens com cartões e botões:
ts
const msg = await client.send(channelId, { content: 'Contando…' });
await msg.edit({ content: 'Pronto!', cards: [{ title: 'Resultado', description: '42' }], components: [] });Pela API, sem biblioteca
| ação | rota |
|---|---|
| Cadastrar os comandos | PUT /users/@me/commands com a lista |
| Ver os comandos | GET /users/@me/commands |
| Responder | POST /interactions/{id}/{token}/callback |
O INTERACTION_CREATE traz id e token. A resposta leva type ("message", o padrão, ou "update" para mudar a mensagem do botão), content, cards, components e ephemeral. Os detalhes estão em Rotas e Eventos.