tezx 1.0.73 → 1.0.75-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 (76) hide show
  1. package/adapter/bun.d.ts +29 -0
  2. package/adapter/deno.d.ts +30 -0
  3. package/adapter/index.d.ts +1 -1
  4. package/adapter/index.js +1 -1
  5. package/adapter/node/index.d.ts +47 -0
  6. package/adapter/{node.js → node/index.js} +2 -2
  7. package/cjs/adapter/index.js +1 -1
  8. package/cjs/adapter/{node.js → node/index.js} +2 -2
  9. package/cjs/core/context.js +13 -97
  10. package/cjs/core/environment.js +0 -8
  11. package/cjs/core/request.js +69 -25
  12. package/cjs/core/router.js +5 -0
  13. package/cjs/core/server.js +6 -5
  14. package/cjs/index.js +1 -1
  15. package/cjs/middleware/basicAuth.js +1 -1
  16. package/cjs/middleware/cacheControl.js +1 -1
  17. package/cjs/middleware/cors.js +2 -2
  18. package/cjs/middleware/detectBot.js +1 -1
  19. package/cjs/middleware/detectLocale.js +1 -1
  20. package/cjs/middleware/{i18nMiddleware.js → i18n.js} +4 -4
  21. package/cjs/middleware/index.js +1 -1
  22. package/cjs/middleware/lazyLoadModules.js +1 -1
  23. package/cjs/middleware/logger.js +1 -1
  24. package/cjs/middleware/pagination.js +1 -1
  25. package/cjs/middleware/powered-by.js +1 -1
  26. package/cjs/middleware/rateLimiter.js +1 -1
  27. package/cjs/middleware/request-id.js +1 -1
  28. package/cjs/middleware/requestTimeout.js +1 -1
  29. package/cjs/middleware/sanitizeHeader.js +3 -3
  30. package/cjs/middleware/secureHeaders.js +1 -1
  31. package/cjs/middleware/xssProtection.js +1 -1
  32. package/cjs/utils/formData.js +0 -235
  33. package/cjs/utils/httpStatusMap.js +68 -0
  34. package/cjs/utils/staticFile.js +4 -1
  35. package/cjs/utils/toWebRequest.js +35 -0
  36. package/core/context.d.ts +5 -6
  37. package/core/context.js +14 -98
  38. package/core/environment.d.ts +0 -2
  39. package/core/environment.js +0 -8
  40. package/core/request.d.ts +11 -32
  41. package/core/request.js +70 -26
  42. package/core/router.d.ts +30 -0
  43. package/core/router.js +5 -0
  44. package/core/server.js +5 -4
  45. package/index.js +1 -1
  46. package/middleware/basicAuth.js +1 -1
  47. package/middleware/cacheControl.js +1 -1
  48. package/middleware/cors.js +2 -2
  49. package/middleware/detectBot.js +1 -1
  50. package/middleware/detectLocale.js +1 -1
  51. package/middleware/{i18nMiddleware.d.ts → i18n.d.ts} +3 -3
  52. package/middleware/{i18nMiddleware.js → i18n.js} +2 -2
  53. package/middleware/index.d.ts +1 -1
  54. package/middleware/index.js +1 -1
  55. package/middleware/lazyLoadModules.js +1 -1
  56. package/middleware/logger.js +1 -1
  57. package/middleware/pagination.js +1 -1
  58. package/middleware/powered-by.js +1 -1
  59. package/middleware/rateLimiter.js +1 -1
  60. package/middleware/request-id.js +1 -1
  61. package/middleware/requestTimeout.js +1 -1
  62. package/middleware/sanitizeHeader.js +3 -3
  63. package/middleware/secureHeaders.js +1 -1
  64. package/middleware/xssProtection.js +1 -1
  65. package/package.json +1 -1
  66. package/utils/formData.d.ts +0 -5
  67. package/utils/formData.js +0 -231
  68. package/utils/httpStatusMap.d.ts +1 -0
  69. package/utils/httpStatusMap.js +65 -0
  70. package/utils/staticFile.js +4 -1
  71. package/utils/toWebRequest.d.ts +11 -0
  72. package/utils/toWebRequest.js +32 -0
  73. package/adapter/node.d.ts +0 -19
  74. package/cjs/core/header.js +0 -92
  75. package/core/header.d.ts +0 -77
  76. package/core/header.js +0 -88
