zumito-framework 1.1.33 → 1.1.35
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/TranslationManager.js +6 -1
- package/dist/ZumitoFramework.d.ts +1 -0
- package/dist/ZumitoFramework.js +28 -9
- package/dist/baseModule/events/discord/interactionCreate.js +7 -3
- package/dist/baseModule/events/discord/messageCreate.d.ts +10 -0
- package/dist/baseModule/events/discord/messageCreate.js +126 -23
- package/dist/baseModule/index.d.ts +1 -1
- package/dist/baseModule/index.js +1 -1
- package/dist/baseModule/models/errors.json +14 -0
- package/dist/baseModule/models/guild.json +23 -0
- package/dist/types/Command.d.ts +10 -10
- package/dist/types/Command.js +1 -2
- package/dist/types/CommandParameters.d.ts +1 -0
- package/dist/types/Commands.js +1 -1
- package/dist/types/Module.d.ts +2 -2
- package/dist/types/Module.js +62 -33
- package/dist/types/SelectMenuParameters.d.ts +3 -2
- package/package.json +8 -7
- package/plop-templates/command.js.hbs +10 -3
- package/plopfile.js +3 -0
|
@@ -4,7 +4,12 @@ export class TranslationManager {
|
|
|
4
4
|
defaultLanguage = 'en';
|
|
5
5
|
constructor() { }
|
|
6
6
|
get(key, language, params) {
|
|
7
|
-
|
|
7
|
+
if (this.translations.has(key)) {
|
|
8
|
+
return this.translations.get(key).get(language, params);
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
return key;
|
|
12
|
+
}
|
|
8
13
|
}
|
|
9
14
|
set(key, language, text) {
|
|
10
15
|
if (!this.translations.has(key)) {
|
|
@@ -46,4 +46,5 @@ export declare class ZumitoFramework {
|
|
|
46
46
|
private initializeDiscordClient;
|
|
47
47
|
static splitCommandLine(commandLine: any): any;
|
|
48
48
|
memberHasPermission(member: GuildMember, channel: TextChannel, permission: bigint): Promise<boolean>;
|
|
49
|
+
getGuildSettings(guildId: string): Promise<any>;
|
|
49
50
|
}
|
package/dist/ZumitoFramework.js
CHANGED
|
@@ -13,6 +13,7 @@ import mongoose from "mongoose";
|
|
|
13
13
|
import cookieParser from 'cookie-parser';
|
|
14
14
|
import cors from 'cors';
|
|
15
15
|
import http from 'http';
|
|
16
|
+
import * as url from 'url';
|
|
16
17
|
/**
|
|
17
18
|
* @class ZumitoFramework
|
|
18
19
|
* @classdesc The main class of the framework.
|
|
@@ -28,7 +29,7 @@ export class ZumitoFramework {
|
|
|
28
29
|
modules;
|
|
29
30
|
commands;
|
|
30
31
|
events;
|
|
31
|
-
translations
|
|
32
|
+
translations;
|
|
32
33
|
routes;
|
|
33
34
|
models;
|
|
34
35
|
database;
|
|
@@ -54,9 +55,12 @@ export class ZumitoFramework {
|
|
|
54
55
|
this.events = new Map();
|
|
55
56
|
this.translations = new TranslationManager();
|
|
56
57
|
this.models = new Map();
|
|
58
|
+
if (settings.logLevel) {
|
|
59
|
+
console.logLevel = settings.logLevel;
|
|
60
|
+
}
|
|
57
61
|
this.initialize().then(() => {
|
|
58
62
|
if (callback)
|
|
59
|
-
callback();
|
|
63
|
+
callback(this);
|
|
60
64
|
}).catch(err => {
|
|
61
65
|
console.error(err, err.message, err.stack, err.name);
|
|
62
66
|
});
|
|
@@ -75,7 +79,7 @@ export class ZumitoFramework {
|
|
|
75
79
|
}
|
|
76
80
|
this.initializeDiscordClient();
|
|
77
81
|
this.startApiServer();
|
|
78
|
-
this.registerModules();
|
|
82
|
+
await this.registerModules();
|
|
79
83
|
}
|
|
80
84
|
startApiServer() {
|
|
81
85
|
this.app = express();
|
|
@@ -108,7 +112,7 @@ export class ZumitoFramework {
|
|
|
108
112
|
}
|
|
109
113
|
});
|
|
110
114
|
}
|
|
111
|
-
registerModules() {
|
|
115
|
+
async registerModules() {
|
|
112
116
|
let modulesFolder;
|
|
113
117
|
if (fs.existsSync(`${process.cwd()}/modules`)) {
|
|
114
118
|
modulesFolder = `${process.cwd()}/modules`;
|
|
@@ -118,10 +122,12 @@ export class ZumitoFramework {
|
|
|
118
122
|
}
|
|
119
123
|
else
|
|
120
124
|
return;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
+
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
|
126
|
+
await this.registerModule(__dirname, 'baseModule', baseModule);
|
|
127
|
+
let files = fs.readdirSync(modulesFolder);
|
|
128
|
+
for (let file of files) {
|
|
129
|
+
await this.registerModule(modulesFolder, file);
|
|
130
|
+
}
|
|
125
131
|
this.models.forEach((modelDefiniton, modelName) => {
|
|
126
132
|
const schema = new mongoose.Schema(modelDefiniton);
|
|
127
133
|
this.models.set(modelName, mongoose.model(modelName, schema));
|
|
@@ -147,12 +153,18 @@ export class ZumitoFramework {
|
|
|
147
153
|
try {
|
|
148
154
|
moduleInstance = new module(path.join(modulesFolder, moduleName), this);
|
|
149
155
|
await moduleInstance.initialize();
|
|
150
|
-
this.modules.set(moduleInstance.constructor.name, moduleInstance);
|
|
156
|
+
this.modules.set(moduleName || moduleInstance.constructor.name, moduleInstance);
|
|
151
157
|
}
|
|
152
158
|
catch (err) {
|
|
153
159
|
console.error(`[📦🔴] Error loading module ${moduleName}: ${err.message}`);
|
|
160
|
+
console.error(err.stack);
|
|
154
161
|
}
|
|
155
162
|
// Register module commands
|
|
163
|
+
if (moduleInstance.getCommands()) {
|
|
164
|
+
moduleInstance.getCommands().forEach((command) => {
|
|
165
|
+
this.commands.set(command.name, command);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
156
168
|
this.commands = new Map([...this.commands, ...moduleInstance.getCommands()]);
|
|
157
169
|
// Register module events
|
|
158
170
|
this.events = new Map([...this.events, ...moduleInstance.getEvents()]);
|
|
@@ -210,6 +222,13 @@ export class ZumitoFramework {
|
|
|
210
222
|
let memberPermission = await channel.permissionsFor(member);
|
|
211
223
|
return memberPermission.has(permission);
|
|
212
224
|
}
|
|
225
|
+
async getGuildSettings(guildId) {
|
|
226
|
+
let guild = await this.models.get('Guild').findOne({ guild_id: guildId });
|
|
227
|
+
if (guild == null) {
|
|
228
|
+
guild = await this.models.get('Guild').create({ guild_id: guildId });
|
|
229
|
+
}
|
|
230
|
+
return guild;
|
|
231
|
+
}
|
|
213
232
|
}
|
|
214
233
|
function MergeRecursive(obj1, obj2) {
|
|
215
234
|
for (var p in obj2) {
|
|
@@ -3,6 +3,10 @@ import { FrameworkEvent } from "../../../types/FrameworkEvent.js";
|
|
|
3
3
|
export class InteractionCreate extends FrameworkEvent {
|
|
4
4
|
once = false;
|
|
5
5
|
async execute({ interaction, client, framework }) {
|
|
6
|
+
let guildSettings;
|
|
7
|
+
if (interaction.guildId) {
|
|
8
|
+
guildSettings = await framework.getGuildSettings(interaction.guildId);
|
|
9
|
+
}
|
|
6
10
|
if (interaction.isCommand()) {
|
|
7
11
|
if (!framework.commands.has(interaction.commandName))
|
|
8
12
|
return;
|
|
@@ -17,10 +21,10 @@ export class InteractionCreate extends FrameworkEvent {
|
|
|
17
21
|
if (![CommandType.any, CommandType.separated, CommandType.slash].includes(commandInstance.type))
|
|
18
22
|
return;
|
|
19
23
|
if (commandInstance.type === CommandType.separated || commandInstance.type === CommandType.slash) {
|
|
20
|
-
await commandInstance.executeSlashCommand({ client, interaction, args, framework });
|
|
24
|
+
await commandInstance.executeSlashCommand({ client, interaction, args, framework, guildSettings });
|
|
21
25
|
}
|
|
22
26
|
else {
|
|
23
|
-
await commandInstance.execute({ client, interaction, args, framework });
|
|
27
|
+
await commandInstance.execute({ client, interaction, args, framework, guildSettings });
|
|
24
28
|
}
|
|
25
29
|
}
|
|
26
30
|
else if (interaction.isButton()) {
|
|
@@ -29,7 +33,7 @@ export class InteractionCreate extends FrameworkEvent {
|
|
|
29
33
|
let path = interaction.customId.split('.');
|
|
30
34
|
const command = framework.commands.get(path[0]);
|
|
31
35
|
if (command.selectMenu) {
|
|
32
|
-
command.selectMenu({ path, interaction, client, framework });
|
|
36
|
+
command.selectMenu({ path, interaction, client, framework, guildSettings });
|
|
33
37
|
}
|
|
34
38
|
}
|
|
35
39
|
}
|
|
@@ -1,6 +1,16 @@
|
|
|
1
|
+
import { ActionRowBuilder, EmbedBuilder } from "discord.js";
|
|
1
2
|
import { EventParameters } from "../../../types/EventParameters.js";
|
|
2
3
|
import { FrameworkEvent } from "../../../types/FrameworkEvent.js";
|
|
3
4
|
export declare class MessageCreate extends FrameworkEvent {
|
|
4
5
|
once: boolean;
|
|
5
6
|
execute({ message, client, framework }: EventParameters): Promise<import("discord.js").Message<boolean>>;
|
|
7
|
+
autocorrect(str: string, words: string[]): any;
|
|
8
|
+
getErrorEmbed(error: any, parse: any): {
|
|
9
|
+
embeds: EmbedBuilder[];
|
|
10
|
+
components: ActionRowBuilder<import("discord.js").AnyComponentBuilder>[];
|
|
11
|
+
allowedMentions: {
|
|
12
|
+
repliedUser: boolean;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
parseError(error: any): any;
|
|
6
16
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import { PermissionsBitField } from "discord.js";
|
|
1
|
+
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, PermissionsBitField } from "discord.js";
|
|
2
2
|
import { FrameworkEvent } from "../../../types/FrameworkEvent.js";
|
|
3
3
|
import { ZumitoFramework } from "../../../ZumitoFramework.js";
|
|
4
|
+
import leven from 'leven';
|
|
5
|
+
import ErrorStackParser from 'error-stack-parser';
|
|
6
|
+
import * as url from 'url';
|
|
7
|
+
import path from "path";
|
|
4
8
|
export class MessageCreate extends FrameworkEvent {
|
|
5
9
|
once = false;
|
|
6
10
|
async execute({ message, client, framework }) {
|
|
@@ -12,9 +16,7 @@ export class MessageCreate extends FrameworkEvent {
|
|
|
12
16
|
if (message.content.startsWith(prefix)) {
|
|
13
17
|
if (!framework.commands.has(command)) {
|
|
14
18
|
let commandNames = Array.from(framework.commands.keys());
|
|
15
|
-
var
|
|
16
|
-
autocorrect = autocorrect({ words: commandNames });
|
|
17
|
-
var correctedCommand = autocorrect(command);
|
|
19
|
+
var correctedCommand = this.autocorrect(command, commandNames);
|
|
18
20
|
if (framework.commands.has(correctedCommand)) {
|
|
19
21
|
commandInstance = framework.commands.get(correctedCommand);
|
|
20
22
|
}
|
|
@@ -27,11 +29,11 @@ export class MessageCreate extends FrameworkEvent {
|
|
|
27
29
|
}
|
|
28
30
|
if (message.guild == null && commandInstance.dm == false)
|
|
29
31
|
return;
|
|
30
|
-
if (commandInstance.adminOnly || commandInstance.
|
|
32
|
+
if (commandInstance.adminOnly || commandInstance.userPermissions.length > 0) {
|
|
31
33
|
let denied = false;
|
|
32
34
|
if (framework.memberHasPermission(message.member, message.channel, PermissionsBitField.Flags.Administrator) || message.member.id != message.guild.ownerId) {
|
|
33
|
-
if (commandInstance.
|
|
34
|
-
commandInstance.
|
|
35
|
+
if (commandInstance.userPermissions.length > 0) {
|
|
36
|
+
commandInstance.userPermissions.forEach(permission => {
|
|
35
37
|
if (!framework.memberHasPermission(message.member, message.channel, permission)) {
|
|
36
38
|
denied = true;
|
|
37
39
|
}
|
|
@@ -60,18 +62,17 @@ export class MessageCreate extends FrameworkEvent {
|
|
|
60
62
|
}
|
|
61
63
|
}
|
|
62
64
|
try {
|
|
65
|
+
let guildSettings = await framework.getGuildSettings(message.guildId);
|
|
63
66
|
let parsedArgs = new Map();
|
|
64
67
|
args.forEach(function (arg, index) {
|
|
65
|
-
parsedArgs.set(commandInstance.args?.[index]?.name || index,
|
|
66
|
-
name: commandInstance.args?.[index]?.name || index,
|
|
67
|
-
value: arg
|
|
68
|
-
});
|
|
68
|
+
parsedArgs.set(commandInstance.args?.[index]?.name || index, arg);
|
|
69
69
|
});
|
|
70
70
|
await commandInstance.execute({
|
|
71
71
|
message,
|
|
72
72
|
args: parsedArgs,
|
|
73
73
|
client: framework.client,
|
|
74
74
|
framework: framework,
|
|
75
|
+
guildSettings: guildSettings,
|
|
75
76
|
});
|
|
76
77
|
if (!message.channel.isDMBased && !message.deletable && (false)) { // false = settings.deleteCommands
|
|
77
78
|
try {
|
|
@@ -86,19 +87,121 @@ export class MessageCreate extends FrameworkEvent {
|
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
catch (error) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
90
|
+
let content = await this.getErrorEmbed({
|
|
91
|
+
name: error.name,
|
|
92
|
+
message: error.message,
|
|
93
|
+
command: commandInstance,
|
|
94
|
+
args: args,
|
|
95
|
+
stack: error.stack,
|
|
96
|
+
}, true);
|
|
97
|
+
try {
|
|
98
|
+
message.reply(content);
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
channel.send(content);
|
|
102
|
+
}
|
|
101
103
|
}
|
|
102
104
|
}
|
|
103
105
|
}
|
|
106
|
+
autocorrect(str, words) {
|
|
107
|
+
var distance, bestWord, i, word, min;
|
|
108
|
+
var dictionary = words || [];
|
|
109
|
+
var len = dictionary.length;
|
|
110
|
+
for (i = 0; i < len; i++) {
|
|
111
|
+
word = dictionary[i];
|
|
112
|
+
distance = leven(str, word);
|
|
113
|
+
if (distance === 0) {
|
|
114
|
+
return word;
|
|
115
|
+
}
|
|
116
|
+
else if (min === undefined || distance < min) {
|
|
117
|
+
min = distance;
|
|
118
|
+
bestWord = word;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return bestWord;
|
|
122
|
+
}
|
|
123
|
+
getErrorEmbed(error, parse) {
|
|
124
|
+
let parsedError;
|
|
125
|
+
if (parse) {
|
|
126
|
+
parsedError = this.parseError(error);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
parsedError = error;
|
|
130
|
+
}
|
|
131
|
+
let embed = new EmbedBuilder()
|
|
132
|
+
.setTitle('Error')
|
|
133
|
+
.setDescription('An error has occured while executing this command.')
|
|
134
|
+
.setTimestamp()
|
|
135
|
+
.addFields([{
|
|
136
|
+
name: 'Command:',
|
|
137
|
+
value: (error.command.name || 'Not defined')
|
|
138
|
+
}])
|
|
139
|
+
.addFields([{
|
|
140
|
+
name: 'Arguments:',
|
|
141
|
+
value: (error.args.toString() || 'None')
|
|
142
|
+
}])
|
|
143
|
+
.addFields([{
|
|
144
|
+
name: 'Error name:',
|
|
145
|
+
value: (error.name || 'Not defined')
|
|
146
|
+
}])
|
|
147
|
+
.addFields([{
|
|
148
|
+
name: 'Error message:',
|
|
149
|
+
value: (error.message || 'Not defined')
|
|
150
|
+
}]);
|
|
151
|
+
if (error.possibleSolutions !== undefined) {
|
|
152
|
+
error.possibleSolutions.forEach((solution) => {
|
|
153
|
+
embed.addFields([{
|
|
154
|
+
name: 'Posible solution:',
|
|
155
|
+
value: solution
|
|
156
|
+
}]);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
let stackFrames = ErrorStackParser.parse(error).filter(e => !e.fileName.includes('node_modules') && !e.fileName.includes('node:internal'));
|
|
160
|
+
let stack = '';
|
|
161
|
+
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
|
162
|
+
let path1 = path.resolve('./');
|
|
163
|
+
let path2 = path1.replaceAll('\\', '/');
|
|
164
|
+
stackFrames.forEach((frame) => {
|
|
165
|
+
stack += `[${frame.fileName.replace(path1, '').replace(path2, '').replace('file://', '')}:${frame.lineNumber}](https://zumito.ga/redirect?url=vscode://file/${frame.fileName.replace('file://', '')}:${frame.lineNumber}) ${frame.functionName}()\n`;
|
|
166
|
+
});
|
|
167
|
+
if (error.stack !== undefined) {
|
|
168
|
+
embed.addFields([{
|
|
169
|
+
name: 'Call stack:',
|
|
170
|
+
value: stack || error.stack || error.stack.toString()
|
|
171
|
+
}]);
|
|
172
|
+
}
|
|
173
|
+
if (error.details !== undefined) {
|
|
174
|
+
error.details.forEach((detail) => {
|
|
175
|
+
embed.addFields([{
|
|
176
|
+
name: 'Detail:',
|
|
177
|
+
value: detail
|
|
178
|
+
}]);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
const body = `\n\n\n---\nComand:\`\`\`${error.command.name || 'not defined'}\`\`\`\nArguments:\`\`\`${error.args.toString() || 'none'}\`\`\`\nError:\`\`\`${error.name || 'not defined'}\`\`\`\nError message:\`\`\`${error.message || 'not defined'}\`\`\`\n`;
|
|
182
|
+
const requestUrl = `https://github.com/fernandomema/Zumito/issues/new?body=${encodeURIComponent(body)}`;
|
|
183
|
+
const row = new ActionRowBuilder()
|
|
184
|
+
.addComponents(new ButtonBuilder()
|
|
185
|
+
.setStyle(ButtonStyle.Link)
|
|
186
|
+
.setLabel('Report error')
|
|
187
|
+
.setEmoji('975645505302437978')
|
|
188
|
+
.setURL(requestUrl));
|
|
189
|
+
return {
|
|
190
|
+
embeds: [embed],
|
|
191
|
+
components: [row],
|
|
192
|
+
allowedMentions: {
|
|
193
|
+
repliedUser: false
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
parseError(error) {
|
|
198
|
+
error.possibleSolutions = [];
|
|
199
|
+
if (/(?:^|(?<= ))(EmbedBuilder|Discord|ActionRowBuilder|ButtonBuilder|MessageSelectMenu)(?:(?= )|$) is not defined/gm.test(error.message)) {
|
|
200
|
+
error.possibleSolutions.push('const { ' + error.message.split(" ")[0] + ' } = require(\'discord.js\');');
|
|
201
|
+
}
|
|
202
|
+
else if (error.message.includes('A custom id and url cannot both be specified')) {
|
|
203
|
+
error.possibleSolutions.push("Remove .setCustomId(...) or .setURL(...)");
|
|
204
|
+
}
|
|
205
|
+
return error;
|
|
206
|
+
}
|
|
104
207
|
}
|
|
@@ -2,5 +2,5 @@ import { Module } from "../types/Module.js";
|
|
|
2
2
|
import { ZumitoFramework } from "../ZumitoFramework.js";
|
|
3
3
|
export declare class baseModule extends Module {
|
|
4
4
|
constructor(modulePath: string, framework: ZumitoFramework);
|
|
5
|
-
|
|
5
|
+
registerEvents(): Promise<any>;
|
|
6
6
|
}
|
package/dist/baseModule/index.js
CHANGED
|
@@ -5,7 +5,7 @@ export class baseModule extends Module {
|
|
|
5
5
|
constructor(modulePath, framework) {
|
|
6
6
|
super(modulePath, framework);
|
|
7
7
|
}
|
|
8
|
-
|
|
8
|
+
async registerEvents() {
|
|
9
9
|
this.events.set('interactionCreate', new InteractionCreate());
|
|
10
10
|
this.events.set('messageCreate', new MessageCreate());
|
|
11
11
|
this.events.forEach(event => {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"guild_id": {
|
|
3
|
+
"type": "string",
|
|
4
|
+
"index": true,
|
|
5
|
+
"unique": true
|
|
6
|
+
},
|
|
7
|
+
"lang": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"default": "en"
|
|
10
|
+
},
|
|
11
|
+
"prefix": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"default": "z-"
|
|
14
|
+
},
|
|
15
|
+
"public": {
|
|
16
|
+
"type": "boolean",
|
|
17
|
+
"default": false
|
|
18
|
+
},
|
|
19
|
+
"deleteCommands": {
|
|
20
|
+
"type": "boolean",
|
|
21
|
+
"default": false
|
|
22
|
+
}
|
|
23
|
+
}
|
package/dist/types/Command.d.ts
CHANGED
|
@@ -3,15 +3,15 @@ import { SelectMenuParameters } from "./SelectMenuParameters.js";
|
|
|
3
3
|
export declare abstract class Command {
|
|
4
4
|
name: string;
|
|
5
5
|
categories: string[];
|
|
6
|
-
aliases
|
|
7
|
-
examples
|
|
8
|
-
|
|
9
|
-
botPermissions
|
|
10
|
-
hidden
|
|
11
|
-
adminOnly
|
|
12
|
-
nsfw
|
|
13
|
-
cooldown
|
|
14
|
-
slashCommand
|
|
6
|
+
aliases: string[];
|
|
7
|
+
examples: string[];
|
|
8
|
+
userPermissions: bigint[];
|
|
9
|
+
botPermissions: string[];
|
|
10
|
+
hidden: boolean;
|
|
11
|
+
adminOnly: boolean;
|
|
12
|
+
nsfw: boolean;
|
|
13
|
+
cooldown: number;
|
|
14
|
+
slashCommand: boolean;
|
|
15
15
|
dm: boolean;
|
|
16
16
|
args: CommandArgDefinition[];
|
|
17
17
|
type: string;
|
|
@@ -19,5 +19,5 @@ export declare abstract class Command {
|
|
|
19
19
|
abstract execute({ message, interaction, args, client, framework }: CommandParameters): void;
|
|
20
20
|
executePrefixCommand({ message, interaction, args, client, framework }: CommandParameters): void;
|
|
21
21
|
executeSlashCommand({ message, interaction, args, client, framework }: CommandParameters): void;
|
|
22
|
-
selectMenu({ path, interaction, client, framework }: SelectMenuParameters): void;
|
|
22
|
+
abstract selectMenu({ path, interaction, client, framework }: SelectMenuParameters): void;
|
|
23
23
|
}
|
package/dist/types/Command.js
CHANGED
|
@@ -4,7 +4,7 @@ export class Command {
|
|
|
4
4
|
categories = [];
|
|
5
5
|
aliases = [];
|
|
6
6
|
examples = [];
|
|
7
|
-
|
|
7
|
+
userPermissions = [];
|
|
8
8
|
botPermissions = [];
|
|
9
9
|
hidden = false;
|
|
10
10
|
adminOnly = false;
|
|
@@ -22,5 +22,4 @@ export class Command {
|
|
|
22
22
|
executeSlashCommand({ message, interaction, args, client, framework }) {
|
|
23
23
|
this.execute({ message, interaction, args, client, framework });
|
|
24
24
|
}
|
|
25
|
-
selectMenu({ path, interaction, client, framework }) { }
|
|
26
25
|
}
|
package/dist/types/Commands.js
CHANGED
package/dist/types/Module.d.ts
CHANGED
|
@@ -10,8 +10,8 @@ export declare abstract class Module {
|
|
|
10
10
|
constructor(path: any, framework: any);
|
|
11
11
|
initialize(): Promise<void>;
|
|
12
12
|
registerCommands(): Promise<void>;
|
|
13
|
-
onCommandCreated(filePath: string): void
|
|
14
|
-
onCommandChanged(filePath: string): void
|
|
13
|
+
onCommandCreated(filePath: string): Promise<void>;
|
|
14
|
+
onCommandChanged(filePath: string): Promise<void>;
|
|
15
15
|
onErrorLoadingCommand(error: Error): void;
|
|
16
16
|
getCommands(): Map<string, Command>;
|
|
17
17
|
registerEvents(): Promise<void>;
|
package/dist/types/Module.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as chokidar from 'chokidar';
|
|
2
|
+
import chalk from 'chalk';
|
|
2
3
|
import boxen from "boxen";
|
|
3
4
|
import * as fs from 'fs';
|
|
4
5
|
import path from 'path';
|
|
6
|
+
import { SelectMenuInteraction } from "discord.js";
|
|
5
7
|
export class Module {
|
|
6
8
|
path;
|
|
7
9
|
framework;
|
|
@@ -16,41 +18,63 @@ export class Module {
|
|
|
16
18
|
await this.registerCommands();
|
|
17
19
|
await this.registerEvents();
|
|
18
20
|
await this.registerTranslations();
|
|
21
|
+
await this.registerModels();
|
|
22
|
+
// console.error('[🔄🔴 ] Error initializing module ' + this.constructor.name);
|
|
23
|
+
// console.log(boxen(e + '\n' + e.stack, { padding: 1 }));
|
|
19
24
|
}
|
|
20
25
|
async registerCommands() {
|
|
21
|
-
if (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
if (fs.existsSync(path.join(this.path, 'commands'))) {
|
|
27
|
+
let files = fs.readdirSync(path.join(this.path, 'commands'));
|
|
28
|
+
for (let file of files) {
|
|
29
|
+
if (file.endsWith('.js') || file.endsWith('.ts')) {
|
|
30
|
+
let command = await import('file://' + path.join(this.path, 'commands', file)).catch(e => {
|
|
31
|
+
console.error(`[🔄🔴 ] Error loading ${file.slice(0, -3)} command on module ${this.constructor.name}`);
|
|
32
|
+
console.error(e + '\n' + e.name + '\n' + e.stack);
|
|
33
|
+
});
|
|
34
|
+
command = Object.values(command)[0];
|
|
35
|
+
command = new command();
|
|
36
|
+
this.commands.set(command.constructor.name.toLowerCase(), command);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
;
|
|
40
|
+
// register watcher
|
|
41
|
+
if (process.env.DEBUG) {
|
|
42
|
+
/*
|
|
43
|
+
Debug only cause in prod environment commands should't be changed.
|
|
44
|
+
Appart from that, esm module cache invalidation is not working properly
|
|
45
|
+
and can cause memory leaks and crashes.
|
|
46
|
+
*/
|
|
47
|
+
chokidar.watch(path.resolve(path.join(this.path, 'commands')), { ignored: /^\./, persistent: true, ignoreInitial: true })
|
|
48
|
+
.on('add', this.onCommandCreated.bind(this))
|
|
49
|
+
.on('change', this.onCommandChanged.bind(this))
|
|
50
|
+
//.on('unlink', function(path) {console.log('File', path, 'has been removed');})
|
|
51
|
+
.on('error', this.onErrorLoadingCommand.bind(this));
|
|
30
52
|
}
|
|
31
|
-
}
|
|
32
|
-
;
|
|
33
|
-
// register watcher
|
|
34
|
-
if (process.env.DEBUG) {
|
|
35
|
-
chokidar.watch(path.resolve(path.join(this.path, 'commands')), { ignored: /^\./, persistent: true, ignoreInitial: true })
|
|
36
|
-
.on('add', this.onCommandCreated.bind(this))
|
|
37
|
-
.on('change', this.onCommandChanged.bind(this))
|
|
38
|
-
//.on('unlink', function(path) {console.log('File', path, 'has been removed');})
|
|
39
|
-
.on('error', this.onErrorLoadingCommand.bind(this));
|
|
40
53
|
}
|
|
41
54
|
}
|
|
42
|
-
onCommandCreated(filePath) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
async onCommandCreated(filePath) {
|
|
56
|
+
if (filePath.endsWith('.js') || filePath.endsWith('.ts')) {
|
|
57
|
+
let command = await import('file://' + filePath).catch(e => {
|
|
58
|
+
console.error('[🆕🔴 ] Error loading command ' + chalk.blue(filePath.replace(/^.*[\\\/]/, '').split('.').slice(0, -1).join('.')));
|
|
59
|
+
console.log(e + '\n' + e.name + '\n' + e.stack);
|
|
60
|
+
});
|
|
61
|
+
command = Object.values(command)[0];
|
|
62
|
+
command = new command();
|
|
63
|
+
this.commands.set(command.constructor.name.toLowerCase(), command);
|
|
64
|
+
console.debug('[🆕🟢 ] Command ' + chalk.blue(filePath.replace(/^.*[\\\/]/, '').split('.').slice(0, -1).join('.')) + ' loaded');
|
|
65
|
+
}
|
|
52
66
|
}
|
|
53
|
-
onCommandChanged(filePath) {
|
|
67
|
+
async onCommandChanged(filePath) {
|
|
68
|
+
if (filePath.endsWith('.js') || filePath.endsWith('.ts')) {
|
|
69
|
+
let command = await import('file://' + filePath + '?update=' + Date.now().toString()).catch(e => {
|
|
70
|
+
console.error('[🔄🔴 ] Error reloading command ' + chalk.blue(filePath.replace(/^.*[\\\/]/, '').split('.').slice(0, -1).join('.')));
|
|
71
|
+
console.log(boxen(e + '\n' + e.name + '\n' + e.stack, { padding: 1 }));
|
|
72
|
+
});
|
|
73
|
+
command = Object.values(command)[0];
|
|
74
|
+
command = new command();
|
|
75
|
+
this.commands.set(command.constructor.name.toLowerCase(), command);
|
|
76
|
+
console.debug('[🔄🟢 ] Command ' + chalk.blue(filePath.replace(/^.*[\\\/]/, '').split('.').slice(0, -1).join('.')) + ' reloaded');
|
|
77
|
+
}
|
|
54
78
|
}
|
|
55
79
|
onErrorLoadingCommand(error) {
|
|
56
80
|
console.error('[🔄🔴 ] Error reloading command');
|
|
@@ -68,7 +92,10 @@ export class Module {
|
|
|
68
92
|
let moduleFileNames = fs.readdirSync(path.join(this.path, 'events', 'discord'));
|
|
69
93
|
for (let moduleFileName of moduleFileNames) {
|
|
70
94
|
if (moduleFileName.endsWith('.js') || moduleFileName.endsWith('.ts')) {
|
|
71
|
-
let event = await import('file://' + path.join(this.path, 'events', 'discord', moduleFileName))
|
|
95
|
+
let event = await import('file://' + path.join(this.path, 'events', 'discord', moduleFileName)).catch(e => {
|
|
96
|
+
console.error(`[🔄🔴 ] Error loading ${moduleFileName.slice(0, -3)} event on module ${this.constructor.name}`);
|
|
97
|
+
console.log(boxen(e + '\n' + e.name + '\n' + e.stack, { padding: 1 }));
|
|
98
|
+
});
|
|
72
99
|
event = Object.values(event)[0];
|
|
73
100
|
event = new event();
|
|
74
101
|
this.events.set(event.constructor.name.toLowerCase(), event);
|
|
@@ -101,6 +128,10 @@ export class Module {
|
|
|
101
128
|
args.forEach(arg => {
|
|
102
129
|
finalArgs[arg.constructor.name.toLowerCase()] = arg;
|
|
103
130
|
});
|
|
131
|
+
let selectMenuInteraction = args.find((arg) => arg instanceof SelectMenuInteraction);
|
|
132
|
+
if (selectMenuInteraction) {
|
|
133
|
+
finalArgs['interaction'] = selectMenuInteraction;
|
|
134
|
+
}
|
|
104
135
|
return finalArgs;
|
|
105
136
|
}
|
|
106
137
|
getEvents() {
|
|
@@ -112,7 +143,6 @@ export class Module {
|
|
|
112
143
|
let files = fs.readdirSync(path.join(this.path, 'translations'));
|
|
113
144
|
for (let file of files) {
|
|
114
145
|
if (file.endsWith('.json')) {
|
|
115
|
-
console.log('load ' + file);
|
|
116
146
|
let json = await import('file://' + `${this.path}/translations/${file}`, {
|
|
117
147
|
assert: {
|
|
118
148
|
type: "json",
|
|
@@ -122,7 +152,7 @@ export class Module {
|
|
|
122
152
|
console.log(boxen(e + '\n' + e.name + '\n' + e.stack, { padding: 1 }));
|
|
123
153
|
});
|
|
124
154
|
let lang = file.slice(0, -5);
|
|
125
|
-
this.parseTranslation('', lang, json);
|
|
155
|
+
this.parseTranslation('', lang, json.default);
|
|
126
156
|
}
|
|
127
157
|
}
|
|
128
158
|
}
|
|
@@ -143,7 +173,6 @@ export class Module {
|
|
|
143
173
|
for (let file of files) {
|
|
144
174
|
if (file.endsWith('.json')) {
|
|
145
175
|
let modelName = file.slice(0, -5).charAt(0).toUpperCase() + file.slice(0, -5).slice(1);
|
|
146
|
-
console.log('load ' + file);
|
|
147
176
|
let modelDefiniton = await import('file://' + `${this.path}/models/${file}`, {
|
|
148
177
|
assert: {
|
|
149
178
|
type: "json",
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { Client,
|
|
1
|
+
import { Client, SelectMenuInteraction } from "discord.js";
|
|
2
2
|
import { ZumitoFramework } from "../ZumitoFramework.js";
|
|
3
3
|
export interface SelectMenuParameters {
|
|
4
4
|
path: string[];
|
|
5
|
-
interaction:
|
|
5
|
+
interaction: SelectMenuInteraction;
|
|
6
6
|
client: Client;
|
|
7
7
|
framework: ZumitoFramework;
|
|
8
|
+
guildSettings?: any;
|
|
8
9
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zumito-framework",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.35",
|
|
4
4
|
"description": "Discord.js bot framework",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
17
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
18
|
-
"build": "tsc",
|
|
18
|
+
"build": "tsc-esm",
|
|
19
19
|
"publish": "npm publish",
|
|
20
20
|
"docs": "typedoc --out docs src"
|
|
21
21
|
},
|
|
@@ -30,16 +30,17 @@
|
|
|
30
30
|
"chokidar": "^3.5.3",
|
|
31
31
|
"cookie-parser": "^1.4.6",
|
|
32
32
|
"cors": "^2.8.5",
|
|
33
|
-
"discord.js": "^14.
|
|
33
|
+
"discord.js": "^14.3.0",
|
|
34
|
+
"error-stack-parser": "^2.1.4",
|
|
34
35
|
"express": "^4.18.1",
|
|
36
|
+
"leven": "^4.0.0",
|
|
35
37
|
"mongoose": "^6.5.2",
|
|
36
|
-
"plop": "^3.1.1"
|
|
37
|
-
"zumito-framework": "^1.1.16"
|
|
38
|
+
"plop": "^3.1.1"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"@types/node": "^18.7.16",
|
|
41
|
-
"typedoc": "^0.23.
|
|
42
|
-
"typescript": "^4.
|
|
42
|
+
"typedoc": "^0.23.14",
|
|
43
|
+
"typescript": "^4.8.2"
|
|
43
44
|
},
|
|
44
45
|
"type": "module"
|
|
45
46
|
}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { Command, CommandParameters } from "zumito-framework";
|
|
2
2
|
|
|
3
|
-
export class {{
|
|
3
|
+
export class {{capitalize command}} extends Command {
|
|
4
4
|
|
|
5
|
-
execute({ message, interaction, args, client, framework }: CommandParameters): void {
|
|
6
|
-
(message || interaction).reply({
|
|
5
|
+
execute({ message, interaction, args, client, framework, guildSettings }: CommandParameters): void {
|
|
6
|
+
(message || interaction!).reply({
|
|
7
7
|
content: "Message content",
|
|
8
8
|
});
|
|
9
9
|
}
|
|
10
|
+
|
|
11
|
+
async selectMenu({ path, interaction, client, framework }: SelectMenuParameters): Promise<void> {
|
|
12
|
+
await interaction.deferUpdate();
|
|
13
|
+
await interaction.editReply({
|
|
14
|
+
content: "Select menu content",
|
|
15
|
+
});
|
|
16
|
+
}
|
|
10
17
|
}
|
package/plopfile.js
CHANGED