@common-stack/store-redis 8.2.5-alpha.33 → 8.2.5-alpha.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.
- package/lib/containers/container.d.ts +2 -0
- package/lib/containers/container.js +3 -0
- package/lib/containers/container.js.map +1 -0
- package/lib/containers/index.d.ts +1 -0
- package/lib/core/index.d.ts +3 -0
- package/lib/core/ioredis.d.ts +15 -0
- package/lib/core/ioredis.js +27 -0
- package/lib/core/ioredis.js.map +1 -0
- package/lib/core/keyBuilder/generate-query-cache-key.d.ts +57 -0
- package/lib/core/keyBuilder/generate-query-cache-key.js +82 -0
- package/lib/core/keyBuilder/generate-query-cache-key.js.map +1 -0
- package/lib/core/keyBuilder/index.d.ts +18 -0
- package/lib/core/keyBuilder/index.js +20 -0
- package/lib/core/keyBuilder/index.js.map +1 -0
- package/lib/core/keyBuilder/redis-key-builder.d.ts +152 -0
- package/lib/core/keyBuilder/redis-key-builder.js +181 -0
- package/lib/core/keyBuilder/redis-key-builder.js.map +1 -0
- package/lib/core/keyBuilder/sanitize-redis-key.d.ts +118 -0
- package/lib/core/keyBuilder/sanitize-redis-key.js +115 -0
- package/lib/core/keyBuilder/sanitize-redis-key.js.map +1 -0
- package/lib/core/upstash-redis.d.ts +14 -0
- package/lib/core/upstash-redis.js +23 -0
- package/lib/core/upstash-redis.js.map +1 -0
- package/lib/graphql/schema/base-services.graphql +134 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.js +1 -3
- package/lib/index.js.map +1 -0
- package/lib/interfaces/index.d.ts +1 -6
- package/lib/interfaces/redis.d.ts +11 -0
- package/lib/module.d.ts +2 -0
- package/lib/module.js +4 -0
- package/lib/module.js.map +1 -0
- package/lib/services/RedisCacheManager.d.ts +77 -0
- package/lib/services/RedisCacheManager.js +177 -0
- package/lib/services/RedisCacheManager.js.map +1 -0
- package/lib/services/index.d.ts +1 -5
- package/lib/templates/constants/SERVER_TYPES.ts.template +0 -1
- package/lib/templates/repositories/IRedisKeyBuilder.ts.template +4 -4
- package/lib/templates/repositories/redisCommonTypes.ts.template +2 -163
- package/lib/templates/{repositories/IRedisCacheManager.ts.template → services/RedisCacheManager.ts.template} +7 -7
- package/package.json +8 -7
- package/lib/interfaces/cache-manager.d.ts +0 -28
- package/lib/interfaces/redis-key-options.d.ts +0 -35
- package/lib/interfaces/redis-key-options.js +0 -17
- package/lib/interfaces/storage-backend.d.ts +0 -17
- package/lib/templates/repositories/IRedisService.ts.template +0 -236
- package/lib/templates/repositories/IRedisStorageBackend.ts.template +0 -229
- package/lib/utils/index.d.ts +0 -5
- package/lib/utils/redis-key-builder.d.ts +0 -32
- package/lib/utils/redis-key-builder.js +0 -68
- package/lib/utils/redis-key-sanitizer.d.ts +0 -30
- package/lib/utils/redis-key-sanitizer.js +0 -54
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
/**
|
|
3
|
-
* @file IRedisService.ts
|
|
4
|
-
* @description Defines the IRedisService interface for advanced Redis operations and patterns.
|
|
5
|
-
* This interface provides high-level Redis operations beyond simple key-value storage,
|
|
6
|
-
* including pub/sub, streams, sorted sets, and distributed locking.
|
|
7
|
-
*
|
|
8
|
-
* The Redis service is designed for:
|
|
9
|
-
* - Pub/Sub messaging patterns
|
|
10
|
-
* - Distributed locking (mutex)
|
|
11
|
-
* - Rate limiting
|
|
12
|
-
* - Leaderboards and rankings (sorted sets)
|
|
13
|
-
* - Event streams
|
|
14
|
-
* - Queue management
|
|
15
|
-
*
|
|
16
|
-
* Key features:
|
|
17
|
-
* - Pub/Sub for real-time messaging
|
|
18
|
-
* - Distributed locks for resource coordination
|
|
19
|
-
* - Rate limiting for API throttling
|
|
20
|
-
* - Sorted sets for rankings and leaderboards
|
|
21
|
-
* - Redis Streams for event sourcing
|
|
22
|
-
* - Pipeline operations for performance
|
|
23
|
-
*
|
|
24
|
-
* This service layer provides advanced Redis patterns that go beyond simple caching
|
|
25
|
-
* and storage, enabling sophisticated distributed system architectures.
|
|
26
|
-
*
|
|
27
|
-
* @see IRedisCacheManager - For query caching
|
|
28
|
-
* @see IRedisStorageBackend - For simple key-value storage
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
export interface IRedisService {
|
|
32
|
-
/**
|
|
33
|
-
* Publish a message to a Redis channel
|
|
34
|
-
* Part of the Pub/Sub pattern for real-time messaging
|
|
35
|
-
*
|
|
36
|
-
* @param channel - Channel name to publish to
|
|
37
|
-
* @param message - Message to publish (will be stringified if object)
|
|
38
|
-
* @returns Promise resolving to number of subscribers that received the message
|
|
39
|
-
*
|
|
40
|
-
* @example
|
|
41
|
-
* // Publish user update event
|
|
42
|
-
* await redisService.publish('user:updates', JSON.stringify({
|
|
43
|
-
* userId: '123',
|
|
44
|
-
* action: 'updated'
|
|
45
|
-
* }));
|
|
46
|
-
*/
|
|
47
|
-
publish(channel: string, message: string): Promise<number>;
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Subscribe to a Redis channel
|
|
51
|
-
* Receives messages published to the channel
|
|
52
|
-
*
|
|
53
|
-
* @param channel - Channel name to subscribe to
|
|
54
|
-
* @param callback - Function called when message received
|
|
55
|
-
* @returns Promise that resolves when subscribed
|
|
56
|
-
*
|
|
57
|
-
* @example
|
|
58
|
-
* // Subscribe to user updates
|
|
59
|
-
* await redisService.subscribe('user:updates', (message) => {
|
|
60
|
-
* const event = JSON.parse(message);
|
|
61
|
-
* console.log(`User ${event.userId} was ${event.action}`);
|
|
62
|
-
* });
|
|
63
|
-
*/
|
|
64
|
-
subscribe(channel: string, callback: (message: string) => void): Promise<void>;
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Unsubscribe from a Redis channel
|
|
68
|
-
*
|
|
69
|
-
* @param channel - Channel name to unsubscribe from
|
|
70
|
-
* @returns Promise that resolves when unsubscribed
|
|
71
|
-
*
|
|
72
|
-
* @example
|
|
73
|
-
* // Unsubscribe from updates
|
|
74
|
-
* await redisService.unsubscribe('user:updates');
|
|
75
|
-
*/
|
|
76
|
-
unsubscribe(channel: string): Promise<void>;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Acquire a distributed lock
|
|
80
|
-
* Ensures only one process can execute critical section
|
|
81
|
-
*
|
|
82
|
-
* @param key - Lock key (unique identifier for the resource)
|
|
83
|
-
* @param ttl - Lock TTL in milliseconds (auto-release if process dies)
|
|
84
|
-
* @param retries - Number of retry attempts
|
|
85
|
-
* @returns Promise resolving to lock token (needed for release) or null if failed
|
|
86
|
-
*
|
|
87
|
-
* @example
|
|
88
|
-
* // Acquire lock for order processing
|
|
89
|
-
* const lock = await redisService.acquireLock('order:123:processing', 5000);
|
|
90
|
-
* if (lock) {
|
|
91
|
-
* try {
|
|
92
|
-
* await processOrder('123');
|
|
93
|
-
* } finally {
|
|
94
|
-
* await redisService.releaseLock('order:123:processing', lock);
|
|
95
|
-
* }
|
|
96
|
-
* }
|
|
97
|
-
*/
|
|
98
|
-
acquireLock(key: string, ttl: number, retries?: number): Promise<string | null>;
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Release a distributed lock
|
|
102
|
-
* Only the process that acquired the lock can release it
|
|
103
|
-
*
|
|
104
|
-
* @param key - Lock key
|
|
105
|
-
* @param token - Lock token returned from acquireLock
|
|
106
|
-
* @returns Promise resolving to true if lock was released
|
|
107
|
-
*
|
|
108
|
-
* @example
|
|
109
|
-
* // Release lock after critical section
|
|
110
|
-
* await redisService.releaseLock('resource:123', lockToken);
|
|
111
|
-
*/
|
|
112
|
-
releaseLock(key: string, token: string): Promise<boolean>;
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Check rate limit for a key
|
|
116
|
-
* Implements sliding window rate limiting
|
|
117
|
-
*
|
|
118
|
-
* @param key - Rate limit key (e.g., userId or IP address)
|
|
119
|
-
* @param limit - Maximum requests allowed
|
|
120
|
-
* @param window - Time window in seconds
|
|
121
|
-
* @returns Promise resolving to object with allowed status and remaining count
|
|
122
|
-
*
|
|
123
|
-
* @example
|
|
124
|
-
* // Check API rate limit
|
|
125
|
-
* const rateLimitStatus = await redisService.checkRateLimit(
|
|
126
|
-
* `api:user:${userId}`,
|
|
127
|
-
* 100, // 100 requests
|
|
128
|
-
* 3600 // per hour
|
|
129
|
-
* );
|
|
130
|
-
*
|
|
131
|
-
* if (!rateLimitStatus.allowed) {
|
|
132
|
-
* throw new Error('Rate limit exceeded');
|
|
133
|
-
* }
|
|
134
|
-
*/
|
|
135
|
-
checkRateLimit(
|
|
136
|
-
key: string,
|
|
137
|
-
limit: number,
|
|
138
|
-
window: number
|
|
139
|
-
): Promise<{
|
|
140
|
-
allowed: boolean;
|
|
141
|
-
remaining: number;
|
|
142
|
-
resetAt: number;
|
|
143
|
-
}>;
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Add member to sorted set with score
|
|
147
|
-
* Useful for leaderboards, rankings, and time-ordered data
|
|
148
|
-
*
|
|
149
|
-
* @param key - Sorted set key
|
|
150
|
-
* @param score - Score for ordering (lower scores first)
|
|
151
|
-
* @param member - Member to add
|
|
152
|
-
* @returns Promise resolving to number of elements added
|
|
153
|
-
*
|
|
154
|
-
* @example
|
|
155
|
-
* // Add user score to leaderboard
|
|
156
|
-
* await redisService.sortedSetAdd('leaderboard:game1', 1000, 'user-123');
|
|
157
|
-
*/
|
|
158
|
-
sortedSetAdd(key: string, score: number, member: string): Promise<number>;
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Get top members from sorted set
|
|
162
|
-
*
|
|
163
|
-
* @param key - Sorted set key
|
|
164
|
-
* @param start - Start index (0-based)
|
|
165
|
-
* @param stop - Stop index (-1 for all)
|
|
166
|
-
* @param withScores - Whether to include scores in result
|
|
167
|
-
* @returns Promise resolving to array of members (and scores if requested)
|
|
168
|
-
*
|
|
169
|
-
* @example
|
|
170
|
-
* // Get top 10 players
|
|
171
|
-
* const topPlayers = await redisService.sortedSetRange(
|
|
172
|
-
* 'leaderboard:game1',
|
|
173
|
-
* 0,
|
|
174
|
-
* 9,
|
|
175
|
-
* true
|
|
176
|
-
* );
|
|
177
|
-
* // Result: [{member: 'user-1', score: 1500}, {member: 'user-2', score: 1400}, ...]
|
|
178
|
-
*/
|
|
179
|
-
sortedSetRange(
|
|
180
|
-
key: string,
|
|
181
|
-
start: number,
|
|
182
|
-
stop: number,
|
|
183
|
-
withScores?: boolean
|
|
184
|
-
): Promise<Array<{ member: string; score?: number }>>;
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Get member rank in sorted set
|
|
188
|
-
*
|
|
189
|
-
* @param key - Sorted set key
|
|
190
|
-
* @param member - Member to get rank for
|
|
191
|
-
* @returns Promise resolving to rank (0-based) or null if not found
|
|
192
|
-
*
|
|
193
|
-
* @example
|
|
194
|
-
* // Get user's leaderboard position
|
|
195
|
-
* const rank = await redisService.sortedSetRank('leaderboard:game1', 'user-123');
|
|
196
|
-
* console.log(`You are ranked #${rank + 1}`);
|
|
197
|
-
*/
|
|
198
|
-
sortedSetRank(key: string, member: string): Promise<number | null>;
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Add entry to Redis Stream
|
|
202
|
-
* Useful for event sourcing and message queues
|
|
203
|
-
*
|
|
204
|
-
* @param key - Stream key
|
|
205
|
-
* @param fields - Fields to add to stream entry
|
|
206
|
-
* @returns Promise resolving to entry ID
|
|
207
|
-
*
|
|
208
|
-
* @example
|
|
209
|
-
* // Add event to stream
|
|
210
|
-
* const entryId = await redisService.streamAdd('events:user-actions', {
|
|
211
|
-
* userId: '123',
|
|
212
|
-
* action: 'login',
|
|
213
|
-
* timestamp: Date.now().toString()
|
|
214
|
-
* });
|
|
215
|
-
*/
|
|
216
|
-
streamAdd(key: string, fields: Record<string, string>): Promise<string>;
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Read entries from Redis Stream
|
|
220
|
-
*
|
|
221
|
-
* @param key - Stream key
|
|
222
|
-
* @param options - Read options (count, id to start from)
|
|
223
|
-
* @returns Promise resolving to array of stream entries
|
|
224
|
-
*
|
|
225
|
-
* @example
|
|
226
|
-
* // Read last 100 events
|
|
227
|
-
* const events = await redisService.streamRead('events:user-actions', {
|
|
228
|
-
* count: 100,
|
|
229
|
-
* id: '0' // Start from beginning
|
|
230
|
-
* });
|
|
231
|
-
*/
|
|
232
|
-
streamRead(
|
|
233
|
-
key: string,
|
|
234
|
-
options?: { count?: number; id?: string }
|
|
235
|
-
): Promise<Array<{ id: string; fields: Record<string, string> }>>;
|
|
236
|
-
}
|
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
/**
|
|
3
|
-
* @file IRedisStorageBackend.ts
|
|
4
|
-
* @description Defines the IRedisStorageBackend interface for simple key-value storage operations using Redis.
|
|
5
|
-
* This interface provides a clean abstraction for basic Redis operations, suitable for request-scoped storage,
|
|
6
|
-
* temporary data, session storage, and other simple caching scenarios.
|
|
7
|
-
*
|
|
8
|
-
* The storage backend is designed for:
|
|
9
|
-
* - Request-scoped temporary data
|
|
10
|
-
* - Session storage
|
|
11
|
-
* - Simple key-value caching
|
|
12
|
-
* - Temporary flags and state
|
|
13
|
-
*
|
|
14
|
-
* Unlike RedisCacheManager which is optimized for GraphQL query caching with hashing,
|
|
15
|
-
* this storage backend provides straightforward get/set/delete operations for simple use cases.
|
|
16
|
-
*
|
|
17
|
-
* Key features:
|
|
18
|
-
* - Simple key-value operations
|
|
19
|
-
* - TTL support for automatic expiration
|
|
20
|
-
* - Bulk operations for efficiency
|
|
21
|
-
* - Clear operations for cleanup
|
|
22
|
-
* - Type-safe with generics
|
|
23
|
-
*
|
|
24
|
-
* @see IRedisCacheManager - For complex caching with GraphQL queries
|
|
25
|
-
* @see IRedisKeyBuilder - For standardized key generation
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
export interface IRedisStorageBackend {
|
|
29
|
-
/**
|
|
30
|
-
* Get a value by key
|
|
31
|
-
* Returns null if key doesn't exist
|
|
32
|
-
*
|
|
33
|
-
* @param key - Redis key to retrieve
|
|
34
|
-
* @returns Promise resolving to the value or null
|
|
35
|
-
*
|
|
36
|
-
* @example
|
|
37
|
-
* // Get session data
|
|
38
|
-
* const sessionData = await storage.get('session:user-123');
|
|
39
|
-
* if (sessionData) {
|
|
40
|
-
* const session = JSON.parse(sessionData);
|
|
41
|
-
* }
|
|
42
|
-
*/
|
|
43
|
-
get(key: string): Promise<string | null>;
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Get multiple values by keys
|
|
47
|
-
* Returns array with same order as keys, null for missing keys
|
|
48
|
-
*
|
|
49
|
-
* @param keys - Array of Redis keys to retrieve
|
|
50
|
-
* @returns Promise resolving to array of values
|
|
51
|
-
*
|
|
52
|
-
* @example
|
|
53
|
-
* // Get multiple user preferences
|
|
54
|
-
* const keys = ['pref:user-1', 'pref:user-2', 'pref:user-3'];
|
|
55
|
-
* const values = await storage.getMany(keys);
|
|
56
|
-
*/
|
|
57
|
-
getMany(keys: string[]): Promise<(string | null)[]>;
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Set a value for a key
|
|
61
|
-
* Optionally specify TTL in seconds
|
|
62
|
-
*
|
|
63
|
-
* @param key - Redis key to set
|
|
64
|
-
* @param value - Value to store (will be stringified if object)
|
|
65
|
-
* @param ttl - Optional time-to-live in seconds
|
|
66
|
-
* @returns Promise that resolves when set is complete
|
|
67
|
-
*
|
|
68
|
-
* @example
|
|
69
|
-
* // Store session with 1 hour expiration
|
|
70
|
-
* await storage.set('session:user-123', JSON.stringify(sessionData), 3600);
|
|
71
|
-
*
|
|
72
|
-
* @example
|
|
73
|
-
* // Store temporary flag
|
|
74
|
-
* await storage.set('flag:processing', 'true', 300); // 5 minutes
|
|
75
|
-
*/
|
|
76
|
-
set(key: string, value: string, ttl?: number): Promise<void>;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Set multiple key-value pairs
|
|
80
|
-
* Efficiently stores multiple entries in one operation
|
|
81
|
-
*
|
|
82
|
-
* @param entries - Array of key-value pairs to set
|
|
83
|
-
* @param ttl - Optional TTL to apply to all entries
|
|
84
|
-
* @returns Promise that resolves when all are set
|
|
85
|
-
*
|
|
86
|
-
* @example
|
|
87
|
-
* // Set multiple user preferences
|
|
88
|
-
* await storage.setMany([
|
|
89
|
-
* { key: 'pref:theme', value: 'dark' },
|
|
90
|
-
* { key: 'pref:lang', value: 'en' }
|
|
91
|
-
* ], 86400); // 24 hours
|
|
92
|
-
*/
|
|
93
|
-
setMany(entries: Array<{ key: string; value: string }>, ttl?: number): Promise<void>;
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Delete a value by key
|
|
97
|
-
* Returns true if key existed and was deleted
|
|
98
|
-
*
|
|
99
|
-
* @param key - Redis key to delete
|
|
100
|
-
* @returns Promise resolving to deletion success
|
|
101
|
-
*
|
|
102
|
-
* @example
|
|
103
|
-
* // Delete session on logout
|
|
104
|
-
* const deleted = await storage.delete('session:user-123');
|
|
105
|
-
*/
|
|
106
|
-
delete(key: string): Promise<boolean>;
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Delete multiple keys
|
|
110
|
-
* Returns number of keys that were deleted
|
|
111
|
-
*
|
|
112
|
-
* @param keys - Array of Redis keys to delete
|
|
113
|
-
* @returns Promise resolving to count of deleted keys
|
|
114
|
-
*
|
|
115
|
-
* @example
|
|
116
|
-
* // Delete multiple cache entries
|
|
117
|
-
* const deletedCount = await storage.deleteMany([
|
|
118
|
-
* 'cache:user-1',
|
|
119
|
-
* 'cache:user-2'
|
|
120
|
-
* ]);
|
|
121
|
-
*/
|
|
122
|
-
deleteMany(keys: string[]): Promise<number>;
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Check if a key exists
|
|
126
|
-
*
|
|
127
|
-
* @param key - Redis key to check
|
|
128
|
-
* @returns Promise resolving to true if key exists
|
|
129
|
-
*
|
|
130
|
-
* @example
|
|
131
|
-
* // Check if session exists
|
|
132
|
-
* const hasSession = await storage.exists('session:user-123');
|
|
133
|
-
*/
|
|
134
|
-
exists(key: string): Promise<boolean>;
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Get remaining TTL for a key in seconds
|
|
138
|
-
* Returns -1 if key has no expiration
|
|
139
|
-
* Returns -2 if key doesn't exist
|
|
140
|
-
*
|
|
141
|
-
* @param key - Redis key to check
|
|
142
|
-
* @returns Promise resolving to TTL in seconds
|
|
143
|
-
*
|
|
144
|
-
* @example
|
|
145
|
-
* // Check session expiration
|
|
146
|
-
* const ttl = await storage.getTTL('session:user-123');
|
|
147
|
-
* if (ttl < 300) {
|
|
148
|
-
* // Session expires in less than 5 minutes
|
|
149
|
-
* }
|
|
150
|
-
*/
|
|
151
|
-
getTTL(key: string): Promise<number>;
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Set TTL for an existing key
|
|
155
|
-
* Updates expiration time without changing the value
|
|
156
|
-
*
|
|
157
|
-
* @param key - Redis key to update
|
|
158
|
-
* @param ttl - New TTL in seconds
|
|
159
|
-
* @returns Promise resolving to true if TTL was set
|
|
160
|
-
*
|
|
161
|
-
* @example
|
|
162
|
-
* // Extend session by 1 hour
|
|
163
|
-
* await storage.setTTL('session:user-123', 3600);
|
|
164
|
-
*/
|
|
165
|
-
setTTL(key: string, ttl: number): Promise<boolean>;
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Clear all keys matching a pattern
|
|
169
|
-
* Uses SCAN to find keys, then deletes them
|
|
170
|
-
*
|
|
171
|
-
* @param pattern - Redis pattern to match (supports wildcards)
|
|
172
|
-
* @returns Promise resolving to count of deleted keys
|
|
173
|
-
*
|
|
174
|
-
* @example
|
|
175
|
-
* // Clear all session keys for a tenant
|
|
176
|
-
* const cleared = await storage.clearPattern('APP:tenant-123:session:*');
|
|
177
|
-
*
|
|
178
|
-
* @example
|
|
179
|
-
* // Clear all temporary keys
|
|
180
|
-
* await storage.clearPattern('APP:*:temp:*');
|
|
181
|
-
*/
|
|
182
|
-
clearPattern(pattern: string): Promise<number>;
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Clear all keys in this storage's namespace
|
|
186
|
-
* Useful for cleanup operations
|
|
187
|
-
*
|
|
188
|
-
* @returns Promise that resolves when clear is complete
|
|
189
|
-
*
|
|
190
|
-
* @example
|
|
191
|
-
* // Clear all storage on request end
|
|
192
|
-
* res.on('finish', async () => {
|
|
193
|
-
* await storage.clear();
|
|
194
|
-
* });
|
|
195
|
-
*/
|
|
196
|
-
clear(): Promise<void>;
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Increment a numeric value
|
|
200
|
-
* Creates key with value 0 if it doesn't exist
|
|
201
|
-
*
|
|
202
|
-
* @param key - Redis key to increment
|
|
203
|
-
* @param amount - Amount to increment by (default: 1)
|
|
204
|
-
* @returns Promise resolving to new value
|
|
205
|
-
*
|
|
206
|
-
* @example
|
|
207
|
-
* // Increment counter
|
|
208
|
-
* const newCount = await storage.increment('counter:requests');
|
|
209
|
-
*
|
|
210
|
-
* @example
|
|
211
|
-
* // Add to score
|
|
212
|
-
* const score = await storage.increment('score:user-123', 10);
|
|
213
|
-
*/
|
|
214
|
-
increment(key: string, amount?: number): Promise<number>;
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* Decrement a numeric value
|
|
218
|
-
* Creates key with value 0 if it doesn't exist
|
|
219
|
-
*
|
|
220
|
-
* @param key - Redis key to decrement
|
|
221
|
-
* @param amount - Amount to decrement by (default: 1)
|
|
222
|
-
* @returns Promise resolving to new value
|
|
223
|
-
*
|
|
224
|
-
* @example
|
|
225
|
-
* // Decrement available slots
|
|
226
|
-
* const remaining = await storage.decrement('slots:available');
|
|
227
|
-
*/
|
|
228
|
-
decrement(key: string, amount?: number): Promise<number>;
|
|
229
|
-
}
|
package/lib/utils/index.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { RedisKeyOptions } from '../interfaces/redis-key-options';
|
|
2
|
-
/**
|
|
3
|
-
* Build a standardized Redis key with proper formatting and sanitization
|
|
4
|
-
*
|
|
5
|
-
* Format: <APP_NAME>:<tenantId>:<namespace>:<segments...>
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* buildRedisKey({
|
|
9
|
-
* tenantId: 'tenant-123',
|
|
10
|
-
* namespace: RedisNamespace.CACHE,
|
|
11
|
-
* segments: ['user', 'profile']
|
|
12
|
-
* })
|
|
13
|
-
* // Returns: "APP_NAME:tenant-123:cache:user:profile"
|
|
14
|
-
*/
|
|
15
|
-
export declare function buildRedisKey(options: RedisKeyOptions): string;
|
|
16
|
-
/**
|
|
17
|
-
* Build a Redis key pattern for wildcard matching
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* buildRedisKeyPattern({
|
|
21
|
-
* tenantId: 'tenant-123',
|
|
22
|
-
* namespace: RedisNamespace.CACHE,
|
|
23
|
-
* segments: ['user', '*']
|
|
24
|
-
* })
|
|
25
|
-
* // Returns: "APP_NAME:tenant-123:cache:user:*"
|
|
26
|
-
*/
|
|
27
|
-
export declare function buildRedisKeyPattern(options: RedisKeyOptions): string;
|
|
28
|
-
/**
|
|
29
|
-
* Validate if a string is a valid Redis key
|
|
30
|
-
* Redis keys can be up to 512MB but should be kept reasonable
|
|
31
|
-
*/
|
|
32
|
-
export declare function isValidRedisKey(key: string): boolean;
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { sanitizeKeyComponent } from './redis-key-sanitizer.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Get application name from environment or config
|
|
5
|
-
* This will be replaced with actual config import during migration
|
|
6
|
-
*/
|
|
7
|
-
const getAppName = () => {
|
|
8
|
-
return process.env.APP_NAME || 'APP';
|
|
9
|
-
};
|
|
10
|
-
/**
|
|
11
|
-
* Build a standardized Redis key with proper formatting and sanitization
|
|
12
|
-
*
|
|
13
|
-
* Format: <APP_NAME>:<tenantId>:<namespace>:<segments...>
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* buildRedisKey({
|
|
17
|
-
* tenantId: 'tenant-123',
|
|
18
|
-
* namespace: RedisNamespace.CACHE,
|
|
19
|
-
* segments: ['user', 'profile']
|
|
20
|
-
* })
|
|
21
|
-
* // Returns: "APP_NAME:tenant-123:cache:user:profile"
|
|
22
|
-
*/
|
|
23
|
-
function buildRedisKey(options) {
|
|
24
|
-
const { tenantId = 'default', namespace, segments, userId } = options;
|
|
25
|
-
// Sanitize all components
|
|
26
|
-
const sanitizedTenantId = sanitizeKeyComponent(tenantId);
|
|
27
|
-
const sanitizedNamespace = sanitizeKeyComponent(namespace);
|
|
28
|
-
const sanitizedSegments = segments.map(sanitizeKeyComponent);
|
|
29
|
-
// Build key parts
|
|
30
|
-
const parts = [getAppName(), sanitizedTenantId, sanitizedNamespace, ...sanitizedSegments];
|
|
31
|
-
// Add userId if provided
|
|
32
|
-
if (userId) {
|
|
33
|
-
parts.splice(2, 0, sanitizeKeyComponent(userId));
|
|
34
|
-
}
|
|
35
|
-
return parts.join(':');
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Build a Redis key pattern for wildcard matching
|
|
39
|
-
*
|
|
40
|
-
* @example
|
|
41
|
-
* buildRedisKeyPattern({
|
|
42
|
-
* tenantId: 'tenant-123',
|
|
43
|
-
* namespace: RedisNamespace.CACHE,
|
|
44
|
-
* segments: ['user', '*']
|
|
45
|
-
* })
|
|
46
|
-
* // Returns: "APP_NAME:tenant-123:cache:user:*"
|
|
47
|
-
*/
|
|
48
|
-
function buildRedisKeyPattern(options) {
|
|
49
|
-
// Same as buildRedisKey but allows '*' in segments
|
|
50
|
-
return buildRedisKey(options);
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Validate if a string is a valid Redis key
|
|
54
|
-
* Redis keys can be up to 512MB but should be kept reasonable
|
|
55
|
-
*/
|
|
56
|
-
function isValidRedisKey(key) {
|
|
57
|
-
// Basic validation rules
|
|
58
|
-
if (!key || key.length === 0)
|
|
59
|
-
return false;
|
|
60
|
-
if (key.length > 1024)
|
|
61
|
-
return false; // Reasonable limit
|
|
62
|
-
// Check for invalid characters after sanitization
|
|
63
|
-
// After sanitization, keys should only contain alphanumeric, colons, hyphens, underscores
|
|
64
|
-
const validPattern = /^[a-zA-Z0-9:_-]+$/;
|
|
65
|
-
return validPattern.test(key);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export { buildRedisKey, buildRedisKeyPattern, isValidRedisKey };
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sanitize a Redis key component to ensure it's valid and safe
|
|
3
|
-
*
|
|
4
|
-
* Redis keys can contain any binary sequence, but for best practices:
|
|
5
|
-
* - Avoid whitespace (spaces, tabs, newlines) - replace with underscores
|
|
6
|
-
* - Avoid control characters (0x00-0x1F, 0x7F) - remove them
|
|
7
|
-
* - Avoid quotes and backslashes that could cause escaping issues - remove them
|
|
8
|
-
* - Replace pipes (|) with hyphens since Auth0 userIds use pipes (auth0|123)
|
|
9
|
-
*
|
|
10
|
-
* @param component - The key component to sanitize
|
|
11
|
-
* @returns Sanitized key component
|
|
12
|
-
*/
|
|
13
|
-
export declare function sanitizeKeyComponent(component: string): string;
|
|
14
|
-
/**
|
|
15
|
-
* Sanitize an entire Redis key (all components)
|
|
16
|
-
* Useful for keys that are already constructed
|
|
17
|
-
*
|
|
18
|
-
* @param key - The complete Redis key to sanitize
|
|
19
|
-
* @returns Sanitized Redis key
|
|
20
|
-
*/
|
|
21
|
-
export declare function sanitizeRedisKey(key: string): string;
|
|
22
|
-
/**
|
|
23
|
-
* Escape special Redis pattern characters for exact matching
|
|
24
|
-
* Useful when you want to search for keys containing wildcards literally
|
|
25
|
-
* Note: Hyphens are not escaped as they're commonly used in keys
|
|
26
|
-
*
|
|
27
|
-
* @param pattern - The pattern to escape
|
|
28
|
-
* @returns Escaped pattern
|
|
29
|
-
*/
|
|
30
|
-
export declare function escapeRedisPattern(pattern: string): string;
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sanitize a Redis key component to ensure it's valid and safe
|
|
3
|
-
*
|
|
4
|
-
* Redis keys can contain any binary sequence, but for best practices:
|
|
5
|
-
* - Avoid whitespace (spaces, tabs, newlines) - replace with underscores
|
|
6
|
-
* - Avoid control characters (0x00-0x1F, 0x7F) - remove them
|
|
7
|
-
* - Avoid quotes and backslashes that could cause escaping issues - remove them
|
|
8
|
-
* - Replace pipes (|) with hyphens since Auth0 userIds use pipes (auth0|123)
|
|
9
|
-
*
|
|
10
|
-
* @param component - The key component to sanitize
|
|
11
|
-
* @returns Sanitized key component
|
|
12
|
-
*/
|
|
13
|
-
function sanitizeKeyComponent(component) {
|
|
14
|
-
if (!component)
|
|
15
|
-
return '';
|
|
16
|
-
return component
|
|
17
|
-
.trim() // Trim first to remove leading/trailing whitespace
|
|
18
|
-
.replace(/[\s\r\n\t]+/g, '_') // Replace whitespace with underscore
|
|
19
|
-
.replace(/\|/g, '-') // Replace pipe with hyphen (Auth0 userIds: auth0|123 → auth0-123)
|
|
20
|
-
.replace(/[\x00-\x1F\x7F]/g, '') // Remove control characters
|
|
21
|
-
.replace(/["'\\]/g, ''); // Remove quotes and backslashes
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Sanitize an entire Redis key (all components)
|
|
25
|
-
* Useful for keys that are already constructed
|
|
26
|
-
*
|
|
27
|
-
* @param key - The complete Redis key to sanitize
|
|
28
|
-
* @returns Sanitized Redis key
|
|
29
|
-
*/
|
|
30
|
-
function sanitizeRedisKey(key) {
|
|
31
|
-
if (!key)
|
|
32
|
-
return '';
|
|
33
|
-
// Split by colon, sanitize each part, rejoin
|
|
34
|
-
return key
|
|
35
|
-
.split(':')
|
|
36
|
-
.map(sanitizeKeyComponent)
|
|
37
|
-
.filter((part) => part.length > 0)
|
|
38
|
-
.join(':');
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Escape special Redis pattern characters for exact matching
|
|
42
|
-
* Useful when you want to search for keys containing wildcards literally
|
|
43
|
-
* Note: Hyphens are not escaped as they're commonly used in keys
|
|
44
|
-
*
|
|
45
|
-
* @param pattern - The pattern to escape
|
|
46
|
-
* @returns Escaped pattern
|
|
47
|
-
*/
|
|
48
|
-
function escapeRedisPattern(pattern) {
|
|
49
|
-
// Escape Redis KEYS pattern special characters: * ? [ ] ^ \
|
|
50
|
-
// Note: We don't escape hyphen (-) as it's not special outside character classes
|
|
51
|
-
return pattern.replace(/[*?[\]^\\]/g, '\\$&');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export { escapeRedisPattern, sanitizeKeyComponent, sanitizeRedisKey };
|