zumito-framework 1.1.58 → 1.1.60

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,30 +4,83 @@ import { FrameworkSettings } from './types/FrameworkSettings.js';
4
4
  import { Module } from './types/Module.js';
5
5
  import { FrameworkEvent } from './types/FrameworkEvent.js';
6
6
  import { TranslationManager } from './TranslationManager.js';
7
+ import { DatabaseModel } from './types/DatabaseModel.js';
7
8
  /**
8
9
  * @class ZumitoFramework
9
- * @classdesc The main class of the framework.
10
- *
11
- * @property {FrameworkSettings} settings - The settings for the framework.
12
- * @property {Client} client - The discord client instance.
13
- * @property {Map<string, Module>} modules - The modules loaded in the framework.
14
- * @property {Map<string, Command>} commands - The commands loaded in the framework.
15
- * @property {Map<string, FrameworkEvent>} events - The events loaded in the framework.
16
- * @property {TranslationManager} translations - The Translation Manager for the framework.
17
- * @property {Map<string, any>} models - The database models loaded in the framework.
18
- * @property {mongoose.Connection} database - The connection to the MongoDB database.
19
- * @property {express.Application} app - The ExpressJS application for the API server.
10
+ * @description The main class of the framework.
11
+ * @example
12
+ * new ZumitoFramework({
13
+ * discordClientOptions: {
14
+ * intents: 3276799,
15
+ * token: 'XXXXXXXXXXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
16
+ * clientId: 755XXXXXXXXXX98,
17
+ * },
18
+ * defaultPrefix: process.env.BOTPREFIX || "z-",
19
+ * mongoQueryString: mongodb://XXXXXX,
20
+ * logLevel: parseInt(process.env.LOGLEVEL || "3"),
21
+ * });
20
22
  */
21
23
  export declare class ZumitoFramework {
24
+ /**
25
+ * The discord client instance.
26
+ * @type {Client}
27
+ * @private
28
+ * @see {@link https://discord.js.org/#/docs/main/stable/class/Client}
29
+ */
22
30
  client: Client;
31
+ /**
32
+ * The settings for the framework.
33
+ * @type {FrameworkSettings}
34
+ * @private
35
+ */
23
36
  settings: FrameworkSettings;
37
+ /**
38
+ * The modules loaded in the framework.
39
+ * @type {Map<string, Module>}
40
+ * @private
41
+ */
24
42
  modules: Map<string, Module>;
43
+ /**
44
+ * The commands loaded in the framework.
45
+ * @type {Map<string, Command>}
46
+ * @private
47
+ * @see {@link Command}
48
+ */
25
49
  commands: Map<string, Command>;
50
+ /**
51
+ * The events loaded in the framework.
52
+ * @type {Map<string, FrameworkEvent>}
53
+ * @private
54
+ * @see {@link FrameworkEvent}
55
+ */
26
56
  events: Map<string, FrameworkEvent>;
57
+ /**
58
+ * The Translation Manager for the framework.
59
+ * @type {TranslationManager}
60
+ * @private
61
+ * @see {@link TranslationManager}
62
+ */
27
63
  translations: TranslationManager;
28
64
  routes: any;
29
- models: any;
65
+ /**
66
+ * The database models loaded in the framework.
67
+ * @type {Array<DatabaseModel>}
68
+ * @private
69
+ */
70
+ models: Array<DatabaseModel>;
71
+ /**
72
+ * The canario database schema instance.
73
+ * @type {canario.Schema}
74
+ * @private
75
+ * @see {@link https://www.npmjs.com/package/canario}
76
+ */
30
77
  database: any;
78
+ /**
79
+ * The ExpressJS app instance.
80
+ * @type {express.Application}
81
+ * @private
82
+ * @see {@link https://expressjs.com/en/4x/api.html#app}
83
+ */
31
84
  app: any;
32
85
  /**
33
86
  * @constructor
@@ -44,6 +97,7 @@ export declare class ZumitoFramework {
44
97
  * @returns {Promise<void>}
45
98
  */
46
99
  private initialize;
100
+ private initializeDatabase;
47
101
  /**
48
102
  * Initializes and starts the API server using ExpressJS.
49
103
  * Sets up middleware, routes, and error handling for the server.
@@ -117,6 +171,6 @@ export declare class ZumitoFramework {
117
171
  * // returns the guild settings
118
172
  * getGuildSettings(interaction.guildId);
119
173
  */
120
- getGuildSettings(guildId: string): Promise<any>;
174
+ getGuildSettings(guildId: string): Promise<unknown>;
121
175
  refreshSlashCommands(): Promise<void>;
122
176
  }
@@ -11,7 +11,7 @@ import { betterLogging } from 'better-logging';
11
11
  betterLogging(console);
12
12
  import { REST } from '@discordjs/rest';
13
13
  import { Routes } from 'discord-api-types/v9';
14
- import mongoose from 'mongoose';
14
+ import canario from 'canario';
15
15
  import cookieParser from 'cookie-parser';
16
16
  import cors from 'cors';
17
17
  import http from 'http';
@@ -19,28 +19,80 @@ import * as url from 'url';
19
19
  import { CommandType } from './types/CommandType.js';
20
20
  /**
21
21
  * @class ZumitoFramework
22
- * @classdesc The main class of the framework.
23
- *
24
- * @property {FrameworkSettings} settings - The settings for the framework.
25
- * @property {Client} client - The discord client instance.
26
- * @property {Map<string, Module>} modules - The modules loaded in the framework.
27
- * @property {Map<string, Command>} commands - The commands loaded in the framework.
28
- * @property {Map<string, FrameworkEvent>} events - The events loaded in the framework.
29
- * @property {TranslationManager} translations - The Translation Manager for the framework.
30
- * @property {Map<string, any>} models - The database models loaded in the framework.
31
- * @property {mongoose.Connection} database - The connection to the MongoDB database.
32
- * @property {express.Application} app - The ExpressJS application for the API server.
22
+ * @description The main class of the framework.
23
+ * @example
24
+ * new ZumitoFramework({
25
+ * discordClientOptions: {
26
+ * intents: 3276799,
27
+ * token: 'XXXXXXXXXXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
28
+ * clientId: 755XXXXXXXXXX98,
29
+ * },
30
+ * defaultPrefix: process.env.BOTPREFIX || "z-",
31
+ * mongoQueryString: mongodb://XXXXXX,
32
+ * logLevel: parseInt(process.env.LOGLEVEL || "3"),
33
+ * });
33
34
  */
