zumito-framework 1.1.45 → 1.1.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/TranslationManager.d.ts +15 -15
- package/dist/TranslationManager.js +41 -41
- package/dist/ZumitoFramework.d.ts +51 -51
- package/dist/ZumitoFramework.js +312 -312
- package/dist/baseModule/BaseModule.d.ts +6 -6
- package/dist/baseModule/BaseModule.js +16 -16
- package/dist/baseModule/events/discord/interactionCreate.d.ts +6 -6
- package/dist/baseModule/events/discord/interactionCreate.js +50 -50
- package/dist/baseModule/events/discord/messageCreate.d.ts +16 -16
- package/dist/baseModule/events/discord/messageCreate.js +233 -233
- package/dist/baseModule/index.d.ts +6 -6
- package/dist/baseModule/index.js +15 -15
- package/dist/baseModule/models/errors.json +13 -13
- package/dist/baseModule/models/guild.json +22 -22
- package/dist/definitions/ApiResponse.d.ts +4 -4
- package/dist/definitions/ApiResponse.js +16 -16
- package/dist/index.d.ts +17 -17
- package/dist/index.js +12 -12
- package/dist/managers/EmojiManager.d.ts +11 -11
- package/dist/managers/EmojiManager.js +32 -32
- package/dist/types/Command.d.ts +24 -24
- package/dist/types/Command.js +25 -25
- package/dist/types/CommandArgDefinition.d.ts +7 -7
- package/dist/types/CommandArgDefinition.js +1 -1
- package/dist/types/CommandArguments.d.ts +8 -8
- package/dist/types/CommandArguments.js +15 -15
- package/dist/types/CommandChoiceDefinition.d.ts +4 -4
- package/dist/types/CommandChoiceDefinition.js +1 -1
- package/dist/types/CommandParameters.d.ts +18 -18
- package/dist/types/CommandParameters.js +1 -1
- package/dist/types/CommandType.d.ts +6 -6
- package/dist/types/CommandType.js +6 -6
- package/dist/types/Commands.d.ts +23 -23
- package/dist/types/Commands.js +26 -26
- package/dist/types/EventParameters.d.ts +8 -8
- package/dist/types/EventParameters.js +1 -1
- package/dist/types/FrameworkEvent.d.ts +5 -5
- package/dist/types/FrameworkEvent.js +4 -4
- package/dist/types/FrameworkSettings.d.ts +11 -11
- package/dist/types/FrameworkSettings.js +1 -1
- package/dist/types/Module.d.ts +26 -25
- package/dist/types/Module.js +201 -191
- package/dist/types/SelectMenuParameters.d.ts +9 -9
- package/dist/types/SelectMenuParameters.js +1 -1
- package/dist/types/Translation.d.ts +9 -9
- package/dist/types/Translation.js +31 -31
- package/dist/utils/EmojiFallback.d.ts +6 -6
- package/dist/utils/EmojiFallback.js +14 -14
- package/dist/utils/TextFormatter.d.ts +26 -26
- package/dist/utils/TextFormatter.js +82 -82
- package/package.json +1 -1
- package/plop-templates/command.js.hbs +16 -16
- package/plop-templates/translation.json.hbs +7 -7
- package/plopfile.js +88 -88
- package/templateGenerator.mjs +25 -25
package/dist/ZumitoFramework.js
CHANGED
|
@@ -1,312 +1,312 @@
|
|
|
1
|
-
import { SlashCommandBuilder } from "discord.js";
|
|
2
|
-
import { Module } from "./types/Module.js";
|
|
3
|
-
import { ApiResponse } from './definitions/ApiResponse.js';
|
|
4
|
-
import { baseModule } from "./baseModule/index.js";
|
|
5
|
-
import { TranslationManager } from "./TranslationManager.js";
|
|
6
|
-
import express from 'express';
|
|
7
|
-
import * as fs from 'fs';
|
|
8
|
-
import path from 'path';
|
|
9
|
-
import { Client } from "discord.js";
|
|
10
|
-
// import better-logging
|
|
11
|
-
import { betterLogging } from "better-logging";
|
|
12
|
-
betterLogging(console);
|
|
13
|
-
import { REST } from '@discordjs/rest';
|
|
14
|
-
import { Routes } from 'discord-api-types/v9';
|
|
15
|
-
import mongoose from "mongoose";
|
|
16
|
-
import cookieParser from 'cookie-parser';
|
|
17
|
-
import cors from 'cors';
|
|
18
|
-
import http from 'http';
|
|
19
|
-
import * as url from 'url';
|
|
20
|
-
import { CommandType } from "./types/CommandType.js";
|
|
21
|
-
/**
|
|
22
|
-
* @class ZumitoFramework
|
|
23
|
-
* @classdesc The main class of the framework.
|
|
24
|
-
*
|
|
25
|
-
* @property {FrameworkSettings} settings - The settings of the framework.
|
|
26
|
-
* @property {Client} client - The client client instance.
|
|
27
|
-
* @property {Collection<string, Module>} modules - The modules loaded in the framework.
|
|
28
|
-
* @property {Collection<string, Command>} commands - The commands loaded in the framework.
|
|
29
|
-
*/
|
|
30
|
-
export class ZumitoFramework {
|
|
31
|
-
client;
|
|
32
|
-
settings;
|
|
33
|
-
modules;
|
|
34
|
-
commands;
|
|
35
|
-
events;
|
|
36
|
-
translations;
|
|
37
|
-
routes;
|
|
38
|
-
models;
|
|
39
|
-
database;
|
|
40
|
-
app;
|
|
41
|
-
/**
|
|
42
|
-
* @constructor
|
|
43
|
-
* @description Creates a new instance of the framework.
|
|
44
|
-
* @param {FrameworkSettings} settings - The settings of the framework.
|
|
45
|
-
* @example new ZumitoFramework({
|
|
46
|
-
* prefix: '!',
|
|
47
|
-
* discordClientOptions: {
|
|
48
|
-
* token: 'token',
|
|
49
|
-
* clientId: 'clientId',
|
|
50
|
-
* intents: 0
|
|
51
|
-
* }
|
|
52
|
-
* });
|
|
53
|
-
* @public
|
|
54
|
-
*/
|
|
55
|
-
constructor(settings, callback) {
|
|
56
|
-
this.settings = settings;
|
|
57
|
-
this.modules = new Map();
|
|
58
|
-
this.commands = new Map();
|
|
59
|
-
this.events = new Map();
|
|
60
|
-
this.translations = new TranslationManager();
|
|
61
|
-
this.models = new Map();
|
|
62
|
-
if (settings.logLevel) {
|
|
63
|
-
console.logLevel = settings.logLevel;
|
|
64
|
-
}
|
|
65
|
-
this.initialize().then(() => {
|
|
66
|
-
if (callback)
|
|
67
|
-
callback(this);
|
|
68
|
-
}).catch(err => {
|
|
69
|
-
console.error(err, err.message, err.stack, err.name);
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
async initialize() {
|
|
73
|
-
try {
|
|
74
|
-
await mongoose.connect(this.settings.mongoQueryString);
|
|
75
|
-
}
|
|
76
|
-
catch (err) {
|
|
77
|
-
console.error("[🗄️🔴] Database connection error:", err.message);
|
|
78
|
-
process.exit(1);
|
|
79
|
-
}
|
|
80
|
-
finally {
|
|
81
|
-
this.database = mongoose.connection;
|
|
82
|
-
console.log('[🗄️🟢] Database connection successful');
|
|
83
|
-
}
|
|
84
|
-
this.initializeDiscordClient();
|
|
85
|
-
this.startApiServer();
|
|
86
|
-
await this.registerModules();
|
|
87
|
-
await this.refreshSlashCommands();
|
|
88
|
-
}
|
|
89
|
-
startApiServer() {
|
|
90
|
-
this.app = express();
|
|
91
|
-
let port = process.env.PORT || '80';
|
|
92
|
-
this.app.set('port', port);
|
|
93
|
-
var server = http.createServer(this.app);
|
|
94
|
-
server.listen(port);
|
|
95
|
-
server.on('error', (err) => {
|
|
96
|
-
console.log('[🌐🔴] Error starting API web server: ' + err);
|
|
97
|
-
});
|
|
98
|
-
server.on('listening', () => {
|
|
99
|
-
console.log('[🌐🟢] API web server listening on port ' + port);
|
|
100
|
-
});
|
|
101
|
-
this.app.use(express.json());
|
|
102
|
-
this.app.use(express.urlencoded({ extended: false }));
|
|
103
|
-
this.app.use(cookieParser());
|
|
104
|
-
//this.app.use(express.static(path.join(__dirname, "public")));
|
|
105
|
-
//To allow cross-origin requests
|
|
106
|
-
this.app.use(cors());
|
|
107
|
-
//Route Prefixes
|
|
108
|
-
//this.app.use("/", indexRouter);
|
|
109
|
-
//this.app.use("/api/", apiRouter);
|
|
110
|
-
// throw 404 if URL not found
|
|
111
|
-
this.app.all("*", function (req, res) {
|
|
112
|
-
return ApiResponse.notFoundResponse(res, "Page not found");
|
|
113
|
-
});
|
|
114
|
-
this.app.use(function (err, req, res) {
|
|
115
|
-
if (err.name === 'UnauthorizedError') {
|
|
116
|
-
return ApiResponse.unauthorizedResponse(res, "Invalid token");
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
async registerModules() {
|
|
121
|
-
let modulesFolder;
|
|
122
|
-
if (fs.existsSync(`${process.cwd()}/modules`)) {
|
|
123
|
-
modulesFolder = `${process.cwd()}/modules`;
|
|
124
|
-
}
|
|
125
|
-
else if (fs.existsSync(`${process.cwd()}/src/modules`)) {
|
|
126
|
-
modulesFolder = `${process.cwd()}/src/modules`;
|
|
127
|
-
}
|
|
128
|
-
else
|
|
129
|
-
return;
|
|
130
|
-
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
|
131
|
-
await this.registerModule(__dirname, 'baseModule', baseModule);
|
|
132
|
-
let files = fs.readdirSync(modulesFolder);
|
|
133
|
-
for (let file of files) {
|
|
134
|
-
await this.registerModule(modulesFolder, file);
|
|
135
|
-
}
|
|
136
|
-
this.models.forEach((modelDefinition, modelName) => {
|
|
137
|
-
const schema = new mongoose.Schema(modelDefinition);
|
|
138
|
-
this.models.set(modelName, mongoose.model(modelName, schema));
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
async registerModule(modulesFolder, moduleName, module) {
|
|
142
|
-
if (!module) {
|
|
143
|
-
if (fs.existsSync(path.join(modulesFolder, moduleName, 'index.js'))) {
|
|
144
|
-
module = await import(path.join(modulesFolder, moduleName, 'index.js'));
|
|
145
|
-
module = Object.values(module)[0];
|
|
146
|
-
}
|
|
147
|
-
else if (fs.existsSync(path.join(modulesFolder, moduleName, 'index.ts'))) {
|
|
148
|
-
module = await import(path.join(modulesFolder, moduleName, 'index.ts'));
|
|
149
|
-
module = Object.values(module)[0];
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
module = Module;
|
|
153
|
-
}
|
|
154
|
-
;
|
|
155
|
-
}
|
|
156
|
-
// Create module instance
|
|
157
|
-
let moduleInstance;
|
|
158
|
-
try {
|
|
159
|
-
moduleInstance = new module(path.join(modulesFolder, moduleName), this);
|
|
160
|
-
await moduleInstance.initialize();
|
|
161
|
-
this.modules.set(moduleName || moduleInstance.constructor.name, moduleInstance);
|
|
162
|
-
}
|
|
163
|
-
catch (err) {
|
|
164
|
-
console.error(`[📦🔴] Error loading module ${moduleName}: ${err.message}`);
|
|
165
|
-
console.error(err.stack);
|
|
166
|
-
}
|
|
167
|
-
// Register module commands
|
|
168
|
-
if (moduleInstance.getCommands()) {
|
|
169
|
-
moduleInstance.getCommands().forEach((command) => {
|
|
170
|
-
this.commands.set(command.name, command);
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
this.commands = new Map([...this.commands, ...moduleInstance.getCommands()]);
|
|
174
|
-
// Register module events
|
|
175
|
-
this.events = new Map([...this.events, ...moduleInstance.getEvents()]);
|
|
176
|
-
// Register models
|
|
177
|
-
moduleInstance.getModels().forEach((modelDefinition, modelName) => {
|
|
178
|
-
if (!this.models.has(modelName)) {
|
|
179
|
-
this.models.set(modelName, modelDefinition);
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
this.models.set(modelName, MergeRecursive(this.models.get(modelName), modelDefinition));
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
/*
|
|
186
|
-
|
|
187
|
-
// Register module routes
|
|
188
|
-
this.routes = new Map([...this.routes, ...moduleInstance.getRoutes()]);
|
|
189
|
-
|
|
190
|
-
*/
|
|
191
|
-
}
|
|
192
|
-
initializeDiscordClient() {
|
|
193
|
-
this.client = new Client({
|
|
194
|
-
intents: this.settings.discordClientOptions.intents
|
|
195
|
-
});
|
|
196
|
-
this.client.login(this.settings.discordClientOptions.token);
|
|
197
|
-
this.client.on('ready', () => {
|
|
198
|
-
// Bot emoji
|
|
199
|
-
console.log('[🤖🟢] Discord client ready');
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
static splitCommandLine(commandLine) {
|
|
203
|
-
//log( 'commandLine', commandLine ) ;
|
|
204
|
-
// Find a unique marker for the space character.
|
|
205
|
-
// Start with '<SP>' and repeatedly append '@' if necessary to make it unique.
|
|
206
|
-
var spaceMarker = '<SP>';
|
|
207
|
-
while (commandLine.indexOf(spaceMarker) > -1)
|
|
208
|
-
spaceMarker += '@';
|
|
209
|
-
// Protect double-quoted strings.
|
|
210
|
-
// o Find strings of non-double-quotes, wrapped in double-quotes.
|
|
211
|
-
// o The final double-quote is optional to allow for an unterminated string.
|
|
212
|
-
// o Replace each double-quoted-string with what's inside the qouble-quotes,
|
|
213
|
-
// after each space character has been replaced with the space-marker above.
|
|
214
|
-
// o The outer double-quotes will not be present.
|
|
215
|
-
var noSpacesInQuotes = commandLine.replace(/"([^"]*)"?/g, (fullMatch, capture) => {
|
|
216
|
-
return capture.replace(/ /g, spaceMarker);
|
|
217
|
-
});
|
|
218
|
-
// Now that it is safe to do so, split the command-line at one-or-more spaces.
|
|
219
|
-
var mangledParamArray = noSpacesInQuotes.split(/ +/);
|
|
220
|
-
// Create a new array by restoring spaces from any space-markers.
|
|
221
|
-
var paramArray = mangledParamArray.map((mangledParam) => {
|
|
222
|
-
return mangledParam.replace(RegExp(spaceMarker, 'g'), ' ');
|
|
223
|
-
});
|
|
224
|
-
return paramArray;
|
|
225
|
-
}
|
|
226
|
-
async memberHasPermission(member, channel, permission) {
|
|
227
|
-
let memberPermission = await channel.permissionsFor(member);
|
|
228
|
-
return memberPermission.has(permission);
|
|
229
|
-
}
|
|
230
|
-
async getGuildSettings(guildId) {
|
|
231
|
-
const Guild = this.models.get('Guild');
|
|
232
|
-
let guild = await Guild.findOne({ guild_id: guildId }).exec();
|
|
233
|
-
if (guild == null) {
|
|
234
|
-
guild = new Guild({
|
|
235
|
-
guild_id: guildId,
|
|
236
|
-
});
|
|
237
|
-
await guild.save();
|
|
238
|
-
}
|
|
239
|
-
return guild;
|
|
240
|
-
}
|
|
241
|
-
async refreshSlashCommands() {
|
|
242
|
-
const rest = new REST({ version: '10' }).setToken(this.settings.discordClientOptions.token);
|
|
243
|
-
let commands = Array.from(this.commands.values())
|
|
244
|
-
.filter((command) => command.type == CommandType.slash || command.type == CommandType.separated || command.type == CommandType.any)
|
|
245
|
-
.map((command) => {
|
|
246
|
-
let slashCommand = new SlashCommandBuilder()
|
|
247
|
-
.setName(command.name)
|
|
248
|
-
.setDescription(this.translations.get('command.' + command.name + '.description', 'en'));
|
|
249
|
-
if (command.args) {
|
|
250
|
-
command.args.forEach((arg) => {
|
|
251
|
-
let method;
|
|
252
|
-
switch (arg.type) {
|
|
253
|
-
case 'string':
|
|
254
|
-
method = 'addStringOption';
|
|
255
|
-
break;
|
|
256
|
-
case 'user':
|
|
257
|
-
case 'member':
|
|
258
|
-
method = 'addUserOption';
|
|
259
|
-
break;
|
|
260
|
-
case 'channel':
|
|
261
|
-
method = 'addChannelOption';
|
|
262
|
-
break;
|
|
263
|
-
case 'role':
|
|
264
|
-
method = 'addRoleOption';
|
|
265
|
-
break;
|
|
266
|
-
default:
|
|
267
|
-
throw new Error('Invalid argument type ' + arg.type);
|
|
268
|
-
}
|
|
269
|
-
slashCommand[method]((option) => {
|
|
270
|
-
option.setName(arg.name);
|
|
271
|
-
option.setDescription(this.translations.get('command.' + command.name + '.args.' + arg.name + '.description', 'en'));
|
|
272
|
-
option.setRequired(!arg.optional);
|
|
273
|
-
if (arg.choices) {
|
|
274
|
-
// if arg.choices is function, call it
|
|
275
|
-
if (typeof arg.choices == 'function') {
|
|
276
|
-
arg.choices = arg.choices();
|
|
277
|
-
}
|
|
278
|
-
arg.choices.forEach((choice) => {
|
|
279
|
-
option.addChoices({
|
|
280
|
-
name: choice.name,
|
|
281
|
-
value: choice.value
|
|
282
|
-
});
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
return option;
|
|
286
|
-
});
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
return slashCommand.toJSON();
|
|
290
|
-
});
|
|
291
|
-
const data = await rest.put(Routes.applicationCommands(this.settings.discordClientOptions.clientId), { body: commands });
|
|
292
|
-
console.debug(`Successfully reloaded ${data.length} of ${commands.length} application (/) commands.`);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
function MergeRecursive(obj1, obj2) {
|
|
296
|
-
for (var p in obj2) {
|
|
297
|
-
try {
|
|
298
|
-
// Property in destination object set; update its value.
|
|
299
|
-
if (obj2[p].constructor == Object) {
|
|
300
|
-
obj1[p] = MergeRecursive(obj1[p], obj2[p]);
|
|
301
|
-
}
|
|
302
|
-
else {
|
|
303
|
-
obj1[p] = obj2[p];
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
catch (e) {
|
|
307
|
-
// Property in destination object not set; create it and set its value.
|
|
308
|
-
obj1[p] = obj2[p];
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
return obj1;
|
|
312
|
-
}
|
|
1
|
+
import { SlashCommandBuilder } from "discord.js";
|
|
2
|
+
import { Module } from "./types/Module.js";
|
|
3
|
+
import { ApiResponse } from './definitions/ApiResponse.js';
|
|
4
|
+
import { baseModule } from "./baseModule/index.js";
|
|
5
|
+
import { TranslationManager } from "./TranslationManager.js";
|
|
6
|
+
import express from 'express';
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { Client } from "discord.js";
|
|
10
|
+
// import better-logging
|
|
11
|
+
import { betterLogging } from "better-logging";
|
|
12
|
+
betterLogging(console);
|
|
13
|
+
import { REST } from '@discordjs/rest';
|
|
14
|
+
import { Routes } from 'discord-api-types/v9';
|
|
15
|
+
import mongoose from "mongoose";
|
|
16
|
+
import cookieParser from 'cookie-parser';
|
|
17
|
+
import cors from 'cors';
|
|
18
|
+
import http from 'http';
|
|
19
|
+
import * as url from 'url';
|
|
20
|
+
import { CommandType } from "./types/CommandType.js";
|
|
21
|
+
/**
|
|
22
|
+
* @class ZumitoFramework
|
|
23
|
+
* @classdesc The main class of the framework.
|
|
24
|
+
*
|
|
25
|
+
* @property {FrameworkSettings} settings - The settings of the framework.
|
|
26
|
+
* @property {Client} client - The client client instance.
|
|
27
|
+
* @property {Collection<string, Module>} modules - The modules loaded in the framework.
|
|
28
|
+
* @property {Collection<string, Command>} commands - The commands loaded in the framework.
|
|
29
|
+
*/
|
|
30
|
+
export class ZumitoFramework {
|
|
31
|
+
client;
|
|
32
|
+
settings;
|
|
33
|
+
modules;
|
|
34
|
+
commands;
|
|
35
|
+
events;
|
|
36
|
+
translations;
|
|
37
|
+
routes;
|
|
38
|
+
models;
|
|
39
|
+
database;
|
|
40
|
+
app;
|
|
41
|
+
/**
|
|
42
|
+
* @constructor
|
|
43
|
+
* @description Creates a new instance of the framework.
|
|
44
|
+
* @param {FrameworkSettings} settings - The settings of the framework.
|
|
45
|
+
* @example new ZumitoFramework({
|
|
46
|
+
* prefix: '!',
|
|
47
|
+
* discordClientOptions: {
|
|
48
|
+
* token: 'token',
|
|
49
|
+
* clientId: 'clientId',
|
|
50
|
+
* intents: 0
|
|
51
|
+
* }
|
|
52
|
+
* });
|
|
53
|
+
* @public
|
|
54
|
+
*/
|
|
55
|
+
constructor(settings, callback) {
|
|
56
|
+
this.settings = settings;
|
|
57
|
+
this.modules = new Map();
|
|
58
|
+
this.commands = new Map();
|
|
59
|
+
this.events = new Map();
|
|
60
|
+
this.translations = new TranslationManager();
|
|
61
|
+
this.models = new Map();
|
|
62
|
+
if (settings.logLevel) {
|
|
63
|
+
console.logLevel = settings.logLevel;
|
|
64
|
+
}
|
|
65
|
+
this.initialize().then(() => {
|
|
66
|
+
if (callback)
|
|
67
|
+
callback(this);
|
|
68
|
+
}).catch(err => {
|
|
69
|
+
console.error(err, err.message, err.stack, err.name);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async initialize() {
|
|
73
|
+
try {
|
|
74
|
+
await mongoose.connect(this.settings.mongoQueryString);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
console.error("[🗄️🔴] Database connection error:", err.message);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
this.database = mongoose.connection;
|
|
82
|
+
console.log('[🗄️🟢] Database connection successful');
|
|
83
|
+
}
|
|
84
|
+
this.initializeDiscordClient();
|
|
85
|
+
this.startApiServer();
|
|
86
|
+
await this.registerModules();
|
|
87
|
+
await this.refreshSlashCommands();
|
|
88
|
+
}
|
|
89
|
+
startApiServer() {
|
|
90
|
+
this.app = express();
|
|
91
|
+
let port = process.env.PORT || '80';
|
|
92
|
+
this.app.set('port', port);
|
|
93
|
+
var server = http.createServer(this.app);
|
|
94
|
+
server.listen(port);
|
|
95
|
+
server.on('error', (err) => {
|
|
96
|
+
console.log('[🌐🔴] Error starting API web server: ' + err);
|
|
97
|
+
});
|
|
98
|
+
server.on('listening', () => {
|
|
99
|
+
console.log('[🌐🟢] API web server listening on port ' + port);
|
|
100
|
+
});
|
|
101
|
+
this.app.use(express.json());
|
|
102
|
+
this.app.use(express.urlencoded({ extended: false }));
|
|
103
|
+
this.app.use(cookieParser());
|
|
104
|
+
//this.app.use(express.static(path.join(__dirname, "public")));
|
|
105
|
+
//To allow cross-origin requests
|
|
106
|
+
this.app.use(cors());
|
|
107
|
+
//Route Prefixes
|
|
108
|
+
//this.app.use("/", indexRouter);
|
|
109
|
+
//this.app.use("/api/", apiRouter);
|
|
110
|
+
// throw 404 if URL not found
|
|
111
|
+
this.app.all("*", function (req, res) {
|
|
112
|
+
return ApiResponse.notFoundResponse(res, "Page not found");
|
|
113
|
+
});
|
|
114
|
+
this.app.use(function (err, req, res) {
|
|
115
|
+
if (err.name === 'UnauthorizedError') {
|
|
116
|
+
return ApiResponse.unauthorizedResponse(res, "Invalid token");
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
async registerModules() {
|
|
121
|
+
let modulesFolder;
|
|
122
|
+
if (fs.existsSync(`${process.cwd()}/modules`)) {
|
|
123
|
+
modulesFolder = `${process.cwd()}/modules`;
|
|
124
|
+
}
|
|
125
|
+
else if (fs.existsSync(`${process.cwd()}/src/modules`)) {
|
|
126
|
+
modulesFolder = `${process.cwd()}/src/modules`;
|
|
127
|
+
}
|
|
128
|
+
else
|
|
129
|
+
return;
|
|
130
|
+
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
|
131
|
+
await this.registerModule(__dirname, 'baseModule', baseModule);
|
|
132
|
+
let files = fs.readdirSync(modulesFolder);
|
|
133
|
+
for (let file of files) {
|
|
134
|
+
await this.registerModule(modulesFolder, file);
|
|
135
|
+
}
|
|
136
|
+
this.models.forEach((modelDefinition, modelName) => {
|
|
137
|
+
const schema = new mongoose.Schema(modelDefinition);
|
|
138
|
+
this.models.set(modelName, mongoose.model(modelName, schema));
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
async registerModule(modulesFolder, moduleName, module) {
|
|
142
|
+
if (!module) {
|
|
143
|
+
if (fs.existsSync(path.join(modulesFolder, moduleName, 'index.js'))) {
|
|
144
|
+
module = await import(path.join(modulesFolder, moduleName, 'index.js'));
|
|
145
|
+
module = Object.values(module)[0];
|
|
146
|
+
}
|
|
147
|
+
else if (fs.existsSync(path.join(modulesFolder, moduleName, 'index.ts'))) {
|
|
148
|
+
module = await import(path.join(modulesFolder, moduleName, 'index.ts'));
|
|
149
|
+
module = Object.values(module)[0];
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
module = Module;
|
|
153
|
+
}
|
|
154
|
+
;
|
|
155
|
+
}
|
|
156
|
+
// Create module instance
|
|
157
|
+
let moduleInstance;
|
|
158
|
+
try {
|
|
159
|
+
moduleInstance = new module(path.join(modulesFolder, moduleName), this);
|
|
160
|
+
await moduleInstance.initialize();
|
|
161
|
+
this.modules.set(moduleName || moduleInstance.constructor.name, moduleInstance);
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
console.error(`[📦🔴] Error loading module ${moduleName}: ${err.message}`);
|
|
165
|
+
console.error(err.stack);
|
|
166
|
+
}
|
|
167
|
+
// Register module commands
|
|
168
|
+
if (moduleInstance.getCommands()) {
|
|
169
|
+
moduleInstance.getCommands().forEach((command) => {
|
|
170
|
+
this.commands.set(command.name, command);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
this.commands = new Map([...this.commands, ...moduleInstance.getCommands()]);
|
|
174
|
+
// Register module events
|
|
175
|
+
this.events = new Map([...this.events, ...moduleInstance.getEvents()]);
|
|
176
|
+
// Register models
|
|
177
|
+
moduleInstance.getModels().forEach((modelDefinition, modelName) => {
|
|
178
|
+
if (!this.models.has(modelName)) {
|
|
179
|
+
this.models.set(modelName, modelDefinition);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
this.models.set(modelName, MergeRecursive(this.models.get(modelName), modelDefinition));
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
/*
|
|
186
|
+
|
|
187
|
+
// Register module routes
|
|
188
|
+
this.routes = new Map([...this.routes, ...moduleInstance.getRoutes()]);
|
|
189
|
+
|
|
190
|
+
*/
|
|
191
|
+
}
|
|
192
|
+
initializeDiscordClient() {
|
|
193
|
+
this.client = new Client({
|
|
194
|
+
intents: this.settings.discordClientOptions.intents
|
|
195
|
+
});
|
|
196
|
+
this.client.login(this.settings.discordClientOptions.token);
|
|
197
|
+
this.client.on('ready', () => {
|
|
198
|
+
// Bot emoji
|
|
199
|
+
console.log('[🤖🟢] Discord client ready');
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
static splitCommandLine(commandLine) {
|
|
203
|
+
//log( 'commandLine', commandLine ) ;
|
|
204
|
+
// Find a unique marker for the space character.
|
|
205
|
+
// Start with '<SP>' and repeatedly append '@' if necessary to make it unique.
|
|
206
|
+
var spaceMarker = '<SP>';
|
|
207
|
+
while (commandLine.indexOf(spaceMarker) > -1)
|
|
208
|
+
spaceMarker += '@';
|
|
209
|
+
// Protect double-quoted strings.
|
|
210
|
+
// o Find strings of non-double-quotes, wrapped in double-quotes.
|
|
211
|
+
// o The final double-quote is optional to allow for an unterminated string.
|
|
212
|
+
// o Replace each double-quoted-string with what's inside the qouble-quotes,
|
|
213
|
+
// after each space character has been replaced with the space-marker above.
|
|
214
|
+
// o The outer double-quotes will not be present.
|
|
215
|
+
var noSpacesInQuotes = commandLine.replace(/"([^"]*)"?/g, (fullMatch, capture) => {
|
|
216
|
+
return capture.replace(/ /g, spaceMarker);
|
|
217
|
+
});
|
|
218
|
+
// Now that it is safe to do so, split the command-line at one-or-more spaces.
|
|
219
|
+
var mangledParamArray = noSpacesInQuotes.split(/ +/);
|
|
220
|
+
// Create a new array by restoring spaces from any space-markers.
|
|
221
|
+
var paramArray = mangledParamArray.map((mangledParam) => {
|
|
222
|
+
return mangledParam.replace(RegExp(spaceMarker, 'g'), ' ');
|
|
223
|
+
});
|
|
224
|
+
return paramArray;
|
|
225
|
+
}
|
|
226
|
+
async memberHasPermission(member, channel, permission) {
|
|
227
|
+
let memberPermission = await channel.permissionsFor(member);
|
|
228
|
+
return memberPermission.has(permission);
|
|
229
|
+
}
|
|
230
|
+
async getGuildSettings(guildId) {
|
|
231
|
+
const Guild = this.models.get('Guild');
|
|
232
|
+
let guild = await Guild.findOne({ guild_id: guildId }).exec();
|
|
233
|
+
if (guild == null) {
|
|
234
|
+
guild = new Guild({
|
|
235
|
+
guild_id: guildId,
|
|
236
|
+
});
|
|
237
|
+
await guild.save();
|
|
238
|
+
}
|
|
239
|
+
return guild;
|
|
240
|
+
}
|
|
241
|
+
async refreshSlashCommands() {
|
|
242
|
+
const rest = new REST({ version: '10' }).setToken(this.settings.discordClientOptions.token);
|
|
243
|
+
let commands = Array.from(this.commands.values())
|
|
244
|
+
.filter((command) => command.type == CommandType.slash || command.type == CommandType.separated || command.type == CommandType.any)
|
|
245
|
+
.map((command) => {
|
|
246
|
+
let slashCommand = new SlashCommandBuilder()
|
|
247
|
+
.setName(command.name)
|
|
248
|
+
.setDescription(this.translations.get('command.' + command.name + '.description', 'en'));
|
|
249
|
+
if (command.args) {
|
|
250
|
+
command.args.forEach((arg) => {
|
|
251
|
+
let method;
|
|
252
|
+
switch (arg.type) {
|
|
253
|
+
case 'string':
|
|
254
|
+
method = 'addStringOption';
|
|
255
|
+
break;
|
|
256
|
+
case 'user':
|
|
257
|
+
case 'member':
|
|
258
|
+
method = 'addUserOption';
|
|
259
|
+
break;
|
|
260
|
+
case 'channel':
|
|
261
|
+
method = 'addChannelOption';
|
|
262
|
+
break;
|
|
263
|
+
case 'role':
|
|
264
|
+
method = 'addRoleOption';
|
|
265
|
+
break;
|
|
266
|
+
default:
|
|
267
|
+
throw new Error('Invalid argument type ' + arg.type);
|
|
268
|
+
}
|
|
269
|
+
slashCommand[method]((option) => {
|
|
270
|
+
option.setName(arg.name);
|
|
271
|
+
option.setDescription(this.translations.get('command.' + command.name + '.args.' + arg.name + '.description', 'en'));
|
|
272
|
+
option.setRequired(!arg.optional);
|
|
273
|
+
if (arg.choices) {
|
|
274
|
+
// if arg.choices is function, call it
|
|
275
|
+
if (typeof arg.choices == 'function') {
|
|
276
|
+
arg.choices = arg.choices();
|
|
277
|
+
}
|
|
278
|
+
arg.choices.forEach((choice) => {
|
|
279
|
+
option.addChoices({
|
|
280
|
+
name: choice.name,
|
|
281
|
+
value: choice.value
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
return option;
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
return slashCommand.toJSON();
|
|
290
|
+
});
|
|
291
|
+
const data = await rest.put(Routes.applicationCommands(this.settings.discordClientOptions.clientId), { body: commands });
|
|
292
|
+
console.debug(`Successfully reloaded ${data.length} of ${commands.length} application (/) commands.`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function MergeRecursive(obj1, obj2) {
|
|
296
|
+
for (var p in obj2) {
|
|
297
|
+
try {
|
|
298
|
+
// Property in destination object set; update its value.
|
|
299
|
+
if (obj2[p].constructor == Object) {
|
|
300
|
+
obj1[p] = MergeRecursive(obj1[p], obj2[p]);
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
obj1[p] = obj2[p];
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
catch (e) {
|
|
307
|
+
// Property in destination object not set; create it and set its value.
|
|
308
|
+
obj1[p] = obj2[p];
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return obj1;
|
|
312
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Module } from "../types/Module";
|
|
2
|
-
import { ZumitoFramework } from "../ZumitoFramework";
|
|
3
|
-
export declare class baseModule extends Module {
|
|
4
|
-
constructor(modulePath: string, framework: ZumitoFramework);
|
|
5
|
-
registerEvents(): void;
|
|
6
|
-
}
|
|
1
|
+
import { Module } from "../types/Module";
|
|
2
|
+
import { ZumitoFramework } from "../ZumitoFramework";
|
|
3
|
+
export declare class baseModule extends Module {
|
|
4
|
+
constructor(modulePath: string, framework: ZumitoFramework);
|
|
5
|
+
registerEvents(): void;
|
|
6
|
+
}
|