@ublitzjs/core 0.1.1 → 1.0.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/README.md +17 -14
- package/USAGE.md +16 -5
- package/babel.config.json +8 -0
- package/bun.lock +627 -0
- package/dist/cjs/http-codes.js +99 -0
- package/dist/cjs/http-headers.js +118 -0
- package/dist/cjs/index.js +104 -0
- package/dist/esm/http-codes.js +84 -0
- package/dist/esm/http-headers.js +119 -0
- package/dist/esm/index.js +71 -0
- package/dist/esm/package.json +1 -0
- package/dist/types/http-codes.d.ts +43 -0
- package/dist/types/http-headers.d.ts +1040 -0
- package/dist/types/index.d.ts +249 -0
- package/package.json +27 -7
- package/src/http-codes.ts +94 -0
- package/{types/http-headers.d.ts → src/http-headers.ts} +75 -18
- package/src/index.ts +360 -0
- package/tmp/cjs.cjs +75 -0
- package/tmp/esm.mjs +75 -0
- package/tsconfig.esm.json +9 -0
- package/tsconfig.json +9 -20
- package/tsconfig.types.json +11 -0
- package/cjs/http-codes.cjs +0 -56
- package/cjs/http-headers.cjs +0 -64
- package/cjs/index.cjs +0 -61
- package/mjs/http-codes.mjs +0 -52
- package/mjs/http-headers.mjs +0 -63
- package/mjs/index.mjs +0 -51
- package/types/http-codes.d.ts +0 -54
- package/types/index.d.ts +0 -170
- package/types/uws-types.d.ts +0 -123
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.badRequest = badRequest;
|
|
7
|
+
exports.c413 = exports.c411 = exports.c405 = exports.c404 = exports.c400 = void 0;
|
|
8
|
+
exports.checkContentLength = checkContentLength;
|
|
9
|
+
exports.notFoundConstructor = notFoundConstructor;
|
|
10
|
+
exports.seeOtherMethods = seeOtherMethods;
|
|
11
|
+
exports.tooLargeBody = tooLargeBody;
|
|
12
|
+
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
|
+
/**
|
|
18
|
+
* If something wrong is to content-length, sends 411 code and throws error with a "cause" == { CL : string}, sets res.finished = true
|
|
19
|
+
*/
|
|
20
|
+
function checkContentLength(res, req) {
|
|
21
|
+
var header = req.getHeader(checkHeader);
|
|
22
|
+
var CL;
|
|
23
|
+
if (!header || !Number.isInteger(CL = Number(header))) {
|
|
24
|
+
res.finished = true;
|
|
25
|
+
res.cork(() => res.writeStatus(c411).end(checkMessage));
|
|
26
|
+
throw new Error("Wrong content-length", {
|
|
27
|
+
cause: {
|
|
28
|
+
CL: header
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return CL;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* sends http 400 and throws an Error with "causeForYou", sets res.finished = true
|
|
36
|
+
*/
|
|
37
|
+
function badRequest(res, error, causeForYou) {
|
|
38
|
+
res.finished = true;
|
|
39
|
+
if (!res.aborted) res.cork(() => res.writeStatus(c400).end((0, _index.toAB)(error)));
|
|
40
|
+
throw new Error("Bad request", {
|
|
41
|
+
cause: causeForYou
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* sends http 413, but doesn't throw an Error, sets res.finished = true
|
|
46
|
+
*/
|
|
47
|
+
function tooLargeBody(res, limit) {
|
|
48
|
+
var message = (0, _index.toAB)("Body is too large. Limit in bytes - " + limit);
|
|
49
|
+
if (!res.aborted) res.cork(() => res.writeStatus(c413).end(message));
|
|
50
|
+
res.finished = true;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Constructs function, which sends http 405 and sets http Allow header with all methods you passed.
|
|
54
|
+
* It ignores "ws" and replaces "del" on "DELETE"
|
|
55
|
+
*/
|
|
56
|
+
function seeOtherMethods(methodsArr) {
|
|
57
|
+
if (new Set(methodsArr).size != methodsArr.length) throw new Error("the methods repeat");
|
|
58
|
+
var arr = [];
|
|
59
|
+
loop: for (var method of methodsArr) {
|
|
60
|
+
switch (method) {
|
|
61
|
+
case "ws":
|
|
62
|
+
continue loop;
|
|
63
|
+
case "del":
|
|
64
|
+
arr.push("DELETE");
|
|
65
|
+
break;
|
|
66
|
+
default:
|
|
67
|
+
arr.push(method.toUpperCase());
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
var methods = (0, _index.toAB)(arr.join(", "));
|
|
71
|
+
return res => res.writeStatus(c405).writeHeader(allowHeader, methods).end(c405Message);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Constructs the function, which sets 404 http code and sends the message you have specified
|
|
75
|
+
*/
|
|
76
|
+
function notFoundConstructor(message = "Not found") {
|
|
77
|
+
var mes = (0, _index.toAB)(message);
|
|
78
|
+
return res => res.writeStatus(c404).end(mes, true);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* code: required content length
|
|
82
|
+
*/
|
|
83
|
+
var c411 = exports.c411 = (0, _index.toAB)("411");
|
|
84
|
+
/**
|
|
85
|
+
* code: bad request
|
|
86
|
+
*/
|
|
87
|
+
var c400 = exports.c400 = (0, _index.toAB)("400");
|
|
88
|
+
/**
|
|
89
|
+
* code: payload too large
|
|
90
|
+
*/
|
|
91
|
+
var c413 = exports.c413 = (0, _index.toAB)("413");
|
|
92
|
+
/**
|
|
93
|
+
* code: method not allowed
|
|
94
|
+
*/
|
|
95
|
+
var c405 = exports.c405 = (0, _index.toAB)("405");
|
|
96
|
+
/**
|
|
97
|
+
* code: not found
|
|
98
|
+
*/
|
|
99
|
+
var c404 = exports.c404 = (0, _index.toAB)("404");
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.HeadersMap = exports.CSPDirs = void 0;
|
|
7
|
+
exports.setCSP = setCSP;
|
|
8
|
+
var _index = require("./index.js");
|
|
9
|
+
var helmetHeaders = {
|
|
10
|
+
"X-Content-Type-Options": "nosniff",
|
|
11
|
+
"X-DNS-Prefetch-Control": "off",
|
|
12
|
+
"X-Frame-Options": "DENY",
|
|
13
|
+
"Referrer-Policy": "same-origin",
|
|
14
|
+
"X-Permitted-Cross-Domain-Policies": "none",
|
|
15
|
+
"X-Download-Options": "noopen",
|
|
16
|
+
"Cross-Origin-Resource-Policy": "same-origin",
|
|
17
|
+
"Cross-Origin-Opener-Policy": "same-origin",
|
|
18
|
+
"Cross-Origin-Embedder-Policy": "require-corp",
|
|
19
|
+
"Origin-Agent-Cluster": "?1"
|
|
20
|
+
//"Content-Security-Policy-Report-Only":"",
|
|
21
|
+
//"Strict-Transport-Security":`max-age=${60 * 60 * 24 * 365}; includeSubDomains`,
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* A map containing all headers as ArrayBuffers, so speed remains. There are several use cases of it:
|
|
25
|
+
* 1) Don't define them in requests ( post(res){new HeadersMap({...headers}).prepare().toRes(res)} ). This is slow. Define maps BEFORE actual usage.
|
|
26
|
+
* 2) You can pass them in LightMethod or HeavyMethod in shared property (but handle it manually)
|
|
27
|
+
* 3) Don't define them before writing status on request. uWebSockets.js after first written header considers response as successful and puts "200" code automatically. Set headers AFTER validation in class controllers (handler function) and after writing status (or don't write it at all. It will be 200).
|
|
28
|
+
*/
|
|
29
|
+
class HeadersMap extends Map {
|
|
30
|
+
currentHeaders;
|
|
31
|
+
constructor(opts) {
|
|
32
|
+
super();
|
|
33
|
+
this.currentHeaders = opts;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* remove several headers from this map. Use BEFORE map.prepare(), because it will compare them by location in memory (string !== ArrayBuffer)
|
|
37
|
+
* @example HeadersMap.default.remove("Content-Security-Policy", "X-DNS-Prefetch-Control", ...otherHeaders).prepare()
|
|
38
|
+
*/
|
|
39
|
+
remove(...keys) {
|
|
40
|
+
for (const key of keys) delete this.currentHeaders[key];
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* last function before "going to response". It converts all strings to ArrayBuffers, so you should delete unwanted headers before it
|
|
45
|
+
* @returns function, which sets all headers on the response.
|
|
46
|
+
* @example
|
|
47
|
+
* new HeadersMap({...HeadersMap.baseObj,"a":"a"}).remove("a").prepare();
|
|
48
|
+
*/
|
|
49
|
+
prepare() {
|
|
50
|
+
for (const key in this.currentHeaders) this.set((0, _index.toAB)(key), (0, _index.toAB)(this.currentHeaders[key]));
|
|
51
|
+
delete this.currentHeaders;
|
|
52
|
+
return res => {
|
|
53
|
+
for (var pair of this) res.writeHeader(pair[0], pair[1]);
|
|
54
|
+
return res;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* write all static headers to response. Use BEFORE map.prepare function, because this function requires "currentHeaders" object.
|
|
59
|
+
* @example
|
|
60
|
+
* headersMap.toRes(res);
|
|
61
|
+
*/
|
|
62
|
+
toRes(res) {
|
|
63
|
+
var key;
|
|
64
|
+
for (key in this.currentHeaders) res.writeHeader(key, this.currentHeaders[key]);
|
|
65
|
+
return res;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* obj, containing basic headers, which u can use as a background for own headers. It is mutable, but doing so will modify "HeadersMap.default" behavior
|
|
69
|
+
* @example
|
|
70
|
+
* new HeadersMap({...HeadersMap.baseObj, "ownHeader":"hello world"}).remove("X-Download-Options")
|
|
71
|
+
*/
|
|
72
|
+
static baseObj = helmetHeaders;
|
|
73
|
+
/**
|
|
74
|
+
* this is same as "toRes", but it uses HeadersMap.baseObj
|
|
75
|
+
*/
|
|
76
|
+
static default(res) {
|
|
77
|
+
var key;
|
|
78
|
+
for (key in HeadersMap.baseObj) res.writeHeader(key, HeadersMap.baseObj[key]);
|
|
79
|
+
return res;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* This function creates Content-Security-Policy string.
|
|
84
|
+
*/
|
|
85
|
+
exports.HeadersMap = HeadersMap;
|
|
86
|
+
function setCSP(mainCSP, ...remove) {
|
|
87
|
+
var CSPstring = "";
|
|
88
|
+
for (const dir of remove) delete mainCSP[dir];
|
|
89
|
+
var key;
|
|
90
|
+
for (key in mainCSP) CSPstring += key + " " + mainCSP[key].join(" ") + "; ";
|
|
91
|
+
return CSPstring;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Usual CSP directories. If you want more dirs:
|
|
95
|
+
* 1) I will put more in soon
|
|
96
|
+
* 2) use string concatenation (use BASE)
|
|
97
|
+
* @example
|
|
98
|
+
* new HeadersMap({...HeadersMap.baseObj, "Content-Security-Policy":setCSP({...CSPDirs}) + " your-dir: 'self';"})
|
|
99
|
+
*/
|
|
100
|
+
var CSPDirs = exports.CSPDirs = {
|
|
101
|
+
"default-src": ["'self'"],
|
|
102
|
+
"base-uri": ["'self'"],
|
|
103
|
+
"font-src": ["'self'"],
|
|
104
|
+
"form-action": ["'self'"],
|
|
105
|
+
"frame-ancestors": ["'none'"],
|
|
106
|
+
"img-src": ["'self'"],
|
|
107
|
+
"connect-src": ["'self'"],
|
|
108
|
+
"object-src": ["'none'"],
|
|
109
|
+
"script-src": ["'self'"],
|
|
110
|
+
"script-src-attr": ["'none'"],
|
|
111
|
+
"script-src-elem": ["'self'"],
|
|
112
|
+
"style-src": ["'self'"],
|
|
113
|
+
"style-src-attr": ["'none'"],
|
|
114
|
+
"style-src-elem": ["'self'"],
|
|
115
|
+
"trusted-types": ["'none'"],
|
|
116
|
+
"worker-src": ["'self'"],
|
|
117
|
+
"media-src": ["'self'"]
|
|
118
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var _exportNames = {
|
|
7
|
+
registerAbort: true,
|
|
8
|
+
closure: true,
|
|
9
|
+
extendApp: true,
|
|
10
|
+
toAB: true,
|
|
11
|
+
DeclarativeResponse: true
|
|
12
|
+
};
|
|
13
|
+
exports.closure = exports.DeclarativeResponse = void 0;
|
|
14
|
+
exports.extendApp = extendApp;
|
|
15
|
+
exports.registerAbort = registerAbort;
|
|
16
|
+
exports.toAB = toAB;
|
|
17
|
+
var _uWebSockets = require("uWebSockets.js");
|
|
18
|
+
var _nodeBuffer = require("node:buffer");
|
|
19
|
+
var _tseep = require("tseep");
|
|
20
|
+
var _httpCodes = require("./http-codes.js");
|
|
21
|
+
Object.keys(_httpCodes).forEach(function (key) {
|
|
22
|
+
if (key === "default" || key === "__esModule") return;
|
|
23
|
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
24
|
+
if (key in exports && exports[key] === _httpCodes[key]) return;
|
|
25
|
+
Object.defineProperty(exports, key, {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
get: function () {
|
|
28
|
+
return _httpCodes[key];
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
var _httpHeaders = require("./http-headers.js");
|
|
33
|
+
Object.keys(_httpHeaders).forEach(function (key) {
|
|
34
|
+
if (key === "default" || key === "__esModule") return;
|
|
35
|
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
36
|
+
if (key in exports && exports[key] === _httpHeaders[key]) return;
|
|
37
|
+
Object.defineProperty(exports, key, {
|
|
38
|
+
enumerable: true,
|
|
39
|
+
get: function () {
|
|
40
|
+
return _httpHeaders[key];
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
_uWebSockets.DeclarativeResponse.prototype.writeHeaders = function (headers) {
|
|
45
|
+
for (const key in headers) this.writeHeader(key, headers[key]);
|
|
46
|
+
return this;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
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
|
+
* @param res
|
|
51
|
+
*/
|
|
52
|
+
function registerAbort(res) {
|
|
53
|
+
if (typeof res.aborted === "boolean") throw new Error("abort already registered");
|
|
54
|
+
res.aborted = false;
|
|
55
|
+
res.emitter = new _tseep.EventEmitter();
|
|
56
|
+
return res.onAborted(() => {
|
|
57
|
+
res.aborted = true;
|
|
58
|
+
res.emitter.emit("abort");
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
;
|
|
62
|
+
/**
|
|
63
|
+
* Utility for making closures. Exists for organizing code and caching values in non-global scope.
|
|
64
|
+
* @param param
|
|
65
|
+
* @returns what you passed
|
|
66
|
+
*/
|
|
67
|
+
var closure = param => param();
|
|
68
|
+
/**
|
|
69
|
+
* extends uWS.App() or uWS.SSLApp. See interface Server
|
|
70
|
+
* @param app uWS.App()
|
|
71
|
+
*/
|
|
72
|
+
exports.closure = closure;
|
|
73
|
+
function extendApp(app, ...rest) {
|
|
74
|
+
app.register = function (plugin) {
|
|
75
|
+
return plugin(this), this;
|
|
76
|
+
};
|
|
77
|
+
app.onError = function (fn) {
|
|
78
|
+
return this._errHandler = fn, this;
|
|
79
|
+
};
|
|
80
|
+
app._startPromises = [];
|
|
81
|
+
app.awaitLater = function () {
|
|
82
|
+
this._startPromises.push(...arguments);
|
|
83
|
+
};
|
|
84
|
+
app.ready = function () {
|
|
85
|
+
return Promise.all(this._startPromises).then(() => this._startPromises = []);
|
|
86
|
+
};
|
|
87
|
+
app.route = function (opts, plugins) {
|
|
88
|
+
if (plugins) for (const p of plugins) p(opts, this);
|
|
89
|
+
return this[opts.method](opts.path, opts.controller);
|
|
90
|
+
};
|
|
91
|
+
for (const extension of rest) Object.assign(app, extension);
|
|
92
|
+
return app;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* conversion to ArrayBuffer ('cause transferring strings to uWS is really slow)
|
|
96
|
+
*/
|
|
97
|
+
function toAB(data) {
|
|
98
|
+
var NodeBuf = data instanceof _nodeBuffer.Buffer ? data : _nodeBuffer.Buffer.from(data);
|
|
99
|
+
return NodeBuf.buffer.slice(NodeBuf.byteOffset, NodeBuf.byteOffset + NodeBuf.byteLength);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Almost nothing different from uWS.DeclarativeResponse. The only modification - writeHeaders method (several methods, typescript intellisense)
|
|
103
|
+
*/
|
|
104
|
+
var DeclarativeResponse = exports.DeclarativeResponse = _uWebSockets.DeclarativeResponse;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
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
|
+
/**
|
|
8
|
+
* If something wrong is to content-length, sends 411 code and throws error with a "cause" == { CL : string}, sets res.finished = true
|
|
9
|
+
*/
|
|
10
|
+
export function checkContentLength(res, req) {
|
|
11
|
+
var header = req.getHeader(checkHeader);
|
|
12
|
+
var CL;
|
|
13
|
+
if (!header || !Number.isInteger(CL = Number(header))) {
|
|
14
|
+
res.finished = true;
|
|
15
|
+
res.cork(() => res.writeStatus(c411).end(checkMessage));
|
|
16
|
+
throw new Error("Wrong content-length", { cause: { CL: header } });
|
|
17
|
+
}
|
|
18
|
+
return CL;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* sends http 400 and throws an Error with "causeForYou", sets res.finished = true
|
|
22
|
+
*/
|
|
23
|
+
export function badRequest(res, error, causeForYou) {
|
|
24
|
+
res.finished = true;
|
|
25
|
+
if (!res.aborted)
|
|
26
|
+
res.cork(() => res.writeStatus(c400).end(toAB(error)));
|
|
27
|
+
throw new Error("Bad request", { cause: causeForYou });
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* sends http 413, but doesn't throw an Error, sets res.finished = true
|
|
31
|
+
*/
|
|
32
|
+
export function tooLargeBody(res, limit) {
|
|
33
|
+
var message = toAB("Body is too large. Limit in bytes - " + limit);
|
|
34
|
+
if (!res.aborted)
|
|
35
|
+
res.cork(() => res.writeStatus(c413).end(message));
|
|
36
|
+
res.finished = true;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Constructs function, which sends http 405 and sets http Allow header with all methods you passed.
|
|
40
|
+
* It ignores "ws" and replaces "del" on "DELETE"
|
|
41
|
+
*/
|
|
42
|
+
export function seeOtherMethods(methodsArr) {
|
|
43
|
+
if (new Set(methodsArr).size != methodsArr.length)
|
|
44
|
+
throw new Error("the methods repeat");
|
|
45
|
+
var arr = [];
|
|
46
|
+
loop: for (var method of methodsArr) {
|
|
47
|
+
switch (method) {
|
|
48
|
+
case "ws": continue loop;
|
|
49
|
+
case "del":
|
|
50
|
+
arr.push("DELETE");
|
|
51
|
+
break;
|
|
52
|
+
default: arr.push(method.toUpperCase());
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
var methods = toAB(arr.join(", "));
|
|
56
|
+
return (res) => res.writeStatus(c405).writeHeader(allowHeader, methods).end(c405Message);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Constructs the function, which sets 404 http code and sends the message you have specified
|
|
60
|
+
*/
|
|
61
|
+
export function notFoundConstructor(message = "Not found") {
|
|
62
|
+
var mes = toAB(message);
|
|
63
|
+
return (res) => res.writeStatus(c404).end(mes, true);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* code: required content length
|
|
67
|
+
*/
|
|
68
|
+
export var c411 = toAB("411");
|
|
69
|
+
/**
|
|
70
|
+
* code: bad request
|
|
71
|
+
*/
|
|
72
|
+
export var c400 = toAB("400");
|
|
73
|
+
/**
|
|
74
|
+
* code: payload too large
|
|
75
|
+
*/
|
|
76
|
+
export var c413 = toAB("413");
|
|
77
|
+
/**
|
|
78
|
+
* code: method not allowed
|
|
79
|
+
*/
|
|
80
|
+
export var c405 = toAB("405");
|
|
81
|
+
/**
|
|
82
|
+
* code: not found
|
|
83
|
+
*/
|
|
84
|
+
export var c404 = toAB("404");
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import { toAB } from "./index.js";
|
|
3
|
+
var helmetHeaders = {
|
|
4
|
+
"X-Content-Type-Options": "nosniff",
|
|
5
|
+
"X-DNS-Prefetch-Control": "off",
|
|
6
|
+
"X-Frame-Options": "DENY",
|
|
7
|
+
"Referrer-Policy": "same-origin",
|
|
8
|
+
"X-Permitted-Cross-Domain-Policies": "none",
|
|
9
|
+
"X-Download-Options": "noopen",
|
|
10
|
+
"Cross-Origin-Resource-Policy": "same-origin",
|
|
11
|
+
"Cross-Origin-Opener-Policy": "same-origin",
|
|
12
|
+
"Cross-Origin-Embedder-Policy": "require-corp",
|
|
13
|
+
"Origin-Agent-Cluster": "?1",
|
|
14
|
+
//"Content-Security-Policy-Report-Only":"",
|
|
15
|
+
//"Strict-Transport-Security":`max-age=${60 * 60 * 24 * 365}; includeSubDomains`,
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* A map containing all headers as ArrayBuffers, so speed remains. There are several use cases of it:
|
|
19
|
+
* 1) Don't define them in requests ( post(res){new HeadersMap({...headers}).prepare().toRes(res)} ). This is slow. Define maps BEFORE actual usage.
|
|
20
|
+
* 2) You can pass them in LightMethod or HeavyMethod in shared property (but handle it manually)
|
|
21
|
+
* 3) Don't define them before writing status on request. uWebSockets.js after first written header considers response as successful and puts "200" code automatically. Set headers AFTER validation in class controllers (handler function) and after writing status (or don't write it at all. It will be 200).
|
|
22
|
+
*/
|
|
23
|
+
export class HeadersMap extends Map {
|
|
24
|
+
currentHeaders;
|
|
25
|
+
constructor(opts) {
|
|
26
|
+
super();
|
|
27
|
+
this.currentHeaders = opts;
|
|
28
|
+
}
|
|
29
|
+
;
|
|
30
|
+
/**
|
|
31
|
+
* remove several headers from this map. Use BEFORE map.prepare(), because it will compare them by location in memory (string !== ArrayBuffer)
|
|
32
|
+
* @example HeadersMap.default.remove("Content-Security-Policy", "X-DNS-Prefetch-Control", ...otherHeaders).prepare()
|
|
33
|
+
*/
|
|
34
|
+
remove(...keys) {
|
|
35
|
+
for (const key of keys)
|
|
36
|
+
delete this.currentHeaders[key];
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* last function before "going to response". It converts all strings to ArrayBuffers, so you should delete unwanted headers before it
|
|
41
|
+
* @returns function, which sets all headers on the response.
|
|
42
|
+
* @example
|
|
43
|
+
* new HeadersMap({...HeadersMap.baseObj,"a":"a"}).remove("a").prepare();
|
|
44
|
+
*/
|
|
45
|
+
prepare() {
|
|
46
|
+
for (const key in this.currentHeaders)
|
|
47
|
+
this.set(toAB(key), toAB(this.currentHeaders[key]));
|
|
48
|
+
delete this.currentHeaders;
|
|
49
|
+
return (res) => {
|
|
50
|
+
for (var pair of this)
|
|
51
|
+
res.writeHeader(pair[0], pair[1]);
|
|
52
|
+
return res;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* write all static headers to response. Use BEFORE map.prepare function, because this function requires "currentHeaders" object.
|
|
57
|
+
* @example
|
|
58
|
+
* headersMap.toRes(res);
|
|
59
|
+
*/
|
|
60
|
+
toRes(res) {
|
|
61
|
+
var key;
|
|
62
|
+
for (key in this.currentHeaders)
|
|
63
|
+
res.writeHeader(key, this.currentHeaders[key]);
|
|
64
|
+
return res;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* obj, containing basic headers, which u can use as a background for own headers. It is mutable, but doing so will modify "HeadersMap.default" behavior
|
|
68
|
+
* @example
|
|
69
|
+
* new HeadersMap({...HeadersMap.baseObj, "ownHeader":"hello world"}).remove("X-Download-Options")
|
|
70
|
+
*/
|
|
71
|
+
static baseObj = helmetHeaders;
|
|
72
|
+
/**
|
|
73
|
+
* this is same as "toRes", but it uses HeadersMap.baseObj
|
|
74
|
+
*/
|
|
75
|
+
static default(res) {
|
|
76
|
+
var key;
|
|
77
|
+
for (key in HeadersMap.baseObj)
|
|
78
|
+
res.writeHeader(key, HeadersMap.baseObj[key]);
|
|
79
|
+
return res;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* This function creates Content-Security-Policy string.
|
|
84
|
+
*/
|
|
85
|
+
export function setCSP(mainCSP, ...remove) {
|
|
86
|
+
var CSPstring = "";
|
|
87
|
+
for (const dir of remove)
|
|
88
|
+
delete mainCSP[dir];
|
|
89
|
+
var key;
|
|
90
|
+
for (key in mainCSP)
|
|
91
|
+
CSPstring += key + " " + mainCSP[key].join(" ") + "; ";
|
|
92
|
+
return CSPstring;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Usual CSP directories. If you want more dirs:
|
|
96
|
+
* 1) I will put more in soon
|
|
97
|
+
* 2) use string concatenation (use BASE)
|
|
98
|
+
* @example
|
|
99
|
+
* new HeadersMap({...HeadersMap.baseObj, "Content-Security-Policy":setCSP({...CSPDirs}) + " your-dir: 'self';"})
|
|
100
|
+
*/
|
|
101
|
+
export var CSPDirs = {
|
|
102
|
+
"default-src": ["'self'"],
|
|
103
|
+
"base-uri": ["'self'"],
|
|
104
|
+
"font-src": ["'self'"],
|
|
105
|
+
"form-action": ["'self'"],
|
|
106
|
+
"frame-ancestors": ["'none'"],
|
|
107
|
+
"img-src": ["'self'"],
|
|
108
|
+
"connect-src": ["'self'"],
|
|
109
|
+
"object-src": ["'none'"],
|
|
110
|
+
"script-src": ["'self'"],
|
|
111
|
+
"script-src-attr": ["'none'"],
|
|
112
|
+
"script-src-elem": ["'self'"],
|
|
113
|
+
"style-src": ["'self'"],
|
|
114
|
+
"style-src-attr": ["'none'"],
|
|
115
|
+
"style-src-elem": ["'self'"],
|
|
116
|
+
"trusted-types": ["'none'"],
|
|
117
|
+
"worker-src": ["'self'"],
|
|
118
|
+
"media-src": ["'self'"],
|
|
119
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
import uWS from "uWebSockets.js";
|
|
3
|
+
import { Buffer } from "node:buffer";
|
|
4
|
+
import { EventEmitter } from "tseep";
|
|
5
|
+
uWS.DeclarativeResponse.prototype.writeHeaders = function (headers) {
|
|
6
|
+
for (const key in headers)
|
|
7
|
+
this.writeHeader(key, headers[key]);
|
|
8
|
+
return this;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
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
|
+
* @param res
|
|
13
|
+
*/
|
|
14
|
+
export function registerAbort(res) {
|
|
15
|
+
if (typeof res.aborted === "boolean")
|
|
16
|
+
throw new Error("abort already registered");
|
|
17
|
+
res.aborted = false;
|
|
18
|
+
res.emitter = new EventEmitter();
|
|
19
|
+
return res.onAborted(() => {
|
|
20
|
+
res.aborted = true;
|
|
21
|
+
res.emitter.emit("abort");
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
;
|
|
25
|
+
/**
|
|
26
|
+
* Utility for making closures. Exists for organizing code and caching values in non-global scope.
|
|
27
|
+
* @param param
|
|
28
|
+
* @returns what you passed
|
|
29
|
+
*/
|
|
30
|
+
export var closure = (param) => param();
|
|
31
|
+
/**
|
|
32
|
+
* extends uWS.App() or uWS.SSLApp. See interface Server
|
|
33
|
+
* @param app uWS.App()
|
|
34
|
+
*/
|
|
35
|
+
export function extendApp(app, ...rest) {
|
|
36
|
+
app.register = function (plugin) {
|
|
37
|
+
return plugin(this), this;
|
|
38
|
+
};
|
|
39
|
+
app.onError = function (fn) {
|
|
40
|
+
return (this._errHandler = fn), this;
|
|
41
|
+
};
|
|
42
|
+
app._startPromises = [];
|
|
43
|
+
app.awaitLater = function () {
|
|
44
|
+
this._startPromises.push(...arguments);
|
|
45
|
+
};
|
|
46
|
+
app.ready = function () {
|
|
47
|
+
return Promise.all(this._startPromises).then(() => (this._startPromises = []));
|
|
48
|
+
};
|
|
49
|
+
app.route = function (opts, plugins) {
|
|
50
|
+
if (plugins)
|
|
51
|
+
for (const p of plugins)
|
|
52
|
+
p(opts, this);
|
|
53
|
+
return this[opts.method](opts.path, opts.controller);
|
|
54
|
+
};
|
|
55
|
+
for (const extension of rest)
|
|
56
|
+
Object.assign(app, extension);
|
|
57
|
+
return app;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* conversion to ArrayBuffer ('cause transferring strings to uWS is really slow)
|
|
61
|
+
*/
|
|
62
|
+
export function toAB(data) {
|
|
63
|
+
var NodeBuf = data instanceof Buffer ? data : Buffer.from(data);
|
|
64
|
+
return NodeBuf.buffer.slice(NodeBuf.byteOffset, NodeBuf.byteOffset + NodeBuf.byteLength);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Almost nothing different from uWS.DeclarativeResponse. The only modification - writeHeaders method (several methods, typescript intellisense)
|
|
68
|
+
*/
|
|
69
|
+
export var DeclarativeResponse = uWS.DeclarativeResponse;
|
|
70
|
+
export * from "./http-codes.js";
|
|
71
|
+
export * from "./http-headers.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type": "module"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { HttpResponse as uwsHttpResponse } from "uWebSockets.js";
|
|
2
|
+
import type { HttpRequest, HttpMethods } from "./index.ts";
|
|
3
|
+
/**
|
|
4
|
+
* If something wrong is to content-length, sends 411 code and throws error with a "cause" == { CL : string}, sets res.finished = true
|
|
5
|
+
*/
|
|
6
|
+
export declare function checkContentLength(res: uwsHttpResponse, req: HttpRequest): number;
|
|
7
|
+
/**
|
|
8
|
+
* sends http 400 and throws an Error with "causeForYou", sets res.finished = true
|
|
9
|
+
*/
|
|
10
|
+
export declare function badRequest(res: uwsHttpResponse, error: string, causeForYou: string): void;
|
|
11
|
+
/**
|
|
12
|
+
* sends http 413, but doesn't throw an Error, sets res.finished = true
|
|
13
|
+
*/
|
|
14
|
+
export declare function tooLargeBody(res: uwsHttpResponse, limit: number): void;
|
|
15
|
+
/**
|
|
16
|
+
* Constructs function, which sends http 405 and sets http Allow header with all methods you passed.
|
|
17
|
+
* It ignores "ws" and replaces "del" on "DELETE"
|
|
18
|
+
*/
|
|
19
|
+
export declare function seeOtherMethods(methodsArr: HttpMethods[]): (res: uwsHttpResponse, req: any) => any;
|
|
20
|
+
/**
|
|
21
|
+
* Constructs the function, which sets 404 http code and sends the message you have specified
|
|
22
|
+
*/
|
|
23
|
+
export declare function notFoundConstructor(message?: string): (res: uwsHttpResponse, req: any) => any;
|
|
24
|
+
/**
|
|
25
|
+
* code: required content length
|
|
26
|
+
*/
|
|
27
|
+
export declare var c411: ArrayBuffer;
|
|
28
|
+
/**
|
|
29
|
+
* code: bad request
|
|
30
|
+
*/
|
|
31
|
+
export declare var c400: ArrayBuffer;
|
|
32
|
+
/**
|
|
33
|
+
* code: payload too large
|
|
34
|
+
*/
|
|
35
|
+
export declare var c413: ArrayBuffer;
|
|
36
|
+
/**
|
|
37
|
+
* code: method not allowed
|
|
38
|
+
*/
|
|
39
|
+
export declare var c405: ArrayBuffer;
|
|
40
|
+
/**
|
|
41
|
+
* code: not found
|
|
42
|
+
*/
|
|
43
|
+
export declare var c404: ArrayBuffer;
|