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 +6 -0
- package/dist/cjs/_shared/{meocord.app-BcwCzqru.cjs → meocord.app-Ds9XbbCN.cjs} +7 -7
- package/dist/cjs/core/index.cjs +3 -3
- package/dist/cjs/decorator/index.cjs +15 -15
- package/dist/cjs/enum/index.cjs +32 -0
- package/dist/esm/core/meocord-factory.js +2 -1
- package/dist/esm/core/meocord.app.js +3 -2
- package/dist/esm/decorator/app.decorator.js +5 -4
- package/dist/esm/decorator/command-builder.decorator.js +3 -2
- package/dist/esm/decorator/controller.decorator.js +6 -5
- package/dist/esm/decorator/guard.decorator.js +5 -4
- package/dist/esm/decorator/service.decorator.js +4 -3
- package/dist/esm/enum/index.js +1 -0
- package/dist/esm/enum/metadata-key.enum.js +32 -0
- package/dist/types/controller.enum-QA-IuReF.d.ts +18 -0
- package/dist/types/decorator/index.d.ts +1 -1
- package/dist/types/enum/index.d.ts +36 -14
- package/dist/types/interface/index.d.ts +1 -1
- package/package.json +11 -4
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(
|
|
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(
|
|
208
|
+
if (!Reflect.hasMetadata(enum_index.MetadataKey.Injectable, target)) {
|
|
209
209
|
inversify.injectable()(target);
|
|
210
210
|
}
|
|
211
|
-
const injectables = Reflect.getMetadata(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
435
|
+
const container = Reflect.getMetadata(enum_index.MetadataKey.Container, controller.constructor);
|
|
436
436
|
controllerInstance = container.get(controller.constructor, {
|
|
437
437
|
autobind: true
|
|
438
438
|
});
|
package/dist/cjs/core/index.cjs
CHANGED
|
@@ -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-
|
|
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(
|
|
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-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
345
|
+
Reflect.defineMetadata(enum_index.MetadataKey.Container, meocord_app.mainContainer, target);
|
|
346
346
|
};
|
|
347
347
|
}
|
|
348
348
|
|
package/dist/cjs/enum/index.cjs
CHANGED
|
@@ -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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
203
|
+
if (!Reflect.hasMetadata(MetadataKey.Injectable, target)) {
|
|
203
204
|
injectable()(target);
|
|
204
205
|
}
|
|
205
|
-
const injectables = Reflect.getMetadata(
|
|
206
|
+
const injectables = Reflect.getMetadata(MetadataKey.ParamTypes, target) || [];
|
|
206
207
|
injectables.map((dep)=>{
|
|
207
208
|
if (!mainContainer.isBound(dep)) {
|
|
208
|
-
if (!Reflect.hasMetadata(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
47
|
+
if (!Reflect.hasMetadata(MetadataKey.Injectable, dep)) {
|
|
47
48
|
injectable()(dep);
|
|
48
49
|
}
|
|
49
50
|
mainContainer.bind(dep).toSelf().inSingletonScope();
|
package/dist/esm/enum/index.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
*
|
|
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
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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 {
|
|
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
|
|
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.
|
|
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": "^
|
|
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",
|