xernerx 4.7.0 → 4.8.0

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.
Files changed (39) hide show
  1. package/dist/build/XernerxContextCommand.d.ts +4 -2
  2. package/dist/build/XernerxContextCommand.js +3 -2
  3. package/dist/build/XernerxMessageCommand.d.ts +4 -2
  4. package/dist/build/XernerxMessageCommand.js +3 -2
  5. package/dist/build/XernerxSlashCommand.d.ts +4 -2
  6. package/dist/build/XernerxSlashCommand.js +3 -2
  7. package/dist/client/XernerxClient.d.ts +8 -5
  8. package/dist/client/XernerxClient.js +5 -2
  9. package/dist/functions/load.js +1 -0
  10. package/dist/functions/reload.d.ts +2 -2
  11. package/dist/functions/reload.js +24 -37
  12. package/dist/handlers/CommandHandler.d.ts +3 -2
  13. package/dist/handlers/CommandHandler.js +42 -20
  14. package/dist/handlers/EventHandler.d.ts +1 -0
  15. package/dist/handlers/EventHandler.js +6 -3
  16. package/dist/handlers/ExtensionHandler.d.ts +1 -0
  17. package/dist/handlers/ExtensionHandler.js +6 -2
  18. package/dist/handlers/Handler.d.ts +1 -2
  19. package/dist/handlers/Handler.js +0 -2
  20. package/dist/handlers/InhibitorHandler.d.ts +1 -0
  21. package/dist/handlers/InhibitorHandler.js +8 -3
  22. package/dist/handlers/WebhookHandler.d.ts +1 -0
  23. package/dist/handlers/WebhookHandler.js +1 -0
  24. package/dist/main.d.ts +2 -5
  25. package/dist/main.js +2 -24
  26. package/dist/models/Cooldowns.d.ts +11 -0
  27. package/dist/models/Cooldowns.js +33 -0
  28. package/dist/tools/XernerxIntents.d.ts +5 -0
  29. package/dist/tools/XernerxIntents.js +24 -0
  30. package/dist/tools/XernerxLog.js +0 -1
  31. package/dist/types/extenders.d.ts +8 -5
  32. package/dist/types/interfaces.d.ts +7 -6
  33. package/dist/utils/InteractionUtil.d.ts +6 -2
  34. package/dist/utils/InteractionUtil.js +4 -1
  35. package/dist/utils/MessageUtil.d.ts +3 -2
  36. package/dist/utils/MessageUtil.js +1 -1
  37. package/dist/utils/Util.d.ts +1 -1
  38. package/dist/validators/commandValidation.js +91 -25
  39. package/package.json +2 -2
@@ -2,6 +2,7 @@
2
2
  import { ContextMenuCommandBuilder } from 'discord.js';
3
3
  import { XernerxMessageContextInteraction, XernerxUserContextInteraction, XernerxClientType } from '../types/extenders.js';
4
4
  import { ContextCommandArguments, ContextCommandOptions } from '../types/interfaces.js';
