npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

hat653

v0.2.0

Published

A unique JavaScript library for Discord bots with modern features and extensibility.

Readme

Event System

hat653 provides a typed event system for Discord and custom events.

Usage Example

import { EventEmitter } from 'hat653';

const events = new EventEmitter();

// Listen for a user update
events.on('userUpdate', (oldUser, newUser) => {
    console.log(`User updated: ${oldUser.username} → ${newUser.username}`);
});

// Emit a user update event
events.emit('userUpdate', oldUser, newUser);

// Listen for a message create event
events.on('messageCreate', (msg) => {
    console.log('New message:', msg.content);
});

// Listen for a custom event
events.on('customEvent', (data) => {
    console.log('Custom event:', data);
});

// One-time listener
events.once('messageDelete', (msg) => {
    console.log('Message deleted:', msg.id);
});

// Remove a listener
const handler = (msg) => console.log(msg.content);
events.on('messageCreate', handler);
events.off('messageCreate', handler);

API Reference

  • .on(event, listener) — Register a listener for a typed or custom event
  • .emit(event, ...args) — Emit a typed or custom event
  • .off(event, listener) — Remove a listener
  • .once(event, listener) — Register a one-time listener

hat653 Discord Bot Utility Library

A modern, extensible JavaScript/TypeScript library for building Discord bots with unique features.

Mention Formatting

import { mention } from 'hat653/dist/utils';
mention('user', '123456789012345678'); // <@123456789012345678>
mention('role', '987654321098765432'); // <@&987654321098765432>
mention('channel', '112233445566778899'); // <#112233445566778899>

Discord Timestamp Formatting

import { discordTimestamp } from 'hat653/dist/utils';
discordTimestamp(new Date(), 'R'); // <t:1693449600:R>
discordTimestamp(Date.now(), 'f'); // <t:1693449600:f>

Markdown Helpers

import { bold, italic, underline, strikethrough, code, codeblock } from 'hat653/dist/utils';
bold('Important'); // **Important**
italic('Emphasis'); // *Emphasis*
underline('Underline'); // __Underline__
strikethrough('Removed'); // ~~Removed~~
code('inline'); // `inline`
codeblock('console.log("Hello")', 'js'); // ```js\nconsole.log("Hello")\n```
import { paginate } from 'hat653/dist/utils';
const items = Array.from({ length: 25 }, (_, i) => `Item ${i+1}`);
const { page, totalPages, pageNumber } = paginate(items, 2, 10);
// page = ['Item 11', ..., 'Item 20']
// totalPages = 3
// pageNumber = 2

Installation

npm install hat653

Usage

Import the library in your project:

import { Mat653653Bot, DiscordApiHelper, CommandManager, Logger } from 'hat653';

Example

See the examples/ directory for sample Discord bot code using this library.

Features

  • Dynamic command loading
  • Advanced permission system
  • Rate limiting
  • Context-aware responses
  • Plugin system
  • Built-in logging
  • Scheduler
  • Interactive prompts
  • Localization

Plugin System (Example)

API Reference (will update these later)

Customization Features

Configurable Bot Settings

const bot = new Mat653653Bot(token, {
    locale: 'es',
    loggingLevel: 'info',
    features: { moderation: true }
});

Event Hooks

bot.setOnMessage(msg => Logger.info('Received message:', msg));
bot.setOnCommand((cmd, args) => Logger.info(`Command: ${cmd}`, args));
bot.setOnError(err => Logger.error('Bot error:', err));

Command Permissions

commands.setPermissions('ban', ['admin', 'mod'], ['123456789']);
if (commands.canExecute('ban', { id: '123456789', roles: ['admin'] })) {
    commands.execute('ban', 'targetUserId');
}

Custom Message Validation

builder.addValidator(data => {
    if (!data.content) return 'Content is required.';
    return null;
});
builder.validate();

Plugin Config Storage

pluginManager.saveConfig('logger', { level: 'debug' });
const config = pluginManager.loadConfig('logger');

Scheduler Persistence

// Recurring tasks persist in advTasks.json
scheduleRecurringTask('cleanup', 3600000, () => Logger.info('Cleanup'), 2, 'maintenance');

Localization

import { localize } from 'hat653';
bot.sendMessage(channelId, localize('welcome', bot.config.locale));

Advanced Logging

Logger.logLevel = 'info';
Logger.logToFile = true;
Logger.logFile = 'bot.log';
Logger.format = (level, ...args) => `${new Date().toISOString()} [${level}] ${args.join(' ')}`;
Logger.info('Bot started');

