@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
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import {__decorate,__param,__metadata}from'tslib';import {isHashLikeTenantId,sanitizeRedisKeyComponent}from'../core/keyBuilder/sanitize-redis-key.js';import {generateQueryCacheKey}from'../core/keyBuilder/generate-query-cache-key.js';import {print}from'graphql';import {injectable,inject}from'inversify';/**
|
|
2
|
+
* @file RedisCacheManager.ts
|
|
3
|
+
* @description Redis-based cache manager for GraphQL query caching
|
|
4
|
+
*
|
|
5
|
+
* This implementation provides sophisticated caching for GraphQL operations with:
|
|
6
|
+
* - Automatic query hashing for cache keys
|
|
7
|
+
* - Multi-tenant and user isolation
|
|
8
|
+
* - Wildcard-based cache invalidation
|
|
9
|
+
* - TTL-based expiration
|
|
10
|
+
* - Automatic key sanitization (handles Auth0 userIds with pipes)
|
|
11
|
+
*
|
|
12
|
+
* Migrated from @adminide-stack/platform-server to be shared across applications
|
|
13
|
+
*/
|
|
14
|
+
var RedisCacheManager_1;
|
|
15
|
+
/**
|
|
16
|
+
* Redis Cache Manager implementation
|
|
17
|
+
*
|
|
18
|
+
* Provides GraphQL query caching with automatic key generation and invalidation
|
|
19
|
+
*/
|
|
20
|
+
let RedisCacheManager = RedisCacheManager_1 = class RedisCacheManager {
|
|
21
|
+
redisClient;
|
|
22
|
+
logger;
|
|
23
|
+
constructor(redisClient, logger) {
|
|
24
|
+
this.redisClient = redisClient;
|
|
25
|
+
if (logger) {
|
|
26
|
+
this.logger = logger.child ? logger.child({ className: RedisCacheManager_1.name }) : logger;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Delete cached data for a GraphQL query
|
|
31
|
+
*
|
|
32
|
+
* @param query - GraphQL query to invalidate
|
|
33
|
+
* @param variables - Optional variables (if omitted, clears all variants)
|
|
34
|
+
* @param ctx - Cache context for tenant/user isolation
|
|
35
|
+
* @param shouldRemoveAll - If true, removes all related cache keys
|
|
36
|
+
*/
|
|
37
|
+
async del(query, variables, ctx, shouldRemoveAll = false) {
|
|
38
|
+
const cacheKey = this.getCacheKey(query, variables ?? {}, ctx);
|
|
39
|
+
// If variables provided, delete exact match
|
|
40
|
+
if (variables && Object.keys(variables).length > 0) {
|
|
41
|
+
this.log('debug', `Deleting ${cacheKey} from redis`);
|
|
42
|
+
await this.redisClient.del(cacheKey);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// Build wildcard pattern
|
|
46
|
+
const keysWithWildCard = shouldRemoveAll
|
|
47
|
+
? this.getWildCardQueryKey(query, ctx)
|
|
48
|
+
: `${cacheKey.substring(0, cacheKey.lastIndexOf(':'))}:*`;
|
|
49
|
+
const cacheKeys = await this.redisClient.keys(keysWithWildCard);
|
|
50
|
+
this.log('debug', `Found ${cacheKeys.length} keys against pattern ${keysWithWildCard}`);
|
|
51
|
+
if (cacheKeys.length) {
|
|
52
|
+
this.log('debug', `Deleting ${cacheKeys.length} keys from redis`);
|
|
53
|
+
await this.redisClient.del(...cacheKeys);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get cached data for a GraphQL query
|
|
58
|
+
*
|
|
59
|
+
* @param query - GraphQL query
|
|
60
|
+
* @param variables - Query variables
|
|
61
|
+
* @param ctx - Cache context
|
|
62
|
+
* @returns Cached data or null if cache miss
|
|
63
|
+
*/
|
|
64
|
+
async get(query, variables, ctx) {
|
|
65
|
+
const cacheKey = this.getCacheKey(query, variables, ctx);
|
|
66
|
+
const cacheResponse = await this.redisClient.get(cacheKey);
|
|
67
|
+
if (cacheResponse) {
|
|
68
|
+
try {
|
|
69
|
+
const { data } = JSON.parse(JSON.parse(cacheResponse)?.value) ?? {};
|
|
70
|
+
const queryName = this.getQueryName(query);
|
|
71
|
+
this.log('debug', `Found cache for ${cacheKey}`);
|
|
72
|
+
return data?.[queryName] ?? null;
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
this.log('warn', `Failed to parse cache data for ${cacheKey}:`, error);
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
this.log('debug', `No cache found for key ${cacheKey}`);
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Set cached data for a GraphQL query
|
|
84
|
+
*
|
|
85
|
+
* @param query - GraphQL query
|
|
86
|
+
* @param variables - Query variables
|
|
87
|
+
* @param data - Data to cache
|
|
88
|
+
* @param ctx - Cache context
|
|
89
|
+
* @param cachePolicy - Cache policy (TTL, scope)
|
|
90
|
+
*/
|
|
91
|
+
async set(query, variables, data, ctx, cachePolicy = { maxAge: 86400, scope: 'PUBLIC' }) {
|
|
92
|
+
const cacheKey = this.getCacheKey(query, variables, ctx);
|
|
93
|
+
const cacheTime = Date.now();
|
|
94
|
+
// Ensure maxAge is not negative or zero
|
|
95
|
+
const maxAge = Math.max(1, cachePolicy.maxAge);
|
|
96
|
+
if (cachePolicy.maxAge <= 0) {
|
|
97
|
+
this.log('warn', `Invalid maxAge (${cachePolicy.maxAge}) for cache key ${cacheKey}, using minimum value of 1 second`);
|
|
98
|
+
}
|
|
99
|
+
this.log('debug', `Set cache for key ${cacheKey} with maxAge ${maxAge}`);
|
|
100
|
+
await this.redisClient.set(cacheKey, JSON.stringify({
|
|
101
|
+
value: JSON.stringify({
|
|
102
|
+
data: { [this.getQueryName(query)]: data },
|
|
103
|
+
cachePolicy: { ...cachePolicy, maxAge },
|
|
104
|
+
cacheTime,
|
|
105
|
+
}),
|
|
106
|
+
expires: cacheTime + maxAge * 1000,
|
|
107
|
+
}).trim(), 'EX', maxAge);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Extract query name from GraphQL query
|
|
111
|
+
*/
|
|
112
|
+
getQueryName(query) {
|
|
113
|
+
const queryStr = typeof query === 'string' ? query : print(query);
|
|
114
|
+
const [, queryName] = queryStr?.match(/{\s*(\w+)/) ?? [];
|
|
115
|
+
return queryName;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Build wildcard pattern for query invalidation
|
|
119
|
+
*/
|
|
120
|
+
getWildCardQueryKey(query, ctx) {
|
|
121
|
+
const queryStr = typeof query === 'string' ? query : print(query);
|
|
122
|
+
const [, queryName] = queryStr?.match(/{\s*(\w+)/) ?? [];
|
|
123
|
+
const { tenantId } = ctx || {};
|
|
124
|
+
// Build pattern without namespace - just APP_NAME:tenantId:segments
|
|
125
|
+
const appName = this.getAppName();
|
|
126
|
+
const sanitizedTenantId = tenantId || 'default';
|
|
127
|
+
return `${appName}:${sanitizedTenantId}:*:${queryName || '*'}:*`;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Generate cache key for a GraphQL query
|
|
131
|
+
*
|
|
132
|
+
* Format: APP_NAME:tenantId:userId:queryName:queryHash:variablesHash
|
|
133
|
+
*/
|
|
134
|
+
getCacheKey(query, variables, ctx) {
|
|
135
|
+
// Generate the legacy key WITHOUT tenantId/userId since we'll add them via manual construction
|
|
136
|
+
const legacyKey = generateQueryCacheKey({
|
|
137
|
+
query,
|
|
138
|
+
variables,
|
|
139
|
+
logger: this.logger,
|
|
140
|
+
});
|
|
141
|
+
// Build key without namespace - format: APP_NAME:tenantId:userId:legacyKey
|
|
142
|
+
const appName = this.getAppName();
|
|
143
|
+
// Validate tenantId - if it looks like a hash (all hex, 24+ chars), use 'default'
|
|
144
|
+
let tenantId = ctx?.tenantId || 'default';
|
|
145
|
+
if (isHashLikeTenantId(tenantId)) {
|
|
146
|
+
this.log('warn', `TenantId appears to be a hash (${tenantId.substring(0, 16)}...), using "default" instead`);
|
|
147
|
+
tenantId = 'default';
|
|
148
|
+
}
|
|
149
|
+
const userId = ctx?.userId || 'anonymous';
|
|
150
|
+
// Sanitize components (handles Auth0 userIds like "auth0|123")
|
|
151
|
+
const sanitizedAppName = sanitizeRedisKeyComponent(appName);
|
|
152
|
+
const sanitizedTenantId = sanitizeRedisKeyComponent(tenantId);
|
|
153
|
+
const sanitizedUserId = sanitizeRedisKeyComponent(userId);
|
|
154
|
+
return `${sanitizedAppName}:${sanitizedTenantId}:${sanitizedUserId}:${legacyKey}`;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Get application name for key prefix
|
|
158
|
+
* Override this method to provide custom app name
|
|
159
|
+
*/
|
|
160
|
+
getAppName() {
|
|
161
|
+
return process.env.APP_NAME || 'COMMON_STACK';
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Log helper
|
|
165
|
+
*/
|
|
166
|
+
log(level, message, ...args) {
|
|
167
|
+
if (this.logger && typeof this.logger[level] === 'function') {
|
|
168
|
+
this.logger[level](message, ...args);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
RedisCacheManager = RedisCacheManager_1 = __decorate([
|
|
173
|
+
injectable(),
|
|
174
|
+
__param(0, inject('REDIS_CLIENT')),
|
|
175
|
+
__param(1, inject('LOGGER')),
|
|
176
|
+
__metadata("design:paramtypes", [Function, Object])
|
|
177
|
+
], RedisCacheManager);export{RedisCacheManager};//# sourceMappingURL=RedisCacheManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RedisCacheManager.js","sources":["../../src/services/RedisCacheManager.ts"],"sourcesContent":["/**\n * @file RedisCacheManager.ts\n * @description Redis-based cache manager for GraphQL query caching\n *\n * This implementation provides sophisticated caching for GraphQL operations with:\n * - Automatic query hashing for cache keys\n * - Multi-tenant and user isolation\n * - Wildcard-based cache invalidation\n * - TTL-based expiration\n * - Automatic key sanitization (handles Auth0 userIds with pipes)\n *\n * Migrated from @adminide-stack/platform-server to be shared across applications\n */\n\nimport { generateQueryCacheKey, sanitizeRedisKeyComponent, isHashLikeTenantId } from '../core/keyBuilder';\nimport type { Redis } from 'ioredis';\nimport { print } from 'graphql';\nimport type { DocumentNode } from 'graphql';\nimport { injectable, inject } from 'inversify';\nimport type { ICacheContext, ICachePolicy, IRedisCacheManager } from 'common/server';\n\n/**\n * Redis Cache Manager implementation\n *\n * Provides GraphQL query caching with automatic key generation and invalidation\n */\n@injectable()\nexport class RedisCacheManager implements IRedisCacheManager {\n protected logger?: any;\n\n constructor(\n @inject('REDIS_CLIENT')\n protected readonly redisClient: Redis,\n @inject('LOGGER')\n logger?: any,\n ) {\n if (logger) {\n this.logger = logger.child ? logger.child({ className: RedisCacheManager.name }) : logger;\n }\n }\n\n /**\n * Delete cached data for a GraphQL query\n *\n * @param query - GraphQL query to invalidate\n * @param variables - Optional variables (if omitted, clears all variants)\n * @param ctx - Cache context for tenant/user isolation\n * @param shouldRemoveAll - If true, removes all related cache keys\n */\n async del(\n query: string | DocumentNode,\n variables?: Record<string, unknown>,\n ctx?: ICacheContext,\n shouldRemoveAll = false,\n ): Promise<void> {\n const cacheKey = this.getCacheKey(query, variables ?? {}, ctx);\n\n // If variables provided, delete exact match\n if (variables && Object.keys(variables).length > 0) {\n this.log('debug', `Deleting ${cacheKey} from redis`);\n await this.redisClient.del(cacheKey);\n return;\n }\n\n // Build wildcard pattern\n const keysWithWildCard = shouldRemoveAll\n ? this.getWildCardQueryKey(query, ctx)\n : `${cacheKey.substring(0, cacheKey.lastIndexOf(':'))}:*`;\n\n const cacheKeys = await this.redisClient.keys(keysWithWildCard);\n this.log('debug', `Found ${cacheKeys.length} keys against pattern ${keysWithWildCard}`);\n\n if (cacheKeys.length) {\n this.log('debug', `Deleting ${cacheKeys.length} keys from redis`);\n await this.redisClient.del(...cacheKeys);\n }\n }\n\n /**\n * Get cached data for a GraphQL query\n *\n * @param query - GraphQL query\n * @param variables - Query variables\n * @param ctx - Cache context\n * @returns Cached data or null if cache miss\n */\n async get<T>(\n query: string | DocumentNode,\n variables: Record<string, unknown>,\n ctx: ICacheContext,\n ): Promise<T | null> {\n const cacheKey = this.getCacheKey(query, variables, ctx);\n const cacheResponse = await this.redisClient.get(cacheKey);\n\n if (cacheResponse) {\n try {\n const { data } = JSON.parse(JSON.parse(cacheResponse)?.value) ?? {};\n const queryName = this.getQueryName(query);\n this.log('debug', `Found cache for ${cacheKey}`);\n return data?.[queryName] ?? null;\n } catch (error) {\n this.log('warn', `Failed to parse cache data for ${cacheKey}:`, error);\n return null;\n }\n }\n\n this.log('debug', `No cache found for key ${cacheKey}`);\n return null;\n }\n\n /**\n * Set cached data for a GraphQL query\n *\n * @param query - GraphQL query\n * @param variables - Query variables\n * @param data - Data to cache\n * @param ctx - Cache context\n * @param cachePolicy - Cache policy (TTL, scope)\n */\n async set<T>(\n query: string | DocumentNode,\n variables: Record<string, unknown>,\n data: T,\n ctx: ICacheContext,\n cachePolicy: ICachePolicy = { maxAge: 86400, scope: 'PUBLIC' },\n ): Promise<void> {\n const cacheKey = this.getCacheKey(query, variables, ctx);\n const cacheTime = Date.now();\n\n // Ensure maxAge is not negative or zero\n const maxAge = Math.max(1, cachePolicy.maxAge);\n\n if (cachePolicy.maxAge <= 0) {\n this.log(\n 'warn',\n `Invalid maxAge (${cachePolicy.maxAge}) for cache key ${cacheKey}, using minimum value of 1 second`,\n );\n }\n\n this.log('debug', `Set cache for key ${cacheKey} with maxAge ${maxAge}`);\n\n await this.redisClient.set(\n cacheKey,\n JSON.stringify({\n value: JSON.stringify({\n data: { [this.getQueryName(query)]: data },\n cachePolicy: { ...cachePolicy, maxAge },\n cacheTime,\n }),\n expires: cacheTime + maxAge * 1000,\n }).trim(),\n 'EX',\n maxAge,\n );\n }\n\n /**\n * Extract query name from GraphQL query\n */\n private getQueryName(query: string | DocumentNode): string {\n const queryStr = typeof query === 'string' ? query : print(query);\n const [, queryName] = queryStr?.match(/{\\s*(\\w+)/) ?? [];\n return queryName;\n }\n\n /**\n * Build wildcard pattern for query invalidation\n */\n private getWildCardQueryKey(query: string | DocumentNode, ctx?: ICacheContext): string {\n const queryStr = typeof query === 'string' ? query : print(query);\n const [, queryName] = queryStr?.match(/{\\s*(\\w+)/) ?? [];\n const { tenantId } = ctx || {};\n\n // Build pattern without namespace - just APP_NAME:tenantId:segments\n const appName = this.getAppName();\n const sanitizedTenantId = tenantId || 'default';\n return `${appName}:${sanitizedTenantId}:*:${queryName || '*'}:*`;\n }\n\n /**\n * Generate cache key for a GraphQL query\n *\n * Format: APP_NAME:tenantId:userId:queryName:queryHash:variablesHash\n */\n private getCacheKey(query: string | DocumentNode, variables: Record<string, unknown>, ctx?: ICacheContext): string {\n // Generate the legacy key WITHOUT tenantId/userId since we'll add them via manual construction\n const legacyKey = generateQueryCacheKey({\n query,\n variables,\n logger: this.logger,\n });\n\n // Build key without namespace - format: APP_NAME:tenantId:userId:legacyKey\n const appName = this.getAppName();\n\n // Validate tenantId - if it looks like a hash (all hex, 24+ chars), use 'default'\n let tenantId = ctx?.tenantId || 'default';\n if (isHashLikeTenantId(tenantId)) {\n this.log(\n 'warn',\n `TenantId appears to be a hash (${tenantId.substring(0, 16)}...), using \"default\" instead`,\n );\n tenantId = 'default';\n }\n\n const userId = ctx?.userId || 'anonymous';\n\n // Sanitize components (handles Auth0 userIds like \"auth0|123\")\n const sanitizedAppName = sanitizeRedisKeyComponent(appName);\n const sanitizedTenantId = sanitizeRedisKeyComponent(tenantId);\n const sanitizedUserId = sanitizeRedisKeyComponent(userId);\n\n return `${sanitizedAppName}:${sanitizedTenantId}:${sanitizedUserId}:${legacyKey}`;\n }\n\n /**\n * Get application name for key prefix\n * Override this method to provide custom app name\n */\n protected getAppName(): string {\n return process.env.APP_NAME || 'COMMON_STACK';\n }\n\n /**\n * Log helper\n */\n private log(level: string, message: string, ...args: any[]): void {\n if (this.logger && typeof this.logger[level] === 'function') {\n this.logger[level](message, ...args);\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
package/lib/services/index.d.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Redis service implementations
|
|
3
|
-
*
|
|
4
|
-
* Note: Actual implementations will be migrated from:
|
|
5
|
-
* - @adminide-stack/platform-server/RedisCacheManager
|
|
6
|
-
* - @adminide-stack/auth0-server-core/RedisStorageBackend
|
|
7
3
|
*/
|
|
8
|
-
export
|
|
4
|
+
export * from './RedisCacheManager';
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export const SERVER_TYPES = {
|
|
2
2
|
RedisClient: Symbol.for('RedisClient'),
|
|
3
3
|
RedisCacheManager: Symbol.for('RedisCacheManager'),
|
|
4
|
-
RedisStorageBackend: Symbol.for('RedisStorageBackend'),
|
|
5
4
|
RedisConnectionPool: Symbol.for('RedisConnectionPool'),
|
|
6
5
|
RedisKeyBuilder: Symbol.for('RedisKeyBuilder'),
|
|
7
6
|
};
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
* This pattern helps prevent key collisions, makes debugging easier, and enables
|
|
23
23
|
* efficient bulk operations through pattern matching.
|
|
24
24
|
*
|
|
25
|
-
* @see
|
|
25
|
+
* @see IRedisKeyOptions - Configuration for key building
|
|
26
26
|
* @see RedisNamespace - Standard namespaces for key organization
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
import {
|
|
29
|
+
import { IRedisKeyOptions } from 'common/server';
|
|
30
30
|
|
|
31
31
|
export interface IRedisKeyBuilder {
|
|
32
32
|
/**
|
|
@@ -56,7 +56,7 @@ export interface IRedisKeyBuilder {
|
|
|
56
56
|
* });
|
|
57
57
|
* // Result: "APP_NAME:tenant-123:user-456:session:session-789"
|
|
58
58
|
*/
|
|
59
|
-
buildKey(options:
|
|
59
|
+
buildKey(options: IRedisKeyOptions): string;
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* Build a Redis key pattern for wildcard matching
|
|
@@ -82,7 +82,7 @@ export interface IRedisKeyBuilder {
|
|
|
82
82
|
* segments: ['*']
|
|
83
83
|
* });
|
|
84
84
|
*/
|
|
85
|
-
buildPattern(options:
|
|
85
|
+
buildPattern(options: IRedisKeyOptions): string;
|
|
86
86
|
|
|
87
87
|
/**
|
|
88
88
|
* Sanitize a key component to ensure it's valid and safe
|
|
@@ -5,109 +5,15 @@
|
|
|
5
5
|
* These types provide a standardized approach to working with Redis operations, including
|
|
6
6
|
* key management, caching, and storage patterns.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* - RedisNamespace: Enum for organizing keys into logical namespaces
|
|
11
|
-
* - CacheContext: Context information for cache operations (tenant, user, org)
|
|
12
|
-
* - CachePolicy: Configuration for cache TTL and scope
|
|
13
|
-
* - RedisValue: Union type for values that can be stored in Redis
|
|
14
|
-
* - RedisHashValue: Type for Redis hash field values
|
|
15
|
-
* - RedisScanOptions: Options for scanning Redis keys
|
|
16
|
-
*
|
|
17
|
-
* These types ensure consistency across Redis operations, providing type safety and
|
|
18
|
-
* clear contracts for data caching and storage throughout the application.
|
|
8
|
+
* Most types are generated from GraphQL schema via codegen.
|
|
9
|
+
* Additional runtime types (RedisValue, RedisHashValue) are defined here.
|
|
19
10
|
*
|
|
20
11
|
* @see IRedisCacheManager - Cache manager interface using these types
|
|
21
12
|
* @see IRedisStorageBackend - Storage backend interface using these types
|
|
22
13
|
* @see IRedisKeyBuilder - Key builder interface using these types
|
|
23
14
|
*/
|
|
24
15
|
|
|
25
|
-
/**
|
|
26
|
-
* Options for building Redis keys with standardized format
|
|
27
|
-
*
|
|
28
|
-
* @property tenantId - Tenant ID for multi-tenant isolation (defaults to 'default')
|
|
29
|
-
* @property namespace - Namespace to categorize keys (e.g., 'cache', 'session', 'storage')
|
|
30
|
-
* @property segments - Additional key segments to append
|
|
31
|
-
* @property userId - Optional user ID for user-specific keys
|
|
32
|
-
*
|
|
33
|
-
* @example
|
|
34
|
-
* const keyOptions: RedisKeyOptions = {
|
|
35
|
-
* tenantId: 'tenant-123',
|
|
36
|
-
* namespace: RedisNamespace.CACHE,
|
|
37
|
-
* segments: ['user', 'profile']
|
|
38
|
-
* };
|
|
39
|
-
* // Produces key: APP_NAME:tenant-123:cache:user:profile
|
|
40
|
-
*/
|
|
41
|
-
export interface RedisKeyOptions {
|
|
42
|
-
tenantId?: string;
|
|
43
|
-
namespace: string;
|
|
44
|
-
segments: string[];
|
|
45
|
-
userId?: string;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Standard Redis namespaces for organizing keys
|
|
50
|
-
* Using namespaces helps prevent key collisions and makes bulk operations easier
|
|
51
|
-
*
|
|
52
|
-
* @example
|
|
53
|
-
* // Use namespaces to organize cache keys
|
|
54
|
-
* const cacheKey = buildRedisKey({
|
|
55
|
-
* tenantId: 'tenant-123',
|
|
56
|
-
* namespace: RedisNamespace.CACHE,
|
|
57
|
-
* segments: ['query', 'users']
|
|
58
|
-
* });
|
|
59
|
-
*/
|
|
60
|
-
export enum RedisNamespace {
|
|
61
|
-
CACHE = 'cache',
|
|
62
|
-
SESSION = 'session',
|
|
63
|
-
TENANT = 'tenant',
|
|
64
|
-
CONFIG = 'config',
|
|
65
|
-
EXTENSION = 'extension',
|
|
66
|
-
CONTRIBUTION = 'contribution',
|
|
67
|
-
STORAGE = 'storage',
|
|
68
|
-
PERMISSION = 'permission',
|
|
69
|
-
TEMP = 'temp',
|
|
70
|
-
QUEUE = 'queue',
|
|
71
|
-
LOCK = 'lock',
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Context for cache operations
|
|
76
|
-
* Provides tenant, user, and organization isolation for cached data
|
|
77
|
-
*
|
|
78
|
-
* @property tenantId - Tenant identifier for multi-tenant applications
|
|
79
|
-
* @property userId - User identifier for user-specific caching
|
|
80
|
-
* @property orgId - Organization identifier for org-level caching
|
|
81
|
-
*
|
|
82
|
-
* @example
|
|
83
|
-
* const ctx: CacheContext = {
|
|
84
|
-
* tenantId: 'tenant-123',
|
|
85
|
-
* userId: 'user-456',
|
|
86
|
-
* orgId: 'org-789'
|
|
87
|
-
* };
|
|
88
|
-
*/
|
|
89
|
-
export interface CacheContext {
|
|
90
|
-
tenantId?: string;
|
|
91
|
-
userId?: string;
|
|
92
|
-
orgId?: string;
|
|
93
|
-
}
|
|
94
16
|
|
|
95
|
-
/**
|
|
96
|
-
* Cache policy for controlling cache behavior
|
|
97
|
-
*
|
|
98
|
-
* @property maxAge - Maximum age in seconds (TTL)
|
|
99
|
-
* @property scope - Cache scope (PUBLIC, PRIVATE, etc.)
|
|
100
|
-
*
|
|
101
|
-
* @example
|
|
102
|
-
* const policy: CachePolicy = {
|
|
103
|
-
* maxAge: 3600, // 1 hour
|
|
104
|
-
* scope: 'PRIVATE'
|
|
105
|
-
* };
|
|
106
|
-
*/
|
|
107
|
-
export interface CachePolicy {
|
|
108
|
-
maxAge: number;
|
|
109
|
-
scope?: string;
|
|
110
|
-
}
|
|
111
17
|
|
|
112
18
|
/**
|
|
113
19
|
* Union type for values that can be stored in Redis
|
|
@@ -120,70 +26,3 @@ export type RedisValue = string | number | Buffer | null;
|
|
|
120
26
|
* Hashes in Redis store field-value pairs
|
|
121
27
|
*/
|
|
122
28
|
export type RedisHashValue = Record<string, string>;
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Options for scanning Redis keys
|
|
126
|
-
* Used for iterating through keys matching a pattern
|
|
127
|
-
*
|
|
128
|
-
* @property match - Pattern to match keys (supports wildcards)
|
|
129
|
-
* @property count - Number of keys to return per iteration
|
|
130
|
-
* @property type - Optional Redis data type to filter by
|
|
131
|
-
*
|
|
132
|
-
* @example
|
|
133
|
-
* const scanOptions: RedisScanOptions = {
|
|
134
|
-
* match: 'APP:tenant-*:cache:*',
|
|
135
|
-
* count: 100,
|
|
136
|
-
* type: 'string'
|
|
137
|
-
* };
|
|
138
|
-
*/
|
|
139
|
-
export interface RedisScanOptions {
|
|
140
|
-
match?: string;
|
|
141
|
-
count?: number;
|
|
142
|
-
type?: 'string' | 'list' | 'set' | 'zset' | 'hash' | 'stream';
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Result from a Redis SCAN operation
|
|
147
|
-
*
|
|
148
|
-
* @property cursor - Next cursor position (0 means scan is complete)
|
|
149
|
-
* @property keys - Array of keys matching the scan criteria
|
|
150
|
-
*/
|
|
151
|
-
export interface RedisScanResult {
|
|
152
|
-
cursor: string;
|
|
153
|
-
keys: string[];
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Options for Redis bulk operations
|
|
158
|
-
* Used when performing operations on multiple keys
|
|
159
|
-
*
|
|
160
|
-
* @property pipeline - Whether to use Redis pipeline for batch operations
|
|
161
|
-
* @property transaction - Whether to wrap operations in a MULTI/EXEC transaction
|
|
162
|
-
*/
|
|
163
|
-
export interface RedisBulkOptions {
|
|
164
|
-
pipeline?: boolean;
|
|
165
|
-
transaction?: boolean;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Redis connection configuration
|
|
170
|
-
*
|
|
171
|
-
* @property host - Redis server host
|
|
172
|
-
* @property port - Redis server port
|
|
173
|
-
* @property password - Optional password for authentication
|
|
174
|
-
* @property db - Database number to use
|
|
175
|
-
* @property keyPrefix - Prefix to add to all keys
|
|
176
|
-
* @property maxRetriesPerRequest - Maximum retry attempts
|
|
177
|
-
* @property enableReadyCheck - Whether to check connection is ready
|
|
178
|
-
* @property lazyConnect - Whether to delay connection until first command
|
|
179
|
-
*/
|
|
180
|
-
export interface RedisConnectionConfig {
|
|
181
|
-
host?: string;
|
|
182
|
-
port?: number;
|
|
183
|
-
password?: string;
|
|
184
|
-
db?: number;
|
|
185
|
-
keyPrefix?: string;
|
|
186
|
-
maxRetriesPerRequest?: number;
|
|
187
|
-
enableReadyCheck?: boolean;
|
|
188
|
-
lazyConnect?: boolean;
|
|
189
|
-
}
|
|
@@ -24,12 +24,12 @@
|
|
|
24
24
|
* while maintaining cache correctness through intelligent invalidation strategies.
|
|
25
25
|
*
|
|
26
26
|
* @see IRedisStorageBackend - For simpler key-value storage
|
|
27
|
-
* @see
|
|
28
|
-
* @see
|
|
27
|
+
* @see ICachePolicy - For cache TTL and scope configuration
|
|
28
|
+
* @see ICacheContext - For tenant/user isolation
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
31
|
import type { DocumentNode } from 'graphql';
|
|
32
|
-
import {
|
|
32
|
+
import { ICacheContext, ICachePolicy } from 'common/server';
|
|
33
33
|
|
|
34
34
|
export interface IRedisCacheManager {
|
|
35
35
|
/**
|
|
@@ -60,7 +60,7 @@ export interface IRedisCacheManager {
|
|
|
60
60
|
get<T>(
|
|
61
61
|
query: string | DocumentNode,
|
|
62
62
|
variables: Record<string, any>,
|
|
63
|
-
ctx:
|
|
63
|
+
ctx: ICacheContext
|
|
64
64
|
): Promise<T | null>;
|
|
65
65
|
|
|
66
66
|
/**
|
|
@@ -97,8 +97,8 @@ export interface IRedisCacheManager {
|
|
|
97
97
|
query: string | DocumentNode,
|
|
98
98
|
variables: Record<string, any>,
|
|
99
99
|
data: T,
|
|
100
|
-
ctx:
|
|
101
|
-
cachePolicy?:
|
|
100
|
+
ctx: ICacheContext,
|
|
101
|
+
cachePolicy?: ICachePolicy
|
|
102
102
|
): Promise<void>;
|
|
103
103
|
|
|
104
104
|
/**
|
|
@@ -143,7 +143,7 @@ export interface IRedisCacheManager {
|
|
|
143
143
|
del(
|
|
144
144
|
query: string | DocumentNode,
|
|
145
145
|
variables?: Record<string, unknown>,
|
|
146
|
-
ctx?:
|
|
146
|
+
ctx?: ICacheContext,
|
|
147
147
|
shouldRemoveAll?: boolean
|
|
148
148
|
): Promise<void>;
|
|
149
149
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@common-stack/store-redis",
|
|
3
|
-
"version": "8.2.5-alpha.
|
|
3
|
+
"version": "8.2.5-alpha.36",
|
|
4
4
|
"description": "Redis store utilities and services for common-stack",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"author": "CDMBase LLC",
|
|
@@ -24,13 +24,14 @@
|
|
|
24
24
|
"watch": "npm run build:lib:watch"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@common-stack/core": "8.2.5-alpha.
|
|
27
|
+
"@common-stack/core": "8.2.5-alpha.35"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"common": "8.2.5-alpha.
|
|
30
|
+
"common": "8.2.5-alpha.35",
|
|
31
31
|
"ioredis": "^5.3.2"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
+
"graphql": ">=16.0.0",
|
|
34
35
|
"inversify": "*",
|
|
35
36
|
"ioredis": ">=5.0.0"
|
|
36
37
|
},
|
|
@@ -44,15 +45,15 @@
|
|
|
44
45
|
],
|
|
45
46
|
"repositories": [
|
|
46
47
|
"./${libDir}/templates/repositories/IRedisKeyBuilder.ts.template",
|
|
47
|
-
"./${libDir}/templates/repositories/IRedisStorageBackend.ts.template",
|
|
48
|
-
"./${libDir}/templates/repositories/IRedisCacheManager.ts.template",
|
|
49
|
-
"./${libDir}/templates/repositories/IRedisService.ts.template",
|
|
50
48
|
"./${libDir}/templates/repositories/redisCommonTypes.ts.template"
|
|
49
|
+
],
|
|
50
|
+
"services": [
|
|
51
|
+
"./${libDir}/templates/services/RedisCacheManager.ts.template"
|
|
51
52
|
]
|
|
52
53
|
}
|
|
53
54
|
},
|
|
54
55
|
"typescript": {
|
|
55
56
|
"definition": "lib/index.d.ts"
|
|
56
57
|
},
|
|
57
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "073ba112d0d673927cca535e7805946fe30880d4"
|
|
58
59
|
}
|
|
@@ -1,28 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
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 };
|
|
@@ -1,17 +0,0 @@
|
|
|
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
|
-
}
|