Giter Site home page Giter Site logo

discord-akairo's Introduction


discord-akairo


NPM version NPM downloads Build status

npm installnfo

Features

Completely modular commands, inhibitors, and listeners.

  • Reading files recursively from directories.
  • Adding, removing, and reloading modules.
  • Creating your own handlers and module types.

Flexible command handling and creation.

  • Command aliases.
  • Command throttling and cooldowns.
  • Client and user permission checks.
  • Running commands on edits and editing previous responses.
  • Multiple prefixes and mention prefixes.
  • Regular expression and conditional triggers.

Complex and highly customizable arguments.

  • Support for quoted arguments.
  • Arguments based on previous arguments.
  • Several ways to match arguments, such as flag arguments.
  • Casting input into certain types.
    • Simple types such as string, integer, float, url, date, etc.
    • Discord-related types such as user, member, message, etc.
    • Types that you can add yourself.
    • Asynchronous type casting.
  • Prompting for input for arguments.
    • Customizable prompts with embeds, files, etc.
    • Easily include dynamic data such as the incorrect input.
    • Infinite argument prompting.

Blocking and monitoring messages with inhibitors.

  • Run at various stages of command handling.
    • On all messages.
    • On messages that are from valid users.
    • On messages before commands.

Helpful events and modular listeners.

  • Events for handlers, such as loading modules.
  • Events for various stages of command handling.
  • Reloadable listeners to easily separate your event handling.

Useful utilities and database providers.

  • Resolvers for members, users, and others that can filter by name.
  • Shortcut methods for making embeds and collections.
  • Simple to use database providers.
    • Built-in support for sqlite and sequelize.
    • Works on entire table or single JSON column.
    • Caching data from databases.

Installation

Requires Node 16.6.0+ and Discord.js v13.

discord-akairo
npm install discord-akairo

discord.js
npm install discord.js

sqlite (optional)
npm install sqlite

sequelize (optional)
npm install sequelize

Links

Contributing

Open an issue or a pull request!
Everyone is welcome to do so.
Make sure to run npm test before committing.

discord-akairo's People

Contributors

1computer1 avatar adrienbrignon avatar aeryle avatar almostsouji avatar bumbummen99 avatar csuvajit avatar gamesproseif avatar gazmull avatar goldenangel2 avatar ha6000 avatar icrawl avatar kagchi avatar lioness100 avatar maruf99 avatar monbrey avatar mzato0001 avatar norviah avatar noxillio avatar papaia avatar pastusedby avatar pyrotechniac avatar qwright10 avatar raideer avatar shaybox avatar slimyboy2 avatar terminal69 avatar username1307 avatar vaporoxx avatar vetlix avatar zerefdev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

discord-akairo's Issues

Typing : MessageAdditions is not exported

> [email protected] build /tmp/build_5f489609686e90e25aa7a2e12f79b066
> tsc

node_modules/discord-akairo/src/index.d.ts(5,9): error TS2724: Module '"discord.js"' has no exported member 'MessageAdditions'. Did you mean 'MessageEditOptions'?

Discord.js 11.5.1, TypeScript 3.7.5, commit cb458b3 (8.0.0beta8 if I am right) for reference

MongoDB Support?

I don't know, since you support SQLite and Sequelize I just thought it'd be kind of handy to also support MongoDB. :)

ClientUtil Resolvers behave odd when given an empty string

If I were to do

client.util.resolveMember('', members)

where members is any list of members, it'll return the first member in the collection because node returns true when something like this is run:

('blah').includes('')

I guess the expected behavior would be to have it return null or throw an error rather than actually returning an entry.

Exclude files/folders in command directory

One of the recommended patterns for organizing jest unit tests is to have a tests folder alongside the files you want to test. This style doesn't seem to work when registering my command folder. Discord Commando lets you pass in an exclusion rule when importing your files. This is what I have currently set up in Commando.

