Giter Club home page Giter Club logo

tscord's Introduction

Latest version

Build state Repo size Stars count

What is TSCord

TSCord is a fully-featured discord bot template written in Typescript, intended to provide a framework that's easy to use, extend and modify.

It uses discordx and discord.js v14 under the hood to simplify the development of discord bots.

This template was created to give developers a starting point for new Discord bots, so that much of the initial setup can be avoided and developers can instead focus on meaningful bot features. Developers can simply follow the installation and the configuration instructions, and have a working bot with many boilerplate features already included!

Getting started is as easy as one command

npx tscord init bot my-bot

To know how to use TSCord and all its components, check the documentation here γ…€

But TSCord is not only a Discord bot template...

A ready-to-use fancy dashboard for your TSCord bot

Customizable static homepage for your TSCord-based bot

tscord-website.preview.mp4

Really useful CLI meant to initialize a new TSCord project, generate files by type or even manage plugins

tscord-cli.preview.mp4

Fully extensible thanks to the plugin eco-system


πŸ“œ Features

Talking about features, here are some of the core features of the template:

  • Advanced handlers for:
    • Interactions (slash, context menu, button, modal, select menu, etc)
    • Simple message commands
    • Discord events listeners
  • Guards functions, acting like middlewares on handlers with some built-ins:
    • Rate limiter
    • Maintenance mode
    • Disabling command
    • Guild only command (no DMs)
    • NSFW only command
    • Message's content match using regex
  • Internal API to interact with the bot from external services, with built-in useful endpoints
  • Multiple databases support out-of-the-box using Mikro-ORM
  • Migrations system to keep a safe database
  • Custom events handlers
  • Advanced error handler
  • Fully-typed localization (i18n)
  • Local store to manage global state through the app
  • Advanced logger with log files and discord channels support
  • Scheduler for cron jobs
  • Built-in rich statistics system
  • Automatic static assets upload to imgur

This template is also developer friendly and follow strict design patterns to ease its maintenance:

  • Written in Typescript
  • Built around the Dependency Injection and Singleton patterns
  • HMR on events and commands for a faster development
  • Use of battle-tested libraries under the hood (discordx and discord.js)
  • Linting and formatting thanks to a top-notch ESLint config
  • Typesafe and validated environment variables
  • Built-in debugging setup for VSCode
  • Support for running with the PM2 process manger
  • Support for running with Docker
  • CI/CD integration with Github Actions

and many more!

πŸ“š Documentation

Check the official documentation to get started and understand how to use this template.

You can also find useful documentations at:

πŸ“’ Support

If you need support on the template or just want to exchange with us, don't hesitate to join the official Discord support server!

Roadmap

We use Github milestones for

Click here to access the milestone roadmap

πŸ“‘ License

MIT License

Copyright (c) barthofu

tscord's People

Contributors

airone01 avatar barthofu avatar dependabot[bot] avatar dmsavchik avatar mr-artemus avatar sykhodev 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

tscord's Issues

[Bug] yarn & pnpm unsupported

What happened?

I cannot build or run dev with the latest version pulled from github

Reproduction

  • Use the template in a new repo
  • Clone the repo
  • pnpm i
  • pnpm run build

Relevant log output

src/api/controllers/health.ts:26:50 - error TS2339: Property 'get' does not exist on type 'SqlEntityRepository<object>'.

26             lastStartup: await this.db.get(Data).get('lastStartup'),
                                                    ~~~

src/commands/Admin/prefix.ts:44:14 - error TS2339: Property 'prefix' does not exist on type 'object'.

44    guildData.prefix = prefix || null
                ~~~~~~

src/events/custom/simpleCommandCreate.ts:31:33 - error TS2339: Property 'updateLastInteract' does not exist on type 'SqlEntityRepository<object>'.

31         await this.db.get(User).updateLastInteract(command.message.author.id)
                                   ~~~~~~~~~~~~~~~~~~

src/events/custom/simpleCommandCreate.ts:32:34 - error TS2339: Property 'updateLastInteract' does not exist on type 'SqlEntityRepository<object>'.

32         await this.db.get(Guild).updateLastInteract(command.message.guild?.id)
                                    ~~~~~~~~~~~~~~~~~~

