fulmine.js 5.1.8 → 5.1.9
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 +4 -2
- package/package.json +5 -3
- package/src/application.js +8 -7
- package/src/declarative.js +7 -0
- package/src/usage.js +7 -1
package/README.md
CHANGED
|
@@ -25,6 +25,7 @@ See [Migrating](#migrating) for what it handles and what it deliberately does no
|
|
|
25
25
|
|
|
26
26
|
[](https://www.npmjs.com/package/fulmine.js)
|
|
27
27
|
[](https://nodejs.org)
|
|
28
|
+
[](https://coveralls.io/github/nigrosimone/fulmine.js?branch=main)
|
|
28
29
|
[](./LICENSE)
|
|
29
30
|
|
|
30
31
|
## Why this exists
|
|
@@ -55,7 +56,7 @@ to run it yourself.
|
|
|
55
56
|
|
|
56
57
|
Numbers produced by a project about itself deserve suspicion, so Fulmine also stands in public arenas, run by their own rigs under their own rules:
|
|
57
58
|
|
|
58
|
-
- **[HttpArena](https://www.http-arena.com/#sort=rps:-1&q=Js)** (the link lands filtered on the JavaScript entries): first among the JavaScript entries
|
|
59
|
+
- **[HttpArena](https://www.http-arena.com/#sort=rps:-1&q=Js)** (the link lands filtered on the JavaScript entries): first among the JavaScript entries, across fifteen subscribed profiles. The saved runs measure 24.3 million WebSocket echoes per second pipelined and 3.77 million one-at-a-time (past Bun's own dedicated WebSocket entry), 7.3 million pipelined HTTP requests per second, 1.12 million on the json profile with 1.04 million of that surviving TLS, 457 thousand on compressed json, and 359 thousand on the Postgres CRUD profile, within ten percent of the leading Rust and C# entries there.
|
|
59
60
|
- **[web-frameworks](https://github.com/the-benchmarker/web-frameworks)**: entry merged, numbers arrive with their next published round.
|
|
60
61
|
|
|
61
62
|
More to come as their maintainers take the entries in.
|
|
@@ -226,9 +227,10 @@ which runs the same file against Express and against Fulmine and compares the ou
|
|
|
226
227
|
|
|
227
228
|
## HTTP/3
|
|
228
229
|
|
|
229
|
-
HTTP/3 is
|
|
230
|
+
There is an `http3: true` option, inherited from Ultimate Express, that asks µWebSockets.js for its experimental HTTP/3 app. **It is guarded off with the currently pinned µWS build**: asking for it throws a clear error, because the underlying `H3App` segfaults during construction on Linux, verified with µWS alone before a single request is served. On Windows the listener does come up, but nothing answers over QUIC that we could verify, and shipping an option that works on no deployable platform helps nobody. A skipped canary test probes `H3App` on every CI run and will turn red the day µWS ships working QUIC in its prebuilt binaries, which is when the guard goes and this section changes.
|
|
230
231
|
|
|
231
232
|
```js
|
|
233
|
+
// what it would look like, once µWS's H3 support actually works
|
|
232
234
|
const app = express({
|
|
233
235
|
http3: true,
|
|
234
236
|
uwsOptions: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fulmine.js",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.9",
|
|
4
4
|
"description": "Drop-in Express 5 replacement on uWebSockets.js. Your existing middleware keeps working.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"test:types": "tsd --files tests/types/*.test-d.ts",
|
|
14
14
|
"test:express": "node tools/express-suite.js",
|
|
15
15
|
"benchmark:compare": "node benchmark/run.js",
|
|
16
|
-
"cover": "npm run cover:
|
|
16
|
+
"cover": "npm run cover:full && npm run cover:report",
|
|
17
17
|
"cover:unit": "nyc --silent npm run test",
|
|
18
18
|
"cover:report": "nyc report --reporter=html",
|
|
19
19
|
"lint": "eslint .",
|
|
@@ -25,7 +25,9 @@
|
|
|
25
25
|
"typecheck": "tsc -p tsconfig.typecheck.json",
|
|
26
26
|
"benchmark:ab": "node benchmark/ab.js",
|
|
27
27
|
"benchmark:profile": "node benchmark/profile.js",
|
|
28
|
-
"release:local": "node tools/release-local.js"
|
|
28
|
+
"release:local": "node tools/release-local.js",
|
|
29
|
+
"cover:full": "nyc --silent npm run test && nyc --silent --no-clean npm run test:unit && nyc --silent --no-clean npm run test:express && nyc report",
|
|
30
|
+
"cover:check": "nyc check-coverage --statements 93 --branches 88 --functions 92 --lines 93"
|
|
29
31
|
},
|
|
30
32
|
"engines": {
|
|
31
33
|
"node": ">=22"
|
package/src/application.js
CHANGED
|
@@ -15,10 +15,7 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
// H3App, DeclarativeResponse and _cfg all exist at runtime but are missing from the
|
|
19
|
-
// declaration file the package ships, so the module is read through a loose alias
|
|
20
18
|
const uWS = require("uWebSockets.js");
|
|
21
|
-
const uWSAny = /** @type {any} */ (uWS);
|
|
22
19
|
const Router = require("./router.js");
|
|
23
20
|
const {
|
|
24
21
|
removeDuplicateSlashes,
|
|
@@ -102,10 +99,14 @@ class Application extends Router {
|
|
|
102
99
|
if (settings.uwsApp) {
|
|
103
100
|
this.uwsApp = settings.uwsApp;
|
|
104
101
|
} else if (settings.http3) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
102
|
+
// uWS.H3App exists in the pinned build but its QUIC stack does not: the constructor
|
|
103
|
+
// segfaults on Linux and hangs forever on Windows before serving a single request,
|
|
104
|
+
// verified 2026-08-05 with uWS alone. A clear throw beats a native crash; this
|
|
105
|
+
// branch goes back to H3App once uNetworking ships working QUIC in the prebuilts.
|
|
106
|
+
throw new Error(
|
|
107
|
+
"http3 is not usable with the pinned uWebSockets.js build: its H3App crashes " +
|
|
108
|
+
"during construction. Track uNetworking/uWebSockets.js for working QUIC support."
|
|
109
|
+
);
|
|
109
110
|
} else if (settings.uwsOptions.key_file_name && settings.uwsOptions.cert_file_name) {
|
|
110
111
|
this.uwsApp = uWS.SSLApp(settings.uwsOptions);
|
|
111
112
|
} else {
|
package/src/declarative.js
CHANGED
|
@@ -606,6 +606,13 @@ module.exports = function compileDeclarative(cb, app) {
|
|
|
606
606
|
}
|
|
607
607
|
}
|
|
608
608
|
|
|
609
|
+
// a handler that never sends is not a response: Express leaves the request waiting, so
|
|
610
|
+
// compiling the empty shape would answer a bare 200 where the ordinary path answers
|
|
611
|
+
// nothing at all. It has to fall back instead.
|
|
612
|
+
if (!sendUsed && !sendStatusUsed) {
|
|
613
|
+
return false;
|
|
614
|
+
}
|
|
615
|
+
|
|
609
616
|
let decRes = new uWSAny.DeclarativeResponse();
|
|
610
617
|
|
|
611
618
|
if (statusCode !== 200) {
|
package/src/usage.js
CHANGED
|
@@ -76,7 +76,13 @@ function callbackUsage(fn) {
|
|
|
76
76
|
|
|
77
77
|
/** @param {Function} fn @returns {number} */
|
|
78
78
|
function analyze(fn) {
|
|
79
|
-
|
|
79
|
+
// toString is application-controlled and may throw or answer anything: unreadable is unknown
|
|
80
|
+
let code;
|
|
81
|
+
try {
|
|
82
|
+
code = String(fn.toString());
|
|
83
|
+
} catch {
|
|
84
|
+
return UNKNOWN;
|
|
85
|
+
}
|
|
80
86
|
if (code.startsWith("function") || code.startsWith("async function")) {
|
|
81
87
|
code = code.replace(/function *\(/, "function __cb(");
|
|
82
88
|
}
|