@common-stack/store-redis 8.2.5-alpha.33
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/LICENSE +34 -0
- package/README.md +69 -0
- package/lib/__tests__/redis-key-builder.test.d.ts +1 -0
- package/lib/__tests__/redis-key-sanitizer.test.d.ts +1 -0
- package/lib/index.d.ts +14 -0
- package/lib/index.js +3 -0
- package/lib/interfaces/cache-manager.d.ts +28 -0
- package/lib/interfaces/index.d.ts +6 -0
- package/lib/interfaces/redis-key-options.d.ts +35 -0
- package/lib/interfaces/redis-key-options.js +17 -0
- package/lib/interfaces/storage-backend.d.ts +17 -0
- package/lib/services/index.d.ts +8 -0
- package/lib/templates/constants/SERVER_TYPES.ts.template +7 -0
- package/lib/templates/repositories/IRedisCacheManager.ts.template +212 -0
- package/lib/templates/repositories/IRedisKeyBuilder.ts.template +169 -0
- package/lib/templates/repositories/IRedisService.ts.template +236 -0
- package/lib/templates/repositories/IRedisStorageBackend.ts.template +229 -0
- package/lib/templates/repositories/redisCommonTypes.ts.template +189 -0
- package/lib/utils/index.d.ts +5 -0
- package/lib/utils/redis-key-builder.d.ts +32 -0
- package/lib/utils/redis-key-builder.js +68 -0
- package/lib/utils/redis-key-sanitizer.d.ts +30 -0
- package/lib/utils/redis-key-sanitizer.js +54 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
PROPRIETARY LICENSE
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017-2025 CDMBase LLC. All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
This software and associated documentation files (the "Software") are the
|
|
6
|
+
proprietary and confidential information of CDMBase LLC ("Confidential Information").
|
|
7
|
+
|
|
8
|
+
NOTICE: All information contained herein is, and remains the property of
|
|
9
|
+
CDMBase LLC. The intellectual and technical concepts contained herein are
|
|
10
|
+
proprietary to CDMBase LLC and may be covered by U.S. and Foreign Patents,
|
|
11
|
+
patents in process, and are protected by trade secret or copyright law.
|
|
12
|
+
|
|
13
|
+
Dissemination of this information or reproduction of this material is strictly
|
|
14
|
+
forbidden unless prior written permission is obtained from CDMBase LLC.
|
|
15
|
+
|
|
16
|
+
NO LICENSE, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, TO ANY INTELLECTUAL
|
|
17
|
+
PROPERTY RIGHTS ARE GRANTED BY THIS DOCUMENT.
|
|
18
|
+
|
|
19
|
+
RESTRICTIONS:
|
|
20
|
+
1. You may NOT use, copy, modify, merge, publish, distribute, sublicense,
|
|
21
|
+
and/or sell copies of the Software without explicit written permission
|
|
22
|
+
from CDMBase LLC.
|
|
23
|
+
2. You may NOT reverse engineer, decompile, or disassemble the Software.
|
|
24
|
+
3. You may NOT remove or alter any proprietary notices or labels on the Software.
|
|
25
|
+
4. The Software is licensed, not sold.
|
|
26
|
+
|
|
27
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
28
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
29
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
30
|
+
CDMBASE LLC BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
31
|
+
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
32
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
33
|
+
|
|
34
|
+
For licensing inquiries, please contact: legal@cdmbase.com
|
package/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# @common-stack/store-redis
|
|
2
|
+
|
|
3
|
+
Redis store utilities and services for common-stack applications.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This package provides centralized Redis utilities, services, and patterns for managing Redis operations across common-stack applications. It includes:
|
|
8
|
+
|
|
9
|
+
- **Key Management**: Centralized Redis key building and sanitization
|
|
10
|
+
- **Cache Services**: Redis-based caching services with consistent patterns
|
|
11
|
+
- **Storage Backends**: Simple key-value storage implementations
|
|
12
|
+
- **Utilities**: Helper functions for Redis operations
|
|
13
|
+
|
|
14
|
+
## Structure
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
src/
|
|
18
|
+
├── interfaces/ # TypeScript interfaces and types
|
|
19
|
+
├── services/ # Redis service implementations
|
|
20
|
+
├── utils/ # Utility functions (key builders, sanitizers)
|
|
21
|
+
└── index.ts # Public API exports
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Future Migration
|
|
25
|
+
|
|
26
|
+
This package is prepared to consolidate Redis utilities from:
|
|
27
|
+
|
|
28
|
+
- `@adminide-stack/platform-server` (redis-key-builder, RedisCacheManager)
|
|
29
|
+
- `@adminide-stack/auth0-server-core` (RedisStorageBackend)
|
|
30
|
+
- Other Redis-related utilities across the codebase
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { buildRedisKey, buildRedisKeyPattern, RedisNamespace } from '@common-stack/store-redis';
|
|
36
|
+
|
|
37
|
+
// Build a Redis key
|
|
38
|
+
const key = buildRedisKey({
|
|
39
|
+
tenantId: 'tenant-123',
|
|
40
|
+
namespace: RedisNamespace.CACHE,
|
|
41
|
+
segments: ['user', 'profile'],
|
|
42
|
+
});
|
|
43
|
+
// Result: APP_NAME:tenant-123:cache:user:profile
|
|
44
|
+
|
|
45
|
+
// Build a pattern for bulk operations
|
|
46
|
+
const pattern = buildRedisKeyPattern({
|
|
47
|
+
tenantId: 'tenant-123',
|
|
48
|
+
namespace: RedisNamespace.CACHE,
|
|
49
|
+
segments: ['user', '*'],
|
|
50
|
+
});
|
|
51
|
+
// Result: APP_NAME:tenant-123:cache:user:*
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Development
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Build the package
|
|
58
|
+
npm run build
|
|
59
|
+
|
|
60
|
+
# Watch mode
|
|
61
|
+
npm run watch
|
|
62
|
+
|
|
63
|
+
# Run tests
|
|
64
|
+
npm test
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
UNLICENSED
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @common-stack/store-redis
|
|
3
|
+
*
|
|
4
|
+
* Redis store utilities and services for common-stack applications
|
|
5
|
+
*
|
|
6
|
+
* This package will consolidate Redis utilities from across the codebase:
|
|
7
|
+
* - Key management and sanitization
|
|
8
|
+
* - Cache services
|
|
9
|
+
* - Storage backends
|
|
10
|
+
* - Redis patterns and utilities
|
|
11
|
+
*/
|
|
12
|
+
export * from './interfaces';
|
|
13
|
+
export * from './services';
|
|
14
|
+
export * from './utils';
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { RedisNamespace } from './interfaces/redis-key-options.js';
|
|
2
|
+
export { buildRedisKey, buildRedisKeyPattern, isValidRedisKey } from './utils/redis-key-builder.js';
|
|
3
|
+
export { escapeRedisPattern, sanitizeKeyComponent, sanitizeRedisKey } from './utils/redis-key-sanitizer.js';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { DocumentNode } from 'graphql';
|
|
2
|
+
import type { CacheContext } from './redis-key-options';
|
|
3
|
+
/**
|
|
4
|
+
* Cache policy for controlling cache behavior
|
|
5
|
+
*/
|
|
6
|
+
export interface CachePolicy {
|
|
7
|
+
/** Maximum age in seconds */
|
|
8
|
+
maxAge: number;
|
|
9
|
+
/** Cache scope (PUBLIC, PRIVATE, etc.) */
|
|
10
|
+
scope?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Redis cache manager interface for GraphQL query caching
|
|
14
|
+
*/
|
|
15
|
+
export interface IRedisCacheManager {
|
|
16
|
+
/**
|
|
17
|
+
* Get cached data for a query
|
|
18
|
+
*/
|
|
19
|
+
get<T>(query: string | DocumentNode, variables: Record<string, any>, ctx: CacheContext): Promise<T | null>;
|
|
20
|
+
/**
|
|
21
|
+
* Set cached data for a query
|
|
22
|
+
*/
|
|
23
|
+
set<T>(query: string | DocumentNode, variables: Record<string, any>, data: T, ctx: CacheContext, cachePolicy?: CachePolicy): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Delete cached data for a query
|
|
26
|
+
*/
|
|
27
|
+
del(query: string | DocumentNode, variables?: Record<string, unknown>, ctx?: CacheContext, shouldRemoveAll?: boolean): Promise<void>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for building Redis keys with standardized format
|
|
3
|
+
*/
|
|
4
|
+
export interface RedisKeyOptions {
|
|
5
|
+
/** Tenant ID for multi-tenant isolation */
|
|
6
|
+
tenantId?: string;
|
|
7
|
+
/** Namespace to categorize keys (e.g., 'cache', 'session', 'storage') */
|
|
8
|
+
namespace: string;
|
|
9
|
+
/** Additional key segments to append */
|
|
10
|
+
segments: string[];
|
|
11
|
+
/** Optional user ID for user-specific keys */
|
|
12
|
+
userId?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Standard Redis namespaces for organizing keys
|
|
16
|
+
*/
|
|
17
|
+
export declare enum RedisNamespace {
|
|
18
|
+
CACHE = "cache",
|
|
19
|
+
SESSION = "session",
|
|
20
|
+
TENANT = "tenant",
|
|
21
|
+
CONFIG = "config",
|
|
22
|
+
EXTENSION = "extension",
|
|
23
|
+
CONTRIBUTION = "contribution",
|
|
24
|
+
STORAGE = "storage",
|
|
25
|
+
PERMISSION = "permission",
|
|
26
|
+
TEMP = "temp"
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Context for cache operations
|
|
30
|
+
*/
|
|
31
|
+
export interface CacheContext {
|
|
32
|
+
tenantId?: string;
|
|
33
|
+
userId?: string;
|
|
34
|
+
orgId?: string;
|
|
35
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard Redis namespaces for organizing keys
|
|
3
|
+
*/
|
|
4
|
+
var RedisNamespace;
|
|
5
|
+
(function (RedisNamespace) {
|
|
6
|
+
RedisNamespace["CACHE"] = "cache";
|
|
7
|
+
RedisNamespace["SESSION"] = "session";
|
|
8
|
+
RedisNamespace["TENANT"] = "tenant";
|
|
9
|
+
RedisNamespace["CONFIG"] = "config";
|
|
10
|
+
RedisNamespace["EXTENSION"] = "extension";
|
|
11
|
+
RedisNamespace["CONTRIBUTION"] = "contribution";
|
|
12
|
+
RedisNamespace["STORAGE"] = "storage";
|
|
13
|
+
RedisNamespace["PERMISSION"] = "permission";
|
|
14
|
+
RedisNamespace["TEMP"] = "temp";
|
|
15
|
+
})(RedisNamespace || (RedisNamespace = {}));
|
|
16
|
+
|
|
17
|
+
export { RedisNamespace };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic storage backend interface for simple key-value operations
|
|
3
|
+
*/
|
|
4
|
+
export interface IStorageBackend {
|
|
5
|
+
/**
|
|
6
|
+
* Get a value by key
|
|
7
|
+
*/
|
|
8
|
+
get(key: string): Promise<string | null>;
|
|
9
|
+
/**
|
|
10
|
+
* Set a value for a key
|
|
11
|
+
*/
|
|
12
|
+
set(key: string, value: string): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Clear all keys in this storage
|
|
15
|
+
*/
|
|
16
|
+
clear(): Promise<void>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const SERVER_TYPES = {
|
|
2
|
+
RedisClient: Symbol.for('RedisClient'),
|
|
3
|
+
RedisCacheManager: Symbol.for('RedisCacheManager'),
|
|
4
|
+
RedisStorageBackend: Symbol.for('RedisStorageBackend'),
|
|
5
|
+
RedisConnectionPool: Symbol.for('RedisConnectionPool'),
|
|
6
|
+
RedisKeyBuilder: Symbol.for('RedisKeyBuilder'),
|
|
7
|
+
};
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/**
|
|
3
|
+
* @file IRedisCacheManager.ts
|
|
4
|
+
* @description Defines the IRedisCacheManager interface for GraphQL query caching with Redis.
|
|
5
|
+
* This interface provides sophisticated caching capabilities specifically designed for GraphQL operations,
|
|
6
|
+
* with automatic query hashing, variable-based cache keys, and wildcard invalidation support.
|
|
7
|
+
*
|
|
8
|
+
* The cache manager is optimized for:
|
|
9
|
+
* - GraphQL query result caching
|
|
10
|
+
* - Automatic cache key generation from queries and variables
|
|
11
|
+
* - Multi-tenant cache isolation
|
|
12
|
+
* - Flexible cache invalidation strategies
|
|
13
|
+
* - TTL-based expiration
|
|
14
|
+
*
|
|
15
|
+
* Key features:
|
|
16
|
+
* - Automatic hashing of GraphQL queries and variables
|
|
17
|
+
* - Cache key format: {APP_NAME}:{tenantId}:{userId}:{queryName}:{queryHash}:{variablesHash}
|
|
18
|
+
* - Support for both string queries and DocumentNode
|
|
19
|
+
* - Wildcard-based cache invalidation
|
|
20
|
+
* - Tenant and user isolation
|
|
21
|
+
* - Configurable cache policies (TTL, scope)
|
|
22
|
+
*
|
|
23
|
+
* This cache manager helps improve GraphQL API performance by caching expensive query results
|
|
24
|
+
* while maintaining cache correctness through intelligent invalidation strategies.
|
|
25
|
+
*
|
|
26
|
+
* @see IRedisStorageBackend - For simpler key-value storage
|
|
27
|
+
* @see CachePolicy - For cache TTL and scope configuration
|
|
28
|
+
* @see CacheContext - For tenant/user isolation
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import type { DocumentNode } from 'graphql';
|
|
32
|
+
import { CacheContext, CachePolicy } from './redisCommonTypes';
|
|
33
|
+
|
|
34
|
+
export interface IRedisCacheManager {
|
|
35
|
+
/**
|
|
36
|
+
* Get cached data for a GraphQL query
|
|
37
|
+
* Returns null if cache miss or cache expired
|
|
38
|
+
*
|
|
39
|
+
* The cache key is automatically generated from the query, variables, and context
|
|
40
|
+
*
|
|
41
|
+
* @param query - GraphQL query string or DocumentNode
|
|
42
|
+
* @param variables - Query variables for cache key generation
|
|
43
|
+
* @param ctx - Cache context (tenant, user, org)
|
|
44
|
+
* @returns Promise resolving to cached data or null
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* // Get cached user query result
|
|
48
|
+
* const cachedUser = await cacheManager.get<User>(
|
|
49
|
+
* GET_USER_QUERY,
|
|
50
|
+
* { userId: '123' },
|
|
51
|
+
* { tenantId: 'tenant-1', userId: 'user-1' }
|
|
52
|
+
* );
|
|
53
|
+
*
|
|
54
|
+
* if (!cachedUser) {
|
|
55
|
+
* // Cache miss, fetch from database
|
|
56
|
+
* const user = await fetchUser('123');
|
|
57
|
+
* await cacheManager.set(GET_USER_QUERY, { userId: '123' }, user, ctx);
|
|
58
|
+
* }
|
|
59
|
+
*/
|
|
60
|
+
get<T>(
|
|
61
|
+
query: string | DocumentNode,
|
|
62
|
+
variables: Record<string, any>,
|
|
63
|
+
ctx: CacheContext
|
|
64
|
+
): Promise<T | null>;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Set cached data for a GraphQL query
|
|
68
|
+
* Stores the result with automatic key generation and optional TTL
|
|
69
|
+
*
|
|
70
|
+
* @param query - GraphQL query string or DocumentNode
|
|
71
|
+
* @param variables - Query variables for cache key generation
|
|
72
|
+
* @param data - Data to cache
|
|
73
|
+
* @param ctx - Cache context (tenant, user, org)
|
|
74
|
+
* @param cachePolicy - Optional cache policy with TTL and scope
|
|
75
|
+
* @returns Promise that resolves when data is cached
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* // Cache query result for 1 hour
|
|
79
|
+
* await cacheManager.set(
|
|
80
|
+
* GET_USERS_QUERY,
|
|
81
|
+
* { role: 'admin' },
|
|
82
|
+
* users,
|
|
83
|
+
* { tenantId: 'tenant-1' },
|
|
84
|
+
* { maxAge: 3600, scope: 'PUBLIC' }
|
|
85
|
+
* );
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* // Cache with default TTL (24 hours)
|
|
89
|
+
* await cacheManager.set(
|
|
90
|
+
* GET_PRODUCT_QUERY,
|
|
91
|
+
* { productId: '456' },
|
|
92
|
+
* product,
|
|
93
|
+
* { tenantId: 'tenant-1' }
|
|
94
|
+
* );
|
|
95
|
+
*/
|
|
96
|
+
set<T>(
|
|
97
|
+
query: string | DocumentNode,
|
|
98
|
+
variables: Record<string, any>,
|
|
99
|
+
data: T,
|
|
100
|
+
ctx: CacheContext,
|
|
101
|
+
cachePolicy?: CachePolicy
|
|
102
|
+
): Promise<void>;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Delete cached data for a GraphQL query
|
|
106
|
+
* Supports both exact deletion and wildcard patterns
|
|
107
|
+
*
|
|
108
|
+
* When variables are provided: Deletes exact cache entry for those specific variables
|
|
109
|
+
* When variables are omitted: Deletes all cache entries for that query
|
|
110
|
+
* When shouldRemoveAll is true: Uses wildcard pattern to match query name
|
|
111
|
+
*
|
|
112
|
+
* @param query - GraphQL query string or DocumentNode
|
|
113
|
+
* @param variables - Optional query variables for specific deletion
|
|
114
|
+
* @param ctx - Optional cache context for tenant/user filtering
|
|
115
|
+
* @param shouldRemoveAll - If true, removes all entries matching query name
|
|
116
|
+
* @returns Promise that resolves when deletion is complete
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* // Delete specific cached query
|
|
120
|
+
* await cacheManager.del(
|
|
121
|
+
* GET_USER_QUERY,
|
|
122
|
+
* { userId: '123' },
|
|
123
|
+
* { tenantId: 'tenant-1' }
|
|
124
|
+
* );
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* // Delete all cached user queries for a tenant
|
|
128
|
+
* await cacheManager.del(
|
|
129
|
+
* GET_USER_QUERY,
|
|
130
|
+
* undefined,
|
|
131
|
+
* { tenantId: 'tenant-1' },
|
|
132
|
+
* true
|
|
133
|
+
* );
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* // Delete all variations of a query
|
|
137
|
+
* await cacheManager.del(
|
|
138
|
+
* GET_USERS_QUERY,
|
|
139
|
+
* undefined,
|
|
140
|
+
* { tenantId: 'tenant-1' }
|
|
141
|
+
* );
|
|
142
|
+
*/
|
|
143
|
+
del(
|
|
144
|
+
query: string | DocumentNode,
|
|
145
|
+
variables?: Record<string, unknown>,
|
|
146
|
+
ctx?: CacheContext,
|
|
147
|
+
shouldRemoveAll?: boolean
|
|
148
|
+
): Promise<void>;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Clear all cache entries for a tenant
|
|
152
|
+
* Useful when tenant data changes significantly
|
|
153
|
+
*
|
|
154
|
+
* @param tenantId - Tenant ID to clear cache for
|
|
155
|
+
* @returns Promise resolving to count of deleted entries
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* // Clear all tenant cache on major update
|
|
159
|
+
* await cacheManager.clearTenant('tenant-123');
|
|
160
|
+
*/
|
|
161
|
+
clearTenant(tenantId: string): Promise<number>;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Clear all cache entries for a user
|
|
165
|
+
* Useful when user permissions or data changes
|
|
166
|
+
*
|
|
167
|
+
* @param userId - User ID to clear cache for
|
|
168
|
+
* @param tenantId - Optional tenant ID to scope the clear operation
|
|
169
|
+
* @returns Promise resolving to count of deleted entries
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* // Clear user cache on permission change
|
|
173
|
+
* await cacheManager.clearUser('user-456', 'tenant-123');
|
|
174
|
+
*/
|
|
175
|
+
clearUser(userId: string, tenantId?: string): Promise<number>;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Clear all cache entries matching a pattern
|
|
179
|
+
* Advanced operation for custom cache invalidation strategies
|
|
180
|
+
*
|
|
181
|
+
* @param pattern - Redis pattern to match
|
|
182
|
+
* @returns Promise resolving to count of deleted entries
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* // Clear all product caches
|
|
186
|
+
* await cacheManager.clearPattern('*:getProduct:*');
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* // Clear all admin queries
|
|
190
|
+
* await cacheManager.clearPattern('APP:tenant-1:*:admin*:*');
|
|
191
|
+
*/
|
|
192
|
+
clearPattern(pattern: string): Promise<number>;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Get cache statistics
|
|
196
|
+
* Useful for monitoring cache performance
|
|
197
|
+
*
|
|
198
|
+
* @param tenantId - Optional tenant ID to scope statistics
|
|
199
|
+
* @returns Promise resolving to cache statistics
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* // Get overall cache stats
|
|
203
|
+
* const stats = await cacheManager.getStats();
|
|
204
|
+
* console.log(`Cache keys: ${stats.totalKeys}`);
|
|
205
|
+
* console.log(`Memory used: ${stats.memoryUsage}`);
|
|
206
|
+
*/
|
|
207
|
+
getStats(tenantId?: string): Promise<{
|
|
208
|
+
totalKeys: number;
|
|
209
|
+
memoryUsage: number;
|
|
210
|
+
hitRate?: number;
|
|
211
|
+
}>;
|
|
212
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/**
|
|
3
|
+
* @file IRedisKeyBuilder.ts
|
|
4
|
+
* @description Defines the IRedisKeyBuilder interface for standardized Redis key management.
|
|
5
|
+
* This interface ensures consistent key formatting across the application with proper sanitization,
|
|
6
|
+
* tenant isolation, and namespace organization.
|
|
7
|
+
*
|
|
8
|
+
* The key builder enforces a standard format: <APP_NAME>:<tenantId>:<namespace>:<segments>
|
|
9
|
+
* This structure provides:
|
|
10
|
+
* - Multi-tenant isolation through tenantId
|
|
11
|
+
* - Organized key spaces through namespaces
|
|
12
|
+
* - Hierarchical structure through segments
|
|
13
|
+
* - Automatic sanitization of special characters
|
|
14
|
+
*
|
|
15
|
+
* Key features:
|
|
16
|
+
* - Standardized key format across the application
|
|
17
|
+
* - Automatic sanitization of pipes, spaces, control characters
|
|
18
|
+
* - Support for wildcard patterns for bulk operations
|
|
19
|
+
* - Key validation utilities
|
|
20
|
+
* - Pattern escaping for exact matching
|
|
21
|
+
*
|
|
22
|
+
* This pattern helps prevent key collisions, makes debugging easier, and enables
|
|
23
|
+
* efficient bulk operations through pattern matching.
|
|
24
|
+
*
|
|
25
|
+
* @see RedisKeyOptions - Configuration for key building
|
|
26
|
+
* @see RedisNamespace - Standard namespaces for key organization
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import { RedisKeyOptions } from './redisCommonTypes';
|
|
30
|
+
|
|
31
|
+
export interface IRedisKeyBuilder {
|
|
32
|
+
/**
|
|
33
|
+
* Build a standardized Redis key with proper formatting and sanitization
|
|
34
|
+
*
|
|
35
|
+
* Format: <APP_NAME>:<tenantId>:<namespace>:<segments...>
|
|
36
|
+
*
|
|
37
|
+
* @param options - Key building options including tenant, namespace, and segments
|
|
38
|
+
* @returns Properly formatted and sanitized Redis key
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* // Build a cache key for user profile
|
|
42
|
+
* const key = keyBuilder.buildKey({
|
|
43
|
+
* tenantId: 'tenant-123',
|
|
44
|
+
* namespace: RedisNamespace.CACHE,
|
|
45
|
+
* segments: ['user', 'profile', userId]
|
|
46
|
+
* });
|
|
47
|
+
* // Result: "APP_NAME:tenant-123:cache:user:profile:user-456"
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* // Build a session key
|
|
51
|
+
* const sessionKey = keyBuilder.buildKey({
|
|
52
|
+
* tenantId: 'tenant-123',
|
|
53
|
+
* userId: 'user-456',
|
|
54
|
+
* namespace: RedisNamespace.SESSION,
|
|
55
|
+
* segments: [sessionId]
|
|
56
|
+
* });
|
|
57
|
+
* // Result: "APP_NAME:tenant-123:user-456:session:session-789"
|
|
58
|
+
*/
|
|
59
|
+
buildKey(options: RedisKeyOptions): string;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Build a Redis key pattern for wildcard matching
|
|
63
|
+
* Useful for bulk operations like deleting all keys matching a pattern
|
|
64
|
+
*
|
|
65
|
+
* @param options - Key building options, segments can include wildcards (*)
|
|
66
|
+
* @returns Redis key pattern with wildcards
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* // Pattern to match all user cache keys for a tenant
|
|
70
|
+
* const pattern = keyBuilder.buildPattern({
|
|
71
|
+
* tenantId: 'tenant-123',
|
|
72
|
+
* namespace: RedisNamespace.CACHE,
|
|
73
|
+
* segments: ['user', '*']
|
|
74
|
+
* });
|
|
75
|
+
* // Result: "APP_NAME:tenant-123:cache:user:*"
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* // Pattern to match all keys for a namespace
|
|
79
|
+
* const allCachePattern = keyBuilder.buildPattern({
|
|
80
|
+
* tenantId: 'tenant-123',
|
|
81
|
+
* namespace: RedisNamespace.CACHE,
|
|
82
|
+
* segments: ['*']
|
|
83
|
+
* });
|
|
84
|
+
*/
|
|
85
|
+
buildPattern(options: RedisKeyOptions): string;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Sanitize a key component to ensure it's valid and safe
|
|
89
|
+
* Removes/replaces special characters that could cause issues
|
|
90
|
+
*
|
|
91
|
+
* - Replaces spaces/tabs/newlines with underscores
|
|
92
|
+
* - Replaces pipes (|) with hyphens (for Auth0 userIds: auth0|123 → auth0-123)
|
|
93
|
+
* - Removes control characters
|
|
94
|
+
* - Removes quotes and backslashes
|
|
95
|
+
*
|
|
96
|
+
* @param component - Key component to sanitize
|
|
97
|
+
* @returns Sanitized component
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* // Sanitize Auth0 userId
|
|
101
|
+
* const sanitized = keyBuilder.sanitize('auth0|123456');
|
|
102
|
+
* // Result: "auth0-123456"
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* // Sanitize filename with spaces
|
|
106
|
+
* const sanitized = keyBuilder.sanitize('my file.txt');
|
|
107
|
+
* // Result: "my_file.txt"
|
|
108
|
+
*/
|
|
109
|
+
sanitize(component: string): string;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Validate if a string is a valid Redis key
|
|
113
|
+
* Checks for empty strings, excessive length, and invalid characters
|
|
114
|
+
*
|
|
115
|
+
* @param key - Key to validate
|
|
116
|
+
* @returns True if key is valid, false otherwise
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* // Validate a key
|
|
120
|
+
* const isValid = keyBuilder.isValidKey('APP:tenant:cache:user:profile');
|
|
121
|
+
* // Result: true
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* // Invalid key with spaces
|
|
125
|
+
* const isValid = keyBuilder.isValidKey('APP tenant cache');
|
|
126
|
+
* // Result: false
|
|
127
|
+
*/
|
|
128
|
+
isValidKey(key: string): boolean;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Escape Redis pattern special characters for exact matching
|
|
132
|
+
* Useful when you want to search for keys containing wildcards literally
|
|
133
|
+
*
|
|
134
|
+
* Escapes: * ? [ ] ^ \
|
|
135
|
+
*
|
|
136
|
+
* @param pattern - Pattern to escape
|
|
137
|
+
* @returns Escaped pattern
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* // Escape wildcards for literal search
|
|
141
|
+
* const escaped = keyBuilder.escapePattern('file*.txt');
|
|
142
|
+
* // Result: "file\\*.txt"
|
|
143
|
+
*/
|
|
144
|
+
escapePattern(pattern: string): string;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Parse a Redis key into its components
|
|
148
|
+
* Useful for debugging and key analysis
|
|
149
|
+
*
|
|
150
|
+
* @param key - Redis key to parse
|
|
151
|
+
* @returns Object with parsed components (appName, tenantId, namespace, segments)
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* const parsed = keyBuilder.parseKey('APP:tenant-123:cache:user:profile');
|
|
155
|
+
* // Result: {
|
|
156
|
+
* // appName: 'APP',
|
|
157
|
+
* // tenantId: 'tenant-123',
|
|
158
|
+
* // namespace: 'cache',
|
|
159
|
+
* // segments: ['user', 'profile']
|
|
160
|
+
* // }
|
|
161
|
+
*/
|
|
162
|
+
parseKey(key: string): {
|
|
163
|
+
appName: string;
|
|
164
|
+
tenantId: string;
|
|
165
|
+
namespace: string;
|
|
166
|
+
segments: string[];
|
|
167
|
+
userId?: string;
|
|
168
|
+
};
|
|
169
|
+
}
|