@somehiddenkey/discord-command-utils 2.6.0 → 2.7.1

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/README.md CHANGED
@@ -169,7 +169,7 @@ Interaction.OnButton(
169
169
  ```
170
170
 
171
171
  ### Call Interaction
172
- All interactions get stored in a so-called `InteractionContainer` that still needs to be called:
172
+ All interactions get stored in a so-called `InteractionContainer` that still needs to be called. If someone goes wrong in an unexpected way, the interaction will be replied to with "something went wrong" and a consola error will be displayed. Optionally, you can provide an extra error handler as second argument to the interaction caller.
173
173
  ```js
174
174
  const interactionContainer = new InteractionContainer(localConfig, globalConfig);
175
175
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@somehiddenkey/discord-command-utils",
3
- "version": "2.6.0",
3
+ "version": "2.7.1",
4
4
  "description": "A utility library for building Discord bot commands using discord.js",
5
5
  "author": {
6
6
  "email": "k3y.throwaway@gmail.com",
@@ -2,8 +2,8 @@
2
2
  * @typedef {string} Snowflake
3
3
  */
4
4
 
5
- import consola from 'consola';
6
5
  import { Client } from 'discord.js';
6
+ import { consolaConfig } from '../Utils/consola.js';
7
7
 
8
8
  export default class Fetchable {
9
9
  /** @type {string[]} */
@@ -30,7 +30,7 @@ export default class Fetchable {
30
30
  if (prop === "refreshFromBot") {
31
31
  return async () => {
32
32
  cachedObject = await fetcher(id);
33
- consola.debug(`Fetched config object with ID ${id}`);
33
+ consolaConfig.debug(`Fetched config object with ID ${id}`);
34
34
  return cachedObject;
35
35
  };
36
36
  }
@@ -41,7 +41,7 @@ export default class Fetchable {
41
41
  cachedObject = await fetcher(id);
42
42
  if (!cachedObject)
43
43
  throw new Error(`Cannot fetch config object for ID "${id}"`);
44
- consola.debug(`Fetched config object with ID ${id}`);
44
+ consolaConfig.debug(`Fetched config object with ID ${id}`);
45
45
  }
46
46
  return cachedObject;
47
47
  };
@@ -23,7 +23,7 @@ import GuildStaff from './GlobalConfigStaff.js';
23
23
  import { GuildBased } from '../NestedGlobalConfig.js';
24
24
  import { Client } from 'discord.js';
25
25
  import ConfigError from '../ConfigError.js';
26
- import consola from 'consola';
26
+ import { consolaConfig } from '../../Utils/consola.js';
27
27
 
28
28
  export default class GlobalConfig {
29
29
  /** @type {GuildMain} */
@@ -47,7 +47,7 @@ export default class GlobalConfig {
47
47
  const raw = fs.readFileSync(path, { encoding: 'utf8', flag: 'r' });
48
48
  json = JSON.parse(raw);
49
49
  const g = new GlobalConfig(json.guilds, bot);
50
- consola.start(`Loaded GlobalConfig from path: ${path}`);
50
+ consolaConfig.start(`Loaded GlobalConfig from path: ${path}`);
51
51
  return g;
52
52
  } catch (error) {
53
53
  throw new ConfigError(`Failed to load GlobalConfig from path: ${path}`, error);
@@ -1,6 +1,6 @@
1
1
  import fs from 'fs';
2
2
  import ConfigError from "./ConfigError.js";
3
- import consola from 'consola';
3
+ import { consolaConfig } from '../Utils/consola.js';
4
4
 
5
5
  /**
6
6
  * @typedef {string} Snowflake
@@ -10,23 +10,23 @@ export default class LocalConfig {
10
10
  /** @type {string?} */
11
11
  prefix;
12
12
  /** @type {Snowflake} */
13
- clientId;
13
+ client_id;
14
14
 
15
15
  /** @type {object} */
16
16
  local;
17
17
  /** @type {object} */
18
- restOptions;
18
+ rest_options;
19
19
  /** @type {object} */
20
20
  activity;
21
21
 
22
22
  constructor(data) {
23
23
  this.prefix = data.prefix;
24
- this.clientId = data.client_id;
24
+ this.client_id = data.client_id;
25
25
  this.local = data.local || {};
26
- this.restOptions = data.rest_options || {};
26
+ this.rest_options = data.rest_options || {};
27
27
  this.activity = data.activity || {};
28
28
 
29
- if(!this.clientId)
29
+ if(!this.client_id)
30
30
  throw new ConfigError('No client_id initialized for LocalConfig');
31
31
  }
32
32
 
@@ -40,9 +40,48 @@ export default class LocalConfig {
40
40
  try {
41
41
  const raw = fs.readFileSync(path, { encoding: 'utf8', flag: 'r' });
42
42
  json = JSON.parse(raw);
43
- return new LocalConfig(json);
43
+ const localConfig =new LocalConfig(json);
44
+ localConfig.#reloadable(path, "localConfig");
45
+ consolaConfig.start(`Loaded LocalConfig from path: ${path}`);
46
+ return localConfig;
44
47
  } catch (error) {
45
48
  throw new ConfigError(`Failed to load LocalConfig from path: ${path}`, error);
46
49
  }
47
50
  }
51
+
52
+ #reloadable(filepath, root=""){
53
+ fs.watch(filepath, { encoding: 'utf8' }, (eventType, _) => {
54
+ if (eventType !== 'change') return;
55
+ fs.readFile(filepath, 'utf8', (err, data) => {
56
+ if (err)
57
+ return consolaConfig.error(err);
58
+ else
59
+ LocalConfig.#compareObjects(JSON.parse(data), this, root+".");
60
+ })
61
+ });
62
+ }
63
+
64
+ static #compareObjects(data, currentObject, tree="") {
65
+ Object.entries(data).forEach(([key, newValue]) => {
66
+ const oldValue = currentObject[key]
67
+ const newValueIsObject = typeof newValue === 'object' && !Array.isArray(newValue) && newValue !== null
68
+ const oldValueIsObject = typeof oldValue === 'object' && !Array.isArray(oldValue) && oldValue !== null
69
+
70
+ if(newValueIsObject && oldValueIsObject)
71
+ LocalConfig.#compareObjects(newValue, oldValue, tree+"."+key);
72
+ else {
73
+ if(Array.isArray(newValue) || Array.isArray(oldValue)) {
74
+ const newValueString = JSON.stringify(newValue);
75
+ const oldValueString = JSON.stringify(oldValue);
76
+ if(newValueString != oldValueString) {
77
+ currentObject[key] = newValue
78
+ consolaConfig.warn(`Updated ${tree}${key}\n - Old: ${oldValueString}\n - New: ${newValueString}`);
79
+ }
80
+ } else if (newValue !== oldValue){
81
+ currentObject[key] = newValue
82
+ consolaConfig.warn(`Updated ${tree}${key}\n - Old: ${JSON.stringify(oldValue)}\n - New: ${JSON.stringify(newValue)}`);
83
+ }
84
+ }
85
+ });
86
+ }
48
87
  }
@@ -1,21 +1,10 @@
1
- import consola from "consola";
2
1
  import ConfigError from "./ConfigError.js";
2
+ import { consolaConfig } from "../Utils/consola.js";
3
3
 
4
4
  /**
5
5
  * @typedef {{client: string, connection: {host: string, user: string, password: string, database: string}}} DatabaseConfig
6
6
  */
7
7
 
8
- const levels = {
9
- silent: -1,
10
- fatal: 0,
11
- error: 1,
12
- warn: 2,
13
- info: 3,
14
- debug: 4,
15
- trace: 5,
16
- };
17
- consola.level = levels[process.env.LOG_LEVEL?.toLowerCase() || "info"] ?? 3;
18
-
19
8
  export default class SecretConfig {
20
9
  /** @type {string} */
21
10
  token;
@@ -52,11 +41,11 @@ export default class SecretConfig {
52
41
 
53
42
  databaseConfigs.push(db_config);
54
43
  } catch (error) {
55
- consola.error(`Failed to load database config for section: ${section}`, error);
44
+ consolaConfig.error(`Failed to load database config for section: ${section}`, error);
56
45
  throw error;
57
46
  }
58
47
  }
59
48
  this.databaseConfig = databaseConfigs;
60
- consola.start(`Loaded SecretConfig for environment: ${this.environment}`);
49
+ consolaConfig.start(`Loaded SecretConfig for environment: ${this.environment}`);
61
50
  }
62
51
  }
