tspace-spear 1.2.1 → 1.2.3

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.
@@ -15,27 +15,36 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
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
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
28
38
  Object.defineProperty(exports, "__esModule", { value: true });
29
39
  exports.Spear = exports.Application = void 0;
40
+ const http_1 = __importStar(require("http"));
41
+ const find_my_way_1 = __importDefault(require("find-my-way"));
30
42
  const cluster_1 = __importDefault(require("cluster"));
31
43
  const os_1 = __importDefault(require("os"));
32
44
  const fs_1 = __importDefault(require("fs"));
33
45
  const path_1 = __importDefault(require("path"));
34
- const url_1 = require("url");
35
46
  const on_finished_1 = __importDefault(require("on-finished"));
36
47
  const ws_1 = __importDefault(require("ws"));
37
- const http_1 = __importStar(require("http"));
38
- const find_my_way_1 = __importDefault(require("find-my-way"));
39
48
  const parser_factory_1 = require("./parser-factory");
40
49
  /**
41
50
  *
@@ -59,6 +68,7 @@ class Spear {
59
68
  _globalPrefix;
60
69
  _router = (0, find_my_way_1.default)();
61
70
  _parser = new parser_factory_1.ParserFactory();
71
+ _adapter = http_1.default;
62
72
  _cluster;
63
73
  _cors;
64
74
  _swagger = {
@@ -76,10 +86,10 @@ class Spear {
76
86
  version: "1.0.0"
77
87
  }
78
88
  };
89
+ _swaggerSpecs = [];
79
90
  _wss;
80
91
  _ws;
81
92
  _wsOptions;
82
- _swaggerSpecs = [];
83
93
  _errorHandler = null;
84
94
  _globalMiddlewares = [];
85
95
  _formatResponse = null;
@@ -92,11 +102,13 @@ class Spear {
92
102
  ms: 1000 * 60 * 10
93
103
  }
94
104
  };
95
- constructor({ controllers, middlewares, globalPrefix, logger, cluster } = {}) {
105
+ constructor({ controllers, middlewares, globalPrefix, logger, cluster, adapter } = {}) {
96
106
  if (logger)
97
107
  this.useLogger();
98
108
  if (cluster)
99
109
  this.useCluster(cluster);
110
+ if (adapter)
111
+ this.useAdater(adapter);
100
112
  this._controllers = controllers;
101
113
  this._middlewares = middlewares;
102
114
  this._globalPrefix = globalPrefix == null ? '' : globalPrefix;
@@ -141,6 +153,18 @@ class Spear {
141
153
  this._globalMiddlewares.push(middleware);
142
154
  return this;
143
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
+ }
144
168
  /**
145
169
  * The 'useCluster' method is used cluster run the server
146
170
  *
@@ -209,7 +233,7 @@ class Spear {
209
233
  */
