vimcord 1.0.38 → 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.js CHANGED
@@ -133,8 +133,30 @@ function validateCommandPermissions(permissions, client, user, command) {
133
133
  return { validated: true };
134
134
  }
135
135
 
136
+ // src/utils/mergeUtils.ts
137
+ function isPlainObject(value) {
138
+ if (typeof value !== "object" || value === null) return false;
139
+ if (Array.isArray(value)) return false;
140
+ return Object.prototype.toString.call(value) === "[object Object]";
141
+ }
142
+ function deepMerge(target, ...sources) {
143
+ for (const source of sources) {
144
+ if (!source) continue;
145
+ for (const key in source) {
146
+ if (!Object.prototype.hasOwnProperty.call(source, key)) continue;
147
+ const sourceValue = source[key];
148
+ const targetValue = target[key];
149
+ if (isPlainObject(sourceValue) && isPlainObject(targetValue)) {
150
+ deepMerge(targetValue, sourceValue);
151
+ } else if (sourceValue !== void 0) {
152
+ target[key] = sourceValue;
153
+ }
154
+ }
155
+ }
156
+ return target;
157
+ }
158
+
136
159
  // src/builders/baseCommand.builder.ts
137
- import _ from "lodash";
138
160
  import { randomUUID } from "crypto";