src/events/interactionCreate.ts:37:33 - error TS2339: Property 'updateLastInteract' does not exist on type 'SqlEntityRepository<object>'.

37         await this.db.get(User).updateLastInteract(interaction.user.id)
                                   ~~~~~~~~~~~~~~~~~~

src/events/interactionCreate.ts:38:34 - error TS2339: Property 'updateLastInteract' does not exist on type 'SqlEntityRepository<object>'.

38         await this.db.get(Guild).updateLastInteract(interaction.guild?.id)
                                    ~~~~~~~~~~~~~~~~~~

src/events/ready.ts:56:33 - error TS2339: Property 'set' does not exist on type 'SqlEntityRepository<object>'.

56         await this.db.get(Data).set('lastStartup', Date.now())
                                   ~~~

src/services/Database.ts:55:43 - error TS2769: No overload matches this call.
  Overload 1 of 2, '(entityName: EntityName<object>): SqlEntityRepository<object>', gave the following error.
    Argument of type 'EntityName<T>' is not assignable to parameter of type 'EntityName<object>'.
      Type 'EntitySchema<T, any>' is not assignable to type 'EntityName<object>'.
        Type 'EntitySchema<T, any>' is not assignable to type 'EntitySchema<object, any>'.
          Types of property 'addProperty' are incompatible.
            Type '(name: string & keyof T, type?: TypeType | undefined, options?: EntityProperty<any> | PropertyOptions<T> | undefined) => void' is not assignable to type '(name: never, type?: TypeType | undefined, options?: EntityProperty<any> | PropertyOptions<object> | undefined) => void'.
              Types of parameters 'options' and 'options' are incompatible.
                Type 'EntityProperty<any> | PropertyOptions<object> | undefined' is not assignable to type 'EntityProperty<any> | PropertyOptions<T> | undefined'.
                  Type 'PropertyOptions<object>' is not assignable to type 'EntityProperty<any> | PropertyOptions<T> | undefined'.
                    Type 'PropertyOptions<object>' is not assignable to type 'PropertyOptions<T>'.
                      Type 'T' is not assignable to type 'object'.
  Overload 2 of 2, '(entityName: EntityName<object>): EntityRepository<object>', gave the following error.
    Argument of type 'EntityName<T>' is not assignable to parameter of type 'EntityName<object>'.

55         return this._orm.em.getRepository(entity)
                                             ~~~~~~


src/services/ImagesUpload.ts:31:9 - error TS2322: Type 'SqlEntityRepository<object>' is not assignable to type 'ImageRepository'.
  Types of property 'entityName' are incompatible.
    Type 'EntityName<object>' is not assignable to type 'EntityName<Image>'.
      Type 'EntitySchema<object, any>' is not assignable to type 'EntityName<Image>'.
        Type 'EntitySchema<object, any>' is not assignable to type 'EntitySchema<Image, any>'.
          The types of 'meta.addProperty' are incompatible between these types.
            Type '(prop: EntityProperty<object>, sync?: boolean | undefined) => void' is not assignable to type '(prop: EntityProperty<Image>, sync?: boolean | undefined) => void'.
              Types of parameters 'prop' and 'prop' are incompatible.
                Type 'EntityProperty<Image>' is not assignable to type 'EntityProperty<object>'.
                  Types of property 'name' are incompatible.
                    Type 'string' is not assignable to type 'never'.
                      Type 'string' is not assignable to type 'never'.

31         this.imageRepo = this.db.get(Image)
           ~~~~~~~~~~~~~~

src/services/Pastebin.ts:50:49 - error TS2339: Property 'editCode' does not exist on type 'object'.

50         await this.client.deletePaste(id, paste.editCode)
                                                   ~~~~~~~~

src/services/Pastebin.ts:60:51 - error TS2339: Property 'createdAt' does not exist on type 'object'.

60             const diff = dayjs().diff(dayjs(paste.createdAt), 'day')
                                                     ~~~~~~~~~

src/services/Pastebin.ts:62:31 - error TS2339: Property 'lifetime' does not exist on type 'object'.

