@via-profit/ability 3.6.2 → 3.6.5
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/dist/index.cjs +3380 -0
- package/dist/index.d.ts +51 -3
- package/dist/index.js +157 -73
- package/package.json +9 -2
package/dist/index.d.ts
CHANGED
|
@@ -218,14 +218,14 @@ type AbilityExplainConfig = {
|
|
|
218
218
|
readonly type: AbilityExplainType;
|
|
219
219
|
readonly name: string;
|
|
220
220
|
readonly match: AbilityMatchType;
|
|
221
|
-
readonly debugInfo?:
|
|
221
|
+
readonly debugInfo?: string;
|
|
222
222
|
};
|
|
223
223
|
declare class AbilityExplain {
|
|
224
224
|
readonly type: AbilityExplainType;
|
|
225
225
|
readonly children: AbilityExplain[];
|
|
226
226
|
readonly name: string;
|
|
227
227
|
readonly match: AbilityMatchType;
|
|
228
|
-
readonly debugInfo?:
|
|
228
|
+
readonly debugInfo?: string;
|
|
229
229
|
constructor(config: AbilityExplainConfig, children?: AbilityExplain[]);
|
|
230
230
|
toString(indentPrefix?: string, isLast?: boolean): string;
|
|
231
231
|
}
|
|
@@ -396,10 +396,40 @@ declare abstract class AbilityStrategy<Resource extends ResourceObject = Record<
|
|
|
396
396
|
readonly policies: readonly AbilityPolicy<Resource, Environment>[];
|
|
397
397
|
private readonly matched;
|
|
398
398
|
constructor(policies: readonly AbilityPolicy<Resource, Environment>[]);
|
|
399
|
+
/**
|
|
400
|
+
* Executes the strategy’s decision logic and returns the final policy effect
|
|
401
|
+
* (permit or deny).
|
|
402
|
+
*
|
|
403
|
+
* Each concrete strategy must implement its own evaluation rules:
|
|
404
|
+
* - how matched policies are interpreted,
|
|
405
|
+
* - how priority, order, or overrides are applied,
|
|
406
|
+
* - and how the final effect is determined.
|
|
407
|
+
*
|
|
408
|
+
* The implementation must also record the policy that actually determined
|
|
409
|
+
* the outcome (if any), so that decisivePolicy() can later expose it.
|
|
410
|
+
*/
|
|
399
411
|
abstract evaluate(): AbilityPolicyEffectType;
|
|
412
|
+
/**
|
|
413
|
+
* Returns the policy that directly determined the final decision of the strategy.
|
|
414
|
+
*
|
|
415
|
+
* This is:
|
|
416
|
+
* - the specific policy chosen by the strategy’s evaluation rules, or
|
|
417
|
+
* - null if the decision was made by default (e.g., no matched policies,
|
|
418
|
+
* or the strategy cannot identify a single decisive policy).
|
|
419
|
+
*
|
|
420
|
+
* This method performs no computation; it simply exposes the result stored
|
|
421
|
+
* during evaluate(), enabling explainability and debugging tools to show
|
|
422
|
+
* why a decision was made.
|
|
423
|
+
*/
|
|
424
|
+
abstract decisivePolicy(): AbilityPolicy<Resource, Environment> | null;
|
|
400
425
|
matchedPolicies(): readonly AbilityPolicy<Resource, Environment, string>[];
|
|
426
|
+
hasMatched(): boolean;
|
|
401
427
|
protected firstMatched(): AbilityPolicy<Resource, Environment> | null;
|
|
402
428
|
protected lastMatched(): AbilityPolicy<Resource, Environment> | null;
|
|
429
|
+
protected firstDenied(): AbilityPolicy<Resource, Environment> | null;
|
|
430
|
+
protected firstPermitted(): AbilityPolicy<Resource, Environment> | null;
|
|
431
|
+
protected getPermitPolicies(): AbilityPolicy<Resource, Environment, string>[];
|
|
432
|
+
protected getDenyPolicies(): AbilityPolicy<Resource, Environment, string>[];
|
|
403
433
|
protected hasPermit(): boolean;
|
|
404
434
|
protected hasDeny(): boolean;
|
|
405
435
|
isAllowed(): boolean;
|
|
@@ -416,7 +446,9 @@ declare class AbilityResult<R extends ResourceObject = Record<string, unknown>,
|
|
|
416
446
|
*
|
|
417
447
|
* Useful for debugging, logging, or building UI tools that visualize permission logic.
|
|
418
448
|
*/
|
|
419
|
-
explain():
|
|
449
|
+
explain(): string;
|
|
450
|
+
decisive(): AbilityPolicy<R, E, string> | null;
|
|
451
|
+
explainDecisive(): string | null;
|
|
420
452
|
isAllowed: () => boolean;
|
|
421
453
|
isDenied: () => boolean;
|
|
422
454
|
}
|
|
@@ -659,7 +691,9 @@ declare function ability<R extends ResourceObject = Record<string, unknown>, E e
|
|
|
659
691
|
* Result: deny (because not all policies permitted)
|
|
660
692
|
*/
|
|
661
693
|
declare class AllMustPermitStrategy<R extends ResourceObject, E extends EnvironmentObject = Record<string, unknown>> extends AbilityStrategy<R, E> {
|
|
694
|
+
private _decisive;
|
|
662
695
|
evaluate(): AbilityPolicyEffectType;
|
|
696
|
+
decisivePolicy(): AbilityPolicy<R, E, string> | null;
|
|
663
697
|
}
|
|
664
698
|
|
|
665
699
|
/**
|
|
@@ -680,7 +714,9 @@ declare class AllMustPermitStrategy<R extends ResourceObject, E extends Environm
|
|
|
680
714
|
* Result: permit (because at least one policy permitted)
|
|
681
715
|
*/
|
|
682
716
|
declare class AnyPermitStrategy<R extends ResourceObject, E extends EnvironmentObject = Record<string, unknown>> extends AbilityStrategy<R, E> {
|
|
717
|
+
private _decisive;
|
|
683
718
|
evaluate(): AbilityPolicyEffectType;
|
|
719
|
+
decisivePolicy(): AbilityPolicy<R, E, string> | null;
|
|
684
720
|
}
|
|
685
721
|
|
|
686
722
|
/**
|
|
@@ -702,7 +738,9 @@ declare class AnyPermitStrategy<R extends ResourceObject, E extends EnvironmentO
|
|
|
702
738
|
* Result: deny (because deny overrides everything)
|
|
703
739
|
*/
|
|
704
740
|
declare class DenyOverridesStrategy<R extends ResourceObject, E extends EnvironmentObject = Record<string, unknown>> extends AbilityStrategy<R, E> {
|
|
741
|
+
private _decisive;
|
|
705
742
|
evaluate(): AbilityPolicyEffectType;
|
|
743
|
+
decisivePolicy(): AbilityPolicy<R, E, string> | null;
|
|
706
744
|
}
|
|
707
745
|
|
|
708
746
|
/**
|
|
@@ -723,7 +761,9 @@ declare class DenyOverridesStrategy<R extends ResourceObject, E extends Environm
|
|
|
723
761
|
* Result: permit (P2 is the first applicable)
|
|
724
762
|
*/
|
|
725
763
|
declare class FirstMatchStrategy<R extends ResourceObject, E extends EnvironmentObject = Record<string, unknown>> extends AbilityStrategy<R, E> {
|
|
764
|
+
private _decisive;
|
|
726
765
|
evaluate(): AbilityPolicyEffectType;
|
|
766
|
+
decisivePolicy(): AbilityPolicy<R, E, string> | null;
|
|
727
767
|
}
|
|
728
768
|
|
|
729
769
|
/**
|
|
@@ -743,7 +783,9 @@ declare class FirstMatchStrategy<R extends ResourceObject, E extends Environment
|
|
|
743
783
|
* Result: deny (more than one applicable policy)
|
|
744
784
|
*/
|
|
745
785
|
declare class OnlyOneApplicableStrategy<R extends ResourceObject, E extends EnvironmentObject = Record<string, unknown>> extends AbilityStrategy<R, E> {
|
|
786
|
+
private _decisive;
|
|
746
787
|
evaluate(): AbilityPolicyEffectType;
|
|
788
|
+
decisivePolicy(): AbilityPolicy<R, E, string> | null;
|
|
747
789
|
}
|
|
748
790
|
|
|
749
791
|
/**
|
|
@@ -765,7 +807,9 @@ declare class OnlyOneApplicableStrategy<R extends ResourceObject, E extends Envi
|
|
|
765
807
|
* Result: permit (permit overrides deny)
|
|
766
808
|
*/
|
|
767
809
|
declare class PermitOverridesStrategy<R extends ResourceObject, E extends EnvironmentObject = Record<string, unknown>> extends AbilityStrategy<R, E> {
|
|
810
|
+
private _decisive;
|
|
768
811
|
evaluate(): AbilityPolicyEffectType;
|
|
812
|
+
decisivePolicy(): AbilityPolicy<R, E, string> | null;
|
|
769
813
|
}
|
|
770
814
|
|
|
771
815
|
/**
|
|
@@ -785,7 +829,9 @@ declare class PermitOverridesStrategy<R extends ResourceObject, E extends Enviro
|
|
|
785
829
|
* Result: permit (P3 is the last applicable)
|
|
786
830
|
*/
|
|
787
831
|
declare class SequentialLastMatchStrategy<R extends ResourceObject, E extends EnvironmentObject = Record<string, unknown>> extends AbilityStrategy<R, E> {
|
|
832
|
+
private _decisive;
|
|
788
833
|
evaluate(): AbilityPolicyEffectType;
|
|
834
|
+
decisivePolicy(): AbilityPolicy<R, E, string> | null;
|
|
789
835
|
}
|
|
790
836
|
|
|
791
837
|
/**
|
|
@@ -806,7 +852,9 @@ declare class SequentialLastMatchStrategy<R extends ResourceObject, E extends En
|
|
|
806
852
|
* Result: permit (P2 has higher priority)
|
|
807
853
|
*/
|
|
808
854
|
declare class PriorityStrategy<R extends ResourceObject, E extends EnvironmentObject = Record<string, unknown>> extends AbilityStrategy<R, E> {
|
|
855
|
+
private _decisive;
|
|
809
856
|
evaluate(): AbilityPolicyEffectType;
|
|
857
|
+
decisivePolicy(): AbilityPolicy<R, E, string> | null;
|
|
810
858
|
}
|
|
811
859
|
|
|
812
860
|
export { AbilityCompare, AbilityCondition, AbilityDSLLexer, AbilityDSLParser, AbilityDSLToken, AbilityError, AbilityExplain, AbilityExplainPolicy, AbilityExplainRule, AbilityExplainRuleSet, AbilityJSONParser, AbilityMatch, AbilityParserError, AbilityPolicy, AbilityPolicyEffect, AbilityResolver, AbilityResult, AbilityRule, AbilityRuleSet, AbilityStrategy, AbilityTypeGenerator, AllMustPermitStrategy, AnyPermitStrategy, DenyOverridesStrategy, FirstMatchStrategy, OnlyOneApplicableStrategy, PermitOverridesStrategy, PriorityStrategy, SequentialLastMatchStrategy, TokenTypes, ability, fromLiteral, isConditionEqual, isConditionNotEqual, toLiteral };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
1
|
function brand$4(code) {
|
|
4
2
|
return code;
|
|
5
3
|
}
|
|
@@ -151,24 +149,28 @@ class AbilityExplain {
|
|
|
151
149
|
toString(indentPrefix = '', isLast = true) {
|
|
152
150
|
const isMatch = this.match === AbilityMatch.match;
|
|
153
151
|
const mark = isMatch ? `${colors.green}✓${colors.reset}` : `${colors.red}✗${colors.reset}`;
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
152
|
+
let label;
|
|
153
|
+
switch (this.type) {
|
|
154
|
+
case 'policy':
|
|
155
|
+
label = `${colors.blue}POLICY${colors.reset}`;
|
|
156
|
+
break;
|
|
157
|
+
case 'ruleSet':
|
|
158
|
+
label = `${colors.yellow}RULESET${colors.reset}`;
|
|
159
|
+
break;
|
|
160
|
+
default:
|
|
161
|
+
label = `${colors.white}RULE${colors.reset}`;
|
|
162
|
+
}
|
|
159
163
|
const branch = indentPrefix.length === 0
|
|
160
164
|
? ''
|
|
161
165
|
: isLast
|
|
162
166
|
? `${colors.gray}└─${colors.reset} `
|
|
163
167
|
: `${colors.gray}├─${colors.reset} `;
|
|
164
168
|
let out = `${indentPrefix}${branch}${label} ${this.name} — ${mark}`;
|
|
165
|
-
if (this.debugInfo)
|
|
169
|
+
if (this.debugInfo)
|
|
166
170
|
out += ` ${colors.gray}(${this.debugInfo})${colors.reset}`;
|
|
167
|
-
}
|
|
168
171
|
const nextIndent = indentPrefix + (isLast ? ' ' : `${colors.gray}│ ${colors.reset}`);
|
|
169
|
-
this.children.forEach((child,
|
|
170
|
-
|
|
171
|
-
out += '\n' + child.toString(nextIndent, last);
|
|
172
|
+
this.children.forEach((child, idx) => {
|
|
173
|
+
out += '\n' + child.toString(nextIndent, idx === this.children.length - 1);
|
|
172
174
|
});
|
|
173
175
|
return out;
|
|
174
176
|
}
|
|
@@ -217,9 +219,21 @@ class AbilityResult {
|
|
|
217
219
|
* Useful for debugging, logging, or building UI tools that visualize permission logic.
|
|
218
220
|
*/
|
|
219
221
|
explain() {
|
|
220
|
-
return this.strategy.policies
|
|
221
|
-
|
|
222
|
-
|
|
222
|
+
return this.strategy.policies
|
|
223
|
+
.map(policy => {
|
|
224
|
+
return new AbilityExplainPolicy(policy).toString();
|
|
225
|
+
})
|
|
226
|
+
.join('\n');
|
|
227
|
+
}
|
|
228
|
+
decisive() {
|
|
229
|
+
return this.strategy.decisivePolicy();
|
|
230
|
+
}
|
|
231
|
+
explainDecisive() {
|
|
232
|
+
const policy = this.decisive();
|
|
233
|
+
if (!policy) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
return new AbilityExplainPolicy(policy).toString();
|
|
223
237
|
}
|
|
224
238
|
isAllowed = () => {
|
|
225
239
|
return this.strategy.isAllowed();
|
|
@@ -309,24 +323,25 @@ class AbilityResolver {
|
|
|
309
323
|
.toLowerCase(); // optional: make case-insensitive
|
|
310
324
|
}
|
|
311
325
|
static matchPermissions(policySegments, inputSegments) {
|
|
312
|
-
|
|
313
|
-
for (
|
|
326
|
+
let i = 0;
|
|
327
|
+
for (; i < policySegments.length; i++) {
|
|
314
328
|
const pSeg = policySegments[i];
|
|
315
329
|
const iSeg = inputSegments[i];
|
|
316
|
-
|
|
317
|
-
return false;
|
|
318
|
-
}
|
|
330
|
+
// '*' — глобальный wildcard: матчим всё, что дальше
|
|
319
331
|
if (pSeg === '*') {
|
|
320
|
-
|
|
332
|
+
return true;
|
|
321
333
|
}
|
|
334
|
+
// input закончился раньше — mismatch
|
|
322
335
|
if (iSeg === undefined) {
|
|
323
336
|
return false;
|
|
324
337
|
}
|
|
338
|
+
// обычное сравнение
|
|
325
339
|
if (pSeg !== iSeg) {
|
|
326
340
|
return false;
|
|
327
341
|
}
|
|
328
342
|
}
|
|
329
|
-
|
|
343
|
+
// Если политика закончилась, но input длиннее — match только если последний сегмент был '*'
|
|
344
|
+
return i === inputSegments.length;
|
|
330
345
|
}
|
|
331
346
|
}
|
|
332
347
|
|
|
@@ -2991,17 +3006,33 @@ class AbilityStrategy {
|
|
|
2991
3006
|
matchedPolicies() {
|
|
2992
3007
|
return this.matched;
|
|
2993
3008
|
}
|
|
3009
|
+
hasMatched() {
|
|
3010
|
+
return this.matched.length > 0;
|
|
3011
|
+
}
|
|
2994
3012
|
firstMatched() {
|
|
2995
|
-
return this.
|
|
3013
|
+
return this.matchedPolicies()[0] ?? null;
|
|
2996
3014
|
}
|
|
2997
3015
|
lastMatched() {
|
|
2998
|
-
|
|
3016
|
+
const list = this.matchedPolicies();
|
|
3017
|
+
return list.length > 0 ? list[list.length - 1] : null;
|
|
3018
|
+
}
|
|
3019
|
+
firstDenied() {
|
|
3020
|
+
return this.getDenyPolicies()[0] ?? null;
|
|
3021
|
+
}
|
|
3022
|
+
firstPermitted() {
|
|
3023
|
+
return this.getPermitPolicies()[0] ?? null;
|
|
3024
|
+
}
|
|
3025
|
+
getPermitPolicies() {
|
|
3026
|
+
return this.matched.filter(p => p.effect === AbilityPolicyEffect.permit);
|
|
3027
|
+
}
|
|
3028
|
+
getDenyPolicies() {
|
|
3029
|
+
return this.matched.filter(p => p.effect === AbilityPolicyEffect.deny);
|
|
2999
3030
|
}
|
|
3000
3031
|
hasPermit() {
|
|
3001
|
-
return this.
|
|
3032
|
+
return this.getPermitPolicies().length > 0;
|
|
3002
3033
|
}
|
|
3003
3034
|
hasDeny() {
|
|
3004
|
-
return this.
|
|
3035
|
+
return this.getDenyPolicies().length > 0;
|
|
3005
3036
|
}
|
|
3006
3037
|
isAllowed() {
|
|
3007
3038
|
return this.evaluate() === AbilityPolicyEffect.permit;
|
|
@@ -3029,13 +3060,24 @@ class AbilityStrategy {
|
|
|
3029
3060
|
* Result: deny (because not all policies permitted)
|
|
3030
3061
|
*/
|
|
3031
3062
|
class AllMustPermitStrategy extends AbilityStrategy {
|
|
3063
|
+
_decisive = null;
|
|
3032
3064
|
evaluate() {
|
|
3033
|
-
|
|
3034
|
-
if (
|
|
3065
|
+
// 1. Нет совпавших политик → deny, но решающей политики нет
|
|
3066
|
+
if (!this.hasMatched()) {
|
|
3067
|
+
this._decisive = null;
|
|
3068
|
+
return AbilityPolicyEffect.deny;
|
|
3069
|
+
}
|
|
3070
|
+
// 2. Если есть deny — она решающая
|
|
3071
|
+
const deny = this.firstDenied();
|
|
3072
|
+
if (deny) {
|
|
3073
|
+
this._decisive = deny;
|
|
3035
3074
|
return AbilityPolicyEffect.deny;
|
|
3036
3075
|
}
|
|
3037
|
-
|
|
3038
|
-
return
|
|
3076
|
+
this._decisive = this.firstPermitted();
|
|
3077
|
+
return AbilityPolicyEffect.permit;
|
|
3078
|
+
}
|
|
3079
|
+
decisivePolicy() {
|
|
3080
|
+
return this._decisive;
|
|
3039
3081
|
}
|
|
3040
3082
|
}
|
|
3041
3083
|
|
|
@@ -3057,8 +3099,20 @@ class AllMustPermitStrategy extends AbilityStrategy {
|
|
|
3057
3099
|
* Result: permit (because at least one policy permitted)
|
|
3058
3100
|
*/
|
|
3059
3101
|
class AnyPermitStrategy extends AbilityStrategy {
|
|
3102
|
+
_decisive = null;
|
|
3060
3103
|
evaluate() {
|
|
3061
|
-
|
|
3104
|
+
// 1. Если есть permit — он решающий
|
|
3105
|
+
const permit = this.firstPermitted();
|
|
3106
|
+
if (permit) {
|
|
3107
|
+
this._decisive = permit;
|
|
3108
|
+
return AbilityPolicyEffect.permit;
|
|
3109
|
+
}
|
|
3110
|
+
// 2. Нет permit → deny по умолчанию
|
|
3111
|
+
this._decisive = null;
|
|
3112
|
+
return AbilityPolicyEffect.deny;
|
|
3113
|
+
}
|
|
3114
|
+
decisivePolicy() {
|
|
3115
|
+
return this._decisive;
|
|
3062
3116
|
}
|
|
3063
3117
|
}
|
|
3064
3118
|
|
|
@@ -3081,15 +3135,27 @@ class AnyPermitStrategy extends AbilityStrategy {
|
|
|
3081
3135
|
* Result: deny (because deny overrides everything)
|
|
3082
3136
|
*/
|
|
3083
3137
|
class DenyOverridesStrategy extends AbilityStrategy {
|
|
3138
|
+
_decisive = null;
|
|
3084
3139
|
evaluate() {
|
|
3085
|
-
|
|
3140
|
+
// 1. Если есть deny — он решающий
|
|
3141
|
+
const deny = this.firstDenied();
|
|
3142
|
+
if (deny) {
|
|
3143
|
+
this._decisive = deny;
|
|
3086
3144
|
return AbilityPolicyEffect.deny;
|
|
3087
3145
|
}
|
|
3088
|
-
|
|
3146
|
+
// 2. Если есть permit — он решающий
|
|
3147
|
+
const permit = this.firstPermitted();
|
|
3148
|
+
if (permit) {
|
|
3149
|
+
this._decisive = permit;
|
|
3089
3150
|
return AbilityPolicyEffect.permit;
|
|
3090
3151
|
}
|
|
3152
|
+
// 3. Нет ни permit, ни deny → deny по умолчанию
|
|
3153
|
+
this._decisive = null;
|
|
3091
3154
|
return AbilityPolicyEffect.deny;
|
|
3092
3155
|
}
|
|
3156
|
+
decisivePolicy() {
|
|
3157
|
+
return this._decisive;
|
|
3158
|
+
}
|
|
3093
3159
|
}
|
|
3094
3160
|
|
|
3095
3161
|
/**
|
|
@@ -3110,9 +3176,20 @@ class DenyOverridesStrategy extends AbilityStrategy {
|
|
|
3110
3176
|
* Result: permit (P2 is the first applicable)
|
|
3111
3177
|
*/
|
|
3112
3178
|
class FirstMatchStrategy extends AbilityStrategy {
|
|
3179
|
+
_decisive = null;
|
|
3113
3180
|
evaluate() {
|
|
3114
3181
|
const first = this.firstMatched();
|
|
3115
|
-
|
|
3182
|
+
// Если нет совпавших политик → deny по умолчанию
|
|
3183
|
+
if (!first) {
|
|
3184
|
+
this._decisive = null;
|
|
3185
|
+
return AbilityPolicyEffect.deny;
|
|
3186
|
+
}
|
|
3187
|
+
// Первая совпавшая политика — решающая
|
|
3188
|
+
this._decisive = first;
|
|
3189
|
+
return first.effect;
|
|
3190
|
+
}
|
|
3191
|
+
decisivePolicy() {
|
|
3192
|
+
return this._decisive;
|
|
3116
3193
|
}
|
|
3117
3194
|
}
|
|
3118
3195
|
|
|
@@ -3133,13 +3210,21 @@ class FirstMatchStrategy extends AbilityStrategy {
|
|
|
3133
3210
|
* Result: deny (more than one applicable policy)
|
|
3134
3211
|
*/
|
|
3135
3212
|
class OnlyOneApplicableStrategy extends AbilityStrategy {
|
|
3213
|
+
_decisive = null;
|
|
3136
3214
|
evaluate() {
|
|
3137
3215
|
const matched = this.matchedPolicies();
|
|
3216
|
+
// 1. Ровно одна совпавшая политика → она решающая
|
|
3138
3217
|
if (matched.length === 1) {
|
|
3218
|
+
this._decisive = matched[0];
|
|
3139
3219
|
return matched[0].effect;
|
|
3140
3220
|
}
|
|
3221
|
+
// 2. Иначе deny, решающей политики нет
|
|
3222
|
+
this._decisive = null;
|
|
3141
3223
|
return AbilityPolicyEffect.deny;
|
|
3142
3224
|
}
|
|
3225
|
+
decisivePolicy() {
|
|
3226
|
+
return this._decisive;
|
|
3227
|
+
}
|
|
3143
3228
|
}
|
|
3144
3229
|
|
|
3145
3230
|
/**
|
|
@@ -3161,15 +3246,27 @@ class OnlyOneApplicableStrategy extends AbilityStrategy {
|
|
|
3161
3246
|
* Result: permit (permit overrides deny)
|
|
3162
3247
|
*/
|
|
3163
3248
|
class PermitOverridesStrategy extends AbilityStrategy {
|
|
3249
|
+
_decisive = null;
|
|
3164
3250
|
evaluate() {
|
|
3165
|
-
|
|
3251
|
+
// 1. Если есть permit — он выигрывает
|
|
3252
|
+
const permit = this.matchedPolicies().find(p => p.effect === AbilityPolicyEffect.permit);
|
|
3253
|
+
if (permit) {
|
|
3254
|
+
this._decisive = permit;
|
|
3166
3255
|
return AbilityPolicyEffect.permit;
|
|
3167
3256
|
}
|
|
3168
|
-
|
|
3257
|
+
// 2. Если permit нет — ищем deny
|
|
3258
|
+
const deny = this.matchedPolicies().find(p => p.effect === AbilityPolicyEffect.deny);
|
|
3259
|
+
if (deny) {
|
|
3260
|
+
this._decisive = deny;
|
|
3169
3261
|
return AbilityPolicyEffect.deny;
|
|
3170
3262
|
}
|
|
3263
|
+
// 3. Нет ни permit, ни deny → deny по умолчанию
|
|
3264
|
+
this._decisive = null;
|
|
3171
3265
|
return AbilityPolicyEffect.deny;
|
|
3172
3266
|
}
|
|
3267
|
+
decisivePolicy() {
|
|
3268
|
+
return this._decisive;
|
|
3269
|
+
}
|
|
3173
3270
|
}
|
|
3174
3271
|
|
|
3175
3272
|
/**
|
|
@@ -3189,9 +3286,20 @@ class PermitOverridesStrategy extends AbilityStrategy {
|
|
|
3189
3286
|
* Result: permit (P3 is the last applicable)
|
|
3190
3287
|
*/
|
|
3191
3288
|
class SequentialLastMatchStrategy extends AbilityStrategy {
|
|
3289
|
+
_decisive = null;
|
|
3192
3290
|
evaluate() {
|
|
3193
3291
|
const last = this.lastMatched();
|
|
3194
|
-
|
|
3292
|
+
// Нет совпавших политик → deny по умолчанию
|
|
3293
|
+
if (!last) {
|
|
3294
|
+
this._decisive = null;
|
|
3295
|
+
return AbilityPolicyEffect.deny;
|
|
3296
|
+
}
|
|
3297
|
+
// Последняя совпавшая политика — решающая
|
|
3298
|
+
this._decisive = last;
|
|
3299
|
+
return last.effect;
|
|
3300
|
+
}
|
|
3301
|
+
decisivePolicy() {
|
|
3302
|
+
return this._decisive;
|
|
3195
3303
|
}
|
|
3196
3304
|
}
|
|
3197
3305
|
|
|
@@ -3213,48 +3321,24 @@ class SequentialLastMatchStrategy extends AbilityStrategy {
|
|
|
3213
3321
|
* Result: permit (P2 has higher priority)
|
|
3214
3322
|
*/
|
|
3215
3323
|
class PriorityStrategy extends AbilityStrategy {
|
|
3324
|
+
_decisive = null;
|
|
3216
3325
|
evaluate() {
|
|
3217
3326
|
const matched = this.matchedPolicies();
|
|
3327
|
+
// 1. Нет совпавших политик → deny, решающей политики нет
|
|
3218
3328
|
if (matched.length === 0) {
|
|
3329
|
+
this._decisive = null;
|
|
3219
3330
|
return AbilityPolicyEffect.deny;
|
|
3220
3331
|
}
|
|
3332
|
+
// 2. Сортируем по приоритету (больший приоритет — выше)
|
|
3221
3333
|
const sorted = [...matched].sort((a, b) => b.priority - a.priority);
|
|
3222
|
-
|
|
3334
|
+
// 3. Самая приоритетная политика — решающая
|
|
3335
|
+
const top = sorted[0];
|
|
3336
|
+
this._decisive = top;
|
|
3337
|
+
return top.effect;
|
|
3338
|
+
}
|
|
3339
|
+
decisivePolicy() {
|
|
3340
|
+
return this._decisive;
|
|
3223
3341
|
}
|
|
3224
3342
|
}
|
|
3225
3343
|
|
|
3226
|
-
|
|
3227
|
-
exports.AbilityCondition = AbilityCondition;
|
|
3228
|
-
exports.AbilityDSLLexer = AbilityDSLLexer;
|
|
3229
|
-
exports.AbilityDSLParser = AbilityDSLParser;
|
|
3230
|
-
exports.AbilityDSLToken = AbilityDSLToken;
|
|
3231
|
-
exports.AbilityError = AbilityError;
|
|
3232
|
-
exports.AbilityExplain = AbilityExplain;
|
|
3233
|
-
exports.AbilityExplainPolicy = AbilityExplainPolicy;
|
|
3234
|
-
exports.AbilityExplainRule = AbilityExplainRule;
|
|
3235
|
-
exports.AbilityExplainRuleSet = AbilityExplainRuleSet;
|
|
3236
|
-
exports.AbilityJSONParser = AbilityJSONParser;
|
|
3237
|
-
exports.AbilityMatch = AbilityMatch;
|
|
3238
|
-
exports.AbilityParserError = AbilityParserError;
|
|
3239
|
-
exports.AbilityPolicy = AbilityPolicy;
|
|
3240
|
-
exports.AbilityPolicyEffect = AbilityPolicyEffect;
|
|
3241
|
-
exports.AbilityResolver = AbilityResolver;
|
|
3242
|
-
exports.AbilityResult = AbilityResult;
|
|
3243
|
-
exports.AbilityRule = AbilityRule;
|
|
3244
|
-
exports.AbilityRuleSet = AbilityRuleSet;
|
|
3245
|
-
exports.AbilityStrategy = AbilityStrategy;
|
|
3246
|
-
exports.AbilityTypeGenerator = AbilityTypeGenerator;
|
|
3247
|
-
exports.AllMustPermitStrategy = AllMustPermitStrategy;
|
|
3248
|
-
exports.AnyPermitStrategy = AnyPermitStrategy;
|
|
3249
|
-
exports.DenyOverridesStrategy = DenyOverridesStrategy;
|
|
3250
|
-
exports.FirstMatchStrategy = FirstMatchStrategy;
|
|
3251
|
-
exports.OnlyOneApplicableStrategy = OnlyOneApplicableStrategy;
|
|
3252
|
-
exports.PermitOverridesStrategy = PermitOverridesStrategy;
|
|
3253
|
-
exports.PriorityStrategy = PriorityStrategy;
|
|
3254
|
-
exports.SequentialLastMatchStrategy = SequentialLastMatchStrategy;
|
|
3255
|
-
exports.TokenTypes = TokenTypes;
|
|
3256
|
-
exports.ability = ability;
|
|
3257
|
-
exports.fromLiteral = fromLiteral;
|
|
3258
|
-
exports.isConditionEqual = isConditionEqual;
|
|
3259
|
-
exports.isConditionNotEqual = isConditionNotEqual;
|
|
3260
|
-
exports.toLiteral = toLiteral;
|
|
3344
|
+
export { AbilityCompare, AbilityCondition, AbilityDSLLexer, AbilityDSLParser, AbilityDSLToken, AbilityError, AbilityExplain, AbilityExplainPolicy, AbilityExplainRule, AbilityExplainRuleSet, AbilityJSONParser, AbilityMatch, AbilityParserError, AbilityPolicy, AbilityPolicyEffect, AbilityResolver, AbilityResult, AbilityRule, AbilityRuleSet, AbilityStrategy, AbilityTypeGenerator, AllMustPermitStrategy, AnyPermitStrategy, DenyOverridesStrategy, FirstMatchStrategy, OnlyOneApplicableStrategy, PermitOverridesStrategy, PriorityStrategy, SequentialLastMatchStrategy, TokenTypes, ability, fromLiteral, isConditionEqual, isConditionNotEqual, toLiteral };
|
package/package.json
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@via-profit/ability",
|
|
3
3
|
"support": "https://via-profit.ru",
|
|
4
|
-
"version": "3.6.
|
|
4
|
+
"version": "3.6.5",
|
|
5
5
|
"description": "Via-Profit Ability service",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"ability",
|
|
8
8
|
"access",
|
|
9
9
|
"via-profit"
|
|
10
10
|
],
|
|
11
|
-
"
|
|
11
|
+
"type": "module",
|
|
12
|
+
"main": "./dist/index.cjs",
|
|
13
|
+
"module": "./dist/index.js",
|
|
14
|
+
"exports": {
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"require": "./dist/index.cjs"
|
|
17
|
+
},
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
12
19
|
"engines": {
|
|
13
20
|
"node": ">= 17.0.0",
|
|
14
21
|
"npm": ">= 8.19.3"
|