tezx 1.0.41 → 1.0.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/core/context.js +7 -5
- package/cjs/index.js +1 -1
- package/cjs/middleware/detectBot.js +3 -2
- package/cjs/middleware/pagination.js +4 -2
- package/core/context.d.ts +35 -20
- package/core/context.js +7 -5
- package/core/router.d.ts +4 -3
- package/index.js +1 -1
- package/middleware/detectBot.d.ts +4 -3
- package/middleware/detectBot.js +3 -2
- package/middleware/pagination.d.ts +1 -0
- package/middleware/pagination.js +4 -2
- package/middleware/rateLimiter.d.ts +2 -2
- package/package.json +1 -1
package/cjs/core/context.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Context = exports.httpStatusMap = void 0;
|
|
4
|
+
const state_1 = require("../utils/state");
|
|
5
|
+
const staticFile_1 = require("../utils/staticFile");
|
|
4
6
|
const environment_1 = require("./environment");
|
|
5
7
|
const header_1 = require("./header");
|
|
6
8
|
const request_1 = require("./request");
|
|
7
|
-
const state_1 = require("../utils/state");
|
|
8
|
-
const staticFile_1 = require("../utils/staticFile");
|
|
9
9
|
exports.httpStatusMap = {
|
|
10
10
|
100: "Continue",
|
|
11
11
|
101: "Switching Protocols",
|
|
@@ -81,7 +81,8 @@ class Context {
|
|
|
81
81
|
#status = 200;
|
|
82
82
|
state = new state_1.State();
|
|
83
83
|
#params = {};
|
|
84
|
-
|
|
84
|
+
resBody;
|
|
85
|
+
#body;
|
|
85
86
|
#localAddress = {};
|
|
86
87
|
#remoteAddress = {};
|
|
87
88
|
constructor(req, connInfo) {
|
|
@@ -392,6 +393,7 @@ class Context {
|
|
|
392
393
|
status: status,
|
|
393
394
|
headers,
|
|
394
395
|
});
|
|
396
|
+
this.resBody = body;
|
|
395
397
|
return response;
|
|
396
398
|
}
|
|
397
399
|
get req() {
|
|
@@ -401,10 +403,10 @@ class Context {
|
|
|
401
403
|
this.#params = params;
|
|
402
404
|
}
|
|
403
405
|
set body(body) {
|
|
404
|
-
this.#
|
|
406
|
+
this.#body = body;
|
|
405
407
|
}
|
|
406
408
|
get body() {
|
|
407
|
-
return this.#
|
|
409
|
+
return this.#body;
|
|
408
410
|
}
|
|
409
411
|
get params() {
|
|
410
412
|
return this.#params;
|
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.
|
|
10
|
+
exports.version = "1.0.43";
|
|
@@ -7,7 +7,7 @@ const config_1 = require("../core/config");
|
|
|
7
7
|
const detectBot = (options = {}) => {
|
|
8
8
|
const { botUserAgents = ["bot", "spider", "crawl", "slurp"], maxRequests = 30, windowMs = 60000, isBlacklisted = async () => false, queryKeyBot = "bot", onBotDetected = "block", enableRateLimiting = false, customBotDetector = async () => false, customBlockedResponse = (ctx, { reason }) => {
|
|
9
9
|
ctx.setStatus = 403;
|
|
10
|
-
ctx.
|
|
10
|
+
return ctx.json({ error: `Bot detected: ${reason}` });
|
|
11
11
|
}, storage, confidenceThreshold = 0.5, } = options;
|
|
12
12
|
let store = storage;
|
|
13
13
|
if (enableRateLimiting) {
|
|
@@ -19,7 +19,8 @@ const detectBot = (options = {}) => {
|
|
|
19
19
|
indicators: [],
|
|
20
20
|
};
|
|
21
21
|
const userAgent = ctx.headers.get("user-agent")?.toLowerCase() || "";
|
|
22
|
-
const remoteAddress = `${ctx.req.remoteAddress?.address}:${ctx.req.remoteAddress?.port}` ||
|
|
22
|
+
const remoteAddress = `${ctx.req.remoteAddress?.address}:${ctx.req.remoteAddress?.port}` ||
|
|
23
|
+
"unknown";
|
|
23
24
|
const isBotQuery = ctx.req.query[queryKeyBot] === "true";
|
|
24
25
|
if (botUserAgents.some((agent) => userAgent.includes(agent))) {
|
|
25
26
|
detectionResult.indicators.push("User-Agent");
|
|
@@ -27,6 +27,7 @@ const paginationHandler = (options = {}) => {
|
|
|
27
27
|
const pagination = {
|
|
28
28
|
page,
|
|
29
29
|
limit,
|
|
30
|
+
offset,
|
|
30
31
|
totalItems: total,
|
|
31
32
|
totalPages: Math.ceil(total / limit),
|
|
32
33
|
hasNextPage: page < Math.ceil(total / limit),
|
|
@@ -40,12 +41,13 @@ const paginationHandler = (options = {}) => {
|
|
|
40
41
|
[countKey]: total,
|
|
41
42
|
pagination,
|
|
42
43
|
};
|
|
44
|
+
ctx.body = body;
|
|
43
45
|
if (next) {
|
|
44
|
-
ctx.body = body;
|
|
45
46
|
return await next();
|
|
46
47
|
}
|
|
47
|
-
return
|
|
48
|
+
return ctx.json(body);
|
|
48
49
|
}
|
|
50
|
+
return await next();
|
|
49
51
|
};
|
|
50
52
|
};
|
|
51
53
|
exports.paginationHandler = paginationHandler;
|
package/core/context.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { State } from "../utils/state";
|
|
1
2
|
import { HeadersParser } from "./header";
|
|
2
3
|
import { ConnAddress, HTTPMethod, Request } from "./request";
|
|
3
|
-
import { State } from "../utils/state";
|
|
4
4
|
export interface CookieOptions {
|
|
5
5
|
expires?: Date;
|
|
6
6
|
path?: string;
|
|
@@ -46,6 +46,7 @@ export declare class Context<T extends Record<string, any> = {}> {
|
|
|
46
46
|
* @type {State}
|
|
47
47
|
*/
|
|
48
48
|
state: State;
|
|
49
|
+
protected readonly resBody?: BodyInit | null;
|
|
49
50
|
constructor(req: any, connInfo: ConnAddress);
|
|
50
51
|
/**
|
|
51
52
|
* Appends or set a value to an existing header or creates a new one.
|
|
@@ -60,14 +61,14 @@ export declare class Context<T extends Record<string, any> = {}> {
|
|
|
60
61
|
append?: false;
|
|
61
62
|
}): this;
|
|
62
63
|
/**
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
64
|
+
* Cookie handling utility with get/set/delete operations
|
|
65
|
+
* @returns {{
|
|
66
|
+
* get: (name: string) => string | undefined,
|
|
67
|
+
* all: () => Record<string, string>,
|
|
68
|
+
* delete: (name: string, options?: CookieOptions) => void,
|
|
69
|
+
* set: (name: string, value: string, options?: CookieOptions) => void
|
|
70
|
+
* }} Cookie handling interface
|
|
71
|
+
*/
|
|
71
72
|
get cookies(): {
|
|
72
73
|
/**
|
|
73
74
|
* Get a specific cookie by name.
|
|
@@ -101,9 +102,9 @@ export declare class Context<T extends Record<string, any> = {}> {
|
|
|
101
102
|
* @param headers - (Optional) Additional response headers.
|
|
102
103
|
* @returns Response object with JSON data.
|
|
103
104
|
*/
|
|
104
|
-
json(body:
|
|
105
|
-
json(body:
|
|
106
|
-
json(body:
|
|
105
|
+
json(body: object, status?: number, headers?: ResponseHeaders): Response;
|
|
106
|
+
json(body: object, headers?: ResponseHeaders): Response;
|
|
107
|
+
json(body: object, status?: number): Response;
|
|
107
108
|
/**
|
|
108
109
|
* Sends a response with any content type.
|
|
109
110
|
* Automatically determines content type if not provided.
|
|
@@ -193,16 +194,30 @@ export declare class Context<T extends Record<string, any> = {}> {
|
|
|
193
194
|
get req(): Request;
|
|
194
195
|
protected set params(params: Record<string, any>);
|
|
195
196
|
/**
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
197
|
+
* Set response body to be passed between middlewares or returned as final output.
|
|
198
|
+
*
|
|
199
|
+
* 🔄 Use-case:
|
|
200
|
+
* - Middleware or route handlers can set this value to share data.
|
|
201
|
+
* - If no explicit Response is returned (e.g., `ctx.json()` or `new Response()`),
|
|
202
|
+
* then this body will be auto-wrapped into a `Response` by the framework.
|
|
203
|
+
*
|
|
204
|
+
* ⚠️ Note:
|
|
205
|
+
* Always use `return next()` or an explicit return like `return ctx.json(...)`
|
|
206
|
+
* to ensure proper flow control and response resolution.
|
|
207
|
+
*
|
|
208
|
+
* @param body - The response content (string, object, etc).
|
|
199
209
|
*/
|
|
200
|
-
set body(body: any
|
|
210
|
+
set body(body: any);
|
|
201
211
|
/**
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
212
|
+
* Get the current response body.
|
|
213
|
+
*
|
|
214
|
+
* 🧠 Use-case:
|
|
215
|
+
* - Allows middleware or route handler to access any pre-set data
|
|
216
|
+
* from earlier in the middleware chain.
|
|
217
|
+
* - Common for situations where response is deferred or centrally handled.
|
|
218
|
+
*
|
|
219
|
+
* @returns The currently stored response body.
|
|
205
220
|
*/
|
|
206
|
-
get body(): any
|
|
221
|
+
get body(): any;
|
|
207
222
|
protected get params(): Record<string, any>;
|
|
208
223
|
}
|
package/core/context.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { State } from "../utils/state";
|
|
2
|
+
import { defaultMimeType, mimeTypes } from "../utils/staticFile";
|
|
1
3
|
import { EnvironmentDetector } from "./environment";
|
|
2
4
|
import { HeadersParser } from "./header";
|
|
3
5
|
import { Request } from "./request";
|
|
4
|
-
import { State } from "../utils/state";
|
|
5
|
-
import { defaultMimeType, mimeTypes } from "../utils/staticFile";
|
|
6
6
|
export const httpStatusMap = {
|
|
7
7
|
100: "Continue",
|
|
8
8
|
101: "Switching Protocols",
|
|
@@ -78,7 +78,8 @@ export class Context {
|
|
|
78
78
|
#status = 200;
|
|
79
79
|
state = new State();
|
|
80
80
|
#params = {};
|
|
81
|
-
|
|
81
|
+
resBody;
|
|
82
|
+
#body;
|
|
82
83
|
#localAddress = {};
|
|
83
84
|
#remoteAddress = {};
|
|
84
85
|
constructor(req, connInfo) {
|
|
@@ -389,6 +390,7 @@ export class Context {
|
|
|
389
390
|
status: status,
|
|
390
391
|
headers,
|
|
391
392
|
});
|
|
393
|
+
this.resBody = body;
|
|
392
394
|
return response;
|
|
393
395
|
}
|
|
394
396
|
get req() {
|
|
@@ -398,10 +400,10 @@ export class Context {
|
|
|
398
400
|
this.#params = params;
|
|
399
401
|
}
|
|
400
402
|
set body(body) {
|
|
401
|
-
this.#
|
|
403
|
+
this.#body = body;
|
|
402
404
|
}
|
|
403
405
|
get body() {
|
|
404
|
-
return this.#
|
|
406
|
+
return this.#body;
|
|
405
407
|
}
|
|
406
408
|
get params() {
|
|
407
409
|
return this.#params;
|
package/core/router.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Context, ResponseHeaders } from "./context";
|
|
2
2
|
import MiddlewareConfigure, { DuplicateMiddlewares, UniqueMiddlewares } from "./MiddlewareConfigure";
|
|
3
3
|
import { HTTPMethod } from "./request";
|
|
4
|
-
export type NextCallback = () => Promise<any>;
|
|
5
4
|
export type ctx<T extends Record<string, any> = {}> = Context<T> & T;
|
|
6
|
-
export type
|
|
7
|
-
export type
|
|
5
|
+
export type NextCallback = () => Promise<any>;
|
|
6
|
+
export type CallbackReturn = Promise<Response> | Response;
|
|
7
|
+
export type Callback<T extends Record<string, any> = {}> = (ctx: ctx<T>) => CallbackReturn;
|
|
8
|
+
export type Middleware<T extends Record<string, any> = {}> = (ctx: ctx<T>, next: NextCallback) => Promise<Response> | Response | NextCallback;
|
|
8
9
|
export type RouterConfig = {
|
|
9
10
|
/**
|
|
10
11
|
* `env` allows you to define environment variables for the router.
|
package/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Context, Middleware } from "..";
|
|
2
|
+
import { CallbackReturn } from "../core/router";
|
|
2
3
|
export type DetectBotReason = "User-Agent" | "Blacklisted IP" | "Query Parameter" | "Rate Limiting" | "Custom Detector" | "Multiple Indicators";
|
|
3
4
|
type BotDetectionResult = {
|
|
4
5
|
isBot: boolean;
|
|
@@ -35,7 +36,7 @@ type DetectBotOptions = {
|
|
|
35
36
|
* 🛡️ Action to take when bot is detected
|
|
36
37
|
* @default "block"
|
|
37
38
|
*/
|
|
38
|
-
onBotDetected?: "block" | ((ctx: Context, result: BotDetectionResult) =>
|
|
39
|
+
onBotDetected?: "block" | ((ctx: Context, result: BotDetectionResult) => CallbackReturn);
|
|
39
40
|
/**
|
|
40
41
|
* ⚖️ Enable rate-limiting based detection
|
|
41
42
|
* @default false
|
|
@@ -49,7 +50,7 @@ type DetectBotOptions = {
|
|
|
49
50
|
/**
|
|
50
51
|
* ✉️ Custom response for blocked requests
|
|
51
52
|
*/
|
|
52
|
-
customBlockedResponse?: (ctx: Context, result: BotDetectionResult) =>
|
|
53
|
+
customBlockedResponse?: (ctx: Context, result: BotDetectionResult) => CallbackReturn;
|
|
53
54
|
/**
|
|
54
55
|
* 🔄 Custom cache storage implementation (e.g., using `Map`, `Redis`, etc.).
|
|
55
56
|
* By default, it uses a `Map<string, { count: number; resetTime: number }>`.
|
|
@@ -96,7 +97,7 @@ type DetectBotOptions = {
|
|
|
96
97
|
* isBlacklistedIP: async (ip) => await checkIPReputation(ip),
|
|
97
98
|
* onBotDetected: (ctx, { reason }) => {
|
|
98
99
|
* ctx.status = 403;
|
|
99
|
-
* ctx.
|
|
100
|
+
* return ctx.json({ error: `Bot detected (${reason})` });
|
|
100
101
|
* }
|
|
101
102
|
* }));
|
|
102
103
|
*/
|
package/middleware/detectBot.js
CHANGED
|
@@ -2,7 +2,7 @@ import { GlobalConfig } from "../core/config";
|
|
|
2
2
|
export const detectBot = (options = {}) => {
|
|
3
3
|
const { botUserAgents = ["bot", "spider", "crawl", "slurp"], maxRequests = 30, windowMs = 60000, isBlacklisted = async () => false, queryKeyBot = "bot", onBotDetected = "block", enableRateLimiting = false, customBotDetector = async () => false, customBlockedResponse = (ctx, { reason }) => {
|
|
4
4
|
ctx.setStatus = 403;
|
|
5
|
-
ctx.
|
|
5
|
+
return ctx.json({ error: `Bot detected: ${reason}` });
|
|
6
6
|
}, storage, confidenceThreshold = 0.5, } = options;
|
|
7
7
|
let store = storage;
|
|
8
8
|
if (enableRateLimiting) {
|
|
@@ -14,7 +14,8 @@ export const detectBot = (options = {}) => {
|
|
|
14
14
|
indicators: [],
|
|
15
15
|
};
|
|
16
16
|
const userAgent = ctx.headers.get("user-agent")?.toLowerCase() || "";
|
|
17
|
-
const remoteAddress = `${ctx.req.remoteAddress?.address}:${ctx.req.remoteAddress?.port}` ||
|
|
17
|
+
const remoteAddress = `${ctx.req.remoteAddress?.address}:${ctx.req.remoteAddress?.port}` ||
|
|
18
|
+
"unknown";
|
|
18
19
|
const isBotQuery = ctx.req.query[queryKeyBot] === "true";
|
|
19
20
|
if (botUserAgents.some((agent) => userAgent.includes(agent))) {
|
|
20
21
|
detectionResult.indicators.push("User-Agent");
|
package/middleware/pagination.js
CHANGED
|
@@ -24,6 +24,7 @@ export const paginationHandler = (options = {}) => {
|
|
|
24
24
|
const pagination = {
|
|
25
25
|
page,
|
|
26
26
|
limit,
|
|
27
|
+
offset,
|
|
27
28
|
totalItems: total,
|
|
28
29
|
totalPages: Math.ceil(total / limit),
|
|
29
30
|
hasNextPage: page < Math.ceil(total / limit),
|
|
@@ -37,11 +38,12 @@ export const paginationHandler = (options = {}) => {
|
|
|
37
38
|
[countKey]: total,
|
|
38
39
|
pagination,
|
|
39
40
|
};
|
|
41
|
+
ctx.body = body;
|
|
40
42
|
if (next) {
|
|
41
|
-
ctx.body = body;
|
|
42
43
|
return await next();
|
|
43
44
|
}
|
|
44
|
-
return
|
|
45
|
+
return ctx.json(body);
|
|
45
46
|
}
|
|
47
|
+
return await next();
|
|
46
48
|
};
|
|
47
49
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Context } from "../core/context";
|
|
2
|
-
import { Middleware } from "../core/router";
|
|
2
|
+
import { CallbackReturn, Middleware } from "../core/router";
|
|
3
3
|
export type RateLimiterOptions = {
|
|
4
4
|
/**
|
|
5
5
|
* 🔴 Maximum allowed requests in the time window
|
|
@@ -49,7 +49,7 @@ export type RateLimiterOptions = {
|
|
|
49
49
|
* throw new Error( `Rate limit exceeded. Try again in ${retryAfter} seconds.`);
|
|
50
50
|
* }
|
|
51
51
|
*/
|
|
52
|
-
onError?: (ctx: Context, retryAfter: number, error: Error) =>
|
|
52
|
+
onError?: (ctx: Context, retryAfter: number, error: Error) => CallbackReturn;
|
|
53
53
|
};
|
|
54
54
|
/**
|
|
55
55
|
* 🚦 Rate limiting middleware for request throttling
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tezx",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.43",
|
|
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",
|