Introduction overview
WingetCord is a modern Discord library built from the ground up with TypeScript-first design, offering a fluent API, smart caching, zero-config handlers, and powerful plugin/middleware systems.
Ultra-Fast REST
Uses undici for persistent connection pooling and per-route queuing.
Resilient Gateway
Automatic session resume and internal packet rate limiting.
Expressiveness
Modern, fluent API that reduces boilerplate code significantly.
Zero-Config Handlers
Automated command and event discovery with one line.
Plugin System
Reusable, independent plugins with full dependency management.
Scheduler
Cron-based and interval task scheduling built-in.
Audio Player
Multi-channel audio queue with advanced playback control.
Metrics & Logging
Professional logging with correlation IDs and real-time metrics.
Installation setup
Install WingetCord via npm or directly from GitHub.
Package Manager
# Install from npm
npm install @wingetcord/wingetcord
# Or install latest from GitHub
npm install github:wingetcord/WingetCord
Requires Node.js 18+ and TypeScript 5.0+. Enable experimentalDecorators and emitDecoratorMetadata in your tsconfig.json to use the decorator API.
tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"strict": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
Quick Start example
Get a bot running in under 10 lines.
import { Client, Intents } from '@wingetcord/wingetcord';
const client = new Client({
token: 'YOUR_BOT_TOKEN',
intents: ['GUILDS', 'GUILD_MESSAGES', 'MESSAGE_CONTENT']
});
client.onReady((user) => {
console.log(`🚀 Logged in as ${user.tag}`);
});
client.onMessage(async (msg) => {
if (msg.content === '!ping') {
await msg.reply('🏓 Pong!');
}
});
client.login();
Client class
The Client class is the main entry point. It manages REST, Gateway, caching, commands, events, interactions, plugins, and more.
import { Client, IntentBits } from '@wingetcord/wingetcord';
const client = new Client({
token: process.env.DISCORD_TOKEN,
intents: [
IntentBits.GUILDS,
IntentBits.GUILD_MESSAGES,
IntentBits.MESSAGE_CONTENT
]
});
Properties
| Property | Type | Description |
|---|---|---|
token | string | Bot authentication token |
rest | RESTManager | Handles all REST API requests |
gateway | GatewayManager | Manages WebSocket connections |
cache | CacheManager | In-memory caching system |
commands | CommandManager | Manages prefix commands |
events | EventManager | Manages event listeners |
plugins | PluginManager | Plugin system |
interactions | InteractionManager | Handles slash commands & components |
handler | HandlerManager | Automated resource discovery |
voice | VoiceManager | Voice channel management |
store | ReactiveStore | Reactive state management |
user | User | null | The current bot user |
Methods
login()
Logs the bot in and establishes a gateway connection.
await client.login();say(channelId, content)
High-level shortcut to send a message to a channel by ID.
await client.say('123456789', 'Hello, World!');
await client.say('123456789', { embeds: [embed], components: [] });pulse()
Returns an instant health snapshot of the bot runtime.
const health = client.pulse();
// Returns: { status, ping, uptime, memory, guilds }| Key | Type | Description |
|---|---|---|
status | string | "healthy" | "degraded" | "down" |
ping | number | Gateway latency in ms |
uptime | number | Process uptime in seconds |
memory | object | Heap and RSS memory usage |
guilds | number | Total connected guilds |
IntentBits enum
Bitfield flags to declare which events your bot will receive from the Discord Gateway.
Privileged Intents — GUILD_MEMBERS, GUILD_PRESENCES, and MESSAGE_CONTENT require explicit enabling in the Discord Developer Portal.
Commands & Events handlers
Register commands by extending the Command base class, or use decorators for a declarative style.
Command Class
import { Command, CommandContext } from '@wingetcord/wingetcord';
class PingCommand extends Command {
options = {
name: 'ping',
description: 'Responds with pong',
aliases: ['p'],
cooldown: 5000,
permissions: ['SendMessages']
};
async execute(ctx: CommandContext) {
await ctx.message.reply('🏓 Pong!');
}
}
client.commands.register(new PingCommand());| Option | Type | Required | Description |
|---|---|---|---|
name | string | required | Command trigger name |
description | string | optional | Command description |
aliases | string[] | optional | Alternative trigger names |
cooldown | number | optional | Cooldown in milliseconds |
permissions | string[] | optional | Required permissions |
Event Class
class ReadyEvent extends Event {
name = 'READY';
once = true;
execute() { console.log('Bot is ready!'); }
}
client.events.register(new ReadyEvent());HandlerManager
Automatically discover and load all commands, events, and interactions from directories.
await client.handler.setup({
commands: './src/commands',
events: './src/events',
interactions: './src/interactions'
});Fluent Listeners events
Shorthand helpers for the most common events directly on the client.
client.onMessage((msg) => { /* MESSAGE_CREATE */ });
client.onInteraction((i) => { /* INTERACTION_CREATE */ });
client.onReady((user) => { /* READY */ });Middleware advanced
Intercept and transform events with priority-based async middleware chains.
client.use(async (ctx, next) => {
const start = Date.now();
await next();
console.log(`[${ctx.event}] ${Date.now() - start}ms`);
});Structures classes
Message
| Property / Method | Type | Description |
|---|---|---|
id | Readonly<string> | Message snowflake ID |
channelId | Readonly<string> | Channel snowflake ID |
guildId | string | undefined | Guild ID (undefined in DMs) |
content | string | Message text content |
author | User | Message author |
timestamp | Date | Sent timestamp |
embeds | Embed[] | Array of embed objects |
attachments | Attachment[] | Attached files |
reply(content) | Promise<Message> | Reply to this message |
delete() | Promise<void> | Delete this message |
pin() | Promise<void> | Pin this message |
crosspost() | Promise<Message> | Crosspost to following channels |
User
| Property | Type | Description |
|---|---|---|
id | string | User snowflake ID |
username | string | Username |
discriminator | string | User discriminator |
globalName | string | null | Display name |
avatar | string | null | Avatar hash |
bot | boolean | Whether this user is a bot |
tag | string | "username#0000" |
displayAvatarURL | string | Full avatar CDN URL |
Guild
| Property | Type | Description |
|---|---|---|
id | string | Guild snowflake ID |
name | string | Guild name |
icon | string | null | Icon hash |
ownerId | string | Owner user ID |
roles | Collection | Map of Role objects |
emojis | Emoji[] | Array of emoji objects |
features | string[] | Enabled guild features |
Member
| Property | Type | Description |
|---|---|---|
user | User | User object |
nick | string | null | Server nickname |
roles | string[] | Array of role IDs |
joinedAt | Date | Join timestamp |
deaf | boolean | Server deafened |
mute | boolean | Server muted |
permissions | PermissionsBitField | Calculated permissions |
Collection utility
An extended Map with utility methods for common data operations.
const col = new Collection<string, User>();
col.find(u => u.bot); col.filter(u => u.bot);
col.map(u => u.tag); col.some(u => u.bot);
col.every(u => !u.bot); col.random(); col.first();PermissionsBitField utility
const perms = new PermissionsBitField('SendMessages');
perms.has('SendMessages'); // true
perms.add('ManageMessages');
perms.remove('SendMessages');
perms.toJSON();Builders components
EmbedBuilder
const embed = new EmbedBuilder()
.setTitle('Hello World')
.setDescription('This is an embed')
.setColor('#6366f1')
.addField('Field 1', 'Value 1', true)
.setTimestamp()
.setFooter('Footer text', 'https://example.com/icon.png');ButtonBuilder
const button = new ButtonBuilder()
.setCustomId('my-btn')
.setLabel('Click Me')
.setStyle(ButtonStyle.Primary)
.setEmoji({ name: '👋' })
.onAction(async (i) => { await i.reply('Clicked!'); });SelectMenuBuilder
const select = new SelectMenuBuilder()
.setCustomId('my-select')
.setPlaceholder('Select an option')
.addOptions(
{ label: 'Option 1', value: 'option1' },
{ label: 'Option 2', value: 'option2' }
)
.onAction(async (i) => { await i.reply(`Selected: ${i.values}`); });ModalBuilder
const modal = new ModalBuilder()
.setTitle('Feedback Form')
.setCustomId('feedback-modal')
.addComponents(
new TextInputBuilder()
.setLabel('Name').setCustomId('name')
.setStyle(TextInputStyle.Short).setRequired(true),
new TextInputBuilder()
.setLabel('Feedback').setCustomId('feedback')
.setStyle(TextInputStyle.Paragraph)
);
await interaction.showModal(modal);ActionRowBuilder
const row = new ActionRowBuilder().addComponents(button, select);
await channel.send({ content: 'Choose:', components: [row] });Enums & Constants enums
ButtonStyle
ComponentType
TextInputStyle
Advanced advanced
ReactiveStore
Proxy-based reactive state container. Subscribe to any property change with fine-grained listeners.
const store = new ReactiveStore({ count: 0 });
store.state.count = 5;
store.on('change', ({ property, oldValue, newValue }) => {
console.log(`${property}: ${oldValue} → ${newValue}`);
});
store.on('change:count', ({ newValue }) => console.log(newValue));Collector
Collect and filter interactions with built-in max/timeout limits.
const collector = client.interactions.createCollector({
filter: (i) => i.customId === 'verify',
max: 10, time: 60000
});
collector.on('collect', (i) => console.log(i.id));
collector.on('end', (collected, reason) => console.log(reason));Decorators
Class-based command and event handlers using TypeScript decorators.
@Command({ name: 'ban', description: 'Ban a user' })
@Permissions('BAN_MEMBERS')
@Cooldown(1000)
@Option('user', { description: 'User to ban', required: true })
export class BanCommand {
async execute(ctx: CommandContext) {
const user = ctx.getUser('user');
}
}
@Once('ready')
export class ReadyHandler {
execute() { console.log('Ready!'); }
}Caching
| Strategy | Description |
|---|---|
LRU | Least Recently Used — evicts least recently accessed entries |
LFU | Least Frequently Used — evicts entries accessed least often |
TTL | Time To Live — entries expire after a set duration |
Memory | Full in-memory caching, no automatic eviction |
Color Utility
Color.resolve('#FF5733'); // hex string
Color.resolve(0xFF5733); // hex number
Color.resolve([255, 87, 51]); // RGB array
Color.resolve('random'); // random color
Color.toHex(16737203); // → "#FF5733"
Color.toRGB(16737203); // → [255, 87, 51]Full Example reference
A complete bot with middleware, message commands, embeds, buttons, and slash command interactions.
import {
Client, IntentBits, EmbedBuilder,
ButtonBuilder, ButtonStyle, ActionRowBuilder
} from '@wingetcord/wingetcord';
const client = new Client({
token: process.env.DISCORD_TOKEN,
intents: [IntentBits.GUILDS, IntentBits.GUILD_MESSAGES, IntentBits.MESSAGE_CONTENT]
});
client.use(async (ctx, next) => {
console.log(`[${ctx.event}]`); await next();
});
client.onReady((user) => console.log(`🚀 ${user.tag}`));
client.onMessage(async (msg) => {
if (msg.content === '!help') {
const embed = new EmbedBuilder()
.setTitle('📖 Help')
.setDescription('Available: !ping, !stats, !help')
.setColor('#6366f1');
const btn = new ButtonBuilder()
.setLabel('Ping').setStyle(ButtonStyle.Primary)
.setCustomId('ping')
.onAction(async (i) => await i.reply('Pong!'));
await msg.reply({
embeds: [embed],
components: [new ActionRowBuilder().addComponents(btn)]
});
}
if (msg.content === '!ping')
await msg.reply(`🏓 Pong! (${client.gateway.ping}ms)`);
});
client.interactions.on('command', async (i) => {
if (i.commandName === 'stats') {
const h = client.pulse();
await i.reply({ embeds: [{
title: '📊 Stats',
fields: [
{ name: 'Ping', value: `${h.ping}ms`, inline: true },
{ name: 'Uptime', value: `${Math.floor(h.uptime)}s`, inline: true },
{ name: 'Guilds', value: `${h.guilds}`, inline: true }
]
}]});
}
});
client.login();Build & Run cli
npm install # Install dependencies
npm run build # Compile TypeScript
npm run dev # Run in development
npm run typecheck # Type checking only
npm run clean # Clean dist output