fulmine.js 5.21.5 → 5.21.6
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 +1 -1
- package/src/index.js +0 -21
- package/src/node-shim.js +50 -12
- package/src/uws.js +25 -0
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -17,27 +17,6 @@ See the License for the specific language governing permissions and
|
|
|
17
17
|
limitations under the License.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
// A project on pnpm owns the uWebSockets.js dependency itself, see `npx fulmine.js pnpm`, so the
|
|
21
|
-
// one installed can drift from the one this package pins and was tested against. Said once, at
|
|
22
|
-
// require time, where it reaches every deployment rather than only the ones that run verify.
|
|
23
|
-
{
|
|
24
|
-
const pinned = /#v?([\d.]+)$/.exec(require("../package.json").dependencies["uWebSockets.js"])?.[1];
|
|
25
|
-
/** @type {string|undefined} */
|
|
26
|
-
let installed;
|
|
27
|
-
try {
|
|
28
|
-
// its exports map does not expose package.json, so it is read beside the entry point
|
|
29
|
-
const beside = require("path").join(require.resolve("uWebSockets.js"), "..", "package.json");
|
|
30
|
-
installed = JSON.parse(require("fs").readFileSync(beside, "utf8")).version;
|
|
31
|
-
} catch {
|
|
32
|
-
// nothing to compare against, which is not worth a warning of its own
|
|
33
|
-
}
|
|
34
|
-
if (pinned && installed && installed !== pinned) {
|
|
35
|
-
console.warn(
|
|
36
|
-
`fulmine.js: uWebSockets.js ${installed} is installed, this version was tested with ${pinned}.\n` +
|
|
37
|
-
" On pnpm the pin is the project's own: `npx fulmine.js pnpm` writes the tested one."
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
20
|
const Application = require("./application.js");
|
|
42
21
|
const Router = require("./router.js");
|
|
43
22
|
const Route = require("./route.js");
|
package/src/node-shim.js
CHANGED
|
@@ -15,14 +15,36 @@ limitations under the License.
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
// A uWS-shaped request and response over node's own, for supertest and http.createServer(app).
|
|
18
|
-
// Not fast
|
|
19
|
-
// callback, a status is kept until the first
|
|
18
|
+
// Not the fast path, app.listen() is, but about 1.5x Express on a hello world on Linux. Where the
|
|
19
|
+
// models disagree node's gives way: cork only runs its callback, a status is kept until the first
|
|
20
|
+
// byte of body
|
|
20
21
|
|
|
21
22
|
const { IncomingMessage } = require("http");
|
|
23
|
+
const { HEADER_NAME_BUF, HEADER_VALUE_BUF } = require("./response-utils.js");
|
|
22
24
|
|
|
23
25
|
/** What µWS returns for an address nobody declared. */
|
|
24
26
|
const emptyAddress = new ArrayBuffer(0);
|
|
25
27
|
|
|
28
|
+
// The strings behind the Buffers writeHeaders hands over for the recurring names and values.
|
|
29
|
+
// Decoded on every response they gave node a new string to check, lowercase and hash each time
|
|
30
|
+
/** @type {Map<unknown, string>} */
|
|
31
|
+
const HEADER_TEXT = new Map();
|
|
32
|
+
for (const cache of [HEADER_NAME_BUF, HEADER_VALUE_BUF]) {
|
|
33
|
+
for (const text in cache) {
|
|
34
|
+
HEADER_TEXT.set(cache[text], text);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* A header name or value as node's appendHeader takes it.
|
|
40
|
+
*
|
|
41
|
+
* @param {unknown} part
|
|
42
|
+
* @returns {string}
|
|
43
|
+
*/
|
|
44
|
+
function headerText(part) {
|
|
45
|
+
return typeof part === "string" ? part : (HEADER_TEXT.get(part) ?? String(part));
|
|
46
|
+
}
|
|
47
|
+
|
|
26
48
|
/**
|
|
27
49
|
* An IP address as the four or sixteen bytes uWS hands over; unreadable comes back empty.
|
|
28
50
|
*
|
|
@@ -93,6 +115,22 @@ function toArrayBuffer(chunk) {
|
|
|
93
115
|
return /** @type {ArrayBuffer} */ (buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength));
|
|
94
116
|
}
|
|
95
117
|
|
|
118
|
+
/**
|
|
119
|
+
* A body chunk as node's write takes it: a string goes as it is and node encodes it once, with
|
|
120
|
+
* the head, anything else is copied as toArrayBuffer does.
|
|
121
|
+
*
|
|
122
|
+
* @param {ArrayBuffer|Buffer|string} chunk
|
|
123
|
+
* @returns {Buffer|string}
|
|
124
|
+
*/
|
|
125
|
+
function toNodeChunk(chunk) {
|
|
126
|
+
return typeof chunk === "string" ? chunk : Buffer.from(toArrayBuffer(chunk));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** @param {Buffer|string} chunk */
|
|
130
|
+
function byteLength(chunk) {
|
|
131
|
+
return typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.length;
|
|
132
|
+
}
|
|
133
|
+
|
|
96
134
|
/** uWS's HttpRequest over node's IncomingMessage. */
|
|
97
135
|
class NodeHttpRequest {
|
|
98
136
|
/** @type {import("http").IncomingMessage} */
|
|
@@ -241,16 +279,16 @@ class NodeHttpResponse {
|
|
|
241
279
|
writeHeader(key, value) {
|
|
242
280
|
if (!this._nodeRes.headersSent) {
|
|
243
281
|
// writeHeaders hands the recurring names and values over as Buffers
|
|
244
|
-
this._nodeRes.appendHeader(
|
|
282
|
+
this._nodeRes.appendHeader(headerText(key), headerText(value));
|
|
245
283
|
}
|
|
246
284
|
return this;
|
|
247
285
|
}
|
|
248
286
|
|
|
249
287
|
/** @param {ArrayBuffer|Buffer|string} chunk @returns {boolean} false when the socket is full */
|
|
250
288
|
write(chunk) {
|
|
251
|
-
const
|
|
252
|
-
this._offset +=
|
|
253
|
-
return this._nodeRes.write(
|
|
289
|
+
const data = toNodeChunk(chunk);
|
|
290
|
+
this._offset += byteLength(data);
|
|
291
|
+
return this._nodeRes.write(data);
|
|
254
292
|
}
|
|
255
293
|
|
|
256
294
|
/** @param {ArrayBuffer|Buffer|string} [body] */
|
|
@@ -262,9 +300,9 @@ class NodeHttpResponse {
|
|
|
262
300
|
this._nodeRes.end();
|
|
263
301
|
return this;
|
|
264
302
|
}
|
|
265
|
-
const
|
|
266
|
-
this._offset +=
|
|
267
|
-
this._nodeRes.end(
|
|
303
|
+
const data = toNodeChunk(body);
|
|
304
|
+
this._offset += byteLength(data);
|
|
305
|
+
this._nodeRes.end(data);
|
|
268
306
|
return this;
|
|
269
307
|
}
|
|
270
308
|
|
|
@@ -298,9 +336,9 @@ class NodeHttpResponse {
|
|
|
298
336
|
if (!this._nodeRes.headersSent && !this._nodeRes.hasHeader("Content-Length")) {
|
|
299
337
|
this._nodeRes.setHeader("Content-Length", String(totalSize));
|
|
300
338
|
}
|
|
301
|
-
const
|
|
302
|
-
const ok = this._nodeRes.write(
|
|
303
|
-
this._offset +=
|
|
339
|
+
const data = toNodeChunk(chunk);
|
|
340
|
+
const ok = this._nodeRes.write(data);
|
|
341
|
+
this._offset += byteLength(data);
|
|
304
342
|
const done = this._offset >= totalSize;
|
|
305
343
|
if (done) {
|
|
306
344
|
this._nodeRes.end();
|
package/src/uws.js
CHANGED
|
@@ -21,6 +21,30 @@ limitations under the License.
|
|
|
21
21
|
/** @type {any} */
|
|
22
22
|
let uWS;
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* A project on pnpm owns the uWebSockets.js dependency itself, see `npx fulmine.js pnpm`, so the
|
|
26
|
+
* one installed can drift from the one this package pins and was tested against. Said once, when
|
|
27
|
+
* it is loaded: an app served through node's http never loads it and has nothing to hear.
|
|
28
|
+
*/
|
|
29
|
+
function warnOnDrift() {
|
|
30
|
+
const pinned = /#v?([\d.]+)$/.exec(require("../package.json").dependencies["uWebSockets.js"])?.[1];
|
|
31
|
+
/** @type {string|undefined} */
|
|
32
|
+
let installed;
|
|
33
|
+
try {
|
|
34
|
+
// its exports map does not expose package.json, so it is read beside the entry point
|
|
35
|
+
const beside = require("path").join(require.resolve("uWebSockets.js"), "..", "package.json");
|
|
36
|
+
installed = JSON.parse(require("fs").readFileSync(beside, "utf8")).version;
|
|
37
|
+
} catch {
|
|
38
|
+
// nothing to compare against, which is not worth a warning of its own
|
|
39
|
+
}
|
|
40
|
+
if (pinned && installed && installed !== pinned) {
|
|
41
|
+
console.warn(
|
|
42
|
+
`fulmine.js: uWebSockets.js ${installed} is installed, this version was tested with ${pinned}.\n` +
|
|
43
|
+
" On pnpm the pin is the project's own: `npx fulmine.js pnpm` writes the tested one."
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
24
48
|
/**
|
|
25
49
|
* The µWS module. H3App, DeclarativeResponse and _cfg exist at runtime but are missing from the
|
|
26
50
|
* .d.ts the package ships, so it is handed back loosely typed.
|
|
@@ -29,6 +53,7 @@ let uWS;
|
|
|
29
53
|
*/
|
|
30
54
|
function loadUWS() {
|
|
31
55
|
if (uWS === undefined) {
|
|
56
|
+
warnOnDrift();
|
|
32
57
|
uWS = /** @type {any} */ (require("uWebSockets.js"));
|
|
33
58
|
try {
|
|
34
59
|
// disable Uwebsockets header
|