.registerCommandsIn({
  dirname: path.join(__dirname, "commands"),
  excludeDirs: /^__tests__$/
});

Test ping-pong not work.

I'm using:

  • Node - 10
  • Discord.js 12.2.0
  • Discord-Akairo - 8

I can start the bot normally

bot.js

const { AkairoClient, CommandHandler } = require('discord-akairo');

class AnoregBot extends AkairoClient {
    constructor() {
        super({
            ownerID: '709871375099101275',
        }, {
            disableEveryone: true
        });
        this.commandHandler = new CommandHandler(this, {
            directory: './commands/',
            prefix: '!'
        });
    }
}

const anoregBot = new AnoregBot();
anoregBot.login('NzA5ODcxMzc1MDk5MTAxMjc1.Xr2aBQ.WpC_HUbBgqviTDSJbzKin3i81os');

anoregBot.once("ready", () => {
    console.log(`Logged in as ${anoregBot.user.tag}!`)

})

folder commands file ping-command.js

const { Command } = require('discord-akairo');

class PingCommand extends Command {
    constructor() {
        super('ping', {
           aliases: ['ping'] 
        });
    }

    exec(message) {
        return message.reply('Pong!');
    }
}

module.exports = PingCommand;

When I run node bot.js , the bot does not respond.

I followed the example: https://discord-akairo.github.io/#/docs/main/master/basics/commands

Prompting with custom type

Prompting is not working with custom type.

I'm just playing around to test some stuff and as I couldn't find how to validate prompts I thought that custom types might be my solution.

My custom type is just a e-mail validation, so I have the following command

const { Command } = require('discord-akairo')

function isValidEmail(word) {
    if (word.startsWith('william'))
        return word
    return null
}

module.exports = class RegisterCommand extends Command {
    constructor() {
        super('register', {
            aliases: ['register'],
            args: [
                {
                    id: 'email',
                    type: word => {
                        return isValidEmail(word)
                    },
                    prompt: {
                        start: 'Please enter your e-mail',
                        retry: 'LOL! Try again!'
                    }
                }
            ]
        })
    }

    exec(message, args) {
        return message.reply('Reply with ```' + JSON.stringify(args) + '```')
    }
}

The intended behavior is: ask for e-mail (with prompt) and when the user inputs the value, I "execute" the type to check wether the value is valid or not, returning a null if something wrong.

What is happening: prompt is not happening.

Version:
discord-akairo => 7.5.5
discord.js => 11.4.2

cooldown listener issues?

I can't seem to trigger a warning with a command with a cooldown so i set up a listener like this

const { Listener } = require('discord-akairo');

class CommandCooldownListener extends Listener {
    constructor() {
        super('commandCooldown', {
            emitter: 'commandHandler',
            event: 'commandCooldown'
        });
    }

    async exec(message, command, reason) {
        console.log(`${message.author.user} triggered a cooldown from using ${command.id} because of ${reason}`);
    }
}
module.exports = CommandCooldownListener;

and this triggers a AkairoError [INVALID_TYPE]: Value of 'emitter' was not an EventEmitter error
if i use client as the emitter that does nothing.

I read somewhere that you need to add extra classes as classToHandle under the ListenerHandle but I couldn't seem to get that to work either. am I making some rookie mistake or is something changed about the cooldown system? I can't find any other examples online

ArgumentMatch type rest no longer ignores phrases that match a flag

This occurred to me not too long ago, figured I did something wrong,
my client who apparanently ran npm i just yesterday had all the commands with ArgumentMatch rest stop working, this obviously confirms that I wasn't wrong and there's something with the arguments being parsed.

Using AkairoHandler instance in Command class

Hello!

I'm currently coding a new feature for Akairo; I should be able to use the AkairoHandler in the Akairo Command class constructor in order to be able to retrieve some commands according to a certain criteria.

Thanks in advance

Let date argument accept relative times

