tezx 1.0.34 → 1.0.36

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.
@@ -82,7 +82,7 @@ class Context {
82
82
  #status = 200;
83
83
  state = new state_1.State();
84
84
  #params = {};
85
- body = {};
85
+ #resBody;
86
86
  #localAddress = {};
87
87
  #remoteAddress = {};
88
88
  constructor(req, connInfo) {
@@ -167,8 +167,8 @@ class Context {
167
167
  else if (typeof args[0] === "object") {
168
168
  headers = args[0];
169
169
  }
170
- if (!headers["Content-Type"]) {
171
- if (typeof body === "string") {
170
+ if ((!headers["Content-Type"] && !headers['content-type'])) {
171
+ if (typeof body === "string" || typeof body == 'number') {
172
172
  headers["Content-Type"] = "text/plain;";
173
173
  }
174
174
  else if (typeof body === "object" && body !== null) {
@@ -388,6 +388,7 @@ class Context {
388
388
  headers,
389
389
  });
390
390
  let clone = response.clone();
391
+ this.body = body;
391
392
  this.res = response;
392
393
  return clone;
393
394
  }
@@ -397,6 +398,12 @@ class Context {
397
398
  set params(params) {
398
399
  this.#params = params;
399
400
  }
401
+ set body(body) {
402
+ this.#resBody = body;
403
+ }
404
+ get body() {
405
+ return this.#resBody;
406
+ }
400
407
  get params() {
401
408
  return this.#params;
402
409
  }
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Router = void 0;
4
- const config_1 = require("./config");
5
- const MiddlewareConfigure_1 = require("./MiddlewareConfigure");
6
4
  const staticFile_1 = require("../utils/staticFile");
7
5
  const url_1 = require("../utils/url");
6
+ const config_1 = require("./config");
7
+ const MiddlewareConfigure_1 = require("./MiddlewareConfigure");
8
+ ;
8
9
  class TrieRouter {
9
10
  children = new Map();
10
11
  handlers = new Map();
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TezX = void 0;
4
+ const colors_1 = require("../utils/colors");
4
5
  const config_1 = require("./config");
5
6
  const context_1 = require("./context");
6
7
  const router_1 = require("./router");
7
- const colors_1 = require("../utils/colors");
8
8
  const params_1 = require("../utils/params");
9
9
  class TezX extends router_1.Router {
10
10
  constructor({ basePath = "/", env = {}, debugMode = false, allowDuplicateMw = false, overwriteMethod = true, } = {}) {
@@ -86,10 +86,14 @@ class TezX extends router_1.Router {
86
86
  }
87
87
  };
88
88
  const response = await next();
89
- if (!response) {
89
+ if (response instanceof Response) {
90
+ return response;
91
+ }
92
+ if (!response && !ctx.body) {
90
93
  throw new Error(`Handler did not return a response or next() was not called. Path: ${ctx.pathname}, Method: ${ctx.method}`);
91
94
  }
92
- return response;
95
+ const resBody = response || ctx.body;
96
+ return ctx.send(resBody, ctx.headers.toObject());
93
97
  };
94
98
  }
95
99
  #findMiddleware(pathname) {
package/cjs/index.js CHANGED
@@ -7,4 +7,4 @@ var server_1 = require("./core/server");
7
7
  Object.defineProperty(exports, "TezX", { enumerable: true, get: function () { return server_1.TezX; } });
8
8
  var params_1 = require("./utils/params");
9
9
  Object.defineProperty(exports, "useParams", { enumerable: true, get: function () { return params_1.useParams; } });
10
- exports.version = "1.0.34";
10
+ exports.version = "1.0.36";
@@ -48,14 +48,14 @@ const lazyLoadModules = (options) => {
48
48
  lifecycleHooks.onCacheSet?.(moduleName, module, ctx);
49
49
  }
50
50
  ctx[moduleContextKey] = module;
51
- lifecycleHooks.onComplete?.(moduleName, module, ctx);
52
- config_1.GlobalConfig.debugging.success(`Successfully loaded module: ${moduleName}`);
53
51
  if (module.init && typeof module.init === "function") {
54
52
  const initResult = await module.init(dependencies, ctx);
55
53
  if (initResult instanceof Response) {
56
54
  return initResult;
57
55
  }
58
56
  }
57
+ lifecycleHooks.onComplete?.(moduleName, module, ctx);
58
+ config_1.GlobalConfig.debugging.success(`Successfully loaded module: ${moduleName}`);
59
59
  }
60
60
  catch (error) {
61
61
  config_1.GlobalConfig.debugging.error(`Error loading module: ${moduleName}`, error);
@@ -12,40 +12,36 @@ const paginationHandler = (options = {}) => {
12
12
  ctx.pagination = {
13
13
  page,
14
14
  limit,
15
- offset: offset,
15
+ offset,
16
16
  queryKeyPage,
17
- queryKeyLimit
17
+ queryKeyLimit,
18
18
  };
19
19
  if (getDataSource) {
20
- try {
21
- const dataSourceResponse = await getDataSource(ctx, { page, limit, offset });
22
- const total = dataSourceResponse?.[countKey];
23
- const data = dataSourceResponse?.[dataKey];
24
- if (typeof total !== "number" || !Array.isArray(data)) {
25
- throw new Error("Invalid data structure returned by getDataSource.");
26
- }
27
- ctx.body = {
28
- [dataKey]: data,
29
- [countKey]: total,
30
- pagination: {
31
- page,
32
- limit,
33
- totalItems: total,
34
- totalPages: Math.ceil(total / limit),
35
- hasNextPage: page < Math.ceil(total / limit),
36
- hasPrevPage: page > 1,
37
- nextPage: page < Math.ceil(total / limit) ? page + 1 : null,
38
- prevPage: page > 1 ? page - 1 : null,
39
- },
40
- };
41
- }
42
- catch (error) {
43
- ctx.setStatus = 500;
44
- ctx.body = { error: "Internal Server Error", };
45
- throw new Error("Error fetching or processing data:", error?.message);
20
+ const dataSourceResponse = await getDataSource(ctx, { page, limit, offset });
21
+ const total = dataSourceResponse?.[countKey];
22
+ const data = dataSourceResponse?.[dataKey];
23
+ const pagination = {
24
+ page,
25
+ limit,
26
+ totalItems: total,
27
+ totalPages: Math.ceil(total / limit),
28
+ hasNextPage: page < Math.ceil(total / limit),
29
+ hasPrevPage: page > 1,
30
+ nextPage: page < Math.ceil(total / limit) ? page + 1 : null,
31
+ prevPage: page > 1 ? page - 1 : null,
32
+ };
33
+ ctx.pagination = pagination;
34
+ const body = {
35
+ [dataKey]: data,
36
+ [countKey]: total,
37
+ pagination,
38
+ };
39
+ if (next) {
40
+ ctx.body = body;
41
+ return await next();
46
42
  }
43
+ return (ctx.body = body);
47
44
  }
48
- return await next();
49
45
  };
50
46
  };
51
47
  exports.paginationHandler = paginationHandler;
@@ -2,21 +2,20 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.rateLimiter = void 0;
4
4
  const rateLimiter = (options) => {
5
- const { maxRequests, windowMs, keyGenerator = (ctx) => `${ctx.req.remoteAddress.address}:${ctx.req.remoteAddress.port}`, onError = (ctx, retryAfter, error) => {
5
+ const { maxRequests, windowMs, keyGenerator = (ctx) => `${ctx.req.remoteAddress.address}:${ctx.req.remoteAddress.port}`, cacheStorage = new Map(), onError = (ctx, retryAfter, error) => {
6
6
  ctx.setStatus = 429;
7
7
  throw new Error(`Rate limit exceeded. Try again in ${retryAfter} seconds.`);
8
8
  }, } = options;
9
- const memoryStore = new Map();
10
9
  return async (ctx, next) => {
11
10
  const key = keyGenerator(ctx);
12
11
  let requestCount;
13
12
  let resetTime;
14
- for (const [key, entry] of memoryStore.entries()) {
13
+ for (const [key, entry] of cacheStorage.entries()) {
15
14
  if (Date.now() >= entry.resetTime) {
16
- memoryStore.delete(key);
15
+ cacheStorage.delete(key);
17
16
  }
18
17
  }
19
- const entry = memoryStore.get(key);
18
+ const entry = cacheStorage.get(key);
20
19
  if (entry && Date.now() < entry.resetTime) {
21
20
  requestCount = entry.count + 1;
22
21
  resetTime = entry.resetTime;
@@ -24,7 +23,7 @@ const rateLimiter = (options) => {
24
23
  else {
25
24
  requestCount = 1;
26
25
  resetTime = Date.now() + windowMs;
27
- memoryStore.set(key, { count: requestCount, resetTime });
26
+ cacheStorage.set(key, { count: requestCount, resetTime });
28
27
  }
29
28
  if (requestCount > maxRequests) {
30
29
  const retryAfter = Math.ceil((resetTime - Date.now()) / 1000);
package/core/context.d.ts CHANGED
@@ -51,7 +51,6 @@ export declare class Context<T extends Record<string, any> = {}> {
51
51
  * @type {State}
52
52
  */
53
53
  state: State;
54
- body: Record<string, any>;
55
54
  constructor(req: any, connInfo: ConnAddress);
56
55
  /**
57
56
  * Cookie handling utility with get/set/delete operations
@@ -192,5 +191,17 @@ export declare class Context<T extends Record<string, any> = {}> {
192
191
  */
193
192
  get req(): Request;
194
193
  protected set params(params: Record<string, any>);
194
+ /**
195
+ * Sets the HTTP response body to be returned to the client.
196
+ * This can be a string, object, or any serializable data.
197
+ * @param body - The response payload to be stored internally.
198
+ */
199
+ set body(body: any | undefined);
200
+ /**
201
+ * Retrieves the current response body set for the outgoing HTTP response.
202
+ * This value will be used when sending the final response.
203
+ * @returns The internally stored response payload.
204
+ */
205
+ get body(): any | undefined;
195
206
  protected get params(): Record<string, any>;
196
207
  }
package/core/context.js CHANGED
@@ -79,7 +79,7 @@ export class Context {
79
79
  #status = 200;
80
80
  state = new State();
81
81
  #params = {};
82
- body = {};
82
+ #resBody;
83
83
  #localAddress = {};
84
84
  #remoteAddress = {};
85
85
  constructor(req, connInfo) {
@@ -164,8 +164,8 @@ export class Context {
164
164
  else if (typeof args[0] === "object") {
165
165
  headers = args[0];
166
166
  }
167
- if (!headers["Content-Type"]) {
168
- if (typeof body === "string") {
167
+ if ((!headers["Content-Type"] && !headers['content-type'])) {
168
+ if (typeof body === "string" || typeof body == 'number') {
169
169
  headers["Content-Type"] = "text/plain;";
170
170
  }
171
171
  else if (typeof body === "object" && body !== null) {
@@ -385,6 +385,7 @@ export class Context {
385
385
  headers,
386
386
  });
387
387
  let clone = response.clone();
388
+ this.body = body;
388
389
  this.res = response;
389
390
  return clone;
390
391
  }
@@ -394,6 +395,12 @@ export class Context {
394
395
  set params(params) {
395
396
  this.#params = params;
396
397
  }
398
+ set body(body) {
399
+ this.#resBody = body;
400
+ }
401
+ get body() {
402
+ return this.#resBody;
403
+ }
397
404
  get params() {
398
405
  return this.#params;
399
406
  }
package/core/router.d.ts CHANGED
@@ -3,8 +3,9 @@ import MiddlewareConfigure, { DuplicateMiddlewares, UniqueMiddlewares } from "./
3
3
  import { HTTPMethod } from "./request";
4
4
  export type NextCallback = () => Promise<any>;
5
5
  export type ctx<T extends Record<string, any> = {}> = Context<T> & T;
6
- export type Callback<T extends Record<string, any> = {}> = (ctx: ctx<T>) => Promise<Response> | Response;
7
- export type Middleware<T extends Record<string, any> = {}> = (ctx: ctx<T>, next: NextCallback) => NextCallback | Promise<NextCallback | Response> | Response;
6
+ export type CallbackReturnType = Promise<Response> | Response | string | Record<string, any>;
7
+ export type Callback<T extends Record<string, any> = {}> = (ctx: ctx<T>) => CallbackReturnType;
8
+ export type Middleware<T extends Record<string, any> = {}> = (ctx: ctx<T>, next: NextCallback) => NextCallback | Promise<NextCallback | Response> | Response | string | Record<string, any>;
8
9
  export type RouterConfig = {
9
10
  /**
10
11
  * `env` allows you to define environment variables for the router.
@@ -75,64 +76,72 @@ export declare class Router<T extends Record<string, any> = {}> extends Middlewa
75
76
  * app.get('/admin', [authMiddleware, adminMiddleware], (ctx) => { ... });
76
77
  */
77
78
  get(path: string, callback: Callback<T>): this;
79
+ get(path: string, middleware: Middleware<T>): this;
80
+ get(path: string, middleware: Middleware<T>, callback: Callback<T>): this;
78
81
  get(path: string, middlewares: Middleware<T>[], callback: Callback<T>): this;
79
- get(path: string, middlewares: Middleware<T>, callback: Callback<T>): this;
80
82
  /**
81
83
  * Registers a POST route with optional middleware(s)
82
84
  * @param path - URL path pattern
83
85
  * @param args - Handler callback or middleware(s) + handler
84
86
  */
85
87
  post(path: string, callback: Callback<T>): this;
88
+ post(path: string, middleware: Middleware<T>): this;
89
+ post(path: string, middleware: Middleware<T>, callback: Callback<T>): this;
86
90
  post(path: string, middlewares: Middleware<T>[], callback: Callback<T>): this;
87
- post(path: string, middlewares: Middleware<T>, callback: Callback<T>): this;
88
91
  /**
89
92
  * Registers a PUT route with optional middleware(s)
90
93
  * @param path - URL path pattern
91
94
  * @param args - Handler callback or middleware(s) + handler
92
95
  */
93
96
  put(path: string, callback: Callback<T>): this;
97
+ put(path: string, middleware: Middleware<T>): this;
98
+ put(path: string, middleware: Middleware<T>, callback: Callback<T>): this;
94
99
  put(path: string, middlewares: Middleware<T>[], callback: Callback<T>): this;
95
- put(path: string, middlewares: Middleware<T>, callback: Callback<T>): this;
96
100
  /**
97
101
  * Registers a PATCH route with optional middleware(s)
98
102
  * @param path - URL path pattern
99
103
  * @param args - Handler callback or middleware(s) + handler
100
104
  */
101
105
  patch(path: string, callback: Callback<T>): this;
106
+ patch(path: string, middleware: Middleware<T>): this;
107
+ patch(path: string, middleware: Middleware<T>, callback: Callback<T>): this;
102
108
  patch(path: string, middlewares: Middleware<T>[], callback: Callback<T>): this;
103
- patch(path: string, middlewares: Middleware<T>, callback: Callback<T>): this;
104
109
  /**
105
110
  * Registers a DELETE route with optional middleware(s)
106
111
  * @param path - URL path pattern
107
112
  * @param args - Handler callback or middleware(s) + handler
108
113
  */
109
114
  delete(path: string, callback: Callback<T>): this;
115
+ delete(path: string, middleware: Middleware<T>): this;
116
+ delete(path: string, middleware: Middleware<T>, callback: Callback<T>): this;
110
117
  delete(path: string, middlewares: Middleware<T>[], callback: Callback<T>): this;
111
- delete(path: string, middlewares: Middleware<T>, callback: Callback<T>): this;
112
118
  /**
113
119
  * Registers an OPTIONS route (primarily for CORS preflight requests)
114
120
  * @param path - URL path pattern
115
121
  * @param args - Handler callback or middleware(s) + handler
116
122
  */
117
123
  options(path: string, callback: Callback<T>): this;
124
+ options(path: string, middleware: Middleware<T>): this;
125
+ options(path: string, middleware: Middleware<T>, callback: Callback<T>): this;
118
126
  options(path: string, middlewares: Middleware<T>[], callback: Callback<T>): this;
119
- options(path: string, middlewares: Middleware<T>, callback: Callback<T>): this;
120
127
  /**
121
128
  * Registers a HEAD route (returns headers only)
122
129
  * @param path - URL path pattern
123
130
  * @param args - Handler callback or middleware(s) + handler
124
131
  */
125
132
  head(path: string, callback: Callback<T>): this;
133
+ head(path: string, middleware: Middleware<T>): this;
134
+ head(path: string, middleware: Middleware<T>, callback: Callback<T>): this;
126
135
  head(path: string, middlewares: Middleware<T>[], callback: Callback<T>): this;
127
- head(path: string, middlewares: Middleware<T>, callback: Callback<T>): this;
128
136
  /**
129
137
  * Registers a route that responds to all HTTP methods
130
138
  * @param path - URL path pattern
131
139
  * @param args - Handler callback or middleware(s) + handler
132
140
  */
133
141
  all(path: string, callback: Callback<T>): this;
142
+ all(path: string, middleware: Middleware<T>): this;
143
+ all(path: string, middleware: Middleware<T>, callback: Callback<T>): this;
134
144
  all(path: string, middlewares: Middleware<T>[], callback: Callback<T>): this;
135
- all(path: string, middlewares: Middleware<T>, callback: Callback<T>): this;
136
145
  /**
137
146
  * Generic method registration for custom HTTP methods
138
147
  * @param method - HTTP method name (e.g., 'PURGE')
@@ -144,8 +153,9 @@ export declare class Router<T extends Record<string, any> = {}> extends Middlewa
144
153
  * server.addRoute('PURGE', '/cache', purgeHandler);
145
154
  */
146
155
  addRoute(method: HTTPMethod, path: string, callback: Callback<T>): this;
156
+ addRoute(method: HTTPMethod, path: string, middleware: Middleware<T>): this;
157
+ addRoute(method: HTTPMethod, path: string, middleware: Middleware<T>, callback: Callback<T>): this;
147
158
  addRoute(method: HTTPMethod, path: string, middlewares: Middleware<T>[], callback: Callback<T>): this;
148
- addRoute(method: HTTPMethod, path: string, middlewares: Middleware<T>, callback: Callback<T>): this;
149
159
  /**
150
160
  * Mount a sub-router at specific path prefix
151
161
  * @param path - Base path for the sub-router
package/core/router.js CHANGED
@@ -1,7 +1,8 @@
1
- import { GlobalConfig } from "./config";
2
- import MiddlewareConfigure, { TriMiddleware, } from "./MiddlewareConfigure";
3
1
  import { getFiles } from "../utils/staticFile";
4
2
  import { sanitizePathSplit } from "../utils/url";
3
+ import { GlobalConfig } from "./config";
4
+ import MiddlewareConfigure, { TriMiddleware, } from "./MiddlewareConfigure";
5
+ ;
5
6
  class TrieRouter {
6
7
  children = new Map();
7
8
  handlers = new Map();
package/core/server.js CHANGED
@@ -1,7 +1,7 @@
1
+ import { COLORS } from "../utils/colors";
1
2
  import { GlobalConfig } from "./config";
2
3
  import { Context, httpStatusMap } from "./context";
3
4
  import { Router } from "./router";
4
- import { COLORS } from "../utils/colors";
5
5
  import { useParams } from "../utils/params";
6
6
  export class TezX extends Router {
7
7
  constructor({ basePath = "/", env = {}, debugMode = false, allowDuplicateMw = false, overwriteMethod = true, } = {}) {
@@ -83,10 +83,14 @@ export class TezX extends Router {
83
83
  }
84
84
  };
85
85
  const response = await next();
86
- if (!response) {
86
+ if (response instanceof Response) {
87
+ return response;
88
+ }
89
+ if (!response && !ctx.body) {
87
90
  throw new Error(`Handler did not return a response or next() was not called. Path: ${ctx.pathname}, Method: ${ctx.method}`);
88
91
  }
89
- return response;
92
+ const resBody = response || ctx.body;
93
+ return ctx.send(resBody, ctx.headers.toObject());
90
94
  };
91
95
  }
92
96
  #findMiddleware(pathname) {
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export { Router } from "./core/router";
2
2
  export { TezX } from "./core/server";
3
3
  export { useParams } from "./utils/params";
4
- export let version = "1.0.34";
4
+ export let version = "1.0.36";
@@ -42,7 +42,6 @@ interface LazyLoadOptions<T> {
42
42
  get: (key: string) => CacheItem<T> | undefined;
43
43
  set: (key: string, value: CacheItem<T>) => void;
44
44
  delete: (key: string) => void;
45
- clear?: () => void;
46
45
  };
47
46
  /**
48
47
  * ⏳ Cache Time-To-Live (TTL) in milliseconds. This determines how long cached modules are valid.
@@ -45,14 +45,14 @@ export const lazyLoadModules = (options) => {
45
45
  lifecycleHooks.onCacheSet?.(moduleName, module, ctx);
46
46
  }
47
47
  ctx[moduleContextKey] = module;
48
- lifecycleHooks.onComplete?.(moduleName, module, ctx);
49
- GlobalConfig.debugging.success(`Successfully loaded module: ${moduleName}`);
50
48
  if (module.init && typeof module.init === "function") {
51
49
  const initResult = await module.init(dependencies, ctx);
52
50
  if (initResult instanceof Response) {
53
51
  return initResult;
54
52
  }
55
53
  }
54
+ lifecycleHooks.onComplete?.(moduleName, module, ctx);
55
+ GlobalConfig.debugging.success(`Successfully loaded module: ${moduleName}`);
56
56
  }
57
57
  catch (error) {
58
58
  GlobalConfig.debugging.error(`Error loading module: ${moduleName}`, error);
@@ -1,4 +1,5 @@
1
- import { Context, Middleware } from "..";
1
+ import { Context } from "..";
2
+ import { Middleware } from "../core/router";
2
3
  export type PaginationOptions = {
3
4
  /**
4
5
  * 🔢 Default page number when not specified
@@ -52,7 +53,7 @@ export type PaginationOptions = {
52
53
  * return db.find().skip((page-1)*limit).limit(limit);
53
54
  * }
54
55
  */
55
- getDataSource?: (ctx: Context, pagination: {
56
+ getDataSource?: <T extends Record<string, any> = {}>(ctx: Context<T>, pagination: {
56
57
  page: number;
57
58
  limit: number;
58
59
  offset: number;
@@ -60,6 +61,19 @@ export type PaginationOptions = {
60
61
  [key: string]: any;
61
62
  }>;
62
63
  };
64
+ export type PaginationBodyType = {
65
+ [x: string]: any;
66
+ pagination: {
67
+ page: number;
68
+ limit: number;
69
+ totalItems: any;
70
+ totalPages: number;
71
+ hasNextPage: boolean;
72
+ hasPrevPage: boolean;
73
+ nextPage: number | null;
74
+ prevPage: number | null;
75
+ };
76
+ };
63
77
  /**
64
78
  * 🗂️ Advanced pagination middleware with dynamic data fetching
65
79
  *
@@ -69,12 +83,12 @@ export type PaginationOptions = {
69
83
  * - Comprehensive pagination metadata
70
84
  * - Built-in error handling
71
85
  *
72
- * @param {PaginationOptions} [options={}] - Configuration options
73
- * @returns {Middleware} Configured middleware
86
+ * @param {PaginationOptions} [options={}] - Configuration options for pagination behavior
87
+ * @returns {Callback} Middleware function that processes pagination and sets response
74
88
  *
75
89
  * @example
76
90
  * // Basic usage
77
- * app.get('/users', paginationHandler(), getUsers);
91
+ * app.get('/users', paginationHandler());
78
92
  *
79
93
  * // With dynamic data source
80
94
  * app.get('/products', paginationHandler({
@@ -9,39 +9,35 @@ export const paginationHandler = (options = {}) => {
9
9
  ctx.pagination = {
10
10
  page,
11
11
  limit,
12
- offset: offset,
12
+ offset,
13
13
  queryKeyPage,
14
- queryKeyLimit
14
+ queryKeyLimit,
15
15
  };
16
16
  if (getDataSource) {
17
- try {
18
- const dataSourceResponse = await getDataSource(ctx, { page, limit, offset });
19
- const total = dataSourceResponse?.[countKey];
20
- const data = dataSourceResponse?.[dataKey];
21
- if (typeof total !== "number" || !Array.isArray(data)) {
22
- throw new Error("Invalid data structure returned by getDataSource.");
23
- }
24
- ctx.body = {
25
- [dataKey]: data,
26
- [countKey]: total,
27
- pagination: {
28
- page,
29
- limit,
30
- totalItems: total,
31
- totalPages: Math.ceil(total / limit),
32
- hasNextPage: page < Math.ceil(total / limit),
33
- hasPrevPage: page > 1,
34
- nextPage: page < Math.ceil(total / limit) ? page + 1 : null,
35
- prevPage: page > 1 ? page - 1 : null,
36
- },
37
- };
38
- }
39
- catch (error) {
40
- ctx.setStatus = 500;
41
- ctx.body = { error: "Internal Server Error", };
42
- throw new Error("Error fetching or processing data:", error?.message);
17
+ const dataSourceResponse = await getDataSource(ctx, { page, limit, offset });
18
+ const total = dataSourceResponse?.[countKey];
19
+ const data = dataSourceResponse?.[dataKey];
20
+ const pagination = {
21
+ page,
22
+ limit,
23
+ totalItems: total,
24
+ totalPages: Math.ceil(total / limit),
25
+ hasNextPage: page < Math.ceil(total / limit),
26
+ hasPrevPage: page > 1,
27
+ nextPage: page < Math.ceil(total / limit) ? page + 1 : null,
28
+ prevPage: page > 1 ? page - 1 : null,
29
+ };
30
+ ctx.pagination = pagination;
31
+ const body = {
32
+ [dataKey]: data,
33
+ [countKey]: total,
34
+ pagination,
35
+ };
36
+ if (next) {
37
+ ctx.body = body;
38
+ return await next();
43
39
  }
40
+ return (ctx.body = body);
44
41
  }
45
- return await next();
46
42
  };
47
43
  };
@@ -24,13 +24,32 @@ export type RateLimiterOptions = {
24
24
  // * ⚠️ (Future) Storage backend - currently memory only
25
25
  // * @todo Implement Redis storage
26
26
  // */
27
+ /**
28
+ * 🔄 Custom cache storage implementation (e.g., using `Map`, `Redis`, etc.).
29
+ * By default, it uses a `Map<string, { count: number; resetTime: number }>`.
30
+ */
31
+ cacheStorage?: {
32
+ get: (key: string) => {
33
+ count: number;
34
+ resetTime: number;
35
+ } | undefined;
36
+ set: (key: string, value: {
37
+ count: number;
38
+ resetTime: number;
39
+ }) => void;
40
+ delete: (key: string) => void;
41
+ entries: () => IterableIterator<[string, {
42
+ count: number;
43
+ resetTime: number;
44
+ }]>;
45
+ };
27
46
  /**
28
47
  * 🛑 Custom rate limit exceeded handler
29
48
  * @default Sends 429 status with Retry-After header
30
49
  * @example
31
50
  * onError: (ctx, retryAfter) => {
32
51
  * ctx.status = 429;
33
- * ctx.body = { error: `Try again in ${retryAfter} seconds` };
52
+ * throw new Error( `Rate limit exceeded. Try again in ${retryAfter} seconds.`);
34
53
  * }
35
54
  */
36
55
  onError?: (ctx: Context, retryAfter: number, error: Error) => void;
@@ -1,19 +1,18 @@
1
1
  export const rateLimiter = (options) => {
2
- const { maxRequests, windowMs, keyGenerator = (ctx) => `${ctx.req.remoteAddress.address}:${ctx.req.remoteAddress.port}`, onError = (ctx, retryAfter, error) => {
2
+ const { maxRequests, windowMs, keyGenerator = (ctx) => `${ctx.req.remoteAddress.address}:${ctx.req.remoteAddress.port}`, cacheStorage = new Map(), onError = (ctx, retryAfter, error) => {
3
3
  ctx.setStatus = 429;
4
4
  throw new Error(`Rate limit exceeded. Try again in ${retryAfter} seconds.`);
5
5
  }, } = options;
6
- const memoryStore = new Map();
7
6
  return async (ctx, next) => {
8
7
  const key = keyGenerator(ctx);
9
8
  let requestCount;
10
9
  let resetTime;
11
- for (const [key, entry] of memoryStore.entries()) {
10
+ for (const [key, entry] of cacheStorage.entries()) {
12
11
  if (Date.now() >= entry.resetTime) {
13
- memoryStore.delete(key);
12
+ cacheStorage.delete(key);
14
13
  }
15
14
  }
16
- const entry = memoryStore.get(key);
15
+ const entry = cacheStorage.get(key);
17
16
  if (entry && Date.now() < entry.resetTime) {
18
17
  requestCount = entry.count + 1;
19
18
  resetTime = entry.resetTime;
@@ -21,7 +20,7 @@ export const rateLimiter = (options) => {
21
20
  else {
22
21
  requestCount = 1;
23
22
  resetTime = Date.now() + windowMs;
24
- memoryStore.set(key, { count: requestCount, resetTime });
23
+ cacheStorage.set(key, { count: requestCount, resetTime });
25
24
  }
26
25
  if (requestCount > maxRequests) {
27
26
  const retryAfter = Math.ceil((resetTime - Date.now()) / 1000);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tezx",
3
- "version": "1.0.34",
3
+ "version": "1.0.36",
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",