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.
Files changed (90) hide show
  1. package/bun/index.d.ts +4 -2
  2. package/bun/index.js +3 -2
  3. package/bun/ws.d.ts +37 -0
  4. package/bun/ws.js +23 -0
  5. package/cjs/bun/index.js +37 -5
  6. package/cjs/bun/ws.js +25 -0
  7. package/cjs/core/context.js +86 -88
  8. package/cjs/core/error.js +41 -0
  9. package/cjs/core/request.js +6 -6
  10. package/cjs/core/router.js +6 -6
  11. package/cjs/core/server.js +45 -63
  12. package/cjs/index.js +5 -2
  13. package/cjs/middleware/basic-auth.js +28 -54
  14. package/cjs/middleware/bearer-auth.js +34 -0
  15. package/cjs/middleware/cors.js +14 -24
  16. package/cjs/middleware/index.js +25 -0
  17. package/cjs/middleware/logger.js +6 -3
  18. package/cjs/middleware/pagination.js +1 -1
  19. package/cjs/middleware/powered-by.js +1 -1
  20. package/cjs/middleware/rate-limiter.js +20 -7
  21. package/cjs/middleware/request-id.js +4 -7
  22. package/cjs/middleware/sanitize-headers.js +8 -40
  23. package/cjs/middleware/xss-protection.js +2 -6
  24. package/cjs/registry/RadixRouter.js +72 -23
  25. package/cjs/utils/cookie.js +1 -1
  26. package/cjs/utils/rateLimit.js +2 -2
  27. package/cjs/utils/regexRouter.js +1 -0
  28. package/cjs/utils/response.js +21 -30
  29. package/core/context.d.ts +68 -68
  30. package/core/context.js +87 -89
  31. package/core/error.d.ts +95 -0
  32. package/core/error.js +37 -0
  33. package/core/request.d.ts +2 -2
  34. package/core/request.js +6 -6
  35. package/core/router.d.ts +11 -6
  36. package/core/router.js +6 -6
  37. package/core/server.js +45 -63
  38. package/index.d.ts +5 -3
  39. package/index.js +4 -2
  40. package/middleware/basic-auth.d.ts +38 -66
  41. package/middleware/basic-auth.js +28 -54
  42. package/middleware/bearer-auth.d.ts +52 -0
  43. package/middleware/bearer-auth.js +30 -0
  44. package/middleware/cors.d.ts +7 -21
  45. package/middleware/cors.js +14 -24
  46. package/middleware/index.d.ts +9 -0
  47. package/middleware/index.js +9 -0
  48. package/middleware/logger.d.ts +3 -1
  49. package/middleware/logger.js +6 -3
  50. package/middleware/pagination.d.ts +8 -6
  51. package/middleware/pagination.js +1 -1
  52. package/middleware/powered-by.js +1 -1
  53. package/middleware/rate-limiter.d.ts +0 -4
  54. package/middleware/rate-limiter.js +20 -7
  55. package/middleware/request-id.d.ts +1 -1
  56. package/middleware/request-id.js +3 -6
  57. package/middleware/sanitize-headers.d.ts +3 -11
  58. package/middleware/sanitize-headers.js +8 -40
  59. package/middleware/xss-protection.d.ts +1 -1
  60. package/middleware/xss-protection.js +1 -5
  61. package/package.json +6 -1
  62. package/registry/RadixRouter.js +72 -23
  63. package/types/index.d.ts +2 -1
  64. package/utils/cookie.js +1 -1
  65. package/utils/rateLimit.d.ts +1 -2
  66. package/utils/rateLimit.js +2 -2
  67. package/utils/regexRouter.js +1 -0
  68. package/utils/response.d.ts +12 -14
  69. package/utils/response.js +20 -29
  70. package/cjs/middleware/cache-control.js +0 -93
  71. package/cjs/middleware/detect-bot.js +0 -66
  72. package/cjs/middleware/detect-locale.js +0 -45
  73. package/cjs/middleware/i18n.js +0 -93
  74. package/cjs/middleware/lazy-loader.js +0 -74
  75. package/cjs/middleware/request-timeout.js +0 -43
  76. package/cjs/middleware/secure-headers.js +0 -43
  77. package/middleware/cache-control.d.ts +0 -56
  78. package/middleware/cache-control.js +0 -56
  79. package/middleware/detect-bot.d.ts +0 -111
  80. package/middleware/detect-bot.js +0 -62
  81. package/middleware/detect-locale.d.ts +0 -56
  82. package/middleware/detect-locale.js +0 -41
  83. package/middleware/i18n.d.ts +0 -102
  84. package/middleware/i18n.js +0 -89
  85. package/middleware/lazy-loader.d.ts +0 -73
  86. package/middleware/lazy-loader.js +0 -70
  87. package/middleware/request-timeout.d.ts +0 -26
  88. package/middleware/request-timeout.js +0 -39
  89. package/middleware/secure-headers.d.ts +0 -78
  90. package/middleware/secure-headers.js +0 -39
