ultimate-express 2.1.0 → 2.1.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 +3 -1
- package/package.json +6 -5
- package/src/request.js +23 -33
package/README.md
CHANGED
|
@@ -8,10 +8,12 @@ To make sure µExpress matches behavior of Express in all cases, we run all test
|
|
|
8
8
|
|
|
9
9
|
`npm install ultimate-express` -> replace `express` with `ultimate-express` -> done[*](https://github.com/dimdenGD/ultimate-express?tab=readme-ov-file#differences-from-express)
|
|
10
10
|
|
|
11
|
-
[](https://nodejs.org)
|
|
12
12
|
[](https://npmjs.com/package/ultimate-express)
|
|
13
13
|
[](https://patreon.com/dimdendev)
|
|
14
14
|
|
|
15
|
+
> Use `npm install ultimate-express@2.1.0` to install last version that supported Node.js v21, v20 and v19.
|
|
16
|
+
|
|
15
17
|
> Use `npm install ultimate-express@node-v18` to install last version that supported Node.js v18.
|
|
16
18
|
|
|
17
19
|
## Difference from similar projects
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ultimate-express",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.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": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"cover:report": "nyc report --reporter=html"
|
|
13
13
|
},
|
|
14
14
|
"engines": {
|
|
15
|
-
"node": ">=
|
|
15
|
+
"node": ">=22"
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"src",
|
|
@@ -64,12 +64,12 @@
|
|
|
64
64
|
"statuses": "^2.0.2",
|
|
65
65
|
"tseep": "^1.3.1",
|
|
66
66
|
"type-is": "^2.0.1",
|
|
67
|
-
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.
|
|
67
|
+
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.67.0",
|
|
68
68
|
"vary": "^1.1.2"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@codechecks/client": "^0.1.12",
|
|
72
|
-
"@types/node": "^25.
|
|
72
|
+
"@types/node": "^25.6.0",
|
|
73
73
|
"better-sse": "^0.16.1",
|
|
74
74
|
"body-parser": "^2.2.2",
|
|
75
75
|
"compression": "^1.8.1",
|
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
"eventsource": "^4.1.0",
|
|
82
82
|
"exit-hook": "^2.2.1",
|
|
83
83
|
"express": "latest-4",
|
|
84
|
+
"express5": "npm:express@5",
|
|
84
85
|
"express-art-template": "^1.0.1",
|
|
85
86
|
"express-async-errors": "^3.1.1",
|
|
86
87
|
"express-dot-engine": "^1.0.8",
|
|
@@ -88,7 +89,7 @@
|
|
|
88
89
|
"express-handlebars": "^8.0.7",
|
|
89
90
|
"express-http-proxy": "^2.1.2",
|
|
90
91
|
"express-mongo-sanitize": "^2.2.0",
|
|
91
|
-
"express-rate-limit": "^8.
|
|
92
|
+
"express-rate-limit": "^8.4.0",
|
|
92
93
|
"express-session": "^1.19.0",
|
|
93
94
|
"express-subdomain": "^1.0.6",
|
|
94
95
|
"graphql-http": "^1.22.4",
|
package/src/request.js
CHANGED
|
@@ -38,16 +38,14 @@ module.exports = class Request extends Readable {
|
|
|
38
38
|
#cachedDistinctHeaders = null;
|
|
39
39
|
#rawHeadersEntries = [];
|
|
40
40
|
#cachedParsedIp = null;
|
|
41
|
-
#
|
|
42
|
-
#doneReadingData = false;
|
|
43
|
-
#bufferedData = null;
|
|
41
|
+
#paused = false;
|
|
44
42
|
body;
|
|
45
43
|
res;
|
|
46
44
|
optimizedParams;
|
|
47
45
|
_error;
|
|
48
46
|
noEtag;
|
|
49
47
|
constructor(req, res, app) {
|
|
50
|
-
super();
|
|
48
|
+
super({ highWaterMark: 128 * 1024 });
|
|
51
49
|
this._res = res;
|
|
52
50
|
this._req = req;
|
|
53
51
|
this.readable = true;
|
|
@@ -100,46 +98,38 @@ module.exports = class Request extends Readable {
|
|
|
100
98
|
this.method === 'PATCH' ||
|
|
101
99
|
(additionalMethods && additionalMethods.includes(this.method))
|
|
102
100
|
) {
|
|
103
|
-
this.#bufferedData = Buffer.allocUnsafe(0);
|
|
104
101
|
this._res.onData((ab, isLast) => {
|
|
105
|
-
// make stream actually readable
|
|
106
102
|
this.receivedData = true;
|
|
107
|
-
if(
|
|
108
|
-
|
|
103
|
+
if(this.#responseEnded) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
// ab.slice(0) copies the ArrayBuffer; uWS neuters `ab` after this callback,
|
|
107
|
+
// so a Buffer.from(ab) view would corrupt data left in the Readable queue.
|
|
108
|
+
const chunk = Buffer.from(ab.slice(0));
|
|
109
|
+
const accepted = this.push(chunk);
|
|
110
|
+
// push() may synchronously end the response via a flowing-mode listener.
|
|
111
|
+
if(!accepted && !isLast && !this.#responseEnded) {
|
|
112
|
+
this._res.pause();
|
|
113
|
+
this.#paused = true;
|
|
109
114
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const chunk = Buffer.from(ab);
|
|
113
|
-
this.#bufferedData = Buffer.concat([this.#bufferedData, chunk]);
|
|
114
|
-
|
|
115
|
-
if(this.#needsData) {
|
|
116
|
-
this.#needsData = false;
|
|
117
|
-
this._read();
|
|
115
|
+
if(isLast) {
|
|
116
|
+
this.push(null);
|
|
118
117
|
}
|
|
119
118
|
});
|
|
120
119
|
} else {
|
|
121
120
|
this.receivedData = true;
|
|
122
|
-
|
|
123
|
-
// to ensure pipe() works correctly
|
|
124
|
-
this.#bufferedData = Buffer.allocUnsafe(0);
|
|
125
|
-
this.#doneReadingData = true;
|
|
121
|
+
this.push(null);
|
|
126
122
|
}
|
|
127
123
|
}
|
|
128
124
|
|
|
125
|
+
get #responseEnded() {
|
|
126
|
+
return this.res?.finished || this.res?.aborted;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
129
|
_read() {
|
|
130
|
-
if(
|
|
131
|
-
this.#
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
if(this.#bufferedData.length > 0) {
|
|
135
|
-
// push 128kb chunks
|
|
136
|
-
const chunk = this.#bufferedData.subarray(0, 1024 * 128);
|
|
137
|
-
this.#bufferedData = this.#bufferedData.subarray(1024 * 128);
|
|
138
|
-
this.push(chunk);
|
|
139
|
-
} else if(this.#doneReadingData) {
|
|
140
|
-
this.push(null);
|
|
141
|
-
} else {
|
|
142
|
-
this.#needsData = true;
|
|
130
|
+
if(this.#paused && !this.#responseEnded) {
|
|
131
|
+
this.#paused = false;
|
|
132
|
+
this._res.resume();
|
|
143
133
|
}
|
|
144
134
|
}
|
|
145
135
|
|