@common-stack/store-redis 8.2.5-alpha.33

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.
@@ -0,0 +1,68 @@
1
+ import { sanitizeKeyComponent } from './redis-key-sanitizer.js';
2
+
3
+ /**
4
+ * Get application name from environment or config
5
+ * This will be replaced with actual config import during migration
6
+ */
7
+ const getAppName = () => {
8
+ return process.env.APP_NAME || 'APP';
9
+ };
10
+ /**
11
+ * Build a standardized Redis key with proper formatting and sanitization
12
+ *
13
+ * Format: <APP_NAME>:<tenantId>:<namespace>:<segments...>
14
+ *
15
+ * @example
16
+ * buildRedisKey({
17
+ * tenantId: 'tenant-123',
18
+ * namespace: RedisNamespace.CACHE,
19
+ * segments: ['user', 'profile']
20
+ * })
21
+ * // Returns: "APP_NAME:tenant-123:cache:user:profile"
22
+ */
23
+ function buildRedisKey(options) {
24
+ const { tenantId = 'default', namespace, segments, userId } = options;
25
+ // Sanitize all components
26
+ const sanitizedTenantId = sanitizeKeyComponent(tenantId);
27
+ const sanitizedNamespace = sanitizeKeyComponent(namespace);
28
+ const sanitizedSegments = segments.map(sanitizeKeyComponent);
29
+ // Build key parts
30
+ const parts = [getAppName(), sanitizedTenantId, sanitizedNamespace, ...sanitizedSegments];
31
+ // Add userId if provided
32
+ if (userId) {
33
+ parts.splice(2, 0, sanitizeKeyComponent(userId));
34
+ }
35
+ return parts.join(':');
36
+ }
37
+ /**
38
+ * Build a Redis key pattern for wildcard matching
39
+ *
40
+ * @example
41
+ * buildRedisKeyPattern({
42
+ * tenantId: 'tenant-123',
43
+ * namespace: RedisNamespace.CACHE,
44
+ * segments: ['user', '*']
45
+ * })
46
+ * // Returns: "APP_NAME:tenant-123:cache:user:*"
47
+ */
48
+ function buildRedisKeyPattern(options) {
49
+ // Same as buildRedisKey but allows '*' in segments
50
+ return buildRedisKey(options);
51
+ }
52
+ /**
53
+ * Validate if a string is a valid Redis key
54
+ * Redis keys can be up to 512MB but should be kept reasonable
55
+ */
56
+ function isValidRedisKey(key) {
57
+ // Basic validation rules
58
+ if (!key || key.length === 0)
59
+ return false;
60
+ if (key.length > 1024)
61
+ return false; // Reasonable limit
62
+ // Check for invalid characters after sanitization
63
+ // After sanitization, keys should only contain alphanumeric, colons, hyphens, underscores
64
+ const validPattern = /^[a-zA-Z0-9:_-]+$/;
65
+ return validPattern.test(key);
66
+ }
67
+
68
+ export { buildRedisKey, buildRedisKeyPattern, isValidRedisKey };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Sanitize a Redis key component to ensure it's valid and safe
3
+ *
4
+ * Redis keys can contain any binary sequence, but for best practices:
5
+ * - Avoid whitespace (spaces, tabs, newlines) - replace with underscores
6
+ * - Avoid control characters (0x00-0x1F, 0x7F) - remove them
7
+ * - Avoid quotes and backslashes that could cause escaping issues - remove them
8
+ * - Replace pipes (|) with hyphens since Auth0 userIds use pipes (auth0|123)
9
+ *
10
+ * @param component - The key component to sanitize
11
+ * @returns Sanitized key component
12
+ */
13
+ export declare function sanitizeKeyComponent(component: string): string;
14
+ /**
15
+ * Sanitize an entire Redis key (all components)
16
+ * Useful for keys that are already constructed
17
+ *
18
+ * @param key - The complete Redis key to sanitize
19
+ * @returns Sanitized Redis key
20
+ */
21
+ export declare function sanitizeRedisKey(key: string): string;
22
+ /**
23
+ * Escape special Redis pattern characters for exact matching
24
+ * Useful when you want to search for keys containing wildcards literally
25
+ * Note: Hyphens are not escaped as they're commonly used in keys
26
+ *
27
+ * @param pattern - The pattern to escape
28
+ * @returns Escaped pattern
29
+ */
30
+ export declare function escapeRedisPattern(pattern: string): string;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Sanitize a Redis key component to ensure it's valid and safe
3
+ *
4
+ * Redis keys can contain any binary sequence, but for best practices:
5
+ * - Avoid whitespace (spaces, tabs, newlines) - replace with underscores
6
+ * - Avoid control characters (0x00-0x1F, 0x7F) - remove them
7
+ * - Avoid quotes and backslashes that could cause escaping issues - remove them
8
+ * - Replace pipes (|) with hyphens since Auth0 userIds use pipes (auth0|123)
9
+ *
10
+ * @param component - The key component to sanitize
11
+ * @returns Sanitized key component
12
+ */
13
+ function sanitizeKeyComponent(component) {
14
+ if (!component)
15
+ return '';
16
+ return component
17
+ .trim() // Trim first to remove leading/trailing whitespace
18
+ .replace(/[\s\r\n\t]+/g, '_') // Replace whitespace with underscore
19
+ .replace(/\|/g, '-') // Replace pipe with hyphen (Auth0 userIds: auth0|123 → auth0-123)
20
+ .replace(/[\x00-\x1F\x7F]/g, '') // Remove control characters
21
+ .replace(/["'\\]/g, ''); // Remove quotes and backslashes
22
+ }
23
+ /**
24
+ * Sanitize an entire Redis key (all components)
25
+ * Useful for keys that are already constructed
26
+ *
27
+ * @param key - The complete Redis key to sanitize
28
+ * @returns Sanitized Redis key
29
+ */
30
+ function sanitizeRedisKey(key) {
31
+ if (!key)
32
+ return '';
33
+ // Split by colon, sanitize each part, rejoin
34
+ return key
35
+ .split(':')
36
+ .map(sanitizeKeyComponent)
37
+ .filter((part) => part.length > 0)
38
+ .join(':');
39
+ }
40
+ /**
41
+ * Escape special Redis pattern characters for exact matching
42
+ * Useful when you want to search for keys containing wildcards literally
43
+ * Note: Hyphens are not escaped as they're commonly used in keys
44
+ *
45
+ * @param pattern - The pattern to escape
46
+ * @returns Escaped pattern
47
+ */
48
+ function escapeRedisPattern(pattern) {
49
+ // Escape Redis KEYS pattern special characters: * ? [ ] ^ \
50
+ // Note: We don't escape hyphen (-) as it's not special outside character classes
51
+ return pattern.replace(/[*?[\]^\\]/g, '\\$&');
52
+ }
53
+
54
+ export { escapeRedisPattern, sanitizeKeyComponent, sanitizeRedisKey };
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@common-stack/store-redis",
3
+ "version": "8.2.5-alpha.33",
4
+ "description": "Redis store utilities and services for common-stack",
5
+ "license": "UNLICENSED",
6
+ "author": "CDMBase LLC",
7
+ "type": "module",
8
+ "main": "lib/index.js",
9
+ "module": "lib/index.js",
10
+ "types": "lib/index.d.ts",
11
+ "files": [
12
+ "lib"
13
+ ],
14
+ "scripts": {
15
+ "build": "npm run build:clean && npm run build:lib",
16
+ "build:clean": "rimraf lib",
17
+ "build:lib": "rollup -c rollup.config.mjs",
18
+ "build:lib:watch": "npm run build:lib -- --watch",
19
+ "jest": "./node_modules/.bin/jest",
20
+ "prepublish": "npm run build",
21
+ "test": "cross-env ENV_FILE=../../config/test/test.env jest",
22
+ "test:debug": "npm test -- --runInBand",
23
+ "test:watch": "npm test -- --watch",
24
+ "watch": "npm run build:lib:watch"
25
+ },
26
+ "dependencies": {
27
+ "@common-stack/core": "8.2.5-alpha.15"
28
+ },
29
+ "devDependencies": {
30
+ "common": "8.2.5-alpha.15",
31
+ "ioredis": "^5.3.2"
32
+ },
33
+ "peerDependencies": {
34
+ "inversify": "*",
35
+ "ioredis": ">=5.0.0"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "cdecode": {
41
+ "common": {
42
+ "constants": [
43
+ "./${libDir}/templates/constants/SERVER_TYPES.ts.template"
44
+ ],
45
+ "repositories": [
46
+ "./${libDir}/templates/repositories/IRedisKeyBuilder.ts.template",
47
+ "./${libDir}/templates/repositories/IRedisStorageBackend.ts.template",
48
+ "./${libDir}/templates/repositories/IRedisCacheManager.ts.template",
49
+ "./${libDir}/templates/repositories/IRedisService.ts.template",
50
+ "./${libDir}/templates/repositories/redisCommonTypes.ts.template"
51
+ ]
52
+ }
53
+ },
54
+ "typescript": {
55
+ "definition": "lib/index.d.ts"
56
+ },
57
+ "gitHead": "5745649eba49ac589b9ace8c55378b6cbe130096"
58
+ }