rashi-discord-bot-lib
Version:
🚀 Powerful Discord bot framework with built-in database, event handling, and utilities
170 lines • 7.02 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CooldownManager = void 0;
exports.isOwner = isOwner;
exports.isDev = isDev;
exports.checkContext = checkContext;
exports.checkPermsSlash = checkPermsSlash;
exports.checkPermsPrefix = checkPermsPrefix;
exports.enforceSlashGuards = enforceSlashGuards;
exports.enforcePrefixGuards = enforcePrefixGuards;
const discord_js_1 = require("discord.js");
class CooldownManager {
backend;
store = new Map();
constructor(backend) {
this.backend = backend;
}
key(userId, command) {
return `${userId}:${command}`;
}
async getRemaining(userId, command) {
const now = Date.now();
const key = this.key(userId, command);
if (!this.backend) {
const expires = this.store.get(key) ?? 0;
return expires <= now ? 0 : Math.ceil((expires - now) / 1000);
}
const raw = this.backend.instance.get(`cooldowns.${key}`);
if (!raw || raw <= now)
return 0;
return Math.ceil((raw - now) / 1000);
}
async set(userId, command, seconds) {
const key = this.key(userId, command);
const expiresAt = Date.now() + seconds * 1000;
if (!this.backend) {
this.store.set(key, expiresAt);
setTimeout(() => this.store.delete(key), seconds * 1000 + 1000);
return;
}
await this.backend.instance.set(`cooldowns.${key}`, expiresAt);
}
async checkAndSet(userId, command, seconds) {
const remaining = await this.getRemaining(userId, command);
if (remaining > 0)
return remaining;
await this.set(userId, command, seconds);
return 0;
}
async clear(userId, command) {
const key = this.key(userId, command);
if (!this.backend) {
this.store.delete(key);
return;
}
await this.backend.instance.delete(`cooldowns.${key}`);
}
}
exports.CooldownManager = CooldownManager;
/* ----------------------------- Owner / Dev check -------------------------- */
function isOwner(userId) {
return process.env.BOT_OWNER_ID?.trim() === userId;
}
function isDev(userId) {
return (process.env.DEVS?.split(',').map(s => s.trim()) ?? []).includes(userId);
}
/* ------------------------------- Context check ---------------------------- */
function checkContext(inGuild, options) {
if (options.guildOnly && !inGuild)
return { ok: false, message: 'This command can only be used in a server.' };
if (options.dmOnly && inGuild)
return { ok: false, message: 'This command can only be used in Direct Messages.' };
return { ok: true };
}
/* --------------------------- Permission utilities ------------------------- */
function hasAll(member, perms) {
if (!perms || perms.length === 0)
return { ok: true, missing: [] };
if (!member)
return { ok: false, missing: perms.map(String) };
const bits = new discord_js_1.PermissionsBitField(member.permissions);
const missing = perms.filter(p => !bits.has(p));
return { ok: missing.length === 0, missing: missing.map(String) };
}
function checkPermsSlash(interaction, options) {
const guild = interaction.guild ?? null;
const me = guild?.members.me ?? null;
const member = guild ? interaction.member : null;
const user = hasAll(member, options.permissions);
const bot = hasAll(me, options.permissions);
return { ok: user.ok && bot.ok, userMissing: user.missing, botMissing: bot.missing };
}
function checkPermsPrefix(message, options) {
const guild = message.guild ?? null;
const me = guild?.members.me ?? null;
const member = guild ? message.member : null;
const user = hasAll(member ?? null, options.permissions);
const bot = hasAll(me ?? null, options.permissions);
return { ok: user.ok && bot.ok, userMissing: user.missing, botMissing: bot.missing };
}
/* ------------------------------ Guard wrappers ---------------------------- */
async function enforceSlashGuards(interaction, commandName, options, cooldowns) {
if (options.ownerOnly && !isOwner(interaction.user.id)) {
await interaction.reply({ content: 'This command is for the bot owner only.', ephemeral: true });
return false;
}
if (options.devOnly && !isDev(interaction.user.id)) {
await interaction.reply({ content: 'This command is for developers only.', ephemeral: true });
return false;
}
const ctx = checkContext(!!interaction.guild, options);
if (!ctx.ok) {
await interaction.reply({ content: ctx.message, ephemeral: true });
return false;
}
const perms = checkPermsSlash(interaction, options);
if (!perms.ok) {
const parts = [];
if (perms.userMissing.length)
parts.push(`Missing **user** permissions: \`${perms.userMissing.join(', ')}\``);
if (perms.botMissing.length)
parts.push(`Missing **bot** permissions: \`${perms.botMissing.join(', ')}\``);
await interaction.reply({ content: parts.join('\n'), ephemeral: true });
return false;
}
if (options.cooldown && options.cooldown > 0) {
const remain = await cooldowns.getRemaining(interaction.user.id, commandName);
if (remain > 0) {
await interaction.reply({ content: `\u23F3 Please wait **${remain}s** before using this command again.`, ephemeral: true });
return false;
}
await cooldowns.set(interaction.user.id, commandName, options.cooldown);
}
return true;
}
async function enforcePrefixGuards(message, commandName, options, cooldowns) {
if (options.ownerOnly && !isOwner(message.author.id)) {
await message.reply('This command is for the bot owner only.');
return false;
}
if (options.devOnly && !isDev(message.author.id)) {
await message.reply('This command is for developers only.');
return false;
}
const ctx = checkContext(!!message.guild, options);
if (!ctx.ok) {
await message.reply(ctx.message);
return false;
}
const perms = checkPermsPrefix(message, options);
if (!perms.ok) {
const parts = [];
if (perms.userMissing.length)
parts.push(`Missing **user** permissions: \`${perms.userMissing.join(', ')}\``);
if (perms.botMissing.length)
parts.push(`Missing **bot** permissions: \`${perms.botMissing.join(', ')}\``);
await message.reply(parts.join('\n'));
return false;
}
if (options.cooldown && options.cooldown > 0) {
const remain = await cooldowns.getRemaining(message.author.id, commandName);
if (remain > 0) {
await message.reply(`\u23F3 Please wait **${remain}s** before using this command again.`);
return false;
}
await cooldowns.set(message.author.id, commandName, options.cooldown);
}
return true;
}
//# sourceMappingURL=commandGuards.js.map