X Tutup
Skip to content

UniquePixels/unicorn

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

14 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Unicorn

A type-safe Discord bot framework built on Discord.js and TypeScript, designed to run on Bun.

CodeQL SonarCloud OpenSSF Scorecard OpenSSF Best Practices Discord Built with Unicorn open communities: aligned


Unicorn gives you a structured system to build Discord bots for your communities using a Spark system for modular command and event handling, composable Guards for validation and gating, and type-safe configuration β€” so you can focus on building great communities, not plumbing. πŸ¦„

Features

  • Sparks β€” modular handlers for slash commands, components (buttons/selects/modals), gateway events, and cron-scheduled tasks
  • Guards β€” chainable validation with automatic TypeScript type narrowing. 15 built-in guards included
  • Type-safe config β€” Zod-validated configuration with secret resolution and typed Snowflake IDs
  • Component pattern matching β€” exact and parameterized matching for interactive components with automatic parameter extraction
  • Command scoping β€” control where commands appear: guild, DMs, user-installed, or everywhere
  • Structured logging β€” Pino-based logger with automatic redaction and optional Sentry integration
  • Health checks β€” liveness and readiness endpoints for container orchestration
  • Graceful shutdown β€” coordinated cleanup of cron jobs, health server, and the Discord client
  • Lagniappe β€” a growing collection of drop-in sparks, guards, and utilities

Quick Start

Prerequisites

Setup

bun install

Update src/config.ts with your bot's application ID and desired intents:

export const appConfig = {
  discord: {
    appID: 'your-application-id',
    apiToken: 'secret://apiKey',
    intents: [GatewayIntentBits.Guilds],
    // ...
  },
} satisfies UnicornConfig;

Add your bot token to .env β€” Bun loads it automatically, no dotenv needed:

apiKey=your-bot-token
bun start

Sparks

Sparks are the building blocks of your bot. Each spark is a self-contained module that defines its trigger, optional guards, and action handler.

Commands

import { SlashCommandBuilder } from 'discord.js';
import { defineCommand } from '@/core/sparks';

export const ping = defineCommand({
  command: new SlashCommandBuilder()
    .setName('ping')
    .setDescription('Check bot latency'),
  action: async (interaction) => {
    await interaction.reply(`Pong! ${interaction.client.ws.ping}ms`);
  },
});

Unicorn also supports autocomplete, subcommand groups, and context menu commands.

Components

Handle buttons, select menus, and modals with pattern-matched IDs:

import { defineComponent } from '@/core/sparks';

export const confirmButton = defineComponent({
  id: 'confirm-action',       // exact match (O(1) lookup)
  action: async (interaction) => {
    await interaction.reply('Confirmed!');
  },
});

Supports exact and parameterized matching with automatic parameter extraction. See Components.

Gateway Events

import { Events } from 'discord.js';
import { defineGatewayEvent } from '@/core/sparks';

export const memberJoin = defineGatewayEvent({
  event: Events.GuildMemberAdd,
  action: async (member, client) => {
    client.logger.info({ userId: member.id }, 'New member joined');
  },
});

Supports once mode, guards, and more. See Gateway Events.

Scheduled Events

import { defineScheduledEvent } from '@/core/sparks';

export const dailyCleanup = defineScheduledEvent({
  id: 'daily-cleanup',
  schedule: '0 0 * * *',       // midnight UTC
  timezone: 'America/New_York', // optional
  action: async (ctx) => {
    ctx.client.logger.info('Running daily cleanup');
  },
});

Supports multiple schedules, timezones, and guards. See Scheduled Events.

Guards

Guards are composable validators that run before a spark's action. They chain sequentially with type narrowing β€” if a guard ensures a guild context, every subsequent guard and the action receive guild-typed interactions.

import { PermissionFlagsBits, SlashCommandBuilder } from 'discord.js';
import { defineCommand } from '@/core/sparks';
import { inCachedGuild, hasPermission } from '@/guards/built-in';

export const kick = defineCommand({
  command: new SlashCommandBuilder()
    .setName('kick')
    .setDescription('Kick a member'),
  guards: [inCachedGuild, hasPermission(PermissionFlagsBits.KickMembers)],
  action: async (interaction) => {
    // interaction is typed with guild guaranteed
  },
});

17 built-in guards ship with Unicorn. You can also create your own. See Guards for the full reference.

Configuration

Type-safe configuration with Zod schemas, automatic secret resolution from environment variables, and typed Snowflake IDs:

import type { UnicornConfig } from '@/core/configuration';

export default {
  apiKey: 'secret://BOT_TOKEN',
  ids: {
    guild: { main: '123456789' },
    role:  { admin: '987654321' },
  },
} satisfies UnicornConfig;

See Configuration for the full schema, secret handling, environment mapping, and health check setup.

Documentation

  • Commands β€” slash commands, autocomplete, subcommand groups, context menus
  • Components β€” interactive components (buttons, select menus, modals) with exact and parameterized matching
  • Guards β€” built-in guards, custom guards, composition, type narrowing
  • Gateway Events β€” event listeners, once vs recurring
  • Scheduled Events β€” cron tasks, timezones, lifecycle
  • Configuration β€” config schema, secrets, environment mapping, health checks
  • Errors β€” AppError, error handling strategy, best practices
  • Logger β€” structured logging, redaction, Sentry integration
  • Emoji β€” application emoji resolver

Support

Contributing

See CONTRIBUTING.md for development setup, code style, and pull request guidelines.

License

MIT


About

Unicorn gives you a structured system to build Discord bots for your communities using a "Spark" system for modular command and event handling, composable "Guards" for validation and gating, and type-safe configuration β€” so you can focus on building great communities, not plumbing. πŸ¦„

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

Contributors

X Tutup