62             if (diff >= paste.lifetime) {
                                 ~~~~~~~~

src/services/Pastebin.ts:63:53 - error TS2339: Property 'id' does not exist on type 'object'.

63                 await this.client.deletePaste(paste.id, paste.editCode)
                                                       ~~

src/services/Pastebin.ts:63:63 - error TS2339: Property 'editCode' does not exist on type 'object'.

63                 await this.client.deletePaste(paste.id, paste.editCode)
                                                                 ~~~~~~~~

src/services/Stats.ts:34:9 - error TS2322: Type 'SqlEntityRepository<object>' is not assignable to type 'EntityRepository<Stat>'.
  Types of property 'entityName' are incompatible.
    Type 'EntityName<object>' is not assignable to type 'EntityName<Stat>'.
      Type 'EntitySchema<object, any>' is not assignable to type 'EntityName<Stat>'.
        Type 'EntitySchema<object, any>' is not assignable to type 'EntitySchema<Stat, any>'.
          The types of 'meta.addProperty' are incompatible between these types.
            Type '(prop: EntityProperty<object>, sync?: boolean | undefined) => void' is not assignable to type '(prop: EntityProperty<Stat>, sync?: boolean | undefined) => void'.
              Types of parameters 'prop' and 'prop' are incompatible.
                Type 'EntityProperty<Stat>' is not assignable to type 'EntityProperty<object>'.
                  Types of property 'name' are incompatible.
                    Type 'string' is not assignable to type 'never'.
                      Type 'string' is not assignable to type 'never'.

34         this.statsRepo = this.db.get(Stat)
           ~~~~~~~~~~~~~~

src/services/Stats.ts:179:32 - error TS2339: Property 'id' does not exist on type 'object'.

179                     user: user.id
                                   ~~

src/services/Stats.ts:201:49 - error TS2339: Property 'getActiveGuilds' does not exist on type 'SqlEntityRepository<object>'.

201         const guilds = await this.db.get(Guild).getActiveGuilds()
                                                    ~~~~~~~~~~~~~~~

src/utils/functions/database.ts:20:30 - error TS2339: Property 'add' does not exist on type 'SqlEntityRepository<object>'.

20         await dataRepository.add(
                                ~~~

src/utils/functions/image.ts:25:19 - error TS2339: Property 'url' does not exist on type 'object'.

25     return image?.url || null
                     ~~~

src/utils/functions/maintenance.ts:12:46 - error TS2339: Property 'get' does not exist on type 'SqlEntityRepository<object>'.

12     const maintenance = await dataRepository.get('maintenance')
                                                ~~~

src/utils/functions/maintenance.ts:23:26 - error TS2339: Property 'set' does not exist on type 'SqlEntityRepository<object>'.

23     await dataRepository.set('maintenance', maintenance)
                            ~~~

src/utils/functions/prefix.ts:19:23 - error TS2339: Property 'prefix' does not exist on type 'object'.

19     return guildData?.prefix || generalConfig.simpleCommandsPrefix
                         ~~~~~~

src/utils/functions/synchronizer.ts:100:40 - error TS2339: Property 'getActiveGuilds' does not exist on type 'SqlEntityRepository<object>'.

100     const guildsData = await guildRepo.getActiveGuilds()
                                           ~~~~~~~~~~~~~~~


Found 23 errors in 14 files.

Errors  Files
     1  src/api/controllers/health.ts:26
     1  src/commands/Admin/prefix.ts:44
     2  src/events/custom/simpleCommandCreate.ts:31
     2  src/events/interactionCreate.ts:37
     1  src/events/ready.ts:56
     1  src/services/Database.ts:55
     1  src/services/ImagesUpload.ts:31
     5  src/services/Pastebin.ts:50
     3  src/services/Stats.ts:34
     1  src/utils/functions/database.ts:20
     1  src/utils/functions/image.ts:25
     2  src/utils/functions/maintenance.ts:12
     1  src/utils/functions/prefix.ts:19
     1  src/utils/functions/synchronizer.ts:100
 ELIFECYCLE  Command failed with exit code 2.

Code of Conduct

  • I agree to follow this project's Code of Conduct

[Bug] DB Entity update process

What happened?

After I added the new property to User entity named balance I expected it to go live with next boot up of the bot.

    @Property()
    balance: number = 100

On other hand it gave me the error first saying that column is not present, after investigation got an adivse to make migration for DB

npm run migration:create && nom run migration:up"

Which brough up an error:

alter table `user` add column `balance` integer not null; - SQLITE_ERROR: Cannot add a NOT NULL column with default value NULL

then we found that this can be fixed by changing the way it described in User Entiry

    @Property({ default: 100 })
    balance: number

Which is works nice.

Would be good to iclude this in the Documentation for visibility

Reproduction

add new property

    @Property()
    balance: number = 100

and try to migrate with sqlite as your database

Relevant log output

alter table `user` add column `balance` integer not null; - SQLITE_ERROR: Cannot add a NOT NULL column with default value NULL

Code of Conduct

  • I agree to follow this project's Code of Conduct

[Feature] JSDoc

Feature?

Complete the JSDoc everywhere on the template, with links to the official documentation, etc

[Bug] Simple commands not handled in DMs

What happened?

The client doesn't listen to messageCreate of DMs messages.

Reproduction

  1. Write a simple handler of the messageCreate event
@On('messageCreate')
async handler() {
     console.log('invoked')
}
  1. Send a message to the bot in DM
  2. You won't have anything logged in the console

Relevant log output

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

[Feature] Plugins

Feature?

Add a plugin ecosystem to TSCord, so that everyone can code its little add-on for TSCord.
Would come with a CLI to download, manage, search, etc plugins.

[Bug] Random crashs at startup

What happened?

The bot randomly crash at startup because of the WSOn decorator.

Reproduction

No response

Relevant log output

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

[Feature] CLI

Feature?

The purpose of this issue is to submit ideas of enhancements and new features to the current CLI

Migration

Migrating from plop to another CLI engine (maybe NX?).
Plopjs is quite slow and we can do that way better.

Template generations

Add the following type of files to the already existing template-based generation:

  • Error classes
  • Service
  • Utils
    • Class
    • Function
    • Decorator
  • API route
  • API middleware
  • i18n language (would c/p an other language file to have it boilerplate ready)

Plugins

Add plugins management:

  • install <plugin_name | gh repo url>
  • uninstall <plugin_name>
  • search <query>
  • update <plugin_name>

[Feature] Tags and recursive scanning of assets

Feature?

Currently, only images placed directly in the assets/ folders are scanned by the bot.
I want to have a recursive scan of files and then the folders they're in would be registered in the db as tags so we can search them quite fast.

E.g:
The following image

assets/foo/bar/image.png

have the foo and bar tags.

[Bug] `koa-context-validator` is throwing an error rather than returning a `400 response`

What happened?

Not quite a bug but more of an unexpected behavior.
The koa-context-validator is throwing an error on the server when the request's query/body is not validated.
It would be better to return it to the client in the form of a 400 (bad argument) response error, with the Joi's error description as the response message.

But the middleware ecosystem of Koya is quite poor and rarely used.
I propose to either:

  • Create our own middleware (and possibly publish it on npm)
  • Switch to another web server (such as @node-decorators/express)

Reproduction

No response

Relevant log output

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

[Bug] Intents causing infinite error loop

What happened?

If the bot is started with bad Intents flags, and because the bot won't crash as it should due to the Error Handler, it will cause an infinite error logging loop, as well as not working at all.

Reproduction

No response

Relevant log output

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

[Bug] Discord error before client is up

What happened?

It can happen that an error is thrown before the discord client is online, and the Error Handler will try to send it via en embed anyway, resulting in an error loop.

Reproduction

No response

Relevant log output

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

[Bug] Help and Stat command send new message at every interaction

What happened?

When I interact with a component like a button or a dropdown, the bot send a new response that never anwsered.

image

Reproduction

Execute /help command et choose an entry from the dropdown

Relevant log output

error [21/08/2022 - 00:33:11] Unhandled rejection : The reply to this interaction has already been sent or deferred.
        > /workspaces/tscord-template/node_modules/discord.js/src/structures/interfaces/InteractionResponses.js:217
        > /workspaces/tscord-template/src/commands/General/help.ts:47
        > /workspaces/tscord-template/node_modules/discordx/src/decorators/classes/Method.ts:85
        > /workspaces/tscord-template/src/guards/extractLocale.ts:28
        > /workspaces/tscord-template/node_modules/discordx/src/decorators/classes/Method.ts:94
error [21/08/2022 - 00:33:13] Unhandled rejection : The reply to this interaction has already been sent or deferred.
        > /workspaces/tscord-template/node_modules/discord.js/src/structures/interfaces/InteractionResponses.js:217
        > /workspaces/tscord-template/src/commands/General/help.ts:47
        > /workspaces/tscord-template/node_modules/discordx/src/decorators/classes/Method.ts:85
        > /workspaces/tscord-template/src/guards/extractLocale.ts:28
        > /workspaces/tscord-template/node_modules/discordx/src/decorators/classes/Method.ts:94

Code of Conduct

  • I agree to follow this project's Code of Conduct

[Bug] Infinite error loop

What happened?

Infinite error loops can happens and should be avoided.

Solution

Put a limit on the number of times an error can happen without crashing the bot.

Reproduction

No response

Relevant log output

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

[Feature] Simplification of localization in handlers

Feature?

Create a middleware to automaticaly extract the sanitized locale and the L function from interactions. With this, no need to import getLocaleFromInteraction and L from @i18n anymore, and this will lead to less "useless" lines of code as localized content is used in nearly every commands.

Originaly asked by @Sykhodev

[Feature] `create-tscord-bot`

Feature?

Add the possibility to install the template using npx create-tscord-bot, which will prompt options (using plop or something else) to generate the template.

We could also think of a create-tscord-app, which will setup the entire monolith environment of TSCord (bot, dashboard, website, proxy, website analytics, traeffik, etc).

[Bug] Some commands doesn't work

What happened?

Some commands doesn't seem to have access to localize guardData.

Reproduction

  1. Execute the /prefix or /invite command for example.
  2. The bot "crash"

Relevant log output

error [20/08/2022 - 15:59:21] Unhandled rejection : Cannot read properties of undefined (reading 'COMMANDS')
        > /workspaces/tscord/src/commands/General/stats.ts:70
        > /workspaces/tscord/node_modules/discordx/src/decorators/classes/Method.ts:85
        > /workspaces/tscord/src/guards/extractLocale.ts:28
        > /workspaces/tscord/node_modules/discordx/src/decorators/classes/Method.ts:94
        > /workspaces/tscord/node_modules/discordx/src/decorators/classes/Method.ts:94
        > /workspaces/tscord/src/guards/notBot.ts:16
        > /workspaces/tscord/node_modules/discordx/src/decorators/classes/Method.ts:94

Code of Conduct

  • I agree to follow this project's Code of Conduct

[Feature] Beautify discord channel logs

Feature?

Beautify logs embeds sent to discord with :

  • Default style for each type of log (error, info, warn, etc)
  • Custom styles (ex: command / guild tracking, critical errors, etc)

[Bug] Retrieve channels from cache

What happened?

Replace all the client.channels.cache.get('channel_id') (which only returns already fetched channels from the cache) with client.channels.fetch('channel_id')

Reproduction

No response

Relevant log output

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

[Bug] `fs` crash caused by `backupPath`

What happened?

The bot crash when needing to access the backupPath with fs. Must be replace with a __dirname relative version of the path, like the others used by fs.

Reproduction

No response

Relevant log output

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

[Feature] Ukrainian and Russian Translation

Feature

Would be great to have Ukrainian and Russian translation added to the template so it would be more accessible and ready to use for communities with those languages.

[Bug] undefined `image.size`

What happened?

When the automaticUploadImagesToImgur option is set to true but no imgur client_id is referenced in the .env, the upload to imgur fails and some properties of the Image entity are not defined.

image

Fixes todo:

  • turn off by default the option in the config
  • add a special handling in case of failure of the upload in the service
  • in the check before the call of the service (in the main.ts), don't just check if the IMGUR_CLIENT_ID env variable is set but that's also different from the default value of the .env.example

Reproduction

  1. Set automaticUploadImagesToImgur config option to true
  2. Set the IMGUR_CLIENT_ID env variable as an invalid client_id
  3. Add an image in the assets/ folder
  4. Start the bot

Relevant log output

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

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.