tspace-spear 1.2.4 → 1.2.5

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.
@@ -1,1356 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.Express = void 0;
40
- const http_1 = __importStar(require("http"));
41
- const cluster_1 = __importDefault(require("cluster"));
42
- const os_1 = __importDefault(require("os"));
43
- const fs_1 = __importDefault(require("fs"));
44
- const path_1 = __importDefault(require("path"));
45
- const on_finished_1 = __importDefault(require("on-finished"));
46
- const ws_1 = __importDefault(require("ws"));
47
- const parser_factory_1 = require("./parser-factory");
48
- const fast_router_1 = require("./fast-router");
49
- /**
50
- *
51
- * The 'Spear' class is used to create a server and handle HTTP requests.
52
- *
53
- * @returns {Spear} application
54
- * @example
55
- * new Spear()
56
- * .get('/' , () => 'Hello world!')
57
- * .get('/json' , () => {
58
- * return {
59
- * message : 'Hello world!'
60
- * }
61
- * })
62
- * .listen(3000 , () => console.log('server listening on port : 3000'))
63
- *
64
- */
65
- class Express {
66
- _controllers;
67
- _middlewares;
68
- _globalPrefix;
69
- _router = new fast_router_1.FastRouter();
70
- _parser = new parser_factory_1.ParserFactory();
71
- _adapter = http_1.default;
72
- _cluster;
73
- _cors;
74
- _swagger = {
75
- use: false,
76
- path: '/api/docs',
77
- servers: [
78
- {
79
- url: 'http://localhost:3000'
80
- }
81
- ],
82
- tags: [],
83
- info: {
84
- title: "API Documentation",
85
- description: "This is a sample documentation",
86
- version: "1.0.0"
87
- }
88
- };
89
- _swaggerSpecs = [];
90
- _ws;
91
- _errorHandler = null;
92
- _globalMiddlewares = [];
93
- _formatResponse = null;
94
- _onListeners = [];
95
- _fileUploadOptions = {
96
- limit: Infinity,
97
- tempFileDir: 'tmp',
98
- removeTempFile: {
99
- remove: false,
100
- ms: 1000 * 60 * 10
101
- }
102
- };
103
- _express = true;
104
- constructor({ controllers, middlewares, globalPrefix, logger, cluster, adapter, express }) {
105
- if (logger)
106
- this.useLogger();
107
- if (cluster)
108
- this.useCluster(cluster);
109
- if (adapter)
110
- this.useAdater(adapter);
111
- // if(express)
112
- this._controllers = controllers;
113
- // this._middlewares = middlewares;
114
- this._globalPrefix = globalPrefix == null ? '' : globalPrefix;
115
- }
116
- /**
117
- * The get 'instance' method is used to get the instance of Spear.
118
- *
119
- * @returns {this}
120
- */
121
- get instance() {
122
- return this;
123
- }
124
- /**
125
- * The get 'routers' method is used get the all routers.
126
- *
127
- * @returns {FastRouter}
128
- */
129
- get routers() {
130
- return this._router;
131
- }
132
- /**
133
- * The 'ws' method is used to creates the WebSocket server.
134
- *
135
- * @callback {Function} WebSocketServer
136
- * @param {WebSocketServer} wss - WebSocketServer
137
- * @returns {this}
138
- */
139
- ws(handlers, options) {
140
- this._ws.handler = handlers();
141
- this._ws.options = options ?? {};
142
- return this;
143
- }
144
- /**
145
- * The 'use' method is used to add the middleware into the request pipeline.
146
- *
147
- * @callback {Function} middleware
148
- * @property {Object} ctx - context { req , res , query , params , cookies , files , body}
149
- * @property {Function} next - go to next function
150
- * @returns {this}
151
- */
152
- use(middleware) {
153
- this._globalMiddlewares.push(middleware);
154
- return this;
155
- }
156
- /**
157
- * The 'useAdater' method is used to switch between different server implementations,
158
- * such as the native Node.js HTTP server or uWebSockets.js (uWS).
159
- *
160
- * @param {T.Adapter} adapter - The adapter instance (e.g., HTTP or uWS).
161
- * @returns {this} Returns the current instance for chaining
162
- */
163
- useAdater(adapter) {
164
- this._adapter = adapter;
165
- this._parser.useAdater(adapter);
166
- return this;
167
- }
168
- /**
169
- * The 'useCluster' method is used cluster run the server
170
- *
171
- * @param {boolean | number} cluster
172
- * @returns {this}
173
- */
174
- useCluster(cluster) {
175
- if (cluster === false)
176
- return this;
177
- this._cluster = cluster ?? true;
178
- return this;
179
- }
180
- /**
181
- * The 'useLogger' method is used to add the middleware view logger response.
182
- *
183
- * @callback {Function} middleware
184
- * @property {Object} ctx - context { req , res , query , params , cookies , files , body}
185
- * @property {Function} next - go to next function
186
- * @returns {this}
187
- */
188
- useLogger({ methods, exceptPath } = {}) {
189
- this._globalMiddlewares.push(({ req, res }, next) => {
190
- const diffTime = (hrtime) => {
191
- const MS = 1000;
192
- if (hrtime == null)
193
- return 0;
194
- const [start, end] = process.hrtime(hrtime);
195
- const time = ((start * MS) + (end / 1e6));
196
- return `${time > MS ? `${(time / MS).toFixed(2)} s` : `${time.toFixed(2)} ms`}`;
197
- };
198
- const statusCode = (res) => {
199
- const statusCode = res.statusCode == null ? 500 : Number(res.statusCode);
200
- return statusCode < 400
201
- ? `\x1b[32m${statusCode}\x1b[0m`
202
- : `\x1b[31m${statusCode}\x1b[0m`;
203
- };
204
- if (exceptPath instanceof RegExp && exceptPath.test(req.url))
205
- return next();
206
- if (Array.isArray(exceptPath) && exceptPath.some(v => req.url === v))
207
- return next();
208
- if (methods != null &&
209
- methods.length &&
210
- !methods.some(v => v.toLowerCase() === req.method.toLowerCase())) {
211
- return next();
212
- }
213
- const startTime = process.hrtime();
214
- (0, on_finished_1.default)(res, () => {
215
- console.log([
216
- `[\x1b[1m\x1b[34mINFO\x1b[0m]`,
217
- `\x1b[34m${new Date().toJSON()}\x1b[0m`,
218
- `\x1b[33m${req.method}\x1b[0m`,
219
- `${decodeURIComponent(req.url)}`,
220
- `${statusCode(res)}`,
221
- `${diffTime(startTime)}`,
222
- ].join(" "));
223
- });
224
- return next();
225
- });
226
- return this;
227
- }
228
- /**
229
- * The 'useBodyParser' method is a middleware used to parse the request body of incoming HTTP requests.
230
- * @param {object?}
231
- * @property {array?} except the body parser with some methods
232
- * @returns {this}
233
- */
234
- useBodyParser({ except } = {}) {
235
- this._globalMiddlewares.push((ctx, next) => {
236
- const { req, res } = ctx;
237
- if (Array.isArray(except) &&
238
- except.some(v => v.toLowerCase() === (req.method).toLowerCase())) {
239
- return next();
240
- }
241
- const contentType = req?.headers['content-type'] ?? null;
242
- if (contentType == null)
243
- return next();
244
- const isFileUpload = contentType && contentType.startsWith('multipart/form-data');
245
- if (isFileUpload)
246
- return next();
247
- if (req?.body != null)
248
- return next();
249
- Promise.resolve(this._parser.body(req, res))
250
- .then(body => {
251
- req.body = body;
252
- return next();
253
- })
254
- .catch(err => {
255
- return this._nextFunction(ctx)(err);
256
- });
257
- });
258
- return this;
259
- }
260
- /**
261
- * The 'useFileUpload' method is a middleware used to handler file uploads. It adds a file upload of incoming HTTP requests.
262
- *
263
- * @param {?Object}
264
- * @property {?number} limits // bytes. default Infinity
265
- * @property {?string} tempFileDir
266
- * @property {?Object} removeTempFile
267
- * @property {boolean} removeTempFile.remove
268
- * @property {number} removeTempFile.ms
269
- * @returns
270
- */
271
- useFileUpload({ limit, tempFileDir, removeTempFile } = {}) {
272
- if (limit != null) {
273
- this._fileUploadOptions.limit = limit;
274
- }
275
- if (tempFileDir != null) {
276
- this._fileUploadOptions.tempFileDir = tempFileDir;
277
- }
278
- if (removeTempFile != null) {
279
- this._fileUploadOptions.removeTempFile = removeTempFile;
280
- }
281
- this._globalMiddlewares.push((ctx, next) => {
282
- const { req, res } = ctx;
283
- if (req.method === 'GET') {
284
- return next();
285
- }
286
- const contentType = req?.headers['content-type'];
287
- const isFileUpload = contentType && contentType.startsWith('multipart/form-data');
288
- if (!isFileUpload)
289
- return next();
290
- if (req?.files != null)
291
- return next();
292
- Promise
293
- .resolve(this._parser.files({ req, res, options: this._fileUploadOptions }))
294
- .then(r => {
295
- req.files = r.files;
296
- req.body = r.body;
297
- return next();
298
- })
299
- .catch(err => {
300
- return this._nextFunction(ctx)(err);
301
- });
302
- });
303
- return this;
304
- }
305
- /**
306
- * The 'useCookiesParser' method is a middleware used to parses cookies attached to the client request object.
307
- *
308
- * @returns {this}
309
- */
310
- useCookiesParser() {
311
- this._globalMiddlewares.push(({ req }, next) => {
312
- if (req?.cookies != null)
313
- return next();
314
- req.cookies = this._parser.cookies(req);
315
- return next();
316
- });
317
- return this;
318
- }
319
- /**
320
- * The 'useRouter' method is used to add the router in the request context.
321
- *
322
- * @parms {Function} router
323
- * @property {Function} router - get() , post() , put() , patch() , delete()
324
- * @returns {this}
325
- */
326
- useRouter(router) {
327
- const routes = router.routes;
328
- for (const { path, method, handlers } of routes) {
329
- this[method](this._normalizePath(this._globalPrefix, path), ...handlers);
330
- }
331
- return this;
332
- }
333
- /**
334
- * The 'useSwagger' method is a middleware used to create swagger api.
335
- *
336
- * @param {?Object} doc
337
- * @returns
338
- */
339
- useSwagger(doc = {}) {
340
- const { path, servers, tags, info, options } = doc;
341
- this._swagger = {
342
- use: true,
343
- options: options,
344
- path: path ?? this._swagger.path,
345
- servers: servers ?? this._swagger.servers,
346
- tags: tags ?? this._swagger.tags,
347
- info: info ?? this._swagger.info
348
- };
349
- return this;
350
- }
351
- /**
352
- * The 'listen' method is used to bind and start a server to a particular port and optionally a hostname.
353
- *
354
- * @param {number} port
355
- * @param {function} callback
356
- * @returns
357
- */
358
- async listen(port, hostname, callback) {
359
- if (arguments.length === 2 && typeof hostname === 'function') {
360
- callback = hostname;
361
- }
362
- const server = await this._createServer();
363
- if (this._cluster != null &&
364
- this._cluster || typeof this._cluster === 'number') {
365
- this._clusterMode({
366
- server,
367
- port,
368
- hostname,
369
- callback
370
- });
371
- return server;
372
- }
373
- if ('App' in this._adapter) {
374
- const handler = () => {
375
- this._onListeners.forEach(listener => listener());
376
- if (this._swagger.use) {
377
- this._swaggerHandler();
378
- }
379
- callback?.({ server, port });
380
- };
381
- if (hostname) {
382
- server.listen(port, String(hostname), handler);
383
- }
384
- else {
385
- server.listen(port, handler);
386
- }
387
- return server;
388
- }
389
- const args = hostname
390
- ? [port, hostname, () => callback?.({ server, port: port })]
391
- : [port, () => callback?.({ server, port: port })];
392
- server.listen(...args);
393
- server.on('listening', () => {
394
- this._onListeners.forEach(listener => listener());
395
- if (this._swagger.use) {
396
- this._swaggerHandler();
397
- }
398
- });
399
- return server;
400
- }
401
- /**
402
- * The 'cors' is used to enable the cors origins on the server.
403
- *
404
- * @params {Object}
405
- * @property {(string | RegExp)[]} origins
406
- * @property {boolean} credentials
407
- * @returns
408
- */
409
- cors({ origins, credentials } = {}) {
410
- this._cors = ((req, res) => {
411
- const origin = req.headers?.origin ?? null;
412
- if (origin == null)
413
- return;
414
- res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS');
415
- res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
416
- if (Array.isArray(origins) && origins.length) {
417
- for (const o of origins) {
418
- if (typeof o === 'string' && (o === origin || o === '*')) {
419
- res.setHeader('Access-Control-Allow-Origin', origin);
420
- continue;
421
- }
422
- if (o instanceof RegExp && o.test(origin)) {
423
- res.setHeader('Access-Control-Allow-Origin', origin);
424
- }
425
- }
426
- }
427
- if (credentials) {
428
- res.setHeader('Access-Control-Allow-Credentials', 'true');
429
- }
430
- if (req.method === 'OPTIONS') {
431
- res.writeHead(204, { 'Content-Length': '0' });
432
- res.end();
433
- return;
434
- }
435
- return;
436
- });
437
- return this;
438
- }
439
- /**
440
- * The 'response' method is used to format the response
441
- *
442
- * @param {function} format
443
- * @returns
444
- */
445
- response(format) {
446
- this._formatResponse = format;
447
- return this;
448
- }
449
- /**
450
- * The 'catch' method is middleware that is specifically designed to handle errors.
451
- *
452
- * that occur during the processing of requests
453
- *
454
- * @param {function} error
455
- * @returns
456
- */
457
- catch(error) {
458
- this._errorHandler = error;
459
- return this;
460
- }
461
- /**
462
- * The 'notfound' method is middleware that is specifically designed to handle errors notfound that occur during the processing of requests
463
- *
464
- * @param {function} fn
465
- * @returns
466
- */
467
- notfound(fn) {
468
- const handler = ({ req, res }) => {
469
- const ctx = this._createContext({ req, res, ps: {} });
470
- return fn(ctx);
471
- };
472
- this.all('*', handler);
473
- return this;
474
- }
475
- /**
476
- * The 'get' method is used to add the request handler to the router for the 'GET' method.
477
- *
478
- * @param {string} path
479
- * @callback {...Function[]} handlers of the middlewares
480
- * @property {Object} ctx - context { req , res , query , params , cookies , files , body}
481
- * @property {Function} next - go to next function
482
- * @returns {this}
483
- */
484
- get(path, ...handlers) {
485
- this._onListeners.push(() => {
486
- return this._router.get(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
487
- });
488
- return this;
489
- }
490
- getx(path, ...handlers) {
491
- this._onListeners.push(() => {
492
- return this._router.get(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
493
- });
494
- return this;
495
- }
496
- /**
497
- * The 'post' method is used to add the request handler to the router for the 'POST' method.
498
- *
499
- * @param {string} path
500
- * @callback {...Function[]} handlers of the middlewares
501
- * @property {Object} ctx - context { req , res , query , params , cookies , files , body}
502
- * @property {Function} next - go to next function
503
- * @returns {this}
504
- */
505
- post(path, ...handlers) {
506
- this._onListeners.push(() => {
507
- return this._router.post(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
508
- });
509
- return this;
510
- }
511
- /**
512
- * The 'put' method is used to add the request handler to the router for the 'PUT' method.
513
- *
514
- * @param {string} path
515
- * @callback {...Function[]} handlers of the middlewares
516
- * @property {Object} ctx - context { req , res , query , params , cookies , files , body}
517
- * @property {Function} next - go to next function
518
- * @returns {this}
519
- */
520
- put(path, ...handlers) {
521
- this._onListeners.push(() => {
522
- return this._router.put(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
523
- });
524
- return this;
525
- }
526
- /**
527
- * The 'patch' method is used to add the request handler to the router for the 'PATCH' method.
528
- *
529
- * @param {string} path
530
- * @callback {...Function[]} handlers of the middlewares
531
- * @property {Object} ctx - context { req , res , query , params , cookies , files , body}
532
- * @property {Function} next - go to next function
533
- * @returns {this}
534
- */
535
- patch(path, ...handlers) {
536
- this._onListeners.push(() => {
537
- return this._router.patch(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
538
- });
539
- return this;
540
- }
541
- /**
542
- * The 'delete' method is used to add the request handler to the router for the 'DELETE' method.
543
- *
544
- * @param {string} path
545
- * @callback {...Function[]} handlers of the middlewares
546
- * @property {Object} ctx - context { req , res , query , params , cookies , files , body}
547
- * @property {Function} next - go to next function
548
- * @returns {this}
549
- */
550
- delete(path, ...handlers) {
551
- this._onListeners.push(() => {
552
- return this._router.delete(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
553
- });
554
- return this;
555
- }
556
- /**
557
- * The 'head' method is used to add the request handler to the router for 'HEAD' methods.
558
- *
559
- * @param {string} path
560
- * @callback {...Function[]} handlers of the middlewares
561
- * @property {object} ctx - context { req , res , query , params , cookies , files , body}
562
- * @property {function} next - go to next function
563
- * @returns {this}
564
- */
565
- head(path, ...handlers) {
566
- this._onListeners.push(() => {
567
- return this._router.head(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
568
- });
569
- return this;
570
- }
571
- /**
572
- * The 'head' method is used to add the request handler to the router for 'HEAD' methods.
573
- *
574
- * @param {string} path
575
- * @callback {...Function[]} handlers of the middlewares
576
- * @property {object} ctx - context { req , res , query , params , cookies , files , body}
577
- * @property {function} next - go to next function
578
- * @returns {this}
579
- */
580
- options(path, ...handlers) {
581
- this._onListeners.push(() => {
582
- return this._router.options(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
583
- });
584
- return this;
585
- }
586
- /**
587
- * The 'all' method is used to add the request handler to the router for 'GET' 'POST' 'PUT' 'PATCH' 'DELETE' 'HEAD' 'OPTIONS' methods.
588
- *
589
- * @param {string} path
590
- * @callback {...Function[]} handlers of the middlewares
591
- * @property {object} ctx - context { req , res , query , params , cookies , files , body}
592
- * @property {function} next - go to next function
593
- * @returns {this}
594
- */
595
- all(path, ...handlers) {
596
- this._onListeners.push(() => {
597
- return this._router.all(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
598
- });
599
- return this;
600
- }
601
- async _import(dir, pattern) {
602
- const directories = fs_1.default.readdirSync(dir, { withFileTypes: true });
603
- const files = (await Promise.all(directories.map((directory) => {
604
- const newDir = path_1.default.resolve(String(dir), directory.name);
605
- if (pattern == null) {
606
- return directory.isDirectory() ? this._import(newDir) : newDir;
607
- }
608
- return directory.isDirectory()
609
- ? this._import(newDir)
610
- : pattern.test(directory.name)
611
- ? newDir
612
- : null;
613
- }))).filter(d => d != null);
614
- return [].concat(...files);
615
- }
616
- async _registerControllers() {
617
- if (this._controllers == null)
618
- return;
619
- if (!Array.isArray(this._controllers)) {
620
- const controllers = await this._import(this._controllers.folder, this._controllers.name);
621
- for (const file of controllers) {
622
- const imported = await Promise.resolve(`${file}`).then(s => __importStar(require(s)));
623
- let maybeController = imported?.default;
624
- if (maybeController == null) {
625
- const entry = Object
626
- .entries(imported)
627
- .find(([name]) => {
628
- return /controller$/i.test(name);
629
- });
630
- maybeController = entry?.[1];
631
- }
632
- const controller = maybeController;
633
- if (typeof controller !== "function") {
634
- console.log(`\x1b[31m[ControllerLoader ERROR]\x1b[0m \x1b[36m${file}\x1b[0m must export a controller class`);
635
- continue;
636
- }
637
- const controllerInstance = new controller();
638
- const prefixPath = Reflect.getMetadata("controllers", controller) ?? '';
639
- const routers = Reflect.getMetadata("routers", controller) ?? [];
640
- const swaggers = Reflect.getMetadata("swaggers", controller) ?? [];
641
- if (prefixPath == null)
642
- continue;
643
- for (const { method, path, handler } of Array.from(routers)) {
644
- const find = Array.from(swaggers).find(s => s.handler === handler);
645
- if (find != null) {
646
- this._swaggerSpecs = [
647
- ...this._swaggerSpecs,
648
- {
649
- ...find,
650
- path: this._normalizePath(this._globalPrefix, prefixPath, path),
651
- method
652
- }
653
- ];
654
- }
655
- this[method](this._normalizePath(this._globalPrefix, prefixPath, path), controllerInstance[String(handler)].bind(controllerInstance));
656
- }
657
- }
658
- return;
659
- }
660
- for (const controller of this._controllers) {
661
- const controllerInstance = new controller();
662
- const prefixPath = Reflect.getMetadata("controllers", controller) ?? '';
663
- const routers = Reflect.getMetadata("routers", controller) ?? [];
664
- const swaggers = Reflect.getMetadata("swaggers", controller) ?? [];
665
- if (prefixPath == null)
666
- continue;
667
- for (const { method, path, handler } of Array.from(routers)) {
668
- const find = Array.from(swaggers).find(s => s.handler === handler);
669
- if (find != null) {
670
- this._swaggerSpecs = [
671
- ...this._swaggerSpecs,
672
- {
673
- ...find,
674
- path: this._normalizePath(this._globalPrefix, prefixPath, path),
675
- method
676
- }
677
- ];
678
- }
679
- this[method](this._normalizePath(this._globalPrefix, prefixPath, path), controllerInstance[String(handler)].bind(controllerInstance));
680
- }
681
- }
682
- }
683
- async _registerMiddlewares() {
684
- if (this._middlewares == null)
685
- return;
686
- if (!Array.isArray(this._middlewares)) {
687
- const middlewares = await this._import(this._middlewares.folder, this._middlewares.name);
688
- for (const file of middlewares) {
689
- const imported = await Promise.resolve(`${file}`).then(s => __importStar(require(s)));
690
- let maybeMiddleware = imported?.default;
691
- if (maybeMiddleware == null) {
692
- const entry = Object
693
- .entries(imported)
694
- .find(([name]) => {
695
- return /middleware$/i.test(name);
696
- });
697
- maybeMiddleware = entry?.[1];
698
- }
699
- const middleware = maybeMiddleware;
700
- if (typeof middleware !== "function") {
701
- console.log(`\x1b[31m[MiddlewareLoader ERROR]\x1b[0m \x1b[36m${file}\x1b[0m must export a middleware`);
702
- continue;
703
- }
704
- this.use(middleware);
705
- }
706
- return;
707
- }
708
- const middlewares = this._middlewares;
709
- for (const middleware of middlewares) {
710
- this.use(middleware);
711
- }
712
- return;
713
- }
714
- _customizeResponse(req, res) {
715
- const response = res;
716
- response.json = (results) => {
717
- if (res.writableEnded)
718
- return;
719
- if (typeof results === 'string') {
720
- if (!res.headersSent) {
721
- res.writeHead(200, { 'Content-Type': 'text/plain' });
722
- }
723
- return res.end(results);
724
- }
725
- if (!res.headersSent) {
726
- res.writeHead(200, { 'Content-Type': 'application/json' });
727
- }
728
- if (results == null) {
729
- if (this._formatResponse != null) {
730
- return res.end(JSON.stringify(this._formatResponse(null, res.statusCode)));
731
- }
732
- return res.end();
733
- }
734
- if (this._formatResponse != null) {
735
- return res.end(JSON.stringify(this._formatResponse({
736
- ...results
737
- }, res.statusCode)));
738
- }
739
- return res.end(JSON.stringify({
740
- ...results,
741
- }));
742
- };
743
- response.send = (results) => {
744
- if (res.writableEnded)
745
- return;
746
- res.writeHead(res.statusCode, { 'Content-Type': 'text/plain' });
747
- return res.end(results);
748
- };
749
- response.html = (results) => {
750
- if (res.writableEnded)
751
- return;
752
- res.writeHead(res.statusCode, { 'Content-Type': 'text/html' });
753
- return res.end(results);
754
- };
755
- response.error = (err) => {
756
- const statusCandidates = [
757
- err?.response?.data?.code,
758
- err?.code,
759
- err?.status,
760
- err?.statusCode,
761
- err?.response?.data?.statusCode
762
- ];
763
- let code = statusCandidates
764
- .map(v => Number(v))
765
- .find(v => Number.isFinite(v) && v >= 400) ?? 500;
766
- const message = err?.response?.data?.errorMessage ??
767
- err?.response?.data?.message ??
768
- err?.message ??
769
- `The request '${req.url}' resulted in a server error.`;
770
- response.status(code);
771
- const payload = { message };
772
- if (this._formatResponse) {
773
- return res.end(JSON.stringify(this._formatResponse(payload, code)));
774
- }
775
- return res.end(JSON.stringify(payload));
776
- };
777
- response.ok = (results) => {
778
- return response.json(results == null ? {} : results);
779
- };
780
- response.created = (results) => {
781
- response.status(201);
782
- return response.json(results == null ? {} : results);
783
- };
784
- response.accepted = (results) => {
785
- response.status(202);
786
- return response.json(results == null ? {} : results);
787
- };
788
- response.noContent = () => {
789
- response.status(204);
790
- return res.end();
791
- };
792
- response.badRequest = (message) => {
793
- if (res.writableEnded)
794
- return;
795
- response.status(400);
796
- message = message ?? `The request '${req.url}' resulted in a bad request. Please review the data and try again.`;
797
- if (this._formatResponse != null) {
798
- return res.end(JSON.stringify(this._formatResponse({ message }, 400)));
799
- }
800
- return res.end(JSON.stringify({
801
- message: message
802
- }));
803
- };
804
- response.unauthorized = (message) => {
805
- response.status(401);
806
- message = message ?? `The request '${req.url}' is unauthorized. Please verify.`;
807
- if (this._formatResponse != null) {
808
- return res.end(JSON.stringify(this._formatResponse({ message }, 401)));
809
- }
810
- return res.end(JSON.stringify({
811
- message
812
- }));
813
- };
814
- response.paymentRequired = (message) => {
815
- response.status(402);
816
- message = message ?? `The request '${req.url}' requires payment. Please proceed with payment.`;
817
- if (this._formatResponse != null) {
818
- return res.end(JSON.stringify(this._formatResponse({ message }, 402)));
819
- }
820
- return res.end(JSON.stringify({
821
- message
822
- }));
823
- };
824
- response.forbidden = (message) => {
825
- response.status(403);
826
- message = message ?? `The request '${req.url}' is forbidden. Please check the permissions or access rights.`;
827
- if (this._formatResponse != null) {
828
- return res.end(JSON.stringify(this._formatResponse({ message }, 403)));
829
- }
830
- return res.end(JSON.stringify({
831
- message
832
- }));
833
- };
834
- response.notFound = (message) => {
835
- response.status(404);
836
- message = message ?? `The request '${req.url}' was not found. Please re-check the your url again.`;
837
- if (this._formatResponse != null) {
838
- return res.end(JSON.stringify(this._formatResponse({ message }, 404)));
839
- }
840
- return res.end(JSON.stringify({
841
- message
842
- }));
843
- };
844
- response.unprocessable = (message) => {
845
- response.status(422);
846
- message = message ?? `The request to '${req.url}' failed validation.`;
847
- if (this._formatResponse != null) {
848
- return res.end(JSON.stringify(this._formatResponse({ message }, 422)));
849
- }
850
- return res.end(JSON.stringify({
851
- message
852
- }));
853
- };
854
- response.tooManyRequests = (message) => {
855
- response.status(429);
856
- message = message ?? `The request '${req.url}' is too many request. Please wait and try agian.`;
857
- if (this._formatResponse != null) {
858
- return res.end(JSON.stringify(this._formatResponse({ message }, 429)));
859
- }
860
- return res.end(JSON.stringify({
861
- message
862
- }));
863
- };
864
- response.serverError = (message) => {
865
- response.status(500);
866
- message = message ?? `The request '${req.url}' resulted in a server error. Please investigate.`;
867
- if (this._formatResponse != null) {
868
- return res.end(JSON.stringify(this._formatResponse({ message }, 500)));
869
- }
870
- return res.end(JSON.stringify({
871
- message
872
- }));
873
- };
874
- response.status = (code) => {
875
- res.writeHead(code, { 'Content-Type': 'application/json' });
876
- return res;
877
- };
878
- response.setCookies = (cookies) => {
879
- const cookieLists = [];
880
- for (const [key, v] of Object.entries(cookies)) {
881
- let str = `${key}=${typeof v === 'string' ? v : v.value}`;
882
- if (typeof v !== 'string') {
883
- if (v.sameSite)
884
- str += `; SameSite=${v.sameSite}`;
885
- str += `; Path=${v.path ?? '/'}`;
886
- if (v.domain)
887
- str += `; Domain=${v.domain}`;
888
- if (v.httpOnly)
889
- str += `; HttpOnly`;
890
- if (v.secure)
891
- str += `; Secure`;
892
- if (v.expires) {
893
- const maxAge = Math.floor((v.expires.getTime() - Date.now()) / 1000);
894
- str += `; Max-Age=${maxAge}`;
895
- }
896
- }
897
- cookieLists.push(str);
898
- }
899
- if ('App' in this._adapter) {
900
- for (const cookie of cookieLists) {
901
- res.setHeader('Set-Cookie', cookie);
902
- }
903
- return;
904
- }
905
- res.setHeader('Set-Cookie', cookieLists);
906
- };
907
- return response;
908
- }
909
- _wrapHandlers(...handlers) {
910
- if (this._express) {
911
- return (req, res, ps) => {
912
- if (res.writableEnded)
913
- return;
914
- const ctx = this._createContext({ req, res, ps });
915
- const dispatch = (index = 0) => {
916
- try {
917
- const handler = handlers[index];
918
- if (!handler)
919
- return;
920
- const result = index === handlers.length - 1
921
- ? this._wrapResponse(handler)(req, res, this._nextFunction(req, res))
922
- : handler(req, res, () => dispatch(index + 1));
923
- return Promise.resolve(result);
924
- }
925
- catch (err) {
926
- return this._nextFunction(ctx)(err);
927
- }
928
- };
929
- return dispatch();
930
- };
931
- }
932
- return (req, res, ps) => {
933
- if (res.writableEnded)
934
- return;
935
- const ctx = this._createContext({ req, res, ps });
936
- const dispatch = (index = 0) => {
937
- try {
938
- const handler = handlers[index];
939
- if (!handler)
940
- return;
941
- const result = index === handlers.length - 1
942
- ? this._wrapResponse(handler)(ctx, this._nextFunction(ctx))
943
- : handler(ctx, () => dispatch(index + 1));
944
- return Promise.resolve(result);
945
- }
946
- catch (err) {
947
- return this._nextFunction(ctx)(err);
948
- }
949
- };
950
- return dispatch();
951
- };
952
- }
953
- _wrapResponse(handler) {
954
- return (ctx, next) => {
955
- Promise.resolve(handler(ctx, next))
956
- .then(result => {
957
- if (ctx.res.writableEnded)
958
- return;
959
- if (result instanceof http_1.ServerResponse) {
960
- return;
961
- }
962
- if (result == null) {
963
- if (!ctx.res.headersSent) {
964
- ctx.res.writeHead(204, { 'Content-Type': 'text/plain' });
965
- }
966
- ctx.res.end();
967
- return;
968
- }
969
- if (typeof result === 'string') {
970
- ctx.res.end(result ?? '');
971
- return;
972
- }
973
- if (this._formatResponse != null) {
974
- const formattedResult = this._formatResponse(result, ctx.res.statusCode);
975
- if (typeof formattedResult === 'string') {
976
- if (!ctx.res.headersSent) {
977
- ctx.res.writeHead(200, { 'Content-Type': 'text/plain' });
978
- }
979
- ctx.res.end(formattedResult);
980
- return;
981
- }
982
- if (!ctx.res.headersSent) {
983
- ctx.res.writeHead(200, { 'Content-Type': 'application/json' });
984
- }
985
- ctx.res.end(JSON.stringify(formattedResult));
986
- return;
987
- }
988
- if (!ctx.res.headersSent) {
989
- ctx.res.writeHead(200, { 'Content-Type': 'application/json' });
990
- }
991
- ctx.res.end(JSON.stringify(result));
992
- return;
993
- })
994
- .catch(err => {
995
- return this._nextFunction(ctx)(err);
996
- });
997
- };
998
- }
999
- _nextFunction(ctx) {
1000
- const NEXT_MESSAGE = "The 'next' function does not have any subsequent function.";
1001
- return (err) => {
1002
- if (err != null) {
1003
- if (this._errorHandler != null) {
1004
- const callback = this._errorHandler(err, ctx);
1005
- if (callback == null || !(callback instanceof http_1.ServerResponse)) {
1006
- ctx.res.writeHead(500, { 'Content-Type': 'application/json' });
1007
- return ctx.res.end(JSON.stringify({
1008
- message: err?.message
1009
- }));
1010
- }
1011
- return callback;
1012
- }
1013
- ctx.res.writeHead(500, { 'Content-Type': 'application/json' });
1014
- if (this._formatResponse != null) {
1015
- return ctx.res.end(JSON.stringify(this._formatResponse({
1016
- message: err?.message,
1017
- }, ctx.res.statusCode)));
1018
- }
1019
- ctx.res.end(JSON.stringify({
1020
- message: err?.message
1021
- }));
1022
- return;
1023
- }
1024
- if (this._errorHandler != null) {
1025
- return this._errorHandler(new Error(NEXT_MESSAGE), ctx);
1026
- }
1027
- ctx.res.writeHead(500, { 'Content-Type': 'application/json' });
1028
- if (this._formatResponse != null) {
1029
- ctx.res.end(JSON.stringify(this._formatResponse({
1030
- message: NEXT_MESSAGE
1031
- }, ctx.res.statusCode)));
1032
- return;
1033
- }
1034
- ctx.res.end(JSON.stringify({
1035
- message: NEXT_MESSAGE
1036
- }));
1037
- return;
1038
- };
1039
- }
1040
- _clusterMode({ server, port, hostname, callback }) {
1041
- if (cluster_1.default.isPrimary) {
1042
- const numCPUs = os_1.default.cpus().length;
1043
- const maxWorkers = typeof this._cluster === 'boolean' || this._cluster == null
1044
- ? numCPUs
1045
- : this._cluster;
1046
- for (let i = 0; i < maxWorkers; i++) {
1047
- cluster_1.default.fork();
1048
- }
1049
- cluster_1.default.on('exit', () => {
1050
- cluster_1.default.fork();
1051
- });
1052
- }
1053
- if (cluster_1.default.isWorker) {
1054
- if ('App' in this._adapter) {
1055
- const handler = () => {
1056
- this._onListeners.forEach(listener => listener());
1057
- if (this._swagger.use) {
1058
- this._swaggerHandler();
1059
- }
1060
- callback?.({ server, port });
1061
- };
1062
- if (hostname) {
1063
- server.listen(port, hostname, handler);
1064
- return server;
1065
- }
1066
- server.listen(port, handler);
1067
- return server;
1068
- }
1069
- const args = hostname
1070
- ? [port, hostname, () => callback?.({ server, port: port })]
1071
- : [port, () => callback?.({ server, port: port })];
1072
- server.listen(...args);
1073
- server.on('listening', () => {
1074
- this._onListeners.forEach(listener => listener());
1075
- if (this._swagger.use) {
1076
- this._swaggerHandler();
1077
- }
1078
- });
1079
- server.on('error', (_) => {
1080
- port = Math.floor(Math.random() * 8999) + 1000;
1081
- server.listen(port);
1082
- });
1083
- }
1084
- return;
1085
- }
1086
- async _createServer() {
1087
- await this._registerMiddlewares();
1088
- await this._registerControllers();
1089
- const lookup = this._router.lookup.bind(this._router);
1090
- const cors = this._cors;
1091
- const adapter = this._adapter;
1092
- if ('App' in adapter) {
1093
- const server = adapter.App();
1094
- server.any('/*', (uwsRes, uwsReq) => {
1095
- const { req, res } = this._uWSRequestResponse(uwsReq, uwsRes);
1096
- if (cors)
1097
- cors(req, res);
1098
- return lookup(req, res);
1099
- });
1100
- if (this._ws?.handler) {
1101
- server.ws('/*', {
1102
- open: (ws) => {
1103
- this._ws.handler?.connection?.(ws);
1104
- },
1105
- message: (ws, message) => {
1106
- this._ws.handler?.message?.(ws, Buffer.from(message));
1107
- },
1108
- close: (ws, code, message) => {
1109
- this._ws.handler?.close?.(ws, code, Buffer.from(message));
1110
- }
1111
- });
1112
- }
1113
- return server;
1114
- }
1115
- const server = http_1.default.createServer((req, res) => {
1116
- if (cors)
1117
- cors(req, res);
1118
- this._router.lookup(req, res);
1119
- });
1120
- if (this._ws?.handler) {
1121
- this._ws.server = new ws_1.default.Server({ server, ...this._ws.options });
1122
- this._ws.server.on('connection', (ws) => {
1123
- if (this._ws.handler?.connection) {
1124
- this._ws.handler.connection(ws);
1125
- }
1126
- ws.on('message', (data) => {
1127
- this._ws.handler?.message?.(ws, data);
1128
- });
1129
- ws.on('close', (code, reason) => {
1130
- if (this._ws.handler?.close) {
1131
- this._ws.handler?.close(ws, code, reason);
1132
- }
1133
- });
1134
- ws.on('error', (err) => {
1135
- if (this._ws.handler?.error) {
1136
- this._ws.handler.error(ws, err);
1137
- }
1138
- });
1139
- });
1140
- }
1141
- return server;
1142
- }
1143
- _createContext({ req, res, ps }) {
1144
- const request = req;
1145
- const response = this._customizeResponse(req, res);
1146
- const headers = req.headers;
1147
- const params = ps;
1148
- const body = request.body;
1149
- const files = request.files;
1150
- const cookies = request.cookies;
1151
- const query = this._parser.queryString(req.url) || {};
1152
- const xff = headers['x-forwarded-for'];
1153
- const xrip = headers['x-real-ip'];
1154
- const cfip = headers['cf-connecting-ip'];
1155
- let ips = [];
1156
- if (cfip) {
1157
- ips = Array.isArray(cfip) ? cfip : [cfip];
1158
- }
1159
- else if (xff) {
1160
- ips = Array.isArray(xff) ? xff : [xff];
1161
- }
1162
- else if (xrip) {
1163
- ips = Array.isArray(xrip) ? xrip : [xrip];
1164
- }
1165
- else {
1166
- const addr = req.socket?.remoteAddress;
1167
- ips = addr ? [addr] : [];
1168
- }
1169
- const ip = (ips.length ? ips[0] : null);
1170
- request.params = params;
1171
- request.query = query;
1172
- request.ip = ip;
1173
- request.ips = ips;
1174
- return {
1175
- req: request,
1176
- res: response,
1177
- headers: headers || {},
1178
- params: params || {},
1179
- query,
1180
- body: body || {},
1181
- files: files || {},
1182
- cookies: cookies || {},
1183
- ip,
1184
- ips
1185
- };
1186
- }
1187
- _uWSRequestResponse(uwsReq, uwsRes) {
1188
- const req = {
1189
- method: String(uwsReq.getMethod()).toUpperCase(),
1190
- url: uwsReq.getUrl() + (uwsReq.getQuery() ? `?${uwsReq.getQuery()}` : ''),
1191
- headers: {}
1192
- };
1193
- uwsReq.forEach((key, value) => req.headers[key] = value);
1194
- const res = {
1195
- writeHeader: (key, value) => {
1196
- if (!res.aborted) {
1197
- uwsRes.writeHeader(key, value);
1198
- }
1199
- return res;
1200
- },
1201
- setHeader: (key, value) => {
1202
- if (!res.aborted) {
1203
- uwsRes.writeHeader(key, value);
1204
- }
1205
- return res;
1206
- },
1207
- writeHead(status, context) {
1208
- res.writeHeaders = {
1209
- ...res.writeHeaders,
1210
- [status]: context
1211
- };
1212
- res.headersSent = true;
1213
- res.statusCode = status;
1214
- return res;
1215
- },
1216
- _writeHead(status, context) {
1217
- const statusMessages = {
1218
- 100: 'Continue',
1219
- 101: 'Switching Protocols',
1220
- 102: 'Processing',
1221
- 200: 'OK',
1222
- 201: 'Created',
1223
- 202: 'Accepted',
1224
- 203: 'Non-Authoritative Information',
1225
- 204: 'No Content',
1226
- 205: 'Reset Content',
1227
- 206: 'Partial Content',
1228
- 207: 'Multi-Status',
1229
- 208: 'Already Reported',
1230
- 226: 'IM Used',
1231
- 300: 'Multiple Choices',
1232
- 301: 'Moved Permanently',
1233
- 302: 'Found',
1234
- 303: 'See Other',
1235
- 304: 'Not Modified',
1236
- 305: 'Use Proxy',
1237
- 306: '(Unused)',
1238
- 307: 'Temporary Redirect',
1239
- 308: 'Permanent Redirect',
1240
- 400: 'Bad Request',
1241
- 401: 'Unauthorized',
1242
- 402: 'Payment Required',
1243
- 403: 'Forbidden',
1244
- 404: 'Not Found',
1245
- 405: 'Method Not Allowed',
1246
- 406: 'Not Acceptable',
1247
- 407: 'Proxy Authentication Required',
1248
- 408: 'Request Timeout',
1249
- 409: 'Conflict',
1250
- 410: 'Gone',
1251
- 411: 'Length Required',
1252
- 412: 'Precondition Failed',
1253
- 413: 'Payload Too Large',
1254
- 414: 'URI Too Long',
1255
- 415: 'Unsupported Media Type',
1256
- 416: 'Range Not Satisfiable',
1257
- 417: 'Expectation Failed',
1258
- 418: 'I\'m a teapot',
1259
- 421: 'Misdirected Request',
1260
- 422: 'Unprocessable Entity',
1261
- 423: 'Locked',
1262
- 424: 'Failed Dependency',
1263
- 425: 'Too Early',
1264
- 426: 'Upgrade Required',
1265
- 428: 'Precondition Required',
1266
- 429: 'Too Many Requests',
1267
- 431: 'Request Header Fields Too Large',
1268
- 451: 'Unavailable For Legal Reasons',
1269
- 500: 'Internal Server Error',
1270
- 501: 'Not Implemented',
1271
- 502: 'Bad Gateway',
1272
- 503: 'Service Unavailable',
1273
- 504: 'Gateway Timeout',
1274
- 505: 'HTTP Version Not Supported',
1275
- 506: 'Variant Also Negotiates',
1276
- 507: 'Insufficient Storage',
1277
- 508: 'Loop Detected',
1278
- 510: 'Not Extended',
1279
- 511: 'Network Authentication Required'
1280
- };
1281
- const statusMessage = statusMessages[status] || statusMessages[500];
1282
- res.uwsRes.writeStatus(`${status} ${statusMessage}`);
1283
- res.uwsRes.writeHeader(Object.keys(context)[0], Object.values(context)[0]);
1284
- return res;
1285
- },
1286
- writeStatus: (status) => {
1287
- if (!res.aborted) {
1288
- res.uwsRes.writeStatus(status);
1289
- }
1290
- return res;
1291
- },
1292
- end: (str) => {
1293
- if (res.aborted) {
1294
- return;
1295
- }
1296
- uwsRes.cork(() => {
1297
- if (!res.aborted) {
1298
- res.aborted = true;
1299
- for (const h in res.writeHeaders) {
1300
- //@ts-ignore
1301
- res._writeHead(h, res.writeHeaders[h]);
1302
- }
1303
- uwsRes.end(str);
1304
- return;
1305
- }
1306
- });
1307
- },
1308
- aborted: false,
1309
- writeHeaders: {},
1310
- headersSent: false,
1311
- statusCode: 200,
1312
- uwsRes,
1313
- };
1314
- uwsRes.onAborted(() => {
1315
- res.aborted = true;
1316
- });
1317
- return { req, res };
1318
- }
1319
- _normalizePath(...paths) {
1320
- const path = paths
1321
- .join('/')
1322
- .replace(/\/+/g, '/')
1323
- .replace(/\/+$/, '');
1324
- const normalizedPath = path.startsWith('/') ? path : `/${path}`;
1325
- return /\/api\/api/.test(normalizedPath)
1326
- ? normalizedPath.replace(/\/api\/api\//, "/api/")
1327
- : normalizedPath;
1328
- }
1329
- _swaggerHandler() {
1330
- const routes = this.routers
1331
- .routes
1332
- .filter(r => {
1333
- return [
1334
- "GET", "POST",
1335
- "PUT", "PATCH",
1336
- "DELETE",
1337
- "HEAD", "OPTIONS"
1338
- ].includes(r.method);
1339
- });
1340
- const { path, html, staticSwaggerHandler, staticUrl } = this._parser.swagger({
1341
- ...this._swagger,
1342
- specs: this._swaggerSpecs,
1343
- routes
1344
- });
1345
- this._router.get(staticUrl, staticSwaggerHandler);
1346
- this._router.get(path, (req, res) => {
1347
- res.writeHead(200, { 'Content-Type': 'text/html' });
1348
- res.end(html);
1349
- return;
1350
- });
1351
- return;
1352
- }
1353
- }
1354
- exports.Express = Express;
1355
- exports.default = Express;
1356
- //# sourceMappingURL=express.js.map