package/core/request.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { UrlRef } from "../utils/url.js";
2
- import { HeadersParser } from "./header.js";
3
2
  import { TezXServeOptions } from "./server.js";
4
3
  export type FormDataOptions = {
5
4
  maxSize?: number;
@@ -20,7 +19,6 @@ export type ConnAddress = {
20
19
  };
21
20
  export type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE" | "OPTIONS" | "PATCH" | "HEAD" | "ALL" | "TRACE" | "CONNECT" | string;
22
21
  export declare class Request {
23
- #private;
24
22
  /**
25
23
  * Full request URL including protocol and query string
26
24
  * @type {string}
@@ -57,31 +55,21 @@ export declare class Request {
57
55
  * ```
58
56
  */
59
57
  remoteAddress: NetAddr;
60
- constructor({ headers, params, req, options, urlRef, }: {
58
+ constructor({ params, method, req, options, }: {
59
+ method: string;
61
60
  req: any;
62
61
  params: Record<string, any>;
63
- headers: HeadersParser;
64
- urlRef: UrlRef;
65
62
  options: TezXServeOptions;
66
63
  });
67
64
  get headers(): {
68
65
  /**
69
66
  * Retrieves the first value of a specific header.
70
67
  * @param key - Header name to search for.
71
- * @returns The first header value or undefined if not found.
68
+ * @returns The first header value or null if not found.
72
69
  * @example
73
70
  * get('content-type') // returns 'application/json'
74
71
  */
75
- get: (key: string) => string | undefined;
76
- /**
77
- * Retrieves all values of a specific header.
78
- * If multiple values exist for a header, all will be returned as an array.
79
- * @param key - Header name to search for.
80
- * @returns An array of all header values associated with the key.
81
- * @example
82
- * getAll('accept-language') // returns ['en-US', 'fr-CA']
83
- */
84
- getAll: (key: string) => string | never[];
72
+ get: (key: string) => string | null;
85
73
  /**
86
74
  * Checks if a header exists in the request.
87
75
  * @param key - Header name to check for existence.
@@ -93,13 +81,13 @@ export declare class Request {
93
81
  /**
94
82
  * Returns an iterator over all header entries.
95
83
  * Each entry is a [key, value] pair where the value can be an array of strings.
96
- * @returns IterableIterator for iterating over header key-value pairs.
84
+ * @returns HeadersIterator for iterating over header key-value pairs.
97
85
  * @example
98
86
  * for (let [key, value] of headers.entries()) {
99
87
  * console.log(key, value);
100
88
  * }
101
89
  */
102
- entries: () => IterableIterator<[string, string[]]>;
90
+ entries: () => HeadersIterator<[string, string]>;
103
91
  /**
104
92
  * Returns an iterator over all header keys.
105
93
  * This allows iteration over the names of all headers in the request.
@@ -113,13 +101,13 @@ export declare class Request {
113
101
  /**
114
102
  * Returns an iterator over all header values.
115
103
  * This allows iteration over the values of all headers, with each value being an array of strings.
116
- * @returns IterableIterator of header values.
104
+ * @returns HeadersIterator<string> of header values.
117
105
  * @example
118
106
  * for (let value of headers.values()) {
119
107
  * console.log(value);
120
108
  * }
121
109
  */
122
- values: () => IterableIterator<string[]>;
110
+ values: () => HeadersIterator<string>;
123
111
  /**
124
112
  * Iterates over each header and executes a callback for every header found.
125
113
  * @param callback - Function to execute for each header. Receives the value array and key.
@@ -128,34 +116,25 @@ export declare class Request {
128
116
  * console.log(key, value);
129
117
  * });
130
118
  */
131
- forEach: (callback: (value: string[], key: string) => void) => void;
119
+ forEach: (callbackfn: (value: string, key: string, parent: Headers) => void) => void;
132
120
  /**
133
121
  * Converts headers to a JSON-safe plain object (only single string values).
134
122
  * Multi-value headers are joined by commas.
135
123
  * @returns A record of headers with string values.
136
124
  */
137
125
  toJSON(): Record<string, string>;
138
- /**
139
- * Converts all headers into a plain JavaScript object.
140
- * Single-value headers are represented as a string, and multi-value headers as an array.
141
- * @returns A plain object with header names as keys and their values as strings or arrays.
142
- * @example
143
- * const headersObject = headers.toObject();
144
- * console.log(headersObject);
145
- */
146
- toObject: () => Record<string, string | string[]>;
147
126
  };
148
127
  /**
149
128
  * Parses the request body as plain text.
150
129
  * @returns {Promise<string>} The text content of the request body.
151
130
  */
152
- text(): Promise<string>;
131
+ text(): Promise<any>;
153
132
  /**
154
133
  * Parses the request body as JSON.
155
134
  * @returns {Promise<Record<string, any>>} The parsed JSON object.
156
135
  * If the Content-Type is not 'application/json', it returns an empty object.
157
136
  */
158
- json(): Promise<Record<string, any>>;
137
+ json(): Promise<any>;
159
138
  /**
160
139
  * Parses the request body based on Content-Type.
161
140
  * Supports:
package/core/request.js CHANGED
@@ -1,7 +1,6 @@
1
- import { parseJsonBody, parseMultipartBody, parseTextBody, parseUrlEncodedBody, } from "../utils/formData.js";
2
- import { HeadersParser } from "./header.js";
1
+ import { sanitized } from "../utils/formData.js";
2
+ import { urlParse } from "../utils/url.js";
3
3
  export class Request {
4
- #headers = new HeadersParser();
5
4
  url;
6
5
  method;
7
6
  urlRef = {
@@ -17,25 +16,23 @@ export class Request {
17
16
  rawRequest;
18
17
  params = {};
19
18
  remoteAddress = {};
20
- constructor({ headers, params, req, options, urlRef, }) {
19
+ constructor({ params, method, req, options, }) {
20
+ let parse = urlParse(req.url);
21
+ let url = parse?.href;
21
22
  this.remoteAddress = options?.connInfo?.remoteAddr;
22
- this.#headers = headers;
23
- this.url = urlRef.href || "";
24
- this.urlRef = urlRef;
25
- this.method = req?.method?.toUpperCase();
23
+ this.url = url || "";
24
+ this.urlRef = parse;
25
+ this.method = method;
26
26
  this.params = params;
27
27
  this.rawRequest = req;
28
- this.query = urlRef.query;
28
+ this.query = parse.query;
29
29
  }
30
30
  get headers() {
31
- let requestHeaders = this.#headers;
31
+ let requestHeaders = this.rawRequest.headers;
32
32
  return {
33
33
  get: function get(key) {
34
34
  return requestHeaders.get(key.toLowerCase());
35
35
  },
36
- getAll: function getAll(key) {
37
- return requestHeaders.get(key.toLowerCase()) || [];
38
- },
39
36
  has: function has(key) {
40
37
  return requestHeaders.has(key.toLowerCase());
41
38
  },
@@ -48,47 +45,94 @@ export class Request {
48
45
  values: function values() {
49
46
  return requestHeaders.values();
50
47
  },
51
- forEach: function forEach(callback) {
52
- return requestHeaders.forEach(callback);
48
+ forEach: function forEach(callbackfn) {
49
+ return requestHeaders.forEach(callbackfn);
53
50
  },
54
51
  toJSON() {
55
52
  return requestHeaders.toJSON();
56
53
  },
57
- toObject: function toObject() {
58
- return requestHeaders.toObject();
59
- },
60
54
  };
61
55
  }
62
56
  async text() {
63
- return await parseTextBody(this.rawRequest);
57
+ return await this.rawRequest.text();
64
58
  }
65
59
  async json() {
66
- const contentType = this.#headers.get("content-type") || "";
60
+ const contentType = this.rawRequest.headers.get("content-type") || "";
67
61
  if (contentType.includes("application/json")) {
68
- return await parseJsonBody(this.rawRequest);
62
+ return await this.rawRequest.json();
69
63
  }
70
64
  else {
71
65
  return {};
72
66
  }
73
67
  }
74
68
  async formData(options) {
75
- const contentType = this.#headers.get("content-type") || "";
69
+ const contentType = this.rawRequest.headers.get("content-type") || "";
76
70
  if (!contentType) {
77
71
  throw Error("Invalid Content-Type");
78
72
  }
79
73
  if (contentType.includes("application/json")) {
80
- return await parseJsonBody(this.rawRequest);
74
+ return await this.rawRequest.json();
81
75
  }
82
76
  else if (contentType.includes("application/x-www-form-urlencoded")) {
83
- return parseUrlEncodedBody(this.rawRequest);
77
+ const formData = await this.rawRequest.formData();
78
+ const result = {};
79
+ for (const [key, value] of formData.entries()) {
80
+ result[key] = value;
81
+ }
82
+ return result;
84
83
  }
85
84
  else if (contentType.includes("multipart/form-data")) {
86
85
  const boundaryMatch = contentType.match(/boundary=([^;]+)/);
87
86
  if (!boundaryMatch) {
88
87
  throw new Error("Boundary not found in multipart/form-data");
89
88
  }
90
- const boundary = boundaryMatch[1];
91
- return await parseMultipartBody(this.rawRequest, boundary, options);
89
+ const formData = await this.rawRequest.formData();
90
+ const result = {};
91
+ for (const [key, value] of formData.entries()) {
92
+ let val = value;
93
+ if (val instanceof File && typeof options == "object") {
94
+ let filename = val.name;
95
+ if (options?.sanitized) {
96
+ filename = `${Date.now()}-${sanitized(filename)}`;
97
+ }
98
+ if (Array.isArray(options?.allowedTypes) &&
99
+ !options.allowedTypes?.includes(val.type)) {
100
+ throw new Error(`Invalid file type: "${val.type}". Allowed types: ${options.allowedTypes.join(", ")}`);
101
+ }
102
+ if (typeof options?.maxSize !== "undefined" &&
103
+ val.size > options.maxSize) {
104
+ throw new Error(`File size exceeds the limit: ${val.size} bytes (Max: ${options.maxSize} bytes)`);
105
+ }
106
+ if (typeof options?.maxFiles != "undefined" && options.maxFiles == 0) {
107
+ throw new Error(`Field "${key}" exceeds the maximum allowed file count of ${options.maxFiles}.`);
108
+ }
109
+ val = new File([await val.arrayBuffer()], filename, {
110
+ type: val.type,
111
+ });
112
+ }
113
+ if (result[key]) {
114
+ if (Array.isArray(result[key])) {
115
+ if (val instanceof File &&
116
+ typeof options?.maxFiles != "undefined" &&
117
+ result[key]?.length >= options.maxFiles) {
118
+ throw new Error(`Field "${key}" exceeds the maximum allowed file count of ${options.maxFiles}.`);
119
+ }
120
+ result[key].push(val);
121
+ }
122
+ else {
123
+ if (val instanceof File &&
124
+ typeof options?.maxFiles != "undefined" &&
125
+ options.maxFiles == 1) {
126
+ throw new Error(`Field "${key}" exceeds the maximum allowed file count of ${options.maxFiles}.`);
127
+ }
128
+ result[key] = [result[key], val];
129
+ }
130
+ }
131
+ else {
132
+ result[key] = val;
133
+ }
134
+ }
135
+ return result;
92
136
  }
93
137
  else {
94
138
  return {};
package/core/router.d.ts CHANGED
@@ -79,6 +79,35 @@ export declare class Router<T extends Record<string, any> = {}> extends Middlewa
79
79
  get(path: string, callback: Callback<T>): this;
80
80
  get(path: string, middleware: Middleware<T>, callback: Callback<T>): this;
81
81
  get(path: string, middlewares: Middleware<T>[], callback: Callback<T>): this;
82
+ /**
83
+ * Registers a Server-Sent Events (SSE) route handler for the given path.
84
+ *
85
+ * This method sets up an HTTP GET route that sends real-time updates to the client
86
+ * over a persistent HTTP connection using the SSE protocol.
87
+ *
88
+ * ### Example:
89
+ * ```ts
90
+ * app.sse("/events", async (ctx) => {
91
+ * const stream = new ReadableStream({
92
+ * start(controller) {
93
+ * controller.enqueue(new TextEncoder().encode("data: Hello\n\n"));
94
+ * },
95
+ * });
96
+ *
97
+ * return ctx.send(stream, {
98
+ * headers: {
99
+ * "Content-Type": "text/event-stream",
100
+ * "Cache-Control": "no-cache",
101
+ * "Connection": "keep-alive",
102
+ * },
103
+ * });
104
+ * });
105
+ * ```
106
+ *
107
+ * @param {string} path - The route path for SSE (e.g. `/events`).
108
+ * @param {(ctx: Context) => any} handler - A handler function that returns a streamed response.
109
+ */
110
+ sse(path: string, handler: (ctx: Context) => any): void;
82
111
  /**
83
112
  * Registers a POST route with optional middleware(s)
84
113
  * @param path - URL path pattern
@@ -183,6 +212,7 @@ export declare class Router<T extends Record<string, any> = {}> extends Middlewa
183
212
  use(path: string, middlewares: Middleware<T>[], callback: Callback<T> | Router<T | any>): this;
184
213
  use(path: string, middleware: Middleware<T>, callback: Callback<T> | Router<T | any>): this;
185
214
  use(path: string, middlewares: Middleware<T>[]): this;
215
+ use(path: string, middlewares: Middleware<T>): this;
186
216
  use(path: string, callback: Callback<T> | Router<T | any>): this;
187
217
  use(middlewares: Middleware<T>[], callback: Callback<T> | Router<T | any>): this;
188
218
  use(middleware: Middleware<T>, callback: Callback<T> | Router<T | any>): this;
package/core/router.js CHANGED
@@ -59,6 +59,11 @@ export class Router extends MiddlewareConfigure {
59
59
  this.#registerRoute("GET", path, ...args);
60
60
  return this;
61
61
  }
62
+ sse(path, handler) {
63
+ this.get(path, async (ctx) => {
64
+ return handler(ctx);
65
+ });
66
+ }
62
67
  post(path, ...args) {
63
68
  this.#registerRoute("POST", path, ...args);
64
69
  return this;
package/core/server.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { COLORS } from "../utils/colors.js";
2
+ import { httpStatusMap } from "../utils/httpStatusMap.js";
2
3
  import { useParams } from "../utils/params.js";
3
4
  import { GlobalConfig } from "./config.js";
4
- import { Context, httpStatusMap } from "./context.js";
5
+ import { Context } from "./context.js";
5
6
  import { Router } from "./router.js";
6
7
  export class TezX extends Router {
7
8
  #onPathResolve;
@@ -194,12 +195,12 @@ export class TezX extends Router {
194
195
  }
195
196
  let finalResponse = () => {
196
197
  return (ctx) => {
197
- if (response?.headers) {
198
- ctx.headers.add(response.headers);
198
+ for (const [key, value] of response?.headers.entries()) {
199
+ ctx.headers.set(key, value);
199
200
  }
200
201
  const statusText = response?.statusText || httpStatusMap[response?.status] || "";
201
202
  const status = response.status || ctx.getStatus;
202
- let headers = ctx.headers.toObject();
203
+ let headers = ctx.headers.toJSON();
203
204
  return new Response(response.body, {
204
205
  status,
205
206
  statusText,
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export { Router } from "./core/router.js";
2
2
  export { TezX } from "./core/server.js";
3
3
  export { useParams } from "./utils/params.js";
4
- export let version = "1.0.73";
4
+ export let version = "1.0.75-beta";
@@ -12,7 +12,7 @@ export const basicAuth = (options) => {
12
12
  if (rateLimit && !rateLimit.storage) {
13
13
  storage = createRateLimitDefaultStorage();
14
14
  }
15
- return async (ctx, next) => {
15
+ return async function basicAuth(ctx, next) {
16
16
  let authMethod;
17
17
  let credentials = {};
18
18
  const authHeader = ctx.req.headers.get("authorization");
@@ -8,7 +8,7 @@ export const cacheControl = (options) => {
8
8
  GlobalConfig.debugging.success(`[CACHE] ${event.toUpperCase()} for ${ctx.method} ${ctx.pathname}`);
9
9
  }
10
10
  }, } = options;
11
- return async (ctx, next) => {
11
+ return async function cacheControl(ctx, next) {
12
12
  if (!["GET", "HEAD"].includes(ctx.method)) {
13
13
  return await next();
14
14
  }
@@ -1,6 +1,6 @@
1
1
  export function cors(option = {}) {
2
2
  const { methods, allowedHeaders, credentials, exposedHeaders, maxAge, origin, } = option;
3
- return async (ctx, next) => {
3
+ return async function cors(ctx, next) {
4
4
  const reqOrigin = ctx.req.headers.get("origin") || "";
5
5
  let allowOrigin = "*";
6
6
  if (typeof origin === "string") {
@@ -38,7 +38,7 @@ export function cors(option = {}) {
38
38
  if (ctx.req.method === "OPTIONS") {
39
39
  return new Response(null, {
40
40
  status: 204,
41
- headers: ctx.headers.toObject(),
41
+ headers: ctx.headers.toJSON(),
42
42
  });
43
43
  }
44
44
  return await next();
@@ -8,7 +8,7 @@ export const detectBot = (options = {}) => {
8
8
  if (enableRateLimiting) {
9
9
  store = createRateLimitDefaultStorage();
10
10
  }
11
- return async (ctx, next) => {
11
+ return async function detectBot(ctx, next) {
12
12
  const detectionResult = {
13
13
  isBot: false,
14
14
  indicators: [],
@@ -1,7 +1,7 @@
1
1
  import { GlobalConfig } from "../core/config.js";
2
2
  export const detectLocale = (options) => {
3
3
  const { supportedLocales, defaultLocale = "en", queryKeyLocale = "lang", cookieKeyLocale = "locale", localeContextKey = "locale", customLocaleDetector, } = options;
4
- return async (ctx, next) => {
4
+ return async function detectLocale(ctx, next) {
5
5
  let detectedLocale;
6
6
  const queryLocale = ctx.req.query[queryKeyLocale];
7
7
  if (queryLocale && supportedLocales.includes(queryLocale)) {
@@ -86,16 +86,16 @@ export type I18nOptions = {
86
86
  *
87
87
  * @example
88
88
  * // Basic usage
89
- * app.use(i18nMiddleware({
89
+ * app.use(i18n({
90
90
  * loadTranslations: lang => import(`./locales/${lang}.json`),
91
91
  * defaultLanguage: 'en'
92
92
  * }));
93
93
  *
94
94
  * // With caching and custom detection
95
- * app.use(i18nMiddleware({
95
+ * app.use(i18n({
96
96
  * loadTranslations: fetchTranslations,
97
97
  * detectLanguage: ctx => ctx.get('X-Language'),
98
98
  * cacheTranslations: true
99
99
  * }));
100
100
  */
101
- export declare const i18nMiddleware: (options: I18nOptions) => Middleware;
101
+ export declare const i18n: (options: I18nOptions) => Middleware;
@@ -1,5 +1,5 @@
1
1
  import { GlobalConfig } from "../core/config.js";
2
- export const i18nMiddleware = (options) => {
2
+ export const i18n = (options) => {
3
3
  const { loadTranslations, defaultCacheDuration = 3600000, isCacheValid = (cached) => cached.expiresAt > Date.now(), detectLanguage = (ctx) => ctx.req.query.lang ||
4
4
  ctx.cookies?.get("lang") ||
5
5
  ctx.req.headers.get("accept-language")?.split(",")[0] ||
@@ -8,7 +8,7 @@ export const i18nMiddleware = (options) => {
8
8
  return Object.entries(options).reduce((msg, [key, value]) => msg.replace(new RegExp(`{{${key}}}`, "g"), String(value)), message);
9
9
  }, cacheTranslations = true, } = options;
10
10
  const translationCache = {};
11
- return async (ctx, next) => {
11
+ return async function i18n(ctx, next) {
12
12
  try {
13
13
  const detectedLanguage = detectLanguage(ctx);
14
14
  const languageChain = [
@@ -4,7 +4,7 @@ export type { CorsOptions } from "./cors.js";
4
4
  export { detectBot } from "./detectBot.js";
5
5
  export type { DetectBotReason } from "./detectBot.js";
6
6
  export * from "./detectLocale.js";
7
- export * from "./i18nMiddleware.js";
7
+ export * from "./i18n.js";
8
8
  export * from "./lazyLoadModules.js";
9
9
  export * from "./logger.js";
10
10
  export * from "./pagination.js";
@@ -2,7 +2,7 @@ export * from "./basicAuth.js";
2
2
  export { cors } from "./cors.js";
3
3
  export { detectBot } from "./detectBot.js";
4
4
  export * from "./detectLocale.js";
5
- export * from "./i18nMiddleware.js";
5
+ export * from "./i18n.js";
6
6
  export * from "./lazyLoadModules.js";
7
7
  export * from "./logger.js";
8
8
  export * from "./pagination.js";
@@ -5,7 +5,7 @@ export const lazyLoadModules = (options) => {
5
5
  if (enableCache && !cacheStorage) {
6
6
  storage = new Map();
7
7
  }
8
- return async (ctx, next) => {
8
+ return async function lazyLoadModules(ctx, next) {
9
9
  let moduleName = moduleKey(ctx) ||
10
10
  ctx.req.params[queryKeyModule] ||
11
11
  ctx.req.query[queryKeyModule];
@@ -1,6 +1,6 @@
1
1
  import { COLORS } from "../utils/colors.js";
2
2
  export function logger() {
3
- return async (ctx, next) => {
3
+ return async function logger(ctx, next) {
4
4
  try {
5
5
  console.log(`${COLORS.bold}<-- ${COLORS.reset}${COLORS.bgMagenta} ${ctx.method} ${COLORS.reset} ${ctx.pathname}`);
6
6
  const startTime = performance.now();
@@ -1,6 +1,6 @@
1
1
  export const paginationHandler = (options = {}) => {
2
2
  const { defaultPage = 1, defaultLimit = 10, maxLimit = 100, queryKeyPage = "page", queryKeyLimit = "limit", countKey = "total", dataKey = "data", getDataSource, } = options;
3
- return async (ctx, next) => {
3
+ return async function paginationHandler(ctx, next) {
4
4
  const rawPage = ctx.req.query[queryKeyPage];
5
5
  const rawLimit = ctx.req.query[queryKeyLimit];
6
6
  const page = Math.max(parseInt(rawPage || `${defaultPage}`, 10), 1);
@@ -1,5 +1,5 @@
1
1
  export const poweredBy = (serverName) => {
2
- return (ctx, next) => {
2
+ return function poweredBy(ctx, next) {
3
3
  ctx.header("X-Powered-By", serverName || "TezX");
4
4
  return next();
5
5
  };
@@ -4,7 +4,7 @@ export const rateLimiter = (options) => {
4
4
  ctx.setStatus = 429;
5
5
  throw new Error(`Rate limit exceeded. Try again in ${retryAfter} seconds.`);
6
6
  }, } = options;
7
- return async (ctx, next) => {
7
+ return async function rateLimiter(ctx, next) {
8
8
  const key = keyGenerator(ctx);
9
9
  const { check, entry } = isRateLimit(ctx, key, storage, maxRequests, windowMs);
10
10
  if (check) {
@@ -1,6 +1,6 @@
1
1
  import { generateID } from "../helper/index.js";
2
2
  export const requestID = (headerName = "X-Request-ID", contextKey = "requestID") => {
3
- return (ctx, next) => {
3
+ return function requestID(ctx, next) {
4
4
  const existingID = ctx.headers?.get(headerName.toLowerCase()) ||
5
5
  ctx.headers?.get(headerName);
6
6
  const requestId = existingID || `req-${generateID()}`;
@@ -7,7 +7,7 @@ export const requestTimeout = (options) => {
7
7
  GlobalConfig.debugging.warn(`[TIMEOUT] ${error.message}: ${ctx.method} ${ctx.path}`);
8
8
  }, cleanup = () => {
9
9
  }, } = options;
10
- return async (ctx, next) => {
10
+ return async function requestTimeout(ctx, next) {
11
11
  let timeoutId = null;
12
12
  try {
13
13
  const timeout = getTimeout(ctx);
@@ -1,7 +1,7 @@
1
1
  import { GlobalConfig } from "../core/config.js";
2
2
  export const sanitizeHeaders = (options = {}) => {
3
3
  const { whitelist = [], blacklist = [], normalizeKeys = true, allowUnsafeCharacters = false, } = options;
4
- return async (ctx, next) => {
4
+ return async function sanitizeHeaders(ctx, next) {
5
5
  const sanitizedHeaders = new Map();
6
6
  for (const [key, values] of ctx.headers.entries()) {
7
7
  if (!Array.isArray(values) || values.length === 0) {
@@ -28,9 +28,9 @@ export const sanitizeHeaders = (options = {}) => {
28
28
  GlobalConfig.debugging.warn(`⚠️ All values for "${normalizedKey}" invalid - removed`);
29
29
  continue;
30
30
  }
31
- sanitizedHeaders.set(normalizedKey, sanitizedValues);
31
+ sanitizedHeaders.set(normalizedKey, sanitizedValues?.join(", "));
32
32
  }
33
- ctx.headers.clear().add([...sanitizedHeaders.entries()]);
33
+ ctx.headers = new Headers(sanitizedHeaders);
34
34
  return await next();
35
35
  };
36
36
  };
@@ -1,5 +1,5 @@
1
1
  export const secureHeaders = (options = {}) => {
2
- return async (ctx, next) => {
2
+ return async function secureHeaders(ctx, next) {
3
3
  const resolveValue = (value) => {
4
4
  return typeof value === "function" ? value(ctx) : value;
5
5
  };
@@ -1,7 +1,7 @@
1
1
  import { GlobalConfig } from "../core/config.js";
2
2
  export const xssProtection = (options = {}) => {
3
3
  const { enabled = true, mode = "block", fallbackCSP = "default-src 'self'; script-src 'self';", } = options;
4
- return async (ctx, next) => {
4
+ return async function xssProtection(ctx, next) {
5
5
  const isEnabled = typeof enabled === "function" ? enabled(ctx) : enabled;
6
6
  if (!isEnabled) {
7
7
  GlobalConfig.debugging.warn("🟠 XSS protection is disabled.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tezx",
3
- "version": "1.0.73",
3
+ "version": "1.0.75-beta",
4
4
  "description": "TezX is a high-performance, lightweight JavaScript framework designed for speed, scalability, and flexibility. It enables efficient routing, middleware management, and static file serving with minimal configuration. Fully compatible with Node.js, Deno, and Bun.",
5
5
  "main": "cjs/index.js",
6
6
  "module": "index.js",
@@ -1,6 +1 @@
1
- import { FormDataOptions } from "../core/request.js";
2
- export declare function parseJsonBody(req: any): Promise<Record<string, any>>;
3
- export declare function parseTextBody(req: any): Promise<string>;
4
- export declare function parseUrlEncodedBody(req: any): Promise<Record<string, any>>;
5
1
  export declare function sanitized(title: string): string;
6
- export declare function parseMultipartBody(req: any, boundary: string, options?: FormDataOptions): Promise<Record<string, any>>;