meocord 1.4.0 → 1.4.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
@@ -571,6 +571,12 @@ Thank you for helping make **MeoCord** better!
571
571
 
572
572
  ---
573
573
 
574
+ ## Release Notes
575
+
576
+ Full release history is available on the [GitHub Releases](https://github.com/l7aromeo/meocord/releases) page.
577
+
578
+ ---
579
+
574
580
  ## License
575
581
 
576
582
  **MeoCord Framework** is licensed under the [MIT License](./LICENSE).
@@ -153,7 +153,7 @@ const REACTION_HANDLER_METADATA_KEY = Symbol('reaction_handlers');
153
153
  if (typeof builderOrType === 'function') {
154
154
  const builderObj = new builderOrType();
155
155
  builderInstance = builderObj.build(commandName);
156
- commandType = Reflect.getMetadata('commandType', builderOrType);
156
+ commandType = Reflect.getMetadata(enum_index.MetadataKey.CommandType, builderOrType);
157
157
  if (!(commandType in enum_index.CommandType)) {
158
158
  throw new Error(`Metadata for 'commandType' is missing on builder ${builderOrType.name}`);
159
159
  }
@@ -205,19 +205,19 @@ const REACTION_HANDLER_METADATA_KEY = Symbol('reaction_handlers');
205
205
  * ```
206
206
  */ function Controller() {
207
207
  return function(target) {
208
- if (!Reflect.hasMetadata('inversify:injectable', target)) {
208
+ if (!Reflect.hasMetadata(enum_index.MetadataKey.Injectable, target)) {
209
209
  inversify.injectable()(target);
210
210
  }
211
- const injectables = Reflect.getMetadata('design:paramtypes', target) || [];
211
+ const injectables = Reflect.getMetadata(enum_index.MetadataKey.ParamTypes, target) || [];
212
212
  injectables.map((dep)=>{
213
213
  if (!mainContainer.isBound(dep)) {
214
- if (!Reflect.hasMetadata('inversify:injectable', dep)) {
214
+ if (!Reflect.hasMetadata(enum_index.MetadataKey.Injectable, dep)) {
215
215
  inversify.injectable()(dep);
216
216
  }
217
217
  mainContainer.bind(dep).toSelf().inSingletonScope();
218
218
  }
219
219
  });
220
- Reflect.defineMetadata('inversify:container', mainContainer, target);
220
+ Reflect.defineMetadata(enum_index.MetadataKey.Container, mainContainer, target);
221
221
  };
222
222
  }
223
223
 
@@ -399,7 +399,7 @@ class MeoCordApp {
399
399
  for (const controller of relevantControllers){
400
400
  let controllerInstance = this.controllerInstancesCache.get(controller.constructor);
401
401
  if (!controllerInstance) {
402
- const container = Reflect.getMetadata('inversify:container', controller.constructor);
402
+ const container = Reflect.getMetadata(enum_index.MetadataKey.Container, controller.constructor);
403
403
  controllerInstance = container.get(controller.constructor, {
404
404
  autobind: true
405
405
  });
@@ -432,7 +432,7 @@ class MeoCordApp {
432
432
  for (const controller of relevantControllers){
433
433
  let controllerInstance = this.controllerInstancesCache.get(controller.constructor);
434
434
  if (!controllerInstance) {
435
- const container = Reflect.getMetadata('inversify:container', controller.constructor);
435
+ const container = Reflect.getMetadata(enum_index.MetadataKey.Container, controller.constructor);
436
436
  controllerInstance = container.get(controller.constructor, {
437
437
  autobind: true
438
438
  });
@@ -2,9 +2,10 @@
2
2
 
3
3
  require('reflect-metadata');
4
4
  var theme = require('../_shared/theme-Bz-D4RbT.cjs');
5
- var meocord_app = require('../_shared/meocord.app-BcwCzqru.cjs');
5
+ var meocord_app = require('../_shared/meocord.app-Ds9XbbCN.cjs');
6
6
  require('inversify');
7
7
  require('discord.js');
8
+ var enum_index = require('../enum/index.cjs');
8
9
  require('path');
9
10
  require('fs');
10
11
  require('jiti');
@@ -13,13 +14,12 @@ require('dayjs');
13
14
  require('dayjs/plugin/utc.js');
14
15
  require('dayjs/plugin/timezone.js');
15
16
  require('chalk');
16
- require('../enum/index.cjs');
17
17
  require('lodash-es');
18
18
  require('cli-table3');
19
19
 
20
20
  class MeoCordFactory {
21
21
  static create(target) {
22
- const container = Reflect.getMetadata('inversify:container', target);
22
+ const container = Reflect.getMetadata(enum_index.MetadataKey.Container, target);
23
23
  if (!container) {
24
24
  if (typeof target === 'function') {
25
25
  this.logger.error(`No container found for class: ${target.name}`);
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
3
  require('reflect-metadata');
4
- var meocord_app = require('../_shared/meocord.app-BcwCzqru.cjs');
4
+ var meocord_app = require('../_shared/meocord.app-Ds9XbbCN.cjs');
5
5
  var inversify = require('inversify');
6
6
  var discord_js = require('discord.js');
7
+ var enum_index = require('../enum/index.cjs');
7
8
  var theme = require('../_shared/theme-Bz-D4RbT.cjs');
8
- require('../enum/index.cjs');
9
9
  require('lodash-es');
10
10
  require('cli-table3');
11
11
  require('node:util');
@@ -36,7 +36,7 @@ require('chalk');
36
36
  */ function Service() {
37
37
  return function(target) {
38
38
  // Check if the class is already injectable; if not, make it injectable dynamically
39
- if (!Reflect.hasMetadata('inversify:injectable', target)) {
39
+ if (!Reflect.hasMetadata(enum_index.MetadataKey.Injectable, target)) {
40
40
  inversify.injectable()(target);
41
41
  }
42
42
  // Check if the class is already injectable; if not, make it injectable dynamically
@@ -50,14 +50,14 @@ require('chalk');
50
50
  }
51
51
  function bindDependencies$1(target) {
52
52
  // Get the constructor parameter types using Reflect metadata
53
- const dependencies = Reflect.getMetadata('design:paramtypes', target) || [];
53
+ const dependencies = Reflect.getMetadata(enum_index.MetadataKey.ParamTypes, target) || [];
54
54
  dependencies.forEach((dep)=>{
55
55
  // Bind the dependency if not already bound
56
56
  if (!meocord_app.mainContainer.isBound(dep)) {
57
57
  if (dep.name === discord_js.Client.name) return;
58
58
  try {
59
59
  // Check if the class is already injectable; if not, make it injectable dynamically
60
- if (!Reflect.hasMetadata('inversify:injectable', dep)) {
60
+ if (!Reflect.hasMetadata(enum_index.MetadataKey.Injectable, dep)) {
61
61
  inversify.injectable()(dep);
62
62
  }
63
63
  meocord_app.mainContainer.bind(dep).toSelf().inSingletonScope();
@@ -89,11 +89,11 @@ function bindDependencies$1(target) {
89
89
  */ function CommandBuilder(commandType) {
90
90
  return function(target) {
91
91
  // Check if the class is already injectable; if not, make it injectable dynamically
92
- if (!Reflect.hasMetadata('inversify:injectable', target)) {
92
+ if (!Reflect.hasMetadata(enum_index.MetadataKey.Injectable, target)) {
93
93
  inversify.injectable()(target);
94
94
  }
95
95
  // Define the command type metadata for the target class
96
- Reflect.defineMetadata('commandType', commandType, target);
96
+ Reflect.defineMetadata(enum_index.MetadataKey.CommandType, commandType, target);
97
97
  };
98
98
  }
99
99
 
@@ -167,12 +167,12 @@ export class ButtonInteractionGuard implements GuardInterface {
167
167
  */ function Guard() {
168
168
  return function(target) {
169
169
  // Check if the class is already injectable; if not, make it injectable dynamically
170
- if (!Reflect.hasMetadata('inversify:injectable', target)) {
170
+ if (!Reflect.hasMetadata(enum_index.MetadataKey.Injectable, target)) {
171
171
  inversify.injectable()(target);
172
172
  }
173
173
  meocord_app.mainContainer.bind(target).toSelf().inTransientScope();
174
174
  // Bind any dependencies that the guard requires
175
- const injectables = Reflect.getMetadata('design:paramtypes', target) || [];
175
+ const injectables = Reflect.getMetadata(enum_index.MetadataKey.ParamTypes, target) || [];
176
176
  injectables.forEach((dep)=>{
177
177
  if (!meocord_app.mainContainer.isBound(dep)) {
178
178
  meocord_app.mainContainer.bind(dep).toSelf().inSingletonScope();
@@ -231,7 +231,7 @@ export class ButtonInteractionGuard implements GuardInterface {
231
231
  // Method Decorator
232
232
  applyGuards(descriptor, guards, String(propertyKey));
233
233
  // Store guard metadata for later access (if needed)
234
- Reflect.defineMetadata('guards', guards, target, propertyKey);
234
+ Reflect.defineMetadata(enum_index.MetadataKey.Guards, guards, target, propertyKey);
235
235
  } else if (typeof target === 'function' && !propertyKey && !descriptor) {
236
236
  // Class Decorator
237
237
  const prototype = target.prototype;
@@ -248,7 +248,7 @@ export class ButtonInteractionGuard implements GuardInterface {
248
248
  if (methodDescriptor) {
249
249
  applyGuards(methodDescriptor, guards, methodName);
250
250
  Object.defineProperty(prototype, methodName, methodDescriptor);
251
- Reflect.defineMetadata('guards', guards, prototype, methodName);
251
+ Reflect.defineMetadata(enum_index.MetadataKey.Guards, guards, prototype, methodName);
252
252
  }
253
253
  }
254
254
  }
@@ -263,7 +263,7 @@ export class ButtonInteractionGuard implements GuardInterface {
263
263
  */ function bindDependencies(container, cls) {
264
264
  if (!container.isBound(cls)) {
265
265
  container.bind(cls).toSelf().inSingletonScope();
266
- const dependencies = Reflect.getMetadata('design:paramtypes', cls) || [];
266
+ const dependencies = Reflect.getMetadata(enum_index.MetadataKey.ParamTypes, cls) || [];
267
267
  dependencies.forEach((dep)=>bindDependencies(container, dep));
268
268
  }
269
269
  }
@@ -274,7 +274,7 @@ export class ButtonInteractionGuard implements GuardInterface {
274
274
  * @param {any} target - The target class whose dependencies are to be resolved.
275
275
  * @returns {any[]} - An array of resolved instances of the target's dependencies.
276
276
  */ function resolveDependencies(container, target) {
277
- const injectables = Reflect.getMetadata('design:paramtypes', target) || [];
277
+ const injectables = Reflect.getMetadata(enum_index.MetadataKey.ParamTypes, target) || [];
278
278
  return injectables.map((dep)=>{
279
279
  bindDependencies(container, dep);
280
280
  return container.get(dep);
@@ -314,7 +314,7 @@ export class ButtonInteractionGuard implements GuardInterface {
314
314
  * ```
315
315
  **/ function MeoCord(options) {
316
316
  return (target)=>{
317
- if (!Reflect.hasMetadata('inversify:injectable', target)) {
317
+ if (!Reflect.hasMetadata(enum_index.MetadataKey.Injectable, target)) {
318
318
  inversify.injectable()(target); // Make target injectable (inversify-specific)
319
319
  }
320
320
  const meocordConfig = theme.loadMeoCordConfig();
@@ -342,7 +342,7 @@ export class ButtonInteractionGuard implements GuardInterface {
342
342
  const dependencies = resolveDependencies(meocord_app.mainContainer, target);
343
343
  return new target(...dependencies);
344
344
  }).inSingletonScope();
345
- Reflect.defineMetadata('inversify:container', meocord_app.mainContainer, target);
345
+ Reflect.defineMetadata(enum_index.MetadataKey.Container, meocord_app.mainContainer, target);
346
346
  };
347
347
  }
348
348
 
@@ -16,5 +16,37 @@ var CommandType = /*#__PURE__*/ function(CommandType) {
16
16
  return ReactionHandlerAction;
17
17
  }({});
18
18
 
19
+ /**
20
+ * MeoCord Framework
21
+ * Copyright (c) 2025 Ukasyah Rahmatullah Zada
22
+ * SPDX-License-Identifier: MIT
23
+ */ /**
24
+ * Centralised metadata keys used across the framework's `Reflect` calls.
25
+ *
26
+ * Keeping them here prevents typos, documents the Inversify 8 key rename,
27
+ * and makes key changes a single-file edit.
28
+ */ var MetadataKey = /*#__PURE__*/ function(MetadataKey) {
29
+ /**
30
+ * Set by Inversify 8's `injectable()` decorator.
31
+ * Renamed from the legacy `'inversify:injectable'` string used in older versions.
32
+ */ MetadataKey["Injectable"] = "@inversifyjs/core/classIsInjectableFlagReflectKey";
33
+ /**
34
+ * Stores the Inversify `Container` instance on a `@Controller` or `@MeoCord` class.
35
+ * Read by `MeoCordFactory.create()` and `MeoCordApp` event handlers.
36
+ */ MetadataKey["Container"] = "inversify:container";
37
+ /**
38
+ * TypeScript compiler-emitted metadata listing constructor parameter types.
39
+ * Requires `"emitDecoratorMetadata": true` in tsconfig.
40
+ */ MetadataKey["ParamTypes"] = "design:paramtypes";
41
+ /**
42
+ * Stores the guard list applied to a method or class via `@UseGuard`.
43
+ */ MetadataKey["Guards"] = "guards";
44
+ /**
45
+ * Stores the `CommandType` on a `@CommandBuilder` class.
46
+ */ MetadataKey["CommandType"] = "commandType";
47
+ return MetadataKey;
48
+ }({});
49
+
19
50
  exports.CommandType = CommandType;
51
+ exports.MetadataKey = MetadataKey;
20
52
  exports.ReactionHandlerAction = ReactionHandlerAction;
@@ -5,13 +5,14 @@ import { MeoCordApp } from './meocord.app.js';
5
5
  import { mainContainer } from '../decorator/container.js';
6
6
  import 'inversify';
7
7
  import 'discord.js';
8
+ import { MetadataKey } from '../enum/metadata-key.enum.js';
8
9
  import 'path';
9
10
  import 'fs';
10
11
  import 'jiti';
11
12
 
12
13
  class MeoCordFactory {
13
14
  static create(target) {
14
- const container = Reflect.getMetadata('inversify:container', target);
15
+ const container = Reflect.getMetadata(MetadataKey.Container, target);
15
16
  if (!container) {
16
17
  if (typeof target === 'function') {
17
18
  this.logger.error(`No container found for class: ${target.name}`);
@@ -6,6 +6,7 @@ import { mainContainer } from '../decorator/container.js';
6
6
  import { sample } from 'lodash-es';
7
7
  import { createErrorEmbed } from '../util/embed.util.js';
8
8
  import { ReactionHandlerAction, CommandType } from '../enum/controller.enum.js';
9
+ import { MetadataKey } from '../enum/metadata-key.enum.js';
9
10
  import CliTable3 from 'cli-table3';
10
11
 
11
12
  class MeoCordApp {
@@ -178,7 +179,7 @@ class MeoCordApp {
178
179
  for (const controller of relevantControllers){
179
180
  let controllerInstance = this.controllerInstancesCache.get(controller.constructor);
180
181
  if (!controllerInstance) {
181
- const container = Reflect.getMetadata('inversify:container', controller.constructor);
182
+ const container = Reflect.getMetadata(MetadataKey.Container, controller.constructor);
182
183
  controllerInstance = container.get(controller.constructor, {
183
184
  autobind: true
184
185
  });
@@ -211,7 +212,7 @@ class MeoCordApp {
211
212
  for (const controller of relevantControllers){
212
213
  let controllerInstance = this.controllerInstancesCache.get(controller.constructor);
213
214
  if (!controllerInstance) {
214
- const container = Reflect.getMetadata('inversify:container', controller.constructor);
215
+ const container = Reflect.getMetadata(MetadataKey.Container, controller.constructor);
215
216
  controllerInstance = container.get(controller.constructor, {
216
217
  autobind: true
217
218
  });
@@ -4,6 +4,7 @@ import { injectable } from 'inversify';
4
4
  import { Client } from 'discord.js';
5
5
  import { MeoCordApp } from '../core/meocord.app.js';
6
6
  import { loadMeoCordConfig } from '../util/meocord-config-loader.util.js';
7
+ import { MetadataKey } from '../enum/metadata-key.enum.js';
7
8
 
8
9
  /**
9
10
  * Binds a class and its dependencies to the Inversify container in singleton scope.
@@ -13,7 +14,7 @@ import { loadMeoCordConfig } from '../util/meocord-config-loader.util.js';
13
14
  */ function bindDependencies(container, cls) {
14
15
  if (!container.isBound(cls)) {
15
16
  container.bind(cls).toSelf().inSingletonScope();
16
- const dependencies = Reflect.getMetadata('design:paramtypes', cls) || [];
17
+ const dependencies = Reflect.getMetadata(MetadataKey.ParamTypes, cls) || [];
17
18
  dependencies.forEach((dep)=>bindDependencies(container, dep));
18
19
  }
19
20
  }
@@ -24,7 +25,7 @@ import { loadMeoCordConfig } from '../util/meocord-config-loader.util.js';
24
25
  * @param {any} target - The target class whose dependencies are to be resolved.
25
26
  * @returns {any[]} - An array of resolved instances of the target's dependencies.
26
27
  */ function resolveDependencies(container, target) {
27
- const injectables = Reflect.getMetadata('design:paramtypes', target) || [];
28
+ const injectables = Reflect.getMetadata(MetadataKey.ParamTypes, target) || [];
28
29
  return injectables.map((dep)=>{
29
30
  bindDependencies(container, dep);
30
31
  return container.get(dep);
@@ -64,7 +65,7 @@ import { loadMeoCordConfig } from '../util/meocord-config-loader.util.js';
64
65
  * ```
65
66
  **/ function MeoCord(options) {
66
67
  return (target)=>{
67
- if (!Reflect.hasMetadata('inversify:injectable', target)) {
68
+ if (!Reflect.hasMetadata(MetadataKey.Injectable, target)) {
68
69
  injectable()(target); // Make target injectable (inversify-specific)
69
70
  }
70
71
  const meocordConfig = loadMeoCordConfig();
@@ -92,7 +93,7 @@ import { loadMeoCordConfig } from '../util/meocord-config-loader.util.js';
92
93
  const dependencies = resolveDependencies(mainContainer, target);
93
94
  return new target(...dependencies);
94
95
  }).inSingletonScope();
95
- Reflect.defineMetadata('inversify:container', mainContainer, target);
96
+ Reflect.defineMetadata(MetadataKey.Container, mainContainer, target);
96
97
  };
97
98
  }
98
99
 
@@ -1,5 +1,6 @@
1
1
  import 'reflect-metadata';
2
2
  import { injectable } from 'inversify';
3
+ import { MetadataKey } from '../enum/metadata-key.enum.js';
3
4
 
4
5
  /**
5
6
  * This decorator is used to mark a class as a Discord command builder that later can be registered on the `@Command` decorator.
@@ -21,11 +22,11 @@ import { injectable } from 'inversify';
21
22
  */ function CommandBuilder(commandType) {
22
23
  return function(target) {
23
24
  // Check if the class is already injectable; if not, make it injectable dynamically
24
- if (!Reflect.hasMetadata('inversify:injectable', target)) {
25
+ if (!Reflect.hasMetadata(MetadataKey.Injectable, target)) {
25
26
  injectable()(target);
26
27
  }
27
28
  // Define the command type metadata for the target class
28
- Reflect.defineMetadata('commandType', commandType, target);
29
+ Reflect.defineMetadata(MetadataKey.CommandType, commandType, target);
29
30
  };
30
31
  }
31
32
 
@@ -3,6 +3,7 @@ import { injectable } from 'inversify';
3
3
  import { mainContainer } from './container.js';
4
4
  import { ButtonInteraction, StringSelectMenuInteraction, ChatInputCommandInteraction, ContextMenuCommandInteraction, ModalSubmitInteraction } from 'discord.js';
5
5
  import { CommandType } from '../enum/controller.enum.js';
6
+ import { MetadataKey } from '../enum/metadata-key.enum.js';
6
7
 
7
8
  const COMMAND_METADATA_KEY = Symbol('commands');
8
9
  const MESSAGE_HANDLER_METADATA_KEY = Symbol('message_handlers');
@@ -147,7 +148,7 @@ const REACTION_HANDLER_METADATA_KEY = Symbol('reaction_handlers');
147
148
  if (typeof builderOrType === 'function') {
148
149
  const builderObj = new builderOrType();
149
150
  builderInstance = builderObj.build(commandName);
150
- commandType = Reflect.getMetadata('commandType', builderOrType);
151
+ commandType = Reflect.getMetadata(MetadataKey.CommandType, builderOrType);
151
152
  if (!(commandType in CommandType)) {
152
153
  throw new Error(`Metadata for 'commandType' is missing on builder ${builderOrType.name}`);
153
154
  }
@@ -199,19 +200,19 @@ const REACTION_HANDLER_METADATA_KEY = Symbol('reaction_handlers');
199
200
  * ```
200
201
  */ function Controller() {
201
202
  return function(target) {
202
- if (!Reflect.hasMetadata('inversify:injectable', target)) {
203
+ if (!Reflect.hasMetadata(MetadataKey.Injectable, target)) {
203
204
  injectable()(target);
204
205
  }
205
- const injectables = Reflect.getMetadata('design:paramtypes', target) || [];
206
+ const injectables = Reflect.getMetadata(MetadataKey.ParamTypes, target) || [];
206
207
  injectables.map((dep)=>{
207
208
  if (!mainContainer.isBound(dep)) {
208
- if (!Reflect.hasMetadata('inversify:injectable', dep)) {
209
+ if (!Reflect.hasMetadata(MetadataKey.Injectable, dep)) {
209
210
  injectable()(dep);
210
211
  }
211
212
  mainContainer.bind(dep).toSelf().inSingletonScope();
212
213
  }
213
214
  });
214
- Reflect.defineMetadata('inversify:container', mainContainer, target);
215
+ Reflect.defineMetadata(MetadataKey.Container, mainContainer, target);
215
216
  };
216
217
  }
217
218
 
@@ -3,6 +3,7 @@ import { injectable } from 'inversify';
3
3
  import { mainContainer } from './container.js';
4
4
  import { BaseInteraction, Message, MessageReaction } from 'discord.js';
5
5
  import { getCommandMap, getMessageHandlers, getReactionHandlers } from './controller.decorator.js';
6
+ import { MetadataKey } from '../enum/metadata-key.enum.js';
6
7
 
7
8
  function isValidContext(context) {
8
9
  return context instanceof BaseInteraction || context instanceof Message || context instanceof MessageReaction;
@@ -74,12 +75,12 @@ export class ButtonInteractionGuard implements GuardInterface {
74
75
  */ function Guard() {
75
76
  return function(target) {
76
77
  // Check if the class is already injectable; if not, make it injectable dynamically
77
- if (!Reflect.hasMetadata('inversify:injectable', target)) {
78
+ if (!Reflect.hasMetadata(MetadataKey.Injectable, target)) {
78
79
  injectable()(target);
79
80
  }
80
81
  mainContainer.bind(target).toSelf().inTransientScope();
81
82
  // Bind any dependencies that the guard requires
82
- const injectables = Reflect.getMetadata('design:paramtypes', target) || [];
83
+ const injectables = Reflect.getMetadata(MetadataKey.ParamTypes, target) || [];
83
84
  injectables.forEach((dep)=>{
84
85
  if (!mainContainer.isBound(dep)) {
85
86
  mainContainer.bind(dep).toSelf().inSingletonScope();
@@ -138,7 +139,7 @@ export class ButtonInteractionGuard implements GuardInterface {
138
139
  // Method Decorator
139
140
  applyGuards(descriptor, guards, String(propertyKey));
140
141
  // Store guard metadata for later access (if needed)
141
- Reflect.defineMetadata('guards', guards, target, propertyKey);
142
+ Reflect.defineMetadata(MetadataKey.Guards, guards, target, propertyKey);
142
143
  } else if (typeof target === 'function' && !propertyKey && !descriptor) {
143
144
  // Class Decorator
144
145
  const prototype = target.prototype;
@@ -155,7 +156,7 @@ export class ButtonInteractionGuard implements GuardInterface {
155
156
  if (methodDescriptor) {
156
157
  applyGuards(methodDescriptor, guards, methodName);
157
158
  Object.defineProperty(prototype, methodName, methodDescriptor);
158
- Reflect.defineMetadata('guards', guards, prototype, methodName);
159
+ Reflect.defineMetadata(MetadataKey.Guards, guards, prototype, methodName);
159
160
  }
160
161
  }
161
162
  }
@@ -2,6 +2,7 @@ import 'reflect-metadata';
2
2
  import { mainContainer } from './container.js';
3
3
  import { injectable } from 'inversify';
4
4
  import { Client } from 'discord.js';
5
+ import { MetadataKey } from '../enum/metadata-key.enum.js';
5
6
 
6
7
  /**
7
8
  * `@Service()` decorator to mark a class as a service that can be injected into controllers or used as standalone services.
@@ -22,7 +23,7 @@ import { Client } from 'discord.js';
22
23
  */ function Service() {
23
24
  return function(target) {
24
25
  // Check if the class is already injectable; if not, make it injectable dynamically
25
- if (!Reflect.hasMetadata('inversify:injectable', target)) {
26
+ if (!Reflect.hasMetadata(MetadataKey.Injectable, target)) {
26
27
  injectable()(target);
27
28
  }
28
29
  // Check if the class is already injectable; if not, make it injectable dynamically
@@ -36,14 +37,14 @@ import { Client } from 'discord.js';
36
37
  }
37
38
  function bindDependencies(target) {
38
39
  // Get the constructor parameter types using Reflect metadata
39
- const dependencies = Reflect.getMetadata('design:paramtypes', target) || [];
40
+ const dependencies = Reflect.getMetadata(MetadataKey.ParamTypes, target) || [];
40
41
  dependencies.forEach((dep)=>{
41
42
  // Bind the dependency if not already bound
42
43
  if (!mainContainer.isBound(dep)) {
43
44
  if (dep.name === Client.name) return;
44
45
  try {
45
46
  // Check if the class is already injectable; if not, make it injectable dynamically
46
- if (!Reflect.hasMetadata('inversify:injectable', dep)) {
47
+ if (!Reflect.hasMetadata(MetadataKey.Injectable, dep)) {
47
48
  injectable()(dep);
48
49
  }
49
50
  mainContainer.bind(dep).toSelf().inSingletonScope();
@@ -1 +1,2 @@
1
1
  export { CommandType, ReactionHandlerAction } from './controller.enum.js';
2
+ export { MetadataKey } from './metadata-key.enum.js';
@@ -0,0 +1,32 @@
1
+ /**
2
+ * MeoCord Framework
3
+ * Copyright (c) 2025 Ukasyah Rahmatullah Zada
4
+ * SPDX-License-Identifier: MIT
5
+ */ /**
6
+ * Centralised metadata keys used across the framework's `Reflect` calls.
7
+ *
8
+ * Keeping them here prevents typos, documents the Inversify 8 key rename,
9
+ * and makes key changes a single-file edit.
10
+ */ var MetadataKey = /*#__PURE__*/ function(MetadataKey) {
11
+ /**
12
+ * Set by Inversify 8's `injectable()` decorator.
13
+ * Renamed from the legacy `'inversify:injectable'` string used in older versions.
14
+ */ MetadataKey["Injectable"] = "@inversifyjs/core/classIsInjectableFlagReflectKey";
15
+ /**
16
+ * Stores the Inversify `Container` instance on a `@Controller` or `@MeoCord` class.
17
+ * Read by `MeoCordFactory.create()` and `MeoCordApp` event handlers.
18
+ */ MetadataKey["Container"] = "inversify:container";
19
+ /**
20
+ * TypeScript compiler-emitted metadata listing constructor parameter types.
21
+ * Requires `"emitDecoratorMetadata": true` in tsconfig.
22
+ */ MetadataKey["ParamTypes"] = "design:paramtypes";
23
+ /**
24
+ * Stores the guard list applied to a method or class via `@UseGuard`.
25
+ */ MetadataKey["Guards"] = "guards";
26
+ /**
27
+ * Stores the `CommandType` on a `@CommandBuilder` class.
28
+ */ MetadataKey["CommandType"] = "commandType";
29
+ return MetadataKey;
30
+ }({});
31
+
32
+ export { MetadataKey };
@@ -0,0 +1,18 @@
1
+ declare enum CommandType {
2
+ SLASH = "SLASH",
3
+ BUTTON = "BUTTON",
4
+ CONTEXT_MENU = "CONTEXT_MENU",
5
+ SELECT_MENU = "SELECT_MENU",
6
+ MODAL_SUBMIT = "MODAL_SUBMIT"
7
+ }
8
+ /**
9
+ * Enum representing actions that can be performed on a message reaction.
10
+ */
11
+ declare enum ReactionHandlerAction {
12
+ /** Reaction added to a message. */
13
+ ADD = "ADD",
14
+ /** Reaction removed from a message. */
15
+ REMOVE = "REMOVE"
16
+ }
17
+
18
+ export { CommandType as C, ReactionHandlerAction as R };
@@ -1,4 +1,4 @@
1
- import { CommandType } from '../enum/index.js';
1
+ import { C as CommandType } from '../controller.enum-QA-IuReF.js';
2
2
  import { SlashCommandBuilder, SlashCommandSubcommandsOnlyBuilder, ContextMenuCommandBuilder, ButtonInteraction, StringSelectMenuInteraction, ChatInputCommandInteraction, UserContextMenuCommandInteraction, MessageContextMenuCommandInteraction, ModalSubmitInteraction, OmitPartialGroupDMChannel, Message, MessageReaction, PartialMessageReaction, ClientOptions, ActivityOptions } from 'discord.js';
3
3
  import { ReactionHandlerOptions, GuardInterface } from '../interface/index.js';
4
4
  import { ServiceIdentifier, Container } from 'inversify';
@@ -1,18 +1,40 @@
1
- declare enum CommandType {
2
- SLASH = "SLASH",
3
- BUTTON = "BUTTON",
4
- CONTEXT_MENU = "CONTEXT_MENU",
5
- SELECT_MENU = "SELECT_MENU",
6
- MODAL_SUBMIT = "MODAL_SUBMIT"
7
- }
1
+ export { C as CommandType, R as ReactionHandlerAction } from '../controller.enum-QA-IuReF.js';
2
+
3
+ /**
4
+ * MeoCord Framework
5
+ * Copyright (c) 2025 Ukasyah Rahmatullah Zada
6
+ * SPDX-License-Identifier: MIT
7
+ */
8
8
  /**
9
- * Enum representing actions that can be performed on a message reaction.
9
+ * Centralised metadata keys used across the framework's `Reflect` calls.
10
+ *
11
+ * Keeping them here prevents typos, documents the Inversify 8 key rename,
12
+ * and makes key changes a single-file edit.
10
13
  */
11
- declare enum ReactionHandlerAction {
12
- /** Reaction added to a message. */
13
- ADD = "ADD",
14
- /** Reaction removed from a message. */
15
- REMOVE = "REMOVE"
14
+ declare const enum MetadataKey {
15
+ /**
16
+ * Set by Inversify 8's `injectable()` decorator.
17
+ * Renamed from the legacy `'inversify:injectable'` string used in older versions.
18
+ */
19
+ Injectable = "@inversifyjs/core/classIsInjectableFlagReflectKey",
20
+ /**
21
+ * Stores the Inversify `Container` instance on a `@Controller` or `@MeoCord` class.
22
+ * Read by `MeoCordFactory.create()` and `MeoCordApp` event handlers.
23
+ */
24
+ Container = "inversify:container",
25
+ /**
26
+ * TypeScript compiler-emitted metadata listing constructor parameter types.
27
+ * Requires `"emitDecoratorMetadata": true` in tsconfig.
28
+ */
29
+ ParamTypes = "design:paramtypes",
30
+ /**
31
+ * Stores the guard list applied to a method or class via `@UseGuard`.
32
+ */
33
+ Guards = "guards",
34
+ /**
35
+ * Stores the `CommandType` on a `@CommandBuilder` class.
36
+ */
37
+ CommandType = "commandType"
16
38
  }
17
39
 
18
- export { CommandType, ReactionHandlerAction };
40
+ export { MetadataKey };
@@ -1,6 +1,6 @@
1
1
  import { User, PartialUser, BaseInteraction, Message, MessageReaction } from 'discord.js';
2
2
  import { Configuration } from 'webpack';
3
- import { ReactionHandlerAction } from '../enum/index.js';
3
+ import { R as ReactionHandlerAction } from '../controller.enum-QA-IuReF.js';
4
4
 
5
5
  /**
6
6
  * MeoCord Framework
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "meocord",
3
3
  "description": "MeoCord is a lightweight and modular framework for building scalable Discord bots using TypeScript and Discord.js. It simplifies bot development with an extensible architecture, TypeScript-first approach, and powerful CLI tools.",
4
- "version": "1.4.0",
4
+ "version": "1.4.1",
5
5
  "type": "module",
6
6
  "scripts": {
7
- "lint": "eslint --fix . && tsc --noEmit",
7
+ "lint": "eslint --fix . && tsc --noEmit && tsc --noEmit --project tsconfig.test.json",
8
8
  "build": "rm -rf ./dist && rollup -c",
9
- "prepare": "husky"
9
+ "prepare": "husky",
10
+ "test": "node --experimental-vm-modules node_modules/.bin/jest",
11
+ "test:watch": "node --experimental-vm-modules node_modules/.bin/jest --watch",
12
+ "test:coverage": "node --experimental-vm-modules node_modules/.bin/jest --coverage",
13
+ "test:typecheck": "bunx tsc --noEmit --project tsconfig.test.json"
10
14
  },
11
15
  "bin": "./dist/esm/bin/meocord.js",
12
16
  "repository": {
@@ -62,7 +66,7 @@
62
66
  "cli-table3": "^0.6.5",
63
67
  "commander": "^14.0.3",
64
68
  "dayjs": "^1.11.20",
65
- "dotenv": "^17.4.1",
69
+ "dotenv": "^16.4.7",
66
70
  "inversify": "^8.1.0",
67
71
  "jiti": "^2.6.1",
68
72
  "lodash-es": "^4.18.1",
@@ -85,6 +89,8 @@
85
89
  "@semantic-release/exec": "^7.1.0",
86
90
  "@semantic-release/github": "^12.0.6",
87
91
  "@semantic-release/release-notes-generator": "^14.1.0",
92
+ "@swc/jest": "^0.2.39",
93
+ "@types/jest": "29",
88
94
  "@types/lodash-es": "^4.17.12",
89
95
  "@types/webpack-node-externals": "^3.0.4",
90
96
  "@typescript-eslint/parser": "^8.58.1",
@@ -97,6 +103,7 @@
97
103
  "eslint-plugin-unused-imports": "^4.4.1",
98
104
  "globals": "^17.4.0",
99
105
  "husky": "^9.1.7",
106
+ "jest": "29",
100
107
  "prettier": "^3.8.1",
101
108
  "rollup": "^4.60.1",
102
109
  "rollup-plugin-copy": "^3.5.0",