Error Handling & Auto-Fix Examples

MessageBuilder

import { MessageBuilder } from 'hat653';

const builder = new MessageBuilder();
### Moderation Utilities (Basic)
if (!builder.validate()) {
    console.log('Errors:', builder.getErrors());
    builder.autoFix(); // Attempts to fix errors automatically
}

Moderation

import { warnUser } from 'hat653';

try {
    await warnUser(token, guildId, userId, 'Reason');
} catch (err) {
    if (err.code === 'MISSING_PERMISSIONS') {
        console.error(err.message);
        // Suggestion: err.fix
    }
}

Plugin System

import { PluginManager } from 'hat653';
const manager = new PluginManager();
try {
    manager.register({ name: 'logger', init: () => {} });
    manager.register({ name: 'logger', init: () => {} }); // Will throw PLUGIN_EXISTS
} catch (err) {
    if (err.code === 'PLUGIN_EXISTS') {
        console.error(err.message);
        // Suggestion: err.fix
    }
}

MessageBuilder (Advanced)

MessageBuilder lets you build Discord messages and embeds with a chainable API, validation, and auto-fix.

Features:

  • Chainable methods for all embed properties
  • Add multiple embeds, fields, images, thumbnails, authors, footers, timestamps
  • Add buttons, selects, modals, and components
  • Validation and auto-fix for Discord message structure
  • Preview and error reporting

Example:

import { MessageBuilder } from 'hat653';

const builder = new MessageBuilder()
    .setContent('Hello!')
    .addEmbed({ title: 'Embed 1', description: 'First embed', color: 0x00ff00 })
    .addEmbed({ title: 'Embed 2', description: 'Second embed', color: 0xff0000 })
    .setImage('https://example.com/image.png')
    .setThumbnail('https://example.com/thumb.png')
    .setUrl('https://example.com')
    .setAuthor('Bot', 'https://example.com/icon.png')
    .setFooter('Footer text', 'https://example.com/icon.png')
    .setTimestamp()
    .addField('Field 1', 'Value 1')
    .addField('Field 2', 'Value 2', true)
    .setButtons([
        {
            type: 1,
            components: [
                { type: 2, label: 'Click Me', style: 1, custom_id: 'btn1' }
            ]
        }
    ])
    .validate();

if (!builder.validate()) {
    console.log('Errors:', builder.getErrors());
    builder.autoFix();
}

console.log(builder.preview());
// Send with Discord.js: channel.send(builder.build());

API Reference:

  • .setContent(content: string)
  • .addEmbed(embed: object)
  • .setEmbed(embed: object)
  • .setImage(url: string)
  • .setThumbnail(url: string)
  • .setUrl(url: string)
  • .setAuthor(name: string, iconUrl?: string, url?: string)
  • .setFooter(text: string, iconUrl?: string)
  • .setTimestamp(date?: Date)
  • .addField(name: string, value: string, inline?: boolean)
  • .setButtons(components: any[])
  • .setSelects(selects: any[])
  • .setModal(modal: any)
  • .setComponents(components: any[])
  • .addValidator(fn: (data) => string | null)
  • .validate()
  • .getErrors()
  • .autoFix()
  • .preview()
  • .build()

Moderation (Advanced)

import { warnUser, unbanUser, fetchAuditLogs, tempBanUser, tempMuteUser, addRole, removeRole } from 'hat653';

await warnUser(token, guildId, userId, 'Warning reason');
await unbanUser(token, guildId, userId);
const logs = await fetchAuditLogs(token, guildId, 22); // 22 = ban action type
await tempBanUser(token, guildId, userId, 60000, 'Temp ban for 1 min');
await tempMuteUser(token, guildId, userId, 60000); // mute for 1 min
await addRole(token, guildId, userId, roleId);
await removeRole(token, guildId, userId, roleId);

Plugin System (Advanced)

import { registerPlugin, removePlugin, getPlugins, triggerPluginEvent } from 'hat653';

registerPlugin({
    name: 'logger',
    config: { level: 'info' },
    dependencies: ['database'],
    filterEvents: (event) => event === 'message',
    onInit: () => console.log('Plugin initializing'),
    setup: () => console.log('Logger plugin loaded'),
    onReady: () => console.log('Plugin ready'),
    teardown: () => console.log('Logger plugin removed'),
    onShutdown: () => console.log('Plugin shutting down'),
    onEvent: (event, ...args) => {
        if (event === 'message') console.log('Message event:', ...args);
    }
});

triggerPluginEvent('message', { content: 'Hello!' });
removePlugin('logger');