210
234
  useBodyParser({ except } = {}) {
211
235
  this._globalMiddlewares.push((ctx, next) => {
212
- const { req } = ctx;
236
+ const { req, res } = ctx;
213
237
  const contentType = req?.headers['content-type'] ?? '';
214
238
  const isFileUpload = contentType && contentType.startsWith('multipart/form-data');
215
239
  const isCanParserBody = contentType.includes('application/json') ||
@@ -225,7 +249,7 @@ class Spear {
225
249
  return next();
226
250
  if (req?.body != null)
227
251
  return next();
228
- Promise.resolve(this._parser.body(req))
252
+ Promise.resolve(this._parser.body(req, res))
229
253
  .then(r => {
230
254
  req.body = r;
231
255
  return next();
@@ -258,7 +282,7 @@ class Spear {
258
282
  this._fileUploadOptions.removeTempFile = removeTempFile;
259
283
  }
260
284
  this._globalMiddlewares.push((ctx, next) => {
261
- const { req } = ctx;
285
+ const { req, res } = ctx;
262
286
  if (req.method === 'GET') {
263
287
  return next();
264
288
  }
@@ -269,7 +293,7 @@ class Spear {
269
293
  if (req?.files != null)
270
294
  return next();
271
295
  Promise
272
- .resolve(this._parser.files(req, this._fileUploadOptions))
296
+ .resolve(this._parser.files({ req, res, options: this._fileUploadOptions }))
273
297
  .then(r => {
274
298
  req.files = r.files;
275
299
  req.body = r.body;
@@ -349,6 +373,22 @@ class Spear {
349
373
  });
350
374
  return server;
351
375
  }
376
+ if ('App' in this._adapter) {
377
+ const handler = () => {
378
+ this._onListeners.forEach(listener => listener());
379
+ if (this._swagger.use) {
380
+ this._swaggerHandler();
381
+ }
382
+ callback?.({ server, port });
383
+ };
384
+ if (hostname) {
385
+ server.listen(port, String(hostname), handler);
386
+ }
387
+ else {
388
+ server.listen(port, handler);
389
+ }
390
+ return server;
391
+ }
352
392
  const args = hostname
353
393
  ? [port, hostname, () => callback?.({ server, port: port })]
354
394
  : [port, () => callback?.({ server, port: port })];
@@ -359,10 +399,6 @@ class Spear {
359
399
  this._swaggerHandler();
360
400
  }
361
401
  });
362
- server.on('error', (_) => {
363
- port = Math.floor(Math.random() * 8999) + 1000;
364
- server.listen(port);
365
- });
366
402
  return server;
367
403
  }
368
404
  /**
@@ -441,7 +477,8 @@ class Spear {
441
477
  files: {},
442
478
  body: {},
443
479
  params: {},
444
- cookies: {}
480
+ cookies: {},
481
+ ip: null
445
482
  });
446
483
  };
447
484
  this._onListeners.push(() => {
@@ -584,37 +621,6 @@ class Spear {
584
621
  });
585
622
  return this;
586
623
  }
587
- _clusterMode({ server, port, hostname, callback }) {
588
- if (cluster_1.default.isPrimary) {
589
- const numCPUs = os_1.default.cpus().length;
590
- const maxWorkers = typeof this._cluster === 'boolean' || this._cluster == null
591
- ? numCPUs
592
- : this._cluster;
593
- for (let i = 0; i < maxWorkers; i++) {
594
- cluster_1.default.fork();
595
- }
596
- cluster_1.default.on('exit', () => {
597
- cluster_1.default.fork();
598
- });
599
- }
600
- if (cluster_1.default.isWorker) {
601
- const args = hostname
602
- ? [port, hostname, () => callback?.({ server, port: port })]
603
- : [port, () => callback?.({ server, port: port })];
604
- server.listen(...args);
605
- server.on('listening', () => {
606
- this._onListeners.forEach(listener => listener());
607
- if (this._swagger.use) {
608
- this._swaggerHandler();
609
- }
610
- });
611
- server.on('error', (_) => {
612
- port = Math.floor(Math.random() * 8999) + 1000;
613
- server.listen(port);
614
- });
615
- }
616
- return;
617
- }
618
624
  async _import(dir, pattern) {
619
625
  const directories = fs_1.default.readdirSync(dir, { withFileTypes: true });
620
626
  const files = (await Promise.all(directories.map((directory) => {
@@ -744,18 +750,18 @@ class Spear {
744
750
  }
745
751
  if (results == null) {
746
752
  if (this._formatResponse != null) {
747
- return res.end(JSON.stringify(this._formatResponse(null, res.statusCode), null, 2));
753
+ return res.end(JSON.stringify(this._formatResponse(null, res.statusCode)));
748
754
  }
749
755
  return res.end();
750
756
  }
751
757
  if (this._formatResponse != null) {
752
758
  return res.end(JSON.stringify(this._formatResponse({
753
759
  ...results
754
- }, res.statusCode), null, 2));
760
+ }, res.statusCode)));
755
761
  }
756
762
  return res.end(JSON.stringify({
757
763
  ...results,
758
- }, null, 2));
764
+ }));
759
765
  };
760
766
  response.send = (results) => {
761
767
  if (res.writableEnded)
@@ -812,81 +818,81 @@ class Spear {
812
818
  response.status(400);
813
819
  message = message ?? `The request '${req.url}' resulted in a bad request. Please review the data and try again.`;
814
820
  if (this._formatResponse != null) {
815
- return res.end(JSON.stringify(this._formatResponse({ message }, 400), null, 2));
821
+ return res.end(JSON.stringify(this._formatResponse({ message }, 400)));
816
822
  }
817
823
  return res.end(JSON.stringify({
818
824
  message: message
819
- }, null, 2));
825
+ }));
820
826
  };
821
827
  response.unauthorized = (message) => {
822
828
  response.status(401);
823
829
  message = message ?? `The request '${req.url}' is unauthorized. Please verify.`;
824
830
  if (this._formatResponse != null) {
825
- return res.end(JSON.stringify(this._formatResponse({ message }, 401), null, 2));
831
+ return res.end(JSON.stringify(this._formatResponse({ message }, 401)));
826
832
  }
827
833
  return res.end(JSON.stringify({
828
834
  message
829
- }, null, 2));
835
+ }));
830
836
  };
831
837
  response.paymentRequired = (message) => {
832
838
  response.status(402);
833
839
  message = message ?? `The request '${req.url}' requires payment. Please proceed with payment.`;
834
840
  if (this._formatResponse != null) {
835
- return res.end(JSON.stringify(this._formatResponse({ message }, 402), null, 2));
841
+ return res.end(JSON.stringify(this._formatResponse({ message }, 402)));
836
842
  }
837
843
  return res.end(JSON.stringify({
838
844
  message
839
- }, null, 2));
845
+ }));
840
846
  };
841
847
  response.forbidden = (message) => {
842
848
  response.status(403);
843
849
  message = message ?? `The request '${req.url}' is forbidden. Please check the permissions or access rights.`;
844
850
  if (this._formatResponse != null) {
845
- return res.end(JSON.stringify(this._formatResponse({ message }, 403), null, 2));
851
+ return res.end(JSON.stringify(this._formatResponse({ message }, 403)));
846
852
  }
847
853
  return res.end(JSON.stringify({
848
854
  message
849
- }, null, 2));
855
+ }));
850
856
  };
851
857
  response.notFound = (message) => {
852
858
  response.status(404);
853
859
  message = message ?? `The request '${req.url}' was not found. Please re-check the your url again.`;
854
860
  if (this._formatResponse != null) {
855
- return res.end(JSON.stringify(this._formatResponse({ message }, 404), null, 2));
861
+ return res.end(JSON.stringify(this._formatResponse({ message }, 404)));
856
862
  }
857
863
  return res.end(JSON.stringify({
858
864
  message
859
- }, null, 2));
865
+ }));
860
866
  };
861
867
  response.unprocessable = (message) => {
862
868
  response.status(422);
863
869
  message = message ?? `The request to '${req.url}' failed validation.`;
864
870
  if (this._formatResponse != null) {
865
- return res.end(JSON.stringify(this._formatResponse({ message }, 422), null, 2));
871
+ return res.end(JSON.stringify(this._formatResponse({ message }, 422)));
866
872
  }
867
873
  return res.end(JSON.stringify({
868
874
  message
869
- }, null, 2));
875
+ }));
870
876
  };
871
877
  response.tooManyRequests = (message) => {
872
878
  response.status(429);
873
879
  message = message ?? `The request '${req.url}' is too many request. Please wait and try agian.`;
874
880
  if (this._formatResponse != null) {
875
- return res.end(JSON.stringify(this._formatResponse({ message }, 429), null, 2));
881
+ return res.end(JSON.stringify(this._formatResponse({ message }, 429)));
876
882
  }
877
883
  return res.end(JSON.stringify({
878
884
  message
879
- }, null, 2));
885
+ }));
880
886
  };
881
887
  response.serverError = (message) => {
882
888
  response.status(500);
883
889
  message = message ?? `The request '${req.url}' resulted in a server error. Please investigate.`;
884
890
  if (this._formatResponse != null) {
885
- return res.end(JSON.stringify(this._formatResponse({ message }, 500), null, 2));
891
+ return res.end(JSON.stringify(this._formatResponse({ message }, 500)));
886
892
  }
887
893
  return res.end(JSON.stringify({
888
894
  message
889
- }, null, 2));
895
+ }));
890
896
  };
891
897
  response.status = (code) => {
892
898
  res.writeHead(code, { 'Content-Type': 'application/json' });
@@ -922,58 +928,48 @@ class Spear {
922
928
  return response;
923
929
  }
924
930
  _wrapHandlers(...handlers) {
925
- return (req, res, params) => {
926
- const nextHandler = (index = 0) => {
931
+ return (req, res, ps) => {
932
+ if (res.writableEnded)
933
+ return;
934
+ const request = req;
935
+ const response = this._customizeResponse(req, res);
936
+ const params = ps;
937
+ const headers = req.headers;
938
+ const query = this._parser.queryString(req.url);
939
+ const xff = headers['x-forwarded-for'];
940
+ const ip = (Array.isArray(xff) ? xff[0] : xff)?.split(',')[0]?.trim()
941
+ || (Array.isArray(headers['x-real-ip']) ? headers['x-real-ip'][0] : headers['x-real-ip'])
942
+ || (Array.isArray(headers['cf-connecting-ip']) ? headers['cf-connecting-ip'][0] : headers['cf-connecting-ip'])
943
+ || null;
944
+ const dispatch = (index = 0) => {
945
+ const body = request.body;
946
+ const files = request.files;
947
+ const cookies = request.cookies;
948
+ const ctx = {
949
+ req: request,
950
+ res: response,
951
+ headers: headers ?? {},
952
+ params: params ?? {},
953
+ query: query ?? {},
954
+ body: body ?? {},
955
+ files: files ?? {},
956
+ cookies: cookies ?? {},
957
+ ip: ip ?? null
958
+ };
927
959
  try {
928
- const response = this._customizeResponse(req, res);
929
- const request = req;
930
- request.params = params;
931
- const body = request.body;
932
- const files = request.files;
933
- const cookies = request.cookies;
934
- const headers = request.headers;
935
- const url = new url_1.URL(req.url, "http://localhost");
936
- const query = Object.fromEntries(url.searchParams);
937
- const RecordOrEmptyRecord = (data) => {
938
- if (data == null)
939
- return {};
940
- return Object.keys(data).length ? data : {};
941
- };
942
- const ctx = {
943
- req: request,
944
- res: response,
945
- headers: RecordOrEmptyRecord(headers),
946
- params: RecordOrEmptyRecord(params),
947
- query: RecordOrEmptyRecord(query),
948
- body: RecordOrEmptyRecord(body),
949
- files: RecordOrEmptyRecord(files),
950
- cookies: RecordOrEmptyRecord(cookies)
951
- };
960
+ const handler = handlers[index];
961
+ if (!handler)
962
+ return;
952
963
  if (index === handlers.length - 1) {
953
- return this._wrapResponse(handlers[index]
954
- .bind(handlers[index]))(ctx, this._nextFunction(ctx));
964
+ return Promise.resolve(this._wrapResponse(handler)(ctx, this._nextFunction(ctx))).catch(err => this._nextFunction(ctx)(err));
955
965
  }
956
- return handlers[index](ctx, () => {
957
- return nextHandler(index + 1);
958
- });
966
+ return Promise.resolve(handler(ctx, () => dispatch(index + 1))).catch(err => this._nextFunction(ctx)(err));
959
967
  }
960
968
  catch (err) {
961
- const ctx = {
962
- req,
963
- res: this._customizeResponse(req, res),
964
- params: Object.keys(params).length ? params : {},
965
- headers: {},
966
- query: {},
967
- body: {},
968
- files: {},
969
- cookies: {}
970
- };
971
969
  return this._nextFunction(ctx)(err);
972
970
  }
973
971
  };
974
- if (res.writableEnded)
975
- return;
976
- return nextHandler();
972
+ return dispatch();
977
973
  };
978
974
  }
979
975
  _wrapResponse(handler) {
@@ -996,9 +992,6 @@ class Spear {
996
992
  return;
997
993
  }
998
994
  if (typeof result === 'string') {
999
- if (!ctx.res.headersSent) {
1000
- ctx.res.writeHead(200, { 'Content-Type': 'text/plain' });
1001
- }
1002
995
  ctx.res.end(result ?? '');
1003
996
  return;
1004
997
  }
@@ -1038,7 +1031,7 @@ class Spear {
1038
1031
  ctx.res.writeHead(500, { 'Content-Type': 'application/json' });
1039
1032
  return ctx.res.end(JSON.stringify({
1040
1033
  message: err?.message
1041
- }, null, 2));
1034
+ }));
1042
1035
  }
1043
1036
  return callback;
1044
1037
  }
@@ -1046,39 +1039,109 @@ class Spear {
1046
1039
  if (this._formatResponse != null) {
1047
1040
  return ctx.res.end(JSON.stringify(this._formatResponse({
1048
1041
  message: err?.message,
1049
- }, ctx.res.statusCode), null, 2));
1042
+ }, ctx.res.statusCode)));
1050
1043
  }
1051
- return ctx.res.end(JSON.stringify({
1044
+ ctx.res.end(JSON.stringify({
1052
1045
  message: err?.message
1053
- }, null, 2));
1046
+ }));
1047
+ return;
1054
1048
  }
1055
1049
  if (this._errorHandler != null) {
1056
1050
  return this._errorHandler(new Error(NEXT_MESSAGE), ctx);
1057
1051
  }
1058
1052
  ctx.res.writeHead(500, { 'Content-Type': 'application/json' });
1059
1053
  if (this._formatResponse != null) {
1060
- return ctx.res.end(JSON.stringify(this._formatResponse({
1054
+ ctx.res.end(JSON.stringify(this._formatResponse({
1061
1055
  message: NEXT_MESSAGE
1062
- }, ctx.res.statusCode), null, 2));
1056
+ }, ctx.res.statusCode)));
1057
+ return;
1063
1058
  }
1064
- return ctx.res.end(JSON.stringify({
1059
+ ctx.res.end(JSON.stringify({
1065
1060
  message: NEXT_MESSAGE
1066
- }, null, 2));
1061
+ }));
1062
+ return;
1067
1063
  };
1068
1064
  }
1065
+ _clusterMode({ server, port, hostname, callback }) {
1066
+ if (cluster_1.default.isPrimary) {
1067
+ const numCPUs = os_1.default.cpus().length;
1068
+ const maxWorkers = typeof this._cluster === 'boolean' || this._cluster == null
1069
+ ? numCPUs
1070
+ : this._cluster;
1071
+ for (let i = 0; i < maxWorkers; i++) {
1072
+ cluster_1.default.fork();
1073
+ }
1074
+ cluster_1.default.on('exit', () => {
1075
+ cluster_1.default.fork();
1076
+ });
1077
+ }
1078
+ if (cluster_1.default.isWorker) {
1079
+ if ('App' in this._adapter) {
1080
+ const handler = () => {
1081
+ this._onListeners.forEach(listener => listener());
1082
+ if (this._swagger.use) {
1083
+ this._swaggerHandler();
1084
+ }
1085
+ callback?.({ server, port });
1086
+ };
1087
+ if (hostname) {
1088
+ server.listen(port, hostname, handler);
1089
+ return server;
1090
+ }
1091
+ server.listen(port, handler);
1092
+ return server;
1093
+ }
1094
+ const args = hostname
1095
+ ? [port, hostname, () => callback?.({ server, port: port })]
1096
+ : [port, () => callback?.({ server, port: port })];
1097
+ server.listen(...args);
1098
+ server.on('listening', () => {
1099
+ this._onListeners.forEach(listener => listener());
1100
+ if (this._swagger.use) {
1101
+ this._swaggerHandler();
1102
+ }
1103
+ });
1104
+ server.on('error', (_) => {
1105
+ port = Math.floor(Math.random() * 8999) + 1000;
1106
+ server.listen(port);
1107
+ });
1108
+ }
1109
+ return;
1110
+ }
1069
1111
  async _createServer() {
1070
1112
  await this._registerMiddlewares();
1071
1113
  await this._registerControllers();
1072
1114
  const lookup = this._router.lookup.bind(this._router);
1073
1115
  const cors = this._cors;
1074
- const server = http_1.default.createServer({ maxHeaderSize: 1024 * 1024 }, cors
1075
- ? (req, res) => {
1076
- cors(req, res);
1077
- return lookup(req, res);
1078
- }
1079
- : (req, res) => {
1116
+ const adapter = this._adapter;
1117
+ if ('App' in adapter) {
1118
+ const server = adapter.App();
1119
+ server.any('/*', (uwsRes, uwsReq) => {
1120
+ const { req, res } = this._uWSRequestResponse(uwsReq, uwsRes);
1121
+ if (cors)
1122
+ cors(req, res);
1080
1123
  return lookup(req, res);
1081
1124
  });
1125
+ if (this._ws) {
1126
+ server.ws('/*', {
1127
+ open: (ws) => {
1128
+ this._ws?.connection?.(ws);
1129
+ },
1130
+ message: (ws, message) => {
1131
+ this._ws?.message?.(ws, Buffer.from(message));
1132
+ },
1133
+ close: (ws, code, message) => {
1134
+ this._ws?.close?.(ws, code, Buffer.from(message));
1135
+ }
1136
+ });
1137
+ }
1138
+ return server;
1139
+ }
1140
+ const server = http_1.default.createServer((req, res) => {
1141
+ if (cors)
1142
+ cors(req, res);
1143
+ return lookup(req, res);
1144
+ });
1082
1145
  if (this._ws) {
1083
1146
  this._wss = new ws_1.default.Server({ server, ...this._wsOptions });
1084
1147
  this._wss.on('connection', (ws) => {
@@ -1086,9 +1149,7 @@ class Spear {
1086
1149
  this._ws.connection(ws);
1087
1150
  }
1088
1151
  ws.on('message', (data) => {
1089
- if (this._ws?.message) {
1090
- this._ws.message(ws, data);
1091
- }
1152
+ this._ws?.message?.(ws, data);
1092
1153
  });
1093
1154
  ws.on('close', (code, reason) => {
1094
1155
  if (this._ws?.close) {
@@ -1104,27 +1165,169 @@ class Spear {
1104
1165
  }
1105
1166
  return server;
1106
1167
  }
1168
+ _uWSRequestResponse(uwsReq, uwsRes) {
1169
+ const req = {
1170
+ method: String(uwsReq.getMethod()).toLocaleUpperCase(),
1171
+ url: uwsReq.getUrl() + (uwsReq.getQuery() ? `?${uwsReq.getQuery()}` : ''),
1172
+ headers: {}
1173
+ };
1174
+ uwsReq.forEach((key, value) => req.headers[key] = value);
1175
+ const res = {
1176
+ writeHeader: (key, value) => {
1177
+ if (!res.aborted) {
1178
+ uwsRes.writeHeader(key, value);
1179
+ }
1180
+ return res;
1181
+ },
1182
+ setHeader: (key, value) => {
1183
+ if (!res.aborted) {
1184
+ uwsRes.writeHeader(key, value);
1185
+ }
1186
+ return res;
1187
+ },
1188
+ writeHead(status, context) {
1189
+ res.writeHeaders = {
1190
+ ...res.writeHeaders,
1191
+ [status]: context
1192
+ };
1193
+ res.headersSent = true;
1194
+ res.statusCode = status;
1195
+ return res;
1196
+ },
1197
+ _writeHead(status, context) {
1198
+ const statusMessages = {
1199
+ 100: 'Continue',
1200
+ 101: 'Switching Protocols',
1201
+ 102: 'Processing',
1202
+ 200: 'OK',
1203
+ 201: 'Created',
1204
+ 202: 'Accepted',
1205
+ 203: 'Non-Authoritative Information',
1206
+ 204: 'No Content',
1207
+ 205: 'Reset Content',
1208
+ 206: 'Partial Content',
1209
+ 207: 'Multi-Status',
1210
+ 208: 'Already Reported',
1211
+ 226: 'IM Used',
1212
+ 300: 'Multiple Choices',
1213
+ 301: 'Moved Permanently',
1214
+ 302: 'Found',
1215
+ 303: 'See Other',
1216
+ 304: 'Not Modified',
1217
+ 305: 'Use Proxy',
1218
+ 306: '(Unused)',
1219
+ 307: 'Temporary Redirect',
1220
+ 308: 'Permanent Redirect',
1221
+ 400: 'Bad Request',
1222
+ 401: 'Unauthorized',
1223
+ 402: 'Payment Required',
1224
+ 403: 'Forbidden',
1225
+ 404: 'Not Found',
1226
+ 405: 'Method Not Allowed',
1227
+ 406: 'Not Acceptable',
1228
+ 407: 'Proxy Authentication Required',
1229
+ 408: 'Request Timeout',
1230
+ 409: 'Conflict',
1231
+ 410: 'Gone',
1232
+ 411: 'Length Required',
1233
+ 412: 'Precondition Failed',
1234
+ 413: 'Payload Too Large',
1235
+ 414: 'URI Too Long',
1236
+ 415: 'Unsupported Media Type',
1237
+ 416: 'Range Not Satisfiable',
1238
+ 417: 'Expectation Failed',
1239
+ 418: 'I\'m a teapot',
1240
+ 421: 'Misdirected Request',
1241
+ 422: 'Unprocessable Entity',
1242
+ 423: 'Locked',
1243
+ 424: 'Failed Dependency',
1244
+ 425: 'Too Early',
1245
+ 426: 'Upgrade Required',
1246
+ 428: 'Precondition Required',
1247
+ 429: 'Too Many Requests',
1248
+ 431: 'Request Header Fields Too Large',
1249
+ 451: 'Unavailable For Legal Reasons',
1250
+ 500: 'Internal Server Error',
1251
+ 501: 'Not Implemented',
1252
+ 502: 'Bad Gateway',
1253
+ 503: 'Service Unavailable',
1254
+ 504: 'Gateway Timeout',
1255
+ 505: 'HTTP Version Not Supported',
1256
+ 506: 'Variant Also Negotiates',
1257
+ 507: 'Insufficient Storage',
1258
+ 508: 'Loop Detected',
1259
+ 510: 'Not Extended',
1260
+ 511: 'Network Authentication Required'
1261
+ };
1262
+ const statusMessage = statusMessages[status] || statusMessages[500];
1263
+ res.uwsRes.writeStatus(`${status} ${statusMessage}`);
1264
+ res.uwsRes.writeHeader(Object.keys(context)[0], Object.values(context)[0]);
1265
+ return res;
1266
+ },
1267
+ writeStatus: (status) => {
1268
+ if (!res.aborted) {
1269
+ res.uwsRes.writeStatus(status);
1270
+ }
1271
+ return res;
1272
+ },
1273
+ end: (str) => {
1274
+ if (res.aborted) {
1275
+ return;
1276
+ }
1277
+ uwsRes.cork(() => {
1278
+ if (!res.aborted) {
1279
+ res.aborted = true;
1280
+ for (const h in res.writeHeaders) {
1281
+ //@ts-ignore
1282
+ res._writeHead(h, res.writeHeaders[h]);
1283
+ }
1284
+ uwsRes.end(str);
1285
+ return;
1286
+ }
1287
+ });
1288
+ },
1289
+ aborted: false,
1290
+ writeHeaders: {},
1291
+ headersSent: false,
1292
+ statusCode: 200,
1293
+ uwsRes,
1294
+ };
1295
+ uwsRes.onAborted(() => {
1296
+ res.aborted = true;
1297
+ });
1298
+ return { req, res };
1299
+ }
1107
1300
  _normalizePath(...paths) {
1108
1301
  const path = paths
1109
1302
  .join('/')
1110
1303
  .replace(/\/+/g, '/')
1111
1304
  .replace(/\/+$/, '');
1112
1305
  const normalizedPath = path.startsWith('/') ? path : `/${path}`;
1113
- return /\/api\/api/.test(normalizedPath) ? normalizedPath.replace(/\/api\/api\//, "/api/") : normalizedPath;
1306
+ return /\/api\/api/.test(normalizedPath)
1307
+ ? normalizedPath.replace(/\/api\/api\//, "/api/")
1308
+ : normalizedPath;
1114
1309
  }
1115
1310
  _swaggerHandler() {
1116
1311
  const routes = this.routers
1117
- .routes.filter(r => ["GET", "POST", "PUT", "PATCH", "DELETE"].includes(r.method));
1312
+ .routes
1313
+ .filter(r => {
1314
+ return [
1315
+ "GET", "POST",
1316
+ "PUT", "PATCH",
1317
+ "DELETE",
1318
+ "HEAD", "OPTIONS"
1319
+ ].includes(r.method);
1320
+ });
1118
1321
  const { path, html, staticSwaggerHandler, staticUrl } = this._parser.swagger({
1119
1322
  ...this._swagger,
1120
1323
  specs: this._swaggerSpecs,
1121
1324
  routes
1122
1325
  });
1123
1326
  this._router.get(staticUrl, staticSwaggerHandler);
1124
- this._router.get(String(path), (req, res) => {
1327
+ this._router.get(path, (_, res) => {
1125
1328
  res.writeHead(200, { 'Content-Type': 'text/html' });
1126
- res.write(html);
1127
- return res.end();
1329
+ res.end(html);
1330
+ return;
1128
1331
  });
1129
1332
  return;
1130
1333
  }