zumito-framework 1.2.17 → 1.2.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ZumitoFramework.d.ts +1 -1
- package/dist/ZumitoFramework.js +3 -1
- package/dist/definitions/ErrorType.d.ts +2 -1
- package/dist/definitions/ErrorType.js +1 -0
- package/dist/definitions/FrameworkSettings.d.ts +4 -19
- package/dist/definitions/commands/Command.d.ts +8 -12
- package/dist/definitions/commands/Command.js +9 -4
- package/dist/definitions/commands/CommandBinds.d.ts +4 -0
- package/dist/definitions/commands/CommandBinds.js +1 -0
- package/dist/definitions/commands/CommandParameters.d.ts +10 -3
- package/dist/definitions/parameters/EventParameters.d.ts +6 -0
- package/dist/definitions/parameters/SelectMenuParameters.d.ts +6 -0
- package/dist/definitions/settings/FrameworkSettings.d.ts +24 -0
- package/dist/definitions/settings/FrameworkSettings.js +1 -0
- package/dist/definitions/settings/InteractionHandlerSettings.d.ts +3 -0
- package/dist/definitions/settings/InteractionHandlerSettings.js +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +5 -1
- package/dist/modules/core/baseModule/events/discord/InteractionCreate.d.ts +4 -3
- package/dist/modules/core/baseModule/events/discord/InteractionCreate.js +8 -122
- package/dist/modules/core/baseModule/events/discord/MessageCreate.d.ts +7 -0
- package/dist/modules/core/baseModule/events/discord/MessageCreate.js +35 -36
- package/dist/services/CommandManager.js +16 -9
- package/dist/services/CommandParser.d.ts +7 -0
- package/dist/services/CommandParser.js +32 -0
- package/dist/services/ErrorHandler.d.ts +2 -1
- package/dist/services/ErrorHandler.js +69 -7
- package/dist/services/InteractionHandler.d.ts +21 -0
- package/dist/services/InteractionHandler.js +206 -0
- package/dist/services/ServiceContainer.d.ts +9 -1
- package/dist/services/ServiceContainer.js +14 -2
- package/dist/services/SlashCommandRefresher.d.ts +4 -1
- package/dist/services/SlashCommandRefresher.js +67 -50
- package/dist/services/TranslationManager.d.ts +1 -0
- package/dist/services/TranslationManager.js +12 -0
- package/package.json +6 -1
|
@@ -2,7 +2,7 @@ import { Client, GuildMember, TextChannel } from 'discord.js';
|
|
|
2
2
|
import { DatabaseModel } from './definitions/DatabaseModel.js';
|
|
3
3
|
import { EventEmitter } from "tseep";
|
|
4
4
|
import { FrameworkEvent } from './definitions/FrameworkEvent.js';
|
|
5
|
-
import { FrameworkSettings } from './definitions/FrameworkSettings.js';
|
|
5
|
+
import { FrameworkSettings } from './definitions/settings/FrameworkSettings.js';
|
|
6
6
|
import { StatusManager } from './services/StatusManager.js';
|
|
7
7
|
import { TranslationManager } from './services/TranslationManager.js';
|
|
8
8
|
import { EventManager } from './services/EventManager.js';
|
package/dist/ZumitoFramework.js
CHANGED
|
@@ -138,6 +138,8 @@ export class ZumitoFramework {
|
|
|
138
138
|
this.models = [];
|
|
139
139
|
this.eventManager = new EventManager();
|
|
140
140
|
ServiceContainer.addService(TranslationManager, [], true, this.translations);
|
|
141
|
+
ServiceContainer.addService(CommandManager, [], true, this.commands);
|
|
142
|
+
ServiceContainer.addService(EventManager, [], true, this.eventManager);
|
|
141
143
|
if (settings.logLevel) {
|
|
142
144
|
console.logLevel = settings.logLevel;
|
|
143
145
|
}
|
|
@@ -247,7 +249,7 @@ export class ZumitoFramework {
|
|
|
247
249
|
}
|
|
248
250
|
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
|
249
251
|
if (this.settings.bundles && this.settings.bundles.length > 0) {
|
|
250
|
-
for (
|
|
252
|
+
for (const bundle of this.settings.bundles) {
|
|
251
253
|
await this.registerBundle(bundle.path, bundle.options);
|
|
252
254
|
}
|
|
253
255
|
}
|
|
@@ -3,4 +3,5 @@ export var ErrorType;
|
|
|
3
3
|
ErrorType[ErrorType["CommandInstance"] = 1] = "CommandInstance";
|
|
4
4
|
ErrorType[ErrorType["CommandLoad"] = 2] = "CommandLoad";
|
|
5
5
|
ErrorType[ErrorType["CommandRun"] = 3] = "CommandRun";
|
|
6
|
+
ErrorType[ErrorType["Other"] = 4] = "Other";
|
|
6
7
|
})(ErrorType || (ErrorType = {}));
|
|
@@ -1,19 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
logLevel?: number;
|
|
6
|
-
debug?: boolean;
|
|
7
|
-
discordClientOptions: {
|
|
8
|
-
intents?: number;
|
|
9
|
-
token: string;
|
|
10
|
-
clientId: string;
|
|
11
|
-
};
|
|
12
|
-
defaultPrefix?: string;
|
|
13
|
-
statusOptions?: StatusManagerOptions;
|
|
14
|
-
srcMode?: 'multiBundle' | 'monoBundle' | undefined;
|
|
15
|
-
bundles?: {
|
|
16
|
-
path: string;
|
|
17
|
-
options?: ModuleParameters;
|
|
18
|
-
}[];
|
|
19
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated
|
|
3
|
+
*/
|
|
4
|
+
export { FrameworkSettings } from "./settings/FrameworkSettings";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CommandArgDefinition } from './CommandArgDefinition.js';
|
|
2
|
-
import { CommandParameters } from './CommandParameters.js';
|
|
3
|
-
import {
|
|
2
|
+
import { CommandParameters, PrefixCommandParameters, SlashCommandParameters } from './CommandParameters.js';
|
|
3
|
+
import { CommandBinds } from './CommandBinds.js';
|
|
4
4
|
/**
|
|
5
5
|
* @name Command
|
|
6
6
|
* @description Base class for all commands
|
|
@@ -201,19 +201,15 @@ export declare abstract class Command {
|
|
|
201
201
|
* @see {@link CommandType}
|
|
202
202
|
*/
|
|
203
203
|
type: string;
|
|
204
|
+
parent?: string;
|
|
205
|
+
binds?: CommandBinds;
|
|
204
206
|
/**
|
|
205
207
|
* @name execute
|
|
206
208
|
* @description The function that is executed when the command is called.
|
|
207
209
|
* @param {CommandParameters} parameters The parameters of the command.
|
|
208
|
-
* @param {Message} parameters.message The message that triggered the command.
|
|
209
|
-
* @param {CommandInteraction} parameters.interaction The interaction that triggered the command.
|
|
210
|
-
* @param {string[]} parameters.args The arguments of the command.
|
|
211
|
-
* @param {Client} parameters.client The client.
|
|
212
|
-
* @param {Framework} parameters.framework The framework.
|
|
213
|
-
* @param {trans} (key: string, options?: any) => string Translation shorthand function.
|
|
214
210
|
*/
|
|
215
|
-
abstract execute(
|
|
216
|
-
executePrefixCommand({ message,
|
|
217
|
-
executeSlashCommand({
|
|
218
|
-
|
|
211
|
+
abstract execute(parameters: CommandParameters): Promise<void>;
|
|
212
|
+
executePrefixCommand({ message, args, client, framework, trans, }: PrefixCommandParameters): Promise<void>;
|
|
213
|
+
executeSlashCommand({ interaction, args, client, framework, trans, }: SlashCommandParameters): Promise<void>;
|
|
214
|
+
isSubCommand(): boolean;
|
|
219
215
|
}
|
|
@@ -199,10 +199,15 @@ export class Command {
|
|
|
199
199
|
* @see {@link CommandType}
|
|
200
200
|
*/
|
|
201
201
|
type = CommandType.prefix;
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
parent;
|
|
203
|
+
binds;
|
|
204
|
+
async executePrefixCommand({ message, args, client, framework, trans, }) {
|
|
205
|
+
await this.execute({ message, args, client, framework, trans });
|
|
204
206
|
}
|
|
205
|
-
executeSlashCommand({
|
|
206
|
-
this.execute({
|
|
207
|
+
async executeSlashCommand({ interaction, args, client, framework, trans, }) {
|
|
208
|
+
await this.execute({ interaction, args, client, framework, trans });
|
|
209
|
+
}
|
|
210
|
+
isSubCommand() {
|
|
211
|
+
return this.parent !== undefined;
|
|
207
212
|
}
|
|
208
213
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -8,9 +8,7 @@ import { ZumitoFramework } from '../../ZumitoFramework.js';
|
|
|
8
8
|
* @property {interaction} interaction - The interaction that triggered the command.
|
|
9
9
|
* @property {args} args - The arguments passed to the command.
|
|
10
10
|
*/
|
|
11
|
-
export interface
|
|
12
|
-
message?: Message;
|
|
13
|
-
interaction?: CommandInteraction;
|
|
11
|
+
export interface BaseCommandParameters {
|
|
14
12
|
args: Map<string, any>;
|
|
15
13
|
/**
|
|
16
14
|
* Discord client instance
|
|
@@ -29,3 +27,12 @@ export interface CommandParameters {
|
|
|
29
27
|
guildSettings?: any;
|
|
30
28
|
trans: (key: string, params?: any) => string;
|
|
31
29
|
}
|
|
30
|
+
export declare type SlashCommandParameters = BaseCommandParameters & {
|
|
31
|
+
interaction: CommandInteraction;
|
|
32
|
+
message?: null;
|
|
33
|
+
};
|
|
34
|
+
export declare type PrefixCommandParameters = BaseCommandParameters & {
|
|
35
|
+
message: Message;
|
|
36
|
+
interaction?: null;
|
|
37
|
+
};
|
|
38
|
+
export declare type CommandParameters = PrefixCommandParameters | SlashCommandParameters;
|
|
@@ -3,7 +3,13 @@ import { ZumitoFramework } from '../../ZumitoFramework.js';
|
|
|
3
3
|
export interface SelectMenuParameters {
|
|
4
4
|
path: string[];
|
|
5
5
|
interaction: SelectMenuInteraction;
|
|
6
|
+
/**
|
|
7
|
+
* @deprecated
|
|
8
|
+
*/
|
|
6
9
|
client: Client;
|
|
10
|
+
/**
|
|
11
|
+
* @deprecated
|
|
12
|
+
*/
|
|
7
13
|
framework: ZumitoFramework;
|
|
8
14
|
guildSettings?: any;
|
|
9
15
|
trans: (key: string, params?: any) => string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ModuleParameters } from "../parameters/ModuleParameters";
|
|
2
|
+
import { StatusManagerOptions } from "../StatusManagerOptions";
|
|
3
|
+
export interface FrameworkSettings {
|
|
4
|
+
database: any;
|
|
5
|
+
logLevel?: number;
|
|
6
|
+
debug?: boolean;
|
|
7
|
+
discordClientOptions: {
|
|
8
|
+
intents?: number;
|
|
9
|
+
token: string;
|
|
10
|
+
clientId: string;
|
|
11
|
+
};
|
|
12
|
+
defaultPrefix?: string;
|
|
13
|
+
statusOptions?: StatusManagerOptions;
|
|
14
|
+
/**
|
|
15
|
+
* Read the ./src folder as multiple modules or unique module
|
|
16
|
+
* This feature is experimental and can disapear anytime
|
|
17
|
+
* @experimental
|
|
18
|
+
*/
|
|
19
|
+
srcMode?: 'multiBundle' | 'monoBundle' | undefined;
|
|
20
|
+
bundles?: {
|
|
21
|
+
path: string;
|
|
22
|
+
options?: ModuleParameters;
|
|
23
|
+
}[];
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -27,4 +27,7 @@ import { CommandParser } from './services/CommandParser.js';
|
|
|
27
27
|
import { SlashCommandRefresher } from './services/SlashCommandRefresher.js';
|
|
28
28
|
import { ErrorHandler } from './services/ErrorHandler.js';
|
|
29
29
|
import { Route, RouteMethod } from './definitions/Route.js';
|
|
30
|
-
|
|
30
|
+
import { InteractionHandler } from './services/InteractionHandler.js';
|
|
31
|
+
import { CommandManager } from './services/CommandManager.js';
|
|
32
|
+
import { ErrorType } from './definitions/ErrorType.js';
|
|
33
|
+
export { ZumitoFramework, FrameworkSettings, Command, Module, CommandParameters, CommandArguments, FrameworkEvent, Translation, TranslationManager, ApiResponse, SelectMenuParameters, CommandType, CommandArgDefinition, CommandChoiceDefinition, ButtonPressed, ButtonPressedParams, TextFormatter, EmojiFallback, DatabaseConfigLoader, DatabaseModel, PresenceDataRule, RuledPresenceData, StatusManagerOptions, discord, EventParameters, ServiceContainer, GuildDataGetter, SlashCommandRefresher, CommandParser, ErrorHandler, ErrorType, Route, RouteMethod, InteractionHandler, CommandManager };
|
package/dist/index.js
CHANGED
|
@@ -20,11 +20,15 @@ import { CommandParser } from './services/CommandParser.js';
|
|
|
20
20
|
import { SlashCommandRefresher } from './services/SlashCommandRefresher.js';
|
|
21
21
|
import { ErrorHandler } from './services/ErrorHandler.js';
|
|
22
22
|
import { Route, RouteMethod } from './definitions/Route.js';
|
|
23
|
+
import { InteractionHandler } from './services/InteractionHandler.js';
|
|
24
|
+
import { CommandManager } from './services/CommandManager.js';
|
|
25
|
+
import { ErrorType } from './definitions/ErrorType.js';
|
|
23
26
|
ServiceContainer.addService(TextFormatter, []);
|
|
24
27
|
ServiceContainer.addService(EmojiFallback, [discord.Client.name, TranslationManager.name]);
|
|
25
28
|
ServiceContainer.addService(GuildDataGetter, [ZumitoFramework.name]);
|
|
26
29
|
ServiceContainer.addService(MemberPermissionChecker, []);
|
|
27
30
|
ServiceContainer.addService(CommandParser, []);
|
|
28
31
|
ServiceContainer.addService(SlashCommandRefresher, [ZumitoFramework.name]);
|
|
32
|
+
ServiceContainer.addService(InteractionHandler, []);
|
|
29
33
|
ServiceContainer.addService(ErrorHandler, ['ZumitoFramework']);
|
|
30
|
-
export { ZumitoFramework, Command, Module, CommandArguments, FrameworkEvent, Translation, TranslationManager, ApiResponse, CommandType, ButtonPressed, TextFormatter, EmojiFallback, DatabaseConfigLoader, DatabaseModel, discord, ServiceContainer, GuildDataGetter, SlashCommandRefresher, CommandParser, ErrorHandler, Route, RouteMethod };
|
|
34
|
+
export { ZumitoFramework, Command, Module, CommandArguments, FrameworkEvent, Translation, TranslationManager, ApiResponse, CommandType, ButtonPressed, TextFormatter, EmojiFallback, DatabaseConfigLoader, DatabaseModel, discord, ServiceContainer, GuildDataGetter, SlashCommandRefresher, CommandParser, ErrorHandler, ErrorType, Route, RouteMethod, InteractionHandler, CommandManager };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { Command } from '../../../../../definitions/commands/Command.js';
|
|
2
1
|
import { EventParameters } from '../../../../../definitions/parameters/EventParameters.js';
|
|
3
2
|
import { FrameworkEvent } from '../../../../../definitions/FrameworkEvent.js';
|
|
3
|
+
import { InteractionHandler } from '../../../../../services/InteractionHandler.js';
|
|
4
4
|
export declare class InteractionCreate extends FrameworkEvent {
|
|
5
5
|
once: boolean;
|
|
6
6
|
source: string;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
interactionHandler: InteractionHandler;
|
|
8
|
+
constructor();
|
|
9
|
+
execute({ interaction, }: EventParameters): Promise<void>;
|
|
9
10
|
}
|
|
@@ -1,129 +1,15 @@
|
|
|
1
|
-
import { CommandType } from '../../../../../definitions/commands/CommandType.js';
|
|
2
1
|
import { FrameworkEvent } from '../../../../../definitions/FrameworkEvent.js';
|
|
2
|
+
import { ServiceContainer } from '../../../../../services/ServiceContainer.js';
|
|
3
|
+
import { InteractionHandler } from '../../../../../services/InteractionHandler.js';
|
|
3
4
|
export class InteractionCreate extends FrameworkEvent {
|
|
4
5
|
once = false;
|
|
5
6
|
source = 'discord';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
if (interaction.isCommand()) {
|
|
12
|
-
if (!framework.commands.getAll().has(interaction.commandName))
|
|
13
|
-
return;
|
|
14
|
-
const commandInstance = framework.commands.get(interaction.commandName);
|
|
15
|
-
const args = new Map();
|
|
16
|
-
commandInstance.args.forEach((arg) => {
|
|
17
|
-
const option = interaction.options.get(arg.name);
|
|
18
|
-
if (option) {
|
|
19
|
-
switch (arg.type) {
|
|
20
|
-
case 'user':
|
|
21
|
-
args.set(arg.name, option.user);
|
|
22
|
-
break;
|
|
23
|
-
case 'member':
|
|
24
|
-
args.set(arg.name, option.member);
|
|
25
|
-
break;
|
|
26
|
-
default:
|
|
27
|
-
args.set(arg.name, option.value ||
|
|
28
|
-
option.user ||
|
|
29
|
-
option.role ||
|
|
30
|
-
option.channel ||
|
|
31
|
-
option.options ||
|
|
32
|
-
option.message ||
|
|
33
|
-
option.member ||
|
|
34
|
-
option.focused ||
|
|
35
|
-
option.autocomplete ||
|
|
36
|
-
option.attachment);
|
|
37
|
-
break;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
if (![CommandType.any, CommandType.separated, CommandType.slash,].includes(commandInstance.type))
|
|
42
|
-
return;
|
|
43
|
-
const trans = this.getTransMethod(commandInstance, framework, guildSettings);
|
|
44
|
-
if (commandInstance.type === CommandType.separated ||
|
|
45
|
-
commandInstance.type === CommandType.slash) {
|
|
46
|
-
await commandInstance.executeSlashCommand({
|
|
47
|
-
client, interaction, args, framework, guildSettings, trans,
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
await commandInstance.execute({
|
|
52
|
-
client, interaction, args, framework, guildSettings, trans,
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
else if (interaction.isButton()) {
|
|
57
|
-
interaction = interaction;
|
|
58
|
-
const path = interaction.customId.split('.');
|
|
59
|
-
const commandInstance = framework.commands.get(path[0]);
|
|
60
|
-
if (!commandInstance)
|
|
61
|
-
throw new Error(`Command ${path[0]} not found or button id bad formatted`);
|
|
62
|
-
// If the command has impements ButtonPress class then execute the method
|
|
63
|
-
if (commandInstance.constructor.prototype.hasOwnProperty('buttonPressed')) {
|
|
64
|
-
commandInstance.buttonPressed({
|
|
65
|
-
path,
|
|
66
|
-
interaction,
|
|
67
|
-
client,
|
|
68
|
-
framework,
|
|
69
|
-
guildSettings,
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
else if (interaction.isStringSelectMenu()) {
|
|
74
|
-
const path = interaction.customId.split('.');
|
|
75
|
-
const commandInstance = framework.commands.get(path[0]);
|
|
76
|
-
if (!commandInstance)
|
|
77
|
-
throw new Error(`Command ${path[0]} not found or select menu id bad formatted`);
|
|
78
|
-
const trans = (key, params) => {
|
|
79
|
-
if (key.startsWith('$')) {
|
|
80
|
-
return framework.translations.get(key.replace('$', ''), guildSettings.lang, params);
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
return framework.translations.get('command.' + commandInstance.name + '.' + key, guildSettings.lang, params);
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
if (commandInstance.selectMenu) {
|
|
87
|
-
commandInstance.selectMenu({
|
|
88
|
-
path,
|
|
89
|
-
interaction,
|
|
90
|
-
client,
|
|
91
|
-
framework,
|
|
92
|
-
guildSettings,
|
|
93
|
-
trans,
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
else if (interaction.isModalSubmit()) {
|
|
98
|
-
const path = interaction.customId.split('.');
|
|
99
|
-
const commandInstance = framework.commands.get(path[0]);
|
|
100
|
-
if (!commandInstance) {
|
|
101
|
-
throw new Error(`Command ${path[0]} not found or modal id bad formatted`);
|
|
102
|
-
}
|
|
103
|
-
if (commandInstance.modalSubmit) {
|
|
104
|
-
commandInstance.modalSubmit({
|
|
105
|
-
path,
|
|
106
|
-
interaction,
|
|
107
|
-
client,
|
|
108
|
-
framework,
|
|
109
|
-
guildSettings,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
framework.eventManager.emitEvent('modalSubmit', 'framework', {
|
|
114
|
-
path, interaction, client, framework, guildSettings,
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
}
|
|
7
|
+
interactionHandler;
|
|
8
|
+
constructor() {
|
|
9
|
+
super();
|
|
10
|
+
this.interactionHandler = ServiceContainer.getService(InteractionHandler);
|
|
118
11
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (key.startsWith('$')) {
|
|
122
|
-
return framework.translations.get(key.replace('$', ''), guildSettings.lang, params);
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
return framework.translations.get('command.' + commandInstance.name + '.' + key, guildSettings.lang, params);
|
|
126
|
-
}
|
|
127
|
-
};
|
|
12
|
+
async execute({ interaction, }) {
|
|
13
|
+
await this.interactionHandler.handleInteraction(interaction);
|
|
128
14
|
}
|
|
129
15
|
}
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { ActionRowBuilder, EmbedBuilder } from 'discord.js';
|
|
2
2
|
import { EventParameters } from '../../../../../definitions/parameters/EventParameters.js';
|
|
3
3
|
import { FrameworkEvent } from '../../../../../definitions/FrameworkEvent.js';
|
|
4
|
+
import { MemberPermissionChecker } from '../../../../../services/MemberPermissionChecker.js';
|
|
5
|
+
import { ZumitoFramework } from '../../../../../ZumitoFramework.js';
|
|
6
|
+
import { GuildDataGetter } from '../../../../../services/GuildDataGetter.js';
|
|
4
7
|
export declare class MessageCreate extends FrameworkEvent {
|
|
5
8
|
once: boolean;
|
|
6
9
|
source: string;
|
|
10
|
+
memberPermissionChecker: MemberPermissionChecker;
|
|
11
|
+
framework: ZumitoFramework;
|
|
12
|
+
guildDataGetter: GuildDataGetter;
|
|
13
|
+
constructor();
|
|
7
14
|
execute({ message, framework }: EventParameters): Promise<import("discord.js").Message<boolean>>;
|
|
8
15
|
autocorrect(str: string, words: string[]): any;
|
|
9
16
|
getErrorEmbed(error: any, parse: any): {
|
|
@@ -1,20 +1,33 @@
|
|
|
1
1
|
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ChannelType, EmbedBuilder, PermissionsBitField, } from 'discord.js';
|
|
2
2
|
import ErrorStackParser from 'error-stack-parser';
|
|
3
3
|
import { FrameworkEvent } from '../../../../../definitions/FrameworkEvent.js';
|
|
4
|
-
import { ZumitoFramework } from '../../../../../ZumitoFramework.js';
|
|
5
4
|
import leven from 'leven';
|
|
6
5
|
import path from 'path';
|
|
7
|
-
import {
|
|
6
|
+
import { ServiceContainer } from '../../../../../services/ServiceContainer.js';
|
|
7
|
+
import { CommandParser } from '../../../../../services/CommandParser.js';
|
|
8
|
+
import { MemberPermissionChecker } from '../../../../../services/MemberPermissionChecker.js';
|
|
9
|
+
import { ZumitoFramework } from '../../../../../ZumitoFramework.js';
|
|
10
|
+
import { GuildDataGetter } from '../../../../../services/GuildDataGetter.js';
|
|
8
11
|
export class MessageCreate extends FrameworkEvent {
|
|
9
12
|
once = false;
|
|
10
13
|
source = 'discord';
|
|
14
|
+
memberPermissionChecker;
|
|
15
|
+
framework;
|
|
16
|
+
guildDataGetter;
|
|
17
|
+
constructor() {
|
|
18
|
+
super();
|
|
19
|
+
this.memberPermissionChecker = ServiceContainer.getService(MemberPermissionChecker);
|
|
20
|
+
this.framework = ServiceContainer.getService(ZumitoFramework);
|
|
21
|
+
this.guildDataGetter = ServiceContainer.getService(GuildDataGetter);
|
|
22
|
+
}
|
|
11
23
|
async execute({ message, framework }) {
|
|
12
24
|
const channel = message.channel;
|
|
13
25
|
const prefix = framework.settings.defaultPrefix;
|
|
14
|
-
const args =
|
|
26
|
+
const args = CommandParser.splitCommandLine(message.content.slice(prefix.length));
|
|
15
27
|
const command = args.shift().toLowerCase();
|
|
16
28
|
let commandInstance;
|
|
17
29
|
if (message.content.startsWith(prefix)) {
|
|
30
|
+
debugger;
|
|
18
31
|
if (!framework.commands.getAll().has(command)) {
|
|
19
32
|
const commandNames = Array.from(framework.commands.getAll().keys());
|
|
20
33
|
const correctedCommand = this.autocorrect(command, commandNames);
|
|
@@ -26,18 +39,24 @@ export class MessageCreate extends FrameworkEvent {
|
|
|
26
39
|
}
|
|
27
40
|
}
|
|
28
41
|
else {
|
|
29
|
-
|
|
42
|
+
const tmpCmd = framework.commands.get(command);
|
|
43
|
+
if (tmpCmd && !tmpCmd.parent) {
|
|
44
|
+
commandInstance = tmpCmd;
|
|
45
|
+
}
|
|
30
46
|
}
|
|
47
|
+
commandInstance = Array.from(this.framework.commands.getAll().values()).find((c) => c.name == args.at(0) && c.parent && c.parent == command) || commandInstance;
|
|
48
|
+
if (!commandInstance)
|
|
49
|
+
return;
|
|
31
50
|
if (message.guild == null && commandInstance.dm == false)
|
|
32
51
|
return;
|
|
33
52
|
if (commandInstance.adminOnly ||
|
|
34
53
|
commandInstance.userPermissions.length > 0) {
|
|
35
54
|
let denied = false;
|
|
36
|
-
if (
|
|
55
|
+
if (this.memberPermissionChecker.hasPermissionOnChannel(message.member, message.channel, PermissionsBitField.Flags.Administrator) ||
|
|
37
56
|
message.member.id != message.guild.ownerId) {
|
|
38
57
|
if (commandInstance.userPermissions.length > 0) {
|
|
39
58
|
commandInstance.userPermissions.forEach((permission) => {
|
|
40
|
-
if (!
|
|
59
|
+
if (!this.memberPermissionChecker.hasPermissionOnChannel(message.member, message.channel, permission)) {
|
|
41
60
|
denied = true;
|
|
42
61
|
}
|
|
43
62
|
});
|
|
@@ -70,37 +89,17 @@ export class MessageCreate extends FrameworkEvent {
|
|
|
70
89
|
}
|
|
71
90
|
}
|
|
72
91
|
try {
|
|
73
|
-
const guildSettings = await
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (type == 'user') {
|
|
83
|
-
parsedArgs.set(commandInstance.args[i].name, member.user);
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
parsedArgs.set(commandInstance.args[i].name, member);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
return message.reply({
|
|
91
|
-
content: 'Invalid user.',
|
|
92
|
-
allowedMentions: {
|
|
93
|
-
repliedUser: false,
|
|
94
|
-
},
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
else if (type == 'string') {
|
|
99
|
-
parsedArgs.set(commandInstance.args?.[i]?.name || i.toString(), arg);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
92
|
+
const guildSettings = await this.guildDataGetter.getGuildSettings(message.guildId);
|
|
93
|
+
const parsedArgsResponse = await CommandParser.parseFromSplitedString(args, commandInstance.args, message.guild);
|
|
94
|
+
if (parsedArgsResponse.errors.length > 0) {
|
|
95
|
+
return message.reply({
|
|
96
|
+
content: parsedArgsResponse.errors.at(0),
|
|
97
|
+
allowedMentions: {
|
|
98
|
+
repliedUser: false,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
102
101
|
}
|
|
103
|
-
const
|
|
102
|
+
const parsedArgs = parsedArgsResponse.parsedArgs;
|
|
104
103
|
await commandInstance.execute({
|
|
105
104
|
message,
|
|
106
105
|
args: parsedArgs,
|
|
@@ -40,6 +40,7 @@ export class CommandManager {
|
|
|
40
40
|
* @returns {Promise<Command>}
|
|
41
41
|
*/
|
|
42
42
|
async loadCommandFile(filePath) {
|
|
43
|
+
let loaded = false;
|
|
43
44
|
// Validate file has .ts or .js extension
|
|
44
45
|
if (!filePath.endsWith('.js') && !filePath.endsWith('.ts')) {
|
|
45
46
|
throw new Error("File must be a .ts or .js");
|
|
@@ -49,9 +50,14 @@ export class CommandManager {
|
|
|
49
50
|
console.error('[🆕🔴 ] Error loading command ' + chalk.blue(filePath.toString().replace(/^.*[\\\/]/, '').split('.').slice(0, -1).join('.')));
|
|
50
51
|
console.log(e + '\n' + e.name + '\n' + e.stack);
|
|
51
52
|
});
|
|
53
|
+
if (!command)
|
|
54
|
+
return;
|
|
52
55
|
command = Object.values(command)[0];
|
|
53
56
|
try {
|
|
54
57
|
command = new command();
|
|
58
|
+
this.framework.commands.set(command.constructor.name.toLowerCase(), command);
|
|
59
|
+
console.debug('[🆕🟢 ] Command ' + chalk.blue(filePath.toString().replace(/^.*[\\\/]/, '').split('.').slice(0, -1).join('.')) + ' loaded');
|
|
60
|
+
loaded = true;
|
|
55
61
|
}
|
|
56
62
|
catch (error) {
|
|
57
63
|
this.errorHandler.handleError(error, {
|
|
@@ -59,9 +65,8 @@ export class CommandManager {
|
|
|
59
65
|
command: command,
|
|
60
66
|
});
|
|
61
67
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return command;
|
|
68
|
+
if (loaded)
|
|
69
|
+
return command;
|
|
65
70
|
}
|
|
66
71
|
/**
|
|
67
72
|
* Load all command files from a folder
|
|
@@ -77,12 +82,14 @@ export class CommandManager {
|
|
|
77
82
|
continue;
|
|
78
83
|
if (file.endsWith('.js') || file.endsWith('.ts')) {
|
|
79
84
|
const command = await this.loadCommandFile(path.join(folderPath, file));
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
if (command) {
|
|
86
|
+
const commandName = command.constructor.name.toLowerCase();
|
|
87
|
+
if (options?.blacklist && options.blacklist.includes(commandName))
|
|
88
|
+
continue;
|
|
89
|
+
if (options?.whitelist && !options.whitelist.includes(commandName))
|
|
90
|
+
continue;
|
|
91
|
+
this.commands.set(options?.renames?.[commandName] || commandName, command);
|
|
92
|
+
}
|
|
86
93
|
}
|
|
87
94
|
}
|
|
88
95
|
return this.commands;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Guild } from "discord.js";
|
|
2
|
+
import { CommandArgDefinition } from "../definitions/commands/CommandArgDefinition";
|
|
1
3
|
export declare class CommandParser {
|
|
2
4
|
/**
|
|
3
5
|
* From a command-line string, returns an array of parameters.
|
|
@@ -13,4 +15,9 @@ export declare class CommandParser {
|
|
|
13
15
|
* splitCommandLine('a "b c"');
|
|
14
16
|
*/
|
|
15
17
|
static splitCommandLine(commandLine: any): any;
|
|
18
|
+
static parseFromSplitedString(args: any, argDefinitions: CommandArgDefinition[], guild: Guild): Promise<{
|
|
19
|
+
validated: boolean;
|
|
20
|
+
errors: any[];
|
|
21
|
+
parsedArgs: Map<string, any>;
|
|
22
|
+
}>;
|
|
16
23
|
}
|
|
@@ -36,4 +36,36 @@ export class CommandParser {
|
|
|
36
36
|
});
|
|
37
37
|
return paramArray;
|
|
38
38
|
}
|
|
39
|
+
static async parseFromSplitedString(args, argDefinitions, guild) {
|
|
40
|
+
const parsedArgs = new Map();
|
|
41
|
+
const errors = [];
|
|
42
|
+
for (let i = 0; i < args.length; i++) {
|
|
43
|
+
const arg = args[i];
|
|
44
|
+
const type = argDefinitions[i]?.type;
|
|
45
|
+
if (type) {
|
|
46
|
+
if (type == 'member' || type == 'user') {
|
|
47
|
+
const member = await guild.members.cache.get(arg.replace(/[<@!>]/g, ''));
|
|
48
|
+
if (member) {
|
|
49
|
+
if (type == 'user') {
|
|
50
|
+
parsedArgs.set(argDefinitions[i].name, member.user);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
parsedArgs.set(argDefinitions[i].name, member);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
errors.push('Invalid user.');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else if (type == 'string') {
|
|
61
|
+
parsedArgs.set(argDefinitions[i]?.name || i.toString(), arg);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
validated: errors.length == 0,
|
|
67
|
+
errors,
|
|
68
|
+
parsedArgs,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
39
71
|
}
|
|
@@ -12,8 +12,9 @@ declare type CommandErrorOptions = BaseErrorOptions & {
|
|
|
12
12
|
export declare class ErrorHandler {
|
|
13
13
|
framework: ZumitoFramework;
|
|
14
14
|
constructor(framework: ZumitoFramework);
|
|
15
|
-
handleError(error:
|
|
15
|
+
handleError(error: any, options: BaseErrorOptions | CommandErrorOptions): void;
|
|
16
16
|
handleCommandError(error: Error, options: CommandErrorOptions): void;
|
|
17
|
+
handleShapeShiftErrors(error: any): void;
|
|
17
18
|
printErrorStack(error: Error): void;
|
|
18
19
|
}
|
|
19
20
|
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import ErrorStackParser from "error-stack-parser";
|
|
2
2
|
import { ErrorType } from "../definitions/ErrorType";
|
|
3
3
|
import chalk from "chalk";
|
|
4
|
+
import sf from 'source-fragment';
|
|
4
5
|
export class ErrorHandler {
|
|
5
6
|
framework;
|
|
6
7
|
constructor(framework) {
|
|
@@ -10,8 +11,20 @@ export class ErrorHandler {
|
|
|
10
11
|
if (options?.type == ErrorType.CommandInstance || options?.type == ErrorType.CommandLoad || options?.type == ErrorType.CommandRun) {
|
|
11
12
|
this.handleCommandError(error, options);
|
|
12
13
|
}
|
|
14
|
+
else if (error.constructor.name == 'CombinedError') {
|
|
15
|
+
this.handleShapeShiftErrors(error);
|
|
16
|
+
}
|
|
17
|
+
else if (error.constructor?.name == "ExpectedValidationError") {
|
|
18
|
+
console.error(`Validation error: Expected ${error.expected}, but received ${error.given}.`);
|
|
19
|
+
console.line('');
|
|
20
|
+
}
|
|
21
|
+
else if (error.constructor.name == "ValidationError") {
|
|
22
|
+
console.error(`Validation error: ${error.validator} received invalid input: ${error.given}`);
|
|
23
|
+
console.line('');
|
|
24
|
+
}
|
|
13
25
|
else {
|
|
14
26
|
console.error(error.toString());
|
|
27
|
+
console.line('');
|
|
15
28
|
}
|
|
16
29
|
this.printErrorStack(error);
|
|
17
30
|
if (options.exit)
|
|
@@ -20,7 +33,7 @@ export class ErrorHandler {
|
|
|
20
33
|
handleCommandError(error, options) {
|
|
21
34
|
switch (options.type) {
|
|
22
35
|
case ErrorType.CommandInstance:
|
|
23
|
-
console.group(`[❌] Error instanciating command ${options
|
|
36
|
+
console.group(`[❌] Error instanciating command ${options?.command?.name}`);
|
|
24
37
|
break;
|
|
25
38
|
case ErrorType.CommandLoad:
|
|
26
39
|
console.group(`[❌] Error loading command ${options.command.name}`);
|
|
@@ -29,21 +42,70 @@ export class ErrorHandler {
|
|
|
29
42
|
console.group(`[❌] Error running command ${options.command.name}`);
|
|
30
43
|
break;
|
|
31
44
|
}
|
|
32
|
-
|
|
33
|
-
|
|
45
|
+
if (error.constructor.name == 'CombinedError') {
|
|
46
|
+
console.groupEnd();
|
|
47
|
+
this.handleShapeShiftErrors(error);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
console.line(chalk.red('Error:'));
|
|
51
|
+
console.line(error.toString());
|
|
52
|
+
console.line('');
|
|
53
|
+
console.groupEnd();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
handleShapeShiftErrors(error) {
|
|
57
|
+
if (error.constructor.name == 'CombinedError') {
|
|
58
|
+
error.errors.forEach(err => {
|
|
59
|
+
this.handleError(err, {
|
|
60
|
+
type: ErrorType.Other
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
34
64
|
}
|
|
35
65
|
printErrorStack(error) {
|
|
36
66
|
const stackParsedError = ErrorStackParser.parse(error);
|
|
37
67
|
let functionColor = 'blue';
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
68
|
+
const lines = [];
|
|
69
|
+
let codeFragment;
|
|
70
|
+
let lastStack;
|
|
71
|
+
for (const stack of stackParsedError) {
|
|
72
|
+
const filePath = stack.getFileName().replace(process.cwd(), '.').replace('file://', '');
|
|
73
|
+
const functionName = stack.getFunctionName();
|
|
41
74
|
if (functionName == 'CommandManager.loadCommandFile') {
|
|
42
75
|
functionColor = 'yellow';
|
|
43
76
|
}
|
|
44
|
-
|
|
77
|
+
lines.push(` at ${chalk.gray(filePath)}:${stack.getLineNumber()}:${stack.getColumnNumber()} ${chalk[functionColor](functionName)}`);
|
|
45
78
|
if (functionName == 'CommandManager.loadCommandFile' && !this.framework.settings.debug)
|
|
46
79
|
break;
|
|
80
|
+
if (!codeFragment && functionName.includes('.execute')) {
|
|
81
|
+
let columnEnd = -1;
|
|
82
|
+
if (lastStack) {
|
|
83
|
+
if (lastStack.getFunctionName().contains('.')) {
|
|
84
|
+
columnEnd = lastStack.getFunctionName().split('.').at(-1).length;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
columnEnd = lastStack.getFunctionName().length;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
codeFragment = {
|
|
91
|
+
path: `${filePath}:${stack.getLineNumber()}:${stack.getColumnNumber()}`,
|
|
92
|
+
code: sf(`${filePath}:${stack.getLineNumber()}:${stack.getColumnNumber()}:${stack.getLineNumber()}:${stack.getColumnNumber() + columnEnd}`, {
|
|
93
|
+
format: 'tty',
|
|
94
|
+
linesBefore: 2,
|
|
95
|
+
linesAfter: 2,
|
|
96
|
+
})
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
lastStack = stack;
|
|
100
|
+
}
|
|
101
|
+
// Log code fragment
|
|
102
|
+
if (codeFragment) {
|
|
103
|
+
console.line(chalk.blue('File: ') + `${codeFragment.path}`);
|
|
104
|
+
console.line(codeFragment.code);
|
|
105
|
+
console.line('');
|
|
47
106
|
}
|
|
107
|
+
// Log stack
|
|
108
|
+
console.line(chalk.blue('StackTrace:'));
|
|
109
|
+
lines.forEach(line => console.line(line));
|
|
48
110
|
}
|
|
49
111
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ButtonInteraction, Client, CommandInteraction, Interaction, ModalSubmitInteraction, StringSelectMenuInteraction } from "discord.js";
|
|
2
|
+
import { CommandManager } from "./CommandManager";
|
|
3
|
+
import { GuildDataGetter } from "./GuildDataGetter";
|
|
4
|
+
import { TranslationManager } from "./TranslationManager";
|
|
5
|
+
import { EventManager } from "./EventManager";
|
|
6
|
+
import { InteractionHandlerSettings } from "@definitions/settings/InteractionHandlerSettings";
|
|
7
|
+
import { ErrorHandler } from "./ErrorHandler";
|
|
8
|
+
export declare class InteractionHandler {
|
|
9
|
+
protected commandManager: CommandManager;
|
|
10
|
+
protected guildDataGetter: GuildDataGetter;
|
|
11
|
+
protected client: Client;
|
|
12
|
+
protected translationManager: TranslationManager;
|
|
13
|
+
protected eventManager: EventManager;
|
|
14
|
+
protected errorHandler: ErrorHandler;
|
|
15
|
+
constructor();
|
|
16
|
+
handleInteraction(interaction: Interaction, params?: InteractionHandlerSettings): Promise<void>;
|
|
17
|
+
handleCommandInteraction(interaction: CommandInteraction, guildSettings?: any): Promise<void>;
|
|
18
|
+
handleButtonInteraction(interaction: ButtonInteraction, guildSettings?: any): Promise<void>;
|
|
19
|
+
handleSelectMenu(interaction: StringSelectMenuInteraction, guildSettings?: any): Promise<void>;
|
|
20
|
+
handleModalInteraction(interaction: ModalSubmitInteraction, guildSettings?: any): Promise<void>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { Client } from "discord.js";
|
|
2
|
+
import { CommandManager } from "./CommandManager";
|
|
3
|
+
import { GuildDataGetter } from "./GuildDataGetter";
|
|
4
|
+
import { ServiceContainer } from "./ServiceContainer";
|
|
5
|
+
import { CommandType } from "../definitions/commands/CommandType";
|
|
6
|
+
import { ZumitoFramework } from "../ZumitoFramework";
|
|
7
|
+
import { TranslationManager } from "./TranslationManager";
|
|
8
|
+
import { EventManager } from "./EventManager";
|
|
9
|
+
import { ErrorHandler } from "./ErrorHandler";
|
|
10
|
+
import { ErrorType } from "../definitions/ErrorType";
|
|
11
|
+
export class InteractionHandler {
|
|
12
|
+
commandManager;
|
|
13
|
+
guildDataGetter;
|
|
14
|
+
client;
|
|
15
|
+
translationManager;
|
|
16
|
+
eventManager;
|
|
17
|
+
errorHandler;
|
|
18
|
+
constructor() {
|
|
19
|
+
this.commandManager = ServiceContainer.getService(CommandManager);
|
|
20
|
+
this.guildDataGetter = ServiceContainer.getService(GuildDataGetter);
|
|
21
|
+
this.client = ServiceContainer.getService(Client);
|
|
22
|
+
this.translationManager = ServiceContainer.getService(TranslationManager);
|
|
23
|
+
this.eventManager = ServiceContainer.getService(EventManager);
|
|
24
|
+
this.errorHandler = ServiceContainer.getService(ErrorHandler);
|
|
25
|
+
}
|
|
26
|
+
async handleInteraction(interaction, params) {
|
|
27
|
+
if (interaction.isCommand()) {
|
|
28
|
+
if (params?.disabledHandlers?.includes("command"))
|
|
29
|
+
return;
|
|
30
|
+
await this.handleCommandInteraction(interaction);
|
|
31
|
+
}
|
|
32
|
+
else if (interaction.isButton()) {
|
|
33
|
+
if (params?.disabledHandlers?.includes("button"))
|
|
34
|
+
return;
|
|
35
|
+
await this.handleButtonInteraction(interaction);
|
|
36
|
+
}
|
|
37
|
+
else if (interaction.isStringSelectMenu()) {
|
|
38
|
+
if (params?.disabledHandlers?.includes("selectMenu"))
|
|
39
|
+
return;
|
|
40
|
+
await this.handleSelectMenu(interaction);
|
|
41
|
+
}
|
|
42
|
+
else if (interaction.isModalSubmit()) {
|
|
43
|
+
if (params?.disabledHandlers?.includes("modal"))
|
|
44
|
+
return;
|
|
45
|
+
await this.handleModalInteraction(interaction);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async handleCommandInteraction(interaction, guildSettings) {
|
|
49
|
+
const subcommandName = interaction.options.getSubcommand(false);
|
|
50
|
+
const commandName = interaction.commandName;
|
|
51
|
+
let commandInstance;
|
|
52
|
+
if (subcommandName) {
|
|
53
|
+
commandInstance = Array.from(this.commandManager.getAll().values()).find(c => c.name == subcommandName && c.parent == commandName);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
commandInstance = this.commandManager.get(commandName);
|
|
57
|
+
}
|
|
58
|
+
if (!commandInstance)
|
|
59
|
+
return;
|
|
60
|
+
const framework = ServiceContainer.getService(ZumitoFramework);
|
|
61
|
+
const args = new Map();
|
|
62
|
+
commandInstance.args.forEach((arg) => {
|
|
63
|
+
const option = (interaction).options.get(arg.name);
|
|
64
|
+
if (option) {
|
|
65
|
+
switch (arg.type) {
|
|
66
|
+
case 'user':
|
|
67
|
+
args.set(arg.name, option.user);
|
|
68
|
+
break;
|
|
69
|
+
case 'member':
|
|
70
|
+
args.set(arg.name, option.member);
|
|
71
|
+
break;
|
|
72
|
+
default:
|
|
73
|
+
args.set(arg.name, option.value ||
|
|
74
|
+
option.user ||
|
|
75
|
+
option.role ||
|
|
76
|
+
option.channel ||
|
|
77
|
+
option.options ||
|
|
78
|
+
option.message ||
|
|
79
|
+
option.member ||
|
|
80
|
+
option.focused ||
|
|
81
|
+
option.autocomplete ||
|
|
82
|
+
option.attachment);
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
if (![CommandType.any, CommandType.separated, CommandType.slash,].includes(commandInstance.type))
|
|
88
|
+
return;
|
|
89
|
+
if (!guildSettings && interaction.guildId) {
|
|
90
|
+
guildSettings = await ServiceContainer.getService(GuildDataGetter).getGuildSettings(interaction.guildId);
|
|
91
|
+
}
|
|
92
|
+
const trans = this.translationManager.getShortHandMethod('command.' + commandInstance.name, guildSettings?.lang);
|
|
93
|
+
if (commandInstance.type === CommandType.separated ||
|
|
94
|
+
commandInstance.type === CommandType.slash) {
|
|
95
|
+
await commandInstance.executeSlashCommand({
|
|
96
|
+
client: this.client,
|
|
97
|
+
interaction, args, framework, guildSettings, trans,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
try {
|
|
102
|
+
await commandInstance.execute({
|
|
103
|
+
client: this.client,
|
|
104
|
+
interaction, args, framework, guildSettings, trans,
|
|
105
|
+
}).catch((error) => {
|
|
106
|
+
this.errorHandler.handleError(error, {
|
|
107
|
+
command: commandInstance,
|
|
108
|
+
type: ErrorType.CommandRun,
|
|
109
|
+
});
|
|
110
|
+
interaction.reply({
|
|
111
|
+
content: "An error ocurred while running this command.",
|
|
112
|
+
ephemeral: true
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
this.errorHandler.handleError(error, {
|
|
118
|
+
command: commandInstance,
|
|
119
|
+
type: ErrorType.CommandRun,
|
|
120
|
+
});
|
|
121
|
+
interaction.reply({
|
|
122
|
+
content: "An error ocurred while running this command.",
|
|
123
|
+
ephemeral: true,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async handleButtonInteraction(interaction, guildSettings) {
|
|
129
|
+
const framework = ServiceContainer.getService(ZumitoFramework);
|
|
130
|
+
const path = interaction.customId.split('.');
|
|
131
|
+
const commandInstance = this.commandManager.get(path[0]);
|
|
132
|
+
if (!commandInstance)
|
|
133
|
+
throw new Error(`Command ${path[0]} not found or button id bad formatted`);
|
|
134
|
+
if (!guildSettings && interaction.guildId) {
|
|
135
|
+
guildSettings = await ServiceContainer.getService(GuildDataGetter).getGuildSettings(interaction.guildId);
|
|
136
|
+
}
|
|
137
|
+
// If the command has impements ButtonPress class then execute the method
|
|
138
|
+
if (commandInstance.constructor.prototype.hasOwnProperty('buttonPressed')) {
|
|
139
|
+
commandInstance.buttonPressed({
|
|
140
|
+
client: this.client,
|
|
141
|
+
path,
|
|
142
|
+
interaction,
|
|
143
|
+
framework,
|
|
144
|
+
guildSettings,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async handleSelectMenu(interaction, guildSettings) {
|
|
149
|
+
const path = interaction.customId.split('.');
|
|
150
|
+
const commandInstance = this.commandManager.get(path[0]);
|
|
151
|
+
if (!commandInstance)
|
|
152
|
+
throw new Error(`Command ${path[0]} not found or select menu id bad formatted`);
|
|
153
|
+
if (!guildSettings && interaction.guildId) {
|
|
154
|
+
guildSettings = await ServiceContainer.getService(GuildDataGetter).getGuildSettings(interaction.guildId);
|
|
155
|
+
}
|
|
156
|
+
const trans = this.translationManager.getShortHandMethod('command.' + commandInstance.name, guildSettings?.lang);
|
|
157
|
+
const framework = ServiceContainer.getService(ZumitoFramework);
|
|
158
|
+
if (commandInstance.binds?.selectMenu) {
|
|
159
|
+
commandInstance.binds?.selectMenu({
|
|
160
|
+
path,
|
|
161
|
+
interaction,
|
|
162
|
+
client: this.client,
|
|
163
|
+
framework,
|
|
164
|
+
guildSettings,
|
|
165
|
+
trans,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
else if ( // Deprecated
|
|
169
|
+
commandInstance.constructor.prototype.hasOwnProperty('selectMenu')) {
|
|
170
|
+
commandInstance.selectMenu({
|
|
171
|
+
path,
|
|
172
|
+
interaction,
|
|
173
|
+
client: this.client,
|
|
174
|
+
framework,
|
|
175
|
+
guildSettings,
|
|
176
|
+
trans,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async handleModalInteraction(interaction, guildSettings) {
|
|
181
|
+
const path = interaction.customId.split('.');
|
|
182
|
+
const commandInstance = this.commandManager.get(path[0]);
|
|
183
|
+
if (!commandInstance) {
|
|
184
|
+
throw new Error(`Command ${path[0]} not found or modal id bad formatted`);
|
|
185
|
+
}
|
|
186
|
+
const framework = ServiceContainer.getService(ZumitoFramework);
|
|
187
|
+
if (commandInstance.modalSubmit) {
|
|
188
|
+
if (!guildSettings && interaction.guildId) {
|
|
189
|
+
guildSettings = await ServiceContainer.getService(GuildDataGetter).getGuildSettings(interaction.guildId);
|
|
190
|
+
}
|
|
191
|
+
commandInstance.modalSubmit({
|
|
192
|
+
client: this.client,
|
|
193
|
+
path,
|
|
194
|
+
interaction,
|
|
195
|
+
framework,
|
|
196
|
+
guildSettings,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
this.eventManager.emitEvent('modalSubmit', 'framework', {
|
|
201
|
+
client: this.client,
|
|
202
|
+
path, interaction, framework, guildSettings,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
@@ -1 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
declare class ServiceContainerManager {
|
|
2
|
+
private services;
|
|
3
|
+
addService(serviceClass: any, dependencies: string[], singleton?: boolean, instance?: any): void;
|
|
4
|
+
getService<T>(serviceClass: new (...args: any[]) => T | string): T;
|
|
5
|
+
getServiceByName<T>(serviceName: string): T;
|
|
6
|
+
addInstance(serviceClass: any, instance: any): void;
|
|
7
|
+
}
|
|
8
|
+
export declare const ServiceContainer: ServiceContainerManager;
|
|
9
|
+
export {};
|
|
@@ -9,13 +9,25 @@ class ServiceContainerManager {
|
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
11
|
getService(serviceClass) {
|
|
12
|
-
const serviceName = typeof serviceClass
|
|
12
|
+
const serviceName = typeof serviceClass === 'string' ? serviceClass : serviceClass.name;
|
|
13
|
+
const service = this.services.get(serviceName);
|
|
14
|
+
if (!service)
|
|
15
|
+
throw new Error(`Service ${serviceName} not found`);
|
|
16
|
+
if (service.singleton && service.instance)
|
|
17
|
+
return service.instance;
|
|
18
|
+
const dependencies = service.dependencies.map(dependency => this.getServiceByName(dependency));
|
|
19
|
+
const instance = new service.class(...dependencies);
|
|
20
|
+
if (service.singleton)
|
|
21
|
+
service.instance = instance;
|
|
22
|
+
return instance;
|
|
23
|
+
}
|
|
24
|
+
getServiceByName(serviceName) {
|
|
13
25
|
const service = this.services.get(serviceName);
|
|
14
26
|
if (!service)
|
|
15
27
|
throw new Error(`Service ${serviceName} not found`);
|
|
16
28
|
if (service.singleton && service.instance)
|
|
17
29
|
return service.instance;
|
|
18
|
-
const dependencies = service.dependencies.map(dependency => this.
|
|
30
|
+
const dependencies = service.dependencies.map(dependency => this.getServiceByName(dependency));
|
|
19
31
|
const instance = new service.class(...dependencies);
|
|
20
32
|
if (service.singleton)
|
|
21
33
|
service.instance = instance;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { ZumitoFramework } from "../ZumitoFramework";
|
|
2
|
+
import { Command } from "../definitions/commands/Command";
|
|
3
|
+
import { SlashCommandSubcommandBuilder } from "discord.js";
|
|
2
4
|
export declare class SlashCommandRefresher {
|
|
3
|
-
framework: ZumitoFramework;
|
|
5
|
+
protected framework: ZumitoFramework;
|
|
4
6
|
constructor(framework: ZumitoFramework);
|
|
5
7
|
refreshSlashCommands(): Promise<void>;
|
|
8
|
+
mapCommand(command: Command, commandBuilder?: SlashCommandSubcommandBuilder): import("discord.js").RESTPostAPIChatInputApplicationCommandsJSONBody | import("discord.js").APIApplicationCommandSubcommandOption;
|
|
6
9
|
}
|
|
@@ -13,61 +13,78 @@ export class SlashCommandRefresher {
|
|
|
13
13
|
async refreshSlashCommands() {
|
|
14
14
|
const rest = new REST({ version: '10' }).setToken(this.framework.settings.discordClientOptions.token);
|
|
15
15
|
const commands = Array.from(this.framework.commands.getAll().values())
|
|
16
|
-
.filter((command) => command.type == CommandType.slash ||
|
|
16
|
+
.filter((command) => (command.type == CommandType.slash ||
|
|
17
17
|
command.type == CommandType.separated ||
|
|
18
18
|
command.type == CommandType.any)
|
|
19
|
-
.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
});
|
|
19
|
+
&& !command.parent)
|
|
20
|
+
.map(command => this.mapCommand(command));
|
|
21
|
+
const data = await rest.put(Routes.applicationCommands(this.framework.settings.discordClientOptions.clientId), { body: commands });
|
|
22
|
+
console.debug(`Successfully reloaded ${data.length} of ${commands.length} application (/) commands.`);
|
|
23
|
+
}
|
|
24
|
+
mapCommand(command, commandBuilder) {
|
|
25
|
+
const slashCommand = commandBuilder || new SlashCommandBuilder();
|
|
26
|
+
slashCommand
|
|
27
|
+
.setName(command.name)
|
|
28
|
+
.setDescription(this.framework.translations.get('command.' + command.name + '.description', 'en'));
|
|
29
|
+
if (command.args) {
|
|
30
|
+
command.args.forEach((arg) => {
|
|
31
|
+
let method;
|
|
32
|
+
switch (arg.type) {
|
|
33
|
+
case 'string':
|
|
34
|
+
method = 'addStringOption';
|
|
35
|
+
break;
|
|
36
|
+
case 'user':
|
|
37
|
+
case 'member':
|
|
38
|
+
method = 'addUserOption';
|
|
39
|
+
break;
|
|
40
|
+
case 'channel':
|
|
41
|
+
method = 'addChannelOption';
|
|
42
|
+
break;
|
|
43
|
+
case 'role':
|
|
44
|
+
method = 'addRoleOption';
|
|
45
|
+
break;
|
|
46
|
+
default:
|
|
47
|
+
throw new Error('Invalid argument type ' + arg.type);
|
|
48
|
+
}
|
|
49
|
+
slashCommand[method]((option) => {
|
|
50
|
+
option.setName(arg.name);
|
|
51
|
+
option.setDescription(this.framework.translations.get('command.' +
|
|
52
|
+
command.name +
|
|
53
|
+
'.args.' +
|
|
54
|
+
arg.name +
|
|
55
|
+
'.description', 'en'));
|
|
56
|
+
option.setRequired(!arg.optional);
|
|
57
|
+
if (arg.choices) {
|
|
58
|
+
// if arg.choices is function, call it
|
|
59
|
+
if (typeof arg.choices == 'function') {
|
|
60
|
+
arg.choices =
|
|
61
|
+
arg.choices();
|
|
63
62
|
}
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
arg.choices.forEach((choice) => {
|
|
64
|
+
option.addChoices({
|
|
65
|
+
name: choice.name,
|
|
66
|
+
value: choice.value,
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return option;
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
Array.from(this.framework.commands.getAll().values())
|
|
75
|
+
.filter((subcommand) => (subcommand.type == CommandType.slash ||
|
|
76
|
+
subcommand.type == CommandType.separated ||
|
|
77
|
+
subcommand.type == CommandType.any)
|
|
78
|
+
&& subcommand.parent
|
|
79
|
+
&& subcommand.parent == command.name)
|
|
80
|
+
.forEach(subcommand => {
|
|
81
|
+
if (!commandBuilder) {
|
|
82
|
+
slashCommand.addSubcommand((subcommandSlashBuilder) => {
|
|
83
|
+
this.mapCommand(subcommand, subcommandSlashBuilder);
|
|
84
|
+
return subcommandSlashBuilder;
|
|
66
85
|
});
|
|
67
86
|
}
|
|
68
|
-
return slashCommand.toJSON();
|
|
69
87
|
});
|
|
70
|
-
|
|
71
|
-
console.debug(`Successfully reloaded ${data.length} of ${commands.length} application (/) commands.`);
|
|
88
|
+
return slashCommand.toJSON();
|
|
72
89
|
}
|
|
73
90
|
}
|
|
@@ -31,4 +31,5 @@ export declare class TranslationManager {
|
|
|
31
31
|
*/
|
|
32
32
|
registerTranslationsFromFolder(folderPath: string, baseKey?: string, watch?: boolean): Promise<void>;
|
|
33
33
|
watchTranslationFolder(folderPath: string, baseKey: string): void;
|
|
34
|
+
getShortHandMethod(keyPrefix: string, language?: string): (key: string, params?: any, lang?: string) => string;
|
|
34
35
|
}
|
|
@@ -119,4 +119,16 @@ export class TranslationManager {
|
|
|
119
119
|
// TODO: Handle file removal
|
|
120
120
|
//.on('unlink', function(path) {console.log('File', path, 'has been removed');})
|
|
121
121
|
}
|
|
122
|
+
getShortHandMethod(keyPrefix, language) {
|
|
123
|
+
return (key, params, lang) => {
|
|
124
|
+
if (key.startsWith('$')) {
|
|
125
|
+
return this.get(key.replace('$', ''), lang || language, params);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
if (!keyPrefix.endsWith('.'))
|
|
129
|
+
keyPrefix += '.';
|
|
130
|
+
return this.get(keyPrefix + key, lang || language, params);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
122
134
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zumito-framework",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.18",
|
|
4
4
|
"description": "Discord.js bot framework",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"express": "^4.18.1",
|
|
34
34
|
"leven": "^4.0.0",
|
|
35
35
|
"mongoose": "^6.6.5",
|
|
36
|
+
"source-fragment": "^1.1.0",
|
|
36
37
|
"tingodb": "^0.6.1",
|
|
37
38
|
"tseep": "^1.2.2",
|
|
38
39
|
"zumito-db": "^1.0.0"
|
|
@@ -54,6 +55,10 @@
|
|
|
54
55
|
".": "./dist/index.js",
|
|
55
56
|
"./discord": "./dist/discord/index.js"
|
|
56
57
|
},
|
|
58
|
+
"_moduleAliases": {
|
|
59
|
+
"@definitions": "definitions",
|
|
60
|
+
"@services": "services"
|
|
61
|
+
},
|
|
57
62
|
"typesVersions": {
|
|
58
63
|
"*": {
|
|
59
64
|
".": [
|