@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.
Files changed (52) hide show
  1. package/lib/containers/container.d.ts +2 -0
  2. package/lib/containers/container.js +3 -0
  3. package/lib/containers/container.js.map +1 -0
  4. package/lib/containers/index.d.ts +1 -0
  5. package/lib/core/index.d.ts +3 -0
  6. package/lib/core/ioredis.d.ts +15 -0
  7. package/lib/core/ioredis.js +27 -0
  8. package/lib/core/ioredis.js.map +1 -0
  9. package/lib/core/keyBuilder/generate-query-cache-key.d.ts +57 -0
  10. package/lib/core/keyBuilder/generate-query-cache-key.js +82 -0
  11. package/lib/core/keyBuilder/generate-query-cache-key.js.map +1 -0
  12. package/lib/core/keyBuilder/index.d.ts +18 -0
  13. package/lib/core/keyBuilder/index.js +20 -0
  14. package/lib/core/keyBuilder/index.js.map +1 -0
  15. package/lib/core/keyBuilder/redis-key-builder.d.ts +152 -0
  16. package/lib/core/keyBuilder/redis-key-builder.js +181 -0
  17. package/lib/core/keyBuilder/redis-key-builder.js.map +1 -0
  18. package/lib/core/keyBuilder/sanitize-redis-key.d.ts +118 -0
  19. package/lib/core/keyBuilder/sanitize-redis-key.js +115 -0
  20. package/lib/core/keyBuilder/sanitize-redis-key.js.map +1 -0
  21. package/lib/core/upstash-redis.d.ts +14 -0
  22. package/lib/core/upstash-redis.js +23 -0
  23. package/lib/core/upstash-redis.js.map +1 -0
  24. package/lib/graphql/schema/base-services.graphql +134 -0
  25. package/lib/index.d.ts +2 -1
  26. package/lib/index.js +1 -3
  27. package/lib/index.js.map +1 -0
  28. package/lib/interfaces/index.d.ts +1 -6
  29. package/lib/interfaces/redis.d.ts +11 -0
  30. package/lib/module.d.ts +2 -0
  31. package/lib/module.js +4 -0
  32. package/lib/module.js.map +1 -0
  33. package/lib/services/RedisCacheManager.d.ts +77 -0
  34. package/lib/services/RedisCacheManager.js +177 -0
  35. package/lib/services/RedisCacheManager.js.map +1 -0
  36. package/lib/services/index.d.ts +1 -5
  37. package/lib/templates/constants/SERVER_TYPES.ts.template +0 -1
  38. package/lib/templates/repositories/IRedisKeyBuilder.ts.template +4 -4
  39. package/lib/templates/repositories/redisCommonTypes.ts.template +2 -163
  40. package/lib/templates/{repositories/IRedisCacheManager.ts.template → services/RedisCacheManager.ts.template} +7 -7
  41. package/package.json +8 -7
  42. package/lib/interfaces/cache-manager.d.ts +0 -28
  43. package/lib/interfaces/redis-key-options.d.ts +0 -35
  44. package/lib/interfaces/redis-key-options.js +0 -17
  45. package/lib/interfaces/storage-backend.d.ts +0 -17
  46. package/lib/templates/repositories/IRedisService.ts.template +0 -236
  47. package/lib/templates/repositories/IRedisStorageBackend.ts.template +0 -229
  48. package/lib/utils/index.d.ts +0 -5
  49. package/lib/utils/redis-key-builder.d.ts +0 -32
  50. package/lib/utils/redis-key-builder.js +0 -68
  51. package/lib/utils/redis-key-sanitizer.d.ts +0 -30
  52. 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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"}
@@ -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 RedisKeyOptions - Configuration for key building
25
+ * @see IRedisKeyOptions - Configuration for key building
26
26
  * @see RedisNamespace - Standard namespaces for key organization
27
27
  */
28
28
 
29
- import { RedisKeyOptions } from './redisCommonTypes';
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: RedisKeyOptions): string;
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: RedisKeyOptions): string;
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
- * Key components include:
9
- * - RedisKeyOptions: Configuration for building standardized Redis keys
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 CachePolicy - For cache TTL and scope configuration
28
- * @see CacheContext - For tenant/user isolation
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 { CacheContext, CachePolicy } from './redisCommonTypes';
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: CacheContext
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: CacheContext,
101
- cachePolicy?: 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?: CacheContext,
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.33",
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.15"
27
+ "@common-stack/core": "8.2.5-alpha.35"
28
28
  },
29
29
  "devDependencies": {
30
- "common": "8.2.5-alpha.15",
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": "5745649eba49ac589b9ace8c55378b6cbe130096"
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
- }