zumito-framework 1.1.33 → 1.1.34

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.
@@ -4,7 +4,12 @@ export class TranslationManager {
4
4
  defaultLanguage = 'en';
5
5
  constructor() { }
6
6
  get(key, language, params) {
7
- return this.translations.get(key).get(language, params);
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)) {
@@ -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 = new TranslationManager();
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
- this.registerModule(path.resolve(), 'baseModule', baseModule);
122
- fs.readdirSync(modulesFolder).forEach(file => {
123
- this.registerModule(modulesFolder, file);
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()]);
@@ -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 autocorrect = await import('autocorrect');
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.permissions.length > 0) {
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.permissions.length > 0) {
34
- commandInstance.permissions.forEach(permission => {
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
  }
@@ -62,10 +64,7 @@ export class MessageCreate extends FrameworkEvent {
62
64
  try {
63
65
  let parsedArgs = new Map();
64
66
  args.forEach(function (arg, index) {
65
- parsedArgs.set(commandInstance.args?.[index]?.name || index, {
66
- name: commandInstance.args?.[index]?.name || index,
67
- value: arg
68
- });
67
+ parsedArgs.set(commandInstance.args?.[index]?.name || index, arg);
69
68
  });
70
69
  await commandInstance.execute({
71
70
  message,
@@ -86,19 +85,121 @@ export class MessageCreate extends FrameworkEvent {
86
85
  }
87
86
  }
88
87
  catch (error) {
89
- // let content = await getErrorEmbed({
90
- // name: error.name,
91
- // message: error.message,
92
- // comid: com,
93
- // args: args,
94
- // stack: error.stack,
95
- // }, true);
96
- // try {
97
- // message.reply(content);
98
- // } catch (e) {
99
- // channel.send(content);
100
- // }
88
+ let content = await this.getErrorEmbed({
89
+ name: error.name,
90
+ message: error.message,
91
+ command: commandInstance,
92
+ args: args,
93
+ stack: error.stack,
94
+ }, true);
95
+ try {
96
+ message.reply(content);
97
+ }
98
+ catch (e) {
99
+ channel.send(content);
100
+ }
101
101
  }
102
102
  }
103
103
  }
104
+ autocorrect(str, words) {
105
+ var distance, bestWord, i, word, min;
106
+ var dictionary = words || [];
107
+ var len = dictionary.length;
108
+ for (i = 0; i < len; i++) {
109
+ word = dictionary[i];
110
+ distance = leven(str, word);
111
+ if (distance === 0) {
112
+ return word;
113
+ }
114
+ else if (min === undefined || distance < min) {
115
+ min = distance;
116
+ bestWord = word;
117
+ }
118
+ }
119
+ return bestWord;
120
+ }
121
+ getErrorEmbed(error, parse) {
122
+ let parsedError;
123
+ if (parse) {
124
+ parsedError = this.parseError(error);
125
+ }
126
+ else {
127
+ parsedError = error;
128
+ }
129
+ let embed = new EmbedBuilder()
130
+ .setTitle('Error')
131
+ .setDescription('An error has occured while executing this command.')
132
+ .setTimestamp()
133
+ .addFields([{
134
+ name: 'Command:',
135
+ value: (error.command.name || 'Not defined')
136
+ }])
137
+ .addFields([{
138
+ name: 'Arguments:',
139
+ value: (error.args.toString() || 'None')
140
+ }])
141
+ .addFields([{
142
+ name: 'Error name:',
143
+ value: (error.name || 'Not defined')
144
+ }])
145
+ .addFields([{
146
+ name: 'Error message:',
147
+ value: (error.message || 'Not defined')
148
+ }]);
149
+ if (error.possibleSolutions !== undefined) {
150
+ error.possibleSolutions.forEach((solution) => {
151
+ embed.addFields([{
152
+ name: 'Posible solution:',
153
+ value: solution
154
+ }]);
155
+ });
156
+ }
157
+ let stackFrames = ErrorStackParser.parse(error).filter(e => !e.fileName.includes('node_modules') && !e.fileName.includes('node:internal'));
158
+ let stack = '';
159
+ const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
160
+ let path1 = path.resolve('./');
161
+ let path2 = path1.replaceAll('\\', '/');
162
+ stackFrames.forEach((frame) => {
163
+ 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`;
164
+ });
165
+ if (error.stack !== undefined) {
166
+ embed.addFields([{
167
+ name: 'Call stack:',
168
+ value: stack || error.stack || error.stack.toString()
169
+ }]);
170
+ }
171
+ if (error.details !== undefined) {
172
+ error.details.forEach((detail) => {
173
+ embed.addFields([{
174
+ name: 'Detail:',
175
+ value: detail
176
+ }]);
177
+ });
178
+ }
179
+ 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`;
180
+ const requestUrl = `https://github.com/fernandomema/Zumito/issues/new?body=${encodeURIComponent(body)}`;
181
+ const row = new ActionRowBuilder()
182
+ .addComponents(new ButtonBuilder()
183
+ .setStyle(ButtonStyle.Link)
184
+ .setLabel('Report error')
185
+ .setEmoji('975645505302437978')
186
+ .setURL(requestUrl));
187
+ return {
188
+ embeds: [embed],
189
+ components: [row],
190
+ allowedMentions: {
191
+ repliedUser: false
192
+ }
193
+ };
194
+ }
195
+ parseError(error) {
196
+ error.possibleSolutions = [];
197
+ if (/(?:^|(?<= ))(EmbedBuilder|Discord|ActionRowBuilder|ButtonBuilder|MessageSelectMenu)(?:(?= )|$) is not defined/gm.test(error.message)) {
198
+ error.possibleSolutions.push('const { ' + error.message.split(" ")[0] + ' } = require(\'discord.js\');');
199
+ }
200
+ else if (error.message.includes('A custom id and url cannot both be specified')) {
201
+ error.possibleSolutions.push("Remove .setCustomId(...) or .setURL(...)");
202
+ }
203
+ return error;
204
+ }
104
205
  }
@@ -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
- asyncregisterEvents(): any;
5
+ registerEvents(): Promise<any>;
6
6
  }
@@ -5,7 +5,7 @@ export class baseModule extends Module {
5
5
  constructor(modulePath, framework) {
6
6
  super(modulePath, framework);
7
7
  }
8
- asyncregisterEvents() {
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 => {
@@ -5,7 +5,7 @@ export declare abstract class Command {
5
5
  categories: string[];
6
6
  aliases?: string[];
7
7
  examples?: string[];
8
- permissions?: bigint[];
8
+ userPermissions?: bigint[];
9
9
  botPermissions?: string[];
10
10
  hidden?: boolean;
11
11
  adminOnly?: boolean;
@@ -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
  }
@@ -4,7 +4,7 @@ export class Command {
4
4
  categories = [];
5
5
  aliases = [];
6
6
  examples = [];
7
- permissions = [];
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
  }
@@ -1,4 +1,4 @@
1
- import { CommandType } from "./CommandType";
1
+ import { CommandType } from "./CommandType.js";
2
2
  export class Command {
3
3
  name = this.constructor.name.toLowerCase();
4
4
  categories = [];
@@ -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>;
@@ -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,62 @@ export class Module {
16
18
  await this.registerCommands();
17
19
  await this.registerEvents();
18
20
  await this.registerTranslations();
21
+ // console.error('[🔄🔴 ] Error initializing module ' + this.constructor.name);
22
+ // console.log(boxen(e + '\n' + e.stack, { padding: 1 }));
19
23
  }
20
24
  async registerCommands() {
21
- if (!fs.existsSync(path.join(this.path, 'commands')))
22
- return;
23
- let files = fs.readdirSync(path.join(this.path, 'commands'));
24
- for (let file of files) {
25
- if (file.endsWith('.js') || file.endsWith('.ts')) {
26
- let command = await import('file://' + path.join(this.path, 'commands', file));
27
- command = Object.values(command)[0];
28
- command = new command();
29
- this.commands.set(command.constructor.name.toLowerCase(), command);
25
+ if (fs.existsSync(path.join(this.path, 'commands'))) {
26
+ let files = fs.readdirSync(path.join(this.path, 'commands'));
27
+ for (let file of files) {
28
+ if (file.endsWith('.js') || file.endsWith('.ts')) {
29
+ let command = await import('file://' + path.join(this.path, 'commands', file)).catch(e => {
30
+ console.error(`[🔄🔴 ] Error loading ${file.slice(0, -3)} command on module ${this.constructor.name}`);
31
+ console.error(e + '\n' + e.name + '\n' + e.stack);
32
+ });
33
+ command = Object.values(command)[0];
34
+ command = new command();
35
+ this.commands.set(command.constructor.name.toLowerCase(), command);
36
+ }
37
+ }
38
+ ;
39
+ // register watcher
40
+ if (process.env.DEBUG) {
41
+ /*
42
+ Debug only cause in prod environment commands should't be changed.
43
+ Appart from that, esm module cache invalidation is not working properly
44
+ and can cause memory leaks and crashes.
45
+ */
46
+ chokidar.watch(path.resolve(path.join(this.path, 'commands')), { ignored: /^\./, persistent: true, ignoreInitial: true })
47
+ .on('add', this.onCommandCreated.bind(this))
48
+ .on('change', this.onCommandChanged.bind(this))
49
+ //.on('unlink', function(path) {console.log('File', path, 'has been removed');})
50
+ .on('error', this.onErrorLoadingCommand.bind(this));
30
51
  }
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
52
  }
41
53
  }
42
- onCommandCreated(filePath) {
43
- console.log(filePath);
44
- // GRreen dot emoji
45
- // try {
46
- // delete require.cache[path.resolve(path.join(this.path, 'commands', path))];
47
- // console.debug('[🔄🟢 ] Command ' + chalk.blue(path.replace(/^.*[\\\/]/, '').split('.').slice(0, -1).join('.')) + ' reloaded');
48
- // } catch(e) {
49
- // console.error('[🔄🔴 ] Error reloading command ' + chalk.blue(path.replace(/^.*[\\\/]/, '').split('.').slice(0, -1).join('.')));
50
- // console.log(boxen(e + '\n' + e.stack, { padding: 1 }));
51
- // }
54
+ async onCommandCreated(filePath) {
55
+ if (filePath.endsWith('.js') || filePath.endsWith('.ts')) {
56
+ let command = await import('file://' + filePath).catch(e => {
57
+ console.error('[🆕🔴 ] Error loading command ' + chalk.blue(filePath.replace(/^.*[\\\/]/, '').split('.').slice(0, -1).join('.')));
58
+ console.log(e + '\n' + e.name + '\n' + e.stack);
59
+ });
60
+ command = Object.values(command)[0];
61
+ command = new command();
62
+ this.commands.set(command.constructor.name.toLowerCase(), command);
63
+ console.debug('[🆕🟢 ] Command ' + chalk.blue(filePath.replace(/^.*[\\\/]/, '').split('.').slice(0, -1).join('.')) + ' loaded');
64
+ }
52
65
  }
53
- onCommandChanged(filePath) {
66
+ async onCommandChanged(filePath) {
67
+ if (filePath.endsWith('.js') || filePath.endsWith('.ts')) {
68
+ let command = await import('file://' + filePath + '?update=' + Date.now().toString()).catch(e => {
69
+ console.error('[🔄🔴 ] Error reloading command ' + chalk.blue(filePath.replace(/^.*[\\\/]/, '').split('.').slice(0, -1).join('.')));
70
+ console.log(boxen(e + '\n' + e.name + '\n' + e.stack, { padding: 1 }));
71
+ });
72
+ command = Object.values(command)[0];
73
+ command = new command();
74
+ this.commands.set(command.constructor.name.toLowerCase(), command);
75
+ console.debug('[🔄🟢 ] Command ' + chalk.blue(filePath.replace(/^.*[\\\/]/, '').split('.').slice(0, -1).join('.')) + ' reloaded');
76
+ }
54
77
  }
55
78
  onErrorLoadingCommand(error) {
56
79
  console.error('[🔄🔴 ] Error reloading command');
@@ -68,7 +91,10 @@ export class Module {
68
91
  let moduleFileNames = fs.readdirSync(path.join(this.path, 'events', 'discord'));
69
92
  for (let moduleFileName of moduleFileNames) {
70
93
  if (moduleFileName.endsWith('.js') || moduleFileName.endsWith('.ts')) {
71
- let event = await import('file://' + path.join(this.path, 'events', 'discord', moduleFileName));
94
+ let event = await import('file://' + path.join(this.path, 'events', 'discord', moduleFileName)).catch(e => {
95
+ console.error(`[🔄🔴 ] Error loading ${moduleFileName.slice(0, -3)} event on module ${this.constructor.name}`);
96
+ console.log(boxen(e + '\n' + e.name + '\n' + e.stack, { padding: 1 }));
97
+ });
72
98
  event = Object.values(event)[0];
73
99
  event = new event();
74
100
  this.events.set(event.constructor.name.toLowerCase(), event);
@@ -101,6 +127,10 @@ export class Module {
101
127
  args.forEach(arg => {
102
128
  finalArgs[arg.constructor.name.toLowerCase()] = arg;
103
129
  });
130
+ let selectMenuInteraction = args.find((arg) => arg instanceof SelectMenuInteraction);
131
+ if (selectMenuInteraction) {
132
+ finalArgs['interaction'] = selectMenuInteraction;
133
+ }
104
134
  return finalArgs;
105
135
  }
106
136
  getEvents() {
@@ -112,7 +142,6 @@ export class Module {
112
142
  let files = fs.readdirSync(path.join(this.path, 'translations'));
113
143
  for (let file of files) {
114
144
  if (file.endsWith('.json')) {
115
- console.log('load ' + file);
116
145
  let json = await import('file://' + `${this.path}/translations/${file}`, {
117
146
  assert: {
118
147
  type: "json",
@@ -122,7 +151,7 @@ export class Module {
122
151
  console.log(boxen(e + '\n' + e.name + '\n' + e.stack, { padding: 1 }));
123
152
  });
124
153
  let lang = file.slice(0, -5);
125
- this.parseTranslation('', lang, json);
154
+ this.parseTranslation('', lang, json.default);
126
155
  }
127
156
  }
128
157
  }
@@ -143,7 +172,6 @@ export class Module {
143
172
  for (let file of files) {
144
173
  if (file.endsWith('.json')) {
145
174
  let modelName = file.slice(0, -5).charAt(0).toUpperCase() + file.slice(0, -5).slice(1);
146
- console.log('load ' + file);
147
175
  let modelDefiniton = await import('file://' + `${this.path}/models/${file}`, {
148
176
  assert: {
149
177
  type: "json",
@@ -1,8 +1,8 @@
1
- import { Client, Interaction } from "discord.js";
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: Interaction;
5
+ interaction: SelectMenuInteraction;
6
6
  client: Client;
7
7
  framework: ZumitoFramework;
8
8
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zumito-framework",
3
- "version": "1.1.33",
3
+ "version": "1.1.34",
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,18 @@
30
30
  "chokidar": "^3.5.3",
31
31
  "cookie-parser": "^1.4.6",
32
32
  "cors": "^2.8.5",
33
- "discord.js": "^14.2.0",
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
38
  "plop": "^3.1.1",
37
39
  "zumito-framework": "^1.1.16"
38
40
  },
39
41
  "devDependencies": {
40
42
  "@types/node": "^18.7.16",
41
- "typedoc": "^0.23.10",
42
- "typescript": "^4.7.4"
43
+ "typedoc": "^0.23.14",
44
+ "typescript": "^4.8.2"
43
45
  },
44
46
  "type": "module"
45
47
  }
@@ -1,10 +1,17 @@
1
1
  import { Command, CommandParameters } from "zumito-framework";
2
2
 
3
- export class {{command.charAt(0).toUpperCase() + command.slice(1)}} extends Command {
3
+ export class {{capitalize command}} extends Command {
4
4
 
5
5
  execute({ message, interaction, args, client, framework }: CommandParameters): void {
6
- (message || interaction).reply({
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
@@ -1,4 +1,7 @@
1
1
  module.exports = function (plop) {
2
+ plop.setHelper('capitalize', function (text) {
3
+ return text.charAt(0).toUpperCase() + text.slice(1);
4
+ });
2
5
  // create your generators here
3
6
  plop.setGenerator('command', {
4
7
  description: 'this is a skeleton command file',