5
+ import InteractionUtil from '../utils/InteractionUtil.js';
5
6
  export default class XernerxContextCommand {
6
7
  readonly id: string;
7
8
  readonly data: ContextMenuCommandBuilder;
@@ -29,8 +30,8 @@ export default class XernerxContextCommand {
29
30
  voice?: boolean | undefined;
30
31
  } | undefined;
31
32
  readonly permissions: {
32
- user?: string[] | import("../main.js").PermissionNames[] | undefined;
33
- client?: string[] | import("../main.js").PermissionNames[] | undefined;
33
+ user?: string[] | import("../main.js").PermissionNames[] | null | undefined;
34
+ client?: string[] | import("../main.js").PermissionNames[] | null | undefined;
34
35
  dm?: boolean | undefined;
35
36
  } | undefined;
36
37
  readonly defer: {
@@ -41,6 +42,7 @@ export default class XernerxContextCommand {
41
42
  readonly filetype: 'ContextCommand';
42
43
  readonly filepath: string;
43
44
  readonly client: XernerxClientType;
45
+ util: InteractionUtil;
44
46
  constructor(id: string, options: ContextCommandOptions);
45
47
  /**
46
48
  * @description the execution of the command
@@ -79,8 +79,8 @@ export default class XernerxContextCommand {
79
79
  .default({}),
80
80
  permissions: z
81
81
  .object({
82
- user: z.array(z.string()).default([]),
83
- client: z.array(z.string()).default([]),
82
+ user: z.array(z.string()).or(z.null()).default(null),
83
+ client: z.array(z.string()).or(z.null()).default(null),
84
84
  dm: z.boolean().default(true),
85
85
  })
86
86
  .default({}),
@@ -107,6 +107,7 @@ export default class XernerxContextCommand {
107
107
  this.permissions = options.permissions;
108
108
  this.defer = options.defer;
109
109
  this.client = this.client;
110
+ this.util = this.util;
110
111
  }
111
112
  /**
112
113
  * @description the execution of the command
@@ -1,6 +1,7 @@
1
1
  /** @format */
2
2
  import { XernerxClientType, XernerxMessage } from '../types/extenders.js';
3
3
  import { MessageCommandArguments, MessageCommandOptions } from '../types/interfaces.js';
4
+ import MessageUtil from '../utils/MessageUtil.js';
4
5
  export default class XernerxMessageCommand {
5
6
  readonly id: string;
6
7
  readonly name: string;
@@ -32,13 +33,14 @@ export default class XernerxMessageCommand {
32
33
  voice?: boolean | undefined;
33
34
  } | undefined;
34
35
  readonly permissions: {
35
- user?: string[] | import("../main.js").PermissionNames[] | undefined;
36
- client?: string[] | import("../main.js").PermissionNames[] | undefined;
36
+ user?: string[] | import("../main.js").PermissionNames[] | null | undefined;
37
+ client?: string[] | import("../main.js").PermissionNames[] | null | undefined;
37
38
  dm?: boolean | undefined;
38
39
  } | undefined;
39
40
  readonly filetype: 'MessageCommand';
40
41
  readonly filepath: string;
41
42
  readonly client: XernerxClientType;
43
+ util: MessageUtil;
42
44
  constructor(id: string, options: MessageCommandOptions);
43
45
  /**
44
46
  * @description Checks for conditions before running the command
@@ -77,8 +77,8 @@ export default class XernerxMessageCommand {
77
77
  .default({}),
78
78
  permissions: z
79
79
  .object({
80
- user: z.array(z.string()).default([]),
81
- client: z.array(z.string()).default([]),
80
+ user: z.array(z.string()).or(z.null()).default(null),
81
+ client: z.array(z.string()).or(z.null()).default(null),
82
82
  dm: z.boolean().default(true),
83
83
  })
84
84
  .default({}),
@@ -99,6 +99,7 @@ export default class XernerxMessageCommand {
99
99
  this.separator = options.separator;
100
100
  this.permissions = options.permissions;
101
101
  this.client = this.client;
102
+ this.util = this.util;
102
103
  }
103
104
  /**
104
105
  * @description Checks for conditions before running the command
@@ -3,6 +3,7 @@ import Discord from 'discord.js';
3
3
  import { XernerxClientType, XernerxMessageContextInteraction, XernerxSlashInteraction, XernerxUserContextInteraction } from '../types/extenders.js';
4
4
  import { SlashCommandArguments, SlashCommandOptions } from '../types/interfaces.js';
5
5
  import { XernerxInteraction } from '../types/types.js';
6
+ import InteractionUtil from '../utils/InteractionUtil.js';
6
7
  export default class XernerxSlashCommand {
7
8
  readonly id: string;
8
9
  readonly data: Discord.SlashCommandBuilder;
@@ -29,8 +30,8 @@ export default class XernerxSlashCommand {
29
30
  voice?: boolean | undefined;
30
31
  } | undefined;
31
32
  readonly permissions: {
32
- user?: string[] | import("../main.js").PermissionNames[] | undefined;
33
- client?: string[] | import("../main.js").PermissionNames[] | undefined;
33
+ user?: string[] | import("../main.js").PermissionNames[] | null | undefined;
34
+ client?: string[] | import("../main.js").PermissionNames[] | null | undefined;
34
35
  dm?: boolean | undefined;
35
36
  } | undefined;
36
37
  readonly defer: {
@@ -41,6 +42,7 @@ export default class XernerxSlashCommand {
41
42
  readonly filetype: 'SlashCommand';
42
43
  readonly filepath: string;
43
44
  readonly client: XernerxClientType;
45
+ util: InteractionUtil;
44
46
  constructor(id: string, options: SlashCommandOptions);
45
47
  /**
46
48
  * @description autocomplete let's you add choices to string option arguments
@@ -88,8 +88,8 @@ export default class XernerxSlashCommand {
88
88
  .default({}),
89
89
  permissions: z
90
90
  .object({
91
- user: z.array(z.string()).default([]),
92
- client: z.array(z.string()).default([]),
91
+ user: z.array(z.string()).or(z.null()).default(null),
92
+ client: z.array(z.string()).or(z.null()).default(null),
93
93
  dm: z.boolean().default(true),
94
94
  })
95
95
  .default({}),
@@ -115,6 +115,7 @@ export default class XernerxSlashCommand {
115
115
  this.permissions = options.permissions;
116
116
  this.defer = options.defer;
117
117
  this.client = this.client;
118
+ this.util = this.util;
118
119
  }
119
120
  /**
120
121
  * @description autocomplete let's you add choices to string option arguments
@@ -3,14 +3,15 @@ import { Client, ClientOptions, Collection } from 'discord.js';
3
3
  import { XernerxOptions, ModuleOptions, XernerxCommands, XernerxCache } from '../types/interfaces.js';
4
4
  import ClientUtil from '../utils/ClientUtil.js';
5
5
  import { XernerxInhibitor, XernerxEvent } from '../main.js';
6
- export default class XernerxClient<T = unknown> extends Client {
6
+ import Cooldowns from '../models/Cooldowns.js';
7
+ export default class XernerxClient extends Client {
7
8
  readonly settings: {
8
9
  ownerId: (string | string[]) & (string | string[] | undefined);
9
10
  local: string;
10
11
  global?: boolean | undefined;
11
12
  permissions?: {
12
- client: string[];
13
- user: string[];
13
+ user: string[] | null;
14
+ client: string[] | null;
14
15
  dm: boolean;
15
16
  } | undefined;
16
17
  ignore?: {
@@ -32,9 +33,10 @@ export default class XernerxClient<T = unknown> extends Client {
32
33
  cooldown?: {
33
34
  command: number;
34
35
  cache: number;
36
+ collections: string[];
35
37
  } | undefined;
36
38
  };
37
- readonly config: NonNullable<T> | null;
39
+ readonly config: {} | null;
38
40
  readonly commands: XernerxCommands;
39
41
  readonly events: Collection<string, XernerxEvent>;
40
42
  readonly inhibitors: Collection<string, XernerxInhibitor>;
@@ -42,6 +44,7 @@ export default class XernerxClient<T = unknown> extends Client {
42
44
  readonly util: ClientUtil;
43
45
  readonly stats: Record<string, number>;
44
46
  readonly cache: XernerxCache;
45
- constructor(discordOptions: ClientOptions, xernerxOptions: XernerxOptions, config?: T);
47
+ readonly cooldowns: Cooldowns;
48
+ constructor(discordOptions: ClientOptions, xernerxOptions: XernerxOptions, config?: unknown);
46
49
  connect(token: string): Promise<string>;
47
50
  }
@@ -9,6 +9,7 @@ import XernerxLog from '../tools/XernerxLog.js';
9
9
  import ClientUtil from '../utils/ClientUtil.js';
10
10
  import ExtensionHandler from '../handlers/ExtensionHandler.js';
11
11
  import deploy from '../functions/deploy.js';
12
+ import Cooldowns from '../models/Cooldowns.js';
12
13
  export default class XernerxClient extends Client {
13
14
  constructor(discordOptions, xernerxOptions, config) {
14
15
  super(discordOptions);
@@ -19,8 +20,8 @@ export default class XernerxClient extends Client {
19
20
  ownerId: z.string().or(z.array(z.string())).default([]),
20
21
  permissions: z
21
22
  .object({
22
- client: z.array(z.string()).default([]),
23
- user: z.array(z.string()).default([]),
23
+ client: z.array(z.string()).or(z.null()).default(null),
24
+ user: z.array(z.string()).or(z.null()).default(null),
24
25
  dm: z.boolean().default(false),
25
26
  })
26
27
  .optional(),
@@ -49,6 +50,7 @@ export default class XernerxClient extends Client {
49
50
  .object({
50
51
  command: z.number().default(0),
51
52
  cache: z.number().default(0),
53
+ collections: z.array(z.string()).default(['commands']),
52
54
  })
53
55
  .optional(),
54
56
  })
@@ -80,6 +82,7 @@ export default class XernerxClient extends Client {
80
82
  messages: new Collection(),
81
83
  cooldowns: new Collection(),
82
84
  };
85
+ this.cooldowns = new Cooldowns(this, xernerxOptions.cooldown?.collections);
83
86
  return this;
84
87
  }
85
88
  async connect(token) {
@@ -6,6 +6,7 @@ export default async function load(client, path, type) {
6
6
  file.filetype = type;
7
7
  file.filepath = path;
8
8
  file.client = client;
9
+ file.util = {};
9
10
  fileSave(client, file, type);
10
11
  return file;
11
12
  }
@@ -1,3 +1,3 @@
1
1
  /** @format */
2
- import XernerxClient from '../client/XernerxClient.js';
3
- export default function reload(client: XernerxClient, type: 'message' | 'slash' | 'context' | 'event' | 'inhibitor'): Promise<any>[];
2
+ import { XernerxClient } from '../main.js';
3
+ export default function reload(client: XernerxClient, type: 'commands' | 'context' | 'message' | 'slash' | 'events' | 'inhibitors'): Promise<true | void | null>;
@@ -1,43 +1,30 @@
1
1
  /** @format */
2
- var filetypes;
3
- (function (filetypes) {
4
- filetypes["message"] = "MessageCommand";
5
- filetypes["slash"] = "SlashCommand";
6
- filetypes["context"] = "ContextCommand";
7
- filetypes["event"] = "Event";
8
- filetypes["inhibitor"] = "Inhibitor";
9
- })(filetypes || (filetypes = {}));
10
- export default function reload(client, type) {
11
- const files = [];
12
- if (type === 'message' || type === 'slash' || type === 'context') {
13
- for (const [name] of client.commands[type]) {
14
- files.push(client.commands[type].get(name).filepath);
2
+ import * as path from 'path';
3
+ import * as fs from 'fs';
4
+ import load from './load.js';
5
+ export default async function reload(client, type) {
6
+ switch (type) {
7
+ case 'message': {
8
+ client.commands.message.clear();
9
+ if (!client.modules.options.message)
10
+ return null;
11
+ const directory = path.resolve(client.modules.options.message?.directory);
12
+ for (const file of fs.readdirSync(directory)) {
13
+ load(client, `${directory}\\${file}`, 'MessageCommand');
14
+ }
15
+ return true;
15
16
  }
16
- client.commands[type].sweep(() => true);
17
- }
18
- if (type === 'event') {
19
- for (const [name] of client.events) {
20
- files.push(client.events.get(name).filepath);
17
+ case 'slash': {
18
+ return client.commands.slash.clear();
21
19
  }
22
- client.events.sweep(() => true);
23
- }
24
- if (type === 'inhibitor') {
25
- for (const [name] of client.inhibitors) {
26
- files.push(client.inhibitors.get(name).filepath);
20
+ case 'context': {
21
+ return client.commands.context.clear();
22
+ }
23
+ case 'events': {
24
+ return client.events.clear();
25
+ }
26
+ case 'inhibitors': {
27
+ return client.inhibitors.clear();
27
28
  }
28
- client.inhibitors.sweep(() => true);
29
29
  }
30
- return files.map(async (file) => {
31
- let filedata = new (await import(`file://${file}`)).default();
32
- filedata.filetype = filetypes[type];
33
- filedata.filepath = file;
34
- filedata.client = client;
35
- if (type === 'message' || type === 'slash' || type === 'context')
36
- client.commands[type].set(filedata.name, filedata);
37
- if (type === 'event')
38
- client.events.set(filedata.name, filedata);
39
- if (type === 'inhibitor')
40
- client.inhibitors.set(filedata.name, filedata);
41
- return filedata;
42
- });
43
30
  }
@@ -3,10 +3,11 @@ import XernerxClient from '../client/XernerxClient.js';
3
3
  import { ContextHandlerOptions, MessageHandlerOptions, SlashHandlerOptions } from '../types/interfaces.js';
4
4
  import Handler from './Handler.js';
5
5
  export default class CommandHandler extends Handler {
6
+ readonly readyTimestamp: number;
6
7
  constructor(client: XernerxClient);
7
8
  loadMessageCommands(options: MessageHandlerOptions): Promise<void>;
8
- loadSlashCommands(options: SlashHandlerOptions): void;
9
- loadContextCommands(options: ContextHandlerOptions): void;
9
+ loadSlashCommands(options: SlashHandlerOptions): Promise<void>;
10
+ loadContextCommands(options: ContextHandlerOptions): Promise<void>;
10
11
  private messageCommandRun;
11
12
  private slashCommandRun;
12
13
  private contextCommandRun;
@@ -14,8 +14,10 @@ import { Style } from 'dumfunctions';
14
14
  export default class CommandHandler extends Handler {
15
15
  constructor(client) {
16
16
  super(client);
17
+ this.readyTimestamp = Number(Date.now());
17
18
  }
18
19
  async loadMessageCommands(options) {
20
+ const commands = [];
19
21
  if (!this.client.options.intents.has(GatewayIntentBits.MessageContent))
20
22
  new XernerxLog(this.client).warn(`Message commands might not work as you're missing the intent MessageContent!`);
21
23
  if (!this.client.options.intents.has(GatewayIntentBits.GuildMessages))
@@ -28,8 +30,8 @@ export default class CommandHandler extends Handler {
28
30
  cooldown: z.number().default(0),
29
31
  permissions: z
30
32
  .object({
31
- user: z.array(z.string()).default([]),
32
- client: z.array(z.string()).default([]),
33
+ user: z.array(z.string()).or(z.null()).default(null),
34
+ client: z.array(z.string()).or(z.null()).default(null),
33
35
  dm: z.boolean().default(true),
34
36
  })
35
37
  .default({}),
@@ -45,8 +47,9 @@ export default class CommandHandler extends Handler {
45
47
  const filepath = `${path.resolve(options.directory)}\\${file}`;
46
48
  const command = await this.load(filepath, 'MessageCommand');
47
49
  this._checks(command);
50
+ commands.push(command.id);
48
51
  }
49
- new XernerxLog(this.client).info(`Loaded ${Style.log(String(files.length), { color: Style.TextColor.Cyan })} Message Commands.`);
52
+ new XernerxLog(this.client).info(`Loaded ${Style.log(String(files.length), { color: Style.TextColor.Cyan })} Message Commands: ${commands.map((command) => Style.log(command, { color: Style.TextColor.LightYellow })).join(', ')}`);
50
53
  this.emit({
51
54
  name: 'messageCreate',
52
55
  filetype: 'MessageCommand',
@@ -64,9 +67,10 @@ export default class CommandHandler extends Handler {
64
67
  });
65
68
  }
66
69
  // public reloadMessageCommands() {
67
- // return reload(this.client, 'message');
70
+ // return reload(this.client, 'message');
68
71
  // }
69
- loadSlashCommands(options) {
72
+ async loadSlashCommands(options) {
73
+ const commands = [];
70
74
  if (!this.client.settings.local)
71
75
  new XernerxLog(this.client).warn(`Slash commands might not work as you haven't specified a local guild ID.`);
72
76
  options = z
@@ -75,8 +79,8 @@ export default class CommandHandler extends Handler {
75
79
  cooldown: z.number().default(0),
76
80
  permissions: z
77
81
  .object({
78
- user: z.array(z.string()).default([]),
79
- client: z.array(z.string()).default([]),
82
+ user: z.array(z.string()).or(z.null()).default(null),
83
+ client: z.array(z.string()).or(z.null()).default(null),
80
84
  dm: z.boolean().default(true),
81
85
  })
82
86
  .default({}),
@@ -94,16 +98,18 @@ export default class CommandHandler extends Handler {
94
98
  const files = this.readdir(options.directory);
95
99
  for (const file of files) {
96
100
  const filepath = `${path.resolve(options.directory)}\\${file}`;
97
- this.load(filepath, 'SlashCommand');
101
+ const command = await this.load(filepath, 'SlashCommand');
102
+ commands.push(command.id);
98
103
  }
99
- new XernerxLog(this.client).info(`Loaded ${Style.log(String(files.length), { color: Style.TextColor.Cyan })} Slash Commands.`);
104
+ new XernerxLog(this.client).info(`Loaded ${Style.log(String(files.length), { color: Style.TextColor.Cyan })} Slash Commands: ${commands.map((command) => Style.log(command, { color: Style.TextColor.LightYellow })).join(', ')}`);
100
105
  this.emit({
101
106
  name: 'interactionCreate',
102
107
  filetype: 'SlashCommand',
103
108
  run: (interaction) => this.slashCommandRun(interaction),
104
109
  });
105
110
  }
106
- loadContextCommands(options) {
111
+ async loadContextCommands(options) {
112
+ const commands = [];
107
113
  if (!this.client.settings.local)
108
114
  new XernerxLog(this.client).warn(`Context commands might not work as you haven't specified a local guild ID.`);
109
115
  options = z
@@ -112,8 +118,8 @@ export default class CommandHandler extends Handler {
112
118
  cooldown: z.number().default(0),
113
119
  permissions: z
114
120
  .object({
115
- user: z.array(z.string()).default([]),
116
- client: z.array(z.string()).default([]),
121
+ user: z.array(z.string()).or(z.null()).default(null),
122
+ client: z.array(z.string()).or(z.null()).default(null),
117
123
  dm: z.boolean().default(true),
118
124
  })
119
125
  .default({}),
@@ -131,9 +137,10 @@ export default class CommandHandler extends Handler {
131
137
  const files = this.readdir(options.directory);
132
138
  for (const file of files) {
133
139
  const filepath = `${path.resolve(options.directory)}\\${file}`;
134
- this.load(filepath, 'ContextCommand');
140
+ const command = await this.load(filepath, 'ContextCommand');
141
+ commands.push(command.id);
135
142
  }
136
- new XernerxLog(this.client).info(`Loaded ${Style.log(String(files.length), { color: Style.TextColor.Cyan })} Context Commands.`);
143
+ new XernerxLog(this.client).info(`Loaded ${Style.log(String(files.length), { color: Style.TextColor.Cyan })} Context Commands: ${commands.map((command) => Style.log(command, { color: Style.TextColor.LightYellow })).join(', ')}`);
137
144
  this.emit({
138
145
  name: 'interactionCreate',
139
146
  filetype: 'ContextCommand',
@@ -231,12 +238,15 @@ export default class CommandHandler extends Handler {
231
238
  return;
232
239
  if (!cmd)
233
240
  return await this.client.emit('commandNotFound', message, commandName, filetype);
241
+ await this.client.emit('commandStart', message, cmd, filetype);
242
+ const args = await messageArguments(message, cmd, commandPrefix);
234
243
  message.util.parsed = {
235
244
  alias: commandAlias,
236
245
  prefix: commandPrefix,
246
+ args: args.args,
237
247
  };
238
- this.client.emit('commandStart', message, cmd, filetype);
239
- return await this.exec(cmd, message, await messageArguments(message, cmd, commandPrefix), filetype);
248
+ cmd.util = message.util;
249
+ return await this.exec(cmd, message, args, filetype);
240
250
  }
241
251
  }
242
252
  async slashCommandRun(interaction) {
@@ -260,8 +270,14 @@ export default class CommandHandler extends Handler {
260
270
  resolve(true);
261
271
  })
262
272
  .then(async () => {
263
- this.client.emit('commandStart', interaction, filetype);
264
- return await this.exec(cmd, interaction, await interactionArguments(interaction, cmd), filetype);
273
+ await this.client.emit('commandStart', interaction, filetype);
274
+ const args = await interactionArguments(interaction, cmd);
275
+ interaction.util.parsed = {
276
+ alias: interaction.commandName + (args.group || '') + (args.subcommand || ''),
277
+ args: args.args,
278
+ };
279
+ cmd.util = interaction.util;
280
+ return await this.exec(cmd, interaction, args, filetype);
265
281
  })
266
282
  .catch((error) => this.client.emit('commandError', interaction, error, cmd, filetype));
267
283
  }
@@ -276,8 +292,14 @@ export default class CommandHandler extends Handler {
276
292
  cmd = this.client.commands.context.get(interaction.commandName);
277
293
  if (!cmd)
278
294
  return this.client.emit('commandNotFound', interaction, interaction.commandName, filetype);
279
- this.client.emit('commandStart', interaction, filetype);
280
- return await this.exec(cmd, interaction, await interactionArguments(interaction, cmd), filetype);
295
+ await this.client.emit('commandStart', interaction, filetype);
296
+ const args = await interactionArguments(interaction, cmd);
297
+ interaction.util.parsed = {
298
+ alias: interaction.commandName,
299
+ args: args,
300
+ };
301
+ cmd.util = interaction.util;
302
+ return await this.exec(cmd, interaction, args, filetype);
281
303
  }
282
304
  async exec(cmd, event, args, type) {
283
305
  try {
@@ -3,6 +3,7 @@ import XernerxClient from '../client/XernerxClient.js';
3
3
  import { EventHandlerOptions } from '../types/interfaces.js';
4
4
  import Handler from './Handler.js';
5
5
  export default class EventHandler extends Handler {
6
+ readonly readyTimestamp: number;
6
7
  constructor(client: XernerxClient);
7
8
  loadEvents(options: EventHandlerOptions): Promise<void>;
8
9
  }
@@ -7,8 +7,10 @@ import { Style } from 'dumfunctions';
7
7
  export default class EventHandler extends Handler {
8
8
  constructor(client) {
9
9
  super(client);
10
+ this.readyTimestamp = Number(Date.now());
10
11
  }
11
12
  async loadEvents(options) {
13
+ const events = [];
12
14
  options = z
13
15
  .object({
14
16
  directory: z.string(),
@@ -18,9 +20,10 @@ export default class EventHandler extends Handler {
18
20
  const files = this.readdir(options.directory);
19
21
  for (const file of files) {
20
22
  const filepath = `${path.resolve(options.directory)}\\${file}`;
21
- const data = await this.load(filepath, 'Event');
22
- this.emit(data);
23
+ const event = await this.load(filepath, 'Event');
24
+ this.emit(event);
25
+ events.push(event.id);
23
26
  }
24
- new XernerxLog(this.client).info(`Loaded ${Style.log(String(this.client.events.size), { color: Style.TextColor.Cyan })} Events.`);
27
+ new XernerxLog(this.client).info(`Loaded ${Style.log(String(this.client.events.size), { color: Style.TextColor.Cyan })} Events: ${events.map((event) => Style.log(event, { color: Style.TextColor.LightYellow })).join(', ')}`);
25
28
  }
26
29
  }
@@ -3,6 +3,7 @@ import XernerxExtensionBuilder from 'xernerx-extension-builder';
3
3
  import XernerxClient from '../client/XernerxClient.js';
4
4
  import Handler from './Handler.js';
5
5
  export default class ExtensionHandler extends Handler {
6
+ readonly readyTimestamp: number;
6
7
  constructor(client: XernerxClient);
7
8
  loadExtensions(...extensions: Array<XernerxExtensionBuilder>): void;
8
9
  }
@@ -5,6 +5,7 @@ import { Style } from 'dumfunctions';
5
5
  export default class ExtensionHandler extends Handler {
6
6
  constructor(client) {
7
7
  super(client);
8
+ this.readyTimestamp = Number(Date.now());
8
9
  }
9
10
  loadExtensions(...extensions) {
10
11
  const active = extensions.map((extension) => {
@@ -17,9 +18,12 @@ export default class ExtensionHandler extends Handler {
17
18
  return extension.name;
18
19
  }
19
20
  catch (error) {
20
- return new XernerxLog(this.client).error(`An error occurred while loading ${Style.log(extension.name, { color: Style.TextColor.Blue })}`, error);
21
+ return new XernerxLog(this.client).error(`An error occurred while loading ${Style.log(extension.name, { color: Style.TextColor.Red })}`, error);
21
22
  }
22
23
  });
23
- new XernerxLog(this.client).info(`Loaded ${Style.log(String(extensions.length), { color: Style.TextColor.Cyan })} Extensions: ${active.filter((e) => e).join(', ')}`);
24
+ new XernerxLog(this.client).info(`Loaded ${Style.log(String(extensions.length), { color: Style.TextColor.Cyan })} Extensions: ${active
25
+ .filter((e) => e)
26
+ .map((event) => Style.log(event, { color: Style.TextColor.LightYellow }))
27
+ .join(', ')}`);
24
28
  }
25
29
  }
@@ -5,9 +5,8 @@ import XernerxSlashCommand from '../build/XernerxSlashCommand.js';
5
5
  import XernerxContextCommand from '../build/XernerxContextCommand.js';
6
6
  import { filetype } from '../types/types.js';
7
7
  export default class Handler {
8
- readonly client: XernerxClient<unknown>;
8
+ readonly client: XernerxClient;
9
9
  readonly files: Array<MessageCommandBuilder | XernerxSlashCommand | XernerxContextCommand>;
10
- readonly readyTimestamp: number;
11
10
  constructor(client: XernerxClient);
12
11
  readdir(dir: string): string[];
13
12
  load(filepath: string, type: filetype): Promise<any>;
@@ -5,11 +5,9 @@ import load from '../functions/load.js';
5
5
  export default class Handler {
6
6
  client;
7
7
  files;
8
- readyTimestamp;
9
8
  constructor(client) {
10
9
  this.client = client;
11
10
  this.files = [];
12
- this.readyTimestamp = Number(Date.now());
13
11
  }
14
12
  readdir(dir) {
15
13
  try {
@@ -3,6 +3,7 @@ import XernerxClient from '../client/XernerxClient.js';
3
3
  import Handler from './Handler.js';
4
4
  import { InhibitorHandlerOptions } from '../types/interfaces.js';
5
5
  export default class InhibitorHandler extends Handler {
6
+ readonly readyTimestamp: number;
6
7
  constructor(client: XernerxClient);
7
8
  loadInhibitors(options: InhibitorHandlerOptions): Promise<void>;
8
9
  }
@@ -7,8 +7,10 @@ import { Style } from 'dumfunctions';
7
7
  export default class InhibitorHandler extends Handler {
8
8
  constructor(client) {
9
9
  super(client);
10
+ this.readyTimestamp = Number(Date.now());
10
11
  }
11
12
  async loadInhibitors(options) {
13
+ const inhibitors = [];
12
14
  options = z
13
15
  .object({
14
16
  directory: z.string(),
@@ -18,9 +20,12 @@ export default class InhibitorHandler extends Handler {
18
20
  const files = this.readdir(options.directory);
19
21
  for (const file of files) {
20
22
  const filepath = `${path.resolve(options.directory)}\\${file}`;
21
- const data = await this.load(filepath, 'Inhibitor');
22
- this.emit(data);
23
+ const inhibitor = await this.load(filepath, 'Inhibitor');
24
+ this.emit(inhibitor);
25
+ inhibitors.push(inhibitor.id);
23
26
  }
24
- new XernerxLog(this.client).info(`Loaded ${Style.log(String(this.client.inhibitors.size), { color: Style.TextColor.Cyan })} Inhibitors.`);
27
+ new XernerxLog(this.client).info(`Loaded ${Style.log(String(this.client.inhibitors.size), { color: Style.TextColor.Cyan })} Inhibitors: ${inhibitors
28
+ .map((inhibitor) => Style.log(inhibitor, { color: Style.TextColor.LightYellow }))
29
+ .join(', ')}`);
25
30
  }
26
31
  }
@@ -2,6 +2,7 @@
2
2
  import XernerxClient from '../client/XernerxClient.js';
3
3
  import Handler from './Handler.js';
4
4
  export default class WebhookHandler extends Handler {
5
+ readonly readyTimestamp: number;
5
6
  constructor(client: XernerxClient);
6
7
  loadWebhooks(options: {
7
8
  token: string;
@@ -4,6 +4,7 @@ import Handler from './Handler.js';
4
4
  export default class WebhookHandler extends Handler {
5
5
  constructor(client) {
6
6
  super(client);
7
+ this.readyTimestamp = Number(Date.now());
7
8
  }
8
9
  async loadWebhooks(options) {
9
10
  this.client.once('ready', async (client) => {
package/dist/main.d.ts CHANGED
@@ -8,6 +8,7 @@ import XernerxContextCommand from './build/XernerxContextCommand.js';
8
8
  import XernerxEvent from './build/XernerxEvent.js';
9
9
  import XernerxInhibitor from './build/XernerxInhibitor.js';
10
10
  import XernerxLog from './tools/XernerxLog.js';
11
+ export { XernerxIntents as XernerxIntents } from './tools/XernerxIntents.js';
11
12
  export * from 'discord.js';
12
13
  export * from 'dumfunctions';
13
14
  import XernerxExtension from 'xernerx-extension-builder';
@@ -15,10 +16,6 @@ export * from './types/types.js';
15
16
  export * from './types/extenders.js';
16
17
  export * from './types/interfaces.js';
17
18
  import Discord from 'discord.js';
18
- declare const XernerxIntents: {
19
- Default: string[];
20
- All: string[];
21
- };
22
19
  export default XernerxClient;
23
20
  export {
24
21
  /**
@@ -40,4 +37,4 @@ version,
40
37
  /**
41
38
  ** Tools
42
39
  */
43
- XernerxLog, XernerxIntents, };
40
+ XernerxLog, };
package/dist/main.js CHANGED
@@ -10,6 +10,7 @@ import XernerxContextCommand from './build/XernerxContextCommand.js';
10
10
  import XernerxEvent from './build/XernerxEvent.js';
11
11
  import XernerxInhibitor from './build/XernerxInhibitor.js';
12
12
  import XernerxLog from './tools/XernerxLog.js';
13
+ export { XernerxIntents as XernerxIntents } from './tools/XernerxIntents.js';
13
14
  export * from 'discord.js';
14
15
  export * from 'dumfunctions';
15
16
  import XernerxExtension from 'xernerx-extension-builder';
@@ -17,29 +18,6 @@ export * from './types/types.js';
17
18
  export * from './types/extenders.js';
18
19
  export * from './types/interfaces.js';
19
20
  import Discord from 'discord.js';
20
- const XernerxIntents = {
21
- Default: [
22
- 'Guilds',
23
- 'GuildModeration',
24
- 'GuildBans',
25
- 'GuildEmojisAndStickers',
26
- 'GuildIntegrations',
27
- 'GuildWebhooks',
28
- 'GuildInvites',
29
- 'GuildVoiceStates',
30
- 'GuildMessages',
31
- 'GuildMessageReactions',
32
- 'GuildMessageTyping',
33
- 'DirectMessages',
34
- 'DirectMessageReactions',
35
- 'DirectMessageTyping',
36
- 'GuildScheduledEvents',
37
- 'AutoModerationConfiguration',
38
- 'AutoModerationExecution',
39
- ],
40
- All: [''],
41
- };
42
- XernerxIntents.All = [...XernerxIntents.Default, 'GuildMembers', 'GuildPresences', 'MessageContent'];
43
21
  export default XernerxClient;
44
22
  export {
45
23
  /**
@@ -61,4 +39,4 @@ version,
61
39
  /**
62
40
  ** Tools
63
41
  */
64
- XernerxLog, XernerxIntents, };
42
+ XernerxLog, };
@@ -0,0 +1,11 @@
1
+ /** @format */
2
+ import { Collection } from 'discord.js';
3
+ import XernerxClient from '../main.js';
4
+ export default class Cooldowns {
5
+ private readonly _client;
6
+ readonly collections: Record<string, Collection<string, unknown>>;
7
+ constructor(client: XernerxClient, collections?: Array<string>);
8
+ add(collection: keyof typeof this.collections, id: string, value: unknown): string | Collection<string, unknown>;
9
+ delete(collection: keyof typeof this.collections, id: string): string | boolean;
10
+ has(id: string): Record<string, Collection<string, unknown>>;
11
+ }
@@ -0,0 +1,33 @@
1
+ /** @format */
2
+ import { Collection } from 'discord.js';
3
+ export default class Cooldowns {
4
+ constructor(client, collections = []) {
5
+ this._client = client;
6
+ this.collections = {
7
+ commands: new Collection(),
8
+ };
9
+ for (const collection of collections) {
10
+ this.collections[collection] = new Collection();
11
+ }
12
+ }
13
+ add(collection, id, value) {
14
+ if (!this.collections[collection])
15
+ return `${collection} collection does not exist!`;
16
+ return this.collections[collection].set(id, value);
17
+ }
18
+ delete(collection, id) {
19
+ if (!this.collections[collection])
20
+ return `${collection} collection does not exist!`;
21
+ return this.collections[collection].delete(id);
22
+ }
23
+ has(id) {
24
+ const collected = {};
25
+ for (const [name, collection] of Object.entries(this.collections)) {
26
+ if (collection.has(id))
27
+ collected[name] = collection;
28
+ else
29
+ continue;
30
+ }
31
+ return collected;
32
+ }
33
+ }
@@ -0,0 +1,5 @@
1
+ /** @format */
2
+ export declare const XernerxIntents: {
3
+ Default: string[];
4
+ All: string[];
5
+ };
@@ -0,0 +1,24 @@
1
+ /** @format */
2
+ export const XernerxIntents = {
3
+ Default: [
4
+ 'Guilds',
5
+ 'GuildModeration',
6
+ 'GuildBans',
7
+ 'GuildEmojisAndStickers',
8
+ 'GuildIntegrations',
9
+ 'GuildWebhooks',
10
+ 'GuildInvites',
11
+ 'GuildVoiceStates',
12
+ 'GuildMessages',
13
+ 'GuildMessageReactions',
14
+ 'GuildMessageTyping',
15
+ 'DirectMessages',
16
+ 'DirectMessageReactions',
17
+ 'DirectMessageTyping',
18
+ 'GuildScheduledEvents',
19
+ 'AutoModerationConfiguration',
20
+ 'AutoModerationExecution',
21
+ ],
22
+ All: [''],
23
+ };
24
+ XernerxIntents.All = [...XernerxIntents.Default, 'GuildMembers', 'GuildPresences', 'MessageContent'];
@@ -9,7 +9,6 @@ export default class XernerxLog {
9
9
  this.warnLog = true;
10
10
  }
11
11
  else {
12
- client.settings.log = client.settings.log;
13
12
  this.errorLog = client.settings.log?.error;
14
13
  this.infoLog = client.settings.log?.info;
15
14
  this.warnLog = client.settings.log?.warn;
@@ -1,8 +1,8 @@
1
1
  /** @format */
2
- import { ChatInputCommandInteraction, Client, Collection, DMChannel, Guild, GuildChannel, GuildMember, Message, MessageContextMenuCommandInteraction, User, UserContextMenuCommandInteraction } from 'discord.js';
2
+ import { ChatInputCommandInteraction, Collection, DMChannel, Guild, GuildChannel, GuildMember, Message, MessageContextMenuCommandInteraction, User, UserContextMenuCommandInteraction } from 'discord.js';
3
3
  import InteractionUtil from '../utils/InteractionUtil.js';
4
4
  import MessageUtil from '../utils/MessageUtil.js';
5
- import { ModuleOptions, XernerxCache, XernerxCommands, XernerxEvent, XernerxInhibitor, XernerxOptions } from '../main.js';
5
+ import { ModuleOptions, XernerxCache, XernerxCommands, XernerxEvent, XernerxInhibitor, XernerxClient } from '../main.js';
6
6
  import ClientUtil from '../utils/ClientUtil.js';
7
7
  export interface XernerxUser extends User {
8
8
  owner: boolean;
@@ -35,20 +35,23 @@ export interface XernerxMessageContextInteraction extends MessageContextMenuComm
35
35
  user: XernerxUser;
36
36
  util: InteractionUtil;
37
37
  }
38
- export interface XernerxClientType extends Client {
39
- config: unknown | null;
38
+ export interface XernerxClientType extends XernerxClient {
40
39
  commands: XernerxCommands;
41
40
  events: Collection<string, XernerxEvent>;
42
41
  inhibitors: Collection<string, XernerxInhibitor>;
43
42
  modules: ModuleOptions;
44
43
  util: ClientUtil;
45
- settings: XernerxOptions;
46
44
  stats: {
47
45
  guildCount: number;
48
46
  userCount: number;
49
47
  shardId: number;
50
48
  shardCount: number;
51
49
  };
50
+ cooldown: {
51
+ default: number;
52
+ cache: number;
53
+ collections: Array<string>;
54
+ };
52
55
  cache: XernerxCache;
53
56
  connect: () => Promise<string>;
54
57
  }
@@ -15,8 +15,8 @@ export interface XernerxOptions {
15
15
  global?: boolean;
16
16
  ownerId?: string | Array<string>;
17
17
  permissions?: {
18
- client?: Array<string>;
19
- user?: Array<string>;
18
+ user?: Array<PermissionNames> | Array<string> | null;
19
+ client?: Array<PermissionNames> | Array<string> | null;
20
20
  dm?: boolean;
21
21
  };
22
22
  ignore?: {
@@ -38,6 +38,7 @@ export interface XernerxOptions {
38
38
  cooldown?: {
39
39
  command?: number;
40
40
  cache?: number;
41
+ collections?: Array<string>;
41
42
  };
42
43
  }
43
44
  export interface ModuleOptions {
@@ -83,8 +84,8 @@ interface CommandHandlerOptions {
83
84
  directory: string;
84
85
  cooldown?: number;
85
86
  permissions?: {
86
- user?: Array<string>;
87
- client?: Array<string>;
87
+ user?: Array<PermissionNames> | Array<string> | null;
88
+ client?: Array<PermissionNames> | Array<string> | null;
88
89
  dm?: boolean;
89
90
  };
90
91
  }
@@ -139,8 +140,8 @@ interface CommandOptions {
139
140
  voice?: boolean;
140
141
  };
141
142
  permissions?: {
142
- user?: Array<PermissionNames> | Array<string>;
143
- client?: Array<PermissionNames> | Array<string>;
143
+ user?: Array<PermissionNames> | Array<string> | null;
144
+ client?: Array<PermissionNames> | Array<string> | null;
144
145
  dm?: boolean;
145
146
  };
146
147
  }
@@ -1,12 +1,16 @@
1
1
  /** @format */
2
2
  import { EmbedBuilder, InteractionEditReplyOptions, InteractionReplyOptions, MessagePayload } from 'discord.js';
3
3
  import XernerxClient from '../client/XernerxClient.js';
4
- import { PaginatorOptions } from '../types/interfaces.js';
4
+ import { ContextCommandArguments, PaginatorOptions, SlashCommandArguments } from '../types/interfaces.js';
5
5
  import { XernerxInteraction } from '../types/types.js';
6
6
  import Util from './Util.js';
7
7
  import { XernerxMessageContextInteraction, XernerxSlashInteraction, XernerxUserContextInteraction } from '../types/extenders.js';
8
8
  export default class InteractionUtil extends Util {
9
- private interaction;
9
+ private readonly interaction;
10
+ parsed: {
11
+ alias: string | null;
12
+ args: (SlashCommandArguments | ContextCommandArguments<'message' | 'user'>) | null;
13
+ };
10
14
  constructor(client: XernerxClient, interaction: XernerxInteraction<XernerxSlashInteraction | XernerxUserContextInteraction | XernerxMessageContextInteraction>);
11
15
  send(content: any): Promise<import("discord.js").Message<false> | import("discord.js").Message<true> | undefined>;
12
16
  reply(content: string | MessagePayload | InteractionReplyOptions | InteractionEditReplyOptions): Promise<import("discord.js").InteractionResponse<boolean> | import("discord.js").Message<boolean>>;
@@ -3,10 +3,13 @@ import { ActionRowBuilder, ButtonBuilder, ButtonStyle, StringSelectMenuBuilder }
3
3
  import Util from './Util.js';
4
4
  import XernerxError from '../tools/XernerxError.js';
5
5
  export default class InteractionUtil extends Util {
6
- interaction;
7
6
  constructor(client, interaction) {
8
7
  super(client);
9
8
  this.interaction = interaction;
9
+ this.parsed = {
10
+ alias: null,
11
+ args: null,
12
+ };
10
13
  }
11
14
  async send(content) {
12
15
  if (!content)
@@ -7,8 +7,9 @@ import { PaginatorOptions } from '../main.js';
7
7
  export default class MessageUtil extends Util {
8
8
  private readonly message;
9
9
  parsed: {
10
- alias: null | string;
11
- prefix: null | string;
10
+ alias: string | null;
11
+ prefix: string | null;
12
+ args: Record<string, unknown> | null;
12
13
  };
13
14
  constructor(client: XernerxClient, message: XernerxMessage);
14
15
  send(content: any): Promise<import("discord.js").Message<boolean> | null>;
@@ -4,13 +4,13 @@ import Util from './Util.js';
4
4
  import sendWebhook from '../functions/sendWebhook.js';
5
5
  import XernerxError from '../tools/XernerxError.js';
6
6
  export default class MessageUtil extends Util {
7
- message;
8
7
  constructor(client, message) {
9
8
  super(client);
10
9
  this.message = message;
11
10
  this.parsed = {
12
11
  alias: null,
13
12
  prefix: null,
13
+ args: null,
14
14
  };
15
15
  }
16
16
  async send(content) {
@@ -2,7 +2,7 @@
2
2
  import XernerxClient from '../client/XernerxClient.js';
3
3
  import XernerxText from '../tools/XernerxText.js';
4
4
  export default class Util {
5
- readonly client: XernerxClient<unknown>;
5
+ readonly client: XernerxClient;
6
6
  readonly text: XernerxText;
7
7
  constructor(client: XernerxClient);
8
8
  delay(time: number): Promise<unknown>;
@@ -1,27 +1,47 @@
1
1
  /** @format */
2
2
  import { ChannelType, PermissionFlagsBits } from 'discord.js';
3
+ var CommandTypes;
4
+ (function (CommandTypes) {
5
+ CommandTypes["SlashCommand"] = "slash";
6
+ CommandTypes["MessageCommand"] = "message";
7
+ CommandTypes["ContextCommand"] = "context";
8
+ })(CommandTypes || (CommandTypes = {}));
3
9
  export default async function commandValidation(event, command) {
4
10
  const client = event.client;
5
- if (command.ignore?.owner && client.settings.ownerId.includes(event.user.id))
11
+ if (command.ignore?.owner && client.settings.ownerId?.includes(event.user.id))
6
12
  return false;
7
- if (!client.cache.cooldowns.has(`${event.user.id}-${command.name}`)) {
8
- client.cache.cooldowns.set(`${event.user.id}-${command.name}`, {
9
- id: event.user.id,
10
- command: command.name,
11
- createdTimestamp: Number(Date.now()) + (command.cooldown || 0),
12
- });
13
+ const cooldownTime = command.cooldown || client.modules.options?.[CommandTypes[command.filetype]]?.cooldown || client.cooldown?.default || 0;
14
+ const cooldown = {
15
+ id: event.user.id,
16
+ command: command.name,
17
+ createdTimestamp: Number(Date.now()) + cooldownTime,
18
+ };
19
+ const clientPermissions = command.permissions?.client || client.modules.options?.[CommandTypes[command.filetype]]?.permissions?.client || client.settings.permissions?.client || [];
20
+ const userPermissions = command.permissions?.user || client.modules.options?.[CommandTypes[command.filetype]]?.permissions?.user || client.settings.permissions?.user || [];
21
+ if (!client.cooldowns.collections.commands.has(`${event.user.id}-${command.name}`)) {
22
+ client.cooldowns.collections.commands.set(`${event.user.id}-${command.name}`, cooldown);
13
23
  setTimeout(() => {
14
- client.cache.cooldowns.delete(`${event.user.id}-${command.name}`);
15
- }, command.cooldown || 0);
24
+ client.cooldowns.collections.commands.delete(`${event.user.id}-${command.name}`);
25
+ }, cooldownTime);
16
26
  }
17
27
  else {
18
- const user = client.cache.cooldowns.get(`${event.user.id}-${command.name}`);
28
+ const user = client.cooldowns.collections.commands.get(`${event.user.id}-${command.name}`);
19
29
  const time = (user?.createdTimestamp || 0) - Number(Date.now());
20
- return emit(event, `Command on cooldown, ${time}`);
30
+ return emit(event, {
31
+ reason: 'cooldown',
32
+ message: `You are on cooldown for \`${command.name}\`, wait another \`${Math.round(time / 10) / 100}s\``,
33
+ startedAt: user.createdTimestamp,
34
+ endsAt: user.createdTimestamp + time,
35
+ time,
36
+ }, command);
21
37
  }
22
38
  if (command.channel && event.channel?.type !== undefined && event.channel?.type >= 0) {
23
39
  if (!command.channel.includes(ChannelType[event.channel?.type]))
24
- return await emit(event, `Command can only be used in ${command.channel.join(', ')} channels`);
40
+ return await emit(event, {
41
+ reason: 'invalidChannel',
42
+ message: `\`${command.name}\` can only be used in ${command.channel.join(', ')} channels`,
43
+ channels: command.channel,
44
+ }, command);
25
45
  }
26
46
  if ((command.ignore?.channels?.length || 0) > 0 && command.ignore?.channels?.includes(event.channel?.id))
27
47
  return true;
@@ -30,29 +50,75 @@ export default async function commandValidation(event, command) {
30
50
  if ((command.ignore?.users?.length || 0) > 0 && command.ignore?.users?.includes(event.user.id))
31
51
  return true;
32
52
  if (command.ignore?.voice && event.member?.voice?.channel)
33
- return await emit(event, 'Command cannot be ran while in voice chat');
53
+ return await emit(event, {
54
+ reason: 'inVoice',
55
+ message: `\`${command.name}\` cannot be ran while in voice chat`,
56
+ }, command);
34
57
  if (command.strict?.owner && !client.settings.ownerId.includes(event.user.id))
35
- return await emit(event, 'Command is a developer command');
58
+ return await emit(event, {
59
+ reason: 'notADeveloper',
60
+ message: `\`${command.name}\` is a developer command`,
61
+ owners: client.settings.ownerId,
62
+ }, command);
36
63
  if ((command.strict?.channels?.length || 0) > 0 && !command.strict?.channels?.includes(event.channel?.id))
37
- return await emit(event, 'Command cannot be ran in this channel');
64
+ return await emit(event, {
65
+ reason: 'channelRestricted',
66
+ message: `\`${command.name}\` cannot be ran in this channel`,
67
+ channels: command.strict?.channels,
68
+ }, command);
38
69
  if ((command.strict?.guilds?.length || 0) > 0 && !command.strict?.guilds?.includes(event.guild?.id))
39
- return await emit(event, 'Command cannot be ran in this guild');
70
+ return await emit(event, {
71
+ reason: 'guildRestricted',
72
+ message: `\`${command.name}\` cannot be ran in this guild`,
73
+ guilds: command.strict?.guilds,
74
+ }, command);
40
75
  if ((command.strict?.users?.length || 0) > 0 && !command.strict?.users?.includes(event.user.id))
41
- return await emit(event, 'Command cannot be ran by you');
76
+ return await emit(event, {
77
+ reason: 'userRestricted',
78
+ message: `\`${command.name}\` cannot be ran by you`,
79
+ users: command.strict?.users,
80
+ }, command);
42
81
  if (command.strict?.voice && !event.member?.voice?.channel)
43
- return await emit(event, 'Command cannot be ran while not in voice chat');
82
+ return await emit(event, {
83
+ reason: 'voiceRestricted',
84
+ message: `\`${command.name}\` cannot be ran while not in voice chat`,
85
+ }, command);
44
86
  if (command.permissions?.dm == false && event.channel?.type === ChannelType.DM)
45
- return await emit(event, "Can't use in a DM Channel");
46
- if (command.permissions?.user) {
47
- if (!(event.member?.permissions).has(toBigInt(command.permissions.user)))
48
- return await emit(event, 'Missing User Permissions');
87
+ return await emit(event, {
88
+ reason: 'DMRestricted',
89
+ message: `\`${command.name}\` can't be used in a DM Channel`,
90
+ }, command);
91
+ if (userPermissions) {
92
+ const missing = userPermissions.map((permission) => ((event.member?.permissions).has(toBigInt([permission])) ? null : permission)).filter((x) => x);
93
+ const desired = (event.member?.permissions).has(toBigInt(userPermissions));
94
+ if (!desired)
95
+ return await emit(event, {
96
+ reason: 'missingUserPermissions',
97
+ message: `You are missing the following permissions to run \`${command.name}\`:\n${missing.map((permission) => `> - ${permission}`).join('\n')}`,
98
+ required: userPermissions,
99
+ missing,
100
+ }, command);
101
+ }
102
+ if (clientPermissions) {
103
+ const missing = clientPermissions.map((permission) => (event.guild?.members.me?.permissions.has(toBigInt([permission])) ? null : permission)).filter((x) => x);
104
+ const desired = event.guild?.members.me?.permissions?.has(toBigInt(clientPermissions));
105
+ if (!desired)
106
+ return await emit(event, {
107
+ reason: 'missingClientPermissions',
108
+ message: `I am missing the following permissions to run \`${command.name}\`:\n${missing.map((permission) => `> - ${permission}`).join('\n')}`,
109
+ required: clientPermissions,
110
+ missing,
111
+ }, command);
49
112
  }
50
113
  if ((!command.global || !client.settings.global) && client.settings.local !== event.guild?.id)
51
- return await emit(event, 'Command is not globally deployed');
114
+ return await emit(event, {
115
+ reason: 'local',
116
+ message: `\`${command.name}\` is not globally deployed`,
117
+ }, command);
52
118
  return false;
53
119
  }
54
- async function emit(event, reason) {
55
- event.client.emit('commandBlock', event, reason);
120
+ async function emit(event, info, command) {
121
+ event.client.emit('commandBlock', event, info, command);
56
122
  return true;
57
123
  }
58
124
  function toBigInt(permissions) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xernerx",
3
- "version": "4.7.0",
3
+ "version": "4.8.0",
4
4
  "description": "A bot framework for discord.js.",
5
5
  "main": "dist/main.js",
6
6
  "type": "module",
@@ -44,7 +44,7 @@
44
44
  "discord.js": "14.13.0",
45
45
  "dumfunctions": "2.1.2",
46
46
  "xernerx-extension-builder": "0.0.16",
47
- "zod": "3.22.0"
47
+ "zod": "3.22.2"
48
48
  },
49
49
  "devDependencies": {
50
50
  "prettier": "3.0.0",