@discordx/utilities
Version:
Utilities package for enhancing discordx functionality
506 lines (491 loc) • 15.1 kB
JavaScript
;
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
});