139
161
  var BaseCommandBuilder = class {
140
162
  uuid = randomUUID();
@@ -148,8 +170,7 @@ var BaseCommandBuilder = class {
148
170
  [1 /* Guild */]: /* @__PURE__ */ new Map(),
149
171
  [2 /* Channel */]: /* @__PURE__ */ new Map()
150
172
  };
151
- /** * Mapping of CommandTypes to their respective config keys in the Vimcord client
152
- */
173
+ /** Mapping of CommandTypes to their respective config keys in the Vimcord client */
153
174
  typeConfigMapping = {
154
175
  [0 /* Slash */]: "slashCommands",
155
176
  [1 /* Prefix */]: "prefixCommands",
@@ -174,7 +195,7 @@ var BaseCommandBuilder = class {
174
195
  resolveConfig(client) {
175
196
  const typeKey = this.typeConfigMapping[this.commandType];
176
197
  const typeSpecificGlobals = client.config?.[typeKey] || {};
177
- return _.merge({}, typeSpecificGlobals, this.options);
198
+ return deepMerge({}, typeSpecificGlobals, this.options);
178
199
  }
179
200
  /**
180
201
  * Executes the command lifecycle.
@@ -292,12 +313,12 @@ var BaseCommandBuilder = class {
292
313
  }
293
314
  /** Merge new permission requirements into the existing ones */
294
315
  setPermissions(perms) {
295
- this.options.permissions = _.merge(this.options.permissions || {}, perms);
316
+ this.options.permissions = deepMerge(this.options.permissions || {}, perms);
296
317
  return this;
297
318
  }
298
- /** Add custom logic checks that run before execution */
299
- addConditions(...conditions) {
300
- this.options.conditions = [...this.options.conditions || [], ...conditions];
319
+ /** Set the custom conditions that must be met for this command to execute */
320
+ setConditions(conditions) {
321
+ this.options.conditions = conditions;
301
322
  return this;
302
323
  }
303
324
  /** Set the primary command execution logic */
@@ -305,79 +326,21 @@ var BaseCommandBuilder = class {
305
326
  this.options.execute = fn;
306
327
  return this;
307
328
  }
308
- /** * Set the custom conditions that must be met for this command to execute
309
- */
310
- setConditions(conditions) {
311
- this.options.conditions = conditions;
312
- return this;
313
- }
314
- /** * Set the command metadata configuration
315
- */
329
+ /** Set the command metadata configuration */
316
330
  setMetadata(metadata) {
317
- this.options.metadata = _.merge(this.options.metadata || {}, metadata);
331
+ this.options.metadata = deepMerge(this.options.metadata || {}, metadata);
318
332
  return this;
319
333
  }
320
- /** * Set the rate limiting options for this command
321
- */
334
+ /** Set the rate limiting options for this command */
322
335
  setRateLimit(options) {
323
336
  this.options.rateLimit = options;
324
337
  this.validateBaseConfig();
325
338
  return this;
326
339
  }
327
- /** * Set whether to log whenever this command is executed
328
- * @defaultValue true
329
- */
330
- setLogExecution(log) {
331
- this.options.logExecution = log;
332
- return this;
333
- }
334
- /** * Set the function to execute before the main command logic
335
- */
336
- setBeforeExecute(callback) {
337
- this.options.beforeExecute = callback;
338
- return this;
339
- }
340
- /** * Set the function to execute after successful command execution
341
- */
342
- setAfterExecute(callback) {
343
- this.options.afterExecute = callback;
344
- return this;
345
- }
346
- /** * Set the function to execute when the required permissions are not met
347
- */
348
- setOnMissingPermissions(callback) {
349
- this.options.onMissingPermissions = callback;
350
- return this;
351
- }
352
- /** * Set the function to execute when the required conditions are not met
353
- */
354
- setOnConditionsNotMet(callback) {
355
- this.options.onConditionsNotMet = callback;
356
- return this;
357
- }
358
- /** * Set the function to execute when this command is used when its disabled
359
- */
360
- setOnUsedWhenDisabled(callback) {
361
- this.options.onUsedWhenDisabled = callback;
362
- return this;
363
- }
364
- /** * Set the function to execute when the rate limit is hit
365
- */
366
- setOnRateLimit(callback) {
367
- this.options.onRateLimit = callback;
368
- return this;
369
- }
370
- /** * Set a custom error handler for this command
371
- */
372
- setOnError(callback) {
373
- this.options.onError = callback;
374
- return this;
375
- }
376
340
  };
377
341
 
378
342
  // src/builders/contextCommand.builder.ts
379
343
  import { ContextMenuCommandBuilder } from "discord.js";
380
- import _2 from "lodash";
381
344
  var ContextCommandBuilder = class extends BaseCommandBuilder {
382
345
  builder;
383
346
  constructor(config) {
@@ -405,14 +368,6 @@ var ContextCommandBuilder = class extends BaseCommandBuilder {
405
368
  this.validateBuilder();
406
369
  return this;
407
370
  }
408
- setDeferReply(defer) {
409
- this.options.deferReply = defer;
410
- return this;
411
- }
412
- setDeployment(deployment) {
413
- this.options.deployment = _2.merge(this.options.deployment || {}, deployment);
414
- return this;
415
- }
416
371
  setExecute(fn) {
417
372
  const originalExecute = fn;
418
373
  this.options.execute = async (client, interaction) => {
@@ -427,7 +382,6 @@ var ContextCommandBuilder = class extends BaseCommandBuilder {
427
382
 
428
383
  // src/builders/event.builder.ts
429
384
  import { randomUUID as randomUUID2 } from "crypto";
430
- import _3 from "lodash";
431
385
 
432
386
  // src/tools/Logger.ts
433
387
  import chalk from "chalk";
@@ -688,77 +642,14 @@ var EventBuilder = class _EventBuilder {
688
642
  onError: this.onError
689
643
  };
690
644
  }
691
- setEvent(event) {
692
- this.event = event;
693
- return this;
694
- }
695
- setName(name) {
696
- this.name = name;
697
- return this;
698
- }
699
645
  setEnabled(enabled) {
700
646
  this.enabled = enabled;
701
647
  return this;
702
648
  }
703
- enable() {
704
- return this.setEnabled(true);
705
- }
706
- disable() {
707
- return this.setEnabled(false);
708
- }
709
- setOnce(once = true) {
710
- this.once = once;
711
- return this;
712
- }
713
- setPriority(priority) {
714
- this.priority = priority;
715
- return this;
716
- }
717
- addCondition(condition) {
718
- if (!this.conditions) this.conditions = [];
719
- this.conditions.push(condition);
720
- return this;
721
- }
722
- setConditions(conditions) {
723
- this.conditions = conditions;
724
- return this;
725
- }
726
- setMetadata(metadata) {
727
- this.metadata = _3.merge(this.metadata, metadata);
728
- return this;
729
- }
730
- setDeployment(deployment) {
731
- this.deployment = _3.merge(this.deployment, deployment);
732
- return this;
733
- }
734
- setRateLimit(options) {
735
- this.rateLimit = options;
736
- return this;
737
- }
738
- setBeforeExecute(beforeExecute) {
739
- this.beforeExecute = beforeExecute;
740
- return this;
741
- }
742
649
  setExecute(execute) {
743
650
  this.execute = execute;
744
651
  return this;
745
652
  }
746
- setAfterExecute(afterExecute) {
747
- this.afterExecute = afterExecute;
748
- return this;
749
- }
750
- setOnError(onError) {
751
- this.onError = onError;
752
- return this;
753
- }
754
- getRateLimitInfo() {
755
- if (!this.rateLimit) return null;
756
- return { ...this.rateLimitData, isLimited: this.isRateLimited(false) };
757
- }
758
- resetRateLimit() {
759
- this.rateLimitData = { executions: 0, timestamp: 0 };
760
- return this;
761
- }
762
653
  isRateLimited(updateExecutions = true) {
763
654
  if (!this.rateLimit) return false;
764
655
  const now = Date.now();
@@ -831,39 +722,9 @@ var PrefixCommandBuilder = class extends BaseCommandBuilder {
831
722
  throw new Error(`[Vimcord] PrefixCommandBuilder: Command name is required.`);
832
723
  }
833
724
  }
834
- // --- Fluent API (Prefix Specific Only) ---
835
- /**
836
- * Set the primary name of the command.
837
- */
838
- setName(name) {
839
- this.options.name = name;
840
- return this;
841
- }
842
- /**
843
- * Set or replace the command aliases.
844
- */
845
- setAliases(aliases) {
846
- this.options.aliases = aliases;
847
- return this;
848
- }
849
- /**
850
- * Add additional aliases without clearing existing ones.
851
- */
852
- addAliases(...aliases) {
853
- this.options.aliases = [...this.options.aliases || [], ...aliases];
854
- return this;
855
- }
856
- /**
857
- * Set the command description.
858
- */
859
- setDescription(description) {
860
- this.options.description = description;
861
- return this;
862
- }
863
725
  // --- Overrides ---
864
726
  /**
865
727
  * Override setExecute to ensure handleExecution remains the entry point.
866
- * This is the only base method we need to redefine.
867
728
  */
868
729
  setExecute(fn) {
869
730
  const originalExecute = fn;
@@ -884,7 +745,6 @@ var PrefixCommandBuilder = class extends BaseCommandBuilder {
884
745
 
885
746
  // src/builders/slashCommand.builder.ts
886
747
  import { SlashCommandBuilder as DJSSlashCommandBuilder } from "discord.js";
887
- import _4 from "lodash";
888
748
  var SlashCommandBuilder = class extends BaseCommandBuilder {
889
749
  builder;
890
750
  routes = /* @__PURE__ */ new Map();
@@ -925,19 +785,6 @@ var SlashCommandBuilder = class extends BaseCommandBuilder {
925
785
  this.validateBuilder();
926
786
  return this;
927
787
  }
928
- setDeferReply(defer) {
929
- this.options.deferReply = defer;
930
- return this;
931
- }
932
- setDeployment(deployment) {
933
- this.options.deployment = _4.merge(this.options.deployment || {}, deployment);
934
- return this;
935
- }
936
- setRoutes(...routes) {
937
- this.routes.clear();
938
- this.addRoutes(...routes);
939
- return this;
940
- }
941
788
  addRoutes(...routes) {
942
789
  if (!this.options.routes) this.options.routes = [];
943
790
  for (const route of routes) {
@@ -949,10 +796,6 @@ var SlashCommandBuilder = class extends BaseCommandBuilder {
949
796
  }
950
797
  return this;
951
798
  }
952
- setUnknownRouteHandler(handler) {
953
- this.options.onUnknownRouteHandler = handler;
954
- return this;
955
- }
956
799
  setExecute(fn) {
957
800
  const originalExecute = fn;
958
801
  this.options.execute = async (client, interaction) => {
@@ -969,7 +812,7 @@ var SlashCommandBuilder = class extends BaseCommandBuilder {
969
812
  }
970
813
  };
971
814
 
972
- // src/modules/builtins/context-command.builtins.ts
815
+ // src/modules/builtins/contextCommand.builtin.ts
973
816
  var contextCommandHandler = new EventBuilder({
974
817
  event: "interactionCreate",
975
818
  name: "ContextCommandHandler",
@@ -991,7 +834,7 @@ var contextCommandHandler = new EventBuilder({
991
834
  }
992
835
  });
993
836
 
994
- // src/modules/builtins/prefix-command.builtins.ts
837
+ // src/modules/builtins/prefixCommand.builtin.ts
995
838
  import { userMention } from "discord.js";
996
839
  var prefixCommandHandler = new EventBuilder({
997
840
  event: "messageCreate",
@@ -1033,7 +876,7 @@ var prefixCommandHandler = new EventBuilder({
1033
876
  }
1034
877
  });
1035
878
 
1036
- // src/modules/builtins/slash-command.builtins.ts
879
+ // src/modules/builtins/slashCommand.builtin.ts
1037
880
  var slashCommandHandler = new EventBuilder({
1038
881
  event: "interactionCreate",
1039
882
  name: "SlashCommandHandler",
@@ -1055,6 +898,196 @@ var slashCommandHandler = new EventBuilder({
1055
898
  }
1056
899
  });
1057
900
 
901
+ // src/client/vimcord.cli.ts
902
+ import { createInterface } from "readline";
903
+ import { $ } from "qznt";
904
+ var VimcordCLI = class _VimcordCLI {
905
+ static mode = "off";
906
+ static setMode(mode) {
907
+ if (_VimcordCLI.mode === mode) return;
908
+ _VimcordCLI.mode = mode;
909
+ if (mode === "on") {
910
+ CLI.logger.log(`~ Type ${CLI.options.prefix}help to view available commands`);
911
+ } else {
912
+ CLI.logger.log(`~ [MODE] Now set to "${mode}"`);
913
+ }
914
+ }
915
+ rl;
916
+ options;
917
+ commands = /* @__PURE__ */ new Map();
918
+ logger = new Logger({ prefixEmoji: "\u{1F680}", prefix: "CLI", showTimestamp: false });
919
+ constructor(options) {
920
+ this.options = options;
921
+ this.rl = createInterface({
922
+ input: process.stdin,
923
+ output: process.stdout,
924
+ terminal: false
925
+ });
926
+ this.rl.on("line", (line) => {
927
+ if (_VimcordCLI.mode !== "on") return;
928
+ const { isCommand, commandName, content, args } = this.parseLine(line);
929
+ if (!isCommand) return;
930
+ const command = this.commands.get(commandName);
931
+ if (!command) {
932
+ const nearestMatches = Array.from(this.commands.keys()).filter(
933
+ (cmd) => cmd.toLowerCase().includes(commandName.toLowerCase())
934
+ );
935
+ return this.logger.error(
936
+ `Unknown command '${commandName}'${nearestMatches.length ? `. Did you mean ${nearestMatches.length > 1 ? `[${nearestMatches.map((m) => `'${this.options.prefix}${m}'`).join(", ")}]` : `'${this.options.prefix}${nearestMatches[0]}'`}?` : ""}`
937
+ );
938
+ }
939
+ command.fn(args, content);
940
+ });
941
+ }
942
+ parseLine(line) {
943
+ if (line.startsWith(this.options.prefix)) {
944
+ line = line.slice(this.options.prefix.length);
945
+ } else {
946
+ return { isCommand: false };
947
+ }
948
+ const args = line.split(" ").map((s) => s.trim());
949
+ const commandName = args.shift();
950
+ return { isCommand: true, commandName, content: args.join(" "), args };
951
+ }
952
+ getClientInstance(line) {
953
+ const clientIndex = $.str.getFlag(line, "--client", 1) || $.str.getFlag(line, "-c", 1);
954
+ if (clientIndex) {
955
+ const idx = Number(clientIndex);
956
+ if (isNaN(idx)) {
957
+ CLI.logger.error(`'${clientIndex}' is not a valid number`);
958
+ return void 0;
959
+ }
960
+ const client = useClient(idx);
961
+ if (!client) {
962
+ CLI.logger.error("Client instance not found");
963
+ return void 0;
964
+ }
965
+ return client;
966
+ } else {
967
+ const client = useClient(0);
968
+ if (!client) {
969
+ CLI.logger.error("Client instance not found");
970
+ return void 0;
971
+ }
972
+ return client;
973
+ }
974
+ }
975
+ addCommand(commandName, description, fn) {
976
+ this.commands.set(commandName, { description, fn });
977
+ }
978
+ removeCommand(commandName) {
979
+ if (!this.commands.has(commandName)) return false;
980
+ this.commands.delete(commandName);
981
+ return true;
982
+ }
983
+ };
984
+ var CLI = new VimcordCLI({ prefix: "/" });
985
+ CLI.addCommand("help", "View information about a command, or the available CLI options", (args) => {
986
+ const prefix = CLI.options.prefix;
987
+ const helpList = {};
988
+ for (const cmd of CLI.commands.entries()) {
989
+ const commandName = cmd[0];
990
+ const commandDescription = cmd[1].description;
991
+ helpList[`${prefix}${commandName}`] = `~ ${commandDescription}`;
992
+ }
993
+ CLI.logger.table("(help)", helpList);
994
+ });
995
+ CLI.addCommand("register", "Register app commands (slash & context) globally, or per guild", async (args, content) => {
996
+ const client = CLI.getClientInstance(content);
997
+ if (!client) return;
998
+ const mode = args[0]?.toLowerCase() || "";
999
+ if (!["guild", "global"].includes(mode)) {
1000
+ return CLI.logger.error(`'${mode}' is not a valid option. Your options are [guild|global]`);
1001
+ }
1002
+ let guildIds = ($.str.getFlag(content, "--guilds", 1) || $.str.getFlag(content, "-g", 1) || "").replaceAll(/["']/g, "").split(" ").filter(Boolean).map((s) => s.replaceAll(",", "").trim());
1003
+ if (!guildIds.length) guildIds = client.guilds.cache.map((g) => g.id);
1004
+ switch (mode) {
1005
+ case "guild":
1006
+ CLI.logger.info("Registering guild commands...");
1007
+ await client.commands.registerGuild({ guilds: guildIds });
1008
+ break;
1009
+ case "global":
1010
+ CLI.logger.info("Registering global commands...");
1011
+ await client.commands.registerGlobal();
1012
+ break;
1013
+ }
1014
+ });
1015
+ CLI.addCommand("unregister", "Unregister app commands globally, or per guild", async (args, content) => {
1016
+ const client = CLI.getClientInstance(content);
1017
+ if (!client) return;
1018
+ const mode = args[0]?.toLowerCase() || "";
1019
+ if (!["guild", "global"].includes(mode)) {
1020
+ return CLI.logger.error(`'${mode}' is not a valid option. Your options are [guild|global]`);
1021
+ }
1022
+ let guildIds = ($.str.getFlag(content, "--guilds", 1) || $.str.getFlag(content, "-g", 1) || "").replaceAll(/["']/g, "").split(" ").filter(Boolean).map((s) => s.replaceAll(",", "").trim());
1023
+ if (!guildIds.length) guildIds = client.guilds.cache.map((g) => g.id);
1024
+ switch (mode) {
1025
+ case "guild":
1026
+ CLI.logger.info("Unregistering guild commands...");
1027
+ await client.commands.unregisterGuild({ guilds: guildIds });
1028
+ break;
1029
+ case "global":
1030
+ CLI.logger.info("Unregistering global commands...");
1031
+ await client.commands.unregisterGlobal();
1032
+ break;
1033
+ }
1034
+ });
1035
+ CLI.addCommand("stats", "View statistics about a client instance", (args, content) => {
1036
+ const client = CLI.getClientInstance(content);
1037
+ if (!client) return;
1038
+ CLI.logger.table(`(stats) ~ ${client.config.app.name}`, {
1039
+ "Guilds:": $.format.number(client.guilds.cache.size),
1040
+ "Ping:": `${client.ws.ping || 0}ms`,
1041
+ "Uptime:": `${$.math.secs(client.uptime || 0)}s`,
1042
+ "Process Uptime:": `${Math.floor(process.uptime())}s`,
1043
+ "Memory Usage:": `${(process.memoryUsage().rss / 1024 / 1024).toFixed(2)} MB`
1044
+ });
1045
+ });
1046
+ CLI.addCommand("cmds", "List the loaded commands", async (args, content) => {
1047
+ const client = CLI.getClientInstance(content);
1048
+ if (!client) return;
1049
+ const mode = (args[0] || "slash").toLowerCase();
1050
+ switch (mode) {
1051
+ case "slash": {
1052
+ const commands = Array.from(client.commands.slash.commands.values());
1053
+ commands.sort((a, b) => a.builder.name.localeCompare(b.builder.name));
1054
+ const tableData = {};
1055
+ for (const cmd of commands) {
1056
+ tableData[`/${cmd.builder.name}`] = `~ ${cmd.builder.description || "No description"}`;
1057
+ }
1058
+ return CLI.logger.table(`(cmds) ~ slash (${$.format.number(commands.length)})`, tableData);
1059
+ }
1060
+ case "prefix": {
1061
+ const commands = Array.from(client.commands.prefix.commands.values());
1062
+ commands.sort((a, b) => {
1063
+ const nameA = a.toConfig().name;
1064
+ const nameB = b.toConfig().name;
1065
+ return nameA.localeCompare(nameB);
1066
+ });
1067
+ const tableData = {};
1068
+ const defaultPrefix = client.config.prefixCommands.defaultPrefix;
1069
+ for (const cmd of commands) {
1070
+ const config = cmd.toConfig();
1071
+ const aliasIndicator = config.aliases?.length ? ` [${config.aliases.join(", ")}]` : "";
1072
+ tableData[`${defaultPrefix}${config.name}${aliasIndicator}`] = `~ ${config.description || "No description"}`;
1073
+ }
1074
+ return CLI.logger.table(`(cmds) ~ prefix (${$.format.number(commands.length)})`, tableData);
1075
+ }
1076
+ case "ctx": {
1077
+ const commands = Array.from(client.commands.context.commands.values());
1078
+ commands.sort((a, b) => a.builder.name.localeCompare(b.builder.name));
1079
+ const tableData = {};
1080
+ for (const cmd of commands) {
1081
+ const type = cmd.builder.type === 2 ? "User" : "Msg";
1082
+ tableData[`[${type}] ${cmd.builder.name}`] = "";
1083
+ }
1084
+ return CLI.logger.table(`(cmds) ~ ctx (${$.format.number(commands.length)})`, tableData);
1085
+ }
1086
+ default:
1087
+ return CLI.logger.error(`'${mode}' is not a valid option. Valid options: [slash|prefix|ctx]`);
1088
+ }
1089
+ });
1090
+
1058
1091
  // src/tools/BetterEmbed.ts
1059
1092
  import {
1060
1093
  EmbedBuilder,
@@ -1062,11 +1095,11 @@ import {
1062
1095
  User as User3
1063
1096
  } from "discord.js";
1064
1097
 
1065
- // src/utils/config.factory.ts
1066
- import _5 from "lodash";
1098
+ // src/utils/configFactory.ts
1067
1099
  function createConfigFactory(defaultConfig6, validate) {
1068
1100
  return (options = {}, existing) => {
1069
- const result = _5.merge({}, defaultConfig6, existing, options);
1101
+ const base = existing ? { ...existing } : { ...defaultConfig6 };
1102
+ const result = deepMerge(base, options);
1070
1103
  validate?.(result);
1071
1104
  return result;
1072
1105
  };
@@ -1567,7 +1600,7 @@ var BetterEmbed = class _BetterEmbed {
1567
1600
  }
1568
1601
  };
1569
1602
 
1570
- // src/utils/command-error.utils.ts
1603
+ // src/modules/builtins/commandError.builtin.ts
1571
1604
  import {
1572
1605
  ActionRowBuilder as ActionRowBuilder2,
1573
1606
  AttachmentBuilder,
@@ -1631,8 +1664,8 @@ ${error.stack}`), {
1631
1664
  return msg;
1632
1665
  }
1633
1666
 
1634
- // src/client/error-handler.ts
1635
- var ErrorHandler = class {
1667
+ // src/client/vimcord.errorHandler.ts
1668
+ var VimcordErrorHandler = class {
1636
1669
  client;
1637
1670
  constructor(client) {
1638
1671
  this.client = client;
@@ -1725,7 +1758,7 @@ var clientLoggerFactory = (client) => new Logger({ prefixEmoji: "\u26A1", prefix
1725
1758
  }
1726
1759
  });
1727
1760
 
1728
- // src/utils/process.utils.ts
1761
+ // src/utils/processUtils.ts
1729
1762
  import { readFileSync } from "fs";
1730
1763
  import { join } from "path";
1731
1764
  function getPackageJson() {
@@ -1768,6 +1801,7 @@ var createPrefixCommandConfig = createConfigFactory(defaultConfig3);
1768
1801
 
1769
1802
  // src/configs/slashCommand.config.ts
1770
1803
  var defaultConfig4 = {
1804
+ enabled: true,
1771
1805
  logExecution: true
1772
1806
  };
1773
1807
  var createSlashCommandConfig = createConfigFactory(defaultConfig4);
@@ -1860,22 +1894,28 @@ function createClient(options, features, config) {
1860
1894
  // src/modules/command.manager.ts
1861
1895
  import { Routes } from "discord.js";
1862
1896
 
1863
- // src/utils/import.utils.ts
1897
+ // src/utils/importUtils.ts
1864
1898
  import path from "path";
1865
- import { $ } from "qznt";
1899
+ import { $ as $2 } from "qznt";
1866
1900
  function getProcessDir() {
1867
1901
  const mainPath = process.argv[1];
1868
1902
  if (!mainPath) return "";
1869
1903
  return path.dirname(mainPath);
1870
1904
  }
1905
+ function testFilenameSuffix(filename, suffix) {
1906
+ if (!suffix) return filename.endsWith(".ts") || filename.endsWith(".js");
1907
+ if (Array.isArray(suffix)) {
1908
+ return suffix.some((s) => filename.endsWith(`${s}.ts`) || filename.endsWith(`${s}.js`));
1909
+ } else {
1910
+ return filename.endsWith(`${suffix}.ts`) || filename.endsWith(`${suffix}.js`);
1911
+ }
1912
+ }
1871
1913
  async function importModulesFromDir(dir, suffix) {
1872
1914
  const cwd = getProcessDir();
1873
1915
  const MODULE_RELATIVE_PATH = path.join(cwd, dir);
1874
1916
  const MODULE_LOG_PATH = dir;
1875
- const files = $.fs.readDir(MODULE_RELATIVE_PATH).filter((fn) => fn.endsWith(`${suffix ? `${suffix}` : ""}.js`) || fn.endsWith(`${suffix ? `${suffix}` : ""}.ts`));
1876
- if (!files.length) {
1877
- return [];
1878
- }
1917
+ const files = $2.fs.readDir(MODULE_RELATIVE_PATH).filter((filename) => testFilenameSuffix(filename, suffix));
1918
+ if (!files.length) return [];
1879
1919
  const modules = await Promise.all(
1880
1920
  files.map(async (fn) => {
1881
1921
  let _path = path.join(MODULE_RELATIVE_PATH, fn);
@@ -1898,7 +1938,7 @@ async function importModulesFromDir(dir, suffix) {
1898
1938
  return filteredModules;
1899
1939
  }
1900
1940
 
1901
- // src/modules/base-module.importer.ts
1941
+ // src/modules/importers/baseModule.importer.ts
1902
1942
  var ModuleImporter = class {
1903
1943
  client;
1904
1944
  constructor(client) {
@@ -1908,9 +1948,8 @@ var ModuleImporter = class {
1908
1948
  if (set) this.items.clear();
1909
1949
  const dirs = Array.isArray(dir) ? dir : [dir];
1910
1950
  const modules = [];
1911
- const effectiveSuffix = Array.isArray(suffix) ? suffix[0] : suffix ?? this.itemSuffix;
1912
1951
  for (const _dir of dirs) {
1913
- const results = await importModulesFromDir(_dir, effectiveSuffix ?? void 0);
1952
+ const results = await importModulesFromDir(_dir, suffix ?? this.itemSuffix);
1914
1953
  modules.push(...results.map(({ module }) => module.default));
1915
1954
  }
1916
1955
  for (const module of modules) {
@@ -2359,7 +2398,6 @@ async function fetchRole(guild, roleId) {
2359
2398
 
2360
2399
  // src/types/status.ts
2361
2400
  import { ActivityType } from "discord.js";
2362
- import _6 from "lodash";
2363
2401
  var StatusType = /* @__PURE__ */ ((StatusType2) => {
2364
2402
  StatusType2["DND"] = "dnd";
2365
2403
  StatusType2["Idle"] = "idle";
@@ -2382,12 +2420,12 @@ var defaultPresence = {
2382
2420
  }
2383
2421
  };
2384
2422
  function createVimcordStatusConfig(options = {}) {
2385
- return _6.merge(defaultPresence, options);
2423
+ return deepMerge({ ...defaultPresence }, options);
2386
2424
  }
2387
2425
 
2388
2426
  // src/modules/status.manager.ts
2389
2427
  import EventEmitter from "events";
2390
- import { $ as $2 } from "qznt";
2428
+ import { $ as $3 } from "qznt";
2391
2429
  var StatusManager = class {
2392
2430
  client;
2393
2431
  logger;
@@ -2422,14 +2460,14 @@ var StatusManager = class {
2422
2460
  return client;
2423
2461
  }
2424
2462
  async formatActivityName(name) {
2425
- 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(
2463
+ name = name.replace("$USER_COUNT", $3.format.number(this.client.users.cache.size)).replace("$GUILD_COUNT", $3.format.number(this.client.guilds.cache.size)).replace(
2426
2464
  "$INVITE",
2427
2465
  this.client.config.staff.guild.inviteUrl ? this.client.config.staff.guild.inviteUrl : "<STAFF_INVITE_URL_NOT_SET>"
2428
2466
  );
2429
2467
  if (name.includes("$STAFF_GUILD_MEMBER_COUNT")) {
2430
2468
  await fetchGuild(this.client, this.client.config.staff.guild.id).then((guild) => {
2431
2469
  if (!guild) return name = name.replace("$STAFF_GUILD_MEMBER_COUNT", "<STAFF_GUILD_NOT_FOUND>");
2432
- name = name.replace("$STAFF_GUILD_MEMBER_COUNT", $2.format.number(guild.members.cache.size));
2470
+ name = name.replace("$STAFF_GUILD_MEMBER_COUNT", $3.format.number(guild.members.cache.size));
2433
2471
  }).catch((err) => this.logger.error("Failed to fetch the staff guild", err));
2434
2472
  }
2435
2473
  return name;
@@ -2444,7 +2482,7 @@ var StatusManager = class {
2444
2482
  async statusRotationTask(clientStatus) {
2445
2483
  let activity;
2446
2484
  if (clientStatus.randomize && Array.isArray(clientStatus.activity)) {
2447
- activity = $2.rnd.choice(clientStatus.activity, { not: this.lastActivity });
2485
+ activity = $3.rnd.choice(clientStatus.activity, { not: this.lastActivity });
2448
2486
  this.lastActivity = activity;
2449
2487
  } else {
2450
2488
  const activityIndex = (this.lastActivityIndex + 1) % clientStatus.activity.length;
@@ -2458,7 +2496,7 @@ var StatusManager = class {
2458
2496
  if (!clientStatus.interval) throw new Error("Cannot create client activity interval without interval time");
2459
2497
  this.task?.stop();
2460
2498
  this.task = null;
2461
- this.task = new $2.Loop(() => this.statusRotationTask(clientStatus), $2.math.ms(clientStatus.interval), true);
2499
+ this.task = new $3.Loop(() => this.statusRotationTask(clientStatus), $3.math.ms(clientStatus.interval), true);
2462
2500
  this.start();
2463
2501
  }
2464
2502
  start() {
@@ -2508,196 +2546,6 @@ var StatusManager = class {
2508
2546
  }
2509
2547
  };
2510
2548
 
2511
- // src/utils/vimcord.cli.ts
2512
- import { createInterface } from "readline";
2513
- import { $ as $3 } from "qznt";
2514
- var VimcordCLI = class _VimcordCLI {
2515
- static mode = "off";
2516
- static setMode(mode) {
2517
- if (_VimcordCLI.mode === mode) return;
2518
- _VimcordCLI.mode = mode;
2519
- if (mode === "on") {
2520
- CLI.logger.log(`~ Type ${CLI.options.prefix}help to view available commands`);
2521
- } else {
2522
- CLI.logger.log(`~ [MODE] Now set to "${mode}"`);
2523
- }
2524
- }
2525
- rl;
2526
- options;
2527
- commands = /* @__PURE__ */ new Map();
2528
- logger = new Logger({ prefixEmoji: "\u{1F680}", prefix: "CLI", showTimestamp: false });
2529
- constructor(options) {
2530
- this.options = options;
2531
- this.rl = createInterface({
2532
- input: process.stdin,
2533
- output: process.stdout,
2534
- terminal: false
2535
- });
2536
- this.rl.on("line", (line) => {
2537
- if (_VimcordCLI.mode !== "on") return;
2538
- const { isCommand, commandName, content, args } = this.parseLine(line);
2539
- if (!isCommand) return;
2540
- const command = this.commands.get(commandName);
2541
- if (!command) {
2542
- const nearestMatches = Array.from(this.commands.keys()).filter(
2543
- (cmd) => cmd.toLowerCase().includes(commandName.toLowerCase())
2544
- );
2545
- return this.logger.error(
2546
- `Unknown command '${commandName}'${nearestMatches.length ? `. Did you mean ${nearestMatches.length > 1 ? `[${nearestMatches.map((m) => `'${this.options.prefix}${m}'`).join(", ")}]` : `'${this.options.prefix}${nearestMatches[0]}'`}?` : ""}`
2547
- );
2548
- }
2549
- command.fn(args, content);
2550
- });
2551
- }
2552
- parseLine(line) {
2553
- if (line.startsWith(this.options.prefix)) {
2554
- line = line.slice(this.options.prefix.length);
2555
- } else {
2556
- return { isCommand: false };
2557
- }
2558
- const args = line.split(" ").map((s) => s.trim());
2559
- const commandName = args.shift();
2560
- return { isCommand: true, commandName, content: args.join(" "), args };
2561
- }
2562
- getClientInstance(line) {
2563
- const clientIndex = $3.str.getFlag(line, "--client", 1) || $3.str.getFlag(line, "-c", 1);
2564
- if (clientIndex) {
2565
- const idx = Number(clientIndex);
2566
- if (isNaN(idx)) {
2567
- CLI.logger.error(`'${clientIndex}' is not a valid number`);
2568
- return void 0;
2569
- }
2570
- const client = useClient(idx);
2571
- if (!client) {
2572
- CLI.logger.error("Client instance not found");
2573
- return void 0;
2574
- }
2575
- return client;
2576
- } else {
2577
- const client = useClient(0);
2578
- if (!client) {
2579
- CLI.logger.error("Client instance not found");
2580
- return void 0;
2581
- }
2582
- return client;
2583
- }
2584
- }
2585
- addCommand(commandName, description, fn) {
2586
- this.commands.set(commandName, { description, fn });
2587
- }
2588
- removeCommand(commandName) {
2589
- if (!this.commands.has(commandName)) return false;
2590
- this.commands.delete(commandName);
2591
- return true;
2592
- }
2593
- };
2594
- var CLI = new VimcordCLI({ prefix: "/" });
2595
- CLI.addCommand("help", "View information about a command, or the available CLI options", (args) => {
2596
- const prefix = CLI.options.prefix;
2597
- const helpList = {};
2598
- for (const cmd of CLI.commands.entries()) {
2599
- const commandName = cmd[0];
2600
- const commandDescription = cmd[1].description;
2601
- helpList[`${prefix}${commandName}`] = `~ ${commandDescription}`;
2602
- }
2603
- CLI.logger.table("(help)", helpList);
2604
- });
2605
- CLI.addCommand("register", "Register app commands (slash & context) globally, or per guild", async (args, content) => {
2606
- const client = CLI.getClientInstance(content);
2607
- if (!client) return;
2608
- const mode = args[0]?.toLowerCase() || "";
2609
- if (!["guild", "global"].includes(mode)) {
2610
- return CLI.logger.error(`'${mode}' is not a valid option. Your options are [guild|global]`);
2611
- }
2612
- let guildIds = ($3.str.getFlag(content, "--guilds", 1) || $3.str.getFlag(content, "-g", 1) || "").replaceAll(/["']/g, "").split(" ").filter(Boolean).map((s) => s.replaceAll(",", "").trim());
2613
- if (!guildIds.length) guildIds = client.guilds.cache.map((g) => g.id);
2614
- switch (mode) {
2615
- case "guild":
2616
- CLI.logger.info("Registering guild commands...");
2617
- await client.commands.registerGuild({ guilds: guildIds });
2618
- break;
2619
- case "global":
2620
- CLI.logger.info("Registering global commands...");
2621
- await client.commands.registerGlobal();
2622
- break;
2623
- }
2624
- });
2625
- CLI.addCommand("unregister", "Unregister app commands globally, or per guild", async (args, content) => {
2626
- const client = CLI.getClientInstance(content);
2627
- if (!client) return;
2628
- const mode = args[0]?.toLowerCase() || "";
2629
- if (!["guild", "global"].includes(mode)) {
2630
- return CLI.logger.error(`'${mode}' is not a valid option. Your options are [guild|global]`);
2631
- }
2632
- let guildIds = ($3.str.getFlag(content, "--guilds", 1) || $3.str.getFlag(content, "-g", 1) || "").replaceAll(/["']/g, "").split(" ").filter(Boolean).map((s) => s.replaceAll(",", "").trim());
2633
- if (!guildIds.length) guildIds = client.guilds.cache.map((g) => g.id);
2634
- switch (mode) {
2635
- case "guild":
2636
- CLI.logger.info("Unregistering guild commands...");
2637
- await client.commands.unregisterGuild({ guilds: guildIds });
2638
- break;
2639
- case "global":
2640
- CLI.logger.info("Unregistering global commands...");
2641
- await client.commands.unregisterGlobal();
2642
- break;
2643
- }
2644
- });
2645
- CLI.addCommand("stats", "View statistics about a client instance", (args, content) => {
2646
- const client = CLI.getClientInstance(content);
2647
- if (!client) return;
2648
- CLI.logger.table(`(stats) ~ ${client.config.app.name}`, {
2649
- "Guilds:": $3.format.number(client.guilds.cache.size),
2650
- "Ping:": `${client.ws.ping || 0}ms`,
2651
- "Uptime:": `${$3.math.secs(client.uptime || 0)}s`,
2652
- "Process Uptime:": `${Math.floor(process.uptime())}s`,
2653
- "Memory Usage:": `${(process.memoryUsage().rss / 1024 / 1024).toFixed(2)} MB`
2654
- });
2655
- });
2656
- CLI.addCommand("cmds", "List the loaded commands", async (args, content) => {
2657
- const client = CLI.getClientInstance(content);
2658
- if (!client) return;
2659
- const mode = (args[0] || "slash").toLowerCase();
2660
- switch (mode) {
2661
- case "slash": {
2662
- const commands = Array.from(client.commands.slash.commands.values());
2663
- commands.sort((a, b) => a.builder.name.localeCompare(b.builder.name));
2664
- const tableData = {};
2665
- for (const cmd of commands) {
2666
- tableData[`/${cmd.builder.name}`] = `~ ${cmd.builder.description || "No description"}`;
2667
- }
2668
- return CLI.logger.table(`(cmds) ~ slash (${$3.format.number(commands.length)})`, tableData);
2669
- }
2670
- case "prefix": {
2671
- const commands = Array.from(client.commands.prefix.commands.values());
2672
- commands.sort((a, b) => {
2673
- const nameA = a.toConfig().name;
2674
- const nameB = b.toConfig().name;
2675
- return nameA.localeCompare(nameB);
2676
- });
2677
- const tableData = {};
2678
- const defaultPrefix = client.config.prefixCommands.defaultPrefix;
2679
- for (const cmd of commands) {
2680
- const config = cmd.toConfig();
2681
- const aliasIndicator = config.aliases?.length ? ` [${config.aliases.join(", ")}]` : "";
2682
- tableData[`${defaultPrefix}${config.name}${aliasIndicator}`] = `~ ${config.description || "No description"}`;
2683
- }
2684
- return CLI.logger.table(`(cmds) ~ prefix (${$3.format.number(commands.length)})`, tableData);
2685
- }
2686
- case "ctx": {
2687
- const commands = Array.from(client.commands.context.commands.values());
2688
- commands.sort((a, b) => a.builder.name.localeCompare(b.builder.name));
2689
- const tableData = {};
2690
- for (const cmd of commands) {
2691
- const type = cmd.builder.type === 2 ? "User" : "Msg";
2692
- tableData[`[${type}] ${cmd.builder.name}`] = "";
2693
- }
2694
- return CLI.logger.table(`(cmds) ~ ctx (${$3.format.number(commands.length)})`, tableData);
2695
- }
2696
- default:
2697
- return CLI.logger.error(`'${mode}' is not a valid option. Valid options: [slash|prefix|ctx]`);
2698
- }
2699
- });
2700
-
2701
2549
  // src/client/Vimcord.ts
2702
2550
  import { Client as Client2 } from "discord.js";
2703
2551
  import { configDotenv } from "dotenv";
@@ -2788,7 +2636,7 @@ var Vimcord = class _Vimcord extends Client2 {
2788
2636
  this.clientOptions = options;
2789
2637
  this.features = features;
2790
2638
  this.config = defineVimcordConfig(config);
2791
- this.error = new ErrorHandler(this);
2639
+ this.error = new VimcordErrorHandler(this);
2792
2640
  if (this.features.useGlobalErrorHandlers) {
2793
2641
  this.error.setupGlobalHandlers();
2794
2642
  }
@@ -2974,12 +2822,30 @@ var Vimcord = class _Vimcord extends Client2 {
2974
2822
  }
2975
2823
  };
2976
2824
 
2977
- // src/db/mongo/mongo-schema.builder.ts
2978
- import {
2979
- Schema
2980
- } from "mongoose";
2981
- import { randomBytes } from "crypto";
2982
- import { $ as $6 } from "qznt";
2825
+ // src/client/error.handler.ts
2826
+ var ErrorHandler = class {
2827
+ client;
2828
+ constructor(client) {
2829
+ this.client = client;
2830
+ }
2831
+ /** Handles command errors - sends error embed to user, then rethrows. */
2832
+ async handleCommandError(error, guild, messageOrInteraction) {
2833
+ await sendCommandErrorEmbed(this.client, error, guild, messageOrInteraction);
2834
+ throw error;
2835
+ }
2836
+ /** Handles internal Vimcord errors - logs with [Vimcord] prefix. */
2837
+ handleVimcordError(error, context) {
2838
+ this.client.logger.error(`[Vimcord] [${context}]`, error);
2839
+ }
2840
+ /** Sets up global process error handlers. */
2841
+ setupGlobalHandlers() {
2842
+ process.on("uncaughtException", (err) => this.handleVimcordError(err, "Uncaught Exception"));
2843
+ process.on("unhandledRejection", (err) => this.handleVimcordError(err, "Unhandled Rejection"));
2844
+ process.on("exit", (code) => this.client.logger.debug(`Process exited with code ${code}`));
2845
+ this.client.on("error", (err) => this.handleVimcordError(err, "Client Error"));
2846
+ this.client.on("shardError", (err) => this.handleVimcordError(err, "Client Shard Error"));
2847
+ }
2848
+ };
2983
2849
 
2984
2850
  // src/db/mongo/mongo.database.ts
2985
2851
  import mongoose, { ConnectionStates } from "mongoose";
@@ -3110,7 +2976,12 @@ var MongoDatabase = class _MongoDatabase {
3110
2976
  }
3111
2977
  };
3112
2978
 
3113
- // src/db/mongo/mongo-schema.builder.ts
2979
+ // src/db/mongo/mongoSchema.builder.ts
2980
+ import {
2981
+ Schema
2982
+ } from "mongoose";
2983
+ import { randomBytes } from "crypto";
2984
+ import { $ as $6 } from "qznt";
3114
2985
  try {
3115
2986
  import("mongoose");
3116
2987
  } catch {
@@ -4532,6 +4403,7 @@ export {
4532
4403
  StatusType,
4533
4404
  Vimcord,
4534
4405
  VimcordCLI,
4406
+ VimcordErrorHandler,
4535
4407
  __zero,
4536
4408
  cleanMention,
4537
4409
  clientLoggerFactory,
@@ -4548,6 +4420,7 @@ export {
4548
4420
  createStaffConfig,
4549
4421
  createToolsConfig,
4550
4422
  createVimcordStatusConfig,
4423
+ deepMerge,
4551
4424
  defineClientOptions,
4552
4425
  defineGlobalToolsConfig,
4553
4426
  defineVimcordConfig,
@@ -4563,7 +4436,6 @@ export {
4563
4436
  getFirstMentionId,
4564
4437
  getMessageMention,
4565
4438
  getPackageJson,
4566
- getProcessDir,
4567
4439
  globalToolsConfig,
4568
4440
  importModulesFromDir,
4569
4441
  isMentionOrSnowflake,