Advanced Scheduler

import { scheduleRecurringTask, cancelRecurringTask, listAdvancedTasks } from 'hat653';

scheduleRecurringTask('heartbeat', 10000, () => {
    console.log('Heartbeat every 10 seconds');
}, 1, 'system');

console.log(listAdvancedTasks());
cancelRecurringTask('heartbeat');

MessageBuilder (Example)

import { MessageBuilder } from 'hat653';

const builder = new MessageBuilder()
    .setContent('Hello!')
    .setEmbed({ title: 'Embed Title', description: 'Embed body', color: 0x00ff00 })
    .addField('Field 1', 'Value 1')
    .setAuthor('Bot', 'https://example.com/icon.png')
    .setFooter('Footer text')
    .setTimestamp();

const messageData = builder.build();
// Use messageData with DiscordRestApi, Mat653653Bot, or discord.js

Moderation Utilities

import { kickUser, banUser, muteUser, purgeMessages } from 'hat653';

await kickUser(token, guildId, userId, 'Spamming');
await banUser(token, guildId, userId, 'Bad behavior');
await muteUser(token, guildId, userId, 10 * 60 * 1000); // mute for 10 minutes
await purgeMessages(token, channelId, ['msgId1', 'msgId2']);

Plugin System (Basic)

import { registerPlugin, removePlugin, getPlugins, triggerPluginEvent } from 'hat653';

registerPlugin({
    name: 'logger',
    setup: () => console.log('Logger plugin loaded'),
    teardown: () => console.log('Logger plugin removed'),
    onEvent: (event, ...args) => {
        if (event === 'message') console.log('Message event:', ...args);
    }
});

triggerPluginEvent('message', { content: 'Hello!' });
removePlugin('logger');

Scheduler / Task Runner

import { scheduleTask, cancelTask, listScheduledTasks } from 'hat653';

scheduleTask('reminder', 60000, () => {
    console.log('This runs after 1 minute');
});

console.log(listScheduledTasks());
cancelTask('reminder');

Slash Command Registration

Slash command registration should be handled directly with discord.js in your bot code. This library does not provide a deploy utility for slash commands.

keepBotAlive

keepBotAlive can accept either a callback function or a Discord.js client:

import { keepBotAlive } from 'hat653';
import { Client } from 'discord.js';

const client = new Client({ intents: [/* ... */] });

// Option 1: Pass a callback function
keepBotAlive(() => {
    // Custom heartbeat logic
    console.log('Bot is alive!');
});

// Option 2: Pass a Discord.js client directly
keepBotAlive(client);

hat653Bot

const bot = new Mat653653Bot('YOUR_BOT_TOKEN');
const user = await bot.getUser('USER_ID');
const guild = await bot.getGuild('GUILD_ID');
const channel = await bot.getChannel('CHANNEL_ID');
const messages = await bot.getMessages('CHANNEL_ID', 10);
const member = await bot.getMember('GUILD_ID', 'USER_ID');
const roles = await bot.getRoles('GUILD_ID');
const emojis = await bot.getEmojis('GUILD_ID');
const invites = await bot.getInvites('GUILD_ID');
const reactions = await bot.getReactions('CHANNEL_ID', 'MESSAGE_ID', '👍');

// Send a plain message
await bot.sendMessage('CHANNEL_ID', 'Hello world!');

// Send an embed
await bot.sendEmbed('CHANNEL_ID', {
    title: 'Embed Title',
    description: 'Embed description',
    color: 0x00ff00
});

// Send a message with buttons
await bot.sendButton('CHANNEL_ID', 'Click a button:', [
    {
        type: 1,
        components: [
            {
                type: 2,
                label: 'Button 1',
                style: 1,
                custom_id: 'btn1'
            }
        ]
    }
]);

DiscordApiHelper

DiscordApiHelper.getUserTag({ username: 'user', discriminator: '1234' });
DiscordApiHelper.isValidId('123456789012345678');
await DiscordApiHelper.fetchEmojis(token, guildId);
await DiscordApiHelper.fetchInvites(token, guildId);
await DiscordApiHelper.fetchReactions(token, channelId, messageId, '👍');

sendMessageToChannel

import { sendMessageToChannel } from 'hat653';
// Usage with discord.js Client instance:
await sendMessageToChannel(client, 'CHANNEL_ID', 'Hello from discord.js!');

CommandManager

const manager = new CommandManager();
manager.register({ name: 'ping', execute: () => Logger.info('Pong!') });
manager.execute('ping');

License

MIT