vimcord 1.0.35 → 1.0.37

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.js CHANGED
@@ -5,6 +5,9 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
5
5
  throw Error('Dynamic require of "' + x + '" is not supported');
6
6
  });
7
7
 
8
+ // src/modules/validators/permissions.validator.ts
9
+ import { BaseInteraction } from "discord.js";
10
+
8
11
  // src/types/command.base.ts
9
12
  var CommandType = /* @__PURE__ */ ((CommandType2) => {
10
13
  CommandType2[CommandType2["Slash"] = 0] = "Slash";
@@ -32,8 +35,7 @@ var RateLimitScope = /* @__PURE__ */ ((RateLimitScope2) => {
32
35
  return RateLimitScope2;
33
36
  })(RateLimitScope || {});
34
37
 
35
- // src/validators/permissions.validator.ts
36
- import { BaseInteraction } from "discord.js";
38
+ // src/modules/validators/permissions.validator.ts
37
39
  function __existsAndTrue(value) {
38
40
  return value !== void 0 && value;
39
41
  }
@@ -132,8 +134,8 @@ function validateCommandPermissions(permissions, client, user, command) {
132
134
  }
133
135
 
134
136
  // src/builders/baseCommand.builder.ts
135
- import { randomUUID } from "crypto";
136
137
  import _ from "lodash";
138
+ import { randomUUID } from "crypto";
137
139
  var BaseCommandBuilder = class {
138
140
  uuid = randomUUID();
139
141
  commandType;
@@ -423,55 +425,199 @@ var ContextCommandBuilder = class extends BaseCommandBuilder {
423
425
  }
424
426
  };
425
427
 
426
- // src/utils/dir.ts
427
- import path from "path";
428
- import { $ } from "qznt";
429
- function getCallerFileName() {
430
- const stack = new Error().stack?.split("\n");
431
- return stack?.at(4)?.split("at file")?.at(1)?.split("/").at(-1)?.split(":").at(0)?.split(".").at(0);
432
- }
433
- function getProcessDir() {
434
- const mainPath = process.argv[1];
435
- if (!mainPath) return "";
436
- return path.dirname(mainPath);
437
- }
438
- async function importModulesFromDir(dir, suffix) {
439
- const cwd = getProcessDir();
440
- const MODULE_RELATIVE_PATH = path.join(cwd, dir);
441
- const MODULE_LOG_PATH = dir;
442
- const files = $.fs.readDir(MODULE_RELATIVE_PATH).filter((fn) => fn.endsWith(`${suffix ? `.${suffix}` : ""}.js`) || fn.endsWith(`${suffix ? `.${suffix}` : ""}.ts`));
443
- if (!files.length) {
444
- return [];
428
+ // src/builders/event.builder.ts
429
+ import { randomUUID as randomUUID2 } from "crypto";
430
+ import _3 from "lodash";
431
+
432
+ // src/tools/Logger.ts
433
+ import chalk from "chalk";
434
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
435
+ LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
436
+ LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
437
+ LogLevel2[LogLevel2["SUCCESS"] = 2] = "SUCCESS";
438
+ LogLevel2[LogLevel2["WARN"] = 3] = "WARN";
439
+ LogLevel2[LogLevel2["ERROR"] = 4] = "ERROR";
440
+ return LogLevel2;
441
+ })(LogLevel || {});
442
+ var LOGGER_COLORS = {
443
+ primary: "#5865F2",
444
+ success: "#57F287",
445
+ warn: "#FEE75C",
446
+ danger: "#ED4245",
447
+ muted: "#747F8D",
448
+ text: "#FFFFFF"
449
+ };
450
+ var Logger = class {
451
+ logPrefixEmoji;
452
+ logPrefix;
453
+ minLevel;
454
+ showTimestamp;
455
+ colorScheme;
456
+ constructor(options) {
457
+ const { prefixEmoji = null, prefix = null, minLevel = 0 /* DEBUG */, showTimestamp = true } = options || {};
458
+ this.logPrefixEmoji = prefixEmoji;
459
+ this.logPrefix = prefix;
460
+ this.minLevel = minLevel;
461
+ this.showTimestamp = showTimestamp;
462
+ this.colorScheme = {
463
+ ...LOGGER_COLORS,
464
+ ...options?.colors
465
+ };
445
466
  }
446
- const modules = await Promise.all(
447
- files.map(async (fn) => {
448
- let _path = path.join(MODULE_RELATIVE_PATH, fn);
449
- let _logPath = `./${path.join(MODULE_LOG_PATH, fn)}`;
450
- let _module;
451
- try {
452
- delete __require.cache[__require.resolve(_path)];
453
- _module = __require(_path);
454
- } catch (err) {
455
- console.warn(`Failed to import module at '${_logPath}'`, err);
456
- _module = null;
467
+ formatTimestamp() {
468
+ if (!this.showTimestamp) return "";
469
+ const now = /* @__PURE__ */ new Date();
470
+ const time = now.toLocaleTimeString("en-US", {
471
+ hour12: false,
472
+ hour: "2-digit",
473
+ minute: "2-digit",
474
+ second: "2-digit"
475
+ });
476
+ return chalk.hex(this.colorScheme.muted)(`[${time}]`);
477
+ }
478
+ formatPrefix() {
479
+ if (!this.logPrefix) return "";
480
+ return chalk.bold.hex(this.colorScheme.primary)(
481
+ `${this.logPrefixEmoji ? `${this.logPrefixEmoji} ` : ""}${this.logPrefix}`
482
+ );
483
+ }
484
+ shouldLog(level) {
485
+ return level >= this.minLevel;
486
+ }
487
+ get prefixEmoji() {
488
+ return this.logPrefixEmoji;
489
+ }
490
+ get prefix() {
491
+ return this.logPrefix;
492
+ }
493
+ get colors() {
494
+ return this.colorScheme;
495
+ }
496
+ extend(extras) {
497
+ for (const [key, fn] of Object.entries(extras)) {
498
+ if (typeof fn === "function") {
499
+ this[key] = function(...args) {
500
+ return fn.call(this, ...args);
501
+ };
457
502
  }
458
- return { module: _module, path: _logPath };
459
- })
460
- );
461
- const filteredModules = modules.filter((m) => m.module);
462
- if (!filteredModules.length) {
463
- console.warn(`No valid modules were found in directory '${dir}'`);
503
+ }
504
+ return this;
464
505
  }
465
- return filteredModules;
466
- }
506
+ setPrefix(prefix) {
507
+ this.logPrefix = prefix;
508
+ return this;
509
+ }
510
+ setPrefixEmoji(prefixEmoji) {
511
+ this.logPrefixEmoji = prefixEmoji;
512
+ return this;
513
+ }
514
+ setMinLevel(minLevel) {
515
+ this.minLevel = minLevel;
516
+ return this;
517
+ }
518
+ setShowTimestamp(show) {
519
+ this.showTimestamp = show;
520
+ return this;
521
+ }
522
+ setColors(colors) {
523
+ this.colorScheme = {
524
+ ...LOGGER_COLORS,
525
+ ...colors
526
+ };
527
+ return this;
528
+ }
529
+ log(message, ...args) {
530
+ console.log(this.formatTimestamp(), this.formatPrefix(), message, ...args);
531
+ }
532
+ debug(message, ...args) {
533
+ if (!this.shouldLog(0 /* DEBUG */)) return;
534
+ console.log(
535
+ this.formatTimestamp(),
536
+ this.formatPrefix(),
537
+ chalk.hex(this.colorScheme.muted)("DEBUG"),
538
+ chalk.dim(message),
539
+ ...args
540
+ );
541
+ }
542
+ info(message, ...args) {
543
+ if (!this.shouldLog(1 /* INFO */)) return;
544
+ console.log(this.formatTimestamp(), this.formatPrefix(), chalk.hex("#87CEEB")("INFO"), message, ...args);
545
+ }
546
+ success(message, ...args) {
547
+ if (!this.shouldLog(2 /* SUCCESS */)) return;
548
+ console.log(
549
+ this.formatTimestamp(),
550
+ this.formatPrefix(),
551
+ chalk.bold.hex(this.colorScheme.success)("\u2713 SUCCESS"),
552
+ chalk.hex(this.colorScheme.success)(message),
553
+ ...args
554
+ );
555
+ }
556
+ warn(message, ...args) {
557
+ if (!this.shouldLog(3 /* WARN */)) return;
558
+ console.warn(
559
+ this.formatTimestamp(),
560
+ this.formatPrefix(),
561
+ chalk.bold.hex(this.colorScheme.warn)("\u26A0 WARN"),
562
+ chalk.hex(this.colorScheme.warn)(message),
563
+ ...args
564
+ );
565
+ }
566
+ error(message, error, ...args) {
567
+ if (!this.shouldLog(4 /* ERROR */)) return;
568
+ console.error(
569
+ this.formatTimestamp(),
570
+ this.formatPrefix(),
571
+ chalk.bold.hex(this.colorScheme.danger)("\u2715 ERROR"),
572
+ chalk.hex(this.colorScheme.danger)(message),
573
+ ...args
574
+ );
575
+ if (error && error.stack) {
576
+ console.error(chalk.dim(error.stack));
577
+ }
578
+ }
579
+ loader(message) {
580
+ const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
581
+ let i = 0;
582
+ const interval = setInterval(() => {
583
+ process.stdout.write(
584
+ `\r${this.formatTimestamp()} ${this.formatPrefix()} ${chalk.hex(this.colorScheme.warn)(frames[i])} ${message}`
585
+ );
586
+ i = (i + 1) % frames.length;
587
+ }, 100);
588
+ return (newMessage) => {
589
+ clearInterval(interval);
590
+ process.stdout.write(
591
+ `\r${this.formatTimestamp()} ${this.formatPrefix()} ${chalk.hex(this.colorScheme.success)("\u2713")} ${newMessage || message}
592
+ `
593
+ );
594
+ };
595
+ }
596
+ table(title, data) {
597
+ console.log(this.formatTimestamp(), this.formatPrefix(), chalk.bold(title));
598
+ Object.entries(data).forEach(([key, value]) => {
599
+ const formattedKey = chalk.hex(this.colorScheme.warn)(` ${key}`);
600
+ const formattedValue = chalk.hex(this.colorScheme.muted)(value);
601
+ console.log(`${formattedKey.padEnd(25)} ${formattedValue}`);
602
+ });
603
+ }
604
+ section(title) {
605
+ const line = "\u2500".repeat(Math.max(30, title.length + 4));
606
+ console.log(chalk.hex(this.colorScheme.muted)(`
607
+ \u250C\u2500${line}\u2500\u2510`));
608
+ console.log(
609
+ chalk.hex(this.colorScheme.muted)("\u2502 ") + chalk.bold.hex(this.colorScheme.text)(title.padEnd(line.length)) + chalk.hex(this.colorScheme.muted)(" \u2502")
610
+ );
611
+ console.log(chalk.hex(this.colorScheme.muted)(`\u2514\u2500${line}\u2500\u2518`));
612
+ }
613
+ };
614
+ var logger = new Logger();
467
615
 
468
616
  // src/builders/event.builder.ts
469
- import { randomUUID as randomUUID2 } from "crypto";
470
- import _3 from "lodash";
471
617
  var EventBuilder = class _EventBuilder {
472
618
  uuid = randomUUID2();
473
619
  event;
474
- name = getCallerFileName() || this.uuid;
620
+ name = this.uuid;
475
621
  enabled;
476
622
  once;
477
623
  priority;
@@ -636,6 +782,7 @@ var EventBuilder = class _EventBuilder {
636
782
  return;
637
783
  }
638
784
  if (this.isRateLimited()) {
785
+ logger.warn(`Event '${this.name}' (${this.event}) is rate limited`);
639
786
  if (this.rateLimit?.onRateLimit) {
640
787
  return await this.rateLimit.onRateLimit(...args);
641
788
  }
@@ -656,7 +803,7 @@ var EventBuilder = class _EventBuilder {
656
803
  if (this.onError) {
657
804
  return await this.onError(err, ...args);
658
805
  }
659
- console.error(`Error in event '${this.name}':`, err);
806
+ logger.error(`Event execution error '${this.name}' (${this.event}):`, err);
660
807
  throw err;
661
808
  }
662
809
  }
@@ -759,7 +906,11 @@ var SlashCommandBuilder = class extends BaseCommandBuilder {
759
906
  if (subCommand) {
760
907
  const handler = this.routes.get(subCommand.toLowerCase());
761
908
  if (handler) return await handler(client, interaction);
762
- if (config.onUnknownRouteHandler) return await config.onUnknownRouteHandler(client, interaction);
909
+ if (config.onUnknownRouteHandler) {
910
+ return await config.onUnknownRouteHandler(client, interaction);
911
+ } else {
912
+ return await interaction.reply({ content: `Unknown subcommand: ${subCommand}`, flags: "Ephemeral" });
913
+ }
763
914
  }
764
915
  return await originalExecute?.(client, interaction);
765
916
  }
@@ -818,21 +969,119 @@ var SlashCommandBuilder = class extends BaseCommandBuilder {
818
969
  }
819
970
  };
820
971
 
821
- // src/client.ts
822
- import { Client as Client2 } from "discord.js";
823
- import dotEnv from "dotenv";
972
+ // src/modules/builtins/context-command.builtins.ts
973
+ var contextCommandHandler = new EventBuilder({
974
+ event: "interactionCreate",
975
+ name: "ContextCommandHandler",
976
+ async execute(client, interaction) {
977
+ if (!interaction.isContextMenuCommand()) return;
978
+ const command = client.commands.context.get(interaction.commandName);
979
+ if (!command) {
980
+ const content = `**${interaction.commandName}** is not a registered context command.`;
981
+ if (interaction.replied || interaction.deferred) {
982
+ return interaction.followUp({ content, flags: "Ephemeral" });
983
+ }
984
+ return interaction.reply({ content, flags: "Ephemeral" });
985
+ }
986
+ try {
987
+ return await command.run(client, client, interaction);
988
+ } catch (err) {
989
+ await client.error.handleCommandError(err, interaction.guild, interaction);
990
+ }
991
+ }
992
+ });
824
993
 
825
- // src/configs/tools.config.ts
826
- import _5 from "lodash";
827
- var globalVimcordToolsConfig = {
828
- devMode: false,
829
- embedColor: [],
830
- embedColorDev: [],
831
- timeouts: {
832
- collectorTimeout: 6e4,
833
- collectorIdle: 6e4,
834
- pagination: 6e4,
835
- prompt: 3e4,
994
+ // src/modules/builtins/prefix-command.builtins.ts
995
+ import { userMention } from "discord.js";
996
+ var prefixCommandHandler = new EventBuilder({
997
+ event: "messageCreate",
998
+ name: "PrefixCommandHandler",
999
+ async execute(client, message) {
1000
+ if (message.author.bot || !message.guild) return;
1001
+ const config = client.config.prefixCommands;
1002
+ let activePrefix = config.defaultPrefix;
1003
+ if (config.guildPrefixResolver) {
1004
+ try {
1005
+ const customPrefix = await config.guildPrefixResolver(client, message.guild.id);
1006
+ if (customPrefix) activePrefix = customPrefix;
1007
+ } catch (err) {
1008
+ client.logger.error(`Error in guildPrefixResolver for guild ${message.guild.id}:`, err);
1009
+ }
1010
+ }
1011
+ let prefixUsed;
1012
+ if (message.content.startsWith(activePrefix)) {
1013
+ prefixUsed = activePrefix;
1014
+ } else if (config.allowMentionAsPrefix) {
1015
+ const mention = userMention(client.user.id);
1016
+ if (message.content.startsWith(mention)) {
1017
+ prefixUsed = message.content.startsWith(`${mention} `) ? `${mention} ` : mention;
1018
+ }
1019
+ }
1020
+ if (!prefixUsed) return;
1021
+ const contentWithoutPrefix = message.content.slice(prefixUsed.length).trim();
1022
+ const args = contentWithoutPrefix.split(/\s+/);
1023
+ const trigger = args.shift();
1024
+ if (!trigger) return;
1025
+ const command = client.commands.prefix.get(trigger);
1026
+ if (!command) return;
1027
+ message.content = args.join(" ");
1028
+ try {
1029
+ return await command.run(client, client, message);
1030
+ } catch (err) {
1031
+ await client.error.handleCommandError(err, message.guild, message);
1032
+ }
1033
+ }
1034
+ });
1035
+
1036
+ // src/modules/builtins/slash-command.builtins.ts
1037
+ var slashCommandHandler = new EventBuilder({
1038
+ event: "interactionCreate",
1039
+ name: "SlashCommandHandler",
1040
+ async execute(client, interaction) {
1041
+ if (!interaction.isChatInputCommand()) return;
1042
+ const command = client.commands.slash.get(interaction.commandName);
1043
+ if (!command) {
1044
+ const content = `**/\`${interaction.commandName}\`** is not a registered command.`;
1045
+ if (interaction.replied || interaction.deferred) {
1046
+ return interaction.followUp({ content, flags: "Ephemeral" });
1047
+ }
1048
+ return interaction.reply({ content, flags: "Ephemeral" });
1049
+ }
1050
+ try {
1051
+ return await command.run(client, client, interaction);
1052
+ } catch (err) {
1053
+ await client.error.handleCommandError(err, interaction.guild, interaction);
1054
+ }
1055
+ }
1056
+ });
1057
+
1058
+ // src/tools/BetterEmbed.ts
1059
+ import {
1060
+ EmbedBuilder,
1061
+ GuildMember as GuildMember3,
1062
+ User as User3
1063
+ } from "discord.js";
1064
+
1065
+ // src/utils/config.factory.ts
1066
+ import _5 from "lodash";
1067
+ function createConfigFactory(defaultConfig6, validate) {
1068
+ return (options = {}, existing) => {
1069
+ const result = _5.merge({}, defaultConfig6, existing, options);
1070
+ validate?.(result);
1071
+ return result;
1072
+ };
1073
+ }
1074
+
1075
+ // src/configs/tools.config.ts
1076
+ var globalToolsConfig = {
1077
+ devMode: false,
1078
+ embedColor: [],
1079
+ embedColorDev: [],
1080
+ timeouts: {
1081
+ collectorTimeout: 6e4,
1082
+ collectorIdle: 6e4,
1083
+ pagination: 6e4,
1084
+ prompt: 3e4,
836
1085
  modalSubmit: 6e4
837
1086
  },
838
1087
  collector: {
@@ -859,103 +1108,10 @@ var globalVimcordToolsConfig = {
859
1108
  rejectLabel: "Cancel"
860
1109
  }
861
1110
  };
862
- function defineGlobalToolsConfig(options) {
863
- Object.assign(globalVimcordToolsConfig, _5.merge(globalVimcordToolsConfig, options));
864
- }
865
- function createToolsConfig(options) {
866
- return _5.merge(globalVimcordToolsConfig, options);
867
- }
868
-
869
- // src/configs/app.config.ts
870
- import _6 from "lodash";
871
- var defaultConfig = {
872
- devMode: process.argv.includes("--dev"),
873
- name: "Discord Bot",
874
- appVersion: "1.0.0",
875
- verbose: false,
876
- disableBanner: false,
877
- moduleSuffixes: {
878
- slashCommand: "slash",
879
- contextCommand: "ctx",
880
- prefixCommand: "prefix",
881
- event: "event"
882
- }
883
- };
884
- function createVimcordAppConfig(options = {}) {
885
- return _6.merge(defaultConfig, options);
886
- }
887
-
888
- // src/configs/staff.config.ts
889
- import _7 from "lodash";
890
- var defaultConfig2 = {
891
- ownerId: null,
892
- superUsers: [],
893
- superUserRoles: [],
894
- bypassers: [],
895
- bypassesGuildAdmin: {
896
- allBotStaff: false,
897
- botOwner: false,
898
- superUsers: false,
899
- bypassers: false
900
- },
901
- guild: {
902
- id: null,
903
- inviteUrl: null,
904
- channels: {}
905
- }
906
- };
907
- function createVimcordStaffConfig(options = {}) {
908
- return _7.merge(defaultConfig2, options);
909
- }
910
-
911
- // src/configs/slashCommand.config.ts
912
- import _8 from "lodash";
913
- var defaultConfig3 = {
914
- logExecution: true
915
- };
916
- function createVimcordSlashCommandConfig(options = {}) {
917
- return _8.merge(defaultConfig3, options);
918
- }
919
-
920
- // src/configs/prefixCommand.config.ts
921
- import _9 from "lodash";
922
- var defaultConfig4 = {
923
- enabled: true,
924
- defaultPrefix: "!",
925
- allowMentionAsPrefix: true,
926
- allowCaseInsensitiveCommandNames: true,
927
- logExecution: true
928
- };
929
- function createVimcordPrefixCommandConfig(options = {}) {
930
- return _9.merge(defaultConfig4, options);
931
- }
932
-
933
- // src/configs/contextCommand.config.ts
934
- import _10 from "lodash";
935
- var defaultConfig5 = {
936
- enabled: true,
937
- logExecution: true
1111
+ var createToolsConfig = createConfigFactory(globalToolsConfig);
1112
+ var defineGlobalToolsConfig = (options) => {
1113
+ Object.assign(globalToolsConfig, createToolsConfig(options, globalToolsConfig));
938
1114
  };
939
- function createVimcordContextCommandConfig(options = {}) {
940
- return _10.merge(defaultConfig5, options);
941
- }
942
-
943
- // src/utils/sendCommandErrorEmbed.ts
944
- import {
945
- ActionRowBuilder as ActionRowBuilder2,
946
- AttachmentBuilder,
947
- ButtonBuilder,
948
- ButtonStyle,
949
- ComponentType,
950
- Message as Message3
951
- } from "discord.js";
952
-
953
- // src/tools/BetterEmbed.ts
954
- import {
955
- EmbedBuilder,
956
- GuildMember as GuildMember3,
957
- User as User3
958
- } from "discord.js";
959
1115
 
960
1116
  // src/tools/dynaSend.ts
961
1117
  import {
@@ -1172,7 +1328,7 @@ var BetterEmbed = class _BetterEmbed {
1172
1328
  * - __`$month`__: _M or MM_
1173
1329
  * - __`$day`__: _D or DD_ */
1174
1330
  constructor(data = {}) {
1175
- this.config = data.config || globalVimcordToolsConfig;
1331
+ this.config = data.config ? createToolsConfig(data.config) : globalToolsConfig;
1176
1332
  this.data = {
1177
1333
  context: data.context || null,
1178
1334
  author: data.author || null,
@@ -1411,7 +1567,15 @@ var BetterEmbed = class _BetterEmbed {
1411
1567
  }
1412
1568
  };
1413
1569
 
1414
- // src/utils/sendCommandErrorEmbed.ts
1570
+ // src/utils/command-error.utils.ts
1571
+ import {
1572
+ ActionRowBuilder as ActionRowBuilder2,
1573
+ AttachmentBuilder,
1574
+ ButtonBuilder,
1575
+ ButtonStyle,
1576
+ ComponentType,
1577
+ Message as Message3
1578
+ } from "discord.js";
1415
1579
  async function sendCommandErrorEmbed(client, error, guild, messageOrInteraction) {
1416
1580
  if (!client.features.enableCommandErrorMessage) return null;
1417
1581
  const config = typeof client.features.enableCommandErrorMessage !== "boolean" ? client.features.enableCommandErrorMessage : void 0;
@@ -1436,7 +1600,8 @@ async function sendCommandErrorEmbed(client, error, guild, messageOrInteraction)
1436
1600
  title: "Something went wrong",
1437
1601
  description: "If you keep encountering this error, please report it."
1438
1602
  });
1439
- const msg = await embed_error.send(messageOrInteraction, {
1603
+ const msg = await dynaSend(messageOrInteraction, {
1604
+ embeds: [embed_error],
1440
1605
  components: [actionRow],
1441
1606
  flags: config?.ephemeral ? "Ephemeral" : void 0,
1442
1607
  deleteAfter: config?.deleteAfter
@@ -1457,7 +1622,8 @@ ${error.stack}`), {
1457
1622
  });
1458
1623
  collector.on("end", () => {
1459
1624
  buttons.details.setDisabled(true);
1460
- embed_error.send(messageOrInteraction, {
1625
+ dynaSend(messageOrInteraction, {
1626
+ embeds: [embed_error],
1461
1627
  sendMethod: messageOrInteraction instanceof Message3 ? 5 /* MessageEdit */ : void 0,
1462
1628
  components: [actionRow]
1463
1629
  });
@@ -1465,529 +1631,326 @@ ${error.stack}`), {
1465
1631
  return msg;
1466
1632
  }
1467
1633
 
1468
- // src/modules/builtins/builtin.slashCommandHandler.ts
1469
- var BUILTIN_SlashCommandHandler = new EventBuilder({
1470
- event: "interactionCreate",
1471
- name: "SlashCommandHandler",
1472
- async execute(client, interaction) {
1473
- if (!interaction.isChatInputCommand()) return;
1474
- const command = client.commands.slash.get(interaction.commandName);
1475
- if (!command) {
1476
- const content = `**/\`${interaction.commandName}\`** is not a registered command.`;
1477
- if (interaction.replied || interaction.deferred) {
1478
- return interaction.followUp({ content, flags: "Ephemeral" });
1479
- }
1480
- return interaction.reply({ content, flags: "Ephemeral" });
1481
- }
1482
- try {
1483
- return await command.run(client, client, interaction);
1484
- } catch (err) {
1485
- await sendCommandErrorEmbed(client, err, interaction.guild, interaction);
1486
- throw err;
1487
- }
1634
+ // src/client/error-handler.ts
1635
+ var ErrorHandler = class {
1636
+ client;
1637
+ constructor(client) {
1638
+ this.client = client;
1488
1639
  }
1489
- });
1640
+ /** Handles command errors - sends error embed to user, then rethrows. */
1641
+ async handleCommandError(error, guild, messageOrInteraction) {
1642
+ await sendCommandErrorEmbed(this.client, error, guild, messageOrInteraction);
1643
+ throw error;
1644
+ }
1645
+ /** Handles internal Vimcord errors - logs with [Vimcord] prefix. */
1646
+ handleVimcordError(error, context) {
1647
+ this.client.logger.error(`[Vimcord] [${context}]`, error);
1648
+ }
1649
+ /** Sets up global process error handlers. */
1650
+ setupGlobalHandlers() {
1651
+ process.on("uncaughtException", (err) => this.handleVimcordError(err, "Uncaught Exception"));
1652
+ process.on("unhandledRejection", (err) => this.handleVimcordError(err, "Unhandled Rejection"));
1653
+ process.on("exit", (code) => this.client.logger.debug(`Process exited with code ${code}`));
1654
+ this.client.on("error", (err) => this.handleVimcordError(err, "Client Error"));
1655
+ this.client.on("shardError", (err) => this.handleVimcordError(err, "Client Shard Error"));
1656
+ }
1657
+ };
1490
1658
 
1491
- // src/modules/builtins/builtin.prefixCommandHandler.ts
1492
- import { userMention } from "discord.js";
1493
- var BUILTIN_PrefixCommandHandler = new EventBuilder({
1494
- event: "messageCreate",
1495
- name: "PrefixCommandHandler",
1496
- async execute(client, message) {
1497
- if (message.author.bot || !message.guild) return;
1498
- const config = client.config.prefixCommands;
1499
- let activePrefix = config.defaultPrefix;
1500
- if (config.guildPrefixResolver) {
1501
- try {
1502
- const customPrefix = await config.guildPrefixResolver(client, message.guild.id);
1503
- if (customPrefix) activePrefix = customPrefix;
1504
- } catch (err) {
1505
- client.logger.error(`Error in guildPrefixResolver for guild ${message.guild.id}:`, err);
1506
- }
1507
- }
1508
- let prefixUsed;
1509
- if (message.content.startsWith(activePrefix)) {
1510
- prefixUsed = activePrefix;
1511
- } else if (config.allowMentionAsPrefix) {
1512
- const mention = userMention(client.user.id);
1513
- if (message.content.startsWith(mention)) {
1514
- prefixUsed = message.content.startsWith(`${mention} `) ? `${mention} ` : mention;
1515
- }
1516
- }
1517
- if (!prefixUsed) return;
1518
- const contentWithoutPrefix = message.content.slice(prefixUsed.length).trim();
1519
- const args = contentWithoutPrefix.split(/\s+/);
1520
- const trigger = args.shift();
1521
- if (!trigger) return;
1522
- const command = client.commands.prefix.get(trigger);
1523
- if (!command) return;
1524
- message.content = args.join(" ");
1525
- try {
1526
- return await command.run(client, client, message);
1527
- } catch (err) {
1528
- await sendCommandErrorEmbed(client, err, message.guild, message);
1529
- throw err;
1530
- }
1659
+ // src/client/vimcord.logger.ts
1660
+ import chalk2 from "chalk";
1661
+
1662
+ // package.json
1663
+ var version = "1.0.37";
1664
+
1665
+ // src/client/vimcord.logger.ts
1666
+ var clientLoggerFactory = (client) => new Logger({ prefixEmoji: "\u26A1", prefix: `vimcord (i${client.clientId})` }).extend({
1667
+ clientBanner(client2) {
1668
+ if (client2.config.app.disableBanner) return;
1669
+ const border = "\u2550".repeat(50);
1670
+ console.log(chalk2.hex(this.colors.primary)(`
1671
+ \u2554${border}\u2557`));
1672
+ console.log(
1673
+ chalk2.hex(this.colors.primary)("\u2551") + chalk2.bold.hex(this.colors.text)(
1674
+ ` \u{1F680} ${client2.config.app.name} v${client2.$version}`.padEnd(50 - (client2.$devMode ? 12 : 0))
1675
+ ) + chalk2.hex(this.colors.primary)(`${client2.$devMode ? chalk2.hex(this.colors.warn)("devMode \u26A0\uFE0F ") : ""}\u2551`)
1676
+ );
1677
+ console.log(chalk2.hex(this.colors.primary)(`\u2551${"".padEnd(50)}\u2551`));
1678
+ console.log(
1679
+ chalk2.hex(this.colors.primary)("\u2551") + chalk2.hex(this.colors.muted)(
1680
+ ` # Powered by Vimcord v${version}`.padEnd(50 - 3 - `${client2.clientId}`.length)
1681
+ ) + chalk2.hex(this.colors.primary)(`${chalk2.hex(this.colors.muted)(`i${client2.clientId}`)} \u2551`)
1682
+ );
1683
+ console.log(chalk2.hex(this.colors.primary)(`\u255A${border}\u255D
1684
+ `));
1685
+ },
1686
+ clientReady(clientTag, guildCount) {
1687
+ console.log(
1688
+ this.formatTimestamp(),
1689
+ this.formatPrefix(),
1690
+ chalk2.hex(this.colors.success)("\u{1F916} READY"),
1691
+ chalk2.white(`Connected as ${chalk2.bold.hex(this.colors.primary)(clientTag)}`),
1692
+ chalk2.hex(this.colors.muted)(`\u2022 ${guildCount} guilds`)
1693
+ );
1694
+ },
1695
+ moduleLoaded(moduleName, count, ignoredCount) {
1696
+ const countText = count ? chalk2.hex(this.colors.muted)(`(${count} items)`) : "";
1697
+ console.log(
1698
+ this.formatTimestamp(),
1699
+ this.formatPrefix(),
1700
+ chalk2.hex("#9B59B6")("\u{1F4E6} MODULE"),
1701
+ chalk2.hex(this.colors.warn)(`${moduleName} loaded`),
1702
+ ignoredCount ? chalk2.hex(this.colors.muted)(`(${ignoredCount} ignored)`) : "",
1703
+ countText
1704
+ );
1705
+ },
1706
+ commandExecuted(commandName, username, guildName) {
1707
+ const location = guildName ? `in ${chalk2.hex(this.colors.muted)(guildName)}` : "in DMs";
1708
+ console.log(
1709
+ this.formatTimestamp(),
1710
+ this.formatPrefix(),
1711
+ chalk2.hex("#87CEEB")("\u{1F4DD} COMMAND"),
1712
+ chalk2.hex(this.colors.warn)(`/${commandName}`),
1713
+ chalk2.white(`used by ${chalk2.bold(username)}`),
1714
+ chalk2.hex(this.colors.muted)(location)
1715
+ );
1716
+ },
1717
+ database(action, details) {
1718
+ console.log(
1719
+ this.formatTimestamp(),
1720
+ this.formatPrefix(),
1721
+ chalk2.hex("#FF6B9D")("\u{1F5C4}\uFE0F DATABASE"),
1722
+ chalk2.white(action),
1723
+ details ? chalk2.hex(this.colors.muted)(details) : ""
1724
+ );
1531
1725
  }
1532
1726
  });
1533
1727
 
1534
- // src/modules/builtins/builtin.contextCommandHandler.ts
1535
- var BUILTIN_ContextCommandHandler = new EventBuilder({
1536
- event: "interactionCreate",
1537
- name: "ContextCommandHandler",
1538
- async execute(client, interaction) {
1539
- if (!interaction.isContextMenuCommand()) return;
1540
- const command = client.commands.context.get(interaction.commandName);
1541
- if (!command) {
1542
- const content = `**${interaction.commandName}** is not a registered context command.`;
1543
- if (interaction.replied || interaction.deferred) {
1544
- return interaction.followUp({ content, flags: "Ephemeral" });
1545
- }
1546
- return interaction.reply({ content, flags: "Ephemeral" });
1547
- }
1548
- try {
1549
- return await command.run(client, client, interaction);
1550
- } catch (err) {
1551
- await sendCommandErrorEmbed(client, err, interaction.guild, interaction);
1552
- throw err;
1553
- }
1554
- }
1728
+ // src/utils/process.utils.ts
1729
+ import { readFileSync } from "fs";
1730
+ import { join } from "path";
1731
+ function getPackageJson() {
1732
+ return JSON.parse(readFileSync(join(process.cwd(), "package.json"), "utf-8"));
1733
+ }
1734
+ function getDevMode() {
1735
+ return process.argv.includes("--dev");
1736
+ }
1737
+
1738
+ // src/configs/app.config.ts
1739
+ var defaultConfig = {
1740
+ name: "Discord Bot",
1741
+ version: getPackageJson()?.version ?? "1.0.0",
1742
+ devMode: getDevMode(),
1743
+ verbose: false,
1744
+ enableCLI: false,
1745
+ disableBanner: false
1746
+ };
1747
+ var createAppConfig = createConfigFactory(defaultConfig, (config) => {
1748
+ if (!config.name) throw new Error("App name is required");
1749
+ defineGlobalToolsConfig({ devMode: config.devMode });
1555
1750
  });
1556
1751
 
1557
- // src/tools/Logger.ts
1558
- import chalk from "chalk";
1559
- var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
1560
- LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
1561
- LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
1562
- LogLevel2[LogLevel2["SUCCESS"] = 2] = "SUCCESS";
1563
- LogLevel2[LogLevel2["WARN"] = 3] = "WARN";
1564
- LogLevel2[LogLevel2["ERROR"] = 4] = "ERROR";
1565
- return LogLevel2;
1566
- })(LogLevel || {});
1567
- var LOGGER_COLORS = {
1568
- primary: "#5865F2",
1569
- success: "#57F287",
1570
- warn: "#FEE75C",
1571
- danger: "#ED4245",
1572
- muted: "#747F8D",
1573
- text: "#FFFFFF"
1752
+ // src/configs/contextCommand.config.ts
1753
+ var defaultConfig2 = {
1754
+ enabled: true,
1755
+ logExecution: true
1574
1756
  };
1575
- var Logger = class {
1576
- logPrefixEmoji;
1577
- logPrefix;
1578
- minLevel;
1579
- showTimestamp;
1580
- colorScheme;
1581
- constructor(options) {
1582
- const { prefixEmoji = null, prefix = null, minLevel = 0 /* DEBUG */, showTimestamp = true } = options || {};
1583
- this.logPrefixEmoji = prefixEmoji;
1584
- this.logPrefix = prefix;
1585
- this.minLevel = minLevel;
1586
- this.showTimestamp = showTimestamp;
1587
- this.colorScheme = {
1588
- ...LOGGER_COLORS,
1589
- ...options?.colors
1590
- };
1591
- }
1592
- formatTimestamp() {
1593
- if (!this.showTimestamp) return "";
1594
- const now = /* @__PURE__ */ new Date();
1595
- const time = now.toLocaleTimeString("en-US", {
1596
- hour12: false,
1597
- hour: "2-digit",
1598
- minute: "2-digit",
1599
- second: "2-digit"
1600
- });
1601
- return chalk.hex(this.colorScheme.muted)(`[${time}]`);
1602
- }
1603
- formatPrefix() {
1604
- if (!this.logPrefix) return "";
1605
- return chalk.bold.hex(this.colorScheme.primary)(
1606
- `${this.logPrefixEmoji ? `${this.logPrefixEmoji} ` : ""}${this.logPrefix}`
1607
- );
1608
- }
1609
- shouldLog(level) {
1610
- return level >= this.minLevel;
1611
- }
1612
- get prefixEmoji() {
1613
- return this.logPrefixEmoji;
1614
- }
1615
- get prefix() {
1616
- return this.logPrefix;
1617
- }
1618
- get colors() {
1619
- return this.colorScheme;
1620
- }
1621
- extend(extras) {
1622
- for (const [key, fn] of Object.entries(extras)) {
1623
- if (typeof fn === "function") {
1624
- this[key] = function(...args) {
1625
- return fn.call(this, ...args);
1626
- };
1627
- }
1628
- }
1629
- return this;
1630
- }
1631
- setPrefix(prefix) {
1632
- this.logPrefix = prefix;
1633
- return this;
1634
- }
1635
- setPrefixEmoji(prefixEmoji) {
1636
- this.logPrefixEmoji = prefixEmoji;
1637
- return this;
1638
- }
1639
- setMinLevel(minLevel) {
1640
- this.minLevel = minLevel;
1641
- return this;
1642
- }
1643
- setShowTimestamp(show) {
1644
- this.showTimestamp = show;
1645
- return this;
1646
- }
1647
- setColors(colors) {
1648
- this.colorScheme = {
1649
- ...LOGGER_COLORS,
1650
- ...colors
1651
- };
1652
- return this;
1653
- }
1654
- log(message, ...args) {
1655
- console.log(this.formatTimestamp(), this.formatPrefix(), message, ...args);
1656
- }
1657
- debug(message, ...args) {
1658
- if (!this.shouldLog(0 /* DEBUG */)) return;
1659
- console.log(
1660
- this.formatTimestamp(),
1661
- this.formatPrefix(),
1662
- chalk.hex(this.colorScheme.muted)("DEBUG"),
1663
- chalk.dim(message),
1664
- ...args
1665
- );
1666
- }
1667
- info(message, ...args) {
1668
- if (!this.shouldLog(1 /* INFO */)) return;
1669
- console.log(this.formatTimestamp(), this.formatPrefix(), chalk.hex("#87CEEB")("INFO"), message, ...args);
1670
- }
1671
- success(message, ...args) {
1672
- if (!this.shouldLog(2 /* SUCCESS */)) return;
1673
- console.log(
1674
- this.formatTimestamp(),
1675
- this.formatPrefix(),
1676
- chalk.bold.hex(this.colorScheme.success)("\u2713 SUCCESS"),
1677
- chalk.hex(this.colorScheme.success)(message),
1678
- ...args
1679
- );
1680
- }
1681
- warn(message, ...args) {
1682
- if (!this.shouldLog(3 /* WARN */)) return;
1683
- console.warn(
1684
- this.formatTimestamp(),
1685
- this.formatPrefix(),
1686
- chalk.bold.hex(this.colorScheme.warn)("\u26A0 WARN"),
1687
- chalk.hex(this.colorScheme.warn)(message),
1688
- ...args
1689
- );
1690
- }
1691
- error(message, error, ...args) {
1692
- if (!this.shouldLog(4 /* ERROR */)) return;
1693
- console.error(
1694
- this.formatTimestamp(),
1695
- this.formatPrefix(),
1696
- chalk.bold.hex(this.colorScheme.danger)("\u2715 ERROR"),
1697
- chalk.hex(this.colorScheme.danger)(message),
1698
- ...args
1699
- );
1700
- if (error && error.stack) {
1701
- console.error(chalk.dim(error.stack));
1702
- }
1703
- }
1704
- loader(message) {
1705
- const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
1706
- let i = 0;
1707
- const interval = setInterval(() => {
1708
- process.stdout.write(
1709
- `\r${this.formatTimestamp()} ${this.formatPrefix()} ${chalk.hex(this.colorScheme.warn)(frames[i])} ${message}`
1710
- );
1711
- i = (i + 1) % frames.length;
1712
- }, 100);
1713
- return (newMessage) => {
1714
- clearInterval(interval);
1715
- process.stdout.write(
1716
- `\r${this.formatTimestamp()} ${this.formatPrefix()} ${chalk.hex(this.colorScheme.success)("\u2713")} ${newMessage || message}
1717
- `
1718
- );
1719
- };
1720
- }
1721
- table(title, data) {
1722
- console.log(this.formatTimestamp(), this.formatPrefix(), chalk.bold(title));
1723
- Object.entries(data).forEach(([key, value]) => {
1724
- const formattedKey = chalk.hex(this.colorScheme.warn)(` ${key}`);
1725
- const formattedValue = chalk.hex(this.colorScheme.muted)(value);
1726
- console.log(`${formattedKey.padEnd(25)} ${formattedValue}`);
1727
- });
1728
- }
1729
- section(title) {
1730
- const line = "\u2500".repeat(Math.max(30, title.length + 4));
1731
- console.log(chalk.hex(this.colorScheme.muted)(`
1732
- \u250C\u2500${line}\u2500\u2510`));
1733
- console.log(
1734
- chalk.hex(this.colorScheme.muted)("\u2502 ") + chalk.bold.hex(this.colorScheme.text)(title.padEnd(line.length)) + chalk.hex(this.colorScheme.muted)(" \u2502")
1735
- );
1736
- console.log(chalk.hex(this.colorScheme.muted)(`\u2514\u2500${line}\u2500\u2518`));
1737
- }
1757
+ var createContextCommandConfig = createConfigFactory(defaultConfig2);
1758
+
1759
+ // src/configs/prefixCommand.config.ts
1760
+ var defaultConfig3 = {
1761
+ enabled: true,
1762
+ defaultPrefix: "!",
1763
+ allowMentionAsPrefix: true,
1764
+ allowCaseInsensitiveCommandNames: true,
1765
+ logExecution: true
1738
1766
  };
1739
- var logger = new Logger();
1767
+ var createPrefixCommandConfig = createConfigFactory(defaultConfig3);
1740
1768
 
1741
- // src/tools/utils.ts
1742
- function __zero(str) {
1743
- return str?.length ? str : "0";
1744
- }
1745
- function isMentionOrSnowflake(str) {
1746
- return str ? str.match(/<@[#&]?[\d]{6,}>/) || str.match(/\d{6,}/) ? true : false : false;
1747
- }
1748
- function cleanMention(str) {
1749
- return str ? str.replaceAll(/[<@#&>]/g, "").trim() : void 0;
1750
- }
1751
- async function getMessageMention(message, content, type, index = 0, idOnly) {
1752
- const args = content?.split(" ");
1753
- const arg = isMentionOrSnowflake(args?.[index]) ? cleanMention(args?.[index]) : void 0;
1754
- switch (type) {
1755
- case "user":
1756
- const userMention2 = message.mentions.users.at(index) || null;
1757
- if (!userMention2 && arg) {
1758
- return idOnly ? arg : await fetchUser(message.client, arg);
1759
- } else {
1760
- return idOnly ? userMention2?.id || null : userMention2;
1761
- }
1762
- case "member":
1763
- if (!message.guild) return null;
1764
- const member = await fetchMember(message.guild, message.mentions.users.at(index)?.id ?? arg);
1765
- return idOnly ? member?.id || null : member;
1766
- case "channel":
1767
- const channelMention = message.mentions.channels.at(index) || null;
1768
- if (!channelMention && arg) {
1769
- return idOnly ? arg : message.guild ? await fetchChannel(message.guild, arg) : message.client.channels.cache.get(__zero(arg)) ?? message.client.channels.fetch(__zero(arg));
1770
- } else {
1771
- return idOnly ? channelMention?.id || null : channelMention;
1772
- }
1773
- case "role":
1774
- const roleMention = message.mentions.roles.at(index) || null;
1775
- if (!roleMention && arg) {
1776
- return idOnly ? arg : message.guild ? await fetchRole(message.guild, arg) : null;
1777
- } else {
1778
- return idOnly ? roleMention?.id || null : roleMention;
1779
- }
1780
- default:
1781
- return null;
1782
- }
1783
- }
1784
- function getFirstMentionId(options) {
1785
- let mentionId = "";
1786
- if (options.message) {
1787
- switch (options.type) {
1788
- case "user":
1789
- mentionId = options.message.mentions.users.first()?.id || "";
1790
- break;
1791
- case "channel":
1792
- mentionId = options.message.mentions.channels.first()?.id || "";
1793
- break;
1794
- case "role":
1795
- mentionId = options.message.mentions.roles.first()?.id || "";
1796
- break;
1797
- }
1769
+ // src/configs/slashCommand.config.ts
1770
+ var defaultConfig4 = {
1771
+ logExecution: true
1772
+ };
1773
+ var createSlashCommandConfig = createConfigFactory(defaultConfig4);
1774
+
1775
+ // src/configs/staff.config.ts
1776
+ var defaultConfig5 = {
1777
+ ownerId: null,
1778
+ superUsers: [],
1779
+ superUserRoles: [],
1780
+ bypassers: [],
1781
+ bypassesGuildAdmin: {
1782
+ allBotStaff: false,
1783
+ botOwner: false,
1784
+ superUsers: false,
1785
+ bypassers: false
1786
+ },
1787
+ guild: {
1788
+ id: null,
1789
+ inviteUrl: null,
1790
+ channels: {}
1798
1791
  }
1799
- const firstArg = options.content?.split(" ")[0] || "";
1800
- return mentionId || isMentionOrSnowflake(firstArg) ? cleanMention(firstArg) : "";
1801
- }
1802
- async function fetchUser(client, userId) {
1803
- if (!userId) return null;
1804
- return client.users.cache.get(__zero(userId)) || await client.users.fetch(__zero(userId)).catch(() => null);
1805
- }
1806
- async function fetchGuild(client, guildId) {
1807
- if (!guildId) return null;
1808
- return client.guilds.cache.get(__zero(guildId)) || await client.guilds.fetch(__zero(guildId)).catch(() => null);
1809
- }
1810
- async function fetchMember(guild, memberId) {
1811
- if (!memberId) return null;
1812
- return guild.members.cache.get(__zero(memberId)) || await guild.members.fetch(__zero(memberId)).catch(() => null);
1813
- }
1814
- async function fetchChannel(guild, channelId, type) {
1815
- if (!channelId) return null;
1816
- const channel = guild.channels.cache.get(__zero(channelId)) || await guild.channels.fetch(__zero(channelId)).catch(() => null);
1817
- if (type && channel?.type !== type) return null;
1818
- return channel;
1819
- }
1820
- async function fetchRole(guild, roleId) {
1821
- if (!roleId) return null;
1822
- return guild.roles.cache.get(__zero(roleId)) || await guild.roles.fetch(__zero(roleId)).catch(() => null) || null;
1823
- }
1824
- async function fetchMessage(channel, messageId) {
1825
- if (!messageId) return null;
1826
- return channel.messages.cache.get(__zero(messageId)) || await channel.messages.fetch(__zero(messageId)).catch(() => null) || null;
1827
- }
1792
+ };
1793
+ var createStaffConfig = createConfigFactory(defaultConfig5);
1828
1794
 
1829
- // src/types/status.ts
1830
- import { ActivityType } from "discord.js";
1831
- import _11 from "lodash";
1832
- var StatusType = /* @__PURE__ */ ((StatusType2) => {
1833
- StatusType2["DND"] = "dnd";
1834
- StatusType2["Idle"] = "idle";
1835
- StatusType2["Online"] = "online";
1836
- StatusType2["Invisible"] = "invisible";
1837
- return StatusType2;
1838
- })(StatusType || {});
1839
- var defaultPresence = {
1840
- production: {
1841
- interval: 6e4,
1842
- randomize: false,
1843
- activity: [
1844
- { status: "online" /* Online */, type: ActivityType.Custom, name: "Need help? Use /help or !help" },
1845
- { status: "online" /* Online */, type: ActivityType.Custom, name: "Join our community!" },
1846
- { status: "online" /* Online */, type: ActivityType.Watching, name: "\u2728 $GUILD_COUNT servers" }
1847
- ]
1795
+ // src/client/vimcord.utils.ts
1796
+ var DEFAULT_MODULE_SUFFIXES = {
1797
+ slashCommands: ".slash",
1798
+ contextCommands: ".ctx",
1799
+ prefixCommands: ".prefix",
1800
+ events: ".event"
1801
+ };
1802
+ var configSetters = {
1803
+ app: createAppConfig,
1804
+ staff: createStaffConfig,
1805
+ slashCommands: createSlashCommandConfig,
1806
+ prefixCommands: createPrefixCommandConfig,
1807
+ contextCommands: createContextCommandConfig
1808
+ };
1809
+ var moduleImporters = {
1810
+ slashCommands: (client, options, set) => {
1811
+ const opt = options;
1812
+ const dir = Array.isArray(options) ? options : opt?.dir ?? [];
1813
+ const suffix = Array.isArray(options) ? DEFAULT_MODULE_SUFFIXES.slashCommands : opt?.suffix ?? DEFAULT_MODULE_SUFFIXES.slashCommands;
1814
+ return client.commands.slash.importFrom(dir, set, suffix);
1848
1815
  },
1849
- development: {
1850
- activity: { status: "dnd" /* DND */, type: ActivityType.Custom, name: "In development!" }
1816
+ contextCommands: (client, options, set) => {
1817
+ const opt = options;
1818
+ const dir = Array.isArray(options) ? options : opt?.dir ?? [];
1819
+ const suffix = Array.isArray(options) ? DEFAULT_MODULE_SUFFIXES.contextCommands : opt?.suffix ?? DEFAULT_MODULE_SUFFIXES.contextCommands;
1820
+ return client.commands.context.importFrom(dir, set, suffix);
1821
+ },
1822
+ prefixCommands: (client, options, set) => {
1823
+ const opt = options;
1824
+ const dir = Array.isArray(options) ? options : opt?.dir ?? [];
1825
+ const suffix = Array.isArray(options) ? DEFAULT_MODULE_SUFFIXES.prefixCommands : opt?.suffix ?? DEFAULT_MODULE_SUFFIXES.prefixCommands;
1826
+ return client.commands.prefix.importFrom(dir, set, suffix);
1827
+ },
1828
+ events: (client, options, set) => {
1829
+ const opt = options;
1830
+ const dir = Array.isArray(options) ? options : opt?.dir ?? [];
1831
+ const suffix = Array.isArray(options) ? DEFAULT_MODULE_SUFFIXES.events : opt?.suffix ?? DEFAULT_MODULE_SUFFIXES.events;
1832
+ return client.events.importFrom(dir, set, suffix);
1851
1833
  }
1852
1834
  };
1853
- function createVimcordStatusConfig(options = {}) {
1854
- return _11.merge(defaultPresence, options);
1835
+ function defineClientOptions(options) {
1836
+ return options;
1837
+ }
1838
+ function defineVimcordFeatures(features) {
1839
+ return features;
1840
+ }
1841
+ function defineVimcordConfig(config) {
1842
+ return {
1843
+ app: createAppConfig(config.app),
1844
+ staff: createStaffConfig(config.staff),
1845
+ slashCommands: createSlashCommandConfig(config.slashCommands),
1846
+ prefixCommands: createPrefixCommandConfig(config.prefixCommands),
1847
+ contextCommands: createContextCommandConfig(config.contextCommands)
1848
+ };
1855
1849
  }
1850
+ var useClient = Vimcord.getInstance;
1851
+ var useReadyClient = Vimcord.getReadyInstance;
1852
+ var createClient = Vimcord.create;
1856
1853
 
1857
- // src/modules/status.manager.ts
1858
- import EventEmitter from "events";
1859
- import { $ as $2 } from "qznt";
1860
- var StatusManager = class {
1861
- client;
1862
- logger;
1863
- emitter = new EventEmitter();
1864
- lastActivity = null;
1865
- lastActivityIndex = 0;
1866
- task = null;
1867
- constructor(client) {
1868
- this.client = client;
1869
- this.logger = new Logger({ prefixEmoji: "\u{1F4AC}", prefix: `StatusManager (i${this.client.clientId})` });
1870
- this.emitter.on("changed", (activity) => {
1871
- if (this.client.config.app.verbose) {
1872
- this.logger.debug(`Status changed to '${activity.name}'`);
1873
- }
1874
- });
1875
- this.emitter.on("cleared", () => {
1876
- if (this.client.config.app.verbose) {
1877
- this.logger.debug("Status cleared");
1878
- }
1879
- });
1880
- }
1881
- clearData() {
1882
- this.task?.stop();
1883
- this.task = null;
1884
- this.lastActivity = null;
1885
- this.lastActivityIndex = 0;
1886
- return this;
1887
- }
1888
- async getReadyClient() {
1889
- const client = await this.client.waitForReady();
1890
- if (!client.user) throw new Error("Cannot manage the client's activity when its user is not hydrated");
1891
- return client;
1892
- }
1893
- async formatActivityName(name) {
1894
- name = name.replace("$USER_COUNT", $2.format.number(this.client.users.cache.size)).replace("$GUILD_COUNT", $2.format.number(this.client.guilds.cache.size)).replace(
1895
- "$INVITE",
1896
- this.client.config.staff.guild.inviteUrl ? this.client.config.staff.guild.inviteUrl : "<STAFF_INVITE_URL_NOT_SET>"
1897
- );
1898
- if (name.includes("$STAFF_GUILD_MEMBER_COUNT")) {
1899
- await fetchGuild(this.client, this.client.config.staff.guild.id).then((guild) => {
1900
- if (!guild) return name = name.replace("$STAFF_GUILD_MEMBER_COUNT", "<STAFF_GUILD_NOT_FOUND>");
1901
- name = name.replace("$STAFF_GUILD_MEMBER_COUNT", $2.format.number(guild.members.cache.size));
1902
- }).catch((err) => this.logger.error("Failed to fetch the staff guild", err));
1903
- }
1904
- return name;
1905
- }
1906
- async setActivity(activity) {
1907
- const client = await this.getReadyClient();
1908
- activity.name = await this.formatActivityName(activity.name);
1909
- client.user.setStatus(activity.status);
1910
- client.user.setActivity({ name: activity.name, type: activity.type, url: activity.streamUrl });
1911
- this.emitter.emit("changed", activity);
1912
- }
1913
- async statusRotationTask(clientStatus) {
1914
- let activity;
1915
- if (clientStatus.randomize && Array.isArray(clientStatus.activity)) {
1916
- activity = $2.rnd.choice(clientStatus.activity, { not: this.lastActivity });
1917
- this.lastActivity = activity;
1918
- } else {
1919
- const activityIndex = (this.lastActivityIndex + 1) % clientStatus.activity.length;
1920
- this.lastActivityIndex = activityIndex;
1921
- activity = clientStatus.activity[activityIndex];
1922
- }
1923
- await this.setActivity(activity);
1924
- this.emitter.emit("rotation", activity);
1925
- }
1926
- async scheduleStatusRotation(clientStatus) {
1927
- if (!clientStatus.interval) throw new Error("Cannot create client activity interval without interval time");
1928
- this.task?.stop();
1929
- this.task = null;
1930
- this.task = new $2.Loop(() => this.statusRotationTask(clientStatus), $2.math.ms(clientStatus.interval), true);
1931
- this.start();
1932
- }
1933
- start() {
1934
- if (this.task) {
1935
- this.task.start();
1936
- this.emitter.emit("started", this.task);
1937
- }
1938
- return this;
1939
- }
1940
- pause() {
1941
- if (this.task) {
1942
- this.task.stop();
1943
- this.emitter.emit("paused", this.task);
1944
- }
1945
- return this;
1854
+ // src/modules/command.manager.ts
1855
+ import { Routes } from "discord.js";
1856
+
1857
+ // src/utils/import.utils.ts
1858
+ import path from "path";
1859
+ import { $ } from "qznt";
1860
+ function getProcessDir() {
1861
+ const mainPath = process.argv[1];
1862
+ if (!mainPath) return "";
1863
+ return path.dirname(mainPath);
1864
+ }
1865
+ async function importModulesFromDir(dir, suffix) {
1866
+ const cwd = getProcessDir();
1867
+ const MODULE_RELATIVE_PATH = path.join(cwd, dir);
1868
+ const MODULE_LOG_PATH = dir;
1869
+ const files = $.fs.readDir(MODULE_RELATIVE_PATH).filter((fn) => fn.endsWith(`${suffix ? `.${suffix}` : ""}.js`) || fn.endsWith(`${suffix ? `.${suffix}` : ""}.ts`));
1870
+ if (!files.length) {
1871
+ return [];
1946
1872
  }
1947
- async set(status) {
1948
- const statusConfig = createVimcordStatusConfig(status);
1949
- let clientStatus;
1950
- if (this.client.config.app.devMode) {
1951
- clientStatus = statusConfig.development;
1952
- } else {
1953
- clientStatus = statusConfig.production;
1954
- }
1955
- if (!clientStatus.interval) {
1956
- await this.setActivity(Array.isArray(clientStatus.activity) ? clientStatus.activity[0] : clientStatus.activity);
1957
- } else {
1958
- await this.scheduleStatusRotation(clientStatus);
1959
- }
1960
- return this;
1873
+ const modules = await Promise.all(
1874
+ files.map(async (fn) => {
1875
+ let _path = path.join(MODULE_RELATIVE_PATH, fn);
1876
+ let _logPath = `./${path.join(MODULE_LOG_PATH, fn)}`;
1877
+ let _module;
1878
+ try {
1879
+ delete __require.cache[__require.resolve(_path)];
1880
+ _module = __require(_path);
1881
+ } catch (err) {
1882
+ console.warn(`Failed to import module at '${_logPath}'`, err);
1883
+ _module = null;
1884
+ }
1885
+ return { module: _module, path: _logPath };
1886
+ })
1887
+ );
1888
+ const filteredModules = modules.filter((m) => m.module);
1889
+ if (!filteredModules.length) {
1890
+ console.warn(`No valid modules were found in directory '${dir}'`);
1961
1891
  }
1962
- async destroy() {
1963
- if (this.task) {
1964
- this.task.stop();
1965
- this.task = null;
1966
- this.emitter.emit("destroyed");
1967
- await this.clear();
1968
- }
1969
- return this;
1892
+ return filteredModules;
1893
+ }
1894
+
1895
+ // src/modules/base-module.importer.ts
1896
+ var ModuleImporter = class {
1897
+ client;
1898
+ constructor(client) {
1899
+ this.client = client;
1970
1900
  }
1971
- async clear() {
1972
- const client = await this.getReadyClient();
1973
- this.clearData();
1974
- client.user.setActivity({ name: "" });
1975
- this.emitter.emit("cleared");
1976
- return this;
1901
+ async importFrom(dir, set = false, suffix) {
1902
+ if (set) this.items.clear();
1903
+ const dirs = Array.isArray(dir) ? dir : [dir];
1904
+ const modules = [];
1905
+ const effectiveSuffix = Array.isArray(suffix) ? suffix[0] : suffix ?? this.itemSuffix;
1906
+ for (const _dir of dirs) {
1907
+ const results = await importModulesFromDir(_dir, effectiveSuffix ?? void 0);
1908
+ modules.push(...results.map(({ module }) => module.default));
1909
+ }
1910
+ for (const module of modules) {
1911
+ const name = this.getName(module);
1912
+ this.items.set(name, module);
1913
+ }
1914
+ this.client.logger.moduleLoaded(this.itemName, modules.length);
1915
+ return this.items;
1977
1916
  }
1978
1917
  };
1979
1918
 
1980
1919
  // src/modules/command.manager.ts
1981
- import { Routes } from "discord.js";
1982
- var BaseCommandManager = class {
1920
+ var BaseCommandManager = class extends ModuleImporter {
1983
1921
  type;
1984
- client;
1985
- commands = /* @__PURE__ */ new Map();
1986
- moduleSuffix;
1987
- constructor(client, type, moduleSuffix) {
1922
+ items = /* @__PURE__ */ new Map();
1923
+ itemSuffix;
1924
+ constructor(client, type, itemSuffix) {
1925
+ super(client);
1988
1926
  this.type = type;
1989
- this.client = client;
1990
- this.moduleSuffix = moduleSuffix;
1927
+ switch (type) {
1928
+ case 0 /* Slash */:
1929
+ this.itemSuffix = itemSuffix ?? DEFAULT_MODULE_SUFFIXES.slashCommands;
1930
+ break;
1931
+ case 2 /* Context */:
1932
+ this.itemSuffix = itemSuffix ?? DEFAULT_MODULE_SUFFIXES.contextCommands;
1933
+ break;
1934
+ case 1 /* Prefix */:
1935
+ this.itemSuffix = itemSuffix ?? DEFAULT_MODULE_SUFFIXES.prefixCommands;
1936
+ break;
1937
+ }
1938
+ }
1939
+ get commands() {
1940
+ return this.items;
1941
+ }
1942
+ get itemName() {
1943
+ switch (this.type) {
1944
+ case 0 /* Slash */:
1945
+ return "Slash Commands";
1946
+ case 2 /* Context */:
1947
+ return "Context Commands";
1948
+ case 1 /* Prefix */:
1949
+ return "Prefix Commands";
1950
+ }
1951
+ }
1952
+ getName(module) {
1953
+ return "builder" in module ? module.builder.name : module.options.name;
1991
1954
  }
1992
1955
  /**
1993
1956
  * Gets a command by name.
@@ -1996,7 +1959,7 @@ var BaseCommandManager = class {
1996
1959
  if (this.type === 1 /* Prefix */) {
1997
1960
  const config = this.client.config.prefixCommands;
1998
1961
  const search = config.allowCaseInsensitiveCommandNames ? name.toLowerCase() : name;
1999
- return Array.from(this.commands.values()).find((cmd) => {
1962
+ return Array.from(this.items.values()).find((cmd) => {
2000
1963
  const commandName = "builder" in cmd ? cmd.builder.name : cmd.options.name;
2001
1964
  const trigger = config.allowCaseInsensitiveCommandNames ? commandName.toLowerCase() : commandName;
2002
1965
  if (trigger === search) return true;
@@ -2007,7 +1970,7 @@ var BaseCommandManager = class {
2007
1970
  }
2008
1971
  });
2009
1972
  } else {
2010
- return this.commands.get(name);
1973
+ return this.items.get(name);
2011
1974
  }
2012
1975
  }
2013
1976
  /**
@@ -2016,7 +1979,7 @@ var BaseCommandManager = class {
2016
1979
  getAll(options = {}) {
2017
1980
  const matchedCommands = /* @__PURE__ */ new Map();
2018
1981
  const isDev = this.client.config.app.devMode;
2019
- for (const cmd of this.commands.values()) {
1982
+ for (const cmd of this.items.values()) {
2020
1983
  const commandName = "builder" in cmd ? cmd.builder.name : cmd.options.name;
2021
1984
  if (options.names || options.fuzzyNames) {
2022
1985
  const nameMatched = options.names?.includes(commandName) || options.fuzzyNames?.some((fuzzy) => commandName.includes(fuzzy));
@@ -2043,7 +2006,7 @@ var BaseCommandManager = class {
2043
2006
  */
2044
2007
  sortByCategory() {
2045
2008
  const categories = /* @__PURE__ */ new Map();
2046
- for (const cmd of this.commands.values()) {
2009
+ for (const cmd of this.items.values()) {
2047
2010
  const metadata = cmd.options.metadata;
2048
2011
  if (!metadata?.category) continue;
2049
2012
  let entry = categories.get(metadata.category);
@@ -2066,52 +2029,20 @@ var BaseCommandManager = class {
2066
2029
  return cat;
2067
2030
  });
2068
2031
  }
2069
- /**
2070
- * Imports command modules from a directory.
2071
- * @param dir Path of one or more folders.
2072
- * @param set Replaces imported command modules with the ones found.
2073
- */
2074
- async importFrom(dir, set = false) {
2075
- if (set) this.commands.clear();
2076
- const dirs = Array.isArray(dir) ? dir : [dir];
2077
- const modules = [];
2078
- for (const _dir of dirs) {
2079
- const results = await importModulesFromDir(_dir, this.moduleSuffix);
2080
- modules.push(...results.map(({ module }) => module.default));
2081
- }
2082
- for (const module of modules) {
2083
- const commandName = "builder" in module ? module.builder.name : module.options.name;
2084
- this.commands.set(commandName, module);
2085
- }
2086
- let moduleType;
2087
- switch (this.type) {
2088
- case 0 /* Slash */:
2089
- moduleType = "Slash Commands";
2090
- break;
2091
- case 2 /* Context */:
2092
- moduleType = "Context Commands";
2093
- break;
2094
- case 1 /* Prefix */:
2095
- moduleType = "Prefix Commands";
2096
- break;
2097
- }
2098
- this.client.logger.moduleLoaded(moduleType, modules.length);
2099
- return this.commands;
2100
- }
2101
2032
  };
2102
2033
  var SlashCommandManager = class extends BaseCommandManager {
2103
2034
  constructor(client) {
2104
- super(client, 0 /* Slash */, client.config.app.moduleSuffixes.slashCommand);
2035
+ super(client, 0 /* Slash */);
2105
2036
  }
2106
2037
  };
2107
2038
  var ContextCommandManager = class extends BaseCommandManager {
2108
2039
  constructor(client) {
2109
- super(client, 2 /* Context */, client.config.app.moduleSuffixes.contextCommand);
2040
+ super(client, 2 /* Context */);
2110
2041
  }
2111
2042
  };
2112
2043
  var PrefixCommandManager = class extends BaseCommandManager {
2113
2044
  constructor(client) {
2114
- super(client, 1 /* Prefix */, client.config.app.moduleSuffixes.prefixCommand);
2045
+ super(client, 1 /* Prefix */);
2115
2046
  }
2116
2047
  };
2117
2048
  var CommandManager = class {
@@ -2129,7 +2060,7 @@ var CommandManager = class {
2129
2060
  return [...this.slash.getAll(options), ...this.context.getAll(options)];
2130
2061
  }
2131
2062
  async registerGlobal(options = {}) {
2132
- const client = await this.client.waitForReady();
2063
+ const client = await Vimcord.getReadyInstance(this.client.clientId);
2133
2064
  if (!client.rest) {
2134
2065
  console.error(`[CommandManager] \u2716 Failed to register app commands globally: REST is not initialized`);
2135
2066
  return;
@@ -2139,16 +2070,21 @@ var CommandManager = class {
2139
2070
  console.log("[CommandManager] No commands to register globally");
2140
2071
  return;
2141
2072
  }
2142
- console.log(`[CommandManager] Registering (${commands.length}) commands globally...`);
2073
+ console.log(
2074
+ `[CommandManager] Registering (${commands.length}) ${commands.length === 1 ? "command" : "commands"} globally...`
2075
+ );
2143
2076
  try {
2144
2077
  await client.rest.put(Routes.applicationCommands(client.user.id), { body: commands });
2145
- console.log(`[CommandManager] \u2714 Registered app commands globally`);
2078
+ console.log(`[CommandManager] \u2714 Registered app ${commands.length === 1 ? "command" : "commands"} globally`);
2146
2079
  } catch (err) {
2147
- console.error(`[CommandManager] \u2716 Failed to register app commands globally`, err);
2080
+ console.error(
2081
+ `[CommandManager] \u2716 Failed to register app ${commands.length === 1 ? "command" : "commands"} globally`,
2082
+ err
2083
+ );
2148
2084
  }
2149
2085
  }
2150
2086
  async unregisterGlobal() {
2151
- const client = await this.client.waitForReady();
2087
+ const client = await Vimcord.getReadyInstance(this.client.clientId);
2152
2088
  if (!client.rest) {
2153
2089
  console.error(`[CommandManager] \u2716 Failed to remove app commands globally: REST is not initialized`);
2154
2090
  return;
@@ -2161,7 +2097,7 @@ var CommandManager = class {
2161
2097
  }
2162
2098
  }
2163
2099
  async registerGuild(options = {}) {
2164
- const client = await this.client.waitForReady();
2100
+ const client = await Vimcord.getReadyInstance(this.client.clientId);
2165
2101
  if (!client.rest) {
2166
2102
  console.error(`[CommandManager] \u2716 Failed to register app commands by guild: REST is not initialized`);
2167
2103
  return;
@@ -2172,21 +2108,28 @@ var CommandManager = class {
2172
2108
  return;
2173
2109
  }
2174
2110
  const guildIds = options.guilds || client.guilds.cache.map((g) => g.id);
2175
- console.log(`[CommandManager] Registering (${commands.length}) commands for ${guildIds.length} guilds...`);
2111
+ console.log(
2112
+ `[CommandManager] Registering (${commands.length}) ${commands.length === 1 ? "command" : "commands"} for ${guildIds.length} guilds...`
2113
+ );
2176
2114
  await Promise.all(
2177
2115
  guildIds.map(
2178
2116
  (guildId) => client.rest.put(Routes.applicationGuildCommands(client.user.id, guildId), { body: commands }).then(() => {
2179
2117
  const gName = client.guilds.cache.get(guildId)?.name || "n/a";
2180
- console.log(`[CommandManager] \u2714 Set app commands in guild: ${guildId} (${gName})`);
2118
+ console.log(
2119
+ `[CommandManager] \u2714 Set app ${commands.length === 1 ? "command" : "commands"} in guild: ${guildId} (${gName})`
2120
+ );
2181
2121
  }).catch((err) => {
2182
2122
  const gName = client.guilds.cache.get(guildId)?.name || "n/a";
2183
- console.log(`[CommandManager] \u2716 Failed to set app commands in guild: ${guildId} (${gName})`, err);
2123
+ console.log(
2124
+ `[CommandManager] \u2716 Failed to set app ${commands.length === 1 ? "command" : "commands"} in guild: ${guildId} (${gName})`,
2125
+ err
2126
+ );
2184
2127
  })
2185
2128
  )
2186
2129
  );
2187
2130
  }
2188
2131
  async unregisterGuild(options = {}) {
2189
- const client = await this.client.waitForReady();
2132
+ const client = await Vimcord.getReadyInstance(this.client.clientId);
2190
2133
  if (!client.rest) {
2191
2134
  console.error(`[CommandManager] \u2716 Failed to register app commands by guild: REST is not initialized`);
2192
2135
  return;
@@ -2203,12 +2146,13 @@ var CommandManager = class {
2203
2146
 
2204
2147
  // src/modules/event.manager.ts
2205
2148
  import { Events } from "discord.js";
2206
- var EventManager = class {
2207
- client;
2208
- events = /* @__PURE__ */ new Map();
2149
+ var EventManager = class extends ModuleImporter {
2150
+ items = /* @__PURE__ */ new Map();
2151
+ itemSuffix = "event";
2152
+ itemName = "Event Handlers";
2209
2153
  logger;
2210
2154
  constructor(client) {
2211
- this.client = client;
2155
+ super(client);
2212
2156
  this.logger = new Logger({ prefixEmoji: "\u{1F4CB}", prefix: `EventManager (i${this.client.clientId})` });
2213
2157
  for (const event of Object.values(Events)) {
2214
2158
  client.on(
@@ -2217,9 +2161,12 @@ var EventManager = class {
2217
2161
  );
2218
2162
  }
2219
2163
  }
2164
+ getName(module) {
2165
+ return module.name;
2166
+ }
2220
2167
  register(...events) {
2221
2168
  for (const event of events) {
2222
- this.events.set(event.name, event);
2169
+ this.items.set(event.name, event);
2223
2170
  if (this.client.config.app.verbose) {
2224
2171
  this.logger.debug(`'${event.name}' registered for EventType '${event.event}'`);
2225
2172
  }
@@ -2227,95 +2174,348 @@ var EventManager = class {
2227
2174
  }
2228
2175
  unregister(...names) {
2229
2176
  for (const name of names) {
2230
- const event = this.events.get(name);
2177
+ const event = this.items.get(name);
2231
2178
  if (!event) continue;
2232
- this.events.delete(name);
2179
+ this.items.delete(name);
2233
2180
  if (this.client.config.app.verbose) {
2234
2181
  this.logger.debug(`'${event.name}' unregistered for EventType '${event.event}'`);
2235
2182
  }
2236
2183
  }
2237
2184
  }
2238
- clear() {
2239
- this.events.forEach((e) => this.unregister(e.name));
2240
- this.events.clear();
2185
+ clear() {
2186
+ this.items.forEach((e) => this.unregister(e.name));
2187
+ this.items.clear();
2188
+ }
2189
+ get(name) {
2190
+ return this.items.get(name);
2191
+ }
2192
+ getByTag(tag) {
2193
+ return Array.from(this.items.values()).filter((event) => event.metadata?.tags?.includes(tag));
2194
+ }
2195
+ getByCategory(category) {
2196
+ return Array.from(this.items.values()).filter((event) => event.metadata?.category?.includes(category));
2197
+ }
2198
+ getByEvent(eventType) {
2199
+ return Array.from(this.items.values()).filter((event) => event.event === eventType);
2200
+ }
2201
+ async executeEvents(eventType, ...args) {
2202
+ const events = this.getByEvent(eventType);
2203
+ if (!events.length) return;
2204
+ const sortedEvents = events.sort((a, b) => b.priority - a.priority);
2205
+ await Promise.all(
2206
+ sortedEvents.map(async (event) => {
2207
+ try {
2208
+ await event.execute?.(this.client, ...args);
2209
+ if (event.once) {
2210
+ this.unregister(event.name);
2211
+ }
2212
+ } catch (err) {
2213
+ this.logger.error(`'${event.name}' failed to execute`, err);
2214
+ }
2215
+ })
2216
+ );
2217
+ }
2218
+ };
2219
+
2220
+ // src/tools/utils.ts
2221
+ var MENTION_OR_SNOWFLAKE_REGEX = /<@[#&]?[\d]{6,}>|[\d]{6,}/;
2222
+ var fetchUserPromises = /* @__PURE__ */ new Map();
2223
+ var fetchGuildPromises = /* @__PURE__ */ new Map();
2224
+ var fetchMemberPromises = /* @__PURE__ */ new Map();
2225
+ var fetchChannelPromises = /* @__PURE__ */ new Map();
2226
+ var fetchMessagePromises = /* @__PURE__ */ new Map();
2227
+ var fetchRolePromises = /* @__PURE__ */ new Map();
2228
+ function createCachedFetch(cache, fetchFn, cacheKey) {
2229
+ const cached = cache.get(cacheKey);
2230
+ if (cached) return cached;
2231
+ const promise = fetchFn().finally(() => cache.delete(cacheKey));
2232
+ cache.set(cacheKey, promise);
2233
+ return promise;
2234
+ }
2235
+ function __zero(str) {
2236
+ return str?.length ? str : "0";
2237
+ }
2238
+ function isMentionOrSnowflake(str) {
2239
+ return str ? MENTION_OR_SNOWFLAKE_REGEX.test(str) : false;
2240
+ }
2241
+ function cleanMention(str) {
2242
+ return str ? str.replaceAll(/[<@#&>]/g, "").trim() : void 0;
2243
+ }
2244
+ async function getMessageMention(message, content, type, index = 0, idOnly) {
2245
+ const args = content?.split(" ");
2246
+ const arg = isMentionOrSnowflake(args?.[index]) ? cleanMention(args?.[index]) : void 0;
2247
+ switch (type) {
2248
+ case "user": {
2249
+ const userMention2 = message.mentions.users.at(index) || null;
2250
+ if (!userMention2 && arg) {
2251
+ return idOnly ? arg : await fetchUser(message.client, arg);
2252
+ }
2253
+ return idOnly ? userMention2?.id || null : userMention2;
2254
+ }
2255
+ case "member": {
2256
+ if (!message.guild) return null;
2257
+ const member = await fetchMember(message.guild, message.mentions.users.at(index)?.id ?? arg);
2258
+ return idOnly ? member?.id || null : member;
2259
+ }
2260
+ case "channel": {
2261
+ const channelMention = message.mentions.channels.at(index) || null;
2262
+ if (!channelMention && arg) {
2263
+ if (idOnly) return arg;
2264
+ const channel = message.guild ? await fetchChannel(message.guild, arg) : message.client.channels.cache.get(__zero(arg)) ?? message.client.channels.fetch(__zero(arg));
2265
+ return channel;
2266
+ }
2267
+ return idOnly ? channelMention?.id || null : channelMention;
2268
+ }
2269
+ case "role": {
2270
+ const roleMention = message.mentions.roles.at(index) || null;
2271
+ if (!roleMention && arg) {
2272
+ if (idOnly) return arg;
2273
+ return message.guild ? await fetchRole(message.guild, arg) : null;
2274
+ }
2275
+ return idOnly ? roleMention?.id || null : roleMention;
2276
+ }
2277
+ default:
2278
+ return null;
2279
+ }
2280
+ }
2281
+ function getFirstMentionId(options) {
2282
+ let mentionId = "";
2283
+ if (options.message) {
2284
+ switch (options.type) {
2285
+ case "user":
2286
+ mentionId = options.message.mentions.users.first()?.id || "";
2287
+ break;
2288
+ case "member":
2289
+ mentionId = options.message.mentions.members?.first()?.id || "";
2290
+ break;
2291
+ case "channel":
2292
+ mentionId = options.message.mentions.channels.first()?.id || "";
2293
+ break;
2294
+ case "role":
2295
+ mentionId = options.message.mentions.roles.first()?.id || "";
2296
+ break;
2297
+ }
2298
+ }
2299
+ const firstArg = options.content?.split(" ")[0] || "";
2300
+ return mentionId || isMentionOrSnowflake(firstArg) ? cleanMention(firstArg) : "";
2301
+ }
2302
+ async function fetchUser(client, userId) {
2303
+ if (!userId) return null;
2304
+ const key = `${client.user.id}-${userId}`;
2305
+ const cached = client.users.cache.get(__zero(userId));
2306
+ if (cached) return cached;
2307
+ return createCachedFetch(fetchUserPromises, () => client.users.fetch(__zero(userId)).catch(() => null), key);
2308
+ }
2309
+ async function fetchGuild(client, guildId) {
2310
+ if (!guildId) return null;
2311
+ const key = `${client.user.id}-${guildId}`;
2312
+ const cached = client.guilds.cache.get(__zero(guildId));
2313
+ if (cached) return cached;
2314
+ return createCachedFetch(fetchGuildPromises, () => client.guilds.fetch(__zero(guildId)).catch(() => null), key);
2315
+ }
2316
+ async function fetchMember(guild, memberId) {
2317
+ if (!memberId) return null;
2318
+ const key = `${guild.id}-${memberId}`;
2319
+ const cached = guild.members.cache.get(__zero(memberId));
2320
+ if (cached) return cached;
2321
+ return createCachedFetch(fetchMemberPromises, () => guild.members.fetch(__zero(memberId)).catch(() => null), key);
2322
+ }
2323
+ async function fetchChannel(guild, channelId, type) {
2324
+ if (!channelId) return null;
2325
+ const key = `${guild.id}-${channelId}`;
2326
+ const cached = guild.channels.cache.get(__zero(channelId)) ?? null;
2327
+ if (cached) {
2328
+ if (type && cached.type !== type) return null;
2329
+ return cached;
2330
+ }
2331
+ const channel = await createCachedFetch(
2332
+ fetchChannelPromises,
2333
+ () => guild.channels.fetch(__zero(channelId)).catch(() => null),
2334
+ key
2335
+ );
2336
+ if (type && channel?.type !== type) return null;
2337
+ return channel;
2338
+ }
2339
+ async function fetchMessage(channel, messageId) {
2340
+ if (!messageId) return null;
2341
+ const key = `${channel.guild.id}-${messageId}`;
2342
+ const cached = channel.messages.cache.get(__zero(messageId));
2343
+ if (cached) return cached;
2344
+ return createCachedFetch(fetchMessagePromises, () => channel.messages.fetch(__zero(messageId)).catch(() => null), key);
2345
+ }
2346
+ async function fetchRole(guild, roleId) {
2347
+ if (!roleId) return null;
2348
+ const key = `${guild.id}-${roleId}`;
2349
+ const cached = guild.roles.cache.get(__zero(roleId));
2350
+ if (cached) return cached;
2351
+ return createCachedFetch(fetchRolePromises, () => guild.roles.fetch(__zero(roleId)).catch(() => null), key);
2352
+ }
2353
+
2354
+ // src/types/status.ts
2355
+ import { ActivityType } from "discord.js";
2356
+ import _6 from "lodash";
2357
+ var StatusType = /* @__PURE__ */ ((StatusType2) => {
2358
+ StatusType2["DND"] = "dnd";
2359
+ StatusType2["Idle"] = "idle";
2360
+ StatusType2["Online"] = "online";
2361
+ StatusType2["Invisible"] = "invisible";
2362
+ return StatusType2;
2363
+ })(StatusType || {});
2364
+ var defaultPresence = {
2365
+ production: {
2366
+ interval: 6e4,
2367
+ randomize: false,
2368
+ activity: [
2369
+ { status: "online" /* Online */, type: ActivityType.Custom, name: "Need help? Use /help or !help" },
2370
+ { status: "online" /* Online */, type: ActivityType.Custom, name: "Join our community!" },
2371
+ { status: "online" /* Online */, type: ActivityType.Watching, name: "\u2728 $GUILD_COUNT servers" }
2372
+ ]
2373
+ },
2374
+ development: {
2375
+ activity: { status: "dnd" /* DND */, type: ActivityType.Custom, name: "In development!" }
2376
+ }
2377
+ };
2378
+ function createVimcordStatusConfig(options = {}) {
2379
+ return _6.merge(defaultPresence, options);
2380
+ }
2381
+
2382
+ // src/modules/status.manager.ts
2383
+ import EventEmitter from "events";
2384
+ import { $ as $2 } from "qznt";
2385
+ var StatusManager = class {
2386
+ client;
2387
+ logger;
2388
+ emitter = new EventEmitter();
2389
+ lastActivity = null;
2390
+ lastActivityIndex = 0;
2391
+ task = null;
2392
+ constructor(client) {
2393
+ this.client = client;
2394
+ this.logger = new Logger({ prefixEmoji: "\u{1F4AC}", prefix: `StatusManager (i${this.client.clientId})` });
2395
+ this.emitter.on("changed", (activity) => {
2396
+ if (this.client.config.app.verbose) {
2397
+ this.logger.debug(`Status changed to '${activity.name}'`);
2398
+ }
2399
+ });
2400
+ this.emitter.on("cleared", () => {
2401
+ if (this.client.config.app.verbose) {
2402
+ this.logger.debug("Status cleared");
2403
+ }
2404
+ });
2405
+ }
2406
+ clearData() {
2407
+ this.task?.stop();
2408
+ this.task = null;
2409
+ this.lastActivity = null;
2410
+ this.lastActivityIndex = 0;
2411
+ return this;
2412
+ }
2413
+ async getReadyClient() {
2414
+ const client = await Vimcord.getReadyInstance(this.client.clientId);
2415
+ if (!client.user) throw new Error("Cannot manage the client's activity when its user is not hydrated");
2416
+ return client;
2417
+ }
2418
+ async formatActivityName(name) {
2419
+ name = name.replace("$USER_COUNT", $2.format.number(this.client.users.cache.size)).replace("$GUILD_COUNT", $2.format.number(this.client.guilds.cache.size)).replace(
2420
+ "$INVITE",
2421
+ this.client.config.staff.guild.inviteUrl ? this.client.config.staff.guild.inviteUrl : "<STAFF_INVITE_URL_NOT_SET>"
2422
+ );
2423
+ if (name.includes("$STAFF_GUILD_MEMBER_COUNT")) {
2424
+ await fetchGuild(this.client, this.client.config.staff.guild.id).then((guild) => {
2425
+ if (!guild) return name = name.replace("$STAFF_GUILD_MEMBER_COUNT", "<STAFF_GUILD_NOT_FOUND>");
2426
+ name = name.replace("$STAFF_GUILD_MEMBER_COUNT", $2.format.number(guild.members.cache.size));
2427
+ }).catch((err) => this.logger.error("Failed to fetch the staff guild", err));
2428
+ }
2429
+ return name;
2430
+ }
2431
+ async setActivity(activity) {
2432
+ const client = await this.getReadyClient();
2433
+ activity.name = await this.formatActivityName(activity.name);
2434
+ client.user.setStatus(activity.status);
2435
+ client.user.setActivity({ name: activity.name, type: activity.type, url: activity.streamUrl });
2436
+ this.emitter.emit("changed", activity);
2241
2437
  }
2242
- get(name) {
2243
- return this.events.get(name);
2438
+ async statusRotationTask(clientStatus) {
2439
+ let activity;
2440
+ if (clientStatus.randomize && Array.isArray(clientStatus.activity)) {
2441
+ activity = $2.rnd.choice(clientStatus.activity, { not: this.lastActivity });
2442
+ this.lastActivity = activity;
2443
+ } else {
2444
+ const activityIndex = (this.lastActivityIndex + 1) % clientStatus.activity.length;
2445
+ this.lastActivityIndex = activityIndex;
2446
+ activity = clientStatus.activity[activityIndex];
2447
+ }
2448
+ await this.setActivity(activity);
2449
+ this.emitter.emit("rotation", activity);
2244
2450
  }
2245
- getByTag(tag) {
2246
- return Array.from(this.events.values()).filter((event) => event.metadata?.tags?.includes(tag));
2451
+ async scheduleStatusRotation(clientStatus) {
2452
+ if (!clientStatus.interval) throw new Error("Cannot create client activity interval without interval time");
2453
+ this.task?.stop();
2454
+ this.task = null;
2455
+ this.task = new $2.Loop(() => this.statusRotationTask(clientStatus), $2.math.ms(clientStatus.interval), true);
2456
+ this.start();
2247
2457
  }
2248
- getByCategory(category) {
2249
- return Array.from(this.events.values()).filter((event) => event.metadata?.category?.includes(category));
2458
+ start() {
2459
+ if (this.task) {
2460
+ this.task.start();
2461
+ this.emitter.emit("started", this.task);
2462
+ }
2463
+ return this;
2250
2464
  }
2251
- getByEvent(eventType) {
2252
- return Array.from(this.events.values()).filter((event) => event.event === eventType);
2465
+ pause() {
2466
+ if (this.task) {
2467
+ this.task.stop();
2468
+ this.emitter.emit("paused", this.task);
2469
+ }
2470
+ return this;
2253
2471
  }
2254
- async executeEvents(eventType, ...args) {
2255
- const events = this.getByEvent(eventType);
2256
- if (!events.length) return;
2257
- const sortedEvents = events.sort((a, b) => b.priority - a.priority);
2258
- await Promise.all(
2259
- sortedEvents.map(async (event) => {
2260
- try {
2261
- await event.execute?.(this.client, ...args);
2262
- if (event.once) {
2263
- this.unregister(event.name);
2264
- }
2265
- } catch (err) {
2266
- this.logger.error(`'${event.name}' failed to execute`, err);
2267
- }
2268
- })
2269
- );
2472
+ async set(status) {
2473
+ const statusConfig = createVimcordStatusConfig(status);
2474
+ let clientStatus;
2475
+ if (this.client.config.app.devMode) {
2476
+ clientStatus = statusConfig.development;
2477
+ } else {
2478
+ clientStatus = statusConfig.production;
2479
+ }
2480
+ if (!clientStatus.interval) {
2481
+ await this.setActivity(Array.isArray(clientStatus.activity) ? clientStatus.activity[0] : clientStatus.activity);
2482
+ } else {
2483
+ await this.scheduleStatusRotation(clientStatus);
2484
+ }
2485
+ return this;
2270
2486
  }
2271
- /** Import event modules that end with `.event` */
2272
- async importFrom(dir, replaceAll) {
2273
- dir = Array.isArray(dir) ? dir : [dir];
2274
- const eventModules = await Promise.all(
2275
- dir.map((dir2) => importModulesFromDir(dir2, "event"))
2276
- );
2277
- if (replaceAll) {
2278
- this.clear();
2279
- }
2280
- let importedEvents = 0;
2281
- let ignoredEvents = 0;
2282
- for (const event of eventModules.flat()) {
2283
- if (!event.module.default.enabled) {
2284
- ignoredEvents++;
2285
- } else {
2286
- importedEvents++;
2287
- }
2288
- this.register(event.module.default);
2487
+ async destroy() {
2488
+ if (this.task) {
2489
+ this.task.stop();
2490
+ this.task = null;
2491
+ this.emitter.emit("destroyed");
2492
+ await this.clear();
2289
2493
  }
2290
- this.client.logger.moduleLoaded("Event Handlers", importedEvents, ignoredEvents);
2291
- return this.events;
2494
+ return this;
2495
+ }
2496
+ async clear() {
2497
+ const client = await this.getReadyClient();
2498
+ this.clearData();
2499
+ client.user.setActivity({ name: "" });
2500
+ this.emitter.emit("cleared");
2501
+ return this;
2292
2502
  }
2293
2503
  };
2294
2504
 
2295
- // package.json
2296
- var version = "1.0.35";
2297
-
2298
- // src/client.ts
2299
- import { randomUUID as randomUUID3 } from "crypto";
2300
- import { $ as $4 } from "qznt";
2301
-
2302
- // src/utils/VimcordCLI.ts
2505
+ // src/utils/vimcord.cli.ts
2303
2506
  import { createInterface } from "readline";
2304
2507
  import { $ as $3 } from "qznt";
2305
-
2306
- // src/utils/clientUtils.ts
2307
- function useClient(clientId = 0) {
2308
- return Vimcord.instances.get(clientId);
2309
- }
2310
- async function useReadyClient(clientId = 0) {
2311
- return useClient(clientId)?.waitForReady();
2312
- }
2313
- function createClient(options, features = {}, config = {}) {
2314
- return new Vimcord(options, features, config);
2315
- }
2316
-
2317
- // src/utils/VimcordCLI.ts
2318
- var VimcordCLI = class {
2508
+ var VimcordCLI = class _VimcordCLI {
2509
+ static mode = "off";
2510
+ static setMode(mode) {
2511
+ if (_VimcordCLI.mode === mode) return;
2512
+ _VimcordCLI.mode = mode;
2513
+ if (mode === "on") {
2514
+ CLI.logger.log(`~ Type ${CLI.options.prefix}help to view available commands`);
2515
+ } else {
2516
+ CLI.logger.log(`~ [MODE] Now set to "${mode}"`);
2517
+ }
2518
+ }
2319
2519
  rl;
2320
2520
  options;
2321
2521
  commands = /* @__PURE__ */ new Map();
@@ -2328,6 +2528,7 @@ var VimcordCLI = class {
2328
2528
  terminal: false
2329
2529
  });
2330
2530
  this.rl.on("line", (line) => {
2531
+ if (_VimcordCLI.mode !== "on") return;
2331
2532
  const { isCommand, commandName, content, args } = this.parseLine(line);
2332
2533
  if (!isCommand) return;
2333
2534
  const command = this.commands.get(commandName);
@@ -2384,7 +2585,6 @@ var VimcordCLI = class {
2384
2585
  return true;
2385
2586
  }
2386
2587
  };
2387
- var initCalled = false;
2388
2588
  var CLI = new VimcordCLI({ prefix: "/" });
2389
2589
  CLI.addCommand("help", "View information about a command, or the available CLI options", (args) => {
2390
2590
  const prefix = CLI.options.prefix;
@@ -2491,16 +2691,81 @@ CLI.addCommand("cmds", "List the loaded commands", async (args, content) => {
2491
2691
  return CLI.logger.error(`'${mode}' is not a valid option. Valid options: [slash|prefix|ctx]`);
2492
2692
  }
2493
2693
  });
2494
- function initCLI() {
2495
- if (initCalled) return;
2496
- CLI.logger.log(`~ Type ${CLI.options.prefix}help to view available commands`);
2497
- initCalled = true;
2498
- }
2499
2694
 
2500
- // src/client.ts
2501
- import chalk2 from "chalk";
2695
+ // src/client/Vimcord.ts
2696
+ import { Client as Client2 } from "discord.js";
2697
+ import { configDotenv } from "dotenv";
2698
+ import { randomUUID as randomUUID3 } from "crypto";
2699
+ import EventEmitter2 from "events";
2700
+ import { $ as $4 } from "qznt";
2502
2701
  var Vimcord = class _Vimcord extends Client2 {
2503
2702
  static instances = /* @__PURE__ */ new Map();
2703
+ static emitter = new EventEmitter2();
2704
+ clientStartingPromise = null;
2705
+ static create(optionsOrConfig, features, config) {
2706
+ if ("options" in optionsOrConfig) {
2707
+ const { options, features: features2, config: config2 } = optionsOrConfig;
2708
+ return new _Vimcord(options, features2, config2);
2709
+ } else {
2710
+ return new _Vimcord(optionsOrConfig, features, config);
2711
+ }
2712
+ }
2713
+ /**
2714
+ * Returns an instance of Vimcord.
2715
+ * @param clientId [default: 0]
2716
+ */
2717
+ static getInstance(clientId) {
2718
+ if (clientId === void 0) {
2719
+ return _Vimcord.instances.values().next().value;
2720
+ }
2721
+ return _Vimcord.instances.get(clientId);
2722
+ }
2723
+ /**
2724
+ * Waits for a Vimcord instance to be ready.
2725
+ * @param clientId [default: 0]
2726
+ * @param timeoutMs [default: 60000]
2727
+ */
2728
+ static async getReadyInstance(clientId, timeoutMs = 6e4) {
2729
+ const client = _Vimcord.getInstance(clientId);
2730
+ if (client?.isReady()) {
2731
+ _Vimcord.emitter.emit("ready", client);
2732
+ return client;
2733
+ }
2734
+ if (client) {
2735
+ return new Promise((resolve, reject) => {
2736
+ const timeout = setTimeout(() => {
2737
+ _Vimcord.emitter.off("ready", listener);
2738
+ reject(new Error(`Client (i${clientId ?? 0}) timed out waiting for ready`));
2739
+ }, timeoutMs);
2740
+ const listener = (c) => {
2741
+ if (c.clientId === (clientId ?? 0)) {
2742
+ clearTimeout(timeout);
2743
+ _Vimcord.emitter.off("ready", listener);
2744
+ resolve(c);
2745
+ }
2746
+ };
2747
+ client.once("clientReady", () => {
2748
+ clearTimeout(timeout);
2749
+ _Vimcord.emitter.emit("ready", client);
2750
+ resolve(client);
2751
+ });
2752
+ });
2753
+ }
2754
+ return new Promise((resolve, reject) => {
2755
+ const timeout = setTimeout(() => {
2756
+ _Vimcord.emitter.off("ready", listener);
2757
+ reject(new Error(`Vimcord instance (i${clientId ?? 0}) failed to initialize within ${timeoutMs / 1e3}s.`));
2758
+ }, timeoutMs);
2759
+ const listener = (c) => {
2760
+ if (c.clientId === (clientId ?? 0)) {
2761
+ clearTimeout(timeout);
2762
+ _Vimcord.emitter.off("ready", listener);
2763
+ resolve(c);
2764
+ }
2765
+ };
2766
+ _Vimcord.emitter.on("ready", listener);
2767
+ });
2768
+ }
2504
2769
  uuid = randomUUID3();
2505
2770
  clientId = _Vimcord.instances.size;
2506
2771
  clientOptions;
@@ -2510,229 +2775,181 @@ var Vimcord = class _Vimcord extends Client2 {
2510
2775
  events;
2511
2776
  commands;
2512
2777
  db;
2513
- // Configure custom logger
2514
- logger = new Logger({ prefixEmoji: "\u26A1", prefix: `vimcord (i${this.clientId})` }).extend({
2515
- clientBanner(client) {
2516
- if (client.config.app.disableBanner) return;
2517
- const border = "\u2550".repeat(50);
2518
- console.log(chalk2.hex(this.colors.primary)(`
2519
- \u2554${border}\u2557`));
2520
- console.log(
2521
- chalk2.hex(this.colors.primary)("\u2551") + chalk2.bold.hex(this.colors.text)(
2522
- ` \u{1F680} ${client.config.app.name} v${client.config.app.appVersion}`.padEnd(
2523
- 50 - (client.config.app.devMode ? 12 : 0)
2524
- )
2525
- ) + chalk2.hex(this.colors.primary)(
2526
- `${client.config.app.devMode ? chalk2.hex(this.colors.warn)("devMode \u26A0\uFE0F ") : ""}\u2551`
2527
- )
2528
- );
2529
- console.log(chalk2.hex(this.colors.primary)(`\u2551${"".padEnd(50)}\u2551`));
2530
- console.log(
2531
- chalk2.hex(this.colors.primary)("\u2551") + chalk2.hex(this.colors.muted)(
2532
- ` # Powered by Vimcord v${version}`.padEnd(50 - 3 - `${client.clientId}`.length)
2533
- ) + chalk2.hex(this.colors.primary)(`${chalk2.hex(this.colors.muted)(`i${client.clientId}`)} \u2551`)
2534
- );
2535
- console.log(chalk2.hex(this.colors.primary)(`\u255A${border}\u255D
2536
- `));
2537
- },
2538
- clientReady(clientTag, guildCount) {
2539
- console.log(
2540
- this.formatTimestamp(),
2541
- this.formatPrefix(),
2542
- chalk2.hex(this.colors.success)("\u{1F916} READY"),
2543
- chalk2.white(`Connected as ${chalk2.bold.hex(this.colors.primary)(clientTag)}`),
2544
- chalk2.hex(this.colors.muted)(`\u2022 ${guildCount} guilds`)
2545
- );
2546
- },
2547
- moduleLoaded(moduleName, count, ignoredCount) {
2548
- const countText = count ? chalk2.hex(this.colors.muted)(`(${count} items)`) : "";
2549
- console.log(
2550
- this.formatTimestamp(),
2551
- this.formatPrefix(),
2552
- chalk2.hex("#9B59B6")("\u{1F4E6} MODULE"),
2553
- chalk2.hex(this.colors.warn)(`${moduleName} loaded`),
2554
- ignoredCount ? chalk2.hex(this.colors.muted)(`(${ignoredCount} ignored)`) : "",
2555
- countText
2556
- );
2557
- },
2558
- commandExecuted(commandName, username, guildName) {
2559
- const location = guildName ? `in ${chalk2.hex(this.colors.muted)(guildName)}` : "in DMs";
2560
- console.log(
2561
- this.formatTimestamp(),
2562
- this.formatPrefix(),
2563
- chalk2.hex("#87CEEB")("\u{1F4DD} COMMAND"),
2564
- chalk2.hex(this.colors.warn)(`/${commandName}`),
2565
- chalk2.white(`used by ${chalk2.bold(username)}`),
2566
- chalk2.hex(this.colors.muted)(location)
2567
- );
2568
- },
2569
- database(action, details) {
2570
- console.log(
2571
- this.formatTimestamp(),
2572
- this.formatPrefix(),
2573
- chalk2.hex("#FF6B9D")("\u{1F5C4}\uFE0F DATABASE"),
2574
- chalk2.white(action),
2575
- details ? chalk2.hex(this.colors.muted)(details) : ""
2576
- );
2577
- }
2578
- });
2579
- clientStartingPromise = null;
2778
+ logger = clientLoggerFactory(this);
2779
+ error;
2580
2780
  constructor(options, features = {}, config = {}) {
2581
2781
  super(options);
2582
2782
  this.clientOptions = options;
2583
2783
  this.features = features;
2584
- this.config = {
2585
- app: createVimcordAppConfig(config.app),
2586
- staff: createVimcordStaffConfig(config.staff),
2587
- slashCommands: createVimcordSlashCommandConfig(config.slashCommands),
2588
- prefixCommands: createVimcordPrefixCommandConfig(config.prefixCommands),
2589
- contextCommands: createVimcordContextCommandConfig(config.contextCommands)
2590
- };
2784
+ this.config = defineVimcordConfig(config);
2785
+ this.error = new ErrorHandler(this);
2786
+ if (this.features.useGlobalErrorHandlers) {
2787
+ this.error.setupGlobalHandlers();
2788
+ }
2591
2789
  this.status = new StatusManager(this);
2592
2790
  this.events = new EventManager(this);
2593
2791
  this.commands = new CommandManager(this);
2594
- if (this.features.useEnv) {
2595
- if (typeof this.features.useEnv === "object") {
2596
- dotEnv.config({ quiet: true, ...this.features.useEnv });
2597
- } else {
2598
- dotEnv.config({ quiet: true });
2599
- }
2600
- }
2601
- if (this.features.useGlobalErrorHandlers) {
2602
- process.on("uncaughtException", (err) => this.logger.error("Uncaught Exception", err));
2603
- process.on("unhandledRejection", (err) => this.logger.error("Unhandled Rejection", err));
2604
- process.on("exit", (code) => this.logger.debug(`Process exited with code ${code}`));
2605
- this.on("error", (err) => this.logger.error("Client Error", err));
2606
- this.on("shardError", (err) => this.logger.error("Client Shard Error", err));
2607
- }
2608
2792
  this.logger.clientBanner(this);
2609
- this.once("clientReady", (client) => {
2610
- this.logger.clientReady(client.user.tag, client.guilds.cache.size);
2611
- });
2793
+ this.once("clientReady", (client) => this.logger.clientReady(client.user.tag, client.guilds.cache.size));
2612
2794
  _Vimcord.instances.set(this.clientId, this);
2613
- initCLI();
2795
+ if (this.config.app.enableCLI) {
2796
+ VimcordCLI.setMode("on");
2797
+ }
2614
2798
  }
2615
- /** Returns the options, features, and config of this client. */
2616
- toJSON() {
2617
- return {
2618
- options: this.clientOptions,
2619
- features: this.features,
2620
- config: this.config
2621
- };
2799
+ /** Current app name */
2800
+ // prettier-ignore
2801
+ get $name() {
2802
+ return this.config.app.name;
2622
2803
  }
2623
- /** Makes a clone of this client. */
2624
- clone() {
2625
- const { options, features, config } = this.toJSON();
2626
- return new _Vimcord(options, features, config);
2804
+ // prettier-ignore
2805
+ set $name(name) {
2806
+ this.config.app.name = name;
2627
2807
  }
2628
- configureApp(options = {}) {
2629
- this.config.app = createVimcordAppConfig(options);
2630
- if (this.features.hookToolsDevMode) {
2631
- globalVimcordToolsConfig.devMode = this.config.app.devMode;
2632
- }
2633
- return this;
2808
+ /** Current app version */
2809
+ // prettier-ignore
2810
+ get $version() {
2811
+ return this.config.app.version;
2634
2812
  }
2635
- configureStaff(options = {}) {
2636
- this.config.staff = createVimcordStaffConfig(options);
2637
- return this;
2813
+ // prettier-ignore
2814
+ set $version(version2) {
2815
+ this.config.app.version = version2;
2638
2816
  }
2639
- configureSlashCommands(options = {}) {
2640
- this.config.slashCommands = createVimcordSlashCommandConfig(options);
2641
- return this;
2817
+ /** Current dev mode state */
2818
+ // prettier-ignore
2819
+ get $devMode() {
2820
+ return this.config.app.devMode;
2642
2821
  }
2643
- configurePrefixCommands(options = {}) {
2644
- this.config.prefixCommands = createVimcordPrefixCommandConfig(options);
2645
- return this;
2822
+ // prettier-ignore
2823
+ set $devMode(mode) {
2824
+ this.config.app.devMode = mode;
2646
2825
  }
2647
- configureContextCommands(options = {}) {
2648
- this.config.contextCommands = createVimcordContextCommandConfig(options);
2649
- return this;
2826
+ /** Current verbose mode state */
2827
+ // prettier-ignore
2828
+ get $verboseMode() {
2829
+ return this.config.app.verbose;
2650
2830
  }
2651
- async importEventModules(dir, replaceAll) {
2652
- await this.events.importFrom(dir, replaceAll);
2653
- return this;
2831
+ // prettier-ignore
2832
+ set $verboseMode(mode) {
2833
+ this.config.app.verbose = mode;
2654
2834
  }
2655
- async importSlashCommandModules(dir, replaceAll) {
2656
- await this.commands.slash.importFrom(dir, replaceAll);
2657
- return this;
2835
+ /** Returns the options, features, and config of this client. */
2836
+ toJSON() {
2837
+ return { options: this.clientOptions, features: this.features, config: this.config };
2658
2838
  }
2659
- async importPrefixCommandModules(dir, replaceAll) {
2660
- await this.commands.prefix.importFrom(dir, replaceAll);
2661
- return this;
2839
+ /** Makes a clone of this client. */
2840
+ clone() {
2841
+ const { options, features, config } = this.toJSON();
2842
+ return new _Vimcord(options, features, config);
2662
2843
  }
2663
- async importContextCommandModules(dir, replaceAll) {
2664
- await this.commands.context.importFrom(dir, replaceAll);
2844
+ /**
2845
+ * Modifies a client config.
2846
+ * @param type The type of config to modify.
2847
+ * @param options The options to set for the config.
2848
+ */
2849
+ configure(type, options = {}) {
2850
+ this.config[type] = configSetters[type](options, this.config[type]);
2665
2851
  return this;
2666
2852
  }
2667
- async useDatabase(db) {
2668
- this.db = db;
2669
- this.logger.database("Using", db.moduleName);
2670
- return this.db.connect();
2671
- }
2672
- async waitForReady() {
2673
- if (this.isReady()) return this;
2674
- return new Promise((resolve, reject) => {
2675
- const timeout = setTimeout(
2676
- () => reject(new Error(`Client (i${this.clientId}) timed out waiting for ready`)),
2677
- 6e4
2678
- );
2679
- this.once("clientReady", () => {
2680
- clearTimeout(timeout);
2681
- resolve(this);
2682
- });
2683
- });
2684
- }
2853
+ /** Builds the client by importing modules and registering builtin handlers. */
2685
2854
  async build() {
2686
- this.configureApp(this.config.app);
2687
- this.configureStaff(this.config.staff);
2688
- this.configureSlashCommands(this.config.slashCommands);
2689
- this.configurePrefixCommands(this.config.prefixCommands);
2690
- this.configureContextCommands(this.config.contextCommands);
2855
+ this.configure("app", this.config.app);
2856
+ this.configure("staff", this.config.staff);
2857
+ this.configure("slashCommands", this.config.slashCommands);
2858
+ this.configure("prefixCommands", this.config.prefixCommands);
2859
+ this.configure("contextCommands", this.config.contextCommands);
2691
2860
  if (this.features.importModules) {
2692
2861
  const importModules = this.features.importModules;
2693
2862
  await Promise.all([
2694
- importModules.events && this.importEventModules(importModules.events),
2695
- importModules.slashCommands && this.importSlashCommandModules(importModules.slashCommands),
2696
- importModules.prefixCommands && this.importPrefixCommandModules(importModules.prefixCommands),
2697
- importModules.contextCommands && this.importContextCommandModules(importModules.contextCommands)
2863
+ importModules.events && this.importModules("events", importModules.events),
2864
+ importModules.slashCommands && this.importModules("slashCommands", importModules.slashCommands),
2865
+ importModules.prefixCommands && this.importModules("prefixCommands", importModules.prefixCommands),
2866
+ importModules.contextCommands && this.importModules("contextCommands", importModules.contextCommands)
2698
2867
  ]);
2699
2868
  }
2700
2869
  if (this.features.useDefaultSlashCommandHandler) {
2701
- this.events.register(BUILTIN_SlashCommandHandler);
2870
+ this.events.register(slashCommandHandler);
2702
2871
  }
2703
2872
  if (this.features.useDefaultContextCommandHandler) {
2704
- this.events.register(BUILTIN_ContextCommandHandler);
2873
+ this.events.register(contextCommandHandler);
2705
2874
  }
2706
2875
  if (this.features.useDefaultPrefixCommandHandler) {
2707
- this.events.register(BUILTIN_PrefixCommandHandler);
2876
+ this.events.register(prefixCommandHandler);
2708
2877
  }
2709
2878
  return this;
2710
2879
  }
2711
- async start(tokenOrPreHook, preHook) {
2880
+ /**
2881
+ * Imports modules into the client.
2882
+ * @param type The type of modules to import.
2883
+ * @param options The options to import the module with.
2884
+ * @param set Replaces already imported modules with the ones found.
2885
+ */
2886
+ async importModules(type, options, set) {
2887
+ await moduleImporters[type](this, options, set);
2888
+ return this;
2889
+ }
2890
+ /**
2891
+ * Allows Vimcord to handle environment variables using [dotenv](https://www.npmjs.com/package/dotenv).
2892
+ * @param options Options for dotenv
2893
+ * @see https://www.npmjs.com/package/dotenv
2894
+ */
2895
+ useEnv(options) {
2896
+ this.logger.database("Using", "dotenv");
2897
+ configDotenv({ quiet: true, ...options });
2898
+ return this;
2899
+ }
2900
+ /**
2901
+ * Connects to a database.
2902
+ * @param db The database manager to use.
2903
+ */
2904
+ async useDatabase(db) {
2905
+ this.db = db;
2906
+ this.logger.database("Using", db.moduleName);
2907
+ return this.db.connect();
2908
+ }
2909
+ /**
2910
+ * Fetches a user from the client, checking the cache first.
2911
+ * @param userId The ID of the user to fetch.
2912
+ */
2913
+ async fetchUser(userId) {
2914
+ const client = await _Vimcord.getReadyInstance(this.clientId);
2915
+ return fetchUser(client, userId);
2916
+ }
2917
+ /**
2918
+ * Fetches a guild from the client, checking the cache first.
2919
+ * @param guildId The ID of the guild to fetch.
2920
+ */
2921
+ async fetchGuild(guildId) {
2922
+ const client = await _Vimcord.getReadyInstance(this.clientId);
2923
+ return fetchGuild(client, guildId);
2924
+ }
2925
+ async start(tokenOrPreHook, callback) {
2712
2926
  if (this.clientStartingPromise) return this.clientStartingPromise;
2713
- const main = async () => {
2927
+ const execute = async () => {
2714
2928
  let token = typeof tokenOrPreHook === "string" ? tokenOrPreHook : void 0;
2715
- token ??= this.config.app.devMode ? process.env.TOKEN_DEV : process.env.TOKEN;
2929
+ token ??= this.$devMode ? process.env.TOKEN_DEV : process.env.TOKEN;
2716
2930
  if (!token) {
2717
2931
  throw new Error(
2718
- `TOKEN Missing: ${this.config.app.devMode ? "devMode is enabled, but TOKEN_DEV is not set" : "TOKEN not set"}`
2932
+ `TOKEN Missing: ${this.$devMode ? "devMode is enabled, but TOKEN_DEV is not set" : "TOKEN not set"}`
2719
2933
  );
2720
2934
  }
2721
2935
  await this.build();
2722
2936
  try {
2937
+ const stopLoader = this.logger.loader("Connecting to Discord...");
2938
+ const loginResult = await $4.async.retry(() => super.login(token), {
2939
+ retries: this.features.maxLoginAttempts ?? 3,
2940
+ delay: 1e3
2941
+ });
2942
+ stopLoader("Connected to Discord ");
2943
+ this.$verboseMode && this.logger.debug("Waiting for ready...");
2723
2944
  if (typeof tokenOrPreHook === "function") {
2724
2945
  await tokenOrPreHook(this);
2725
2946
  } else {
2726
- await preHook?.(this);
2947
+ await callback?.(this);
2727
2948
  }
2728
- const stopLoader = this.logger.loader("Connecting to Discord...");
2729
- const loginResult = await $4.async.retry(() => super.login(token), this.features.loginAttempts ?? 3, 1e3);
2730
- stopLoader("Connected to Discord ");
2731
- this.config.app.verbose && this.logger.debug("\u23F3 Waiting for ready...");
2732
2949
  return loginResult;
2733
2950
  } catch (err) {
2734
2951
  this.logger.error(
2735
- `Failed to log into Discord after ${this.features.loginAttempts} attempt(s))`,
2952
+ `Failed to log into Discord after ${this.features.maxLoginAttempts} attempt(s)`,
2736
2953
  err
2737
2954
  );
2738
2955
  return null;
@@ -2740,29 +2957,27 @@ var Vimcord = class _Vimcord extends Client2 {
2740
2957
  this.clientStartingPromise = null;
2741
2958
  }
2742
2959
  };
2743
- this.clientStartingPromise = main();
2960
+ this.clientStartingPromise = execute();
2744
2961
  return this.clientStartingPromise;
2745
2962
  }
2963
+ /** Destroys the client and disconnects from Discord. */
2746
2964
  async kill() {
2747
2965
  await super.destroy();
2748
2966
  _Vimcord.instances.delete(this.clientId);
2749
- this.logger.debug("\u{1F6AA} Logged out of Discord");
2750
- }
2751
- /** Shortcut for {@link fetchUser tools.fetchUser} */
2752
- async fetchUser(id) {
2753
- const client = await this.waitForReady();
2754
- return fetchUser(client, id);
2755
- }
2756
- /** Shortcut for {@link fetchGuild tools.fetchGuild} */
2757
- async fetchGuild(id) {
2758
- const client = await this.waitForReady();
2759
- return fetchGuild(client, id);
2967
+ this.logger.debug("Logged out of Discord");
2760
2968
  }
2761
2969
  };
2762
2970
 
2763
- // src/modules/db/mongo/mongo.ts
2971
+ // src/db/mongo/mongo-schema.builder.ts
2972
+ import {
2973
+ Schema
2974
+ } from "mongoose";
2975
+ import { randomBytes } from "crypto";
2976
+ import { $ as $6 } from "qznt";
2977
+
2978
+ // src/db/mongo/mongo.database.ts
2764
2979
  import mongoose, { ConnectionStates } from "mongoose";
2765
- import EventEmitter2 from "events";
2980
+ import EventEmitter3 from "events";
2766
2981
  import { $ as $5 } from "qznt";
2767
2982
  try {
2768
2983
  import("mongoose");
@@ -2771,7 +2986,7 @@ try {
2771
2986
  }
2772
2987
  var MongoDatabase = class _MongoDatabase {
2773
2988
  static instances = /* @__PURE__ */ new Map();
2774
- static emitter = new EventEmitter2();
2989
+ static emitter = new EventEmitter3();
2775
2990
  moduleName = "MongoDatabase";
2776
2991
  clientId;
2777
2992
  client;
@@ -2856,10 +3071,9 @@ var MongoDatabase = class _MongoDatabase {
2856
3071
  this.isConnecting = true;
2857
3072
  try {
2858
3073
  const stopLoader = this.client.logger.loader("Connecting to MongoDB...");
2859
- await $5.async.retry(
2860
- () => this.mongoose.connect(connectionUri, { autoIndex: true, ...connectionOptions }),
2861
- maxRetries
2862
- );
3074
+ await $5.async.retry(() => this.mongoose.connect(connectionUri, { autoIndex: true, ...connectionOptions }), {
3075
+ retries: maxRetries
3076
+ });
2863
3077
  _MongoDatabase.emitter.emit("ready", this);
2864
3078
  stopLoader("Connected to MongoDB ");
2865
3079
  } catch (err) {
@@ -2890,12 +3104,7 @@ var MongoDatabase = class _MongoDatabase {
2890
3104
  }
2891
3105
  };
2892
3106
 
2893
- // src/modules/db/mongo/mongoSchema.builder.ts
2894
- import {
2895
- Schema
2896
- } from "mongoose";
2897
- import { randomBytes } from "crypto";
2898
- import { $ as $6 } from "qznt";
3107
+ // src/db/mongo/mongo-schema.builder.ts
2899
3108
  try {
2900
3109
  import("mongoose");
2901
3110
  } catch {
@@ -2981,10 +3190,13 @@ var MongoSchemaBuilder = class _MongoSchemaBuilder {
2981
3190
  * @param maxRetries [default: 3]
2982
3191
  */
2983
3192
  async execute(fn, maxRetries = 3) {
2984
- return await $6.async.retry(async () => {
2985
- const model = await this.getModel();
2986
- return await fn(model);
2987
- }, maxRetries);
3193
+ return await $6.async.retry(
3194
+ async () => {
3195
+ const model = await this.getModel();
3196
+ return await fn(model);
3197
+ },
3198
+ { retries: maxRetries }
3199
+ );
2988
3200
  }
2989
3201
  async startSession(options) {
2990
3202
  return await this.execute(async () => {
@@ -3058,6 +3270,12 @@ var MongoSchemaBuilder = class _MongoSchemaBuilder {
3058
3270
  return result?.length ? result : [];
3059
3271
  });
3060
3272
  }
3273
+ async bulkWrite(ops, options) {
3274
+ return await this.execute(async (model) => model.bulkWrite(ops, options));
3275
+ }
3276
+ async bulkSave(docs, options) {
3277
+ return await this.execute(async (model) => model.bulkSave(docs, options));
3278
+ }
3061
3279
  };
3062
3280
 
3063
3281
  // src/tools/BetterCollector.ts
@@ -3229,8 +3447,8 @@ var BetterCollector = class _BetterCollector {
3229
3447
  handleListenerError(err) {
3230
3448
  console.error("[BetterCollector] Listener Error:", err);
3231
3449
  }
3232
- constructor(message, options) {
3233
- this.config = options?.config || globalVimcordToolsConfig;
3450
+ constructor(message, options = {}) {
3451
+ this.config = options.config ? createToolsConfig(options.config) : globalToolsConfig;
3234
3452
  this.message = message || void 0;
3235
3453
  this.options = options;
3236
3454
  this.build();
@@ -3280,7 +3498,7 @@ var BetterContainer = class {
3280
3498
  data;
3281
3499
  config;
3282
3500
  constructor(data = {}) {
3283
- this.config = data.config || globalVimcordToolsConfig;
3501
+ this.config = data.config ? createToolsConfig(data.config) : globalToolsConfig;
3284
3502
  this.data = {
3285
3503
  color: data.color ?? (this.config.devMode ? this.config.embedColorDev : this.config.embedColor),
3286
3504
  ...data
@@ -3288,7 +3506,7 @@ var BetterContainer = class {
3288
3506
  this.build();
3289
3507
  }
3290
3508
  configure() {
3291
- if (this.data.color) {
3509
+ if (this.data.color !== void 0) {
3292
3510
  try {
3293
3511
  const color = Array.isArray(this.data.color) ? this.data.color[Math.floor(Math.random() * this.data.color.length)] ?? null : this.data.color;
3294
3512
  if (color) {
@@ -3304,6 +3522,14 @@ var BetterContainer = class {
3304
3522
  build() {
3305
3523
  this.configure();
3306
3524
  }
3525
+ setColor(color) {
3526
+ this.data.color = color;
3527
+ return this;
3528
+ }
3529
+ clearColor() {
3530
+ this.data.color = null;
3531
+ return this;
3532
+ }
3307
3533
  addSeparator(options) {
3308
3534
  this.container.addSeparatorComponents((sb) => {
3309
3535
  if (options?.divider !== void 0) sb.setDivider(options.divider);
@@ -3392,7 +3618,7 @@ var BetterModal = class {
3392
3618
  this.id = options.id || this.createModalId();
3393
3619
  this.options = options;
3394
3620
  this.modal = new ModalBuilder().setCustomId(this.id);
3395
- this.config = options.config || globalVimcordToolsConfig;
3621
+ this.config = options.config || globalToolsConfig;
3396
3622
  if (options.title) {
3397
3623
  this.setTitle(options.title);
3398
3624
  }
@@ -3572,7 +3798,8 @@ var BetterModal = class {
3572
3798
  values,
3573
3799
  interaction: modalSubmit,
3574
3800
  reply: (options2) => dynaSend(modalSubmit, options2),
3575
- deferUpdate: async (options2) => await modalSubmit.deferUpdate(options2)
3801
+ deferUpdate: async (options2) => await modalSubmit.deferUpdate(options2),
3802
+ followUp: async (options2) => await modalSubmit.followUp(options2)
3576
3803
  };
3577
3804
  } catch (error) {
3578
3805
  return null;
@@ -3599,7 +3826,7 @@ import {
3599
3826
  EmbedBuilder as EmbedBuilder2,
3600
3827
  StringSelectMenuBuilder as StringSelectMenuBuilder2
3601
3828
  } from "discord.js";
3602
- import EventEmitter3 from "events";
3829
+ import EventEmitter4 from "events";
3603
3830
  var PaginationType = /* @__PURE__ */ ((PaginationType2) => {
3604
3831
  PaginationType2[PaginationType2["Short"] = 0] = "Short";
3605
3832
  PaginationType2[PaginationType2["ShortJump"] = 1] = "ShortJump";
@@ -3644,9 +3871,9 @@ var Paginator = class {
3644
3871
  config;
3645
3872
  data;
3646
3873
  events;
3647
- eventEmitter = new EventEmitter3();
3874
+ eventEmitter = new EventEmitter4();
3648
3875
  constructor(options = {}) {
3649
- this.config = options.config || globalVimcordToolsConfig;
3876
+ this.config = options.config ? createToolsConfig(options.config) : globalToolsConfig;
3650
3877
  this.options = {
3651
3878
  type: options.type ?? 0 /* Short */,
3652
3879
  participants: options.participants ?? [],
@@ -4079,7 +4306,7 @@ var Prompt = class {
4079
4306
  config;
4080
4307
  message = null;
4081
4308
  constructor(options = {}) {
4082
- this.config = options.config ?? globalVimcordToolsConfig;
4309
+ this.config = options.config ? createToolsConfig(options.config) : globalToolsConfig;
4083
4310
  this.participants = options.participants ?? [];
4084
4311
  this.timeout = options.timeout ?? this.config.timeouts.prompt;
4085
4312
  this.content = options.content;
@@ -4260,9 +4487,6 @@ async function prompt(handler, options, sendOptions) {
4260
4487
  return await p.awaitResponse();
4261
4488
  }
4262
4489
  export {
4263
- BUILTIN_ContextCommandHandler,
4264
- BUILTIN_PrefixCommandHandler,
4265
- BUILTIN_SlashCommandHandler,
4266
4490
  BaseCommandBuilder,
4267
4491
  BaseCommandManager,
4268
4492
  BetterCollector,
@@ -4275,13 +4499,16 @@ export {
4275
4499
  CommandType,
4276
4500
  ContextCommandBuilder,
4277
4501
  ContextCommandManager,
4502
+ DEFAULT_MODULE_SUFFIXES,
4278
4503
  DynaSend,
4504
+ ErrorHandler,
4279
4505
  EventBuilder,
4280
4506
  EventManager,
4281
4507
  LOGGER_COLORS,
4282
4508
  LogLevel,
4283
4509
  Logger,
4284
4510
  MissingPermissionReason,
4511
+ ModuleImporter,
4285
4512
  MongoDatabase,
4286
4513
  MongoSchemaBuilder,
4287
4514
  PaginationTimeoutType,
@@ -4301,17 +4528,24 @@ export {
4301
4528
  VimcordCLI,
4302
4529
  __zero,
4303
4530
  cleanMention,
4531
+ clientLoggerFactory,
4532
+ configSetters,
4533
+ contextCommandHandler,
4534
+ createAppConfig,
4304
4535
  createClient,
4536
+ createConfigFactory,
4537
+ createContextCommandConfig,
4305
4538
  createMongoPlugin,
4306
4539
  createMongoSchema,
4540
+ createPrefixCommandConfig,
4541
+ createSlashCommandConfig,
4542
+ createStaffConfig,
4307
4543
  createToolsConfig,
4308
- createVimcordAppConfig,
4309
- createVimcordContextCommandConfig,
4310
- createVimcordPrefixCommandConfig,
4311
- createVimcordSlashCommandConfig,
4312
- createVimcordStaffConfig,
4313
4544
  createVimcordStatusConfig,
4545
+ defineClientOptions,
4314
4546
  defineGlobalToolsConfig,
4547
+ defineVimcordConfig,
4548
+ defineVimcordFeatures,
4315
4549
  dynaSend,
4316
4550
  fetchChannel,
4317
4551
  fetchGuild,
@@ -4319,17 +4553,20 @@ export {
4319
4553
  fetchMessage,
4320
4554
  fetchRole,
4321
4555
  fetchUser,
4322
- getCallerFileName,
4556
+ getDevMode,
4323
4557
  getFirstMentionId,
4324
4558
  getMessageMention,
4559
+ getPackageJson,
4325
4560
  getProcessDir,
4326
- globalVimcordToolsConfig,
4561
+ globalToolsConfig,
4327
4562
  importModulesFromDir,
4328
- initCLI,
4329
4563
  isMentionOrSnowflake,
4330
4564
  logger,
4565
+ moduleImporters,
4566
+ prefixCommandHandler,
4331
4567
  prompt,
4332
4568
  sendCommandErrorEmbed,
4569
+ slashCommandHandler,
4333
4570
  useClient,
4334
4571
  useReadyClient,
4335
4572
  validateCommandPermissions