@prosopo/user-access-policy 3.12.8 → 3.12.9

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 (84) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +45 -41
  2. package/.turbo/turbo-build$colon$tsc.log +14 -14
  3. package/.turbo/turbo-build.log +46 -42
  4. package/CHANGELOG.md +18 -0
  5. package/dist/.export.js +7 -21
  6. package/dist/_virtual/_rolldown/runtime.js +3 -0
  7. package/dist/api/.export.js +2 -9
  8. package/dist/api/accessRulesApiClient.js +1 -1
  9. package/dist/api/delete/.export.js +2 -1
  10. package/dist/api/delete/deleteAllRules.js +22 -24
  11. package/dist/api/delete/deleteRuleGroups.js +39 -51
  12. package/dist/api/delete/deleteRules.js +37 -41
  13. package/dist/api/read/.export.js +2 -1
  14. package/dist/api/read/fetchRules.js +34 -42
  15. package/dist/api/read/findRuleIds.js +35 -48
  16. package/dist/api/read/getMissingIds.js +36 -40
  17. package/dist/api/ruleApiRoutes.js +62 -120
  18. package/dist/api/rulesApiClient.js +51 -87
  19. package/dist/api/write/.export.js +2 -1
  20. package/dist/api/write/insertRules.js +84 -102
  21. package/dist/api/write/rehashRules.js +48 -56
  22. package/dist/cjs/.export.cjs +21 -23
  23. package/dist/cjs/_virtual/_rolldown/runtime.cjs +23 -0
  24. package/dist/cjs/api/.export.cjs +6 -10
  25. package/dist/cjs/api/accessRulesApiClient.cjs +0 -0
  26. package/dist/cjs/api/delete/.export.cjs +0 -1
  27. package/dist/cjs/api/delete/deleteAllRules.cjs +22 -24
  28. package/dist/cjs/api/delete/deleteRuleGroups.cjs +39 -51
  29. package/dist/cjs/api/delete/deleteRules.cjs +41 -42
  30. package/dist/cjs/api/read/.export.cjs +0 -1
  31. package/dist/cjs/api/read/fetchRules.cjs +34 -41
  32. package/dist/cjs/api/read/findRuleIds.cjs +37 -48
  33. package/dist/cjs/api/read/getMissingIds.cjs +36 -39
  34. package/dist/cjs/api/ruleApiRoutes.cjs +69 -125
  35. package/dist/cjs/api/rulesApiClient.cjs +54 -90
  36. package/dist/cjs/api/write/.export.cjs +0 -1
  37. package/dist/cjs/api/write/insertRules.cjs +85 -103
  38. package/dist/cjs/api/write/rehashRules.cjs +48 -56
  39. package/dist/cjs/classifyOs.cjs +46 -26
  40. package/dist/cjs/mongoose/.export.cjs +2 -3
  41. package/dist/cjs/mongoose/mongooseRuleSchema.cjs +97 -36
  42. package/dist/cjs/redis/.export.cjs +4 -5
  43. package/dist/cjs/redis/reader/redisAggregate.cjs +59 -84
  44. package/dist/cjs/redis/reader/redisRulesQuery.cjs +74 -116
  45. package/dist/cjs/redis/reader/redisRulesReader.cjs +322 -503
  46. package/dist/cjs/redis/reader/redisRulesSplitQuery.cjs +94 -72
  47. package/dist/cjs/redis/redisClient.cjs +53 -58
  48. package/dist/cjs/redis/redisRuleIndex.cjs +93 -49
  49. package/dist/cjs/redis/redisRulesStorage.cjs +21 -30
  50. package/dist/cjs/redis/redisRulesWriter.cjs +86 -112
  51. package/dist/cjs/rule.cjs +8 -7
  52. package/dist/cjs/ruleInput/.export.cjs +7 -8
  53. package/dist/cjs/ruleInput/policyInput.cjs +35 -58
  54. package/dist/cjs/ruleInput/ruleInput.cjs +37 -42
  55. package/dist/cjs/ruleInput/userScopeInput.cjs +47 -55
  56. package/dist/cjs/ruleRecord.cjs +15 -22
  57. package/dist/cjs/rulesStorage.cjs +7 -6
  58. package/dist/cjs/transformRule.cjs +36 -70
  59. package/dist/classifyOs.js +48 -29
  60. package/dist/mongoose/.export.js +2 -3
  61. package/dist/mongoose/mongooseRuleSchema.js +99 -38
  62. package/dist/redis/.export.js +3 -5
  63. package/dist/redis/reader/redisAggregate.js +60 -86
  64. package/dist/redis/reader/redisRulesQuery.js +75 -118
  65. package/dist/redis/reader/redisRulesReader.js +312 -487
  66. package/dist/redis/reader/redisRulesSplitQuery.js +96 -75
  67. package/dist/redis/redisClient.js +54 -62
  68. package/dist/redis/redisRuleIndex.js +93 -58
  69. package/dist/redis/redisRulesStorage.js +21 -30
  70. package/dist/redis/redisRulesWriter.js +82 -113
  71. package/dist/rule.js +10 -10
  72. package/dist/ruleInput/.export.js +3 -7
  73. package/dist/ruleInput/policyInput.js +35 -61
  74. package/dist/ruleInput/ruleInput.js +36 -44
  75. package/dist/ruleInput/userScopeInput.js +44 -55
  76. package/dist/ruleRecord.js +17 -27
  77. package/dist/rulesStorage.js +9 -8
  78. package/dist/tests/redis/redisRulesStorage.integration.test.js +1 -3
  79. package/dist/tests/redis/redisRulesStorage.integration.test.js.map +1 -1
  80. package/dist/transformRule.js +34 -73
  81. package/entries.ts +25 -6
  82. package/package.json +13 -12
  83. package/src/tests/redis/redisRulesStorage.integration.test.ts +191 -195
  84. package/tsconfig.tsbuildinfo +1 -1
