ultimate-express 1.2.30 → 1.3.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/README.md +5 -3
- package/package.json +7 -2
- package/src/application.js +12 -11
- package/src/middlewares.js +4 -4
- package/src/request.js +5 -5
- package/src/response.js +19 -23
- package/src/router.js +11 -5
- package/src/types.d.ts +49 -0
- package/src/utils.js +5 -0
- package/src/view.js +2 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ To make sure µExpress matches behavior of Express in all cases, we run all test
|
|
|
16
16
|
|
|
17
17
|
Similar projects based on uWebSockets:
|
|
18
18
|
|
|
19
|
-
- `express` on Bun - since Bun uses uWS for its HTTP module, Express is about 2-3 times faster than on Node.js, but still slower than µExpress because it doesn't do uWS-specific optimizations.
|
|
19
|
+
- `express` on Bun - since Bun uses uWS for its HTTP module, Express is about 2-3 times faster than on Node.js, but still almost 2 times slower than µExpress because it doesn't do uWS-specific optimizations.
|
|
20
20
|
- `hyper-express` - while having a similar API to Express, it's very far from being a drop-in replacement, and implements most of the functionality differently. This creates a lot of random quirks and issues, making the switch quite difficult. Built in middlewares are also very different, middlewares for Express are mostly not supported.
|
|
21
21
|
- `uwebsockets-express` - this library is closer to being a drop-in replacement, but misses a lot of APIs, depends on Express by calling it's methods under the hood and doesn't try to optimize routing by using native uWS router.
|
|
22
22
|
|
|
@@ -61,6 +61,7 @@ Also tested on a [real-world application](https://nekoweb.org) with templates, s
|
|
|
61
61
|
In a lot of cases, you can just replace `require("express")` with `require("ultimate-express")` and everything works the same. But there are some differences:
|
|
62
62
|
|
|
63
63
|
- `case sensitive routing` is enabled by default.
|
|
64
|
+
- a new option `catch async errors` is added. If it's enabled, you don't need to use `express-async-errors` module.
|
|
64
65
|
- request body is only read for POST, PUT and PATCH requests by default. You can add additional methods by setting `body methods` to array with uppercased methods.
|
|
65
66
|
- For HTTPS, instead of doing this:
|
|
66
67
|
```js
|
|
@@ -288,6 +289,7 @@ Almost all middlewares that are compatible with Express are compatible with µEx
|
|
|
288
289
|
- ✅ [body-parser](https://npmjs.com/package/body-parser) (use `express.text()` etc instead for better performance)
|
|
289
290
|
- ✅ [cookie-parser](https://npmjs.com/package/cookie-parser)
|
|
290
291
|
- ✅ [cookie-session](https://npmjs.com/package/cookie-session)
|
|
292
|
+
- ✅ [compression](https://npmjs.com/package/compression)
|
|
291
293
|
- ✅ [serve-static](https://npmjs.com/package/serve-static) (use `express.static()` instead for better performance)
|
|
292
294
|
- ✅ [serve-index](https://npmjs.com/package/serve-index)
|
|
293
295
|
- ✅ [cors](https://npmjs.com/package/cors)
|
|
@@ -301,9 +303,9 @@ Almost all middlewares that are compatible with Express are compatible with µEx
|
|
|
301
303
|
- ✅ [express-subdomain](https://npmjs.com/package/express-subdomain)
|
|
302
304
|
- ✅ [vhost](https://npmjs.com/package/vhost)
|
|
303
305
|
|
|
304
|
-
Middlewares that are confirmed to not work:
|
|
306
|
+
Middlewares and modules that are confirmed to not work:
|
|
305
307
|
|
|
306
|
-
- ❌ [
|
|
308
|
+
- ❌ [express-async-errors](https://npmjs.com/package/express-async-errors) - doesn't work, use `app.set('catch async errors', true)` instead.
|
|
307
309
|
|
|
308
310
|
## Tested view engines
|
|
309
311
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultimate-express",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "The Ultimate Express. Fastest http server with full Express compatibility, based on uWebSockets.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"uwebsockets",
|
|
32
32
|
"uws"
|
|
33
33
|
],
|
|
34
|
+
"types": "src/types.d.ts",
|
|
34
35
|
"author": "dimden.dev",
|
|
35
36
|
"license": "Apache-2.0",
|
|
36
37
|
"bugs": {
|
|
@@ -38,9 +39,10 @@
|
|
|
38
39
|
},
|
|
39
40
|
"homepage": "https://github.com/dimdenGD/ultimate-express#readme",
|
|
40
41
|
"dependencies": {
|
|
42
|
+
"@types/express": "^4.0.0",
|
|
41
43
|
"accepts": "^1.3.8",
|
|
42
44
|
"bytes": "^3.1.2",
|
|
43
|
-
"cookie": "^0.
|
|
45
|
+
"cookie": "^1.0.1",
|
|
44
46
|
"cookie-signature": "^1.2.1",
|
|
45
47
|
"encodeurl": "^2.0.0",
|
|
46
48
|
"etag": "^1.8.1",
|
|
@@ -60,6 +62,7 @@
|
|
|
60
62
|
},
|
|
61
63
|
"devDependencies": {
|
|
62
64
|
"body-parser": "^1.20.3",
|
|
65
|
+
"compression": "^1.7.4",
|
|
63
66
|
"cookie-parser": "^1.4.6",
|
|
64
67
|
"cookie-session": "^2.1.0",
|
|
65
68
|
"cors": "^2.8.5",
|
|
@@ -68,6 +71,7 @@
|
|
|
68
71
|
"exit-hook": "^2.2.1",
|
|
69
72
|
"express": "^4.19.2",
|
|
70
73
|
"express-art-template": "^1.0.1",
|
|
74
|
+
"express-async-errors": "^3.1.1",
|
|
71
75
|
"express-dot-engine": "^1.0.8",
|
|
72
76
|
"express-fileupload": "^1.5.1",
|
|
73
77
|
"express-handlebars": "^8.0.1",
|
|
@@ -78,6 +82,7 @@
|
|
|
78
82
|
"multer": "^1.4.5-lts.1",
|
|
79
83
|
"mustache-express": "^1.3.2",
|
|
80
84
|
"pako": "^2.1.0",
|
|
85
|
+
"pkg-pr-new": "^0.0.29",
|
|
81
86
|
"pug": "^3.0.3",
|
|
82
87
|
"response-time": "^2.3.2",
|
|
83
88
|
"serve-index": "^1.9.1",
|
package/src/application.js
CHANGED
|
@@ -16,7 +16,7 @@ limitations under the License.
|
|
|
16
16
|
|
|
17
17
|
const uWS = require("uWebSockets.js");
|
|
18
18
|
const Router = require("./router.js");
|
|
19
|
-
const { removeDuplicateSlashes, defaultSettings, compileTrust, createETagGenerator, fastQueryParse } = require("./utils.js");
|
|
19
|
+
const { removeDuplicateSlashes, defaultSettings, compileTrust, createETagGenerator, fastQueryParse, NullObject } = require("./utils.js");
|
|
20
20
|
const querystring = require("fast-querystring");
|
|
21
21
|
const ViewClass = require("./view.js");
|
|
22
22
|
const path = require("path");
|
|
@@ -27,7 +27,7 @@ const cpuCount = os.cpus().length;
|
|
|
27
27
|
|
|
28
28
|
let workers = [];
|
|
29
29
|
let taskKey = 0;
|
|
30
|
-
const workerTasks =
|
|
30
|
+
const workerTasks = new NullObject();
|
|
31
31
|
|
|
32
32
|
function createWorker() {
|
|
33
33
|
const worker = new Worker(path.join(__dirname, 'worker.js'));
|
|
@@ -47,7 +47,7 @@ function createWorker() {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
class Application extends Router {
|
|
50
|
-
constructor(settings =
|
|
50
|
+
constructor(settings = new NullObject()) {
|
|
51
51
|
super(settings);
|
|
52
52
|
if(!settings?.uwsOptions) {
|
|
53
53
|
settings.uwsOptions = {};
|
|
@@ -62,8 +62,8 @@ class Application extends Router {
|
|
|
62
62
|
this.uwsApp = uWS.App(settings.uwsOptions);
|
|
63
63
|
this.ssl = false;
|
|
64
64
|
}
|
|
65
|
-
this.cache =
|
|
66
|
-
this.engines =
|
|
65
|
+
this.cache = new NullObject();
|
|
66
|
+
this.engines = new NullObject();
|
|
67
67
|
this.locals = {
|
|
68
68
|
settings: this.settings
|
|
69
69
|
};
|
|
@@ -159,12 +159,12 @@ class Application extends Router {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
enable(key) {
|
|
162
|
-
this.
|
|
162
|
+
this.set(key, true);
|
|
163
163
|
return this;
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
disable(key) {
|
|
167
|
-
this.
|
|
167
|
+
this.set(key, false);
|
|
168
168
|
return this;
|
|
169
169
|
}
|
|
170
170
|
|
|
@@ -206,7 +206,7 @@ class Application extends Router {
|
|
|
206
206
|
throw err;
|
|
207
207
|
}
|
|
208
208
|
this.port = uWS.us_socket_local_port(socket);
|
|
209
|
-
callback(this.port);
|
|
209
|
+
if(callback) callback(this.port);
|
|
210
210
|
};
|
|
211
211
|
let fn = 'listen';
|
|
212
212
|
let args = [];
|
|
@@ -229,6 +229,7 @@ class Application extends Router {
|
|
|
229
229
|
}
|
|
230
230
|
this.listenCalled = true;
|
|
231
231
|
this.uwsApp[fn](...args);
|
|
232
|
+
return this.uwsApp;
|
|
232
233
|
}
|
|
233
234
|
|
|
234
235
|
address() {
|
|
@@ -260,10 +261,10 @@ class Application extends Router {
|
|
|
260
261
|
render(name, options, callback) {
|
|
261
262
|
if(typeof options === 'function') {
|
|
262
263
|
callback = options;
|
|
263
|
-
options =
|
|
264
|
+
options = new NullObject();
|
|
264
265
|
}
|
|
265
266
|
if(!options) {
|
|
266
|
-
options =
|
|
267
|
+
options = new NullObject();
|
|
267
268
|
} else {
|
|
268
269
|
options = Object.assign({}, options);
|
|
269
270
|
}
|
|
@@ -318,4 +319,4 @@ class Application extends Router {
|
|
|
318
319
|
|
|
319
320
|
module.exports = function(options) {
|
|
320
321
|
return new Application(options);
|
|
321
|
-
}
|
|
322
|
+
}
|
package/src/middlewares.js
CHANGED
|
@@ -20,10 +20,10 @@ const bytes = require('bytes');
|
|
|
20
20
|
const zlib = require('fast-zlib');
|
|
21
21
|
const typeis = require('type-is');
|
|
22
22
|
const querystring = require('fast-querystring');
|
|
23
|
-
const { fastQueryParse } = require('./utils.js');
|
|
23
|
+
const { fastQueryParse, NullObject } = require('./utils.js');
|
|
24
24
|
|
|
25
25
|
function static(root, options) {
|
|
26
|
-
if(!options) options =
|
|
26
|
+
if(!options) options = new NullObject();
|
|
27
27
|
if(typeof options.index === 'undefined') options.index = 'index.html';
|
|
28
28
|
if(typeof options.redirect === 'undefined') options.redirect = true;
|
|
29
29
|
if(typeof options.fallthrough === 'undefined') options.fallthrough = true;
|
|
@@ -132,7 +132,7 @@ function createInflate(contentEncoding) {
|
|
|
132
132
|
function createBodyParser(defaultType, beforeReturn) {
|
|
133
133
|
return function(options) {
|
|
134
134
|
if(typeof options !== 'object') {
|
|
135
|
-
options =
|
|
135
|
+
options = new NullObject();
|
|
136
136
|
}
|
|
137
137
|
if(typeof options.limit === 'undefined') options.limit = bytes('100kb');
|
|
138
138
|
else options.limit = bytes(options.limit);
|
|
@@ -160,7 +160,7 @@ function createBodyParser(defaultType, beforeReturn) {
|
|
|
160
160
|
return next();
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
req.body =
|
|
163
|
+
req.body = new NullObject();
|
|
164
164
|
|
|
165
165
|
// skip reading body for non-json content type
|
|
166
166
|
if(!type) {
|
package/src/request.js
CHANGED
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
const { patternToRegex, deprecated } = require("./utils.js");
|
|
17
|
+
const { patternToRegex, deprecated, NullObject } = require("./utils.js");
|
|
18
18
|
const accepts = require("accepts");
|
|
19
19
|
const typeis = require("type-is");
|
|
20
20
|
const parseRange = require("range-parser");
|
|
@@ -64,7 +64,7 @@ module.exports = class Request extends Readable {
|
|
|
64
64
|
this._opPath = this._opPath.slice(0, -1);
|
|
65
65
|
}
|
|
66
66
|
this.method = req.getCaseSensitiveMethod().toUpperCase();
|
|
67
|
-
this.params =
|
|
67
|
+
this.params = new NullObject();
|
|
68
68
|
|
|
69
69
|
this._gotParams = new Set();
|
|
70
70
|
this._stack = [];
|
|
@@ -206,7 +206,7 @@ module.exports = class Request extends Readable {
|
|
|
206
206
|
if(qp) {
|
|
207
207
|
this.#cachedQuery = qp(this.urlQuery.slice(1));
|
|
208
208
|
} else {
|
|
209
|
-
this.#cachedQuery =
|
|
209
|
+
this.#cachedQuery = new NullObject();
|
|
210
210
|
}
|
|
211
211
|
return this.#cachedQuery;
|
|
212
212
|
}
|
|
@@ -351,7 +351,7 @@ module.exports = class Request extends Readable {
|
|
|
351
351
|
if(this.#cachedHeaders) {
|
|
352
352
|
return this.#cachedHeaders;
|
|
353
353
|
}
|
|
354
|
-
let headers =
|
|
354
|
+
let headers = new NullObject();
|
|
355
355
|
this.#rawHeadersEntries.forEach((val) => {
|
|
356
356
|
const key = val[0].toLowerCase();
|
|
357
357
|
const value = val[1];
|
|
@@ -382,7 +382,7 @@ module.exports = class Request extends Readable {
|
|
|
382
382
|
if(this.#cachedDistinctHeaders) {
|
|
383
383
|
return this.#cachedDistinctHeaders;
|
|
384
384
|
}
|
|
385
|
-
let headers =
|
|
385
|
+
let headers = new NullObject();
|
|
386
386
|
this.#rawHeadersEntries.forEach((val) => {
|
|
387
387
|
if(!headers[val[0]]) {
|
|
388
388
|
headers[val[0]] = [];
|
package/src/response.js
CHANGED
|
@@ -20,7 +20,7 @@ const vary = require("vary");
|
|
|
20
20
|
const encodeUrl = require("encodeurl");
|
|
21
21
|
const {
|
|
22
22
|
normalizeType, stringify, deprecated, UP_PATH_REGEXP, decode,
|
|
23
|
-
containsDotFile, isPreconditionFailure, isRangeFresh,
|
|
23
|
+
containsDotFile, isPreconditionFailure, isRangeFresh, NullObject
|
|
24
24
|
} = require("./utils.js");
|
|
25
25
|
const { Writable } = require("stream");
|
|
26
26
|
const { isAbsolute } = require("path");
|
|
@@ -70,7 +70,7 @@ module.exports = class Response extends Writable {
|
|
|
70
70
|
this._res = res;
|
|
71
71
|
this.headersSent = false;
|
|
72
72
|
this.app = app;
|
|
73
|
-
this.locals =
|
|
73
|
+
this.locals = new NullObject();
|
|
74
74
|
this.finished = false;
|
|
75
75
|
this.aborted = false;
|
|
76
76
|
this.statusCode = 200;
|
|
@@ -208,12 +208,9 @@ module.exports = class Response extends Writable {
|
|
|
208
208
|
_implicitHeader() {
|
|
209
209
|
// compatibility function
|
|
210
210
|
// usually should send headers but this is useless for us
|
|
211
|
-
|
|
211
|
+
this.writeHead(this.statusCode);
|
|
212
212
|
}
|
|
213
213
|
status(code) {
|
|
214
|
-
if(this.headersSent) {
|
|
215
|
-
throw new Error('Can\'t set status: Response was already sent');
|
|
216
|
-
}
|
|
217
214
|
this.statusCode = parseInt(code);
|
|
218
215
|
return this;
|
|
219
216
|
}
|
|
@@ -224,7 +221,7 @@ module.exports = class Response extends Writable {
|
|
|
224
221
|
if(this.finished) {
|
|
225
222
|
return;
|
|
226
223
|
}
|
|
227
|
-
|
|
224
|
+
this.writeHead(this.statusCode);
|
|
228
225
|
this._res.cork(() => {
|
|
229
226
|
if(!this.headersSent) {
|
|
230
227
|
const etagFn = this.app.get('etag fn');
|
|
@@ -282,22 +279,23 @@ module.exports = class Response extends Writable {
|
|
|
282
279
|
}
|
|
283
280
|
if(typeof body === 'string') {
|
|
284
281
|
const contentType = this.headers['content-type'];
|
|
285
|
-
if(
|
|
282
|
+
if(!contentType){
|
|
283
|
+
this.type('html'); // string defaulting to html
|
|
284
|
+
} else if(!contentType.includes(';')) {
|
|
286
285
|
this.headers['content-type'] += '; charset=utf-8';
|
|
287
286
|
}
|
|
288
287
|
}
|
|
289
|
-
this.writeHead(this.statusCode);
|
|
290
288
|
return this.end(body);
|
|
291
289
|
}
|
|
292
|
-
sendFile(path, options =
|
|
290
|
+
sendFile(path, options = new NullObject(), callback) {
|
|
293
291
|
if(typeof path !== 'string') {
|
|
294
292
|
throw new TypeError('path argument is required to res.sendFile');
|
|
295
293
|
}
|
|
296
294
|
if(typeof options === 'function') {
|
|
297
295
|
callback = options;
|
|
298
|
-
options =
|
|
296
|
+
options = new NullObject();
|
|
299
297
|
}
|
|
300
|
-
if(!options) options =
|
|
298
|
+
if(!options) options = new NullObject();
|
|
301
299
|
let done = callback;
|
|
302
300
|
if(!done) done = this.req.next;
|
|
303
301
|
// default options
|
|
@@ -489,16 +487,16 @@ module.exports = class Response extends Writable {
|
|
|
489
487
|
download(path, filename, options, callback) {
|
|
490
488
|
let done = callback;
|
|
491
489
|
let name = filename;
|
|
492
|
-
let opts = options ||
|
|
490
|
+
let opts = options || new NullObject();
|
|
493
491
|
|
|
494
492
|
// support function as second or third arg
|
|
495
493
|
if (typeof filename === 'function') {
|
|
496
494
|
done = filename;
|
|
497
495
|
name = null;
|
|
498
|
-
opts =
|
|
496
|
+
opts = new NullObject();
|
|
499
497
|
} else if (typeof options === 'function') {
|
|
500
498
|
done = options;
|
|
501
|
-
opts =
|
|
499
|
+
opts = new NullObject();
|
|
502
500
|
}
|
|
503
501
|
|
|
504
502
|
// support optional filename, where options may be in it's place
|
|
@@ -519,7 +517,7 @@ module.exports = class Response extends Writable {
|
|
|
519
517
|
}
|
|
520
518
|
set(field, value) {
|
|
521
519
|
if(this.headersSent) {
|
|
522
|
-
throw new Error('
|
|
520
|
+
throw new Error('Cannot set headers after they are sent to the client');
|
|
523
521
|
}
|
|
524
522
|
if(typeof field === 'object') {
|
|
525
523
|
for(const header in field) {
|
|
@@ -578,10 +576,10 @@ module.exports = class Response extends Writable {
|
|
|
578
576
|
render(view, options, callback) {
|
|
579
577
|
if(typeof options === 'function') {
|
|
580
578
|
callback = options;
|
|
581
|
-
options =
|
|
579
|
+
options = new NullObject();
|
|
582
580
|
}
|
|
583
581
|
if(!options) {
|
|
584
|
-
options =
|
|
582
|
+
options = new NullObject();
|
|
585
583
|
} else {
|
|
586
584
|
options = Object.assign({}, options);
|
|
587
585
|
}
|
|
@@ -595,7 +593,7 @@ module.exports = class Response extends Writable {
|
|
|
595
593
|
}
|
|
596
594
|
cookie(name, value, options) {
|
|
597
595
|
if(!options) {
|
|
598
|
-
options =
|
|
596
|
+
options = new NullObject();
|
|
599
597
|
}
|
|
600
598
|
let val = typeof value === 'object' ? "j:"+JSON.stringify(value) : String(value);
|
|
601
599
|
if(options.maxAge != null) {
|
|
@@ -708,9 +706,7 @@ module.exports = class Response extends Writable {
|
|
|
708
706
|
let ct = type.indexOf('/') === -1
|
|
709
707
|
? (mime.contentType(type) || 'application/octet-stream')
|
|
710
708
|
: type;
|
|
711
|
-
|
|
712
|
-
ct += '; charset=UTF-8';
|
|
713
|
-
}
|
|
709
|
+
|
|
714
710
|
return this.set('content-type', ct);
|
|
715
711
|
}
|
|
716
712
|
contentType(type) {
|
|
@@ -784,4 +780,4 @@ function pipeStreamOverResponse(res, readStream, totalSize, callback) {
|
|
|
784
780
|
if(res.socketExists) res.socket.emit('error', e);
|
|
785
781
|
}
|
|
786
782
|
});
|
|
787
|
-
}
|
|
783
|
+
}
|
package/src/router.js
CHANGED
|
@@ -18,6 +18,7 @@ const { patternToRegex, needsConversionToRegex, deprecated, findIndexStartingFro
|
|
|
18
18
|
const Response = require("./response.js");
|
|
19
19
|
const Request = require("./request.js");
|
|
20
20
|
const { EventEmitter } = require("tseep");
|
|
21
|
+
const { NullObject } = require("./utils.js");
|
|
21
22
|
|
|
22
23
|
let routeKey = 0;
|
|
23
24
|
|
|
@@ -268,7 +269,7 @@ module.exports = class Router extends EventEmitter {
|
|
|
268
269
|
const fn = async (res, req) => {
|
|
269
270
|
const { request, response } = this.handleRequest(res, req);
|
|
270
271
|
if(route.optimizedParams) {
|
|
271
|
-
request.optimizedParams =
|
|
272
|
+
request.optimizedParams = new NullObject();
|
|
272
273
|
for(let i = 0; i < route.optimizedParams.length; i++) {
|
|
273
274
|
request.optimizedParams[route.optimizedParams[i]] = req.getParameter(i);
|
|
274
275
|
}
|
|
@@ -319,7 +320,7 @@ module.exports = class Router extends EventEmitter {
|
|
|
319
320
|
|
|
320
321
|
_extractParams(pattern, path) {
|
|
321
322
|
let match = pattern.exec(path);
|
|
322
|
-
const obj = match?.groups ??
|
|
323
|
+
const obj = match?.groups ?? new NullObject();
|
|
323
324
|
for(let i = 1; i < match.length; i++) {
|
|
324
325
|
obj[i - 1] = match[i];
|
|
325
326
|
}
|
|
@@ -342,7 +343,7 @@ module.exports = class Router extends EventEmitter {
|
|
|
342
343
|
}
|
|
343
344
|
}
|
|
344
345
|
} else {
|
|
345
|
-
req.params =
|
|
346
|
+
req.params = new NullObject();
|
|
346
347
|
if(req._paramStack.length > 0) {
|
|
347
348
|
for(let params of req._paramStack) {
|
|
348
349
|
req.params = {...params, ...req.params};
|
|
@@ -485,7 +486,12 @@ module.exports = class Router extends EventEmitter {
|
|
|
485
486
|
const out = callback(req, res, next);
|
|
486
487
|
if(out instanceof Promise) {
|
|
487
488
|
out.catch(err => {
|
|
488
|
-
|
|
489
|
+
if(this.get("catch async errors")) {
|
|
490
|
+
this._handleError(err, req, res);
|
|
491
|
+
return resolve(true);
|
|
492
|
+
} else {
|
|
493
|
+
throw err;
|
|
494
|
+
}
|
|
489
495
|
});
|
|
490
496
|
}
|
|
491
497
|
} catch(err) {
|
|
@@ -528,7 +534,7 @@ module.exports = class Router extends EventEmitter {
|
|
|
528
534
|
}
|
|
529
535
|
|
|
530
536
|
route(path) {
|
|
531
|
-
let fns =
|
|
537
|
+
let fns = new NullObject();
|
|
532
538
|
for(let method of methods) {
|
|
533
539
|
fns[method] = (...callbacks) => {
|
|
534
540
|
return this.createRoute(method.toUpperCase(), path, fns, ...callbacks);
|
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
declare module "ultimate-express" {
|
|
2
|
+
import e from "@types/express";
|
|
3
|
+
import { AppOptions } from "uWebSockets.js";
|
|
4
|
+
|
|
5
|
+
type Settings = {
|
|
6
|
+
uwsOptions?: AppOptions;
|
|
7
|
+
threads?: number;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
namespace express {
|
|
11
|
+
export import json = e.json;
|
|
12
|
+
export import raw = e.raw;
|
|
13
|
+
export import text = e.text;
|
|
14
|
+
|
|
15
|
+
// export import application = e.application;
|
|
16
|
+
export import request = e.request;
|
|
17
|
+
export import response = e.response;
|
|
18
|
+
|
|
19
|
+
export import static = e.static;
|
|
20
|
+
// export import query = e.query;
|
|
21
|
+
|
|
22
|
+
export import urlencoded = e.urlencoded;
|
|
23
|
+
|
|
24
|
+
export import RouterOptions = e.RouterOptions;
|
|
25
|
+
export import Application = e.Application;
|
|
26
|
+
export import CookieOptions = e.CookieOptions;
|
|
27
|
+
export import Errback = e.Errback;
|
|
28
|
+
export import ErrorRequestHandler = e.ErrorRequestHandler;
|
|
29
|
+
export import Express = e.Express;
|
|
30
|
+
export import Handler = e.Handler;
|
|
31
|
+
export import IRoute = e.IRoute;
|
|
32
|
+
export import IRouter = e.IRouter;
|
|
33
|
+
export import IRouterHandler = e.IRouterHandler;
|
|
34
|
+
export import IRouterMatcher = e.IRouterMatcher;
|
|
35
|
+
export import MediaType = e.MediaType;
|
|
36
|
+
export import NextFunction = e.NextFunction;
|
|
37
|
+
export import Locals = e.Locals;
|
|
38
|
+
export import Request = e.Request;
|
|
39
|
+
export import RequestHandler = e.RequestHandler;
|
|
40
|
+
export import RequestParamHandler = e.RequestParamHandler;
|
|
41
|
+
export import Response = e.Response;
|
|
42
|
+
export import Router = e.Router;
|
|
43
|
+
export import Send = e.Send;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function express(settings?: Settings): e.Express;
|
|
47
|
+
|
|
48
|
+
export = express;
|
|
49
|
+
}
|
package/src/utils.js
CHANGED
|
@@ -315,6 +315,10 @@ function isRangeFresh(req, res) {
|
|
|
315
315
|
return parseHttpDate(lastModified) <= parseHttpDate(ifRange);
|
|
316
316
|
}
|
|
317
317
|
|
|
318
|
+
// fast null object
|
|
319
|
+
const NullObject = function() {};
|
|
320
|
+
NullObject.prototype = Object.create(null);
|
|
321
|
+
|
|
318
322
|
module.exports = {
|
|
319
323
|
removeDuplicateSlashes,
|
|
320
324
|
patternToRegex,
|
|
@@ -326,6 +330,7 @@ module.exports = {
|
|
|
326
330
|
compileTrust,
|
|
327
331
|
deprecated,
|
|
328
332
|
UP_PATH_REGEXP,
|
|
333
|
+
NullObject,
|
|
329
334
|
decode,
|
|
330
335
|
containsDotFile,
|
|
331
336
|
parseTokenList,
|
package/src/view.js
CHANGED
|
@@ -16,11 +16,12 @@ limitations under the License.
|
|
|
16
16
|
|
|
17
17
|
const path = require("path");
|
|
18
18
|
const fs = require("fs");
|
|
19
|
+
const { NullObject } = require("./utils.js");
|
|
19
20
|
|
|
20
21
|
module.exports = class View {
|
|
21
22
|
constructor(name, options) {
|
|
22
23
|
this.name = name;
|
|
23
|
-
this.options = options ? Object.assign({}, options) :
|
|
24
|
+
this.options = options ? Object.assign({}, options) : new NullObject();
|
|
24
25
|
this.defaultEngine = options.defaultEngine;
|
|
25
26
|
this.ext = path.extname(name);
|
|
26
27
|
this.root = options.root;
|