Let the date argument accept times which are relative to now.

Some examples:

  • "now"
  • "Yesterday"
  • "-1hour"
  • "-4days"
  • "-4day"
  • "-4d"
  • "+1month"
  • "-5d3h5m"
  • "next monday"

CommandUtil enabled - Getting Cannot read property 'transformOptions' of undefined

Hi,

index.js

const { AkairoClient, CommandHandler } = require('discord-akairo');
...
this.commandHandler = new CommandHandler(this, {
            directory: './commands/',
            prefix: '*', // or ['?', '!'],
            commandUtil: true,
            handleEdits: true
        });
this.commandHandler.loadAll();
...

Using the snippet here

I'm getting this error:

UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'transformOptions' of undefined

If i use the normal message.reply it works just the reply. Perhaps i'm doing something wrong?

version installed:

discord-akairo: 8.0.0-beta.8
discord.js: 11.5.1

Any help would be appreciated, thank you.

List of events

Hi, is there a list of events in the docs? If so, where?
Thanks.

Quotation marks not working on iOS

When using the split: "quoted" option, the quotation marks which are used on iOS (maybe other devices, I'm not sure) aren't recognised as quotation marks.

When command is done from iPhone:
image

When done from Desktop app:
image

Thanks :D

akairo does not support ES6 syntax

Using latest master & djs master
Node 13.11.0:

import { AkairoClient } from 'discord-akairo';

results in

SyntaxError: The requested module 'discord-akairo' does not provide an export named 'AkairoClient'

as workaround you have to do

import Akairo from 'discord-akairo';

class GideonClient extends Akairo.AkairoClient {...

also the commandhandler uses require() on the files instead of import, resulting in

Error: [ERR_REQUIRE_ESM] [ERR_REQUIRE_ESM]: Must use import to load ES Module: C:\Users\Adrian\code\Gideon\akairo\cmds  \admin\abm.js
  require() of ES modules is not supported.

Inhibitor doesn't seem to be working

Hey, I wrote a very simple inhibitor, and if I understand the documentation correctly, the following code should prevent all messages containing 'test' from appearing in the channel:

const {Inhibitor} = require('discord-akairo');
class RoombaInhibitor extends Inhibitor {
    constructor() {
        super('roomba', {
            reason: 'Roomba!',
            type: 'all',
        });
    }
    exec(message) {
        return message.content.toLowerCase().includes('test');
    }
}
module.exports = RoombaInhibitor;

I verified that the exec method returns true, but the message still shows up.
Is this the expected behavior? If so, the documentation doesn't make it clear.

If not, any idea how to fix this?

Date arguments are assumed to be in the server's timezone

Reproducible steps:

  • Make a command which needs a date.
  • Execute that command with for example "2017-07-16 21:00"

Expected result:
Printing the date in the command handler results in "2017-07-16T21:00:00.000Z"

Actual result:
Printing the date in the command handler results in "2017-07-16T19:00:00.000Z" (My timezone is +2 hours)

Rationale:
The timezone of the server has mostly no relation with the user who issued the command.

Some of my code with everything unrelated removed (not yet run):

"use strict";

const { Command } = require('discord-akairo');

class DateCommand extends Command {
    constructor() {
        super('date', {
            aliases: ['date'],
            cooldown: 5000,
            ratelimit: 10,
            split: 'sticky',
            args: [
                {
                    id: 'date',
                    type: 'date',
                }
            ]
        });
    }

    exec(message, args) {
        let date = args.date
        console.log(date)
        
        return Promise.resolve()
    }
};

module.exports = DateCommand

guildMemberAdd - Event isn't working.

So I've read through the docs multiple times and this issue is killing me.

const { Listener } = require('discord-akairo');
const { RichEmbed } = require("discord.js")

class memberAddListen extends Listener {
    constructor() {
        super('guildMemberAdd', {
            event: 'guildMemberAdd',
            emitter: 'client',
            type: "on",
            category: 'guild'
        });
    }

    exec(user) {
        let wms = this.client.settings.get(user.guild.id, "welcome");
        if(!wms) return;
        if(wms.enabled === false) return;
        let wmsg = wms.message || `Welcome __${user.tag}__ to __${user.guild.name}__!`
        let mcn = this.client.settings.get(user.guild.id, "mainchat");
        let channel = this.client.channels.find("id", mcn);
        if(channel) {
            let wx = new RichEmbed().setColor("#0062ff").setTitle(":wave: Welcome!").setDescription(wmsg.replace("{{user}}", user.tag).replace("{{guild}}", user.guild.name))
            channel.send({embed:wx})
        }
    }
}

module.exports = memberAddListen;

This code doesn't work as when the bot is starting I am greeted with
image

I honestly don't know if I'm just being stupid or not.

Async text fields in prompts throw DiscordAPIError: Cannot send an empty message

(node:18356) UnhandledPromiseRejectionWarning: DiscordAPIError: Cannot send an empty message
    at RequestHandler.execute (D:\Projects\backend\packages\streams\node_modules\discord.js\src\rest\RequestHandler.js:170:25)
    at process._tickCallback (internal/process/next_tick.js:68:7)
(node:18356) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:18356) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
{
    id: 'id',
    type: 'string'
    prompt: {
        start: async () => `some text: ${await promise}`,
    },
}

Unexpected `limit` option behaviour during prompting

As per Discord conversation: https://discordapp.com/channels/305153029567676426/387777801412935691/619151476433879062

Adding limit: 4 with match: "separate" during prompting did not stop collecting at 4 phrases.
The infinite prompting continued until I said stop, at which point the collected phrases were parsed and then limited to 4 return values.

Code sample:

const members = yield {
    type: "member",
    match: "separate",
    limit: 4,
    prompt: { start: "List four members" }
};

To make this stop at 4 phrases, prompt: { limit: 4 } worked

Postgres Support?

Is there any way to implement postgres into this or can you do that with the in-built sequelize provider?

Some events no longer emit

As said in the title, after testing multiple things, including using a Listener or directly calling .on('messageReactionAdd', () => console.log('react')), the events don't emit on guilds, they still do on DM and worked fine, but events like messageUpdate or messageReactionAdd or no longer emitted (even though the raw one still get them).
After testing with a quick dummy bot without akairo, it appeared it worked fine again.

Example code:

const cli = new SomeBasicAkairoClient() //needs partials enabled
cli.login('token').catch(console.error);
cli.on('messageReactionAdd', () => console.log('react'));

Working code:

const { Client } = require('discord.js');
const client = new Client(); //with partials enabled too
client.on('messageReactionAdd', () => console.log('react'));
client.login('token');

(both are latest commits of discord.js and akairo)

Allow multiple input values for option flag arguments

Example: !command -flag 1 -flag 2 gives { flag: [1, 2] } given

{
  id: 'flag',
  type: 'integer',
  match: 'option',
  flag: '-flag',
  multipleFlags: true
}

Name of multipleFlags is WIP. Also, what would it do with flag match? Probably nothing but there could be a use case for some feature.

Remove ClientUtil, or detach it from the client.

So what's wrong with ClientUtil now?

ClientUtil currently is a bunch of concepts mashed together:

  • Shortcut functions: attachment, collection, embed, permissionNames

  • Tiny utilities: compareStreaming, fetchMember

  • Resolvers and checks for them: resolve*(s), check*

Seems fine, what is the problem here?

An instance of ClientUtil is attached to every AkairoClient in the
constructor to allow access to the client through the ClientUtil instance, but just one method in ClientUtil actually uses the client (fetchMember)!

  • Shortcut functions are shortcuts for discord.js objects (that don't use a Client instance):

    • Constructors (collection for new Collection, embed for new MessageEmbed, etc.)
    • Object.keys(Permissions.FLAGS) (being permissionNames)
  • compareStreaming doesn't need a client as it compares presences of GuildMember objects given to it.

  • Resolvers and their checks take Collections of structures (Guilds, Users, etc.) and resolve through them, passing them from the resolver to the check, without the ClientUtil's client being used in them.

My Vision

I'll give my opinion for each category I mentioned at the top.

Shortcut Functions

I believe, CommandUtil's shortcuts could be removed completely.

Yeah, it was cool doing this.client.util.embed() instead of importing MessageEmbed over and over again, but is it really such a big difference?

All of the open-source Akairo projects I looked at on GitHub imported MessageEmbed or MessageAttachment, and not their ClientUtil shortcuts

Tiny Utilities

Personally, I never needed / used compareStreaming, nor fetchMember in my own project,
and from my 1-minute GitHub searches (CS, FM), they are not used internally in Akairo.

They could be moved to Akairo's Util class (should also be documented), or removed.

Resolvers (and checks)

Guess what? Akairo has a TypeResolver class, which is the only internal call for ClientUtil's resolvers, which are the only internal call to ClientUtil's checks! Coincidence? I think not!

The reolvers are crucial for arguments, probably the feature Akairo is mostly known for.

For the reason mentioned above, resolvers can't be removed entirely.

BUT they could be moved to static methods on an existing class (TypeResolver / Argument make sense), or to their own class (Resolver could be its name), or somthing along that.

The changes whould not be hard to migrate to if done cleanly, and if I see this being requested, I'll PR and do it myself.

Guess what #101

Using Argument#union with validated arguments throws `TypeError: Cannot read property 'handler' of undefined`

TypeError: Cannot read property 'handler' of undefined
    at typeFn (/project/node_modules/discord-akairo/src/struct/commands/arguments/Argument.js:450:56)
    at Function.cast (/project/node_modules/discord-akairo/src/struct/commands/arguments/Argument.js:370:23)
    at Argument.typeFn (/project/node_modules/discord-akairo/src/struct/commands/arguments/Argument.js:412:44)
    at processTicksAndRejections (internal/process/task_queues.js:94:5)
    at Function.cast (/project/node_modules/discord-akairo/src/struct/commands/arguments/Argument.js:371:39)
    at Argument.process (/project/node_modules/discord-akairo/src/struct/commands/arguments/Argument.js:169:21)
    at ArgumentRunner.run (/project/node_modules/discord-akairo/src/struct/commands/arguments/ArgumentRunner.js:61:25)
    at CommandHandler.handleDirectCommand (/project/node_modules/discord-akairo/src/struct/commands/CommandHandler.js:411:26)
    at CommandHandler.handle (/project/node_modules/discord-akairo/src/struct/commands/CommandHandler.js:377:23)

Occurs when the command argument's type is a union of a validated type

Example reproduction:

Argument.union(
	'integer',
	Argument.validate('uppercase', (message, phrase) => (^[MDCLXVI]+$).test(phrase))
)

possible to have timeout and cancel prompt edit the last start or retry?

I'm currently using

prompt: {
    modifyStart: (message, text) => {
        return `${text}\n\`Type exit to cancel this command.\``;
    },
    cancelWord: 'exit',
    cancel: 'Command has been cancelled.',
}

in my commandHandler and when i type exit to cancel the command it creates a new message saying the command has been canceled or when the message times out it puts a new message saying the command has been canceled. Can I make it where instead of creating a new message it edits the last message instead? I feel it'd be much cleaner and remove some confusion compared to when the prompt question is still visible.

SequelizeProvider and SQLiteProvider delete() function does not update cached data

The delete() function present in both providers deletes the key value specified and affects the database but does not update the cached data.
For example, this.client.settings(message.guild.id, "prefix") returns !
After this.client.settings.delete(message.guild.id, "prefix"),
when running this.client.settings(message.guild.id, "prefix"), still returns !
However, in the actual database, the value is already deleted, just that the local cached storage is not updated.

Separate matched number args causes weird behavior

I made a simple command shown below

import {Command} from 'discord-akairo';
import {Message} from 'discord.js';

export default class BruhCommand extends Command {
	constructor() {
		super('bruh', {
			aliases: ['bruh'],
			description: {content: 'Get the mean of a set of numbers.'},
			category: 'utility',
			args: [
				{
					id: 'numbers',
					match: 'separate',
					type: 'number',
					prompt: {start: 'What numbers should be averaged?', retry: 'Invalid numbers provided, please try again', optional: false}
				}
			]
		});
	}

	async exec(message: Message, {numbers}: {numbers: number[]}): Promise<Message | undefined> {
		console.debug(numbers);
		if (numbers.length > 0) {
			return message.util?.send((numbers.reduce((a, b) => a + b) / numbers.length).toLocaleString());
		}
	}
}

This simply collects an array of numbers and returns the mean of them.
When the command is run with valid numbers, it works as expected.
When the command is run with invalid input (ex. a b c) it does the following

  1. Prompts for valid input several times (sometimes once, sometimes 3 times)
  2. Runs the command anyway, except the number array is an array of Flags
// Sample log output of `args`
[ Flag { type: 'cancel' } ]

The number of Flags passed to args is equal to the number of times correct input was prompted from a retry.

NPM module uses broken typings

For some reason, the npm module seems to have outdated typings -

    export class AkairoClient extends Client {
        public constructor(options: AkairoOptions, clientOptions: ClientOptions);

        public akairoOptions: AkairoOptions;
        public commandHandler: CommandHandler;
        public databases: Object;
        public inhibitorHandler: InhibitorHandler;
        public listenerHandler: ListenerHandler;
        public mem: Object;
        public ownerID: string | string[];
        public selfbot: boolean;
        public util: ClientUtil;

        public addDatabase(name: string, database: SQLiteHandler): this;
        public build(): this;
        public loadAll(): void;
        public login(token: string): Promise<string>;
    }

is the definition it is using, rather than what is found in this repo

CommandHandler loads commands from subfolders several times

When trying to loadAll() commands from folder, that contains subfolders of command files, command handler is trying to load those files second time.
But before I will tell you what problem is, I would like to mention that I use TypeScript and custom Command class:

import { Command, CommandOptions } from "discord-akairo";
import { Repository, getRepository } from "typeorm";
import { Guild } from "../entity/Guild.entity";
import { Search } from "../entity/Search.entity";
import { Chat } from "../entity/Chat.entity";
import { User } from "../entity/User.entity";
import CustomClient from "./Client";
import { Report } from "../entity/Report.entity";
import { Message } from "discord.js";
import i18n from "i18n";

class CustomCommand extends Command {
  client: CustomClient;
  guildRepository: Repository<Guild>;
  searchRepository: Repository<Search>;
  chatRepository: Repository<Chat>;
  userRepository: Repository<User>;
  reportRepository: Repository<Report>;
  user: User;
  guild: Guild;
  chat: Chat;
  userChatId: string;

  constructor(id: string, options?: CommandOptions) {
    super(id, options);
    this.guildRepository = getRepository(Guild);
    this.searchRepository = getRepository(Search);
    this.chatRepository = getRepository(Chat);
    this.userRepository = getRepository(User);
    this.reportRepository = getRepository(Report);
  }

  async before(message: Message) {
    this.user = await this.userRepository.findOne({
      userId: message.author.id
    });
    i18n.setLocale(this.user.locale);

    this.chat = await this.chatRepository.findOne({
      where: [
        {
          user1Id: this.user.userId,
          endedAt: null
        },
        {
          user2Id: this.user.userId,
          endedAt: null
        }
      ]
    });

    if (this.chat) {
      this.userChatId =
        this.chat.user1Id === message.author.id ? "user1Id" : "user2Id";
    }

    if (message.guild) {
      this.guild = await this.guildRepository.findOne({
        where: { discordId: message.guild.id }
      });
    }
  }
}

export default CustomCommand;

The error log is:

(node:6340) UnhandledPromiseRejectionWarning: AkairoError [ALREADY_LOADED]: Command 'config-guild' is already loaded
    at CommandHandler.load (C:\Users\deris\Documents\Projects\AnonChats\node_modules\discord-akairo\src\struct\AkairoHandler.js:137:45)
    at CommandHandler.loadAll (C:\Users\deris\Documents\Projects\AnonChats\node_modules\discord-akairo\src\struct\AkairoHandler.js:156:40)
    at CustomClient.initHandlers (C:\Users\deris\Documents\Projects\AnonChats\dist\struct\Client.js:105:29)
    at CustomClient.init (C:\Users\deris\Documents\Projects\AnonChats\dist\struct\Client.js:53:14)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:6340) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)