@@ -1,90 +1,65 @@
1
- "use strict";
2
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const zod = require("zod");
4
- const redisRulesQuery = require("./redisRulesQuery.cjs");
5
- const redisClient = require("../redisClient.cjs");
6
- const redisRuleIndex = require("../redisRuleIndex.cjs");
7
- const searchRedisKeysBounded = async (client, query, maxKeys) => {
8
- const reply = await client.ft.searchNoContent(
9
- redisRuleIndex.ACCESS_RULES_REDIS_INDEX_NAME,
10
- query,
11
- {
12
- DIALECT: redisRulesQuery.REDIS_QUERY_DIALECT,
13
- LIMIT: { from: 0, size: maxKeys }
14
- }
15
- );
16
- return reply.documents;
2
+ require("./redisRulesQuery.cjs");
3
+ const require_redis_redisClient = require("../redisClient.cjs");
4
+ const require_redis_redisRuleIndex = require("../redisRuleIndex.cjs");
5
+ let zod = require("zod");
6
+ //#region src/redis/reader/redisAggregate.ts
7
+ var searchRedisKeysBounded = async (client, query, maxKeys) => {
8
+ return (await client.ft.searchNoContent(require_redis_redisRuleIndex.ACCESS_RULES_REDIS_INDEX_NAME, query, {
9
+ DIALECT: 2,
10
+ LIMIT: {
11
+ from: 0,
12
+ size: maxKeys
13
+ }
14
+ })).documents;
17
15
  };
18
- const aggregateRedisKeys = async (client, query, logger, batchHandler, maxKeys) => {
19
- const keyField = "__key";
20
- const recordSchema = zod.z.object({
21
- // it's a reserved name for the record key
22
- [keyField]: zod.z.string()
23
- });
24
- const foundKeys = [];
25
- let stopRequested = false;
26
- const addRecordKeys = async (records) => {
27
- if (stopRequested) {
28
- return;
29
- }
30
- const parsedRecords = redisClient.parseRedisRecords(records, recordSchema, logger);
31
- const recordKeys = parsedRecords.map((record) => record[keyField]);
32
- if (batchHandler) {
33
- await batchHandler(recordKeys);
34
- } else {
35
- if (maxKeys !== void 0 && foundKeys.length + recordKeys.length > maxKeys) {
36
- const remaining = Math.max(0, maxKeys - foundKeys.length);
37
- foundKeys.push(...recordKeys.slice(0, remaining));
38
- stopRequested = true;
39
- logger.warn(() => ({
40
- msg: "Redis aggregation candidate cap hit; truncating result set. This can suppress less-frequent rules and should be investigated.",
41
- data: {
42
- maxKeys,
43
- query
44
- }
45
- }));
46
- return;
47
- }
48
- foundKeys.push(...recordKeys);
49
- logger.debug(() => ({
50
- msg: "Processed aggregation batch",
51
- data: {
52
- size: recordKeys.length
53
- }
54
- }));
55
- }
56
- };
57
- await executeAggregation(
58
- client,
59
- query,
60
- {
61
- // #2 is a required option when the 'ismissing()' function is in the query body
62
- DIALECT: redisRulesQuery.REDIS_QUERY_DIALECT,
63
- COUNT: redisClient.REDIS_BATCH_SIZE,
64
- LOAD: `@${keyField}`
65
- },
66
- addRecordKeys,
67
- () => stopRequested
68
- );
69
- return foundKeys;
16
+ var aggregateRedisKeys = async (client, query, logger, batchHandler, maxKeys) => {
17
+ const keyField = "__key";
18
+ const recordSchema = zod.z.object({ [keyField]: zod.z.string() });
19
+ const foundKeys = [];
20
+ let stopRequested = false;
21
+ const addRecordKeys = async (records) => {
22
+ if (stopRequested) return;
23
+ const recordKeys = require_redis_redisClient.parseRedisRecords(records, recordSchema, logger).map((record) => record[keyField]);
24
+ if (batchHandler) await batchHandler(recordKeys);
25
+ else {
26
+ if (maxKeys !== void 0 && foundKeys.length + recordKeys.length > maxKeys) {
27
+ const remaining = Math.max(0, maxKeys - foundKeys.length);
28
+ foundKeys.push(...recordKeys.slice(0, remaining));
29
+ stopRequested = true;
30
+ logger.warn(() => ({
31
+ msg: "Redis aggregation candidate cap hit; truncating result set. This can suppress less-frequent rules and should be investigated.",
32
+ data: {
33
+ maxKeys,
34
+ query
35
+ }
36
+ }));
37
+ return;
38
+ }
39
+ foundKeys.push(...recordKeys);
40
+ logger.debug(() => ({
41
+ msg: "Processed aggregation batch",
42
+ data: { size: recordKeys.length }
43
+ }));
44
+ }
45
+ };
46
+ await executeAggregation(client, query, {
47
+ DIALECT: 2,
48
+ COUNT: require_redis_redisClient.REDIS_BATCH_SIZE,
49
+ LOAD: `@${keyField}`
50
+ }, addRecordKeys, () => stopRequested);
51
+ return foundKeys;
70
52
  };
71
- const executeAggregation = async (client, query, aggregateOptions, handleBatch, shouldStop) => {
72
- const initialReply = await client.ft.aggregateWithCursor(
73
- redisRuleIndex.ACCESS_RULES_REDIS_INDEX_NAME,
74
- query,
75
- aggregateOptions
76
- );
77
- await handleBatch(initialReply.results);
78
- let cursor = initialReply.cursor;
79
- while (0 !== cursor && !shouldStop?.()) {
80
- const batchReply = await client.ft.cursorRead(
81
- redisRuleIndex.ACCESS_RULES_REDIS_INDEX_NAME,
82
- cursor,
83
- { COUNT: aggregateOptions.COUNT }
84
- );
85
- await handleBatch(batchReply.results);
86
- cursor = batchReply.cursor;
87
- }
53
+ var executeAggregation = async (client, query, aggregateOptions, handleBatch, shouldStop) => {
54
+ const initialReply = await client.ft.aggregateWithCursor(require_redis_redisRuleIndex.ACCESS_RULES_REDIS_INDEX_NAME, query, aggregateOptions);
55
+ await handleBatch(initialReply.results);
56
+ let cursor = initialReply.cursor;
57
+ while (0 !== cursor && !shouldStop?.()) {
58
+ const batchReply = await client.ft.cursorRead(require_redis_redisRuleIndex.ACCESS_RULES_REDIS_INDEX_NAME, cursor, { COUNT: aggregateOptions.COUNT });
59
+ await handleBatch(batchReply.results);
60
+ cursor = batchReply.cursor;
61
+ }
88
62
  };
63
+ //#endregion
89
64
  exports.aggregateRedisKeys = aggregateRedisKeys;
90
65
  exports.searchRedisKeysBounded = searchRedisKeysBounded;
@@ -1,125 +1,83 @@
1
- "use strict";
2
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const rule = require("../../rule.cjs");
4
- const userScopeInput = require("../../ruleInput/userScopeInput.cjs");
5
- const rulesStorage = require("../../rulesStorage.cjs");
6
- const escapeTagValue = (value) => {
7
- return value.replace(/([,.<>{}\[\]"':;!@#$%^&*()\-+=~|/\\])/g, "\\$1");
2
+ const require_rulesStorage = require("../../rulesStorage.cjs");
3
+ const require_rule = require("../../rule.cjs");
4
+ const require_ruleInput_userScopeInput = require("../../ruleInput/userScopeInput.cjs");
5
+ //#region src/redis/reader/redisRulesQuery.ts
6
+ /**
7
+ * Escapes special characters for Redis TAG field queries.
8
+ * Redis TAG fields treat these characters as special and they must be escaped with a backslash.
9
+ */
10
+ var escapeTagValue = (value) => {
11
+ return value.replace(/([,.<>{}\[\]"':;!@#$%^&*()\-+=~|/\\])/g, "\\$1");
8
12
  };
9
- const REDIS_QUERY_DIALECT = 2;
10
- const userIpQueries = {
11
- numericIp: (value, scope) => {
12
- if (void 0 !== value) {
13
- return `( @numericIp:[${value} ${value}] | ( @numericIpMaskMin:[-inf ${value}] @numericIpMaskMax:[${value} +inf] ) )`;
14
- }
15
- if (scope.numericIpMaskMin === void 0 && scope.numericIpMaskMax === void 0) {
16
- return "ismissing(@numericIp) ismissing(@numericIpMaskMin) ismissing(@numericIpMaskMax)";
17
- }
18
- return "";
19
- },
20
- numericIpMaskMin: (value, scope) => {
21
- if (scope.numericIp !== void 0) {
22
- return "";
23
- }
24
- if (value === void 0 && scope.numericIpMaskMax === void 0) {
25
- return "";
26
- }
27
- return value !== void 0 ? `@numericIpMaskMin:[-inf ${value}]` : "ismissing(@numericIpMaskMin)";
28
- },
29
- numericIpMaskMax: (value, scope) => {
30
- if (scope.numericIp !== void 0) {
31
- return "";
32
- }
33
- if (value === void 0 && scope.numericIpMaskMin === void 0) {
34
- return "";
35
- }
36
- return value !== void 0 ? `@numericIpMaskMax:[${value} +inf]` : "ismissing(@numericIpMaskMax)";
37
- }
13
+ var REDIS_QUERY_DIALECT = 2;
14
+ var userIpQueries = {
15
+ numericIp: (value, scope) => {
16
+ if (void 0 !== value) return `( @numericIp:[${value} ${value}] | ( @numericIpMaskMin:[-inf ${value}] @numericIpMaskMax:[${value} +inf] ) )`;
17
+ if (scope.numericIpMaskMin === void 0 && scope.numericIpMaskMax === void 0) return "ismissing(@numericIp) ismissing(@numericIpMaskMin) ismissing(@numericIpMaskMax)";
18
+ return "";
19
+ },
20
+ numericIpMaskMin: (value, scope) => {
21
+ if (scope.numericIp !== void 0) return "";
22
+ if (value === void 0 && scope.numericIpMaskMax === void 0) return "";
23
+ return value !== void 0 ? `@numericIpMaskMin:[-inf ${value}]` : "ismissing(@numericIpMaskMin)";
24
+ },
25
+ numericIpMaskMax: (value, scope) => {
26
+ if (scope.numericIp !== void 0) return "";
27
+ if (value === void 0 && scope.numericIpMaskMin === void 0) return "";
28
+ return value !== void 0 ? `@numericIpMaskMax:[${value} +inf]` : "ismissing(@numericIpMaskMax)";
29
+ }
38
30
  };
39
- const getUserScopeQuery = (userScope, FilterScopeMatchType, matchingFieldsOnly) => {
40
- let scopeEntries = Object.entries(userScope);
41
- let scopeJoinType = " ";
42
- if (FilterScopeMatchType === rulesStorage.FilterScopeMatch.Greedy) {
43
- scopeEntries = scopeEntries.filter(
44
- ([_, value]) => value !== void 0
45
- );
46
- scopeJoinType = " | ";
47
- }
48
- if (matchingFieldsOnly) {
49
- const scopeMap = new Map(scopeEntries);
50
- if (scopeMap.has("numericIp") && scopeMap.get("numericIp") === void 0) {
51
- scopeMap.set("numericIpMaskMin", void 0);
52
- scopeMap.set("numericIpMaskMax", void 0);
53
- }
54
- for (const name of Object.keys(userScopeInput.userScopeSchema.shape)) {
55
- if (!scopeMap.has(name)) {
56
- scopeMap.set(name, void 0);
57
- }
58
- }
59
- scopeEntries = [...scopeMap.entries()];
60
- }
61
- const scopeObj = Object.fromEntries(scopeEntries);
62
- return scopeEntries.map(
63
- ([scopeFieldName, scopeFieldValue]) => getUserScopeFieldQuery(
64
- scopeFieldName,
65
- scopeFieldValue,
66
- FilterScopeMatchType,
67
- scopeObj
68
- )
69
- ).filter(Boolean).join(scopeJoinType);
31
+ var getUserScopeQuery = (userScope, FilterScopeMatchType, matchingFieldsOnly) => {
32
+ let scopeEntries = Object.entries(userScope);
33
+ let scopeJoinType = " ";
34
+ if (FilterScopeMatchType === require_rulesStorage.FilterScopeMatch.Greedy) {
35
+ scopeEntries = scopeEntries.filter(([_, value]) => value !== void 0);
36
+ scopeJoinType = " | ";
37
+ }
38
+ if (matchingFieldsOnly) {
39
+ const scopeMap = new Map(scopeEntries);
40
+ if (scopeMap.has("numericIp") && scopeMap.get("numericIp") === void 0) {
41
+ scopeMap.set("numericIpMaskMin", void 0);
42
+ scopeMap.set("numericIpMaskMax", void 0);
43
+ }
44
+ for (const name of Object.keys(require_ruleInput_userScopeInput.userScopeSchema.shape)) if (!scopeMap.has(name)) scopeMap.set(name, void 0);
45
+ scopeEntries = [...scopeMap.entries()];
46
+ }
47
+ const scopeObj = Object.fromEntries(scopeEntries);
48
+ return scopeEntries.map(([scopeFieldName, scopeFieldValue]) => getUserScopeFieldQuery(scopeFieldName, scopeFieldValue, FilterScopeMatchType, scopeObj)).filter(Boolean).join(scopeJoinType);
70
49
  };
71
- const FIELDS_REQUIRING_ESCAPE = /* @__PURE__ */ new Set([
72
- "coords"
73
- ]);
74
- const NUMERIC_FIELDS = /* @__PURE__ */ new Set(["asn"]);
75
- const getUserScopeFieldQuery = (fieldName, fieldValue, scopeMatch, fullScope) => {
76
- if (fieldName in userIpQueries) {
77
- const queryBuilder = userIpQueries[fieldName];
78
- return queryBuilder(fieldValue, fullScope);
79
- }
80
- if (void 0 === fieldValue) {
81
- return `ismissing(@${fieldName})`;
82
- }
83
- const stringValue = String(fieldValue);
84
- if (NUMERIC_FIELDS.has(fieldName)) {
85
- return `@${fieldName}:[${stringValue} ${stringValue}]`;
86
- }
87
- const queryValue = FIELDS_REQUIRING_ESCAPE.has(fieldName) ? escapeTagValue(stringValue) : stringValue;
88
- return `@${fieldName}:{${queryValue}}`;
50
+ var FIELDS_REQUIRING_ESCAPE = /* @__PURE__ */ new Set(["coords"]);
51
+ var NUMERIC_FIELDS = /* @__PURE__ */ new Set(["asn"]);
52
+ var getUserScopeFieldQuery = (fieldName, fieldValue, scopeMatch, fullScope) => {
53
+ if (fieldName in userIpQueries) {
54
+ const queryBuilder = userIpQueries[fieldName];
55
+ return queryBuilder(fieldValue, fullScope);
56
+ }
57
+ if (void 0 === fieldValue) return `ismissing(@${fieldName})`;
58
+ const stringValue = String(fieldValue);
59
+ if (NUMERIC_FIELDS.has(fieldName)) return `@${fieldName}:[${stringValue} ${stringValue}]`;
60
+ return `@${fieldName}:{${FIELDS_REQUIRING_ESCAPE.has(fieldName) ? escapeTagValue(stringValue) : stringValue}}`;
89
61
  };
90
- const GLOBAL_MATCH_CLAUSE_INNER = `@clientId:{${rule.GLOBAL_CLIENT_SCOPE_SENTINEL}} | ismissing(@clientId)`;
91
- const getPolicyScopeQuery = (policyScope, scopeMatch) => {
92
- const clientId = policyScope?.clientId;
93
- if ("string" === typeof clientId) {
94
- return rulesStorage.FilterScopeMatch.Exact === scopeMatch ? `@clientId:{${clientId}}` : `( @clientId:{${clientId}} | ${GLOBAL_MATCH_CLAUSE_INNER} )`;
95
- }
96
- return rulesStorage.FilterScopeMatch.Exact === scopeMatch ? `( ${GLOBAL_MATCH_CLAUSE_INNER} )` : "";
62
+ var GLOBAL_MATCH_CLAUSE_INNER = `@clientId:{${require_rule.GLOBAL_CLIENT_SCOPE_SENTINEL}} | ismissing(@clientId)`;
63
+ var getPolicyScopeQuery = (policyScope, scopeMatch) => {
64
+ const clientId = policyScope?.clientId;
65
+ if ("string" === typeof clientId) return require_rulesStorage.FilterScopeMatch.Exact === scopeMatch ? `@clientId:{${clientId}}` : `( @clientId:{${clientId}} | ${GLOBAL_MATCH_CLAUSE_INNER} )`;
66
+ return require_rulesStorage.FilterScopeMatch.Exact === scopeMatch ? `( ${GLOBAL_MATCH_CLAUSE_INNER} )` : "";
97
67
  };
98
- const getRulesRedisQuery = (filter, matchingFieldsOnly) => {
99
- const { policyScope, userScope } = filter;
100
- const queryParts = [];
101
- if (filter.groupId) {
102
- queryParts.push(`@groupId:{${filter.groupId}}`);
103
- }
104
- if (filter.blockOnly) {
105
- queryParts.push(`@type:{${rule.AccessPolicyType.Block}}`);
106
- }
107
- const policyScopeQuery = getPolicyScopeQuery(
108
- policyScope,
109
- filter.policyScopeMatch
110
- );
111
- if (policyScopeQuery) {
112
- queryParts.push(policyScopeQuery);
113
- }
114
- if (userScope && Object.keys(userScope).length > 0) {
115
- const userScopeFilter = getUserScopeQuery(
116
- userScope,
117
- filter.userScopeMatch,
118
- matchingFieldsOnly
119
- );
120
- queryParts.push(`( ${userScopeFilter} )`);
121
- }
122
- return queryParts.length > 0 ? queryParts.join(" ") : "*";
68
+ var getRulesRedisQuery = (filter, matchingFieldsOnly) => {
69
+ const { policyScope, userScope } = filter;
70
+ const queryParts = [];
71
+ if (filter.groupId) queryParts.push(`@groupId:{${filter.groupId}}`);
72
+ if (filter.blockOnly) queryParts.push(`@type:{${require_rule.AccessPolicyType.Block}}`);
73
+ const policyScopeQuery = getPolicyScopeQuery(policyScope, filter.policyScopeMatch);
74
+ if (policyScopeQuery) queryParts.push(policyScopeQuery);
75
+ if (userScope && Object.keys(userScope).length > 0) {
76
+ const userScopeFilter = getUserScopeQuery(userScope, filter.userScopeMatch, matchingFieldsOnly);
77
+ queryParts.push(`( ${userScopeFilter} )`);
78
+ }
79
+ return queryParts.length > 0 ? queryParts.join(" ") : "*";
123
80
  };
81
+ //#endregion
124
82
  exports.REDIS_QUERY_DIALECT = REDIS_QUERY_DIALECT;
125
83
  exports.getRulesRedisQuery = getRulesRedisQuery;