@via-profit/ability 3.1.1 → 3.3.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/CHANGELOG.md +0 -127
- package/README.md +238 -39
- package/dist/core/AbilityPolicy.d.ts +9 -14
- package/dist/core/AbilityResolver.d.ts +1 -1
- package/dist/core/AbilityResult.d.ts +1 -1
- package/dist/core/AbilityRule.d.ts +7 -1
- package/dist/core/AbilityRuleSet.d.ts +7 -5
- package/dist/core/AbilityTypeGenerator.d.ts +55 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +661 -1049
- package/dist/parsers/dsl/AbilityDSLParser.d.ts +1 -1
- package/dist/parsers/json/AbilityJSONParser.d.ts +1 -1
- package/package.json +13 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,129 +1,2 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [3.2.0] - 2026-x3-xx
|
|
4
|
-
|
|
5
|
-
### Изменено
|
|
6
|
-
|
|
7
|
-
- Метод `AbilityPolicy.parseAll()` переименован в `AbilityPolicy.fromJSONAll()`
|
|
8
|
-
- Метод `AbilityPolicy.parse()` переименован в `AbilityPolicy.toJSON()`
|
|
9
|
-
- Метод `AbilityRule.parse()` переименован в `AbilityRule.toJSON()`
|
|
10
|
-
- Метод `AbilityRuleSet.parse()` переименован в `.toJSON()`
|
|
11
|
-
|
|
12
|
-
## [3.1.0] - 2026-03-20
|
|
13
|
-
|
|
14
|
-
### Добавлено
|
|
15
|
-
|
|
16
|
-
- Реализован кэш
|
|
17
|
-
- Добавлен кэш-провайдер `AbilityCacheProvider` для реализации кастомного кэша
|
|
18
|
-
- Реализован и включён по умолчанию `AbilityInMemoryCache` (кэш в памяти)
|
|
19
|
-
- Добавлена полноценная поддержка `environment` как третьего аргумента в:
|
|
20
|
-
- `resolver.resolve(action, resource, environment)`
|
|
21
|
-
- `resolver.enforce(action, resource, environment)`
|
|
22
|
-
- Введена возможность использовать пути вида `env.*` в правилах политик.
|
|
23
|
-
- Пример: `"subject": "env.time.hour"`
|
|
24
|
-
- Добавлена поддержка смешанных сравнений:
|
|
25
|
-
- `resource.*` ↔ `env.*`
|
|
26
|
-
- литерал ↔ `env.*`
|
|
27
|
-
- `env.*` ↔ литерал
|
|
28
|
-
|
|
29
|
-
### Breaking changes
|
|
30
|
-
|
|
31
|
-
Асинхронизация механизма проверки политик.
|
|
32
|
-
Все методы, участвующие в цепочке вычисления разрешений, теперь возвращают `Promise`.
|
|
33
|
-
|
|
34
|
-
#### Изменено
|
|
35
|
-
|
|
36
|
-
- `AbilityRule.check(resource): Promise<AbilityMatch>`
|
|
37
|
-
Ранее возвращал `AbilityMatch` синхронно.
|
|
38
|
-
|
|
39
|
-
- `AbilityRuleSet.check(resource): Promise<AbilityMatch>`
|
|
40
|
-
Теперь выполняет правила последовательно и асинхронно.
|
|
41
|
-
|
|
42
|
-
- `AbilityPolicy.check(resource): Promise<AbilityMatch>`
|
|
43
|
-
Асинхронно проверяет ruleSet в строгом порядке.
|
|
44
|
-
|
|
45
|
-
- `AbilityResolver.resolve(action, resource): Promise<AbilityResult>`
|
|
46
|
-
Теперь асинхронный метод, который дожидается выполнения всех политик.
|
|
47
|
-
|
|
48
|
-
- `AbilityResolver.enforce(action, resource): Promise<void | never>`
|
|
49
|
-
Теперь работает асинхронно.
|
|
50
|
-
|
|
51
|
-
### Миграция
|
|
52
|
-
|
|
53
|
-
1. Все вызовы `check()` должны быть обновлены:
|
|
54
|
-
|
|
55
|
-
```ts
|
|
56
|
-
await rule.check(resource);
|
|
57
|
-
await ruleSet.check(resource);
|
|
58
|
-
await policy.check(resource);
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
2. Все вызовы `resolver.resolve()` и `resolver.enforce()` теперь требуют `await`:
|
|
62
|
-
|
|
63
|
-
```ts
|
|
64
|
-
await resolver.resolve('order.update', resource);
|
|
65
|
-
await resolver.enforce('order.update', resource);
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## [3.0.1] - 2026-03-19
|
|
69
|
-
|
|
70
|
-
## Добавлено
|
|
71
|
-
|
|
72
|
-
### 1. **Лицензия MIT** (`LICENSE`)
|
|
73
|
-
|
|
74
|
-
- Добавлен официальный файл лицензии MIT от Via Profit
|
|
75
|
-
|
|
76
|
-
### 2. **Класс `AbilityExplain.ts`**
|
|
77
|
-
|
|
78
|
-
- Новый класс для получения человекочитаемых объяснений результатов проверки
|
|
79
|
-
- Классы-наследники:
|
|
80
|
-
- `AbilityExplainRule` - объяснение для правила
|
|
81
|
-
- `AbilityExplainRuleSet` - объяснение для группы правил
|
|
82
|
-
- `AbilityExplainPolicy` - объяснение для политики
|
|
83
|
-
- Метод `toString()` форматирует вывод с отступами и символами ✓/✗
|
|
84
|
-
|
|
85
|
-
---
|
|
86
|
-
|
|
87
|
-
## Обновлено
|
|
88
|
-
|
|
89
|
-
### **AbilityParser.ts** (полная переработка)
|
|
90
|
-
|
|
91
|
-
- **Было**: Базовая генерация типов
|
|
92
|
-
- **Стало**: Расширенная система генерации TypeScript типов
|
|
93
|
-
- Новые методы:
|
|
94
|
-
- `determineTypeFromRule()` - определение типа на основе правила
|
|
95
|
-
- `getArrayType()` - обработка массивов
|
|
96
|
-
- `getPrimitiveType()` - определение примитивных типов
|
|
97
|
-
- `buildNestedStructure()` - трансформация плоской структуры во вложенную
|
|
98
|
-
- `formatTypeDefinitions()` - форматирование финального вывода
|
|
99
|
-
- `formatNestedObject()` - рекурсивное форматирование объектов
|
|
100
|
-
|
|
101
|
-
### **AbilityRule.ts**
|
|
102
|
-
|
|
103
|
-
- `id` и `name` теперь опциональные (`?`)
|
|
104
|
-
- Автогенерация `id` и `name` если не предоставлены
|
|
105
|
-
- **Новые статические методы** (фабричные методы):
|
|
106
|
-
- `equal()`, `notEqual()`, `in()`, `notIn()`
|
|
107
|
-
- `lessThan()`, `lessOrEqual()`, `moreThan()`, `moreOrEqual()`
|
|
108
|
-
|
|
109
|
-
### **AbilityRuleSet.ts**
|
|
110
|
-
|
|
111
|
-
- `id` и `name` теперь опциональные
|
|
112
|
-
- Добавлены статические методы:
|
|
113
|
-
- `and()` - создание группы с логическим И
|
|
114
|
-
- `or()` - создание группы с логическим ИЛИ
|
|
115
|
-
|
|
116
|
-
### **AbilityPolicy.ts**
|
|
117
|
-
|
|
118
|
-
- Новый метод `explain()` - получение объяснения проверки
|
|
119
|
-
- Новый статический метод `parseAll()` - парсинг массива конфигураций
|
|
120
|
-
- Улучшены комментарии к полю `action`
|
|
121
|
-
|
|
122
|
-
### **AbilityResolver.ts**
|
|
123
|
-
|
|
124
|
-
- Новый метод `resolveWithExplain()` - проверка с детальным объяснением
|
|
125
|
-
- Возвращает массив `AbilityExplain[]` для анализа результатов
|
|
126
|
-
|
|
127
|
-
---
|
|
128
|
-
|
|
129
|
-
## Обновлена документация и примеры
|
package/README.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
> A set of services that partially implement the [Attribute Based Access Control](https://en.wikipedia.org/wiki/Attribute-based_access_control) principle.
|
|
4
4
|
> The package allows you to describe rules, combine them into groups, form policies, and apply them to data to determine permissions.
|
|
5
5
|
|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
|
|
6
15
|
## Language / Язык
|
|
7
16
|
|
|
8
17
|
- [🇬🇧 English](/docs/en/README.md)
|
|
@@ -113,6 +122,191 @@ Let’s briefly list the key points you need to know before starting to use the
|
|
|
113
122
|
7. Generally, rely on the principle: if permission is not explicitly granted → access is denied.
|
|
114
123
|
8. Use the built-in cache only if your policies are incredibly complex and contain a large number of rules.
|
|
115
124
|
|
|
125
|
+
### Interaction Model
|
|
126
|
+
|
|
127
|
+
First, you define "raw" policies (using DSL, JSON, or classes). Then, you transform the raw data into ready-to-use policies (an array of policies). This is done once and provides a single source of truth. After that, you can perform permission checks in any part of your code using the prepared policies and the resolver.
|
|
128
|
+
|
|
129
|
+
Policies, rule sets, and rules can be created using:
|
|
130
|
+
|
|
131
|
+
- DSL (Domain-Specific Language)
|
|
132
|
+
- Classes (classic approach)
|
|
133
|
+
- JSON
|
|
134
|
+
|
|
135
|
+
**Creating policies with DSL**
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import { AbilityDSLParser } from '@via-profit/ability';
|
|
139
|
+
|
|
140
|
+
// Describe policies using Ability-DSL
|
|
141
|
+
const dsl = `
|
|
142
|
+
# @name Order creation is only available to persons over 18 years old
|
|
143
|
+
permit permission.order.action.create if all:
|
|
144
|
+
all of:
|
|
145
|
+
user.age gte 18
|
|
146
|
+
|
|
147
|
+
# @name Price editing is only available to administrators
|
|
148
|
+
permit permission.order.data.price if all:
|
|
149
|
+
all of:
|
|
150
|
+
user.roles contains 'administrator'
|
|
151
|
+
`;
|
|
152
|
+
|
|
153
|
+
// Define resource types for TypeScript
|
|
154
|
+
// Types can be generated automatically (more on this later) or defined manually
|
|
155
|
+
// In this example, for simplicity, types are defined manually
|
|
156
|
+
type Resources = {
|
|
157
|
+
['order.action.create']: {
|
|
158
|
+
user: {
|
|
159
|
+
age: number;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
['order.data.price']: {
|
|
163
|
+
user: {
|
|
164
|
+
roles: string[];
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Use the parser to create policies
|
|
170
|
+
// Pass the resource type as a generic parameter
|
|
171
|
+
const policies = new AbilityDSLParser<Resources>(dsl).parse(); // AbilityPolicy[]
|
|
172
|
+
|
|
173
|
+
// The parser returns an array of policies even
|
|
174
|
+
// if only one policy is described in the DSL
|
|
175
|
+
console.log(policies); // [AbilityPolicy, AbilityPolicy, ...]
|
|
176
|
+
|
|
177
|
+
// Export the ready-to-use policies
|
|
178
|
+
export default policies;
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
For more details about DSL, see the [DSL](#dsl) section.
|
|
182
|
+
|
|
183
|
+
**Creating policies using classes (classic approach)**
|
|
184
|
+
|
|
185
|
+
This approach is quite verbose but gives you full control over the policies.
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
import { AbilityPolicy, AbilityRuleSet, AbilityRule, AbilityCompare, AbilityPolicyEffect } from '@via-profit/ability';
|
|
189
|
+
|
|
190
|
+
// Define resource types for TypeScript
|
|
191
|
+
// Types can be generated automatically (more on this later) or defined manually
|
|
192
|
+
// In this example, for simplicity, types are defined manually
|
|
193
|
+
type Resources = {
|
|
194
|
+
['order.action.create']: {
|
|
195
|
+
user: {
|
|
196
|
+
age: number;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
['order.data.price']: {
|
|
200
|
+
user: {
|
|
201
|
+
roles: string[];
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const policies = [
|
|
207
|
+
// first policy
|
|
208
|
+
new AbilityPolicy<Resources>({
|
|
209
|
+
id: '1',
|
|
210
|
+
name: 'Order creation is only available to persons over 18 years old',
|
|
211
|
+
compareMethod: AbilityCompare.and,
|
|
212
|
+
effect: AbilityPolicyEffect.permit,
|
|
213
|
+
permission: 'order.action.create',
|
|
214
|
+
}).addRuleSet(
|
|
215
|
+
AbilityRuleSet.and([
|
|
216
|
+
// rule
|
|
217
|
+
AbilityRule.moreOrEqual('user.age', 18),
|
|
218
|
+
]),
|
|
219
|
+
),
|
|
220
|
+
|
|
221
|
+
// second policy
|
|
222
|
+
new AbilityPolicy<Resources>({
|
|
223
|
+
id: '2',
|
|
224
|
+
name: 'Price editing is only available to administrators',
|
|
225
|
+
compareMethod: AbilityCompare.and,
|
|
226
|
+
effect: AbilityPolicyEffect.permit,
|
|
227
|
+
permission: 'order.data.price',
|
|
228
|
+
}).addRuleSet(
|
|
229
|
+
AbilityRuleSet.and([
|
|
230
|
+
// rule
|
|
231
|
+
AbilityRule.contains('user.roles', 'administrator'),
|
|
232
|
+
])
|
|
233
|
+
),
|
|
234
|
+
];
|
|
235
|
+
|
|
236
|
+
// Export the ready-to-use policies
|
|
237
|
+
export default policies;
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Creating policies with JSON**
|
|
241
|
+
|
|
242
|
+
JSON allows you to store policies in a file or database, for example, in PostgreSQL, which supports working with JSON data.
|
|
243
|
+
|
|
244
|
+
Policy, rule set, and rule classes have JSON export methods, so you can create policies in any way and export them to JSON whenever needed.
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
import { AbilityJSONParser } from '@via-profit/ability';
|
|
248
|
+
|
|
249
|
+
// Define resource types for TypeScript
|
|
250
|
+
// Types can be generated automatically (more on this later) or defined manually
|
|
251
|
+
// In this example, for simplicity, types are defined manually
|
|
252
|
+
type Resources = {
|
|
253
|
+
['order.action.create']: {
|
|
254
|
+
user: {
|
|
255
|
+
age: number;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
['order.data.price']: {
|
|
259
|
+
user: {
|
|
260
|
+
roles: string[];
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Parse JSON using AbilityJSONParser
|
|
266
|
+
// Pass the resource types as a generic parameter
|
|
267
|
+
const policies = AbilityJSONParser.parse<Resources>([
|
|
268
|
+
{
|
|
269
|
+
id: '1',
|
|
270
|
+
name: 'Order creation is only available to persons over 18 years old',
|
|
271
|
+
effect: 'permit',
|
|
272
|
+
permission: 'order.action.create',
|
|
273
|
+
compareMethod: 'and',
|
|
274
|
+
ruleSet: [
|
|
275
|
+
{
|
|
276
|
+
compareMethod: 'and',
|
|
277
|
+
rules: [
|
|
278
|
+
{
|
|
279
|
+
subject: 'user.age',
|
|
280
|
+
resource: 18,
|
|
281
|
+
condition: '>',
|
|
282
|
+
}
|
|
283
|
+
]
|
|
284
|
+
}
|
|
285
|
+
],
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
id: '2',
|
|
289
|
+
name: 'Price editing is only available to administrators',
|
|
290
|
+
effect: 'permit',
|
|
291
|
+
permission: 'order.data.price',
|
|
292
|
+
compareMethod: 'and',
|
|
293
|
+
ruleSet: [
|
|
294
|
+
{
|
|
295
|
+
compareMethod: 'and',
|
|
296
|
+
rules: [
|
|
297
|
+
{
|
|
298
|
+
subject: 'user.roles',
|
|
299
|
+
resource: 'administrator',
|
|
300
|
+
condition: 'contains',
|
|
301
|
+
}
|
|
302
|
+
]
|
|
303
|
+
}
|
|
304
|
+
]
|
|
305
|
+
}
|
|
306
|
+
]);
|
|
307
|
+
|
|
308
|
+
export default policies;
|
|
309
|
+
```
|
|
116
310
|
---
|
|
117
311
|
|
|
118
312
|
## DSL
|
|
@@ -447,24 +641,17 @@ The content of the object is defined by the developer and can be any object cons
|
|
|
447
641
|
- session context,
|
|
448
642
|
- any other external conditions.
|
|
449
643
|
|
|
450
|
-
**Examples:**
|
|
451
|
-
|
|
452
|
-
```ts
|
|
453
|
-
type Environment = {
|
|
454
|
-
time: {
|
|
455
|
-
hour: number;
|
|
456
|
-
};
|
|
457
|
-
ip: string;
|
|
458
|
-
geo: {
|
|
459
|
-
country: string;
|
|
460
|
-
};
|
|
461
|
-
};
|
|
462
|
-
```
|
|
463
644
|
|
|
464
645
|
Environment is passed to `resolve()` and `enforce()` as the third argument:
|
|
465
646
|
|
|
466
647
|
```ts
|
|
467
|
-
|
|
648
|
+
const environment = {
|
|
649
|
+
time: {
|
|
650
|
+
hour: new Date().getHours(),
|
|
651
|
+
},
|
|
652
|
+
ip: req.ip,
|
|
653
|
+
}
|
|
654
|
+
|
|
468
655
|
await resolver.enforce('order.update', resource, environment);
|
|
469
656
|
```
|
|
470
657
|
|
|
@@ -515,18 +702,14 @@ This allows:
|
|
|
515
702
|
|
|
516
703
|
## TypeScript Type Generator
|
|
517
704
|
|
|
518
|
-
`
|
|
519
|
-
|
|
520
|
-
**Usage Example**
|
|
705
|
+
`AbilityTypeGenerator.generateTypeDefs(policies)` generates TypeScript types based on policies, allowing you to avoid inconsistencies between types and the data in the policies.
|
|
521
706
|
|
|
522
|
-
|
|
707
|
+
**Example usage**
|
|
523
708
|
|
|
524
|
-
|
|
525
|
-
// scripts/policies.ts
|
|
526
|
-
|
|
527
|
-
import { AbilityDSLParser } from './AbilityDSLParser';
|
|
709
|
+
Policies can be stored in DSL or JSON. This example uses a DSL file.
|
|
528
710
|
|
|
529
|
-
|
|
711
|
+
_policies/policies.dsl_
|
|
712
|
+
```
|
|
530
713
|
# @name Update order
|
|
531
714
|
permit permission.order.update if all:
|
|
532
715
|
|
|
@@ -534,25 +717,46 @@ permit permission.order.update if all:
|
|
|
534
717
|
all of:
|
|
535
718
|
# @name User is owner
|
|
536
719
|
user.id = order.ownerId
|
|
537
|
-
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
_scripts/policies.js_
|
|
723
|
+
```js
|
|
724
|
+
const fs = require('node:fs');
|
|
725
|
+
const path = require('node:path');
|
|
726
|
+
const { AbilityTypeGenerator, AbilityDSLParser } = require('@via-profit/ability');
|
|
727
|
+
|
|
728
|
+
// Prepare paths
|
|
729
|
+
const dslPath = path.resolve(__dirname, '../src/policies/policies.dsl');
|
|
730
|
+
const typeDefsPath = path.join(path.dirname(dslPath), 'policies.types.ts');
|
|
538
731
|
|
|
732
|
+
// Read DSL as a string
|
|
733
|
+
const dsl = fs.readFileSync(dslPath, {encoding: 'utf-8'});
|
|
734
|
+
|
|
735
|
+
// Create policies
|
|
539
736
|
const policies = new AbilityDSLParser(dsl).parse();
|
|
540
737
|
|
|
541
|
-
|
|
738
|
+
// Generate TypeScript types
|
|
739
|
+
const typeDefs = new AbilityTypeGenerator(policies).generateTypeDefs();
|
|
740
|
+
|
|
741
|
+
// Save TypeScript types to file
|
|
742
|
+
fs.writeFileSync(typeDefsPath, typeDefs, {encoding: 'utf-8'});
|
|
542
743
|
```
|
|
543
744
|
|
|
745
|
+
_policies/index.ts_
|
|
544
746
|
```ts
|
|
545
|
-
|
|
546
|
-
import {
|
|
547
|
-
import
|
|
548
|
-
|
|
747
|
+
import { AbilityDSLParser, AbilityResolver } from '@via-profit/ability';
|
|
748
|
+
import type { Resources } from './policies.types';
|
|
749
|
+
import dsl from './policies.dsl';
|
|
750
|
+
|
|
751
|
+
const policies = new AbilityDSLParser<Resources>(dsl).parse();
|
|
549
752
|
|
|
550
|
-
const
|
|
753
|
+
export const policyResolver = new AbilityResolver(new AbilityDSLParser<Resources>(dsl).parse());
|
|
754
|
+
|
|
755
|
+
export default policyResolver;
|
|
551
756
|
|
|
552
|
-
writeFileSync('./src/ability/types.generated.ts', typedefs, 'utf8');
|
|
553
757
|
```
|
|
554
758
|
|
|
555
|
-
**Generated
|
|
759
|
+
**Generated file (example)**
|
|
556
760
|
|
|
557
761
|
```ts
|
|
558
762
|
// src/ability/types.generated.ts
|
|
@@ -574,12 +778,7 @@ export type Resources = {
|
|
|
574
778
|
**Usage in code**
|
|
575
779
|
|
|
576
780
|
```ts
|
|
577
|
-
import {
|
|
578
|
-
import type { Resources } from './ability/types.generated';
|
|
579
|
-
|
|
580
|
-
const resolver = new AbilityResolver<Resources>(
|
|
581
|
-
AbilityPolicy.parseAll(policies),
|
|
582
|
-
);
|
|
781
|
+
import { policyResolver } from './policies';
|
|
583
782
|
|
|
584
783
|
await resolver.enforce('order.update', {
|
|
585
784
|
user: { id: 'u1' },
|
|
@@ -1144,4 +1343,4 @@ Throughput (ops/s)
|
|
|
1144
1343
|
|
|
1145
1344
|
## License
|
|
1146
1345
|
|
|
1147
|
-
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
|
1346
|
+
This project is licensed under the MIT License. See the [LICENSE](/LICENSE) file for details.
|
|
@@ -3,7 +3,7 @@ import AbilityMatch from './AbilityMatch';
|
|
|
3
3
|
import AbilityCompare, { AbilityCompareCodeType } from './AbilityCompare';
|
|
4
4
|
import AbilityPolicyEffect, { AbilityPolicyEffectCodeType } from './AbilityPolicyEffect';
|
|
5
5
|
import { AbilityExplain } from './AbilityExplain';
|
|
6
|
-
import { ResourceObject } from './
|
|
6
|
+
import { ResourceObject } from './AbilityTypeGenerator';
|
|
7
7
|
export type AbilityPolicyConfig = {
|
|
8
8
|
readonly permission: string;
|
|
9
9
|
readonly effect: AbilityPolicyEffectCodeType;
|
|
@@ -67,18 +67,13 @@ export declare class AbilityPolicy<Resource extends ResourceObject = Record<stri
|
|
|
67
67
|
*/
|
|
68
68
|
check(resource: Resource, environment?: Environment): Promise<AbilityMatch>;
|
|
69
69
|
explain(): AbilityExplain;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
*/
|
|
79
|
-
static fromJSON<Resource extends ResourceObject = Record<string, unknown>, Environment = unknown>(config: AbilityPolicyConfig): AbilityPolicy<Resource, Environment>;
|
|
80
|
-
static fromDSL<Resource extends ResourceObject = Record<string, unknown>, Environment = unknown>(dsl: string): AbilityPolicy<Resource, Environment>;
|
|
81
|
-
toJSON(): AbilityPolicyConfig;
|
|
82
|
-
toString(): string;
|
|
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>;
|
|
83
78
|
}
|
|
84
79
|
export default AbilityPolicy;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import AbilityPolicy from './AbilityPolicy';
|
|
2
2
|
import { AbilityResult } from './AbilityResult';
|
|
3
|
-
import { ResourcesMap } from './
|
|
3
|
+
import { ResourcesMap } from './AbilityTypeGenerator';
|
|
4
4
|
import { AbilityCacheAdapter } from '../cache/AbilityCacheAdapter';
|
|
5
5
|
export type AbilityResolverOptions = {
|
|
6
6
|
readonly cache?: AbilityCacheAdapter | null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AbilityExplain } from './AbilityExplain';
|
|
2
|
-
import { ResourceObject } from './
|
|
2
|
+
import { ResourceObject } from './AbilityTypeGenerator';
|
|
3
3
|
import AbilityPolicy from './AbilityPolicy';
|
|
4
4
|
import AbilityPolicyEffect from './AbilityPolicyEffect';
|
|
5
5
|
export declare class AbilityResult<Resource extends ResourceObject = Record<string, unknown>> {
|
|
@@ -61,7 +61,13 @@ export declare class AbilityRule<Resources extends object = object, Environment
|
|
|
61
61
|
*/
|
|
62
62
|
getDotNotationValue<T = unknown>(resource: unknown, desc: string): T | undefined;
|
|
63
63
|
toString(): string;
|
|
64
|
-
|
|
64
|
+
copyWith(props: Partial<{
|
|
65
|
+
id: string | null;
|
|
66
|
+
name: string | null;
|
|
67
|
+
subject: string;
|
|
68
|
+
resource: AbilityRuleConfig['resource'];
|
|
69
|
+
condition: AbilityCondition;
|
|
70
|
+
}>): AbilityRule<Resources, Environment>;
|
|
65
71
|
static equals<Resources extends object = object, Environment = unknown>(subject: string, resource: AbilityRuleConfig['resource']): AbilityRule<Resources, Environment>;
|
|
66
72
|
static notEquals<Resources extends object = object, Environment = unknown>(subject: string, resource: AbilityRuleConfig['resource']): AbilityRule<Resources, Environment>;
|
|
67
73
|
static contains<Resources extends object = object, Environment = unknown>(subject: string, resource: AbilityRuleConfig['resource']): AbilityRule<Resources, Environment>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import AbilityRule, { AbilityRuleConfig } from './AbilityRule';
|
|
2
2
|
import AbilityCompare, { AbilityCompareCodeType } from './AbilityCompare';
|
|
3
3
|
import AbilityMatch from './AbilityMatch';
|
|
4
|
-
import { ResourceObject } from './
|
|
4
|
+
import { ResourceObject } from './AbilityTypeGenerator';
|
|
5
5
|
export type AbilityRuleSetConfig = {
|
|
6
6
|
readonly id?: string | null;
|
|
7
7
|
readonly name?: string | null;
|
|
@@ -39,10 +39,12 @@ export declare class AbilityRuleSet<Resources extends ResourceObject = Record<st
|
|
|
39
39
|
addRules(rules: AbilityRule<Resources, Environment>[]): this;
|
|
40
40
|
check(resources: Resources | null, environment?: Environment): Promise<AbilityMatch>;
|
|
41
41
|
toString(): string;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
copyWith(props: Partial<{
|
|
43
|
+
id: string | null;
|
|
44
|
+
name: string | null;
|
|
45
|
+
compareMethod: AbilityCompare;
|
|
46
|
+
rules: AbilityRule<Resources, Environment>[];
|
|
47
|
+
}>): AbilityRuleSet<Resources, Environment>;
|
|
46
48
|
static and(rules: AbilityRule[]): AbilityRuleSet<Record<string, unknown>, unknown>;
|
|
47
49
|
static or(rules: AbilityRule[]): AbilityRuleSet<Record<string, unknown>, unknown>;
|
|
48
50
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import AbilityPolicy from './AbilityPolicy';
|
|
2
|
+
export type Primitive = string | number | boolean | null | undefined;
|
|
3
|
+
export type NestedDict<T = Primitive> = {
|
|
4
|
+
[key: string]: NestedDict<T> | T;
|
|
5
|
+
};
|
|
6
|
+
export type ResourceObject = Record<string, unknown>;
|
|
7
|
+
export type ResourcesMap = Record<string, ResourceObject>;
|
|
8
|
+
export declare class AbilityTypeGenerator {
|
|
9
|
+
readonly policies: readonly AbilityPolicy[];
|
|
10
|
+
constructor(policies: readonly AbilityPolicy[]);
|
|
11
|
+
/**
|
|
12
|
+
* Generates TypeScript type definitions based on the provided policies.
|
|
13
|
+
* @returns A generated type definitions.
|
|
14
|
+
*/
|
|
15
|
+
generateTypeDefs(): string;
|
|
16
|
+
/**
|
|
17
|
+
* Determines TypeScript type based on the rule
|
|
18
|
+
* @param rule - The rule to analyze
|
|
19
|
+
* @returns TypeScript type as string
|
|
20
|
+
*/
|
|
21
|
+
private determineTypeFromRule;
|
|
22
|
+
/**
|
|
23
|
+
* Gets TypeScript type for array values
|
|
24
|
+
* @param resource - The resource value to analyze
|
|
25
|
+
* @returns TypeScript array type as string
|
|
26
|
+
*/
|
|
27
|
+
private getArrayType;
|
|
28
|
+
/**
|
|
29
|
+
* Gets primitive TypeScript type for a value
|
|
30
|
+
* @param value - The value to analyze
|
|
31
|
+
* @returns TypeScript primitive type as string
|
|
32
|
+
*/
|
|
33
|
+
private getPrimitiveType;
|
|
34
|
+
/**
|
|
35
|
+
* Builds nested structure from flat paths
|
|
36
|
+
* Example: 'user.profile.name' -> { user: { profile: { name: 'string' } } }
|
|
37
|
+
* @param flatStructure - Flat structure with dot notation paths
|
|
38
|
+
* @returns Nested object structure
|
|
39
|
+
*/
|
|
40
|
+
private buildNestedStructure;
|
|
41
|
+
/**
|
|
42
|
+
* Formats type structure into a string
|
|
43
|
+
* @param structure - Nested type structure
|
|
44
|
+
* @returns Formatted TypeScript type definition string
|
|
45
|
+
*/
|
|
46
|
+
private formatTypeDefinitions;
|
|
47
|
+
/**
|
|
48
|
+
* Recursively formats nested object
|
|
49
|
+
* @param obj - Object to format
|
|
50
|
+
* @param indent - Current indentation level
|
|
51
|
+
* @returns Formatted string
|
|
52
|
+
*/
|
|
53
|
+
private formatNestedObject;
|
|
54
|
+
}
|
|
55
|
+
export default AbilityTypeGenerator;
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export * from './core/AbilityCompare';
|
|
|
3
3
|
export * from './core/AbilityCondition';
|
|
4
4
|
export * from './core/AbilityError';
|
|
5
5
|
export * from './core/AbilityMatch';
|
|
6
|
-
export * from './core/
|
|
6
|
+
export * from './core/AbilityTypeGenerator';
|
|
7
7
|
export * from './core/AbilityPolicy';
|
|
8
8
|
export * from './core/AbilityPolicyEffect';
|
|
9
9
|
export * from './core/AbilityResolver';
|