This is my folder structure for commands folder, that I specified in directory property for CommandHandler in my Client class:

commands
├── bot
│   ├── help.ts
│   ├── info.ts
│   ├── invite.ts
│   └── ping.ts
├── chat
│   ├── deanon.ts
│   ├── game.ts
│   ├── report.ts
│   ├── search.ts
│   ├── stop.ts
│   └── stopSearch.ts
└── config
    ├── config-guild.ts
    ├── config.ts
    ├── language.ts
    └── prefix.ts

And I checked several times that all of those files contains unique ids.

I've tried to do some experiment with those problem and write this.commandHandler.on("load", command => console.log(command.aliases[0])); in my Client class and that what I have:

help
stats
invite
ping
deanon
game
report
search
stop
stop-search
config-guild
config
language
prefix
(node:6340) UnhandledPromiseRejectionWarning: AkairoError [ALREADY_LOADED]: { error log that I have write above }

So, I can tell that CommandHandler is trying to read dirs with commands the second time, when all commands are already loaded.

client.login does not return on invalid token

Reproducible steps:

const client = new AkairoClient({
    ownerID: '123456679',
    prefix: '$',
    commandDirectory: './commands/',
    inhibitorDirectory: './inhibitors/',
    listenerDirectory: './listeners/'
});
 
