Warning: We're still in development, and packages are published to npm every 12 hours to the
@devtag. You can view our v1.0.0 milestone to see what features are planned for the first release and their current status.
Disploy is a flexible router for building HTTP interaction-based Discord bots with ease. It's designed to make it easy to build, test and deploy Discord bots.
Disploy features a library and an opinionated framework with tooling inspired by Next.js.
Disploy does not come included with a "server", that's up to you to implement. We have a guide showcasing you how to do so with Express (Node.js) and Deno's inbuilt server.
This is a slimmed-down guide to using Disploy with Next.js as your server.
The API entry point:
// Entrypoint - pages/api/interactions.tsimport{createNextAdapter}from'disploy';import{ExampleApp}from'../../lib/main';exportdefaultcreateNextAdapter(ExampleApp);Note: An "adapter" is a function that transforms requests from your server implementation of choice and creates a
TRequestthat's fed intoApp#router#entrywhich returns aPromise<TResponse>which your adapter should transform and return to Discord.
Setting up the Disploy App:
// Main Bot - lib/core/main.tsimport{App}from'disploy';importcommandsfrom'./commands/commands';constclientId=process.env.DISCORD_CLIENT_ID;consttoken=process.env.DISCORD_TOKEN;constpublicKey=process.env.DISCORD_PUBLIC_KEY;if(!clientId||!token||!publicKey){thrownewError('Missing environment variables');}exportconstExampleApp=newApp({logger: {debug: true,},
commands,});ExampleApp.start({
clientId,
token,
publicKey,});Setting up an array of commands:
// Command Array - lib/core/commands/commands.tsimportPingfrom'./core/ping';constc=[Ping];exportdefaultc;Example command:
importtype{ChatInputInteraction,Command}from'disploy';constPing: Command={name: 'ping',description: 'pong!',run(interaction: ChatInputInteraction){interaction.reply({content: 'Hello World!',});},};exportdefaultPing;Disploy comes inbuilt with a CLI that can bundle your bot based on a file system structure, which is inspired by Next.js.
Use the "TypeScript Framework" boilerplate from create-disploy-app.
npx create-disploy-app@latestHere are two examples, a command and a message component handler. Keep in mind none of this is exclusive to the framework, the only "framework exclusive" feature showcased here is the file structure and default exports.
// Example command - commands/ping.tsimporttype{Command}from'disploy';exportdefault{// Command "data"name: 'ping',description: 'pong!',// Command entrypointasyncrun(interaction){if(!interaction.guild){returnvoidinteraction.reply({content: 'You must use this in a guild.',});}interaction.deferReply();// Synchronously reply to the incoming HTTP requestconstguild=awaitinteraction.guild.fetch();// BaseInteraction#guild is a ToBeFetched class, awaiting fetch on it will return the full structure// All our methods take in raw JSON (or our Message structure, coming soon)returnvoidinteraction.editReply({content: 'hello world!!!!!!!!',components: [{type: 1,components: [{type: 2,label: 'Click me!',style: 1,custom_id: `ping-${interaction.user.id}`,// You can handle message components with express-like routes.},],},],});},}satisfiesCommand;// Example message component handler - handlers/ping.tsimporttype{ButtonHandler}from'disploy';exportdefault{customId: 'ping-:userId',asyncrun(interaction){constoriginalUser=awaitinteraction.params.getUserParam('userId');// This fetches a user structure from the interaction's params, it would be better to use getParam in this use case, but we're showcasing the getUserParam method here.constclicker=interaction.user;returnvoidinteraction.reply({content: `hello world!!!!!!!! (clicked by ${clicker}) [made by ${originalUser}]`,});},}satisfiesButtonHandler;disploy dev # test your bot locally with hot-reloading and tunnelingdisploy deploy # deploy your bot to Cloudflare WorkersThe CLI bundles your app by taking in commands and message components and turning them into a single bundle. It accomplishes this by transforming your default exports into an array, creating an App instance, and attaching an adapter for your specified target.
@disploy/disbench will be a testing library that will allow you to test your bot in a similar way to how you would test a web app with a mocked Discord API. View the repository here.
Example usage (this is not final):
// Disbench demo snippet (fake code)import{Disbench}from'@disploy/disbench';constdisbench=newDisbench({app: 'dist/bot.js',});awaitdisbench.setup();// This will start the bot and start communicating with the framework to "deploy" commands to the mocked APIconstechoCommand=disbench.commands.find({name: 'echo'});constresponse=awaitdisbench.interact(echoCommand,{options: {message: 'Hello World!',},});expect(response).toEqual('Hello World!');Join our Discord server for support and updates!