tspace-spear 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/License +1 -1
- package/README.md +336 -47
- package/build/lib/core/decorators/context.js +10 -9
- package/build/lib/core/decorators/context.js.map +1 -0
- package/build/lib/core/decorators/controller.js +1 -0
- package/build/lib/core/decorators/controller.js.map +1 -0
- package/build/lib/core/decorators/headers.js +1 -0
- package/build/lib/core/decorators/headers.js.map +1 -0
- package/build/lib/core/decorators/index.d.ts +1 -0
- package/build/lib/core/decorators/index.js +2 -0
- package/build/lib/core/decorators/index.js.map +1 -0
- package/build/lib/core/decorators/methods.js +1 -0
- package/build/lib/core/decorators/methods.js.map +1 -0
- package/build/lib/core/decorators/middleware.d.ts +1 -1
- package/build/lib/core/decorators/middleware.js +1 -0
- package/build/lib/core/decorators/middleware.js.map +1 -0
- package/build/lib/core/decorators/statusCode.js +1 -0
- package/build/lib/core/decorators/statusCode.js.map +1 -0
- package/build/lib/core/decorators/swagger.d.ts +2 -0
- package/build/lib/core/decorators/swagger.js +15 -0
- package/build/lib/core/decorators/swagger.js.map +1 -0
- package/build/lib/core/server/index.d.ts +53 -24
- package/build/lib/core/server/index.js +165 -211
- package/build/lib/core/server/index.js.map +1 -0
- package/build/lib/core/server/parser-factory.d.ts +26 -0
- package/build/lib/core/server/parser-factory.js +413 -0
- package/build/lib/core/server/parser-factory.js.map +1 -0
- package/build/lib/core/server/router.d.ts +2 -2
- package/build/lib/core/server/router.js +1 -0
- package/build/lib/core/server/router.js.map +1 -0
- package/build/lib/{types → core/types}/index.d.ts +79 -7
- package/build/lib/{types → core/types}/index.js +1 -0
- package/build/lib/core/types/index.js.map +1 -0
- package/build/lib/index.d.ts +4 -13
- package/build/lib/index.js +7 -23
- package/build/lib/index.js.map +1 -0
- package/build/tests/benchmark.test.d.ts +1 -0
- package/build/tests/benchmark.test.js +135 -0
- package/build/tests/benchmark.test.js.map +1 -0
- package/package.json +22 -13
|
@@ -35,20 +35,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
35
35
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
36
|
};
|
|
37
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
-
exports.Application = void 0;
|
|
38
|
+
exports.Application = exports.Spear = void 0;
|
|
39
39
|
const fs_1 = __importDefault(require("fs"));
|
|
40
40
|
const path_1 = __importDefault(require("path"));
|
|
41
41
|
const find_my_way_1 = __importDefault(require("find-my-way"));
|
|
42
|
-
const formidable_1 = __importDefault(require("formidable"));
|
|
43
42
|
const url_1 = require("url");
|
|
44
43
|
const on_finished_1 = __importDefault(require("on-finished"));
|
|
45
|
-
const string_decoder_1 = require("string_decoder");
|
|
46
44
|
const http_1 = __importStar(require("http"));
|
|
45
|
+
const parser_factory_1 = require("./parser-factory");
|
|
47
46
|
/**
|
|
48
47
|
*
|
|
49
|
-
* The '
|
|
48
|
+
* The 'Spear' class is used to create a server and handle HTTP requests.
|
|
50
49
|
*
|
|
51
|
-
* @returns {
|
|
50
|
+
* @returns {Spear} application
|
|
52
51
|
* @example
|
|
53
52
|
* new Application()
|
|
54
53
|
* .get('/' , () => 'Hello world!')
|
|
@@ -60,128 +59,62 @@ const http_1 = __importStar(require("http"));
|
|
|
60
59
|
* .listen(3000 , () => console.log('server listening on port : 3000'))
|
|
61
60
|
*
|
|
62
61
|
*/
|
|
63
|
-
class
|
|
62
|
+
class Spear {
|
|
64
63
|
constructor({ controllers, middlewares, globalPrefix, logger } = {}) {
|
|
65
64
|
this._router = (0, find_my_way_1.default)();
|
|
65
|
+
this._parser = new parser_factory_1.ParserFactory();
|
|
66
|
+
this._swagger = {
|
|
67
|
+
use: false,
|
|
68
|
+
path: '/api/docs',
|
|
69
|
+
servers: [
|
|
70
|
+
{
|
|
71
|
+
url: 'http://localhost:3000'
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
tags: [],
|
|
75
|
+
info: {
|
|
76
|
+
title: "API Documentation",
|
|
77
|
+
description: "This is a sample documentation",
|
|
78
|
+
version: "1.0.0"
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
this._swaggerAdditional = [];
|
|
66
82
|
this._errorHandler = null;
|
|
67
83
|
this._globalMiddlewares = [];
|
|
68
84
|
this._formatResponse = null;
|
|
69
85
|
this._onListeners = [];
|
|
70
86
|
this._fileUploadOptions = {
|
|
71
|
-
|
|
72
|
-
useTempFiles: false,
|
|
87
|
+
limit: Infinity,
|
|
73
88
|
tempFileDir: 'tmp',
|
|
74
89
|
removeTempFile: {
|
|
75
|
-
remove:
|
|
90
|
+
remove: false,
|
|
76
91
|
ms: 1000 * 60 * 10
|
|
77
92
|
}
|
|
78
93
|
};
|
|
79
|
-
this._filesParser = (req) => __awaiter(this, void 0, void 0, function* () {
|
|
80
|
-
try {
|
|
81
|
-
const temp = this._fileUploadOptions.tempFileDir;
|
|
82
|
-
if (!fs_1.default.existsSync(temp)) {
|
|
83
|
-
try {
|
|
84
|
-
fs_1.default.mkdirSync(temp, { recursive: true });
|
|
85
|
-
}
|
|
86
|
-
catch (err) { }
|
|
87
|
-
}
|
|
88
|
-
const form = (0, formidable_1.default)({ uploadDir: temp });
|
|
89
|
-
const [dataBody, dataFiles] = yield form.parse(req);
|
|
90
|
-
const files = {};
|
|
91
|
-
const body = {};
|
|
92
|
-
const removeTemp = (fileTemp) => {
|
|
93
|
-
if (!this._fileUploadOptions.removeTempFile.remove)
|
|
94
|
-
return;
|
|
95
|
-
const remove = () => fs_1.default.unlinkSync(fileTemp);
|
|
96
|
-
setTimeout(remove, this._fileUploadOptions.removeTempFile.ms);
|
|
97
|
-
};
|
|
98
|
-
for (const key in dataFiles) {
|
|
99
|
-
const v = dataFiles[key];
|
|
100
|
-
if (v == null)
|
|
101
|
-
continue;
|
|
102
|
-
const file = v[0];
|
|
103
|
-
if (file.size > this._fileUploadOptions.limits) {
|
|
104
|
-
fs_1.default.unlinkSync(file.filepath);
|
|
105
|
-
continue;
|
|
106
|
-
}
|
|
107
|
-
files[key] = {
|
|
108
|
-
size: file.size,
|
|
109
|
-
tempFilePath: file.filepath,
|
|
110
|
-
tempFileName: file.newFilename,
|
|
111
|
-
mimetype: file.mimetype,
|
|
112
|
-
name: file.originalFilename
|
|
113
|
-
};
|
|
114
|
-
removeTemp(file.filepath);
|
|
115
|
-
}
|
|
116
|
-
for (const key in dataBody) {
|
|
117
|
-
const v = dataBody[key];
|
|
118
|
-
if (v == null)
|
|
119
|
-
continue;
|
|
120
|
-
body[key] = v[0];
|
|
121
|
-
}
|
|
122
|
-
return {
|
|
123
|
-
body,
|
|
124
|
-
files
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
catch (e) {
|
|
128
|
-
return {
|
|
129
|
-
body: {},
|
|
130
|
-
files: {}
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
this._bodyParser = (req) => {
|
|
135
|
-
if ((req === null || req === void 0 ? void 0 : req._writeParserEnd) === true)
|
|
136
|
-
return req._bodyParser;
|
|
137
|
-
return new Promise((resolve, reject) => {
|
|
138
|
-
const decoder = new string_decoder_1.StringDecoder('utf-8');
|
|
139
|
-
let payload = '';
|
|
140
|
-
req.on('data', (data) => {
|
|
141
|
-
payload += decoder.write(data);
|
|
142
|
-
});
|
|
143
|
-
req.on('end', () => {
|
|
144
|
-
try {
|
|
145
|
-
payload += decoder.end();
|
|
146
|
-
req._writeParserEnd = true;
|
|
147
|
-
req._bodyParser = JSON.parse(payload);
|
|
148
|
-
return resolve(JSON.parse(payload));
|
|
149
|
-
}
|
|
150
|
-
catch (e) {
|
|
151
|
-
req._writeParserEnd = true;
|
|
152
|
-
req._bodyParser = {};
|
|
153
|
-
return resolve({});
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
req.on('error', (err) => {
|
|
157
|
-
req._writeParserEnd = true;
|
|
158
|
-
req._bodyParser = {};
|
|
159
|
-
return reject(err);
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
};
|
|
163
94
|
this._wrapHandlers = (...handlers) => {
|
|
164
95
|
return (req, res, params) => __awaiter(this, void 0, void 0, function* () {
|
|
165
|
-
const runHandler = (
|
|
96
|
+
const runHandler = (...args_1) => __awaiter(this, [...args_1], void 0, function* (index = 0) {
|
|
166
97
|
const response = this._customizeResponse(req, res);
|
|
167
98
|
const request = req;
|
|
168
99
|
const body = request._bodyParser;
|
|
169
100
|
const files = request._filesParser;
|
|
170
101
|
const cookies = request._cookiesParser;
|
|
102
|
+
const headers = request.headers;
|
|
171
103
|
const query = Object.assign({}, (0, url_1.parse)(String(req.url), true).query);
|
|
172
|
-
const
|
|
104
|
+
const RecordOrEmptyRecord = (data) => {
|
|
173
105
|
if (data == null)
|
|
174
|
-
return
|
|
175
|
-
return Object.keys(data).length ? data :
|
|
106
|
+
return {};
|
|
107
|
+
return Object.keys(data).length ? data : {};
|
|
176
108
|
};
|
|
177
109
|
const ctx = {
|
|
178
110
|
req: request,
|
|
179
111
|
res: response,
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
112
|
+
headers: RecordOrEmptyRecord(headers),
|
|
113
|
+
params: RecordOrEmptyRecord(params),
|
|
114
|
+
query: RecordOrEmptyRecord(query),
|
|
115
|
+
body: RecordOrEmptyRecord(body),
|
|
116
|
+
files: RecordOrEmptyRecord(files),
|
|
117
|
+
cookies: RecordOrEmptyRecord(cookies),
|
|
185
118
|
};
|
|
186
119
|
if (index === handlers.length - 1) {
|
|
187
120
|
return this._wrapResponse(handlers[index].bind(handlers[index]))(ctx, this._nextFunction(ctx));
|
|
@@ -195,11 +128,12 @@ class Application {
|
|
|
195
128
|
const ctx = {
|
|
196
129
|
req,
|
|
197
130
|
res: this._customizeResponse(req, res),
|
|
198
|
-
params: Object.keys(params).length ? params :
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
131
|
+
params: Object.keys(params).length ? params : {},
|
|
132
|
+
headers: {},
|
|
133
|
+
query: {},
|
|
134
|
+
body: {},
|
|
135
|
+
files: {},
|
|
136
|
+
cookies: {}
|
|
203
137
|
};
|
|
204
138
|
return this._nextFunction(ctx)(err);
|
|
205
139
|
});
|
|
@@ -211,6 +145,12 @@ class Application {
|
|
|
211
145
|
this._middlewares = middlewares;
|
|
212
146
|
this._globalPrefix = globalPrefix == null ? '' : globalPrefix;
|
|
213
147
|
}
|
|
148
|
+
get instance() {
|
|
149
|
+
return this;
|
|
150
|
+
}
|
|
151
|
+
get routers() {
|
|
152
|
+
return this._router;
|
|
153
|
+
}
|
|
214
154
|
/**
|
|
215
155
|
* The 'enableCors' is used to enable the cors origins on the server.
|
|
216
156
|
*
|
|
@@ -225,7 +165,7 @@ class Application {
|
|
|
225
165
|
const origin = (_a = req.headers) === null || _a === void 0 ? void 0 : _a.origin;
|
|
226
166
|
if (origin == null)
|
|
227
167
|
return next();
|
|
228
|
-
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
|
168
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS');
|
|
229
169
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
230
170
|
if (origins == null) {
|
|
231
171
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
@@ -254,44 +194,20 @@ class Application {
|
|
|
254
194
|
this._globalMiddlewares.push(middleware);
|
|
255
195
|
return this;
|
|
256
196
|
}
|
|
257
|
-
/**
|
|
258
|
-
* The 'useRouter' method is used to add the router in the request context.
|
|
259
|
-
*
|
|
260
|
-
* @parms {Function} router
|
|
261
|
-
* @property {Function} router - get() , post() , put() , patch() , delete()
|
|
262
|
-
* @returns {this}
|
|
263
|
-
*/
|
|
264
|
-
useRouter(router) {
|
|
265
|
-
const routes = router.routes;
|
|
266
|
-
for (const { path, method, handlers } of routes) {
|
|
267
|
-
let normalizePath = [
|
|
268
|
-
this._globalPrefix,
|
|
269
|
-
path
|
|
270
|
-
].join('/')
|
|
271
|
-
.replace(/\/+/g, '/')
|
|
272
|
-
.replace(/\/+$/, '');
|
|
273
|
-
normalizePath = normalizePath.startsWith('/') ? normalizePath : `/${normalizePath}`;
|
|
274
|
-
this[method](normalizePath, ...handlers);
|
|
275
|
-
}
|
|
276
|
-
return this;
|
|
277
|
-
}
|
|
278
197
|
/**
|
|
279
198
|
* The 'useBodyParser' method is a middleware used to parse the request body of incoming HTTP requests.
|
|
280
199
|
*
|
|
281
200
|
* @returns {this}
|
|
282
201
|
*/
|
|
283
202
|
useBodyParser() {
|
|
284
|
-
this._globalMiddlewares.push((
|
|
203
|
+
this._globalMiddlewares.push((_a, next_1) => __awaiter(this, [_a, next_1], void 0, function* ({ req, res }, next) {
|
|
285
204
|
const contentType = req === null || req === void 0 ? void 0 : req.headers['content-type'];
|
|
286
205
|
const isFileUpload = contentType && contentType.startsWith('multipart/form-data');
|
|
287
|
-
const isListMethods = ['POST', 'PATCH', 'PUT'].includes(String(req.method));
|
|
288
|
-
if (!isListMethods)
|
|
289
|
-
return next();
|
|
290
206
|
if (isFileUpload)
|
|
291
207
|
return next();
|
|
292
208
|
if ((req === null || req === void 0 ? void 0 : req._bodyParser) != null)
|
|
293
209
|
return next();
|
|
294
|
-
req._bodyParser = yield this.
|
|
210
|
+
req._bodyParser = yield this._parser.body(req);
|
|
295
211
|
return next();
|
|
296
212
|
}));
|
|
297
213
|
return this;
|
|
@@ -305,37 +221,47 @@ class Application {
|
|
|
305
221
|
this._globalMiddlewares.push(({ req }, next) => {
|
|
306
222
|
if ((req === null || req === void 0 ? void 0 : req._cookiesParser) != null)
|
|
307
223
|
return next();
|
|
308
|
-
req._cookiesParser = this.
|
|
224
|
+
req._cookiesParser = this._parser.cookies(req);
|
|
309
225
|
return next();
|
|
310
226
|
});
|
|
311
227
|
return this;
|
|
312
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* The 'useRouter' method is used to add the router in the request context.
|
|
231
|
+
*
|
|
232
|
+
* @parms {Function} router
|
|
233
|
+
* @property {Function} router - get() , post() , put() , patch() , delete()
|
|
234
|
+
* @returns {this}
|
|
235
|
+
*/
|
|
236
|
+
useRouter(router) {
|
|
237
|
+
const routes = router.routes;
|
|
238
|
+
for (const { path, method, handlers } of routes) {
|
|
239
|
+
this[method](this._normalizePath(this._globalPrefix, path), ...handlers);
|
|
240
|
+
}
|
|
241
|
+
return this;
|
|
242
|
+
}
|
|
313
243
|
/**
|
|
314
244
|
* The 'useFileUpload' method is a middleware used to handler file uploads. It adds a file upload of incoming HTTP requests.
|
|
315
245
|
*
|
|
316
246
|
* @param {?Object}
|
|
317
247
|
* @property {?number} limits
|
|
318
|
-
* @property {?boolean} useTempFiles
|
|
319
248
|
* @property {?string} tempFileDir
|
|
320
249
|
* @property {?Object} removeTempFile
|
|
321
250
|
* @property {boolean} removeTempFile.remove
|
|
322
251
|
* @property {number} removeTempFile.ms
|
|
323
252
|
* @returns
|
|
324
253
|
*/
|
|
325
|
-
useFileUpload({
|
|
326
|
-
if (
|
|
327
|
-
this._fileUploadOptions.
|
|
254
|
+
useFileUpload({ limit, tempFileDir, removeTempFile } = {}) {
|
|
255
|
+
if (limit != null) {
|
|
256
|
+
this._fileUploadOptions.limit = limit;
|
|
328
257
|
}
|
|
329
258
|
if (tempFileDir != null) {
|
|
330
259
|
this._fileUploadOptions.tempFileDir = tempFileDir;
|
|
331
260
|
}
|
|
332
|
-
if (useTempFiles != null) {
|
|
333
|
-
this._fileUploadOptions.useTempFiles = useTempFiles;
|
|
334
|
-
}
|
|
335
261
|
if (removeTempFile != null) {
|
|
336
262
|
this._fileUploadOptions.removeTempFile = removeTempFile;
|
|
337
263
|
}
|
|
338
|
-
this._globalMiddlewares.push((
|
|
264
|
+
this._globalMiddlewares.push((_a, next_1) => __awaiter(this, [_a, next_1], void 0, function* ({ req }, next) {
|
|
339
265
|
const contentType = req === null || req === void 0 ? void 0 : req.headers['content-type'];
|
|
340
266
|
const isFileUpload = contentType && contentType.startsWith('multipart/form-data');
|
|
341
267
|
const isListMethods = ['POST', 'PATCH', 'PUT'].includes(String(req.method));
|
|
@@ -345,13 +271,33 @@ class Application {
|
|
|
345
271
|
return next();
|
|
346
272
|
if ((req === null || req === void 0 ? void 0 : req._filesParser) != null)
|
|
347
273
|
return next();
|
|
348
|
-
const { body, files } = yield this.
|
|
274
|
+
const { body, files } = yield this._parser.files({ req, options: this._fileUploadOptions });
|
|
349
275
|
req._filesParser = files;
|
|
350
276
|
req._bodyParser = body;
|
|
351
277
|
return next();
|
|
352
278
|
}));
|
|
353
279
|
return this;
|
|
354
280
|
}
|
|
281
|
+
/**
|
|
282
|
+
* The 'useSwagger' method is a middleware used to create swagger api.
|
|
283
|
+
*
|
|
284
|
+
* @param {?Object}
|
|
285
|
+
* @property {?string} path
|
|
286
|
+
* @property {?array} servers
|
|
287
|
+
* @property {?object} info
|
|
288
|
+
* @property {?array} tags
|
|
289
|
+
* @returns
|
|
290
|
+
*/
|
|
291
|
+
useSwagger({ path, servers, info, tags } = {}) {
|
|
292
|
+
this._swagger = {
|
|
293
|
+
use: true,
|
|
294
|
+
path: path !== null && path !== void 0 ? path : this._swagger.path,
|
|
295
|
+
servers: servers !== null && servers !== void 0 ? servers : this._swagger.servers,
|
|
296
|
+
tags: tags !== null && tags !== void 0 ? tags : this._swagger.tags,
|
|
297
|
+
info: info !== null && info !== void 0 ? info : this._swagger.info
|
|
298
|
+
};
|
|
299
|
+
return this;
|
|
300
|
+
}
|
|
355
301
|
/**
|
|
356
302
|
* The 'formatResponse' method is used to format the response
|
|
357
303
|
*
|
|
@@ -383,11 +329,12 @@ class Application {
|
|
|
383
329
|
return notfound({
|
|
384
330
|
req,
|
|
385
331
|
res: this._customizeResponse(req, res),
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
332
|
+
headers: {},
|
|
333
|
+
query: {},
|
|
334
|
+
files: {},
|
|
335
|
+
body: {},
|
|
336
|
+
params: {},
|
|
337
|
+
cookies: {}
|
|
391
338
|
});
|
|
392
339
|
};
|
|
393
340
|
this._onListeners.push(() => {
|
|
@@ -406,7 +353,7 @@ class Application {
|
|
|
406
353
|
*/
|
|
407
354
|
get(path, ...handlers) {
|
|
408
355
|
this._onListeners.push(() => {
|
|
409
|
-
return this._router.get(path, this._wrapHandlers(...this._globalMiddlewares, ...handlers));
|
|
356
|
+
return this._router.get(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
|
|
410
357
|
});
|
|
411
358
|
return this;
|
|
412
359
|
}
|
|
@@ -421,7 +368,7 @@ class Application {
|
|
|
421
368
|
*/
|
|
422
369
|
post(path, ...handlers) {
|
|
423
370
|
this._onListeners.push(() => {
|
|
424
|
-
return this._router.post(path, this._wrapHandlers(...this._globalMiddlewares, ...handlers));
|
|
371
|
+
return this._router.post(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
|
|
425
372
|
});
|
|
426
373
|
return this;
|
|
427
374
|
}
|
|
@@ -436,7 +383,7 @@ class Application {
|
|
|
436
383
|
*/
|
|
437
384
|
put(path, ...handlers) {
|
|
438
385
|
this._onListeners.push(() => {
|
|
439
|
-
return this._router.put(path, this._wrapHandlers(...this._globalMiddlewares, ...handlers));
|
|
386
|
+
return this._router.put(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
|
|
440
387
|
});
|
|
441
388
|
return this;
|
|
442
389
|
}
|
|
@@ -451,7 +398,7 @@ class Application {
|
|
|
451
398
|
*/
|
|
452
399
|
patch(path, ...handlers) {
|
|
453
400
|
this._onListeners.push(() => {
|
|
454
|
-
return this._router.patch(path, this._wrapHandlers(...this._globalMiddlewares, ...handlers));
|
|
401
|
+
return this._router.patch(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
|
|
455
402
|
});
|
|
456
403
|
return this;
|
|
457
404
|
}
|
|
@@ -466,7 +413,7 @@ class Application {
|
|
|
466
413
|
*/
|
|
467
414
|
delete(path, ...handlers) {
|
|
468
415
|
this._onListeners.push(() => {
|
|
469
|
-
return this._router.delete(path, this._wrapHandlers(...this._globalMiddlewares, ...handlers));
|
|
416
|
+
return this._router.delete(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
|
|
470
417
|
});
|
|
471
418
|
return this;
|
|
472
419
|
}
|
|
@@ -481,7 +428,7 @@ class Application {
|
|
|
481
428
|
*/
|
|
482
429
|
all(path, ...handlers) {
|
|
483
430
|
this._onListeners.push(() => {
|
|
484
|
-
return this._router.all(path, this._wrapHandlers(...this._globalMiddlewares, ...handlers));
|
|
431
|
+
return this._router.all(this._normalizePath(this._globalPrefix, path), this._wrapHandlers(...this._globalMiddlewares, ...handlers));
|
|
485
432
|
});
|
|
486
433
|
return this;
|
|
487
434
|
}
|
|
@@ -492,24 +439,36 @@ class Application {
|
|
|
492
439
|
* @param {function} cb
|
|
493
440
|
* @returns
|
|
494
441
|
*/
|
|
495
|
-
listen(
|
|
496
|
-
|
|
497
|
-
|
|
442
|
+
listen() {
|
|
443
|
+
var arguments_1 = arguments;
|
|
444
|
+
return __awaiter(this, arguments, void 0, function* (port = 3000, cb) {
|
|
445
|
+
if (arguments_1.length === 1 && typeof port === 'function') {
|
|
498
446
|
cb = port;
|
|
499
447
|
port = 3000;
|
|
500
448
|
}
|
|
501
449
|
const server = yield this._createServer();
|
|
450
|
+
server.listen(port == null ? 3000 : port, () => {
|
|
451
|
+
if (cb)
|
|
452
|
+
cb({ server, port });
|
|
453
|
+
});
|
|
502
454
|
server.on('listening', () => {
|
|
503
455
|
this._onListeners.forEach(listener => listener());
|
|
456
|
+
if (this._swagger.use) {
|
|
457
|
+
const routes = this.routers
|
|
458
|
+
.routes.filter(r => ["GET", "POST", "PUT", "PATCH", "DELETE"].includes(r.method));
|
|
459
|
+
const { path, html, staticSwaggerHandler, staticUrl } = this._parser.swagger(Object.assign(Object.assign({}, this._swagger), { options: this._swaggerAdditional, routes }));
|
|
460
|
+
this.routers.get(staticUrl, staticSwaggerHandler);
|
|
461
|
+
this.routers.get(String(path), (req, res) => {
|
|
462
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
463
|
+
res.write(html);
|
|
464
|
+
return res.end();
|
|
465
|
+
});
|
|
466
|
+
}
|
|
504
467
|
});
|
|
505
468
|
server.on('error', (_) => {
|
|
506
469
|
port = Math.floor(Math.random() * 8999) + 1000;
|
|
507
470
|
server.listen(port);
|
|
508
471
|
});
|
|
509
|
-
server.listen(port == null ? 3000 : port, () => {
|
|
510
|
-
if (cb)
|
|
511
|
-
cb();
|
|
512
|
-
});
|
|
513
472
|
return;
|
|
514
473
|
});
|
|
515
474
|
}
|
|
@@ -560,6 +519,7 @@ class Application {
|
|
|
560
519
|
}
|
|
561
520
|
_registerControllers() {
|
|
562
521
|
return __awaiter(this, void 0, void 0, function* () {
|
|
522
|
+
var _a, _b, _c, _d, _e, _f;
|
|
563
523
|
if (this._controllers == null)
|
|
564
524
|
return;
|
|
565
525
|
if (!Array.isArray(this._controllers)) {
|
|
@@ -568,40 +528,40 @@ class Application {
|
|
|
568
528
|
const response = yield Promise.resolve(`${file}`).then(s => __importStar(require(s)));
|
|
569
529
|
const controller = response === null || response === void 0 ? void 0 : response.default;
|
|
570
530
|
const controllerInstance = new controller();
|
|
571
|
-
const prefixPath = Reflect.getMetadata("controllers", controller);
|
|
572
|
-
const routers = Reflect.getMetadata("routers", controller);
|
|
531
|
+
const prefixPath = (_a = Reflect.getMetadata("controllers", controller)) !== null && _a !== void 0 ? _a : '';
|
|
532
|
+
const routers = (_b = Reflect.getMetadata("routers", controller)) !== null && _b !== void 0 ? _b : [];
|
|
533
|
+
const swaggers = (_c = Reflect.getMetadata("swaggers", controller)) !== null && _c !== void 0 ? _c : [];
|
|
573
534
|
if (prefixPath == null)
|
|
574
535
|
continue;
|
|
575
|
-
for (const { method, path, handler } of routers) {
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
this[method](normalizePath, this._wrapResponse(controllerInstance[String(handler)].bind(controllerInstance)));
|
|
536
|
+
for (const { method, path, handler } of Array.from(routers)) {
|
|
537
|
+
const find = Array.from(swaggers).find(s => s.handler === handler);
|
|
538
|
+
if (find != null) {
|
|
539
|
+
this._swaggerAdditional = [
|
|
540
|
+
...this._swaggerAdditional,
|
|
541
|
+
Object.assign(Object.assign({}, find), { path: this._normalizePath(this._globalPrefix, prefixPath, path), method })
|
|
542
|
+
];
|
|
543
|
+
}
|
|
544
|
+
this[method](this._normalizePath(this._globalPrefix, prefixPath, path), this._wrapResponse(controllerInstance[String(handler)].bind(controllerInstance)));
|
|
585
545
|
}
|
|
586
546
|
}
|
|
587
547
|
return;
|
|
588
548
|
}
|
|
589
549
|
for (const controller of this._controllers) {
|
|
590
550
|
const controllerInstance = new controller();
|
|
591
|
-
const prefixPath = Reflect.getMetadata("controllers", controller);
|
|
592
|
-
const routers = Reflect.getMetadata("routers", controller);
|
|
551
|
+
const prefixPath = (_d = Reflect.getMetadata("controllers", controller)) !== null && _d !== void 0 ? _d : '';
|
|
552
|
+
const routers = (_e = Reflect.getMetadata("routers", controller)) !== null && _e !== void 0 ? _e : [];
|
|
553
|
+
const swaggers = (_f = Reflect.getMetadata("swaggers", controller)) !== null && _f !== void 0 ? _f : [];
|
|
593
554
|
if (prefixPath == null)
|
|
594
555
|
continue;
|
|
595
|
-
for (const { method, path, handler } of routers) {
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
this[method](normalizePath, this._wrapResponse(controllerInstance[String(handler)].bind(controllerInstance)));
|
|
556
|
+
for (const { method, path, handler } of Array.from(routers)) {
|
|
557
|
+
const find = Array.from(swaggers).find(s => s.handler === handler);
|
|
558
|
+
if (find != null) {
|
|
559
|
+
this._swaggerAdditional = [
|
|
560
|
+
...this._swaggerAdditional,
|
|
561
|
+
Object.assign(Object.assign({}, find), { path: this._normalizePath(this._globalPrefix, prefixPath, path), method })
|
|
562
|
+
];
|
|
563
|
+
}
|
|
564
|
+
this[method](this._normalizePath(this._globalPrefix, prefixPath, path), this._wrapResponse(controllerInstance[String(handler)].bind(controllerInstance)));
|
|
605
565
|
}
|
|
606
566
|
}
|
|
607
567
|
});
|
|
@@ -626,28 +586,6 @@ class Application {
|
|
|
626
586
|
return;
|
|
627
587
|
});
|
|
628
588
|
}
|
|
629
|
-
_cookiesParser(req) {
|
|
630
|
-
var _a;
|
|
631
|
-
const cookies = {};
|
|
632
|
-
const cookieString = (_a = req.headers) === null || _a === void 0 ? void 0 : _a.cookie;
|
|
633
|
-
if (cookieString == null)
|
|
634
|
-
return null;
|
|
635
|
-
for (const cookie of cookieString.split(';')) {
|
|
636
|
-
const [name, value] = cookie.split('=').map(v => v.trim());
|
|
637
|
-
cookies[name] = decodeURIComponent(value);
|
|
638
|
-
}
|
|
639
|
-
for (const name of Object.keys(cookies)) {
|
|
640
|
-
const cookie = cookies[name];
|
|
641
|
-
if (!cookie.startsWith('Expires='))
|
|
642
|
-
continue;
|
|
643
|
-
const expiresString = cookie.replace('Expires=', '');
|
|
644
|
-
const expiresDate = new Date(expiresString);
|
|
645
|
-
if (isNaN(expiresDate.getTime()) || expiresDate < new Date()) {
|
|
646
|
-
delete cookies[name];
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
return cookies;
|
|
650
|
-
}
|
|
651
589
|
_customizeResponse(req, res) {
|
|
652
590
|
const response = res;
|
|
653
591
|
response.json = (results) => {
|
|
@@ -837,8 +775,6 @@ class Application {
|
|
|
837
775
|
_wrapResponse(handler) {
|
|
838
776
|
return (ctx, next) => __awaiter(this, void 0, void 0, function* () {
|
|
839
777
|
const result = yield handler(ctx, next);
|
|
840
|
-
if (result == null)
|
|
841
|
-
return;
|
|
842
778
|
if (result instanceof http_1.ServerResponse)
|
|
843
779
|
return;
|
|
844
780
|
if (typeof result === 'string') {
|
|
@@ -858,11 +794,17 @@ class Application {
|
|
|
858
794
|
if (!ctx.res.headersSent) {
|
|
859
795
|
ctx.res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
860
796
|
}
|
|
797
|
+
if (Array.isArray(result)) {
|
|
798
|
+
return ctx.res.end(JSON.stringify(this._formatResponse(result)));
|
|
799
|
+
}
|
|
861
800
|
return ctx.res.end(JSON.stringify(this._formatResponse(Object.assign({}, result), ctx.res.statusCode), null, 2));
|
|
862
801
|
}
|
|
863
802
|
if (!ctx.res.headersSent) {
|
|
864
803
|
ctx.res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
865
804
|
}
|
|
805
|
+
if (Array.isArray(result)) {
|
|
806
|
+
return ctx.res.end(JSON.stringify(result));
|
|
807
|
+
}
|
|
866
808
|
return ctx.res.end(JSON.stringify(Object.assign({}, result), null, 2));
|
|
867
809
|
});
|
|
868
810
|
}
|
|
@@ -876,6 +818,18 @@ class Application {
|
|
|
876
818
|
return server;
|
|
877
819
|
});
|
|
878
820
|
}
|
|
821
|
+
_normalizePath(...paths) {
|
|
822
|
+
const path = paths
|
|
823
|
+
.join('/')
|
|
824
|
+
.replace(/\/+/g, '/')
|
|
825
|
+
.replace(/\/+$/, '');
|
|
826
|
+
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
827
|
+
return /\/api\/api/.test(normalizedPath) ? normalizedPath.replace(/\/api\/api\//, "/api/") : normalizedPath;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
exports.Spear = Spear;
|
|
831
|
+
class Application extends Spear {
|
|
879
832
|
}
|
|
880
833
|
exports.Application = Application;
|
|
881
|
-
exports.default =
|
|
834
|
+
exports.default = Spear;
|
|
835
|
+
//# sourceMappingURL=index.js.map
|