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.
Files changed (68) hide show
  1. package/README.md +197 -187
  2. package/auto-docs/analysis/handler-analyzer.js +58 -58
  3. package/auto-docs/analysis/source-resolver.js +101 -101
  4. package/auto-docs/constants.js +37 -37
  5. package/auto-docs/docs-llm/index.js +7 -0
  6. package/auto-docs/{llm → docs-llm}/prompts.js +222 -222
  7. package/auto-docs/{llm → docs-llm}/provider.js +132 -187
  8. package/auto-docs/index.js +146 -146
  9. package/auto-docs/openapi/endpoint-processor.js +277 -277
  10. package/auto-docs/openapi/generator.js +107 -107
  11. package/auto-docs/openapi/level3.js +131 -131
  12. package/auto-docs/openapi/spec-builders.js +244 -244
  13. package/auto-docs/ui/docs-ui.js +186 -186
  14. package/auto-docs/utils/logger.js +17 -17
  15. package/auto-docs/utils/strip-usage.js +10 -10
  16. package/cli/docs-command.js +315 -315
  17. package/cli/fly-command.js +71 -71
  18. package/cli/index.js +56 -56
  19. package/database/index.js +165 -165
  20. package/database/mongodb.js +146 -146
  21. package/database/redis.js +201 -201
  22. package/docs/README.md +36 -36
  23. package/docs/ammo.md +362 -362
  24. package/docs/api-reference.md +490 -489
  25. package/docs/auto-docs.md +216 -215
  26. package/docs/cli.md +152 -152
  27. package/docs/configuration.md +275 -233
  28. package/docs/database.md +390 -391
  29. package/docs/error-handling.md +438 -417
  30. package/docs/file-uploads.md +333 -334
  31. package/docs/getting-started.md +214 -215
  32. package/docs/middleware.md +355 -356
  33. package/docs/rate-limiting.md +393 -394
  34. package/docs/routing.md +302 -302
  35. package/package.json +62 -62
  36. package/rate-limit/algorithms/fixed-window.js +141 -141
  37. package/rate-limit/algorithms/sliding-window.js +147 -147
  38. package/rate-limit/algorithms/token-bucket.js +115 -115
  39. package/rate-limit/base.js +165 -165
  40. package/rate-limit/index.js +147 -147
  41. package/rate-limit/storage/base.js +104 -104
  42. package/rate-limit/storage/memory.js +101 -101
  43. package/rate-limit/storage/redis.js +88 -88
  44. package/server/ammo/body-parser.js +220 -220
  45. package/server/ammo/dispatch-helper.js +103 -103
  46. package/server/ammo/enhancer.js +57 -57
  47. package/server/ammo.js +454 -356
  48. package/server/endpoint.js +97 -74
  49. package/server/error.js +9 -9
  50. package/server/errors/code-context.js +125 -0
  51. package/server/errors/llm-error-service.js +140 -0
  52. package/server/files/helper.js +33 -33
  53. package/server/files/uploader.js +143 -143
  54. package/server/handler.js +158 -113
  55. package/server/target.js +185 -175
  56. package/server/targets/middleware-validator.js +22 -22
  57. package/server/targets/path-validator.js +21 -21
  58. package/server/targets/registry.js +160 -160
  59. package/server/targets/shoot-validator.js +21 -21
  60. package/te.js +428 -363
  61. package/utils/auto-register.js +17 -17
  62. package/utils/configuration.js +64 -64
  63. package/utils/errors-llm-config.js +84 -0
  64. package/utils/request-logger.js +43 -43
  65. package/utils/status-codes.js +82 -82
  66. package/utils/tejas-entrypoint-html.js +18 -18
  67. package/auto-docs/llm/index.js +0 -6
  68. package/auto-docs/llm/parse.js +0 -88
