Setup is simple, make sure you have npm installed. Just clone the repo and install dependencies
git clone https://repo.git
cd sjbot
npm install
In order to run the bot, you will need to create a .env
file in the root directory, and then run
npm run dev --symbol=@
note: (--symbol=@) means to run commands via @help
instead of !help
. If it is not set, it will default to _
in dev mode
Hit up @s3b if you want access to the dev server. Will provide you a .env file with the dev keys
config/
- Holds a webpack-inspired config where plugins are imported, and any plugins are initiated with their optionslib/
- The Bastion library, a thing I built on top of the discord.io to make things more opinionated/structuredplugins/
- Subdirectories split by commands, this is where you want to be
Going to walk through making a simple calculator app
The index.js
file expects a function that returns an array of JSON. First argument of the function should be bastion
, which is a reference to the lib. Normally, we'd also take in a second opt
parameter so the plugin can be configed from plugins.config.js
export default function(bastion, opt={}) {
return []
}
A command follows a simple structure (see PluginResolver below)
We're going to create a command that adds two numbers
return [{
command: 'add',
resolve(context, msg) {
const [a, b] = msg.split(" ")
return parseInt(a) + parseInt(b)
}
}]
If you just return a value, the bot will just reply with that to the channel id
This will throw an error if someone just typed !add 5
. There's an option that lets you pre-validate things
return [{
command: 'add',
validate(context, msg) {
if (msg.split(" ").length < 2) return 'Need two numbers to add'
const [a, b] = msg.split(" ")
if (isNaN(parseInt(a)) || isNaN(parseInt(b))) return 'Those are not valid numbers'
}
resolve(context, msg) {
const [a, b] = msg.split(" ")
return parseInt(a) + parseInt(b)
}
}]
If you return a string, the bot will reply the error message. If no return, it will continue on to resolve()
Head over to plugins.config.js
and import your module
// ....
import Calculator from '../plugins/Calculator'
// ....
export default bastion => ([
// ... other plugins
Calculator
])
Bastion will figure out if it needs to pass in it's own reference or not, so no need to explicitely do it
CTRL+C and hit npm run dev
again -- there's no file watcher, so you have to restart it after each change
Plugin
is the json that each plugin uses. Here are the options and helpers it provides
interface Plugin {
/** Restrict this route to these channels [channelID] */
restrict?: string[];
/** If command is restricted, bot will autoreply this message if used outside of restricted channels */
restrictMessage?: string;
/** Ignore these channels [channelID] */
ignore?: string[];
/** Throw an error if dependency is not setup in config */
requires?: string[];
/** The command to use for this plugin to be called. Will run when !{command} is called */
command?: string;
/** An action is a subset of a command, can be called by doing this.route(action) */
action?: string;
/** Automatically reply with a help string if `!{command} help` is called */
help?: string;
/** Send help string if !command is called with no argument. Default false */
helpOnEmpty?: boolean;
/** Takes incoming context, and parses the context. Result of this function gets passed in as the second argument of any Resolver */
options?: Parser;
/** Syntax way to run some validates before passing data to resolve(). If a string is returned, the bot will send that as a message and skip resolve() */
validate?: Resolver;
/** Main router for the command. If string is returned, will reply with just that */
resolve: string|Resolver;
/** Container for command-specific methods. Gets mapped to `this` inside of validate() and resolve() */
methods?: {
[key: string]: Function
};
}
// todo
Type checking is a WIP and kinda new, but it may help you working in a plugin. If using VSCode, it will help you with auto completion, intellisense and validating your arguments
To enable it for your plugin, add this above your imports
/** @typedef {import('@/types').PluginResolver} PluginResolver */
And above your export function, set the type as PluginResolver
/** @type {PluginResolver} */
export default function(bastion, opt={}) {