Atualização 1.0 - Menos é mais

Grande atualização mudando drasticamente estruturas e melhorando performance

Bot Base
Atualizações
Novidades
Voltar

Essa atualização traz mudanças radicais nas estruturas e na forma como elas são construídas. Um destaque especial para os Responders que ficaram melhores ainda. Como vocês puderam notar no título, essa atualização traz a possibilidade de fazer muito mais, com menos. Vocês verão!

Comando para executar a CLI

npx constatic@latest

Biblioteca do discord

A biblioteca discord.js foi atualizada para a versão mais recente. Atualmente 14.17.2

▶️ Função inicial

A função que antes se chamava bootstrapApp, agora se chama apenas bootstrap. Essa função é responsável por iniciar toda a nossa aplicação, desde carregar comandos, eventos, responders, registrar dados na aplicação e fazer login com o token do bot.

src/index.ts
import { bootstrapApp } from "#base"; 
import { bootstrap } from "#base"; 
 
await bootstrapApp({ workdir: import.meta.dirname }); 
await bootstrap({ meta: import.meta }); 

Vamos ver agora algumas opções que foram removidas da função bootstrap

src/index.ts
interface BootstrapOptions extends Partial<ClientOptions> {
    workdir: string; 
    meta: ImportMeta; 
	commands?: { 
		guilds?: string[]; 
		defaultMemberPermissions?: PermissionResolvable[]; 
        onError?: CommandErrorHandler; 
	}, 
	responders?: { 
        onNotFound?(interaction: ResponderInteraction<ResponderType, CacheType>): void; 
        onError?: ResponderErrorHandler; 
	}, 
    directories?: string[];
    loadLogs?: boolean;
    beforeLoad?(client: Client): void
    whenReady?(client: Client<true>): void;
}

Antes era possível definir algumas funções para determinados contextos para os comandos e os responders nas opções da função bootstrap. Mas agora não é mais possível.

🟦 Pasta discord

Essa pasta ainda funciona da mesma maneira, todas as estruturas que estiverem dentro dela, seja qual for a profundidade de pastas aninhadas, serão carregadas antes da aplicação iniciar. Mas um pequeno detalhe foi adicionado. Agora existe um arquivo index.ts na pasta discord.

Neste arquivo é feita a preparação das estrutras da base

src/discord/index.ts
import { setupCreators } from "#base";
 
export const { createCommand, createEvent, createResponder } = setupCreators();

Para aqueles que já usavam a base antes, já perceberam que não usaremos mais as classes Command, Event e Responder. Elas foram substituídas pelas funções createCommand, createEvet e createResponder.

Mais uma vez, isso não é por acaso, essa alteração trará grandes recursos em futuras atualizações.

Os snippets da base também foram atualizados! Você ainda pode continuar usando new.command, new.event e new.responder para gerar um pequeno trecho de código inicial para essas funções.

Lembra que algumas opções foram removidas da função bootstrap? Então, agora elas serão definidas na função setupCreators:

export const { createCommand, createEvent, createResponder } = setupCreators({
    commands: {
        // ...
    },
    responders: {
        // ...
    }
});

Opções de comandos

Defina quais serão as permissões padrões de todos os comandos, caso não seja definida nenhuma com a opção defaultMemberPermissions (É o mesmo array de permissões do comando).

/* ... */ setupCreators({
    commands: {
        defaultMemberPermissions: ["SendMessages", "Connect"]
    },
});

Dessa forma, ao criar um comando e não definir nenhuma permissão padrão de membro, o que você definiu na função setupCreators, será o padrão de todos os comandos.

Você pode definir vários IDs de guildas que deseja registrar os comandos do seu bot com a opção guilds.

/* ... */ setupCreators({
    commands: {
        guilds: [process.env.MAIN_GUILD_ID, "537817462272557057"]
    },
});

Assim, ao invés de registrar os comandos globalmente na aplicação, eles serão registrados apenas nas guildas, cujo os ids foram passados para essa opção.

Agora vamos ver algumas funções abaixo que você pode definir para comandos e responders (Elas funcionam da mesma forma para ambos).

Funçãodescrição
middlewareÉ executada toda vez antes de cada comando/responder ser executado
onError,É executada quando ocorrer um erro na execução de um comando/responder
onNotFoundÉ executada caso um comando/responder não for encontrado para a interação

Sobre a função onError, você pode conferir alguns exemplos de uso dela em uma postagem anterior, basta adptar agora para a função setupCreators.

Agora sobre as outras funções, um blog de dicas será postado em breve.

Responders

Os Responders são com certeza um dos recursos favoritos do desenvolvedor desta base, o que mais recebe atenção e melhorias ao longo do tempo. Vamos começar vendo algumas remoções:

export enum ResponderType {
    Button,
    Select
    StringSelect,
    UserSelect,
    RoleSelect,
    ChannelSelect,
    MentionableSelect,
    Row
    Modal,
    ModalComponent,
    All
}

O tipo ResponderType.Select servia para responder qualquer tipo de select menu, o ResponderType.Row respondia qualquer componente de mensagem e o ResponderType.All respondia todos. Mas e agora?

A propriedade type foi renomeada para types e agora você pode passar um array de ResponderType que deseja que este Responder responda.

import { createResponder, ResponderType } from "#base";
 
createResponder({
    customId: "context/action",
    types: [ResponderType.Button], cache: "cached",
    async run(interaction) {
        // ...
    },
});

Você pode limitar quais tipos de select menu deseja responder:

createResponder({
    // ..
    types: [
        ResponderType.StringSelect,
        ResponderType.UserSelect,
    ],
    // ..
});

Que tal responder apenas botões e modais?

createResponder({
    // ..
    types: [
        ResponderType.Button,
        ResponderType.ModalComponent,
        ResponderType.Modal,
    ],
    // ..
});

São mais de 200 combinações possíveis e maior controle. Um detalhe importante, essa pequena alteração diminuiu o tempo médio para encontrar o Responder de 500-400ms para 30-20ms

Alguns tipos foram removidos, mas diversas possibilidades foram adicionadas. Menos é mais!

⭐ Extras

Adicionado um novo snippet para criar uma função de menu interativo

Use new.menu e será gerado um trecho de código como este:

import { ButtonBuilder, ButtonStyle, type InteractionReplyOptions } from "discord.js";
import { createEmbed, createRow } from "@magicyan/discord";
 
export function menu<R>(): R {
    const embed = createEmbed({
        description: "Menu"
    });
 
    const row = createRow(
        new ButtonBuilder({
            customId: "menu/action",
            label: ">", 
            style: ButtonStyle.Success
        })
    );
 
    return ({
        flags,
        embeds: [embed],
        components: [row] 
    } satisfies InteractionReplyOptions) as R;
}

Conclusão

Estes novos recursos da base estão em um estado experimental, pode haver bugs ou erros inesperados, caso encontre algum, reporte diretamente no discord Zunder Community.


Novidades, atualizações, alterações, dicas e muito mais será postado neste blog! Se você quiser ser notificado sempre que uma nova postagem for publicada, entre no discord Zunder Community ou Siga @rinckodev no twitter/x