te.js 2.0.3 → 2.1.1
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/README.md +197 -187
- package/auto-docs/analysis/handler-analyzer.js +58 -58
- package/auto-docs/analysis/source-resolver.js +101 -101
- package/auto-docs/constants.js +37 -37
- package/auto-docs/docs-llm/index.js +7 -0
- package/auto-docs/{llm → docs-llm}/prompts.js +222 -222
- package/auto-docs/{llm → docs-llm}/provider.js +132 -187
- package/auto-docs/index.js +146 -146
- package/auto-docs/openapi/endpoint-processor.js +277 -277
- package/auto-docs/openapi/generator.js +107 -107
- package/auto-docs/openapi/level3.js +131 -131
- package/auto-docs/openapi/spec-builders.js +244 -244
- package/auto-docs/ui/docs-ui.js +186 -186
- package/auto-docs/utils/logger.js +17 -17
- package/auto-docs/utils/strip-usage.js +10 -10
- package/cli/docs-command.js +315 -315
- package/cli/fly-command.js +71 -71
- package/cli/index.js +56 -56
- package/database/index.js +165 -165
- package/database/mongodb.js +146 -146
- package/database/redis.js +201 -201
- package/docs/README.md +36 -36
- package/docs/ammo.md +362 -362
- package/docs/api-reference.md +490 -489
- package/docs/auto-docs.md +216 -215
- package/docs/cli.md +152 -152
- package/docs/configuration.md +275 -233
- package/docs/database.md +390 -391
- package/docs/error-handling.md +438 -417
- package/docs/file-uploads.md +333 -334
- package/docs/getting-started.md +214 -215
- package/docs/middleware.md +355 -356
- package/docs/rate-limiting.md +393 -394
- package/docs/routing.md +302 -302
- package/package.json +62 -62
- package/rate-limit/algorithms/fixed-window.js +141 -141
- package/rate-limit/algorithms/sliding-window.js +147 -147
- package/rate-limit/algorithms/token-bucket.js +115 -115
- package/rate-limit/base.js +165 -165
- package/rate-limit/index.js +147 -147
- package/rate-limit/storage/base.js +104 -104
- package/rate-limit/storage/memory.js +101 -101
- package/rate-limit/storage/redis.js +88 -88
- package/server/ammo/body-parser.js +220 -220
- package/server/ammo/dispatch-helper.js +103 -103
- package/server/ammo/enhancer.js +57 -57
- package/server/ammo.js +454 -356
- package/server/endpoint.js +97 -74
- package/server/error.js +9 -9
- package/server/errors/code-context.js +125 -0
- package/server/errors/llm-error-service.js +140 -0
- package/server/files/helper.js +33 -33
- package/server/files/uploader.js +143 -143
- package/server/handler.js +158 -113
- package/server/target.js +185 -175
- package/server/targets/middleware-validator.js +22 -22
- package/server/targets/path-validator.js +21 -21
- package/server/targets/registry.js +160 -160
- package/server/targets/shoot-validator.js +21 -21
- package/te.js +428 -363
- package/utils/auto-register.js +17 -17
- package/utils/configuration.js +64 -64
- package/utils/errors-llm-config.js +84 -0
- package/utils/request-logger.js +43 -43
- package/utils/status-codes.js +82 -82
- package/utils/tejas-entrypoint-html.js +18 -18
- package/auto-docs/llm/index.js +0 -6
- package/auto-docs/llm/parse.js +0 -88
package/package.json
CHANGED
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "te.js",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "A nodejs framework",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "te.js",
|
|
7
|
-
"bin": {
|
|
8
|
-
"tejas": "
|
|
9
|
-
},
|
|
10
|
-
"scripts": {
|
|
11
|
-
"start": "node te.js",
|
|
12
|
-
"test": "vitest",
|
|
13
|
-
"test:run": "vitest run",
|
|
14
|
-
"test:coverage": "vitest run --coverage",
|
|
15
|
-
"prepare": "husky"
|
|
16
|
-
},
|
|
17
|
-
"author": "Hirak",
|
|
18
|
-
"license": "ISC",
|
|
19
|
-
"devDependencies": {
|
|
20
|
-
"@types/node": "^20.12.5",
|
|
21
|
-
"husky": "^9.0.11",
|
|
22
|
-
"lint-staged": "^15.2.2",
|
|
23
|
-
"prettier": "3.2.5",
|
|
24
|
-
"vitest": "^4.0.18"
|
|
25
|
-
},
|
|
26
|
-
"repository": {
|
|
27
|
-
"type": "git",
|
|
28
|
-
"url": "git+ssh://git@github.com/hirakchhatbar/te.js.git"
|
|
29
|
-
},
|
|
30
|
-
"files": [
|
|
31
|
-
"te.js",
|
|
32
|
-
"cli",
|
|
33
|
-
"server",
|
|
34
|
-
"database",
|
|
35
|
-
"rate-limit",
|
|
36
|
-
"utils",
|
|
37
|
-
"auto-docs",
|
|
38
|
-
"README.md",
|
|
39
|
-
"docs"
|
|
40
|
-
],
|
|
41
|
-
"dependencies": {
|
|
42
|
-
"ansi-colors": "^4.1.3",
|
|
43
|
-
"filesize": "^10.1.1",
|
|
44
|
-
"formidable": "^3.5.1",
|
|
45
|
-
"mime": "^4.0.1",
|
|
46
|
-
"statuses": "^2.0.1",
|
|
47
|
-
"tej-env": "^1.1.3",
|
|
48
|
-
"tej-logger": "^1.2.1"
|
|
49
|
-
},
|
|
50
|
-
"husky": {
|
|
51
|
-
"hooks": {
|
|
52
|
-
"pre-commit": "lint-staged",
|
|
53
|
-
"pre-push": "npm test"
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
"lint-staged": {
|
|
57
|
-
"src/**/*.{js,jsx}": [
|
|
58
|
-
"pretty-quick --staged",
|
|
59
|
-
"eslint --fix"
|
|
60
|
-
]
|
|
61
|
-
}
|
|
62
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "te.js",
|
|
3
|
+
"version": "2.1.1",
|
|
4
|
+
"description": "A nodejs framework",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "te.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"tejas": "cli/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node te.js",
|
|
12
|
+
"test": "vitest",
|
|
13
|
+
"test:run": "vitest run",
|
|
14
|
+
"test:coverage": "vitest run --coverage",
|
|
15
|
+
"prepare": "husky"
|
|
16
|
+
},
|
|
17
|
+
"author": "Hirak",
|
|
18
|
+
"license": "ISC",
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^20.12.5",
|
|
21
|
+
"husky": "^9.0.11",
|
|
22
|
+
"lint-staged": "^15.2.2",
|
|
23
|
+
"prettier": "3.2.5",
|
|
24
|
+
"vitest": "^4.0.18"
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+ssh://git@github.com/hirakchhatbar/te.js.git"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"te.js",
|
|
32
|
+
"cli",
|
|
33
|
+
"server",
|
|
34
|
+
"database",
|
|
35
|
+
"rate-limit",
|
|
36
|
+
"utils",
|
|
37
|
+
"auto-docs",
|
|
38
|
+
"README.md",
|
|
39
|
+
"docs"
|
|
40
|
+
],
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"ansi-colors": "^4.1.3",
|
|
43
|
+
"filesize": "^10.1.1",
|
|
44
|
+
"formidable": "^3.5.1",
|
|
45
|
+
"mime": "^4.0.1",
|
|
46
|
+
"statuses": "^2.0.1",
|
|
47
|
+
"tej-env": "^1.1.3",
|
|
48
|
+
"tej-logger": "^1.2.1"
|
|
49
|
+
},
|
|
50
|
+
"husky": {
|
|
51
|
+
"hooks": {
|
|
52
|
+
"pre-commit": "lint-staged",
|
|
53
|
+
"pre-push": "npm test"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"lint-staged": {
|
|
57
|
+
"src/**/*.{js,jsx}": [
|
|
58
|
+
"pretty-quick --staged",
|
|
59
|
+
"eslint --fix"
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -1,141 +1,141 @@
|
|
|
1
|
-
import RateLimiter from '../base.js';
|
|
2
|
-
import TejError from '../../server/error.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Fixed Window Rate Limiter Implementation
|
|
6
|
-
*
|
|
7
|
-
* @extends RateLimiter
|
|
8
|
-
* @description
|
|
9
|
-
* The fixed window algorithm uses discrete time windows to track and limit requests.
|
|
10
|
-
* It's the simplest rate limiting approach, but can allow request spikes at window boundaries
|
|
11
|
-
* when using rolling windows. This can be mitigated by using strict window alignment with
|
|
12
|
-
* clock time.
|
|
13
|
-
*
|
|
14
|
-
* Key features:
|
|
15
|
-
* - Simple to understand and implement
|
|
16
|
-
* - Low memory usage (only stores counter and window start time)
|
|
17
|
-
* - Optional strict window alignment with clock time
|
|
18
|
-
* - Best for cases where precise spacing of requests is not critical
|
|
19
|
-
*
|
|
20
|
-
* Window types:
|
|
21
|
-
* 1. Rolling windows: Start when first request arrives
|
|
22
|
-
* 2. Strict windows: Align with clock time (e.g. every minute)
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* // Create a fixed window rate limiter with strict clock alignment
|
|
26
|
-
* const limiter = new FixedWindowRateLimiter({
|
|
27
|
-
* maxRequests: 60, // Allow 60 requests per minute
|
|
28
|
-
* timeWindowSeconds: 60,
|
|
29
|
-
* fixedWindow: {
|
|
30
|
-
* strictWindow: true // Align windows with clock minutes
|
|
31
|
-
* }
|
|
32
|
-
* });
|
|
33
|
-
*
|
|
34
|
-
* // Use in an API endpoint
|
|
35
|
-
* async function handleRequest(ip) {
|
|
36
|
-
* const result = await limiter.consume(ip);
|
|
37
|
-
* if (!result.success) {
|
|
38
|
-
* throw new TejError(429, 'Rate limit exceeded');
|
|
39
|
-
* }
|
|
40
|
-
* // Process request...
|
|
41
|
-
* }
|
|
42
|
-
*/
|
|
43
|
-
class FixedWindowRateLimiter extends RateLimiter {
|
|
44
|
-
constructor(options) {
|
|
45
|
-
if (!options.fixedWindowConfig) {
|
|
46
|
-
options.fixedWindowConfig = {}; // Ensure defaults are set in base class
|
|
47
|
-
}
|
|
48
|
-
super(options);
|
|
49
|
-
|
|
50
|
-
if (!this.fixedWindowOptions) {
|
|
51
|
-
throw new TejError(
|
|
52
|
-
400,
|
|
53
|
-
'FixedWindowRateLimiter requires fixedWindowConfig options',
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Check if a request should be allowed within the current window
|
|
60
|
-
*
|
|
61
|
-
* @param {string} identifier - Unique identifier for rate limiting (e.g., IP address, user ID)
|
|
62
|
-
* @returns {Promise<Object>} Rate limit check result
|
|
63
|
-
* @returns {boolean} result.success - Whether the request is allowed
|
|
64
|
-
* @returns {number} result.remainingRequests - Number of requests remaining in the window
|
|
65
|
-
* @returns {number} result.resetTime - Unix timestamp when the current window ends
|
|
66
|
-
*/
|
|
67
|
-
async consume(identifier) {
|
|
68
|
-
const key = this.getKey(identifier);
|
|
69
|
-
const now = Date.now();
|
|
70
|
-
const options = this.getAlgorithmOptions('fixed-window');
|
|
71
|
-
|
|
72
|
-
// If using strict windows, align window start with clock
|
|
73
|
-
const windowStart = options.strictWindow
|
|
74
|
-
? Math.floor(now / (this.options.timeWindowSeconds * 1000)) *
|
|
75
|
-
(this.options.timeWindowSeconds * 1000)
|
|
76
|
-
: now;
|
|
77
|
-
|
|
78
|
-
const stored = await this.storage.get(key);
|
|
79
|
-
if (!stored) {
|
|
80
|
-
await this.storage.set(
|
|
81
|
-
key,
|
|
82
|
-
{
|
|
83
|
-
counter: 1,
|
|
84
|
-
startTime: windowStart,
|
|
85
|
-
},
|
|
86
|
-
this.options.timeWindowSeconds,
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
return {
|
|
90
|
-
success: true,
|
|
91
|
-
remainingRequests: this.options.maxRequests - 1,
|
|
92
|
-
resetTime: Math.floor(
|
|
93
|
-
windowStart / 1000 + this.options.timeWindowSeconds,
|
|
94
|
-
),
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// If using strict windows, check if we need to start a new window
|
|
99
|
-
if (options.strictWindow && stored.startTime < windowStart) {
|
|
100
|
-
await this.storage.set(
|
|
101
|
-
key,
|
|
102
|
-
{
|
|
103
|
-
counter: 1,
|
|
104
|
-
startTime: windowStart,
|
|
105
|
-
},
|
|
106
|
-
this.options.timeWindowSeconds,
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
return {
|
|
110
|
-
success: true,
|
|
111
|
-
remainingRequests: this.options.maxRequests - 1,
|
|
112
|
-
resetTime: Math.floor(
|
|
113
|
-
windowStart / 1000 + this.options.timeWindowSeconds,
|
|
114
|
-
),
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (stored.counter >= this.options.maxRequests) {
|
|
119
|
-
return {
|
|
120
|
-
success: false,
|
|
121
|
-
remainingRequests: 0,
|
|
122
|
-
resetTime: Math.floor(
|
|
123
|
-
stored.startTime / 1000 + this.options.timeWindowSeconds,
|
|
124
|
-
),
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
stored.counter++;
|
|
129
|
-
await this.storage.set(key, stored, this.options.timeWindowSeconds);
|
|
130
|
-
|
|
131
|
-
return {
|
|
132
|
-
success: true,
|
|
133
|
-
remainingRequests: this.options.maxRequests - stored.counter,
|
|
134
|
-
resetTime: Math.floor(
|
|
135
|
-
stored.startTime / 1000 + this.options.timeWindowSeconds,
|
|
136
|
-
),
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export default FixedWindowRateLimiter;
|
|
1
|
+
import RateLimiter from '../base.js';
|
|
2
|
+
import TejError from '../../server/error.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Fixed Window Rate Limiter Implementation
|
|
6
|
+
*
|
|
7
|
+
* @extends RateLimiter
|
|
8
|
+
* @description
|
|
9
|
+
* The fixed window algorithm uses discrete time windows to track and limit requests.
|
|
10
|
+
* It's the simplest rate limiting approach, but can allow request spikes at window boundaries
|
|
11
|
+
* when using rolling windows. This can be mitigated by using strict window alignment with
|
|
12
|
+
* clock time.
|
|
13
|
+
*
|
|
14
|
+
* Key features:
|
|
15
|
+
* - Simple to understand and implement
|
|
16
|
+
* - Low memory usage (only stores counter and window start time)
|
|
17
|
+
* - Optional strict window alignment with clock time
|
|
18
|
+
* - Best for cases where precise spacing of requests is not critical
|
|
19
|
+
*
|
|
20
|
+
* Window types:
|
|
21
|
+
* 1. Rolling windows: Start when first request arrives
|
|
22
|
+
* 2. Strict windows: Align with clock time (e.g. every minute)
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // Create a fixed window rate limiter with strict clock alignment
|
|
26
|
+
* const limiter = new FixedWindowRateLimiter({
|
|
27
|
+
* maxRequests: 60, // Allow 60 requests per minute
|
|
28
|
+
* timeWindowSeconds: 60,
|
|
29
|
+
* fixedWindow: {
|
|
30
|
+
* strictWindow: true // Align windows with clock minutes
|
|
31
|
+
* }
|
|
32
|
+
* });
|
|
33
|
+
*
|
|
34
|
+
* // Use in an API endpoint
|
|
35
|
+
* async function handleRequest(ip) {
|
|
36
|
+
* const result = await limiter.consume(ip);
|
|
37
|
+
* if (!result.success) {
|
|
38
|
+
* throw new TejError(429, 'Rate limit exceeded');
|
|
39
|
+
* }
|
|
40
|
+
* // Process request...
|
|
41
|
+
* }
|
|
42
|
+
*/
|
|
43
|
+
class FixedWindowRateLimiter extends RateLimiter {
|
|
44
|
+
constructor(options) {
|
|
45
|
+
if (!options.fixedWindowConfig) {
|
|
46
|
+
options.fixedWindowConfig = {}; // Ensure defaults are set in base class
|
|
47
|
+
}
|
|
48
|
+
super(options);
|
|
49
|
+
|
|
50
|
+
if (!this.fixedWindowOptions) {
|
|
51
|
+
throw new TejError(
|
|
52
|
+
400,
|
|
53
|
+
'FixedWindowRateLimiter requires fixedWindowConfig options',
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Check if a request should be allowed within the current window
|
|
60
|
+
*
|
|
61
|
+
* @param {string} identifier - Unique identifier for rate limiting (e.g., IP address, user ID)
|
|
62
|
+
* @returns {Promise<Object>} Rate limit check result
|
|
63
|
+
* @returns {boolean} result.success - Whether the request is allowed
|
|
64
|
+
* @returns {number} result.remainingRequests - Number of requests remaining in the window
|
|
65
|
+
* @returns {number} result.resetTime - Unix timestamp when the current window ends
|
|
66
|
+
*/
|
|
67
|
+
async consume(identifier) {
|
|
68
|
+
const key = this.getKey(identifier);
|
|
69
|
+
const now = Date.now();
|
|
70
|
+
const options = this.getAlgorithmOptions('fixed-window');
|
|
71
|
+
|
|
72
|
+
// If using strict windows, align window start with clock
|
|
73
|
+
const windowStart = options.strictWindow
|
|
74
|
+
? Math.floor(now / (this.options.timeWindowSeconds * 1000)) *
|
|
75
|
+
(this.options.timeWindowSeconds * 1000)
|
|
76
|
+
: now;
|
|
77
|
+
|
|
78
|
+
const stored = await this.storage.get(key);
|
|
79
|
+
if (!stored) {
|
|
80
|
+
await this.storage.set(
|
|
81
|
+
key,
|
|
82
|
+
{
|
|
83
|
+
counter: 1,
|
|
84
|
+
startTime: windowStart,
|
|
85
|
+
},
|
|
86
|
+
this.options.timeWindowSeconds,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
success: true,
|
|
91
|
+
remainingRequests: this.options.maxRequests - 1,
|
|
92
|
+
resetTime: Math.floor(
|
|
93
|
+
windowStart / 1000 + this.options.timeWindowSeconds,
|
|
94
|
+
),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// If using strict windows, check if we need to start a new window
|
|
99
|
+
if (options.strictWindow && stored.startTime < windowStart) {
|
|
100
|
+
await this.storage.set(
|
|
101
|
+
key,
|
|
102
|
+
{
|
|
103
|
+
counter: 1,
|
|
104
|
+
startTime: windowStart,
|
|
105
|
+
},
|
|
106
|
+
this.options.timeWindowSeconds,
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
success: true,
|
|
111
|
+
remainingRequests: this.options.maxRequests - 1,
|
|
112
|
+
resetTime: Math.floor(
|
|
113
|
+
windowStart / 1000 + this.options.timeWindowSeconds,
|
|
114
|
+
),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (stored.counter >= this.options.maxRequests) {
|
|
119
|
+
return {
|
|
120
|
+
success: false,
|
|
121
|
+
remainingRequests: 0,
|
|
122
|
+
resetTime: Math.floor(
|
|
123
|
+
stored.startTime / 1000 + this.options.timeWindowSeconds,
|
|
124
|
+
),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
stored.counter++;
|
|
129
|
+
await this.storage.set(key, stored, this.options.timeWindowSeconds);
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
success: true,
|
|
133
|
+
remainingRequests: this.options.maxRequests - stored.counter,
|
|
134
|
+
resetTime: Math.floor(
|
|
135
|
+
stored.startTime / 1000 + this.options.timeWindowSeconds,
|
|
136
|
+
),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export default FixedWindowRateLimiter;
|