@@ -1,147 +1,147 @@
1
- import RateLimiter from '../base.js';
2
- import TejError from '../../server/error.js';
3
-
4
- /**
5
- * Sliding Window Rate Limiter Implementation
6
- *
7
- * @extends RateLimiter
8
- * @description
9
- * The sliding window algorithm provides precise rate limiting by considering both the current
10
- * and previous time windows with configurable weights. This prevents traffic spikes that can
11
- * occur at window boundaries with fixed window rate limiting.
12
- *
13
- * Key features:
14
- * - Smoother rate limiting than fixed windows
15
- * - Prevents boundary spike issues
16
- * - Configurable time granularity
17
- * - Weighted window transitions
18
- *
19
- * For example, with 60-second windows and 30 seconds into the current window:
20
- * - Current window gets full weight (e.g. 1.0)
21
- * - Previous window gets partial weight (e.g. 0.5)
22
- * Total requests = (current_requests * 1.0) + (previous_requests * 0.5)
23
- *
24
- * @example
25
- * // Create a sliding window rate limiter with weighted windows
26
- * const limiter = new SlidingWindowRateLimiter({
27
- * maxRequests: 100, // Allow 100 requests per minute
28
- * timeWindowSeconds: 60,
29
- * slidingWindow: {
30
- * granularity: 1, // 1-second precision
31
- * weights: {
32
- * current: 1, // Full weight for current window
33
- * previous: 0.5 // Half weight for previous window
34
- * }
35
- * }
36
- * });
37
- *
38
- * // Use in an API endpoint
39
- * async function handleRequest(ip) {
40
- * const result = await limiter.consume(ip);
41
- * if (!result.success) {
42
- * throw new TejError(429, 'Rate limit exceeded');
43
- * }
44
- * // Process request...
45
- * }
46
- */
47
- class SlidingWindowRateLimiter extends RateLimiter {
48
- constructor(options) {
49
- if (!options.slidingWindowConfig) {
50
- options.slidingWindowConfig = {}; // Ensure defaults are set in base class
51
- }
52
- super(options);
53
-
54
- if (!this.slidingWindowOptions) {
55
- throw new TejError(
56
- 400,
57
- 'SlidingWindowRateLimiter requires slidingWindowConfig options',
58
- );
59
- }
60
- }
61
-
62
- /**
63
- * Check if a request should be allowed based on weighted window counts
64
- *
65
- * @param {string} identifier - Unique identifier for rate limiting (e.g., IP address, user ID)
66
- * @returns {Promise<Object>} Rate limit check result
67
- * @returns {boolean} result.success - Whether the request is allowed
68
- * @returns {number} result.remainingRequests - Number of requests remaining in the current window
69
- * @returns {number} result.resetTime - Unix timestamp when the current window ends
70
- */
71
- async consume(identifier) {
72
- const key = this.getKey(identifier);
73
- const now = Date.now();
74
- const options = this.getAlgorithmOptions('sliding-window');
75
-
76
- const stored = await this.storage.get(key);
77
- if (!stored) {
78
- await this.storage.set(
79
- key,
80
- {
81
- counter: 1,
82
- timestamps: [now],
83
- windowStart:
84
- Math.floor(now / (options.granularity * 1000)) *
85
- (options.granularity * 1000),
86
- },
87
- this.options.timeWindowSeconds,
88
- );
89
-
90
- return {
91
- success: true,
92
- remainingRequests: this.options.maxRequests - 1,
93
- resetTime: Math.floor(now / 1000) + this.options.timeWindowSeconds,
94
- };
95
- }
96
-
97
- // Calculate window boundaries
98
- const currentWindowStart =
99
- Math.floor(now / (options.granularity * 1000)) *
100
- (options.granularity * 1000);
101
- const previousWindowStart =
102
- currentWindowStart - this.options.timeWindowSeconds * 1000;
103
-
104
- // Split timestamps into current and previous windows
105
- const currentWindowRequests = stored.timestamps.filter(
106
- (ts) => ts >= currentWindowStart,
107
- ).length;
108
- const previousWindowRequests = stored.timestamps.filter(
109
- (ts) => ts >= previousWindowStart && ts < currentWindowStart,
110
- ).length;
111
-
112
- // Calculate weighted request count
113
- const weightedCount =
114
- currentWindowRequests * options.weights.current +
115
- previousWindowRequests * options.weights.previous;
116
-
117
- if (weightedCount >= this.options.maxRequests) {
118
- return {
119
- success: false,
120
- remainingRequests: 0,
121
- resetTime: Math.floor(
122
- currentWindowStart / 1000 + this.options.timeWindowSeconds,
123
- ),
124
- };
125
- }
126
-
127
- // Remove timestamps outside both windows and add new timestamp
128
- stored.timestamps = stored.timestamps.filter(
129
- (ts) => ts >= previousWindowStart,
130
- );
131
- stored.timestamps.push(now);
132
- stored.windowStart = currentWindowStart;
133
- await this.storage.set(key, stored, this.options.timeWindowSeconds);
134
-
135
- return {
136
- success: true,
137
- remainingRequests: Math.floor(
138
- this.options.maxRequests - weightedCount - 1,
139
- ),
140
- resetTime: Math.floor(
141
- currentWindowStart / 1000 + this.options.timeWindowSeconds,
142
- ),
143
- };
144
- }
145
- }
146
-
147
- export default SlidingWindowRateLimiter;
1
+ import RateLimiter from '../base.js';
2
+ import TejError from '../../server/error.js';
3
+
4
+ /**
5
+ * Sliding Window Rate Limiter Implementation
6
+ *
7
+ * @extends RateLimiter
8
+ * @description
9
+ * The sliding window algorithm provides precise rate limiting by considering both the current
10
+ * and previous time windows with configurable weights. This prevents traffic spikes that can
11
+ * occur at window boundaries with fixed window rate limiting.
12
+ *
13
+ * Key features:
14
+ * - Smoother rate limiting than fixed windows
15
+ * - Prevents boundary spike issues
16
+ * - Configurable time granularity
17
+ * - Weighted window transitions
18
+ *
19
+ * For example, with 60-second windows and 30 seconds into the current window:
20
+ * - Current window gets full weight (e.g. 1.0)
21
+ * - Previous window gets partial weight (e.g. 0.5)
22
+ * Total requests = (current_requests * 1.0) + (previous_requests * 0.5)
23
+ *
24
+ * @example
25
+ * // Create a sliding window rate limiter with weighted windows
26
+ * const limiter = new SlidingWindowRateLimiter({
27
+ * maxRequests: 100, // Allow 100 requests per minute
28
+ * timeWindowSeconds: 60,
29
+ * slidingWindow: {
30
+ * granularity: 1, // 1-second precision
31
+ * weights: {
32
+ * current: 1, // Full weight for current window
33
+ * previous: 0.5 // Half weight for previous window
34
+ * }
35
+ * }
36
+ * });
37
+ *
38
+ * // Use in an API endpoint
39
+ * async function handleRequest(ip) {
40
+ * const result = await limiter.consume(ip);
41
+ * if (!result.success) {
42
+ * throw new TejError(429, 'Rate limit exceeded');
43
+ * }
44
+ * // Process request...
45
+ * }
46
+ */
47
+ class SlidingWindowRateLimiter extends RateLimiter {
48
+ constructor(options) {
49
+ if (!options.slidingWindowConfig) {
50
+ options.slidingWindowConfig = {}; // Ensure defaults are set in base class
51
+ }
52
+ super(options);
53
+
54
+ if (!this.slidingWindowOptions) {
55
+ throw new TejError(
56
+ 400,
57
+ 'SlidingWindowRateLimiter requires slidingWindowConfig options',
58
+ );
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Check if a request should be allowed based on weighted window counts
64
+ *
65
+ * @param {string} identifier - Unique identifier for rate limiting (e.g., IP address, user ID)
66
+ * @returns {Promise<Object>} Rate limit check result
67
+ * @returns {boolean} result.success - Whether the request is allowed
68
+ * @returns {number} result.remainingRequests - Number of requests remaining in the current window
69
+ * @returns {number} result.resetTime - Unix timestamp when the current window ends
70
+ */
71
+ async consume(identifier) {
72
+ const key = this.getKey(identifier);
73
+ const now = Date.now();
74
+ const options = this.getAlgorithmOptions('sliding-window');
75
+
76
+ const stored = await this.storage.get(key);
77
+ if (!stored) {
78
+ await this.storage.set(
79
+ key,
80
+ {
81
+ counter: 1,
82
+ timestamps: [now],
83
+ windowStart:
84
+ Math.floor(now / (options.granularity * 1000)) *
85
+ (options.granularity * 1000),
86
+ },
87
+ this.options.timeWindowSeconds,
88
+ );
89
+
90
+ return {
91
+ success: true,
92
+ remainingRequests: this.options.maxRequests - 1,
93
+ resetTime: Math.floor(now / 1000) + this.options.timeWindowSeconds,
94
+ };
95
+ }
96
+
97
+ // Calculate window boundaries
98
+ const currentWindowStart =
99
+ Math.floor(now / (options.granularity * 1000)) *
100
+ (options.granularity * 1000);
101
+ const previousWindowStart =
102
+ currentWindowStart - this.options.timeWindowSeconds * 1000;
103
+
104
+ // Split timestamps into current and previous windows
105
+ const currentWindowRequests = stored.timestamps.filter(
106
+ (ts) => ts >= currentWindowStart,
107
+ ).length;
108
+ const previousWindowRequests = stored.timestamps.filter(
109
+ (ts) => ts >= previousWindowStart && ts < currentWindowStart,
110
+ ).length;
111
+
112
+ // Calculate weighted request count
113
+ const weightedCount =
114
+ currentWindowRequests * options.weights.current +
115
+ previousWindowRequests * options.weights.previous;
116
+
117
+ if (weightedCount >= this.options.maxRequests) {
118
+ return {
119
+ success: false,
120
+ remainingRequests: 0,
121
+ resetTime: Math.floor(
122
+ currentWindowStart / 1000 + this.options.timeWindowSeconds,
123
+ ),
124
+ };
125
+ }
126
+
127
+ // Remove timestamps outside both windows and add new timestamp
128
+ stored.timestamps = stored.timestamps.filter(
129
+ (ts) => ts >= previousWindowStart,
130
+ );
131
+ stored.timestamps.push(now);
132
+ stored.windowStart = currentWindowStart;
133
+ await this.storage.set(key, stored, this.options.timeWindowSeconds);
134
+
135
+ return {
136
+ success: true,
137
+ remainingRequests: Math.floor(
138
+ this.options.maxRequests - weightedCount - 1,
139
+ ),
140
+ resetTime: Math.floor(
141
+ currentWindowStart / 1000 + this.options.timeWindowSeconds,
142
+ ),
143
+ };
144
+ }
145
+ }
146
+
147
+ export default SlidingWindowRateLimiter;
@@ -1,115 +1,115 @@
1
- import RateLimiter from '../base.js';
2
- import TejError from '../../server/error.js';
3
-
4
- /**
5
- * Token Bucket Rate Limiter Implementation
6
- *
7
- * @extends RateLimiter
8
- * @description
9
- * The token bucket algorithm provides smooth rate limiting with burst handling capabilities.
10
- * It maintains a bucket of tokens that refills at a constant rate, allowing for temporary
11
- * bursts of traffic while maintaining a long-term average rate.
12
- *
13
- * Key features:
14
- * - Smooth rate limiting with continuous token regeneration
15
- * - Burst handling with configurable burst size
16
- * - Predictable long-term average rate
17
- * - Fair distribution of requests over time
18
- *
19
- * @example
20
- * // Create a rate limiter that allows bursts
21
- * const limiter = new TokenBucketRateLimiter({
22
- * maxRequests: 60, // Base rate: 60 requests per minute
23
- * timeWindowSeconds: 60,
24
- * tokenBucket: {
25
- * refillRate: 1, // Refill 1 token per second
26
- * burstSize: 90 // Allow bursts up to 90 requests
27
- * }
28
- * });
29
- *
30
- * // Use the rate limiter in an endpoint
31
- * async function handleRequest(ip) {
32
- * const result = await limiter.consume(ip);
33
- * if (!result.success) {
34
- * throw new TejError(429, 'Rate limit exceeded');
35
- * }
36
- * // Handle request...
37
- * }
38
- */
39
- class TokenBucketRateLimiter extends RateLimiter {
40
- constructor(options) {
41
- if (!options.tokenBucketConfig) {
42
- options.tokenBucketConfig = {}; // Ensure defaults are set in base class
43
- }
44
- super(options);
45
-
46
- if (!this.tokenBucketOptions) {
47
- throw new TejError(
48
- 400,
49
- 'TokenBucketRateLimiter requires tokenBucketConfig options',
50
- );
51
- }
52
- }
53
-
54
- /**
55
- * Check if a request should be allowed and update token count
56
- *
57
- * @param {string} identifier - Unique identifier for rate limiting (e.g., IP address, user ID)
58
- * @returns {Promise<Object>} Rate limit check result
59
- * @returns {boolean} result.success - Whether the request is allowed
60
- * @returns {number} result.remainingRequests - Number of tokens remaining in the bucket
61
- * @returns {number} result.resetTime - Unix timestamp when the next token will be added
62
- */
63
- async consume(identifier) {
64
- const key = this.getKey(identifier);
65
- const now = Date.now();
66
- const options = this.getAlgorithmOptions('tokenBucketConfig');
67
-
68
- const stored = await this.storage.get(key);
69
- if (!stored) {
70
- await this.storage.set(
71
- key,
72
- {
73
- tokens: options.burstSize - 1,
74
- lastRefill: now,
75
- },
76
- this.options.timeWindowSeconds,
77
- );
78
-
79
- return {
80
- success: true,
81
- remainingRequests: options.burstSize - 1,
82
- resetTime: Math.floor(now / 1000) + this.options.timeWindowSeconds,
83
- };
84
- }
85
-
86
- // Calculate token refill based on configured refill rate
87
- const timePassed = now - stored.lastRefill;
88
- const refillTokens = Math.floor((timePassed * options.refillRate) / 1000);
89
-
90
- stored.tokens = Math.min(options.burstSize, stored.tokens + refillTokens);
91
- stored.lastRefill = now;
92
-
93
- if (stored.tokens < 1) {
94
- const timeToNextToken = Math.ceil(
95
- ((1 - stored.tokens) / options.refillRate) * 1000,
96
- );
97
- return {
98
- success: false,
99
- remainingRequests: 0,
100
- resetTime: Math.floor((now + timeToNextToken) / 1000),
101
- };
102
- }
103
-
104
- stored.tokens--;
105
- await this.storage.set(key, stored, this.options.timeWindowSeconds);
106
-
107
- return {
108
- success: true,
109
- remainingRequests: Math.floor(stored.tokens),
110
- resetTime: Math.floor(now / 1000) + this.options.timeWindowSeconds,
111
- };
112
- }
113
- }
114
-
115
- export default TokenBucketRateLimiter;
1
+ import RateLimiter from '../base.js';
2
+ import TejError from '../../server/error.js';
3
+
4
+ /**
5
+ * Token Bucket Rate Limiter Implementation
6
+ *
7
+ * @extends RateLimiter
8
+ * @description
9
+ * The token bucket algorithm provides smooth rate limiting with burst handling capabilities.
10
+ * It maintains a bucket of tokens that refills at a constant rate, allowing for temporary
11
+ * bursts of traffic while maintaining a long-term average rate.
12
+ *
13
+ * Key features:
14
+ * - Smooth rate limiting with continuous token regeneration
15
+ * - Burst handling with configurable burst size
16
+ * - Predictable long-term average rate
17
+ * - Fair distribution of requests over time
18
+ *
19
+ * @example
20
+ * // Create a rate limiter that allows bursts
21
+ * const limiter = new TokenBucketRateLimiter({
22
+ * maxRequests: 60, // Base rate: 60 requests per minute
23
+ * timeWindowSeconds: 60,
24
+ * tokenBucket: {
25
+ * refillRate: 1, // Refill 1 token per second
26
+ * burstSize: 90 // Allow bursts up to 90 requests
27
+ * }
28
+ * });
29
+ *
30
+ * // Use the rate limiter in an endpoint
31
+ * async function handleRequest(ip) {
32
+ * const result = await limiter.consume(ip);
33
+ * if (!result.success) {
34
+ * throw new TejError(429, 'Rate limit exceeded');
35
+ * }
36
+ * // Handle request...
37
+ * }
38
+ */
39
+ class TokenBucketRateLimiter extends RateLimiter {
40
+ constructor(options) {
41
+ if (!options.tokenBucketConfig) {
42
+ options.tokenBucketConfig = {}; // Ensure defaults are set in base class
43
+ }
44
+ super(options);
45
+
46
+ if (!this.tokenBucketOptions) {
47
+ throw new TejError(
48
+ 400,
49
+ 'TokenBucketRateLimiter requires tokenBucketConfig options',
50
+ );
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Check if a request should be allowed and update token count
56
+ *
57
+ * @param {string} identifier - Unique identifier for rate limiting (e.g., IP address, user ID)
58
+ * @returns {Promise<Object>} Rate limit check result
59
+ * @returns {boolean} result.success - Whether the request is allowed
60
+ * @returns {number} result.remainingRequests - Number of tokens remaining in the bucket
61
+ * @returns {number} result.resetTime - Unix timestamp when the next token will be added
62
+ */
63
+ async consume(identifier) {
64
+ const key = this.getKey(identifier);
65
+ const now = Date.now();
66
+ const options = this.getAlgorithmOptions('tokenBucketConfig');
67
+
68
+ const stored = await this.storage.get(key);
69
+ if (!stored) {
70
+ await this.storage.set(
71
+ key,
72
+ {
73
+ tokens: options.burstSize - 1,
74
+ lastRefill: now,
75
+ },
76
+ this.options.timeWindowSeconds,
77
+ );
78
+
79
+ return {
80
+ success: true,
81
+ remainingRequests: options.burstSize - 1,
82
+ resetTime: Math.floor(now / 1000) + this.options.timeWindowSeconds,
83
+ };
84
+ }
85
+
86
+ // Calculate token refill based on configured refill rate
87
+ const timePassed = now - stored.lastRefill;
88
+ const refillTokens = Math.floor((timePassed * options.refillRate) / 1000);
89
+
90
+ stored.tokens = Math.min(options.burstSize, stored.tokens + refillTokens);
91
+ stored.lastRefill = now;
92
+
93
+ if (stored.tokens < 1) {
94
+ const timeToNextToken = Math.ceil(
95
+ ((1 - stored.tokens) / options.refillRate) * 1000,
96
+ );
97
+ return {
98
+ success: false,
99
+ remainingRequests: 0,
100
+ resetTime: Math.floor((now + timeToNextToken) / 1000),
101
+ };
102
+ }
103
+
104
+ stored.tokens--;
105
+ await this.storage.set(key, stored, this.options.timeWindowSeconds);
106
+
107
+ return {
108
+ success: true,
109
+ remainingRequests: Math.floor(stored.tokens),
110
+ resetTime: Math.floor(now / 1000) + this.options.timeWindowSeconds,
111
+ };
112
+ }
113
+ }
114
+
115
+ export default TokenBucketRateLimiter;