client.login('foo').then(() => {
    console.log('Started up!');
}, () => {
    console.error('Failed to startup. :(')
});

Expected result:
Failed to startup is printed and program exits.

Actual result:
Failed to startup is never printed. Nothing is printed. Program does not exit.

Wrong example in the Composing Types section of the Arguments guide

Issue

In the Composing Types section of Arguments part in the guide, the example for Argument.validate shows

{
    id: 'content',
    type: Argument.validate('string', str => str.length < 2000)
}

where the type should be Argument.validate('string', (m, p, str) => str.length < 2000), since the second parameter that Argument.validate takes is a ParsedValuePredicate, which the actual resolved value of the argument is the third parameter of, not the first, unlike shown in the example.
Additionaly, that example will never work, because str will be a Message object, which propery length of is undefined, causing str.length < 2000 (in reality undefined < 2000) to always be false, which will cause the argument to fail. Always.

Fix

Just change the example to

{
    id: 'content',
    type: Argument.validate('string', (m, p, str) => str.length < 2000)
}

Yes, this is tested.

Why don't you just make a PR if you have the fix?

Because I have no git knowledge, unfortunately.

How to take a command with a string of text with spaces as an argument?

I have the need to take a string as input for example with a ban command I want a reason so the command being !ban 354835091211419648 For doing something bad as an advanced example but even something simple like !say Hi there person

