@adaas/a-utils 0.1.6 → 0.1.8
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 +393 -6
- package/dist/src/lib/A-Channel/A-Channel.component.d.ts +19 -0
- package/dist/src/lib/A-Channel/A-Channel.component.js +76 -0
- package/dist/src/lib/A-Channel/A-Channel.component.js.map +1 -1
- package/dist/src/lib/A-Channel/A-Channel.error.d.ts +1 -0
- package/dist/src/lib/A-Channel/A-Channel.error.js +1 -0
- package/dist/src/lib/A-Channel/A-Channel.error.js.map +1 -1
- package/dist/src/lib/A-Config/A-Config.container.js +1 -1
- package/dist/src/lib/A-Config/A-Config.container.js.map +1 -1
- package/dist/src/lib/A-Manifest/A-Manifest.context.d.ts +52 -0
- package/dist/src/lib/A-Manifest/A-Manifest.context.js +154 -0
- package/dist/src/lib/A-Manifest/A-Manifest.context.js.map +1 -0
- package/dist/src/lib/A-Manifest/A-Manifest.error.d.ts +4 -0
- package/dist/src/lib/A-Manifest/A-Manifest.error.js +9 -0
- package/dist/src/lib/A-Manifest/A-Manifest.error.js.map +1 -0
- package/dist/src/lib/A-Manifest/A-Manifest.types.d.ts +43 -0
- package/dist/src/lib/A-Manifest/A-Manifest.types.js +3 -0
- package/dist/src/lib/A-Manifest/A-Manifest.types.js.map +1 -0
- package/dist/src/lib/A-Manifest/classes/A-ManifestChecker.class.d.ts +13 -0
- package/dist/src/lib/A-Manifest/classes/A-ManifestChecker.class.js +24 -0
- package/dist/src/lib/A-Manifest/classes/A-ManifestChecker.class.js.map +1 -0
- package/package.json +2 -2
- package/src/lib/A-Channel/A-Channel.component.ts +70 -2
- package/src/lib/A-Channel/A-Channel.error.ts +2 -0
- package/src/lib/A-Config/A-Config.container.ts +1 -1
- package/src/lib/A-Manifest/A-Manifest.context.ts +198 -0
- package/src/lib/A-Manifest/A-Manifest.error.ts +7 -0
- package/src/lib/A-Manifest/A-Manifest.types.ts +62 -0
- package/src/lib/A-Manifest/README.md +201 -0
- package/src/lib/A-Manifest/classes/A-ManifestChecker.class.ts +24 -0
- package/tests/A-Manifest.test.ts +290 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# A-Manifest Usage Guide
|
|
2
|
+
|
|
3
|
+
The `A_Manifest` class provides a flexible configuration system for controlling component access and method permissions using regex patterns. It allows you to include or exclude components for particular methods based on sophisticated rule-based configurations.
|
|
4
|
+
|
|
5
|
+
## Core Concepts
|
|
6
|
+
|
|
7
|
+
### 1. **Component-Level Rules**
|
|
8
|
+
Apply rules to all methods of a component:
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
const manifest = new A_Manifest([
|
|
12
|
+
{
|
|
13
|
+
component: UserController,
|
|
14
|
+
exclude: [GuestUser] // Guests cannot access any UserController methods
|
|
15
|
+
}
|
|
16
|
+
]);
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 2. **Method-Level Rules**
|
|
20
|
+
Apply specific rules to individual methods:
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
const manifest = new A_Manifest([
|
|
24
|
+
{
|
|
25
|
+
component: UserController,
|
|
26
|
+
methods: [
|
|
27
|
+
{
|
|
28
|
+
method: 'delete',
|
|
29
|
+
apply: [AdminUser, SuperAdmin] // Only admins can delete
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
method: 'post',
|
|
33
|
+
exclude: [GuestUser] // Guests cannot create
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
]);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 3. **Regex Support**
|
|
41
|
+
Use regex patterns for flexible matching:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
const manifest = new A_Manifest([
|
|
45
|
+
{
|
|
46
|
+
component: UserController,
|
|
47
|
+
methods: [
|
|
48
|
+
{
|
|
49
|
+
method: /^(post|put|delete)$/, // Match mutating operations
|
|
50
|
+
exclude: [GuestUser]
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
]);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## API Reference
|
|
58
|
+
|
|
59
|
+
### Constructor
|
|
60
|
+
```typescript
|
|
61
|
+
new A_Manifest(config: A_UTILS_TYPES__Manifest_Init)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Creates a new manifest with the provided configuration.
|
|
65
|
+
|
|
66
|
+
### isAllowed()
|
|
67
|
+
```typescript
|
|
68
|
+
isAllowed<T extends A_Component>(
|
|
69
|
+
ctor: T | A_TYPES__Component_Constructor<T>,
|
|
70
|
+
method: string
|
|
71
|
+
): A_ManifestChecker
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Returns a fluent checker to verify if access is allowed.
|
|
75
|
+
|
|
76
|
+
**Usage:**
|
|
77
|
+
```typescript
|
|
78
|
+
const allowed = manifest.isAllowed(UserController, 'post').for(GuestUser);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### isExcluded()
|
|
82
|
+
```typescript
|
|
83
|
+
isExcluded<T extends A_Component>(
|
|
84
|
+
ctor: T | A_TYPES__Component_Constructor<T>,
|
|
85
|
+
method: string
|
|
86
|
+
): A_ManifestChecker
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Returns a fluent checker to verify if access is explicitly excluded.
|
|
90
|
+
|
|
91
|
+
**Usage:**
|
|
92
|
+
```typescript
|
|
93
|
+
const excluded = manifest.isExcluded(UserController, 'post').for(GuestUser);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Configuration Types
|
|
97
|
+
|
|
98
|
+
### A_UTILS_TYPES__Manifest_ComponentLevelConfig
|
|
99
|
+
```typescript
|
|
100
|
+
{
|
|
101
|
+
component: A_TYPES__Component_Constructor<T>,
|
|
102
|
+
methods?: Array<A_UTILS_TYPES__Manifest_MethodLevelConfig<T>>,
|
|
103
|
+
apply?: Array<A_UTILS_TYPES__Manifest_AllowedComponents> | RegExp,
|
|
104
|
+
exclude?: Array<A_UTILS_TYPES__Manifest_AllowedComponents> | RegExp
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### A_UTILS_TYPES__Manifest_MethodLevelConfig
|
|
109
|
+
```typescript
|
|
110
|
+
{
|
|
111
|
+
method: string | RegExp,
|
|
112
|
+
apply?: Array<A_UTILS_TYPES__Manifest_AllowedComponents> | RegExp,
|
|
113
|
+
exclude?: Array<A_UTILS_TYPES__Manifest_AllowedComponents> | RegExp
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Rule Precedence
|
|
118
|
+
|
|
119
|
+
1. **Method-level rules** override component-level rules
|
|
120
|
+
2. **Exclude rules** take precedence over apply rules
|
|
121
|
+
3. **No rules** = allow by default
|
|
122
|
+
|
|
123
|
+
## Advanced Examples
|
|
124
|
+
|
|
125
|
+
### Example 1: Hierarchical Permissions
|
|
126
|
+
```typescript
|
|
127
|
+
const manifest = new A_Manifest([
|
|
128
|
+
{
|
|
129
|
+
component: UserController,
|
|
130
|
+
exclude: [GuestUser], // Base rule: no access for guests
|
|
131
|
+
methods: [
|
|
132
|
+
{
|
|
133
|
+
method: 'get',
|
|
134
|
+
apply: [GuestUser, RegisteredUser, AdminUser] // Override: guests can read
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
method: 'delete',
|
|
138
|
+
apply: [AdminUser] // Only admins can delete
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
]);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Example 2: Using Regex for Complex Patterns
|
|
146
|
+
```typescript
|
|
147
|
+
const manifest = new A_Manifest([
|
|
148
|
+
{
|
|
149
|
+
component: AdminController,
|
|
150
|
+
methods: [
|
|
151
|
+
{
|
|
152
|
+
method: /^admin/, // Methods starting with "admin"
|
|
153
|
+
apply: [SuperAdmin] // Only super admins
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
method: /^(get|list)/, // Read operations
|
|
157
|
+
apply: [AdminUser, SuperAdmin] // All admins
|
|
158
|
+
}
|
|
159
|
+
]
|
|
160
|
+
}
|
|
161
|
+
]);
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Example 3: Multiple Components
|
|
165
|
+
```typescript
|
|
166
|
+
const manifest = new A_Manifest([
|
|
167
|
+
{
|
|
168
|
+
component: UserController,
|
|
169
|
+
exclude: [GuestUser]
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
component: AdminController,
|
|
173
|
+
apply: [AdminUser, SuperAdmin]
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
component: PublicController,
|
|
177
|
+
// No rules = accessible to all
|
|
178
|
+
}
|
|
179
|
+
]);
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Best Practices
|
|
183
|
+
|
|
184
|
+
1. **Start with restrictive rules** and add exceptions rather than the opposite
|
|
185
|
+
2. **Use component-level rules** for broad access control
|
|
186
|
+
3. **Use method-level rules** for fine-grained permissions
|
|
187
|
+
4. **Leverage regex patterns** for dynamic method matching
|
|
188
|
+
5. **Test your configurations** thoroughly with the provided fluent API
|
|
189
|
+
|
|
190
|
+
## Error Handling
|
|
191
|
+
|
|
192
|
+
The manifest will throw `A_ManifestError` for:
|
|
193
|
+
- Invalid configuration structure
|
|
194
|
+
- Non-component constructors in configuration
|
|
195
|
+
- Malformed regex patterns
|
|
196
|
+
|
|
197
|
+
## Performance Considerations
|
|
198
|
+
|
|
199
|
+
- Rules are compiled to regex patterns during initialization
|
|
200
|
+
- Runtime checks are optimized for fast pattern matching
|
|
201
|
+
- Consider the number of rules when designing complex hierarchies
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { A_TYPES__Component_Constructor } from "@adaas/a-concept";
|
|
2
|
+
import { A_Manifest } from "../A-Manifest.context";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Fluent API for checking manifest permissions
|
|
6
|
+
*/
|
|
7
|
+
export class A_ManifestChecker {
|
|
8
|
+
constructor(
|
|
9
|
+
private manifest: A_Manifest,
|
|
10
|
+
private component: A_TYPES__Component_Constructor,
|
|
11
|
+
private method: string,
|
|
12
|
+
private checkExclusion: boolean = false
|
|
13
|
+
) {}
|
|
14
|
+
|
|
15
|
+
for(target: A_TYPES__Component_Constructor): boolean {
|
|
16
|
+
const result = this.manifest.internal_checkAccess({
|
|
17
|
+
component: this.component,
|
|
18
|
+
method: this.method,
|
|
19
|
+
target: target
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return this.checkExclusion ? !result : result;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { A_Component } from "@adaas/a-concept";
|
|
2
|
+
import { A_Manifest } from "../src/lib/A-Manifest/A-Manifest.context";
|
|
3
|
+
|
|
4
|
+
describe('A_Manifest', () => {
|
|
5
|
+
it('Should deny access to excluded components at component level', () => {
|
|
6
|
+
class UserController extends A_Component {
|
|
7
|
+
get() { return 'user.get'; }
|
|
8
|
+
post() { return 'user.post'; }
|
|
9
|
+
}
|
|
10
|
+
class GuestUser extends A_Component {}
|
|
11
|
+
class RegisteredUser extends A_Component {}
|
|
12
|
+
|
|
13
|
+
const manifest = new A_Manifest([
|
|
14
|
+
{
|
|
15
|
+
component: UserController,
|
|
16
|
+
exclude: [GuestUser]
|
|
17
|
+
}
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
expect(manifest.isAllowed(UserController, 'get').for(GuestUser)).toBe(false);
|
|
21
|
+
expect(manifest.isAllowed(UserController, 'post').for(GuestUser)).toBe(false);
|
|
22
|
+
expect(manifest.isAllowed(UserController, 'get').for(RegisteredUser)).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('Should allow access only to included components at component level', () => {
|
|
26
|
+
class AdminController extends A_Component {
|
|
27
|
+
get() { return 'admin.get'; }
|
|
28
|
+
adminPanel() { return 'admin.adminPanel'; }
|
|
29
|
+
}
|
|
30
|
+
class AdminUser extends A_Component {}
|
|
31
|
+
class SuperAdmin extends A_Component {}
|
|
32
|
+
class RegisteredUser extends A_Component {}
|
|
33
|
+
|
|
34
|
+
const manifest = new A_Manifest([
|
|
35
|
+
{
|
|
36
|
+
component: AdminController,
|
|
37
|
+
apply: [AdminUser, SuperAdmin]
|
|
38
|
+
}
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
expect(manifest.isAllowed(AdminController, 'get').for(RegisteredUser)).toBe(false);
|
|
42
|
+
expect(manifest.isAllowed(AdminController, 'get').for(AdminUser)).toBe(true);
|
|
43
|
+
expect(manifest.isAllowed(AdminController, 'adminPanel').for(SuperAdmin)).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('Should respect method-level exclusion rules', () => {
|
|
47
|
+
class UserController extends A_Component {
|
|
48
|
+
get() { return 'user.get'; }
|
|
49
|
+
post() { return 'user.post'; }
|
|
50
|
+
delete() { return 'user.delete'; }
|
|
51
|
+
}
|
|
52
|
+
class GuestUser extends A_Component {}
|
|
53
|
+
class RegisteredUser extends A_Component {}
|
|
54
|
+
class AdminUser extends A_Component {}
|
|
55
|
+
class SuperAdmin extends A_Component {}
|
|
56
|
+
|
|
57
|
+
const manifest = new A_Manifest([
|
|
58
|
+
{
|
|
59
|
+
component: UserController,
|
|
60
|
+
methods: [
|
|
61
|
+
{
|
|
62
|
+
method: 'delete',
|
|
63
|
+
apply: [AdminUser, SuperAdmin]
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
method: 'post',
|
|
67
|
+
exclude: [GuestUser]
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
]);
|
|
72
|
+
|
|
73
|
+
expect(manifest.isAllowed(UserController, 'get').for(GuestUser)).toBe(true);
|
|
74
|
+
expect(manifest.isAllowed(UserController, 'post').for(GuestUser)).toBe(false);
|
|
75
|
+
expect(manifest.isAllowed(UserController, 'post').for(RegisteredUser)).toBe(true);
|
|
76
|
+
expect(manifest.isAllowed(UserController, 'delete').for(RegisteredUser)).toBe(false);
|
|
77
|
+
expect(manifest.isAllowed(UserController, 'delete').for(AdminUser)).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('Should handle regex patterns for method matching', () => {
|
|
81
|
+
class UserController extends A_Component {
|
|
82
|
+
get() { return 'user.get'; }
|
|
83
|
+
post() { return 'user.post'; }
|
|
84
|
+
put() { return 'user.put'; }
|
|
85
|
+
delete() { return 'user.delete'; }
|
|
86
|
+
}
|
|
87
|
+
class GuestUser extends A_Component {}
|
|
88
|
+
class RegisteredUser extends A_Component {}
|
|
89
|
+
|
|
90
|
+
const manifest = new A_Manifest([
|
|
91
|
+
{
|
|
92
|
+
component: UserController,
|
|
93
|
+
methods: [
|
|
94
|
+
{
|
|
95
|
+
method: /^(post|put|delete)$/,
|
|
96
|
+
exclude: [GuestUser]
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
}
|
|
100
|
+
]);
|
|
101
|
+
|
|
102
|
+
expect(manifest.isAllowed(UserController, 'get').for(GuestUser)).toBe(true);
|
|
103
|
+
expect(manifest.isAllowed(UserController, 'post').for(GuestUser)).toBe(false);
|
|
104
|
+
expect(manifest.isAllowed(UserController, 'put').for(GuestUser)).toBe(false);
|
|
105
|
+
expect(manifest.isAllowed(UserController, 'delete').for(GuestUser)).toBe(false);
|
|
106
|
+
expect(manifest.isAllowed(UserController, 'post').for(RegisteredUser)).toBe(true);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('Should allow method-level overrides of component-level rules', () => {
|
|
110
|
+
class UserController extends A_Component {
|
|
111
|
+
get() { return 'user.get'; }
|
|
112
|
+
post() { return 'user.post'; }
|
|
113
|
+
}
|
|
114
|
+
class AdminController extends A_Component {
|
|
115
|
+
get() { return 'admin.get'; }
|
|
116
|
+
}
|
|
117
|
+
class GuestUser extends A_Component {}
|
|
118
|
+
class RegisteredUser extends A_Component {}
|
|
119
|
+
class AdminUser extends A_Component {}
|
|
120
|
+
class SuperAdmin extends A_Component {}
|
|
121
|
+
|
|
122
|
+
const manifest = new A_Manifest([
|
|
123
|
+
{
|
|
124
|
+
component: UserController,
|
|
125
|
+
exclude: [GuestUser],
|
|
126
|
+
methods: [
|
|
127
|
+
{
|
|
128
|
+
method: 'get',
|
|
129
|
+
apply: [GuestUser, RegisteredUser, AdminUser, SuperAdmin]
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
component: AdminController,
|
|
135
|
+
apply: [AdminUser, SuperAdmin]
|
|
136
|
+
}
|
|
137
|
+
]);
|
|
138
|
+
|
|
139
|
+
// Method-level rule Should override component-level exclusion
|
|
140
|
+
expect(manifest.isAllowed(UserController, 'get').for(GuestUser)).toBe(true);
|
|
141
|
+
|
|
142
|
+
// Component-level exclusion Should apply to methods without specific rules
|
|
143
|
+
expect(manifest.isAllowed(UserController, 'post').for(GuestUser)).toBe(false);
|
|
144
|
+
|
|
145
|
+
// Other component rules Should work independently
|
|
146
|
+
expect(manifest.isAllowed(AdminController, 'get').for(RegisteredUser)).toBe(false);
|
|
147
|
+
expect(manifest.isAllowed(AdminController, 'get').for(AdminUser)).toBe(true);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('Should work with isExcluded method', () => {
|
|
151
|
+
class UserController extends A_Component {
|
|
152
|
+
post() { return 'user.post'; }
|
|
153
|
+
}
|
|
154
|
+
class GuestUser extends A_Component {}
|
|
155
|
+
class RegisteredUser extends A_Component {}
|
|
156
|
+
|
|
157
|
+
const manifest = new A_Manifest([
|
|
158
|
+
{
|
|
159
|
+
component: UserController,
|
|
160
|
+
exclude: [GuestUser]
|
|
161
|
+
}
|
|
162
|
+
]);
|
|
163
|
+
|
|
164
|
+
expect(manifest.isExcluded(UserController, 'post').for(GuestUser)).toBe(true);
|
|
165
|
+
expect(manifest.isExcluded(UserController, 'post').for(RegisteredUser)).toBe(false);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('Should handle empty configuration and allow all by default', () => {
|
|
169
|
+
class UserController extends A_Component {
|
|
170
|
+
get() { return 'user.get'; }
|
|
171
|
+
}
|
|
172
|
+
class GuestUser extends A_Component {}
|
|
173
|
+
|
|
174
|
+
const manifest = new A_Manifest([]);
|
|
175
|
+
|
|
176
|
+
expect(manifest.isAllowed(UserController, 'get').for(GuestUser)).toBe(true);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('Should handle component with no specific rules and allow all by default', () => {
|
|
180
|
+
class UserController extends A_Component {
|
|
181
|
+
get() { return 'user.get'; }
|
|
182
|
+
}
|
|
183
|
+
class GuestUser extends A_Component {}
|
|
184
|
+
|
|
185
|
+
const manifest = new A_Manifest([
|
|
186
|
+
{
|
|
187
|
+
component: UserController
|
|
188
|
+
// No apply or exclude rules
|
|
189
|
+
}
|
|
190
|
+
]);
|
|
191
|
+
|
|
192
|
+
expect(manifest.isAllowed(UserController, 'get').for(GuestUser)).toBe(true);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('Should apply component-level rules to all methods when no method rules exist', () => {
|
|
196
|
+
class UserController extends A_Component {
|
|
197
|
+
get() { return 'user.get'; }
|
|
198
|
+
post() { return 'user.post'; }
|
|
199
|
+
}
|
|
200
|
+
class GuestUser extends A_Component {}
|
|
201
|
+
|
|
202
|
+
const manifest = new A_Manifest([
|
|
203
|
+
{
|
|
204
|
+
component: UserController,
|
|
205
|
+
exclude: [GuestUser]
|
|
206
|
+
}
|
|
207
|
+
]);
|
|
208
|
+
|
|
209
|
+
expect(manifest.isAllowed(UserController, 'get').for(GuestUser)).toBe(false);
|
|
210
|
+
expect(manifest.isAllowed(UserController, 'post').for(GuestUser)).toBe(false);
|
|
211
|
+
expect(manifest.isAllowed(UserController, 'anyMethod').for(GuestUser)).toBe(false);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('Should throw error for invalid configuration type', () => {
|
|
215
|
+
expect(() => {
|
|
216
|
+
// @ts-ignore - Testing runtime error
|
|
217
|
+
new A_Manifest("invalid");
|
|
218
|
+
}).toThrow();
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('Should throw error for non-component constructor in configuration', () => {
|
|
222
|
+
class GuestUser extends A_Component {}
|
|
223
|
+
|
|
224
|
+
expect(() => {
|
|
225
|
+
new A_Manifest([
|
|
226
|
+
{
|
|
227
|
+
// @ts-ignore - Testing runtime error
|
|
228
|
+
component: "not-a-constructor",
|
|
229
|
+
exclude: [GuestUser]
|
|
230
|
+
}
|
|
231
|
+
]);
|
|
232
|
+
}).toThrow();
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('Should handle multiple method rules for the same component', () => {
|
|
236
|
+
class UserController extends A_Component {
|
|
237
|
+
get() { return 'user.get'; }
|
|
238
|
+
post() { return 'user.post'; }
|
|
239
|
+
put() { return 'user.put'; }
|
|
240
|
+
delete() { return 'user.delete'; }
|
|
241
|
+
}
|
|
242
|
+
class GuestUser extends A_Component {}
|
|
243
|
+
class RegisteredUser extends A_Component {}
|
|
244
|
+
class AdminUser extends A_Component {}
|
|
245
|
+
|
|
246
|
+
const manifest = new A_Manifest([
|
|
247
|
+
{
|
|
248
|
+
component: UserController,
|
|
249
|
+
methods: [
|
|
250
|
+
{
|
|
251
|
+
method: 'get',
|
|
252
|
+
apply: [GuestUser, RegisteredUser, AdminUser]
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
method: 'post',
|
|
256
|
+
apply: [RegisteredUser, AdminUser]
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
method: 'delete',
|
|
260
|
+
apply: [AdminUser]
|
|
261
|
+
}
|
|
262
|
+
]
|
|
263
|
+
}
|
|
264
|
+
]);
|
|
265
|
+
|
|
266
|
+
expect(manifest.isAllowed(UserController, 'get').for(GuestUser)).toBe(true);
|
|
267
|
+
expect(manifest.isAllowed(UserController, 'post').for(GuestUser)).toBe(false);
|
|
268
|
+
expect(manifest.isAllowed(UserController, 'post').for(RegisteredUser)).toBe(true);
|
|
269
|
+
expect(manifest.isAllowed(UserController, 'delete').for(RegisteredUser)).toBe(false);
|
|
270
|
+
expect(manifest.isAllowed(UserController, 'delete').for(AdminUser)).toBe(true);
|
|
271
|
+
expect(manifest.isAllowed(UserController, 'put').for(GuestUser)).toBe(true); // No rule = allow
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('Should prioritize exclude rules over apply rules', () => {
|
|
275
|
+
class UserController extends A_Component {
|
|
276
|
+
post() { return 'user.post'; }
|
|
277
|
+
}
|
|
278
|
+
class RegisteredUser extends A_Component {}
|
|
279
|
+
|
|
280
|
+
const manifest = new A_Manifest([
|
|
281
|
+
{
|
|
282
|
+
component: UserController,
|
|
283
|
+
apply: [RegisteredUser],
|
|
284
|
+
exclude: [RegisteredUser] // Exclude Should take precedence
|
|
285
|
+
}
|
|
286
|
+
]);
|
|
287
|
+
|
|
288
|
+
expect(manifest.isAllowed(UserController, 'post').for(RegisteredUser)).toBe(false);
|
|
289
|
+
});
|
|
290
|
+
});
|