tezx 2.0.11 → 3.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.
Files changed (234) hide show
  1. package/README.md +122 -89
  2. package/bun/getConnInfo.d.ts +21 -0
  3. package/bun/getConnInfo.js +9 -0
  4. package/bun/index.d.ts +10 -4
  5. package/bun/index.js +8 -4
  6. package/bun/ws.d.ts +48 -0
  7. package/bun/ws.js +58 -0
  8. package/cjs/bun/getConnInfo.js +12 -0
  9. package/cjs/bun/index.js +35 -7
  10. package/cjs/bun/ws.js +63 -0
  11. package/cjs/core/config.js +2 -12
  12. package/cjs/core/context.js +131 -379
  13. package/cjs/core/error.js +49 -0
  14. package/cjs/core/request.js +79 -131
  15. package/cjs/core/router.js +54 -387
  16. package/cjs/core/server.js +83 -202
  17. package/cjs/deno/env.js +4 -4
  18. package/cjs/deno/getConnInfo.js +18 -0
  19. package/cjs/deno/index.js +11 -18
  20. package/cjs/deno/serveStatic.js +53 -0
  21. package/cjs/deno/ws.js +39 -0
  22. package/cjs/helper/index.js +46 -10
  23. package/cjs/index.js +5 -7
  24. package/cjs/jwt/node.js +94 -0
  25. package/cjs/jwt/web.js +178 -0
  26. package/cjs/middleware/basic-auth.js +42 -0
  27. package/cjs/middleware/bearer-auth.js +34 -0
  28. package/cjs/middleware/cache-control.js +44 -0
  29. package/cjs/middleware/cors.js +11 -21
  30. package/cjs/middleware/detect-bot.js +57 -0
  31. package/cjs/middleware/i18n.js +73 -60
  32. package/cjs/middleware/index.js +8 -46
  33. package/cjs/middleware/logger.js +9 -4
  34. package/cjs/middleware/pagination.js +3 -2
  35. package/cjs/middleware/powered-by.js +3 -2
  36. package/cjs/middleware/rate-limiter.js +38 -0
  37. package/cjs/middleware/request-id.js +4 -5
  38. package/cjs/middleware/sanitize-headers.js +22 -0
  39. package/cjs/middleware/secure-headers copy.js +143 -0
  40. package/cjs/middleware/secure-headers.js +157 -0
  41. package/cjs/middleware/{xssProtection.js → xss-protection.js} +5 -8
  42. package/cjs/node/env.js +7 -7
  43. package/cjs/node/getConnInfo.js +16 -0
  44. package/cjs/node/index.js +17 -18
  45. package/cjs/node/mount-node.js +59 -0
  46. package/cjs/node/serveStatic.js +56 -0
  47. package/cjs/node/toWebRequest.js +25 -0
  48. package/cjs/node/ws.js +82 -0
  49. package/cjs/registry/RadixRouter.js +148 -0
  50. package/cjs/registry/index.js +17 -0
  51. package/cjs/types/headers.js +2 -0
  52. package/cjs/types/index.js +13 -0
  53. package/cjs/utils/buffer.js +17 -0
  54. package/cjs/utils/colors.js +2 -0
  55. package/cjs/utils/cookie.js +59 -0
  56. package/cjs/utils/file.js +136 -0
  57. package/cjs/utils/formData.js +60 -10
  58. package/cjs/utils/generateID.js +37 -0
  59. package/cjs/utils/low-level.js +115 -0
  60. package/cjs/utils/{staticFile.js → mimeTypes.js} +0 -87
  61. package/cjs/utils/rateLimit.js +41 -0
  62. package/cjs/utils/response.js +65 -0
  63. package/cjs/{core/environment.js → utils/runtime.js} +2 -1
  64. package/cjs/utils/url.js +65 -30
  65. package/core/config.d.ts +2 -7
  66. package/core/config.js +2 -12
  67. package/core/context.d.ts +209 -164
  68. package/core/context.js +131 -346
  69. package/core/error.d.ts +96 -0
  70. package/core/error.js +44 -0
  71. package/core/request.d.ts +67 -107
  72. package/core/request.js +78 -130
  73. package/core/router.d.ts +138 -133
  74. package/core/router.js +53 -352
  75. package/core/server.d.ts +99 -38
  76. package/core/server.js +83 -202
  77. package/deno/env.js +3 -3
  78. package/deno/getConnInfo.d.ts +21 -0
  79. package/deno/getConnInfo.js +15 -0
  80. package/deno/index.d.ts +9 -4
  81. package/deno/index.js +7 -4
  82. package/deno/serveStatic.d.ts +28 -0
  83. package/deno/serveStatic.js +49 -0
  84. package/deno/ws.d.ts +42 -0
  85. package/deno/ws.js +36 -0
  86. package/helper/index.d.ts +29 -15
  87. package/helper/index.js +27 -7
  88. package/index.d.ts +10 -8
  89. package/index.js +4 -5
  90. package/jwt/node.d.ts +39 -0
  91. package/jwt/node.js +87 -0
  92. package/jwt/web.d.ts +14 -0
  93. package/jwt/web.js +174 -0
  94. package/middleware/basic-auth.d.ts +56 -0
  95. package/middleware/basic-auth.js +38 -0
  96. package/middleware/bearer-auth.d.ts +53 -0
  97. package/middleware/bearer-auth.js +30 -0
  98. package/middleware/cache-control.d.ts +30 -0
  99. package/middleware/cache-control.js +40 -0
  100. package/middleware/cors.d.ts +30 -3
  101. package/middleware/cors.js +12 -22
  102. package/middleware/detect-bot.d.ts +113 -0
  103. package/middleware/detect-bot.js +53 -0
  104. package/middleware/i18n.d.ts +166 -73
  105. package/middleware/i18n.js +73 -60
  106. package/middleware/index.d.ts +8 -32
  107. package/middleware/index.js +8 -44
  108. package/middleware/logger.d.ts +5 -2
  109. package/middleware/logger.js +9 -4
  110. package/middleware/pagination.d.ts +9 -6
  111. package/middleware/pagination.js +3 -2
  112. package/middleware/powered-by.d.ts +2 -1
  113. package/middleware/powered-by.js +3 -2
  114. package/middleware/{rateLimiter.d.ts → rate-limiter.d.ts} +15 -9
  115. package/middleware/rate-limiter.js +34 -0
  116. package/middleware/request-id.d.ts +2 -1
  117. package/middleware/request-id.js +5 -6
  118. package/middleware/{sanitizeHeader.d.ts → sanitize-headers.d.ts} +5 -19
  119. package/middleware/sanitize-headers.js +18 -0
  120. package/middleware/secure-headers copy.d.ts +15 -0
  121. package/middleware/secure-headers copy.js +136 -0
  122. package/middleware/secure-headers.d.ts +132 -0
  123. package/middleware/secure-headers.js +153 -0
  124. package/middleware/{xssProtection.d.ts → xss-protection.d.ts} +2 -1
  125. package/middleware/xss-protection.js +19 -0
  126. package/node/env.js +4 -4
  127. package/node/getConnInfo.d.ts +21 -0
  128. package/node/getConnInfo.js +13 -0
  129. package/node/index.d.ts +13 -4
  130. package/node/index.js +11 -4
  131. package/node/mount-node.d.ts +11 -0
  132. package/node/mount-node.js +56 -0
  133. package/node/serveStatic.d.ts +36 -0
  134. package/node/serveStatic.js +52 -0
  135. package/node/toWebRequest.js +22 -0
  136. package/node/ws.d.ts +56 -0
  137. package/node/ws.js +46 -0
  138. package/package.json +39 -30
  139. package/registry/RadixRouter.d.ts +40 -0
  140. package/registry/RadixRouter.js +144 -0
  141. package/registry/index.d.ts +2 -0
  142. package/registry/index.js +1 -0
  143. package/types/headers.d.ts +2 -0
  144. package/types/headers.js +1 -0
  145. package/types/index.d.ts +318 -18
  146. package/types/index.js +12 -1
  147. package/utils/buffer.d.ts +1 -0
  148. package/utils/buffer.js +14 -0
  149. package/utils/colors.d.ts +24 -0
  150. package/utils/colors.js +2 -0
  151. package/utils/cookie.d.ts +55 -0
  152. package/utils/cookie.js +53 -0
  153. package/utils/file.d.ts +38 -0
  154. package/utils/file.js +96 -0
  155. package/utils/formData.d.ts +41 -1
  156. package/utils/formData.js +58 -9
  157. package/utils/generateID.d.ts +42 -0
  158. package/utils/generateID.js +32 -0
  159. package/utils/httpStatusMap.d.ts +14 -0
  160. package/utils/low-level.d.ts +58 -0
  161. package/utils/low-level.js +108 -0
  162. package/utils/mimeTypes.d.ts +4 -0
  163. package/utils/{staticFile.js → mimeTypes.js} +0 -53
  164. package/utils/rateLimit.d.ts +18 -0
  165. package/utils/rateLimit.js +37 -0
  166. package/utils/response.d.ts +18 -0
  167. package/utils/response.js +58 -0
  168. package/{core/environment.d.ts → utils/runtime.d.ts} +1 -0
  169. package/{core/environment.js → utils/runtime.js} +1 -0
  170. package/utils/url.d.ts +42 -14
  171. package/utils/url.js +61 -27
  172. package/bun/adapter.d.ts +0 -127
  173. package/bun/adapter.js +0 -97
  174. package/cjs/bun/adapter.js +0 -100
  175. package/cjs/core/MiddlewareConfigure.js +0 -68
  176. package/cjs/core/common.js +0 -15
  177. package/cjs/deno/adpater.js +0 -67
  178. package/cjs/helper/common.js +0 -17
  179. package/cjs/middleware/basicAuth.js +0 -71
  180. package/cjs/middleware/cacheControl.js +0 -90
  181. package/cjs/middleware/detectBot.js +0 -104
  182. package/cjs/middleware/detectLocale.js +0 -43
  183. package/cjs/middleware/lazyLoadModules.js +0 -73
  184. package/cjs/middleware/rateLimiter.js +0 -24
  185. package/cjs/middleware/requestTimeout.js +0 -42
  186. package/cjs/middleware/sanitizeHeader.js +0 -51
  187. package/cjs/middleware/secureHeaders.js +0 -42
  188. package/cjs/node/adapter.js +0 -138
  189. package/cjs/utils/regexRouter.js +0 -58
  190. package/cjs/utils/state.js +0 -34
  191. package/cjs/utils/toWebRequest.js +0 -35
  192. package/cjs/ws/deno.js +0 -20
  193. package/cjs/ws/index.js +0 -53
  194. package/cjs/ws/node.js +0 -65
  195. package/core/MiddlewareConfigure.d.ts +0 -15
  196. package/core/MiddlewareConfigure.js +0 -63
  197. package/core/common.d.ts +0 -21
  198. package/core/common.js +0 -11
  199. package/deno/adpater.d.ts +0 -38
  200. package/deno/adpater.js +0 -64
  201. package/helper/common.d.ts +0 -5
  202. package/helper/common.js +0 -14
  203. package/middleware/basicAuth.d.ts +0 -81
  204. package/middleware/basicAuth.js +0 -67
  205. package/middleware/cacheControl.d.ts +0 -48
  206. package/middleware/cacheControl.js +0 -53
  207. package/middleware/detectBot.d.ts +0 -121
  208. package/middleware/detectBot.js +0 -98
  209. package/middleware/detectLocale.d.ts +0 -55
  210. package/middleware/detectLocale.js +0 -39
  211. package/middleware/lazyLoadModules.d.ts +0 -72
  212. package/middleware/lazyLoadModules.js +0 -69
  213. package/middleware/rateLimiter.js +0 -20
  214. package/middleware/requestTimeout.d.ts +0 -25
  215. package/middleware/requestTimeout.js +0 -38
  216. package/middleware/sanitizeHeader.js +0 -47
  217. package/middleware/secureHeaders.d.ts +0 -78
  218. package/middleware/secureHeaders.js +0 -38
  219. package/middleware/xssProtection.js +0 -22
  220. package/node/adapter.d.ts +0 -46
  221. package/node/adapter.js +0 -102
  222. package/utils/regexRouter.d.ts +0 -66
  223. package/utils/regexRouter.js +0 -53
  224. package/utils/state.d.ts +0 -50
  225. package/utils/state.js +0 -30
  226. package/utils/staticFile.d.ts +0 -10
  227. package/utils/toWebRequest.js +0 -32
  228. package/ws/deno.d.ts +0 -6
  229. package/ws/deno.js +0 -16
  230. package/ws/index.d.ts +0 -180
  231. package/ws/index.js +0 -50
  232. package/ws/node.d.ts +0 -7
  233. package/ws/node.js +0 -28
  234. /package/{utils → node}/toWebRequest.d.ts +0 -0
