tezx 3.0.9-beta → 3.0.11-beta
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/bun/index.d.ts +4 -2
- package/bun/index.js +3 -2
- package/bun/ws.d.ts +37 -0
- package/bun/ws.js +23 -0
- package/cjs/bun/index.js +37 -5
- package/cjs/bun/ws.js +25 -0
- package/cjs/core/context.js +86 -88
- package/cjs/core/error.js +41 -0
- package/cjs/core/request.js +6 -6
- package/cjs/core/router.js +6 -6
- package/cjs/core/server.js +45 -63
- package/cjs/index.js +5 -2
- package/cjs/middleware/basic-auth.js +28 -54
- package/cjs/middleware/bearer-auth.js +34 -0
- package/cjs/middleware/cors.js +14 -24
- package/cjs/middleware/index.js +25 -0
- package/cjs/middleware/logger.js +6 -3
- package/cjs/middleware/pagination.js +1 -1
- package/cjs/middleware/powered-by.js +1 -1
- package/cjs/middleware/rate-limiter.js +20 -7
- package/cjs/middleware/request-id.js +4 -7
- package/cjs/middleware/sanitize-headers.js +8 -40
- package/cjs/middleware/xss-protection.js +2 -6
- package/cjs/registry/RadixRouter.js +72 -23
- package/cjs/utils/cookie.js +1 -1
- package/cjs/utils/rateLimit.js +2 -2
- package/cjs/utils/regexRouter.js +1 -0
- package/cjs/utils/response.js +21 -30
- package/core/context.d.ts +68 -68
- package/core/context.js +87 -89
- package/core/error.d.ts +95 -0
- package/core/error.js +37 -0
- package/core/request.d.ts +2 -2
- package/core/request.js +6 -6
- package/core/router.d.ts +11 -6
- package/core/router.js +6 -6
- package/core/server.js +45 -63
- package/index.d.ts +5 -3
- package/index.js +4 -2
- package/middleware/basic-auth.d.ts +38 -66
- package/middleware/basic-auth.js +28 -54
- package/middleware/bearer-auth.d.ts +52 -0
- package/middleware/bearer-auth.js +30 -0
- package/middleware/cors.d.ts +7 -21
- package/middleware/cors.js +14 -24
- package/middleware/index.d.ts +9 -0
- package/middleware/index.js +9 -0
- package/middleware/logger.d.ts +3 -1
- package/middleware/logger.js +6 -3
- package/middleware/pagination.d.ts +8 -6
- package/middleware/pagination.js +1 -1
- package/middleware/powered-by.js +1 -1
- package/middleware/rate-limiter.d.ts +0 -4
- package/middleware/rate-limiter.js +20 -7
- package/middleware/request-id.d.ts +1 -1
- package/middleware/request-id.js +3 -6
- package/middleware/sanitize-headers.d.ts +3 -11
- package/middleware/sanitize-headers.js +8 -40
- package/middleware/xss-protection.d.ts +1 -1
- package/middleware/xss-protection.js +1 -5
- package/package.json +6 -1
- package/registry/RadixRouter.js +72 -23
- package/types/index.d.ts +2 -1
- package/utils/cookie.js +1 -1
- package/utils/rateLimit.d.ts +1 -2
- package/utils/rateLimit.js +2 -2
- package/utils/regexRouter.js +1 -0
- package/utils/response.d.ts +12 -14
- package/utils/response.js +20 -29
- package/cjs/middleware/cache-control.js +0 -93
- package/cjs/middleware/detect-bot.js +0 -66
- package/cjs/middleware/detect-locale.js +0 -45
- package/cjs/middleware/i18n.js +0 -93
- package/cjs/middleware/lazy-loader.js +0 -74
- package/cjs/middleware/request-timeout.js +0 -43
- package/cjs/middleware/secure-headers.js +0 -43
- package/middleware/cache-control.d.ts +0 -56
- package/middleware/cache-control.js +0 -56
- package/middleware/detect-bot.d.ts +0 -111
- package/middleware/detect-bot.js +0 -62
- package/middleware/detect-locale.d.ts +0 -56
- package/middleware/detect-locale.js +0 -41
- package/middleware/i18n.d.ts +0 -102
- package/middleware/i18n.js +0 -89
- package/middleware/lazy-loader.d.ts +0 -73
- package/middleware/lazy-loader.js +0 -70
- package/middleware/request-timeout.d.ts +0 -26
- package/middleware/request-timeout.js +0 -39
- package/middleware/secure-headers.d.ts +0 -78
- package/middleware/secure-headers.js +0 -39
package/cjs/core/server.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TezX = void 0;
|
|
4
|
-
const colors_js_1 = require("../utils/colors.js");
|
|
5
4
|
const response_js_1 = require("../utils/response.js");
|
|
6
5
|
const url_js_1 = require("../utils/url.js");
|
|
7
6
|
const config_js_1 = require("./config.js");
|
|
8
7
|
const context_js_1 = require("./context.js");
|
|
8
|
+
const error_js_1 = require("./error.js");
|
|
9
9
|
const router_js_1 = require("./router.js");
|
|
10
10
|
class TezX extends router_js_1.Router {
|
|
11
11
|
#pathResolver;
|
|
@@ -27,88 +27,70 @@ class TezX extends router_js_1.Router {
|
|
|
27
27
|
this.#errorHandler = callback;
|
|
28
28
|
return this;
|
|
29
29
|
}
|
|
30
|
-
async #
|
|
31
|
-
let
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
return resolvePath;
|
|
40
|
-
}
|
|
41
|
-
#chain(middlewares) {
|
|
42
|
-
if (!Array.isArray(middlewares)) {
|
|
43
|
-
throw new TypeError("Middleware stack must be an array!");
|
|
44
|
-
}
|
|
45
|
-
const len = middlewares.length;
|
|
46
|
-
return async function (ctx) {
|
|
47
|
-
let index = -1;
|
|
48
|
-
async function dispatch(i) {
|
|
49
|
-
if (i <= index) {
|
|
50
|
-
throw new Error("next() called multiple times");
|
|
51
|
-
}
|
|
52
|
-
index = i;
|
|
53
|
-
if (i >= len)
|
|
54
|
-
return;
|
|
30
|
+
async #chain(ctx, mLen, middlewares, hLen, handlers) {
|
|
31
|
+
let index = -1;
|
|
32
|
+
let res;
|
|
33
|
+
async function dispatch(i) {
|
|
34
|
+
if (i <= index)
|
|
35
|
+
throw new Error("next() called multiple times");
|
|
36
|
+
index = i;
|
|
37
|
+
if (i < mLen) {
|
|
55
38
|
const fn = middlewares[i];
|
|
56
|
-
if (typeof fn !== "function")
|
|
57
|
-
throw new TypeError(`Middleware
|
|
39
|
+
if (typeof fn !== "function")
|
|
40
|
+
throw new TypeError(`Middleware[${i}] must be a function`);
|
|
41
|
+
res = (await fn(ctx, () => dispatch(i + 1)));
|
|
42
|
+
if (res !== undefined) {
|
|
43
|
+
ctx.res = res;
|
|
58
44
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
45
|
+
return ctx.res;
|
|
46
|
+
}
|
|
47
|
+
const hi = i - mLen;
|
|
48
|
+
if (hi < hLen) {
|
|
49
|
+
const fn = handlers[hi];
|
|
50
|
+
if (typeof fn !== "function")
|
|
51
|
+
throw new TypeError(`Handler[${hi}] must be a function`);
|
|
52
|
+
res = (await fn(ctx, () => dispatch(i + 1)));
|
|
53
|
+
if (res !== undefined) {
|
|
54
|
+
ctx.res = res;
|
|
62
55
|
}
|
|
63
56
|
return ctx.res;
|
|
64
57
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
58
|
+
}
|
|
59
|
+
await dispatch(0);
|
|
60
|
+
return (ctx.res ??
|
|
61
|
+
(ctx.body !== undefined ? ctx.send(ctx.body) : this.#notFound(ctx)));
|
|
68
62
|
}
|
|
69
63
|
async #handleRequest(req, method, args) {
|
|
70
|
-
if (!(req instanceof Request))
|
|
64
|
+
if (!(req instanceof Request))
|
|
71
65
|
throw new Error("Invalid request object provided to tezX server.");
|
|
72
|
-
|
|
73
|
-
const pathname =
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
env: this.env,
|
|
78
|
-
args,
|
|
79
|
-
});
|
|
66
|
+
const rawPath = (0, url_js_1.getPathname)(req.url);
|
|
67
|
+
const pathname = this.#pathResolver
|
|
68
|
+
? await this.#pathResolver(rawPath)
|
|
69
|
+
: rawPath;
|
|
70
|
+
const ctx = new context_js_1.Context(req, pathname, method, this.env, args);
|
|
80
71
|
try {
|
|
81
72
|
const staticHandler = this.staticFile?.[`${method} ${pathname}`];
|
|
82
73
|
if (staticHandler) {
|
|
83
74
|
return staticHandler(ctx);
|
|
84
75
|
}
|
|
85
76
|
const route = this.router.search(method, pathname);
|
|
86
|
-
|
|
77
|
+
const mLen = route?.middlewares?.length;
|
|
78
|
+
const hLen = route?.handlers?.length;
|
|
79
|
+
if (!route || (hLen === 0 && mLen === 0)) {
|
|
87
80
|
return this.#notFound(ctx);
|
|
88
81
|
}
|
|
89
82
|
ctx.params = route.params;
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return result;
|
|
94
|
-
if (ctx.body !== undefined)
|
|
95
|
-
return ctx.send(ctx.body);
|
|
96
|
-
return this.#notFound(ctx);
|
|
97
|
-
}
|
|
98
|
-
let res = await this.#chain([
|
|
99
|
-
...route.middlewares,
|
|
100
|
-
...route.handlers,
|
|
101
|
-
])(ctx);
|
|
102
|
-
if (!res && ctx.body !== undefined) {
|
|
103
|
-
res = ctx.send(ctx.body);
|
|
83
|
+
if (hLen === 1 && mLen === 0) {
|
|
84
|
+
return ((await route.handlers[0](ctx)) ??
|
|
85
|
+
(ctx.body !== undefined ? ctx.send(ctx.body) : this.#notFound(ctx)));
|
|
104
86
|
}
|
|
105
|
-
|
|
106
|
-
return this.#notFound(ctx);
|
|
107
|
-
}
|
|
108
|
-
return res;
|
|
87
|
+
return await this.#chain(ctx, mLen, route.middlewares, hLen, route.handlers);
|
|
109
88
|
}
|
|
110
89
|
catch (err) {
|
|
111
|
-
|
|
90
|
+
if (!(err instanceof error_js_1.TezXError)) {
|
|
91
|
+
return this.#errorHandler?.(error_js_1.TezXError.internal(err?.message, err?.stack), ctx);
|
|
92
|
+
}
|
|
93
|
+
return this.#errorHandler?.(err, ctx);
|
|
112
94
|
}
|
|
113
95
|
}
|
|
114
96
|
async serve(req, ...args) {
|
package/cjs/index.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.version = exports.TezX = exports.Router = void 0;
|
|
3
|
+
exports.version = exports.TezXError = exports.TezX = exports.Router = void 0;
|
|
4
|
+
const error_js_1 = require("./core/error.js");
|
|
5
|
+
Object.defineProperty(exports, "TezXError", { enumerable: true, get: function () { return error_js_1.TezXError; } });
|
|
4
6
|
const router_js_1 = require("./core/router.js");
|
|
5
7
|
Object.defineProperty(exports, "Router", { enumerable: true, get: function () { return router_js_1.Router; } });
|
|
6
8
|
const server_js_1 = require("./core/server.js");
|
|
7
9
|
Object.defineProperty(exports, "TezX", { enumerable: true, get: function () { return server_js_1.TezX; } });
|
|
8
|
-
exports.version = "3.0.
|
|
10
|
+
exports.version = "3.0.11-beta";
|
|
9
11
|
exports.default = {
|
|
10
12
|
Router: router_js_1.Router,
|
|
11
13
|
TezX: server_js_1.TezX,
|
|
12
14
|
version: exports.version,
|
|
15
|
+
TezXError: error_js_1.TezXError,
|
|
13
16
|
};
|
|
@@ -1,73 +1,47 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.basicAuth = void 0;
|
|
4
4
|
const node_buffer_1 = require("node:buffer");
|
|
5
|
-
const config_js_1 = require("../core/config.js");
|
|
6
|
-
const colors_js_1 = require("../utils/colors.js");
|
|
7
|
-
const rateLimit_js_1 = require("../utils/rateLimit.js");
|
|
8
5
|
const basicAuth = (options) => {
|
|
9
|
-
const {
|
|
10
|
-
const realm = getRealm(ctx);
|
|
6
|
+
const { validate, realm = "Restricted Area", onUnauthorized = (ctx, error) => {
|
|
11
7
|
ctx.setStatus = 401;
|
|
12
8
|
ctx.setHeader("WWW-Authenticate", `Basic realm="${realm}"`);
|
|
13
|
-
ctx.
|
|
14
|
-
},
|
|
15
|
-
|
|
16
|
-
if (rateLimit && !rateLimit.storage) {
|
|
17
|
-
storage = (0, rateLimit_js_1.createRateLimitDefaultStorage)();
|
|
18
|
-
}
|
|
19
|
-
return async function basicAuth(ctx, next) {
|
|
20
|
-
let authMethod;
|
|
21
|
-
let credentials = {};
|
|
9
|
+
return ctx.json({ error: error?.message || "Unauthorized" });
|
|
10
|
+
}, } = options;
|
|
11
|
+
return async (ctx, next) => {
|
|
22
12
|
const auth = ctx.req.header("authorization");
|
|
23
|
-
if (auth) {
|
|
24
|
-
|
|
25
|
-
authMethod = "basic";
|
|
26
|
-
const base64Credentials = auth.split(" ")[1];
|
|
27
|
-
const decoded = node_buffer_1.Buffer.from(base64Credentials, "base64").toString("utf-8");
|
|
28
|
-
const [username, password] = decoded.split(":");
|
|
29
|
-
credentials = { username, password };
|
|
30
|
-
}
|
|
31
|
-
else if (auth.startsWith("Bearer ")) {
|
|
32
|
-
authMethod = "bearer-token";
|
|
33
|
-
credentials = { token: auth.split(" ")[1] };
|
|
34
|
-
}
|
|
13
|
+
if (!auth || !auth.startsWith("Basic ")) {
|
|
14
|
+
return onUnauthorized(ctx, new Error("Basic authentication required"));
|
|
35
15
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
16
|
+
const base64 = auth.slice(6).trim();
|
|
17
|
+
if (!base64) {
|
|
18
|
+
return onUnauthorized(ctx, new Error("Empty credentials"));
|
|
39
19
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
20
|
+
let username, password;
|
|
21
|
+
try {
|
|
22
|
+
const decoded = node_buffer_1.Buffer.from(base64, "base64").toString("utf-8");
|
|
23
|
+
const idx = decoded.indexOf(":");
|
|
24
|
+
if (idx === -1)
|
|
25
|
+
throw new Error("Missing colon in credentials");
|
|
26
|
+
username = decoded.slice(0, idx);
|
|
27
|
+
password = decoded.slice(idx + 1);
|
|
43
28
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const { check, entry } = (0, rateLimit_js_1.isRateLimit)(ctx, key, storage, rateLimit.maxRequests, rateLimit.windowMs);
|
|
47
|
-
if (check) {
|
|
48
|
-
const retryAfter = Math.ceil((entry.resetTime - Date.now()) / 1000);
|
|
49
|
-
ctx.setHeader("Retry-After", retryAfter.toString());
|
|
50
|
-
return onUnauthorized(ctx, new Error(`Rate limit exceeded. Retry after ${retryAfter} seconds.`));
|
|
51
|
-
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
return onUnauthorized(ctx, new Error("Invalid Basic auth format"));
|
|
52
31
|
}
|
|
53
32
|
try {
|
|
54
|
-
const
|
|
55
|
-
if (!
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
if (checkAccess) {
|
|
59
|
-
const hasAccess = await checkAccess(ctx, credentials);
|
|
60
|
-
if (!hasAccess) {
|
|
61
|
-
return onUnauthorized(ctx, new Error("Access denied."));
|
|
62
|
-
}
|
|
33
|
+
const valid = await validate(username, password, ctx);
|
|
34
|
+
if (!valid) {
|
|
35
|
+
return onUnauthorized(ctx, new Error("Invalid username or password"));
|
|
63
36
|
}
|
|
64
|
-
|
|
37
|
+
ctx.user = { username };
|
|
38
|
+
await next();
|
|
65
39
|
}
|
|
66
|
-
catch (
|
|
67
|
-
|
|
40
|
+
catch (err) {
|
|
41
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
68
42
|
return onUnauthorized(ctx, error);
|
|
69
43
|
}
|
|
70
44
|
};
|
|
71
45
|
};
|
|
72
46
|
exports.basicAuth = basicAuth;
|
|
73
|
-
exports.default = basicAuth;
|
|
47
|
+
exports.default = exports.basicAuth;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bearerAuth = void 0;
|
|
4
|
+
const bearerAuth = (options) => {
|
|
5
|
+
const { validate, realm = "API", onUnauthorized = (ctx, error) => {
|
|
6
|
+
ctx.setStatus = 401;
|
|
7
|
+
ctx.setHeader("WWW-Authenticate", `Bearer realm="${realm}"`);
|
|
8
|
+
return ctx.json({ error: error?.message || "Unauthorized" });
|
|
9
|
+
}, } = options;
|
|
10
|
+
return async (ctx, next) => {
|
|
11
|
+
const auth = ctx.req.header("authorization");
|
|
12
|
+
if (!auth || !auth.startsWith("Bearer ")) {
|
|
13
|
+
return onUnauthorized(ctx, new Error("Bearer token required"));
|
|
14
|
+
}
|
|
15
|
+
const token = auth.slice(7).trim();
|
|
16
|
+
if (!token) {
|
|
17
|
+
return onUnauthorized(ctx, new Error("Empty token"));
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const valid = await validate(token, ctx);
|
|
21
|
+
if (!valid) {
|
|
22
|
+
return onUnauthorized(ctx, new Error("Invalid or expired token"));
|
|
23
|
+
}
|
|
24
|
+
ctx.token = token;
|
|
25
|
+
await next();
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
29
|
+
return onUnauthorized(ctx, error);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
exports.bearerAuth = bearerAuth;
|
|
34
|
+
exports.default = exports.bearerAuth;
|
package/cjs/middleware/cors.js
CHANGED
|
@@ -3,47 +3,37 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.cors = cors;
|
|
4
4
|
exports.default = cors;
|
|
5
5
|
function cors(option = {}) {
|
|
6
|
-
const {
|
|
6
|
+
const { credentials, maxAge, origin, } = option;
|
|
7
|
+
let methods = (option.methods || ["GET", "POST", "PUT", "DELETE"]).join(", ");
|
|
8
|
+
let allowedHeaders = (option.allowedHeaders || ["Content-Type", "Authorization"]).join(", ");
|
|
9
|
+
let exposedHeaders = option?.exposedHeaders?.join(", ");
|
|
7
10
|
return async function cors(ctx, next) {
|
|
8
11
|
const reqOrigin = ctx.req.header("origin") || "";
|
|
9
12
|
let allowOrigin = "*";
|
|
10
13
|
if (typeof origin === "string") {
|
|
11
14
|
allowOrigin = origin;
|
|
12
15
|
}
|
|
13
|
-
else if (origin instanceof RegExp) {
|
|
14
|
-
allowOrigin = origin.test(reqOrigin) ? reqOrigin : "";
|
|
15
|
-
}
|
|
16
16
|
else if (Array.isArray(origin)) {
|
|
17
|
-
|
|
18
|
-
if (typeof item === "string") {
|
|
19
|
-
return item === reqOrigin;
|
|
20
|
-
}
|
|
21
|
-
else if (item instanceof RegExp) {
|
|
22
|
-
return item.test(reqOrigin);
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
allowOrigin = isAllowed ? reqOrigin : "";
|
|
17
|
+
allowOrigin = origin.includes(reqOrigin) ? reqOrigin : "";
|
|
26
18
|
}
|
|
27
19
|
else if (typeof origin === "function") {
|
|
28
20
|
allowOrigin = origin(reqOrigin) ? reqOrigin : "";
|
|
29
21
|
}
|
|
30
|
-
ctx.
|
|
31
|
-
ctx.
|
|
32
|
-
ctx.
|
|
22
|
+
ctx.headers.set("Access-Control-Allow-Origin", allowOrigin);
|
|
23
|
+
ctx.headers.set("Access-Control-Allow-Methods", methods);
|
|
24
|
+
ctx.headers.set("Access-Control-Allow-Headers", allowedHeaders);
|
|
33
25
|
if (exposedHeaders) {
|
|
34
|
-
ctx.
|
|
26
|
+
ctx.headers.set("Access-Control-Expose-Headers", exposedHeaders);
|
|
35
27
|
}
|
|
36
28
|
if (credentials) {
|
|
37
|
-
ctx.
|
|
29
|
+
ctx.headers.set("Access-Control-Allow-Credentials", "true");
|
|
38
30
|
}
|
|
39
31
|
if (maxAge) {
|
|
40
|
-
ctx.
|
|
32
|
+
ctx.headers.set("Access-Control-Max-Age", maxAge.toString());
|
|
41
33
|
}
|
|
42
|
-
if (ctx.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
headers: ctx.header(),
|
|
46
|
-
});
|
|
34
|
+
if (ctx.method === "OPTIONS") {
|
|
35
|
+
ctx.setStatus = 204;
|
|
36
|
+
return;
|
|
47
37
|
}
|
|
48
38
|
return await next();
|
|
49
39
|
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./basic-auth.js"), exports);
|
|
18
|
+
__exportStar(require("./bearer-auth.js"), exports);
|
|
19
|
+
__exportStar(require("./cors.js"), exports);
|
|
20
|
+
__exportStar(require("./logger.js"), exports);
|
|
21
|
+
__exportStar(require("./pagination.js"), exports);
|
|
22
|
+
__exportStar(require("./powered-by.js"), exports);
|
|
23
|
+
__exportStar(require("./request-id.js"), exports);
|
|
24
|
+
__exportStar(require("./sanitize-headers.js"), exports);
|
|
25
|
+
__exportStar(require("./xss-protection.js"), exports);
|
package/cjs/middleware/logger.js
CHANGED
|
@@ -3,15 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.logger = logger;
|
|
4
4
|
exports.default = logger;
|
|
5
5
|
const colors_js_1 = require("../utils/colors.js");
|
|
6
|
-
function logger() {
|
|
6
|
+
function logger(options = { enabled: true }) {
|
|
7
7
|
return async function logger(ctx, next) {
|
|
8
8
|
try {
|
|
9
|
+
if (!options?.enabled) {
|
|
10
|
+
return next();
|
|
11
|
+
}
|
|
9
12
|
console.log(`${(0, colors_js_1.colorText)("<--", "bold")} ${(0, colors_js_1.colorText)(ctx.method, "bgMagenta")} ${ctx.pathname}`);
|
|
10
13
|
const startTime = performance.now();
|
|
11
|
-
let n = await next();
|
|
14
|
+
let n = (await next());
|
|
12
15
|
const elapsed = performance.now() - startTime;
|
|
13
16
|
console.log(`${(0, colors_js_1.colorText)("-->", "bold")} ${(0, colors_js_1.colorText)(ctx.method, "bgBlue")} ${ctx.pathname} ` +
|
|
14
|
-
`${(0, colors_js_1.colorText)(ctx.getStatus, "yellow")} ${(0, colors_js_1.colorText)(`${elapsed.toFixed(2)}ms`, "magenta")}`);
|
|
17
|
+
`${(0, colors_js_1.colorText)(n ? ctx.getStatus : 404, "yellow")} ${(0, colors_js_1.colorText)(`${elapsed.toFixed(2)}ms`, "magenta")}`);
|
|
15
18
|
return n;
|
|
16
19
|
}
|
|
17
20
|
catch (err) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = exports.paginationHandler = void 0;
|
|
4
4
|
const paginationHandler = (options = {}) => {
|
|
5
|
-
|
|
5
|
+
let { defaultPage = 1, defaultLimit = 10, maxLimit = 100, queryKeyPage = "page", queryKeyLimit = "limit", countKey = "total", dataKey = "data", getDataSource, } = options;
|
|
6
6
|
return async function paginationHandler(ctx, next) {
|
|
7
7
|
const rawPage = ctx.req.query[queryKeyPage];
|
|
8
8
|
const rawLimit = ctx.req.query[queryKeyLimit];
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.default = exports.poweredBy = void 0;
|
|
4
4
|
const poweredBy = (serverName) => {
|
|
5
5
|
return function poweredBy(ctx, next) {
|
|
6
|
-
ctx.
|
|
6
|
+
ctx.headers.set("x-powered-by", serverName || "TezX");
|
|
7
7
|
return next();
|
|
8
8
|
};
|
|
9
9
|
};
|
|
@@ -1,23 +1,36 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = exports.rateLimiter = void 0;
|
|
4
|
+
const error_js_1 = require("../core/error.js");
|
|
4
5
|
const rateLimit_js_1 = require("../utils/rateLimit.js");
|
|
5
6
|
const rateLimiter = (options) => {
|
|
6
|
-
const { maxRequests, windowMs, keyGenerator = (ctx) =>
|
|
7
|
+
const { maxRequests, windowMs, keyGenerator = (ctx) => {
|
|
8
|
+
const xForwardedFor = ctx.req.header("x-forwarded-for");
|
|
9
|
+
if (xForwardedFor) {
|
|
10
|
+
const ip = xForwardedFor.split(",")[0].trim();
|
|
11
|
+
return ip;
|
|
12
|
+
}
|
|
13
|
+
const clientIp = ctx.req.header("client-ip");
|
|
14
|
+
if (clientIp)
|
|
15
|
+
return clientIp;
|
|
16
|
+
const addr = ctx.req.remoteAddress?.address || "unknown";
|
|
17
|
+
const port = ctx.req.remoteAddress?.port || "0";
|
|
18
|
+
return `${addr}:${port}`;
|
|
19
|
+
}, storage = (0, rateLimit_js_1.createRateLimitDefaultStorage)(), onError = (ctx, retryAfter, error) => {
|
|
7
20
|
ctx.setStatus = 429;
|
|
8
|
-
throw new
|
|
21
|
+
throw new error_js_1.TezXError(`Rate limit exceeded. Try again in ${retryAfter} seconds.`, 429);
|
|
9
22
|
}, } = options;
|
|
10
23
|
return async function rateLimiter(ctx, next) {
|
|
11
24
|
const key = keyGenerator(ctx);
|
|
12
|
-
const { check, entry } = (0, rateLimit_js_1.isRateLimit)(
|
|
25
|
+
const { check, entry } = (0, rateLimit_js_1.isRateLimit)(key, storage, maxRequests, windowMs);
|
|
13
26
|
if (check) {
|
|
14
27
|
const retryAfter = Math.ceil((entry.resetTime - Date.now()) / 1000);
|
|
15
|
-
ctx.
|
|
28
|
+
ctx.headers.set("Retry-After", retryAfter.toString());
|
|
16
29
|
return onError(ctx, retryAfter, new Error(`Rate limit exceeded. Retry after ${retryAfter} seconds.`));
|
|
17
30
|
}
|
|
18
|
-
ctx.
|
|
19
|
-
ctx.
|
|
20
|
-
ctx.
|
|
31
|
+
ctx.headers.set("X-RateLimit-Limit", maxRequests.toString());
|
|
32
|
+
ctx.headers.set("X-RateLimit-Remaining", (maxRequests - entry.count).toString());
|
|
33
|
+
ctx.headers.set("X-RateLimit-Reset", entry.resetTime.toString());
|
|
21
34
|
return await next();
|
|
22
35
|
};
|
|
23
36
|
};
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.requestID = exports.default = void 0;
|
|
4
4
|
const index_js_1 = require("../helper/index.js");
|
|
5
5
|
const requestID = (headerName = "X-Request-ID", contextKey = "requestID") => {
|
|
6
6
|
return function requestID(ctx, next) {
|
|
7
|
-
let requestId = ctx.
|
|
8
|
-
if (!requestId) {
|
|
9
|
-
requestId = `req-${(0, index_js_1.generateUUID)()}`;
|
|
10
|
-
}
|
|
7
|
+
let requestId = ctx.headers.get(headerName) ?? `req-${(0, index_js_1.generateUUID)()}`;
|
|
11
8
|
ctx[contextKey] = requestId;
|
|
12
|
-
ctx.
|
|
9
|
+
ctx.headers.set(headerName, requestId);
|
|
13
10
|
return next();
|
|
14
11
|
};
|
|
15
12
|
};
|
|
16
|
-
exports.requestID = requestID;
|
|
17
13
|
exports.default = requestID;
|
|
14
|
+
exports.requestID = requestID;
|
|
@@ -1,54 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.sanitizeHeaders = exports.default = void 0;
|
|
4
|
-
const config_js_1 = require("../core/config.js");
|
|
5
4
|
const sanitizeHeaders = (options = {}) => {
|
|
6
|
-
const { whitelist = [], blacklist = [],
|
|
5
|
+
const { whitelist = [], blacklist = [], } = options;
|
|
7
6
|
const normalizedWhitelist = whitelist.map((h) => h.toLowerCase());
|
|
8
7
|
const normalizedBlacklist = blacklist.map((h) => h.toLowerCase());
|
|
8
|
+
let lWhite = normalizedWhitelist.length;
|
|
9
9
|
return async function sanitizeHeaders(ctx, next) {
|
|
10
|
-
|
|
11
|
-
for (const key
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (normalizedWhitelist.length > 0 &&
|
|
15
|
-
!normalizedWhitelist.includes(normalizedKey)) {
|
|
16
|
-
config_js_1.GlobalConfig.debugging.warn(`🚫 Header "${key}" not in whitelist - removed`);
|
|
17
|
-
continue;
|
|
10
|
+
await next();
|
|
11
|
+
for (const key of ctx.headers.keys()) {
|
|
12
|
+
if (lWhite > 0 && !normalizedWhitelist.includes(key)) {
|
|
13
|
+
ctx.headers.delete(key);
|
|
18
14
|
}
|
|
19
|
-
if (normalizedBlacklist.includes(
|
|
20
|
-
|
|
21
|
-
continue;
|
|
15
|
+
if (normalizedBlacklist.includes(key)) {
|
|
16
|
+
ctx.headers.delete(key);
|
|
22
17
|
}
|
|
23
|
-
if (!isValidHeaderName(normalizedKey)) {
|
|
24
|
-
config_js_1.GlobalConfig.debugging.warn(`⚠️ Invalid header name: "${normalizedKey}" - removed`);
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
const sanitizedValue = sanitizeHeaderValue(value, allowUnsafeCharacters);
|
|
28
|
-
if (!sanitizedValue) {
|
|
29
|
-
config_js_1.GlobalConfig.debugging.warn(`⚠️ Header "${key}" has invalid/empty value - removed`);
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
sanitizedHeaders[normalizedKey] = sanitizedValue;
|
|
33
|
-
}
|
|
34
|
-
for (const k in sanitizedHeaders) {
|
|
35
|
-
let v = sanitizedHeaders[k];
|
|
36
|
-
ctx.setHeader(k, v);
|
|
37
18
|
}
|
|
38
|
-
ctx.clearHeader = sanitizedHeaders;
|
|
39
|
-
return await next();
|
|
40
19
|
};
|
|
41
20
|
};
|
|
42
21
|
exports.default = sanitizeHeaders;
|
|
43
22
|
exports.sanitizeHeaders = sanitizeHeaders;
|
|
44
|
-
const isValidHeaderName = (name) => {
|
|
45
|
-
const HEADER_NAME_REGEX = /^[a-zA-Z0-9\-_]+$/;
|
|
46
|
-
return HEADER_NAME_REGEX.test(name);
|
|
47
|
-
};
|
|
48
|
-
const sanitizeHeaderValue = (value, allowUnsafeCharacters) => {
|
|
49
|
-
let sanitized = value.trim();
|
|
50
|
-
if (!allowUnsafeCharacters) {
|
|
51
|
-
sanitized = sanitized.replace(/[\x00-\x1F\x7F]/g, "");
|
|
52
|
-
}
|
|
53
|
-
return sanitized;
|
|
54
|
-
};
|
|
@@ -1,27 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const config_js_1 = require("../core/config.js");
|
|
3
|
+
exports.xssProtection = exports.default = void 0;
|
|
5
4
|
const xssProtection = (options = {}) => {
|
|
6
5
|
const { enabled = true, mode = "block", fallbackCSP = "default-src 'self'; script-src 'self';", } = options;
|
|
7
6
|
return async function xssProtection(ctx, next) {
|
|
8
7
|
const isEnabled = typeof enabled === "function" ? enabled(ctx) : enabled;
|
|
9
8
|
if (!isEnabled) {
|
|
10
|
-
config_js_1.GlobalConfig.debugging.warn("🟠 XSS protection is disabled.");
|
|
11
9
|
return await next();
|
|
12
10
|
}
|
|
13
11
|
const xssHeaderValue = mode === "block" ? "1; mode=block" : "1";
|
|
14
12
|
ctx.setHeader("X-XSS-Protection", xssHeaderValue);
|
|
15
|
-
config_js_1.GlobalConfig.debugging.warn(`🟢 X-XSS-Protection set to: ${xssHeaderValue}`);
|
|
16
13
|
if (fallbackCSP) {
|
|
17
14
|
const existingCSP = ctx.req.header("content-security-policy");
|
|
18
15
|
if (!existingCSP) {
|
|
19
16
|
ctx.setHeader("Content-Security-Policy", fallbackCSP);
|
|
20
|
-
config_js_1.GlobalConfig.debugging.warn(`🟣 Fallback CSP set to: ${fallbackCSP}`);
|
|
21
17
|
}
|
|
22
18
|
}
|
|
23
19
|
return await next();
|
|
24
20
|
};
|
|
25
21
|
};
|
|
26
|
-
exports.xssProtection = xssProtection;
|
|
27
22
|
exports.default = xssProtection;
|
|
23
|
+
exports.xssProtection = xssProtection;
|