vimcord 1.0.37 → 1.0.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -69,6 +69,7 @@ __export(index_exports, {
69
69
  StatusType: () => StatusType,
70
70
  Vimcord: () => Vimcord,
71
71
  VimcordCLI: () => VimcordCLI,
72
+ VimcordErrorHandler: () => VimcordErrorHandler,
72
73
  __zero: () => __zero,
73
74
  cleanMention: () => cleanMention,
74
75
  clientLoggerFactory: () => clientLoggerFactory,
@@ -85,6 +86,7 @@ __export(index_exports, {
85
86
  createStaffConfig: () => createStaffConfig,
86
87
  createToolsConfig: () => createToolsConfig,
87
88
  createVimcordStatusConfig: () => createVimcordStatusConfig,
89
+ deepMerge: () => deepMerge,
88
90
  defineClientOptions: () => defineClientOptions,
89
91
  defineGlobalToolsConfig: () => defineGlobalToolsConfig,
90
92
  defineVimcordConfig: () => defineVimcordConfig,
@@ -100,7 +102,6 @@ __export(index_exports, {
100
102
  getFirstMentionId: () => getFirstMentionId,
101
103
  getMessageMention: () => getMessageMention,
102
104
  getPackageJson: () => getPackageJson,
103
- getProcessDir: () => getProcessDir,
104
105
  globalToolsConfig: () => globalToolsConfig,
105
106
  importModulesFromDir: () => importModulesFromDir,
106
107
  isMentionOrSnowflake: () => isMentionOrSnowflake,
@@ -244,8 +245,30 @@ function validateCommandPermissions(permissions, client, user, command) {
244
245
  return { validated: true };
245
246
  }
246
247
 
248
+ // src/utils/mergeUtils.ts
249
+ function isPlainObject(value) {
250
+ if (typeof value !== "object" || value === null) return false;
251
+ if (Array.isArray(value)) return false;
252
+ return Object.prototype.toString.call(value) === "[object Object]";
253
+ }
254
+ function deepMerge(target, ...sources) {
255
+ for (const source of sources) {
256
+ if (!source) continue;
257
+ for (const key in source) {
258
+ if (!Object.prototype.hasOwnProperty.call(source, key)) continue;
259
+ const sourceValue = source[key];
260
+ const targetValue = target[key];
261
+ if (isPlainObject(sourceValue) && isPlainObject(targetValue)) {
262
+ deepMerge(targetValue, sourceValue);
263
+ } else if (sourceValue !== void 0) {
264
+ target[key] = sourceValue;
265
+ }
266
+ }
267
+ }
268
+ return target;
269
+ }
270
+
247
271
  // src/builders/baseCommand.builder.ts
248
- var import_lodash = __toESM(require("lodash"));
249
272
  var import_node_crypto = require("crypto");
250
273
  var BaseCommandBuilder = class {
251
274
  uuid = (0, import_node_crypto.randomUUID)();
@@ -259,8 +282,7 @@ var BaseCommandBuilder = class {
259
282
  [1 /* Guild */]: /* @__PURE__ */ new Map(),
260
283
  [2 /* Channel */]: /* @__PURE__ */ new Map()
261
284
  };
262
- /** * Mapping of CommandTypes to their respective config keys in the Vimcord client
263
- */
285
+ /** Mapping of CommandTypes to their respective config keys in the Vimcord client */
264
286
  typeConfigMapping = {
265
287
  [0 /* Slash */]: "slashCommands",
266
288
  [1 /* Prefix */]: "prefixCommands",
@@ -285,7 +307,7 @@ var BaseCommandBuilder = class {
285
307
  resolveConfig(client) {
286
308
  const typeKey = this.typeConfigMapping[this.commandType];
287
309
  const typeSpecificGlobals = client.config?.[typeKey] || {};
288
- return import_lodash.default.merge({}, typeSpecificGlobals, this.options);
310
+ return deepMerge({}, typeSpecificGlobals, this.options);
289
311
  }
290
312
  /**
291
313
  * Executes the command lifecycle.
@@ -403,12 +425,12 @@ var BaseCommandBuilder = class {
403
425
  }
404
426
  /** Merge new permission requirements into the existing ones */
405
427
  setPermissions(perms) {
406
- this.options.permissions = import_lodash.default.merge(this.options.permissions || {}, perms);
428
+ this.options.permissions = deepMerge(this.options.permissions || {}, perms);
407
429
  return this;
408
430
  }
409
- /** Add custom logic checks that run before execution */
410
- addConditions(...conditions) {
411
- this.options.conditions = [...this.options.conditions || [], ...conditions];
431
+ /** Set the custom conditions that must be met for this command to execute */
432
+ setConditions(conditions) {
433
+ this.options.conditions = conditions;
412
434
  return this;
413
435
  }
414
436
  /** Set the primary command execution logic */
@@ -416,79 +438,21 @@ var BaseCommandBuilder = class {
416
438
  this.options.execute = fn;
417
439
  return this;
418
440
  }
419
- /** * Set the custom conditions that must be met for this command to execute
420
- */
421
- setConditions(conditions) {
422
- this.options.conditions = conditions;
423
- return this;
424
- }
425
- /** * Set the command metadata configuration
426
- */
441
+ /** Set the command metadata configuration */
427
442
  setMetadata(metadata) {
428
- this.options.metadata = import_lodash.default.merge(this.options.metadata || {}, metadata);
443
+ this.options.metadata = deepMerge(this.options.metadata || {}, metadata);
429
444
  return this;
430
445
  }
431
- /** * Set the rate limiting options for this command
432
- */
446
+ /** Set the rate limiting options for this command */
433
447
  setRateLimit(options) {
434
448
  this.options.rateLimit = options;
435
449
  this.validateBaseConfig();
436
450
  return this;
437
451
  }
438
- /** * Set whether to log whenever this command is executed
439
- * @defaultValue true
440
- */
441
- setLogExecution(log) {
442
- this.options.logExecution = log;
443
- return this;
444
- }
445
- /** * Set the function to execute before the main command logic
446
- */
447
- setBeforeExecute(callback) {
448
- this.options.beforeExecute = callback;
449
- return this;
450
- }
451
- /** * Set the function to execute after successful command execution
452
- */
453
- setAfterExecute(callback) {
454
- this.options.afterExecute = callback;
455
- return this;
456
- }
457
- /** * Set the function to execute when the required permissions are not met
458
- */
459
- setOnMissingPermissions(callback) {
460
- this.options.onMissingPermissions = callback;
461
- return this;
462
- }
463
- /** * Set the function to execute when the required conditions are not met
464
- */
465
- setOnConditionsNotMet(callback) {
466
- this.options.onConditionsNotMet = callback;
467
- return this;
468
- }
469
- /** * Set the function to execute when this command is used when its disabled
470
- */
471
- setOnUsedWhenDisabled(callback) {
472
- this.options.onUsedWhenDisabled = callback;
473
- return this;
474
- }
475
- /** * Set the function to execute when the rate limit is hit
476
- */
477
- setOnRateLimit(callback) {
478
- this.options.onRateLimit = callback;
479
- return this;
480
- }
481
- /** * Set a custom error handler for this command
482
- */
483
- setOnError(callback) {
484
- this.options.onError = callback;
485
- return this;
486
- }
487
452
  };
488
453
 
489
454
  // src/builders/contextCommand.builder.ts
490
455
  var import_discord2 = require("discord.js");
491
- var import_lodash2 = __toESM(require("lodash"));
492
456
  var ContextCommandBuilder = class extends BaseCommandBuilder {
493
457
  builder;
494
458
  constructor(config) {
@@ -516,14 +480,6 @@ var ContextCommandBuilder = class extends BaseCommandBuilder {
516
480
  this.validateBuilder();
517
481
  return this;
518
482
  }
519
- setDeferReply(defer) {
520
- this.options.deferReply = defer;
521
- return this;
522
- }
523
- setDeployment(deployment) {
524
- this.options.deployment = import_lodash2.default.merge(this.options.deployment || {}, deployment);
525
- return this;
526
- }
527
483
  setExecute(fn) {
528
484
  const originalExecute = fn;
529
485
  this.options.execute = async (client, interaction) => {
@@ -538,7 +494,6 @@ var ContextCommandBuilder = class extends BaseCommandBuilder {
538
494
 
539
495
  // src/builders/event.builder.ts
540
496
  var import_node_crypto2 = require("crypto");
541
- var import_lodash3 = __toESM(require("lodash"));
542
497
 
543
498
  // src/tools/Logger.ts
544
499
  var import_chalk = __toESM(require("chalk"));
@@ -799,77 +754,14 @@ var EventBuilder = class _EventBuilder {
799
754
  onError: this.onError
800
755
  };
801
756
  }
802
- setEvent(event) {
803
- this.event = event;
804
- return this;
805
- }
806
- setName(name) {
807
- this.name = name;
808
- return this;
809
- }
810
757
  setEnabled(enabled) {
811
758
  this.enabled = enabled;
812
759
  return this;
813
760
  }
814
- enable() {
815
- return this.setEnabled(true);
816
- }
817
- disable() {
818
- return this.setEnabled(false);
819
- }
820
- setOnce(once = true) {
821
- this.once = once;
822
- return this;
823
- }
824
- setPriority(priority) {
825
- this.priority = priority;
826
- return this;
827
- }
828
- addCondition(condition) {
829
- if (!this.conditions) this.conditions = [];
830
- this.conditions.push(condition);
831
- return this;
832
- }
833
- setConditions(conditions) {
834
- this.conditions = conditions;
835
- return this;
836
- }
837
- setMetadata(metadata) {
838
- this.metadata = import_lodash3.default.merge(this.metadata, metadata);
839
- return this;
840
- }
841
- setDeployment(deployment) {
842
- this.deployment = import_lodash3.default.merge(this.deployment, deployment);
843
- return this;
844
- }
845
- setRateLimit(options) {
846
- this.rateLimit = options;
847
- return this;
848
- }
849
- setBeforeExecute(beforeExecute) {
850
- this.beforeExecute = beforeExecute;
851
- return this;
852
- }
853
761
  setExecute(execute) {
854
762
  this.execute = execute;
855
763
  return this;
856
764
  }
857
- setAfterExecute(afterExecute) {
858
- this.afterExecute = afterExecute;
859
- return this;
860
- }
861
- setOnError(onError) {
862
- this.onError = onError;
863
- return this;
864
- }
865
- getRateLimitInfo() {
866
- if (!this.rateLimit) return null;
867
- return { ...this.rateLimitData, isLimited: this.isRateLimited(false) };
868
- }
869
- resetRateLimit() {
870
- this.rateLimitData = { executions: 0, timestamp: 0 };
871
- return this;
872
- }
873
765
  isRateLimited(updateExecutions = true) {
874
766
  if (!this.rateLimit) return false;
875
767
  const now = Date.now();
@@ -942,39 +834,9 @@ var PrefixCommandBuilder = class extends BaseCommandBuilder {
942
834
  throw new Error(`[Vimcord] PrefixCommandBuilder: Command name is required.`);
943
835
  }
944
836
  }
945
- // --- Fluent API (Prefix Specific Only) ---
946
- /**
947
- * Set the primary name of the command.
948
- */
949
- setName(name) {
950
- this.options.name = name;
951
- return this;
952
- }
953
- /**
954
- * Set or replace the command aliases.
955
- */
956
- setAliases(aliases) {
957
- this.options.aliases = aliases;
958
- return this;
959
- }
960
- /**
961
- * Add additional aliases without clearing existing ones.
962
- */
963
- addAliases(...aliases) {
964
- this.options.aliases = [...this.options.aliases || [], ...aliases];
965
- return this;
966
- }
967
- /**
968
- * Set the command description.
969
- */
970
- setDescription(description) {
971
- this.options.description = description;
972
- return this;
973
- }
974
837
  // --- Overrides ---
975
838
  /**
976
839
  * Override setExecute to ensure handleExecution remains the entry point.
977
- * This is the only base method we need to redefine.
978
840
  */
979
841
  setExecute(fn) {
980
842
  const originalExecute = fn;
@@ -995,7 +857,6 @@ var PrefixCommandBuilder = class extends BaseCommandBuilder {
995
857
 
996
858
  // src/builders/slashCommand.builder.ts
997
859
  var import_discord3 = require("discord.js");
998
- var import_lodash4 = __toESM(require("lodash"));
999
860
  var SlashCommandBuilder = class extends BaseCommandBuilder {
1000
861
  builder;
1001
862
  routes = /* @__PURE__ */ new Map();
@@ -1036,19 +897,6 @@ var SlashCommandBuilder = class extends BaseCommandBuilder {
1036
897
  this.validateBuilder();
1037
898
  return this;
1038
899
  }
1039
- setDeferReply(defer) {
1040
- this.options.deferReply = defer;
1041
- return this;
1042
- }
1043
- setDeployment(deployment) {
1044
- this.options.deployment = import_lodash4.default.merge(this.options.deployment || {}, deployment);
1045
- return this;
1046
- }
1047
- setRoutes(...routes) {
1048
- this.routes.clear();
1049
- this.addRoutes(...routes);
1050
- return this;
1051
- }
1052
900
  addRoutes(...routes) {
1053
901
  if (!this.options.routes) this.options.routes = [];
1054
902
  for (const route of routes) {
@@ -1060,10 +908,6 @@ var SlashCommandBuilder = class extends BaseCommandBuilder {
1060
908
  }
1061
909
  return this;
1062
910
  }
1063
- setUnknownRouteHandler(handler) {
1064
- this.options.onUnknownRouteHandler = handler;
1065
- return this;
1066
- }
1067
911
  setExecute(fn) {
1068
912
  const originalExecute = fn;
1069
913
  this.options.execute = async (client, interaction) => {
@@ -1080,7 +924,7 @@ var SlashCommandBuilder = class extends BaseCommandBuilder {
1080
924
  }
1081
925
  };
1082
926
 
1083
- // src/modules/builtins/context-command.builtins.ts
927
+ // src/modules/builtins/contextCommand.builtin.ts
1084
928
  var contextCommandHandler = new EventBuilder({
1085
929
  event: "interactionCreate",
1086
930
  name: "ContextCommandHandler",
@@ -1102,7 +946,7 @@ var contextCommandHandler = new EventBuilder({
1102
946
  }
1103
947
  });
1104
948
 
1105
- // src/modules/builtins/prefix-command.builtins.ts
949
+ // src/modules/builtins/prefixCommand.builtin.ts
1106
950
  var import_discord4 = require("discord.js");
1107
951
  var prefixCommandHandler = new EventBuilder({
1108
952
  event: "messageCreate",
@@ -1144,7 +988,7 @@ var prefixCommandHandler = new EventBuilder({
1144
988
  }
1145
989
  });
1146
990
 
1147
- // src/modules/builtins/slash-command.builtins.ts
991
+ // src/modules/builtins/slashCommand.builtin.ts
1148
992
  var slashCommandHandler = new EventBuilder({
1149
993
  event: "interactionCreate",
1150
994
  name: "SlashCommandHandler",
@@ -1166,14 +1010,204 @@ var slashCommandHandler = new EventBuilder({
1166
1010
  }
1167
1011
  });
1168
1012
 
1013
+ // src/client/vimcord.cli.ts
1014
+ var import_node_readline = require("readline");
1015
+ var import_qznt = require("qznt");
1016
+ var VimcordCLI = class _VimcordCLI {
1017
+ static mode = "off";
1018
+ static setMode(mode) {
1019
+ if (_VimcordCLI.mode === mode) return;
1020
+ _VimcordCLI.mode = mode;
1021
+ if (mode === "on") {
1022
+ CLI.logger.log(`~ Type ${CLI.options.prefix}help to view available commands`);
1023
+ } else {
1024
+ CLI.logger.log(`~ [MODE] Now set to "${mode}"`);
1025
+ }
1026
+ }
1027
+ rl;
1028
+ options;
1029
+ commands = /* @__PURE__ */ new Map();
1030
+ logger = new Logger({ prefixEmoji: "\u{1F680}", prefix: "CLI", showTimestamp: false });
1031
+ constructor(options) {
1032
+ this.options = options;
1033
+ this.rl = (0, import_node_readline.createInterface)({
1034
+ input: process.stdin,
1035
+ output: process.stdout,
1036
+ terminal: false
1037
+ });
1038
+ this.rl.on("line", (line) => {
1039
+ if (_VimcordCLI.mode !== "on") return;
1040
+ const { isCommand, commandName, content, args } = this.parseLine(line);
1041
+ if (!isCommand) return;
1042
+ const command = this.commands.get(commandName);
1043
+ if (!command) {
1044
+ const nearestMatches = Array.from(this.commands.keys()).filter(
1045
+ (cmd) => cmd.toLowerCase().includes(commandName.toLowerCase())
1046
+ );
1047
+ return this.logger.error(
1048
+ `Unknown command '${commandName}'${nearestMatches.length ? `. Did you mean ${nearestMatches.length > 1 ? `[${nearestMatches.map((m) => `'${this.options.prefix}${m}'`).join(", ")}]` : `'${this.options.prefix}${nearestMatches[0]}'`}?` : ""}`
1049
+ );
1050
+ }
1051
+ command.fn(args, content);
1052
+ });
1053
+ }
1054
+ parseLine(line) {
1055
+ if (line.startsWith(this.options.prefix)) {
1056
+ line = line.slice(this.options.prefix.length);
1057
+ } else {
1058
+ return { isCommand: false };
1059
+ }
1060
+ const args = line.split(" ").map((s) => s.trim());
1061
+ const commandName = args.shift();
1062
+ return { isCommand: true, commandName, content: args.join(" "), args };
1063
+ }
1064
+ getClientInstance(line) {
1065
+ const clientIndex = import_qznt.$.str.getFlag(line, "--client", 1) || import_qznt.$.str.getFlag(line, "-c", 1);
1066
+ if (clientIndex) {
1067
+ const idx = Number(clientIndex);
1068
+ if (isNaN(idx)) {
1069
+ CLI.logger.error(`'${clientIndex}' is not a valid number`);
1070
+ return void 0;
1071
+ }
1072
+ const client = useClient(idx);
1073
+ if (!client) {
1074
+ CLI.logger.error("Client instance not found");
1075
+ return void 0;
1076
+ }
1077
+ return client;
1078
+ } else {
1079
+ const client = useClient(0);
1080
+ if (!client) {
1081
+ CLI.logger.error("Client instance not found");
1082
+ return void 0;
1083
+ }
1084
+ return client;
1085
+ }
1086
+ }
1087
+ addCommand(commandName, description, fn) {
1088
+ this.commands.set(commandName, { description, fn });
1089
+ }
1090
+ removeCommand(commandName) {
1091
+ if (!this.commands.has(commandName)) return false;
1092
+ this.commands.delete(commandName);
1093
+ return true;
1094
+ }
1095
+ };
1096
+ var CLI = new VimcordCLI({ prefix: "/" });
1097
+ CLI.addCommand("help", "View information about a command, or the available CLI options", (args) => {
1098
+ const prefix = CLI.options.prefix;
1099
+ const helpList = {};
1100
+ for (const cmd of CLI.commands.entries()) {
1101
+ const commandName = cmd[0];
1102
+ const commandDescription = cmd[1].description;
1103
+ helpList[`${prefix}${commandName}`] = `~ ${commandDescription}`;
1104
+ }
1105
+ CLI.logger.table("(help)", helpList);
1106
+ });
1107
+ CLI.addCommand("register", "Register app commands (slash & context) globally, or per guild", async (args, content) => {
1108
+ const client = CLI.getClientInstance(content);
1109
+ if (!client) return;
1110
+ const mode = args[0]?.toLowerCase() || "";
1111
+ if (!["guild", "global"].includes(mode)) {
1112
+ return CLI.logger.error(`'${mode}' is not a valid option. Your options are [guild|global]`);
1113
+ }
1114
+ let guildIds = (import_qznt.$.str.getFlag(content, "--guilds", 1) || import_qznt.$.str.getFlag(content, "-g", 1) || "").replaceAll(/["']/g, "").split(" ").filter(Boolean).map((s) => s.replaceAll(",", "").trim());
1115
+ if (!guildIds.length) guildIds = client.guilds.cache.map((g) => g.id);
1116
+ switch (mode) {
1117
+ case "guild":
1118
+ CLI.logger.info("Registering guild commands...");
1119
+ await client.commands.registerGuild({ guilds: guildIds });
1120
+ break;
1121
+ case "global":
1122
+ CLI.logger.info("Registering global commands...");
1123
+ await client.commands.registerGlobal();
1124
+ break;
1125
+ }
1126
+ });
1127
+ CLI.addCommand("unregister", "Unregister app commands globally, or per guild", async (args, content) => {
1128
+ const client = CLI.getClientInstance(content);
1129
+ if (!client) return;
1130
+ const mode = args[0]?.toLowerCase() || "";
1131
+ if (!["guild", "global"].includes(mode)) {
1132
+ return CLI.logger.error(`'${mode}' is not a valid option. Your options are [guild|global]`);
1133
+ }
1134
+ let guildIds = (import_qznt.$.str.getFlag(content, "--guilds", 1) || import_qznt.$.str.getFlag(content, "-g", 1) || "").replaceAll(/["']/g, "").split(" ").filter(Boolean).map((s) => s.replaceAll(",", "").trim());
1135
+ if (!guildIds.length) guildIds = client.guilds.cache.map((g) => g.id);
1136
+ switch (mode) {
1137
+ case "guild":
1138
+ CLI.logger.info("Unregistering guild commands...");
1139
+ await client.commands.unregisterGuild({ guilds: guildIds });
1140
+ break;
1141
+ case "global":
1142
+ CLI.logger.info("Unregistering global commands...");
1143
+ await client.commands.unregisterGlobal();
1144
+ break;
1145
+ }
1146
+ });
1147
+ CLI.addCommand("stats", "View statistics about a client instance", (args, content) => {
1148
+ const client = CLI.getClientInstance(content);
1149
+ if (!client) return;
1150
+ CLI.logger.table(`(stats) ~ ${client.config.app.name}`, {
1151
+ "Guilds:": import_qznt.$.format.number(client.guilds.cache.size),
1152
+ "Ping:": `${client.ws.ping || 0}ms`,
1153
+ "Uptime:": `${import_qznt.$.math.secs(client.uptime || 0)}s`,
1154
+ "Process Uptime:": `${Math.floor(process.uptime())}s`,
1155
+ "Memory Usage:": `${(process.memoryUsage().rss / 1024 / 1024).toFixed(2)} MB`
1156
+ });
1157
+ });
1158
+ CLI.addCommand("cmds", "List the loaded commands", async (args, content) => {
1159
+ const client = CLI.getClientInstance(content);
1160
+ if (!client) return;
1161
+ const mode = (args[0] || "slash").toLowerCase();
1162
+ switch (mode) {
1163
+ case "slash": {
1164
+ const commands = Array.from(client.commands.slash.commands.values());
1165
+ commands.sort((a, b) => a.builder.name.localeCompare(b.builder.name));
1166
+ const tableData = {};
1167
+ for (const cmd of commands) {
1168
+ tableData[`/${cmd.builder.name}`] = `~ ${cmd.builder.description || "No description"}`;
1169
+ }
1170
+ return CLI.logger.table(`(cmds) ~ slash (${import_qznt.$.format.number(commands.length)})`, tableData);
1171
+ }
1172
+ case "prefix": {
1173
+ const commands = Array.from(client.commands.prefix.commands.values());
1174
+ commands.sort((a, b) => {
1175
+ const nameA = a.toConfig().name;
1176
+ const nameB = b.toConfig().name;
1177
+ return nameA.localeCompare(nameB);
1178
+ });
1179
+ const tableData = {};
1180
+ const defaultPrefix = client.config.prefixCommands.defaultPrefix;
1181
+ for (const cmd of commands) {
1182
+ const config = cmd.toConfig();
1183
+ const aliasIndicator = config.aliases?.length ? ` [${config.aliases.join(", ")}]` : "";
1184
+ tableData[`${defaultPrefix}${config.name}${aliasIndicator}`] = `~ ${config.description || "No description"}`;
1185
+ }
1186
+ return CLI.logger.table(`(cmds) ~ prefix (${import_qznt.$.format.number(commands.length)})`, tableData);
1187
+ }
1188
+ case "ctx": {
1189
+ const commands = Array.from(client.commands.context.commands.values());
1190
+ commands.sort((a, b) => a.builder.name.localeCompare(b.builder.name));
1191
+ const tableData = {};
1192
+ for (const cmd of commands) {
1193
+ const type = cmd.builder.type === 2 ? "User" : "Msg";
1194
+ tableData[`[${type}] ${cmd.builder.name}`] = "";
1195
+ }
1196
+ return CLI.logger.table(`(cmds) ~ ctx (${import_qznt.$.format.number(commands.length)})`, tableData);
1197
+ }
1198
+ default:
1199
+ return CLI.logger.error(`'${mode}' is not a valid option. Valid options: [slash|prefix|ctx]`);
1200
+ }
1201
+ });
1202
+
1169
1203
  // src/tools/BetterEmbed.ts
1170
1204
  var import_discord6 = require("discord.js");
1171
1205
 
1172
- // src/utils/config.factory.ts
1173
- var import_lodash5 = __toESM(require("lodash"));
1206
+ // src/utils/configFactory.ts
1174
1207
  function createConfigFactory(defaultConfig6, validate) {
1175
1208
  return (options = {}, existing) => {
1176
- const result = import_lodash5.default.merge({}, defaultConfig6, existing, options);
1209
+ const base = existing ? { ...existing } : { ...defaultConfig6 };
1210
+ const result = deepMerge(base, options);
1177
1211
  validate?.(result);
1178
1212
  return result;
1179
1213
  };
@@ -1667,7 +1701,7 @@ var BetterEmbed = class _BetterEmbed {
1667
1701
  }
1668
1702
  };
1669
1703
 
1670
- // src/utils/command-error.utils.ts
1704
+ // src/modules/builtins/commandError.builtin.ts
1671
1705
  var import_discord7 = require("discord.js");
1672
1706
  async function sendCommandErrorEmbed(client, error, guild, messageOrInteraction) {
1673
1707
  if (!client.features.enableCommandErrorMessage) return null;
@@ -1724,8 +1758,8 @@ ${error.stack}`), {
1724
1758
  return msg;
1725
1759
  }
1726
1760
 
1727
- // src/client/error-handler.ts
1728
- var ErrorHandler = class {
1761
+ // src/client/vimcord.errorHandler.ts
1762
+ var VimcordErrorHandler = class {
1729
1763
  client;
1730
1764
  constructor(client) {
1731
1765
  this.client = client;
@@ -1753,7 +1787,7 @@ var ErrorHandler = class {
1753
1787
  var import_chalk2 = __toESM(require("chalk"));
1754
1788
 
1755
1789
  // package.json
1756
- var version = "1.0.37";
1790
+ var version = "1.0.38";
1757
1791
 
1758
1792
  // src/client/vimcord.logger.ts
1759
1793
  var clientLoggerFactory = (client) => new Logger({ prefixEmoji: "\u26A1", prefix: `vimcord (i${client.clientId})` }).extend({
@@ -1818,7 +1852,7 @@ var clientLoggerFactory = (client) => new Logger({ prefixEmoji: "\u26A1", prefix
1818
1852
  }
1819
1853
  });
1820
1854
 
1821
- // src/utils/process.utils.ts
1855
+ // src/utils/processUtils.ts
1822
1856
  var import_node_fs = require("fs");
1823
1857
  var import_node_path = require("path");
1824
1858
  function getPackageJson() {
@@ -1861,6 +1895,7 @@ var createPrefixCommandConfig = createConfigFactory(defaultConfig3);
1861
1895
 
1862
1896
  // src/configs/slashCommand.config.ts
1863
1897
  var defaultConfig4 = {
1898
+ enabled: true,
1864
1899
  logExecution: true
1865
1900
  };
1866
1901
  var createSlashCommandConfig = createConfigFactory(defaultConfig4);
@@ -1896,31 +1931,31 @@ var configSetters = {
1896
1931
  app: createAppConfig,
1897
1932
  staff: createStaffConfig,
1898
1933
  slashCommands: createSlashCommandConfig,
1899
- prefixCommands: createPrefixCommandConfig,
1900
- contextCommands: createContextCommandConfig
1934
+ contextCommands: createContextCommandConfig,
1935
+ prefixCommands: createPrefixCommandConfig
1901
1936
  };
1902
1937
  var moduleImporters = {
1903
1938
  slashCommands: (client, options, set) => {
1904
1939
  const opt = options;
1905
- const dir = Array.isArray(options) ? options : opt?.dir ?? [];
1940
+ const dir = Array.isArray(options) ? options : typeof options === "string" ? options : options?.dir ?? [];
1906
1941
  const suffix = Array.isArray(options) ? DEFAULT_MODULE_SUFFIXES.slashCommands : opt?.suffix ?? DEFAULT_MODULE_SUFFIXES.slashCommands;
1907
1942
  return client.commands.slash.importFrom(dir, set, suffix);
1908
1943
  },
1909
1944
  contextCommands: (client, options, set) => {
1910
1945
  const opt = options;
1911
- const dir = Array.isArray(options) ? options : opt?.dir ?? [];
1946
+ const dir = Array.isArray(options) ? options : typeof options === "string" ? options : options?.dir ?? [];
1912
1947
  const suffix = Array.isArray(options) ? DEFAULT_MODULE_SUFFIXES.contextCommands : opt?.suffix ?? DEFAULT_MODULE_SUFFIXES.contextCommands;
1913
1948
  return client.commands.context.importFrom(dir, set, suffix);
1914
1949
  },
1915
1950
  prefixCommands: (client, options, set) => {
1916
1951
  const opt = options;
1917
- const dir = Array.isArray(options) ? options : opt?.dir ?? [];
1952
+ const dir = Array.isArray(options) ? options : typeof options === "string" ? options : options?.dir ?? [];
1918
1953
  const suffix = Array.isArray(options) ? DEFAULT_MODULE_SUFFIXES.prefixCommands : opt?.suffix ?? DEFAULT_MODULE_SUFFIXES.prefixCommands;
1919
1954
  return client.commands.prefix.importFrom(dir, set, suffix);
1920
1955
  },
1921
1956
  events: (client, options, set) => {
1922
1957
  const opt = options;
1923
- const dir = Array.isArray(options) ? options : opt?.dir ?? [];
1958
+ const dir = Array.isArray(options) ? options : typeof options === "string" ? options : options?.dir ?? [];
1924
1959
  const suffix = Array.isArray(options) ? DEFAULT_MODULE_SUFFIXES.events : opt?.suffix ?? DEFAULT_MODULE_SUFFIXES.events;
1925
1960
  return client.events.importFrom(dir, set, suffix);
1926
1961
  }
@@ -1940,29 +1975,41 @@ function defineVimcordConfig(config) {
1940
1975
  contextCommands: createContextCommandConfig(config.contextCommands)
1941
1976
  };
1942
1977
  }
1943
- var useClient = Vimcord.getInstance;
1944
- var useReadyClient = Vimcord.getReadyInstance;
1945
- var createClient = Vimcord.create;
1978
+ function useClient(clientId) {
1979
+ return Vimcord.getInstance(clientId);
1980
+ }
1981
+ function useReadyClient(clientId, timeoutMs) {
1982
+ return Vimcord.getReadyInstance(clientId, timeoutMs);
1983
+ }
1984
+ function createClient(options, features, config) {
1985
+ return Vimcord.create(options, features, config);
1986
+ }
1946
1987
 
1947
1988
  // src/modules/command.manager.ts
1948
1989
  var import_discord8 = require("discord.js");
1949
1990
 
1950
- // src/utils/import.utils.ts
1991
+ // src/utils/importUtils.ts
1951
1992
  var import_node_path2 = __toESM(require("path"));
1952
- var import_qznt = require("qznt");
1993
+ var import_qznt2 = require("qznt");
1953
1994
  function getProcessDir() {
1954
1995
  const mainPath = process.argv[1];
1955
1996
  if (!mainPath) return "";
1956
1997
  return import_node_path2.default.dirname(mainPath);
1957
1998
  }
1999
+ function testFilenameSuffix(filename, suffix) {
2000
+ if (!suffix) return filename.endsWith(".ts") || filename.endsWith(".js");
2001
+ if (Array.isArray(suffix)) {
2002
+ return suffix.some((s) => filename.endsWith(`${s}.ts`) || filename.endsWith(`${s}.js`));
2003
+ } else {
2004
+ return filename.endsWith(`${suffix}.ts`) || filename.endsWith(`${suffix}.js`);
2005
+ }
2006
+ }
1958
2007
  async function importModulesFromDir(dir, suffix) {
1959
2008
  const cwd = getProcessDir();
1960
2009
  const MODULE_RELATIVE_PATH = import_node_path2.default.join(cwd, dir);
1961
2010
  const MODULE_LOG_PATH = dir;
1962
- const files = import_qznt.$.fs.readDir(MODULE_RELATIVE_PATH).filter((fn) => fn.endsWith(`${suffix ? `.${suffix}` : ""}.js`) || fn.endsWith(`${suffix ? `.${suffix}` : ""}.ts`));
1963
- if (!files.length) {
1964
- return [];
1965
- }
2011
+ const files = import_qznt2.$.fs.readDir(MODULE_RELATIVE_PATH).filter((filename) => testFilenameSuffix(filename, suffix));
2012
+ if (!files.length) return [];
1966
2013
  const modules = await Promise.all(
1967
2014
  files.map(async (fn) => {
1968
2015
  let _path = import_node_path2.default.join(MODULE_RELATIVE_PATH, fn);
@@ -1985,7 +2032,7 @@ async function importModulesFromDir(dir, suffix) {
1985
2032
  return filteredModules;
1986
2033
  }
1987
2034
 
1988
- // src/modules/base-module.importer.ts
2035
+ // src/modules/importers/baseModule.importer.ts
1989
2036
  var ModuleImporter = class {
1990
2037
  client;
1991
2038
  constructor(client) {
@@ -1995,9 +2042,8 @@ var ModuleImporter = class {
1995
2042
  if (set) this.items.clear();
1996
2043
  const dirs = Array.isArray(dir) ? dir : [dir];
1997
2044
  const modules = [];
1998
- const effectiveSuffix = Array.isArray(suffix) ? suffix[0] : suffix ?? this.itemSuffix;
1999
2045
  for (const _dir of dirs) {
2000
- const results = await importModulesFromDir(_dir, effectiveSuffix ?? void 0);
2046
+ const results = await importModulesFromDir(_dir, suffix ?? this.itemSuffix);
2001
2047
  modules.push(...results.map(({ module: module2 }) => module2.default));
2002
2048
  }
2003
2049
  for (const module2 of modules) {
@@ -2446,7 +2492,6 @@ async function fetchRole(guild, roleId) {
2446
2492
 
2447
2493
  // src/types/status.ts
2448
2494
  var import_discord10 = require("discord.js");
2449
- var import_lodash6 = __toESM(require("lodash"));
2450
2495
  var StatusType = /* @__PURE__ */ ((StatusType2) => {
2451
2496
  StatusType2["DND"] = "dnd";
2452
2497
  StatusType2["Idle"] = "idle";
@@ -2469,12 +2514,12 @@ var defaultPresence = {
2469
2514
  }
2470
2515
  };
2471
2516
  function createVimcordStatusConfig(options = {}) {
2472
- return import_lodash6.default.merge(defaultPresence, options);
2517
+ return deepMerge({ ...defaultPresence }, options);
2473
2518
  }
2474
2519
 
2475
2520
  // src/modules/status.manager.ts
2476
2521
  var import_node_events = __toESM(require("events"));
2477
- var import_qznt2 = require("qznt");
2522
+ var import_qznt3 = require("qznt");
2478
2523
  var StatusManager = class {
2479
2524
  client;
2480
2525
  logger;
@@ -2509,14 +2554,14 @@ var StatusManager = class {
2509
2554
  return client;
2510
2555
  }
2511
2556
  async formatActivityName(name) {
2512
- name = name.replace("$USER_COUNT", import_qznt2.$.format.number(this.client.users.cache.size)).replace("$GUILD_COUNT", import_qznt2.$.format.number(this.client.guilds.cache.size)).replace(
2557
+ name = name.replace("$USER_COUNT", import_qznt3.$.format.number(this.client.users.cache.size)).replace("$GUILD_COUNT", import_qznt3.$.format.number(this.client.guilds.cache.size)).replace(
2513
2558
  "$INVITE",
2514
2559
  this.client.config.staff.guild.inviteUrl ? this.client.config.staff.guild.inviteUrl : "<STAFF_INVITE_URL_NOT_SET>"
2515
2560
  );
2516
2561
  if (name.includes("$STAFF_GUILD_MEMBER_COUNT")) {
2517
2562
  await fetchGuild(this.client, this.client.config.staff.guild.id).then((guild) => {
2518
2563
  if (!guild) return name = name.replace("$STAFF_GUILD_MEMBER_COUNT", "<STAFF_GUILD_NOT_FOUND>");
2519
- name = name.replace("$STAFF_GUILD_MEMBER_COUNT", import_qznt2.$.format.number(guild.members.cache.size));
2564
+ name = name.replace("$STAFF_GUILD_MEMBER_COUNT", import_qznt3.$.format.number(guild.members.cache.size));
2520
2565
  }).catch((err) => this.logger.error("Failed to fetch the staff guild", err));
2521
2566
  }
2522
2567
  return name;
@@ -2531,7 +2576,7 @@ var StatusManager = class {
2531
2576
  async statusRotationTask(clientStatus) {
2532
2577
  let activity;
2533
2578
  if (clientStatus.randomize && Array.isArray(clientStatus.activity)) {
2534
- activity = import_qznt2.$.rnd.choice(clientStatus.activity, { not: this.lastActivity });
2579
+ activity = import_qznt3.$.rnd.choice(clientStatus.activity, { not: this.lastActivity });
2535
2580
  this.lastActivity = activity;
2536
2581
  } else {
2537
2582
  const activityIndex = (this.lastActivityIndex + 1) % clientStatus.activity.length;
@@ -2545,7 +2590,7 @@ var StatusManager = class {
2545
2590
  if (!clientStatus.interval) throw new Error("Cannot create client activity interval without interval time");
2546
2591
  this.task?.stop();
2547
2592
  this.task = null;
2548
- this.task = new import_qznt2.$.Loop(() => this.statusRotationTask(clientStatus), import_qznt2.$.math.ms(clientStatus.interval), true);
2593
+ this.task = new import_qznt3.$.Loop(() => this.statusRotationTask(clientStatus), import_qznt3.$.math.ms(clientStatus.interval), true);
2549
2594
  this.start();
2550
2595
  }
2551
2596
  start() {
@@ -2595,196 +2640,6 @@ var StatusManager = class {
2595
2640
  }
2596
2641
  };
2597
2642
 
2598
- // src/utils/vimcord.cli.ts
2599
- var import_node_readline = require("readline");
2600
- var import_qznt3 = require("qznt");
2601
- var VimcordCLI = class _VimcordCLI {
2602
- static mode = "off";
2603
- static setMode(mode) {
2604
- if (_VimcordCLI.mode === mode) return;
2605
- _VimcordCLI.mode = mode;
2606
- if (mode === "on") {
2607
- CLI.logger.log(`~ Type ${CLI.options.prefix}help to view available commands`);
2608
- } else {
2609
- CLI.logger.log(`~ [MODE] Now set to "${mode}"`);
2610
- }
2611
- }
2612
- rl;
2613
- options;
2614
- commands = /* @__PURE__ */ new Map();
2615
- logger = new Logger({ prefixEmoji: "\u{1F680}", prefix: "CLI", showTimestamp: false });
2616
- constructor(options) {
2617
- this.options = options;
2618
- this.rl = (0, import_node_readline.createInterface)({
2619
- input: process.stdin,
2620
- output: process.stdout,
2621
- terminal: false
2622
- });
2623
- this.rl.on("line", (line) => {
2624
- if (_VimcordCLI.mode !== "on") return;
2625
- const { isCommand, commandName, content, args } = this.parseLine(line);
2626
- if (!isCommand) return;
2627
- const command = this.commands.get(commandName);
2628
- if (!command) {
2629
- const nearestMatches = Array.from(this.commands.keys()).filter(
2630
- (cmd) => cmd.toLowerCase().includes(commandName.toLowerCase())
2631
- );
2632
- return this.logger.error(
2633
- `Unknown command '${commandName}'${nearestMatches.length ? `. Did you mean ${nearestMatches.length > 1 ? `[${nearestMatches.map((m) => `'${this.options.prefix}${m}'`).join(", ")}]` : `'${this.options.prefix}${nearestMatches[0]}'`}?` : ""}`
2634
- );
2635
- }
2636
- command.fn(args, content);
2637
- });
2638
- }
2639
- parseLine(line) {
2640
- if (line.startsWith(this.options.prefix)) {
2641
- line = line.slice(this.options.prefix.length);
2642
- } else {
2643
- return { isCommand: false };
2644
- }
2645
- const args = line.split(" ").map((s) => s.trim());
2646
- const commandName = args.shift();
2647
- return { isCommand: true, commandName, content: args.join(" "), args };
2648
- }
2649
- getClientInstance(line) {
2650
- const clientIndex = import_qznt3.$.str.getFlag(line, "--client", 1) || import_qznt3.$.str.getFlag(line, "-c", 1);
2651
- if (clientIndex) {
2652
- const idx = Number(clientIndex);
2653
- if (isNaN(idx)) {
2654
- CLI.logger.error(`'${clientIndex}' is not a valid number`);
2655
- return void 0;
2656
- }
2657
- const client = useClient(idx);
2658
- if (!client) {
2659
- CLI.logger.error("Client instance not found");
2660
- return void 0;
2661
- }
2662
- return client;
2663
- } else {
2664
- const client = useClient(0);
2665
- if (!client) {
2666
- CLI.logger.error("Client instance not found");
2667
- return void 0;
2668
- }
2669
- return client;
2670
- }
2671
- }
2672
- addCommand(commandName, description, fn) {
2673
- this.commands.set(commandName, { description, fn });
2674
- }
2675
- removeCommand(commandName) {
2676
- if (!this.commands.has(commandName)) return false;
2677
- this.commands.delete(commandName);
2678
- return true;
2679
- }
2680
- };
2681
- var CLI = new VimcordCLI({ prefix: "/" });
2682
- CLI.addCommand("help", "View information about a command, or the available CLI options", (args) => {
2683
- const prefix = CLI.options.prefix;
2684
- const helpList = {};
2685
- for (const cmd of CLI.commands.entries()) {
2686
- const commandName = cmd[0];
2687
- const commandDescription = cmd[1].description;
2688
- helpList[`${prefix}${commandName}`] = `~ ${commandDescription}`;
2689
- }
2690
- CLI.logger.table("(help)", helpList);
2691
- });
2692
- CLI.addCommand("register", "Register app commands (slash & context) globally, or per guild", async (args, content) => {
2693
- const client = CLI.getClientInstance(content);
2694
- if (!client) return;
2695
- const mode = args[0]?.toLowerCase() || "";
2696
- if (!["guild", "global"].includes(mode)) {
2697
- return CLI.logger.error(`'${mode}' is not a valid option. Your options are [guild|global]`);
2698
- }
2699
- let guildIds = (import_qznt3.$.str.getFlag(content, "--guilds", 1) || import_qznt3.$.str.getFlag(content, "-g", 1) || "").replaceAll(/["']/g, "").split(" ").filter(Boolean).map((s) => s.replaceAll(",", "").trim());
2700
- if (!guildIds.length) guildIds = client.guilds.cache.map((g) => g.id);
2701
- switch (mode) {
2702
- case "guild":
2703
- CLI.logger.info("Registering guild commands...");
2704
- await client.commands.registerGuild({ guilds: guildIds });
2705
- break;
2706
- case "global":
2707
- CLI.logger.info("Registering global commands...");
2708
- await client.commands.registerGlobal();
2709
- break;
2710
- }
2711
- });
2712
- CLI.addCommand("unregister", "Unregister app commands globally, or per guild", async (args, content) => {
2713
- const client = CLI.getClientInstance(content);
2714
- if (!client) return;
2715
- const mode = args[0]?.toLowerCase() || "";
2716
- if (!["guild", "global"].includes(mode)) {
2717
- return CLI.logger.error(`'${mode}' is not a valid option. Your options are [guild|global]`);
2718
- }
2719
- let guildIds = (import_qznt3.$.str.getFlag(content, "--guilds", 1) || import_qznt3.$.str.getFlag(content, "-g", 1) || "").replaceAll(/["']/g, "").split(" ").filter(Boolean).map((s) => s.replaceAll(",", "").trim());
2720
- if (!guildIds.length) guildIds = client.guilds.cache.map((g) => g.id);
2721
- switch (mode) {
2722
- case "guild":
2723
- CLI.logger.info("Unregistering guild commands...");
2724
- await client.commands.unregisterGuild({ guilds: guildIds });
2725
- break;
2726
- case "global":
2727
- CLI.logger.info("Unregistering global commands...");
2728
- await client.commands.unregisterGlobal();
2729
- break;
2730
- }
2731
- });
2732
- CLI.addCommand("stats", "View statistics about a client instance", (args, content) => {
2733
- const client = CLI.getClientInstance(content);
2734
- if (!client) return;
2735
- CLI.logger.table(`(stats) ~ ${client.config.app.name}`, {
2736
- "Guilds:": import_qznt3.$.format.number(client.guilds.cache.size),
2737
- "Ping:": `${client.ws.ping || 0}ms`,
2738
- "Uptime:": `${import_qznt3.$.math.secs(client.uptime || 0)}s`,
2739
- "Process Uptime:": `${Math.floor(process.uptime())}s`,
2740
- "Memory Usage:": `${(process.memoryUsage().rss / 1024 / 1024).toFixed(2)} MB`
2741
- });
2742
- });
2743
- CLI.addCommand("cmds", "List the loaded commands", async (args, content) => {
2744
- const client = CLI.getClientInstance(content);
2745
- if (!client) return;
2746
- const mode = (args[0] || "slash").toLowerCase();
2747
- switch (mode) {
2748
- case "slash": {
2749
- const commands = Array.from(client.commands.slash.commands.values());
2750
- commands.sort((a, b) => a.builder.name.localeCompare(b.builder.name));
2751
- const tableData = {};
2752
- for (const cmd of commands) {
2753
- tableData[`/${cmd.builder.name}`] = `~ ${cmd.builder.description || "No description"}`;
2754
- }
2755
- return CLI.logger.table(`(cmds) ~ slash (${import_qznt3.$.format.number(commands.length)})`, tableData);
2756
- }
2757
- case "prefix": {
2758
- const commands = Array.from(client.commands.prefix.commands.values());
2759
- commands.sort((a, b) => {
2760
- const nameA = a.toConfig().name;
2761
- const nameB = b.toConfig().name;
2762
- return nameA.localeCompare(nameB);
2763
- });
2764
- const tableData = {};
2765
- const defaultPrefix = client.config.prefixCommands.defaultPrefix;
2766
- for (const cmd of commands) {
2767
- const config = cmd.toConfig();
2768
- const aliasIndicator = config.aliases?.length ? ` [${config.aliases.join(", ")}]` : "";
2769
- tableData[`${defaultPrefix}${config.name}${aliasIndicator}`] = `~ ${config.description || "No description"}`;
2770
- }
2771
- return CLI.logger.table(`(cmds) ~ prefix (${import_qznt3.$.format.number(commands.length)})`, tableData);
2772
- }
2773
- case "ctx": {
2774
- const commands = Array.from(client.commands.context.commands.values());
2775
- commands.sort((a, b) => a.builder.name.localeCompare(b.builder.name));
2776
- const tableData = {};
2777
- for (const cmd of commands) {
2778
- const type = cmd.builder.type === 2 ? "User" : "Msg";
2779
- tableData[`[${type}] ${cmd.builder.name}`] = "";
2780
- }
2781
- return CLI.logger.table(`(cmds) ~ ctx (${import_qznt3.$.format.number(commands.length)})`, tableData);
2782
- }
2783
- default:
2784
- return CLI.logger.error(`'${mode}' is not a valid option. Valid options: [slash|prefix|ctx]`);
2785
- }
2786
- });
2787
-
2788
2643
  // src/client/Vimcord.ts
2789
2644
  var import_discord11 = require("discord.js");
2790
2645
  var import_dotenv = require("dotenv");
@@ -2875,7 +2730,7 @@ var Vimcord = class _Vimcord extends import_discord11.Client {
2875
2730
  this.clientOptions = options;
2876
2731
  this.features = features;
2877
2732
  this.config = defineVimcordConfig(config);
2878
- this.error = new ErrorHandler(this);
2733
+ this.error = new VimcordErrorHandler(this);
2879
2734
  if (this.features.useGlobalErrorHandlers) {
2880
2735
  this.error.setupGlobalHandlers();
2881
2736
  }
@@ -3061,10 +2916,30 @@ var Vimcord = class _Vimcord extends import_discord11.Client {
3061
2916
  }
3062
2917
  };
3063
2918
 
3064
- // src/db/mongo/mongo-schema.builder.ts
3065
- var import_mongoose2 = require("mongoose");
3066
- var import_node_crypto4 = require("crypto");
3067
- var import_qznt6 = require("qznt");
2919
+ // src/client/error.handler.ts
2920
+ var ErrorHandler = class {
2921
+ client;
2922
+ constructor(client) {
2923
+ this.client = client;
2924
+ }
2925
+ /** Handles command errors - sends error embed to user, then rethrows. */
2926
+ async handleCommandError(error, guild, messageOrInteraction) {
2927
+ await sendCommandErrorEmbed(this.client, error, guild, messageOrInteraction);
2928
+ throw error;
2929
+ }
2930
+ /** Handles internal Vimcord errors - logs with [Vimcord] prefix. */
2931
+ handleVimcordError(error, context) {
2932
+ this.client.logger.error(`[Vimcord] [${context}]`, error);
2933
+ }
2934
+ /** Sets up global process error handlers. */
2935
+ setupGlobalHandlers() {
2936
+ process.on("uncaughtException", (err) => this.handleVimcordError(err, "Uncaught Exception"));
2937
+ process.on("unhandledRejection", (err) => this.handleVimcordError(err, "Unhandled Rejection"));
2938
+ process.on("exit", (code) => this.client.logger.debug(`Process exited with code ${code}`));
2939
+ this.client.on("error", (err) => this.handleVimcordError(err, "Client Error"));
2940
+ this.client.on("shardError", (err) => this.handleVimcordError(err, "Client Shard Error"));
2941
+ }
2942
+ };
3068
2943
 
3069
2944
  // src/db/mongo/mongo.database.ts
3070
2945
  var import_mongoose = __toESM(require("mongoose"));
@@ -3195,7 +3070,10 @@ var MongoDatabase = class _MongoDatabase {
3195
3070
  }
3196
3071
  };
3197
3072
 
3198
- // src/db/mongo/mongo-schema.builder.ts
3073
+ // src/db/mongo/mongoSchema.builder.ts
3074
+ var import_mongoose2 = require("mongoose");
3075
+ var import_node_crypto4 = require("crypto");
3076
+ var import_qznt6 = require("qznt");
3199
3077
  try {
3200
3078
  import("mongoose");
3201
3079
  } catch {
@@ -4589,6 +4467,7 @@ async function prompt(handler, options, sendOptions) {
4589
4467
  StatusType,
4590
4468
  Vimcord,
4591
4469
  VimcordCLI,
4470
+ VimcordErrorHandler,
4592
4471
  __zero,
4593
4472
  cleanMention,
4594
4473
  clientLoggerFactory,
@@ -4605,6 +4484,7 @@ async function prompt(handler, options, sendOptions) {
4605
4484
  createStaffConfig,
4606
4485
  createToolsConfig,
4607
4486
  createVimcordStatusConfig,
4487
+ deepMerge,
4608
4488
  defineClientOptions,
4609
4489
  defineGlobalToolsConfig,
4610
4490
  defineVimcordConfig,
@@ -4620,7 +4500,6 @@ async function prompt(handler, options, sendOptions) {
4620
4500
  getFirstMentionId,
4621
4501
  getMessageMention,
4622
4502
  getPackageJson,
4623
- getProcessDir,
4624
4503
  globalToolsConfig,
4625
4504
  importModulesFromDir,
4626
4505
  isMentionOrSnowflake,