if I do something like

args: [
    {
        id: 'msg',
        type: 'string', //I tried 'content' too
        prompt: {
            start: 'What do you want to say?',
            retry: 'Try again',
            optional: false
        },
    }
],

It will work only if I let the prompt pop up, but if I try to just the command at once it only grabs the first word. Am I doing something wrong?

Error Receiving path

After following the setup instructions for the command directory I get this as an error.

TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type undefined

My exact code:
const { AkairoClient, CommandHandler } = require('discord-akairo'); class MyClient extends AkairoClient { constructor() { super({ ownerID: '123992700587343872', // or ['123992700587343872', '86890631690977280'] }, { disableEveryone: true }); this.commandHandler = new CommandHandler(this, { directory: './commands/', prefix: '?' // or ['?', '!'] }); this.commandHandler.loadAll(); } } const client = new MyClient(); client.login('mytoken')

Suggestion: Undo Command

Have an optional extendable function in the command class called "undo", Akairo will detect when a user runs (prefix)undo (customizable?), and if the function is extended, run the undo function in the last ran command by the author

Accessing/editing command module properties on the spot

I tried to edit a command module by adding another alias.
The first thing I did was go into the commandHandler object
const h = this.client.commandHandler.modules.map(e => e); const cmd = h[9]; cmd['aliases'].push('alias2');
The new aliases does get pushed, but the handler doesn't seem to use it. So then, I tried reloading after and the result of that was very, very confusing.
Input ->
const h = this.client.commandHandler.modules.map(e => e); const cmd = h[9]; cmd['aliases'].push('stats'); cmd.reload()
Output ->
> dice
"dice" is a completely different command module, and it didn't work there afterwards either.
Since Akairo is as modular as it is, could you just make another listener for new aliases to be added?

Question: Is there a way to perform actions on startup?

There are some actions that I want my bot to perform on startup. When I used the discord.js client this was simple as I could just pass the client to every event handler.

discord-js/bot.js

fs.readdir('./events', (err, files) => {
    files.forEach(file => {
        const eventHandler = require(`./events/${file}`);
        const eventName = file.split('.')[0];
        client.on(eventName, (...args) => eventHandler(client, ...args));
    });
});

Then I could access the client in the 'ready' event:

discord-js/events/ready.js

const ready = (client) => {
    console.log(`Ready! (Username: ${client.user.username}, ` +
                `ID: ${client.user.id})`);	
    doStuff(client);
}

module.exports = ready;

Is there a way to achieve a similar thing with discord-akairo? My ready listener looks like this:

discord-akairo/listeners/ReadyListener.ts

export default class ReadyListener extends Listener {
    constructor() {
        super('ready', {
            category: 'client',
            emitter: 'client',
            event: 'ready',
        });
    }

    public exec(): void {
        console.log('Ready!');
    }
}

SQLiteProvider.set is saved in db file, but not loaded when bot is restarted

Hello.
Using SQLiteProvider as described in the docs but after a restart of my bot the values in the db file isn't loaded so all values are empty.

I setup the provider like this:

this.settings = new SQLiteProvider(sqlite.open('./data/verifier.sqlite'), 'verifier', {
    idColumn: 'guild_id',
    dataColumn: 'settings'
});

Initializing the provider:

login(token) {
    return this.settings.init().then(() => super.login(token));
}

And I set/get the settings like this:

// Setting guild name
this.client.settings.set(message.guild.id, "guild-name", args.value);

// Getting guild name
var v = this.client.settings.get(message.guild.id, "guild-name", "[None]");

And it always returns "[None]" after a restart of the bot. Before the restart it returns the correct value. And I've verified that the value is actually stored in the db file with DB Browser for SQLite.

Any ideas what the issue could be?

Provide testing utilities

Would be nice if we could mock commands and users so we can unit test our bots.
Possibly expose methods to invoke commands with mocked data.

Add file type for argument

I making a bot for my personal purposes, and I need to get an file from message as argument.
I tried to make my own type, but, as I see, discord-akairo accepts only message.content as argument.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.