@ublitzjs/core 1.0.0 → 1.1.0
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/LICENSE +22 -0
- package/README.md +3 -1
- package/dist/cjs/http-codes.js +24 -17
- package/dist/cjs/http-headers.js +100 -12
- package/dist/cjs/index.js +6 -1
- package/dist/esm/http-codes.js +24 -17
- package/dist/esm/http-headers.js +90 -10
- package/dist/esm/index.js +6 -1
- package/dist/types/http-codes.d.ts +15 -6
- package/dist/types/http-headers.d.ts +76 -16
- package/dist/types/index.d.ts +34 -5
- package/package.json +10 -2
- package/USAGE.md +0 -330
- package/babel.config.json +0 -8
- package/bun.lock +0 -627
- package/logo.png +0 -0
- package/src/http-codes.ts +0 -94
- package/src/http-headers.ts +0 -1136
- package/src/index.ts +0 -360
- package/tmp/cjs.cjs +0 -75
- package/tmp/esm.mjs +0 -75
- package/tsconfig.esm.json +0 -9
- package/tsconfig.json +0 -30
- package/tsconfig.types.json +0 -11
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
(The MIT License)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Daniel Dyryl <diril656@gmail.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
'Software'), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -10,12 +10,14 @@ On NPM you can find such packages: (with @ublitzjs/ organization)
|
|
|
10
10
|
- static (send files)
|
|
11
11
|
- payload (handling POST-like requests)
|
|
12
12
|
- router (OpenAPI-like router for simple orientation)
|
|
13
|
-
- openapi
|
|
13
|
+
- openapi
|
|
14
14
|
- preprocess (Code preprocessing + templating framework)
|
|
15
15
|
- asyncapi
|
|
16
16
|
- testing (coming soon)
|
|
17
17
|
- auth (coming soon)
|
|
18
18
|
|
|
19
|
+
The ones having version < 1.0.0 are unstable.
|
|
20
|
+
|
|
19
21
|
# Installation
|
|
20
22
|
|
|
21
23
|
```ps1
|
package/dist/cjs/http-codes.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Yes, I have just deprecated the whole category. It will be completely removed in 2.0.0. When is it coming? Who knows
|
|
5
|
+
* */
|
|
3
6
|
Object.defineProperty(exports, "__esModule", {
|
|
4
7
|
value: true
|
|
5
8
|
});
|
|
@@ -10,19 +13,16 @@ exports.notFoundConstructor = notFoundConstructor;
|
|
|
10
13
|
exports.seeOtherMethods = seeOtherMethods;
|
|
11
14
|
exports.tooLargeBody = tooLargeBody;
|
|
12
15
|
var _index = require("./index.js");
|
|
13
|
-
var c405Message = (0, _index.toAB)("Method is not allowed");
|
|
14
|
-
var allowHeader = (0, _index.toAB)("Allow");
|
|
15
|
-
var checkHeader = (0, _index.toAB)("content-length");
|
|
16
|
-
var checkMessage = (0, _index.toAB)("Content-Length is required to be > 0 and to be an integer");
|
|
17
16
|
/**
|
|
18
|
-
*
|
|
17
|
+
* @deprecated
|
|
18
|
+
* uWS actually checks content-length by itself
|
|
19
19
|
*/
|
|
20
20
|
function checkContentLength(res, req) {
|
|
21
|
-
var header = req.getHeader(
|
|
21
|
+
var header = req.getHeader("content-length");
|
|
22
22
|
var CL;
|
|
23
23
|
if (!header || !Number.isInteger(CL = Number(header))) {
|
|
24
24
|
res.finished = true;
|
|
25
|
-
res.cork(() => res.writeStatus(
|
|
25
|
+
res.cork(() => res.writeStatus("411").end("Content-Length is required to be > 0 and to be an integer"));
|
|
26
26
|
throw new Error("Wrong content-length", {
|
|
27
27
|
cause: {
|
|
28
28
|
CL: header
|
|
@@ -32,26 +32,27 @@ function checkContentLength(res, req) {
|
|
|
32
32
|
return CL;
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
35
|
+
* @deprecated
|
|
36
|
+
* This function throws, so it is slow.
|
|
36
37
|
*/
|
|
37
38
|
function badRequest(res, error, causeForYou) {
|
|
38
39
|
res.finished = true;
|
|
39
|
-
if (!res.aborted) res.cork(() => res.writeStatus(
|
|
40
|
+
if (!res.aborted) res.cork(() => res.writeStatus("400").end((0, _index.toAB)(error)));
|
|
40
41
|
throw new Error("Bad request", {
|
|
41
42
|
cause: causeForYou
|
|
42
43
|
});
|
|
43
44
|
}
|
|
44
45
|
/**
|
|
45
|
-
*
|
|
46
|
+
* @deprecated
|
|
47
|
+
* These are 2 lines of code.
|
|
46
48
|
*/
|
|
47
49
|
function tooLargeBody(res, limit) {
|
|
48
|
-
|
|
49
|
-
if (!res.aborted) res.cork(() => res.writeStatus(c413).end(message));
|
|
50
|
+
if (!res.aborted) res.cork(() => res.writeStatus("413").end("Body is too large. Limit in bytes - " + limit));
|
|
50
51
|
res.finished = true;
|
|
51
52
|
}
|
|
52
53
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
54
|
+
* @deprecated
|
|
55
|
+
* use "typedAllowHeader" instead
|
|
55
56
|
*/
|
|
56
57
|
function seeOtherMethods(methodsArr) {
|
|
57
58
|
if (new Set(methodsArr).size != methodsArr.length) throw new Error("the methods repeat");
|
|
@@ -68,32 +69,38 @@ function seeOtherMethods(methodsArr) {
|
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
var methods = (0, _index.toAB)(arr.join(", "));
|
|
71
|
-
return res => res.writeStatus(
|
|
72
|
+
return res => res.writeStatus("405").writeHeader("Allow", methods).end("Method is not allowed");
|
|
72
73
|
}
|
|
73
74
|
/**
|
|
74
|
-
*
|
|
75
|
+
* @deprecated
|
|
76
|
+
* This is 1-2 lines of code
|
|
75
77
|
*/
|
|
76
78
|
function notFoundConstructor(message = "Not found") {
|
|
77
79
|
var mes = (0, _index.toAB)(message);
|
|
78
|
-
return res => res.writeStatus(
|
|
80
|
+
return res => res.writeStatus("404").end(mes, true);
|
|
79
81
|
}
|
|
80
82
|
/**
|
|
83
|
+
* @deprecated
|
|
81
84
|
* code: required content length
|
|
82
85
|
*/
|
|
83
86
|
var c411 = exports.c411 = (0, _index.toAB)("411");
|
|
84
87
|
/**
|
|
88
|
+
* @deprecated
|
|
85
89
|
* code: bad request
|
|
86
90
|
*/
|
|
87
91
|
var c400 = exports.c400 = (0, _index.toAB)("400");
|
|
88
92
|
/**
|
|
93
|
+
* @deprecated
|
|
89
94
|
* code: payload too large
|
|
90
95
|
*/
|
|
91
96
|
var c413 = exports.c413 = (0, _index.toAB)("413");
|
|
92
97
|
/**
|
|
98
|
+
* @deprecated
|
|
93
99
|
* code: method not allowed
|
|
94
100
|
*/
|
|
95
101
|
var c405 = exports.c405 = (0, _index.toAB)("405");
|
|
96
102
|
/**
|
|
103
|
+
* @deprecated
|
|
97
104
|
* code: not found
|
|
98
105
|
*/
|
|
99
106
|
var c404 = exports.c404 = (0, _index.toAB)("404");
|
package/dist/cjs/http-headers.js
CHANGED
|
@@ -3,10 +3,13 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.HeadersMap = exports.CSPDirs = void 0;
|
|
6
|
+
exports.helmentHeaders = exports.HeadersMap = exports.CSPDirs = void 0;
|
|
7
|
+
exports.parseRange = parseRange;
|
|
7
8
|
exports.setCSP = setCSP;
|
|
9
|
+
exports.staticHeaders = staticHeaders;
|
|
10
|
+
exports.typedAllowHeader = typedAllowHeader;
|
|
8
11
|
var _index = require("./index.js");
|
|
9
|
-
var
|
|
12
|
+
var helmentHeaders = exports.helmentHeaders = {
|
|
10
13
|
"X-Content-Type-Options": "nosniff",
|
|
11
14
|
"X-DNS-Prefetch-Control": "off",
|
|
12
15
|
"X-Frame-Options": "DENY",
|
|
@@ -17,14 +20,41 @@ var helmetHeaders = {
|
|
|
17
20
|
"Cross-Origin-Opener-Policy": "same-origin",
|
|
18
21
|
"Cross-Origin-Embedder-Policy": "require-corp",
|
|
19
22
|
"Origin-Agent-Cluster": "?1"
|
|
20
|
-
//"Content-Security-Policy-Report-Only":"",
|
|
21
|
-
//"Strict-Transport-Security":`max-age=${60 * 60 * 24 * 365}; includeSubDomains`,
|
|
22
23
|
};
|
|
23
24
|
/**
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
* This function is created as a replacement for "HeadersMap" (which became deprecated in 1.1.0).
|
|
26
|
+
* The most overhead when sending request doesn't come from utf16 -> utf8 conversion, but from many subsequent res.writeHeader, which is JS->C++ switch.
|
|
27
|
+
* To reduce an amount of calling headers, you can use manual string concatenation and HTTP header separator - CRLF.
|
|
28
|
+
* @notice this function doesn't create completely ready data to send. Look a the example below
|
|
29
|
+
* @notice2 its return-type LIES. In fact it is just a concatenated string, but TS lies just for LSP help for the second param and, as a result, last header, value to which should be written in res.writeHeader
|
|
30
|
+
* @example
|
|
31
|
+
* //if all headers don't change
|
|
32
|
+
* var headers = staticHeaders({
|
|
33
|
+
* "Content-Type": "text/plain"
|
|
34
|
+
* }, "Etag") // However "Etag" doesn't have value yet
|
|
35
|
+
* * var littleFasterHeaders = Buffer.from(headers)
|
|
36
|
+
* server.get("/", (res)=>{
|
|
37
|
+
* // we put ETag's value to the right. This way we can combine static + dynamic headers in one single call
|
|
38
|
+
* res.writeHeader(littleFasterHeaders, 'W/"' + 123 + '"')
|
|
39
|
+
* res.end("ok")
|
|
40
|
+
*
|
|
41
|
+
* // underneath this is the same (gain speed but lose TypeScript. Not bad if your head is a compiler)
|
|
42
|
+
* res.writeHeader("Content-Type: text/plain\r\nETag", 'W/"' + 123 + '"')
|
|
43
|
+
* // you can make right side look same as well
|
|
44
|
+
* res.writeHeader<string>("Content-Type", 'text/plain\r\nETag: W/"' + 123 + '"')
|
|
45
|
+
* })
|
|
46
|
+
*
|
|
47
|
+
* */
|
|
48
|
+
function staticHeaders(headers, likelyDynamicHeader) {
|
|
49
|
+
var result = "";
|
|
50
|
+
for (var key in headers) {
|
|
51
|
+
result += key + ": " + headers[key] + "\r\n";
|
|
52
|
+
}
|
|
53
|
+
return result += likelyDynamicHeader;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* @deprecated because using ArrayBuffers vs strings in headers doesn't bring much benefit, as it turned out after some benchmarks (+ it uses Map class, so that's even slower). It is going to be removed in 2.0.0. When is it coming? Who knows.
|
|
57
|
+
* And YES, I removed description of it. Stick to "staticHeaders" or CRLF manipulations
|
|
28
58
|
*/
|
|
29
59
|
class HeadersMap extends Map {
|
|
30
60
|
currentHeaders;
|
|
@@ -69,7 +99,7 @@ class HeadersMap extends Map {
|
|
|
69
99
|
* @example
|
|
70
100
|
* new HeadersMap({...HeadersMap.baseObj, "ownHeader":"hello world"}).remove("X-Download-Options")
|
|
71
101
|
*/
|
|
72
|
-
static baseObj =
|
|
102
|
+
static baseObj = helmentHeaders;
|
|
73
103
|
/**
|
|
74
104
|
* this is same as "toRes", but it uses HeadersMap.baseObj
|
|
75
105
|
*/
|
|
@@ -94,8 +124,6 @@ function setCSP(mainCSP, ...remove) {
|
|
|
94
124
|
* Usual CSP directories. If you want more dirs:
|
|
95
125
|
* 1) I will put more in soon
|
|
96
126
|
* 2) use string concatenation (use BASE)
|
|
97
|
-
* @example
|
|
98
|
-
* new HeadersMap({...HeadersMap.baseObj, "Content-Security-Policy":setCSP({...CSPDirs}) + " your-dir: 'self';"})
|
|
99
127
|
*/
|
|
100
128
|
var CSPDirs = exports.CSPDirs = {
|
|
101
129
|
"default-src": ["'self'"],
|
|
@@ -115,4 +143,64 @@ var CSPDirs = exports.CSPDirs = {
|
|
|
115
143
|
"trusted-types": ["'none'"],
|
|
116
144
|
"worker-src": ["'self'"],
|
|
117
145
|
"media-src": ["'self'"]
|
|
118
|
-
};
|
|
146
|
+
};
|
|
147
|
+
var badRange = {
|
|
148
|
+
ok: false,
|
|
149
|
+
code: "400"
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* "Range" http header requires validation, so here you get it
|
|
153
|
+
* @example
|
|
154
|
+
* var data = Buffer.allocUnsafe(1024*1024)
|
|
155
|
+
* server.get("/largeData", (res, req)=>{
|
|
156
|
+
* var range = req.getHeader("range")
|
|
157
|
+
* if(!range) return res.end(data)
|
|
158
|
+
* // so parseRange might modify "range" to suit requirements + check if header is right
|
|
159
|
+
* var parsedRange = parseRange(range, data.length - 1, 64*1024)
|
|
160
|
+
* // might be
|
|
161
|
+
* if(!parsedRange.ok) return res.writeStatus(parsedRange.code).end("bad")
|
|
162
|
+
* })
|
|
163
|
+
* */
|
|
164
|
+
function parseRange(range, maxEnd, maxChunk) {
|
|
165
|
+
if (range.length == 7 || range.slice(0, 6) != "bytes=") return badRange;
|
|
166
|
+
var dash = range.indexOf("-", 6);
|
|
167
|
+
if (dash == -1) return badRange;
|
|
168
|
+
var start = dash == 6 ? undefined : Number(range.slice(6, dash));
|
|
169
|
+
if (Number.isNaN(start)) return badRange;
|
|
170
|
+
var end = range.length == dash + 1 ? undefined : Number(range.slice(dash + 1));
|
|
171
|
+
if (Number.isNaN(end)) return badRange;
|
|
172
|
+
if (end === undefined) {
|
|
173
|
+
end = maxChunk ? Math.min(start + maxChunk, maxEnd) : maxEnd;
|
|
174
|
+
} else if (start === undefined) {
|
|
175
|
+
start = maxEnd - end;
|
|
176
|
+
end = maxEnd;
|
|
177
|
+
}
|
|
178
|
+
if (start >= end || start >= maxEnd) return {
|
|
179
|
+
ok: false,
|
|
180
|
+
code: "416"
|
|
181
|
+
};
|
|
182
|
+
return {
|
|
183
|
+
ok: true,
|
|
184
|
+
start: start,
|
|
185
|
+
end
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* This function takes methods that you registered on an endpoint and formats them to suit "Allow" header.
|
|
190
|
+
* */
|
|
191
|
+
function typedAllowHeader(methodsArr) {
|
|
192
|
+
if (new Set(methodsArr).size != methodsArr.length) throw new Error("the methods repeat");
|
|
193
|
+
var arr = [];
|
|
194
|
+
loop: for (var method of methodsArr) {
|
|
195
|
+
switch (method) {
|
|
196
|
+
case "ws":
|
|
197
|
+
continue loop;
|
|
198
|
+
case "del":
|
|
199
|
+
arr.push("DELETE");
|
|
200
|
+
break;
|
|
201
|
+
default:
|
|
202
|
+
arr.push(method.toUpperCase());
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return arr.join(", ");
|
|
206
|
+
}
|
package/dist/cjs/index.js
CHANGED
|
@@ -47,7 +47,12 @@ _uWebSockets.DeclarativeResponse.prototype.writeHeaders = function (headers) {
|
|
|
47
47
|
};
|
|
48
48
|
/**
|
|
49
49
|
* function to effortlessly mark response as aborted AND to attach an event emitter, so that you can easily scale the handler. If you don't need event emitter and only some res.aborted - set it by yourself (no overkill for the handler)
|
|
50
|
+
* If some utility expect import("@ublitzjs/core").HttpResponse, it means that they response to first go through this registerAbort
|
|
50
51
|
* @param res
|
|
52
|
+
* @example
|
|
53
|
+
* console.log(Boolean(res.emitter)) // false
|
|
54
|
+
* registerAbort(res)
|
|
55
|
+
* console.log(Boolean(res.emitter)) // true
|
|
51
56
|
*/
|
|
52
57
|
function registerAbort(res) {
|
|
53
58
|
if (typeof res.aborted === "boolean") throw new Error("abort already registered");
|
|
@@ -92,7 +97,7 @@ function extendApp(app, ...rest) {
|
|
|
92
97
|
return app;
|
|
93
98
|
}
|
|
94
99
|
/**
|
|
95
|
-
* conversion to
|
|
100
|
+
* @deprecated this conversion to arrayBuffer is not really necessary. You just have Buffer.from(""). Slicing that is rarely needed, and even if it is, that takes 4 lines of code
|
|
96
101
|
*/
|
|
97
102
|
function toAB(data) {
|
|
98
103
|
var NodeBuf = data instanceof _nodeBuffer.Buffer ? data : _nodeBuffer.Buffer.from(data);
|
package/dist/esm/http-codes.js
CHANGED
|
@@ -1,43 +1,44 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Yes, I have just deprecated the whole category. It will be completely removed in 2.0.0. When is it coming? Who knows
|
|
4
|
+
* */
|
|
2
5
|
import { toAB } from "./index.js";
|
|
3
|
-
var c405Message = toAB("Method is not allowed");
|
|
4
|
-
var allowHeader = toAB("Allow");
|
|
5
|
-
var checkHeader = toAB("content-length");
|
|
6
|
-
var checkMessage = toAB("Content-Length is required to be > 0 and to be an integer");
|
|
7
6
|
/**
|
|
8
|
-
*
|
|
7
|
+
* @deprecated
|
|
8
|
+
* uWS actually checks content-length by itself
|
|
9
9
|
*/
|
|
10
10
|
export function checkContentLength(res, req) {
|
|
11
|
-
var header = req.getHeader(
|
|
11
|
+
var header = req.getHeader("content-length");
|
|
12
12
|
var CL;
|
|
13
13
|
if (!header || !Number.isInteger(CL = Number(header))) {
|
|
14
14
|
res.finished = true;
|
|
15
|
-
res.cork(() => res.writeStatus(
|
|
15
|
+
res.cork(() => res.writeStatus("411").end("Content-Length is required to be > 0 and to be an integer"));
|
|
16
16
|
throw new Error("Wrong content-length", { cause: { CL: header } });
|
|
17
17
|
}
|
|
18
18
|
return CL;
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* @deprecated
|
|
22
|
+
* This function throws, so it is slow.
|
|
22
23
|
*/
|
|
23
24
|
export function badRequest(res, error, causeForYou) {
|
|
24
25
|
res.finished = true;
|
|
25
26
|
if (!res.aborted)
|
|
26
|
-
res.cork(() => res.writeStatus(
|
|
27
|
+
res.cork(() => res.writeStatus("400").end(toAB(error)));
|
|
27
28
|
throw new Error("Bad request", { cause: causeForYou });
|
|
28
29
|
}
|
|
29
30
|
/**
|
|
30
|
-
*
|
|
31
|
+
* @deprecated
|
|
32
|
+
* These are 2 lines of code.
|
|
31
33
|
*/
|
|
32
34
|
export function tooLargeBody(res, limit) {
|
|
33
|
-
var message = toAB("Body is too large. Limit in bytes - " + limit);
|
|
34
35
|
if (!res.aborted)
|
|
35
|
-
res.cork(() => res.writeStatus(
|
|
36
|
+
res.cork(() => res.writeStatus("413").end("Body is too large. Limit in bytes - " + limit));
|
|
36
37
|
res.finished = true;
|
|
37
38
|
}
|
|
38
39
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
40
|
+
* @deprecated
|
|
41
|
+
* use "typedAllowHeader" instead
|
|
41
42
|
*/
|
|
42
43
|
export function seeOtherMethods(methodsArr) {
|
|
43
44
|
if (new Set(methodsArr).size != methodsArr.length)
|
|
@@ -53,32 +54,38 @@ export function seeOtherMethods(methodsArr) {
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
var methods = toAB(arr.join(", "));
|
|
56
|
-
return (res) => res.writeStatus(
|
|
57
|
+
return (res) => res.writeStatus("405").writeHeader("Allow", methods).end("Method is not allowed");
|
|
57
58
|
}
|
|
58
59
|
/**
|
|
59
|
-
*
|
|
60
|
+
* @deprecated
|
|
61
|
+
* This is 1-2 lines of code
|
|
60
62
|
*/
|
|
61
63
|
export function notFoundConstructor(message = "Not found") {
|
|
62
64
|
var mes = toAB(message);
|
|
63
|
-
return (res) => res.writeStatus(
|
|
65
|
+
return (res) => res.writeStatus("404").end(mes, true);
|
|
64
66
|
}
|
|
65
67
|
/**
|
|
68
|
+
* @deprecated
|
|
66
69
|
* code: required content length
|
|
67
70
|
*/
|
|
68
71
|
export var c411 = toAB("411");
|
|
69
72
|
/**
|
|
73
|
+
* @deprecated
|
|
70
74
|
* code: bad request
|
|
71
75
|
*/
|
|
72
76
|
export var c400 = toAB("400");
|
|
73
77
|
/**
|
|
78
|
+
* @deprecated
|
|
74
79
|
* code: payload too large
|
|
75
80
|
*/
|
|
76
81
|
export var c413 = toAB("413");
|
|
77
82
|
/**
|
|
83
|
+
* @deprecated
|
|
78
84
|
* code: method not allowed
|
|
79
85
|
*/
|
|
80
86
|
export var c405 = toAB("405");
|
|
81
87
|
/**
|
|
88
|
+
* @deprecated
|
|
82
89
|
* code: not found
|
|
83
90
|
*/
|
|
84
91
|
export var c404 = toAB("404");
|
package/dist/esm/http-headers.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
import { toAB } from "./index.js";
|
|
3
|
-
var
|
|
3
|
+
export var helmentHeaders = {
|
|
4
4
|
"X-Content-Type-Options": "nosniff",
|
|
5
5
|
"X-DNS-Prefetch-Control": "off",
|
|
6
6
|
"X-Frame-Options": "DENY",
|
|
@@ -11,14 +11,41 @@ var helmetHeaders = {
|
|
|
11
11
|
"Cross-Origin-Opener-Policy": "same-origin",
|
|
12
12
|
"Cross-Origin-Embedder-Policy": "require-corp",
|
|
13
13
|
"Origin-Agent-Cluster": "?1",
|
|
14
|
-
//"Content-Security-Policy-Report-Only":"",
|
|
15
|
-
//"Strict-Transport-Security":`max-age=${60 * 60 * 24 * 365}; includeSubDomains`,
|
|
16
14
|
};
|
|
17
15
|
/**
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
* This function is created as a replacement for "HeadersMap" (which became deprecated in 1.1.0).
|
|
17
|
+
* The most overhead when sending request doesn't come from utf16 -> utf8 conversion, but from many subsequent res.writeHeader, which is JS->C++ switch.
|
|
18
|
+
* To reduce an amount of calling headers, you can use manual string concatenation and HTTP header separator - CRLF.
|
|
19
|
+
* @notice this function doesn't create completely ready data to send. Look a the example below
|
|
20
|
+
* @notice2 its return-type LIES. In fact it is just a concatenated string, but TS lies just for LSP help for the second param and, as a result, last header, value to which should be written in res.writeHeader
|
|
21
|
+
* @example
|
|
22
|
+
* //if all headers don't change
|
|
23
|
+
* var headers = staticHeaders({
|
|
24
|
+
* "Content-Type": "text/plain"
|
|
25
|
+
* }, "Etag") // However "Etag" doesn't have value yet
|
|
26
|
+
* * var littleFasterHeaders = Buffer.from(headers)
|
|
27
|
+
* server.get("/", (res)=>{
|
|
28
|
+
* // we put ETag's value to the right. This way we can combine static + dynamic headers in one single call
|
|
29
|
+
* res.writeHeader(littleFasterHeaders, 'W/"' + 123 + '"')
|
|
30
|
+
* res.end("ok")
|
|
31
|
+
*
|
|
32
|
+
* // underneath this is the same (gain speed but lose TypeScript. Not bad if your head is a compiler)
|
|
33
|
+
* res.writeHeader("Content-Type: text/plain\r\nETag", 'W/"' + 123 + '"')
|
|
34
|
+
* // you can make right side look same as well
|
|
35
|
+
* res.writeHeader<string>("Content-Type", 'text/plain\r\nETag: W/"' + 123 + '"')
|
|
36
|
+
* })
|
|
37
|
+
*
|
|
38
|
+
* */
|
|
39
|
+
export function staticHeaders(headers, likelyDynamicHeader) {
|
|
40
|
+
var result = "";
|
|
41
|
+
for (var key in headers) {
|
|
42
|
+
result += key + ": " + headers[key] + "\r\n";
|
|
43
|
+
}
|
|
44
|
+
return (result += likelyDynamicHeader);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* @deprecated because using ArrayBuffers vs strings in headers doesn't bring much benefit, as it turned out after some benchmarks (+ it uses Map class, so that's even slower). It is going to be removed in 2.0.0. When is it coming? Who knows.
|
|
48
|
+
* And YES, I removed description of it. Stick to "staticHeaders" or CRLF manipulations
|
|
22
49
|
*/
|
|
23
50
|
export class HeadersMap extends Map {
|
|
24
51
|
currentHeaders;
|
|
@@ -68,7 +95,7 @@ export class HeadersMap extends Map {
|
|
|
68
95
|
* @example
|
|
69
96
|
* new HeadersMap({...HeadersMap.baseObj, "ownHeader":"hello world"}).remove("X-Download-Options")
|
|
70
97
|
*/
|
|
71
|
-
static baseObj =
|
|
98
|
+
static baseObj = helmentHeaders;
|
|
72
99
|
/**
|
|
73
100
|
* this is same as "toRes", but it uses HeadersMap.baseObj
|
|
74
101
|
*/
|
|
@@ -95,8 +122,6 @@ export function setCSP(mainCSP, ...remove) {
|
|
|
95
122
|
* Usual CSP directories. If you want more dirs:
|
|
96
123
|
* 1) I will put more in soon
|
|
97
124
|
* 2) use string concatenation (use BASE)
|
|
98
|
-
* @example
|
|
99
|
-
* new HeadersMap({...HeadersMap.baseObj, "Content-Security-Policy":setCSP({...CSPDirs}) + " your-dir: 'self';"})
|
|
100
125
|
*/
|
|
101
126
|
export var CSPDirs = {
|
|
102
127
|
"default-src": ["'self'"],
|
|
@@ -117,3 +142,58 @@ export var CSPDirs = {
|
|
|
117
142
|
"worker-src": ["'self'"],
|
|
118
143
|
"media-src": ["'self'"],
|
|
119
144
|
};
|
|
145
|
+
var badRange = { ok: false, code: "400" };
|
|
146
|
+
/**
|
|
147
|
+
* "Range" http header requires validation, so here you get it
|
|
148
|
+
* @example
|
|
149
|
+
* var data = Buffer.allocUnsafe(1024*1024)
|
|
150
|
+
* server.get("/largeData", (res, req)=>{
|
|
151
|
+
* var range = req.getHeader("range")
|
|
152
|
+
* if(!range) return res.end(data)
|
|
153
|
+
* // so parseRange might modify "range" to suit requirements + check if header is right
|
|
154
|
+
* var parsedRange = parseRange(range, data.length - 1, 64*1024)
|
|
155
|
+
* // might be
|
|
156
|
+
* if(!parsedRange.ok) return res.writeStatus(parsedRange.code).end("bad")
|
|
157
|
+
* })
|
|
158
|
+
* */
|
|
159
|
+
export function parseRange(range, maxEnd, maxChunk) {
|
|
160
|
+
if (range.length == 7 || range.slice(0, 6) != "bytes=")
|
|
161
|
+
return badRange;
|
|
162
|
+
var dash = range.indexOf("-", 6);
|
|
163
|
+
if (dash == -1)
|
|
164
|
+
return badRange;
|
|
165
|
+
var start = dash == 6 ? undefined : Number(range.slice(6, dash));
|
|
166
|
+
if (Number.isNaN(start))
|
|
167
|
+
return badRange;
|
|
168
|
+
var end = range.length == dash + 1 ? undefined : Number(range.slice(dash + 1));
|
|
169
|
+
if (Number.isNaN(end))
|
|
170
|
+
return badRange;
|
|
171
|
+
if (end === undefined) {
|
|
172
|
+
end = maxChunk ? Math.min(start + maxChunk, maxEnd) : maxEnd;
|
|
173
|
+
}
|
|
174
|
+
else if (start === undefined) {
|
|
175
|
+
start = maxEnd - end;
|
|
176
|
+
end = maxEnd;
|
|
177
|
+
}
|
|
178
|
+
if (start >= end || start >= maxEnd)
|
|
179
|
+
return { ok: false, code: "416" };
|
|
180
|
+
return { ok: true, start: start, end };
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* This function takes methods that you registered on an endpoint and formats them to suit "Allow" header.
|
|
184
|
+
* */
|
|
185
|
+
export function typedAllowHeader(methodsArr) {
|
|
186
|
+
if (new Set(methodsArr).size != methodsArr.length)
|
|
187
|
+
throw new Error("the methods repeat");
|
|
188
|
+
var arr = [];
|
|
189
|
+
loop: for (var method of methodsArr) {
|
|
190
|
+
switch (method) {
|
|
191
|
+
case "ws": continue loop;
|
|
192
|
+
case "del":
|
|
193
|
+
arr.push("DELETE");
|
|
194
|
+
break;
|
|
195
|
+
default: arr.push(method.toUpperCase());
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return arr.join(", ");
|
|
199
|
+
}
|
package/dist/esm/index.js
CHANGED
|
@@ -9,7 +9,12 @@ uWS.DeclarativeResponse.prototype.writeHeaders = function (headers) {
|
|
|
9
9
|
};
|
|
10
10
|
/**
|
|
11
11
|
* function to effortlessly mark response as aborted AND to attach an event emitter, so that you can easily scale the handler. If you don't need event emitter and only some res.aborted - set it by yourself (no overkill for the handler)
|
|
12
|
+
* If some utility expect import("@ublitzjs/core").HttpResponse, it means that they response to first go through this registerAbort
|
|
12
13
|
* @param res
|
|
14
|
+
* @example
|
|
15
|
+
* console.log(Boolean(res.emitter)) // false
|
|
16
|
+
* registerAbort(res)
|
|
17
|
+
* console.log(Boolean(res.emitter)) // true
|
|
13
18
|
*/
|
|
14
19
|
export function registerAbort(res) {
|
|
15
20
|
if (typeof res.aborted === "boolean")
|
|
@@ -57,7 +62,7 @@ export function extendApp(app, ...rest) {
|
|
|
57
62
|
return app;
|
|
58
63
|
}
|
|
59
64
|
/**
|
|
60
|
-
* conversion to
|
|
65
|
+
* @deprecated this conversion to arrayBuffer is not really necessary. You just have Buffer.from(""). Slicing that is rarely needed, and even if it is, that takes 4 lines of code
|
|
61
66
|
*/
|
|
62
67
|
export function toAB(data) {
|
|
63
68
|
var NodeBuf = data instanceof Buffer ? data : Buffer.from(data);
|
|
@@ -1,43 +1,52 @@
|
|
|
1
1
|
import type { HttpResponse as uwsHttpResponse } from "uWebSockets.js";
|
|
2
2
|
import type { HttpRequest, HttpMethods } from "./index.ts";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* @deprecated
|
|
5
|
+
* uWS actually checks content-length by itself
|
|
5
6
|
*/
|
|
6
7
|
export declare function checkContentLength(res: uwsHttpResponse, req: HttpRequest): number;
|
|
7
8
|
/**
|
|
8
|
-
*
|
|
9
|
+
* @deprecated
|
|
10
|
+
* This function throws, so it is slow.
|
|
9
11
|
*/
|
|
10
12
|
export declare function badRequest(res: uwsHttpResponse, error: string, causeForYou: string): void;
|
|
11
13
|
/**
|
|
12
|
-
*
|
|
14
|
+
* @deprecated
|
|
15
|
+
* These are 2 lines of code.
|
|
13
16
|
*/
|
|
14
17
|
export declare function tooLargeBody(res: uwsHttpResponse, limit: number): void;
|
|
15
18
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
19
|
+
* @deprecated
|
|
20
|
+
* use "typedAllowHeader" instead
|
|
18
21
|
*/
|
|
19
22
|
export declare function seeOtherMethods(methodsArr: HttpMethods[]): (res: uwsHttpResponse, req: any) => any;
|
|
20
23
|
/**
|
|
21
|
-
*
|
|
24
|
+
* @deprecated
|
|
25
|
+
* This is 1-2 lines of code
|
|
22
26
|
*/
|
|
23
27
|
export declare function notFoundConstructor(message?: string): (res: uwsHttpResponse, req: any) => any;
|
|
24
28
|
/**
|
|
29
|
+
* @deprecated
|
|
25
30
|
* code: required content length
|
|
26
31
|
*/
|
|
27
32
|
export declare var c411: ArrayBuffer;
|
|
28
33
|
/**
|
|
34
|
+
* @deprecated
|
|
29
35
|
* code: bad request
|
|
30
36
|
*/
|
|
31
37
|
export declare var c400: ArrayBuffer;
|
|
32
38
|
/**
|
|
39
|
+
* @deprecated
|
|
33
40
|
* code: payload too large
|
|
34
41
|
*/
|
|
35
42
|
export declare var c413: ArrayBuffer;
|
|
36
43
|
/**
|
|
44
|
+
* @deprecated
|
|
37
45
|
* code: method not allowed
|
|
38
46
|
*/
|
|
39
47
|
export declare var c405: ArrayBuffer;
|
|
40
48
|
/**
|
|
49
|
+
* @deprecated
|
|
41
50
|
* code: not found
|
|
42
51
|
*/
|
|
43
52
|
export declare var c404: ArrayBuffer;
|