@jadl/cmd
Version:
A command handler for JADL
157 lines (156 loc) • 7.54 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CommandHandler = void 0;
const CommandFactory_1 = require("../handler/CommandFactory");
const Symbols_1 = require("../Symbols");
const v9_1 = require("discord-api-types/v9");
const CommandError_1 = require("../structures/CommandError");
const InteractionChanges_1 = require("../utils/InteractionChanges");
const builders_1 = require("@jadl/builders");
const form_data_1 = __importDefault(require("form-data"));
const InteractionCommandResponse_1 = require("../structures/InteractionCommandResponse");
const WorkerInject_1 = require("../structures/WorkerInject");
class CommandHandler extends CommandFactory_1.CommandFactory {
constructor(worker, injections, options = {}) {
super(injections.filter((x) => !(x instanceof WorkerInject_1.WorkerInject)));
this.worker = worker;
const workerInjects = injections.filter((x) => x instanceof WorkerInject_1.WorkerInject);
this.commands.forEach((x) => {
if (x[Symbols_1.Symbols.injections])
workerInjects.push(...x[Symbols_1.Symbols.injections]);
});
workerInjects.forEach((inject) => inject._setup(this.worker));
this.options = {
interactionGuild: options.interactionGuild,
ephemeralError: options.ephemeralError ?? true
};
worker.on('INTERACTION_CREATE', (int) => {
void this.handleInteraction(int);
workerInjects.forEach((inject) => inject._onInteraction(int, this.worker));
});
worker.on('READY', () => {
if (this.worker.comms.id === '0')
void this.updateInteractions();
});
}
formCommandEndpoint(guildId, interactionId) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
return `/applications/${this.worker.user.id}/${this.options.interactionGuild ?? guildId
? `/guilds/${this.options.interactionGuild ?? guildId}/`
: ''}commands${interactionId ? `/${interactionId}` : ''}`;
}
async updateInteractions() {
const oldInteractions = (await this.worker.api.get(this.formCommandEndpoint()));
const newInteractions = this.commands.map((cmd) => cmd[Symbols_1.Symbols.interaction]);
const changes = (0, InteractionChanges_1.SeekInteractions)(oldInteractions, newInteractions);
await Promise.all([
...[
...changes.added,
...newInteractions.filter((x) => this.findCommand(x.name)?.[Symbols_1.Symbols.guild])
].map(async (x) => await this.worker.api.post(this.formCommandEndpoint(this.findCommand(x.name)?.[Symbols_1.Symbols.guild]), { body: x })),
...changes.updated.map(async (x) => await this.worker.api.post(this.formCommandEndpoint(this.findCommand(x.name)?.[Symbols_1.Symbols.guild]), {
body: x
})),
...changes.deleted.map(async (x) => await this.worker.api.delete(this.formCommandEndpoint(undefined, x.id)))
]);
this.worker.log(`Added ${changes.added.length}, deleted ${changes.deleted.length}, and updated ${changes.updated.length} command interactions`);
}
async handleInteraction(_interaction) {
if (_interaction.type !== v9_1.InteractionType.ApplicationCommand)
return;
if (!_interaction.data ||
(_interaction.data.type !== v9_1.ApplicationCommandType.ChatInput &&
_interaction.data.type !== v9_1.ApplicationCommandType.User &&
_interaction.data.type !== v9_1.ApplicationCommandType.Message))
return;
const command = this.findCommand(_interaction.data.name);
if (!command)
return;
const interaction = {
..._interaction,
responded: false
};
// TODO sub commands
const running = interaction.data.type === v9_1.ApplicationCommandType.ChatInput
? interaction.data.options &&
[
v9_1.ApplicationCommandOptionType.Subcommand,
v9_1.ApplicationCommandOptionType.SubcommandGroup
].includes(interaction.data.options[0].type)
? interaction.data.options[0].name
: Symbols_1.Symbols.baseCommand
: Symbols_1.Symbols.baseCommand;
const baseCommand = command[Symbols_1.Symbols.commands].find((x) => x.name === running);
if (!baseCommand)
return;
try {
for (const runner of baseCommand.canRun) {
if (!(await runner(interaction, this)))
return;
}
for (const runner of baseCommand.onRun) {
await runner(interaction, this);
}
const res = await command[baseCommand.method]?.(interaction, this);
await this.handleRes?.(res, interaction);
}
catch (err) {
if (err instanceof CommandError_1.CommandError) {
if (this.options.ephemeralError) {
const formatted = (0, builders_1.parseMessage)(err.response);
if (!(formatted instanceof form_data_1.default)) {
err.response = {
...formatted,
flags: v9_1.MessageFlags.Ephemeral
};
}
}
void this.handleRes(err.response, interaction).catch((err) => {
console.error(err);
});
}
else if (err instanceof Error) {
err.message += ` (In command ${baseCommand.name === Symbols_1.Symbols.baseCommand
? command[Symbols_1.Symbols.commandName]
: baseCommand.name.toString()})`;
console.error(err);
}
else {
console.error(err);
}
}
}
async editOriginal(res, int) {
await this.worker.api.patch(`/webhooks/${this.worker.user.id}/${int.token}/messages/@original`, (0, builders_1.parse)(res));
}
static async callback(worker, body, int) {
return await worker.api.post(`/interactions/${int.id}/${int.token}/callback`, {
body
});
}
async callback(body, int) {
return await CommandHandler.callback(this.worker, body, int);
}
async handleRes(res, int) {
if (res instanceof InteractionCommandResponse_1.InteractionCommandResponse) {
await this.callback(res.data, int);
}
else if (int.responded) {
await this.editOriginal(res, int);
}
else {
const msg = (0, builders_1.parseMessage)(res);
if (msg instanceof form_data_1.default) {
await this.callback({ type: v9_1.InteractionResponseType.DeferredChannelMessageWithSource }, int);
await this.editOriginal(res, int);
}
else {
await this.callback({ type: v9_1.InteractionResponseType.ChannelMessageWithSource, data: msg }, int);
}
}
}
}
exports.CommandHandler = CommandHandler;