@@ -1,75 +1,88 @@
1
- import { GlobalConfig } from "../core/config.js";
2
- export const i18n = (options) => {
3
- const { loadTranslations, defaultCacheDuration = 3600000, isCacheValid = (cached) => cached.expiresAt > Date.now(), detectLanguage = (ctx) => ctx.req.query.lang ||
4
- ctx.cookies?.get("lang") ||
5
- ctx.req.headers.get("accept-language")?.split(",")[0] ||
6
- options.defaultLanguage ||
7
- "en", defaultLanguage = "en", fallbackChain = [], translationFunctionKey = "t", formatMessage = (message, options = {}) => {
8
- return Object.entries(options).reduce((msg, [key, value]) => msg.replace(new RegExp(`{{${key}}}`, "g"), String(value)), message);
9
- }, cacheTranslations = true, } = options;
10
- const translationCache = {};
1
+ import { TezXError } from "../index.js";
2
+ const i18n = (options) => {
3
+ const { loadTranslations, defaultCacheDuration = 3600000, detectLanguage, defaultLanguage = "en", translationFunctionKey = "t", formatMessage = (msg, vars = {}) => {
4
+ if (vars && msg.indexOf("{{") !== -1) {
5
+ let out = "";
6
+ let i = 0;
7
+ while (i < msg.length) {
8
+ const startVar = msg.indexOf("{{", i);
9
+ if (startVar === -1) {
10
+ out += msg.slice(i);
11
+ break;
12
+ }
13
+ const endVar = msg.indexOf("}}", startVar + 2);
14
+ if (endVar === -1) {
15
+ out += msg.slice(i);
16
+ break;
17
+ }
18
+ out += msg.slice(i, startVar);
19
+ const keyVar = msg.slice(startVar + 2, endVar).trim();
20
+ out += vars[keyVar] !== undefined ? String(vars[keyVar]) : "";
21
+ i = endVar + 2;
22
+ }
23
+ return out;
24
+ }
25
+ return msg;
26
+ }, isCacheValid = (cached) => cached.expiresAt > Date.now(), cacheTranslations = false, cacheStorage: externalCache = null, } = options;
27
+ let localCache = null;
28
+ if (cacheTranslations && !externalCache)
29
+ localCache = new Map();
11
30
  return async function i18n(ctx, next) {
12
31
  try {
13
- const detectedLanguage = detectLanguage(ctx);
14
- const languageChain = [
15
- detectedLanguage,
16
- ...fallbackChain,
17
- defaultLanguage,
18
- ].filter(Boolean);
19
- let translations = null;
20
- let selectedLanguage = defaultLanguage;
21
- for (const lang of languageChain) {
22
- const normalizedLang = lang.split("-")[0].toLowerCase();
23
- if (cacheTranslations && translationCache[normalizedLang]) {
24
- const cached = translationCache[normalizedLang];
25
- if (isCacheValid(cached, normalizedLang)) {
32
+ const lang = detectLanguage(ctx) ?? defaultLanguage;
33
+ let translations = undefined;
34
+ if (cacheTranslations) {
35
+ if (externalCache) {
36
+ const cached = await externalCache.get(lang);
37
+ if (cached && isCacheValid(cached, lang))
26
38
  translations = cached.translations;
27
- selectedLanguage = lang;
28
- break;
29
- }
30
- delete translationCache[normalizedLang];
31
- }
32
- try {
33
- const { translations: loadedTranslations, expiresAt } = await loadTranslations(normalizedLang);
34
- let expirationTime = Date.now() + defaultCacheDuration;
35
- if (expiresAt instanceof Date) {
36
- expirationTime = expiresAt.getTime();
37
- }
38
- else if (typeof expiresAt === "number") {
39
- expirationTime = expiresAt;
40
- }
41
- translations = loadedTranslations;
42
- selectedLanguage = lang;
43
- if (cacheTranslations) {
44
- translationCache[normalizedLang] = {
45
- translations,
46
- expiresAt: expirationTime,
47
- };
48
- }
49
- break;
50
39
  }
51
- catch (error) {
52
- GlobalConfig.debugging.warn(`Translation load failed for ${lang}:`, error);
40
+ else if (localCache?.get(lang)) {
41
+ const cached = localCache.get(lang);
42
+ if (isCacheValid(cached, lang))
43
+ translations = cached.translations;
44
+ else
45
+ localCache.delete(lang);
53
46
  }
54
47
  }
55
48
  if (!translations) {
56
- throw new Error("No translations available");
49
+ translations = await loadTranslations(lang);
50
+ const expiresAt = Date.now() + defaultCacheDuration;
51
+ if (cacheTranslations) {
52
+ if (externalCache) {
53
+ await externalCache.set(lang, { translations, expiresAt });
54
+ }
55
+ else {
56
+ localCache?.set(lang, { translations, expiresAt });
57
+ }
58
+ }
57
59
  }
58
- ctx[translationFunctionKey] = (key, options) => {
59
- const value = key.split(".").reduce((acc, k) => {
60
- return acc && typeof acc === "object" ? acc[k] : undefined;
61
- }, translations);
62
- const message = typeof value === "string" ? value : key;
63
- return formatMessage(message, options);
60
+ ctx[translationFunctionKey] = function translate(key, vars) {
61
+ let acc = translations;
62
+ let start = 0;
63
+ for (let i = 0; i <= key.length; i++) {
64
+ const c = key.charCodeAt(i);
65
+ if (c === 46 || i === key.length) {
66
+ const segment = key.slice(start, i);
67
+ if (acc && typeof acc === "object") {
68
+ acc = acc[segment];
69
+ }
70
+ else {
71
+ acc = undefined;
72
+ break;
73
+ }
74
+ start = i + 1;
75
+ }
76
+ }
77
+ let msg = typeof acc === "string" ? acc : key;
78
+ return formatMessage(msg, vars);
64
79
  };
65
- ctx.language = selectedLanguage;
66
- ctx.languageChain = languageChain;
80
+ ctx.language = lang;
67
81
  return await next();
68
82
  }
69
83
  catch (error) {
70
- GlobalConfig.debugging.error("i18n processing error:", error);
71
- ctx.setStatus = 500;
72
- throw error;
84
+ throw new TezXError(error?.message ?? "i18n failed", 500, error?.stack);
73
85
  }
74
86
  };
75
87
  };
88
+ export { i18n as default, i18n };
@@ -1,38 +1,14 @@
1
- import { cors } from "./cors.js";
2
- import { logger } from "./logger.js";
3
- export * from "./basicAuth.js";
4
- export * from "./cacheControl.js";
1
+ export * from "./basic-auth.js";
2
+ export * from "./bearer-auth.js";
3
+ export * from "./cache-control.js";
5
4
  export * from "./cors.js";
6
- export { detectBot } from "./detectBot.js";
7
- export type { DetectBotReason } from "./detectBot.js";
8
- export * from "./detectLocale.js";
5
+ export * from "./detect-bot.js";
9
6
  export * from "./i18n.js";
10
- export * from "./lazyLoadModules.js";
11
7
  export * from "./logger.js";
12
8
  export * from "./pagination.js";
13
9
  export * from "./powered-by.js";
14
- export * from "./rateLimiter.js";
10
+ export * from "./rate-limiter.js";
15
11
  export * from "./request-id.js";
16
- export * from "./requestTimeout.js";
17
- export * from "./sanitizeHeader.js";
18
- export * from "./secureHeaders.js";
19
- export * from "./xssProtection.js";
20
- declare const _default: {
21
- basicAuth: (options: import("./basicAuth.js").DynamicBasicAuthOptions) => import("../index.js").Middleware;
22
- cacheControl: (options: import("./cacheControl.js").CacheOptions) => import("../index.js").Middleware;
23
- cors: typeof cors;
24
- detectBot: (options?: import("./detectBot.js").DetectBotOptions) => import("../index.js").Middleware;
25
- detectLocale: (options: import("./detectLocale.js").DetectLocaleOptions) => import("../index.js").Middleware;
26
- i18n: (options: import("./i18n.js").I18nOptions) => import("../index.js").Middleware;
27
- lazyLoadModules: <T = any>(options: import("./lazyLoadModules.js").LazyLoadOptions<T>) => import("../index.js").Middleware;
28
- logger: typeof logger;
29
- paginationHandler: (options?: import("./pagination.js").PaginationOptions) => import("../index.js").Middleware;
30
- poweredBy: (serverName?: string) => import("../index.js").Middleware;
31
- rateLimiter: (options: import("./rateLimiter.js").RateLimiterOptions) => import("../index.js").Middleware;
32
- requestID: (headerName?: string, contextKey?: string) => import("../index.js").Middleware;
33
- requestTimeout: (options: import("./requestTimeout.js").TimeoutOptions) => import("../index.js").Middleware;
34
- sanitizeHeaders: (options?: import("./sanitizeHeader.js").SanitizeHeadersOptions) => import("../index.js").Middleware;
35
- secureHeaders: (options?: import("./secureHeaders.js").SecurityHeaderOptions) => import("../index.js").Middleware;
36
- xssProtection: (options?: import("./xssProtection.js").XSSProtectionOptions) => (ctx: import("../index.js").BaseContext, next: import("../index.js").NextCallback) => Promise<any>;
37
- };
38
- export default _default;
12
+ export * from "./sanitize-headers.js";
13
+ export * from "./secure-headers.js";
14
+ export * from "./xss-protection.js";
@@ -1,50 +1,14 @@
1
- import { basicAuth } from "./basicAuth.js";
2
- import { cacheControl } from "./cacheControl.js";
3
- import { cors } from "./cors.js";
4
- import { detectBot } from "./detectBot.js";
5
- import { detectLocale } from "./detectLocale.js";
6
- import { i18n } from "./i18n.js";
7
- import { lazyLoadModules } from "./lazyLoadModules.js";
8
- import { logger } from "./logger.js";
9
- import { paginationHandler } from "./pagination.js";
10
- import { poweredBy } from "./powered-by.js";
11
- import { rateLimiter } from "./rateLimiter.js";
12
- import { requestID } from "./request-id.js";
13
- import { requestTimeout } from "./requestTimeout.js";
14
- import { sanitizeHeaders } from "./sanitizeHeader.js";
15
- import { secureHeaders } from "./secureHeaders.js";
16
- import { xssProtection } from "./xssProtection.js";
17
- export * from "./basicAuth.js";
18
- export * from "./cacheControl.js";
1
+ export * from "./basic-auth.js";
2
+ export * from "./bearer-auth.js";
3
+ export * from "./cache-control.js";
19
4
  export * from "./cors.js";
20
- export { detectBot } from "./detectBot.js";
21
- export * from "./detectLocale.js";
5
+ export * from "./detect-bot.js";
22
6
  export * from "./i18n.js";
23
- export * from "./lazyLoadModules.js";
24
7
  export * from "./logger.js";
25
8
  export * from "./pagination.js";
26
9
  export * from "./powered-by.js";
27
- export * from "./rateLimiter.js";
10
+ export * from "./rate-limiter.js";
28
11
  export * from "./request-id.js";
29
- export * from "./requestTimeout.js";
30
- export * from "./sanitizeHeader.js";
31
- export * from "./secureHeaders.js";
32
- export * from "./xssProtection.js";
33
- export default {
34
- basicAuth,
35
- cacheControl,
36
- cors,
37
- detectBot,
38
- detectLocale,
39
- i18n,
40
- lazyLoadModules,
41
- logger,
42
- paginationHandler,
43
- poweredBy,
44
- rateLimiter,
45
- requestID,
46
- requestTimeout,
47
- sanitizeHeaders,
48
- secureHeaders,
49
- xssProtection,
50
- };
12
+ export * from "./sanitize-headers.js";
13
+ export * from "./secure-headers.js";
14
+ export * from "./xss-protection.js";
@@ -7,9 +7,12 @@ import { Middleware } from "../types/index.js";
7
7
  *
8
8
  * @example
9
9
  * ```ts
10
- * import { logger } from 'tezx';
10
+ * import { logger } from 'tezx/logger';
11
11
  *
12
12
  * app.use(logger());
13
13
  * ```
14
14
  */
15
- export declare function logger(): Middleware;
15
+ declare function logger(options?: {
16
+ enabled: boolean;
17
+ }): Middleware;
18
+ export { logger as default, logger };
@@ -1,18 +1,23 @@
1
+ import { TezXError } from "../core/error.js";
1
2
  import { colorText } from "../utils/colors.js";
2
- export function logger() {
3
+ function logger(options = { enabled: true }) {
3
4
  return async function logger(ctx, next) {
4
5
  try {
6
+ if (!options?.enabled) {
7
+ return next();
8
+ }
5
9
  console.log(`${colorText("<--", "bold")} ${colorText(ctx.method, "bgMagenta")} ${ctx.pathname}`);
6
10
  const startTime = performance.now();
7
- let n = await next();
11
+ let n = (await next());
8
12
  const elapsed = performance.now() - startTime;
9
13
  console.log(`${colorText("-->", "bold")} ${colorText(ctx.method, "bgBlue")} ${ctx.pathname} ` +
10
- `${colorText(ctx.getStatus, "yellow")} ${colorText(`${elapsed.toFixed(2)}ms`, "magenta")}`);
14
+ `${colorText(n ? ctx.getStatus : 404, "yellow")} ${colorText(`${elapsed.toFixed(2)}ms`, "magenta")}`);
11
15
  return n;
12
16
  }
13
17
  catch (err) {
14
18
  console.error(`${colorText("Error:", "red")}`, err.stack);
15
- throw new Error(err.stack);
19
+ throw new TezXError(err.stack);
16
20
  }
17
21
  };
18
22
  }
23
+ export { logger as default, logger };
@@ -1,5 +1,5 @@
1
- import { Context, Middleware } from "../index.js";
2
- export type PaginationOptions = {
1
+ import { Context } from "../index.js";
2
+ export type PaginationOptions<DataKey extends string = "data", CountKey extends string = "total", Item = any> = {
3
3
  /**
4
4
  * 🔢 Default page number when not specified
5
5
  * @default 1
@@ -35,13 +35,13 @@ export type PaginationOptions = {
35
35
  * @default "total"
36
36
  * @example "totalCount" // Read from response.totalCount
37
37
  */
38
- countKey?: string;
38
+ countKey?: CountKey;
39
39
  /**
40
40
  * 📦 Key containing the data array in response
41
41
  * @default "data"
42
42
  * @example "items" // Process response.items array
43
43
  */
44
- dataKey?: string;
44
+ dataKey?: DataKey;
45
45
  /**
46
46
  * 🛠️ Function to fetch data dynamically
47
47
  * @param ctx - Request context
@@ -57,7 +57,9 @@ export type PaginationOptions = {
57
57
  limit: number;
58
58
  offset: number;
59
59
  }) => Promise<{
60
- [key: string]: any;
60
+ [K in DataKey]: Item[];
61
+ } & {
62
+ [K in CountKey]: number;
61
63
  }>;
62
64
  };
63
65
  export type PaginationBodyType = {
@@ -100,4 +102,5 @@ export type PaginationBodyType = {
100
102
  * }
101
103
  * }));
102
104
  */
103
- export declare const paginationHandler: (options?: PaginationOptions) => Middleware;
105
+ declare const paginationHandler: <DataKey extends string = "data", CountKey extends string = "total", Item = any>(options?: PaginationOptions<DataKey, CountKey, Item>) => any;
106
+ export { paginationHandler, paginationHandler as default };
@@ -1,5 +1,5 @@
1
- export const paginationHandler = (options = {}) => {
2
- const { defaultPage = 1, defaultLimit = 10, maxLimit = 100, queryKeyPage = "page", queryKeyLimit = "limit", countKey = "total", dataKey = "data", getDataSource, } = options;
1
+ const paginationHandler = (options = {}) => {
2
+ let { defaultPage = 1, defaultLimit = 10, maxLimit = 100, queryKeyPage = "page", queryKeyLimit = "limit", countKey = "total", dataKey = "data", getDataSource, } = options;
3
3
  return async function paginationHandler(ctx, next) {
4
4
  const rawPage = ctx.req.query[queryKeyPage];
5
5
  const rawLimit = ctx.req.query[queryKeyLimit];
@@ -47,3 +47,4 @@ export const paginationHandler = (options = {}) => {
47
47
  return await next();
48
48
  };
49
49
  };
50
+ export { paginationHandler, paginationHandler as default };
@@ -13,4 +13,5 @@ import { Middleware } from "../types/index.js";
13
13
  * app.use(poweredBy("MyServer"));
14
14
  * ```
15
15
  */
16
- export declare const poweredBy: (serverName?: string) => Middleware;
16
+ declare const poweredBy: (serverName?: string) => Middleware;
17
+ export { poweredBy, poweredBy as default };
@@ -1,6 +1,7 @@
1
- export const poweredBy = (serverName) => {
1
+ const poweredBy = (serverName) => {
2
2
  return function poweredBy(ctx, next) {
3
- ctx.header("X-Powered-By", serverName || "TezX");
3
+ ctx.headers.set("x-powered-by", serverName || "TezX");
4
4
  return next();
5
5
  };
6
6
  };
7
+ export { poweredBy, poweredBy as default };
@@ -1,5 +1,6 @@
1
1
  import { Context } from "../core/context.js";
2
- import { CallbackReturn, Middleware } from "../types/index.js";
2
+ import { TezXError } from "../core/error.js";
3
+ import { HttpBaseResponse, Middleware } from "../types/index.js";
3
4
  export type RateLimiterOptions = {
4
5
  /**
5
6
  * 🔴 Maximum allowed requests in the time window
@@ -20,10 +21,6 @@ export type RateLimiterOptions = {
20
21
  * keyGenerator: (ctx) => ctx.user?.id || ctx.ip // Use user ID if authenticated
21
22
  */
22
23
  keyGenerator?: (ctx: Context) => string;
23
- /**
24
- // * ⚠️ (Future) Storage backend - currently memory only
25
- // * @todo Implement Redis storage
26
- // */
27
24
  /**
28
25
  * 🔄 Custom cache storage implementation (e.g., using `Map`, `Redis`, etc.).
29
26
  * By default, it uses a `Map<string, { count: number; resetTime: number }>`.
@@ -45,17 +42,25 @@ export type RateLimiterOptions = {
45
42
  * @example
46
43
  * onError: (ctx, retryAfter) => {
47
44
  * ctx.status = 429;
48
- * throw new Error( `Rate limit exceeded. Try again in ${retryAfter} seconds.`);
45
+ * throw new TezXError( `Rate limit exceeded. Try again in ${retryAfter} seconds.`);
49
46
  * }
50
47
  */
51
- onError?: (ctx: Context, retryAfter: number, error: Error) => CallbackReturn;
48
+ onError?: (ctx: Context, retryAfter: number, error: TezXError) => HttpBaseResponse;
52
49
  };
53
50
  /**
54
51
  * 🚦 Rate limiting middleware for request throttling
55
52
  *
56
53
  * Enforces maximum request limits per client with sliding window.
57
54
  * Currently supports in-memory storage only (Redis coming soon).
58
- *
55
+ * @requires
56
+ * *
57
+ ```ts
58
+ import { getConnInfo } from "tezx/bun";
59
+ // or
60
+ import { getConnInfo } from "tezx/deno";
61
+ // or
62
+ import { getConnInfo } from "tezx/node";
63
+ ```
59
64
  * @param {RateLimiterOptions} options - Configuration
60
65
  * @returns {Middleware} Middleware function
61
66
  *
@@ -73,4 +78,5 @@ export type RateLimiterOptions = {
73
78
  * keyGenerator: (ctx) => ctx.user?.id || ctx.ip
74
79
  * }));
75
80
  */
76
- export declare const rateLimiter: (options: RateLimiterOptions) => Middleware;
81
+ declare const rateLimiter: (options: RateLimiterOptions) => Middleware;
82
+ export { rateLimiter, rateLimiter as default };
@@ -0,0 +1,34 @@
1
+ import { TezXError } from "../core/error.js";
2
+ import { createRateLimitDefaultStorage, isRateLimit, } from "../utils/rateLimit.js";
3
+ const rateLimiter = (options) => {
4
+ const { maxRequests, windowMs, keyGenerator = (ctx) => {
5
+ const xForwardedFor = ctx.req.header("x-forwarded-for");
6
+ if (xForwardedFor) {
7
+ const ip = xForwardedFor.split(",")[0].trim();
8
+ return ip;
9
+ }
10
+ const clientIp = ctx.req.header("client-ip");
11
+ if (clientIp)
12
+ return clientIp;
13
+ const addr = ctx.req.remoteAddress?.address || "unknown";
14
+ const port = ctx.req.remoteAddress?.port || "0";
15
+ return `${addr}:${port}`;
16
+ }, storage = createRateLimitDefaultStorage(), onError = (ctx, retryAfter, error) => {
17
+ ctx.setStatus = 429;
18
+ throw new TezXError(`Rate limit exceeded. Try again in ${retryAfter} seconds.`, 429);
19
+ }, } = options;
20
+ return async function rateLimiter(ctx, next) {
21
+ const key = keyGenerator(ctx);
22
+ const { check, entry } = isRateLimit(key, storage, maxRequests, windowMs);
23
+ if (check) {
24
+ const retryAfter = Math.ceil((entry.resetTime - Date.now()) / 1000);
25
+ ctx.headers.set("Retry-After", retryAfter.toString());
26
+ return onError(ctx, retryAfter, new TezXError(`Rate limit exceeded. Retry after ${retryAfter} seconds.`));
27
+ }
28
+ ctx.headers.set("X-RateLimit-Limit", maxRequests.toString());
29
+ ctx.headers.set("X-RateLimit-Remaining", (maxRequests - entry.count).toString());
30
+ ctx.headers.set("X-RateLimit-Reset", entry.resetTime.toString());
31
+ return await next();
32
+ };
33
+ };
34
+ export { rateLimiter, rateLimiter as default };
@@ -13,4 +13,5 @@ import { Middleware } from "../types/index.js";
13
13
  * app.use(requestID());
14
14
  * ```
15
15
  */
16
- export declare const requestID: (headerName?: string, contextKey?: string) => Middleware;
16
+ declare const requestID: (headerName?: string, contextKey?: string) => Middleware;
17
+ export { requestID as default, requestID };
@@ -1,11 +1,10 @@
1
- import { generateID } from "../helper/index.js";
2
- export const requestID = (headerName = "X-Request-ID", contextKey = "requestID") => {
1
+ import { generateUUID } from "../helper/index.js";
2
+ const requestID = (headerName = "X-Request-ID", contextKey = "requestID") => {
3
3
  return function requestID(ctx, next) {
4
- const existingID = ctx.headers?.get(headerName.toLowerCase()) ||
5
- ctx.headers?.get(headerName);
6
- const requestId = existingID || `req-${generateID()}`;
4
+ let requestId = ctx.headers.get(headerName) ?? `req-${generateUUID()}`;
7
5
  ctx[contextKey] = requestId;
8
- ctx.header(headerName, requestId);
6
+ ctx.headers.set(headerName, requestId);
9
7
  return next();
10
8
  };
11
9
  };
10
+ export { requestID as default, requestID };
@@ -1,4 +1,4 @@
1
- import { Middleware } from "../types/index.js";
1
+ import { Middleware, ResHeaderKey } from "../types/index.js";
2
2
  export type SanitizeHeadersOptions = {
3
3
  /**
4
4
  * 🟢 Whitelist of allowed headers (case-insensitive)
@@ -6,29 +6,14 @@ export type SanitizeHeadersOptions = {
6
6
  * @example
7
7
  * whitelist: ['content-type', 'authorization'] // Only allow these headers
8
8
  */
9
- whitelist?: string[];
9
+ whitelist?: ResHeaderKey[];
10
10
  /**
11
11
  * 🔴 Blacklist of disallowed headers (case-insensitive)
12
12
  * @default [] (block none if empty)
13
13
  * @example
14
14
  * blacklist: ['x-powered-by', 'server'] // Block server info headers
15
15
  */
16
- blacklist?: string[];
17
- /**
18
- * 🔵 Normalize header keys to lowercase
19
- * @default true
20
- * @example
21
- * normalizeKeys: false // Preserve original header case
22
- */
23
- normalizeKeys?: boolean;
24
- /**
25
- * 🟠 Allow potentially unsafe characters in header values
26
- * @default false
27
- * @warning Enabling this may reduce security
28
- * @example
29
- * allowUnsafeCharacters: true // Allow CR/LF in headers
30
- */
31
- allowUnsafeCharacters?: boolean;
16
+ blacklist?: ResHeaderKey[];
32
17
  };
33
18
  /**
34
19
  * 🧼 Middleware to sanitize HTTP headers for security and compliance
@@ -49,4 +34,5 @@ export type SanitizeHeadersOptions = {
49
34
  * normalizeKeys: true
50
35
  * }));
51
36
  */
52
- export declare const sanitizeHeaders: (options?: SanitizeHeadersOptions) => Middleware;
37
+ declare const sanitizeHeaders: (options?: SanitizeHeadersOptions) => Middleware;
38
+ export { sanitizeHeaders as default, sanitizeHeaders };
@@ -0,0 +1,18 @@
1
+ const sanitizeHeaders = (options = {}) => {
2
+ const { whitelist = [], blacklist = [] } = options;
3
+ const normalizedWhitelist = whitelist.map((h) => h.toLowerCase());
4
+ const normalizedBlacklist = blacklist.map((h) => h.toLowerCase());
5
+ let lWhite = normalizedWhitelist.length;
6
+ return async function sanitizeHeaders(ctx, next) {
7
+ await next();
8
+ for (const key of ctx.headers.keys()) {
9
+ if (lWhite > 0 && !normalizedWhitelist.includes(key)) {
10
+ ctx.headers.delete(key);
11
+ }
12
+ if (normalizedBlacklist.includes(key)) {
13
+ ctx.headers.delete(key);
14
+ }
15
+ }
16
+ };
17
+ };
18
+ export { sanitizeHeaders as default, sanitizeHeaders };
@@ -0,0 +1,15 @@
1
+ export type SecureHeadersOptions = {
2
+ preset?: "strict" | "balanced" | "dev";
3
+ hsts?: boolean;
4
+ hstsMaxAge?: number;
5
+ frameGuard?: "DENY" | "SAMEORIGIN" | string;
6
+ noSniff?: boolean;
7
+ xssProtection?: boolean;
8
+ referrerPolicy?: string;
9
+ permissionsPolicy?: string;
10
+ csp?: string | Record<string, string | string[]>;
11
+ cspReportOnly?: boolean;
12
+ cspUseNonce?: boolean;
13
+ ultraFastMode?: boolean;
14
+ };
15
+ export declare const secureHeaders: <T extends Record<string, any> = {}, Path extends string = any>(userOpts?: SecureHeadersOptions) => (ctx: any, next: () => Promise<any>) => Promise<any>;