https://github.com/almeidx/discore
A lightweight, functional Discord bot framework built on @discordjs/core
https://github.com/almeidx/discore
bot discord discordjs framework typescript
Last synced: 1 day ago
JSON representation
A lightweight, functional Discord bot framework built on @discordjs/core
- Host: GitHub
- URL: https://github.com/almeidx/discore
- Owner: almeidx
- License: apache-2.0
- Created: 2026-03-05T00:00:41.000Z (about 1 month ago)
- Default Branch: main
- Last Pushed: 2026-03-26T12:27:06.000Z (10 days ago)
- Last Synced: 2026-03-26T18:30:04.702Z (10 days ago)
- Topics: bot, discord, discordjs, framework, typescript
- Language: TypeScript
- Homepage:
- Size: 240 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
# @almeidx/discore
A lightweight, functional Discord bot framework built on [`@discordjs/core`](https://github.com/discordjs/discord.js/tree/main/packages/core).
## Features
- **Functional API** — No classes, just functions. `defineCommand`, `defineEvent`, `defineButton`, etc.
- **Type-safe options** — Command options inferred from definitions. `ctx.options.user` is typed automatically.
- **Component routing** — Regex-based `customId` matching with named capture groups as `ctx.params`.
- **Collectors** — `awaitComponent` (single, Promise-based) and `collectComponents` (async iterator).
- **Hooks** — Per-command and global `beforeCommand`/`afterCommand`/`onError` hooks.
- **Command publishing** — `publishCommands` maps definitions to the Discord API format.
## Requirements
- Node.js >= 24.0.0
- `@discordjs/core` >= 3.0.0-dev
## Install
```sh
npm install @almeidx/discore @discordjs/core @discordjs/rest @discordjs/ws
```
## Quick start
```ts
import { REST } from "@discordjs/rest";
import { WebSocketManager } from "@discordjs/ws";
import { GatewayIntentBits, Routes, type RESTGetAPIGatewayBotResult } from "discord-api-types/v10";
import { createBot, defineCommand, publishCommands } from "@almeidx/discore";
const token = process.env.DISCORD_TOKEN!;
const ping = defineCommand({
data: {
name: "ping",
description: "Pong!",
},
handler: async (ctx) => {
await ctx.reply({ content: "Pong!" });
},
});
const rest = new REST().setToken(token);
const gateway = new WebSocketManager({
token,
intents: GatewayIntentBits.Guilds,
fetchGatewayInformation: () => rest.get(Routes.gatewayBot()) as Promise,
});
createBot({ rest, gateway, commands: [ping] });
await publishCommands({ rest, commands: [ping] });
await gateway.connect();
```
## Typed options
```ts
import { ApplicationCommandOptionType } from "discord-api-types/v10";
import { defineCommand } from "@almeidx/discore";
const ban = defineCommand({
data: {
name: "ban",
description: "Ban a member",
options: [
{ name: "user", type: ApplicationCommandOptionType.User, description: "Target user", required: true },
{ name: "reason", type: ApplicationCommandOptionType.String, description: "Ban reason" },
],
},
handler: async (ctx) => {
// ctx.options.user: { user, member } (required — always present)
// ctx.options.reason: string | undefined (optional)
await ctx.reply({ content: `Banned <@${ctx.options.user.user.id}>` });
},
});
```
## Components
Buttons, select menus, and modals use regex patterns with named capture groups:
```ts
import { MessageFlags } from "discord-api-types/v10";
import { defineButton } from "@almeidx/discore";
const verify = defineButton({
customId: /^verify:(?\d+)$/,
handler: async (ctx) => {
const userId = ctx.params.userId; // extracted from the regex match
await ctx.reply({ content: `Verified ${userId}!`, flags: MessageFlags.Ephemeral });
},
});
```
## Collectors
```ts
const response = await ctx.awaitComponent({
filter: (i) => i.customId === "confirm",
timeout: 30_000,
});
// Or iterate over multiple interactions:
const collector = ctx.collectComponents({
filter: (i) => i.customId.startsWith("vote:"),
timeout: 60_000,
});
for await (const interaction of collector) {
await interaction.reply({ content: "Recorded!", flags: MessageFlags.Ephemeral });
}
```
## More examples
See the [`examples/`](./examples) directory.
## License
[Apache-2.0](./LICENSE)