Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 2 additions & 45 deletions apps/docs/docs/Guide/getting-started/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,10 @@ sidebar_position: 1

:::warning

Disploy is currently in development. It is not ready for production use, but you can try it out and give us feedback.
You can view our [v1.0.0 milestone](https://github.com/Disploy/disploy/milestone/1) to see what features are planned for the first release and their current status.
We're still in development, and packages are published to npm every 12 hours to the `@dev` tag. You can view our [v1.0.0 milestone](https://github.com/Disploy/disploy/milestone/1) to see what features are planned for the first release and their current status.

:::

Disploy is a framework for building Discord bots with ease. It's designed to make it easy to build, test and deploy Discord bots.

## It's as easy as 1, 2, 3, 4

### #1

```bash
npx create-disploy-app@latest
# or
yarn create disploy-app
# or
pnpm create disploy-app
```

### #2

```ts
// Example command
import type { Command } from 'disploy';

export default {
name: 'hey',
description: 'heyy!',

async run(interaction) {
return void interaction.editReply({
content: `Just wanted to say hey!`,
});
}
} satisfies Command;
```

### #3

```bash
disploy dev # test your bot locally with hot-reloading and tunneling
```

### #4

```bash
disploy deploy # deploy your bot to Cloudflare Workers
```
Disploy is a library for building HTTP interaction-based Discord bots with ease. It's designed to make it easy to build, test and deploy Discord bots. You can learn more on our GitHub [README](https://github.com/Disploy/disploy#readme).

This guide will walk you through the basics of Disploy, we recommend reading it from top to bottom. If you have any questions, feel free to ask in our [Discord server](https://discord.gg/E3z8MDnTWn).
20 changes: 15 additions & 5 deletions apps/example/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
# `@disploy/example`

Common code for our example bot.
This is an example Discord bot made with Disploy to test the library.

## Implementations
## Usage

- [Express](https://github.com/Disploy/disploy/blob/main/apps/express-example/src/bot.ts)
- [Next.js](https://github.com/Disploy/disploy/blob/main/apps/next-example/pages/api/interactions.ts)
- [Cloudflare worker](https://github.com/Disploy/disploy/blob/main/apps/cf-example)
You should be already running `yarn dev` in the root of the repository (live transpile TypeScript), then you can deploy this bot to a Cloudflare Worker with:

```bash
yarn disploy deploy
```

or just run a local dev server with an ngrok tunnel:

```bash
yarn disploy dev
```

Commands will be automatically registered when running `yarn disploy dev`, but you'll need to manually register them when deploying to a Cloudflare Worker (`yarn disploy sync`).
1 change: 0 additions & 1 deletion apps/example/disploy.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"prebuild": "yarn run build",
"watcher": "yarn run dev",
"root": "dist",
"target": {
"type": "cloudflare",
Expand Down
23 changes: 22 additions & 1 deletion apps/example/src/commands/ping.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import type { Command } from 'disploy';

export default {
Expand All @@ -8,6 +7,28 @@ export default {
async run(interaction) {
return void interaction.reply({
content: 'hello world!!!!!!!!',
components: [
{
type: 1,
components: [
{
type: 2,
label: 'Click me!',
style: 1,
custom_id: `ping-${interaction.user.id}`,
},
{
type: 2,
label: 'i have no params',
style: 2,
emoji: {
name: "🫢"
},
custom_id: `ping`,
},
],
},
],
})
}

Expand Down
14 changes: 14 additions & 0 deletions apps/example/src/handlers/ping.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { ButtonHandler } from "disploy";

export default {
customId: 'ping-:userId',

async run(interaction) {
const originalUser = await interaction.params.getUserParam('userId');
const clicker = interaction.user;

return void interaction.reply({
content: `hello world!!!!!!!! (clicked by ${clicker}) [made by ${originalUser}]`,
});
},
} satisfies ButtonHandler;
12 changes: 12 additions & 0 deletions apps/example/src/handlers/pingNoParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { ButtonHandler } from 'disploy';

export default {
customId: 'ping',

async run(interaction) {
return void interaction.reply({
content: `hello world!!!!!!!! (clicked by ${interaction.user})`,
})
}

} satisfies ButtonHandler;
159 changes: 140 additions & 19 deletions packages/disploy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,56 +17,177 @@

</div>

> **Warning**: We're still in development, and the packages published are not up to date. They're just early builds that we've published to reserve our package names on NPM.
> **Warning**: We're still in development, and packages are published to npm every 12 hours to the `@dev` tag. You can view our [v1.0.0 milestone](https://github.com/Disploy/disploy/milestone/1) to see what features are planned for the first release and their current status.

Disploy is a framework for building Discord bots with ease. It's designed to make it easy to build, test and deploy Discord bots.
Disploy is a library for building HTTP interaction-based Discord bots with ease. It's designed to make it easy to build, test and deploy Discord bots.

## It's as easy as 1, 2, 3, 4
# Features

### #1
Disploy features a [library](#library) and an opinionated [framework](#framework) with tooling inspired by Next.js.

## Library

> Disploy does not come included with a "server", that's up to you to implement. We have a [guide](https://disploy.dev/docs/Reference/framework-less/) 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.

### Usage with Next.js

The API entry point

```ts
// Entrypoint - pages/api/interactions.ts
import { createNextAdapter } from 'disploy';
import { ExampleApp } from '../../lib/main';

export default createNextAdapter(ExampleApp);
```

> **Note**: An "adapter" is a function that transforms requests from your server implementation of choice and creates a [`TRequest`](https://disploy.dev/docs/Documentation/disploy/interfaces/TRequest) that's fed into `App#router#entry` which returns a [`Promise<TResponse>`](https://disploy.dev/docs/Documentation/disploy/classes/TResponse) which your adapter should transform and return to Discord.

Setting up the Disploy App

```ts
// Main Bot - lib/core/main.ts
import { App } from 'disploy';
import commands from './commands/commands';

const clientId = process.env.DISCORD_CLIENT_ID;
const token = process.env.DISCORD_TOKEN;
const publicKey = process.env.DISCORD_PUBLIC_KEY;

if (!clientId || !token || !publicKey) {
throw new Error('Missing environment variables');
}

export const ExampleApp = new App({
logger: {
debug: true,
},
});

ExampleApp.start({
clientId,
token,
publicKey,
});

for (const command of commands) {
ExampleApp.commands.registerCommand(command);
}
```

Setting up an array of commands

```ts
// Command Array - lib/core/commands/commands.ts
import Ping from './core/ping';

const c = [Ping];

export default c;
```

Example command

```ts
import type { ChatInputInteraction, Command } from 'disploy';

const Ping: Command = {
name: 'ping',
description: 'pong!',

run(interaction: ChatInputInteraction) {
interaction.reply({
content: 'Hello World!',
});
},
};

export default Ping;
```

## Framework

Disploy comes inbuilt with a CLI that can bundle your bot based on a file system structure. Inspired by Next.js.

Use the "TypeScript Framework" boilerplate from [`create-disploy-app`](https://github.com/Disploy/create-disploy-app).

```bash
npx create-disploy-app@latest
# or
yarn create disploy-app
# or
pnpm create disploy-app
```

### #2
Here 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.

```ts
// Example command
// Example command - commands/ping.ts
import type { Command } from 'disploy';

export default {
name: 'hey',
description: 'heyy!',
// Command "data"
name: 'ping',
description: 'pong!',

// Command entrypoint
async run(interaction) {
interaction.deferReply(); // You can even defer on serverless platforms like Cloudflare Workers! https://disploy.dev/docs/Guide/learning-the-workflow/creating-commands#run
if (!interaction.guild) {
return void interaction.reply({
content: 'You must use this in a guild.',
});
}

await new Promise((resolve) => setTimeout(resolve, 2000));
interaction.deferReply(); // Synchronously reply to the incoming HTTP request
const guild = await interaction.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)
return void interaction.editReply({
content: `Just wanted to say hey!`,
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.
},
],
},
],
});
}
},
} satisfies Command;
```

### #3
```ts
// Example message component handler - handlers/ping.ts
import type { ButtonHandler } from "disploy";

export default {
customId: 'ping-:userId',

async run(interaction) {
const originalUser = await interaction.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.
const clicker = interaction.user;

return void interaction.reply({
content: `hello world!!!!!!!! (clicked by ${clicker}) [made by ${originalUser}]`,
});
},
} satisfies ButtonHandler;
```

```bash
disploy dev # test your bot locally with hot-reloading and tunneling
```

### #4

```bash
disploy deploy # deploy your bot to Cloudflare Workers
```

The 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.

## Planned Features

### Testing
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{{imports}}

export const Commands = [
export const {{name}} = [
{{array}}
];
3 changes: 2 additions & 1 deletion packages/disploy/cli/assets/code/cfWorkerEntry.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { App } from 'disploy';
import { Commands } from './commands';
import { Handlers } from './handlers';

function createCloudflareAdapter(app) {
return async function (req, randId) {
Expand Down Expand Up @@ -40,7 +41,7 @@ function createCloudflareAdapter(app) {

export default {
async fetch(request, env, ctx) {
const app = new App({ commands: Commands });
const app = new App({ commands: Commands, handlers: Handlers });
app.start({
publicKey: env.PUBLIC_KEY,
clientId: env.CLIENT_ID,
Expand Down
3 changes: 2 additions & 1 deletion packages/disploy/cli/assets/code/standaloneEntry.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { App } from 'disploy';
import { Commands } from './commands';
import { Handlers } from './handlers';

const app = new App();

export default { app, commands: Commands };
export default { app, commands: Commands, handlers: Handlers };
3 changes: 2 additions & 1 deletion packages/disploy/cli/src/lib/compiler/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ export async function parseCommands(workbench: string) {
}),
);

const commandArray = CompilerAssets.commandArray({
const commandArray = CompilerAssets.array({
name: 'Commands',
imports: commandsFiles
.map((file) => `import {${path.basename(file, '.js')}} from "./commands/${path.basename(file, '.js')}";`)
.join('\n'),
Expand Down
Loading