Fusebot is the simplest way to quickly develop custom Slash Commands for Discord and Slack. Fusebot gives you a Node.js and npm development environment and takes care of running, scaling, and securing your Slash Commands. All you need to bring is your code and imagination.
You interact with Fusebot using the /fusebot
Slash Command from Discord or Slack. It enables you to open a browser-based Node.js and npm development environment to implement any number of custom commands. Once created, the commands can be invoked by anyone in your Slack workspace or Discord guild.
Fusebot was created for developers by developers at fusebit.io and is free to use. We hope you enjoy it!
Installing Fusebot
Code your first command
Interacting with Fusebot
Command code samples
Programming model
Receiving data from Slack or Discord
Managing secrets and configuration
Sending messages back to Slack or Discord
Using storage
Support
- Download Fusebot on Discord or Slack
- Run
/fusebot coin DOGE
to test command
If you see the current value of dogecoin, then Fusebot is successfully installed! Let's move on to coding our first command.
Now that you have Fusebot installed and you tested the /fusebot coin
command, let's get started on building your first custom command. Let's build a command to search reddit. It is best to do development on a desktop browser as you will have more room to work with tabs and copy/paste code.
- Type
/fusebot edit reddit
and hit enter
- Click the "click here" link
Your browser will open a window like this:
You are looking at the Fusebot command editor that allows you to implement the logic behind the reddit command or any command you build. You can write any Node.js code here and use all public npm modules by declaring them in package.json. After you save the code, you can invoke it from Slack or Discord using the /fusebot reddit
Slash Command.
- Open this command.js file in another tab
- Copy and paste the entire command.js file file content into the command.js file in the web editor.
Copy:
Paste:
- Click the save icon in the top left of the web editor
- Return back to Slack or Discord to test out your new reddit command
/fusebot reddit node API
This command will search for "API" in the node subreddit.
BOOM! You've built your first custom command with Fusebot. Check out other examples below and start coding today.
If you are wondering about all of the ways to interact with manage your custom slash commands, just run:
/fusebot help
This is what you can do with Fusebot:
/fusebot ls
list custom commands in your workspace
/fusebot edit {command}
create or edit a custom command
/fusebot rm {command}
remove a command
/fusebot feedback {your-feedback}
tell us what you think (leave contact if expecting response)
/fusebot {command} [arguments]
run a custom command
Note: replace {command} and/or [arguments] with the specific command you are creating or editing. { } denotes an argument you decide.
With the power of Node.js and npm, the sky is the limit. What are you going to build today?
- /fusebot kudos - leave kudos for your team members, check ranking, and more
- /fusebot status - check and report the status of your systems
- /fusebot bitly - shorten URLs using bit.ly
- /fusebot coin - get current value of a digital currency
- /fusebot github-dispatch - trigger a github action
- /fusebot run-query - run SQL queries against MySQL compatible databases
- /fusebot stocks - get current value of a stock
- /fusebot gif - display your favorite meme by name
- /fusebot reddit - search a subreddit for posts
The function exported from command.js
is the entry point to your Slash Command implementation.
The ctx
parameter contains the details of the event generated by Slack or Discord and a few useful methods
described below.
At the time your code executes, we have already done the Slack or Discord signature validation for you, so you can focus on the task at hand. Also, we have responded to Slack, so you are not subject to the 3 second execution limit those platforms impose.
module.export = async (ctx) => {
await ctx.client.send(`Hello ${ctx.body.userName}!`);
};
Using package.json
you can specify a dependency on any public npm module and then use
it code.
{
"engines": {
"node": ">= 14"
},
"dependencies": {
"superagent": "6.1.0"
}
}
The ctx.body
contains the payload describing the event received from Slack or Discord. It is normalized
between the two systems to facilite reusing the same code.
{
"teamId": "TDFBLCJV9",
"channelId": "DFNE1FG2E",
"userId": "UFN96HN1J",
"userName": "tomek",
"text": "hello arg1 arg2 arg3",
"args": ["arg1", "arg2", "arg3"],
"native": {
/* native event received from Slack or Discord */
}
}
The ctx.body.args
contains tokenized arguments the caller passed to your Slash Command. For example,
if the command name is hello
, calling /fusebot hello arg1 arg2 arg3
would result in the ctx.body.args
value shown above.
The ctx.body.native
represents the native event received from Slack or Discord. Check the Slack event schema or the Discord event schema for details.
The ctx.configuration
property provides access to the key/value pairs you define in the Configuration section of the editor. These values are stored encrypted at rest and are a convenient way of providing any secrets or API keys to your code.
// In Configuration:
// MY_KEY=SOME_VALUE
const key = ctx.configuration.MY_KEY;
// key is "SOME_VALUE"
The ctx.client
provides a way to send messages back to Slack or Discord. You can send multiple messages during
a single invocation of your Slash Command.
The ctx.client.send
asynchronous method sends a text message back to Slack or Discord. The message
is visible to anyone in the channel the Slash Command was invoked in. You can use Slack markup, or Discord markup to format the message, respectively:
Remember to wait for the asynchronous method to complete:
await ctx.client.send(`Hello, ${ctx.body.userName}!`);
Works similarly to ctx.client.send
, but the message will only be visible to the person who invoked
the Slash Command.
The ctx.storage
offers access to a simple persistent storage solution. Think about it as local storage,
only in the cloud.
Returns a named document or undefined if no document is stored under the specified name:
const item = await ctx.storage.get("my_data");
// item is:
// {
// data: { ...object you previously stored... },
// etag: "{etag}"
// }
The etag
property describes the version of the item in storage which can be used in the call to ctx.storage.put
to detect and prevent conflicting, concurrent writes.
You can omit the document name to read the default document.
Upserts a named document:
const item = {
data: { ...whatever object you want to store... },
etag: "{etag}" // optional
};
await ctx.storage.put(item, "my_data")
If you specify the etag
property (usually by obtaining it from a prior ctx.storage.get
call), and the
document in storage has changed since then, the call will fail with an exception indicating a conflict.
If you don't specify the etag
property, any data in storage will be forcefuly overwritten.
You can omit the document name to write to the default document.
The ctx.storage.list
returns the list of existing documents:
const result = await ctx.storage.list();
// result is
// {
// items: [ { storageKey: "{storageKey1}" }, ... ],
// next: "{continuation-token}" // optional
// }
If you organize your documents in a hierarchy using the /
character as segment delimiter, you can also
list only the documents underneath a particular segment of the hierarchy:
const result = await ctx.storage.list("/a/b");
If the result.next
property is present, there are more results which can be obtained with a subsequent call
to the API:
const next;
const result = await ctx.storage.list("/a/b", { next });
You can limit the maximum number of results returned using the limit
parameter:
const result = await ctx.storage.list("/a/b", { limit: 10 });
The ctx.storage.delete
deletes an item from storage:
await ctx.storage.delete("my_data");
If you organize your documents in a hierarchy using the /
character as segment delimiter, you can also
delete an entire branch of documents with a single call:
// Existing documents:
// /a/b/c/d
// /a/b/e/f
// /a/b/
// /a/g/h/i
await ctx.storage.delete("/a/b", true, true);
// Documents after delete:
// /a/b/
// /a/g/h/i
NOTE Deleteing /a/b
recursively deletes all documents underneath /a/b
but not /a/b
itself.
NOTE The two true
parameters are not a typo - they are intended to prevent accidental deletion of the entire storage.
You can share your thoughts or ask questions using /fusebot feedback
command, contacting the Fusebit team.