@common-stack/store-redis 8.3.1-alpha.13 → 8.3.1-alpha.15
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/core/keyBuilder/generate-query-cache-key.d.ts +39 -0
- package/lib/core/keyBuilder/generate-query-cache-key.js +46 -2
- package/lib/core/keyBuilder/generate-query-cache-key.js.map +1 -1
- package/lib/index.js +1 -1
- package/lib/module.d.ts +2 -1
- package/lib/plugins/invalidateCachePlugin.js +23 -6
- package/lib/plugins/invalidateCachePlugin.js.map +1 -1
- package/package.json +2 -2
|
@@ -19,6 +19,45 @@ export type GenerateQueryCacheKeyOptions = {
|
|
|
19
19
|
appName?: string;
|
|
20
20
|
logger?: any;
|
|
21
21
|
};
|
|
22
|
+
export type GenerateQueryCachePatternOptions = {
|
|
23
|
+
appName: string;
|
|
24
|
+
tenantId?: string;
|
|
25
|
+
userId?: string;
|
|
26
|
+
queryName: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Generates a wildcard pattern for invalidating GraphQL query cache keys
|
|
30
|
+
*
|
|
31
|
+
* This function creates patterns that match the keys generated by `generateQueryCacheKey`.
|
|
32
|
+
* Use this for cache invalidation to ensure consistent pattern matching.
|
|
33
|
+
*
|
|
34
|
+
* Key pattern format: `appName:tenantId:[userId]:queryName:*`
|
|
35
|
+
* - All components are sanitized the same way as cache key generation
|
|
36
|
+
* - Trailing wildcard matches the query hash and variables hash
|
|
37
|
+
*
|
|
38
|
+
* @param options - Pattern generation options
|
|
39
|
+
* @returns Redis pattern string for SCAN/KEYS operations
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* generateQueryCachePattern({
|
|
44
|
+
* appName: 'CDMBASE_TEST',
|
|
45
|
+
* tenantId: 'default',
|
|
46
|
+
* userId: 'auth0|123',
|
|
47
|
+
* queryName: 'pageSettings'
|
|
48
|
+
* })
|
|
49
|
+
* // Returns: 'CDMBASE_TEST:default:auth0-123:pageSettings:*'
|
|
50
|
+
*
|
|
51
|
+
* // Without userId (for public queries)
|
|
52
|
+
* generateQueryCachePattern({
|
|
53
|
+
* appName: 'CDMBASE_TEST',
|
|
54
|
+
* tenantId: 'default',
|
|
55
|
+
* queryName: 'pageSettings'
|
|
56
|
+
* })
|
|
57
|
+
* // Returns: 'CDMBASE_TEST:default:pageSettings:*'
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare const generateQueryCachePattern: ({ appName, tenantId, userId, queryName, }: GenerateQueryCachePatternOptions) => string;
|
|
22
61
|
/**
|
|
23
62
|
* Generates a cache key for GraphQL queries using standardized Redis key builder
|
|
24
63
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {createHash}from'crypto';import {print}from'graphql/language/index.js';import {buildRedisKey}from'./sanitize-redis-key.js';/**
|
|
1
|
+
import {createHash}from'crypto';import {print}from'graphql/language/index.js';import {sanitizeRedisKeyComponent,buildRedisKey}from'./sanitize-redis-key.js';/**
|
|
2
2
|
* @file generate-query-cache-key.ts
|
|
3
3
|
* @description Generates consistent cache keys for GraphQL queries
|
|
4
4
|
*
|
|
@@ -10,6 +10,50 @@ import {createHash}from'crypto';import {print}from'graphql/language/index.js';im
|
|
|
10
10
|
* - Variables are optionally hashed if provided
|
|
11
11
|
* - All components are sanitized for Redis key safety
|
|
12
12
|
*/
|
|
13
|
+
/**
|
|
14
|
+
* Generates a wildcard pattern for invalidating GraphQL query cache keys
|
|
15
|
+
*
|
|
16
|
+
* This function creates patterns that match the keys generated by `generateQueryCacheKey`.
|
|
17
|
+
* Use this for cache invalidation to ensure consistent pattern matching.
|
|
18
|
+
*
|
|
19
|
+
* Key pattern format: `appName:tenantId:[userId]:queryName:*`
|
|
20
|
+
* - All components are sanitized the same way as cache key generation
|
|
21
|
+
* - Trailing wildcard matches the query hash and variables hash
|
|
22
|
+
*
|
|
23
|
+
* @param options - Pattern generation options
|
|
24
|
+
* @returns Redis pattern string for SCAN/KEYS operations
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* generateQueryCachePattern({
|
|
29
|
+
* appName: 'CDMBASE_TEST',
|
|
30
|
+
* tenantId: 'default',
|
|
31
|
+
* userId: 'auth0|123',
|
|
32
|
+
* queryName: 'pageSettings'
|
|
33
|
+
* })
|
|
34
|
+
* // Returns: 'CDMBASE_TEST:default:auth0-123:pageSettings:*'
|
|
35
|
+
*
|
|
36
|
+
* // Without userId (for public queries)
|
|
37
|
+
* generateQueryCachePattern({
|
|
38
|
+
* appName: 'CDMBASE_TEST',
|
|
39
|
+
* tenantId: 'default',
|
|
40
|
+
* queryName: 'pageSettings'
|
|
41
|
+
* })
|
|
42
|
+
* // Returns: 'CDMBASE_TEST:default:pageSettings:*'
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
const generateQueryCachePattern = ({ appName, tenantId, userId, queryName, }) => {
|
|
46
|
+
const parts = [sanitizeRedisKeyComponent(appName)];
|
|
47
|
+
if (tenantId) {
|
|
48
|
+
parts.push(sanitizeRedisKeyComponent(tenantId));
|
|
49
|
+
}
|
|
50
|
+
if (userId) {
|
|
51
|
+
parts.push(sanitizeRedisKeyComponent(userId));
|
|
52
|
+
}
|
|
53
|
+
parts.push(sanitizeRedisKeyComponent(queryName));
|
|
54
|
+
parts.push('*'); // Wildcard to match queryHash and variablesHash
|
|
55
|
+
return parts.join(':');
|
|
56
|
+
};
|
|
13
57
|
/**
|
|
14
58
|
* Generates a cache key for GraphQL queries using standardized Redis key builder
|
|
15
59
|
*
|
|
@@ -79,4 +123,4 @@ const generateQueryCacheKey = ({ query, variables, logger, userId, tenantId, app
|
|
|
79
123
|
});
|
|
80
124
|
// Remove the temporary appName prefix: __temp__:
|
|
81
125
|
return fullKey.substring('__temp__:'.length);
|
|
82
|
-
};export{generateQueryCacheKey};//# sourceMappingURL=generate-query-cache-key.js.map
|
|
126
|
+
};export{generateQueryCacheKey,generateQueryCachePattern};//# sourceMappingURL=generate-query-cache-key.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-query-cache-key.js","sources":["../../../src/core/keyBuilder/generate-query-cache-key.ts"],"sourcesContent":["/**\n * @file generate-query-cache-key.ts\n * @description Generates consistent cache keys for GraphQL queries\n *\n * This utility creates deterministic cache keys by hashing GraphQL queries and variables,\n * with proper sanitization for Redis key compatibility (e.g., Auth0 userIds with pipes).\n *\n * Key format: queryName:queryHash[:variablesHash]\n * - Query is hashed using SHA-256 for consistent, compact keys\n * - Variables are optionally hashed if provided\n * - All components are sanitized for Redis key safety\n */\n\nimport { createHash } from 'crypto';\nimport { DocumentNode, print } from 'graphql/language/index.js';\nimport { buildRedisKey } from './sanitize-redis-key';\n\nexport type GenerateQueryCacheKeyOptions = {\n query: string | DocumentNode;\n variables: Record<string, unknown>;\n userId?: string;\n tenantId?: string;\n appName?: string;\n logger?: any;\n};\n\n/**\n * Generates a cache key for GraphQL queries using standardized Redis key builder\n *\n * Key format: `[appName]:[tenantId]:[userId]:queryName:queryHash[:variablesHash]`\n * or legacy format: `[tenantId]:[userId]:queryName:queryHash[:variablesHash]`\n * - Query and variables are hashed for consistent, compact keys\n * - Uses buildRedisKey for proper sanitization and validation\n * - Optional components are omitted if not provided\n *\n * @param options - Cache key generation options\n * @returns Generated cache key string\n *\n * @example\n * ```typescript\n * // With appName (recommended)\n * generateQueryCacheKey({\n * query: GetUserDocument,\n * variables: { userId: '123' },\n * userId: 'auth0|123',\n * tenantId: 'default',\n * appName: 'MY_APP',\n * logger: myLogger\n * })\n * // Returns: 'MY_APP:default:auth0-123:user:hash1:hash2'\n *\n * // Legacy format without appName (for backward compatibility)\n * generateQueryCacheKey({\n * query: GetUserDocument,\n * variables: { userId: '123' },\n * userId: 'auth0|123',\n * tenantId: 'default',\n * })\n * // Returns: 'default:auth0-123:user:hash1:hash2'\n * ```\n */\nexport const generateQueryCacheKey = ({\n query,\n variables,\n logger,\n userId,\n tenantId,\n appName,\n}: GenerateQueryCacheKeyOptions): string => {\n const normalizedQuery = (typeof query === 'string' ? query : print(query)).trim();\n const [, queryName] = normalizedQuery?.match(/{\\s*(\\w+)/) ?? [];\n\n // Log the data right before hashing\n if (logger && typeof logger.trace === 'function') {\n logger.trace('About to hash normalized query: [%s]', normalizedQuery);\n logger.trace('About to hash variables: [%j]', variables);\n }\n\n const queryHash = createHash('sha256').update(normalizedQuery).digest('hex');\n const variablesHash = variables ? createHash('sha256').update(JSON.stringify(variables)).digest('hex') : null;\n\n // Build segments: queryName, queryHash, and optional variablesHash\n const segments = [queryName, queryHash];\n if (variablesHash) {\n segments.push(variablesHash);\n }\n\n // If appName is provided, use the full standardized format\n if (appName) {\n return buildRedisKey({\n appName,\n tenantId,\n userId,\n segments,\n });\n }\n\n // Legacy format for backward compatibility (no appName)\n // Still uses buildRedisKey for sanitization, but strips the appName prefix\n const fullKey = buildRedisKey({\n appName: '__temp__',\n tenantId,\n userId,\n segments,\n });\n\n // Remove the temporary appName prefix: __temp__:\n return fullKey.substring('__temp__:'.length);\n};\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generate-query-cache-key.js","sources":["../../../src/core/keyBuilder/generate-query-cache-key.ts"],"sourcesContent":["/**\n * @file generate-query-cache-key.ts\n * @description Generates consistent cache keys for GraphQL queries\n *\n * This utility creates deterministic cache keys by hashing GraphQL queries and variables,\n * with proper sanitization for Redis key compatibility (e.g., Auth0 userIds with pipes).\n *\n * Key format: queryName:queryHash[:variablesHash]\n * - Query is hashed using SHA-256 for consistent, compact keys\n * - Variables are optionally hashed if provided\n * - All components are sanitized for Redis key safety\n */\n\nimport { createHash } from 'crypto';\nimport { DocumentNode, print } from 'graphql/language/index.js';\nimport { buildRedisKey, sanitizeRedisKeyComponent } from './sanitize-redis-key';\n\nexport type GenerateQueryCacheKeyOptions = {\n query: string | DocumentNode;\n variables: Record<string, unknown>;\n userId?: string;\n tenantId?: string;\n appName?: string;\n logger?: any;\n};\n\nexport type GenerateQueryCachePatternOptions = {\n appName: string;\n tenantId?: string;\n userId?: string;\n queryName: string;\n};\n\n/**\n * Generates a wildcard pattern for invalidating GraphQL query cache keys\n *\n * This function creates patterns that match the keys generated by `generateQueryCacheKey`.\n * Use this for cache invalidation to ensure consistent pattern matching.\n *\n * Key pattern format: `appName:tenantId:[userId]:queryName:*`\n * - All components are sanitized the same way as cache key generation\n * - Trailing wildcard matches the query hash and variables hash\n *\n * @param options - Pattern generation options\n * @returns Redis pattern string for SCAN/KEYS operations\n *\n * @example\n * ```typescript\n * generateQueryCachePattern({\n * appName: 'CDMBASE_TEST',\n * tenantId: 'default',\n * userId: 'auth0|123',\n * queryName: 'pageSettings'\n * })\n * // Returns: 'CDMBASE_TEST:default:auth0-123:pageSettings:*'\n *\n * // Without userId (for public queries)\n * generateQueryCachePattern({\n * appName: 'CDMBASE_TEST',\n * tenantId: 'default',\n * queryName: 'pageSettings'\n * })\n * // Returns: 'CDMBASE_TEST:default:pageSettings:*'\n * ```\n */\nexport const generateQueryCachePattern = ({\n appName,\n tenantId,\n userId,\n queryName,\n}: GenerateQueryCachePatternOptions): string => {\n const parts: string[] = [sanitizeRedisKeyComponent(appName)];\n\n if (tenantId) {\n parts.push(sanitizeRedisKeyComponent(tenantId));\n }\n\n if (userId) {\n parts.push(sanitizeRedisKeyComponent(userId));\n }\n\n parts.push(sanitizeRedisKeyComponent(queryName));\n parts.push('*'); // Wildcard to match queryHash and variablesHash\n\n return parts.join(':');\n};\n\n/**\n * Generates a cache key for GraphQL queries using standardized Redis key builder\n *\n * Key format: `[appName]:[tenantId]:[userId]:queryName:queryHash[:variablesHash]`\n * or legacy format: `[tenantId]:[userId]:queryName:queryHash[:variablesHash]`\n * - Query and variables are hashed for consistent, compact keys\n * - Uses buildRedisKey for proper sanitization and validation\n * - Optional components are omitted if not provided\n *\n * @param options - Cache key generation options\n * @returns Generated cache key string\n *\n * @example\n * ```typescript\n * // With appName (recommended)\n * generateQueryCacheKey({\n * query: GetUserDocument,\n * variables: { userId: '123' },\n * userId: 'auth0|123',\n * tenantId: 'default',\n * appName: 'MY_APP',\n * logger: myLogger\n * })\n * // Returns: 'MY_APP:default:auth0-123:user:hash1:hash2'\n *\n * // Legacy format without appName (for backward compatibility)\n * generateQueryCacheKey({\n * query: GetUserDocument,\n * variables: { userId: '123' },\n * userId: 'auth0|123',\n * tenantId: 'default',\n * })\n * // Returns: 'default:auth0-123:user:hash1:hash2'\n * ```\n */\nexport const generateQueryCacheKey = ({\n query,\n variables,\n logger,\n userId,\n tenantId,\n appName,\n}: GenerateQueryCacheKeyOptions): string => {\n const normalizedQuery = (typeof query === 'string' ? query : print(query)).trim();\n const [, queryName] = normalizedQuery?.match(/{\\s*(\\w+)/) ?? [];\n\n // Log the data right before hashing\n if (logger && typeof logger.trace === 'function') {\n logger.trace('About to hash normalized query: [%s]', normalizedQuery);\n logger.trace('About to hash variables: [%j]', variables);\n }\n\n const queryHash = createHash('sha256').update(normalizedQuery).digest('hex');\n const variablesHash = variables ? createHash('sha256').update(JSON.stringify(variables)).digest('hex') : null;\n\n // Build segments: queryName, queryHash, and optional variablesHash\n const segments = [queryName, queryHash];\n if (variablesHash) {\n segments.push(variablesHash);\n }\n\n // If appName is provided, use the full standardized format\n if (appName) {\n return buildRedisKey({\n appName,\n tenantId,\n userId,\n segments,\n });\n }\n\n // Legacy format for backward compatibility (no appName)\n // Still uses buildRedisKey for sanitization, but strips the appName prefix\n const fullKey = buildRedisKey({\n appName: '__temp__',\n tenantId,\n userId,\n segments,\n });\n\n // Remove the temporary appName prefix: __temp__:\n return fullKey.substring('__temp__:'.length);\n};\n"],"names":[],"mappings":"4JAAA;;;;;;;;;;;AAWG;AAsBH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BG;AACI,MAAM,yBAAyB,GAAG,CAAC,EACtC,OAAO,EACP,QAAQ,EACR,MAAM,EACN,SAAS,GACsB,KAAY;IAC3C,MAAM,KAAK,GAAa,CAAC,yBAAyB,CAAC,OAAO,CAAC,CAAC,CAAC;IAE7D,IAAI,QAAQ,EAAE;QACV,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,QAAQ,CAAC,CAAC,CAAC;KACnD;IAED,IAAI,MAAM,EAAE;QACR,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,MAAM,CAAC,CAAC,CAAC;KACjD;IAED,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,SAAS,CAAC,CAAC,CAAC;AACjD,IAAA,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEhB,IAAA,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3B,EAAE;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCG;AACU,MAAA,qBAAqB,GAAG,CAAC,EAClC,KAAK,EACL,SAAS,EACT,MAAM,EACN,MAAM,EACN,QAAQ,EACR,OAAO,GACoB,KAAY;IACvC,MAAM,eAAe,GAAG,CAAC,OAAO,KAAK,KAAK,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;AAClF,IAAA,MAAM,GAAG,SAAS,CAAC,GAAG,eAAe,EAAE,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;;IAGhE,IAAI,MAAM,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,UAAU,EAAE;AAC9C,QAAA,MAAM,CAAC,KAAK,CAAC,sCAAsC,EAAE,eAAe,CAAC,CAAC;AACtE,QAAA,MAAM,CAAC,KAAK,CAAC,+BAA+B,EAAE,SAAS,CAAC,CAAC;KAC5D;AAED,IAAA,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC7E,IAAA,MAAM,aAAa,GAAG,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;;AAG9G,IAAA,MAAM,QAAQ,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACxC,IAAI,aAAa,EAAE;AACf,QAAA,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;KAChC;;IAGD,IAAI,OAAO,EAAE;AACT,QAAA,OAAO,aAAa,CAAC;YACjB,OAAO;YACP,QAAQ;YACR,MAAM;YACN,QAAQ;AACX,SAAA,CAAC,CAAC;KACN;;;IAID,MAAM,OAAO,GAAG,aAAa,CAAC;AAC1B,QAAA,OAAO,EAAE,UAAU;QACnB,QAAQ;QACR,MAAM;QACN,QAAQ;AACX,KAAA,CAAC,CAAC;;IAGH,OAAO,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AACjD"}
|
package/lib/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{IORedisClient}from'./core/ioredis.js';export{UpstashRedisClient}from'./core/upstash-redis.js';export{buildRedisKey,buildRedisKeyPattern}from'./core/keyBuilder/index.js';export{RedisCacheManager}from'./services/RedisCacheManager.js';export{invalidateCachePlugin}from'./plugins/invalidateCachePlugin.js';export{responseCachePlugin}from'./plugins/responseCachePlugin.js';export{escapeRedisPattern,isHashLikeTenantId,isValidRedisKey,sanitizeRedisKey,sanitizeRedisKeyComponent}from'./core/keyBuilder/sanitize-redis-key.js';export{RedisNamespace,buildRedisKeyPatternWithNamespace,buildRedisKeyWithNamespace,extractNamespaceFromRedisKey,extractTenantIdFromRedisKey,isValidRedisKeyWithNamespace,parseRedisKey}from'./core/keyBuilder/redis-key-builder.js';export{generateQueryCacheKey}from'./core/keyBuilder/generate-query-cache-key.js';//# sourceMappingURL=index.js.map
|
|
1
|
+
export{IORedisClient}from'./core/ioredis.js';export{UpstashRedisClient}from'./core/upstash-redis.js';export{buildRedisKey,buildRedisKeyPattern}from'./core/keyBuilder/index.js';export{RedisCacheManager}from'./services/RedisCacheManager.js';export{invalidateCachePlugin}from'./plugins/invalidateCachePlugin.js';export{responseCachePlugin}from'./plugins/responseCachePlugin.js';export{escapeRedisPattern,isHashLikeTenantId,isValidRedisKey,sanitizeRedisKey,sanitizeRedisKeyComponent}from'./core/keyBuilder/sanitize-redis-key.js';export{RedisNamespace,buildRedisKeyPatternWithNamespace,buildRedisKeyWithNamespace,extractNamespaceFromRedisKey,extractTenantIdFromRedisKey,isValidRedisKeyWithNamespace,parseRedisKey}from'./core/keyBuilder/redis-key-builder.js';export{generateQueryCacheKey,generateQueryCachePattern}from'./core/keyBuilder/generate-query-cache-key.js';//# sourceMappingURL=index.js.map
|
package/lib/module.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { Feature } from '@common-stack/server-core';
|
|
1
2
|
import type { interfaces } from 'inversify';
|
|
2
3
|
export declare const redisServiceGen: (container: interfaces.Container) => {
|
|
3
4
|
redisCacheManager: IRedisCacheManager;
|
|
4
5
|
};
|
|
5
|
-
declare const _default: any
|
|
6
|
+
declare const _default: Feature<any, any>;
|
|
6
7
|
export default _default;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {uniq}from'lodash-es';import {extractTenantId,getDirectiveArgsFromSchema,CACHE_CONTROL_DIRECTIVE}from'@common-stack/server-core';import {config}from'../config/env-config.js';/**
|
|
1
|
+
import {uniq}from'lodash-es';import {extractTenantId,getDirectiveArgsFromSchema,CACHE_CONTROL_DIRECTIVE}from'@common-stack/server-core';import {config}from'../config/env-config.js';import {generateQueryCachePattern}from'../core/keyBuilder/generate-query-cache-key.js';/**
|
|
2
2
|
* Scans Redis keys using SCAN command instead of KEYS for better performance.
|
|
3
3
|
* SCAN is non-blocking and safe to use in production environments.
|
|
4
4
|
*/
|
|
@@ -42,8 +42,12 @@ const invalidateCachePlugin = ({ cache: redisClient, invalidateCacheKeyGenerator
|
|
|
42
42
|
const operation = firstDefinition?.operation;
|
|
43
43
|
const isMutation = operation === 'mutation';
|
|
44
44
|
if (hasErrors || !queriesToInvalidate?.length || !isMutation) {
|
|
45
|
+
if (isMutation) {
|
|
46
|
+
console.log('🔍 invalidateCachePlugin: skipping - hasErrors:', hasErrors, 'queriesToInvalidate:', queriesToInvalidate);
|
|
47
|
+
}
|
|
45
48
|
return;
|
|
46
49
|
}
|
|
50
|
+
console.log('🗑️ invalidateCachePlugin: invalidating queries:', queriesToInvalidate);
|
|
47
51
|
const nestedKeys = await Promise.all(queriesToInvalidate.map(async (query) => {
|
|
48
52
|
// Build keys in order of specificity
|
|
49
53
|
let keys = [];
|
|
@@ -62,14 +66,27 @@ const invalidateCachePlugin = ({ cache: redisClient, invalidateCacheKeyGenerator
|
|
|
62
66
|
const isPrivate = cachePolicy?.scope?.toLowerCase() === 'private';
|
|
63
67
|
// Add tenant-specific key if tenant exists
|
|
64
68
|
if (tenantId) {
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
// Pattern without userId (for public queries or as fallback)
|
|
70
|
+
keys.push(generateQueryCachePattern({
|
|
71
|
+
appName: config.APP_NAME,
|
|
72
|
+
tenantId,
|
|
73
|
+
queryName: query,
|
|
74
|
+
}));
|
|
75
|
+
// Add user-specific pattern if user exists and query is private
|
|
67
76
|
if (user?.sub && isPrivate) {
|
|
68
|
-
keys.push(
|
|
77
|
+
keys.push(generateQueryCachePattern({
|
|
78
|
+
appName: config.APP_NAME,
|
|
79
|
+
tenantId,
|
|
80
|
+
userId: user.sub,
|
|
81
|
+
queryName: query,
|
|
82
|
+
}));
|
|
69
83
|
}
|
|
70
84
|
}
|
|
71
|
-
// Add global
|
|
72
|
-
keys.push(
|
|
85
|
+
// Add global pattern as fallback (no tenant)
|
|
86
|
+
keys.push(generateQueryCachePattern({
|
|
87
|
+
appName: config.APP_NAME,
|
|
88
|
+
queryName: query,
|
|
89
|
+
}));
|
|
73
90
|
// Allow custom key generation if provided
|
|
74
91
|
if (typeof invalidateCacheKeyGenerator === 'function') {
|
|
75
92
|
keys = keys.map((key) => invalidateCacheKeyGenerator(requestContext, responseContext, key));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invalidateCachePlugin.js","sources":["../../src/plugins/invalidateCachePlugin.ts"],"sourcesContent":["import { Redis, Cluster } from 'ioredis';\nimport { uniq } from 'lodash-es';\nimport { OperationDefinitionNode } from 'graphql/language/ast.js';\nimport type { BaseContext, GraphQLRequestContextWillSendResponse } from '@apollo/server';\nimport { ApolloServerOptions, GraphQLRequestContext } from '@apollo/server';\nimport { CACHE_CONTROL_DIRECTIVE, extractTenantId, getDirectiveArgsFromSchema } from '@common-stack/server-core';\nimport { IGraphQLCacheContext } from 'common/server';\nimport { config } from '../config';\n\nexport type InvalidationKeyGenerator = (\n requestContext: GraphQLRequestContext<unknown>,\n responseContext: GraphQLRequestContextWillSendResponse<unknown>,\n cacheKey?: string,\n) => string;\n\n/**\n * Scans Redis keys using SCAN command instead of KEYS for better performance.\n * SCAN is non-blocking and safe to use in production environments.\n */\nasync function scanKeys(redisClient: Redis | Cluster, pattern: string): Promise<string[]> {\n const allKeys: string[] = [];\n let cursor = '0';\n\n do {\n // SCAN returns [cursor, keys[]]\n const [nextCursor, keys] = await redisClient.scan(cursor, 'MATCH', pattern, 'COUNT', 100);\n cursor = nextCursor;\n if (keys.length) {\n allKeys.push(...keys);\n }\n } while (cursor !== '0');\n\n return allKeys;\n}\n\nexport const invalidateCachePlugin = ({\n cache: redisClient,\n invalidateCacheKeyGenerator,\n}: {\n cache: Redis | Cluster;\n invalidateCacheKeyGenerator: InvalidationKeyGenerator;\n}) =>\n ({\n requestDidStart(requestContext: GraphQLRequestContext<IGraphQLCacheContext>) {\n return {\n willSendResponse: async (responseContext: GraphQLRequestContextWillSendResponse<unknown>) => {\n // in case of websocket request initially the requestContext comes empty\n if (!requestContext) {\n return;\n }\n try {\n const hasErrors = !!requestContext.errors?.length;\n const { schema } = requestContext;\n\n // Safely access contextValue properties\n const contextValue = requestContext.contextValue;\n if (!contextValue) {\n return;\n }\n const { queriesToInvalidate, user, req } = contextValue;\n const tenantId = extractTenantId(req?.currentPageUriSegments?.authority);\n\n // Safely extract operation from document definitions\n const definitions = responseContext.document?.definitions as OperationDefinitionNode[];\n if (!definitions?.length) {\n return;\n }\n const firstDefinition = definitions[0];\n const operation = firstDefinition?.operation;\n const isMutation = operation === 'mutation';\n\n if (hasErrors || !queriesToInvalidate?.length || !isMutation) {\n return;\n }\n\n const nestedKeys = await Promise.all<string[]>(\n queriesToInvalidate.map(async (query: string) => {\n // Build keys in order of specificity\n let keys: string[] = [];\n\n // Safely get cache policy directive\n let cachePolicy: { scope?: string } | null = null;\n try {\n cachePolicy = getDirectiveArgsFromSchema({\n schema,\n queryName: query,\n directiveName: CACHE_CONTROL_DIRECTIVE,\n });\n } catch (e) {\n requestContext.logger?.warn?.(`Failed to get cache policy for query: ${query}`);\n }\n\n const isPrivate = cachePolicy?.scope?.toLowerCase() === 'private';\n // Add tenant-specific key if tenant exists\n if (tenantId) {\n keys.push(`${config.APP_NAME}:${tenantId}:${query}:*`);\n // Add user-specific key if user exists\n if (user?.sub && isPrivate) {\n keys.push(`${config.APP_NAME}:${tenantId}:${user.sub}:${query}:*`);\n }\n }\n // Add global key as fallback\n keys.push(`${config.APP_NAME}:${query}:*`);\n\n // Allow custom key generation if provided\n if (typeof invalidateCacheKeyGenerator === 'function') {\n keys = keys.map((key) =>\n invalidateCacheKeyGenerator(requestContext, responseContext, key),\n );\n }\n // Use SCAN instead of KEYS for better performance (non-blocking)\n const matchedKeys = await Promise.all(\n keys.map(async (key) => {\n const matchingKeys = await scanKeys(redisClient, key);\n if (matchingKeys.length) {\n return matchingKeys;\n }\n return [];\n }),\n );\n return matchedKeys.flat();\n }),\n );\n const keys = nestedKeys.flat();\n if (keys?.length) {\n await redisClient.del(uniq(keys));\n }\n } catch (e) {\n requestContext.logger.error('Error occurred in invalidateCachePlugin');\n requestContext.logger.error(e);\n }\n },\n };\n },\n }) as unknown as ApolloServerOptions<BaseContext>['plugins'][0];\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"invalidateCachePlugin.js","sources":["../../src/plugins/invalidateCachePlugin.ts"],"sourcesContent":["import { Redis, Cluster } from 'ioredis';\nimport { uniq } from 'lodash-es';\nimport { OperationDefinitionNode } from 'graphql/language/ast.js';\nimport type { BaseContext, GraphQLRequestContextWillSendResponse } from '@apollo/server';\nimport { ApolloServerOptions, GraphQLRequestContext } from '@apollo/server';\nimport { CACHE_CONTROL_DIRECTIVE, extractTenantId, getDirectiveArgsFromSchema } from '@common-stack/server-core';\nimport { IGraphQLCacheContext } from 'common/server';\nimport { config } from '../config';\nimport { generateQueryCachePattern } from '../core/keyBuilder/generate-query-cache-key';\n\nexport type InvalidationKeyGenerator = (\n requestContext: GraphQLRequestContext<unknown>,\n responseContext: GraphQLRequestContextWillSendResponse<unknown>,\n cacheKey?: string,\n) => string;\n\n/**\n * Scans Redis keys using SCAN command instead of KEYS for better performance.\n * SCAN is non-blocking and safe to use in production environments.\n */\nasync function scanKeys(redisClient: Redis | Cluster, pattern: string): Promise<string[]> {\n const allKeys: string[] = [];\n let cursor = '0';\n\n do {\n // SCAN returns [cursor, keys[]]\n const [nextCursor, keys] = await redisClient.scan(cursor, 'MATCH', pattern, 'COUNT', 100);\n cursor = nextCursor;\n if (keys.length) {\n allKeys.push(...keys);\n }\n } while (cursor !== '0');\n\n return allKeys;\n}\n\nexport const invalidateCachePlugin = ({\n cache: redisClient,\n invalidateCacheKeyGenerator,\n}: {\n cache: Redis | Cluster;\n invalidateCacheKeyGenerator: InvalidationKeyGenerator;\n}) =>\n ({\n requestDidStart(requestContext: GraphQLRequestContext<IGraphQLCacheContext>) {\n return {\n willSendResponse: async (responseContext: GraphQLRequestContextWillSendResponse<unknown>) => {\n // in case of websocket request initially the requestContext comes empty\n if (!requestContext) {\n return;\n }\n try {\n const hasErrors = !!requestContext.errors?.length;\n const { schema } = requestContext;\n\n // Safely access contextValue properties\n const contextValue = requestContext.contextValue;\n if (!contextValue) {\n return;\n }\n const { queriesToInvalidate, user, req } = contextValue;\n const tenantId = extractTenantId(req?.currentPageUriSegments?.authority);\n\n // Safely extract operation from document definitions\n const definitions = responseContext.document?.definitions as OperationDefinitionNode[];\n if (!definitions?.length) {\n return;\n }\n const firstDefinition = definitions[0];\n const operation = firstDefinition?.operation;\n const isMutation = operation === 'mutation';\n\n if (hasErrors || !queriesToInvalidate?.length || !isMutation) {\n if (isMutation) {\n console.log(\n '🔍 invalidateCachePlugin: skipping - hasErrors:',\n hasErrors,\n 'queriesToInvalidate:',\n queriesToInvalidate,\n );\n }\n return;\n }\n\n console.log('🗑️ invalidateCachePlugin: invalidating queries:', queriesToInvalidate);\n\n const nestedKeys = await Promise.all<string[]>(\n queriesToInvalidate.map(async (query: string) => {\n // Build keys in order of specificity\n let keys: string[] = [];\n\n // Safely get cache policy directive\n let cachePolicy: { scope?: string } | null = null;\n try {\n cachePolicy = getDirectiveArgsFromSchema({\n schema,\n queryName: query,\n directiveName: CACHE_CONTROL_DIRECTIVE,\n });\n } catch (e) {\n requestContext.logger?.warn?.(`Failed to get cache policy for query: ${query}`);\n }\n\n const isPrivate = cachePolicy?.scope?.toLowerCase() === 'private';\n // Add tenant-specific key if tenant exists\n if (tenantId) {\n // Pattern without userId (for public queries or as fallback)\n keys.push(\n generateQueryCachePattern({\n appName: config.APP_NAME,\n tenantId,\n queryName: query,\n }),\n );\n // Add user-specific pattern if user exists and query is private\n if (user?.sub && isPrivate) {\n keys.push(\n generateQueryCachePattern({\n appName: config.APP_NAME,\n tenantId,\n userId: user.sub,\n queryName: query,\n }),\n );\n }\n }\n // Add global pattern as fallback (no tenant)\n keys.push(\n generateQueryCachePattern({\n appName: config.APP_NAME,\n queryName: query,\n }),\n );\n\n // Allow custom key generation if provided\n if (typeof invalidateCacheKeyGenerator === 'function') {\n keys = keys.map((key) =>\n invalidateCacheKeyGenerator(requestContext, responseContext, key),\n );\n }\n // Use SCAN instead of KEYS for better performance (non-blocking)\n const matchedKeys = await Promise.all(\n keys.map(async (key) => {\n const matchingKeys = await scanKeys(redisClient, key);\n if (matchingKeys.length) {\n return matchingKeys;\n }\n return [];\n }),\n );\n return matchedKeys.flat();\n }),\n );\n const keys = nestedKeys.flat();\n if (keys?.length) {\n await redisClient.del(uniq(keys));\n }\n } catch (e) {\n requestContext.logger.error('Error occurred in invalidateCachePlugin');\n requestContext.logger.error(e);\n }\n },\n };\n },\n }) as unknown as ApolloServerOptions<BaseContext>['plugins'][0];\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@common-stack/store-redis",
|
|
3
|
-
"version": "8.3.1-alpha.
|
|
3
|
+
"version": "8.3.1-alpha.15",
|
|
4
4
|
"description": "Redis store utilities and services for common-stack",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"author": "CDMBase LLC",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
]
|
|
55
55
|
}
|
|
56
56
|
},
|
|
57
|
-
"gitHead": "
|
|
57
|
+
"gitHead": "64078a271552159366521d7482ad421845639209",
|
|
58
58
|
"typescript": {
|
|
59
59
|
"definition": "lib/index.d.ts"
|
|
60
60
|
}
|