UNPKG

@discordx/utilities

Version:

Utilities package for enhancing discordx functionality

506 lines (491 loc) 15.1 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { Category: () => Category, Description: () => Description, EnumChoice: () => EnumChoice, IsGuildUser: () => IsGuildUser, NotBot: () => NotBot, PermissionGuard: () => PermissionGuard, RateLimit: () => RateLimit, TIME_UNIT: () => TIME_UNIT, TimeFormat: () => TimeFormat, TimedSet: () => TimedSet, dayjs: () => dayjs }); module.exports = __toCommonJS(index_exports); // src/guards/IsGuildUser/index.ts var import_discord = require("discord.js"); var import_discordx = require("discordx"); var IsGuildUser = (callback) => async (arg, client, next) => { let guild = null; let user = null; const argItem = arg instanceof Array ? arg[0] : arg; switch (true) { case argItem instanceof import_discord.CommandInteraction: guild = argItem.guild; user = argItem.user; break; case argItem instanceof import_discord.MessageReaction: guild = argItem.message.guild; user = argItem.message.author; break; case argItem instanceof import_discord.VoiceState: guild = argItem.guild; user = argItem.member?.user ?? null; break; case argItem instanceof import_discord.Message: guild = argItem.guild; user = argItem.author; break; case argItem instanceof import_discordx.SimpleCommandMessage: guild = argItem.message.guild; user = argItem.message.author; break; case (argItem instanceof import_discord.ButtonInteraction || argItem instanceof import_discord.ChannelSelectMenuInteraction || argItem instanceof import_discord.CommandInteraction || argItem instanceof import_discord.ContextMenuCommandInteraction || argItem instanceof import_discord.MentionableSelectMenuInteraction || argItem instanceof import_discord.ModalSubmitInteraction || argItem instanceof import_discord.RoleSelectMenuInteraction || argItem instanceof import_discord.StringSelectMenuInteraction || argItem instanceof import_discord.UserSelectMenuInteraction): user = argItem.member?.user ?? argItem.message?.author ?? null; guild = argItem.guild; break; } const isNext = await callback({ arg, client, guild, user }); if (isNext) { await next(); } }; // src/guards/NotBot/index.ts var NotBot = IsGuildUser(({ user }) => !user?.bot); // src/guards/PermissionGuard/index.ts var import_discord2 = require("discord.js"); var import_discordx2 = require("discordx"); function PermissionGuard(permissions, options) { async function replyOrFollowUp(interaction, replyOptions) { if (interaction.replied) { await interaction.followUp(replyOptions); return; } if (interaction.deferred) { await interaction.editReply(replyOptions); return; } await interaction.reply(replyOptions); return; } async function post(arg, perms) { const finalResponse = options ?? { content: `you need \`\`${perms.join( ", " )}\`\` permissions for this command` }; if (arg instanceof import_discordx2.SimpleCommandMessage) { await arg.message.reply(finalResponse); } else { await replyOrFollowUp(arg, finalResponse); } return; } return async function(arg, client, next) { let guild = null; let callee = null; if (arg instanceof import_discordx2.SimpleCommandMessage) { if (arg.message.inGuild()) { guild = arg.message.guild; callee = arg.message.member; } } else { guild = arg.guild; if (arg.member instanceof import_discord2.GuildMember) { callee = arg.member; } } if (!guild || !callee) { return next(); } const perms = typeof permissions === "function" ? await permissions(arg) : permissions; const isAllowed = callee.permissions.has(perms, true); if (isAllowed) { return next(); } return post(arg, perms); }; } // src/guards/Rate Limiter/logic/TimedSet.ts var TimedSet = class { /** * @param _timeOut - Timeout in milliseconds */ constructor(_timeOut) { this._timeOut = _timeOut; if (Number.isNaN(_timeOut)) { throw new Error("Please supply a number"); } this._map = /* @__PURE__ */ new Map(); } _map; get size() { return this._map.size; } /** * Get the raw underlying set backing this times array. * NOTE: this set is Immutable */ get rawSet() { return [...this._map.keys()]; } [Symbol.toStringTag] = "Set"; isEmpty() { return this._map.size === 0; } add(key) { const timer = new Timer(() => { this._map.delete(key); }, this._timeOut); this._map.set(key, timer); return this; } has(value) { return this._map.has(value); } delete(key) { if (!this._map.has(key)) { return false; } const timeoutFunction = this._map.get(key); if (timeoutFunction) { timeoutFunction.clearTimer(); } return this._map.delete(key); } refresh(key) { if (!this._map.has(key)) { return false; } const timeoutFunction = this._map.get(key); if (timeoutFunction) { timeoutFunction.clearTimer(); } this.add(key); return true; } clear() { for (const [, value] of this._map) { value.clearTimer(); } this._map = /* @__PURE__ */ new Map(); } [Symbol.iterator]() { return new Set(this._map.keys())[Symbol.iterator](); } entries() { return (/* @__PURE__ */ new Set([...this._map.keys()])).entries(); } forEach(callbackfn, thisArg) { this._map.forEach((value, key) => { callbackfn.call(thisArg ?? this, key, key, this); }); } keys() { return this._map.keys(); } values() { return this._map.keys(); } getTimeRemaining(key) { const item = this._map.get(key); if (!item) { return -1; } return item.timeLeft; } }; // src/guards/Rate Limiter/logic/TimeOutEntry.ts var TimeOutEntry = class { constructor(userId, guildId, _rateValue = 1) { this.userId = userId; this.guildId = guildId; this._rateValue = _rateValue; this._currentCallAmount++; } _currentCallAmount = 0; hasLimitReached() { return !(this._currentCallAmount <= this._rateValue); } incrementCallCount() { this._currentCallAmount++; } }; // src/guards/Rate Limiter/logic/Timer.ts var Timer = class { id; _whenWillExecute; constructor(callback, delay) { this._whenWillExecute = Date.now() + delay; this.id = setTimeout(callback, delay); } get timeLeft() { return this._whenWillExecute - Date.now(); } clearTimer() { clearTimeout(this.id); this._whenWillExecute = -1; } }; // src/guards/Rate Limiter/RateLimit.ts var import_discordx3 = require("discordx"); // src/useful/time-format.ts var import_dayjs = __toESM(require("dayjs")); var import_customParseFormat = __toESM(require("dayjs/plugin/customParseFormat.js")); var import_objectSupport = __toESM(require("dayjs/plugin/objectSupport.js")); var import_relativeTime = __toESM(require("dayjs/plugin/relativeTime.js")); import_dayjs.default.extend(import_relativeTime.default); import_dayjs.default.extend(import_customParseFormat.default); import_dayjs.default.extend(import_objectSupport.default); var dayjs = import_dayjs.default; var TimeFormat = { /** * 12 Hour Clock: November 28, 2018 9:01 AM * * 24 Hour Clock: 28 November 2018 09:01 */ Default: (time) => `<t:${String(dayjs(time).unix())}>`, /** * 12 Hour Clock: November 28, 2018 * * 24 Hour Clock: 28 November 2018 */ LongDate: (time) => `<t:${String(dayjs(time).unix())}:D>`, /** * 12 Hour Clock: Wednesday, November 28, 2018 9:01 AM * * 24 Hour Clock: Wednesday, 28 November 2018 09:01 */ LongDateTime: (time) => `<t:${String(dayjs(time).unix())}:F>`, /** * 12 Hour Clock: 9:01:00 AM * * 24 Hour Clock: 09:01:00 */ LongTime: (time) => `<t:${String(dayjs(time, "").unix())}:T>`, /** * The Discord relative time updates every second. * * 12 Hour Clock: 3 years ago * * 24 Hour Clock: 3 years ago */ RelativeTime: (time) => `<t:${String(dayjs(time).unix())}:R>`, /** * 12 Hour Clock: 11/28/2018 * * 24 Hour Clock: 28/11/2018 */ ShortDate: (time) => `<t:${String(dayjs(time).unix())}:d>`, /** * 12 Hour Clock: November 28, 2018 9:01 AM * * 24 Hour Clock: 28 November 2018 09:01 */ ShortDateTime: (time) => `<t:${String(dayjs(time).unix())}:f>`, /** * 12 Hour Clock: 9:01 AM * * 24 Hour Clock: 09:01 */ ShortTime: (time) => `<t:${String(dayjs(time).unix())}:t>`, /** * Unlike Discord relative time which updates every second, this remain static. * * 12 Hour Clock: 3 years ago * * 24 Hour Clock: 3 years ago */ StaticRelativeTime: (time, withoutSuffix) => dayjs(time).fromNow(withoutSuffix) }; // src/guards/Rate Limiter/RateLimit.ts function RateLimit(timeout, value, options = { ephemeral: true, message: "message being rate limited!, please try again in {time}", rateValue: 1 }) { const rateValue = options.rateValue ?? 1; const rateMessage = options.message ?? "message being rate limited!, please try again in {time}"; function convertToMillisecond(timeValue, unit) { switch (unit) { case 3 /* seconds */: return timeValue * 1e3; case 2 /* minutes */: return timeValue * 6e4; case 1 /* hours */: return timeValue * 36e5; case 0 /* days */: return timeValue * 864e5; default: return 1e3; } } const _millisecond = convertToMillisecond(value, timeout); const _timer = new TimedSet(_millisecond); async function replyOrFollowUp(interaction, content, ephemeral) { if (interaction.replied) { await interaction.followUp({ content, ephemeral }); return; } if (interaction.deferred) { await interaction.editReply(content); return; } await interaction.reply({ content, ephemeral }); } function getFromArray(userId, guildId) { const arr = _timer.rawSet; return arr.find( (v) => v.userId === userId && v.guildId === guildId ); } function getTimeLeft(item) { return _timer.getTimeRemaining(item); } async function post(arg, msg) { if (arg instanceof import_discordx3.SimpleCommandMessage) { await arg.message.reply(msg); } else { await replyOrFollowUp(arg, msg, options.ephemeral ?? true); } } return async function(arg, client, next) { let memberId = null; let guildId = null; if (arg instanceof import_discordx3.SimpleCommandMessage) { memberId = arg.message.member?.id ?? null; guildId = arg.message.guildId; } else if (!arg.isAutocomplete()) { memberId = arg.member?.user.id ?? null; guildId = arg.guildId; } if (!memberId || !guildId) { return next(); } let fromArray = getFromArray(memberId, guildId); if (fromArray) { fromArray.incrementCallCount(); if (fromArray.hasLimitReached()) { const timeLeft = getTimeLeft(fromArray); let messageString = typeof rateMessage === "function" ? await rateMessage(arg, timeLeft) : rateMessage; const timeText = dayjs().add(timeLeft, "milliseconds").fromNow(true); ["{until}", "{time}"].forEach((text) => { messageString = messageString.replaceAll(text, timeText); }); return post(arg, messageString); } _timer.refresh(fromArray); } else { fromArray = new TimeOutEntry(memberId, guildId, rateValue); _timer.add(fromArray); } return next(); }; } // src/guards/Rate Limiter/types/enum.ts var TIME_UNIT = /* @__PURE__ */ ((TIME_UNIT2) => { TIME_UNIT2[TIME_UNIT2["days"] = 0] = "days"; TIME_UNIT2[TIME_UNIT2["hours"] = 1] = "hours"; TIME_UNIT2[TIME_UNIT2["minutes"] = 2] = "minutes"; TIME_UNIT2[TIME_UNIT2["seconds"] = 3] = "seconds"; return TIME_UNIT2; })(TIME_UNIT || {}); // src/decorators/category.ts var import_discordx4 = require("discordx"); function Category(category) { return function(target, key, descriptor) { import_discordx4.MetadataStorage.instance.addModifier( import_discordx4.Modifier.create( (original) => { if (original instanceof import_discordx4.DDiscord) { [ ...original.applicationCommands, ...original.simpleCommands ].forEach( (ob) => { ob.category = category; } ); } else { original.category = category; } }, import_discordx4.DApplicationCommand, import_discordx4.DSimpleCommand, import_discordx4.DDiscord ).decorateUnknown(target, key, descriptor) ); }; } // src/decorators/description.ts var import_discordx5 = require("discordx"); function Description(description) { return function(target, key, descriptor) { import_discordx5.MetadataStorage.instance.addModifier( import_discordx5.Modifier.create( (original) => { original.description = description; }, import_discordx5.DApplicationCommand, import_discordx5.DSimpleCommand ).decorateUnknown(target, key, descriptor) ); }; } // src/useful/enum.ts function EnumChoice(choices) { return Object.keys(choices).map((key) => ({ name: key, value: choices[key] })); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Category, Description, EnumChoice, IsGuildUser, NotBot, PermissionGuard, RateLimit, TIME_UNIT, TimeFormat, TimedSet, dayjs });