zumito-framework 1.21.0 → 1.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ZumitoFramework.d.ts +9 -3
- package/dist/ZumitoFramework.js +54 -15
- package/dist/definitions/Module.d.ts +1 -3
- package/dist/definitions/Module.js +34 -14
- package/dist/definitions/settings/FrameworkSettings.d.ts +13 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +3 -1
- package/dist/launcher.js +0 -2
- package/dist/modules/core/baseModule/events/discord/MessageCreate.js +2 -0
- package/dist/services/handlers/ErrorHandler.d.ts +2 -0
- package/dist/services/handlers/InteractionHandler.js +2 -0
- package/dist/services/managers/CommandManager.d.ts +2 -2
- package/dist/services/managers/CommandManager.js +31 -99
- package/dist/services/managers/ModuleManager.js +0 -13
- package/dist/services/managers/TranslationManager.js +18 -26
- package/dist/services/utilities/EnvValidator.js +4 -2
- package/dist/services/utilities/FileWatcher.d.ts +10 -0
- package/dist/services/utilities/FileWatcher.js +32 -0
- package/dist/services/utilities/GuildDataGetter.d.ts +1 -1
- package/dist/services/utilities/GuildDataGetter.js +26 -0
- package/dist/testing/createTestFramework.d.ts +1 -0
- package/dist/testing/createTestFramework.js +49 -0
- package/package.json +3 -3
|
@@ -10,6 +10,7 @@ import { ModuleManager } from './services/managers/ModuleManager.js';
|
|
|
10
10
|
import { Route } from './definitions/Route.js';
|
|
11
11
|
import { Db } from 'mongodb';
|
|
12
12
|
import { MongoService } from './services/MongoService.js';
|
|
13
|
+
import { DatabaseManager } from 'zumito-db';
|
|
13
14
|
/**
|
|
14
15
|
* @class ZumitoFramework
|
|
15
16
|
* @description The main class of the framework.
|
|
@@ -70,15 +71,20 @@ export declare class ZumitoFramework {
|
|
|
70
71
|
/**
|
|
71
72
|
* The MongoDB service instance.
|
|
72
73
|
* @type {MongoService}
|
|
73
|
-
* @
|
|
74
|
+
* @deprecated Use `framework.db` (DatabaseManager from zumito-db) instead.
|
|
74
75
|
*/
|
|
75
76
|
mongoService: MongoService;
|
|
76
77
|
/**
|
|
77
78
|
* The MongoDB database instance (shortcut).
|
|
78
79
|
* @type {Db}
|
|
79
|
-
* @
|
|
80
|
+
* @deprecated Use `framework.db.getRepository(Model).find(...)` instead.
|
|
80
81
|
*/
|
|
81
82
|
database: Db;
|
|
83
|
+
/**
|
|
84
|
+
* The new zumito-db DatabaseManager instance.
|
|
85
|
+
* @type {DatabaseManager}
|
|
86
|
+
*/
|
|
87
|
+
db: DatabaseManager;
|
|
82
88
|
/**
|
|
83
89
|
* The ExpressJS app instance.
|
|
84
90
|
* @type {express.Application}
|
|
@@ -162,7 +168,7 @@ export declare class ZumitoFramework {
|
|
|
162
168
|
*
|
|
163
169
|
* @deprecated
|
|
164
170
|
*/
|
|
165
|
-
getGuildSettings(guildId: string): Promise<
|
|
171
|
+
getGuildSettings(guildId: string): Promise<any>;
|
|
166
172
|
/**
|
|
167
173
|
* @deprecated
|
|
168
174
|
*/
|
package/dist/ZumitoFramework.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as url from 'url';
|
|
3
|
-
import { Client, } from 'discord.js';
|
|
3
|
+
import { Client, Events, } from 'discord.js';
|
|
4
4
|
import { ApiResponse } from './definitions/api/ApiResponse.js';
|
|
5
5
|
import { EventEmitter } from "tseep";
|
|
6
6
|
import { StatusManager } from './services/managers/StatusManager.js';
|
|
@@ -23,6 +23,7 @@ import { ErrorHandler } from './services/handlers/ErrorHandler.js';
|
|
|
23
23
|
import { ErrorType } from './definitions/ErrorType.js';
|
|
24
24
|
import { MongoService } from './services/MongoService.js';
|
|
25
25
|
import { registerDefaultExecutionRules } from './modules/core/baseModule/defaultRules.js';
|
|
26
|
+
import { DatabaseManager } from 'zumito-db';
|
|
26
27
|
// import better-logging
|
|
27
28
|
betterLogging(console);
|
|
28
29
|
/**
|
|
@@ -85,15 +86,20 @@ export class ZumitoFramework {
|
|
|
85
86
|
/**
|
|
86
87
|
* The MongoDB service instance.
|
|
87
88
|
* @type {MongoService}
|
|
88
|
-
* @
|
|
89
|
+
* @deprecated Use `framework.db` (DatabaseManager from zumito-db) instead.
|
|
89
90
|
*/
|
|
90
91
|
mongoService;
|
|
91
92
|
/**
|
|
92
93
|
* The MongoDB database instance (shortcut).
|
|
93
94
|
* @type {Db}
|
|
94
|
-
* @
|
|
95
|
+
* @deprecated Use `framework.db.getRepository(Model).find(...)` instead.
|
|
95
96
|
*/
|
|
96
97
|
database;
|
|
98
|
+
/**
|
|
99
|
+
* The new zumito-db DatabaseManager instance.
|
|
100
|
+
* @type {DatabaseManager}
|
|
101
|
+
*/
|
|
102
|
+
db;
|
|
97
103
|
/**
|
|
98
104
|
* The ExpressJS app instance.
|
|
99
105
|
* @type {express.Application}
|
|
@@ -140,6 +146,7 @@ export class ZumitoFramework {
|
|
|
140
146
|
ServiceContainer.addService(TranslationManager, [], true, this.translations);
|
|
141
147
|
ServiceContainer.addService(CommandManager, [], true, this.commands);
|
|
142
148
|
ServiceContainer.addService(EventManager, [], true, this.eventManager);
|
|
149
|
+
ServiceContainer.addService(SlashCommandRefresher, [], true, new SlashCommandRefresher(this));
|
|
143
150
|
if (settings.logLevel) {
|
|
144
151
|
console.logLevel = settings.logLevel;
|
|
145
152
|
}
|
|
@@ -167,6 +174,8 @@ export class ZumitoFramework {
|
|
|
167
174
|
this.eventManager.addEventEmitter('framework', this.eventEmitter);
|
|
168
175
|
await this.registerModules();
|
|
169
176
|
registerDefaultExecutionRules();
|
|
177
|
+
// Ensure all model schemas (from config + module auto-load) are created
|
|
178
|
+
await this.db.ensureSchemas();
|
|
170
179
|
await this.refreshSlashCommands();
|
|
171
180
|
this.startApiServer();
|
|
172
181
|
if (this.settings.statusOptions) {
|
|
@@ -179,23 +188,54 @@ export class ZumitoFramework {
|
|
|
179
188
|
}
|
|
180
189
|
async initializeDatabase() {
|
|
181
190
|
const mongoUri = this.settings?.mongoQueryString || process.env.MONGO_URI;
|
|
182
|
-
|
|
183
|
-
|
|
191
|
+
const dbSettings = this.settings.database;
|
|
192
|
+
let config;
|
|
193
|
+
if (dbSettings?.default) {
|
|
194
|
+
config = {
|
|
195
|
+
default: dbSettings.default,
|
|
196
|
+
drivers: dbSettings.drivers || {},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
else if (mongoUri) {
|
|
200
|
+
const match = mongoUri.match(/\/([^/?]+)(\?|$)/);
|
|
201
|
+
const dbName = match ? match[1] : 'zumito';
|
|
202
|
+
config = {
|
|
203
|
+
default: 'mongo',
|
|
204
|
+
drivers: { mongo: { uri: mongoUri, database: dbName } },
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
console.error('[🗄️🔴] No database configured.');
|
|
209
|
+
console.error(' Set database.default in zumito.config.ts (memory, tingo, mongo, sqlite)');
|
|
210
|
+
console.error(' or set MONGO_URI / mongoQueryString for MongoDB.');
|
|
184
211
|
process.exit(1);
|
|
185
212
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
this.
|
|
213
|
+
if (this.settings.models) {
|
|
214
|
+
config.models = this.settings.models;
|
|
215
|
+
}
|
|
216
|
+
this.db = new DatabaseManager();
|
|
190
217
|
try {
|
|
191
|
-
await this.
|
|
192
|
-
|
|
193
|
-
console.log(
|
|
218
|
+
await this.db.connect(config);
|
|
219
|
+
ServiceContainer.addService(DatabaseManager, [], true, this.db);
|
|
220
|
+
console.log(`[🗄️🟢] Database connected (driver: ${config.default})`);
|
|
194
221
|
}
|
|
195
222
|
catch (err) {
|
|
196
|
-
console.error(
|
|
223
|
+
console.error(`[🗄️🔴] Database connection error: ${err.message}`);
|
|
197
224
|
process.exit(1);
|
|
198
225
|
}
|
|
226
|
+
// Backward compat: only set up mongoService for mongo driver
|
|
227
|
+
if (config.default === 'mongo' && mongoUri) {
|
|
228
|
+
const driver = this.db.getDriver();
|
|
229
|
+
this.database = driver.raw;
|
|
230
|
+
const dbName = config.drivers.mongo?.database || 'zumito';
|
|
231
|
+
this.mongoService = new MongoService(mongoUri, dbName);
|
|
232
|
+
this.mongoService.db = this.database;
|
|
233
|
+
this.mongoService.client = driver.client;
|
|
234
|
+
}
|
|
235
|
+
// Apply migrations if configured
|
|
236
|
+
if (this.settings.database?.migrations && this.settings.database.migrations.length > 0) {
|
|
237
|
+
await this.db.migrator.latest(this.settings.database.migrations);
|
|
238
|
+
}
|
|
199
239
|
}
|
|
200
240
|
/**
|
|
201
241
|
* Initializes and starts the API server using ExpressJS.
|
|
@@ -306,7 +346,6 @@ export class ZumitoFramework {
|
|
|
306
346
|
await this.modules.instanceModule(module, path.join(modulesFolder, moduleName), moduleName);
|
|
307
347
|
}
|
|
308
348
|
async registerBundle(bundlePath, bundleOptions) {
|
|
309
|
-
console.log(bundlePath);
|
|
310
349
|
const bundle = await this.modules.loadModuleFile(bundlePath);
|
|
311
350
|
const bundleName = path.basename(bundlePath);
|
|
312
351
|
await this.modules.instanceModule(bundle, bundlePath, bundleName, bundleOptions);
|
|
@@ -323,7 +362,7 @@ export class ZumitoFramework {
|
|
|
323
362
|
this.client.login(this.settings.discordClientOptions.token);
|
|
324
363
|
ServiceContainer.addService(Client, [], true, this.client);
|
|
325
364
|
await new Promise((resolve) => {
|
|
326
|
-
this.client.on(
|
|
365
|
+
this.client.on(Events.ClientReady, () => {
|
|
327
366
|
// Bot emoji
|
|
328
367
|
console.log('[🤖🟢] Discord client ready');
|
|
329
368
|
resolve();
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ZumitoFramework } from '../ZumitoFramework.js';
|
|
2
2
|
import { Command } from './commands/Command.js';
|
|
3
3
|
import { FrameworkEvent } from './FrameworkEvent.js';
|
|
4
|
-
import { CommandManager } from '../services/managers/CommandManager.js';
|
|
5
4
|
import { ModuleParameters } from './parameters/ModuleParameters.js';
|
|
6
5
|
import { ErrorHandler } from '../services/handlers/ErrorHandler.js';
|
|
7
6
|
export type ModuleRequeriments = {
|
|
@@ -13,10 +12,8 @@ export declare abstract class Module {
|
|
|
13
12
|
protected path: string;
|
|
14
13
|
protected parameters: ModuleParameters;
|
|
15
14
|
protected framework: ZumitoFramework;
|
|
16
|
-
protected commands: CommandManager;
|
|
17
15
|
protected events: Map<string, FrameworkEvent>;
|
|
18
16
|
static requeriments: ModuleRequeriments;
|
|
19
|
-
protected commandManager: CommandManager;
|
|
20
17
|
protected errorHandler: ErrorHandler;
|
|
21
18
|
constructor(path: any, parameters?: ModuleParameters);
|
|
22
19
|
initialize(): Promise<void>;
|
|
@@ -29,6 +26,7 @@ export declare abstract class Module {
|
|
|
29
26
|
parseEventArgs(args: any[]): any;
|
|
30
27
|
getEvents(): Map<string, FrameworkEvent>;
|
|
31
28
|
registerTranslations(subpath?: string): Promise<void>;
|
|
29
|
+
registerModels(): Promise<void>;
|
|
32
30
|
registerRoutes(): Promise<void>;
|
|
33
31
|
registerRoutesFolder(folder: string): Promise<void>;
|
|
34
32
|
}
|
|
@@ -2,24 +2,21 @@ import { ZumitoFramework } from '../ZumitoFramework.js';
|
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { ButtonInteraction, CommandInteraction, ModalSubmitInteraction, StringSelectMenuInteraction, } from 'discord.js';
|
|
5
|
-
import { CommandManager } from '../services/managers/CommandManager.js';
|
|
6
5
|
import { ServiceContainer } from '../services/ServiceContainer.js';
|
|
7
6
|
import { ErrorHandler } from '../services/handlers/ErrorHandler.js';
|
|
8
7
|
import { ErrorType } from './ErrorType.js';
|
|
8
|
+
import { getModelMetadata } from 'zumito-db';
|
|
9
9
|
export class Module {
|
|
10
10
|
path;
|
|
11
11
|
parameters;
|
|
12
12
|
framework;
|
|
13
|
-
commands;
|
|
14
13
|
events = new Map();
|
|
15
14
|
static requeriments;
|
|
16
|
-
commandManager;
|
|
17
15
|
errorHandler;
|
|
18
16
|
constructor(path, parameters) {
|
|
19
17
|
this.path = path;
|
|
20
18
|
this.parameters = parameters;
|
|
21
19
|
this.framework = ServiceContainer.getService(ZumitoFramework);
|
|
22
|
-
this.commands = new CommandManager(this.framework);
|
|
23
20
|
this.errorHandler = ServiceContainer.getService(ErrorHandler);
|
|
24
21
|
}
|
|
25
22
|
async initialize() {
|
|
@@ -27,26 +24,21 @@ export class Module {
|
|
|
27
24
|
await this.registerEvents();
|
|
28
25
|
await this.registerTranslations();
|
|
29
26
|
await this.registerRoutes();
|
|
27
|
+
await this.registerModels();
|
|
30
28
|
}
|
|
31
29
|
async onAllReady() {
|
|
32
30
|
}
|
|
33
31
|
async registerCommands() {
|
|
34
32
|
const commandsFolder = path.join(this.path, 'commands');
|
|
35
33
|
if (fs.existsSync(commandsFolder)) {
|
|
36
|
-
await this.commands.loadCommandsFolder(commandsFolder);
|
|
37
|
-
// register watcher
|
|
34
|
+
await this.framework.commands.loadCommandsFolder(commandsFolder);
|
|
38
35
|
if (process.env.DEBUG) {
|
|
39
|
-
|
|
40
|
-
Debug only cause in prod environment commands should't be changed.
|
|
41
|
-
Appart from that, esm module cache invalidation is not working properly
|
|
42
|
-
and can cause memory leaks and crashes.
|
|
43
|
-
*/
|
|
44
|
-
this.commands.watchCommandsFolder(commandsFolder);
|
|
36
|
+
this.framework.commands.watchCommandsFolder(commandsFolder);
|
|
45
37
|
}
|
|
46
38
|
}
|
|
47
39
|
}
|
|
48
40
|
getCommands() {
|
|
49
|
-
return this.commands.getAll();
|
|
41
|
+
return this.framework.commands.getAll();
|
|
50
42
|
}
|
|
51
43
|
async registerEvents() {
|
|
52
44
|
if (!fs.existsSync(path.join(this.path, 'events')))
|
|
@@ -55,7 +47,6 @@ export class Module {
|
|
|
55
47
|
for (const file of files) {
|
|
56
48
|
// if file is folder
|
|
57
49
|
if (fs.lstatSync(path.join(this.path, 'events', file)).isDirectory()) {
|
|
58
|
-
console.log('registering events folder ' + file);
|
|
59
50
|
this.registerEventsFolder(file);
|
|
60
51
|
}
|
|
61
52
|
}
|
|
@@ -115,6 +106,35 @@ export class Module {
|
|
|
115
106
|
return;
|
|
116
107
|
this.framework.translations.registerTranslationsFromFolder(path.join(this.path, 'translations', subpath), '', process.env.DEBUG ? true : false);
|
|
117
108
|
}
|
|
109
|
+
async registerModels() {
|
|
110
|
+
const modelsFolder = path.join(this.path, 'models');
|
|
111
|
+
if (!fs.existsSync(modelsFolder))
|
|
112
|
+
return;
|
|
113
|
+
const db = this.framework.db;
|
|
114
|
+
if (!db)
|
|
115
|
+
return;
|
|
116
|
+
const files = fs.readdirSync(modelsFolder);
|
|
117
|
+
for (const file of files) {
|
|
118
|
+
if (file.endsWith('.d.ts'))
|
|
119
|
+
continue;
|
|
120
|
+
if (file.endsWith('.js') || file.endsWith('.ts')) {
|
|
121
|
+
const mod = await import('file://' + path.join(modelsFolder, file)).catch((e) => {
|
|
122
|
+
this.errorHandler.handleError(e, {
|
|
123
|
+
type: ErrorType.ModuleLoad,
|
|
124
|
+
moduleName: this.constructor.name,
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
if (!mod)
|
|
128
|
+
continue;
|
|
129
|
+
// Register every exported class that has @Collection metadata
|
|
130
|
+
for (const exportValue of Object.values(mod)) {
|
|
131
|
+
if (typeof exportValue === 'function' && getModelMetadata(exportValue)) {
|
|
132
|
+
db.registerModel(exportValue);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
118
138
|
async registerRoutes() {
|
|
119
139
|
const folderPath = path.join(this.path, 'routes');
|
|
120
140
|
if (fs.existsSync(folderPath)) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ModuleParameters } from "../parameters/ModuleParameters";
|
|
2
2
|
import { StatusManagerOptions } from "../StatusManagerOptions";
|
|
3
|
+
import type { DatabaseConfig } from 'zumito-db';
|
|
3
4
|
export interface FrameworkSettings {
|
|
4
|
-
mongoQueryString
|
|
5
|
+
mongoQueryString?: string;
|
|
5
6
|
logLevel?: number;
|
|
6
7
|
debug?: boolean;
|
|
7
8
|
discordClientOptions: {
|
|
@@ -25,4 +26,15 @@ export interface FrameworkSettings {
|
|
|
25
26
|
port?: number;
|
|
26
27
|
disableNotFoundHandler?: boolean;
|
|
27
28
|
};
|
|
29
|
+
/**
|
|
30
|
+
* New database configuration for zumito-db.
|
|
31
|
+
* If omitted, falls back to `mongoQueryString` with MongoDB driver.
|
|
32
|
+
*/
|
|
33
|
+
database?: Partial<DatabaseConfig> & {
|
|
34
|
+
migrations?: any[];
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Model classes to register with zumito-db.
|
|
38
|
+
*/
|
|
39
|
+
models?: any[];
|
|
28
40
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -32,10 +32,14 @@ import { ErrorType } from './definitions/ErrorType.js';
|
|
|
32
32
|
import { InviteUrlGenerator } from './services/utilities/InviteUrlGenerator.js';
|
|
33
33
|
import { PrefixResolver } from './services/utilities/PrefixResolver.js';
|
|
34
34
|
import { CommandExecutionChecker } from './services/CommandExecutionChecker.js';
|
|
35
|
+
import { DatabaseManager } from 'zumito-db';
|
|
36
|
+
export { Collection, Field, HasMany, BelongsTo, HasOne, Migration, Repository, QueryBuilder } from 'zumito-db';
|
|
37
|
+
export type { CollectionOptions, FieldOptions, HasManyOptions, BelongsToOptions, HasOneOptions } from 'zumito-db';
|
|
38
|
+
export type { FieldType, Operator, WhereClause, SortClause, QueryIR, FieldMetadata, RelationMetadata, ModelMetadata, DriverConfig, DatabaseConfig, DatabaseDriver } from 'zumito-db';
|
|
35
39
|
export type { CommandExecutionRule, CommandExecutionContext, CommandExecutionCheck, CommandExecutionType } from './definitions/CommandExecutionRule.js';
|
|
36
40
|
export { ModalSubmitParameters } from './definitions/parameters/ModalSubmitParameters.js';
|
|
37
41
|
export { CommandBinds } from './definitions/commands/CommandBinds.js';
|
|
38
42
|
export { Injectable } from './definitions/decorators/Injectable.decorator.js';
|
|
39
43
|
export { LauncherConfig } from './definitions/config/LauncherConfig.js';
|
|
40
44
|
export { ModuleParameters } from './definitions/parameters/ModuleParameters.js';
|
|
41
|
-
export { ZumitoFramework, FrameworkSettings, Command, Module, CommandParameters, CommandArguments, FrameworkEvent, Translation, TranslationManager, ApiResponse, SelectMenuParameters, CommandType, CommandArgDefinition, CommandChoiceDefinition, ButtonPressed, ButtonPressedParams, TextFormatter, EmojiFallback, DatabaseConfigLoader, PresenceDataRule, RuledPresenceData, StatusManagerOptions, discord, EventParameters, ServiceContainer, GuildDataGetter, SlashCommandRefresher, CommandParser, ErrorHandler, ErrorType, Route, RouteMethod, InteractionHandler, CommandManager, InviteUrlGenerator, PrefixResolver, CommandExecutionChecker, };
|
|
45
|
+
export { ZumitoFramework, FrameworkSettings, Command, Module, CommandParameters, CommandArguments, FrameworkEvent, Translation, TranslationManager, ApiResponse, SelectMenuParameters, CommandType, CommandArgDefinition, CommandChoiceDefinition, ButtonPressed, ButtonPressedParams, TextFormatter, EmojiFallback, DatabaseConfigLoader, PresenceDataRule, RuledPresenceData, StatusManagerOptions, discord, EventParameters, ServiceContainer, GuildDataGetter, SlashCommandRefresher, CommandParser, ErrorHandler, ErrorType, Route, RouteMethod, InteractionHandler, CommandManager, InviteUrlGenerator, PrefixResolver, CommandExecutionChecker, DatabaseManager, };
|
package/dist/index.js
CHANGED
|
@@ -25,6 +25,8 @@ import { ErrorType } from './definitions/ErrorType.js';
|
|
|
25
25
|
import { InviteUrlGenerator } from './services/utilities/InviteUrlGenerator.js';
|
|
26
26
|
import { PrefixResolver } from './services/utilities/PrefixResolver.js';
|
|
27
27
|
import { CommandExecutionChecker } from './services/CommandExecutionChecker.js';
|
|
28
|
+
import { DatabaseManager } from 'zumito-db';
|
|
29
|
+
export { Collection, Field, HasMany, BelongsTo, HasOne, Migration, Repository, QueryBuilder } from 'zumito-db';
|
|
28
30
|
export { Injectable } from './definitions/decorators/Injectable.decorator.js';
|
|
29
31
|
ServiceContainer.addService(TextFormatter, []);
|
|
30
32
|
ServiceContainer.addService(EmojiFallback, [discord.Client.name, TranslationManager.name]);
|
|
@@ -37,4 +39,4 @@ ServiceContainer.addService(InviteUrlGenerator, []);
|
|
|
37
39
|
ServiceContainer.addService(PrefixResolver, []);
|
|
38
40
|
ServiceContainer.addService(CommandExecutionChecker, [], true);
|
|
39
41
|
ServiceContainer.addService(ErrorHandler, ['ZumitoFramework']);
|
|
40
|
-
export { ZumitoFramework, Command, Module, CommandArguments, FrameworkEvent, Translation, TranslationManager, ApiResponse, CommandType, ButtonPressed, TextFormatter, EmojiFallback, DatabaseConfigLoader, discord, ServiceContainer, GuildDataGetter, SlashCommandRefresher, CommandParser, ErrorHandler, ErrorType, Route, RouteMethod, InteractionHandler, CommandManager, InviteUrlGenerator, PrefixResolver, CommandExecutionChecker, };
|
|
42
|
+
export { ZumitoFramework, Command, Module, CommandArguments, FrameworkEvent, Translation, TranslationManager, ApiResponse, CommandType, ButtonPressed, TextFormatter, EmojiFallback, DatabaseConfigLoader, discord, ServiceContainer, GuildDataGetter, SlashCommandRefresher, CommandParser, ErrorHandler, ErrorType, Route, RouteMethod, InteractionHandler, CommandManager, InviteUrlGenerator, PrefixResolver, CommandExecutionChecker, DatabaseManager, };
|
package/dist/launcher.js
CHANGED
|
@@ -12,7 +12,6 @@ dotenv.config();
|
|
|
12
12
|
const REQUIRED_ENV_VARS = {
|
|
13
13
|
DISCORD_TOKEN: 'Discord Bot Token',
|
|
14
14
|
DISCORD_CLIENT_ID: 'Discord Client ID',
|
|
15
|
-
MONGO_URI: 'MongoDB connection URI',
|
|
16
15
|
};
|
|
17
16
|
EnvValidator.validate(REQUIRED_ENV_VARS);
|
|
18
17
|
const defaultConfig = {
|
|
@@ -22,7 +21,6 @@ const defaultConfig = {
|
|
|
22
21
|
clientId: process.env.DISCORD_CLIENT_ID,
|
|
23
22
|
},
|
|
24
23
|
defaultPrefix: process.env.BOT_PREFIX || "z-",
|
|
25
|
-
mongoQueryString: process.env.MONGO_URI,
|
|
26
24
|
logLevel: parseInt(process.env.LOGLEVEL || "3"),
|
|
27
25
|
};
|
|
28
26
|
const configFilePath = path.join(process.cwd(), 'zumito.config.ts');
|
|
@@ -95,6 +95,7 @@ export class MessageCreate extends FrameworkEvent {
|
|
|
95
95
|
errorHandler.handleError(error, {
|
|
96
96
|
command: commandInstance,
|
|
97
97
|
type: ErrorType.CommandRun,
|
|
98
|
+
message,
|
|
98
99
|
});
|
|
99
100
|
message.reply({
|
|
100
101
|
content: "An error ocurred while running this command.",
|
|
@@ -118,6 +119,7 @@ export class MessageCreate extends FrameworkEvent {
|
|
|
118
119
|
errorHandler.handleError(error, {
|
|
119
120
|
command: commandInstance,
|
|
120
121
|
type: ErrorType.CommandRun,
|
|
122
|
+
message,
|
|
121
123
|
});
|
|
122
124
|
message.reply({
|
|
123
125
|
content: "An error ocurred while running this command.",
|
|
@@ -8,6 +8,8 @@ type BaseErrorOptions = {
|
|
|
8
8
|
type CommandErrorOptions = BaseErrorOptions & {
|
|
9
9
|
type: ErrorType.CommandInstance | ErrorType.CommandLoad | ErrorType.CommandRun;
|
|
10
10
|
command: Command;
|
|
11
|
+
interaction?: any;
|
|
12
|
+
message?: any;
|
|
11
13
|
};
|
|
12
14
|
type ApiErrorOptions = BaseErrorOptions & {
|
|
13
15
|
type: ErrorType.Api;
|
|
@@ -128,6 +128,7 @@ export class InteractionHandler {
|
|
|
128
128
|
this.errorHandler.handleError(error, {
|
|
129
129
|
command: commandInstance,
|
|
130
130
|
type: ErrorType.CommandRun,
|
|
131
|
+
interaction,
|
|
131
132
|
});
|
|
132
133
|
interaction.reply({
|
|
133
134
|
content: "An error ocurred while running this command.",
|
|
@@ -139,6 +140,7 @@ export class InteractionHandler {
|
|
|
139
140
|
this.errorHandler.handleError(error, {
|
|
140
141
|
command: commandInstance,
|
|
141
142
|
type: ErrorType.CommandRun,
|
|
143
|
+
interaction,
|
|
142
144
|
});
|
|
143
145
|
interaction.reply({
|
|
144
146
|
content: "An error ocurred while running this command.",
|
|
@@ -7,6 +7,7 @@ export declare class CommandManager {
|
|
|
7
7
|
protected commands: Map<string, Command>;
|
|
8
8
|
protected framework: ZumitoFramework;
|
|
9
9
|
protected errorHandler: ErrorHandler;
|
|
10
|
+
private importCounters;
|
|
10
11
|
constructor(framework: any);
|
|
11
12
|
set(name: string, command: Command): void;
|
|
12
13
|
get(name: string): Command;
|
|
@@ -22,7 +23,7 @@ export declare class CommandManager {
|
|
|
22
23
|
* @param filePath - Absolute path to command file
|
|
23
24
|
* @returns {Promise<Command>}
|
|
24
25
|
*/
|
|
25
|
-
loadCommandFile(filePath: string): Promise<any>;
|
|
26
|
+
loadCommandFile(filePath: string, silent?: boolean): Promise<any>;
|
|
26
27
|
/**
|
|
27
28
|
* Load all command files from a folder
|
|
28
29
|
* @async
|
|
@@ -40,5 +41,4 @@ export declare class CommandManager {
|
|
|
40
41
|
* @returns {Promise<Map<string, Command>>}
|
|
41
42
|
*/
|
|
42
43
|
watchCommandsFolder(folderPath: string): void;
|
|
43
|
-
refreshSlashCommands(): Promise<void>;
|
|
44
44
|
}
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
-
import * as chokidar from 'chokidar';
|
|
3
2
|
import path from "path";
|
|
4
|
-
import boxen from "boxen";
|
|
5
3
|
import fs from 'fs';
|
|
6
|
-
import { REST, Routes, SlashCommandBuilder } from "discord.js";
|
|
7
|
-
import { CommandType } from "../../definitions/commands/CommandType.js";
|
|
8
4
|
import { ErrorHandler } from "../handlers/ErrorHandler";
|
|
9
5
|
import { ServiceContainer } from "../ServiceContainer";
|
|
10
6
|
import { ErrorType } from "../../definitions/ErrorType";
|
|
7
|
+
import { FileWatcher } from "../utilities/FileWatcher.js";
|
|
11
8
|
import 'reflect-metadata';
|
|
12
9
|
export class CommandManager {
|
|
13
10
|
commands;
|
|
14
11
|
framework;
|
|
15
12
|
errorHandler;
|
|
13
|
+
importCounters = new Map();
|
|
16
14
|
constructor(framework) {
|
|
17
15
|
this.commands = new Map;
|
|
18
16
|
this.errorHandler = ServiceContainer.getService(ErrorHandler);
|
|
@@ -40,15 +38,15 @@ export class CommandManager {
|
|
|
40
38
|
* @param filePath - Absolute path to command file
|
|
41
39
|
* @returns {Promise<Command>}
|
|
42
40
|
*/
|
|
43
|
-
async loadCommandFile(filePath) {
|
|
44
|
-
let loaded = false;
|
|
45
|
-
// Validate file has .ts or .js extension
|
|
41
|
+
async loadCommandFile(filePath, silent = false) {
|
|
46
42
|
if (!filePath.endsWith('.js') && !filePath.endsWith('.ts')) {
|
|
47
|
-
|
|
43
|
+
return;
|
|
48
44
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
const counter = (this.importCounters.get(filePath) || 0) + 1;
|
|
46
|
+
this.importCounters.set(filePath, counter);
|
|
47
|
+
const baseName = path.basename(filePath).split('.').slice(0, -1).join('.');
|
|
48
|
+
let command = await import('file://' + filePath + '?v=' + counter).catch(e => {
|
|
49
|
+
console.error('[🆕🔴 ] Error loading command ' + chalk.blue(baseName));
|
|
52
50
|
console.log(e + '\n' + e.name + '\n' + e.stack);
|
|
53
51
|
});
|
|
54
52
|
if (!command)
|
|
@@ -56,9 +54,12 @@ export class CommandManager {
|
|
|
56
54
|
command = Object.values(command)[0];
|
|
57
55
|
try {
|
|
58
56
|
command = new command();
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
const commandName = command.constructor.name.toLowerCase();
|
|
58
|
+
this.commands.set(commandName, command);
|
|
59
|
+
if (!silent) {
|
|
60
|
+
console.debug('[🆕🟢 ] Command ' + chalk.blue(baseName) + ' loaded');
|
|
61
|
+
}
|
|
62
|
+
return command;
|
|
62
63
|
}
|
|
63
64
|
catch (error) {
|
|
64
65
|
this.errorHandler.handleError(error, {
|
|
@@ -66,8 +67,6 @@ export class CommandManager {
|
|
|
66
67
|
command: command,
|
|
67
68
|
});
|
|
68
69
|
}
|
|
69
|
-
if (loaded)
|
|
70
|
-
return command;
|
|
71
70
|
}
|
|
72
71
|
/**
|
|
73
72
|
* Load all command files from a folder
|
|
@@ -82,7 +81,7 @@ export class CommandManager {
|
|
|
82
81
|
if (file.endsWith('.d.ts'))
|
|
83
82
|
continue;
|
|
84
83
|
if (file.endsWith('.js') || file.endsWith('.ts')) {
|
|
85
|
-
const command = await this.loadCommandFile(path.join(folderPath, file));
|
|
84
|
+
const command = await this.loadCommandFile(path.join(folderPath, file), true);
|
|
86
85
|
if (command) {
|
|
87
86
|
const commandName = command.constructor.name.toLowerCase();
|
|
88
87
|
if (options?.blacklist && options.blacklist.includes(commandName))
|
|
@@ -104,87 +103,20 @@ export class CommandManager {
|
|
|
104
103
|
* @returns {Promise<Map<string, Command>>}
|
|
105
104
|
*/
|
|
106
105
|
watchCommandsFolder(folderPath) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
});
|
|
123
|
-
// TODO: Handle file removal
|
|
124
|
-
//.on('unlink', function(path) {console.log('File', path, 'has been removed');})
|
|
125
|
-
}
|
|
126
|
-
async refreshSlashCommands() {
|
|
127
|
-
const rest = new REST({ version: '10' }).setToken(this.framework.settings.discordClientOptions.token);
|
|
128
|
-
const commands = Array.from(this.commands.values())
|
|
129
|
-
.filter((command) => (command.type == CommandType.slash ||
|
|
130
|
-
command.type == CommandType.separated ||
|
|
131
|
-
command.type == CommandType.any) &&
|
|
132
|
-
!command.parent)
|
|
133
|
-
.map((command) => {
|
|
134
|
-
const slashCommand = new SlashCommandBuilder()
|
|
135
|
-
.setName(command.name)
|
|
136
|
-
.setDescription(this.framework.translations.get('command.' + command.name + '.description', 'en'));
|
|
137
|
-
if (command.args) {
|
|
138
|
-
command.args.forEach((arg) => {
|
|
139
|
-
let method;
|
|
140
|
-
switch (arg.type) {
|
|
141
|
-
case 'string':
|
|
142
|
-
method = 'addStringOption';
|
|
143
|
-
break;
|
|
144
|
-
case 'number':
|
|
145
|
-
method = 'addNumberOption';
|
|
146
|
-
break;
|
|
147
|
-
case 'user':
|
|
148
|
-
case 'member':
|
|
149
|
-
method = 'addUserOption';
|
|
150
|
-
break;
|
|
151
|
-
case 'channel':
|
|
152
|
-
method = 'addChannelOption';
|
|
153
|
-
break;
|
|
154
|
-
case 'role':
|
|
155
|
-
method = 'addRoleOption';
|
|
156
|
-
break;
|
|
157
|
-
default:
|
|
158
|
-
throw new Error(`Invalid argument type ${arg.type} in command ${command.name} for argument ${arg.name}`);
|
|
159
|
-
}
|
|
160
|
-
slashCommand[method]((option) => {
|
|
161
|
-
option.setName(arg.name);
|
|
162
|
-
option.setDescription(this.framework.translations.get('command.' +
|
|
163
|
-
command.name +
|
|
164
|
-
'.args.' +
|
|
165
|
-
arg.name +
|
|
166
|
-
'.description', 'en'));
|
|
167
|
-
option.setRequired(!arg.optional);
|
|
168
|
-
if (arg.choices) {
|
|
169
|
-
// if arg.choices is function, call it
|
|
170
|
-
if (typeof arg.choices == 'function') {
|
|
171
|
-
arg.choices =
|
|
172
|
-
arg.choices();
|
|
173
|
-
}
|
|
174
|
-
arg.choices.forEach((choice) => {
|
|
175
|
-
option.addChoices({
|
|
176
|
-
name: choice.name,
|
|
177
|
-
value: choice.value,
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
return option;
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
return slashCommand.toJSON();
|
|
186
|
-
});
|
|
187
|
-
const data = await rest.put(Routes.applicationCommands(this.framework.settings.discordClientOptions.clientId), { body: commands });
|
|
188
|
-
console.debug(`Successfully reloaded ${data.length} of ${commands.length} application (/) commands.`);
|
|
106
|
+
new FileWatcher().watch(folderPath, {
|
|
107
|
+
onAdd: (filePath) => {
|
|
108
|
+
this.loadCommandFile(filePath);
|
|
109
|
+
},
|
|
110
|
+
onChange: (filePath) => {
|
|
111
|
+
this.loadCommandFile(filePath);
|
|
112
|
+
},
|
|
113
|
+
onUnlink: (filePath) => {
|
|
114
|
+
const fileName = path.basename(filePath).split('.').slice(0, -1).join('.');
|
|
115
|
+
const commandName = fileName.toLowerCase();
|
|
116
|
+
this.commands.delete(commandName);
|
|
117
|
+
this.importCounters.delete(filePath);
|
|
118
|
+
console.debug('[🔄🟡] Command ' + chalk.blue(fileName) + ' removed');
|
|
119
|
+
},
|
|
120
|
+
}, 'command');
|
|
189
121
|
}
|
|
190
122
|
}
|
|
@@ -49,21 +49,8 @@ export class ModuleManager {
|
|
|
49
49
|
return moduleClass || exports[0];
|
|
50
50
|
}
|
|
51
51
|
registerModule(module) {
|
|
52
|
-
// Register module commands
|
|
53
|
-
if (module.getCommands()) {
|
|
54
|
-
module.getCommands().forEach((command) => {
|
|
55
|
-
this.framework.commands.set(command.name, command);
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
52
|
// Register module events
|
|
59
53
|
this.framework.events = new Map([...this.framework.events, ...module.getEvents()]);
|
|
60
|
-
// Register models (eliminado, migración a MongoDB)
|
|
61
|
-
/*
|
|
62
|
-
|
|
63
|
-
// Register module routes
|
|
64
|
-
this.routes = new Map([...this.routes, ...moduleInstance.getRoutes()]);
|
|
65
|
-
|
|
66
|
-
*/
|
|
67
54
|
}
|
|
68
55
|
async instanceModule(module, rootPath, name, options) {
|
|
69
56
|
// Comprobar requerimientos del módulo
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { Translation } from '../../definitions/Translation.js';
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import * as chokidar from 'chokidar';
|
|
5
|
-
import boxen from 'boxen';
|
|
6
4
|
import chalk from "chalk";
|
|
5
|
+
import { FileWatcher } from '../utilities/FileWatcher.js';
|
|
7
6
|
export class TranslationManager {
|
|
8
7
|
translations = new Map();
|
|
9
8
|
defaultLanguage = 'en';
|
|
@@ -94,30 +93,23 @@ export class TranslationManager {
|
|
|
94
93
|
}
|
|
95
94
|
}
|
|
96
95
|
watchTranslationFolder(folderPath, baseKey) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
})
|
|
115
|
-
.on('error', (error) => {
|
|
116
|
-
console.error('[🔄🔴 ] Error reloading translation file');
|
|
117
|
-
console.log(boxen(error + '\n' + error.stack, { padding: 1 }));
|
|
118
|
-
});
|
|
119
|
-
// TODO: Handle file removal
|
|
120
|
-
//.on('unlink', function(path) {console.log('File', path, 'has been removed');})
|
|
96
|
+
new FileWatcher().watch(folderPath, {
|
|
97
|
+
onAdd: async (filePath) => {
|
|
98
|
+
const json = await this.loadTranslationFile(filePath);
|
|
99
|
+
const lang = filePath.replace(/^.*[\\/]/, '').slice(0, -5);
|
|
100
|
+
this.importTranslationsJson(baseKey, lang, json);
|
|
101
|
+
console.debug('[🆕🟢 ] Translations file ' + chalk.blue(filePath) + ' loaded');
|
|
102
|
+
},
|
|
103
|
+
onChange: async (filePath) => {
|
|
104
|
+
const json = await this.loadTranslationFile(filePath);
|
|
105
|
+
const lang = filePath.replace(/^.*[\\/]/, '').slice(0, -5);
|
|
106
|
+
this.importTranslationsJson(baseKey, lang, json);
|
|
107
|
+
console.debug('[🆕🟢 ] Translations file ' + chalk.blue(filePath) + ' loaded');
|
|
108
|
+
},
|
|
109
|
+
onUnlink: (filePath) => {
|
|
110
|
+
console.debug('[🔄🟡] Translations file ' + chalk.blue(filePath) + ' removed');
|
|
111
|
+
},
|
|
112
|
+
}, 'translation');
|
|
121
113
|
}
|
|
122
114
|
getShortHandMethod(keyPrefix, language) {
|
|
123
115
|
return (key, params, lang) => {
|
|
@@ -23,7 +23,8 @@ export class EnvValidator {
|
|
|
23
23
|
const divider = chalk.yellow('━'.repeat(54));
|
|
24
24
|
const envPath = path.join(process.cwd(), '.env');
|
|
25
25
|
const hasEnvFile = fs.existsSync(envPath);
|
|
26
|
-
console.error(
|
|
26
|
+
console.error('');
|
|
27
|
+
console.error(divider);
|
|
27
28
|
console.error(` ${chalk.bold.red('CONFIGURATION ERROR')} — Missing environment variables`);
|
|
28
29
|
console.error(divider);
|
|
29
30
|
for (const key of present) {
|
|
@@ -44,7 +45,8 @@ export class EnvValidator {
|
|
|
44
45
|
else {
|
|
45
46
|
console.error(` ${chalk.dim('.env file found but missing required variables.')}`);
|
|
46
47
|
}
|
|
47
|
-
console.error(divider
|
|
48
|
+
console.error(divider);
|
|
49
|
+
console.error('');
|
|
48
50
|
process.exit(1);
|
|
49
51
|
}
|
|
50
52
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as chokidar from 'chokidar';
|
|
2
|
+
export type FileWatcherCallbacks = {
|
|
3
|
+
onAdd?: (filePath: string) => void | Promise<void>;
|
|
4
|
+
onChange?: (filePath: string) => void | Promise<void>;
|
|
5
|
+
onUnlink?: (filePath: string) => void | Promise<void>;
|
|
6
|
+
onError?: (error: Error) => void;
|
|
7
|
+
};
|
|
8
|
+
export declare class FileWatcher {
|
|
9
|
+
watch(folderPath: string, callbacks: FileWatcherCallbacks, label?: string): chokidar.FSWatcher;
|
|
10
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as chokidar from 'chokidar';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import boxen from 'boxen';
|
|
4
|
+
export class FileWatcher {
|
|
5
|
+
watch(folderPath, callbacks, label = 'file') {
|
|
6
|
+
const watcher = chokidar
|
|
7
|
+
.watch(path.resolve(folderPath), {
|
|
8
|
+
ignored: /^\./,
|
|
9
|
+
persistent: true,
|
|
10
|
+
ignoreInitial: true,
|
|
11
|
+
})
|
|
12
|
+
.on('add', (filePath) => {
|
|
13
|
+
callbacks.onAdd?.(filePath);
|
|
14
|
+
})
|
|
15
|
+
.on('change', (filePath) => {
|
|
16
|
+
callbacks.onChange?.(filePath);
|
|
17
|
+
})
|
|
18
|
+
.on('unlink', (filePath) => {
|
|
19
|
+
callbacks.onUnlink?.(filePath);
|
|
20
|
+
})
|
|
21
|
+
.on('error', (error) => {
|
|
22
|
+
if (callbacks.onError) {
|
|
23
|
+
callbacks.onError(error);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
console.error(`[🔄🔴 ] Error watching ${label}`);
|
|
27
|
+
console.log(boxen(error + '\n' + error.stack, { padding: 1 }));
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
return watcher;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -25,5 +25,5 @@ export declare class GuildDataGetter {
|
|
|
25
25
|
* // returns the guild settings
|
|
26
26
|
* getGuildSettings(interaction.guildId);
|
|
27
27
|
*/
|
|
28
|
-
getGuildSettings(guildId: string): Promise<
|
|
28
|
+
getGuildSettings(guildId: string): Promise<any>;
|
|
29
29
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { ServiceContainer } from "../ServiceContainer";
|
|
1
2
|
import { ObjectId } from "mongodb";
|
|
3
|
+
import { DatabaseManager } from 'zumito-db';
|
|
2
4
|
export class GuildDataGetter {
|
|
3
5
|
framework;
|
|
4
6
|
constructor(framework) {
|
|
@@ -28,6 +30,30 @@ export class GuildDataGetter {
|
|
|
28
30
|
* getGuildSettings(interaction.guildId);
|
|
29
31
|
*/
|
|
30
32
|
async getGuildSettings(guildId) {
|
|
33
|
+
// Use new zumito-db DatabaseManager if available
|
|
34
|
+
const db = ServiceContainer.getService(DatabaseManager);
|
|
35
|
+
if (db) {
|
|
36
|
+
const driver = db.getDriver();
|
|
37
|
+
const results = await driver.find('guilds', {
|
|
38
|
+
collection: 'guilds',
|
|
39
|
+
type: 'findOne',
|
|
40
|
+
where: [{ field: 'guild_id', operator: 'eq', value: guildId, logic: 'and' }],
|
|
41
|
+
});
|
|
42
|
+
let guild = results && results.length > 0 ? results[0] : null;
|
|
43
|
+
if (!guild) {
|
|
44
|
+
guild = {
|
|
45
|
+
guild_id: guildId,
|
|
46
|
+
lang: 'en',
|
|
47
|
+
prefix: null,
|
|
48
|
+
public: false,
|
|
49
|
+
deleteCommands: false
|
|
50
|
+
};
|
|
51
|
+
await driver.insert('guilds', guild);
|
|
52
|
+
}
|
|
53
|
+
return guild;
|
|
54
|
+
}
|
|
55
|
+
// Fallback to deprecated raw MongoDB access
|
|
56
|
+
console.warn('[🗄️⚠️] GuildDataGetter is using deprecated raw MongoDB access. Please update to zumito-db.');
|
|
31
57
|
const collection = this.framework.database.collection('guilds');
|
|
32
58
|
let guild = await collection.findOne({ guild_id: guildId });
|
|
33
59
|
if (!guild) {
|
|
@@ -6,6 +6,51 @@ export function createTestFramework(overrides = {}) {
|
|
|
6
6
|
ServiceContainer.services.clear();
|
|
7
7
|
const mockClient = createMockClient(overrides.client);
|
|
8
8
|
const eventEmitter = new EventEmitter();
|
|
9
|
+
const mockDb = {
|
|
10
|
+
getDriver: vi.fn().mockReturnValue({
|
|
11
|
+
find: vi.fn().mockResolvedValue([]),
|
|
12
|
+
findOne: vi.fn().mockResolvedValue(null),
|
|
13
|
+
insert: vi.fn().mockResolvedValue({}),
|
|
14
|
+
update: vi.fn().mockResolvedValue(0),
|
|
15
|
+
delete: vi.fn().mockResolvedValue(0),
|
|
16
|
+
count: vi.fn().mockResolvedValue(0),
|
|
17
|
+
ensureSchema: vi.fn().mockResolvedValue(undefined),
|
|
18
|
+
dropCollection: vi.fn().mockResolvedValue(undefined),
|
|
19
|
+
raw: {},
|
|
20
|
+
disconnect: vi.fn().mockResolvedValue(undefined),
|
|
21
|
+
}),
|
|
22
|
+
getRepository: vi.fn().mockReturnValue({
|
|
23
|
+
find: vi.fn().mockResolvedValue([]),
|
|
24
|
+
findOne: vi.fn().mockResolvedValue(null),
|
|
25
|
+
insert: vi.fn().mockResolvedValue({}),
|
|
26
|
+
update: vi.fn().mockResolvedValue(0),
|
|
27
|
+
delete: vi.fn().mockResolvedValue(0),
|
|
28
|
+
count: vi.fn().mockResolvedValue(0),
|
|
29
|
+
query: vi.fn().mockReturnValue({
|
|
30
|
+
where: vi.fn().mockReturnThis(),
|
|
31
|
+
andWhere: vi.fn().mockReturnThis(),
|
|
32
|
+
orWhere: vi.fn().mockReturnThis(),
|
|
33
|
+
select: vi.fn().mockReturnThis(),
|
|
34
|
+
sort: vi.fn().mockReturnThis(),
|
|
35
|
+
limit: vi.fn().mockReturnThis(),
|
|
36
|
+
offset: vi.fn().mockReturnThis(),
|
|
37
|
+
exec: vi.fn().mockResolvedValue([]),
|
|
38
|
+
first: vi.fn().mockResolvedValue(null),
|
|
39
|
+
count: vi.fn().mockResolvedValue(0),
|
|
40
|
+
}),
|
|
41
|
+
collection: 'test',
|
|
42
|
+
}),
|
|
43
|
+
registerModel: vi.fn(),
|
|
44
|
+
ensureSchemas: vi.fn().mockResolvedValue(undefined),
|
|
45
|
+
connect: vi.fn().mockResolvedValue(undefined),
|
|
46
|
+
disconnect: vi.fn().mockResolvedValue(undefined),
|
|
47
|
+
migrator: {
|
|
48
|
+
latest: vi.fn().mockResolvedValue([]),
|
|
49
|
+
rollback: vi.fn().mockResolvedValue([]),
|
|
50
|
+
status: vi.fn().mockResolvedValue([]),
|
|
51
|
+
},
|
|
52
|
+
...overrides.db,
|
|
53
|
+
};
|
|
9
54
|
const mockFramework = {
|
|
10
55
|
client: mockClient,
|
|
11
56
|
commands: {
|
|
@@ -39,10 +84,13 @@ export function createTestFramework(overrides = {}) {
|
|
|
39
84
|
getAll: vi.fn().mockReturnValue(new Map()),
|
|
40
85
|
size: 0,
|
|
41
86
|
},
|
|
87
|
+
db: mockDb,
|
|
42
88
|
...overrides.framework,
|
|
43
89
|
};
|
|
44
90
|
ServiceContainer.addService(class ZumitoFramework {
|
|
45
91
|
}, [], true, mockFramework);
|
|
92
|
+
ServiceContainer.addService(class DatabaseManager {
|
|
93
|
+
}, [], true, mockDb);
|
|
46
94
|
class MockErrorHandler {
|
|
47
95
|
handleError = vi.fn();
|
|
48
96
|
}
|
|
@@ -52,5 +100,6 @@ export function createTestFramework(overrides = {}) {
|
|
|
52
100
|
framework: mockFramework,
|
|
53
101
|
client: mockClient,
|
|
54
102
|
eventEmitter,
|
|
103
|
+
db: mockDb,
|
|
55
104
|
};
|
|
56
105
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zumito-framework",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.22.1",
|
|
4
4
|
"description": "Discord.js bot framework",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -37,12 +37,12 @@
|
|
|
37
37
|
"error-stack-parser": "^2.1.4",
|
|
38
38
|
"express": "^4.18.1",
|
|
39
39
|
"leven": "^4.0.0",
|
|
40
|
-
"
|
|
40
|
+
"mongodb": "^6.3.0",
|
|
41
41
|
"reflect-metadata": "^0.2.2",
|
|
42
42
|
"source-fragment": "^1.1.0",
|
|
43
43
|
"tingodb": "^0.6.1",
|
|
44
44
|
"tseep": "^1.2.2",
|
|
45
|
-
"zumito-db": "
|
|
45
|
+
"zumito-db": "^2.0.3"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/node": "^18.19.44",
|