@prosopo/user-access-policy 3.9.0 → 3.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build$colon$cjs.log +35 -35
- package/.turbo/turbo-build$colon$tsc.log +14 -14
- package/.turbo/turbo-build.log +4 -4
- package/CHANGELOG.md +21 -0
- package/dist/cjs/redis/reader/redisAggregate.cjs +22 -4
- package/dist/cjs/redis/reader/redisRulesReader.cjs +133 -35
- package/dist/redis/reader/redisAggregate.d.ts +1 -1
- package/dist/redis/reader/redisAggregate.d.ts.map +1 -1
- package/dist/redis/reader/redisAggregate.js +22 -4
- package/dist/redis/reader/redisAggregate.js.map +1 -1
- package/dist/redis/reader/redisRulesReader.d.ts +4 -1
- package/dist/redis/reader/redisRulesReader.d.ts.map +1 -1
- package/dist/redis/reader/redisRulesReader.js +132 -34
- package/dist/redis/reader/redisRulesReader.js.map +1 -1
- package/dist/tests/redis/redisRulesReaderRank.benchmark.integration.test.d.ts +2 -0
- package/dist/tests/redis/redisRulesReaderRank.benchmark.integration.test.d.ts.map +1 -0
- package/dist/tests/redis/redisRulesReaderRank.benchmark.integration.test.js +189 -0
- package/dist/tests/redis/redisRulesReaderRank.benchmark.integration.test.js.map +1 -0
- package/dist/tests/redis/redisRulesStorage.integration.test.js +31 -0
- package/dist/tests/redis/redisRulesStorage.integration.test.js.map +1 -1
- package/package.json +3 -3
- package/src/redis/reader/redisAggregate.ts +27 -1
- package/src/redis/reader/redisRulesReader.ts +197 -37
- package/src/tests/redis/redisRulesReaderRank.benchmark.integration.test.ts +338 -0
- package/src/tests/redis/redisRulesStorage.integration.test.ts +52 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/vite.test.config.ts +12 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/user-access-policy@3.
|
|
2
|
+
> @prosopo/user-access-policy@3.10.0 build:cjs
|
|
3
3
|
> NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV
|
|
4
4
|
|
|
5
5
|
ViteCommonJSConfig: .
|
|
@@ -35,37 +35,37 @@ transforming...
|
|
|
35
35
|
Build end
|
|
36
36
|
[32m✓[39m 33 modules transformed.
|
|
37
37
|
rendering chunks...
|
|
38
|
-
[2mdist/cjs/[22m[36mapi/delete/.export.cjs [39m[1m[
|
|
39
|
-
[2mdist/cjs/[22m[36mapi/read/.export.cjs [39m[1m[
|
|
40
|
-
[2mdist/cjs/[22m[36mapi/write/.export.cjs [39m[1m[
|
|
41
|
-
[2mdist/cjs/[22m[36mmongoose/.export.cjs [39m[1m[
|
|
42
|
-
[2mdist/cjs/[22m[36mrulesStorage.cjs [39m[1m[
|
|
43
|
-
[2mdist/cjs/[22m[36mrule.cjs [39m[1m[
|
|
44
|
-
[2mdist/cjs/[22m[36mredis/.export.cjs [39m[1m[
|
|
45
|
-
[2mdist/cjs/[22m[36mruleInput/.export.cjs [39m[1m[
|
|
46
|
-
[2mdist/cjs/[22m[36mapi/.export.cjs [39m[1m[
|
|
47
|
-
[2mdist/cjs/[22m[36mapi/delete/deleteAllRules.cjs [39m[1m[
|
|
48
|
-
[2mdist/cjs/[22m[36mruleRecord.cjs [39m[1m[
|
|
49
|
-
[2mdist/cjs/[22m[36mapi/read/getMissingIds.cjs [39m[1m[
|
|
50
|
-
[2mdist/cjs/[22m[36mapi/read/fetchRules.cjs [39m[1m[
|
|
51
|
-
[2mdist/cjs/[22m[36m.export.cjs [39m[1m[
|
|
52
|
-
[2mdist/cjs/[22m[36mredis/redisRulesStorage.cjs [39m[1m[
|
|
53
|
-
[2mdist/cjs/[22m[36mmongoose/mongooseRuleSchema.cjs [39m[1m[
|
|
54
|
-
[2mdist/cjs/[22m[36mapi/delete/deleteRules.cjs [39m[1m[
|
|
55
|
-
[2mdist/cjs/[22m[36mapi/delete/deleteRuleGroups.cjs [39m[1m[
|
|
56
|
-
[2mdist/cjs/[22m[36mapi/write/rehashRules.cjs [39m[1m[
|
|
57
|
-
[2mdist/cjs/[22m[36mapi/read/findRuleIds.cjs [39m[1m[
|
|
58
|
-
[2mdist/cjs/[22m[36mruleInput/policyInput.cjs [39m[1m[
|
|
59
|
-
[2mdist/cjs/[22m[
|
|
60
|
-
[2mdist/cjs/[22m[
|
|
61
|
-
[2mdist/cjs/[22m[
|
|
62
|
-
[2mdist/cjs/[22m[
|
|
63
|
-
[2mdist/cjs/[22m[
|
|
64
|
-
[2mdist/cjs/[22m[
|
|
65
|
-
[2mdist/cjs/[22m[36mtransformRule.cjs [39m[1m[
|
|
66
|
-
[2mdist/cjs/[22m[36mapi/write/insertRules.cjs [39m[1m[
|
|
67
|
-
[2mdist/cjs/[22m[36mredis/redisRulesWriter.cjs [39m[1m[
|
|
68
|
-
[2mdist/cjs/[22m[36mredis/reader/redisRulesQuery.cjs [39m[1m[
|
|
69
|
-
[2mdist/cjs/[22m[36mapi/ruleApiRoutes.cjs [39m[1m[
|
|
70
|
-
[2mdist/cjs/[22m[36mredis/reader/redisRulesReader.cjs [39m[1m[
|
|
71
|
-
[32m✓ built in
|
|
38
|
+
[2mdist/cjs/[22m[36mapi/delete/.export.cjs [39m[1m[2m 0.01 kB[22m[1m[22m
|
|
39
|
+
[2mdist/cjs/[22m[36mapi/read/.export.cjs [39m[1m[2m 0.01 kB[22m[1m[22m
|
|
40
|
+
[2mdist/cjs/[22m[36mapi/write/.export.cjs [39m[1m[2m 0.01 kB[22m[1m[22m
|
|
41
|
+
[2mdist/cjs/[22m[36mmongoose/.export.cjs [39m[1m[2m 0.23 kB[22m[1m[22m
|
|
42
|
+
[2mdist/cjs/[22m[36mrulesStorage.cjs [39m[1m[2m 0.34 kB[22m[1m[22m
|
|
43
|
+
[2mdist/cjs/[22m[36mrule.cjs [39m[1m[2m 0.34 kB[22m[1m[22m
|
|
44
|
+
[2mdist/cjs/[22m[36mredis/.export.cjs [39m[1m[2m 0.36 kB[22m[1m[22m
|
|
45
|
+
[2mdist/cjs/[22m[36mruleInput/.export.cjs [39m[1m[2m 0.46 kB[22m[1m[22m
|
|
46
|
+
[2mdist/cjs/[22m[36mapi/.export.cjs [39m[1m[2m 0.57 kB[22m[1m[22m
|
|
47
|
+
[2mdist/cjs/[22m[36mapi/delete/deleteAllRules.cjs [39m[1m[2m 0.77 kB[22m[1m[22m
|
|
48
|
+
[2mdist/cjs/[22m[36mruleRecord.cjs [39m[1m[2m 0.83 kB[22m[1m[22m
|
|
49
|
+
[2mdist/cjs/[22m[36mapi/read/getMissingIds.cjs [39m[1m[2m 1.15 kB[22m[1m[22m
|
|
50
|
+
[2mdist/cjs/[22m[36mapi/read/fetchRules.cjs [39m[1m[2m 1.22 kB[22m[1m[22m
|
|
51
|
+
[2mdist/cjs/[22m[36m.export.cjs [39m[1m[2m 1.24 kB[22m[1m[22m
|
|
52
|
+
[2mdist/cjs/[22m[36mredis/redisRulesStorage.cjs [39m[1m[2m 1.35 kB[22m[1m[22m
|
|
53
|
+
[2mdist/cjs/[22m[36mmongoose/mongooseRuleSchema.cjs [39m[1m[2m 1.48 kB[22m[1m[22m
|
|
54
|
+
[2mdist/cjs/[22m[36mapi/delete/deleteRules.cjs [39m[1m[2m 1.51 kB[22m[1m[22m
|
|
55
|
+
[2mdist/cjs/[22m[36mapi/delete/deleteRuleGroups.cjs [39m[1m[2m 1.57 kB[22m[1m[22m
|
|
56
|
+
[2mdist/cjs/[22m[36mapi/write/rehashRules.cjs [39m[1m[2m 1.64 kB[22m[1m[22m
|
|
57
|
+
[2mdist/cjs/[22m[36mapi/read/findRuleIds.cjs [39m[1m[2m 1.65 kB[22m[1m[22m
|
|
58
|
+
[2mdist/cjs/[22m[36mruleInput/policyInput.cjs [39m[1m[2m 1.70 kB[22m[1m[22m
|
|
59
|
+
[2mdist/cjs/[22m[36mruleInput/ruleInput.cjs [39m[1m[2m 2.07 kB[22m[1m[22m
|
|
60
|
+
[2mdist/cjs/[22m[36mredis/redisClient.cjs [39m[1m[2m 2.09 kB[22m[1m[22m
|
|
61
|
+
[2mdist/cjs/[22m[36mruleInput/userScopeInput.cjs [39m[1m[2m 2.45 kB[22m[1m[22m
|
|
62
|
+
[2mdist/cjs/[22m[36mredis/redisRuleIndex.cjs [39m[1m[2m 2.46 kB[22m[1m[22m
|
|
63
|
+
[2mdist/cjs/[22m[36mapi/rulesApiClient.cjs [39m[1m[2m 2.60 kB[22m[1m[22m
|
|
64
|
+
[2mdist/cjs/[22m[36mredis/reader/redisAggregate.cjs [39m[1m[2m 2.61 kB[22m[1m[22m
|
|
65
|
+
[2mdist/cjs/[22m[36mtransformRule.cjs [39m[1m[2m 3.05 kB[22m[1m[22m
|
|
66
|
+
[2mdist/cjs/[22m[36mapi/write/insertRules.cjs [39m[1m[2m 3.38 kB[22m[1m[22m
|
|
67
|
+
[2mdist/cjs/[22m[36mredis/redisRulesWriter.cjs [39m[1m[2m 3.44 kB[22m[1m[22m
|
|
68
|
+
[2mdist/cjs/[22m[36mredis/reader/redisRulesQuery.cjs [39m[1m[2m 4.34 kB[22m[1m[22m
|
|
69
|
+
[2mdist/cjs/[22m[36mapi/ruleApiRoutes.cjs [39m[1m[2m 4.55 kB[22m[1m[22m
|
|
70
|
+
[2mdist/cjs/[22m[36mredis/reader/redisRulesReader.cjs [39m[1m[2m10.28 kB[22m[1m[22m
|
|
71
|
+
[32m✓ built in 465ms[39m
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/user-access-policy@3.
|
|
2
|
+
> @prosopo/user-access-policy@3.10.0 build:tsc
|
|
3
3
|
> tsc --build --verbose
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
2:03:13 PM - Projects in this build:
|
|
6
6
|
* ../../dev/config/tsconfig.json
|
|
7
7
|
* ../locale/tsconfig.json
|
|
8
8
|
* ../util/tsconfig.json
|
|
@@ -15,27 +15,27 @@
|
|
|
15
15
|
* ../api/tsconfig.json
|
|
16
16
|
* tsconfig.json
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
2:03:13 PM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/webpack/webpack.config.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
2:03:13 PM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/util.ts' is older than output '../locale/tsconfig.tsbuildinfo'
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
2:03:13 PM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
2:03:13 PM - Project '../logger/tsconfig.json' is up to date because newest input '../logger/src/index.ts' is older than output '../logger/tsconfig.tsbuildinfo'
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
2:03:13 PM - Project '../util-crypto/tsconfig.json' is up to date because newest input '../util-crypto/src/types.ts' is older than output '../util-crypto/tsconfig.tsbuildinfo'
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
2:03:14 PM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/provider/api.ts' is older than output '../types/tsconfig.tsbuildinfo'
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
2:03:14 PM - Project '../common/tsconfig.json' is up to date because newest input '../common/src/index.ts' is older than output '../common/tsconfig.tsbuildinfo'
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
2:03:14 PM - Project '../api-route/tsconfig.json' is up to date because newest input '../api-route/src/apiRoutes.ts' is older than output '../api-route/tsconfig.tsbuildinfo'
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
2:03:14 PM - Project '../redis-client/tsconfig.json' is up to date because newest input '../redis-client/src/index.ts' is older than output '../redis-client/tsconfig.tsbuildinfo'
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
2:03:14 PM - Project '../api/tsconfig.json' is up to date because newest input '../api/src/index.ts' is older than output '../api/tsconfig.tsbuildinfo'
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
2:03:14 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
2:03:14 PM - Building project '/home/runner/work/captcha/captcha/packages/user-access-policy/tsconfig.json'...
|
|
41
41
|
|
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/user-access-policy@3.
|
|
2
|
+
> @prosopo/user-access-policy@3.10.0 build
|
|
3
3
|
> npm run build:cross-env -- --mode ${NODE_ENV:-development}
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @prosopo/user-access-policy@3.
|
|
6
|
+
> @prosopo/user-access-policy@3.10.0 build:cross-env
|
|
7
7
|
> vite build --config vite.esm.config.ts --mode production
|
|
8
8
|
|
|
9
9
|
ViteEsmConfig: .
|
|
@@ -61,15 +61,15 @@ rendering chunks...
|
|
|
61
61
|
[2mdist/[22m[36mapi/read/findRuleIds.js [39m[1m[2m1.54 kB[22m[1m[22m
|
|
62
62
|
[2mdist/[22m[36mapi/write/rehashRules.js [39m[1m[2m1.54 kB[22m[1m[22m
|
|
63
63
|
[2mdist/[22m[36mruleInput/ruleInput.js [39m[1m[2m1.72 kB[22m[1m[22m
|
|
64
|
-
[2mdist/[22m[36mredis/reader/redisAggregate.js [39m[1m[2m1.80 kB[22m[1m[22m
|
|
65
64
|
[2mdist/[22m[36mredis/redisClient.js [39m[1m[2m1.90 kB[22m[1m[22m
|
|
66
65
|
[2mdist/[22m[36mredis/redisRuleIndex.js [39m[1m[2m2.01 kB[22m[1m[22m
|
|
67
66
|
[2mdist/[22m[36mruleInput/userScopeInput.js [39m[1m[2m2.22 kB[22m[1m[22m
|
|
68
67
|
[2mdist/[22m[36mapi/rulesApiClient.js [39m[1m[2m2.36 kB[22m[1m[22m
|
|
68
|
+
[2mdist/[22m[36mredis/reader/redisAggregate.js [39m[1m[2m2.46 kB[22m[1m[22m
|
|
69
69
|
[2mdist/[22m[36mtransformRule.js [39m[1m[2m2.76 kB[22m[1m[22m
|
|
70
70
|
[2mdist/[22m[36mapi/write/insertRules.js [39m[1m[2m3.22 kB[22m[1m[22m
|
|
71
71
|
[2mdist/[22m[36mredis/redisRulesWriter.js [39m[1m[2m3.22 kB[22m[1m[22m
|
|
72
72
|
[2mdist/[22m[36mredis/reader/redisRulesQuery.js [39m[1m[2m4.15 kB[22m[1m[22m
|
|
73
73
|
[2mdist/[22m[36mapi/ruleApiRoutes.js [39m[1m[2m4.33 kB[22m[1m[22m
|
|
74
|
-
[2mdist/[22m[36mredis/reader/redisRulesReader.js [39m[1m[
|
|
74
|
+
[2mdist/[22m[36mredis/reader/redisRulesReader.js [39m[1m[2m9.40 kB[22m[1m[22m
|
|
75
75
|
[32m✓ built in 499ms[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @prosopo/user-access-policy
|
|
2
2
|
|
|
3
|
+
## 3.10.0
|
|
4
|
+
### Minor Changes
|
|
5
|
+
|
|
6
|
+
- c1c7998: Server-side specificity rank for the access-rule lookup. Strict-match callers (the `blockMiddleware` and the verify-time `checkForHardBlock`) now issue one `FT.AGGREGATE` with `APPLY exists()` for specificity, `APPLY @type == "block"` for the severity tiebreak, `SORTBY @_rank DESC`, and `LIMIT 0 20`. Node receives at most 20 fully-populated rules — no follow-up HGETALL per candidate, no JS-side rank, no silent truncation past the LIMIT (which only applies after Redis has scored every candidate the strict filter returned).
|
|
7
|
+
|
|
8
|
+
Supersedes both the v3.6.38 regression (`b520cd94c` — FT.AGGREGATE WITHCURSOR materialising ~1190 hashes per request, pegged provider1 at ~125% CPU on pronode10) and the 3.6.38-hotfix1 shape that reverted to FT.SEARCH (re-opened the 1000-candidate silent-truncation bug). The greedy/admin path (`matchingFieldsOnly=false`) keeps the FT.AGGREGATE+CURSOR approach with a generous `GREEDY_MAX_CANDIDATES` cap since those callers do not run on the per-request hot path.
|
|
9
|
+
|
|
10
|
+
`packages/provider/src/api/blacklistRequestInspector.ts` flips `getPrioritisedAccessRule` to `matchingFieldsOnly: true` to engage the new path. The defensive JS `rankCandidateRules` is kept so any drift between the Redis-side score and the JS semantics surfaces as ordering, not as letting traffic through. New benchmark integration test seeds 10k rules across a realistic specificity distribution and asserts p50 < 80ms / p99 < 250ms over 200 lookups; local measurement is steady at p50 ≈ 20ms, p99 ≈ 24ms.
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Updated dependencies [9b91e85]
|
|
15
|
+
- Updated dependencies [c80a05b]
|
|
16
|
+
- @prosopo/types@4.5.0
|
|
17
|
+
- @prosopo/api@3.4.12
|
|
18
|
+
|
|
19
|
+
## 3.9.1
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- b520cd9: Paginate the greedy `findRules` RediSearch query via `FT.AGGREGATE WITHCURSOR` so the candidate set is no longer truncated at `REDIS_BATCH_SIZE` (1000). Under high-volume bot traffic, a single popular ja4 fingerprint can be carried by thousands of rules; the OR-style greedy query returned > 1000 candidates and `FT.SEARCH`'s LIMIT silently dropped the tail — block rules emitted by less-frequent detectors sat past offset 1000 and never reached the JS-side specificity sort, letting matching requests through. Aggregation cursors return the full result set, so ranking sees every candidate.
|
|
23
|
+
|
|
3
24
|
## 3.9.0
|
|
4
25
|
### Minor Changes
|
|
5
26
|
|
|
@@ -4,19 +4,36 @@ const zod = require("zod");
|
|
|
4
4
|
const redisRulesQuery = require("./redisRulesQuery.cjs");
|
|
5
5
|
const redisClient = require("../redisClient.cjs");
|
|
6
6
|
const redisRuleIndex = require("../redisRuleIndex.cjs");
|
|
7
|
-
const aggregateRedisKeys = async (client, query, logger, batchHandler) => {
|
|
7
|
+
const aggregateRedisKeys = async (client, query, logger, batchHandler, maxKeys) => {
|
|
8
8
|
const keyField = "__key";
|
|
9
9
|
const recordSchema = zod.z.object({
|
|
10
10
|
// it's a reserved name for the record key
|
|
11
11
|
[keyField]: zod.z.string()
|
|
12
12
|
});
|
|
13
13
|
const foundKeys = [];
|
|
14
|
+
let stopRequested = false;
|
|
14
15
|
const addRecordKeys = async (records) => {
|
|
16
|
+
if (stopRequested) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
15
19
|
const parsedRecords = redisClient.parseRedisRecords(records, recordSchema, logger);
|
|
16
20
|
const recordKeys = parsedRecords.map((record) => record[keyField]);
|
|
17
21
|
if (batchHandler) {
|
|
18
22
|
await batchHandler(recordKeys);
|
|
19
23
|
} else {
|
|
24
|
+
if (maxKeys !== void 0 && foundKeys.length + recordKeys.length > maxKeys) {
|
|
25
|
+
const remaining = Math.max(0, maxKeys - foundKeys.length);
|
|
26
|
+
foundKeys.push(...recordKeys.slice(0, remaining));
|
|
27
|
+
stopRequested = true;
|
|
28
|
+
logger.warn(() => ({
|
|
29
|
+
msg: "Redis aggregation candidate cap hit; truncating result set. This can suppress less-frequent rules and should be investigated.",
|
|
30
|
+
data: {
|
|
31
|
+
maxKeys,
|
|
32
|
+
query
|
|
33
|
+
}
|
|
34
|
+
}));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
20
37
|
foundKeys.push(...recordKeys);
|
|
21
38
|
logger.debug(() => ({
|
|
22
39
|
msg: "Processed aggregation batch",
|
|
@@ -35,11 +52,12 @@ const aggregateRedisKeys = async (client, query, logger, batchHandler) => {
|
|
|
35
52
|
COUNT: redisClient.REDIS_BATCH_SIZE,
|
|
36
53
|
LOAD: `@${keyField}`
|
|
37
54
|
},
|
|
38
|
-
addRecordKeys
|
|
55
|
+
addRecordKeys,
|
|
56
|
+
() => stopRequested
|
|
39
57
|
);
|
|
40
58
|
return foundKeys;
|
|
41
59
|
};
|
|
42
|
-
const executeAggregation = async (client, query, aggregateOptions, handleBatch) => {
|
|
60
|
+
const executeAggregation = async (client, query, aggregateOptions, handleBatch, shouldStop) => {
|
|
43
61
|
const initialReply = await client.ft.aggregateWithCursor(
|
|
44
62
|
redisRuleIndex.ACCESS_RULES_REDIS_INDEX_NAME,
|
|
45
63
|
query,
|
|
@@ -47,7 +65,7 @@ const executeAggregation = async (client, query, aggregateOptions, handleBatch)
|
|
|
47
65
|
);
|
|
48
66
|
await handleBatch(initialReply.results);
|
|
49
67
|
let cursor = initialReply.cursor;
|
|
50
|
-
while (0 !== cursor) {
|
|
68
|
+
while (0 !== cursor && !shouldStop?.()) {
|
|
51
69
|
const batchReply = await client.ft.cursorRead(
|
|
52
70
|
redisRuleIndex.ACCESS_RULES_REDIS_INDEX_NAME,
|
|
53
71
|
cursor,
|
|
@@ -5,6 +5,7 @@ const common = require("@prosopo/common");
|
|
|
5
5
|
const redisRulesQuery = require("./redisRulesQuery.cjs");
|
|
6
6
|
const redisClient = require("../redisClient.cjs");
|
|
7
7
|
const redisRuleIndex = require("../redisRuleIndex.cjs");
|
|
8
|
+
const rule = require("../../rule.cjs");
|
|
8
9
|
const ruleInput = require("../../ruleInput/ruleInput.cjs");
|
|
9
10
|
const redisAggregate = require("./redisAggregate.cjs");
|
|
10
11
|
function _interopNamespaceDefault(e) {
|
|
@@ -24,6 +25,48 @@ function _interopNamespaceDefault(e) {
|
|
|
24
25
|
return Object.freeze(n);
|
|
25
26
|
}
|
|
26
27
|
const util__namespace = /* @__PURE__ */ _interopNamespaceDefault(util);
|
|
28
|
+
const SERVER_SIDE_RANK_TOP_N = 20;
|
|
29
|
+
const GREEDY_MAX_CANDIDATES = redisClient.REDIS_BATCH_SIZE * 10;
|
|
30
|
+
const SPECIFICITY_EXPR = [
|
|
31
|
+
"exists(@clientId)",
|
|
32
|
+
"exists(@userId)",
|
|
33
|
+
"exists(@ja4Hash)",
|
|
34
|
+
"exists(@headersHash)",
|
|
35
|
+
"exists(@userAgentHash)",
|
|
36
|
+
"exists(@headHash)",
|
|
37
|
+
"exists(@coords)",
|
|
38
|
+
"exists(@countryCode)",
|
|
39
|
+
"exists(@asn)",
|
|
40
|
+
"exists(@numericIp)",
|
|
41
|
+
"exists(@numericIpMaskMin)"
|
|
42
|
+
].join(" + ");
|
|
43
|
+
const SEVERITY_EXPR = `(@type == "${rule.AccessPolicyType.Block}")`;
|
|
44
|
+
const RANK_EXPR = "(@_spec * 2) + @_sev";
|
|
45
|
+
const RULE_LOAD_FIELDS = [
|
|
46
|
+
"@__key",
|
|
47
|
+
"@type",
|
|
48
|
+
"@captchaType",
|
|
49
|
+
"@description",
|
|
50
|
+
"@solvedImagesCount",
|
|
51
|
+
"@imageThreshold",
|
|
52
|
+
"@powDifficulty",
|
|
53
|
+
"@unsolvedImagesCount",
|
|
54
|
+
"@frictionlessScore",
|
|
55
|
+
"@deferToVerify",
|
|
56
|
+
"@clientId",
|
|
57
|
+
"@groupId",
|
|
58
|
+
"@userId",
|
|
59
|
+
"@ja4Hash",
|
|
60
|
+
"@headersHash",
|
|
61
|
+
"@userAgentHash",
|
|
62
|
+
"@headHash",
|
|
63
|
+
"@coords",
|
|
64
|
+
"@countryCode",
|
|
65
|
+
"@asn",
|
|
66
|
+
"@numericIp",
|
|
67
|
+
"@numericIpMaskMin",
|
|
68
|
+
"@numericIpMaskMax"
|
|
69
|
+
];
|
|
27
70
|
class RedisRulesReader {
|
|
28
71
|
constructor(client, logger) {
|
|
29
72
|
this.client = client;
|
|
@@ -52,40 +95,102 @@ class RedisRulesReader {
|
|
|
52
95
|
if (skipEmptyUserScopes && query === "ismissing(@clientId)") {
|
|
53
96
|
return [];
|
|
54
97
|
}
|
|
98
|
+
if (matchingFieldsOnly) {
|
|
99
|
+
return this.findRulesRanked(filter, query);
|
|
100
|
+
}
|
|
101
|
+
return this.findRulesGreedy(filter, query);
|
|
102
|
+
}
|
|
103
|
+
async findRulesRanked(filter, query) {
|
|
55
104
|
try {
|
|
56
|
-
const
|
|
105
|
+
const reply = await this.client.ft.aggregate(
|
|
57
106
|
redisRuleIndex.ACCESS_RULES_REDIS_INDEX_NAME,
|
|
58
107
|
query,
|
|
59
108
|
{
|
|
60
109
|
DIALECT: redisRulesQuery.REDIS_QUERY_DIALECT,
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
110
|
+
LOAD: [...RULE_LOAD_FIELDS],
|
|
111
|
+
STEPS: [
|
|
112
|
+
{ type: "APPLY", expression: SPECIFICITY_EXPR, AS: "_spec" },
|
|
113
|
+
{ type: "APPLY", expression: SEVERITY_EXPR, AS: "_sev" },
|
|
114
|
+
{ type: "APPLY", expression: RANK_EXPR, AS: "_rank" },
|
|
115
|
+
{
|
|
116
|
+
type: "SORTBY",
|
|
117
|
+
BY: [{ BY: "@_rank", DIRECTION: "DESC" }]
|
|
118
|
+
// SORTBY MAX would let RediSearch keep only the
|
|
119
|
+
// top-N in a bounded heap rather than fully
|
|
120
|
+
// sorting, but the @redis/search client
|
|
121
|
+
// serialises MAX *before* DESC and RediSearch
|
|
122
|
+
// rejects that order ("MISSING ASC or DESC
|
|
123
|
+
// after sort field (MAX)"). LIMIT below still
|
|
124
|
+
// trims; SORTBY does a full sort. Acceptable
|
|
125
|
+
// because the strict-match filter already
|
|
126
|
+
// keeps the candidate set small in practice.
|
|
127
|
+
},
|
|
128
|
+
{ type: "LIMIT", from: 0, size: SERVER_SIDE_RANK_TOP_N }
|
|
129
|
+
]
|
|
66
130
|
}
|
|
67
131
|
);
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
msg: "Executed search query",
|
|
71
|
-
data: {
|
|
72
|
-
inspect: util__namespace.inspect(
|
|
73
|
-
{
|
|
74
|
-
filter,
|
|
75
|
-
searchReply,
|
|
76
|
-
query
|
|
77
|
-
},
|
|
78
|
-
{ depth: null }
|
|
79
|
-
)
|
|
80
|
-
}
|
|
81
|
-
}));
|
|
132
|
+
if (reply.results.length === 0) {
|
|
133
|
+
return [];
|
|
82
134
|
}
|
|
83
|
-
|
|
135
|
+
this.logger.debug(() => ({
|
|
136
|
+
msg: "Executed ranked search query",
|
|
137
|
+
data: {
|
|
138
|
+
inspect: util__namespace.inspect(
|
|
139
|
+
{
|
|
140
|
+
filter,
|
|
141
|
+
foundCount: reply.results.length,
|
|
142
|
+
query
|
|
143
|
+
},
|
|
144
|
+
{ depth: null }
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
}));
|
|
148
|
+
return redisClient.parseRedisRecords(reply.results, ruleInput.accessRuleInput, this.logger);
|
|
149
|
+
} catch (e) {
|
|
150
|
+
this.logger.error(() => ({
|
|
151
|
+
err: e,
|
|
152
|
+
data: {
|
|
153
|
+
inspect: util__namespace.inspect({ query, filter }, { depth: null })
|
|
154
|
+
},
|
|
155
|
+
msg: "failed to execute ranked search query"
|
|
156
|
+
}));
|
|
157
|
+
return [];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Used only by admin / internal callers (matchingFieldsOnly=false).
|
|
161
|
+
// Not on the per-request blockMiddleware path any more, so the CPU
|
|
162
|
+
// cost of the HGETALL fanout is acceptable. Same shape as #2689's
|
|
163
|
+
// aggregate-with-cursor: returns every candidate up to
|
|
164
|
+
// GREEDY_MAX_CANDIDATES so we don't silently drop matches that
|
|
165
|
+
// admin tools depend on (e.g. ASN-wide rule listings).
|
|
166
|
+
async findRulesGreedy(filter, query) {
|
|
167
|
+
try {
|
|
168
|
+
const ruleKeys = await redisAggregate.aggregateRedisKeys(
|
|
169
|
+
this.client,
|
|
170
|
+
query,
|
|
171
|
+
this.logger,
|
|
172
|
+
void 0,
|
|
173
|
+
GREEDY_MAX_CANDIDATES
|
|
174
|
+
);
|
|
175
|
+
if (ruleKeys.length === 0) {
|
|
84
176
|
return [];
|
|
85
177
|
}
|
|
178
|
+
this.logger.debug(() => ({
|
|
179
|
+
msg: "Executed greedy search query",
|
|
180
|
+
data: {
|
|
181
|
+
inspect: util__namespace.inspect(
|
|
182
|
+
{
|
|
183
|
+
filter,
|
|
184
|
+
foundCount: ruleKeys.length,
|
|
185
|
+
query
|
|
186
|
+
},
|
|
187
|
+
{ depth: null }
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
}));
|
|
86
191
|
const { records } = await redisClient.fetchRedisHashRecords(
|
|
87
192
|
this.client,
|
|
88
|
-
|
|
193
|
+
ruleKeys,
|
|
89
194
|
this.logger
|
|
90
195
|
);
|
|
91
196
|
const nonEmptyRecords = records.filter(
|
|
@@ -96,17 +201,9 @@ class RedisRulesReader {
|
|
|
96
201
|
this.logger.error(() => ({
|
|
97
202
|
err: e,
|
|
98
203
|
data: {
|
|
99
|
-
inspect: util__namespace.inspect(
|
|
100
|
-
{
|
|
101
|
-
query,
|
|
102
|
-
filter
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
depth: null
|
|
106
|
-
}
|
|
107
|
-
)
|
|
204
|
+
inspect: util__namespace.inspect({ query, filter }, { depth: null })
|
|
108
205
|
},
|
|
109
|
-
msg: "failed to execute search query"
|
|
206
|
+
msg: "failed to execute greedy search query"
|
|
110
207
|
}));
|
|
111
208
|
return [];
|
|
112
209
|
}
|
|
@@ -170,14 +267,14 @@ class RedisRulesReader {
|
|
|
170
267
|
for (const [index, ruleData] of records.entries()) {
|
|
171
268
|
const isRulePresent = Object.keys(ruleData).length > 0;
|
|
172
269
|
if (isRulePresent) {
|
|
173
|
-
const
|
|
270
|
+
const rule2 = redisClient.parseRedisRecords(
|
|
174
271
|
[ruleData],
|
|
175
272
|
ruleInput.accessRuleInput,
|
|
176
273
|
this.logger
|
|
177
274
|
)[0];
|
|
178
|
-
if (
|
|
275
|
+
if (rule2) {
|
|
179
276
|
entries.push({
|
|
180
|
-
rule,
|
|
277
|
+
rule: rule2,
|
|
181
278
|
expiresUnixTimestamp: expirations[index]
|
|
182
279
|
});
|
|
183
280
|
}
|
|
@@ -237,3 +334,4 @@ class DummyRedisRulesReader {
|
|
|
237
334
|
}
|
|
238
335
|
exports.DummyRedisRulesReader = DummyRedisRulesReader;
|
|
239
336
|
exports.RedisRulesReader = RedisRulesReader;
|
|
337
|
+
exports.SERVER_SIDE_RANK_TOP_N = SERVER_SIDE_RANK_TOP_N;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Logger } from "@prosopo/logger";
|
|
2
2
|
import type { RedisClientType } from "redis";
|
|
3
|
-
export declare const aggregateRedisKeys: (client: RedisClientType, query: string, logger: Logger, batchHandler?: (keys: string[]) => Promise<void
|
|
3
|
+
export declare const aggregateRedisKeys: (client: RedisClientType, query: string, logger: Logger, batchHandler?: (keys: string[]) => Promise<void>, maxKeys?: number) => Promise<string[]>;
|
|
4
4
|
//# sourceMappingURL=redisAggregate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redisAggregate.d.ts","sourceRoot":"","sources":["../../../src/redis/reader/redisAggregate.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAU7C,eAAO,MAAM,kBAAkB,WACtB,eAAe,SAChB,MAAM,UACL,MAAM,iBACC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"redisAggregate.d.ts","sourceRoot":"","sources":["../../../src/redis/reader/redisAggregate.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAU7C,eAAO,MAAM,kBAAkB,WACtB,eAAe,SAChB,MAAM,UACL,MAAM,iBACC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,YACtC,MAAM,KACd,OAAO,CAAC,MAAM,EAAE,CAkElB,CAAC"}
|
|
@@ -2,19 +2,36 @@ import { z } from "zod";
|
|
|
2
2
|
import { REDIS_QUERY_DIALECT } from "./redisRulesQuery.js";
|
|
3
3
|
import { parseRedisRecords, REDIS_BATCH_SIZE } from "../redisClient.js";
|
|
4
4
|
import { ACCESS_RULES_REDIS_INDEX_NAME } from "../redisRuleIndex.js";
|
|
5
|
-
const aggregateRedisKeys = async (client, query, logger, batchHandler) => {
|
|
5
|
+
const aggregateRedisKeys = async (client, query, logger, batchHandler, maxKeys) => {
|
|
6
6
|
const keyField = "__key";
|
|
7
7
|
const recordSchema = z.object({
|
|
8
8
|
// it's a reserved name for the record key
|
|
9
9
|
[keyField]: z.string()
|
|
10
10
|
});
|
|
11
11
|
const foundKeys = [];
|
|
12
|
+
let stopRequested = false;
|
|
12
13
|
const addRecordKeys = async (records) => {
|
|
14
|
+
if (stopRequested) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
13
17
|
const parsedRecords = parseRedisRecords(records, recordSchema, logger);
|
|
14
18
|
const recordKeys = parsedRecords.map((record) => record[keyField]);
|
|
15
19
|
if (batchHandler) {
|
|
16
20
|
await batchHandler(recordKeys);
|
|
17
21
|
} else {
|
|
22
|
+
if (maxKeys !== void 0 && foundKeys.length + recordKeys.length > maxKeys) {
|
|
23
|
+
const remaining = Math.max(0, maxKeys - foundKeys.length);
|
|
24
|
+
foundKeys.push(...recordKeys.slice(0, remaining));
|
|
25
|
+
stopRequested = true;
|
|
26
|
+
logger.warn(() => ({
|
|
27
|
+
msg: "Redis aggregation candidate cap hit; truncating result set. This can suppress less-frequent rules and should be investigated.",
|
|
28
|
+
data: {
|
|
29
|
+
maxKeys,
|
|
30
|
+
query
|
|
31
|
+
}
|
|
32
|
+
}));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
18
35
|
foundKeys.push(...recordKeys);
|
|
19
36
|
logger.debug(() => ({
|
|
20
37
|
msg: "Processed aggregation batch",
|
|
@@ -33,11 +50,12 @@ const aggregateRedisKeys = async (client, query, logger, batchHandler) => {
|
|
|
33
50
|
COUNT: REDIS_BATCH_SIZE,
|
|
34
51
|
LOAD: `@${keyField}`
|
|
35
52
|
},
|
|
36
|
-
addRecordKeys
|
|
53
|
+
addRecordKeys,
|
|
54
|
+
() => stopRequested
|
|
37
55
|
);
|
|
38
56
|
return foundKeys;
|
|
39
57
|
};
|
|
40
|
-
const executeAggregation = async (client, query, aggregateOptions, handleBatch) => {
|
|
58
|
+
const executeAggregation = async (client, query, aggregateOptions, handleBatch, shouldStop) => {
|
|
41
59
|
const initialReply = await client.ft.aggregateWithCursor(
|
|
42
60
|
ACCESS_RULES_REDIS_INDEX_NAME,
|
|
43
61
|
query,
|
|
@@ -45,7 +63,7 @@ const executeAggregation = async (client, query, aggregateOptions, handleBatch)
|
|
|
45
63
|
);
|
|
46
64
|
await handleBatch(initialReply.results);
|
|
47
65
|
let cursor = initialReply.cursor;
|
|
48
|
-
while (0 !== cursor) {
|
|
66
|
+
while (0 !== cursor && !shouldStop?.()) {
|
|
49
67
|
const batchReply = await client.ft.cursorRead(
|
|
50
68
|
ACCESS_RULES_REDIS_INDEX_NAME,
|
|
51
69
|
cursor,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redisAggregate.js","sourceRoot":"","sources":["../../../src/redis/reader/redisAggregate.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAC9E,OAAO,EACN,gBAAgB,EAChB,iBAAiB,GACjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,6BAA6B,EAAE,MAAM,iCAAiC,CAAC;AAGhF,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,EACtC,MAAuB,EACvB,KAAa,EACb,MAAc,EACd,YAAgD,
|
|
1
|
+
{"version":3,"file":"redisAggregate.js","sourceRoot":"","sources":["../../../src/redis/reader/redisAggregate.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { Logger } from "@prosopo/logger";
|
|
2
2
|
import type { RedisClientType } from "redis";
|
|
3
|
-
import type
|
|
3
|
+
import { type AccessRule } from "#policy/rule.js";
|
|
4
4
|
import type { AccessRuleEntry, AccessRulesFilter, AccessRulesReader } from "#policy/rulesStorage.js";
|
|
5
|
+
export declare const SERVER_SIDE_RANK_TOP_N = 20;
|
|
5
6
|
export declare class RedisRulesReader implements AccessRulesReader {
|
|
6
7
|
private readonly client;
|
|
7
8
|
private readonly logger;
|
|
@@ -9,6 +10,8 @@ export declare class RedisRulesReader implements AccessRulesReader {
|
|
|
9
10
|
getMissingRuleIds(ruleIds: string[]): Promise<string[]>;
|
|
10
11
|
fetchRules(ruleIds: string[]): Promise<AccessRuleEntry[]>;
|
|
11
12
|
findRules(filter: AccessRulesFilter, matchingFieldsOnly?: boolean, skipEmptyUserScopes?: boolean): Promise<AccessRule[]>;
|
|
13
|
+
private findRulesRanked;
|
|
14
|
+
private findRulesGreedy;
|
|
12
15
|
findRuleIds(filter: AccessRulesFilter, matchingFieldsOnly?: boolean): Promise<string[]>;
|
|
13
16
|
fetchAllRuleIds(batchHandler: (ruleIds: string[]) => Promise<void>): Promise<void>;
|
|
14
17
|
protected fetchRuleEntries(keys: string[]): Promise<AccessRuleEntry[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redisRulesReader.d.ts","sourceRoot":"","sources":["../../../src/redis/reader/redisRulesReader.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAe7C,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"redisRulesReader.d.ts","sourceRoot":"","sources":["../../../src/redis/reader/redisRulesReader.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAe7C,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEpE,OAAO,KAAK,EACX,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,MAAM,yBAAyB,CAAC;AAoBjC,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAoEzC,qBAAa,gBAAiB,YAAW,iBAAiB;IAExD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM;IAG1B,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAcvD,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAazD,SAAS,CACd,MAAM,EAAE,iBAAiB,EACzB,kBAAkB,UAAQ,EAC1B,mBAAmB,UAAO,GACxB,OAAO,CAAC,UAAU,EAAE,CAAC;YAuBV,eAAe;YA2Ef,eAAe;IAuDvB,WAAW,CAChB,MAAM,EAAE,iBAAiB,EACzB,kBAAkB,UAAQ,GACxB,OAAO,CAAC,MAAM,EAAE,CAAC;IAgDd,eAAe,CACpB,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAChD,OAAO,CAAC,IAAI,CAAC;cAYA,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA8B5E,SAAS,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE;CAGlD;AAED,qBAAa,qBAAsB,YAAW,iBAAiB;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAErC,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAWvD,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAWzD,SAAS,CACd,MAAM,EAAE,iBAAiB,EACzB,kBAAkB,UAAQ,EAC1B,mBAAmB,UAAO,GACxB,OAAO,CAAC,UAAU,EAAE,CAAC;IAWlB,WAAW,CAChB,MAAM,EAAE,iBAAiB,EACzB,kBAAkB,UAAQ,GACxB,OAAO,CAAC,MAAM,EAAE,CAAC;IAWd,eAAe,CACpB,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAChD,OAAO,CAAC,IAAI,CAAC;CAKhB"}
|