@@ -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 #resolvePath(pathname) {
31
- let resolvePath = pathname;
32
- if (this.#pathResolver) {
33
- resolvePath = await this.#pathResolver(pathname);
34
- config_js_1.GlobalConfig.debugging.warn(`${(0, colors_js_1.colorText)(" PATH RESOLVE ", "white")} ${(0, colors_js_1.colorText)(pathname, "red")} ➞ ${(0, colors_js_1.colorText)(resolvePath, "cyan")}`);
35
- }
36
- if (typeof resolvePath !== "string") {
37
- throw new Error(`Path resolution failed: expected a string, got ${typeof resolvePath}`);
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 at index ${i} must be a function`);
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
- const result = await fn(ctx, () => dispatch(i + 1));
60
- if (result instanceof Response) {
61
- ctx.res = result;
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
- await dispatch(0);
66
- return ctx.res;
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 = await this.#resolvePath((0, url_js_1.getPathname)(req.url));
74
- let ctx = new context_js_1.Context(req, {
75
- pathname,
76
- method,
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
- if (!route || (route.handlers.length === 0 && route.middlewares.length === 0)) {
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 (route.handlers.length === 1 && route.middlewares.length === 0) {
91
- const result = await route.handlers[0](ctx);
92
- if (result)
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
- if (!res) {
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
- return this.#errorHandler(err, ctx);
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.9-beta";
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.default = exports.basicAuth = void 0;
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 { validateCredentials, getRealm = () => "Restricted Area", onUnauthorized = (ctx, error) => {
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.body = { error: error?.message };
14
- }, rateLimit, supportedMethods = ["basic", "api-key", "bearer-token"], checkAccess, } = options;
15
- let storage = rateLimit?.storage;
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
- if (auth.startsWith("Basic ")) {
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
- else if (ctx.header("x-api-key")) {
37
- authMethod = "api-key";
38
- credentials = { apiKey: ctx.header("x-api-key") };
16
+ const base64 = auth.slice(6).trim();
17
+ if (!base64) {
18
+ return onUnauthorized(ctx, new Error("Empty credentials"));
39
19
  }
40
- if (!authMethod || !supportedMethods.includes(authMethod)) {
41
- config_js_1.GlobalConfig.debugging.error(`${(0, colors_js_1.colorText)("[AUTH]", "bgRed")} Unsupported or missing authentication method.`);
42
- return onUnauthorized(ctx, new Error("Unsupported authentication method"));
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
- if (rateLimit) {
45
- let key = `${ctx.req.remoteAddress.address}:${ctx.req.remoteAddress.port}`;
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 isValid = await validateCredentials(authMethod, credentials, ctx);
55
- if (!isValid) {
56
- throw new Error("Invalid credentials.");
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
- return await next();
37
+ ctx.user = { username };
38
+ await next();
65
39
  }
66
- catch (error) {
67
- config_js_1.GlobalConfig.debugging.error(`${(0, colors_js_1.colorText)("[AUTH]", "bgRed")} Failure for method: ${ctx.method}`);
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;
@@ -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 { methods, allowedHeaders, credentials, exposedHeaders, maxAge, origin, } = option;
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
- const isAllowed = origin.some((item) => {
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.setHeader("Access-Control-Allow-Origin", allowOrigin);
31
- ctx.setHeader("Access-Control-Allow-Methods", (methods || ["GET", "POST", "PUT", "DELETE"]).join(", "));
32
- ctx.setHeader("Access-Control-Allow-Headers", (allowedHeaders || ["Content-Type", "Authorization"]).join(", "));
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.setHeader("Access-Control-Expose-Headers", exposedHeaders.join(", "));
26
+ ctx.headers.set("Access-Control-Expose-Headers", exposedHeaders);
35
27
  }
36
28
  if (credentials) {
37
- ctx.setHeader("Access-Control-Allow-Credentials", "true");
29
+ ctx.headers.set("Access-Control-Allow-Credentials", "true");
38
30
  }
39
31
  if (maxAge) {
40
- ctx.setHeader("Access-Control-Max-Age", maxAge.toString());
32
+ ctx.headers.set("Access-Control-Max-Age", maxAge.toString());
41
33
  }
42
- if (ctx.req.method === "OPTIONS") {
43
- return new Response(null, {
44
- status: 204,
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);
@@ -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
- const { defaultPage = 1, defaultLimit = 10, maxLimit = 100, queryKeyPage = "page", queryKeyLimit = "limit", countKey = "total", dataKey = "data", getDataSource, } = options;
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.setHeader("x-powered-by", serverName || "TezX");
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) => `${ctx.req.remoteAddress.address}:${ctx.req.remoteAddress.port}`, storage = (0, rateLimit_js_1.createRateLimitDefaultStorage)(), onError = (ctx, retryAfter, error) => {
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 Error(`Rate limit exceeded. Try again in ${retryAfter} seconds.`);
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)(ctx, key, storage, maxRequests, windowMs);
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.setHeader("Retry-After", retryAfter.toString());
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.setHeader("X-RateLimit-Limit", maxRequests.toString());
19
- ctx.setHeader("X-RateLimit-Remaining", (maxRequests - entry.count).toString());
20
- ctx.setHeader("X-RateLimit-Reset", entry.resetTime.toString());
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.default = exports.requestID = void 0;
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.header(headerName);
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.setHeader(headerName, requestId);
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 = [], allowUnsafeCharacters = false, } = options;
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
- const sanitizedHeaders = {};
11
- for (const key in ctx.header()) {
12
- let value = ctx.header(key);
13
- const normalizedKey = key.toLowerCase();
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(normalizedKey)) {
20
- config_js_1.GlobalConfig.debugging.warn(`🚫 Header "${key}" in blacklist - removed`);
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.default = exports.xssProtection = void 0;
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;