@vulkano/core 1.18.0 → 1.19.0
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/.oxlintrc.json +42 -0
- package/.vscode/settings.json +14 -0
- package/app.js +51 -58
- package/bin/setup.js +3 -3
- package/biome.json +31 -0
- package/bootstrap/engines/handlebars.js +55 -0
- package/bootstrap/engines/index.js +31 -0
- package/bootstrap/engines/nunjucks.js +33 -0
- package/bootstrap/express.js +1 -1
- package/bootstrap/logger.js +2 -2
- package/bootstrap/responses.js +1 -1
- package/bootstrap/server.js +163 -289
- package/bootstrap/services.js +1 -1
- package/bootstrap/views.js +4 -7
- package/libs/Download.js +3 -3
- package/libs/Encrypter.js +1 -1
- package/libs/Filter.js +1 -1
- package/libs/VSError.js +1 -1
- package/libs/Vite.js +1 -1
- package/package.json +8 -17
- package/views/errors/handlebars/exception.html +48 -0
- package/views/errors/handlebars/no_action.html +63 -0
- package/views/errors/handlebars/no_controller.html +65 -0
- package/views/errors/handlebars/no_view.html +57 -0
package/bootstrap/server.js
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
const express = require('express');
|
|
8
8
|
const frameguard = require('frameguard');
|
|
9
9
|
const { Server } = require('socket.io');
|
|
10
|
-
const nunjucks = require('nunjucks');
|
|
11
10
|
const morgan = require('morgan');
|
|
12
11
|
const compression = require('compression');
|
|
13
12
|
const multer = require('multer');
|
|
@@ -28,8 +27,8 @@ const AllControllers = require('include-all')({
|
|
|
28
27
|
optional: true
|
|
29
28
|
});
|
|
30
29
|
|
|
31
|
-
//
|
|
32
|
-
const
|
|
30
|
+
// View Engine Setup
|
|
31
|
+
const setupViewEngine = require('./engines');
|
|
33
32
|
|
|
34
33
|
// JWT Middleware
|
|
35
34
|
const jwtMiddleware = require('../libs/Jwt');
|
|
@@ -41,18 +40,12 @@ const expressConfig = require('./express')();
|
|
|
41
40
|
const responses = require('./responses');
|
|
42
41
|
|
|
43
42
|
module.exports = function loadServer() {
|
|
44
|
-
|
|
45
43
|
return {
|
|
46
|
-
|
|
47
44
|
routes: {},
|
|
48
45
|
|
|
49
46
|
start: async function startServerApplication(cb) {
|
|
50
|
-
|
|
51
47
|
// Get ENV Vars
|
|
52
|
-
const {
|
|
53
|
-
JWT_SECRET_KEY,
|
|
54
|
-
COOKIES_SECRET_KEY
|
|
55
|
-
} = process.env || {};
|
|
48
|
+
const { JWT_SECRET_KEY, COOKIES_SECRET_KEY } = process.env || {};
|
|
56
49
|
|
|
57
50
|
const vulkano = express();
|
|
58
51
|
|
|
@@ -88,27 +81,26 @@ module.exports = function loadServer() {
|
|
|
88
81
|
// ---------------
|
|
89
82
|
// COMPRESSION - File: app/config/express/compression.js
|
|
90
83
|
// ---------------
|
|
91
|
-
vulkano.use(compression(
|
|
84
|
+
vulkano.use(compression(expressConfig.compression || {}));
|
|
92
85
|
|
|
93
86
|
// ---------------
|
|
94
87
|
// COOKIES - File: app/config/express/cookies.js
|
|
95
88
|
// ---------------
|
|
96
|
-
const {
|
|
97
|
-
enabled: cookiesEnabled
|
|
98
|
-
} = expressConfig.cookies || {};
|
|
89
|
+
const { enabled: cookiesEnabled } = expressConfig.cookies || {};
|
|
99
90
|
|
|
100
91
|
let cookiesSecretKey = null;
|
|
101
92
|
|
|
102
93
|
if (cookiesEnabled) {
|
|
103
|
-
|
|
104
|
-
|
|
94
|
+
cookiesSecretKey =
|
|
95
|
+
COOKIES_SECRET_KEY || expressConfig.cookies.key || expressConfig.cookies.secret || '';
|
|
105
96
|
|
|
106
97
|
if (!cookiesSecretKey) {
|
|
107
|
-
console.log(
|
|
98
|
+
console.log(
|
|
99
|
+
' \x1b[33mWARNING\x1b[0m: Set the secret key in the config/express/cookie.js file or COOKIES_SECRET_KEY in the .env file.'
|
|
100
|
+
);
|
|
108
101
|
}
|
|
109
102
|
|
|
110
103
|
vulkano.use(cookieParser(cookiesSecretKey));
|
|
111
|
-
|
|
112
104
|
}
|
|
113
105
|
|
|
114
106
|
// ---------------
|
|
@@ -136,7 +128,7 @@ module.exports = function loadServer() {
|
|
|
136
128
|
// ---------------
|
|
137
129
|
if (expressConfig.frameguard) {
|
|
138
130
|
if (Array.isArray(expressConfig.frameguard)) {
|
|
139
|
-
expressConfig.frameguard.forEach(
|
|
131
|
+
expressConfig.frameguard.forEach((frame) => {
|
|
140
132
|
vulkano.use(frameguard(frame));
|
|
141
133
|
});
|
|
142
134
|
} else {
|
|
@@ -147,8 +139,7 @@ module.exports = function loadServer() {
|
|
|
147
139
|
// ---------------
|
|
148
140
|
// PROTOCOL & POWERED BY - File: app/config/settings.js
|
|
149
141
|
// ---------------
|
|
150
|
-
vulkano.use(
|
|
151
|
-
|
|
142
|
+
vulkano.use((req, res, next) => {
|
|
152
143
|
const proto = req.secure ? 'https' : 'http';
|
|
153
144
|
const forwarded = req.headers['x-forwarded-proto'] || null;
|
|
154
145
|
const currentProtocol = (forwarded || proto).split('://')[0];
|
|
@@ -159,19 +150,22 @@ module.exports = function loadServer() {
|
|
|
159
150
|
}
|
|
160
151
|
|
|
161
152
|
next();
|
|
162
|
-
|
|
163
153
|
});
|
|
164
154
|
|
|
165
155
|
// ---------------
|
|
166
156
|
// REQUEST OPTIONS - File: app/config/express/cors.js
|
|
167
157
|
// ---------------
|
|
168
158
|
vulkano.options('*', (req, res) => {
|
|
169
|
-
|
|
170
159
|
// ---------------
|
|
171
160
|
// CORS
|
|
172
161
|
// ---------------
|
|
173
162
|
if (expressConfig.cors && expressConfig.cors.enabled) {
|
|
174
|
-
let tmpCustomHeaders = [
|
|
163
|
+
let tmpCustomHeaders = [
|
|
164
|
+
'X-Requested-With',
|
|
165
|
+
'X-HTTP-Method-Override',
|
|
166
|
+
'Content-Type',
|
|
167
|
+
'Accept'
|
|
168
|
+
];
|
|
175
169
|
tmpCustomHeaders = tmpCustomHeaders.concat(expressConfig.cors.headers || []);
|
|
176
170
|
res.header('Access-Control-Allow-Origin', expressConfig.cors.origin);
|
|
177
171
|
res.header('Access-Control-Allow-Headers', tmpCustomHeaders.join(', '));
|
|
@@ -181,17 +175,18 @@ module.exports = function loadServer() {
|
|
|
181
175
|
res.header('Allow', 'GET,PUT,PATCH,POST,DELETE,OPTIONS');
|
|
182
176
|
|
|
183
177
|
res.status(200).end();
|
|
184
|
-
|
|
185
178
|
});
|
|
186
179
|
|
|
187
180
|
// ---------------
|
|
188
181
|
// TIMEOUT - File: app/config/settings.js
|
|
189
182
|
// ---------------
|
|
190
|
-
vulkano.use(timeout(
|
|
183
|
+
vulkano.use(timeout(expressConfig.timeout || 120000));
|
|
191
184
|
|
|
192
|
-
vulkano.use(
|
|
185
|
+
vulkano.use((req, res, next) => {
|
|
193
186
|
if (req.timedout) {
|
|
194
|
-
res
|
|
187
|
+
res
|
|
188
|
+
.status(503)
|
|
189
|
+
.json({ success: false, statusCode: 503, error: { detail: 'Request timeout' } });
|
|
195
190
|
return;
|
|
196
191
|
}
|
|
197
192
|
next();
|
|
@@ -201,17 +196,22 @@ module.exports = function loadServer() {
|
|
|
201
196
|
// JWT - File: app/config/express/jwt.js
|
|
202
197
|
// ---------------
|
|
203
198
|
if (expressConfig.jwt && expressConfig.jwt.enabled) {
|
|
204
|
-
|
|
205
|
-
|
|
199
|
+
const jwtSecretKey =
|
|
200
|
+
JWT_SECRET_KEY || expressConfig.jwt.key || expressConfig.jwt.secret || '';
|
|
206
201
|
if (!jwtSecretKey) {
|
|
207
|
-
console.log(
|
|
202
|
+
console.log(
|
|
203
|
+
' \x1b[41mERROR\x1b[0m: Can not get key in config/express/jwt.js file or JWT_SECRET_KEY in .env file'
|
|
204
|
+
);
|
|
208
205
|
return;
|
|
209
206
|
}
|
|
210
207
|
|
|
211
208
|
// JWT (secret key)
|
|
212
|
-
vulkano.use(
|
|
213
|
-
|
|
214
|
-
|
|
209
|
+
vulkano.use(
|
|
210
|
+
expressConfig.jwt.path || '*',
|
|
211
|
+
jwtMiddleware.init().unless({
|
|
212
|
+
path: expressConfig.jwt.ignore || []
|
|
213
|
+
})
|
|
214
|
+
);
|
|
215
215
|
|
|
216
216
|
// JWT Handler error
|
|
217
217
|
vulkano.use((err, req, res, next) => {
|
|
@@ -221,18 +221,20 @@ module.exports = function loadServer() {
|
|
|
221
221
|
next();
|
|
222
222
|
}
|
|
223
223
|
});
|
|
224
|
-
|
|
225
224
|
}
|
|
226
225
|
|
|
227
226
|
// ---------------
|
|
228
227
|
// CORS - File: app/config/express/cors.js
|
|
229
228
|
// ---------------
|
|
230
229
|
if (expressConfig.cors && expressConfig.cors.enabled) {
|
|
231
|
-
|
|
232
230
|
vulkano.use(expressConfig.cors.path, (req, res, next) => {
|
|
233
|
-
|
|
234
231
|
// Enable CORS.
|
|
235
|
-
let tmpCorsHeaders = [
|
|
232
|
+
let tmpCorsHeaders = [
|
|
233
|
+
'X-Requested-With',
|
|
234
|
+
'X-HTTP-Method-Override',
|
|
235
|
+
'Content-Type',
|
|
236
|
+
'Accept'
|
|
237
|
+
];
|
|
236
238
|
tmpCorsHeaders = tmpCorsHeaders.concat(expressConfig.cors.headers || []);
|
|
237
239
|
|
|
238
240
|
res.header('Access-Control-Allow-Origin', expressConfig.cors.origin);
|
|
@@ -245,52 +247,41 @@ module.exports = function loadServer() {
|
|
|
245
247
|
res.header('Expires', '0'); // Proxies.
|
|
246
248
|
|
|
247
249
|
next();
|
|
248
|
-
|
|
249
250
|
});
|
|
250
251
|
}
|
|
251
252
|
|
|
252
253
|
// ---------------
|
|
253
254
|
// Express Session - File: app/config/express/session.js
|
|
254
255
|
// ---------------
|
|
255
|
-
const {
|
|
256
|
-
enabled: sessionEnabled
|
|
257
|
-
} = expressConfig.session || {};
|
|
256
|
+
const { enabled: sessionEnabled } = expressConfig.session || {};
|
|
258
257
|
|
|
259
258
|
if (sessionEnabled) {
|
|
260
|
-
|
|
261
259
|
if (!cookiesEnabled) {
|
|
262
|
-
console.log(
|
|
260
|
+
console.log(
|
|
261
|
+
" \x1b[41mERROR\x1b[0m: Can not load the Express Session because the Cookies aren't enabled"
|
|
262
|
+
);
|
|
263
263
|
return;
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
delete expressConfig.session.enabled;
|
|
267
267
|
|
|
268
268
|
vulkano.use(expressSession({ ...expressConfig.session, secret: cookiesSecretKey }));
|
|
269
|
-
|
|
270
269
|
}
|
|
271
270
|
|
|
272
271
|
// ---------------
|
|
273
272
|
// Content Security Policy - File: app/config/express/csp.js
|
|
274
273
|
// ---------------
|
|
275
|
-
const {
|
|
276
|
-
enabled: cspEnabled,
|
|
277
|
-
report: cspReportTo,
|
|
278
|
-
rules: cspRules
|
|
279
|
-
} = expressConfig.csp || {};
|
|
274
|
+
const { enabled: cspEnabled, report: cspReportTo, rules: cspRules } = expressConfig.csp || {};
|
|
280
275
|
|
|
281
276
|
if (cspEnabled && cspRules) {
|
|
282
|
-
|
|
283
277
|
const cspRulesHeader = [];
|
|
284
278
|
|
|
285
279
|
if (Array.isArray(cspRules) && cspRules.length > 0) {
|
|
286
|
-
|
|
287
|
-
for ( let i = 0; i < cspRules.length; i += 1) {
|
|
280
|
+
for (let i = 0; i < cspRules.length; i += 1) {
|
|
288
281
|
cspRulesHeader.push(cspRules[i]);
|
|
289
282
|
}
|
|
290
|
-
|
|
291
283
|
} else if (typeof cspRules === 'object') {
|
|
292
|
-
|
|
293
|
-
Object.keys(cspRules).forEach( (r) => {
|
|
284
|
+
Object.keys(cspRules).forEach((r) => {
|
|
294
285
|
const tmpValues = cspRules[r];
|
|
295
286
|
if (Array.isArray(tmpValues)) {
|
|
296
287
|
cspRulesHeader.push(`${r} ${tmpValues.join(' ')}`);
|
|
@@ -298,18 +289,13 @@ module.exports = function loadServer() {
|
|
|
298
289
|
cspRulesHeader.push(`${r} ${tmpValues}`);
|
|
299
290
|
}
|
|
300
291
|
});
|
|
301
|
-
|
|
302
292
|
} else if (typeof cspRules === 'string') {
|
|
303
|
-
|
|
304
293
|
cspRulesHeader.push(cspRules);
|
|
305
|
-
|
|
306
294
|
}
|
|
307
295
|
|
|
308
296
|
// Has Rules
|
|
309
297
|
if (cspRulesHeader.length > 0) {
|
|
310
|
-
|
|
311
|
-
vulkano.use( (req, res, next) => {
|
|
312
|
-
|
|
298
|
+
vulkano.use((req, res, next) => {
|
|
313
299
|
if (cspReportTo) {
|
|
314
300
|
res.setHeader('Report-To', JSON.stringify(cspReportTo));
|
|
315
301
|
}
|
|
@@ -317,134 +303,63 @@ module.exports = function loadServer() {
|
|
|
317
303
|
res.setHeader('Content-Security-Policy', cspRulesHeader.join('; '));
|
|
318
304
|
|
|
319
305
|
next();
|
|
320
|
-
|
|
321
306
|
});
|
|
322
|
-
|
|
323
307
|
}
|
|
324
|
-
|
|
325
308
|
}
|
|
326
309
|
|
|
327
310
|
// ---------------
|
|
328
311
|
// Permission Policy - File: app/config/express/permissionPolicy.js
|
|
329
312
|
// ---------------
|
|
330
|
-
const {
|
|
331
|
-
|
|
332
|
-
permissions: ppPermissions
|
|
333
|
-
} = expressConfig.permissionPolicy || {};
|
|
313
|
+
const { enabled: ppEnabled, permissions: ppPermissions } =
|
|
314
|
+
expressConfig.permissionPolicy || {};
|
|
334
315
|
|
|
335
316
|
if (ppEnabled) {
|
|
336
|
-
|
|
337
317
|
if (!Array.isArray(ppPermissions)) {
|
|
338
318
|
console.error('Vulkano Error: ', 'The Permission Policy values must be an array');
|
|
339
319
|
return;
|
|
340
320
|
}
|
|
341
321
|
|
|
342
322
|
if (ppPermissions.length > 0) {
|
|
343
|
-
|
|
344
|
-
vulkano.use( (req, res, next) => {
|
|
345
|
-
|
|
323
|
+
vulkano.use((req, res, next) => {
|
|
346
324
|
res.setHeader('Permissions-Policy', ppPermissions.join(', '));
|
|
347
325
|
|
|
348
326
|
next();
|
|
349
|
-
|
|
350
327
|
});
|
|
351
|
-
|
|
352
328
|
}
|
|
353
|
-
|
|
354
329
|
}
|
|
355
330
|
|
|
356
331
|
// ---------------
|
|
357
332
|
// REDIS - File: app/config/redis.js
|
|
358
333
|
// ---------------
|
|
359
|
-
const {
|
|
360
|
-
enabled: redisEnabled
|
|
361
|
-
} = app.config.redis || {};
|
|
334
|
+
const { enabled: redisEnabled } = app.config.redis || {};
|
|
362
335
|
|
|
363
336
|
app.redisClient = null;
|
|
364
337
|
|
|
365
338
|
if (redisEnabled === true) {
|
|
366
|
-
|
|
367
|
-
const {
|
|
368
|
-
redis
|
|
369
|
-
} = app.config || {};
|
|
339
|
+
const { redis } = app.config || {};
|
|
370
340
|
|
|
371
341
|
const rClient = socketRedis(redis);
|
|
372
342
|
rClient.on('error', (err) => console.log('Redis Client Error', err));
|
|
373
343
|
|
|
374
344
|
app.redisClient = await rClient.connect();
|
|
375
|
-
|
|
376
345
|
}
|
|
377
346
|
|
|
378
347
|
// ---------------
|
|
379
348
|
// VIEWS
|
|
380
349
|
// ---------------
|
|
381
350
|
|
|
382
|
-
const
|
|
383
|
-
...viewsConfig,
|
|
384
|
-
...(app.server.views || {})
|
|
385
|
-
};
|
|
386
|
-
|
|
387
|
-
vulkano.set('views', views.path);
|
|
388
|
-
|
|
389
|
-
const {
|
|
390
|
-
settings: nunjucksSettingsUser
|
|
391
|
-
} = views || {};
|
|
392
|
-
|
|
393
|
-
const nunjucksSettings = {
|
|
394
|
-
autoescape: true,
|
|
395
|
-
watch: !app.PRODUCTION,
|
|
396
|
-
...(nunjucksSettingsUser || {}),
|
|
397
|
-
express: vulkano
|
|
398
|
-
};
|
|
399
|
-
|
|
400
|
-
const envNunjucks = nunjucks.configure([views.path, CORE_PATH], nunjucksSettings);
|
|
401
|
-
|
|
402
|
-
app.server.views._engine = envNunjucks;
|
|
403
|
-
|
|
404
|
-
envNunjucks.addGlobal('app', app);
|
|
405
|
-
|
|
406
|
-
if (views.globals && Array.isArray(views.globals)) {
|
|
407
|
-
views.globals.forEach((global) => {
|
|
408
|
-
Object.keys(global || []).forEach((i) => {
|
|
409
|
-
envNunjucks.addGlobal(i, global[i]);
|
|
410
|
-
});
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
if (views.helpers && Array.isArray(views.helpers)) {
|
|
415
|
-
views.helpers.forEach((helper) => {
|
|
416
|
-
Object.keys(helper || []).forEach((i) => {
|
|
417
|
-
envNunjucks.addGlobal(i, helper[i]);
|
|
418
|
-
});
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
if (views.filters && Array.isArray(views.filters)) {
|
|
423
|
-
views.filters.forEach((filter) => {
|
|
424
|
-
Object.keys(filter || []).forEach((i) => {
|
|
425
|
-
envNunjucks.addFilter(i, filter[i]);
|
|
426
|
-
});
|
|
427
|
-
});
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
if (views.extensions && Array.isArray(views.extensions)) {
|
|
431
|
-
views.extensions.forEach((extension) => {
|
|
432
|
-
Object.keys(extension || []).forEach((i) => {
|
|
433
|
-
envNunjucks.addExtension(i, extension[i]);
|
|
434
|
-
});
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
app.nunjucks = nunjucks;
|
|
351
|
+
const viewsEngine = setupViewEngine(vulkano);
|
|
439
352
|
|
|
440
353
|
// ---------------
|
|
441
354
|
// Middlewares
|
|
442
355
|
// ---------------
|
|
443
356
|
|
|
444
357
|
// Middleware File (compatibility)
|
|
445
|
-
const middleware =
|
|
446
|
-
|
|
447
|
-
|
|
358
|
+
const middleware =
|
|
359
|
+
app.config.middleware ||
|
|
360
|
+
((req, res, next) => {
|
|
361
|
+
next();
|
|
362
|
+
});
|
|
448
363
|
|
|
449
364
|
// Middleware Folder — routes.js always loads first if present
|
|
450
365
|
const middlewares = app.config.middlewares || {};
|
|
@@ -453,8 +368,10 @@ module.exports = function loadServer() {
|
|
|
453
368
|
vulkano.use(middlewares.routes);
|
|
454
369
|
}
|
|
455
370
|
|
|
456
|
-
Object.keys(middlewares).forEach(
|
|
457
|
-
if (item === 'routes')
|
|
371
|
+
Object.keys(middlewares).forEach((item) => {
|
|
372
|
+
if (item === 'routes') {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
458
375
|
const middlewareFunction = middlewares[item];
|
|
459
376
|
if (typeof middlewareFunction === 'function') {
|
|
460
377
|
vulkano.use(middlewareFunction);
|
|
@@ -470,9 +387,7 @@ module.exports = function loadServer() {
|
|
|
470
387
|
// ROUTES
|
|
471
388
|
// ---------------
|
|
472
389
|
|
|
473
|
-
const {
|
|
474
|
-
routes
|
|
475
|
-
} = app;
|
|
390
|
+
const { routes } = app;
|
|
476
391
|
|
|
477
392
|
let method;
|
|
478
393
|
let pathToRoute;
|
|
@@ -480,13 +395,9 @@ module.exports = function loadServer() {
|
|
|
480
395
|
|
|
481
396
|
// Routes from convention (controller name & method = route)
|
|
482
397
|
Object.keys(routes).forEach((route) => {
|
|
483
|
-
|
|
484
398
|
const parts = route.split(' ');
|
|
485
399
|
|
|
486
|
-
const [
|
|
487
|
-
methodToRun,
|
|
488
|
-
pathToRun
|
|
489
|
-
] = parts;
|
|
400
|
+
const [methodToRun, pathToRun] = parts;
|
|
490
401
|
|
|
491
402
|
method = methodToRun;
|
|
492
403
|
|
|
@@ -501,12 +412,10 @@ module.exports = function loadServer() {
|
|
|
501
412
|
} else {
|
|
502
413
|
vulkano[method](pathToRoute, middleware, handler);
|
|
503
414
|
}
|
|
504
|
-
|
|
505
415
|
});
|
|
506
416
|
|
|
507
417
|
// Routes from config/routes.js
|
|
508
418
|
Object.keys(this.routes || {}).forEach((i) => {
|
|
509
|
-
|
|
510
419
|
const current = this.routes[i];
|
|
511
420
|
|
|
512
421
|
// Initializer functions: keys that are not path-based ('/...') and not
|
|
@@ -514,7 +423,9 @@ module.exports = function loadServer() {
|
|
|
514
423
|
// directly via app.vulkano.get(), app.vulkano.post(), etc.
|
|
515
424
|
const keyParts = i.split(' ');
|
|
516
425
|
const isPathRoute = i.includes('/');
|
|
517
|
-
const isMethodRoute =
|
|
426
|
+
const isMethodRoute =
|
|
427
|
+
['get', 'post', 'put', 'delete', 'patch'].includes(keyParts[0].toLowerCase()) &&
|
|
428
|
+
keyParts.length > 1;
|
|
518
429
|
|
|
519
430
|
if (!isPathRoute && !isMethodRoute && typeof current === 'function') {
|
|
520
431
|
current();
|
|
@@ -525,9 +436,15 @@ module.exports = function loadServer() {
|
|
|
525
436
|
let pathToRun = parts.pop();
|
|
526
437
|
|
|
527
438
|
// Capture the HTTP Method
|
|
528
|
-
let option =
|
|
529
|
-
|
|
530
|
-
if (
|
|
439
|
+
let option = parts[0] !== undefined ? String(parts[0]).toLowerCase() : 'get';
|
|
440
|
+
|
|
441
|
+
if (
|
|
442
|
+
option !== 'get' &&
|
|
443
|
+
option !== 'post' &&
|
|
444
|
+
option !== 'put' &&
|
|
445
|
+
option !== 'patch' &&
|
|
446
|
+
option !== 'delete'
|
|
447
|
+
) {
|
|
531
448
|
option = 'get';
|
|
532
449
|
}
|
|
533
450
|
|
|
@@ -538,24 +455,18 @@ module.exports = function loadServer() {
|
|
|
538
455
|
let toExecute = null;
|
|
539
456
|
|
|
540
457
|
if (typeof current === 'function') {
|
|
541
|
-
|
|
542
458
|
toExecute = current;
|
|
543
|
-
|
|
544
459
|
} else {
|
|
545
|
-
|
|
546
460
|
const fullPath = this.routes[i].split('.');
|
|
547
461
|
|
|
548
|
-
const [
|
|
549
|
-
moduleToRun,
|
|
550
|
-
controllerToRun,
|
|
551
|
-
actionToRun
|
|
552
|
-
] = fullPath;
|
|
462
|
+
const [moduleToRun, controllerToRun, actionToRun] = fullPath;
|
|
553
463
|
|
|
554
464
|
let module;
|
|
555
465
|
let controller;
|
|
556
466
|
let action;
|
|
557
467
|
|
|
558
|
-
if (actionToRun) {
|
|
468
|
+
if (actionToRun) {
|
|
469
|
+
// Has folder
|
|
559
470
|
module = moduleToRun;
|
|
560
471
|
controller = controllerToRun;
|
|
561
472
|
action = actionToRun;
|
|
@@ -567,16 +478,20 @@ module.exports = function loadServer() {
|
|
|
567
478
|
|
|
568
479
|
try {
|
|
569
480
|
toExecute = module
|
|
570
|
-
?
|
|
481
|
+
? AllControllers[module][controller][action]
|
|
571
482
|
: AllControllers[controller][action];
|
|
572
483
|
} catch (e) {
|
|
573
484
|
toExecute = null;
|
|
574
485
|
}
|
|
575
486
|
|
|
576
487
|
if (!toExecute) {
|
|
577
|
-
console.error(
|
|
488
|
+
console.error(
|
|
489
|
+
'\x1b[31mError:',
|
|
490
|
+
'Controller not found in',
|
|
491
|
+
module ? `${module}.${controller}.${action}` : `${controller}.${action}`,
|
|
492
|
+
'\x1b[0m'
|
|
493
|
+
);
|
|
578
494
|
}
|
|
579
|
-
|
|
580
495
|
}
|
|
581
496
|
|
|
582
497
|
if (toExecute) {
|
|
@@ -586,7 +501,6 @@ module.exports = function loadServer() {
|
|
|
586
501
|
vulkano[option](pathToRun || '/', middleware, toExecute);
|
|
587
502
|
}
|
|
588
503
|
}
|
|
589
|
-
|
|
590
504
|
});
|
|
591
505
|
|
|
592
506
|
const server = await vulkano.listen(expressConfig.port);
|
|
@@ -605,7 +519,6 @@ module.exports = function loadServer() {
|
|
|
605
519
|
// ERROR 404
|
|
606
520
|
// ---------------
|
|
607
521
|
vulkano.use((req, res) => {
|
|
608
|
-
|
|
609
522
|
if (+res.statusCode >= 500 && +res.statusCode < 600) {
|
|
610
523
|
throw new Error();
|
|
611
524
|
}
|
|
@@ -617,46 +530,41 @@ module.exports = function loadServer() {
|
|
|
617
530
|
return;
|
|
618
531
|
}
|
|
619
532
|
|
|
620
|
-
|
|
621
|
-
const isController = routesRegistered.filter( (r) => {
|
|
533
|
+
const errFolder = viewsEngine === 'handlebars' ? 'handlebars/' : '';
|
|
622
534
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
} = r || {};
|
|
535
|
+
// Verify if the error is a controller
|
|
536
|
+
const isController = routesRegistered.filter((r) => {
|
|
537
|
+
const { path: routePath } = r || {};
|
|
626
538
|
|
|
627
|
-
const routerControllerToCheck =
|
|
628
|
-
|
|
629
|
-
|
|
539
|
+
const routerControllerToCheck =
|
|
540
|
+
typeof Filter !== 'undefined'
|
|
541
|
+
? Filter.get(req.path, 'trim', '/').split('/')[0]
|
|
542
|
+
: req.path.replace(/^\/+|\/+$/g, '').split('/')[0];
|
|
630
543
|
|
|
631
544
|
return routePath.startsWith(`/${routerControllerToCheck}`);
|
|
632
|
-
|
|
633
545
|
});
|
|
634
546
|
|
|
635
547
|
if (isController.length === 0) {
|
|
636
|
-
|
|
637
|
-
res.render(`${CORE_PATH}/views/errors/no_controller.html`, {
|
|
548
|
+
res.render(`${CORE_PATH}/views/errors/${errFolder}no_controller.html`, {
|
|
638
549
|
method: req.method,
|
|
639
550
|
controller: req.path.split('/')[1]
|
|
640
551
|
});
|
|
641
552
|
|
|
642
553
|
return;
|
|
643
|
-
|
|
644
554
|
}
|
|
645
555
|
|
|
646
556
|
// Show the action name error
|
|
647
|
-
res.render(`${CORE_PATH}/views/errors
|
|
557
|
+
res.render(`${CORE_PATH}/views/errors/${errFolder}no_action.html`, {
|
|
648
558
|
method: req.method,
|
|
649
559
|
controller: req.path.split('/')[1],
|
|
650
560
|
action: req.path.split('/')[2]
|
|
651
561
|
});
|
|
652
|
-
|
|
653
562
|
});
|
|
654
563
|
|
|
655
564
|
// ---------------
|
|
656
565
|
// ERROR 5XX
|
|
657
566
|
// ---------------
|
|
658
567
|
vulkano.use((err, req, res, next) => {
|
|
659
|
-
|
|
660
568
|
if (res.headersSent) {
|
|
661
569
|
next(err);
|
|
662
570
|
return;
|
|
@@ -664,32 +572,36 @@ module.exports = function loadServer() {
|
|
|
664
572
|
|
|
665
573
|
// Timeout — always respond with JSON regardless of request type
|
|
666
574
|
if (req.timedout || (err && err.timeout)) {
|
|
667
|
-
res
|
|
575
|
+
res
|
|
576
|
+
.status(503)
|
|
577
|
+
.json({ success: false, statusCode: 503, error: { detail: 'Request timeout' } });
|
|
668
578
|
return;
|
|
669
579
|
}
|
|
670
580
|
|
|
671
|
-
const status = err ?
|
|
581
|
+
const status = err ? err.status || 500 : res.statusCode || 500;
|
|
672
582
|
|
|
673
583
|
res.status(status);
|
|
674
584
|
|
|
675
585
|
// AJAX Response
|
|
676
586
|
if (req.xhr) {
|
|
677
|
-
|
|
678
587
|
res.jsonp({
|
|
679
588
|
success: false,
|
|
680
589
|
statusCode: status,
|
|
681
590
|
error: {
|
|
682
|
-
detail:
|
|
683
|
-
|
|
591
|
+
detail:
|
|
592
|
+
err.message ||
|
|
593
|
+
err.error ||
|
|
594
|
+
err.invalidAttributes ||
|
|
595
|
+
err.toString() ||
|
|
596
|
+
'Object Not Found',
|
|
597
|
+
stack: app.PRODUCTION ? {} : err.stack || {}
|
|
684
598
|
}
|
|
685
599
|
});
|
|
686
600
|
|
|
687
601
|
return;
|
|
688
|
-
|
|
689
602
|
}
|
|
690
603
|
|
|
691
604
|
if (app.PRODUCTION) {
|
|
692
|
-
|
|
693
605
|
if (+status > 400 && +status < 500) {
|
|
694
606
|
res.render(`${vulkano.get('views')}/_shared/errors/404.html`);
|
|
695
607
|
} else {
|
|
@@ -697,10 +609,9 @@ module.exports = function loadServer() {
|
|
|
697
609
|
}
|
|
698
610
|
|
|
699
611
|
return;
|
|
700
|
-
|
|
701
612
|
}
|
|
702
613
|
|
|
703
|
-
const errStack =
|
|
614
|
+
const errStack = err && err.stack ? String(err.stack) : '';
|
|
704
615
|
const isMissingTemplate = errStack.includes('template not found');
|
|
705
616
|
|
|
706
617
|
let missingView = '';
|
|
@@ -709,9 +620,11 @@ module.exports = function loadServer() {
|
|
|
709
620
|
missingView = `${afterNotFound.split('.')[0].trim()}.html`;
|
|
710
621
|
}
|
|
711
622
|
|
|
623
|
+
const errFolder2 = viewsEngine === 'handlebars' ? 'handlebars/' : '';
|
|
624
|
+
|
|
712
625
|
const errorViewToShow = isMissingTemplate
|
|
713
|
-
? `${CORE_PATH}/views/errors
|
|
714
|
-
: `${CORE_PATH}/views/errors
|
|
626
|
+
? `${CORE_PATH}/views/errors/${errFolder2}no_view.html`
|
|
627
|
+
: `${CORE_PATH}/views/errors/${errFolder2}exception.html`;
|
|
715
628
|
|
|
716
629
|
res.render(errorViewToShow, {
|
|
717
630
|
statusCode: status,
|
|
@@ -721,7 +634,6 @@ module.exports = function loadServer() {
|
|
|
721
634
|
view: missingView,
|
|
722
635
|
stack: errStack
|
|
723
636
|
});
|
|
724
|
-
|
|
725
637
|
});
|
|
726
638
|
|
|
727
639
|
app.vulkano = vulkano;
|
|
@@ -730,19 +642,14 @@ module.exports = function loadServer() {
|
|
|
730
642
|
// ---------------
|
|
731
643
|
// SOCKETS
|
|
732
644
|
// ---------------
|
|
733
|
-
const {
|
|
734
|
-
sockets
|
|
735
|
-
} = expressConfig || {};
|
|
645
|
+
const { sockets } = expressConfig || {};
|
|
736
646
|
|
|
737
647
|
if (!sockets || (sockets && !sockets.enabled)) {
|
|
738
648
|
cb();
|
|
739
649
|
return;
|
|
740
650
|
}
|
|
741
651
|
|
|
742
|
-
const {
|
|
743
|
-
config: socketsConfig,
|
|
744
|
-
middlewares: socketsMiddlewares
|
|
745
|
-
} = sockets;
|
|
652
|
+
const { config: socketsConfig, middlewares: socketsMiddlewares } = sockets;
|
|
746
653
|
|
|
747
654
|
const socketProps = {
|
|
748
655
|
...(socketsConfig || {}),
|
|
@@ -759,41 +666,31 @@ module.exports = function loadServer() {
|
|
|
759
666
|
}
|
|
760
667
|
}
|
|
761
668
|
|
|
762
|
-
const {
|
|
763
|
-
adapter
|
|
764
|
-
} = sockets;
|
|
669
|
+
const { adapter } = sockets;
|
|
765
670
|
|
|
766
|
-
const {
|
|
767
|
-
redis: redisAdapter,
|
|
768
|
-
mongodb: mongodbAdapter
|
|
769
|
-
} = sockets.adapters || {};
|
|
671
|
+
const { redis: redisAdapter, mongodb: mongodbAdapter } = sockets.adapters || {};
|
|
770
672
|
|
|
771
|
-
if (
|
|
673
|
+
if (String(adapter).toLocaleLowerCase() === 'redis') {
|
|
674
|
+
const { socket: socketRedisConfig } = redisAdapter || {};
|
|
772
675
|
|
|
773
|
-
const {
|
|
774
|
-
socket: socketRedisConfig
|
|
775
|
-
} = redisAdapter || {};
|
|
776
|
-
|
|
777
|
-
const {
|
|
778
|
-
host,
|
|
779
|
-
port
|
|
780
|
-
} = socketRedisConfig || redisAdapter || {};
|
|
676
|
+
const { host, port } = socketRedisConfig || redisAdapter || {};
|
|
781
677
|
|
|
782
678
|
if (!host || !port) {
|
|
783
|
-
throw new Error(
|
|
679
|
+
throw new Error(
|
|
680
|
+
'Unable to connect to Redis. File: "app/config/sockets/adapters/redis.js" to connect the sockets'
|
|
681
|
+
);
|
|
784
682
|
}
|
|
785
683
|
|
|
786
684
|
if (socketProps.transports.includes('polling')) {
|
|
787
|
-
throw new Error(
|
|
685
|
+
throw new Error(
|
|
686
|
+
'To enable Sockets with Redis support, the transports must be set ¨websocket¨ only'
|
|
687
|
+
);
|
|
788
688
|
}
|
|
789
|
-
|
|
790
|
-
} else if ( String(adapter).toLocaleLowerCase() === 'mongodb') {
|
|
791
|
-
|
|
689
|
+
} else if (String(adapter).toLocaleLowerCase() === 'mongodb') {
|
|
792
690
|
// if (socketProps.transports.includes('polling')) {
|
|
793
691
|
// eslint-disable-next-line max-len
|
|
794
692
|
// console.log('To enable Sockets with MongoDB support the transports must be set to ["websocket"] only');
|
|
795
693
|
// }
|
|
796
|
-
|
|
797
694
|
}
|
|
798
695
|
|
|
799
696
|
const io = new Server(server, socketProps);
|
|
@@ -801,58 +698,56 @@ module.exports = function loadServer() {
|
|
|
801
698
|
let pubClient = null;
|
|
802
699
|
let subClient = null;
|
|
803
700
|
|
|
804
|
-
if (
|
|
805
|
-
|
|
701
|
+
if (String(adapter).toLocaleLowerCase() === 'redis') {
|
|
806
702
|
pubClient = socketRedis(redisAdapter);
|
|
807
703
|
pubClient.on('error', (err) => console.log('Socket Redis Client Error', err));
|
|
808
704
|
|
|
809
705
|
subClient = pubClient.duplicate();
|
|
810
706
|
|
|
811
707
|
io.adapter(socketRedisAdapter(pubClient, subClient));
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
const
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
const socketsCollection = String(
|
|
708
|
+
} else if (String(adapter).toLocaleLowerCase() === 'mongodb') {
|
|
709
|
+
const { settings: socketsMongoSettings } = mongodbAdapter || {};
|
|
710
|
+
|
|
711
|
+
const socketsConnection = String(
|
|
712
|
+
process.env.SOCKETS_MONGO_URI || mongodbAdapter.connection || ''
|
|
713
|
+
).trim();
|
|
714
|
+
let socketsDatabase = String(
|
|
715
|
+
process.env.SOCKETS_MONGO_DATABASE || mongodbAdapter.database || ''
|
|
716
|
+
).trim();
|
|
717
|
+
const socketsCollection = String(
|
|
718
|
+
process.env.SOCKETS_MONGO_COLLECTION ||
|
|
719
|
+
mongodbAdapter.collection ||
|
|
720
|
+
'socket.io-adapter-events'
|
|
721
|
+
).trim();
|
|
822
722
|
|
|
823
723
|
let socketsMongoCollection = null;
|
|
824
724
|
|
|
825
725
|
try {
|
|
826
|
-
|
|
827
726
|
let mongoClientDB = null;
|
|
828
727
|
|
|
829
728
|
// If no active Mongoose connection, create a dedicated one
|
|
830
729
|
if (!mongoose.connection.readyState) {
|
|
831
|
-
|
|
832
730
|
if (!socketsConnection) {
|
|
833
|
-
throw new Error(
|
|
731
|
+
throw new Error(
|
|
732
|
+
'Unable to connecto to the database for SocketIO. Please check the env var SOCKETS_MONGO_URI and try again.'
|
|
733
|
+
);
|
|
834
734
|
}
|
|
835
735
|
|
|
836
736
|
const socketMongooseConnection = await socketMongoose.connect(socketsConnection);
|
|
837
737
|
mongoClientDB = socketMongooseConnection.connection.getClient();
|
|
838
|
-
|
|
839
738
|
} else {
|
|
840
|
-
|
|
841
739
|
// Get current connection
|
|
842
740
|
mongoClientDB = mongoose.connection.getClient();
|
|
843
741
|
socketsDatabase = mongoose.connection.db.s.namespace.db;
|
|
844
742
|
|
|
845
743
|
// SOCKETS_MONGO_URI
|
|
846
|
-
if (socketsConnection &&
|
|
847
|
-
|
|
744
|
+
if (socketsConnection && socketsConnection !== mongoClientDB.s.url) {
|
|
848
745
|
const socketMongoInstance = new socketMongoose.Mongoose();
|
|
849
746
|
|
|
850
747
|
const socketMongooseConnection = await socketMongoInstance.connect(socketsConnection);
|
|
851
748
|
mongoClientDB = socketMongooseConnection.connection.getClient();
|
|
852
749
|
socketsDatabase = socketMongoInstance.connection.db.s.namespace.db;
|
|
853
|
-
|
|
854
750
|
}
|
|
855
|
-
|
|
856
751
|
}
|
|
857
752
|
|
|
858
753
|
socketsMongoCollection = mongoClientDB.db(socketsDatabase).collection(socketsCollection);
|
|
@@ -864,36 +759,27 @@ module.exports = function loadServer() {
|
|
|
864
759
|
};
|
|
865
760
|
|
|
866
761
|
socketsMongoCollection.createIndex({ createdAt: 1 }, propsToMongoCollection);
|
|
867
|
-
|
|
868
762
|
} catch (err) {
|
|
869
763
|
console.log(err);
|
|
870
764
|
throw new Error('To enable Sockets with MongoDB support. Check the connection.');
|
|
871
765
|
}
|
|
872
766
|
|
|
873
767
|
io.adapter(socketMongoAdapter(socketsMongoCollection, { addCreatedAtField: true }));
|
|
874
|
-
|
|
875
768
|
}
|
|
876
769
|
|
|
877
|
-
Promise
|
|
878
|
-
.all([
|
|
879
|
-
(pubClient ? pubClient.connect() : null),
|
|
880
|
-
(subClient ? subClient.connect() : null)
|
|
881
|
-
])
|
|
770
|
+
Promise.all([pubClient ? pubClient.connect() : null, subClient ? subClient.connect() : null])
|
|
882
771
|
.catch((err) => {
|
|
883
772
|
throw new Error(`Socket Redis adapter failed to connect: ${err.message}`);
|
|
884
773
|
})
|
|
885
774
|
.then(() => {
|
|
886
|
-
|
|
887
775
|
io.on('connection', (socket) => {
|
|
888
|
-
|
|
889
|
-
if ( typeof sockets.onConnect === 'function') {
|
|
776
|
+
if (typeof sockets.onConnect === 'function') {
|
|
890
777
|
sockets.onConnect(socket);
|
|
891
778
|
}
|
|
892
779
|
|
|
893
780
|
const socketEvents = sockets.events || sockets.routes || {};
|
|
894
781
|
|
|
895
|
-
Object.keys(socketEvents).forEach(
|
|
896
|
-
|
|
782
|
+
Object.keys(socketEvents).forEach((i) => {
|
|
897
783
|
const checkPath = socketEvents[i] || '';
|
|
898
784
|
|
|
899
785
|
let toExecute = null;
|
|
@@ -902,38 +788,25 @@ module.exports = function loadServer() {
|
|
|
902
788
|
let action = null;
|
|
903
789
|
|
|
904
790
|
if (typeof checkPath === 'function') {
|
|
905
|
-
|
|
906
791
|
toExecute = checkPath;
|
|
907
|
-
|
|
908
792
|
} else {
|
|
909
|
-
|
|
910
793
|
const fullPath = checkPath.split('.');
|
|
911
794
|
|
|
912
|
-
if (fullPath.length > 2) {
|
|
913
|
-
|
|
914
|
-
[
|
|
915
|
-
module,
|
|
916
|
-
controller,
|
|
917
|
-
action
|
|
918
|
-
] = fullPath;
|
|
795
|
+
if (fullPath.length > 2) {
|
|
796
|
+
// Has folder
|
|
919
797
|
|
|
798
|
+
[module, controller, action] = fullPath;
|
|
920
799
|
} else {
|
|
921
|
-
|
|
922
|
-
[
|
|
923
|
-
controller,
|
|
924
|
-
action
|
|
925
|
-
] = fullPath;
|
|
926
|
-
|
|
800
|
+
[controller, action] = fullPath;
|
|
927
801
|
}
|
|
928
802
|
|
|
929
803
|
try {
|
|
930
804
|
toExecute = module
|
|
931
|
-
?
|
|
805
|
+
? AllControllers[module][controller][action]
|
|
932
806
|
: AllControllers[controller][action];
|
|
933
807
|
} catch (e) {
|
|
934
808
|
toExecute = null;
|
|
935
809
|
}
|
|
936
|
-
|
|
937
810
|
}
|
|
938
811
|
|
|
939
812
|
if (toExecute) {
|
|
@@ -941,14 +814,19 @@ module.exports = function loadServer() {
|
|
|
941
814
|
toExecute({ socket, body: body || {} }, callback || (() => {}));
|
|
942
815
|
});
|
|
943
816
|
} else {
|
|
944
|
-
console.error(
|
|
817
|
+
console.error(
|
|
818
|
+
'\x1b[31mError:',
|
|
819
|
+
'Controller not found in',
|
|
820
|
+
module ? `${module}.${controller}.${action}` : `${controller}.${action}`,
|
|
821
|
+
'\x1b[0m',
|
|
822
|
+
'to socket event',
|
|
823
|
+
i
|
|
824
|
+
);
|
|
945
825
|
}
|
|
946
|
-
|
|
947
826
|
});
|
|
948
827
|
|
|
949
828
|
vulkano.set('socket', socket);
|
|
950
829
|
app.socket = socket;
|
|
951
|
-
|
|
952
830
|
});
|
|
953
831
|
|
|
954
832
|
// Expose io globally so controllers can emit events
|
|
@@ -960,7 +838,7 @@ module.exports = function loadServer() {
|
|
|
960
838
|
io.use(sockets.middleware);
|
|
961
839
|
}
|
|
962
840
|
|
|
963
|
-
Object.keys(socketsMiddlewares || {}).forEach(
|
|
841
|
+
Object.keys(socketsMiddlewares || {}).forEach((item) => {
|
|
964
842
|
const middlewareFunction = socketsMiddlewares[item];
|
|
965
843
|
if (typeof middlewareFunction === 'function') {
|
|
966
844
|
io.use(middlewareFunction);
|
|
@@ -971,11 +849,7 @@ module.exports = function loadServer() {
|
|
|
971
849
|
app.vulkano = vulkano;
|
|
972
850
|
|
|
973
851
|
cb();
|
|
974
|
-
|
|
975
852
|
});
|
|
976
|
-
|
|
977
853
|
}
|
|
978
|
-
|
|
979
854
|
};
|
|
980
|
-
|
|
981
855
|
};
|