@@ -2,10 +2,10 @@ import Interaction from "./Interaction.js";
2
2
  import { InteractionScope, InteractionType } from "../Utils/enums.js";
3
3
  import GlobalConfig from "../Configs/GlobalConfig/GlobalConfig.js";
4
4
  import LocalConfig from "../Configs/LocalConfig.js";
5
- import consola from "consola";
6
5
  import CommandError from "./CommandError.js";
7
6
  import RestCommands from './RestCommands.js';
8
7
  import { ChannelType } from 'discord.js';
8
+ import { consolaInteraction } from "../Utils/consola.js";
9
9
 
10
10
  /**
11
11
  * @typedef { import("discord.js").Interaction } DiscordBaseInteraction
@@ -44,7 +44,7 @@ export default class InteractionContainer {
44
44
  */
45
45
  static add(base_interaction) {
46
46
  const key = InteractionContainer.#make_key(base_interaction.type, base_interaction.scope, base_interaction.id);
47
- consola.debug(`Registered interaction with key ${key}`);
47
+ consolaInteraction.debug(`Registered interaction with key ${key}`);
48
48
  InteractionContainer.#interaction_container.set(key, base_interaction);
49
49
  }
50
50
 
@@ -56,7 +56,7 @@ export default class InteractionContainer {
56
56
  */
57
57
  static get(type, scope, id) {
58
58
  const key = InteractionContainer.#make_key(type, scope, id);
59
- consola.debug(`Fetching interaction with key ${key}`);
59
+ consolaInteraction.debug(`Fetching interaction with key ${key}`);
60
60
  return InteractionContainer.#interaction_container.get(key);
61
61
  }
62
62
 
@@ -118,10 +118,8 @@ export default class InteractionContainer {
118
118
  const scope =
119
119
  (interaction.channel.type === ChannelType.DM) ?
120
120
  InteractionScope.DM : this.#global_config.get_scope(interaction.guild.id);
121
- console.log(scope)
122
121
 
123
122
  const [customId, ...command_arguments] = (interaction.commandName || interaction.customId)?.split("?")
124
- console.log(customId)
125
123
 
126
124
  var type;
127
125
  if (interaction.isChatInputCommand())
@@ -134,7 +132,6 @@ export default class InteractionContainer {
134
132
  type = InteractionType.Modal;
135
133
  else
136
134
  return;
137
- console.log(type)
138
135
 
139
136
  return InteractionContainer
140
137
  .#call(interaction, type, scope, {name: customId, subcommand: interaction.options?.getSubcommand()}, command_arguments)
@@ -145,8 +142,12 @@ export default class InteractionContainer {
145
142
  return interaction
146
143
  .editReply("something went wrong")
147
144
  .catch(() => interaction.reply("something went wrong"))
148
- .then(() => on_error(error))
149
- .then();
145
+ .then(
146
+ () => {consolaInteraction.error(e); return on_error(error)},
147
+ () => {consolaInteraction.error(e); return on_error(error)}
148
+ )
149
+ .then()
150
+ .catch(consolaInteraction.error);
150
151
  });
151
152
  }
152
153
 
@@ -163,7 +164,7 @@ export default class InteractionContainer {
163
164
  static async #call(interaction, type, scope, customId, command_arguments = []) {
164
165
  const interaction_command = InteractionContainer.get(type, scope, customId);
165
166
  if(!interaction_command)
166
- return consola.error(`No interaction found:\n${JSON.stringify({customId, type, scope, command_arguments: command_arguments.join(',')}, null, 2)}`);
167
+ return consolaInteraction.error(`No interaction found:\n${JSON.stringify({customId, type, scope, command_arguments: command_arguments.join(',')}, null, 2)}`);
167
168
 
168
169
  return await interaction_command.interaction_command_function.apply(null, [interaction, ...command_arguments]);
169
170
  }
@@ -0,0 +1,25 @@
1
+ import { createConsola } from "consola";
2
+
3
+ const levels = {
4
+ silent: -1,
5
+ fatal: 0,
6
+ error: 1,
7
+ warn: 2,
8
+ info: 3,
9
+ debug: 4,
10
+ trace: 5,
11
+ };
12
+ const level = levels[process.env.LOG_LEVEL?.toLowerCase() || "info"] ?? 3;
13
+
14
+ const consolaInstance = createConsola({
15
+ level,
16
+ fancy: true,
17
+ formatOptions: {
18
+ date: true,
19
+ columns: 20
20
+ }
21
+ });
22
+
23
+ export const consolaConfig = consolaInstance.withTag("Config");
24
+ export const consolaInteraction = consolaInstance.withTag("Interaction");
25
+ export default consolaInstance;