te.js 2.1.0 → 2.1.2
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 -196
- 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 -7
- package/auto-docs/docs-llm/prompts.js +222 -222
- package/auto-docs/docs-llm/provider.js +132 -132
- 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/cors/index.js +71 -0
- 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 -490
- package/docs/auto-docs.md +216 -216
- package/docs/cli.md +152 -152
- package/docs/configuration.md +275 -275
- package/docs/database.md +390 -390
- package/docs/error-handling.md +438 -438
- package/docs/file-uploads.md +333 -333
- package/docs/getting-started.md +214 -214
- package/docs/middleware.md +355 -355
- package/docs/rate-limiting.md +393 -393
- package/docs/routing.md +302 -302
- package/lib/llm/client.js +73 -0
- package/lib/llm/index.js +7 -0
- package/lib/llm/parse.js +89 -0
- package/package.json +64 -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 -415
- package/server/endpoint.js +97 -74
- package/server/error.js +9 -9
- package/server/errors/code-context.js +125 -125
- package/server/errors/llm-error-service.js +140 -140
- package/server/files/helper.js +33 -33
- package/server/files/uploader.js +143 -143
- package/server/handler.js +158 -119
- 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 -402
- package/utils/auto-register.js +17 -17
- package/utils/configuration.js +64 -64
- package/utils/errors-llm-config.js +84 -84
- package/utils/request-logger.js +43 -43
- package/utils/status-codes.js +82 -82
- package/utils/tejas-entrypoint-html.js +18 -18
|
@@ -1,104 +1,104 @@
|
|
|
1
|
-
import TejError from '../../server/error.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Abstract base class for rate limiter storage backends
|
|
5
|
-
*
|
|
6
|
-
* @abstract
|
|
7
|
-
* @description
|
|
8
|
-
* Defines the interface that all storage implementations must follow.
|
|
9
|
-
* Storage backends are responsible for persisting rate limit data and handling
|
|
10
|
-
* data expiration. Two implementations are provided out of the box:
|
|
11
|
-
* - MemoryStorage: For single-instance applications and testing
|
|
12
|
-
* - RedisStorage: For distributed applications
|
|
13
|
-
*
|
|
14
|
-
* Custom storage implementations can be created by extending this class
|
|
15
|
-
* and implementing all required methods.
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* // Custom storage implementation
|
|
19
|
-
* class MyCustomStorage extends RateLimitStorage {
|
|
20
|
-
* async get(key) {
|
|
21
|
-
* // Implementation
|
|
22
|
-
* }
|
|
23
|
-
* async set(key, value, ttl) {
|
|
24
|
-
* // Implementation
|
|
25
|
-
* }
|
|
26
|
-
* async increment(key) {
|
|
27
|
-
* // Implementation
|
|
28
|
-
* }
|
|
29
|
-
* async delete(key) {
|
|
30
|
-
* // Implementation
|
|
31
|
-
* }
|
|
32
|
-
* }
|
|
33
|
-
*/
|
|
34
|
-
class RateLimitStorage {
|
|
35
|
-
/**
|
|
36
|
-
* Retrieve rate limit data for a given key
|
|
37
|
-
*
|
|
38
|
-
* @abstract
|
|
39
|
-
* @param {string} key - The storage key to retrieve data for
|
|
40
|
-
* @returns {Promise<Object|null>} The stored data, or null if not found
|
|
41
|
-
* @throws {Error} If not implemented by child class
|
|
42
|
-
*
|
|
43
|
-
* @example
|
|
44
|
-
* const data = await storage.get('rl:127.0.0.1');
|
|
45
|
-
* if (data) {
|
|
46
|
-
* console.log('Found rate limit data:', data);
|
|
47
|
-
* }
|
|
48
|
-
*/
|
|
49
|
-
async get(key) {
|
|
50
|
-
throw new TejError(500, 'Not implemented');
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Store rate limit data with optional expiration
|
|
55
|
-
*
|
|
56
|
-
* @abstract
|
|
57
|
-
* @param {string} key - The storage key to store data under
|
|
58
|
-
* @param {Object} value - The data to store
|
|
59
|
-
* @param {number} ttl - Time-to-live in seconds
|
|
60
|
-
* @returns {Promise<void>}
|
|
61
|
-
* @throws {Error} If not implemented by child class
|
|
62
|
-
*
|
|
63
|
-
* @example
|
|
64
|
-
* await storage.set('rl:127.0.0.1', { counter: 5 }, 60);
|
|
65
|
-
*/
|
|
66
|
-
async set(key, value, ttl) {
|
|
67
|
-
throw new TejError(500, 'Not implemented');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Increment a numeric value in storage
|
|
72
|
-
*
|
|
73
|
-
* @abstract
|
|
74
|
-
* @param {string} key - The storage key to increment
|
|
75
|
-
* @returns {Promise<number|null>} The new value after increment, or null if key not found
|
|
76
|
-
* @throws {Error} If not implemented by child class
|
|
77
|
-
*
|
|
78
|
-
* @example
|
|
79
|
-
* const newValue = await storage.increment('rl:127.0.0.1');
|
|
80
|
-
* if (newValue !== null) {
|
|
81
|
-
* console.log('New counter value:', newValue);
|
|
82
|
-
* }
|
|
83
|
-
*/
|
|
84
|
-
async increment(key) {
|
|
85
|
-
throw new TejError(500, 'Not implemented');
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Delete data for a given key
|
|
90
|
-
*
|
|
91
|
-
* @abstract
|
|
92
|
-
* @param {string} key - The storage key to delete
|
|
93
|
-
* @returns {Promise<void>}
|
|
94
|
-
* @throws {Error} If not implemented by child class
|
|
95
|
-
*
|
|
96
|
-
* @example
|
|
97
|
-
* await storage.delete('rl:127.0.0.1');
|
|
98
|
-
*/
|
|
99
|
-
async delete(key) {
|
|
100
|
-
throw new TejError(500, 'Not implemented');
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export default RateLimitStorage;
|
|
1
|
+
import TejError from '../../server/error.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Abstract base class for rate limiter storage backends
|
|
5
|
+
*
|
|
6
|
+
* @abstract
|
|
7
|
+
* @description
|
|
8
|
+
* Defines the interface that all storage implementations must follow.
|
|
9
|
+
* Storage backends are responsible for persisting rate limit data and handling
|
|
10
|
+
* data expiration. Two implementations are provided out of the box:
|
|
11
|
+
* - MemoryStorage: For single-instance applications and testing
|
|
12
|
+
* - RedisStorage: For distributed applications
|
|
13
|
+
*
|
|
14
|
+
* Custom storage implementations can be created by extending this class
|
|
15
|
+
* and implementing all required methods.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // Custom storage implementation
|
|
19
|
+
* class MyCustomStorage extends RateLimitStorage {
|
|
20
|
+
* async get(key) {
|
|
21
|
+
* // Implementation
|
|
22
|
+
* }
|
|
23
|
+
* async set(key, value, ttl) {
|
|
24
|
+
* // Implementation
|
|
25
|
+
* }
|
|
26
|
+
* async increment(key) {
|
|
27
|
+
* // Implementation
|
|
28
|
+
* }
|
|
29
|
+
* async delete(key) {
|
|
30
|
+
* // Implementation
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
*/
|
|
34
|
+
class RateLimitStorage {
|
|
35
|
+
/**
|
|
36
|
+
* Retrieve rate limit data for a given key
|
|
37
|
+
*
|
|
38
|
+
* @abstract
|
|
39
|
+
* @param {string} key - The storage key to retrieve data for
|
|
40
|
+
* @returns {Promise<Object|null>} The stored data, or null if not found
|
|
41
|
+
* @throws {Error} If not implemented by child class
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* const data = await storage.get('rl:127.0.0.1');
|
|
45
|
+
* if (data) {
|
|
46
|
+
* console.log('Found rate limit data:', data);
|
|
47
|
+
* }
|
|
48
|
+
*/
|
|
49
|
+
async get(key) {
|
|
50
|
+
throw new TejError(500, 'Not implemented');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Store rate limit data with optional expiration
|
|
55
|
+
*
|
|
56
|
+
* @abstract
|
|
57
|
+
* @param {string} key - The storage key to store data under
|
|
58
|
+
* @param {Object} value - The data to store
|
|
59
|
+
* @param {number} ttl - Time-to-live in seconds
|
|
60
|
+
* @returns {Promise<void>}
|
|
61
|
+
* @throws {Error} If not implemented by child class
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* await storage.set('rl:127.0.0.1', { counter: 5 }, 60);
|
|
65
|
+
*/
|
|
66
|
+
async set(key, value, ttl) {
|
|
67
|
+
throw new TejError(500, 'Not implemented');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Increment a numeric value in storage
|
|
72
|
+
*
|
|
73
|
+
* @abstract
|
|
74
|
+
* @param {string} key - The storage key to increment
|
|
75
|
+
* @returns {Promise<number|null>} The new value after increment, or null if key not found
|
|
76
|
+
* @throws {Error} If not implemented by child class
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* const newValue = await storage.increment('rl:127.0.0.1');
|
|
80
|
+
* if (newValue !== null) {
|
|
81
|
+
* console.log('New counter value:', newValue);
|
|
82
|
+
* }
|
|
83
|
+
*/
|
|
84
|
+
async increment(key) {
|
|
85
|
+
throw new TejError(500, 'Not implemented');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Delete data for a given key
|
|
90
|
+
*
|
|
91
|
+
* @abstract
|
|
92
|
+
* @param {string} key - The storage key to delete
|
|
93
|
+
* @returns {Promise<void>}
|
|
94
|
+
* @throws {Error} If not implemented by child class
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* await storage.delete('rl:127.0.0.1');
|
|
98
|
+
*/
|
|
99
|
+
async delete(key) {
|
|
100
|
+
throw new TejError(500, 'Not implemented');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export default RateLimitStorage;
|
|
@@ -1,102 +1,102 @@
|
|
|
1
|
-
import RateLimitStorage from './base.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* In-memory storage implementation for rate limiting
|
|
5
|
-
*
|
|
6
|
-
* @extends RateLimitStorage
|
|
7
|
-
* @description
|
|
8
|
-
* This storage backend uses a JavaScript Map to store rate limit data in memory.
|
|
9
|
-
* It's suitable for single-instance applications or testing environments, but not
|
|
10
|
-
* recommended for production use in distributed systems as data is not shared
|
|
11
|
-
* between instances.
|
|
12
|
-
*
|
|
13
|
-
* Key features:
|
|
14
|
-
* - Fast access (all data in memory)
|
|
15
|
-
* - Automatic cleanup of expired entries
|
|
16
|
-
* - No external dependencies
|
|
17
|
-
* - Data is lost on process restart
|
|
18
|
-
* - Not suitable for distributed systems
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* import { TokenBucketRateLimiter, MemoryStorage } from 'te.js/rate-limit';
|
|
22
|
-
*
|
|
23
|
-
* // Memory storage is used by default if no redis config is provided
|
|
24
|
-
* const limiter = new TokenBucketRateLimiter({
|
|
25
|
-
* maxRequests: 60,
|
|
26
|
-
* timeWindowSeconds: 60,
|
|
27
|
-
* tokenBucketConfig: {
|
|
28
|
-
* refillRate: 1,
|
|
29
|
-
* burstSize: 60
|
|
30
|
-
* }
|
|
31
|
-
* });
|
|
32
|
-
*
|
|
33
|
-
* // Or create storage instance explicitly
|
|
34
|
-
* const storage = new MemoryStorage();
|
|
35
|
-
* await storage.set('key', { counter: 5 }, 60); // Store for 60 seconds
|
|
36
|
-
*/
|
|
37
|
-
class MemoryStorage extends RateLimitStorage {
|
|
38
|
-
/**
|
|
39
|
-
* Initialize a new memory storage instance
|
|
40
|
-
*/
|
|
41
|
-
constructor() {
|
|
42
|
-
super();
|
|
43
|
-
this.store = new Map();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Get stored data for a key, handling expiration
|
|
48
|
-
*
|
|
49
|
-
* @param {string} key - The storage key to retrieve data for
|
|
50
|
-
* @returns {Promise<Object|null>} The stored data, or null if not found or expired
|
|
51
|
-
*/
|
|
52
|
-
async get(key) {
|
|
53
|
-
const item = this.store.get(key);
|
|
54
|
-
if (!item) return null;
|
|
55
|
-
if (item.expireAt < Date.now()) {
|
|
56
|
-
this.store.delete(key);
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
return item.value;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Store data with expiration time
|
|
64
|
-
*
|
|
65
|
-
* @param {string} key - The storage key
|
|
66
|
-
* @param {Object} value - The data to store
|
|
67
|
-
* @param {number} ttl - Time-to-live in seconds
|
|
68
|
-
* @returns {Promise<void>}
|
|
69
|
-
*/
|
|
70
|
-
async set(key, value, ttl) {
|
|
71
|
-
this.store.set(key, {
|
|
72
|
-
value,
|
|
73
|
-
expireAt: Date.now() + ttl * 1000
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Increment a numeric value in storage
|
|
79
|
-
*
|
|
80
|
-
* @param {string} key - The storage key to increment
|
|
81
|
-
* @returns {Promise<number|null>} New value after increment, or null if key not found/expired
|
|
82
|
-
*/
|
|
83
|
-
async increment(key) {
|
|
84
|
-
const item = await this.get(key);
|
|
85
|
-
if (!item) return null;
|
|
86
|
-
item.counter = (item.counter || 0) + 1;
|
|
87
|
-
await this.set(key, item, (item.expireAt - Date.now()) / 1000);
|
|
88
|
-
return item.counter;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Delete data for a key
|
|
93
|
-
*
|
|
94
|
-
* @param {string} key - The storage key to delete
|
|
95
|
-
* @returns {Promise<void>}
|
|
96
|
-
*/
|
|
97
|
-
async delete(key) {
|
|
98
|
-
this.store.delete(key);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
1
|
+
import RateLimitStorage from './base.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* In-memory storage implementation for rate limiting
|
|
5
|
+
*
|
|
6
|
+
* @extends RateLimitStorage
|
|
7
|
+
* @description
|
|
8
|
+
* This storage backend uses a JavaScript Map to store rate limit data in memory.
|
|
9
|
+
* It's suitable for single-instance applications or testing environments, but not
|
|
10
|
+
* recommended for production use in distributed systems as data is not shared
|
|
11
|
+
* between instances.
|
|
12
|
+
*
|
|
13
|
+
* Key features:
|
|
14
|
+
* - Fast access (all data in memory)
|
|
15
|
+
* - Automatic cleanup of expired entries
|
|
16
|
+
* - No external dependencies
|
|
17
|
+
* - Data is lost on process restart
|
|
18
|
+
* - Not suitable for distributed systems
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* import { TokenBucketRateLimiter, MemoryStorage } from 'te.js/rate-limit';
|
|
22
|
+
*
|
|
23
|
+
* // Memory storage is used by default if no redis config is provided
|
|
24
|
+
* const limiter = new TokenBucketRateLimiter({
|
|
25
|
+
* maxRequests: 60,
|
|
26
|
+
* timeWindowSeconds: 60,
|
|
27
|
+
* tokenBucketConfig: {
|
|
28
|
+
* refillRate: 1,
|
|
29
|
+
* burstSize: 60
|
|
30
|
+
* }
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* // Or create storage instance explicitly
|
|
34
|
+
* const storage = new MemoryStorage();
|
|
35
|
+
* await storage.set('key', { counter: 5 }, 60); // Store for 60 seconds
|
|
36
|
+
*/
|
|
37
|
+
class MemoryStorage extends RateLimitStorage {
|
|
38
|
+
/**
|
|
39
|
+
* Initialize a new memory storage instance
|
|
40
|
+
*/
|
|
41
|
+
constructor() {
|
|
42
|
+
super();
|
|
43
|
+
this.store = new Map();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get stored data for a key, handling expiration
|
|
48
|
+
*
|
|
49
|
+
* @param {string} key - The storage key to retrieve data for
|
|
50
|
+
* @returns {Promise<Object|null>} The stored data, or null if not found or expired
|
|
51
|
+
*/
|
|
52
|
+
async get(key) {
|
|
53
|
+
const item = this.store.get(key);
|
|
54
|
+
if (!item) return null;
|
|
55
|
+
if (item.expireAt < Date.now()) {
|
|
56
|
+
this.store.delete(key);
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
return item.value;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Store data with expiration time
|
|
64
|
+
*
|
|
65
|
+
* @param {string} key - The storage key
|
|
66
|
+
* @param {Object} value - The data to store
|
|
67
|
+
* @param {number} ttl - Time-to-live in seconds
|
|
68
|
+
* @returns {Promise<void>}
|
|
69
|
+
*/
|
|
70
|
+
async set(key, value, ttl) {
|
|
71
|
+
this.store.set(key, {
|
|
72
|
+
value,
|
|
73
|
+
expireAt: Date.now() + ttl * 1000
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Increment a numeric value in storage
|
|
79
|
+
*
|
|
80
|
+
* @param {string} key - The storage key to increment
|
|
81
|
+
* @returns {Promise<number|null>} New value after increment, or null if key not found/expired
|
|
82
|
+
*/
|
|
83
|
+
async increment(key) {
|
|
84
|
+
const item = await this.get(key);
|
|
85
|
+
if (!item) return null;
|
|
86
|
+
item.counter = (item.counter || 0) + 1;
|
|
87
|
+
await this.set(key, item, (item.expireAt - Date.now()) / 1000);
|
|
88
|
+
return item.counter;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Delete data for a key
|
|
93
|
+
*
|
|
94
|
+
* @param {string} key - The storage key to delete
|
|
95
|
+
* @returns {Promise<void>}
|
|
96
|
+
*/
|
|
97
|
+
async delete(key) {
|
|
98
|
+
this.store.delete(key);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
102
|
export default MemoryStorage;
|
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
import RateLimitStorage from './base.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Redis storage implementation for rate limiting
|
|
5
|
-
*
|
|
6
|
-
* @extends RateLimitStorage
|
|
7
|
-
* @description
|
|
8
|
-
* This storage backend uses Redis for distributed rate limiting across multiple application instances.
|
|
9
|
-
* It's the recommended storage backend for production use in distributed systems as it provides
|
|
10
|
-
* reliable rate limiting across all application instances.
|
|
11
|
-
*
|
|
12
|
-
* Key features:
|
|
13
|
-
* - Distributed rate limiting (works across multiple app instances)
|
|
14
|
-
* - Atomic operations for race condition prevention
|
|
15
|
-
* - Automatic key expiration using Redis TTL
|
|
16
|
-
* - Persistence options available through Redis configuration
|
|
17
|
-
* - Clustering support for high availability
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* import { TokenBucketRateLimiter } from 'te.js/rate-limit';
|
|
21
|
-
*
|
|
22
|
-
* // Use Redis storage for distributed rate limiting
|
|
23
|
-
* const limiter = new TokenBucketRateLimiter({
|
|
24
|
-
* maxRequests: 100,
|
|
25
|
-
* timeWindowSeconds: 60,
|
|
26
|
-
* store: 'redis', // Use Redis storage
|
|
27
|
-
* tokenBucketConfig: {
|
|
28
|
-
* refillRate: 2,
|
|
29
|
-
* burstSize: 100
|
|
30
|
-
* }
|
|
31
|
-
* });
|
|
32
|
-
*/
|
|
33
|
-
class RedisStorage extends RateLimitStorage {
|
|
34
|
-
/**
|
|
35
|
-
* Initialize Redis storage with client
|
|
36
|
-
*
|
|
37
|
-
* @param {RedisClient} client - Connected Redis client instance
|
|
38
|
-
*/
|
|
39
|
-
constructor(client) {
|
|
40
|
-
super();
|
|
41
|
-
this.client = client;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Get stored data for a key
|
|
46
|
-
*
|
|
47
|
-
* @param {string} key - The storage key to retrieve
|
|
48
|
-
* @returns {Promise<Object|null>} Stored value if found, null otherwise
|
|
49
|
-
*/
|
|
50
|
-
async get(key) {
|
|
51
|
-
const value = await this.client.get(key);
|
|
52
|
-
return value ? JSON.parse(value) : null;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Store data with expiration time
|
|
57
|
-
*
|
|
58
|
-
* @param {string} key - The storage key
|
|
59
|
-
* @param {Object} value - The data to store
|
|
60
|
-
* @param {number} ttl - Time-to-live in seconds
|
|
61
|
-
* @returns {Promise<void>}
|
|
62
|
-
*/
|
|
63
|
-
async set(key, value, ttl) {
|
|
64
|
-
await this.client.set(key, JSON.stringify(value), { EX: ttl });
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Increment a counter value atomically
|
|
69
|
-
*
|
|
70
|
-
* @param {string} key - The storage key to increment
|
|
71
|
-
* @returns {Promise<number>} New value after increment
|
|
72
|
-
*/
|
|
73
|
-
async increment(key) {
|
|
74
|
-
return await this.client.incr(key);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Delete data for a key
|
|
79
|
-
*
|
|
80
|
-
* @param {string} key - The storage key to delete
|
|
81
|
-
* @returns {Promise<void>}
|
|
82
|
-
*/
|
|
83
|
-
async delete(key) {
|
|
84
|
-
await this.client.del(key);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export default RedisStorage;
|
|
1
|
+
import RateLimitStorage from './base.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Redis storage implementation for rate limiting
|
|
5
|
+
*
|
|
6
|
+
* @extends RateLimitStorage
|
|
7
|
+
* @description
|
|
8
|
+
* This storage backend uses Redis for distributed rate limiting across multiple application instances.
|
|
9
|
+
* It's the recommended storage backend for production use in distributed systems as it provides
|
|
10
|
+
* reliable rate limiting across all application instances.
|
|
11
|
+
*
|
|
12
|
+
* Key features:
|
|
13
|
+
* - Distributed rate limiting (works across multiple app instances)
|
|
14
|
+
* - Atomic operations for race condition prevention
|
|
15
|
+
* - Automatic key expiration using Redis TTL
|
|
16
|
+
* - Persistence options available through Redis configuration
|
|
17
|
+
* - Clustering support for high availability
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* import { TokenBucketRateLimiter } from 'te.js/rate-limit';
|
|
21
|
+
*
|
|
22
|
+
* // Use Redis storage for distributed rate limiting
|
|
23
|
+
* const limiter = new TokenBucketRateLimiter({
|
|
24
|
+
* maxRequests: 100,
|
|
25
|
+
* timeWindowSeconds: 60,
|
|
26
|
+
* store: 'redis', // Use Redis storage
|
|
27
|
+
* tokenBucketConfig: {
|
|
28
|
+
* refillRate: 2,
|
|
29
|
+
* burstSize: 100
|
|
30
|
+
* }
|
|
31
|
+
* });
|
|
32
|
+
*/
|
|
33
|
+
class RedisStorage extends RateLimitStorage {
|
|
34
|
+
/**
|
|
35
|
+
* Initialize Redis storage with client
|
|
36
|
+
*
|
|
37
|
+
* @param {RedisClient} client - Connected Redis client instance
|
|
38
|
+
*/
|
|
39
|
+
constructor(client) {
|
|
40
|
+
super();
|
|
41
|
+
this.client = client;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get stored data for a key
|
|
46
|
+
*
|
|
47
|
+
* @param {string} key - The storage key to retrieve
|
|
48
|
+
* @returns {Promise<Object|null>} Stored value if found, null otherwise
|
|
49
|
+
*/
|
|
50
|
+
async get(key) {
|
|
51
|
+
const value = await this.client.get(key);
|
|
52
|
+
return value ? JSON.parse(value) : null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Store data with expiration time
|
|
57
|
+
*
|
|
58
|
+
* @param {string} key - The storage key
|
|
59
|
+
* @param {Object} value - The data to store
|
|
60
|
+
* @param {number} ttl - Time-to-live in seconds
|
|
61
|
+
* @returns {Promise<void>}
|
|
62
|
+
*/
|
|
63
|
+
async set(key, value, ttl) {
|
|
64
|
+
await this.client.set(key, JSON.stringify(value), { EX: ttl });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Increment a counter value atomically
|
|
69
|
+
*
|
|
70
|
+
* @param {string} key - The storage key to increment
|
|
71
|
+
* @returns {Promise<number>} New value after increment
|
|
72
|
+
*/
|
|
73
|
+
async increment(key) {
|
|
74
|
+
return await this.client.incr(key);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Delete data for a key
|
|
79
|
+
*
|
|
80
|
+
* @param {string} key - The storage key to delete
|
|
81
|
+
* @returns {Promise<void>}
|
|
82
|
+
*/
|
|
83
|
+
async delete(key) {
|
|
84
|
+
await this.client.del(key);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export default RedisStorage;
|