@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,2 @@
1
+ import { interfaces } from 'inversify';
2
+ export declare const infraContainer: (settings: any) => interfaces.ContainerModule;
@@ -0,0 +1,3 @@
1
+ import {ContainerModule}from'inversify';import {SERVER_TYPES}from'common/server';import {RedisCacheManager}from'../services/RedisCacheManager.js';const infraContainer = (settings) => new ContainerModule((bind) => {
2
+ bind(SERVER_TYPES.RedisCacheManager).to(RedisCacheManager).inSingletonScope();
3
+ });export{infraContainer};//# sourceMappingURL=container.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container.js","sources":["../../src/containers/container.ts"],"sourcesContent":["import { ContainerModule, interfaces } from 'inversify';\nimport { SERVER_TYPES, IRedisCacheManager } from 'common/server';\nimport { RedisCacheManager } from '../services/RedisCacheManager';\n\nexport const infraContainer: (settings: any) => interfaces.ContainerModule = (settings: any) =>\n new ContainerModule((bind: interfaces.Bind) => {\n bind<IRedisCacheManager>(SERVER_TYPES.RedisCacheManager).to(RedisCacheManager).inSingletonScope();\n });\n"],"names":[],"mappings":"kJAIO,MAAM,cAAc,GAAkD,CAAC,QAAa,KACvF,IAAI,eAAe,CAAC,CAAC,IAAqB,KAAI;AAC1C,IAAA,IAAI,CAAqB,YAAY,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC,gBAAgB,EAAE,CAAC;AACtG,CAAC"}
@@ -0,0 +1 @@
1
+ export * from './container';
@@ -0,0 +1,3 @@
1
+ export * from './ioredis';
2
+ export * from './upstash-redis';
3
+ export * from './keyBuilder';
@@ -0,0 +1,15 @@
1
+ import Redis from 'ioredis';
2
+ import { IRedisClient } from 'common/server';
3
+ export declare class IORedisClient implements IRedisClient {
4
+ private redis;
5
+ constructor(config: {
6
+ url: string;
7
+ });
8
+ get(key: string): Promise<any | null>;
9
+ set(key: string, value: string, options?: {
10
+ ex?: number;
11
+ }): Promise<string>;
12
+ delMulti(keys: string[]): Promise<any>;
13
+ del(key: string): Promise<number>;
14
+ on(event: string, cb: (...args: any[]) => void): Redis;
15
+ }
@@ -0,0 +1,27 @@
1
+ import Redis from'ioredis';class IORedisClient {
2
+ redis;
3
+ constructor(config) {
4
+ this.redis = new Redis(config.url);
5
+ }
6
+ async get(key) {
7
+ const data = await this.redis.get(key);
8
+ return data;
9
+ }
10
+ async set(key, value, options) {
11
+ if (options?.ex) {
12
+ return await this.redis.set(key, value, 'EX', options?.ex);
13
+ }
14
+ else {
15
+ return await this.redis.set(key, value);
16
+ }
17
+ }
18
+ async delMulti(keys) {
19
+ return await this.redis.del(keys);
20
+ }
21
+ async del(key) {
22
+ return await this.redis.del(key);
23
+ }
24
+ on(event, cb) {
25
+ return this.redis.on(event, cb);
26
+ }
27
+ }export{IORedisClient};//# sourceMappingURL=ioredis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ioredis.js","sources":["../../src/core/ioredis.ts"],"sourcesContent":["import Redis from 'ioredis';\nimport { IRedisClient } from 'common/server';\n\nexport class IORedisClient implements IRedisClient {\n private redis: Redis;\n\n constructor(config: { url: string }) {\n this.redis = new Redis(config.url);\n }\n\n async get(key: string): Promise<any | null> {\n const data = await this.redis.get(key);\n return data;\n }\n\n async set(key: string, value: string, options?: { ex?: number }): Promise<string> {\n if (options?.ex) {\n return await this.redis.set(key, value, 'EX', options?.ex);\n } else {\n return await this.redis.set(key, value);\n }\n }\n\n async delMulti(keys: string[]): Promise<any> {\n return await this.redis.del(keys);\n }\n\n async del(key: string): Promise<number> {\n return await this.redis.del(key);\n }\n\n on(event: string, cb: (...args: any[]) => void) {\n return this.redis.on(event, cb);\n }\n}\n"],"names":[],"mappings":"iCAGa,aAAa,CAAA;AACd,IAAA,KAAK,CAAQ;AAErB,IAAA,WAAA,CAAY,MAAuB,EAAA;QAC/B,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;KACtC;IAED,MAAM,GAAG,CAAC,GAAW,EAAA;QACjB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACvC,QAAA,OAAO,IAAI,CAAC;KACf;AAED,IAAA,MAAM,GAAG,CAAC,GAAW,EAAE,KAAa,EAAE,OAAyB,EAAA;AAC3D,QAAA,IAAI,OAAO,EAAE,EAAE,EAAE;AACb,YAAA,OAAO,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;SAC9D;aAAM;YACH,OAAO,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;SAC3C;KACJ;IAED,MAAM,QAAQ,CAAC,IAAc,EAAA;QACzB,OAAO,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;KACrC;IAED,MAAM,GAAG,CAAC,GAAW,EAAA;QACjB,OAAO,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;KACpC;IAED,EAAE,CAAC,KAAa,EAAE,EAA4B,EAAA;QAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;KACnC;AACJ"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @file generate-query-cache-key.ts
3
+ * @description Generates consistent cache keys for GraphQL queries
4
+ *
5
+ * This utility creates deterministic cache keys by hashing GraphQL queries and variables,
6
+ * with proper sanitization for Redis key compatibility (e.g., Auth0 userIds with pipes).
7
+ *
8
+ * Key format: queryName:queryHash[:variablesHash]
9
+ * - Query is hashed using SHA-256 for consistent, compact keys
10
+ * - Variables are optionally hashed if provided
11
+ * - All components are sanitized for Redis key safety
12
+ */
13
+ import { DocumentNode } from 'graphql/language/index.js';
14
+ export type GenerateQueryCacheKeyOptions = {
15
+ query: string | DocumentNode;
16
+ variables: Record<string, unknown>;
17
+ userId?: string;
18
+ tenantId?: string;
19
+ appName?: string;
20
+ logger?: any;
21
+ };
22
+ /**
23
+ * Generates a cache key for GraphQL queries using standardized Redis key builder
24
+ *
25
+ * Key format: `[appName]:[tenantId]:[userId]:queryName:queryHash[:variablesHash]`
26
+ * or legacy format: `[tenantId]:[userId]:queryName:queryHash[:variablesHash]`
27
+ * - Query and variables are hashed for consistent, compact keys
28
+ * - Uses buildRedisKey for proper sanitization and validation
29
+ * - Optional components are omitted if not provided
30
+ *
31
+ * @param options - Cache key generation options
32
+ * @returns Generated cache key string
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * // With appName (recommended)
37
+ * generateQueryCacheKey({
38
+ * query: GetUserDocument,
39
+ * variables: { userId: '123' },
40
+ * userId: 'auth0|123',
41
+ * tenantId: 'default',
42
+ * appName: 'MY_APP',
43
+ * logger: myLogger
44
+ * })
45
+ * // Returns: 'MY_APP:default:auth0-123:user:hash1:hash2'
46
+ *
47
+ * // Legacy format without appName (for backward compatibility)
48
+ * generateQueryCacheKey({
49
+ * query: GetUserDocument,
50
+ * variables: { userId: '123' },
51
+ * userId: 'auth0|123',
52
+ * tenantId: 'default',
53
+ * })
54
+ * // Returns: 'default:auth0-123:user:hash1:hash2'
55
+ * ```
56
+ */
57
+ export declare const generateQueryCacheKey: ({ query, variables, logger, userId, tenantId, appName, }: GenerateQueryCacheKeyOptions) => string;
@@ -0,0 +1,82 @@
1
+ import {createHash}from'crypto';import {print}from'graphql/language/index.js';import {buildRedisKey}from'./sanitize-redis-key.js';/**
2
+ * @file generate-query-cache-key.ts
3
+ * @description Generates consistent cache keys for GraphQL queries
4
+ *
5
+ * This utility creates deterministic cache keys by hashing GraphQL queries and variables,
6
+ * with proper sanitization for Redis key compatibility (e.g., Auth0 userIds with pipes).
7
+ *
8
+ * Key format: queryName:queryHash[:variablesHash]
9
+ * - Query is hashed using SHA-256 for consistent, compact keys
10
+ * - Variables are optionally hashed if provided
11
+ * - All components are sanitized for Redis key safety
12
+ */
13
+ /**
14
+ * Generates a cache key for GraphQL queries using standardized Redis key builder
15
+ *
16
+ * Key format: `[appName]:[tenantId]:[userId]:queryName:queryHash[:variablesHash]`
17
+ * or legacy format: `[tenantId]:[userId]:queryName:queryHash[:variablesHash]`
18
+ * - Query and variables are hashed for consistent, compact keys
19
+ * - Uses buildRedisKey for proper sanitization and validation
20
+ * - Optional components are omitted if not provided
21
+ *
22
+ * @param options - Cache key generation options
23
+ * @returns Generated cache key string
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * // With appName (recommended)
28
+ * generateQueryCacheKey({
29
+ * query: GetUserDocument,
30
+ * variables: { userId: '123' },
31
+ * userId: 'auth0|123',
32
+ * tenantId: 'default',
33
+ * appName: 'MY_APP',
34
+ * logger: myLogger
35
+ * })
36
+ * // Returns: 'MY_APP:default:auth0-123:user:hash1:hash2'
37
+ *
38
+ * // Legacy format without appName (for backward compatibility)
39
+ * generateQueryCacheKey({
40
+ * query: GetUserDocument,
41
+ * variables: { userId: '123' },
42
+ * userId: 'auth0|123',
43
+ * tenantId: 'default',
44
+ * })
45
+ * // Returns: 'default:auth0-123:user:hash1:hash2'
46
+ * ```
47
+ */
48
+ const generateQueryCacheKey = ({ query, variables, logger, userId, tenantId, appName, }) => {
49
+ const normalizedQuery = (typeof query === 'string' ? query : print(query)).trim();
50
+ const [, queryName] = normalizedQuery?.match(/{\s*(\w+)/) ?? [];
51
+ // Log the data right before hashing
52
+ if (logger && typeof logger.trace === 'function') {
53
+ logger.trace('About to hash normalized query: [%s]', normalizedQuery);
54
+ logger.trace('About to hash variables: [%j]', variables);
55
+ }
56
+ const queryHash = createHash('sha256').update(normalizedQuery).digest('hex');
57
+ const variablesHash = variables ? createHash('sha256').update(JSON.stringify(variables)).digest('hex') : null;
58
+ // Build segments: queryName, queryHash, and optional variablesHash
59
+ const segments = [queryName, queryHash];
60
+ if (variablesHash) {
61
+ segments.push(variablesHash);
62
+ }
63
+ // If appName is provided, use the full standardized format
64
+ if (appName) {
65
+ return buildRedisKey({
66
+ appName,
67
+ tenantId,
68
+ userId,
69
+ segments,
70
+ });
71
+ }
72
+ // Legacy format for backward compatibility (no appName)
73
+ // Still uses buildRedisKey for sanitization, but strips the appName prefix
74
+ const fullKey = buildRedisKey({
75
+ appName: '__temp__',
76
+ tenantId,
77
+ userId,
78
+ segments,
79
+ });
80
+ // Remove the temporary appName prefix: __temp__:
81
+ return fullKey.substring('__temp__:'.length);
82
+ };export{generateQueryCacheKey};//# sourceMappingURL=generate-query-cache-key.js.map
@@ -0,0 +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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Redis Utilities
3
+ *
4
+ * Utility functions for Redis key building, sanitization, and cache key generation.
5
+ * These utilities provide consistent Redis key formatting across applications.
6
+ */
7
+ export * from './sanitize-redis-key';
8
+ export * from './redis-key-builder';
9
+ export * from './generate-query-cache-key';
10
+ import { type RedisKeyBuilderOptions } from './redis-key-builder';
11
+ /**
12
+ * Simplified buildRedisKey that uses APP_NAME from environment
13
+ */
14
+ export declare function buildRedisKey(options: Omit<RedisKeyBuilderOptions, 'appName'>): string;
15
+ /**
16
+ * Simplified buildRedisKeyPattern that uses APP_NAME from environment
17
+ */
18
+ export declare function buildRedisKeyPattern(options: Omit<RedisKeyBuilderOptions, 'appName'>): string;
@@ -0,0 +1,20 @@
1
+ import {buildRedisKeyWithNamespace,buildRedisKeyPatternWithNamespace}from'./redis-key-builder.js';export{RedisNamespace,extractNamespaceFromRedisKey,extractTenantIdFromRedisKey,isValidRedisKeyWithNamespace,parseRedisKey}from'./redis-key-builder.js';import'crypto';import'graphql/language/index.js';/**
2
+ * Redis Utilities
3
+ *
4
+ * Utility functions for Redis key building, sanitization, and cache key generation.
5
+ * These utilities provide consistent Redis key formatting across applications.
6
+ */
7
+ /**
8
+ * Simplified buildRedisKey that uses APP_NAME from environment
9
+ */
10
+ function buildRedisKey(options) {
11
+ const appName = process.env.APP_NAME || 'APP';
12
+ return buildRedisKeyWithNamespace({ ...options, appName });
13
+ }
14
+ /**
15
+ * Simplified buildRedisKeyPattern that uses APP_NAME from environment
16
+ */
17
+ function buildRedisKeyPattern(options) {
18
+ const appName = process.env.APP_NAME || 'APP';
19
+ return buildRedisKeyPatternWithNamespace({ ...options, appName });
20
+ }export{buildRedisKey,buildRedisKeyPattern,buildRedisKeyPatternWithNamespace,buildRedisKeyWithNamespace};//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../../src/core/keyBuilder/index.ts"],"sourcesContent":["/**\n * Redis Utilities\n *\n * Utility functions for Redis key building, sanitization, and cache key generation.\n * These utilities provide consistent Redis key formatting across applications.\n */\n\nexport * from './sanitize-redis-key';\nexport * from './redis-key-builder';\nexport * from './generate-query-cache-key';\n\n// Re-export with simplified API for common use cases\nimport {\n buildRedisKeyWithNamespace,\n buildRedisKeyPatternWithNamespace,\n type RedisKeyBuilderOptions,\n} from './redis-key-builder';\n\n/**\n * Simplified buildRedisKey that uses APP_NAME from environment\n */\nexport function buildRedisKey(options: Omit<RedisKeyBuilderOptions, 'appName'>): string {\n const appName = process.env.APP_NAME || 'APP';\n return buildRedisKeyWithNamespace({ ...options, appName });\n}\n\n/**\n * Simplified buildRedisKeyPattern that uses APP_NAME from environment\n */\nexport function buildRedisKeyPattern(options: Omit<RedisKeyBuilderOptions, 'appName'>): string {\n const appName = process.env.APP_NAME || 'APP';\n return buildRedisKeyPatternWithNamespace({ ...options, appName });\n}\n"],"names":[],"mappings":"0SAAA;;;;;AAKG;AAaH;;AAEG;AACG,SAAU,aAAa,CAAC,OAAgD,EAAA;IAC1E,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,KAAK,CAAC;IAC9C,OAAO,0BAA0B,CAAC,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED;;AAEG;AACG,SAAU,oBAAoB,CAAC,OAAgD,EAAA;IACjF,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,KAAK,CAAC;IAC9C,OAAO,iCAAiC,CAAC,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;AACtE"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Centralized Redis Key Builder
3
+ *
4
+ * Enforces consistent Redis key formatting across the entire application.
5
+ * Standard format: <APP_NAME>:<tenantId>:<namespace>:<...segments>
6
+ *
7
+ * Key Design Principles:
8
+ * 1. All keys MUST start with APP_NAME for application isolation
9
+ * 2. All keys SHOULD include tenantId for multi-tenancy (use 'default' if no tenant context)
10
+ * 3. Keys are sanitized to remove invalid Redis characters
11
+ * 4. Use namespaces to organize keys by domain/feature
12
+ */
13
+ /**
14
+ * Options for building Redis keys with namespace support
15
+ */
16
+ export interface RedisKeyBuilderOptions {
17
+ /** Application name for key prefix (e.g., 'CDMBASE_TEST') */
18
+ appName: string;
19
+ /** Tenant ID for multi-tenancy. Use 'default' for global/system keys */
20
+ tenantId?: string;
21
+ /** Optional user ID for user-specific keys */
22
+ userId?: string;
23
+ /** Namespace for organizing keys (e.g., 'cache', 'session', 'tenant', 'config') */
24
+ namespace: string;
25
+ /** Additional key segments (e.g., ['user', userId] or ['query', queryName]) */
26
+ segments: string[];
27
+ }
28
+ /**
29
+ * Builds a standardized Redis key with namespace and consistent formatting
30
+ *
31
+ * Format: <APP_NAME>:<tenantId>:<namespace>:<segment1>:<segment2>:...
32
+ *
33
+ * @param options - Key building options
34
+ * @returns Formatted and sanitized Redis key
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * // Cache key with tenant
39
+ * buildRedisKeyWithNamespace({
40
+ * appName: 'CDMBASE_TEST',
41
+ * tenantId: 'tenant-123',
42
+ * namespace: 'cache',
43
+ * segments: ['user', userId, 'profile']
44
+ * });
45
+ * // => "CDMBASE_TEST:tenant-123:cache:user:auth0-123:profile"
46
+ *
47
+ * // Global configuration key
48
+ * buildRedisKeyWithNamespace({
49
+ * appName: 'CDMBASE_TEST',
50
+ * tenantId: 'default',
51
+ * namespace: 'config',
52
+ * segments: ['extension', 'permissions']
53
+ * });
54
+ * // => "CDMBASE_TEST:default:config:extension:permissions"
55
+ *
56
+ * // Session key without tenant
57
+ * buildRedisKeyWithNamespace({
58
+ * appName: 'CDMBASE_TEST',
59
+ * namespace: 'session',
60
+ * segments: ['abc123']
61
+ * });
62
+ * // => "CDMBASE_TEST:default:session:abc123"
63
+ * ```
64
+ */
65
+ export declare function buildRedisKeyWithNamespace(options: RedisKeyBuilderOptions): string;
66
+ /**
67
+ * Builds a wildcard pattern for Redis KEYS command with namespace support
68
+ *
69
+ * @param options - Key building options (segments can include '*' wildcards)
70
+ * @returns Redis key pattern for matching multiple keys
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * // Match all cache keys for a tenant
75
+ * buildRedisKeyPatternWithNamespace({
76
+ * appName: 'CDMBASE_TEST',
77
+ * tenantId: 'tenant-123',
78
+ * namespace: 'cache',
79
+ * segments: ['*']
80
+ * });
81
+ * // => "CDMBASE_TEST:tenant-123:cache:*"
82
+ *
83
+ * // Match all user cache keys across all tenants
84
+ * buildRedisKeyPatternWithNamespace({
85
+ * appName: 'CDMBASE_TEST',
86
+ * tenantId: '*',
87
+ * namespace: 'cache',
88
+ * segments: ['user', '*']
89
+ * });
90
+ * // => "CDMBASE_TEST:*:cache:user:*"
91
+ * ```
92
+ */
93
+ export declare function buildRedisKeyPatternWithNamespace(options: RedisKeyBuilderOptions): string;
94
+ /**
95
+ * Common namespaces used across the application
96
+ * These provide a standardized vocabulary for organizing Redis keys
97
+ */
98
+ export declare const RedisNamespace: {
99
+ /** GraphQL/API response caching */
100
+ readonly CACHE: "cache";
101
+ /** User session data */
102
+ readonly SESSION: "session";
103
+ /** Tenant information cache */
104
+ readonly TENANT: "tenant";
105
+ /** Configuration and settings */
106
+ readonly CONFIG: "config";
107
+ /** Extension/plugin data */
108
+ readonly EXTENSION: "extension";
109
+ /** Contribution points */
110
+ readonly CONTRIBUTION: "contribution";
111
+ /** Request-scoped storage */
112
+ readonly STORAGE: "storage";
113
+ /** Permission and access control */
114
+ readonly PERMISSION: "permission";
115
+ /** Temporary/TTL based data */
116
+ readonly TEMP: "temp";
117
+ };
118
+ export type RedisNamespaceType = (typeof RedisNamespace)[keyof typeof RedisNamespace];
119
+ /**
120
+ * Extracts tenant ID from a Redis key if present
121
+ *
122
+ * @param key - Redis key to parse
123
+ * @returns Tenant ID or null if not found/parseable
124
+ */
125
+ export declare function extractTenantIdFromRedisKey(key: string): string | null;
126
+ /**
127
+ * Extracts namespace from a Redis key if present
128
+ *
129
+ * @param key - Redis key to parse
130
+ * @returns Namespace or null if not found/parseable
131
+ */
132
+ export declare function extractNamespaceFromRedisKey(key: string): string | null;
133
+ /**
134
+ * Validates if a key follows the standard format with namespace
135
+ *
136
+ * @param key - Redis key to validate
137
+ * @returns True if key follows standard format
138
+ */
139
+ export declare function isValidRedisKeyWithNamespace(key: string): boolean;
140
+ /**
141
+ * Parses a Redis key into its components
142
+ *
143
+ * @param key - Redis key to parse
144
+ * @returns Parsed key components or null if invalid
145
+ */
146
+ export interface ParsedRedisKey {
147
+ appName: string;
148
+ tenantId: string;
149
+ namespace: string;
150
+ segments: string[];
151
+ }
152
+ export declare function parseRedisKey(key: string): ParsedRedisKey | null;
@@ -0,0 +1,181 @@
1
+ import {sanitizeRedisKeyComponent}from'./sanitize-redis-key.js';/**
2
+ * Centralized Redis Key Builder
3
+ *
4
+ * Enforces consistent Redis key formatting across the entire application.
5
+ * Standard format: <APP_NAME>:<tenantId>:<namespace>:<...segments>
6
+ *
7
+ * Key Design Principles:
8
+ * 1. All keys MUST start with APP_NAME for application isolation
9
+ * 2. All keys SHOULD include tenantId for multi-tenancy (use 'default' if no tenant context)
10
+ * 3. Keys are sanitized to remove invalid Redis characters
11
+ * 4. Use namespaces to organize keys by domain/feature
12
+ */
13
+ /**
14
+ * Builds a standardized Redis key with namespace and consistent formatting
15
+ *
16
+ * Format: <APP_NAME>:<tenantId>:<namespace>:<segment1>:<segment2>:...
17
+ *
18
+ * @param options - Key building options
19
+ * @returns Formatted and sanitized Redis key
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * // Cache key with tenant
24
+ * buildRedisKeyWithNamespace({
25
+ * appName: 'CDMBASE_TEST',
26
+ * tenantId: 'tenant-123',
27
+ * namespace: 'cache',
28
+ * segments: ['user', userId, 'profile']
29
+ * });
30
+ * // => "CDMBASE_TEST:tenant-123:cache:user:auth0-123:profile"
31
+ *
32
+ * // Global configuration key
33
+ * buildRedisKeyWithNamespace({
34
+ * appName: 'CDMBASE_TEST',
35
+ * tenantId: 'default',
36
+ * namespace: 'config',
37
+ * segments: ['extension', 'permissions']
38
+ * });
39
+ * // => "CDMBASE_TEST:default:config:extension:permissions"
40
+ *
41
+ * // Session key without tenant
42
+ * buildRedisKeyWithNamespace({
43
+ * appName: 'CDMBASE_TEST',
44
+ * namespace: 'session',
45
+ * segments: ['abc123']
46
+ * });
47
+ * // => "CDMBASE_TEST:default:session:abc123"
48
+ * ```
49
+ */
50
+ function buildRedisKeyWithNamespace(options) {
51
+ const { appName, tenantId = 'default', userId, namespace, segments } = options;
52
+ // Sanitize all components
53
+ const sanitizedAppName = sanitizeRedisKeyComponent(appName);
54
+ const sanitizedTenantId = sanitizeRedisKeyComponent(tenantId);
55
+ const sanitizedNamespace = sanitizeRedisKeyComponent(namespace);
56
+ const sanitizedSegments = segments.map(sanitizeRedisKeyComponent);
57
+ // Build key with consistent format, including userId if provided
58
+ const parts = [sanitizedAppName, sanitizedTenantId];
59
+ if (userId) {
60
+ parts.push(sanitizeRedisKeyComponent(userId));
61
+ }
62
+ parts.push(sanitizedNamespace, ...sanitizedSegments);
63
+ return parts.join(':');
64
+ }
65
+ /**
66
+ * Builds a wildcard pattern for Redis KEYS command with namespace support
67
+ *
68
+ * @param options - Key building options (segments can include '*' wildcards)
69
+ * @returns Redis key pattern for matching multiple keys
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * // Match all cache keys for a tenant
74
+ * buildRedisKeyPatternWithNamespace({
75
+ * appName: 'CDMBASE_TEST',
76
+ * tenantId: 'tenant-123',
77
+ * namespace: 'cache',
78
+ * segments: ['*']
79
+ * });
80
+ * // => "CDMBASE_TEST:tenant-123:cache:*"
81
+ *
82
+ * // Match all user cache keys across all tenants
83
+ * buildRedisKeyPatternWithNamespace({
84
+ * appName: 'CDMBASE_TEST',
85
+ * tenantId: '*',
86
+ * namespace: 'cache',
87
+ * segments: ['user', '*']
88
+ * });
89
+ * // => "CDMBASE_TEST:*:cache:user:*"
90
+ * ```
91
+ */
92
+ function buildRedisKeyPatternWithNamespace(options) {
93
+ // For patterns, allow '*' to pass through without sanitization
94
+ const { appName, tenantId = '*', userId, namespace, segments } = options;
95
+ const sanitizedAppName = sanitizeRedisKeyComponent(appName);
96
+ const sanitizedTenantId = tenantId === '*' ? '*' : sanitizeRedisKeyComponent(tenantId);
97
+ const sanitizedNamespace = sanitizeRedisKeyComponent(namespace);
98
+ const sanitizedSegments = segments.map((seg) => (seg === '*' ? '*' : sanitizeRedisKeyComponent(seg)));
99
+ // Build pattern with userId if provided
100
+ const parts = [sanitizedAppName, sanitizedTenantId];
101
+ if (userId !== undefined) {
102
+ parts.push(userId === '*' ? '*' : sanitizeRedisKeyComponent(userId));
103
+ }
104
+ parts.push(sanitizedNamespace, ...sanitizedSegments);
105
+ return parts.join(':');
106
+ }
107
+ /**
108
+ * Common namespaces used across the application
109
+ * These provide a standardized vocabulary for organizing Redis keys
110
+ */
111
+ const RedisNamespace = {
112
+ /** GraphQL/API response caching */
113
+ CACHE: 'cache',
114
+ /** User session data */
115
+ SESSION: 'session',
116
+ /** Tenant information cache */
117
+ TENANT: 'tenant',
118
+ /** Configuration and settings */
119
+ CONFIG: 'config',
120
+ /** Extension/plugin data */
121
+ EXTENSION: 'extension',
122
+ /** Contribution points */
123
+ CONTRIBUTION: 'contribution',
124
+ /** Request-scoped storage */
125
+ STORAGE: 'storage',
126
+ /** Permission and access control */
127
+ PERMISSION: 'permission',
128
+ /** Temporary/TTL based data */
129
+ TEMP: 'temp',
130
+ };
131
+ /**
132
+ * Extracts tenant ID from a Redis key if present
133
+ *
134
+ * @param key - Redis key to parse
135
+ * @returns Tenant ID or null if not found/parseable
136
+ */
137
+ function extractTenantIdFromRedisKey(key) {
138
+ const parts = key.split(':');
139
+ // Format: APP_NAME:tenantId:namespace:...
140
+ if (parts.length >= 3) {
141
+ return parts[1];
142
+ }
143
+ return null;
144
+ }
145
+ /**
146
+ * Extracts namespace from a Redis key if present
147
+ *
148
+ * @param key - Redis key to parse
149
+ * @returns Namespace or null if not found/parseable
150
+ */
151
+ function extractNamespaceFromRedisKey(key) {
152
+ const parts = key.split(':');
153
+ // Format: APP_NAME:tenantId:namespace:...
154
+ if (parts.length >= 3) {
155
+ return parts[2];
156
+ }
157
+ return null;
158
+ }
159
+ /**
160
+ * Validates if a key follows the standard format with namespace
161
+ *
162
+ * @param key - Redis key to validate
163
+ * @returns True if key follows standard format
164
+ */
165
+ function isValidRedisKeyWithNamespace(key) {
166
+ const parts = key.split(':');
167
+ // Minimum format: APP_NAME:tenantId:namespace
168
+ return parts.length >= 3 && parts[0].length > 0 && parts[1].length > 0 && parts[2].length > 0;
169
+ }
170
+ function parseRedisKey(key) {
171
+ const parts = key.split(':');
172
+ if (parts.length < 3) {
173
+ return null;
174
+ }
175
+ return {
176
+ appName: parts[0],
177
+ tenantId: parts[1],
178
+ namespace: parts[2],
179
+ segments: parts.slice(3),
180
+ };
181
+ }export{RedisNamespace,buildRedisKeyPatternWithNamespace,buildRedisKeyWithNamespace,extractNamespaceFromRedisKey,extractTenantIdFromRedisKey,isValidRedisKeyWithNamespace,parseRedisKey};//# sourceMappingURL=redis-key-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-key-builder.js","sources":["../../../src/core/keyBuilder/redis-key-builder.ts"],"sourcesContent":["/**\n * Centralized Redis Key Builder\n *\n * Enforces consistent Redis key formatting across the entire application.\n * Standard format: <APP_NAME>:<tenantId>:<namespace>:<...segments>\n *\n * Key Design Principles:\n * 1. All keys MUST start with APP_NAME for application isolation\n * 2. All keys SHOULD include tenantId for multi-tenancy (use 'default' if no tenant context)\n * 3. Keys are sanitized to remove invalid Redis characters\n * 4. Use namespaces to organize keys by domain/feature\n */\n\nimport { sanitizeRedisKeyComponent } from './sanitize-redis-key';\n\n/**\n * Options for building Redis keys with namespace support\n */\nexport interface RedisKeyBuilderOptions {\n /** Application name for key prefix (e.g., 'CDMBASE_TEST') */\n appName: string;\n /** Tenant ID for multi-tenancy. Use 'default' for global/system keys */\n tenantId?: string;\n /** Optional user ID for user-specific keys */\n userId?: string;\n /** Namespace for organizing keys (e.g., 'cache', 'session', 'tenant', 'config') */\n namespace: string;\n /** Additional key segments (e.g., ['user', userId] or ['query', queryName]) */\n segments: string[];\n}\n\n/**\n * Builds a standardized Redis key with namespace and consistent formatting\n *\n * Format: <APP_NAME>:<tenantId>:<namespace>:<segment1>:<segment2>:...\n *\n * @param options - Key building options\n * @returns Formatted and sanitized Redis key\n *\n * @example\n * ```typescript\n * // Cache key with tenant\n * buildRedisKeyWithNamespace({\n * appName: 'CDMBASE_TEST',\n * tenantId: 'tenant-123',\n * namespace: 'cache',\n * segments: ['user', userId, 'profile']\n * });\n * // => \"CDMBASE_TEST:tenant-123:cache:user:auth0-123:profile\"\n *\n * // Global configuration key\n * buildRedisKeyWithNamespace({\n * appName: 'CDMBASE_TEST',\n * tenantId: 'default',\n * namespace: 'config',\n * segments: ['extension', 'permissions']\n * });\n * // => \"CDMBASE_TEST:default:config:extension:permissions\"\n *\n * // Session key without tenant\n * buildRedisKeyWithNamespace({\n * appName: 'CDMBASE_TEST',\n * namespace: 'session',\n * segments: ['abc123']\n * });\n * // => \"CDMBASE_TEST:default:session:abc123\"\n * ```\n */\nexport function buildRedisKeyWithNamespace(options: RedisKeyBuilderOptions): string {\n const { appName, tenantId = 'default', userId, namespace, segments } = options;\n\n // Sanitize all components\n const sanitizedAppName = sanitizeRedisKeyComponent(appName);\n const sanitizedTenantId = sanitizeRedisKeyComponent(tenantId);\n const sanitizedNamespace = sanitizeRedisKeyComponent(namespace);\n const sanitizedSegments = segments.map(sanitizeRedisKeyComponent);\n\n // Build key with consistent format, including userId if provided\n const parts = [sanitizedAppName, sanitizedTenantId];\n\n if (userId) {\n parts.push(sanitizeRedisKeyComponent(userId));\n }\n\n parts.push(sanitizedNamespace, ...sanitizedSegments);\n\n return parts.join(':');\n}\n\n/**\n * Builds a wildcard pattern for Redis KEYS command with namespace support\n *\n * @param options - Key building options (segments can include '*' wildcards)\n * @returns Redis key pattern for matching multiple keys\n *\n * @example\n * ```typescript\n * // Match all cache keys for a tenant\n * buildRedisKeyPatternWithNamespace({\n * appName: 'CDMBASE_TEST',\n * tenantId: 'tenant-123',\n * namespace: 'cache',\n * segments: ['*']\n * });\n * // => \"CDMBASE_TEST:tenant-123:cache:*\"\n *\n * // Match all user cache keys across all tenants\n * buildRedisKeyPatternWithNamespace({\n * appName: 'CDMBASE_TEST',\n * tenantId: '*',\n * namespace: 'cache',\n * segments: ['user', '*']\n * });\n * // => \"CDMBASE_TEST:*:cache:user:*\"\n * ```\n */\nexport function buildRedisKeyPatternWithNamespace(options: RedisKeyBuilderOptions): string {\n // For patterns, allow '*' to pass through without sanitization\n const { appName, tenantId = '*', userId, namespace, segments } = options;\n\n const sanitizedAppName = sanitizeRedisKeyComponent(appName);\n const sanitizedTenantId = tenantId === '*' ? '*' : sanitizeRedisKeyComponent(tenantId);\n const sanitizedNamespace = sanitizeRedisKeyComponent(namespace);\n const sanitizedSegments = segments.map((seg) => (seg === '*' ? '*' : sanitizeRedisKeyComponent(seg)));\n\n // Build pattern with userId if provided\n const parts = [sanitizedAppName, sanitizedTenantId];\n\n if (userId !== undefined) {\n parts.push(userId === '*' ? '*' : sanitizeRedisKeyComponent(userId));\n }\n\n parts.push(sanitizedNamespace, ...sanitizedSegments);\n\n return parts.join(':');\n}\n\n/**\n * Common namespaces used across the application\n * These provide a standardized vocabulary for organizing Redis keys\n */\nexport const RedisNamespace = {\n /** GraphQL/API response caching */\n CACHE: 'cache',\n /** User session data */\n SESSION: 'session',\n /** Tenant information cache */\n TENANT: 'tenant',\n /** Configuration and settings */\n CONFIG: 'config',\n /** Extension/plugin data */\n EXTENSION: 'extension',\n /** Contribution points */\n CONTRIBUTION: 'contribution',\n /** Request-scoped storage */\n STORAGE: 'storage',\n /** Permission and access control */\n PERMISSION: 'permission',\n /** Temporary/TTL based data */\n TEMP: 'temp',\n} as const;\n\nexport type RedisNamespaceType = (typeof RedisNamespace)[keyof typeof RedisNamespace];\n\n/**\n * Extracts tenant ID from a Redis key if present\n *\n * @param key - Redis key to parse\n * @returns Tenant ID or null if not found/parseable\n */\nexport function extractTenantIdFromRedisKey(key: string): string | null {\n const parts = key.split(':');\n // Format: APP_NAME:tenantId:namespace:...\n if (parts.length >= 3) {\n return parts[1];\n }\n return null;\n}\n\n/**\n * Extracts namespace from a Redis key if present\n *\n * @param key - Redis key to parse\n * @returns Namespace or null if not found/parseable\n */\nexport function extractNamespaceFromRedisKey(key: string): string | null {\n const parts = key.split(':');\n // Format: APP_NAME:tenantId:namespace:...\n if (parts.length >= 3) {\n return parts[2];\n }\n return null;\n}\n\n/**\n * Validates if a key follows the standard format with namespace\n *\n * @param key - Redis key to validate\n * @returns True if key follows standard format\n */\nexport function isValidRedisKeyWithNamespace(key: string): boolean {\n const parts = key.split(':');\n // Minimum format: APP_NAME:tenantId:namespace\n return parts.length >= 3 && parts[0].length > 0 && parts[1].length > 0 && parts[2].length > 0;\n}\n\n/**\n * Parses a Redis key into its components\n *\n * @param key - Redis key to parse\n * @returns Parsed key components or null if invalid\n */\nexport interface ParsedRedisKey {\n appName: string;\n tenantId: string;\n namespace: string;\n segments: string[];\n}\n\nexport function parseRedisKey(key: string): ParsedRedisKey | null {\n const parts = key.split(':');\n if (parts.length < 3) {\n return null;\n }\n\n return {\n appName: parts[0],\n tenantId: parts[1],\n namespace: parts[2],\n segments: parts.slice(3),\n };\n}\n"],"names":[],"mappings":"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"}