@via-profit/ability 3.6.5 → 3.7.1
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/README.md +245 -1165
- package/dist/index.cjs +100 -45
- package/dist/index.d.ts +19 -6
- package/dist/index.js +100 -45
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -32,6 +32,8 @@ function brand$3(code) {
|
|
|
32
32
|
}
|
|
33
33
|
const AbilityCondition = {
|
|
34
34
|
equals: brand$3('='),
|
|
35
|
+
defined: brand$3('defined'),
|
|
36
|
+
not_defined: brand$3('not_defined'),
|
|
35
37
|
not_equals: brand$3('<>'),
|
|
36
38
|
greater_than: brand$3('>'),
|
|
37
39
|
less_than: brand$3('<'),
|
|
@@ -64,6 +66,8 @@ function fromLiteral(literal) {
|
|
|
64
66
|
length_equals: AbilityCondition.length_equals,
|
|
65
67
|
always: AbilityCondition.always,
|
|
66
68
|
never: AbilityCondition.never,
|
|
69
|
+
defined: AbilityCondition.defined,
|
|
70
|
+
not_defined: AbilityCondition.not_defined,
|
|
67
71
|
};
|
|
68
72
|
const value = map[literal];
|
|
69
73
|
if (!value) {
|
|
@@ -104,6 +108,10 @@ function toLiteral(cond) {
|
|
|
104
108
|
return 'always';
|
|
105
109
|
case AbilityCondition.never:
|
|
106
110
|
return 'never';
|
|
111
|
+
case AbilityCondition.defined:
|
|
112
|
+
return 'defined';
|
|
113
|
+
case AbilityCondition.not_defined:
|
|
114
|
+
return 'not_defined';
|
|
107
115
|
default:
|
|
108
116
|
return 'never';
|
|
109
117
|
}
|
|
@@ -126,15 +134,6 @@ const AbilityMatch = {
|
|
|
126
134
|
disabled: brand$2('disabled'),
|
|
127
135
|
};
|
|
128
136
|
|
|
129
|
-
const colors = {
|
|
130
|
-
reset: '\x1b[0m',
|
|
131
|
-
green: '\x1b[32m',
|
|
132
|
-
red: '\x1b[31m',
|
|
133
|
-
blue: '\x1b[34m',
|
|
134
|
-
yellow: '\x1b[33m',
|
|
135
|
-
white: '\x1b[37m',
|
|
136
|
-
gray: '\x1b[90m',
|
|
137
|
-
};
|
|
138
137
|
class AbilityExplain {
|
|
139
138
|
type;
|
|
140
139
|
children;
|
|
@@ -150,27 +149,36 @@ class AbilityExplain {
|
|
|
150
149
|
}
|
|
151
150
|
toString(indentPrefix = '', isLast = true) {
|
|
152
151
|
const isMatch = this.match === AbilityMatch.match;
|
|
153
|
-
const
|
|
152
|
+
const isMismatch = this.match === AbilityMatch.mismatch;
|
|
153
|
+
const isPending = this.match === AbilityMatch.pending;
|
|
154
|
+
// const isDisabled = this.match === AbilityMatch.disabled;
|
|
155
|
+
const mark = isMatch
|
|
156
|
+
? `<match ✓>`
|
|
157
|
+
: isMismatch
|
|
158
|
+
? `<mismatch ✗>`
|
|
159
|
+
: isPending
|
|
160
|
+
? `<pending …>`
|
|
161
|
+
: `<disabled ⊘>`;
|
|
154
162
|
let label;
|
|
155
163
|
switch (this.type) {
|
|
156
164
|
case 'policy':
|
|
157
|
-
label =
|
|
165
|
+
label = `POLICY`;
|
|
158
166
|
break;
|
|
159
167
|
case 'ruleSet':
|
|
160
|
-
label =
|
|
168
|
+
label = `RULESET`;
|
|
161
169
|
break;
|
|
162
170
|
default:
|
|
163
|
-
label =
|
|
171
|
+
label = `RULE`;
|
|
164
172
|
}
|
|
165
173
|
const branch = indentPrefix.length === 0
|
|
166
174
|
? ''
|
|
167
175
|
: isLast
|
|
168
|
-
?
|
|
169
|
-
:
|
|
176
|
+
? `└─ `
|
|
177
|
+
: `├─ `;
|
|
170
178
|
let out = `${indentPrefix}${branch}${label} ${this.name} — ${mark}`;
|
|
171
179
|
if (this.debugInfo)
|
|
172
|
-
out += `
|
|
173
|
-
const nextIndent = indentPrefix + (isLast ? ' ' :
|
|
180
|
+
out += ` (${this.debugInfo})`;
|
|
181
|
+
const nextIndent = indentPrefix + (isLast ? ' ' : `│ `);
|
|
174
182
|
this.children.forEach((child, idx) => {
|
|
175
183
|
out += '\n' + child.toString(nextIndent, idx === this.children.length - 1);
|
|
176
184
|
});
|
|
@@ -183,6 +191,7 @@ class AbilityExplainRule extends AbilityExplain {
|
|
|
183
191
|
type: 'rule',
|
|
184
192
|
match: rule.state,
|
|
185
193
|
name: rule.name,
|
|
194
|
+
debugInfo: `${rule.subject} ${rule.condition} ${JSON.stringify(rule.resource)}`,
|
|
186
195
|
});
|
|
187
196
|
}
|
|
188
197
|
}
|
|
@@ -221,11 +230,13 @@ class AbilityResult {
|
|
|
221
230
|
* Useful for debugging, logging, or building UI tools that visualize permission logic.
|
|
222
231
|
*/
|
|
223
232
|
explain() {
|
|
224
|
-
|
|
233
|
+
const resMarker = this.strategy.isDenied() ? '== DENIED==' : '== ALLOWED ==';
|
|
234
|
+
const policiesExplain = this.strategy.policies
|
|
225
235
|
.map(policy => {
|
|
226
236
|
return new AbilityExplainPolicy(policy).toString();
|
|
227
237
|
})
|
|
228
238
|
.join('\n');
|
|
239
|
+
return `${resMarker}\n${policiesExplain}\n`;
|
|
229
240
|
}
|
|
230
241
|
decisive() {
|
|
231
242
|
return this.strategy.decisivePolicy();
|
|
@@ -245,7 +256,17 @@ class AbilityResult {
|
|
|
245
256
|
};
|
|
246
257
|
}
|
|
247
258
|
|
|
259
|
+
function brand$1(code) {
|
|
260
|
+
return code;
|
|
261
|
+
}
|
|
262
|
+
const AbilityPolicyEffect = {
|
|
263
|
+
deny: brand$1('deny'),
|
|
264
|
+
permit: brand$1('permit'),
|
|
265
|
+
};
|
|
266
|
+
|
|
248
267
|
class AbilityResolver {
|
|
268
|
+
onDeny;
|
|
269
|
+
onAllow;
|
|
249
270
|
StrategyClass;
|
|
250
271
|
policyEntries;
|
|
251
272
|
constructor(
|
|
@@ -254,6 +275,8 @@ class AbilityResolver {
|
|
|
254
275
|
*/
|
|
255
276
|
policyOrListOfPolicies, strategy, options = {}) {
|
|
256
277
|
const policies = this.toArray(policyOrListOfPolicies);
|
|
278
|
+
this.onDeny = options.onDeny;
|
|
279
|
+
this.onAllow = options.onAllow;
|
|
257
280
|
const filtered = options.tags
|
|
258
281
|
? policies.filter(p => p.tags.some(tag => options.tags.includes(tag)))
|
|
259
282
|
: policies;
|
|
@@ -291,11 +314,19 @@ class AbilityResolver {
|
|
|
291
314
|
// 3. Use strategy
|
|
292
315
|
const strategy = new this.StrategyClass(filteredPolicies);
|
|
293
316
|
const effect = strategy.evaluate();
|
|
294
|
-
|
|
317
|
+
const result = new AbilityResult(effect, strategy);
|
|
318
|
+
if (effect === AbilityPolicyEffect.deny && this.onDeny) {
|
|
319
|
+
this.onDeny(result);
|
|
320
|
+
}
|
|
321
|
+
if (effect === AbilityPolicyEffect.permit && this.onAllow) {
|
|
322
|
+
this.onAllow(result);
|
|
323
|
+
}
|
|
324
|
+
return result;
|
|
295
325
|
}
|
|
296
|
-
enforce(permission, resource, environment) {
|
|
326
|
+
enforce(permission, resource, environment, options) {
|
|
297
327
|
const result = this.resolve(permission, resource, environment);
|
|
298
328
|
if (result.isDenied()) {
|
|
329
|
+
options?.onDeny && options?.onDeny(result);
|
|
299
330
|
throw new AbilityError(`Permission denied`);
|
|
300
331
|
}
|
|
301
332
|
}
|
|
@@ -416,7 +447,7 @@ class AbilityTypeGenerator {
|
|
|
416
447
|
environmentStructure[action] = {};
|
|
417
448
|
}
|
|
418
449
|
const existingEnvType = environmentStructure[action][envPath];
|
|
419
|
-
const targetType = ruleType;
|
|
450
|
+
const targetType = ruleType;
|
|
420
451
|
if (existingEnvType && existingEnvType !== targetType) {
|
|
421
452
|
environmentStructure[action][envPath] = `${existingEnvType} | ${targetType}`;
|
|
422
453
|
}
|
|
@@ -1004,14 +1035,6 @@ class AbilityPolicy {
|
|
|
1004
1035
|
}
|
|
1005
1036
|
}
|
|
1006
1037
|
|
|
1007
|
-
function brand$1(code) {
|
|
1008
|
-
return code;
|
|
1009
|
-
}
|
|
1010
|
-
const AbilityPolicyEffect = {
|
|
1011
|
-
deny: brand$1('deny'),
|
|
1012
|
-
permit: brand$1('permit'),
|
|
1013
|
-
};
|
|
1014
|
-
|
|
1015
1038
|
/**
|
|
1016
1039
|
* Represents a rule that defines a condition to be checked against a subject and resource.
|
|
1017
1040
|
*/
|
|
@@ -1063,6 +1086,8 @@ class AbilityRule {
|
|
|
1063
1086
|
static valueLen = (v) => this.isString(v) || Array.isArray(v) ? v.length : null;
|
|
1064
1087
|
static operatorHandlers = {
|
|
1065
1088
|
[toLiteral(AbilityCondition.always)]: () => true,
|
|
1089
|
+
[toLiteral(AbilityCondition.defined)]: (a) => typeof a !== 'undefined',
|
|
1090
|
+
[toLiteral(AbilityCondition.not_defined)]: (a) => typeof a === 'undefined',
|
|
1066
1091
|
[toLiteral(AbilityCondition.never)]: () => false,
|
|
1067
1092
|
[toLiteral(AbilityCondition.equals)]: (a, b) => a === b,
|
|
1068
1093
|
[toLiteral(AbilityCondition.not_equals)]: (a, b) => a !== b,
|
|
@@ -1602,6 +1627,7 @@ const TokenTypes = {
|
|
|
1602
1627
|
NULL: brand('NULL'),
|
|
1603
1628
|
EQ_NULL: brand('EQ_NULL'),
|
|
1604
1629
|
NOT_EQ_NULL: brand('NOT_EQ_NULL'),
|
|
1630
|
+
DEFINED: brand('DEFINED'),
|
|
1605
1631
|
NOT_EQ: brand('NOT_EQ'),
|
|
1606
1632
|
LEN_GT: brand('LEN_GT'),
|
|
1607
1633
|
LEN_LT: brand('LEN_LT'),
|
|
@@ -1652,9 +1678,11 @@ class AbilityDSLLexer {
|
|
|
1652
1678
|
'true',
|
|
1653
1679
|
'false',
|
|
1654
1680
|
'null',
|
|
1681
|
+
'defined',
|
|
1655
1682
|
'contains',
|
|
1656
1683
|
'includes',
|
|
1657
1684
|
'length',
|
|
1685
|
+
'len',
|
|
1658
1686
|
'has',
|
|
1659
1687
|
'in',
|
|
1660
1688
|
'gt',
|
|
@@ -1868,11 +1896,11 @@ class AbilityDSLLexer {
|
|
|
1868
1896
|
const startLine = this.line;
|
|
1869
1897
|
const startColumn = this.column;
|
|
1870
1898
|
const start = this.pos;
|
|
1871
|
-
//
|
|
1899
|
+
// First segment
|
|
1872
1900
|
while (!this.isAtEnd() && /[a-zA-Z0-9_*]/.test(this.peek())) {
|
|
1873
1901
|
this.advance();
|
|
1874
1902
|
}
|
|
1875
|
-
//
|
|
1903
|
+
// dots segments
|
|
1876
1904
|
while (!this.isAtEnd() && this.peek() === '.') {
|
|
1877
1905
|
this.advance(); // dot
|
|
1878
1906
|
if (!/[a-zA-Z_*]/.test(this.peek())) {
|
|
@@ -1889,7 +1917,7 @@ class AbilityDSLLexer {
|
|
|
1889
1917
|
if (word === 'never') {
|
|
1890
1918
|
return new AbilityDSLToken(TokenTypes.NEVER, word, startLine, startColumn);
|
|
1891
1919
|
}
|
|
1892
|
-
//
|
|
1920
|
+
// (identifier or permission)
|
|
1893
1921
|
if (word.includes('.')) {
|
|
1894
1922
|
const last = this.tokens[this.tokens.length - 1];
|
|
1895
1923
|
if (last?.type === TokenTypes.EFFECT) {
|
|
@@ -1899,16 +1927,13 @@ class AbilityDSLLexer {
|
|
|
1899
1927
|
}
|
|
1900
1928
|
return new AbilityDSLToken(TokenTypes.IDENTIFIER, word, startLine, startColumn);
|
|
1901
1929
|
}
|
|
1902
|
-
// Ключевые слова
|
|
1903
1930
|
if (this.keywords.has(word)) {
|
|
1904
|
-
// Эффекты
|
|
1905
1931
|
if (word === 'permit' || word === 'allow') {
|
|
1906
1932
|
return new AbilityDSLToken(TokenTypes.EFFECT, 'permit', startLine, startColumn);
|
|
1907
1933
|
}
|
|
1908
1934
|
if (word === 'deny' || word === 'forbidden') {
|
|
1909
1935
|
return new AbilityDSLToken(TokenTypes.EFFECT, 'deny', startLine, startColumn);
|
|
1910
1936
|
}
|
|
1911
|
-
// Групповые ключевые слова
|
|
1912
1937
|
if (word === 'all') {
|
|
1913
1938
|
return new AbilityDSLToken(TokenTypes.ALL, word, startLine, startColumn);
|
|
1914
1939
|
}
|
|
@@ -1921,13 +1946,15 @@ class AbilityDSLLexer {
|
|
|
1921
1946
|
if (word === 'if') {
|
|
1922
1947
|
return new AbilityDSLToken(TokenTypes.IF, word, startLine, startColumn);
|
|
1923
1948
|
}
|
|
1924
|
-
// Булевы и null
|
|
1925
1949
|
if (word === 'true' || word === 'false') {
|
|
1926
1950
|
return new AbilityDSLToken(TokenTypes.BOOLEAN, word, startLine, startColumn);
|
|
1927
1951
|
}
|
|
1928
1952
|
if (word === 'null') {
|
|
1929
1953
|
return new AbilityDSLToken(TokenTypes.NULL, word, startLine, startColumn);
|
|
1930
1954
|
}
|
|
1955
|
+
if (word === 'defined') {
|
|
1956
|
+
return new AbilityDSLToken(TokenTypes.DEFINED, word, startLine, startColumn);
|
|
1957
|
+
}
|
|
1931
1958
|
if (word === 'except') {
|
|
1932
1959
|
return new AbilityDSLToken(TokenTypes.EXCEPT, word, startLine, startColumn);
|
|
1933
1960
|
}
|
|
@@ -2079,7 +2106,8 @@ class AbilityDSLTokenStream {
|
|
|
2079
2106
|
if (this.eof()) {
|
|
2080
2107
|
return false;
|
|
2081
2108
|
}
|
|
2082
|
-
|
|
2109
|
+
const p = this.peek().type;
|
|
2110
|
+
return p === type;
|
|
2083
2111
|
}
|
|
2084
2112
|
match(type) {
|
|
2085
2113
|
if (this.check(type)) {
|
|
@@ -2515,6 +2543,7 @@ class AbilityDSLParser {
|
|
|
2515
2543
|
const operatorConsumesValue = operator !== TokenTypes.EQ_NULL &&
|
|
2516
2544
|
operator !== TokenTypes.NOT_EQ_NULL &&
|
|
2517
2545
|
operator !== TokenTypes.NULL &&
|
|
2546
|
+
operator !== TokenTypes.DEFINED &&
|
|
2518
2547
|
operator !== TokenTypes.ALWAYS &&
|
|
2519
2548
|
operator !== TokenTypes.NEVER;
|
|
2520
2549
|
if (operatorConsumesValue) {
|
|
@@ -2567,42 +2596,46 @@ class AbilityDSLParser {
|
|
|
2567
2596
|
this.stream.reset();
|
|
2568
2597
|
// "length equals"
|
|
2569
2598
|
this.stream.mark();
|
|
2570
|
-
if (this.matchWord('length') && this.matchWord('equals')) {
|
|
2599
|
+
if ((this.matchWord('length') || this.matchWord('len')) && this.matchWord('equals')) {
|
|
2571
2600
|
this.stream.commit();
|
|
2572
2601
|
return { condition: AbilityCondition.length_equals, operator: TokenTypes.LEN_EQ };
|
|
2573
2602
|
}
|
|
2574
2603
|
this.stream.reset();
|
|
2575
2604
|
// "length ="
|
|
2576
2605
|
this.stream.mark();
|
|
2577
|
-
if (this.matchWord('length') && this.matchSymbol('=')) {
|
|
2606
|
+
if ((this.matchWord('length') || this.matchWord('len')) && this.matchSymbol('=')) {
|
|
2578
2607
|
this.stream.commit();
|
|
2579
2608
|
return { condition: AbilityCondition.length_equals, operator: TokenTypes.LEN_EQ };
|
|
2580
2609
|
}
|
|
2581
2610
|
this.stream.reset();
|
|
2582
2611
|
// "length greater than"
|
|
2583
2612
|
this.stream.mark();
|
|
2584
|
-
if (this.matchWord('length')
|
|
2613
|
+
if ((this.matchWord('length') || this.matchWord('len')) &&
|
|
2614
|
+
this.matchWord('greater') &&
|
|
2615
|
+
this.matchWord('than')) {
|
|
2585
2616
|
this.stream.commit();
|
|
2586
2617
|
return { condition: AbilityCondition.length_greater_than, operator: TokenTypes.LEN_GT };
|
|
2587
2618
|
}
|
|
2588
2619
|
this.stream.reset();
|
|
2589
2620
|
// "length >"
|
|
2590
2621
|
this.stream.mark();
|
|
2591
|
-
if (this.matchWord('length') && this.matchSymbol('>')) {
|
|
2622
|
+
if ((this.matchWord('length') || this.matchWord('len')) && this.matchSymbol('>')) {
|
|
2592
2623
|
this.stream.commit();
|
|
2593
2624
|
return { condition: AbilityCondition.length_greater_than, operator: TokenTypes.LEN_GT };
|
|
2594
2625
|
}
|
|
2595
2626
|
this.stream.reset();
|
|
2596
2627
|
// "length less than"
|
|
2597
2628
|
this.stream.mark();
|
|
2598
|
-
if (this.matchWord('length')
|
|
2629
|
+
if ((this.matchWord('length') || this.matchWord('len')) &&
|
|
2630
|
+
this.matchWord('less') &&
|
|
2631
|
+
this.matchWord('than')) {
|
|
2599
2632
|
this.stream.commit();
|
|
2600
2633
|
return { condition: AbilityCondition.length_less_than, operator: TokenTypes.LEN_LT };
|
|
2601
2634
|
}
|
|
2602
2635
|
this.stream.reset();
|
|
2603
2636
|
// "length <"
|
|
2604
2637
|
this.stream.mark();
|
|
2605
|
-
if (this.matchWord('length') && this.matchSymbol('<')) {
|
|
2638
|
+
if ((this.matchWord('length') || this.matchWord('len')) && this.matchSymbol('<')) {
|
|
2606
2639
|
this.stream.commit();
|
|
2607
2640
|
return { condition: AbilityCondition.length_less_than, operator: TokenTypes.LEN_LT };
|
|
2608
2641
|
}
|
|
@@ -2730,6 +2763,20 @@ class AbilityDSLParser {
|
|
|
2730
2763
|
}
|
|
2731
2764
|
}
|
|
2732
2765
|
this.stream.reset();
|
|
2766
|
+
// is defined
|
|
2767
|
+
this.stream.mark();
|
|
2768
|
+
if (this.matchWord('is') && this.matchWord('defined')) {
|
|
2769
|
+
this.stream.commit();
|
|
2770
|
+
return { condition: AbilityCondition.defined, operator: TokenTypes.DEFINED };
|
|
2771
|
+
}
|
|
2772
|
+
this.stream.reset();
|
|
2773
|
+
// is not defined
|
|
2774
|
+
this.stream.mark();
|
|
2775
|
+
if (this.matchWord('is') && this.matchWord('not') && this.matchWord('defined')) {
|
|
2776
|
+
this.stream.commit();
|
|
2777
|
+
return { condition: AbilityCondition.not_defined, operator: TokenTypes.DEFINED };
|
|
2778
|
+
}
|
|
2779
|
+
this.stream.reset();
|
|
2733
2780
|
// Single token (symbol or keyword)
|
|
2734
2781
|
const token = this.stream.peek();
|
|
2735
2782
|
if (token.type !== TokenTypes.SYMBOL &&
|
|
@@ -2801,7 +2848,8 @@ class AbilityDSLParser {
|
|
|
2801
2848
|
if ((token.type === TokenTypes.KEYWORD ||
|
|
2802
2849
|
token.type === TokenTypes.IDENTIFIER ||
|
|
2803
2850
|
token.type === TokenTypes.ALWAYS ||
|
|
2804
|
-
token.type === TokenTypes.NEVER
|
|
2851
|
+
token.type === TokenTypes.NEVER ||
|
|
2852
|
+
token.type === TokenTypes.DEFINED) &&
|
|
2805
2853
|
token.value === word) {
|
|
2806
2854
|
this.stream.next();
|
|
2807
2855
|
return true;
|
|
@@ -2839,6 +2887,11 @@ class AbilityDSLParser {
|
|
|
2839
2887
|
this.stream.syntaxError(`Unexpected ${token.type} in value position`, token);
|
|
2840
2888
|
}
|
|
2841
2889
|
this.stream.next();
|
|
2890
|
+
// if (token.type === TokenTypes.IDENTIFIER) {
|
|
2891
|
+
// this.stream.next();
|
|
2892
|
+
//
|
|
2893
|
+
// return this.parseValue();
|
|
2894
|
+
// }
|
|
2842
2895
|
// CHECK THIS SWITCH COMPARE
|
|
2843
2896
|
switch (token.type) {
|
|
2844
2897
|
case TokenTypes.STRING:
|
|
@@ -2849,8 +2902,10 @@ class AbilityDSLParser {
|
|
|
2849
2902
|
return token.value === 'true';
|
|
2850
2903
|
case TokenTypes.NULL:
|
|
2851
2904
|
return null;
|
|
2905
|
+
case TokenTypes.DEFINED:
|
|
2906
|
+
return typeof token.value !== 'undefined';
|
|
2852
2907
|
case TokenTypes.IDENTIFIER:
|
|
2853
|
-
return
|
|
2908
|
+
return null;
|
|
2854
2909
|
default: {
|
|
2855
2910
|
this.stream.syntaxError(`Unexpected value token "${token.value}"`, token, [
|
|
2856
2911
|
TokenTypes.KEYWORD,
|
package/dist/index.d.ts
CHANGED
|
@@ -7,13 +7,15 @@ declare const AbilityCompare: {
|
|
|
7
7
|
readonly and: AbilityCompareType;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
-
type AbilityConditionCode = '=' | '<>' | '>' | '<' | '>=' | '<=' | 'in' | 'not in' | 'contains' | 'not contains' | 'length greater than' | 'length less than' | 'length equals' | 'always' | 'never';
|
|
11
|
-
type AbilityConditionLiteral = 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'in' | 'not_in' | 'greater_than' | 'less_than' | 'less_or_equal' | 'greater_or_equal' | 'length_greater_than' | 'length_less_than' | 'length_equals' | 'always' | 'never';
|
|
10
|
+
type AbilityConditionCode = '=' | '<>' | '>' | '<' | '>=' | '<=' | 'in' | 'not in' | 'contains' | 'not contains' | 'length greater than' | 'length less than' | 'length equals' | 'always' | 'never' | 'defined' | 'not_defined';
|
|
11
|
+
type AbilityConditionLiteral = 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'in' | 'not_in' | 'greater_than' | 'less_than' | 'less_or_equal' | 'greater_or_equal' | 'length_greater_than' | 'length_less_than' | 'length_equals' | 'always' | 'never' | 'defined' | 'not_defined';
|
|
12
12
|
type AbilityConditionType = AbilityConditionCode & {
|
|
13
13
|
__brand: 'AbilityCondition';
|
|
14
14
|
};
|
|
15
15
|
declare const AbilityCondition: {
|
|
16
16
|
readonly equals: AbilityConditionType;
|
|
17
|
+
readonly defined: AbilityConditionType;
|
|
18
|
+
readonly not_defined: AbilityConditionType;
|
|
17
19
|
readonly not_equals: AbilityConditionType;
|
|
18
20
|
readonly greater_than: AbilityConditionType;
|
|
19
21
|
readonly less_than: AbilityConditionType;
|
|
@@ -438,7 +440,7 @@ declare abstract class AbilityStrategy<Resource extends ResourceObject = Record<
|
|
|
438
440
|
|
|
439
441
|
declare class AbilityResult<R extends ResourceObject = Record<string, unknown>, E extends EnvironmentObject = Record<string, unknown>> {
|
|
440
442
|
protected readonly effect: AbilityPolicyEffectType;
|
|
441
|
-
|
|
443
|
+
readonly strategy: AbilityStrategy<R, E>;
|
|
442
444
|
constructor(effect: AbilityPolicyEffectType, strategy: AbilityStrategy<R, E>);
|
|
443
445
|
/**
|
|
444
446
|
* Returns a list of explanations for each policy involved in the ability evaluation.
|
|
@@ -455,13 +457,23 @@ declare class AbilityResult<R extends ResourceObject = Record<string, unknown>,
|
|
|
455
457
|
|
|
456
458
|
interface AbilityResolverOptions<TTags extends string> {
|
|
457
459
|
tags?: readonly TTags[];
|
|
460
|
+
readonly onDeny?: EnforceOnDeny;
|
|
461
|
+
readonly onAllow?: EnforceOnAllow;
|
|
458
462
|
}
|
|
459
463
|
type ExtractResources<P> = P extends AbilityPolicy<infer R, any, any> ? R : never;
|
|
460
464
|
type ExtractEnvironment<P> = P extends AbilityPolicy<any, infer E, any> ? E : never;
|
|
461
465
|
type ExtractPermission<R> = R extends AbilityResolver<infer P, any, any> ? keyof ExtractResources<P> & string : never;
|
|
462
466
|
type ExtractResourceByPermission<P, Perm extends string> = P extends AbilityPolicy<infer R, any, any> ? (Perm extends keyof R ? R[Perm] : never) : never;
|
|
463
467
|
type ExtractEnvironmentByPermission<P, Perm extends string> = P extends AbilityPolicy<any, infer E, any> ? (Perm extends keyof E ? E[Perm] : never) : never;
|
|
468
|
+
type EnforceOptions<R extends ResourceObject = Record<string, unknown>, E extends EnvironmentObject = Record<string, unknown>> = {
|
|
469
|
+
readonly onDeny?: EnforceOnDeny<R, E>;
|
|
470
|
+
readonly onAllow?: EnforceOnDeny<R, E>;
|
|
471
|
+
};
|
|
472
|
+
type EnforceOnDeny<R extends ResourceObject = Record<string, unknown>, E extends EnvironmentObject = Record<string, unknown>> = (result: AbilityResult<R, E>) => void;
|
|
473
|
+
type EnforceOnAllow<R extends ResourceObject = Record<string, unknown>, E extends EnvironmentObject = Record<string, unknown>> = (result: AbilityResult<R, E>) => void;
|
|
464
474
|
declare class AbilityResolver<P extends AbilityPolicy<any, any, any>, S extends AbilityStrategy<P extends AbilityPolicy<infer R, infer E, any> ? R : never, P extends AbilityPolicy<any, infer E, any> ? E : never>, TTags extends string = P extends AbilityPolicy<any, any, infer T> ? T : never> {
|
|
475
|
+
private readonly onDeny?;
|
|
476
|
+
private readonly onAllow?;
|
|
465
477
|
private readonly StrategyClass;
|
|
466
478
|
private readonly policyEntries;
|
|
467
479
|
constructor(
|
|
@@ -477,7 +489,7 @@ declare class AbilityResolver<P extends AbilityPolicy<any, any, any>, S extends
|
|
|
477
489
|
* @param environment
|
|
478
490
|
*/
|
|
479
491
|
resolve<Permission extends keyof ExtractResources<P> & string>(permission: Permission, resource: ExtractResourceByPermission<P, Permission>, environment?: ExtractEnvironmentByPermission<P, Permission>): AbilityResult<ExtractResourceByPermission<P, Permission>, ExtractEnvironment<P>>;
|
|
480
|
-
enforce<Permission extends keyof ExtractResources<P> & string>(permission: Permission, resource: ExtractResourceByPermission<P, Permission>, environment?: ExtractEnvironmentByPermission<P, Permission
|
|
492
|
+
enforce<Permission extends keyof ExtractResources<P> & string>(permission: Permission, resource: ExtractResourceByPermission<P, Permission>, environment?: ExtractEnvironmentByPermission<P, Permission>, options?: EnforceOptions): void | never;
|
|
481
493
|
/**
|
|
482
494
|
* @deprecated - will be removed
|
|
483
495
|
*
|
|
@@ -590,7 +602,7 @@ declare class AbilityDSLParser<R extends ResourceObject = Record<string, unknown
|
|
|
590
602
|
private isStartOfAlias;
|
|
591
603
|
}
|
|
592
604
|
|
|
593
|
-
type TokenTypeCode = 'EFFECT' | 'IF' | 'PERMISSION' | 'IDENTIFIER' | 'COLON' | 'COMMA' | 'DOT' | 'LBRACKET' | 'RBRACKET' | 'ALL' | 'ANY' | 'OF' | 'EOF' | 'COMMENT' | 'EQ' | 'CONTAINS' | 'IN' | 'NOT_IN' | 'NOT_CONTAINS' | 'GT' | 'GTE' | 'LT' | 'LTE' | 'NULL' | 'EQ_NULL' | 'NOT_EQ_NULL' | 'NOT_EQ' | 'LEN_GT' | 'LEN_LT' | 'LEN_EQ' | 'ALWAYS' | 'NEVER' | 'EXCEPT' | 'ANNOTATION' | 'STRING' | 'NUMBER' | 'BOOLEAN' | 'SYMBOL' | 'KEYWORD' | 'ALIAS' | 'UNKNOWN';
|
|
605
|
+
type TokenTypeCode = 'EFFECT' | 'IF' | 'PERMISSION' | 'IDENTIFIER' | 'COLON' | 'COMMA' | 'DOT' | 'LBRACKET' | 'RBRACKET' | 'ALL' | 'ANY' | 'OF' | 'EOF' | 'COMMENT' | 'EQ' | 'CONTAINS' | 'IN' | 'NOT_IN' | 'NOT_CONTAINS' | 'GT' | 'GTE' | 'LT' | 'LTE' | 'NULL' | 'EQ_NULL' | 'NOT_EQ_NULL' | 'DEFINED' | 'NOT_EQ' | 'LEN_GT' | 'LEN_LT' | 'LEN_EQ' | 'ALWAYS' | 'NEVER' | 'EXCEPT' | 'ANNOTATION' | 'STRING' | 'NUMBER' | 'BOOLEAN' | 'SYMBOL' | 'KEYWORD' | 'ALIAS' | 'UNKNOWN';
|
|
594
606
|
type TokenType = TokenTypeCode & {
|
|
595
607
|
__brand: 'TokenType';
|
|
596
608
|
};
|
|
@@ -621,6 +633,7 @@ declare const TokenTypes: {
|
|
|
621
633
|
readonly NULL: TokenType;
|
|
622
634
|
readonly EQ_NULL: TokenType;
|
|
623
635
|
readonly NOT_EQ_NULL: TokenType;
|
|
636
|
+
readonly DEFINED: TokenType;
|
|
624
637
|
readonly NOT_EQ: TokenType;
|
|
625
638
|
readonly LEN_GT: TokenType;
|
|
626
639
|
readonly LEN_LT: TokenType;
|
|
@@ -858,4 +871,4 @@ declare class PriorityStrategy<R extends ResourceObject, E extends EnvironmentOb
|
|
|
858
871
|
}
|
|
859
872
|
|
|
860
873
|
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 };
|
|
861
|
-
export type { AbilityCompareType, AbilityConditionCode, AbilityConditionLiteral, AbilityConditionType, AbilityExplainConfig, AbilityExplainType, AbilityMatchType, AbilityPolicyConfig, AbilityPolicyConstructorProps, AbilityPolicyEffectType, AbilityResolverOptions, AbilityRuleConfig, AbilityRuleConstructorProps, AbilityRuleSetConfig, AbilityRuleSetConstructorProps, EnvironmentObject, ExtractEnvironment, ExtractEnvironmentByPermission, ExtractPermission, ExtractResourceByPermission, ExtractResources, NestedDict, Primitive, ResourceObject, ResourcesMap, TokenType, TokenTypeCode };
|
|
874
|
+
export type { AbilityCompareType, AbilityConditionCode, AbilityConditionLiteral, AbilityConditionType, AbilityExplainConfig, AbilityExplainType, AbilityMatchType, AbilityPolicyConfig, AbilityPolicyConstructorProps, AbilityPolicyEffectType, AbilityResolverOptions, AbilityRuleConfig, AbilityRuleConstructorProps, AbilityRuleSetConfig, AbilityRuleSetConstructorProps, EnforceOnAllow, EnforceOnDeny, EnforceOptions, EnvironmentObject, ExtractEnvironment, ExtractEnvironmentByPermission, ExtractPermission, ExtractResourceByPermission, ExtractResources, NestedDict, Primitive, ResourceObject, ResourcesMap, TokenType, TokenTypeCode };
|