34
35
  export class ZumitoFramework {
36
+ /**
37
+ * The discord client instance.
38
+ * @type {Client}
39
+ * @private
40
+ * @see {@link https://discord.js.org/#/docs/main/stable/class/Client}
41
+ */
35
42
  client;
43
+ /**
44
+ * The settings for the framework.
45
+ * @type {FrameworkSettings}
46
+ * @private
47
+ */
36
48
  settings;
49
+ /**
50
+ * The modules loaded in the framework.
51
+ * @type {Map<string, Module>}
52
+ * @private
53
+ */
37
54
  modules;
55
+ /**
56
+ * The commands loaded in the framework.
57
+ * @type {Map<string, Command>}
58
+ * @private
59
+ * @see {@link Command}
60
+ */
38
61
  commands;
62
+ /**
63
+ * The events loaded in the framework.
64
+ * @type {Map<string, FrameworkEvent>}
65
+ * @private
66
+ * @see {@link FrameworkEvent}
67
+ */
39
68
  events;
69
+ /**
70
+ * The Translation Manager for the framework.
71
+ * @type {TranslationManager}
72
+ * @private
73
+ * @see {@link TranslationManager}
74
+ */
40
75
  translations;
41
76
  routes;
77
+ /**
78
+ * The database models loaded in the framework.
79
+ * @type {Array<DatabaseModel>}
80
+ * @private
81
+ */
42
82
  models;
83
+ /**
84
+ * The canario database schema instance.
85
+ * @type {canario.Schema}
86
+ * @private
87
+ * @see {@link https://www.npmjs.com/package/canario}
88
+ */
43
89
  database;
90
+ /**
91
+ * The ExpressJS app instance.
92
+ * @type {express.Application}
93
+ * @private
94
+ * @see {@link https://expressjs.com/en/4x/api.html#app}
95
+ */
44
96
  app;
45
97
  /**
46
98
  * @constructor
@@ -53,7 +105,7 @@ export class ZumitoFramework {
53
105
  this.commands = new Map();
54
106
  this.events = new Map();
55
107
  this.translations = new TranslationManager();
56
- this.models = new Map();
108
+ this.models = [];
57
109
  if (settings.logLevel) {
58
110
  console.logLevel = settings.logLevel;
59
111
  }
@@ -75,23 +127,32 @@ export class ZumitoFramework {
75
127
  * @returns {Promise<void>}
76
128
  */
77
129
  async initialize() {
78
- try {
79
- mongoose.set('strictQuery', true);
80
- await mongoose.connect(this.settings.mongoQueryString);
81
- }
82
- catch (err) {
83
- console.error('[🗄️🔴] Database connection error:', err.message);
84
- process.exit(1);
85
- }
86
- finally {
87
- this.database = mongoose.connection;
88
- console.log('[🗄️🟢] Database connection successful');
89
- }
130
+ await this.initializeDatabase();
90
131
  this.initializeDiscordClient();
91
132
  this.startApiServer();
92
133
  await this.registerModules();
93
134
  await this.refreshSlashCommands();
94
135
  }
136
+ async initializeDatabase() {
137
+ const folders = ['db', 'db/tingodb'];
138
+ for (const folder of folders) {
139
+ if (!fs.existsSync(folder)) {
140
+ fs.mkdirSync(folder);
141
+ }
142
+ }
143
+ this.database = new canario.Schema(this.settings?.database?.type || 'tingodb', this.settings?.database || {});
144
+ await new Promise((resolve, reject) => {
145
+ this.database.on('connected', resolve);
146
+ this.database.on('error', reject);
147
+ })
148
+ .then(() => {
149
+ console.log('[🗄️🟢] Database connection successful!');
150
+ })
151
+ .catch((err) => {
152
+ console.error('[🗄️🔴] Database connection error:', err.message);
153
+ process.exit(1);
154
+ });
155
+ }
95
156
  /**
96
157
  * Initializes and starts the API server using ExpressJS.
97
158
  * Sets up middleware, routes, and error handling for the server.
@@ -150,9 +211,21 @@ export class ZumitoFramework {
150
211
  for (const file of files) {
151
212
  await this.registerModule(modulesFolder, file);
152
213
  }
153
- this.models.forEach((modelDefinition, modelName) => {
154
- const schema = new mongoose.Schema(modelDefinition);
155
- this.models.set(modelName, mongoose.model(modelName, schema));
214
+ // Define models
215
+ const schemas = {};
216
+ this.models.forEach((model) => {
217
+ if (!schemas[model.name]) {
218
+ schemas[model.name] = model.getModel(this.database);
219
+ }
220
+ else {
221
+ schemas[model.name] = MergeRecursive(schemas[model.name], model.getModel(this.database));
222
+ }
223
+ });
224
+ Object.keys(schemas).forEach((schemaName) => {
225
+ this.database.define(schemaName, schemas[schemaName]);
226
+ });
227
+ this.models.forEach((model) => {
228
+ model.define(this.database.models[model.name], this.database.models);
156
229
  });
157
230
  }
158
231
  async registerModule(modulesFolder, moduleName, module) {
@@ -193,13 +266,8 @@ export class ZumitoFramework {
193
266
  // Register module events
194
267
  this.events = new Map([...this.events, ...moduleInstance.getEvents()]);
195
268
  // Register models
196
- moduleInstance.getModels().forEach((modelDefinition, modelName) => {
197
- if (!this.models.has(modelName)) {
198
- this.models.set(modelName, modelDefinition);
199
- }
200
- else {
201
- this.models.set(modelName, MergeRecursive(this.models.get(modelName), modelDefinition));
202
- }
269
+ moduleInstance.getModels().forEach((model) => {
270
+ this.models.push(model);
203
271
  });
204
272
  /*
205
273
 
@@ -303,15 +371,26 @@ export class ZumitoFramework {
303
371
  * getGuildSettings(interaction.guildId);
304
372
  */
305
373
  async getGuildSettings(guildId) {
306
- const Guild = this.models.get('Guild');
307
- let guild = await Guild.findOne({ guild_id: guildId }).exec();
308
- if (guild == null) {
309
- guild = new Guild({
310
- guild_id: guildId,
374
+ const Guild = this.database.models.Guild;
375
+ return await new Promise((resolve, reject) => {
376
+ Guild.findOne({ where: { guild_id: guildId } }, (err, guild) => {
377
+ if (err)
378
+ reject(err);
379
+ if (guild == null) {
380
+ guild = new Guild({
381
+ guild_id: guildId,
382
+ });
383
+ guild.save((err) => {
384
+ if (err)
385
+ reject(err);
386
+ resolve(guild);
387
+ });
388
+ }
389
+ else {
390
+ resolve(guild);
391
+ }
311
392
  });
312
- await guild.save();
313
- }
314
- return guild;
393
+ });
315
394
  }
316
395
  async refreshSlashCommands() {
317
396
  const rest = new REST({ version: '10' }).setToken(this.settings.discordClientOptions.token);
@@ -43,7 +43,7 @@ export class InteractionCreate extends FrameworkEvent {
43
43
  CommandType.slash,
44
44
  ].includes(commandInstance.type))
45
45
  return;
46
- const trans = this.getTransMethod(commandInstance, guildSettings, framework);
46
+ const trans = this.getTransMethod(commandInstance, framework, guildSettings);
47
47
  if (commandInstance.type === CommandType.separated ||
48
48
  commandInstance.type === CommandType.slash) {
49
49
  await commandInstance.executeSlashCommand({
@@ -3,4 +3,5 @@ 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
+ registerModels(): Promise<void>;
6
7
  }
@@ -1,6 +1,7 @@
1
1
  import { Module } from '../types/Module.js';
2
2
  import { InteractionCreate } from './events/discord/interactionCreate.js';
3
3
  import { MessageCreate } from './events/discord/messageCreate.js';
4
+ import { Guild } from './models/Guild.js';
4
5
  export class baseModule extends Module {
5
6
  constructor(modulePath, framework) {
6
7
  super(modulePath, framework);
@@ -12,4 +13,7 @@ export class baseModule extends Module {
12
13
  this.registerDiscordEvent(event);
13
14
  });
14
15
  }
16
+ async registerModels() {
17
+ this.models.push(new Guild(this.framework));
18
+ }
15
19
  }
@@ -0,0 +1,27 @@
1
+ import { DatabaseModel } from '../../types/DatabaseModel.js';
2
+ export declare class Guild extends DatabaseModel {
3
+ getModel(schema: any): {
4
+ guild_id: {
5
+ type: any;
6
+ required: boolean;
7
+ unique: boolean;
8
+ };
9
+ lang: {
10
+ type: any;
11
+ default: string;
12
+ };
13
+ prefix: {
14
+ type: any;
15
+ default: string;
16
+ };
17
+ public: {
18
+ type: any;
19
+ default: boolean;
20
+ };
21
+ deleteCommands: {
22
+ type: any;
23
+ default: boolean;
24
+ };
25
+ };
26
+ define(model: any, models: any): void;
27
+ }
@@ -0,0 +1,32 @@
1
+ import { DatabaseModel } from '../../types/DatabaseModel.js';
2
+ export class Guild extends DatabaseModel {
3
+ getModel(schema) {
4
+ return {
5
+ guild_id: {
6
+ type: schema.String,
7
+ required: true,
8
+ unique: true,
9
+ },
10
+ lang: {
11
+ type: schema.String,
12
+ default: 'en',
13
+ },
14
+ prefix: {
15
+ type: schema.String,
16
+ default: 'z-',
17
+ },
18
+ public: {
19
+ type: schema.Boolean,
20
+ default: false,
21
+ },
22
+ deleteCommands: {
23
+ type: schema.Boolean,
24
+ default: false,
25
+ },
26
+ };
27
+ }
28
+ define(model, models) {
29
+ model.validatesUniquenessOf('guild_id');
30
+ model.validatesInclusionOf('lang', { in: ['en', 'es'] });
31
+ }
32
+ }
package/dist/index.d.ts CHANGED
@@ -1,19 +1,20 @@
1
1
  import { ApiResponse } from './definitions/ApiResponse.js';
2
+ import { TranslationManager } from './TranslationManager.js';
2
3
  import { Command } from './types/Command.js';
3
4
  import { CommandArgDefinition } from './types/CommandArgDefinition.js';
4
5
  import { CommandArguments } from './types/CommandArguments.js';
5
6
  import { CommandChoiceDefinition } from './types/CommandChoiceDefinition.js';
6
7
  import { CommandParameters } from './types/CommandParameters.js';
8
+ import { ButtonPressed } from './types/Commands/ButtonPressed.js';
9
+ import { ButtonPressedParams } from './types/Commands/ButtonPressedParams.js';
7
10
  import { CommandType } from './types/CommandType.js';
8
11
  import { FrameworkEvent } from './types/FrameworkEvent.js';
9
12
  import { FrameworkSettings } from './types/FrameworkSettings.js';
10
13
  import { Module } from './types/Module.js';
11
14
  import { SelectMenuParameters } from './types/SelectMenuParameters.js';
12
- import { TextFormatter } from './utils/TextFormatter.js';
13
15
  import { Translation } from './types/Translation.js';
14
- import { TranslationManager } from './TranslationManager.js';
15
- import { ZumitoFramework } from './ZumitoFramework.js';
16
+ import { DatabaseConfigLoader } from './utils/DatabaseConfigLoader.js';
16
17
  import { EmojiFallback } from './utils/EmojiFallback.js';
17
- import { ButtonPressed } from './types/Commands/ButtonPressed.js';
18
- import { ButtonPressedParams } from './types/Commands/ButtonPressedParams.js';
19
- export { ZumitoFramework, FrameworkSettings, Command, Module, CommandParameters, CommandArguments, FrameworkEvent, Translation, TranslationManager, ApiResponse, SelectMenuParameters, CommandType, CommandArgDefinition, CommandChoiceDefinition, ButtonPressed, ButtonPressedParams, TextFormatter, EmojiFallback, };
18
+ import { TextFormatter } from './utils/TextFormatter.js';
19
+ import { ZumitoFramework } from './ZumitoFramework.js';
20
+ export { ZumitoFramework, FrameworkSettings, Command, Module, CommandParameters, CommandArguments, FrameworkEvent, Translation, TranslationManager, ApiResponse, SelectMenuParameters, CommandType, CommandArgDefinition, CommandChoiceDefinition, ButtonPressed, ButtonPressedParams, TextFormatter, EmojiFallback, DatabaseConfigLoader, };
package/dist/index.js CHANGED
@@ -1,13 +1,14 @@
1
1
  import { ApiResponse } from './definitions/ApiResponse.js';
2
+ import { TranslationManager } from './TranslationManager.js';
2
3
  import { Command } from './types/Command.js';
3
4
  import { CommandArguments } from './types/CommandArguments.js';
5
+ import { ButtonPressed } from './types/Commands/ButtonPressed.js';
4
6
  import { CommandType } from './types/CommandType.js';
5
7
  import { FrameworkEvent } from './types/FrameworkEvent.js';
6
8
  import { Module } from './types/Module.js';
7
- import { TextFormatter } from './utils/TextFormatter.js';
8
9
  import { Translation } from './types/Translation.js';
9
- import { TranslationManager } from './TranslationManager.js';
10
- import { ZumitoFramework } from './ZumitoFramework.js';
10
+ import { DatabaseConfigLoader } from './utils/DatabaseConfigLoader.js';
11
11
  import { EmojiFallback } from './utils/EmojiFallback.js';
12
- import { ButtonPressed } from './types/Commands/ButtonPressed.js';
13
- export { ZumitoFramework, Command, Module, CommandArguments, FrameworkEvent, Translation, TranslationManager, ApiResponse, CommandType, ButtonPressed, TextFormatter, EmojiFallback, };
12
+ import { TextFormatter } from './utils/TextFormatter.js';
13
+ import { ZumitoFramework } from './ZumitoFramework.js';
14
+ export { ZumitoFramework, Command, Module, CommandArguments, FrameworkEvent, Translation, TranslationManager, ApiResponse, CommandType, ButtonPressed, TextFormatter, EmojiFallback, DatabaseConfigLoader, };
@@ -1,22 +1,217 @@
1
1
  import { CommandArgDefinition } from './CommandArgDefinition.js';
2
2
  import { CommandParameters } from './CommandParameters.js';
3
3
  import { SelectMenuParameters } from './SelectMenuParameters.js';
4
+ /**
5
+ * @name Command
6
+ * @description Base class for all commands
7
+ * @see {@link https://docs.zumito.ga/docs/custom/create-command}
8
+ */
4
9
  export declare abstract class Command {
10
+ /**
11
+ * @name name
12
+ * @description The name of the command. This is the name that will be used to execute the command. The framework will automatically set this to the name of the class in lowercase.
13
+ * @type {string}
14
+ * @default this.constructor.name.toLowerCase()
15
+ * @example
16
+ * ```ts
17
+ * export class PingCommand extends Command {
18
+ * name = 'ping';
19
+ * }
20
+ * ```
21
+ */
5
22
  name: string;
23
+ /**
24
+ * @name categories
25
+ * @description Array of strings of each category the command belongs to. This is used to group commands together in the help command.
26
+ * The framework will load the translations for each category from key `global.category.${category}`, so its recommended to use camelCase since this is the category key and not the category name.
27
+ * @type {string[]}
28
+ * @default []
29
+ * @example
30
+ * ```ts
31
+ * export class PingCommand extends Command {
32
+ * categories = ['utility', 'info'];
33
+ * }
34
+ * ```
35
+ */
6
36
  categories: string[];
37
+ /**
38
+ * @name aliases
39
+ * @description Array of strings of each alias the command has. This is used to execute the command with an alias.
40
+ * @type {string[]}
41
+ * @default []
42
+ * @example
43
+ * ```ts
44
+ * export class PingCommand extends Command {
45
+ * aliases = ['pong'];
46
+ * }
47
+ * ```
48
+ */
7
49
  aliases: string[];
50
+ /**
51
+ * @name examples
52
+ * @description Array of strings of each example of how to use the command. This is used to show examples of how to use the command in the help command.
53
+ * Do not include the prefix in the example.
54
+ * @type {string[]}
55
+ * @default []
56
+ * @example
57
+ * ```ts
58
+ * export class PingCommand extends Command {
59
+ * examples = ['ping', 'ping 100'];
60
+ * }
61
+ * ```
62
+ */
8
63
  examples: string[];
64
+ /**
65
+ * @name userPermissions
66
+ * @description Array of {@link https://discord.js.org/#/docs/main/stable/class/Permissions} of each permission the user needs to execute the command.
67
+ * @type {bigint[]}
68
+ * @default []
69
+ * @example
70
+ * ```ts
71
+ * export class ClearCommand extends Command {
72
+ * userPermissions = [Permissions.FLAGS.MANAGE_MESSAGES];
73
+ * }
74
+ * ```
75
+ * @see {@link https://discord.js.org/#/docs/main/stable/class/Permissions}
76
+ */
9
77
  userPermissions: bigint[];
78
+ /**
79
+ * @name botPermissions
80
+ * @description Array of {@link https://discord.js.org/#/docs/main/stable/class/Permissions} of each permission the bot needs to execute the command.
81
+ * @type {bigint[]}
82
+ * @default []
83
+ * @example
84
+ * ```ts
85
+ * export class BanCommand extends Command {
86
+ * botPermissions = [Permissions.FLAGS.BAN_MEMBERS];
87
+ * }
88
+ * ```
89
+ * @see {@link https://discord.js.org/#/docs/main/stable/class/Permissions}
90
+ */
10
91
  botPermissions: string[];
92
+ /**
93
+ * @name hidden
94
+ * @description Whether the command should be hidden from the help command.
95
+ * @type {boolean}
96
+ * @default false
97
+ * @example
98
+ * ```ts
99
+ * export class PingCommand extends Command {
100
+ * hidden = true;
101
+ * }
102
+ * ```
103
+ */
11
104
  hidden: boolean;
105
+ /**
106
+ * @name adminOnly
107
+ * @description Whether the command should only be available to the guild admins.
108
+ * @type {boolean}
109
+ * @default false
110
+ * @example
111
+ * ```ts
112
+ * export class PingCommand extends Command {
113
+ * adminOnly = true;
114
+ * }
115
+ * ```
116
+ */
12
117
  adminOnly: boolean;
118
+ /**
119
+ * @name nsfw
120
+ * @description Whether the command should only be available in nsfw channels.
121
+ * @type {boolean}
122
+ * @default false
123
+ * @example
124
+ * ```ts
125
+ * export class PingCommand extends Command {
126
+ * nsfw = true;
127
+ * }
128
+ * ```
129
+ */
13
130
  nsfw: boolean;
131
+ /**
132
+ * @name cooldown
133
+ * @description The cooldown in seconds for the command. This is used to prevent spamming the command or for command with high processing time.
134
+ * @type {number}
135
+ * @default 0
136
+ * @example
137
+ * ```ts
138
+ * export class PingCommand extends Command {
139
+ * cooldown = 5;
140
+ * }
141
+ * ```
142
+ */
14
143
  cooldown: number;
15
144
  slashCommand: boolean;
145
+ /**
146
+ * @name dm
147
+ * @description Whether the command should be available in dms.
148
+ * @type {boolean}
149
+ * @default false
150
+ * @example
151
+ * ```ts
152
+ * export class PingCommand extends Command {
153
+ * dm = true;
154
+ * }
155
+ * ```
156
+ */
16
157
  dm: boolean;
158
+ /**
159
+ * @name args
160
+ * @description Array of {@link CommandArgDefinition} of each argument the command has.
161
+ * @type {CommandArgDefinition[]}
162
+ * @default []
163
+ * @example
164
+ * ```ts
165
+ * export class PingCommand extends Command {
166
+ * args = [
167
+ * {
168
+ * name: 'number',
169
+ * type: 'number',
170
+ * required: true,
171
+ * },
172
+ * ];
173
+ * }
174
+ * ```
175
+ * @see {@link CommandArgDefinition}
176
+ */
17
177
  args: CommandArgDefinition[];
178
+ /**
179
+ * @name type
180
+ * @description The type of the command. This is used to determine how the command should be executed.
181
+ * @type {CommandType}
182
+ * @default CommandType.prefix
183
+ * @example
184
+ * ```ts
185
+ * export class PingCommand extends Command {
186
+ * type = CommandType.slash;
187
+ * }
188
+ * ```
189
+ * @example
190
+ * ```ts
191
+ * export class PingCommand extends Command {
192
+ * type = CommandType.any;
193
+ * }
194
+ * ```
195
+ * @example
196
+ * ```ts
197
+ * export class PingCommand extends Command {
198
+ * type = CommandType.separated;
199
+ * }
200
+ * ```
201
+ * @see {@link CommandType}
202
+ */
18
203
  type: string;
19
- constructor();
204
+ /**
205
+ * @name execute
206
+ * @description The function that is executed when the command is called.
207
+ * @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
+ */
20
215
  abstract execute({ message, interaction, args, client, framework, }: CommandParameters): void;
21
216
  executePrefixCommand({ message, interaction, args, client, framework, trans, }: CommandParameters): void;
22
217
  executeSlashCommand({ message, interaction, args, client, framework, trans, }: CommandParameters): void;
@@ -1,20 +1,204 @@
1
1
  import { CommandType } from './CommandType.js';
2
+ /**
3
+ * @name Command
4
+ * @description Base class for all commands
5
+ * @see {@link https://docs.zumito.ga/docs/custom/create-command}
6
+ */
2
7
  export class Command {
8
+ /**
9
+ * @name name
10
+ * @description The name of the command. This is the name that will be used to execute the command. The framework will automatically set this to the name of the class in lowercase.
11
+ * @type {string}
12
+ * @default this.constructor.name.toLowerCase()
13
+ * @example
14
+ * ```ts
15
+ * export class PingCommand extends Command {
16
+ * name = 'ping';
17
+ * }
18
+ * ```
19
+ */
3
20
  name = this.constructor.name.toLowerCase();
21
+ /**
22
+ * @name categories
23
+ * @description Array of strings of each category the command belongs to. This is used to group commands together in the help command.
24
+ * The framework will load the translations for each category from key `global.category.${category}`, so its recommended to use camelCase since this is the category key and not the category name.
25
+ * @type {string[]}
26
+ * @default []
27
+ * @example
28
+ * ```ts
29
+ * export class PingCommand extends Command {
30
+ * categories = ['utility', 'info'];
31
+ * }
32
+ * ```
33
+ */
4
34
  categories = [];
35
+ /**
36
+ * @name aliases
37
+ * @description Array of strings of each alias the command has. This is used to execute the command with an alias.
38
+ * @type {string[]}
39
+ * @default []
40
+ * @example
41
+ * ```ts
42
+ * export class PingCommand extends Command {
43
+ * aliases = ['pong'];
44
+ * }
45
+ * ```
46
+ */
5
47
  aliases = [];
48
+ /**
49
+ * @name examples
50
+ * @description Array of strings of each example of how to use the command. This is used to show examples of how to use the command in the help command.
51
+ * Do not include the prefix in the example.
52
+ * @type {string[]}
53
+ * @default []
54
+ * @example
55
+ * ```ts
56
+ * export class PingCommand extends Command {
57
+ * examples = ['ping', 'ping 100'];
58
+ * }
59
+ * ```
60
+ */
6
61
  examples = [];
62
+ /**
63
+ * @name userPermissions
64
+ * @description Array of {@link https://discord.js.org/#/docs/main/stable/class/Permissions} of each permission the user needs to execute the command.
65
+ * @type {bigint[]}
66
+ * @default []
67
+ * @example
68
+ * ```ts
69
+ * export class ClearCommand extends Command {
70
+ * userPermissions = [Permissions.FLAGS.MANAGE_MESSAGES];
71
+ * }
72
+ * ```
73
+ * @see {@link https://discord.js.org/#/docs/main/stable/class/Permissions}
74
+ */
7
75
  userPermissions = [];
76
+ /**
77
+ * @name botPermissions
78
+ * @description Array of {@link https://discord.js.org/#/docs/main/stable/class/Permissions} of each permission the bot needs to execute the command.
79
+ * @type {bigint[]}
80
+ * @default []
81
+ * @example
82
+ * ```ts
83
+ * export class BanCommand extends Command {
84
+ * botPermissions = [Permissions.FLAGS.BAN_MEMBERS];
85
+ * }
86
+ * ```
87
+ * @see {@link https://discord.js.org/#/docs/main/stable/class/Permissions}
88
+ */
8
89
  botPermissions = [];
90
+ /**
91
+ * @name hidden
92
+ * @description Whether the command should be hidden from the help command.
93
+ * @type {boolean}
94
+ * @default false
95
+ * @example
96
+ * ```ts
97
+ * export class PingCommand extends Command {
98
+ * hidden = true;
99
+ * }
100
+ * ```
101
+ */
9
102
  hidden = false;
103
+ /**
104
+ * @name adminOnly
105
+ * @description Whether the command should only be available to the guild admins.
106
+ * @type {boolean}
107
+ * @default false
108
+ * @example
109
+ * ```ts
110
+ * export class PingCommand extends Command {
111
+ * adminOnly = true;
112
+ * }
113
+ * ```
114
+ */
10
115
  adminOnly = false;
116
+ /**
117
+ * @name nsfw
118
+ * @description Whether the command should only be available in nsfw channels.
119
+ * @type {boolean}
120
+ * @default false
121
+ * @example
122
+ * ```ts
123
+ * export class PingCommand extends Command {
124
+ * nsfw = true;
125
+ * }
126
+ * ```
127
+ */
11
128
  nsfw = false;
129
+ /**
130
+ * @name cooldown
131
+ * @description The cooldown in seconds for the command. This is used to prevent spamming the command or for command with high processing time.
132
+ * @type {number}
133
+ * @default 0
134
+ * @example
135
+ * ```ts
136
+ * export class PingCommand extends Command {
137
+ * cooldown = 5;
138
+ * }
139
+ * ```
140
+ */
12
141
  cooldown = 0;
13
142
  slashCommand = false;
143
+ /**
144
+ * @name dm
145
+ * @description Whether the command should be available in dms.
146
+ * @type {boolean}
147
+ * @default false
148
+ * @example
149
+ * ```ts
150
+ * export class PingCommand extends Command {
151
+ * dm = true;
152
+ * }
153
+ * ```
154
+ */
14
155
  dm = false;
156
+ /**
157
+ * @name args
158
+ * @description Array of {@link CommandArgDefinition} of each argument the command has.
159
+ * @type {CommandArgDefinition[]}
160
+ * @default []
161
+ * @example
162
+ * ```ts
163
+ * export class PingCommand extends Command {
164
+ * args = [
165
+ * {
166
+ * name: 'number',
167
+ * type: 'number',
168
+ * required: true,
169
+ * },
170
+ * ];
171
+ * }
172
+ * ```
173
+ * @see {@link CommandArgDefinition}
174
+ */
15
175
  args = [];
176
+ /**
177
+ * @name type
178
+ * @description The type of the command. This is used to determine how the command should be executed.
179
+ * @type {CommandType}
180
+ * @default CommandType.prefix
181
+ * @example
182
+ * ```ts
183
+ * export class PingCommand extends Command {
184
+ * type = CommandType.slash;
185
+ * }
186
+ * ```
187
+ * @example
188
+ * ```ts
189
+ * export class PingCommand extends Command {
190
+ * type = CommandType.any;
191
+ * }
192
+ * ```
193
+ * @example
194
+ * ```ts
195
+ * export class PingCommand extends Command {
196
+ * type = CommandType.separated;
197
+ * }
198
+ * ```
199
+ * @see {@link CommandType}
200
+ */
16
201
  type = CommandType.prefix;
17
- constructor() { }
18
202
  executePrefixCommand({ message, interaction, args, client, framework, trans, }) {
19
203
  this.execute({ message, interaction, args, client, framework, trans });
20
204
  }
@@ -3,5 +3,5 @@ export interface CommandArgDefinition {
3
3
  name: string;
4
4
  optional: boolean;
5
5
  type: string;
6
- choices?: CommandChoiceDefinition[] | Function;
6
+ choices?: CommandChoiceDefinition[] | (() => CommandChoiceDefinition[]);
7
7
  }
@@ -1,6 +1,18 @@
1
1
  export declare const CommandType: {
2
+ /**
3
+ * The command is executed when the prefix is used. Running `executePrefixCommand` method or `execute` method as fallback.
4
+ */
2
5
  prefix: string;
6
+ /**
7
+ * The command is executed when the slash is used. Running `executeSlashCommand` method or `execute` method as fallback.
8
+ */
3
9
  slash: string;
10
+ /**
11
+ * The command is executed when the prefix or slash is used. Running `executeSlashCommand` or `executePrefixCommand` method respectively or `execute` method as fallback.
12
+ */
4
13
  separated: string;
14
+ /**
15
+ * The command is executed when the prefix or slash is used. Running always `execute` method.
16
+ */
5
17
  any: string;
6
18
  };
@@ -1,6 +1,18 @@
1
1
  export const CommandType = {
2
+ /**
3
+ * The command is executed when the prefix is used. Running `executePrefixCommand` method or `execute` method as fallback.
4
+ */
2
5
  prefix: 'prefix',
6
+ /**
7
+ * The command is executed when the slash is used. Running `executeSlashCommand` method or `execute` method as fallback.
8
+ */
3
9
  slash: 'slash',
10
+ /**
11
+ * The command is executed when the prefix or slash is used. Running `executeSlashCommand` or `executePrefixCommand` method respectively or `execute` method as fallback.
12
+ */
4
13
  separated: 'separated',
14
+ /**
15
+ * The command is executed when the prefix or slash is used. Running always `execute` method.
16
+ */
5
17
  any: 'any',
6
18
  };
@@ -1,4 +1,4 @@
1
- import { ButtonPressedParams } from './ButtonPressedParams';
1
+ import { ButtonPressedParams } from './ButtonPressedParams.js';
2
2
  export declare abstract class ButtonPressed {
3
- abstract buttonPressed({}: ButtonPressedParams): void;
3
+ abstract buttonPressed(buttonPressedParams: ButtonPressedParams): void;
4
4
  }
@@ -0,0 +1,4 @@
1
+ import { SelectMenuParameters } from '../SelectMenuParameters.js';
2
+ export declare abstract class SelectMenuSelected {
3
+ abstract selectMenu(selectMenuParameters: SelectMenuParameters): void;
4
+ }
@@ -0,0 +1,2 @@
1
+ export class SelectMenuSelected {
2
+ }
@@ -0,0 +1,70 @@
1
+ import { ZumitoFramework } from '../ZumitoFramework.js';
2
+ /**
3
+ * @name DatabaseModel
4
+ * @description Base class for all database models.
5
+ * @see {@link https://docs.zumito.ga/docs/custom/create-database-model}
6
+ */
7
+ export declare abstract class DatabaseModel {
8
+ readonly name: string;
9
+ framework: ZumitoFramework;
10
+ constructor(framework: ZumitoFramework);
11
+ /**
12
+ * @name getModel
13
+ * @description This method should return the model that will be used by the framework.
14
+ * @returns {any}
15
+ * @example
16
+ * ```ts
17
+ * getModel(schema) {
18
+ * return {
19
+ * name: { type: schema.String, required: true },
20
+ * age: { type: schema.Number, required: true },
21
+ * email: { type: schema.String, limit: 155, unique: true },
22
+ * approved: { type: schema.Boolean, default: false, index: true }
23
+ * joinedAt: { type: schema.Date, default: Date.now },
24
+ * };
25
+ * ```
26
+ * @see {@link https://docs.zumito.ga/docs/custom/create-database-model#model}
27
+ */
28
+ abstract getModel(schema: any): any;
29
+ /**
30
+ * @name define
31
+ * @description This method is called after all models are loaded. Here you can define relationships, validations, hooks, methods, etc.
32
+ * @param {any} model The model that was returned by the {@link DatabaseModel.getModel} method.
33
+ * @param {any} schema The schema of the database.
34
+ * @example
35
+ * Example of defining a relationship:
36
+ * ```ts
37
+ * define(model, models) {
38
+ * model.hasMany(models.SocialMediaUrl, {as: 'socialMediaUrl', foreignKey: 'userId'});
39
+ * }
40
+ * ```
41
+ * @example
42
+ * Example of defining a validation:
43
+ * ```ts
44
+ * define(model) {
45
+ * model.validatesPresenceOf('name', 'email')
46
+ * model.validatesUniquenessOf('email', {message: 'email is not unique'});
47
+ * model.validatesInclusionOf('gender', {in: ['male', 'female']});
48
+ * model.validatesNumericalityOf('age', {int: true});
49
+ * ```
50
+ * @example
51
+ * Example of defining a hook:
52
+ * ```ts
53
+ * define(model) {
54
+ * model.afterUpdate = function (next) {
55
+ * this.updated = new Date();
56
+ * this.save();
57
+ * next();
58
+ * };
59
+ * ```
60
+ * @example
61
+ * Example of defining a method:
62
+ * ```ts
63
+ * define(model) {
64
+ * model.prototype.getNameAndAge = function () {
65
+ * return this.name + ', ' + this.age;
66
+ * };
67
+ * ```
68
+ */
69
+ abstract define(model: any, models: any): void;
70
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @name DatabaseModel
3
+ * @description Base class for all database models.
4
+ * @see {@link https://docs.zumito.ga/docs/custom/create-database-model}
5
+ */
6
+ export class DatabaseModel {
7
+ // set name to the name of the class capitalized first letter
8
+ name = this.constructor.name.charAt(0).toUpperCase() +
9
+ this.constructor.name.slice(1);
10
+ framework;
11
+ constructor(framework) {
12
+ this.framework = framework;
13
+ }
14
+ }
@@ -1,4 +1,5 @@
1
1
  export interface FrameworkSettings {
2
+ database: any;
2
3
  logLevel?: number;
3
4
  debug?: boolean;
4
5
  discordClientOptions: {
@@ -7,5 +8,4 @@ export interface FrameworkSettings {
7
8
  clientId: string;
8
9
  };
9
10
  defaultPrefix?: string;
10
- mongoQueryString: string;
11
11
  }
@@ -1,12 +1,13 @@
1
1
  import { ZumitoFramework } from '../ZumitoFramework.js';
2
2
  import { Command } from './Command.js';
3
3
  import { FrameworkEvent } from './FrameworkEvent.js';
4
+ import { DatabaseModel } from './DatabaseModel.js';
4
5
  export declare abstract class Module {
5
6
  protected path: string;
6
7
  protected framework: ZumitoFramework;
7
8
  protected commands: Map<string, Command>;
8
9
  protected events: Map<string, FrameworkEvent>;
9
- protected models: Map<string, any>;
10
+ protected models: Array<DatabaseModel>;
10
11
  constructor(path: any, framework: any);
11
12
  initialize(): Promise<void>;
12
13
  registerCommands(): Promise<void>;
@@ -22,5 +23,5 @@ export declare abstract class Module {
22
23
  loadTranslationFile(subpath: string, file: string): Promise<any>;
23
24
  parseTranslation(path: string, lang: string, json: any): any;
24
25
  registerModels(): Promise<void>;
25
- getModels(): Map<string, any>;
26
+ getModels(): Array<DatabaseModel>;
26
27
  }
@@ -9,7 +9,7 @@ export class Module {
9
9
  framework;
10
10
  commands = new Map();
11
11
  events = new Map();
12
- models = new Map();
12
+ models = [];
13
13
  constructor(path, framework) {
14
14
  this.path = path;
15
15
  this.framework = framework;
@@ -19,8 +19,6 @@ export class Module {
19
19
  await this.registerEvents();
20
20
  await this.registerTranslations();
21
21
  await this.registerModels();
22
- // console.error('[🔄🔴 ] Error initializing module ' + this.constructor.name);
23
- // console.log(boxen(e + '\n' + e.stack, { padding: 1 }));
24
22
  }
25
23
  async registerCommands() {
26
24
  if (fs.existsSync(path.join(this.path, 'commands'))) {
@@ -218,18 +216,14 @@ export class Module {
218
216
  return;
219
217
  const files = fs.readdirSync(path.join(this.path, 'models'));
220
218
  for (const file of files) {
221
- if (file.endsWith('.json')) {
222
- const modelName = file.slice(0, -5).charAt(0).toUpperCase() +
223
- file.slice(0, -5).slice(1);
224
- const modelDefiniton = await import('file://' + `${this.path}/models/${file}`, {
225
- assert: {
226
- type: 'json',
227
- },
228
- }).catch((e) => {
229
- console.error(`[🔄🔴 ] Error loading model ${modelName} on module ${this.constructor.name}`);
230
- console.error(e, e.name, e.stack);
219
+ if (file.endsWith('.ts') || file.endsWith('.js')) {
220
+ let model = await import('file://' + `${this.path}/models/${file}`).catch((e) => {
221
+ console.error(`[🔄🔴 ] Error loading ${file.slice(0, -3)} model on module ${this.constructor.name}`);
222
+ console.error(e + '\n' + e.name + '\n' + e.stack);
231
223
  });
232
- this.models.set(modelName, modelDefiniton.default);
224
+ model = Object.values(model)[0];
225
+ model = new model();
226
+ this.models.push(model);
233
227
  }
234
228
  }
235
229
  }
@@ -0,0 +1,3 @@
1
+ export declare class DatabaseConfigLoader {
2
+ static getFromEnv(): any;
3
+ }
@@ -0,0 +1,43 @@
1
+ export class DatabaseConfigLoader {
2
+ static getFromEnv() {
3
+ const config = {};
4
+ if (!process.env.DATABASE_TYPE) {
5
+ console.warn('No database type specified. Using tingodb as default.\nIf this is intended, Set DATABASE_TYPE to "tingodb" in your .env file.');
6
+ config.type = 'tingodb';
7
+ }
8
+ else {
9
+ config.type = process.env.DATABASE_TYPE;
10
+ }
11
+ if (config.type == 'mysql') {
12
+ config.host = process.env.DATABASE_HOST;
13
+ config.port = process.env.DATABASE_PORT || 3306;
14
+ config.username = process.env.DATABASE_USERNAME;
15
+ config.password = process.env.DATABASE_PASSWORD;
16
+ config.database = process.env.DATABASE_NAME;
17
+ }
18
+ else if (config.type == 'sqlite') {
19
+ config.database = process.env.DATABASE_NAME;
20
+ }
21
+ else if (config.type == 'postgres') {
22
+ config.host = process.env.DATABASE_HOST;
23
+ config.port = process.env.DATABASE_PORT || 5432;
24
+ config.username = process.env.DATABASE_USERNAME;
25
+ config.password = process.env.DATABASE_PASSWORD;
26
+ config.database = process.env.DATABASE_NAME;
27
+ }
28
+ else if (config.type == 'mongodb') {
29
+ config.uri = process.env.DATABASE_URI;
30
+ }
31
+ else if (config.type == 'tingodb') {
32
+ config.database = './db/tingodb';
33
+ }
34
+ else if (config.type == 'couchdb') {
35
+ config.host = process.env.DATABASE_HOST;
36
+ config.port = process.env.DATABASE_PORT || 5984;
37
+ config.username = process.env.DATABASE_USERNAME;
38
+ config.password = process.env.DATABASE_PASSWORD;
39
+ config.database = process.env.DATABASE_NAME;
40
+ }
41
+ return config;
42
+ }
43
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zumito-framework",
3
- "version": "1.1.58",
3
+ "version": "1.1.60",
4
4
  "description": "Discord.js bot framework",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -11,6 +11,7 @@
11
11
  "scripts": {
12
12
  "test": "echo \"Error: no test specified\" && exit 1",
13
13
  "build": "tsc",
14
+ "build-watch": "tsc -w",
14
15
  "lint": "eslint .",
15
16
  "publish-npm": "npm publish",
16
17
  "docs": "typedoc --out docs src"
@@ -22,6 +23,7 @@
22
23
  "autocorrect": "^1.2.0",
23
24
  "better-logging": "^5.0.0",
24
25
  "boxen": "^7.0.0",
26
+ "canario": "^1.0.1",
25
27
  "chalk": "^4.1.2",
26
28
  "chokidar": "^3.5.3",
27
29
  "cookie-parser": "^1.4.6",
@@ -30,7 +32,8 @@
30
32
  "error-stack-parser": "^2.1.4",
31
33
  "express": "^4.18.1",
32
34
  "leven": "^4.0.0",
33
- "mongoose": "^6.6.5"
35
+ "mongoose": "^6.6.5",
36
+ "tingodb": "^0.6.1"
34
37
  },
35
38
  "devDependencies": {
36
39
  "@types/node": "^18.7.16",
@@ -1,14 +0,0 @@
1
- {
2
- "id": "string",
3
- "command": {
4
- "command": "string",
5
- "args": {
6
- "type": "array"
7
- }
8
- },
9
- "error": {
10
- "title": "string",
11
- "message": "string",
12
- "stacktrace": "string"
13
- }
14
- }
@@ -1,23 +0,0 @@
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
- }