Skip to content

Repository files navigation

🤖 Harmonix Framework

npm versionTypeScriptLicense: MIT

A modern, type-safe Discord.js framework with decorators and advanced features.

Typed decorators without repeated generics

Decorated classes are the primary HarmonixJS API. Create a typed decorator definition once, then reuse it for the class and its inferred handler:

constGuildCreated=Event(Events.GuildCreate);
@GuildCreatedexportdefaultclassGuildCreatedEvent{execute=GuildCreated.handler(async(bot,guild)=>{// guild is inferred as Guild});}constPing=Command({name: "ping",description: "Ping",type: "prefix"});
@PingexportdefaultclassPingCommand{execute=Ping.handler(async(bot,ctx)=>{// ctx is inferred as CommandContext<"prefix">});}

No implements EventExecutor<...> or implements CommandExecutor<...> is required. The defineEvent, defineCommand, and defineComponent helpers remain available as a secondary functional API.

Application events are declared once through module augmentation:

declare module "@harmonixjs/core"{interfaceHarmonixCustomEvents{"guild:configured": [guildId: string,enabled: boolean];}}bot.events.on("guild:configured",(bot,guildId,enabled)=>{// bot is always injected as the first argument});awaitbot.events.emitAsync("guild:configured",guild.id,true);

Providers use the same typed registry pattern:

declare module "@harmonixjs/core"{interfaceHarmonixProviderRegistry{notifications: NotificationProvider;}}constbot=newHarmonix({// ...providers: [newNotificationProvider()]});bot.providers.notifications.send();

Harmonix can be used from JavaScript projects. TypeScript remains recommended for the typed decorators, plugin registries, and provider registries.

✨ Features

  • 🎯 TypeScript-friendly with full type safety when you want it
  • 🎨 Decorator-based commands and events
  • 📥 Automatic imports so you write less and code faster
  • 🔌 Plugin system for extensibility
  • 🚀 Easy to use with minimal setup

📦 Installation

npm install @harmonixjs/core tsx discord.js

🚀 Quick Start

1. Initialize TypeScript (optional, recommended)

npx tsc --init

Update tsconfig.json:

{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"outDir": "dist",
"esModuleInterop": true
}
}

2. Create your bot

// src/index.tsimport{Harmonix}from"@harmonixjs/core";import{DatabasePlugin}from"@harmonixjs/quick-db";interfaceUser{id: string;coins: number;}constbot=newHarmonix({bot: {id: "YOUR_BOT_CLIENT_ID",token: "YOUR_BOT_TOKEN"},publicApp: true,folders: {commands: "./src/commands",events: "./src/events",components: "./src/components"},plugins: [newDatabasePlugin()],intents: [3249151]// (All Intents)});// The plugin name and type are inferred automatically.constusers=bot.plugins.database.table<User>("users");// Start listeningbot.start();

3. Create a command / event / component

// src/commands/Ping.tsconstPing=Command({name: "ping",description: "Ping command"});
@PingexportdefaultclassPingCommand{execute=Ping.handler(async(bot,ctx)=>{awaitctx.reply(`Pong! ${bot.ws.ping}ms`);});}
// src/events/Ready.tsconstReady=Event(Events.ClientReady);
@ReadyexportdefaultclassClientReady{execute=Ready.handler((bot,client)=>{bot.logger.sendLog("SUCCESS",`Bot is ready! Logged in as ${client.user.tag}`);});}
// src/components/TestButton.tsconstTestButton=Component({id: "test_button"});
@TestButtonexportdefaultclassTestButtonComponent{execute=TestButton.handler(async(bot,ctx)=>{awaitctx.reply("Test button clicked!");});}

JavaScript projects can use the functional helpers instead of decorator syntax:

// src/commands/ping.jsconst{ defineCommand }=require("@harmonixjs/core");module.exports=defineCommand({name: "ping",description: "Ping command"},async(bot,ctx)=>{awaitctx.reply(`Pong! ${bot.ws.ping}ms`);});

4. Run your bot

npx tsx src/index.ts

📚 Documentation

🔌 Plugins

Harmonix supports first-class plugins — you can add plugins directly to the framework to register commands, events, middleware, or extend internals.

Official and third-party plugins can augment the typed registry:

exportclassMyPluginimplementsHarmonixPlugin{readonlyname="myPlugin"asconst;init(bot: Harmonix){// Initialize the plugin.}}declare module "@harmonixjs/core"{interfaceHarmonixPluginRegistry{myPlugin: MyPlugin;}}

Applications can then use bot.plugins.myPlugin without a generic, optional chaining, or a non-null assertion. Accessing a plugin that was not registered throws an explicit runtime error.

Application command capabilities

Harmonix forwards Discord.js application-command options directly:

import{ApplicationCommandOptionType,ApplicationCommandType,ApplicationIntegrationType,InteractionContextType}from"discord.js";
@Command({name: "profile",description: "Display a profile",contexts: [InteractionContextType.Guild,InteractionContextType.BotDM,InteractionContextType.PrivateChannel],integrationTypes: [ApplicationIntegrationType.GuildInstall,ApplicationIntegrationType.UserInstall],options: [{name: "user",description: "The user to display",type: ApplicationCommandOptionType.User}]})

User and message context commands are also supported:

@Command({name: "View profile",type: "user",applicationType: ApplicationCommandType.User})
  • @harmonixjs/quick-db: Simple and flexible Quick.db plugin for Harmonix Discord framework.
  • @harmonixjs/express: A powerful Express-based HTTP API plugin for the Harmonix Discord framework.
  • @harmonixjs/i18n: Runtime translations and Discord command localization.
  • @harmonixjs/shard: Automatic multi-process sharding using Discord's recommended shard count.
  • @harmonixjs/image-builder: Development..

About

A modern, type-safe Discord.js framework with decorators and advanced features.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages