@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.
@@ -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":"kIAAA;;;;;;;;;;;AAWG;AAeH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
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
- keys.push(`${config.APP_NAME}:${tenantId}:${query}:*`);
66
- // Add user-specific key if user exists
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(`${config.APP_NAME}:${tenantId}:${user.sub}:${query}:*`);
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 key as fallback
72
- keys.push(`${config.APP_NAME}:${query}:*`);
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.13",
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": "cfa241bc137e9a9aa6ed811496737585c133f870",
57
+ "gitHead": "64078a271552159366521d7482ad421845639209",
58
58
  "typescript": {
59
59
  "definition": "lib/index.d.ts"
60
60
  }