README
Opinionated framework for creating Discord bots with minimal boilerplate
cordless is a simple wrapper for discord.js that allows you to create extensive and extensible Discord bots.
yarn add cordless
npm i cordless
Basic Usage
Follow this guide to create a Discord bot in the Discord developer portal.
TypeScript:
import { init, BotFunction } from 'cordless'
const ping: BotFunction = {
condition: (msg) => msg.content === 'ping',
callback: (msg) => msg.reply('pong'),
}
init({ functions: [ping] }).login('your.bot.token')
JavaScript:
const cordless = require('cordless')
const ping = {
condition: (msg) => msg.content === 'ping',
callback: (msg) => msg.reply('pong'),
}
cordless.init({ functions: [ping] }).login('your.bot.token')
Table of Contents
Advanced Usage
Automatic documentation
Auto-generate a help function for your bot by passing a helpCommand
.
Make sure you give your functions a name and description if you want to use them with the generated help function.
For example, let's generate a !help
command:
const ping: BotFunction = {
name: 'ping',
description: 'Responds to your ping with a pong!\n\nUsage: ping',
condition: (msg) => msg.content === 'ping',
callback: (msg) => msg.reply('pong'),
}
const client = init({
functions: [ping],
helpCommand: '!help',
})
client.login('your.bot.token')
Now your bot can respond to !help
:
Share business logic with Context
You can share business logic and state between your different functions using context. By default, the context contains the discord.js
client and the current list of functions.
For example, here is a function that uses context to display the number of functions available:
const numberOfFunctions: BotFunction = {
condition: (msg) => msg.content === 'How many functions?',
callback: (msg, context) => {
msg.reply(`There are ${context.functions.length} functions.`)
},
}
You can also extend the context with your own custom context.
Here's a basic implementation of state management - the count
will be shared between function calls and its value will be persisted:
TypeScript:
const state = {
count: 0,
increment: () => {
state.count++
},
}
type MyCustomContext = {
state: {
count: number
increment: () => void
}
}
const counter: BotFunction<MyCustomContext> = {
condition: (msg) => msg.content === 'count',
callback: (msg, context) => {
context.state.increment()
msg.reply(`The count is ${context.state.count}`)
},
}
const client = init<MyCustomContext>({
functions: [counter],
context: { state },
})
JavaScript:
const state = {
count: 0,
increment: () => {
state.count++
},
}
const counter = {
condition: (msg) => msg.content === 'count',
callback: (msg, context) => {
context.state.increment()
msg.reply(`The count is ${context.state.count}`)
},
}
const client = cordless.init({
functions: [counter],
context: { state },
})
Using discord.js features
The init
method returns a discord.js Client.
Read the discord.js documentation for more information about using the client.
const client = init({
// ...
})
client.on('ready', () => {
console.log(`Logged in as ${client.user?.tag}!`)
})
client.on('message', console.log)
client.login('your.bot.token')
Local development
Clone and install the dependencies:
git clone https://github.com/TomerRon/cordless.git
cd cordless
yarn
We recommend installing yalc. Publish your changes locally with:
yalc publish
You can then test your changes in a local app using:
yalc add cordless
Unit tests
Run the unit tests:
yarn test
End-to-end tests
You must first create two bots and add them to a Discord server. One of the bots will run the cordless client, and the other bot will pretend to be a normal user.
You'll need the tokens for both of the bots, and the channel ID of a channel where the bots can send messages.
Copy the .env
file and edit it:
cp .example.env .env
# .env
E2E_CLIENT_TOKEN=some.discord.token
E2E_USER_TOKEN=some.discord.token
E2E_CHANNEL_ID=12345678
Run the e2e tests:
yarn e2e
Special thanks
Huge shoutout to fivenp (@fivenp) for the amazing visual assets. Go check out his work!
License
This project is licensed under the ISC License - see the LICENSE file for details.