fulmine.js 5.21.0 → 5.21.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/package.json +2 -2
- package/src/application.js +37 -11
- package/src/declarative.js +2 -3
- package/src/index.js +0 -12
- package/src/router.js +4 -2
- package/src/types.d.ts +11 -1
- package/src/uws.js +45 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fulmine.js",
|
|
3
|
-
"version": "5.21.
|
|
3
|
+
"version": "5.21.1",
|
|
4
4
|
"description": "Drop-in Express 5 replacement on uWebSockets.js, up to 20x faster. Same API, your middleware and framework keep working.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
"statuses": "^2.0.2",
|
|
117
117
|
"tseep": "^1.3.1",
|
|
118
118
|
"type-is": "^2.1.0",
|
|
119
|
-
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.
|
|
119
|
+
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.71.0",
|
|
120
120
|
"vary": "^1.1.2"
|
|
121
121
|
},
|
|
122
122
|
"peerDependencies": {
|
package/src/application.js
CHANGED
|
@@ -17,7 +17,7 @@ See the License for the specific language governing permissions and
|
|
|
17
17
|
limitations under the License.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
const
|
|
20
|
+
const { loadUWS } = require("./uws.js");
|
|
21
21
|
const Router = require("./router.js");
|
|
22
22
|
const {
|
|
23
23
|
removeDuplicateSlashes,
|
|
@@ -59,7 +59,10 @@ class FSWorker {
|
|
|
59
59
|
*/
|
|
60
60
|
constructor() {
|
|
61
61
|
this.busy = false;
|
|
62
|
-
|
|
62
|
+
// its own execArgv, not the parent thread's: a worker inherits them, and a --require or
|
|
63
|
+
// --import written for the parent (Angular's route extraction registers a loader that reads
|
|
64
|
+
// workerData) throws inside a thread that only reads files
|
|
65
|
+
this.worker = new Worker(path.join(__dirname, "worker.js"), { execArgv: [] });
|
|
63
66
|
|
|
64
67
|
this.worker.on("message", (message) => {
|
|
65
68
|
// node speaks on this channel too: under --watch a worker reports the files it loaded
|
|
@@ -113,6 +116,15 @@ class Application extends Router {
|
|
|
113
116
|
*/
|
|
114
117
|
_testingCompiled;
|
|
115
118
|
|
|
119
|
+
/**
|
|
120
|
+
* The uWS app once made, or the one settings.uwsApp handed in. See the uwsApp getter.
|
|
121
|
+
* @type {any}
|
|
122
|
+
*/
|
|
123
|
+
_uwsApp;
|
|
124
|
+
|
|
125
|
+
/** What uWS.App or uWS.SSLApp is given, kept until the app is made. */
|
|
126
|
+
_uwsOptions;
|
|
127
|
+
|
|
116
128
|
/**
|
|
117
129
|
* @param {object} [settings] the options express() takes. uwsOptions goes to uWS and decides
|
|
118
130
|
* between an HTTP, an HTTPS and an HTTP/3 server; threads sizes the file-reading pool, and 0
|
|
@@ -135,9 +147,7 @@ class Application extends Router {
|
|
|
135
147
|
if (this._clusterWorkers > 0 && cluster.isPrimary) {
|
|
136
148
|
becomeSupervisor();
|
|
137
149
|
}
|
|
138
|
-
if (settings.
|
|
139
|
-
this.uwsApp = /** @type {import("uWebSockets.js").TemplatedApp} */ (settings.uwsApp);
|
|
140
|
-
} else if (settings.http3) {
|
|
150
|
+
if (settings.http3) {
|
|
141
151
|
// uWS.H3App exists in the pinned build but its QUIC stack does not: the constructor
|
|
142
152
|
// segfaults on Linux and hangs forever on Windows before serving a single request,
|
|
143
153
|
// verified 2026-08-05 with uWS alone. A clear throw beats a native crash; this
|
|
@@ -146,12 +156,12 @@ class Application extends Router {
|
|
|
146
156
|
"http3 is not usable with the pinned uWebSockets.js build: its H3App crashes " +
|
|
147
157
|
"during construction. Track uNetworking/uWebSockets.js for working QUIC support."
|
|
148
158
|
);
|
|
149
|
-
} else if (settings.uwsOptions.key_file_name && settings.uwsOptions.cert_file_name) {
|
|
150
|
-
this.uwsApp = uWS.SSLApp(settings.uwsOptions);
|
|
151
|
-
} else {
|
|
152
|
-
this.uwsApp = uWS.App(settings.uwsOptions);
|
|
153
159
|
}
|
|
154
160
|
this.ssl = settings.uwsOptions.key_file_name && settings.uwsOptions.cert_file_name;
|
|
161
|
+
// the uWS app is made on first use, see the uwsApp getter: what listen(), ws() and the
|
|
162
|
+
// optimizer need, and what an app served through node's http never asks for
|
|
163
|
+
this._uwsApp = settings.uwsApp;
|
|
164
|
+
this._uwsOptions = settings.uwsOptions;
|
|
155
165
|
this.cache = new NullObject();
|
|
156
166
|
this.engines = { __proto__: null };
|
|
157
167
|
// a null prototype, as express gives app.locals, so a local named like an Object method
|
|
@@ -509,6 +519,22 @@ class Application extends Router {
|
|
|
509
519
|
return request;
|
|
510
520
|
}
|
|
511
521
|
|
|
522
|
+
/**
|
|
523
|
+
* The µWS app underneath, for anything µWS offers that this does not: socket.io attaches to
|
|
524
|
+
* it. Made the first time it is asked for, so an application that only ever answers through
|
|
525
|
+
* node's http, a test through supertest or Angular's build extracting routes in a worker
|
|
526
|
+
* thread, never loads the binary. See src/uws.js for why that matters.
|
|
527
|
+
*
|
|
528
|
+
* @returns {any}
|
|
529
|
+
*/
|
|
530
|
+
get uwsApp() {
|
|
531
|
+
if (this._uwsApp === undefined) {
|
|
532
|
+
const uWS = loadUWS();
|
|
533
|
+
this._uwsApp = this.ssl ? uWS.SSLApp(this._uwsOptions) : uWS.App(this._uwsOptions);
|
|
534
|
+
}
|
|
535
|
+
return this._uwsApp;
|
|
536
|
+
}
|
|
537
|
+
|
|
512
538
|
/**
|
|
513
539
|
* Registers the catch-all uWS handler, which is what serves every request that no optimized
|
|
514
540
|
* route took natively. It walks this app's own chain and, when nothing in it answered, decides
|
|
@@ -617,7 +643,7 @@ class Application extends Router {
|
|
|
617
643
|
// listen() returns. The callback is not: running it here would run it before listen()
|
|
618
644
|
// had returned, and `const server = app.listen(p, () => server.address())` - the form
|
|
619
645
|
// the Express docs use - would die on the temporal dead zone.
|
|
620
|
-
this.port =
|
|
646
|
+
this.port = loadUWS().us_socket_local_port(socket);
|
|
621
647
|
this.listening = true;
|
|
622
648
|
this._listenHost = host;
|
|
623
649
|
// kept so close() can stop accepting without dropping what is in flight
|
|
@@ -888,7 +914,7 @@ class Application extends Router {
|
|
|
888
914
|
return this;
|
|
889
915
|
}
|
|
890
916
|
if (this._listenSocket) {
|
|
891
|
-
|
|
917
|
+
loadUWS().us_listen_socket_close(this._listenSocket);
|
|
892
918
|
this._listenSocket = undefined;
|
|
893
919
|
}
|
|
894
920
|
this._draining = true;
|
package/src/declarative.js
CHANGED
|
@@ -21,8 +21,7 @@ const acorn = require("acorn");
|
|
|
21
21
|
const { stringify, contentTypeSet, withUtf8Charset, contentTypeFor, headerIsWritable } = require("./utils.js");
|
|
22
22
|
// H3App, DeclarativeResponse and _cfg exist at runtime but are missing from the .d.ts the
|
|
23
23
|
// package ships, so the module is read through a loose alias
|
|
24
|
-
const
|
|
25
|
-
const uWSAny = /** @type {any} */ (uWS);
|
|
24
|
+
const { loadUWS } = require("./uws.js");
|
|
26
25
|
const statuses = require("statuses");
|
|
27
26
|
|
|
28
27
|
/** @typedef {import("./application.js").Application} Application */
|
|
@@ -836,7 +835,7 @@ module.exports = function compileDeclarative(cb, app) {
|
|
|
836
835
|
return false;
|
|
837
836
|
}
|
|
838
837
|
|
|
839
|
-
let decRes = new
|
|
838
|
+
let decRes = new (loadUWS().DeclarativeResponse)();
|
|
840
839
|
|
|
841
840
|
if (statusCode !== 200) {
|
|
842
841
|
const statusMessage = statuses.message[statusCode] ?? "unknown";
|
package/src/index.js
CHANGED
|
@@ -17,11 +17,6 @@ See the License for the specific language governing permissions and
|
|
|
17
17
|
limitations under the License.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
// H3App, DeclarativeResponse and _cfg exist at runtime but are missing from the .d.ts the
|
|
21
|
-
// package ships, so the module is read through a loose alias
|
|
22
|
-
const uWS = require("uWebSockets.js");
|
|
23
|
-
const uWSAny = /** @type {any} */ (uWS);
|
|
24
|
-
|
|
25
20
|
// A project on pnpm owns the uWebSockets.js dependency itself, see `npx fulmine.js pnpm`, so the
|
|
26
21
|
// one installed can drift from the one this package pins and was tested against. Said once, at
|
|
27
22
|
// require time, where it reaches every deployment rather than only the ones that run verify.
|
|
@@ -50,13 +45,6 @@ const middlewares = require("./middlewares.js");
|
|
|
50
45
|
const Request = require("./request.js");
|
|
51
46
|
const Response = require("./response.js");
|
|
52
47
|
|
|
53
|
-
try {
|
|
54
|
-
// disable Uwebsockets header
|
|
55
|
-
uWSAny._cfg("999999990007");
|
|
56
|
-
} catch (error) {
|
|
57
|
-
// older uWS builds do not expose _cfg; there is nothing to fall back to
|
|
58
|
-
}
|
|
59
|
-
|
|
60
48
|
try {
|
|
61
49
|
// the compile cache, node 22.8 and up: the next boot skips compiling the same code. Respects
|
|
62
50
|
// NODE_DISABLE_COMPILE_CACHE, and booting without a cache is not an error
|
package/src/router.js
CHANGED
|
@@ -100,9 +100,11 @@ module.exports = class Router extends EventEmitter {
|
|
|
100
100
|
* it have already established that, so the honest `TemplatedApp|undefined` would only add
|
|
101
101
|
* casts where the guard already is.
|
|
102
102
|
*
|
|
103
|
-
* @
|
|
103
|
+
* @returns {any}
|
|
104
104
|
*/
|
|
105
|
-
uwsApp
|
|
105
|
+
get uwsApp() {
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
106
108
|
|
|
107
109
|
/**
|
|
108
110
|
* Whether an unset routing flag reads on through the mount parent. Only an application does,
|
package/src/types.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ declare module "fulmine.js" {
|
|
|
18
18
|
import e from "express";
|
|
19
19
|
import uWS from "uWebSockets.js";
|
|
20
20
|
import { ZlibOptions, BrotliOptions } from "zlib";
|
|
21
|
+
import serveStatic = require("serve-static");
|
|
21
22
|
|
|
22
23
|
type Settings = {
|
|
23
24
|
uwsOptions?: uWS.AppOptions;
|
|
@@ -36,7 +37,16 @@ declare module "fulmine.js" {
|
|
|
36
37
|
export import request = e.request;
|
|
37
38
|
export import response = e.response;
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
/** serve-static's options plus preCompressed, which is this project's. */
|
|
41
|
+
interface StaticOptions extends serveStatic.ServeStaticOptions<e.Response> {
|
|
42
|
+
/**
|
|
43
|
+
* Serve `file.br` or `file.gz` in place of `file` when one is on disk and the client
|
|
44
|
+
* takes it. Off by default. Which twins a path has is remembered for a second;
|
|
45
|
+
* `{ cache: false }` asks the disk every time, a duration sets how long.
|
|
46
|
+
*/
|
|
47
|
+
preCompressed?: boolean | { cache?: number | string | false };
|
|
48
|
+
}
|
|
49
|
+
function static(root: string, options?: StaticOptions): e.RequestHandler;
|
|
40
50
|
// export import query = e.query;
|
|
41
51
|
|
|
42
52
|
// express has no compression middleware, so there is nothing to re-export: these are the
|
package/src/uws.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2024 dimden.dev
|
|
3
|
+
Copyright 2026 Nigro Simone
|
|
4
|
+
|
|
5
|
+
This file is derived from Ultimate Express and has been modified.
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
|
|
17
|
+
// µWebSockets.js, loaded the first time something needs it rather than when this package is
|
|
18
|
+
// required. An application that is built and never listens never loads the binary. Angular's
|
|
19
|
+
// build imports server.ts in a worker thread to extract the routes and serves it through node's
|
|
20
|
+
// http, and on Windows the binary crashes the process when a thread that loaded it exits
|
|
21
|
+
// (uNetworking/uWebSockets.js#668), so the build only works if nothing in that thread loads it.
|
|
22
|
+
|
|
23
|
+
/** @type {any} */
|
|
24
|
+
let uWS;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The µWS module. H3App, DeclarativeResponse and _cfg exist at runtime but are missing from the
|
|
28
|
+
* .d.ts the package ships, so it is handed back loosely typed.
|
|
29
|
+
*
|
|
30
|
+
* @returns {any}
|
|
31
|
+
*/
|
|
32
|
+
function loadUWS() {
|
|
33
|
+
if (uWS === undefined) {
|
|
34
|
+
uWS = /** @type {any} */ (require("uWebSockets.js"));
|
|
35
|
+
try {
|
|
36
|
+
// disable Uwebsockets header
|
|
37
|
+
uWS._cfg("999999990007");
|
|
38
|
+
} catch (error) {
|
|
39
|
+
// older uWS builds do not expose _cfg; there is nothing to fall back to
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return uWS;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports = { loadUWS };
|