detritus-client
Version:
A Typescript NodeJS library to interact with Discord's API, both Rest and Gateway.
915 lines (914 loc) • 38.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InteractionCommandClient = void 0;
const path = require("path");
const detritus_utils_1 = require("detritus-utils");
const client_1 = require("./client");
const clusterclient_1 = require("./clusterclient");
const collections_1 = require("./collections");
const commandclient_1 = require("./commandclient");
const constants_1 = require("./constants");
const errors_1 = require("./errors");
const structures_1 = require("./structures");
const utils_1 = require("./utils");
const commandratelimit_1 = require("./commandratelimit");
const interaction_1 = require("./interaction");
/**
* Interaction Command Client, hooks onto a ClusterClient or ShardClient to provide easier command handling
* Flow is `onInteractionCheck` -> `onCommandCheck`
* @category Clients
*/
class InteractionCommandClient extends detritus_utils_1.EventSpewer {
constructor(token, options = {}) {
super();
this._clientSubscriptions = [];
this.checkCommands = true;
this.commands = new collections_1.BaseSet();
this.commandsById = new collections_1.BaseCollection();
this.directories = new collections_1.BaseCollection();
this.ran = false;
this.ratelimits = [];
this.strictCommandCheck = true;
options = Object.assign({ useClusterClient: true }, options);
this.checkCommands = (options.checkCommands || options.checkCommands === undefined);
this.ratelimiter = options.ratelimiter || new commandratelimit_1.CommandRatelimiter();
this.strictCommandCheck = (options.strictCommandCheck || options.strictCommandCheck === undefined);
this.onCommandCheck = options.onCommandCheck || this.onCommandCheck;
this.onCommandCancel = options.onCommandCancel || this.onCommandCancel;
this.onInteractionCheck = options.onInteractionCheck || this.onInteractionCheck;
this.onInteractionCancel = options.onInteractionCancel || this.onInteractionCancel;
if (token instanceof commandclient_1.CommandClient) {
token = token.client;
}
if (process.env.CLUSTER_MANAGER === 'true') {
options.useClusterClient = true;
if (token instanceof clusterclient_1.ClusterClient) {
if (process.env.CLUSTER_TOKEN !== token.token) {
throw new Error('Cluster Client must have matching tokens with the Manager!');
}
}
else {
token = process.env.CLUSTER_TOKEN;
}
}
let client;
if (typeof (token) === 'string') {
if (options.useClusterClient) {
client = new clusterclient_1.ClusterClient(token, options);
}
else {
client = new client_1.ShardClient(token, options);
}
}
else {
client = token;
}
if (!client || !(client instanceof clusterclient_1.ClusterClient || client instanceof client_1.ShardClient)) {
throw new Error('Token has to be a string or an instance of a client');
}
this.client = client;
Object.defineProperty(this.client, 'interactionCommandClient', { value: this });
if (this.client instanceof clusterclient_1.ClusterClient) {
for (let [shardId, shard] of this.client.shards) {
Object.defineProperty(shard, 'interactionCommandClient', { value: this });
}
}
if (options.ratelimit) {
this.ratelimits.push(new commandratelimit_1.CommandRatelimit(options.ratelimit));
}
if (options.ratelimits) {
for (let rOptions of options.ratelimits) {
if (typeof (rOptions.type) === 'string') {
const rType = (rOptions.type || '').toLowerCase();
if (this.ratelimits.some((ratelimit) => ratelimit.type === rType)) {
throw new Error(`Ratelimit with type ${rType} already exists`);
}
}
this.ratelimits.push(new commandratelimit_1.CommandRatelimit(rOptions));
}
}
Object.defineProperties(this, {
_clientSubscriptions: { enumerable: false, writable: false },
ran: { configurable: true, writable: false },
onCommandCheck: { enumerable: false, writable: true },
onCommandCancel: { enumerable: false, writable: true },
onInteractionCheck: { enumerable: false, writable: true },
onInteractionCancel: { enumerable: false, writable: true },
});
}
get canUpload() {
if (this.manager) {
// only upload on the first cluster process
return this.manager.clusterId === 0;
}
return true;
}
get manager() {
return (this.client instanceof clusterclient_1.ClusterClient) ? this.client.manager : null;
}
get rest() {
return this.client.rest;
}
/* Generic Command Function */
add(options, run) {
let command;
if (options instanceof interaction_1.InteractionCommand) {
command = options;
}
else {
if (run !== undefined) {
options.run = run;
}
// create a normal command class with the options given
if (options._class === undefined) {
command = new interaction_1.InteractionCommand(options);
}
else {
// check for `.constructor` to make sure it's a class
if (options._class.constructor) {
command = new options._class(options);
}
else {
// else it's just a function, `ts-node` outputs these
command = options._class(options);
}
if (!command._file) {
Object.defineProperty(command, '_file', { value: options._file });
}
}
}
command._transferValuesToChildren();
if (!command.hasRun) {
throw new Error('Command needs a run function');
}
this.commands.add(command);
const guildIds = (command.guildIds) ? command.guildIds.toArray() : [];
if (command.global) {
guildIds.unshift(constants_1.LOCAL_GUILD_ID);
}
for (let guildId of guildIds) {
let commands;
if (this.commandsById.has(guildId)) {
commands = this.commandsById.get(guildId);
}
else {
commands = new collections_1.BaseSet();
this.commandsById.set(guildId, commands);
}
commands.add(command);
}
if (!this._clientSubscriptions.length) {
this.setSubscriptions();
}
return this;
}
addMultiple(commands = []) {
for (let command of commands) {
this.add(command);
}
return this;
}
async addMultipleIn(directory, options = {}) {
options = Object.assign({ subdirectories: true }, options);
if (!options.isAbsolute) {
if (require.main) {
// require.main.path exists but typescript doesn't let us use it..
directory = path.join(path.dirname(require.main.filename), directory);
}
}
this.directories.set(directory, { subdirectories: !!options.subdirectories });
const files = await utils_1.getFiles(directory, options.subdirectories);
const errors = {};
const addCommand = (imported, filepath) => {
if (!imported) {
return;
}
if (typeof (imported) === 'function') {
this.add({ _file: filepath, _class: imported, name: '' });
}
else if (imported instanceof interaction_1.InteractionCommand) {
Object.defineProperty(imported, '_file', { value: filepath });
this.add(imported);
}
else if (typeof (imported) === 'object' && Object.keys(imported).length) {
if (Array.isArray(imported)) {
for (let child of imported) {
addCommand(child, filepath);
}
}
else {
if ('name' in imported) {
this.add({ ...imported, _file: filepath });
}
}
}
};
for (let file of files) {
if (!file.endsWith((constants_1.IS_TS_NODE) ? '.ts' : '.js')) {
continue;
}
const filepath = path.resolve(directory, file);
try {
let importedCommand = require(filepath);
if (typeof (importedCommand) === 'object' && importedCommand.__esModule) {
importedCommand = importedCommand.default;
}
addCommand(importedCommand, filepath);
}
catch (error) {
errors[filepath] = error;
}
}
if (Object.keys(errors).length) {
throw new errors_1.ImportedCommandsError(errors);
}
return this;
}
clear() {
for (let command of this.commands) {
if (command._file) {
const requirePath = require.resolve(command._file);
if (requirePath) {
delete require.cache[requirePath];
}
}
}
this.commands.clear();
for (let [guildId, commands] of this.commandsById) {
commands.clear();
this.commandsById.delete(guildId);
}
this.commandsById.clear();
this.clearSubscriptions();
}
clearSubscriptions() {
while (this._clientSubscriptions.length) {
const subscription = this._clientSubscriptions.shift();
if (subscription) {
subscription.remove();
}
}
}
async resetCommands() {
this.clear();
for (let [directory, options] of this.directories) {
await this.addMultipleIn(directory, { isAbsolute: true, ...options });
}
await this.checkAndUploadCommands();
}
/* Application Command Checking */
async checkApplicationCommands(guildId) {
if (!this.client.ran) {
return false;
}
const commands = await this.fetchApplicationCommands(guildId);
return this.validateCommands(commands);
}
async checkAndUploadCommands(force = false) {
if (!this.client.ran) {
return;
}
for (let [guildId, localCommands] of this.commandsById) {
const guildIdOrUndefined = (guildId === constants_1.LOCAL_GUILD_ID) ? undefined : guildId;
if (!await this.checkApplicationCommands(guildIdOrUndefined) && (force || this.canUpload)) {
const commands = await this.uploadApplicationCommands(guildIdOrUndefined);
this.validateCommands(commands);
if (this.manager && this.manager.hasMultipleClusters) {
this.manager.sendIPC(constants_1.ClusterIPCOpCodes.FILL_INTERACTION_COMMANDS, { data: commands });
}
}
}
}
createApplicationCommandsFromRaw(data) {
const collection = new collections_1.BaseCollection();
const shard = (this.client instanceof clusterclient_1.ClusterClient) ? this.client.shards.first() : this.client;
for (let raw of data) {
const command = new structures_1.ApplicationCommand(shard, raw);
collection.set(command.id, command);
}
return collection;
}
async fetchApplicationCommands(guildId) {
// add ability for ClusterManager checks
if (!this.client.ran) {
throw new Error('Client hasn\'t ran yet so we don\'t know our application id!');
}
let data;
if (this.manager && this.manager.hasMultipleClusters) {
if (guildId) {
data = await this.manager.sendRestRequest('fetchApplicationGuildCommands', [this.client.applicationId, guildId]);
}
else {
data = await this.manager.sendRestRequest('fetchApplicationCommands', [this.client.applicationId]);
}
}
else {
if (guildId) {
data = await this.rest.fetchApplicationGuildCommands(this.client.applicationId, guildId);
}
else {
data = await this.rest.fetchApplicationCommands(this.client.applicationId);
}
}
return this.createApplicationCommandsFromRaw(data);
}
async uploadApplicationCommands(guildId) {
// add ability for ClusterManager
if (!this.client.ran) {
throw new Error('Client hasn\'t ran yet so we don\'t know our application id!');
}
const localCommands = (this.commandsById.get(guildId || constants_1.LOCAL_GUILD_ID) || []).map((command) => {
const data = command.toJSON();
data[constants_1.DiscordKeys.ID] = command.ids.get(guildId || constants_1.LOCAL_GUILD_ID);
data[constants_1.DiscordKeys.IDS] = undefined;
return data;
});
const shard = (this.client instanceof clusterclient_1.ClusterClient) ? this.client.shards.first() : this.client;
if (guildId) {
return shard.rest.bulkOverwriteApplicationGuildCommands(this.client.applicationId, guildId, localCommands);
}
else {
return shard.rest.bulkOverwriteApplicationCommands(this.client.applicationId, localCommands);
}
}
validateCommands(commands) {
if (!commands.length) {
return true;
}
const guildId = commands.first().guildId || constants_1.LOCAL_GUILD_ID;
const localCommands = this.commandsById.get(guildId);
if (localCommands) {
let matches = commands.length === localCommands.length;
for (let [commandId, command] of commands) {
const localCommand = localCommands.find((cmd) => cmd.name === command.name && cmd.type === command.type);
if (localCommand) {
localCommand.ids.set(guildId, command.id);
if (matches && localCommand.hash !== command.hash) {
matches = false;
}
}
else {
matches = false;
}
}
return matches;
}
return false;
}
validateCommandsFromRaw(data) {
const collection = this.createApplicationCommandsFromRaw(data);
return this.validateCommands(collection);
}
/* end */
async parseArgs(context, data) {
if (data.isSlashCommand) {
return this.parseArgsFromOptions(context, context.command._options, data.options, data.resolved);
}
else if (data.isContextCommand) {
return this.parseArgsFromContextMenu(data);
}
return [{}, null];
}
async parseArgsFromContextMenu(data) {
const args = {};
if (data.targetId && data.resolved) {
switch (data.type) {
case constants_1.ApplicationCommandTypes.MESSAGE:
{
if (data.resolved.messages) {
args.message = data.resolved.messages.get(data.targetId);
}
}
;
break;
case constants_1.ApplicationCommandTypes.USER:
{
if (data.resolved.members) {
args.member = data.resolved.members.get(data.targetId);
}
if (data.resolved.users) {
args.user = data.resolved.users.get(data.targetId);
}
}
;
break;
}
}
return [args, null];
}
async parseArgsFromOptions(context, commandOptions, options, resolved) {
const args = {};
const errors = {};
/*
We will get data like this
{
id: '',
name: '',
options: [
{
name: '',
options: [
{
name: '',
options: [
{name: '', type: int, value: any},
],
type: 1,
}
],
type: 2,
},
],
type: 1,
}
{
id: '',
name: '',
options: [
{
name: '',
options: [
{
name: '',
type: 1,
}
],
type: 2,
},
],
type: 1,
}
{
id: '',
name: '',
type: 1,
}
Non-required options wont be there so we must look through our command and fill out the defaults
*/
let hasError = false;
if (options) {
for (let [name, option] of options) {
let commandOption;
if (commandOptions && commandOptions.has(name)) {
commandOption = commandOptions.get(name);
}
if (option.options) {
const [childArgs, childErrors] = await this.parseArgsFromOptions(context, commandOption && commandOption._options, option.options, resolved);
Object.assign(args, childArgs);
if (childErrors) {
hasError = true;
Object.assign(errors, childErrors);
}
}
else if (option.value !== undefined) {
let value = option.value;
if (resolved) {
switch (option.type) {
case constants_1.ApplicationCommandOptionTypes.CHANNEL:
{
if (resolved.channels) {
value = resolved.channels.get(value) || value;
}
}
;
break;
case constants_1.ApplicationCommandOptionTypes.BOOLEAN:
value = Boolean(value);
break;
case constants_1.ApplicationCommandOptionTypes.INTEGER:
value = parseInt(value);
break;
case constants_1.ApplicationCommandOptionTypes.MENTIONABLE:
{
if (resolved.roles && resolved.roles.has(value)) {
value = resolved.roles.get(value);
}
else if (resolved.members && resolved.members.has(value)) {
value = resolved.members.get(value);
}
else if (resolved.users && resolved.users.has(value)) {
value = resolved.users.get(value);
}
}
;
break;
case constants_1.ApplicationCommandOptionTypes.ROLE:
{
if (resolved.roles) {
value = resolved.roles.get(value) || value;
}
}
;
break;
case constants_1.ApplicationCommandOptionTypes.USER:
{
if (resolved.members) {
value = resolved.members.get(value) || value;
}
else if (resolved.users) {
value = resolved.users.get(value) || value;
}
}
;
break;
}
}
const label = (commandOption) ? commandOption.label || name : name;
if (commandOption) {
if (commandOption.value && typeof (commandOption.value) === 'function') {
try {
args[label] = await Promise.resolve(commandOption.value(value, context));
}
catch (error) {
hasError = true;
errors[label] = error;
}
}
else {
args[label] = value;
}
}
else {
args[label] = value;
}
}
else if (commandOption && commandOption._options) {
hasError = (await this.parseDefaultArgsFromOptions(context, commandOption._options, args, errors)) || hasError;
}
}
}
if (commandOptions) {
hasError = (await this.parseDefaultArgsFromOptions(context, commandOptions, args, errors)) || hasError;
}
return [args, (hasError) ? errors : null];
}
async parseDefaultArgsFromOptions(context, commandOptions, args = {}, errors = {}) {
let hasError = false;
for (let [name, commandOption] of commandOptions) {
if (commandOption.isSubCommand || commandOption.isSubCommandGroup) {
continue;
}
const label = commandOption.label || name;
if (commandOption.default !== undefined && !(label in args) && !(label in errors)) {
if (typeof (commandOption.default) === 'function') {
try {
args[label] = await Promise.resolve(commandOption.default(context));
}
catch (error) {
hasError = true;
errors[label] = error;
}
}
else {
args[label] = commandOption.default;
}
}
}
return hasError;
}
setSubscriptions() {
this.clearSubscriptions();
const subscriptions = this._clientSubscriptions;
subscriptions.push(this.client.subscribe(constants_1.ClientEvents.INTERACTION_CREATE, this.handleInteractionCreate.bind(this)));
}
/* Kill/Run */
kill() {
this.client.kill();
this.emit(constants_1.ClientEvents.KILLED);
this.clearSubscriptions();
this.removeAllListeners();
}
async run(options = {}) {
if (this.ran) {
return this.client;
}
if (options.directories) {
for (let directory of options.directories) {
await this.addMultipleIn(directory);
}
}
await this.client.run(options);
if (this.checkCommands) {
await this.checkAndUploadCommands();
}
Object.defineProperty(this, 'ran', { value: true });
return this.client;
}
async handleInteractionCreate(event) {
return this.handle(constants_1.ClientEvents.INTERACTION_CREATE, event);
}
async handle(name, event) {
const { interaction } = event;
if (interaction.type !== constants_1.InteractionTypes.APPLICATION_COMMAND) {
return;
}
// assume the interaction is global for now
const data = interaction.data;
let command;
const guildIds = (interaction.guildId) ? [interaction.guildId, constants_1.LOCAL_GUILD_ID] : [constants_1.LOCAL_GUILD_ID];
for (let guildId of guildIds) {
if (this.commandsById.has(guildId)) {
const localCommands = this.commandsById.get(guildId);
if (this.strictCommandCheck) {
command = localCommands.find((cmd) => cmd.ids.get(guildId) === data.id);
}
else {
command = localCommands.find((cmd) => cmd.name === data.name && cmd.type === data.type);
}
if (command) {
break;
}
}
}
if (!command) {
return;
}
const invoker = command.getInvoker(data);
if (!invoker) {
return;
}
const context = new interaction_1.InteractionContext(this, interaction, command, invoker);
if (typeof (this.onInteractionCheck) === 'function') {
try {
const shouldContinue = await Promise.resolve(this.onInteractionCheck(context));
if (!shouldContinue) {
if (typeof (this.onInteractionCancel) === 'function') {
return await Promise.resolve(this.onInteractionCancel(context));
}
return;
}
}
catch (error) {
const payload = { command, context, error };
this.emit(constants_1.ClientEvents.COMMAND_ERROR, payload);
return;
}
}
if (typeof (this.onCommandCheck) === 'function') {
try {
const shouldContinue = await Promise.resolve(this.onCommandCheck(context, command));
if (!shouldContinue) {
if (typeof (this.onCommandCancel) === 'function') {
return await Promise.resolve(this.onCommandCancel(context, command));
}
return;
}
}
catch (error) {
const payload = { command, context, error };
this.emit(constants_1.ClientEvents.COMMAND_ERROR, payload);
return;
}
}
if (this.ratelimits.length || (invoker.ratelimits && invoker.ratelimits.length)) {
const now = Date.now();
{
const ratelimits = this.ratelimiter.getExceeded(context, this.ratelimits, now);
if (ratelimits.length) {
const global = true;
const payload = { command, context, global, ratelimits, now };
this.emit(constants_1.ClientEvents.COMMAND_RATELIMIT, payload);
if (typeof (invoker.onRatelimit) === 'function') {
try {
await Promise.resolve(invoker.onRatelimit(context, ratelimits, { global, now }));
}
catch (error) {
// do something with this error?
}
}
return;
}
}
if (invoker.ratelimits && invoker.ratelimits.length) {
const ratelimits = this.ratelimiter.getExceeded(context, invoker.ratelimits, now);
if (ratelimits.length) {
const global = false;
const payload = { command, context, global, ratelimits, now };
this.emit(constants_1.ClientEvents.COMMAND_RATELIMIT, payload);
if (typeof (invoker.onRatelimit) === 'function') {
try {
await Promise.resolve(invoker.onRatelimit(context, ratelimits, { global, now }));
}
catch (error) {
// do something with this error?
}
}
return;
}
}
}
if (context.inDm) {
// dm checks? maybe add ability to disable it in dm?
if (invoker.disableDm) {
if (typeof (invoker.onDmBlocked) === 'function') {
try {
await Promise.resolve(invoker.onDmBlocked(context));
}
catch (error) {
const payload = { command, context, error };
this.emit(constants_1.ClientEvents.COMMAND_ERROR, payload);
}
}
else {
const error = new Error('Command with DMs disabled used in DM');
const payload = { command, context, error };
this.emit(constants_1.ClientEvents.COMMAND_ERROR, payload);
}
return;
}
}
else {
// check the bot's permissions in the server
// should never be ignored since it's most likely the bot will rely on this permission to do whatever action
if (Array.isArray(invoker.permissionsClient) && invoker.permissionsClient.length) {
const failed = [];
const channel = context.channel;
const member = context.me;
if (channel && member) {
const total = member.permissionsIn(channel);
if (!member.isOwner && !utils_1.PermissionTools.checkPermissions(total, constants_1.Permissions.ADMINISTRATOR)) {
for (let permission of invoker.permissionsClient) {
if (!utils_1.PermissionTools.checkPermissions(total, permission)) {
failed.push(permission);
}
}
}
}
else {
for (let permission of invoker.permissionsClient) {
failed.push(permission);
}
}
if (failed.length) {
const payload = { command, context, permissions: failed };
this.emit(constants_1.ClientEvents.COMMAND_PERMISSIONS_FAIL_CLIENT, payload);
if (typeof (invoker.onPermissionsFailClient) === 'function') {
try {
await Promise.resolve(invoker.onPermissionsFailClient(context, failed));
}
catch (error) {
// do something with this error?
}
}
return;
}
}
// if command doesn't specify it should ignore the client owner, or if the user isn't a client owner
// continue to permission checking
if (!invoker.permissionsIgnoreClientOwner || !context.user.isClientOwner) {
// check the user's permissions
if (Array.isArray(invoker.permissions) && invoker.permissions.length) {
const failed = [];
const channel = context.channel;
const member = context.member;
if (channel && member) {
const total = member.permissionsIn(channel);
if (!member.isOwner && !utils_1.PermissionTools.checkPermissions(total, constants_1.Permissions.ADMINISTRATOR)) {
for (let permission of invoker.permissions) {
if (!utils_1.PermissionTools.checkPermissions(total, permission)) {
failed.push(permission);
}
}
}
}
else {
for (let permission of invoker.permissions) {
failed.push(permission);
}
}
if (failed.length) {
const payload = { command, context, permissions: failed };
this.emit(constants_1.ClientEvents.COMMAND_PERMISSIONS_FAIL, payload);
if (typeof (invoker.onPermissionsFail) === 'function') {
try {
await Promise.resolve(invoker.onPermissionsFail(context, failed));
}
catch (error) {
// do something with this error?
}
}
return;
}
}
}
}
if (typeof (invoker.onBefore) === 'function') {
try {
const shouldContinue = await Promise.resolve(invoker.onBefore(context));
if (!shouldContinue) {
if (typeof (invoker.onCancel) === 'function') {
await Promise.resolve(invoker.onCancel(context));
}
return;
}
}
catch (error) {
const payload = { command, context, error };
this.emit(constants_1.ClientEvents.COMMAND_ERROR, payload);
return;
}
}
let timeout = null;
try {
if (invoker.triggerLoadingAfter !== undefined && 0 <= invoker.triggerLoadingAfter && !context.responded) {
let data;
if (invoker.triggerLoadingAsEphemeral) {
data = { flags: constants_1.MessageFlags.EPHEMERAL };
}
if (invoker.triggerLoadingAfter) {
timeout = new detritus_utils_1.Timers.Timeout();
Object.defineProperty(context, 'loadingTimeout', { value: timeout });
timeout.start(invoker.triggerLoadingAfter, async () => {
if (!context.responded) {
try {
if (typeof (invoker.onLoadingTrigger) === 'function') {
await Promise.resolve(invoker.onLoadingTrigger(context));
}
else {
await context.respond(constants_1.InteractionCallbackTypes.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE, data);
}
}
catch (error) {
// do something maybe?
}
}
});
}
else {
if (typeof (invoker.onLoadingTrigger) === 'function') {
await Promise.resolve(invoker.onLoadingTrigger(context));
}
else {
await context.respond(constants_1.InteractionCallbackTypes.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE, data);
}
}
}
}
catch (error) {
// 404 interaction unknown most likely, do nothing
}
const [args, errors] = await this.parseArgs(context, data);
try {
if (errors) {
if (typeof (invoker.onValueError) === 'function') {
await Promise.resolve(invoker.onValueError(context, args, errors));
}
const error = new Error('Command errored out while converting args');
const payload = { command, context, error, extra: errors };
this.emit(constants_1.ClientEvents.COMMAND_ERROR, payload);
return;
}
if (typeof (invoker.onBeforeRun) === 'function') {
const shouldRun = await Promise.resolve(invoker.onBeforeRun(context, args));
if (!shouldRun) {
if (typeof (invoker.onCancelRun) === 'function') {
await Promise.resolve(invoker.onCancelRun(context, args));
}
return;
}
}
try {
if (typeof (invoker.run) === 'function') {
await Promise.resolve(invoker.run(context, args));
}
if (timeout) {
timeout.stop();
}
const payload = { args, command, context };
this.emit(constants_1.ClientEvents.COMMAND_RAN, payload);
if (typeof (invoker.onSuccess) === 'function') {
await Promise.resolve(invoker.onSuccess(context, args));
}
}
catch (error) {
if (timeout) {
timeout.stop();
}
const payload = { args, command, context, error };
this.emit(constants_1.ClientEvents.COMMAND_RUN_ERROR, payload);
if (typeof (invoker.onRunError) === 'function') {
await Promise.resolve(invoker.onRunError(context, args, error));
}
}
}
catch (error) {
if (typeof (invoker.onError) === 'function') {
await Promise.resolve(invoker.onError(context, args, error));
}
const payload = { args, command, context, error };
this.emit(constants_1.ClientEvents.COMMAND_FAIL, payload);
}
}
on(event, listener) {
super.on(event, listener);
return this;
}
once(event, listener) {
super.once(event, listener);
return this;
}
subscribe(event, listener) {
return super.subscribe(event, listener);
}
}
exports.InteractionCommandClient = InteractionCommandClient;