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 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
- [![Node.js >= 20.0.0](https://img.shields.io/badge/Node.js-%3E=20.0.0-green)](https://nodejs.org)
11
+ [![Node.js >= 22.0.0](https://img.shields.io/badge/Node.js-%3E=22.0.0-green)](https://nodejs.org)
12
12
  [![npm](https://img.shields.io/npm/v/ultimate-express?label=last+version)](https://npmjs.com/package/ultimate-express)
13
13
  [![Patreon](https://img.shields.io/badge/donate-Patreon-orange)](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.0",
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": ">=20"
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.64.0",
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.5.2",
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.3.2",
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
- #needsData = false;
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(isLast) {
108
- this.#doneReadingData = true;
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
- // instead of pushing data immediately, buffer it
111
- // because writable streams cant handle the amount of data uWS gives (usually 512kb+)
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
- // For GET and other non-body methods, initialize bufferedData as empty buffer
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(!this.receivedData || !this.#bufferedData) {
131
- this.#needsData = true;
132
- return;
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