vimcord 1.0.29 → 1.0.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -30,6 +30,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ BUILTIN_ContextCommandHandler: () => BUILTIN_ContextCommandHandler,
34
+ BUILTIN_PrefixCommandHandler: () => BUILTIN_PrefixCommandHandler,
35
+ BUILTIN_SlashCommandHandler: () => BUILTIN_SlashCommandHandler,
33
36
  BaseCommandBuilder: () => BaseCommandBuilder,
34
37
  BaseCommandManager: () => BaseCommandManager,
35
38
  BetterCollector: () => BetterCollector,
@@ -68,7 +71,6 @@ __export(index_exports, {
68
71
  VimcordCLI: () => VimcordCLI,
69
72
  __zero: () => __zero,
70
73
  cleanMention: () => cleanMention,
71
- clientInstances: () => clientInstances,
72
74
  createClient: () => createClient,
73
75
  createMongoPlugin: () => createMongoPlugin,
74
76
  createMongoSchema: () => createMongoSchema,
@@ -87,9 +89,7 @@ __export(index_exports, {
87
89
  fetchMessage: () => fetchMessage,
88
90
  fetchRole: () => fetchRole,
89
91
  fetchUser: () => fetchUser,
90
- formatThousands: () => formatThousands,
91
92
  getCallerFileName: () => getCallerFileName,
92
- getClientInstances: () => getClientInstances,
93
93
  getFirstMentionId: () => getFirstMentionId,
94
94
  getMessageMention: () => getMessageMention,
95
95
  getProcessDir: () => getProcessDir,
@@ -99,7 +99,6 @@ __export(index_exports, {
99
99
  isMentionOrSnowflake: () => isMentionOrSnowflake,
100
100
  logger: () => logger,
101
101
  prompt: () => prompt,
102
- retryExponentialBackoff: () => retryExponentialBackoff,
103
102
  sendCommandErrorEmbed: () => sendCommandErrorEmbed,
104
103
  useClient: () => useClient,
105
104
  useReadyClient: () => useReadyClient,
@@ -528,6 +527,10 @@ var ContextCommandBuilder = class extends BaseCommandBuilder {
528
527
  // src/utils/dir.ts
529
528
  var import_node_path = __toESM(require("path"));
530
529
  var import_qznt = require("qznt");
530
+ function getCallerFileName() {
531
+ const stack = new Error().stack?.split("\n");
532
+ return stack?.at(4)?.split("at file")?.at(1)?.split("/").at(-1)?.split(":").at(0)?.split(".").at(0);
533
+ }
531
534
  function getProcessDir() {
532
535
  const mainPath = process.argv[1];
533
536
  if (!mainPath) return "";
@@ -537,9 +540,7 @@ async function importModulesFromDir(dir, suffix) {
537
540
  const cwd = getProcessDir();
538
541
  const MODULE_RELATIVE_PATH = import_node_path.default.join(cwd, dir);
539
542
  const MODULE_LOG_PATH = dir;
540
- const files = import_qznt.$.fs.readDir(MODULE_RELATIVE_PATH).filter(
541
- (fn) => fn.endsWith(`${suffix ? `.${suffix}` : ""}.js`) || fn.endsWith(`${suffix ? `.${suffix}` : ""}.ts`)
542
- );
543
+ const files = import_qznt.$.fs.readDir(MODULE_RELATIVE_PATH).filter((fn) => fn.endsWith(`${suffix ? `.${suffix}` : ""}.js`) || fn.endsWith(`${suffix ? `.${suffix}` : ""}.ts`));
543
544
  if (!files.length) {
544
545
  return [];
545
546
  }
@@ -564,10 +565,6 @@ async function importModulesFromDir(dir, suffix) {
564
565
  }
565
566
  return filteredModules;
566
567
  }
567
- function getCallerFileName() {
568
- const stack = new Error().stack?.split("\n");
569
- return stack?.at(4)?.split("at file")?.at(1)?.split("/").at(-1)?.split(":").at(0)?.split(".").at(0);
570
- }
571
568
 
572
569
  // src/builders/event.builder.ts
573
570
  var import_node_crypto2 = require("crypto");
@@ -923,7 +920,7 @@ var SlashCommandBuilder = class extends BaseCommandBuilder {
923
920
  };
924
921
 
925
922
  // src/client.ts
926
- var import_discord10 = require("discord.js");
923
+ var import_discord11 = require("discord.js");
927
924
  var import_dotenv = __toESM(require("dotenv"));
928
925
 
929
926
  // src/configs/tools.config.ts
@@ -1044,1280 +1041,1551 @@ function createVimcordContextCommandConfig(options = {}) {
1044
1041
  return import_lodash10.default.merge(defaultConfig5, options);
1045
1042
  }
1046
1043
 
1047
- // src/tools/Logger.ts
1048
- var import_chalk = __toESM(require("chalk"));
1049
- var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
1050
- LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
1051
- LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
1052
- LogLevel2[LogLevel2["SUCCESS"] = 2] = "SUCCESS";
1053
- LogLevel2[LogLevel2["WARN"] = 3] = "WARN";
1054
- LogLevel2[LogLevel2["ERROR"] = 4] = "ERROR";
1055
- return LogLevel2;
1056
- })(LogLevel || {});
1057
- var LOGGER_COLORS = {
1058
- primary: "#5865F2",
1059
- success: "#57F287",
1060
- warn: "#FEE75C",
1061
- danger: "#ED4245",
1062
- muted: "#747F8D",
1063
- text: "#FFFFFF"
1064
- };
1065
- var Logger = class {
1066
- logPrefixEmoji;
1067
- logPrefix;
1068
- minLevel;
1069
- showTimestamp;
1070
- colorScheme;
1071
- constructor(options) {
1072
- const { prefixEmoji = null, prefix = null, minLevel = 0 /* DEBUG */, showTimestamp = true } = options || {};
1073
- this.logPrefixEmoji = prefixEmoji;
1074
- this.logPrefix = prefix;
1075
- this.minLevel = minLevel;
1076
- this.showTimestamp = showTimestamp;
1077
- this.colorScheme = {
1078
- ...LOGGER_COLORS,
1079
- ...options?.colors
1080
- };
1081
- }
1082
- formatTimestamp() {
1083
- if (!this.showTimestamp) return "";
1084
- const now = /* @__PURE__ */ new Date();
1085
- const time = now.toLocaleTimeString("en-US", {
1086
- hour12: false,
1087
- hour: "2-digit",
1088
- minute: "2-digit",
1089
- second: "2-digit"
1090
- });
1091
- return import_chalk.default.hex(this.colorScheme.muted)(`[${time}]`);
1092
- }
1093
- formatPrefix() {
1094
- if (!this.logPrefix) return "";
1095
- return import_chalk.default.bold.hex(this.colorScheme.primary)(
1096
- `${this.logPrefixEmoji ? `${this.logPrefixEmoji} ` : ""}${this.logPrefix}`
1097
- );
1044
+ // src/utils/sendCommandErrorEmbed.ts
1045
+ var import_discord6 = require("discord.js");
1046
+
1047
+ // src/tools/BetterEmbed.ts
1048
+ var import_discord5 = require("discord.js");
1049
+
1050
+ // src/tools/dynaSend.ts
1051
+ var import_discord4 = require("discord.js");
1052
+
1053
+ // src/tools/types.ts
1054
+ var SendMethod = /* @__PURE__ */ ((SendMethod2) => {
1055
+ SendMethod2[SendMethod2["Reply"] = 0] = "Reply";
1056
+ SendMethod2[SendMethod2["EditReply"] = 1] = "EditReply";
1057
+ SendMethod2[SendMethod2["FollowUp"] = 2] = "FollowUp";
1058
+ SendMethod2[SendMethod2["Channel"] = 3] = "Channel";
1059
+ SendMethod2[SendMethod2["MessageReply"] = 4] = "MessageReply";
1060
+ SendMethod2[SendMethod2["MessageEdit"] = 5] = "MessageEdit";
1061
+ SendMethod2[SendMethod2["User"] = 6] = "User";
1062
+ return SendMethod2;
1063
+ })(SendMethod || {});
1064
+
1065
+ // src/tools/dynaSend.ts
1066
+ var DynaSend = class {
1067
+ static forceArray(value) {
1068
+ return Array.isArray(value) ? value : [value];
1098
1069
  }
1099
- shouldLog(level) {
1100
- return level >= this.minLevel;
1070
+ static isInteractionCallback(obj) {
1071
+ return obj instanceof import_discord4.InteractionCallbackResponse;
1101
1072
  }
1102
- get prefixEmoji() {
1103
- return this.logPrefixEmoji;
1073
+ static filterFlags(flags, excludeFlags) {
1074
+ if (!flags) return void 0;
1075
+ const flagArray = this.forceArray(flags);
1076
+ return flagArray.filter((flag) => !excludeFlags.includes(flag));
1104
1077
  }
1105
- get prefix() {
1106
- return this.logPrefix;
1078
+ static detectSendMethod(handler) {
1079
+ if (handler instanceof import_discord4.BaseInteraction) {
1080
+ return handler.replied || handler.deferred ? 1 /* EditReply */ : 0 /* Reply */;
1081
+ }
1082
+ if (handler instanceof import_discord4.BaseChannel) return 3 /* Channel */;
1083
+ if (handler instanceof import_discord4.Message) return 4 /* MessageReply */;
1084
+ if (handler instanceof import_discord4.GuildMember || handler instanceof import_discord4.User) return 6 /* User */;
1085
+ throw new Error("[DynaSend] Unable to determine send method for handler type");
1107
1086
  }
1108
- get colors() {
1109
- return this.colorScheme;
1087
+ static validateSendMethod(handler, method) {
1088
+ const interactionMethods = [0 /* Reply */, 1 /* EditReply */, 2 /* FollowUp */];
1089
+ if (interactionMethods.includes(method) && !(handler instanceof import_discord4.BaseInteraction)) {
1090
+ throw new TypeError(`[DynaSend] SendMethod '${SendMethod[method]}' requires BaseInteraction handler`);
1091
+ }
1092
+ if (method === 3 /* Channel */ && !(handler instanceof import_discord4.BaseChannel)) {
1093
+ throw new TypeError(`[DynaSend] SendMethod '${SendMethod[method]}' requires BaseChannel handler`);
1094
+ }
1095
+ if ([4 /* MessageReply */, 5 /* MessageEdit */].includes(method) && !(handler instanceof import_discord4.Message)) {
1096
+ throw new TypeError(`[DynaSend] SendMethod '${SendMethod[method]}' requires Message handler`);
1097
+ }
1098
+ if (method === 6 /* User */ && !(handler instanceof import_discord4.GuildMember || handler instanceof import_discord4.User)) {
1099
+ throw new TypeError(`[DynaSend] SendMethod '${SendMethod[method]}' requires User or GuildMember handler`);
1100
+ }
1110
1101
  }
1111
- extend(extras) {
1112
- for (const [key, fn] of Object.entries(extras)) {
1113
- if (typeof fn === "function") {
1114
- this[key] = function(...args) {
1115
- return fn.call(this, ...args);
1102
+ static createMessageData(options, method) {
1103
+ const baseData = {
1104
+ content: options.content,
1105
+ embeds: options.embeds,
1106
+ components: options.components,
1107
+ files: options.files,
1108
+ allowedMentions: options.allowedMentions,
1109
+ tts: options.tts
1110
+ };
1111
+ switch (method) {
1112
+ case 0 /* Reply */:
1113
+ return {
1114
+ ...baseData,
1115
+ flags: options.flags,
1116
+ withResponse: options.withResponse,
1117
+ poll: options.poll
1116
1118
  };
1117
- }
1119
+ case 1 /* EditReply */:
1120
+ return {
1121
+ ...baseData,
1122
+ flags: this.filterFlags(options.flags, ["Ephemeral", "SuppressNotifications"]),
1123
+ withResponse: options.withResponse,
1124
+ poll: options.poll
1125
+ };
1126
+ case 2 /* FollowUp */:
1127
+ return {
1128
+ ...baseData,
1129
+ flags: options.flags,
1130
+ withResponse: options.withResponse,
1131
+ poll: options.poll
1132
+ };
1133
+ case 3 /* Channel */:
1134
+ return {
1135
+ ...baseData,
1136
+ flags: this.filterFlags(options.flags, ["Ephemeral"]),
1137
+ poll: options.poll,
1138
+ stickers: options.stickers,
1139
+ reply: options.reply
1140
+ };
1141
+ case 4 /* MessageReply */:
1142
+ return {
1143
+ ...baseData,
1144
+ flags: this.filterFlags(options.flags, ["Ephemeral"]),
1145
+ poll: options.poll,
1146
+ stickers: options.stickers
1147
+ };
1148
+ case 5 /* MessageEdit */:
1149
+ return {
1150
+ ...baseData,
1151
+ flags: this.filterFlags(options.flags, ["Ephemeral", "SuppressNotifications"])
1152
+ };
1153
+ case 6 /* User */:
1154
+ return {
1155
+ ...baseData,
1156
+ flags: this.filterFlags(options.flags, ["Ephemeral"]),
1157
+ poll: options.poll,
1158
+ forward: options.forward,
1159
+ stickers: options.stickers
1160
+ };
1161
+ default:
1162
+ return baseData;
1118
1163
  }
1119
- return this;
1120
- }
1121
- setPrefix(prefix) {
1122
- this.logPrefix = prefix;
1123
- return this;
1124
- }
1125
- setPrefixEmoji(prefixEmoji) {
1126
- this.logPrefixEmoji = prefixEmoji;
1127
- return this;
1128
1164
  }
1129
- setMinLevel(minLevel) {
1130
- this.minLevel = minLevel;
1131
- return this;
1165
+ static async executeSend(handler, method, data) {
1166
+ try {
1167
+ switch (method) {
1168
+ case 0 /* Reply */: {
1169
+ const response = await handler.reply(data);
1170
+ return this.isInteractionCallback(response) ? response.resource?.message ?? null : null;
1171
+ }
1172
+ case 1 /* EditReply */:
1173
+ return await handler.editReply(data);
1174
+ case 2 /* FollowUp */:
1175
+ return await handler.followUp(data);
1176
+ case 3 /* Channel */:
1177
+ return await handler.send(data);
1178
+ case 4 /* MessageReply */:
1179
+ return await handler.reply(data);
1180
+ case 5 /* MessageEdit */: {
1181
+ const message = handler;
1182
+ if (!message.editable) {
1183
+ console.warn("[DynaSend] Message is not editable");
1184
+ return null;
1185
+ }
1186
+ return await message.edit(data);
1187
+ }
1188
+ case 6 /* User */:
1189
+ return await handler.send(data);
1190
+ default:
1191
+ throw new Error(`[DynaSend] Unknown send method '${method}'`);
1192
+ }
1193
+ } catch (error) {
1194
+ console.error(`[DynaSend] Error with method '${SendMethod[method]}':`, error);
1195
+ return null;
1196
+ }
1132
1197
  }
1133
- setShowTimestamp(show) {
1134
- this.showTimestamp = show;
1135
- return this;
1198
+ static scheduleDelete(message, delay) {
1199
+ if (delay < 1e3) {
1200
+ console.warn(`[DynaSend] Delete delay is less than 1 second (${delay}ms). Is this intentional?`);
1201
+ }
1202
+ setTimeout(async () => {
1203
+ try {
1204
+ if (message.deletable) {
1205
+ await message.delete();
1206
+ }
1207
+ } catch (error) {
1208
+ console.error("[DynaSend] Error deleting message:", error);
1209
+ }
1210
+ }, delay);
1136
1211
  }
1137
- setColors(colors) {
1138
- this.colorScheme = {
1139
- ...LOGGER_COLORS,
1140
- ...colors
1141
- };
1142
- return this;
1212
+ static async send(handler, options) {
1213
+ const sendMethod = options.sendMethod ?? this.detectSendMethod(handler);
1214
+ this.validateSendMethod(handler, sendMethod);
1215
+ const messageData = this.createMessageData(options, sendMethod);
1216
+ const message = await this.executeSend(handler, sendMethod, messageData);
1217
+ if (options.deleteAfter && message) {
1218
+ this.scheduleDelete(message, options.deleteAfter);
1219
+ }
1220
+ return message;
1143
1221
  }
1144
- log(message, ...args) {
1145
- console.log(this.formatTimestamp(), this.formatPrefix(), message, ...args);
1222
+ };
1223
+ async function dynaSend(handler, options) {
1224
+ return DynaSend.send(handler, options);
1225
+ }
1226
+
1227
+ // src/tools/BetterEmbed.ts
1228
+ var BetterEmbed = class _BetterEmbed {
1229
+ embed = new import_discord5.EmbedBuilder();
1230
+ data;
1231
+ config;
1232
+ /** A powerful wrapper for `EmbedBuilder` that introduces useful features
1233
+ *
1234
+ * Auto-shorthand context formatting (_ACF_) is enabled by default
1235
+ *
1236
+ * All functions utilize _ACF_ unless `BetterEmbed.acf` is set to `false`
1237
+ *
1238
+ * ___Use a blackslash___ `\` ___to escape any context___
1239
+ *
1240
+ * \- - - Author Context - - -
1241
+ * - __`$USER`__: _author's mention (@xsqu1znt)_
1242
+ * - __`$USER_NAME`__: _author's username_
1243
+ * - __`$DISPLAY_NAME`__: _author's display name (requires `GuildMember` context)_
1244
+ * - __`$USER_AVATAR`__: _author's avatar_
1245
+ *
1246
+ * \- - - Client Context - - -
1247
+ *
1248
+ * - __`$BOT_AVATAR`__: _bot's avatar_
1249
+ *
1250
+ * \- - - Shorthand Context - - -
1251
+ * - __`$YEAR`__: _YYYY_
1252
+ * - __`$MONTH`__: _MM_
1253
+ * - __`$DAY`__: _DD_
1254
+ * - __`$year`__: _YY_
1255
+ * - __`$month`__: _M or MM_
1256
+ * - __`$day`__: _D or DD_ */
1257
+ constructor(data = {}) {
1258
+ this.config = data.config || globalVimcordToolsConfig;
1259
+ this.data = {
1260
+ context: data.context || null,
1261
+ author: data.author || null,
1262
+ title: data.title || null,
1263
+ thumbnailUrl: data.thumbnailUrl || null,
1264
+ description: data.description || null,
1265
+ imageUrl: data.imageUrl || null,
1266
+ footer: data.footer || null,
1267
+ fields: data.fields || [],
1268
+ color: data.color ?? (this.config.devMode ? this.config.embedColorDev : this.config.embedColor),
1269
+ timestamp: data.timestamp || null,
1270
+ acf: data.acf ?? true
1271
+ };
1272
+ this.build();
1146
1273
  }
1147
- debug(message, ...args) {
1148
- if (!this.shouldLog(0 /* DEBUG */)) return;
1149
- console.log(
1150
- this.formatTimestamp(),
1151
- this.formatPrefix(),
1152
- import_chalk.default.hex(this.colorScheme.muted)("DEBUG"),
1153
- import_chalk.default.dim(message),
1154
- ...args
1155
- );
1274
+ build() {
1275
+ this.normalizeData();
1276
+ this.applyContextFormatting();
1277
+ this.configureEmbed();
1156
1278
  }
1157
- info(message, ...args) {
1158
- if (!this.shouldLog(1 /* INFO */)) return;
1159
- console.log(this.formatTimestamp(), this.formatPrefix(), import_chalk.default.hex("#87CEEB")("INFO"), message, ...args);
1279
+ normalizeData() {
1280
+ if (typeof this.data.author === "string") {
1281
+ this.data.author = { text: this.data.author };
1282
+ }
1283
+ if (typeof this.data.title === "string") {
1284
+ this.data.title = { text: this.data.title };
1285
+ }
1286
+ if (typeof this.data.footer === "string") {
1287
+ this.data.footer = { text: this.data.footer };
1288
+ }
1289
+ if (this.data.timestamp === true) {
1290
+ this.data.timestamp = Date.now();
1291
+ }
1160
1292
  }
1161
- success(message, ...args) {
1162
- if (!this.shouldLog(2 /* SUCCESS */)) return;
1163
- console.log(
1164
- this.formatTimestamp(),
1165
- this.formatPrefix(),
1166
- import_chalk.default.bold.hex(this.colorScheme.success)("\u2713 SUCCESS"),
1167
- import_chalk.default.hex(this.colorScheme.success)(message),
1168
- ...args
1169
- );
1293
+ getContextUser() {
1294
+ const context = this.data.context;
1295
+ if (!context) return null;
1296
+ return context.user || context.interaction?.member || context.interaction?.user || context.message?.member || context.message?.author || null;
1170
1297
  }
1171
- warn(message, ...args) {
1172
- if (!this.shouldLog(3 /* WARN */)) return;
1173
- console.warn(
1174
- this.formatTimestamp(),
1175
- this.formatPrefix(),
1176
- import_chalk.default.bold.hex(this.colorScheme.warn)("\u26A0 WARN"),
1177
- import_chalk.default.hex(this.colorScheme.warn)(message),
1178
- ...args
1179
- );
1298
+ getContextClient() {
1299
+ const context = this.data.context;
1300
+ if (!context) return null;
1301
+ return context.client || context.interaction?.client || context.message?.client || null;
1180
1302
  }
1181
- error(message, error, ...args) {
1182
- if (!this.shouldLog(4 /* ERROR */)) return;
1183
- console.error(
1184
- this.formatTimestamp(),
1185
- this.formatPrefix(),
1186
- import_chalk.default.bold.hex(this.colorScheme.danger)("\u2715 ERROR"),
1187
- import_chalk.default.hex(this.colorScheme.danger)(message),
1188
- ...args
1189
- );
1190
- if (error && error.stack) {
1191
- console.error(import_chalk.default.dim(error.stack));
1303
+ applyContextFormatting(str) {
1304
+ if (!this.data.acf) return;
1305
+ const user = this.getContextUser();
1306
+ const guildMember = user instanceof import_discord5.GuildMember ? user : null;
1307
+ const actualUser = guildMember?.user || (user instanceof import_discord5.User ? user : null);
1308
+ const client = this.getContextClient();
1309
+ const formatString = (str2) => {
1310
+ if (!str2 || !str2.includes("$")) return str2;
1311
+ return str2.replace(/(?<!\\)\$USER\b/g, actualUser?.toString() || "$USER").replace(/(?<!\\)\$USER_NAME\b/g, actualUser?.username || "$USER_NAME").replace(/(?<!\\)\$USER_AVATAR\b/g, actualUser?.avatarURL() || "$USER_AVATAR").replace(/(?<!\\)\$DISPLAY_NAME\b/g, guildMember?.displayName || "$DISPLAY_NAME").replace(/(?<!\\)\$BOT_AVATAR\b/g, client?.user?.avatarURL() || "$BOT_AVATAR").replace(/(?<!\\)\$INVIS\b/g, "\u200B").replace(/(?<!\\)\$YEAR/g, (/* @__PURE__ */ new Date()).getFullYear().toString()).replace(/(?<!\\)\$MONTH/g, String((/* @__PURE__ */ new Date()).getMonth() + 1).padStart(2, "0")).replace(/(?<!\\)\$DAY/g, String((/* @__PURE__ */ new Date()).getDate()).padStart(2, "0")).replace(/(?<!\\)\$year/g, String((/* @__PURE__ */ new Date()).getFullYear()).slice(-2)).replace(/(?<!\\)\$month/g, String((/* @__PURE__ */ new Date()).getMonth() + 1).padStart(2, "0")).replace(/(?<!\\)\$day/g, String((/* @__PURE__ */ new Date()).getDate()).padStart(2, "0")).replace(/(?<!\\|<)@([0-9]+)(?!>)/g, "<@$1>").replace(/(?<!\\|<)@&([0-9]+)(?!>)/g, "<@&$1>").replace(/(?<!\\|<)#([0-9]+)(?!>)/g, "<#$1>");
1312
+ };
1313
+ if (str) {
1314
+ return formatString(str);
1192
1315
  }
1193
- }
1194
- loader(message) {
1195
- const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
1196
- let i = 0;
1197
- const interval = setInterval(() => {
1198
- process.stdout.write(
1199
- `\r${this.formatTimestamp()} ${this.formatPrefix()} ${import_chalk.default.hex(this.colorScheme.warn)(frames[i])} ${message}`
1200
- );
1201
- i = (i + 1) % frames.length;
1202
- }, 100);
1203
- return (newMessage) => {
1204
- clearInterval(interval);
1205
- process.stdout.write(
1206
- `\r${this.formatTimestamp()} ${this.formatPrefix()} ${import_chalk.default.hex(this.colorScheme.success)("\u2713")} ${newMessage || message}
1207
- `
1316
+ if (this.data.author && typeof this.data.author === "object") {
1317
+ this.data.author.text = formatString(this.data.author.text);
1318
+ if (this.data.author.icon === true && actualUser) {
1319
+ this.data.author.icon = actualUser.avatarURL();
1320
+ } else if (typeof this.data.author.icon === "string") {
1321
+ this.data.author.icon = formatString(this.data.author.icon);
1322
+ }
1323
+ }
1324
+ if (this.data.title && typeof this.data.title === "object") {
1325
+ this.data.title.text = formatString(this.data.title.text);
1326
+ }
1327
+ if (this.data.description) {
1328
+ this.data.description = formatString(
1329
+ Array.isArray(this.data.description) ? this.data.description.filter((s) => s !== null && s !== void 0).join("\n") : this.data.description
1208
1330
  );
1209
- };
1210
- }
1211
- table(title, data) {
1212
- console.log(this.formatTimestamp(), this.formatPrefix(), import_chalk.default.bold(title));
1213
- Object.entries(data).forEach(([key, value]) => {
1214
- const formattedKey = import_chalk.default.hex(this.colorScheme.warn)(` ${key}`);
1215
- const formattedValue = import_chalk.default.hex(this.colorScheme.muted)(value);
1216
- console.log(`${formattedKey.padEnd(25)} ${formattedValue}`);
1217
- });
1218
- }
1219
- section(title) {
1220
- const line = "\u2500".repeat(Math.max(30, title.length + 4));
1221
- console.log(import_chalk.default.hex(this.colorScheme.muted)(`
1222
- \u250C\u2500${line}\u2500\u2510`));
1223
- console.log(
1224
- import_chalk.default.hex(this.colorScheme.muted)("\u2502 ") + import_chalk.default.bold.hex(this.colorScheme.text)(title.padEnd(line.length)) + import_chalk.default.hex(this.colorScheme.muted)(" \u2502")
1225
- );
1226
- console.log(import_chalk.default.hex(this.colorScheme.muted)(`\u2514\u2500${line}\u2500\u2518`));
1331
+ }
1332
+ if (this.data.footer && typeof this.data.footer === "object") {
1333
+ this.data.footer.text = formatString(this.data.footer.text);
1334
+ }
1335
+ if (this.data.thumbnailUrl) {
1336
+ this.data.thumbnailUrl = formatString(this.data.thumbnailUrl);
1337
+ }
1338
+ if (this.data.imageUrl) {
1339
+ this.data.imageUrl = formatString(this.data.imageUrl);
1340
+ }
1341
+ this.data.fields = this.data.fields.filter(Boolean).map((field) => ({
1342
+ ...field,
1343
+ name: formatString(field.name),
1344
+ value: formatString(field.value)
1345
+ }));
1227
1346
  }
1228
- };
1229
- var logger = new Logger();
1230
-
1231
- // src/tools/utils.ts
1232
- function __zero(str) {
1233
- return str?.length ? str : "0";
1234
- }
1235
- function isMentionOrSnowflake(str) {
1236
- return str ? str.match(/<@[#&]?[\d]{6,}>/) || str.match(/\d{6,}/) ? true : false : false;
1237
- }
1238
- function cleanMention(str) {
1239
- return str ? str.replaceAll(/[<@#&>]/g, "").trim() : void 0;
1240
- }
1241
- async function getMessageMention(message, content, type, index = 0, idOnly) {
1242
- const args = content?.split(" ");
1243
- const arg = isMentionOrSnowflake(args?.[index]) ? cleanMention(args?.[index]) : void 0;
1244
- switch (type) {
1245
- case "user":
1246
- const userMention2 = message.mentions.users.at(index) || null;
1247
- if (!userMention2 && arg) {
1248
- return idOnly ? arg : await fetchUser(message.client, arg);
1249
- } else {
1250
- return idOnly ? userMention2?.id || null : userMention2;
1347
+ configureEmbed() {
1348
+ if (this.data.author && typeof this.data.author === "object" && this.data.author.text) {
1349
+ try {
1350
+ this.embed.setAuthor({
1351
+ name: this.data.author.text,
1352
+ iconURL: typeof this.data.author.icon === "string" ? this.data.author.icon : void 0,
1353
+ url: this.data.author.hyperlink || void 0
1354
+ });
1355
+ } catch (error) {
1356
+ console.error("[BetterEmbed] Invalid author configuration:", error);
1251
1357
  }
1252
- case "member":
1253
- if (!message.guild) return null;
1254
- const member = await fetchMember(message.guild, message.mentions.users.at(index)?.id ?? arg);
1255
- return idOnly ? member?.id || null : member;
1256
- case "channel":
1257
- const channelMention = message.mentions.channels.at(index) || null;
1258
- if (!channelMention && arg) {
1259
- return idOnly ? arg : message.guild ? await fetchChannel(message.guild, arg) : message.client.channels.cache.get(__zero(arg)) ?? message.client.channels.fetch(__zero(arg));
1260
- } else {
1261
- return idOnly ? channelMention?.id || null : channelMention;
1358
+ }
1359
+ if (this.data.title && typeof this.data.title === "object" && this.data.title.text) {
1360
+ try {
1361
+ this.embed.setTitle(this.data.title.text);
1362
+ if (this.data.title.hyperlink) {
1363
+ this.embed.setURL(this.data.title.hyperlink);
1364
+ }
1365
+ } catch (error) {
1366
+ console.error("[BetterEmbed] Invalid title configuration:", error);
1262
1367
  }
1263
- case "role":
1264
- const roleMention = message.mentions.roles.at(index) || null;
1265
- if (!roleMention && arg) {
1266
- return idOnly ? arg : message.guild ? await fetchRole(message.guild, arg) : null;
1267
- } else {
1268
- return idOnly ? roleMention?.id || null : roleMention;
1368
+ }
1369
+ if (this.data.description) {
1370
+ this.embed.setDescription(
1371
+ Array.isArray(this.data.description) ? this.data.description.join("\n") : this.data.description
1372
+ );
1373
+ }
1374
+ if (this.data.thumbnailUrl) {
1375
+ try {
1376
+ this.embed.setThumbnail(this.data.thumbnailUrl);
1377
+ } catch (error) {
1378
+ console.error("[BetterEmbed] Invalid thumbnail URL:", error);
1269
1379
  }
1270
- default:
1271
- return null;
1272
- }
1273
- }
1274
- function getFirstMentionId(options) {
1275
- let mentionId = "";
1276
- if (options.message) {
1277
- switch (options.type) {
1278
- case "user":
1279
- mentionId = options.message.mentions.users.first()?.id || "";
1280
- break;
1281
- case "channel":
1282
- mentionId = options.message.mentions.channels.first()?.id || "";
1283
- break;
1284
- case "role":
1285
- mentionId = options.message.mentions.roles.first()?.id || "";
1286
- break;
1287
1380
  }
1288
- }
1289
- const firstArg = options.content?.split(" ")[0] || "";
1290
- return mentionId || isMentionOrSnowflake(firstArg) ? cleanMention(firstArg) : "";
1291
- }
1292
- async function fetchUser(client, userId) {
1293
- if (!userId) return null;
1294
- return client.users.cache.get(__zero(userId)) || await client.users.fetch(__zero(userId)).catch(() => null);
1295
- }
1296
- async function fetchGuild(client, guildId) {
1297
- if (!guildId) return null;
1298
- return client.guilds.cache.get(__zero(guildId)) || await client.guilds.fetch(__zero(guildId)).catch(() => null);
1299
- }
1300
- async function fetchMember(guild, memberId) {
1301
- if (!memberId) return null;
1302
- return guild.members.cache.get(__zero(memberId)) || await guild.members.fetch(__zero(memberId)).catch(() => null);
1303
- }
1304
- async function fetchChannel(guild, channelId, type) {
1305
- if (!channelId) return null;
1306
- const channel = guild.channels.cache.get(__zero(channelId)) || await guild.channels.fetch(__zero(channelId)).catch(() => null);
1307
- if (type && channel?.type !== type) return null;
1308
- return channel;
1309
- }
1310
- async function fetchRole(guild, roleId) {
1311
- if (!roleId) return null;
1312
- return guild.roles.cache.get(__zero(roleId)) || await guild.roles.fetch(__zero(roleId)).catch(() => null) || null;
1313
- }
1314
- async function fetchMessage(channel, messageId) {
1315
- if (!messageId) return null;
1316
- return channel.messages.cache.get(__zero(messageId)) || await channel.messages.fetch(__zero(messageId)).catch(() => null) || null;
1317
- }
1318
-
1319
- // src/types/status.ts
1320
- var import_discord4 = require("discord.js");
1321
- var import_lodash11 = __toESM(require("lodash"));
1322
- var StatusType = /* @__PURE__ */ ((StatusType2) => {
1323
- StatusType2["DND"] = "dnd";
1324
- StatusType2["Idle"] = "idle";
1325
- StatusType2["Online"] = "online";
1326
- StatusType2["Invisible"] = "invisible";
1327
- return StatusType2;
1328
- })(StatusType || {});
1329
- var defaultPresence = {
1330
- production: {
1331
- interval: 6e4,
1332
- randomize: false,
1333
- activity: [
1334
- { status: "online" /* Online */, type: import_discord4.ActivityType.Custom, name: "Need help? Use /help or !help" },
1335
- { status: "online" /* Online */, type: import_discord4.ActivityType.Custom, name: "Join our community!" },
1336
- { status: "online" /* Online */, type: import_discord4.ActivityType.Watching, name: "\u2728 $GUILD_COUNT servers" }
1337
- ]
1338
- },
1339
- development: {
1340
- activity: { status: "dnd" /* DND */, type: import_discord4.ActivityType.Custom, name: "In development!" }
1341
- }
1342
- };
1343
- function createVimcordStatusConfig(options = {}) {
1344
- return import_lodash11.default.merge(defaultPresence, options);
1345
- }
1346
-
1347
- // src/utils/number.ts
1348
- function formatThousands(num, sep = ",") {
1349
- return `${num}`.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, sep);
1350
- }
1351
-
1352
- // src/modules/status.manager.ts
1353
- var import_node_events = __toESM(require("events"));
1354
- var import_qznt2 = require("qznt");
1355
- var StatusManager = class {
1356
- client;
1357
- logger;
1358
- emitter = new import_node_events.default();
1359
- lastActivity = null;
1360
- lastActivityIndex = 0;
1361
- task = null;
1362
- constructor(client) {
1363
- this.client = client;
1364
- this.logger = new Logger({ prefixEmoji: "\u{1F4AC}", prefix: `StatusManager (i${this.client.clientId})` });
1365
- this.emitter.on("changed", (activity) => {
1366
- if (this.client.config.app.verbose) {
1367
- this.logger.debug(`Status changed to '${activity.name}'`);
1381
+ if (this.data.imageUrl) {
1382
+ try {
1383
+ this.embed.setImage(this.data.imageUrl);
1384
+ } catch (error) {
1385
+ console.error("[BetterEmbed] Invalid image URL:", error);
1368
1386
  }
1369
- });
1370
- this.emitter.on("cleared", () => {
1371
- if (this.client.config.app.verbose) {
1372
- this.logger.debug("Status cleared");
1387
+ }
1388
+ if (this.data.footer && typeof this.data.footer === "object" && this.data.footer.text) {
1389
+ try {
1390
+ this.embed.setFooter({
1391
+ text: this.data.footer.text,
1392
+ iconURL: typeof this.data.footer.icon === "string" ? this.data.footer.icon : void 0
1393
+ });
1394
+ } catch (error) {
1395
+ console.error("[BetterEmbed] Invalid footer configuration:", error);
1373
1396
  }
1374
- });
1397
+ }
1398
+ if (this.data.color) {
1399
+ try {
1400
+ const color = Array.isArray(this.data.color) ? this.data.color[Math.floor(Math.random() * this.data.color.length)] ?? null : this.data.color;
1401
+ this.embed.setColor(color);
1402
+ } catch (error) {
1403
+ console.error("[BetterEmbed] Invalid color:", error);
1404
+ }
1405
+ }
1406
+ if (this.data.timestamp && this.data.timestamp !== true) {
1407
+ try {
1408
+ this.embed.setTimestamp(this.data.timestamp);
1409
+ } catch (error) {
1410
+ console.error("[BetterEmbed] Invalid timestamp:", error);
1411
+ }
1412
+ }
1413
+ if (this.data.fields.length > 0) {
1414
+ const validFields = this.data.fields.slice(0, 25);
1415
+ if (this.data.fields.length > 25) {
1416
+ console.warn("[BetterEmbed] Only first 25 fields will be used (Discord limit)");
1417
+ }
1418
+ this.embed.setFields(validFields);
1419
+ }
1375
1420
  }
1376
- clearData() {
1377
- this.task?.stop();
1378
- this.task = null;
1379
- this.lastActivity = null;
1380
- this.lastActivityIndex = 0;
1421
+ setAuthor(author) {
1422
+ this.data.author = author;
1423
+ this.build();
1381
1424
  return this;
1382
1425
  }
1383
- async getReadyClient() {
1384
- const client = await this.client.whenReady();
1385
- if (!client.user) throw new Error("Cannot manage the client's activity when its user is not hydrated");
1386
- return client;
1426
+ setTitle(title) {
1427
+ this.data.title = title;
1428
+ this.build();
1429
+ return this;
1387
1430
  }
1388
- async formatActivityName(name) {
1389
- name = name.replace("$USER_COUNT", formatThousands(this.client.users.cache.size)).replace("$GUILD_COUNT", formatThousands(this.client.guilds.cache.size)).replace(
1390
- "$INVITE",
1391
- this.client.config.staff.guild.inviteUrl ? this.client.config.staff.guild.inviteUrl : "<STAFF_INVITE_URL_NOT_SET>"
1392
- );
1393
- if (name.includes("$STAFF_GUILD_MEMBER_COUNT")) {
1394
- await fetchGuild(this.client, this.client.config.staff.guild.id).then((guild) => {
1395
- if (!guild) return name = name.replace("$STAFF_GUILD_MEMBER_COUNT", "<STAFF_GUILD_NOT_FOUND>");
1396
- name = name.replace("$STAFF_GUILD_MEMBER_COUNT", formatThousands(guild.members.cache.size));
1397
- }).catch((err) => this.logger.error("Failed to fetch the staff guild", err));
1398
- }
1399
- return name;
1431
+ setDescription(description) {
1432
+ this.data.description = description;
1433
+ this.build();
1434
+ return this;
1400
1435
  }
1401
- async setActivity(activity) {
1402
- const client = await this.getReadyClient();
1403
- activity.name = await this.formatActivityName(activity.name);
1404
- client.user.setStatus(activity.status);
1405
- client.user.setActivity({ name: activity.name, type: activity.type, url: activity.streamUrl });
1406
- this.emitter.emit("changed", activity);
1436
+ setThumbnail(url) {
1437
+ this.data.thumbnailUrl = url;
1438
+ this.build();
1439
+ return this;
1407
1440
  }
1408
- async statusRotationTask(clientStatus) {
1409
- let activity;
1410
- if (clientStatus.randomize && Array.isArray(clientStatus.activity)) {
1411
- activity = import_qznt2.$.rnd.choice(clientStatus.activity, { not: this.lastActivity });
1412
- this.lastActivity = activity;
1413
- } else {
1414
- const activityIndex = (this.lastActivityIndex + 1) % clientStatus.activity.length;
1415
- this.lastActivityIndex = activityIndex;
1416
- activity = clientStatus.activity[activityIndex];
1417
- }
1418
- await this.setActivity(activity);
1419
- this.emitter.emit("rotation", activity);
1441
+ setImage(url) {
1442
+ this.data.imageUrl = url;
1443
+ this.build();
1444
+ return this;
1420
1445
  }
1421
- async scheduleStatusRotation(clientStatus) {
1422
- if (!clientStatus.interval) throw new Error("Cannot create client activity interval without interval time");
1423
- this.task?.stop();
1424
- this.task = null;
1425
- this.task = new import_qznt2.$.Loop(() => this.statusRotationTask(clientStatus), import_qznt2.$.math.ms(clientStatus.interval), true);
1426
- this.start();
1446
+ setFooter(footer) {
1447
+ this.data.footer = footer;
1448
+ this.build();
1449
+ return this;
1427
1450
  }
1428
- start() {
1429
- if (this.task) {
1430
- this.task.start();
1431
- this.emitter.emit("started", this.task);
1432
- }
1451
+ setColor(color) {
1452
+ this.data.color = color;
1453
+ this.build();
1454
+ return this;
1455
+ }
1456
+ setTimestamp(timestamp) {
1457
+ this.data.timestamp = timestamp;
1458
+ this.build();
1433
1459
  return this;
1434
1460
  }
1435
- pause() {
1436
- if (this.task) {
1437
- this.task.stop();
1438
- this.emitter.emit("paused", this.task);
1439
- }
1461
+ addFields(fields) {
1462
+ this.data.fields = [...this.data.fields, ...fields];
1463
+ this.build();
1440
1464
  return this;
1441
1465
  }
1442
- async set(status) {
1443
- const statusConfig = createVimcordStatusConfig(status);
1444
- let clientStatus;
1445
- if (this.client.config.app.devMode) {
1446
- clientStatus = statusConfig.development;
1447
- } else {
1448
- clientStatus = statusConfig.production;
1449
- }
1450
- if (!clientStatus.interval) {
1451
- await this.setActivity(Array.isArray(clientStatus.activity) ? clientStatus.activity[0] : clientStatus.activity);
1452
- } else {
1453
- await this.scheduleStatusRotation(clientStatus);
1454
- }
1466
+ setFields(fields) {
1467
+ this.data.fields = fields;
1468
+ this.build();
1455
1469
  return this;
1456
1470
  }
1457
- async destroy() {
1458
- if (this.task) {
1459
- this.task.stop();
1460
- this.task = null;
1461
- this.emitter.emit("destroyed");
1462
- await this.clear();
1463
- }
1471
+ spliceFields(index, deleteCount, ...fields) {
1472
+ this.data.fields.splice(index, deleteCount, ...fields);
1473
+ this.build();
1464
1474
  return this;
1465
1475
  }
1466
- async clear() {
1467
- const client = await this.getReadyClient();
1468
- this.clearData();
1469
- client.user.setActivity({ name: "" });
1470
- this.emitter.emit("cleared");
1471
- return this;
1476
+ clone(overrides = {}) {
1477
+ return new _BetterEmbed({ ...this.data, ...overrides });
1478
+ }
1479
+ toJSON() {
1480
+ return this.embed.toJSON();
1481
+ }
1482
+ async send(handler, options = {}, overrides) {
1483
+ this.build();
1484
+ if (options.content && this.data.acf) {
1485
+ options.content = this.applyContextFormatting(options.content);
1486
+ }
1487
+ return await dynaSend(handler, {
1488
+ ...options,
1489
+ embeds: [
1490
+ overrides ? this.clone(overrides) : this,
1491
+ ...Array.isArray(options?.embeds) ? options?.embeds : options?.embeds ? [options?.embeds] : []
1492
+ ]
1493
+ });
1472
1494
  }
1473
1495
  };
1474
1496
 
1475
- // src/modules/command.manager.ts
1476
- var import_discord5 = require("discord.js");
1477
- var BaseCommandManager = class {
1478
- type;
1479
- client;
1480
- commands = /* @__PURE__ */ new Map();
1481
- moduleSuffix;
1482
- constructor(client, type, moduleSuffix) {
1483
- this.type = type;
1484
- this.client = client;
1485
- this.moduleSuffix = moduleSuffix;
1486
- }
1487
- /**
1488
- * Gets a command by name.
1489
- */
1490
- get(name) {
1491
- if (this.type === 1 /* Prefix */) {
1492
- const config = this.client.config.prefixCommands;
1493
- const search = config.allowCaseInsensitiveCommandNames ? name.toLowerCase() : name;
1494
- return Array.from(this.commands.values()).find((cmd) => {
1495
- const commandName = "builder" in cmd ? cmd.builder.name : cmd.options.name;
1496
- const trigger = config.allowCaseInsensitiveCommandNames ? commandName.toLowerCase() : commandName;
1497
- if (trigger === search) return true;
1498
- if ("aliases" in cmd.options) {
1499
- return cmd.options.aliases?.some(
1500
- (a) => config.allowCaseInsensitiveCommandNames ? a.toLowerCase() === search : a === search
1501
- );
1502
- }
1503
- });
1504
- } else {
1505
- return this.commands.get(name);
1497
+ // src/utils/sendCommandErrorEmbed.ts
1498
+ async function sendCommandErrorEmbed(client, error, guild, messageOrInteraction) {
1499
+ if (!client.features.enableCommandErrorMessage) return null;
1500
+ const config = typeof client.features.enableCommandErrorMessage !== "boolean" ? client.features.enableCommandErrorMessage : void 0;
1501
+ const buttons = {
1502
+ supportServer: new import_discord6.ButtonBuilder({
1503
+ url: config?.inviteUrl || client.config.staff.guild.inviteUrl || "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
1504
+ // may or may not be a rickroll
1505
+ label: config?.inviteButtonLabel || "Support Support",
1506
+ style: import_discord6.ButtonStyle.Link
1507
+ }),
1508
+ details: new import_discord6.ButtonBuilder({
1509
+ customId: "btn_details",
1510
+ label: config?.detailButtonLabel || "Details",
1511
+ style: import_discord6.ButtonStyle.Secondary
1512
+ })
1513
+ };
1514
+ const actionRow = new import_discord6.ActionRowBuilder({
1515
+ components: config?.inviteUrl && guild?.id !== (config.inviteUrl || client.config.staff.guild.id) ? [buttons.supportServer, buttons.details] : [buttons.details]
1516
+ });
1517
+ const embed_error = config?.embed?.(new BetterEmbed(), error, guild) || new BetterEmbed({
1518
+ color: "Red",
1519
+ title: "Something went wrong",
1520
+ description: "If you keep encountering this error, please report it."
1521
+ });
1522
+ const msg = await embed_error.send(messageOrInteraction, {
1523
+ components: [actionRow],
1524
+ flags: config?.ephemeral ? "Ephemeral" : void 0,
1525
+ deleteAfter: config?.deleteAfter
1526
+ });
1527
+ if (!msg) return null;
1528
+ const collector = msg.createMessageComponentCollector({
1529
+ componentType: import_discord6.ComponentType.Button,
1530
+ idle: config?.detailButtonIdleTimeout ?? 3e4,
1531
+ filter: (i) => i.customId === "btn_details"
1532
+ });
1533
+ collector.on("collect", (i) => {
1534
+ const attachment = new import_discord6.AttachmentBuilder(Buffer.from(`${error.message}
1535
+
1536
+ ${error.stack}`), {
1537
+ name: "error.txt"
1538
+ });
1539
+ i.reply({ files: [attachment], flags: "Ephemeral" });
1540
+ });
1541
+ collector.on("end", () => {
1542
+ buttons.details.setDisabled(true);
1543
+ embed_error.send(messageOrInteraction, {
1544
+ sendMethod: messageOrInteraction instanceof import_discord6.Message ? 5 /* MessageEdit */ : void 0,
1545
+ components: [actionRow]
1546
+ });
1547
+ });
1548
+ return msg;
1549
+ }
1550
+
1551
+ // src/modules/builtins/builtin.slashCommandHandler.ts
1552
+ var BUILTIN_SlashCommandHandler = new EventBuilder({
1553
+ event: "interactionCreate",
1554
+ name: "SlashCommandHandler",
1555
+ async execute(client, interaction) {
1556
+ if (!interaction.isChatInputCommand()) return;
1557
+ const command = client.commands.slash.get(interaction.commandName);
1558
+ if (!command) {
1559
+ const content = `**/\`${interaction.commandName}\`** is not a registered command.`;
1560
+ if (interaction.replied || interaction.deferred) {
1561
+ return interaction.followUp({ content, flags: "Ephemeral" });
1562
+ }
1563
+ return interaction.reply({ content, flags: "Ephemeral" });
1564
+ }
1565
+ try {
1566
+ return await command.run(client, client, interaction);
1567
+ } catch (err) {
1568
+ await sendCommandErrorEmbed(client, err, interaction.guild, interaction);
1569
+ throw err;
1506
1570
  }
1507
1571
  }
1508
- /**
1509
- * Gets/filters commands and orders them alphabetically.
1510
- */
1511
- getAll(options = {}) {
1512
- const matchedCommands = /* @__PURE__ */ new Map();
1513
- const isDev = this.client.config.app.devMode;
1514
- for (const cmd of this.commands.values()) {
1515
- const commandName = "builder" in cmd ? cmd.builder.name : cmd.options.name;
1516
- if (options.names || options.fuzzyNames) {
1517
- const nameMatched = options.names?.includes(commandName) || options.fuzzyNames?.some((fuzzy) => commandName.includes(fuzzy));
1518
- if (!nameMatched) continue;
1572
+ });
1573
+
1574
+ // src/modules/builtins/builtin.prefixCommandHandler.ts
1575
+ var import_discord7 = require("discord.js");
1576
+ var BUILTIN_PrefixCommandHandler = new EventBuilder({
1577
+ event: "messageCreate",
1578
+ name: "PrefixCommandHandler",
1579
+ async execute(client, message) {
1580
+ if (message.author.bot || !message.guild) return;
1581
+ const config = client.config.prefixCommands;
1582
+ let activePrefix = config.defaultPrefix;
1583
+ if (config.guildPrefixResolver) {
1584
+ try {
1585
+ const customPrefix = await config.guildPrefixResolver(client, message.guild.id);
1586
+ if (customPrefix) activePrefix = customPrefix;
1587
+ } catch (err) {
1588
+ client.logger.error(`Error in guildPrefixResolver for guild ${message.guild.id}:`, err);
1519
1589
  }
1520
- if (options.ignoreDeploymentOptions) {
1521
- matchedCommands.set(commandName, cmd);
1522
- continue;
1590
+ }
1591
+ let prefixUsed;
1592
+ if (message.content.startsWith(activePrefix)) {
1593
+ prefixUsed = activePrefix;
1594
+ } else if (config.allowMentionAsPrefix) {
1595
+ const mention = (0, import_discord7.userMention)(client.user.id);
1596
+ if (message.content.startsWith(mention)) {
1597
+ prefixUsed = message.content.startsWith(`${mention} `) ? `${mention} ` : mention;
1523
1598
  }
1524
- const deployment = "deployment" in cmd.options ? cmd.options.deployment ?? {} : {};
1525
- const isProperEnv = !deployment.environments || deployment.environments.includes(isDev ? "development" : "production");
1526
- if (!isProperEnv) continue;
1527
- if (options.globalOnly && deployment.global === false) continue;
1528
- matchedCommands.set(commandName, cmd);
1529
1599
  }
1530
- return Array.from(matchedCommands.values()).sort((a, b) => {
1531
- const commandNameA = "builder" in a ? a.builder.name : a.options.name;
1532
- const commandNameB = "builder" in b ? b.builder.name : b.options.name;
1533
- return commandNameA.localeCompare(commandNameB);
1600
+ if (!prefixUsed) return;
1601
+ const contentWithoutPrefix = message.content.slice(prefixUsed.length).trim();
1602
+ const args = contentWithoutPrefix.split(/\s+/);
1603
+ const trigger = args.shift();
1604
+ if (!trigger) return;
1605
+ const command = client.commands.prefix.get(trigger);
1606
+ if (!command) return;
1607
+ message.content = args.join(" ");
1608
+ try {
1609
+ return await command.run(client, client, message);
1610
+ } catch (err) {
1611
+ await sendCommandErrorEmbed(client, err, message.guild, message);
1612
+ throw err;
1613
+ }
1614
+ }
1615
+ });
1616
+
1617
+ // src/modules/builtins/builtin.contextCommandHandler.ts
1618
+ var BUILTIN_ContextCommandHandler = new EventBuilder({
1619
+ event: "interactionCreate",
1620
+ name: "ContextCommandHandler",
1621
+ async execute(client, interaction) {
1622
+ if (!interaction.isContextMenuCommand()) return;
1623
+ const command = client.commands.context.get(interaction.commandName);
1624
+ if (!command) {
1625
+ const content = `**${interaction.commandName}** is not a registered context command.`;
1626
+ if (interaction.replied || interaction.deferred) {
1627
+ return interaction.followUp({ content, flags: "Ephemeral" });
1628
+ }
1629
+ return interaction.reply({ content, flags: "Ephemeral" });
1630
+ }
1631
+ try {
1632
+ return await command.run(client, client, interaction);
1633
+ } catch (err) {
1634
+ await sendCommandErrorEmbed(client, err, interaction.guild, interaction);
1635
+ throw err;
1636
+ }
1637
+ }
1638
+ });
1639
+
1640
+ // src/tools/Logger.ts
1641
+ var import_chalk = __toESM(require("chalk"));
1642
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
1643
+ LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
1644
+ LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
1645
+ LogLevel2[LogLevel2["SUCCESS"] = 2] = "SUCCESS";
1646
+ LogLevel2[LogLevel2["WARN"] = 3] = "WARN";
1647
+ LogLevel2[LogLevel2["ERROR"] = 4] = "ERROR";
1648
+ return LogLevel2;
1649
+ })(LogLevel || {});
1650
+ var LOGGER_COLORS = {
1651
+ primary: "#5865F2",
1652
+ success: "#57F287",
1653
+ warn: "#FEE75C",
1654
+ danger: "#ED4245",
1655
+ muted: "#747F8D",
1656
+ text: "#FFFFFF"
1657
+ };
1658
+ var Logger = class {
1659
+ logPrefixEmoji;
1660
+ logPrefix;
1661
+ minLevel;
1662
+ showTimestamp;
1663
+ colorScheme;
1664
+ constructor(options) {
1665
+ const { prefixEmoji = null, prefix = null, minLevel = 0 /* DEBUG */, showTimestamp = true } = options || {};
1666
+ this.logPrefixEmoji = prefixEmoji;
1667
+ this.logPrefix = prefix;
1668
+ this.minLevel = minLevel;
1669
+ this.showTimestamp = showTimestamp;
1670
+ this.colorScheme = {
1671
+ ...LOGGER_COLORS,
1672
+ ...options?.colors
1673
+ };
1674
+ }
1675
+ formatTimestamp() {
1676
+ if (!this.showTimestamp) return "";
1677
+ const now = /* @__PURE__ */ new Date();
1678
+ const time = now.toLocaleTimeString("en-US", {
1679
+ hour12: false,
1680
+ hour: "2-digit",
1681
+ minute: "2-digit",
1682
+ second: "2-digit"
1534
1683
  });
1684
+ return import_chalk.default.hex(this.colorScheme.muted)(`[${time}]`);
1535
1685
  }
1536
- /**
1537
- * Groups commands by category alphabetically.
1538
- */
1539
- sortByCategory() {
1540
- const categories = /* @__PURE__ */ new Map();
1541
- for (const cmd of this.commands.values()) {
1542
- const metadata = cmd.options.metadata;
1543
- if (!metadata?.category) continue;
1544
- let entry = categories.get(metadata.category);
1545
- if (!entry) {
1546
- entry = {
1547
- name: metadata.category,
1548
- emoji: metadata.categoryEmoji,
1549
- commands: []
1686
+ formatPrefix() {
1687
+ if (!this.logPrefix) return "";
1688
+ return import_chalk.default.bold.hex(this.colorScheme.primary)(
1689
+ `${this.logPrefixEmoji ? `${this.logPrefixEmoji} ` : ""}${this.logPrefix}`
1690
+ );
1691
+ }
1692
+ shouldLog(level) {
1693
+ return level >= this.minLevel;
1694
+ }
1695
+ get prefixEmoji() {
1696
+ return this.logPrefixEmoji;
1697
+ }
1698
+ get prefix() {
1699
+ return this.logPrefix;
1700
+ }
1701
+ get colors() {
1702
+ return this.colorScheme;
1703
+ }
1704
+ extend(extras) {
1705
+ for (const [key, fn] of Object.entries(extras)) {
1706
+ if (typeof fn === "function") {
1707
+ this[key] = function(...args) {
1708
+ return fn.call(this, ...args);
1550
1709
  };
1551
- categories.set(metadata.category, entry);
1552
1710
  }
1553
- entry.commands.push(cmd);
1554
1711
  }
1555
- return Array.from(categories.values()).sort((a, b) => a.name.localeCompare(b.name)).map((cat) => {
1556
- cat.commands.sort((a, b) => {
1557
- const commandNameA = "builder" in a ? a.builder.name : a.options.name;
1558
- const commandNameB = "builder" in b ? b.builder.name : b.options.name;
1559
- return commandNameA.localeCompare(commandNameB);
1560
- });
1561
- return cat;
1562
- });
1712
+ return this;
1563
1713
  }
1564
- /**
1565
- * Imports command modules from a directory.
1566
- * @param dir Path of one or more folders.
1567
- * @param set Replaces imported command modules with the ones found.
1568
- */
1569
- async importFrom(dir, set = false) {
1570
- if (set) this.commands.clear();
1571
- const dirs = Array.isArray(dir) ? dir : [dir];
1572
- const modules = [];
1573
- for (const _dir of dirs) {
1574
- const results = await importModulesFromDir(_dir, this.moduleSuffix);
1575
- modules.push(...results.map(({ module: module2 }) => module2.default));
1576
- }
1577
- for (const module2 of modules) {
1578
- const commandName = "builder" in module2 ? module2.builder.name : module2.options.name;
1579
- this.commands.set(commandName, module2);
1580
- }
1581
- let moduleType;
1582
- switch (this.type) {
1583
- case 0 /* Slash */:
1584
- moduleType = "Prefix Commands";
1585
- break;
1586
- case 2 /* Context */:
1587
- moduleType = "Context Commands";
1588
- break;
1589
- case 1 /* Prefix */:
1590
- moduleType = "Prefix Commands";
1591
- break;
1592
- }
1593
- this.client.logger.moduleLoaded(moduleType, modules.length);
1594
- return this.commands;
1714
+ setPrefix(prefix) {
1715
+ this.logPrefix = prefix;
1716
+ return this;
1595
1717
  }
1596
- };
1597
- var SlashCommandManager = class extends BaseCommandManager {
1598
- constructor(client) {
1599
- super(client, 0 /* Slash */, client.config.app.moduleSuffixes.slashCommand);
1718
+ setPrefixEmoji(prefixEmoji) {
1719
+ this.logPrefixEmoji = prefixEmoji;
1720
+ return this;
1600
1721
  }
1601
- };
1602
- var ContextCommandManager = class extends BaseCommandManager {
1603
- constructor(client) {
1604
- super(client, 2 /* Context */, client.config.app.moduleSuffixes.contextCommand);
1722
+ setMinLevel(minLevel) {
1723
+ this.minLevel = minLevel;
1724
+ return this;
1605
1725
  }
1606
- };
1607
- var PrefixCommandManager = class extends BaseCommandManager {
1608
- constructor(client) {
1609
- super(client, 1 /* Prefix */, client.config.app.moduleSuffixes.prefixCommand);
1726
+ setShowTimestamp(show) {
1727
+ this.showTimestamp = show;
1728
+ return this;
1610
1729
  }
1611
- };
1612
- var CommandManager = class {
1613
- client;
1614
- slash;
1615
- prefix;
1616
- context;
1617
- constructor(client) {
1618
- this.client = client;
1619
- this.slash = new SlashCommandManager(client);
1620
- this.prefix = new PrefixCommandManager(client);
1621
- this.context = new ContextCommandManager(client);
1730
+ setColors(colors) {
1731
+ this.colorScheme = {
1732
+ ...LOGGER_COLORS,
1733
+ ...colors
1734
+ };
1735
+ return this;
1622
1736
  }
1623
- getAllAppCommands(options = {}) {
1624
- return [...this.slash.getAll(options), ...this.context.getAll(options)];
1737
+ log(message, ...args) {
1738
+ console.log(this.formatTimestamp(), this.formatPrefix(), message, ...args);
1625
1739
  }
1626
- async registerGlobal(options = {}) {
1627
- const client = await this.client.whenReady();
1628
- if (!client.rest) {
1629
- console.error(`[CommandManager] \u2716 Failed to register app commands globally: REST is not initialized`);
1630
- return;
1631
- }
1632
- const commands = this.getAllAppCommands(options);
1633
- if (!commands.length) {
1634
- console.log("[CommandManager] No commands to register globally");
1635
- return;
1636
- }
1637
- console.log(`[CommandManager] Registering (${commands.length}) commands globally...`);
1638
- try {
1639
- await client.rest.put(import_discord5.Routes.applicationCommands(client.user.id), { body: commands });
1640
- console.log(`[CommandManager] \u2714 Registered app commands globally`);
1641
- } catch (err) {
1642
- console.error(`[CommandManager] \u2716 Failed to register app commands globally`, err);
1643
- }
1740
+ debug(message, ...args) {
1741
+ if (!this.shouldLog(0 /* DEBUG */)) return;
1742
+ console.log(
1743
+ this.formatTimestamp(),
1744
+ this.formatPrefix(),
1745
+ import_chalk.default.hex(this.colorScheme.muted)("DEBUG"),
1746
+ import_chalk.default.dim(message),
1747
+ ...args
1748
+ );
1644
1749
  }
1645
- async unregisterGlobal() {
1646
- const client = await this.client.whenReady();
1647
- if (!client.rest) {
1648
- console.error(`[CommandManager] \u2716 Failed to remove app commands globally: REST is not initialized`);
1649
- return;
1650
- }
1651
- try {
1652
- await client.rest.put(import_discord5.Routes.applicationCommands(client.user.id), { body: [] });
1653
- console.log(`[CommandManager] \u2714 Removed app commands globally`);
1654
- } catch (err) {
1655
- console.error(`[CommandManager] \u2716 Failed to remove app commands globally`, err);
1656
- }
1750
+ info(message, ...args) {
1751
+ if (!this.shouldLog(1 /* INFO */)) return;
1752
+ console.log(this.formatTimestamp(), this.formatPrefix(), import_chalk.default.hex("#87CEEB")("INFO"), message, ...args);
1657
1753
  }
1658
- async registerGuild(options = {}) {
1659
- const client = await this.client.whenReady();
1660
- if (!client.rest) {
1661
- console.error(`[CommandManager] \u2716 Failed to register app commands by guild: REST is not initialized`);
1662
- return;
1663
- }
1664
- const commands = this.getAllAppCommands(options);
1665
- if (!commands.length) {
1666
- console.log("[CommandManager] No commands to register by guild");
1667
- return;
1754
+ success(message, ...args) {
1755
+ if (!this.shouldLog(2 /* SUCCESS */)) return;
1756
+ console.log(
1757
+ this.formatTimestamp(),
1758
+ this.formatPrefix(),
1759
+ import_chalk.default.bold.hex(this.colorScheme.success)("\u2713 SUCCESS"),
1760
+ import_chalk.default.hex(this.colorScheme.success)(message),
1761
+ ...args
1762
+ );
1763
+ }
1764
+ warn(message, ...args) {
1765
+ if (!this.shouldLog(3 /* WARN */)) return;
1766
+ console.warn(
1767
+ this.formatTimestamp(),
1768
+ this.formatPrefix(),
1769
+ import_chalk.default.bold.hex(this.colorScheme.warn)("\u26A0 WARN"),
1770
+ import_chalk.default.hex(this.colorScheme.warn)(message),
1771
+ ...args
1772
+ );
1773
+ }
1774
+ error(message, error, ...args) {
1775
+ if (!this.shouldLog(4 /* ERROR */)) return;
1776
+ console.error(
1777
+ this.formatTimestamp(),
1778
+ this.formatPrefix(),
1779
+ import_chalk.default.bold.hex(this.colorScheme.danger)("\u2715 ERROR"),
1780
+ import_chalk.default.hex(this.colorScheme.danger)(message),
1781
+ ...args
1782
+ );
1783
+ if (error && error.stack) {
1784
+ console.error(import_chalk.default.dim(error.stack));
1668
1785
  }
1669
- const guildIds = options.guilds || client.guilds.cache.map((g) => g.id);
1670
- console.log(`[CommandManager] Registering (${commands.length}) commands for ${guildIds.length} guilds...`);
1671
- await Promise.all(
1672
- guildIds.map(
1673
- (guildId) => client.rest.put(import_discord5.Routes.applicationGuildCommands(client.user.id, guildId), { body: commands }).then(() => {
1674
- const gName = client.guilds.cache.get(guildId)?.name || "n/a";
1675
- console.log(`[CommandManager] \u2714 Set app commands in guild: ${guildId} (${gName})`);
1676
- }).catch((err) => {
1677
- const gName = client.guilds.cache.get(guildId)?.name || "n/a";
1678
- console.log(`[CommandManager] \u2716 Failed to set app commands in guild: ${guildId} (${gName})`, err);
1679
- })
1680
- )
1786
+ }
1787
+ loader(message) {
1788
+ const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
1789
+ let i = 0;
1790
+ const interval = setInterval(() => {
1791
+ process.stdout.write(
1792
+ `\r${this.formatTimestamp()} ${this.formatPrefix()} ${import_chalk.default.hex(this.colorScheme.warn)(frames[i])} ${message}`
1793
+ );
1794
+ i = (i + 1) % frames.length;
1795
+ }, 100);
1796
+ return (newMessage) => {
1797
+ clearInterval(interval);
1798
+ process.stdout.write(
1799
+ `\r${this.formatTimestamp()} ${this.formatPrefix()} ${import_chalk.default.hex(this.colorScheme.success)("\u2713")} ${newMessage || message}
1800
+ `
1801
+ );
1802
+ };
1803
+ }
1804
+ table(title, data) {
1805
+ console.log(this.formatTimestamp(), this.formatPrefix(), import_chalk.default.bold(title));
1806
+ Object.entries(data).forEach(([key, value]) => {
1807
+ const formattedKey = import_chalk.default.hex(this.colorScheme.warn)(` ${key}`);
1808
+ const formattedValue = import_chalk.default.hex(this.colorScheme.muted)(value);
1809
+ console.log(`${formattedKey.padEnd(25)} ${formattedValue}`);
1810
+ });
1811
+ }
1812
+ section(title) {
1813
+ const line = "\u2500".repeat(Math.max(30, title.length + 4));
1814
+ console.log(import_chalk.default.hex(this.colorScheme.muted)(`
1815
+ \u250C\u2500${line}\u2500\u2510`));
1816
+ console.log(
1817
+ import_chalk.default.hex(this.colorScheme.muted)("\u2502 ") + import_chalk.default.bold.hex(this.colorScheme.text)(title.padEnd(line.length)) + import_chalk.default.hex(this.colorScheme.muted)(" \u2502")
1681
1818
  );
1819
+ console.log(import_chalk.default.hex(this.colorScheme.muted)(`\u2514\u2500${line}\u2500\u2518`));
1682
1820
  }
1683
- async unregisterGuild(options = {}) {
1684
- const client = await this.client.whenReady();
1685
- if (!client.rest) {
1686
- console.error(`[CommandManager] \u2716 Failed to register app commands by guild: REST is not initialized`);
1687
- return;
1821
+ };
1822
+ var logger = new Logger();
1823
+
1824
+ // src/tools/utils.ts
1825
+ function __zero(str) {
1826
+ return str?.length ? str : "0";
1827
+ }
1828
+ function isMentionOrSnowflake(str) {
1829
+ return str ? str.match(/<@[#&]?[\d]{6,}>/) || str.match(/\d{6,}/) ? true : false : false;
1830
+ }
1831
+ function cleanMention(str) {
1832
+ return str ? str.replaceAll(/[<@#&>]/g, "").trim() : void 0;
1833
+ }
1834
+ async function getMessageMention(message, content, type, index = 0, idOnly) {
1835
+ const args = content?.split(" ");
1836
+ const arg = isMentionOrSnowflake(args?.[index]) ? cleanMention(args?.[index]) : void 0;
1837
+ switch (type) {
1838
+ case "user":
1839
+ const userMention2 = message.mentions.users.at(index) || null;
1840
+ if (!userMention2 && arg) {
1841
+ return idOnly ? arg : await fetchUser(message.client, arg);
1842
+ } else {
1843
+ return idOnly ? userMention2?.id || null : userMention2;
1844
+ }
1845
+ case "member":
1846
+ if (!message.guild) return null;
1847
+ const member = await fetchMember(message.guild, message.mentions.users.at(index)?.id ?? arg);
1848
+ return idOnly ? member?.id || null : member;
1849
+ case "channel":
1850
+ const channelMention = message.mentions.channels.at(index) || null;
1851
+ if (!channelMention && arg) {
1852
+ return idOnly ? arg : message.guild ? await fetchChannel(message.guild, arg) : message.client.channels.cache.get(__zero(arg)) ?? message.client.channels.fetch(__zero(arg));
1853
+ } else {
1854
+ return idOnly ? channelMention?.id || null : channelMention;
1855
+ }
1856
+ case "role":
1857
+ const roleMention = message.mentions.roles.at(index) || null;
1858
+ if (!roleMention && arg) {
1859
+ return idOnly ? arg : message.guild ? await fetchRole(message.guild, arg) : null;
1860
+ } else {
1861
+ return idOnly ? roleMention?.id || null : roleMention;
1862
+ }
1863
+ default:
1864
+ return null;
1865
+ }
1866
+ }
1867
+ function getFirstMentionId(options) {
1868
+ let mentionId = "";
1869
+ if (options.message) {
1870
+ switch (options.type) {
1871
+ case "user":
1872
+ mentionId = options.message.mentions.users.first()?.id || "";
1873
+ break;
1874
+ case "channel":
1875
+ mentionId = options.message.mentions.channels.first()?.id || "";
1876
+ break;
1877
+ case "role":
1878
+ mentionId = options.message.mentions.roles.first()?.id || "";
1879
+ break;
1688
1880
  }
1689
- const guildIds = options.guilds || client.guilds.cache.map((g) => g.id);
1690
- console.log(`[CommandManager] Unregistering commands from ${guildIds.length} guilds...`);
1691
- await Promise.all(
1692
- guildIds.map(
1693
- (guildId) => client.rest.put(import_discord5.Routes.applicationGuildCommands(client.user.id, guildId), { body: [] }).then(() => console.log(`[CommandManager] \u2714 Removed app commands in guild: ${guildId}`)).catch((err) => console.log(`[CommandManager] \u2716 Failed to remove app commands in guild: ${guildId}`, err))
1694
- )
1695
- );
1881
+ }
1882
+ const firstArg = options.content?.split(" ")[0] || "";
1883
+ return mentionId || isMentionOrSnowflake(firstArg) ? cleanMention(firstArg) : "";
1884
+ }
1885
+ async function fetchUser(client, userId) {
1886
+ if (!userId) return null;
1887
+ return client.users.cache.get(__zero(userId)) || await client.users.fetch(__zero(userId)).catch(() => null);
1888
+ }
1889
+ async function fetchGuild(client, guildId) {
1890
+ if (!guildId) return null;
1891
+ return client.guilds.cache.get(__zero(guildId)) || await client.guilds.fetch(__zero(guildId)).catch(() => null);
1892
+ }
1893
+ async function fetchMember(guild, memberId) {
1894
+ if (!memberId) return null;
1895
+ return guild.members.cache.get(__zero(memberId)) || await guild.members.fetch(__zero(memberId)).catch(() => null);
1896
+ }
1897
+ async function fetchChannel(guild, channelId, type) {
1898
+ if (!channelId) return null;
1899
+ const channel = guild.channels.cache.get(__zero(channelId)) || await guild.channels.fetch(__zero(channelId)).catch(() => null);
1900
+ if (type && channel?.type !== type) return null;
1901
+ return channel;
1902
+ }
1903
+ async function fetchRole(guild, roleId) {
1904
+ if (!roleId) return null;
1905
+ return guild.roles.cache.get(__zero(roleId)) || await guild.roles.fetch(__zero(roleId)).catch(() => null) || null;
1906
+ }
1907
+ async function fetchMessage(channel, messageId) {
1908
+ if (!messageId) return null;
1909
+ return channel.messages.cache.get(__zero(messageId)) || await channel.messages.fetch(__zero(messageId)).catch(() => null) || null;
1910
+ }
1911
+
1912
+ // src/types/status.ts
1913
+ var import_discord8 = require("discord.js");
1914
+ var import_lodash11 = __toESM(require("lodash"));
1915
+ var StatusType = /* @__PURE__ */ ((StatusType2) => {
1916
+ StatusType2["DND"] = "dnd";
1917
+ StatusType2["Idle"] = "idle";
1918
+ StatusType2["Online"] = "online";
1919
+ StatusType2["Invisible"] = "invisible";
1920
+ return StatusType2;
1921
+ })(StatusType || {});
1922
+ var defaultPresence = {
1923
+ production: {
1924
+ interval: 6e4,
1925
+ randomize: false,
1926
+ activity: [
1927
+ { status: "online" /* Online */, type: import_discord8.ActivityType.Custom, name: "Need help? Use /help or !help" },
1928
+ { status: "online" /* Online */, type: import_discord8.ActivityType.Custom, name: "Join our community!" },
1929
+ { status: "online" /* Online */, type: import_discord8.ActivityType.Watching, name: "\u2728 $GUILD_COUNT servers" }
1930
+ ]
1931
+ },
1932
+ development: {
1933
+ activity: { status: "dnd" /* DND */, type: import_discord8.ActivityType.Custom, name: "In development!" }
1696
1934
  }
1697
1935
  };
1936
+ function createVimcordStatusConfig(options = {}) {
1937
+ return import_lodash11.default.merge(defaultPresence, options);
1938
+ }
1698
1939
 
1699
- // src/modules/event.manager.ts
1700
- var import_discord6 = require("discord.js");
1701
- var EventManager = class {
1940
+ // src/modules/status.manager.ts
1941
+ var import_node_events = __toESM(require("events"));
1942
+ var import_qznt2 = require("qznt");
1943
+ var StatusManager = class {
1702
1944
  client;
1703
- events = /* @__PURE__ */ new Map();
1704
1945
  logger;
1946
+ emitter = new import_node_events.default();
1947
+ lastActivity = null;
1948
+ lastActivityIndex = 0;
1949
+ task = null;
1705
1950
  constructor(client) {
1706
1951
  this.client = client;
1707
- this.logger = new Logger({ prefixEmoji: "\u{1F4CB}", prefix: `EventManager (i${this.client.clientId})` });
1708
- for (const event of Object.values(import_discord6.Events)) {
1709
- client.on(
1710
- event.toString(),
1711
- async (...args) => this.executeEvents.apply(this, [event, ...args])
1712
- );
1713
- }
1714
- }
1715
- register(...events) {
1716
- for (const event of events) {
1717
- this.events.set(event.name, event);
1952
+ this.logger = new Logger({ prefixEmoji: "\u{1F4AC}", prefix: `StatusManager (i${this.client.clientId})` });
1953
+ this.emitter.on("changed", (activity) => {
1718
1954
  if (this.client.config.app.verbose) {
1719
- this.logger.debug(`'${event.name}' registered for EventType '${event.event}'`);
1955
+ this.logger.debug(`Status changed to '${activity.name}'`);
1720
1956
  }
1721
- }
1722
- }
1723
- unregister(...names) {
1724
- for (const name of names) {
1725
- const event = this.events.get(name);
1726
- if (!event) continue;
1727
- this.events.delete(name);
1957
+ });
1958
+ this.emitter.on("cleared", () => {
1728
1959
  if (this.client.config.app.verbose) {
1729
- this.logger.debug(`'${event.name}' unregistered for EventType '${event.event}'`);
1730
- }
1731
- }
1732
- }
1733
- clear() {
1734
- this.events.forEach((e) => this.unregister(e.name));
1735
- this.events.clear();
1736
- }
1737
- get(name) {
1738
- return this.events.get(name);
1739
- }
1740
- getByTag(tag) {
1741
- return Array.from(this.events.values()).filter((event) => event.metadata?.tags?.includes(tag));
1742
- }
1743
- getByCategory(category) {
1744
- return Array.from(this.events.values()).filter((event) => event.metadata?.category?.includes(category));
1745
- }
1746
- getByEvent(eventType) {
1747
- return Array.from(this.events.values()).filter((event) => event.event === eventType);
1748
- }
1749
- async executeEvents(eventType, ...args) {
1750
- const events = this.getByEvent(eventType);
1751
- if (!events.length) return;
1752
- const sortedEvents = events.sort((a, b) => b.priority - a.priority);
1753
- await Promise.all(
1754
- sortedEvents.map(async (event) => {
1755
- try {
1756
- await event.execute?.(this.client, ...args);
1757
- if (event.once) {
1758
- this.unregister(event.name);
1759
- }
1760
- } catch (err) {
1761
- this.logger.error(`'${event.name}' failed to execute`, err);
1762
- }
1763
- })
1764
- );
1765
- }
1766
- /** Import event modules that end with `.event` */
1767
- async importFrom(dir, replaceAll) {
1768
- dir = Array.isArray(dir) ? dir : [dir];
1769
- const eventModules = await Promise.all(
1770
- dir.map((dir2) => importModulesFromDir(dir2, "event"))
1771
- );
1772
- if (replaceAll) {
1773
- this.clear();
1774
- }
1775
- let importedEvents = 0;
1776
- let ignoredEvents = 0;
1777
- for (const event of eventModules.flat()) {
1778
- if (!event.module.default.enabled) {
1779
- ignoredEvents++;
1780
- } else {
1781
- importedEvents++;
1960
+ this.logger.debug("Status cleared");
1782
1961
  }
1783
- this.register(event.module.default);
1784
- }
1785
- this.client.logger.moduleLoaded("Event Handlers", importedEvents, ignoredEvents);
1786
- return this.events;
1962
+ });
1787
1963
  }
1788
- };
1789
-
1790
- // src/utils/sendCommandErrorEmbed.ts
1791
- var import_discord9 = require("discord.js");
1792
-
1793
- // src/tools/BetterEmbed.ts
1794
- var import_discord8 = require("discord.js");
1795
-
1796
- // src/tools/dynaSend.ts
1797
- var import_discord7 = require("discord.js");
1798
-
1799
- // src/tools/types.ts
1800
- var SendMethod = /* @__PURE__ */ ((SendMethod2) => {
1801
- SendMethod2[SendMethod2["Reply"] = 0] = "Reply";
1802
- SendMethod2[SendMethod2["EditReply"] = 1] = "EditReply";
1803
- SendMethod2[SendMethod2["FollowUp"] = 2] = "FollowUp";
1804
- SendMethod2[SendMethod2["Channel"] = 3] = "Channel";
1805
- SendMethod2[SendMethod2["MessageReply"] = 4] = "MessageReply";
1806
- SendMethod2[SendMethod2["MessageEdit"] = 5] = "MessageEdit";
1807
- SendMethod2[SendMethod2["User"] = 6] = "User";
1808
- return SendMethod2;
1809
- })(SendMethod || {});
1810
-
1811
- // src/tools/dynaSend.ts
1812
- var DynaSend = class {
1813
- static forceArray(value) {
1814
- return Array.isArray(value) ? value : [value];
1964
+ clearData() {
1965
+ this.task?.stop();
1966
+ this.task = null;
1967
+ this.lastActivity = null;
1968
+ this.lastActivityIndex = 0;
1969
+ return this;
1815
1970
  }
1816
- static isInteractionCallback(obj) {
1817
- return obj instanceof import_discord7.InteractionCallbackResponse;
1971
+ async getReadyClient() {
1972
+ const client = await this.client.waitForReady();
1973
+ if (!client.user) throw new Error("Cannot manage the client's activity when its user is not hydrated");
1974
+ return client;
1818
1975
  }
1819
- static filterFlags(flags, excludeFlags) {
1820
- if (!flags) return void 0;
1821
- const flagArray = this.forceArray(flags);
1822
- return flagArray.filter((flag) => !excludeFlags.includes(flag));
1976
+ async formatActivityName(name) {
1977
+ name = name.replace("$USER_COUNT", import_qznt2.$.format.number(this.client.users.cache.size)).replace("$GUILD_COUNT", import_qznt2.$.format.number(this.client.guilds.cache.size)).replace(
1978
+ "$INVITE",
1979
+ this.client.config.staff.guild.inviteUrl ? this.client.config.staff.guild.inviteUrl : "<STAFF_INVITE_URL_NOT_SET>"
1980
+ );
1981
+ if (name.includes("$STAFF_GUILD_MEMBER_COUNT")) {
1982
+ await fetchGuild(this.client, this.client.config.staff.guild.id).then((guild) => {
1983
+ if (!guild) return name = name.replace("$STAFF_GUILD_MEMBER_COUNT", "<STAFF_GUILD_NOT_FOUND>");
1984
+ name = name.replace("$STAFF_GUILD_MEMBER_COUNT", import_qznt2.$.format.number(guild.members.cache.size));
1985
+ }).catch((err) => this.logger.error("Failed to fetch the staff guild", err));
1986
+ }
1987
+ return name;
1823
1988
  }
1824
- static detectSendMethod(handler) {
1825
- if (handler instanceof import_discord7.BaseInteraction) {
1826
- return handler.replied || handler.deferred ? 1 /* EditReply */ : 0 /* Reply */;
1989
+ async setActivity(activity) {
1990
+ const client = await this.getReadyClient();
1991
+ activity.name = await this.formatActivityName(activity.name);
1992
+ client.user.setStatus(activity.status);
1993
+ client.user.setActivity({ name: activity.name, type: activity.type, url: activity.streamUrl });
1994
+ this.emitter.emit("changed", activity);
1995
+ }
1996
+ async statusRotationTask(clientStatus) {
1997
+ let activity;
1998
+ if (clientStatus.randomize && Array.isArray(clientStatus.activity)) {
1999
+ activity = import_qznt2.$.rnd.choice(clientStatus.activity, { not: this.lastActivity });
2000
+ this.lastActivity = activity;
2001
+ } else {
2002
+ const activityIndex = (this.lastActivityIndex + 1) % clientStatus.activity.length;
2003
+ this.lastActivityIndex = activityIndex;
2004
+ activity = clientStatus.activity[activityIndex];
1827
2005
  }
1828
- if (handler instanceof import_discord7.BaseChannel) return 3 /* Channel */;
1829
- if (handler instanceof import_discord7.Message) return 4 /* MessageReply */;
1830
- if (handler instanceof import_discord7.GuildMember || handler instanceof import_discord7.User) return 6 /* User */;
1831
- throw new Error("[DynaSend] Unable to determine send method for handler type");
2006
+ await this.setActivity(activity);
2007
+ this.emitter.emit("rotation", activity);
1832
2008
  }
1833
- static validateSendMethod(handler, method) {
1834
- const interactionMethods = [0 /* Reply */, 1 /* EditReply */, 2 /* FollowUp */];
1835
- if (interactionMethods.includes(method) && !(handler instanceof import_discord7.BaseInteraction)) {
1836
- throw new TypeError(`[DynaSend] SendMethod '${SendMethod[method]}' requires BaseInteraction handler`);
2009
+ async scheduleStatusRotation(clientStatus) {
2010
+ if (!clientStatus.interval) throw new Error("Cannot create client activity interval without interval time");
2011
+ this.task?.stop();
2012
+ this.task = null;
2013
+ this.task = new import_qznt2.$.Loop(() => this.statusRotationTask(clientStatus), import_qznt2.$.math.ms(clientStatus.interval), true);
2014
+ this.start();
2015
+ }
2016
+ start() {
2017
+ if (this.task) {
2018
+ this.task.start();
2019
+ this.emitter.emit("started", this.task);
1837
2020
  }
1838
- if (method === 3 /* Channel */ && !(handler instanceof import_discord7.BaseChannel)) {
1839
- throw new TypeError(`[DynaSend] SendMethod '${SendMethod[method]}' requires BaseChannel handler`);
2021
+ return this;
2022
+ }
2023
+ pause() {
2024
+ if (this.task) {
2025
+ this.task.stop();
2026
+ this.emitter.emit("paused", this.task);
1840
2027
  }
1841
- if ([4 /* MessageReply */, 5 /* MessageEdit */].includes(method) && !(handler instanceof import_discord7.Message)) {
1842
- throw new TypeError(`[DynaSend] SendMethod '${SendMethod[method]}' requires Message handler`);
2028
+ return this;
2029
+ }
2030
+ async set(status) {
2031
+ const statusConfig = createVimcordStatusConfig(status);
2032
+ let clientStatus;
2033
+ if (this.client.config.app.devMode) {
2034
+ clientStatus = statusConfig.development;
2035
+ } else {
2036
+ clientStatus = statusConfig.production;
1843
2037
  }
1844
- if (method === 6 /* User */ && !(handler instanceof import_discord7.GuildMember || handler instanceof import_discord7.User)) {
1845
- throw new TypeError(`[DynaSend] SendMethod '${SendMethod[method]}' requires User or GuildMember handler`);
2038
+ if (!clientStatus.interval) {
2039
+ await this.setActivity(Array.isArray(clientStatus.activity) ? clientStatus.activity[0] : clientStatus.activity);
2040
+ } else {
2041
+ await this.scheduleStatusRotation(clientStatus);
1846
2042
  }
2043
+ return this;
1847
2044
  }
1848
- static createMessageData(options, method) {
1849
- const baseData = {
1850
- content: options.content,
1851
- embeds: options.embeds,
1852
- components: options.components,
1853
- files: options.files,
1854
- allowedMentions: options.allowedMentions,
1855
- tts: options.tts
1856
- };
1857
- switch (method) {
1858
- case 0 /* Reply */:
1859
- return {
1860
- ...baseData,
1861
- flags: options.flags,
1862
- withResponse: options.withResponse,
1863
- poll: options.poll
1864
- };
1865
- case 1 /* EditReply */:
1866
- return {
1867
- ...baseData,
1868
- flags: this.filterFlags(options.flags, ["Ephemeral", "SuppressNotifications"]),
1869
- withResponse: options.withResponse,
1870
- poll: options.poll
1871
- };
1872
- case 2 /* FollowUp */:
1873
- return {
1874
- ...baseData,
1875
- flags: options.flags,
1876
- withResponse: options.withResponse,
1877
- poll: options.poll
1878
- };
1879
- case 3 /* Channel */:
1880
- return {
1881
- ...baseData,
1882
- flags: this.filterFlags(options.flags, ["Ephemeral"]),
1883
- poll: options.poll,
1884
- stickers: options.stickers,
1885
- reply: options.reply
1886
- };
1887
- case 4 /* MessageReply */:
1888
- return {
1889
- ...baseData,
1890
- flags: this.filterFlags(options.flags, ["Ephemeral"]),
1891
- poll: options.poll,
1892
- stickers: options.stickers
1893
- };
1894
- case 5 /* MessageEdit */:
1895
- return {
1896
- ...baseData,
1897
- flags: this.filterFlags(options.flags, ["Ephemeral", "SuppressNotifications"])
1898
- };
1899
- case 6 /* User */:
1900
- return {
1901
- ...baseData,
1902
- flags: this.filterFlags(options.flags, ["Ephemeral"]),
1903
- poll: options.poll,
1904
- forward: options.forward,
1905
- stickers: options.stickers
1906
- };
1907
- default:
1908
- return baseData;
2045
+ async destroy() {
2046
+ if (this.task) {
2047
+ this.task.stop();
2048
+ this.task = null;
2049
+ this.emitter.emit("destroyed");
2050
+ await this.clear();
1909
2051
  }
2052
+ return this;
1910
2053
  }
1911
- static async executeSend(handler, method, data) {
1912
- try {
1913
- switch (method) {
1914
- case 0 /* Reply */: {
1915
- const response = await handler.reply(data);
1916
- return this.isInteractionCallback(response) ? response.resource?.message ?? null : null;
1917
- }
1918
- case 1 /* EditReply */:
1919
- return await handler.editReply(data);
1920
- case 2 /* FollowUp */:
1921
- return await handler.followUp(data);
1922
- case 3 /* Channel */:
1923
- return await handler.send(data);
1924
- case 4 /* MessageReply */:
1925
- return await handler.reply(data);
1926
- case 5 /* MessageEdit */: {
1927
- const message = handler;
1928
- if (!message.editable) {
1929
- console.warn("[DynaSend] Message is not editable");
1930
- return null;
1931
- }
1932
- return await message.edit(data);
2054
+ async clear() {
2055
+ const client = await this.getReadyClient();
2056
+ this.clearData();
2057
+ client.user.setActivity({ name: "" });
2058
+ this.emitter.emit("cleared");
2059
+ return this;
2060
+ }
2061
+ };
2062
+
2063
+ // src/modules/command.manager.ts
2064
+ var import_discord9 = require("discord.js");
2065
+ var BaseCommandManager = class {
2066
+ type;
2067
+ client;
2068
+ commands = /* @__PURE__ */ new Map();
2069
+ moduleSuffix;
2070
+ constructor(client, type, moduleSuffix) {
2071
+ this.type = type;
2072
+ this.client = client;
2073
+ this.moduleSuffix = moduleSuffix;
2074
+ }
2075
+ /**
2076
+ * Gets a command by name.
2077
+ */
2078
+ get(name) {
2079
+ if (this.type === 1 /* Prefix */) {
2080
+ const config = this.client.config.prefixCommands;
2081
+ const search = config.allowCaseInsensitiveCommandNames ? name.toLowerCase() : name;
2082
+ return Array.from(this.commands.values()).find((cmd) => {
2083
+ const commandName = "builder" in cmd ? cmd.builder.name : cmd.options.name;
2084
+ const trigger = config.allowCaseInsensitiveCommandNames ? commandName.toLowerCase() : commandName;
2085
+ if (trigger === search) return true;
2086
+ if ("aliases" in cmd.options) {
2087
+ return cmd.options.aliases?.some(
2088
+ (a) => config.allowCaseInsensitiveCommandNames ? a.toLowerCase() === search : a === search
2089
+ );
1933
2090
  }
1934
- case 6 /* User */:
1935
- return await handler.send(data);
1936
- default:
1937
- throw new Error(`[DynaSend] Unknown send method '${method}'`);
2091
+ });
2092
+ } else {
2093
+ return this.commands.get(name);
2094
+ }
2095
+ }
2096
+ /**
2097
+ * Gets/filters commands and orders them alphabetically.
2098
+ */
2099
+ getAll(options = {}) {
2100
+ const matchedCommands = /* @__PURE__ */ new Map();
2101
+ const isDev = this.client.config.app.devMode;
2102
+ for (const cmd of this.commands.values()) {
2103
+ const commandName = "builder" in cmd ? cmd.builder.name : cmd.options.name;
2104
+ if (options.names || options.fuzzyNames) {
2105
+ const nameMatched = options.names?.includes(commandName) || options.fuzzyNames?.some((fuzzy) => commandName.includes(fuzzy));
2106
+ if (!nameMatched) continue;
2107
+ }
2108
+ if (options.ignoreDeploymentOptions) {
2109
+ matchedCommands.set(commandName, cmd);
2110
+ continue;
2111
+ }
2112
+ const deployment = "deployment" in cmd.options ? cmd.options.deployment ?? {} : {};
2113
+ const isProperEnv = !deployment.environments || deployment.environments.includes(isDev ? "development" : "production");
2114
+ if (!isProperEnv) continue;
2115
+ if (options.globalOnly && deployment.global === false) continue;
2116
+ matchedCommands.set(commandName, cmd);
2117
+ }
2118
+ return Array.from(matchedCommands.values()).sort((a, b) => {
2119
+ const commandNameA = "builder" in a ? a.builder.name : a.options.name;
2120
+ const commandNameB = "builder" in b ? b.builder.name : b.options.name;
2121
+ return commandNameA.localeCompare(commandNameB);
2122
+ });
2123
+ }
2124
+ /**
2125
+ * Groups commands by category alphabetically.
2126
+ */
2127
+ sortByCategory() {
2128
+ const categories = /* @__PURE__ */ new Map();
2129
+ for (const cmd of this.commands.values()) {
2130
+ const metadata = cmd.options.metadata;
2131
+ if (!metadata?.category) continue;
2132
+ let entry = categories.get(metadata.category);
2133
+ if (!entry) {
2134
+ entry = {
2135
+ name: metadata.category,
2136
+ emoji: metadata.categoryEmoji,
2137
+ commands: []
2138
+ };
2139
+ categories.set(metadata.category, entry);
1938
2140
  }
1939
- } catch (error) {
1940
- console.error(`[DynaSend] Error with method '${SendMethod[method]}':`, error);
1941
- return null;
2141
+ entry.commands.push(cmd);
1942
2142
  }
2143
+ return Array.from(categories.values()).sort((a, b) => a.name.localeCompare(b.name)).map((cat) => {
2144
+ cat.commands.sort((a, b) => {
2145
+ const commandNameA = "builder" in a ? a.builder.name : a.options.name;
2146
+ const commandNameB = "builder" in b ? b.builder.name : b.options.name;
2147
+ return commandNameA.localeCompare(commandNameB);
2148
+ });
2149
+ return cat;
2150
+ });
1943
2151
  }
1944
- static scheduleDelete(message, delay) {
1945
- if (delay < 1e3) {
1946
- console.warn(`[DynaSend] Delete delay is less than 1 second (${delay}ms). Is this intentional?`);
2152
+ /**
2153
+ * Imports command modules from a directory.
2154
+ * @param dir Path of one or more folders.
2155
+ * @param set Replaces imported command modules with the ones found.
2156
+ */
2157
+ async importFrom(dir, set = false) {
2158
+ if (set) this.commands.clear();
2159
+ const dirs = Array.isArray(dir) ? dir : [dir];
2160
+ const modules = [];
2161
+ for (const _dir of dirs) {
2162
+ const results = await importModulesFromDir(_dir, this.moduleSuffix);
2163
+ modules.push(...results.map(({ module: module2 }) => module2.default));
1947
2164
  }
1948
- setTimeout(async () => {
1949
- try {
1950
- if (message.deletable) {
1951
- await message.delete();
1952
- }
1953
- } catch (error) {
1954
- console.error("[DynaSend] Error deleting message:", error);
1955
- }
1956
- }, delay);
1957
- }
1958
- static async send(handler, options) {
1959
- const sendMethod = options.sendMethod ?? this.detectSendMethod(handler);
1960
- this.validateSendMethod(handler, sendMethod);
1961
- const messageData = this.createMessageData(options, sendMethod);
1962
- const message = await this.executeSend(handler, sendMethod, messageData);
1963
- if (options.deleteAfter && message) {
1964
- this.scheduleDelete(message, options.deleteAfter);
2165
+ for (const module2 of modules) {
2166
+ const commandName = "builder" in module2 ? module2.builder.name : module2.options.name;
2167
+ this.commands.set(commandName, module2);
1965
2168
  }
1966
- return message;
2169
+ let moduleType;
2170
+ switch (this.type) {
2171
+ case 0 /* Slash */:
2172
+ moduleType = "Prefix Commands";
2173
+ break;
2174
+ case 2 /* Context */:
2175
+ moduleType = "Context Commands";
2176
+ break;
2177
+ case 1 /* Prefix */:
2178
+ moduleType = "Prefix Commands";
2179
+ break;
2180
+ }
2181
+ this.client.logger.moduleLoaded(moduleType, modules.length);
2182
+ return this.commands;
1967
2183
  }
1968
2184
  };
1969
- async function dynaSend(handler, options) {
1970
- return DynaSend.send(handler, options);
1971
- }
1972
-
1973
- // src/tools/BetterEmbed.ts
1974
- var BetterEmbed = class _BetterEmbed {
1975
- embed = new import_discord8.EmbedBuilder();
1976
- data;
1977
- config;
1978
- /** A powerful wrapper for `EmbedBuilder` that introduces useful features
1979
- *
1980
- * Auto-shorthand context formatting (_ACF_) is enabled by default
1981
- *
1982
- * All functions utilize _ACF_ unless `BetterEmbed.acf` is set to `false`
1983
- *
1984
- * ___Use a blackslash___ `\` ___to escape any context___
1985
- *
1986
- * \- - - Author Context - - -
1987
- * - __`$USER`__: _author's mention (@xsqu1znt)_
1988
- * - __`$USER_NAME`__: _author's username_
1989
- * - __`$DISPLAY_NAME`__: _author's display name (requires `GuildMember` context)_
1990
- * - __`$USER_AVATAR`__: _author's avatar_
1991
- *
1992
- * \- - - Client Context - - -
1993
- *
1994
- * - __`$BOT_AVATAR`__: _bot's avatar_
1995
- *
1996
- * \- - - Shorthand Context - - -
1997
- * - __`$YEAR`__: _YYYY_
1998
- * - __`$MONTH`__: _MM_
1999
- * - __`$DAY`__: _DD_
2000
- * - __`$year`__: _YY_
2001
- * - __`$month`__: _M or MM_
2002
- * - __`$day`__: _D or DD_ */
2003
- constructor(data = {}) {
2004
- this.config = data.config || globalVimcordToolsConfig;
2005
- this.data = {
2006
- context: data.context || null,
2007
- author: data.author || null,
2008
- title: data.title || null,
2009
- thumbnailUrl: data.thumbnailUrl || null,
2010
- description: data.description || null,
2011
- imageUrl: data.imageUrl || null,
2012
- footer: data.footer || null,
2013
- fields: data.fields || [],
2014
- color: data.color ?? (this.config.devMode ? this.config.embedColorDev : this.config.embedColor),
2015
- timestamp: data.timestamp || null,
2016
- acf: data.acf ?? true
2017
- };
2018
- this.build();
2185
+ var SlashCommandManager = class extends BaseCommandManager {
2186
+ constructor(client) {
2187
+ super(client, 0 /* Slash */, client.config.app.moduleSuffixes.slashCommand);
2019
2188
  }
2020
- build() {
2021
- this.normalizeData();
2022
- this.applyContextFormatting();
2023
- this.configureEmbed();
2189
+ };
2190
+ var ContextCommandManager = class extends BaseCommandManager {
2191
+ constructor(client) {
2192
+ super(client, 2 /* Context */, client.config.app.moduleSuffixes.contextCommand);
2024
2193
  }
2025
- normalizeData() {
2026
- if (typeof this.data.author === "string") {
2027
- this.data.author = { text: this.data.author };
2028
- }
2029
- if (typeof this.data.title === "string") {
2030
- this.data.title = { text: this.data.title };
2194
+ };
2195
+ var PrefixCommandManager = class extends BaseCommandManager {
2196
+ constructor(client) {
2197
+ super(client, 1 /* Prefix */, client.config.app.moduleSuffixes.prefixCommand);
2198
+ }
2199
+ };
2200
+ var CommandManager = class {
2201
+ client;
2202
+ slash;
2203
+ prefix;
2204
+ context;
2205
+ constructor(client) {
2206
+ this.client = client;
2207
+ this.slash = new SlashCommandManager(client);
2208
+ this.prefix = new PrefixCommandManager(client);
2209
+ this.context = new ContextCommandManager(client);
2210
+ }
2211
+ getAllAppCommands(options = {}) {
2212
+ return [...this.slash.getAll(options), ...this.context.getAll(options)];
2213
+ }
2214
+ async registerGlobal(options = {}) {
2215
+ const client = await this.client.waitForReady();
2216
+ if (!client.rest) {
2217
+ console.error(`[CommandManager] \u2716 Failed to register app commands globally: REST is not initialized`);
2218
+ return;
2031
2219
  }
2032
- if (typeof this.data.footer === "string") {
2033
- this.data.footer = { text: this.data.footer };
2220
+ const commands = this.getAllAppCommands(options);
2221
+ if (!commands.length) {
2222
+ console.log("[CommandManager] No commands to register globally");
2223
+ return;
2034
2224
  }
2035
- if (this.data.timestamp === true) {
2036
- this.data.timestamp = Date.now();
2225
+ console.log(`[CommandManager] Registering (${commands.length}) commands globally...`);
2226
+ try {
2227
+ await client.rest.put(import_discord9.Routes.applicationCommands(client.user.id), { body: commands });
2228
+ console.log(`[CommandManager] \u2714 Registered app commands globally`);
2229
+ } catch (err) {
2230
+ console.error(`[CommandManager] \u2716 Failed to register app commands globally`, err);
2037
2231
  }
2038
2232
  }
2039
- getContextUser() {
2040
- const context = this.data.context;
2041
- if (!context) return null;
2042
- return context.user || context.interaction?.member || context.interaction?.user || context.message?.member || context.message?.author || null;
2043
- }
2044
- getContextClient() {
2045
- const context = this.data.context;
2046
- if (!context) return null;
2047
- return context.client || context.interaction?.client || context.message?.client || null;
2233
+ async unregisterGlobal() {
2234
+ const client = await this.client.waitForReady();
2235
+ if (!client.rest) {
2236
+ console.error(`[CommandManager] \u2716 Failed to remove app commands globally: REST is not initialized`);
2237
+ return;
2238
+ }
2239
+ try {
2240
+ await client.rest.put(import_discord9.Routes.applicationCommands(client.user.id), { body: [] });
2241
+ console.log(`[CommandManager] \u2714 Removed app commands globally`);
2242
+ } catch (err) {
2243
+ console.error(`[CommandManager] \u2716 Failed to remove app commands globally`, err);
2244
+ }
2048
2245
  }
2049
- applyContextFormatting(str) {
2050
- if (!this.data.acf) return;
2051
- const user = this.getContextUser();
2052
- const guildMember = user instanceof import_discord8.GuildMember ? user : null;
2053
- const actualUser = guildMember?.user || (user instanceof import_discord8.User ? user : null);
2054
- const client = this.getContextClient();
2055
- const formatString = (str2) => {
2056
- if (!str2 || !str2.includes("$")) return str2;
2057
- return str2.replace(/(?<!\\)\$USER\b/g, actualUser?.toString() || "$USER").replace(/(?<!\\)\$USER_NAME\b/g, actualUser?.username || "$USER_NAME").replace(/(?<!\\)\$USER_AVATAR\b/g, actualUser?.avatarURL() || "$USER_AVATAR").replace(/(?<!\\)\$DISPLAY_NAME\b/g, guildMember?.displayName || "$DISPLAY_NAME").replace(/(?<!\\)\$BOT_AVATAR\b/g, client?.user?.avatarURL() || "$BOT_AVATAR").replace(/(?<!\\)\$INVIS\b/g, "\u200B").replace(/(?<!\\)\$YEAR/g, (/* @__PURE__ */ new Date()).getFullYear().toString()).replace(/(?<!\\)\$MONTH/g, String((/* @__PURE__ */ new Date()).getMonth() + 1).padStart(2, "0")).replace(/(?<!\\)\$DAY/g, String((/* @__PURE__ */ new Date()).getDate()).padStart(2, "0")).replace(/(?<!\\)\$year/g, String((/* @__PURE__ */ new Date()).getFullYear()).slice(-2)).replace(/(?<!\\)\$month/g, String((/* @__PURE__ */ new Date()).getMonth() + 1).padStart(2, "0")).replace(/(?<!\\)\$day/g, String((/* @__PURE__ */ new Date()).getDate()).padStart(2, "0")).replace(/(?<!\\|<)@([0-9]+)(?!>)/g, "<@$1>").replace(/(?<!\\|<)@&([0-9]+)(?!>)/g, "<@&$1>").replace(/(?<!\\|<)#([0-9]+)(?!>)/g, "<#$1>");
2058
- };
2059
- if (str) {
2060
- return formatString(str);
2246
+ async registerGuild(options = {}) {
2247
+ const client = await this.client.waitForReady();
2248
+ if (!client.rest) {
2249
+ console.error(`[CommandManager] \u2716 Failed to register app commands by guild: REST is not initialized`);
2250
+ return;
2061
2251
  }
2062
- if (this.data.author && typeof this.data.author === "object") {
2063
- this.data.author.text = formatString(this.data.author.text);
2064
- if (this.data.author.icon === true && actualUser) {
2065
- this.data.author.icon = actualUser.avatarURL();
2066
- } else if (typeof this.data.author.icon === "string") {
2067
- this.data.author.icon = formatString(this.data.author.icon);
2068
- }
2252
+ const commands = this.getAllAppCommands(options);
2253
+ if (!commands.length) {
2254
+ console.log("[CommandManager] No commands to register by guild");
2255
+ return;
2069
2256
  }
2070
- if (this.data.title && typeof this.data.title === "object") {
2071
- this.data.title.text = formatString(this.data.title.text);
2257
+ const guildIds = options.guilds || client.guilds.cache.map((g) => g.id);
2258
+ console.log(`[CommandManager] Registering (${commands.length}) commands for ${guildIds.length} guilds...`);
2259
+ await Promise.all(
2260
+ guildIds.map(
2261
+ (guildId) => client.rest.put(import_discord9.Routes.applicationGuildCommands(client.user.id, guildId), { body: commands }).then(() => {
2262
+ const gName = client.guilds.cache.get(guildId)?.name || "n/a";
2263
+ console.log(`[CommandManager] \u2714 Set app commands in guild: ${guildId} (${gName})`);
2264
+ }).catch((err) => {
2265
+ const gName = client.guilds.cache.get(guildId)?.name || "n/a";
2266
+ console.log(`[CommandManager] \u2716 Failed to set app commands in guild: ${guildId} (${gName})`, err);
2267
+ })
2268
+ )
2269
+ );
2270
+ }
2271
+ async unregisterGuild(options = {}) {
2272
+ const client = await this.client.waitForReady();
2273
+ if (!client.rest) {
2274
+ console.error(`[CommandManager] \u2716 Failed to register app commands by guild: REST is not initialized`);
2275
+ return;
2072
2276
  }
2073
- if (this.data.description) {
2074
- this.data.description = formatString(
2075
- Array.isArray(this.data.description) ? this.data.description.filter((s) => s !== null && s !== void 0).join("\n") : this.data.description
2277
+ const guildIds = options.guilds || client.guilds.cache.map((g) => g.id);
2278
+ console.log(`[CommandManager] Unregistering commands from ${guildIds.length} guilds...`);
2279
+ await Promise.all(
2280
+ guildIds.map(
2281
+ (guildId) => client.rest.put(import_discord9.Routes.applicationGuildCommands(client.user.id, guildId), { body: [] }).then(() => console.log(`[CommandManager] \u2714 Removed app commands in guild: ${guildId}`)).catch((err) => console.log(`[CommandManager] \u2716 Failed to remove app commands in guild: ${guildId}`, err))
2282
+ )
2283
+ );
2284
+ }
2285
+ };
2286
+
2287
+ // src/modules/event.manager.ts
2288
+ var import_discord10 = require("discord.js");
2289
+ var EventManager = class {
2290
+ client;
2291
+ events = /* @__PURE__ */ new Map();
2292
+ logger;
2293
+ constructor(client) {
2294
+ this.client = client;
2295
+ this.logger = new Logger({ prefixEmoji: "\u{1F4CB}", prefix: `EventManager (i${this.client.clientId})` });
2296
+ for (const event of Object.values(import_discord10.Events)) {
2297
+ client.on(
2298
+ event.toString(),
2299
+ async (...args) => this.executeEvents.apply(this, [event, ...args])
2076
2300
  );
2077
2301
  }
2078
- if (this.data.footer && typeof this.data.footer === "object") {
2079
- this.data.footer.text = formatString(this.data.footer.text);
2080
- }
2081
- if (this.data.thumbnailUrl) {
2082
- this.data.thumbnailUrl = formatString(this.data.thumbnailUrl);
2083
- }
2084
- if (this.data.imageUrl) {
2085
- this.data.imageUrl = formatString(this.data.imageUrl);
2086
- }
2087
- this.data.fields = this.data.fields.filter(Boolean).map((field) => ({
2088
- ...field,
2089
- name: formatString(field.name),
2090
- value: formatString(field.value)
2091
- }));
2092
2302
  }
2093
- configureEmbed() {
2094
- if (this.data.author && typeof this.data.author === "object" && this.data.author.text) {
2095
- try {
2096
- this.embed.setAuthor({
2097
- name: this.data.author.text,
2098
- iconURL: typeof this.data.author.icon === "string" ? this.data.author.icon : void 0,
2099
- url: this.data.author.hyperlink || void 0
2100
- });
2101
- } catch (error) {
2102
- console.error("[BetterEmbed] Invalid author configuration:", error);
2303
+ register(...events) {
2304
+ for (const event of events) {
2305
+ this.events.set(event.name, event);
2306
+ if (this.client.config.app.verbose) {
2307
+ this.logger.debug(`'${event.name}' registered for EventType '${event.event}'`);
2103
2308
  }
2104
2309
  }
2105
- if (this.data.title && typeof this.data.title === "object" && this.data.title.text) {
2106
- try {
2107
- this.embed.setTitle(this.data.title.text);
2108
- if (this.data.title.hyperlink) {
2109
- this.embed.setURL(this.data.title.hyperlink);
2110
- }
2111
- } catch (error) {
2112
- console.error("[BetterEmbed] Invalid title configuration:", error);
2310
+ }
2311
+ unregister(...names) {
2312
+ for (const name of names) {
2313
+ const event = this.events.get(name);
2314
+ if (!event) continue;
2315
+ this.events.delete(name);
2316
+ if (this.client.config.app.verbose) {
2317
+ this.logger.debug(`'${event.name}' unregistered for EventType '${event.event}'`);
2113
2318
  }
2114
2319
  }
2115
- if (this.data.description) {
2116
- this.embed.setDescription(
2117
- Array.isArray(this.data.description) ? this.data.description.join("\n") : this.data.description
2118
- );
2119
- }
2120
- if (this.data.thumbnailUrl) {
2121
- try {
2122
- this.embed.setThumbnail(this.data.thumbnailUrl);
2123
- } catch (error) {
2124
- console.error("[BetterEmbed] Invalid thumbnail URL:", error);
2125
- }
2320
+ }
2321
+ clear() {
2322
+ this.events.forEach((e) => this.unregister(e.name));
2323
+ this.events.clear();
2324
+ }
2325
+ get(name) {
2326
+ return this.events.get(name);
2327
+ }
2328
+ getByTag(tag) {
2329
+ return Array.from(this.events.values()).filter((event) => event.metadata?.tags?.includes(tag));
2330
+ }
2331
+ getByCategory(category) {
2332
+ return Array.from(this.events.values()).filter((event) => event.metadata?.category?.includes(category));
2333
+ }
2334
+ getByEvent(eventType) {
2335
+ return Array.from(this.events.values()).filter((event) => event.event === eventType);
2336
+ }
2337
+ async executeEvents(eventType, ...args) {
2338
+ const events = this.getByEvent(eventType);
2339
+ if (!events.length) return;
2340
+ const sortedEvents = events.sort((a, b) => b.priority - a.priority);
2341
+ await Promise.all(
2342
+ sortedEvents.map(async (event) => {
2343
+ try {
2344
+ await event.execute?.(this.client, ...args);
2345
+ if (event.once) {
2346
+ this.unregister(event.name);
2347
+ }
2348
+ } catch (err) {
2349
+ this.logger.error(`'${event.name}' failed to execute`, err);
2350
+ }
2351
+ })
2352
+ );
2353
+ }
2354
+ /** Import event modules that end with `.event` */
2355
+ async importFrom(dir, replaceAll) {
2356
+ dir = Array.isArray(dir) ? dir : [dir];
2357
+ const eventModules = await Promise.all(
2358
+ dir.map((dir2) => importModulesFromDir(dir2, "event"))
2359
+ );
2360
+ if (replaceAll) {
2361
+ this.clear();
2126
2362
  }
2127
- if (this.data.imageUrl) {
2128
- try {
2129
- this.embed.setImage(this.data.imageUrl);
2130
- } catch (error) {
2131
- console.error("[BetterEmbed] Invalid image URL:", error);
2363
+ let importedEvents = 0;
2364
+ let ignoredEvents = 0;
2365
+ for (const event of eventModules.flat()) {
2366
+ if (!event.module.default.enabled) {
2367
+ ignoredEvents++;
2368
+ } else {
2369
+ importedEvents++;
2132
2370
  }
2371
+ this.register(event.module.default);
2133
2372
  }
2134
- if (this.data.footer && typeof this.data.footer === "object" && this.data.footer.text) {
2135
- try {
2136
- this.embed.setFooter({
2137
- text: this.data.footer.text,
2138
- iconURL: typeof this.data.footer.icon === "string" ? this.data.footer.icon : void 0
2139
- });
2140
- } catch (error) {
2141
- console.error("[BetterEmbed] Invalid footer configuration:", error);
2373
+ this.client.logger.moduleLoaded("Event Handlers", importedEvents, ignoredEvents);
2374
+ return this.events;
2375
+ }
2376
+ };
2377
+
2378
+ // package.json
2379
+ var version = "1.0.31";
2380
+
2381
+ // src/client.ts
2382
+ var import_node_crypto3 = require("crypto");
2383
+ var import_qznt4 = require("qznt");
2384
+
2385
+ // src/utils/VimcordCLI.ts
2386
+ var import_node_readline = require("readline");
2387
+ var import_qznt3 = require("qznt");
2388
+
2389
+ // src/utils/clientUtils.ts
2390
+ function useClient(clientId = 0) {
2391
+ return Vimcord.instances.get(clientId);
2392
+ }
2393
+ async function useReadyClient(clientId = 0) {
2394
+ return useClient(clientId)?.waitForReady();
2395
+ }
2396
+ function createClient(options, features = {}, config = {}) {
2397
+ return new Vimcord(options, features, config);
2398
+ }
2399
+
2400
+ // src/utils/VimcordCLI.ts
2401
+ var VimcordCLI = class {
2402
+ rl;
2403
+ options;
2404
+ commands = /* @__PURE__ */ new Map();
2405
+ logger = new Logger({ prefixEmoji: "\u{1F680}", prefix: "CLI", showTimestamp: false });
2406
+ constructor(options) {
2407
+ this.options = options;
2408
+ this.rl = (0, import_node_readline.createInterface)({
2409
+ input: process.stdin,
2410
+ output: process.stdout,
2411
+ terminal: false
2412
+ });
2413
+ this.rl.on("line", (line) => {
2414
+ const { isCommand, commandName, content, args } = this.parseLine(line);
2415
+ if (!isCommand) return;
2416
+ const command = this.commands.get(commandName);
2417
+ if (!command) {
2418
+ const nearestMatches = Array.from(this.commands.keys()).filter(
2419
+ (cmd) => cmd.toLowerCase().includes(commandName.toLowerCase())
2420
+ );
2421
+ return this.logger.error(
2422
+ `Unknown command '${commandName}'${nearestMatches.length ? `. Did you mean ${nearestMatches.length > 1 ? `[${nearestMatches.map((m) => `'${this.options.prefix}${m}'`).join(", ")}]` : `'${this.options.prefix}${nearestMatches[0]}'`}?` : ""}`
2423
+ );
2142
2424
  }
2425
+ command.fn(args, content);
2426
+ });
2427
+ }
2428
+ parseLine(line) {
2429
+ if (line.startsWith(this.options.prefix)) {
2430
+ line = line.slice(this.options.prefix.length);
2431
+ } else {
2432
+ return { isCommand: false };
2143
2433
  }
2144
- if (this.data.color) {
2145
- try {
2146
- const color = Array.isArray(this.data.color) ? this.data.color[Math.floor(Math.random() * this.data.color.length)] ?? null : this.data.color;
2147
- this.embed.setColor(color);
2148
- } catch (error) {
2149
- console.error("[BetterEmbed] Invalid color:", error);
2434
+ const args = line.split(" ").map((s) => s.trim());
2435
+ const commandName = args.shift();
2436
+ return { isCommand: true, commandName, content: args.join(" "), args };
2437
+ }
2438
+ getClientInstance(line) {
2439
+ const clientIndex = import_qznt3.$.str.getFlag(line, "--client", 1) || import_qznt3.$.str.getFlag(line, "-c", 1);
2440
+ if (clientIndex) {
2441
+ const idx = Number(clientIndex);
2442
+ if (isNaN(idx)) {
2443
+ CLI.logger.error(`'${clientIndex}' is not a valid number`);
2444
+ return void 0;
2150
2445
  }
2151
- }
2152
- if (this.data.timestamp && this.data.timestamp !== true) {
2153
- try {
2154
- this.embed.setTimestamp(this.data.timestamp);
2155
- } catch (error) {
2156
- console.error("[BetterEmbed] Invalid timestamp:", error);
2446
+ const client = useClient(idx);
2447
+ if (!client) {
2448
+ CLI.logger.error("Client instance not found");
2449
+ return void 0;
2157
2450
  }
2158
- }
2159
- if (this.data.fields.length > 0) {
2160
- const validFields = this.data.fields.slice(0, 25);
2161
- if (this.data.fields.length > 25) {
2162
- console.warn("[BetterEmbed] Only first 25 fields will be used (Discord limit)");
2451
+ return client;
2452
+ } else {
2453
+ const client = useClient(0);
2454
+ if (!client) {
2455
+ CLI.logger.error("Client instance not found");
2456
+ return void 0;
2163
2457
  }
2164
- this.embed.setFields(validFields);
2458
+ return client;
2165
2459
  }
2166
2460
  }
2167
- setAuthor(author) {
2168
- this.data.author = author;
2169
- this.build();
2170
- return this;
2171
- }
2172
- setTitle(title) {
2173
- this.data.title = title;
2174
- this.build();
2175
- return this;
2176
- }
2177
- setDescription(description) {
2178
- this.data.description = description;
2179
- this.build();
2180
- return this;
2181
- }
2182
- setThumbnail(url) {
2183
- this.data.thumbnailUrl = url;
2184
- this.build();
2185
- return this;
2186
- }
2187
- setImage(url) {
2188
- this.data.imageUrl = url;
2189
- this.build();
2190
- return this;
2191
- }
2192
- setFooter(footer) {
2193
- this.data.footer = footer;
2194
- this.build();
2195
- return this;
2196
- }
2197
- setColor(color) {
2198
- this.data.color = color;
2199
- this.build();
2200
- return this;
2201
- }
2202
- setTimestamp(timestamp) {
2203
- this.data.timestamp = timestamp;
2204
- this.build();
2205
- return this;
2461
+ addCommand(commandName, description, fn) {
2462
+ this.commands.set(commandName, { description, fn });
2206
2463
  }
2207
- addFields(fields) {
2208
- this.data.fields = [...this.data.fields, ...fields];
2209
- this.build();
2210
- return this;
2464
+ removeCommand(commandName) {
2465
+ if (!this.commands.has(commandName)) return false;
2466
+ this.commands.delete(commandName);
2467
+ return true;
2211
2468
  }
2212
- setFields(fields) {
2213
- this.data.fields = fields;
2214
- this.build();
2215
- return this;
2469
+ };
2470
+ var initCalled = false;
2471
+ var CLI = new VimcordCLI({ prefix: "/" });
2472
+ CLI.addCommand("help", "View information about a command, or the available CLI options", (args) => {
2473
+ const prefix = CLI.options.prefix;
2474
+ const helpList = {};
2475
+ for (const cmd of CLI.commands.entries()) {
2476
+ const commandName = cmd[0];
2477
+ const commandDescription = cmd[1].description;
2478
+ helpList[`${prefix}${commandName}`] = `~ ${commandDescription}`;
2216
2479
  }
2217
- spliceFields(index, deleteCount, ...fields) {
2218
- this.data.fields.splice(index, deleteCount, ...fields);
2219
- this.build();
2220
- return this;
2480
+ CLI.logger.table("(help)", helpList);
2481
+ });
2482
+ CLI.addCommand("register", "Register app commands (slash & context) globally, or per guild", async (args, content) => {
2483
+ const client = CLI.getClientInstance(content);
2484
+ if (!client) return;
2485
+ const mode = args[0]?.toLowerCase() || "";
2486
+ if (!["guild", "global"].includes(mode)) {
2487
+ return CLI.logger.error(`'${mode}' is not a valid option. Your options are [guild|global]`);
2221
2488
  }
2222
- clone(overrides = {}) {
2223
- return new _BetterEmbed({ ...this.data, ...overrides });
2489
+ let guildIds = (import_qznt3.$.str.getFlag(content, "--guilds", 1) || import_qznt3.$.str.getFlag(content, "-g", 1) || "").replaceAll(/["']/g, "").split(" ").filter(Boolean).map((s) => s.replaceAll(",", "").trim());
2490
+ if (!guildIds.length) guildIds = client.guilds.cache.map((g) => g.id);
2491
+ switch (mode) {
2492
+ case "guild":
2493
+ CLI.logger.info("Registering guild commands...");
2494
+ await client.commands.registerGuild({ guilds: guildIds });
2495
+ break;
2496
+ case "global":
2497
+ CLI.logger.info("Registering global commands...");
2498
+ await client.commands.registerGlobal();
2499
+ break;
2224
2500
  }
2225
- toJSON() {
2226
- return this.embed.toJSON();
2501
+ });
2502
+ CLI.addCommand("unregister", "Unregister app commands globally, or per guild", async (args, content) => {
2503
+ const client = CLI.getClientInstance(content);
2504
+ if (!client) return;
2505
+ const mode = args[0]?.toLowerCase() || "";
2506
+ if (!["guild", "global"].includes(mode)) {
2507
+ return CLI.logger.error(`'${mode}' is not a valid option. Your options are [guild|global]`);
2227
2508
  }
2228
- async send(handler, options = {}, overrides) {
2229
- this.build();
2230
- if (options.content && this.data.acf) {
2231
- options.content = this.applyContextFormatting(options.content);
2232
- }
2233
- return await dynaSend(handler, {
2234
- ...options,
2235
- embeds: [
2236
- overrides ? this.clone(overrides) : this,
2237
- ...Array.isArray(options?.embeds) ? options?.embeds : options?.embeds ? [options?.embeds] : []
2238
- ]
2239
- });
2509
+ let guildIds = (import_qznt3.$.str.getFlag(content, "--guilds", 1) || import_qznt3.$.str.getFlag(content, "-g", 1) || "").replaceAll(/["']/g, "").split(" ").filter(Boolean).map((s) => s.replaceAll(",", "").trim());
2510
+ if (!guildIds.length) guildIds = client.guilds.cache.map((g) => g.id);
2511
+ switch (mode) {
2512
+ case "guild":
2513
+ CLI.logger.info("Unregistering guild commands...");
2514
+ await client.commands.unregisterGuild({ guilds: guildIds });
2515
+ break;
2516
+ case "global":
2517
+ CLI.logger.info("Unregistering global commands...");
2518
+ await client.commands.unregisterGlobal();
2519
+ break;
2240
2520
  }
2241
- };
2242
-
2243
- // src/utils/sendCommandErrorEmbed.ts
2244
- async function sendCommandErrorEmbed(client, error, guild, messageOrInteraction) {
2245
- if (!client.features.enableCommandErrorMessage) return null;
2246
- const config = typeof client.features.enableCommandErrorMessage !== "boolean" ? client.features.enableCommandErrorMessage : void 0;
2247
- const buttons = {
2248
- supportServer: new import_discord9.ButtonBuilder({
2249
- url: config?.inviteUrl || client.config.staff.guild.inviteUrl || "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
2250
- // may or may not be a rickroll
2251
- label: config?.inviteButtonLabel || "Support Support",
2252
- style: import_discord9.ButtonStyle.Link
2253
- }),
2254
- details: new import_discord9.ButtonBuilder({
2255
- customId: "btn_details",
2256
- label: config?.detailButtonLabel || "Details",
2257
- style: import_discord9.ButtonStyle.Secondary
2258
- })
2259
- };
2260
- const actionRow = new import_discord9.ActionRowBuilder({
2261
- components: config?.inviteUrl && guild?.id !== (config.inviteUrl || client.config.staff.guild.id) ? [buttons.supportServer, buttons.details] : [buttons.details]
2262
- });
2263
- const embed_error = config?.embed?.(new BetterEmbed(), error, guild) || new BetterEmbed({
2264
- color: "Red",
2265
- title: "Something went wrong",
2266
- description: "If you keep encountering this error, please report it."
2267
- });
2268
- const msg = await embed_error.send(messageOrInteraction, {
2269
- components: [actionRow],
2270
- flags: config?.ephemeral ? "Ephemeral" : void 0,
2271
- deleteAfter: config?.deleteAfter
2272
- });
2273
- if (!msg) return null;
2274
- const collector = msg.createMessageComponentCollector({
2275
- componentType: import_discord9.ComponentType.Button,
2276
- idle: config?.detailButtonIdleTimeout ?? 3e4,
2277
- filter: (i) => i.customId === "btn_details"
2278
- });
2279
- collector.on("collect", (i) => {
2280
- const attachment = new import_discord9.AttachmentBuilder(Buffer.from(`${error.message}
2281
-
2282
- ${error.stack}`), {
2283
- name: "error.txt"
2284
- });
2285
- i.reply({ files: [attachment], flags: "Ephemeral" });
2286
- });
2287
- collector.on("end", () => {
2288
- buttons.details.setDisabled(true);
2289
- embed_error.send(messageOrInteraction, {
2290
- sendMethod: messageOrInteraction instanceof import_discord9.Message ? 5 /* MessageEdit */ : void 0,
2291
- components: [actionRow]
2292
- });
2521
+ });
2522
+ CLI.addCommand("stats", "View statistics about a client instance", (args, content) => {
2523
+ const client = CLI.getClientInstance(content);
2524
+ if (!client) return;
2525
+ CLI.logger.table(`(stats) ~ ${client.config.app.name}`, {
2526
+ "Guilds:": import_qznt3.$.format.number(client.guilds.cache.size),
2527
+ "Ping:": `${client.ws.ping || 0}ms`,
2528
+ "Uptime:": `${import_qznt3.$.math.secs(client.uptime || 0)}s`,
2529
+ "Process Uptime:": `${Math.floor(process.uptime())}s`,
2530
+ "Memory Usage:": `${(process.memoryUsage().rss / 1024 / 1024).toFixed(2)} MB`
2293
2531
  });
2294
- return msg;
2295
- }
2296
-
2297
- // src/utils/async.ts
2298
- async function retryExponentialBackoff(fn, maxRetries = 3, retryDelay = 1e3) {
2299
- let attempts = 0;
2300
- while (true) {
2301
- try {
2302
- return await fn(attempts);
2303
- } catch (error) {
2304
- if (attempts >= maxRetries) throw error;
2305
- await new Promise((resolve) => setTimeout(resolve, Math.pow(1.75, attempts) * retryDelay + Math.random() * 500));
2306
- attempts++;
2532
+ });
2533
+ CLI.addCommand("cmds", "List the loaded commands", async (args, content) => {
2534
+ const client = CLI.getClientInstance(content);
2535
+ if (!client) return;
2536
+ const mode = (args[0] || "slash").toLowerCase();
2537
+ switch (mode) {
2538
+ case "slash": {
2539
+ const commands = Array.from(client.commands.slash.commands.values());
2540
+ commands.sort((a, b) => a.builder.name.localeCompare(b.builder.name));
2541
+ const tableData = {};
2542
+ for (const cmd of commands) {
2543
+ tableData[`/${cmd.builder.name}`] = `~ ${cmd.builder.description || "No description"}`;
2544
+ }
2545
+ return CLI.logger.table(`(cmds) ~ slash (${import_qznt3.$.format.number(commands.length)})`, tableData);
2546
+ }
2547
+ case "prefix": {
2548
+ const commands = Array.from(client.commands.prefix.commands.values());
2549
+ commands.sort((a, b) => {
2550
+ const nameA = a.toConfig().name;
2551
+ const nameB = b.toConfig().name;
2552
+ return nameA.localeCompare(nameB);
2553
+ });
2554
+ const tableData = {};
2555
+ const defaultPrefix = client.config.prefixCommands.defaultPrefix;
2556
+ for (const cmd of commands) {
2557
+ const config = cmd.toConfig();
2558
+ const aliasIndicator = config.aliases?.length ? ` [${config.aliases.join(", ")}]` : "";
2559
+ tableData[`${defaultPrefix}${config.name}${aliasIndicator}`] = `~ ${config.description || "No description"}`;
2560
+ }
2561
+ return CLI.logger.table(`(cmds) ~ prefix (${import_qznt3.$.format.number(commands.length)})`, tableData);
2562
+ }
2563
+ case "ctx": {
2564
+ const commands = Array.from(client.commands.context.commands.values());
2565
+ commands.sort((a, b) => a.builder.name.localeCompare(b.builder.name));
2566
+ const tableData = {};
2567
+ for (const cmd of commands) {
2568
+ const type = cmd.builder.type === 2 ? "User" : "Msg";
2569
+ tableData[`[${type}] ${cmd.builder.name}`] = "";
2570
+ }
2571
+ return CLI.logger.table(`(cmds) ~ ctx (${import_qznt3.$.format.number(commands.length)})`, tableData);
2307
2572
  }
2573
+ default:
2574
+ return CLI.logger.error(`'${mode}' is not a valid option. Valid options: [slash|prefix|ctx]`);
2308
2575
  }
2576
+ });
2577
+ function initCLI() {
2578
+ if (initCalled) return;
2579
+ CLI.logger.log(`~ Type ${CLI.options.prefix}help to view available commands`);
2580
+ initCalled = true;
2309
2581
  }
2310
2582
 
2311
- // package.json
2312
- var version = "1.0.29";
2313
-
2314
2583
  // src/client.ts
2315
- var import_node_crypto3 = require("crypto");
2316
2584
  var import_chalk2 = __toESM(require("chalk"));
2317
- var clientInstances = [];
2318
- var Vimcord = class _Vimcord extends import_discord10.Client {
2585
+ var Vimcord = class _Vimcord extends import_discord11.Client {
2586
+ static instances = /* @__PURE__ */ new Map();
2319
2587
  uuid = (0, import_node_crypto3.randomUUID)();
2320
- clientId = clientInstances.length;
2588
+ clientId = _Vimcord.instances.size;
2321
2589
  clientOptions;
2322
2590
  features;
2323
2591
  config;
@@ -2420,13 +2688,16 @@ var Vimcord = class _Vimcord extends import_discord10.Client {
2420
2688
  this.on("error", (err) => this.logger.error("Client Error", err));
2421
2689
  this.on("shardError", (err) => this.logger.error("Client Shard Error", err));
2422
2690
  }
2423
- this.logger.clientBanner(this);
2691
+ if (!this.config.app.disableBanner === true) {
2692
+ this.logger.clientBanner(this);
2693
+ }
2424
2694
  this.once("clientReady", (client) => {
2425
2695
  this.logger.clientReady(client.user.tag, client.guilds.cache.size);
2426
2696
  });
2427
- clientInstances.push(this);
2697
+ _Vimcord.instances.set(this.clientId, this);
2698
+ initCLI();
2428
2699
  }
2429
- /** Returns the options, features, and config of this client */
2700
+ /** Returns the options, features, and config of this client. */
2430
2701
  toJSON() {
2431
2702
  return {
2432
2703
  options: this.clientOptions,
@@ -2434,7 +2705,7 @@ var Vimcord = class _Vimcord extends import_discord10.Client {
2434
2705
  config: this.config
2435
2706
  };
2436
2707
  }
2437
- /** Make a clone of this client */
2708
+ /** Makes a clone of this client. */
2438
2709
  clone() {
2439
2710
  const { options, features, config } = this.toJSON();
2440
2711
  return new _Vimcord(options, features, config);
@@ -2450,31 +2721,31 @@ var Vimcord = class _Vimcord extends import_discord10.Client {
2450
2721
  this.config.staff = createVimcordStaffConfig(options);
2451
2722
  return this;
2452
2723
  }
2453
- configureSlashCommands(options) {
2724
+ configureSlashCommands(options = {}) {
2454
2725
  this.config.slashCommands = createVimcordSlashCommandConfig(options);
2455
2726
  return this;
2456
2727
  }
2457
- configurePrefixCommands(options) {
2728
+ configurePrefixCommands(options = {}) {
2458
2729
  this.config.prefixCommands = createVimcordPrefixCommandConfig(options);
2459
2730
  return this;
2460
2731
  }
2461
- configureContextCommands(options) {
2732
+ configureContextCommands(options = {}) {
2462
2733
  this.config.contextCommands = createVimcordContextCommandConfig(options);
2463
2734
  return this;
2464
2735
  }
2465
- async addEventModules(dir, replaceAll) {
2736
+ async importEventModules(dir, replaceAll) {
2466
2737
  await this.events.importFrom(dir, replaceAll);
2467
2738
  return this;
2468
2739
  }
2469
- async addSlashCommandModules(dir, replaceAll) {
2740
+ async importSlashCommandModules(dir, replaceAll) {
2470
2741
  await this.commands.slash.importFrom(dir, replaceAll);
2471
2742
  return this;
2472
2743
  }
2473
- async addPrefixCommandModules(dir, replaceAll) {
2744
+ async importPrefixCommandModules(dir, replaceAll) {
2474
2745
  await this.commands.prefix.importFrom(dir, replaceAll);
2475
2746
  return this;
2476
2747
  }
2477
- async addContextCommandModules(dir, replaceAll) {
2748
+ async importContextCommandModules(dir, replaceAll) {
2478
2749
  await this.commands.context.importFrom(dir, replaceAll);
2479
2750
  return this;
2480
2751
  }
@@ -2483,10 +2754,13 @@ var Vimcord = class _Vimcord extends import_discord10.Client {
2483
2754
  this.logger.database("Using", db.moduleName);
2484
2755
  return this.db.connect();
2485
2756
  }
2486
- async whenReady() {
2757
+ async waitForReady() {
2487
2758
  if (this.isReady()) return this;
2488
2759
  return new Promise((resolve, reject) => {
2489
- const timeout = setTimeout(() => reject(new Error("Client is not ready")), 45e3);
2760
+ const timeout = setTimeout(
2761
+ () => reject(new Error(`Client (i${this.clientId}) timed out waiting for ready`)),
2762
+ 6e4
2763
+ );
2490
2764
  this.once("clientReady", () => {
2491
2765
  clearTimeout(timeout);
2492
2766
  resolve(this);
@@ -2502,20 +2776,20 @@ var Vimcord = class _Vimcord extends import_discord10.Client {
2502
2776
  if (this.features.importModules) {
2503
2777
  const importModules = this.features.importModules;
2504
2778
  await Promise.all([
2505
- importModules.events && this.addEventModules(importModules.events),
2506
- importModules.slashCommands && this.addSlashCommandModules(importModules.slashCommands),
2507
- importModules.prefixCommands && this.addPrefixCommandModules(importModules.prefixCommands),
2508
- importModules.contextCommands && this.addContextCommandModules(importModules.contextCommands)
2779
+ importModules.events && this.importEventModules(importModules.events),
2780
+ importModules.slashCommands && this.importSlashCommandModules(importModules.slashCommands),
2781
+ importModules.prefixCommands && this.importPrefixCommandModules(importModules.prefixCommands),
2782
+ importModules.contextCommands && this.importContextCommandModules(importModules.contextCommands)
2509
2783
  ]);
2510
2784
  }
2511
2785
  if (this.features.useDefaultSlashCommandHandler) {
2512
- this.events.register(defaultSlashCommandHandler);
2513
- }
2514
- if (this.features.useDefaultPrefixCommandHandler) {
2515
- this.events.register(defaultPrefixCommandHandler);
2786
+ this.events.register(BUILTIN_SlashCommandHandler);
2516
2787
  }
2517
2788
  if (this.features.useDefaultContextCommandHandler) {
2518
- this.events.register(defaultContextCommandHandler);
2789
+ this.events.register(BUILTIN_ContextCommandHandler);
2790
+ }
2791
+ if (this.features.useDefaultPrefixCommandHandler) {
2792
+ this.events.register(BUILTIN_PrefixCommandHandler);
2519
2793
  }
2520
2794
  return this;
2521
2795
  }
@@ -2537,131 +2811,44 @@ var Vimcord = class _Vimcord extends import_discord10.Client {
2537
2811
  await preHook?.(this);
2538
2812
  }
2539
2813
  const stopLoader = this.logger.loader("Connecting to Discord...");
2540
- const loginResult = await retryExponentialBackoff(
2541
- () => super.login(token),
2542
- this.features.loginAttempts ?? 3,
2543
- 1e3
2544
- );
2814
+ const loginResult = await import_qznt4.$.async.retry(() => super.login(token), this.features.loginAttempts ?? 3, 1e3);
2545
2815
  stopLoader("Connected to Discord ");
2546
2816
  this.config.app.verbose && this.logger.debug("\u23F3 Waiting for ready...");
2547
2817
  return loginResult;
2548
2818
  } catch (err) {
2549
- this.logger.error(
2550
- `Failed to log into Discord after ${this.features.loginAttempts} attempt(s))`,
2551
- err
2552
- );
2553
- return null;
2554
- } finally {
2555
- this.clientStartingPromise = null;
2556
- }
2557
- };
2558
- this.clientStartingPromise = main();
2559
- return this.clientStartingPromise;
2560
- }
2561
- async kill() {
2562
- await super.destroy();
2563
- const idx = clientInstances.indexOf(this);
2564
- if (idx >= 0) clientInstances.splice(idx, 1);
2565
- this.logger.debug("\u{1F6AA} Logged out of Discord");
2566
- }
2567
- /** Shortcut for {@link fetchUser tools.fetchUser} */
2568
- async fetchUser(id) {
2569
- const client = await this.whenReady();
2570
- return fetchUser(client, id);
2571
- }
2572
- /** Shortcut for {@link fetchGuild tools.fetchGuild} */
2573
- async fetchGuild(id) {
2574
- const client = await this.whenReady();
2575
- return fetchGuild(client, id);
2576
- }
2577
- };
2578
- var defaultPrefixCommandHandler = new EventBuilder({
2579
- event: "messageCreate",
2580
- name: "PrefixCommandHandler",
2581
- async execute(client, message) {
2582
- if (message.author.bot || !message.guild) return;
2583
- const config = client.config.prefixCommands;
2584
- let activePrefix = config.defaultPrefix;
2585
- if (config.guildPrefixResolver) {
2586
- try {
2587
- const customPrefix = await config.guildPrefixResolver(client, message.guild.id);
2588
- if (customPrefix) activePrefix = customPrefix;
2589
- } catch (err) {
2590
- client.logger.error(`Error in guildPrefixResolver for guild ${message.guild.id}:`, err);
2591
- }
2592
- }
2593
- let prefixUsed;
2594
- if (message.content.startsWith(activePrefix)) {
2595
- prefixUsed = activePrefix;
2596
- } else if (config.allowMentionAsPrefix) {
2597
- const mention = (0, import_discord10.userMention)(client.user.id);
2598
- if (message.content.startsWith(mention)) {
2599
- prefixUsed = message.content.startsWith(`${mention} `) ? `${mention} ` : mention;
2600
- }
2601
- }
2602
- if (!prefixUsed) return;
2603
- const contentWithoutPrefix = message.content.slice(prefixUsed.length).trim();
2604
- const args = contentWithoutPrefix.split(/\s+/);
2605
- const trigger = args.shift();
2606
- if (!trigger) return;
2607
- const command = client.commands.prefix.get(trigger);
2608
- if (!command) return;
2609
- message.content = args.join(" ");
2610
- try {
2611
- return await command.run(client, client, message);
2612
- } catch (err) {
2613
- await sendCommandErrorEmbed(client, err, message.guild, message);
2614
- throw err;
2615
- }
2616
- }
2617
- });
2618
- var defaultSlashCommandHandler = new EventBuilder({
2619
- event: "interactionCreate",
2620
- name: "SlashCommandHandler",
2621
- async execute(client, interaction) {
2622
- if (!interaction.isChatInputCommand()) return;
2623
- const command = client.commands.slash.get(interaction.commandName);
2624
- if (!command) {
2625
- const content = `**/\`${interaction.commandName}\`** is not a registered command.`;
2626
- if (interaction.replied || interaction.deferred) {
2627
- return interaction.followUp({ content, flags: "Ephemeral" });
2819
+ this.logger.error(
2820
+ `Failed to log into Discord after ${this.features.loginAttempts} attempt(s))`,
2821
+ err
2822
+ );
2823
+ return null;
2824
+ } finally {
2825
+ this.clientStartingPromise = null;
2628
2826
  }
2629
- return interaction.reply({ content, flags: "Ephemeral" });
2630
- }
2631
- try {
2632
- return await command.run(client, client, interaction);
2633
- } catch (err) {
2634
- await sendCommandErrorEmbed(client, err, interaction.guild, interaction);
2635
- throw err;
2636
- }
2827
+ };
2828
+ this.clientStartingPromise = main();
2829
+ return this.clientStartingPromise;
2637
2830
  }
2638
- });
2639
- var defaultContextCommandHandler = new EventBuilder({
2640
- event: "interactionCreate",
2641
- name: "ContextCommandHandler",
2642
- async execute(client, interaction) {
2643
- if (!interaction.isContextMenuCommand()) return;
2644
- const command = client.commands.context.get(interaction.commandName);
2645
- if (!command) {
2646
- const content = `**${interaction.commandName}** is not a registered context command.`;
2647
- if (interaction.replied || interaction.deferred) {
2648
- return interaction.followUp({ content, flags: "Ephemeral" });
2649
- }
2650
- return interaction.reply({ content, flags: "Ephemeral" });
2651
- }
2652
- try {
2653
- return await command.run(client, client, interaction);
2654
- } catch (err) {
2655
- await sendCommandErrorEmbed(client, err, interaction.guild, interaction);
2656
- throw err;
2657
- }
2831
+ async kill() {
2832
+ await super.destroy();
2833
+ _Vimcord.instances.delete(this.clientId);
2834
+ this.logger.debug("\u{1F6AA} Logged out of Discord");
2658
2835
  }
2659
- });
2836
+ /** Shortcut for {@link fetchUser tools.fetchUser} */
2837
+ async fetchUser(id) {
2838
+ const client = await this.waitForReady();
2839
+ return fetchUser(client, id);
2840
+ }
2841
+ /** Shortcut for {@link fetchGuild tools.fetchGuild} */
2842
+ async fetchGuild(id) {
2843
+ const client = await this.waitForReady();
2844
+ return fetchGuild(client, id);
2845
+ }
2846
+ };
2660
2847
 
2661
2848
  // src/modules/db/mongo/mongo.ts
2662
2849
  var import_mongoose = __toESM(require("mongoose"));
2663
2850
  var import_node_events2 = __toESM(require("events"));
2664
- var import_qznt3 = require("qznt");
2851
+ var import_qznt5 = require("qznt");
2665
2852
  try {
2666
2853
  import("mongoose");
2667
2854
  } catch {
@@ -2754,7 +2941,7 @@ var MongoDatabase = class _MongoDatabase {
2754
2941
  this.isConnecting = true;
2755
2942
  try {
2756
2943
  const stopLoader = this.client.logger.loader("Connecting to MongoDB...");
2757
- await import_qznt3.$.async.retry(
2944
+ await import_qznt5.$.async.retry(
2758
2945
  () => this.mongoose.connect(connectionUri, { autoIndex: true, ...connectionOptions }),
2759
2946
  maxRetries
2760
2947
  );
@@ -2791,7 +2978,7 @@ var MongoDatabase = class _MongoDatabase {
2791
2978
  // src/modules/db/mongo/mongoSchema.builder.ts
2792
2979
  var import_mongoose2 = require("mongoose");
2793
2980
  var import_node_crypto4 = require("crypto");
2794
- var import_qznt4 = require("qznt");
2981
+ var import_qznt6 = require("qznt");
2795
2982
  try {
2796
2983
  import("mongoose");
2797
2984
  } catch {
@@ -2877,7 +3064,7 @@ var MongoSchemaBuilder = class _MongoSchemaBuilder {
2877
3064
  * @param maxRetries [default: 3]
2878
3065
  */
2879
3066
  async execute(fn, maxRetries = 3) {
2880
- return await import_qznt4.$.async.retry(async () => {
3067
+ return await import_qznt6.$.async.retry(async () => {
2881
3068
  const model = await this.getModel();
2882
3069
  return await fn(model);
2883
3070
  }, maxRetries);
@@ -3166,9 +3353,9 @@ var BetterCollector = class _BetterCollector {
3166
3353
  };
3167
3354
 
3168
3355
  // src/tools/BetterContainer.ts
3169
- var import_discord11 = require("discord.js");
3356
+ var import_discord12 = require("discord.js");
3170
3357
  var BetterContainer = class {
3171
- container = new import_discord11.ContainerBuilder();
3358
+ container = new import_discord12.ContainerBuilder();
3172
3359
  data;
3173
3360
  config;
3174
3361
  constructor(data = {}) {
@@ -3236,8 +3423,8 @@ var BetterContainer = class {
3236
3423
  )
3237
3424
  );
3238
3425
  }
3239
- if (data.thumbnail) sb.setThumbnailAccessory(new import_discord11.ThumbnailBuilder(data.thumbnail));
3240
- if (data.button) sb.setButtonAccessory(new import_discord11.ButtonBuilder(data.button));
3426
+ if (data.thumbnail) sb.setThumbnailAccessory(new import_discord12.ThumbnailBuilder(data.thumbnail));
3427
+ if (data.button) sb.setButtonAccessory(new import_discord12.ButtonBuilder(data.button));
3241
3428
  return sb;
3242
3429
  });
3243
3430
  return this;
@@ -3261,11 +3448,8 @@ var BetterContainer = class {
3261
3448
  };
3262
3449
 
3263
3450
  // src/tools/BetterModal.ts
3264
- var import_discord12 = require("discord.js");
3265
- function randomCharString(length) {
3266
- const chars = "ABCDEFGHJKLMOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
3267
- return Array.from({ length }, () => chars.charAt(Math.floor(Math.random() * chars.length))).join("");
3268
- }
3451
+ var import_discord13 = require("discord.js");
3452
+ var import_qznt7 = require("qznt");
3269
3453
  var BetterModal = class {
3270
3454
  id;
3271
3455
  options;
@@ -3275,7 +3459,7 @@ var BetterModal = class {
3275
3459
  constructor(options = {}) {
3276
3460
  this.id = options.id || this.createModalId();
3277
3461
  this.options = options;
3278
- this.modal = new import_discord12.ModalBuilder().setCustomId(this.id);
3462
+ this.modal = new import_discord13.ModalBuilder().setCustomId(this.id);
3279
3463
  this.config = options.config || globalVimcordToolsConfig;
3280
3464
  if (options.title) {
3281
3465
  this.setTitle(options.title);
@@ -3285,10 +3469,10 @@ var BetterModal = class {
3285
3469
  }
3286
3470
  }
3287
3471
  createModalId() {
3288
- return `modal:${randomCharString(10)}-${Date.now()}`;
3472
+ return `modal:${import_qznt7.$.rnd.str(10, "alpha", { casing: "mixed" })}-${Date.now()}`;
3289
3473
  }
3290
3474
  createComponentId() {
3291
- return `modal-component:${randomCharString(4)}-${Date.now().toString().slice(-4)}`;
3475
+ return `modal-component:${this.id}-${import_qznt7.$.rnd.str(4, "alpha", { casing: "mixed" })}-${Date.now().toString().slice(-4)}`;
3292
3476
  }
3293
3477
  validateComponentLength() {
3294
3478
  if (this.components.size >= 5) throw new Error("Modal can only have 5 components");
@@ -3333,9 +3517,9 @@ var BetterModal = class {
3333
3517
  this.validateComponentLength();
3334
3518
  let { label, description, custom_id, ...rest } = data;
3335
3519
  custom_id ||= this.createComponentId();
3336
- const textInputComponent = new import_discord12.TextInputBuilder(rest).setCustomId(custom_id);
3337
- if (!rest.style) textInputComponent.setStyle(import_discord12.TextInputStyle.Short);
3338
- const labelComponent = new import_discord12.LabelBuilder().setLabel(label).setTextInputComponent(textInputComponent);
3520
+ const textInputComponent = new import_discord13.TextInputBuilder(rest).setCustomId(custom_id);
3521
+ if (!rest.style) textInputComponent.setStyle(import_discord13.TextInputStyle.Short);
3522
+ const labelComponent = new import_discord13.LabelBuilder().setLabel(label).setTextInputComponent(textInputComponent);
3339
3523
  if (description) labelComponent.setDescription(description);
3340
3524
  this.components.set(custom_id, labelComponent);
3341
3525
  return this;
@@ -3344,8 +3528,8 @@ var BetterModal = class {
3344
3528
  this.validateComponentLength();
3345
3529
  let { label, description, custom_id, ...rest } = data;
3346
3530
  custom_id ||= this.createComponentId();
3347
- const stringSelectComponent = new import_discord12.StringSelectMenuBuilder(rest).setCustomId(custom_id);
3348
- const labelComponent = new import_discord12.LabelBuilder().setLabel(label).setStringSelectMenuComponent(stringSelectComponent);
3531
+ const stringSelectComponent = new import_discord13.StringSelectMenuBuilder(rest).setCustomId(custom_id);
3532
+ const labelComponent = new import_discord13.LabelBuilder().setLabel(label).setStringSelectMenuComponent(stringSelectComponent);
3349
3533
  if (description) labelComponent.setDescription(description);
3350
3534
  this.components.set(custom_id, labelComponent);
3351
3535
  return this;
@@ -3354,8 +3538,8 @@ var BetterModal = class {
3354
3538
  this.validateComponentLength();
3355
3539
  let { label, description, custom_id, ...rest } = data;
3356
3540
  custom_id ||= this.createComponentId();
3357
- const channelSelectComponent = new import_discord12.ChannelSelectMenuBuilder(rest).setCustomId(custom_id);
3358
- const labelComponent = new import_discord12.LabelBuilder().setLabel(label).setChannelSelectMenuComponent(channelSelectComponent);
3541
+ const channelSelectComponent = new import_discord13.ChannelSelectMenuBuilder(rest).setCustomId(custom_id);
3542
+ const labelComponent = new import_discord13.LabelBuilder().setLabel(label).setChannelSelectMenuComponent(channelSelectComponent);
3359
3543
  if (description) labelComponent.setDescription(description);
3360
3544
  this.components.set(custom_id, labelComponent);
3361
3545
  return this;
@@ -3364,8 +3548,8 @@ var BetterModal = class {
3364
3548
  this.validateComponentLength();
3365
3549
  let { label, description, custom_id, ...rest } = data;
3366
3550
  custom_id ||= this.createComponentId();
3367
- const userSelectComponent = new import_discord12.UserSelectMenuBuilder(rest).setCustomId(custom_id);
3368
- const labelComponent = new import_discord12.LabelBuilder().setLabel(label).setUserSelectMenuComponent(userSelectComponent);
3551
+ const userSelectComponent = new import_discord13.UserSelectMenuBuilder(rest).setCustomId(custom_id);
3552
+ const labelComponent = new import_discord13.LabelBuilder().setLabel(label).setUserSelectMenuComponent(userSelectComponent);
3369
3553
  if (description) labelComponent.setDescription(description);
3370
3554
  this.components.set(custom_id, labelComponent);
3371
3555
  return this;
@@ -3374,8 +3558,8 @@ var BetterModal = class {
3374
3558
  this.validateComponentLength();
3375
3559
  let { label, description, custom_id, ...rest } = data;
3376
3560
  custom_id ||= this.createComponentId();
3377
- const roleSelectComponent = new import_discord12.RoleSelectMenuBuilder(rest).setCustomId(custom_id);
3378
- const labelComponent = new import_discord12.LabelBuilder().setLabel(label).setRoleSelectMenuComponent(roleSelectComponent);
3561
+ const roleSelectComponent = new import_discord13.RoleSelectMenuBuilder(rest).setCustomId(custom_id);
3562
+ const labelComponent = new import_discord13.LabelBuilder().setLabel(label).setRoleSelectMenuComponent(roleSelectComponent);
3379
3563
  if (description) labelComponent.setDescription(description);
3380
3564
  this.components.set(custom_id, labelComponent);
3381
3565
  return this;
@@ -3384,8 +3568,8 @@ var BetterModal = class {
3384
3568
  this.validateComponentLength();
3385
3569
  let { label, description, custom_id, ...rest } = data;
3386
3570
  custom_id ||= this.createComponentId();
3387
- const mentionableSelectComponent = new import_discord12.MentionableSelectMenuBuilder(rest).setCustomId(custom_id);
3388
- const labelComponent = new import_discord12.LabelBuilder().setLabel(label).setMentionableSelectMenuComponent(mentionableSelectComponent);
3571
+ const mentionableSelectComponent = new import_discord13.MentionableSelectMenuBuilder(rest).setCustomId(custom_id);
3572
+ const labelComponent = new import_discord13.LabelBuilder().setLabel(label).setMentionableSelectMenuComponent(mentionableSelectComponent);
3389
3573
  if (description) labelComponent.setDescription(description);
3390
3574
  this.components.set(custom_id, labelComponent);
3391
3575
  return this;
@@ -3394,13 +3578,16 @@ var BetterModal = class {
3394
3578
  this.validateComponentLength();
3395
3579
  let { label, description, custom_id, ...rest } = data;
3396
3580
  custom_id ||= this.createComponentId();
3397
- const fileUploadComponent = new import_discord12.FileUploadBuilder(rest).setCustomId(custom_id);
3398
- const labelComponent = new import_discord12.LabelBuilder().setLabel(label).setFileUploadComponent(fileUploadComponent);
3581
+ const fileUploadComponent = new import_discord13.FileUploadBuilder(rest).setCustomId(custom_id);
3582
+ const labelComponent = new import_discord13.LabelBuilder().setLabel(label).setFileUploadComponent(fileUploadComponent);
3399
3583
  if (description) labelComponent.setDescription(description);
3400
3584
  this.components.set(custom_id, labelComponent);
3401
3585
  return this;
3402
3586
  }
3403
- /** Show the modal via interaction */
3587
+ /**
3588
+ * Shows the modal via interaction.
3589
+ * @param interaction The interaction used to show the modal
3590
+ */
3404
3591
  async show(interaction) {
3405
3592
  if (!("showModal" in interaction)) throw new Error("Interaction does not support showing modals");
3406
3593
  if (!this.modal.data.title) throw new Error("Modal must have a title");
@@ -3409,18 +3596,22 @@ var BetterModal = class {
3409
3596
  console.error("Modal failed to send", err);
3410
3597
  });
3411
3598
  }
3412
- /** Waits for the modal to be submitted and returns the component data
3599
+ /**
3600
+ * Waits for the modal to be submitted and returns the component data.
3413
3601
  * @param interaction The interaction used to show the modal
3414
3602
  * @param options Options */
3415
3603
  async awaitSubmit(interaction, options) {
3416
3604
  if (!("showModal" in interaction)) throw new Error("Interaction does not support showing modals");
3417
3605
  try {
3418
3606
  const modalSubmit = await interaction.awaitModalSubmit({
3419
- time: this.config.timeouts.modalSubmit,
3420
- ...options,
3421
- filter: (i) => i.customId === this.id
3607
+ filter: (i) => i.customId === this.id,
3608
+ time: options?.timeout ?? this.config.timeouts.modalSubmit,
3609
+ ...options
3422
3610
  });
3423
- const fields = {};
3611
+ if (options?.autoDefer) {
3612
+ await modalSubmit.deferUpdate();
3613
+ }
3614
+ const fields = /* @__PURE__ */ new Map();
3424
3615
  const values = [];
3425
3616
  for (const [customId] of this.components) {
3426
3617
  let value = null;
@@ -3435,23 +3626,38 @@ var BetterModal = class {
3435
3626
  } catch {
3436
3627
  }
3437
3628
  }
3438
- fields[customId] = value;
3629
+ fields.set(customId, value);
3439
3630
  values.push(value);
3440
3631
  }
3441
- return { fields, values, interaction: modalSubmit };
3632
+ return {
3633
+ getField(customId, required) {
3634
+ const value = fields.get(customId);
3635
+ if (required && value === void 0) {
3636
+ throw new Error(`ModalSubmitResult: Field ${customId} is required but was not found`);
3637
+ }
3638
+ return value;
3639
+ },
3640
+ values,
3641
+ interaction: modalSubmit,
3642
+ reply: (options2) => dynaSend(modalSubmit, options2),
3643
+ deferUpdate: async (options2) => await modalSubmit.deferUpdate(options2)
3644
+ };
3442
3645
  } catch (error) {
3443
3646
  return null;
3444
3647
  }
3445
3648
  }
3649
+ /**
3650
+ * Shows the modal and waits for the modal to be submitted, returning the component data.
3651
+ * @param interaction The interaction used to show the modal
3652
+ * @param options Options */
3446
3653
  async showAndAwait(interaction, options) {
3447
- if (!("showModal" in interaction)) throw new Error("Interaction does not support showing modals");
3448
3654
  await this.show(interaction);
3449
3655
  return this.awaitSubmit(interaction, options);
3450
3656
  }
3451
3657
  };
3452
3658
 
3453
3659
  // src/tools/Paginator.ts
3454
- var import_discord13 = require("discord.js");
3660
+ var import_discord14 = require("discord.js");
3455
3661
  var import_node_events3 = __toESM(require("events"));
3456
3662
  var PaginationType = /* @__PURE__ */ ((PaginationType2) => {
3457
3663
  PaginationType2[PaginationType2["Short"] = 0] = "Short";
@@ -3472,7 +3678,7 @@ function wrapPositive(num, max) {
3472
3678
  }
3473
3679
  function createNavButton(id, config) {
3474
3680
  const data = config.paginator.buttons[id];
3475
- const btn = new import_discord13.ButtonBuilder({ customId: `btn_${id}`, style: import_discord13.ButtonStyle.Secondary });
3681
+ const btn = new import_discord14.ButtonBuilder({ customId: `btn_${id}`, style: import_discord14.ButtonStyle.Secondary });
3476
3682
  if (data.label) {
3477
3683
  btn.setLabel(data.label);
3478
3684
  } else {
@@ -3481,7 +3687,7 @@ function createNavButton(id, config) {
3481
3687
  return btn;
3482
3688
  }
3483
3689
  function isEmbed(item) {
3484
- return item instanceof import_discord13.EmbedBuilder || item instanceof BetterEmbed;
3690
+ return item instanceof import_discord14.EmbedBuilder || item instanceof BetterEmbed;
3485
3691
  }
3486
3692
  function resolvePages(pages) {
3487
3693
  if (Array.isArray(pages)) {
@@ -3518,7 +3724,7 @@ var Paginator = class {
3518
3724
  navigation: { reactions: [], isRequired: false, isLong: false, canJump: false },
3519
3725
  collectors: { component: null, reaction: null },
3520
3726
  components: {
3521
- chapterSelect: new import_discord13.StringSelectMenuBuilder({ customId: "ssm_chapterSelect" }),
3727
+ chapterSelect: new import_discord14.StringSelectMenuBuilder({ customId: "ssm_chapterSelect" }),
3522
3728
  navigation: {
3523
3729
  first: createNavButton("first", this.config),
3524
3730
  back: createNavButton("back", this.config),
@@ -3527,8 +3733,8 @@ var Paginator = class {
3527
3733
  last: createNavButton("last", this.config)
3528
3734
  },
3529
3735
  actionRows: {
3530
- chapterSelect: new import_discord13.ActionRowBuilder(),
3531
- navigation: new import_discord13.ActionRowBuilder()
3736
+ chapterSelect: new import_discord14.ActionRowBuilder(),
3737
+ navigation: new import_discord14.ActionRowBuilder()
3532
3738
  }
3533
3739
  }
3534
3740
  };
@@ -3628,9 +3834,9 @@ var Paginator = class {
3628
3834
  sendOptions.content = page;
3629
3835
  } else if (isEmbed(page)) {
3630
3836
  sendOptions.embeds.push(page);
3631
- } else if (page instanceof import_discord13.AttachmentBuilder) {
3837
+ } else if (page instanceof import_discord14.AttachmentBuilder) {
3632
3838
  sendOptions.files.push(page);
3633
- } else if (page instanceof import_discord13.ContainerBuilder || page instanceof BetterContainer) {
3839
+ } else if (page instanceof import_discord14.ContainerBuilder || page instanceof BetterContainer) {
3634
3840
  sendOptions.components.push(page);
3635
3841
  if (!sendOptions.flags.includes("IsComponentsV2")) {
3636
3842
  sendOptions.flags.push("IsComponentsV2");
@@ -3653,20 +3859,20 @@ var Paginator = class {
3653
3859
  }
3654
3860
  return component;
3655
3861
  });
3656
- const disabledNavRow = import_discord13.ActionRowBuilder.from(this.data.components.actionRows.navigation).setComponents(
3862
+ const disabledNavRow = import_discord14.ActionRowBuilder.from(this.data.components.actionRows.navigation).setComponents(
3657
3863
  disabledNavComponents
3658
3864
  );
3659
3865
  const newComponents = [];
3660
3866
  const currentPage = this.data.page.current;
3661
- if (currentPage instanceof import_discord13.ContainerBuilder || currentPage instanceof BetterContainer) {
3867
+ if (currentPage instanceof import_discord14.ContainerBuilder || currentPage instanceof BetterContainer) {
3662
3868
  newComponents.push(currentPage);
3663
3869
  }
3664
3870
  if (this.chapters.length > 1) {
3665
- const disabledSelect = import_discord13.StringSelectMenuBuilder.from(this.data.components.chapterSelect).setDisabled(
3871
+ const disabledSelect = import_discord14.StringSelectMenuBuilder.from(this.data.components.chapterSelect).setDisabled(
3666
3872
  true
3667
3873
  );
3668
3874
  newComponents.push(
3669
- import_discord13.ActionRowBuilder.from(this.data.components.actionRows.chapterSelect).setComponents(disabledSelect)
3875
+ import_discord14.ActionRowBuilder.from(this.data.components.actionRows.chapterSelect).setComponents(disabledSelect)
3670
3876
  );
3671
3877
  }
3672
3878
  if (disabledNavRow.components.length > 0) {
@@ -3695,7 +3901,7 @@ var Paginator = class {
3695
3901
  if (this.options.useReactions) {
3696
3902
  await this.data.message.reactions.removeAll().catch(Boolean);
3697
3903
  } else {
3698
- const newComponents = this.data.message.components.filter((c) => c.type !== import_discord13.ComponentType.Container);
3904
+ const newComponents = this.data.message.components.filter((c) => c.type !== import_discord14.ComponentType.Container);
3699
3905
  await this.data.message.edit({ components: newComponents }).catch(Boolean);
3700
3906
  }
3701
3907
  }
@@ -3906,7 +4112,7 @@ var Paginator = class {
3906
4112
  };
3907
4113
 
3908
4114
  // src/tools/Prompt.ts
3909
- var import_discord14 = require("discord.js");
4115
+ var import_discord15 = require("discord.js");
3910
4116
  var PromptResolveType = /* @__PURE__ */ ((PromptResolveType2) => {
3911
4117
  PromptResolveType2[PromptResolveType2["DisableComponents"] = 0] = "DisableComponents";
3912
4118
  PromptResolveType2[PromptResolveType2["ClearComponents"] = 1] = "ClearComponents";
@@ -3949,13 +4155,13 @@ var Prompt = class {
3949
4155
  buttonOptions?.confirm,
3950
4156
  "btn_confirm",
3951
4157
  this.config.prompt.confirmLabel,
3952
- import_discord14.ButtonStyle.Success
4158
+ import_discord15.ButtonStyle.Success
3953
4159
  );
3954
4160
  const reject = this.buildButton(
3955
4161
  buttonOptions?.reject,
3956
4162
  "btn_reject",
3957
4163
  this.config.prompt.rejectLabel,
3958
- import_discord14.ButtonStyle.Danger
4164
+ import_discord15.ButtonStyle.Danger
3959
4165
  );
3960
4166
  return { confirm, reject };
3961
4167
  }
@@ -3963,19 +4169,19 @@ var Prompt = class {
3963
4169
  const map = /* @__PURE__ */ new Map();
3964
4170
  if (!customOptions) return map;
3965
4171
  for (const [customId, { builder, handler, index = 2 }] of Object.entries(customOptions)) {
3966
- const button = this.buildButton(builder, customId, customId, import_discord14.ButtonStyle.Primary);
4172
+ const button = this.buildButton(builder, customId, customId, import_discord15.ButtonStyle.Primary);
3967
4173
  map.set(customId, { button, handler, index });
3968
4174
  }
3969
4175
  return map;
3970
4176
  }
3971
4177
  buildButton(option, customId, defaultLabel, defaultStyle) {
3972
4178
  if (typeof option === "function") {
3973
- return option(new import_discord14.ButtonBuilder());
4179
+ return option(new import_discord15.ButtonBuilder());
3974
4180
  }
3975
- if (option instanceof import_discord14.ButtonBuilder) {
4181
+ if (option instanceof import_discord15.ButtonBuilder) {
3976
4182
  return option;
3977
4183
  }
3978
- return new import_discord14.ButtonBuilder({
4184
+ return new import_discord15.ButtonBuilder({
3979
4185
  customId,
3980
4186
  label: defaultLabel,
3981
4187
  style: defaultStyle,
@@ -3983,12 +4189,12 @@ var Prompt = class {
3983
4189
  });
3984
4190
  }
3985
4191
  buildActionRow(disable = {}) {
3986
- const confirmBtn = disable.confirm ? new import_discord14.ButtonBuilder(this.buttons.confirm.data).setDisabled(true) : this.buttons.confirm;
3987
- const rejectBtn = disable.reject ? new import_discord14.ButtonBuilder(this.buttons.reject.data).setDisabled(true) : this.buttons.reject;
4192
+ const confirmBtn = disable.confirm ? new import_discord15.ButtonBuilder(this.buttons.confirm.data).setDisabled(true) : this.buttons.confirm;
4193
+ const rejectBtn = disable.reject ? new import_discord15.ButtonBuilder(this.buttons.reject.data).setDisabled(true) : this.buttons.reject;
3988
4194
  const buttons = [];
3989
4195
  const customButtonsArray = Array.from(this.customButtons.entries()).map(([customId, data]) => ({
3990
4196
  customId,
3991
- button: disable[customId] ? new import_discord14.ButtonBuilder(data.button.data).setDisabled(true) : data.button,
4197
+ button: disable[customId] ? new import_discord15.ButtonBuilder(data.button.data).setDisabled(true) : data.button,
3992
4198
  index: data.index
3993
4199
  }));
3994
4200
  customButtonsArray.sort((a, b) => a.index - b.index);
@@ -4009,7 +4215,7 @@ var Prompt = class {
4009
4215
  buttons.push(custom.button);
4010
4216
  }
4011
4217
  }
4012
- return new import_discord14.ActionRowBuilder({ components: buttons });
4218
+ return new import_discord15.ActionRowBuilder({ components: buttons });
4013
4219
  }
4014
4220
  buildSendOptions(options) {
4015
4221
  const sendData = { ...options };
@@ -4069,7 +4275,7 @@ var Prompt = class {
4069
4275
  const validCustomIds = /* @__PURE__ */ new Set(["btn_confirm", "btn_reject", ...this.customButtons.keys()]);
4070
4276
  try {
4071
4277
  const interaction = await this.message.awaitMessageComponent({
4072
- componentType: import_discord14.ComponentType.Button,
4278
+ componentType: import_discord15.ComponentType.Button,
4073
4279
  filter: (i) => validCustomIds.has(i.customId) && this.isParticipant(i.user.id),
4074
4280
  time: this.timeout
4075
4281
  });
@@ -4107,209 +4313,11 @@ async function prompt(handler, options, sendOptions) {
4107
4313
  await p.send(handler, sendOptions);
4108
4314
  return await p.awaitResponse();
4109
4315
  }
4110
-
4111
- // src/utils/VimcordCLI.ts
4112
- var import_node_readline = require("readline");
4113
- var import_qznt5 = require("qznt");
4114
- var VimcordCLI = class {
4115
- rl;
4116
- options;
4117
- commands = /* @__PURE__ */ new Map();
4118
- logger = new Logger({ prefixEmoji: "\u{1F680}", prefix: "CLI", showTimestamp: false });
4119
- constructor(options) {
4120
- this.options = options;
4121
- this.rl = (0, import_node_readline.createInterface)({
4122
- input: process.stdin,
4123
- output: process.stdout,
4124
- terminal: false
4125
- });
4126
- this.rl.on("line", (line) => {
4127
- const { isCommand, commandName, content, args } = this.parseLine(line);
4128
- if (!isCommand) return;
4129
- const command = this.commands.get(commandName);
4130
- if (!command) {
4131
- const nearestMatches = Array.from(this.commands.keys()).filter(
4132
- (cmd) => cmd.toLowerCase().includes(commandName.toLowerCase())
4133
- );
4134
- return this.logger.error(
4135
- `Unknown command '${commandName}'${nearestMatches.length ? `. Did you mean ${nearestMatches.length > 1 ? `[${nearestMatches.map((m) => `'${this.options.prefix}${m}'`).join(", ")}]` : `'${this.options.prefix}${nearestMatches[0]}'`}?` : ""}`
4136
- );
4137
- }
4138
- command.fn(args, content);
4139
- });
4140
- }
4141
- parseLine(line) {
4142
- if (line.startsWith(this.options.prefix)) {
4143
- line = line.slice(this.options.prefix.length);
4144
- } else {
4145
- return { isCommand: false };
4146
- }
4147
- const args = line.split(" ").map((s) => s.trim());
4148
- const commandName = args.shift();
4149
- return { isCommand: true, commandName, content: args.join(" "), args };
4150
- }
4151
- getClientInstance(line) {
4152
- const clientIndex = import_qznt5.$.str.getFlag(line, "--client", 1) || import_qznt5.$.str.getFlag(line, "-c", 1);
4153
- if (clientIndex) {
4154
- const idx = Number(clientIndex);
4155
- if (isNaN(idx)) {
4156
- CLI.logger.error(`'${clientIndex}' is not a valid number`);
4157
- return void 0;
4158
- }
4159
- const client = clientInstances[idx];
4160
- if (!client) {
4161
- CLI.logger.error("Client instance not found");
4162
- return void 0;
4163
- }
4164
- return client;
4165
- } else {
4166
- const client = clientInstances[0];
4167
- if (!client) {
4168
- CLI.logger.error("Client instance not found");
4169
- return void 0;
4170
- }
4171
- return client;
4172
- }
4173
- }
4174
- addCommand(commandName, description, fn) {
4175
- this.commands.set(commandName, { description, fn });
4176
- }
4177
- removeCommand(commandName) {
4178
- if (!this.commands.has(commandName)) return false;
4179
- this.commands.delete(commandName);
4180
- return true;
4181
- }
4182
- };
4183
- var initCalled = false;
4184
- var CLI = new VimcordCLI({ prefix: "/" });
4185
- CLI.addCommand("help", "View information about a command, or the available CLI options", (args) => {
4186
- const prefix = CLI.options.prefix;
4187
- const helpList = {};
4188
- for (const cmd of CLI.commands.entries()) {
4189
- const commandName = cmd[0];
4190
- const commandDescription = cmd[1].description;
4191
- helpList[`${prefix}${commandName}`] = `~ ${commandDescription}`;
4192
- }
4193
- CLI.logger.table("(help)", helpList);
4194
- });
4195
- CLI.addCommand("register", "Register app commands (slash & context) globally, or per guild", async (args, content) => {
4196
- const client = CLI.getClientInstance(content);
4197
- if (!client) return;
4198
- const mode = args[0]?.toLowerCase() || "";
4199
- if (!["guild", "global"].includes(mode)) {
4200
- return CLI.logger.error(`'${mode}' is not a valid option. Your options are [guild|global]`);
4201
- }
4202
- let guildIds = (import_qznt5.$.str.getFlag(content, "--guilds", 1) || import_qznt5.$.str.getFlag(content, "-g", 1) || "").replaceAll(/["']/g, "").split(" ").filter(Boolean).map((s) => s.replaceAll(",", "").trim());
4203
- if (!guildIds.length) guildIds = client.guilds.cache.map((g) => g.id);
4204
- switch (mode) {
4205
- case "guild":
4206
- CLI.logger.info("Registering guild commands...");
4207
- await client.commands.registerGuild({ guilds: guildIds });
4208
- break;
4209
- case "global":
4210
- CLI.logger.info("Registering global commands...");
4211
- await client.commands.registerGlobal();
4212
- break;
4213
- }
4214
- });
4215
- CLI.addCommand("unregister", "Unregister app commands globally, or per guild", async (args, content) => {
4216
- const client = CLI.getClientInstance(content);
4217
- if (!client) return;
4218
- const mode = args[0]?.toLowerCase() || "";
4219
- if (!["guild", "global"].includes(mode)) {
4220
- return CLI.logger.error(`'${mode}' is not a valid option. Your options are [guild|global]`);
4221
- }
4222
- let guildIds = (import_qznt5.$.str.getFlag(content, "--guilds", 1) || import_qznt5.$.str.getFlag(content, "-g", 1) || "").replaceAll(/["']/g, "").split(" ").filter(Boolean).map((s) => s.replaceAll(",", "").trim());
4223
- if (!guildIds.length) guildIds = client.guilds.cache.map((g) => g.id);
4224
- switch (mode) {
4225
- case "guild":
4226
- CLI.logger.info("Unregistering guild commands...");
4227
- await client.commands.unregisterGuild({ guilds: guildIds });
4228
- break;
4229
- case "global":
4230
- CLI.logger.info("Unregistering global commands...");
4231
- await client.commands.unregisterGlobal();
4232
- break;
4233
- }
4234
- });
4235
- CLI.addCommand("stats", "View statistics about a client instance", (args, content) => {
4236
- const client = CLI.getClientInstance(content);
4237
- if (!client) return;
4238
- CLI.logger.table(`(stats) ~ ${client.config.app.name}`, {
4239
- "Guilds:": import_qznt5.$.format.number(client.guilds.cache.size),
4240
- "Ping:": `${client.ws.ping || 0}ms`,
4241
- "Uptime:": `${import_qznt5.$.math.secs(client.uptime || 0)}s`,
4242
- "Process Uptime:": `${Math.floor(process.uptime())}s`,
4243
- "Memory Usage:": `${(process.memoryUsage().rss / 1024 / 1024).toFixed(2)} MB`
4244
- });
4245
- });
4246
- CLI.addCommand("cmds", "List the loaded commands", async (args, content) => {
4247
- const client = CLI.getClientInstance(content);
4248
- if (!client) return;
4249
- const mode = (args[0] || "slash").toLowerCase();
4250
- switch (mode) {
4251
- case "slash": {
4252
- const commands = Array.from(client.commands.slash.commands.values());
4253
- commands.sort((a, b) => a.builder.name.localeCompare(b.builder.name));
4254
- const tableData = {};
4255
- for (const cmd of commands) {
4256
- tableData[`/${cmd.builder.name}`] = `~ ${cmd.builder.description || "No description"}`;
4257
- }
4258
- return CLI.logger.table(`(cmds) ~ slash (${import_qznt5.$.format.number(commands.length)})`, tableData);
4259
- }
4260
- case "prefix": {
4261
- const commands = Array.from(client.commands.prefix.commands.values());
4262
- commands.sort((a, b) => {
4263
- const nameA = a.toConfig().name;
4264
- const nameB = b.toConfig().name;
4265
- return nameA.localeCompare(nameB);
4266
- });
4267
- const tableData = {};
4268
- const defaultPrefix = client.config.prefixCommands.defaultPrefix;
4269
- for (const cmd of commands) {
4270
- const config = cmd.toConfig();
4271
- const aliasIndicator = config.aliases?.length ? ` [${config.aliases.join(", ")}]` : "";
4272
- tableData[`${defaultPrefix}${config.name}${aliasIndicator}`] = `~ ${config.description || "No description"}`;
4273
- }
4274
- return CLI.logger.table(`(cmds) ~ prefix (${import_qznt5.$.format.number(commands.length)})`, tableData);
4275
- }
4276
- case "ctx": {
4277
- const commands = Array.from(client.commands.context.commands.values());
4278
- commands.sort((a, b) => a.builder.name.localeCompare(b.builder.name));
4279
- const tableData = {};
4280
- for (const cmd of commands) {
4281
- const type = cmd.builder.type === 2 ? "User" : "Msg";
4282
- tableData[`[${type}] ${cmd.builder.name}`] = "";
4283
- }
4284
- return CLI.logger.table(`(cmds) ~ ctx (${import_qznt5.$.format.number(commands.length)})`, tableData);
4285
- }
4286
- default:
4287
- return CLI.logger.error(`'${mode}' is not a valid option. Valid options: [slash|prefix|ctx]`);
4288
- }
4289
- });
4290
- function initCLI() {
4291
- if (initCalled) return;
4292
- CLI.logger.log(`~ Type ${CLI.options.prefix}help to view available commands`);
4293
- initCalled = true;
4294
- }
4295
-
4296
- // src/utils/clientUtils.ts
4297
- function useClient(index = 0) {
4298
- return clientInstances.at(index);
4299
- }
4300
- async function useReadyClient(index = 0) {
4301
- return useClient(index)?.whenReady();
4302
- }
4303
- function createClient(options, features = {}, config = {}) {
4304
- const client = new Vimcord(options, features, config);
4305
- initCLI();
4306
- return client;
4307
- }
4308
- function getClientInstances() {
4309
- return clientInstances;
4310
- }
4311
4316
  // Annotate the CommonJS export names for ESM import in node:
4312
4317
  0 && (module.exports = {
4318
+ BUILTIN_ContextCommandHandler,
4319
+ BUILTIN_PrefixCommandHandler,
4320
+ BUILTIN_SlashCommandHandler,
4313
4321
  BaseCommandBuilder,
4314
4322
  BaseCommandManager,
4315
4323
  BetterCollector,
@@ -4348,7 +4356,6 @@ function getClientInstances() {
4348
4356
  VimcordCLI,
4349
4357
  __zero,
4350
4358
  cleanMention,
4351
- clientInstances,
4352
4359
  createClient,
4353
4360
  createMongoPlugin,
4354
4361
  createMongoSchema,
@@ -4367,9 +4374,7 @@ function getClientInstances() {
4367
4374
  fetchMessage,
4368
4375
  fetchRole,
4369
4376
  fetchUser,
4370
- formatThousands,
4371
4377
  getCallerFileName,
4372
- getClientInstances,
4373
4378
  getFirstMentionId,
4374
4379
  getMessageMention,
4375
4380
  getProcessDir,
@@ -4379,7 +4384,6 @@ function getClientInstances() {
4379
4384
  isMentionOrSnowflake,
4380
4385
  logger,
4381
4386
  prompt,
4382
- retryExponentialBackoff,
4383
4387
  sendCommandErrorEmbed,
4384
4388
  useClient,
4385
4389
  useReadyClient,