@via-profit/ability 3.4.1 → 3.5.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 +346 -360
- package/dist/index.d.ts +576 -19
- package/dist/index.js +69 -142
- package/package.json +19 -18
- package/dist/cache/AbilityCacheAdapter.d.ts +0 -8
- package/dist/cache/AbilityInMemoryCache.d.ts +0 -12
- package/dist/core/AbilityCode.d.ts +0 -8
- package/dist/core/AbilityCompare.d.ts +0 -7
- package/dist/core/AbilityCondition.d.ts +0 -23
- package/dist/core/AbilityError.d.ts +0 -6
- package/dist/core/AbilityExplain.d.ts +0 -27
- package/dist/core/AbilityMatch.d.ts +0 -8
- package/dist/core/AbilityPolicy.d.ts +0 -79
- package/dist/core/AbilityPolicyEffect.d.ts +0 -7
- package/dist/core/AbilityResolver.d.ts +0 -35
- package/dist/core/AbilityResult.d.ts +0 -27
- package/dist/core/AbilityRule.d.ts +0 -88
- package/dist/core/AbilityRuleSet.d.ts +0 -51
- package/dist/core/AbilityTypeGenerator.d.ts +0 -55
- package/dist/parsers/dsl/AbilityDSLLexer.d.ts +0 -24
- package/dist/parsers/dsl/AbilityDSLParser.d.ts +0 -85
- package/dist/parsers/dsl/AbilityDSLSyntaxError.d.ts +0 -13
- package/dist/parsers/dsl/AbilityDSLToken.d.ts +0 -57
- package/dist/parsers/json/AbilityJSONParser.d.ts +0 -22
package/dist/index.js
CHANGED
|
@@ -130,7 +130,7 @@ class AbilityCondition extends AbilityCode {
|
|
|
130
130
|
case 'never':
|
|
131
131
|
return 'never';
|
|
132
132
|
default:
|
|
133
|
-
throw new Error(`Unknown condition code: ${this.code}`);
|
|
133
|
+
throw new Error(`Unknown condition code: ${String(this.code)}`);
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
136
|
}
|
|
@@ -167,8 +167,11 @@ class AbilityTypeGenerator {
|
|
|
167
167
|
const subjectPath = rule.subject;
|
|
168
168
|
const existingType = typeStructure[action][subjectPath];
|
|
169
169
|
const ruleType = this.determineTypeFromRule(rule);
|
|
170
|
-
|
|
170
|
+
if (!ruleType) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
171
173
|
if (existingType && existingType !== ruleType) {
|
|
174
|
+
// If a type already exists for this path, create a union
|
|
172
175
|
typeStructure[action][subjectPath] = `${existingType} | ${ruleType}`;
|
|
173
176
|
}
|
|
174
177
|
else {
|
|
@@ -187,6 +190,10 @@ class AbilityTypeGenerator {
|
|
|
187
190
|
* @returns TypeScript type as string
|
|
188
191
|
*/
|
|
189
192
|
determineTypeFromRule(rule) {
|
|
193
|
+
if (rule.condition.isEqual(AbilityCondition.never) ||
|
|
194
|
+
rule.condition.isEqual(AbilityCondition.always)) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
190
197
|
// Numeric comparisons - always number
|
|
191
198
|
if (rule.condition.isEqual(AbilityCondition.greater_than) ||
|
|
192
199
|
rule.condition.isEqual(AbilityCondition.less_than) ||
|
|
@@ -213,8 +220,9 @@ class AbilityTypeGenerator {
|
|
|
213
220
|
*/
|
|
214
221
|
getArrayType(resource) {
|
|
215
222
|
if (Array.isArray(resource)) {
|
|
216
|
-
if (resource.length === 0)
|
|
223
|
+
if (resource.length === 0) {
|
|
217
224
|
return 'any[]';
|
|
225
|
+
}
|
|
218
226
|
// Determine types of array elements
|
|
219
227
|
const elementTypes = new Set(resource.map(item => this.getPrimitiveType(item)));
|
|
220
228
|
const elementType = elementTypes.size === 1
|
|
@@ -232,10 +240,12 @@ class AbilityTypeGenerator {
|
|
|
232
240
|
* @returns TypeScript primitive type as string
|
|
233
241
|
*/
|
|
234
242
|
getPrimitiveType(value) {
|
|
235
|
-
if (value === null)
|
|
243
|
+
if (value === null) {
|
|
236
244
|
return 'null';
|
|
237
|
-
|
|
245
|
+
}
|
|
246
|
+
if (value === undefined) {
|
|
238
247
|
return 'undefined';
|
|
248
|
+
}
|
|
239
249
|
switch (typeof value) {
|
|
240
250
|
case 'string':
|
|
241
251
|
return 'string';
|
|
@@ -294,12 +304,20 @@ class AbilityTypeGenerator {
|
|
|
294
304
|
let output = '// Automatically generated by via-profit/ability\n';
|
|
295
305
|
output += '// Do not edit manually\n';
|
|
296
306
|
output += 'export type Resources = {\n';
|
|
297
|
-
// Sort actions for stable output
|
|
298
307
|
const sortedActions = Object.keys(structure).sort();
|
|
299
308
|
sortedActions.forEach(action => {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
309
|
+
const actionObj = structure[action];
|
|
310
|
+
const isEmpty = Object.keys(actionObj).length === 0;
|
|
311
|
+
if (isEmpty) {
|
|
312
|
+
// Пустой объект → undefined
|
|
313
|
+
output += ` ['${action}']: undefined;\n`;
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
// Непустой объект → как раньше
|
|
317
|
+
output += ` ['${action}']: {\n`;
|
|
318
|
+
output += this.formatNestedObject(actionObj, 4);
|
|
319
|
+
output += ' };\n';
|
|
320
|
+
}
|
|
303
321
|
});
|
|
304
322
|
output += '}\n';
|
|
305
323
|
return output;
|
|
@@ -346,7 +364,11 @@ class AbilityExplain {
|
|
|
346
364
|
toString(indent = 0) {
|
|
347
365
|
const pad = ' '.repeat(indent);
|
|
348
366
|
const mark = this.match.code === AbilityMatch.match.code ? '✓' : '✗';
|
|
349
|
-
let out =
|
|
367
|
+
let out = '';
|
|
368
|
+
if (this.type === 'policy') {
|
|
369
|
+
out += '\n';
|
|
370
|
+
}
|
|
371
|
+
out += `${pad}${mark} ${this.type} «${this.name}» is ${this.match.code}`;
|
|
350
372
|
this.children.forEach(child => {
|
|
351
373
|
out += '\n' + child.toString(indent + 1);
|
|
352
374
|
});
|
|
@@ -444,14 +466,14 @@ class AbilityPolicy {
|
|
|
444
466
|
* @param resource - The resource to check
|
|
445
467
|
* @param environment - The user environment object
|
|
446
468
|
*/
|
|
447
|
-
|
|
469
|
+
check(resource, environment) {
|
|
448
470
|
this.matchState = AbilityMatch.mismatch;
|
|
449
471
|
if (!this.ruleSet.length) {
|
|
450
472
|
return this.matchState;
|
|
451
473
|
}
|
|
452
474
|
const rulesetCheckStates = [];
|
|
453
475
|
for (const ruleSet of this.ruleSet) {
|
|
454
|
-
const state =
|
|
476
|
+
const state = ruleSet.check(resource, environment);
|
|
455
477
|
rulesetCheckStates.push(state);
|
|
456
478
|
if (AbilityCompare.and.isEqual(this.compareMethod) && AbilityMatch.mismatch.isEqual(state)) {
|
|
457
479
|
return this.matchState; // mismatch
|
|
@@ -500,6 +522,12 @@ class AbilityPolicyEffect extends AbilityCode {
|
|
|
500
522
|
static permit = new AbilityPolicyEffect('permit');
|
|
501
523
|
}
|
|
502
524
|
|
|
525
|
+
class AbilityResultState extends AbilityCode {
|
|
526
|
+
static allow = new AbilityResultState('allow');
|
|
527
|
+
static deny = new AbilityResultState('deny');
|
|
528
|
+
static neutral = new AbilityResultState('neutral');
|
|
529
|
+
}
|
|
530
|
+
|
|
503
531
|
class AbilityResult {
|
|
504
532
|
/**
|
|
505
533
|
* Already checked policies (after call the policy.check())
|
|
@@ -527,40 +555,38 @@ class AbilityResult {
|
|
|
527
555
|
}
|
|
528
556
|
return null;
|
|
529
557
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
}
|
|
534
|
-
isDenied() {
|
|
535
|
-
const effect = this.getLastEffectOfMatchedPolicy();
|
|
536
|
-
return effect?.isEqual(AbilityPolicyEffect.deny) ?? true;
|
|
537
|
-
}
|
|
538
|
-
/**
|
|
539
|
-
* Get the last effect of the policy
|
|
540
|
-
*
|
|
541
|
-
* @returns {AbilityPolicyEffect | null}
|
|
542
|
-
*/
|
|
543
|
-
getLastEffectOfMatchedPolicy() {
|
|
544
|
-
for (let i = this.policies.length - 1; i >= 0; i--) {
|
|
545
|
-
const p = this.policies[i];
|
|
558
|
+
getFinalState() {
|
|
559
|
+
let state = AbilityResultState.neutral;
|
|
560
|
+
for (const p of this.policies) {
|
|
546
561
|
if (p.matchState.isEqual(AbilityMatch.match)) {
|
|
547
|
-
|
|
562
|
+
if (p.effect.isEqual(AbilityPolicyEffect.permit)) {
|
|
563
|
+
state = AbilityResultState.allow;
|
|
564
|
+
}
|
|
565
|
+
else if (p.effect.isEqual(AbilityPolicyEffect.deny)) {
|
|
566
|
+
state = AbilityResultState.deny;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
else if (p.matchState.isEqual(AbilityMatch.mismatch)) {
|
|
570
|
+
state = AbilityResultState.neutral;
|
|
548
571
|
}
|
|
549
572
|
}
|
|
550
|
-
return
|
|
573
|
+
return state;
|
|
574
|
+
}
|
|
575
|
+
isAllowed() {
|
|
576
|
+
return this.getFinalState().isEqual(AbilityResultState.allow);
|
|
577
|
+
}
|
|
578
|
+
isDenied() {
|
|
579
|
+
return this.getFinalState().isNotEqual(AbilityResultState.allow);
|
|
551
580
|
}
|
|
552
581
|
}
|
|
553
582
|
|
|
554
583
|
class AbilityResolver {
|
|
555
584
|
policies;
|
|
556
|
-
cache;
|
|
557
585
|
constructor(
|
|
558
586
|
/**
|
|
559
587
|
* `Important!` The incorrect Resources type was intentionally passed to AbilityPolicy so that TypeScript could suggest the name of the permission and the structure of its resource in the parse method.
|
|
560
588
|
*/
|
|
561
|
-
policyOrListOfPolicies
|
|
562
|
-
const { cache } = options || {};
|
|
563
|
-
this.cache = cache;
|
|
589
|
+
policyOrListOfPolicies) {
|
|
564
590
|
this.policies = Array.isArray(policyOrListOfPolicies)
|
|
565
591
|
? policyOrListOfPolicies
|
|
566
592
|
: [policyOrListOfPolicies];
|
|
@@ -572,30 +598,18 @@ class AbilityResolver {
|
|
|
572
598
|
* @param resource - Resource
|
|
573
599
|
* @param environment
|
|
574
600
|
*/
|
|
575
|
-
|
|
601
|
+
resolve(permission, resource, environment) {
|
|
576
602
|
const filteredPolicies = this.policies.filter(policy => AbilityResolver.isInPermissionContain(policy.permission, String(permission).replace(/^permission\./, '')));
|
|
577
603
|
for (const policy of filteredPolicies) {
|
|
578
|
-
const
|
|
579
|
-
// cache
|
|
580
|
-
if (this.cache) {
|
|
581
|
-
const cached = await this.cache.get(cacheKey);
|
|
582
|
-
if (cached !== undefined) {
|
|
583
|
-
policy.matchState = cached;
|
|
584
|
-
continue;
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
const policyMatchState = await policy.check(resource, environment);
|
|
604
|
+
const policyMatchState = policy.check(resource, environment);
|
|
588
605
|
if (policyMatchState === AbilityMatch.pending) {
|
|
589
606
|
throw new AbilityError(`The policy "${policy.name}" is still in a pending state. Make sure to call "check" to evaluate the policy before resolving permissions.`);
|
|
590
607
|
}
|
|
591
|
-
if (this.cache) {
|
|
592
|
-
await this.cache.set(cacheKey, policyMatchState);
|
|
593
|
-
}
|
|
594
608
|
}
|
|
595
609
|
return new AbilityResult(filteredPolicies);
|
|
596
610
|
}
|
|
597
|
-
|
|
598
|
-
const result =
|
|
611
|
+
enforce(permission, resource, environment) {
|
|
612
|
+
const result = this.resolve(permission, resource, environment);
|
|
599
613
|
if (result.isDenied()) {
|
|
600
614
|
const lastPolicy = result.getLastMatchedPolicy();
|
|
601
615
|
if (lastPolicy) {
|
|
@@ -618,18 +632,6 @@ class AbilityResolver {
|
|
|
618
632
|
return chunk === '*' || longer[i] === '*' || chunk === longer[i];
|
|
619
633
|
});
|
|
620
634
|
}
|
|
621
|
-
makeCacheKey(policyId, resource, environment) {
|
|
622
|
-
if (!this.cache) {
|
|
623
|
-
return '';
|
|
624
|
-
}
|
|
625
|
-
return `policy:${policyId}:res:${this.cache.serialize(resource)}:env:${this.cache.serialize(environment)}`;
|
|
626
|
-
}
|
|
627
|
-
async invalidatePolicy(policyId) {
|
|
628
|
-
await this.cache?.deleteByPrefix(policyId);
|
|
629
|
-
}
|
|
630
|
-
async invalidateCache() {
|
|
631
|
-
await this.cache?.clear();
|
|
632
|
-
}
|
|
633
635
|
}
|
|
634
636
|
|
|
635
637
|
/**
|
|
@@ -776,7 +778,7 @@ class AbilityRule {
|
|
|
776
778
|
* @param resource - The resource to check
|
|
777
779
|
* @param environment
|
|
778
780
|
*/
|
|
779
|
-
|
|
781
|
+
check(resource, environment) {
|
|
780
782
|
const [subjectValue, resourceValue] = this.extractValues(resource, environment);
|
|
781
783
|
const handler = this.operatorHandlers[this.condition.literal];
|
|
782
784
|
const result = handler(subjectValue, resourceValue);
|
|
@@ -979,14 +981,14 @@ class AbilityRuleSet {
|
|
|
979
981
|
rules.forEach(rule => this.addRule(rule));
|
|
980
982
|
return this;
|
|
981
983
|
}
|
|
982
|
-
|
|
984
|
+
check(resources, environment) {
|
|
983
985
|
this.state = AbilityMatch.mismatch;
|
|
984
986
|
if (!this.rules.length) {
|
|
985
987
|
return this.state;
|
|
986
988
|
}
|
|
987
989
|
const ruleCheckStates = [];
|
|
988
990
|
for (const rule of this.rules) {
|
|
989
|
-
const state =
|
|
991
|
+
const state = rule.check(resources, environment);
|
|
990
992
|
ruleCheckStates.push(state);
|
|
991
993
|
if (AbilityCompare.and.isEqual(this.compareMethod) && AbilityMatch.mismatch.isEqual(state)) {
|
|
992
994
|
return this.state; // mismatch
|
|
@@ -1035,79 +1037,6 @@ class AbilityRuleSet {
|
|
|
1035
1037
|
}
|
|
1036
1038
|
}
|
|
1037
1039
|
|
|
1038
|
-
class AbilityInMemoryCache {
|
|
1039
|
-
store = new Map();
|
|
1040
|
-
async get(key) {
|
|
1041
|
-
const entry = this.store.get(key);
|
|
1042
|
-
if (!entry)
|
|
1043
|
-
return undefined;
|
|
1044
|
-
if (Date.now() > entry.expires) {
|
|
1045
|
-
this.store.delete(key);
|
|
1046
|
-
return undefined;
|
|
1047
|
-
}
|
|
1048
|
-
return entry.value;
|
|
1049
|
-
}
|
|
1050
|
-
async set(key, value, ttlSeconds = 60) {
|
|
1051
|
-
this.store.set(key, {
|
|
1052
|
-
value,
|
|
1053
|
-
expires: Date.now() + ttlSeconds * 1000,
|
|
1054
|
-
});
|
|
1055
|
-
}
|
|
1056
|
-
serialize(input) {
|
|
1057
|
-
return this.fastHash(this.stableStringify(input));
|
|
1058
|
-
}
|
|
1059
|
-
async delete(key) {
|
|
1060
|
-
this.store.delete(key);
|
|
1061
|
-
}
|
|
1062
|
-
async clear() {
|
|
1063
|
-
this.store.clear();
|
|
1064
|
-
}
|
|
1065
|
-
async deleteByPrefix(prefix) {
|
|
1066
|
-
for (const key of this.store.keys()) {
|
|
1067
|
-
if (key.startsWith(prefix)) {
|
|
1068
|
-
this.store.delete(key);
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
}
|
|
1072
|
-
fastHash(str) {
|
|
1073
|
-
let hash = 5381;
|
|
1074
|
-
for (let i = 0; i < str.length; i++) {
|
|
1075
|
-
hash = (hash * 33) ^ str.charCodeAt(i);
|
|
1076
|
-
}
|
|
1077
|
-
return (hash >>> 0).toString(36);
|
|
1078
|
-
}
|
|
1079
|
-
stableStringify(obj) {
|
|
1080
|
-
if (obj === null)
|
|
1081
|
-
return 'null';
|
|
1082
|
-
const type = typeof obj;
|
|
1083
|
-
if (type === 'string')
|
|
1084
|
-
return JSON.stringify(obj);
|
|
1085
|
-
if (type === 'number' || type === 'boolean')
|
|
1086
|
-
return String(obj);
|
|
1087
|
-
if (type === 'undefined')
|
|
1088
|
-
return 'undefined';
|
|
1089
|
-
if (Array.isArray(obj)) {
|
|
1090
|
-
let out = '[';
|
|
1091
|
-
for (let i = 0; i < obj.length; i++) {
|
|
1092
|
-
if (i > 0)
|
|
1093
|
-
out += ',';
|
|
1094
|
-
out += this.stableStringify(obj[i]);
|
|
1095
|
-
}
|
|
1096
|
-
return out + ']';
|
|
1097
|
-
}
|
|
1098
|
-
const keys = Object.keys(obj);
|
|
1099
|
-
keys.sort();
|
|
1100
|
-
let out = '{';
|
|
1101
|
-
for (let i = 0; i < keys.length; i++) {
|
|
1102
|
-
const k = keys[i];
|
|
1103
|
-
if (i > 0)
|
|
1104
|
-
out += ',';
|
|
1105
|
-
out += k + ':' + this.stableStringify(obj[k]);
|
|
1106
|
-
}
|
|
1107
|
-
return out + '}';
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
|
|
1111
1040
|
class AbilityJSONParser {
|
|
1112
1041
|
/**
|
|
1113
1042
|
* Parses an array of policy configurations into an array of AbilityPolicy instances.
|
|
@@ -2185,9 +2114,7 @@ class AbilityDSLParser {
|
|
|
2185
2114
|
return best;
|
|
2186
2115
|
}
|
|
2187
2116
|
levenshteinDistance(a, b) {
|
|
2188
|
-
const matrix = Array(b.length + 1)
|
|
2189
|
-
.fill(null)
|
|
2190
|
-
.map(() => Array(a.length + 1).fill(null));
|
|
2117
|
+
const matrix = Array.from({ length: b.length + 1 }, () => Array.from({ length: a.length + 1 }, () => 0));
|
|
2191
2118
|
for (let i = 0; i <= a.length; i++)
|
|
2192
2119
|
matrix[0][i] = i;
|
|
2193
2120
|
for (let j = 0; j <= b.length; j++)
|
|
@@ -2262,7 +2189,6 @@ exports.AbilityExplain = AbilityExplain;
|
|
|
2262
2189
|
exports.AbilityExplainPolicy = AbilityExplainPolicy;
|
|
2263
2190
|
exports.AbilityExplainRule = AbilityExplainRule;
|
|
2264
2191
|
exports.AbilityExplainRuleSet = AbilityExplainRuleSet;
|
|
2265
|
-
exports.AbilityInMemoryCache = AbilityInMemoryCache;
|
|
2266
2192
|
exports.AbilityJSONParser = AbilityJSONParser;
|
|
2267
2193
|
exports.AbilityMatch = AbilityMatch;
|
|
2268
2194
|
exports.AbilityParserError = AbilityParserError;
|
|
@@ -2270,6 +2196,7 @@ exports.AbilityPolicy = AbilityPolicy;
|
|
|
2270
2196
|
exports.AbilityPolicyEffect = AbilityPolicyEffect;
|
|
2271
2197
|
exports.AbilityResolver = AbilityResolver;
|
|
2272
2198
|
exports.AbilityResult = AbilityResult;
|
|
2199
|
+
exports.AbilityResultState = AbilityResultState;
|
|
2273
2200
|
exports.AbilityRule = AbilityRule;
|
|
2274
2201
|
exports.AbilityRuleSet = AbilityRuleSet;
|
|
2275
2202
|
exports.AbilityTypeGenerator = AbilityTypeGenerator;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@via-profit/ability",
|
|
3
3
|
"support": "https://via-profit.ru",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.5.1",
|
|
5
5
|
"description": "Via-Profit Ability service",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"ability",
|
|
@@ -43,31 +43,32 @@
|
|
|
43
43
|
],
|
|
44
44
|
"license": "MIT",
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@eslint/js": "^
|
|
46
|
+
"@eslint/js": "^10.0.1",
|
|
47
47
|
"@jagi/jest-transform-graphql": "^1.0.2",
|
|
48
|
-
"@jest/types": "^
|
|
48
|
+
"@jest/types": "^30.3.0",
|
|
49
49
|
"@rollup/plugin-alias": "^6.0.0",
|
|
50
50
|
"@rollup/plugin-commonjs": "^29.0.2",
|
|
51
51
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
52
52
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
53
|
-
"@types/jest": "^
|
|
54
|
-
"@types/node": "^
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"eslint": "^
|
|
59
|
-
"globals": "^
|
|
60
|
-
"jest": "^
|
|
53
|
+
"@types/jest": "^30.0.0",
|
|
54
|
+
"@types/node": "^25.5.0",
|
|
55
|
+
"concurrently": "^9.2.1",
|
|
56
|
+
"cross-env": "^10.1.0",
|
|
57
|
+
"eslint": "^10.1.0",
|
|
58
|
+
"eslint-plugin-jest": "^29.15.1",
|
|
59
|
+
"globals": "^17.4.0",
|
|
60
|
+
"jest": "^30.3.0",
|
|
61
61
|
"jest-transform-graphql": "^2.1.0",
|
|
62
|
-
"nodemon": "^3.1.
|
|
63
|
-
"prettier": "^3.
|
|
64
|
-
"rollup": "^4.60.
|
|
62
|
+
"nodemon": "^3.1.14",
|
|
63
|
+
"prettier": "^3.8.1",
|
|
64
|
+
"rollup": "^4.60.1",
|
|
65
65
|
"rollup-plugin-copy": "^3.5.0",
|
|
66
|
+
"rollup-plugin-dts": "^6.4.1",
|
|
66
67
|
"tinybench": "^6.0.0",
|
|
67
|
-
"ts-jest": "^29.
|
|
68
|
-
"ts-loader": "^9.5.
|
|
68
|
+
"ts-jest": "^29.4.9",
|
|
69
|
+
"ts-loader": "^9.5.4",
|
|
69
70
|
"ts-node": "^10.9.2",
|
|
70
|
-
"typescript": "^
|
|
71
|
-
"typescript-eslint": "^8.
|
|
71
|
+
"typescript": "^6.0.2",
|
|
72
|
+
"typescript-eslint": "^8.58.0"
|
|
72
73
|
}
|
|
73
74
|
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export interface AbilityCacheAdapter {
|
|
2
|
-
get<T = unknown>(key: string): Promise<T | undefined>;
|
|
3
|
-
set<T = unknown>(key: string, value: T, ttlSeconds?: number): Promise<void>;
|
|
4
|
-
serialize<T = unknown>(input: T): string;
|
|
5
|
-
delete(key: string): Promise<void>;
|
|
6
|
-
clear(): Promise<void>;
|
|
7
|
-
deleteByPrefix(prefix: string): Promise<void>;
|
|
8
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { AbilityCacheAdapter } from '../cache/AbilityCacheAdapter';
|
|
2
|
-
export declare class AbilityInMemoryCache implements AbilityCacheAdapter {
|
|
3
|
-
private store;
|
|
4
|
-
get<T>(key: string): Promise<T | undefined>;
|
|
5
|
-
set<T>(key: string, value: T, ttlSeconds?: number): Promise<void>;
|
|
6
|
-
serialize(input: unknown): string;
|
|
7
|
-
delete(key: string): Promise<void>;
|
|
8
|
-
clear(): Promise<void>;
|
|
9
|
-
deleteByPrefix(prefix: string): Promise<void>;
|
|
10
|
-
private fastHash;
|
|
11
|
-
private stableStringify;
|
|
12
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export declare class AbilityCode<Code extends string | number> {
|
|
2
|
-
_code: Code;
|
|
3
|
-
constructor(code: Code);
|
|
4
|
-
get code(): Code;
|
|
5
|
-
isEqual(compareWith: AbilityCode<Code> | null): boolean;
|
|
6
|
-
isNotEqual(compareWith: AbilityCode<Code> | null): boolean;
|
|
7
|
-
}
|
|
8
|
-
export default AbilityCode;
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import AbilityCode from './AbilityCode';
|
|
2
|
-
export type AbilityCompareCodeType = 'and' | 'or';
|
|
3
|
-
export declare class AbilityCompare extends AbilityCode<AbilityCompareCodeType> {
|
|
4
|
-
static and: AbilityCompare;
|
|
5
|
-
static or: AbilityCompare;
|
|
6
|
-
}
|
|
7
|
-
export default AbilityCompare;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import AbilityCode from './AbilityCode';
|
|
2
|
-
export type AbilityConditionCodeType = '=' | '<>' | '>' | '<' | '>=' | '<=' | 'in' | 'not in' | 'contains' | 'not contains' | 'length greater than' | 'length less than' | 'length equals' | 'always' | 'never';
|
|
3
|
-
export type AbilityConditionLiteralType = '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';
|
|
4
|
-
export declare class AbilityCondition extends AbilityCode<AbilityConditionCodeType> {
|
|
5
|
-
static equals: AbilityCondition;
|
|
6
|
-
static not_equals: AbilityCondition;
|
|
7
|
-
static greater_than: AbilityCondition;
|
|
8
|
-
static less_than: AbilityCondition;
|
|
9
|
-
static less_or_equal: AbilityCondition;
|
|
10
|
-
static greater_or_equal: AbilityCondition;
|
|
11
|
-
static in: AbilityCondition;
|
|
12
|
-
static not_in: AbilityCondition;
|
|
13
|
-
static contains: AbilityCondition;
|
|
14
|
-
static not_contains: AbilityCondition;
|
|
15
|
-
static length_greater_than: AbilityCondition;
|
|
16
|
-
static length_less_than: AbilityCondition;
|
|
17
|
-
static length_equals: AbilityCondition;
|
|
18
|
-
static always: AbilityCondition;
|
|
19
|
-
static never: AbilityCondition;
|
|
20
|
-
static fromLiteral(literal: AbilityConditionLiteralType): AbilityCondition;
|
|
21
|
-
get literal(): AbilityConditionLiteralType;
|
|
22
|
-
}
|
|
23
|
-
export default AbilityCondition;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import AbilityRule from './AbilityRule';
|
|
2
|
-
import AbilityRuleSet from '../core/AbilityRuleSet';
|
|
3
|
-
import AbilityPolicy from '../core/AbilityPolicy';
|
|
4
|
-
import AbilityMatch from '../core/AbilityMatch';
|
|
5
|
-
export type AbilityExplainConfig = {
|
|
6
|
-
readonly type: AbilityExplainType;
|
|
7
|
-
readonly name: string;
|
|
8
|
-
readonly match: AbilityMatch;
|
|
9
|
-
};
|
|
10
|
-
export declare class AbilityExplain {
|
|
11
|
-
readonly type: AbilityExplainType;
|
|
12
|
-
readonly children: AbilityExplain[];
|
|
13
|
-
readonly name: string;
|
|
14
|
-
readonly match: AbilityMatch;
|
|
15
|
-
constructor(config: AbilityExplainConfig, children?: AbilityExplain[]);
|
|
16
|
-
toString(indent?: number): string;
|
|
17
|
-
}
|
|
18
|
-
export declare class AbilityExplainRule extends AbilityExplain {
|
|
19
|
-
constructor(rule: AbilityRule);
|
|
20
|
-
}
|
|
21
|
-
export declare class AbilityExplainRuleSet extends AbilityExplain {
|
|
22
|
-
constructor(ruleSet: AbilityRuleSet);
|
|
23
|
-
}
|
|
24
|
-
export declare class AbilityExplainPolicy extends AbilityExplain {
|
|
25
|
-
constructor(policy: AbilityPolicy);
|
|
26
|
-
}
|
|
27
|
-
export type AbilityExplainType = 'policy' | 'rule' | 'ruleSet';
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import AbilityCode from './AbilityCode';
|
|
2
|
-
export type AbilityMatchCodeType = 'pending' | 'match' | 'mismatch';
|
|
3
|
-
export declare class AbilityMatch extends AbilityCode<AbilityMatchCodeType> {
|
|
4
|
-
static pending: AbilityMatch;
|
|
5
|
-
static match: AbilityMatch;
|
|
6
|
-
static mismatch: AbilityMatch;
|
|
7
|
-
}
|
|
8
|
-
export default AbilityMatch;
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import AbilityRuleSet, { AbilityRuleSetConfig } from './AbilityRuleSet';
|
|
2
|
-
import AbilityMatch from './AbilityMatch';
|
|
3
|
-
import AbilityCompare, { AbilityCompareCodeType } from './AbilityCompare';
|
|
4
|
-
import AbilityPolicyEffect, { AbilityPolicyEffectCodeType } from './AbilityPolicyEffect';
|
|
5
|
-
import { AbilityExplain } from './AbilityExplain';
|
|
6
|
-
import { ResourceObject } from './AbilityTypeGenerator';
|
|
7
|
-
export type AbilityPolicyConfig = {
|
|
8
|
-
readonly permission: string;
|
|
9
|
-
readonly effect: AbilityPolicyEffectCodeType;
|
|
10
|
-
readonly compareMethod: AbilityCompareCodeType;
|
|
11
|
-
readonly ruleSet: readonly AbilityRuleSetConfig[];
|
|
12
|
-
readonly id: string;
|
|
13
|
-
readonly name: string;
|
|
14
|
-
};
|
|
15
|
-
export type AbilityPolicyConstructorProps = {
|
|
16
|
-
id: string;
|
|
17
|
-
name: string;
|
|
18
|
-
permission: string;
|
|
19
|
-
effect: AbilityPolicyEffect;
|
|
20
|
-
compareMethod?: AbilityCompare;
|
|
21
|
-
};
|
|
22
|
-
export declare class AbilityPolicy<Resource extends ResourceObject = Record<string, unknown>, Environment = unknown> {
|
|
23
|
-
matchState: AbilityMatch;
|
|
24
|
-
/**
|
|
25
|
-
* List of rules
|
|
26
|
-
*/
|
|
27
|
-
ruleSet: AbilityRuleSet<Resource, Environment>[];
|
|
28
|
-
/**
|
|
29
|
-
* Policy effect
|
|
30
|
-
*/
|
|
31
|
-
effect: AbilityPolicyEffect;
|
|
32
|
-
/**
|
|
33
|
-
* Rules compare method.\
|
|
34
|
-
* For the «and» method the rule will be permitted if all\
|
|
35
|
-
* rules will be returns «permit» status and for the «or» - if\
|
|
36
|
-
* one of the rules returns as «permit»
|
|
37
|
-
*/
|
|
38
|
-
compareMethod: AbilityCompare;
|
|
39
|
-
/**
|
|
40
|
-
* Policy name
|
|
41
|
-
*/
|
|
42
|
-
name: string;
|
|
43
|
-
/**
|
|
44
|
-
* Policy ID
|
|
45
|
-
*/
|
|
46
|
-
id: string;
|
|
47
|
-
/**
|
|
48
|
-
* Running the `enforce` or `resolve` method
|
|
49
|
-
* will select only those from all passed policies that fall under the specified permission key.
|
|
50
|
-
*/
|
|
51
|
-
permission: string;
|
|
52
|
-
constructor(params: AbilityPolicyConstructorProps);
|
|
53
|
-
/**
|
|
54
|
-
* Add rule set to the policy
|
|
55
|
-
* @param ruleSet - The rule set to add
|
|
56
|
-
*/
|
|
57
|
-
addRuleSet(ruleSet: AbilityRuleSet<Resource, Environment>): this;
|
|
58
|
-
/**
|
|
59
|
-
* Add rule set to the policy
|
|
60
|
-
* @param ruleSets - The array of rule set to add
|
|
61
|
-
*/
|
|
62
|
-
addRuleSets(ruleSets: readonly AbilityRuleSet<Resource, Environment>[]): this;
|
|
63
|
-
/**
|
|
64
|
-
* Check if the policy is matched
|
|
65
|
-
* @param resource - The resource to check
|
|
66
|
-
* @param environment - The user environment object
|
|
67
|
-
*/
|
|
68
|
-
check(resource: Resource, environment?: Environment): Promise<AbilityMatch>;
|
|
69
|
-
explain(): AbilityExplain;
|
|
70
|
-
copyWith(props: Partial<{
|
|
71
|
-
id: string;
|
|
72
|
-
name: string;
|
|
73
|
-
permission: string;
|
|
74
|
-
effect: AbilityPolicyEffect;
|
|
75
|
-
compareMethod: AbilityCompare;
|
|
76
|
-
ruleSet: AbilityRuleSet<Resource, Environment>[];
|
|
77
|
-
}>): AbilityPolicy<Resource, Environment>;
|
|
78
|
-
}
|
|
79
|
-
export default AbilityPolicy;
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import AbilityCode from './AbilityCode';
|
|
2
|
-
export type AbilityPolicyEffectCodeType = 'deny' | 'permit';
|
|
3
|
-
export declare class AbilityPolicyEffect extends AbilityCode<AbilityPolicyEffectCodeType> {
|
|
4
|
-
static deny: AbilityPolicyEffect;
|
|
5
|
-
static permit: AbilityPolicyEffect;
|
|
6
|
-
}
|
|
7
|
-
export default AbilityPolicyEffect;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import AbilityPolicy from './AbilityPolicy';
|
|
2
|
-
import { AbilityResult } from './AbilityResult';
|
|
3
|
-
import { ResourcesMap } from './AbilityTypeGenerator';
|
|
4
|
-
import { AbilityCacheAdapter } from '../cache/AbilityCacheAdapter';
|
|
5
|
-
export type AbilityResolverOptions = {
|
|
6
|
-
readonly cache?: AbilityCacheAdapter | null;
|
|
7
|
-
};
|
|
8
|
-
export declare class AbilityResolver<Resources extends ResourcesMap, Environment = unknown> {
|
|
9
|
-
private policies;
|
|
10
|
-
private readonly cache?;
|
|
11
|
-
constructor(
|
|
12
|
-
/**
|
|
13
|
-
* `Important!` The incorrect Resources type was intentionally passed to AbilityPolicy so that TypeScript could suggest the name of the permission and the structure of its resource in the parse method.
|
|
14
|
-
*/
|
|
15
|
-
policyOrListOfPolicies: readonly AbilityPolicy<Resources>[] | AbilityPolicy<Resources>, options?: AbilityResolverOptions);
|
|
16
|
-
/**
|
|
17
|
-
* Resolve policy for the resource and permission key
|
|
18
|
-
*
|
|
19
|
-
* @param permission - Permission key
|
|
20
|
-
* @param resource - Resource
|
|
21
|
-
* @param environment
|
|
22
|
-
*/
|
|
23
|
-
resolve<Permission extends keyof Resources>(permission: Permission, resource: Resources[Permission], environment?: Environment): Promise<AbilityResult<Resources[Permission]>>;
|
|
24
|
-
enforce<Permission extends keyof Resources>(permission: Permission, resource: Resources[Permission], environment?: Environment): Promise<void | never>;
|
|
25
|
-
/**
|
|
26
|
-
* Check if the permission key is contained in another permission key
|
|
27
|
-
* @param permissionA - The first permission to check
|
|
28
|
-
* @param permissionB - The second permission to check
|
|
29
|
-
*/
|
|
30
|
-
static isInPermissionContain(permissionA: string, permissionB: string): boolean;
|
|
31
|
-
private makeCacheKey;
|
|
32
|
-
invalidatePolicy(policyId: string): Promise<void>;
|
|
33
|
-
invalidateCache(): Promise<void>;
|
|
34
|
-
}
|
|
35
|
-
export default AbilityResolver;
|